{"id":445,"date":"2023-06-22T00:38:45","date_gmt":"2023-06-22T08:38:45","guid":{"rendered":"http:\/\/bitas.net.cn\/?page_id=445"},"modified":"2023-06-22T00:39:22","modified_gmt":"2023-06-22T08:39:22","slug":"647-lk-sysfs-example","status":"publish","type":"page","link":"http:\/\/bitas.net.cn\/index.php\/sourcecode\/647-lk-sysfs-example\/","title":{"rendered":"647 (LK) sysfs \u793a\u4f8b"},"content":{"rendered":"\n<pre class=\"wp-block-code\"><code>\/*\n * sysfs example\n *\/\n#include &lt;linux\/kobject.h>\n#include &lt;linux\/slab.h>\n#include &lt;linux\/module.h>\n#include &lt;linux\/init.h>\n\n\/*\n * This module shows how to create a kset in sysfs called\n * \/sys\/kernel\/ks_a\n *\/\n\n\n\/*\n * This is our \"object\" that we will create a few of and register them with\n * sysfs.\n *\/\nstruct fu_obj {\n    struct kobject kobj;\n    int par;\n};\n#define to_fu_obj(x) container_of(x, struct fu_obj, kobj)\n\n\/* a custom attribute that works just for a struct fu_obj. *\/\nstruct fu_attribute {\n    struct attribute attr;\n    ssize_t (*show)(struct fu_obj *fu, struct fu_attribute *attr, char *buf);\n    ssize_t (*store)(struct fu_obj *fu, struct fu_attribute *attr, const char *buf, size_t count);\n};\n#define to_fu_attr(x) container_of(x, struct fu_attribute, attr)\n\n\/*\n * The default show function that must be passed to sysfs.  This will be\n * called by sysfs for whenever a show function is called by the user on a\n * sysfs file associated with the kobjects we have registered.  We need to\n * transpose back from a \"default\" kobject to our custom struct fu_obj and\n * then call the show function for that specific object.\n *\/\nstatic ssize_t fu_attr_show(struct kobject *kobj,\n                 struct attribute *attr,\n                 char *buf)\n{\n    struct fu_attribute *attribute;\n    struct fu_obj *fu;\n\n    attribute = to_fu_attr(attr);\n    fu = to_fu_obj(kobj);\n\n    if (!attribute->show)\n        return -EIO;\n\n    return attribute->show(fu, attribute, buf);\n}\n\n\/*\n * Just like the default show function above, but this one is for when the\n * sysfs \"store\" is requested (when a value is written to a file.)\n *\/\nstatic ssize_t fu_attr_store(struct kobject *kobj,\n                  struct attribute *attr,\n                  const char *buf, size_t len)\n{\n    struct fu_attribute *attribute;\n    struct fu_obj *fu;\n\n    attribute = to_fu_attr(attr);\n    fu = to_fu_obj(kobj);\n\n    if (!attribute->store)\n        return -EIO;\n\n    return attribute->store(fu, attribute, buf, len);\n}\n\n\/* Our custom sysfs_ops that we will associate with our ktype later on *\/\nstatic const struct sysfs_ops fu_sysfs_ops = {\n    .show = fu_attr_show,\n    .store = fu_attr_store,\n};\n\n\/*\n * The release function for our object.  This is REQUIRED by the kernel to\n * have.  We free the memory held in our object here.\n *\n * NEVER try to get away with just a \"blank\" release function to try to be\n * smarter than the kernel.  Turns out, no one ever is...\n *\/\nstatic void fu_release(struct kobject *kobj)\n{\n    struct fu_obj *fu;\n\n    fu = to_fu_obj(kobj);\n    kfree(fu);\n}\n\n\/*\n * The \"para\" file where the .par variable is read from and written to.\n *\/\nstatic ssize_t para_show(struct fu_obj *fu_obj, struct fu_attribute *attr,\n            char *buf)\n{\n    return sprintf(buf, \"%d\\n\", fu_obj->par);\n}\n\nstatic ssize_t para_store(struct fu_obj *fu_obj, struct fu_attribute *attr,\n             const char *buf, size_t count)\n{\n    int ret;\n\n    ret = kstrtoint(buf, 10, &amp;fu_obj->par);\n    if (ret &lt; 0)\n        return ret;\n\n    return count;\n}\n\nstatic struct fu_attribute para_attribute =\n    __ATTR(para, 0664, para_show, para_store);\n\n\/*\n * Create a group of attributes so that we can create and destroy them all\n * at once.\n *\/\nstatic struct attribute *fu_default_attrs&#91;] = {\n    &amp;para_attribute.attr,\n    NULL,   \/* need to NULL terminate the list of attributes *\/\n};\n\n\/*\n * Our own ktype for our kobjects.  Here we specify our sysfs ops, the\n * release function, and the set of default attributes we want created\n * whenever a kobject of this type is registered with the kernel.\n *\/\nstatic struct kobj_type fu_ktype = {\n    .sysfs_ops = &amp;fu_sysfs_ops,\n    .release = fu_release,\n    .default_attrs = fu_default_attrs,\n};\n\nstatic struct kset *ks_a;\nstatic struct fu_obj *fu_a;\n\nstatic struct fu_obj *create_fu_obj(const char *name)\n{\n    struct fu_obj *fu;\n    int retval;\n\n    \/* allocate the memory for the whole object *\/\n    fu = kzalloc(sizeof(*fu), GFP_KERNEL);\n    if (!fu)\n        return NULL;\n\n    \/*\n     * As we have a kset for this kobject, we need to set it before calling\n     * the kobject core.\n     *\/\n    fu->kobj.kset = ks_a;\n\n    \/*\n     * Initialize and add the kobject to the kernel.  All the default files\n     * will be created here.  As we have already specified a kset for this\n     * kobject, we don't have to set a parent for the kobject, the kobject\n     * will be placed beneath that kset automatically.\n     *\/\n    retval = kobject_init_and_add(&amp;fu->kobj, &amp;fu_ktype, NULL, \"%s\", name);\n    if (retval) {\n        kobject_put(&amp;fu->kobj);\n        return NULL;\n    }\n\n    return fu;\n}\n\nstatic void destroy_fu_obj(struct fu_obj *fu)\n{\n    kobject_put(&amp;fu->kobj);\n}\n\nstatic int __init example_init(void)\n{\n    \/*\n     * Create a kset with the name of \"ks_a\",\n     * located under \/sys\/kernel\/\n     *\/\n    ks_a = kset_create_and_add(\"ks_a\", NULL, kernel_kobj);\n    if (!ks_a)\n        return -ENOMEM;\n\n    \/*\n     * Create fu object and register it with our kset\n     *\/\n    fu_a = create_fu_obj(\"fu_a\");\n    if (!fu_a)\n        return -EINVAL;\n    else\n        return 0;\n}\n\nstatic void __exit example_exit(void)\n{\n    destroy_fu_obj(fu_a);\n    kset_unregister(ks_a);\n}\n\nmodule_init(example_init);\nmodule_exit(example_exit);\nMODULE_LICENSE(\"GPL\");<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":1,"featured_media":0,"parent":127,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-445","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"http:\/\/bitas.net.cn\/index.php\/wp-json\/wp\/v2\/pages\/445","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/bitas.net.cn\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"http:\/\/bitas.net.cn\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"http:\/\/bitas.net.cn\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/bitas.net.cn\/index.php\/wp-json\/wp\/v2\/comments?post=445"}],"version-history":[{"count":1,"href":"http:\/\/bitas.net.cn\/index.php\/wp-json\/wp\/v2\/pages\/445\/revisions"}],"predecessor-version":[{"id":446,"href":"http:\/\/bitas.net.cn\/index.php\/wp-json\/wp\/v2\/pages\/445\/revisions\/446"}],"up":[{"embeddable":true,"href":"http:\/\/bitas.net.cn\/index.php\/wp-json\/wp\/v2\/pages\/127"}],"wp:attachment":[{"href":"http:\/\/bitas.net.cn\/index.php\/wp-json\/wp\/v2\/media?parent=445"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}