USB WIFI驱动分析
1. USB设备枚举过程 设备在插入USB 接口到设备成功找到它自己的驱动这一过程为:当把USB 设备插到USB 接口上后,USB 中央控制器会检测到有设备插入USB 接口了,Linux 内核会给设备分配一个数据结构来代表这个设备,Linux 会分配一个struct usb_device 数据结构来代表该设备,该数据结构记录设备的一些属性及数据。并把该数据结构挂载到一个全局的USB 设备链
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
- 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,其详细定义如下:
- 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 协议层需要的内存结构,又顺便分配了驱动的私有数据结构,该函数分配的内存结构如下图所示:
- /* 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
- 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
- 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,
- };
更多推荐
所有评论(0)