Massive IDE clean-ups, and finally implemented ATAPI hard disks.
This commit is contained in:
208
src/disk/zip.c
208
src/disk/zip.c
@@ -36,6 +36,8 @@
|
||||
#include <86box/hdc_ide.h>
|
||||
#include <86box/zip.h>
|
||||
|
||||
#define IDE_ATAPI_IS_EARLY id->sc->pad0
|
||||
|
||||
zip_drive_t zip_drives[ZIP_NUM];
|
||||
|
||||
/* Table of all SCSI commands and their flags, needed for the new disc change / not ready handler. */
|
||||
@@ -588,11 +590,11 @@ zip_init(zip_t *dev)
|
||||
dev->drv->bus_mode |= 1;
|
||||
zip_log("ZIP %i: Bus type %i, bus mode %i\n", dev->id, dev->drv->bus_type, dev->drv->bus_mode);
|
||||
if (dev->drv->bus_type < ZIP_BUS_SCSI) {
|
||||
dev->phase = 1;
|
||||
dev->request_length = 0xEB14;
|
||||
dev->tf->phase = 1;
|
||||
dev->tf->request_length = 0xEB14;
|
||||
}
|
||||
dev->status = READY_STAT | DSC_STAT;
|
||||
dev->pos = 0;
|
||||
dev->tf->status = READY_STAT | DSC_STAT;
|
||||
dev->tf->pos = 0;
|
||||
dev->packet_status = PHASE_NONE;
|
||||
zip_sense_key = zip_asc = zip_ascq = dev->unit_attention = 0;
|
||||
}
|
||||
@@ -622,36 +624,9 @@ zip_current_mode(zip_t *dev)
|
||||
if (!zip_supports_pio(dev) && zip_supports_dma(dev))
|
||||
return 2;
|
||||
if (zip_supports_pio(dev) && zip_supports_dma(dev)) {
|
||||
zip_log("ZIP %i: Drive supports both, setting to %s\n", dev->id, (dev->features & 1) ? "DMA" : "PIO");
|
||||
return (dev->features & 1) ? 2 : 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Translates ATAPI phase (DRQ, I/O, C/D) to SCSI phase (MSG, C/D, I/O). */
|
||||
int
|
||||
zip_atapi_phase_to_scsi(zip_t *dev)
|
||||
{
|
||||
if (dev->status & 8) {
|
||||
switch (dev->phase & 3) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
return 2;
|
||||
case 2:
|
||||
return 1;
|
||||
case 3:
|
||||
return 7;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if ((dev->phase & 3) == 3)
|
||||
return 3;
|
||||
else
|
||||
return 4;
|
||||
zip_log("ZIP %i: Drive supports both, setting to %s\n", dev->id,
|
||||
(dev->tf->features & 1) ? "DMA" : "PIO");
|
||||
return (dev->tf->features & 1) ? 2 : 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -791,7 +766,7 @@ zip_update_request_length(zip_t *dev, int len, int block_len)
|
||||
int bt;
|
||||
int min_len = 0;
|
||||
|
||||
dev->max_transfer_len = dev->request_length;
|
||||
dev->max_transfer_len = dev->tf->request_length;
|
||||
|
||||
/* For media access commands, make sure the requested DRQ length matches the block length. */
|
||||
switch (dev->current_cdb[0]) {
|
||||
@@ -835,9 +810,9 @@ zip_update_request_length(zip_t *dev, int len, int block_len)
|
||||
dev->max_transfer_len = 65534;
|
||||
|
||||
if ((len <= dev->max_transfer_len) && (len >= min_len))
|
||||
dev->request_length = dev->max_transfer_len = len;
|
||||
dev->tf->request_length = dev->max_transfer_len = len;
|
||||
else if (len > dev->max_transfer_len)
|
||||
dev->request_length = dev->max_transfer_len;
|
||||
dev->tf->request_length = dev->max_transfer_len;
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -868,9 +843,9 @@ zip_command_common(zip_t *dev)
|
||||
double bytes_per_second;
|
||||
double period;
|
||||
|
||||
dev->status = BUSY_STAT;
|
||||
dev->phase = 1;
|
||||
dev->pos = 0;
|
||||
dev->tf->status = BUSY_STAT;
|
||||
dev->tf->phase = 1;
|
||||
dev->tf->pos = 0;
|
||||
if (dev->packet_status == PHASE_COMPLETE)
|
||||
dev->callback = 0.0;
|
||||
else {
|
||||
@@ -932,8 +907,8 @@ static void
|
||||
zip_data_command_finish(zip_t *dev, int len, int block_len, int alloc_len, int direction)
|
||||
{
|
||||
zip_log("ZIP %i: Finishing command (%02X): %i, %i, %i, %i, %i\n",
|
||||
dev->id, dev->current_cdb[0], len, block_len, alloc_len, direction, dev->request_length);
|
||||
dev->pos = 0;
|
||||
dev->id, dev->current_cdb[0], len, block_len, alloc_len, direction, dev->tf->request_length);
|
||||
dev->tf->pos = 0;
|
||||
if (alloc_len >= 0) {
|
||||
if (alloc_len < len)
|
||||
len = alloc_len;
|
||||
@@ -962,7 +937,8 @@ zip_data_command_finish(zip_t *dev, int len, int block_len, int alloc_len, int d
|
||||
}
|
||||
|
||||
zip_log("ZIP %i: Status: %i, cylinder %i, packet length: %i, position: %i, phase: %i\n",
|
||||
dev->id, dev->packet_status, dev->request_length, dev->packet_len, dev->pos, dev->phase);
|
||||
dev->id, dev->packet_status, dev->tf->request_length, dev->packet_len, dev->tf->pos,
|
||||
dev->tf->phase);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -987,12 +963,12 @@ static void
|
||||
zip_cmd_error(zip_t *dev)
|
||||
{
|
||||
zip_set_phase(dev, SCSI_PHASE_STATUS);
|
||||
dev->error = ((zip_sense_key & 0xf) << 4) | ABRT_ERR;
|
||||
dev->tf->error = ((zip_sense_key & 0xf) << 4) | ABRT_ERR;
|
||||
if (dev->unit_attention)
|
||||
dev->error |= MCR_ERR;
|
||||
dev->status = READY_STAT | ERR_STAT;
|
||||
dev->phase = 3;
|
||||
dev->pos = 0;
|
||||
dev->tf->error |= MCR_ERR;
|
||||
dev->tf->status = READY_STAT | ERR_STAT;
|
||||
dev->tf->phase = 3;
|
||||
dev->tf->pos = 0;
|
||||
dev->packet_status = PHASE_ERROR;
|
||||
dev->callback = 50.0 * ZIP_TIME;
|
||||
zip_set_callback(dev);
|
||||
@@ -1004,12 +980,12 @@ static void
|
||||
zip_unit_attention(zip_t *dev)
|
||||
{
|
||||
zip_set_phase(dev, SCSI_PHASE_STATUS);
|
||||
dev->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR;
|
||||
dev->tf->error = (SENSE_UNIT_ATTENTION << 4) | ABRT_ERR;
|
||||
if (dev->unit_attention)
|
||||
dev->error |= MCR_ERR;
|
||||
dev->status = READY_STAT | ERR_STAT;
|
||||
dev->phase = 3;
|
||||
dev->pos = 0;
|
||||
dev->tf->error |= MCR_ERR;
|
||||
dev->tf->status = READY_STAT | ERR_STAT;
|
||||
dev->tf->phase = 3;
|
||||
dev->tf->pos = 0;
|
||||
dev->packet_status = PHASE_ERROR;
|
||||
dev->callback = 50.0 * ZIP_TIME;
|
||||
zip_set_callback(dev);
|
||||
@@ -1097,7 +1073,7 @@ zip_invalid_field(zip_t *dev)
|
||||
zip_asc = ASC_INV_FIELD_IN_CMD_PACKET;
|
||||
zip_ascq = 0;
|
||||
zip_cmd_error(dev);
|
||||
dev->status = 0x53;
|
||||
dev->tf->status = 0x53;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1107,7 +1083,7 @@ zip_invalid_field_pl(zip_t *dev)
|
||||
zip_asc = ASC_INV_FIELD_IN_PARAMETER_LIST;
|
||||
zip_ascq = 0;
|
||||
zip_cmd_error(dev);
|
||||
dev->status = 0x53;
|
||||
dev->tf->status = 0x53;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1184,7 +1160,8 @@ zip_pre_execution_check(zip_t *dev, uint8_t *cdb)
|
||||
int ready = 0;
|
||||
|
||||
if ((cdb[0] != GPCMD_REQUEST_SENSE) && (dev->cur_lun == SCSI_LUN_USE_CDB) && (cdb[1] & 0xe0)) {
|
||||
zip_log("ZIP %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", dev->id, ((dev->request_length >> 5) & 7));
|
||||
zip_log("ZIP %i: Attempting to execute a unknown command targeted at SCSI LUN %i\n", dev->id,
|
||||
((dev->tf->request_length >> 5) & 7));
|
||||
zip_invalid_lun(dev);
|
||||
return 0;
|
||||
}
|
||||
@@ -1274,14 +1251,14 @@ zip_reset(scsi_common_t *sc)
|
||||
zip_t *dev = (zip_t *) sc;
|
||||
|
||||
zip_rezero(dev);
|
||||
dev->status = 0;
|
||||
dev->callback = 0.0;
|
||||
dev->tf->status = 0;
|
||||
dev->callback = 0.0;
|
||||
zip_set_callback(dev);
|
||||
dev->phase = 1;
|
||||
dev->request_length = 0xEB14;
|
||||
dev->packet_status = PHASE_NONE;
|
||||
dev->unit_attention = 0;
|
||||
dev->cur_lun = SCSI_LUN_USE_CDB;
|
||||
dev->tf->phase = 1;
|
||||
dev->tf->request_length = 0xEB14;
|
||||
dev->packet_status = PHASE_NONE;
|
||||
dev->unit_attention = 0;
|
||||
dev->cur_lun = SCSI_LUN_USE_CDB;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1373,11 +1350,11 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
uint8_t scsi_id = dev->drv->scsi_device_id & 0x0f;
|
||||
|
||||
if (dev->drv->bus_type == ZIP_BUS_SCSI) {
|
||||
BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length;
|
||||
dev->status &= ~ERR_STAT;
|
||||
BufLen = &scsi_devices[scsi_bus][scsi_id].buffer_length;
|
||||
dev->tf->status &= ~ERR_STAT;
|
||||
} else {
|
||||
BufLen = &blen;
|
||||
dev->error = 0;
|
||||
BufLen = &blen;
|
||||
dev->tf->error = 0;
|
||||
}
|
||||
|
||||
dev->packet_len = 0;
|
||||
@@ -1388,7 +1365,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
if (cdb[0] != 0) {
|
||||
zip_log("ZIP %i: Command 0x%02X, Sense Key %02X, Asc %02X, Ascq %02X, Unit attention: %i\n",
|
||||
dev->id, cdb[0], zip_sense_key, zip_asc, zip_ascq, dev->unit_attention);
|
||||
zip_log("ZIP %i: Request length: %04X\n", dev->id, dev->request_length);
|
||||
zip_log("ZIP %i: Request length: %04X\n", dev->id, dev->tf->request_length);
|
||||
|
||||
zip_log("ZIP %i: CDB: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id,
|
||||
cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7],
|
||||
@@ -1465,8 +1442,9 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
break;
|
||||
|
||||
case GPCMD_REQUEST_SENSE:
|
||||
/* If there's a unit attention condition and there's a buffered not ready, a standalone REQUEST SENSE
|
||||
should forget about the not ready, and report unit attention straight away. */
|
||||
/* If there's a unit attention condition and there's a buffered not
|
||||
ready, a standalone REQUEST SENSE should forget about the not
|
||||
ready, and report unit attention straight away. */
|
||||
zip_set_phase(dev, SCSI_PHASE_DATA_IN);
|
||||
max_len = cdb[4];
|
||||
|
||||
@@ -1507,7 +1485,14 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
switch (cdb[0]) {
|
||||
case GPCMD_READ_6:
|
||||
dev->sector_len = cdb[4];
|
||||
dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]);
|
||||
/*
|
||||
For READ (6) and WRITE (6), a length of 0 indicates a
|
||||
transfer of 256 sectors.
|
||||
*/
|
||||
if (dev->sector_len == 0)
|
||||
dev->sector_len = 256;
|
||||
dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) |
|
||||
(((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]);
|
||||
zip_log("ZIP %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos);
|
||||
break;
|
||||
case GPCMD_READ_10:
|
||||
@@ -1516,14 +1501,21 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
zip_log("ZIP %i: Length: %i, LBA: %i\n", dev->id, dev->sector_len, dev->sector_pos);
|
||||
break;
|
||||
case GPCMD_READ_12:
|
||||
dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]);
|
||||
dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]);
|
||||
dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) |
|
||||
(((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]);
|
||||
dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) |
|
||||
(((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (dev->sector_pos >= dev->drv->medium_size) {
|
||||
zip_lba_out_of_range(dev);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dev->sector_len) {
|
||||
zip_set_phase(dev, SCSI_PHASE_STATUS);
|
||||
/* zip_log("ZIP %i: All done - callback set\n", dev->id); */
|
||||
@@ -1534,9 +1526,13 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
}
|
||||
|
||||
max_len = dev->sector_len;
|
||||
dev->requested_blocks = max_len; /* If we're reading all blocks in one go for DMA, why not also for PIO, it should NOT
|
||||
matter anyway, this step should be identical and only the way the read dat is
|
||||
transferred to the host should be different. */
|
||||
/*
|
||||
If we're reading all blocks in one go for DMA, why not also for
|
||||
PIO, it should NOT matter anyway, this step should be identical
|
||||
and only the way the read dat is transferred to the host should
|
||||
be different.
|
||||
*/
|
||||
dev->requested_blocks = max_len;
|
||||
|
||||
dev->packet_len = max_len * alloc_length;
|
||||
zip_buf_alloc(dev, dev->packet_len);
|
||||
@@ -1558,10 +1554,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
|
||||
zip_data_command_finish(dev, alloc_length, 512, alloc_length, 0);
|
||||
|
||||
if (dev->packet_status != PHASE_COMPLETE)
|
||||
ui_sb_update_icon(SB_ZIP | dev->id, 1);
|
||||
else
|
||||
ui_sb_update_icon(SB_ZIP | dev->id, 0);
|
||||
ui_sb_update_icon(SB_ZIP | dev->id, dev->packet_status != PHASE_COMPLETE);
|
||||
return;
|
||||
|
||||
case GPCMD_VERIFY_6:
|
||||
@@ -1590,9 +1583,14 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
case GPCMD_VERIFY_6:
|
||||
case GPCMD_WRITE_6:
|
||||
dev->sector_len = cdb[4];
|
||||
/*
|
||||
For READ (6) and WRITE (6), a length of 0 indicates a
|
||||
transfer of 256 sectors.
|
||||
*/
|
||||
if (dev->sector_len == 0)
|
||||
dev->sector_len = 256; /* For READ (6) and WRITE (6), a length of 0 indicates a transfer of 256 sector. */
|
||||
dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) | (((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]);
|
||||
dev->sector_len = 256;
|
||||
dev->sector_pos = ((((uint32_t) cdb[1]) & 0x1f) << 16) |
|
||||
(((uint32_t) cdb[2]) << 8) | ((uint32_t) cdb[3]);
|
||||
break;
|
||||
case GPCMD_VERIFY_10:
|
||||
case GPCMD_WRITE_10:
|
||||
@@ -1604,17 +1602,17 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
case GPCMD_VERIFY_12:
|
||||
case GPCMD_WRITE_12:
|
||||
case GPCMD_WRITE_AND_VERIFY_12:
|
||||
dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) | (((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]);
|
||||
dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) | (((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]);
|
||||
dev->sector_len = (((uint32_t) cdb[6]) << 24) | (((uint32_t) cdb[7]) << 16) |
|
||||
(((uint32_t) cdb[8]) << 8) | ((uint32_t) cdb[9]);
|
||||
dev->sector_pos = (((uint32_t) cdb[2]) << 24) | (((uint32_t) cdb[3]) << 16) |
|
||||
(((uint32_t) cdb[4]) << 8) | ((uint32_t) cdb[5]);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if ((dev->sector_pos >= dev->drv->medium_size) /* ||
|
||||
((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)*/
|
||||
) {
|
||||
if (dev->sector_pos >= dev->drv->medium_size) {
|
||||
zip_lba_out_of_range(dev);
|
||||
return;
|
||||
}
|
||||
@@ -1629,9 +1627,13 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
}
|
||||
|
||||
max_len = dev->sector_len;
|
||||
dev->requested_blocks = max_len; /* If we're writing all blocks in one go for DMA, why not also for PIO, it should NOT
|
||||
matter anyway, this step should be identical and only the way the read dat is
|
||||
transferred to the host should be different. */
|
||||
/*
|
||||
If we're writing all blocks in one go for DMA, why not also for
|
||||
PIO, it should NOT matter anyway, this step should be identical
|
||||
and only the way the read dat is transferred to the host should
|
||||
be different.
|
||||
*/
|
||||
dev->requested_blocks = max_len;
|
||||
|
||||
dev->packet_len = max_len * alloc_length;
|
||||
zip_buf_alloc(dev, dev->packet_len);
|
||||
@@ -1643,10 +1645,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
|
||||
zip_data_command_finish(dev, dev->packet_len, 512, dev->packet_len, 1);
|
||||
|
||||
if (dev->packet_status != PHASE_COMPLETE)
|
||||
ui_sb_update_icon(SB_ZIP | dev->id, 1);
|
||||
else
|
||||
ui_sb_update_icon(SB_ZIP | dev->id, 0);
|
||||
ui_sb_update_icon(SB_ZIP | dev->id, dev->packet_status != PHASE_COMPLETE);
|
||||
return;
|
||||
|
||||
case GPCMD_WRITE_SAME_10:
|
||||
@@ -1665,9 +1664,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
dev->sector_len = (cdb[7] << 8) | cdb[8];
|
||||
dev->sector_pos = (cdb[2] << 24) | (cdb[3] << 16) | (cdb[4] << 8) | cdb[5];
|
||||
|
||||
if ((dev->sector_pos >= dev->drv->medium_size) /* ||
|
||||
((dev->sector_pos + dev->sector_len - 1) >= dev->drv->medium_size)*/
|
||||
) {
|
||||
if (dev->sector_pos >= dev->drv->medium_size) {
|
||||
zip_lba_out_of_range(dev);
|
||||
return;
|
||||
}
|
||||
@@ -1693,10 +1690,7 @@ zip_command(scsi_common_t *sc, uint8_t *cdb)
|
||||
|
||||
zip_data_command_finish(dev, 512, 512, alloc_length, 1);
|
||||
|
||||
if (dev->packet_status != PHASE_COMPLETE)
|
||||
ui_sb_update_icon(SB_ZIP | dev->id, 1);
|
||||
else
|
||||
ui_sb_update_icon(SB_ZIP | dev->id, 0);
|
||||
ui_sb_update_icon(SB_ZIP | dev->id, dev->packet_status != PHASE_COMPLETE);
|
||||
return;
|
||||
|
||||
case GPCMD_MODE_SENSE_6:
|
||||
@@ -2034,10 +2028,10 @@ atapi_out:
|
||||
}
|
||||
|
||||
#if 0
|
||||
zip_log("ZIP %i: Phase: %02X, request length: %i\n", dev->id, dev->phase, dev->request_length);
|
||||
zip_log("ZIP %i: Phase: %02X, request length: %i\n", dev->id, dev->tf->phase, dev->tf->request_length);
|
||||
#endif
|
||||
|
||||
if (zip_atapi_phase_to_scsi(dev) == SCSI_PHASE_STATUS)
|
||||
if ((dev->packet_status == PHASE_COMPLETE) || (dev->packet_status == PHASE_ERROR))
|
||||
zip_buf_free(dev);
|
||||
}
|
||||
|
||||
@@ -2321,6 +2315,9 @@ zip_drive_reset(int c)
|
||||
dev->cur_lun = SCSI_LUN_USE_CDB;
|
||||
|
||||
if (zip_drives[c].bus_type == ZIP_BUS_SCSI) {
|
||||
if (!dev->tf)
|
||||
dev->tf = (ide_tf_t *) calloc(1, sizeof(ide_tf_t));
|
||||
|
||||
/* SCSI ZIP, attach to the SCSI bus. */
|
||||
sd = &scsi_devices[scsi_bus][scsi_id];
|
||||
|
||||
@@ -2339,6 +2336,8 @@ zip_drive_reset(int c)
|
||||
that's not attached to anything. */
|
||||
if (id) {
|
||||
id->sc = (scsi_common_t *) dev;
|
||||
dev->tf = id->tf;
|
||||
IDE_ATAPI_IS_EARLY = 0;
|
||||
id->get_max = zip_get_max;
|
||||
id->get_timings = zip_get_timings;
|
||||
id->identify = zip_identify;
|
||||
@@ -2425,6 +2424,9 @@ zip_close(void)
|
||||
if (dev) {
|
||||
zip_disk_unload(dev);
|
||||
|
||||
if (dev->tf)
|
||||
free(dev->tf);
|
||||
|
||||
free(dev);
|
||||
zip_drives[c].priv = NULL;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user