dev: implement driver objects to organise and identify devices
This commit is contained in:
90
dev/core.c
90
dev/core.c
@@ -1,6 +1,7 @@
|
||||
#include <socks/status.h>
|
||||
#include <socks/object.h>
|
||||
#include <socks/device.h>
|
||||
#include <socks/bitmap.h>
|
||||
#include <socks/libc/stdio.h>
|
||||
|
||||
#define DEVICE_CAST(p) OBJECT_C_CAST(struct device, dev_base, &device_type, p)
|
||||
@@ -15,6 +16,8 @@ static kern_status_t device_object_query_name(struct object *, char out[OBJECT_N
|
||||
static kern_status_t device_object_get_child_at(struct object *, size_t, struct object **);
|
||||
static kern_status_t device_object_get_child_named(struct object *, const char *, struct object **);
|
||||
|
||||
extern kern_status_t init_driver_tree(void);
|
||||
|
||||
static struct object_type device_type = {
|
||||
.ob_name = "device",
|
||||
.ob_size = sizeof(struct device),
|
||||
@@ -42,36 +45,31 @@ static kern_status_t set_root_device(struct device *dev)
|
||||
return KERN_OK;
|
||||
}
|
||||
|
||||
static kern_status_t device_generate_name(struct device *dev)
|
||||
{
|
||||
switch (dev->dev_type) {
|
||||
case DEV_TYPE_INPUT:
|
||||
return input_device_generate_name(&dev->input);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return KERN_UNSUPPORTED;
|
||||
}
|
||||
|
||||
kern_status_t device_init(void)
|
||||
{
|
||||
object_type_register(&device_type);
|
||||
dev_folder = set_create("dev");
|
||||
object_publish(global_namespace(), "/", dev_folder);
|
||||
|
||||
kern_status_t status = init_driver_tree();
|
||||
if (status != KERN_OK) {
|
||||
return status;
|
||||
}
|
||||
|
||||
struct bus_device *system_dev = bus_device_create();
|
||||
struct device *system_dev_base = bus_device_base(system_dev);
|
||||
snprintf(system_dev_base->dev_name, sizeof system_dev_base->dev_name, "system");
|
||||
|
||||
set_root_device(system_dev_base);
|
||||
__root_device = bus_device_base(system_dev);
|
||||
|
||||
struct bus_device *misc_dev = bus_device_create();
|
||||
struct device *misc_dev_base = bus_device_base(misc_dev);
|
||||
snprintf(misc_dev_base->dev_name, sizeof misc_dev_base->dev_name, "misc");
|
||||
__misc_device = misc_dev_base;
|
||||
|
||||
device_register(__misc_device, __root_device);
|
||||
struct driver *system = system_driver();
|
||||
|
||||
device_register(__root_device, system, NULL);
|
||||
device_register(__misc_device, system, __root_device);
|
||||
|
||||
return KERN_OK;
|
||||
}
|
||||
@@ -179,23 +177,11 @@ static kern_status_t device_object_get_child_named(struct object *obj, const cha
|
||||
return KERN_NO_ENTRY;
|
||||
}
|
||||
|
||||
kern_status_t device_register(struct device *dev, struct device *parent)
|
||||
static kern_status_t add_device_to_parent(struct device *dev, struct device *parent)
|
||||
{
|
||||
unsigned long flags;
|
||||
device_lock_irqsave(dev, &flags);
|
||||
|
||||
kern_status_t status = KERN_OK;
|
||||
|
||||
if (dev->dev_name[0] == 0) {
|
||||
status = device_generate_name(dev);
|
||||
}
|
||||
|
||||
if (status != KERN_OK) {
|
||||
device_unlock_irqrestore(dev, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
queue_foreach (struct device, child, &dev->dev_children, dev_childent) {
|
||||
queue_foreach (struct device, child, &parent->dev_children, dev_childent) {
|
||||
if (!strcmp(dev->dev_name, child->dev_name)) {
|
||||
status = KERN_NAME_EXISTS;
|
||||
break;
|
||||
@@ -203,12 +189,56 @@ kern_status_t device_register(struct device *dev, struct device *parent)
|
||||
}
|
||||
|
||||
if (status != KERN_OK) {
|
||||
device_unlock_irqrestore(dev, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
queue_push_back(&parent->dev_children, &dev->dev_childent);
|
||||
|
||||
return KERN_OK;
|
||||
}
|
||||
|
||||
kern_status_t device_register(struct device *dev, struct driver *owner, struct device *parent)
|
||||
{
|
||||
unsigned long flags;
|
||||
device_lock_irqsave(dev, &flags);
|
||||
driver_lock(owner);
|
||||
|
||||
unsigned int minor = driver_alloc_minor(owner);
|
||||
|
||||
if (minor == DEV_MINOR_INVALID) {
|
||||
driver_unlock(owner);
|
||||
device_unlock_irqrestore(dev, flags);
|
||||
/* TODO better error message for lack of resources? */
|
||||
return KERN_BUSY;
|
||||
}
|
||||
|
||||
kern_status_t status = KERN_OK;
|
||||
if (parent) {
|
||||
status = add_device_to_parent(dev, parent);
|
||||
}
|
||||
|
||||
if (status != KERN_OK) {
|
||||
driver_unlock(owner);
|
||||
device_unlock_irqrestore(dev, flags);
|
||||
return status;
|
||||
}
|
||||
|
||||
dev->dev_minor = minor;
|
||||
dev->dev_owner = owner;
|
||||
|
||||
driver_add_device(owner, dev);
|
||||
|
||||
switch (dev->dev_type) {
|
||||
case DEV_TYPE_INPUT:
|
||||
status = input_device_register(INPUT_DEVICE(dev));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
driver_unlock(owner);
|
||||
device_unlock_irqrestore(dev, flags);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user