* 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:
Axel Dörfler 2008-05-08 16:48:14 +00:00
parent 56bbbbc9ca
commit b9c7ba4bba
3 changed files with 513 additions and 67 deletions

View File

@ -8,10 +8,10 @@ UsePrivateHeaders shared ;
SimpleTest device_manager :
device_manager.cpp
KPath.cpp
bus.cpp
driver.cpp
: be libkernelland_emu.so
;

View 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';
}
}

View File

@ -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;
}