From 13dbe1c7fffb30b6b56bdb30f26108783d32edac Mon Sep 17 00:00:00 2001 From: Marcus Overhagen Date: Sat, 17 Feb 2007 22:57:59 +0000 Subject: [PATCH] Added support function to find a PCI capability offset in the configuration data, needed for SATA support. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20149 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/drivers/PCI.h | 9 +++ src/add-ons/kernel/bus_managers/pci/pci.cpp | 58 +++++++++++++++++++ .../kernel/bus_managers/pci/pci_module.c | 3 +- .../kernel/bus_managers/pci/pci_priv.h | 4 +- 4 files changed, 72 insertions(+), 2 deletions(-) diff --git a/headers/os/drivers/PCI.h b/headers/os/drivers/PCI.h index a38ac35574..bd54e4bf21 100644 --- a/headers/os/drivers/PCI.h +++ b/headers/os/drivers/PCI.h @@ -147,6 +147,14 @@ struct pci_module_info { ); void * (*ram_address) (const void *physical_address_in_system_memory); + + status_t (*find_pci_capability) ( + uchar bus, + uchar device, + uchar function, + uchar cap_id, + uchar *offset + ); }; #define B_PCI_MODULE_NAME "bus_managers/pci/v1" @@ -617,6 +625,7 @@ struct pci_module_info { #define PCI_cap_id_debugport 0x0a #define PCI_cap_id_cpci_rsrcctl 0x0b #define PCI_cap_id_hotplug 0x0c +#define PCI_cap_id_sata 0x12 /* Serial ATA Capability */ /** Power Management Control Status Register settings */ #define PCI_pm_mask 0x03 diff --git a/src/add-ons/kernel/bus_managers/pci/pci.cpp b/src/add-ons/kernel/bus_managers/pci/pci.cpp index bcfa66e16c..0e2d282fc6 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci.cpp +++ b/src/add-ons/kernel/bus_managers/pci/pci.cpp @@ -64,6 +64,64 @@ pci_write_config(uint8 virt_bus, uint8 device, uint8 function, uint8 offset, uin } +status_t +pci_find_capability(uchar bus, uchar device, uchar function, uchar cap_id, uchar *offset) +{ + uint16 status; + uint8 header_type; + uint8 cap_ptr; + int i; + + if (!offset) { + dprintf("find_pci_capability: ERROR %02x:%02x:%02x cap %02x offset NULL pointer\n", bus, device, function, cap_id); + return B_BAD_VALUE; + } + + status = pci_read_config(bus, device, function, PCI_status, 2); + if (!(status & PCI_status_capabilities)) { + dprintf("find_pci_capability: ERROR %02x:%02x:%02x cap %02x not supported\n", bus, device, function, cap_id); + return B_ERROR; + } + + header_type = pci_read_config(bus, device, function, PCI_header_type, 1); + switch (header_type & PCI_header_type_mask) { + case PCI_header_type_generic: + case PCI_header_type_PCI_to_PCI_bridge: + cap_ptr = pci_read_config(bus, device, function, PCI_capabilities_ptr, 1); + break; + case PCI_header_type_cardbus: + cap_ptr = pci_read_config(bus, device, function, PCI_capabilities_ptr_2, 1); + break; + default: + dprintf("find_pci_capability: ERROR %02x:%02x:%02x cap %02x unknown header type\n", bus, device, function, cap_id); + return B_ERROR; + } + + cap_ptr &= ~3; + if (!cap_ptr) { + dprintf("find_pci_capability: ERROR %02x:%02x:%02x cap %02x empty list\n", bus, device, function, cap_id); + return B_NAME_NOT_FOUND; + } + + for (i = 0; i < 48; i++) { + uint8 this_cap_id = pci_read_config(bus, device, function, cap_ptr, 1); + if (this_cap_id == cap_id) { + *offset = cap_ptr; + return B_OK; + } + + cap_ptr = pci_read_config(bus, device, function, cap_ptr + 1, 1); + cap_ptr &= ~3; + + if (!cap_ptr) + return B_NAME_NOT_FOUND; + } + + dprintf("find_pci_capability: ERROR %02x:%02x:%02x cap %02x circular list\n", bus, device, function, cap_id); + return B_ERROR; +} + + // #pragma mark bus manager init/uninit status_t diff --git a/src/add-ons/kernel/bus_managers/pci/pci_module.c b/src/add-ons/kernel/bus_managers/pci/pci_module.c index 94bff4cf05..b978decde5 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci_module.c +++ b/src/add-ons/kernel/bus_managers/pci/pci_module.c @@ -221,7 +221,8 @@ static struct pci_module_info sOldPCIModule = { &pci_get_nth_pci_info, &pci_read_config, &pci_write_config, - &pci_ram_address + &pci_ram_address, + &pci_find_capability }; static struct pci_root_info sPCIModule = { diff --git a/src/add-ons/kernel/bus_managers/pci/pci_priv.h b/src/add-ons/kernel/bus_managers/pci/pci_priv.h index 1eed43c168..97b4149725 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci_priv.h +++ b/src/add-ons/kernel/bus_managers/pci/pci_priv.h @@ -41,7 +41,9 @@ extern pci_device_module_info gPCIDeviceModule; extern "C" { #endif -void *pci_ram_address(const void *physical_address_in_system_memory); +void * pci_ram_address(const void *physical_address_in_system_memory); + +status_t pci_find_capability(uchar bus, uchar device, uchar function, uchar cap_id, uchar *offset); status_t pci_io_init(void); uint8 pci_read_io_8(int mapped_io_addr);