Extensive rework of SCSI and ATAPI devices and numerous bug fixes and cleanups;

Extensive rework of CD-ROM image handling;
The settings save code now forces some devices' (SCSI disk, CD-ROM, etc.) pointers to NULL before resetting the machine - fixes segmentation faults after changing settings;
Added the NCR 53c825A and 53c875 SCSI controllers;
Fixed IDE/ATAPI DMA;
Slight changed to PCI IDE bus master operation.
This commit is contained in:
OBattler
2018-10-30 13:32:25 +01:00
parent 6410e0ac75
commit 3a8bd15b9d
31 changed files with 3116 additions and 3370 deletions

View File

@@ -9,7 +9,7 @@
* Implementation of the IDE emulation for hard disks and ATAPI
* CD-ROM devices.
*
* Version: @(#)hdc_ide.c 1.0.55 2018/10/25
* Version: @(#)hdc_ide.c 1.0.56 2018/10/28
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
@@ -109,7 +109,7 @@
#define FEATURE_DISABLE_IRQ_OVERLAPPED 0xdd
#define FEATURE_DISABLE_IRQ_SERVICE 0xde
#define IDE_PCI (PCI && pio_override && (ide->board < 2))
#define IDE_PCI (PCI && !pio_override && (ide->board < 2))
typedef struct {
@@ -379,7 +379,7 @@ static int
ide_get_max(ide_t *ide, int type)
{
if (ide_drive_is_atapi(ide))
return ide->get_max(!IDE_PCI, type);
return ide->get_max(IDE_PCI, type);
switch(type) {
case TYPE_PIO: /* PIO */
@@ -413,7 +413,7 @@ static int
ide_get_timings(ide_t *ide, int type)
{
if (ide_drive_is_atapi(ide))
return ide->get_timings(!IDE_PCI, type);
return ide->get_timings(IDE_PCI, type);
switch(type) {
case TIMINGS_DMA:
@@ -551,6 +551,8 @@ ide_identify(ide_t *ide)
max_sdma = ide_get_max(ide, TYPE_SDMA);
max_mdma = ide_get_max(ide, TYPE_MDMA);
max_udma = ide_get_max(ide, TYPE_UDMA);
ide_log("IDE %i: max_pio = %i, max_sdma = %i, max_mdma = %i, max_udma = %i\n",
ide->channel, max_pio, max_sdma, max_mdma, max_udma);
if (ide_boards[ide->board]->bit32)
ide->buffer[48] |= 1; /*Dword transfers supported*/
@@ -669,18 +671,17 @@ loadhd(ide_t *ide, int d, const wchar_t *fn)
void
ide_set_signature(ide_t *ide)
{
scsi_device_data_t *atapi = (scsi_device_data_t *) ide->p;
ide->sector=1;
ide->head=0;
if (ide_drive_is_atapi(ide)) {
ide->set_signature(ide->p);
ide->secount = atapi->phase;
ide->cylinder = atapi->request_length;
ide->sc->phase = 1;
ide->sc->request_length = 0xEB14;
ide->secount = ide->sc->phase;
ide->cylinder = ide->sc->request_length;
} else {
ide->secount=1;
ide->cylinder=((ide->type == IDE_HDD) ? 0 : 0xFFFF);
ide->secount = 1;
ide->cylinder = ((ide->type == IDE_HDD) ? 0 : 0xFFFF);
if (ide->type == IDE_HDD)
ide->drive = 0;
}
@@ -813,7 +814,6 @@ ide_board_close(int board)
{
ide_t *dev;
int c, d;
scsi_device_data_t *atapi;
/* Close hard disk image files (if previously open) */
for (d = 0; d < 2; d++) {
@@ -824,10 +824,8 @@ ide_board_close(int board)
hdd_image_close(dev->hdd_num);
if (board < 4) {
if (ide_drive_is_atapi(dev)) {
atapi = (scsi_device_data_t *) dev->p;
atapi->status = DRDY_STAT | DSC_STAT;
}
if (ide_drive_is_atapi(dev))
dev->sc->status = DRDY_STAT | DSC_STAT;
}
if (dev->buffer)
@@ -943,6 +941,164 @@ ide_set_callback(uint8_t board, int64_t callback)
}
/* This is the general ATAPI PIO request function. */
static void
ide_atapi_pio_request(ide_t *ide, uint8_t out)
{
scsi_common_t *dev = ide->sc;
ide_irq_lower(ide_drives[ide->board]);
dev->status = BSY_STAT;
if (dev->pos >= dev->packet_len) {
ide_log("%i bytes %s, command done\n", dev->pos, out ? "written" : "read");
dev->pos = dev->request_pos = 0;
if (out && ide->phase_data_out)
ide->phase_data_out(dev);
else if (ide->command_stop)
ide->command_stop(dev);
} else {
ide_log("%i bytes %s, %i bytes are still left\n", dev->pos,
out ? "written" : "read", dev->packet_len - dev->pos);
/* If less than (packet length) bytes are remaining, update packet length
accordingly. */
if ((dev->packet_len - dev->pos) < (dev->max_transfer_len))
dev->max_transfer_len = dev->packet_len - dev->pos;
ide_log("CD-ROM %i: Packet length %i, request length %i\n", dev->id, dev->packet_len,
dev->max_transfer_len);
dev->packet_status = out ? PHASE_DATA_OUT : PHASE_DATA_IN;
dev->status = BSY_STAT;
dev->phase = 1;
if (ide->packet_callback)
ide->packet_callback(dev);
dev->callback = 0LL;
ide_set_callback(ide->board >> 1, dev->callback);
dev->request_pos = 0;
}
}
static uint32_t
ide_atapi_packet_read(ide_t *ide, int length)
{
scsi_common_t *dev = ide->sc;
uint16_t *bufferw;
uint32_t *bufferl;
uint32_t temp = 0;
if (!dev || !dev->temp_buffer || (dev->packet_status != PHASE_DATA_IN))
return 0;
bufferw = (uint16_t *) dev->temp_buffer;
bufferl = (uint32_t *) dev->temp_buffer;
/* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it,
which can happen when issuing media access commands with an allocated length below minimum request length
(which is 1 sector = 2048 bytes). */
switch(length) {
case 1:
temp = (dev->pos < dev->packet_len) ? dev->temp_buffer[dev->pos] : 0;
dev->pos++;
dev->request_pos++;
break;
case 2:
temp = (dev->pos < dev->packet_len) ? bufferw[dev->pos >> 1] : 0;
dev->pos += 2;
dev->request_pos += 2;
break;
case 4:
temp = (dev->pos < dev->packet_len) ? bufferl[dev->pos >> 2] : 0;
dev->pos += 4;
dev->request_pos += 4;
break;
default:
return 0;
}
if (dev->packet_status == PHASE_DATA_IN) {
if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) {
/* Time for a DRQ. */
ide_atapi_pio_request(ide, 0);
}
return temp;
} else
return 0;
}
static void
ide_atapi_packet_write(ide_t *ide, uint32_t val, int length)
{
scsi_common_t *dev = ide->sc;
uint8_t *bufferb;
uint16_t *bufferw;
uint32_t *bufferl;
if (!dev)
return;
if (dev->packet_status == PHASE_IDLE)
bufferb = dev->atapi_cdb;
else {
if (dev->temp_buffer)
bufferb = dev->temp_buffer;
else
return;
}
bufferw = (uint16_t *) bufferb;
bufferl = (uint32_t *) bufferb;
switch(length) {
case 1:
bufferb[dev->pos] = val & 0xff;
dev->pos++;
dev->request_pos++;
break;
case 2:
bufferw[dev->pos >> 1] = val & 0xffff;
dev->pos += 2;
dev->request_pos += 2;
break;
case 4:
bufferl[dev->pos >> 2] = val;
dev->pos += 4;
dev->request_pos += 4;
break;
default:
return;
}
if (dev->packet_status == PHASE_DATA_OUT) {
if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) {
/* Time for a DRQ. */
ide_atapi_pio_request(ide, 1);
}
return;
} else if (dev->packet_status == PHASE_IDLE) {
if (dev->pos >= 12) {
dev->pos = 0;
dev->status = BSY_STAT;
dev->packet_status = PHASE_COMMAND;
timer_process();
if (ide->packet_callback)
ide->packet_callback(dev);
timer_update_outstanding();
}
return;
}
}
void
ide_write_data(ide_t *ide, uint32_t val, int length)
{
@@ -957,7 +1113,7 @@ ide_write_data(ide_t *ide, uint32_t val, int length)
return;
if (ide_drive_is_atapi(ide))
ide->packet_write(ide->p, val, length);
ide_atapi_packet_write(ide, val, length);
return;
} else {
switch(length) {
@@ -1048,7 +1204,6 @@ void
ide_write_devctl(uint16_t addr, uint8_t val, void *priv)
{
ide_board_t *dev = (ide_board_t *) priv;
scsi_device_data_t *atapi;
ide_t *ide, *ide_other;
int ch;
@@ -1060,11 +1215,9 @@ ide_write_devctl(uint16_t addr, uint8_t val, void *priv)
ide_log("ide_write_devctl %04X %02X from %04X(%08X):%08X\n", addr, val, CS, cs, cpu_state.pc);
if ((ide->fdisk & 4) && !(val&4) && (ide->type != IDE_NONE || ide_other->type != IDE_NONE)) {
atapi = (scsi_device_data_t *) ide->p;
timer_process();
if (ide_drive_is_atapi(ide))
atapi->callback = 0LL;
ide->sc->callback = 0LL;
ide_set_callback(ide->board, 500LL * IDE_TIME);
timer_update_outstanding();
@@ -1073,7 +1226,7 @@ ide_write_devctl(uint16_t addr, uint8_t val, void *priv)
if (ide_other->type != IDE_NONE)
ide->reset = 1;
if (ide_drive_is_atapi(ide))
atapi->status = BSY_STAT;
ide->sc->status = BSY_STAT;
ide->atastat = ide_other->atastat = BSY_STAT;
}
@@ -1093,7 +1246,6 @@ void
ide_writeb(uint16_t addr, uint8_t val, void *priv)
{
ide_board_t *dev = (ide_board_t *) priv;
scsi_device_data_t *atapi, *atapi_other;
ide_t *ide, *ide_other;
int ch;
@@ -1109,9 +1261,6 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
if ((ide->type == IDE_NONE) && ((addr == 0x0) || (addr == 0x7)))
return;
atapi = (scsi_device_data_t *) ide->p;
atapi_other = (scsi_device_data_t *) ide_other->p;
switch (addr) {
case 0x0: /* Data */
ide_write_data(ide, val | (val << 8), 2);
@@ -1121,25 +1270,25 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
case 0x1: /* Features */
if (ide_drive_is_atapi(ide)) {
ide_log("ATAPI transfer mode: %s\n", (val & 1) ? "DMA" : "PIO");
atapi->features = val;
ide->sc->features = val;
}
ide->cylprecomp = val;
if (ide_drive_is_atapi(ide_other))
atapi_other->features = val;
ide_other->sc->features = val;
ide_other->cylprecomp = val;
return;
case 0x2: /* Sector count */
if (ide_drive_is_atapi(ide)) {
ide_log("Sector count write: %i\n", val);
atapi->phase = val;
ide->sc->phase = val;
}
ide->secount = val;
if (ide_drive_is_atapi(ide_other)) {
ide_log("Other sector count write: %i\n", val);
atapi_other->phase = val;
ide_other->sc->phase = val;
}
ide_other->secount = val;
return;
@@ -1153,15 +1302,15 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
case 0x4: /* Cylinder low */
if (ide_drive_is_atapi(ide)) {
atapi->request_length &= 0xFF00;
atapi->request_length |= val;
ide->sc->request_length &= 0xFF00;
ide->sc->request_length |= val;
}
ide->cylinder = (ide->cylinder & 0xFF00) | val;
ide->lba_addr = (ide->lba_addr & 0xFFF00FF) | (val << 8);
if (ide_drive_is_atapi(ide_other)) {
atapi_other->request_length &= 0xFF00;
atapi_other->request_length |= val;
ide_other->sc->request_length &= 0xFF00;
ide_other->sc->request_length |= val;
}
ide_other->cylinder = (ide_other->cylinder & 0xFF00) | val;
ide_other->lba_addr = (ide_other->lba_addr & 0xFFF00FF) | (val << 8);
@@ -1169,15 +1318,15 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
case 0x5: /* Cylinder high */
if (ide_drive_is_atapi(ide)) {
atapi->request_length &= 0xFF;
atapi->request_length |= (val << 8);
ide->sc->request_length &= 0xFF;
ide->sc->request_length |= (val << 8);
}
ide->cylinder = (ide->cylinder & 0xFF) | (val << 8);
ide->lba_addr = (ide->lba_addr & 0xF00FFFF) | (val << 16);
if (ide_drive_is_atapi(ide_other)) {
atapi_other->request_length &= 0xFF;
atapi_other->request_length |= (val << 8);
ide_other->sc->request_length &= 0xFF;
ide_other->sc->request_length |= (val << 8);
}
ide_other->cylinder = (ide_other->cylinder & 0xFF) | (val << 8);
ide_other->lba_addr = (ide_other->lba_addr & 0xF00FFFF) | (val << 16);
@@ -1198,20 +1347,20 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
ide->reset = ide_other->reset = 0;
if (ide_drive_is_atapi(ide)) {
atapi->status = DRDY_STAT | DSC_STAT;
atapi->error = 1;
atapi->phase = 1;
atapi->request_length = 0xEB14;
atapi->callback = 0LL;
ide->sc->status = DRDY_STAT | DSC_STAT;
ide->sc->error = 1;
ide->sc->phase = 1;
ide->sc->request_length = 0xEB14;
ide->sc->callback = 0LL;
ide->cylinder = 0xEB14;
}
if (ide_drive_is_atapi(ide_other)) {
atapi_other->status = DRDY_STAT | DSC_STAT;
atapi_other->error = 1;
atapi_other->phase = 1;
atapi_other->request_length = 0xEB14;
atapi_other->callback = 0LL;
ide_other->sc->status = DRDY_STAT | DSC_STAT;
ide_other->sc->error = 1;
ide_other->sc->phase = 1;
ide_other->sc->request_length = 0xEB14;
ide_other->sc->callback = 0LL;
ide->cylinder = 0xEB14;
}
@@ -1241,17 +1390,17 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
ide->error=0;
if (ide_drive_is_atapi(ide))
atapi->error = 0;
ide->sc->error = 0;
if (((val >= WIN_RECAL) && (val <= 0x1F)) || ((val >= WIN_SEEK) && (val <= 0x7F))) {
if (ide_drive_is_atapi(ide))
atapi->status = DRDY_STAT;
ide->sc->status = DRDY_STAT;
else
ide->atastat = BSY_STAT;
timer_process();
if (ide_drive_is_atapi(ide))
atapi->callback = 100LL * IDE_TIME;
ide->sc->callback = 100LL * IDE_TIME;
ide_set_callback(ide->board, 100LL * IDE_TIME);
timer_update_outstanding();
return;
@@ -1260,13 +1409,13 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
switch (val) {
case WIN_SRST: /* ATAPI Device Reset */
if (ide_drive_is_atapi(ide))
atapi->status = BSY_STAT;
ide->sc->status = BSY_STAT;
else
ide->atastat = DRDY_STAT;
timer_process();
if (ide_drive_is_atapi(ide))
atapi->callback = 100LL * IDE_TIME;
ide->sc->callback = 100LL * IDE_TIME;
ide_set_callback(ide->board, 100LL * IDE_TIME);
timer_update_outstanding();
return;
@@ -1287,13 +1436,13 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
case WIN_READ_DMA:
case WIN_READ_DMA_ALT:
if (ide_drive_is_atapi(ide))
atapi->status = BSY_STAT;
ide->sc->status = BSY_STAT;
else
ide->atastat = BSY_STAT;
timer_process();
if (ide_drive_is_atapi(ide))
atapi->callback = 200LL * IDE_TIME;
ide->sc->callback = 200LL * IDE_TIME;
if (ide->type == IDE_HDD) {
if ((val == WIN_READ_DMA) || (val == WIN_READ_DMA_ALT)) {
@@ -1320,8 +1469,8 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
case WIN_WRITE:
case WIN_WRITE_NORETRY:
if (ide_drive_is_atapi(ide)) {
atapi->status = DRQ_STAT | DSC_STAT | DRDY_STAT;
atapi->pos = 0;
ide->sc->status = DRQ_STAT | DSC_STAT | DRDY_STAT;
ide->sc->pos = 0;
} else {
ide->atastat = DRQ_STAT | DSC_STAT | DRDY_STAT;
ide->pos=0;
@@ -1336,13 +1485,13 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
case WIN_SET_FEATURES: /* Set Features */
case WIN_READ_NATIVE_MAX:
if (ide_drive_is_atapi(ide))
atapi->status = BSY_STAT;
ide->sc->status = BSY_STAT;
else
ide->atastat = BSY_STAT;
timer_process();
if (ide_drive_is_atapi(ide))
atapi->callback = 200LL * IDE_TIME;
ide->sc->callback = 200LL * IDE_TIME;
if ((ide->type == IDE_HDD) &&
((val == WIN_WRITE_DMA) || (val == WIN_WRITE_DMA_ALT))) {
if (ide->secount)
@@ -1368,31 +1517,31 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
case WIN_SPECIFY: /* Initialize Drive Parameters */
if (ide_drive_is_atapi(ide))
atapi->status = BSY_STAT;
ide->sc->status = BSY_STAT;
else
ide->atastat = BSY_STAT;
timer_process();
if (ide_drive_is_atapi(ide))
atapi->callback = 30LL * IDE_TIME;
ide->sc->callback = 30LL * IDE_TIME;
ide_set_callback(ide->board, 30LL * IDE_TIME);
timer_update_outstanding();
return;
case WIN_DRIVE_DIAGNOSTICS: /* Execute Drive Diagnostics */
if (ide_drive_is_atapi(ide))
atapi->status = BSY_STAT;
ide->sc->status = BSY_STAT;
else
ide->atastat = BSY_STAT;
if (ide_drive_is_atapi(ide_other))
atapi_other->status = BSY_STAT;
ide_other->sc->status = BSY_STAT;
else
ide_other->atastat = BSY_STAT;
timer_process();
if (ide_drive_is_atapi(ide))
atapi->callback = 200LL * IDE_TIME;
ide->sc->callback = 200LL * IDE_TIME;
ide_set_callback(ide->board, 200LL * IDE_TIME);
timer_update_outstanding();
return;
@@ -1406,7 +1555,7 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
case WIN_CHECKPOWERMODE1:
case WIN_SLEEP1:
if (ide_drive_is_atapi(ide))
atapi->status = BSY_STAT;
ide->sc->status = BSY_STAT;
else
ide->atastat = BSY_STAT;
timer_process();
@@ -1417,10 +1566,10 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
case WIN_PACKETCMD: /* ATAPI Packet */
/* Skip the command callback wait, and process immediately. */
if (ide_drive_is_atapi(ide)) {
atapi->packet_status = PHASE_IDLE;
atapi->pos = 0;
atapi->phase = 1;
atapi->status = DRDY_STAT | DRQ_STAT;
ide->sc->packet_status = PHASE_IDLE;
ide->sc->pos = 0;
ide->sc->phase = 1;
ide->sc->status = DRDY_STAT | DRQ_STAT;
if (ide->interrupt_drq)
ide_irq_raise(ide); /* Interrupt DRQ, requires IRQ on any DRQ. */
} else {
@@ -1436,8 +1585,8 @@ ide_writeb(uint16_t addr, uint8_t val, void *priv)
default:
ide_bad_command:
if (ide_drive_is_atapi(ide)) {
atapi->status = DRDY_STAT | ERR_STAT | DSC_STAT;
atapi->error = ABRT_ERR;
ide->sc->status = DRDY_STAT | ERR_STAT | DSC_STAT;
ide->sc->error = ABRT_ERR;
} else {
ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT;
ide->error = ABRT_ERR;
@@ -1453,7 +1602,6 @@ ide_bad_command:
static uint32_t
ide_read_data(ide_t *ide, int length)
{
scsi_device_data_t *atapi = (scsi_device_data_t *) ide->p;
uint32_t temp = 0;
if (!ide->buffer) {
@@ -1476,7 +1624,7 @@ ide_read_data(ide_t *ide, int length)
if (ide->command == WIN_PACKETCMD) {
ide->pos = 0;
if (ide_drive_is_atapi(ide))
temp = ide->packet_read(ide->p, length);
temp = ide_atapi_packet_read(ide, length);
else {
ide_log("Drive not ATAPI (position: %i)\n", ide->pos);
return 0;
@@ -1503,8 +1651,8 @@ ide_read_data(ide_t *ide, int length)
ide->pos = 0;
ide->atastat = DRDY_STAT | DSC_STAT;
if (ide_drive_is_atapi(ide)) {
atapi->status = DRDY_STAT | DSC_STAT;
atapi->packet_status = PHASE_IDLE;
ide->sc->status = DRDY_STAT | DSC_STAT;
ide->sc->packet_status = PHASE_IDLE;
}
if ((ide->command == WIN_READ) || (ide->command == WIN_READ_NORETRY) || (ide->command == WIN_READ_MULTIPLE)) {
ide->secount = (ide->secount - 1) & 0xff;
@@ -1517,10 +1665,8 @@ ide_read_data(ide_t *ide, int length)
else
ide_set_callback(ide->board, ide_get_period(ide, 512));
timer_update_outstanding();
} else {
if (ide->command != WIN_READ_MULTIPLE)
ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0);
}
} else if (ide->command != WIN_READ_MULTIPLE)
ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0);
}
}
@@ -1531,13 +1677,11 @@ ide_read_data(ide_t *ide, int length)
static uint8_t
ide_status(ide_t *ide, int ch)
{
scsi_device_data_t *atapi = (scsi_device_data_t *) ide->p;
if (ide->type == IDE_NONE)
return 0;
else {
if (ide_drive_is_atapi(ide))
return (atapi->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0);
return (ide->sc->status & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0);
else
return ide->atastat;
}
@@ -1547,7 +1691,6 @@ ide_status(ide_t *ide, int ch)
uint8_t
ide_readb(uint16_t addr, void *priv)
{
scsi_device_data_t *atapi;
ide_board_t *dev = (ide_board_t *) priv;
int ch;
@@ -1555,7 +1698,6 @@ ide_readb(uint16_t addr, void *priv)
ch = dev->cur_dev;
ide = ide_drives[ch];
atapi = (scsi_device_data_t *) ide->p;
uint8_t temp = 0xff;
uint16_t tempw;
@@ -1577,7 +1719,7 @@ ide_readb(uint16_t addr, void *priv)
temp = 0;
else {
if (ide_drive_is_atapi(ide))
temp = atapi->error;
temp = ide->sc->error;
else
temp = ide->error;
}
@@ -1598,7 +1740,7 @@ ide_readb(uint16_t addr, void *priv)
1 0 1 Status. */
case 0x2: /* Sector count */
if (ide_drive_is_atapi(ide))
temp = atapi->phase;
temp = ide->sc->phase;
else
temp = ide->secount;
break;
@@ -1612,7 +1754,7 @@ ide_readb(uint16_t addr, void *priv)
temp = 0xFF;
else {
if (ide_drive_is_atapi(ide))
temp = atapi->request_length & 0xff;
temp = ide->sc->request_length & 0xff;
else
temp = ide->cylinder & 0xff;
}
@@ -1623,7 +1765,7 @@ ide_readb(uint16_t addr, void *priv)
temp = 0xFF;
else {
if (ide_drive_is_atapi(ide))
temp = atapi->request_length >> 8;
temp = ide->sc->request_length >> 8;
else
temp = ide->cylinder >> 8;
}
@@ -1725,13 +1867,10 @@ ide_callback(void *priv)
int snum, ret, ch;
ide_board_t *dev = (ide_board_t *) priv;
scsi_device_data_t *atapi, *atapi_other;
ch = dev->cur_dev;
ide = ide_drives[ch];
atapi = (scsi_device_data_t *) ide->p;
ide_other = ide_drives[ch ^ 1];
atapi_other = (scsi_device_data_t *) ide_other->p;
ide_set_callback(ide->board, 0LL);
@@ -1752,18 +1891,18 @@ ide_callback(void *priv)
ide_set_signature(ide);
if (ide_drive_is_atapi(ide)) {
atapi->status = DRDY_STAT | DSC_STAT;
atapi->error = 1;
ide->sc->status = DRDY_STAT | DSC_STAT;
ide->sc->error = 1;
if (ide->stop)
ide->stop(ide->p);
ide->stop(ide->sc);
}
ide_set_signature(ide_other);
if (ide_drive_is_atapi(ide_other)) {
atapi_other->status = DRDY_STAT | DSC_STAT;
atapi_other->error = 1;
ide_other->sc->status = DRDY_STAT | DSC_STAT;
ide_other->sc->error = 1;
if (ide_other->stop)
ide_other->stop(ide_other->p);
ide_other->stop(ide_other->sc);
}
return;
@@ -1798,10 +1937,10 @@ ide_callback(void *priv)
ide_set_signature(ide);
if (ide_drive_is_atapi(ide)) {
atapi->status = DRDY_STAT | DSC_STAT;
atapi->error = 1;
ide->sc->status = DRDY_STAT | DSC_STAT;
ide->sc->error = 1;
if (ide->device_reset)
ide->device_reset(ide->p);
ide->device_reset(ide->sc);
}
ide_irq_raise(ide);
if (ide_drive_is_atapi(ide))
@@ -1813,7 +1952,7 @@ ide_callback(void *priv)
case WIN_IDLENOW1:
case WIN_SETIDLE1:
if (ide_drive_is_atapi(ide))
atapi->status = DRDY_STAT | DSC_STAT;
ide->sc->status = DRDY_STAT | DSC_STAT;
else
ide->atastat = DRDY_STAT | DSC_STAT;
ide_irq_raise(ide);
@@ -1822,8 +1961,8 @@ ide_callback(void *priv)
case WIN_CHECKPOWERMODE1:
case WIN_SLEEP1:
if (ide_drive_is_atapi(ide)) {
atapi->phase = 0xFF;
atapi->status = DRDY_STAT | DSC_STAT;
ide->sc->phase = 0xFF;
ide->sc->status = DRDY_STAT | DSC_STAT;
}
ide->secount = 0xFF;
ide->atastat = DRDY_STAT | DSC_STAT;
@@ -1891,10 +2030,6 @@ ide_callback(void *priv)
ide_set_callback(ide->board, 6LL * IDE_TIME);
return;
} else if (ret == 1) {
/* Bus master DMAS error, abort the command. */
ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel);
goto abort_cmd;
} else {
/*DMA successful*/
ide_log("IDE %i: DMA read successful\n", ide->channel);
@@ -1902,6 +2037,10 @@ ide_callback(void *priv)
ide_irq_raise(ide);
ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0);
} else {
/* Bus master DMAS error, abort the command. */
ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel);
goto abort_cmd;
}
} else {
ide_log("IDE %i: DMA read aborted (no bus master)\n", ide->channel);
@@ -1974,7 +2113,7 @@ ide_callback(void *priv)
goto id_not_found;
}
if (ide_bus_master_read) {
if (ide_bus_master_write) {
if (ide->secount)
ide->sector_pos = ide->secount;
else
@@ -1990,10 +2129,6 @@ ide_callback(void *priv)
ide_set_callback(ide->board, 6LL * IDE_TIME);
return;
} else if (ret == 1) {
/* Bus master DMA error, abort the command. */
ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel);
goto abort_cmd;
} else {
/*DMA successful*/
ide_log("IDE %i: DMA write successful\n", ide->channel);
@@ -2003,6 +2138,10 @@ ide_callback(void *priv)
ide_irq_raise(ide);
ui_sb_update_icon(SB_HDD | hdd[ide->hdd_num].bus, 0);
} else {
/* Bus master DMA error, abort the command. */
ide_log("IDE %i: DMA read aborted (failed)\n", ide->channel);
goto abort_cmd;
}
} else {
ide_log("IDE %i: DMA write aborted (no bus master)\n", ide->channel);
@@ -2060,11 +2199,11 @@ ide_callback(void *priv)
case WIN_DRIVE_DIAGNOSTICS:
ide_set_signature(ide);
ide->error=1; /*No error detected*/
ide->error = 1; /*No error detected*/
if (ide_drive_is_atapi(ide)) {
atapi->status = 0;
atapi->error = 1;
ide->sc->status = 0;
ide->sc->error = 1;
ide_irq_raise(ide);
} else {
ide->atastat = DRDY_STAT | DSC_STAT;
@@ -2073,11 +2212,11 @@ ide_callback(void *priv)
}
ide_set_signature(ide_other);
ide_other->error=1; /*No error detected*/
ide_other->error = 1; /*No error detected*/
if (ide_drive_is_atapi(ide_other)) {
atapi_other->status = 0;
atapi_other->error = 1;
ide_other->sc->status = 0;
ide_other->sc->error = 1;
} else {
ide_other->atastat = DRDY_STAT | DSC_STAT;
ide_other->error = 1;
@@ -2105,10 +2244,10 @@ ide_callback(void *priv)
if (ide_drive_is_atapi(ide)) {
ide_identify(ide);
ide->pos = 0;
atapi->phase = 2;
atapi->pos = 0;
atapi->error = 0;
atapi->status = DRQ_STAT | DRDY_STAT | DSC_STAT;
ide->sc->phase = 2;
ide->sc->pos = 0;
ide->sc->error = 0;
ide->sc->status = DRQ_STAT | DRDY_STAT | DSC_STAT;
ide_irq_raise(ide);
return;
}
@@ -2123,19 +2262,16 @@ ide_callback(void *priv)
return;
case WIN_SET_FEATURES:
if (ide->type == IDE_NONE)
if ((ide->type == IDE_NONE) || !ide_set_features(ide))
goto abort_cmd;
if (!ide_set_features(ide))
goto abort_cmd;
else {
if (ide_drive_is_atapi(ide)) {
atapi->status = DRDY_STAT | DSC_STAT;
atapi->pos = 0;
}
ide->atastat = DRDY_STAT | DSC_STAT;
ide_irq_raise(ide);
if (ide_drive_is_atapi(ide)) {
ide->sc->status = DRDY_STAT | DSC_STAT;
ide->sc->pos = 0;
}
ide->atastat = DRDY_STAT | DSC_STAT;
ide_irq_raise(ide);
return;
case WIN_READ_NATIVE_MAX:
@@ -2165,7 +2301,7 @@ ide_callback(void *priv)
if (!ide_drive_is_atapi(ide) || !ide->packet_callback)
goto abort_cmd;
ide->packet_callback(ide->p);
ide->packet_callback(ide->sc);
return;
case 0xFF:
@@ -2175,9 +2311,9 @@ ide_callback(void *priv)
abort_cmd:
ide->command = 0;
if (ide_drive_is_atapi(ide)) {
atapi->status = DRDY_STAT | ERR_STAT | DSC_STAT;
atapi->error = ABRT_ERR;
atapi->pos = 0;
ide->sc->status = DRDY_STAT | ERR_STAT | DSC_STAT;
ide->sc->error = ABRT_ERR;
ide->sc->pos = 0;
} else {
ide->atastat = DRDY_STAT | ERR_STAT | DSC_STAT;
ide->error = ABRT_ERR;

View File

@@ -9,7 +9,7 @@
* Implementation of the IDE emulation for hard disks and ATAPI
* CD-ROM devices.
*
* Version: @(#)hdd_ide.h 1.0.12 2018/10/10
* Version: @(#)hdd_ide.h 1.0.13 2018/10/28
*
* Authors: Sarah Walker, <http://pcem-emulator.co.uk/>
* Miran Grca, <mgrca8@gmail.com>
@@ -27,7 +27,8 @@ enum
IDE_ATAPI
};
typedef struct {
#ifdef SCSI_DEVICE_H
typedef struct ide_s {
uint8_t atastat, error,
command, fdisk;
int type, board,
@@ -49,19 +50,19 @@ typedef struct {
uint8_t *sector_buffer;
/* Stuff mostly used by ATAPI */
void *p;
scsi_common_t *sc;
int interrupt_drq;
int (*get_max)(int ide_has_dma, int type);
int (*get_timings)(int ide_has_dma, int type);
void (*identify)(void *p, int ide_has_dma);
void (*set_signature)(void *p);
void (*packet_write)(void *p, uint32_t val, int length);
uint32_t (*packet_read)(void *p, int length);
void (*stop)(void *p);
void (*packet_callback)(void *p);
void (*device_reset)(void *p);
void (*identify)(struct ide_s *ide, int ide_has_dma);
void (*stop)(scsi_common_t *sc);
void (*packet_callback)(scsi_common_t *sc);
void (*device_reset)(scsi_common_t *sc);
uint8_t (*phase_data_out)(scsi_common_t *sc);
void (*command_stop)(scsi_common_t *sc);
} ide_t;
#endif
/* Type:
0 = PIO,
@@ -95,12 +96,18 @@ enum {
extern int ideboard;
extern int ide_ter_enabled, ide_qua_enabled;
#ifdef SCSI_DEVICE_H
extern ide_t *ide_drives[IDE_NUM];
#endif
extern int64_t idecallback[5];
#ifdef SCSI_DEVICE_H
extern void ide_irq_raise(ide_t *ide);
extern void ide_irq_lower(ide_t *ide);
extern void ide_allocate_buffer(ide_t *dev);
extern void ide_atapi_attach(ide_t *dev);
#endif
extern void * ide_xtide_init(void);
extern void ide_xtide_close(void);
@@ -140,8 +147,6 @@ extern void (*ide_bus_master_set_irq)(int channel, void *priv);
extern void *ide_bus_master_priv[2];
extern void ide_enable_pio_override(void);
extern void ide_allocate_buffer(ide_t *dev);
extern void ide_atapi_attach(ide_t *dev);
#endif /*EMU_IDE_H*/

View File

@@ -8,7 +8,7 @@
*
* Definitions for the hard disk image handler.
*
* Version: @(#)hdd.h 1.0.7 2018/10/26
* Version: @(#)hdd.h 1.0.8 2018/10/28
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
@@ -74,30 +74,28 @@ enum {
/* Define the virtual Hard Disk. */
typedef struct {
int8_t is_hdi; /* image type (should rename) */
int8_t wp; /* disk has been mounted READ-ONLY */
uint8_t bus;
uint8_t mfm_channel; /* should rename and/or unionize */
uint8_t id;
uint8_t mfm_channel; /* Should rename and/or unionize */
uint8_t esdi_channel;
uint8_t xta_channel;
uint8_t ide_channel;
uint8_t scsi_id;
uint8_t bus,
res; /* Reserved for bus mode */
uint8_t wp; /* Disk has been mounted READ-ONLY */
uint8_t pad, pad0;
uint32_t base,
spt,
hpc, /* physical geometry parameters */
tracks,
at_spt, /* [Translation] parameters */
at_hpc;
FILE *f; /* Current file handle to image */
void *priv;
FILE *f; /* current file handle to image */
wchar_t fn[1024], /* Name of current image file */
prev_fn[1024]; /* Name of previous image file */
wchar_t fn[260]; /* name of current image file */
wchar_t prev_fn[260]; /* name of previous image file */
uint32_t res0, pad1,
base,
spt,
hpc, /* Physical geometry parameters */
tracks;
} hard_disk_t;
@@ -147,7 +145,6 @@ extern int hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count);
extern uint32_t hdd_image_get_last_sector(uint8_t id);
extern uint32_t hdd_image_get_pos(uint8_t id);
extern uint8_t hdd_image_get_type(uint8_t id);
extern void hdd_image_specify(uint8_t id, uint64_t hpc, uint64_t spt);
extern void hdd_image_unload(uint8_t id, int fn_preserve);
extern void hdd_image_close(uint8_t id);
extern void hdd_image_calc_chs(uint32_t *c, uint32_t *h, uint32_t *s, uint32_t size);

View File

@@ -8,7 +8,7 @@
*
* Handling of hard disk image files.
*
* Version: @(#)hdd_image.c 1.0.19 2018/10/17
* Version: @(#)hdd_image.c 1.0.20 2018/10/28
*
* Authors: Miran Grca, <mgrca8@gmail.com>
* Fred N. van Kempen, <decwiz@yahoo.com>
@@ -182,14 +182,14 @@ image_is_vhd(const wchar_t *s, int check_signature)
static uint64_t
be_to_u64(uint8_t *bytes, int start)
{
uint64_t n = ((uint64_t)bytes[start+7] << 0) |
((uint64_t)bytes[start+6] << 8) |
((uint64_t)bytes[start+5] << 16) |
((uint64_t)bytes[start+4] << 24) |
((uint64_t)bytes[start+3] << 32) |
((uint64_t)bytes[start+2] << 40) |
((uint64_t)bytes[start+1] << 48) |
((uint64_t)bytes[start] << 56);
uint64_t n = ((uint64_t) bytes[start + 7] << 0) |
((uint64_t) bytes[start + 6] << 8) |
((uint64_t) bytes[start + 5] << 16) |
((uint64_t) bytes[start + 4] << 24) |
((uint64_t) bytes[start + 3] << 32) |
((uint64_t) bytes[start + 2] << 40) |
((uint64_t) bytes[start + 1] << 48) |
((uint64_t) bytes[start ] << 56);
return n;
}
@@ -197,10 +197,10 @@ be_to_u64(uint8_t *bytes, int start)
static uint32_t
be_to_u32(uint8_t *bytes, int start)
{
uint32_t n = ((uint32_t)bytes[start+3] << 0) |
((uint32_t)bytes[start+2] << 8) |
((uint32_t)bytes[start+1] << 16) |
((uint32_t)bytes[start] << 24);
uint32_t n = ((uint32_t) bytes[start + 3] << 0) |
((uint32_t) bytes[start + 2] << 8) |
((uint32_t) bytes[start + 1] << 16) |
((uint32_t) bytes[start ] << 24);
return n;
}
@@ -208,8 +208,8 @@ be_to_u32(uint8_t *bytes, int start)
static uint16_t
be_to_u16(uint8_t *bytes, int start)
{
uint16_t n = ((uint16_t)bytes[start+1] << 0) |
((uint16_t)bytes[start] <<8);
uint16_t n = ((uint16_t) bytes[start + 1] << 0) |
((uint16_t) bytes[start ] << 8);
return n;
}
@@ -222,11 +222,11 @@ u64_to_be(uint64_t value, int is_be)
res = value;
else {
uint64_t mask = 0xff00000000000000;
res = ((value & (mask >> 0)) >> 56) |
((value & (mask >> 8)) >> 40) |
res = ((value & (mask >> 0)) >> 56) |
((value & (mask >> 8)) >> 40) |
((value & (mask >> 16)) >> 24) |
((value & (mask >> 24)) >> 8) |
((value & (mask >> 32)) << 8) |
((value & (mask >> 24)) >> 8) |
((value & (mask >> 32)) << 8) |
((value & (mask >> 40)) << 24) |
((value & (mask >> 48)) << 40) |
((value & (mask >> 56)) << 56);
@@ -243,9 +243,9 @@ u32_to_be(uint32_t value, int is_be)
res = value;
else {
uint32_t mask = 0xff000000;
res = ((value & (mask >> 0)) >> 24) |
((value & (mask >> 8)) >> 8) |
((value & (mask >> 16)) << 8) |
res = ((value & (mask >> 0)) >> 24) |
((value & (mask >> 8)) >> 8) |
((value & (mask >> 16)) << 8) |
((value & (mask >> 24)) << 24);
}
return res;
@@ -286,7 +286,7 @@ calc_vhd_timestamp()
time_t start_time;
time_t curr_time;
double vhd_time;
start_time = 946684800; /* 1 Jan 2000 00:00 */
start_time = 946684800; /* 1 Jan 2000 00:00 */
curr_time = time(NULL);
vhd_time = difftime(curr_time, start_time);
@@ -498,6 +498,25 @@ hdd_image_init(void)
}
static void
hdd_image_gen_vft(int id, vhd_footer_t **vft, uint64_t full_size)
{
/* Generate new footer. */
new_vhd_footer(vft);
(*vft)->orig_size = (*vft)->curr_size = full_size;
(*vft)->geom.cyl = hdd[id].tracks;
(*vft)->geom.heads = hdd[id].hpc;
(*vft)->geom.spt = hdd[id].spt;
generate_vhd_checksum(*vft);
vhd_footer_to_bytes((uint8_t *) empty_sector, *vft);
fseeko64(hdd_images[id].file, 0, SEEK_END);
fwrite(empty_sector, 1, 512, hdd_images[id].file);
free(*vft);
*vft = NULL;
hdd_images[id].type = 3;
}
int
hdd_image_load(int id)
{
@@ -601,23 +620,7 @@ hdd_image_load(int id)
if (is_vhd[0]) {
/* VHD image. */
/* Generate new footer. */
empty_sector_1mb = (char *) malloc(512);
new_vhd_footer(&vft);
vft->orig_size = vft->curr_size = full_size;
vft->geom.cyl = hdd[id].tracks;
vft->geom.heads = hdd[id].hpc;
vft->geom.spt = hdd[id].spt;
generate_vhd_checksum(vft);
memset(empty_sector_1mb, 0, 512);
vhd_footer_to_bytes((uint8_t *) empty_sector_1mb, vft);
fseeko64(hdd_images[id].file, 0, SEEK_END);
fwrite(empty_sector_1mb, 1, 512, hdd_images[id].file);
free(vft);
vft = NULL;
free(empty_sector_1mb);
empty_sector_1mb = NULL;
hdd_images[id].type = 3;
hdd_image_gen_vft(id, &vft, full_size);
}
return ret;
@@ -671,23 +674,17 @@ hdd_image_load(int id)
hdd[id].spt = spt;
hdd[id].hpc = hpc;
hdd[id].tracks = tracks;
fread(&(hdd[id].at_spt), 1, 4, hdd_images[id].file);
fread(&(hdd[id].at_hpc), 1, 4, hdd_images[id].file);
hdd_images[id].type = 2;
} else if (is_vhd[1]) {
empty_sector_1mb = (char *) malloc(512);
memset(empty_sector_1mb, 0, 512);
fseeko64(hdd_images[id].file, -512, SEEK_END);
fread(empty_sector_1mb, 1, 512, hdd_images[id].file);
fread(empty_sector, 1, 512, hdd_images[id].file);
new_vhd_footer(&vft);
vhd_footer_from_bytes(vft, (uint8_t *) empty_sector_1mb);
vhd_footer_from_bytes(vft, (uint8_t *) empty_sector);
if (vft->type != 2) {
/* VHD is not fixed size */
hdd_image_log("VHD: Image is not fixed size\n");
free(vft);
vft = NULL;
free(empty_sector_1mb);
empty_sector_1mb = NULL;
fclose(hdd_images[id].file);
hdd_images[id].file = NULL;
memset(hdd[id].fn, 0, sizeof(hdd[id].fn));
@@ -699,8 +696,6 @@ hdd_image_load(int id)
hdd[id].spt = vft->geom.spt;
free(vft);
vft = NULL;
free(empty_sector_1mb);
empty_sector_1mb = NULL;
hdd_images[id].type = 3;
/* If we're here, this means there is a valid VHD footer in the
image, which means that by definition, all valid sectors
@@ -731,22 +726,7 @@ hdd_image_load(int id)
s = ftello64(hdd_images[id].file);
if (s == (full_size + hdd_images[id].base)) {
/* VHD image. */
/* Generate new footer. */
empty_sector_1mb = (char *) malloc(512);
new_vhd_footer(&vft);
vft->orig_size = vft->curr_size = full_size;
vft->geom.cyl = hdd[id].tracks;
vft->geom.heads = hdd[id].hpc;
vft->geom.spt = hdd[id].spt;
generate_vhd_checksum(vft);
memset(empty_sector_1mb, 0, 512);
vhd_footer_to_bytes((uint8_t *) empty_sector_1mb, vft);
fwrite(empty_sector_1mb, 1, 512, hdd_images[id].file);
free(vft);
vft = NULL;
free(empty_sector_1mb);
empty_sector_1mb = NULL;
hdd_images[id].type = 3;
hdd_image_gen_vft(id, &vft, full_size);
}
}
@@ -791,9 +771,7 @@ hdd_image_read_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer)
if ((sectors - sector) < transfer_sectors)
transfer_sectors = sectors - sector;
hdd_images[id].pos = sector;
fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET);
fread(buffer, 1, transfer_sectors << 9, hdd_images[id].file);
hdd_image_read(id, sector, transfer_sectors, buffer);
if (count != transfer_sectors)
return 1;
@@ -819,9 +797,7 @@ hdd_image_write_ex(uint8_t id, uint32_t sector, uint32_t count, uint8_t *buffer)
if ((sectors - sector) < transfer_sectors)
transfer_sectors = sectors - sector;
hdd_images[id].pos = sector;
fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET);
fwrite(buffer, transfer_sectors << 9, 1, hdd_images[id].file);
hdd_image_write(id, sector, transfer_sectors, buffer);
if (count != transfer_sectors)
return 1;
@@ -836,6 +812,7 @@ hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count)
hdd_images[id].pos = sector;
fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET);
memset(empty_sector, 0, 512);
for (i = 0; i < count; i++)
fwrite(empty_sector, 512, 1, hdd_images[id].file);
}
@@ -844,18 +821,13 @@ hdd_image_zero(uint8_t id, uint32_t sector, uint32_t count)
int
hdd_image_zero_ex(uint8_t id, uint32_t sector, uint32_t count)
{
uint32_t i = 0;
uint32_t transfer_sectors = count;
uint32_t sectors = hdd_sectors(id);
if ((sectors - sector) < transfer_sectors)
transfer_sectors = sectors - sector;
hdd_images[id].pos = sector;
fseeko64(hdd_images[id].file, ((uint64_t)sector << 9LL) + hdd_images[id].base, SEEK_SET);
for (i = 0; i < transfer_sectors; i++)
fwrite(empty_sector, 1, 512, hdd_images[id].file);
hdd_image_zero(id, sector, transfer_sectors);
if (count != transfer_sectors)
return 1;
@@ -884,19 +856,6 @@ hdd_image_get_type(uint8_t id)
}
void
hdd_image_specify(uint8_t id, uint64_t hpc, uint64_t spt)
{
if (hdd_images[id].type == 2) {
hdd[id].at_hpc = hpc;
hdd[id].at_spt = spt;
fseeko64(hdd_images[id].file, 0x20, SEEK_SET);
fwrite(&(hdd[id].at_spt), 1, 4, hdd_images[id].file);
fwrite(&(hdd[id].at_hpc), 1, 4, hdd_images[id].file);
}
}
void
hdd_image_unload(uint8_t id, int fn_preserve)
{

View File

@@ -9,7 +9,7 @@
* Implementation of the Iomega ZIP drive with SCSI(-like)
* commands, for both ATAPI and SCSI usage.
*
* Version: @(#)zip.c 1.0.34 2018/10/27
* Version: @(#)zip.c 1.0.34 2018/10/28
*
* Author: Miran Grca, <mgrca8@gmail.com>
*
@@ -36,19 +36,6 @@
#include "zip.h"
/* Bits of 'status' */
#define ERR_STAT 0x01
#define DRQ_STAT 0x08 /* Data request */
#define DSC_STAT 0x10
#define SERVICE_STAT 0x10
#define READY_STAT 0x40
#define BUSY_STAT 0x80
/* Bits of 'error' */
#define ABRT_ERR 0x04 /* Command aborted */
#define MCR_ERR 0x08 /* Media change request */
zip_drive_t zip_drives[ZIP_NUM];
@@ -450,7 +437,7 @@ static const mode_sense_pages_t zip_250_mode_sense_pages_changeable =
static void zip_command_complete(zip_t *dev);
static void zip_init(zip_t *dev);
static void zip_callback(void *p);
static void zip_callback(scsi_common_t *sc);
#ifdef ENABLE_ZIP_LOG
@@ -486,62 +473,66 @@ find_zip_for_channel(uint8_t channel)
}
static int
zip_load_abort(zip_t *dev)
{
if (dev->drv->f)
fclose(dev->drv->f);
dev->drv->f = NULL;
dev->drv->medium_size = 0;
zip_eject(dev->id); /* Make sure the host OS knows we've rejected (and ejected) the image. */
return 0;
}
int
zip_load(zip_t *dev, wchar_t *fn)
{
int read_only = dev->drv->ui_writeprot;
int size = 0;
dev->drv->f = plat_fopen(fn, dev->drv->ui_writeprot ? L"rb" : L"rb+");
if (!dev->drv->ui_writeprot && !dev->drv->f) {
dev->drv->f = plat_fopen(fn, L"rb");
read_only = 1;
}
if (dev->drv->f) {
fseek(dev->drv->f, 0, SEEK_END);
size = ftell(dev->drv->f);
if ((size == ((ZIP_250_SECTORS << 9) + 0x1000)) || (size == ((ZIP_SECTORS << 9) + 0x1000))) {
/* This is a ZDI image. */
size -= 0x1000;
dev->drv->base = 0x1000;
dev->drv->f = plat_fopen(fn, dev->drv->read_only ? L"rb" : L"rb+");
if (!dev->drv->f) {
if (!dev->drv->read_only) {
dev->drv->f = plat_fopen(fn, L"rb");
if (dev->drv->f)
dev->drv->read_only = 1;
else
return zip_load_abort(dev);
} else
dev->drv->base = 0;
if (dev->drv->is_250) {
if ((size != (ZIP_250_SECTORS << 9)) && (size != (ZIP_SECTORS << 9))) {
zip_log("File is incorrect size for a ZIP image\nMust be exactly %i or %i bytes\n",
ZIP_250_SECTORS << 9, ZIP_SECTORS << 9);
fclose(dev->drv->f);
dev->drv->f = NULL;
dev->drv->medium_size = 0;
zip_eject(dev->id); /* Make sure the host OS knows we've rejected (and ejected) the image. */
return 0;
}
} else {
if (size != (ZIP_SECTORS << 9)) {
zip_log("File is incorrect size for a ZIP image\nMust be exactly %i bytes\n",
ZIP_SECTORS << 9);
fclose(dev->drv->f);
dev->drv->f = NULL;
dev->drv->medium_size = 0;
zip_eject(dev->id); /* Make sure the host OS knows we've rejected (and ejected) the image. */
return 0;
}
}
dev->drv->medium_size = size >> 9;
fseek(dev->drv->f, dev->drv->base, SEEK_SET);
memcpy(dev->drv->image_path, fn, sizeof(dev->drv->image_path));
dev->drv->read_only = read_only;
return 1;
return zip_load_abort(dev);
}
return 0;
fseek(dev->drv->f, 0, SEEK_END);
size = ftell(dev->drv->f);
if ((size == ((ZIP_250_SECTORS << 9) + 0x1000)) || (size == ((ZIP_SECTORS << 9) + 0x1000))) {
/* This is a ZDI image. */
size -= 0x1000;
dev->drv->base = 0x1000;
} else
dev->drv->base = 0;
if (dev->drv->is_250) {
if ((size != (ZIP_250_SECTORS << 9)) && (size != (ZIP_SECTORS << 9))) {
zip_log("File is incorrect size for a ZIP image\nMust be exactly %i or %i bytes\n",
ZIP_250_SECTORS << 9, ZIP_SECTORS << 9);
return zip_load_abort(dev);
}
} else {
if (size != (ZIP_SECTORS << 9)) {
zip_log("File is incorrect size for a ZIP image\nMust be exactly %i bytes\n",
ZIP_SECTORS << 9);
return zip_load_abort(dev);
}
}
dev->drv->medium_size = size >> 9;
fseek(dev->drv->f, dev->drv->base, SEEK_SET);
memcpy(dev->drv->image_path, fn, sizeof(dev->drv->image_path));
return 1;
}
@@ -592,18 +583,6 @@ zip_set_callback(zip_t *dev)
}
static void
zip_set_signature(void *p)
{
zip_t *dev = (zip_t *) p;
if (dev->id >= ZIP_NUM)
return;
dev->phase = 1;
dev->request_length = 0xEB14;
}
static void
zip_init(zip_t *dev)
{
@@ -619,8 +598,10 @@ zip_init(zip_t *dev)
if (dev->drv->bus_type < ZIP_BUS_SCSI)
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)
zip_set_signature(dev);
if (dev->drv->bus_type < ZIP_BUS_SCSI) {
dev->phase = 1;
dev->request_length = 0xEB14;
}
dev->status = READY_STAT | DSC_STAT;
dev->pos = 0;
dev->packet_status = 0xff;
@@ -663,19 +644,6 @@ zip_current_mode(zip_t *dev)
}
/* Translates ATAPI status (ERR_STAT flag) to SCSI status. */
static int
zip_err_stat_to_scsi(void *p)
{
zip_t *dev = (zip_t *) p;
if (dev->status & ERR_STAT)
return SCSI_STATUS_CHECK_CONDITION;
else
return SCSI_STATUS_OK;
}
/* 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)
@@ -753,25 +721,6 @@ zip_mode_sense_save(zip_t *dev)
}
static int
zip_read_capacity(void *p, uint8_t *cdb, uint8_t *buffer, uint32_t *len)
{
zip_t *dev = (zip_t *) p;
int size = 0;
size = dev->drv->medium_size - 1; /* IMPORTANT: What's returned is the last LBA block. */
memset(buffer, 0, 8);
buffer[0] = (size >> 24) & 0xff;
buffer[1] = (size >> 16) & 0xff;
buffer[2] = (size >> 8) & 0xff;
buffer[3] = size & 0xff;
buffer[6] = 2; /* 512 = 0x0200 */
*len = 8;
return 1;
}
/*SCSI Mode Sense 6/10*/
static uint8_t
zip_mode_sense_read(zip_t *dev, uint8_t page_control, uint8_t page, uint8_t pos)
@@ -927,7 +876,7 @@ zip_command_common(zip_t *dev)
dev->phase = 1;
dev->pos = 0;
if (dev->packet_status == PHASE_COMPLETE) {
zip_callback((void *) dev);
zip_callback((scsi_common_t *) dev);
dev->callback = 0LL;
} else {
if (dev->drv->bus_type == ZIP_BUS_SCSI) {
@@ -1322,15 +1271,16 @@ zip_rezero(zip_t *dev)
void
zip_reset(void *p)
zip_reset(scsi_common_t *sc)
{
zip_t *dev = (zip_t *) p;
zip_t *dev = (zip_t *) sc;
zip_rezero(dev);
dev->status = 0;
dev->callback = 0LL;
zip_set_callback(dev);
zip_set_signature(dev);
dev->phase = 1;
dev->request_length = 0xEB14;
dev->packet_status = 0xff;
dev->unit_attention = 0;
}
@@ -1373,9 +1323,9 @@ zip_request_sense(zip_t *dev, uint8_t *buffer, uint8_t alloc_length, int desc)
static void
zip_request_sense_for_scsi(void *p, uint8_t *buffer, uint8_t alloc_length)
zip_request_sense_for_scsi(scsi_common_t *sc, uint8_t *buffer, uint8_t alloc_length)
{
zip_t *dev = (zip_t *) p;
zip_t *dev = (zip_t *) sc;
int ready = 0;
ready = (dev->drv->f != NULL);
@@ -1412,7 +1362,8 @@ static void
zip_buf_alloc(zip_t *dev, uint32_t len)
{
zip_log("ZIP %i: Allocated buffer length: %i\n", dev->id, len);
dev->buffer = (uint8_t *) malloc(len);
if (!dev->buffer)
dev->buffer = (uint8_t *) malloc(len);
}
@@ -1428,9 +1379,9 @@ zip_buf_free(zip_t *dev)
static void
zip_command(void *p, uint8_t *cdb)
zip_command(scsi_common_t *sc, uint8_t *cdb)
{
zip_t *dev = (zip_t *) p;
zip_t *dev = (zip_t *) sc;
int pos = 0, block_desc = 0;
int ret;
int32_t len, max_len;
@@ -1555,10 +1506,9 @@ zip_command(void *p, uint8_t *cdb)
case GPCMD_MECHANISM_STATUS:
zip_set_phase(dev, SCSI_PHASE_DATA_IN);
len = (cdb[7] << 16) | (cdb[8] << 8) | cdb[9];
len = (cdb[8] << 8) | cdb[9];
zip_buf_alloc(dev, 8);
zip_set_buf_len(dev, BufLen, &len);
memset(dev->buffer, 0, 8);
@@ -1609,6 +1559,10 @@ zip_command(void *p, uint8_t *cdb)
ret = zip_blocks(dev, &alloc_length, 1, 0);
if (ret <= 0) {
zip_set_phase(dev, SCSI_PHASE_STATUS);
dev->packet_status = PHASE_COMPLETE;
dev->callback = 20LL * ZIP_TIME;
zip_set_callback(dev);
zip_buf_free(dev);
return;
}
@@ -1705,7 +1659,6 @@ zip_command(void *p, uint8_t *cdb)
return;
case GPCMD_WRITE_SAME_10:
zip_set_phase(dev, SCSI_PHASE_DATA_OUT);
alloc_length = 512;
if ((cdb[1] & 6) == 6) {
@@ -1736,20 +1689,17 @@ zip_command(void *p, uint8_t *cdb)
break;
}
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. */
dev->packet_len = max_len * alloc_length;
zip_buf_alloc(dev, dev->packet_len);
dev->requested_blocks = max_len;
dev->packet_len = alloc_length;
zip_buf_alloc(dev, alloc_length);
zip_set_buf_len(dev, BufLen, (int32_t *) &dev->packet_len);
zip_data_command_finish(dev, dev->packet_len, 512, dev->packet_len, 1);
max_len = 1;
dev->requested_blocks = 1;
dev->packet_len = alloc_length;
zip_set_phase(dev, SCSI_PHASE_DATA_OUT);
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);
@@ -1986,10 +1936,14 @@ atapi_out:
zip_buf_alloc(dev, 8);
if (zip_read_capacity(dev, dev->current_cdb, dev->buffer, (uint32_t *) &len) == 0) {
zip_buf_free(dev);
return;
}
max_len = dev->drv->medium_size - 1; /* IMPORTANT: What's returned is the last LBA block. */
memset(dev->buffer, 0, 8);
dev->buffer[0] = (max_len >> 24) & 0xff;
dev->buffer[1] = (max_len >> 16) & 0xff;
dev->buffer[2] = (max_len >> 8) & 0xff;
dev->buffer[3] = max_len & 0xff;
dev->buffer[6] = 2; /* 512 = 0x0200 */
len = 8;
zip_set_buf_len(dev, BufLen, &len);
@@ -2082,10 +2036,22 @@ atapi_out:
}
static void
zip_command_stop(scsi_common_t *sc)
{
zip_t *dev = (zip_t *) sc;
zip_command_complete(dev);
zip_buf_free(dev);
}
/* The command second phase function, needed for Mode Select. */
static uint8_t
zip_phase_data_out(zip_t *dev)
zip_phase_data_out(scsi_common_t *sc)
{
zip_t *dev = (zip_t *) sc;
uint16_t block_desc_len;
uint16_t pos;
@@ -2202,407 +2168,137 @@ zip_phase_data_out(zip_t *dev)
}
if (error) {
zip_buf_free(dev);
zip_invalid_field_pl(dev);
return 0;
}
break;
}
return 1;
}
/* This is the general ATAPI PIO request function. */
static void
zip_pio_request(zip_t *dev, uint8_t out)
{
int ret = 0;
if (dev->drv->bus_type < ZIP_BUS_SCSI) {
zip_log("ZIP %i: Lowering IDE IRQ\n", dev->id);
ide_irq_lower(ide_drives[dev->drv->ide_channel]);
}
dev->status = BUSY_STAT;
if (dev->pos >= dev->packet_len) {
zip_log("ZIP %i: %i bytes %s, command done\n", dev->id, dev->pos, out ? "written" : "read");
dev->pos = dev->request_pos = 0;
if (out) {
ret = zip_phase_data_out(dev);
/* If ret = 0 (phase 1 error), then we do not do anything else other than
free the buffer, as the phase and callback have already been set by the
error function. */
if (ret)
zip_command_complete(dev);
} else
zip_command_complete(dev);
zip_buf_free(dev);
} else {
zip_log("ZIP %i: %i bytes %s, %i bytes are still left\n", dev->id, dev->pos,
out ? "written" : "read", dev->packet_len - dev->pos);
/* If less than (packet length) bytes are remaining, update packet length
accordingly. */
if ((dev->packet_len - dev->pos) < (dev->max_transfer_len))
dev->max_transfer_len = dev->packet_len - dev->pos;
zip_log("ZIP %i: Packet length %i, request length %i\n", dev->id, dev->packet_len,
dev->max_transfer_len);
dev->packet_status = out ? PHASE_DATA_OUT : PHASE_DATA_IN;
dev->status = BUSY_STAT;
dev->phase = 1;
zip_callback((void *) dev);
dev->callback = 0LL;
zip_set_callback(dev);
dev->request_pos = 0;
}
}
static int
zip_read_from_ide_dma(zip_t *dev)
{
int ret;
if (!dev)
return 0;
if (ide_bus_master_write) {
ret = ide_bus_master_write(dev->drv->ide_channel >> 1,
dev->buffer, dev->packet_len,
ide_bus_master_priv[dev->drv->ide_channel >> 1]);
if (ret == 2) /* DMA not enabled, wait for it to be enabled. */
return 2;
else if (ret == 1) { /* DMA error. */
zip_bus_master_error(dev);
return 0;
} else
return 1;
} else
return 0;
}
static int
zip_read_from_scsi_dma(uint8_t scsi_id)
{
zip_t *dev = (zip_t *) scsi_devices[scsi_id].p;
int32_t *BufLen = &scsi_devices[scsi_id].buffer_length;
if (!dev)
return 0;
zip_log("Reading from SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen);
memcpy(dev->buffer, scsi_devices[scsi_id].cmd_buffer, *BufLen);
zip_command_stop((scsi_common_t *) dev);
return 1;
}
static void
zip_irq_raise(zip_t *dev)
zip_irq_raise(scsi_common_t *sc)
{
if (dev->drv->bus_type < ZIP_BUS_SCSI)
zip_t *dev = (zip_t *) sc;
if (dev->drv && (dev->drv->bus_type < ZIP_BUS_SCSI))
ide_irq_raise(ide_drives[dev->drv->ide_channel]);
}
static int
zip_read_from_dma(zip_t *dev)
zip_dma(zip_t *dev, int out)
{
#ifdef ENABLE_ZIP_LOG
int32_t *BufLen = &scsi_devices[dev->drv->scsi_device_id].buffer_length;
#endif
int ret = 0;
int ret = 1;
if (dev->drv->bus_type == ZIP_BUS_SCSI)
ret = zip_read_from_scsi_dma(dev->drv->scsi_device_id);
else
ret = zip_read_from_ide_dma(dev);
if (dev->drv->bus_type == ZIP_BUS_ATAPI) {
ret = 0;
if (ret != 1)
return ret;
if (out && dev && ide_bus_master_write) {
ret = ide_bus_master_write(dev->drv->ide_channel >> 1,
dev->buffer, dev->packet_len,
ide_bus_master_priv[dev->drv->ide_channel >> 1]);
} else if (!out && dev && ide_bus_master_read) {
ret = ide_bus_master_read(dev->drv->ide_channel >> 1,
dev->buffer, dev->packet_len,
ide_bus_master_priv[dev->drv->ide_channel >> 1]);
}
}
if (dev->drv->bus_type == ZIP_BUS_SCSI)
zip_log("ZIP %i: SCSI Input data length: %i\n", dev->id, *BufLen);
else
zip_log("ZIP %i: ATAPI Input data length: %i\n", dev->id, dev->packet_len);
ret = zip_phase_data_out(dev);
if (ret)
return 1;
else
return 0;
}
static int
zip_write_to_ide_dma(zip_t *dev)
{
int ret;
if (!dev)
return 0;
if (ide_bus_master_read) {
ret = ide_bus_master_read(dev->drv->ide_channel >> 1,
dev->buffer, dev->packet_len,
ide_bus_master_priv[dev->drv->ide_channel >> 1]);
if (ret == 2) /* DMA not enabled, wait for it to be enabled. */
return 2;
else if (ret == 1) { /* DMA error. */
zip_bus_master_error(dev);
return 0;
} else
return 1;
} else
return 0;
}
static int
zip_write_to_scsi_dma(uint8_t scsi_id)
{
zip_t *dev = (zip_t *) scsi_devices[scsi_id].p;
int32_t *BufLen = &scsi_devices[scsi_id].buffer_length;
if (!dev)
return 0;
zip_log("Writing to SCSI DMA: SCSI ID %02X, init length %i\n", scsi_id, *BufLen);
memcpy(scsi_devices[scsi_id].cmd_buffer, dev->buffer, *BufLen);
zip_log("ZIP %i: Data from CD buffer: %02X %02X %02X %02X %02X %02X %02X %02X\n", dev->id,
dev->buffer[0], dev->buffer[1], dev->buffer[2], dev->buffer[3], dev->buffer[4], dev->buffer[5],
dev->buffer[6], dev->buffer[7]);
return 1;
}
static int
zip_write_to_dma(zip_t *dev)
{
#ifdef ENABLE_ZIP_LOG
int32_t *BufLen = &scsi_devices[dev->drv->scsi_device_id].buffer_length;
#endif
int ret = 0;
if (dev->drv->bus_type == ZIP_BUS_SCSI) {
zip_log("Write to SCSI DMA: (ID %02X)\n", dev->drv->scsi_device_id);
ret = zip_write_to_scsi_dma(dev->drv->scsi_device_id);
} else
ret = zip_write_to_ide_dma(dev);
if (dev->drv->bus_type == ZIP_BUS_SCSI)
zip_log("ZIP %i: SCSI Output data length: %i\n", dev->id, *BufLen);
else
zip_log("ZIP %i: ATAPI Output data length: %i\n", dev->id, dev->packet_len);
if (ret == 0) {
zip_buf_free(dev);
zip_bus_master_error(dev);
} else if (ret == 1) {
if (out)
ret = zip_phase_data_out((scsi_common_t *) dev);
else
zip_command_stop((scsi_common_t *) dev);
}
return ret;
}
static void
zip_callback(void *p)
zip_callback(scsi_common_t *sc)
{
zip_t *dev = (zip_t *) p;
zip_t *dev = (zip_t *) sc;
int ret;
switch(dev->packet_status) {
switch(sc->packet_status) {
case PHASE_IDLE:
zip_log("ZIP %i: PHASE_IDLE\n", dev->id);
dev->pos = 0;
dev->phase = 1;
dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT);
zip_log("ZIP %i: PHASE_IDLE\n", sc->id);
sc->pos = 0;
sc->phase = 1;
sc->status = READY_STAT | DRQ_STAT | (sc->status & ERR_STAT);
return;
case PHASE_COMMAND:
zip_log("ZIP %i: PHASE_COMMAND\n", dev->id);
dev->status = BUSY_STAT | (dev->status & ERR_STAT);
memcpy(dev->atapi_cdb, dev->buffer, 12);
zip_command(dev, dev->atapi_cdb);
zip_log("ZIP %i: PHASE_COMMAND\n", sc->id);
sc->status = BUSY_STAT | (sc->status & ERR_STAT);
zip_command(sc, sc->atapi_cdb);
return;
case PHASE_COMPLETE:
zip_log("ZIP %i: PHASE_COMPLETE\n", dev->id);
dev->status = READY_STAT;
dev->phase = 3;
dev->packet_status = 0xFF;
ui_sb_update_icon(SB_ZIP | dev->id, 0);
zip_irq_raise(dev);
zip_log("ZIP %i: PHASE_COMPLETE\n", sc->id);
sc->status = READY_STAT;
sc->phase = 3;
sc->packet_status = 0xFF;
ui_sb_update_icon(SB_ZIP | sc->id, 0);
zip_irq_raise(sc);
return;
case PHASE_DATA_OUT:
zip_log("ZIP %i: PHASE_DATA_OUT\n", dev->id);
dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT);
dev->phase = 0;
zip_irq_raise(dev);
zip_log("ZIP %i: PHASE_DATA_OUT\n", sc->id);
sc->status = READY_STAT | DRQ_STAT | (sc->status & ERR_STAT);
sc->phase = 0;
zip_irq_raise(sc);
return;
case PHASE_DATA_OUT_DMA:
zip_log("ZIP %i: PHASE_DATA_OUT_DMA\n", dev->id);
ret = zip_read_from_dma(dev);
ret = zip_dma(dev, 1);
if ((ret == 1) || (dev->drv->bus_type == ZIP_BUS_SCSI)) {
zip_log("ZIP %i: DMA data out phase done\n");
zip_buf_free(dev);
zip_command_complete(dev);
} else if (ret == 2) {
zip_log("ZIP %i: DMA out not enabled, wait\n");
if (ret == 2) {
zip_log("ZIP %i: DMA out not enabled, wait\n", sc->id);
zip_command_bus(dev);
#ifdef ENABLE_ZIP_LOG
} else {
zip_log("ZIP %i: DMA data out phase failure\n");
zip_buf_free(dev);
zip_log("ZIP %i: DMA data out phase %s\n", sc->id, ret ? "done" : "failure");
#endif
}
return;
case PHASE_DATA_IN:
zip_log("ZIP %i: PHASE_DATA_IN\n", dev->id);
dev->status = READY_STAT | DRQ_STAT | (dev->status & ERR_STAT);
dev->phase = 2;
zip_irq_raise(dev);
zip_log("ZIP %i: PHASE_DATA_IN\n", sc->id);
sc->status = READY_STAT | DRQ_STAT | (sc->status & ERR_STAT);
sc->phase = 2;
zip_irq_raise(sc);
return;
case PHASE_DATA_IN_DMA:
zip_log("ZIP %i: PHASE_DATA_IN_DMA\n", dev->id);
ret = zip_write_to_dma(dev);
zip_log("ZIP %i: PHASE_DATA_IN_DMA\n", sc->id);
ret = zip_dma(dev, 0);
if ((ret == 1) || (dev->drv->bus_type == ZIP_BUS_SCSI)) {
zip_log("ZIP %i: DMA data in phase done\n", dev->id);
zip_buf_free(dev);
zip_command_complete(dev);
} else if (ret == 2) {
zip_log("ZIP %i: DMA in not enabled, wait\n", dev->id);
if (ret == 2) {
zip_log("ZIP %i: DMA in not enabled, wait\n", sc->id);
zip_command_bus(dev);
#ifdef ENABLE_ZIP_LOG
} else {
zip_log("ZIP %i: DMA data in phase failure\n", dev->id);
zip_buf_free(dev);
zip_log("ZIP %i: DMA data in phase %s\n", sc->id, ret ? "done" : "failure");
#endif
}
return;
case PHASE_ERROR:
zip_log("ZIP %i: PHASE_ERROR\n", dev->id);
dev->status = READY_STAT | ERR_STAT;
dev->phase = 3;
dev->packet_status = 0xFF;
zip_irq_raise(dev);
ui_sb_update_icon(SB_ZIP | dev->id, 0);
zip_log("ZIP %i: PHASE_ERROR\n", sc->id);
sc->status = READY_STAT | ERR_STAT;
sc->phase = 3;
sc->packet_status = 0xFF;
zip_irq_raise(sc);
ui_sb_update_icon(SB_ZIP | sc->id, 0);
return;
}
}
static uint32_t
zip_packet_read(void *p, int length)
{
zip_t *dev = (zip_t *) p;
uint16_t *zipbufferw;
uint32_t *zipbufferl;
uint32_t temp = 0;
if (!dev)
return 0;
zipbufferw = (uint16_t *) dev->buffer;
zipbufferl = (uint32_t *) dev->buffer;
if (!dev->buffer)
return 0;
/* Make sure we return a 0 and don't attempt to read from the buffer if we're transferring bytes beyond it,
which can happen when issuing media access commands with an allocated length below minimum request length
(which is 1 sector = 512 bytes). */
switch(length) {
case 1:
temp = (dev->pos < dev->packet_len) ? dev->buffer[dev->pos] : 0;
dev->pos++;
dev->request_pos++;
break;
case 2:
temp = (dev->pos < dev->packet_len) ? zipbufferw[dev->pos >> 1] : 0;
dev->pos += 2;
dev->request_pos += 2;
break;
case 4:
temp = (dev->pos < dev->packet_len) ? zipbufferl[dev->pos >> 2] : 0;
dev->pos += 4;
dev->request_pos += 4;
break;
default:
return 0;
}
if (dev->packet_status == PHASE_DATA_IN) {
if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) {
/* Time for a DRQ. */
zip_pio_request(dev, 0);
}
return temp;
} else
return 0;
}
static void
zip_packet_write(void *p, uint32_t val, int length)
{
zip_t *dev = (zip_t *) p;
uint16_t *zipbufferw;
uint32_t *zipbufferl;
if (!dev)
return;
if (dev->packet_status == PHASE_IDLE) {
if (!dev->buffer)
zip_buf_alloc(dev, 12);
}
zipbufferw = (uint16_t *) dev->buffer;
zipbufferl = (uint32_t *) dev->buffer;
if (!dev->buffer)
return;
switch(length) {
case 1:
dev->buffer[dev->pos] = val & 0xff;
dev->pos++;
dev->request_pos++;
break;
case 2:
zipbufferw[dev->pos >> 1] = val & 0xffff;
dev->pos += 2;
dev->request_pos += 2;
break;
case 4:
zipbufferl[dev->pos >> 2] = val;
dev->pos += 4;
dev->request_pos += 4;
break;
default:
return;
}
if (dev->packet_status == PHASE_DATA_OUT) {
if ((dev->request_pos >= dev->max_transfer_len) || (dev->pos >= dev->packet_len)) {
/* Time for a DRQ. */
zip_pio_request(dev, 1);
}
return;
} else if (dev->packet_status == PHASE_IDLE) {
if (dev->pos >= 12) {
dev->pos = 0;
dev->status = BUSY_STAT;
dev->packet_status = PHASE_COMMAND;
timer_process();
zip_callback((void *) dev);
timer_update_outstanding();
}
return;
}
}
/* Peform a master init on the entire module. */
void
zip_global_init(void)
@@ -2612,27 +2308,6 @@ zip_global_init(void)
}
static void
zip_100_identify(ide_t *ide)
{
ide_padstr((char *) (ide->buffer + 23), "E.08", 8); /* Firmware */
ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 100 ATAPI", 40); /* Model */
}
static void
zip_250_identify(ide_t *ide, int ide_has_dma)
{
ide_padstr((char *) (ide->buffer + 23), "42.S", 8); /* Firmware */
ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 250 ATAPI", 40); /* Model */
if (ide_has_dma) {
ide->buffer[80] = 0x30; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-5*/
ide->buffer[81] = 0x15; /*Maximum ATA revision supported : ATA/ATAPI-5 T13 1321D revision 1*/
}
}
static int
zip_get_max(int ide_has_dma, int type)
{
@@ -2647,10 +2322,10 @@ zip_get_max(int ide_has_dma, int type)
ret = -1;
break;
case TYPE_MDMA:
ret = ide_has_dma ? -1 : 1;
ret = ide_has_dma ? 1 : -1;
break;
case TYPE_UDMA:
ret = ide_has_dma ? -1 : 2;
ret = ide_has_dma ? 2 : -1;
break;
}
@@ -2683,16 +2358,38 @@ zip_get_timings(int ide_has_dma, int type)
static void
zip_identify(void *p, int ide_has_dma)
zip_100_identify(ide_t *ide)
{
ide_padstr((char *) (ide->buffer + 23), "E.08", 8); /* Firmware */
ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 100 ATAPI", 40); /* Model */
}
static void
zip_250_identify(ide_t *ide, int ide_has_dma)
{
ide_padstr((char *) (ide->buffer + 23), "42.S", 8); /* Firmware */
ide_padstr((char *) (ide->buffer + 27), "IOMEGA ZIP 250 ATAPI", 40); /* Model */
if (ide_has_dma) {
ide->buffer[80] = 0x30; /*Supported ATA versions : ATA/ATAPI-4 ATA/ATAPI-5*/
ide->buffer[81] = 0x15; /*Maximum ATA revision supported : ATA/ATAPI-5 T13 1321D revision 1*/
}
}
static void
zip_identify(ide_t *ide, int ide_has_dma)
{
ide_t *ide = (ide_t *) p;
zip_t *zip;
zip = (zip_t *) ide->p;
zip = (zip_t *) ide->sc;
/* Using (2<<5) below makes the ASUS P/I-P54TP4XE misdentify the ZIP drive
/* ATAPI device, direct-access device, removable media, interrupt DRQ:
Using (2 << 5) below makes the ASUS P/I-P54TP4XE misdentify the ZIP drive
as a LS-120. */
ide->buffer[0] = 0x8000 | (0<<8) | 0x80 | (1<<5); /* ATAPI device, direct-access device, removable media, interrupt DRQ */
ide->buffer[0] = 0x8000 | (0 << 8) | 0x80 | (1 << 5);
ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */
ide->buffer[49] = 0x200; /* LBA supported */
ide->buffer[126] = 0xfffe; /* Interpret zero byte count limit as maximum length */
@@ -2724,13 +2421,12 @@ zip_drive_reset(int c)
/* SCSI ZIP, attach to the SCSI bus. */
sd = &scsi_devices[zip_drives[c].scsi_device_id];
sd->p = dev;
sd->sc = (scsi_common_t *) dev;
sd->command = zip_command;
sd->callback = zip_callback;
sd->err_stat_to_scsi = zip_err_stat_to_scsi;
sd->request_sense = zip_request_sense_for_scsi;
sd->reset = zip_reset;
sd->read_capacity = zip_read_capacity;
sd->command_stop = zip_command_stop;
sd->type = SCSI_REMOVABLE_DISK;
} else if (zip_drives[c].bus_type == ZIP_BUS_ATAPI) {
/* ATAPI CD-ROM, attach to the IDE bus. */
@@ -2739,16 +2435,15 @@ zip_drive_reset(int c)
otherwise, we do nothing - it's going to be a drive
that's not attached to anything. */
if (id) {
id->p = dev;
id->sc = (scsi_common_t *) dev;
id->get_max = zip_get_max;
id->get_timings = zip_get_timings;
id->identify = zip_identify;
id->set_signature = zip_set_signature;
id->packet_write = zip_packet_write;
id->packet_read = zip_packet_read;
id->stop = NULL;
id->packet_callback = zip_callback;
id->device_reset = zip_reset;
id->phase_data_out = zip_phase_data_out;
id->command_stop = zip_command_stop;
id->interrupt_drq = 1;
ide_atapi_attach(id);

View File

@@ -9,7 +9,7 @@
* Implementation of the Iomega ZIP drive with SCSI(-like)
* commands, for both ATAPI and SCSI usage.
*
* Version: @(#)zip.h 1.0.7 2018/10/26
* Version: @(#)zip.h 1.0.8 2018/10/28
*
* Author: Miran Grca, <mgrca8@gmail.com>
*
@@ -39,22 +39,25 @@ enum {
typedef struct {
unsigned int bus_type; /* 0 = ATAPI, 1 = SCSI */
uint8_t ide_channel,
bus_mode; /* Bit 0 = PIO suported;
uint8_t id,
res, res0, /* Reserved for other ID's. */
res1,
ide_channel, scsi_device_id,
bus_type, /* 0 = ATAPI, 1 = SCSI */
bus_mode, /* Bit 0 = PIO suported;
Bit 1 = DMA supportd. */
read_only, /* Struct variable reserved for
media status. */
pad, pad0;
unsigned int scsi_device_id, is_250;
FILE *f;
void *priv;
wchar_t image_path[1024],
prev_image_path[1024];
int read_only, ui_writeprot;
uint32_t medium_size, base;
FILE *f;
void *priv;
uint32_t is_250, medium_size,
base;
} zip_drive_t;
typedef struct {
@@ -76,16 +79,13 @@ typedef struct {
int requested_blocks, packet_status,
total_length, do_page_save,
unit_attention;
unit_attention, request_pos,
old_len, pad3;
uint32_t sector_pos, sector_len,
packet_len, pos;
int64_t callback;
int request_pos, old_len;
uint32_t seek_pos;
} zip_t;
@@ -116,7 +116,7 @@ extern void zip_insert(zip_t *dev);
extern void zip_global_init(void);
extern void zip_hard_reset(void);
extern void zip_reset(void *p);
extern void zip_reset(scsi_common_t *sc);
extern int zip_load(zip_t *dev, wchar_t *fn);
extern void zip_close();