Fix: stale dnode caching instance cause locked-up upon accessing (#52)
[lunaix-os.git] / lunaix-os / includes / lunaix / device.h
index 05b8639a6579c790582a4bf379ea206a72b7a3ab..7a469a113c725b31e1fba06cb0c0667788f9dcb1 100644 (file)
@@ -1,7 +1,7 @@
 #ifndef __LUNAIX_DEVICE_H
 #define __LUNAIX_DEVICE_H
 
-#define DEVICE_NAME_SIZE 32
+#define DEVICE_NAME_SIZE 16
 
 #include <lunaix/device_num.h>
 #include <lunaix/ds/hashtable.h>
@@ -11,6 +11,9 @@
 #include <lunaix/ds/mutex.h>
 #include <lunaix/iopoll.h>
 #include <lunaix/types.h>
+#include <lunaix/changeling.h>
+
+#include <hal/devtreem.h>
 
 #include <usr/lunaix/device.h>
 
  */
 #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.
  * @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_MASK 0x56454440U
-#define DEV_STRUCT 0xc
-#define DEV_CAT 0xd
-#define DEV_ALIAS 0xf
-
-#define DEV_STRUCT_MAGIC (DEV_STRUCT_MAGIC_MASK | DEV_STRUCT)
-#define DEV_CAT_MAGIC (DEV_STRUCT_MAGIC_MASK | DEV_CAT)
-#define DEV_ALIAS_MAGIC (DEV_STRUCT_MAGIC_MASK | DEV_ALIAS)
-
 #define DEV_MSKIF 0x00000003
-
 #define DEV_IFVOL 0x0 // volumetric (block) device
 #define DEV_IFSEQ 0x1 // sequential (character) device
 #define DEV_IFSYS 0x3 // a system device
 
-struct device_meta
+#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
 {
-    u32_t magic;
-    struct llist_header siblings;
-    struct llist_header children;
-    struct device_meta* parent;
-    struct hstr name;
+    struct device* owner;
     
-    u32_t dev_uid;
-    
-    char name_val[DEVICE_NAME_SIZE];
+    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 <listings/device_potens.lst>
 };
 
+/**
+ * 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;                    \
-        struct {                                    \
-            u32_t magic;                            \
-            struct llist_header siblings;           \
-            struct llist_header children;           \
-            struct device_meta* parent;             \
-            struct hstr name;                       \
-                                                    \
-            u32_t dev_uid;                          \
-                                                    \
-            char name_val[DEVICE_NAME_SIZE];        \
-        };                                          \
-    }                                              
-
-#define dev_meta(dev) (&(dev)->meta)
-#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))
+        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;
@@ -149,6 +188,12 @@ struct device
 
     DEVICE_METADATA;
 
+    potentium_list_t potentium;
+
+#ifdef CONFIG_USE_DEVICETREE
+    devtree_link_t devtree_node;
+#endif
+
     /* -- device state -- */
 
     mutex_t lock;
@@ -180,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;
@@ -187,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
@@ -210,29 +290,16 @@ struct device_def
     int (*free)(struct device_def*, void* instance);
 };
 
-static inline bool must_inline
-valid_device_ref(void* maybe_dev) {
-    if (!maybe_dev) 
-        return false;
-        
-    unsigned int magic = ((struct device_meta*)maybe_dev)->magic;
-    return (magic ^ DEV_STRUCT_MAGIC_MASK) <= 0xfU;
-}
+#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
 
-static inline bool must_inline
-valid_device_subtype_ref(void* maybe_dev, unsigned int subtype) {
-    if (!maybe_dev) 
-        return false;
-    
-    unsigned int magic = ((struct device_meta*)maybe_dev)->magic;
-    return (magic ^ DEV_STRUCT_MAGIC_MASK) == subtype;
-}
-
-struct device*
-resolve_device(void* maybe_dev);
-
-struct device_meta*
-resolve_device_meta(void* maybe_dev);
+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
@@ -249,6 +316,12 @@ 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();
 
@@ -259,11 +332,18 @@ void
 device_setname(struct device_meta* dev, char* fmt, ...);
 
 void
-device_register_generic(struct device_meta* 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_meta* parent,
@@ -273,6 +353,14 @@ device_create(struct device* dev,
 struct device*
 device_alloc(struct device_meta* parent, u32_t type, 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)
 {
@@ -292,7 +380,8 @@ device_allocvol(struct device_meta* parent, void* underlay)
 }
 
 struct device_alias*
-device_addalias(struct device_meta* parent, struct device_meta* aliased, char* name_fmt, ...);
+device_addalias(struct device_meta* parent, struct device_meta* aliased, 
+                char* name_fmt, ...);
 
 struct device_cat*
 device_addcat(struct device_meta* parent, char* name_fmt, ...);
@@ -300,18 +389,6 @@ device_addcat(struct device_meta* parent, char* name_fmt, ...);
 void
 device_remove(struct device_meta* dev);
 
-struct device_meta*
-device_getbyid(struct llist_header* devlist, u32_t id);
-
-struct device_meta*
-device_getbyhname(struct device_meta* root_dev, struct hstr* name);
-
-struct device_meta*
-device_getbyname(struct device_meta* root_dev, const char* name, size_t len);
-
-struct device_meta*
-device_getbyoffset(struct device_meta* root_dev, int pos);
-
 struct hbucket*
 device_definitions_byif(int if_type);
 
@@ -324,6 +401,23 @@ 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
@@ -335,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)
 {
@@ -355,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 */