2021.10.11

作业:在sysfs中建立一个属性,可以通过shell更改属性,可查询

参考:Linux内核宏DEVICE_ATTR使用 - Cqlismy - 博客园 (cnblogs.com)

思路:通过驱动建立属性?查询资料得知在include/linux.h/device.h中有添加非默认属性的接口:device_attribute。在linux驱动程序编写中使用DEVICE_ATTR宏,可以定义一个struct device_attribute设备属性,再使用sysfs的API函数就可以在设备目录下创建出属性文件,当我们在驱动程序中实现了show和store函数后就可以使用cat和echo命令对创建出来的设备属性文件进行读写从而达到控制设备的功能。

结论:在驱动中实现show和store功能就可以实现属性更改和查询

需掌握的知识点:struct attribute结构体(在linux/device.h中有定义)

                             struct device_attribute(在linux/device.h中有定义)

                             宏DEVICE_ATTR的实现(在linux/device.h和linux/sysfs.h中有定义)

                             模块加载函数和模块卸载函数

                             make之后的操作

 know1:struct attribute结构体     

struct attribute {
    const char        *name;
    umode_t            mode;
#ifdef CONFIG_DEBUG_LOCK_ALLOC
    bool            ignore_lockdep:1;
    struct lock_class_key    *key;
    struct lock_class_key    skey;
#endif
};

name:属性名称 mode:属性的读写权限

know2:struct device_attribute结构体

 /* interface for exporting device attributes */
struct device_attribute {
    struct attribute    attr;
    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);
};

show:读取设备属性文件 store:写设备的属性文件

*驱动中实现后可以用cat和echo读写 

know3:DEVICE_ATTR

#define DEVICE_ATTR(_name,_mode,_show,_store)        \

        struct device_attribute dev_attribute dev_attr_##_name = __ATTR(_name,_mode,_show,_store)

宏的功能:定义一个struct device_attribute结构体变量dev_attr_name并对里面的成员进行初始化,包括struct attribute结构体里面的name和mode成员变量、实现属性文件读写的show和store函数赋值。

*代码中的"\"表示换行,无实际意义

know4:应用实例

static ssize_t  mydevice_show(struct device *dev,struct device_attribute *attr,char *buf){

        return sprintf(buf,"%s\n",mybuf);

}

static ssize_t mydevice_store(struct device *dev,struct devie_attribute *attr,const char *buf,size_t count){

        sprintf(mybuf,"%s",buf);

        return count;

}

static DEVICE_ATTR(mydevice,0644,mydevice_show,mydevice_store);

可以看出,要使用DEVICE_ATTR宏,先对_show和_store函数进行定义,再通过宏初始化。

上述代码定义了一个mydevice的属性文件,这个属性文件的读写权限为:拥有者可以读写,所属组和其他人只能读。cat和echo命令会调用到上面写的show和store函数。

*权限:0644:用户具有读写权限,组和其他用户具有只读权限

        0755:用户具有读写执行权限,组和其他用户具有只读权限

        一般,目录0755,文件0644权限

*ssize_t表示有符号整形,在32位机器上等同int,在64位机器上等同long int;size_t表示无符号整形,unsigned long/unsigned int 

*const:定义一个在整个作用域值都不能被改变的变量

know5:加载模块

static int __init mydevice_init(void){

        int ret;

        struct device *mydevice;

        major = register_chrdev(0,"mydevice",&myfops);

        if(major<0){

                ret = major;

                return ret;

        }

        myclass = class_create(THIS_MODULE,"myclass");

        if(IS_ERR(myclass)){

        ret = -EBUSY;

        goto fail;

        }

        mydevice = device_create(myclass,NULL,MKDEV(major,0),NULL,"mydevice");

        if(IS_ERR(mydevice)){

        class_destory(myclass);

        ret = -EBUSY;

        goto fail;

        }

        ret = sysfs_create_file(&mydevice->kobj,&dev_attr_mydevice.attr);

        if(ret<0)

                return ret;

        return 0;

fail:

        unregister_chrdev(major,"mydevice");

        return ret;

}

register_chrdev()完成对主设备号的动态申请,且注册设备名称为mydevice,再用class_create()和device_create()在sysfs中动态创建出设备所属的类myclass和设备mydevice并对返回结果进行了错误检测,最后使用sysfs的API函数在sys中创建出设备的属性文件,完成模块加载。

*register_chrdev()是注册设备驱动程序的内核函数,需要的参数:

        major,主设备号,当设置为0时内核会动态分配一个设备号

        baseminor:次设备号,在一定范围内从0开始

        count:次设备号的范围

        name:设备名称

        fops:文件系统的接口指针

在上述代码中主设备号是动态分配的,没有使用次设备号。因此baseminor和count都没有出现。当major为0时且正常注册后,返回分配的主设备号;注册失败则返回-EBUSY。当major不为0时,若指定的major值已有注册的设备,返回-EBUSY;注册成功则返回0.

*卸载模块使用device_destory(myclass,MKDEV(major,0)),class_destory(myclass),unregister_chrdev(major,"mydevice")

*MKDEV宏:MKDEV(MAJOR,MINOR)获取设备在设备表中的位置,major为主设备号,minor为次设备号,为0表示不能使用

*__函数代表内核级函数

know6:模块编译运行

将文件保存为test_cha.c

编写makefile,后在命令行:

make

sudo insmod test_cha.ko

sudo dmesg

cd /sys/device/virtual/myclass/mydevice/

ls

可以看到其中有我们创建的属性文件mydevice。

*sys/device/virtual中存放的是我们创建的东西

用cat和echo进行测试。

cat mydevice

echo "success">mydevice 

这里如果使用su进入root用户模式后可以直接这么操作,但如果没有进入该模式,只用sudo是无法解决权限不足的情况的,需要使用sudo bash -c 'echo "success">mydevice',就不会报错了。

这之后再用cat获取mydevice的值,就可以看到改变了。 

上一篇:C# 反射 通过类名创建类实例


下一篇:让你的WPF程序在Win7下呈现Win8风格主题