xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/intersil/orinoco/cfg.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /* cfg80211 support
2*4882a593Smuzhiyun  *
3*4882a593Smuzhiyun  * See copyright notice in main.c
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun #include <linux/ieee80211.h>
6*4882a593Smuzhiyun #include <net/cfg80211.h>
7*4882a593Smuzhiyun #include "hw.h"
8*4882a593Smuzhiyun #include "main.h"
9*4882a593Smuzhiyun #include "orinoco.h"
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun #include "cfg.h"
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun /* Supported bitrates. Must agree with hw.c */
14*4882a593Smuzhiyun static struct ieee80211_rate orinoco_rates[] = {
15*4882a593Smuzhiyun 	{ .bitrate = 10 },
16*4882a593Smuzhiyun 	{ .bitrate = 20 },
17*4882a593Smuzhiyun 	{ .bitrate = 55 },
18*4882a593Smuzhiyun 	{ .bitrate = 110 },
19*4882a593Smuzhiyun };
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun static const void * const orinoco_wiphy_privid = &orinoco_wiphy_privid;
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun /* Called after orinoco_private is allocated. */
orinoco_wiphy_init(struct wiphy * wiphy)24*4882a593Smuzhiyun void orinoco_wiphy_init(struct wiphy *wiphy)
25*4882a593Smuzhiyun {
26*4882a593Smuzhiyun 	struct orinoco_private *priv = wiphy_priv(wiphy);
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 	wiphy->privid = orinoco_wiphy_privid;
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun 	set_wiphy_dev(wiphy, priv->dev);
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun /* Called after firmware is initialised */
orinoco_wiphy_register(struct wiphy * wiphy)34*4882a593Smuzhiyun int orinoco_wiphy_register(struct wiphy *wiphy)
35*4882a593Smuzhiyun {
36*4882a593Smuzhiyun 	struct orinoco_private *priv = wiphy_priv(wiphy);
37*4882a593Smuzhiyun 	int i, channels = 0;
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	if (priv->firmware_type == FIRMWARE_TYPE_AGERE)
40*4882a593Smuzhiyun 		wiphy->max_scan_ssids = 1;
41*4882a593Smuzhiyun 	else
42*4882a593Smuzhiyun 		wiphy->max_scan_ssids = 0;
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun 	wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun 	/* TODO: should we set if we only have demo ad-hoc?
47*4882a593Smuzhiyun 	 *       (priv->has_port3)
48*4882a593Smuzhiyun 	 */
49*4882a593Smuzhiyun 	if (priv->has_ibss)
50*4882a593Smuzhiyun 		wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun 	if (!priv->broken_monitor || force_monitor)
53*4882a593Smuzhiyun 		wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun 	priv->band.bitrates = orinoco_rates;
56*4882a593Smuzhiyun 	priv->band.n_bitrates = ARRAY_SIZE(orinoco_rates);
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	/* Only support channels allowed by the card EEPROM */
59*4882a593Smuzhiyun 	for (i = 0; i < NUM_CHANNELS; i++) {
60*4882a593Smuzhiyun 		if (priv->channel_mask & (1 << i)) {
61*4882a593Smuzhiyun 			priv->channels[i].center_freq =
62*4882a593Smuzhiyun 				ieee80211_channel_to_frequency(i + 1,
63*4882a593Smuzhiyun 							   NL80211_BAND_2GHZ);
64*4882a593Smuzhiyun 			channels++;
65*4882a593Smuzhiyun 		}
66*4882a593Smuzhiyun 	}
67*4882a593Smuzhiyun 	priv->band.channels = priv->channels;
68*4882a593Smuzhiyun 	priv->band.n_channels = channels;
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	wiphy->bands[NL80211_BAND_2GHZ] = &priv->band;
71*4882a593Smuzhiyun 	wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
72*4882a593Smuzhiyun 
73*4882a593Smuzhiyun 	i = 0;
74*4882a593Smuzhiyun 	if (priv->has_wep) {
75*4882a593Smuzhiyun 		priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP40;
76*4882a593Smuzhiyun 		i++;
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun 		if (priv->has_big_wep) {
79*4882a593Smuzhiyun 			priv->cipher_suites[i] = WLAN_CIPHER_SUITE_WEP104;
80*4882a593Smuzhiyun 			i++;
81*4882a593Smuzhiyun 		}
82*4882a593Smuzhiyun 	}
83*4882a593Smuzhiyun 	if (priv->has_wpa) {
84*4882a593Smuzhiyun 		priv->cipher_suites[i] = WLAN_CIPHER_SUITE_TKIP;
85*4882a593Smuzhiyun 		i++;
86*4882a593Smuzhiyun 	}
87*4882a593Smuzhiyun 	wiphy->cipher_suites = priv->cipher_suites;
88*4882a593Smuzhiyun 	wiphy->n_cipher_suites = i;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	wiphy->rts_threshold = priv->rts_thresh;
91*4882a593Smuzhiyun 	if (!priv->has_mwo)
92*4882a593Smuzhiyun 		wiphy->frag_threshold = priv->frag_thresh + 1;
93*4882a593Smuzhiyun 	wiphy->retry_short = priv->short_retry_limit;
94*4882a593Smuzhiyun 	wiphy->retry_long = priv->long_retry_limit;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	return wiphy_register(wiphy);
97*4882a593Smuzhiyun }
98*4882a593Smuzhiyun 
orinoco_change_vif(struct wiphy * wiphy,struct net_device * dev,enum nl80211_iftype type,struct vif_params * params)99*4882a593Smuzhiyun static int orinoco_change_vif(struct wiphy *wiphy, struct net_device *dev,
100*4882a593Smuzhiyun 			      enum nl80211_iftype type,
101*4882a593Smuzhiyun 			      struct vif_params *params)
102*4882a593Smuzhiyun {
103*4882a593Smuzhiyun 	struct orinoco_private *priv = wiphy_priv(wiphy);
104*4882a593Smuzhiyun 	int err = 0;
105*4882a593Smuzhiyun 	unsigned long lock;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	if (orinoco_lock(priv, &lock) != 0)
108*4882a593Smuzhiyun 		return -EBUSY;
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun 	switch (type) {
111*4882a593Smuzhiyun 	case NL80211_IFTYPE_ADHOC:
112*4882a593Smuzhiyun 		if (!priv->has_ibss && !priv->has_port3)
113*4882a593Smuzhiyun 			err = -EINVAL;
114*4882a593Smuzhiyun 		break;
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	case NL80211_IFTYPE_STATION:
117*4882a593Smuzhiyun 		break;
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	case NL80211_IFTYPE_MONITOR:
120*4882a593Smuzhiyun 		if (priv->broken_monitor && !force_monitor) {
121*4882a593Smuzhiyun 			wiphy_warn(wiphy,
122*4882a593Smuzhiyun 				   "Monitor mode support is buggy in this firmware, not enabling\n");
123*4882a593Smuzhiyun 			err = -EINVAL;
124*4882a593Smuzhiyun 		}
125*4882a593Smuzhiyun 		break;
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	default:
128*4882a593Smuzhiyun 		err = -EINVAL;
129*4882a593Smuzhiyun 	}
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	if (!err) {
132*4882a593Smuzhiyun 		priv->iw_mode = type;
133*4882a593Smuzhiyun 		set_port_type(priv);
134*4882a593Smuzhiyun 		err = orinoco_commit(priv);
135*4882a593Smuzhiyun 	}
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	orinoco_unlock(priv, &lock);
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	return err;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun 
orinoco_scan(struct wiphy * wiphy,struct cfg80211_scan_request * request)142*4882a593Smuzhiyun static int orinoco_scan(struct wiphy *wiphy,
143*4882a593Smuzhiyun 			struct cfg80211_scan_request *request)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun 	struct orinoco_private *priv = wiphy_priv(wiphy);
146*4882a593Smuzhiyun 	int err;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	if (!request)
149*4882a593Smuzhiyun 		return -EINVAL;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	if (priv->scan_request && priv->scan_request != request)
152*4882a593Smuzhiyun 		return -EBUSY;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	priv->scan_request = request;
155*4882a593Smuzhiyun 
156*4882a593Smuzhiyun 	err = orinoco_hw_trigger_scan(priv, request->ssids);
157*4882a593Smuzhiyun 	/* On error the we aren't processing the request */
158*4882a593Smuzhiyun 	if (err)
159*4882a593Smuzhiyun 		priv->scan_request = NULL;
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	return err;
162*4882a593Smuzhiyun }
163*4882a593Smuzhiyun 
orinoco_set_monitor_channel(struct wiphy * wiphy,struct cfg80211_chan_def * chandef)164*4882a593Smuzhiyun static int orinoco_set_monitor_channel(struct wiphy *wiphy,
165*4882a593Smuzhiyun 				       struct cfg80211_chan_def *chandef)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun 	struct orinoco_private *priv = wiphy_priv(wiphy);
168*4882a593Smuzhiyun 	int err = 0;
169*4882a593Smuzhiyun 	unsigned long flags;
170*4882a593Smuzhiyun 	int channel;
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	if (!chandef->chan)
173*4882a593Smuzhiyun 		return -EINVAL;
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT)
176*4882a593Smuzhiyun 		return -EINVAL;
177*4882a593Smuzhiyun 
178*4882a593Smuzhiyun 	if (chandef->chan->band != NL80211_BAND_2GHZ)
179*4882a593Smuzhiyun 		return -EINVAL;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	channel = ieee80211_frequency_to_channel(chandef->chan->center_freq);
182*4882a593Smuzhiyun 
183*4882a593Smuzhiyun 	if ((channel < 1) || (channel > NUM_CHANNELS) ||
184*4882a593Smuzhiyun 	     !(priv->channel_mask & (1 << (channel - 1))))
185*4882a593Smuzhiyun 		return -EINVAL;
186*4882a593Smuzhiyun 
187*4882a593Smuzhiyun 	if (orinoco_lock(priv, &flags) != 0)
188*4882a593Smuzhiyun 		return -EBUSY;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	priv->channel = channel;
191*4882a593Smuzhiyun 	if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
192*4882a593Smuzhiyun 		/* Fast channel change - no commit if successful */
193*4882a593Smuzhiyun 		struct hermes *hw = &priv->hw;
194*4882a593Smuzhiyun 		err = hw->ops->cmd_wait(hw, HERMES_CMD_TEST |
195*4882a593Smuzhiyun 					    HERMES_TEST_SET_CHANNEL,
196*4882a593Smuzhiyun 					channel, NULL);
197*4882a593Smuzhiyun 	}
198*4882a593Smuzhiyun 	orinoco_unlock(priv, &flags);
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	return err;
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun 
orinoco_set_wiphy_params(struct wiphy * wiphy,u32 changed)203*4882a593Smuzhiyun static int orinoco_set_wiphy_params(struct wiphy *wiphy, u32 changed)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun 	struct orinoco_private *priv = wiphy_priv(wiphy);
206*4882a593Smuzhiyun 	int frag_value = -1;
207*4882a593Smuzhiyun 	int rts_value = -1;
208*4882a593Smuzhiyun 	int err = 0;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	if (changed & WIPHY_PARAM_RETRY_SHORT) {
211*4882a593Smuzhiyun 		/* Setting short retry not supported */
212*4882a593Smuzhiyun 		err = -EINVAL;
213*4882a593Smuzhiyun 	}
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 	if (changed & WIPHY_PARAM_RETRY_LONG) {
216*4882a593Smuzhiyun 		/* Setting long retry not supported */
217*4882a593Smuzhiyun 		err = -EINVAL;
218*4882a593Smuzhiyun 	}
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 	if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
221*4882a593Smuzhiyun 		/* Set fragmentation */
222*4882a593Smuzhiyun 		if (priv->has_mwo) {
223*4882a593Smuzhiyun 			if (wiphy->frag_threshold == -1)
224*4882a593Smuzhiyun 				frag_value = 0;
225*4882a593Smuzhiyun 			else {
226*4882a593Smuzhiyun 				printk(KERN_WARNING "%s: Fixed fragmentation "
227*4882a593Smuzhiyun 				       "is not supported on this firmware. "
228*4882a593Smuzhiyun 				       "Using MWO robust instead.\n",
229*4882a593Smuzhiyun 				       priv->ndev->name);
230*4882a593Smuzhiyun 				frag_value = 1;
231*4882a593Smuzhiyun 			}
232*4882a593Smuzhiyun 		} else {
233*4882a593Smuzhiyun 			if (wiphy->frag_threshold == -1)
234*4882a593Smuzhiyun 				frag_value = 2346;
235*4882a593Smuzhiyun 			else if ((wiphy->frag_threshold < 257) ||
236*4882a593Smuzhiyun 				 (wiphy->frag_threshold > 2347))
237*4882a593Smuzhiyun 				err = -EINVAL;
238*4882a593Smuzhiyun 			else
239*4882a593Smuzhiyun 				/* cfg80211 value is 257-2347 (odd only)
240*4882a593Smuzhiyun 				 * orinoco rid has range 256-2346 (even only) */
241*4882a593Smuzhiyun 				frag_value = wiphy->frag_threshold & ~0x1;
242*4882a593Smuzhiyun 		}
243*4882a593Smuzhiyun 	}
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
246*4882a593Smuzhiyun 		/* Set RTS.
247*4882a593Smuzhiyun 		 *
248*4882a593Smuzhiyun 		 * Prism documentation suggests default of 2432,
249*4882a593Smuzhiyun 		 * and a range of 0-3000.
250*4882a593Smuzhiyun 		 *
251*4882a593Smuzhiyun 		 * Current implementation uses 2347 as the default and
252*4882a593Smuzhiyun 		 * the upper limit.
253*4882a593Smuzhiyun 		 */
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 		if (wiphy->rts_threshold == -1)
256*4882a593Smuzhiyun 			rts_value = 2347;
257*4882a593Smuzhiyun 		else if (wiphy->rts_threshold > 2347)
258*4882a593Smuzhiyun 			err = -EINVAL;
259*4882a593Smuzhiyun 		else
260*4882a593Smuzhiyun 			rts_value = wiphy->rts_threshold;
261*4882a593Smuzhiyun 	}
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	if (!err) {
264*4882a593Smuzhiyun 		unsigned long flags;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 		if (orinoco_lock(priv, &flags) != 0)
267*4882a593Smuzhiyun 			return -EBUSY;
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 		if (frag_value >= 0) {
270*4882a593Smuzhiyun 			if (priv->has_mwo)
271*4882a593Smuzhiyun 				priv->mwo_robust = frag_value;
272*4882a593Smuzhiyun 			else
273*4882a593Smuzhiyun 				priv->frag_thresh = frag_value;
274*4882a593Smuzhiyun 		}
275*4882a593Smuzhiyun 		if (rts_value >= 0)
276*4882a593Smuzhiyun 			priv->rts_thresh = rts_value;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 		err = orinoco_commit(priv);
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 		orinoco_unlock(priv, &flags);
281*4882a593Smuzhiyun 	}
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun 	return err;
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun const struct cfg80211_ops orinoco_cfg_ops = {
287*4882a593Smuzhiyun 	.change_virtual_intf = orinoco_change_vif,
288*4882a593Smuzhiyun 	.set_monitor_channel = orinoco_set_monitor_channel,
289*4882a593Smuzhiyun 	.scan = orinoco_scan,
290*4882a593Smuzhiyun 	.set_wiphy_params = orinoco_set_wiphy_params,
291*4882a593Smuzhiyun };
292