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

除了在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);
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值