美文网首页
linux创建设备属性节点

linux创建设备属性节点

作者: 令小狐先生 | 来源:发表于2022-07-07 17:28 被阅读0次

创建sys下的属性节点. linux内核中提供有如下三个函数可以创建sys/class下的属性节点

1. device_create_file
2. driver_create_file
3. class_create_file

以上三个函数分别基于device/driver/class来创建属性控制节点,提供store和show函数接口供应用层调用
device_create_file 需要一个device作为参数,创建的属性节点在device设备节点对应的路径下,使用DEVICE_ATTR相关宏来生成属性操作函数
driver_create_file 需要一个driver作为参数,创建的属性节点在driver设备节点对应的路径下,使用DRIVER_ATTR_RW相关宏来生成属性操作函数
class_create_file 需要一个class作为参数,创建的属性节点在class设备节点对应的路径下,使用CLASS_ATTR_RW相关宏来生成属性操作函数

注意:
在最新的内核上(kernel-5.18) 有DEVICE_ATTR宏,没有 DRIVER_ATTR和CLASS_ATTR,只有DRIVER_ATTR_RW/RO/WO
和CLASS_ATTR_RW/RO/WO 这样的宏,内核将DRIVER_ATTR和CLASS_ATTR移除了,可能是基于安全角度出发
DEVICE_ATTR也有DEVICE_ATTR_RW/RO/WO. 猜测以后可能也会移除DEVICE_ATTR宏

具体可以参考
kernel/include/linux/device.h
kernel/include/linux/device/driver.h
kernel/include/linux/device/class.h

1. device_create_file

device_create_file会基于device的设备节点路径来创建属性节点,属性可以使用DEVICE_ATTR来创建

函数原型,定义在include/linux/device.h中

创建设备节点
int device_create_file(struct device *device,
                       const struct device_attribute *entry);
删除设备节点
void device_remove_file(struct device *dev,
                        const struct device_attribute *attr);

device_create_file需要一个struct device类型的参数,
该参数可以使用driver &device probe成功后传入的参数,
也可以使用device_create来手动创建,这两种情况下创建的设备节点的路径会有差异
参考实例:
device.c文件

/****************************
device 部分的代码 device.c
*****************************/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
static void demo_device_release(struct device *dev)
{    
   printk("%s,%d: Enter\n",__func__,__LINE__);  
   return;
}

static struct platform_device demo_device = { 
   .name = "demo", 
   .id = -1, 
   .dev.release = demo_device_release,
};

static int demo_device_init(void){
    printk("%s,%d: Enter\n",__func__,__LINE__); 
    return platform_device_register(&demo_device); 
}

static void demo_device_exit(void){ 
  printk("%s,%d: Enter\n",__func__,__LINE__);
  platform_device_unregister(&demo_device); 
  return;
}

MODULE_LICENSE("GPL");
module_init(demo_device_init);
module_exit(demo_device_exit);

driver.c 的示例代码

1.1 使用probe成功后传入的参数

device_create_file放到probe函数中

/**********************************
driver部分的代码 driver.c
***********************************/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/io.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/of.h>
#include <linux/of_device.h>
#define VERIFY_OCTAL_PERMISSIONS  //不定义这个无法设置为0666,只能设置为0644
static int demo_driver_probe(struct platform_device *pdev);
static  int demo_driver_remove(struct platform_device *pdev);
static ssize_t control_show(struct device *dev,struct device_attribute *attr,
             char *buf)
{  
    printk("%s,%d: Enter\n",__func__,__LINE__);
    return 0;
}

static ssize_t control_store(struct device *dev,struct device_attribute *attr,
             const char *buf, size_t count)
{ 
      if(NULL == buf || count >255 || count == 0)  
            return -1; 
       printk("%s,%d: buf: %s count:%d\n",__func__,__LINE__,buf,count); 
       return count;
}

static DEVICE_ATTR(control,0666, control_show, control_store);

static struct platform_driver demo_driver ={ 
    .probe = demo_driver_probe, 
    .driver = {
          .name = "demo", //
    },
    .remove = demo_driver_remove, 
};

static int demo_driver_probe(struct platform_device *pdev)
{
      int ret; 
      printk("%s,%d: Enter\n",__func__,__LINE__);
      ret = device_create_file(&pdev->dev, &dev_attr_control); 
      if (ret < 0){  
            printk("could not create sysfs files\n"); 
            return ret;
       }  
       return 0;
}

static int demo_driver_remove(struct platform_device *pdev)
{ 
    printk("%s,%d: Enter\n",__func__,__LINE__);
    device_remove_file(&pdev->dev, &dev_attr_control); 
    return 0;
}


static int demo_driver_init(void)
{ 
    int ret;
    printk("%s,%d: Enter\n",__func__,__LINE__);
    return platform_driver_register(&demo_driver);
}

static void demo_driver_exit(void)
{ 
    printk("%s,%d: Enter\n",__func__,__LINE__);

    platform_driver_unregister(&demo_driver); 
    return;
}

MODULE_LICENSE("GPL");
module_init(demo_driver_init);
module_exit(demo_driver_exit);

Makefile文件

ifneq ($(KERNELRELEASE),)
    obj-m:=device.o driver.o
else
    KDIR :=/lib/modules/$(shell uname -r)/build
    PWD  :=$(shell pwd)
all: 
    make -C $(KDIR) M=$(PWD) modules
clean:
    rm -f *.ko *.o *.mod.o *.symvers *.cmd  *.mod.c *.order
endif

验证步骤
将device.c和driver.c Makefile文件放到一个文件目录下,执行make命令,会生成device.ko和driver.ko

按如下步骤安装ko
sudo insmod device.ko
sudo insmod driver.ko

属性节点生成在

/sys/bus/platform/devices/demo/control

使用

cat  /sys/bus/platform/devices/demo/control,

可以看到control_show函数执行了

image.png

1.2 使用使用device_create来手动创建device

由于不需要使用probe成功后传入的参数,因此创建属性节点的操作可以放到demo_init中

/**********************************
driver部分的代码 driver.c
***********************************/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/io.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>
#include <linux/of.h>
#include <linux/of_device.h>
#define VERIFY_OCTAL_PERMISSIONS  //不定义这个无法设置为0666,只能设置为0644
static int demo_driver_probe(struct platform_device *pdev);
static  int demo_driver_remove(struct platform_device *pdev);
static ssize_t control_show(struct device *dev,struct device_attribute *attr,
             char *buf)
{  
    printk("%s,%d: Enter\n",__func__,__LINE__);
    return 0;
}

static ssize_t control_store(struct device *dev,struct device_attribute *attr,
             const char *buf, size_t count)
{ 
    if(NULL == buf || count >255 || count == 0)  
             return -1; 
       printk("%s,%d: buf: %s count:%d\n",__func__,__LINE__,buf,count); 
       return count;
}

static DEVICE_ATTR(control,0666, control_show, control_store);

static struct platform_driver demo_driver ={ 
    .probe = demo_driver_probe, 
    .driver = {
          .name = "demo", //
    },
    .remove = demo_driver_remove, 
};

static int demo_driver_probe(struct platform_device *pdev){
      int ret; 
      printk("%s,%d: Enter\n",__func__,__LINE__);
      return 0;
}

static int demo_driver_remove(struct platform_device *pdev){ 
   printk("%s,%d: Enter\n",__func__,__LINE__);
   return 0;
}

static int demo_open(struct inode *inode, struct file *file){
     printk("%s,%d: Enter",__func__,__LINE__);
     return 0;
}

static ssize_t demo_read (struct file *file, char __user *userbuf, size_t count, loff_t *offset)
{
     printk("%s,%d: Enter",__func__,__LINE__);
     return 0;
}

static ssize_t demo_write (struct file *file, const char __user *userbuf, size_t count, loff_t *offset)
{
     printk("%s,%d: Enter",__func__,__LINE__);
     return 1;
}

static struct file_operations demo_ops = 
{
    .owner = THIS_MODULE,
    .open = demo_open,
    .read = demo_read,
    .write = demo_write,
};

static int demo_major;
static struct class *demo_class;
struct device *demo_dev;

static int demo_driver_init(void)
{ 
    int ret;
    printk("%s,%d: Enter\n",__func__,__LINE__);
//1.创建一个字符设备
    demo_major = register_chrdev(0,"demo", &demo_ops);//创建一个字符设备
//2.在sys/class/下创建一个demo_class的文件夹
    demo_class = class_create(THIS_MODULE, "demo_class");   
//3. 在sys/class/demo_class/创建一个设备节点demo
    demo_dev= device_create(demo_class,NULL,MKDEV(demo_major,0),NULL,"demo");  
//4. 创建sys/class/demo_class/demo/control的属性节点
    ret = device_create_file(demo_dev, &dev_attr_control); 
    if (ret < 0){  
            printk("could not create sysfs files\n"); 
            return ret;
      }  
    return platform_driver_register(&demo_driver);
}

static void demo_driver_exit(void)
{ 
      printk("%s,%d: Enter\n",__func__,__LINE__);
//1.移除sys/class/demo_class/demo/control的属性节点
     device_remove_file(demo_dev, &dev_attr_control); 
//2.移除在sys/class/demo_class/demo
     device_destroy(demo_class,demo_dev->devt);//destory用device的设备号
//3.移除/sys/class/demo_class
     class_destroy(demo_class);

      platform_driver_unregister(&demo_driver); 
     return;
}

MODULE_LICENSE("GPL");
module_init(demo_driver_init);
module_exit(demo_driver_exit);

因为device是我们通过device_create创建的,因此属性节点路径位于
/sys/class/demo_class/demo/control

2. driver_create_file

driver_create_file于device_create_file很像,它是从driver的角度来创建属性节点,因此需要的参数为device_driver 类型。
函数原型为

extern int __must_check driver_create_file(struct device_driver *driver,
                                        const struct driver_attribute *attr);
extern void driver_remove_file(struct device_driver *driver,
                               const struct driver_attribute *attr);

driver_create_file需要的属性使用DRIVER_ATTR_RW来生成
注. 没有DRIVER_ATTR,怀疑是新的linux内核中将其移除了。
DRIVER_ATTR_RW只需要传入属性节点的name即可,属性节点的默认权限是0644
如果是只读或者只写的,可以使用DRIVER_ATTR_RO或者DRIVER_ATTR_WO来创建属性参数

示例代码

/**********************************
driver部分的代码 driver.c
***********************************/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/io.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>

static int demo_driver_probe(struct platform_device *pdev);
static  int demo_driver_remove(struct platform_device *pdev);

static ssize_t control_show(struct device_driver *dev,char *buf)
{                
    printk("%s,%d: Enter\n",__func__,__LINE__);
    return 0;
}

static ssize_t control_store(struct device_driver *driver,const char *buf, size_t count)
{ 
    if(NULL == buf || count >255 || count == 0 )  
         return -1; 
    printk("buf:%s count:%d\n",buf,count); 
    return count;
}

static DRIVER_ATTR_RW(control);

 static struct platform_driver demo_driver ={ 
    .probe = demo_driver_probe, 
    .driver.name = "demo", 
    .remove = demo_driver_remove,  
};

static int demo_driver_probe(struct platform_device *pdev){
   int ret; 
   printk("%s,%d: Enter\n",__func__,__LINE__);
   ret = driver_create_file(&demo_driver.driver, &driver_attr_control); 
   if(ret < 0) {
      printk("could not create sysfs files\n"); 
      return ret;
   }
   return 0;
}

static int demo_driver_remove(struct platform_device *pdev){ 
   printk("%s,%d: Enter\n",__func__,__LINE__);
   return 0;
}

static int demo_driver_init(void)
{ 
    int ret;
    printk("%s,%d: Enter\n",__func__,__LINE__);
    return platform_driver_register(&demo_driver);
}

static void demo_driver_exit(void)
{ 
   printk("%s,%d: Enter\n",__func__,__LINE__); 
   driver_remove_file(&demo_driver.driver, &driver_attr_control); 
   platform_driver_unregister(&demo_driver); 
   return;
}

MODULE_LICENSE("GPL");
module_init(demo_driver_init);
module_exit(demo_driver_exit);

属性节点生成在
/sys/bus/platform/drivers/demo/control

3. class_create_file

class_create_file是基于类来创建属性节点,不依赖于device或driver,使用CLASS_ATTR_RW来创建

/**********************************
driver部分的代码 driver.c
***********************************/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kdev_t.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <asm/io.h>
#include <linux/platform_device.h>
#include <linux/ioport.h>


static int demo_driver_probe(struct platform_device *pdev);
static  int demo_driver_remove(struct platform_device *pdev);

static ssize_t control_show(struct class *class, struct class_attribute *attr,
                        char *buf)
{
    printk("%s,%d: Enter\n",__func__,__LINE__);
    return 0;                           
}

 static ssize_t control_store(struct class *class, struct class_attribute *attr,
                        const char *buf, size_t count)
{ 
    if(NULL == buf || count >255 || count == 0 || strnchr(buf, count, 0x20))  
        return -1; 
    printk("buf:%s count:%d\n",buf,count); 
    return count;
}

static CLASS_ATTR_RW(control);

 static struct platform_driver demo_driver ={ 
    .probe = demo_driver_probe, 
    .driver.name = "demo", 
    .remove = demo_driver_remove,  
};

static int demo_driver_probe(struct platform_device *pdev)
{
   int ret; 
   printk("%s,%d: Enter\n",__func__,__LINE__); 
   return 0;
}

static int demo_driver_remove(struct platform_device *pdev)
{ 
   printk("%s,%d: Enter\n",__func__,__LINE__);
   return 0;
}

static struct class *demo_class;

static int demo_driver_init(void)
{ 
    int ret;
    printk("%s,%d: Enter\n",__func__,__LINE__);

    demo_class = class_create(THIS_MODULE,"demo_class");
    ret = PTR_ERR(demo_class);
    if (IS_ERR(demo_class)){
        printk("could not create sysfs files\n"); 
        return ret;
    }

    ret = class_create_file(demo_class, &class_attr_control);
    if (ret) {
        printk("could not create sysfs files\n"); 
        return ret;
    }
   return platform_driver_register(&demo_driver);
}

static void demo_driver_exit(void)
{ 
   printk("%s,%d: Enter\n",__func__,__LINE__);
   class_remove_file(demo_class, &class_attr_control);
   class_destroy(demo_class);
   platform_driver_unregister(&demo_driver); 
   return;
}

MODULE_LICENSE("GPL");
module_init(demo_driver_init);
module_exit(demo_driver_exit);

相关文章

  • linux创建设备属性节点

    创建sys下的属性节点. linux内核中提供有如下三个函数可以创建sys/class下的属性节点 以上三个函数分...

  • Linux字符设备节点创建

    mknod命令创建节点(手动创建) 代码实现节点的创建(自动创建) 错误处理函数 释放 实例

  • Neo4j-1.1 CQL-CREATE命令

    创建没有属性的节点 使用属性创建节点 在没有属性的节点之间创建关系 使用属性创建节点之间的关系 为节点或者关系创建...

  • jQuery-dom操作

    DOM节点的创建 jQuery节点创建与属性的处理 创建元素节点: 创建为属性节点: DOM节点的插入 DOM内部...

  • Linux中的链接 ln

    i节点 在Linux中创建文件时,Linux会做两件事情,第一是在设备上保留一块空间存储数据,第二是创建一个i节点...

  • Neo4j - CQL语法

    1.CREATE创建 创建一个没有属性的节点 创建具有属性的节点 创建节点与节点关系 2.MATCH & RETU...

  • Neo4j数据库学习二:create操作

    创建一个没有属性的节点 创建一个有属性的节点 给两个节点创建关系

  • 使用jQuery对DOM元素进行处理(创建,修改,删除等)

    1.DOM创建节点及节点属性 创建流程比较简单,大体如下: 创建节点(常见的:元素、属性和文本) 添加节点的一些属...

  • Javascript-节点的增删改查

    一、创建节点 创建元素节点 document.createElement("元素标签名"); 创建属性节点 d...

  • jQuery(DOM篇)

    二、DOM篇 1. DOM创建节点及节点属性 (1) 创建元素节点:$(" ")(2) 创建为本节点:$(" 我...

网友评论

      本文标题:linux创建设备属性节点

      本文链接:https://www.haomeiwen.com/subject/vkupbrtx.html