Linux内核驱动之设备

时间:2022-05-18 10:42:31

原文地址:Linux内核驱动之设备 作者:luozhiyong131

在最底层, Linux 系统中的每个设备由一个 struct device 代表:

点击(此处)折叠或打开

  1. struct device {
  2. ………………………………
  3.     struct device *parent;/* 设备的 "父" 设备,该设备所属的设备,通常一个父设备是某种总线或者主控制器. 如果 parent 是 NULL, 则该设备是顶层设备,较少见 */
  4. struct kobject kobj;
  5. char bus_id[BUS_ID_SIZE];
  6. struct bus_type *bus; /* 设备所在总线*/
  7. struct device_driver *driver; /*管理该设备的驱动*/
  8. void *driver_data; /*该设备驱动使用的私有数据成员*/
  9. struct klist_node knode_class;
  10. struct class *class;
  11. struct attribute_group **groups;
  12. void (*release)(struct device *dev);
  13. }

设备注册和注销:

与总线的注册一样:

1、定义结构体device

2、调用注册函数:

int device_register(struct device *dev)

函数失败返回非零,需要判断返回值来检查注册是否成功。


注意:一个实际的总线也是一个设备,所以必须单独注册

设备注销函数:

void device_unregister(struct device *dev)

设备属性

设备属性由struct device_attribute 描述:

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);

}

int device_create_file(struct device*device, struct device_attribute * entry)创建属性

void device_remove_file(struct device *dev, struct device_attribute * attr)删除属性

设置设备属性有两个步骤:

1、创建并初始化device_attribute结构,使用宏DEVICE_ATTR

DEVICE_ATTR(_name, _mode, _show, _store) 

该宏会定义一个名叫dev_attr__name(红色部分是固定的)的device_attibute的结构,并且成员name设置为_name,文件权限mode设置为_mode,两个函数调用分别人showstore

2、将device_attibute添加到指定的设备上,使用以下调用:

/*drivers/base/core.c*/

430 int device_create_file(struct device *dev, struct device_attribute *attr) 

该函数失败时返回错误号。

一旦调用该函数,会就在指定dev设备的目录下新建一个名叫_name的文件,权限为_mode,当访问和修改该文件是会分别调用showstore函数调用。


如果不需要该属性时,使用以下函数删除:

/*drivers/base/core.c*/

443 void device_remove_file(struct device *dev, struct device_attribute *attr) 

 

源码实例:

点击(此处)折叠或打开

  1. #include <linux/device.h>
  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. #include <linux/init.h>
  5. #include <linux/string.h>

  6. static char *Version = "$Revision: 1.0 $";

  7. /*当一个新设备或者驱动被添加到这个总线时,该方法被调用。用于判断指定的驱动程序是否能处理指定的设备。若可以,则返回非零值。*/
  8. static int my_match(struct device *dev, struct device_driver *driver)
  9. {
  10.         return !strncmp(dev->kobj.name, driver->name, strlen(driver->name));
  11. }
  12. static void my_bus_release(struct device *dev)
  13. {
  14.         printk(KERN_DEBUG "my bus releasen");
  15. }

  16. /*声明总线*/
  17. struct bus_type my_bus_type = {
  18.         .name = "my_bus", //总线名字
  19.         .match = my_match, //总线match函数指针
  20. };

  21. struct device my_bus = {
  22.         .kobj.name = "my_bus0",
  23.         .release = my_bus_release,
  24.       // .bus = &my_bus_type
  25. };

  26. EXPORT_SYMBOL(my_bus); //导出my_bus
  27. EXPORT_SYMBOL(my_bus_type); //导出my_bus_type

  28. static ssize_t show_bus_version(struct bus_type *bus, char *buf)
  29. {
  30.         return snprintf(buf, PAGE_SIZE, "%sn", Version);
  31. }

  32. /*内核代码中如此定义:#define BUS_ATTR(_name, _mode, _show, _store) 
  33. struct bus_attribute bus_attr_##_name = __ATTR(_name, _mode, _show, _store),
  34. 它将bus_attr_作为给定的name的前缀来创建总线的真正名称。对应下面的是bus_attr_version*/
  35. static BUS_ATTR(version, S_IRUGO, show_bus_version, NULL);

  36. /*模块加载函数*/
  37. static int __init my_bus_init(void)
  38. {
  39.         int ret=0;

  40.         /*注册总线*/
  41.         ret = bus_register(&my_bus_type);
  42.         if (ret)
  43.                 return ret;

  44.         /*创建属性文件*/
  45.         if (bus_create_file(&my_bus_type, &bus_attr_version))
  46.                 printk(KERN_NOTICE "Fail to create version attribute!n");
  47.         
  48.          /*注册总线设备*/
  49.         ret = device_register(&my_bus);
  50.         if (ret)
  51.                 printk( "<0> Fail to register device:my_bus!n");
  52.     
  53.         return ret;
  54. }

  55. /*模块卸载函数*/
  56. static void my_bus_exit(void)
  57. {
  58.         device_unregister(&my_bus);
  59.         bus_unregister(&my_bus_type);
  60. }

  61. module_init(my_bus_init); 
  62. module_exit(my_bus_exit);

  63. MODULE_AUTHOR("Lzy");
  64. MODULE_LICENSE("GPL");

点击(此处)折叠或打开

  1. #include <linux/device.h>
  2. #include <linux/module.h>
  3. #include <linux/kernel.h>
  4. #include <linux/init.h>
  5. #include <linux/string.h>

  6. extern struct device my_bus;
  7. extern struct bus_type my_bus_type;

  8.  // 必须要
  9. static void my_dev_release(struct device *dev)
  10. {

  11. }

  12. struct device my_dev = {
  13.         .init_name = "my_dev",
  14.         .bus = &my_bus_type, //指明设备所属的总线
  15.         .parent = &my_bus, //该设备的父设备,总线也是一种设备
  16.         .release = my_dev_release,
  17. };

  18. static ssize_t mydev_show(struct device *dev,struct device_attribute *attr, char *buf)
  19. {
  20.         return sprintf(buf, "%sn", "This is my device!");
  21. }

  22. static DEVICE_ATTR(dev, S_IRUGO, mydev_show, NULL);

  23. static int __init my_device_init(void)
  24. {
  25.     int ret = 0;

  26.     /* 初始化设备 */
  27.     ///strncpy(my_dev->kobj.name, "my_dev", strlen(my_dev->name));

  28.     /*注册设备*/
  29.     device_register(&my_dev);
  30.     
  31.     /*创建属性文件*/
  32.     device_create_file(&my_dev, &dev_attr_dev);
  33.     
  34.     return ret;        
  35. }

  36. static void my_device_exit(void)
  37. {
  38.         device_unregister(&my_dev);
  39. }

  40. module_init(my_device_init);
  41. module_exit(my_device_exit);

  42. MODULE_AUTHOR("Lzy");
  43. MODULE_LICENSE("GPL");