* Work in progress: driver loading triggered by devfs.

* get_driver() now returns a result, as you may theoretically call it on
  any node (and not just your parent, which is guaranteed to be there).


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25406 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2008-05-09 22:05:50 +00:00
parent 4b48c06f26
commit 078d0317d0
2 changed files with 178 additions and 10 deletions

View File

@ -96,7 +96,7 @@ struct device_node : DoublyLinkedListLinkImpl<device_node> {
const AttributeList& Attributes() const { return fAttributes; } const AttributeList& Attributes() const { return fAttributes; }
status_t InitDriver(); status_t InitDriver();
void UninitDriver(); bool UninitDriver();
// The following two are only valid, if the node's driver is // The following two are only valid, if the node's driver is
// initialized // initialized
@ -106,9 +106,12 @@ struct device_node : DoublyLinkedListLinkImpl<device_node> {
void AddChild(device_node *node); void AddChild(device_node *node);
void RemoveChild(device_node *node); void RemoveChild(device_node *node);
const NodeList& Children() const { return fChildren; } const NodeList& Children() const { return fChildren; }
void UninitUnusedChildren();
status_t Register(); status_t Register();
status_t Probe(const char* devicePath);
bool IsRegistered() const { return fRegistered; } bool IsRegistered() const { return fRegistered; }
bool IsInitialized() const { return fInitialized > 0; }
private: private:
status_t _RegisterFixed(uint32& registered); status_t _RegisterFixed(uint32& registered);
@ -123,12 +126,15 @@ private:
float& bestSupport); float& bestSupport);
status_t _RegisterPath(const char* path); status_t _RegisterPath(const char* path);
status_t _RegisterDynamic(); status_t _RegisterDynamic();
status_t _RemoveChildren();
bool _UninitUnusedChildren();
device_node* fParent; device_node* fParent;
NodeList fChildren; NodeList fChildren;
int32 fRefCount; int32 fRefCount;
int32 fInitialized; int32 fInitialized;
bool fRegistered; bool fRegistered;
uint32 fFlags;
const char* fModuleName; const char* fModuleName;
driver_module_info* fDriver; driver_module_info* fDriver;
@ -137,9 +143,14 @@ private:
AttributeList fAttributes; AttributeList fAttributes;
}; };
enum node_flags {
NODE_FLAG_REMOVE_ON_UNINIT = 0x01
};
device_manager_info *gDeviceManager; device_manager_info *gDeviceManager;
static device_node *sRootNode; static device_node *sRootNode;
static recursive_lock sLock;
// #pragma mark - device_attr // #pragma mark - device_attr
@ -371,6 +382,22 @@ dm_dump_node(device_node* node, int32 level)
} }
static void
uninit_unused()
{
RecursiveLocker _(sLock);
sRootNode->UninitUnusedChildren();
}
static status_t
probe_path(const char* path)
{
RecursiveLocker _(sLock);
return sRootNode->Probe(path);
}
// #pragma mark - device_node // #pragma mark - device_node
@ -407,12 +434,22 @@ device_node::device_node(const char* moduleName, const device_attr* attrs,
device_node::~device_node() device_node::~device_node()
{ {
AttributeList::Iterator iterator = fAttributes.GetIterator(); // Delete children
while (iterator.HasNext()) { NodeList::Iterator nodeIterator = fChildren.GetIterator();
device_attr_private* attr = iterator.Next(); while (nodeIterator.HasNext()) {
iterator.Remove(); device_node* child = nodeIterator.Next();
nodeIterator.Remove();
delete child;
}
// Delete attributes
AttributeList::Iterator attrIterator = fAttributes.GetIterator();
while (attrIterator.HasNext()) {
device_attr_private* attr = attrIterator.Next();
attrIterator.Remove();
delete attr; delete attr;
} }
free((char*)fModuleName); free((char*)fModuleName);
} }
@ -448,17 +485,24 @@ device_node::InitDriver()
} }
void bool
device_node::UninitDriver() device_node::UninitDriver()
{ {
if (fInitialized-- > 1) if (fInitialized-- > 1)
return; return false;
if (fDriver->uninit_driver != NULL) if (fDriver->uninit_driver != NULL)
fDriver->uninit_driver(this); fDriver->uninit_driver(this);
fDriver = NULL;
fDriverData = NULL; fDriverData = NULL;
put_module(ModuleName()); put_module(ModuleName());
if ((fFlags & NODE_FLAG_REMOVE_ON_UNINIT) != 0)
delete this;
return true;
} }
@ -807,7 +851,118 @@ printf(" register best module \"%s\", support %f\n", bestDriver->info.name, bes
} }
// #pragma mark - status_t
device_node::_RemoveChildren()
{
NodeList::Iterator iterator = fChildren.GetIterator();
while (iterator.HasNext()) {
device_node* child = iterator.Next();
if (!child->IsInitialized()) {
// this child is not used currently, and can be removed safely
iterator.Remove();
fRefCount--;
child->fParent = NULL;
delete child;
} else
child->fFlags |= NODE_FLAG_REMOVE_ON_UNINIT;
}
return fChildren.IsEmpty() ? B_OK : B_BUSY;
}
status_t
device_node::Probe(const char* devicePath)
{
uint16 type = 0;
uint16 subType = 0;
if (dm_get_attr_uint16(this, B_DEVICE_TYPE, &type, false) == B_OK
&& dm_get_attr_uint16(this, B_DEVICE_SUB_TYPE, &subType, false)
== B_OK) {
// Check if this node matches the device path
// TODO: maybe make this extendible via settings file?
bool matches = false;
if (!strcmp(devicePath, "disk")) {
matches = type == PCI_mass_storage;
} else if (!strcmp(devicePath, "audio")) {
matches = type == PCI_multimedia
&& (subType == PCI_audio || subType == PCI_hd_audio);
} else if (!strcmp(devicePath, "net")) {
matches = type == PCI_network;
} else if (!strcmp(devicePath, "graphics")) {
matches = type == PCI_display;
} else if (!strcmp(devicePath, "video")) {
matches = type == PCI_multimedia && subType == PCI_video;
}
if (matches) {
if (!fChildren.IsEmpty()) {
// We already have a driver that claims this node.
// Try to remove uninitialized children, so that this node
// can be re-evaluated
// TODO: try first if there is a better child!
// TODO: publish both devices, make new one busy as long
// as the old one is in use!
if (_RemoveChildren() != B_OK)
return B_OK;
}
return _RegisterDynamic();
}
return B_OK;
}
NodeList::Iterator iterator = fChildren.GetIterator();
while (iterator.HasNext()) {
device_node* child = iterator.Next();
status_t status = child->Probe(devicePath);
if (status != B_OK)
return status;
}
return B_OK;
}
bool
device_node::_UninitUnusedChildren()
{
// 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;
}
// Not all of our children could be uninitialized
if (!uninit)
return false;
if (!IsInitialized())
return true;
if ((DriverModule()->info.flags & B_KEEP_LOADED) != 0) {
// We must not get unloaded
return false;
}
return UninitDriver();
}
void
device_node::UninitUnusedChildren()
{
_UninitUnusedChildren();
}
// #pragma mark - Device Manager module API // #pragma mark - Device Manager module API
@ -838,6 +993,8 @@ register_device(device_node* parent, const char* moduleName,
TRACE(("%p: register device \"%s\", parent %p\n", newNode, moduleName, TRACE(("%p: register device \"%s\", parent %p\n", newNode, moduleName,
parent)); parent));
RecursiveLocker _(sLock);
status_t status = newNode->InitCheck(); status_t status = newNode->InitCheck();
if (status != B_OK) if (status != B_OK)
goto err1; goto err1;
@ -890,13 +1047,18 @@ unregister_device(device_node* node)
} }
static void static status_t
get_driver(device_node* node, driver_module_info** _module, void** _data) get_driver(device_node* node, driver_module_info** _module, void** _data)
{ {
if (node->DriverModule() == NULL)
return B_NO_INIT;
if (_module != NULL) if (_module != NULL)
*_module = node->DriverModule(); *_module = node->DriverModule();
if (_data != NULL) if (_data != NULL)
*_data = node->DriverData(); *_data = node->DriverData();
return B_OK;
} }
@ -1136,8 +1298,14 @@ main(int argc, char** argv)
return 1; return 1;
} }
recursive_lock_init(&sLock, "device manager");
dm_init_root_node(); dm_init_root_node();
dm_dump_node(sRootNode, 0); dm_dump_node(sRootNode, 0);
probe_path("net");
uninit_unused();
recursive_lock_destroy(&sLock);
return 0; return 0;
} }

View File

@ -69,7 +69,7 @@ typedef struct device_manager_info {
device_node **_node); device_node **_node);
status_t (*unregister_device)(device_node *node); status_t (*unregister_device)(device_node *node);
void (*get_driver)(device_node *node, driver_module_info **_module, status_t (*get_driver)(device_node *node, driver_module_info **_module,
void **_cookie); void **_cookie);
device_node *(*root_device)(); device_node *(*root_device)();