模组broadcom 6356s 蓝牙wifi双模
wifi驱动的通用的软件架构
分为两部分,上面为主机端驱动,下面是我们之前所说的firmware
其中固件部分的主要工作是:因为天线接受和发送回来的都是802.11帧的帧,而主机接受和传送出来的数据都必须是802.3的帧,所以必须由firmware来负责802.3的帧和802.11帧之间的转换
当天线收到数据,并被firmware处理好后会放在一个buffer里,并产生一个中断,主机在收到中断后就去读这个buffer
WiFi芯片内部有一个小系统,用来运行802.11协议,此部分代码就叫Firmware。有些芯片(例如 broadcom)的Firmware是以文件的形式存放的,有些芯片(例如 realteck)的Firmware是做到驱动代码中的。
WiFi芯片工作前,需要host先下载Firmware文件到WiFi芯片中,此部分工作在WiFi驱动中完成。
Broadcom WLAN模块同样存在着一个至关重要的文件:bcmdhd.cal,该文件定义了针对WLAN模块的NV值
Firmware与Nvram文件存放于external/wlan_loader/firmware/目录中,最终被编译到系统的/system/etc/firmware
WLAN Module工作的3种模式
(3)P2P
Broadcom WLAN Module所使用的2种Firmware
(2)fw_bcmdhd_apsta.bin
WLAN Module工作模式与固件的对应关系
扫描,ftrace信息
调用数据处理函数:dhd_sched_dpc-》dhd_dpc_thread-》dhd_dpc_thread-》dhdsdio_readframes-》dhd_rx_frame-》
/* Process special event packets and then discard them */ memset(&event, 0, sizeof(event));//非数据处理即事件如扫描完成,断开,加密出错等事件 if (ntoh16(skb->protocol) == ETHER_TYPE_BRCM) { dhd_wl_host_event(dhd, &ifidx,
- 1
- 2
- 3
- 4
PROC_START(wl_event_handler, cfg, &cfg->event_tsk, 0, “wl_event_handler”);
static s32 wl_event_handler(void *data) { struct bcm_cfg80211 *cfg = NULL; struct wl_event_q *e; tsk_ctl_t *tsk = (tsk_ctl_t *)data; struct wireless_dev *wdev = NULL; cfg = (struct bcm_cfg80211 *)tsk->parent; printf("tsk Enter, tsk = 0x%p\n", tsk); while (down_interruptible (&tsk->sema) == 0) {//由于来传来的参数是&cfg->event_tsk,此处&tsk->sema刚好是 &cfg->event_tsk.sema /* static void wl_wakeup_event(struct bcm_cfg80211 *cfg) { dhd_pub_t *dhd = (dhd_pub_t *)(cfg->pub); if (dhd->up && (cfg->event_tsk.thr_pid >= 0)) { up(&cfg->event_tsk.sema);唤醒进程 } } * / SMP_RD_BARRIER_DEPENDS(); if (tsk->terminated) { break; } while ((e = wl_deq_event(cfg))) {//出队,将刚接收到的事件取出 WL_DBG(("event type (%d), ifidx: %d bssidx: %d \n", e->etype, e->emsg.ifidx, e->emsg.bsscfgidx)); if (e->emsg.ifidx > WL_MAX_IFS) { WL_ERR((" Event ifidx not in range. val:%d \n", e->emsg.ifidx)); goto fail; } if (!(wdev = wl_get_wdev_by_bssidx(cfg, e->emsg.bsscfgidx))) { /* For WLC_E_IF would be handled by wl_host_event */ if (e->etype != WLC_E_IF) WL_ERR(("No wdev corresponding to bssidx: 0x%x found!" " Ignoring event.\n", e->emsg.bsscfgidx)); } else if (e->etype < WLC_E_LAST && cfg->evt_handler[e->etype]) { dhd_pub_t *dhd = (struct dhd_pub *)(cfg->pub); if (dhd->busstate == DHD_BUS_DOWN) { WL_ERR((": BUS is DOWN.\n")); } else { #ifdef DHD_IFDEBUG if (cfg->iface_cnt == 0) { wl_dump_ifinfo(cfg); } #endif cfg->evt_handler[e->etype](cfg, wdev_to_cfgdev(wdev), &e->emsg, e->edata);//调用处理事件的函数,这是一个钩子函数 } } else { WL_DBG(("Unknown Event (%d): ignoring\n", e->etype)); } fail: wl_put_event(e); DHD_EVENT_WAKE_UNLOCK(cfg->pub); } } printf("%s: was terminated\n", __FUNCTION__); complete_and_exit(&tsk->completed, 0); return 0; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
cfg->evt_handler[e->etype](cfg, wdev_to_cfgdev(wdev), &e->emsg, e->edata);
- 1
- 2
- 3
在wl_init_event_handler中注册回调函数
static void wl_init_event_handler(struct bcm_cfg80211 *cfg) { memset(cfg->evt_handler, 0, sizeof(cfg->evt_handler)); cfg->evt_handler[WLC_E_SCAN_COMPLETE] = wl_notify_scan_status; cfg->evt_handler[WLC_E_AUTH] = wl_notify_connect_status; cfg->evt_handler[WLC_E_ASSOC] = wl_notify_connect_status; cfg->evt_handler[WLC_E_LINK] = wl_notify_connect_status; cfg->evt_handler[WLC_E_DEAUTH_IND] = wl_notify_connect_status; cfg->evt_handler[WLC_E_DEAUTH] = wl_notify_connect_status; cfg->evt_handler[WLC_E_DISASSOC_IND] = wl_notify_connect_status; cfg->evt_handler[WLC_E_ASSOC_IND] = wl_notify_connect_status; cfg->evt_handler[WLC_E_REASSOC_IND] = wl_notify_connect_status; cfg->evt_handler[WLC_E_ROAM] = wl_notify_roaming_status; cfg->evt_handler[WLC_E_MIC_ERROR] = wl_notify_mic_status; cfg->evt_handler[WLC_E_SET_SSID] = wl_notify_connect_status; cfg->evt_handler[WLC_E_ACTION_FRAME_RX] = wl_notify_rx_mgmt_frame; cfg->evt_handler[WLC_E_PROBREQ_MSG] = wl_notify_rx_mgmt_frame; cfg->evt_handler[WLC_E_P2P_PROBREQ_MSG] = wl_notify_rx_mgmt_frame; cfg->evt_handler[WLC_E_P2P_DISC_LISTEN_COMPLETE] = wl_cfgp2p_listen_complete; cfg->evt_handler[WLC_E_ACTION_FRAME_COMPLETE] = wl_cfgp2p_action_tx_complete; cfg->evt_handler[WLC_E_ACTION_FRAME_OFF_CHAN_COMPLETE] = wl_cfgp2p_action_tx_complete; cfg->evt_handler[WLC_E_JOIN] = wl_notify_connect_status; cfg->evt_handler[WLC_E_START] = wl_notify_connect_status; #ifdef PNO_SUPPORT cfg->evt_handler[WLC_E_PFN_NET_FOUND] = wl_notify_pfn_status; #endif /* PNO_SUPPORT */ #ifdef GSCAN_SUPPORT cfg->evt_handler[WLC_E_PFN_BEST_BATCHING] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_SCAN_COMPLETE] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_GSCAN_FULL_RESULT] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_SWC] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_BSSID_NET_FOUND] = wl_notify_gscan_event; cfg->evt_handler[WLC_E_PFN_BSSID_NET_LOST] = wl_notify_gscan_event; #endif /* GSCAN_SUPPORT */ #ifdef WLTDLS cfg->evt_handler[WLC_E_TDLS_PEER_EVENT] = wl_tdls_event_handler; #endif /* WLTDLS */ cfg->evt_handler[WLC_E_BSSID] = wl_notify_roaming_status; #ifdef WL_RELMCAST cfg->evt_handler[WLC_E_RMC_EVENT] = wl_notify_rmc_status; #endif #ifdef BT_WIFI_HANDOVER cfg->evt_handler[WLC_E_BT_WIFI_HANDOVER_REQ] = wl_notify_bt_wifi_handover_req; #endif #ifdef WL_NAN cfg->evt_handler[WLC_E_NAN] = wl_cfgnan_notify_nan_status; cfg->evt_handler[WLC_E_PROXD] = wl_cfgnan_notify_proxd_status; #endif /* WL_NAN */ cfg->evt_handler[WLC_E_CSA_COMPLETE_IND] = wl_csa_complete_ind; #ifdef DHD_LOSSLESS_ROAMING cfg->evt_handler[WLC_E_ROAM_PREP] = wl_notify_roam_prep_status; #endif cfg->evt_handler[WLC_E_AP_STARTED] = wl_ap_start_ind; #ifdef CUSTOM_EVENT_PM_WAKE cfg->evt_handler[WLC_E_EXCESS_PM_WAKE_EVENT] = wl_check_pmstatus; #endif /* CUSTOM_EVENT_PM_WAKE */ cfg->evt_handler[WLC_E_PSK_SUP] = wl_notify_idsup_status; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
wl_notify_scan_status
static s32 wl_notify_scan_status(struct bcm_cfg80211 *cfg, bcm_struct_cfgdev *cfgdev, const wl_event_msg_t *e, void *data) { struct channel_info channel_inform; struct wl_scan_results *bss_list; struct net_device *ndev = NULL; u32 len = WL_SCAN_BUF_MAX; s32 err = 0; unsigned long flags; #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)) struct cfg80211_scan_info info; #endif WL_DBG(("Enter \n")); if (!wl_get_drv_status(cfg, SCANNING, ndev)) { WL_ERR(("scan is not ready \n")); return err; } ndev = cfgdev_to_wlc_ndev(cfgdev, cfg); mutex_lock(&cfg->usr_sync); wl_clr_drv_status(cfg, SCANNING, ndev); err = wldev_ioctl(ndev, WLC_GET_CHANNEL, &channel_inform, sizeof(channel_inform), false);//获取信道信息 if (unlikely(err)) { WL_ERR(("scan busy (%d)\n", err)); goto scan_done_out; } channel_inform.scan_channel = dtoh32(channel_inform.scan_channel); if (unlikely(channel_inform.scan_channel)) { WL_DBG(("channel_inform.scan_channel (%d)\n", channel_inform.scan_channel)); } cfg->bss_list = cfg->scan_results; bss_list = cfg->bss_list; memset(bss_list, 0, len); bss_list->buflen = htod32(len); err = wldev_ioctl(ndev, WLC_SCAN_RESULTS, bss_list, len, false);//获取扫描结果 if (unlikely(err) && unlikely(!cfg->scan_suppressed)) { WL_ERR(("%s Scan_results error (%d)\n", ndev->name, err)); err = -EINVAL; goto scan_done_out; } bss_list->buflen = dtoh32(bss_list->buflen); bss_list->version = dtoh32(bss_list->version); bss_list->count = dtoh32(bss_list->count); err = wl_inform_bss(cfg);//更新bss信息,最后调用到cfg80211_inform_bss_frame更新内核无线子系统的bss信息 scan_done_out: del_timer_sync(&cfg->scan_timeout); spin_lock_irqsave(&cfg->cfgdrv_lock, flags); if (cfg->scan_request) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 8, 0)) info.aborted = false; cfg80211_scan_done(cfg->scan_request, &info); #else cfg80211_scan_done(cfg->scan_request, false);//通知内核无线子系统扫描完成,让上层去获取扫描结果等操作 #endif cfg->scan_request = NULL; } spin_unlock_irqrestore(&cfg->cfgdrv_lock, flags); WL_DBG(("cfg80211_scan_done\n")); mutex_unlock(&cfg->usr_sync); return err; }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
wpa_supplicant-4774 [002] ...1 5463.125488: wl_cfg80211_scan <-nl80211_trigger_scan wpa_supplicant-4774 [002] ...1 5463.125495: wl_cfg_multip2p_operational <-wl_cfg80211_scan wpa_supplicant-4774 [002] ...1 5463.125498: wl_cfg80211_get_remain_on_channel_ndev <-wl_cfg80211_scan wpa_supplicant-4774 [002] ...1 5463.125504: wl_cfgp2p_discover_enable_search <-wl_cfg80211_scan wpa_supplicant-4774 [002] ...1 5463.125506: wl_cfg80211_set_mgmt_vndr_ies <-wl_cfg80211_scan wpa_supplicant-4774 [002] ...1 5463.125509: wl_cfg80211_parse_vndr_ies <-wl_cfg80211_set_mgmt_vndr_ies wpa_supplicant-4774 [002] ...1 5463.125511: bcm_next_tlv <-wl_cfg80211_parse_vndr_ies wpa_supplicant-4774 [002] ...1 5463.125513: bcm_next_tlv <-wl_cfg80211_parse_vndr_ies wpa_supplicant-4774 [002] ...1 5463.125514: bcm_next_tlv <-wl_cfg80211_parse_vndr_ies wpa_supplicant-4774 [002] ...1 5463.125515: bcm_next_tlv <-wl_cfg80211_parse_vndr_ies wpa_supplicant-4774 [002] ...1 5463.125519: $x <-wl_cfg80211_scan wpa_supplicant-4774 [002] ...1 5463.125521: dhd_ioctl_entry_local <-$x wpa_supplicant-4774 [002] ...1 5463.125522: dhd_net2idx <-dhd_ioctl_entry_local wpa_supplicant-4774 [002] ...1 5463.125524: dhd_os_wake_lock <-dhd_ioctl_entry_local wpa_supplicant-4774 [002] ...1 5463.125526: dhd_wl_ioctl <-dhd_ioctl_entry_local wpa_supplicant-4774 [002] ...1 5463.125528: dhd_os_proto_block <-dhd_wl_ioctl wpa_supplicant-4774 [002] ...1 5463.125530: dhd_os_general_spin_lock <-dhd_wl_ioctl wpa_supplicant-4774 [002] d..2 5463.125532: dhd_os_general_spin_unlock <-dhd_wl_ioctl wpa_supplicant-4774 [002] ...1 5463.125534: dhd_prot_ioctl <-dhd_wl_ioctl wpa_supplicant-4774 [002] ...1 5463.125536: $x <-dhd_prot_ioctl wpa_supplicant-4774 [002] ...1 5463.125537: dhd_os_wake_lock <-$x wpa_supplicant-4774 [002] ...1 5463.125539: dhd_bus_txctl <-$x wpa_supplicant-4774 [002] ...1 5463.125541: dhd_os_sdlock <-dhd_bus_txctl wpa_supplicant-4774 [002] ...1 5463.125544: dhdsdio_bussleep <-dhd_bus_txctl wpa_supplicant-4774 [002] ...1 5463.125545: dhdsdio_clk_devsleep_iovar <-dhdsdio_bussleep wpa_supplicant-4774 [002] ...1 5463.125547: dhdsdio_clk_kso_enab.isra.7 <-dhdsdio_clk_devsleep_iovar wpa_supplicant-4774 [002] ...1 5463.125549: dhdsdio_sleepcsr_get.isra.1 <-dhdsdio_clk_devsleep_iovar wpa_supplicant-4774 [002] ...1 5463.125550: bcmsdh_cfg_read <-dhdsdio_sleepcsr_get.isra.1 wpa_supplicant-4774 [002] ...1 5463.125552: sdioh_cfg_read <-bcmsdh_cfg_read wpa_supplicant-4774 [002] ...1 5463.125554: sdioh_request_byte <-sdioh_cfg_read wpa_supplicant-4774 [002] ...1 5463.126236: bcmsdh_cfg_read <-dhdsdio_clk_devsleep_iovar wpa_supplicant-4774 [002] ...1 5463.126241: sdioh_cfg_read <-bcmsdh_cfg_read wpa_supplicant-4774 [002] ...1 5463.126242: sdioh_request_byte <-sdioh_cfg_read wpa_supplicant-4774 [002] ...1 5463.126484: dhdsdio_clkctl.isra.10 <-dhd_bus_txctl wpa_supplicant-4774 [002] ...1 5463.126487: dhd_os_wd_timer <-dhdsdio_clkctl.isra.10 wpa_supplicant-4774 [002] ...1 5463.126489: dhd_os_wd_wake_lock <-dhd_os_wd_timer wpa_supplicant-4774 [002] d..2 5463.126494: dhd_os_wd_wake_lock <-dhd_os_wd_timer wpa_supplicant-4774 [002] ...1 5463.126498: dhd_os_wd_wake_unlock <-dhd_os_wd_timer wpa_supplicant-4774 [002] ...1 5463.126502: bcmsdh_cur_sbwad <-dhd_bus_txctl wpa_supplicant-4774 [002] ...1 5463.126503: dhd_bcmsdh_send_buf.constprop.27 <-dhd_bus_txctl wpa_supplicant-4774 [002] ...1 5463.126505: bcmsdh_send_buf <-dhd_bcmsdh_send_buf.constprop.27 wpa_supplicant-4774 [002] ...1 5463.126506: bcmsdhsdio_set_sbaddr_window <-bcmsdh_send_buf wpa_supplicant-4774 [002] ...1 5463.126508: sdioh_request_buffer <-bcmsdh_send_buf wpa_supplicant-4774 [002] ...1 5463.126510: sdioh_buffer_tofrom_bus <-sdioh_request_buffer
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
内核netlink接收来自应用层的消息并处理
genl_rcv()接收到数据会直接调用genl_rcv_msg() genl_family_rcv_msg static int genl_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { //nlmsghdr中的type应该和family的id一致, //但是内核中genl注册family时,id是自动非配的,那用户空间发送的消息怎么确认id, family = genl_family_find_byid(nlh->nlmsg_type); //根据nlh中定义的cmd类型决定 genl_family_rcv_msg(family, skb, nlh); { //在传入的nlh的载荷中包含着geml的头genlmsghdr, struct genlmsghdr *hdr = nlmsg_data(nlh); //genl 信息,里面有netlnik head,genl head,user head等信息,最终会由用户(nl80211)定义的ops处理 struct genl_info info; //如果有family有体检需要处理的,可以放在该处 err = family->pre_doit(ops, skb, &info); //通过cmd找到ops,对传入的数据进行处理 ops = genl_get_cmd(hdr->cmd, family); //ops处理数据 err = ops->doit(skb, &info); //family的后续处理 family->post_doit(ops, skb, &info); } }
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
wifi beacon强度获取:本例子驱动不走这个,直接驱动代码调用cfg80211_inform_bss_frame这类接口更新数据
ieee80211_tasklet_handler ieee80211_rx __ieee80211_rx_handle_packet { ieee80211_scan_rx //probe_rsp beacon帧 { cfg80211_inform_bss_frame--> cfg80211_bss_update--> (list_add_tail(&res->list, &dev->bss_list);)--> cfg80211_scan_done->-nl80211_send_scan_done(NL80211_CMD_NEW_SCAN_RESULTS) 1) + 12.542 us | cfg80211_scan_done [cfg80211](); ------------------------------------------ 1) wl_even-4966 => kworker-7064 ------------------------------------------ 1) | __cfg80211_scan_done [cfg80211]() { 1) | ___cfg80211_scan_done [cfg80211]() { 1) 0.834 us | cfg80211_sme_scan_done [cfg80211](); 1) | nl80211_build_scan_msg [cfg80211]() { 1) 7.541 us | nl80211_send_scan_msg.constprop.68 [cfg80211](); 1) + 14.750 us | } 1) + 22.000 us | nl80211_send_scan_result [cfg80211](); 1) + 48.875 us | } 1) + 53.667 us | } } ieee80211_prepare_and_rx_handle//数据帧,已连接上了后 { ieee80211_invoke_rx_handlers ieee80211_rx_handlers ieee80211_rx_h_sta_process中 sta->last_signal = status->signal; } } 获取给上层: const struct cfg80211_ops mac80211_config_ops = { .get_station = ieee80211_get_station, 中:sta_set_sinfo sinfo->signal = (s8)sta->last_signal;获取
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
wl btc mode 0