天天看點

Linux那些事兒之我是Hub(6)probe,又見probe!

話說因為hub驅動無所事事,是以hub_thread()進入了睡眠,直到某一天,hub_probe被調用.是以我們來看hub_probe().這個函數來自drivers/usb/hub.c,其作用就如同當初我們在usb-storage中的那個storage_probe()一樣.

    887 static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)

    888 {

    889         struct usb_host_interface *desc;

    890         struct usb_endpoint_descriptor *endpoint;

    891         struct usb_device *hdev;

    892         struct usb_hub *hub;

    893

    894         desc = intf->cur_altsetting;

    895         hdev = interface_to_usbdev(intf);

    896

    897 #ifdef  CONFIG_USB_OTG_BLACKLIST_HUB

    898         if (hdev->parent) {

    899                 dev_warn(&intf->dev, "ignoring external hub/n");

    900                 return -ENODEV;

    901         }

    902 #endif

    903

    904        

    905        

    906         if ((desc->desc.bInterfaceSubClass != 0) &&

    907             (desc->desc.bInterfaceSubClass != 1)) {

    908 descriptor_error:

    909                 dev_err (&intf->dev, "bad descriptor, ignoring hub/n");

    910                 return -EIO;

    911         }

    912

    913        

    914         if (desc->desc.bNumEndpoints != 1)

    915                 goto descriptor_error;

    916

    917         endpoint = &desc->endpoint[0].desc;

    918

    919        

    920         if (!usb_endpoint_is_int_in(endpoint))

    921                 goto descriptor_error;

    922

    923        

    924         dev_info (&intf->dev, "USB hub found/n");

    925

    926         hub = kzalloc(sizeof(*hub), GFP_KERNEL);

    927         if (!hub) {

    928                 dev_dbg (&intf->dev, "couldn't kmalloc hub struct/n");

929                 return -ENOMEM;

    930         }

    931

    932         INIT_LIST_HEAD(&hub->event_list);

    933         hub->intfdev = &intf->dev;

    934         hub->hdev = hdev;

    935         INIT_DELAYED_WORK(&hub->leds, led_work);

    936

    937         usb_set_intfdata (intf, hub);

    938         intf->needs_remote_wakeup = 1;

    939

    940         if (hdev->speed == USB_SPEED_HIGH)

    941                 highspeed_hubs++;

    942

    943         if (hub_configure(hub, endpoint) >= 0)

    944                 return 0;

    945

    946         hub_disconnect (intf);

    947         return -ENODEV;

    948 }

幸運的是這個函數還不是很長.看過usb-storage的兄弟姐妹們應該不難看懂這個函數.尤其是894,895這幾行經典的指派.盡管當年我們看的usb-storage是2.6.10的核心,而鬥轉星移,如今我們看的是2.6.22.1的核心,但是江山會變,四季會變,有些經典并不會改變.894行,desc,是這個函數裡定義的一個struct usb_host_interface結構體指針,其實這就相當于當年的那個altsetting,隻是換了個名字,别以為披上馬夾咱就不認識它了.struct usb_host_interface結構體的定義依然還是當初那樣,鑒于子曾經曰過溫故而知新,我們這裡再貼一次這個結構體吧,來自include/linux/usb.h:

     69

     70 struct usb_host_interface {

     71         struct usb_interface_descriptor desc;

     72

     73        

     76         struct usb_host_endpoint *endpoint;

     77

     78         char *string;          

     79         unsigned char *extra;  

     80         int extralen;

     81 };

需要注意的是,71行,這裡有一個成員,對應接口描述符的結構體,struct usb_interface_descriptor desc,剛才我們的那個指針也叫做desc,是以一會我們就會看到,desc->desc這樣的用法.

同樣895行這個指派我們也是很眼熟, interface_to_usbdev()這個宏就是為了從一個struct usb_interface的結構體指針得到那個與它相關的struct usb_device結構體指針.這裡等号右邊的intf自不必說,而左邊的hdev正是我們這裡為了hub而定義的一個struct usb_device結構體指針.

897到902行,這是為OTG而準備的,為了簡化問題,在這裡我做一個偉大的假設,即假設我們不支援OTG.在核心編譯選項中有一個叫做CONFIG_USB_OTG的選項,OTG就是On The Go的意思,正在進行中的意思,随着USB傳輸協定的誕生以及它的迅速走紅,人們不再滿足于以前那種一個裝置要麼就是主裝置,要麼就是從裝置的現狀,也就是說要麼是Host,或者叫主裝置,要麼是外設,也叫Slave,或者叫從裝置.那個年代裡,隻有當一台Host與一台Slave連接配接時才能實作資料的傳輸,而後來善良的開發者們又公布了USB OTG規範,于是出現了OTG裝置,即既可以充當Host,亦能充當Slave的裝置.就是說你有一個數位相機,你有一台列印機,它們各有一個USB接口,把這兩個口連接配接起來,然後就可以把你偷拍的美女照片列印出來了.不過我們為了省事,還是别玩這種高科技了吧,省點時間玩幾盤CS不是挺好麼?是以我隻能假設我們不打開支援OTG的編譯開關,而這裡我們看到的CONFIG_USB_OTG_BLACKLIST_HUB,其實就是一CONFIG_OTG下面的子選項,不選後者根本就見不到前者,是以咱們也不用看.

904到911行,這我真是無話可說了,每一個USB裝置它屬于哪個類,以及哪個子類,這都是上天注定的,自打盤古開天地那會兒就已經确定下來了,比如hub的子類就是0,即desc->desc這個interface描述符裡邊的bInterfaceSubClass就該是0.是以這裡本是判斷如果bInterfaceSubClass不為0那就出錯了,那就甭往下走了,傳回吧,傳回值是-EIO.就像一個人如果連自己是哪一類物種都能弄錯,那還活個什麼勁呢?不過我真正來氣的是偏偏有些沒事找抽型的企業愣是把自己家生産的hub裡邊的描述符中的bInterfaceSubClass這一位弄成了1,完了實踐證明該hub也還能工作,别的方面都還正常,你說你要是調試裝置驅動程式老是碰上這樣的裝置是不是非得急死你?

914,915行,其實幹的事情是差不多的,針對接口描述符再做一次判斷,這次是判斷這個hub有幾個端點,或者說Endpoint.spec規定了hub就是一個endpoint,中斷endpoint,因為hub的傳輸是中斷傳輸.當然還有控制傳輸,但是因為控制傳輸是每一個裝置都必須支援的,即每一個usb裝置都會有一個控制端點,是以在desc->desc.bNumEndpoints中是不包含那個大家都有的控制端點的.是以如果這個值不為1,那麼就說明又出錯了,仍然隻能是傳回.

917行,就是得到這個唯一的端點所對應的端點描述符,920和921行就是判斷這個端點是不是中斷端點,如果不是那還是一樣,傳回報錯吧.

如果以上幾種常見的錯誤都沒有出現,那這時候我們才開始正式的去做一些事情,讓我們繼續,向前進,向前進,戰士的責任重,婦女的冤仇深.

924行,列印調試資訊.

926行,申請hub的資料結構struct usb_hub.早些時候我們已經貼出來這個結構體的定義了,不記得的回去看看.不過926行有一個很新潮的函數,kzalloc().其實這個函數就是原來的兩個函數的整合,即原來我們每次申請記憶體的時候都會這麼做,先是用kmalloc()申請空間,然後用memset()來初始化,而現在省事了,一步到位,直接調用kzalloc(),效果等同于原來那兩個函數,所有申請的元素都被初始化為0.其實對寫驅動的來說,知道現在應該用kzalloc()代替原來的kmalloc()和memset()就可以了,這是核心中記憶體管理部分做出的改變,确切的說是改進,負責記憶體管理那部分的兄弟們的目标無非就是讓核心跑起來更快一些,而從kmalloc/memset到kzalloc的改變确實也是為了實作這方面的優化.是以自從2005年底核心中引入kzalloc之後,忽如一夜春風來,整個核心代碼的許多子產品裡面都先後把原來的kmalloc/memset統統換成了kzalloc().咱們這裡就是其中一處.927到930行不用說了,如果沒申請成功那就挂了,傳回ENOMEM.

932行,還記得咱們之前說了什麼嗎,總分的想法,一個總的事件隊列,hub_event_list,然後各個hub都有一個分的事件隊列,就是這裡的hub->event_list,前面咱們初始化了全局的那個hub_event_list,而這裡咱們針對單個hub就得為其初始化一個event_list.

933行和934行,struct usb_hub中的兩個成員,struct device *intfdev, struct usb_device *hdev,幹嘛用的想必不用多說了吧,第一個,甭管你是usb裝置也好,pci裝置也好,scsi裝置也好,Linux核心中都為你準備一個struct device結構體來描述,是以intfdev就是和咱們這usb hub相關聯的struct device指針,第二個,甭管你是hub也好,u盤也好,移動硬碟也好,usb滑鼠也好,usb core都為你準備一個struct usb_device來描述,是以hdev就将是與咱們這個hub相對應的struct usb_device指針.而這些,在我們調用hub_probe之前就已經建立好了,都在那個參數struct usb_interface *intf中,具體怎麼得到的,對于root hub來說,這涉及到host controller的驅動程式,咱們先不去理睬.但對于一個普通的外接的hub,那咱們一會兒會看到如何得到它的struct usb_interface,因為建立并初始化一個usb裝置的struct usb_interface正是hub驅動裡做的事情.其實也就是我們對hub驅動最好奇的地方.因為找到了這個問題的答案,我們就知道了對于一個usb裝置驅動,其probe指針是在什麼情況下被調用的,比如咱們這裡的hub_probe對于普通hub來說是誰調用的?比如咱們之前那個usb-storage中最有意思的函數storage_probe()究竟是誰調用的?這正是我們想知道的.

繼續閱讀