Implemented ATAPI DMA transfer modes.

This commit is contained in:
SarahW 2018-03-15 19:36:30 +00:00
commit 6602368cc4
9 changed files with 289 additions and 54 deletions

View file

@ -17,6 +17,11 @@
#define ATAPI_STATE_READ_DATA_WAIT 8
#define ATAPI_STATE_WRITE_DATA 9
#define ATAPI_STATE_WRITE_DATA_WAIT 10
#define ATAPI_STATE_RETRY_READ_DMA 11
#define ATAPI_STATE_RETRY_WRITE_DMA 12
#define FEATURES_DMA 0x01
#define FEATURES_OVERLAP 0x02
ATAPI *atapi;
@ -94,9 +99,11 @@ static int wait_for_bus(scsi_bus_t *bus, int state, int req_needed)
return 0;
}
void atapi_command_start(atapi_device_t *atapi)
void atapi_command_start(atapi_device_t *atapi, uint8_t features)
{
scsi_bus_t *bus = &atapi->bus;
atapi->use_dma = features & 1;
scsi_bus_update(bus, BUS_SEL | BUS_SETDATA(1 << 0));
if (!(scsi_bus_read(bus) & BUS_BSY))
@ -243,19 +250,47 @@ void atapi_process_packet(atapi_device_t *atapi_dev)
switch (bus_state & (BUS_IO | BUS_CD | BUS_MSG))
{
case 0:
atapi_dev->state = ATAPI_STATE_WRITE_DATA_WAIT;
atapi_dev->data_read_pos = scsi_dev->get_bytes_required(scsi_data);
if (atapi_dev->data_read_pos > atapi_dev->max_transfer_len)
atapi_dev->data_read_pos = atapi_dev->max_transfer_len;
atapi_dev->data_write_pos = 0;
*atapi_dev->cylinder = atapi_dev->data_read_pos;
if (atapi_dev->use_dma)
{
if (ide_bus_master_write_data)
{
if (ide_bus_master_write_data(atapi_dev->board, atapi_dev->data, atapi_dev->data_read_pos))
{
atapi_dev->state = ATAPI_STATE_RETRY_WRITE_DMA;
idecallback[atapi_dev->board] = 1*IDE_TIME;
}
else
atapi_dev->data_write_pos = atapi_dev->data_read_pos; {
atapi_dev->bus_state = 0;
atapi_dev->state = ATAPI_STATE_WRITE_DATA;
idecallback[atapi_dev->board] = 6 * IDE_TIME;
}
}
else
{
atapi_dev->state = ATAPI_STATE_RETRY_WRITE_DMA;
idecallback[atapi_dev->board] = 1*IDE_TIME;
}
}
else
{
if (atapi_dev->data_read_pos > atapi_dev->max_transfer_len)
atapi_dev->data_read_pos = atapi_dev->max_transfer_len;
atapi_dev->state = ATAPI_STATE_WRITE_DATA_WAIT;
// pclog("WRITE_DATA: bytes=%i\n", *atapi_dev->cylinder);
*atapi_dev->atastat = READY_STAT | DRQ_STAT | (*atapi_dev->atastat & ERR_STAT);
atapi_dev->bus_state = BUS_REQ;
ide_irq_raise(atapi_dev->ide);
*atapi_dev->cylinder = atapi_dev->data_read_pos;
// pclog("WRITE_DATA: bytes=%i\n", *atapi_dev->cylinder);
*atapi_dev->atastat = READY_STAT | DRQ_STAT | (*atapi_dev->atastat & ERR_STAT);
atapi_dev->bus_state = BUS_REQ;
ide_irq_raise(atapi_dev->ide);
}
break;
case BUS_IO:
@ -391,12 +426,36 @@ void atapi_process_packet(atapi_device_t *atapi_dev)
if ((scsi_bus_read(&atapi_dev->bus) & (BUS_IO | BUS_CD | BUS_MSG)) != BUS_IO)
break;
}
atapi_dev->state = ATAPI_STATE_READ_DATA_WAIT;
*atapi_dev->atastat = READY_STAT | DRQ_STAT | (*atapi_dev->atastat & ERR_STAT);
*atapi_dev->cylinder = atapi_dev->data_write_pos;
// pclog("READ_DATA: bytes=%i\n", *atapi_dev->cylinder);
atapi_dev->bus_state = BUS_IO | BUS_REQ;
ide_irq_raise(atapi_dev->ide);
if (atapi_dev->use_dma)
{
if (ide_bus_master_read_data)
{
if (ide_bus_master_read_data(atapi_dev->board, atapi_dev->data, atapi_dev->data_write_pos))
{
atapi_dev->state = ATAPI_STATE_RETRY_READ_DMA;
idecallback[atapi_dev->board] = 1*IDE_TIME;
}
else
{
atapi_dev->state = ATAPI_STATE_NEXT_PHASE;
idecallback[atapi_dev->board] = 6*IDE_TIME;
}
}
else
{
atapi_dev->state = ATAPI_STATE_RETRY_READ_DMA;
idecallback[atapi_dev->board] = 1*IDE_TIME;
}
}
else
{
atapi_dev->state = ATAPI_STATE_READ_DATA_WAIT;
*atapi_dev->atastat = READY_STAT | DRQ_STAT | (*atapi_dev->atastat & ERR_STAT);
*atapi_dev->cylinder = atapi_dev->data_write_pos;
// pclog("READ_DATA: bytes=%i\n", *atapi_dev->cylinder);
atapi_dev->bus_state = BUS_IO | BUS_REQ;
ide_irq_raise(atapi_dev->ide);
}
}
break;
@ -473,5 +532,34 @@ void atapi_process_packet(atapi_device_t *atapi_dev)
idecallback[atapi_dev->board] = 6 * IDE_TIME;
}
break;
case ATAPI_STATE_RETRY_READ_DMA:
{
if (ide_bus_master_read_data(atapi_dev->board, atapi_dev->data, atapi_dev->data_write_pos))
{
idecallback[atapi_dev->board] = 1*IDE_TIME;
}
else
{
atapi_dev->state = ATAPI_STATE_NEXT_PHASE;
idecallback[atapi_dev->board] = 6*IDE_TIME;
}
}
break;
case ATAPI_STATE_RETRY_WRITE_DMA:
{
if (ide_bus_master_write_data(atapi_dev->board, atapi_dev->data, atapi_dev->data_read_pos))
{
idecallback[atapi_dev->board] = 1*IDE_TIME;
}
else
{
atapi_dev->bus_state = 0;
atapi_dev->state = ATAPI_STATE_WRITE_DATA;
idecallback[atapi_dev->board] = 6 * IDE_TIME;
}
}
break;
}
}