设备驱动,字符设备驱动、(总线)设备驱动模型、sysfs文件系统、平台设备驱动
以下內容轉載于微信公眾號:嵌入式企鵝圈。如有侵權,請告知刪除。
? ? 學習Linux設備驅動開發的過程中自然會遇到字符設備驅動、平臺設備驅動、設備驅動模型和sysfs等相關概念和技術。
? ? 對于初學者來說會非常困惑,甚至對Linux有一定基礎的工程師而言,能夠較好理解這些相關技術也相對不錯了。
? ? 要深刻理解其中的原理需要非常熟悉設備驅動相關的框架和模型代碼。
? ? 網絡上有關這些技術的文章不少,但多是對其中的某一點進行闡述,很難找到對這些技術進行比較和關聯的分析。
? ? 對于開發者而言,能夠熟悉某一點并分享出來已很難得,但對于專注傳授技術和經驗給學習者而言,橫向比較關聯各個驅動相關的知識點和縱向剖析Linux整個驅動軟件層次是非常有必要的,也非常有意義。
? ? 本文依然是從需求的角度去理解以上知識點,存在即是合理,以上技術知識能夠存在,即代表其有一定的作用。我們著重去理解每一個技術點的作用,并明確其在驅動開發中的角色。
一、設備驅動
- (設備的)驅動;
- Linux設備驅動分三種,包括字符設備驅動、塊設備驅動和網絡設備驅動。
- 字符設備只能按字節流先后順序訪問設備內存,不能隨機訪問。鼠標、觸摸屏、LCD等是字符設備的代表。
- 塊設備可以隨機訪問設備內存的任意地址,硬盤、SD卡、NAND FLASH是塊設備的代表。
- 網絡設備指的是網卡一類使用socket套接字進行通信的設備。
二、字符設備驅動
? ? 字符設備驅動框架,請參考嵌入式企鵝圈的兩篇文章:《Linux字符設備驅動剖析》和《Linux設備文件的創建和mdev》。
1、字符設備驅動縱向關系
- 從《Linux字符設備驅動剖析》可以看出,應用層訪問設備驅動非常簡單,即通過open接口最終獲得設備驅動的操作接口集struct file_opertions。
- 而open接口傳入的參數是/dev目錄下的設備名,設備名對應的設備文件節點inode會存儲設備號。
- 而驅動框架中的全局數組cdev_map則維護設備號和file_opertions的關系。
- 即應用層到底層的關系主要是(忽略VFS這一層):設備名-->設備號-->file_opertions;
- Open函數返回的局部fd和file_opertions的關系(忽略進程數據結構):fd-->file(當前進程數據結構成員)-> file_opertions;
- 這樣,通過fd即可以獲得file_opertions,即可以通過read、write等接口來調用驅動的讀操作函數和寫操作函數、ioctl函數等。
2、字符設備驅動的任務
- 字符設備驅動最本質的任務,應該是提供file_opertions的各個open、read、write、ioctl等接口的實現。
- 另外從以上的描述中,為了讓應用層能夠調用到底層的file_opertions還涉及到以下任務:
- 申請設備號,并將設備號和file_opertions注冊(cdev_add接口)到驅動框架中的cdev_map數組。這點應該在字符設備驅動中負責,涉及到其主動向系統報備自己的存在。
- 在/dev目錄中創建設備文件,內容包括設備號。這一點是否由字符設備驅動來負責商榷。字符設備驅動位于內核層,如果由其負責這個任務,那么驅動就得知道它要創建的設備名。簡單的字符驅動還好,如果是USB等可插拔的設備,驅動怎么知道自己要創建什么設備名呢?有人說可以寫明一套規則。確實如此,但如果把這套規則放到應用層,由應用程序開發人員去明確這個規則(mdev正是這樣做的),會不會更好?因為是應用程序直接編程訪問這個設備名對應的設備驅動的。所以字符設備驅動不應該直接負責設備文件的創建。
3、誰來創建設備文件
- 一種方法就是用戶在shell中使用mknod命令創建設備文件,同時傳入設備名和設備號。這是人工的做法,很不科學。但它是一種演示的方法。
- 另一種方法就是依賴設備模型來輔助創建設備文件。這也是設備模型的作用之一。
4、字符設備驅動編程流程
(1)定義struct file_opertions my_fops并實現其中的各個接口,如open、read、write、ioctl等接口。
(2)實現驅動的入口函數,如chardev_init
static int __init chardev_init(void) {alloc_chrdev_region(&devno,…);//申請設備號my_cdev=cdev_alloc();cdev_init(my_cdev,&my_fops);cdev_add(my_fops,devno, 1);//注冊設備號和file_opertions}(3)module_init(chardev_init);//宏定義該初始化入口函數。卸載流程不做解釋。
(4)insmod加載這個module后,可以人工在shell命令行利用mknod創建設備文件。
(5)應用層即可以用open來打開設備文件來進行訪問了。
5、總結
- 可以看出,字符設備驅動的核心框架跟設備模型、平臺設備驅動沒有直接關系,不用他們也一樣能夠正常工作。
三、(總線)設備驅動模型
? ? 我們主要談及設備驅動模型在linux驅動中的作用和角色,有關設備模型的原理和實現我們另文再述。1、(總線)設備驅動模型的作用
(1)設備驅動模型實現uevent機制,調用應用層的medv來自動創建設備文件。這在上面已經論述過。
(2)設備驅動模型通過sysfs文件系統向用戶層提供設備驅動視圖,如下。
?
- 上圖只是可視化的一種表達,有助于大家去理解設備模型,類似于windows的設備管理程序;
- 在嵌入式linux里面并沒有相關應用通過圖形的方式來展現這種關系。但是用戶可以通過命令窗口利用ls命名逐級訪問/sys文件夾來獲得各種總線、設備、驅動的信息和關系。可以看出,在/sys頂級目錄,有三個關鍵的子目錄,就是設備類、設備和總線。
- 設備是具體的一個個設備,在/sys/devices/是創建了實際的文件節點。而其他目錄,如設備類和總線以下的子目錄中出現的設備,都是用符號鏈接指向/sys/devices/目錄下的文件。
- 設備類是對/sys/devices/下的各種設備進行歸類,以體現一類設備的公共屬性,如鼠標和觸摸屏都是屬于input設備類。
- 總線目錄是總線、設備、驅動模型的核心目錄。因為設備和驅動都是依附在某種總線上的,如USB、PCI和平臺總線等。設備和驅動正是依靠總線的管理功能才能找到對方,如設備注冊到總線時去尋找驅動,而驅動注冊的時候去尋找其能夠支持的設備。
- 最重要的是,如果沒有設備模型,那應用層很難知曉驅動和設備的關系,因為字符設備驅動并沒有提供這些信息,那對于設備驅動的管理者而言會非常麻煩。事實上,內核中的總線class、設備device和驅動device_driver都不會將所有的信息暴露給用戶層,例如這三個數據結構都有對應的private數據結構,它用于內核對上下級總線設備驅動的鏈表關系維護。如果暴露給用戶層,那容易被用戶層修改而使系統混亂。實際上,用戶層只關心三者的視圖關聯,至于他們的關聯在底層怎么實現則不需要關心。
(3)設備驅動模型提供統一的電源管理機制。
- 很明顯,我們在字符設備驅動的file_operations接口中并沒有看到電源管理方面的接口。但對于操作系統來說,電源功耗管理必不可少。
- 電源管理其實不應該由應用開發人員來負責,而是應該由系統來負責,例如手機很久沒有觸摸了,那會進入休眠狀態。
- 這種狀態的改變應該由系統來完成,而各種設備進入睡眠模式也應該由系統來完成。因此file_operations不提供電源管理的接口給應用程序是合理的。
- 而設備模型作為系統管理的一種機制,由它來提供電源管理是非常合理的。
- 如設備device數據結構有struct dev_pm_info power功耗屬性參數,驅動device_driver數據結構有struct dev_pm_ops *pm功耗操作接口。
(4)設備驅動模型提供各種對象實例的引用計數,防止對象被應用層誤刪。
- 設備模型的所有數據結構均是繼承kobject而來,而kobject就提供基礎的計數功能。
(5)設備驅動模型提供多一種方式給應用層,用戶和內核可以通過sysfs進行交互,如通過修改/sys目錄下設備的文件內容,即可以直接修改設備對應的參數。
2、設備驅動模型的核心接口
bus_register(struct bus_type *bus) 注冊總線 device_add(struct device *dev) 注冊設備 driver_register(struct device_driver*drv) 注冊驅動 class_create(owner, name) 創建設備類 ……
3、設備驅動模型和字符設備驅動區別
- 設備驅動模型側重于內核對總線、設備和驅動的管理,并向應用層暴露這些管理的信息,而字符設備驅動則側重于設備驅動的功能實現。
四、sysfs文件系統
1、sysfs文件系統和設備驅動模型的關系
Sysfs文件系統是設備驅動模型得以向用戶暴露其管理信息的載體。它們之間的關系如下:
(1)設備驅動模型的上下級關系(如子設備和所屬父設備)通過sysfs文件系統的父目錄和子目錄來體現。
(2)設備驅動模型的平級關系(如設備類管理的設備和具體的設備的關系)則通過sysfs文件系統的目錄符號鏈接來實現。
(3)設備驅動模型的屬性(如設備的參數和設備名,設備號等)則通過sysfs文件系統的文件內容來記錄實現。
(4)設備驅動模型數據結構中的kobject對應于sysfs文件系統中的目錄,而數據結構中的struct attribute成員則對應于sysfs文件系統中的文件。
- 對應的意思是指含有kobject的device、device_driver、bus等在向系統注冊時,會(調用sysfs的create_dir接口來)創建對應的目錄;
- 含有struct attribute成員屬性的device、device_driver、bus等在向系統注冊時,會(調用sysfs的sysfs_create_file接口來)創建文件。
2、sysfs核心接口
sysfs_create_file(struct kobject * kobj,const struct attribute * attr)創建屬性文件 sysfs_create_dir(struct kobject * kobj)創建目錄 int sysfs_open_file(struct inode *inode,struct file *file)打開sysfs文件系統格式的文件 sysfs_read_file(struct file *file, char__user *buf, size_t count, loff_t *ppos) 讀操作 sysfs_write_file(struct file *file, constchar __user *buf, size_t count, loff_t *ppos) 寫操作
3、屬性文件的讀寫
(1)sysfs_read_file是sysfs文件系統的讀寫入口,但是驅動需要向系統提供真正的讀寫操作,即struct sysfs_ops數據結構中的show和store接口。(2)Sysfs文件系統是基于內存的,掉電即消失。sysfs所有的操作接口均是對內存中的內核數據結構進行訪問操作。
假如用戶用cat命令去讀取一個屬性文件(如dev)的內容,那么會產生以下流程:
- fd=open(“dev”)->vfs_open(“dev”)->sysfs_open(“dev”),獲取該文件的句柄;
- read()->vfs_read()->sysfs_read_file()->sysfs_ops->show(),該show接口即是設備在注冊時產生屬性文件,并向系統提供該文件的讀接口。而讀接口的實現,自然是對該屬性參數的讀訪問。
(3)/sys掛載了sysfs文件系統,因此所有對/sys目錄下的文件或者目錄的操作,都會通過sysfs文件的接口進行訪問。
五、平臺設備驅動
- “平臺設備驅動”中的“平臺”,指的是平臺總線,即platform_bus_type,是linux眾多總線中的一種,如USB總線、PCI總線、I2C總線等等。
- 平臺總線是一種虛擬的總線,專門用來管理SOC上的控制器(如看門狗、LCD、RTC等等),它們都是(CPU的總線上)直接取址訪問設備的。而USB、PCI等設備都有通過特定的時序來訪問SOC芯片以外的設備。
- 平臺設備驅動是總線設備驅動模型上的一個子集。將平臺視為一種總線的概念,那兩者的關系就會容易理解。
1、平臺設備驅動和設備驅動模型的關系
(1)在設備驅動模型視圖上,平臺設備驅動接口創建了相關的平臺設備類(/sys/class/platform_bus)、平臺總線(/sys/bus/platform)、平臺設備(/sys/devices/)。
(2)平臺設備(platform_device)、平臺設備驅動(platform_driver)均注冊到平臺總線上,即在/sys/bus/platform/目錄下創建相應的設備和驅動目錄。而平臺總線負責匹配注冊到其上面的設備和驅動,匹配成功后會調用驅動的probe接口。
(3)平臺設備驅動,利用設備驅動模型接口,來輔助創建對應的設備文件(位于/dev/目錄下)。
(4)相關的接口包括
platform_device_register(struct platform_device *pdev) 注冊平臺設備 platform_driver_register(struct platform_driver *drv) 注冊平臺設備驅動
兩個接口的實現里面都會對平臺驅動和設備進行匹配,匹配成功會調用驅動的probe接口。
2. 平臺設備驅動和字符設備驅動的關系
我們假設這個平臺設備是字符設備。- 平臺設備驅動和字符設備驅動的關系始于驅動的probe接口,即在probe接口中實現字符設備驅動所要完成的任務,即通過alloc_chrdev_region申請設備號,和通過cdev_add注冊驅動的struct file_opertions。
- 另外為了自動創建應用層訪問的設備文件,還要調用class_create和device_create接口在平臺設備類下創建對應的設備類和設備,并發出uevent事件,調用mdev來創建設備文件。
3、平臺設備驅動的開發流程
(1)將字符設備驅動的char_init函數的實現搬到platform_driver的probe接口中。(2)在char_init中調用platform_device_register和platform_driver_register分別注冊設備和驅動。
- 其實對于移植好的系統,platform_device_register是在linux啟動的過程中完成的。
- 因此char_init一般只有platform_driver_register注冊驅動。
詳細的平臺設備驅動的實現原理和開發流程另文再述。本次的重點是為了闡述字符設備驅動、設備驅動模型、sysfs和平臺設備驅動之間的關系。
總結
以上是生活随笔為你收集整理的设备驱动,字符设备驱动、(总线)设备驱动模型、sysfs文件系统、平台设备驱动的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Keras中文文档】Layer Con
- 下一篇: 信息化建设概述