diff --git a/src/tests/system/kernel/device_manager/playground/Jamfile b/src/tests/system/kernel/device_manager/playground/Jamfile index 6dff182d45..6842e7c13e 100644 --- a/src/tests/system/kernel/device_manager/playground/Jamfile +++ b/src/tests/system/kernel/device_manager/playground/Jamfile @@ -12,6 +12,8 @@ SimpleTest device_manager : bus.cpp driver.cpp + generic_video_driver.cpp + specific_video_driver.cpp : be libkernelland_emu.so ; diff --git a/src/tests/system/kernel/device_manager/playground/bus.cpp b/src/tests/system/kernel/device_manager/playground/bus.cpp index 5ae28c91fe..552c4ce211 100644 --- a/src/tests/system/kernel/device_manager/playground/bus.cpp +++ b/src/tests/system/kernel/device_manager/playground/bus.cpp @@ -71,6 +71,7 @@ register_child_devices(device_node *node) } kDevices[] = { {0x1000, 0x0001, PCI_mass_storage, PCI_sata, PCI_sata_ahci}, {0x1001, 0x0001, PCI_network, PCI_ethernet, 0}, + {0x1001, 0x0002, PCI_display, 0, 0}, {0x1002, 0x0001, PCI_multimedia, PCI_audio, 0}, {0x1002, 0x0002, PCI_serial_bus, PCI_usb, PCI_usb_ehci}, }; diff --git a/src/tests/system/kernel/device_manager/playground/device_manager.cpp b/src/tests/system/kernel/device_manager/playground/device_manager.cpp index 8e712668ec..3dae9a56e9 100644 --- a/src/tests/system/kernel/device_manager/playground/device_manager.cpp +++ b/src/tests/system/kernel/device_manager/playground/device_manager.cpp @@ -29,6 +29,10 @@ extern struct device_module_info gDeviceModuleInfo; extern struct driver_module_info gDriverModuleInfo; +extern struct device_module_info gGenericVideoDeviceModuleInfo; +extern struct driver_module_info gGenericVideoDriverModuleInfo; +extern struct device_module_info gSpecificVideoDeviceModuleInfo; +extern struct driver_module_info gSpecificVideoDriverModuleInfo; extern struct driver_module_info gBusModuleInfo; extern struct driver_module_info gBusDriverModuleInfo; @@ -113,6 +117,14 @@ struct device_node : DoublyLinkedListLinkImpl { bool IsRegistered() const { return fRegistered; } bool IsInitialized() const { return fInitialized > 0; } + void Acquire(); + bool Release(); + + int CompareTo(const device_attr* attributes) const; + device_node* FindChild(const device_attr* attributes) const; + + void Dump(int32 level = 0); + private: status_t _RegisterFixed(uint32& registered); bool _AlwaysRegisterDynamic(); @@ -361,27 +373,6 @@ dump_attribute(device_attr* attr, int32 level) } -void -dm_dump_node(device_node* node, int32 level) -{ - if (node == NULL) - return; - - put_level(level); - dprintf("(%ld) @%p \"%s\"\n", level, node, node->ModuleName()); - - AttributeList::Iterator attribute = node->Attributes().GetIterator(); - while (attribute.HasNext()) { - dump_attribute(attribute.Next(), level); - } - - NodeList::ConstIterator iterator = node->Children().GetIterator(); - while (iterator.HasNext()) { - dm_dump_node(iterator.Next(), level + 1); - } -} - - static void uninit_unused() { @@ -434,6 +425,8 @@ device_node::device_node(const char* moduleName, const device_attr* attrs, device_node::~device_node() { + TRACE(("delete node %p\n", this)); + // Delete children NodeList::Iterator nodeIterator = fChildren.GetIterator(); while (nodeIterator.HasNext()) { @@ -464,10 +457,20 @@ device_node::InitCheck() status_t device_node::InitDriver() { - if (fInitialized++ > 0) + if (fInitialized++ > 0) { + if (Parent() != NULL) { + Parent()->InitDriver(); + // acquire another reference to our parent as well + } + Acquire(); return B_OK; + } status_t status = get_module(ModuleName(), (module_info**)&fDriver); + if (status == B_OK && Parent() != NULL) { + // our parent always have to be initialized + status = Parent()->InitDriver(); + } if (status < B_OK) { fInitialized--; return status; @@ -475,12 +478,17 @@ device_node::InitDriver() if (fDriver->init_driver != NULL) status = fDriver->init_driver(this, &fDriverData); + if (status < B_OK) { fInitialized--; + put_module(ModuleName()); + fDriver = NULL; + fDriverData = NULL; return status; } + Acquire(); return B_OK; } @@ -488,8 +496,11 @@ device_node::InitDriver() bool device_node::UninitDriver() { - if (fInitialized-- > 1) + if (fInitialized-- > 1) { + Release(); return false; + } + TRACE(("uninit driver for node %p\n", this)); if (fDriver->uninit_driver != NULL) fDriver->uninit_driver(this); @@ -499,8 +510,12 @@ device_node::UninitDriver() put_module(ModuleName()); + Release(); + if (Parent() != NULL) + Parent()->UninitDriver(); + if ((fFlags & NODE_FLAG_REMOVE_ON_UNINIT) != 0) - delete this; + Release(); return true; } @@ -510,7 +525,7 @@ void device_node::AddChild(device_node* node) { // we must not be destroyed as long as we have children - fRefCount++; + Acquire(); node->fParent = this; fChildren.Add(node); } @@ -519,10 +534,9 @@ device_node::AddChild(device_node* node) void device_node::RemoveChild(device_node* node) { - fRefCount--; - // TODO: we may need to destruct ourselves here! node->fParent = NULL; fChildren.Remove(node); + Release(); } @@ -784,7 +798,8 @@ device_node::_RegisterPath(const char* path) while (_GetNextDriver(list, driver) == B_OK) { float support = driver->supports_device(this); if (support > 0.0) { -printf(" register module \"%s\", support %f\n", driver->info.name, support); + TRACE((" register module \"%s\", support %f\n", driver->info.name, + support)); if (driver->register_device(this) == B_OK) count++; } @@ -835,7 +850,8 @@ device_node::_RegisterDynamic() } if (bestDriver != NULL) { -printf(" register best module \"%s\", support %f\n", bestDriver->info.name, bestSupport); + TRACE((" register best module \"%s\", support %f\n", + bestDriver->info.name, bestSupport)); bestDriver->register_device(this); put_module(bestDriver->info.name); } @@ -861,9 +877,10 @@ device_node::_RemoveChildren() if (!child->IsInitialized()) { // this child is not used currently, and can be removed safely iterator.Remove(); - fRefCount--; child->fParent = NULL; delete child; + if (Release()) + panic("died early"); } else child->fFlags |= NODE_FLAG_REMOVE_ON_UNINIT; } @@ -875,6 +892,12 @@ device_node::_RemoveChildren() status_t device_node::Probe(const char* devicePath) { + status_t status = InitDriver(); + if (status < B_OK) + return status; + + MethodDeleter uninit(this, &device_node::UninitDriver); + uint16 type = 0; uint16 subType = 0; if (dm_get_attr_uint16(this, B_DEVICE_TYPE, &type, false) == B_OK @@ -917,7 +940,7 @@ device_node::Probe(const char* devicePath) while (iterator.HasNext()) { device_node* child = iterator.Next(); - status_t status = child->Probe(devicePath); + status = child->Probe(devicePath); if (status != B_OK) return status; } @@ -965,6 +988,91 @@ device_node::UninitUnusedChildren() } +void +device_node::Acquire() +{ + atomic_add(&fRefCount, 1); +} + + +bool +device_node::Release() +{ + if (atomic_add(&fRefCount, -1) > 1) + return false; + + if (Parent() != NULL) + Parent()->RemoveChild(this); + delete this; + return true; +} + + +int +device_node::CompareTo(const device_attr* attributes) const +{ + if (attributes == NULL) + return -1; + + for (; attributes->name != NULL; attributes++) { + // find corresponding attribute + AttributeList::ConstIterator iterator = Attributes().GetIterator(); + device_attr_private* attr = NULL; + while (iterator.HasNext()) { + attr = iterator.Next(); + + if (!strcmp(attr->name, attributes->name)) + break; + } + if (!iterator.HasNext()) + return -1; + + int compare = device_attr_private::Compare(attr, attributes); + if (compare != 0) + return compare; + } + + return 0; +} + + +device_node* +device_node::FindChild(const device_attr* attributes) const +{ + if (attributes == NULL) + return NULL; + + NodeList::ConstIterator iterator = Children().GetIterator(); + while (iterator.HasNext()) { + device_node* child = iterator.Next(); + + if (!child->CompareTo(attributes)) + return child; + } + + return NULL; +} + + +void +device_node::Dump(int32 level = 0) +{ + put_level(level); + dprintf("(%ld) @%p \"%s\" (ref %ld, init %ld)\n", level, this, ModuleName(), + fRefCount, fInitialized); + + AttributeList::Iterator attribute = Attributes().GetIterator(); + while (attribute.HasNext()) { + dump_attribute(attribute.Next(), level); + } + + NodeList::ConstIterator iterator = Children().GetIterator(); + while (iterator.HasNext()) { + iterator.Next()->Dump(level + 1); + } +} + + // #pragma mark - Device Manager module API @@ -983,6 +1091,11 @@ register_device(device_node* parent, const char* moduleName, if ((parent == NULL && sRootNode != NULL) || moduleName == NULL) return B_BAD_VALUE; + if (parent != NULL && parent->FindChild(attrs) != NULL) { + // A node like this one already exists for this parent + return B_NAME_IN_USE; + } + // TODO: handle I/O resources! device_node *newNode = new(std::nothrow) device_node(moduleName, attrs, @@ -999,16 +1112,16 @@ register_device(device_node* parent, const char* moduleName, if (status != B_OK) goto err1; - status = newNode->InitDriver(); - if (status != B_OK) - goto err1; - // make it public if (parent != NULL) parent->AddChild(newNode); else sRootNode = newNode; + status = newNode->InitDriver(); + if (status != B_OK) + goto err1; + #if 0 // The following is done to reduce the stack usage of deeply nested // child device nodes. @@ -1063,8 +1176,11 @@ get_driver(device_node* node, driver_module_info** _module, void** _data) static device_node* -device_root(void) +get_device_root(void) { + if (sRootNode != NULL) + sRootNode->Acquire(); + return sRootNode; } @@ -1080,13 +1196,23 @@ get_next_child_device(device_node* parent, device_node* _node, static device_node* get_parent(device_node* node) { - return NULL; + if (node == NULL) + return NULL; + + RecursiveLocker _(sLock); + + device_node* parent = node->Parent(); + parent->Acquire(); + + return parent; } static void put_device_node(device_node* node) { + RecursiveLocker _(sLock); + node->Release(); } @@ -1229,7 +1355,7 @@ static struct device_manager_info sDeviceManagerModule = { register_device, unregister_device, get_driver, - device_root, + get_device_root, get_next_child_device, get_parent, put_device_node, @@ -1284,11 +1410,19 @@ main(int argc, char** argv) { _add_builtin_module((module_info*)&sDeviceManagerModule); _add_builtin_module((module_info*)&sDeviceRootModule); - _add_builtin_module((module_info*)&gDeviceModuleInfo); - _add_builtin_module((module_info*)&gDriverModuleInfo); + + // bus _add_builtin_module((module_info*)&gBusModuleInfo); _add_builtin_module((module_info*)&gBusDriverModuleInfo); + // sample driver + _add_builtin_module((module_info*)&gDriverModuleInfo); + _add_builtin_module((module_info*)&gDeviceModuleInfo); + + // generic video driver + _add_builtin_module((module_info*)&gGenericVideoDriverModuleInfo); + _add_builtin_module((module_info*)&gGenericVideoDeviceModuleInfo); + gDeviceManager = &sDeviceManagerModule; status_t status = _get_builtin_dependencies(); @@ -1301,9 +1435,21 @@ main(int argc, char** argv) recursive_lock_init(&sLock, "device manager"); dm_init_root_node(); - dm_dump_node(sRootNode, 0); + sRootNode->Dump(); probe_path("net"); + probe_path("graphics"); + // TODO: opened devices need to keep a "initialized" reference of the + // device_node + + sRootNode->Dump(); + uninit_unused(); + + // add specific video driver - ie. simulate installing it + _add_builtin_module((module_info*)&gSpecificVideoDriverModuleInfo); + _add_builtin_module((module_info*)&gSpecificVideoDeviceModuleInfo); + probe_path("graphics"); + uninit_unused(); recursive_lock_destroy(&sLock); diff --git a/src/tests/system/kernel/device_manager/playground/device_manager.h b/src/tests/system/kernel/device_manager/playground/device_manager.h index ee1e89b050..f1ee951f87 100644 --- a/src/tests/system/kernel/device_manager/playground/device_manager.h +++ b/src/tests/system/kernel/device_manager/playground/device_manager.h @@ -72,7 +72,7 @@ typedef struct device_manager_info { status_t (*get_driver)(device_node *node, driver_module_info **_module, void **_cookie); - device_node *(*root_device)(); + device_node *(*get_root_device)(); status_t (*get_next_child_device)(device_node *parent, device_node *node, const device_attr *attrs); device_node *(*get_parent)(device_node *node); diff --git a/src/tests/system/kernel/device_manager/playground/driver.cpp b/src/tests/system/kernel/device_manager/playground/driver.cpp index 455d6328b7..8ef3e72817 100644 --- a/src/tests/system/kernel/device_manager/playground/driver.cpp +++ b/src/tests/system/kernel/device_manager/playground/driver.cpp @@ -159,7 +159,7 @@ struct driver_module_info gDriverModuleInfo = { 0, NULL, }, - + supports_device, register_device, init_driver, diff --git a/src/tests/system/kernel/device_manager/playground/generic_video_driver.cpp b/src/tests/system/kernel/device_manager/playground/generic_video_driver.cpp new file mode 100644 index 0000000000..a404d1b6d5 --- /dev/null +++ b/src/tests/system/kernel/device_manager/playground/generic_video_driver.cpp @@ -0,0 +1,182 @@ +/* + * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "bus.h" + +#include +#include + + +#define DRIVER_MODULE_NAME "drivers/graphics/generic_driver/driver_v1" + + +// #pragma mark - driver + + +static float +supports_device(device_node *parent) +{ + bus_for_driver_module_info* module; + void* data; + gDeviceManager->get_driver(parent, (driver_module_info**)&module, &data); + + if (strcmp(module->info.info.name, BUS_FOR_DRIVER_NAME)) + return -1; + + uint16 type; + if (gDeviceManager->get_attr_uint16(parent, B_DEVICE_TYPE, &type, false) + != B_OK) + return -1; + + if (type == PCI_display) + return 0.1; + + return 0.0; +} + + +static status_t +register_device(device_node *parent) +{ + return gDeviceManager->register_device(parent, DRIVER_MODULE_NAME, NULL, + NULL, NULL); +} + + +static status_t +init_driver(device_node *node, void **_cookie) +{ + // also publishes any devices/nodes with dedicated calls + return B_OK; +} + + +static void +uninit_driver(device_node *node) +{ +} + + +static status_t +register_child_devices(device_node *node) +{ + return B_OK; +} + + +static void +device_removed(device_node *node) +{ +} + + +// #pragma mark - device + + +static status_t +init_device(void *deviceCookie) +{ + // called once before one or several open() calls + return B_ERROR; +} + + +static void +uninit_device(void *deviceCookie) +{ + // supposed to free deviceCookie, called when the last reference to + // the device is closed +} + + +static status_t +device_open(void *deviceCookie, int openMode, void **_cookie) +{ + // deviceCookie is an object attached to the published device + return B_ERROR; +} + + +static status_t +device_close(void *cookie) +{ + return B_ERROR; +} + + +static status_t +device_free(void *cookie) +{ + return B_ERROR; +} + + +static status_t +device_read(void *cookie, off_t pos, void *buffer, size_t *_length) +{ + return B_ERROR; +} + + +static status_t +device_write(void *cookie, off_t pos, const void *buffer, size_t *_length) +{ + return B_ERROR; +} + + +static status_t +device_ioctl(void *cookie, int32 op, void *buffer, size_t length) +{ + return B_ERROR; +} + + +static status_t +device_io(void *cookie, io_request *request) +{ + // new function to deal with I/O requests directly. + return B_ERROR; +} + + +// #pragma mark - + + +struct driver_module_info gGenericVideoDriverModuleInfo = { + { + DRIVER_MODULE_NAME, + 0, + NULL, + }, + + supports_device, + register_device, + init_driver, + uninit_driver, + register_child_devices, + NULL, + device_removed, +}; + +struct device_module_info gGenericVideoDeviceModuleInfo = { + { + "drivers/graphics/generic_driver/device_v1", + 0, + NULL, + }, + + init_device, + uninit_device, + + device_open, + device_close, + device_free, + device_read, + device_write, + device_ioctl, + device_io, +}; diff --git a/src/tests/system/kernel/device_manager/playground/specific_video_driver.cpp b/src/tests/system/kernel/device_manager/playground/specific_video_driver.cpp new file mode 100644 index 0000000000..c6d9255a62 --- /dev/null +++ b/src/tests/system/kernel/device_manager/playground/specific_video_driver.cpp @@ -0,0 +1,180 @@ +/* + * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved. + * Distributed under the terms of the MIT License. + */ + + +#include "bus.h" + +#include +#include + + +#define DRIVER_MODULE_NAME "drivers/graphics/specific_driver/driver_v1" + + +// #pragma mark - driver + + +static float +supports_device(device_node *parent) +{ + bus_for_driver_module_info* module; + void* data; + gDeviceManager->get_driver(parent, (driver_module_info**)&module, &data); + + if (strcmp(module->info.info.name, BUS_FOR_DRIVER_NAME)) + return -1; + + bus_info info; + if (module->get_bus_info(data, &info) == B_OK + && info.vendor_id == 0x1001 + && info.device_id == 0x0002) + return 0.8; + + return 0.0; +} + + +static status_t +register_device(device_node *parent) +{ + return gDeviceManager->register_device(parent, DRIVER_MODULE_NAME, NULL, + NULL, NULL); +} + + +static status_t +init_driver(device_node *node, void **_cookie) +{ + // also publishes any devices/nodes with dedicated calls + return B_OK; +} + + +static void +uninit_driver(device_node *node) +{ +} + + +static status_t +register_child_devices(device_node *node) +{ + return B_OK; +} + + +static void +device_removed(device_node *node) +{ +} + + +// #pragma mark - device + + +static status_t +init_device(void *deviceCookie) +{ + // called once before one or several open() calls + return B_ERROR; +} + + +static void +uninit_device(void *deviceCookie) +{ + // supposed to free deviceCookie, called when the last reference to + // the device is closed +} + + +static status_t +device_open(void *deviceCookie, int openMode, void **_cookie) +{ + // deviceCookie is an object attached to the published device + return B_ERROR; +} + + +static status_t +device_close(void *cookie) +{ + return B_ERROR; +} + + +static status_t +device_free(void *cookie) +{ + return B_ERROR; +} + + +static status_t +device_read(void *cookie, off_t pos, void *buffer, size_t *_length) +{ + return B_ERROR; +} + + +static status_t +device_write(void *cookie, off_t pos, const void *buffer, size_t *_length) +{ + return B_ERROR; +} + + +static status_t +device_ioctl(void *cookie, int32 op, void *buffer, size_t length) +{ + return B_ERROR; +} + + +static status_t +device_io(void *cookie, io_request *request) +{ + // new function to deal with I/O requests directly. + return B_ERROR; +} + + +// #pragma mark - + + +struct driver_module_info gSpecificVideoDriverModuleInfo = { + { + DRIVER_MODULE_NAME, + 0, + NULL, + }, + + supports_device, + register_device, + init_driver, + uninit_driver, + register_child_devices, + NULL, + device_removed, +}; + +struct device_module_info gSpecificVideoDeviceModuleInfo = { + { + "drivers/graphics/specific_driver/device_v1", + 0, + NULL, + }, + + init_device, + uninit_device, + + device_open, + device_close, + device_free, + device_read, + device_write, + device_ioctl, + device_io, +};