📄 wavelan.c
字号:
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 doc says : wait at least 10 ms for EEBUSY = 0 */ udelay(10000); 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 *************************//* * Usefull subroutines to manage the Ethernet controler *//*------------------------------------------------------------------*//* * Read bytes from the on-board RAM. * Why 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 the command completion. */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 use 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 * some delay sometime... */static inline voidwv_82586_reconfig(device * dev){ net_local * lp = (net_local *)dev->priv; /* Check if we can do it now ! */ if(!(dev->start) || (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 *********************//* * This routines are used in the code to show debug informations. * Most of the time, it dump the content of hardware structures... */#ifdef DEBUG_PSA_SHOW/*------------------------------------------------------------------*//* * Print the formatted contents of the Parameter Storage Area. */static voidwv_psa_show(psa_t * p){ printk(KERN_DEBUG "##### WaveLAN psa contents: #####\n"); printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", p->psa_io_base_addr_1, p->psa_io_base_addr_2, p->psa_io_base_addr_3, p->psa_io_base_addr_4); printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n", p->psa_rem_boot_addr_1, p->psa_rem_boot_addr_2, p->psa_rem_boot_addr_3); printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); printk("psa_int_req_no: %d\n", p->psa_int_req_no);#ifdef DEBUG_SHOW_UNUSED printk(KERN_DEBUG "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n", p->psa_unused0[0], p->psa_unused0[1], p->psa_unused0[2], p->psa_unused0[3], p->psa_unused0[4], p->psa_unused0[5], p->psa_unused0[6]);#endif /* DEBUG_SHOW_UNUSED */ printk(KERN_DEBUG "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n", p->psa_univ_mac_addr[0], p->psa_univ_mac_addr[1], p->psa_univ_mac_addr[2], p->psa_univ_mac_addr[3],
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -