aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath6kl/wmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c')
-rw-r--r--drivers/net/wireless/ath/ath6kl/wmi.c152
1 files changed, 146 insertions, 6 deletions
diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c
index 922344d3b262..f6f2aa27fc20 100644
--- a/drivers/net/wireless/ath/ath6kl/wmi.c
+++ b/drivers/net/wireless/ath/ath6kl/wmi.c
@@ -85,7 +85,7 @@ struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx)
85{ 85{
86 struct ath6kl_vif *vif, *found = NULL; 86 struct ath6kl_vif *vif, *found = NULL;
87 87
88 if (WARN_ON(if_idx > (MAX_NUM_VIF - 1))) 88 if (WARN_ON(if_idx > (ar->vif_max - 1)))
89 return NULL; 89 return NULL;
90 90
91 /* FIXME: Locking */ 91 /* FIXME: Locking */
@@ -187,7 +187,7 @@ int ath6kl_wmi_data_hdr_add(struct wmi *wmi, struct sk_buff *skb,
187 struct wmi_data_hdr *data_hdr; 187 struct wmi_data_hdr *data_hdr;
188 int ret; 188 int ret;
189 189
190 if (WARN_ON(skb == NULL || (if_idx > MAX_NUM_VIF - 1))) 190 if (WARN_ON(skb == NULL || (if_idx > wmi->parent_dev->vif_max - 1)))
191 return -EINVAL; 191 return -EINVAL;
192 192
193 if (tx_meta_info) { 193 if (tx_meta_info) {
@@ -977,6 +977,13 @@ static int ath6kl_wmi_tkip_micerr_event_rx(struct wmi *wmi, u8 *datap, int len,
977 return 0; 977 return 0;
978} 978}
979 979
980void ath6kl_wmi_sscan_timer(unsigned long ptr)
981{
982 struct ath6kl_vif *vif = (struct ath6kl_vif *) ptr;
983
984 cfg80211_sched_scan_results(vif->ar->wiphy);
985}
986
980static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len, 987static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
981 struct ath6kl_vif *vif) 988 struct ath6kl_vif *vif)
982{ 989{
@@ -1066,6 +1073,21 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
1066 return -ENOMEM; 1073 return -ENOMEM;
1067 cfg80211_put_bss(bss); 1074 cfg80211_put_bss(bss);
1068 1075
1076 /*
1077 * Firmware doesn't return any event when scheduled scan has
1078 * finished, so we need to use a timer to find out when there are
1079 * no more results.
1080 *
1081 * The timer is started from the first bss info received, otherwise
1082 * the timer would not ever fire if the scan interval is short
1083 * enough.
1084 */
1085 if (ar->state == ATH6KL_STATE_SCHED_SCAN &&
1086 !timer_pending(&vif->sched_scan_timer)) {
1087 mod_timer(&vif->sched_scan_timer, jiffies +
1088 msecs_to_jiffies(ATH6KL_SCHED_SCAN_RESULT_DELAY));
1089 }
1090
1069 return 0; 1091 return 0;
1070} 1092}
1071 1093
@@ -1620,7 +1642,7 @@ int ath6kl_wmi_cmd_send(struct wmi *wmi, u8 if_idx, struct sk_buff *skb,
1620 int ret; 1642 int ret;
1621 u16 info1; 1643 u16 info1;
1622 1644
1623 if (WARN_ON(skb == NULL || (if_idx > (MAX_NUM_VIF - 1)))) 1645 if (WARN_ON(skb == NULL || (if_idx > (wmi->parent_dev->vif_max - 1))))
1624 return -EINVAL; 1646 return -EINVAL;
1625 1647
1626 ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n", 1648 ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n",
@@ -1682,7 +1704,8 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx,
1682 u8 pairwise_crypto_len, 1704 u8 pairwise_crypto_len,
1683 enum crypto_type group_crypto, 1705 enum crypto_type group_crypto,
1684 u8 group_crypto_len, int ssid_len, u8 *ssid, 1706 u8 group_crypto_len, int ssid_len, u8 *ssid,
1685 u8 *bssid, u16 channel, u32 ctrl_flags) 1707 u8 *bssid, u16 channel, u32 ctrl_flags,
1708 u8 nw_subtype)
1686{ 1709{
1687 struct sk_buff *skb; 1710 struct sk_buff *skb;
1688 struct wmi_connect_cmd *cc; 1711 struct wmi_connect_cmd *cc;
@@ -1722,6 +1745,7 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx,
1722 cc->grp_crypto_len = group_crypto_len; 1745 cc->grp_crypto_len = group_crypto_len;
1723 cc->ch = cpu_to_le16(channel); 1746 cc->ch = cpu_to_le16(channel);
1724 cc->ctrl_flags = cpu_to_le32(ctrl_flags); 1747 cc->ctrl_flags = cpu_to_le32(ctrl_flags);
1748 cc->nw_subtype = nw_subtype;
1725 1749
1726 if (bssid != NULL) 1750 if (bssid != NULL)
1727 memcpy(cc->bssid, bssid, ETH_ALEN); 1751 memcpy(cc->bssid, bssid, ETH_ALEN);
@@ -1774,6 +1798,72 @@ int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx)
1774 return ret; 1798 return ret;
1775} 1799}
1776 1800
1801int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
1802 enum wmi_scan_type scan_type,
1803 u32 force_fgscan, u32 is_legacy,
1804 u32 home_dwell_time, u32 force_scan_interval,
1805 s8 num_chan, u16 *ch_list, u32 no_cck, u32 *rates)
1806{
1807 struct sk_buff *skb;
1808 struct wmi_begin_scan_cmd *sc;
1809 s8 size;
1810 int i, band, ret;
1811 struct ath6kl *ar = wmi->parent_dev;
1812 int num_rates;
1813
1814 size = sizeof(struct wmi_begin_scan_cmd);
1815
1816 if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))
1817 return -EINVAL;
1818
1819 if (num_chan > WMI_MAX_CHANNELS)
1820 return -EINVAL;
1821
1822 if (num_chan)
1823 size += sizeof(u16) * (num_chan - 1);
1824
1825 skb = ath6kl_wmi_get_new_buf(size);
1826 if (!skb)
1827 return -ENOMEM;
1828
1829 sc = (struct wmi_begin_scan_cmd *) skb->data;
1830 sc->scan_type = scan_type;
1831 sc->force_fg_scan = cpu_to_le32(force_fgscan);
1832 sc->is_legacy = cpu_to_le32(is_legacy);
1833 sc->home_dwell_time = cpu_to_le32(home_dwell_time);
1834 sc->force_scan_intvl = cpu_to_le32(force_scan_interval);
1835 sc->no_cck = cpu_to_le32(no_cck);
1836 sc->num_ch = num_chan;
1837
1838 for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
1839 struct ieee80211_supported_band *sband =
1840 ar->wiphy->bands[band];
1841 u32 ratemask = rates[band];
1842 u8 *supp_rates = sc->supp_rates[band].rates;
1843 num_rates = 0;
1844
1845 for (i = 0; i < sband->n_bitrates; i++) {
1846 if ((BIT(i) & ratemask) == 0)
1847 continue; /* skip rate */
1848 supp_rates[num_rates++] =
1849 (u8) (sband->bitrates[i].bitrate / 5);
1850 }
1851 sc->supp_rates[band].nrates = num_rates;
1852 }
1853
1854 for (i = 0; i < num_chan; i++)
1855 sc->ch_list[i] = cpu_to_le16(ch_list[i]);
1856
1857 ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_BEGIN_SCAN_CMDID,
1858 NO_SYNC_WMIFLAG);
1859
1860 return ret;
1861}
1862
1863/* ath6kl_wmi_start_scan_cmd is to be deprecated. Use
1864 * ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P
1865 * mgmt operations using station interface.
1866 */
1777int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx, 1867int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx,
1778 enum wmi_scan_type scan_type, 1868 enum wmi_scan_type scan_type,
1779 u32 force_fgscan, u32 is_legacy, 1869 u32 force_fgscan, u32 is_legacy,
@@ -2940,7 +3030,10 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
2940 p = (struct wmi_set_appie_cmd *) skb->data; 3030 p = (struct wmi_set_appie_cmd *) skb->data;
2941 p->mgmt_frm_type = mgmt_frm_type; 3031 p->mgmt_frm_type = mgmt_frm_type;
2942 p->ie_len = ie_len; 3032 p->ie_len = ie_len;
2943 memcpy(p->ie_info, ie, ie_len); 3033
3034 if (ie != NULL && ie_len > 0)
3035 memcpy(p->ie_info, ie, ie_len);
3036
2944 return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_APPIE_CMDID, 3037 return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_APPIE_CMDID,
2945 NO_SYNC_WMIFLAG); 3038 NO_SYNC_WMIFLAG);
2946} 3039}
@@ -2981,6 +3074,10 @@ int ath6kl_wmi_remain_on_chnl_cmd(struct wmi *wmi, u8 if_idx, u32 freq, u32 dur)
2981 NO_SYNC_WMIFLAG); 3074 NO_SYNC_WMIFLAG);
2982} 3075}
2983 3076
3077/* ath6kl_wmi_send_action_cmd is to be deprecated. Use
3078 * ath6kl_wmi_send_mgmt_cmd instead. The new function supports P2P
3079 * mgmt operations using station interface.
3080 */
2984int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, 3081int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
2985 u32 wait, const u8 *data, u16 data_len) 3082 u32 wait, const u8 *data, u16 data_len)
2986{ 3083{
@@ -3018,14 +3115,57 @@ int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
3018 NO_SYNC_WMIFLAG); 3115 NO_SYNC_WMIFLAG);
3019} 3116}
3020 3117
3118int ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq,
3119 u32 wait, const u8 *data, u16 data_len,
3120 u32 no_cck)
3121{
3122 struct sk_buff *skb;
3123 struct wmi_send_mgmt_cmd *p;
3124 u8 *buf;
3125
3126 if (wait)
3127 return -EINVAL; /* Offload for wait not supported */
3128
3129 buf = kmalloc(data_len, GFP_KERNEL);
3130 if (!buf)
3131 return -ENOMEM;
3132
3133 skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len);
3134 if (!skb) {
3135 kfree(buf);
3136 return -ENOMEM;
3137 }
3138
3139 kfree(wmi->last_mgmt_tx_frame);
3140 memcpy(buf, data, data_len);
3141 wmi->last_mgmt_tx_frame = buf;
3142 wmi->last_mgmt_tx_frame_len = data_len;
3143
3144 ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u "
3145 "len=%u\n", id, freq, wait, data_len);
3146 p = (struct wmi_send_mgmt_cmd *) skb->data;
3147 p->id = cpu_to_le32(id);
3148 p->freq = cpu_to_le32(freq);
3149 p->wait = cpu_to_le32(wait);
3150 p->no_cck = cpu_to_le32(no_cck);
3151 p->len = cpu_to_le16(data_len);
3152 memcpy(p->data, data, data_len);
3153 return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SEND_MGMT_CMDID,
3154 NO_SYNC_WMIFLAG);
3155}
3156
3021int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq, 3157int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq,
3022 const u8 *dst, const u8 *data, 3158 const u8 *dst, const u8 *data,
3023 u16 data_len) 3159 u16 data_len)
3024{ 3160{
3025 struct sk_buff *skb; 3161 struct sk_buff *skb;
3026 struct wmi_p2p_probe_response_cmd *p; 3162 struct wmi_p2p_probe_response_cmd *p;
3163 size_t cmd_len = sizeof(*p) + data_len;
3027 3164
3028 skb = ath6kl_wmi_get_new_buf(sizeof(*p) + data_len); 3165 if (data_len == 0)
3166 cmd_len++; /* work around target minimum length requirement */
3167
3168 skb = ath6kl_wmi_get_new_buf(cmd_len);
3029 if (!skb) 3169 if (!skb)
3030 return -ENOMEM; 3170 return -ENOMEM;
3031 3171