* Rewrote how the dynamic drivers are registered, and made it a bit more
flexible; now, a driver type can result in any number of paths to probe. * Also, the "bus" modules (busses/bus_managers) are now always probed - that's only a temporary solution and should be restricted to certain driver types later. * Added a userland buildable version of KPath. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25383 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
56bbbbc9ca
commit
b9c7ba4bba
@ -8,10 +8,10 @@ UsePrivateHeaders shared ;
|
||||
|
||||
SimpleTest device_manager :
|
||||
device_manager.cpp
|
||||
KPath.cpp
|
||||
|
||||
bus.cpp
|
||||
driver.cpp
|
||||
|
||||
: be libkernelland_emu.so
|
||||
;
|
||||
|
||||
|
330
src/tests/system/kernel/device_manager/playground/KPath.cpp
Normal file
330
src/tests/system/kernel/device_manager/playground/KPath.cpp
Normal file
@ -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 <fs/KPath.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <Path.h>
|
||||
|
||||
|
||||
// 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';
|
||||
}
|
||||
}
|
||||
|
@ -6,19 +6,21 @@
|
||||
|
||||
#include "device_manager.h"
|
||||
|
||||
#include <util/AutoLock.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <module.h>
|
||||
#include <Locker.h>
|
||||
|
||||
#include <new>
|
||||
#include <set>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <KernelExport.h>
|
||||
#include <module.h>
|
||||
#include <Locker.h>
|
||||
|
||||
#include <fs/KPath.h>
|
||||
#include <util/AutoLock.h>
|
||||
#include <util/DoublyLinkedList.h>
|
||||
#include <util/Stack.h>
|
||||
|
||||
|
||||
#define TRACE(a) dprintf a
|
||||
|
||||
@ -107,6 +109,13 @@ struct device_node : DoublyLinkedListLinkImpl<device_node> {
|
||||
|
||||
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<KPath*>* stack = NULL;
|
||||
|
||||
if (cookie == NULL) {
|
||||
// find all paths and add them
|
||||
stack = new(std::nothrow) Stack<KPath*>();
|
||||
if (stack == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
StackDeleter<KPath*> 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<Stack<KPath*>*>(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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user