📄 3c501.c
字号:
load_it_again_sam: lp->tx_pkt_start = gp_start; lp->collisions = 0; /* * Command mode with status cleared should [in theory] * mean no more interrupts can be pending on the card. */ #ifdef BLOCKOUT_1 disable_irq(dev->irq); #endif outb_p(AX_SYS, AX_CMD); inb_p(RX_STATUS); inb_p(TX_STATUS); lp->loading=1; /* * Turn interrupts back on while we spend a pleasant afternoon * loading bytes into the board */ restore_flags(flags); outw(0x00, RX_BUF_CLR); /* Set rx packet area to 0. */ outw(gp_start, GP_LOW); /* aim - packet will be loaded into buffer start */ outsb(DATAPORT,buf,skb->len); /* load buffer (usual thing each byte increments the pointer) */ outw(gp_start, GP_LOW); /* the board reuses the same register */#ifndef BLOCKOUT_1 if(lp->loading==2) /* A receive upset our load, despite our best efforts */ { if(el_debug>2) printk("%s: burped during tx load.\n", dev->name); goto load_it_again_sam; /* Sigh... */ }#endif outb(AX_XMIT, AX_CMD); /* fire ... Trigger xmit. */ lp->loading=0;#ifdef BLOCKOUT_1 enable_irq(dev->irq);#endif dev->trans_start = jiffies; } if (el_debug > 2) printk(" queued xmit.\n"); dev_kfree_skb (skb, FREE_WRITE); return 0;}/* * The typical workload of the driver: * Handle the ether interface interrupts. */static void el_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct device *dev = (struct device *)(irq2dev_map[irq]); struct net_local *lp; int ioaddr; int axsr; /* Aux. status reg. */ if (dev == NULL || dev->irq != irq) { printk ("3c501 driver: irq %d for unknown device.\n", irq); return; } ioaddr = dev->base_addr; lp = (struct net_local *)dev->priv; /* * What happened ? */ axsr = inb(AX_STATUS); /* * Log it */ if (el_debug > 3) printk("%s: el_interrupt() aux=%#02x", dev->name, axsr); if (dev->interrupt) printk("%s: Reentering the interrupt driver!\n", dev->name); dev->interrupt = 1;#ifndef BLOCKOUT_1 if(lp->loading==1 && !dev->tbusy) printk("%s: Inconsistent state loading while not in tx\n", dev->name);#endif #ifdef BLOCKOUT_3 lp->loading=2; /* So we can spot loading interruptions */#endif if (dev->tbusy) { /* * Board in transmit mode. May be loading. If we are * loading we shouldn't have got this. */ int txsr = inb(TX_STATUS);#ifdef BLOCKOUT_2 if(lp->loading==1) { if(el_debug > 2) { printk("%s: Interrupt while loading [", dev->name); printk(" txsr=%02x gp=%04x rp=%04x]\n", txsr, inw(GP_LOW),inw(RX_LOW)); } lp->loading=2; /* Force a reload */ dev->interrupt = 0; return; }#endif if (el_debug > 6) printk(" txsr=%02x gp=%04x rp=%04x", txsr, inw(GP_LOW),inw(RX_LOW)); if ((axsr & 0x80) && (txsr & TX_READY) == 0) { /* * FIXME: is there a logic to whether to keep on trying or * reset immediately ? */ if(el_debug>1) printk("%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x" " gp=%03x rp=%03x.\n", dev->name, txsr, axsr, inw(ioaddr + EL1_DATAPTR), inw(ioaddr + EL1_RXPTR)); dev->tbusy = 0; mark_bh(NET_BH); } else if (txsr & TX_16COLLISIONS) { /* * Timed out */ if (el_debug) printk("%s: Transmit failed 16 times, ethernet jammed?\n",dev->name); outb(AX_SYS, AX_CMD); lp->stats.tx_aborted_errors++; } else if (txsr & TX_COLLISION) { /* * Retrigger xmit. */ if (el_debug > 6) printk(" retransmitting after a collision.\n"); /* * Poor little chip can't reset its own start pointer */ outb(AX_SYS, AX_CMD); outw(lp->tx_pkt_start, GP_LOW); outb(AX_XMIT, AX_CMD); lp->stats.collisions++; dev->interrupt = 0; return; } else { /* * It worked.. we will now fall through and receive */ lp->stats.tx_packets++; if (el_debug > 6) printk(" Tx succeeded %s\n", (txsr & TX_RDY) ? "." : "but tx is busy!"); /* * This is safe the interrupt is atomic WRT itself. */ dev->tbusy = 0; mark_bh(NET_BH); /* In case more to transmit */ } } else { /* * In receive mode. */ int rxsr = inb(RX_STATUS); if (el_debug > 5) printk(" rxsr=%02x txsr=%02x rp=%04x", rxsr, inb(TX_STATUS),inw(RX_LOW)); /* * Just reading rx_status fixes most errors. */ if (rxsr & RX_MISSED) lp->stats.rx_missed_errors++; else if (rxsr & RX_RUNT) { /* Handled to avoid board lock-up. */ lp->stats.rx_length_errors++; if (el_debug > 5) printk(" runt.\n"); } else if (rxsr & RX_GOOD) { /* * Receive worked. */ el_receive(dev); } else { /* * Nothing? Something is broken! */ if (el_debug > 2) printk("%s: No packet seen, rxsr=%02x **resetting 3c501***\n", dev->name, rxsr); el_reset(dev); } if (el_debug > 3) printk(".\n"); } /* * Move into receive mode */ outb(AX_RX, AX_CMD); outw(0x00, RX_BUF_CLR); inb(RX_STATUS); /* Be certain that interrupts are cleared. */ inb(TX_STATUS); dev->interrupt = 0; return;}/* * We have a good packet. Well, not really "good", just mostly not broken. * We must check everything to see if it is good. */static void el_receive(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; int pkt_len; struct sk_buff *skb; pkt_len = inw(RX_LOW); if (el_debug > 4) printk(" el_receive %d.\n", pkt_len); if ((pkt_len < 60) || (pkt_len > 1536)) { if (el_debug) printk("%s: bogus packet, length=%d\n", dev->name, pkt_len); lp->stats.rx_over_errors++; return; } /* * Command mode so we can empty the buffer */ outb(AX_SYS, AX_CMD); skb = dev_alloc_skb(pkt_len+2); /* * Start of frame */ outw(0x00, GP_LOW); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; return; } else { skb_reserve(skb,2); /* Force 16 byte alignment */ skb->dev = dev; /* * The read increments through the bytes. The interrupt * handler will fix the pointer when it returns to * receive mode. */ insb(DATAPORT, skb_put(skb,pkt_len), pkt_len); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); lp->stats.rx_packets++; } return;}static void el_reset(struct device *dev){ int ioaddr = dev->base_addr; if (el_debug> 2) printk("3c501 reset..."); outb(AX_RESET, AX_CMD); /* Reset the chip */ outb(AX_LOOP, AX_CMD); /* Aux control, irq and loopback enabled */ { int i; for (i = 0; i < 6; i++) /* Set the station address. */ outb(dev->dev_addr[i], ioaddr + i); } outw(0, RX_BUF_CLR); /* Set rx packet area to 0. */ cli(); /* Avoid glitch on writes to CMD regs */ outb(TX_NORM, TX_CMD); /* tx irq on done, collision */ outb(RX_NORM, RX_CMD); /* Set Rx commands. */ inb(RX_STATUS); /* Clear status. */ inb(TX_STATUS); dev->interrupt = 0; dev->tbusy = 0; sti();}static int el1_close(struct device *dev){ int ioaddr = dev->base_addr; if (el_debug > 2) printk("%s: Shutting down ethercard at %#x.\n", dev->name, ioaddr); dev->tbusy = 1; dev->start = 0; /* * Free and disable the IRQ. */ free_irq(dev->irq, NULL); outb(AX_RESET, AX_CMD); /* Reset the chip */ irq2dev_map[dev->irq] = 0; MOD_DEC_USE_COUNT; return 0;}static struct enet_statistics *el1_get_stats(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; return &lp->stats;}/* * Set or clear the multicast filter for this adaptor. * best-effort filtering. */static void set_multicast_list(struct device *dev){ int ioaddr = dev->base_addr; if(dev->flags&IFF_PROMISC) { outb(RX_PROM, RX_CMD); inb(RX_STATUS); } else if (dev->mc_list || dev->flags&IFF_ALLMULTI) { outb(RX_MULT, RX_CMD); /* Multicast or all multicast is the same */ inb(RX_STATUS); /* Clear status. */ } else { outb(RX_NORM, RX_CMD); inb(RX_STATUS); }}#ifdef MODULEstatic char devicename[9] = { 0, };static struct device dev_3c501 = { devicename, /* device name is inserted by linux/drivers/net/net_init.c */ 0, 0, 0, 0, 0x280, 5, 0, 0, 0, NULL, el1_probe };static int io=0x280;static int irq=5; int init_module(void){ dev_3c501.irq=irq; dev_3c501.base_addr=io; if (register_netdev(&dev_3c501) != 0) return -EIO; return 0;}void cleanup_module(void){ /* * No need to check MOD_IN_USE, as sys_delete_module() checks. */ unregister_netdev(&dev_3c501); /* * Free up the private structure, or leak memory :-) */ kfree(dev_3c501.priv); dev_3c501.priv = NULL; /* gets re-allocated by el1_probe1 */ /* * If we don't do this, we can't re-insmod it later. */ release_region(dev_3c501.base_addr, EL1_IO_EXTENT);}#endif /* MODULE *//* * Local variables: * compile-command: "gcc -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -m486 -c -o 3c501.o 3c501.c" * kept-new-versions: 5 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -