X-Git-Url: https://scm.lunaixsky.com/lunaix-os.git/blobdiff_plain/1375eb51603466b723ab7dd1ca4194ee5d662f75..43487eff262637a59a4c2c0272d7c4a824af3944:/lunaix-os/includes/lunaix/device.h diff --git a/lunaix-os/includes/lunaix/device.h b/lunaix-os/includes/lunaix/device.h index 1844590..7a469a1 100644 --- a/lunaix-os/includes/lunaix/device.h +++ b/lunaix-os/includes/lunaix/device.h @@ -1,7 +1,7 @@ #ifndef __LUNAIX_DEVICE_H #define __LUNAIX_DEVICE_H -#define DEVICE_NAME_SIZE 32 +#define DEVICE_NAME_SIZE 16 #include #include @@ -11,6 +11,9 @@ #include #include #include +#include + +#include #include @@ -40,13 +43,6 @@ */ #define load_sysconf ld_sysconf -/** - * @brief Mark the device definition should be loaded as time device, for - * example a real time clock device. Such device will be loaded and managed by - * clock subsystem - */ -#define load_timedev ld_timedev - /** * @brief Mark the device definition should be loaded automatically during the * bootstrapping stage. Most of the driver do load there. @@ -72,47 +68,138 @@ * @brief Declare a device class * */ -#define DEVCLASS(devif, devfn, dev) \ - (struct devclass) \ - { \ - .fn_grp = DEV_FNGRP(devif, devfn), .device = (dev), .variant = 0 \ - } - -#define DEVCLASSV(devif, devfn, dev, devvar) \ +#define DEVCLASS(vendor, devfn, dev) \ (struct devclass) \ { \ - .fn_grp = DEV_FNGRP(devif, devfn), .device = (dev), \ - .variant = (devvar) \ + .fn_grp = DEV_FNGRP(dev_vn(vendor), dev_fn(devfn)), \ + .device = dev_id(dev), .variant = 0 \ } -#define DEV_STRUCT_MAGIC 0x5645444c - #define DEV_MSKIF 0x00000003 - #define DEV_IFVOL 0x0 // volumetric (block) device #define DEV_IFSEQ 0x1 // sequential (character) device -#define DEV_IFCAT 0x2 // a device category (as device groupping) #define DEV_IFSYS 0x3 // a system device +#define dev_object_root \ + ({ extern morph_t* device_mobj_root; device_mobj_root; }) + +/** + * A potens is a capability of the device + * ("potens", means "capable" in latin) + * + * A device can have multiple capabilities + * (or "potentes", plural form of potens) + * + * A group of devices with same capability will forms + * a "globus potentis" or "capability group". The + * group is completely a logical formation, meaning + * that it is not explictly coded. + * + * The idea of potens is to provide a unified and yet + * opaque method to decouple the device provide raw + * functionalities with any higher abstraction, such + * as other subsystem, or standard-compilance wrapper + * (e.g., POSIX terminal) + */ +struct potens_meta +{ + struct device* owner; + + struct llist_header potentes; + unsigned int pot_type; +}; + +#define POTENS_META \ + struct { \ + union { \ + struct potens_meta pot_meta; \ + struct { \ + struct llist_header potentes; \ + unsigned int pot_type; \ + }; \ + }; \ + } + +#define get_potens(cap, pot_struct) \ + container_of((cap), pot_struct, pot_meta) +#define potens_meta(cap) (&(cap)->pot_meta) +#define potens_dev(cap) (potens_meta(cap)->owner) + +#define potens(name) POTENS_##name + +#define potens_check_unique(dev, pot_type) \ + !device_get_potens(dev, pot_type) + +enum device_potens_type +{ + potens(NON), + #include +}; + +/** + * List of potentes of a device, pay attention to + * the spelling, "potentium", genitive plural of "potens". + */ +typedef struct llist_header potentium_list_t; + + +#define DEVICE_META_FIELD \ + struct { \ + morph_t mobj; \ + char name_val[DEVICE_NAME_SIZE]; \ + }; + +#define DEVICE_METADATA \ + union { \ + struct device_meta meta; \ + DEVICE_META_FIELD; \ + } + +#define devmeta_morpher morphable_attrs(device_meta, mobj) +#define devalias_morpher morphable_attrs(device_alias, mobj) +#define devcat_morpher morphable_attrs(device_cat, mobj) +#define device_morpher morphable_attrs(device, mobj) + +#define dev_meta(dev) (&(dev)->meta) +#define dev_mobj(dev) (&(dev)->mobj) +#define dev_morph(dev) ({ likely(dev) ? &(dev)->mobj : dev_object_root; }) +#define dev_uid(dev) (morpher_uid(&(dev)->mobj)) +#define to_dev(dev) (container_of(dev,struct device, meta)) +#define to_catdev(dev) (container_of(dev,struct device_cat, meta)) +#define to_aliasdev(dev) (container_of(dev,struct device_alias, meta)) + +struct device_meta +{ + DEVICE_META_FIELD; +}; + +struct device_alias { + DEVICE_METADATA; + struct device_meta* alias; +}; + +struct device_cat { + DEVICE_METADATA; +}; + struct device { /* -- device structing -- */ - u32_t magic; - struct llist_header siblings; - struct llist_header children; - struct device* parent; + DEVICE_METADATA; + + potentium_list_t potentium; + +#ifdef CONFIG_USE_DEVICETREE + devtree_link_t devtree_node; +#endif /* -- device state -- */ mutex_t lock; - struct hstr name; - struct devident ident; - - u32_t dev_uid; int dev_type; - char name_val[DEVICE_NAME_SIZE]; + struct devident ident; void* underlay; /* -- polling -- */ @@ -138,6 +225,15 @@ struct device } ops; }; +struct device_def; +typedef int (*devdef_ldfn)(struct device_def*); + +struct device_ldfn_chain +{ + struct device_ldfn_chain* chain; + devdef_ldfn load; +}; + struct device_def { struct llist_header dev_list; @@ -145,20 +241,46 @@ struct device_def struct hlist_node hlist_if; char* name; - struct devclass class; + union + { + struct { + bool no_default_realm : 1; + }; + int val; + } flags; + + + struct { + struct devclass class; + unsigned int class_hash; + }; + + struct device_ldfn_chain* load_chain; /** - * @brief Called when the driver is required to initialize itself. + * @brief + * Called when driver is required to register itself to the system + * All registration code should put it here. + * + * ad tabulam - + * "to the record" in latin. just in case anyone wonders. + * I am ran out of naming idea... have to improvise :) * */ - int (*init)(struct device_def*); + devdef_ldfn ad_tabulam; /** - * @brief Called when the driver is required to bind with a device. This is - * the case for a real-hardware-oriented driver + * @brief Called when the driver is loaded at it's desired load stage * */ - int (*bind)(struct device_def*, struct device*); + devdef_ldfn load; + + /** + * @brief Called when the driver is required to create device instance + * This is for device with their own preference of creation + * object that hold parameter for such creation is provided by second argument. + */ + int (*create)(struct device_def*, morph_t*); /** * @brief Called when a driver is requested to detach from the device and @@ -168,6 +290,17 @@ struct device_def int (*free)(struct device_def*, void* instance); }; +#define def_device_name(dev_n) .name = dev_n +#define def_device_class(_if, fn, dev) .class = DEVCLASS(_if, fn, dev) +#define def_on_register(fn) .ad_tabulam = fn +#define def_on_load(fn) .load = fn +#define def_on_create(fn) .create = fn +#define def_on_free(fn) .free = fn +#define def_non_trivial .flags.no_default_realm = true + +morph_t* +resolve_device_morph(void* maybe_dev); + #define mark_device_doing_write(dev_ptr) (dev_ptr)->poll_evflags &= ~_POLLOUT #define mark_device_done_write(dev_ptr) (dev_ptr)->poll_evflags |= _POLLOUT @@ -183,65 +316,78 @@ device_id_from_class(struct devclass* class) return ((class->device & 0xffff) << 16) | ((class->variant & 0xffff)); } +static inline struct device* +resolve_device(void* maybe_dev) { + morph_t* mobj = resolve_device_morph(maybe_dev); + return changeling_try_reveal(mobj, device_morpher); +} + void device_scan_drivers(); void -device_setname_vargs(struct device* dev, char* fmt, va_list args); +device_setname_vargs(struct device_meta* dev, char* fmt, va_list args); void -device_setname(struct device* dev, char* fmt, ...); +device_setname(struct device_meta* dev, char* fmt, ...); void -device_register(struct device* dev, struct devclass* class, char* fmt, ...); +device_register_generic(struct device_meta* dev, struct devclass* class, + char* fmt, ...); + +#define register_device(dev, class, fmt, ...) \ + device_register_generic(dev_meta(dev), class, fmt, ## __VA_ARGS__) + +#define register_device_var(dev, class, fmt, ...) \ + ({device_register_generic( \ + dev_meta(dev), class, \ + fmt "%d", ## __VA_ARGS__, (class)->variant); \ + devclass_mkvar(class); }) void device_create(struct device* dev, - struct device* parent, + struct device_meta* parent, u32_t type, void* underlay); struct device* -device_alloc(struct device* parent, u32_t type, void* underlay); +device_alloc(struct device_meta* parent, u32_t type, void* underlay); -static inline struct device* -device_allocsys(struct device* parent, void* underlay) +#ifdef CONFIG_USE_DEVICETREE +static inline void +device_set_devtree_node(struct device* dev, devtree_link_t node) +{ + dev->devtree_node = node; +} +#endif + +static inline struct device* must_inline +device_allocsys(struct device_meta* parent, void* underlay) { return device_alloc(parent, DEV_IFSYS, underlay); } -static inline struct device* -device_allocseq(struct device* parent, void* underlay) +static inline struct device* must_inline +device_allocseq(struct device_meta* parent, void* underlay) { return device_alloc(parent, DEV_IFSEQ, underlay); } -static inline struct device* -device_allocvol(struct device* parent, void* underlay) +static inline struct device* must_inline +device_allocvol(struct device_meta* parent, void* underlay) { return device_alloc(parent, DEV_IFVOL, underlay); } -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, ...); -void -device_remove(struct device* dev); +struct device_cat* +device_addcat(struct device_meta* parent, char* name_fmt, ...); -struct device* -device_getbyid(struct llist_header* devlist, u32_t id); - -struct device* -device_getbyhname(struct device* root_dev, struct hstr* name); - -struct device* -device_getbyname(struct device* root_dev, const char* name, size_t len); - -struct device* -device_getbyoffset(struct device* root_dev, int pos); - -struct device* -device_cast(void* obj); +void +device_remove(struct device_meta* dev); struct hbucket* device_definitions_byif(int if_type); @@ -255,10 +401,27 @@ device_populate_info(struct device* dev, struct dev_info* devinfo); void device_scan_drivers(); +/*------ Capability ------*/ + +struct potens_meta* +alloc_potens(int cap, unsigned int size); + +#define new_potens(pot_type, pot_struct)\ + ((pot_struct*)alloc_potens((pot_type), sizeof(pot_struct))) + +#define new_potens_marker(pot_type)\ + (alloc_potens((pot_type), sizeof(struct potens_meta))) + +void +device_grant_potens(struct device* dev, struct potens_meta* cap); + +struct potens_meta* +device_get_potens(struct device* dev, unsigned int pot_type); + /*------ Load hooks ------*/ void -device_onbooot_load(); +device_onboot_load(); void device_postboot_load(); @@ -266,6 +429,21 @@ device_postboot_load(); void device_sysconf_load(); +/** + * @brief Add the loader to the chain, used by device domain + * to inject their custom loading logic to the hook + */ +void +device_chain_loader(struct device_def* def, devdef_ldfn fn); + +/** + * @brief Walk the chain and load in a use-and-burnt fashion. + * the chain will be deleted and freed after loading, + * regardless successful or not. + */ +void +device_chain_load_once(struct device_def* def); + static inline void device_lock(struct device* dev) { @@ -286,4 +464,42 @@ device_locked(struct device* dev) #define devprintf_expand(devident) (devident)->fn_grp, (devident)->unique + +/** + * + * Device def hooks extern + * + */ + +static int +default_onregister_hook(struct device_def* def) +{ + return 0; +} + +static int +default_onload_hook(struct device_def* def) +{ + return 0; +} + +static int +default_oncreate_hook(struct device_def* def, morph_t* morphed) +{ + return 0; +} + +#define extern_hook_register(name) \ + int weak_alias("default_onregister_hook") \ + name(struct device_def* def) + +#define extern_hook_load(name) \ + int weak_alias("default_onload_hook") \ + name(struct device_def* def) + +#define extern_hook_create(name) \ + int weak_alias("default_oncreate_hook") \ + name(struct device_def* def, morph_t* morphed) + + #endif /* __LUNAIX_DEVICE_H */