USB WIFI驱动分析

1. USB设备枚举过程

     设备在插入USB 接口到设备成功找到它自己的驱动这一过程为:当把USB 设备插到USB 接口上后,USB 中央控制器会检测到有设备插入USB 接口了,Linux 内核会给设备分配一个数据结构来代表这个设备,Linux 会分配一个struct usb_device 数据结构来代表该设备,该数据结构记录设备的一些属性及数据。并把该数据结构挂载到一个全局的USB 设备链上。在这一期间主机通过0 号端点得知了设备的一些信息,并知道了设备的厂家号和产品号。然后到一个全局的USB 驱动链上查找(通过调用驱动的probe函数来询问),看看哪个驱动程序支持的设备列表中有该设备的厂家号和产品号。当找到后设备就和驱动匹配上了。

 

2. 关键数据结构

1) struct cfg80211_ops :backend description for wireless configuration
2) struct wiphy:wireless hardware description

3) struct ieee80211_ops:callbacks from mac80211 to the driver

4) struct ieee80211_hw:hardware information and state

5) struct ieee80211_channel:channel definition

6) struct usb_driver:identifies USB interface driver to usbcore

 

 3. USB-Wifi驱动架构

    USB-Wifi驱动架构如下图所示:

 

 1) ieee802.11 协议层

     Linux Kernel中有ieee802.11 协议子层,各个不同型号的硬件设备驱动程序都是实现ieee80211_ops 数据结构中的函数,例如打开是start()函数,发送是tx()函数,关闭是stop()函数,睡眠是suspend函数,唤醒是resume函数等。

     其代码位于: kernel/net/mac80211

2) USB无线网卡驱动层

     由上图可见,USB无线网卡驱动层位于USB与802.11协议层之间,为了使其可正常工作,它必须搞好上下级关系:

     a) 向USB Core注册USB驱动,通过USB通道收发数据

     b) 向ieee802.11注册ieee80211_ops,以供ieee80211随时召唤,然后通过USB通道进行数据传输

       

3.1 向USB Core注册USB驱动      

       向USB Core注册USB驱动,通过USB通道收发数据,如我的代码为:      

             kernel/drivers/net/wireless/ath/ath9k/hif_usb.c

[cpp]  view plain copy

[cpp]  view plain  copy
  1. static struct usb_driver ath9k_hif_usb_driver = { //USB 驱动  
  2.     .name = KBUILD_MODNAME,  
  3.     .probe = ath9k_hif_usb_probe,  
  4.     .disconnect = ath9k_hif_usb_disconnect,  
  5. #ifdef CONFIG_PM  
  6.     .suspend = ath9k_hif_usb_suspend,  
  7.     .resume = ath9k_hif_usb_resume,  
  8.     .reset_resume = ath9k_hif_usb_resume,  
  9. #endif  
  10.     .id_table = ath9k_hif_usb_ids,  
  11.     .soft_unbind = 1,  
  12. };  
  13.   
  14. int ath9k_hif_usb_init(void)  
  15. {  
  16.     return usb_register(&ath9k_hif_usb_driver); // 把driver注册到USB驱动链中  
  17. }  
  18.   
  19. void ath9k_hif_usb_exit(void)  
  20. {  
  21.     usb_deregister(&ath9k_hif_usb_driver);  // 把driver从USB驱动链中删除  
  22. }  

    

3.2 向ieee802.11注册ieee80211_ops

      向ieee802.11注册ieee80211_ops,以供ieee80211随时召唤,然后通过USB通道进行数据传输,如我的代码为:
在kernel/drivers/net/wireless/ath/ath9k/htc_drv_main.c中定义了ath9k_htc_ops,其详细定义如下: 

[cpp]  view plain copy

[cpp]  view plain  copy
  1. struct ieee80211_ops ath9k_htc_ops = {  
  2.  .tx                 = ath9k_htc_tx,  
  3.  .start              = ath9k_htc_start,  
  4.  .stop               = ath9k_htc_stop,  
  5.  .add_interface      = ath9k_htc_add_interface,  
  6.  .remove_interface   = ath9k_htc_remove_interface,  
  7.  .config             = ath9k_htc_config,  
  8.  .configure_filter   = ath9k_htc_configure_filter,  
  9.  .sta_add            = ath9k_htc_sta_add,  
  10.  .sta_remove         = ath9k_htc_sta_remove,  
  11.  .conf_tx            = ath9k_htc_conf_tx,  
  12.  .bss_info_changed   = ath9k_htc_bss_info_changed,  
  13.  .set_key            = ath9k_htc_set_key,  
  14.  .get_tsf            = ath9k_htc_get_tsf,  
  15.  .set_tsf            = ath9k_htc_set_tsf,  
  16.  .reset_tsf          = ath9k_htc_reset_tsf,  
  17.  .ampdu_action       = ath9k_htc_ampdu_action,  
  18.  .sw_scan_start      = ath9k_htc_sw_scan_start,  
  19.  .sw_scan_complete   = ath9k_htc_sw_scan_complete,  
  20.  .set_rts_threshold  = ath9k_htc_set_rts_threshold,  
  21.  .rfkill_poll        = ath9k_htc_rfkill_poll_state,  
  22.  .set_coverage_class = ath9k_htc_set_coverage_class,  
  23.  .set_bitrate_mask   = ath9k_htc_set_bitrate_mask,  
  24. };  
  25.   
  26.    

 

      ath9k_htc_ops注册流程如下图所示:

      

   ieee80211_alloc_hw()函数是即分配了802.11 协议层需要的内存结构,又顺便分配了驱动的私有数据结构,该函数分配的内存结构如下图所示: 

[cpp]  view plain copy

[cpp]  view plain  copy
  1. /* Ensure 32-byte alignment of our private data and hw private data. 
  2.  * We use the wiphy priv data for both our ieee80211_local and for 
  3.  * the driver's private data 
  4.  * 
  5.  * In memory it'll be like this: 
  6.  * 
  7.  * +-------------------------+ 
  8.  * | struct wiphy       | 
  9.  * +-------------------------+ 
  10.  * | struct ieee80211_local  | 
  11.  * +-------------------------+ 
  12.  * | driver's private data   | 
  13.  * +-------------------------+ 
  14.  * 
  15.  */  

 

4. Wifi工作流程

4.1  Wifi打开基本流程

    Wifi打开基本流程如下图所示:

 

4.2 Wifi关闭基本流程

      Wifi关闭基本流程如下图所示:

 

 

4.3 Wifi待机和唤醒流程

 

 

 

 5. 注册ieee80211_class

 

    其详细代码如下:

net/wireless/sysfs.c

[cpp]  view plain copy

[cpp]  view plain  copy
  1. struct class ieee80211_class = {  
  2.     .name = "ieee80211",  
  3.     .owner = THIS_MODULE,  
  4.     .dev_release = wiphy_dev_release,  
  5.     .dev_attrs = ieee80211_dev_attrs,  
  6. #ifdef CONFIG_HOTPLUG  
  7.     .dev_uevent = wiphy_uevent,  
  8. #endif  
  9.     .suspend = wiphy_suspend,  // Suspend Wifi  
  10.     .resume = wiphy_resume,    // Resume Wifi  
  11.     .ns_type = &net_ns_type_operations,  
  12.     .namespace = wiphy_namespace,  
  13. };  
  14.   
  15. int wiphy_sysfs_init(void)  
  16. {  
  17.     return class_register(&ieee80211_class);  
  18. }  
  19.   
  20. void wiphy_sysfs_exit(void)  
  21. {  
  22.     class_unregister(&ieee80211_class);  
  23. }  

它需要调用的struct cfg80211_ops定义如下:

net/mac80211/cfg.c

[cpp]  view plain copy

[cpp]  view plain  copy
  1. struct cfg80211_ops mac80211_config_ops = {  
  2.     .add_virtual_intf = ieee80211_add_iface,  
  3.     .del_virtual_intf = ieee80211_del_iface,  
  4.     .change_virtual_intf = ieee80211_change_iface,  
  5.     .add_key = ieee80211_add_key,  
  6.     .del_key = ieee80211_del_key,  
  7.     .get_key = ieee80211_get_key,  
  8.     .set_default_key = ieee80211_config_default_key,  
  9.     .set_default_mgmt_key = ieee80211_config_default_mgmt_key,  
  10.     .add_beacon = ieee80211_add_beacon,  
  11.     .set_beacon = ieee80211_set_beacon,  
  12.     .del_beacon = ieee80211_del_beacon,  
  13.     .add_station = ieee80211_add_station,  
  14.     .del_station = ieee80211_del_station,  
  15.     .change_station = ieee80211_change_station,  
  16.     .get_station = ieee80211_get_station,  
  17.     .dump_station = ieee80211_dump_station,  
  18.     .dump_survey = ieee80211_dump_survey,  
  19. #ifdef CONFIG_MAC80211_MESH  
  20.     .add_mpath = ieee80211_add_mpath,  
  21.     .del_mpath = ieee80211_del_mpath,  
  22.     .change_mpath = ieee80211_change_mpath,  
  23.     .get_mpath = ieee80211_get_mpath,  
  24.     .dump_mpath = ieee80211_dump_mpath,  
  25.     .update_mesh_config = ieee80211_update_mesh_config,  
  26.     .get_mesh_config = ieee80211_get_mesh_config,  
  27.     .join_mesh = ieee80211_join_mesh,  
  28.     .leave_mesh = ieee80211_leave_mesh,  
  29. #endif  
  30.     .change_bss = ieee80211_change_bss,  
  31.     .set_txq_params = ieee80211_set_txq_params,  
  32.     .set_channel = ieee80211_set_channel,  
  33.     .suspend = ieee80211_suspend,  
  34.     .resume = ieee80211_resume,  
  35.     .scan = ieee80211_scan,  
  36.     .sched_scan_start = ieee80211_sched_scan_start,  
  37.     .sched_scan_stop = ieee80211_sched_scan_stop,  
  38.     .auth = ieee80211_auth,  
  39.     .assoc = ieee80211_assoc,  
  40.     .deauth = ieee80211_deauth,  
  41.     .disassoc = ieee80211_disassoc,  
  42.     .join_ibss = ieee80211_join_ibss,  
  43.     .leave_ibss = ieee80211_leave_ibss,  
  44.     .set_wiphy_params = ieee80211_set_wiphy_params,  
  45.     .set_tx_power = ieee80211_set_tx_power,  
  46.     .get_tx_power = ieee80211_get_tx_power,  
  47.     .set_wds_peer = ieee80211_set_wds_peer,  
  48.     .rfkill_poll = ieee80211_rfkill_poll,  
  49.     CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)  
  50.     .set_power_mgmt = ieee80211_set_power_mgmt,  
  51.     .set_bitrate_mask = ieee80211_set_bitrate_mask,  
  52.     .remain_on_channel = ieee80211_remain_on_channel,  
  53.     .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,  
  54.     .mgmt_tx = ieee80211_mgmt_tx,  
  55.     .mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait,  
  56.     .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,  
  57.     .mgmt_frame_register = ieee80211_mgmt_frame_register,  
  58.     .set_antenna = ieee80211_set_antenna,  
  59.     .get_antenna = ieee80211_get_antenna,  
  60.     .set_ringparam = ieee80211_set_ringparam,  
  61.     .get_ringparam = ieee80211_get_ringparam,  
  62. };  

猜你喜欢

转载自blog.csdn.net/dxpqxb/article/details/80183693