📄 3c523.c
字号:
p->rfd_last = p->rfd_first + p->num_recv_buffs - 1; p->scb->rfa_offset = make16(p->rfd_first); p->rfd_first->rbd_offset = make16(rbd); return ptr;}/************************************************** * Interrupt Handler ... */static void elmc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr){ struct device *dev = (struct device *) dev_id; unsigned short stat; struct priv *p; if (dev == NULL) { printk("elmc-interrupt: irq %d for unknown device.\n", (int) -(((struct pt_regs *) reg_ptr)->orig_eax + 2)); return; } else if (!dev->start) { /* The 3c523 has this habit of generating interrupts during the reset. I'm not sure if the ni52 has this same problem, but it's really annoying if we haven't finished initializing it. I was hoping all the elmc_id_* commands would disable this, but I might have missed a few. */ elmc_id_attn586(); /* ack inter. and disable any more */ return; } else if (!(ELMC_CTRL_INT & inb(dev->base_addr + ELMC_CTRL))) { /* wasn't this device */ return; } /* reading ELMC_CTRL also clears the INT bit. */ p = (struct priv *) dev->priv; dev->interrupt = 1; while ((stat = p->scb->status & STAT_MASK)) { p->scb->cmd = stat; 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 (dev->start) { printk("%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("%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; } } dev->interrupt = 0;}/******************************************************* * receive-interrupt */static void elmc_rcv_int(struct 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 */ memcpy(skb_put(skb, totlen), (u8 *)phys_to_virt(p->base) + (unsigned long) rbd->buffer, totlen); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); p->stats.rx_packets++; p->stats.rx_bytes += totlen; } else { p->stats.rx_dropped++; } } else { printk("%s: received oversized frame.\n", dev->name); p->stats.rx_dropped++; } } else { /* frame !(ok), only with 'save-bad-frames' */ printk("%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 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("%s: Receive-Unit restarted. Status: %04x\n", dev->name, p->scb->status);}/********************************************************** * handle xmit - interrupt */static void elmc_xmt_int(struct 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("%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("%s: late collision detected.\n", dev->name); p->stats.collisions++; } else if (status & TCMD_NOCARRIER) { p->stats.tx_carrier_errors++; printk("%s: no carrier detected.\n", dev->name); } else if (status & TCMD_LOSTCTS) { printk("%s: loss of CTS detected.\n", dev->name); } else if (status & TCMD_UNDERRUN) { p->stats.tx_fifo_errors++; printk("%s: DMA underrun detected.\n", dev->name); } else if (status & TCMD_MAXCOLL) { printk("%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 dev->tbusy = 0; mark_bh(NET_BH);}/*********************************************************** * (re)start the receiver */static void startrecv586(struct 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!!) */}/****************************************************** * send frame */static int elmc_send_packet(struct sk_buff *skb, struct device *dev){ int len;#ifndef NO_NOPCOMMANDS int next_nop;#endif struct priv *p = (struct priv *) dev->priv; if (dev->tbusy) { int tickssofar = jiffies - dev->trans_start; if (tickssofar < 5) { return 1; } /* COMMAND-UNIT active? */ if (p->scb->status & CU_ACTIVE) { dev->tbusy = 0;#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(); dev->trans_start = jiffies; return 0; } 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); } dev->trans_start = jiffies; return 0; } if (test_and_set_bit(0, (void *) &dev->tbusy) != 0) { printk("%s: Transmitter access conflict.\n", dev->name); } else { 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("%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; cli(); if (p->xmit_count != p->xmit_last) { dev->tbusy = 0; } sti(); dev_kfree_skb(skb);#endif } return 0;}/******************************************* * Someone wanna have the statistics */static struct net_device_stats *elmc_get_stats(struct 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 .. */static void set_multicast_list(struct 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;}/*************************************************************************/#ifdef MODULEstatic char devicename[9] = {0,};static struct device dev_elmc ={ devicename /*"3c523" */ , 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, elmc_probe};static int irq = 0;static int io = 0;MODULE_PARM(irq, "i");MODULE_PARM(io, "i");int init_module(void){ struct device *dev = &dev_elmc; dev->base_addr = io; dev->irq = irq; if (register_netdev(dev) != 0) { return -EIO; } return 0;}void cleanup_module(void){ struct device *dev = &dev_elmc; /* 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 = 0; io = 0; unregister_netdev(dev); mca_set_adapter_procfn(((struct priv *) (dev->priv))->slot, NULL, NULL); kfree_s(dev->priv, sizeof(struct priv)); dev->priv = NULL;}#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -