📄 wavelan.c
字号:
/* * WaveLAN ISA driver * * Jean II - HPLB '96 * * Reorganisation and extension of the driver. * Original copyright follows (also see the end of this file). * See wavelan.p.h for details. *//* * AT&T GIS (nee NCR) WaveLAN card: * An Ethernet-like radio transceiver * controlled by an Intel 82586 coprocessor. */#include "wavelan.p.h" /* Private header *//************************* MISC SUBROUTINES **************************//* * Subroutines which won't fit in one of the following category * (WaveLAN modem or i82586) *//*------------------------------------------------------------------*//* * Wrapper for disabling interrupts. */static inline unsigned longwv_splhi(void){ unsigned long flags; save_flags(flags); cli(); return(flags);}/*------------------------------------------------------------------*//* * Wrapper for re-enabling interrupts. */static inline voidwv_splx(unsigned long flags){ restore_flags(flags);}/*------------------------------------------------------------------*//* * Translate irq number to PSA irq parameter */static u_charwv_irq_to_psa(int irq){ if(irq < 0 || irq >= NELS(irqvals)) return 0; return irqvals[irq];}/*------------------------------------------------------------------*//* * Translate PSA irq parameter to irq number */__initfunc(static intwv_psa_to_irq(u_char irqval)){ int irq; for(irq = 0; irq < NELS(irqvals); irq++) if(irqvals[irq] == irqval) return irq; return -1;}#ifdef STRUCT_CHECK/*------------------------------------------------------------------*//* * Sanity routine to verify the sizes of the various WaveLAN interface * structures. */static char *wv_struct_check(void){#define SC(t,s,n) if (sizeof(t) != s) return(n); SC(psa_t, PSA_SIZE, "psa_t"); SC(mmw_t, MMW_SIZE, "mmw_t"); SC(mmr_t, MMR_SIZE, "mmr_t"); SC(ha_t, HA_SIZE, "ha_t");#undef SC return((char *) NULL);} /* wv_struct_check */#endif /* STRUCT_CHECK *//********************* HOST ADAPTER SUBROUTINES *********************//* * Useful subroutines to manage the WaveLAN ISA interface * * One major difference with the PCMCIA hardware (except the port mapping) * is that we have to keep the state of the Host Control Register * because of the interrupt enable & bus size flags. *//*------------------------------------------------------------------*//* * Read from card's Host Adaptor Status Register. */static inline u_shorthasr_read(u_long ioaddr){ return(inw(HASR(ioaddr)));} /* hasr_read *//*------------------------------------------------------------------*//* * Write to card's Host Adapter Command Register. */static inline voidhacr_write(u_long ioaddr, u_short hacr){ outw(hacr, HACR(ioaddr));} /* hacr_write *//*------------------------------------------------------------------*//* * Write to card's Host Adapter Command Register. Include a delay for * those times when it is needed. */static inline voidhacr_write_slow(u_long ioaddr, u_short hacr){ hacr_write(ioaddr, hacr); /* delay might only be needed sometimes */ mdelay(1);} /* hacr_write_slow *//*------------------------------------------------------------------*//* * Set the channel attention bit. */static inline voidset_chan_attn(u_long ioaddr, u_short hacr){ hacr_write(ioaddr, hacr | HACR_CA);} /* set_chan_attn *//*------------------------------------------------------------------*//* * Reset, and then set host adaptor into default mode. */static inline voidwv_hacr_reset(u_long ioaddr){ hacr_write_slow(ioaddr, HACR_RESET); hacr_write(ioaddr, HACR_DEFAULT);} /* wv_hacr_reset *//*------------------------------------------------------------------*//* * Set the I/O transfer over the ISA bus to 8-bit mode */static inline voidwv_16_off(u_long ioaddr, u_short hacr){ hacr &= ~HACR_16BITS; hacr_write(ioaddr, hacr);} /* wv_16_off *//*------------------------------------------------------------------*//* * Set the I/O transfer over the ISA bus to 8-bit mode */static inline voidwv_16_on(u_long ioaddr, u_short hacr){ hacr |= HACR_16BITS; hacr_write(ioaddr, hacr);} /* wv_16_on *//*------------------------------------------------------------------*//* * Disable interrupts on the WaveLAN hardware. */static inline voidwv_ints_off(device * dev){ net_local * lp = (net_local *)dev->priv; u_long ioaddr = dev->base_addr; u_long x; x = wv_splhi(); lp->hacr &= ~HACR_INTRON; hacr_write(ioaddr, lp->hacr); wv_splx(x);} /* wv_ints_off *//*------------------------------------------------------------------*//* * Enable interrupts on the WaveLAN hardware. */static inline voidwv_ints_on(device * dev){ net_local * lp = (net_local *)dev->priv; u_long ioaddr = dev->base_addr; u_long x; x = wv_splhi(); lp->hacr |= HACR_INTRON; hacr_write(ioaddr, lp->hacr); wv_splx(x);} /* wv_ints_on *//******************* MODEM MANAGEMENT SUBROUTINES *******************//* * Useful subroutines to manage the modem of the WaveLAN *//*------------------------------------------------------------------*//* * Read the Parameter Storage Area from the WaveLAN card's memory *//* * Read bytes from the PSA. */static voidpsa_read(u_long ioaddr, u_short hacr, int o, /* offset in PSA */ u_char * b, /* buffer to fill */ int n) /* size to read */{ wv_16_off(ioaddr, hacr); while(n-- > 0) { outw(o, PIOR2(ioaddr)); o++; *b++ = inb(PIOP2(ioaddr)); } wv_16_on(ioaddr, hacr);} /* psa_read *//*------------------------------------------------------------------*//* * Write the Parameter Storage Area to the WaveLAN card's memory. */static voidpsa_write(u_long ioaddr, u_short hacr, int o, /* Offset in PSA */ u_char * b, /* Buffer in memory */ int n) /* Length of buffer */{ int count = 0; wv_16_off(ioaddr, hacr); while(n-- > 0) { outw(o, PIOR2(ioaddr)); o++; outb(*b, PIOP2(ioaddr)); b++; /* Wait for the memory to finish its write cycle */ count = 0; while((count++ < 100) && (hasr_read(ioaddr) & HASR_PSA_BUSY)) mdelay(1); } wv_16_on(ioaddr, hacr);} /* psa_write */#ifdef SET_PSA_CRC/*------------------------------------------------------------------*//* * Calculate the PSA CRC * Thanks to Valster, Nico <NVALSTER@wcnd.nl.lucent.com> for the code * NOTE: By specifying a length including the CRC position the * returned value should be zero. (i.e. a correct checksum in the PSA) * * The Windows drivers don't use the CRC, but the AP and the PtP tool * depend on it. */static inline u_shortpsa_crc(u_char * psa, /* The PSA */ int size) /* Number of short for CRC */{ int byte_cnt; /* Loop on the PSA */ u_short crc_bytes = 0; /* Data in the PSA */ int bit_cnt; /* Loop on the bits of the short */ for(byte_cnt = 0; byte_cnt < size; byte_cnt++ ) { crc_bytes ^= psa[byte_cnt]; /* Its an xor */ for(bit_cnt = 1; bit_cnt < 9; bit_cnt++ ) { if(crc_bytes & 0x0001) crc_bytes = (crc_bytes >> 1) ^ 0xA001; else crc_bytes >>= 1 ; } } return crc_bytes;} /* psa_crc *//*------------------------------------------------------------------*//* * update the checksum field in the Wavelan's PSA */static voidupdate_psa_checksum(device * dev, u_long ioaddr, u_short hacr){ psa_t psa; u_short crc; /* read the parameter storage area */ psa_read(ioaddr, hacr, 0, (unsigned char *) &psa, sizeof(psa)); /* update the checksum */ crc = psa_crc((unsigned char *) &psa, sizeof(psa) - sizeof(psa.psa_crc[0]) - sizeof(psa.psa_crc[1]) - sizeof(psa.psa_crc_status)); psa.psa_crc[0] = crc & 0xFF; psa.psa_crc[1] = (crc & 0xFF00) >> 8; /* Write it ! */ psa_write(ioaddr, hacr, (char *)&psa.psa_crc - (char *)&psa, (unsigned char *)&psa.psa_crc, 2);#ifdef DEBUG_IOCTL_INFO printk (KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n", dev->name, psa.psa_crc[0], psa.psa_crc[1]); /* Check again (luxury !) */ crc = psa_crc ((unsigned char *) &psa, sizeof(psa) - sizeof(psa.psa_crc_status)); if(crc != 0) printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name);#endif /* DEBUG_IOCTL_INFO */} /* update_psa_checksum */#endif /* SET_PSA_CRC *//*------------------------------------------------------------------*//* * Write 1 byte to the MMC. */static inline voidmmc_out(u_long ioaddr, u_short o, u_char d){ /* Wait for MMC to go idle */ while(inw(HASR(ioaddr)) & HASR_MMC_BUSY) ; outw((u_short) (((u_short) d << 8) | (o << 1) | 1), MMCR(ioaddr));}/*------------------------------------------------------------------*//* * Routine to write bytes to the Modem Management Controller. * We start at the end because it is the way it should be! */static inline voidmmc_write(u_long ioaddr, u_char o, u_char * b, int n){ o += n; b += n; while(n-- > 0 ) mmc_out(ioaddr, --o, *(--b));} /* mmc_write *//*------------------------------------------------------------------*//* * Read a byte from the MMC. * Optimised version for 1 byte, avoid using memory. */static inline u_charmmc_in(u_long ioaddr, u_short o){ while(inw(HASR(ioaddr)) & HASR_MMC_BUSY) ; outw(o << 1, MMCR(ioaddr)); while(inw(HASR(ioaddr)) & HASR_MMC_BUSY) ; return (u_char) (inw(MMCR(ioaddr)) >> 8);}/*------------------------------------------------------------------*//* * Routine to read bytes from the Modem Management Controller. * The implementation is complicated by a lack of address lines, * which prevents decoding of the low-order bit. * (code has just been moved in the above function) * We start at the end because it is the way it should be! */static inline voidmmc_read(u_long ioaddr, u_char o, u_char * b, int n){ o += n; b += n; while(n-- > 0) *(--b) = mmc_in(ioaddr, --o);} /* mmc_read *//*------------------------------------------------------------------*//* * Get the type of encryption available. */static inline intmmc_encr(u_long ioaddr) /* I/O port of the card */{ int temp; temp = mmc_in(ioaddr, mmroff(0, mmr_des_avail)); if((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES)) return 0; else return temp;}/*------------------------------------------------------------------*//* * Wait for the frequency EEPROM to complete a command. * I hope this one will be optimally inlined. */static inline voidfee_wait(u_long ioaddr, /* I/O port of the card */ int delay, /* Base delay to wait for */ int number) /* Number of time to wait */{ int count = 0; /* Wait only a limited time */ while((count++ < number) && (mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & MMR_FEE_STATUS_BUSY)) udelay(delay);}/*------------------------------------------------------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -