X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/f044ca812256b421e793c4335ce1ffed74710a70..0765e7c133eb393d8cd0292af444543c2edf8ccc:/lunaix-os/kernel/device/device.c diff --git a/lunaix-os/kernel/device/device.c b/lunaix-os/kernel/device/device.c index b794334..d3552c6 100644 --- a/lunaix-os/kernel/device/device.c +++ b/lunaix-os/kernel/device/device.c @@ -1,4 +1,4 @@ -#include + #include #include #include @@ -8,24 +8,19 @@ #include #include -static DEFINE_LLIST(root_list); +#include +#include -static volatile dev_t devid = 0; +static DEFINE_LLIST(root_list); -void -device_prepare(struct device* dev) -{ - dev->magic = DEV_STRUCT_MAGIC; - dev->dev_id = devid++; +static volatile u32_t devid = 0; - llist_init_head(&dev->children); -} +struct devclass default_devclass = {}; -static void -device_setname_vargs(struct device* dev, char* fmt, va_list args) +void +device_setname_vargs(struct device_meta* dev, char* fmt, va_list args) { - size_t strlen = - __ksprintf_internal(dev->name_val, fmt, DEVICE_NAME_SIZE, args); + size_t strlen = ksnprintfv(dev->name_val, fmt, DEVICE_NAME_SIZE, args); dev->name = HSTR(dev->name_val, strlen); @@ -33,122 +28,153 @@ device_setname_vargs(struct device* dev, char* fmt, va_list args) } void -device_setname(struct device* dev, char* fmt, ...) +device_register_generic(struct device_meta* devm, struct devclass* class, char* fmt, ...) { va_list args; va_start(args, fmt); - device_setname_vargs(dev, fmt, args); - - va_end(args); -} + if (fmt) { + device_setname_vargs(devm, fmt, args); + } -struct device* -device_add_vargs(struct device* parent, - void* underlay, - char* name_fmt, - u32_t type, - va_list args) -{ - struct device* dev = vzalloc(sizeof(struct device)); + if (class && valid_device_subtype_ref(devm, DEV_STRUCT)) { + struct device* dev = to_dev(devm); + dev->ident = (struct devident){ .fn_grp = class->fn_grp, + .unique = DEV_UNIQUE(class->device, + class->variant) }; + } - device_prepare(dev); + devm->dev_uid = devid++; + struct device_meta* parent = devm->parent; if (parent) { - assert((parent->dev_type & DEV_MSKIF) == DEV_IFCAT); - llist_append(&parent->children, &dev->siblings); + assert(valid_device_subtype_ref(parent, DEV_CAT)); + llist_append(&parent->children, &devm->siblings); } else { - llist_append(&root_list, &dev->siblings); + llist_append(&root_list, &devm->siblings); } - if (name_fmt) { - device_setname_vargs(dev, name_fmt, args); - } + va_end(args); +} + +static void +device_init_meta(struct device_meta* dmeta, struct device_meta* parent, unsigned int subtype) +{ + dmeta->magic = DEV_STRUCT_MAGIC_MASK | subtype; + dmeta->parent = parent; + + llist_init_head(&dmeta->children); +} - dev->parent = parent; +void +device_create(struct device* dev, + struct device_meta* parent, + u32_t type, + void* underlay) +{ + dev->magic = DEV_STRUCT_MAGIC; dev->underlay = underlay; dev->dev_type = type; - return dev; + device_init_meta(dev_meta(dev), parent, DEV_STRUCT); + llist_init_head(&dev->capabilities); + mutex_init(&dev->lock); + iopoll_init_evt_q(&dev->pollers); } struct device* -device_add(struct device* parent, - void* underlay, - u32_t type, - char* name_fmt, - ...) +device_alloc(struct device_meta* parent, u32_t type, void* underlay) { - va_list args; - va_start(args, name_fmt); + struct device* dev = vzalloc(sizeof(struct device)); - struct device* dev = - device_add_vargs(parent, underlay, name_fmt, type, args); + if (!dev) { + return NULL; + } + + device_create(dev, parent, type, underlay); - va_end(args); return dev; } -struct device* -device_addsys(struct device* parent, void* underlay, char* name_fmt, ...) +struct device_alias* +device_alloc_alias(struct device_meta* parent, struct device_meta* aliased) { - va_list args; - va_start(args, name_fmt); + struct device_alias* dev = vzalloc(sizeof(struct device_alias)); - struct device* dev = - device_add_vargs(parent, underlay, name_fmt, DEV_IFSEQ, args); + if (!dev) { + return NULL; + } + + device_init_meta(dev_meta(dev), parent, DEV_ALIAS); + dev->alias = aliased; - va_end(args); return dev; } -struct device* -device_addseq(struct device* parent, void* underlay, char* name_fmt, ...) +struct device_cat* +device_alloc_cat(struct device_meta* parent) +{ + struct device_cat* dev = vzalloc(sizeof(struct device_cat)); + + if (!dev) { + return NULL; + } + + device_init_meta(dev_meta(dev), parent, DEV_CAT); + + return dev; +} + + +void +device_setname(struct device_meta* dev, char* fmt, ...) { va_list args; - va_start(args, name_fmt); + va_start(args, fmt); - struct device* dev = - device_add_vargs(parent, underlay, name_fmt, DEV_IFSEQ, args); + device_setname_vargs(dev, fmt, args); va_end(args); - return dev; } -struct device* -device_addvol(struct device* parent, void* underlay, char* name_fmt, ...) +struct device_cat* +device_addcat(struct device_meta* parent, char* name_fmt, ...) { va_list args; va_start(args, name_fmt); - struct device* dev = - device_add_vargs(parent, underlay, name_fmt, DEV_IFVOL, args); + struct device_cat* dev = device_alloc_cat(parent); + + device_setname_vargs(dev_meta(dev), name_fmt, args); + device_register_generic(dev_meta(dev), NULL, NULL); va_end(args); return dev; } -struct device* -device_addcat(struct device* parent, char* name_fmt, ...) +struct device_alias* +device_addalias(struct device_meta* parent, struct device_meta* aliased, char* name_fmt, ...) { va_list args; va_start(args, name_fmt); - struct device* dev = - device_add_vargs(parent, NULL, name_fmt, DEV_IFCAT, args); + struct device_alias* dev = device_alloc_alias(parent, aliased); + + device_setname_vargs(dev_meta(dev), name_fmt, args); + device_register_generic(dev_meta(dev), NULL, NULL); va_end(args); return dev; } -struct device* -device_getbyid(struct llist_header* devlist, dev_t id) +struct device_meta* +device_getbyid(struct llist_header* devlist, u32_t id) { devlist = devlist ? devlist : &root_list; - struct device *pos, *n; + struct device_meta *pos, *n; llist_for_each(pos, n, devlist, siblings) { - if (pos->dev_id == id) { + if (pos->dev_uid == id) { return pos; } } @@ -156,11 +182,11 @@ device_getbyid(struct llist_header* devlist, dev_t id) return NULL; } -struct device* -device_getbyhname(struct device* root_dev, struct hstr* name) +struct device_meta* +device_getbyhname(struct device_meta* root_dev, struct hstr* name) { struct llist_header* devlist = root_dev ? &root_dev->children : &root_list; - struct device *pos, *n; + struct device_meta *pos, *n; llist_for_each(pos, n, devlist, siblings) { if (HSTR_EQ(&pos->name, name)) { @@ -171,8 +197,8 @@ device_getbyhname(struct device* root_dev, struct hstr* name) return NULL; } -struct device* -device_getbyname(struct device* root_dev, const char* name, size_t len) +struct device_meta* +device_getbyname(struct device_meta* root_dev, const char* name, size_t len) { struct hstr hname = HSTR(name, len); hstr_rehash(&hname, HSTR_FULL_HASH); @@ -181,17 +207,17 @@ device_getbyname(struct device* root_dev, const char* name, size_t len) } void -device_remove(struct device* dev) +device_remove(struct device_meta* dev) { llist_delete(&dev->siblings); vfree(dev); } -struct device* -device_getbyoffset(struct device* root_dev, int offset) +struct device_meta* +device_getbyoffset(struct device_meta* root_dev, int offset) { struct llist_header* devlist = root_dev ? &root_dev->children : &root_list; - struct device *pos, *n; + struct device_meta *pos, *n; int off = 0; llist_for_each(pos, n, devlist, siblings) { @@ -202,20 +228,90 @@ device_getbyoffset(struct device* root_dev, int offset) return NULL; } +void +device_populate_info(struct device* dev, struct dev_info* devinfo) +{ + devinfo->dev_id.group = dev->ident.fn_grp; + devinfo->dev_id.unique = dev->ident.unique; + + if (!devinfo->dev_name.buf) { + return; + } + + struct device_def* def = devdef_byident(&dev->ident); + size_t buflen = devinfo->dev_name.buf_len; + + strncpy(devinfo->dev_name.buf, def->name, buflen); + devinfo->dev_name.buf[buflen - 1] = 0; +} + +struct device_meta* +resolve_device_meta(void* maybe_dev) { + if (!valid_device_ref(maybe_dev)) { + return NULL; + } + + struct device_meta* dm = (struct device_meta*)maybe_dev; + unsigned int subtype = dm->magic ^ DEV_STRUCT_MAGIC_MASK; + + switch (subtype) + { + case DEV_STRUCT: + case DEV_CAT: + return dm; + + case DEV_ALIAS: { + struct device_meta* aliased_dm = dm; + + while(valid_device_subtype_ref(aliased_dm, DEV_ALIAS)) { + aliased_dm = to_aliasdev(aliased_dm)->alias; + } + + return aliased_dm; + } + default: + return NULL; + } +} + +struct device* +resolve_device(void* maybe_dev) { + struct device_meta* dm = resolve_device_meta(maybe_dev); + + if (!valid_device_subtype_ref(dm, DEV_STRUCT)) { + return NULL; + } + + return to_dev(dm); +} + +void +device_alert_poller(struct device* dev, int poll_evt) +{ + dev->poll_evflags = poll_evt; + iopoll_wake_pollers(&dev->pollers); +} + __DEFINE_LXSYSCALL3(int, ioctl, int, fd, int, req, va_list, args) { - int errno; + int errno = -1; struct v_fd* fd_s; - if ((errno = vfs_getfd(fd, &fd_s))) { + if ((errno &= vfs_getfd(fd, &fd_s))) { goto done; } - struct device* dev = (struct device*)fd_s->file->inode->data; - if (dev->magic != DEV_STRUCT_MAGIC) { + struct device* dev = resolve_device(fd_s->file->inode->data); + if (!valid_device_subtype_ref(dev, DEV_STRUCT)) { errno = ENODEV; goto done; } + if (req == DEVIOIDENT) { + struct dev_info* devinfo = va_arg(args, struct dev_info*); + device_populate_info(dev, devinfo); + errno = 0; + } + if (!dev->ops.exec_cmd) { errno = ENOTSUP; goto done;