Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-next-2.6
[linux-2.6-microblaze.git] / drivers / net / wireless / orinoco / hw.c
1 /* Encapsulate basic setting changes and retrieval on Hermes hardware
2  *
3  * See copyright notice in main.c
4  */
5 #include <linux/kernel.h>
6 #include <linux/device.h>
7 #include <linux/if_arp.h>
8 #include <linux/ieee80211.h>
9 #include <linux/wireless.h>
10 #include <net/cfg80211.h>
11 #include "hermes.h"
12 #include "hermes_rid.h"
13 #include "orinoco.h"
14
15 #include "hw.h"
16
17 #define SYMBOL_MAX_VER_LEN      (14)
18
19 /* Symbol firmware has a bug allocating buffers larger than this */
20 #define TX_NICBUF_SIZE_BUG      1585
21
22 /********************************************************************/
23 /* Data tables                                                      */
24 /********************************************************************/
25
26 /* This tables gives the actual meanings of the bitrate IDs returned
27  * by the firmware. */
28 static const struct {
29         int bitrate; /* in 100s of kilobits */
30         int automatic;
31         u16 agere_txratectrl;
32         u16 intersil_txratectrl;
33 } bitrate_table[] = {
34         {110, 1,  3, 15}, /* Entry 0 is the default */
35         {10,  0,  1,  1},
36         {10,  1,  1,  1},
37         {20,  0,  2,  2},
38         {20,  1,  6,  3},
39         {55,  0,  4,  4},
40         {55,  1,  7,  7},
41         {110, 0,  5,  8},
42 };
43 #define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table)
44
45 /* Firmware version encoding */
46 struct comp_id {
47         u16 id, variant, major, minor;
48 } __attribute__ ((packed));
49
50 static inline fwtype_t determine_firmware_type(struct comp_id *nic_id)
51 {
52         if (nic_id->id < 0x8000)
53                 return FIRMWARE_TYPE_AGERE;
54         else if (nic_id->id == 0x8000 && nic_id->major == 0)
55                 return FIRMWARE_TYPE_SYMBOL;
56         else
57                 return FIRMWARE_TYPE_INTERSIL;
58 }
59
60 /* Set priv->firmware type, determine firmware properties
61  * This function can be called before we have registerred with netdev,
62  * so all errors go out with dev_* rather than printk
63  */
64 int determine_fw_capabilities(struct orinoco_private *priv)
65 {
66         struct device *dev = priv->dev;
67         hermes_t *hw = &priv->hw;
68         int err;
69         struct comp_id nic_id, sta_id;
70         unsigned int firmver;
71         char tmp[SYMBOL_MAX_VER_LEN+1] __attribute__((aligned(2)));
72
73         /* Get the hardware version */
74         err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_NICID, &nic_id);
75         if (err) {
76                 dev_err(dev, "Cannot read hardware identity: error %d\n",
77                         err);
78                 return err;
79         }
80
81         le16_to_cpus(&nic_id.id);
82         le16_to_cpus(&nic_id.variant);
83         le16_to_cpus(&nic_id.major);
84         le16_to_cpus(&nic_id.minor);
85         dev_info(dev, "Hardware identity %04x:%04x:%04x:%04x\n",
86                  nic_id.id, nic_id.variant, nic_id.major, nic_id.minor);
87
88         priv->firmware_type = determine_firmware_type(&nic_id);
89
90         /* Get the firmware version */
91         err = HERMES_READ_RECORD(hw, USER_BAP, HERMES_RID_STAID, &sta_id);
92         if (err) {
93                 dev_err(dev, "Cannot read station identity: error %d\n",
94                         err);
95                 return err;
96         }
97
98         le16_to_cpus(&sta_id.id);
99         le16_to_cpus(&sta_id.variant);
100         le16_to_cpus(&sta_id.major);
101         le16_to_cpus(&sta_id.minor);
102         dev_info(dev, "Station identity  %04x:%04x:%04x:%04x\n",
103                  sta_id.id, sta_id.variant, sta_id.major, sta_id.minor);
104
105         switch (sta_id.id) {
106         case 0x15:
107                 dev_err(dev, "Primary firmware is active\n");
108                 return -ENODEV;
109         case 0x14b:
110                 dev_err(dev, "Tertiary firmware is active\n");
111                 return -ENODEV;
112         case 0x1f:      /* Intersil, Agere, Symbol Spectrum24 */
113         case 0x21:      /* Symbol Spectrum24 Trilogy */
114                 break;
115         default:
116                 dev_notice(dev, "Unknown station ID, please report\n");
117                 break;
118         }
119
120         /* Default capabilities */
121         priv->has_sensitivity = 1;
122         priv->has_mwo = 0;
123         priv->has_preamble = 0;
124         priv->has_port3 = 1;
125         priv->has_ibss = 1;
126         priv->has_wep = 0;
127         priv->has_big_wep = 0;
128         priv->has_alt_txcntl = 0;
129         priv->has_ext_scan = 0;
130         priv->has_wpa = 0;
131         priv->do_fw_download = 0;
132
133         /* Determine capabilities from the firmware version */
134         switch (priv->firmware_type) {
135         case FIRMWARE_TYPE_AGERE:
136                 /* Lucent Wavelan IEEE, Lucent Orinoco, Cabletron RoamAbout,
137                    ELSA, Melco, HP, IBM, Dell 1150, Compaq 110/210 */
138                 snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
139                          "Lucent/Agere %d.%02d", sta_id.major, sta_id.minor);
140
141                 firmver = ((unsigned long)sta_id.major << 16) | sta_id.minor;
142
143                 priv->has_ibss = (firmver >= 0x60006);
144                 priv->has_wep = (firmver >= 0x40020);
145                 priv->has_big_wep = 1; /* FIXME: this is wrong - how do we tell
146                                           Gold cards from the others? */
147                 priv->has_mwo = (firmver >= 0x60000);
148                 priv->has_pm = (firmver >= 0x40020); /* Don't work in 7.52 ? */
149                 priv->ibss_port = 1;
150                 priv->has_hostscan = (firmver >= 0x8000a);
151                 priv->do_fw_download = 1;
152                 priv->broken_monitor = (firmver >= 0x80000);
153                 priv->has_alt_txcntl = (firmver >= 0x90000); /* All 9.x ? */
154                 priv->has_ext_scan = (firmver >= 0x90000); /* All 9.x ? */
155                 priv->has_wpa = (firmver >= 0x9002a);
156                 /* Tested with Agere firmware :
157                  *      1.16 ; 4.08 ; 4.52 ; 6.04 ; 6.16 ; 7.28 => Jean II
158                  * Tested CableTron firmware : 4.32 => Anton */
159                 break;
160         case FIRMWARE_TYPE_SYMBOL:
161                 /* Symbol , 3Com AirConnect, Intel, Ericsson WLAN */
162                 /* Intel MAC : 00:02:B3:* */
163                 /* 3Com MAC : 00:50:DA:* */
164                 memset(tmp, 0, sizeof(tmp));
165                 /* Get the Symbol firmware version */
166                 err = hermes_read_ltv(hw, USER_BAP,
167                                       HERMES_RID_SECONDARYVERSION_SYMBOL,
168                                       SYMBOL_MAX_VER_LEN, NULL, &tmp);
169                 if (err) {
170                         dev_warn(dev, "Error %d reading Symbol firmware info. "
171                                  "Wildly guessing capabilities...\n", err);
172                         firmver = 0;
173                         tmp[0] = '\0';
174                 } else {
175                         /* The firmware revision is a string, the format is
176                          * something like : "V2.20-01".
177                          * Quick and dirty parsing... - Jean II
178                          */
179                         firmver = ((tmp[1] - '0') << 16)
180                                 | ((tmp[3] - '0') << 12)
181                                 | ((tmp[4] - '0') << 8)
182                                 | ((tmp[6] - '0') << 4)
183                                 | (tmp[7] - '0');
184
185                         tmp[SYMBOL_MAX_VER_LEN] = '\0';
186                 }
187
188                 snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
189                          "Symbol %s", tmp);
190
191                 priv->has_ibss = (firmver >= 0x20000);
192                 priv->has_wep = (firmver >= 0x15012);
193                 priv->has_big_wep = (firmver >= 0x20000);
194                 priv->has_pm = (firmver >= 0x20000 && firmver < 0x22000) ||
195                                (firmver >= 0x29000 && firmver < 0x30000) ||
196                                firmver >= 0x31000;
197                 priv->has_preamble = (firmver >= 0x20000);
198                 priv->ibss_port = 4;
199
200                 /* Symbol firmware is found on various cards, but
201                  * there has been no attempt to check firmware
202                  * download on non-spectrum_cs based cards.
203                  *
204                  * Given that the Agere firmware download works
205                  * differently, we should avoid doing a firmware
206                  * download with the Symbol algorithm on non-spectrum
207                  * cards.
208                  *
209                  * For now we can identify a spectrum_cs based card
210                  * because it has a firmware reset function.
211                  */
212                 priv->do_fw_download = (priv->stop_fw != NULL);
213
214                 priv->broken_disableport = (firmver == 0x25013) ||
215                                 (firmver >= 0x30000 && firmver <= 0x31000);
216                 priv->has_hostscan = (firmver >= 0x31001) ||
217                                      (firmver >= 0x29057 && firmver < 0x30000);
218                 /* Tested with Intel firmware : 0x20015 => Jean II */
219                 /* Tested with 3Com firmware : 0x15012 & 0x22001 => Jean II */
220                 break;
221         case FIRMWARE_TYPE_INTERSIL:
222                 /* D-Link, Linksys, Adtron, ZoomAir, and many others...
223                  * Samsung, Compaq 100/200 and Proxim are slightly
224                  * different and less well tested */
225                 /* D-Link MAC : 00:40:05:* */
226                 /* Addtron MAC : 00:90:D1:* */
227                 snprintf(priv->fw_name, sizeof(priv->fw_name) - 1,
228                          "Intersil %d.%d.%d", sta_id.major, sta_id.minor,
229                          sta_id.variant);
230
231                 firmver = ((unsigned long)sta_id.major << 16) |
232                         ((unsigned long)sta_id.minor << 8) | sta_id.variant;
233
234                 priv->has_ibss = (firmver >= 0x000700); /* FIXME */
235                 priv->has_big_wep = priv->has_wep = (firmver >= 0x000800);
236                 priv->has_pm = (firmver >= 0x000700);
237                 priv->has_hostscan = (firmver >= 0x010301);
238
239                 if (firmver >= 0x000800)
240                         priv->ibss_port = 0;
241                 else {
242                         dev_notice(dev, "Intersil firmware earlier than v0.8.x"
243                                    " - several features not supported\n");
244                         priv->ibss_port = 1;
245                 }
246                 break;
247         }
248         dev_info(dev, "Firmware determined as %s\n", priv->fw_name);
249
250         return 0;
251 }
252
253 /* Read settings from EEPROM into our private structure.
254  * MAC address gets dropped into callers buffer
255  * Can be called before netdev registration.
256  */
257 int orinoco_hw_read_card_settings(struct orinoco_private *priv, u8 *dev_addr)
258 {
259         struct device *dev = priv->dev;
260         struct hermes_idstring nickbuf;
261         hermes_t *hw = &priv->hw;
262         int len;
263         int err;
264         u16 reclen;
265
266         /* Get the MAC address */
267         err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
268                               ETH_ALEN, NULL, dev_addr);
269         if (err) {
270                 dev_warn(dev, "Failed to read MAC address!\n");
271                 goto out;
272         }
273
274         dev_dbg(dev, "MAC address %pM\n", dev_addr);
275
276         /* Get the station name */
277         err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
278                               sizeof(nickbuf), &reclen, &nickbuf);
279         if (err) {
280                 dev_err(dev, "failed to read station name\n");
281                 goto out;
282         }
283         if (nickbuf.len)
284                 len = min(IW_ESSID_MAX_SIZE, (int)le16_to_cpu(nickbuf.len));
285         else
286                 len = min(IW_ESSID_MAX_SIZE, 2 * reclen);
287         memcpy(priv->nick, &nickbuf.val, len);
288         priv->nick[len] = '\0';
289
290         dev_dbg(dev, "Station name \"%s\"\n", priv->nick);
291
292         /* Get allowed channels */
293         err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CHANNELLIST,
294                                   &priv->channel_mask);
295         if (err) {
296                 dev_err(dev, "Failed to read channel list!\n");
297                 goto out;
298         }
299
300         /* Get initial AP density */
301         err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE,
302                                   &priv->ap_density);
303         if (err || priv->ap_density < 1 || priv->ap_density > 3)
304                 priv->has_sensitivity = 0;
305
306         /* Get initial RTS threshold */
307         err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
308                                   &priv->rts_thresh);
309         if (err) {
310                 dev_err(dev, "Failed to read RTS threshold!\n");
311                 goto out;
312         }
313
314         /* Get initial fragmentation settings */
315         if (priv->has_mwo)
316                 err = hermes_read_wordrec(hw, USER_BAP,
317                                           HERMES_RID_CNFMWOROBUST_AGERE,
318                                           &priv->mwo_robust);
319         else
320                 err = hermes_read_wordrec(hw, USER_BAP,
321                                           HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
322                                           &priv->frag_thresh);
323         if (err) {
324                 dev_err(dev, "Failed to read fragmentation settings!\n");
325                 goto out;
326         }
327
328         /* Power management setup */
329         if (priv->has_pm) {
330                 priv->pm_on = 0;
331                 priv->pm_mcast = 1;
332                 err = hermes_read_wordrec(hw, USER_BAP,
333                                           HERMES_RID_CNFMAXSLEEPDURATION,
334                                           &priv->pm_period);
335                 if (err) {
336                         dev_err(dev, "Failed to read power management "
337                                 "period!\n");
338                         goto out;
339                 }
340                 err = hermes_read_wordrec(hw, USER_BAP,
341                                           HERMES_RID_CNFPMHOLDOVERDURATION,
342                                           &priv->pm_timeout);
343                 if (err) {
344                         dev_err(dev, "Failed to read power management "
345                                 "timeout!\n");
346                         goto out;
347                 }
348         }
349
350         /* Preamble setup */
351         if (priv->has_preamble) {
352                 err = hermes_read_wordrec(hw, USER_BAP,
353                                           HERMES_RID_CNFPREAMBLE_SYMBOL,
354                                           &priv->preamble);
355         }
356
357 out:
358         return err;
359 }
360
361 /* Can be called before netdev registration */
362 int orinoco_hw_allocate_fid(struct orinoco_private *priv)
363 {
364         struct device *dev = priv->dev;
365         struct hermes *hw = &priv->hw;
366         int err;
367
368         err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
369         if (err == -EIO && priv->nicbuf_size > TX_NICBUF_SIZE_BUG) {
370                 /* Try workaround for old Symbol firmware bug */
371                 priv->nicbuf_size = TX_NICBUF_SIZE_BUG;
372                 err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid);
373
374                 dev_warn(dev, "Firmware ALLOC bug detected "
375                          "(old Symbol firmware?). Work around %s\n",
376                          err ? "failed!" : "ok.");
377         }
378
379         return err;
380 }
381
382 int orinoco_get_bitratemode(int bitrate, int automatic)
383 {
384         int ratemode = -1;
385         int i;
386
387         if ((bitrate != 10) && (bitrate != 20) &&
388             (bitrate != 55) && (bitrate != 110))
389                 return ratemode;
390
391         for (i = 0; i < BITRATE_TABLE_SIZE; i++) {
392                 if ((bitrate_table[i].bitrate == bitrate) &&
393                     (bitrate_table[i].automatic == automatic)) {
394                         ratemode = i;
395                         break;
396                 }
397         }
398         return ratemode;
399 }
400
401 void orinoco_get_ratemode_cfg(int ratemode, int *bitrate, int *automatic)
402 {
403         BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE));
404
405         *bitrate = bitrate_table[ratemode].bitrate * 100000;
406         *automatic = bitrate_table[ratemode].automatic;
407 }
408
409 int orinoco_hw_program_rids(struct orinoco_private *priv)
410 {
411         struct net_device *dev = priv->ndev;
412         struct wireless_dev *wdev = netdev_priv(dev);
413         hermes_t *hw = &priv->hw;
414         int err;
415         struct hermes_idstring idbuf;
416
417         /* Set the MAC address */
418         err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNMACADDR,
419                                HERMES_BYTES_TO_RECLEN(ETH_ALEN), dev->dev_addr);
420         if (err) {
421                 printk(KERN_ERR "%s: Error %d setting MAC address\n",
422                        dev->name, err);
423                 return err;
424         }
425
426         /* Set up the link mode */
427         err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE,
428                                    priv->port_type);
429         if (err) {
430                 printk(KERN_ERR "%s: Error %d setting port type\n",
431                        dev->name, err);
432                 return err;
433         }
434         /* Set the channel/frequency */
435         if (priv->channel != 0 && priv->iw_mode != NL80211_IFTYPE_STATION) {
436                 err = hermes_write_wordrec(hw, USER_BAP,
437                                            HERMES_RID_CNFOWNCHANNEL,
438                                            priv->channel);
439                 if (err) {
440                         printk(KERN_ERR "%s: Error %d setting channel %d\n",
441                                dev->name, err, priv->channel);
442                         return err;
443                 }
444         }
445
446         if (priv->has_ibss) {
447                 u16 createibss;
448
449                 if ((strlen(priv->desired_essid) == 0) && (priv->createibss)) {
450                         printk(KERN_WARNING "%s: This firmware requires an "
451                                "ESSID in IBSS-Ad-Hoc mode.\n", dev->name);
452                         /* With wvlan_cs, in this case, we would crash.
453                          * hopefully, this driver will behave better...
454                          * Jean II */
455                         createibss = 0;
456                 } else {
457                         createibss = priv->createibss;
458                 }
459
460                 err = hermes_write_wordrec(hw, USER_BAP,
461                                            HERMES_RID_CNFCREATEIBSS,
462                                            createibss);
463                 if (err) {
464                         printk(KERN_ERR "%s: Error %d setting CREATEIBSS\n",
465                                dev->name, err);
466                         return err;
467                 }
468         }
469
470         /* Set the desired BSSID */
471         err = __orinoco_hw_set_wap(priv);
472         if (err) {
473                 printk(KERN_ERR "%s: Error %d setting AP address\n",
474                        dev->name, err);
475                 return err;
476         }
477
478         /* Set the desired ESSID */
479         idbuf.len = cpu_to_le16(strlen(priv->desired_essid));
480         memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val));
481         /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */
482         err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID,
483                         HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
484                         &idbuf);
485         if (err) {
486                 printk(KERN_ERR "%s: Error %d setting OWNSSID\n",
487                        dev->name, err);
488                 return err;
489         }
490         err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID,
491                         HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2),
492                         &idbuf);
493         if (err) {
494                 printk(KERN_ERR "%s: Error %d setting DESIREDSSID\n",
495                        dev->name, err);
496                 return err;
497         }
498
499         /* Set the station name */
500         idbuf.len = cpu_to_le16(strlen(priv->nick));
501         memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val));
502         err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME,
503                                HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2),
504                                &idbuf);
505         if (err) {
506                 printk(KERN_ERR "%s: Error %d setting nickname\n",
507                        dev->name, err);
508                 return err;
509         }
510
511         /* Set AP density */
512         if (priv->has_sensitivity) {
513                 err = hermes_write_wordrec(hw, USER_BAP,
514                                            HERMES_RID_CNFSYSTEMSCALE,
515                                            priv->ap_density);
516                 if (err) {
517                         printk(KERN_WARNING "%s: Error %d setting SYSTEMSCALE. "
518                                "Disabling sensitivity control\n",
519                                dev->name, err);
520
521                         priv->has_sensitivity = 0;
522                 }
523         }
524
525         /* Set RTS threshold */
526         err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD,
527                                    priv->rts_thresh);
528         if (err) {
529                 printk(KERN_ERR "%s: Error %d setting RTS threshold\n",
530                        dev->name, err);
531                 return err;
532         }
533
534         /* Set fragmentation threshold or MWO robustness */
535         if (priv->has_mwo)
536                 err = hermes_write_wordrec(hw, USER_BAP,
537                                            HERMES_RID_CNFMWOROBUST_AGERE,
538                                            priv->mwo_robust);
539         else
540                 err = hermes_write_wordrec(hw, USER_BAP,
541                                            HERMES_RID_CNFFRAGMENTATIONTHRESHOLD,
542                                            priv->frag_thresh);
543         if (err) {
544                 printk(KERN_ERR "%s: Error %d setting fragmentation\n",
545                        dev->name, err);
546                 return err;
547         }
548
549         /* Set bitrate */
550         err = __orinoco_hw_set_bitrate(priv);
551         if (err) {
552                 printk(KERN_ERR "%s: Error %d setting bitrate\n",
553                        dev->name, err);
554                 return err;
555         }
556
557         /* Set power management */
558         if (priv->has_pm) {
559                 err = hermes_write_wordrec(hw, USER_BAP,
560                                            HERMES_RID_CNFPMENABLED,
561                                            priv->pm_on);
562                 if (err) {
563                         printk(KERN_ERR "%s: Error %d setting up PM\n",
564                                dev->name, err);
565                         return err;
566                 }
567
568                 err = hermes_write_wordrec(hw, USER_BAP,
569                                            HERMES_RID_CNFMULTICASTRECEIVE,
570                                            priv->pm_mcast);
571                 if (err) {
572                         printk(KERN_ERR "%s: Error %d setting up PM\n",
573                                dev->name, err);
574                         return err;
575                 }
576                 err = hermes_write_wordrec(hw, USER_BAP,
577                                            HERMES_RID_CNFMAXSLEEPDURATION,
578                                            priv->pm_period);
579                 if (err) {
580                         printk(KERN_ERR "%s: Error %d setting up PM\n",
581                                dev->name, err);
582                         return err;
583                 }
584                 err = hermes_write_wordrec(hw, USER_BAP,
585                                            HERMES_RID_CNFPMHOLDOVERDURATION,
586                                            priv->pm_timeout);
587                 if (err) {
588                         printk(KERN_ERR "%s: Error %d setting up PM\n",
589                                dev->name, err);
590                         return err;
591                 }
592         }
593
594         /* Set preamble - only for Symbol so far... */
595         if (priv->has_preamble) {
596                 err = hermes_write_wordrec(hw, USER_BAP,
597                                            HERMES_RID_CNFPREAMBLE_SYMBOL,
598                                            priv->preamble);
599                 if (err) {
600                         printk(KERN_ERR "%s: Error %d setting preamble\n",
601                                dev->name, err);
602                         return err;
603                 }
604         }
605
606         /* Set up encryption */
607         if (priv->has_wep || priv->has_wpa) {
608                 err = __orinoco_hw_setup_enc(priv);
609                 if (err) {
610                         printk(KERN_ERR "%s: Error %d activating encryption\n",
611                                dev->name, err);
612                         return err;
613                 }
614         }
615
616         if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
617                 /* Enable monitor mode */
618                 dev->type = ARPHRD_IEEE80211;
619                 err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
620                                             HERMES_TEST_MONITOR, 0, NULL);
621         } else {
622                 /* Disable monitor mode */
623                 dev->type = ARPHRD_ETHER;
624                 err = hermes_docmd_wait(hw, HERMES_CMD_TEST |
625                                             HERMES_TEST_STOP, 0, NULL);
626         }
627         if (err)
628                 return err;
629
630         /* Reset promiscuity / multicast*/
631         priv->promiscuous = 0;
632         priv->mc_count = 0;
633
634         /* Record mode change */
635         wdev->iftype = priv->iw_mode;
636
637         return 0;
638 }
639
640 /* Get tsc from the firmware */
641 int orinoco_hw_get_tkip_iv(struct orinoco_private *priv, int key, u8 *tsc)
642 {
643         hermes_t *hw = &priv->hw;
644         int err = 0;
645         u8 tsc_arr[4][ORINOCO_SEQ_LEN];
646
647         if ((key < 0) || (key >= 4))
648                 return -EINVAL;
649
650         err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_TKIP_IV,
651                               sizeof(tsc_arr), NULL, &tsc_arr);
652         if (!err)
653                 memcpy(tsc, &tsc_arr[key][0], sizeof(tsc_arr[0]));
654
655         return err;
656 }
657
658 int __orinoco_hw_set_bitrate(struct orinoco_private *priv)
659 {
660         hermes_t *hw = &priv->hw;
661         int ratemode = priv->bitratemode;
662         int err = 0;
663
664         if (ratemode >= BITRATE_TABLE_SIZE) {
665                 printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n",
666                        priv->ndev->name, ratemode);
667                 return -EINVAL;
668         }
669
670         switch (priv->firmware_type) {
671         case FIRMWARE_TYPE_AGERE:
672                 err = hermes_write_wordrec(hw, USER_BAP,
673                                 HERMES_RID_CNFTXRATECONTROL,
674                                 bitrate_table[ratemode].agere_txratectrl);
675                 break;
676         case FIRMWARE_TYPE_INTERSIL:
677         case FIRMWARE_TYPE_SYMBOL:
678                 err = hermes_write_wordrec(hw, USER_BAP,
679                                 HERMES_RID_CNFTXRATECONTROL,
680                                 bitrate_table[ratemode].intersil_txratectrl);
681                 break;
682         default:
683                 BUG();
684         }
685
686         return err;
687 }
688
689 int orinoco_hw_get_act_bitrate(struct orinoco_private *priv, int *bitrate)
690 {
691         hermes_t *hw = &priv->hw;
692         int i;
693         int err = 0;
694         u16 val;
695
696         err = hermes_read_wordrec(hw, USER_BAP,
697                                   HERMES_RID_CURRENTTXRATE, &val);
698         if (err)
699                 return err;
700
701         switch (priv->firmware_type) {
702         case FIRMWARE_TYPE_AGERE: /* Lucent style rate */
703                 /* Note : in Lucent firmware, the return value of
704                  * HERMES_RID_CURRENTTXRATE is the bitrate in Mb/s,
705                  * and therefore is totally different from the
706                  * encoding of HERMES_RID_CNFTXRATECONTROL.
707                  * Don't forget that 6Mb/s is really 5.5Mb/s */
708                 if (val == 6)
709                         *bitrate = 5500000;
710                 else
711                         *bitrate = val * 1000000;
712                 break;
713         case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */
714         case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */
715                 for (i = 0; i < BITRATE_TABLE_SIZE; i++)
716                         if (bitrate_table[i].intersil_txratectrl == val)
717                                 break;
718
719                 if (i >= BITRATE_TABLE_SIZE)
720                         printk(KERN_INFO "%s: Unable to determine current bitrate (0x%04hx)\n",
721                                priv->ndev->name, val);
722
723                 *bitrate = bitrate_table[i].bitrate * 100000;
724                 break;
725         default:
726                 BUG();
727         }
728
729         return err;
730 }
731
732 /* Set fixed AP address */
733 int __orinoco_hw_set_wap(struct orinoco_private *priv)
734 {
735         int roaming_flag;
736         int err = 0;
737         hermes_t *hw = &priv->hw;
738
739         switch (priv->firmware_type) {
740         case FIRMWARE_TYPE_AGERE:
741                 /* not supported */
742                 break;
743         case FIRMWARE_TYPE_INTERSIL:
744                 if (priv->bssid_fixed)
745                         roaming_flag = 2;
746                 else
747                         roaming_flag = 1;
748
749                 err = hermes_write_wordrec(hw, USER_BAP,
750                                            HERMES_RID_CNFROAMINGMODE,
751                                            roaming_flag);
752                 break;
753         case FIRMWARE_TYPE_SYMBOL:
754                 err = HERMES_WRITE_RECORD(hw, USER_BAP,
755                                           HERMES_RID_CNFMANDATORYBSSID_SYMBOL,
756                                           &priv->desired_bssid);
757                 break;
758         }
759         return err;
760 }
761
762 /* Change the WEP keys and/or the current keys.  Can be called
763  * either from __orinoco_hw_setup_enc() or directly from
764  * orinoco_ioctl_setiwencode().  In the later case the association
765  * with the AP is not broken (if the firmware can handle it),
766  * which is needed for 802.1x implementations. */
767 int __orinoco_hw_setup_wepkeys(struct orinoco_private *priv)
768 {
769         hermes_t *hw = &priv->hw;
770         int err = 0;
771         int i;
772
773         switch (priv->firmware_type) {
774         case FIRMWARE_TYPE_AGERE:
775         {
776                 struct orinoco_key keys[ORINOCO_MAX_KEYS];
777
778                 memset(&keys, 0, sizeof(keys));
779                 for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
780                         int len = min(priv->keys[i].key_len,
781                                       ORINOCO_MAX_KEY_SIZE);
782                         memcpy(&keys[i].data, priv->keys[i].key, len);
783                         if (len > SMALL_KEY_SIZE)
784                                 keys[i].len = cpu_to_le16(LARGE_KEY_SIZE);
785                         else if (len > 0)
786                                 keys[i].len = cpu_to_le16(SMALL_KEY_SIZE);
787                         else
788                                 keys[i].len = cpu_to_le16(0);
789                 }
790
791                 err = HERMES_WRITE_RECORD(hw, USER_BAP,
792                                           HERMES_RID_CNFWEPKEYS_AGERE,
793                                           &keys);
794                 if (err)
795                         return err;
796                 err = hermes_write_wordrec(hw, USER_BAP,
797                                            HERMES_RID_CNFTXKEY_AGERE,
798                                            priv->tx_key);
799                 if (err)
800                         return err;
801                 break;
802         }
803         case FIRMWARE_TYPE_INTERSIL:
804         case FIRMWARE_TYPE_SYMBOL:
805                 {
806                         int keylen;
807
808                         /* Force uniform key length to work around
809                          * firmware bugs */
810                         keylen = priv->keys[priv->tx_key].key_len;
811
812                         if (keylen > LARGE_KEY_SIZE) {
813                                 printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n",
814                                        priv->ndev->name, priv->tx_key, keylen);
815                                 return -E2BIG;
816                         } else if (keylen > SMALL_KEY_SIZE)
817                                 keylen = LARGE_KEY_SIZE;
818                         else if (keylen > 0)
819                                 keylen = SMALL_KEY_SIZE;
820                         else
821                                 keylen = 0;
822
823                         /* Write all 4 keys */
824                         for (i = 0; i < ORINOCO_MAX_KEYS; i++) {
825                                 u8 key[LARGE_KEY_SIZE] = { 0 };
826
827                                 memcpy(key, priv->keys[i].key,
828                                        priv->keys[i].key_len);
829
830                                 err = hermes_write_ltv(hw, USER_BAP,
831                                                 HERMES_RID_CNFDEFAULTKEY0 + i,
832                                                 HERMES_BYTES_TO_RECLEN(keylen),
833                                                 key);
834                                 if (err)
835                                         return err;
836                         }
837
838                         /* Write the index of the key used in transmission */
839                         err = hermes_write_wordrec(hw, USER_BAP,
840                                                 HERMES_RID_CNFWEPDEFAULTKEYID,
841                                                 priv->tx_key);
842                         if (err)
843                                 return err;
844                 }
845                 break;
846         }
847
848         return 0;
849 }
850
851 int __orinoco_hw_setup_enc(struct orinoco_private *priv)
852 {
853         hermes_t *hw = &priv->hw;
854         int err = 0;
855         int master_wep_flag;
856         int auth_flag;
857         int enc_flag;
858
859         /* Setup WEP keys */
860         if (priv->encode_alg == ORINOCO_ALG_WEP)
861                 __orinoco_hw_setup_wepkeys(priv);
862
863         if (priv->wep_restrict)
864                 auth_flag = HERMES_AUTH_SHARED_KEY;
865         else
866                 auth_flag = HERMES_AUTH_OPEN;
867
868         if (priv->wpa_enabled)
869                 enc_flag = 2;
870         else if (priv->encode_alg == ORINOCO_ALG_WEP)
871                 enc_flag = 1;
872         else
873                 enc_flag = 0;
874
875         switch (priv->firmware_type) {
876         case FIRMWARE_TYPE_AGERE: /* Agere style WEP */
877                 if (priv->encode_alg == ORINOCO_ALG_WEP) {
878                         /* Enable the shared-key authentication. */
879                         err = hermes_write_wordrec(hw, USER_BAP,
880                                         HERMES_RID_CNFAUTHENTICATION_AGERE,
881                                         auth_flag);
882                 }
883                 err = hermes_write_wordrec(hw, USER_BAP,
884                                            HERMES_RID_CNFWEPENABLED_AGERE,
885                                            enc_flag);
886                 if (err)
887                         return err;
888
889                 if (priv->has_wpa) {
890                         /* Set WPA key management */
891                         err = hermes_write_wordrec(hw, USER_BAP,
892                                   HERMES_RID_CNFSETWPAAUTHMGMTSUITE_AGERE,
893                                   priv->key_mgmt);
894                         if (err)
895                                 return err;
896                 }
897
898                 break;
899
900         case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */
901         case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */
902                 if (priv->encode_alg == ORINOCO_ALG_WEP) {
903                         if (priv->wep_restrict ||
904                             (priv->firmware_type == FIRMWARE_TYPE_SYMBOL))
905                                 master_wep_flag = HERMES_WEP_PRIVACY_INVOKED |
906                                                   HERMES_WEP_EXCL_UNENCRYPTED;
907                         else
908                                 master_wep_flag = HERMES_WEP_PRIVACY_INVOKED;
909
910                         err = hermes_write_wordrec(hw, USER_BAP,
911                                                    HERMES_RID_CNFAUTHENTICATION,
912                                                    auth_flag);
913                         if (err)
914                                 return err;
915                 } else
916                         master_wep_flag = 0;
917
918                 if (priv->iw_mode == NL80211_IFTYPE_MONITOR)
919                         master_wep_flag |= HERMES_WEP_HOST_DECRYPT;
920
921                 /* Master WEP setting : on/off */
922                 err = hermes_write_wordrec(hw, USER_BAP,
923                                            HERMES_RID_CNFWEPFLAGS_INTERSIL,
924                                            master_wep_flag);
925                 if (err)
926                         return err;
927
928                 break;
929         }
930
931         return 0;
932 }
933
934 /* key must be 32 bytes, including the tx and rx MIC keys.
935  * rsc must be NULL or up to 8 bytes
936  * tsc must be NULL or up to 8 bytes
937  */
938 int __orinoco_hw_set_tkip_key(struct orinoco_private *priv, int key_idx,
939                               int set_tx, u8 *key, u8 *rsc, size_t rsc_len,
940                               u8 *tsc, size_t tsc_len)
941 {
942         struct {
943                 __le16 idx;
944                 u8 rsc[ORINOCO_SEQ_LEN];
945                 u8 key[TKIP_KEYLEN];
946                 u8 tx_mic[MIC_KEYLEN];
947                 u8 rx_mic[MIC_KEYLEN];
948                 u8 tsc[ORINOCO_SEQ_LEN];
949         } __attribute__ ((packed)) buf;
950         hermes_t *hw = &priv->hw;
951         int ret;
952         int err;
953         int k;
954         u16 xmitting;
955
956         key_idx &= 0x3;
957
958         if (set_tx)
959                 key_idx |= 0x8000;
960
961         buf.idx = cpu_to_le16(key_idx);
962         memcpy(buf.key, key,
963                sizeof(buf.key) + sizeof(buf.tx_mic) + sizeof(buf.rx_mic));
964
965         if (rsc_len > sizeof(buf.rsc))
966                 rsc_len = sizeof(buf.rsc);
967
968         if (tsc_len > sizeof(buf.tsc))
969                 tsc_len = sizeof(buf.tsc);
970
971         memset(buf.rsc, 0, sizeof(buf.rsc));
972         memset(buf.tsc, 0, sizeof(buf.tsc));
973
974         if (rsc != NULL)
975                 memcpy(buf.rsc, rsc, rsc_len);
976
977         if (tsc != NULL)
978                 memcpy(buf.tsc, tsc, tsc_len);
979         else
980                 buf.tsc[4] = 0x10;
981
982         /* Wait upto 100ms for tx queue to empty */
983         for (k = 100; k > 0; k--) {
984                 udelay(1000);
985                 ret = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_TXQUEUEEMPTY,
986                                           &xmitting);
987                 if (ret || !xmitting)
988                         break;
989         }
990
991         if (k == 0)
992                 ret = -ETIMEDOUT;
993
994         err = HERMES_WRITE_RECORD(hw, USER_BAP,
995                                   HERMES_RID_CNFADDDEFAULTTKIPKEY_AGERE,
996                                   &buf);
997
998         return ret ? ret : err;
999 }
1000
1001 int orinoco_clear_tkip_key(struct orinoco_private *priv, int key_idx)
1002 {
1003         hermes_t *hw = &priv->hw;
1004         int err;
1005
1006         err = hermes_write_wordrec(hw, USER_BAP,
1007                                    HERMES_RID_CNFREMDEFAULTTKIPKEY_AGERE,
1008                                    key_idx);
1009         if (err)
1010                 printk(KERN_WARNING "%s: Error %d clearing TKIP key %d\n",
1011                        priv->ndev->name, err, key_idx);
1012         return err;
1013 }
1014
1015 int __orinoco_hw_set_multicast_list(struct orinoco_private *priv,
1016                                     struct dev_addr_list *mc_list,
1017                                     int mc_count, int promisc)
1018 {
1019         hermes_t *hw = &priv->hw;
1020         int err = 0;
1021
1022         if (promisc != priv->promiscuous) {
1023                 err = hermes_write_wordrec(hw, USER_BAP,
1024                                            HERMES_RID_CNFPROMISCUOUSMODE,
1025                                            promisc);
1026                 if (err) {
1027                         printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n",
1028                                priv->ndev->name, err);
1029                 } else
1030                         priv->promiscuous = promisc;
1031         }
1032
1033         /* If we're not in promiscuous mode, then we need to set the
1034          * group address if either we want to multicast, or if we were
1035          * multicasting and want to stop */
1036         if (!promisc && (mc_count || priv->mc_count)) {
1037                 struct dev_mc_list *p = mc_list;
1038                 struct hermes_multicast mclist;
1039                 int i;
1040
1041                 for (i = 0; i < mc_count; i++) {
1042                         /* paranoia: is list shorter than mc_count? */
1043                         BUG_ON(!p);
1044                         /* paranoia: bad address size in list? */
1045                         BUG_ON(p->dmi_addrlen != ETH_ALEN);
1046
1047                         memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN);
1048                         p = p->next;
1049                 }
1050
1051                 if (p)
1052                         printk(KERN_WARNING "%s: Multicast list is "
1053                                "longer than mc_count\n", priv->ndev->name);
1054
1055                 err = hermes_write_ltv(hw, USER_BAP,
1056                                    HERMES_RID_CNFGROUPADDRESSES,
1057                                    HERMES_BYTES_TO_RECLEN(mc_count * ETH_ALEN),
1058                                    &mclist);
1059                 if (err)
1060                         printk(KERN_ERR "%s: Error %d setting multicast list.\n",
1061                                priv->ndev->name, err);
1062                 else
1063                         priv->mc_count = mc_count;
1064         }
1065         return err;
1066 }
1067
1068 /* Return : < 0 -> error code ; >= 0 -> length */
1069 int orinoco_hw_get_essid(struct orinoco_private *priv, int *active,
1070                          char buf[IW_ESSID_MAX_SIZE+1])
1071 {
1072         hermes_t *hw = &priv->hw;
1073         int err = 0;
1074         struct hermes_idstring essidbuf;
1075         char *p = (char *)(&essidbuf.val);
1076         int len;
1077         unsigned long flags;
1078
1079         if (orinoco_lock(priv, &flags) != 0)
1080                 return -EBUSY;
1081
1082         if (strlen(priv->desired_essid) > 0) {
1083                 /* We read the desired SSID from the hardware rather
1084                    than from priv->desired_essid, just in case the
1085                    firmware is allowed to change it on us. I'm not
1086                    sure about this */
1087                 /* My guess is that the OWNSSID should always be whatever
1088                  * we set to the card, whereas CURRENT_SSID is the one that
1089                  * may change... - Jean II */
1090                 u16 rid;
1091
1092                 *active = 1;
1093
1094                 rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID :
1095                         HERMES_RID_CNFDESIREDSSID;
1096
1097                 err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf),
1098                                       NULL, &essidbuf);
1099                 if (err)
1100                         goto fail_unlock;
1101         } else {
1102                 *active = 0;
1103
1104                 err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID,
1105                                       sizeof(essidbuf), NULL, &essidbuf);
1106                 if (err)
1107                         goto fail_unlock;
1108         }
1109
1110         len = le16_to_cpu(essidbuf.len);
1111         BUG_ON(len > IW_ESSID_MAX_SIZE);
1112
1113         memset(buf, 0, IW_ESSID_MAX_SIZE);
1114         memcpy(buf, p, len);
1115         err = len;
1116
1117  fail_unlock:
1118         orinoco_unlock(priv, &flags);
1119
1120         return err;
1121 }
1122
1123 int orinoco_hw_get_freq(struct orinoco_private *priv)
1124 {
1125         hermes_t *hw = &priv->hw;
1126         int err = 0;
1127         u16 channel;
1128         int freq = 0;
1129         unsigned long flags;
1130
1131         if (orinoco_lock(priv, &flags) != 0)
1132                 return -EBUSY;
1133
1134         err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL,
1135                                   &channel);
1136         if (err)
1137                 goto out;
1138
1139         /* Intersil firmware 1.3.5 returns 0 when the interface is down */
1140         if (channel == 0) {
1141                 err = -EBUSY;
1142                 goto out;
1143         }
1144
1145         if ((channel < 1) || (channel > NUM_CHANNELS)) {
1146                 printk(KERN_WARNING "%s: Channel out of range (%d)!\n",
1147                        priv->ndev->name, channel);
1148                 err = -EBUSY;
1149                 goto out;
1150
1151         }
1152         freq = ieee80211_dsss_chan_to_freq(channel);
1153
1154  out:
1155         orinoco_unlock(priv, &flags);
1156
1157         if (err > 0)
1158                 err = -EBUSY;
1159         return err ? err : freq;
1160 }
1161
1162 int orinoco_hw_get_bitratelist(struct orinoco_private *priv,
1163                                int *numrates, s32 *rates, int max)
1164 {
1165         hermes_t *hw = &priv->hw;
1166         struct hermes_idstring list;
1167         unsigned char *p = (unsigned char *)&list.val;
1168         int err = 0;
1169         int num;
1170         int i;
1171         unsigned long flags;
1172
1173         if (orinoco_lock(priv, &flags) != 0)
1174                 return -EBUSY;
1175
1176         err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES,
1177                               sizeof(list), NULL, &list);
1178         orinoco_unlock(priv, &flags);
1179
1180         if (err)
1181                 return err;
1182
1183         num = le16_to_cpu(list.len);
1184         *numrates = num;
1185         num = min(num, max);
1186
1187         for (i = 0; i < num; i++)
1188                 rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */
1189
1190         return 0;
1191 }
1192
1193 int orinoco_hw_trigger_scan(struct orinoco_private *priv,
1194                             const struct cfg80211_ssid *ssid)
1195 {
1196         struct net_device *dev = priv->ndev;
1197         hermes_t *hw = &priv->hw;
1198         unsigned long flags;
1199         int err = 0;
1200
1201         if (orinoco_lock(priv, &flags) != 0)
1202                 return -EBUSY;
1203
1204         /* Scanning with port 0 disabled would fail */
1205         if (!netif_running(dev)) {
1206                 err = -ENETDOWN;
1207                 goto out;
1208         }
1209
1210         /* In monitor mode, the scan results are always empty.
1211          * Probe responses are passed to the driver as received
1212          * frames and could be processed in software. */
1213         if (priv->iw_mode == NL80211_IFTYPE_MONITOR) {
1214                 err = -EOPNOTSUPP;
1215                 goto out;
1216         }
1217
1218         if (priv->has_hostscan) {
1219                 switch (priv->firmware_type) {
1220                 case FIRMWARE_TYPE_SYMBOL:
1221                         err = hermes_write_wordrec(hw, USER_BAP,
1222                                                 HERMES_RID_CNFHOSTSCAN_SYMBOL,
1223                                                 HERMES_HOSTSCAN_SYMBOL_ONCE |
1224                                                 HERMES_HOSTSCAN_SYMBOL_BCAST);
1225                         break;
1226                 case FIRMWARE_TYPE_INTERSIL: {
1227                         __le16 req[3];
1228
1229                         req[0] = cpu_to_le16(0x3fff);   /* All channels */
1230                         req[1] = cpu_to_le16(0x0001);   /* rate 1 Mbps */
1231                         req[2] = 0;                     /* Any ESSID */
1232                         err = HERMES_WRITE_RECORD(hw, USER_BAP,
1233                                                   HERMES_RID_CNFHOSTSCAN, &req);
1234                         break;
1235                 }
1236                 case FIRMWARE_TYPE_AGERE:
1237                         if (ssid->ssid_len > 0) {
1238                                 struct hermes_idstring idbuf;
1239                                 size_t len = ssid->ssid_len;
1240
1241                                 idbuf.len = cpu_to_le16(len);
1242                                 memcpy(idbuf.val, ssid->ssid, len);
1243
1244                                 err = hermes_write_ltv(hw, USER_BAP,
1245                                                HERMES_RID_CNFSCANSSID_AGERE,
1246                                                HERMES_BYTES_TO_RECLEN(len + 2),
1247                                                &idbuf);
1248                         } else
1249                                 err = hermes_write_wordrec(hw, USER_BAP,
1250                                                    HERMES_RID_CNFSCANSSID_AGERE,
1251                                                    0);  /* Any ESSID */
1252                         if (err)
1253                                 break;
1254
1255                         if (priv->has_ext_scan) {
1256                                 err = hermes_write_wordrec(hw, USER_BAP,
1257                                                 HERMES_RID_CNFSCANCHANNELS2GHZ,
1258                                                 0x7FFF);
1259                                 if (err)
1260                                         goto out;
1261
1262                                 err = hermes_inquire(hw,
1263                                                      HERMES_INQ_CHANNELINFO);
1264                         } else
1265                                 err = hermes_inquire(hw, HERMES_INQ_SCAN);
1266
1267                         break;
1268                 }
1269         } else
1270                 err = hermes_inquire(hw, HERMES_INQ_SCAN);
1271
1272  out:
1273         orinoco_unlock(priv, &flags);
1274
1275         return err;
1276 }
1277
1278 /* Disassociate from node with BSSID addr */
1279 int orinoco_hw_disassociate(struct orinoco_private *priv,
1280                             u8 *addr, u16 reason_code)
1281 {
1282         hermes_t *hw = &priv->hw;
1283         int err;
1284
1285         struct {
1286                 u8 addr[ETH_ALEN];
1287                 __le16 reason_code;
1288         } __attribute__ ((packed)) buf;
1289
1290         /* Currently only supported by WPA enabled Agere fw */
1291         if (!priv->has_wpa)
1292                 return -EOPNOTSUPP;
1293
1294         memcpy(buf.addr, addr, ETH_ALEN);
1295         buf.reason_code = cpu_to_le16(reason_code);
1296         err = HERMES_WRITE_RECORD(hw, USER_BAP,
1297                                   HERMES_RID_CNFDISASSOCIATE,
1298                                   &buf);
1299         return err;
1300 }
1301
1302 int orinoco_hw_get_current_bssid(struct orinoco_private *priv,
1303                                  u8 *addr)
1304 {
1305         hermes_t *hw = &priv->hw;
1306         int err;
1307
1308         err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID,
1309                               ETH_ALEN, NULL, addr);
1310
1311         return err;
1312 }