diff --git a/dev/core.c b/dev/core.c index 15f6712..dfe030a 100644 --- a/dev/core.c +++ b/dev/core.c @@ -1,34 +1,72 @@ #include #include #include +#include #define DEVICE_CAST(p) OBJECT_C_CAST(struct device, dev_base, &device_type, p) -static struct device *root_device = NULL; +static struct object *dev_folder = NULL; +static struct device *__root_device = NULL; +static struct device *__misc_device = NULL; +static kern_status_t device_object_destroy(struct object *); +static kern_status_t device_object_query_name(struct object *, char out[OBJECT_NAME_MAX]); +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 **); static struct object_type device_type = { .ob_name = "device", .ob_size = sizeof(struct device), .ob_ops = { - .destroy = NULL, + .destroy = device_object_destroy, + .query_name = device_object_query_name, + .get_at = device_object_get_child_at, + .get_named = device_object_get_child_named, } }; +static kern_status_t set_root_device(struct device *dev) +{ + if (__root_device) { + set_remove_object(dev_folder, &__root_device->dev_base); + object_deref(&__root_device->dev_base); + } + + object_ref(&dev->dev_base); + set_add_object(dev_folder, &dev->dev_base); + __root_device = dev; + + return KERN_OK; +} + kern_status_t device_init(void) { object_type_register(&device_type); + dev_folder = set_create("dev"); + object_publish(global_namespace(), "/", dev_folder); + + 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); + + 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); + return KERN_OK; } -kern_status_t set_root_device(struct device *dev) +struct device *root_device(void) { - if (root_device) { - object_deref(&root_device->dev_base); - } + return __root_device; +} - object_ref(&dev->dev_base); - root_device = dev; - - return KERN_OK; +struct device *misc_device(void) +{ + return __misc_device; } struct device *device_alloc(void) @@ -40,3 +78,79 @@ struct device *device_alloc(void) return DEVICE_CAST(dev_object); } + +static kern_status_t device_object_destroy(struct object *obj) +{ + return KERN_OK; +} + +static kern_status_t device_object_query_name(struct object *obj, char out[OBJECT_NAME_MAX]) +{ + struct device *dev = DEVICE_CAST(obj); + if (!dev) { + return KERN_INVALID_ARGUMENT; + } + + strncpy(out, dev->dev_name, OBJECT_NAME_MAX - 1); + out[OBJECT_NAME_MAX - 1] = 0; + + return KERN_OK; +} + +static kern_status_t device_object_get_child_at(struct object *obj, size_t at, struct object **out) +{ + struct device *dev = DEVICE_CAST(obj); + size_t i = 0; + queue_foreach(struct device, child, &dev->dev_children, dev_childent) { + if (i == at) { + *out = object_ref(&child->dev_base); + return KERN_OK; + } + + i++; + } + + return KERN_NO_ENTRY; +} + +static kern_status_t device_object_get_child_named(struct object *obj, const char *name, struct object **out) +{ + struct device *dev = DEVICE_CAST(obj); + if (!dev) { + return KERN_INVALID_ARGUMENT; + } + + queue_foreach(struct device, child, &dev->dev_children, dev_childent) { + if (!strcmp(child->dev_name, name)) { + *out = object_ref(&child->dev_base); + return KERN_OK; + } + } + + return KERN_NO_ENTRY; +} + +kern_status_t device_register(struct device *dev, struct device *parent) +{ + unsigned long flags; + device_lock_irqsave(dev, &flags); + + kern_status_t status = KERN_OK; + + queue_foreach (struct device, child, &dev->dev_children, dev_childent) { + if (!strcmp(dev->dev_name, child->dev_name)) { + status = KERN_NAME_EXISTS; + break; + } + } + + if (status != KERN_OK) { + device_unlock_irqrestore(dev, flags); + return status; + } + + queue_push_back(&parent->dev_children, &dev->dev_childent); + + device_unlock_irqrestore(dev, flags); + return status; +} diff --git a/include/socks/device.h b/include/socks/device.h index 4727b57..5f93765 100644 --- a/include/socks/device.h +++ b/include/socks/device.h @@ -7,6 +7,8 @@ struct device; +#define DEV_NAME_MAX OBJECT_NAME_MAX + #define BLOCK_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_BLOCK ? &(dev)->blk : NULL); #define CHAR_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_CHAR ? &(dev)->chr : NULL); #define NET_DEVICE(dev) ((dev)->dev_type == DEV_TYPE_NET ? &(dev)->net : NULL); @@ -73,6 +75,7 @@ struct device { struct device *dev_parent; struct queue dev_children; struct queue_entry dev_childent; + char dev_name[DEV_NAME_MAX]; void *dev_priv; @@ -86,9 +89,19 @@ struct device { }; extern kern_status_t device_init(void); -extern kern_status_t set_root_device(struct device *dev); +extern struct device *root_device(void); +extern struct device *misc_device(void); extern struct device *device_alloc(void); +static inline void device_lock_irqsave(struct device *dev, unsigned long *flags) +{ + object_lock(&dev->dev_base, flags); +} + +static inline void device_unlock_irqrestore(struct device *dev, unsigned long flags) +{ + object_unlock(&dev->dev_base, flags); +} extern struct char_device *char_device_create(void); extern struct block_device *block_device_create(void);