/* * Copyright 2007, Ithamar R. Adema. All rights reserved. * Distributed under the terms of the MIT License. */ #include #include #include #include #define DRIVER_PRETTY_NAME "Legacy SATA" #define CONTROLLER_NAME DRIVER_PRETTY_NAME #define CONTROLLER_MODULE_NAME "busses/ata/legacy_sata/driver_v1" #define CHANNEL_MODULE_NAME "busses/ata/legacy_sata/channel/v1" #define TRACE(a...) dprintf(DRIVER_PRETTY_NAME ": " a) #define FLOW(a...) dprintf(DRIVER_PRETTY_NAME ": " a) #define PCI_vendor_VIA 0x1106 #define PCI_device_VIA6420 0x3149 #define PCI_device_VIA6421 0x3249 #define PCI_device_VIA8237A 0x0591 #define PCI_vendor_ALI 0x10b9 #define PCI_device_ALI5289 0x5289 #define PCI_device_ALI5287 0x5287 #define PCI_device_ALI5281 0x5281 #define PCI_vendor_NVIDIA 0x10de #define PCI_device_NF2PROS1 0x008e #define PCI_device_NF3PROS1 0x00e3 #define PCI_device_NF3PROS2 0x00ee #define PCI_device_MCP4S1 0x0036 #define PCI_device_MCP4S2 0x003e #define PCI_device_CK804S1 0x0054 #define PCI_device_CK804S2 0x0055 #define PCI_device_MCP51S1 0x0266 #define PCI_device_MCP51S2 0x0267 #define PCI_device_MCP55S1 0x037e #define PCI_device_MCP55S2 0x037f #define PCI_device_MCP61S1 0x03e7 #define PCI_device_MCP61S2 0x03f6 #define PCI_device_MCP61S3 0x03f7 #define ID(v,d) (((v)<< 16) | (d)) static const char * const kChannelNames[] = { "Primary Channel", "Secondary Channel", "Tertiary Channel", "Quaternary Channel" }; static ata_for_controller_interface* sATA; static ata_adapter_interface* sATAAdapter; static device_manager_info* sDeviceManager; static float controller_supports(device_node *parent) { uint16 vendor_id; uint16 device_id; status_t res; const char *bus = NULL; // get the bus (should be PCI) if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false) != B_OK) return B_ERROR; if (strcmp(bus, "pci") != 0) { return B_ERROR; } // get vendor and device ID if ((res = sDeviceManager->get_attr_uint16(parent, B_DEVICE_VENDOR_ID, &vendor_id, false)) != B_OK || (res = sDeviceManager->get_attr_uint16(parent, B_DEVICE_ID, &device_id, false)) != B_OK) { return res; } switch (ID(vendor_id, device_id)) { /* VIA SATA chipsets */ case ID(PCI_vendor_VIA, PCI_device_VIA6420): case ID(PCI_vendor_VIA, PCI_device_VIA6421): case ID(PCI_vendor_VIA, PCI_device_VIA8237A): break; /* ALI SATA chipsets */ case ID(PCI_vendor_ALI, PCI_device_ALI5281): case ID(PCI_vendor_ALI, PCI_device_ALI5287): case ID(PCI_vendor_ALI, PCI_device_ALI5289): break; /* NVidia NForce chipsets */ case ID(PCI_vendor_NVIDIA, PCI_device_NF2PROS1): case ID(PCI_vendor_NVIDIA, PCI_device_NF3PROS1): case ID(PCI_vendor_NVIDIA, PCI_device_NF3PROS2): case ID(PCI_vendor_NVIDIA, PCI_device_MCP4S1): case ID(PCI_vendor_NVIDIA, PCI_device_MCP4S2): case ID(PCI_vendor_NVIDIA, PCI_device_CK804S1): case ID(PCI_vendor_NVIDIA, PCI_device_CK804S2): case ID(PCI_vendor_NVIDIA, PCI_device_MCP51S1): case ID(PCI_vendor_NVIDIA, PCI_device_MCP51S2): case ID(PCI_vendor_NVIDIA, PCI_device_MCP55S1): case ID(PCI_vendor_NVIDIA, PCI_device_MCP55S2): case ID(PCI_vendor_NVIDIA, PCI_device_MCP61S1): case ID(PCI_vendor_NVIDIA, PCI_device_MCP61S2): case ID(PCI_vendor_NVIDIA, PCI_device_MCP61S3): break; default: return 0.0f; } TRACE("controller found! vendor 0x%04x, device 0x%04x\n", vendor_id, device_id); return 0.8f; } static status_t controller_probe(device_node *parent) { device_node *controller_node; device_node *channels[4]; uint16 command_block_base[4]; uint16 control_block_base[4]; pci_device_module_info *pci; uint8 num_channels = 2; uint32 bus_master_base; pci_device *device = NULL; uint16 device_id; uint16 vendor_id; uint8 int_num; status_t res; uint8 index; TRACE("controller_probe\n"); sDeviceManager->get_driver(parent, (driver_module_info **)&pci, (void **)&device); device_id = pci->read_pci_config(device, PCI_device_id, 2); vendor_id = pci->read_pci_config(device, PCI_vendor_id, 2); int_num = pci->read_pci_config(device, PCI_interrupt_line, 1); bus_master_base = pci->read_pci_config(device, PCI_base_registers + 16, 4); /* Default PCI assigments */ command_block_base[0] = pci->read_pci_config(device, PCI_base_registers + 0, 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); /* enable PCI interrupt */ pci->write_pci_config(device, PCI_command, 2, pci->read_pci_config(device, PCI_command, 2) & ~PCI_command_int_disable); if (vendor_id == PCI_vendor_NVIDIA) { /* enable control access */ pci->write_pci_config(device, 0x50, 1, pci->read_pci_config(device, 0x50, 1) | 0x04); } switch (ID(vendor_id, device_id)) { case ID(PCI_vendor_VIA,PCI_device_VIA6421): /* newer SATA chips has resources in one BAR for each channel */ num_channels = 4; command_block_base[0] = pci->read_pci_config(device, PCI_base_registers + 0, 4); control_block_base[0] = command_block_base[0] + 8; command_block_base[1] = pci->read_pci_config(device, PCI_base_registers + 4, 4); control_block_base[1] = command_block_base[1] + 8; command_block_base[2] = pci->read_pci_config(device, PCI_base_registers + 8, 4); control_block_base[2] = command_block_base[2] + 8; command_block_base[3] = pci->read_pci_config(device, PCI_base_registers + 12, 4); control_block_base[3] = command_block_base[3] + 8; break; case ID(PCI_vendor_ALI, PCI_device_ALI5287): num_channels = 4; command_block_base[2] = pci->read_pci_config(device, PCI_base_registers + 0, 4) + 8; control_block_base[2] = pci->read_pci_config(device, PCI_base_registers + 4, 4) + 4; command_block_base[3] = pci->read_pci_config(device, PCI_base_registers + 8, 4) + 8; control_block_base[3] = pci->read_pci_config(device, PCI_base_registers + 12, 4) + 4; break; } bus_master_base &= PCI_address_io_mask; for (index = 0; index < num_channels; index++) { command_block_base[index] &= PCI_address_io_mask; control_block_base[index] &= PCI_address_io_mask; } res = sATAAdapter->detect_controller(pci, device, parent, bus_master_base, CONTROLLER_MODULE_NAME, "" /* XXX: unused: controller_driver_type*/, CONTROLLER_NAME, true, true, 1, 0xffff, 0x10000, &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) goto err; if (controller_node == NULL) { res = B_IO_ERROR; goto err; } // ignore errors during registration of channels - could be a simple rescan collision for (index = 0; index < num_channels; index++) { res = sATAAdapter->detect_channel(pci, device, controller_node, CHANNEL_MODULE_NAME, true, command_block_base[index], control_block_base[index], bus_master_base, int_num, index, kChannelNames[index], &channels[index], false); dprintf("%s: %s\n", kChannelNames[index], strerror(res)); } TRACE("controller_probe success\n"); return B_OK; err: TRACE("controller_probe failed (%s)\n", strerror(res)); return res; } static status_t controller_init(device_node *node, void **controller_cookie) { return sATAAdapter->init_controller( node, (ata_adapter_controller_info**)controller_cookie, sizeof(ata_adapter_controller_info)); } static void controller_uninit(void *controller_cookie) { sATAAdapter->uninit_controller((ata_adapter_controller_info*)controller_cookie); } static void controller_removed(void *controller_cookie) { sATAAdapter->controller_removed((ata_adapter_controller_info*)controller_cookie); } static status_t channel_init(device_node *node, void **channel_cookie) { return sATAAdapter->init_channel(node, (ata_adapter_channel_info**)channel_cookie, sizeof(ata_adapter_channel_info), sATAAdapter->inthand); } static void channel_uninit(void *channel_cookie) { sATAAdapter->uninit_channel((ata_adapter_channel_info*)channel_cookie); } static void channel_removed(void *channel_cookie) { sATAAdapter->channel_removed((ata_adapter_channel_info*)channel_cookie); } static void channel_set(void *channel_cookie, ata_channel channel) { sATAAdapter->set_channel((ata_adapter_channel_info*)channel_cookie, channel); } static status_t task_file_write(void *channel_cookie, ata_task_file *tf, ata_reg_mask mask) { return sATAAdapter->write_command_block_regs( (ata_adapter_channel_info*)channel_cookie, tf, mask); } static status_t task_file_read(void *channel_cookie, ata_task_file *tf, ata_reg_mask mask) { return sATAAdapter->read_command_block_regs( (ata_adapter_channel_info*)channel_cookie, tf, mask); } static uint8 altstatus_read(void *channel_cookie) { return sATAAdapter->get_altstatus( (ata_adapter_channel_info*)channel_cookie); } static status_t device_control_write(void *channel_cookie, uint8 val) { return sATAAdapter->write_device_control( (ata_adapter_channel_info*)channel_cookie, val); } static status_t pio_write(void *channel_cookie, uint16 *data, int count, bool force_16bit) { return sATAAdapter->write_pio((ata_adapter_channel_info*)channel_cookie, data, count, force_16bit); } static status_t pio_read(void *channel_cookie, uint16 *data, int count, bool force_16bit) { return sATAAdapter->read_pio((ata_adapter_channel_info*)channel_cookie, data, count, force_16bit); } static status_t dma_prepare(void *channel_cookie, const physical_entry *sg_list, size_t sg_list_count, bool write) { return sATAAdapter->prepare_dma((ata_adapter_channel_info*)channel_cookie, sg_list, sg_list_count, write); } static status_t dma_start(void *channel_cookie) { return sATAAdapter->start_dma((ata_adapter_channel_info*)channel_cookie); } static status_t dma_finish(void *channel_cookie) { return sATAAdapter->finish_dma((ata_adapter_channel_info*)channel_cookie); } module_dependency module_dependencies[] = { { ATA_FOR_CONTROLLER_MODULE_NAME, (module_info **)&sATA }, { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager }, { ATA_ADAPTER_MODULE_NAME, (module_info **)&sATAAdapter }, {} }; static ata_controller_interface sChannelInterface = { { { CHANNEL_MODULE_NAME, 0, NULL }, NULL, NULL, channel_init, channel_uninit, NULL, NULL, channel_removed, }, channel_set, task_file_write, task_file_read, altstatus_read, device_control_write, pio_write, pio_read, dma_prepare, dma_start, dma_finish, }; static driver_module_info sControllerInterface = { { CONTROLLER_MODULE_NAME, 0, NULL }, controller_supports, controller_probe, controller_init, controller_uninit, NULL, // register child devices NULL, // rescan controller_removed, }; module_info *modules[] = { (module_info *)&sControllerInterface, (module_info *)&sChannelInterface, NULL };