|
|
1.1 ! root 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 <ipxe/pci.h> ! 21: #include <ipxe/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*)(®))[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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.