diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath6kl/wmi.c')
-rw-r--r-- | drivers/net/wireless/ath/ath6kl/wmi.c | 152 |
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 | ||
980 | void 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 | |||
980 | static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len, | 987 | static 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 | ||
1801 | int 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 | */ | ||
1777 | int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx, | 1867 | int 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 | */ | ||
2984 | int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id, u32 freq, | 3081 | int 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 | ||
3118 | int 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 | |||
3021 | int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq, | 3157 | int 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 | ||