Home | History | Annotate | Download | only in net
      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. */
    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. */
    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  */
    199 static inline UINT16 hfa384x_getreg_noswap( hfa384x_t *hw, UINT reg )
    200 {
    201   return hfa384x_getreg ( hw, reg );
    202 }
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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  */
    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 ***************************************************************************/
    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 ***************************************************************************/
    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 ***************************************************************************/
    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 ***************************************************************************/
    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 ***************************************************************************/
    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