Forgot to remove now unused files.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25664 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2008-05-26 18:07:04 +00:00
parent 187c576425
commit 34d976b499
10 changed files with 0 additions and 2991 deletions

View File

@ -1,532 +0,0 @@
/*
* Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2002-2004, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
/*
Part of Device Manager
Node attributes handling.
*/
#include "device_manager_private.h"
#include "dl_list.h"
#include <TypeConstants.h>
#include <stdlib.h>
#include <string.h>
static bool is_fixed_attribute(const char *name);
status_t
pnp_get_attr_uint8(device_node_handle node, const char *name,
uint8 *value, bool recursive)
{
status_t status;
benaphore_lock(&gNodeLock);
status = pnp_get_attr_uint8_nolock(node, name, value, recursive);
benaphore_unlock(&gNodeLock);
return status;
}
status_t
pnp_get_attr_uint8_nolock(device_node_handle node, const char *name,
uint8 *value, bool recursive)
{
device_attr_info *attr = pnp_find_attr_nolock(node, name, recursive, B_UINT8_TYPE);
if (attr == NULL)
return B_NAME_NOT_FOUND;
*value = attr->attr.value.ui8;
return B_OK;
}
status_t
pnp_get_attr_uint16(device_node_handle node, const char *name,
uint16 *value, bool recursive)
{
status_t status;
benaphore_lock(&gNodeLock);
status = pnp_get_attr_uint16_nolock(node, name, value, recursive);
benaphore_unlock(&gNodeLock);
return status;
}
status_t
pnp_get_attr_uint16_nolock(device_node_handle node, const char *name,
uint16 *value, bool recursive)
{
device_attr_info *attr = pnp_find_attr_nolock(node, name, recursive, B_UINT16_TYPE);
if (attr == NULL)
return B_NAME_NOT_FOUND;
*value = attr->attr.value.ui16;
return B_OK;
}
status_t
pnp_get_attr_uint32(device_node_handle node, const char *name,
uint32 *value, bool recursive)
{
status_t status;
benaphore_lock(&gNodeLock);
status = pnp_get_attr_uint32_nolock(node, name, value, recursive);
benaphore_unlock(&gNodeLock);
return status;
}
status_t
pnp_get_attr_uint32_nolock(device_node_handle node, const char *name,
uint32 *value, bool recursive)
{
device_attr_info *attr = pnp_find_attr_nolock(node, name, recursive, B_UINT32_TYPE);
if (attr == NULL)
return B_NAME_NOT_FOUND;
*value = attr->attr.value.ui32;
return B_OK;
}
status_t
pnp_get_attr_uint64(device_node_handle node, const char *name,
uint64 *value, bool recursive)
{
status_t status;
benaphore_lock(&gNodeLock);
status = pnp_get_attr_uint64_nolock(node, name, value, recursive);
benaphore_unlock(&gNodeLock);
return status;
}
status_t
pnp_get_attr_uint64_nolock(device_node_handle node, const char *name,
uint64 *value, bool recursive)
{
device_attr_info *attr = pnp_find_attr_nolock(node, name, recursive, B_UINT64_TYPE);
if (attr == NULL)
return B_NAME_NOT_FOUND;
*value = attr->attr.value.ui64;
return B_OK;
}
status_t
pnp_get_attr_string(device_node_handle node, const char *name,
char **value, bool recursive)
{
status_t status;
const char *orig_value;
benaphore_lock(&gNodeLock);
status = pnp_get_attr_string_nolock(node, name, &orig_value, recursive);
if (status == B_OK) {
*value = strdup(orig_value);
if (orig_value != NULL && *value == NULL)
status = B_NO_MEMORY;
}
benaphore_unlock(&gNodeLock);
return status;
}
status_t
pnp_get_attr_string_nolock(device_node_handle node, const char *name,
const char **value, bool recursive)
{
device_attr_info *attr = pnp_find_attr_nolock(node, name, recursive, B_STRING_TYPE);
if (attr == NULL)
return B_NAME_NOT_FOUND;
*value = attr->attr.value.string;
return B_OK;
}
status_t
pnp_get_attr_raw(device_node_handle node, const char *name,
void **data, size_t *length, bool recursive)
{
const void *orig_data;
status_t status;
benaphore_lock(&gNodeLock);
status = pnp_get_attr_raw_nolock( node, name, &orig_data, length, recursive );
if (status == B_OK) {
void *tmp_data = malloc(*length);
if (tmp_data != NULL) {
memcpy(tmp_data, orig_data, *length);
*data = tmp_data;
} else
status = B_NO_MEMORY;
}
benaphore_unlock(&gNodeLock);
return status;
}
status_t
pnp_get_attr_raw_nolock(device_node_handle node, const char *name,
const void **data, size_t *length, bool recursive)
{
device_attr_info *attr = pnp_find_attr_nolock(node, name, recursive, B_RAW_TYPE);
if (attr == NULL)
return B_NAME_NOT_FOUND;
*data = attr->attr.value.raw.data;
*length = attr->attr.value.raw.length;
return B_OK;
}
/** Compare two attributes for */
int
pnp_compare_attrs(const device_attr *attrA, const device_attr *attrB)
{
if (attrA->type != attrB->type)
return -1;
switch (attrA->type) {
case B_UINT8_TYPE:
return (int)attrA->value.ui8 - (int)attrB->value.ui8;
case B_UINT16_TYPE:
return (int)attrA->value.ui16 - (int)attrB->value.ui16;
case B_UINT32_TYPE:
if (attrA->value.ui32 > attrB->value.ui32)
return 1;
if (attrA->value.ui32 < attrB->value.ui32)
return -1;
return 0;
case B_UINT64_TYPE:
if (attrA->value.ui64 > attrB->value.ui64)
return 1;
if (attrA->value.ui64 < attrB->value.ui64)
return -1;
return 0;
case B_STRING_TYPE:
return strcmp(attrA->value.string, attrB->value.string);
case B_RAW_TYPE:
if (attrA->value.raw.length != attrB->value.raw.length)
return -1;
return memcmp(attrA->value.raw.data, attrB->value.raw.data, attrA->value.raw.length);
}
return -1;
}
// free node attribute
void
pnp_free_node_attr(device_attr_info *attr)
{
free((char *)attr->attr.name);
switch (attr->attr.type) {
case B_STRING_TYPE:
free((char *)attr->attr.value.string);
break;
case B_RAW_TYPE:
free(attr->attr.value.raw.data);
break;
}
free(attr);
}
// duplicate node attribute
status_t
pnp_duplicate_node_attr(const device_attr *src, device_attr_info **dest_out)
{
device_attr_info *dest;
status_t res;
dest = malloc(sizeof(*dest));
if (dest == NULL)
return B_NO_MEMORY;
memset(dest, 0, sizeof(*dest));
dest->ref_count = 1;
dest->attr.name = strdup(src->name);
dest->attr.type = src->type;
switch (src->type) {
case B_UINT8_TYPE:
case B_UINT16_TYPE:
case B_UINT32_TYPE:
case B_UINT64_TYPE:
dest->attr.value.ui64 = src->value.ui64;
break;
case B_STRING_TYPE:
dest->attr.value.string = strdup(src->value.string);
if (dest->attr.value.string == NULL) {
res = B_NO_MEMORY;
goto err;
}
break;
case B_RAW_TYPE:
dest->attr.value.raw.data = malloc(src->value.raw.length);
if (dest->attr.value.raw.data == NULL) {
res = B_NO_MEMORY;
goto err;
}
dest->attr.value.raw.length = src->value.raw.length;
memcpy(dest->attr.value.raw.data, src->value.raw.data,
src->value.raw.length);
break;
default:
res = B_BAD_VALUE;
goto err;
}
*dest_out = dest;
return B_OK;
err:
free(dest);
return res;
}
// public: get first/next attribute of node
status_t
pnp_get_next_attr(device_node_handle node, device_attr_handle *attr)
{
device_attr_info *next;
benaphore_lock(&gNodeLock);
if (*attr != NULL) {
// next attribute
next = (*attr)->next;
// implicit release of previous attribute
if (--(*attr)->ref_count == 0)
pnp_free_node_attr(*attr);
} else {
// first attribute
next = node->attributes;
}
if (next)
++next->ref_count;
*attr = next;
benaphore_unlock(&gNodeLock);
return next ? B_OK : B_ENTRY_NOT_FOUND;
}
// public: release attribute of node explicitely
status_t
pnp_release_attr(device_node_handle node, device_attr_handle attr)
{
benaphore_lock(&gNodeLock);
if (--attr->ref_count == 0)
pnp_free_node_attr(attr);
benaphore_unlock(&gNodeLock);
return B_OK;
}
// public: retrieve data of attribute
status_t
pnp_retrieve_attr(device_attr_handle attr, const device_attr **attr_content)
{
*attr_content = &attr->attr;
return B_OK;
}
// remove attribute from node, freeing it if not in use
// node_lock must be hold
void
pnp_remove_attr_int(device_node_handle node, device_attr_info *attr)
{
REMOVE_DL_LIST(attr, node->attributes, );
if (--attr->ref_count == 0)
pnp_free_node_attr(attr);
}
// public: remove attribute from node
status_t
pnp_remove_attr(device_node_handle node, const char *name)
{
device_attr_info *attr;
// don't remove holy attributes
if (is_fixed_attribute(name))
return B_NOT_ALLOWED;
benaphore_lock(&gNodeLock);
// find attribute in list
attr = pnp_find_attr_nolock(node, name, false, B_ANY_TYPE);
if (attr != NULL) {
// and remove it from it
pnp_remove_attr_int(node, attr);
}
benaphore_unlock(&gNodeLock);
return attr ? B_OK : B_ENTRY_NOT_FOUND;
}
// public: modify attribute's content
status_t
pnp_write_attr(device_node_handle node, const device_attr *attr)
{
device_attr_info *old_attr, *new_attr;
status_t res;
// don't touch holy attributes
if (is_fixed_attribute(attr->name))
return B_NOT_ALLOWED;
res = pnp_duplicate_node_attr(attr, &new_attr);
if (res != B_OK)
return res;
benaphore_lock(&gNodeLock);
// check whether it's an add or modify
for (old_attr = node->attributes; old_attr != NULL; old_attr = old_attr->next) {
if (!strcmp(attr->name, old_attr->attr.name))
break;
}
if (old_attr != NULL) {
// it's a modify
// we first insert new attribute after old one...
// (so it appears at same position in attribute list)
new_attr->prev = old_attr;
new_attr->next = old_attr->next;
if (old_attr->next == NULL)
old_attr->next->prev = new_attr;
old_attr->next = new_attr;
// ...and get rid of the old one
REMOVE_DL_LIST(old_attr, node->attributes, );
if (--old_attr->ref_count == 0)
pnp_free_node_attr(old_attr);
} else {
// it's an add
// append to end of list;
// this is really something to optimize
if (node->attributes == NULL) {
ADD_DL_LIST_HEAD(new_attr, node->attributes, );
} else {
device_attr_info *last_attr;
for (last_attr = node->attributes; last_attr->next != NULL; last_attr = last_attr->next)
;
last_attr->next = new_attr;
new_attr->prev = last_attr;
new_attr->next = NULL;
}
}
benaphore_unlock(&gNodeLock);
return B_OK;
}
// check whether attribute cannot be modified;
// returns true, if that's forbidden
static bool
is_fixed_attribute(const char *name)
{
static const char *forbidden_list[] = {
B_DRIVER_MODULE, // never change driver
PNP_BUS_IS_BUS, // never switch between bus/not bus mode
};
uint32 i;
// some attributes are to important to get modified or removed directly
for (i = 0; i < sizeof(forbidden_list) / sizeof(forbidden_list[0]); ++i) {
if (!strcmp(name, forbidden_list[i]))
return true;
}
return false;
}
// same as pnp_find_attr(), but node_lock must be hold and is never released
device_attr_info *
pnp_find_attr_nolock(device_node_handle node, const char *name,
bool recursive, type_code type)
{
do {
device_attr_info *attr;
for (attr = node->attributes; attr != NULL; attr = attr->next) {
if (type != B_ANY_TYPE && attr->attr.type != type)
continue;
if (!strcmp(attr->attr.name, name))
return attr;
}
node = node->parent;
} while (node != NULL && recursive);
return NULL;
}

View File

@ -1,204 +0,0 @@
/*
* Copyright 2004-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2002-2004, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
/*
Part of Device Manager
Main file.
*/
#include "device_manager_private.h"
#include <kdevice_manager.h>
#include <generic_syscall.h>
#include <KernelExport.h>
#include <stdlib.h>
#include <string.h>
//#define TRACE_DEVICE_MANAGER
#ifdef TRACE_DEVICE_MANAGER
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
device_node_info *gRootNode;
bool disable_useraddons;
int pnp_resource_wait_count;
sem_id pnp_resource_wait_sem;
io_resource_info *io_mem_list, *io_port_list, *isa_dma_list;
static int
dump_device_nodes(int argc, char **argv)
{
dm_dump_node(gRootNode, 0);
return 0;
}
static status_t
std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
default:
return B_ERROR;
}
}
// ToDo: the device manager exports these for now, so that Thomas's driver
// can work on both R5 and Haiku without too much hassle.
// We might also want to keep it in order to have the possibility to make
// substantial changes without breaking compatibility, and eventually
// separate it from the kernel for whatever reason.
device_manager_info gDeviceManagerModule = {
{
B_DEVICE_MANAGER_MODULE_NAME,
0,
std_ops
},
pnp_load_driver,
pnp_unload_driver,
dm_rescan,
dm_register_node,
dm_unregister_node,
dm_get_root,
dm_get_next_child_node,
dm_get_parent,
dm_put_node,
dm_acquire_io_resources,
dm_release_io_resources,
dm_create_id,
dm_free_id,
pnp_get_attr_uint8,
pnp_get_attr_uint16,
pnp_get_attr_uint32,
pnp_get_attr_uint64,
pnp_get_attr_string,
pnp_get_attr_raw,
pnp_get_next_attr,
pnp_release_attr,
pnp_retrieve_attr,
pnp_write_attr,
NULL // remove_attr
};
// #pragma mark -
status_t
device_manager_init(struct kernel_args *args)
{
status_t status;
// char name[B_FILE_NAME_LENGTH];
// size_t size = sizeof(name);
// int32 cookie;
TRACE(("device manager init\n"));
status = dm_init_id_generator();
if (status < B_OK) {
panic("could not initialize ID generator\n");
return status;
}
status = dm_init_nodes();
if (status < B_OK) {
panic("could not initialize device nodes\n");
return status;
}
pnp_resource_wait_sem = create_sem(0, "pnp_resource_wait_sem");
if (pnp_resource_wait_sem < 0) {
panic("could not create resource wait sem\n");
return pnp_resource_wait_sem;
}
pnp_resource_wait_count = 0;
io_mem_list = io_port_list = isa_dma_list = NULL;
pnp_fs_emulation_nesting = 0;
dm_init_root_node();
#ifdef TRACE_DEVICE_MANAGER
{
// dump root node
device_node_info *node = gRootNode;
while (node && node->parent != NULL)
node = node->parent;
dm_dump_node(node, 0);
}
#endif
// build initial device tree; register all root bus_managers
#if 0
cookie = 0;
while (get_next_loaded_module_name(&cookie, name, &size) == B_OK) {
if (strncmp(name, "bus_managers", 12))
continue;
dprintf(": %s\n", name);
size = sizeof(name);
}
#endif
add_debugger_command("dm_tree", &dump_device_nodes, "dump device node tree");
register_generic_syscall(DEVICE_MANAGER_SYSCALLS, device_manager_control, 1, 0);
return B_OK;
}
// hold gNodeLock
static void
device_manager_rescan_bus(device_node_info *parent)
{
device_node_info *node = NULL;
char *dummy;
if (pnp_get_attr_string(parent, B_DRIVER_BUS, &dummy, false) == B_OK) {
free(dummy);
dm_rescan(parent);
}
while ((node = (device_node_info *)list_get_next_item(&parent->children, node)) != NULL) {
device_manager_rescan_bus(node);
}
}
status_t
device_manager_init_post_modules(struct kernel_args *args)
{
TRACE(("device_manager_init_post_modules()\n"));
device_manager_rescan_bus(gRootNode);
TRACE(("device_manager_init_post_modules() rescan done\n"));
return B_OK;
}

View File

@ -1,86 +0,0 @@
/*
Copyright 2002/03, Thomas Kurschel. All rights reserved.
Distributed under the terms of the NewOS License.
Macros for double linked lists
*/
#ifndef _DL_LIST_H
#define _DL_LIST_H
#define REMOVE_DL_LIST( item, head, prefix ) \
do { \
if( item->prefix##prev ) \
item->prefix##prev->prefix##next = item->prefix##next; \
else \
head = item->prefix##next; \
\
if( item->prefix##next ) \
item->prefix##next->prefix##prev = item->prefix##prev; \
} while( 0 )
#define ADD_DL_LIST_HEAD( item, head, prefix ) \
do { \
item->prefix##next = head; \
item->prefix##prev = NULL; \
\
if( (head) ) \
(head)->prefix##prev = item; \
\
(head) = item; \
} while( 0 )
#define REMOVE_CDL_LIST( item, head, prefix ) \
do { \
item->prefix##next->prefix##prev = item->prefix##prev; \
item->prefix##prev->prefix##next = item->prefix##next; \
\
if( item == (head) ) { \
if( item->prefix##next != item ) \
(head) = item->prefix##next; \
else \
(head) = NULL; \
} \
} while( 0 )
#define ADD_CDL_LIST_TAIL( item, type, head, prefix ) \
do { \
type *old_head = head; \
\
if( old_head ) { \
type *first, *last; \
\
first = old_head; \
last = first->prefix##prev; \
\
item->prefix##next = first; \
item->prefix##prev = last; \
first->prefix##prev = item; \
last->prefix##next = item; \
} else { \
head = item; \
item->prefix##next = item->prefix##prev = item; \
} \
} while( 0 )
#define ADD_CDL_LIST_HEAD( item, type, head, prefix ) \
do { \
type *old_head = head; \
\
head = item; \
if( old_head ) { \
type *first, *last; \
\
first = old_head; \
last = first->prefix##prev; \
\
item->prefix##next = first; \
item->prefix##prev = last; \
first->prefix##prev = item; \
last->prefix##next = item; \
} else { \
item->prefix##next = item->prefix##prev = item; \
} \
} while( 0 )
#endif

View File

@ -1,343 +0,0 @@
/*
* Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2002-2004, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
/*
Part of Device Manager
device driver loader.
*/
#include "device_manager_private.h"
#include <KernelExport.h>
#include <stdlib.h>
#include <string.h>
//#define TRACE_DRIVER_LOADER
#ifdef TRACE_DRIVER_LOADER
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
/** unblock loading of driver
* node_lock must be hold
*/
void
pnp_unblock_load(device_node_info *node)
{
if (--node->load_block_count == 0 && node->num_blocked_loads > 0) {
TRACE(("Releasing blocked loads of %p\n", node));
release_sem_etc(node->load_block_sem,
node->num_blocked_loads, B_DO_NOT_RESCHEDULE);
node->num_blocked_loads = 0;
}
}
/** if loading of driver is blocked, wait until it is unblocked
* node_lock must be hold
*/
static void
pnp_wait_load_block(device_node_info *node)
{
if (node->load_block_count > 0) {
TRACE(("Loading of %p is blocked - wait until unblock\n", node));
// make sure we get informed about unblock
++node->num_blocked_loads;
benaphore_unlock(&gNodeLock);
acquire_sem(node->load_block_sem);
benaphore_lock(&gNodeLock);
TRACE(("Continuing loading of %p\n", node));
}
}
/** load driver for real
* (loader_lock must be hold)
*/
static status_t
load_driver_int(device_node_info *node, void *user_cookie)
{
driver_module_info *driver;
char *moduleName;
void *cookie;
status_t status;
TRACE(("load_driver_int()\n"));
status = pnp_get_attr_string(node, B_DRIVER_MODULE, &moduleName, false);
if (status != B_OK)
return status;
TRACE(("%s\n", moduleName));
status = get_module(moduleName, (module_info **)&driver);
if (status < B_OK) {
dprintf("Cannot load module %s\n", moduleName);
goto err1;
}
if (driver->init_driver == NULL) {
dprintf("Driver %s has no init_driver hook\n", moduleName);
status = B_ERROR;
goto err2;
}
status = driver->init_driver(node, user_cookie, &cookie);
if (status < B_OK) {
dprintf("init driver failed (node %p, %s): %s\n", node, moduleName, strerror(status));
goto err2;
}
node->driver = driver;
node->cookie = cookie;
free(moduleName);
return B_OK;
err2:
put_module(moduleName);
err1:
free(moduleName);
return status;
}
/** public: load driver */
status_t
pnp_load_driver(device_node_handle node, void *user_cookie,
driver_module_info **interface, void **cookie)
{
status_t res;
TRACE(("pnp_load_driver()\n"));
if (node == NULL)
return B_BAD_VALUE;
benaphore_lock(&gNodeLock);
if (!node->registered) {
benaphore_unlock(&gNodeLock);
TRACE(("Refused loading as driver got unregistered\n"));
return B_NAME_NOT_FOUND;
}
// increase ref_count whenever someone loads the driver
// to keep node information alive
++node->ref_count;
if (node->load_count == 0) {
// driver is not loaded
// tell others that someone will load the driver
// (after this, noone is allowed to block loading)
++node->loading;
// wait until loading is not blocked
pnp_wait_load_block(node);
// make sure noone else load/unloads/notifies the driver
pnp_start_hook_call_nolock(node);
if (!node->registered) {
// device got lost meanwhile
TRACE(("Device got lost during wait\n"));
res = B_NAME_NOT_FOUND;
} else if (node->load_count == 0) {
// noone loaded the driver meanwhile, so
// we have to do that
benaphore_unlock(&gNodeLock);
TRACE(("Driver will be loaded\n"));
res = load_driver_int(node, user_cookie);
benaphore_lock(&gNodeLock);
} else {
// some other thread loaded the driver meanwhile
TRACE(("Driver got loaded during wait\n"));
res = B_OK;
}
// info: the next statements may have a strange order,
// but as we own node_lock, order is not important
// finish loading officially
// (don't release node_lock before load_count gets increased!)
--node->loading;
// unblock concurrent load/unload/notification
pnp_finish_hook_call_nolock(node);
if (res == B_OK) {
// everything went fine - increase load counter
++node->load_count;
} else {
// loading failed or device got removed - restore reference count;
// but first (i.e. as long as ref_count is increased) get
// rid of waiting children
dm_put_node_nolock(node);
}
} else {
// driver is already loaded, so increase load_count
++node->load_count;
res = B_OK;
}
benaphore_unlock(&gNodeLock);
if (res == B_OK) {
if (interface)
*interface = node->driver;
if (cookie)
*cookie = node->cookie;
TRACE(("load_driver: Success \"%s\"\n",
((struct module_info *)node->driver)->name));
} else {
TRACE(("load_driver: Failure (%s)\n", strerror(res)));
}
return res;
}
/** unload driver for real */
static status_t
unload_driver_int(device_node_info *node)
{
driver_module_info *driver = node->driver;
char *moduleName;
status_t status;
status = pnp_get_attr_string(node, B_DRIVER_MODULE, &moduleName, false);
if (status != B_OK)
return status;
TRACE(("unload_driver_int: %s\n", moduleName));
if (driver->uninit_driver == NULL) {
// it has no uninit - we can't unload it, so it stays in memory forever
TRACE(("Driver %s has no uninit_device hook\n", moduleName));
status = B_ERROR;
goto out;
}
status = driver->uninit_driver(node->cookie);
if (status != B_OK) {
TRACE(("Failed to uninit driver %s (%s)\n", moduleName, strerror(status)));
goto out;
}
// if it was unregistered a while ago but couldn't get cleaned up
// because it was in use, do the cleanup now
if (!node->registered) {
if (driver->device_cleanup != NULL)
driver->device_cleanup(node);
}
put_module(moduleName);
out:
free(moduleName);
return status;
}
/** public: unload driver */
status_t
pnp_unload_driver(device_node_handle node)
{
status_t res;
TRACE(("pnp_unload_driver: %p\n", node));
if (node == NULL)
return B_BAD_VALUE;
benaphore_lock(&gNodeLock);
if (node->loading > 0 || node->load_count == 1) {
// we may have to unload the driver because:
// - load_count will be zero after decrement, or
// - there is a concurrent load/unload call, so we
// don't know what the future load_count will be
// signal active unload;
// don't decrease load_count - the driver is still loaded!
++node->loading;
// wait for concurrent load/unload/notification
pnp_start_hook_call_nolock(node);
if (node->load_count == 1) {
// node is still to be unloaded
benaphore_unlock(&gNodeLock);
TRACE(("unloading %p\n", node));
res = unload_driver_int(node);
benaphore_lock(&gNodeLock);
} else {
// concurrent load/unload either unloaded the driver or
// increased load_count so unload is not necessary or forbidden
TRACE(("don't unload as current load_count is %ld\n",
node->load_count));
res = B_OK;
}
// signal unload finished
--node->loading;
if (res == B_OK) {
// everything is fine, so decrease load_count ...
--node->load_count;
// ... and reference count
dm_put_node_nolock(node);
} else {
// unloading failed: leave loaded in memory forever
// as load_count is not decreased, the driver will never
// be unloaded, and as reference count is not decreased,
// the node will exist forever
TRACE(("Unload failed - leaving driver of %p in memory\n", node));
}
// unblock others
pnp_finish_hook_call_nolock(node);
} else {
// no concurrent load/unload and load_count won't reach zero
--node->load_count;
// each load increased reference count by one - time to undo that
dm_put_node_nolock(node);
res = B_OK;
}
benaphore_unlock(&gNodeLock);
return res;
}

View File

@ -1,679 +0,0 @@
/*
* Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2002-2004, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
/*
Part of Device Manager
device node handling.
To make sure that nodes persist as long as somebody is using them, we
maintain a reference count (ref_count) which is increased
- when the node is officially registered
- if someone loads the corresponding driver
- for each child
node_lock must be hold when updating of reference count, children
dependency list and during (un)-registration.
*/
#include "device_manager_private.h"
#include "dl_list.h"
#include <kernel.h>
#include <KernelExport.h>
#include <TypeConstants.h>
#include <stdlib.h>
#include <string.h>
//#define TRACE_NODES
#ifdef TRACE_NODES
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
benaphore gNodeLock;
uint32 sNodeID; // nodes counter
static void
put_level(int32 level)
{
while (level-- > 0)
dprintf(" ");
}
static void
dump_attribute(device_attr_info *attr, int32 level)
{
if (attr == NULL)
return;
put_level(level + 2);
dprintf("\"%s\" : ", attr->attr.name);
switch (attr->attr.type) {
case B_STRING_TYPE:
dprintf("string : \"%s\"", attr->attr.value.string);
break;
case B_UINT8_TYPE:
dprintf("uint8 : %u (%#x)", attr->attr.value.ui8, attr->attr.value.ui8);
break;
case B_UINT16_TYPE:
dprintf("uint16 : %u (%#x)", attr->attr.value.ui16, attr->attr.value.ui16);
break;
case B_UINT32_TYPE:
dprintf("uint32 : %lu (%#lx)", attr->attr.value.ui32, attr->attr.value.ui32);
break;
case B_UINT64_TYPE:
dprintf("uint64 : %Lu (%#Lx)", attr->attr.value.ui64, attr->attr.value.ui64);
break;
default:
dprintf("raw data");
}
dprintf("\n");
dump_attribute(attr->next, level);
}
/** free attributes of node
* if an attribute is still in use, it's deletion is postponed
*/
static void
free_node_attrs(device_node_info *node)
{
device_attr_info *attr, *next_attr;
for (attr = node->attributes; attr != NULL; attr = next_attr) {
next_attr = attr->next;
pnp_remove_attr_int(node, attr);
}
node->attributes = NULL;
}
// free node's I/O resource list, setting it to NULL
// (resources must have been released already)
static void
free_node_resources(device_node_info *node)
{
free(node->io_resources);
node->io_resources = NULL;
}
// free node
// (node lock must be hold)
static void
free_node(device_node_info *node)
{
const char *generator_name, *driver_name;
uint32 auto_id;
// ToDo: we lose memory here if the attributes are available!
if (pnp_get_attr_string_nolock(node, B_DRIVER_MODULE, &driver_name, false) != B_OK)
driver_name = "?";
TRACE(("free_node(node: %p, driver: %s)\n", node, driver_name));
// free associated auto ID, if requested
if (pnp_get_attr_string_nolock(node, PNP_MANAGER_ID_GENERATOR,
&generator_name, false) == B_OK) {
if (pnp_get_attr_uint32(node, PNP_MANAGER_AUTO_ID, &auto_id, false) != B_OK) {
TRACE(("Cannot find corresponding auto_id of generator %s", generator_name));
} else
dm_free_id(generator_name, auto_id);
}
dm_release_node_resources(node);
delete_sem(node->hook_sem);
delete_sem(node->load_block_sem);
free_node_attrs(node);
free_node_resources(node);
free(node);
}
// copy node attributes into node's attribute list
static status_t
copy_node_attrs(device_node_info *node, const device_attr *src)
{
status_t res;
const device_attr *src_attr;
device_attr_info *last_attr = NULL;
node->attributes = NULL;
// take care to keep attributes in same order;
// this is (currently) not necessary but a naive implementation would
// reverse order, which looks a bit odd (at least for the driver writer)
for (src_attr = src; src_attr->name != NULL; ++src_attr) {
device_attr_info *new_attr;
res = pnp_duplicate_node_attr( src_attr, &new_attr );
if (res != B_OK)
goto err;
//list_add_link_to_head(&node->attributes, new_attr);
ADD_DL_LIST_HEAD( new_attr, node->attributes, );
last_attr = new_attr;
}
return B_OK;
err:
free_node_attrs(node);
return res;
}
// allocate array of node I/O resources;
// all resource handles are set to zero, so if something goes wrong
// later on, resources aren't transferred to node
static status_t
allocate_node_resource_array(device_node_info *node, const io_resource_handle *resources)
{
const io_resource_handle *resource;
int num_resources = 0;
if (resources != NULL) {
for (resource = resources; *resource != NULL; ++resource)
++num_resources;
}
node->num_io_resources = num_resources;
node->io_resources = malloc((num_resources + 1) * sizeof(io_resource_handle));
if (node->io_resources == NULL)
return B_NO_MEMORY;
memset(node->io_resources, 0, (num_resources + 1) * sizeof(io_resource_handle));
return B_OK;
}
// #pragma mark -
// Device Manager private functions
/** allocate device node info structure;
* initially, ref_count is one to make sure node won't get destroyed by mistake
*/
status_t
dm_allocate_node(const device_attr *attrs, const io_resource_handle *resources,
device_node_info **_node)
{
device_node_info *node;
status_t res;
node = calloc(1, sizeof(*node));
if (node == NULL)
return B_NO_MEMORY;
res = copy_node_attrs(node, attrs);
if (res < 0)
goto err;
res = allocate_node_resource_array(node, resources);
if (res < 0)
goto err2;
res = node->hook_sem = create_sem(0, "pnp_hook");
if (res < 0)
goto err3;
res = node->load_block_sem = create_sem(0, "pnp_load_block");
if (res < 0)
goto err4;
list_init(&node->children);
node->parent = NULL;
node->rescan_depth = 0;
node->registered = false;
#if 0
node->verifying = false;
node->redetected = false;
node->init_finished = false;
#endif
node->ref_count = 1;
node->load_count = 0;
node->blocked_by_rescan = false;
node->automatically_loaded = false;
node->num_waiting_hooks = 0;
node->num_blocked_loads = 0;
node->load_block_count = 0;
node->loading = 0;
node->internal_id = sNodeID++;
TRACE(("dm_allocate_node(): new node %p\n", node));
*_node = node;
return B_OK;
err4:
delete_sem(node->hook_sem);
err3:
free_node_resources(node);
err2:
free_node_attrs(node);
err:
free(node);
return res;
}
void
dm_add_child_node(device_node_info *parent, device_node_info *node)
{
TRACE(("dm_add_child_node(parent = %p, child = %p)\n", parent, node));
if (parent == NULL)
return;
benaphore_lock(&gNodeLock);
// parent must not be destroyed as long as it has children
parent->ref_count++;
node->parent = parent;
// tell parent about us, so we get unregistered automatically if parent
// gets unregistered
list_add_item(&parent->children, node);
benaphore_unlock(&gNodeLock);
}
void
dm_get_node_nolock(device_node_info *node)
{
node->ref_count++;
}
// increase ref_count of node
void
dm_get_node(device_node_info *node)
{
TRACE(("dm_get_device_node(%p)\n", node));
if (node == NULL)
return;
benaphore_lock(&gNodeLock);
node->ref_count++;
benaphore_unlock(&gNodeLock);
}
// remove node reference and clean it up if necessary
// (gNodeLock must be hold)
void
dm_put_node_nolock(device_node_info *node)
{
do {
device_node_info *parent;
TRACE(("pnp_remove_node_ref_internal(ref_count of %p: %ld)\n", node, node->ref_count - 1));
// unregistered devices lose their I/O resources as soon as they
// are unloaded
if (!node->registered && node->loading == 0 && node->load_count == 0)
dm_release_node_resources(node);
if (--node->ref_count > 0)
return;
TRACE(("cleaning up %p (parent: %p)\n", node, node->parent));
// time to clean up
parent = node->parent;
if (parent != NULL)
list_remove_item(&parent->children, node);
free_node(node);
// unrolled recursive call: decrease ref_count of parent as well
node = parent;
} while (node != NULL);
}
#if 0
// public: find node with some node attributes given
device_node_info *
dm_find_device(device_node_info *parent, const device_attr *attrs)
{
device_node_info *node, *found_node;
found_node = NULL;
benaphore_lock(&gNodeLock);
for (node = gNodeList; node; node = node->next) {
const device_attr *attr;
// list contains removed devices too, so skip them
if (!node->registered)
continue;
if (parent != (device_node_info *)-1 && parent != node->parent)
continue;
for (attr = attrs; attr && attr->name; ++attr) {
device_attr_info *other = pnp_find_attr_nolock(node, attr->name, false, attr->type);
if (other == NULL || pnp_compare_attrs(attr, &other->attr))
break;
}
if (attr != NULL && attr->name != NULL)
continue;
// we found a node
if (found_node != NULL)
// but it wasn't the only one
return NULL;
// even though we found a node, keep on search to make sure no other
// node is matched too
found_node = node;
}
err:
benaphore_unlock(&gNodeLock);
return found_node;
}
#endif
void
dm_dump_node(device_node_info *node, int32 level)
{
device_node_info *child = NULL;
if (node == NULL)
return;
put_level(level);
dprintf("(%ld) @%p \"%s\"\n", level, node, node->driver ? node->driver->info.name : "---");
dump_attribute(node->attributes, level);
while ((child = (device_node_info *)list_get_next_item(&node->children, child)) != NULL) {
dm_dump_node(child, level + 1);
}
}
status_t
dm_init_nodes(void)
{
sNodeID = 1;
return benaphore_init(&gNodeLock, "device nodes");
}
// #pragma mark -
// Functions part of the module API
/** remove node reference and clean it up if necessary */
void
dm_put_node(device_node_info *node)
{
TRACE(("dm_put_node(%p)\n", node));
benaphore_lock(&gNodeLock);
dm_put_node_nolock(node);
benaphore_unlock(&gNodeLock);
}
device_node_info *
dm_get_root(void)
{
dm_get_node(gRootNode);
return gRootNode;
}
device_node_info *
dm_get_parent(device_node_info *node)
{
dm_get_node(node->parent);
return node->parent;
}
status_t
dm_get_next_child_node(device_node_info *parent, device_node_info **_node,
const device_attr *attrs)
{
device_node_info *node = *_node;
device_node_info *nodeToPut = node;
benaphore_lock(&gNodeLock);
while ((node = (device_node_info *)list_get_next_item(&parent->children, node)) != NULL) {
const device_attr *attr;
// list contains removed devices too, so skip them
if (!node->registered)
continue;
for (attr = attrs; attr && attr->name; ++attr) {
device_attr_info *other = pnp_find_attr_nolock(node, attr->name, false, attr->type);
if (other == NULL || pnp_compare_attrs(attr, &other->attr))
break;
}
if (attr != NULL && attr->name != NULL)
continue;
// we found a node
dm_get_node_nolock(node);
*_node = node;
if (nodeToPut != NULL)
dm_put_node_nolock(nodeToPut);
benaphore_unlock(&gNodeLock);
return B_OK;
}
if (nodeToPut != NULL)
dm_put_node_nolock(nodeToPut);
benaphore_unlock(&gNodeLock);
return B_ENTRY_NOT_FOUND;
}
// hold gNodeLock
static device_node_info *
device_manager_find_device(device_node_info *parent, uint32 id)
{
device_node_info *node = NULL;
if (parent->internal_id == id)
return parent;
while ((node = (device_node_info *)list_get_next_item(&parent->children, node)) != NULL) {
device_node_info *child = device_manager_find_device(node, id);
if (child != NULL)
return child;
}
return NULL;
}
status_t
device_manager_control(const char *subsystem, uint32 function, void *buffer, size_t bufferSize)
{
switch (function) {
case DM_GET_ROOT: {
uint32 cookie;
if (!IS_USER_ADDRESS(buffer))
return B_BAD_ADDRESS;
if (bufferSize < sizeof(uint32))
return B_BAD_VALUE;
cookie = gRootNode->internal_id;
// copy back to user space
if (user_memcpy(buffer, &cookie, sizeof(uint32)) < B_OK)
return B_BAD_ADDRESS;
return B_OK;
}
case DM_GET_CHILD: {
uint32 cookie;
device_node_info *node;
device_node_info *child;
if (!IS_USER_ADDRESS(buffer))
return B_BAD_ADDRESS;
if (bufferSize < sizeof(uint32))
return B_BAD_VALUE;
if (user_memcpy(&cookie, buffer, sizeof(uint32)) < B_OK)
return B_BAD_ADDRESS;
benaphore_lock(&gNodeLock);
node = device_manager_find_device(gRootNode, cookie);
if (!node) {
benaphore_unlock(&gNodeLock);
return B_BAD_VALUE;
}
child = (device_node_info *)list_get_next_item(&node->children, NULL);
if (child)
cookie = child->internal_id;
benaphore_unlock(&gNodeLock);
if (!child)
return B_ENTRY_NOT_FOUND;
// copy back to user space
if (user_memcpy(buffer, &cookie, sizeof(uint32)) < B_OK)
return B_BAD_ADDRESS;
return B_OK;
}
case DM_GET_NEXT_CHILD: {
uint32 cookie;
device_node_info *node;
device_node_info *child;
if (!IS_USER_ADDRESS(buffer))
return B_BAD_ADDRESS;
if (bufferSize < sizeof(uint32))
return B_BAD_VALUE;
if (user_memcpy(&cookie, buffer, sizeof(uint32)) < B_OK)
return B_BAD_ADDRESS;
benaphore_lock(&gNodeLock);
node = device_manager_find_device(gRootNode, cookie);
if (!node) {
benaphore_unlock(&gNodeLock);
return B_BAD_VALUE;
}
child = (device_node_info *)list_get_next_item(&node->parent->children, node);
if (child)
cookie = child->internal_id;
benaphore_unlock(&gNodeLock);
if (!child)
return B_ENTRY_NOT_FOUND;
// copy back to user space
if (user_memcpy(buffer, &cookie, sizeof(uint32)) < B_OK)
return B_BAD_ADDRESS;
return B_OK;
}
case DM_GET_NEXT_ATTRIBUTE: {
struct dev_attr attr;
device_node_info *node;
uint32 i = 0;
device_attr_info *attr_info;
if (!IS_USER_ADDRESS(buffer))
return B_BAD_ADDRESS;
if (bufferSize < sizeof(struct dev_attr))
return B_BAD_VALUE;
if (user_memcpy(&attr, buffer, sizeof(struct dev_attr)) < B_OK)
return B_BAD_ADDRESS;
benaphore_lock(&gNodeLock);
node = device_manager_find_device(gRootNode, attr.node_cookie);
if (!node) {
benaphore_unlock(&gNodeLock);
return B_BAD_VALUE;
}
for (attr_info = node->attributes; attr.cookie > i && attr_info != NULL; attr_info = attr_info->next) {
i++;
}
if (!attr_info) {
benaphore_unlock(&gNodeLock);
return B_ENTRY_NOT_FOUND;
}
attr.cookie++;
strlcpy(attr.name, attr_info->attr.name, 254);
attr.type = attr_info->attr.type;
switch (attr_info->attr.type) {
case B_UINT8_TYPE:
attr.value.ui8 = attr_info->attr.value.ui8; break;
case B_UINT16_TYPE:
attr.value.ui16 = attr_info->attr.value.ui16; break;
case B_UINT32_TYPE:
attr.value.ui32 = attr_info->attr.value.ui32; break;
case B_UINT64_TYPE:
attr.value.ui64 = attr_info->attr.value.ui64; break;
case B_STRING_TYPE:
strlcpy(attr.value.string, attr_info->attr.value.string, 254); break;
/*case B_RAW_TYPE:
if (attr.value.raw.length > attr_info->attr.value.raw.length)
attr.value.raw.length = attr_info->attr.value.raw.length;
user_memcpy(attr.value.raw.data, attr_info->attr.value.raw.data,
attr.value.raw.length);
break;*/
}
benaphore_unlock(&gNodeLock);
// copy back to user space
if (user_memcpy(buffer, &attr, sizeof(struct dev_attr)) < B_OK)
return B_BAD_ADDRESS;
return B_OK;
}
};
return B_BAD_HANDLER;
}

View File

@ -1,178 +0,0 @@
/*
* Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2002-2004, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
/*
Part of Device Manager
Execution and synchronization of driver hook calls.
*/
#include "device_manager_private.h"
#include <KernelExport.h>
#include <stdlib.h>
#include <string.h>
#define TRACE_NOTIFICATIONS
#ifdef TRACE_NOTIFICATIONS
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
/** notify driver that it's device got removed */
status_t
dm_notify_unregistration(device_node_info *node)
{
driver_module_info *driver;
bool loaded;
char *module_name;
void *cookie;
status_t res;
res = pnp_get_attr_string(node, B_DRIVER_MODULE, &module_name, false);
if (res != B_OK)
return res;
TRACE(("notify_device_removed(node: %p, consumer: %s)\n", node, module_name));
// block concurrent load/unload calls
pnp_start_hook_call(node);
#if 0
// don't notify driver if it doesn't know that the device was
// published
if (!node->init_finished)
goto skip;
#endif
// don't take node->loading into account - we want to know
// whether driver is loaded, not whether it is about to get loaded
loaded = node->load_count > 0;
if (loaded) {
TRACE(("Already loaded\n"));
driver = node->driver;
cookie = node->cookie;
} else {
TRACE(("Not loaded yet\n"));
// driver is not loaded - load it temporarily without
// calling init_device and pass <cookie>=NULL to tell
// the driver about
res = get_module(module_name, (module_info **)&driver);
if (res < B_OK)
goto err;
cookie = NULL;
}
// this hook is optional, so ignore it silently if NULL
if (driver->device_removed != NULL)
driver->device_removed(node, cookie);
else
dprintf("Driver %s has no device_removed hook\n", module_name);
// if driver wasn't loaded, call its cleanup method
if (!loaded) {
// again: this hook is optional
if (driver->device_cleanup != NULL)
driver->device_cleanup(node);
}
if (!loaded)
put_module(module_name);
skip:
pnp_finish_hook_call(node);
free(module_name);
return B_OK;
err:
free(module_name);
return res;
}
/** start driver hook call; must be called before a
* load/unload/notification hook is called
*/
void
pnp_start_hook_call(device_node_info *node)
{
bool blocked;
benaphore_lock(&gNodeLock);
blocked = ++node->num_waiting_hooks > 1;
benaphore_unlock(&gNodeLock);
if (blocked) {
TRACE(("Hook call of %p is blocked\n", node));
acquire_sem(node->hook_sem);
}
}
/** start driver hook call; same pnp_start_hook_call(), but
* node_lock must be hold
*/
void
pnp_start_hook_call_nolock(device_node_info *node)
{
if (++node->num_waiting_hooks > 1) {
benaphore_unlock(&gNodeLock);
TRACE(("Hook call of %p is blocked\n", node));
acquire_sem(node->hook_sem);
benaphore_lock(&gNodeLock);
}
}
/** finish driver hook call; must be called after a load/unload/notification
* hook is called
*/
void
pnp_finish_hook_call(device_node_info *node)
{
benaphore_lock(&gNodeLock);
if (--node->num_waiting_hooks > 1) {
TRACE(("Releasing other hook calls of %p\n", node));
release_sem(node->hook_sem);
}
benaphore_unlock(&gNodeLock);
}
/** finish driver hook call; same pnp_finish_hook_call(), but
* node_lock must be hold
*/
void
pnp_finish_hook_call_nolock(device_node_info *node)
{
if (--node->num_waiting_hooks > 1) {
TRACE(("Releasing other hook calls of %p\n", node));
release_sem(node->hook_sem);
}
}

View File

@ -1,243 +0,0 @@
/*
* Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2002-2004, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
/*
Part of Device Manager
Expansion of patterns.
Used to expand consumer/connector/device names etc.
*/
#include "device_manager_private.h"
#include <KernelExport.h>
#include <TypeConstants.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
//#define TRACE_PATTERNS
#ifdef TRACE_PATTERNS
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
/** expand node attribute
* node - node to get attributes from
* *pattern - name of attribute, ending with "%" (takes care of "^" sequences)
* on return, *patterns points to trailing "%"
* buffer - buffer for name
* dst - string to write content to
* node_lock must be hold
*/
static status_t
expand_attr(device_node_info *node, const char **pattern, char *buffer, char *dst)
{
device_attr_info *attr;
const char *str;
int buffer_len;
// extract attribute name
buffer_len = 0;
for (str = *pattern; *str; ++str) {
if (*str == '^' && *(str + 1) != 0)
// copy escaped character directly
++str;
else if (*str == '%')
break;
buffer[buffer_len++] = *str;
}
*pattern = str;
buffer[buffer_len] = '\0';
// get attribute content and add it to path
attr = pnp_find_attr_nolock(node, buffer, true, B_ANY_TYPE);
if (attr == NULL) {
dprintf("Reference to unknown attribute %s\n", buffer);
return B_NAME_NOT_FOUND;
}
switch (attr->attr.type) {
case B_UINT8_TYPE:
sprintf(buffer, "%02x", attr->attr.value.ui8);
strlcat(dst, buffer, PATH_MAX);
break;
case B_UINT16_TYPE:
sprintf(buffer, "%04x", attr->attr.value.ui16);
strlcat(dst, buffer, PATH_MAX);
break;
case B_UINT32_TYPE:
sprintf(buffer, "%08lx", attr->attr.value.ui32);
strlcat(dst, buffer, PATH_MAX);
break;
case B_UINT64_TYPE:
sprintf(buffer, "%16Lx", attr->attr.value.ui64);
strlcat(dst, buffer, PATH_MAX);
break;
case B_STRING_TYPE: {
const char *str;
//strlcat(dst, "\"", PATH_MAX);
for (str = attr->attr.value.string; *str; ++str) {
char ch;
ch = *str;
if (ch >= 32 && ch <= 126 && ch != '/' && ch != '%' && ch != '"') {
buffer[0] = ch;
buffer[1] = 0;
} else {
// convert unprintable/forbidden characters to numbers
sprintf(buffer, "%%%u%%", (unsigned char)ch);
}
strlcat(dst, buffer, PATH_MAX);
}
//strlcat(dst, "\"", PATH_MAX);
break;
}
case B_RAW_TYPE:
default:
benaphore_unlock(&gNodeLock);
return B_BAD_VALUE;
}
benaphore_unlock(&gNodeLock);
return B_OK;
}
/** expand pattern.
* the pattern is both expanded and the position of inidiual parts returned
* pattern - pattern to expand
* dest - expanded name is appended to this string
* buffer - buffer of MAX_PATH+1 size supplied by caller
* term_array - list of lengths of individual sub-names
* with index 0 containing the length of the shortest and
* num_parts-1 - length of the longest sub-name
* <term_array> and <num_parts> can be NULL
* node_lock must be hold
*/
status_t
pnp_expand_pattern(device_node_info *node, const char *pattern, char *dest,
char *buffer, size_t *term_array, int *num_parts)
{
const char *str;
int id;
status_t res;
int buffer_len = 0;
TRACE(("expand_pattern(pattern: %s)\n", pattern));
for (str = pattern, id = 0; *str; ++str) {
switch (*str) {
case '^':
// character following "^" is copied directly
// exception: if there is a trailing "^" at end of string,
// we copy it directly
if (*(str + 1) != 0)
++str;
buffer[buffer_len++] = *str;
break;
case '|':
// end of one name part
buffer[buffer_len] = '\0';
buffer_len = 0;
strlcat(dest, buffer, PATH_MAX);
TRACE(("%d: %s\n", id, dest));
if (term_array != NULL)
term_array[id++] = strlen(dest);
break;
case '%':
// begin of place-holder
buffer[buffer_len] = '\0';
buffer_len = 0;
strlcat(dest, buffer, PATH_MAX);
// skip "%"
++str;
res = expand_attr(node, &str, buffer, dest);
if (res != B_OK)
return res;
break;
default:
// normal character
buffer[buffer_len++] = *str;
}
// avoid overflow of buffer
if (buffer_len > PATH_MAX)
buffer_len = PATH_MAX;
}
// append trailing characters
buffer[buffer_len] = 0;
buffer_len = 0;
strlcat(dest, buffer, PATH_MAX);
if (term_array != NULL)
term_array[id++] = strlen(dest);
if (num_parts != NULL)
*num_parts = id;
TRACE(("result: %s\n", dest));
return B_OK;
}
/** expand pattern as specified by attribute <attr_name>
* node_lock must be hold
*/
status_t
pnp_expand_pattern_attr(device_node_info *node, const char *attr_name,
char **expanded)
{
const char *pattern;
status_t res;
TRACE(("pnp_expand_pattern_attr()\n"));
if (pnp_get_attr_string_nolock(node, attr_name, &pattern, false) != B_OK) {
*expanded = strdup("");
return B_OK;
}
*expanded = malloc((PATH_MAX + 1) * 2);
if (*expanded == NULL)
return B_NO_MEMORY;
**expanded = 0;
res = pnp_expand_pattern(node, pattern,
*expanded, *expanded + PATH_MAX + 1, NULL, NULL);
if (res != B_OK)
free(*expanded);
return res;
}

View File

@ -1,382 +0,0 @@
/*
* Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2002-2004, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
/*
Part of Device Manager
Device Node Registration.
*/
#include "device_manager_private.h"
#include "dl_list.h"
#include <KernelExport.h>
#include <string.h>
#include <stdlib.h>
//#define TRACE_REGISTRATION
#ifdef TRACE_REGISTRATION
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
/** mark node being registered, so it can be accessed via load_driver() */
static status_t
mark_node_registered(device_node_info *node)
{
status_t res;
TRACE(("mark_node_registered(%p)\n", node));
benaphore_lock(&gNodeLock);
if (node->parent && !node->parent->registered) {
TRACE(("Cannot mark registered: parent is already unregistered\n"));
res = B_NOT_ALLOWED;
} else {
res = B_OK;
node->registered = true;
++node->ref_count;
}
benaphore_unlock(&gNodeLock);
return res;
}
#if 0
/** Checks whether the device is redetected and removes any other
* device that is on same connection and has the same device identifier.
* \a redetected is set true if device is already registered;
* the node must not yet be linked into parent node's children list
*/
static status_t
is_device_redetected(device_node_info *node, device_node_info *parent, bool *redetected)
{
device_node_info *sibling;
status_t res;
bool found = false;
bool same_device = false;
bool unregister_sibling;
TRACE(("Checking %p, parent %p\n", node, parent));
*redetected = false;
if (parent == NULL) {
TRACE(("done\n"));
return false;
}
// we keep the lock very long, but this is the only way to be sure that
// no one else (un)-registers a conflicting note during the tests
benaphore_lock(&gNodeLock);
{
char *connection, *device_identifier;
// get our connection and device id...
if (pnp_expand_pattern_attr(node, PNP_DRIVER_CONNECTION, &connection) != B_OK)
connection = strdup("");
if (pnp_expand_pattern_attr(node, PNP_DRIVER_DEVICE_IDENTIFIER,
&device_identifier) != B_OK)
device_identifier = strdup("");
TRACE(("connection: %s, device_identifier: %s\n", connection, device_identifier));
// ...and compare it with our siblings
for (sibling = parent->children; sibling != NULL; sibling = sibling->siblings_next) {
char *sibling_connection, *sibling_device_identifier;
bool same_connection;
// ignore dead siblings
if (!sibling->registered)
break;
TRACE(("%p\n", sibling));
if (pnp_expand_pattern_attr(sibling, PNP_DRIVER_CONNECTION,
&sibling_connection) != B_OK)
sibling_connection = strdup("");
same_connection = !strcmp(connection, sibling_connection);
free(sibling_connection);
if (!same_connection)
continue;
// found a device on same connection - check whether it's the same device
found = true;
if (pnp_expand_pattern_attr(sibling, PNP_DRIVER_DEVICE_IDENTIFIER,
&sibling_device_identifier) != B_OK)
sibling_device_identifier = strdup("");
TRACE(("device %s is on same connection\n", sibling_device_identifier));
same_device = !strcmp(device_identifier, sibling_device_identifier);
free(sibling_device_identifier);
break;
}
free(connection);
free(device_identifier);
}
if (found) {
TRACE(("found device on same connection\n"));
if (!same_device) {
// there is a different device on the same connection -
// kick out the old device
TRACE(("different device was detected\n"));
*redetected = false;
unregister_sibling = true;
} else {
const char *driver_name, *old_driver_name;
const char *driver_type, *old_driver_type;
TRACE(("it's the same device\n"));
// found same device on same connection - make sure it's still the same driver
if (pnp_get_attr_string_nolock(node, PNP_DRIVER_DRIVER, &driver_name, false) != B_OK
|| pnp_get_attr_string_nolock(sibling, PNP_DRIVER_DRIVER, &old_driver_name, false) != B_OK
|| pnp_get_attr_string_nolock(node, PNP_DRIVER_TYPE, &driver_type, false) != B_OK
|| pnp_get_attr_string_nolock(sibling, PNP_DRIVER_TYPE, &old_driver_type, false) != B_OK) {
// these attributes _must_ be there, so this cannot happen
// (but we are prepared)
res = B_ERROR;
goto err;
}
if (strcmp(driver_name, old_driver_name) != 0
|| strcmp(driver_type, old_driver_type) != 0) {
// driver has changed - replace device node
TRACE(("driver got replaced\n"));
*redetected = false;
unregister_sibling = true;
} else {
// it's the same driver for the same device
TRACE(("redetected device\n"));
*redetected = true;
unregister_sibling = false;
}
}
} else {
// no collision on the device's connection
TRACE(("no collision\n"));
*redetected = false;
unregister_sibling = false;
}
if (*redetected && sibling->verifying)
sibling->redetected = true;
if (unregister_sibling) {
// increase ref_count to make sure node still exists
// when gNodeLock has been released
++sibling->ref_count;
benaphore_unlock(&gNodeLock);
pnp_unregister_device(sibling);
pnp_remove_node_ref_nolock(sibling);
} else
benaphore_unlock(&gNodeLock);
return B_OK;
err:
benaphore_unlock(&gNodeLock);
return res;
}
#endif
static status_t
push_node_on_stack(struct list *list, device_node_info *node)
{
struct node_entry *entry = (struct node_entry *)malloc(sizeof(struct node_entry));
if (entry == NULL)
return B_NO_MEMORY;
dm_get_node_nolock(node);
entry->node = node;
list_add_item(list, entry);
return B_OK;
}
static device_node_info *
pop_node_from_stack(struct list *list)
{
device_node_info *node;
struct node_entry *entry = (struct node_entry *)list_remove_head_item(list);
if (entry == NULL)
return NULL;
node = entry->node;
free(entry);
return node;
}
// #pragma mark -
// Public functions part of the module API
/** Register device node.
* In terms of I/O resources: if registration fails, they are freed; reason is
* that they may have been transferred to node before error and back-transferring
* them would be complicated.
*/
status_t
dm_register_node(device_node_handle parent, const device_attr *attrs,
const io_resource_handle *ioResources, device_node_handle *_node)
{
device_node_info *newNode;
char *driverName = NULL;
status_t status = B_OK;
struct list stack;
status = dm_allocate_node(attrs, ioResources, &newNode);
if (status != B_OK) {
// always "consume" I/O resources
dm_release_io_resources(ioResources);
return status;
}
if (pnp_get_attr_string(newNode, B_DRIVER_MODULE, &driverName, false) != B_OK)
status = B_BAD_VALUE;
TRACE(("dm_register_node(driver = %s)\n", driverName));
free(driverName);
if (status != B_OK) {
dprintf("device_manager: Missing driver module name.\n");
goto err;
}
// transfer resources to device, unregistering all colliding devices;
// this cannot fail - we've already allocated the resource handle array
dm_assign_io_resources(newNode, ioResources);
// make it public
dm_add_child_node(parent, newNode);
// The following is done to reduce the stack usage of deeply nested
// child device nodes.
// There is no other need to delay the complete registration process
// the way done here. This approach is also slightly different as
// the registration might fail later than it used in case of errors.
if (parent == NULL || parent->registered) {
// register all device nodes not yet registered - build a list
// that contain all of them, and then empty it one by one (during
// iteration, there might be new nodes added)
device_node_info *node = newNode;
list_init(&stack);
push_node_on_stack(&stack, newNode);
while ((node = pop_node_from_stack(&stack)) != NULL) {
device_node_info *child = NULL;
// register all fixed child device nodes as well
status = dm_register_fixed_child_devices(node);
if (status != B_OK)
goto err2;
node->registered = true;
// and now let it register all child devices, if it's a bus
status = dm_register_child_devices(node);
if (status != B_OK)
goto err2;
// push all new nodes on the stack
benaphore_lock(&gNodeLock);
while ((child = (device_node_info *)list_get_next_item(&node->children, child)) != NULL) {
if (!child->registered)
push_node_on_stack(&stack, child);
}
benaphore_unlock(&gNodeLock);
dm_put_node(node);
}
}
if (_node)
*_node = newNode;
return B_OK;
err2:
{
// nodes popped from the stack also need their reference count released
device_node_info *node;
while ((node = pop_node_from_stack(&stack)) != NULL) {
dm_put_node(node);
}
}
err:
// this also releases the I/O resources
dm_put_node(newNode);
return status;
}
/** Unregister device node.
* This also makes sure that all children of this node are unregistered.
*/
status_t
dm_unregister_node(device_node_info *node)
{
device_node_info *child, *nextChild;
TRACE(("pnp_unregister_device(%p)\n", node));
if (node == NULL)
return B_OK;
// unregistered node and all children
benaphore_lock(&gNodeLock);
if (node->parent != NULL)
list_remove_item(&node->parent->children, node);
benaphore_unlock(&gNodeLock);
// tell driver about their unregistration
dm_notify_unregistration(node);
// unregister children recursively
for (child = list_get_first_item(&node->children); child; child = nextChild) {
nextChild = (device_node_info *)child->siblings.next;
dm_unregister_node(child);
}
dm_put_node(node);
return B_OK;
}

View File

@ -1,96 +0,0 @@
/*
* Copyright 2004-2005, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2002/2003, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
/*
Part of Device Manager
Interface of device root module.
This module creates the root devices (usually PCI and ISA) to
initiate the PnP device scan.
*/
#include <KernelExport.h>
#include <Drivers.h>
#include "device_manager_private.h"
#define TRACE_ROOT_NODE
#ifdef TRACE_ROOT_NODE
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
#define PNP_ROOT_MODULE_NAME "system/devices_root/driver_v1"
void
dm_init_root_node(void)
{
device_attr attrs[] = {
{ B_DRIVER_MODULE, B_STRING_TYPE, { string: PNP_ROOT_MODULE_NAME }},
{ B_DRIVER_PRETTY_NAME, B_STRING_TYPE, { string: "Devices Root" }},
{ B_DRIVER_BUS, B_STRING_TYPE, { string: "root" }},
{ NULL }
};
if (dm_register_node(NULL, attrs, NULL, &gRootNode) != B_OK) {
// ToDo: don't panic for now
dprintf("Cannot register Devices Root Node\n");
}
}
static status_t
root_init_driver(device_node_handle node, void *user_cookie, void **_cookie)
{
*_cookie = NULL;
return B_OK;
}
static status_t
root_uninit_driver(void *cookie)
{
return B_OK;
}
static status_t
root_std_ops(int32 op, ...)
{
switch (op) {
case B_MODULE_INIT:
case B_MODULE_UNINIT:
return B_OK;
default:
return B_ERROR;
}
}
driver_module_info gDeviceRootModule = {
{
PNP_ROOT_MODULE_NAME,
0,
root_std_ops,
},
NULL, // supported devices
NULL, // register device
root_init_driver,
root_uninit_driver,
NULL,
NULL
};

View File

@ -1,248 +0,0 @@
/*
* Copyright 2004-2006, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
* Copyright 2002-2004, Thomas Kurschel. All rights reserved.
*
* Distributed under the terms of the MIT License.
*/
/*
Scanning for consumers.
Logic to execute (re)scanning of nodes.
During initial registration, problems with fixed consumers are
fatal. During rescan, this is ignored
(TODO: should this be done more consistently?)
*/
#include "device_manager_private.h"
#include <KernelExport.h>
#include <string.h>
#include <stdlib.h>
//#define TRACE_SCAN
#ifdef TRACE_SCAN
# define TRACE(x) dprintf x
#else
# define TRACE(x) ;
#endif
static status_t scan(device_node_info *node, bool rescan);
static int32 sRescanning = 0;
#if 0
// execute deferred probing of children
// (node_lock must be hold)
void
pnp_probe_waiting_children_nolock(device_node_info *node)
{
TRACE(("execute deferred probing of parent %p\n", node));
while (node->unprobed_children) {
device_node_info *child = node->unprobed_children;
REMOVE_DL_LIST(child, node->unprobed_children, unprobed_);
// child may have been removed meanwhile
if (child->registered) {
benaphore_unlock(&gNodeLock);
if (pnp_initial_scan(child) == B_OK)
pnp_load_driver_automatically(node, false);
benaphore_lock(&gNodeLock);
}
// reference count was increment to keep node alive in wannabe list;
// this is not necessary anymore
pnp_remove_node_ref(node);
}
TRACE((".. done.\n"));
}
// execute deferred probing of children
void
pnp_probe_waiting_children(device_node_info *node)
{
benaphore_lock(&gNodeLock);
pnp_probe_waiting_children_nolock(node);
benaphore_unlock(&gNodeLock);
}
#endif
/** ask bus to (re-)scan for connected devices */
static void
scan_bus(device_node_info *node, bool rescan)
{
// busses can register their children themselves
bus_module_info *interface;
status_t status;
void *cookie;
// load driver during rescan
status = pnp_load_driver(node, NULL, (driver_module_info **)&interface, &cookie);
if (status < B_OK) {
// we couldn't load a driver that had already registered itself...
return;
}
TRACE(("scan bus\n"));
// block other notifications (currently, only "removed" could be
// called as driver is/will stay loaded and scanning the bus
// concurrently has been assured to not happen)
pnp_start_hook_call(node);
if (rescan) {
if (interface->rescan_bus != NULL)
interface->rescan_bus(cookie);
} else {
if (interface->register_child_devices != NULL)
interface->register_child_devices(cookie);
}
pnp_finish_hook_call(node);
pnp_unload_driver(node);
// time to execute delayed probing
// pnp_probe_waiting_children(node);
}
/** recursively scan children of node (using depth-scan).
* node_lock must be hold
*/
static status_t
recursive_scan(device_node_info *node)
{
device_node_info *child = NULL;
status_t status;
TRACE(("recursive_scan(node = %p)\n", node));
while ((child = list_get_next_item(&node->children, child)) != NULL) {
dm_get_node_nolock(child);
// during rescan, we must release node_lock to not deadlock
benaphore_unlock(&gNodeLock);
status = scan(child, true);
benaphore_lock(&gNodeLock);
// unlock current child as it's not accessed anymore
dm_put_node_nolock(child);
// ignore errors because of touching unregistered nodes
if (status != B_OK && status != B_NAME_NOT_FOUND)
return status;
}
// no need unlock last child (don't be loop already)
TRACE(("recursive_scan(): done\n"));
return B_OK;
}
/** (re)scan for child nodes
*/
static status_t
scan(device_node_info *node, bool rescan)
{
status_t status = B_OK;
uint8 dummy;
bool isBus;
TRACE(("scan(node = %p, mode: %s)\n", node, rescan ? "rescan" : "register"));
isBus = pnp_get_attr_uint8(node, PNP_BUS_IS_BUS, &dummy, false) == B_OK;
// do the real thing - scan node
if (!rescan) {
uint8 loadDriversLater = false;
char *deviceType = NULL;
pnp_get_attr_uint8(node, B_DRIVER_FIND_DEVICES_ON_DEMAND, &loadDriversLater, false);
pnp_get_attr_string(node, B_DRIVER_DEVICE_TYPE, &deviceType, false);
if (isBus)
scan_bus(node, false);
// ask possible children to register their nodes
if (!loadDriversLater && deviceType == NULL) {
status = dm_register_dynamic_child_devices(node);
if (status != B_OK)
return status;
}
free(deviceType);
} else {
if (!isBus)
status = dm_register_dynamic_child_devices(node);
}
// scan children recursively;
// keep the node_lock to make sure noone removes children meanwhile
if (rescan && isBus) {
scan_bus(node, true);
benaphore_lock(&gNodeLock);
status = recursive_scan(node);
benaphore_unlock(&gNodeLock);
}
TRACE(("scan(): done (%p) - %s\n", node, strerror(status)));
return status;
}
// #pragma mark -
/** Rescan device node (only works if it's a bus) */
status_t
dm_rescan(device_node_info *node)
{
status_t err;
// only allow a single rescan at a time
if (atomic_add(&sRescanning, 1) > 1) {
dprintf("dm_rescan already scanning\n");
atomic_add(&sRescanning, -1);
return B_BUSY;
}
err = scan(node, true);
atomic_add(&sRescanning, -1);
return err;
}
/** execute registration of fully constructed node */
status_t
dm_register_child_devices(device_node_info *node)
{
return scan(node, false);
}