linux驱动在sys下添加读写属性

class_create
用来创建一个类,存放于sysfs下面,卸载时配套使用class_destroy

device_create
在/dev/目录下创建相应的设备节点,在加载模块的时候,用户空间的udev会自动响应device_create函数,去/sysfs下寻找对应的类似而创建设备节点,卸载时配套使用 device_destroy

device_create_file
实际调用sysfs_create_file,可以在/sys/(注意这里不一定是/sys/class下,由参数一确定)下创建对应的属性文件,从而通过对该文件的读写属性实现特定的数据操作,卸载是自动会把节点删除

下面以misc设备和普通字符设备为例说明一下如何使用上面三个函数在驱动中添加读写属性

注:对于misc设备,不需要我们去执行class_create和device_create。因为在misc_register进行设备注册的时候,就已经自动执行了,所以只需要在注册完设备后,再添加相应的读写属性即可。当然也不需要我们去调用class_destroy和device_destroy来释放资源,因为misc本身做了处理。

#include <linux/init.h>
#include <linux/module.h>
#include <linux/device.h> 
#include <linux/platform_device.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/slab.h>  
#include <linux/kobject.h>  

//#define MISC_DEVICE

#define HELLO_MINORS    256
#define HELLO_MAJOR     125

#define DRIVER_NAME "hello_driver"//驱动名字
#define DEVICE_NAME "hello_device"//生成的设备节点名字

static int value=0;

#ifdef MISC_DEVICE

#else
static struct class *hello_dev_class;
#endif

//对应应用层的write
static ssize_t att_store(struct device *dev,   
                    struct device_attribute *attr,   
                    const char *buf, size_t count)   
{  
    value = simple_strtoul(buf, NULL, 10);

    printk("value:%d\n", value);

    return count;  
}  
//对应应用层的read
static ssize_t att_show(struct device *dev,  
                 struct device_attribute *attr,  
                 char *buf)  
{  
        int val=0;

        val=sprintf(buf, "%d\n",value);

        return val;     
}  

static DEVICE_ATTR(test,0777,att_show,att_store);  

static int hello_release(struct inode *inode, struct file *file){
    printk("hello release\n");
    return 0;
}

static int hello_open(struct inode *inode, struct file *file){
    printk("hello open\n");
    return 0;
}

static struct file_operations hello_ops = {
    .owner = THIS_MODULE,
    .open = hello_open,
    .release = hello_release,
};

#ifdef MISC_DEVICE
static  struct miscdevice hello_dev = {
    .minor = MISC_DYNAMIC_MINOR,
    .name = DEVICE_NAME,//设备节点名
    .fops = &hello_ops,
};
#endif

#ifdef MISC_DEVICE
//如果总线匹配成功 就会执行probe函数
static int hello_probe(struct platform_device *pdv){

        int ret = 0;
    printk("hello_probe\n");
    misc_register(&hello_dev);

        //在删除设备的时候自动删除该节点

        //由于对应的节点   /sys/devices/platform/hello_driver/test
        //ret = device_create_file(&pdv->dev, &dev_attr_test);

        //在/sys/class/misc/hello_device/test
        ret =   device_create_file(hello_dev.this_device, &dev_attr_test);

        if(ret)
            printk("create enable file for hello_device err!\n");

    return ret;  
}
#else  //普通字符设备
static int hello_probe(struct platform_device *pdv){

        int ret;
        struct device *dev;

        //参数二的名字不是作为设备名 仅仅是作为kobject里面的标识 kobject_set_name(&cdev->kobj, "%s", name)
        ret= register_chrdev(HELLO_MAJOR,DEVICE_NAME,&hello_ops );

        if(ret) {
            pr_info(KERN_ERR "%s:register chrdev failed\n",__FILE__);
            return ret;
        }

        hello_dev_class=class_create(THIS_MODULE,"hello_dev");
        if (IS_ERR(hello_dev_class)) {
            ret = PTR_ERR(hello_dev_class);
            class_destroy(hello_dev_class);
        }

        //生成设备 /dev/hello_device       /dev/char/125:256
        //参数二为指向的父设备NULL
        dev = device_create(hello_dev_class, NULL, MKDEV(HELLO_MAJOR,HELLO_MINORS), NULL, "%s", DEVICE_NAME);
        if (IS_ERR(dev))    {
            ret = PTR_ERR(dev);
            return ret;
        }

        //在删除设备的时候自动删除该节点
        //生成节点位置/sys/class/hello_dev/hello_device/device/test
        ret = device_create_file(dev, &dev_attr_test);
        if(ret)
            printk("create enable file for hello_device err!\n");

        return ret;
}
#endif

static int hello_remove(struct platform_device *pdv){

        printk("hello_remove\n");   

#ifdef MISC_DEVICE    
    misc_deregister(&hello_dev);
#endif

    return 0;
}

static void hello_shutdown(struct platform_device *pdv){

    ;
}

static int hello_suspend(struct platform_device *pdv,pm_message_t pmt){

    return 0;
}

static int hello_resume(struct platform_device *pdv){

    return 0;
}

//创建设备
static struct platform_device hello_device=  
{  
    .name = DRIVER_NAME,  //用于总线匹配
    .id = -1,  
}; 

//创建驱动
struct platform_driver hello_driver = {
    .probe = hello_probe,
    .remove = hello_remove,
    .shutdown = hello_shutdown,
    .suspend = hello_suspend,
    .resume = hello_resume,
    .driver = {
        .name = DRIVER_NAME, //用于总线匹配
        .owner = THIS_MODULE,
    }
};

static int hello_init(void)
{
    int DriverState;

        //注册设备
    platform_device_register(&hello_device);

    printk(KERN_EMERG "hello_init!\n");
    //打印信息使用dmesg查看
    //执行platform_driver_register后 适配完 就会执行
    //hello_probe,即先打印hello_probe信息,才会打印
    //tDriverState信息
    //注册驱动
    DriverState = platform_driver_register(&hello_driver);

    printk(KERN_EMERG "\tDriverState is %d\n",DriverState);
    return 0;
}

static void hello_exit(void)
{
    printk(KERN_EMERG "hello_exit!\n");

#ifdef MISC_DEVICE

#else    
    unregister_chrdev(HELLO_MAJOR,DEVICE_NAME);
    /*删除设备节点和设备类*/
    //sysfs: cannot create duplicate filename '/dev/char/125:256'
    // 如果没有正确删除或者系统已存在那么就会出现上面错误
    device_destroy(hello_dev_class, MKDEV(HELLO_MAJOR, HELLO_MINORS));
        class_destroy(hello_dev_class);
#endif
      platform_device_unregister(&hello_device); 
    platform_driver_unregister(&hello_driver);  
}

module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值