📄 wavelan.c
字号:
/* * Read bytes from the Frequency EEPROM (frequency select cards). */static voidfee_read(u_long ioaddr, /* I/O port of the card */ u_short o, /* destination offset */ u_short * 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 voidfee_write(u_long ioaddr, /* I/O port of the card */ u_short o, /* destination offset */ u_short * 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)), mmc_in(ioaddr, mmroff(0, mmr_fee_data_l)));#endif /* DOESNT_SEEM_TO_WORK */ /* Enable protected register. */ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN); fee_wait(ioaddr, 10, 100); /* Unprotect area. */ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n); mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);#ifdef DOESNT_SEEM_TO_WORK /* disabled */ /* or use: */ mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR);#endif /* DOESNT_SEEM_TO_WORK */ fee_wait(ioaddr, 10, 100);#endif /* EEPROM_IS_PROTECTED */ /* Write enable. */ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN); mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN); fee_wait(ioaddr, 10, 100); /* Write the EEPROM address. */ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), o + n - 1); /* Loop on all buffer */ while(n-- > 0) { /* Write the value. */ mmc_out(ioaddr, mmwoff(0, mmw_fee_data_h), (*--b) >> 8); mmc_out(ioaddr, mmwoff(0, mmw_fee_data_l), *b & 0xFF); /* Write the write command. */ mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE); /* WaveLAN documentation says to wait at least 10 ms for EEBUSY = 0 */ mdelay(10); fee_wait(ioaddr, 10, 100); } /* Write disable. */ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS); mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS); fee_wait(ioaddr, 10, 100);#ifdef EEPROM_IS_PROTECTED /* disabled */ /* Reprotect EEPROM. */ mmc_out(ioaddr, mmwoff(0, mmw_fee_addr), 0x00); mmc_out(ioaddr, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE); fee_wait(ioaddr, 10, 100);#endif /* EEPROM_IS_PROTECTED */}#endif /* WIRELESS_EXT *//************************ I82586 SUBROUTINES *************************//* * Useful subroutines to manage the Ethernet controller *//*------------------------------------------------------------------*//* * Read bytes from the on-board RAM. * Why does inlining this function make it fail? */static /*inline*/ voidobram_read(u_long ioaddr, u_short o, u_char * b, int n){ outw(o, PIOR1(ioaddr)); insw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1);}/*------------------------------------------------------------------*//* * Write bytes to the on-board RAM. */static inline voidobram_write(u_long ioaddr, u_short o, u_char * b, int n){ outw(o, PIOR1(ioaddr)); outsw(PIOP1(ioaddr), (unsigned short *) b, (n + 1) >> 1);}/*------------------------------------------------------------------*//* * Acknowledge the reading of the status issued by the i82586. */static voidwv_ack(device * dev){ net_local * lp = (net_local *)dev->priv; u_long ioaddr = dev->base_addr; u_short scb_cs; int i; obram_read(ioaddr, scboff(OFFSET_SCB, scb_status), (unsigned char *) &scb_cs, sizeof(scb_cs)); scb_cs &= SCB_ST_INT; if(scb_cs == 0) return; obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *) &scb_cs, sizeof(scb_cs)); set_chan_attn(ioaddr, lp->hacr); for(i = 1000; i > 0; i--) { obram_read(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *)&scb_cs, sizeof(scb_cs)); if(scb_cs == 0) break; udelay(10); } udelay(100);#ifdef DEBUG_CONFIG_ERROR if(i <= 0) printk(KERN_INFO "%s: wv_ack(): board not accepting command.\n", dev->name);#endif}/*------------------------------------------------------------------*//* * Set channel attention bit and busy wait until command has * completed, then acknowledge completion of the command. */static inline intwv_synchronous_cmd(device * dev, const char * str){ net_local * lp = (net_local *)dev->priv; u_long ioaddr = dev->base_addr; u_short scb_cmd; ach_t cb; int i; scb_cmd = SCB_CMD_CUC & SCB_CMD_CUC_GO; obram_write(ioaddr, scboff(OFFSET_SCB, scb_command), (unsigned char *) &scb_cmd, sizeof(scb_cmd)); set_chan_attn(ioaddr, lp->hacr); for (i = 1000; i > 0; i--) { obram_read(ioaddr, OFFSET_CU, (unsigned char *)&cb, sizeof(cb)); if (cb.ac_status & AC_SFLD_C) break; udelay(10); } udelay(100); if(i <= 0 || !(cb.ac_status & AC_SFLD_OK)) {#ifdef DEBUG_CONFIG_ERROR printk(KERN_INFO "%s: %s failed; status = 0x%x\n", dev->name, str, cb.ac_status);#endif#ifdef DEBUG_I82586_SHOW wv_scb_show(ioaddr);#endif return -1; } /* Ack the status */ wv_ack(dev); return 0;}/*------------------------------------------------------------------*//* * Configuration commands completion interrupt. * Check if done, and if OK. */static inline intwv_config_complete(device * dev, u_long ioaddr, net_local * lp){ unsigned short mcs_addr; unsigned short status; int ret;#ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: ->wv_config_complete()\n", dev->name);#endif mcs_addr = lp->tx_first_in_use + sizeof(ac_tx_t) + sizeof(ac_nop_t) + sizeof(tbd_t) + sizeof(ac_cfg_t) + sizeof(ac_ias_t); /* Read the status of the last command (set mc list). */ obram_read(ioaddr, acoff(mcs_addr, ac_status), (unsigned char *)&status, sizeof(status)); /* If not completed -> exit */ if((status & AC_SFLD_C) == 0) ret = 0; /* Not ready to be scrapped */ else {#ifdef DEBUG_CONFIG_ERROR unsigned short cfg_addr; unsigned short ias_addr; /* Check mc_config command */ if((status & AC_SFLD_OK) != 0) printk(KERN_INFO "wv_config_complete(): set_multicast_address failed; status = 0x%x\n", dev->name, str, status); /* check ia-config command */ ias_addr = mcs_addr - sizeof(ac_ias_t); obram_read(ioaddr, acoff(ias_addr, ac_status), (unsigned char *)&status, sizeof(status)); if((status & AC_SFLD_OK) != 0) printk(KERN_INFO "wv_config_complete(): set_MAC_address; status = 0x%x\n", dev->name, str, status); /* Check config command. */ cfg_addr = ias_addr - sizeof(ac_cfg_t); obram_read(ioaddr, acoff(cfg_addr, ac_status), (unsigned char *)&status, sizeof(status)); if((status & AC_SFLD_OK) != 0) printk(KERN_INFO "wv_config_complete(): configure; status = 0x%x\n", dev->name, str, status);#endif /* DEBUG_CONFIG_ERROR */ ret = 1; /* Ready to be scrapped */ }#ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: <-wv_config_complete() - %d\n", dev->name, ret);#endif return ret;}/*------------------------------------------------------------------*//* * Command completion interrupt. * Reclaim as many freed tx buffers as we can. */static intwv_complete(device * dev, u_long ioaddr, net_local * lp){ int nreaped = 0;#ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: ->wv_complete()\n", dev->name);#endif /* Loop on all the transmit buffers */ while(lp->tx_first_in_use != I82586NULL) { unsigned short tx_status; /* Read the first transmit buffer */ obram_read(ioaddr, acoff(lp->tx_first_in_use, ac_status), (unsigned char *)&tx_status, sizeof(tx_status)); /* Hack for reconfiguration */ if(tx_status == 0xFFFF) if(!wv_config_complete(dev, ioaddr, lp)) break; /* Not completed */ /* If not completed -> exit */ if((tx_status & AC_SFLD_C) == 0) break; /* We now remove this buffer */ nreaped++; --lp->tx_n_in_use;/*if (lp->tx_n_in_use > 0) printk("%c", "0123456789abcdefghijk"[lp->tx_n_in_use]);*/ /* Was it the last one? */ if(lp->tx_n_in_use <= 0) lp->tx_first_in_use = I82586NULL; else { /* Next one in the chain */ lp->tx_first_in_use += TXBLOCKZ; if(lp->tx_first_in_use >= OFFSET_CU + NTXBLOCKS * TXBLOCKZ) lp->tx_first_in_use -= NTXBLOCKS * TXBLOCKZ; } /* Hack for reconfiguration */ if(tx_status == 0xFFFF) continue; /* Now, check status of the finished command */ if(tx_status & AC_SFLD_OK) { int ncollisions; lp->stats.tx_packets++; ncollisions = tx_status & AC_SFLD_MAXCOL; lp->stats.collisions += ncollisions;#ifdef DEBUG_INTERRUPT_INFO if(ncollisions > 0) printk(KERN_DEBUG "%s: wv_complete(): tx completed after %d collisions.\n", dev->name, ncollisions);#endif } else { lp->stats.tx_errors++;#ifndef IGNORE_NORMAL_XMIT_ERRS if(tx_status & AC_SFLD_S10) { lp->stats.tx_carrier_errors++;#ifdef DEBUG_INTERRUPT_ERROR printk(KERN_INFO "%s: wv_complete(): tx error: no CS.\n", dev->name);#endif }#endif /* IGNORE_NORMAL_XMIT_ERRS */ if(tx_status & AC_SFLD_S9) { lp->stats.tx_carrier_errors++;#ifdef DEBUG_INTERRUPT_ERROR printk(KERN_INFO "%s: wv_complete(): tx error: lost CTS.\n", dev->name);#endif } if(tx_status & AC_SFLD_S8) { lp->stats.tx_fifo_errors++;#ifdef DEBUG_INTERRUPT_ERROR printk(KERN_INFO "%s: wv_complete(): tx error: slow DMA.\n", dev->name);#endif }#ifndef IGNORE_NORMAL_XMIT_ERRS if(tx_status & AC_SFLD_S6) { lp->stats.tx_heartbeat_errors++;#ifdef DEBUG_INTERRUPT_ERROR printk(KERN_INFO "%s: wv_complete(): tx error: heart beat.\n", dev->name);#endif } if(tx_status & AC_SFLD_S5) { lp->stats.tx_aborted_errors++;#ifdef DEBUG_INTERRUPT_ERROR printk(KERN_INFO "%s: wv_complete(): tx error: too many collisions.\n", dev->name);#endif }#endif /* IGNORE_NORMAL_XMIT_ERRS */ }#ifdef DEBUG_INTERRUPT_INFO printk(KERN_DEBUG "%s: wv_complete(): tx completed, tx_status 0x%04x\n", dev->name, tx_status);#endif }#ifdef DEBUG_INTERRUPT_INFO if(nreaped > 1) printk(KERN_DEBUG "%s: wv_complete(): reaped %d\n", dev->name, nreaped);#endif /* * Inform upper layers. */ if(lp->tx_n_in_use < NTXBLOCKS - 1) { dev->tbusy = 0; mark_bh(NET_BH); }#ifdef DEBUG_INTERRUPT_TRACE printk(KERN_DEBUG "%s: <-wv_complete()\n", dev->name);#endif return nreaped;}/*------------------------------------------------------------------*//* * Reconfigure the i82586, or at least ask for it. * Because wv_82586_config uses a transmission buffer, we must do it * when we are sure that there is one left, so we do it now * or in wavelan_packet_xmit() (I can't find any better place, * wavelan_interrupt is not an option), so you may experience * delays sometimes. */static inline voidwv_82586_reconfig(device * dev){ net_local * lp = (net_local *)dev->priv; /* Check if we can do it now ! */ if(!(dev->start) || (test_and_set_bit(0, (void *)&dev->tbusy) != 0)) { lp->reconfig_82586 = 1;#ifdef DEBUG_CONFIG_INFO printk(KERN_DEBUG "%s: wv_82586_reconfig(): delayed (busy = %ld, start = %d)\n", dev->name, dev->tbusy, dev->start);#endif } else wv_82586_config(dev);}/********************* DEBUG & INFO SUBROUTINES *********************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -