📄 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) *//*------------------------------------------------------------------*//* * Translate irq number to PSA irq parameter */static u8 wv_irq_to_psa(int irq){ if (irq < 0 || irq >= NELS(irqvals)) return 0; return irqvals[irq];}/*------------------------------------------------------------------*//* * Translate PSA irq parameter to irq number */static int __init wv_psa_to_irq(u8 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 u16 hasr_read(unsigned long ioaddr){ return (inw(HASR(ioaddr)));} /* hasr_read *//*------------------------------------------------------------------*//* * Write to card's Host Adapter Command Register. */static inline void hacr_write(unsigned long ioaddr, u16 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 void hacr_write_slow(unsigned long ioaddr, u16 hacr){ hacr_write(ioaddr, hacr); /* delay might only be needed sometimes */ mdelay(1);} /* hacr_write_slow *//*------------------------------------------------------------------*//* * Set the channel attention bit. */static inline void set_chan_attn(unsigned long ioaddr, u16 hacr){ hacr_write(ioaddr, hacr | HACR_CA);} /* set_chan_attn *//*------------------------------------------------------------------*//* * Reset, and then set host adaptor into default mode. */static inline void wv_hacr_reset(unsigned 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 void wv_16_off(unsigned long ioaddr, u16 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 void wv_16_on(unsigned long ioaddr, u16 hacr){ hacr |= HACR_16BITS; hacr_write(ioaddr, hacr);} /* wv_16_on *//*------------------------------------------------------------------*//* * Disable interrupts on the WaveLAN hardware. * (called by wv_82586_stop()) */static inline void wv_ints_off(struct net_device * dev){ net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; lp->hacr &= ~HACR_INTRON; hacr_write(ioaddr, lp->hacr);} /* wv_ints_off *//*------------------------------------------------------------------*//* * Enable interrupts on the WaveLAN hardware. * (called by wv_hw_reset()) */static inline void wv_ints_on(struct net_device * dev){ net_local *lp = (net_local *) dev->priv; unsigned long ioaddr = dev->base_addr; lp->hacr |= HACR_INTRON; hacr_write(ioaddr, lp->hacr);} /* 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 void psa_read(unsigned long ioaddr, u16 hacr, int o, /* offset in PSA */ u8 * 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 void psa_write(unsigned long ioaddr, u16 hacr, int o, /* Offset in PSA */ u8 * 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 u16 psa_crc(u8 * psa, /* The PSA */ int size){ /* Number of short for CRC */ int byte_cnt; /* Loop on the PSA */ u16 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 */#endif /* SET_PSA_CRC *//*------------------------------------------------------------------*//* * update the checksum field in the Wavelan's PSA */static void update_psa_checksum(struct net_device * dev, unsigned long ioaddr, u16 hacr){#ifdef SET_PSA_CRC psa_t psa; u16 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 */#endif /* SET_PSA_CRC */} /* update_psa_checksum *//*------------------------------------------------------------------*//* * Write 1 byte to the MMC. */static inline void mmc_out(unsigned long ioaddr, u16 o, u8 d){ int count = 0; /* Wait for MMC to go idle */ while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY)) udelay(10); outw((u16) (((u16) 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 void mmc_write(unsigned long ioaddr, u8 o, u8 * 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 u8 mmc_in(unsigned long ioaddr, u16 o){ int count = 0; while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY)) udelay(10); outw(o << 1, MMCR(ioaddr)); while ((count++ < 100) && (inw(HASR(ioaddr)) & HASR_MMC_BUSY)) udelay(10); return (u8) (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 void mmc_read(unsigned long ioaddr, u8 o, u8 * 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 int mmc_encr(unsigned 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 void fee_wait(unsigned 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);}/*------------------------------------------------------------------*//* * Read bytes from the Frequency EEPROM (frequency select cards). */static void fee_read(unsigned long ioaddr, /* I/O port of the card */ u16 o, /* destination offset */ u16 * b, /* data buffer */ int n){ /* number of registers */ b += n; /* Position at the end of the area */ /* Write the address */ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1); /* Loop on all buffer */ while (n-- > 0) { /* Write the read command */ mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ); /* Wait until EEPROM is ready (should be quick). */ fee_wait(ioaddr, 10, 100); /* Read the value. */ *--b = ((mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)) << 8) | mmc_in(ioaddr, mmroff(0, mmr_fee_data_l))); }}#ifdef WIRELESS_EXT /* if the wireless extension exists in the kernel *//*------------------------------------------------------------------*//* * Write bytes from the Frequency EEPROM (frequency select cards). * This is a bit complicated, because the frequency EEPROM has to * be unprotected and the write enabled. * Jean II */static void fee_write(unsigned long ioaddr, /* I/O port of the card */ u16 o, /* destination offset */ u16 * b, /* data buffer */ int n){ /* number of registers */ b += n; /* Position at the end of the area. */#ifdef EEPROM_IS_PROTECTED /* disabled */#ifdef DOESNT_SEEM_TO_WORK /* disabled */ /* Ask to read the protected register */ mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD); fee_wait(ioaddr, 10, 100); /* Read the protected register. */ printk("Protected 2: %02X-%02X\n", mmc_in(ioaddr, mmroff(0, mmr_fee_data_h)),
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -