爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      ldd3学习之十一(2):Linux设备模型---总线、设备、驱动

      首页 知识中心 物联网 文章详情页

      ldd3学习之十一(2):Linux设备模型---总线、设备、驱动

      2024-09-24 06:31:02 阅读次数:94

      linux,struct,总线

      随着技术的不断进步,系统拓扑接口越来越复杂,对智能电源管理、热插拔支持要求也越来越高,为适应这些需求,2.6内核提供了全新的内核设备模型。设备模型三元素:总线、设备、驱动。另:采用总线模型,极大的提高程序可移植性。

      1.总线

      总线就是处理器与设备(包括SOC设备,比如SPI控制器)之间的通道,在设备模型中,所有的设备都通过总线相连,Linux的虚拟总线platform总线。在Linux设备模型中,总线由bus_type结构表示,在 定义

      1. struct bus_type {
      2. const char * name;/*总线类型名称*/
      3. * owner;/*指向模块的指针(如果有), 此模块负责操作这个总线*/
      4.  
      5. ;/*与该总线相关的子系统*/
      6. ;/*总线驱动程序的kset*/
      7. ;/* 挂在该总线的所有设备的kset*/
      8.  
      9. ;/*与该总线相关的驱动程序链表*/
      10. ;/*挂接在该总线的设备链表*/
      11.  
      12. ;
      13.  
      14. * bus_attrs; /*总线属性*/
      15. * dev_attrs; /*设备属性,指向为每个加入总线的设备建立的默认属性链表*/
      16. * drv_attrs; /*驱动程序属性*/
      17. ;/*驱动自动探测属性*/
      18. ;/*驱动探测属性*/
      19.  
      20. int (*match)(struct device * dev, struct device_driver * drv);
      21. int (*uevent)(struct device *dev, char **envp,
      22. int num_envp, char *buffer, int buffer_size);
      23. int (*probe)(struct device * dev);
      24. int (*remove)(struct device * dev);
      25. (*shutdown)(struct device * dev);
      26.  
      27. int (*suspend)(struct device * dev, pm_message_t state);
      28. int (*suspend_late)(struct device * dev, pm_message_t state);
      29. int (*resume_early)(struct device * dev);
      30. (*resume)(struct device * dev);
      31. /*处理热插拔、电源管理、探测和移除等事件的方法*/
      32. int drivers_autoprobe:1;
      33. };

      在新版内核中,这个结构体更简洁,隐藏了无需驱动知道的一些成员:

      1. /*linux-3.1.6*/
      2. struct bus_type {
      3. const char        *name;
      4. *bus_attrs;
      5. *dev_attrs;
      6. *drv_attrs;
      7.  
      8. int (*match)(struct device *dev, struct device_driver *drv);
      9. int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
      10. int (*probe)(struct device *dev);
      11. int (*remove)(struct device *dev);
      12. (*shutdown)(struct device *dev);
      13.  
      14. int (*suspend)(struct device *dev, pm_message_t state);
      15. int (*resume)(struct device *dev);
      16.  
      17. const struct dev_pm_ops *pm;
      18.  
      19. *p;
      20. };

      (1)总线注册过程:

      ① 申明和初始化 bus_type 结构体。只有很少的 bus_type 成员需要初始化,大部分都由设备模型核心控制。但必须为总线指定名字及一些必要的方法。例如

      1. struct bus_type my_bus_type = {
      2. .name = "my_bus",
      3. .match = my_match,
      4. };

      ②调用bus_register函数注册总线

      1. int bus_register(struct bus_type * bus)

      调用可能失败, 所以必须始终检查返回值。若成功,新的总线子系统将被添加进系统,并可在 sysfs 的 /sys/bus 下看到。之后可以向总线添加设备。

      1. ret = bus_register(&my_bus_type);
      2. if (ret)
      3. ;

      ③总线删除:

      1. void bus_unregister(struct bus_type *bus)

      (2)总线方法:

      在 bus_type 结构中定义了许多方法,它们允许总线核心作为设备核心和单独的驱动程序之间提供服务的中介,主要介绍以下两个方法:

      1. int (*match)(struct device * dev, struct device_driver * drv);
      2. /*当一个新设备或者驱动被添加到这个总线时,这个方法会被调用一次或多次,若指定的驱动程序能够处理指定的设备,则返回非零值。*/
      3.  
      4. int (*uevent)(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size);
      5. /*在为用户空间产生热插拔事件之前,这个方法允许总线添加环境变量(参数和 kset 的uevent方法相同)*/

      例如:

      1. static int my_match(struct device *dev, struct device_driver *driver)
      2. {
      3. !strncmp(dev->bus_id, driver->name, strlen(driver->name));
      4. }

      (3)对设备和驱动的迭代

      若要编写总线层代码, 可能不得不对所有已经注册到总线的设备或驱动进行一些操作,这可能需要仔细研究嵌入到 bus_type 结构中的其他数据结构, 但最好使用内核提供的辅助函数:

      1. int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn)(struct device *, void *));
      2. int bus_for_each_drv(struct bus_type *bus, struct device_driver *start, void *data, int (*fn)(struct device_driver *, void *));
      3.  
      4. /*这两个函数迭代总线上的每个设备或驱动程序, 将关联的 device 或 device_driver 传递给 fn, 同时传递 data 值。若 start 为 NULL, 则从第一个设备开始; 否则从 start 之后的第一个设备开始。若 fn 返回非零值, 迭代停止并且那个值从 bus_for_each_dev 或bus_for_each_drv 返回。*/

      (4)总线属性

      几乎 Linux 设备模型中的每一层都提供添加属性的函数, 总线层也不例外。bus_attribute 类型定义在 如下:

      1. struct bus_attribute {
      2. ;
      3. (*show)(struct bus_type *, char * buf);
      4. (*store)(struct bus_type *, const char * buf, size_t count);
      5. };

      可以看出struct bus_attribute 和struct attribute 很相似,其实大部分在 kobject 级上的设备模型层都是以这种方式工作。

      内核提供了一个宏在编译时创建和初始化 bus_attribute 结构:

      1. BUS_ATTR(_name,_mode,_show,_store)/*这个宏声明一个结构, 将 bus_attr_ 作为给定 _name 的前缀来创建总线的真正名称*/
      2.  
      3. /*总线的属性必须显式调用 bus_create_file 来创建:*/
      4. int bus_create_file(struct bus_type *bus, struct bus_attribute *attr);
      5.  
      6. /*删除总线的属性调用:*/
      7. (struct bus_type *bus, struct bus_attribute *attr);

      例如:

      1. /*
      2. * Export a simple attribute.
      3. */
      4. (struct bus_type *bus, char *buf)
      5. {
      6. (buf, PAGE_SIZE, "%s\n", Version);
      7. }
      8.  
      9. (version_file, S_IRUGO, show_bus_version, NULL);
      10. //将会在/sys/bus/my_bus/下显示version_file文件
      11. if (bus_create_file(&my_bus_type, &bus_attr_version_file))
      12. printk(KERN_NOTICE "Fail to create version attribute!\n");

      2.设备

      Linux 系统中的每个设备由一个 struct device 代表:

      1. struct device {
      2. ;
      3. ; /* node in sibling list */
      4. ;
      5. ;
      6. *parent;/* 设备的 "父" 设备,该设备所属的设备,通常一个父设备是某种总线或者主控制器. 如果 parent 是 NULL, 则该设备是顶层设备,较少见 */
      7.  
      8. ;/*代表该设备并将其连接到结构体系中的 kobject; 注意:作为通用的规则, device->kobj->parent 应等于 device->parent->kobj*/
      9. [BUS_ID_SIZE];/*在总线上唯一标识该设备的字符串;例如: PCI 设备使用标准的 PCI ID 格式, 包含:域, 总线, 设备, 和功能号.*/
      10. *type;
      11. :1;
      12. :1;
      13. ;
      14. *devt_attr;
      15.  
      16. ; /* semaphore to synchronize calls to its driver. */
      17. * bus; /*标识该设备连接在何种类型的总线上*/
      18. *driver; /*管理该设备的驱动程序*/
      19. *driver_data; /*该设备驱动使用的私有数据成员*/
      20. *platform_data; /* Platform specific data, device core doesn't touch it */
      21. ;
      22.  
      23. #ifdef CONFIG_NUMA
      24. int numa_node; /* NUMA node this device is close to */
      25. #endif
      26. *dma_mask; /* dma mask (if dma'able device) */
      27. ;/* Like dma_mask, but for
      28.                      alloc_coherent mappings as
      29. not all hardware supports
      30. for consistent
      31. . */
      32.  
      33. ; /* dma pools (if dma'ble) */
      34.  
      35. *dma_mem; /* internal for coherent mem override */
      36. /* arch specific additions */
      37. ;
      38.  
      39. ;
      40. ;
      41.  
      42. /* class_device migration path */
      43. ;
      44. class *class;
      45. ; /* dev_t, creates the sysfs "dev" */
      46. **groups; /* optional groups */
      47.  
      48. (*release)(struct device * dev);/*当这个设备的最后引用被删除时,内核调用该方法; 它从被嵌入的 kobject 的 release 方法中调用。所有注册到核心的设备结构必须有一个 release 方法, 否则内核将打印错误信息*/
      49. };
      50. /*在注册 struct device 前,最少要设置parent, bus_id, bus, 和 release 成员*/

      (1)设备注册

      1. int device_register(struct device *dev);
      2. (struct device *dev);

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

      1.  
      2. static void my_bus_release(struct device *dev)
      3. {
      4. printk(KERN_DEBUG "my bus release\n");
      5. }
      6.  
      7. struct device my_bus_dev = {
      8. .bus_id   = "my_bus0",
      9. .release  = my_bus_release
      10. };
      11. /*注册总线设备*/
      12. = device_register(&my_bus_dev);
      13. if (ret)
      14. (KERN_NOTICE "Fail to register device:my_bus!\n");

      (2)设备属性

      sysfs 中的设备入口可有属性,相关的结构是:

      1. /* interface for exporting device attributes 这个结构体和《LDD3》中的不同,已经被更新过了,请特别注意!*/
      2. {
      3. ;
      4. (*show)(struct device *dev, struct device_attribute *attr,char *buf);
      5. (*store)(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
      6. };
      7.  
      8. /*设备属性结构可在编译时建立, 使用以下宏:*/
      9. (_name,_mode,_show,_store);
      10. /*这个宏声明一个结构, 将 dev_attr_ 作为给定 _name 的前缀来命名设备属性
      11.  
      12. /*属性文件的实际处理使用以下函数:*/
      13. int device_create_file(struct device *device, struct device_attribute * entry);
      14. (struct device * dev, struct device_attribute * attr);

      (3)设备结构的嵌入

      device 结构包含设备模型核心用来模拟系统的信息。但大部分子系统记录了关于它们又拥有的设备的额外信息,所以很少单纯用 device 结构代表设备,而是,通常将其嵌入一个设备的高层表示中。底层驱动几乎不知道 struct device。

      lddbus 驱动创建了它自己的 device 类型,并期望每个设备驱动使用这个类型来注册它们的设备:

      struct ldd_device {
       char *name;
       struct ldd_driver *driver;
       struct device dev; 
      }; 
      #define to_ldd_device(dev) container_of(dev, struct ldd_device, dev);

      lddbus 导出的注册和注销接口如下:

      /*
       * LDD devices.
       */

      /*
       * For now, no references to LDDbus devices go out which are not
       * tracked via the module reference count, so we use a no-op
       * release function.
       */
      static void ldd_dev_release(struct device *dev)
      { }

      int register_ldd_device(struct ldd_device *ldddev)
      {
          ldddev->dev.bus = &ldd_bus_type;
          ldddev->dev.parent = &ldd_bus;
          ldddev->dev.release = ldd_dev_release;
          strncpy(ldddev->dev.bus_id, ldddev->name, BUS_ID_SIZE);
          return device_register(&ldddev->dev);
      }
      EXPORT_SYMBOL(register_ldd_device);

      void unregister_ldd_device(struct ldd_device *ldddev)
      {
          device_unregister(&ldddev->dev);
      }
      EXPORT_SYMBOL(unregister_ldd_device);

       

       

       

      3.设备驱动程序

      (1)驱动定义

      1. /*定义在<linux/device.h>*/
      2. {
      3. const char * name;/*驱动程序的名字( 在 sysfs 中出现 )*/
      4. * bus;/*驱动程序所操作的总线类型*/
      5.  
      6. ;/*内嵌的kobject对象*/
      7. ;/*当前驱动程序能操作的设备链表*/
      8. ;
      9.  
      10. * owner;
      11. const char * mod_name; /* used for built-in modules */
      12. * mkobj;
      13.  
      14. int (*probe) (struct device * dev);/*查询一个特定设备是否存在及驱动是否可以使用它的函数*/
      15. int (*remove) (struct device * dev);/*将设备从系统中删除*/
      16. (*shutdown) (struct device * dev);/*关闭设备*/
      17. int (*suspend) (struct device * dev, pm_message_t state);
      18. int (*resume) (struct device * dev);
      19. };
      20.  
      21. /*注册device_driver 结构的函数是:*/
      22. int driver_register(struct device_driver *drv);
      23. (struct device_driver *drv);
      24.  
      25. /*driver的属性结构在:*/
      26. {
      27. ;
      28. (*show)(struct device_driver *drv, char *buf);
      29. (*store)(struct device_driver *drv, const char *buf, size_t count);
      30. };
      31. (_name,_mode,_show,_store)
      32.  
      33. /*属性文件创建的方法:*/
      34. int driver_create_file(struct device_driver * drv, struct driver_attribute * attr);
      35. (struct device_driver * drv, struct driver_attribute * attr);
      36.  
      37. /*bus_type 结构含有一个成员( drv_attrs ) 指向一组为属于该总线的所有设备创建的默认属性*/

      在新版内核中,这个结构体更简洁,隐藏了无需驱动知道的一些成员:

      1. struct device_driver {
      2.  const char        *name;
      3.  struct bus_type        *bus;
      4.  
      5. *owner;
      6. const char        *mod_name;    /* used for built-in modules */
      7.  
      8. ;    /* disables bind/unbind via sysfs */
      9.  
      10. const struct of_device_id    *of_match_table;
      11.  
      12.  int (*probe) (struct device *dev);
      13.  int (*remove) (struct device *dev);
      14. void (*shutdown) (struct device *dev);
      15. int (*suspend) (struct device *dev, pm_message_t state);
      16. int (*resume) (struct device *dev);
      17. const struct attribute_group **groups;
      18.  
      19. const struct dev_pm_ops *pm;
      20.  
      21. *p;
      22. };
      23.  
      24. struct driver_private {
      25. struct kobject kobj;
      26. struct klist klist_devices;
      27. struct klist_node knode_bus;
      28. struct module_kobject *mkobj;
      29. struct device_driver *driver;
      30. };
      31. #define to_driver(obj) container_of(obj, struct driver_private, kobj)

      (2)驱动程序结构的嵌入

      对大多数驱动程序核心结构, device_driver 结构通常被嵌入到一个更高层的、总线相关的结构中。

      以lddbus 子系统为例,它定义了ldd_driver 结构:

      struct ldd_driver {
       char *version;
       struct module *module;
       struct device_driver driver;
       struct driver_attribute version_attr; 
      }; 
      #define to_ldd_driver(drv) container_of(drv, struct ldd_driver, driver);

      lddbus总线中相关的驱动注册和注销函数是:

      /*
       * Crude driver interface.
       */
      static ssize_t show_version(struct device_driver *driver, char *buf)
      {
          struct ldd_driver *ldriver = to_ldd_driver(driver);
          sprintf(buf, "%s\n", ldriver->version);
          return strlen(buf);
      }

      int register_ldd_driver(struct ldd_driver *driver)
      {
       int ret;
       driver->driver.bus = &ldd_bus_type;
       ret = driver_register(&driver->driver);/*注册底层的 device_driver 结构到核心*/
       if (ret)
       return ret;
       driver-> = "version";/* driver_attribute 结构必须手工填充*/
       driver->version_attr.attr.owner = driver->module;/*注意:设定 version 属性的拥有者为驱动模块, 不是 lddbus 模块!因为 show_version 函数是使用驱动模块所创建的 ldd_driver 结构,若 ldd_driver 结构在一个用户空间进程试图读取版本号时已经注销,就会出错*/
       driver->version_attr.attr.mode = S_IRUGO;
       driver->version_attr.show = show_version;
       driver->version_attr.store = NULL;
       return driver_create_file(&driver->driver, &driver->version_attr);/*建立版本属性,因为这个属性在运行时被创建,所以不能使用 DRIVER_ATTR 宏*/
      }

      void unregister_ldd_driver(struct ldd_driver *driver)
      {
          driver_unregister(&driver->driver);
      }
      EXPORT_SYMBOL(register_ldd_driver);
      EXPORT_SYMBOL(unregister_ldd_driver);

      在sculld 中创建的 ldd_driver 结构如下:

      /* Device model stuff */
      static struct ldd_driver sculld_driver = {
          .version = "$Revision: 1.21 $",
          .module = THIS_MODULE,
          .driver = {
              .name = "sculld",
          },
      };/*只要一个简单的 register_ldd_driver 调用就可添加它到系统中。一旦完成初始化, 驱动信息可在 sysfs 中显示*/

      类 子系统

      类是一个设备的高层视图, 它抽象出了底层的实现细节,从而允许用户空间使用设备所提供的功能, 而不用关心设备是如何连接和工作的。类成员通常由上层代码所控制, 而无需驱动的明确支持。但有些情况下驱动也需要直接处理类。

      几乎所有的类都显示在 /sys/class 目录中。出于历史的原因,有一个例外:块设备显示在 /sys/block目录中。在许多情况, 类子系统是向用户空间导出信息的最好方法。当类子系统创建一个类时, 它将完全拥有这个类,根本不用担心哪个模块拥有那些属性,而且信息的表示也比较友好。

      为了管理类,驱动程序核心导出了一些接口,其目的之一是提供包含设备号的属性以便自动创建设备节点,所以udev的使用离不开类。类函数和结构与设备模型的其他部分遵循相同的模式,所以真正崭新的概念是很少的。

      注意:class_simple 是老接口,在2.6.13中已被删除,这里不再研究。

      管理类的接口

      类由 struct class 的结构体来定义:

      /*
       * device classes
       */
      struct class {
          const char        * name;/*每个类需要一个唯一的名字, 它将显示在 /sys/class 中*/
          struct module        * owner;

          struct kset        subsys;
          struct list_head    children;
          struct list_head    devices;
          struct list_head    interfaces;
          struct kset        class_dirs;
          struct semaphore    sem;    /* locks both the children and interfaces lists */

          struct class_attribute        * class_attrs;/* 指向类属性的指针(以NULL结尾) */
          struct class_device_attribute    * class_dev_attrs;/* 指向类中每个设备的一组默认属性的指针 */
          struct device_attribute        * dev_attrs;

          int    (*uevent)(struct class_device *dev, char **envp,
                   int num_envp, char *buffer, int buffer_size);/* 类热插拔产生时添加环境变量的函数 */
          int    (*dev_uevent)(struct device *dev, char **envp, int num_envp,
                      char *buffer, int buffer_size);/* 类中的设备热插拔时添加环境变量的函数 */

          void    (*release)(struct class_device *dev);/* 把设备从类中删除的函数 */
          void    (*class_release)(struct class *class);/* 删除类本身的函数 */
          void    (*dev_release)(struct device *dev);

          int    (*suspend)(struct device *, pm_message_t state);
          int    (*resume)(struct device *);
      };


      /*类注册函数:*/
      int class_register(struct class *cls);
      void class_unregister(struct class *cls);

      /*类属性的接口:*/
      struct class_attribute {
       struct attribute attr;
       ssize_t (*show)(struct class *cls, char *buf);
       ssize_t (*store)(struct class *cls, const char *buf, size_t count); 
      }; 
      CLASS_ATTR(_name,_mode,_show,_store); 
      int class_create_file(struct class *cls, const struct class_attribute *attr);
      void class_remove_file(struct class *cls, const struct class_attribute *attr);

      在更新的内核里,这个结构体变得简洁了,删除了一些成员:

      /*in Linux 2.6.26.5*/

      /*
       * device classes
       */
      struct class {
          const char        *name;
          struct module        *owner;

          struct kset        subsys;
          struct list_head    devices;
          struct list_head    interfaces;
          struct kset        class_dirs;
          struct semaphore    sem; /* locks children, devices, interfaces */
          struct class_attribute        *class_attrs;
          struct device_attribute        *dev_attrs;

          int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);

          void (*class_release)(struct class *class);
          void (*dev_release)(struct device *dev);

          int (*suspend)(struct device *dev, pm_message_t state);
          int (*resume)(struct device *dev);
      };

      类设备(在新内核中已被删除)

      类存在的真正目的是给作为类成员的各个设备提供一个容器,成员由 struct class_device 来表示:

      struct class_device {
          struct list_head    node;/*for internal use by the driver core only*/
          struct kobject        kobj;/*for internal use by the driver core only*/
          struct class        * class;    /* 指向该设备所属的类,必须*/
          dev_t            devt;        /* dev_t, creates the sysfs "dev" ,for internal use by the driver core only*/
          struct class_device_attribute *devt_attr;/*for internal use by the driver core only*/
          struct class_device_attribute uevent_attr;
          struct device        * dev;        /* 指向此设备相关的 device 结构体,可选。若不为NULL,应是一个从类入口到/sys/devices 下相应入口的符号连接,以便用户空间查找设备入口*/
          void            * class_data;    /* 私有数据指针 */
          struct class_device    *parent;    /* parent of this child device, if there is one */
          struct attribute_group ** groups;    /* optional groups */

          void    (*release)(struct class_device *dev);
          int    (*uevent)(struct class_device *dev, char **envp,
                   int num_envp, char *buffer, int buffer_size);
          char    class_id[BUS_ID_SIZE];    /* 此类中的唯一的名字 */
      };

      /*类设备注册函数:*/
      int class_device_register(struct class_device *cd);
      void class_device_unregister(struct class_device *cd);

      /*重命名一个已经注册的类设备入口:*/
      int class_device_rename(struct class_device *cd, char *new_name); 

      /*类设备入口属性:*/
      struct class_device_attribute {
       struct attribute attr;
       ssize_t (*show)(struct class_device *cls, char *buf);
       ssize_t (*store)(struct class_device *cls, const char *buf,
       size_t count);
      };

      CLASS_DEVICE_ATTR(_name, _mode, _show, _store); 

      /*创建和删除除struct class中设备默认属性外的属性*/
      int class_device_create_file(struct class_device *cls, const struct class_device_attribute *attr);
      void class_device_remove_file(struct class_device *cls, const struct class_device_attribute *attr);

      类接口

      类子系统有一个 Linux 设备模型的其他部分找不到的附加概念,称为“接口”, 可将它理解为一种设备加入或离开类时获得信息的触发机制,结构体如下:

      struct class_interface {
          struct list_head    node;
          struct class        *class;/* 指向该接口所属的类*/

          int (*add) (struct class_device *, struct class_interface *);

      /*当一个类设备被加入到在 class_interface 结构中指定的类时, 将调用接口的 add 函数,进行一些设备需要的额外设置,通常是添加更多属性或其他的一些工作*/
          void (*remove)    (struct class_device *, struct class_interface *);/*一个接口的功能是简单明了的. 当设备从类中删除, 将调用remove 方法来进行必要的清理*/
          int (*add_dev)     (struct device *, struct class_interface *);
          void (*remove_dev) (struct device *, struct class_interface *);
      };

      /*注册或注销接口的函数:*/
      int class_interface_register(struct class_interface *class_intf);
      void class_interface_unregister(struct class_interface *class_intf);
      /*一个类可注册多个接口*/

      测试代码: device_module.rar ​​   

      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://blog.51cto.com/u_7784550/5853222,作者:luteresa,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:决策树结合网格搜索交叉验证的例子

      下一篇:提高mnist模型精确度

      相关文章

      2025-05-19 09:04:53

      查看RISC-V版本的gcc中默认定义的宏

      查看RISC-V版本的gcc中默认定义的宏

      2025-05-19 09:04:53
      c++ , linux
      2025-04-01 10:28:37

      小课2:筛选信息命令

      小课2:筛选信息命令

      2025-04-01 10:28:37
      bash , linux , 升序 , 服务器 , 运维
      2025-03-26 09:31:12

      shell脚本实现查询代码中定义了多少宏的方法

      shell脚本实现查询代码中定义了多少宏的方法

      2025-03-26 09:31:12
      bash , linux , 运维
      2025-03-21 06:57:11

      存储基本概念(lun,volume,HBA,DAS,NAS,SAN,iSCSI,IPSAN、存储池和存储卷)

      存储基本概念(lun,volume,HBA,DAS,NAS,SAN,iSCSI,IPSAN、存储池和存储卷)

      2025-03-21 06:57:11
      一个 , 总线 , 硬盘 , 适配器
      2025-03-06 09:15:26

      spring cloud系统安装涉及的技术说明

      spring cloud系统安装涉及的技术说明

      2025-03-06 09:15:26
      docker , linux , 安装 , 技术
      2025-03-05 09:24:43

      【Python】使用numpy库实现Tic-Tac-Toe井字棋

      【Python】使用numpy库实现Tic-Tac-Toe井字棋

      2025-03-05 09:24:43
      linux , 右键 , 安装 , 打开 , 输入
      2025-03-05 09:23:32

      【python C结构体】Python Ctypes结构体指针处理(函数参数,函数返回)

      【python C结构体】Python Ctypes结构体指针处理(函数参数,函数返回)

      2025-03-05 09:23:32
      char , int , python , struct , test
      2025-02-26 07:22:00

      【verbs】ibv_get_device_name()|ibv_get_device_list()|verbs api

      【verbs】ibv_get_device_name()|ibv_get_device_list()|verbs api

      2025-02-26 07:22:00
      ibv , IBV , qp , QP , struct
      2025-02-21 08:56:54

      【RDMA】ibv_create_qp, ibv_destroy_qp

      【RDMA】ibv_create_qp, ibv_destroy_qp

      2025-02-21 08:56:54
      ibv , qp , QP , struct
      2025-02-10 08:54:20

      C语言基础之——结构体

      结构体是为了用来描述复杂对象而创建的一种数据类型。

      2025-02-10 08:54:20
      struct , 初始化 , 变量 , 成员 , 数据类型 , 结构 , 访问
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5243687

      查看更多

      最新文章

      # **七、时间管理**

      2024-05-29 07:56:46

      查看更多

      热门文章

      # **七、时间管理**

      2024-05-29 07:56:46

      查看更多

      热门标签

      模型 生成 学习 django python 图像 训练
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      # **七、时间管理**

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号