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

嵌入式教程之Linux的基礎命令詳細資料說明

嵌入式硬件系統教程之嵌入式存儲技術的詳細資料說明

評論