2 * Intel Wireless Multicomm 3200 WiFi driver
4 * Copyright (C) 2009 Intel Corporation <ilw@linux.intel.com>
5 * Samuel Ortiz <samuel.ortiz@intel.com>
6 * Zhu Yi <yi.zhu@intel.com>
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.
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.
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
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>
35 #define RATETAB_ENT(_rate, _rateid, _flags) \
38 .hw_value = (_rateid), \
42 #define CHAN2G(_channel, _freq, _flags) { \
43 .band = IEEE80211_BAND_2GHZ, \
44 .center_freq = (_freq), \
45 .hw_value = (_channel), \
47 .max_antenna_gain = 0, \
51 #define CHAN5G(_channel, _flags) { \
52 .band = IEEE80211_BAND_5GHZ, \
53 .center_freq = 5000 + (5 * (_channel)), \
54 .hw_value = (_channel), \
56 .max_antenna_gain = 0, \
60 static 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),
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
80 static struct ieee80211_channel iwm_2ghz_channels[] = {
97 static 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),
119 static 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,
126 static 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,
133 int iwm_cfg80211_inform_bss(struct iwm_priv *iwm)
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;
144 list_for_each_entry_safe(bss, next, &iwm->bss_list, node) {
146 mgmt = (struct ieee80211_mgmt *)(umac_bss->frame_buf);
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];
153 IWM_ERR(iwm, "Invalid band: %d\n", umac_bss->band);
157 freq = ieee80211_channel_to_frequency(umac_bss->channel);
158 channel = ieee80211_get_channel(wiphy, freq);
159 signal = umac_bss->rssi * 100;
161 if (!cfg80211_inform_bss_frame(wiphy, channel, mgmt,
162 le16_to_cpu(umac_bss->frame_len),
170 static int iwm_cfg80211_change_iface(struct wiphy *wiphy,
171 struct net_device *ndev,
172 enum nl80211_iftype type, u32 *flags,
173 struct vif_params *params)
175 struct wireless_dev *wdev;
176 struct iwm_priv *iwm;
179 wdev = ndev->ieee80211_ptr;
180 iwm = ndev_to_iwm(ndev);
181 old_mode = iwm->conf.mode;
184 case NL80211_IFTYPE_STATION:
185 iwm->conf.mode = UMAC_MODE_BSS;
187 case NL80211_IFTYPE_ADHOC:
188 iwm->conf.mode = UMAC_MODE_IBSS;
196 if ((old_mode == iwm->conf.mode) || !iwm->umac_profile)
199 iwm->umac_profile->mode = cpu_to_le32(iwm->conf.mode);
201 if (iwm->umac_profile_active) {
202 int ret = iwm_invalidate_mlme_profile(iwm);
204 IWM_ERR(iwm, "Couldn't invalidate profile\n");
210 static int iwm_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
211 struct cfg80211_scan_request *request)
213 struct iwm_priv *iwm = ndev_to_iwm(ndev);
216 if (!test_bit(IWM_STATUS_READY, &iwm->status)) {
217 IWM_ERR(iwm, "Scan while device is not ready\n");
221 if (test_bit(IWM_STATUS_SCANNING, &iwm->status)) {
222 IWM_ERR(iwm, "Scanning already\n");
226 if (test_bit(IWM_STATUS_SCAN_ABORTING, &iwm->status)) {
227 IWM_ERR(iwm, "Scanning being aborted\n");
231 set_bit(IWM_STATUS_SCANNING, &iwm->status);
233 ret = iwm_scan_ssids(iwm, request->ssids, request->n_ssids);
235 clear_bit(IWM_STATUS_SCANNING, &iwm->status);
239 iwm->scan_request = request;
243 static int iwm_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
245 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
247 if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
248 (iwm->conf.rts_threshold != wiphy->rts_threshold)) {
251 iwm->conf.rts_threshold = wiphy->rts_threshold;
253 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
255 iwm->conf.rts_threshold);
260 if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
261 (iwm->conf.frag_threshold != wiphy->frag_threshold)) {
264 iwm->conf.frag_threshold = wiphy->frag_threshold;
266 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX,
268 iwm->conf.frag_threshold);
276 static int iwm_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
277 struct cfg80211_ibss_params *params)
279 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
280 struct ieee80211_channel *chan = params->channel;
281 struct cfg80211_bss *bss;
283 if (!test_bit(IWM_STATUS_READY, &iwm->status))
286 /* UMAC doesn't support creating IBSS network with specified bssid.
287 * This should be removed after we have join only mode supported. */
291 bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
292 params->ssid, params->ssid_len);
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);
299 /* IBSS join only mode is not supported by UMAC ATM */
301 cfg80211_put_bss(bss);
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);
312 memcpy(&iwm->umac_profile->bssid[0], params->bssid, ETH_ALEN);
314 return iwm_send_mlme_profile(iwm);
317 static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
319 struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
321 if (iwm->umac_profile_active)
322 return iwm_invalidate_mlme_profile(iwm);
327 static 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,
335 struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
338 struct wireless_dev *wdev;
341 * We're trying to have the following memory
344 * +-------------------------+
346 * +-------------------------+
347 * | struct iwm_priv |
348 * +-------------------------+
349 * | bus private data |
350 * | (e.g. iwm_priv_sdio) |
351 * +-------------------------+
355 wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
357 dev_err(dev, "Couldn't allocate wireless device\n");
358 return ERR_PTR(-ENOMEM);
361 wdev->wiphy = wiphy_new(&iwm_cfg80211_ops,
362 sizeof(struct iwm_priv) + sizeof_bus);
364 dev_err(dev, "Couldn't allocate wiphy device\n");
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;
377 ret = wiphy_register(wdev->wiphy);
379 dev_err(dev, "Couldn't register wiphy device\n");
380 goto out_err_register;
386 wiphy_free(wdev->wiphy);
394 void iwm_wdev_free(struct iwm_priv *iwm)
396 struct wireless_dev *wdev = iwm_to_wdev(iwm);
401 wiphy_unregister(wdev->wiphy);
402 wiphy_free(wdev->wiphy);