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 謝謝!