?? wmi.c
字號:
/* * Copyright (c) 2004-2006 Atheros Communications Inc. * * Wireless Network driver for Atheros AR6001 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation; * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * * This module implements the hardware independent layer of the * Wireless Module Interface (WMI) protocol. * */#include "../include/athdefs.h"#include "../include/athtypes.h"#include "../include/osapi.h"#include "../include/htc.h"#include "../include/wmi.h"#include "../include/ieee80211.h"#include "../include/ieee80211_node.h"#include "../include/wlan_api.h"#include "../include/wmi_api.h"#include "../include/dset_api.h"#include "../include/gpio_api.h"#include "../include/wmi_host.h"#include "../include/athdrv.h"#include "../include/ar6000_api.h"#ifdef DEBUGint wmi_debug = 0;#define WMI_DEBUG_PRINTF(args...) if (wmi_debug) printk(args);#define WMI_DEBUG_PRINTF2(args...) if (wmi_debug > 1) printk(args);#else#define WMI_DEBUG_PRINTF(args...)#define WMI_DEBUG_PRINTF2(args...)#endifstatic A_STATUS wmi_ready_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_connect_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_disconnect_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_tkip_micerr_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_bssInfo_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_opt_frame_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_pstream_timeout_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_sync_point(struct wmi_t *wmip);static A_STATUS wmi_create_pstream_reply_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_delete_pstream_reply_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_bitrate_reply_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_channelList_reply_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_regDomain_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_txPwr_reply_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_neighborReport_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_dset_open_req_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);#if CONFIG_HOST_DSET_SUPPORTstatic A_STATUS wmi_dset_close_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_dset_data_req_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);#endif /* CONFIG_HOST_DSET_SUPPORT */static A_STATUS wmi_scanComplete_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_errorEvent_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_statsEvent_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_rssiThresholdEvent_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_reportErrorEvent_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_cac_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_roam_tbl_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_roam_data_event_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);#if CONFIG_HOST_GPIO_SUPPORTstatic A_STATUS wmi_gpio_intr_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_gpio_data_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);static A_STATUS wmi_gpio_ack_rx(struct wmi_t *wmip, A_UINT8 *datap, int len);#endif /* CONFIG_HOST_GPIO_SUPPORT */static const A_INT32 wmi_rateTable[] = { 1000, 2000, 5500, 11000, 6000, 9000, 12000, 18000, 24000, 36000, 48000, 54000, 0};#define MODE_A_SUPPORT_RATE_START 4#define MODE_A_SUPPORT_RATE_STOP 11#define MODE_GONLY_SUPPORT_RATE_START MODE_A_SUPPORT_RATE_START#define MODE_GONLY_SUPPORT_RATE_STOP MODE_A_SUPPORT_RATE_STOP#define MODE_B_SUPPORT_RATE_START 0#define MODE_B_SUPPORT_RATE_STOP 3/* 802.1d to AC mapping. Refer pg 57 of WMM-test-plan-v1.2 */const A_UINT8 up_to_ac[]= { WMM_AC_BE, WMM_AC_BK, WMM_AC_BK, WMM_AC_BE, WMM_AC_VI, WMM_AC_VI, WMM_AC_VO, WMM_AC_VO, };void *wmi_init(void *devt){ struct wmi_t *wmip; A_UINT8 i; wmip = A_MALLOC(sizeof(struct wmi_t)); if (wmip == NULL) { return (NULL); } A_MEMZERO(wmip, sizeof(*wmip)); wmip->wmi_devt = devt; wlan_node_table_init(wmip, &wmip->wmi_scan_table); for (i = UPLINK_TRAFFIC; i < BIDIR_TRAFFIC; i++) { wmip->wmi_pstreamCmdInProgress[i][WMM_AC_BE] = FALSE; wmip->wmi_pstreamCmdInProgress[i][WMM_AC_BK] = FALSE; wmip->wmi_pstreamCmdInProgress[i][WMM_AC_VI] = FALSE; wmip->wmi_pstreamCmdInProgress[i][WMM_AC_VO] = FALSE; } wmip->wmi_cpstreamCmdInProgress = FALSE; wmi_qos_state_init(wmip); wmip->wmi_powerMode = REC_POWER; wmip->wmi_phyMode = WMI_11G_MODE; return (wmip);}voidwmi_qos_state_init(struct wmi_t *wmip){ A_UINT8 i; if (wmip == NULL) { return; } /* Initialize QoS States */ wmip->wmi_numQoSStream = 0; for (i = 0; i < WMI_MAX_NUM_PRI_STREAMS; i++) { wmip->wmi_priority[i].inUse = 0; wmip->wmi_priority[i].mbox = WMI_BEST_EFFORT_MBOX; } for (i = 0; i < WMM_NUM_AC; i++) { wmip->wmi_trafficClassMap[UPLINK_TRAFFIC][i] = WMI_NOT_MAPPED; wmip->wmi_trafficClassMap[DNLINK_TRAFFIC][i] = WMI_NOT_MAPPED; } wmip->wmi_trafficClassMap[UPLINK_TRAFFIC][WMM_AC_BE] = WMI_BEST_EFFORT_MBOX; wmip->wmi_trafficClassMap[DNLINK_TRAFFIC][WMM_AC_BE] = WMI_BEST_EFFORT_MBOX; for (i = 0; i < WMI_MBOX_COUNT; i++) { wmip->wmi_mboxMap[UPLINK_TRAFFIC][i].trafficClass = WMM_AC_BE; wmip->wmi_mboxMap[UPLINK_TRAFFIC][i].priorityNum = WMI_NOT_MAPPED; wmip->wmi_mboxMap[DNLINK_TRAFFIC][i].trafficClass = WMM_AC_BE; wmip->wmi_mboxMap[DNLINK_TRAFFIC][i].priorityNum = WMI_NOT_MAPPED; } wmip->wmi_olderPriRxMbox = WMI_HIGH_PRIORITY_MBOX; wmip->wmi_newerPriRxMbox = WMI_LOW_PRIORITY_MBOX; ar6000_set_numdataendpts(wmip->wmi_devt, 1);}voidwmi_shutdown(struct wmi_t *wmip){ if (wmip != NULL) { wlan_node_table_cleanup(&wmip->wmi_scan_table); A_FREE(wmip); }}/* * performs DIX to 802.3 encapsulation for transmit packets. * uses passed in buffer. Returns buffer or NULL if failed. * Assumes the entire DIX header is contigous and that there is * enough room in the buffer for a 802.3 mac header and LLC+SNAP headers. */A_STATUSwmi_dix_2_dot3(struct wmi_t *wmip, void *osbuf){ A_UINT8 *datap; A_UINT16 typeorlen; ATH_MAC_HDR macHdr; ATH_LLC_SNAP_HDR *llcHdr; A_ASSERT(osbuf != NULL); if (a_netbuf_headroom(osbuf) < (sizeof(ATH_LLC_SNAP_HDR) + sizeof(WMI_DATA_HDR))) { return A_NO_MEMORY; } datap = a_netbuf_to_data(osbuf); typeorlen = *(A_UINT16 *)(datap + ATH_MAC_LEN + ATH_MAC_LEN); if (!IS_ETHERTYPE(A_BE2CPU16(typeorlen))) { /* * packet is already in 802.3 format - return success */ WMI_DEBUG_PRINTF("packet already 802.3\n"); return (A_OK); } /* * Save mac fields and length to be inserted later */ A_MEMCPY(macHdr.dstMac, datap, ATH_MAC_LEN); A_MEMCPY(macHdr.srcMac, datap + ATH_MAC_LEN, ATH_MAC_LEN); macHdr.typeOrLen = A_CPU2BE16(a_netbuf_to_len(osbuf) - sizeof(ATH_MAC_HDR) + sizeof(ATH_LLC_SNAP_HDR)); /* * Make room for LLC+SNAP headers */ if (a_netbuf_push(osbuf, sizeof(ATH_LLC_SNAP_HDR)) != A_OK) { return A_NO_MEMORY; } datap = a_netbuf_to_data(osbuf); A_MEMCPY(datap, &macHdr, sizeof (ATH_MAC_HDR)); llcHdr = (ATH_LLC_SNAP_HDR *)(datap + sizeof(ATH_MAC_HDR)); llcHdr->dsap = 0xAA; llcHdr->ssap = 0xAA; llcHdr->cntl = 0x03; llcHdr->orgCode[0] = 0x0; llcHdr->orgCode[1] = 0x0; llcHdr->orgCode[2] = 0x0; llcHdr->etherType = typeorlen; return (A_OK);}/* * Adds a WMI data header * Assumes there is enough room in the buffer to add header. */A_STATUSwmi_data_hdr_add(struct wmi_t *wmip, void *osbuf, A_UINT8 msgType){ WMI_DATA_HDR *dtHdr; A_ASSERT(osbuf != NULL); if (a_netbuf_push(osbuf, sizeof(WMI_DATA_HDR)) != A_OK) { return A_NO_MEMORY; } dtHdr = (WMI_DATA_HDR *)a_netbuf_to_data(osbuf); dtHdr->info = msgType; dtHdr->rssi = 0; return (A_OK);}A_UINT8 wmi_implicit_create_pstream(struct wmi_t *wmip, void *osbuf, A_UINT8 dir){ A_UINT8 *datap; A_UINT8 trafficClass, userPriority = 0; ATH_LLC_SNAP_HDR *llcHdr; A_UINT16 ipType = IP_ETHERTYPE; WMI_DATA_HDR *dtHdr; WMI_CREATE_PSTREAM_CMD cmd; A_ASSERT(osbuf != NULL); A_ASSERT(dir == DNLINK_TRAFFIC || dir == UPLINK_TRAFFIC); datap = a_netbuf_to_data(osbuf); llcHdr = (ATH_LLC_SNAP_HDR *)(datap + sizeof(WMI_DATA_HDR) + sizeof(ATH_MAC_HDR)); if (llcHdr->etherType == htons(ipType)) { /* Extract the endpoint info from the TOS field in the IP header */ userPriority = ar6000_iptos_to_userPriority(((A_UINT8 *)llcHdr) + sizeof(ATH_LLC_SNAP_HDR)); trafficClass = convert_userPriority_to_trafficClass(userPriority); } else { trafficClass = WMM_AC_BE; } dtHdr = (WMI_DATA_HDR *)datap; if(dir==UPLINK_TRAFFIC) dtHdr->info |= (userPriority & WMI_DATA_HDR_UP_MASK) << WMI_DATA_HDR_UP_SHIFT; /* lower 3-bits are 802.1d priority */ /* Implicitly determine whether a create_pstream_cmd is needed for this trafficClass */ if (!((trafficClass == WMM_AC_BE) || (wmip->wmi_trafficClassMap[dir][trafficClass] != WMI_NOT_MAPPED))) { A_UINT8 reqMbox; /* * If the data pkt is tagged with a priority that doesn't have a MBOX created, * we must first call create_pstream_cmd * Originally, assume traffic goes to BE MBox, * until the driver receives the reply from the create_pstream cmd */ wmip->wmi_trafficClassMap[dir][trafficClass] = WMI_BEST_EFFORT_MBOX; if (dir == DNLINK_TRAFFIC) { /* determine which mailbox to use */ reqMbox = wmip->wmi_olderPriRxMbox; } else { reqMbox = WMI_BEST_EFFORT_MBOX; } A_MEMZERO(&cmd, sizeof(cmd)); cmd.trafficClass = trafficClass; cmd.rxQueueNum = reqMbox; cmd.userPriority = userPriority; cmd.inactivityInt = WMI_IMPLICIT_PSTREAM_INACTIVITY_INT; if (wmi_create_pstream_cmd(wmip, &cmd) != A_OK) { wmip->wmi_trafficClassMap[dir][trafficClass] = WMI_NOT_MAPPED; trafficClass = WMM_AC_BE; } } return trafficClass;}HTC_ENDPOINT_IDwmi_get_endpoint(struct wmi_t *wmip, A_UINT8 trafficClass){ WMI_DEBUG_PRINTF2("1 pkt of traffic class(%d) to mbox(%d)\n", trafficClass, wmip->wmi_trafficClassMap[UPLINK_TRAFFIC][trafficClass]); return wmip->wmi_trafficClassMap[UPLINK_TRAFFIC][trafficClass];}/* * performs 802.3 to DIX encapsulation for received packets. * Assumes the entire 802.3 header is contigous. */A_STATUSwmi_dot3_2_dix(struct wmi_t *wmip, void *osbuf){ A_UINT8 *datap; ATH_MAC_HDR macHdr; ATH_LLC_SNAP_HDR *llcHdr; A_ASSERT(osbuf != NULL); datap = a_netbuf_to_data(osbuf); A_MEMCPY(&macHdr, datap, sizeof(ATH_MAC_HDR)); llcHdr = (ATH_LLC_SNAP_HDR *)(datap + sizeof(ATH_MAC_HDR)); macHdr.typeOrLen = llcHdr->etherType; if (a_netbuf_pull(osbuf, sizeof(ATH_LLC_SNAP_HDR)) != A_OK) { return A_NO_MEMORY; } datap = a_netbuf_to_data(osbuf); A_MEMCPY(datap, &macHdr, sizeof (ATH_MAC_HDR)); return (A_OK);}/* * Removes a WMI data header */A_STATUSwmi_data_hdr_remove(struct wmi_t *wmip, void *osbuf){ A_ASSERT(osbuf != NULL); return (a_netbuf_pull(osbuf, sizeof(WMI_DATA_HDR)));}voidwmi_iterate_nodes(struct wmi_t *wmip, wlan_node_iter_func *f, void *arg){ wlan_iterate_nodes(&wmip->wmi_scan_table, f, arg);}/* * WMI Extended Event received from Target. */A_STATUSwmi_control_rx_xtnd(struct wmi_t *wmip, void *osbuf){ WMIX_CMD_HDR *cmd; A_UINT16 id; A_UINT8 *datap; A_UINT32 len; A_STATUS status = A_OK; if (a_netbuf_to_len(osbuf) < sizeof(WMIX_CMD_HDR)) { WMI_DEBUG_PRINTF("wmi extended event rx: bad packet\n"); wmip->wmi_stats.cmd_len_err++; a_netbuf_free(osbuf); return A_ERROR; } cmd = (WMIX_CMD_HDR *)a_netbuf_to_data(osbuf); id = cmd->commandId; if (a_netbuf_pull(osbuf, sizeof(WMIX_CMD_HDR)) != A_OK) { WMI_DEBUG_PRINTF("wmi extended event rx: bad packet\n"); wmip->wmi_stats.cmd_len_err++; a_netbuf_free(osbuf); return A_ERROR; } datap = a_netbuf_to_data(osbuf); len = a_netbuf_to_len(osbuf); switch (id) { case (WMIX_DSETOPENREQ_EVENTID): status = wmi_dset_open_req_rx(wmip, datap, len); break;#if CONFIG_HOST_DSET_SUPPORT case (WMIX_DSETCLOSE_EVENTID): status = wmi_dset_close_rx(wmip, datap, len); break; case (WMIX_DSETDATAREQ_EVENTID): status = wmi_dset_data_req_rx(wmip, datap, len); break;#endif /* CONFIG_HOST_DSET_SUPPORT */#if CONFIG_HOST_GPIO_SUPPORT case (WMIX_GPIO_INTR_EVENTID): wmi_gpio_intr_rx(wmip, datap, len); break; case (WMIX_GPIO_DATA_EVENTID): wmi_gpio_data_rx(wmip, datap, len);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -