1. 程式人生 > >wifi驅動的理解(1)——驅動架構

wifi驅動的理解(1)——驅動架構

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

         在分析WIFI驅動前,分享一下個人對Linux驅動的一些瞭解,其實縱觀Linux眾多的裝置驅動,幾乎都是以匯流排為載體,所有的資料傳輸都是基於匯流排形式的,即使裝置沒有所謂的匯流排介面,但是Linux還是會給它新增一條虛擬匯流排,如platform匯流排等;介於WIFI的驅動實在是太龐大了,同時又是基於比較複雜的USB匯流排,所以建議讀者在看此文章之前,先了解一下USB裝置驅動和網路裝置驅動。

         我們要看懂WIFI驅動,首先要明白WIFI的工作原理。所以前期有幾篇文章都是講解WIFI的工作原理。從這篇文章開始,我們將進入WIFI的程式碼世界。對於支援802.11n、802.11ac這些比較新的無線標準的WIFI晶片,其驅動程式也會越來越複雜。那麼我們怎麼入手去了解及分析它呢?

         特別宣告:以下文章是以Station的角色去分析WIFI的驅動。

         網上很多文章分析Linux裝置驅動都是從模組載入入手去分析它的驅動原始碼。以博主從事Linux裝置驅動多年的經驗,這確實是一條很直觀又非常好的思路。但是這隻侷限於裝置功能少、介面較簡單、驅動原始碼較少的裝置驅動。對於功能複雜、驅動原始碼龐大的裝置驅動,根據這條思路,很多開發者可能會無耐心走下去,或者會走向死衚衕。

         現在我們可以這樣來看,從硬體層面上看,WIFI裝置與CPU通訊是通過USB介面的,與其他WIFI裝置之間的通訊是通過無線射頻(RF)。從軟體層面上看,Linux作業系統要管理WIFI裝置,那麼就要將WIFI裝置掛載到USB總線上,通過USB子系統實現管理。而同時為了對接網路,又將WIFI裝置封裝成一個網路裝置。

         我們以USB介面的WIFI模組進行分析:

         (1)從USB匯流排的角度去看,它是USB裝置;

         (2)從Linux裝置的分類上看,它又是網路裝置;

         (3)從WIFI本身的角度去看,它又有自己獨特的功能及屬性,因此它又是一個私有的裝置;

         通過上述的分析,我們只要抓住這三條線索深入去分析它的驅動原始碼,整個WIFI驅動框架就會浮現在你眼前。

         1、現在我們先從USB裝置開始,要寫一個USB裝置驅動,那麼大致步驟如下:

         (1)需要針對該裝置定義一個USB驅動,對應到程式碼中即定義一個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_probe,

                                .disconnect=   xxx_disconnect,

                                .suspend=        xxx_suspend,

                                .resume=         xxx_resume,

                                .id_table=        xxx_table,

                           };

          (3)將該驅動註冊到USB子系統。程式碼如下:

                            usb_register(&xxx_usb_wifi_driver);

         以上步驟只是一個大致的USB驅動框架流程,而最大和最複雜的工作是填充usb_driver結構體成員變數。以上步驟的主要工作是將USB介面的WIFI裝置掛載到USB總線上,以便Linux系統在USB總線上就能夠找到該裝置。

         2、接下來是網路裝置的線索,網路裝置驅動大致步驟如下:

         (1)定義一個net_device結構體變數ndev。程式碼如下:

                           struct net_device *ndev;

         (2)初始化ndev變數並分配記憶體。程式碼如下:

                           ndev=alloc_etherdev();

         (3)填充ndev -> netdev_ops結構體成員變數。程式碼如下:

                           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,

                           };

         (4)填充ndev->wireless_handlers結構體成員變數,該變數是無線擴充套件功能。程式碼如下:

                           ndev->wireless_handlers = (struct iw_handler_def *)&xxx_handlers_def;

         (5)將ndev設備註冊到網路子系統。程式碼如下:

                            register_netdev(ndev);

         3、WIFI裝置本身私有的功能及屬性,如自身的配置及初始化、建立與使用者空間的互動介面、自身功能的實現等。

         (1)自身的配置及初始化。程式碼如下:

                           xxx_read_chip_info();

                           xxx_chip_configure();

                           xxx_hal_init();

         (2)主要是在proc和sys檔案系統上建立與使用者空間的互動介面。程式碼如下:

                           xxx_drv_proc_init();

                           xxx_ndev_notifier_register();

         (3)自身功能的實現,在前面章節上我們已經講解過WIFI的網路及接入原理,如掃描等。同時由於WIFI在移動裝置中,相對功耗比較大,因此,對於功耗、電源管理也會在驅動中體現。

         本文章只是博主結合自身工作經驗分享一個大致的對wifi驅動框架的理解,後期文章將會細化這些內容。敬請讀者期待,謝謝!

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

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

         在分析WIFI驅動前,分享一下個人對Linux驅動的一些瞭解,其實縱觀Linux眾多的裝置驅動,幾乎都是以匯流排為載體,所有的資料傳輸都是基於匯流排形式的,即使裝置沒有所謂的匯流排介面,但是Linux還是會給它新增一條虛擬匯流排,如platform匯流排等;介於WIFI的驅動實在是太龐大了,同時又是基於比較複雜的USB匯流排,所以建議讀者在看此文章之前,先了解一下USB裝置驅動和網路裝置驅動。

         我們要看懂WIFI驅動,首先要明白WIFI的工作原理。所以前期有幾篇文章都是講解WIFI的工作原理。從這篇文章開始,我們將進入WIFI的程式碼世界。對於支援802.11n、802.11ac這些比較新的無線標準的WIFI晶片,其驅動程式也會越來越複雜。那麼我們怎麼入手去了解及分析它呢?

         特別宣告:以下文章是以Station的角色去分析WIFI的驅動。

         網上很多文章分析Linux裝置驅動都是從模組載入入手去分析它的驅動原始碼。以博主從事Linux裝置驅動多年的經驗,這確實是一條很直觀又非常好的思路。但是這隻侷限於裝置功能少、介面較簡單、驅動原始碼較少的裝置驅動。對於功能複雜、驅動原始碼龐大的裝置驅動,根據這條思路,很多開發者可能會無耐心走下去,或者會走向死衚衕。

         現在我們可以這樣來看,從硬體層面上看,WIFI裝置與CPU通訊是通過USB介面的,與其他WIFI裝置之間的通訊是通過無線射頻(RF)。從軟體層面上看,Linux作業系統要管理WIFI裝置,那麼就要將WIFI裝置掛載到USB總線上,通過USB子系統實現管理。而同時為了對接網路,又將WIFI裝置封裝成一個網路裝置。

         我們以USB介面的WIFI模組進行分析:

         (1)從USB匯流排的角度去看,它是USB裝置;

         (2)從Linux裝置的分類上看,它又是網路裝置;

         (3)從WIFI本身的角度去看,它又有自己獨特的功能及屬性,因此它又是一個私有的裝置;

         通過上述的分析,我們只要抓住這三條線索深入去分析它的驅動原始碼,整個WIFI驅動框架就會浮現在你眼前。

         1、現在我們先從USB裝置開始,要寫一個USB裝置驅動,那麼大致步驟如下:

         (1)需要針對該裝置定義一個USB驅動,對應到程式碼中即定義一個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_probe,

                                .disconnect=   xxx_disconnect,

                                .suspend=        xxx_suspend,

                                .resume=         xxx_resume,

                                .id_table=        xxx_table,

                           };

          (3)將該驅動註冊到USB子系統。程式碼如下:

                            usb_register(&xxx_usb_wifi_driver);

         以上步驟只是一個大致的USB驅動框架流程,而最大和最複雜的工作是填充usb_driver結構體成員變數。以上步驟的主要工作是將USB介面的WIFI裝置掛載到USB總線上,以便Linux系統在USB總線上就能夠找到該裝置。

         2、接下來是網路裝置的線索,網路裝置驅動大致步驟如下:

         (1)定義一個net_device結構體變數ndev。程式碼如下:

                           struct net_device *ndev;

         (2)初始化ndev變數並分配記憶體。程式碼如下:

                           ndev=alloc_etherdev();

         (3)填充ndev -> netdev_ops結構體成員變數。程式碼如下:

                           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,

                           };

         (4)填充ndev->wireless_handlers結構體成員變數,該變數是無線擴充套件功能。程式碼如下:

                           ndev->wireless_handlers = (struct iw_handler_def *)&xxx_handlers_def;

         (5)將ndev設備註冊到網路子系統。程式碼如下:

                            register_netdev(ndev);

         3、WIFI裝置本身私有的功能及屬性,如自身的配置及初始化、建立與使用者空間的互動介面、自身功能的實現等。

         (1)自身的配置及初始化。程式碼如下:

                           xxx_read_chip_info();

                           xxx_chip_configure();

                           xxx_hal_init();

         (2)主要是在proc和sys檔案系統上建立與使用者空間的互動介面。程式碼如下:

                           xxx_drv_proc_init();

                           xxx_ndev_notifier_register();

         (3)自身功能的實現,在前面章節上我們已經講解過WIFI的網路及接入原理,如掃描等。同時由於WIFI在移動裝置中,相對功耗比較大,因此,對於功耗、電源管理也會在驅動中體現。

         本文章只是博主結合自身工作經驗分享一個大致的對wifi驅動框架的理解,後期文章將會細化這些內容。敬請讀者期待,謝謝!

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