字符設備打開的時候發生了什麼以及一些思考

2022-01-09 justice與初中生小許

linux驅動等於單片機操作+linux各個子系統架構+作業系統,但是學習的時候要把重心放在架構和作業系統上面,這樣驅動設計得更好。我一直不滿足於在產品側當一個看代碼的bsp驅動工程師,有朝一日我想去大廠,去當晶片端的bsp驅動工程師,讓別人用我設計的驅動。因此,我真就只遵循套路來寫一些簡單的設備驅動就行了嗎?

重新學習字符設備的時候發現了第一次學習沒有思考的幾個問題:

總的來看當我們打開一個設備節點,系統發生了什麼?如何和我的驅動操作集關聯?想要一個驅動兼容同類的設備時候,次設備號扮演了什麼角色?如何去設置cdev?cdev需要多少個?

以上問題並不能直接解答,先看看我們是怎麼把一個字符設備以及他的操作集加到系統中的。

設備號的管理

眾所周知,設備驅動中有個很重要的概念叫設備號,一個32位設備號分為主設備號和次設備號,高20位是主設備號,次設備號的低12位。主設備號對應的是某個驅動程序.ko,次設備號標識這個驅動管理下的各種同類設備。

我使用alloc_chrdev_region函數來分配和註冊設備號

int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count,
   const char *name)
#第一個參數是你傳入的一個變量用於保存系統分配的設備號
#第二、三個參數是以次設備號開始申請多少個次設備號
#第四個參數是管理這組設備的一個管理員名字

上面說的管理員實際是結構體char_device_struct。

然後現在啥也別想char_device_struct是什麼了,全都拋棄。系統中有個管理設備號的數組:chardevs[255]。裡面每一個元素都是一個char_device_struct指針。

比如我這樣分配

alloc_chrdev_region(&imx6ull_led_beep.device_num, 0, 2, "led_beep");

那麼對應的狀況就會是這樣的

為什麼major是1或者256?因為如果要找的話,是通過求模找的比如1%255等於1,  256%255也等於1。如果同時1和256主設備號同時存在,那麼也可以加到chrdevs[1]下面來管理,按照major大小從小到大鍊表排列。比如下面這樣

這個結論就是:設備號是通過chedevs數組管理的。但是這並沒有接近我思考的問題的核心。

字符設備cdev的管理

字符設備驅動中最重要的就是cdev和它的操作集。那它是如何管理的。

涉及兩個函數:

void cdev_init(struct cdev *cdev, const struct file_operations *fops)
int cdev_add(struct cdev *p, dev_t dev, unsigned count)

cdev_init就是綁定cdev和操作集,cdev_add就是加入到管理中來。

cdev的管理是由cdev_map指針來管理的,指向一個struct kobj_map

比如我向系統這樣增加

cdev_init(&imx6ull_led_beep.cdev, &imx6ull_led_beep_fops);

cdev_add(&imx6ull_led_beep.cdev, imx6ull_led_beep.device_num, 2);

或者
cdev_init(&imx6ull_led_beep.cdev, &imx6ull_led_beep_fops);

cdev_add(&imx6ull_led_beep.cdev, imx6ull_led_beep.device_num, 1);
cdev_add(&imx6ull_led_beep.cdev, imx6ull_led_beep.device_num+1, 1);
#以上兩種方法一樣的,為什麼呢?因為imx6ull_led_beep.device_num
#和imx6ull_led_beep.device_num+1都是同一個major

對應的狀況是這樣:

因此可以得出結論:一個驅動(主設備號)下,只設置一個cdev也能夠管理多個同類設備,只要你認為同類設備都能用同一個操作集。但是注意cdev註冊和設備號管理並沒有關係!

注意:cdev_map同樣是根據求模取得位置的,和上面chrdevs一樣,但是這個不要太關注也行,因為我們很少能用完255個major,別給自己徒增煩惱。

設備節點生成

設備節點就是一個文件,牢牢記住和inode是僅僅相依的。我也不用mknod那套了,mknod相當於是應用程式幫你生成一個設備節點,但是我希望我的驅動加載後自動生成設備節點。

涉及兩個函數:

#define class_create(owner, name)  \
({      \
 static struct lock_class_key __key; \
 __class_create(owner, name, &__key); \
})

struct device *device_create(struct class *class, struct device *parent,
        dev_t devt, void *drvdata, const char *fmt, ...)

這樣用
class = class_create(THIS_MODULE, "led_beep1");//出現在sys/class
device = device_create(class , \  //出現/dev/imx6ull_led
              NULL, imx6ull_led_beep.device_num, NULL, "imx6ull_led");

imx6ull_led_beep.beep_device = device_create(class , \
             NULL, imx6ull_led_beep.device_num+1, NULL, "imx6ull_beep");

因為是同類設備啊,所以創造一個類唄。

上面就是管理了兩個同類設備,可以看到參數有設備號,所以當device_create完成後,設備節點對應的inode→i_rdev就保存了設備號。這個很重要,這意味著/dev下已經有兩個設備節點並且擁有了設備號信息。

設備節點和驅動程序關聯流程首先我們在驅動程序中申請設備號,用申請到的設備號使用device_create創造設備節點。如果申請的是有多個minor的多個同類設備的,那麼註冊的時候記得也要註冊對應的設備號。這裡能看到的是申請設備號和設備節點文件直接的聯繫。使用cdev_add給我們的cdev註冊進系統(cdev_map),這裡要提供起始設備號以及想註冊的同類子設備個數,因此我們驅動寫的cdev可以只有一個,但是設備號個數要和你申請的一致。這裡可以看到的是一個驅動程序完全可以對應一個cdev,前提是你認為這個cdev的操作集能供你這些同類設備公用。而不需要註冊那麼多cdev。這也是本篇文章我思考的最重要的一個點。應用open的時候,會根據設備節點文件打的inode→i_rdev在cdev_map查找對應的cdev,找到後,就將cdev賦值給inode→i_cdev,以後就能直接找打cdev而不通過cdev_map。同時會分配file結構體,讓file拿到cdev的操作集。因此在進程中我們open一個設備節點會返回一個fd,fd就是file的索引,有了fd就能拿到file,有了file就能拿到cdev的操作集,如圖所示:

4.後續read、write就能通過fd去調到驅動中的read、write

總結

弄清楚這些機制並不是很重要,甚至當我弄清楚之後,覺得用處沒有那麼大。但是有一點點作用就是我知道我編寫的驅動每一步的意義在於什麼,而不是按照市面上的教材套路來。這裡最重要的是搞清楚了一個驅動程序對應多少個cdev的問題!

相關焦點

  • Linux內核學習:簡單的字符設備驅動
    學習Linux內核最好的入門方式之一是從字符設備驅動開始模仿(來自於《奔跑吧 Linux內核——入門篇》)。對於我們日常生活中存在的大量設備,如攝像頭,USB充電器,藍牙,Wi-Fi等,這些設備在電氣特性和實現原理均不相同,對Linux系統來說如何抽象和描述他們呢?Linux很早就根據設備共同特徵將其劃分為三大類型:1,字符設備;塊設備;網絡設備。
  • 很「迷」的字符與字符串
    今天將主要講解字符類型和字符串類型,這兩個類型看起來很簡單,但卻是經常發生問題的地方,所以一定要仔細閱讀哦。回顧上篇博文《4.標準 ASCII 字符表使用 7 位二進位數來表示所有的大寫和小寫字母、數字 0 到 9、標點符號以及在美式英語中使用的特殊控制字符。其中,ASCII 字符表上的數字 0 ~ 31 以及 127(共 33 個)分配給了控制字符,用於控制像印表機等一些外圍設備。這些是看不到的。數字 32 ~ 126 分配給了能在鍵盤上找到的字符,這些是所見即所得的。
  • linux字符設備驅動基本框架
    常見的字符設備有led,蜂鳴器,串口,鍵盤等等。包括lcd與攝像頭驅動都屬於字符設備驅動。塊設備:塊設備是通過內存緩存區訪問,可以隨機存取的設備,一般理解就是存儲介質類的設備,常見的字符設備有U盤,TF卡,eMMC,電腦硬碟,光碟等等網絡設備:可以和其他主機交換數據的設備,主要有乙太網設備,wifi,藍牙等。
  • 除溼機散熱器衡水加工廠家設備什麼時候安裝好一些
    除溼機散熱器衡水加工廠家設備什麼時候安裝好一些   燃氣採暖主要有兩種形式,種是散熱器,種是地暖,這兩種方式相較,散熱器的優勢明顯:地暖須要在地面鋪設管道,增加了地面高度,對樓房層高有嚴格的限制,而且施工繁瑣,費時費力,安裝調試漫長,運行成本高,後期如有故障維修困難,這些對普通家庭用戶來說
  • 【Android 原創】XCTF mobile新手區解題記錄以及一些總結和思考
    3、使用IDA打開so文件,靜態分析一下encrypt函數,發現邏輯很簡單,就是將傳進來的字符串的每個字符的ASCII碼減一;對於getFlag函數,由於該函數沒有輸入只有輸出,直接用frida Hook
  • 蘋果發布長文,揭秘 iPhone 等設備如何利用三萬字符庫實時識別手寫...
    在智能和行動裝置十分普遍的今天,手寫字符識別的重要性愈加顯現出來,在手機、便攜設備、可穿戴設備以及智能手錶上都會有十分重要的應用。對於行動裝置端的設備來說中文手寫字符識別需要大規模的字符庫支持。這篇文章闡述了我們如何在蘋果的行動裝置上實現實時手寫中文字符識別的過程。
  • 語法:什麼時候用hyphen(連字符)?
    名詞前面有前綴的單詞:Ex-wife, anti-ageing pills,  Pro-China journalists 數字+名詞的單詞一般也需要加連字符:Five-year period, 16-year-olds,
  • excel中的西文字符和中文字符,以及提取這兩種字符的函數
    我們平時使用excel表格的時候,輸入的文本大部分可以分為兩大類:一類是西文字符,即是英文輸入法狀態下輸入的字符串,包括英文的標點符號、阿拉伯數字123、英文字母abc等;另一類是中文字符,即是中文輸入法狀態下輸入的字符串,包括中文的標點符號、漢字等。
  • 【專業技術】Linux設備驅動第七篇:高級字符驅動操作之阻塞IO
    比如一個進程調用read讀取數據,當沒有數據可讀時該怎麼辦,是立即返回還是等到有數據的時候;另一種情況是進程調用write向設備寫數據,如果緩衝區滿了或者設備正忙的時候怎麼辦,是立即返回還是繼續等待直到設備可寫?這種情況下,一般的預設做法是使進程睡眠直到請求可以滿足為止。本篇就介紹遇到這類問題驅動的處理方法。睡眠什麼是睡眠?
  • Linux驅動實踐:你知道【字符設備驅動程序】的兩種寫法嗎?
    我們就繼續以此為基礎,用保姆級的粒度一步一步操作,來討論一下字符設備驅動程序的編寫方法。這篇文章的實際操作部分,使用的是的 API 函數;混亂的 API 函數我在剛開始接觸Linux驅動的時候,非常的困擾:註冊一個字符設備,怎麼有這麼多的 API 函數啊?
  • 有關行動裝置天線設計的一些新思考
    ━━━━在深入討論此方法前,我們應當回顧一些天線基礎知識。這件事引發了使用多根同頻天線的熱潮,這些天線通常在手機底部和頂部以及左上角和右下角成對排布。━━━━時代在發展,行動裝置越來越纖巧,功能越來越多,這要歸功於摩爾定律對其中多數電子器件的影響。但摩爾定律對天線沒有幫助。天線設計是模擬電子技術最後的堡壘。
  • 【Python教程】圖片轉字符畫
    ,但即使如此,真正決定課程效果的,還是你的每一次思考和實踐。因此,我們的要求功能的實現,更是要多去思考不同的解決方案,評估不同方案的優劣,然後使用在該場景下最優雅的方式去實現。所以,我們列出的參考資料未必是實現需求所必須的。有的時候,實現題目的要求很簡單,甚至參考資料裡就有,但是背後的思考和親手去實踐卻是任務最關鍵的一部分。在學習這些資料時,要多思考,多提問,多質疑。相信通過和小夥伴們的交流,能讓你的學習事半功倍。
  • Ollydbg之字符串、Windows API搜索
    記得小編在以前逆向一個網際網路公司的通訊模塊的時候,就是通過這個小技巧,找到了recv函數,然後。。。。。。。。。此處省略幾萬字,哈哈。在開始之前,先給大家簡單介紹下字符串和Windows API,一點小理解,大神請繞道,勿噴。1. 字符編碼字符串的基本組成單位是字符,而字符在計算機中的表示方法多種多樣。
  • 可穿戴設備未來十年,聊聊我對可穿戴設備的一些思考
    可穿戴設備已正式的走進在了人們的生活,但是目前來說,可穿戴設備還很難說對人們的生活帶來了多大的改變,作者在本文中暢想了一下可穿戴設備的未來,今天先讓我們一起看看他對於可穿戴設備的一些想法吧
  • 獨立思考:要從小鼓勵孩子去做家務以及一些小事情
    我是一個普通人家長大的孩子,雖然沒有很富足的生活,但是爸媽把我捧在手心裡,什麼都不讓我做,直到我長大了,我才發現,我連一點獨立的能力都沒有。第一次出國上大學的時候,連最基本的做菜也不會做。因為不會做菜,在異國他鄉,在一開始的時候,吃盡了苦頭,無法適應外國的飲食,然後讓自己的生活陷入了惡性循環,以至於低血糖以及營養不均衡,導致一度頭暈站不穩。
  • 第34p,字符編碼,文件操作的基礎知識
    一、 字符編碼介紹我們打開一個文件並閱讀文件的內容,對我們而言是只需點擊一下文件就可以了;但是,文件中包含有中文、英文、數字、標點符號、特殊字符等內容,計算機是如何把這些存儲在硬碟中的二進位0和1翻譯成為我們能看懂的中文、英文?
  • Linux設備樹關鍵技術之一:屬性
    打開APP Linux設備樹關鍵技術之一:屬性 發表於 2019-05-06 16:36:00 標準定義的基本類型包括:空,u32,u64,字符串,,字符數組6種。空前邊我們已經提到,當不需要值就可以表示節點的特性時,屬性的值可以為空。u32,u64,字符串,字符數組和c語言的定義沒有區別,注意的是規範要求都是大端表示,字符串也是以0x00結尾。是一個結構體數組,數組的元素具體是什麼根據屬性的定義確定,後邊我們講到具體的屬性時會詳細說明。
  • 用搜狗快速輸入特殊字符與表情字符
    因為它不僅涵蓋了大量的特殊符號如標點、數字、數學、希臘符號等,還預置了幾百款搜狗表情和字符畫,在寫文章做論文時能快速的輸入需要的特殊字符,在聊天泡論壇時也可隨手可愛的字符畫表達你的心情,很酷的噢。  一、搜狗輸入法都有哪些「表情&符號」?
  • 字符串: KMP是時候上場了(一文讀懂系列)
    所以叫做KMPKMP有什麼用KMP主要應用在字符串匹配上。KMP的主要思想是「當出現字符串不匹配時,可以知道一部分之前已經匹配的文本內容,可以利用這些信息避免從頭再去做匹配了。」其實KMP的代碼不好理解,一些同學甚至直接把KMP代碼的模板背下來。沒有徹底搞懂,懵懵懂懂就把代碼背下來太容易忘了。
  • 一個帶有特殊字符的簡訊就能讓你的iphone死機
    一些iphone和ipad的用戶報告說,他們的設備在收到帶有特定字符的簡訊後就會死機。,這似乎發送與信德語字符相關的某個國旗會導致接收信息的設備崩潰。這個問題涉及到運行iOS 13和iPadOS 13的設備,為什麼是這些特殊的字符?