[e16e8f2] | 1 | /************************************************************************** |
---|
| 2 | Etherboot - BOOTP/TFTP Bootstrap Program |
---|
| 3 | Prism2 NIC driver for Etherboot |
---|
| 4 | |
---|
| 5 | Written by Michael Brown of Fen Systems Ltd |
---|
| 6 | $Id$ |
---|
| 7 | ***************************************************************************/ |
---|
| 8 | |
---|
| 9 | /* |
---|
| 10 | * This program is free software; you can redistribute it and/or |
---|
| 11 | * modify it under the terms of the GNU General Public License as |
---|
| 12 | * published by the Free Software Foundation; either version 2, or (at |
---|
| 13 | * your option) any later version. |
---|
| 14 | */ |
---|
| 15 | |
---|
| 16 | FILE_LICENCE ( GPL2_OR_LATER ); |
---|
| 17 | |
---|
| 18 | #include <etherboot.h> |
---|
| 19 | #include <nic.h> |
---|
| 20 | #include <gpxe/pci.h> |
---|
| 21 | #include <gpxe/ethernet.h> |
---|
| 22 | |
---|
| 23 | /* |
---|
| 24 | * Hard-coded SSID |
---|
| 25 | * Leave blank in order to connect to any available SSID |
---|
| 26 | */ |
---|
| 27 | |
---|
| 28 | static const char hardcoded_ssid[] = ""; |
---|
| 29 | |
---|
| 30 | /* |
---|
| 31 | * Maximum number of info packets to wait for on a join attempt. |
---|
| 32 | * Some APs (including the Linksys WAP11) will send a "you are disconnected" packet |
---|
| 33 | * before sending the "you are connected" packet, if the card has previously been |
---|
| 34 | * attached to the AP. |
---|
| 35 | * |
---|
| 36 | * 2 is probably a sensible value, but YMMV. |
---|
| 37 | */ |
---|
| 38 | |
---|
| 39 | #define MAX_JOIN_INFO_COUNT 2 |
---|
| 40 | |
---|
| 41 | /* |
---|
| 42 | * Type of Prism2 interface to support |
---|
| 43 | * If not already defined, select PLX |
---|
| 44 | */ |
---|
| 45 | #ifndef WLAN_HOSTIF |
---|
| 46 | #define WLAN_HOSTIF WLAN_PLX |
---|
| 47 | #endif |
---|
| 48 | |
---|
| 49 | /* |
---|
| 50 | * Include wlan_compat, p80211 and hfa384x header files from Linux Prism2 driver |
---|
| 51 | * We need to hack some defines in order to avoid compiling kernel-specific routines |
---|
| 52 | */ |
---|
| 53 | |
---|
| 54 | #define __LINUX_WLAN__ |
---|
| 55 | #undef __KERNEL__ |
---|
| 56 | #define __I386__ |
---|
| 57 | #include "wlan_compat.h" |
---|
| 58 | #include "p80211hdr.h" |
---|
| 59 | #include "hfa384x.h" |
---|
| 60 | #define BAP_TIMEOUT ( 5000 ) |
---|
| 61 | |
---|
| 62 | /* |
---|
| 63 | * A few hacks to make the coding environment more Linux-like. This makes it somewhat |
---|
| 64 | * quicker to convert code from the Linux Prism2 driver. |
---|
| 65 | */ |
---|
| 66 | #include <errno.h> |
---|
| 67 | #define __le16_to_cpu(x) (x) |
---|
| 68 | #define __le32_to_cpu(x) (x) |
---|
| 69 | #define __cpu_to_le16(x) (x) |
---|
| 70 | #define __cpu_to_le32(x) (x) |
---|
| 71 | |
---|
| 72 | #define hfa384x2host_16(n) (__le16_to_cpu((UINT16)(n))) |
---|
| 73 | #define hfa384x2host_32(n) (__le32_to_cpu((UINT32)(n))) |
---|
| 74 | #define host2hfa384x_16(n) (__cpu_to_le16((UINT16)(n))) |
---|
| 75 | #define host2hfa384x_32(n) (__cpu_to_le32((UINT32)(n))) |
---|
| 76 | |
---|
| 77 | /* |
---|
| 78 | * PLX9052 PCI register offsets |
---|
| 79 | * Taken from PLX9052 datasheet available from http://www.plxtech.com/download/9052/databook/9052db-20.pdf |
---|
| 80 | */ |
---|
| 81 | |
---|
| 82 | #define PLX_LOCAL_CONFIG_REGISTER_BASE ( PCI_BASE_ADDRESS_1 ) |
---|
| 83 | #define PLX_LOCAL_ADDRESS_SPACE_0_BASE ( PCI_BASE_ADDRESS_2 ) |
---|
| 84 | #define PLX_LOCAL_ADDRESS_SPACE_1_BASE ( PCI_BASE_ADDRESS_3 ) |
---|
| 85 | #define PLX_LOCAL_ADDRESS_SPACE_2_BASE ( PCI_BASE_ADDRESS_4 ) |
---|
| 86 | #define PLX_LOCAL_ADDRESS_SPACE_3_BASE ( PCI_BASE_ADDRESS_5 ) |
---|
| 87 | |
---|
| 88 | #define PRISM2_PLX_ATTR_MEM_BASE ( PLX_LOCAL_ADDRESS_SPACE_0_BASE ) |
---|
| 89 | #define PRISM2_PLX_IO_BASE ( PLX_LOCAL_ADDRESS_SPACE_1_BASE ) |
---|
| 90 | |
---|
| 91 | #define PRISM2_PCI_MEM_BASE ( PCI_BASE_ADDRESS_0 ) |
---|
| 92 | |
---|
| 93 | /* |
---|
| 94 | * PCMCIA CIS types |
---|
| 95 | * Taken from cistpl.h in pcmcia-cs |
---|
| 96 | */ |
---|
| 97 | |
---|
| 98 | #define CISTPL_VERS_1 ( 0x15 ) |
---|
| 99 | #define CISTPL_END ( 0xff ) |
---|
| 100 | |
---|
| 101 | #define CIS_STEP ( 2 ) |
---|
| 102 | #define CISTPL_HEADER_LEN ( 2 * CIS_STEP ) |
---|
| 103 | #define CISTPL_LEN_OFF ( 1 * CIS_STEP ) |
---|
| 104 | #define CISTPL_VERS_1_STR_OFF ( 4 * CIS_STEP ) |
---|
| 105 | |
---|
| 106 | /* |
---|
| 107 | * Prism2 constants |
---|
| 108 | * Taken from prism2sta.c in linux-wlan-ng |
---|
| 109 | */ |
---|
| 110 | |
---|
| 111 | #define COR_OFFSET ( 0x3e0 ) /* COR attribute offset of Prism2 PC card */ |
---|
| 112 | #define COR_VALUE ( 0x41 ) /* Enable PC card with irq in level trigger (but interrupts disabled) */ |
---|
| 113 | |
---|
| 114 | /* NIC specific static variables */ |
---|
| 115 | |
---|
| 116 | /* The hfa384x_t structure is used extensively in the Linux driver but is ifdef'd out in our include since __KERNEL__ is not defined. |
---|
| 117 | * This is a dummy version that contains only the fields we are interested in. |
---|
| 118 | */ |
---|
| 119 | |
---|
| 120 | typedef struct hfa384x |
---|
| 121 | { |
---|
| 122 | UINT32 iobase; |
---|
| 123 | void *membase; |
---|
| 124 | UINT16 lastcmd; |
---|
| 125 | UINT16 status; /* in host order */ |
---|
| 126 | UINT16 resp0; /* in host order */ |
---|
| 127 | UINT16 resp1; /* in host order */ |
---|
| 128 | UINT16 resp2; /* in host order */ |
---|
| 129 | UINT8 bssid[WLAN_BSSID_LEN]; |
---|
| 130 | } hfa384x_t; |
---|
| 131 | |
---|
| 132 | /* The global instance of the hardware (i.e. where we store iobase and membase, in the absence of anywhere better to put them */ |
---|
| 133 | static hfa384x_t hw_global = { |
---|
| 134 | 0, 0, 0, 0, 0, 0, 0, {0,0,0,0,0,0} |
---|
| 135 | }; |
---|
| 136 | |
---|
| 137 | /* |
---|
| 138 | * 802.11 headers in addition to those in hfa384x_tx_frame_t (LLC and SNAP) |
---|
| 139 | * Taken from p80211conv.h |
---|
| 140 | */ |
---|
| 141 | |
---|
| 142 | typedef struct wlan_llc |
---|
| 143 | { |
---|
| 144 | UINT8 dsap; |
---|
| 145 | UINT8 ssap; |
---|
| 146 | UINT8 ctl; |
---|
| 147 | } wlan_llc_t; |
---|
| 148 | |
---|
| 149 | static const wlan_llc_t wlan_llc_snap = { 0xaa, 0xaa, 0x03 }; /* LLC header indicating SNAP (?) */ |
---|
| 150 | |
---|
| 151 | #define WLAN_IEEE_OUI_LEN 3 |
---|
| 152 | typedef struct wlan_snap |
---|
| 153 | { |
---|
| 154 | UINT8 oui[WLAN_IEEE_OUI_LEN]; |
---|
| 155 | UINT16 type; |
---|
| 156 | } wlan_snap_t; |
---|
| 157 | |
---|
| 158 | typedef struct wlan_80211hdr |
---|
| 159 | { |
---|
| 160 | wlan_llc_t llc; |
---|
| 161 | wlan_snap_t snap; |
---|
| 162 | } wlan_80211hdr_t; |
---|
| 163 | |
---|
| 164 | /* |
---|
| 165 | * Function prototypes |
---|
| 166 | */ |
---|
| 167 | |
---|
| 168 | /* |
---|
| 169 | * Hardware-level hfa384x functions |
---|
| 170 | * These are based on the ones in hfa384x.h (which are ifdef'd out since __KERNEL__ is not defined). |
---|
| 171 | * Basically, these functions are the result of hand-evaluating all the ifdefs and defines in the hfa384x.h versions. |
---|
| 172 | */ |
---|
| 173 | |
---|
| 174 | /* Retrieve the value of one of the MAC registers. */ |
---|
| 175 | static inline UINT16 hfa384x_getreg( hfa384x_t *hw, UINT reg ) |
---|
| 176 | { |
---|
| 177 | #if (WLAN_HOSTIF == WLAN_PLX) |
---|
| 178 | return inw ( hw->iobase + reg ); |
---|
| 179 | #elif (WLAN_HOSTIF == WLAN_PCI) |
---|
| 180 | return readw ( hw->membase + reg ); |
---|
| 181 | #endif |
---|
| 182 | } |
---|
| 183 | |
---|
| 184 | /* Set the value of one of the MAC registers. */ |
---|
| 185 | static inline void hfa384x_setreg( hfa384x_t *hw, UINT16 val, UINT reg ) |
---|
| 186 | { |
---|
| 187 | #if (WLAN_HOSTIF == WLAN_PLX) |
---|
| 188 | outw ( val, hw->iobase + reg ); |
---|
| 189 | #elif (WLAN_HOSTIF == WLAN_PCI) |
---|
| 190 | writew ( val, hw->membase + reg ); |
---|
| 191 | #endif |
---|
| 192 | return; |
---|
| 193 | } |
---|
| 194 | |
---|
| 195 | /* |
---|
| 196 | * Noswap versions |
---|
| 197 | * Etherboot is i386 only, so swap and noswap are the same... |
---|
| 198 | */ |
---|
| 199 | static inline UINT16 hfa384x_getreg_noswap( hfa384x_t *hw, UINT reg ) |
---|
| 200 | { |
---|
| 201 | return hfa384x_getreg ( hw, reg ); |
---|
| 202 | } |
---|
| 203 | static inline void hfa384x_setreg_noswap( hfa384x_t *hw, UINT16 val, UINT reg ) |
---|
| 204 | { |
---|
| 205 | hfa384x_setreg ( hw, val, reg ); |
---|
| 206 | } |
---|
| 207 | |
---|
| 208 | /* |
---|
| 209 | * Low-level hfa384x functions |
---|
| 210 | * These are based on the ones in hfa384x.c, modified to work in the Etherboot environment. |
---|
| 211 | */ |
---|
| 212 | |
---|
| 213 | /* |
---|
| 214 | * hfa384x_docmd_wait |
---|
| 215 | * |
---|
| 216 | * Waits for availability of the Command register, then |
---|
| 217 | * issues the given command. Then polls the Evstat register |
---|
| 218 | * waiting for command completion. |
---|
| 219 | * Arguments: |
---|
| 220 | * hw device structure |
---|
| 221 | * cmd Command in host order |
---|
| 222 | * parm0 Parameter0 in host order |
---|
| 223 | * parm1 Parameter1 in host order |
---|
| 224 | * parm2 Parameter2 in host order |
---|
| 225 | * Returns: |
---|
| 226 | * 0 success |
---|
| 227 | * >0 command indicated error, Status and Resp0-2 are |
---|
| 228 | * in hw structure. |
---|
| 229 | */ |
---|
| 230 | static int hfa384x_docmd_wait( hfa384x_t *hw, UINT16 cmd, UINT16 parm0, UINT16 parm1, UINT16 parm2) |
---|
| 231 | { |
---|
| 232 | UINT16 reg = 0; |
---|
| 233 | UINT16 counter = 0; |
---|
| 234 | |
---|
| 235 | /* wait for the busy bit to clear */ |
---|
| 236 | counter = 0; |
---|
| 237 | reg = hfa384x_getreg(hw, HFA384x_CMD); |
---|
| 238 | while ( HFA384x_CMD_ISBUSY(reg) && (counter < 10) ) { |
---|
| 239 | reg = hfa384x_getreg(hw, HFA384x_CMD); |
---|
| 240 | counter++; |
---|
| 241 | udelay(10); |
---|
| 242 | } |
---|
| 243 | if (HFA384x_CMD_ISBUSY(reg)) { |
---|
| 244 | printf("hfa384x_cmd timeout(1), reg=0x%0hx.\n", reg); |
---|
| 245 | return -ETIMEDOUT; |
---|
| 246 | } |
---|
| 247 | |
---|
| 248 | /* busy bit clear, write command */ |
---|
| 249 | hfa384x_setreg(hw, parm0, HFA384x_PARAM0); |
---|
| 250 | hfa384x_setreg(hw, parm1, HFA384x_PARAM1); |
---|
| 251 | hfa384x_setreg(hw, parm2, HFA384x_PARAM2); |
---|
| 252 | hw->lastcmd = cmd; |
---|
| 253 | hfa384x_setreg(hw, cmd, HFA384x_CMD); |
---|
| 254 | |
---|
| 255 | /* Now wait for completion */ |
---|
| 256 | counter = 0; |
---|
| 257 | reg = hfa384x_getreg(hw, HFA384x_EVSTAT); |
---|
| 258 | /* Initialization is the problem. It takes about |
---|
| 259 | 100ms. "normal" commands are typically is about |
---|
| 260 | 200-400 us (I've never seen less than 200). Longer |
---|
| 261 | is better so that we're not hammering the bus. */ |
---|
| 262 | while ( !HFA384x_EVSTAT_ISCMD(reg) && (counter < 5000)) { |
---|
| 263 | reg = hfa384x_getreg(hw, HFA384x_EVSTAT); |
---|
| 264 | counter++; |
---|
| 265 | udelay(200); |
---|
| 266 | } |
---|
| 267 | if ( ! HFA384x_EVSTAT_ISCMD(reg) ) { |
---|
| 268 | printf("hfa384x_cmd timeout(2), reg=0x%0hx.\n", reg); |
---|
| 269 | return -ETIMEDOUT; |
---|
| 270 | } |
---|
| 271 | |
---|
| 272 | /* Read status and response */ |
---|
| 273 | hw->status = hfa384x_getreg(hw, HFA384x_STATUS); |
---|
| 274 | hw->resp0 = hfa384x_getreg(hw, HFA384x_RESP0); |
---|
| 275 | hw->resp1 = hfa384x_getreg(hw, HFA384x_RESP1); |
---|
| 276 | hw->resp2 = hfa384x_getreg(hw, HFA384x_RESP2); |
---|
| 277 | hfa384x_setreg(hw, HFA384x_EVACK_CMD, HFA384x_EVACK); |
---|
| 278 | return HFA384x_STATUS_RESULT_GET(hw->status); |
---|
| 279 | } |
---|
| 280 | |
---|
| 281 | /* |
---|
| 282 | * Prepare BAP for access. Assigns FID and RID, sets offset register |
---|
| 283 | * and waits for BAP to become available. |
---|
| 284 | * |
---|
| 285 | * Arguments: |
---|
| 286 | * hw device structure |
---|
| 287 | * id FID or RID, destined for the select register (host order) |
---|
| 288 | * offset An _even_ offset into the buffer for the given FID/RID. |
---|
| 289 | * Returns: |
---|
| 290 | * 0 success |
---|
| 291 | */ |
---|
| 292 | static int hfa384x_prepare_bap(hfa384x_t *hw, UINT16 id, UINT16 offset) |
---|
| 293 | { |
---|
| 294 | int result = 0; |
---|
| 295 | UINT16 reg; |
---|
| 296 | UINT16 i; |
---|
| 297 | |
---|
| 298 | /* Validate offset, buf, and len */ |
---|
| 299 | if ( (offset > HFA384x_BAP_OFFSET_MAX) || (offset % 2) ) { |
---|
| 300 | result = -EINVAL; |
---|
| 301 | } else { |
---|
| 302 | /* Write fid/rid and offset */ |
---|
| 303 | hfa384x_setreg(hw, id, HFA384x_SELECT0); |
---|
| 304 | udelay(10); |
---|
| 305 | hfa384x_setreg(hw, offset, HFA384x_OFFSET0); |
---|
| 306 | /* Wait for offset[busy] to clear (see BAP_TIMEOUT) */ |
---|
| 307 | i = 0; |
---|
| 308 | do { |
---|
| 309 | reg = hfa384x_getreg(hw, HFA384x_OFFSET0); |
---|
| 310 | if ( i > 0 ) udelay(2); |
---|
| 311 | i++; |
---|
| 312 | } while ( i < BAP_TIMEOUT && HFA384x_OFFSET_ISBUSY(reg)); |
---|
| 313 | if ( i >= BAP_TIMEOUT ) { |
---|
| 314 | /* failure */ |
---|
| 315 | result = reg; |
---|
| 316 | } else if ( HFA384x_OFFSET_ISERR(reg) ){ |
---|
| 317 | /* failure */ |
---|
| 318 | result = reg; |
---|
| 319 | } |
---|
| 320 | } |
---|
| 321 | return result; |
---|
| 322 | } |
---|
| 323 | |
---|
| 324 | /* |
---|
| 325 | * Copy data from BAP to memory. |
---|
| 326 | * |
---|
| 327 | * Arguments: |
---|
| 328 | * hw device structure |
---|
| 329 | * id FID or RID, destined for the select register (host order) |
---|
| 330 | * offset An _even_ offset into the buffer for the given FID/RID. |
---|
| 331 | * buf ptr to array of bytes |
---|
| 332 | * len length of data to transfer in bytes |
---|
| 333 | * Returns: |
---|
| 334 | * 0 success |
---|
| 335 | */ |
---|
| 336 | static int hfa384x_copy_from_bap(hfa384x_t *hw, UINT16 id, UINT16 offset, |
---|
| 337 | void *buf, UINT len) |
---|
| 338 | { |
---|
| 339 | int result = 0; |
---|
| 340 | UINT8 *d = (UINT8*)buf; |
---|
| 341 | UINT16 i; |
---|
| 342 | UINT16 reg = 0; |
---|
| 343 | |
---|
| 344 | /* Prepare BAP */ |
---|
| 345 | result = hfa384x_prepare_bap ( hw, id, offset ); |
---|
| 346 | if ( result == 0 ) { |
---|
| 347 | /* Read even(len) buf contents from data reg */ |
---|
| 348 | for ( i = 0; i < (len & 0xfffe); i+=2 ) { |
---|
| 349 | *(UINT16*)(&(d[i])) = hfa384x_getreg_noswap(hw, HFA384x_DATA0); |
---|
| 350 | } |
---|
| 351 | /* If len odd, handle last byte */ |
---|
| 352 | if ( len % 2 ){ |
---|
| 353 | reg = hfa384x_getreg_noswap(hw, HFA384x_DATA0); |
---|
| 354 | d[len-1] = ((UINT8*)(®))[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 | |
---|