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

歡迎訪問 生活随笔!

生活随笔

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

linux

Linux 下wifi 驱动开发(四)—— USB接口WiFi驱动浅析

發(fā)布時(shí)間:2023/12/9 linux 59 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux 下wifi 驱动开发(四)—— USB接口WiFi驱动浅析 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前面學(xué)習(xí)了SDIO接口的WiFi驅(qū)動(dòng),現(xiàn)在我們來學(xué)習(xí)一下USB接口的WiFi驅(qū)動(dòng),二者的區(qū)別在于接口不同。而USB接口的設(shè)備驅(qū)動(dòng),我們前面也有學(xué)習(xí),比如USB攝像頭驅(qū)動(dòng)、USB鼠標(biāo)驅(qū)動(dòng),同樣都符合LinuxUSB驅(qū)動(dòng)結(jié)構(gòu):


? ? ? ? USB設(shè)備驅(qū)動(dòng)(字符設(shè)備、塊設(shè)備、網(wǎng)絡(luò)設(shè)備)

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? USB 核心

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? USB主機(jī)控制器驅(qū)動(dòng)


? ? ? ? 不同之處只是在于USB攝像頭驅(qū)動(dòng)是字符設(shè)備,而我們今天要學(xué)習(xí)的WiFi驅(qū)動(dòng)是網(wǎng)絡(luò)設(shè)備;當(dāng)然由我們編寫的部分還是USB設(shè)備驅(qū)動(dòng)部分,下面進(jìn)入U(xiǎn)SB接口WiFi驅(qū)動(dòng)的分析,如何分析呢?我們下面從這幾個(gè)方面入手:

? ? ? ? 從硬件層面上看,WIFI設(shè)備與CPU通信是通過USB接口的與其他WIFI設(shè)備之間的通信是通過無線射頻(RF)

? ? ? ? 從軟件層面上看,Linux操作系統(tǒng)要管理WIFI設(shè)備,那么就要將WIFI設(shè)備掛載到USB總線上,通過USB子系統(tǒng)實(shí)現(xiàn)管理。而同時(shí)為了對(duì)接網(wǎng)絡(luò),又將WIFI設(shè)備封裝成一個(gè)網(wǎng)絡(luò)設(shè)備

? ? ? ? 我們以USB接口的WIFI模塊進(jìn)行分析:

a -- 從USB總線的角度去看,它是USB設(shè)備;

b -- 從Linux設(shè)備的分類上看,它又是網(wǎng)絡(luò)設(shè)備;

c -- 從WIFI本身的角度去看,它又有自己獨(dú)特的功能及屬性,因此它又是一個(gè)私有的設(shè)備;

通過上述的分析,我們只要抓住這三條線索深入去分析它的驅(qū)動(dòng)源碼,整個(gè)WIFI驅(qū)動(dòng)框架就會(huì)浮現(xiàn)在你眼前。


一、框架整理

1、USB設(shè)備驅(qū)動(dòng)

? ? ? 現(xiàn)在我們先從USB設(shè)備開始,要寫一個(gè)USB設(shè)備驅(qū)動(dòng),那么大致步驟如下:

a -- 需要針對(duì)該設(shè)備定義一個(gè)USB驅(qū)動(dòng),對(duì)應(yīng)到代碼中即定義一個(gè)usb_driver結(jié)構(gòu)體變量

代碼如下:

[cpp]?view plaincopy
  • struct?usb_driver?xxx_usb_wifi_driver;??
  • b -- 填充該設(shè)備的usb_driver結(jié)構(gòu)體成員變量

    代碼如下:

    [cpp]?view plaincopy
  • static?struct?usb_driver?xxx_usb_wifi_driver?=?{??
  • ????.name?=?"XXX_USB_WIFI",??
  • ????.probe?=?xxx_probe,??
  • ????.disconnect?=?xxx_disconnect,??
  • ????.suspend?=?xxx_suspend,??
  • ????.resume?=?xxx_resume,??
  • ????.id_table?=?xxx_table,??
  • };??
  • c -- 將該驅(qū)動(dòng)注冊(cè)到USB子系統(tǒng)

    代碼如下:

    [cpp]?view plaincopy
  • usb_register(&xxx_usb_wifi_driver);??
  • ? ? ? 以上步驟只是一個(gè)大致的USB驅(qū)動(dòng)框架流程,而最大和最復(fù)雜的工作是填充usb_driver結(jié)構(gòu)體成員變量。以上步驟的主要工作是將USB接口的WIFI設(shè)備掛載到USB總線上,以便Linux系統(tǒng)在USB總線上就能夠找到該設(shè)備。

    2、網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)

    ? ? ? 接下來是網(wǎng)絡(luò)設(shè)備的線索,網(wǎng)絡(luò)設(shè)備驅(qū)動(dòng)大致步驟如下:

    a -- 定義一個(gè)net_device結(jié)構(gòu)體變量ndev

    代碼如下:

    [cpp]?view plaincopy
  • struct?net_device?*ndev;??
  • b -- 初始化ndev變量并分配內(nèi)存

    代碼如下:

    [cpp]?view plaincopy
  • ndev=alloc_etherdev();??
  • c -- 填充ndev -> netdev_ops結(jié)構(gòu)體成員變量

    代碼如下:

    [cpp]?view plaincopy
  • static?const?struct?net_device_ops?xxx_netdev_ops=?{??
  • ????.ndo_init?=?xxx_ndev_init,??
  • ????.ndo_uninit?=?xxx?_ndev_uninit,??
  • ????.ndo_open?=?netdev_open,??
  • ????.ndo_stop?=?netdev_close,??
  • ????.ndo_start_xmit?=?xxx_xmit_entry,??
  • ????.ndo_set_mac_address?=?xxx_net_set_mac_address,??
  • ????.ndo_get_stats?=?xxx_net_get_stats,??
  • ????.ndo_do_ioctl?=?xxx_ioctl,??
  • };??
  • d -- 填充ndev->wireless_handlers結(jié)構(gòu)體成員變量,該變量是無線擴(kuò)展功能

    代碼如下:

    [cpp]?view plaincopy
  • ndev->wireless_handlers?=?(struct?iw_handler_def?*)&xxx_handlers_def;??
  • e -- 將ndev設(shè)備注冊(cè)到網(wǎng)絡(luò)子系統(tǒng)

    代碼如下:

    [cpp]?view plaincopy
  • register_netdev(ndev);??
  • 3、?WIFI設(shè)備本身私有的功能及屬性

    ? ? ? 如自身的配置及初始化、建立與用戶空間的交互接口、自身功能的實(shí)現(xiàn)等。

    a -- 自身的配置及初始化

    代碼如下: ? ? ? ? ? ? ? ?

    [cpp]?view plaincopy
  • xxx_read_chip_info();??
  • ??
  • xxx_chip_configure();??
  • ??
  • xxx_hal_init();??
  • b -- 主要是在proc和sys文件系統(tǒng)上建立與用戶空間的交互接口

    代碼如下:

    [cpp]?view plaincopy
  • xxx_drv_proc_init();??
  • ??
  • xxx_ndev_notifier_register();??
  • c -- 自身功能的實(shí)現(xiàn)

    ? ????WIFI的網(wǎng)絡(luò)及接入原理,如掃描等。同時(shí)由于WIFI在移動(dòng)設(shè)備中,相對(duì)功耗比較大,因此,對(duì)于功耗、電源管理也會(huì)在驅(qū)動(dòng)中體現(xiàn)。


    二、USB 設(shè)備驅(qū)動(dòng)分析

    ? ? ? ? 在分析之前,我們需要理解在整個(gè)wifi模塊中,USB充當(dāng)什么角色?它的作用是什么?實(shí)質(zhì)上wifi模塊上的數(shù)據(jù)傳輸有兩端,一端是wifi芯片與wifi芯片之間,通過無線射頻(RF)進(jìn)行數(shù)據(jù)傳輸;另一端則是wifi芯片與CPU之間,通過USB進(jìn)行數(shù)據(jù)傳輸

    ? ? ? ?了解Linux的USB驅(qū)動(dòng)的讀者都知道,USB驅(qū)動(dòng)分為兩種:一種是USB主機(jī)驅(qū)動(dòng);另一種是USB設(shè)備驅(qū)動(dòng)。而我們的USB接口的wifi模塊對(duì)于CPU(主機(jī))來說,屬于USB設(shè)備,因此采用USB設(shè)備驅(qū)動(dòng)。

    ? ? ? ?有了以上信息之后,我們先讓Linux系統(tǒng)識(shí)別該USB接口的wifi模塊,首先我們?cè)隍?qū)動(dòng)源碼中大致添加以下幾步工作(前面分析過,這里只看步驟,不看代碼):

    a -- 定義一個(gè)usb_driver結(jié)構(gòu)體變量

    b -- 填充該設(shè)備的usb_driver結(jié)構(gòu)體成員變量

    c -- 將該驅(qū)動(dòng)注冊(cè)到USB子系統(tǒng)

    ? ? ? 簡單完成以上幾步工作,再加上板級(jí)文件(arch/mach-xxx.c)對(duì)USB設(shè)備的支持,Linux的USB子系統(tǒng)幾乎可以掛載該wifi模塊為USB設(shè)備了。但是這并不是我們最終想要的結(jié)果。我們還要讓Linux系統(tǒng)知道它掛載的USB設(shè)備屬于無線網(wǎng)絡(luò)設(shè)備,同時(shí)能夠訪問它,利用它實(shí)施無線網(wǎng)絡(luò)的工作

    ? ? ?我們都知道,若要讓USB設(shè)備真正工作起來,需要對(duì)USB設(shè)備的4個(gè)層次(設(shè)備、配置、接口、端點(diǎn))進(jìn)行初始化。當(dāng)然這四個(gè)層次并不是一定都要進(jìn)行初始化,而是根據(jù)你的USB設(shè)備的功能進(jìn)行選擇的,大致初始化流程如下偽代碼:

    [cpp]?view plaincopy
  • static?struct?dvobj_priv?*usb_dvobj_init(struct?usb_interface?*usb_intf)??
  • {??
  • ????int????i;??
  • ????u8?????val8;??
  • ????int????status=?_FAIL;??
  • ????struct?dvobj_priv?*pdvobjpriv;??
  • ??
  • ????//設(shè)備??
  • ????struct?usb_device?*pusbd;??
  • ????struct?usb_device_descriptor?*pdev_desc;??
  • ??
  • ????//配置??
  • ????struct?usb_host_config?*phost_conf;??
  • ????struct?usb_config_descriptor?*pconf_desc;??
  • ??
  • ????//接口??
  • ????struct?usb_host_interface?*phost_iface;??
  • ????struct?usb_interface_descriptor?*piface_desc;??
  • ??????
  • ????//端點(diǎn)??
  • ????struct?usb_host_endpoint?*phost_endp;??
  • ????struct?usb_endpoint_descriptor?*pendp_desc;??
  • ??
  • ??
  • ????//設(shè)備的初始化??
  • ????pdvobjpriv->pusbintf?=?usb_intf?;??
  • ????pusbd?=pdvobjpriv->pusbdev?=?interface_to_usbdev(usb_intf);??
  • ????usb_set_intfdata(usb_intf,?pdvobjpriv);??
  • ????pdev_desc?=&pusbd->descriptor;??
  • ??
  • ??????
  • ????//配置的初始化??
  • ????phost_conf?=pusbd->actconfig;??
  • ????pconf_desc?=&phost_conf->desc;??
  • ??
  • ???
  • ????//接口的初始化??
  • ????phost_iface?=&usb_intf->altsetting[0];??
  • ????piface_desc?=&phost_iface->desc;??
  • ??
  • ??????
  • ????//端點(diǎn)的初始化,由于wifi模塊屬于網(wǎng)絡(luò)設(shè)備,傳輸批量數(shù)據(jù),因此需要初始化為批量端點(diǎn),端點(diǎn)方向(輸入、輸出)等。同時(shí),由于wifi驅(qū)動(dòng)功能比較多,需要初始化幾個(gè)輸入輸出端點(diǎn)。??
  • ????for?(i?=?0;?i?<pdvobjpriv->nr_endpoint;?i++)??
  • ????{??
  • ????????phost_endp?=?phost_iface->endpoint?+i;??
  • ????????if?(phost_endp)??
  • ????????{??
  • ????????????pendp_desc?=&phost_endp->desc;??
  • ??
  • ????????????//檢查是否為輸入端點(diǎn)??
  • ????????????usb_endpoint_is_bulk_in(pendp_desc);??
  • ??
  • ????????????//檢查是否為輸出端點(diǎn)??
  • ????????????usb_endpoint_is_bulk_out(pendp_desc);??
  • ????????}??
  • ??
  • ????}??
  • ??
  • ????usb_get_dev(pusbd);??
  • ??
  • }??
  • ? ? ? 完成以上的初始化工作之后,接下來我們需要理清一下USB接口的作用,它是wifi芯片內(nèi)部的固件程序與主機(jī)上的Linux系統(tǒng)進(jìn)行數(shù)據(jù)通信。USB設(shè)備通信不像普通字符設(shè)備那樣采用I/O內(nèi)存和I/O端口的訪問,而是采用一種稱為URB(USB Request Block)的USB請(qǐng)求塊,URB在整個(gè)USB子系統(tǒng)中,相當(dāng)于通電設(shè)備中的“電波”,USB主機(jī)與設(shè)備的通信,通過“電波”來傳遞。下面我們就來編寫USB接口的讀寫操作函數(shù),偽代碼如下:

    [cpp]?view plaincopy
  • void?xxx_wifi_usb_intf_ops(struct?_io_ops?????*pops)??
  • {??
  • ????//當(dāng)需要進(jìn)行簡單數(shù)據(jù)的讀取時(shí),采用以下操作??
  • ????pops->_read8?=?&usb_read8;??
  • ????pops->_read16?=?&usb_read16;??
  • ????pops->_read32?=?&usb_read32;??
  • ??
  • ????//當(dāng)需要進(jìn)行批量數(shù)據(jù)的讀取時(shí),采用以下操作??
  • ????pops->_read_port?=?&usb_read_port;?????
  • ??
  • ????//當(dāng)需要進(jìn)行簡單數(shù)據(jù)的寫時(shí),采用以下操作??
  • ????pops->_write8?=?&usb_write8;??
  • ????pops->_write16?=?&usb_write16;??
  • ????pops->_write32?=?&usb_write32;??
  • ????pops->_writeN?=?&usb_writeN;??
  • ??
  • ????//當(dāng)需要進(jìn)行批量數(shù)據(jù)的寫時(shí),采用以下操作??
  • ????pops->_write_port?=?&usb_write_port;??
  • ??
  • ????//取消讀寫urb??
  • ????pops->_read_port_cancel?=?&usb_read_port_cancel;??
  • ????pops->_write_port_cancel?=?&usb_write_port_cancel;??
  • ??
  • }??
  • ? ? ? ? ?在進(jìn)行批量數(shù)據(jù)的讀寫時(shí),如usb_read_port()和usb_write_port()函數(shù),需要完成urb創(chuàng)建、初始化、提交、完成處理這個(gè)完整的流程。偽代碼如下:

    1)批量讀操作

    [cpp]?view plaincopy
  • static?u32?usb_read_port(struct?intf_hdl?*pintfhdl,?u32?addr,?u32?cnt,?u8?*rmem)??
  • {?????????
  • ????int?err;??
  • ????unsigned?intpipe;??
  • ????PURB?purb?=NULL;??
  • ????structrecv_buf?????????*precvbuf?=?(structrecv_buf?*)rmem;??
  • ????structusb_device????*pusbd?=?pdvobj->pusbdev;??
  • ??
  • ????//創(chuàng)建urb,這里是在其它地方創(chuàng)建完成之后,傳遞過來??
  • ????purb?=precvbuf->purb;??
  • ??
  • ????//初始化批量urb??
  • ????usb_fill_bulk_urb(purb,?pusbd,?pipe,??
  • ????????precvbuf->pbuf,??
  • ????????MAX_RECVBUF_SZ,??
  • ????????usb_read_port_complete,??
  • ????????precvbuf);//contextis?precvbuf??
  • ??????
  • ????//提交urb??
  • ????err?=usb_submit_urb(purb,?GFP_ATOMIC);??
  • ??
  • }??
  • 2)批量寫操作

    [cpp]?view plaincopy
  • u32?usb_write_port(struct?intf_hdl?*pintfhdl,?u32?addr,?u32?cnt,?u8?*wmem)??
  • {?????
  • ????unsigned?int?pipe;??
  • ????intstatus;??
  • ????PURB????????purb?=?NULL;??
  • ??
  • ????structxmit_priv???????*pxmitpriv?=&padapter->xmitpriv;??
  • ????structxmit_buf?*pxmitbuf?=?(struct?xmit_buf?*)wmem;??
  • ????structxmit_frame?*pxmitframe?=?(struct?xmit_frame?*)pxmitbuf->priv_data;??
  • ????structusb_device?*pusbd?=?pdvobj->pusbdev;??
  • ????structpkt_attrib?*pattrib?=?&pxmitframe->attrib;??
  • ??
  • ????//創(chuàng)建urb,這里是在其它地方創(chuàng)建完成之后,傳遞過來??
  • ?????purb?=?pxmitbuf->pxmit_urb[0];??
  • ??
  • ????//初始化批量urb??
  • ????usb_fill_bulk_urb(purb,?pusbd,?pipe,??
  • ????????pxmitframe->buf_addr,//=?pxmitbuf->pbuf??
  • ????????cnt,??
  • ????????usb_write_port_complete,??
  • ????????pxmitbuf);//contextis?pxmitbuf??
  • ??
  • ????//提交urb??
  • ????status?=?usb_submit_urb(purb,GFP_ATOMIC);??
  • ??
  • ????return?ret;??
  • ??
  • }??
  • ? ? ? ? 完成以上批量數(shù)據(jù)的讀寫操作之后,大家可能會(huì)疑問:這不是一般USB設(shè)備驅(qū)動(dòng)的操作流程嗎?貌似和wifi沒有半毛錢的關(guān)系啊!從上面看,確實(shí)和wifi沒有任何聯(lián)系,但是以上只是一個(gè)鋪墊。我們一直強(qiáng)調(diào)USB接口在wifi模塊中充當(dāng)什么角色,既然是接口,那么它就是為數(shù)據(jù)傳輸而生。所以,和wifi扯上關(guān)系的就在于usb_read_port()usb_write_port()這兩個(gè)函數(shù)。


    三、讀寫函數(shù)分析

    ? ? ? ?USB接口在wifi模塊中的最重要兩個(gè)函數(shù)是usb_read_port()和usb_write_port()。那它們是怎么和wifi扯上關(guān)系的呢?我們可以從以下三個(gè)方面去分析:

    a -- 首先需要明確wifi模塊是USB設(shè)備,主控(CPU)端是USB主機(jī);

    b -- USB主機(jī)若需要對(duì)wifi模塊進(jìn)行數(shù)據(jù)的讀寫時(shí),就必須經(jīng)過USB接口;

    c -- 既然涉及到數(shù)據(jù)的讀寫操作,必然要用相應(yīng)的讀寫函數(shù),那么usb_read_port()和usb_write_port()即是它們的讀寫函數(shù)。


    ? ? ? ?我們先從讀數(shù)據(jù)開始進(jìn)行分析,在分析之前,我們必須了解USB設(shè)備驅(qū)動(dòng)的讀數(shù)據(jù)過程。USB讀取數(shù)據(jù)操作流程如下:

    a -- 通過usb_alloc_urb()函數(shù)創(chuàng)建并分配一個(gè)URB,作為傳輸U(kuò)SB數(shù)據(jù)的載體;

    b -- 創(chuàng)建并分配DMA緩沖區(qū),以DMA方式快速傳輸數(shù)據(jù);

    c -- 初始化URB,根據(jù)wifi的傳輸數(shù)據(jù)量,我們需要初始化為批量URB,相應(yīng)操作函數(shù)為usb_fill_bulk_urb();

    d -- 將URB提交到USB核心;

    e -- 提交成功后,URB的完成函數(shù)將被USB核心調(diào)用。

    ? ? ? ? 我們知道只有當(dāng)wifi模塊有數(shù)據(jù)可讀時(shí),主控端才能成功地讀取數(shù)據(jù)。那么wifi模塊什么時(shí)候有數(shù)據(jù)可讀呢?——下面重點(diǎn)來了!wifi模塊通過RF端接收到無線網(wǎng)絡(luò)數(shù)據(jù),然后緩存到wifi芯片的RAM中,此時(shí),wifi模塊就有數(shù)據(jù)可讀了

    ? ? ? ?經(jīng)過上面的分析,我們找到了一條USB接口與wifi模塊扯上關(guān)系的線索,就是wifi模塊的接收數(shù)據(jù),會(huì)引發(fā)USB接口的讀數(shù)據(jù);

    ? ? ? 現(xiàn)在,我們轉(zhuǎn)到wifi模塊的接收函數(shù)中,看看是不是真的這樣?

    ? ? ? 在wifi接收函數(shù)初始化中,我們可以看到usb_alloc_urb()創(chuàng)建一個(gè)中斷URB。偽代碼如下:

    [cpp]?view plaincopy
  • int?xxxwifi_init_recv(_adapter?*padapter)????
  • {????
  • ????struct?recv_priv?*precvpriv?=?&padapter->recvpriv;????
  • ????int?i,?res?=?_SUCCESS;????
  • ????struct?recv_buf?*precvbuf;????
  • ????
  • ????tasklet_init(&precvpriv->recv_tasklet,?(void(*)(unsigned?long))rtl8188eu_recv_tasklet,?(unsigned?long)padapter);????
  • ????
  • ????precvpriv->int_in_urb?=?usb_alloc_urb(0,?GFP_KERNEL);?//創(chuàng)建一個(gè)中斷URB????
  • ????
  • ????precvpriv->int_in_buf?=?rtw_zmalloc(INTERRUPT_MSG_FORMAT_LEN);????
  • ????//init?recv_buf????
  • ????_rtw_init_queue(&precvpriv->free_recv_buf_queue);????
  • ????_rtw_init_queue(&precvpriv->recv_buf_pending_queue);????
  • ????
  • ????precvpriv?->?pallocated_recv_buf?=?rtw_zmalloc(NR_RECVBUFF?*sizeof(struct?recv_buf)?+?4);????
  • ????precvbuf?=?(struct?recv_buf*)precvpriv->precv_buf;????
  • ????
  • ????for(i=0;?i?<?NR_RECVBUFF?;?i++)????
  • ????{????
  • ????????_rtw_init_listhead(&precvbuf->list);????
  • ????????_rtw_spinlock_init(&precvbuf->recvbuf_lock);????
  • ????????precvbuf->alloc_sz?=?MAX_RECVBUF_SZ;????
  • ????
  • ????????res?=?rtw_os_recvbuf_resource_alloc(padapter,?precvbuf);????
  • ????
  • ????????precvbuf->ref_cnt?=?0;????
  • ????????precvbuf->adapter?=padapter;????
  • ????????precvbuf++;????
  • ????}????
  • ????precvpriv->free_recv_buf_queue_cnt?=?NR_RECVBUFF;????
  • ????
  • ????skb_queue_head_init(&precvpriv->rx_skb_queue);????
  • ????
  • #ifdef?CONFIG_PREALLOC_RECV_SKB????
  • ????{????
  • ????????int?i;????
  • ????????SIZE_PTR?tmpaddr=0;????
  • ????????SIZE_PTR?alignment=0;????
  • ????????struct?sk_buff?*pskb=NULL;????
  • ????????skb_queue_head_init(&precvpriv->free_recv_skb_queue);????
  • ????????for(i=0;?i<NR_PREALLOC_RECV_SKB;?i++)????
  • ????????{????
  • ????????????pskb?=?rtw_skb_alloc(MAX_RECVBUF_SZ?+?RECVBUFF_ALIGN_SZ);????
  • ????????????if(pskb)????
  • ????????????{????
  • ????????????????pskb->dev?=?padapter->pnetdev;????
  • ????????????????tmpaddr?=?(SIZE_PTR)pskb->data;????
  • ????????????????alignment?=?tmpaddr?&?(RECVBUFF_ALIGN_SZ-1);????
  • ????????????????skb_reserve(pskb,?(RECVBUFF_ALIGN_SZ?-?alignment));????
  • ????????????????skb_queue_tail(&precvpriv->free_recv_skb_queue,?pskb);????
  • ????????????}????
  • ????????????pskb=NULL;????
  • ????????}????
  • ????}????
  • #endif????
  • ????return?res;????
  • }????
  • ?在rtw_os_recvbuf_resource_alloc函數(shù)中,創(chuàng)建一個(gè)批量URB和一個(gè)DMA緩沖區(qū)。偽代碼如下:

    [cpp]?view plaincopy
  • int?rtw_os_recvbuf_resource_alloc(_adapter?*padapter,?struct?recv_buf?*precvbuf)????
  • {????
  • ????int?res=_SUCCESS;????
  • ????struct?dvobj_priv???*pdvobjpriv?=?adapter_to_dvobj(padapter);????
  • ????struct?usb_device???*pusbd?=?pdvobjpriv->pusbdev;????
  • ????
  • ????precvbuf->irp_pending?=?_FALSE;????
  • ????precvbuf->purb?=?usb_alloc_urb(0,?GFP_KERNEL);?//創(chuàng)建一個(gè)批量URB????
  • ????
  • ????precvbuf->pskb?=?NULL;????
  • ????precvbuf->reuse?=?_FALSE;????
  • ????precvbuf->pallocated_buf??=?precvbuf->pbuf?=?NULL;????
  • ????precvbuf->pdata?=?precvbuf->phead?=?precvbuf->ptail?=?precvbuf->pend?=?NULL;????
  • ????precvbuf->transfer_len?=?0;????
  • ????precvbuf->len?=?0;????
  • ????
  • ????#ifdef?CONFIG_USE_USB_BUFFER_ALLOC_RX????
  • ????precvbuf->pallocated_buf?=?rtw_usb_buffer_alloc(pusbd,?(size_t)precvbuf->alloc_sz,?&precvbuf->dma_transfer_addr);??//創(chuàng)建一個(gè)DMA緩沖區(qū)????
  • ????precvbuf->pbuf?=?precvbuf->pallocated_buf;????
  • ????if(precvbuf->pallocated_buf?==?NULL)????
  • ????????return?_FAIL;????
  • ????#endif?//CONFIG_USE_USB_BUFFER_ALLOC_RX????
  • ????????
  • ????return?res;????
  • }????
  • ? ? ? 在usb_read_port()函數(shù)中,通過usb_fill_bulk_urb()初始化批量URB,并且提交給USB核心,也即USB讀取數(shù)據(jù)操作流程的第3、4步。在usb_fill_bulk_urb()函數(shù)中,初始化URB的完成函數(shù)usb_read_port_complete(),只有當(dāng)URB提交完成后,函數(shù)usb_read_port_complete()將被調(diào)用。偽代碼如下:

    [cpp]?view plaincopy
  • static?u32?usb_read_port(struct?intf_hdl?*pintfhdl,?u32?addr,?u32?cnt,?u8?*rmem)????
  • {???????
  • ????struct?recv_buf?*precvbuf?=?(struct?recv_buf?*)rmem;????
  • ????_adapter????????*adapter?=?pintfhdl->padapter;????
  • ????struct?dvobj_priv???*pdvobj?=?adapter_to_dvobj(adapter);????
  • ????struct?pwrctrl_priv?*pwrctl?=?dvobj_to_pwrctl(pdvobj);????
  • ????struct?recv_priv????*precvpriv?=?&adapter->recvpriv;????
  • ????struct?usb_device???*pusbd?=?pdvobj->pusbdev;????
  • ????
  • ????rtl8188eu_init_recvbuf(adapter,?precvbuf);??????????
  • ????
  • ????precvpriv->rx_pending_cnt++;????
  • ????
  • ????purb?=?precvbuf->purb;????
  • ????
  • ????//translate?DMA?FIFO?addr?to?pipehandle????
  • ????pipe?=?ffaddr2pipehdl(pdvobj,?addr);????
  • ????
  • ????usb_fill_bulk_urb(purb,?pusbd,?pipe,?????
  • ????????????????????precvbuf->pbuf,????
  • ????????????????????????????MAX_RECVBUF_SZ,????
  • ????????????????????????????usb_read_port_complete,????
  • ????????????????????????????precvbuf);//context?is?precvbuf????
  • ????
  • ????err?=?usb_submit_urb(purb,?GFP_ATOMIC);????
  • ????
  • ????return?ret;????
  • }????
  • ? ? ?通過上面的代碼,我們可以得知在wifi模塊為接收數(shù)據(jù)做初始化準(zhǔn)備時(shí),分配了URB和DMA緩沖區(qū)。而在usb_read_port()函數(shù)中初始化URB和提交URB。

    < 未完待續(xù).....>

    總結(jié)

    以上是生活随笔為你收集整理的Linux 下wifi 驱动开发(四)—— USB接口WiFi驱动浅析的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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