Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  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 
 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),
 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 
 80 static 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 
 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),
116         CHAN5G(216, 0),
117 };
118 
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,
124 };
125 
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,
131 };
132 
133 int 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 
170 static int iwm_cfg80211_change_iface(struct wiphy *wiphy, int ifindex,
171                                      enum nl80211_iftype type, u32 *flags,
172                                      struct vif_params *params)
173 {
174         struct net_device *ndev;
175         struct wireless_dev *wdev;
176         struct iwm_priv *iwm;
177         u32 old_mode;
178 
179         /* we're under RTNL */
180         ndev = __dev_get_by_index(&init_net, ifindex);
181         if (!ndev)
182                 return -ENODEV;
183 
184         wdev = ndev->ieee80211_ptr;
185         iwm = ndev_to_iwm(ndev);
186         old_mode = iwm->conf.mode;
187 
188         switch (type) {
189         case NL80211_IFTYPE_STATION:
190                 iwm->conf.mode = UMAC_MODE_BSS;
191                 break;
192         case NL80211_IFTYPE_ADHOC:
193                 iwm->conf.mode = UMAC_MODE_IBSS;
194                 break;
195         default:
196                 return -EOPNOTSUPP;
197         }
198 
199         wdev->iftype = type;
200 
201         if ((old_mode == iwm->conf.mode) || !iwm->umac_profile)
202                 return 0;
203 
204         iwm->umac_profile->mode = cpu_to_le32(iwm->conf.mode);
205 
206         if (iwm->umac_profile_active) {
207                 int ret = iwm_invalidate_mlme_profile(iwm);
208                 if (ret < 0)
209                         IWM_ERR(iwm, "Couldn't invalidate profile\n");
210         }
211 
212         return 0;
213 }
214 
215 static int iwm_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
216                              struct cfg80211_scan_request *request)
217 {
218         struct iwm_priv *iwm = ndev_to_iwm(ndev);
219         int ret;
220 
221         if (!test_bit(IWM_STATUS_READY, &iwm->status)) {
222                 IWM_ERR(iwm, "Scan while device is not ready\n");
223                 return -EIO;
224         }
225 
226         if (test_bit(IWM_STATUS_SCANNING, &iwm->status)) {
227                 IWM_ERR(iwm, "Scanning already\n");
228                 return -EAGAIN;
229         }
230 
231         if (test_bit(IWM_STATUS_SCAN_ABORTING, &iwm->status)) {
232                 IWM_ERR(iwm, "Scanning being aborted\n");
233                 return -EAGAIN;
234         }
235 
236         set_bit(IWM_STATUS_SCANNING, &iwm->status);
237 
238         ret = iwm_scan_ssids(iwm, request->ssids, request->n_ssids);
239         if (ret) {
240                 clear_bit(IWM_STATUS_SCANNING, &iwm->status);
241                 return ret;
242         }
243 
244         iwm->scan_request = request;
245         return 0;
246 }
247 
248 static int iwm_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
249 {
250         struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
251 
252         if (changed & WIPHY_PARAM_RTS_THRESHOLD &&
253             (iwm->conf.rts_threshold != wiphy->rts_threshold)) {
254                 int ret;
255 
256                 iwm->conf.rts_threshold = wiphy->rts_threshold;
257 
258                 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_CFG_FIX,
259                                              CFG_RTS_THRESHOLD,
260                                              iwm->conf.rts_threshold);
261                 if (ret < 0)
262                         return ret;
263         }
264 
265         if (changed & WIPHY_PARAM_FRAG_THRESHOLD &&
266             (iwm->conf.frag_threshold != wiphy->frag_threshold)) {
267                 int ret;
268 
269                 iwm->conf.frag_threshold = wiphy->frag_threshold;
270 
271                 ret = iwm_umac_set_config_fix(iwm, UMAC_PARAM_TBL_FA_CFG_FIX,
272                                              CFG_FRAG_THRESHOLD,
273                                              iwm->conf.frag_threshold);
274                 if (ret < 0)
275                         return ret;
276         }
277 
278         return 0;
279 }
280 
281 static int iwm_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
282                                   struct cfg80211_ibss_params *params)
283 {
284         struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
285         struct ieee80211_channel *chan = params->channel;
286         struct cfg80211_bss *bss;
287 
288         if (!test_bit(IWM_STATUS_READY, &iwm->status))
289                 return -EIO;
290 
291         /* UMAC doesn't support creating IBSS network with specified bssid.
292          * This should be removed after we have join only mode supported. */
293         if (params->bssid)
294                 return -EOPNOTSUPP;
295 
296         bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
297                                 params->ssid, params->ssid_len);
298         if (!bss) {
299                 iwm_scan_one_ssid(iwm, params->ssid, params->ssid_len);
300                 schedule_timeout_interruptible(2 * HZ);
301                 bss = cfg80211_get_ibss(iwm_to_wiphy(iwm), NULL,
302                                         params->ssid, params->ssid_len);
303         }
304         /* IBSS join only mode is not supported by UMAC ATM */
305         if (bss) {
306                 cfg80211_put_bss(bss);
307                 return -EOPNOTSUPP;
308         }
309 
310         iwm->channel = ieee80211_frequency_to_channel(chan->center_freq);
311         iwm->umac_profile->ibss.band = chan->band;
312         iwm->umac_profile->ibss.channel = iwm->channel;
313         iwm->umac_profile->ssid.ssid_len = params->ssid_len;
314         memcpy(iwm->umac_profile->ssid.ssid, params->ssid, params->ssid_len);
315 
316         if (params->bssid)
317                 memcpy(&iwm->umac_profile->bssid[0], params->bssid, ETH_ALEN);
318 
319         return iwm_send_mlme_profile(iwm);
320 }
321 
322 static int iwm_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
323 {
324         struct iwm_priv *iwm = wiphy_to_iwm(wiphy);
325 
326         if (iwm->umac_profile_active)
327                 return iwm_invalidate_mlme_profile(iwm);
328 
329         return 0;
330 }
331 
332 static struct cfg80211_ops iwm_cfg80211_ops = {
333         .change_virtual_intf = iwm_cfg80211_change_iface,
334         .scan = iwm_cfg80211_scan,
335         .set_wiphy_params = iwm_cfg80211_set_wiphy_params,
336         .join_ibss = iwm_cfg80211_join_ibss,
337         .leave_ibss = iwm_cfg80211_leave_ibss,
338 };
339 
340 struct wireless_dev *iwm_wdev_alloc(int sizeof_bus, struct device *dev)
341 {
342         int ret = 0;
343         struct wireless_dev *wdev;
344 
345         /*
346          * We're trying to have the following memory
347          * layout:
348          *
349          * +-------------------------+
350          * | struct wiphy            |
351          * +-------------------------+
352          * | struct iwm_priv         |
353          * +-------------------------+
354          * | bus private data        |
355          * | (e.g. iwm_priv_sdio)    |
356          * +-------------------------+
357          *
358          */
359 
360         wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
361         if (!wdev) {
362                 dev_err(dev, "Couldn't allocate wireless device\n");
363                 return ERR_PTR(-ENOMEM);
364         }
365 
366         wdev->wiphy = wiphy_new(&iwm_cfg80211_ops,
367                                 sizeof(struct iwm_priv) + sizeof_bus);
368         if (!wdev->wiphy) {
369                 dev_err(dev, "Couldn't allocate wiphy device\n");
370                 ret = -ENOMEM;
371                 goto out_err_new;
372         }
373 
374         set_wiphy_dev(wdev->wiphy, dev);
375         wdev->wiphy->max_scan_ssids = UMAC_WIFI_IF_PROBE_OPTION_MAX;
376         wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
377                                        BIT(NL80211_IFTYPE_ADHOC);
378         wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &iwm_band_2ghz;
379         wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &iwm_band_5ghz;
380         wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
381 
382         ret = wiphy_register(wdev->wiphy);
383         if (ret < 0) {
384                 dev_err(dev, "Couldn't register wiphy device\n");
385                 goto out_err_register;
386         }
387 
388         return wdev;
389 
390  out_err_register:
391         wiphy_free(wdev->wiphy);
392 
393  out_err_new:
394         kfree(wdev);
395 
396         return ERR_PTR(ret);
397 }
398 
399 void iwm_wdev_free(struct iwm_priv *iwm)
400 {
401         struct wireless_dev *wdev = iwm_to_wdev(iwm);
402 
403         if (!wdev)
404                 return;
405 
406         wiphy_unregister(wdev->wiphy);
407         wiphy_free(wdev->wiphy);
408         kfree(wdev);
409 }
410 
  This page was automatically generated by the LXR engine.