Staging: wlan-ng: Replace WLAN_LOG_DEBUG() with printk(KERN_DEBUG
[safe/jmp/linux-2.6] / drivers / staging / wlan-ng / prism2sta.c
1 /* src/prism2/driver/prism2sta.c
2 *
3 * Implements the station functionality for prism2
4 *
5 * Copyright (C) 1999 AbsoluteValue Systems, Inc.  All Rights Reserved.
6 * --------------------------------------------------------------------
7 *
8 * linux-wlan
9 *
10 *   The contents of this file are subject to the Mozilla Public
11 *   License Version 1.1 (the "License"); you may not use this file
12 *   except in compliance with the License. You may obtain a copy of
13 *   the License at http://www.mozilla.org/MPL/
14 *
15 *   Software distributed under the License is distributed on an "AS
16 *   IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
17 *   implied. See the License for the specific language governing
18 *   rights and limitations under the License.
19 *
20 *   Alternatively, the contents of this file may be used under the
21 *   terms of the GNU Public License version 2 (the "GPL"), in which
22 *   case the provisions of the GPL are applicable instead of the
23 *   above.  If you wish to allow the use of your version of this file
24 *   only under the terms of the GPL and not to allow others to use
25 *   your version of this file under the MPL, indicate your decision
26 *   by deleting the provisions above and replace them with the notice
27 *   and other provisions required by the GPL.  If you do not delete
28 *   the provisions above, a recipient may use your version of this
29 *   file under either the MPL or the GPL.
30 *
31 * --------------------------------------------------------------------
32 *
33 * Inquiries regarding the linux-wlan Open Source project can be
34 * made directly to:
35 *
36 * AbsoluteValue Systems Inc.
37 * info@linux-wlan.com
38 * http://www.linux-wlan.com
39 *
40 * --------------------------------------------------------------------
41 *
42 * Portions of the development of this software were funded by
43 * Intersil Corporation as part of PRISM(R) chipset product development.
44 *
45 * --------------------------------------------------------------------
46 *
47 * This file implements the module and linux pcmcia routines for the
48 * prism2 driver.
49 *
50 * --------------------------------------------------------------------
51 */
52
53 /*================================================================*/
54 /* System Includes */
55
56 #include <linux/version.h>
57 #include <linux/module.h>
58 #include <linux/moduleparam.h>
59 #include <linux/kernel.h>
60 #include <linux/sched.h>
61 #include <linux/types.h>
62 #include <linux/init.h>
63 #include <linux/slab.h>
64 #include <linux/wireless.h>
65 #include <linux/netdevice.h>
66 #include <linux/workqueue.h>
67 #include <linux/byteorder/generic.h>
68 #include <linux/ctype.h>
69
70 #include <asm/io.h>
71 #include <linux/delay.h>
72 #include <asm/byteorder.h>
73 #include <linux/if_arp.h>
74 #include <linux/if_ether.h>
75 #include <linux/bitops.h>
76
77 #include "wlan_compat.h"
78
79 /*================================================================*/
80 /* Project Includes */
81
82 #include "p80211types.h"
83 #include "p80211hdr.h"
84 #include "p80211mgmt.h"
85 #include "p80211conv.h"
86 #include "p80211msg.h"
87 #include "p80211netdev.h"
88 #include "p80211req.h"
89 #include "p80211metadef.h"
90 #include "p80211metastruct.h"
91 #include "hfa384x.h"
92 #include "prism2mgmt.h"
93
94 /*================================================================*/
95 /* Local Macros */
96
97 #define wlan_hexchar(x) (((x) < 0x0a) ? ('0' + (x)) : ('a' + ((x) - 0x0a)))
98
99 /* Create a string of printable chars from something that might not be */
100 /* It's recommended that the str be 4*len + 1 bytes long */
101 #define wlan_mkprintstr(buf, buflen, str, strlen) \
102 { \
103         int i = 0; \
104         int j = 0; \
105         memset(str, 0, (strlen)); \
106         for (i = 0; i < (buflen); i++) { \
107                 if ( isprint((buf)[i]) ) { \
108                         (str)[j] = (buf)[i]; \
109                         j++; \
110                 } else { \
111                         (str)[j] = '\\'; \
112                         (str)[j+1] = 'x'; \
113                         (str)[j+2] = wlan_hexchar(((buf)[i] & 0xf0) >> 4); \
114                         (str)[j+3] = wlan_hexchar(((buf)[i] & 0x0f)); \
115                         j += 4; \
116                 } \
117         } \
118 }
119
120 /*================================================================*/
121 /* Local Static Definitions */
122
123 static char *dev_info = "prism2_usb";
124
125 static wlandevice_t *create_wlan(void);
126
127 /*----------------------------------------------------------------*/
128 /* --Module Parameters */
129
130 int      prism2_reset_holdtime=30;      /* Reset hold time in ms */
131 int      prism2_reset_settletime=100;   /* Reset settle time in ms */
132
133 static int      prism2_doreset=0;               /* Do a reset at init? */
134
135 module_param( prism2_doreset, int, 0644);
136 MODULE_PARM_DESC(prism2_doreset, "Issue a reset on initialization");
137
138 module_param( prism2_reset_holdtime, int, 0644);
139 MODULE_PARM_DESC( prism2_reset_holdtime, "reset hold time in ms");
140 module_param( prism2_reset_settletime, int, 0644);
141 MODULE_PARM_DESC( prism2_reset_settletime, "reset settle time in ms");
142
143 MODULE_LICENSE("Dual MPL/GPL");
144
145 /*================================================================*/
146 /* Local Function Declarations */
147
148 static int      prism2sta_open(wlandevice_t *wlandev);
149 static int      prism2sta_close(wlandevice_t *wlandev);
150 static void     prism2sta_reset(wlandevice_t *wlandev );
151 static int      prism2sta_txframe(wlandevice_t *wlandev, struct sk_buff *skb, p80211_hdr_t *p80211_hdr, p80211_metawep_t *p80211_wep);
152 static int      prism2sta_mlmerequest(wlandevice_t *wlandev, p80211msg_t *msg);
153 static int      prism2sta_getcardinfo(wlandevice_t *wlandev);
154 static int      prism2sta_globalsetup(wlandevice_t *wlandev);
155 static int      prism2sta_setmulticast(wlandevice_t *wlandev,
156                                        netdevice_t *dev);
157
158 static void     prism2sta_inf_handover(
159                         wlandevice_t *wlandev, hfa384x_InfFrame_t *inf);
160 static void     prism2sta_inf_tallies(
161                         wlandevice_t *wlandev, hfa384x_InfFrame_t *inf);
162 static void     prism2sta_inf_hostscanresults(
163                         wlandevice_t *wlandev, hfa384x_InfFrame_t *inf);
164 static void     prism2sta_inf_scanresults(
165                         wlandevice_t *wlandev, hfa384x_InfFrame_t *inf);
166 static void     prism2sta_inf_chinforesults(
167                         wlandevice_t *wlandev, hfa384x_InfFrame_t *inf);
168 static void     prism2sta_inf_linkstatus(
169                         wlandevice_t *wlandev, hfa384x_InfFrame_t *inf);
170 static void     prism2sta_inf_assocstatus(
171                         wlandevice_t *wlandev, hfa384x_InfFrame_t *inf);
172 static void     prism2sta_inf_authreq(
173                         wlandevice_t *wlandev, hfa384x_InfFrame_t *inf);
174 static void     prism2sta_inf_authreq_defer(
175                         wlandevice_t *wlandev, hfa384x_InfFrame_t *inf);
176 static void     prism2sta_inf_psusercnt(
177                         wlandevice_t *wlandev, hfa384x_InfFrame_t *inf);
178
179 /*================================================================*/
180 /* Function Definitions */
181
182
183 /*----------------------------------------------------------------
184 * prism2sta_open
185 *
186 * WLAN device open method.  Called from p80211netdev when kernel
187 * device open (start) method is called in response to the
188 * SIOCSIIFFLAGS ioctl changing the flags bit IFF_UP
189 * from clear to set.
190 *
191 * Arguments:
192 *       wlandev         wlan device structure
193 *
194 * Returns:
195 *       0       success
196 *       >0      f/w reported error
197 *       <0      driver reported error
198 *
199 * Side effects:
200 *
201 * Call context:
202 *       process thread
203 ----------------------------------------------------------------*/
204 static int prism2sta_open(wlandevice_t *wlandev)
205 {
206         /* We don't currently have to do anything else.
207          * The setup of the MAC should be subsequently completed via
208          * the mlme commands.
209          * Higher layers know we're ready from dev->start==1 and
210          * dev->tbusy==0.  Our rx path knows to pass up received/
211          * frames because of dev->flags&IFF_UP is true.
212          */
213
214         return 0;
215 }
216
217
218 /*----------------------------------------------------------------
219 * prism2sta_close
220 *
221 * WLAN device close method.  Called from p80211netdev when kernel
222 * device close method is called in response to the
223 * SIOCSIIFFLAGS ioctl changing the flags bit IFF_UP
224 * from set to clear.
225 *
226 * Arguments:
227 *       wlandev         wlan device structure
228 *
229 * Returns:
230 *       0       success
231 *       >0      f/w reported error
232 *       <0      driver reported error
233 *
234 * Side effects:
235 *
236 * Call context:
237 *       process thread
238 ----------------------------------------------------------------*/
239 static int prism2sta_close(wlandevice_t *wlandev)
240 {
241         /* We don't currently have to do anything else.
242          * Higher layers know we're not ready from dev->start==0 and
243          * dev->tbusy==1.  Our rx path knows to not pass up received
244          * frames because of dev->flags&IFF_UP is false.
245          */
246
247         return 0;
248 }
249
250
251 /*----------------------------------------------------------------
252 * prism2sta_reset
253 *
254 * Not currently implented.
255 *
256 * Arguments:
257 *       wlandev         wlan device structure
258 *       none
259 *
260 * Returns:
261 *       nothing
262 *
263 * Side effects:
264 *
265 * Call context:
266 *       process thread
267 ----------------------------------------------------------------*/
268 static void prism2sta_reset(wlandevice_t *wlandev )
269 {
270         return;
271 }
272
273
274 /*----------------------------------------------------------------
275 * prism2sta_txframe
276 *
277 * Takes a frame from p80211 and queues it for transmission.
278 *
279 * Arguments:
280 *       wlandev         wlan device structure
281 *       pb              packet buffer struct.  Contains an 802.11
282 *                       data frame.
283 *       p80211_hdr      points to the 802.11 header for the packet.
284 * Returns:
285 *       0               Success and more buffs available
286 *       1               Success but no more buffs
287 *       2               Allocation failure
288 *       4               Buffer full or queue busy
289 *
290 * Side effects:
291 *
292 * Call context:
293 *       process thread
294 ----------------------------------------------------------------*/
295 static int prism2sta_txframe(wlandevice_t *wlandev, struct sk_buff *skb,
296                              p80211_hdr_t *p80211_hdr,
297                              p80211_metawep_t *p80211_wep)
298 {
299         hfa384x_t               *hw = (hfa384x_t *)wlandev->priv;
300         int                     result;
301
302         /* If necessary, set the 802.11 WEP bit */
303         if ((wlandev->hostwep & (HOSTWEP_PRIVACYINVOKED | HOSTWEP_ENCRYPT)) == HOSTWEP_PRIVACYINVOKED) {
304                 p80211_hdr->a3.fc |= cpu_to_le16(WLAN_SET_FC_ISWEP(1));
305         }
306
307         result = hfa384x_drvr_txframe(hw, skb, p80211_hdr, p80211_wep);
308
309         return result;
310 }
311
312
313 /*----------------------------------------------------------------
314 * prism2sta_mlmerequest
315 *
316 * wlan command message handler.  All we do here is pass the message
317 * over to the prism2sta_mgmt_handler.
318 *
319 * Arguments:
320 *       wlandev         wlan device structure
321 *       msg             wlan command message
322 * Returns:
323 *       0               success
324 *       <0              successful acceptance of message, but we're
325 *                       waiting for an async process to finish before
326 *                       we're done with the msg.  When the asynch
327 *                       process is done, we'll call the p80211
328 *                       function p80211req_confirm() .
329 *       >0              An error occurred while we were handling
330 *                       the message.
331 *
332 * Side effects:
333 *
334 * Call context:
335 *       process thread
336 ----------------------------------------------------------------*/
337 static int prism2sta_mlmerequest(wlandevice_t *wlandev, p80211msg_t *msg)
338 {
339         hfa384x_t               *hw = (hfa384x_t *)wlandev->priv;
340
341         int result = 0;
342
343         switch( msg->msgcode )
344         {
345         case DIDmsg_dot11req_mibget :
346                 pr_debug("Received mibget request\n");
347                 result = prism2mgmt_mibset_mibget(wlandev, msg);
348                 break;
349         case DIDmsg_dot11req_mibset :
350                 pr_debug("Received mibset request\n");
351                 result = prism2mgmt_mibset_mibget(wlandev, msg);
352                 break;
353         case DIDmsg_dot11req_scan :
354                 pr_debug("Received scan request\n");
355                 result = prism2mgmt_scan(wlandev, msg);
356                 break;
357         case DIDmsg_dot11req_scan_results :
358                 pr_debug("Received scan_results request\n");
359                 result = prism2mgmt_scan_results(wlandev, msg);
360                 break;
361         case DIDmsg_dot11req_start :
362                 pr_debug("Received mlme start request\n");
363                 result = prism2mgmt_start(wlandev, msg);
364                 break;
365         /*
366          * Prism2 specific messages
367          */
368         case DIDmsg_p2req_readpda :
369                 pr_debug("Received mlme readpda request\n");
370                 result = prism2mgmt_readpda(wlandev, msg);
371                 break;
372         case DIDmsg_p2req_ramdl_state :
373                 pr_debug("Received mlme ramdl_state request\n");
374                 result = prism2mgmt_ramdl_state(wlandev, msg);
375                 break;
376         case DIDmsg_p2req_ramdl_write :
377                 pr_debug("Received mlme ramdl_write request\n");
378                 result = prism2mgmt_ramdl_write(wlandev, msg);
379                 break;
380         case DIDmsg_p2req_flashdl_state :
381                 pr_debug("Received mlme flashdl_state request\n");
382                 result = prism2mgmt_flashdl_state(wlandev, msg);
383                 break;
384         case DIDmsg_p2req_flashdl_write :
385                 pr_debug("Received mlme flashdl_write request\n");
386                 result = prism2mgmt_flashdl_write(wlandev, msg);
387                 break;
388         /*
389          * Linux specific messages
390          */
391         case DIDmsg_lnxreq_hostwep :
392                 break;   // ignore me.
393         case DIDmsg_lnxreq_ifstate :
394                 {
395                 p80211msg_lnxreq_ifstate_t      *ifstatemsg;
396                 pr_debug("Received mlme ifstate request\n");
397                 ifstatemsg = (p80211msg_lnxreq_ifstate_t*)msg;
398                 result = prism2sta_ifstate(wlandev, ifstatemsg->ifstate.data);
399                 ifstatemsg->resultcode.status =
400                         P80211ENUM_msgitem_status_data_ok;
401                 ifstatemsg->resultcode.data = result;
402                 result = 0;
403                 }
404                 break;
405         case DIDmsg_lnxreq_wlansniff :
406                 pr_debug("Received mlme wlansniff request\n");
407                 result = prism2mgmt_wlansniff(wlandev, msg);
408                 break;
409         case DIDmsg_lnxreq_autojoin :
410                 pr_debug("Received mlme autojoin request\n");
411                 result = prism2mgmt_autojoin(wlandev, msg);
412                 break;
413         case DIDmsg_lnxreq_commsquality: {
414                 p80211msg_lnxreq_commsquality_t *qualmsg;
415
416                 pr_debug("Received commsquality request\n");
417
418                 qualmsg = (p80211msg_lnxreq_commsquality_t*) msg;
419
420                 qualmsg->link.status = P80211ENUM_msgitem_status_data_ok;
421                 qualmsg->level.status = P80211ENUM_msgitem_status_data_ok;
422                 qualmsg->noise.status = P80211ENUM_msgitem_status_data_ok;
423
424
425                 qualmsg->link.data = hfa384x2host_16(hw->qual.CQ_currBSS);
426                 qualmsg->level.data = hfa384x2host_16(hw->qual.ASL_currBSS);
427                 qualmsg->noise.data = hfa384x2host_16(hw->qual.ANL_currFC);
428
429                 break;
430         }
431         default:
432                 printk(KERN_WARNING "Unknown mgmt request message 0x%08x", msg->msgcode);
433                 break;
434         }
435
436         return result;
437 }
438
439
440 /*----------------------------------------------------------------
441 * prism2sta_ifstate
442 *
443 * Interface state.  This is the primary WLAN interface enable/disable
444 * handler.  Following the driver/load/deviceprobe sequence, this
445 * function must be called with a state of "enable" before any other
446 * commands will be accepted.
447 *
448 * Arguments:
449 *       wlandev         wlan device structure
450 *       msgp            ptr to msg buffer
451 *
452 * Returns:
453 *       A p80211 message resultcode value.
454 *
455 * Side effects:
456 *
457 * Call context:
458 *       process thread  (usually)
459 *       interrupt
460 ----------------------------------------------------------------*/
461 u32 prism2sta_ifstate(wlandevice_t *wlandev, u32 ifstate)
462 {
463         hfa384x_t               *hw = (hfa384x_t *)wlandev->priv;
464         u32                     result;
465
466         result = P80211ENUM_resultcode_implementation_failure;
467
468         pr_debug("Current MSD state(%d), requesting(%d)\n",
469                           wlandev->msdstate, ifstate);
470         switch (ifstate)
471         {
472         case P80211ENUM_ifstate_fwload:
473                 switch (wlandev->msdstate) {
474                 case WLAN_MSD_HWPRESENT:
475                         wlandev->msdstate = WLAN_MSD_FWLOAD_PENDING;
476                         /*
477                          * Initialize the device+driver sufficiently
478                          * for firmware loading.
479                          */
480                         if ((result=hfa384x_drvr_start(hw))) {
481                                 printk(KERN_ERR
482                                         "hfa384x_drvr_start() failed,"
483                                         "result=%d\n", (int)result);
484                                 result =
485                                 P80211ENUM_resultcode_implementation_failure;
486                                 wlandev->msdstate = WLAN_MSD_HWPRESENT;
487                                 break;
488                         }
489                         wlandev->msdstate = WLAN_MSD_FWLOAD;
490                         result = P80211ENUM_resultcode_success;
491                         break;
492                 case WLAN_MSD_FWLOAD:
493                         hfa384x_cmd_initialize(hw);
494                         result = P80211ENUM_resultcode_success;
495                         break;
496                 case WLAN_MSD_RUNNING:
497                         printk(KERN_WARNING
498                                 "Cannot enter fwload state from enable state,"
499                                 "you must disable first.\n");
500                         result = P80211ENUM_resultcode_invalid_parameters;
501                         break;
502                 case WLAN_MSD_HWFAIL:
503                 default:
504                         /* probe() had a problem or the msdstate contains
505                          * an unrecognized value, there's nothing we can do.
506                          */
507                         result = P80211ENUM_resultcode_implementation_failure;
508                         break;
509                 }
510                 break;
511         case P80211ENUM_ifstate_enable:
512                 switch (wlandev->msdstate) {
513                 case WLAN_MSD_HWPRESENT:
514                 case WLAN_MSD_FWLOAD:
515                         wlandev->msdstate = WLAN_MSD_RUNNING_PENDING;
516                         /* Initialize the device+driver for full
517                          * operation. Note that this might me an FWLOAD to
518                          * to RUNNING transition so we must not do a chip
519                          * or board level reset.  Note that on failure,
520                          * the MSD state is set to HWPRESENT because we
521                          * can't make any assumptions about the state
522                          * of the hardware or a previous firmware load.
523                          */
524                         if ((result=hfa384x_drvr_start(hw))) {
525                                 printk(KERN_ERR
526                                         "hfa384x_drvr_start() failed,"
527                                         "result=%d\n", (int)result);
528                                 result =
529                                 P80211ENUM_resultcode_implementation_failure;
530                                 wlandev->msdstate = WLAN_MSD_HWPRESENT;
531                                 break;
532                         }
533
534                         if ((result=prism2sta_getcardinfo(wlandev))) {
535                                 printk(KERN_ERR
536                                         "prism2sta_getcardinfo() failed,"
537                                         "result=%d\n", (int)result);
538                                 result =
539                                 P80211ENUM_resultcode_implementation_failure;
540                                 hfa384x_drvr_stop(hw);
541                                 wlandev->msdstate = WLAN_MSD_HWPRESENT;
542                                 break;
543                         }
544                         if ((result=prism2sta_globalsetup(wlandev))) {
545                                 printk(KERN_ERR
546                                         "prism2sta_globalsetup() failed,"
547                                         "result=%d\n", (int)result);
548                                 result =
549                                 P80211ENUM_resultcode_implementation_failure;
550                                 hfa384x_drvr_stop(hw);
551                                 wlandev->msdstate = WLAN_MSD_HWPRESENT;
552                                 break;
553                         }
554                         wlandev->msdstate = WLAN_MSD_RUNNING;
555                         hw->join_ap = 0;
556                         hw->join_retries = 60;
557                         result = P80211ENUM_resultcode_success;
558                         break;
559                 case WLAN_MSD_RUNNING:
560                         /* Do nothing, we're already in this state.*/
561                         result = P80211ENUM_resultcode_success;
562                         break;
563                 case WLAN_MSD_HWFAIL:
564                 default:
565                         /* probe() had a problem or the msdstate contains
566                          * an unrecognized value, there's nothing we can do.
567                          */
568                         result = P80211ENUM_resultcode_implementation_failure;
569                         break;
570                 }
571                 break;
572         case P80211ENUM_ifstate_disable:
573                 switch (wlandev->msdstate) {
574                 case WLAN_MSD_HWPRESENT:
575                         /* Do nothing, we're already in this state.*/
576                         result = P80211ENUM_resultcode_success;
577                         break;
578                 case WLAN_MSD_FWLOAD:
579                 case WLAN_MSD_RUNNING:
580                         wlandev->msdstate = WLAN_MSD_HWPRESENT_PENDING;
581                         /*
582                          * TODO: Shut down the MAC completely. Here a chip
583                          * or board level reset is probably called for.
584                          * After a "disable" _all_ results are lost, even
585                          * those from a fwload.
586                          */
587                         if (!wlandev->hwremoved)
588                                 netif_carrier_off(wlandev->netdev);
589
590                         hfa384x_drvr_stop(hw);
591
592                         wlandev->macmode = WLAN_MACMODE_NONE;
593                         wlandev->msdstate = WLAN_MSD_HWPRESENT;
594                         result = P80211ENUM_resultcode_success;
595                         break;
596                 case WLAN_MSD_HWFAIL:
597                 default:
598                         /* probe() had a problem or the msdstate contains
599                          * an unrecognized value, there's nothing we can do.
600                          */
601                         result = P80211ENUM_resultcode_implementation_failure;
602                         break;
603                 }
604                 break;
605         default:
606                 result = P80211ENUM_resultcode_invalid_parameters;
607                 break;
608         }
609
610         return result;
611 }
612
613
614 /*----------------------------------------------------------------
615 * prism2sta_getcardinfo
616 *
617 * Collect the NICID, firmware version and any other identifiers
618 * we'd like to have in host-side data structures.
619 *
620 * Arguments:
621 *       wlandev         wlan device structure
622 *
623 * Returns:
624 *       0       success
625 *       >0      f/w reported error
626 *       <0      driver reported error
627 *
628 * Side effects:
629 *
630 * Call context:
631 *       Either.
632 ----------------------------------------------------------------*/
633 static int prism2sta_getcardinfo(wlandevice_t *wlandev)
634 {
635         int                     result = 0;
636         hfa384x_t               *hw = (hfa384x_t *)wlandev->priv;
637         u16                  temp;
638         u8                      snum[HFA384x_RID_NICSERIALNUMBER_LEN];
639         char                    pstr[(HFA384x_RID_NICSERIALNUMBER_LEN * 4) + 1];
640
641         /* Collect version and compatibility info */
642         /*  Some are critical, some are not */
643         /* NIC identity */
644         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_NICIDENTITY,
645                         &hw->ident_nic, sizeof(hfa384x_compident_t));
646         if ( result ) {
647                 printk(KERN_ERR "Failed to retrieve NICIDENTITY\n");
648                 goto failed;
649         }
650
651         /* get all the nic id fields in host byte order */
652         hw->ident_nic.id = hfa384x2host_16(hw->ident_nic.id);
653         hw->ident_nic.variant = hfa384x2host_16(hw->ident_nic.variant);
654         hw->ident_nic.major = hfa384x2host_16(hw->ident_nic.major);
655         hw->ident_nic.minor = hfa384x2host_16(hw->ident_nic.minor);
656
657         printk(KERN_INFO  "ident: nic h/w: id=0x%02x %d.%d.%d\n",
658                         hw->ident_nic.id, hw->ident_nic.major,
659                         hw->ident_nic.minor, hw->ident_nic.variant);
660
661         /* Primary f/w identity */
662         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_PRIIDENTITY,
663                         &hw->ident_pri_fw, sizeof(hfa384x_compident_t));
664         if ( result ) {
665                 printk(KERN_ERR "Failed to retrieve PRIIDENTITY\n");
666                 goto failed;
667         }
668
669         /* get all the private fw id fields in host byte order */
670         hw->ident_pri_fw.id = hfa384x2host_16(hw->ident_pri_fw.id);
671         hw->ident_pri_fw.variant = hfa384x2host_16(hw->ident_pri_fw.variant);
672         hw->ident_pri_fw.major = hfa384x2host_16(hw->ident_pri_fw.major);
673         hw->ident_pri_fw.minor = hfa384x2host_16(hw->ident_pri_fw.minor);
674
675         printk(KERN_INFO  "ident: pri f/w: id=0x%02x %d.%d.%d\n",
676                         hw->ident_pri_fw.id, hw->ident_pri_fw.major,
677                         hw->ident_pri_fw.minor, hw->ident_pri_fw.variant);
678
679         /* Station (Secondary?) f/w identity */
680         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_STAIDENTITY,
681                         &hw->ident_sta_fw, sizeof(hfa384x_compident_t));
682         if ( result ) {
683                 printk(KERN_ERR "Failed to retrieve STAIDENTITY\n");
684                 goto failed;
685         }
686
687         if (hw->ident_nic.id < 0x8000) {
688                 printk(KERN_ERR "FATAL: Card is not an Intersil Prism2/2.5/3\n");
689                 result = -1;
690                 goto failed;
691         }
692
693         /* get all the station fw id fields in host byte order */
694         hw->ident_sta_fw.id = hfa384x2host_16(hw->ident_sta_fw.id);
695         hw->ident_sta_fw.variant = hfa384x2host_16(hw->ident_sta_fw.variant);
696         hw->ident_sta_fw.major = hfa384x2host_16(hw->ident_sta_fw.major);
697         hw->ident_sta_fw.minor = hfa384x2host_16(hw->ident_sta_fw.minor);
698
699         /* strip out the 'special' variant bits */
700         hw->mm_mods = hw->ident_sta_fw.variant & (BIT(14) | BIT(15));
701         hw->ident_sta_fw.variant &= ~((u16)(BIT(14) | BIT(15)));
702
703         if  ( hw->ident_sta_fw.id == 0x1f ) {
704                 printk(KERN_INFO
705                         "ident: sta f/w: id=0x%02x %d.%d.%d\n",
706                         hw->ident_sta_fw.id, hw->ident_sta_fw.major,
707                         hw->ident_sta_fw.minor, hw->ident_sta_fw.variant);
708         } else {
709                 printk(KERN_INFO
710                         "ident:  ap f/w: id=0x%02x %d.%d.%d\n",
711                         hw->ident_sta_fw.id, hw->ident_sta_fw.major,
712                         hw->ident_sta_fw.minor, hw->ident_sta_fw.variant);
713                 printk(KERN_ERR "Unsupported Tertiary AP firmeare loaded!\n");
714                 goto failed;
715         }
716
717         /* Compatibility range, Modem supplier */
718         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_MFISUPRANGE,
719                         &hw->cap_sup_mfi, sizeof(hfa384x_caplevel_t));
720         if ( result ) {
721                 printk(KERN_ERR "Failed to retrieve MFISUPRANGE\n");
722                 goto failed;
723         }
724
725         /* get all the Compatibility range, modem interface supplier
726         fields in byte order */
727         hw->cap_sup_mfi.role = hfa384x2host_16(hw->cap_sup_mfi.role);
728         hw->cap_sup_mfi.id = hfa384x2host_16(hw->cap_sup_mfi.id);
729         hw->cap_sup_mfi.variant = hfa384x2host_16(hw->cap_sup_mfi.variant);
730         hw->cap_sup_mfi.bottom = hfa384x2host_16(hw->cap_sup_mfi.bottom);
731         hw->cap_sup_mfi.top = hfa384x2host_16(hw->cap_sup_mfi.top);
732
733         printk(KERN_INFO
734                 "MFI:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
735                 hw->cap_sup_mfi.role, hw->cap_sup_mfi.id,
736                 hw->cap_sup_mfi.variant, hw->cap_sup_mfi.bottom,
737                 hw->cap_sup_mfi.top);
738
739         /* Compatibility range, Controller supplier */
740         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_CFISUPRANGE,
741                         &hw->cap_sup_cfi, sizeof(hfa384x_caplevel_t));
742         if ( result ) {
743                 printk(KERN_ERR "Failed to retrieve CFISUPRANGE\n");
744                 goto failed;
745         }
746
747         /* get all the Compatibility range, controller interface supplier
748         fields in byte order */
749         hw->cap_sup_cfi.role = hfa384x2host_16(hw->cap_sup_cfi.role);
750         hw->cap_sup_cfi.id = hfa384x2host_16(hw->cap_sup_cfi.id);
751         hw->cap_sup_cfi.variant = hfa384x2host_16(hw->cap_sup_cfi.variant);
752         hw->cap_sup_cfi.bottom = hfa384x2host_16(hw->cap_sup_cfi.bottom);
753         hw->cap_sup_cfi.top = hfa384x2host_16(hw->cap_sup_cfi.top);
754
755         printk(KERN_INFO
756                 "CFI:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
757                 hw->cap_sup_cfi.role, hw->cap_sup_cfi.id,
758                 hw->cap_sup_cfi.variant, hw->cap_sup_cfi.bottom,
759                 hw->cap_sup_cfi.top);
760
761         /* Compatibility range, Primary f/w supplier */
762         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_PRISUPRANGE,
763                         &hw->cap_sup_pri, sizeof(hfa384x_caplevel_t));
764         if ( result ) {
765                 printk(KERN_ERR "Failed to retrieve PRISUPRANGE\n");
766                 goto failed;
767         }
768
769         /* get all the Compatibility range, primary firmware supplier
770         fields in byte order */
771         hw->cap_sup_pri.role = hfa384x2host_16(hw->cap_sup_pri.role);
772         hw->cap_sup_pri.id = hfa384x2host_16(hw->cap_sup_pri.id);
773         hw->cap_sup_pri.variant = hfa384x2host_16(hw->cap_sup_pri.variant);
774         hw->cap_sup_pri.bottom = hfa384x2host_16(hw->cap_sup_pri.bottom);
775         hw->cap_sup_pri.top = hfa384x2host_16(hw->cap_sup_pri.top);
776
777         printk(KERN_INFO
778                 "PRI:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
779                 hw->cap_sup_pri.role, hw->cap_sup_pri.id,
780                 hw->cap_sup_pri.variant, hw->cap_sup_pri.bottom,
781                 hw->cap_sup_pri.top);
782
783         /* Compatibility range, Station f/w supplier */
784         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_STASUPRANGE,
785                         &hw->cap_sup_sta, sizeof(hfa384x_caplevel_t));
786         if ( result ) {
787                 printk(KERN_ERR "Failed to retrieve STASUPRANGE\n");
788                 goto failed;
789         }
790
791         /* get all the Compatibility range, station firmware supplier
792         fields in byte order */
793         hw->cap_sup_sta.role = hfa384x2host_16(hw->cap_sup_sta.role);
794         hw->cap_sup_sta.id = hfa384x2host_16(hw->cap_sup_sta.id);
795         hw->cap_sup_sta.variant = hfa384x2host_16(hw->cap_sup_sta.variant);
796         hw->cap_sup_sta.bottom = hfa384x2host_16(hw->cap_sup_sta.bottom);
797         hw->cap_sup_sta.top = hfa384x2host_16(hw->cap_sup_sta.top);
798
799         if ( hw->cap_sup_sta.id == 0x04 ) {
800                 printk(KERN_INFO
801                 "STA:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
802                 hw->cap_sup_sta.role, hw->cap_sup_sta.id,
803                 hw->cap_sup_sta.variant, hw->cap_sup_sta.bottom,
804                 hw->cap_sup_sta.top);
805         } else {
806                 printk(KERN_INFO
807                 "AP:SUP:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
808                 hw->cap_sup_sta.role, hw->cap_sup_sta.id,
809                 hw->cap_sup_sta.variant, hw->cap_sup_sta.bottom,
810                 hw->cap_sup_sta.top);
811         }
812
813         /* Compatibility range, primary f/w actor, CFI supplier */
814         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_PRI_CFIACTRANGES,
815                         &hw->cap_act_pri_cfi, sizeof(hfa384x_caplevel_t));
816         if ( result ) {
817                 printk(KERN_ERR "Failed to retrieve PRI_CFIACTRANGES\n");
818                 goto failed;
819         }
820
821         /* get all the Compatibility range, primary f/w actor, CFI supplier
822         fields in byte order */
823         hw->cap_act_pri_cfi.role = hfa384x2host_16(hw->cap_act_pri_cfi.role);
824         hw->cap_act_pri_cfi.id = hfa384x2host_16(hw->cap_act_pri_cfi.id);
825         hw->cap_act_pri_cfi.variant = hfa384x2host_16(hw->cap_act_pri_cfi.variant);
826         hw->cap_act_pri_cfi.bottom = hfa384x2host_16(hw->cap_act_pri_cfi.bottom);
827         hw->cap_act_pri_cfi.top = hfa384x2host_16(hw->cap_act_pri_cfi.top);
828
829         printk(KERN_INFO
830                 "PRI-CFI:ACT:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
831                 hw->cap_act_pri_cfi.role, hw->cap_act_pri_cfi.id,
832                 hw->cap_act_pri_cfi.variant, hw->cap_act_pri_cfi.bottom,
833                 hw->cap_act_pri_cfi.top);
834
835         /* Compatibility range, sta f/w actor, CFI supplier */
836         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_STA_CFIACTRANGES,
837                         &hw->cap_act_sta_cfi, sizeof(hfa384x_caplevel_t));
838         if ( result ) {
839                 printk(KERN_ERR "Failed to retrieve STA_CFIACTRANGES\n");
840                 goto failed;
841         }
842
843         /* get all the Compatibility range, station f/w actor, CFI supplier
844         fields in byte order */
845         hw->cap_act_sta_cfi.role = hfa384x2host_16(hw->cap_act_sta_cfi.role);
846         hw->cap_act_sta_cfi.id = hfa384x2host_16(hw->cap_act_sta_cfi.id);
847         hw->cap_act_sta_cfi.variant = hfa384x2host_16(hw->cap_act_sta_cfi.variant);
848         hw->cap_act_sta_cfi.bottom = hfa384x2host_16(hw->cap_act_sta_cfi.bottom);
849         hw->cap_act_sta_cfi.top = hfa384x2host_16(hw->cap_act_sta_cfi.top);
850
851         printk(KERN_INFO
852                 "STA-CFI:ACT:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
853                 hw->cap_act_sta_cfi.role, hw->cap_act_sta_cfi.id,
854                 hw->cap_act_sta_cfi.variant, hw->cap_act_sta_cfi.bottom,
855                 hw->cap_act_sta_cfi.top);
856
857         /* Compatibility range, sta f/w actor, MFI supplier */
858         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_STA_MFIACTRANGES,
859                         &hw->cap_act_sta_mfi, sizeof(hfa384x_caplevel_t));
860         if ( result ) {
861                 printk(KERN_ERR "Failed to retrieve STA_MFIACTRANGES\n");
862                 goto failed;
863         }
864
865         /* get all the Compatibility range, station f/w actor, MFI supplier
866         fields in byte order */
867         hw->cap_act_sta_mfi.role = hfa384x2host_16(hw->cap_act_sta_mfi.role);
868         hw->cap_act_sta_mfi.id = hfa384x2host_16(hw->cap_act_sta_mfi.id);
869         hw->cap_act_sta_mfi.variant = hfa384x2host_16(hw->cap_act_sta_mfi.variant);
870         hw->cap_act_sta_mfi.bottom = hfa384x2host_16(hw->cap_act_sta_mfi.bottom);
871         hw->cap_act_sta_mfi.top = hfa384x2host_16(hw->cap_act_sta_mfi.top);
872
873         printk(KERN_INFO
874                 "STA-MFI:ACT:role=0x%02x:id=0x%02x:var=0x%02x:b/t=%d/%d\n",
875                 hw->cap_act_sta_mfi.role, hw->cap_act_sta_mfi.id,
876                 hw->cap_act_sta_mfi.variant, hw->cap_act_sta_mfi.bottom,
877                 hw->cap_act_sta_mfi.top);
878
879         /* Serial Number */
880         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_NICSERIALNUMBER,
881                         snum, HFA384x_RID_NICSERIALNUMBER_LEN);
882         if ( !result ) {
883                 wlan_mkprintstr(snum, HFA384x_RID_NICSERIALNUMBER_LEN,
884                                 pstr, sizeof(pstr));
885                 printk(KERN_INFO "Prism2 card SN: %s\n", pstr);
886         } else {
887                 printk(KERN_ERR "Failed to retrieve Prism2 Card SN\n");
888                 goto failed;
889         }
890
891         /* Collect the MAC address */
892         result = hfa384x_drvr_getconfig(hw, HFA384x_RID_CNFOWNMACADDR,
893                 wlandev->netdev->dev_addr, ETH_ALEN);
894         if ( result != 0 ) {
895                 printk(KERN_ERR "Failed to retrieve mac address\n");
896                 goto failed;
897         }
898
899         /* short preamble is always implemented */
900         wlandev->nsdcaps |= P80211_NSDCAP_SHORT_PREAMBLE;
901
902         /* find out if hardware wep is implemented */
903         hfa384x_drvr_getconfig16(hw, HFA384x_RID_PRIVACYOPTIMP, &temp);
904         if (temp)
905                 wlandev->nsdcaps |= P80211_NSDCAP_HARDWAREWEP;
906
907         /* get the dBm Scaling constant */
908         hfa384x_drvr_getconfig16(hw, HFA384x_RID_CNFDBMADJUST, &temp);
909         hw->dbmadjust = temp;
910
911         /* Only enable scan by default on newer firmware */
912         if (HFA384x_FIRMWARE_VERSION(hw->ident_sta_fw.major,
913                                      hw->ident_sta_fw.minor,
914                                      hw->ident_sta_fw.variant) <
915             HFA384x_FIRMWARE_VERSION(1,5,5)) {
916                 wlandev->nsdcaps |= P80211_NSDCAP_NOSCAN;
917         }
918
919         /* TODO: Set any internally managed config items */
920
921         goto done;
922 failed:
923         printk(KERN_ERR "Failed, result=%d\n", result);
924 done:
925         return result;
926 }
927
928
929 /*----------------------------------------------------------------
930 * prism2sta_globalsetup
931 *
932 * Set any global RIDs that we want to set at device activation.
933 *
934 * Arguments:
935 *       wlandev         wlan device structure
936 *
937 * Returns:
938 *       0       success
939 *       >0      f/w reported error
940 *       <0      driver reported error
941 *
942 * Side effects:
943 *
944 * Call context:
945 *       process thread
946 ----------------------------------------------------------------*/
947 static int prism2sta_globalsetup(wlandevice_t *wlandev)
948 {
949         hfa384x_t               *hw = (hfa384x_t *)wlandev->priv;
950
951         /* Set the maximum frame size */
952         return hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFMAXDATALEN,
953                                             WLAN_DATA_MAXLEN);
954 }
955
956 static int prism2sta_setmulticast(wlandevice_t *wlandev, netdevice_t *dev)
957 {
958         int result = 0;
959         hfa384x_t               *hw = (hfa384x_t *)wlandev->priv;
960
961         u16  promisc;
962
963         /* If we're not ready, what's the point? */
964         if ( hw->state != HFA384x_STATE_RUNNING )
965                 goto exit;
966
967         if ( (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0 )
968                 promisc = P80211ENUM_truth_true;
969         else
970                 promisc = P80211ENUM_truth_false;
971
972         result = hfa384x_drvr_setconfig16_async(hw, HFA384x_RID_PROMISCMODE, promisc);
973
974         /* XXX TODO: configure the multicast list */
975         // CLEAR_HW_MULTICAST_LIST
976         // struct dev_mc_list element = dev->mc_list;
977         // while (element != null) {
978         //  HW_ADD_MULTICAST_ADDR(element->dmi_addr, dmi_addrlen)
979         //  element = element->next;
980         // }
981
982  exit:
983         return result;
984 }
985
986 /*----------------------------------------------------------------
987 * prism2sta_inf_handover
988 *
989 * Handles the receipt of a Handover info frame. Should only be present
990 * in APs only.
991 *
992 * Arguments:
993 *       wlandev         wlan device structure
994 *       inf             ptr to info frame (contents in hfa384x order)
995 *
996 * Returns:
997 *       nothing
998 *
999 * Side effects:
1000 *
1001 * Call context:
1002 *       interrupt
1003 ----------------------------------------------------------------*/
1004 static void prism2sta_inf_handover(wlandevice_t *wlandev, hfa384x_InfFrame_t *inf)
1005 {
1006         pr_debug("received infoframe:HANDOVER (unhandled)\n");
1007         return;
1008 }
1009
1010
1011 /*----------------------------------------------------------------
1012 * prism2sta_inf_tallies
1013 *
1014 * Handles the receipt of a CommTallies info frame.
1015 *
1016 * Arguments:
1017 *       wlandev         wlan device structure
1018 *       inf             ptr to info frame (contents in hfa384x order)
1019 *
1020 * Returns:
1021 *       nothing
1022 *
1023 * Side effects:
1024 *
1025 * Call context:
1026 *       interrupt
1027 ----------------------------------------------------------------*/
1028 static void prism2sta_inf_tallies(wlandevice_t *wlandev, hfa384x_InfFrame_t *inf)
1029 {
1030         hfa384x_t               *hw = (hfa384x_t *)wlandev->priv;
1031         u16                     *src16;
1032         u32                     *dst;
1033         u32                     *src32;
1034         int                     i;
1035         int                     cnt;
1036
1037         /*
1038         ** Determine if these are 16-bit or 32-bit tallies, based on the
1039         ** record length of the info record.
1040         */
1041
1042         cnt = sizeof(hfa384x_CommTallies32_t) / sizeof(u32);
1043         if (inf->framelen > 22) {
1044                 dst   = (u32 *) &hw->tallies;
1045                 src32 = (u32 *) &inf->info.commtallies32;
1046                 for (i = 0; i < cnt; i++, dst++, src32++)
1047                         *dst += hfa384x2host_32(*src32);
1048         } else {
1049                 dst   = (u32 *) &hw->tallies;
1050                 src16 = (u16 *) &inf->info.commtallies16;
1051                 for (i = 0; i < cnt; i++, dst++, src16++)
1052                         *dst += hfa384x2host_16(*src16);
1053         }
1054
1055         return;
1056 }
1057
1058 /*----------------------------------------------------------------
1059 * prism2sta_inf_scanresults
1060 *
1061 * Handles the receipt of a Scan Results info frame.
1062 *
1063 * Arguments:
1064 *       wlandev         wlan device structure
1065 *       inf             ptr to info frame (contents in hfa384x order)
1066 *
1067 * Returns:
1068 *       nothing
1069 *
1070 * Side effects:
1071 *
1072 * Call context:
1073 *       interrupt
1074 ----------------------------------------------------------------*/
1075 static void prism2sta_inf_scanresults(wlandevice_t *wlandev,
1076                                       hfa384x_InfFrame_t *inf)
1077 {
1078
1079         hfa384x_t               *hw = (hfa384x_t *)wlandev->priv;
1080         int                     nbss;
1081         hfa384x_ScanResult_t    *sr = &(inf->info.scanresult);
1082         int                     i;
1083         hfa384x_JoinRequest_data_t      joinreq;
1084         int                     result;
1085
1086         /* Get the number of results, first in bytes, then in results */
1087         nbss = (inf->framelen * sizeof(u16)) -
1088                 sizeof(inf->infotype) -
1089                 sizeof(inf->info.scanresult.scanreason);
1090         nbss /= sizeof(hfa384x_ScanResultSub_t);
1091
1092         /* Print em */
1093         pr_debug("rx scanresults, reason=%d, nbss=%d:\n",
1094                 inf->info.scanresult.scanreason, nbss);
1095         for ( i = 0; i < nbss; i++) {
1096                 pr_debug("chid=%d anl=%d sl=%d bcnint=%d\n",
1097                         sr->result[i].chid,
1098                         sr->result[i].anl,
1099                         sr->result[i].sl,
1100                         sr->result[i].bcnint);
1101                 pr_debug("  capinfo=0x%04x proberesp_rate=%d\n",
1102                         sr->result[i].capinfo,
1103                         sr->result[i].proberesp_rate);
1104         }
1105         /* issue a join request */
1106         joinreq.channel = sr->result[0].chid;
1107         memcpy( joinreq.bssid, sr->result[0].bssid, WLAN_BSSID_LEN);
1108         result = hfa384x_drvr_setconfig( hw,
1109                         HFA384x_RID_JOINREQUEST,
1110                         &joinreq, HFA384x_RID_JOINREQUEST_LEN);
1111         if (result) {
1112                 printk(KERN_ERR "setconfig(joinreq) failed, result=%d\n", result);
1113         }
1114
1115         return;
1116 }
1117
1118 /*----------------------------------------------------------------
1119 * prism2sta_inf_hostscanresults
1120 *
1121 * Handles the receipt of a Scan Results info frame.
1122 *
1123 * Arguments:
1124 *       wlandev         wlan device structure
1125 *       inf             ptr to info frame (contents in hfa384x order)
1126 *
1127 * Returns:
1128 *       nothing
1129 *
1130 * Side effects:
1131 *
1132 * Call context:
1133 *       interrupt
1134 ----------------------------------------------------------------*/
1135 static void prism2sta_inf_hostscanresults(wlandevice_t *wlandev,
1136                                           hfa384x_InfFrame_t *inf)
1137 {
1138         hfa384x_t               *hw = (hfa384x_t *)wlandev->priv;
1139         int                     nbss;
1140
1141         nbss = (inf->framelen - 3) / 32;
1142         pr_debug("Received %d hostscan results\n", nbss);
1143
1144         if (nbss > 32)
1145                 nbss = 32;
1146
1147         if (hw->scanresults)
1148                 kfree(hw->scanresults);
1149
1150         hw->scanresults = kmalloc(sizeof(hfa384x_InfFrame_t), GFP_ATOMIC);
1151         memcpy(hw->scanresults, inf, sizeof(hfa384x_InfFrame_t));
1152
1153         if (nbss == 0)
1154                 nbss = -1;
1155
1156         /* Notify/wake the sleeping caller. */
1157         hw->scanflag = nbss;
1158         wake_up_interruptible(&hw->cmdq);
1159 };
1160
1161 /*----------------------------------------------------------------
1162 * prism2sta_inf_chinforesults
1163 *
1164 * Handles the receipt of a Channel Info Results info frame.
1165 *
1166 * Arguments:
1167 *       wlandev         wlan device structure
1168 *       inf             ptr to info frame (contents in hfa384x order)
1169 *
1170 * Returns:
1171 *       nothing
1172 *
1173 * Side effects:
1174 *
1175 * Call context:
1176 *       interrupt
1177 ----------------------------------------------------------------*/
1178 static void prism2sta_inf_chinforesults(wlandevice_t *wlandev,
1179                                         hfa384x_InfFrame_t *inf)
1180 {
1181         hfa384x_t               *hw = (hfa384x_t *)wlandev->priv;
1182         unsigned int            i, n;
1183
1184         hw->channel_info.results.scanchannels =
1185                 hfa384x2host_16(inf->info.chinforesult.scanchannels);
1186
1187         for (i=0, n=0; i<HFA384x_CHINFORESULT_MAX; i++) {
1188                 if (hw->channel_info.results.scanchannels & (1<<i)) {
1189                         int     channel=hfa384x2host_16(inf->info.chinforesult.result[n].chid)-1;
1190                         hfa384x_ChInfoResultSub_t *chinforesult=&hw->channel_info.results.result[channel];
1191                         chinforesult->chid   = channel;
1192                         chinforesult->anl    = hfa384x2host_16(inf->info.chinforesult.result[n].anl);
1193                         chinforesult->pnl    = hfa384x2host_16(inf->info.chinforesult.result[n].pnl);
1194                         chinforesult->active = hfa384x2host_16(inf->info.chinforesult.result[n].active);
1195                         pr_debug("chinfo: channel %d, %s level (avg/peak)=%d/%d dB, pcf %d\n",
1196                                         channel+1,
1197                                         chinforesult->active &
1198                                         HFA384x_CHINFORESULT_BSSACTIVE ? "signal" : "noise",
1199                                         chinforesult->anl, chinforesult->pnl,
1200                                         chinforesult->active & HFA384x_CHINFORESULT_PCFACTIVE ? 1 : 0
1201                         );
1202                         n++;
1203                 }
1204         }
1205         atomic_set(&hw->channel_info.done, 2);
1206
1207         hw->channel_info.count = n;
1208         return;
1209 }
1210
1211 void prism2sta_processing_defer(struct work_struct *data)
1212 {
1213         hfa384x_t               *hw = container_of(data, struct hfa384x, link_bh);
1214         wlandevice_t            *wlandev = hw->wlandev;
1215         hfa384x_bytestr32_t ssid;
1216         int                     result;
1217
1218         /* First let's process the auth frames */
1219         {
1220                 struct sk_buff          *skb;
1221                 hfa384x_InfFrame_t *inf;
1222
1223                 while ( (skb = skb_dequeue(&hw->authq)) ) {
1224                         inf = (hfa384x_InfFrame_t *) skb->data;
1225                         prism2sta_inf_authreq_defer(wlandev, inf);
1226                 }
1227
1228         }
1229
1230         /* Now let's handle the linkstatus stuff */
1231         if (hw->link_status == hw->link_status_new)
1232                 goto failed;
1233
1234         hw->link_status = hw->link_status_new;
1235
1236         switch(hw->link_status) {
1237         case HFA384x_LINK_NOTCONNECTED:
1238                 /* I'm currently assuming that this is the initial link
1239                  * state.  It should only be possible immediately
1240                  * following an Enable command.
1241                  * Response:
1242                  * Block Transmits, Ignore receives of data frames
1243                  */
1244                 netif_carrier_off(wlandev->netdev);
1245
1246                 printk(KERN_INFO "linkstatus=NOTCONNECTED (unhandled)\n");
1247                 break;
1248
1249         case HFA384x_LINK_CONNECTED:
1250                 /* This one indicates a successful scan/join/auth/assoc.
1251                  * When we have the full MLME complement, this event will
1252                  * signify successful completion of both mlme_authenticate
1253                  * and mlme_associate.  State management will get a little
1254                  * ugly here.
1255                  * Response:
1256                  * Indicate authentication and/or association
1257                  * Enable Transmits, Receives and pass up data frames
1258                  */
1259
1260                 netif_carrier_on(wlandev->netdev);
1261
1262                 /* If we are joining a specific AP, set our state and reset retries */
1263                 if(hw->join_ap == 1)
1264                         hw->join_ap = 2;
1265                 hw->join_retries = 60;
1266
1267                 /* Don't call this in monitor mode */
1268                 if ( wlandev->netdev->type == ARPHRD_ETHER ) {
1269                         u16                     portstatus;
1270
1271                         printk(KERN_INFO "linkstatus=CONNECTED\n");
1272
1273                         /* For non-usb devices, we can use the sync versions */
1274                         /* Collect the BSSID, and set state to allow tx */
1275
1276                         result = hfa384x_drvr_getconfig(hw,
1277                                                         HFA384x_RID_CURRENTBSSID,
1278                                                         wlandev->bssid, WLAN_BSSID_LEN);
1279                         if ( result ) {
1280                                 pr_debug(
1281                                                "getconfig(0x%02x) failed, result = %d\n",
1282                                                HFA384x_RID_CURRENTBSSID, result);
1283                                 goto failed;
1284                         }
1285
1286                         result = hfa384x_drvr_getconfig(hw,
1287                                                         HFA384x_RID_CURRENTSSID,
1288                                                         &ssid, sizeof(ssid));
1289                         if ( result ) {
1290                                 pr_debug(
1291                                                "getconfig(0x%02x) failed, result = %d\n",
1292                                                HFA384x_RID_CURRENTSSID, result);
1293                                 goto failed;
1294                         }
1295                         prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *)&ssid,
1296                                                 (p80211pstrd_t *) &wlandev->ssid);
1297
1298                         /* Collect the port status */
1299                         result = hfa384x_drvr_getconfig16(hw,
1300                                                           HFA384x_RID_PORTSTATUS, &portstatus);
1301                         if ( result ) {
1302                                 pr_debug(
1303                                                "getconfig(0x%02x) failed, result = %d\n",
1304                                                HFA384x_RID_PORTSTATUS, result);
1305                                 goto failed;
1306                         }
1307                         wlandev->macmode =
1308                                 (portstatus == HFA384x_PSTATUS_CONN_IBSS) ?
1309                                 WLAN_MACMODE_IBSS_STA : WLAN_MACMODE_ESS_STA;
1310
1311                         /* Get the ball rolling on the comms quality stuff */
1312                         prism2sta_commsqual_defer(&hw->commsqual_bh);
1313                 }
1314                 break;
1315
1316         case HFA384x_LINK_DISCONNECTED:
1317                 /* This one indicates that our association is gone.  We've
1318                  * lost connection with the AP and/or been disassociated.
1319                  * This indicates that the MAC has completely cleared it's
1320                  * associated state.  We * should send a deauth indication
1321                  * (implying disassoc) up * to the MLME.
1322                  * Response:
1323                  * Indicate Deauthentication
1324                  * Block Transmits, Ignore receives of data frames
1325                  */
1326                 if(hw->join_ap == 2)
1327                 {
1328                         hfa384x_JoinRequest_data_t      joinreq;
1329                         joinreq = hw->joinreq;
1330                         /* Send the join request */
1331                         hfa384x_drvr_setconfig( hw,
1332                                 HFA384x_RID_JOINREQUEST,
1333                                 &joinreq, HFA384x_RID_JOINREQUEST_LEN);
1334                         printk(KERN_INFO "linkstatus=DISCONNECTED (re-submitting join)\n");
1335                 } else {
1336                         if (wlandev->netdev->type == ARPHRD_ETHER)
1337                                 printk(KERN_INFO "linkstatus=DISCONNECTED (unhandled)\n");
1338                 }
1339                 wlandev->macmode = WLAN_MACMODE_NONE;
1340
1341                 netif_carrier_off(wlandev->netdev);
1342
1343                 break;
1344
1345         case HFA384x_LINK_AP_CHANGE:
1346                 /* This one indicates that the MAC has decided to and
1347                  * successfully completed a change to another AP.  We
1348                  * should probably implement a reassociation indication
1349                  * in response to this one.  I'm thinking that the the
1350                  * p80211 layer needs to be notified in case of
1351                  * buffering/queueing issues.  User mode also needs to be
1352                  * notified so that any BSS dependent elements can be
1353                  * updated.
1354                  * associated state.  We * should send a deauth indication
1355                  * (implying disassoc) up * to the MLME.
1356                  * Response:
1357                  * Indicate Reassociation
1358                  * Enable Transmits, Receives and pass up data frames
1359                  */
1360                 printk(KERN_INFO "linkstatus=AP_CHANGE\n");
1361
1362                 result = hfa384x_drvr_getconfig(hw,
1363                                                 HFA384x_RID_CURRENTBSSID,
1364                                                 wlandev->bssid, WLAN_BSSID_LEN);
1365                 if ( result ) {
1366                         pr_debug(
1367                                        "getconfig(0x%02x) failed, result = %d\n",
1368                                        HFA384x_RID_CURRENTBSSID, result);
1369                         goto failed;
1370                 }
1371
1372                 result = hfa384x_drvr_getconfig(hw,
1373                                                 HFA384x_RID_CURRENTSSID,
1374                                                 &ssid, sizeof(ssid));
1375                 if ( result ) {
1376                         pr_debug(
1377                                        "getconfig(0x%02x) failed, result = %d\n",
1378                                        HFA384x_RID_CURRENTSSID, result);
1379                         goto failed;
1380                 }
1381                 prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *)&ssid,
1382                                         (p80211pstrd_t *) &wlandev->ssid);
1383
1384
1385                 hw->link_status = HFA384x_LINK_CONNECTED;
1386                 netif_carrier_on(wlandev->netdev);
1387
1388                 break;
1389
1390         case HFA384x_LINK_AP_OUTOFRANGE:
1391                 /* This one indicates that the MAC has decided that the
1392                  * AP is out of range, but hasn't found a better candidate
1393                  * so the MAC maintains its "associated" state in case
1394                  * we get back in range.  We should block transmits and
1395                  * receives in this state.  Do we need an indication here?
1396                  * Probably not since a polling user-mode element would
1397                  * get this status from from p2PortStatus(FD40). What about
1398                  * p80211?
1399                  * Response:
1400                  * Block Transmits, Ignore receives of data frames
1401                  */
1402                 printk(KERN_INFO "linkstatus=AP_OUTOFRANGE (unhandled)\n");
1403
1404                 netif_carrier_off(wlandev->netdev);
1405
1406                 break;
1407
1408         case HFA384x_LINK_AP_INRANGE:
1409                 /* This one indicates that the MAC has decided that the
1410                  * AP is back in range.  We continue working with our
1411                  * existing association.
1412                  * Response:
1413                  * Enable Transmits, Receives and pass up data frames
1414                  */
1415                 printk(KERN_INFO "linkstatus=AP_INRANGE\n");
1416
1417                 hw->link_status = HFA384x_LINK_CONNECTED;
1418                 netif_carrier_on(wlandev->netdev);
1419
1420                 break;
1421
1422         case HFA384x_LINK_ASSOCFAIL:
1423                 /* This one is actually a peer to CONNECTED.  We've
1424                  * requested a join for a given SSID and optionally BSSID.
1425                  * We can use this one to indicate authentication and
1426                  * association failures.  The trick is going to be
1427                  * 1) identifying the failure, and 2) state management.
1428                  * Response:
1429                  * Disable Transmits, Ignore receives of data frames
1430                  */
1431                 if(hw->join_ap && --hw->join_retries > 0)
1432                 {
1433                         hfa384x_JoinRequest_data_t      joinreq;
1434                         joinreq = hw->joinreq;
1435                         /* Send the join request */
1436                         hfa384x_drvr_setconfig( hw,
1437                                 HFA384x_RID_JOINREQUEST,
1438                                 &joinreq, HFA384x_RID_JOINREQUEST_LEN);
1439                         printk(KERN_INFO "linkstatus=ASSOCFAIL (re-submitting join)\n");
1440                 } else {
1441                         printk(KERN_INFO "linkstatus=ASSOCFAIL (unhandled)\n");
1442                 }
1443
1444                 netif_carrier_off(wlandev->netdev);
1445
1446                 break;
1447
1448         default:
1449                 /* This is bad, IO port problems? */
1450                 printk(KERN_WARNING
1451                         "unknown linkstatus=0x%02x\n", hw->link_status);
1452                 goto failed;
1453                 break;
1454         }
1455
1456         wlandev->linkstatus = (hw->link_status == HFA384x_LINK_CONNECTED);
1457 #ifdef WIRELESS_EXT
1458         p80211wext_event_associated(wlandev, wlandev->linkstatus);
1459 #endif
1460
1461  failed:
1462         return;
1463 }
1464
1465 /*----------------------------------------------------------------
1466 * prism2sta_inf_linkstatus
1467 *
1468 * Handles the receipt of a Link Status info frame.
1469 *
1470 * Arguments:
1471 *       wlandev         wlan device structure
1472 *       inf             ptr to info frame (contents in hfa384x order)
1473 *
1474 * Returns:
1475 *       nothing
1476 *
1477 * Side effects:
1478 *
1479 * Call context:
1480 *       interrupt
1481 ----------------------------------------------------------------*/
1482 static void prism2sta_inf_linkstatus(wlandevice_t *wlandev,
1483                                      hfa384x_InfFrame_t *inf)
1484 {
1485         hfa384x_t               *hw = (hfa384x_t *)wlandev->priv;
1486
1487         hw->link_status_new = hfa384x2host_16(inf->info.linkstatus.linkstatus);
1488
1489         schedule_work(&hw->link_bh);
1490
1491         return;
1492 }
1493
1494 /*----------------------------------------------------------------
1495 * prism2sta_inf_assocstatus
1496 *
1497 * Handles the receipt of an Association Status info frame. Should
1498 * be present in APs only.
1499 *
1500 * Arguments:
1501 *       wlandev         wlan device structure
1502 *       inf             ptr to info frame (contents in hfa384x order)
1503 *
1504 * Returns:
1505 *       nothing
1506 *
1507 * Side effects:
1508 *
1509 * Call context:
1510 *       interrupt
1511 ----------------------------------------------------------------*/
1512 static void prism2sta_inf_assocstatus(wlandevice_t *wlandev,
1513                                       hfa384x_InfFrame_t *inf)
1514 {
1515         hfa384x_t               *hw = (hfa384x_t *)wlandev->priv;
1516         hfa384x_AssocStatus_t   rec;
1517         int                     i;
1518
1519         memcpy(&rec, &inf->info.assocstatus, sizeof(rec));
1520         rec.assocstatus = hfa384x2host_16(rec.assocstatus);
1521         rec.reason      = hfa384x2host_16(rec.reason);
1522
1523         /*
1524         ** Find the address in the list of authenticated stations.  If it wasn't
1525         ** found, then this address has not been previously authenticated and
1526         ** something weird has happened if this is anything other than an
1527         ** "authentication failed" message.  If the address was found, then
1528         ** set the "associated" flag for that station, based on whether the
1529         ** station is associating or losing its association.  Something weird
1530         ** has also happened if we find the address in the list of authenticated
1531         ** stations but we are getting an "authentication failed" message.
1532         */
1533
1534         for (i = 0; i < hw->authlist.cnt; i++)
1535                 if (memcmp(rec.sta_addr, hw->authlist.addr[i], ETH_ALEN) == 0)
1536                         break;
1537
1538         if (i >= hw->authlist.cnt) {
1539                 if (rec.assocstatus != HFA384x_ASSOCSTATUS_AUTHFAIL)
1540                         printk(KERN_WARNING "assocstatus info frame received for non-authenticated station.\n");
1541         } else {
1542                 hw->authlist.assoc[i] =
1543                         (rec.assocstatus == HFA384x_ASSOCSTATUS_STAASSOC ||
1544                          rec.assocstatus == HFA384x_ASSOCSTATUS_REASSOC);
1545
1546                 if (rec.assocstatus == HFA384x_ASSOCSTATUS_AUTHFAIL)
1547                         printk(KERN_WARNING "authfail assocstatus info frame received for authenticated station.\n");
1548         }
1549
1550         return;
1551 }
1552
1553 /*----------------------------------------------------------------
1554 * prism2sta_inf_authreq
1555 *
1556 * Handles the receipt of an Authentication Request info frame. Should
1557 * be present in APs only.
1558 *
1559 * Arguments:
1560 *       wlandev         wlan device structure
1561 *       inf             ptr to info frame (contents in hfa384x order)
1562 *
1563 * Returns:
1564 *       nothing
1565 *
1566 * Side effects:
1567 *
1568 * Call context:
1569 *       interrupt
1570 *
1571 ----------------------------------------------------------------*/
1572 static void prism2sta_inf_authreq(wlandevice_t *wlandev,
1573                                   hfa384x_InfFrame_t *inf)
1574 {
1575         hfa384x_t               *hw = (hfa384x_t *)wlandev->priv;
1576         struct sk_buff *skb;
1577
1578         skb = dev_alloc_skb(sizeof(*inf));
1579         if (skb) {
1580                 skb_put(skb, sizeof(*inf));
1581                 memcpy(skb->data, inf, sizeof(*inf));
1582                 skb_queue_tail(&hw->authq, skb);
1583                 schedule_work(&hw->link_bh);
1584         }
1585 }
1586
1587 static void prism2sta_inf_authreq_defer(wlandevice_t *wlandev,
1588                                         hfa384x_InfFrame_t *inf)
1589 {
1590         hfa384x_t               *hw = (hfa384x_t *)wlandev->priv;
1591         hfa384x_authenticateStation_data_t  rec;
1592
1593         int    i, added, result, cnt;
1594         u8  *addr;
1595
1596         /*
1597         ** Build the AuthenticateStation record.  Initialize it for denying
1598         ** authentication.
1599         */
1600
1601         memcpy(rec.address, inf->info.authreq.sta_addr, ETH_ALEN);
1602         rec.status = P80211ENUM_status_unspec_failure;
1603
1604         /*
1605         ** Authenticate based on the access mode.
1606         */
1607
1608         switch (hw->accessmode) {
1609                 case WLAN_ACCESS_NONE:
1610
1611                         /*
1612                         ** Deny all new authentications.  However, if a station
1613                         ** is ALREADY authenticated, then accept it.
1614                         */
1615
1616                         for (i = 0; i < hw->authlist.cnt; i++)
1617                                 if (memcmp(rec.address, hw->authlist.addr[i],
1618                                                 ETH_ALEN) == 0) {
1619                                         rec.status = P80211ENUM_status_successful;
1620                                         break;
1621                                 }
1622
1623                         break;
1624
1625                 case WLAN_ACCESS_ALL:
1626
1627                         /*
1628                         ** Allow all authentications.
1629                         */
1630
1631                         rec.status = P80211ENUM_status_successful;
1632                         break;
1633
1634                 case WLAN_ACCESS_ALLOW:
1635
1636                         /*
1637                         ** Only allow the authentication if the MAC address
1638                         ** is in the list of allowed addresses.
1639                         **
1640                         ** Since this is the interrupt handler, we may be here
1641                         ** while the access list is in the middle of being
1642                         ** updated.  Choose the list which is currently okay.
1643                         ** See "prism2mib_priv_accessallow()" for details.
1644                         */
1645
1646                         if (hw->allow.modify == 0) {
1647                                 cnt  = hw->allow.cnt;
1648                                 addr = hw->allow.addr[0];
1649                         } else {
1650                                 cnt  = hw->allow.cnt1;
1651                                 addr = hw->allow.addr1[0];
1652                         }
1653
1654                         for (i = 0; i < cnt; i++, addr += ETH_ALEN)
1655                                 if (memcmp(rec.address, addr, ETH_ALEN) == 0) {
1656                                         rec.status = P80211ENUM_status_successful;
1657                                         break;
1658                                 }
1659
1660                         break;
1661
1662                 case WLAN_ACCESS_DENY:
1663
1664                         /*
1665                         ** Allow the authentication UNLESS the MAC address is
1666                         ** in the list of denied addresses.
1667                         **
1668                         ** Since this is the interrupt handler, we may be here
1669                         ** while the access list is in the middle of being
1670                         ** updated.  Choose the list which is currently okay.
1671                         ** See "prism2mib_priv_accessdeny()" for details.
1672                         */
1673
1674                         if (hw->deny.modify == 0) {
1675                                 cnt  = hw->deny.cnt;
1676                                 addr = hw->deny.addr[0];
1677                         } else {
1678                                 cnt  = hw->deny.cnt1;
1679                                 addr = hw->deny.addr1[0];
1680                         }
1681
1682                         rec.status = P80211ENUM_status_successful;
1683
1684                         for (i = 0; i < cnt; i++, addr += ETH_ALEN)
1685                                 if (memcmp(rec.address, addr, ETH_ALEN) == 0) {
1686                                         rec.status = P80211ENUM_status_unspec_failure;
1687                                         break;
1688                                 }
1689
1690                         break;
1691         }
1692
1693         /*
1694         ** If the authentication is okay, then add the MAC address to the list
1695         ** of authenticated stations.  Don't add the address if it is already in
1696         ** the list.  (802.11b does not seem to disallow a station from issuing
1697         ** an authentication request when the station is already authenticated.
1698         ** Does this sort of thing ever happen?  We might as well do the check
1699         ** just in case.)
1700         */
1701
1702         added = 0;
1703
1704         if (rec.status == P80211ENUM_status_successful) {
1705                 for (i = 0; i < hw->authlist.cnt; i++)
1706                         if (memcmp(rec.address, hw->authlist.addr[i], ETH_ALEN) == 0)
1707                                 break;
1708
1709                 if (i >= hw->authlist.cnt) {
1710                         if (hw->authlist.cnt >= WLAN_AUTH_MAX) {
1711                                 rec.status = P80211ENUM_status_ap_full;
1712                         } else {
1713                                 memcpy(hw->authlist.addr[hw->authlist.cnt],
1714                                         rec.address, ETH_ALEN);
1715                                 hw->authlist.cnt++;
1716                                 added = 1;
1717                         }
1718                 }
1719         }
1720
1721         /*
1722         ** Send back the results of the authentication.  If this doesn't work,
1723         ** then make sure to remove the address from the authenticated list if
1724         ** it was added.
1725         */
1726
1727         rec.status = host2hfa384x_16(rec.status);
1728         rec.algorithm = inf->info.authreq.algorithm;
1729
1730         result = hfa384x_drvr_setconfig(hw, HFA384x_RID_AUTHENTICATESTA,
1731                                                         &rec, sizeof(rec));
1732         if (result) {
1733                 if (added) hw->authlist.cnt--;
1734                 printk(KERN_ERR "setconfig(authenticatestation) failed, result=%d\n", result);
1735         }
1736         return;
1737 }
1738
1739
1740 /*----------------------------------------------------------------
1741 * prism2sta_inf_psusercnt
1742 *
1743 * Handles the receipt of a PowerSaveUserCount info frame. Should
1744 * be present in APs only.
1745 *
1746 * Arguments:
1747 *       wlandev         wlan device structure
1748 *       inf             ptr to info frame (contents in hfa384x order)
1749 *
1750 * Returns:
1751 *       nothing
1752 *
1753 * Side effects:
1754 *
1755 * Call context:
1756 *       interrupt
1757 ----------------------------------------------------------------*/
1758 static void prism2sta_inf_psusercnt(wlandevice_t *wlandev,
1759                                     hfa384x_InfFrame_t *inf)
1760 {
1761         hfa384x_t               *hw = (hfa384x_t *)wlandev->priv;
1762
1763         hw->psusercount = hfa384x2host_16(inf->info.psusercnt.usercnt);
1764
1765         return;
1766 }
1767
1768 /*----------------------------------------------------------------
1769 * prism2sta_ev_info
1770 *
1771 * Handles the Info event.
1772 *
1773 * Arguments:
1774 *       wlandev         wlan device structure
1775 *       inf             ptr to a generic info frame
1776 *
1777 * Returns:
1778 *       nothing
1779 *
1780 * Side effects:
1781 *
1782 * Call context:
1783 *       interrupt
1784 ----------------------------------------------------------------*/
1785 void prism2sta_ev_info(wlandevice_t *wlandev, hfa384x_InfFrame_t *inf)
1786 {
1787         inf->infotype = hfa384x2host_16(inf->infotype);
1788         /* Dispatch */
1789         switch ( inf->infotype ) {
1790                 case HFA384x_IT_HANDOVERADDR:
1791                         prism2sta_inf_handover(wlandev, inf);
1792                         break;
1793                 case HFA384x_IT_COMMTALLIES:
1794                         prism2sta_inf_tallies(wlandev, inf);
1795                         break;
1796                case HFA384x_IT_HOSTSCANRESULTS:
1797                         prism2sta_inf_hostscanresults(wlandev, inf);
1798                         break;
1799                 case HFA384x_IT_SCANRESULTS:
1800                         prism2sta_inf_scanresults(wlandev, inf);
1801                         break;
1802                 case HFA384x_IT_CHINFORESULTS:
1803                         prism2sta_inf_chinforesults(wlandev, inf);
1804                         break;
1805                 case HFA384x_IT_LINKSTATUS:
1806                         prism2sta_inf_linkstatus(wlandev, inf);
1807                         break;
1808                 case HFA384x_IT_ASSOCSTATUS:
1809                         prism2sta_inf_assocstatus(wlandev, inf);
1810                         break;
1811                 case HFA384x_IT_AUTHREQ:
1812                         prism2sta_inf_authreq(wlandev, inf);
1813                         break;
1814                 case HFA384x_IT_PSUSERCNT:
1815                         prism2sta_inf_psusercnt(wlandev, inf);
1816                         break;
1817                 case HFA384x_IT_KEYIDCHANGED:
1818                         printk(KERN_WARNING "Unhandled IT_KEYIDCHANGED\n");
1819                         break;
1820                 case HFA384x_IT_ASSOCREQ:
1821                         printk(KERN_WARNING "Unhandled IT_ASSOCREQ\n");
1822                         break;
1823                 case HFA384x_IT_MICFAILURE:
1824                         printk(KERN_WARNING "Unhandled IT_MICFAILURE\n");
1825                         break;
1826                 default:
1827                         printk(KERN_WARNING
1828                                 "Unknown info type=0x%02x\n", inf->infotype);
1829                         break;
1830         }
1831         return;
1832 }
1833
1834
1835 /*----------------------------------------------------------------
1836 * prism2sta_ev_txexc
1837 *
1838 * Handles the TxExc event.  A Transmit Exception event indicates
1839 * that the MAC's TX process was unsuccessful - so the packet did
1840 * not get transmitted.
1841 *
1842 * Arguments:
1843 *       wlandev         wlan device structure
1844 *       status          tx frame status word
1845 *
1846 * Returns:
1847 *       nothing
1848 *
1849 * Side effects:
1850 *
1851 * Call context:
1852 *       interrupt
1853 ----------------------------------------------------------------*/
1854 void prism2sta_ev_txexc(wlandevice_t *wlandev, u16 status)
1855 {
1856         pr_debug("TxExc status=0x%x.\n", status);
1857
1858         return;
1859 }
1860
1861
1862 /*----------------------------------------------------------------
1863 * prism2sta_ev_tx
1864 *
1865 * Handles the Tx event.
1866 *
1867 * Arguments:
1868 *       wlandev         wlan device structure
1869 *       status          tx frame status word
1870 * Returns:
1871 *       nothing
1872 *
1873 * Side effects:
1874 *
1875 * Call context:
1876 *       interrupt
1877 ----------------------------------------------------------------*/
1878 void prism2sta_ev_tx(wlandevice_t *wlandev, u16 status)
1879 {
1880         pr_debug("Tx Complete, status=0x%04x\n", status);
1881         /* update linux network stats */
1882         wlandev->linux_stats.tx_packets++;
1883         return;
1884 }
1885
1886
1887 /*----------------------------------------------------------------
1888 * prism2sta_ev_rx
1889 *
1890 * Handles the Rx event.
1891 *
1892 * Arguments:
1893 *       wlandev         wlan device structure
1894 *
1895 * Returns:
1896 *       nothing
1897 *
1898 * Side effects:
1899 *
1900 * Call context:
1901 *       interrupt
1902 ----------------------------------------------------------------*/
1903 void prism2sta_ev_rx(wlandevice_t *wlandev, struct sk_buff *skb)
1904 {
1905         p80211netdev_rx(wlandev, skb);
1906         return;
1907 }
1908
1909 /*----------------------------------------------------------------
1910 * prism2sta_ev_alloc
1911 *
1912 * Handles the Alloc event.
1913 *
1914 * Arguments:
1915 *       wlandev         wlan device structure
1916 *
1917 * Returns:
1918 *       nothing
1919 *
1920 * Side effects:
1921 *
1922 * Call context:
1923 *       interrupt
1924 ----------------------------------------------------------------*/
1925 void prism2sta_ev_alloc(wlandevice_t *wlandev)
1926 {
1927         netif_wake_queue(wlandev->netdev);
1928         return;
1929 }
1930
1931 /*----------------------------------------------------------------
1932 * create_wlan
1933 *
1934 * Called at module init time.  This creates the wlandevice_t structure
1935 * and initializes it with relevant bits.
1936 *
1937 * Arguments:
1938 *       none
1939 *
1940 * Returns:
1941 *       the created wlandevice_t structure.
1942 *
1943 * Side effects:
1944 *       also allocates the priv/hw structures.
1945 *
1946 * Call context:
1947 *       process thread
1948 *
1949 ----------------------------------------------------------------*/
1950 static wlandevice_t *create_wlan(void)
1951 {
1952         wlandevice_t    *wlandev = NULL;
1953         hfa384x_t       *hw = NULL;
1954
1955         /* Alloc our structures */
1956         wlandev =       kmalloc(sizeof(wlandevice_t), GFP_KERNEL);
1957         hw =            kmalloc(sizeof(hfa384x_t), GFP_KERNEL);
1958
1959         if (!wlandev || !hw) {
1960                 printk(KERN_ERR "%s: Memory allocation failure.\n", dev_info);
1961                 if (wlandev)    kfree(wlandev);
1962                 if (hw)         kfree(hw);
1963                 return NULL;
1964         }
1965
1966         /* Clear all the structs */
1967         memset(wlandev, 0, sizeof(wlandevice_t));
1968         memset(hw, 0, sizeof(hfa384x_t));
1969
1970         /* Initialize the network device object. */
1971         wlandev->nsdname = dev_info;
1972         wlandev->msdstate = WLAN_MSD_HWPRESENT_PENDING;
1973         wlandev->priv = hw;
1974         wlandev->open = prism2sta_open;
1975         wlandev->close = prism2sta_close;
1976         wlandev->reset = prism2sta_reset;
1977         wlandev->txframe = prism2sta_txframe;
1978         wlandev->mlmerequest = prism2sta_mlmerequest;
1979         wlandev->set_multicast_list = prism2sta_setmulticast;
1980         wlandev->tx_timeout = hfa384x_tx_timeout;
1981
1982         wlandev->nsdcaps = P80211_NSDCAP_HWFRAGMENT |
1983                            P80211_NSDCAP_AUTOJOIN;
1984
1985         /* Initialize the device private data stucture. */
1986         hw->dot11_desired_bss_type = 1;
1987
1988         return wlandev;
1989 }
1990
1991 void prism2sta_commsqual_defer(struct work_struct *data)
1992 {
1993         hfa384x_t               *hw = container_of(data, struct hfa384x, commsqual_bh);
1994         wlandevice_t            *wlandev = hw->wlandev;
1995         hfa384x_bytestr32_t ssid;
1996         int result = 0;
1997
1998         if (hw->wlandev->hwremoved)
1999                 goto done;
2000
2001         /* we don't care if we're in AP mode */
2002         if ((wlandev->macmode == WLAN_MACMODE_NONE) ||
2003             (wlandev->macmode == WLAN_MACMODE_ESS_AP)) {
2004                 goto done;
2005         }
2006
2007         /* It only makes sense to poll these in non-IBSS */
2008         if (wlandev->macmode != WLAN_MACMODE_IBSS_STA) {
2009                 result = hfa384x_drvr_getconfig(hw, HFA384x_RID_DBMCOMMSQUALITY,
2010                                                 &hw->qual,
2011                                                 HFA384x_RID_DBMCOMMSQUALITY_LEN);
2012
2013                 if (result) {
2014                         printk(KERN_ERR "error fetching commsqual\n");
2015                         goto done;
2016                 }
2017
2018                 // qual.CQ_currBSS; // link
2019                 // ASL_currBSS;  // level
2020                 // qual.ANL_currFC; // noise
2021
2022                 pr_debug("commsqual %d %d %d\n",
2023                                hfa384x2host_16(hw->qual.CQ_currBSS),
2024                                hfa384x2host_16(hw->qual.ASL_currBSS),
2025                                hfa384x2host_16(hw->qual.ANL_currFC));
2026         }
2027
2028         /* Lastly, we need to make sure the BSSID didn't change on us */
2029         result = hfa384x_drvr_getconfig(hw,
2030                                         HFA384x_RID_CURRENTBSSID,
2031                                         wlandev->bssid, WLAN_BSSID_LEN);
2032         if ( result ) {
2033                 pr_debug(
2034                                "getconfig(0x%02x) failed, result = %d\n",
2035                                HFA384x_RID_CURRENTBSSID, result);
2036                 goto done;
2037         }
2038
2039         result = hfa384x_drvr_getconfig(hw,
2040                                         HFA384x_RID_CURRENTSSID,
2041                                         &ssid, sizeof(ssid));
2042         if ( result ) {
2043                 pr_debug(
2044                                "getconfig(0x%02x) failed, result = %d\n",
2045                                HFA384x_RID_CURRENTSSID, result);
2046                 goto done;
2047         }
2048         prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *)&ssid,
2049                                 (p80211pstrd_t *) &wlandev->ssid);
2050
2051
2052         /* Reschedule timer */
2053         mod_timer(&hw->commsqual_timer, jiffies + HZ);
2054
2055  done:
2056         ;
2057 }
2058
2059 void prism2sta_commsqual_timer(unsigned long data)
2060 {
2061         hfa384x_t               *hw = (hfa384x_t *) data;
2062
2063         schedule_work(&hw->commsqual_bh);
2064 }
2065
2066