dev: implement driver objects to organise and identify devices

This commit is contained in:
2023-06-02 19:35:07 +01:00
parent 577abf3bba
commit b7b0691b8f
17 changed files with 349 additions and 74 deletions

View File

@@ -8,5 +8,6 @@ struct block_device *block_device_create(void)
}
dev->dev_type = DEV_TYPE_BLOCK;
return BLOCK_DEVICE(dev);
}

View File

@@ -8,5 +8,6 @@ struct bus_device *bus_device_create(void)
}
dev->dev_type = DEV_TYPE_BUS;
return BUS_DEVICE(dev);
}

View File

@@ -8,5 +8,6 @@ struct char_device *char_device_create(void)
}
dev->dev_type = DEV_TYPE_CHAR;
return CHAR_DEVICE(dev);
}

View File

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

146
dev/driver.c Normal file
View File

@@ -0,0 +1,146 @@
#include <socks/device.h>
#include <socks/bitmap.h>
#include <socks/btree.h>
#include <socks/kext.h>
#include <socks/vm.h>
static struct vm_cache driver_cache = {
.c_name = "driver",
.c_obj_size = sizeof(struct driver),
};
static DECLARE_BITMAP(major_numbers, DEV_MAJOR_MAX);
static struct btree drivers;
static spin_lock_t drivers_lock = SPIN_LOCK_INIT;
static struct driver *__system_driver;
BTREE_DEFINE_SIMPLE_INSERT(struct driver, drv_ent, drv_major, put_driver)
BTREE_DEFINE_SIMPLE_GET(struct driver, unsigned int, drv_ent, drv_major, get_driver_by_major)
BTREE_DEFINE_SIMPLE_INSERT(struct device, dev_driverent, dev_minor, put_device)
BTREE_DEFINE_SIMPLE_GET(struct device, unsigned int, dev_driverent, dev_minor, get_device_by_minor)
kern_status_t init_driver_tree(void)
{
vm_cache_init(&driver_cache);
bitmap_set(major_numbers, 0);
__system_driver = driver_create(kernel_kext(), "system");
driver_register(__system_driver);
return KERN_OK;
}
struct driver *driver_create(struct kext *self, const char *name)
{
if (!self || !name) {
return NULL;
}
struct driver *driver = vm_cache_alloc(&driver_cache, 0);
if (!driver) {
return NULL;
}
driver->drv_owner = self;
strncpy(driver->drv_name, name, sizeof driver->drv_name - 1);
driver->drv_name[sizeof driver->drv_name - 1] = 0;
bitmap_set(driver->drv_minors, DEV_MINOR_INVALID);
return driver;
}
kern_status_t driver_destroy(struct driver *driver)
{
if (btree_first(&driver->drv_children)) {
return KERN_BUSY;
}
return KERN_UNIMPLEMENTED;
}
kern_status_t driver_register(struct driver *driver)
{
if (driver->drv_major != DEV_MAJOR_INVALID) {
return KERN_INVALID_ARGUMENT;
}
unsigned long flags;
spin_lock_irqsave(&drivers_lock, &flags);
struct btree_node *cur = btree_first(&drivers);
while (cur) {
struct driver *cur_driver = BTREE_CONTAINER(struct driver, drv_ent, cur);
if (driver->drv_owner == cur_driver->drv_owner && !strcmp(driver->drv_name, cur_driver->drv_name)) {
spin_unlock_irqrestore(&drivers_lock, flags);
return KERN_NAME_EXISTS;
}
cur = btree_next(cur);
}
unsigned long major = bitmap_lowest_clear(major_numbers, DEV_MAJOR_MAX);
bitmap_set(major_numbers, major);
driver->drv_major = major;
put_driver(&drivers, driver);
spin_unlock_irqrestore(&drivers_lock, flags);
return KERN_UNIMPLEMENTED;
}
kern_status_t driver_unregister(struct driver *driver)
{
if (driver->drv_major == DEV_MAJOR_INVALID) {
return KERN_INVALID_ARGUMENT;
}
unsigned long flags;
spin_lock_irqsave(&drivers_lock, &flags);
btree_delete(&drivers, &driver->drv_ent);
bitmap_clear(major_numbers, driver->drv_major);
driver->drv_major = DEV_MAJOR_INVALID;
spin_unlock_irqrestore(&drivers_lock, flags);
return KERN_OK;
}
unsigned int driver_alloc_minor(struct driver *driver)
{
unsigned int minor = bitmap_lowest_clear(driver->drv_minors, DEV_MINOR_MAX);
if (minor == BITMAP_NPOS) {
return DEV_MINOR_INVALID;
}
bitmap_set(driver->drv_minors, minor);
return minor;
}
void driver_free_minor(struct driver *driver, unsigned int minor)
{
bitmap_clear(driver->drv_minors, minor);
}
struct driver *system_driver(void)
{
return __system_driver;
}
struct device *driver_get_device(struct driver *driver, unsigned int minor)
{
return get_device_by_minor(&driver->drv_children, minor);
}
kern_status_t driver_add_device(struct driver *driver, struct device *dev)
{
if (get_device_by_minor(&driver->drv_children, dev->dev_minor)) {
return KERN_NAME_EXISTS;
}
put_device(&driver->drv_children, dev);
return KERN_OK;
}

View File

@@ -21,14 +21,6 @@ struct input_device *input_device_create(void)
return NULL;
}
unsigned long flags;
spin_lock_irqsave(&input_device_ids_lock, &flags);
unsigned int id = bitmap_lowest_clear(input_device_ids, INPUT_DEVICE_MAX);
bitmap_set(input_device_ids, id);
spin_unlock_irqrestore(&input_device_ids_lock, flags);
input_dev->i_id = id;
return INPUT_DEVICE(dev);
}
@@ -63,9 +55,27 @@ kern_status_t input_device_read(struct device *dev, void *buf, size_t size, size
return KERN_OK;
}
kern_status_t input_device_generate_name(struct input_device *dev)
static kern_status_t generate_name(struct input_device *dev, char out[DEV_NAME_MAX])
{
struct device *d = input_device_base(dev);
snprintf(d->dev_name, sizeof d->dev_name, "input%u", dev->i_id);
snprintf(out, DEV_NAME_MAX, "input%u", dev->i_id);
return KERN_OK;
}
kern_status_t input_device_register(struct input_device *dev)
{
unsigned long flags;
spin_lock_irqsave(&input_device_ids_lock, &flags);
unsigned int id = bitmap_lowest_clear(input_device_ids, INPUT_DEVICE_MAX);
bitmap_set(input_device_ids, id);
spin_unlock_irqrestore(&input_device_ids_lock, flags);
dev->i_id = id;
char name[DEV_NAME_MAX];
generate_name(dev, name);
char path[OBJECT_PATH_MAX];
snprintf(path, sizeof path, "/dev/input/%s", name);
struct device *base = input_device_base(dev);
return object_namespace_create_link(global_namespace(), path, &base->dev_base);
}

View File

@@ -8,5 +8,6 @@ struct net_device *net_device_create(void)
}
dev->dev_type = DEV_TYPE_NET;
return NET_DEVICE(dev);
}