4.一樣的精靈,不一樣的api(1)
usb_register()這個函式是用來向usb核心層,即usb core,註冊乙個usb裝置驅動的,而這裡我們註冊的是hub的驅動程式所對應的struct usb_driver結構體變數。定義於drivers/usb/ core/hub.c中:
2841 static struct usb_driver這裡面最重要的乙個函式就是hub_probe,很多事情都在這期間發生了。每個usb裝置(或者說所有裝置)的驅動都會有乙個probe函式,比如u盤的probe函式就是storage_probe(),不過storage_probe()被呼叫需要有兩個前提:第乙個前提是usb-storage被載入了,第二個前提是u盤等裝置插入了被檢測到了。hub_driver
= ;
而hub,說它特別,我可絕不是"忽悠"你。hub本身就有兩種:一種是普通的hub,一種是root hub。對於普通hub,它完全可能也和u盤一樣,在某個時刻被插入,然後在這種情況下hub_probe被呼叫,但是對於root hub就不需要這麼多廢話了,root hub肯定是有的,只要你有usb主機控制器,就一定會有root hub,所以hub_probe()基本上很自然地就被呼叫了,不用說非得等待某個插入事件的發生,沒這個必要。當然沒有usb主機控制器就沒有usb裝置能工作。那麼usb core這整個模組你就沒有必要分析了。所以,只要你有usb主機控制器,那麼在usb主機控制器的驅動程式初始化的過程中,它就會呼叫hub_probe()來探測root hub,不管你的主機控制器是ohci、uhci還是ehci的介面。
如果register一切順利的話,那麼返回值為0。如果返回值為負數,就說明出錯了。現在假設這一步沒有出錯。
usb_hub_init()的2862行,這行**其實是很有技術含量的,不過對於寫驅動的人來說,其作用就和當年的kernel_thread()相當。不過kernel_thread()返回值是乙個int型的,而kthread_run()返回的卻是struct task_struct結構體指標。這裡等號左邊的khubd_task是我們自己定義的乙個struct task_struct指標:
88 static struct task_struct *khubd_task;struct task_struct不用多說,記錄程序的資料結構。每乙個程序都用乙個struct task_struct結構體變數來表示。所以這裡所做的就是記錄下建立好的核心程序,以便日後要解除安裝模組時可以用另乙個函式來結束這個核心程序(你也可以叫核心執行緒),到時我們會呼叫kthread_stop(khubd_task)函式來結束這個核心執行緒,這個函式的呼叫我們將會在usb_hub_cleanup()函式中看到。而usb_hub_cleanup()正是hub裡面和usb_hub_init()相對應的函式。
2863行,判斷khubd_task,is_err是乙個巨集,用來判斷指標的。當你建立了乙個程序,你當然想知道這個程序建立成功了沒有。
以前我們注意到每次申請記憶體時都會做一次判斷,你說建立程序是不是也要申請記憶體?不申請記憶體誰來記錄struct task_struct?很顯然,要進行判斷。以前我們判斷的是指標是否為空。以後接觸**多了你會發現,其實linux核心中有很多種記憶體申請的方式,而這些方式所返回的記憶體位址也是不一樣的,所以並不是每一次我們都只要判斷指標是否為空就可以了。事實上,每一次呼叫kthread_run()之後,我們都會用乙個is_err()來判斷指標是否有效。is_err()為1就表示指標有錯,或者準確一點說叫做指標無效。
什麼叫指標無效?後面會專門解釋,讓我們繼續往下看,只需要記得,如果你不希望發生缺頁異常這樣的錯誤的話,每次呼叫完kthread_run()之後要用is_err()來檢測返回的指標。如果is_err()返回值是0,那麼說明沒有問題,於是返回值為 0,也就是說usb_hub_init()就這麼結束了。反之,就會執行usb_deregister(),因為核心執行緒沒有成功建立,hub就沒法驅動起來了。
最後函式在2870行,返回值為-1。回到usb_init()函式中我們會知道,接下來usb_hub_ cleanup()就會被呼叫。usb_hub_cleanup()同樣定義於drivers/usb/core/hub.c中:
2873 void usb_hub_cleanup(void)這個函式我想沒有任何必要解釋了吧。kthread_stop()和剛才的kthread_run()對應,usb_deregister()和usb_register()對應。2874 /* usb_hub_cleanup() */
總之,如果建立子程序出了問題,那麼一切都免談。
反之,如果成功了,那麼kthread_run()的三個引數就是我們要關注的了:第乙個是hub_thread(),子程序將從這裡開始執行。第二個是hub_thread(),傳遞的是null,第三個引數就是精靈程序的名字ps -el,如下所示:
localhost:/usr/src/linux-2.6.22/drivers/usb/core # ps -el | grep khubd你就會發現有這麼乙個精靈程序執行著。所以,下一步,讓我們進入hub_thread()來檢視這個子程序吧。1 s 0 1963 27 0 70 -5 - 0 hub_th ? 00:00:00 khubd
以下是關於is_err的介紹文字。如果你對記憶體管理沒有任何興趣,就不用往下看了。要想明白is_err(),首先你得知道有一種空間叫做核心空間,不清楚也不要緊。結合is_err()的**來看,來自include/linux/err.h:
16 #define max_errno 409517
18 #ifndef __assembly__
19
20 #define is_err_value(x) unlikely((x)
>
= (unsigned long)-max_errno)
21
22 static inline void *err_ptr(long error)
23
26
27 static inline long ptr_err(const void *ptr)
28
31
32 static inline long is_err(const void *ptr)
33
36
37 #endif
4 一樣的精靈,不一樣的API(2)
4 一樣的精靈,不一樣的api 2 關於核心空間,我只想說,所有的驅動程式都是執行在核心空間的,核心空間雖然很大,但總是有限的。而在這有限的空間中,其最後乙個page是專門保留的,也就是說,一般人不可能用到核心空間最後乙個page的指標。換句話說,你在寫裝置驅動程式的過程中,涉及的任何乙個指標,必然...
不一樣又不一樣的 木板接水
空地上豎立著n個從左到右排列的木板,它們可以把水擋住,但溢位最邊上木板的水將會流到空地上。已知木板間距都是單位1,現給定每個木板的高度,請求出總共能接住的水量?說明一點,這裡只考慮間距 寬度 和高度,不考慮第三個維度,因此水量是平方單位。木板高度分別是2,1,3,那麼我們可以接住2 2 4平方單位的...
一樣的月亮,不一樣的心情
轉眼間,又是一年的中秋佳節,這都是乙個懷鄉思親的節日,自從讀書和工作後,就很難有機會和父母 兄弟姐妹一起過了,在這個只掛燈籠但毫無節日氛圍的城市裡,你可以看到許許多多偽裝的慶祝和喜悅,一樣的月亮一樣的月光一樣的月餅,但心情卻是千差萬別,各顯千秋,最可憐的就是小朋友們了,他們失去了各種自然的 純樸的 ...