diff --git a/src/tests/system/kernel/device_manager/playground/Jamfile b/src/tests/system/kernel/device_manager/playground/Jamfile index 63a34cc2b1..6dff182d45 100644 --- a/src/tests/system/kernel/device_manager/playground/Jamfile +++ b/src/tests/system/kernel/device_manager/playground/Jamfile @@ -8,10 +8,10 @@ UsePrivateHeaders shared ; SimpleTest device_manager : device_manager.cpp + KPath.cpp bus.cpp driver.cpp : be libkernelland_emu.so ; - diff --git a/src/tests/system/kernel/device_manager/playground/KPath.cpp b/src/tests/system/kernel/device_manager/playground/KPath.cpp new file mode 100644 index 0000000000..bf24b30671 --- /dev/null +++ b/src/tests/system/kernel/device_manager/playground/KPath.cpp @@ -0,0 +1,330 @@ +/* + * Copyright 2004-2006, Ingo Weinhold, bonefish@users.sf.net. + * Distributed under the terms of the MIT License. + */ + +/** A simple class wrapping a path. Has a fixed-sized buffer. */ + +#include + +#include +#include + +#include + + +// debugging +#define TRACE(x) ; +//#define TRACE(x) dprintf x + + +KPath::KPath(size_t bufferSize) + : + fBuffer(NULL), + fBufferSize(0), + fPathLength(0), + fLocked(false) +{ + SetTo(NULL, false, bufferSize); +} + + +KPath::KPath(const char* path, bool normalize, size_t bufferSize) + : + fBuffer(NULL), + fBufferSize(0), + fPathLength(0), + fLocked(false) +{ + SetTo(path, normalize, bufferSize); +} + + +KPath::KPath(const KPath& other) + : + fBuffer(NULL), + fBufferSize(0), + fPathLength(0), + fLocked(false) +{ + *this = other; +} + + +KPath::~KPath() +{ + free(fBuffer); +} + + +status_t +KPath::SetTo(const char* path, bool normalize, size_t bufferSize) +{ + if (bufferSize == 0) + bufferSize = B_PATH_NAME_LENGTH; + + // free the previous buffer, if the buffer size differs + if (fBuffer && fBufferSize != bufferSize) { + free(fBuffer); + fBuffer = NULL; + fBufferSize = 0; + } + fPathLength = 0; + fLocked = false; + + // allocate buffer + if (!fBuffer) + fBuffer = (char*)malloc(bufferSize); + if (!fBuffer) + return B_NO_MEMORY; + if (fBuffer) { + fBufferSize = bufferSize; + fBuffer[0] = '\0'; + } + return SetPath(path, normalize); +} + + +void +KPath::Adopt(KPath& other) +{ + free(fBuffer); + + fBuffer = other.fBuffer; + fBufferSize = other.fBufferSize; + + other.fBuffer = NULL; +} + + +status_t +KPath::InitCheck() const +{ + return fBuffer ? B_OK : B_NO_MEMORY; +} + + +status_t +KPath::SetPath(const char *path, bool normalize) +{ + if (!fBuffer) + return B_NO_INIT; + + if (path) { + if (normalize) { + // normalize path + BPath normalizedPath; + status_t error = normalizedPath.SetTo(path, NULL, true); + if (error != B_OK) { + SetPath(NULL); + return error; + } + + strlcpy(fBuffer, normalizedPath.Path(), fBufferSize); + fPathLength = strlen(fBuffer); + } else { + // don't normalize path + size_t length = strlen(path); + if (length >= fBufferSize) + return B_BUFFER_OVERFLOW; + + memcpy(fBuffer, path, length + 1); + fPathLength = length; + _ChopTrailingSlashes(); + } + } else { + fBuffer[0] = '\0'; + fPathLength = 0; + } + return B_OK; +} + + +const char* +KPath::Path() const +{ + return fBuffer; +} + + +char * +KPath::LockBuffer() +{ + if (!fBuffer || fLocked) + return NULL; + + fLocked = true; + return fBuffer; +} + + +void +KPath::UnlockBuffer() +{ + if (!fLocked) { + TRACE(("KPath::UnlockBuffer(): ERROR: Buffer not locked!\n")); + return; + } + fLocked = false; + fPathLength = strnlen(fBuffer, fBufferSize); + if (fPathLength == fBufferSize) { + TRACE(("KPath::UnlockBuffer(): WARNING: Unterminated buffer!\n")); + fPathLength--; + fBuffer[fPathLength] = '\0'; + } + _ChopTrailingSlashes(); +} + + +const char * +KPath::Leaf() const +{ + if (!fBuffer) + return NULL; + + // only "/" has trailing slashes -- then we have to return the complete + // buffer, as we have to do in case there are no slashes at all + if (fPathLength != 1 || fBuffer[0] != '/') { + for (int32 i = fPathLength - 1; i >= 0; i--) { + if (fBuffer[i] == '/') + return fBuffer + i + 1; + } + } + return fBuffer; +} + + +status_t +KPath::ReplaceLeaf(const char *newLeaf) +{ + const char *leaf = Leaf(); + if (!leaf) + return B_NO_INIT; + + int32 leafIndex = leaf - fBuffer; + // chop off the current leaf (don't replace "/", though) + if (leafIndex != 0 || fBuffer[leafIndex - 1]) { + fBuffer[leafIndex] = '\0'; + fPathLength = leafIndex; + _ChopTrailingSlashes(); + } + + // if a leaf was given, append it + if (newLeaf) + return Append(newLeaf); + return B_OK; +} + + +bool +KPath::RemoveLeaf() +{ + // get the leaf -- bail out, if not initialized or only the "/" is left + const char *leaf = Leaf(); + if (!leaf || leaf == fBuffer) + return false; + + // chop off the leaf + int32 leafIndex = leaf - fBuffer; + fBuffer[leafIndex] = '\0'; + fPathLength = leafIndex; + _ChopTrailingSlashes(); + + return true; +} + + +status_t +KPath::Append(const char *component, bool isComponent) +{ + // check initialization and parameter + if (!fBuffer) + return B_NO_INIT; + if (!component) + return B_BAD_VALUE; + if (fPathLength == 0) + return SetPath(component); + + // get component length + size_t componentLength = strlen(component); + if (componentLength < 1) + return B_OK; + + // if our current path is empty, we just copy the supplied one + // compute the result path len + bool insertSlash = isComponent && fBuffer[fPathLength - 1] != '/' + && component[0] != '/'; + size_t resultPathLength = fPathLength + componentLength + (insertSlash ? 1 : 0); + if (resultPathLength >= fBufferSize) + return B_BUFFER_OVERFLOW; + + // compose the result path + if (insertSlash) + fBuffer[fPathLength++] = '/'; + memcpy(fBuffer + fPathLength, component, componentLength + 1); + fPathLength = resultPathLength; + return B_OK; +} + + +KPath& +KPath::operator=(const KPath& other) +{ + SetTo(other.fBuffer, other.fBufferSize); + return *this; +} + + +KPath& +KPath::operator=(const char* path) +{ + SetTo(path); + return *this; +} + + +bool +KPath::operator==(const KPath& other) const +{ + if (!fBuffer) + return !other.fBuffer; + + return (other.fBuffer + && fPathLength == other.fPathLength + && strcmp(fBuffer, other.fBuffer) == 0); +} + + +bool +KPath::operator==(const char* path) const +{ + if (!fBuffer) + return (!path); + + return path && !strcmp(fBuffer, path); +} + + +bool +KPath::operator!=(const KPath& other) const +{ + return !(*this == other); +} + + +bool +KPath::operator!=(const char* path) const +{ + return !(*this == path); +} + + +void +KPath::_ChopTrailingSlashes() +{ + if (fBuffer) { + while (fPathLength > 1 && fBuffer[fPathLength - 1] == '/') + fBuffer[--fPathLength] = '\0'; + } +} + 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 0c241a2520..1c9aa4ba5e 100644 --- a/src/tests/system/kernel/device_manager/playground/device_manager.cpp +++ b/src/tests/system/kernel/device_manager/playground/device_manager.cpp @@ -6,19 +6,21 @@ #include "device_manager.h" -#include -#include - -#include -#include -#include - #include #include #include #include #include +#include +#include +#include + +#include +#include +#include +#include + #define TRACE(a) dprintf a @@ -107,6 +109,13 @@ struct device_node : DoublyLinkedListLinkImpl { private: status_t _RegisterFixed(uint32& registered); + status_t _GetNextDriverPath(void*& cookie, KPath& _path); + status_t _GetNextDriver(void* list, + driver_module_info*& driver); + status_t _FindBestDriver(const char* path, + driver_module_info*& bestDriver, + float& bestSupport); + status_t _RegisterPath(const char* path); status_t _RegisterDynamic(); bool _IsBus() const; @@ -123,12 +132,14 @@ private: AttributeList fAttributes; }; - device_manager_info *gDeviceManager; static device_node *sRootNode; +// #pragma mark - device_attr + + device_attr_private::device_attr_private() { name = NULL; @@ -355,7 +366,7 @@ dm_dump_node(device_node* node, int32 level) } -// #pragma mark - +// #pragma mark - device_node /*! Allocate device node info structure; @@ -550,6 +561,150 @@ device_node::_RegisterFixed(uint32& registered) } +status_t +device_node::_GetNextDriverPath(void*& cookie, KPath& _path) +{ + Stack* stack = NULL; + + if (cookie == NULL) { + // find all paths and add them + stack = new(std::nothrow) Stack(); + if (stack == NULL) + return B_NO_MEMORY; + + StackDeleter stackDeleter(stack); + + if (!_IsBus()) { + // add driver paths + KPath* path = new(std::nothrow) KPath; + if (path == NULL) + return B_NO_MEMORY; + + status_t status = path->SetTo("drivers"); + if (status != B_OK) { + delete path; + return status; + } + + // TODO: this might be more than one path! + const char *type; + if (dm_get_attr_string(this, B_DRIVER_DEVICE_TYPE, &type, false) + == B_OK) + path->Append(type); + + stack->Push(path); + } + + // add bus paths + KPath* path = new(std::nothrow) KPath; + if (path == NULL) + return B_NO_MEMORY; + + status_t status = path->SetTo("bus"); + if (status != B_OK) { + delete path; + return status; + } + + stack->Push(path); + stackDeleter.Detach(); + + cookie = (void*)stack; + } else + stack = static_cast*>(cookie); + + KPath* path; + if (stack->Pop(&path)) { + _path.Adopt(*path); + delete path; + return B_OK; + } + + delete stack; + return B_ENTRY_NOT_FOUND; +} + + +status_t +device_node::_GetNextDriver(void* list, driver_module_info*& driver) +{ + while (true) { + char name[B_FILE_NAME_LENGTH]; + size_t nameLength = sizeof(name); + + status_t status = read_next_module_name(list, name, &nameLength); + if (status != B_OK) + return status; + + if (!strcmp(fModuleName, name)) + continue; + + if (get_module(name, (module_info**)&driver) != B_OK) + continue; + + if (driver->supports_device == NULL + || driver->register_device == NULL) { + put_module(name); + continue; + } + + return B_OK; + } +} + + +status_t +device_node::_FindBestDriver(const char* path, driver_module_info*& bestDriver, + float& bestSupport) +{ + if (bestDriver == NULL) + bestSupport = 0.0f; + + void* list = open_module_list_etc(path, "driver_v1"); + driver_module_info* driver; + while (_GetNextDriver(list, driver) == B_OK) { + float support = driver->supports_device(this); + if (support > bestSupport) { + if (bestDriver != NULL) + put_module(bestDriver->info.name); + + bestDriver = driver; + bestSupport = support; + continue; + // keep reference to best module around + } + + put_module(driver->info.name); + } + close_module_list(list); + + return bestDriver != NULL ? B_OK : B_ENTRY_NOT_FOUND; +} + + +status_t +device_node::_RegisterPath(const char* path) +{ + void* list = open_module_list_etc(path, "driver_v1"); + driver_module_info* driver; + uint32 count = 0; + + 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); + if (driver->register_device(this) == B_OK) + count++; + } + + put_module(driver->info.name); + } + close_module_list(list); + + return count > 0 ? B_OK : B_ENTRY_NOT_FOUND; +} + + status_t device_node::_RegisterDynamic() { @@ -558,70 +713,31 @@ device_node::_RegisterDynamic() != B_OK) findFlags = 0; - driver_module_info* bestDriver = NULL; - float best = 0.0; + KPath path; - char path[64]; - if (!_IsBus()) { - strlcpy(path, "drivers", sizeof(path)); + if ((findFlags & B_FIND_MULTIPLE_CHILDREN) == 0) { + // find the one driver + driver_module_info* bestDriver = NULL; + float bestSupport = 0.0; + void* cookie = NULL; - const char *type; - if (dm_get_attr_string(this, B_DRIVER_DEVICE_TYPE, &type, false) - == B_OK) { - strlcat(path, "/", sizeof(path)); - strlcat(path, type, sizeof(path)); + while (_GetNextDriverPath(cookie, path) == B_OK) { + _FindBestDriver(path.Path(), bestDriver, bestSupport); + } + + if (bestDriver != NULL) { +printf(" register best module \"%s\", support %f\n", bestDriver->info.name, bestSupport); + bestDriver->register_device(this); + put_module(bestDriver->info.name); } } else { - // TODO: we might want to allow bus* specifiers as well, ie. - // busses/usb - strlcpy(path, "bus", sizeof(path)); - } - - void* list = open_module_list_etc(path, "driver_v1"); - while (true) { - char name[B_FILE_NAME_LENGTH]; - size_t nameLength = sizeof(name); - - if (read_next_module_name(list, name, &nameLength) != B_OK) - break; - - if (!strcmp(fModuleName, name)) - continue; - - driver_module_info* driver; - if (get_module(name, (module_info**)&driver) != B_OK) - continue; - - if (driver->supports_device != NULL - && driver->register_device != NULL) { - float support = driver->supports_device(this); - - if ((findFlags & B_FIND_MULTIPLE_CHILDREN) == 0) { - if (support > best) { - if (bestDriver != NULL) - put_module(bestDriver->info.name); - - bestDriver = driver; - best = support; - continue; - // keep reference to best module around - } - } else if (support > 0.0) { -printf(" register module \"%s\", support %f\n", name, support); - driver->register_device(this); - } + // register all drivers that match + void* cookie = NULL; + while (_GetNextDriverPath(cookie, path) == B_OK) { + _RegisterPath(path.Path()); } - - put_module(name); } - close_module_list(list); - if (bestDriver != NULL) { -printf(" register best module \"%s\", support %f\n", bestDriver->info.name, best); - bestDriver->register_device(this); - put_module(bestDriver->info.name); - } - return B_OK; }