#include #include #include #include #define DEVICE_CAST(p) OBJECT_C_CAST(struct device, dev_base, &device_type, p) 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_read(struct object *obj, void *, size_t *, socks_flags_t); static kern_status_t device_object_write(struct object *obj, const void *, size_t *, socks_flags_t); 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 = { .read = device_object_read, .write = device_object_write, .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; } 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); 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; } struct device *root_device(void) { return __root_device; } struct device *misc_device(void) { return __misc_device; } struct device *device_alloc(void) { struct object *dev_object = object_create(&device_type); if (!dev_object) { return NULL; } return DEVICE_CAST(dev_object); } kern_status_t device_read(struct device *dev, void *buf, size_t size, size_t *bytes_read, socks_flags_t flags) { switch (dev->dev_type) { case DEV_TYPE_INPUT: return input_device_read(dev, buf, size, bytes_read, flags); default: return KERN_UNSUPPORTED; } } kern_status_t device_write(struct device *dev, const void *buf, size_t size, size_t *bytes_written, socks_flags_t flags) { return KERN_UNSUPPORTED; } struct device *cast_to_device(struct object *obj) { return DEVICE_CAST(obj); } static kern_status_t device_object_read(struct object *obj, void *p, size_t *count, socks_flags_t flags) { struct device *dev = DEVICE_CAST(obj); return device_read(dev, p, *count, count, flags); } static kern_status_t device_object_write(struct object *obj, const void *p, size_t *count, socks_flags_t flags) { struct device *dev = DEVICE_CAST(obj); return device_write(dev, p, *count, count, flags); } 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; 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) { 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; }