📄 3c523.c
字号:
elmc_attn586(); /* ack inter. */ if (stat & STAT_CX) { /* command with I-bit set complete */ elmc_xmt_int(dev); } if (stat & STAT_FR) { /* received a frame */ elmc_rcv_int(dev); }#ifndef NO_NOPCOMMANDS if (stat & STAT_CNA) { /* CU went 'not ready' */ if (netif_running(dev)) { printk(KERN_WARNING "%s: oops! CU has left active state. stat: %04x/%04x.\n", dev->name, (int) stat, (int) p->scb->status); } }#endif if (stat & STAT_RNR) { /* RU went 'not ready' */ if (p->scb->status & RU_SUSPEND) { /* special case: RU_SUSPEND */ WAIT_4_SCB_CMD(); p->scb->cmd = RUC_RESUME; elmc_attn586(); } else { printk(KERN_WARNING "%s: Receiver-Unit went 'NOT READY': %04x/%04x.\n", dev->name, (int) stat, (int) p->scb->status); elmc_rnr_int(dev); } } WAIT_4_SCB_CMD(); /* wait for ack. (elmc_xmt_int can be faster than ack!!) */ if (p->scb->cmd) { /* timed out? */ break; } }}/******************************************************* * receive-interrupt */static void elmc_rcv_int(struct net_device *dev){ int status; unsigned short totlen; struct sk_buff *skb; struct rbd_struct *rbd; struct priv *p = (struct priv *) dev->priv; for (; (status = p->rfd_top->status) & STAT_COMPL;) { rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset); if (status & STAT_OK) { /* frame received without error? */ if ((totlen = rbd->status) & RBD_LAST) { /* the first and the last buffer? */ totlen &= RBD_MASK; /* length of this frame */ rbd->status = 0; skb = (struct sk_buff *) dev_alloc_skb(totlen + 2); if (skb != NULL) { skb->dev = dev; skb_reserve(skb, 2); /* 16 byte alignment */ skb_put(skb,totlen); eth_copy_and_sum(skb, (char *) p->base+(unsigned long) rbd->buffer,totlen,0); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; p->stats.rx_packets++; p->stats.rx_bytes += totlen; } else { p->stats.rx_dropped++; } } else { printk(KERN_WARNING "%s: received oversized frame.\n", dev->name); p->stats.rx_dropped++; } } else { /* frame !(ok), only with 'save-bad-frames' */ printk(KERN_WARNING "%s: oops! rfd-error-status: %04x\n", dev->name, status); p->stats.rx_errors++; } p->rfd_top->status = 0; p->rfd_top->last = RFD_SUSP; p->rfd_last->last = 0; /* delete RU_SUSP */ p->rfd_last = p->rfd_top; p->rfd_top = (struct rfd_struct *) make32(p->rfd_top->next); /* step to next RFD */ }}/********************************************************** * handle 'Receiver went not ready'. */static void elmc_rnr_int(struct net_device *dev){ struct priv *p = (struct priv *) dev->priv; p->stats.rx_errors++; WAIT_4_SCB_CMD(); /* wait for the last cmd */ p->scb->cmd = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */ elmc_attn586(); WAIT_4_SCB_CMD(); /* wait for accept cmd. */ alloc_rfa(dev, (char *) p->rfd_first); startrecv586(dev); /* restart RU */ printk(KERN_WARNING "%s: Receive-Unit restarted. Status: %04x\n", dev->name, p->scb->status);}/********************************************************** * handle xmit - interrupt */static void elmc_xmt_int(struct net_device *dev){ int status; struct priv *p = (struct priv *) dev->priv; status = p->xmit_cmds[p->xmit_last]->cmd_status; if (!(status & STAT_COMPL)) { printk(KERN_WARNING "%s: strange .. xmit-int without a 'COMPLETE'\n", dev->name); } if (status & STAT_OK) { p->stats.tx_packets++; p->stats.collisions += (status & TCMD_MAXCOLLMASK); } else { p->stats.tx_errors++; if (status & TCMD_LATECOLL) { printk(KERN_WARNING "%s: late collision detected.\n", dev->name); p->stats.collisions++; } else if (status & TCMD_NOCARRIER) { p->stats.tx_carrier_errors++; printk(KERN_WARNING "%s: no carrier detected.\n", dev->name); } else if (status & TCMD_LOSTCTS) { printk(KERN_WARNING "%s: loss of CTS detected.\n", dev->name); } else if (status & TCMD_UNDERRUN) { p->stats.tx_fifo_errors++; printk(KERN_WARNING "%s: DMA underrun detected.\n", dev->name); } else if (status & TCMD_MAXCOLL) { printk(KERN_WARNING "%s: Max. collisions exceeded.\n", dev->name); p->stats.collisions += 16; } }#if (NUM_XMIT_BUFFS != 1) if ((++p->xmit_last) == NUM_XMIT_BUFFS) { p->xmit_last = 0; }#endif netif_wake_queue(dev);}/*********************************************************** * (re)start the receiver */static void startrecv586(struct net_device *dev){ struct priv *p = (struct priv *) dev->priv; p->scb->rfa_offset = make16(p->rfd_first); p->scb->cmd = RUC_START; elmc_attn586(); /* start cmd. */ WAIT_4_SCB_CMD(); /* wait for accept cmd. (no timeout!!) */}/****************************************************** * timeout */ static void elmc_timeout(struct net_device *dev){ struct priv *p = (struct priv *) dev->priv; /* COMMAND-UNIT active? */ if (p->scb->status & CU_ACTIVE) {#ifdef DEBUG printk("%s: strange ... timeout with CU active?!?\n", dev->name); printk("%s: X0: %04x N0: %04x N1: %04x %d\n", dev->name, (int) p->xmit_cmds[0]->cmd_status, (int) p->nop_cmds[0]->cmd_status, (int) p->nop_cmds[1]->cmd_status, (int) p->nop_point);#endif p->scb->cmd = CUC_ABORT; elmc_attn586(); WAIT_4_SCB_CMD(); p->scb->cbl_offset = make16(p->nop_cmds[p->nop_point]); p->scb->cmd = CUC_START; elmc_attn586(); WAIT_4_SCB_CMD(); netif_wake_queue(dev); } else {#ifdef DEBUG printk("%s: xmitter timed out, try to restart! stat: %04x\n", dev->name, p->scb->status); printk("%s: command-stats: %04x %04x\n", dev->name, p->xmit_cmds[0]->cmd_status, p->xmit_cmds[1]->cmd_status);#endif elmc_close(dev); elmc_open(dev); }} /****************************************************** * send frame */static int elmc_send_packet(struct sk_buff *skb, struct net_device *dev){ int len; int i;#ifndef NO_NOPCOMMANDS int next_nop;#endif struct priv *p = (struct priv *) dev->priv; netif_stop_queue(dev); memcpy((char *) p->xmit_cbuffs[p->xmit_count], (char *) (skb->data), skb->len); len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;#if (NUM_XMIT_BUFFS == 1)#ifdef NO_NOPCOMMANDS p->xmit_buffs[0]->size = TBD_LAST | len; for (i = 0; i < 16; i++) { p->scb->cbl_offset = make16(p->xmit_cmds[0]); p->scb->cmd = CUC_START; p->xmit_cmds[0]->cmd_status = 0; elmc_attn586(); dev->trans_start = jiffies; if (!i) { dev_kfree_skb(skb); } WAIT_4_SCB_CMD(); if ((p->scb->status & CU_ACTIVE)) { /* test it, because CU sometimes doesn't start immediately */ break; } if (p->xmit_cmds[0]->cmd_status) { break; } if (i == 15) { printk(KERN_WARNING "%s: Can't start transmit-command.\n", dev->name); } }#else next_nop = (p->nop_point + 1) & 0x1; p->xmit_buffs[0]->size = TBD_LAST | len; p->xmit_cmds[0]->cmd_link = p->nop_cmds[next_nop]->cmd_link = make16((p->nop_cmds[next_nop])); p->xmit_cmds[0]->cmd_status = p->nop_cmds[next_nop]->cmd_status = 0; p->nop_cmds[p->nop_point]->cmd_link = make16((p->xmit_cmds[0])); dev->trans_start = jiffies; p->nop_point = next_nop; dev_kfree_skb(skb);#endif#else p->xmit_buffs[p->xmit_count]->size = TBD_LAST | len; if ((next_nop = p->xmit_count + 1) == NUM_XMIT_BUFFS) { next_nop = 0; } p->xmit_cmds[p->xmit_count]->cmd_status = 0; p->xmit_cmds[p->xmit_count]->cmd_link = p->nop_cmds[next_nop]->cmd_link = make16((p->nop_cmds[next_nop])); p->nop_cmds[next_nop]->cmd_status = 0; p->nop_cmds[p->xmit_count]->cmd_link = make16((p->xmit_cmds[p->xmit_count])); dev->trans_start = jiffies; p->xmit_count = next_nop; if (p->xmit_count != p->xmit_last) netif_wake_queue(dev); dev_kfree_skb(skb);#endif return 0;}/******************************************* * Someone wanna have the statistics */static struct net_device_stats *elmc_get_stats(struct net_device *dev){ struct priv *p = (struct priv *) dev->priv; unsigned short crc, aln, rsc, ovrn; crc = p->scb->crc_errs; /* get error-statistic from the ni82586 */ p->scb->crc_errs -= crc; aln = p->scb->aln_errs; p->scb->aln_errs -= aln; rsc = p->scb->rsc_errs; p->scb->rsc_errs -= rsc; ovrn = p->scb->ovrn_errs; p->scb->ovrn_errs -= ovrn; p->stats.rx_crc_errors += crc; p->stats.rx_fifo_errors += ovrn; p->stats.rx_frame_errors += aln; p->stats.rx_dropped += rsc; return &p->stats;}/******************************************************** * Set MC list .. */#ifdef ELMC_MULTICASTstatic void set_multicast_list(struct net_device *dev){ if (!dev->start) { /* without a running interface, promiscuous doesn't work */ return; } dev->start = 0; alloc586(dev); init586(dev); startrecv586(dev); dev->start = 1;}#endif/** * netdev_ethtool_ioctl: Handle network interface SIOCETHTOOL ioctls * @dev: network interface on which out-of-band action is to be performed * @useraddr: userspace address to which data is to be read and returned * * Process the various commands of the SIOCETHTOOL interface. */static int netdev_ethtool_ioctl (struct net_device *dev, void *useraddr){ u32 ethcmd; /* dev_ioctl() in ../../net/core/dev.c has already checked capable(CAP_NET_ADMIN), so don't bother with that here. */ if (get_user(ethcmd, (u32 *)useraddr)) return -EFAULT; switch (ethcmd) { case ETHTOOL_GDRVINFO: { struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO }; strcpy (info.driver, DRV_NAME); strcpy (info.version, DRV_VERSION); sprintf(info.bus_info, "MCA 0x%lx", dev->base_addr); if (copy_to_user (useraddr, &info, sizeof (info))) return -EFAULT; return 0; } default: break; } return -EOPNOTSUPP;}/** * netdev_ioctl: Handle network interface ioctls * @dev: network interface on which out-of-band action is to be performed * @rq: user request data * @cmd: command issued by user * * Process the various out-of-band ioctls passed to this driver. */static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd){ int rc = 0; switch (cmd) { case SIOCETHTOOL: rc = netdev_ethtool_ioctl(dev, (void *) rq->ifr_data); break; default: rc = -EOPNOTSUPP; break; } return rc;} /*************************************************************************/#ifdef MODULE/* Increase if needed ;) */#define MAX_3C523_CARDS 4static struct net_device dev_elmc[MAX_3C523_CARDS];static int irq[MAX_3C523_CARDS];static int io[MAX_3C523_CARDS];MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_3C523_CARDS) "i");MODULE_PARM(io, "1-" __MODULE_STRING(MAX_3C523_CARDS) "i");MODULE_PARM_DESC(io, "EtherLink/MC I/O base address(es)");MODULE_PARM_DESC(irq, "EtherLink/MC IRQ number(s)");int init_module(void){ int this_dev,found = 0; /* Loop until we either can't find any more cards, or we have MAX_3C523_CARDS */ for(this_dev=0; this_dev<MAX_3C523_CARDS; this_dev++) { struct net_device *dev = &dev_elmc[this_dev]; dev->irq=irq[this_dev]; dev->base_addr=io[this_dev]; dev->init=elmc_probe; if(register_netdev(dev)!=0) { if(io[this_dev]==0) break; printk(KERN_WARNING "3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]); } else found++; } if(found==0) { if(io[0]==0) printk(KERN_NOTICE "3c523.c: No 3c523 cards found\n"); return -ENXIO; } else return 0;}void cleanup_module(void){ int this_dev; for(this_dev=0; this_dev<MAX_3C523_CARDS; this_dev++) { struct net_device *dev = &dev_elmc[this_dev]; if(dev->priv) { /* shutdown interrupts on the card */ elmc_id_reset586(); if (dev->irq != 0) { /* this should be done by close, but if we failed to initialize properly something may have gotten hosed. */ free_irq(dev->irq, dev); dev->irq = 0; } if (dev->base_addr != 0) { release_region(dev->base_addr, ELMC_IO_EXTENT); dev->base_addr = 0; } irq[this_dev] = 0; io[this_dev] = 0; unregister_netdev(dev); mca_set_adapter_procfn(((struct priv *) (dev->priv))->slot, NULL, NULL); kfree(dev->priv); dev->priv = NULL; } }}#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -