日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux USB 驱动开发实例 (三)—— 基于USB总线的无线网卡浅析

發(fā)布時間:2023/12/9 linux 45 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux USB 驱动开发实例 (三)—— 基于USB总线的无线网卡浅析 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

回顧一下USB的相關(guān)知識

? ? ???USB(Universal Serial Bus)總線又叫通用串行外部總線,它是20世紀(jì)90年代發(fā)展起來的。USB接口現(xiàn)在得到了廣泛的應(yīng)用和普及,現(xiàn)在的PC機中都帶有大量的USB接口。它最大的特點就是方便通用、支持熱插拔并且可以在一個接口上插上多個設(shè)備。當(dāng)設(shè)備用電量小的時候,它還可以充當(dāng)電源。它的眾多優(yōu)點使得它得到了廣泛的應(yīng)用。

? ? ? ?在PC機器內(nèi)部有個USB中央控制器,這個中央控制器負(fù)責(zé)管理插到USB接口上的設(shè)備。當(dāng)主機要向設(shè)備發(fā)送或接受數(shù)據(jù)時,都是向USB中央控制器發(fā)出命令USB設(shè)備不具備主動與主機通信的能力。編寫USB設(shè)備驅(qū)動不用考慮申請設(shè)備地址空間,因為USB中央控制器會給設(shè)備分配一個設(shè)備號,這個設(shè)備號就代表這個設(shè)備。 ?

? ? ? ?USB設(shè)備和USB中央控制器之間的通信是通過端點來完成的。端點的職能有點類似一棟大樓的傳達(dá)室。例如每個樓層都有一個傳達(dá)室,當(dāng)要訪問5樓的10號房間時,那就是向5號端點發(fā)起對話,并提供偏移量,也就10號房間。USB接口的端點按傳輸信息的類型分為以下4種: ?

a -- 控制端點

? ? ?主要用來傳輸控制信息的,例如配置設(shè)備時發(fā)出的控制信息。控制端點一般都是雙向,既可以輸入又可以輸出。其他端點的輸出方向一般是單向的,要么是輸入,要么是輸出的。這里是站在主機的角度來談?wù)撦斎胼敵龅摹??

b -- 中斷端點

? ? ?主要用來傳輸中斷信息的,由于USB設(shè)備是受USB中央控制器管理的,因此USB設(shè)備沒有向主機發(fā)出中斷的能力,并且USB設(shè)備不能主動向主機發(fā)出請求,只有主機可以向USB設(shè)備發(fā)出命令請求,因此所謂的中斷是指主機周期性的查詢USB設(shè)備。 ?

c -- 批量端點

? ? ?主要用來傳輸批量信息的,批量信息就意味著大量的信息。U盤一般主要使用的就是批量端點。本文研究的USB無線網(wǎng)卡也是使用批量斷點來傳輸數(shù)據(jù)的。發(fā)送和接收函數(shù)都是使用批量端點和USB設(shè)備傳輸數(shù)據(jù)的。 ?

b -- 等時端點

? ? 主要用來傳輸?shù)葧r信息的,主要用于傳輸實時性要求較高的信息,例如實時的音頻、視頻等信息。有代表性的USB設(shè)備是USB攝像頭等。 ?

? ? 在一個具體的USB設(shè)備中不要求一定都存在這4種類型的端點,例如U盤一般就只有批量端點和控制端點。在Linux內(nèi)核中用來描述USB設(shè)備端點信息的數(shù)據(jù)結(jié)構(gòu)如下:

[cpp]?view plaincopy
  • struct?usb_endpoint_descriptor?{????????????
  • ????__u8??bLength;????????????
  • ????__u8??bDescriptorType;????????????
  • ????__u8??bEndpointAddress;????????????
  • ????__u8??bmAttributes;????????????
  • ????__le16?wMaxPacketSize;????????????
  • ????__u8??bInterval;????????????????
  • ????__u8??bRefresh;????????????
  • ????_u8??bSynchAddress;????
  • }?__attribute__?((packed));???
  • ? ? ? 成員bLength描述本數(shù)據(jù)結(jié)構(gòu)共有多少字節(jié),因為后兩個成員是針對音頻設(shè)備的,如果不是音頻設(shè)備則可以沒有后兩個成員。成員bDescriptorType是描述本數(shù)據(jù)結(jié)構(gòu)要描述的類型,這里是描述端點的,在內(nèi)核中0x05就代表端點

    ? ? ??成員bEndpointAddress包含端點號和輸出方向,bits0-bits3表示的是端點號,從這里可以看出一個USB設(shè)備最多只能有不超過16個端點,bits8是代表傳輸方向的,如果該位是1就代表輸入,也就是讀設(shè)備;如果該位為0就代表輸出,也就是寫設(shè)備。

    ? ???成員bmAttributes?表示該端點的類型,如上述的4種類型。

    ? ? ?成員wMaxPacketSize表示該端點一次可以傳輸?shù)淖疃嘧止?jié)數(shù)。如果要傳輸?shù)臄?shù)據(jù)大于這個數(shù)字,那就要分多次傳輸。成員bInterval代表的是該端點希望主機輪詢自己的時間間隔,這只是一種希望,具體還要看主機怎么做。

    ? ? ?該數(shù)據(jù)結(jié)構(gòu)最后的__attribute__((packed))代表在分配該數(shù)據(jù)結(jié)構(gòu)時數(shù)據(jù)成員之間不要為了內(nèi)存對齊而留下空隙,例如有這樣一個數(shù)據(jù)結(jié)構(gòu)的相鄰兩個成員類型是u8 和u16,在一般情況下u8后面要空一個字節(jié),然后才是u16成員,如果有上面attribute的要求后,在u8后面就不要留空間,緊接著就是u16成員。在內(nèi)核中有很多需要訪問設(shè)備的數(shù)據(jù)結(jié)構(gòu)都有這樣的要求,因為在一個設(shè)備中一般沒有內(nèi)存對齊的要求。


    ?

    一、USB設(shè)備驅(qū)動程序的構(gòu)成

    1、設(shè)備的探測

    ? ? ? ?用于檢查傳遞給探測函數(shù)的設(shè)備信息,確認(rèn)驅(qū)動程序是否適合該設(shè)備。

    2、數(shù)據(jù)的發(fā)送和接收

    ? ? ? ?負(fù)責(zé)主機到設(shè)備的發(fā)送和設(shè)備到主機的數(shù)據(jù)接收。

    3、設(shè)備斷開

    ? ? ? 當(dāng)設(shè)備斷開時候,模塊負(fù)責(zé)清除和該設(shè)備關(guān)聯(lián)的所有資源。

    4、模塊的加載和卸載

    ? ? ? 用于加載和卸載usb接口的無線網(wǎng)卡驅(qū)動程序。


    二、USB無線網(wǎng)卡的構(gòu)成

    ? ? ? ? USB無線網(wǎng)卡主要由USB接口、MAC控制器、基帶處理、調(diào)制解調(diào)器、功率放大器收發(fā)器及天線等組成。

    ? ? ? ??MAC控制器是核心部件,它負(fù)責(zé)從主機讀取數(shù)據(jù)并發(fā)送出去,或者接收數(shù)據(jù)并發(fā)送給主機等。它負(fù)責(zé)通道選擇、速率選擇、加密解密等等的控制。

    ? ? ??? 固件存儲區(qū)是用來存儲MAC控制器要運行的微碼。固件是一種經(jīng)過編譯的可執(zhí)行代碼,一般是由設(shè)備的芯片來執(zhí)行的。

    ? ? ? ?幀緩存就是用來存儲數(shù)據(jù)的暫時場所。

    ? ? ???EEPROM是否有沒有要看具體的設(shè)備,有的設(shè)備是沒有的,EEPROM一般都存放一些本設(shè)備的一些參數(shù),例如本設(shè)備的MAC地址,本設(shè)備在家族產(chǎn)品中的型號等等。

    ? ??? ?基帶處理和ADC、DAC是數(shù)模擬轉(zhuǎn)換的功能部分。要發(fā)送的數(shù)據(jù)或者接收的模擬信號在這個地方進行轉(zhuǎn)換。

    ? ? ?? 收發(fā)器的功能類似調(diào)制解調(diào)器,收發(fā)器內(nèi)部有個功率放大器,把弱信號增強到一定的強信號,收發(fā)器還負(fù)責(zé)濾波等工作。

    ? ??? 天線系統(tǒng)就是負(fù)責(zé)把數(shù)據(jù)通過天線發(fā)送或接收。天線的作用是使傳輸距離更遠(yuǎn)。

    USB接口無線網(wǎng)卡的硬件邏輯:



    USB無線網(wǎng)卡的通道和速率是多個的,在發(fā)送和接收時通道和速率是可以變換的。在Linux中通道用如下數(shù)據(jù)結(jié)構(gòu)表示:

    [cpp]?view plaincopy
  • struct?ieee80211_channel?{??
  • ????enum?ieee80211_band?band;????
  • ????u16?center_freq;????
  • ????u16?hw_value;???
  • ????u32?flags;?????
  • ????int?max_antenna_gain;????
  • ????int?max_power;????
  • ????bool?beacon_found;????
  • ????u32?orig_flags;?????
  • ????int?orig_mag,?orig_mpwr;????
  • };??


  • 三、模塊的加載

    ? ? ? ?在編寫USB無線網(wǎng)卡驅(qū)動函數(shù)之前,首先先了解一下設(shè)備在插入到USB接口到設(shè)備成功找到它自己的驅(qū)動這一過程。

    1、獲取設(shè)備一些信息,發(fā)生在USB核心

    ? ? ? 當(dāng)把USB設(shè)備插到USB接口上后,USB主機控制器會檢測到有設(shè)備插入USB接口了,Linux內(nèi)核會給設(shè)備分配一個數(shù)據(jù)結(jié)構(gòu)來代表這個設(shè)備。本文中涉及的硬件是USB設(shè)備,因此Linux會分配一個struct usb_device數(shù)據(jù)結(jié)構(gòu)來代表該設(shè)備,該數(shù)據(jù)結(jié)構(gòu)記錄設(shè)備的一些屬性及數(shù)據(jù)。并把該數(shù)據(jù)結(jié)構(gòu)掛載到一個全局的USB設(shè)備鏈上。在這一期間主機通過0號端點(控制端點)得知了設(shè)備的一些信息,并知道了設(shè)備的廠家號和產(chǎn)品號。

    2、找到匹配的驅(qū)動,發(fā)生在USB核心

    ? ? ? 然后到一個全局的USB驅(qū)動鏈上查找,看看哪個驅(qū)動程序支持的設(shè)備列表中有該設(shè)備的廠家號和產(chǎn)品號。當(dāng)找到后設(shè)備就和驅(qū)動匹配上了。?

    ? ? 了解了上面的過程后,首先需要注冊一個代表USB驅(qū)動的數(shù)據(jù)結(jié)構(gòu),并要明確表示本驅(qū)動要支持的設(shè)備。在模塊初始化函數(shù)module_init中,通過usb_register_driver注冊一個usb驅(qū)動程序。USB核心將調(diào)用通過usb_register_driver注冊的探測回調(diào)函數(shù),在Linux中代表USB驅(qū)動的數(shù)據(jù)結(jié)構(gòu)部分成員如下:

    [cpp]?view plaincopy
  • struct?usb_driver{??
  • ????.name="alld";??
  • ????.probe=ad_probe;??
  • ????.disconnect=ad_disconnect;??
  • ????.id_table=ad_usb_ids;??
  • };??
  • ? ? ? 該數(shù)據(jù)結(jié)構(gòu)中name成員是代表該驅(qū)動的名稱,該名稱在USB驅(qū)動中必須要獨一無二的,不能和別的驅(qū)動的名字重復(fù),在起名字的時候最好和模塊名字相同。? ? ??

    ? ? ?成員 probe()函數(shù)指針就是本章要實現(xiàn)的探索函數(shù),該函數(shù)在本驅(qū)動和設(shè)備的廠家號和產(chǎn)品號相匹配后調(diào)用,作用是探索該驅(qū)動是否支持該設(shè)備,如果支持該設(shè)備的接口,那么在probe函數(shù)中調(diào)用usb_set_intfdata(struct usb_interface *intf, void *data)函數(shù),該函數(shù)中的第一個參數(shù)就是的驅(qū)動要支持的那個設(shè)備接口數(shù)據(jù)結(jié)構(gòu)的指針,第二個參數(shù)是該驅(qū)動為了實現(xiàn)接口正常運行而分配的自己的數(shù)據(jù)結(jié)構(gòu)。

    ? ? ? usb_set_intfdata()的作用就是把接口和它的驅(qū)動要用到的數(shù)據(jù)結(jié)構(gòu)關(guān)聯(lián)起來。成功后返回0;如果不支持該設(shè)備那么返回-ENODEV。

    ? ? ? 函數(shù)probe()的參數(shù)usb_interface驗證了前文所說的一個接口對應(yīng)一個驅(qū)動,本文所涉及的設(shè)備都是單一接口的,因此沒有太區(qū)分接口和設(shè)備的差別,probe()的第二個參數(shù)usb_device_id數(shù)據(jù)結(jié)構(gòu)就包含了上文提及的廠家號和產(chǎn)品號。它是設(shè)備的廠家號和產(chǎn)品號,而usb_driver的id_table是本驅(qū)動支持的所有設(shè)備的廠家號和產(chǎn)品號的列表。

    ? ? ? 成員disconnect函數(shù)指針指向的函數(shù)的作用是當(dāng)設(shè)備已經(jīng)移走或者模塊被卸載時調(diào)用,主要就是處善后工作,例如已經(jīng)注冊的取消注冊,已經(jīng)分配的內(nèi)存釋放掉。


    四、私有數(shù)據(jù)結(jié)構(gòu)的設(shè)計

    ? ? ? ?上文中提到 probe()函數(shù)中要調(diào)用usb_set_intfdata()函數(shù),該函數(shù)的第二個參數(shù)就是本文驅(qū)動程序要用到的私有數(shù)據(jù)結(jié)構(gòu)。由于驅(qū)動程序是工作在ieee802.11協(xié)議層,ieee802.11為驅(qū)動程序提供了一個分配內(nèi)存函數(shù)ieee80211_hw*ieee80211_alloc_hw(size_t priv_data_len,const struct ieee80211_ops *ops),該函數(shù)第一個參數(shù)是自己驅(qū)動程序中的私有數(shù)據(jù)結(jié)構(gòu)的長度,第二個參數(shù)是上文提及的指向驅(qū)動程序各個函數(shù)的數(shù)據(jù)結(jié)構(gòu)的指針,正是在這里把驅(qū)動程序的所有函數(shù)提供給ieee802.11協(xié)議層的。ieee80211_alloc_hw()函數(shù)是即分配了802.11協(xié)議層需要的內(nèi)存結(jié)構(gòu),又順便分配了驅(qū)動的私有數(shù)據(jù)結(jié)構(gòu),該函數(shù)分配的內(nèi)存結(jié)構(gòu)如下圖所示。圖中除了驅(qū)動程序自己的私有數(shù)據(jù)結(jié)構(gòu),其他幾個數(shù)據(jù)結(jié)構(gòu)都是802.11協(xié)議層使用的數(shù)據(jù)結(jié)構(gòu)。需要設(shè)計自己的私有數(shù)據(jù)結(jié)構(gòu),把這個私有數(shù)據(jù)結(jié)構(gòu)抽象成為設(shè)備,把和設(shè)備有關(guān)的參數(shù)都設(shè)計成為數(shù)據(jù)結(jié)構(gòu)放到這個私有數(shù)據(jù)結(jié)構(gòu)中,在編寫驅(qū)動程序的各個函數(shù)時,只要傳遞了私有數(shù)據(jù)結(jié)構(gòu)的指針,就能找到所有關(guān)于設(shè)備的參數(shù),并且它是全局的。


    ? ? ? ? 函數(shù)ieee80211_alloc_hw()成功后返回的是struct ieee80211_hw結(jié)構(gòu)的指針,而該結(jié)構(gòu)的priv指向了的私有數(shù)據(jù)結(jié)構(gòu)。本文設(shè)計的私有數(shù)據(jù)結(jié)構(gòu)如下:

    [cpp]?view plaincopy
  • struct?priv_dev{????
  • ????unsigned?long??????????flags;??????????
  • ????struct?usb_device???????*udev;?????
  • ????struct?usb_interface?????*intf;?????
  • ????struct?ieee80211_hw?????*hw;????
  • ????loff_t??????????????????savep;????????
  • ????char????????????????????fw_name[64];???
  • ????char????????????????????path[64];??????
  • ????u8?*eeprom;???struct?ieee80211_supported_band?bands[IEEE80211_NUM_BANDS];????
  • ????enum?ieee80211_band?????curr_band;????
  • ????spinlock_t??????????????list_lock;?????
  • ????struct?mutex?????list_op,rw_lock;????
  • ????int????????????????????timeout;????
  • ????struct?list_head???cfmg_list[30];???
  • ????u8???bulk[BULKSIZE];?????
  • ????struct?config_msg?*msg_fun[10];//record?config_msg()??position????
  • ????unsigned?char?*skb_data,*skb_tail,*rx_skb_data,*rx_skb_tail;????
  • ????struct?data_queue?*rx,*tx,*beacon;????
  • ????struct??prob_desc?probdesc;????
  • ????struct?priv_rate?*privrate;????
  • ????struct?priv_channel?*privchannel;????
  • ????struct?privdev_rx_status????rxstatus;????
  • ????struct?priv_intf???privintf;????
  • ????u32?parameter[PRIV_PARAMETER_SIZE];????
  • ????int?sparameter[PRIV_PARAMETER_SIZE];????
  • ????struct?pstack????ps;????
  • };???
  • ? ? ? ?其中成員udev、intf和hw成員都是指向上層的數(shù)據(jù)結(jié)構(gòu),有了這些成員后可以很 方便的尋找上層數(shù)據(jù)結(jié)構(gòu)。成員savep是用于在讀參數(shù)文件時記錄參數(shù)文件的偏移量,path成員是參數(shù)文件所在路徑及參數(shù)文件的名字。成員fw_name是用來存放設(shè)備固件程序的名字。成員eeprom只有在設(shè)備存在EEPROM的時候才有意義,如果設(shè)備有EEPROM,那么本文的做法是分配一個和設(shè)備EEPROM一樣大小的內(nèi)存來存放EEPROM中所有的數(shù)據(jù),這樣的好處是當(dāng)要從EEPROM中讀數(shù)據(jù)時,就從內(nèi)存讀取,這樣提升了讀取的速度。這樣也防止錯誤代碼把EEPROM中的數(shù)據(jù)沖掉了。成員bands和curr_band記錄本設(shè)備所在的頻帶及通道和速率列表,bands數(shù)據(jù)結(jié)構(gòu)中存在指向通道和速率的指針成員。成員list_lock、list_op和rw_lock都是鎖[29],list_lock是自旋鎖,它用于短時間的鎖,它的特點是在獲取鎖失敗后不睡眠,而是一直循環(huán)查詢鎖的狀態(tài)。List_op和rw_lock是互斥鎖,它可以用于長時間鎖,它的特點是獲取鎖不成功就阻塞在鎖的鏈表上。成員timeout是和設(shè)備通信的定時器時間,由于本驅(qū)動框架想要支持多個設(shè)備,那么它的值就從參數(shù)文件中讀取。成員cfmg_list就是上文提及的參數(shù)鏈鏈頭指針數(shù)組,struct list_head數(shù)據(jù)結(jié)構(gòu)是Linux中的常用的雙向鏈表結(jié)構(gòu),它的結(jié)構(gòu)非常簡單:?

    struct list_head { ? ? ? ? ?

    ? ? ? ? ? ?struct list_head *next, *prev; ??

    }; ?

    成員next指向下一個list_head數(shù)據(jù)結(jié)構(gòu),prev指向上一個list_head數(shù)據(jù)結(jié)構(gòu)。那么如何使用list_head呢?在使用時把list_head嵌入到宿主數(shù)據(jù)結(jié)構(gòu)中,只要知道list_head的地址,就可以算出宿主數(shù)據(jù)結(jié)構(gòu)的地址。內(nèi)核中給提供了list_entry(ptr,type,member)這個宏來計算宿主數(shù)據(jù)結(jié)構(gòu)的地址,ptr就是宿主數(shù)據(jù)結(jié)構(gòu)中l(wèi)ist_head成員的地址,type是宿主數(shù)據(jù)結(jié)構(gòu)的類型,member是list_head數(shù)據(jù)結(jié)構(gòu)在宿主數(shù)據(jù)結(jié)構(gòu)中的成員名字,在本文中如果知道list_head的指針例如head,那么config_msg的地址就是list_entry(head,struct config_msg,list)。?



    五、操作函數(shù)集

    ? ? ? ? 當(dāng)探索完成后,就要編寫驅(qū)動程序的打開、發(fā)送等函數(shù)。這些函數(shù)都要填充到下面 struct ieee80211_ops數(shù)據(jù)結(jié)構(gòu)中去:

    [cpp]?view plaincopy
  • struct?ieee80211_ops{??
  • ????int?(*tx)(struct?ieee80211_hw?*hw,?struct?sk_buff?*skb);??
  • ????int?(*start)(struct?ieee80211_hw?*hw);??
  • ????void?(*stop)(struct?ieee80211_hw?*hw);??
  • ????int?(*add_interface)(struct?ieee80211_hw?*hw,??
  • ????????????????struct?ieee80211_if_init_conf?*conf);??
  • ????void?(*remove_interface)(struct?ieee80211_hw?*hw,??
  • ?????????????????struct?ieee80211_if_init_conf?*conf);??
  • ????int?(*config)(struct?ieee80211_hw?*hw,?u32?changed);??
  • ????void?(*bss_info_changed)(struct?ieee80211_hw?*hw,??
  • ?????????????????struct?ieee80211_vif?*vif,??
  • ?????????????????struct?ieee80211_bss_conf?*info,??
  • ?????????????????u32?changed);??
  • };??
  • ? ?這里只列舉了部分主要的函數(shù),一個驅(qū)動程序不一定要把這個數(shù)據(jù)結(jié)構(gòu)中的所有函數(shù)指針?biāo)赶虻暮瘮?shù)都實現(xiàn)了,這要根據(jù)具體設(shè)備的情況而定。其中tx函數(shù)指針是指向發(fā)送函數(shù),start函數(shù)指針指向的是開始函數(shù),config函數(shù)指針指向的是配置函數(shù),stop函數(shù)是停止函數(shù)等等。當(dāng)把這里必須要實現(xiàn)的函數(shù)指針實現(xiàn)后,驅(qū)動程序就算寫完了。


    六、USB接口無線網(wǎng)卡數(shù)據(jù)的接收

    ? ? ? ?與pci、pcmia等無線網(wǎng)卡不同,usb總線沒有中斷資源。因此usb無線網(wǎng)卡的數(shù)據(jù)接收不通過中斷實現(xiàn),而是在open函數(shù)通過主機主動查詢是否有數(shù)據(jù)需要讀取

    ? ? ? ?因此,在open函數(shù)中向usb core發(fā)送一個讀請求的urb,使得網(wǎng)絡(luò)數(shù)據(jù)到來時候,主機能夠接收到。

    open回調(diào)函數(shù)主要代碼:

    [cpp]?view plaincopy
  • ......??
  • usb_fill_bulk_urb(dev->rx_urb,//構(gòu)造讀請求的urb??
  • dev->udev,??
  • usb_rcvbulkpipe(dev->udev,6),//指定讀得端點??
  • dev->rx_skb->data,??
  • 512,//count??
  • rx_complete,//讀請求的回調(diào)函數(shù)??
  • dev??
  • );??
  • ??
  • if(result=usb_submit_urb(dev->urb,GFP_KERNEL))??
  • {??
  • 將發(fā)送給kernel的usb?core??
  • }??
  • ? ? ?讀請求完成時候,read_bulk_callback函數(shù)將被內(nèi)核調(diào)用,它構(gòu)造一個skb_bufff數(shù)據(jù)結(jié)構(gòu)來描述數(shù)據(jù)包,并調(diào)用netif_rx把數(shù)據(jù)包傳給網(wǎng)絡(luò)子系統(tǒng),從而完成一次數(shù)據(jù)的接收過程。


    七、USB接口無線網(wǎng)卡數(shù)據(jù)的發(fā)送

    ? ? ? ?當(dāng)網(wǎng)絡(luò)子系統(tǒng)要發(fā)送一個數(shù)據(jù)時候,上層協(xié)議會構(gòu)造一個sk_buff來描述一個數(shù)據(jù)包,并調(diào)用驅(qū)動程序注冊和實現(xiàn)的hard_start_xmit來發(fā)送數(shù)據(jù)包,由于該函數(shù)被調(diào)用時候,網(wǎng)絡(luò)子系統(tǒng)持有xmit_lock自旋鎖,因此驅(qū)動程序不必考慮設(shè)備寫操作的同步問題。hard_start_xmit根據(jù)數(shù)據(jù)包的長度,拆分成usb設(shè)備可以傳輸?shù)拈L度,然后構(gòu)造相應(yīng)地寫請求urb,發(fā)送至usb core即可。

    hard_start_xmit回調(diào)函數(shù)的主要代碼:

    [cpp]?view plaincopy
  • ......??
  • usb_fill_bulk_urb(dev->tx_urb,//構(gòu)造寫請求的urb??
  • dev->udev,??
  • usb_sndbulkpipe(dev->udev,2),//指定寫端點??
  • skb->data,??
  • 512,//count??
  • write_bulk_callback,//寫請求的回調(diào)函數(shù)??
  • dev??
  • );??
  • ??
  • if(result=usb_submit_urb(dev->tx_urb,GFP_ATOMIC))??
  • {??
  • 將發(fā)送給usb?core??
  • }??
  • 寫請求完成時候,write_bulk_callback回調(diào)函數(shù)將被調(diào)用,根據(jù)發(fā)送情況更新統(tǒng)計數(shù)據(jù)


    八、設(shè)備的斷開

    ? ? ? ?我們已經(jīng)分析了usb_driver結(jié)構(gòu)的探測函數(shù),與設(shè)備探測對應(yīng)的是設(shè)備的斷開。設(shè)備斷開可以看做是設(shè)備探測的逆過程,主要工作是釋放驅(qū)動程序已經(jīng)分配的系統(tǒng)資源。

    ? ? ? ?設(shè)備斷開調(diào)用了usb_driver結(jié)構(gòu)的disconnect(struct usb_interface *)函數(shù),函數(shù)首先通過調(diào)用usb_get_intfdata()獲取相關(guān)資源,然后通過usb_set_intfdata(intf,NULL)將資源清零,并釋放資源。


    九、模塊的卸載

    ? ? ? 與模塊加載對應(yīng)的是模塊的卸載,module_exit函數(shù)首先調(diào)用usb_rtusb_exit()卸載網(wǎng)卡驅(qū)動程序,接著調(diào)用usb_deregister(&rtusb_driver)實現(xiàn)設(shè)備的注銷。


    十、IOCTL函數(shù)

    ? ? ? ?Linux中要讓網(wǎng)卡正常工作需要配置IP地址、SSID、工作頻段、工作模式等,這些控制操作都是通過ifconfig和iwconfig調(diào)用驅(qū)動實現(xiàn)的IOCTL函數(shù)實現(xiàn)的。驅(qū)動程序通過IOCTL為應(yīng)用程序提供了一些諸如IO內(nèi)存地址讀寫訪問、配置空間寄存器讀寫訪問、數(shù)據(jù)成員讀寫訪問等函數(shù),通過這些函數(shù),應(yīng)用程序就可以對設(shè)備進行相應(yīng)地操作,其各種函數(shù)都是通過IOCTL命令實現(xiàn)的。應(yīng)用程序?qū)OCTL命令將有關(guān)信息傳遞到驅(qū)動程序的內(nèi)核空間,驅(qū)動程序再處理相應(yīng)地操作。

    ? ? ? 例如該函數(shù)的原型:

    ? ? ??rtxxx_ioctl(struct net_device * net_dev,struct ifreq * ,int cmd)

    總結(jié)

    以上是生活随笔為你收集整理的Linux USB 驱动开发实例 (三)—— 基于USB总线的无线网卡浅析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。