X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/642855f81fd03b9fd6540ac99c665b57b4b38cc8..35a7d633d3f16c1e0539af6ca5d8e7482926cd93:/lunaix-os/kernel/device/device.c diff --git a/lunaix-os/kernel/device/device.c b/lunaix-os/kernel/device/device.c index 3647f10..9af8ac3 100644 --- a/lunaix-os/kernel/device/device.c +++ b/lunaix-os/kernel/device/device.c @@ -1,4 +1,3 @@ -#include #include #include #include @@ -7,163 +6,303 @@ #include #include #include +#include + +#include +#include static DEFINE_LLIST(root_list); -static volatile dev_t devid = 0; +morph_t* device_mobj_root; -struct device* -device_add(struct device* parent, - void* underlay, - char* name_fmt, - u32_t type, - va_list args) +void +device_setname_vargs(struct device_meta* dev, char* fmt, va_list args) { - struct device* dev = vzalloc(sizeof(struct device)); + ksnprintfv(dev->name_val, fmt, DEVICE_NAME_SIZE, args); + changeling_setname(dev_mobj(dev), dev->name_val); +} +void +device_register_generic(struct device_meta* devm, struct devclass* class, + char* fmt, ...) +{ + va_list args; + morph_t* morphed, *parent; + + morphed = &devm->mobj; + va_start(args, fmt); + + if (fmt) { + device_setname_vargs(devm, fmt, args); + } + + if (class && morph_type_of(morphed, device_morpher)) + { + struct device* dev = to_dev(devm); + dev->ident = (struct devident) { + .fn_grp = class->fn_grp, + .unique = DEV_UNIQUE(class->device, class->variant) + }; + } + + parent = morphed->parent; if (parent) { - assert((parent->dev_type & DEV_MSKIF) == DEV_IFCAT); - llist_append(&parent->children, &dev->siblings); - } else { - llist_append(&root_list, &dev->siblings); + changeling_attach(parent, morphed); } - size_t strlen = - __ksprintf_internal(dev->name_val, name_fmt, DEVICE_NAME_SIZE, args); + va_end(args); +} - dev->magic = DEV_STRUCT_MAGIC; - dev->dev_id = devid++; - dev->name = HSTR(dev->name_val, strlen); - dev->parent = parent; +void +device_create(struct device* dev, struct device_meta* parent, + u32_t type, void* underlay) +{ dev->underlay = underlay; dev->dev_type = type; - hstr_rehash(&dev->name, HSTR_FULL_HASH); - llist_init_head(&dev->children); + llist_init_head(&dev->potentium); + mutex_init(&dev->lock); + iopoll_init_evt_q(&dev->pollers); +} + +struct device* +device_alloc(struct device_meta* parent, u32_t type, void* underlay) +{ + struct device* dev = vzalloc(sizeof(struct device)); + + if (!dev) { + return NULL; + } + + device_create(dev, parent, type, underlay); + changeling_morph(dev_morph(parent), dev->mobj, NULL, device_morpher); return dev; } -struct device* -device_addseq(struct device* parent, void* underlay, char* name_fmt, ...) +struct device_alias* +device_alloc_alias(struct device_meta* parent, struct device_meta* aliased) +{ + struct device_alias* dev = vzalloc(sizeof(struct device_alias)); + + if (!dev) { + return NULL; + } + + dev->alias = aliased; + changeling_ref(dev_mobj(aliased)); + changeling_morph(dev_morph(parent), dev->mobj, NULL, devalias_morpher); + + return dev; +} + +struct device_cat* +device_alloc_cat(struct device_meta* parent) +{ + struct device_cat* dev = vzalloc(sizeof(struct device_cat)); + + if (!dev) { + return NULL; + } + + changeling_morph(dev_morph(parent), dev->mobj, NULL, devcat_morpher); + + 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(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(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(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) +void +device_remove(struct device_meta* dev) { - devlist = devlist ? devlist : &root_list; - struct device *pos, *n; - llist_for_each(pos, n, devlist, siblings) - { - if (pos->dev_id == id) { - return pos; - } + changeling_isolate(&dev->mobj); + vfree(dev); +} + +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; } - return NULL; + 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* -device_getbyhname(struct device* root_dev, struct hstr* name) +morph_t* +resolve_device_morph(void* maybe_dev) { - struct llist_header* devlist = root_dev ? &root_dev->children : &root_list; - struct device *pos, *n; - llist_for_each(pos, n, devlist, siblings) + struct device_alias* da = NULL; + morph_t *morphed; + + morphed = morphed_ptr(maybe_dev); + + if (!is_changeling(morphed)) { + return NULL; + } + + if (morph_type_of(morphed, device_morpher)) + { + return morphed; + } + + if (morph_type_of(morphed, devcat_morpher)) + { + return morphed; + } + + while(morph_type_of(morphed, devalias_morpher)) { - if (HSTR_EQ(&pos->name, name)) { - return pos; - } + da = changeling_reveal(morphed, devalias_morpher); + morphed = &da->alias->mobj; } - return NULL; + return da ? morphed : NULL; } -struct device* -device_getbyname(struct device* root_dev, const char* name, size_t len) +void +device_alert_poller(struct device* dev, int poll_evt) { - struct hstr hname = HSTR(name, len); - hstr_rehash(&hname, HSTR_FULL_HASH); - - return device_getbyhname(root_dev, &hname); + dev->poll_evflags = poll_evt; + iopoll_wake_pollers(&dev->pollers); } void -device_remove(struct device* dev) +device_chain_loader(struct device_def* def, devdef_ldfn fn) { - llist_delete(&dev->siblings); - vfree(dev); + struct device_ldfn_chain* node; + + node = valloc(sizeof(*node)); + node->load = fn; + + if (!def->load_chain) { + node->chain = NULL; + } + else { + node->chain = def->load_chain; + } + + def->load_chain = node; } -struct device* -device_getbyoffset(struct device* root_dev, int offset) +void +device_chain_load_once(struct device_def* def) { - struct llist_header* devlist = root_dev ? &root_dev->children : &root_list; - struct device *pos, *n; - int off = 0; - llist_for_each(pos, n, devlist, siblings) + struct device_ldfn_chain *node, *next; + + if (def->load) { + def->load(def); + } + + node = def->load_chain; + def->load_chain = NULL; + + while (node) { - if (off++ >= offset) { - return pos; - } + node->load(def); + next = node->chain; + vfree(node); + + node = next; + } + + if (def->flags.no_default_realm) { + return; } - return NULL; + + if (!def->create) { + return; + } + + def->create(def, NULL); + } -__DEFINE_LXSYSCALL3(int, ioctl, int, fd, int, req, va_list, args) +__DEFINE_LXSYSCALL3(int, ioctl, int, fd, int, req, sc_va_list, _args) { - int errno; + int errno = -1; struct v_fd* fd_s; - if ((errno = vfs_getfd(fd, &fd_s))) { + va_list args; + + convert_valist(&args, _args); + + 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 (!dev) { errno = ENODEV; goto done; } - if (!dev->exec_cmd) { - errno = EINVAL; + 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; } - errno = dev->exec_cmd(dev, req, args); + errno = dev->ops.exec_cmd(dev, req, args); done: return DO_STATUS_OR_RETURN(errno); -} \ No newline at end of file +} + +static void +__device_subsys_init() +{ + device_mobj_root = changeling_spawn(NULL, "devices"); +} +owloysius_fetch_init(__device_subsys_init, on_sysconf); \ No newline at end of file