1. 程式人生 > >wifi驅動的理解(2)——usb介面在wifi模組中的角色

wifi驅動的理解(2)——usb介面在wifi模組中的角色

轉載請註明出處:http://blog.csdn.net/Righthek 謝謝!

       上一篇文章我們已經通過三條線索簡單地描述了wifi驅動的框架,現在我們開始深入到每條線索中。首先我們從USB裝置這條線索開始。在分析之前,我們需要理解在整個wifi模組中,USB充當什麼角色?它的作用是什麼?實質上wifi模組上的資料傳輸有兩端,一端是wifi晶片與wifi晶片之間,通過無線射頻(RF)進行資料傳輸;另一端則是wifi晶片與CPU之間,通過USB進行資料傳輸。

       瞭解Linux的USB驅動的讀者都知道,USB驅動分為兩種:一種是USB主機驅動;另一種是USB裝置驅動。而我們的USB介面的wifi模組對於CPU(主機)來說,屬於USB裝置,因此採用USB裝置驅動。

         有了以上資訊之後,我們先讓Linux系統識別該USB介面的wifi模組,首先我們在驅動原始碼中大致新增以下幾步工作:

       (1)定義一個usb_driver結構體變數:

                struct usb_driver xxx_usb_wifi_driver;

       (2)填充該裝置的usb_driver結構體成員變數:

                static struct usb_driver xxx_usb_wifi_driver = {

                         .name =             "XXX_USB_WIFI",

                         .probe =   xxx_init_wifi,

                         .disconnect =   xxx_remove,

                         .suspend =        xxx_suspend,

                         .resume =         xxx_resume,

                         .id_table=        xxx_table,

                };

          (3)將該驅動註冊到USB子系統:

                usb_register(&xxx_usb_wifi_driver);

         簡單完成以上幾步工作,再加上板級檔案(arch/mach-xxx.c)對USB裝置的支援,Linux的USB子系統幾乎可以掛載該wifi模組為USB裝置了。但是這並不是我們最終想要的結果。我們還要讓Linux系統知道它掛載的USB裝置屬於無線網路裝置,同時能夠訪問它,利用它實施無線網路的工作。

         我們都知道,若要讓USB裝置真正工作起來,需要對USB裝置的4個層次(裝置、配置、介面、端點)進行初始化。當然這四個層次並不是一定都要進行初始化,而是根據你的USB裝置的功能進行選擇的,大致初始化流程如下虛擬碼:

        static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf)

        {

                 int    i;

                 u8     val8;

                 int    status= _FAIL;

                 struct dvobj_priv *pdvobjpriv;

                //裝置

                 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;

                //端點

                 struct usb_host_endpoint                 *phost_endp;

                 struct usb_endpoint_descriptor      *pendp_desc;

 

                 //裝置的初始化

                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;

        

         端點的初始化,由於wifi模組屬於網路裝置,傳輸批量資料,因此需要初始化為批量端點,端點方向(輸入、輸出)等。同時,由於wifi驅動功能比較多,需要初始化幾個輸入輸出端點。

                 for (i = 0; i <pdvobjpriv->nr_endpoint; i++)

                 {

                          phost_endp = phost_iface->endpoint +i;

                          if (phost_endp)

                          {

                                    pendp_desc =&phost_endp->desc;

                                    //檢查是否為輸入端點

                                    usb_endpoint_is_bulk_in(pendp_desc);

                                    //檢查是否為輸出端點

                                    usb_endpoint_is_bulk_out(pendp_desc);

                           }

                 }

                usb_get_dev(pusbd);

        }

         完成以上的初始化工作之後,接下來我們需要理清一下USB介面的作用,它是wifi晶片內部的韌體程式與主機上的Linux系統進行資料通訊。USB裝置通訊不像普通字元裝置那樣採用I/O記憶體和I/O埠的訪問,而是採用一種稱為URB(USB Request Block)的USB請求塊,URB在整個USB子系統中,相當於通電裝置中的“電波”,USB主機與裝置的通訊,通過“電波”來傳遞。下面我們就來編寫USB介面的讀寫操作函式,虛擬碼如下:

         void xxx_wifi_usb_intf_ops(struct _io_ops     *pops)

         {

                  //當需要進行簡單資料的讀取時,採用以下操作

                  pops->_read8 = &usb_read8;

                  pops->_read16 = &usb_read16;

                  pops->_read32 = &usb_read32;

                  //當需要進行批量資料的讀取時,採用以下操作

                  pops->_read_port = &usb_read_port;   

                   //當需要進行簡單資料的寫時,採用以下操作

                  pops->_write8 = &usb_write8;

                  pops->_write16 = &usb_write16;

                  pops->_write32 = &usb_write32;

                  pops->_writeN = &usb_writeN;

                  //當需要進行批量資料的寫時,採用以下操作

                  pops->_write_port = &usb_write_port;

                  //取消讀寫urb

                  pops->_read_port_cancel = &usb_read_port_cancel;

                  pops->_write_port_cancel = &usb_write_port_cancel;

          }

         在進行批量資料的讀寫時,如usb_read_port()和usb_write_port()函式,需要完成urb建立、初始化、提交、完成處理這個完整的流程。虛擬碼如下:

         (1)批量讀操作

        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;

                 //建立urb,這裡是在其它地方建立完成之後,傳遞過來

                 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)批量寫操作

         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;

                 //建立urb,這裡是在其它地方建立完成之後,傳遞過來

                 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;

        }

         完成以上批量資料的讀寫操作之後,大家可能會疑問:這不是一般USB裝置驅動的操作流程嗎?貌似和wifi沒有半毛錢的關係啊!

         從這篇文章上看,確實和wifi沒有任何聯絡,但是以上只是一個鋪墊。我們一直強調USB介面在wifi模組中充當什麼角色,既然是介面,那麼它就是為資料傳輸而生。所以,和wifi扯上關係的就在於usb_read_port()和usb_write_port()這兩個函式。

         讀者可結合USB裝置驅動和網路裝置驅動細心思考,它們之間是如何聯絡上的?

         鑑於文章篇幅有限,以上問題將在下篇文章進行詳細講解,敬請期待!

轉載請註明出處:http://blog.csdn.net/Righthek 謝謝!

轉載請註明出處:http://blog.csdn.net/Righthek 謝謝!

       上一篇文章我們已經通過三條線索簡單地描述了wifi驅動的框架,現在我們開始深入到每條線索中。首先我們從USB裝置這條線索開始。在分析之前,我們需要理解在整個wifi模組中,USB充當什麼角色?它的作用是什麼?實質上wifi模組上的資料傳輸有兩端,一端是wifi晶片與wifi晶片之間,通過無線射頻(RF)進行資料傳輸;另一端則是wifi晶片與CPU之間,通過USB進行資料傳輸。

       瞭解Linux的USB驅動的讀者都知道,USB驅動分為兩種:一種是USB主機驅動;另一種是USB裝置驅動。而我們的USB介面的wifi模組對於CPU(主機)來說,屬於USB裝置,因此採用USB裝置驅動。

         有了以上資訊之後,我們先讓Linux系統識別該USB介面的wifi模組,首先我們在驅動原始碼中大致新增以下幾步工作:

       (1)定義一個usb_driver結構體變數:

                struct usb_driver xxx_usb_wifi_driver;

       (2)填充該裝置的usb_driver結構體成員變數:

                static struct usb_driver xxx_usb_wifi_driver = {

                         .name =             "XXX_USB_WIFI",

                         .probe =   xxx_init_wifi,

                         .disconnect =   xxx_remove,

                         .suspend =        xxx_suspend,

                         .resume =         xxx_resume,

                         .id_table=        xxx_table,

                };

          (3)將該驅動註冊到USB子系統:

                usb_register(&xxx_usb_wifi_driver);

         簡單完成以上幾步工作,再加上板級檔案(arch/mach-xxx.c)對USB裝置的支援,Linux的USB子系統幾乎可以掛載該wifi模組為USB裝置了。但是這並不是我們最終想要的結果。我們還要讓Linux系統知道它掛載的USB裝置屬於無線網路裝置,同時能夠訪問它,利用它實施無線網路的工作。

         我們都知道,若要讓USB裝置真正工作起來,需要對USB裝置的4個層次(裝置、配置、介面、端點)進行初始化。當然這四個層次並不是一定都要進行初始化,而是根據你的USB裝置的功能進行選擇的,大致初始化流程如下虛擬碼:

        static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf)

        {

                 int    i;

                 u8     val8;

                 int    status= _FAIL;

                 struct dvobj_priv *pdvobjpriv;

                //裝置

                 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;

                //端點

                 struct usb_host_endpoint                 *phost_endp;

                 struct usb_endpoint_descriptor      *pendp_desc;

 

                 //裝置的初始化

                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;

        

         端點的初始化,由於wifi模組屬於網路裝置,傳輸批量資料,因此需要初始化為批量端點,端點方向(輸入、輸出)等。同時,由於wifi驅動功能比較多,需要初始化幾個輸入輸出端點。

                 for (i = 0; i <pdvobjpriv->nr_endpoint; i++)

                 {

                          phost_endp = phost_iface->endpoint +i;

                          if (phost_endp)

                          {

                                    pendp_desc =&phost_endp->desc;

                                    //檢查是否為輸入端點

                                    usb_endpoint_is_bulk_in(pendp_desc);

                                    //檢查是否為輸出端點

                                    usb_endpoint_is_bulk_out(pendp_desc);

                           }

                 }

                usb_get_dev(pusbd);

        }

         完成以上的初始化工作之後,接下來我們需要理清一下USB介面的作用,它是wifi晶片內部的韌體程式與主機上的Linux系統進行資料通訊。USB裝置通訊不像普通字元裝置那樣採用I/O記憶體和I/O埠的訪問,而是採用一種稱為URB(USB Request Block)的USB請求塊,URB在整個USB子系統中,相當於通電裝置中的“電波”,USB主機與裝置的通訊,通過“電波”來傳遞。下面我們就來編寫USB介面的讀寫操作函式,虛擬碼如下:

         void xxx_wifi_usb_intf_ops(struct _io_ops     *pops)

         {

                  //當需要進行簡單資料的讀取時,採用以下操作

                  pops->_read8 = &usb_read8;

                  pops->_read16 = &usb_read16;

                  pops->_read32 = &usb_read32;

                  //當需要進行批量資料的讀取時,採用以下操作

                  pops->_read_port = &usb_read_port;   

                   //當需要進行簡單資料的寫時,採用以下操作

                  pops->_write8 = &usb_write8;

                  pops->_write16 = &usb_write16;

                  pops->_write32 = &usb_write32;

                  pops->_writeN = &usb_writeN;

                  //當需要進行批量資料的寫時,採用以下操作

                  pops->_write_port = &usb_write_port;

                  //取消讀寫urb

                  pops->_read_port_cancel = &usb_read_port_cancel;

                  pops->_write_port_cancel = &usb_write_port_cancel;

          }

         在進行批量資料的讀寫時,如usb_read_port()和usb_write_port()函式,需要完成urb建立、初始化、提交、完成處理這個完整的流程。虛擬碼如下:

         (1)批量讀操作

        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;

                 //建立urb,這裡是在其它地方建立完成之後,傳遞過來

                 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)批量寫操作

         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;

                 //建立urb,這裡是在其它地方建立完成之後,傳遞過來

                 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;

        }

         完成以上批量資料的讀寫操作之後,大家可能會疑問:這不是一般USB裝置驅動的操作流程嗎?貌似和wifi沒有半毛錢的關係啊!

         從這篇文章上看,確實和wifi沒有任何聯絡,但是以上只是一個鋪墊。我們一直強調USB介面在wifi模組中充當什麼角色,既然是介面,那麼它就是為資料傳輸而生。所以,和wifi扯上關係的就在於usb_read_port()和usb_write_port()這兩個函式。

         讀者可結合USB裝置驅動和網路裝置驅動細心思考,它們之間是如何聯絡上的?

         鑑於文章篇幅有限,以上問題將在下篇文章進行詳細講解,敬請期待!

轉載請註明出處:http://blog.csdn.net/Righthek 謝謝!