diff --git a/headers/os/drivers/PCI.h b/headers/os/drivers/PCI.h index 152dc45014..2490cd7a43 100644 --- a/headers/os/drivers/PCI.h +++ b/headers/os/drivers/PCI.h @@ -155,6 +155,18 @@ struct pci_module_info { uchar cap_id, uchar *offset ); + status_t (*reserve_device) ( + uchar bus, + uchar device, + uchar function, + const char *driver_name, + void *cookie); + status_t (*unreserve_device) ( + uchar bus, + uchar device, + uchar function, + const char *driver_name, + void *cookie); }; #define B_PCI_MODULE_NAME "bus_managers/pci/v1" diff --git a/src/add-ons/kernel/bus_managers/pci/pci.cpp b/src/add-ons/kernel/bus_managers/pci/pci.cpp index baf77967a5..75b1b84f3a 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci.cpp +++ b/src/add-ons/kernel/bus_managers/pci/pci.cpp @@ -86,6 +86,196 @@ pci_find_capability(uchar virtualBus, uchar device, uchar function, } +status_t +pci_reserve_device(uchar virtualBus, uchar device, uchar function, + const char *driverName, void *nodeCookie) +{ + status_t status; + uint8 bus; + int domain; + + /* + * we add 2 nodes to the PCI devices, one with constant attributes, + * so adding for another driver fails, and a subnode with the + * driver-provided informations. + */ + + if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK) + return B_ERROR; + + //TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus, + // domain, bus, device, function, driverName, nodeCookie)); + + device_attr matchPCIRoot[] = { + {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "PCI"}}, + {NULL} + }; + device_attr matchThis[] = { + // info about device + {B_DEVICE_BUS, B_STRING_TYPE, {string: "pci"}}, + + // location on PCI bus + {B_PCI_DEVICE_DOMAIN, B_UINT32_TYPE, {ui32: domain}}, + {B_PCI_DEVICE_BUS, B_UINT8_TYPE, {ui8: bus}}, + {B_PCI_DEVICE_DEVICE, B_UINT8_TYPE, {ui8: device}}, + {B_PCI_DEVICE_FUNCTION, B_UINT8_TYPE, {ui8: function}}, + {NULL} + }; + device_attr legacyAttrs[] = { + // info about device + {B_DEVICE_BUS, B_STRING_TYPE, {string: "legacy_driver"}}, + {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Legacy Driver Reservation"}}, + {NULL} + }; + device_attr drvAttrs[] = { + // info about device + {B_DEVICE_BUS, B_STRING_TYPE, {string: "legacy_driver"}}, + {"legacy_driver", B_STRING_TYPE, {string: driverName}}, + {"legacy_driver_cookie", B_UINT64_TYPE, {ui64: (uint64)nodeCookie}}, + {NULL} + }; + device_node *root, *pci, *node, *legacy; + + status = B_DEVICE_NOT_FOUND; + root = gDeviceManager->get_root_node(); + if (!root) + return status; + + pci = NULL; + if (gDeviceManager->get_next_child_node(root, matchPCIRoot, &pci) < B_OK) + goto err0; + + node = NULL; + if (gDeviceManager->get_next_child_node(pci, matchThis, &node) < B_OK) + goto err1; + + // common API for all legacy modules ? + //status = legacy_driver_register(node, driverName, nodeCookie, PCI_LEGACY_DRIVER_MODULE_NAME); + + status = gDeviceManager->register_node(node, PCI_LEGACY_DRIVER_MODULE_NAME, + legacyAttrs, NULL, &legacy); + if (status < B_OK) + goto err2; + + status = gDeviceManager->register_node(legacy, PCI_LEGACY_DRIVER_MODULE_NAME, + drvAttrs, NULL, NULL); + if (status < B_OK) + goto err3; + + gDeviceManager->put_node(node); + gDeviceManager->put_node(pci); + gDeviceManager->put_node(root); + + return B_OK; + +err3: + gDeviceManager->unregister_node(legacy); +err2: + gDeviceManager->put_node(node); +err1: + gDeviceManager->put_node(pci); +err0: + gDeviceManager->put_node(root); + TRACE(("pci_reserve_device for driver %s failed: %s\n", driverName, strerror(status))); + return status; +} + + +status_t +pci_unreserve_device(uchar virtualBus, uchar device, uchar function, + const char *driverName, void *nodeCookie) +{ + status_t status; + uint8 bus; + int domain; + + if (gPCI->ResolveVirtualBus(virtualBus, &domain, &bus) != B_OK) + return B_ERROR; + + //TRACE(("%s(%d [%d:%d], %d, %d, %s, %p)\n", __FUNCTION__, virtualBus, + // domain, bus, device, function, driverName, nodeCookie)); + + device_attr matchPCIRoot[] = { + {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "PCI"}}, + {NULL} + }; + device_attr matchThis[] = { + // info about device + {B_DEVICE_BUS, B_STRING_TYPE, {string: "pci"}}, + + // location on PCI bus + {B_PCI_DEVICE_DOMAIN, B_UINT32_TYPE, {ui32: domain}}, + {B_PCI_DEVICE_BUS, B_UINT8_TYPE, {ui8: bus}}, + {B_PCI_DEVICE_DEVICE, B_UINT8_TYPE, {ui8: device}}, + {B_PCI_DEVICE_FUNCTION, B_UINT8_TYPE, {ui8: function}}, + {NULL} + }; + device_attr legacyAttrs[] = { + // info about device + {B_DEVICE_BUS, B_STRING_TYPE, {string: "legacy_driver"}}, + {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Legacy Driver Reservation"}}, + {NULL} + }; + device_attr drvAttrs[] = { + // info about device + {B_DEVICE_BUS, B_STRING_TYPE, {string: "legacy_driver"}}, + {"legacy_driver", B_STRING_TYPE, {string: driverName}}, + {"legacy_driver_cookie", B_UINT64_TYPE, {ui64: (uint64)nodeCookie}}, + {NULL} + }; + device_node *root, *pci, *node, *legacy, *drv; + + status = B_DEVICE_NOT_FOUND; + root = gDeviceManager->get_root_node(); + if (!root) + return status; + + pci = NULL; + if (gDeviceManager->get_next_child_node(root, matchPCIRoot, &pci) < B_OK) + goto err0; + + node = NULL; + if (gDeviceManager->get_next_child_node(pci, matchThis, &node) < B_OK) + goto err1; + + // common API for all legacy modules ? + //status = legacy_driver_unregister(node, driverName, nodeCookie); + + legacy = NULL; + if (gDeviceManager->get_next_child_node(node, legacyAttrs, &legacy) < B_OK) + goto err2; + + drv = NULL; + if (gDeviceManager->get_next_child_node(legacy, drvAttrs, &drv) < B_OK) + goto err3; + + gDeviceManager->put_node(drv); + status = gDeviceManager->unregister_node(drv); + //dprintf("unreg:drv:%s\n", strerror(status)); + + gDeviceManager->put_node(legacy); + status = gDeviceManager->unregister_node(legacy); + //dprintf("unreg:legacy:%s\n", strerror(status)); + // we'll get EBUSY here anyway... + + gDeviceManager->put_node(node); + gDeviceManager->put_node(pci); + gDeviceManager->put_node(root); + return B_OK; + +err3: + gDeviceManager->put_node(legacy); +err2: + gDeviceManager->put_node(node); +err1: + gDeviceManager->put_node(pci); +err0: + gDeviceManager->put_node(root); + TRACE(("pci_unreserve_device for driver %s failed: %s\n", driverName, strerror(status))); + return status; +} + + // used by pci_info.cpp print_info_basic() void __pci_resolve_virtual_bus(uint8 virtualBus, int *domain, uint8 *bus) 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 8ce36d3806..5e7e620a30 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci_module.c +++ b/src/add-ons/kernel/bus_managers/pci/pci_module.c @@ -64,7 +64,9 @@ static struct pci_module_info sOldPCIModule = { &pci_read_config, &pci_write_config, &pci_ram_address, - &pci_find_capability + &pci_find_capability, + &pci_reserve_device, + &pci_unreserve_device }; module_dependency module_dependencies[] = { @@ -72,9 +74,19 @@ module_dependency module_dependencies[] = { {} }; +driver_module_info gPCILegacyDriverModule = { + { + PCI_LEGACY_DRIVER_MODULE_NAME, + 0, + NULL, + }, + NULL +}; + module_info *modules[] = { (module_info *)&sOldPCIModule, (module_info *)&gPCIRootModule, (module_info *)&gPCIDeviceModule, + (module_info *)&gPCILegacyDriverModule, NULL }; diff --git a/src/add-ons/kernel/bus_managers/pci/pci_private.h b/src/add-ons/kernel/bus_managers/pci/pci_private.h index 8633e28ea3..5fe87098c8 100644 --- a/src/add-ons/kernel/bus_managers/pci/pci_private.h +++ b/src/add-ons/kernel/bus_managers/pci/pci_private.h @@ -12,6 +12,8 @@ #include #include +// name of PCI legacy driver endpoint module +#define PCI_LEGACY_DRIVER_MODULE_NAME "bus_managers/pci/legacy_v1" // name of PCI device modules #define PCI_DEVICE_MODULE_NAME "bus_managers/pci/driver_v1" @@ -46,6 +48,11 @@ 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_reserve_device(uchar virtualBus, uchar device, uchar function, + const char *driverName, void *nodeCookie); +status_t pci_unreserve_device(uchar virtualBus, uchar device, uchar function, + const char *driverName, void *nodeCookie); + status_t pci_io_init(void); uint8 pci_read_io_8(int mapped_io_addr); void pci_write_io_8(int mapped_io_addr, uint8 value); diff --git a/src/add-ons/kernel/drivers/audio/ac97/es1370/es1370.c b/src/add-ons/kernel/drivers/audio/ac97/es1370/es1370.c index 308cc7453b..ec237ee738 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/es1370/es1370.c +++ b/src/add-ons/kernel/drivers/audio/ac97/es1370/es1370.c @@ -501,6 +501,7 @@ init_driver(void) pci_info info; int ix = 0; num_cards = 0; + status_t err; PRINT(("init_driver()\n")); @@ -529,7 +530,7 @@ init_driver(void) if (get_module(pci_name, (module_info **) &pci)) return ENOSYS; - while ((*pci->get_nth_pci_info)(ix, &info) == B_OK) { + while ((*pci->get_nth_pci_info)(ix++, &info) == B_OK) { if (info.vendor_id == 0x1274 && (info.device_id == 0x5000 /*|| info.device_id == 0x1371 @@ -541,6 +542,14 @@ init_driver(void) } memset(&cards[num_cards], 0, sizeof(es1370_dev)); cards[num_cards].info = info; +#ifdef __HAIKU__ + if ((err = (*pci->reserve_device)(info.bus, info.device, info.function, + DRIVER_NAME, &cards[num_cards])) < B_OK) { + dprintf("es1370: failed to reserve_device(%d, %d, %d,): %s\n", + info.bus, info.device, info.function, strerror(err)); + continue; + } +#endif if (es1370_setup(&cards[num_cards])) { PRINT(("Setup of es1370 %ld failed\n", num_cards+1)); } @@ -548,7 +557,6 @@ init_driver(void) num_cards++; } } - ix++; } if (!num_cards) { PRINT(("no cards\n")); @@ -579,8 +587,14 @@ uninit_driver(void) num_cards = 0; PRINT(("uninit_driver()\n")); - for (ix=0; ixunreserve_device)(cards[ix].info.bus, + cards[ix].info.device, cards[ix].info.function, + DRIVER_NAME, &cards[ix]); +#endif + } memset(&cards, 0, sizeof(cards)); put_module(pci_name); } diff --git a/src/add-ons/kernel/drivers/audio/hda/driver.cpp b/src/add-ons/kernel/drivers/audio/hda/driver.cpp index 02cabb158b..e0d05f8e52 100644 --- a/src/add-ons/kernel/drivers/audio/hda/driver.cpp +++ b/src/add-ons/kernel/drivers/audio/hda/driver.cpp @@ -55,6 +55,14 @@ init_driver(void) && gNumCards < MAX_CARDS; i++) { if (info.class_base == PCI_multimedia && info.class_sub == PCI_hd_audio) { +#ifdef __HAIKU__ + if ((*gPci->reserve_device)(info.bus, info.device, info.function, "hda", + &gCards[gNumCards]) < B_OK) { + dprintf("HDA: Failed to reserve PCI:%d:%d:%d\n", + info.bus, info.device, info.function); + continue; + } +#endif memset(&gCards[gNumCards], 0, sizeof(hda_controller)); gCards[gNumCards].pci_info = info; gCards[gNumCards].opened = 0; @@ -84,6 +92,10 @@ uninit_driver(void) dprintf("IRA: %s\n", __func__); for (uint32 i = 0; i < gNumCards; i++) { +#ifdef __HAIKU__ + (*gPci->unreserve_device)(gCards[i].pci_info.bus, gCards[i].pci_info.device, + gCards[i].pci_info.function, "hda", &gCards[i]); +#endif free((void*)gCards[i].devfs_path); gCards[i].devfs_path = NULL; }