52 linux设备驱动模型的sysfs接口

来源:互联网 发布:linux 查看内存泄漏 编辑:程序博客网 时间:2024/05/21 17:37

除了在proc目录里实现驱动的简单接口外,还可以/sys目录下实现驱动接口

//在linux内核里很多结构体都包含有kobject成员. 通常每个kobject对象在/sys/目录下有对应的目录

struct kobject {    const char      *name; //显示的目录名    struct list_head    entry; //内核里用于管理kobject对象用,通过此成员加入链表    struct kobject      *parent; //也就在指定此kobject对象是在什么目录下的    struct kset     *kset;  //多个同类型(同子系统)的kobject对象的集合    struct kobj_type    *ktype; //指定当前kobject对象的类型    struct sysfs_dirent *sd; // 对应的/sys下的目录    struct kref     kref;  // 引用当前对象的计数    unsigned int state_initialized:1; //是否已初始化    unsigned int state_in_sysfs:1; //是否显示在/sys目录里    unsigned int state_add_uevent_sent:1; //已增加热插拔事件    unsigned int state_remove_uevent_sent:1; // 移除热插拔事件    unsigned int uevent_suppress:1; };

每个kobject对象表示/sys目录的一个子目录, 此目录里还可以有可读写的文件, 这些文件叫属性(attribute).
每个kobject对象创建时都带有默认的属性, 也可加入自定义的属性.

struct attribute {    const char      *name; //文件名    umode_t         mode; //权限    ...}int sysfs_create_file(struct kobject *kobj,const struct attribute  *attr); //在kobj目录下, 创建属性文件void sysfs_remove_file(struct kobject  *kobj , const   struct attribute  *attr); //移除kobj目录下的属性文件

/////////////////////////////////////////////设备的属性文件/////////////////////////////

//在linux内核的驱动模型里的device结构体struct device {    struct device       *parent;    ...    struct kobject kobj; //包含有kobject对象, 设备对象在/sys/bus/.../devices下可查看    const char      *init_name;     ...}struct device_attribute {    struct attribute    attr; //基于attribute扩展的属性    ssize_t (*show)(struct device *dev, struct device_attribute *attr,            char *buf); //读属性文件时触发调用的函数    ssize_t (*store)(struct device *dev, struct device_attribute *attr,             const char *buf, size_t count); //写属性文件时触发调用的函数}; //基于attribute扩展而来,以便为设备创建属性文件int device_create_file(struct device *dev,               const struct device_attribute *attr)  //方便为设备增加属性文件的函数{    int error = 0;    if (dev)        error = sysfs_create_file(&dev->kobj, &attr->attr); //真家伙    return error;}void device_remove_file(struct device *dev,            const struct device_attribute *attr) //方便移除设备的属性文件的函数{    if (dev)        sysfs_remove_file(&dev->kobj, &attr->attr); //真家伙}

///////////
如为平台设备增加一属性文件:
test.c

#include <linux/init.h>#include <linux/module.h>#include <linux/sysfs.h>#include <linux/platform_device.h>ssize_t myshow(struct device *dev, struct device_attribute *attr,            char *buf){    static int n = 0;    sprintf(buf, "n = %d\n", n++);    return strlen(buf);}size_t mystore(struct device *dev, struct device_attribute *attr,             const char *buf, size_t count){    printk("in mystore: %s\n", buf);    return count;}struct device_attribute attr = {    .attr = {"hello", 0644},    .show = myshow,    .store = mystore,};struct platform_device pdev = {    .name = "haha",    .id = -1,   };static int __init test_init(void){    int ret;    ret = platform_device_register(&pdev);    sysfs_create_file(&pdev.dev.kobj, &attr.attr);    return 0;}static void __exit test_exit(void){    sysfs_remove_file(&pdev.dev.kobj, &attr.attr);    platform_device_register(&pdev);}module_init(test_init);module_exit(test_exit);MODULE_LICENSE("GPL");

/////////
加载模块后, 对”/sys/bus/platform/devices/haha/hello”文件读写即可

/////////////////////////////////////////////总线的属性文件/////////////////////////////

struct bus_type {    const char      *name;    ...    struct subsys_private *p; // 里面有struct kset类型(kobject对象的集合)的成员: subsys, devices_kset, drivers_kset. 所以在"/sys/bus/xx/"总线目录下有devices目录装载挂载到总线的设备, drivers目录挂载到总线的设备驱动}struct bus_attribute {    struct attribute    attr;    ssize_t (*show)(struct bus_type *bus, char *buf);    ssize_t (*store)(struct bus_type *bus, const char *buf, size_t count);}; //为了方便总线创建属性文件封装的类型int bus_create_file(struct bus_type *bus, struct bus_attribute *attr) //为总线创建属性文件{       int error;    if (bus_get(bus)) {        error = sysfs_create_file(&bus->p->subsys.kobj, &attr->attr); //真家伙    ...}EXPORT_SYMBOL_GPL(bus_create_file);void bus_remove_file(struct bus_type *bus, struct bus_attribute *attr){    if (bus_get(bus)) {        sysfs_remove_file(&bus->p->subsys.kobj, &attr->attr); //真家伙        bus_put(bus);    }}EXPORT_SYMBOL_GPL(bus_remove_file);

/////////////////////////////////////////////设备驱动的属性文件/////////////////////////////

struct device_driver {    const char      *name;    struct bus_type     *bus;    ...        struct driver_private *p; //里有struct kobject成员kobj, 所以设备驱动注册后也会在总线的drivers目录下有一个名为name的目录.};struct driver_attribute {    struct attribute attr;    ssize_t (*show)(struct device_driver *driver, char *buf);    ssize_t (*store)(struct device_driver *driver, const char *buf,             size_t count);}; //为了方便在设备驱动目录创建属性文件封装出来的类型int driver_create_file(struct device_driver *drv,                const struct driver_attribute *attr){    int error;    if (drv)        error = sysfs_create_file(&drv->p->kobj, &attr->attr); //真家伙    ...}EXPORT_SYMBOL_GPL(driver_create_file);void driver_remove_file(struct device_driver *drv,            const struct driver_attribute *attr){    if (drv)        sysfs_remove_file(&drv->p->kobj, &attr->attr); //真家伙}EXPORT_SYMBOL_GPL(driver_remove_file);
阅读全文
0 0