您的位置:首页 > 运维架构 > Linux

Linux USB-Wifi Driver

2013-08-30 13:30 225 查看
http://blog.csdn.net/myarrow/article/details/8842943


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
plaincopy

static struct usb_driver ath9k_hif_usb_driver = { //USB 驱动  

    .name = KBUILD_MODNAME,  

    .probe = ath9k_hif_usb_probe,  

    .disconnect = ath9k_hif_usb_disconnect,  

#ifdef CONFIG_PM  

    .suspend = ath9k_hif_usb_suspend,  

    .resume = ath9k_hif_usb_resume,  

    .reset_resume = ath9k_hif_usb_resume,  

#endif  

    .id_table = ath9k_hif_usb_ids,  

    .soft_unbind = 1,  

};  

  

int ath9k_hif_usb_init(void)  

{  

    return usb_register(&ath9k_hif_usb_driver); // 把driver注册到USB驱动链中  

}  

  

void ath9k_hif_usb_exit(void)  

{  

    usb_deregister(&ath9k_hif_usb_driver);  // 把driver从USB驱动链中删除  

}  

    


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
plaincopy

struct ieee80211_ops ath9k_htc_ops = {  

 .tx                 = ath9k_htc_tx,  

 .start              = ath9k_htc_start,  

 .stop               = ath9k_htc_stop,  

 .add_interface      = ath9k_htc_add_interface,  

 .remove_interface   = ath9k_htc_remove_interface,  

 .config             = ath9k_htc_config,  

 .configure_filter   = ath9k_htc_configure_filter,  

 .sta_add            = ath9k_htc_sta_add,  

 .sta_remove         = ath9k_htc_sta_remove,  

 .conf_tx            = ath9k_htc_conf_tx,  

 .bss_info_changed   = ath9k_htc_bss_info_changed,  

 .set_key            = ath9k_htc_set_key,  

 .get_tsf            = ath9k_htc_get_tsf,  

 .set_tsf            = ath9k_htc_set_tsf,  

 .reset_tsf          = ath9k_htc_reset_tsf,  

 .ampdu_action       = ath9k_htc_ampdu_action,  

 .sw_scan_start      = ath9k_htc_sw_scan_start,  

 .sw_scan_complete   = ath9k_htc_sw_scan_complete,  

 .set_rts_threshold  = ath9k_htc_set_rts_threshold,  

 .rfkill_poll        = ath9k_htc_rfkill_poll_state,  

 .set_coverage_class = ath9k_htc_set_coverage_class,  

 .set_bitrate_mask   = ath9k_htc_set_bitrate_mask,  

};  

  

   

 

      ath9k_htc_ops注册流程如下图所示:


      

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

[cpp] view
plaincopy

/* Ensure 32-byte alignment of our private data and hw private data. 

 * We use the wiphy priv data for both our ieee80211_local and for 

 * the driver's private data 

 * 

 * In memory it'll be like this: 

 * 

 * +-------------------------+ 

 * | struct wiphy       | 

 * +-------------------------+ 

 * | struct ieee80211_local  | 

 * +-------------------------+ 

 * | driver's private data   | 

 * +-------------------------+ 

 * 

 */  

 


4. Wifi工作流程


4.1  Wifi打开基本流程

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



 


4.2 Wifi关闭基本流程

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

 


 


4.3 Wifi待机和唤醒流程

 


 

 


 5. 注册ieee80211_class

 

    其详细代码如下:

net/wireless/sysfs.c

[cpp] view
plaincopy

struct class ieee80211_class = {  

    .name = "ieee80211",  

    .owner = THIS_MODULE,  

    .dev_release = wiphy_dev_release,  

    .dev_attrs = ieee80211_dev_attrs,  

#ifdef CONFIG_HOTPLUG  

    .dev_uevent = wiphy_uevent,  

#endif  

    .suspend = wiphy_suspend,  // Suspend Wifi  

    .resume = wiphy_resume,    // Resume Wifi  

    .ns_type = &net_ns_type_operations,  

    .namespace = wiphy_namespace,  

};  

  

int wiphy_sysfs_init(void)  

{  

    return class_register(&ieee80211_class);  

}  

  

void wiphy_sysfs_exit(void)  

{  

    class_unregister(&ieee80211_class);  

}  

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

net/mac80211/cfg.c

[cpp] view
plaincopy

struct cfg80211_ops mac80211_config_ops = {  

    .add_virtual_intf = ieee80211_add_iface,  

    .del_virtual_intf = ieee80211_del_iface,  

    .change_virtual_intf = ieee80211_change_iface,  

    .add_key = ieee80211_add_key,  

    .del_key = ieee80211_del_key,  

    .get_key = ieee80211_get_key,  

    .set_default_key = ieee80211_config_default_key,  

    .set_default_mgmt_key = ieee80211_config_default_mgmt_key,  

    .add_beacon = ieee80211_add_beacon,  

    .set_beacon = ieee80211_set_beacon,  

    .del_beacon = ieee80211_del_beacon,  

    .add_station = ieee80211_add_station,  

    .del_station = ieee80211_del_station,  

    .change_station = ieee80211_change_station,  

    .get_station = ieee80211_get_station,  

    .dump_station = ieee80211_dump_station,  

    .dump_survey = ieee80211_dump_survey,  

#ifdef CONFIG_MAC80211_MESH  

    .add_mpath = ieee80211_add_mpath,  

    .del_mpath = ieee80211_del_mpath,  

    .change_mpath = ieee80211_change_mpath,  

    .get_mpath = ieee80211_get_mpath,  

    .dump_mpath = ieee80211_dump_mpath,  

    .update_mesh_config = ieee80211_update_mesh_config,  

    .get_mesh_config = ieee80211_get_mesh_config,  

    .join_mesh = ieee80211_join_mesh,  

    .leave_mesh = ieee80211_leave_mesh,  

#endif  

    .change_bss = ieee80211_change_bss,  

    .set_txq_params = ieee80211_set_txq_params,  

    .set_channel = ieee80211_set_channel,  

    .suspend = ieee80211_suspend,  

    .resume = ieee80211_resume,  

    .scan = ieee80211_scan,  

    .sched_scan_start = ieee80211_sched_scan_start,  

    .sched_scan_stop = ieee80211_sched_scan_stop,  

    .auth = ieee80211_auth,  

    .assoc = ieee80211_assoc,  

    .deauth = ieee80211_deauth,  

    .disassoc = ieee80211_disassoc,  

    .join_ibss = ieee80211_join_ibss,  

    .leave_ibss = ieee80211_leave_ibss,  

    .set_wiphy_params = ieee80211_set_wiphy_params,  

    .set_tx_power = ieee80211_set_tx_power,  

    .get_tx_power = ieee80211_get_tx_power,  

    .set_wds_peer = ieee80211_set_wds_peer,  

    .rfkill_poll = ieee80211_rfkill_poll,  

    CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)  

    .set_power_mgmt = ieee80211_set_power_mgmt,  

    .set_bitrate_mask = ieee80211_set_bitrate_mask,  

    .remain_on_channel = ieee80211_remain_on_channel,  

    .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,  

    .mgmt_tx = ieee80211_mgmt_tx,  

    .mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait,  

    .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,  

    .mgmt_frame_register = ieee80211_mgmt_frame_register,  

    .set_antenna = ieee80211_set_antenna,  

    .get_antenna = ieee80211_get_antenna,  

    .set_ringparam = ieee80211_set_ringparam,  

    .get_ringparam = ieee80211_get_ringparam,  

};  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: