blob: bc89b1ef0cade5e6a44bf69980bff63c9d70bfee [file] [log] [blame]
Zhu Yibb9f8692009-05-21 21:20:45 +08001/*
2 * Intel Wireless Multicomm 3200 WiFi driver
3 *
4 * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
5 * Samuel Ortiz <samuel.ortiz@intel.com>
6 * Zhu Yi <yi.zhu@intel.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version
10 * 2 as published by the Free Software Foundation.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *
22 */
23
24#include <linux/kernel.h>
25#include <linux/netdevice.h>
26#include <linux/wireless.h>
27#include <linux/ieee80211.h>
28#include <net/cfg80211.h>
29
30#include "iwm.h"
31#include "commands.h"
32#include "cfg80211.h"
33#include "debug.h"
34
35#define RATETAB_ENT(_rate, _rateid, _flags) \
36 { \
37 .bitrate = (_rate), \
38 .hw_value = (_rateid), \
39 .flags = (_flags), \
40 }
41
42#define CHAN2G(_channel, _freq, _flags) { \
43 .band = IEEE80211_BAND_2GHZ, \
44 .center_freq = (_freq), \
45 .hw_value = (_channel), \
46 .flags = (_flags), \
47 .max_antenna_gain = 0, \
48 .max_power = 30, \
49}
50
51#define CHAN5G(_channel, _flags) { \
52 .band = IEEE80211_BAND_5GHZ, \
53 .center_freq = 5000 + (5 * (_channel)), \
54 .hw_value = (_channel), \
55 .flags = (_flags), \
56 .max_antenna_gain = 0, \
57 .max_power = 30, \
58}
59
60static struct ieee80211_rate iwm_rates[] = {
61 RATETAB_ENT(10, 0x1, 0),
62 RATETAB_ENT(20, 0x2, 0),
63 RATETAB_ENT(55, 0x4, 0),
64 RATETAB_ENT(110, 0x8, 0),
65 RATETAB_ENT(60, 0x10, 0),
66 RATETAB_ENT(90, 0x20, 0),
67 RATETAB_ENT(120, 0x40, 0),
68 RATETAB_ENT(180, 0x80, 0),
69 RATETAB_ENT(240, 0x100, 0),
70 RATETAB_ENT(360, 0x200, 0),
71 RATETAB_ENT(480, 0x400, 0),
72 RATETAB_ENT(540, 0x800, 0),
73};
74
75#define iwm_a_rates (iwm_rates + 4)
76#define iwm_a_rates_size 8
77#define iwm_g_rates (iwm_rates + 0)
78#define iwm_g_rates_size 12
79
80static struct ieee80211_channel iwm_2ghz_channels[] = {
81 CHAN2G(1, 2412, 0),
82 CHAN2G(2, 2417, 0),
83 CHAN2G(3, 2422, 0),
84 CHAN2G(4, 2427, 0),
85 CHAN2G(5, 2432, 0),
86 CHAN2G(6, 2437, 0),
87 CHAN2G(7, 2442, 0),
88 CHAN2G(8, 2447, 0),
89 CHAN2G(9, 2452, 0),
90 CHAN2G(10, 2457, 0),
91 CHAN2G(11, 2462, 0),
92 CHAN2G(12, 2467, 0),
93 CHAN2G(13, 2472, 0),
94 CHAN2G(14, 2484, 0),
95};
96
97static struct ieee80211_channel iwm_5ghz_a_channels[] = {
98 CHAN5G(34, 0), CHAN5G(36, 0),
99 CHAN5G(38, 0), CHAN5G(40, 0),
100 CHAN5G(42, 0), CHAN5G(44, 0),
101 CHAN5G(46, 0), CHAN5G(48, 0),
102 CHAN5G(52, 0), CHAN5G(56, 0),
103 CHAN5G(60, 0), CHAN5G(64, 0),
104 CHAN5G(100, 0), CHAN5G(104, 0),
105 CHAN5G(108, 0), CHAN5G(112, 0),
106 CHAN5G(116, 0), CHAN5G(120, 0),
107 CHAN5G(124, 0), CHAN5G(128, 0),
108 CHAN5G(132, 0), CHAN5G(136, 0),
109 CHAN5G(140, 0), CHAN5G(149, 0),
110 CHAN5G(153, 0), CHAN5G(157, 0),
111 CHAN5G(161, 0), CHAN5G(165, 0),
112 CHAN5G(184, 0), CHAN5G(188, 0),
113 CHAN5G(192, 0), CHAN5G(196, 0),
114 CHAN5G(200, 0), CHAN5G(204, 0),
115 CHAN5G(208, 0), CHAN5G(212, 0),
116 CHAN5G(216, 0),
117};
118
119static struct ieee80211_supported_band iwm_band_2ghz = {
120 .channels = iwm_2ghz_channels,
121 .n_channels = ARRAY_SIZE(iwm_2ghz_channels),
122 .bitrates = iwm_g_rates,
123 .n_bitrates = iwm_g_rates_size,
124};
125
126static struct ieee80211_supported_band iwm_band_5ghz = {
127 .channels = iwm_5ghz_a_channels,
128 .n_channels = ARRAY_SIZE(iwm_5ghz_a_channels),
129 .bitrates = iwm_a_rates,
130 .n_bitrates = iwm_a_rates_size,
131};
132
133int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
134{
135 struct wiphy *wiphy = iwm_to_wiphy(iwm);
136 struct iwm_bss_info *bss, *next;
137 struct iwm_umac_notif_bss_info *umac_bss;
138 struct ieee80211_mgmt *mgmt;
139 struct ieee80211_channel *channel;
140 struct ieee80211_supported_band *band;
141 s32 signal;
142 int freq;
143
144 list_for_each_entry_safe(bss, next, &iwm->bss_list, node) {
145 umac_bss = bss->bss;
146 mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf);
147
148 if (umac_bss->band == UMAC_BAND_2GHZ)
149 band = wiphy->bands[IEEE80211_BAND_2GHZ];
150 else if (umac_bss->band == UMAC_BAND_5GHZ)
151 band = wiphy->bands[IEEE80211_BAND_5GHZ];
152 else {
153 IWM_ERR(iwm, "Invalid band: %d\n", umac_bss->band);
154 return -EINVAL;
155 }
156
157 freq = ieee80211_channel_to_frequency(umac_bss->channel);
158 channel = ieee80211_get_channel(wiphy, freq);
159 signal = umac_bss->rssi * 100;
160
161 if (!cfg80211_inform_bss_frame(wiphy, channel, mgmt,
162 le16_to_cpu(umac_bss->frame_len),
163 signal, GFP_KERNEL))
164 return -EINVAL;
165 }
166
167 return 0;
168}
169
Johannes Berge36d56b2009-06-09 21:04:43 +0200170static int iwm_cfg80211_change_iface(struct wiphy *wiphy,
171 struct net_device *ndev,
Zhu Yibb9f8692009-05-21 21:20:45 +0800172 enum nl80211_iftype type, u32 *flags,
173 struct vif_params *params)
174{
Zhu Yibb9f8692009-05-21 21:20:45 +0800175 struct wireless_dev *wdev;
176 struct iwm_priv *iwm;
177 u32 old_mode;
178
Zhu Yibb9f8692009-05-21 21:20:45 +0800179 wdev = ndev->ieee80211_ptr;
180 iwm = ndev_to_iwm(ndev);
181 old_mode = iwm->conf.mode;
182
183 switch (type) {
184 case NL80211_IFTYPE_STATION:
185 iwm->conf.mode = UMAC_MODE_BSS;
186 break;
187 case NL80211_IFTYPE_ADHOC:
188 iwm->conf.mode = UMAC_MODE_IBSS;
189 break;
190 default:
191 return -EOPNOTSUPP;
192 }
193
194 wdev->iftype = type;
195
196 if ((old_mode == iwm->conf.mode) || !iwm->umac_profile)
197 return 0;
198
199 iwm->umac_profile->mode = cpu_to_le32(iwm->conf.mode);
200
201 if (iwm->umac_profile_active) {
202 int ret = iwm_invalidate_mlme_profile(iwm);
203 if (ret < 0)
204 IWM_ERR(iwm, "Couldn't invalidate profile\n");
205 }
206
207 return 0;
208}
209
210static int iwm_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
211 struct cfg80211_scan_request *request)
212{
213 struct iwm_priv *iwm = ndev_to_iwm(ndev);
214 int ret;
215
216 if (!test_bit(IWM_STATUS_READY, &iwm->status)) {
217 IWM_ERR(iwm, "Scan while device is not ready\n");
218 return -EIO;
219 }
220
221 if (test_bit(IWM_STATUS_SCANNING, &iwm->status)) {
222 IWM_ERR(iwm, "Scanning already\n");
223 return -EAGAIN;
224 }
225
226 if (test_bit(IWM_STATUS_SCAN_ABORTING, &iwm->status)) {
227 IWM_ERR(iwm, "Scanning being aborted\n");
228 return -EAGAIN;
229 }
230
231 set_bit(IWM_STATUS_SCANNING, &iwm->status);
232
233 ret = iwm_scan_ssids(iwm, request->ssids, request->n_ssids);
234 if (ret) {
235 clear_bit(IWM_STATUS_SCANNING, &iwm->status);
236 return ret;
237 }
238
239 iwm->scan_request = request;
240 return 0;
241}
242
243static int iwm_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
244{
245 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
246
247 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
248 (iwm->conf.rts_threshold != wiphy->rts_threshold)) {
249 int ret;
250
251 iwm->conf.rts_threshold = wiphy->rts_threshold;
252
253 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
254 CFG_RTS_THRESHOLD,
255 iwm->conf.rts_threshold);
256 if (ret < 0)
257 return ret;
258 }
259
260 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
261 (iwm->conf.frag_threshold != wiphy->frag_threshold)) {
262 int ret;
263
264 iwm->conf.frag_threshold = wiphy->frag_threshold;
265
Samuel Ortizb63b0ea2009-05-26 11:10:46 +0800266 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX,
Zhu Yibb9f8692009-05-21 21:20:45 +0800267 CFG_FRAG_THRESHOLD,
268 iwm->conf.frag_threshold);
269 if (ret < 0)
270 return ret;
271 }
272
273 return 0;
274}
275
276static int iwm_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
277 struct cfg80211_ibss_params *params)
278{
279 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
280 struct ieee80211_channel *chan = params->channel;
281 struct cfg80211_bss *bss;
282
283 if (!test_bit(IWM_STATUS_READY, &iwm->status))
284 return -EIO;
285
286 /* UMAC doesn't support creating IBSS network with specified bssid.
287 * This should be removed after we have join only mode supported. */
288 if (params->bssid)
289 return -EOPNOTSUPP;
290
291 bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
292 params->ssid, params->ssid_len);
293 if (!bss) {
294 iwm_scan_one_ssid(iwm, params->ssid, params->ssid_len);
295 schedule_timeout_interruptible(2 * HZ);
296 bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
297 params->ssid, params->ssid_len);
298 }
299 /* IBSS join only mode is not supported by UMAC ATM */
300 if (bss) {
301 cfg80211_put_bss(bss);
302 return -EOPNOTSUPP;
303 }
304
305 iwm->channel = ieee80211_frequency_to_channel(chan->center_freq);
306 iwm->umac_profile->ibss.band = chan->band;
307 iwm->umac_profile->ibss.channel = iwm->channel;
308 iwm->umac_profile->ssid.ssid_len = params->ssid_len;
309 memcpy(iwm->umac_profile->ssid.ssid, params->ssid, params->ssid_len);
310
311 if (params->bssid)
312 memcpy(&iwm->umac_profile->bssid[0], params->bssid, ETH_ALEN);
313
314 return iwm_send_mlme_profile(iwm);
315}
316
317static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
318{
319 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
320
321 if (iwm->umac_profile_active)
322 return iwm_invalidate_mlme_profile(iwm);
323
324 return 0;
325}
326
327static struct cfg80211_ops iwm_cfg80211_ops = {
328 .change_virtual_intf = iwm_cfg80211_change_iface,
329 .scan = iwm_cfg80211_scan,
330 .set_wiphy_params = iwm_cfg80211_set_wiphy_params,
331 .join_ibss = iwm_cfg80211_join_ibss,
332 .leave_ibss = iwm_cfg80211_leave_ibss,
333};
334
335struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
336{
337 int ret = 0;
338 struct wireless_dev *wdev;
339
340 /*
341 * We're trying to have the following memory
342 * layout:
343 *
344 * +-------------------------+
345 * | struct wiphy |
346 * +-------------------------+
347 * | struct iwm_priv |
348 * +-------------------------+
349 * | bus private data |
350 * | (e.g. iwm_priv_sdio) |
351 * +-------------------------+
352 *
353 */
354
355 wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
356 if (!wdev) {
357 dev_err(dev, "Couldn't allocate wireless device\n");
358 return ERR_PTR(-ENOMEM);
359 }
360
361 wdev->wiphy = wiphy_new(&iwm_cfg80211_ops,
362 sizeof(struct iwm_priv) + sizeof_bus);
363 if (!wdev->wiphy) {
364 dev_err(dev, "Couldn't allocate wiphy device\n");
365 ret = -ENOMEM;
366 goto out_err_new;
367 }
368
369 set_wiphy_dev(wdev->wiphy, dev);
370 wdev->wiphy->max_scan_ssids = UMAC_WIFI_IF_PROBE_OPTION_MAX;
371 wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
372 BIT(NL80211_IFTYPE_ADHOC);
373 wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &iwm_band_2ghz;
374 wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz;
375 wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
376
377 ret = wiphy_register(wdev->wiphy);
378 if (ret < 0) {
379 dev_err(dev, "Couldn't register wiphy device\n");
380 goto out_err_register;
381 }
382
383 return wdev;
384
385 out_err_register:
386 wiphy_free(wdev->wiphy);
387
388 out_err_new:
389 kfree(wdev);
390
391 return ERR_PTR(ret);
392}
393
394void iwm_wdev_free(struct iwm_priv *iwm)
395{
396 struct wireless_dev *wdev = iwm_to_wdev(iwm);
397
398 if (!wdev)
399 return;
400
401 wiphy_unregister(wdev->wiphy);
402 wiphy_free(wdev->wiphy);
403 kfree(wdev);
404}