From 7e26ad5af7cb5f8308f6fb9688b2e8b49ad290cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= Date: Tue, 1 Sep 2009 23:56:02 +0000 Subject: [PATCH] Add functions to the old-style PCI bus manager to reserve a device from an old-style driver for exclusive use. This should help making OSS and native audio drivers mutually exclusive. Used in es1370 and hda drivers as examples. OSS must still be fixed to use it too though. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32899 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/drivers/PCI.h | 12 ++ src/add-ons/kernel/bus_managers/pci/pci.cpp | 190 ++++++++++++++++++ .../kernel/bus_managers/pci/pci_module.c | 14 +- .../kernel/bus_managers/pci/pci_private.h | 7 + .../kernel/drivers/audio/ac97/es1370/es1370.c | 20 +- .../kernel/drivers/audio/hda/driver.cpp | 12 ++ 6 files changed, 251 insertions(+), 4 deletions(-) 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; }