Linux USB-Wifi Driver

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,
};


 

 

 

 


 

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值