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