iPXE
prism2.c
Go to the documentation of this file.
00001 /**************************************************************************
00002 Etherboot -  BOOTP/TFTP Bootstrap Program
00003 Prism2 NIC driver for Etherboot
00004 
00005 Written by Michael Brown of Fen Systems Ltd
00006 $Id$
00007 ***************************************************************************/
00008 
00009 /*
00010  * This program is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU General Public License as
00012  * published by the Free Software Foundation; either version 2 of the
00013  * License, or (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  * General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00023  * 02110-1301, USA.
00024  */
00025 
00026 FILE_LICENCE ( GPL2_OR_LATER );
00027 
00028 #include <etherboot.h>
00029 #include <nic.h>
00030 #include <ipxe/pci.h>
00031 #include <ipxe/ethernet.h>
00032 
00033 /*
00034  * Hard-coded SSID
00035  * Leave blank in order to connect to any available SSID
00036  */
00037 
00038 static const char hardcoded_ssid[] = "";
00039 
00040 /*
00041  * Maximum number of info packets to wait for on a join attempt.
00042  * Some APs (including the Linksys WAP11) will send a "you are disconnected" packet
00043  * before sending the "you are connected" packet, if the card has previously been
00044  * attached to the AP.
00045  *
00046  * 2 is probably a sensible value, but YMMV.
00047  */
00048 
00049 #define MAX_JOIN_INFO_COUNT 2
00050 
00051 /*
00052  * Type of Prism2 interface to support
00053  * If not already defined, select PLX
00054  */
00055 #ifndef WLAN_HOSTIF
00056 #define WLAN_HOSTIF WLAN_PLX
00057 #endif
00058 
00059 /*
00060  * Include wlan_compat, p80211 and hfa384x header files from Linux Prism2 driver
00061  * We need to hack some defines in order to avoid compiling kernel-specific routines
00062  */
00063 
00064 #define __LINUX_WLAN__
00065 #undef __KERNEL__
00066 #define __I386__
00067 #include "wlan_compat.h"
00068 #include "p80211hdr.h"
00069 #include "hfa384x.h"
00070 #define BAP_TIMEOUT ( 5000 )
00071 
00072 /*
00073  * A few hacks to make the coding environment more Linux-like.  This makes it somewhat
00074  * quicker to convert code from the Linux Prism2 driver.
00075  */
00076 #include <errno.h>
00077 #define __le16_to_cpu(x) (x)
00078 #define __le32_to_cpu(x) (x)
00079 #define __cpu_to_le16(x) (x)
00080 #define __cpu_to_le32(x) (x)
00081 
00082 #define hfa384x2host_16(n)      (__le16_to_cpu((uint16_t)(n)))
00083 #define hfa384x2host_32(n)      (__le32_to_cpu((uint32_t)(n)))
00084 #define host2hfa384x_16(n)      (__cpu_to_le16((uint16_t)(n)))
00085 #define host2hfa384x_32(n)      (__cpu_to_le32((uint32_t)(n)))
00086 
00087 /*
00088  * PLX9052 PCI register offsets
00089  * Taken from PLX9052 datasheet available from http://www.plxtech.com/download/9052/databook/9052db-20.pdf
00090  */
00091 
00092 #define PLX_LOCAL_CONFIG_REGISTER_BASE ( PCI_BASE_ADDRESS_1 )
00093 #define PLX_LOCAL_ADDRESS_SPACE_0_BASE ( PCI_BASE_ADDRESS_2 )
00094 #define PLX_LOCAL_ADDRESS_SPACE_1_BASE ( PCI_BASE_ADDRESS_3 )
00095 #define PLX_LOCAL_ADDRESS_SPACE_2_BASE ( PCI_BASE_ADDRESS_4 )
00096 #define PLX_LOCAL_ADDRESS_SPACE_3_BASE ( PCI_BASE_ADDRESS_5 )
00097 
00098 #define PRISM2_PLX_ATTR_MEM_BASE       ( PLX_LOCAL_ADDRESS_SPACE_0_BASE )
00099 #define PRISM2_PLX_IO_BASE             ( PLX_LOCAL_ADDRESS_SPACE_1_BASE )
00100 
00101 #define PRISM2_PCI_MEM_BASE            ( PCI_BASE_ADDRESS_0 )
00102 
00103 /*
00104  * PCMCIA CIS types
00105  * Taken from cistpl.h in pcmcia-cs
00106  */
00107 
00108 #define CISTPL_VERS_1           ( 0x15 )
00109 #define CISTPL_END              ( 0xff )
00110 
00111 #define CIS_STEP                ( 2 )
00112 #define CISTPL_HEADER_LEN       ( 2 * CIS_STEP )
00113 #define CISTPL_LEN_OFF          ( 1 * CIS_STEP )
00114 #define CISTPL_VERS_1_STR_OFF   ( 4 * CIS_STEP )
00115 
00116 /*
00117  * Prism2 constants
00118  * Taken from prism2sta.c in linux-wlan-ng
00119  */
00120 
00121 #define COR_OFFSET      ( 0x3e0 )   /* COR attribute offset of Prism2 PC card */
00122 #define COR_VALUE       ( 0x41 )    /* Enable PC card with irq in level trigger (but interrupts disabled) */
00123 
00124 /* NIC specific static variables */
00125 
00126 /* The hfa384x_t structure is used extensively in the Linux driver but is ifdef'd out in our include since __KERNEL__ is not defined.
00127  * This is a dummy version that contains only the fields we are interested in.
00128  */
00129 
00130 typedef struct hfa384x
00131 {
00132   uint32_t iobase;
00133   void *membase;
00134   uint16_t lastcmd;
00135   uint16_t status;         /* in host order */
00136   uint16_t resp0;          /* in host order */
00137   uint16_t resp1;          /* in host order */
00138   uint16_t resp2;          /* in host order */
00139   uint8_t  bssid[WLAN_BSSID_LEN];
00140 } hfa384x_t;
00141 
00142 /* The global instance of the hardware (i.e. where we store iobase and membase, in the absence of anywhere better to put them */
00143 static hfa384x_t hw_global;
00144 
00145 /*
00146  * 802.11 headers in addition to those in hfa384x_tx_frame_t (LLC and SNAP)
00147  * Taken from p80211conv.h
00148  */
00149 
00150 typedef struct wlan_llc
00151 {
00152   uint8_t   dsap;
00153   uint8_t   ssap;
00154   uint8_t   ctl;
00155 }  wlan_llc_t;
00156 
00157 static const wlan_llc_t wlan_llc_snap = { 0xaa, 0xaa, 0x03 }; /* LLC header indicating SNAP (?) */
00158 
00159 #define WLAN_IEEE_OUI_LEN 3
00160 typedef struct wlan_snap
00161 {
00162   uint8_t   oui[WLAN_IEEE_OUI_LEN];
00163   uint16_t  type;
00164 } wlan_snap_t;
00165 
00166 typedef struct wlan_80211hdr
00167 {
00168   wlan_llc_t llc;
00169   wlan_snap_t snap;
00170 } wlan_80211hdr_t;
00171 
00172 /*
00173  * Function prototypes
00174  */
00175 
00176 /*
00177  * Hardware-level hfa384x functions
00178  * These are based on the ones in hfa384x.h (which are ifdef'd out since __KERNEL__ is not defined).
00179  * Basically, these functions are the result of hand-evaluating all the ifdefs and defines in the hfa384x.h versions.
00180  */
00181 
00182 /* Retrieve the value of one of the MAC registers. */
00183 static inline uint16_t hfa384x_getreg( hfa384x_t *hw, unsigned int reg )
00184 {
00185 #if (WLAN_HOSTIF == WLAN_PLX)
00186   return inw ( hw->iobase + reg );
00187 #elif (WLAN_HOSTIF == WLAN_PCI)
00188   return readw ( hw->membase + reg );
00189 #endif
00190 }
00191 
00192 /* Set the value of one of the MAC registers. */
00193 static inline void hfa384x_setreg( hfa384x_t *hw, uint16_t val, unsigned int reg )
00194 {
00195 #if (WLAN_HOSTIF == WLAN_PLX)
00196   outw ( val, hw->iobase + reg );
00197 #elif (WLAN_HOSTIF == WLAN_PCI)
00198   writew ( val, hw->membase + reg );
00199 #endif
00200   return;
00201 }
00202 
00203 /*
00204  * Noswap versions
00205  * Etherboot is i386 only, so swap and noswap are the same...
00206  */
00207 static inline uint16_t hfa384x_getreg_noswap( hfa384x_t *hw, unsigned int reg )
00208 {
00209   return hfa384x_getreg ( hw, reg );
00210 }
00211 static inline void hfa384x_setreg_noswap( hfa384x_t *hw, uint16_t val, unsigned int reg )
00212 {
00213   hfa384x_setreg ( hw, val, reg );
00214 }
00215 
00216 /*
00217  * Low-level hfa384x functions
00218  * These are based on the ones in hfa384x.c, modified to work in the Etherboot environment.
00219  */
00220 
00221 /*
00222  * hfa384x_docmd_wait
00223  *
00224  * Waits for availability of the Command register, then
00225  * issues the given command.  Then polls the Evstat register
00226  * waiting for command completion.
00227  * Arguments:
00228  *       hw              device structure
00229  *       cmd             Command in host order
00230  *       parm0           Parameter0 in host order
00231  *       parm1           Parameter1 in host order
00232  *       parm2           Parameter2 in host order
00233  * Returns:
00234  *       0               success
00235  *       >0              command indicated error, Status and Resp0-2 are
00236  *                       in hw structure.
00237  */
00238 static int hfa384x_docmd_wait( hfa384x_t *hw, uint16_t cmd, uint16_t parm0, uint16_t parm1, uint16_t parm2)
00239 {
00240   uint16_t reg = 0;
00241   uint16_t counter = 0;
00242 
00243   /* wait for the busy bit to clear */
00244   counter = 0;
00245   reg = hfa384x_getreg(hw, HFA384x_CMD);
00246   while ( HFA384x_CMD_ISBUSY(reg) && (counter < 10) ) {
00247     reg = hfa384x_getreg(hw, HFA384x_CMD);
00248     counter++;
00249     udelay(10);
00250   }
00251   if (HFA384x_CMD_ISBUSY(reg)) {
00252     printf("hfa384x_cmd timeout(1), reg=0x%0hx.\n", reg);
00253     return -ETIMEDOUT;
00254   }
00255 
00256   /* busy bit clear, write command */
00257   hfa384x_setreg(hw, parm0, HFA384x_PARAM0);
00258   hfa384x_setreg(hw, parm1, HFA384x_PARAM1);
00259   hfa384x_setreg(hw, parm2, HFA384x_PARAM2);
00260   hw->lastcmd = cmd;
00261   hfa384x_setreg(hw, cmd, HFA384x_CMD);
00262 
00263   /* Now wait for completion */
00264   counter = 0;
00265   reg = hfa384x_getreg(hw, HFA384x_EVSTAT);
00266   /* Initialization is the problem.  It takes about
00267      100ms. "normal" commands are typically is about
00268      200-400 us (I've never seen less than 200).  Longer
00269      is better so that we're not hammering the bus. */
00270   while ( !HFA384x_EVSTAT_ISCMD(reg) && (counter < 5000)) {
00271     reg = hfa384x_getreg(hw, HFA384x_EVSTAT);
00272     counter++;
00273     udelay(200);
00274   }
00275   if ( ! HFA384x_EVSTAT_ISCMD(reg) ) {
00276     printf("hfa384x_cmd timeout(2), reg=0x%0hx.\n", reg);
00277     return -ETIMEDOUT;
00278   }
00279 
00280   /* Read status and response */
00281   hw->status = hfa384x_getreg(hw, HFA384x_STATUS);
00282   hw->resp0 = hfa384x_getreg(hw, HFA384x_RESP0);
00283   hw->resp1 = hfa384x_getreg(hw, HFA384x_RESP1);
00284   hw->resp2 = hfa384x_getreg(hw, HFA384x_RESP2);
00285   hfa384x_setreg(hw, HFA384x_EVACK_CMD, HFA384x_EVACK);
00286   return HFA384x_STATUS_RESULT_GET(hw->status);
00287 }
00288 
00289 /*
00290  * Prepare BAP for access.  Assigns FID and RID, sets offset register
00291  * and waits for BAP to become available.
00292  *
00293  * Arguments:
00294  *      hw              device structure
00295  *      id              FID or RID, destined for the select register (host order)
00296  *      offset          An _even_ offset into the buffer for the given FID/RID.
00297  * Returns:
00298  *      0               success
00299  */
00300 static int hfa384x_prepare_bap(hfa384x_t *hw, uint16_t id, uint16_t offset)
00301 {
00302   int result = 0;
00303   uint16_t reg;
00304   uint16_t i;
00305 
00306   /* Validate offset, buf, and len */
00307   if ( (offset > HFA384x_BAP_OFFSET_MAX) || (offset % 2) ) {
00308     result = -EINVAL;
00309   } else {
00310     /* Write fid/rid and offset */
00311     hfa384x_setreg(hw, id, HFA384x_SELECT0);
00312     udelay(10);
00313     hfa384x_setreg(hw, offset, HFA384x_OFFSET0);
00314     /* Wait for offset[busy] to clear (see BAP_TIMEOUT) */
00315     i = 0;
00316     do {
00317       reg = hfa384x_getreg(hw, HFA384x_OFFSET0);
00318       if ( i > 0 ) udelay(2);
00319       i++;
00320     } while ( i < BAP_TIMEOUT && HFA384x_OFFSET_ISBUSY(reg));
00321     if ( i >= BAP_TIMEOUT ) {
00322       /* failure */
00323       result = reg;
00324     } else if ( HFA384x_OFFSET_ISERR(reg) ){
00325       /* failure */
00326       result = reg;
00327     }
00328   }
00329   return result;
00330 }
00331 
00332 /*
00333  * Copy data from BAP to memory.
00334  *
00335  * Arguments:
00336  *      hw              device structure
00337  *      id              FID or RID, destined for the select register (host order)
00338  *      offset          An _even_ offset into the buffer for the given FID/RID.
00339  *      buf             ptr to array of bytes
00340  *      len             length of data to transfer in bytes
00341  * Returns:
00342  *      0               success
00343  */
00344 static int hfa384x_copy_from_bap(hfa384x_t *hw, uint16_t id, uint16_t offset,
00345                           void *buf, unsigned int len)
00346 {
00347   int result = 0;
00348   uint8_t       *d = (uint8_t*)buf;
00349   uint16_t i;
00350   uint16_t reg = 0;
00351 
00352   /* Prepare BAP */
00353   result = hfa384x_prepare_bap ( hw, id, offset );
00354   if ( result == 0 ) {
00355     /* Read even(len) buf contents from data reg */
00356     for ( i = 0; i < (len & 0xfffe); i+=2 ) {
00357       *(uint16_t*)(&(d[i])) = hfa384x_getreg_noswap(hw, HFA384x_DATA0);
00358     }
00359     /* If len odd, handle last byte */
00360     if ( len % 2 ){
00361       reg = hfa384x_getreg_noswap(hw, HFA384x_DATA0);
00362       d[len-1] = ((uint8_t*)(&reg))[0];
00363     }
00364   }
00365   if (result) {
00366     printf ( "copy_from_bap(%#hx, %#hx, %d) failed, result=%#hx\n", id, offset, len, result);
00367   }
00368   return result;
00369 }
00370 
00371 /*
00372  * Copy data from memory to BAP.
00373  *
00374  * Arguments:
00375  *      hw              device structure
00376  *      id              FID or RID, destined for the select register (host order)
00377  *      offset          An _even_ offset into the buffer for the given FID/RID.
00378  *      buf             ptr to array of bytes
00379  *      len             length of data to transfer in bytes
00380  * Returns:
00381  *      0               success
00382  */
00383 static int hfa384x_copy_to_bap(hfa384x_t *hw, uint16_t id, uint16_t offset,
00384                         void *buf, unsigned int len)
00385 {
00386   int result = 0;
00387   uint8_t       *d = (uint8_t*)buf;
00388   uint16_t i;
00389   uint16_t savereg;
00390 
00391   /* Prepare BAP */
00392   result = hfa384x_prepare_bap ( hw, id, offset );
00393   if ( result == 0 ) {
00394     /* Write even(len) buf contents to data reg */
00395     for ( i = 0; i < (len & 0xfffe); i+=2 ) {
00396       hfa384x_setreg_noswap(hw, *(uint16_t*)(&(d[i])), HFA384x_DATA0);
00397     }
00398     /* If len odd, handle last byte */
00399     if ( len % 2 ){
00400       savereg = hfa384x_getreg_noswap(hw, HFA384x_DATA0);
00401       result = hfa384x_prepare_bap ( hw, id, offset + (len & 0xfffe) );
00402       if ( result == 0 ) {
00403         ((uint8_t*)(&savereg))[0] = d[len-1];
00404         hfa384x_setreg_noswap(hw, savereg, HFA384x_DATA0);
00405       }
00406     }
00407   }
00408   if (result) {
00409     printf ( "copy_to_bap(%#hx, %#hx, %d) failed, result=%#hx\n", id, offset, len, result);
00410   }
00411   return result;
00412 }
00413 
00414 /*
00415  * Request a given record to be copied to/from the record buffer.
00416  *
00417  * Arguments:
00418  *      hw              device structure
00419  *      write           [0|1] copy the record buffer to the given
00420  *                      configuration record. (host order)
00421  *      rid             RID of the record to read/write. (host order)
00422  *
00423  * Returns:
00424  *      0               success
00425  */
00426 static inline int hfa384x_cmd_access(hfa384x_t *hw, uint16_t write, uint16_t rid)
00427 {
00428   return hfa384x_docmd_wait(hw, HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ACCESS) | HFA384x_CMD_WRITE_SET(write), rid, 0, 0);
00429 }
00430 
00431 /*
00432  * Performs the sequence necessary to read a config/info item.
00433  *
00434  * Arguments:
00435  *      hw              device structure
00436  *      rid             config/info record id (host order)
00437  *      buf             host side record buffer.  Upon return it will
00438  *                      contain the body portion of the record (minus the
00439  *                      RID and len).
00440  *      len             buffer length (in bytes, should match record length)
00441  *
00442  * Returns:
00443  *      0               success
00444  */
00445 static int hfa384x_drvr_getconfig(hfa384x_t *hw, uint16_t rid, void *buf, uint16_t len)
00446 {
00447   int result = 0;
00448   hfa384x_rec_t rec;
00449 
00450   /* Request read of RID */
00451   result = hfa384x_cmd_access( hw, 0, rid);
00452   if ( result ) {
00453     printf("Call to hfa384x_cmd_access failed\n");
00454     return -1;
00455   }
00456   /* Copy out record length */
00457   result = hfa384x_copy_from_bap( hw, rid, 0, &rec, sizeof(rec));
00458   if ( result ) {
00459     return -1;
00460   }
00461   /* Validate the record length */
00462   if ( ((hfa384x2host_16(rec.reclen)-1)*2) != len ) {  /* note body len calculation in bytes */
00463     printf ( "RID len mismatch, rid=%#hx hlen=%d fwlen=%d\n", rid, len, (hfa384x2host_16(rec.reclen)-1)*2);
00464     return -1;
00465   }
00466   /* Copy out record data */
00467   result = hfa384x_copy_from_bap( hw, rid, sizeof(rec), buf, len);
00468   return result;
00469 }
00470 
00471 /*
00472  * Performs the sequence necessary to read a 16/32 bit config/info item
00473  * and convert it to host order.
00474  *
00475  * Arguments:
00476  *      hw              device structure
00477  *      rid             config/info record id (in host order)
00478  *      val             ptr to 16/32 bit buffer to receive value (in host order)
00479  *
00480  * Returns:
00481  *      0               success
00482  */
00483 #if 0 /* Not actually used anywhere */
00484 static int hfa384x_drvr_getconfig16(hfa384x_t *hw, uint16_t rid, void *val)
00485 {
00486   int result = 0;
00487   result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(uint16_t));
00488   if ( result == 0 ) {
00489     *((uint16_t*)val) = hfa384x2host_16(*((uint16_t*)val));
00490   }
00491   return result;
00492 }
00493 #endif
00494 #if 0 /* Not actually used anywhere */
00495 static int hfa384x_drvr_getconfig32(hfa384x_t *hw, uint16_t rid, void *val)
00496 {
00497   int result = 0;
00498   result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(uint32_t));
00499   if ( result == 0 ) {
00500     *((uint32_t*)val) = hfa384x2host_32(*((uint32_t*)val));
00501   }
00502   return result;
00503 }
00504 #endif
00505 
00506 /*
00507  * Performs the sequence necessary to write a config/info item.
00508  *
00509  * Arguments:
00510  *      hw              device structure
00511  *      rid             config/info record id (in host order)
00512  *      buf             host side record buffer
00513  *      len             buffer length (in bytes)
00514  *
00515  * Returns:
00516  *      0               success
00517  */
00518 static int hfa384x_drvr_setconfig(hfa384x_t *hw, uint16_t rid, void *buf, uint16_t len)
00519 {
00520   int result = 0;
00521   hfa384x_rec_t rec;
00522 
00523   rec.rid = host2hfa384x_16(rid);
00524   rec.reclen = host2hfa384x_16((len/2) + 1); /* note conversion to words, +1 for rid field */
00525   /* write the record header */
00526   result = hfa384x_copy_to_bap( hw, rid, 0, &rec, sizeof(rec));
00527   if ( result ) {
00528     printf("Failure writing record header\n");
00529     return -1;
00530   }
00531   /* write the record data (if there is any) */
00532   if ( len > 0 ) {
00533     result = hfa384x_copy_to_bap( hw, rid, sizeof(rec), buf, len);
00534     if ( result ) {
00535       printf("Failure writing record data\n");
00536       return -1;
00537     }
00538   }
00539   /* Trigger setting of record */
00540   result = hfa384x_cmd_access( hw, 1, rid);
00541   return result;
00542 }
00543 
00544 /*
00545  * Performs the sequence necessary to write a 16/32 bit config/info item.
00546  *
00547  * Arguments:
00548  *      hw              device structure
00549  *      rid             config/info record id (in host order)
00550  *      val             16/32 bit value to store (in host order)
00551  *
00552  * Returns:
00553  *      0               success
00554  */
00555 static int hfa384x_drvr_setconfig16(hfa384x_t *hw, uint16_t rid, uint16_t *val)
00556 {
00557   uint16_t value;
00558   value = host2hfa384x_16(*val);
00559   return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(uint16_t));
00560 }
00561 #if 0 /* Not actually used anywhere */
00562 static int hfa384x_drvr_setconfig32(hfa384x_t *hw, uint16_t rid, uint32_t *val)
00563 {
00564   uint32_t value;
00565   value = host2hfa384x_32(*val);
00566   return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(uint32_t));
00567 }
00568 #endif
00569 
00570 /*
00571  * Wait for an event, with specified checking interval and timeout.
00572  * Automatically acknolwedges events.
00573  *
00574  * Arguments:
00575  *      hw              device structure
00576  *      event_mask      EVSTAT register mask of events to wait for
00577  *      event_ack       EVACK register set of events to be acknowledged if they happen (can be
00578  *                      used to acknowledge "ignorable" events in addition to the "main" event)
00579  *      wait            Time (in us) to wait between each poll of the register
00580  *      timeout         Maximum number of polls before timing out
00581  *      descr           Descriptive text string of what is being waited for
00582  *                      (will be printed out if a timeout happens)
00583  *
00584  * Returns:
00585  *      value of EVSTAT register, or 0 on failure
00586  */
00587 static int hfa384x_wait_for_event(hfa384x_t *hw, uint16_t event_mask, uint16_t event_ack, int wait, int timeout, const char *descr)
00588 {
00589   uint16_t reg;
00590   int count = 0;
00591 
00592   do {
00593     reg = hfa384x_getreg(hw, HFA384x_EVSTAT);
00594     if ( count > 0 ) udelay(wait);
00595     count++;
00596   } while ( !(reg & event_mask) && count < timeout);
00597   if ( count >= timeout ) {
00598     printf("hfa384x: Timed out waiting for %s\n", descr);
00599     return 0; /* Return failure */
00600   }
00601   /* Acknowledge all events that we were waiting on */
00602   hfa384x_setreg(hw, reg & ( event_mask | event_ack ), HFA384x_EVACK);
00603   return reg;
00604 }
00605 
00606 /**************************************************************************
00607 POLL - Wait for a frame
00608 ***************************************************************************/
00609 static int prism2_poll(struct nic *nic, int retrieve)
00610 {
00611   uint16_t reg;
00612   uint16_t rxfid;
00613   uint16_t result;
00614   hfa384x_rx_frame_t rxdesc;
00615   hfa384x_t *hw = &hw_global;
00616 
00617   /* Check for received packet */
00618   reg = hfa384x_getreg(hw, HFA384x_EVSTAT);
00619   if ( ! HFA384x_EVSTAT_ISRX(reg) ) {
00620     /* No packet received - return 0 */
00621     return 0;
00622   }
00623 
00624   if ( ! retrieve ) return 1;
00625 
00626   /* Acknowledge RX event */
00627   hfa384x_setreg(hw, HFA384x_EVACK_RX_SET(1), HFA384x_EVACK);
00628   /* Get RX FID */
00629   rxfid = hfa384x_getreg(hw, HFA384x_RXFID);
00630   /* Get the descriptor (including headers) */
00631   result = hfa384x_copy_from_bap(hw, rxfid, 0, &rxdesc, sizeof(rxdesc));
00632   if ( result ) {
00633     return 0; /* fail */
00634   }
00635   /* Byte order convert once up front. */
00636   rxdesc.status = hfa384x2host_16(rxdesc.status);
00637   rxdesc.time = hfa384x2host_32(rxdesc.time);
00638   rxdesc.data_len = hfa384x2host_16(rxdesc.data_len);
00639 
00640   /* Fill in nic->packetlen */
00641   nic->packetlen = rxdesc.data_len;
00642   if ( nic->packetlen > 0 ) {
00643     /* Fill in nic->packet */
00644     /*
00645      * NOTE: Packets as received have an 8-byte header (LLC+SNAP(?)) terminating with the packet type.
00646      * Etherboot expects a 14-byte header terminating with the packet type (it ignores the rest of the
00647      * header), so we use a quick hack to achieve this.
00648      */
00649     result = hfa384x_copy_from_bap(hw, rxfid, HFA384x_RX_DATA_OFF,
00650                                    nic->packet + ETH_HLEN - sizeof(wlan_80211hdr_t), nic->packetlen);
00651     if ( result ) {
00652       return 0; /* fail */
00653     }
00654   }
00655   return 1; /* Packet successfully received */
00656 }
00657 
00658 /**************************************************************************
00659 TRANSMIT - Transmit a frame
00660 ***************************************************************************/
00661 static void prism2_transmit(
00662                             struct nic *nic,
00663                             const char *d,                      /* Destination */
00664                             unsigned int t,                     /* Type */
00665                             unsigned int s,                     /* size */
00666                             const char *p)                      /* Packet */
00667 {
00668   hfa384x_t *hw = &hw_global;
00669   hfa384x_tx_frame_t txdesc;
00670   wlan_80211hdr_t p80211hdr = { wlan_llc_snap, {{0,0,0},0} };
00671   uint16_t fid;
00672   uint16_t status;
00673   int result;
00674 
00675   // Request FID allocation
00676   result = hfa384x_docmd_wait(hw, HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ALLOC), HFA384x_DRVR_TXBUF_MAX, 0, 0);
00677   if (result != 0) {
00678     printf("hfa384x: Tx FID allocate command failed: Aborting transmit..\n");
00679     return;
00680   }
00681   if ( !hfa384x_wait_for_event(hw, HFA384x_EVSTAT_ALLOC, HFA384x_EVACK_INFO, 10, 50, "Tx FID to be allocated\n" ) ) return;
00682   fid = hfa384x_getreg(hw, HFA384x_ALLOCFID);
00683 
00684   /* Build Tx frame structure */
00685   memset(&txdesc, 0, sizeof(txdesc));
00686   txdesc.tx_control = host2hfa384x_16( HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) |
00687                                        HFA384x_TX_TXEX_SET(1) | HFA384x_TX_TXOK_SET(1) );
00688   txdesc.frame_control =  host2ieee16( WLAN_SET_FC_FTYPE(WLAN_FTYPE_DATA) |
00689                                        WLAN_SET_FC_FSTYPE(WLAN_FSTYPE_DATAONLY) |
00690                                        WLAN_SET_FC_TODS(1) );
00691   memcpy(txdesc.address1, hw->bssid, WLAN_ADDR_LEN);
00692   memcpy(txdesc.address2, nic->node_addr, WLAN_ADDR_LEN);
00693   memcpy(txdesc.address3, d, WLAN_ADDR_LEN);
00694   txdesc.data_len = host2hfa384x_16( sizeof(txdesc) + sizeof(p80211hdr) + s );
00695   /* Set up SNAP header */
00696   /* Let OUI default to RFC1042 (0x000000) */
00697   p80211hdr.snap.type = htons(t);
00698 
00699   /* Copy txdesc, p80211hdr and payload parts to FID */
00700   result = hfa384x_copy_to_bap(hw, fid, 0, &txdesc, sizeof(txdesc));
00701   if ( result ) return; /* fail */
00702   result = hfa384x_copy_to_bap( hw, fid, sizeof(txdesc), &p80211hdr, sizeof(p80211hdr) );
00703   if ( result ) return; /* fail */
00704   result = hfa384x_copy_to_bap( hw, fid, sizeof(txdesc) + sizeof(p80211hdr), (uint8_t*)p, s );
00705   if ( result ) return; /* fail */
00706 
00707   /* Issue Tx command */
00708   result = hfa384x_docmd_wait(hw, HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_TX), fid, 0, 0);
00709   if ( result != 0 ) {
00710     printf("hfa384x: Transmit failed with result %#hx.\n", result);
00711     return;
00712   }
00713 
00714   /* Wait for transmit completion (or exception) */
00715   result = hfa384x_wait_for_event(hw, HFA384x_EVSTAT_TXEXC | HFA384x_EVSTAT_TX, HFA384x_EVACK_INFO,
00716                                   200, 500, "Tx to complete\n" );
00717   if ( !result ) return; /* timeout failure */
00718   if ( HFA384x_EVSTAT_ISTXEXC(result) ) {
00719     fid = hfa384x_getreg(hw, HFA384x_TXCOMPLFID);
00720     printf ( "Tx exception occurred with fid %#hx\n", fid );
00721     result = hfa384x_copy_from_bap(hw, fid, 0, &status, sizeof(status));
00722     if ( result ) return; /* fail */
00723     printf("hfa384x: Tx error occurred (status %#hx):\n", status);
00724     if ( HFA384x_TXSTATUS_ISACKERR(status) ) { printf(" ...acknowledgement error\n"); }
00725     if ( HFA384x_TXSTATUS_ISFORMERR(status) ) { printf(" ...format error\n"); }
00726     if ( HFA384x_TXSTATUS_ISDISCON(status) ) { printf(" ...disconnected error\n"); }
00727     if ( HFA384x_TXSTATUS_ISAGEDERR(status) ) { printf(" ...AGED error\n"); }
00728     if ( HFA384x_TXSTATUS_ISRETRYERR(status) ) { printf(" ...retry error\n"); }
00729     return; /* fail */
00730   }
00731 }
00732 
00733 /**************************************************************************
00734 DISABLE - Turn off ethernet interface
00735 ***************************************************************************/
00736 static void prism2_disable ( struct nic *nic __unused ) {
00737   /* put the card in its initial state */
00738 }
00739 
00740 /**************************************************************************
00741 IRQ - Enable, Disable, or Force interrupts
00742 ***************************************************************************/
00743 static void prism2_irq(struct nic *nic __unused, irq_action_t action __unused)
00744 {
00745   switch ( action ) {
00746   case DISABLE :
00747     break;
00748   case ENABLE :
00749     break;
00750   case FORCE :
00751     break;
00752   }
00753 }
00754 
00755 /**************************************************************************
00756 Operations table
00757 ***************************************************************************/
00758 static struct nic_operations prism2_operations = {
00759         .connect        = dummy_connect,
00760         .poll           = prism2_poll,
00761         .transmit       = prism2_transmit,
00762         .irq            = prism2_irq,
00763 };
00764 
00765 /**************************************************************************
00766 PROBE - Look for an adapter, this routine's visible to the outside
00767 You should omit the last argument struct pci_device * for a non-PCI NIC
00768 ***************************************************************************/
00769 static int prism2_probe ( struct nic *nic, hfa384x_t *hw ) {
00770   int result;
00771   uint16_t tmp16 = 0;
00772   uint16_t infofid;
00773   hfa384x_InfFrame_t inf;
00774   char ssid[HFA384x_RID_CNFDESIREDSSID_LEN];
00775   int info_count = 0;
00776 
00777   nic->irqno  = 0;
00778 
00779   /* Initialize card */
00780   result = hfa384x_docmd_wait(hw, HFA384x_CMDCODE_INIT, 0,0,0); /* Send initialize command */
00781   if ( result ) printf ( "Initialize command returned %#hx\n", result );
00782   hfa384x_setreg(hw, 0, HFA384x_INTEN); /* Disable interrupts */
00783   hfa384x_setreg(hw, 0xffff, HFA384x_EVACK); /* Acknowledge any spurious events */
00784 
00785   DBG ( "MAC address %s\n", eth_ntoa ( nic->node_addr ) );
00786 
00787   /* Retrieve MAC address (and fill out nic->node_addr) */
00788   hfa384x_drvr_getconfig ( hw, HFA384x_RID_CNFOWNMACADDR, nic->node_addr, HFA384x_RID_CNFOWNMACADDR_LEN );
00789 
00790   /* Prepare card for autojoin */
00791   /* This procedure is reverse-engineered from a register-level trace of the Linux driver's join process */
00792   tmp16 = WLAN_DATA_MAXLEN; /* Set maximum data length */
00793   result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFMAXDATALEN, &tmp16);
00794   if ( result ) printf ( "Set Max Data Length command returned %#hx\n", result );
00795   tmp16 = 0x000f; /* Set transmit rate(?) */
00796   result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, &tmp16);
00797   if ( result ) printf ( "Set Transmit Rate command returned %#hx\n", result );
00798   tmp16 = HFA384x_CNFAUTHENTICATION_OPENSYSTEM; /* Set authentication type to OpenSystem */
00799   result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAUTHENTICATION, &tmp16);
00800   if ( result ) printf ( "Set Authentication Type command returned %#hx\n", result );
00801   /* Set SSID */
00802   memset(ssid, 0, HFA384x_RID_CNFDESIREDSSID_LEN);
00803   for ( tmp16=0; tmp16<sizeof(hardcoded_ssid); tmp16++ ) { ssid[2+tmp16] = hardcoded_ssid[tmp16]; }
00804   ssid[0] = sizeof(hardcoded_ssid) - 1; /* Ignore terminating zero */
00805   result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID, ssid, HFA384x_RID_CNFDESIREDSSID_LEN); /* Set the SSID */
00806   if ( result ) printf ( "Set SSID command returned %#hx\n", result );
00807   tmp16 = 1; /* Set port type to ESS port */
00808   result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, &tmp16);
00809   if ( result ) printf ( "Set port type command returned %#hx\n", result );
00810   /* Enable card */
00811   result = hfa384x_docmd_wait(hw, HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ENABLE) | HFA384x_CMD_MACPORT_SET(0), 0,0,0);
00812   if ( result ) printf ( "Enable command returned %#hx\n", result );
00813 
00814   do {
00815     /* Increment info_count, abort if too many attempts.
00816      * See comment next to definition of MAX_JOIN_INFO_COUNT for explanation.
00817      */
00818     info_count++;
00819     if ( info_count > MAX_JOIN_INFO_COUNT ) {
00820       printf ( "Too many failed attempts - aborting\n" );
00821       return 0;
00822     }
00823 
00824     /* Wait for info frame to indicate link status */
00825     if ( sizeof(hardcoded_ssid) == 1 ) {
00826       /* Empty SSID => join to any SSID */
00827       printf ( "Attempting to autojoin to any available access point (attempt %d)...", info_count );
00828     } else {
00829       printf ( "Attempting to autojoin to SSID %s (attempt %d)...", &ssid[2], info_count );
00830     }
00831 
00832     if ( !hfa384x_wait_for_event(hw, HFA384x_EVSTAT_INFO, 0, 1000, 2000, "Info event" ) ) return 0;
00833     printf("done\n");
00834     infofid = hfa384x_getreg(hw, HFA384x_INFOFID);
00835     /* Retrieve the length */
00836     result = hfa384x_copy_from_bap( hw, infofid, 0, &inf.framelen, sizeof(uint16_t));
00837     if ( result ) return 0; /* fail */
00838     inf.framelen = hfa384x2host_16(inf.framelen);
00839     /* Retrieve the rest */
00840     result = hfa384x_copy_from_bap( hw, infofid, sizeof(uint16_t),
00841                                     &(inf.infotype), inf.framelen * sizeof(uint16_t));
00842     if ( result ) return 0; /* fail */
00843     if ( inf.infotype != HFA384x_IT_LINKSTATUS ) {
00844       /* Not a Link Status info frame: die */
00845       printf ( "Unexpected info frame type %#hx (not LinkStatus type)\n", inf.infotype );
00846       return 0;
00847     }
00848     inf.info.linkstatus.linkstatus = hfa384x2host_16(inf.info.linkstatus.linkstatus);
00849     if ( inf.info.linkstatus.linkstatus != HFA384x_LINK_CONNECTED ) {
00850       /* Link not connected - retry */
00851       printf ( "Link not connected (status %#hx)\n", inf.info.linkstatus.linkstatus );
00852     }
00853   } while ( inf.info.linkstatus.linkstatus != HFA384x_LINK_CONNECTED );
00854 
00855   /* Retrieve BSSID and print Connected message */
00856   result = hfa384x_drvr_getconfig(hw, HFA384x_RID_CURRENTBSSID, hw->bssid, WLAN_BSSID_LEN);
00857 
00858   DBG ( "Link connected (BSSID %s - ", eth_ntoa ( hw->bssid ) );
00859   DBG ( " MAC address %s)\n", eth_ntoa (nic->node_addr ) );
00860 
00861   /* point to NIC specific routines */
00862   nic->nic_op   = &prism2_operations;
00863   return 1;
00864 }
00865