orinoco: enable cfg80211 "set_channel" operation
[safe/jmp/linux-2.6] / drivers / net / wireless / orinoco / cfg.c
1 /* cfg80211 support
2  *
3  * See copyright notice in main.c
4  */
5 #include <linux/ieee80211.h>
6 #include <net/cfg80211.h>
7 #include "hw.h"
8 #include "main.h"
9 #include "orinoco.h"
10
11 #include "cfg.h"
12
13 /* Supported bitrates. Must agree with hw.c */
14 static struct ieee80211_rate orinoco_rates[] = {
15         { .bitrate = 10 },
16         { .bitrate = 20 },
17         { .bitrate = 55 },
18         { .bitrate = 110 },
19 };
20
21 static const void * const orinoco_wiphy_privid = &orinoco_wiphy_privid;
22
23 /* Called after orinoco_private is allocated. */
24 void orinoco_wiphy_init(struct wiphy *wiphy)
25 {
26         struct orinoco_private *priv = wiphy_priv(wiphy);
27
28         wiphy->privid = orinoco_wiphy_privid;
29
30         set_wiphy_dev(wiphy, priv->dev);
31 }
32
33 /* Called after firmware is initialised */
34 int orinoco_wiphy_register(struct wiphy *wiphy)
35 {
36         struct orinoco_private *priv = wiphy_priv(wiphy);
37         int i, channels = 0;
38
39         if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
40                 wiphy->max_scan_ssids = 1;
41         else
42                 wiphy->max_scan_ssids = 0;
43
44         wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
45
46         /* TODO: should we set if we only have demo ad-hoc?
47          *       (priv->has_port3)
48          */
49         if (priv->has_ibss)
50                 wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
51
52         if (!priv->broken_monitor || force_monitor)
53                 wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
54
55         priv->band.bitrates = orinoco_rates;
56         priv->band.n_bitrates = ARRAY_SIZE(orinoco_rates);
57
58         /* Only support channels allowed by the card EEPROM */
59         for (i = 0; i < NUM_CHANNELS; i++) {
60                 if (priv->channel_mask & (1 << i)) {
61                         priv->channels[i].center_freq =
62                                 ieee80211_dsss_chan_to_freq(i+1);
63                         channels++;
64                 }
65         }
66         priv->band.channels = priv->channels;
67         priv->band.n_channels = channels;
68
69         wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
70         wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
71
72         i = 0;
73         if (priv->has_wep) {
74                 priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP40;
75                 i++;
76
77                 if (priv->has_big_wep) {
78                         priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP104;
79                         i++;
80                 }
81         }
82         if (priv->has_wpa) {
83                 priv->cipher_suites[i] = WLAN_CIPHER_SUITE_TKIP;
84                 i++;
85         }
86         wiphy->cipher_suites = priv->cipher_suites;
87         wiphy->n_cipher_suites = i;
88
89         wiphy->rts_threshold = priv->rts_thresh;
90         if (!priv->has_mwo)
91                 wiphy->frag_threshold = priv->frag_thresh;
92
93         return wiphy_register(wiphy);
94 }
95
96 static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev,
97                               enum nl80211_iftype type, u32 *flags,
98                               struct vif_params *params)
99 {
100         struct orinoco_private *priv = wiphy_priv(wiphy);
101         int err = 0;
102         unsigned long lock;
103
104         if (orinoco_lock(priv, &lock) != 0)
105                 return -EBUSY;
106
107         switch (type) {
108         case NL80211_IFTYPE_ADHOC:
109                 if (!priv->has_ibss && !priv->has_port3)
110                         err = -EINVAL;
111                 break;
112
113         case NL80211_IFTYPE_STATION:
114                 break;
115
116         case NL80211_IFTYPE_MONITOR:
117                 if (priv->broken_monitor && !force_monitor) {
118                         printk(KERN_WARNING "%s: Monitor mode support is "
119                                "buggy in this firmware, not enabling\n",
120                                wiphy_name(wiphy));
121                         err = -EINVAL;
122                 }
123                 break;
124
125         default:
126                 err = -EINVAL;
127         }
128
129         if (!err) {
130                 priv->iw_mode = type;
131                 set_port_type(priv);
132                 err = orinoco_commit(priv);
133         }
134
135         orinoco_unlock(priv, &lock);
136
137         return err;
138 }
139
140 static int orinoco_scan(struct wiphy *wiphy, struct net_device *dev,
141                         struct cfg80211_scan_request *request)
142 {
143         struct orinoco_private *priv = wiphy_priv(wiphy);
144         int err;
145
146         if (!request)
147                 return -EINVAL;
148
149         if (priv->scan_request && priv->scan_request != request)
150                 return -EBUSY;
151
152         priv->scan_request = request;
153
154         err = orinoco_hw_trigger_scan(priv, request->ssids);
155
156         return err;
157 }
158
159 static int orinoco_set_channel(struct wiphy *wiphy,
160                         struct ieee80211_channel *chan,
161                         enum nl80211_channel_type channel_type)
162 {
163         struct orinoco_private *priv = wiphy_priv(wiphy);
164         int err = 0;
165         unsigned long flags;
166         int channel;
167
168         if (!chan)
169                 return -EINVAL;
170
171         if (channel_type != NL80211_CHAN_NO_HT)
172                 return -EINVAL;
173
174         if (chan->band != IEEE80211_BAND_2GHZ)
175                 return -EINVAL;
176
177         channel = ieee80211_freq_to_dsss_chan(chan->center_freq);
178
179         if ((channel < 1) || (channel > NUM_CHANNELS) ||
180              !(priv->channel_mask & (1 << (channel-1))))
181                 return -EINVAL;
182
183         if (orinoco_lock(priv, &flags) != 0)
184                 return -EBUSY;
185
186         priv->channel = channel;
187         if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
188                 /* Fast channel change - no commit if successful */
189                 hermes_t *hw = &priv->hw;
190                 err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
191                                             HERMES_TEST_SET_CHANNEL,
192                                         channel, NULL);
193         }
194         orinoco_unlock(priv, &flags);
195
196         return err;
197 }
198
199 const struct cfg80211_ops orinoco_cfg_ops = {
200         .change_virtual_intf = orinoco_change_vif,
201         .set_channel = orinoco_set_channel,
202         .scan = orinoco_scan,
203 };