溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Linux Driver是什么

發(fā)布時(shí)間:2022-01-27 14:30:19 來源:億速云 閱讀:270 作者:iii 欄目:開發(fā)技術(shù)

這篇“Linux Driver是什么”文章的知識(shí)點(diǎn)大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價(jià)值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Linux Driver是什么”文章吧。

Linux Driver即Linux 驅(qū)動(dòng),linux 系統(tǒng)設(shè)計(jì)將設(shè)備驅(qū)動(dòng)納入了文件系統(tǒng),任何一個(gè)Linux驅(qū)動(dòng)都需要有一個(gè)設(shè)備文件,否則應(yīng)用程序?qū)o法與驅(qū)動(dòng)程序交互。

Linux Driver是什么

設(shè)備分類

  • 字符設(shè)備

  • 塊設(shè)備

  • 網(wǎng)絡(luò)設(shè)備

驅(qū)動(dòng)在kernel中的位置

linux 系統(tǒng)設(shè)計(jì)將設(shè)備驅(qū)動(dòng)納入了文件系統(tǒng), Linux Driver是什么

更為具體的分層調(diào)用結(jié)構(gòu)如下所示: Linux Driver是什么

Linux Device Model

usb 設(shè)備的驅(qū)動(dòng)設(shè)備模型:

Linux Driver是什么

設(shè)備文件的節(jié)點(diǎn)記錄的信息:

  • 文件類型

  • 主設(shè)備號(hào)

  • 次設(shè)備號(hào) 主設(shè)備號(hào)和類型決定了驅(qū)動(dòng)的類型及其界面,而次設(shè)備號(hào)則說明是同類設(shè)備中的第幾個(gè)設(shè)備。

devfs 文件系統(tǒng)

在linux 2.4 引入,主要優(yōu)點(diǎn):

  • 可以通過程序在設(shè)備初始化時(shí)在/dev目錄下創(chuàng)建設(shè)備文件,卸載設(shè)備時(shí)將它 刪除。

  • 設(shè)備驅(qū)動(dòng)程序可以指定設(shè)備名、所有者和權(quán)限位,用戶空間程序仍可以修改 所有者和權(quán)限位。

  • 不再需要為設(shè)備驅(qū)動(dòng)程序分配主設(shè)備號(hào)以及處理次設(shè)備號(hào),在程序中可以直 接給 register_chrdev()傳遞 0 主設(shè)備號(hào)以動(dòng)態(tài)獲得可用的主設(shè)備號(hào),并在 devfs_register()中指定次設(shè)備號(hào)。

udev 設(shè)備文件系統(tǒng)

linux 2.6開始拋棄了devfs,引入了udev 文件系統(tǒng),基于以下幾點(diǎn):

  • devfs所做的工作被確信可以在用戶態(tài)來完成。

  • 一些bug相當(dāng)長(zhǎng)的時(shí)間內(nèi)未被修復(fù)。

  • devfs的維護(hù)者和作者停止了對(duì)代碼的維護(hù)工作。

udev 與devfs的區(qū)別在于:

devfs 在設(shè)備打開時(shí)自動(dòng)加載驅(qū)動(dòng)程序 udev在發(fā)現(xiàn)設(shè)備時(shí)自動(dòng)加載驅(qū)動(dòng)程序

sysfs 文件系統(tǒng)

udev工作在用戶態(tài),利用設(shè)備加入或移除時(shí)內(nèi)核所發(fā)送的熱插拔事件來進(jìn)行工作,同時(shí)hotplug事件,設(shè)備的詳細(xì)信息會(huì)由內(nèi)核輸出到位于/sys 的sysfs文件系統(tǒng)。

udev 利用sysfs中的信息來創(chuàng)建設(shè)備文件節(jié)點(diǎn)等工作

sysfs被看成是與proc、devfs和devpty同 類別的文件系統(tǒng),該文件系統(tǒng)是一個(gè)虛擬的文件系統(tǒng),它可以產(chǎn)生一個(gè)包括所有系統(tǒng) 硬件的層級(jí)視圖,與提供進(jìn)程和狀態(tài)信息的 proc 文件系統(tǒng)十分類似

 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 目錄下展示了所有系統(tǒng)中的設(shè)備層級(jí)目錄,其關(guān)系大致如下 Linux Driver是什么

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;   //指向?qū)ο箢愋兔枋龈街羔?
  struct sysfs_dirent *sd;      //
  struct kref  kref;         // 引用計(jì)數(shù)
  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的對(duì)所包含的kobject 可以執(zhí)行的操作,包括事件過濾和導(dǎo)出環(huán)境變量操作。

 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);   // 環(huán)境變量導(dǎo)出
 };
 
 1234567

device

device 數(shù)據(jù)結(jié)構(gòu)用于描述設(shè)備相關(guān)的信息和設(shè)備之間的層次關(guān)系,設(shè)備與總線與驅(qū)動(dòng)之間的關(guān)系。

 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的相關(guān)函數(shù):

 device_register(): /sys/devices 下創(chuàng)建相關(guān)目錄
 device_unregister(): 移除相關(guān)目錄
 get_device: 增加引用計(jì)數(shù)
 put_device: 減小引用計(jì)數(shù)
 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都是在編譯內(nèi)核時(shí)加入的,主要有以下考慮:

  • 所有模塊默認(rèn)編譯進(jìn)內(nèi)核,將使得內(nèi)核臃腫

  • 使得內(nèi)核不易進(jìn)行擴(kuò)展

linux提供可動(dòng)態(tài)安裝模塊的機(jī)制,可將模塊編譯成ko文件,推遲鏈接的時(shí)間:

  • 在需要時(shí)通過insmod 完成鏈接過程,鏈接系統(tǒng)內(nèi)核導(dǎo)出符號(hào),完成模塊的可插拔功能。

  • 相對(duì)應(yīng)的,移除模塊通過rmmod完成

  • 考慮到模塊之間可相互依賴,進(jìn)行調(diào)用,因此在載入模塊的同時(shí)需要檢查依賴的模塊是否已經(jīng)載入,modprobe 可以自動(dòng)加載依賴模塊,其根據(jù)依賴信息工作:depmod -A 可生成新模塊的依賴信息 推薦使用modprobe 進(jìn)行模塊安裝與卸載:

 modprobe module [parameter]
 modprobe -r modules   ; 如果依賴的模塊有被其他模塊調(diào)用,則不會(huì)移除,反之,一并移除
 12

導(dǎo)出符號(hào)表

模塊之間可通過到處符號(hào)表實(shí)現(xiàn)依賴關(guān)系 Linux Driver是什么

EXPORT_SYMBOL(function_name) 導(dǎo)出函數(shù)符號(hào) EXPORT_SYMBOL_GPL(function_name) 導(dǎo)出給符合GPL 協(xié)議的模塊使用

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

驅(qū)動(dòng)常見錯(cuò)誤debug

  1. invalid format

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

cat /var/log/messages

以上就是關(guān)于“Linux Driver是什么”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對(duì)大家有幫助,若想了解更多相關(guān)的知識(shí)內(nèi)容,請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI