|
|
1.1 ! root 1: /* ! 2: * WaveLAN ISA driver ! 3: * ! 4: * Jean II - HPLB '96 ! 5: * ! 6: * Reorganisation and extension of the driver. ! 7: * Original copyright follows (also see the end of this file). ! 8: * See wavelan.p.h for details. ! 9: */ ! 10: ! 11: /* ! 12: * AT&T GIS (nee NCR) WaveLAN card: ! 13: * An Ethernet-like radio transceiver ! 14: * controlled by an Intel 82586 coprocessor. ! 15: */ ! 16: ! 17: #include "wavelan.p.h" /* Private header */ ! 18: ! 19: /************************* MISC SUBROUTINES **************************/ ! 20: /* ! 21: * Subroutines which won't fit in one of the following category ! 22: * (WaveLAN modem or i82586) ! 23: */ ! 24: ! 25: /*------------------------------------------------------------------*/ ! 26: /* ! 27: * Wrapper for disabling interrupts. ! 28: */ ! 29: static inline unsigned long ! 30: wv_splhi(void) ! 31: { ! 32: unsigned long flags; ! 33: ! 34: save_flags(flags); ! 35: cli(); ! 36: ! 37: return(flags); ! 38: } ! 39: ! 40: /*------------------------------------------------------------------*/ ! 41: /* ! 42: * Wrapper for re-enabling interrupts. ! 43: */ ! 44: static inline void ! 45: wv_splx(unsigned long flags) ! 46: { ! 47: restore_flags(flags); ! 48: } ! 49: ! 50: /*------------------------------------------------------------------*/ ! 51: /* ! 52: * Translate irq number to PSA irq parameter ! 53: */ ! 54: static u_char ! 55: wv_irq_to_psa(int irq) ! 56: { ! 57: if(irq < 0 || irq >= NELS(irqvals)) ! 58: return 0; ! 59: ! 60: return irqvals[irq]; ! 61: } ! 62: ! 63: /*------------------------------------------------------------------*/ ! 64: /* ! 65: * Translate PSA irq parameter to irq number ! 66: */ ! 67: static int ! 68: wv_psa_to_irq(u_char irqval) ! 69: { ! 70: int irq; ! 71: ! 72: for(irq = 0; irq < NELS(irqvals); irq++) ! 73: if(irqvals[irq] == irqval) ! 74: return irq; ! 75: ! 76: return -1; ! 77: } ! 78: ! 79: #ifdef STRUCT_CHECK ! 80: /*------------------------------------------------------------------*/ ! 81: /* ! 82: * Sanity routine to verify the sizes of the various WaveLAN interface ! 83: * structures. ! 84: */ ! 85: static char * ! 86: wv_struct_check(void) ! 87: { ! 88: #define SC(t,s,n) if (sizeof(t) != s) return(n); ! 89: ! 90: SC(psa_t, PSA_SIZE, "psa_t"); ! 91: SC(mmw_t, MMW_SIZE, "mmw_t"); ! 92: SC(mmr_t, MMR_SIZE, "mmr_t"); ! 93: SC(ha_t, HA_SIZE, "ha_t"); ! 94: ! 95: #undef SC ! 96: ! 97: return((char *) NULL); ! 98: } /* wv_struct_check */ ! 99: #endif /* STRUCT_CHECK */ ! 100: ! 101: /********************* HOST ADAPTER SUBROUTINES *********************/ ! 102: /* ! 103: * Useful subroutines to manage the WaveLAN ISA interface ! 104: * ! 105: * One major difference with the PCMCIA hardware (except the port mapping) ! 106: * is that we have to keep the state of the Host Control Register ! 107: * because of the interrupt enable & bus size flags. ! 108: */ ! 109: ! 110: /*------------------------------------------------------------------*/ ! 111: /* ! 112: * Read from card's Host Adaptor Status Register. ! 113: */ ! 114: static inline u_short ! 115: hasr_read(u_long ioaddr) ! 116: { ! 117: return(inw(HASR(ioaddr))); ! 118: } /* hasr_read */ ! 119: ! 120: /*------------------------------------------------------------------*/ ! 121: /* ! 122: * Write to card's Host Adapter Command Register. ! 123: */ ! 124: static inline void ! 125: hacr_write(u_long ioaddr, ! 126: u_short hacr) ! 127: { ! 128: outw(hacr, HACR(ioaddr)); ! 129: } /* hacr_write */ ! 130: ! 131: /*------------------------------------------------------------------*/ ! 132: /* ! 133: * Write to card's Host Adapter Command Register. Include a delay for ! 134: * those times when it is needed. ! 135: */ ! 136: static inline void ! 137: hacr_write_slow(u_long ioaddr, ! 138: u_short hacr) ! 139: { ! 140: hacr_write(ioaddr, hacr); ! 141: /* delay might only be needed sometimes */ ! 142: udelay(1000L); ! 143: } /* hacr_write_slow */ ! 144: ! 145: /*------------------------------------------------------------------*/ ! 146: /* ! 147: * Set the channel attention bit. ! 148: */ ! 149: static inline void ! 150: set_chan_attn(u_long ioaddr, ! 151: u_short hacr) ! 152: { ! 153: hacr_write(ioaddr, hacr | HACR_CA); ! 154: } /* set_chan_attn */ ! 155: ! 156: /*------------------------------------------------------------------*/ ! 157: /* ! 158: * Reset, and then set host adaptor into default mode. ! 159: */ ! 160: static inline void ! 161: wv_hacr_reset(u_long ioaddr) ! 162: { ! 163: hacr_write_slow(ioaddr, HACR_RESET); ! 164: hacr_write(ioaddr, HACR_DEFAULT); ! 165: } /* wv_hacr_reset */ ! 166: ! 167: /*------------------------------------------------------------------*/ ! 168: /* ! 169: * Set the i/o transfer over the ISA bus to 8 bits mode ! 170: */ ! 171: static inline void ! 172: wv_16_off(u_long ioaddr, ! 173: u_short hacr) ! 174: { ! 175: hacr &= ~HACR_16BITS; ! 176: hacr_write(ioaddr, hacr); ! 177: } /* wv_16_off */ ! 178: ! 179: /*------------------------------------------------------------------*/ ! 180: /* ! 181: * Set the i/o transfer over the ISA bus to 8 bits mode ! 182: */ ! 183: static inline void ! 184: wv_16_on(u_long ioaddr, ! 185: u_short hacr) ! 186: { ! 187: hacr |= HACR_16BITS; ! 188: hacr_write(ioaddr, hacr); ! 189: } /* wv_16_on */ ! 190: ! 191: /*------------------------------------------------------------------*/ ! 192: /* ! 193: * Disable interrupts on the WaveLAN hardware ! 194: */ ! 195: static inline void ! 196: wv_ints_off(device * dev) ! 197: { ! 198: net_local * lp = (net_local *)dev->priv; ! 199: u_long ioaddr = dev->base_addr; ! 200: u_long x; ! 201: ! 202: x = wv_splhi(); ! 203: ! 204: lp->hacr &= ~HACR_INTRON; ! 205: hacr_write(ioaddr, lp->hacr); ! 206: ! 207: wv_splx(x); ! 208: } /* wv_ints_off */ ! 209: ! 210: /*------------------------------------------------------------------*/ ! 211: /* ! 212: * Enable interrupts on the WaveLAN hardware ! 213: */ ! 214: static inline void ! 215: wv_ints_on(device * dev) ! 216: { ! 217: net_local * lp = (net_local *)dev->priv; ! 218: u_long ioaddr = dev->base_addr; ! 219: u_long x; ! 220: ! 221: x = wv_splhi(); ! 222: ! 223: lp->hacr |= HACR_INTRON; ! 224: hacr_write(ioaddr, lp->hacr); ! 225: ! 226: wv_splx(x); ! 227: } /* wv_ints_on */ ! 228: ! 229: /******************* MODEM MANAGEMENT SUBROUTINES *******************/ ! 230: /* ! 231: * Useful subroutines to manage the modem of the WaveLAN ! 232: */ ! 233: ! 234: /*------------------------------------------------------------------*/ ! 235: /* ! 236: * Read the Parameter Storage Area from the WaveLAN card's memory ! 237: */ ! 238: /* ! 239: * Read bytes from the PSA. ! 240: */ ! 241: static void ! 242: psa_read(u_long ioaddr, ! 243: u_short hacr, ! 244: int o, /* offset in PSA */ ! 245: u_char * b, /* buffer to fill */ ! 246: int n) /* size to read */ ! 247: { ! 248: wv_16_off(ioaddr, hacr); ! 249: ! 250: while(n-- > 0) ! 251: { ! 252: outw(o, PIOR2(ioaddr)); ! 253: o++; ! 254: *b++ = inb(PIOP2(ioaddr)); ! 255: } ! 256: ! 257: wv_16_on(ioaddr, hacr); ! 258: } /* psa_read */ ! 259: ! 260: /*------------------------------------------------------------------*/ ! 261: /* ! 262: * Write the Paramter Storage Area to the WaveLAN card's memory ! 263: */ ! 264: static void ! 265: psa_write(u_long ioaddr, ! 266: u_short hacr, ! 267: int o, /* Offset in psa */ ! 268: u_char * b, /* Buffer in memory */ ! 269: int n) /* Length of buffer */ ! 270: { ! 271: int count = 0; ! 272: ! 273: wv_16_off(ioaddr, hacr); ! 274: ! 275: while(n-- > 0) ! 276: { ! 277: outw(o, PIOR2(ioaddr)); ! 278: o++; ! 279: ! 280: outb(*b, PIOP2(ioaddr)); ! 281: b++; ! 282: ! 283: /* Wait for the memory to finish its write cycle */ ! 284: count = 0; ! 285: while((count++ < 100) && ! 286: (hasr_read(ioaddr) & HASR_PSA_BUSY)) ! 287: udelay(1000); ! 288: } ! 289: ! 290: wv_16_on(ioaddr, hacr); ! 291: } /* psa_write */ ! 292: ! 293: #ifdef PSA_CRC ! 294: /*------------------------------------------------------------------*/ ! 295: /* ! 296: * Calculate the PSA CRC (not tested yet) ! 297: * As the WaveLAN drivers don't use the CRC, I won't use it either. ! 298: * Thanks to Valster, Nico <[email protected]> for the code ! 299: * NOTE: By specifying a length including the CRC position the ! 300: * returned value should be zero. (i.e. a correct checksum in the PSA) ! 301: */ ! 302: static u_short ! 303: psa_crc(u_short * psa, /* The PSA */ ! 304: int size) /* Number of short for CRC */ ! 305: { ! 306: int byte_cnt; /* Loop on the PSA */ ! 307: u_short crc_bytes = 0; /* Data in the PSA */ ! 308: int bit_cnt; /* Loop on the bits of the short */ ! 309: ! 310: for(byte_cnt = 0; byte_cnt <= size; byte_cnt++ ) ! 311: { ! 312: crc_bytes ^= psa[byte_cnt]; /* Its an xor */ ! 313: ! 314: for(bit_cnt = 1; bit_cnt < 9; bit_cnt++ ) ! 315: { ! 316: if(crc_bytes & 0x0001) ! 317: crc_bytes = (crc_bytes >> 1) ^ 0xA001; ! 318: else ! 319: crc_bytes >>= 1 ; ! 320: } ! 321: } ! 322: ! 323: return crc_bytes; ! 324: } /* psa_crc */ ! 325: #endif /* PSA_CRC */ ! 326: ! 327: /*------------------------------------------------------------------*/ ! 328: /* ! 329: * Write 1 byte to the MMC. ! 330: */ ! 331: static inline void ! 332: mmc_out(u_long ioaddr, ! 333: u_short o, ! 334: u_char d) ! 335: { ! 336: /* Wait for MMC to go idle */ ! 337: while(inw(HASR(ioaddr)) & HASR_MMC_BUSY) ! 338: ; ! 339: ! 340: outw((u_short) (((u_short) d << 8) | (o << 1) | 1), ! 341: MMCR(ioaddr)); ! 342: } ! 343: ! 344: /*------------------------------------------------------------------*/ ! 345: /* ! 346: * Routine to write bytes to the Modem Management Controller. ! 347: * We start by the end because it is the way it should be ! ! 348: */ ! 349: static inline void ! 350: mmc_write(u_long ioaddr, ! 351: u_char o, ! 352: u_char * b, ! 353: int n) ! 354: { ! 355: o += n; ! 356: b += n; ! 357: ! 358: while(n-- > 0 ) ! 359: mmc_out(ioaddr, --o, *(--b)); ! 360: } /* mmc_write */ ! 361: ! 362: /*------------------------------------------------------------------*/ ! 363: /* ! 364: * Read 1 byte from the MMC. ! 365: * Optimised version for 1 byte, avoid using memory... ! 366: */ ! 367: static inline u_char ! 368: mmc_in(u_long ioaddr, ! 369: u_short o) ! 370: { ! 371: while(inw(HASR(ioaddr)) & HASR_MMC_BUSY) ! 372: ; ! 373: outw(o << 1, MMCR(ioaddr)); ! 374: ! 375: while(inw(HASR(ioaddr)) & HASR_MMC_BUSY) ! 376: ; ! 377: return (u_char) (inw(MMCR(ioaddr)) >> 8); ! 378: } ! 379: ! 380: /*------------------------------------------------------------------*/ ! 381: /* ! 382: * Routine to read bytes from the Modem Management Controller. ! 383: * The implementation is complicated by a lack of address lines, ! 384: * which prevents decoding of the low-order bit. ! 385: * (code has just been moved in the above function) ! 386: * We start by the end because it is the way it should be ! ! 387: */ ! 388: static inline void ! 389: mmc_read(u_long ioaddr, ! 390: u_char o, ! 391: u_char * b, ! 392: int n) ! 393: { ! 394: o += n; ! 395: b += n; ! 396: ! 397: while(n-- > 0) ! 398: *(--b) = mmc_in(ioaddr, --o); ! 399: } /* mmc_read */ ! 400: ! 401: /*------------------------------------------------------------------*/ ! 402: /* ! 403: * Get the type of encryption available... ! 404: */ ! 405: static inline int ! 406: mmc_encr(u_long ioaddr) /* i/o port of the card */ ! 407: { ! 408: int temp; ! 409: ! 410: temp = mmc_in(ioaddr, mmroff(0, mmr_des_avail)); ! 411: if((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES)) ! 412: return 0; ! 413: else ! 414: return temp; ! 415: } ! 416: ! 417: /*------------------------------------------------------------------*/ ! 418: /* ! 419: * Wait for the frequency EEPROM to complete a command... ! 420: * I hope this one will be optimally inlined... ! 421: */ ! 422: static inline void ! 423: fee_wait(u_long ioaddr, /* i/o port of the card */ ! 424: int delay, /* Base delay to wait for */ ! 425: int number) /* Number of time to wait */ ! 426: { ! 427: int count = 0; /* Wait only a limited time */ ! 428: ! 429: while((count++ < number) && ! 430: (mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & MMR_FEE_STATUS_BUSY)) ! 431: udelay(delay); ! 432: } ! 433: ! 434: /*------------------------------------------------------------------*/ ! 435: /* ! 436: * Read bytes from the frequency EEPROM (frequency select cards). ! 437: */ ! 438: static void ! 439: fee_read(u_long ioaddr, /* i/o port of the card */ ! 440: u_short o, /* destination offset */ ! 441: u_short * b, /* data buffer */ ! 442: int n) /* number of registers */ ! 443: { ! 444: b += n; /* Position at the end of the area */ ! 445: ! 446: /* Write the address */ ! 447: mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1); ! 448: ! 449: /* Loop on all buffer */ ! 450: while(n-- > 0) ! 451: { ! 452: /* Write the read command */ ! 453: mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ); ! 454: ! 455: /* Wait until EEPROM is ready (should be quick!) */ ! 456: fee_wait(ioaddr, 10, 100); ! 457: ! 458: /* Read the value */ ! 459: *--b = ((mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)) << 8) | ! 460: mmc_in(ioaddr, mmroff(0, mmr_fee_data_l))); ! 461: } ! 462: } ! 463: ! 464: #ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ ! 465: ! 466: /*------------------------------------------------------------------*/ ! 467: /* ! 468: * Write bytes from the Frequency EEPROM (frequency select cards). ! 469: * This is a bit complicated, because the frequency EEPROM has to ! 470: * be unprotected and the write enabled. ! 471: * Jean II ! 472: */ ! 473: static void ! 474: fee_write(u_long ioaddr, /* i/o port of the card */ ! 475: u_short o, /* destination offset */ ! 476: u_short * b, /* data buffer */ ! 477: int n) /* number of registers */ ! 478: { ! 479: b += n; /* Position at the end of the area */ ! 480: ! 481: #ifdef EEPROM_IS_PROTECTED /* disabled */ ! 482: #ifdef DOESNT_SEEM_TO_WORK /* disabled */ ! 483: /* Ask to read the protected register */ ! 484: mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD); ! 485: ! 486: fee_wait(ioaddr, 10, 100); ! 487: ! 488: /* Read the protected register */ ! 489: printk("Protected 2 : %02X-%02X\n", ! 490: mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)), ! 491: mmc_in(ioaddr, mmroff(0, mmr_fee_data_l))); ! 492: #endif /* DOESNT_SEEM_TO_WORK */ ! 493: ! 494: /* Enable protected register */ ! 495: mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); ! 496: mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN); ! 497: ! 498: fee_wait(ioaddr, 10, 100); ! 499: ! 500: /* Unprotect area */ ! 501: mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n); ! 502: mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); ! 503: #ifdef DOESNT_SEEM_TO_WORK /* disabled */ ! 504: /* Or use : */ ! 505: mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR); ! 506: #endif /* DOESNT_SEEM_TO_WORK */ ! 507: ! 508: fee_wait(ioaddr, 10, 100); ! 509: #endif /* EEPROM_IS_PROTECTED */ ! 510: ! 511: /* Write enable */ ! 512: mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); ! 513: mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN); ! 514: ! 515: fee_wait(ioaddr, 10, 100); ! 516: ! 517: /* Write the EEPROM address */ ! 518: mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1); ! 519: ! 520: /* Loop on all buffer */ ! 521: while(n-- > 0) ! 522: { ! 523: /* Write the value */ ! 524: mmc_out(ioaddr, mmwoff(0, mmw_fee_data_h), (*--b) >> 8); ! 525: mmc_out(ioaddr, mmwoff(0, mmw_fee_data_l), *b & 0xFF); ! 526: ! 527: /* Write the write command */ ! 528: mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE); ! 529: ! 530: /* Wavelan doc says : wait at least 10 ms for EEBUSY = 0 */ ! 531: udelay(10000); ! 532: fee_wait(ioaddr, 10, 100); ! 533: } ! 534: ! 535: /* Write disable */ ! 536: mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS); ! 537: mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS); ! 538: ! 539: fee_wait(ioaddr, 10, 100); ! 540: ! 541: #ifdef EEPROM_IS_PROTECTED /* disabled */ ! 542: /* Reprotect EEPROM */ ! 543: mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x00); ! 544: mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); ! 545: ! 546: fee_wait(ioaddr, 10, 100); ! 547: #endif /* EEPROM_IS_PROTECTED */ ! 548: } ! 549: #endif /* WIRELESS_EXT */ ! 550: ! 551: /************************ I82586 SUBROUTINES *************************/ ! 552: /* ! 553: * Usefull subroutines to manage the Ethernet controler ! 554: */ ! 555: ! 556: /*------------------------------------------------------------------*/ ! 557: /* ! 558: * Read bytes from the on-board RAM. ! 559: * Why inlining this function make it fail ??? ! 560: */ ! 561: static /*inline*/ void ! 562: obram_read(u_long ioaddr, ! 563: u_short o, ! 564: u_char * b, ! 565: int n) ! 566: { ! 567: outw(o, PIOR1(ioaddr)); ! 568: insw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1); ! 569: } ! 570: ! 571: /*------------------------------------------------------------------*/ ! 572: /* ! 573: * Write bytes to the on-board RAM. ! 574: */ ! 575: static inline void ! 576: obram_write(u_long ioaddr, ! 577: u_short o, ! 578: u_char * b, ! 579: int n) ! 580: { ! 581: outw(o, PIOR1(ioaddr)); ! 582: outsw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1); ! 583: } ! 584: ! 585: /*------------------------------------------------------------------*/ ! 586: /* ! 587: * Acknowledge the reading of the status issued by the i82586 ! 588: */ ! 589: static void ! 590: wv_ack(device * dev) ! 591: { ! 592: net_local * lp = (net_local *)dev->priv; ! 593: u_long ioaddr = dev->base_addr; ! 594: u_short scb_cs; ! 595: int i; ! 596: ! 597: obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), ! 598: (unsigned char *) &scb_cs, sizeof(scb_cs)); ! 599: scb_cs &= SCB_ST_INT; ! 600: ! 601: if(scb_cs == 0) ! 602: return; ! 603: ! 604: obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), ! 605: (unsigned char *) &scb_cs, sizeof(scb_cs)); ! 606: ! 607: set_chan_attn(ioaddr, lp->hacr); ! 608: ! 609: for(i = 1000; i > 0; i--) ! 610: { ! 611: obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *)&scb_cs, sizeof(scb_cs)); ! 612: if(scb_cs == 0) ! 613: break; ! 614: ! 615: udelay(10); ! 616: } ! 617: udelay(100); ! 618: ! 619: #ifdef DEBUG_CONFIG_ERROR ! 620: if(i <= 0) ! 621: printk(KERN_INFO "%s: wv_ack(): board not accepting command.\n", ! 622: dev->name); ! 623: #endif ! 624: } ! 625: ! 626: /*------------------------------------------------------------------*/ ! 627: /* ! 628: * Set channel attention bit and busy wait until command has ! 629: * completed, then acknowledge the command completion. ! 630: */ ! 631: static inline int ! 632: wv_synchronous_cmd(device * dev, ! 633: const char * str) ! 634: { ! 635: net_local * lp = (net_local *)dev->priv; ! 636: u_long ioaddr = dev->base_addr; ! 637: u_short scb_cmd; ! 638: ach_t cb; ! 639: int i; ! 640: ! 641: scb_cmd = SCB_CMD_CUC & SCB_CMD_CUC_GO; ! 642: obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), ! 643: (unsigned char *) &scb_cmd, sizeof(scb_cmd)); ! 644: ! 645: set_chan_attn(ioaddr, lp->hacr); ! 646: ! 647: for (i = 1000; i > 0; i--) ! 648: { ! 649: obram_read(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb)); ! 650: if (cb.ac_status & AC_SFLD_C) ! 651: break; ! 652: ! 653: udelay(10); ! 654: } ! 655: udelay(100); ! 656: ! 657: if(i <= 0 || !(cb.ac_status & AC_SFLD_OK)) ! 658: { ! 659: #ifdef DEBUG_CONFIG_ERROR ! 660: printk(KERN_INFO "%s: %s failed; status = 0x%x\n", ! 661: dev->name, str, cb.ac_status); ! 662: #endif ! 663: #ifdef DEBUG_I82586_SHOW ! 664: wv_scb_show(ioaddr); ! 665: #endif ! 666: return -1; ! 667: } ! 668: ! 669: /* Ack the status */ ! 670: wv_ack(dev); ! 671: ! 672: return 0; ! 673: } ! 674: ! 675: /*------------------------------------------------------------------*/ ! 676: /* ! 677: * Configuration commands completion interrupt. ! 678: * Check if done, and if ok... ! 679: */ ! 680: static inline int ! 681: wv_config_complete(device * dev, ! 682: u_long ioaddr, ! 683: net_local * lp) ! 684: { ! 685: unsigned short mcs_addr; ! 686: unsigned short status; ! 687: int ret; ! 688: ! 689: #ifdef DEBUG_INTERRUPT_TRACE ! 690: printk(KERN_DEBUG "%s: ->wv_config_complete()\n", dev->name); ! 691: #endif ! 692: ! 693: mcs_addr = lp->tx_first_in_use + sizeof(ac_tx_t) + sizeof(ac_nop_t) ! 694: + sizeof(tbd_t) + sizeof(ac_cfg_t) + sizeof(ac_ias_t); ! 695: ! 696: /* Read the status of the last command (set mc list) */ ! 697: obram_read(ioaddr, acoff(mcs_addr, ac_status), (unsigned char *)&status, sizeof(status)); ! 698: ! 699: /* If not completed -> exit */ ! 700: if((status & AC_SFLD_C) == 0) ! 701: ret = 0; /* Not ready to be scrapped */ ! 702: else ! 703: { ! 704: #ifdef DEBUG_CONFIG_ERROR ! 705: unsigned short cfg_addr; ! 706: unsigned short ias_addr; ! 707: ! 708: /* Check mc_config command */ ! 709: if(status & AC_SFLD_OK != 0) ! 710: printk(KERN_INFO "wv_config_complete(): set_multicast_address failed; status = 0x%x\n", ! 711: dev->name, str, status); ! 712: ! 713: /* check ia-config command */ ! 714: ias_addr = mcs_addr - sizeof(ac_ias_t); ! 715: obram_read(ioaddr, acoff(ias_addr, ac_status), (unsigned char *)&status, sizeof(status)); ! 716: if(status & AC_SFLD_OK != 0) ! 717: printk(KERN_INFO "wv_config_complete(): set_MAC_address; status = 0x%x\n", ! 718: dev->name, str, status); ! 719: ! 720: /* Check config command */ ! 721: cfg_addr = ias_addr - sizeof(ac_cfg_t); ! 722: obram_read(ioaddr, acoff(cfg_addr, ac_status), (unsigned char *)&status, sizeof(status)); ! 723: if(status & AC_SFLD_OK != 0) ! 724: printk(KERN_INFO "wv_config_complete(): configure; status = 0x%x\n", ! 725: dev->name, str, status); ! 726: #endif /* DEBUG_CONFIG_ERROR */ ! 727: ! 728: ret = 1; /* Ready to be scrapped */ ! 729: } ! 730: ! 731: #ifdef DEBUG_INTERRUPT_TRACE ! 732: printk(KERN_DEBUG "%s: <-wv_config_complete() - %d\n", dev->name, ret); ! 733: #endif ! 734: return ret; ! 735: } ! 736: ! 737: /*------------------------------------------------------------------*/ ! 738: /* ! 739: * Command completion interrupt. ! 740: * Reclaim as many freed tx buffers as we can. ! 741: */ ! 742: static int ! 743: wv_complete(device * dev, ! 744: u_long ioaddr, ! 745: net_local * lp) ! 746: { ! 747: int nreaped = 0; ! 748: ! 749: #ifdef DEBUG_INTERRUPT_TRACE ! 750: printk(KERN_DEBUG "%s: ->wv_complete()\n", dev->name); ! 751: #endif ! 752: ! 753: /* Loop on all the transmit buffers */ ! 754: while(lp->tx_first_in_use != I82586NULL) ! 755: { ! 756: unsigned short tx_status; ! 757: ! 758: /* Read the first transmit buffer */ ! 759: obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), (unsigned char *)&tx_status, sizeof(tx_status)); ! 760: ! 761: /* Hack for reconfiguration... */ ! 762: if(tx_status == 0xFFFF) ! 763: if(!wv_config_complete(dev, ioaddr, lp)) ! 764: break; /* Not completed */ ! 765: ! 766: /* If not completed -> exit */ ! 767: if((tx_status & AC_SFLD_C) == 0) ! 768: break; ! 769: ! 770: /* We now remove this buffer */ ! 771: nreaped++; ! 772: --lp->tx_n_in_use; ! 773: ! 774: /* ! 775: if (lp->tx_n_in_use > 0) ! 776: printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]); ! 777: */ ! 778: ! 779: /* Was it the last one ? */ ! 780: if(lp->tx_n_in_use <= 0) ! 781: lp->tx_first_in_use = I82586NULL; ! 782: else ! 783: { ! 784: /* Next one in the chain */ ! 785: lp->tx_first_in_use += TXBLOCKZ; ! 786: if(lp->tx_first_in_use >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) ! 787: lp->tx_first_in_use -= NTXBLOCKS * TXBLOCKZ; ! 788: } ! 789: ! 790: /* Hack for reconfiguration... */ ! 791: if(tx_status == 0xFFFF) ! 792: continue; ! 793: ! 794: /* Now, check status of the finished command */ ! 795: if(tx_status & AC_SFLD_OK) ! 796: { ! 797: int ncollisions; ! 798: ! 799: lp->stats.tx_packets++; ! 800: ncollisions = tx_status & AC_SFLD_MAXCOL; ! 801: lp->stats.collisions += ncollisions; ! 802: #ifdef DEBUG_INTERRUPT_INFO ! 803: if(ncollisions > 0) ! 804: printk(KERN_DEBUG "%s: wv_complete(): tx completed after %d collisions.\n", ! 805: dev->name, ncollisions); ! 806: #endif ! 807: } ! 808: else ! 809: { ! 810: lp->stats.tx_errors++; ! 811: #ifndef IGNORE_NORMAL_XMIT_ERRS ! 812: if(tx_status & AC_SFLD_S10) ! 813: { ! 814: lp->stats.tx_carrier_errors++; ! 815: #ifdef DEBUG_INTERRUPT_ERROR ! 816: printk(KERN_INFO "%s: wv_complete(): tx error: no CS.\n", ! 817: dev->name); ! 818: #endif ! 819: } ! 820: #endif /* IGNORE_NORMAL_XMIT_ERRS */ ! 821: if(tx_status & AC_SFLD_S9) ! 822: { ! 823: lp->stats.tx_carrier_errors++; ! 824: #ifdef DEBUG_INTERRUPT_ERROR ! 825: printk(KERN_INFO "%s: wv_complete(): tx error: lost CTS.\n", ! 826: dev->name); ! 827: #endif ! 828: } ! 829: if(tx_status & AC_SFLD_S8) ! 830: { ! 831: lp->stats.tx_fifo_errors++; ! 832: #ifdef DEBUG_INTERRUPT_ERROR ! 833: printk(KERN_INFO "%s: wv_complete(): tx error: slow DMA.\n", ! 834: dev->name); ! 835: #endif ! 836: } ! 837: #ifndef IGNORE_NORMAL_XMIT_ERRS ! 838: if(tx_status & AC_SFLD_S6) ! 839: { ! 840: lp->stats.tx_heartbeat_errors++; ! 841: #ifdef DEBUG_INTERRUPT_ERROR ! 842: printk(KERN_INFO "%s: wv_complete(): tx error: heart beat.\n", ! 843: dev->name); ! 844: #endif ! 845: } ! 846: if(tx_status & AC_SFLD_S5) ! 847: { ! 848: lp->stats.tx_aborted_errors++; ! 849: #ifdef DEBUG_INTERRUPT_ERROR ! 850: printk(KERN_INFO "%s: wv_complete(): tx error: too many collisions.\n", ! 851: dev->name); ! 852: #endif ! 853: } ! 854: #endif /* IGNORE_NORMAL_XMIT_ERRS */ ! 855: } ! 856: ! 857: #ifdef DEBUG_INTERRUPT_INFO ! 858: printk(KERN_DEBUG "%s: wv_complete(): tx completed, tx_status 0x%04x\n", ! 859: dev->name, tx_status); ! 860: #endif ! 861: } ! 862: ! 863: #ifdef DEBUG_INTERRUPT_INFO ! 864: if(nreaped > 1) ! 865: printk(KERN_DEBUG "%s: wv_complete(): reaped %d\n", dev->name, nreaped); ! 866: #endif ! 867: ! 868: /* ! 869: * Inform upper layers. ! 870: */ ! 871: if(lp->tx_n_in_use < NTXBLOCKS - 1) ! 872: { ! 873: dev->tbusy = 0; ! 874: mark_bh(NET_BH); ! 875: } ! 876: ! 877: #ifdef DEBUG_INTERRUPT_TRACE ! 878: printk(KERN_DEBUG "%s: <-wv_complete()\n", dev->name); ! 879: #endif ! 880: return nreaped; ! 881: } ! 882: ! 883: /*------------------------------------------------------------------*/ ! 884: /* ! 885: * Reconfigure the i82586, or at least ask for it... ! 886: * Because wv_82586_config use a transmission buffer, we must do it ! 887: * when we are sure that there is one left, so we do it now ! 888: * or in wavelan_packet_xmit() (I can't find any better place, ! 889: * wavelan_interrupt is not an option...), so you may experience ! 890: * some delay sometime... ! 891: */ ! 892: static inline void ! 893: wv_82586_reconfig(device * dev) ! 894: { ! 895: net_local * lp = (net_local *)dev->priv; ! 896: ! 897: /* Check if we can do it now ! */ ! 898: if(!(dev->start) || (set_bit(0, (void *)&dev->tbusy) != 0)) ! 899: { ! 900: lp->reconfig_82586 = 1; ! 901: #ifdef DEBUG_CONFIG_INFO ! 902: printk(KERN_DEBUG "%s: wv_82586_reconfig(): delayed (busy = %ld, start = %d)\n", ! 903: dev->name, dev->tbusy, dev->start); ! 904: #endif ! 905: } ! 906: else ! 907: wv_82586_config(dev); ! 908: } ! 909: ! 910: /********************* DEBUG & INFO SUBROUTINES *********************/ ! 911: /* ! 912: * This routines are used in the code to show debug informations. ! 913: * Most of the time, it dump the content of hardware structures... ! 914: */ ! 915: ! 916: #ifdef DEBUG_PSA_SHOW ! 917: /*------------------------------------------------------------------*/ ! 918: /* ! 919: * Print the formatted contents of the Parameter Storage Area. ! 920: */ ! 921: static void ! 922: wv_psa_show(psa_t * p) ! 923: { ! 924: printk(KERN_DEBUG "##### WaveLAN psa contents: #####\n"); ! 925: printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", ! 926: p->psa_io_base_addr_1, ! 927: p->psa_io_base_addr_2, ! 928: p->psa_io_base_addr_3, ! 929: p->psa_io_base_addr_4); ! 930: printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n", ! 931: p->psa_rem_boot_addr_1, ! 932: p->psa_rem_boot_addr_2, ! 933: p->psa_rem_boot_addr_3); ! 934: printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); ! 935: printk("psa_int_req_no: %d\n", p->psa_int_req_no); ! 936: #ifdef DEBUG_SHOW_UNUSED ! 937: printk(KERN_DEBUG "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n", ! 938: p->psa_unused0[0], ! 939: p->psa_unused0[1], ! 940: p->psa_unused0[2], ! 941: p->psa_unused0[3], ! 942: p->psa_unused0[4], ! 943: p->psa_unused0[5], ! 944: p->psa_unused0[6]); ! 945: #endif /* DEBUG_SHOW_UNUSED */ ! 946: printk(KERN_DEBUG "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", ! 947: p->psa_univ_mac_addr[0], ! 948: p->psa_univ_mac_addr[1], ! 949: p->psa_univ_mac_addr[2], ! 950: p->psa_univ_mac_addr[3], ! 951: p->psa_univ_mac_addr[4], ! 952: p->psa_univ_mac_addr[5]); ! 953: printk(KERN_DEBUG "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", ! 954: p->psa_local_mac_addr[0], ! 955: p->psa_local_mac_addr[1], ! 956: p->psa_local_mac_addr[2], ! 957: p->psa_local_mac_addr[3], ! 958: p->psa_local_mac_addr[4], ! 959: p->psa_local_mac_addr[5]); ! 960: printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel); ! 961: printk("psa_comp_number: %d, ", p->psa_comp_number); ! 962: printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); ! 963: printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ", ! 964: p->psa_feature_select); ! 965: printk("psa_subband/decay_update_prm: %d\n", p->psa_subband); ! 966: printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr); ! 967: printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay); ! 968: printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], p->psa_nwid[1]); ! 969: printk("psa_nwid_select: %d\n", p->psa_nwid_select); ! 970: printk(KERN_DEBUG "psa_encryption_select: %d, ", p->psa_encryption_select); ! 971: printk("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", ! 972: p->psa_encryption_key[0], ! 973: p->psa_encryption_key[1], ! 974: p->psa_encryption_key[2], ! 975: p->psa_encryption_key[3], ! 976: p->psa_encryption_key[4], ! 977: p->psa_encryption_key[5], ! 978: p->psa_encryption_key[6], ! 979: p->psa_encryption_key[7]); ! 980: printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width); ! 981: printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ", ! 982: p->psa_call_code[0]); ! 983: printk("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", ! 984: p->psa_call_code[0], ! 985: p->psa_call_code[1], ! 986: p->psa_call_code[2], ! 987: p->psa_call_code[3], ! 988: p->psa_call_code[4], ! 989: p->psa_call_code[5], ! 990: p->psa_call_code[6], ! 991: p->psa_call_code[7]); ! 992: #ifdef DEBUG_SHOW_UNUSED ! 993: printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n", ! 994: p->psa_reserved[0], ! 995: p->psa_reserved[1], ! 996: p->psa_reserved[2], ! 997: p->psa_reserved[3]); ! 998: #endif /* DEBUG_SHOW_UNUSED */ ! 999: printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status); ! 1000: printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]); ! 1001: printk("psa_crc_status: 0x%02x\n", p->psa_crc_status); ! 1002: } /* wv_psa_show */ ! 1003: #endif /* DEBUG_PSA_SHOW */ ! 1004: ! 1005: #ifdef DEBUG_MMC_SHOW ! 1006: /*------------------------------------------------------------------*/ ! 1007: /* ! 1008: * Print the formatted status of the Modem Management Controller. ! 1009: * This function need to be completed... ! 1010: */ ! 1011: static void ! 1012: wv_mmc_show(device * dev) ! 1013: { ! 1014: u_long ioaddr = dev->base_addr; ! 1015: net_local * lp = (net_local *)dev->priv; ! 1016: mmr_t m; ! 1017: ! 1018: /* Basic check */ ! 1019: if(hasr_read(ioaddr) & HASR_NO_CLK) ! 1020: { ! 1021: printk(KERN_WARNING "%s: wv_mmc_show: modem not connected\n", ! 1022: dev->name); ! 1023: return; ! 1024: } ! 1025: ! 1026: /* Read the mmc */ ! 1027: mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); ! 1028: mmc_read(ioaddr, 0, (u_char *)&m, sizeof(m)); ! 1029: mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); ! 1030: ! 1031: #ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ ! 1032: /* Don't forget to update statistics */ ! 1033: lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; ! 1034: #endif /* WIRELESS_EXT */ ! 1035: ! 1036: printk(KERN_DEBUG "##### WaveLAN modem status registers: #####\n"); ! 1037: #ifdef DEBUG_SHOW_UNUSED ! 1038: printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", ! 1039: m.mmr_unused0[0], ! 1040: m.mmr_unused0[1], ! 1041: m.mmr_unused0[2], ! 1042: m.mmr_unused0[3], ! 1043: m.mmr_unused0[4], ! 1044: m.mmr_unused0[5], ! 1045: m.mmr_unused0[6], ! 1046: m.mmr_unused0[7]); ! 1047: #endif /* DEBUG_SHOW_UNUSED */ ! 1048: printk(KERN_DEBUG "Encryption algorythm: %02X - Status: %02X\n", ! 1049: m.mmr_des_avail, m.mmr_des_status); ! 1050: #ifdef DEBUG_SHOW_UNUSED ! 1051: printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n", ! 1052: m.mmr_unused1[0], ! 1053: m.mmr_unused1[1], ! 1054: m.mmr_unused1[2], ! 1055: m.mmr_unused1[3], ! 1056: m.mmr_unused1[4]); ! 1057: #endif /* DEBUG_SHOW_UNUSED */ ! 1058: printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n", ! 1059: m.mmr_dce_status, ! 1060: (m.mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? "energy detected,":"", ! 1061: (m.mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ? ! 1062: "loop test indicated," : "", ! 1063: (m.mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? "transmitter on," : "", ! 1064: (m.mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ? ! 1065: "jabber timer expired," : ""); ! 1066: printk(KERN_DEBUG "Dsp ID: %02X\n", ! 1067: m.mmr_dsp_id); ! 1068: #ifdef DEBUG_SHOW_UNUSED ! 1069: printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n", ! 1070: m.mmr_unused2[0], ! 1071: m.mmr_unused2[1]); ! 1072: #endif /* DEBUG_SHOW_UNUSED */ ! 1073: printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n", ! 1074: (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l, ! 1075: (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l); ! 1076: printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n", ! 1077: m.mmr_thr_pre_set & MMR_THR_PRE_SET, ! 1078: (m.mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : "below"); ! 1079: printk(KERN_DEBUG "signal_lvl: %d [%s], ", ! 1080: m.mmr_signal_lvl & MMR_SIGNAL_LVL, ! 1081: (m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : "no new msg"); ! 1082: printk("silence_lvl: %d [%s], ", m.mmr_silence_lvl & MMR_SILENCE_LVL, ! 1083: (m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : "no new update"); ! 1084: printk("sgnl_qual: 0x%x [%s]\n", ! 1085: m.mmr_sgnl_qual & MMR_SGNL_QUAL, ! 1086: (m.mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : "Antenna 0"); ! 1087: #ifdef DEBUG_SHOW_UNUSED ! 1088: printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l); ! 1089: #endif /* DEBUG_SHOW_UNUSED */ ! 1090: } /* wv_mmc_show */ ! 1091: #endif /* DEBUG_MMC_SHOW */ ! 1092: ! 1093: #ifdef DEBUG_I82586_SHOW ! 1094: /*------------------------------------------------------------------*/ ! 1095: /* ! 1096: * Print the last block of the i82586 memory ! 1097: */ ! 1098: static void ! 1099: wv_scb_show(u_long ioaddr) ! 1100: { ! 1101: scb_t scb; ! 1102: ! 1103: obram_read(ioaddr, OFFSET_SCB, (unsigned char *)&scb, sizeof(scb)); ! 1104: ! 1105: printk(KERN_DEBUG "##### WaveLAN system control block: #####\n"); ! 1106: ! 1107: printk(KERN_DEBUG "status: "); ! 1108: printk("stat 0x%x[%s%s%s%s] ", ! 1109: (scb.scb_status & (SCB_ST_CX | SCB_ST_FR | SCB_ST_CNA | SCB_ST_RNR)) >> 12, ! 1110: (scb.scb_status & SCB_ST_CX) ? "cmd completion interrupt," : "", ! 1111: (scb.scb_status & SCB_ST_FR) ? "frame received," : "", ! 1112: (scb.scb_status & SCB_ST_CNA) ? "cmd unit not active," : "", ! 1113: (scb.scb_status & SCB_ST_RNR) ? "rcv unit not ready," : ""); ! 1114: printk("cus 0x%x[%s%s%s] ", ! 1115: (scb.scb_status & SCB_ST_CUS) >> 8, ! 1116: ((scb.scb_status & SCB_ST_CUS) == SCB_ST_CUS_IDLE) ? "idle" : "", ! 1117: ((scb.scb_status & SCB_ST_CUS) == SCB_ST_CUS_SUSP) ? "suspended" : "", ! 1118: ((scb.scb_status & SCB_ST_CUS) == SCB_ST_CUS_ACTV) ? "active" : ""); ! 1119: printk("rus 0x%x[%s%s%s%s]\n", ! 1120: (scb.scb_status & SCB_ST_RUS) >> 4, ! 1121: ((scb.scb_status & SCB_ST_RUS) == SCB_ST_RUS_IDLE) ? "idle" : "", ! 1122: ((scb.scb_status & SCB_ST_RUS) == SCB_ST_RUS_SUSP) ? "suspended" : "", ! 1123: ((scb.scb_status & SCB_ST_RUS) == SCB_ST_RUS_NRES) ? "no resources" : "", ! 1124: ((scb.scb_status & SCB_ST_RUS) == SCB_ST_RUS_RDY) ? "ready" : ""); ! 1125: ! 1126: printk(KERN_DEBUG "command: "); ! 1127: printk("ack 0x%x[%s%s%s%s] ", ! 1128: (scb.scb_command & (SCB_CMD_ACK_CX | SCB_CMD_ACK_FR | SCB_CMD_ACK_CNA | SCB_CMD_ACK_RNR)) >> 12, ! 1129: (scb.scb_command & SCB_CMD_ACK_CX) ? "ack cmd completion," : "", ! 1130: (scb.scb_command & SCB_CMD_ACK_FR) ? "ack frame received," : "", ! 1131: (scb.scb_command & SCB_CMD_ACK_CNA) ? "ack CU not active," : "", ! 1132: (scb.scb_command & SCB_CMD_ACK_RNR) ? "ack RU not ready," : ""); ! 1133: printk("cuc 0x%x[%s%s%s%s%s] ", ! 1134: (scb.scb_command & SCB_CMD_CUC) >> 8, ! 1135: ((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_NOP) ? "nop" : "", ! 1136: ((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_GO) ? "start cbl_offset" : "", ! 1137: ((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_RES) ? "resume execution" : "", ! 1138: ((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_SUS) ? "suspend execution" : "", ! 1139: ((scb.scb_command & SCB_CMD_CUC) == SCB_CMD_CUC_ABT) ? "abort execution" : ""); ! 1140: printk("ruc 0x%x[%s%s%s%s%s]\n", ! 1141: (scb.scb_command & SCB_CMD_RUC) >> 4, ! 1142: ((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_NOP) ? "nop" : "", ! 1143: ((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_GO) ? "start rfa_offset" : "", ! 1144: ((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_RES) ? "resume reception" : "", ! 1145: ((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_SUS) ? "suspend reception" : "", ! 1146: ((scb.scb_command & SCB_CMD_RUC) == SCB_CMD_RUC_ABT) ? "abort reception" : ""); ! 1147: ! 1148: printk(KERN_DEBUG "cbl_offset 0x%x ", scb.scb_cbl_offset); ! 1149: printk("rfa_offset 0x%x\n", scb.scb_rfa_offset); ! 1150: ! 1151: printk(KERN_DEBUG "crcerrs %d ", scb.scb_crcerrs); ! 1152: printk("alnerrs %d ", scb.scb_alnerrs); ! 1153: printk("rscerrs %d ", scb.scb_rscerrs); ! 1154: printk("ovrnerrs %d\n", scb.scb_ovrnerrs); ! 1155: } ! 1156: ! 1157: /*------------------------------------------------------------------*/ ! 1158: /* ! 1159: * Print the formatted status of the i82586's receive unit. ! 1160: */ ! 1161: static void ! 1162: wv_ru_show(device * dev) ! 1163: { ! 1164: /* net_local *lp = (net_local *) dev->priv; */ ! 1165: ! 1166: printk(KERN_DEBUG "##### WaveLAN i82586 receiver unit status: #####\n"); ! 1167: printk(KERN_DEBUG "ru:"); ! 1168: /* ! 1169: * Not implemented yet... ! 1170: */ ! 1171: printk("\n"); ! 1172: } /* wv_ru_show */ ! 1173: ! 1174: /*------------------------------------------------------------------*/ ! 1175: /* ! 1176: * Display info about one control block of the i82586 memory ! 1177: */ ! 1178: static void ! 1179: wv_cu_show_one(device * dev, ! 1180: net_local * lp, ! 1181: int i, ! 1182: u_short p) ! 1183: { ! 1184: u_long ioaddr; ! 1185: ac_tx_t actx; ! 1186: ! 1187: ioaddr = dev->base_addr; ! 1188: ! 1189: printk("%d: 0x%x:", i, p); ! 1190: ! 1191: obram_read(ioaddr, p, (unsigned char *)&actx, sizeof(actx)); ! 1192: printk(" status=0x%x,", actx.tx_h.ac_status); ! 1193: printk(" command=0x%x,", actx.tx_h.ac_command); ! 1194: ! 1195: /* ! 1196: { ! 1197: tbd_t tbd; ! 1198: ! 1199: obram_read(ioaddr, actx.tx_tbd_offset, (unsigned char *)&tbd, sizeof(tbd)); ! 1200: printk(" tbd_status=0x%x,", tbd.tbd_status); ! 1201: } ! 1202: */ ! 1203: ! 1204: printk("|"); ! 1205: } ! 1206: ! 1207: /*------------------------------------------------------------------*/ ! 1208: /* ! 1209: * Print status of the command unit of the i82586 ! 1210: */ ! 1211: static void ! 1212: wv_cu_show(device * dev) ! 1213: { ! 1214: net_local * lp = (net_local *)dev->priv; ! 1215: unsigned int i; ! 1216: u_short p; ! 1217: ! 1218: printk(KERN_DEBUG "##### WaveLAN i82586 command unit status: #####\n"); ! 1219: ! 1220: printk(KERN_DEBUG); ! 1221: for(i = 0, p = lp->tx_first_in_use; i < NTXBLOCKS; i++) ! 1222: { ! 1223: wv_cu_show_one(dev, lp, i, p); ! 1224: ! 1225: p += TXBLOCKZ; ! 1226: if(p >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) ! 1227: p -= NTXBLOCKS * TXBLOCKZ; ! 1228: } ! 1229: printk("\n"); ! 1230: } ! 1231: #endif /* DEBUG_I82586_SHOW */ ! 1232: ! 1233: #ifdef DEBUG_DEVICE_SHOW ! 1234: /*------------------------------------------------------------------*/ ! 1235: /* ! 1236: * Print the formatted status of the WaveLAN PCMCIA device driver. ! 1237: */ ! 1238: static void ! 1239: wv_dev_show(device * dev) ! 1240: { ! 1241: printk(KERN_DEBUG "dev:"); ! 1242: printk(" start=%d,", dev->start); ! 1243: printk(" tbusy=%ld,", dev->tbusy); ! 1244: printk(" interrupt=%d,", dev->interrupt); ! 1245: printk(" trans_start=%ld,", dev->trans_start); ! 1246: printk(" flags=0x%x,", dev->flags); ! 1247: printk("\n"); ! 1248: } /* wv_dev_show */ ! 1249: ! 1250: /*------------------------------------------------------------------*/ ! 1251: /* ! 1252: * Print the formatted status of the WaveLAN PCMCIA device driver's ! 1253: * private information. ! 1254: */ ! 1255: static void ! 1256: wv_local_show(device * dev) ! 1257: { ! 1258: net_local *lp; ! 1259: ! 1260: lp = (net_local *)dev->priv; ! 1261: ! 1262: printk(KERN_DEBUG "local:"); ! 1263: printk(" tx_n_in_use=%d,", lp->tx_n_in_use); ! 1264: printk(" hacr=0x%x,", lp->hacr); ! 1265: printk(" rx_head=0x%x,", lp->rx_head); ! 1266: printk(" rx_last=0x%x,", lp->rx_last); ! 1267: printk(" tx_first_free=0x%x,", lp->tx_first_free); ! 1268: printk(" tx_first_in_use=0x%x,", lp->tx_first_in_use); ! 1269: printk("\n"); ! 1270: } /* wv_local_show */ ! 1271: #endif /* DEBUG_DEVICE_SHOW */ ! 1272: ! 1273: #if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) ! 1274: /*------------------------------------------------------------------*/ ! 1275: /* ! 1276: * Dump packet header (and content if necessary) on the screen ! 1277: */ ! 1278: static inline void ! 1279: wv_packet_info(u_char * p, /* Packet to dump */ ! 1280: int length, /* Length of the packet */ ! 1281: char * msg1, /* Name of the device */ ! 1282: char * msg2) /* Name of the function */ ! 1283: { ! 1284: #ifndef DEBUG_PACKET_DUMP ! 1285: printk(KERN_DEBUG "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n", ! 1286: msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length); ! 1287: printk(KERN_DEBUG "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n", ! 1288: msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13]); ! 1289: ! 1290: #else /* DEBUG_PACKET_DUMP */ ! 1291: int i; ! 1292: int maxi; ! 1293: ! 1294: printk(KERN_DEBUG "%s: %s(): len=%d, data=\"", msg1, msg2, length); ! 1295: ! 1296: if((maxi = length) > DEBUG_PACKET_DUMP) ! 1297: maxi = DEBUG_PACKET_DUMP; ! 1298: for(i = 0; i < maxi; i++) ! 1299: if(p[i] >= ' ' && p[i] <= '~') ! 1300: printk(" %c", p[i]); ! 1301: else ! 1302: printk("%02X", p[i]); ! 1303: if(maxi < length) ! 1304: printk(".."); ! 1305: printk("\"\n"); ! 1306: printk(KERN_DEBUG "\n"); ! 1307: #endif /* DEBUG_PACKET_DUMP */ ! 1308: } ! 1309: #endif /* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */ ! 1310: ! 1311: /*------------------------------------------------------------------*/ ! 1312: /* ! 1313: * This is the information which is displayed by the driver at startup ! 1314: * There is a lot of flag to configure it at your will... ! 1315: */ ! 1316: static inline void ! 1317: wv_init_info(device * dev) ! 1318: { ! 1319: short ioaddr = dev->base_addr; ! 1320: net_local * lp = (net_local *)dev->priv; ! 1321: psa_t psa; ! 1322: int i; ! 1323: ! 1324: /* Read the parameter storage area */ ! 1325: psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); ! 1326: ! 1327: #ifdef DEBUG_PSA_SHOW ! 1328: wv_psa_show(&psa); ! 1329: #endif ! 1330: #ifdef DEBUG_MMC_SHOW ! 1331: wv_mmc_show(dev); ! 1332: #endif ! 1333: #ifdef DEBUG_I82586_SHOW ! 1334: wv_cu_show(dev); ! 1335: #endif ! 1336: ! 1337: #ifdef DEBUG_BASIC_SHOW ! 1338: /* Now, let's go for the basic stuff */ ! 1339: printk(KERN_NOTICE "%s: WaveLAN at %#x,", dev->name, ioaddr); ! 1340: for(i = 0; i < WAVELAN_ADDR_SIZE; i++) ! 1341: printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]); ! 1342: printk(", IRQ %d", dev->irq); ! 1343: ! 1344: /* Print current network id */ ! 1345: if(psa.psa_nwid_select) ! 1346: printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], psa.psa_nwid[1]); ! 1347: else ! 1348: printk(", nwid off"); ! 1349: ! 1350: /* If 2.00 card */ ! 1351: if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & ! 1352: (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) ! 1353: { ! 1354: unsigned short freq; ! 1355: ! 1356: /* Ask the EEPROM to read the frequency from the first area */ ! 1357: fee_read(ioaddr, 0x00 /* 1st area - frequency... */, ! 1358: &freq, 1); ! 1359: ! 1360: /* Print frequency */ ! 1361: printk(", 2.00, %ld", (freq >> 6) + 2400L); ! 1362: ! 1363: /* Hack !!! */ ! 1364: if(freq & 0x20) ! 1365: printk(".5"); ! 1366: } ! 1367: else ! 1368: { ! 1369: printk(", PC"); ! 1370: switch(psa.psa_comp_number) ! 1371: { ! 1372: case PSA_COMP_PC_AT_915: ! 1373: case PSA_COMP_PC_AT_2400: ! 1374: printk("-AT"); ! 1375: break; ! 1376: case PSA_COMP_PC_MC_915: ! 1377: case PSA_COMP_PC_MC_2400: ! 1378: printk("-MC"); ! 1379: break; ! 1380: case PSA_COMP_PCMCIA_915: ! 1381: printk("MCIA"); ! 1382: break; ! 1383: default: ! 1384: printk("???"); ! 1385: } ! 1386: printk(", "); ! 1387: switch (psa.psa_subband) ! 1388: { ! 1389: case PSA_SUBBAND_915: ! 1390: printk("915"); ! 1391: break; ! 1392: case PSA_SUBBAND_2425: ! 1393: printk("2425"); ! 1394: break; ! 1395: case PSA_SUBBAND_2460: ! 1396: printk("2460"); ! 1397: break; ! 1398: case PSA_SUBBAND_2484: ! 1399: printk("2484"); ! 1400: break; ! 1401: case PSA_SUBBAND_2430_5: ! 1402: printk("2430.5"); ! 1403: break; ! 1404: default: ! 1405: printk("???"); ! 1406: } ! 1407: } ! 1408: ! 1409: printk(" MHz\n"); ! 1410: #endif /* DEBUG_BASIC_SHOW */ ! 1411: ! 1412: #ifdef DEBUG_VERSION_SHOW ! 1413: /* Print version information */ ! 1414: printk(KERN_NOTICE "%s", version); ! 1415: #endif ! 1416: } /* wv_init_info */ ! 1417: ! 1418: /********************* IOCTL, STATS & RECONFIG *********************/ ! 1419: /* ! 1420: * We found here routines that are called by Linux on differents ! 1421: * occasions after the configuration and not for transmitting data ! 1422: * These may be called when the user use ifconfig, /proc/net/dev ! 1423: * or wireless extensions ! 1424: */ ! 1425: ! 1426: /*------------------------------------------------------------------*/ ! 1427: /* ! 1428: * Get the current ethernet statistics. This may be called with the ! 1429: * card open or closed. ! 1430: * Used when the user read /proc/net/dev ! 1431: */ ! 1432: static en_stats * ! 1433: wavelan_get_stats(device * dev) ! 1434: { ! 1435: #ifdef DEBUG_IOCTL_TRACE ! 1436: printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name); ! 1437: #endif ! 1438: ! 1439: return(&((net_local *) dev->priv)->stats); ! 1440: } ! 1441: ! 1442: /*------------------------------------------------------------------*/ ! 1443: /* ! 1444: * Set or clear the multicast filter for this adaptor. ! 1445: * num_addrs == -1 Promiscuous mode, receive all packets ! 1446: * num_addrs == 0 Normal mode, clear multicast list ! 1447: * num_addrs > 0 Multicast mode, receive normal and MC packets, ! 1448: * and do best-effort filtering. ! 1449: */ ! 1450: static void ! 1451: wavelan_set_multicast_list(device * dev) ! 1452: { ! 1453: net_local * lp = (net_local *) dev->priv; ! 1454: ! 1455: #ifdef DEBUG_IOCTL_TRACE ! 1456: printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", dev->name); ! 1457: #endif ! 1458: ! 1459: #ifdef DEBUG_IOCTL_INFO ! 1460: printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n", ! 1461: dev->name, dev->flags, dev->mc_count); ! 1462: #endif ! 1463: ! 1464: /* If we ask for promiscuous mode, ! 1465: * or all multicast addresses (we don't have that !) ! 1466: * or too much multicast addresses for the hardware filter */ ! 1467: if((dev->flags & IFF_PROMISC) || ! 1468: (dev->flags & IFF_ALLMULTI) || ! 1469: (dev->mc_count > I82586_MAX_MULTICAST_ADDRESSES)) ! 1470: { ! 1471: /* ! 1472: * Enable promiscuous mode: receive all packets. ! 1473: */ ! 1474: if(!lp->promiscuous) ! 1475: { ! 1476: lp->promiscuous = 1; ! 1477: lp->mc_count = 0; ! 1478: ! 1479: wv_82586_reconfig(dev); ! 1480: ! 1481: /* Tell the kernel that we are doing a really bad job... */ ! 1482: dev->flags |= IFF_PROMISC; ! 1483: } ! 1484: } ! 1485: else ! 1486: /* If there is some multicast addresses to send */ ! 1487: if(dev->mc_list != (struct dev_mc_list *) NULL) ! 1488: { ! 1489: /* ! 1490: * Disable promiscuous mode, but receive all packets ! 1491: * in multicast list ! 1492: */ ! 1493: #ifdef MULTICAST_AVOID ! 1494: if(lp->promiscuous || ! 1495: (dev->mc_count != lp->mc_count)) ! 1496: #endif ! 1497: { ! 1498: lp->promiscuous = 0; ! 1499: lp->mc_count = dev->mc_count; ! 1500: ! 1501: wv_82586_reconfig(dev); ! 1502: } ! 1503: } ! 1504: else ! 1505: { ! 1506: /* ! 1507: * Switch to normal mode: disable promiscuous mode and ! 1508: * clear the multicast list. ! 1509: */ ! 1510: if(lp->promiscuous || lp->mc_count == 0) ! 1511: { ! 1512: lp->promiscuous = 0; ! 1513: lp->mc_count = 0; ! 1514: ! 1515: wv_82586_reconfig(dev); ! 1516: } ! 1517: } ! 1518: #ifdef DEBUG_IOCTL_TRACE ! 1519: printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", dev->name); ! 1520: #endif ! 1521: } ! 1522: ! 1523: /*------------------------------------------------------------------*/ ! 1524: /* ! 1525: * This function doesn't exist... ! 1526: */ ! 1527: static int ! 1528: wavelan_set_mac_address(device * dev, ! 1529: void * addr) ! 1530: { ! 1531: struct sockaddr * mac = addr; ! 1532: ! 1533: /* Copy the address */ ! 1534: memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE); ! 1535: ! 1536: /* Reconfig the beast */ ! 1537: wv_82586_reconfig(dev); ! 1538: ! 1539: return 0; ! 1540: } ! 1541: ! 1542: #ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ ! 1543: ! 1544: /*------------------------------------------------------------------*/ ! 1545: /* ! 1546: * Frequency setting (for hardware able of it) ! 1547: * It's a bit complicated and you don't really want to look into it... ! 1548: * (called in wavelan_ioctl) ! 1549: */ ! 1550: static inline int ! 1551: wv_set_frequency(u_long ioaddr, /* i/o port of the card */ ! 1552: iw_freq * frequency) ! 1553: { ! 1554: const int BAND_NUM = 10; /* Number of bands */ ! 1555: long freq = 0L; /* offset to 2.4 GHz in .5 MHz */ ! 1556: #ifdef DEBUG_IOCTL_INFO ! 1557: int i; ! 1558: #endif ! 1559: ! 1560: /* Setting by frequency */ ! 1561: /* Theoretically, you may set any frequency between ! 1562: * the two limits with a 0.5 MHz precision. In practice, ! 1563: * I don't want you to have trouble with local ! 1564: * regulations... */ ! 1565: if((frequency->e == 1) && ! 1566: (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8)) ! 1567: { ! 1568: freq = ((frequency->m / 10000) - 24000L) / 5; ! 1569: } ! 1570: ! 1571: /* Setting by channel (same as wfreqsel) */ ! 1572: /* Warning : each channel is 22MHz wide, so some of the channels ! 1573: * will interfere... */ ! 1574: if((frequency->e == 0) && ! 1575: (frequency->m >= 0) && (frequency->m < BAND_NUM)) ! 1576: { ! 1577: /* frequency in 1/4 of MHz (as read in the offset register) */ ! 1578: short bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8, 0xD0, 0xF0, 0xF8, 0x150 }; ! 1579: ! 1580: /* Get frequency offset */ ! 1581: freq = bands[frequency->m] >> 1; ! 1582: } ! 1583: ! 1584: /* Verify if the frequency is allowed */ ! 1585: if(freq != 0L) ! 1586: { ! 1587: u_short table[10]; /* Authorized frequency table */ ! 1588: ! 1589: /* Read the frequency table */ ! 1590: fee_read(ioaddr, 0x71 /* frequency table */, ! 1591: table, 10); ! 1592: ! 1593: #ifdef DEBUG_IOCTL_INFO ! 1594: printk(KERN_DEBUG "Frequency table :"); ! 1595: for(i = 0; i < 10; i++) ! 1596: { ! 1597: printk(" %04X", ! 1598: table[i]); ! 1599: } ! 1600: printk("\n"); ! 1601: #endif ! 1602: ! 1603: /* Look in the table if the frequency is allowed */ ! 1604: if(!(table[9 - ((freq - 24) / 16)] & ! 1605: (1 << ((freq - 24) % 16)))) ! 1606: return -EINVAL; /* not allowed */ ! 1607: } ! 1608: else ! 1609: return -EINVAL; ! 1610: ! 1611: /* If we get a usable frequency */ ! 1612: if(freq != 0L) ! 1613: { ! 1614: unsigned short area[16]; ! 1615: unsigned short dac[2]; ! 1616: unsigned short area_verify[16]; ! 1617: unsigned short dac_verify[2]; ! 1618: /* Corresponding gain (in the power adjust value table) ! 1619: * see AT&T WaveLAN Data Manual, REF 407-024689/E, page 3-8 ! 1620: * & WCIN062D.DOC, page 6.2.9 */ ! 1621: unsigned short power_limit[] = { 40, 80, 120, 160, 0 }; ! 1622: int power_band = 0; /* Selected band */ ! 1623: unsigned short power_adjust; /* Correct value */ ! 1624: ! 1625: /* Search for the gain */ ! 1626: power_band = 0; ! 1627: while((freq > power_limit[power_band]) && ! 1628: (power_limit[++power_band] != 0)) ! 1629: ; ! 1630: ! 1631: /* Read the first area */ ! 1632: fee_read(ioaddr, 0x00, ! 1633: area, 16); ! 1634: ! 1635: /* Read the DAC */ ! 1636: fee_read(ioaddr, 0x60, ! 1637: dac, 2); ! 1638: ! 1639: /* Read the new power adjust value */ ! 1640: fee_read(ioaddr, 0x6B - (power_band >> 1), ! 1641: &power_adjust, 1); ! 1642: if(power_band & 0x1) ! 1643: power_adjust >>= 8; ! 1644: else ! 1645: power_adjust &= 0xFF; ! 1646: ! 1647: #ifdef DEBUG_IOCTL_INFO ! 1648: printk(KERN_DEBUG "WaveLAN EEPROM Area 1:"); ! 1649: for(i = 0; i < 16; i++) ! 1650: { ! 1651: printk(" %04X", ! 1652: area[i]); ! 1653: } ! 1654: printk("\n"); ! 1655: ! 1656: printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n", ! 1657: dac[0], dac[1]); ! 1658: #endif ! 1659: ! 1660: /* Frequency offset (for info only) */ ! 1661: area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F); ! 1662: ! 1663: /* Receiver Principle main divider coefficient */ ! 1664: area[3] = (freq >> 1) + 2400L - 352L; ! 1665: area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); ! 1666: ! 1667: /* Transmitter Main divider coefficient */ ! 1668: area[13] = (freq >> 1) + 2400L; ! 1669: area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF); ! 1670: ! 1671: /* Others part of the area are flags, bit streams or unused... */ ! 1672: ! 1673: /* Set the value in the DAC. */ ! 1674: dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80); ! 1675: dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF); ! 1676: ! 1677: /* Write the first area. */ ! 1678: fee_write(ioaddr, 0x00, ! 1679: area, 16); ! 1680: ! 1681: /* Write the DAC. */ ! 1682: fee_write(ioaddr, 0x60, ! 1683: dac, 2); ! 1684: ! 1685: /* We now should verify here that the EEPROM writing was OK. */ ! 1686: ! 1687: /* Reread the first area. */ ! 1688: fee_read(ioaddr, 0x00, ! 1689: area_verify, 16); ! 1690: ! 1691: /* ReRead the DAC */ ! 1692: fee_read(ioaddr, 0x60, ! 1693: dac_verify, 2); ! 1694: ! 1695: /* Compare */ ! 1696: if(memcmp(area, area_verify, 16 * 2) || ! 1697: memcmp(dac, dac_verify, 2 * 2)) ! 1698: { ! 1699: #ifdef DEBUG_IOCTL_ERROR ! 1700: printk(KERN_INFO "WaveLAN: wv_set_frequency: unable to write new frequency to EEPROM(?).\n"); ! 1701: #endif ! 1702: return -EOPNOTSUPP; ! 1703: } ! 1704: ! 1705: /* We must download the frequency parameters to the ! 1706: * synthesizers (from the EEPROM - area 1) ! 1707: * Note: as the EEPROM is automatically decremented, we set the end ! 1708: * if the area... */ ! 1709: mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x0F); ! 1710: mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), ! 1711: MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); ! 1712: ! 1713: /* Wait until the download is finished */ ! 1714: fee_wait(ioaddr, 100, 100); ! 1715: ! 1716: /* We must now download the power adjust value (gain) to ! 1717: * the synthesizers (from the EEPROM - area 7 - DAC) */ ! 1718: mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x61); ! 1719: mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), ! 1720: MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD); ! 1721: ! 1722: /* Wait until the download is finished */ ! 1723: fee_wait(ioaddr, 100, 100); ! 1724: ! 1725: #ifdef DEBUG_IOCTL_INFO ! 1726: /* Verification of what we have done... */ ! 1727: ! 1728: printk(KERN_DEBUG "WaveLAN EEPROM Area 1:"); ! 1729: for(i = 0; i < 16; i++) ! 1730: { ! 1731: printk(" %04X", ! 1732: area_verify[i]); ! 1733: } ! 1734: printk("\n"); ! 1735: ! 1736: printk(KERN_DEBUG "WaveLAN EEPROM DAC: %04X %04X\n", ! 1737: dac_verify[0], dac_verify[1]); ! 1738: #endif ! 1739: ! 1740: return 0; ! 1741: } ! 1742: else ! 1743: return -EINVAL; /* Bah, never get there... */ ! 1744: } ! 1745: ! 1746: /*------------------------------------------------------------------*/ ! 1747: /* ! 1748: * Give the list of available frequencies ! 1749: */ ! 1750: static inline int ! 1751: wv_frequency_list(u_long ioaddr, /* i/o port of the card */ ! 1752: iw_freq * list, /* List of frequency to fill */ ! 1753: int max) /* Maximum number of frequencies */ ! 1754: { ! 1755: u_short table[10]; /* Authorized frequency table */ ! 1756: long freq = 0L; /* offset to 2.4 GHz in .5 MHz + 12 MHz */ ! 1757: int i; /* index in the table */ ! 1758: ! 1759: /* Read the frequency table */ ! 1760: fee_read(ioaddr, 0x71 /* frequency table */, ! 1761: table, 10); ! 1762: ! 1763: /* Look all frequencies */ ! 1764: i = 0; ! 1765: for(freq = 0; freq < 150; freq++) ! 1766: /* Look in the table if the frequency is allowed */ ! 1767: if(table[9 - (freq / 16)] & (1 << (freq % 16))) ! 1768: { ! 1769: /* put in the list */ ! 1770: list[i].m = (((freq + 24) * 5) + 24000L) * 10000; ! 1771: list[i++].e = 1; ! 1772: ! 1773: /* Check number */ ! 1774: if(i >= max) ! 1775: return(i); ! 1776: } ! 1777: ! 1778: return(i); ! 1779: } ! 1780: ! 1781: #ifdef WIRELESS_SPY ! 1782: /*------------------------------------------------------------------*/ ! 1783: /* ! 1784: * Gather wireless spy statistics : for each packet, compare the source ! 1785: * address with out list, and if match, get the stats... ! 1786: * Sorry, but this function really need wireless extensions... ! 1787: */ ! 1788: static inline void ! 1789: wl_spy_gather(device * dev, ! 1790: u_char * mac, /* MAC address */ ! 1791: u_char * stats) /* Statistics to gather */ ! 1792: { ! 1793: net_local * lp = (net_local *) dev->priv; ! 1794: int i; ! 1795: ! 1796: /* Look all addresses */ ! 1797: for(i = 0; i < lp->spy_number; i++) ! 1798: /* If match */ ! 1799: if(!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE)) ! 1800: { ! 1801: /* Update statistics */ ! 1802: lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL; ! 1803: lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL; ! 1804: lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL; ! 1805: lp->spy_stat[i].updated = 0x7; ! 1806: } ! 1807: } ! 1808: #endif /* WIRELESS_SPY */ ! 1809: ! 1810: #ifdef HISTOGRAM ! 1811: /*------------------------------------------------------------------*/ ! 1812: /* ! 1813: * This function calculates an histogram on the signal level. ! 1814: * As the noise is quite constant, it's like doing it on the SNR. ! 1815: * We have defined a set of interval (lp->his_range), and each time ! 1816: * the level goes in that interval, we increment the count (lp->his_sum). ! 1817: * With this histogram you may detect if one WaveLAN is really weak, ! 1818: * or you may also calculate the mean and standard deviation of the level. ! 1819: */ ! 1820: static inline void ! 1821: wl_his_gather(device * dev, ! 1822: u_char * stats) /* Statistics to gather */ ! 1823: { ! 1824: net_local * lp = (net_local *) dev->priv; ! 1825: u_char level = stats[0] & MMR_SIGNAL_LVL; ! 1826: int i; ! 1827: ! 1828: /* Find the correct interval */ ! 1829: i = 0; ! 1830: while((i < (lp->his_number - 1)) && (level >= lp->his_range[i++])) ! 1831: ; ! 1832: ! 1833: /* Increment interval counter */ ! 1834: (lp->his_sum[i])++; ! 1835: } ! 1836: #endif /* HISTOGRAM */ ! 1837: ! 1838: /*------------------------------------------------------------------*/ ! 1839: /* ! 1840: * Perform ioctl : config & info stuff ! 1841: * This is here that are treated the wireless extensions (iwconfig) ! 1842: */ ! 1843: static int ! 1844: wavelan_ioctl(struct device * dev, /* device on which the ioctl is applied */ ! 1845: struct ifreq * rq, /* data passed */ ! 1846: int cmd) /* ioctl number */ ! 1847: { ! 1848: u_long ioaddr = dev->base_addr; ! 1849: net_local * lp = (net_local *)dev->priv; /* lp is not unused */ ! 1850: struct iwreq * wrq = (struct iwreq *) rq; ! 1851: psa_t psa; ! 1852: mm_t m; ! 1853: unsigned long x; ! 1854: int ret = 0; ! 1855: ! 1856: #ifdef DEBUG_IOCTL_TRACE ! 1857: printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd); ! 1858: #endif ! 1859: ! 1860: /* Disable interrupts & save flags */ ! 1861: x = wv_splhi(); ! 1862: ! 1863: /* Look what is the request */ ! 1864: switch(cmd) ! 1865: { ! 1866: /* --------------- WIRELESS EXTENSIONS --------------- */ ! 1867: ! 1868: case SIOCGIWNAME: ! 1869: strcpy(wrq->u.name, "Wavelan"); ! 1870: break; ! 1871: ! 1872: case SIOCSIWNWID: ! 1873: /* Set NWID in WaveLAN */ ! 1874: if(wrq->u.nwid.on) ! 1875: { ! 1876: /* Set NWID in psa */ ! 1877: psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8; ! 1878: psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF; ! 1879: psa.psa_nwid_select = 0x01; ! 1880: psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa, ! 1881: (unsigned char *)psa.psa_nwid, 3); ! 1882: ! 1883: /* Set NWID in mmc */ ! 1884: m.w.mmw_netw_id_l = wrq->u.nwid.nwid & 0xFF; ! 1885: m.w.mmw_netw_id_h = (wrq->u.nwid.nwid & 0xFF00) >> 8; ! 1886: mmc_write(ioaddr, (char *)&m.w.mmw_netw_id_l - (char *)&m, ! 1887: (unsigned char *)&m.w.mmw_netw_id_l, 2); ! 1888: mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), 0x00); ! 1889: } ! 1890: else ! 1891: { ! 1892: /* Disable nwid in the psa */ ! 1893: psa.psa_nwid_select = 0x00; ! 1894: psa_write(ioaddr, lp->hacr, ! 1895: (char *)&psa.psa_nwid_select - (char *)&psa, ! 1896: (unsigned char *)&psa.psa_nwid_select, 1); ! 1897: ! 1898: /* Disable nwid in the mmc (no filtering) */ ! 1899: mmc_out(ioaddr, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID); ! 1900: } ! 1901: break; ! 1902: ! 1903: case SIOCGIWNWID: ! 1904: /* Read the NWID */ ! 1905: psa_read(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa, ! 1906: (unsigned char *)psa.psa_nwid, 3); ! 1907: wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; ! 1908: wrq->u.nwid.on = psa.psa_nwid_select; ! 1909: break; ! 1910: ! 1911: case SIOCSIWFREQ: ! 1912: /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */ ! 1913: if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & ! 1914: (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) ! 1915: ret = wv_set_frequency(ioaddr, &(wrq->u.freq)); ! 1916: else ! 1917: ret = -EOPNOTSUPP; ! 1918: break; ! 1919: ! 1920: case SIOCGIWFREQ: ! 1921: /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) ! 1922: * (does it work for everybody ??? - especially old cards...) */ ! 1923: if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & ! 1924: (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) ! 1925: { ! 1926: unsigned short freq; ! 1927: ! 1928: /* Ask the EEPROM to read the frequency from the first area */ ! 1929: fee_read(ioaddr, 0x00 /* 1st area - frequency... */, ! 1930: &freq, 1); ! 1931: wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000; ! 1932: wrq->u.freq.e = 1; ! 1933: } ! 1934: else ! 1935: { ! 1936: int bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 }; ! 1937: ! 1938: psa_read(ioaddr, lp->hacr, (char *)&psa.psa_subband - (char *)&psa, ! 1939: (unsigned char *)&psa.psa_subband, 1); ! 1940: ! 1941: if(psa.psa_subband <= 4) ! 1942: { ! 1943: wrq->u.freq.m = bands[psa.psa_subband]; ! 1944: wrq->u.freq.e = (psa.psa_subband != 0); ! 1945: } ! 1946: else ! 1947: ret = -EOPNOTSUPP; ! 1948: } ! 1949: break; ! 1950: ! 1951: case SIOCSIWSENS: ! 1952: /* Set the level threshold */ ! 1953: if(!suser()) ! 1954: return -EPERM; ! 1955: psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F; ! 1956: psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa, ! 1957: (unsigned char *) &psa.psa_thr_pre_set, 1); ! 1958: mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set); ! 1959: break; ! 1960: ! 1961: case SIOCGIWSENS: ! 1962: /* Read the level threshold */ ! 1963: psa_read(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa, ! 1964: (unsigned char *) &psa.psa_thr_pre_set, 1); ! 1965: wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F; ! 1966: break; ! 1967: ! 1968: case SIOCSIWENCODE: ! 1969: /* Set encryption key */ ! 1970: if(!mmc_encr(ioaddr)) ! 1971: { ! 1972: ret = -EOPNOTSUPP; ! 1973: break; ! 1974: } ! 1975: ! 1976: if(wrq->u.encoding.method) ! 1977: { /* enable encryption */ ! 1978: int i; ! 1979: long long key = wrq->u.encoding.code; ! 1980: ! 1981: for(i = 7; i >= 0; i--) ! 1982: { ! 1983: psa.psa_encryption_key[i] = key & 0xFF; ! 1984: key >>= 8; ! 1985: } ! 1986: psa.psa_encryption_select = 1; ! 1987: psa_write(ioaddr, lp->hacr, ! 1988: (char *) &psa.psa_encryption_select - (char *) &psa, ! 1989: (unsigned char *) &psa.psa_encryption_select, 8+1); ! 1990: ! 1991: mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), ! 1992: MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); ! 1993: mmc_write(ioaddr, mmwoff(0, mmw_encr_key), ! 1994: (unsigned char *) &psa.psa_encryption_key, 8); ! 1995: } ! 1996: else ! 1997: { /* disable encryption */ ! 1998: psa.psa_encryption_select = 0; ! 1999: psa_write(ioaddr, lp->hacr, ! 2000: (char *) &psa.psa_encryption_select - (char *) &psa, ! 2001: (unsigned char *) &psa.psa_encryption_select, 1); ! 2002: ! 2003: mmc_out(ioaddr, mmwoff(0, mmw_encr_enable), 0); ! 2004: } ! 2005: break; ! 2006: ! 2007: case SIOCGIWENCODE: ! 2008: /* Read the encryption key */ ! 2009: if(!mmc_encr(ioaddr)) ! 2010: { ! 2011: ret = -EOPNOTSUPP; ! 2012: break; ! 2013: } ! 2014: ! 2015: /* only super-user can see encryption key */ ! 2016: if(!suser()) ! 2017: { ! 2018: ret = -EPERM; ! 2019: break; ! 2020: } ! 2021: else ! 2022: { ! 2023: int i; ! 2024: long long key = 0; ! 2025: ! 2026: psa_read(ioaddr, lp->hacr, ! 2027: (char *) &psa.psa_encryption_select - (char *) &psa, ! 2028: (unsigned char *) &psa.psa_encryption_select, 1+8); ! 2029: for(i = 0; i < 8; i++) ! 2030: { ! 2031: key <<= 8; ! 2032: key += psa.psa_encryption_key[i]; ! 2033: } ! 2034: wrq->u.encoding.code = key; ! 2035: ! 2036: /* encryption is enabled */ ! 2037: if(psa.psa_encryption_select) ! 2038: wrq->u.encoding.method = mmc_encr(ioaddr); ! 2039: else ! 2040: wrq->u.encoding.method = 0; ! 2041: } ! 2042: break; ! 2043: ! 2044: case SIOCGIWRANGE: ! 2045: /* basic checking */ ! 2046: if(wrq->u.data.pointer != (caddr_t) 0) ! 2047: { ! 2048: struct iw_range range; ! 2049: ! 2050: /* Verify the user buffer */ ! 2051: ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer, ! 2052: sizeof(struct iw_range)); ! 2053: if(ret) ! 2054: break; ! 2055: ! 2056: /* Set the length (useless : its constant...) */ ! 2057: wrq->u.data.length = sizeof(struct iw_range); ! 2058: ! 2059: /* Set information in the range struct */ ! 2060: range.throughput = 1.6 * 1024 * 1024; /* don't argue on this ! */ ! 2061: range.min_nwid = 0x0000; ! 2062: range.max_nwid = 0xFFFF; ! 2063: ! 2064: /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ ! 2065: if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & ! 2066: (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) ! 2067: { ! 2068: range.num_channels = 10; ! 2069: range.num_frequency = wv_frequency_list(ioaddr, range.freq, ! 2070: IW_MAX_FREQUENCIES); ! 2071: } ! 2072: else ! 2073: range.num_channels = range.num_frequency = 0; ! 2074: ! 2075: range.sensitivity = 0x3F; ! 2076: range.max_qual.qual = MMR_SGNL_QUAL; ! 2077: range.max_qual.level = MMR_SIGNAL_LVL; ! 2078: range.max_qual.noise = MMR_SILENCE_LVL; ! 2079: ! 2080: /* Copy structure to the user buffer */ ! 2081: copy_to_user(wrq->u.data.pointer, &range, ! 2082: sizeof(struct iw_range)); ! 2083: } ! 2084: break; ! 2085: ! 2086: case SIOCGIWPRIV: ! 2087: /* Basic checking... */ ! 2088: if(wrq->u.data.pointer != (caddr_t) 0) ! 2089: { ! 2090: struct iw_priv_args priv[] = ! 2091: { /* cmd, set_args, get_args, name */ ! 2092: { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, ! 2093: { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, ! 2094: ! 2095: { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, ! 2096: { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, ! 2097: }; ! 2098: ! 2099: /* Verify the user buffer */ ! 2100: ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer, ! 2101: sizeof(priv)); ! 2102: if(ret) ! 2103: break; ! 2104: ! 2105: /* Set the number of ioctl available */ ! 2106: wrq->u.data.length = 4; ! 2107: ! 2108: /* Copy structure to the user buffer */ ! 2109: copy_to_user(wrq->u.data.pointer, (u_char *) priv, ! 2110: sizeof(priv)); ! 2111: } ! 2112: break; ! 2113: ! 2114: #ifdef WIRELESS_SPY ! 2115: case SIOCSIWSPY: ! 2116: /* Set the spy list */ ! 2117: ! 2118: /* Check the number of addresses */ ! 2119: if(wrq->u.data.length > IW_MAX_SPY) ! 2120: { ! 2121: ret = -E2BIG; ! 2122: break; ! 2123: } ! 2124: lp->spy_number = wrq->u.data.length; ! 2125: ! 2126: /* If there is some addresses to copy */ ! 2127: if(lp->spy_number > 0) ! 2128: { ! 2129: struct sockaddr address[IW_MAX_SPY]; ! 2130: int i; ! 2131: ! 2132: /* Verify where the user has set his addresses */ ! 2133: ret = verify_area(VERIFY_READ, wrq->u.data.pointer, ! 2134: sizeof(struct sockaddr) * lp->spy_number); ! 2135: if(ret) ! 2136: break; ! 2137: /* Copy addresses to the driver */ ! 2138: copy_from_user(address, wrq->u.data.pointer, ! 2139: sizeof(struct sockaddr) * lp->spy_number); ! 2140: ! 2141: /* Copy addresses to the lp structure */ ! 2142: for(i = 0; i < lp->spy_number; i++) ! 2143: { ! 2144: memcpy(lp->spy_address[i], address[i].sa_data, ! 2145: WAVELAN_ADDR_SIZE); ! 2146: } ! 2147: ! 2148: /* Reset structure... */ ! 2149: memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY); ! 2150: ! 2151: #ifdef DEBUG_IOCTL_INFO ! 2152: printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n"); ! 2153: for(i = 0; i < wrq->u.data.length; i++) ! 2154: printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X \n", ! 2155: lp->spy_address[i][0], ! 2156: lp->spy_address[i][1], ! 2157: lp->spy_address[i][2], ! 2158: lp->spy_address[i][3], ! 2159: lp->spy_address[i][4], ! 2160: lp->spy_address[i][5]); ! 2161: #endif /* DEBUG_IOCTL_INFO */ ! 2162: } ! 2163: ! 2164: break; ! 2165: ! 2166: case SIOCGIWSPY: ! 2167: /* Get the spy list and spy stats */ ! 2168: ! 2169: /* Set the number of addresses */ ! 2170: wrq->u.data.length = lp->spy_number; ! 2171: ! 2172: /* If the user want to have the addresses back... */ ! 2173: if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) ! 2174: { ! 2175: struct sockaddr address[IW_MAX_SPY]; ! 2176: int i; ! 2177: ! 2178: /* Verify the user buffer */ ! 2179: ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer, ! 2180: (sizeof(iw_qual) + sizeof(struct sockaddr)) ! 2181: * IW_MAX_SPY); ! 2182: if(ret) ! 2183: break; ! 2184: ! 2185: /* Copy addresses from the lp structure */ ! 2186: for(i = 0; i < lp->spy_number; i++) ! 2187: { ! 2188: memcpy(address[i].sa_data, lp->spy_address[i], ! 2189: WAVELAN_ADDR_SIZE); ! 2190: address[i].sa_family = AF_UNIX; ! 2191: } ! 2192: ! 2193: /* Copy addresses to the user buffer */ ! 2194: copy_to_user(wrq->u.data.pointer, address, ! 2195: sizeof(struct sockaddr) * lp->spy_number); ! 2196: ! 2197: /* Copy stats to the user buffer (just after) */ ! 2198: copy_to_user(wrq->u.data.pointer + ! 2199: (sizeof(struct sockaddr) * lp->spy_number), ! 2200: lp->spy_stat, sizeof(iw_qual) * lp->spy_number); ! 2201: ! 2202: /* Reset updated flags */ ! 2203: for(i = 0; i < lp->spy_number; i++) ! 2204: lp->spy_stat[i].updated = 0x0; ! 2205: } /* if(pointer != NULL) */ ! 2206: ! 2207: break; ! 2208: #endif /* WIRELESS_SPY */ ! 2209: ! 2210: /* ------------------ PRIVATE IOCTL ------------------ */ ! 2211: ! 2212: case SIOCSIPQTHR: ! 2213: if(!suser()) ! 2214: return -EPERM; ! 2215: psa.psa_quality_thr = *(wrq->u.name) & 0x0F; ! 2216: psa_write(ioaddr, lp->hacr, (char *)&psa.psa_quality_thr - (char *)&psa, ! 2217: (unsigned char *)&psa.psa_quality_thr, 1); ! 2218: mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr); ! 2219: break; ! 2220: ! 2221: case SIOCGIPQTHR: ! 2222: psa_read(ioaddr, lp->hacr, (char *)&psa.psa_quality_thr - (char *)&psa, ! 2223: (unsigned char *)&psa.psa_quality_thr, 1); ! 2224: *(wrq->u.name) = psa.psa_quality_thr & 0x0F; ! 2225: break; ! 2226: ! 2227: #ifdef HISTOGRAM ! 2228: case SIOCSIPHISTO: ! 2229: /* Verif if the user is root */ ! 2230: if(!suser()) ! 2231: return -EPERM; ! 2232: ! 2233: /* Check the number of intervals */ ! 2234: if(wrq->u.data.length > 16) ! 2235: { ! 2236: ret = -E2BIG; ! 2237: break; ! 2238: } ! 2239: lp->his_number = wrq->u.data.length; ! 2240: ! 2241: /* If there is some addresses to copy */ ! 2242: if(lp->his_number > 0) ! 2243: { ! 2244: /* Verify where the user has set his addresses */ ! 2245: ret = verify_area(VERIFY_READ, wrq->u.data.pointer, ! 2246: sizeof(char) * lp->his_number); ! 2247: if(ret) ! 2248: break; ! 2249: /* Copy interval ranges to the driver */ ! 2250: copy_from_user(lp->his_range, wrq->u.data.pointer, ! 2251: sizeof(char) * lp->his_number); ! 2252: ! 2253: /* Reset structure... */ ! 2254: memset(lp->his_sum, 0x00, sizeof(long) * 16); ! 2255: } ! 2256: break; ! 2257: ! 2258: case SIOCGIPHISTO: ! 2259: /* Set the number of intervals */ ! 2260: wrq->u.data.length = lp->his_number; ! 2261: ! 2262: /* Give back the distribution statistics */ ! 2263: if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0)) ! 2264: { ! 2265: /* Verify the user buffer */ ! 2266: ret = verify_area(VERIFY_WRITE, wrq->u.data.pointer, ! 2267: sizeof(long) * 16); ! 2268: if(ret) ! 2269: break; ! 2270: ! 2271: /* Copy data to the user buffer */ ! 2272: copy_to_user(wrq->u.data.pointer, lp->his_sum, ! 2273: sizeof(long) * lp->his_number); ! 2274: } /* if(pointer != NULL) */ ! 2275: break; ! 2276: #endif /* HISTOGRAM */ ! 2277: ! 2278: /* ------------------- OTHER IOCTL ------------------- */ ! 2279: ! 2280: default: ! 2281: ret = -EOPNOTSUPP; ! 2282: } ! 2283: ! 2284: /* Enable interrupts, restore flags */ ! 2285: wv_splx(x); ! 2286: ! 2287: #ifdef DEBUG_IOCTL_TRACE ! 2288: printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); ! 2289: #endif ! 2290: return ret; ! 2291: } ! 2292: ! 2293: /*------------------------------------------------------------------*/ ! 2294: /* ! 2295: * Get wireless statistics ! 2296: * Called by /proc/net/wireless ! 2297: */ ! 2298: static iw_stats * ! 2299: wavelan_get_wireless_stats(device * dev) ! 2300: { ! 2301: u_long ioaddr = dev->base_addr; ! 2302: net_local * lp = (net_local *) dev->priv; ! 2303: mmr_t m; ! 2304: iw_stats * wstats; ! 2305: unsigned long x; ! 2306: ! 2307: #ifdef DEBUG_IOCTL_TRACE ! 2308: printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name); ! 2309: #endif ! 2310: ! 2311: /* Disable interrupts & save flags */ ! 2312: x = wv_splhi(); ! 2313: ! 2314: if(lp == (net_local *) NULL) ! 2315: return (iw_stats *) NULL; ! 2316: wstats = &lp->wstats; ! 2317: ! 2318: /* Get data from the mmc */ ! 2319: mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); ! 2320: ! 2321: mmc_read(ioaddr, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1); ! 2322: mmc_read(ioaddr, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, 2); ! 2323: mmc_read(ioaddr, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, 4); ! 2324: ! 2325: mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); ! 2326: ! 2327: /* Copy data to wireless stuff */ ! 2328: wstats->status = m.mmr_dce_status; ! 2329: wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL; ! 2330: wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL; ! 2331: wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL; ! 2332: wstats->qual.updated = (((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) | ! 2333: ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) | ! 2334: ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5)); ! 2335: wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; ! 2336: wstats->discard.code = 0L; ! 2337: wstats->discard.misc = 0L; ! 2338: ! 2339: /* Enable interrupts & restore flags */ ! 2340: wv_splx(x); ! 2341: ! 2342: #ifdef DEBUG_IOCTL_TRACE ! 2343: printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name); ! 2344: #endif ! 2345: return &lp->wstats; ! 2346: } ! 2347: #endif /* WIRELESS_EXT */ ! 2348: ! 2349: /************************* PACKET RECEPTION *************************/ ! 2350: /* ! 2351: * This part deals with receiving the packets. ! 2352: * The interrupt handler gets an interrupt when a packet has been ! 2353: * successfully received and calls this part. ! 2354: */ ! 2355: ! 2356: /*------------------------------------------------------------------*/ ! 2357: /* ! 2358: * This routine does the actual copying of data (including the Ethernet ! 2359: * header structure) from the WaveLAN card to an sk_buff chain that ! 2360: * will be passed up to the network interface layer. NOTE: we ! 2361: * currently don't handle trailer protocols (neither does the rest of ! 2362: * the network interface), so if that is needed, it will (at least in ! 2363: * part) be added here. The contents of the receive ring buffer are ! 2364: * copied to a message chain that is then passed to the kernel. ! 2365: * ! 2366: * Note: if any errors occur, the packet is "dropped on the floor" ! 2367: * (called by wv_packet_rcv()) ! 2368: */ ! 2369: static inline void ! 2370: wv_packet_read(device * dev, ! 2371: u_short buf_off, ! 2372: int sksize) ! 2373: { ! 2374: net_local * lp = (net_local *) dev->priv; ! 2375: u_long ioaddr = dev->base_addr; ! 2376: struct sk_buff * skb; ! 2377: ! 2378: #ifdef DEBUG_RX_TRACE ! 2379: printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n", ! 2380: dev->name, fd_p, sksize); ! 2381: #endif ! 2382: ! 2383: /* Allocate buffer for the data */ ! 2384: if((skb = dev_alloc_skb(sksize)) == (struct sk_buff *) NULL) ! 2385: { ! 2386: #ifdef DEBUG_RX_ERROR ! 2387: printk(KERN_INFO "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC).\n", ! 2388: dev->name, sksize); ! 2389: #endif ! 2390: lp->stats.rx_dropped++; ! 2391: return; ! 2392: } ! 2393: ! 2394: skb->dev = dev; ! 2395: ! 2396: /* Copy the packet to the buffer */ ! 2397: obram_read(ioaddr, buf_off, skb_put(skb, sksize), sksize); ! 2398: skb->protocol=eth_type_trans(skb, dev); ! 2399: ! 2400: #ifdef DEBUG_RX_INFO ! 2401: wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read"); ! 2402: #endif /* DEBUG_RX_INFO */ ! 2403: ! 2404: /* Statistics gathering & stuff associated. ! 2405: * It seem a bit messy with all the define, but it's really simple... */ ! 2406: #if defined(WIRELESS_SPY) || defined(HISTOGRAM) ! 2407: if( ! 2408: #ifdef WIRELESS_SPY ! 2409: (lp->spy_number > 0) || ! 2410: #endif /* WIRELESS_SPY */ ! 2411: #ifdef HISTOGRAM ! 2412: (lp->his_number > 0) || ! 2413: #endif /* HISTOGRAM */ ! 2414: 0) ! 2415: { ! 2416: u_char stats[3]; /* signal level, noise level, signal quality */ ! 2417: ! 2418: /* read signal level, silence level and signal quality bytes */ ! 2419: /* Note: in the PCMCIA hardware, these are part of the frame. It seems ! 2420: * that for the ISA hardware, it's nowhere to be found in the frame, ! 2421: * so I'm obliged to do this (it has a side effect on /proc/net/wireless). ! 2422: * Any ideas? */ ! 2423: mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1); ! 2424: mmc_read(ioaddr, mmroff(0, mmr_signal_lvl), stats, 3); ! 2425: mmc_out(ioaddr, mmwoff(0, mmw_freeze), 0); ! 2426: ! 2427: #ifdef DEBUG_RX_INFO ! 2428: printk(KERN_DEBUG "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n", ! 2429: dev->name, stats[0] & 0x3F, stats[1] & 0x3F, stats[2] & 0x0F); ! 2430: #endif ! 2431: ! 2432: /* Spying stuff */ ! 2433: #ifdef WIRELESS_SPY ! 2434: wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats); ! 2435: #endif /* WIRELESS_SPY */ ! 2436: #ifdef HISTOGRAM ! 2437: wl_his_gather(dev, stats); ! 2438: #endif /* HISTOGRAM */ ! 2439: } ! 2440: #endif /* defined(WIRELESS_SPY) || defined(HISTOGRAM) */ ! 2441: ! 2442: /* ! 2443: * Hand the packet to the Network Module ! 2444: */ ! 2445: netif_rx(skb); ! 2446: ! 2447: lp->stats.rx_packets++; ! 2448: ! 2449: #ifdef DEBUG_RX_TRACE ! 2450: printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name); ! 2451: #endif ! 2452: } ! 2453: ! 2454: /*------------------------------------------------------------------*/ ! 2455: /* ! 2456: * Transfer as many packets as we can ! 2457: * from the device RAM. ! 2458: * Called by the interrupt handler. ! 2459: */ ! 2460: static inline void ! 2461: wv_receive(device * dev) ! 2462: { ! 2463: u_long ioaddr = dev->base_addr; ! 2464: net_local * lp = (net_local *)dev->priv; ! 2465: int nreaped = 0; ! 2466: ! 2467: #ifdef DEBUG_RX_TRACE ! 2468: printk(KERN_DEBUG "%s: ->wv_receive()\n", dev->name); ! 2469: #endif ! 2470: ! 2471: /* Loop on each received packet */ ! 2472: for(;;) ! 2473: { ! 2474: fd_t fd; ! 2475: rbd_t rbd; ! 2476: ushort pkt_len; ! 2477: ! 2478: obram_read(ioaddr, lp->rx_head, (unsigned char *) &fd, sizeof(fd)); ! 2479: ! 2480: /* If the current frame is not complete, we have reach the end... */ ! 2481: if((fd.fd_status & FD_STATUS_C) != FD_STATUS_C) ! 2482: break; /* This is how we exit the loop */ ! 2483: ! 2484: nreaped++; ! 2485: ! 2486: /* Check if frame correctly received */ ! 2487: if((fd.fd_status & (FD_STATUS_B | FD_STATUS_OK)) != ! 2488: (FD_STATUS_B | FD_STATUS_OK)) ! 2489: { ! 2490: /* ! 2491: * Not sure about this one -- it does not seem ! 2492: * to be an error so we will keep quiet about it. ! 2493: */ ! 2494: #ifndef IGNORE_NORMAL_XMIT_ERRS ! 2495: #ifdef DEBUG_RX_ERROR ! 2496: if((fd.fd_status & FD_STATUS_B) != FD_STATUS_B) ! 2497: printk(KERN_INFO "%s: wv_receive(): frame not consumed by RU.\n", ! 2498: dev->name); ! 2499: #endif ! 2500: #endif /* IGNORE_NORMAL_XMIT_ERRS */ ! 2501: ! 2502: #ifdef DEBUG_RX_ERROR ! 2503: if((fd.fd_status & FD_STATUS_OK) != FD_STATUS_OK) ! 2504: printk(KERN_INFO "%s: wv_receive(): frame not received successfully.\n", ! 2505: dev->name); ! 2506: #endif ! 2507: } ! 2508: ! 2509: /* Were there problems in processing the frame? Let's check. */ ! 2510: if((fd.fd_status & (FD_STATUS_S6 | FD_STATUS_S7 | FD_STATUS_S8 | ! 2511: FD_STATUS_S9 | FD_STATUS_S10 | FD_STATUS_S11)) ! 2512: != 0) ! 2513: { ! 2514: lp->stats.rx_errors++; ! 2515: ! 2516: #ifdef DEBUG_RX_ERROR ! 2517: if((fd.fd_status & FD_STATUS_S6) != 0) ! 2518: printk(KERN_INFO "%s: wv_receive(): no EOF flag.\n", dev->name); ! 2519: #endif ! 2520: ! 2521: if((fd.fd_status & FD_STATUS_S7) != 0) ! 2522: { ! 2523: lp->stats.rx_length_errors++; ! 2524: #ifdef DEBUG_RX_ERROR ! 2525: printk(KERN_INFO "%s: wv_receive(): frame too short.\n", ! 2526: dev->name); ! 2527: #endif ! 2528: } ! 2529: ! 2530: if((fd.fd_status & FD_STATUS_S8) != 0) ! 2531: { ! 2532: lp->stats.rx_over_errors++; ! 2533: #ifdef DEBUG_RX_ERROR ! 2534: printk(KERN_INFO "%s: wv_receive(): rx DMA overrun.\n", ! 2535: dev->name); ! 2536: #endif ! 2537: } ! 2538: ! 2539: if((fd.fd_status & FD_STATUS_S9) != 0) ! 2540: { ! 2541: lp->stats.rx_fifo_errors++; ! 2542: #ifdef DEBUG_RX_ERROR ! 2543: printk(KERN_INFO "%s: wv_receive(): ran out of resources.\n", ! 2544: dev->name); ! 2545: #endif ! 2546: } ! 2547: ! 2548: if((fd.fd_status & FD_STATUS_S10) != 0) ! 2549: { ! 2550: lp->stats.rx_frame_errors++; ! 2551: #ifdef DEBUG_RX_ERROR ! 2552: printk(KERN_INFO "%s: wv_receive(): alignment error.\n", ! 2553: dev->name); ! 2554: #endif ! 2555: } ! 2556: ! 2557: if((fd.fd_status & FD_STATUS_S11) != 0) ! 2558: { ! 2559: lp->stats.rx_crc_errors++; ! 2560: #ifdef DEBUG_RX_ERROR ! 2561: printk(KERN_INFO "%s: wv_receive(): CRC error.\n", dev->name); ! 2562: #endif ! 2563: } ! 2564: } ! 2565: ! 2566: /* Does the frame contain a pointer to the data? Let's check. */ ! 2567: if(fd.fd_rbd_offset == I82586NULL) ! 2568: #ifdef DEBUG_RX_ERROR ! 2569: printk(KERN_INFO "%s: wv_receive(): frame has no data.\n", dev->name); ! 2570: #endif ! 2571: else ! 2572: { ! 2573: obram_read(ioaddr, fd.fd_rbd_offset, ! 2574: (unsigned char *) &rbd, sizeof(rbd)); ! 2575: ! 2576: #ifdef DEBUG_RX_ERROR ! 2577: if((rbd.rbd_status & RBD_STATUS_EOF) != RBD_STATUS_EOF) ! 2578: printk(KERN_INFO "%s: wv_receive(): missing EOF flag.\n", ! 2579: dev->name); ! 2580: ! 2581: if((rbd.rbd_status & RBD_STATUS_F) != RBD_STATUS_F) ! 2582: printk(KERN_INFO "%s: wv_receive(): missing F flag.\n", ! 2583: dev->name); ! 2584: #endif ! 2585: ! 2586: pkt_len = rbd.rbd_status & RBD_STATUS_ACNT; ! 2587: ! 2588: /* Read the packet and transmit to Linux */ ! 2589: wv_packet_read(dev, rbd.rbd_bufl, pkt_len); ! 2590: } /* if frame has data */ ! 2591: ! 2592: fd.fd_status = 0; ! 2593: obram_write(ioaddr, fdoff(lp->rx_head, fd_status), ! 2594: (unsigned char *) &fd.fd_status, sizeof(fd.fd_status)); ! 2595: ! 2596: fd.fd_command = FD_COMMAND_EL; ! 2597: obram_write(ioaddr, fdoff(lp->rx_head, fd_command), ! 2598: (unsigned char *) &fd.fd_command, sizeof(fd.fd_command)); ! 2599: ! 2600: fd.fd_command = 0; ! 2601: obram_write(ioaddr, fdoff(lp->rx_last, fd_command), ! 2602: (unsigned char *) &fd.fd_command, sizeof(fd.fd_command)); ! 2603: ! 2604: lp->rx_last = lp->rx_head; ! 2605: lp->rx_head = fd.fd_link_offset; ! 2606: } /* for(;;) -> loop on all frames */ ! 2607: ! 2608: #ifdef DEBUG_RX_INFO ! 2609: if(nreaped > 1) ! 2610: printk(KERN_DEBUG "%s: wv_receive(): reaped %d\n", dev->name, nreaped); ! 2611: #endif ! 2612: #ifdef DEBUG_RX_TRACE ! 2613: printk(KERN_DEBUG "%s: <-wv_receive()\n", dev->name); ! 2614: #endif ! 2615: } ! 2616: ! 2617: /*********************** PACKET TRANSMISSION ***********************/ ! 2618: /* ! 2619: * This part deals with sending packet through the WaveLAN ! 2620: * ! 2621: */ ! 2622: ! 2623: /*------------------------------------------------------------------*/ ! 2624: /* ! 2625: * This routine fills in the appropriate registers and memory ! 2626: * locations on the WaveLAN card and starts the card off on ! 2627: * the transmit. ! 2628: * ! 2629: * The principle : ! 2630: * Each block contain a transmit command, a nop command, ! 2631: * a transmit block descriptor and a buffer. ! 2632: * The CU read the transmit block which point to the tbd, ! 2633: * read the tbd and the content of the buffer. ! 2634: * When it has finished with it, it goes to the next command ! 2635: * which in our case is the nop. The nop point on itself, ! 2636: * so the CU stop here. ! 2637: * When we add the next block, we modify the previous nop ! 2638: * to make it point on the new tx command. ! 2639: * Simple, isn't it ? ! 2640: * ! 2641: * (called in wavelan_packet_xmit()) ! 2642: */ ! 2643: static inline void ! 2644: wv_packet_write(device * dev, ! 2645: void * buf, ! 2646: short length) ! 2647: { ! 2648: net_local * lp = (net_local *) dev->priv; ! 2649: u_long ioaddr = dev->base_addr; ! 2650: unsigned short txblock; ! 2651: unsigned short txpred; ! 2652: unsigned short tx_addr; ! 2653: unsigned short nop_addr; ! 2654: unsigned short tbd_addr; ! 2655: unsigned short buf_addr; ! 2656: ac_tx_t tx; ! 2657: ac_nop_t nop; ! 2658: tbd_t tbd; ! 2659: int clen = length; ! 2660: unsigned long x; ! 2661: ! 2662: #ifdef DEBUG_TX_TRACE ! 2663: printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length); ! 2664: #endif ! 2665: ! 2666: /* Check if we need some padding */ ! 2667: if(clen < ETH_ZLEN) ! 2668: clen = ETH_ZLEN; ! 2669: ! 2670: x = wv_splhi(); ! 2671: ! 2672: /* Calculate addresses of next block and previous block */ ! 2673: txblock = lp->tx_first_free; ! 2674: txpred = txblock - TXBLOCKZ; ! 2675: if(txpred < OFFSET_CU) ! 2676: txpred += NTXBLOCKS * TXBLOCKZ; ! 2677: lp->tx_first_free += TXBLOCKZ; ! 2678: if(lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) ! 2679: lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ; ! 2680: ! 2681: /* ! 2682: if (lp->tx_n_in_use > 0) ! 2683: printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]); ! 2684: */ ! 2685: ! 2686: lp->tx_n_in_use++; ! 2687: ! 2688: /* Calculate addresses of the differents part of the block */ ! 2689: tx_addr = txblock; ! 2690: nop_addr = tx_addr + sizeof(tx); ! 2691: tbd_addr = nop_addr + sizeof(nop); ! 2692: buf_addr = tbd_addr + sizeof(tbd); ! 2693: ! 2694: /* ! 2695: * Transmit command. ! 2696: */ ! 2697: tx.tx_h.ac_status = 0; ! 2698: obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status), ! 2699: (unsigned char *) &tx.tx_h.ac_status, ! 2700: sizeof(tx.tx_h.ac_status)); ! 2701: ! 2702: /* ! 2703: * NOP command. ! 2704: */ ! 2705: nop.nop_h.ac_status = 0; ! 2706: obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), ! 2707: (unsigned char *) &nop.nop_h.ac_status, ! 2708: sizeof(nop.nop_h.ac_status)); ! 2709: nop.nop_h.ac_link = nop_addr; ! 2710: obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), ! 2711: (unsigned char *) &nop.nop_h.ac_link, ! 2712: sizeof(nop.nop_h.ac_link)); ! 2713: ! 2714: /* ! 2715: * Transmit buffer descriptor ! 2716: */ ! 2717: tbd.tbd_status = TBD_STATUS_EOF | (TBD_STATUS_ACNT & clen); ! 2718: tbd.tbd_next_bd_offset = I82586NULL; ! 2719: tbd.tbd_bufl = buf_addr; ! 2720: tbd.tbd_bufh = 0; ! 2721: obram_write(ioaddr, tbd_addr, (unsigned char *)&tbd, sizeof(tbd)); ! 2722: ! 2723: /* ! 2724: * Data ! 2725: */ ! 2726: obram_write(ioaddr, buf_addr, buf, clen); ! 2727: ! 2728: /* ! 2729: * Overwrite the predecessor NOP link ! 2730: * so that it points to this txblock. ! 2731: */ ! 2732: nop_addr = txpred + sizeof(tx); ! 2733: nop.nop_h.ac_status = 0; ! 2734: obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), ! 2735: (unsigned char *)&nop.nop_h.ac_status, ! 2736: sizeof(nop.nop_h.ac_status)); ! 2737: nop.nop_h.ac_link = txblock; ! 2738: obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), ! 2739: (unsigned char *) &nop.nop_h.ac_link, ! 2740: sizeof(nop.nop_h.ac_link)); ! 2741: ! 2742: /* If watchdog not already active, activate it... */ ! 2743: if(lp->watchdog.prev == (timer_list *) NULL) ! 2744: { ! 2745: /* set timer to expire in WATCHDOG_JIFFIES */ ! 2746: lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; ! 2747: add_timer(&lp->watchdog); ! 2748: } ! 2749: ! 2750: if(lp->tx_first_in_use == I82586NULL) ! 2751: lp->tx_first_in_use = txblock; ! 2752: ! 2753: if(lp->tx_n_in_use < NTXBLOCKS - 1) ! 2754: dev->tbusy = 0; ! 2755: ! 2756: wv_splx(x); ! 2757: ! 2758: #ifdef DEBUG_TX_INFO ! 2759: wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write"); ! 2760: #endif /* DEBUG_TX_INFO */ ! 2761: ! 2762: #ifdef DEBUG_TX_TRACE ! 2763: printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name); ! 2764: #endif ! 2765: } ! 2766: ! 2767: /*------------------------------------------------------------------*/ ! 2768: /* ! 2769: * This routine is called when we want to send a packet (NET3 callback) ! 2770: * In this routine, we check if the hardware is ready to accept ! 2771: * the packet. We also prevent reentrance. Then, we call the function ! 2772: * to send the packet... ! 2773: */ ! 2774: static int ! 2775: wavelan_packet_xmit(struct sk_buff * skb, ! 2776: device * dev) ! 2777: { ! 2778: net_local * lp = (net_local *)dev->priv; ! 2779: ! 2780: #ifdef DEBUG_TX_TRACE ! 2781: printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name, ! 2782: (unsigned) skb); ! 2783: #endif ! 2784: ! 2785: /* This flag indicate that the hardware can't perform a transmission. ! 2786: * Theoretically, NET3 checks it before sending a packet to the driver, ! 2787: * but in fact it never does that and pool continuously. ! 2788: * As the watchdog will abort overly long transmissions, we are quite safe. ! 2789: */ ! 2790: if(dev->tbusy) ! 2791: return 1; ! 2792: ! 2793: /* ! 2794: * If some higher layer thinks we've missed ! 2795: * a tx-done interrupt we are passed NULL. ! 2796: * Caution: dev_tint() handles the cli()/sti() itself. ! 2797: */ ! 2798: if(skb == (struct sk_buff *)0) ! 2799: { ! 2800: #ifdef DEBUG_TX_ERROR ! 2801: printk(KERN_INFO "%s: wavelan_packet_xmit(): skb == NULL\n", dev->name); ! 2802: #endif ! 2803: dev_tint(dev); ! 2804: return 0; ! 2805: } ! 2806: ! 2807: /* ! 2808: * Block a timer-based transmit from overlapping. ! 2809: * In other words, prevent reentering this routine. ! 2810: */ ! 2811: if(set_bit(0, (void *)&dev->tbusy) != 0) ! 2812: #ifdef DEBUG_TX_ERROR ! 2813: printk(KERN_INFO "%s: Transmitter access conflict.\n", dev->name); ! 2814: #endif ! 2815: else ! 2816: { ! 2817: /* If somebody has asked to reconfigure the controller, ! 2818: * we can do it now. ! 2819: */ ! 2820: if(lp->reconfig_82586) ! 2821: { ! 2822: wv_82586_config(dev); ! 2823: if(dev->tbusy) ! 2824: return 1; ! 2825: } ! 2826: ! 2827: #ifdef DEBUG_TX_ERROR ! 2828: if(skb->next) ! 2829: printk(KERN_INFO "skb has next\n"); ! 2830: #endif ! 2831: ! 2832: wv_packet_write(dev, skb->data, skb->len); ! 2833: } ! 2834: ! 2835: dev_kfree_skb(skb, FREE_WRITE); ! 2836: ! 2837: #ifdef DEBUG_TX_TRACE ! 2838: printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name); ! 2839: #endif ! 2840: return 0; ! 2841: } ! 2842: ! 2843: /*********************** HARDWARE CONFIGURATION ***********************/ ! 2844: /* ! 2845: * This part does the real job of starting and configuring the hardware. ! 2846: */ ! 2847: ! 2848: /*--------------------------------------------------------------------*/ ! 2849: /* ! 2850: * Routine to initialize the Modem Management Controller. ! 2851: * (called by wv_hw_reset()) ! 2852: */ ! 2853: static inline int ! 2854: wv_mmc_init(device * dev) ! 2855: { ! 2856: u_long ioaddr = dev->base_addr; ! 2857: net_local * lp = (net_local *)dev->priv; ! 2858: psa_t psa; ! 2859: mmw_t m; ! 2860: int configured; ! 2861: ! 2862: #ifdef DEBUG_CONFIG_TRACE ! 2863: printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name); ! 2864: #endif ! 2865: ! 2866: /* Read the parameter storage area */ ! 2867: psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); ! 2868: ! 2869: #ifdef USE_PSA_CONFIG ! 2870: configured = psa.psa_conf_status & 1; ! 2871: #else ! 2872: configured = 0; ! 2873: #endif ! 2874: ! 2875: /* Is the PSA is not configured */ ! 2876: if(!configured) ! 2877: { ! 2878: /* User will be able to configure NWID after (with iwconfig) */ ! 2879: psa.psa_nwid[0] = 0; ! 2880: psa.psa_nwid[1] = 0; ! 2881: ! 2882: /* no NWID checking since NWID is not set */ ! 2883: psa.psa_nwid_select = 0; ! 2884: ! 2885: /* Disable encryption */ ! 2886: psa.psa_encryption_select = 0; ! 2887: ! 2888: /* Set to standard values ! 2889: * 0x04 for AT, ! 2890: * 0x01 for MCA, ! 2891: * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document) ! 2892: */ ! 2893: if (psa.psa_comp_number & 1) ! 2894: psa.psa_thr_pre_set = 0x01; ! 2895: else ! 2896: psa.psa_thr_pre_set = 0x04; ! 2897: psa.psa_quality_thr = 0x03; ! 2898: ! 2899: /* It is configured */ ! 2900: psa.psa_conf_status |= 1; ! 2901: ! 2902: #ifdef USE_PSA_CONFIG ! 2903: /* Write the psa */ ! 2904: psa_write(ioaddr, lp->hacr, (char *)psa.psa_nwid - (char *)&psa, ! 2905: (unsigned char *)psa.psa_nwid, 4); ! 2906: psa_write(ioaddr, lp->hacr, (char *)&psa.psa_thr_pre_set - (char *)&psa, ! 2907: (unsigned char *)&psa.psa_thr_pre_set, 1); ! 2908: psa_write(ioaddr, lp->hacr, (char *)&psa.psa_quality_thr - (char *)&psa, ! 2909: (unsigned char *)&psa.psa_quality_thr, 1); ! 2910: psa_write(ioaddr, lp->hacr, (char *)&psa.psa_conf_status - (char *)&psa, ! 2911: (unsigned char *)&psa.psa_conf_status, 1); ! 2912: #endif ! 2913: } ! 2914: ! 2915: /* Zero the mmc structure */ ! 2916: memset(&m, 0x00, sizeof(m)); ! 2917: ! 2918: /* Copy PSA info to the mmc */ ! 2919: m.mmw_netw_id_l = psa.psa_nwid[1]; ! 2920: m.mmw_netw_id_h = psa.psa_nwid[0]; ! 2921: ! 2922: if(psa.psa_nwid_select & 1) ! 2923: m.mmw_loopt_sel = 0x00; ! 2924: else ! 2925: m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID; ! 2926: ! 2927: memcpy(&m.mmw_encr_key, &psa.psa_encryption_key, ! 2928: sizeof(m.mmw_encr_key)); ! 2929: ! 2930: if(psa.psa_encryption_select) ! 2931: m.mmw_encr_enable = MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE; ! 2932: else ! 2933: m.mmw_encr_enable = 0; ! 2934: ! 2935: m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F; ! 2936: m.mmw_quality_thr = psa.psa_quality_thr & 0x0F; ! 2937: ! 2938: /* Missing: encryption stuff... */ ! 2939: ! 2940: /* ! 2941: * Set default modem control parameters. ! 2942: * See NCR document 407-0024326 Rev. A. ! 2943: */ ! 2944: m.mmw_jabber_enable = 0x01; ! 2945: m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN; ! 2946: m.mmw_ifs = 0x20; ! 2947: m.mmw_mod_delay = 0x04; ! 2948: m.mmw_jam_time = 0x38; ! 2949: ! 2950: m.mmw_encr_enable = 0; ! 2951: m.mmw_des_io_invert = 0; ! 2952: m.mmw_freeze = 0; ! 2953: m.mmw_decay_prm = 0; ! 2954: m.mmw_decay_updat_prm = 0; ! 2955: ! 2956: /* Write all info to MMC */ ! 2957: mmc_write(ioaddr, 0, (u_char *)&m, sizeof(m)); ! 2958: ! 2959: /* The following code starts the modem of the 2.00 frequency ! 2960: * selectable cards at power on. It's not strictly needed for the ! 2961: * following boots. ! 2962: * The original patch was by Joe Finney for the PCMCIA driver, but ! 2963: * I've cleaned it up a bit and added documentation. ! 2964: * Thanks to Loeke Brederveld from Lucent for the info. ! 2965: */ ! 2966: ! 2967: /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) ! 2968: * (does it work for everybody? -- especially old cards?) */ ! 2969: /* Note: WFREQSEL verifies that it is able to read a sensible ! 2970: * frequency from EEPROM (address 0x00) and that MMR_FEE_STATUS_ID ! 2971: * is 0xA (Xilinx version) or 0xB (Ariadne version). ! 2972: * My test is more crude but does work. */ ! 2973: if(!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & ! 2974: (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) ! 2975: { ! 2976: /* We must download the frequency parameters to the ! 2977: * synthesizers (from the EEPROM - area 1) ! 2978: * Note : as the EEPROM is auto decremented, we set the end ! 2979: * if the area... */ ! 2980: m.mmw_fee_addr = 0x0F; ! 2981: m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; ! 2982: mmc_write(ioaddr, (char *)&m.mmw_fee_ctrl - (char *)&m, ! 2983: (unsigned char *)&m.mmw_fee_ctrl, 2); ! 2984: ! 2985: /* Wait until the download is finished */ ! 2986: fee_wait(ioaddr, 100, 100); ! 2987: ! 2988: #ifdef DEBUG_CONFIG_INFO ! 2989: /* The frequency was in the last word downloaded. */ ! 2990: mmc_read(ioaddr, (char *)&m.mmw_fee_data_l - (char *)&m, ! 2991: (unsigned char *)&m.mmw_fee_data_l, 2); ! 2992: ! 2993: /* Print some info for the user. */ ! 2994: printk(KERN_DEBUG "%s: WaveLAN 2.00 recognised (frequency select) : Current frequency = %ld\n", ! 2995: dev->name, ! 2996: ((m.mmw_fee_data_h << 4) | ! 2997: (m.mmw_fee_data_l >> 4)) * 5 / 2 + 24000L); ! 2998: #endif ! 2999: ! 3000: /* We must now download the power adjust value (gain) to ! 3001: * the synthesizers (from the EEPROM - area 7 - DAC) */ ! 3002: m.mmw_fee_addr = 0x61; ! 3003: m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD; ! 3004: mmc_write(ioaddr, (char *)&m.mmw_fee_ctrl - (char *)&m, ! 3005: (unsigned char *)&m.mmw_fee_ctrl, 2); ! 3006: ! 3007: /* Wait until the download is finished */ ! 3008: } /* if 2.00 card */ ! 3009: ! 3010: #ifdef DEBUG_CONFIG_TRACE ! 3011: printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name); ! 3012: #endif ! 3013: return 0; ! 3014: } ! 3015: ! 3016: /*------------------------------------------------------------------*/ ! 3017: /* ! 3018: * Construct the fd and rbd structures. ! 3019: * Start the receive unit. ! 3020: * (called by wv_hw_reset()) ! 3021: */ ! 3022: static inline int ! 3023: wv_ru_start(device * dev) ! 3024: { ! 3025: net_local * lp = (net_local *) dev->priv; ! 3026: u_long ioaddr = dev->base_addr; ! 3027: u_short scb_cs; ! 3028: fd_t fd; ! 3029: rbd_t rbd; ! 3030: u_short rx; ! 3031: u_short rx_next; ! 3032: int i; ! 3033: ! 3034: #ifdef DEBUG_CONFIG_TRACE ! 3035: printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name); ! 3036: #endif ! 3037: ! 3038: obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), (unsigned char *)&scb_cs, sizeof(scb_cs)); ! 3039: if((scb_cs & SCB_ST_RUS) == SCB_ST_RUS_RDY) ! 3040: return 0; ! 3041: ! 3042: lp->rx_head = OFFSET_RU; ! 3043: ! 3044: for(i = 0, rx = lp->rx_head; i < NRXBLOCKS; i++, rx = rx_next) ! 3045: { ! 3046: rx_next = (i == NRXBLOCKS - 1) ? lp->rx_head : rx + RXBLOCKZ; ! 3047: ! 3048: fd.fd_status = 0; ! 3049: fd.fd_command = (i == NRXBLOCKS - 1) ? FD_COMMAND_EL : 0; ! 3050: fd.fd_link_offset = rx_next; ! 3051: fd.fd_rbd_offset = rx + sizeof(fd); ! 3052: obram_write(ioaddr, rx, (unsigned char *)&fd, sizeof(fd)); ! 3053: ! 3054: rbd.rbd_status = 0; ! 3055: rbd.rbd_next_rbd_offset = I82586NULL; ! 3056: rbd.rbd_bufl = rx + sizeof(fd) + sizeof(rbd); ! 3057: rbd.rbd_bufh = 0; ! 3058: rbd.rbd_el_size = RBD_EL | (RBD_SIZE & MAXDATAZ); ! 3059: obram_write(ioaddr, rx + sizeof(fd), ! 3060: (unsigned char *) &rbd, sizeof(rbd)); ! 3061: ! 3062: lp->rx_last = rx; ! 3063: } ! 3064: ! 3065: obram_write(ioaddr, scboff(OFFSET_SCB, scb_rfa_offset), ! 3066: (unsigned char *) &lp->rx_head, sizeof(lp->rx_head)); ! 3067: ! 3068: scb_cs = SCB_CMD_RUC_GO; ! 3069: obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), ! 3070: (unsigned char *) &scb_cs, sizeof(scb_cs)); ! 3071: ! 3072: set_chan_attn(ioaddr, lp->hacr); ! 3073: ! 3074: for(i = 1000; i > 0; i--) ! 3075: { ! 3076: obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), ! 3077: (unsigned char *) &scb_cs, sizeof(scb_cs)); ! 3078: if (scb_cs == 0) ! 3079: break; ! 3080: ! 3081: udelay(10); ! 3082: } ! 3083: ! 3084: if(i <= 0) ! 3085: { ! 3086: #ifdef DEBUG_CONFIG_ERRORS ! 3087: printk(KERN_INFO "%s: wavelan_ru_start(): board not accepting command.\n", ! 3088: dev->name); ! 3089: #endif ! 3090: return -1; ! 3091: } ! 3092: ! 3093: #ifdef DEBUG_CONFIG_TRACE ! 3094: printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name); ! 3095: #endif ! 3096: return 0; ! 3097: } ! 3098: ! 3099: /*------------------------------------------------------------------*/ ! 3100: /* ! 3101: * Initialise the transmit blocks. ! 3102: * Start the command unit executing the NOP ! 3103: * self-loop of the first transmit block. ! 3104: * ! 3105: * Here, we create the list of send buffers used to transmit packets ! 3106: * between the PC and the command unit. For each buffer, we create a ! 3107: * buffer descriptor (pointing on the buffer), a transmit command ! 3108: * (pointing to the buffer descriptor) and a NOP command. ! 3109: * The transmit command is linked to the NOP, and the NOP to itself. ! 3110: * When we will have finished executing the transmit command, we will ! 3111: * then loop on the NOP. By releasing the NOP link to a new command, ! 3112: * we may send another buffer. ! 3113: * ! 3114: * (called by wv_hw_reset()) ! 3115: */ ! 3116: static inline int ! 3117: wv_cu_start(device * dev) ! 3118: { ! 3119: net_local * lp = (net_local *) dev->priv; ! 3120: u_long ioaddr = dev->base_addr; ! 3121: int i; ! 3122: u_short txblock; ! 3123: u_short first_nop; ! 3124: u_short scb_cs; ! 3125: ! 3126: #ifdef DEBUG_CONFIG_TRACE ! 3127: printk(KERN_DEBUG "%s: ->wv_cu_start()\n", dev->name); ! 3128: #endif ! 3129: ! 3130: lp->tx_first_free = OFFSET_CU; ! 3131: lp->tx_first_in_use = I82586NULL; ! 3132: ! 3133: for(i = 0, txblock = OFFSET_CU; ! 3134: i < NTXBLOCKS; ! 3135: i++, txblock += TXBLOCKZ) ! 3136: { ! 3137: ac_tx_t tx; ! 3138: ac_nop_t nop; ! 3139: tbd_t tbd; ! 3140: unsigned short tx_addr; ! 3141: unsigned short nop_addr; ! 3142: unsigned short tbd_addr; ! 3143: unsigned short buf_addr; ! 3144: ! 3145: tx_addr = txblock; ! 3146: nop_addr = tx_addr + sizeof(tx); ! 3147: tbd_addr = nop_addr + sizeof(nop); ! 3148: buf_addr = tbd_addr + sizeof(tbd); ! 3149: ! 3150: tx.tx_h.ac_status = 0; ! 3151: tx.tx_h.ac_command = acmd_transmit | AC_CFLD_I; ! 3152: tx.tx_h.ac_link = nop_addr; ! 3153: tx.tx_tbd_offset = tbd_addr; ! 3154: obram_write(ioaddr, tx_addr, (unsigned char *) &tx, sizeof(tx)); ! 3155: ! 3156: nop.nop_h.ac_status = 0; ! 3157: nop.nop_h.ac_command = acmd_nop; ! 3158: nop.nop_h.ac_link = nop_addr; ! 3159: obram_write(ioaddr, nop_addr, (unsigned char *) &nop, sizeof(nop)); ! 3160: ! 3161: tbd.tbd_status = TBD_STATUS_EOF; ! 3162: tbd.tbd_next_bd_offset = I82586NULL; ! 3163: tbd.tbd_bufl = buf_addr; ! 3164: tbd.tbd_bufh = 0; ! 3165: obram_write(ioaddr, tbd_addr, (unsigned char *) &tbd, sizeof(tbd)); ! 3166: } ! 3167: ! 3168: first_nop = OFFSET_CU + (NTXBLOCKS - 1) * TXBLOCKZ + sizeof(ac_tx_t); ! 3169: obram_write(ioaddr, scboff(OFFSET_SCB, scb_cbl_offset), ! 3170: (unsigned char *) &first_nop, sizeof(first_nop)); ! 3171: ! 3172: scb_cs = SCB_CMD_CUC_GO; ! 3173: obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), ! 3174: (unsigned char *) &scb_cs, sizeof(scb_cs)); ! 3175: ! 3176: set_chan_attn(ioaddr, lp->hacr); ! 3177: ! 3178: for(i = 1000; i > 0; i--) ! 3179: { ! 3180: obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), ! 3181: (unsigned char *) &scb_cs, sizeof(scb_cs)); ! 3182: if (scb_cs == 0) ! 3183: break; ! 3184: ! 3185: udelay(10); ! 3186: } ! 3187: ! 3188: if(i <= 0) ! 3189: { ! 3190: #ifdef DEBUG_CONFIG_ERRORS ! 3191: printk(KERN_INFO "%s: wavelan_cu_start(): board not accepting command.\n", ! 3192: dev->name); ! 3193: #endif ! 3194: return -1; ! 3195: } ! 3196: ! 3197: lp->tx_n_in_use = 0; ! 3198: dev->tbusy = 0; ! 3199: ! 3200: #ifdef DEBUG_CONFIG_TRACE ! 3201: printk(KERN_DEBUG "%s: <-wv_cu_start()\n", dev->name); ! 3202: #endif ! 3203: return 0; ! 3204: } ! 3205: ! 3206: /*------------------------------------------------------------------*/ ! 3207: /* ! 3208: * This routine does a standard config of the WaveLAN controler (i82586). ! 3209: * ! 3210: * It initialises the scp, iscp and scb structure ! 3211: * The first two are just pointers to the next. ! 3212: * The last one is used for basic configuration and for basic ! 3213: * communication (interrupt status). ! 3214: * ! 3215: * (called by wv_hw_reset()) ! 3216: */ ! 3217: static inline int ! 3218: wv_82586_start(device * dev) ! 3219: { ! 3220: net_local * lp = (net_local *) dev->priv; ! 3221: u_long ioaddr = dev->base_addr; ! 3222: scp_t scp; /* system configuration pointer */ ! 3223: iscp_t iscp; /* intermediate scp */ ! 3224: scb_t scb; /* system control block */ ! 3225: ach_t cb; /* Action command header */ ! 3226: u_char zeroes[512]; ! 3227: int i; ! 3228: ! 3229: #ifdef DEBUG_CONFIG_TRACE ! 3230: printk(KERN_DEBUG "%s: ->wv_82586_start()\n", dev->name); ! 3231: #endif ! 3232: ! 3233: /* ! 3234: * Clear the onboard RAM. ! 3235: */ ! 3236: memset(&zeroes[0], 0x00, sizeof(zeroes)); ! 3237: for(i = 0; i < I82586_MEMZ; i += sizeof(zeroes)) ! 3238: obram_write(ioaddr, i, &zeroes[0], sizeof(zeroes)); ! 3239: ! 3240: /* ! 3241: * Construct the command unit structures: ! 3242: * scp, iscp, scb, cb. ! 3243: */ ! 3244: memset(&scp, 0x00, sizeof(scp)); ! 3245: scp.scp_sysbus = SCP_SY_16BBUS; ! 3246: scp.scp_iscpl = OFFSET_ISCP; ! 3247: obram_write(ioaddr, OFFSET_SCP, (unsigned char *)&scp, sizeof(scp)); ! 3248: ! 3249: memset(&iscp, 0x00, sizeof(iscp)); ! 3250: iscp.iscp_busy = 1; ! 3251: iscp.iscp_offset = OFFSET_SCB; ! 3252: obram_write(ioaddr, OFFSET_ISCP, (unsigned char *)&iscp, sizeof(iscp)); ! 3253: ! 3254: /* Our first command is to reset the i82586. */ ! 3255: memset(&scb, 0x00, sizeof(scb)); ! 3256: scb.scb_command = SCB_CMD_RESET; ! 3257: scb.scb_cbl_offset = OFFSET_CU; ! 3258: scb.scb_rfa_offset = OFFSET_RU; ! 3259: obram_write(ioaddr, OFFSET_SCB, (unsigned char *)&scb, sizeof(scb)); ! 3260: ! 3261: set_chan_attn(ioaddr, lp->hacr); ! 3262: ! 3263: /* Wait for command to finish. */ ! 3264: for(i = 1000; i > 0; i--) ! 3265: { ! 3266: obram_read(ioaddr, OFFSET_ISCP, (unsigned char *) &iscp, sizeof(iscp)); ! 3267: ! 3268: if(iscp.iscp_busy == (unsigned short) 0) ! 3269: break; ! 3270: ! 3271: udelay(10); ! 3272: } ! 3273: ! 3274: if(i <= 0) ! 3275: { ! 3276: #ifdef DEBUG_CONFIG_ERRORS ! 3277: printk(KERN_INFO "%s: wv_82586_start(): iscp_busy timeout.\n", ! 3278: dev->name); ! 3279: #endif ! 3280: return -1; ! 3281: } ! 3282: ! 3283: /* Check command completion */ ! 3284: for(i = 15; i > 0; i--) ! 3285: { ! 3286: obram_read(ioaddr, OFFSET_SCB, (unsigned char *) &scb, sizeof(scb)); ! 3287: ! 3288: if (scb.scb_status == (SCB_ST_CX | SCB_ST_CNA)) ! 3289: break; ! 3290: ! 3291: udelay(10); ! 3292: } ! 3293: ! 3294: if (i <= 0) ! 3295: { ! 3296: #ifdef DEBUG_CONFIG_ERRORS ! 3297: printk(KERN_INFO "%s: wv_82586_start(): status: expected 0x%02x, got 0x%02x.\n", ! 3298: dev->name, SCB_ST_CX | SCB_ST_CNA, scb.scb_status); ! 3299: #endif ! 3300: return -1; ! 3301: } ! 3302: ! 3303: wv_ack(dev); ! 3304: ! 3305: /* Set the action command header. */ ! 3306: memset(&cb, 0x00, sizeof(cb)); ! 3307: cb.ac_command = AC_CFLD_EL | (AC_CFLD_CMD & acmd_diagnose); ! 3308: cb.ac_link = OFFSET_CU; ! 3309: obram_write(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb)); ! 3310: ! 3311: if(wv_synchronous_cmd(dev, "diag()") == -1) ! 3312: return -1; ! 3313: ! 3314: obram_read(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb)); ! 3315: if(cb.ac_status & AC_SFLD_FAIL) ! 3316: { ! 3317: #ifdef DEBUG_CONFIG_ERRORS ! 3318: printk(KERN_INFO "%s: wv_82586_start(): i82586 Self Test failed.\n", ! 3319: dev->name); ! 3320: #endif ! 3321: return -1; ! 3322: } ! 3323: ! 3324: #ifdef DEBUG_I82586_SHOW ! 3325: wv_scb_show(ioaddr); ! 3326: #endif ! 3327: ! 3328: #ifdef DEBUG_CONFIG_TRACE ! 3329: printk(KERN_DEBUG "%s: <-wv_82586_start()\n", dev->name); ! 3330: #endif ! 3331: return 0; ! 3332: } ! 3333: ! 3334: /*------------------------------------------------------------------*/ ! 3335: /* ! 3336: * This routine does a standard configuration of the WaveLAN controller ! 3337: * (i82586). ! 3338: * ! 3339: * This routine is a violent hack. We use the first free transmit block ! 3340: * to make our configuration. In the buffer area, we create the three ! 3341: * configuration commands (linked). We make the previous NOP point to ! 3342: * the beginning of the buffer instead of the tx command. After, we go ! 3343: * as usual to the NOP command. ! 3344: * Note that only the last command (mc_set) will generate an interrupt. ! 3345: * ! 3346: * (called by wv_hw_reset(), wv_82586_reconfig()) ! 3347: */ ! 3348: static void ! 3349: wv_82586_config(device * dev) ! 3350: { ! 3351: net_local * lp = (net_local *) dev->priv; ! 3352: u_long ioaddr = dev->base_addr; ! 3353: unsigned short txblock; ! 3354: unsigned short txpred; ! 3355: unsigned short tx_addr; ! 3356: unsigned short nop_addr; ! 3357: unsigned short tbd_addr; ! 3358: unsigned short cfg_addr; ! 3359: unsigned short ias_addr; ! 3360: unsigned short mcs_addr; ! 3361: ac_tx_t tx; ! 3362: ac_nop_t nop; ! 3363: ac_cfg_t cfg; /* Configure action */ ! 3364: ac_ias_t ias; /* IA-setup action */ ! 3365: ac_mcs_t mcs; /* Multicast setup */ ! 3366: struct dev_mc_list * dmi; ! 3367: unsigned long x; ! 3368: ! 3369: #ifdef DEBUG_CONFIG_TRACE ! 3370: printk(KERN_DEBUG "%s: ->wv_82586_config()\n", dev->name); ! 3371: #endif ! 3372: ! 3373: x = wv_splhi(); ! 3374: ! 3375: /* Calculate addresses of next block and previous block */ ! 3376: txblock = lp->tx_first_free; ! 3377: txpred = txblock - TXBLOCKZ; ! 3378: if(txpred < OFFSET_CU) ! 3379: txpred += NTXBLOCKS * TXBLOCKZ; ! 3380: lp->tx_first_free += TXBLOCKZ; ! 3381: if(lp->tx_first_free >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) ! 3382: lp->tx_first_free -= NTXBLOCKS * TXBLOCKZ; ! 3383: ! 3384: lp->tx_n_in_use++; ! 3385: ! 3386: /* Calculate addresses of the different parts of the block. */ ! 3387: tx_addr = txblock; ! 3388: nop_addr = tx_addr + sizeof(tx); ! 3389: tbd_addr = nop_addr + sizeof(nop); ! 3390: cfg_addr = tbd_addr + sizeof(tbd_t); /* beginning of the buffer */ ! 3391: ias_addr = cfg_addr + sizeof(cfg); ! 3392: mcs_addr = ias_addr + sizeof(ias); ! 3393: ! 3394: /* ! 3395: * Transmit command ! 3396: */ ! 3397: tx.tx_h.ac_status = 0xFFFF; /* Fake completion value */ ! 3398: obram_write(ioaddr, toff(ac_tx_t, tx_addr, tx_h.ac_status), ! 3399: (unsigned char *) &tx.tx_h.ac_status, ! 3400: sizeof(tx.tx_h.ac_status)); ! 3401: ! 3402: /* ! 3403: * NOP command ! 3404: */ ! 3405: nop.nop_h.ac_status = 0; ! 3406: obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), ! 3407: (unsigned char *) &nop.nop_h.ac_status, ! 3408: sizeof(nop.nop_h.ac_status)); ! 3409: nop.nop_h.ac_link = nop_addr; ! 3410: obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), ! 3411: (unsigned char *) &nop.nop_h.ac_link, ! 3412: sizeof(nop.nop_h.ac_link)); ! 3413: ! 3414: /* Create a configure action */ ! 3415: memset(&cfg, 0x00, sizeof(cfg)); ! 3416: ! 3417: #if 0 ! 3418: /* ! 3419: * The default board configuration ! 3420: */ ! 3421: cfg.fifolim_bytecnt = 0x080c; ! 3422: cfg.addrlen_mode = 0x2600; ! 3423: cfg.linprio_interframe = 0x7820; /* IFS=120, ACS=2 */ ! 3424: cfg.slot_time = 0xf00c; /* slottime=12 */ ! 3425: cfg.hardware = 0x0008; /* tx even without CD */ ! 3426: cfg.min_frame_len = 0x0040; ! 3427: #endif /* 0 */ ! 3428: ! 3429: /* ! 3430: * For Linux we invert AC_CFG_ALOC(..) so as to conform ! 3431: * to the way that net packets reach us from above. ! 3432: * (See also ac_tx_t.) ! 3433: */ ! 3434: cfg.cfg_byte_cnt = AC_CFG_BYTE_CNT(sizeof(ac_cfg_t) - sizeof(ach_t)); ! 3435: cfg.cfg_fifolim = AC_CFG_FIFOLIM(8); ! 3436: cfg.cfg_byte8 = AC_CFG_SAV_BF(0) | ! 3437: AC_CFG_SRDY(0); ! 3438: cfg.cfg_byte9 = AC_CFG_ELPBCK(0) | ! 3439: AC_CFG_ILPBCK(0) | ! 3440: AC_CFG_PRELEN(AC_CFG_PLEN_2) | ! 3441: AC_CFG_ALOC(1) | ! 3442: AC_CFG_ADDRLEN(WAVELAN_ADDR_SIZE); ! 3443: cfg.cfg_byte10 = AC_CFG_BOFMET(0) | ! 3444: AC_CFG_ACR(0) | ! 3445: AC_CFG_LINPRIO(0); ! 3446: cfg.cfg_ifs = 32; ! 3447: cfg.cfg_slotl = 0; ! 3448: cfg.cfg_byte13 = AC_CFG_RETRYNUM(15) | ! 3449: AC_CFG_SLTTMHI(2); ! 3450: cfg.cfg_byte14 = AC_CFG_FLGPAD(0) | ! 3451: AC_CFG_BTSTF(0) | ! 3452: AC_CFG_CRC16(0) | ! 3453: AC_CFG_NCRC(0) | ! 3454: AC_CFG_TNCRS(1) | ! 3455: AC_CFG_MANCH(0) | ! 3456: AC_CFG_BCDIS(0) | ! 3457: AC_CFG_PRM(lp->promiscuous); ! 3458: cfg.cfg_byte15 = AC_CFG_ICDS(0) | ! 3459: AC_CFG_CDTF(0) | ! 3460: AC_CFG_ICSS(0) | ! 3461: AC_CFG_CSTF(0); ! 3462: /* ! 3463: cfg.cfg_min_frm_len = AC_CFG_MNFRM(64); ! 3464: */ ! 3465: cfg.cfg_min_frm_len = AC_CFG_MNFRM(8); ! 3466: ! 3467: cfg.cfg_h.ac_command = (AC_CFLD_CMD & acmd_configure); ! 3468: cfg.cfg_h.ac_link = ias_addr; ! 3469: obram_write(ioaddr, cfg_addr, (unsigned char *)&cfg, sizeof(cfg)); ! 3470: ! 3471: /* Setup the MAC address */ ! 3472: memset(&ias, 0x00, sizeof(ias)); ! 3473: ias.ias_h.ac_command = (AC_CFLD_CMD & acmd_ia_setup); ! 3474: ias.ias_h.ac_link = mcs_addr; ! 3475: memcpy(&ias.ias_addr[0], (unsigned char *)&dev->dev_addr[0], sizeof(ias.ias_addr)); ! 3476: obram_write(ioaddr, ias_addr, (unsigned char *)&ias, sizeof(ias)); ! 3477: ! 3478: /* Initialize adapter's ethernet multicast addresses */ ! 3479: memset(&mcs, 0x00, sizeof(mcs)); ! 3480: mcs.mcs_h.ac_command = AC_CFLD_I | (AC_CFLD_CMD & acmd_mc_setup); ! 3481: mcs.mcs_h.ac_link = nop_addr; ! 3482: mcs.mcs_cnt = WAVELAN_ADDR_SIZE * lp->mc_count; ! 3483: obram_write(ioaddr, mcs_addr, (unsigned char *)&mcs, sizeof(mcs)); ! 3484: ! 3485: /* If any address to set */ ! 3486: if(lp->mc_count) ! 3487: { ! 3488: for(dmi=dev->mc_list; dmi; dmi=dmi->next) ! 3489: outsw(PIOP1(ioaddr), (u_short *) dmi->dmi_addr, ! 3490: WAVELAN_ADDR_SIZE >> 1); ! 3491: ! 3492: #ifdef DEBUG_CONFIG_INFO ! 3493: printk(KERN_DEBUG "%s: wv_82586_config(): set %d multicast addresses:\n", ! 3494: dev->name, lp->mc_count); ! 3495: for(dmi=dev->mc_list; dmi; dmi=dmi->next) ! 3496: printk(KERN_DEBUG " %02x:%02x:%02x:%02x:%02x:%02x\n", ! 3497: dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], ! 3498: dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5] ); ! 3499: #endif ! 3500: } ! 3501: ! 3502: /* ! 3503: * Overwrite the predecessor NOP link ! 3504: * so that it points to the configure action. ! 3505: */ ! 3506: nop_addr = txpred + sizeof(tx); ! 3507: nop.nop_h.ac_status = 0; ! 3508: obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_status), ! 3509: (unsigned char *)&nop.nop_h.ac_status, ! 3510: sizeof(nop.nop_h.ac_status)); ! 3511: nop.nop_h.ac_link = cfg_addr; ! 3512: obram_write(ioaddr, toff(ac_nop_t, nop_addr, nop_h.ac_link), ! 3513: (unsigned char *) &nop.nop_h.ac_link, ! 3514: sizeof(nop.nop_h.ac_link)); ! 3515: ! 3516: /* If watchdog not already active, activate it... */ ! 3517: if(lp->watchdog.prev == (timer_list *) NULL) ! 3518: { ! 3519: /* set timer to expire in WATCHDOG_JIFFIES */ ! 3520: lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; ! 3521: add_timer(&lp->watchdog); ! 3522: } ! 3523: ! 3524: lp->reconfig_82586 = 0; ! 3525: ! 3526: if(lp->tx_first_in_use == I82586NULL) ! 3527: lp->tx_first_in_use = txblock; ! 3528: ! 3529: if(lp->tx_n_in_use < NTXBLOCKS - 1) ! 3530: dev->tbusy = 0; ! 3531: ! 3532: wv_splx(x); ! 3533: ! 3534: #ifdef DEBUG_CONFIG_TRACE ! 3535: printk(KERN_DEBUG "%s: <-wv_82586_config()\n", dev->name); ! 3536: #endif ! 3537: } ! 3538: ! 3539: /*------------------------------------------------------------------*/ ! 3540: /* ! 3541: * This routine, called by wavelan_close(), gracefully stops the ! 3542: * WaveLAN controller (i82586). ! 3543: */ ! 3544: static inline void ! 3545: wv_82586_stop(device * dev) ! 3546: { ! 3547: net_local * lp = (net_local *) dev->priv; ! 3548: u_long ioaddr = dev->base_addr; ! 3549: u_short scb_cmd; ! 3550: ! 3551: #ifdef DEBUG_CONFIG_TRACE ! 3552: printk(KERN_DEBUG "%s: ->wv_82586_stop()\n", dev->name); ! 3553: #endif ! 3554: ! 3555: /* Suspend both command unit and receive unit. */ ! 3556: scb_cmd = (SCB_CMD_CUC & SCB_CMD_CUC_SUS) | (SCB_CMD_RUC & SCB_CMD_RUC_SUS); ! 3557: obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), ! 3558: (unsigned char *)&scb_cmd, sizeof(scb_cmd)); ! 3559: set_chan_attn(ioaddr, lp->hacr); ! 3560: ! 3561: /* No more interrupts */ ! 3562: wv_ints_off(dev); ! 3563: ! 3564: #ifdef DEBUG_CONFIG_TRACE ! 3565: printk(KERN_DEBUG "%s: <-wv_82586_stop()\n", dev->name); ! 3566: #endif ! 3567: } ! 3568: ! 3569: /*------------------------------------------------------------------*/ ! 3570: /* ! 3571: * Totally reset the WaveLAN and restart it. ! 3572: * Performs the following actions: ! 3573: * 1. A power reset (reset DMA) ! 3574: * 2. Initialize the radio modem (using wv_mmc_init) ! 3575: * 3. Reset & Configure LAN controller (using wv_82586_start) ! 3576: * 4. Start the LAN controller's command unit ! 3577: * 5. Start the LAN controller's receive unit ! 3578: */ ! 3579: static int ! 3580: wv_hw_reset(device * dev) ! 3581: { ! 3582: net_local * lp = (net_local *)dev->priv; ! 3583: u_long ioaddr = dev->base_addr; ! 3584: ! 3585: #ifdef DEBUG_CONFIG_TRACE ! 3586: printk(KERN_DEBUG "%s: ->wv_hw_reset(dev=0x%x)\n", dev->name, ! 3587: (unsigned int)dev); ! 3588: #endif ! 3589: ! 3590: /* If watchdog was activated, kill it! */ ! 3591: if(lp->watchdog.prev != (timer_list *) NULL) ! 3592: del_timer(&lp->watchdog); ! 3593: ! 3594: /* Increase the number of resets done */ ! 3595: lp->nresets++; ! 3596: ! 3597: wv_hacr_reset(ioaddr); ! 3598: lp->hacr = HACR_DEFAULT; ! 3599: ! 3600: if((wv_mmc_init(dev) < 0) || ! 3601: (wv_82586_start(dev) < 0)) ! 3602: return -1; ! 3603: ! 3604: /* Enable the card to send interrupts */ ! 3605: wv_ints_on(dev); ! 3606: ! 3607: /* Start card functions */ ! 3608: if((wv_ru_start(dev) < 0) || ! 3609: (wv_cu_start(dev) < 0)) ! 3610: return -1; ! 3611: ! 3612: /* Finish configuration */ ! 3613: wv_82586_config(dev); ! 3614: ! 3615: #ifdef DEBUG_CONFIG_TRACE ! 3616: printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name); ! 3617: #endif ! 3618: return 0; ! 3619: } ! 3620: ! 3621: /*------------------------------------------------------------------*/ ! 3622: /* ! 3623: * Check if there is a WaveLAN at the specific base address. ! 3624: * As a side effect, this reads the MAC address. ! 3625: * (called in wavelan_probe() and init_module()) ! 3626: */ ! 3627: static int ! 3628: wv_check_ioaddr(u_long ioaddr, ! 3629: u_char * mac) ! 3630: { ! 3631: int i; /* Loop counter */ ! 3632: ! 3633: /* Check if the base address if available */ ! 3634: if(check_region(ioaddr, sizeof(ha_t))) ! 3635: return EADDRINUSE; /* ioaddr already used... */ ! 3636: ! 3637: /* Reset host interface */ ! 3638: wv_hacr_reset(ioaddr); ! 3639: ! 3640: /* Read the MAC address from the parameter storage area */ ! 3641: psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_univ_mac_addr), ! 3642: mac, 6); ! 3643: ! 3644: /* ! 3645: * Check the first three octets of the address for the manufacturer's code. ! 3646: * Note: If this can't find your WaveLAN card, you've got a ! 3647: * non-NCR/AT&T/Lucent ISA card. See wavelan.p.h for details on ! 3648: * how to configure your card. ! 3649: */ ! 3650: for(i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++) ! 3651: if((mac[0] == MAC_ADDRESSES[i][0]) && ! 3652: (mac[1] == MAC_ADDRESSES[i][1]) && ! 3653: (mac[2] == MAC_ADDRESSES[i][2])) ! 3654: return 0; ! 3655: ! 3656: #ifdef DEBUG_CONFIG_INFO ! 3657: printk(KERN_WARNING "WaveLAN (0x%3X): your MAC address might be: %02X:%02X:%02X.\n", ! 3658: ioaddr, mac[0], mac[1], mac[2]); ! 3659: #endif ! 3660: return ENODEV; ! 3661: } ! 3662: ! 3663: /************************ INTERRUPT HANDLING ************************/ ! 3664: ! 3665: /* ! 3666: * This function is the interrupt handler for the WaveLAN card. This ! 3667: * routine will be called whenever: ! 3668: */ ! 3669: static void ! 3670: wavelan_interrupt(int irq, ! 3671: void * dev_id, ! 3672: struct pt_regs * regs) ! 3673: { ! 3674: device * dev; ! 3675: u_long ioaddr; ! 3676: net_local * lp; ! 3677: u_short hasr; ! 3678: u_short status; ! 3679: u_short ack_cmd; ! 3680: ! 3681: if((dev = (device *) (irq2dev_map[irq])) == (device *) NULL) ! 3682: { ! 3683: #ifdef DEBUG_INTERRUPT_ERROR ! 3684: printk(KERN_WARNING "wavelan_interrupt(): irq %d for unknown device.\n", ! 3685: irq); ! 3686: #endif ! 3687: return; ! 3688: } ! 3689: ! 3690: #ifdef DEBUG_INTERRUPT_TRACE ! 3691: printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name); ! 3692: #endif ! 3693: ! 3694: lp = (net_local *) dev->priv; ! 3695: ioaddr = dev->base_addr; ! 3696: ! 3697: /* Prevent reentrance. What should we do here? */ ! 3698: #ifdef DEBUG_INTERRUPT_ERROR ! 3699: if(dev->interrupt) ! 3700: printk(KERN_INFO "%s: wavelan_interrupt(): Re-entering the interrupt handler.\n", ! 3701: dev->name); ! 3702: #endif ! 3703: dev->interrupt = 1; ! 3704: ! 3705: if((hasr = hasr_read(ioaddr)) & HASR_MMC_INTR) ! 3706: { ! 3707: u_char dce_status; ! 3708: ! 3709: /* ! 3710: * Interrupt from the modem management controller. ! 3711: * This will clear it -- ignored for now. ! 3712: */ ! 3713: mmc_read(ioaddr, mmroff(0, mmr_dce_status), &dce_status, sizeof(dce_status)); ! 3714: #ifdef DEBUG_INTERRUPT_ERROR ! 3715: printk(KERN_INFO "%s: wavelan_interrupt(): unexpected mmc interrupt: status 0x%04x.\n", ! 3716: dev->name, dce_status); ! 3717: #endif ! 3718: } ! 3719: ! 3720: if((hasr & HASR_82586_INTR) == 0) ! 3721: { ! 3722: dev->interrupt = 0; ! 3723: #ifdef DEBUG_INTERRUPT_ERROR ! 3724: printk(KERN_INFO "%s: wavelan_interrupt(): interrupt not coming from i82586\n", ! 3725: dev->name); ! 3726: #endif ! 3727: return; ! 3728: } ! 3729: ! 3730: /* Read interrupt data. */ ! 3731: obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), ! 3732: (unsigned char *) &status, sizeof(status)); ! 3733: ! 3734: /* ! 3735: * Acknowledge the interrupt(s). ! 3736: */ ! 3737: ack_cmd = status & SCB_ST_INT; ! 3738: obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), ! 3739: (unsigned char *) &ack_cmd, sizeof(ack_cmd)); ! 3740: set_chan_attn(ioaddr, lp->hacr); ! 3741: ! 3742: #ifdef DEBUG_INTERRUPT_INFO ! 3743: printk(KERN_DEBUG "%s: wavelan_interrupt(): status 0x%04x.\n", ! 3744: dev->name, status); ! 3745: #endif ! 3746: ! 3747: /* Command completed. */ ! 3748: if((status & SCB_ST_CX) == SCB_ST_CX) ! 3749: { ! 3750: #ifdef DEBUG_INTERRUPT_INFO ! 3751: printk(KERN_DEBUG "%s: wavelan_interrupt(): command completed.\n", ! 3752: dev->name); ! 3753: #endif ! 3754: wv_complete(dev, ioaddr, lp); ! 3755: ! 3756: /* If watchdog was activated, kill it ! */ ! 3757: if(lp->watchdog.prev != (timer_list *) NULL) ! 3758: del_timer(&lp->watchdog); ! 3759: if(lp->tx_n_in_use > 0) ! 3760: { ! 3761: /* set timer to expire in WATCHDOG_JIFFIES */ ! 3762: lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; ! 3763: add_timer(&lp->watchdog); ! 3764: } ! 3765: } ! 3766: ! 3767: /* Frame received. */ ! 3768: if((status & SCB_ST_FR) == SCB_ST_FR) ! 3769: { ! 3770: #ifdef DEBUG_INTERRUPT_INFO ! 3771: printk(KERN_DEBUG "%s: wavelan_interrupt(): received packet.\n", ! 3772: dev->name); ! 3773: #endif ! 3774: wv_receive(dev); ! 3775: } ! 3776: ! 3777: /* Check the state of the command unit. */ ! 3778: if(((status & SCB_ST_CNA) == SCB_ST_CNA) || ! 3779: (((status & SCB_ST_CUS) != SCB_ST_CUS_ACTV) && dev->start)) ! 3780: { ! 3781: #ifdef DEBUG_INTERRUPT_ERROR ! 3782: printk(KERN_INFO "%s: wavelan_interrupt(): CU inactive -- restarting\n", ! 3783: dev->name); ! 3784: #endif ! 3785: wv_hw_reset(dev); ! 3786: } ! 3787: ! 3788: /* Check the state of the command unit. */ ! 3789: if(((status & SCB_ST_RNR) == SCB_ST_RNR) || ! 3790: (((status & SCB_ST_RUS) != SCB_ST_RUS_RDY) && dev->start)) ! 3791: { ! 3792: #ifdef DEBUG_INTERRUPT_ERROR ! 3793: printk(KERN_INFO "%s: wavelan_interrupt(): RU not ready -- restarting\n", ! 3794: dev->name); ! 3795: #endif ! 3796: wv_hw_reset(dev); ! 3797: } ! 3798: ! 3799: dev->interrupt = 0; ! 3800: ! 3801: #ifdef DEBUG_INTERRUPT_TRACE ! 3802: printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name); ! 3803: #endif ! 3804: } ! 3805: ! 3806: /*------------------------------------------------------------------*/ ! 3807: /* ! 3808: * Watchdog: when we start a transmission, we set a timer in the ! 3809: * kernel. If the transmission completes, this timer is disabled. If ! 3810: * the timer expires, we try to unlock the hardware. ! 3811: * ! 3812: * Note: this watchdog doesn't work on the same principle as the ! 3813: * watchdog in the previous version of the ISA driver. I made it this ! 3814: * way because the overhead of add_timer() and del_timer() is nothing ! 3815: * and because it avoids calling the watchdog, saving some CPU time. ! 3816: */ ! 3817: static void ! 3818: wavelan_watchdog(u_long a) ! 3819: { ! 3820: device * dev; ! 3821: net_local * lp; ! 3822: u_long ioaddr; ! 3823: unsigned long x; ! 3824: unsigned int nreaped; ! 3825: ! 3826: dev = (device *) a; ! 3827: ioaddr = dev->base_addr; ! 3828: lp = (net_local *) dev->priv; ! 3829: ! 3830: #ifdef DEBUG_INTERRUPT_TRACE ! 3831: printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name); ! 3832: #endif ! 3833: ! 3834: #ifdef DEBUG_INTERRUPT_ERROR ! 3835: printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n", ! 3836: dev->name); ! 3837: #endif ! 3838: ! 3839: x = wv_splhi(); ! 3840: ! 3841: dev = (device *) a; ! 3842: ioaddr = dev->base_addr; ! 3843: lp = (net_local *) dev->priv; ! 3844: ! 3845: if(lp->tx_n_in_use <= 0) ! 3846: { ! 3847: wv_splx(x); ! 3848: return; ! 3849: } ! 3850: ! 3851: nreaped = wv_complete(dev, ioaddr, lp); ! 3852: ! 3853: #ifdef DEBUG_INTERRUPT_INFO ! 3854: printk(KERN_DEBUG "%s: wavelan_watchdog(): %d reaped, %d remain.\n", ! 3855: dev->name, nreaped, lp->tx_n_in_use); ! 3856: #endif ! 3857: ! 3858: #ifdef DEBUG_PSA_SHOW ! 3859: { ! 3860: psa_t psa; ! 3861: psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); ! 3862: wv_psa_show(&psa); ! 3863: } ! 3864: #endif ! 3865: #ifdef DEBUG_MMC_SHOW ! 3866: wv_mmc_show(dev); ! 3867: #endif ! 3868: #ifdef DEBUG_I82586_SHOW ! 3869: wv_cu_show(dev); ! 3870: #endif ! 3871: ! 3872: /* If no buffer has been freed */ ! 3873: if(nreaped == 0) ! 3874: { ! 3875: #ifdef DEBUG_INTERRUPT_ERROR ! 3876: printk(KERN_INFO "%s: wavelan_watchdog(): cleanup failed, trying reset\n", ! 3877: dev->name); ! 3878: #endif ! 3879: wv_hw_reset(dev); ! 3880: } ! 3881: else ! 3882: /* Reset watchdog for next transmission. */ ! 3883: if(lp->tx_n_in_use > 0) ! 3884: { ! 3885: /* set timer to expire in WATCHDOG_JIFFIES */ ! 3886: lp->watchdog.expires = jiffies + WATCHDOG_JIFFIES; ! 3887: add_timer(&lp->watchdog); ! 3888: } ! 3889: ! 3890: wv_splx(x); ! 3891: ! 3892: #ifdef DEBUG_INTERRUPT_TRACE ! 3893: printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); ! 3894: #endif ! 3895: } ! 3896: ! 3897: /********************* CONFIGURATION CALLBACKS *********************/ ! 3898: /* ! 3899: * Here are the functions called by the Linux networking code (NET3) ! 3900: * for initialization, configuration and deinstallations of the ! 3901: * WaveLAN ISA hardware. ! 3902: */ ! 3903: ! 3904: /*------------------------------------------------------------------*/ ! 3905: /* ! 3906: * Configure and start up the WaveLAN PCMCIA adaptor. ! 3907: * Called by NET3 when it "open" the device. ! 3908: */ ! 3909: static int ! 3910: wavelan_open(device * dev) ! 3911: { ! 3912: u_long x; ! 3913: ! 3914: #ifdef DEBUG_CALLBACK_TRACE ! 3915: printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name, ! 3916: (unsigned int) dev); ! 3917: #endif ! 3918: ! 3919: /* Check irq */ ! 3920: if(dev->irq == 0) ! 3921: { ! 3922: #ifdef DEBUG_CONFIG_ERRORS ! 3923: printk(KERN_WARNING "%s: wavelan_open(): no IRQ\n", dev->name); ! 3924: #endif ! 3925: return -ENXIO; ! 3926: } ! 3927: ! 3928: if((irq2dev_map[dev->irq] != (device *) NULL) || ! 3929: /* This is always true, but avoid the false IRQ. */ ! 3930: ((irq2dev_map[dev->irq] = dev) == (device *) NULL) || ! 3931: (request_irq(dev->irq, &wavelan_interrupt, 0, "WaveLAN", NULL) != 0)) ! 3932: { ! 3933: irq2dev_map[dev->irq] = (device *) NULL; ! 3934: #ifdef DEBUG_CONFIG_ERRORS ! 3935: printk(KERN_WARNING "%s: wavelan_open(): invalid IRQ\n", dev->name); ! 3936: #endif ! 3937: return -EAGAIN; ! 3938: } ! 3939: ! 3940: x = wv_splhi(); ! 3941: if(wv_hw_reset(dev) != -1) ! 3942: { ! 3943: dev->interrupt = 0; ! 3944: dev->start = 1; ! 3945: } ! 3946: else ! 3947: { ! 3948: free_irq(dev->irq, NULL); ! 3949: irq2dev_map[dev->irq] = (device *) NULL; ! 3950: #ifdef DEBUG_CONFIG_ERRORS ! 3951: printk(KERN_INFO "%s: wavelan_open(): impossible to start the card\n", ! 3952: dev->name); ! 3953: #endif ! 3954: return -EAGAIN; ! 3955: } ! 3956: wv_splx(x); ! 3957: ! 3958: MOD_INC_USE_COUNT; ! 3959: ! 3960: #ifdef DEBUG_CALLBACK_TRACE ! 3961: printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); ! 3962: #endif ! 3963: return 0; ! 3964: } ! 3965: ! 3966: /*------------------------------------------------------------------*/ ! 3967: /* ! 3968: * Shut down the WaveLAN ISA card. ! 3969: * Called by NET3 when it "closes" the device. ! 3970: */ ! 3971: static int ! 3972: wavelan_close(device * dev) ! 3973: { ! 3974: net_local * lp = (net_local *)dev->priv; ! 3975: ! 3976: #ifdef DEBUG_CALLBACK_TRACE ! 3977: printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name, ! 3978: (unsigned int) dev); ! 3979: #endif ! 3980: ! 3981: /* Not do the job twice. */ ! 3982: if(dev->start == 0) ! 3983: return 0; ! 3984: ! 3985: dev->tbusy = 1; ! 3986: dev->start = 0; ! 3987: ! 3988: /* If watchdog was activated, kill it! */ ! 3989: if(lp->watchdog.prev != (timer_list *) NULL) ! 3990: del_timer(&lp->watchdog); ! 3991: ! 3992: /* ! 3993: * Flush the Tx and disable Rx. ! 3994: */ ! 3995: wv_82586_stop(dev); ! 3996: ! 3997: free_irq(dev->irq, NULL); ! 3998: irq2dev_map[dev->irq] = (device *) NULL; ! 3999: ! 4000: MOD_DEC_USE_COUNT; ! 4001: ! 4002: #ifdef DEBUG_CALLBACK_TRACE ! 4003: printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name); ! 4004: #endif ! 4005: return 0; ! 4006: } ! 4007: ! 4008: /*------------------------------------------------------------------*/ ! 4009: /* ! 4010: * Probe an I/O address, and if the WaveLAN is there configure the ! 4011: * device structure ! 4012: * (called by wavelan_probe() & via init_module()) ! 4013: */ ! 4014: static int ! 4015: wavelan_config(device * dev) ! 4016: { ! 4017: u_long ioaddr = dev->base_addr; ! 4018: u_char irq_mask; ! 4019: int irq; ! 4020: net_local * lp; ! 4021: ! 4022: #ifdef DEBUG_CALLBACK_TRACE ! 4023: printk(KERN_DEBUG "%s: ->wavelan_config(dev=0x%x, ioaddr=0x%x)\n", dev->name, ! 4024: (unsigned int)dev, ioaddr); ! 4025: #endif ! 4026: ! 4027: /* Check irq arg on command line */ ! 4028: if(dev->irq != 0) ! 4029: { ! 4030: irq_mask = wv_irq_to_psa(dev->irq); ! 4031: ! 4032: if(irq_mask == 0) ! 4033: { ! 4034: #ifdef DEBUG_CONFIG_ERROR ! 4035: printk(KERN_WARNING "%s: wavelan_config(): invalid irq %d -- ignored.\n", ! 4036: dev->name, dev->irq); ! 4037: #endif ! 4038: dev->irq = 0; ! 4039: } ! 4040: else ! 4041: { ! 4042: #ifdef DEBUG_CONFIG_INFO ! 4043: printk(KERN_DEBUG "%s: wavelan_config(): changing irq to %d\n", ! 4044: dev->name, dev->irq); ! 4045: #endif ! 4046: psa_write(ioaddr, HACR_DEFAULT, ! 4047: psaoff(0, psa_int_req_no), &irq_mask, 1); ! 4048: wv_hacr_reset(ioaddr); ! 4049: } ! 4050: } ! 4051: ! 4052: psa_read(ioaddr, HACR_DEFAULT, psaoff(0, psa_int_req_no), &irq_mask, 1); ! 4053: if((irq = wv_psa_to_irq(irq_mask)) == -1) ! 4054: { ! 4055: #ifdef DEBUG_CONFIG_ERROR ! 4056: printk(KERN_INFO "%s: wavelan_config(): could not wavelan_map_irq(%d).\n", ! 4057: dev->name, irq_mask); ! 4058: #endif ! 4059: return EAGAIN; ! 4060: } ! 4061: ! 4062: dev->irq = irq; ! 4063: ! 4064: request_region(ioaddr, sizeof(ha_t), "wavelan"); ! 4065: ! 4066: dev->mem_start = 0x0000; ! 4067: dev->mem_end = 0x0000; ! 4068: dev->if_port = 0; ! 4069: ! 4070: /* Initialize device structures */ ! 4071: dev->priv = kmalloc(sizeof(net_local), GFP_KERNEL); ! 4072: if(dev->priv == NULL) ! 4073: return -ENOMEM; ! 4074: memset(dev->priv, 0x00, sizeof(net_local)); ! 4075: lp = (net_local *)dev->priv; ! 4076: ! 4077: /* Back link to the device structure. */ ! 4078: lp->dev = dev; ! 4079: /* Add the device at the beginning of the linked list. */ ! 4080: lp->next = wavelan_list; ! 4081: wavelan_list = lp; ! 4082: ! 4083: lp->hacr = HACR_DEFAULT; ! 4084: ! 4085: lp->watchdog.function = wavelan_watchdog; ! 4086: lp->watchdog.data = (unsigned long) dev; ! 4087: lp->promiscuous = 0; ! 4088: lp->mc_count = 0; ! 4089: ! 4090: /* ! 4091: * Fill in the fields of the device structure ! 4092: * with Ethernet-generic values. ! 4093: */ ! 4094: ether_setup(dev); ! 4095: ! 4096: dev->open = wavelan_open; ! 4097: dev->stop = wavelan_close; ! 4098: dev->hard_start_xmit = wavelan_packet_xmit; ! 4099: dev->get_stats = wavelan_get_stats; ! 4100: dev->set_multicast_list = &wavelan_set_multicast_list; ! 4101: dev->set_mac_address = &wavelan_set_mac_address; ! 4102: ! 4103: #ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ ! 4104: dev->do_ioctl = wavelan_ioctl; ! 4105: dev->get_wireless_stats = wavelan_get_wireless_stats; ! 4106: #endif ! 4107: ! 4108: dev->mtu = WAVELAN_MTU; ! 4109: ! 4110: /* Display nice info */ ! 4111: wv_init_info(dev); ! 4112: ! 4113: #ifdef DEBUG_CALLBACK_TRACE ! 4114: printk(KERN_DEBUG "%s: <-wavelan_config()\n", dev->name); ! 4115: #endif ! 4116: return 0; ! 4117: } ! 4118: ! 4119: /*------------------------------------------------------------------*/ ! 4120: /* ! 4121: * Check for a network adaptor of this type. Return '0' iff one ! 4122: * exists. (There seem to be different interpretations of ! 4123: * the initial value of dev->base_addr. ! 4124: * We follow the example in drivers/net/ne.c.) ! 4125: * (called in "Space.c") ! 4126: * As this function is called outside the wavelan module, it should be ! 4127: * declared extern, but it seem to cause troubles... ! 4128: */ ! 4129: /* extern */ int ! 4130: wavelan_probe(device * dev) ! 4131: { ! 4132: short base_addr; ! 4133: mac_addr mac; /* MAC address (check WaveLAN existence) */ ! 4134: int i; ! 4135: int r; ! 4136: ! 4137: #ifdef DEBUG_CALLBACK_TRACE ! 4138: printk(KERN_DEBUG "%s: ->wavelan_probe(dev=0x%x (base_addr=0x%x))\n", ! 4139: dev->name, (unsigned int)dev, (unsigned int)dev->base_addr); ! 4140: #endif ! 4141: ! 4142: #ifdef STRUCT_CHECK ! 4143: if (wv_struct_check() != (char *) NULL) ! 4144: { ! 4145: printk(KERN_WARNING "%s: wavelan_probe(): structure/compiler botch: \"%s\"\n", ! 4146: dev->name, wv_struct_check()); ! 4147: return ENODEV; ! 4148: } ! 4149: #endif /* STRUCT_CHECK */ ! 4150: ! 4151: /* Check the value of the command line parameter for base address */ ! 4152: base_addr = dev->base_addr; ! 4153: ! 4154: /* Don't probe at all. */ ! 4155: if(base_addr < 0) ! 4156: { ! 4157: #ifdef DEBUG_CONFIG_ERRORS ! 4158: printk(KERN_WARNING "%s: wavelan_probe(): invalid base address\n", ! 4159: dev->name); ! 4160: #endif ! 4161: return ENXIO; ! 4162: } ! 4163: ! 4164: /* Check a single specified location. */ ! 4165: if(base_addr > 0x100) ! 4166: { ! 4167: /* Check if the is something at this base address */ ! 4168: if((r = wv_check_ioaddr(base_addr, mac)) == 0) ! 4169: { ! 4170: memcpy(dev->dev_addr, mac, 6); /* Copy MAC address */ ! 4171: r = wavelan_config(dev); ! 4172: } ! 4173: ! 4174: #ifdef DEBUG_CONFIG_INFO ! 4175: if(r != 0) ! 4176: printk(KERN_DEBUG "%s: wavelan_probe(): no device at specified base address (0x%X) or address already in use\n", ! 4177: dev->name, base_addr); ! 4178: #endif ! 4179: ! 4180: #ifdef DEBUG_CALLBACK_TRACE ! 4181: printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name); ! 4182: #endif ! 4183: return r; ! 4184: } ! 4185: ! 4186: /* Scan all possible addresses of the WaveLAN hardware */ ! 4187: for(i = 0; i < NELS(iobase); i++) ! 4188: { ! 4189: /* Check whether there is something at this base address */ ! 4190: if(wv_check_ioaddr(iobase[i], mac) == 0) ! 4191: { ! 4192: dev->base_addr = iobase[i]; /* Copy base address. */ ! 4193: memcpy(dev->dev_addr, mac, 6); /* Copy MAC address. */ ! 4194: if(wavelan_config(dev) == 0) ! 4195: { ! 4196: #ifdef DEBUG_CALLBACK_TRACE ! 4197: printk(KERN_DEBUG "%s: <-wavelan_probe()\n", dev->name); ! 4198: #endif ! 4199: return 0; ! 4200: } ! 4201: } ! 4202: } ! 4203: ! 4204: /* We may have touch base_addr: another driver may not like it. */ ! 4205: dev->base_addr = base_addr; ! 4206: ! 4207: #ifdef DEBUG_CONFIG_INFO ! 4208: printk(KERN_DEBUG "%s: wavelan_probe(): no device found\n", ! 4209: dev->name); ! 4210: #endif ! 4211: ! 4212: return ENODEV; ! 4213: } ! 4214: ! 4215: /****************************** MODULE ******************************/ ! 4216: /* ! 4217: * Module entry point: insertion & removal ! 4218: */ ! 4219: ! 4220: #ifdef MODULE ! 4221: /*------------------------------------------------------------------*/ ! 4222: /* ! 4223: * Insertion of the module. ! 4224: * I'm now quite proud of the multi-device support. ! 4225: */ ! 4226: int ! 4227: init_module(void) ! 4228: { ! 4229: mac_addr mac; /* MAC address (check WaveLAN existence) */ ! 4230: int ret = 0; ! 4231: int i; ! 4232: ! 4233: #ifdef DEBUG_MODULE_TRACE ! 4234: printk(KERN_DEBUG "-> init_module()\n"); ! 4235: #endif ! 4236: ! 4237: /* If probing is asked */ ! 4238: if(io[0] == 0) ! 4239: { ! 4240: #ifdef DEBUG_CONFIG_ERRORS ! 4241: printk(KERN_WARNING "WaveLAN init_module(): doing device probing (bad !)\n"); ! 4242: printk(KERN_WARNING "Specify base addresses while loading module to correct the problem\n"); ! 4243: #endif ! 4244: ! 4245: /* Copy the basic set of address to be probed. */ ! 4246: for(i = 0; i < NELS(iobase); i++) ! 4247: io[i] = iobase[i]; ! 4248: } ! 4249: ! 4250: ! 4251: /* Loop on all possible base addresses */ ! 4252: i = -1; ! 4253: while((io[++i] != 0) && (i < NELS(io))) ! 4254: { ! 4255: /* Check if there is something at this base address. */ ! 4256: if(wv_check_ioaddr(io[i], mac) == 0) ! 4257: { ! 4258: device * dev; ! 4259: ! 4260: /* Create device and set basics args */ ! 4261: dev = kmalloc(sizeof(struct device), GFP_KERNEL); ! 4262: memset(dev, 0x00, sizeof(struct device)); ! 4263: dev->name = name[i]; ! 4264: dev->base_addr = io[i]; ! 4265: dev->irq = irq[i]; ! 4266: dev->init = &wavelan_config; ! 4267: memcpy(dev->dev_addr, mac, 6); /* Copy MAC address */ ! 4268: ! 4269: /* Try to create the device */ ! 4270: if(register_netdev(dev) != 0) ! 4271: { ! 4272: /* DeAllocate everything */ ! 4273: /* Note : if dev->priv is mallocated, there is no way to fail */ ! 4274: kfree_s(dev, sizeof(struct device)); ! 4275: ret = -EIO; ! 4276: } ! 4277: } /* if there is something at the address */ ! 4278: } /* Loop on all addresses. */ ! 4279: ! 4280: #ifdef DEBUG_CONFIG_ERRORS ! 4281: if(wavelan_list == (net_local *) NULL) ! 4282: printk(KERN_WARNING "WaveLAN init_module(): no device found\n"); ! 4283: #endif ! 4284: ! 4285: #ifdef DEBUG_MODULE_TRACE ! 4286: printk(KERN_DEBUG "<- init_module()\n"); ! 4287: #endif ! 4288: return ret; ! 4289: } ! 4290: ! 4291: /*------------------------------------------------------------------*/ ! 4292: /* ! 4293: * Removal of the module ! 4294: */ ! 4295: void ! 4296: cleanup_module(void) ! 4297: { ! 4298: #ifdef DEBUG_MODULE_TRACE ! 4299: printk(KERN_DEBUG "-> cleanup_module()\n"); ! 4300: #endif ! 4301: ! 4302: /* Loop on all devices and release them. */ ! 4303: while(wavelan_list != (net_local *) NULL) ! 4304: { ! 4305: device * dev = wavelan_list->dev; ! 4306: ! 4307: #ifdef DEBUG_CONFIG_INFO ! 4308: printk(KERN_DEBUG "%s: cleanup_module(): removing device at 0x%x\n", ! 4309: dev->name, (unsigned int) dev); ! 4310: #endif ! 4311: ! 4312: /* Release the ioport-region. */ ! 4313: release_region(dev->base_addr, sizeof(ha_t)); ! 4314: ! 4315: /* Definitely remove the device. */ ! 4316: unregister_netdev(dev); ! 4317: ! 4318: /* Unlink the device. */ ! 4319: wavelan_list = wavelan_list->next; ! 4320: ! 4321: /* Free pieces. */ ! 4322: kfree_s(dev->priv, sizeof(struct net_local)); ! 4323: kfree_s(dev, sizeof(struct device)); ! 4324: } ! 4325: ! 4326: #ifdef DEBUG_MODULE_TRACE ! 4327: printk(KERN_DEBUG "<- cleanup_module()\n"); ! 4328: #endif ! 4329: } ! 4330: #endif /* MODULE */ ! 4331: ! 4332: /* ! 4333: * This software may only be used and distributed ! 4334: * according to the terms of the GNU Public License. ! 4335: * ! 4336: * This software was developed as a component of the ! 4337: * Linux operating system. ! 4338: * It is based on other device drivers and information ! 4339: * either written or supplied by: ! 4340: * Ajay Bakre ([email protected]), ! 4341: * Donald Becker ([email protected]), ! 4342: * Loeke Brederveld ([email protected]), ! 4343: * Anders Klemets ([email protected]), ! 4344: * Vladimir V. Kolpakov ([email protected]), ! 4345: * Marc Meertens ([email protected]), ! 4346: * Pauline Middelink ([email protected]), ! 4347: * Robert Morris ([email protected]), ! 4348: * Jean Tourrilhes ([email protected]), ! 4349: * Girish Welling ([email protected]), ! 4350: * ! 4351: * Thanks go also to: ! 4352: * James Ashton ([email protected]), ! 4353: * Alan Cox ([email protected]), ! 4354: * Allan Creighton ([email protected]), ! 4355: * Matthew Geier ([email protected]), ! 4356: * Remo di Giovanni ([email protected]), ! 4357: * Eckhard Grah ([email protected]), ! 4358: * Vipul Gupta ([email protected]), ! 4359: * Mark Hagan ([email protected]), ! 4360: * Tim Nicholson ([email protected]), ! 4361: * Ian Parkin ([email protected]), ! 4362: * John Rosenberg ([email protected]), ! 4363: * George Rossi ([email protected]), ! 4364: * Arthur Scott ([email protected]), ! 4365: * Peter Storey, ! 4366: * for their assistance and advice. ! 4367: * ! 4368: * Please send bug reports, updates, comments to: ! 4369: * ! 4370: * Bruce Janson Email: [email protected] ! 4371: * Basser Department of Computer Science Phone: +61-2-9351-3423 ! 4372: * University of Sydney, N.S.W., 2006, AUSTRALIA Fax: +61-2-9351-3838 ! 4373: */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.