3c523.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,324 行 · 第 1/3 页
C
1,324 行
ptr = (char *) ptr + RECV_BUFF_SIZE; } p->rfd_top = p->rfd_first; 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 irqreturn_telmc_interrupt(int irq, void *dev_id, struct pt_regs *reg_ptr){ struct net_device *dev = (struct net_device *) dev_id; unsigned short stat; struct priv *p; if (dev == NULL) { printk(KERN_ERR "elmc-interrupt: irq %d for unknown device.\n", (int) -(((struct pt_regs *) reg_ptr)->orig_eax + 2)); return IRQ_NONE; } else if (!netif_running(dev)) { /* 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 IRQ_HANDLED; } else if (!(ELMC_CTRL_INT & inb(dev->base_addr + ELMC_CTRL))) { /* wasn't this device */ return IRQ_NONE; } /* reading ELMC_CTRL also clears the INT bit. */ p = (struct priv *) dev->priv; 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 (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; } } return IRQ_HANDLED;}/******************************************************* * 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); len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; if (len != skb->len) memset((char *) p->xmit_cbuffs[p->xmit_count], 0, ETH_ZLEN); memcpy((char *) p->xmit_cbuffs[p->xmit_count], (char *) (skb->data), skb->len);#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;}#endifstatic void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info){ strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); sprintf(info->bus_info, "MCA 0x%lx", dev->base_addr);}static struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo,};#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 = alloc_etherdev(sizeof(struct priv)); if (!dev) break; dev->irq=irq[this_dev]; dev->base_addr=io[this_dev]; if (do_elmc_probe(dev) == 0) { if (register_netdev(dev) == 0) { dev_elmc[this_dev] = dev; found++; continue; } cleanup_card(dev); } free_netdev(dev); if (io[this_dev]==0) break; printk(KERN_WARNING "3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]); } 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) { unregister_netdev(dev); cleanup_card(dev); free_netdev(dev); } }}#endif /* MODULE */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?