就當我還在學校的時候,我就曾在一個裝機群里聽一位裝機圣手說,,驅動程序的安裝沒你想的那么簡單,分類型的,,分為字符設備驅動和塊設備驅動,。我當時就納悶了,,我說我裝機的時候好像沒看到啊,我就把光盤放過去然后就一直點下一步,,然后重啟就好了啊,。后面我在群里被幾位高手圍攻,敗下陣來,,時過境遷,,哥現(xiàn)在也算是道上混的兄弟了,再也沒那么容易被蒙了,。就算你DIY再牛,,你也不要和我說裝驅動要分類。否則我就和你講內(nèi)核,,講暈你再說,。看誰更能吹,,哈哈,。我得意的笑。我發(fā)現(xiàn)學內(nèi)核的一個好處,,就是非常好裝B,。你只要把內(nèi)核里面的名詞背熟了,拿出來去嚇唬嚇唬人,,挺管用的,,不過撞到行家的話,你就要注意了,。呵呵,。 好了,學內(nèi)核不是為了嚇唬人的,,是為了掌握其原理,,學習其技巧與方法,知其然而知其所以然,,另外內(nèi)核代碼是具有一定復雜度的,,看了內(nèi)核代碼再看看我們自已寫的,和玩具沒啥兩樣,,這就是學內(nèi)核的好處! 如果你已經(jīng)看過驅動模型應該有這種感受:你這玩意折騰來折騰去半天的,,昨不干活呢? 字符設備是傳說中的東西,玩過linux的人都知道這個東西,,很多同志也可以照貓畫虎的寫出一個字符設備,。但哥不,哥是有追求的人,,知其然,,必需得知其所以然,。我決不會不負責任的把大家領進門后就不管了。我依然會不惜筆墨的把該說的全都說清楚,。 我們先不用去摳概念,,不要說,什么是字符設備啊,,什么是塊設備啊,。這些都沒意義,你最需要知道的是這個叫字符設備的東西究竟都干了些啥?他到底是怎么工作的?搞清楚后,,什么是字符設備你就明白了,。如果再學塊設備,一對比,,差異在哪?你就明白了,。我學習一向都不喜歡摳概念。有的同志你叫字符設備他回答你說char設備,,你說塊設備他說block設備,,你說底半部他說下半部。你說NXP他說恩智浦,,還好哥是道上混的,,多少知道一點。否則就被人家給唬住了,。好了,,閑話不多說了,總的來說要表達的就是一種學習態(tài)度:不用摳概念,。 接下來我們欣賞一下字符設備,。 看過驅動模型系列的朋友現(xiàn)在應該有一種意識了,我們暫且把它叫做“初始化意識”,。就是說你用register_chrdev()注冊的時候是很爽,,但是那是因為前人把路鋪好了,好,,我們就來看看前人都做了些啥,,再提醒一次一定要有“初始化意識”。 我們在“初始化意識”的指引下找到了一個文件:char_dev.c,。打開這個文件一看,。有這么一個初始化函數(shù): void __init chrdev_init(void) { cdev_map = kobj_map_init(base_probe, &chrdevs_lock); bdi_init(&directly_mappable_cdev_bdi); } base_probe是一個很簡單的函數(shù): static struct kobject *base_probe(dev_t dev, int *part, void *data) { if (request_module('char-major-%d-%d', MAJOR(dev), MINOR(dev)) > 0) /* Make old-style 2.4 aliases work */ request_module('char-major-%d', MAJOR(dev)); return NULL; } request_module這個函數(shù)先大概知道意思就行了,他的意思是請求加載一個模塊,。 chrdevs_lock是一把大大的鎖,。沒別的,就這兩玩意。 關鍵在: struct kobj_map *kobj_map_init(kobj_probe_t *base_probe, struct mutex *lock) { struct kobj_map *p = kmalloc(sizeof(struct kobj_map), GFP_KERNEL); struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL); int i; if ((p == NULL) || (base == NULL)) { kfree(p); kfree(base); return NULL; } base->dev = 1; base->range = ~0; base->get = base_probe; for (i = 0; i < 255;=""> p->probes[i] = base; p->lock = lock; return p; } 最關鍵的一個角色就在這種神不知鬼不覺的情況下登場了,,那就是struct kobj_map,。 我們可以看到首先用kmalloc分配了一塊內(nèi)存并賦值給struct kobj_map *p了。 struct kobj_map { struct probe { struct probe *next; dev_t dev; unsigned long range; struct module *owner; kobj_probe_t *get; int (*lock)(dev_t, void *); void *data; } *probes[255]; struct mutex *lock; }; 里面內(nèi)嵌了一個長度為255的結構體數(shù)組和一把鎖,。 Linux內(nèi)核里面如果是直接分配比較大塊的內(nèi)存,基本都是有hash思想在里面的,,主要是為了效率,。這個結構體中的成員等會大家就知道干嘛用的了。 接下來 struct probe *base = kzalloc(sizeof(*base), GFP_KERNEL); 內(nèi)核作者你就賣弄吧,。寫成struct probe *base = kzalloc(sizeof(struct probe), GFP_KERNEL)這樣多好?不管了,,隨便了,反正我只取其精華,。 接下來: if ((p == NULL) || (base == NULL)) { kfree(p); kfree(base); return NULL; } 如果對這個有疑問的同志可以仔細研究一下kfree函數(shù),。這個是沒有問題的。我再說一個思想,,有疑問就看源碼,,不要去翻書,或者google百度的,。Linux內(nèi)核里面的函數(shù)全都是自給自足的,,你所有的疑問都可以通過翻閱內(nèi)核源碼本身得到解決。當然啦,,如果不是說不要去看書,,我的意思是能不看就盡量不看。 接下來: base->dev = 1; base->range = ~0; //取反,,比你寫一堆0xff...好多了,,并且可移植性更好 base->get = base_probe;//把函數(shù)指針指向傳進來的那個回調函數(shù)。 接下來: for (i = 0; i < 255;=""> p->probes[i] = base; 用base初始化整個kobj_map.probe[255],。 p->lock = lock; return p; 最后把鎖也傳過來,,并返回指針。 接下來: bdi_init(&directly_mappable_cdev_bdi); 這個玩意先不用管了,,這個對我們理解字符設備目前沒有任何幫助,,并且只能添亂。 好了,。今天就到這吧,。 |
|
來自: 西北望msm66g9f > 《編程》