Work in progress:
* added [un]publish_device() calls to the device manager. * added a very basic devfs emulation to the playground to be able to test how the manager reacts to opened devices. * renamed *_device() functions to *_node() in the device manager API. * made B_DEVICE_FIND_CHILD_FLAGS a generic flags field, and renamed it to B_DEVICE_FLAGS. * added support for keeping a driver loaded as long as its device is available. * implemented get_next_child_node(). * added test for device removal, and implemented unregister_node() for this. * fixed some bugs in the device node reference/initialization count maintenance. * moved more code from register_node() to device_node::Register(). * initialize the device_node::fFlags member to the value of B_DEVICE_FLAGS, and have additional private flags. * renamed UninitUnusedChildren() to UninitUnusedDriver(), and fixed this function by adding the new flag NODE_FLAG_REGISTER_INITIALIZED. * Now remembers the support when a driver is registered - this will be used later to be able to compare with a new driver without having to call supports_device() again. * Removed NODE_FLAG_REMOVE_ON_UNINIT again, as that was pretty stupid - there is reference counting for a reason. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25498 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
c27f3926a0
commit
7a6818d3fa
@ -10,7 +10,27 @@
|
||||
#include <PCI.h>
|
||||
|
||||
|
||||
#define BUS_MODULE_NAME "bus_managers/sample_bus/driver_v1"
|
||||
void
|
||||
bus_trigger_device_removed(device_node* node)
|
||||
{
|
||||
// the network device
|
||||
device_attr attrs[] = {
|
||||
{B_DEVICE_VENDOR_ID, B_UINT16_TYPE, {ui16: 0x1001}},
|
||||
{B_DEVICE_ID, B_UINT16_TYPE, {ui16: 0x0001}},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
device_node* child = NULL;
|
||||
while (gDeviceManager->get_next_child_node(node, attrs, &child) == B_OK) {
|
||||
gDeviceManager->unregister_node(child);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
bus_trigger_device_added(device_node* node)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - bus
|
||||
@ -40,7 +60,7 @@ register_device(device_node *parent)
|
||||
{NULL}
|
||||
};
|
||||
|
||||
return gDeviceManager->register_device(parent, BUS_MODULE_NAME, attrs, NULL,
|
||||
return gDeviceManager->register_node(parent, BUS_MODULE_NAME, attrs, NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
@ -90,12 +110,11 @@ register_child_devices(device_node *node)
|
||||
{B_DEVICE_INTERFACE, B_UINT16_TYPE,
|
||||
{ui16: kDevices[i].interface}},
|
||||
|
||||
{B_DEVICE_FIND_CHILD_FLAGS, B_UINT32_TYPE,
|
||||
{ui32: B_FIND_CHILD_ON_DEMAND}},
|
||||
{B_DEVICE_FLAGS, B_UINT32_TYPE, {ui32: B_FIND_CHILD_ON_DEMAND}},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
gDeviceManager->register_device(node, BUS_FOR_DRIVER_NAME, attrs, NULL,
|
||||
gDeviceManager->register_node(node, BUS_FOR_DRIVER_NAME, attrs, NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
@ -107,7 +126,7 @@ register_child_devices(device_node *node)
|
||||
|
||||
#if 1
|
||||
// this is supposed to fail
|
||||
dprintf("non-existing child: %ld\n", gDeviceManager->register_device(node,
|
||||
dprintf("non-existing child: %ld\n", gDeviceManager->register_node(node,
|
||||
BUS_FOR_DRIVER_NAME, attrs, NULL, NULL));
|
||||
#endif
|
||||
return B_OK;
|
||||
|
@ -20,7 +20,14 @@ struct bus_for_driver_module_info {
|
||||
status_t (*get_bus_info)(void* cookie, bus_info* info);
|
||||
};
|
||||
|
||||
// Note: this file is also used by the device manager test to control the bus
|
||||
// driver
|
||||
|
||||
#define BUS_MODULE_NAME "bus_managers/sample_bus/driver_v1"
|
||||
#define BUS_FOR_DRIVER_NAME "bus_managers/sample_bus/device/driver_v1"
|
||||
#define BUS_NAME "mybus"
|
||||
|
||||
extern void bus_trigger_device_removed(device_node* node);
|
||||
extern void bus_trigger_device_added(device_node* node);
|
||||
|
||||
#endif // BUS_H
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <util/DoublyLinkedList.h>
|
||||
#include <util/Stack.h>
|
||||
|
||||
#include "bus.h"
|
||||
|
||||
#define TRACE(a) dprintf a
|
||||
|
||||
@ -69,7 +70,6 @@ private:
|
||||
|
||||
typedef DoublyLinkedList<device_attr_private> AttributeList;
|
||||
|
||||
|
||||
// I/O resource
|
||||
typedef struct io_resource_info {
|
||||
struct io_resource_info *prev, *next;
|
||||
@ -77,13 +77,20 @@ typedef struct io_resource_info {
|
||||
io_resource resource; // info about actual resource
|
||||
} io_resource_info;
|
||||
|
||||
struct device : DoublyLinkedListLinkImpl<device> {
|
||||
device() : node(NULL), path(NULL), module_name(NULL) {}
|
||||
~device()
|
||||
{
|
||||
free((char*)path);
|
||||
free((char*)module_name);
|
||||
}
|
||||
|
||||
// a structure to put nodes into lists
|
||||
struct node_entry {
|
||||
struct list_link link;
|
||||
device_node* node;
|
||||
const char* path;
|
||||
const char* module_name;
|
||||
};
|
||||
|
||||
typedef DoublyLinkedList<device> DeviceList;
|
||||
typedef DoublyLinkedList<device_node> NodeList;
|
||||
|
||||
struct device_node : DoublyLinkedListLinkImpl<device_node> {
|
||||
@ -101,6 +108,7 @@ struct device_node : DoublyLinkedListLinkImpl<device_node> {
|
||||
|
||||
status_t InitDriver();
|
||||
bool UninitDriver();
|
||||
void UninitUnusedDriver();
|
||||
|
||||
// The following two are only valid, if the node's driver is
|
||||
// initialized
|
||||
@ -110,9 +118,9 @@ struct device_node : DoublyLinkedListLinkImpl<device_node> {
|
||||
void AddChild(device_node *node);
|
||||
void RemoveChild(device_node *node);
|
||||
const NodeList& Children() const { return fChildren; }
|
||||
void UninitUnusedChildren();
|
||||
void DeviceRemoved();
|
||||
|
||||
status_t Register();
|
||||
status_t Register(device_node* parent);
|
||||
status_t Probe(const char* devicePath);
|
||||
bool IsRegistered() const { return fRegistered; }
|
||||
bool IsInitialized() const { return fInitialized > 0; }
|
||||
@ -122,6 +130,7 @@ struct device_node : DoublyLinkedListLinkImpl<device_node> {
|
||||
|
||||
int CompareTo(const device_attr* attributes) const;
|
||||
device_node* FindChild(const device_attr* attributes) const;
|
||||
device_node* FindChild(const char* moduleName) const;
|
||||
|
||||
void Dump(int32 level = 0);
|
||||
|
||||
@ -139,7 +148,6 @@ private:
|
||||
status_t _RegisterPath(const char* path);
|
||||
status_t _RegisterDynamic();
|
||||
status_t _RemoveChildren();
|
||||
bool _UninitUnusedChildren();
|
||||
|
||||
device_node* fParent;
|
||||
NodeList fChildren;
|
||||
@ -147,16 +155,21 @@ private:
|
||||
int32 fInitialized;
|
||||
bool fRegistered;
|
||||
uint32 fFlags;
|
||||
float fSupportsParent;
|
||||
|
||||
const char* fModuleName;
|
||||
|
||||
driver_module_info* fDriver;
|
||||
void* fDriverData;
|
||||
|
||||
AttributeList fAttributes;
|
||||
};
|
||||
|
||||
// flags in addition to those specified by B_DEVICE_FLAGS
|
||||
enum node_flags {
|
||||
NODE_FLAG_REMOVE_ON_UNINIT = 0x01
|
||||
NODE_FLAG_REGISTER_INITIALIZED = 0x00010000,
|
||||
|
||||
NODE_FLAG_PUBLIC_MASK = 0x0000ffff
|
||||
};
|
||||
|
||||
device_manager_info *gDeviceManager;
|
||||
@ -164,6 +177,9 @@ device_manager_info *gDeviceManager;
|
||||
static device_node *sRootNode;
|
||||
static recursive_lock sLock;
|
||||
|
||||
static DeviceList sDeviceList;
|
||||
// this is a *very* basic devfs emulation
|
||||
|
||||
|
||||
// #pragma mark - device_attr
|
||||
|
||||
@ -376,19 +392,51 @@ dump_attribute(device_attr* attr, int32 level)
|
||||
static void
|
||||
uninit_unused()
|
||||
{
|
||||
puts("uninit unused");
|
||||
RecursiveLocker _(sLock);
|
||||
sRootNode->UninitUnusedChildren();
|
||||
sRootNode->UninitUnusedDriver();
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
probe_path(const char* path)
|
||||
{
|
||||
printf("probe path \"%s\"\n", path);
|
||||
RecursiveLocker _(sLock);
|
||||
return sRootNode->Probe(path);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
close_path(void* cookie)
|
||||
{
|
||||
struct device* device = (struct device*)cookie;
|
||||
|
||||
printf("close path \"%s\" (node %p)\n", device->path, device->node);
|
||||
device->node->UninitDriver();
|
||||
}
|
||||
|
||||
|
||||
static void*
|
||||
open_path(const char* path)
|
||||
{
|
||||
DeviceList::Iterator iterator = sDeviceList.GetIterator();
|
||||
while (iterator.HasNext()) {
|
||||
struct device* device = iterator.Next();
|
||||
if (!strcmp(device->path, path)) {
|
||||
status_t status = device->node->InitDriver();
|
||||
if (status != B_OK)
|
||||
return NULL;
|
||||
|
||||
printf("open path \"%s\" (node %p)\n", device->path, device->node);
|
||||
return device;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
// #pragma mark - device_node
|
||||
|
||||
|
||||
@ -406,6 +454,8 @@ device_node::device_node(const char* moduleName, const device_attr* attrs,
|
||||
fRefCount = 1;
|
||||
fInitialized = 0;
|
||||
fRegistered = false;
|
||||
fFlags = 0;
|
||||
fSupportsParent = 0.0;
|
||||
fDriver = NULL;
|
||||
fDriverData = NULL;
|
||||
|
||||
@ -420,12 +470,19 @@ device_node::device_node(const char* moduleName, const device_attr* attrs,
|
||||
fAttributes.Add(attr);
|
||||
attrs++;
|
||||
}
|
||||
|
||||
dm_get_attr_uint32(this, B_DEVICE_FLAGS, &fFlags, false);
|
||||
fFlags &= NODE_FLAG_PUBLIC_MASK;
|
||||
}
|
||||
|
||||
|
||||
device_node::~device_node()
|
||||
{
|
||||
TRACE(("delete node %p\n", this));
|
||||
ASSERT(DriverModule() == NULL);
|
||||
|
||||
if (Parent() != NULL)
|
||||
Parent()->RemoveChild(this);
|
||||
|
||||
// Delete children
|
||||
NodeList::Iterator nodeIterator = fChildren.GetIterator();
|
||||
@ -468,7 +525,7 @@ device_node::InitDriver()
|
||||
|
||||
status_t status = get_module(ModuleName(), (module_info**)&fDriver);
|
||||
if (status == B_OK && Parent() != NULL) {
|
||||
// our parent always have to be initialized
|
||||
// our parent always has to be initialized
|
||||
status = Parent()->InitDriver();
|
||||
}
|
||||
if (status < B_OK) {
|
||||
@ -480,6 +537,8 @@ device_node::InitDriver()
|
||||
status = fDriver->init_driver(this, &fDriverData);
|
||||
|
||||
if (status < B_OK) {
|
||||
if (Parent() != NULL)
|
||||
Parent()->UninitDriver();
|
||||
fInitialized--;
|
||||
|
||||
put_module(ModuleName());
|
||||
@ -497,9 +556,12 @@ bool
|
||||
device_node::UninitDriver()
|
||||
{
|
||||
if (fInitialized-- > 1) {
|
||||
if (Parent() != NULL)
|
||||
Parent()->UninitDriver();
|
||||
Release();
|
||||
return false;
|
||||
}
|
||||
|
||||
TRACE(("uninit driver for node %p\n", this));
|
||||
|
||||
if (fDriver->uninit_driver != NULL)
|
||||
@ -510,12 +572,9 @@ device_node::UninitDriver()
|
||||
|
||||
put_module(ModuleName());
|
||||
|
||||
Release();
|
||||
if (Parent() != NULL)
|
||||
Parent()->UninitDriver();
|
||||
|
||||
if ((fFlags & NODE_FLAG_REMOVE_ON_UNINIT) != 0)
|
||||
Release();
|
||||
Release();
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -540,13 +599,38 @@ device_node::RemoveChild(device_node* node)
|
||||
}
|
||||
|
||||
|
||||
/*! Registers this node, and all of its children that have to be registered.
|
||||
Also initializes the driver and keeps it that way on return in case
|
||||
it returns successfully.
|
||||
*/
|
||||
status_t
|
||||
device_node::Register()
|
||||
device_node::Register(device_node* parent)
|
||||
{
|
||||
uint32 registered;
|
||||
status_t status = _RegisterFixed(registered);
|
||||
// make it public
|
||||
if (parent != NULL)
|
||||
parent->AddChild(this);
|
||||
else
|
||||
sRootNode = this;
|
||||
|
||||
status_t status = InitDriver();
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
|
||||
if ((fFlags & B_KEEP_DRIVER_LOADED) != 0) {
|
||||
// We keep this driver loaded by having it always initialized
|
||||
InitDriver();
|
||||
}
|
||||
|
||||
fFlags |= NODE_FLAG_REGISTER_INITIALIZED;
|
||||
// We don't uninitialize the driver - this is done by the caller
|
||||
// in order to save reinitializing during driver loading.
|
||||
|
||||
uint32 registered;
|
||||
status = _RegisterFixed(registered);
|
||||
if (status != B_OK) {
|
||||
UninitUnusedDriver();
|
||||
return status;
|
||||
}
|
||||
if (registered > 0) {
|
||||
fRegistered = true;
|
||||
return B_OK;
|
||||
@ -556,8 +640,10 @@ device_node::Register()
|
||||
|
||||
if (DriverModule()->register_child_devices != NULL) {
|
||||
status = DriverModule()->register_child_devices(this);
|
||||
if (status != B_OK)
|
||||
if (status != B_OK) {
|
||||
UninitUnusedDriver();
|
||||
return status;
|
||||
}
|
||||
|
||||
if (!fChildren.IsEmpty()) {
|
||||
fRegistered = true;
|
||||
@ -570,6 +656,8 @@ device_node::Register()
|
||||
status = _RegisterDynamic();
|
||||
if (status == B_OK)
|
||||
fRegistered = true;
|
||||
else
|
||||
UninitUnusedDriver();
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -578,7 +666,7 @@ device_node::Register()
|
||||
/*! Registers any children that are identified via the B_DRIVER_FIXED_CHILD
|
||||
attribute.
|
||||
If any of these children cannot be registered, this call will fail (we
|
||||
don't remove already registered children in this case).
|
||||
don't remove children we already registered up to this point in this case).
|
||||
*/
|
||||
status_t
|
||||
device_node::_RegisterFixed(uint32& registered)
|
||||
@ -828,18 +916,15 @@ device_node::_AlwaysRegisterDynamic()
|
||||
status_t
|
||||
device_node::_RegisterDynamic()
|
||||
{
|
||||
uint32 findFlags = 0;
|
||||
dm_get_attr_uint32(this, B_DEVICE_FIND_CHILD_FLAGS, &findFlags, false);
|
||||
|
||||
// If this is our initial registration, we honour the B_FIND_CHILD_ON_DEMAND
|
||||
// requirements
|
||||
if (!fRegistered && (findFlags & B_FIND_CHILD_ON_DEMAND) != 0
|
||||
if (!fRegistered && (fFlags & B_FIND_CHILD_ON_DEMAND) != 0
|
||||
&& !_AlwaysRegisterDynamic())
|
||||
return B_OK;
|
||||
|
||||
KPath path;
|
||||
|
||||
if ((findFlags & B_FIND_MULTIPLE_CHILDREN) == 0) {
|
||||
if ((fFlags & B_FIND_MULTIPLE_CHILDREN) == 0) {
|
||||
// find the one driver
|
||||
driver_module_info* bestDriver = NULL;
|
||||
float bestSupport = 0.0;
|
||||
@ -852,7 +937,16 @@ device_node::_RegisterDynamic()
|
||||
if (bestDriver != NULL) {
|
||||
TRACE((" register best module \"%s\", support %f\n",
|
||||
bestDriver->info.name, bestSupport));
|
||||
bestDriver->register_device(this);
|
||||
if (bestDriver->register_device(this) == B_OK) {
|
||||
// There can only be one node of this driver
|
||||
// (usually only one at all, but there might be a new driver
|
||||
// "waiting" for its turn)
|
||||
device_node* child = FindChild(bestDriver->info.name);
|
||||
if (child != NULL)
|
||||
child->fSupportsParent = bestSupport;
|
||||
// TODO: if this fails, we could try the second best driver,
|
||||
// and so on...
|
||||
}
|
||||
put_module(bestDriver->info.name);
|
||||
}
|
||||
} else {
|
||||
@ -878,11 +972,12 @@ device_node::_RemoveChildren()
|
||||
// this child is not used currently, and can be removed safely
|
||||
iterator.Remove();
|
||||
child->fParent = NULL;
|
||||
delete child;
|
||||
child->Release();
|
||||
|
||||
if (Release())
|
||||
panic("died early");
|
||||
} else
|
||||
child->fFlags |= NODE_FLAG_REMOVE_ON_UNINIT;
|
||||
child->Release();
|
||||
}
|
||||
|
||||
return fChildren.IsEmpty() ? B_OK : B_BUSY;
|
||||
@ -939,7 +1034,7 @@ device_node::Probe(const char* devicePath)
|
||||
NodeList::Iterator iterator = fChildren.GetIterator();
|
||||
while (iterator.HasNext()) {
|
||||
device_node* child = iterator.Next();
|
||||
|
||||
|
||||
status = child->Probe(devicePath);
|
||||
if (status != B_OK)
|
||||
return status;
|
||||
@ -949,42 +1044,57 @@ device_node::Probe(const char* devicePath)
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
device_node::_UninitUnusedChildren()
|
||||
/*! Uninitializes all temporary references to the driver. The registration
|
||||
process keeps the driver initialized to optimize the startup procedure;
|
||||
this function gives this reference away again.
|
||||
*/
|
||||
void
|
||||
device_node::UninitUnusedDriver()
|
||||
{
|
||||
// First, we need to go to the leaf, and go back from there
|
||||
|
||||
bool uninit = true;
|
||||
|
||||
NodeList::Iterator iterator = fChildren.GetIterator();
|
||||
|
||||
while (iterator.HasNext()) {
|
||||
device_node* child = iterator.Next();
|
||||
|
||||
if (!child->_UninitUnusedChildren())
|
||||
uninit = false;
|
||||
child->UninitUnusedDriver();
|
||||
}
|
||||
|
||||
// Not all of our children could be uninitialized
|
||||
if (!uninit)
|
||||
return false;
|
||||
if (!IsInitialized()
|
||||
|| (fFlags & NODE_FLAG_REGISTER_INITIALIZED) == 0)
|
||||
return;
|
||||
|
||||
if (!IsInitialized())
|
||||
return true;
|
||||
fFlags &= ~NODE_FLAG_REGISTER_INITIALIZED;
|
||||
|
||||
if ((DriverModule()->info.flags & B_KEEP_LOADED) != 0) {
|
||||
// We must not get unloaded
|
||||
return false;
|
||||
}
|
||||
|
||||
return UninitDriver();
|
||||
UninitDriver();
|
||||
}
|
||||
|
||||
|
||||
/*! Calls device_removed() on this node and all of its children - starting
|
||||
with the deepest and last child.
|
||||
It will also remove the one reference that every node gets on its creation.
|
||||
*/
|
||||
void
|
||||
device_node::UninitUnusedChildren()
|
||||
device_node::DeviceRemoved()
|
||||
{
|
||||
_UninitUnusedChildren();
|
||||
NodeList::ConstIterator iterator = Children().GetIterator();
|
||||
while (iterator.HasNext()) {
|
||||
device_node* child = iterator.Next();
|
||||
|
||||
child->DeviceRemoved();
|
||||
}
|
||||
|
||||
if (IsInitialized() && DriverModule()->device_removed != NULL)
|
||||
DriverModule()->device_removed(this);
|
||||
|
||||
if ((fFlags & B_KEEP_DRIVER_LOADED) != 0) {
|
||||
// There is no point in keeping this driver loaded when its device
|
||||
// is gone
|
||||
UninitDriver();
|
||||
}
|
||||
|
||||
UninitUnusedDriver();
|
||||
Release();
|
||||
}
|
||||
|
||||
|
||||
@ -1001,8 +1111,6 @@ device_node::Release()
|
||||
if (atomic_add(&fRefCount, -1) > 1)
|
||||
return false;
|
||||
|
||||
if (Parent() != NULL)
|
||||
Parent()->RemoveChild(this);
|
||||
delete this;
|
||||
return true;
|
||||
}
|
||||
@ -1054,6 +1162,24 @@ device_node::FindChild(const device_attr* attributes) const
|
||||
}
|
||||
|
||||
|
||||
device_node*
|
||||
device_node::FindChild(const char* moduleName) const
|
||||
{
|
||||
if (moduleName == NULL)
|
||||
return NULL;
|
||||
|
||||
NodeList::ConstIterator iterator = Children().GetIterator();
|
||||
while (iterator.HasNext()) {
|
||||
device_node* child = iterator.Next();
|
||||
|
||||
if (!strcmp(child->ModuleName(), moduleName))
|
||||
return child;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
device_node::Dump(int32 level = 0)
|
||||
{
|
||||
@ -1077,14 +1203,14 @@ device_node::Dump(int32 level = 0)
|
||||
|
||||
|
||||
static status_t
|
||||
rescan_device(device_node* node)
|
||||
rescan_node(device_node* node)
|
||||
{
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
register_device(device_node* parent, const char* moduleName,
|
||||
register_node(device_node* parent, const char* moduleName,
|
||||
const device_attr* attrs, const io_resource* ioResources,
|
||||
device_node** _node)
|
||||
{
|
||||
@ -1103,7 +1229,7 @@ register_device(device_node* parent, const char* moduleName,
|
||||
if (newNode == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
TRACE(("%p: register device \"%s\", parent %p\n", newNode, moduleName,
|
||||
TRACE(("%p: register node \"%s\", parent %p\n", newNode, moduleName,
|
||||
parent));
|
||||
|
||||
RecursiveLocker _(sLock);
|
||||
@ -1112,16 +1238,6 @@ register_device(device_node* parent, const char* moduleName,
|
||||
if (status != B_OK)
|
||||
goto err1;
|
||||
|
||||
// make it public
|
||||
if (parent != NULL)
|
||||
parent->AddChild(newNode);
|
||||
else
|
||||
sRootNode = newNode;
|
||||
|
||||
status = newNode->InitDriver();
|
||||
if (status != B_OK)
|
||||
goto err1;
|
||||
|
||||
#if 0
|
||||
// The following is done to reduce the stack usage of deeply nested
|
||||
// child device nodes.
|
||||
@ -1136,7 +1252,7 @@ register_device(device_node* parent, const char* moduleName,
|
||||
}
|
||||
#endif
|
||||
|
||||
status = newNode->Register();
|
||||
status = newNode->Register(parent);
|
||||
if (status < B_OK) {
|
||||
parent->RemoveChild(newNode);
|
||||
goto err1;
|
||||
@ -1148,15 +1264,27 @@ register_device(device_node* parent, const char* moduleName,
|
||||
return B_OK;
|
||||
|
||||
err1:
|
||||
delete newNode;
|
||||
newNode->Release();
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
unregister_device(device_node* node)
|
||||
unregister_node(device_node* node)
|
||||
{
|
||||
return B_ERROR;
|
||||
TRACE(("unregister_node(node %p)\n", node));
|
||||
RecursiveLocker _(sLock);
|
||||
|
||||
bool initialized = node->IsInitialized();
|
||||
|
||||
node->DeviceRemoved();
|
||||
|
||||
// TODO: We can't just remove it from its parent, as it might still be in
|
||||
// use. However, we shouldn't really fail in this case, either.
|
||||
// We should try to uninit the device - if it's just a bus, we can just do
|
||||
// this. If it has devfs device, there are several options on how to do
|
||||
// that (for example, by disconnecting the file descriptor).
|
||||
return initialized ? B_BUSY : B_OK;
|
||||
}
|
||||
|
||||
|
||||
@ -1176,7 +1304,7 @@ get_driver(device_node* node, driver_module_info** _module, void** _data)
|
||||
|
||||
|
||||
static device_node*
|
||||
get_device_root(void)
|
||||
get_root_node(void)
|
||||
{
|
||||
if (sRootNode != NULL)
|
||||
sRootNode->Acquire();
|
||||
@ -1186,15 +1314,48 @@ get_device_root(void)
|
||||
|
||||
|
||||
static status_t
|
||||
get_next_child_device(device_node* parent, device_node* _node,
|
||||
const device_attr* attrs)
|
||||
get_next_child_node(device_node* parent, const device_attr* attributes,
|
||||
device_node** _node)
|
||||
{
|
||||
return B_ERROR;
|
||||
RecursiveLocker _(sLock);
|
||||
|
||||
NodeList::ConstIterator iterator = parent->Children().GetIterator();
|
||||
device_node* last = *_node;
|
||||
|
||||
// skip those we already traversed
|
||||
while (iterator.HasNext() && last != NULL) {
|
||||
device_node* node = iterator.Next();
|
||||
|
||||
if (node != last)
|
||||
continue;
|
||||
}
|
||||
|
||||
// find the next one that fits
|
||||
while (iterator.HasNext()) {
|
||||
device_node* node = iterator.Next();
|
||||
|
||||
if (!node->IsRegistered())
|
||||
continue;
|
||||
|
||||
if (!node->CompareTo(attributes)) {
|
||||
if (last != NULL)
|
||||
last->Release();
|
||||
|
||||
node->Acquire();
|
||||
*_node = node;
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
if (last != NULL)
|
||||
last->Release();
|
||||
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
static device_node*
|
||||
get_parent(device_node* node)
|
||||
get_parent_node(device_node* node)
|
||||
{
|
||||
if (node == NULL)
|
||||
return NULL;
|
||||
@ -1209,13 +1370,50 @@ get_parent(device_node* node)
|
||||
|
||||
|
||||
static void
|
||||
put_device_node(device_node* node)
|
||||
put_node(device_node* node)
|
||||
{
|
||||
RecursiveLocker _(sLock);
|
||||
node->Release();
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
publish_device(device_node *node, const char *path, const char *moduleName)
|
||||
{
|
||||
RecursiveLocker _(sLock);
|
||||
dprintf("publish device: node %p, path %s, module %s\n", node, path,
|
||||
moduleName);
|
||||
|
||||
struct device* device = new(std::nothrow) ::device;
|
||||
if (device == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
device->node = node;
|
||||
device->path = strdup(path);
|
||||
device->module_name = strdup(moduleName);
|
||||
|
||||
sDeviceList.Add(device);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
static status_t
|
||||
unpublish_device(device_node *node, const char *path)
|
||||
{
|
||||
DeviceList::Iterator iterator = sDeviceList.GetIterator();
|
||||
while (iterator.HasNext()) {
|
||||
struct device* device = iterator.Next();
|
||||
if (!strcmp(device->path, path)) {
|
||||
iterator.Remove();
|
||||
delete device;
|
||||
return B_OK;
|
||||
}
|
||||
}
|
||||
|
||||
return B_ENTRY_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
dm_get_attr_uint8(const device_node* node, const char* name, uint8* _value,
|
||||
bool recursive)
|
||||
@ -1351,14 +1549,18 @@ static struct device_manager_info sDeviceManagerModule = {
|
||||
},
|
||||
|
||||
// device nodes
|
||||
rescan_device,
|
||||
register_device,
|
||||
unregister_device,
|
||||
rescan_node,
|
||||
register_node,
|
||||
unregister_node,
|
||||
get_driver,
|
||||
get_device_root,
|
||||
get_next_child_device,
|
||||
get_parent,
|
||||
put_device_node,
|
||||
get_root_node,
|
||||
get_next_child_node,
|
||||
get_parent_node,
|
||||
put_node,
|
||||
|
||||
// devices
|
||||
publish_device,
|
||||
unpublish_device,
|
||||
|
||||
// attributes
|
||||
dm_get_attr_uint8,
|
||||
@ -1380,12 +1582,12 @@ dm_init_root_node(void)
|
||||
device_attr attrs[] = {
|
||||
{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Devices Root"}},
|
||||
{B_DEVICE_BUS, B_STRING_TYPE, {string: "root"}},
|
||||
{B_DEVICE_FIND_CHILD_FLAGS, B_UINT32_TYPE,
|
||||
{ui32: B_FIND_MULTIPLE_CHILDREN}},
|
||||
{B_DEVICE_FLAGS, B_UINT32_TYPE,
|
||||
{ui32: B_FIND_MULTIPLE_CHILDREN | B_KEEP_DRIVER_LOADED }},
|
||||
{NULL}
|
||||
};
|
||||
|
||||
if (register_device(NULL, DEVICE_MANAGER_ROOT_NAME, attrs, NULL, NULL)
|
||||
if (register_node(NULL, DEVICE_MANAGER_ROOT_NAME, attrs, NULL, NULL)
|
||||
!= B_OK) {
|
||||
dprintf("Cannot register Devices Root Node\n");
|
||||
}
|
||||
@ -1439,12 +1641,19 @@ main(int argc, char** argv)
|
||||
|
||||
probe_path("net");
|
||||
probe_path("graphics");
|
||||
// TODO: opened devices need to keep a "initialized" reference of the
|
||||
// device_node
|
||||
|
||||
sRootNode->Dump();
|
||||
void* graphicsHandle = open_path("graphics/generic/0");
|
||||
// void* netHandle = open_path("net/sample/0");
|
||||
|
||||
uninit_unused();
|
||||
|
||||
puts("remove net driver");
|
||||
device_node* busNode = sRootNode->FindChild(BUS_MODULE_NAME);
|
||||
bus_trigger_device_removed(busNode);
|
||||
|
||||
close_path(graphicsHandle);
|
||||
// close_path(netHandle);
|
||||
|
||||
// add specific video driver - ie. simulate installing it
|
||||
_add_builtin_module((module_info*)&gSpecificVideoDriverModuleInfo);
|
||||
_add_builtin_module((module_info*)&gSpecificVideoDeviceModuleInfo);
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include <module.h>
|
||||
|
||||
|
||||
// type of I/O resource
|
||||
/* type of I/O resource */
|
||||
enum {
|
||||
IO_MEM = 1,
|
||||
IO_PORT = 2,
|
||||
@ -19,33 +19,35 @@ enum {
|
||||
};
|
||||
|
||||
|
||||
// I/O resource description
|
||||
/* I/O resource description */
|
||||
typedef struct {
|
||||
uint32 type;
|
||||
// type of I/O resource
|
||||
/* type of I/O resource */
|
||||
|
||||
uint32 base;
|
||||
// I/O memory: first physical address (32 bit)
|
||||
// I/O port: first port address (16 bit)
|
||||
// ISA DMA channel: channel number (0-7)
|
||||
/* I/O memory: first physical address (32 bit)
|
||||
* I/O port: first port address (16 bit)
|
||||
* ISA DMA channel: channel number (0-7)
|
||||
*/
|
||||
|
||||
uint32 length;
|
||||
// I/O memory: size of address range (32 bit)
|
||||
// I/O port: size of port range (16 bit)
|
||||
// ISA DMA channel: must be 1
|
||||
/* I/O memory: size of address range (32 bit)
|
||||
* I/O port: size of port range (16 bit)
|
||||
* ISA DMA channel: must be 1
|
||||
*/
|
||||
} io_resource;
|
||||
|
||||
// attribute of a device node
|
||||
/* attribute of a device node */
|
||||
typedef struct {
|
||||
const char *name;
|
||||
type_code type; // for supported types, see value
|
||||
type_code type; /* for supported types, see value */
|
||||
union {
|
||||
uint8 ui8; // B_UINT8_TYPE
|
||||
uint16 ui16; // B_UINT16_TYPE
|
||||
uint32 ui32; // B_UINT32_TYPE
|
||||
uint64 ui64; // B_UINT64_TYPE
|
||||
const char *string; // B_STRING_TYPE
|
||||
struct { // B_RAW_TYPE
|
||||
uint8 ui8; /* B_UINT8_TYPE */
|
||||
uint16 ui16; /* B_UINT16_TYPE */
|
||||
uint32 ui32; /* B_UINT32_TYPE */
|
||||
uint64 ui64; /* B_UINT64_TYPE */
|
||||
const char *string; /* B_STRING_TYPE */
|
||||
struct { /* B_RAW_TYPE */
|
||||
const void *data;
|
||||
size_t length;
|
||||
} raw;
|
||||
@ -57,26 +59,30 @@ typedef struct device_node device_node;
|
||||
typedef struct driver_module_info driver_module_info;
|
||||
|
||||
|
||||
// interface of the device manager
|
||||
/* interface of the device manager */
|
||||
|
||||
typedef struct device_manager_info {
|
||||
module_info info;
|
||||
|
||||
status_t (*rescan)(device_node *node);
|
||||
status_t (*rescan_node)(device_node *node);
|
||||
|
||||
status_t (*register_device)(device_node *parent, const char *moduleName,
|
||||
status_t (*register_node)(device_node *parent, const char *moduleName,
|
||||
const device_attr *attrs, const io_resource *ioResources,
|
||||
device_node **_node);
|
||||
status_t (*unregister_device)(device_node *node);
|
||||
status_t (*unregister_node)(device_node *node);
|
||||
|
||||
status_t (*get_driver)(device_node *node, driver_module_info **_module,
|
||||
void **_cookie);
|
||||
|
||||
device_node *(*get_root_device)();
|
||||
status_t (*get_next_child_device)(device_node *parent, device_node *node,
|
||||
const device_attr *attrs);
|
||||
device_node *(*get_parent)(device_node *node);
|
||||
void (*put_device_node)(device_node *node);
|
||||
device_node *(*get_root_node)();
|
||||
status_t (*get_next_child_node)(device_node *parent,
|
||||
const device_attr *attrs, device_node **node);
|
||||
device_node *(*get_parent_node)(device_node *node);
|
||||
void (*put_node)(device_node *node);
|
||||
|
||||
status_t (*publish_device)(device_node *node, const char *path,
|
||||
const char *deviceModuleName);
|
||||
status_t (*unpublish_device)(device_node *node, const char *path);
|
||||
|
||||
#if 0
|
||||
status_t (*acquire_io_resources)(io_resource *resources);
|
||||
@ -106,7 +112,7 @@ typedef struct device_manager_info {
|
||||
#define B_DEVICE_MANAGER_MODULE_NAME "system/device_manager/v1"
|
||||
|
||||
|
||||
// interface of device driver
|
||||
/* interface of device driver */
|
||||
|
||||
struct driver_module_info {
|
||||
module_info info;
|
||||
@ -128,7 +134,7 @@ struct driver_module_info {
|
||||
#define B_DEVICE_MAPPING "device/mapping" /* string */
|
||||
#define B_DEVICE_BUS "device/bus" /* string */
|
||||
#define B_DEVICE_FIXED_CHILD "device/fixed child" /* string */
|
||||
#define B_DEVICE_FIND_CHILD_FLAGS "device/find child flags" /* uint32 */
|
||||
#define B_DEVICE_FLAGS "device/flags" /* uint32 */
|
||||
|
||||
#define B_DEVICE_VENDOR_ID "device/vendor" /* uint16 */
|
||||
#define B_DEVICE_ID "device/id" /* uint16 */
|
||||
@ -141,20 +147,21 @@ struct driver_module_info {
|
||||
|
||||
#define B_DEVICE_UNIQUE_ID "device/unique id" /* string */
|
||||
|
||||
// find child flags
|
||||
/* device flags */
|
||||
#define B_FIND_CHILD_ON_DEMAND 0x01
|
||||
#define B_FIND_MULTIPLE_CHILDREN 0x02
|
||||
#define B_KEEP_DRIVER_LOADED 0x04
|
||||
|
||||
|
||||
// interface of device
|
||||
/* interface of device */
|
||||
|
||||
typedef struct io_request io_request;
|
||||
|
||||
struct device_module_info {
|
||||
module_info info;
|
||||
|
||||
status_t (*init_device)(void *cookie);
|
||||
void (*uninit_device)(void *cookie);
|
||||
status_t (*init_device)(device_node *node, void **_deviceCookie);
|
||||
void (*uninit_device)(void *deviceCookie);
|
||||
|
||||
status_t (*device_open)(void *deviceCookie, int openMode, void **_cookie);
|
||||
status_t (*device_close)(void *cookie);
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
|
||||
#define DRIVER_MODULE_NAME "drivers/net/sample_driver/driver_v1"
|
||||
#define DRIVER_DEVICE_MODULE_NAME "drivers/net/sample_driver/device_v1"
|
||||
|
||||
|
||||
// #pragma mark - driver
|
||||
@ -48,7 +49,7 @@ supports_device(device_node *parent)
|
||||
static status_t
|
||||
register_device(device_node *parent)
|
||||
{
|
||||
return gDeviceManager->register_device(parent, DRIVER_MODULE_NAME, NULL,
|
||||
return gDeviceManager->register_node(parent, DRIVER_MODULE_NAME, NULL,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
@ -56,7 +57,6 @@ register_device(device_node *parent)
|
||||
static status_t
|
||||
init_driver(device_node *node, void **_cookie)
|
||||
{
|
||||
// also publishes any devices/nodes with dedicated calls
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -70,6 +70,8 @@ uninit_driver(device_node *node)
|
||||
static status_t
|
||||
register_child_devices(device_node *node)
|
||||
{
|
||||
gDeviceManager->publish_device(node, "net/sample/0",
|
||||
DRIVER_DEVICE_MODULE_NAME);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -84,7 +86,7 @@ device_removed(device_node *node)
|
||||
|
||||
|
||||
static status_t
|
||||
init_device(void *deviceCookie)
|
||||
init_device(device_node *node, void **_deviceCookie)
|
||||
{
|
||||
// called once before one or several open() calls
|
||||
return B_ERROR;
|
||||
@ -171,7 +173,7 @@ struct driver_module_info gDriverModuleInfo = {
|
||||
|
||||
struct device_module_info gDeviceModuleInfo = {
|
||||
{
|
||||
"drivers/net/sample_driver/device_v1",
|
||||
DRIVER_DEVICE_MODULE_NAME,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
|
||||
#define DRIVER_MODULE_NAME "drivers/graphics/generic_driver/driver_v1"
|
||||
#define DRIVER_DEVICE_MODULE_NAME "drivers/graphics/generic_driver/device_v1"
|
||||
|
||||
|
||||
// #pragma mark - driver
|
||||
@ -41,7 +42,7 @@ supports_device(device_node *parent)
|
||||
static status_t
|
||||
register_device(device_node *parent)
|
||||
{
|
||||
return gDeviceManager->register_device(parent, DRIVER_MODULE_NAME, NULL,
|
||||
return gDeviceManager->register_node(parent, DRIVER_MODULE_NAME, NULL,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
@ -49,7 +50,6 @@ register_device(device_node *parent)
|
||||
static status_t
|
||||
init_driver(device_node *node, void **_cookie)
|
||||
{
|
||||
// also publishes any devices/nodes with dedicated calls
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -63,6 +63,8 @@ uninit_driver(device_node *node)
|
||||
static status_t
|
||||
register_child_devices(device_node *node)
|
||||
{
|
||||
gDeviceManager->publish_device(node, "graphics/generic/0",
|
||||
DRIVER_DEVICE_MODULE_NAME);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -77,7 +79,7 @@ device_removed(device_node *node)
|
||||
|
||||
|
||||
static status_t
|
||||
init_device(void *deviceCookie)
|
||||
init_device(device_node *node, void **_deviceCookie)
|
||||
{
|
||||
// called once before one or several open() calls
|
||||
return B_ERROR;
|
||||
@ -164,7 +166,7 @@ struct driver_module_info gGenericVideoDriverModuleInfo = {
|
||||
|
||||
struct device_module_info gGenericVideoDeviceModuleInfo = {
|
||||
{
|
||||
"drivers/graphics/generic_driver/device_v1",
|
||||
DRIVER_DEVICE_MODULE_NAME,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
|
||||
#define DRIVER_MODULE_NAME "drivers/graphics/specific_driver/driver_v1"
|
||||
#define DRIVER_DEVICE_MODULE_NAME "drivers/graphics/specific_driver/device_v1"
|
||||
|
||||
|
||||
// #pragma mark - driver
|
||||
@ -39,7 +40,7 @@ supports_device(device_node *parent)
|
||||
static status_t
|
||||
register_device(device_node *parent)
|
||||
{
|
||||
return gDeviceManager->register_device(parent, DRIVER_MODULE_NAME, NULL,
|
||||
return gDeviceManager->register_node(parent, DRIVER_MODULE_NAME, NULL,
|
||||
NULL, NULL);
|
||||
}
|
||||
|
||||
@ -47,7 +48,6 @@ register_device(device_node *parent)
|
||||
static status_t
|
||||
init_driver(device_node *node, void **_cookie)
|
||||
{
|
||||
// also publishes any devices/nodes with dedicated calls
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -61,6 +61,8 @@ uninit_driver(device_node *node)
|
||||
static status_t
|
||||
register_child_devices(device_node *node)
|
||||
{
|
||||
gDeviceManager->publish_device(node, "graphics/specific/0",
|
||||
DRIVER_DEVICE_MODULE_NAME);
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -75,7 +77,7 @@ device_removed(device_node *node)
|
||||
|
||||
|
||||
static status_t
|
||||
init_device(void *deviceCookie)
|
||||
init_device(device_node *node, void **_deviceCookie)
|
||||
{
|
||||
// called once before one or several open() calls
|
||||
return B_ERROR;
|
||||
@ -162,7 +164,7 @@ struct driver_module_info gSpecificVideoDriverModuleInfo = {
|
||||
|
||||
struct device_module_info gSpecificVideoDeviceModuleInfo = {
|
||||
{
|
||||
"drivers/graphics/specific_driver/device_v1",
|
||||
DRIVER_DEVICE_MODULE_NAME,
|
||||
0,
|
||||
NULL,
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user