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
staticstructusb_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,
};
intath9k_hif_usb_init(void)
{
returnusb_register(&ath9k_hif_usb_driver);// 把driver注册到USB驱动链中
}
voidath9k_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,其详细定义如下:
structieee80211_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
协议层需要的内存结构,又顺便分配了驱动的私有数据结构,该函数分配的内存结构如下图所示:
4. Wifi工作流程
4.1
Wifi打开基本流程
Wifi打开基本流程如下图所示:
4.2
Wifi关闭基本流程
Wifi关闭基本流程如下图所示:
4.3
Wifi待机和唤醒流程
5.
注册ieee80211_class
其详细代码如下:
net/wireless/sysfs.c
structclassieee80211_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,
};
intwiphy_sysfs_init(void)
{
returnclass_register(&ieee80211_class);
}
voidwiphy_sysfs_exit(void)
{
class_unregister(&ieee80211_class);
}
它需要调用的struct
cfg80211_ops定义如下:
net/mac80211/cfg.c
structcfg80211_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,
};