df373d3876964d22d756804e9f9b0c132c482eac
[people/xl0/gpxe.git] / src / drivers / net / prism2.c
1 /**************************************************************************
2 Etherboot -  BOOTP/TFTP Bootstrap Program
3 Prism2 NIC driver for Etherboot
4
5 Written by Michael Brown of Fen Systems Ltd
6 $Id$
7 ***************************************************************************/
8
9 /*
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License as
12  * published by the Free Software Foundation; either version 2, or (at
13  * your option) any later version.
14  */
15
16 /* to get some global routines like printf */
17 #include "etherboot.h"
18 /* to get the interface to the body of the program */
19 #include "nic.h"
20 /* to get the PCI support functions, if this is a PCI NIC */
21 #include "pci.h"
22
23 /*
24  * Hard-coded SSID
25  * Leave blank in order to connect to any available SSID
26  */
27
28 static const char hardcoded_ssid[] = "";
29
30 /*
31  * Maximum number of info packets to wait for on a join attempt.
32  * Some APs (including the Linksys WAP11) will send a "you are disconnected" packet
33  * before sending the "you are connected" packet, if the card has previously been
34  * attached to the AP.
35  *
36  * 2 is probably a sensible value, but YMMV.
37  */
38
39 #define MAX_JOIN_INFO_COUNT 2
40
41 /*
42  * Type of Prism2 interface to support
43  * If not already defined, select PLX
44  */
45 #ifndef WLAN_HOSTIF
46 #define WLAN_HOSTIF WLAN_PLX
47 #endif
48
49 /*
50  * Include wlan_compat, p80211 and hfa384x header files from Linux Prism2 driver
51  * We need to hack some defines in order to avoid compiling kernel-specific routines
52  */
53
54 #define __LINUX_WLAN__
55 #undef __KERNEL__
56 #define __I386__
57 #include "wlan_compat.h"
58 #include "p80211hdr.h"
59 #include "hfa384x.h"
60 #define BAP_TIMEOUT ( 5000 )
61
62 /*
63  * A few hacks to make the coding environment more Linux-like.  This makes it somewhat
64  * quicker to convert code from the Linux Prism2 driver.
65  */
66 #include <errno.h>
67 #include "timer.h"
68 #define __le16_to_cpu(x) (x)
69 #define __le32_to_cpu(x) (x)
70 #define __cpu_to_le16(x) (x)
71 #define __cpu_to_le32(x) (x)
72
73 /*
74  * PLX9052 PCI register offsets
75  * Taken from PLX9052 datasheet available from http://www.plxtech.com/download/9052/databook/9052db-20.pdf
76  */
77
78 #define PLX_LOCAL_CONFIG_REGISTER_BASE ( PCI_BASE_ADDRESS_1 )
79 #define PLX_LOCAL_ADDRESS_SPACE_0_BASE ( PCI_BASE_ADDRESS_2 )
80 #define PLX_LOCAL_ADDRESS_SPACE_1_BASE ( PCI_BASE_ADDRESS_3 )
81 #define PLX_LOCAL_ADDRESS_SPACE_2_BASE ( PCI_BASE_ADDRESS_4 )
82 #define PLX_LOCAL_ADDRESS_SPACE_3_BASE ( PCI_BASE_ADDRESS_5 )
83
84 #define PRISM2_PLX_ATTR_MEM_BASE       ( PLX_LOCAL_ADDRESS_SPACE_0_BASE )
85 #define PRISM2_PLX_IO_BASE             ( PLX_LOCAL_ADDRESS_SPACE_1_BASE )
86
87 #define PRISM2_PCI_MEM_BASE            ( PCI_BASE_ADDRESS_0 )
88
89 /*
90  * PCMCIA CIS types
91  * Taken from cistpl.h in pcmcia-cs
92  */
93
94 #define CISTPL_VERS_1           ( 0x15 )
95 #define CISTPL_END              ( 0xff )
96
97 #define CIS_STEP                ( 2 )
98 #define CISTPL_HEADER_LEN       ( 2 * CIS_STEP )
99 #define CISTPL_LEN_OFF          ( 1 * CIS_STEP )
100 #define CISTPL_VERS_1_STR_OFF   ( 4 * CIS_STEP )
101
102 /*
103  * Prism2 constants
104  * Taken from prism2sta.c in linux-wlan-ng
105  */
106
107 #define COR_OFFSET      ( 0x3e0 )   /* COR attribute offset of Prism2 PC card */
108 #define COR_VALUE       ( 0x41 )    /* Enable PC card with irq in level trigger (but interrupts disabled) */
109
110 /* NIC specific static variables */
111
112 /* The hfa384x_t structure is used extensively in the Linux driver but is ifdef'd out in our include since __KERNEL__ is not defined.
113  * This is a dummy version that contains only the fields we are interested in.
114  */
115
116 typedef struct hfa384x
117 {
118   UINT32 iobase;
119   UINT32 membase;
120   UINT16 lastcmd;
121   UINT16 status;         /* in host order */
122   UINT16 resp0;          /* in host order */
123   UINT16 resp1;          /* in host order */
124   UINT16 resp2;          /* in host order */
125   UINT8  bssid[WLAN_BSSID_LEN];
126 } hfa384x_t;
127
128 /* The global instance of the hardware (i.e. where we store iobase and membase, in the absence of anywhere better to put them */
129 static hfa384x_t hw_global = {
130   0, 0, 0, 0, 0, 0, 0, {0,0,0,0,0,0}
131 };
132
133 /*
134  * 802.11 headers in addition to those in hfa384x_tx_frame_t (LLC and SNAP)
135  * Taken from p80211conv.h
136  */
137
138 typedef struct wlan_llc
139 {
140   UINT8   dsap                            __WLAN_ATTRIB_PACK__;
141   UINT8   ssap                            __WLAN_ATTRIB_PACK__;
142   UINT8   ctl                             __WLAN_ATTRIB_PACK__;
143 } __WLAN_ATTRIB_PACK__ wlan_llc_t;
144
145 static const wlan_llc_t wlan_llc_snap = { 0xaa, 0xaa, 0x03 }; /* LLC header indicating SNAP (?) */
146
147 #define WLAN_IEEE_OUI_LEN 3
148 typedef struct wlan_snap
149 {
150   UINT8   oui[WLAN_IEEE_OUI_LEN]          __WLAN_ATTRIB_PACK__;
151   UINT16  type                            __WLAN_ATTRIB_PACK__;
152 } __WLAN_ATTRIB_PACK__ wlan_snap_t;
153
154 typedef struct wlan_80211hdr
155 {
156   wlan_llc_t llc;
157   wlan_snap_t snap;
158 } wlan_80211hdr_t;
159
160 /*
161  * Function prototypes
162  */
163
164 #if (WLAN_HOSTIF == WLAN_PLX)
165 static int prism2_find_plx ( hfa384x_t *hw, struct pci_device *p );
166 #elif (WLAN_HOSTIF == WLAN_PCI)
167 static int prism2_find_pci ( hfa384x_t *hw, struct pci_device *p );
168 #endif
169
170 /*
171  * Hardware-level hfa384x functions
172  * These are based on the ones in hfa384x.h (which are ifdef'd out since __KERNEL__ is not defined).
173  * Basically, these functions are the result of hand-evaluating all the ifdefs and defines in the hfa384x.h versions. 
174  */
175
176 /* Retrieve the value of one of the MAC registers. */
177 static inline UINT16 hfa384x_getreg( hfa384x_t *hw, UINT reg )
178 {
179 #if (WLAN_HOSTIF == WLAN_PLX)
180   return inw ( hw->iobase + reg );
181 #elif (WLAN_HOSTIF == WLAN_PCI)
182   return readw ( hw->membase + reg );
183 #endif
184 }
185
186 /* Set the value of one of the MAC registers. */
187 static inline void hfa384x_setreg( hfa384x_t *hw, UINT16 val, UINT reg )
188 {
189 #if (WLAN_HOSTIF == WLAN_PLX)
190   outw ( val, hw->iobase + reg );
191 #elif (WLAN_HOSTIF == WLAN_PCI)
192   writew ( val, hw->membase + reg );
193 #endif
194   return;
195 }
196
197 /* 
198  * Noswap versions
199  * Etherboot is i386 only, so swap and noswap are the same...
200  */
201 static inline UINT16 hfa384x_getreg_noswap( hfa384x_t *hw, UINT reg )
202 {
203   return hfa384x_getreg ( hw, reg );
204 }
205 static inline void hfa384x_setreg_noswap( hfa384x_t *hw, UINT16 val, UINT reg )
206 {
207   hfa384x_setreg ( hw, val, reg );
208 }
209
210 /*
211  * Low-level hfa384x functions
212  * These are based on the ones in hfa384x.c, modified to work in the Etherboot environment.
213  */
214
215 /*
216  * hfa384x_docmd_wait
217  *
218  * Waits for availability of the Command register, then
219  * issues the given command.  Then polls the Evstat register
220  * waiting for command completion.
221  * Arguments:
222  *       hw              device structure
223  *       cmd             Command in host order
224  *       parm0           Parameter0 in host order
225  *       parm1           Parameter1 in host order
226  *       parm2           Parameter2 in host order
227  * Returns:
228  *       0               success
229  *       >0              command indicated error, Status and Resp0-2 are
230  *                       in hw structure.
231  */
232 static int hfa384x_docmd_wait( hfa384x_t *hw, UINT16 cmd, UINT16 parm0, UINT16 parm1, UINT16 parm2)
233 {
234   UINT16 reg = 0;
235   UINT16 counter = 0;
236   
237   /* wait for the busy bit to clear */  
238   counter = 0;
239   reg = hfa384x_getreg(hw, HFA384x_CMD);
240   while ( HFA384x_CMD_ISBUSY(reg) && (counter < 10) ) {
241     reg = hfa384x_getreg(hw, HFA384x_CMD);
242     counter++;
243     udelay(10);
244   }
245   if (HFA384x_CMD_ISBUSY(reg)) {
246     printf("hfa384x_cmd timeout(1), reg=0x%0hx.\n", reg);
247     return -ETIMEDOUT;
248   }
249
250   /* busy bit clear, write command */
251   hfa384x_setreg(hw, parm0, HFA384x_PARAM0);
252   hfa384x_setreg(hw, parm1, HFA384x_PARAM1);
253   hfa384x_setreg(hw, parm2, HFA384x_PARAM2);
254   hw->lastcmd = cmd;
255   hfa384x_setreg(hw, cmd, HFA384x_CMD);
256   
257   /* Now wait for completion */
258   counter = 0;
259   reg = hfa384x_getreg(hw, HFA384x_EVSTAT);
260   /* Initialization is the problem.  It takes about
261      100ms. "normal" commands are typically is about
262      200-400 us (I've never seen less than 200).  Longer
263      is better so that we're not hammering the bus. */
264   while ( !HFA384x_EVSTAT_ISCMD(reg) && (counter < 5000)) {
265     reg = hfa384x_getreg(hw, HFA384x_EVSTAT);
266     counter++;
267     udelay(200);
268   }
269   if ( ! HFA384x_EVSTAT_ISCMD(reg) ) {
270     printf("hfa384x_cmd timeout(2), reg=0x%0hx.\n", reg);
271     return -ETIMEDOUT;
272   }
273
274   /* Read status and response */
275   hw->status = hfa384x_getreg(hw, HFA384x_STATUS);
276   hw->resp0 = hfa384x_getreg(hw, HFA384x_RESP0);
277   hw->resp1 = hfa384x_getreg(hw, HFA384x_RESP1);
278   hw->resp2 = hfa384x_getreg(hw, HFA384x_RESP2);
279   hfa384x_setreg(hw, HFA384x_EVACK_CMD, HFA384x_EVACK);
280   return HFA384x_STATUS_RESULT_GET(hw->status);
281 }
282
283 /*
284  * Prepare BAP for access.  Assigns FID and RID, sets offset register
285  * and waits for BAP to become available.
286  *
287  * Arguments:
288  *      hw              device structure
289  *      id              FID or RID, destined for the select register (host order)
290  *      offset          An _even_ offset into the buffer for the given FID/RID.
291  * Returns: 
292  *      0               success
293  */
294 static int hfa384x_prepare_bap(hfa384x_t *hw, UINT16 id, UINT16 offset)
295 {
296   int result = 0;
297   UINT16 reg;
298   UINT16 i;
299
300   /* Validate offset, buf, and len */
301   if ( (offset > HFA384x_BAP_OFFSET_MAX) || (offset % 2) ) {
302     result = -EINVAL;
303   } else {
304     /* Write fid/rid and offset */
305     hfa384x_setreg(hw, id, HFA384x_SELECT0);
306     udelay(10);
307     hfa384x_setreg(hw, offset, HFA384x_OFFSET0);
308     /* Wait for offset[busy] to clear (see BAP_TIMEOUT) */
309     i = 0; 
310     do {
311       reg = hfa384x_getreg(hw, HFA384x_OFFSET0);
312       if ( i > 0 ) udelay(2);
313       i++;
314     } while ( i < BAP_TIMEOUT && HFA384x_OFFSET_ISBUSY(reg));
315     if ( i >= BAP_TIMEOUT ) {
316       /* failure */
317       result = reg;
318     } else if ( HFA384x_OFFSET_ISERR(reg) ){
319       /* failure */
320       result = reg;
321     }
322   }
323   return result;
324 }
325
326 /*
327  * Copy data from BAP to memory.
328  *
329  * Arguments:
330  *      hw              device structure
331  *      id              FID or RID, destined for the select register (host order)
332  *      offset          An _even_ offset into the buffer for the given FID/RID.
333  *      buf             ptr to array of bytes
334  *      len             length of data to transfer in bytes
335  * Returns: 
336  *      0               success
337  */
338 static int hfa384x_copy_from_bap(hfa384x_t *hw, UINT16 id, UINT16 offset,
339                           void *buf, UINT len)
340 {
341   int result = 0;
342   UINT8 *d = (UINT8*)buf;
343   UINT16 i;
344   UINT16 reg = 0;
345   
346   /* Prepare BAP */
347   result = hfa384x_prepare_bap ( hw, id, offset );
348   if ( result == 0 ) {
349     /* Read even(len) buf contents from data reg */
350     for ( i = 0; i < (len & 0xfffe); i+=2 ) {
351       *(UINT16*)(&(d[i])) = hfa384x_getreg_noswap(hw, HFA384x_DATA0);
352     }
353     /* If len odd, handle last byte */
354     if ( len % 2 ){
355       reg = hfa384x_getreg_noswap(hw, HFA384x_DATA0);
356       d[len-1] = ((UINT8*)(&reg))[0];
357     }
358   }
359   if (result) {
360     printf ( "copy_from_bap(%#hx, %#hx, %d) failed, result=%#hx\n", id, offset, len, result);
361   }
362   return result;
363 }
364
365 /*
366  * Copy data from memory to BAP.
367  *
368  * Arguments:
369  *      hw              device structure
370  *      id              FID or RID, destined for the select register (host order)
371  *      offset          An _even_ offset into the buffer for the given FID/RID.
372  *      buf             ptr to array of bytes
373  *      len             length of data to transfer in bytes
374  * Returns: 
375  *      0               success
376  */
377 static int hfa384x_copy_to_bap(hfa384x_t *hw, UINT16 id, UINT16 offset,
378                         void *buf, UINT len)
379 {
380   int result = 0;
381   UINT8 *d = (UINT8*)buf;
382   UINT16 i;
383   UINT16 savereg;
384
385   /* Prepare BAP */
386   result = hfa384x_prepare_bap ( hw, id, offset );
387   if ( result == 0 ) {
388     /* Write even(len) buf contents to data reg */
389     for ( i = 0; i < (len & 0xfffe); i+=2 ) {
390       hfa384x_setreg_noswap(hw, *(UINT16*)(&(d[i])), HFA384x_DATA0);
391     }
392     /* If len odd, handle last byte */
393     if ( len % 2 ){
394       savereg = hfa384x_getreg_noswap(hw, HFA384x_DATA0);
395       result = hfa384x_prepare_bap ( hw, id, offset + (len & 0xfffe) );
396       if ( result == 0 ) {
397         ((UINT8*)(&savereg))[0] = d[len-1];
398         hfa384x_setreg_noswap(hw, savereg, HFA384x_DATA0);
399       }
400     }
401   }
402   if (result) {
403     printf ( "copy_to_bap(%#hx, %#hx, %d) failed, result=%#hx\n", id, offset, len, result);
404   }
405   return result;
406 }
407
408 /*
409  * Request a given record to be copied to/from the record buffer.
410  *
411  * Arguments:
412  *      hw              device structure
413  *      write           [0|1] copy the record buffer to the given
414  *                      configuration record. (host order)
415  *      rid             RID of the record to read/write. (host order)
416  *
417  * Returns: 
418  *      0               success
419  */
420 static inline int hfa384x_cmd_access(hfa384x_t *hw, UINT16 write, UINT16 rid)
421 {
422   return hfa384x_docmd_wait(hw, HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ACCESS) | HFA384x_CMD_WRITE_SET(write), rid, 0, 0);
423 }
424
425 /*
426  * Performs the sequence necessary to read a config/info item.
427  *
428  * Arguments:
429  *      hw              device structure
430  *      rid             config/info record id (host order)
431  *      buf             host side record buffer.  Upon return it will
432  *                      contain the body portion of the record (minus the 
433  *                      RID and len).
434  *      len             buffer length (in bytes, should match record length)
435  *
436  * Returns: 
437  *      0               success
438  */
439 static int hfa384x_drvr_getconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len)
440 {
441   int result = 0;
442   hfa384x_rec_t rec;
443
444   /* Request read of RID */
445   result = hfa384x_cmd_access( hw, 0, rid);
446   if ( result ) {
447     printf("Call to hfa384x_cmd_access failed\n");
448     return -1;
449   }
450   /* Copy out record length */
451   result = hfa384x_copy_from_bap( hw, rid, 0, &rec, sizeof(rec));
452   if ( result ) {
453     return -1;
454   }
455   /* Validate the record length */
456   if ( ((hfa384x2host_16(rec.reclen)-1)*2) != len ) {  /* note body len calculation in bytes */
457     printf ( "RID len mismatch, rid=%#hx hlen=%d fwlen=%d\n", rid, len, (hfa384x2host_16(rec.reclen)-1)*2);
458     return -1;
459   }
460   /* Copy out record data */
461   result = hfa384x_copy_from_bap( hw, rid, sizeof(rec), buf, len);
462   return result;
463 }
464
465 /*
466  * Performs the sequence necessary to read a 16/32 bit config/info item
467  * and convert it to host order.
468  *
469  * Arguments:
470  *      hw              device structure
471  *      rid             config/info record id (in host order)
472  *      val             ptr to 16/32 bit buffer to receive value (in host order)
473  *
474  * Returns: 
475  *      0               success
476  */
477 #if 0 /* Not actually used anywhere */
478 static int hfa384x_drvr_getconfig16(hfa384x_t *hw, UINT16 rid, void *val)
479 {
480   int result = 0;
481   result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(UINT16));
482   if ( result == 0 ) {
483     *((UINT16*)val) = hfa384x2host_16(*((UINT16*)val));
484   }
485   return result;
486 }
487 #endif
488 #if 0 /* Not actually used anywhere */
489 static int hfa384x_drvr_getconfig32(hfa384x_t *hw, UINT16 rid, void *val)
490 {
491   int result = 0;
492   result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(UINT32));
493   if ( result == 0 ) {
494     *((UINT32*)val) = hfa384x2host_32(*((UINT32*)val));
495   }
496   return result;
497 }
498 #endif
499
500 /*
501  * Performs the sequence necessary to write a config/info item.
502  *
503  * Arguments:
504  *      hw              device structure
505  *      rid             config/info record id (in host order)
506  *      buf             host side record buffer
507  *      len             buffer length (in bytes)
508  *
509  * Returns: 
510  *      0               success
511  */
512 static int hfa384x_drvr_setconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len)
513 {
514   int result = 0;
515   hfa384x_rec_t rec;
516
517   rec.rid = host2hfa384x_16(rid);
518   rec.reclen = host2hfa384x_16((len/2) + 1); /* note conversion to words, +1 for rid field */
519   /* write the record header */
520   result = hfa384x_copy_to_bap( hw, rid, 0, &rec, sizeof(rec));
521   if ( result ) {
522     printf("Failure writing record header\n");
523     return -1;
524   }
525   /* write the record data (if there is any) */
526   if ( len > 0 ) {
527     result = hfa384x_copy_to_bap( hw, rid, sizeof(rec), buf, len);
528     if ( result ) {
529       printf("Failure writing record data\n");
530       return -1;
531     }
532   }
533   /* Trigger setting of record */
534   result = hfa384x_cmd_access( hw, 1, rid);
535   return result;
536 }
537
538 /*
539  * Performs the sequence necessary to write a 16/32 bit config/info item.
540  *
541  * Arguments:
542  *      hw              device structure
543  *      rid             config/info record id (in host order)
544  *      val             16/32 bit value to store (in host order)
545  *
546  * Returns: 
547  *      0               success
548  */
549 static int hfa384x_drvr_setconfig16(hfa384x_t *hw, UINT16 rid, UINT16 *val)
550 {
551   UINT16 value;
552   value = host2hfa384x_16(*val);
553   return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(UINT16));
554 }
555 #if 0 /* Not actually used anywhere */
556 static int hfa384x_drvr_setconfig32(hfa384x_t *hw, UINT16 rid, UINT32 *val)
557 {
558   UINT32 value;
559   value = host2hfa384x_32(*val);
560   return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(UINT32));
561 }
562 #endif
563
564 /*
565  * Wait for an event, with specified checking interval and timeout.
566  * Automatically acknolwedges events.
567  *
568  * Arguments:
569  *      hw              device structure
570  *      event_mask      EVSTAT register mask of events to wait for
571  *      event_ack       EVACK register set of events to be acknowledged if they happen (can be
572  *                      used to acknowledge "ignorable" events in addition to the "main" event)
573  *      wait            Time (in us) to wait between each poll of the register
574  *      timeout         Maximum number of polls before timing out
575  *      descr           Descriptive text string of what is being waited for
576  *                      (will be printed out if a timeout happens)
577  *
578  * Returns: 
579  *      value of EVSTAT register, or 0 on failure 
580  */
581 static int hfa384x_wait_for_event(hfa384x_t *hw, UINT16 event_mask, UINT16 event_ack, int wait, int timeout, const char *descr)
582 {
583   UINT16 reg;
584   int count = 0;
585   
586   do {
587     reg = hfa384x_getreg(hw, HFA384x_EVSTAT);
588     if ( count > 0 ) udelay(wait);
589     count++;
590   } while ( !(reg & event_mask) && count < timeout);
591   if ( count >= timeout ) {
592     printf("hfa384x: Timed out waiting for %s\n", descr);
593     return 0; /* Return failure */
594   }
595   /* Acknowledge all events that we were waiting on */
596   hfa384x_setreg(hw, reg & ( event_mask | event_ack ), HFA384x_EVACK);
597   return reg;
598 }
599
600 /**************************************************************************
601 POLL - Wait for a frame
602 ***************************************************************************/
603 static int prism2_poll(struct nic *nic, int retrieve)
604 {
605   UINT16 reg;
606   UINT16 rxfid;
607   UINT16 result;
608   hfa384x_rx_frame_t rxdesc;
609   hfa384x_t *hw = &hw_global;
610   
611   /* Check for received packet */
612   reg = hfa384x_getreg(hw, HFA384x_EVSTAT);
613   if ( ! HFA384x_EVSTAT_ISRX(reg) ) {
614     /* No packet received - return 0 */
615     return 0;
616   }
617
618   if ( ! retrieve ) return 1;
619
620   /* Acknowledge RX event */
621   hfa384x_setreg(hw, HFA384x_EVACK_RX_SET(1), HFA384x_EVACK);
622   /* Get RX FID */  
623   rxfid = hfa384x_getreg(hw, HFA384x_RXFID);
624   /* Get the descriptor (including headers) */
625   result = hfa384x_copy_from_bap(hw, rxfid, 0, &rxdesc, sizeof(rxdesc));
626   if ( result ) {
627     return 0; /* fail */
628   }
629   /* Byte order convert once up front. */
630   rxdesc.status = hfa384x2host_16(rxdesc.status);
631   rxdesc.time = hfa384x2host_32(rxdesc.time);
632   rxdesc.data_len = hfa384x2host_16(rxdesc.data_len);
633
634   /* Fill in nic->packetlen */
635   nic->packetlen = rxdesc.data_len;
636   if ( nic->packetlen > 0 ) {
637     /* Fill in nic->packet */
638     /*
639      * NOTE: Packets as received have an 8-byte header (LLC+SNAP(?)) terminating with the packet type.
640      * Etherboot expects a 14-byte header terminating with the packet type (it ignores the rest of the
641      * header), so we use a quick hack to achieve this.
642      */
643     result = hfa384x_copy_from_bap(hw, rxfid, HFA384x_RX_DATA_OFF,
644                                    nic->packet + ETH_HLEN - sizeof(wlan_80211hdr_t), nic->packetlen);
645     if ( result ) {
646       return 0; /* fail */
647     }
648   }
649   return 1; /* Packet successfully received */
650 }
651
652 /**************************************************************************
653 TRANSMIT - Transmit a frame
654 ***************************************************************************/
655 static void prism2_transmit(
656                             struct nic *nic,
657                             const char *d,                      /* Destination */
658                             unsigned int t,                     /* Type */
659                             unsigned int s,                     /* size */
660                             const char *p)                      /* Packet */
661 {
662   hfa384x_t *hw = &hw_global;
663   hfa384x_tx_frame_t txdesc;
664   wlan_80211hdr_t p80211hdr = { wlan_llc_snap, {{0,0,0},0} };
665   UINT16 fid;
666   UINT16 status;
667   int result;
668
669   // Request FID allocation
670   result = hfa384x_docmd_wait(hw, HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ALLOC), HFA384x_DRVR_TXBUF_MAX, 0, 0);
671   if (result != 0) {
672     printf("hfa384x: Tx FID allocate command failed: Aborting transmit..\n");
673     return;
674   }
675   if ( !hfa384x_wait_for_event(hw, HFA384x_EVSTAT_ALLOC, HFA384x_EVACK_INFO, 10, 50, "Tx FID to be allocated\n" ) ) return;
676   fid = hfa384x_getreg(hw, HFA384x_ALLOCFID);
677
678   /* Build Tx frame structure */
679   memset(&txdesc, 0, sizeof(txdesc));
680   txdesc.tx_control = host2hfa384x_16( HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) | 
681                                        HFA384x_TX_TXEX_SET(1) | HFA384x_TX_TXOK_SET(1) );
682   txdesc.frame_control =  host2ieee16( WLAN_SET_FC_FTYPE(WLAN_FTYPE_DATA) |
683                                        WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DATAONLY) |
684                                        WLAN_SET_FC_TODS(1) );
685   memcpy(txdesc.address1, hw->bssid, WLAN_ADDR_LEN);
686   memcpy(txdesc.address2, nic->node_addr, WLAN_ADDR_LEN);
687   memcpy(txdesc.address3, d, WLAN_ADDR_LEN);
688   txdesc.data_len = host2hfa384x_16( sizeof(txdesc) + sizeof(p80211hdr) + s );
689   /* Set up SNAP header */
690   /* Let OUI default to RFC1042 (0x000000) */
691   p80211hdr.snap.type = htons(t);
692   
693   /* Copy txdesc, p80211hdr and payload parts to FID */
694   result = hfa384x_copy_to_bap(hw, fid, 0, &txdesc, sizeof(txdesc));
695   if ( result ) return; /* fail */
696   result = hfa384x_copy_to_bap( hw, fid, sizeof(txdesc), &p80211hdr, sizeof(p80211hdr) );
697   if ( result ) return; /* fail */
698   result = hfa384x_copy_to_bap( hw, fid, sizeof(txdesc) + sizeof(p80211hdr), (UINT8*)p, s );
699   if ( result ) return; /* fail */
700
701   /* Issue Tx command */
702   result = hfa384x_docmd_wait(hw, HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_TX), fid, 0, 0);
703   if ( result != 0 ) {
704     printf("hfa384x: Transmit failed with result %#hx.\n", result);
705     return;
706   }
707   
708   /* Wait for transmit completion (or exception) */
709   result = hfa384x_wait_for_event(hw, HFA384x_EVSTAT_TXEXC | HFA384x_EVSTAT_TX, HFA384x_EVACK_INFO,
710                                   200, 500, "Tx to complete\n" );
711   if ( !result ) return; /* timeout failure */
712   if ( HFA384x_EVSTAT_ISTXEXC(result) ) {
713     fid = hfa384x_getreg(hw, HFA384x_TXCOMPLFID);
714     printf ( "Tx exception occurred with fid %#hx\n", fid );
715     result = hfa384x_copy_from_bap(hw, fid, 0, &status, sizeof(status));
716     if ( result ) return; /* fail */
717     printf("hfa384x: Tx error occurred (status %#hx):\n", status);
718     if ( HFA384x_TXSTATUS_ISACKERR(status) ) { printf(" ...acknowledgement error\n"); }
719     if ( HFA384x_TXSTATUS_ISFORMERR(status) ) { printf(" ...format error\n"); }
720     if ( HFA384x_TXSTATUS_ISDISCON(status) ) { printf(" ...disconnected error\n"); }
721     if ( HFA384x_TXSTATUS_ISAGEDERR(status) ) { printf(" ...AGED error\n"); }
722     if ( HFA384x_TXSTATUS_ISRETRYERR(status) ) { printf(" ...retry error\n"); }
723     return; /* fail */
724   }
725 }
726
727 /**************************************************************************
728 DISABLE - Turn off ethernet interface
729 ***************************************************************************/
730 static void prism2_disable ( struct nic *nic __unused ) {
731   /* put the card in its initial state */
732 }
733
734 /**************************************************************************
735 IRQ - Enable, Disable, or Force interrupts
736 ***************************************************************************/
737 static void prism2_irq(struct nic *nic __unused, irq_action_t action __unused)
738 {
739   switch ( action ) {
740   case DISABLE :
741     break;
742   case ENABLE :
743     break;
744   case FORCE :
745     break;
746   }
747 }
748
749 /**************************************************************************
750 PROBE - Look for an adapter, this routine's visible to the outside
751 You should omit the last argument struct pci_device * for a non-PCI NIC
752 ***************************************************************************/
753 #if (WLAN_HOSTIF == WLAN_PLX)
754 static int prism2_plx_probe(struct dev *dev, struct pci_device *p)
755 #elif (WLAN_HOSTIF == WLAN_PCI)
756 static int prism2_pci_probe(struct dev *dev, struct pci_device *p)
757 #endif
758 {
759   struct nic *nic = (struct nic *)dev;
760   hfa384x_t *hw = &hw_global;
761   int result;
762   UINT16 tmp16 = 0;
763   UINT16 infofid;
764   hfa384x_InfFrame_t inf;
765   char ssid[HFA384x_RID_CNFDESIREDSSID_LEN];
766   int info_count = 0;
767
768   /* Find and intialise PLX Prism2 card */
769 #if (WLAN_HOSTIF == WLAN_PLX)
770   if ( ! prism2_find_plx ( hw, p ) ) return 0;
771   nic->ioaddr = hw->iobase;
772 #elif (WLAN_HOSTIF == WLAN_PCI)
773   if ( ! prism2_find_pci ( hw, p ) ) return 0;
774   nic->ioaddr = hw->membase;
775 #endif
776
777   nic->irqno  = 0;
778
779   /* Initialize card */
780   result = hfa384x_docmd_wait(hw, HFA384x_CMDCODE_INIT, 0,0,0); /* Send initialize command */
781   if ( result ) printf ( "Initialize command returned %#hx\n", result );
782   hfa384x_setreg(hw, 0, HFA384x_INTEN); /* Disable interrupts */
783   hfa384x_setreg(hw, 0xffff, HFA384x_EVACK); /* Acknowledge any spurious events */
784
785   /* Retrieve MAC address (and fill out nic->node_addr) */
786   hfa384x_drvr_getconfig ( hw, HFA384x_RID_CNFOWNMACADDR, nic->node_addr, HFA384x_RID_CNFOWNMACADDR_LEN );
787   printf ( "MAC address %!\n", nic->node_addr );
788
789   /* Prepare card for autojoin */
790   /* This procedure is reverse-engineered from a register-level trace of the Linux driver's join process */
791   tmp16 = WLAN_DATA_MAXLEN; /* Set maximum data length */
792   result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFMAXDATALEN, &tmp16);
793   if ( result ) printf ( "Set Max Data Length command returned %#hx\n", result );
794   tmp16 = 0x000f; /* Set transmit rate(?) */
795   result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, &tmp16);
796   if ( result ) printf ( "Set Transmit Rate command returned %#hx\n", result );
797   tmp16 = HFA384x_CNFAUTHENTICATION_OPENSYSTEM; /* Set authentication type to OpenSystem */
798   result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAUTHENTICATION, &tmp16);
799   if ( result ) printf ( "Set Authentication Type command returned %#hx\n", result );
800   /* Set SSID */
801   memset(ssid, 0, HFA384x_RID_CNFDESIREDSSID_LEN);
802   for ( tmp16=0; tmp16<sizeof(hardcoded_ssid); tmp16++ ) { ssid[2+tmp16] = hardcoded_ssid[tmp16]; }
803   ssid[0] = sizeof(hardcoded_ssid) - 1; /* Ignore terminating zero */
804   result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID, ssid, HFA384x_RID_CNFDESIREDSSID_LEN); /* Set the SSID */
805   if ( result ) printf ( "Set SSID command returned %#hx\n", result );
806   tmp16 = 1; /* Set port type to ESS port */
807   result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, &tmp16);
808   if ( result ) printf ( "Set port type command returned %#hx\n", result );
809   /* Enable card */
810   result = hfa384x_docmd_wait(hw, HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ENABLE) | HFA384x_CMD_MACPORT_SET(0), 0,0,0);
811   if ( result ) printf ( "Enable command returned %#hx\n", result );
812
813   do {
814     /* Increment info_count, abort if too many attempts.
815      * See comment next to definition of MAX_JOIN_INFO_COUNT for explanation.
816      */
817     info_count++;
818     if ( info_count > MAX_JOIN_INFO_COUNT ) {
819       printf ( "Too many failed attempts - aborting\n" );
820       return 0;
821     }
822
823     /* Wait for info frame to indicate link status */
824     if ( sizeof(hardcoded_ssid) == 1 ) {
825       /* Empty SSID => join to any SSID */
826       printf ( "Attempting to autojoin to any available access point (attempt %d)...", info_count );
827     } else {
828       printf ( "Attempting to autojoin to SSID %s (attempt %d)...", &ssid[2], info_count );
829     }
830     
831     if ( !hfa384x_wait_for_event(hw, HFA384x_EVSTAT_INFO, 0, 1000, 2000, "Info event" ) ) return 0;
832     printf("done\n");
833     infofid = hfa384x_getreg(hw, HFA384x_INFOFID);
834     /* Retrieve the length */
835     result = hfa384x_copy_from_bap( hw, infofid, 0, &inf.framelen, sizeof(UINT16));
836     if ( result ) return 0; /* fail */
837     inf.framelen = hfa384x2host_16(inf.framelen);
838     /* Retrieve the rest */
839     result = hfa384x_copy_from_bap( hw, infofid, sizeof(UINT16),
840                                     &(inf.infotype), inf.framelen * sizeof(UINT16));
841     if ( result ) return 0; /* fail */
842     if ( inf.infotype != HFA384x_IT_LINKSTATUS ) {
843       /* Not a Link Status info frame: die */
844       printf ( "Unexpected info frame type %#hx (not LinkStatus type)\n", inf.infotype );
845       return 0;
846     }
847     inf.info.linkstatus.linkstatus = hfa384x2host_16(inf.info.linkstatus.linkstatus);
848     if ( inf.info.linkstatus.linkstatus != HFA384x_LINK_CONNECTED ) {
849       /* Link not connected - retry */
850       printf ( "Link not connected (status %#hx)\n", inf.info.linkstatus.linkstatus );
851     }
852   } while ( inf.info.linkstatus.linkstatus != HFA384x_LINK_CONNECTED );
853     
854   /* Retrieve BSSID and print Connected message */
855   result = hfa384x_drvr_getconfig(hw, HFA384x_RID_CURRENTBSSID, hw->bssid, WLAN_BSSID_LEN);
856   printf ( "Link connected (BSSID %! - MAC address %!)\n", hw->bssid, nic->node_addr );
857   
858   /* point to NIC specific routines */
859 static struct nic_operations prism2_operations;
860 static struct nic_operations prism2_operations = {
861         .connect        = dummy_connect,
862         .poll           = prism2_poll,
863         .transmit       = prism2_transmit,
864         .irq            = prism2_irq,
865         .disable        = prism2_disable,
866 };  nic->nic_op = &prism2_operations;
867   return 1;
868 }
869
870 #if (WLAN_HOSTIF == WLAN_PLX)
871 /*
872  * Find PLX card.  Prints out information strings from PCMCIA CIS as visual
873  * confirmation of presence of card.
874  *
875  * Arguments:
876  *      hw              device structure to be filled in
877  *      p               PCI device structure
878  *
879  * Returns:
880  *      1               Success
881  */
882 static int prism2_find_plx ( hfa384x_t *hw, struct pci_device *p )
883 {
884   int found = 0;
885   uint32_t plx_lcr  = 0; /* PLX9052 Local Configuration Register Base (I/O) */
886   uint32_t attr_mem = 0; /* Prism2 Attribute Memory Base */
887   uint32_t iobase   = 0; /* Prism2 I/O Base */
888   unsigned char *cis_tpl  = NULL;
889   unsigned char *cis_string;
890   
891   /* Obtain all memory and IO base addresses */
892   pcibios_read_config_dword( p->bus, p->devfn, PLX_LOCAL_CONFIG_REGISTER_BASE, &plx_lcr);
893   plx_lcr &= PCI_BASE_ADDRESS_IO_MASK;
894   pcibios_read_config_dword( p->bus, p->devfn, PRISM2_PLX_ATTR_MEM_BASE, &attr_mem);
895   pcibios_read_config_dword( p->bus, p->devfn, PRISM2_PLX_IO_BASE, &iobase);
896   iobase &= PCI_BASE_ADDRESS_IO_MASK;
897
898   /* Fill out hw structure */
899   hw->membase = attr_mem;
900   hw->iobase = iobase;
901   printf ( "PLX9052 has local config registers at %#hx\n", plx_lcr );
902   printf ( "Prism2 has attribute memory at %#x and I/O base at %#hx\n", attr_mem, iobase );
903
904   /* Search for CIS strings */
905   printf ( "Searching for PCMCIA card...\n" );
906   cis_tpl = bus_to_virt(attr_mem);
907   while ( *cis_tpl != CISTPL_END ) {
908     if ( *cis_tpl == CISTPL_VERS_1 ) {
909       /* CISTPL_VERS_1 contains some nice text strings */
910       printf ( "...found " );
911       found = 1;
912       cis_string = cis_tpl + CISTPL_VERS_1_STR_OFF;
913       while ( ! ( ( *cis_string == 0 ) && ( *(cis_string+CIS_STEP) == 0 ) ) ) {
914         printf ( "%c", *cis_string == 0 ? ' ' : *cis_string );
915         cis_string += CIS_STEP;
916       }
917       printf ( "\n" );
918     }
919     /* printf ( "CIS tuple type %#hhx, length %#hhx\n", *cis_tpl, *(cis_tpl+CISTPL_LEN_OFF) ); */
920     cis_tpl += CISTPL_HEADER_LEN + CIS_STEP * ( *(cis_tpl+CISTPL_LEN_OFF) );
921   }
922   if ( found == 0 ) {
923     printf ( "...nothing found\n" );
924   }
925   ((unsigned char *)bus_to_virt(attr_mem))[COR_OFFSET] = COR_VALUE; /* Write COR to enable PC card */
926   return found;
927 }
928 #endif /* WLAN_PLX */
929
930 #if (WLAN_HOSTIF == WLAN_PCI)
931 /*
932  * Find PCI card.
933  *
934  * Arguments:
935  *      hw              device structure to be filled in
936  *      p               PCI device structure
937  *
938  * Returns:
939  *      1               Success
940  */
941 static int prism2_find_pci ( hfa384x_t *hw, struct pci_device *p )
942 {
943   uint32_t membase = 0; /* Prism2.5 Memory Base */
944   pcibios_read_config_dword( p->bus, p->devfn, PRISM2_PCI_MEM_BASE, &membase);
945   membase &= PCI_BASE_ADDRESS_MEM_MASK;
946   hw->membase = (uint32_t) phys_to_virt(membase);
947   printf ( "Prism2.5 has registers at %#x\n", hw->membase );
948   return 1;
949 }
950 #endif /* WLAN_PCI */
951