a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync/**************************************************************************
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncEtherboot - BOOTP/TFTP Bootstrap Program
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncPrism2 NIC driver for Etherboot
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncWritten by Michael Brown of Fen Systems Ltd
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync$Id: prism2.c 80479 2012-08-30 16:24:44Z klaus $
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync***************************************************************************/
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * This program is free software; you can redistribute it and/or
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * modify it under the terms of the GNU General Public License as
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * published by the Free Software Foundation; either version 2, or (at
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * your option) any later version.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Oracle GPL Disclaimer: For the avoidance of doubt, except that if any license choice
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * the General Public License version 2 (GPLv2) at this time for any software where
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * a choice of GPL license versions is made available with the language indicating
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * that GPLv2 or any later version may be used, or where a choice of which version
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * of the GPL is applied is otherwise unspecified.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Hard-coded SSID
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Leave blank in order to connect to any available SSID
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Maximum number of info packets to wait for on a join attempt.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Some APs (including the Linksys WAP11) will send a "you are disconnected" packet
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * before sending the "you are connected" packet, if the card has previously been
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * attached to the AP.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * 2 is probably a sensible value, but YMMV.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Type of Prism2 interface to support
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * If not already defined, select PLX
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Include wlan_compat, p80211 and hfa384x header files from Linux Prism2 driver
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * We need to hack some defines in order to avoid compiling kernel-specific routines
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * A few hacks to make the coding environment more Linux-like. This makes it somewhat
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * quicker to convert code from the Linux Prism2 driver.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#define hfa384x2host_16(n) (__le16_to_cpu((UINT16)(n)))
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#define hfa384x2host_32(n) (__le32_to_cpu((UINT32)(n)))
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#define host2hfa384x_16(n) (__cpu_to_le16((UINT16)(n)))
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#define host2hfa384x_32(n) (__cpu_to_le32((UINT32)(n)))
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * PLX9052 PCI register offsets
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Taken from PLX9052 datasheet available from http://www.plxtech.com/download/9052/databook/9052db-20.pdf
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#define PLX_LOCAL_CONFIG_REGISTER_BASE ( PCI_BASE_ADDRESS_1 )
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#define PLX_LOCAL_ADDRESS_SPACE_0_BASE ( PCI_BASE_ADDRESS_2 )
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#define PLX_LOCAL_ADDRESS_SPACE_1_BASE ( PCI_BASE_ADDRESS_3 )
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#define PLX_LOCAL_ADDRESS_SPACE_2_BASE ( PCI_BASE_ADDRESS_4 )
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#define PLX_LOCAL_ADDRESS_SPACE_3_BASE ( PCI_BASE_ADDRESS_5 )
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#define PRISM2_PLX_ATTR_MEM_BASE ( PLX_LOCAL_ADDRESS_SPACE_0_BASE )
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#define PRISM2_PLX_IO_BASE ( PLX_LOCAL_ADDRESS_SPACE_1_BASE )
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * PCMCIA CIS types
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Taken from cistpl.h in pcmcia-cs
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Prism2 constants
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Taken from prism2sta.c in linux-wlan-ng
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#define COR_OFFSET ( 0x3e0 ) /* COR attribute offset of Prism2 PC card */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#define COR_VALUE ( 0x41 ) /* Enable PC card with irq in level trigger (but interrupts disabled) */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync/* NIC specific static variables */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync/* The hfa384x_t structure is used extensively in the Linux driver but is ifdef'd out in our include since __KERNEL__ is not defined.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * This is a dummy version that contains only the fields we are interested in.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync/* The global instance of the hardware (i.e. where we store iobase and membase, in the absence of anywhere better to put them */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync 0, 0, 0, 0, 0, 0, 0, {0,0,0,0,0,0}
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * 802.11 headers in addition to those in hfa384x_tx_frame_t (LLC and SNAP)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic const wlan_llc_t wlan_llc_snap = { 0xaa, 0xaa, 0x03 }; /* LLC header indicating SNAP (?) */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Function prototypes
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Hardware-level hfa384x functions
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * These are based on the ones in hfa384x.h (which are ifdef'd out since __KERNEL__ is not defined).
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Basically, these functions are the result of hand-evaluating all the ifdefs and defines in the hfa384x.h versions.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync/* Retrieve the value of one of the MAC registers. */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic inline UINT16 hfa384x_getreg( hfa384x_t *hw, UINT reg )
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync/* Set the value of one of the MAC registers. */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic inline void hfa384x_setreg( hfa384x_t *hw, UINT16 val, UINT reg )
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Noswap versions
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Etherboot is i386 only, so swap and noswap are the same...
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic inline UINT16 hfa384x_getreg_noswap( hfa384x_t *hw, UINT reg )
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic inline void hfa384x_setreg_noswap( hfa384x_t *hw, UINT16 val, UINT reg )
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Low-level hfa384x functions
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * These are based on the ones in hfa384x.c, modified to work in the Etherboot environment.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * hfa384x_docmd_wait
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Waits for availability of the Command register, then
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * issues the given command. Then polls the Evstat register
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * waiting for command completion.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Arguments:
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * hw device structure
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * cmd Command in host order
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * parm0 Parameter0 in host order
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * parm1 Parameter1 in host order
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * parm2 Parameter2 in host order
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * 0 success
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * >0 command indicated error, Status and Resp0-2 are
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * in hw structure.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic int hfa384x_docmd_wait( hfa384x_t *hw, UINT16 cmd, UINT16 parm0, UINT16 parm1, UINT16 parm2)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* wait for the busy bit to clear */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync while ( HFA384x_CMD_ISBUSY(reg) && (counter < 10) ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf("hfa384x_cmd timeout(1), reg=0x%0hx.\n", reg);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* busy bit clear, write command */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Now wait for completion */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Initialization is the problem. It takes about
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync 100ms. "normal" commands are typically is about
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync 200-400 us (I've never seen less than 200). Longer
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync is better so that we're not hammering the bus. */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync while ( !HFA384x_EVSTAT_ISCMD(reg) && (counter < 5000)) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf("hfa384x_cmd timeout(2), reg=0x%0hx.\n", reg);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Read status and response */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync hfa384x_setreg(hw, HFA384x_EVACK_CMD, HFA384x_EVACK);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Prepare BAP for access. Assigns FID and RID, sets offset register
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * and waits for BAP to become available.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Arguments:
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * hw device structure
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * id FID or RID, destined for the select register (host order)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * offset An _even_ offset into the buffer for the given FID/RID.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * 0 success
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic int hfa384x_prepare_bap(hfa384x_t *hw, UINT16 id, UINT16 offset)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Validate offset, buf, and len */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( (offset > HFA384x_BAP_OFFSET_MAX) || (offset % 2) ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Write fid/rid and offset */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Wait for offset[busy] to clear (see BAP_TIMEOUT) */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync } while ( i < BAP_TIMEOUT && HFA384x_OFFSET_ISBUSY(reg));
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( i >= BAP_TIMEOUT ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* failure */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* failure */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Copy data from BAP to memory.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Arguments:
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * hw device structure
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * id FID or RID, destined for the select register (host order)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * offset An _even_ offset into the buffer for the given FID/RID.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * buf ptr to array of bytes
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * len length of data to transfer in bytes
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * 0 success
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic int hfa384x_copy_from_bap(hfa384x_t *hw, UINT16 id, UINT16 offset,
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Prepare BAP */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( result == 0 ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Read even(len) buf contents from data reg */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync *(UINT16*)(&(d[i])) = hfa384x_getreg_noswap(hw, HFA384x_DATA0);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* If len odd, handle last byte */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf ( "copy_from_bap(%#hx, %#hx, %d) failed, result=%#hx\n", id, offset, len, result);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Copy data from memory to BAP.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Arguments:
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * hw device structure
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * id FID or RID, destined for the select register (host order)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * offset An _even_ offset into the buffer for the given FID/RID.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * buf ptr to array of bytes
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * len length of data to transfer in bytes
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * 0 success
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic int hfa384x_copy_to_bap(hfa384x_t *hw, UINT16 id, UINT16 offset,
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Prepare BAP */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( result == 0 ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Write even(len) buf contents to data reg */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync hfa384x_setreg_noswap(hw, *(UINT16*)(&(d[i])), HFA384x_DATA0);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* If len odd, handle last byte */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync savereg = hfa384x_getreg_noswap(hw, HFA384x_DATA0);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_prepare_bap ( hw, id, offset + (len & 0xfffe) );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( result == 0 ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf ( "copy_to_bap(%#hx, %#hx, %d) failed, result=%#hx\n", id, offset, len, result);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Request a given record to be copied to/from the record buffer.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Arguments:
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * hw device structure
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * write [0|1] copy the record buffer to the given
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * configuration record. (host order)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * rid RID of the record to read/write. (host order)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * 0 success
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic inline int hfa384x_cmd_access(hfa384x_t *hw, UINT16 write, UINT16 rid)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync return hfa384x_docmd_wait(hw, HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ACCESS) | HFA384x_CMD_WRITE_SET(write), rid, 0, 0);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Performs the sequence necessary to read a config/info item.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Arguments:
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * hw device structure
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * rid config/info record id (host order)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * buf host side record buffer. Upon return it will
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * contain the body portion of the record (minus the
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * RID and len).
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * len buffer length (in bytes, should match record length)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * 0 success
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic int hfa384x_drvr_getconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Request read of RID */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Copy out record length */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_copy_from_bap( hw, rid, 0, &rec, sizeof(rec));
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Validate the record length */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( ((hfa384x2host_16(rec.reclen)-1)*2) != len ) { /* note body len calculation in bytes */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf ( "RID len mismatch, rid=%#hx hlen=%d fwlen=%d\n", rid, len, (hfa384x2host_16(rec.reclen)-1)*2);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Copy out record data */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_copy_from_bap( hw, rid, sizeof(rec), buf, len);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Performs the sequence necessary to read a 16/32 bit config/info item
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * and convert it to host order.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Arguments:
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * hw device structure
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * rid config/info record id (in host order)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * val ptr to 16/32 bit buffer to receive value (in host order)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * 0 success
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#if 0 /* Not actually used anywhere */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic int hfa384x_drvr_getconfig16(hfa384x_t *hw, UINT16 rid, void *val)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(UINT16));
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( result == 0 ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync *((UINT16*)val) = hfa384x2host_16(*((UINT16*)val));
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#if 0 /* Not actually used anywhere */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic int hfa384x_drvr_getconfig32(hfa384x_t *hw, UINT16 rid, void *val)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_drvr_getconfig(hw, rid, val, sizeof(UINT32));
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( result == 0 ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync *((UINT32*)val) = hfa384x2host_32(*((UINT32*)val));
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Performs the sequence necessary to write a config/info item.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Arguments:
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * hw device structure
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * rid config/info record id (in host order)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * buf host side record buffer
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * len buffer length (in bytes)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * 0 success
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic int hfa384x_drvr_setconfig(hfa384x_t *hw, UINT16 rid, void *buf, UINT16 len)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync rec.reclen = host2hfa384x_16((len/2) + 1); /* note conversion to words, +1 for rid field */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* write the record header */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_copy_to_bap( hw, rid, 0, &rec, sizeof(rec));
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* write the record data (if there is any) */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( len > 0 ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_copy_to_bap( hw, rid, sizeof(rec), buf, len);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Trigger setting of record */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Performs the sequence necessary to write a 16/32 bit config/info item.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Arguments:
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * hw device structure
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * rid config/info record id (in host order)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * val 16/32 bit value to store (in host order)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * 0 success
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic int hfa384x_drvr_setconfig16(hfa384x_t *hw, UINT16 rid, UINT16 *val)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(UINT16));
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync#if 0 /* Not actually used anywhere */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic int hfa384x_drvr_setconfig32(hfa384x_t *hw, UINT16 rid, UINT32 *val)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync return hfa384x_drvr_setconfig(hw, rid, &value, sizeof(UINT32));
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Wait for an event, with specified checking interval and timeout.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Automatically acknolwedges events.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Arguments:
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * hw device structure
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * event_mask EVSTAT register mask of events to wait for
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * event_ack EVACK register set of events to be acknowledged if they happen (can be
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * used to acknowledge "ignorable" events in addition to the "main" event)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * wait Time (in us) to wait between each poll of the register
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * timeout Maximum number of polls before timing out
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * descr Descriptive text string of what is being waited for
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * (will be printed out if a timeout happens)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * value of EVSTAT register, or 0 on failure
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic int hfa384x_wait_for_event(hfa384x_t *hw, UINT16 event_mask, UINT16 event_ack, int wait, int timeout, const char *descr)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf("hfa384x: Timed out waiting for %s\n", descr);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync return 0; /* Return failure */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Acknowledge all events that we were waiting on */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync hfa384x_setreg(hw, reg & ( event_mask | event_ack ), HFA384x_EVACK);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync/**************************************************************************
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncPOLL - Wait for a frame
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync***************************************************************************/
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic int prism2_poll(struct nic *nic, int retrieve)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Check for received packet */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* No packet received - return 0 */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Acknowledge RX event */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync hfa384x_setreg(hw, HFA384x_EVACK_RX_SET(1), HFA384x_EVACK);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Get RX FID */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Get the descriptor (including headers) */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_copy_from_bap(hw, rxfid, 0, &rxdesc, sizeof(rxdesc));
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync return 0; /* fail */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Byte order convert once up front. */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync rxdesc.data_len = hfa384x2host_16(rxdesc.data_len);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Fill in nic->packetlen */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Fill in nic->packet */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * NOTE: Packets as received have an 8-byte header (LLC+SNAP(?)) terminating with the packet type.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * Etherboot expects a 14-byte header terminating with the packet type (it ignores the rest of the
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * header), so we use a quick hack to achieve this.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_copy_from_bap(hw, rxfid, HFA384x_RX_DATA_OFF,
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync nic->packet + ETH_HLEN - sizeof(wlan_80211hdr_t), nic->packetlen);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync return 0; /* fail */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync/**************************************************************************
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncTRANSMIT - Transmit a frame
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync***************************************************************************/
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync const char *d, /* Destination */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync unsigned int t, /* Type */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync unsigned int s, /* size */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync const char *p) /* Packet */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync wlan_80211hdr_t p80211hdr = { wlan_llc_snap, {{0,0,0},0} };
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync // Request FID allocation
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_docmd_wait(hw, HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ALLOC), HFA384x_DRVR_TXBUF_MAX, 0, 0);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf("hfa384x: Tx FID allocate command failed: Aborting transmit..\n");
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( !hfa384x_wait_for_event(hw, HFA384x_EVSTAT_ALLOC, HFA384x_EVACK_INFO, 10, 50, "Tx FID to be allocated\n" ) ) return;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Build Tx frame structure */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync txdesc.tx_control = host2hfa384x_16( HFA384x_TX_MACPORT_SET(0) | HFA384x_TX_STRUCTYPE_SET(1) |
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync txdesc.frame_control = host2ieee16( WLAN_SET_FC_FTYPE(WLAN_FTYPE_DATA) |
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync memcpy(txdesc.address2, nic->node_addr, WLAN_ADDR_LEN);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync txdesc.data_len = host2hfa384x_16( sizeof(txdesc) + sizeof(p80211hdr) + s );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Set up SNAP header */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Let OUI default to RFC1042 (0x000000) */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Copy txdesc, p80211hdr and payload parts to FID */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_copy_to_bap(hw, fid, 0, &txdesc, sizeof(txdesc));
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_copy_to_bap( hw, fid, sizeof(txdesc), &p80211hdr, sizeof(p80211hdr) );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_copy_to_bap( hw, fid, sizeof(txdesc) + sizeof(p80211hdr), (UINT8*)p, s );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Issue Tx command */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_docmd_wait(hw, HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_TX), fid, 0, 0);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( result != 0 ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf("hfa384x: Transmit failed with result %#hx.\n", result);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Wait for transmit completion (or exception) */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_wait_for_event(hw, HFA384x_EVSTAT_TXEXC | HFA384x_EVSTAT_TX, HFA384x_EVACK_INFO,
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf ( "Tx exception occurred with fid %#hx\n", fid );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_copy_from_bap(hw, fid, 0, &status, sizeof(status));
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf("hfa384x: Tx error occurred (status %#hx):\n", status);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( HFA384x_TXSTATUS_ISACKERR(status) ) { printf(" ...acknowledgement error\n"); }
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( HFA384x_TXSTATUS_ISFORMERR(status) ) { printf(" ...format error\n"); }
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( HFA384x_TXSTATUS_ISDISCON(status) ) { printf(" ...disconnected error\n"); }
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( HFA384x_TXSTATUS_ISAGEDERR(status) ) { printf(" ...AGED error\n"); }
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( HFA384x_TXSTATUS_ISRETRYERR(status) ) { printf(" ...retry error\n"); }
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync return; /* fail */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync/**************************************************************************
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncDISABLE - Turn off ethernet interface
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync***************************************************************************/
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic void prism2_disable ( struct nic *nic __unused ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* put the card in its initial state */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync/**************************************************************************
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncIRQ - Enable, Disable, or Force interrupts
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync***************************************************************************/
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic void prism2_irq(struct nic *nic __unused, irq_action_t action __unused)
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync switch ( action ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync/**************************************************************************
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncOperations table
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync***************************************************************************/
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync/**************************************************************************
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncPROBE - Look for an adapter, this routine's visible to the outside
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncYou should omit the last argument struct pci_device * for a non-PCI NIC
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync***************************************************************************/
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsyncstatic int prism2_probe ( struct nic *nic, hfa384x_t *hw ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Initialize card */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_docmd_wait(hw, HFA384x_CMDCODE_INIT, 0,0,0); /* Send initialize command */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( result ) printf ( "Initialize command returned %#hx\n", result );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync hfa384x_setreg(hw, 0, HFA384x_INTEN); /* Disable interrupts */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync hfa384x_setreg(hw, 0xffff, HFA384x_EVACK); /* Acknowledge any spurious events */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync DBG ( "MAC address %s\n", eth_ntoa ( nic->node_addr ) );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Retrieve MAC address (and fill out nic->node_addr) */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync hfa384x_drvr_getconfig ( hw, HFA384x_RID_CNFOWNMACADDR, nic->node_addr, HFA384x_RID_CNFOWNMACADDR_LEN );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Prepare card for autojoin */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* This procedure is reverse-engineered from a register-level trace of the Linux driver's join process */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync tmp16 = WLAN_DATA_MAXLEN; /* Set maximum data length */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFMAXDATALEN, &tmp16);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( result ) printf ( "Set Max Data Length command returned %#hx\n", result );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_TXRATECNTL, &tmp16);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( result ) printf ( "Set Transmit Rate command returned %#hx\n", result );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync tmp16 = HFA384x_CNFAUTHENTICATION_OPENSYSTEM; /* Set authentication type to OpenSystem */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFAUTHENTICATION, &tmp16);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( result ) printf ( "Set Authentication Type command returned %#hx\n", result );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Set SSID */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync for ( tmp16=0; tmp16<sizeof(hardcoded_ssid); tmp16++ ) { ssid[2+tmp16] = hardcoded_ssid[tmp16]; }
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync ssid[0] = sizeof(hardcoded_ssid) - 1; /* Ignore terminating zero */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_drvr_setconfig(hw, HFA384x_RID_CNFDESIREDSSID, ssid, HFA384x_RID_CNFDESIREDSSID_LEN); /* Set the SSID */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( result ) printf ( "Set SSID command returned %#hx\n", result );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_drvr_setconfig16(hw, HFA384x_RID_CNFPORTTYPE, &tmp16);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( result ) printf ( "Set port type command returned %#hx\n", result );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Enable card */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_docmd_wait(hw, HFA384x_CMD_CMDCODE_SET(HFA384x_CMDCODE_ENABLE) | HFA384x_CMD_MACPORT_SET(0), 0,0,0);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( result ) printf ( "Enable command returned %#hx\n", result );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Increment info_count, abort if too many attempts.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync * See comment next to definition of MAX_JOIN_INFO_COUNT for explanation.
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf ( "Too many failed attempts - aborting\n" );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Wait for info frame to indicate link status */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Empty SSID => join to any SSID */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf ( "Attempting to autojoin to any available access point (attempt %d)...", info_count );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf ( "Attempting to autojoin to SSID %s (attempt %d)...", &ssid[2], info_count );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( !hfa384x_wait_for_event(hw, HFA384x_EVSTAT_INFO, 0, 1000, 2000, "Info event" ) ) return 0;
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Retrieve the length */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_copy_from_bap( hw, infofid, 0, &inf.framelen, sizeof(UINT16));
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Retrieve the rest */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_copy_from_bap( hw, infofid, sizeof(UINT16),
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Not a Link Status info frame: die */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf ( "Unexpected info frame type %#hx (not LinkStatus type)\n", inf.infotype );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync inf.info.linkstatus.linkstatus = hfa384x2host_16(inf.info.linkstatus.linkstatus);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync if ( inf.info.linkstatus.linkstatus != HFA384x_LINK_CONNECTED ) {
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Link not connected - retry */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync printf ( "Link not connected (status %#hx)\n", inf.info.linkstatus.linkstatus );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync } while ( inf.info.linkstatus.linkstatus != HFA384x_LINK_CONNECTED );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* Retrieve BSSID and print Connected message */
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync result = hfa384x_drvr_getconfig(hw, HFA384x_RID_CURRENTBSSID, hw->bssid, WLAN_BSSID_LEN);
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync DBG ( "Link connected (BSSID %s - ", eth_ntoa ( hw->bssid ) );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync DBG ( " MAC address %s)\n", eth_ntoa (nic->node_addr ) );
a734c64bff58bda2fa48c2795453e092167b0ff7vboxsync /* point to NIC specific routines */