1/**************************************************************************
2Etherboot -  BOOTP/TFTP Bootstrap Program
3Prism2 NIC driver for Etherboot
4
5Written 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
16FILE_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
28static 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
120typedef 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 */
133static 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
142typedef struct wlan_llc
143{
144  UINT8   dsap;
145  UINT8   ssap;
146  UINT8   ctl;
147}  wlan_llc_t;
148
149static const wlan_llc_t wlan_llc_snap = { 0xaa, 0xaa, 0x03 }; /* LLC header indicating SNAP (?) */
150
151#define WLAN_IEEE_OUI_LEN 3
152typedef struct wlan_snap
153{
154  UINT8   oui[WLAN_IEEE_OUI_LEN];
155  UINT16  type;
156} wlan_snap_t;
157
158typedef 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. */
175static 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. */
185static 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 */
199static inline UINT16 hfa384x_getreg_noswap( hfa384x_t *hw, UINT reg )
200{
201  return hfa384x_getreg ( hw, reg );
202}
203static 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 */
230static 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 */
292static 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 */
336static 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 */
375static 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 */
418static 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 */
437static 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 */
476static 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 */
487static 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 */
510static 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 */
547static 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 */
554static 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 */
579static 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/**************************************************************************
599POLL - Wait for a frame
600***************************************************************************/
601static 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/**************************************************************************
651TRANSMIT - Transmit a frame
652***************************************************************************/
653static 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/**************************************************************************
726DISABLE - Turn off ethernet interface
727***************************************************************************/
728static void prism2_disable ( struct nic *nic __unused ) {
729  /* put the card in its initial state */
730}
731
732/**************************************************************************
733IRQ - Enable, Disable, or Force interrupts
734***************************************************************************/
735static 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/**************************************************************************
748Operations table
749***************************************************************************/
750static struct nic_operations prism2_operations = {
751	.connect	= dummy_connect,
752	.poll		= prism2_poll,
753	.transmit	= prism2_transmit,
754	.irq		= prism2_irq,
755};
756
757/**************************************************************************
758PROBE - Look for an adapter, this routine's visible to the outside
759You should omit the last argument struct pci_device * for a non-PCI NIC
760***************************************************************************/
761static 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