diff --git a/src/add-ons/kernel/generic/ide_adapter/ide_adapter.c b/src/add-ons/kernel/generic/ide_adapter/ide_adapter.c index 14ebe422d6..ab791cea66 100644 --- a/src/add-ons/kernel/generic/ide_adapter/ide_adapter.c +++ b/src/add-ons/kernel/generic/ide_adapter/ide_adapter.c @@ -31,6 +31,8 @@ #define TRACE dprintf +// set this to 1 for the ata stack, or 0 for the ide stack +#define ATA_STACK 0 static ide_for_controller_interface *ide; static device_manager_info *pnp; @@ -188,6 +190,35 @@ ide_adapter_read_pio(ide_adapter_channel_info *channel, uint16 *data, static int32 ide_adapter_inthand(void *arg) { +#if ATA_STACK + ide_adapter_channel_info *channel = (ide_adapter_channel_info *)arg; + pci_device_module_info *pci = channel->pci; + pci_device *device = channel->device; + uint8 statusATA, statusBM; + + // this could be a spurious interrupt, so always read status + // register unconditionally to acknowledge those + statusATA = pci->read_io_8(device, channel->command_block_base + 7); + + if (!channel->dmaing) + return B_UNHANDLED_INTERRUPT; + + // read bus master DMA status to test if the interrupt was + // really generated by our controller + statusBM = pci->read_io_8(device, channel->bus_master_base + + IDE_BM_STATUS_REG); + + if (statusBM & IDE_BM_STATUS_INTERRUPT) { + // clear pending PCI bus master DMA interrupt + pci->write_io_8(device, channel->bus_master_base + IDE_BM_STATUS_REG, + (statusBM & 0xf8) | IDE_BM_STATUS_INTERRUPT); + // signal interrupt to ATA stack + return ide->irq_handler(channel->ide_channel, statusATA); + } else { + return B_UNHANDLED_INTERRUPT; + } + +#else ide_adapter_channel_info *channel = (ide_adapter_channel_info *)arg; pci_device_module_info *pci = channel->pci; pci_device *device = channel->device; @@ -215,6 +246,7 @@ ide_adapter_inthand(void *arg) status = pci->read_io_8(device, channel->command_block_base + 7); return ide->irq_handler(channel->ide_channel, status); +#endif } @@ -274,6 +306,7 @@ ide_adapter_start_dma(ide_adapter_channel_info *channel) + IDE_BM_COMMAND_REG); command |= IDE_BM_COMMAND_START_STOP; + channel->dmaing = true; pci->write_io_8(device, channel->bus_master_base + IDE_BM_COMMAND_REG, @@ -286,6 +319,36 @@ ide_adapter_start_dma(ide_adapter_channel_info *channel) static status_t ide_adapter_finish_dma(ide_adapter_channel_info *channel) { +#if ATA_STACK + pci_device_module_info *pci = channel->pci; + pci_device *device = channel->device; + uint8 command; + uint8 status; + + // read BM status first + status = pci->read_io_8(device, channel->bus_master_base + + IDE_BM_STATUS_REG); + + // stop DMA engine, this also clears IDE_BM_STATUS_ACTIVE + // in the BM status register + command = pci->read_io_8(device, channel->bus_master_base + + IDE_BM_COMMAND_REG); + pci->write_io_8(device, channel->bus_master_base + IDE_BM_COMMAND_REG, + command & ~IDE_BM_COMMAND_START_STOP); + channel->dmaing = false; + + // reset error flag + pci->write_io_8(device, channel->bus_master_base + IDE_BM_STATUS_REG, + status | IDE_BM_STATUS_ERROR); + + if ((status & IDE_BM_STATUS_ACTIVE) != 0) + return B_DEV_DATA_OVERRUN; + + if ((status & IDE_BM_STATUS_ERROR) != 0) + return B_ERROR; + + return B_OK; +#else pci_device_module_info *pci = channel->pci; pci_device *device = channel->device; uint8 command; @@ -310,7 +373,9 @@ ide_adapter_finish_dma(ide_adapter_channel_info *channel) if ((status & IDE_BM_STATUS_ERROR) != 0) return B_ERROR; - +/* + // this doesn't work anymore, because the + // interrupt handler always clears this bit now if ((status & IDE_BM_STATUS_INTERRUPT) == 0) { if ((status & IDE_BM_STATUS_ACTIVE) != 0) { SHOW_ERROR0( 2, "DMA transfer aborted" ); @@ -320,13 +385,14 @@ ide_adapter_finish_dma(ide_adapter_channel_info *channel) SHOW_ERROR0( 2, "DMA transfer: buffer underrun" ); return B_DEV_DATA_UNDERRUN; } - +*/ if ((status & IDE_BM_STATUS_ACTIVE) != 0) { SHOW_ERROR0( 2, "DMA transfer: buffer too large" ); return B_DEV_DATA_OVERRUN; } return B_OK; +#endif } @@ -417,8 +483,15 @@ ide_adapter_init_channel(device_node *node, } TRACE("PCI-IDE: init channel done\n"); + +#if ATA_STACK + // disable interrupts + ide_adapter_write_device_control(channel, ide_devctrl_bit3 | ide_devctrl_nien); +#else // enable interrupts so the channel is ready to run ide_adapter_write_device_control(channel, ide_devctrl_bit3); +#endif + *cookie = channel;