[haiku-commits] r42725 - in haiku/trunk/src/add-ons/kernel/generic: ata_adapter ide_adapter

Author: kallisti5
Date: 2011-09-08 17:47:25 +0200 (Thu, 08 Sep 2011)
New Revision: 42725
Changeset: https://dev.haiku-os.org/changeset/42725

Added:
   haiku/trunk/src/add-ons/kernel/generic/ata_adapter/ata_adapter.cpp
   haiku/trunk/src/add-ons/kernel/generic/ide_adapter/ide_adapter.cpp
Removed:
   haiku/trunk/src/add-ons/kernel/generic/ata_adapter/ata_adapter.c
   haiku/trunk/src/add-ons/kernel/generic/ide_adapter/ide_adapter.c
Modified:
   haiku/trunk/src/add-ons/kernel/generic/ata_adapter/Jamfile
   haiku/trunk/src/add-ons/kernel/generic/ide_adapter/Jamfile
Log:
* change c to cpp to resolve C89/C99 issue. (thanks Deadyak!)
* changing to cpp uncovered a few bugs in ide_adaptor
* correct losing signed integer
* correct a variable name that conflicted with a type
* gcc2 build now fixed after r42724


Modified: haiku/trunk/src/add-ons/kernel/generic/ata_adapter/Jamfile
===================================================================
--- haiku/trunk/src/add-ons/kernel/generic/ata_adapter/Jamfile  2011-09-08 
03:15:37 UTC (rev 42724)
+++ haiku/trunk/src/add-ons/kernel/generic/ata_adapter/Jamfile  2011-09-08 
15:47:25 UTC (rev 42725)
@@ -3,6 +3,6 @@
 UsePrivateHeaders drivers kernel ;
 
 KernelAddon ata_adapter :
-       ata_adapter.c
+       ata_adapter.cpp
        ;
 

Copied: haiku/trunk/src/add-ons/kernel/generic/ata_adapter/ata_adapter.cpp 
(from rev 42724, 
haiku/trunk/src/add-ons/kernel/generic/ata_adapter/ata_adapter.c)
===================================================================
--- haiku/trunk/src/add-ons/kernel/generic/ata_adapter/ata_adapter.cpp          
                (rev 0)
+++ haiku/trunk/src/add-ons/kernel/generic/ata_adapter/ata_adapter.cpp  
2011-09-08 15:47:25 UTC (rev 42725)
@@ -0,0 +1,894 @@
+/*
+ * Copyright 2002-04, Thomas Kurschel. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ */
+
+/*
+       Generic ATA adapter library.
+*/
+
+#include <KernelExport.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <ata_adapter.h>
+#include <tracing.h>
+
+#define debug_level_flow 0
+#define debug_level_error 3
+#define debug_level_info 3
+
+#define DEBUG_MSG_PREFIX "ATA PCI -- "
+
+#include "wrapper.h"
+
+#define TRACE dprintf
+
+#define INTERRUPT_TRACING 0
+#if INTERRUPT_TRACING
+       #define TRACE_INT(a...)         ktrace_printf(a)
+#else
+       #define TRACE_INT(a...)
+#endif
+
+
+#if ATA_DMA_TRACING
+       #define TRACE_DMA(x...)         ktrace_printf(x)
+#else
+       #define TRACE_DMA(x...)
+#endif
+
+static ata_for_controller_interface *sATA;
+static device_manager_info *sDeviceManager;
+
+
+static void
+set_channel(ata_adapter_channel_info *channel, ata_channel ataChannel)
+{
+       channel->ataChannel = ataChannel;
+}
+
+
+static status_t
+ata_adapter_write_command_block_regs(ata_adapter_channel_info *channel,
+       ata_task_file *tf, ata_reg_mask mask)
+{
+       pci_device_module_info *pci = channel->pci;
+       pci_device *device = channel->device;
+       int i;
+
+       uint16 ioaddr = channel->command_block_base;
+
+       if (channel->lost)
+               return B_ERROR;
+
+       for (i = 0; i < 7; i++) {
+               // LBA48 registers must be written twice
+               if (((1 << (i + 7)) & mask) != 0) {
+                       SHOW_FLOW( 4, "%x->HI(%x)", tf->raw.r[i + 7], i );
+                       pci->write_io_8(device, ioaddr + 1 + i, tf->raw.r[i + 
7]);
+               }
+
+               if (((1 << i) & mask) != 0) {
+                       SHOW_FLOW( 4, "%x->LO(%x)", tf->raw.r[i], i );
+                       pci->write_io_8(device, ioaddr + 1 + i, tf->raw.r[i]);
+               }
+       }
+
+       return B_OK;
+}
+
+
+static status_t
+ata_adapter_read_command_block_regs(ata_adapter_channel_info *channel,
+       ata_task_file *tf, ata_reg_mask mask)
+{
+       pci_device_module_info *pci = channel->pci;
+       pci_device *device = channel->device;
+       int i;
+
+       uint16 ioaddr = channel->command_block_base;
+
+       if (channel->lost)
+               return B_ERROR;
+
+       for (i = 0; i < 7; i++) {
+               if (((1 << i) & mask) != 0) {
+                       tf->raw.r[i] = pci->read_io_8(device, ioaddr + 1 + i);
+                       SHOW_FLOW( 4, "%x: %x", i, (int)tf->raw.r[i] );
+               }
+       }
+
+       return B_OK;
+}
+
+
+static uint8
+ata_adapter_get_altstatus(ata_adapter_channel_info *channel)
+{
+       pci_device_module_info *pci = channel->pci;
+       pci_device *device = channel->device;
+       uint16 altstatusaddr = channel->control_block_base;
+
+       if (channel->lost)
+               return 0x01; // Error bit
+
+       return pci->read_io_8(device, altstatusaddr);
+}
+
+
+static status_t
+ata_adapter_write_device_control(ata_adapter_channel_info *channel, uint8 val)
+{
+       pci_device_module_info *pci = channel->pci;
+       pci_device *device = channel->device;
+       uint16 device_control_addr = channel->control_block_base;
+
+       SHOW_FLOW(3, "%x", (int)val);
+
+       if (channel->lost)
+               return B_ERROR;
+
+       pci->write_io_8(device, device_control_addr, val);
+
+       return B_OK;
+}
+
+
+static status_t
+ata_adapter_write_pio(ata_adapter_channel_info *channel, uint16 *data,
+       int count, bool force_16bit)
+{
+       pci_device_module_info *pci = channel->pci;
+       pci_device *device = channel->device;
+
+       uint16 ioaddr = channel->command_block_base;
+
+       if (channel->lost)
+               return B_ERROR;
+
+       force_16bit = true;
+
+       if ((count & 1) != 0 || force_16bit) {
+               for (; count > 0; --count)
+                       pci->write_io_16(device, ioaddr, *(data++));
+       } else {
+               uint32 *cur_data = (uint32 *)data;
+
+               for (; count > 0; count -= 2)
+                       pci->write_io_32(device, ioaddr, *(cur_data++));
+       }
+
+       return B_OK;
+}
+
+
+static status_t
+ata_adapter_read_pio(ata_adapter_channel_info *channel, uint16 *data,
+       int count, bool force_16bit)
+{
+       pci_device_module_info *pci = channel->pci;
+       pci_device *device = channel->device;
+
+       uint16 ioaddr = channel->command_block_base;
+
+       if (channel->lost)
+               return B_ERROR;
+
+       force_16bit = true;
+
+       if ((count & 1) != 0 || force_16bit) {
+               for (; count > 0; --count)
+                       *(data++) = pci->read_io_16(device, ioaddr );
+       } else {
+               uint32 *cur_data = (uint32 *)data;
+
+               for (; count > 0; count -= 2)
+                       *(cur_data++) = pci->read_io_32(device, ioaddr);
+       }
+
+       return B_OK;
+}
+
+
+static int32
+ata_adapter_inthand(void *arg)
+{
+       ata_adapter_channel_info *channel = (ata_adapter_channel_info *)arg;
+       pci_device_module_info *pci = channel->pci;
+       pci_device *device = channel->device;
+       uint8 statusATA, statusBM;
+
+       TRACE_INT("ata_adapter_inthand\n");
+
+       // need to read bus master status first, because some controllers
+       // will clear the interrupt status bit once ATA status is read
+       statusBM = pci->read_io_8(device, channel->bus_master_base
+               + ATA_BM_STATUS_REG);
+       TRACE_INT("ata_adapter_inthand: BM-status 0x%02x\n", statusBM);
+
+       // test if the interrupt was really generated by our controller
+       if (statusBM & ATA_BM_STATUS_INTERRUPT) {
+               // read ATA status register to acknowledge interrupt
+               statusATA = pci->read_io_8(device, channel->command_block_base 
+ 7);
+               TRACE_INT("ata_adapter_inthand: ATA-status 0x%02x\n", 
statusATA);
+
+               // clear pending PCI bus master DMA interrupt, for those
+               // controllers who don't clear it themselves
+               pci->write_io_8(device, channel->bus_master_base + 
ATA_BM_STATUS_REG,
+                       (statusBM & 0xf8) | ATA_BM_STATUS_INTERRUPT);
+
+               if (!channel->dmaing) {
+                       // we check this late so that potential spurious 
interrupts
+                       // are acknoledged above
+                       TRACE_INT("ata_adapter_inthand: no DMA transfer 
active\n");
+                       return B_UNHANDLED_INTERRUPT;
+               }
+
+               // signal interrupt to ATA stack
+               return sATA->interrupt_handler(channel->ataChannel, statusATA);
+       } else {
+               TRACE_INT("ata_adapter_inthand: not BM\n");
+               return B_UNHANDLED_INTERRUPT;
+       }
+}
+
+
+static status_t
+ata_adapter_prepare_dma(ata_adapter_channel_info *channel,
+       const physical_entry *sgList, size_t sgListCount, bool writeToDevice)
+{
+       pci_device_module_info *pci = channel->pci;
+       pci_device *device = channel->device;
+       uint8 command;
+       uint8 status;
+       prd_entry *prd = channel->prdt;
+       int i;
+
+       TRACE_DMA("ata_adapter: prepare_dma (%s) %lu entrys:\n",
+               writeToDevice ? "write" : "read", sgListCount);
+
+       for (i = sgListCount - 1, prd = channel->prdt; i >= 0; --i, ++prd, 
++sgList) {
+               prd->address = 
B_HOST_TO_LENDIAN_INT32((uint32)pci->ram_address(device,
+                       (void*)(addr_t)sgList->address));
+               // 0 means 64K - this is done automatically be discarding upper 
16 bits
+               prd->count = B_HOST_TO_LENDIAN_INT16((uint16)sgList->size);
+               prd->EOT = i == 0;
+
+               TRACE_DMA("ata_adapter: %#" B_PRIxPHYSADDR ", %" B_PRIuPHYSADDR 
" => "
+                       "%#010" B_PRIx32 ", %" B_PRIu16 ", %d\n",
+                       sgList->address, sgList->size, 
+                       prd->address, prd->count, prd->EOT);
+               SHOW_FLOW( 4, "%#010" B_PRIx32 ", %" B_PRIu16 ", %d", 
+                       prd->address, prd->count, prd->EOT);
+       }
+
+       pci->write_io_32(device, channel->bus_master_base + ATA_BM_PRDT_ADDRESS,
+               (pci->read_io_32(device, channel->bus_master_base + 
ATA_BM_PRDT_ADDRESS) & 3)
+               | (B_HOST_TO_LENDIAN_INT32((uint32)pci->ram_address(device,
+                       (void *)channel->prdt_phys)) & ~3));
+
+       // reset interrupt and error signal
+       status = pci->read_io_8(device, channel->bus_master_base
+               + ATA_BM_STATUS_REG) | ATA_BM_STATUS_INTERRUPT | 
ATA_BM_STATUS_ERROR;
+       pci->write_io_8(device,
+               channel->bus_master_base + ATA_BM_STATUS_REG, status);
+
+       // set data direction
+       command = pci->read_io_8(device, channel->bus_master_base
+               + ATA_BM_COMMAND_REG);
+       if (writeToDevice)
+               command &= ~ATA_BM_COMMAND_READ_FROM_DEVICE;
+       else
+               command |= ATA_BM_COMMAND_READ_FROM_DEVICE;
+
+       pci->write_io_8(device, channel->bus_master_base + ATA_BM_COMMAND_REG,
+               command);
+
+       return B_OK;
+}
+
+
+static status_t
+ata_adapter_start_dma(ata_adapter_channel_info *channel)
+{
+       pci_device_module_info *pci = channel->pci;
+       pci_device *device = channel->device;
+       uint8 command;
+
+       command = pci->read_io_8(device, channel->bus_master_base
+               + ATA_BM_COMMAND_REG);
+
+       command |= ATA_BM_COMMAND_START_STOP;
+
+       channel->dmaing = true;
+
+       pci->write_io_8(device, channel->bus_master_base + ATA_BM_COMMAND_REG,
+               command);
+
+       return B_OK;
+}
+
+
+static status_t
+ata_adapter_finish_dma(ata_adapter_channel_info *channel)
+{
+       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
+               + ATA_BM_STATUS_REG);
+
+       // stop DMA engine, this also clears ATA_BM_STATUS_ACTIVE
+       // in the BM status register
+       command = pci->read_io_8(device, channel->bus_master_base
+               + ATA_BM_COMMAND_REG);
+       pci->write_io_8(device, channel->bus_master_base + ATA_BM_COMMAND_REG,
+               command & ~ATA_BM_COMMAND_START_STOP);
+       channel->dmaing = false;
+
+       // reset error flag
+       pci->write_io_8(device, channel->bus_master_base + ATA_BM_STATUS_REG,
+               status | ATA_BM_STATUS_ERROR);
+
+       if ((status & ATA_BM_STATUS_ACTIVE) != 0)
+               return B_DEV_DATA_OVERRUN;
+
+       if ((status & ATA_BM_STATUS_ERROR) != 0)
+               return B_ERROR;
+
+       return B_OK;
+}
+
+
+static status_t
+ata_adapter_init_channel(device_node *node,
+       ata_adapter_channel_info **cookie, size_t total_data_size,
+       int32 (*inthand)(void *arg))
+{
+       ata_adapter_controller_info *controller;
+       ata_adapter_channel_info *channel;
+       uint16 command_block_base, control_block_base;
+       uint8 intnum;
+       int prdt_size;
+       physical_entry pe[1];
+       uint8 channel_index;
+       status_t res;
+
+       TRACE("PCI-ATA: init channel...\n");
+
+#if 0
+       if (1 /* debug */){
+               uint8 bus, device, function;
+               uint16 vendorID, deviceID;
+               sDeviceManager->get_attr_uint8(node, PCI_DEVICE_BUS_ITEM, &bus, 
true);
+               sDeviceManager->get_attr_uint8(node, PCI_DEVICE_DEVICE_ITEM, 
&device, true);
+               sDeviceManager->get_attr_uint8(node, PCI_DEVICE_FUNCTION_ITEM, 
&function, true);
+               sDeviceManager->get_attr_uint16(node, 
PCI_DEVICE_VENDOR_ID_ITEM, &vendorID, true);
+               sDeviceManager->get_attr_uint16(node, 
PCI_DEVICE_DEVICE_ID_ITEM, &deviceID, true);
+               TRACE("PCI-ATA: bus %3d, device %2d, function %2d: vendor %04x, 
device %04x\n",
+                       bus, device, function, vendorID, deviceID);
+       }
+#endif
+
+       // get device data
+       if (sDeviceManager->get_attr_uint16(node, 
ATA_ADAPTER_COMMAND_BLOCK_BASE, &command_block_base, false) != B_OK
+               || sDeviceManager->get_attr_uint16(node, 
ATA_ADAPTER_CONTROL_BLOCK_BASE, &control_block_base, false) != B_OK
+               || sDeviceManager->get_attr_uint8(node, ATA_ADAPTER_INTNUM, 
&intnum, true) != B_OK
+               || sDeviceManager->get_attr_uint8(node, 
ATA_ADAPTER_CHANNEL_INDEX, &channel_index, false) != B_OK)
+               return B_ERROR;
+
+       {
+               device_node *parent = sDeviceManager->get_parent_node(node);
+               sDeviceManager->get_driver(parent, NULL, (void **)&controller);
+               sDeviceManager->put_node(parent);
+       }
+
+       channel = (ata_adapter_channel_info *)malloc(total_data_size);
+       if (channel == NULL) {
+               res = B_NO_MEMORY;
+               goto err;
+       }
+
+       TRACE("PCI-ATA: channel index %d\n", channel_index);
+
+       channel->node = node;
+       channel->pci = controller->pci;
+       channel->device = controller->device;
+       channel->lost = false;
+       channel->command_block_base = command_block_base;
+       channel->control_block_base = control_block_base;
+       channel->bus_master_base = controller->bus_master_base + (channel_index 
* 8);
+       channel->intnum = intnum;
+       channel->dmaing = false;
+       channel->inthand = inthand;
+
+       TRACE("PCI-ATA: bus master base %#x\n", channel->bus_master_base);
+
+       // PRDT must be contiguous, dword-aligned and must not cross 64K 
boundary
+// TODO: Where's the handling for the 64 K boundary? create_area_etc() can be
+// used.
+       prdt_size = (ATA_ADAPTER_MAX_SG_COUNT * sizeof( prd_entry ) + 
(B_PAGE_SIZE - 1)) & ~(B_PAGE_SIZE - 1);
+       channel->prd_area = create_area("prd", (void **)&channel->prdt, 
B_ANY_KERNEL_ADDRESS,
+               prdt_size, B_32_BIT_CONTIGUOUS, 0);
+       if (channel->prd_area < B_OK) {
+               res = channel->prd_area;
+               goto err2;
+       }
+
+       get_memory_map(channel->prdt, prdt_size, pe, 1);
+       channel->prdt_phys = pe[0].address;
+
+       SHOW_FLOW(3, "virt=%p, phys=%x", channel->prdt, 
(int)channel->prdt_phys);
+
+       res = install_io_interrupt_handler(channel->intnum,
+               inthand, channel, 0);
+
+       if (res < 0) {
+               SHOW_ERROR(0, "couldn't install irq handler @%d", 
channel->intnum);
+               goto err3;
+       }
+
+       TRACE("PCI-ATA: init channel done\n");
+
+       // disable interrupts
+       ata_adapter_write_device_control(channel, ATA_DEVICE_CONTROL_BIT3 | 
ATA_DEVICE_CONTROL_DISABLE_INTS);
+
+       *cookie = channel;
+
+       return B_OK;
+
+err3:
+       delete_area(channel->prd_area);
+err2:
+err:
+       free(channel);
+
+       return res;
+}
+
+
+static void
+ata_adapter_uninit_channel(ata_adapter_channel_info *channel)
+{
+       // disable IRQs
+       ata_adapter_write_device_control(channel, ATA_DEVICE_CONTROL_BIT3 | 
ATA_DEVICE_CONTROL_DISABLE_INTS);
+
+       // catch spurious interrupt
+       // (some controllers generate an IRQ when you _disable_ interrupts,
+       //  they are delayed by less then 40 µs, so 1 ms is safe)
+       snooze(1000);
+
+       remove_io_interrupt_handler(channel->intnum, channel->inthand, channel);
+
+       delete_area(channel->prd_area);
+       free(channel);
+}
+
+
+static void
+ata_adapter_channel_removed(ata_adapter_channel_info *channel)
+{
+       SHOW_FLOW0( 3, "" );
+
+       if (channel != NULL)
+               // disable access instantly
+               atomic_or((int32*)&channel->lost, 1);
+}
+
+
+/** publish node of ata channel */
+
+static status_t
+ata_adapter_publish_channel(device_node *controller_node,
+       const char *channel_module_name, uint16 command_block_base,
+       uint16 control_block_base, uint8 intnum, bool can_dma,
+       uint8 channel_index, const char *name, const io_resource *resources,
+       device_node **node)
+{
+       char prettyName[25];
+       sprintf(prettyName, "ATA Channel %" B_PRIu8, channel_index);
+
+       device_attr attrs[] = {
+               // info about ourself and our consumer
+               { B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
+                       { string: prettyName }},
+               { B_DEVICE_FIXED_CHILD, B_STRING_TYPE,
+                       { string: ATA_FOR_CONTROLLER_MODULE_NAME }},
+
+               // private data to identify channel
+               { ATA_ADAPTER_COMMAND_BLOCK_BASE, B_UINT16_TYPE,
+                       { ui16: command_block_base }},
+               { ATA_ADAPTER_CONTROL_BLOCK_BASE, B_UINT16_TYPE,
+                       { ui16: control_block_base }},
+               { ATA_CONTROLLER_CAN_DMA_ITEM, B_UINT8_TYPE, { ui8: can_dma }},
+               { ATA_ADAPTER_INTNUM, B_UINT8_TYPE, { ui8: intnum }},
+               { ATA_ADAPTER_CHANNEL_INDEX, B_UINT8_TYPE, { ui8: channel_index 
}},
+               { NULL }
+       };
+
+       SHOW_FLOW0(2, "");
+
+       return sDeviceManager->register_node(controller_node, 
channel_module_name, attrs,
+               resources, node);
+}
+
+
+/** detect IDE channel */
+
+static status_t
+ata_adapter_detect_channel(pci_device_module_info *pci, pci_device *pci_device,
+       device_node *controller_node, const char *channel_module_name,
+       bool controller_can_dma, uint16 command_block_base, uint16 
control_block_base,
+       uint16 bus_master_base, uint8 intnum, uint8 channel_index, const char 
*name,
+       device_node **node, bool supports_compatibility_mode)
+{
+       uint8 api;
+       uint16 pcicmdOld;
+       uint16 pcicmdNew;
+       uint16 pciVendor;
+
+       SHOW_FLOW0( 3, "" );
+
+       // if channel works in compatibility mode, addresses and interrupt are 
fixed
+       api = pci->read_pci_config(pci_device, PCI_class_api, 1);
+
+       if (supports_compatibility_mode
+               && channel_index == 0 && (api & ATA_API_PRIMARY_NATIVE) == 0) {
+               command_block_base = 0x1f0;
+               control_block_base = 0x3f6;
+               intnum = 14;
+               TRACE("PCI-ATA: Controller in legacy mode: cmd %#x, ctrl %#x, 
irq %d\n",
+                         command_block_base, control_block_base, intnum);
+       } else if (supports_compatibility_mode
+               && channel_index == 1 && (api & ATA_API_PRIMARY_NATIVE) == 0) {
+               command_block_base = 0x170;
+               control_block_base = 0x376;
+               intnum = 15;
+               TRACE("PCI-ATA: Controller in legacy mode: cmd %#x, ctrl %#x, 
irq %d\n",
+                         command_block_base, control_block_base, intnum);
+       } else {
+               if (command_block_base == 0 || control_block_base == 0) {
+                       TRACE("PCI-ATA: Command/Control Block base is not 
configured\n");
+                       return B_ERROR;
+               }
+               if (intnum == 0 || intnum == 0xff) {
+                       TRACE("PCI-ATA: Interrupt is not configured\n");
+                       return B_ERROR;
+               }
+
+               // historically, they start at 3f6h/376h, but PCI spec requires 
registers
+               // to be aligned at 4 bytes, so only 3f4h/374h can be 
specified; thus
+               // PCI IDE defines that control block starts at offset 2
+               control_block_base += 2;
+               TRACE("PCI-ATA: Controller in native mode: cmd %#x, ctrl %#x, 
irq %d\n",
+                         command_block_base, control_block_base, intnum);
+       }
+
+
+       // this should be done in ata_adapter_init_controller but there is 
crashes
+       pcicmdOld = pcicmdNew = pci->read_pci_config(pci_device, PCI_command, 
2);
+       if ((pcicmdNew & (1 << 10)) != 0) {
+               TRACE("PCI-ATA: enabling interrupts\n");
+               pcicmdNew &= ~(1 << 10);
+       }
+       if ((pcicmdNew & PCI_command_io) == 0) {
+               TRACE("PCI-ATA: enabling io decoder\n");
+               pcicmdNew |= PCI_command_io;
+       }
+       if ((pcicmdNew & PCI_command_master) == 0) {
+               TRACE("PCI-ATA: enabling bus mastering\n");
+               pcicmdNew |= PCI_command_master;
+       }
+       if (pcicmdOld != pcicmdNew) {
+               pci->write_pci_config(pci_device, PCI_command, 2, pcicmdNew);
+               TRACE("PCI-ATA: pcicmd changed from 0x%04x to 0x%04x\n",
+                       pcicmdOld, pcicmdNew);
+       }
+
+
+       if (supports_compatibility_mode) {
+               // read status of primary(!) channel to detect simplex
+               uint8 status = pci->read_io_8(pci_device, bus_master_base
+                       + ATA_BM_STATUS_REG);
+
+               if (status & ATA_BM_STATUS_SIMPLEX_DMA && channel_index != 0) {
+                       // in simplex mode, channels cannot operate 
independantly of each other;
+                       // we simply disable bus mastering of second channel to 
satisfy that;
+                       // better were to use a controller lock, but this had 
to be done in the IDE
+                       // bus manager, and I don't see any reason to add extra 
code for old
+                       // simplex controllers
+
+                       // Intel controllers use this bit for something else 
and are not simplex.
+                       pciVendor = pci->read_pci_config(pci_device, 
PCI_vendor_id, 2);
+
+                       if (pciVendor != 0x8086) {
+                               TRACE("PCI-ATA: Simplex controller - disabling 
DMA of secondary channel\n");
+                               controller_can_dma = false;
+                       } else {
+                               TRACE("PCI-ATA: Simplex bit ignored - Intel 
controller\n");
+                       }
+               }
+       }
+
+       {
+               io_resource resources[3] = {
+                       { B_IO_PORT, command_block_base, 8 },
+                       { B_IO_PORT, control_block_base, 1 },
+                       {}
+               };
+
+               return ata_adapter_publish_channel(controller_node, 
channel_module_name,
+                       command_block_base, control_block_base, intnum, 
controller_can_dma,
+                       channel_index, name, resources, node);
+       }
+}
+
+
+static status_t
+ata_adapter_init_controller(device_node *node,
+       ata_adapter_controller_info **cookie, size_t total_data_size)
+{
+       pci_device_module_info *pci;
+       pci_device *device;
+       ata_adapter_controller_info *controller;
+       uint16 bus_master_base;
+
+       // get device data
+       if (sDeviceManager->get_attr_uint16(node, ATA_ADAPTER_BUS_MASTER_BASE, 
&bus_master_base, false) != B_OK)
+               return B_ERROR;
+
+       {
+               device_node *parent = sDeviceManager->get_parent_node(node);
+               sDeviceManager->get_driver(parent, (driver_module_info **)&pci, 
(void **)&device);
+               sDeviceManager->put_node(parent);
+       }
+
+       controller = (ata_adapter_controller_info *)malloc(total_data_size);
+       if (controller == NULL)
+               return B_NO_MEMORY;
+
+#if 0
+       pcicmdOld = pcicmdNew = pci->read_pci_config(node, PCI_command, 2);
+       if ((pcicmdNew & PCI_command_io) == 0) {
+               TRACE("PCI-ATA: adapter init: enabling io decoder\n");
+               pcicmdNew |= PCI_command_io;
+       }
+       if ((pcicmdNew & PCI_command_master) == 0) {
+               TRACE("PCI-ATA: adapter init: enabling bus mastering\n");
+               pcicmdNew |= PCI_command_master;
+       }
+       if (pcicmdOld != pcicmdNew) {
+               pci->write_pci_config(node, PCI_command, 2, pcicmdNew);
+               TRACE("PCI-ATA: adapter init: pcicmd old 0x%04x, new 0x%04x\n",
+                       pcicmdOld, pcicmdNew);
+       }
+#endif
+
+       controller->node = node;
+       controller->pci = pci;
+       controller->device = device;
+       controller->lost = false;
+       controller->bus_master_base = bus_master_base;
+
+       *cookie = controller;
+
+       return B_OK;
+}
+
+
+static void
+ata_adapter_uninit_controller(ata_adapter_controller_info *controller)
+{
+       free(controller);
+}
+
+
+static void
+ata_adapter_controller_removed(ata_adapter_controller_info *controller)
+{
+       SHOW_FLOW0(3, "");
+
+       if (controller != NULL) {
+               // disable access instantly; unit_device takes care of 
unregistering ioports
+               atomic_or((int32*)&controller->lost, 1);
+       }
+}
+
+
+/** publish node of ata controller */
+
+static status_t
+ata_adapter_publish_controller(device_node *parent, uint16 bus_master_base,
+       io_resource *resources, const char *controller_driver,
+       const char *controller_driver_type, const char *controller_name, bool 
can_dma,
+       bool can_cq, uint32 dma_alignment, uint32 dma_boundary, uint32 
max_sg_block_size,
+       device_node **node)
+{
+       device_attr attrs[] = {
+               // properties of this controller for ata bus manager
+               // there are always max. 2 devices
+               // (unless this is a Compact Flash Card with a built-in IDE 
controller,
+               //  which has exactly 1 device)
+               { ATA_CONTROLLER_MAX_DEVICES_ITEM, B_UINT8_TYPE, { ui8: 2 }},
+               // of course we can DMA
+               { ATA_CONTROLLER_CAN_DMA_ITEM, B_UINT8_TYPE, { ui8: can_dma }},
+               // choose any name here
+               { ATA_CONTROLLER_CONTROLLER_NAME_ITEM, B_STRING_TYPE,
+                       { string: controller_name }},
+
+               // DMA properties
+               // data must be word-aligned;
+               // warning: some controllers are more picky!
+               { B_DMA_ALIGNMENT, B_UINT32_TYPE, { ui32: dma_alignment /*1*/}},
+               // one S/G block must not cross 64K boundary
+               { B_DMA_BOUNDARY, B_UINT32_TYPE, { ui32: dma_boundary/*0xffff*/ 
}},
+               // max size of S/G block is 16 bits with zero being 64K
+               { B_DMA_MAX_SEGMENT_BLOCKS, B_UINT32_TYPE,
+                       { ui32: max_sg_block_size/*0x10000*/ }},
+               { B_DMA_MAX_SEGMENT_COUNT, B_UINT32_TYPE,
+                       { ui32: ATA_ADAPTER_MAX_SG_COUNT }},
+               { B_DMA_HIGH_ADDRESS, B_UINT64_TYPE, { ui64: 0x100000000LL }},
+
+               // private data to find controller
+               { ATA_ADAPTER_BUS_MASTER_BASE, B_UINT16_TYPE, { ui16: 
bus_master_base }},
+               { NULL }
+       };
+
+       SHOW_FLOW0( 2, "" );
+
+       return sDeviceManager->register_node(parent, controller_driver, attrs, 
resources, node);
+}
+
+
+/** detect pure IDE controller, i.e. without channels */
+
+static status_t
+ata_adapter_detect_controller(pci_device_module_info *pci, pci_device 
*pci_device,
+       device_node *parent, uint16 bus_master_base, const char 
*controller_driver,
+       const char *controller_driver_type, const char *controller_name, bool 
can_dma,
+       bool can_cq, uint32 dma_alignment, uint32 dma_boundary, uint32 
max_sg_block_size,
+       device_node **node)
+{
+       io_resource resources[2] = {
+               { B_IO_PORT, bus_master_base, 16 },
+               {}
+       };
+
+       SHOW_FLOW0( 3, "" );
+
+       if (bus_master_base == 0) {
+               TRACE("PCI-ATA: Controller detection failed! bus master base 
not configured\n");
+               return B_ERROR;
+       }
+
+       return ata_adapter_publish_controller(parent, bus_master_base, 
resources,
+               controller_driver, controller_driver_type, controller_name, 
can_dma, can_cq,
+               dma_alignment, dma_boundary, max_sg_block_size, node);
+}
+
+
+static status_t
+ata_adapter_probe_controller(device_node *parent, const char 
*controller_driver,
+       const char *controller_driver_type, const char *controller_name,
+       const char *channel_module_name, bool can_dma, bool can_cq, uint32 
dma_alignment,
+       uint32 dma_boundary, uint32 max_sg_block_size, bool 
supports_compatibility_mode)
+{
+       pci_device_module_info *pci;
+       pci_device *device;
+       uint16 command_block_base[2];
+       uint16 control_block_base[2];
+       uint16 bus_master_base;
+       device_node *controller_node;
+       device_node *channels[2];
+       uint8 intnum;
+       status_t res;
+
+       SHOW_FLOW0( 3, "" );
+
+       sDeviceManager->get_driver(parent, (driver_module_info **)&pci, (void 
**)&device);
+
+       command_block_base[0] = pci->read_pci_config(device, 
PCI_base_registers, 4 );
+       control_block_base[0] = pci->read_pci_config(device, PCI_base_registers 
+ 4, 4);
+       command_block_base[1] = pci->read_pci_config(device, PCI_base_registers 
+ 8, 4);
+       control_block_base[1] = pci->read_pci_config(device, PCI_base_registers 
+ 12, 4);
+       bus_master_base = pci->read_pci_config(device, PCI_base_registers + 16, 
4);
+       intnum = pci->read_pci_config(device, PCI_interrupt_line, 1);
+
+       command_block_base[0] &= PCI_address_io_mask;
+       control_block_base[0] &= PCI_address_io_mask;
+       command_block_base[1] &= PCI_address_io_mask;
+       control_block_base[1] &= PCI_address_io_mask;
+       bus_master_base &= PCI_address_io_mask;
+
+       res = ata_adapter_detect_controller(pci, device, parent, 
bus_master_base,
+               controller_driver, controller_driver_type, controller_name, 
can_dma,
+               can_cq, dma_alignment, dma_boundary, max_sg_block_size, 
&controller_node);
+       // don't register if controller is already registered!
+       // (happens during rescan; registering new channels would kick out old 
channels)
+       if (res != B_OK || controller_node == NULL)
+               return res;
+
+       // ignore errors during registration of channels - could be a simple 
rescan collision
+       ata_adapter_detect_channel(pci, device, controller_node, 
channel_module_name,
+               can_dma, command_block_base[0], control_block_base[0], 
bus_master_base,
+               intnum, 0, "Primary Channel", &channels[0], 
supports_compatibility_mode);
+
+       ata_adapter_detect_channel(pci, device, controller_node, 
channel_module_name,
+               can_dma, command_block_base[1], control_block_base[1], 
bus_master_base,
+               intnum, 1, "Secondary Channel", &channels[1], 
supports_compatibility_mode);
+
+       return B_OK;
+}
+
+
+static status_t
+std_ops(int32 op, ...)
+{
+       switch (op) {
+               case B_MODULE_INIT:
+               case B_MODULE_UNINIT:
+                       return B_OK;
+
+               default:
+                       return B_ERROR;
+       }
+}
+
+
+module_dependency module_dependencies[] = {
+       { ATA_FOR_CONTROLLER_MODULE_NAME, (module_info **)&sATA },
+       { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager },
+       {}
+};
+
+
+static ata_adapter_interface adapter_interface = {
+       {
+               ATA_ADAPTER_MODULE_NAME,
+               0,
+               std_ops
+       },
+
+       set_channel,
+
+       ata_adapter_write_command_block_regs,
+       ata_adapter_read_command_block_regs,
+
+       ata_adapter_get_altstatus,
+       ata_adapter_write_device_control,
+
+       ata_adapter_write_pio,
+       ata_adapter_read_pio,
+
+       ata_adapter_prepare_dma,
+       ata_adapter_start_dma,
+       ata_adapter_finish_dma,
+
+       ata_adapter_inthand,
+
+       ata_adapter_init_channel,
+       ata_adapter_uninit_channel,
+       ata_adapter_channel_removed,
+
+       ata_adapter_publish_channel,
+       ata_adapter_detect_channel,
+
+       ata_adapter_init_controller,
+       ata_adapter_uninit_controller,
+       ata_adapter_controller_removed,
+
+       ata_adapter_publish_controller,
+       ata_adapter_detect_controller,
+
+       ata_adapter_probe_controller
+};
+
+module_info *modules[] = {
+       &adapter_interface.info,
+       NULL
+};

Modified: haiku/trunk/src/add-ons/kernel/generic/ide_adapter/Jamfile
===================================================================
--- haiku/trunk/src/add-ons/kernel/generic/ide_adapter/Jamfile  2011-09-08 
03:15:37 UTC (rev 42724)
+++ haiku/trunk/src/add-ons/kernel/generic/ide_adapter/Jamfile  2011-09-08 
15:47:25 UTC (rev 42725)
@@ -3,6 +3,6 @@
 UsePrivateHeaders drivers kernel ;
 
 KernelAddon ide_adapter :
-       ide_adapter.c
+       ide_adapter.cpp
        ;
 

Copied: haiku/trunk/src/add-ons/kernel/generic/ide_adapter/ide_adapter.cpp 
(from rev 42724, 
haiku/trunk/src/add-ons/kernel/generic/ide_adapter/ide_adapter.c)
===================================================================
--- haiku/trunk/src/add-ons/kernel/generic/ide_adapter/ide_adapter.cpp          
                (rev 0)
+++ haiku/trunk/src/add-ons/kernel/generic/ide_adapter/ide_adapter.cpp  
2011-09-08 15:47:25 UTC (rev 42725)
@@ -0,0 +1,845 @@
+/*
+ * Copyright 2002-04, Thomas Kurschel. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ */
+
+/*
+       Generic IDE adapter library.
+
+       The correct name would be ATA adapter, but I chose the old name as it's
+       more widely known.
+*/
+
+#include <KernelExport.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <device_manager.h>
+#include <bus/PCI.h>
+#include <bus/IDE.h>
+#include <ide_types.h>
+#include <ide_adapter.h>
+#include <lendian_bitfield.h>
+
+#define debug_level_flow 0
+#define debug_level_error 3
+#define debug_level_info 3
+
+#define DEBUG_MSG_PREFIX "IDE PCI -- "
+
+#include "wrapper.h"
+
+#define TRACE dprintf
+
+
+static ide_for_controller_interface *ide;
+static device_manager_info *pnp;
+
+
+static void
+set_channel(ide_adapter_channel_info *channel, ide_channel ideChannel)
+{
+       channel->ideChannel = ideChannel;
+}
+
+
+static status_t
+ide_adapter_write_command_block_regs(ide_adapter_channel_info *channel,
+       ide_task_file *tf, ide_reg_mask mask)
+{
+       pci_device_module_info *pci = channel->pci;
+       pci_device *device = channel->device;
+       int i;
+
+       uint16 ioaddr = channel->command_block_base;
+
+       if (channel->lost)
+               return B_ERROR;
+
+       for (i = 0; i < 7; i++) {
+               // LBA48 registers must be written twice
+               if (((1 << (i + 7)) & mask) != 0) {
+                       SHOW_FLOW( 4, "%x->HI(%x)", tf->raw.r[i + 7], i );
+                       pci->write_io_8(device, ioaddr + 1 + i, tf->raw.r[i + 
7]);
+               }
+
+               if (((1 << i) & mask) != 0) {
+                       SHOW_FLOW( 4, "%x->LO(%x)", tf->raw.r[i], i );
+                       pci->write_io_8(device, ioaddr + 1 + i, tf->raw.r[i]);

[... truncated: 777 lines follow ...]

Other related posts: