良许Linux教程网 干货合集 Linux Driver详解

Linux Driver详解

Linux Driver即Linux 驱动,linux 系统设计将设备驱动纳入了文件系统,任何一个Linux驱动都需要有一个设备文件,否则应用程序将无法与驱动程序交互,下面良许教程网为大家详细讲解一下Linux Driver。

u=3635442949,203735331&fm=26&gp=0

设备分类

  • 字符设备

  • 块设备

  • 网络设备

驱动在kernel中的位置

linux 系统设计将设备驱动纳入了文件系统, 这里写图片描述

更为具体的分层调用结构如下所示: 这里写图片描述

Linux Device Model

usb 设备的驱动设备模型:

这里写图片描述

设备文件的节点记录的信息:

  • 文件类型

  • 主设备号

  • 次设备号 主设备号和类型决定了驱动的类型及其界面,而次设备号则说明是同类设备中的第几个设备。

devfs 文件系统

在linux 2.4 引入,主要优点:

  • 可以通过程序在设备初始化时在/dev目录下创建设备文件,卸载设备时将它 删除。

  • 设备驱动程序可以指定设备名、所有者和权限位,用户空间程序仍可以修改 所有者和权限位。

  • 不再需要为设备驱动程序分配主设备号以及处理次设备号,在程序中可以直 接给 register_chrdev()传递 0 主设备号以动态获得可用的主设备号,并在 devfs_register()中指定次设备号。

udev 设备文件系统

linux 2.6开始抛弃了devfs,引入了udev 文件系统,基于以下几点:

  • devfs所做的工作被确信可以在用户态来完成。

  • 一些bug相当长的时间内未被修复。

  • devfs的维护者和作者停止了对代码的维护工作。

udev 与devfs的区别在于:

devfs 在设备打开时自动加载驱动程序 udev在发现设备时自动加载驱动程序

sysfs 文件系统

udev工作在用户态,利用设备加入或移除时内核所发送的热插拔事件来进行工作,同时hotplug事件,设备的详细信息会由内核输出到位于/sys 的sysfs文件系统。

udev 利用sysfs中的信息来创建设备文件节点等工作

sysfs被看成是与proc、devfs和devpty同 类别的文件系统,该文件系统是一个虚拟的文件系统,它可以产生一个包括所有系统 硬件的层级视图,与提供进程和状态信息的 proc 文件系统十分类似

 tree /sys/dev/
 ├── block
 │   ├── 7:0 -> ../../devices/virtual/block/loop0
 │   ├── 7:1 -> ../../devices/virtual/block/loop1
 │   ├── 7:2 -> ../../devices/virtual/block/loop2
 │   ├── 7:3 -> ../../devices/virtual/block/loop3
 │   ├── 7:4 -> ../../devices/virtual/block/loop4
 │   ├── 7:5 -> ../../devices/virtual/block/loop5
 │   ├── 7:6 -> ../../devices/virtual/block/loop6
 │   ├── 7:7 -> ../../devices/virtual/block/loop7
 │   ├── 8:0 -> ../../devices/pci0000:00/0000:00:17.0/ata1/host0/target0:0:0/0:0:0:0/block/sda
 │   ├── 8:1 -> ../../devices/pci0000:00/0000:00:17.0/ata1/host0/target0:0:0/0:0:0:0/block/sda/sda1
 │   ├── 8:16 -> ../../devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8.2/1-8.2:1.0/host4/target4:0:0/4:0:0:0/block/sdb
 │   ├── 8:2 -> ../../devices/pci0000:00/0000:00:17.0/ata1/host0/target0:0:0/0:0:0:0/block/sda/sda2
 │   ├── 8:32 -> ../../devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8.2/1-8.2:1.0/host4/target4:0:0/4:0:0:1/block/sdc
 │   ├── 8:48 -> ../../devices/pci0000:00/0000:00:14.0/usb1/1-8/1-8.2/1-8.2:1.0/host4/target4:0:0/4:0:0:2/block/sdd
 │   ├── 8:5 -> ../../devices/pci0000:00/0000:00:17.0/ata1/host0/target0:0:0/0:0:0:0/block/sda/sda5
 │   └── 8:6 -> ../../devices/pci0000:00/0000:00:17.0/ata1/host0/target0:0:0/0:0:0:0/block/sda/sda6
 └── char
     ├── 10:1 -> ../../devices/virtual/misc/psaux
     ├── 10:183 -> ../../devices/virtual/misc/hw_random
     ├── 10:184 -> ../../devices/virtual/misc/microcode
     ├── 10:200 -> ../../devices/virtual/misc/tun
     ├── 10:223 -> ../../devices/virtual/misc/uinput
     ├── 10:227 -> ../../devices/virtual/misc/mcelog
     ├── 10:228 -> ../../devices/virtual/misc/hpet
     ├── 10:229 -> ../../devices/virtual/misc/fuse
     ├── 10:231 -> ../../devices/virtual/misc/snapshot
     ├── 10:232 -> ../../devices/virtual/misc/kvm
 
 
 12345678910111213141516171819202122232425262728293031

/sys 目录下展示了所有系统中的设备层级目录,其关系大致如下 这里写图片描述

kobject

linux3.4

 struct kobject {
  const char  *name;  
  struct list_head entry;   //used for mount to kset list
  struct kobject  *parent;  
  struct kset  *kset;      
  struct kobj_type *ktype;   //指向对象类型描述附指针
  struct sysfs_dirent *sd;      //
  struct kref  kref;         // 引用计数
  unsigned int state_initialized:1;
  unsigned int state_in_sysfs:1;
  unsigned int state_add_uevent_sent:1;
  unsigned int state_remove_uevent_sent:1;
  unsigned int uevent_suppress:1;
 };
 
 123456789101112131415

其中 sysfs_dirent,

 /*
  * sysfs_dirent - the building block of sysfs hierarchy.  Each and
  * every sysfs node is represented by single sysfs_dirent.
  *
  * As long as s_count reference is held, the sysfs_dirent itself is
  * accessible.  Dereferencing s_elem or any other outer entity
  * requires s_active reference.
  */
 struct sysfs_dirent {
  atomic_t  s_count;
  atomic_t  s_active;
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
  struct lockdep_map dep_map;
 #endif
  struct sysfs_dirent *s_parent;
  const char  *s_name;
 
  struct rb_node  s_rb;
 
  union {
   struct completion *completion;
   struct sysfs_dirent *removed_list;
  } u;
 
  const void  *s_ns; /* namespace tag */
  unsigned int  s_hash; /* ns + name hash */
  union {
   struct sysfs_elem_dir  s_dir;
   struct sysfs_elem_symlink s_symlink;
   struct sysfs_elem_attr  s_attr;
   struct sysfs_elem_bin_attr s_bin_attr;
  };
 
  unsigned short  s_flags;
  umode_t   s_mode;
  unsigned int  s_ino;
  struct sysfs_inode_attrs *s_iattr;
 };
 
 123456789101112131415161718192021222324252627282930313233343536373839

kset

 struct kset {
  struct list_head list; //double list head
  spinlock_t list_lock;  
  struct kobject kobj;  //嵌入的kobject
  const struct kset_uevent_ops *uevent_ops;  //事件操作集
 };
 123456

其中 kset_uevent_ops 定义了kset的对所包含的kobject 可以执行的操作,包括事件过滤和导出环境变量操作。

 struct kset_uevent_ops {
  int (* const filter)(struct kset *kset, struct kobject *kobj);  //事件过滤
  const char *(* const name)(struct kset *kset, struct kobject *kobj);
  int (* const uevent)(struct kset *kset, struct kobject *kobj,
         struct kobj_uevent_env *env);   // 环境变量导出
 };
 
 1234567

device

device 数据结构用于描述设备相关的信息和设备之间的层次关系,设备与总线与驱动之间的关系。

 struct device {
  struct device  *parent;
 
  struct device_private *p;
 
  struct kobject kobj;
  const char  *init_name; /* initial name of the device */
  const struct device_type *type;
 
  struct mutex  mutex; /* mutex to synchronize calls to
       * its driver.
       */
 
  struct bus_type *bus;  /* type of bus device is on */
  struct device_driver *driver; /* which driver has allocated this
         device */
  void  *platform_data; /* Platform specific data, device
         core doesn't touch it */
  struct dev_pm_info power;
  struct dev_pm_domain *pm_domain;
 
 #ifdef CONFIG_NUMA
  int  numa_node; /* NUMA node this device is close to */
 #endif
  u64  *dma_mask; /* dma mask (if dma'able device) */
  u64  coherent_dma_mask;/* Like dma_mask, but for
           alloc_coherent mappings as
           not all hardware supports
           64 bit addresses for consistent
           allocations such descriptors. */
 
  struct device_dma_parameters *dma_parms;
 
  struct list_head dma_pools; /* dma pools (if dma'ble) */
 
  struct dma_coherent_mem *dma_mem; /* internal for coherent mem
           override */
 #ifdef CONFIG_CMA
  struct cma *cma_area;  /* contiguous memory area for dma
         allocations */
 #endif
  /* arch specific additions */
  struct dev_archdata archdata;
 
  struct device_node *of_node; /* associated device tree node */
 
  dev_t   devt; /* dev_t, creates the sysfs "dev" */
  u32   id; /* device instance */
 
  spinlock_t  devres_lock;
  struct list_head devres_head;
 
  struct klist_node knode_class;
  struct class  *class;
  const struct attribute_group **groups; /* optional groups */
 
  void (*release)(struct device *dev);
 };
 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758

操作device的相关函数:

 device_register(): /sys/devices 下创建相关目录
 device_unregister(): 移除相关目录
 get_device: 增加引用计数
 put_device: 减小引用计数
 1234

device_driver

 struct device_driver {
  const char  *name;
  struct bus_type  *bus;
 
  struct module  *owner;
  const char  *mod_name; /* used for built-in modules */
 
  bool suppress_bind_attrs; /* disables bind/unbind via sysfs */
 
  const struct of_device_id *of_match_table;
 
  int (*probe) (struct device *dev);
  int (*remove) (struct device *dev);
  void (*shutdown) (struct device *dev);
  int (*suspend) (struct device *dev, pm_message_t state);
  int (*resume) (struct device *dev);
  const struct attribute_group **groups;
 
  const struct dev_pm_ops *pm;
 
  struct driver_private *p;
 };
 12345678910111213141516171819202122

其中

 struct bus_type {
  const char  *name;
  const char  *dev_name;
  struct device  *dev_root;
  struct bus_attribute *bus_attrs;
  struct device_attribute *dev_attrs;
  struct driver_attribute *drv_attrs;
 
  int (*match)(struct device *dev, struct device_driver *drv);
  int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
  int (*probe)(struct device *dev);
  int (*remove)(struct device *dev);
  void (*shutdown)(struct device *dev);
 
  int (*suspend)(struct device *dev, pm_message_t state);
  int (*resume)(struct device *dev);
 
  const struct dev_pm_ops *pm;
 
  struct iommu_ops *iommu_ops;
 
  struct subsys_private *p;
 };
 1234567891011121314151617181920212223

Kernel modules

模块安装与卸载

并不是所有的module都是在编译内核时加入的,主要有以下考虑:

  • 所有模块默认编译进内核,将使得内核臃肿

  • 使得内核不易进行扩展

linux提供可动态安装模块的机制,可将模块编译成ko文件,推迟链接的时间:

  • 在需要时通过insmod 完成链接过程,链接系统内核导出符号,完成模块的可插拔功能。

  • 相对应的,移除模块通过rmmod完成

  • 考虑到模块之间可相互依赖,进行调用,因此在载入模块的同时需要检查依赖的模块是否已经载入,modprobe 可以自动加载依赖模块,其根据依赖信息工作:depmod -A 可生成新模块的依赖信息 推荐使用modprobe 进行模块安装与卸载:

 modprobe module [parameter]
 modprobe -r modules   ; 如果依赖的模块有被其他模块调用,则不会移除,反之,一并移除
 12

导出符号表

模块之间可通过到处符号表实现依赖关系 在这里插入图片描述

EXPORT_SYMBOL(function_name) 导出函数符号 EXPORT_SYMBOL_GPL(function_name) 导出给符合GPL 协议的模块使用

The minor number is used by the kernel to determine exactly which device is being referred to. Depending on how your driver is written (as we will see below), you can either get a direct pointer to your device from the kernel, or you can use the minor number yourself as an index into a local array of devices. Either way, the kernel itself knows almost nothing about minor numbers beyond the fact that they refer to devices implemented by your driver.

Module Stack

驱动常见错误debug

  1. invalid format

 # insmod hello.ko
 Error inserting './hello.ko': -1 Invalid module format
 12

cat /var/log/messages

以上就是良许教程网为各位朋友分享的Linux系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你!

137e00002230ad9f26e78-265x300

本文由 良许Linux教程网 发布,可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。
良许

作者: 良许

良许,世界500强企业Linux开发工程师,公众号【良许Linux】的作者,全网拥有超30W粉丝。个人标签:创业者,CSDN学院讲师,副业达人,流量玩家,摄影爱好者。
上一篇
下一篇

发表评论

联系我们

联系我们

公众号:良许Linux

在线咨询: QQ交谈

邮箱: yychuyu@163.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部