📄 ni5010.c
字号:
netif_start_queue(dev); if (NI5010_DEBUG) show_registers(dev); PRINTK((KERN_DEBUG "%s: open successful\n", dev->name)); return 0;}static void reset_receiver(struct net_device *dev){ int ioaddr = dev->base_addr; PRINTK3((KERN_DEBUG "%s: resetting receiver\n", dev->name)); outw(0, IE_GP); /* Receive packet at start of buffer */ outb(0xff, EDLC_RCLR); /* Clear all pending rcv interrupts */ outb(0, IE_MMODE); /* Put EDLC to rcv buffer */ outb(MM_EN_RCV, IE_MMODE); /* Enable rcv */ outb(0xff, EDLC_RMASK); /* Enable all rcv interrupts */}static void ni5010_timeout(struct net_device *dev){ printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name, tx_done(dev) ? "IRQ conflict" : "network cable problem"); /* Try to restart the adaptor. */ /* FIXME: Give it a real kick here */ chipset_init(dev, 1); dev->trans_start = jiffies; netif_wake_queue(dev);}static int ni5010_send_packet(struct sk_buff *skb, struct net_device *dev){ int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; PRINTK2((KERN_DEBUG "%s: entering ni5010_send_packet\n", dev->name)); /* * Block sending */ netif_stop_queue(dev); hardware_send_packet(dev, (unsigned char *)skb->data, length); dev->trans_start = jiffies; dev_kfree_skb (skb); return 0;}/* * The typical workload of the driver: * Handle the network interface interrupts. */static void ni5010_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct net_device *dev = dev_id; struct ni5010_local *lp; int ioaddr, status; int xmit_was_error = 0; PRINTK2((KERN_DEBUG "%s: entering ni5010_interrupt\n", dev->name)); ioaddr = dev->base_addr; lp = (struct ni5010_local *)dev->priv; status = inb(IE_ISTAT); PRINTK3((KERN_DEBUG "%s: IE_ISTAT = %#02x\n", dev->name, status)); if ((status & IS_R_INT) == 0) ni5010_rx(dev); if ((status & IS_X_INT) == 0) { xmit_was_error = process_xmt_interrupt(dev); } if ((status & IS_DMA_INT) == 0) { PRINTK((KERN_DEBUG "%s: DMA complete (???)\n", dev->name)); outb(0, IE_DMA_RST); /* Reset DMA int */ } if (!xmit_was_error) reset_receiver(dev); return;}static void dump_packet(void *buf, int len){ int i; printk(KERN_DEBUG "Packet length = %#4x\n", len); for (i = 0; i < len; i++){ if (i % 16 == 0) printk(KERN_DEBUG "%#4.4x", i); if (i % 2 == 0) printk(" "); printk("%2.2x", ((unsigned char *)buf)[i]); if (i % 16 == 15) printk("\n"); } printk("\n"); return;}/* We have a good packet, get it out of the buffer. */static void ni5010_rx(struct net_device *dev){ struct ni5010_local *lp = (struct ni5010_local *)dev->priv; int ioaddr = dev->base_addr; unsigned char rcv_stat; struct sk_buff *skb; PRINTK2((KERN_DEBUG "%s: entering ni5010_rx()\n", dev->name)); rcv_stat = inb(EDLC_RSTAT); PRINTK3((KERN_DEBUG "%s: EDLC_RSTAT = %#2x\n", dev->name, rcv_stat)); if ( (rcv_stat & RS_VALID_BITS) != RS_PKT_OK) { PRINTK((KERN_INFO "%s: receive error.\n", dev->name)); lp->stats.rx_errors++; if (rcv_stat & RS_RUNT) lp->stats.rx_length_errors++; if (rcv_stat & RS_ALIGN) lp->stats.rx_frame_errors++; if (rcv_stat & RS_CRC_ERR) lp->stats.rx_crc_errors++; if (rcv_stat & RS_OFLW) lp->stats.rx_fifo_errors++; outb(0xff, EDLC_RCLR); /* Clear the interrupt */ return; } outb(0xff, EDLC_RCLR); /* Clear the interrupt */ lp->i_pkt_size = inw(IE_RCNT); if (lp->i_pkt_size > ETH_FRAME_LEN || lp->i_pkt_size < 10 ) { PRINTK((KERN_DEBUG "%s: Packet size error, packet size = %#4.4x\n", dev->name, lp->i_pkt_size)); lp->stats.rx_errors++; lp->stats.rx_length_errors++; return; } /* Malloc up new buffer. */ skb = dev_alloc_skb(lp->i_pkt_size + 3); if (skb == NULL) { printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); lp->stats.rx_dropped++; return; } skb->dev = dev; skb_reserve(skb, 2); /* Read packet into buffer */ outb(MM_MUX, IE_MMODE); /* Rcv buffer to system bus */ outw(0, IE_GP); /* Seek to beginning of packet */ insb(IE_RBUF, skb_put(skb, lp->i_pkt_size), lp->i_pkt_size); if (NI5010_DEBUG >= 4) dump_packet(skb->data, skb->len); skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); lp->stats.rx_packets++; lp->stats.rx_bytes += lp->i_pkt_size; PRINTK2((KERN_DEBUG "%s: Received packet, size=%#4.4x\n", dev->name, lp->i_pkt_size)); }static int process_xmt_interrupt(struct net_device *dev){ struct ni5010_local *lp = (struct ni5010_local *)dev->priv; int ioaddr = dev->base_addr; int xmit_stat; PRINTK2((KERN_DEBUG "%s: entering process_xmt_interrupt\n", dev->name)); xmit_stat = inb(EDLC_XSTAT); PRINTK3((KERN_DEBUG "%s: EDLC_XSTAT = %2.2x\n", dev->name, xmit_stat)); outb(0, EDLC_XMASK); /* Disable xmit IRQ's */ outb(0xff, EDLC_XCLR); /* Clear all pending xmit IRQ's */ if (xmit_stat & XS_COLL){ printk("ether collision\n"); /* FIXME: remove */ PRINTK((KERN_DEBUG "%s: collision detected, retransmitting\n", dev->name)); outw(NI5010_BUFSIZE - lp->o_pkt_size, IE_GP); /* outb(0, IE_MMODE); */ /* xmt buf on sysbus FIXME: needed ? */ outb(MM_EN_XMT | MM_MUX, IE_MMODE); outb(XM_ALL, EDLC_XMASK); /* Enable xmt IRQ's */ lp->stats.collisions++; return 1; } /* FIXME: handle other xmt error conditions */ lp->stats.tx_packets++; lp->stats.tx_bytes += lp->o_pkt_size; netif_wake_queue(dev); PRINTK2((KERN_DEBUG "%s: sent packet, size=%#4.4x\n", dev->name, lp->o_pkt_size)); return 0;}/* The inverse routine to ni5010_open(). */static int ni5010_close(struct net_device *dev){ int ioaddr = dev->base_addr; PRINTK2((KERN_DEBUG "%s: entering ni5010_close\n", dev->name));#ifdef jumpered_interrupts free_irq(dev->irq, NULL);#endif /* Put card in held-RESET state */ outb(0, IE_MMODE); outb(RS_RESET, EDLC_RESET); netif_stop_queue(dev); PRINTK((KERN_DEBUG "%s: %s closed down\n", dev->name, boardname)); return 0;}/* Get the current statistics. This may be called with the card open or closed. */static struct net_device_stats *ni5010_get_stats(struct net_device *dev){ struct ni5010_local *lp = (struct ni5010_local *)dev->priv; PRINTK2((KERN_DEBUG "%s: entering ni5010_get_stats\n", dev->name)); if (NI5010_DEBUG) show_registers(dev); /* cli(); */ /* Update the statistics from the device registers. */ /* We do this in the interrupt handler */ /* sti(); */ return &lp->stats;}/* Set or clear the multicast filter for this adaptor. num_addrs == -1 Promiscuous mode, receive all packets num_addrs == 0 Normal mode, clear multicast list num_addrs > 0 Multicast mode, receive normal and MC packets, and do best-effort filtering.*/static void ni5010_set_multicast_list(struct net_device *dev){ short ioaddr = dev->base_addr; PRINTK2((KERN_DEBUG "%s: entering set_multicast_list\n", dev->name)); if (dev->flags&IFF_PROMISC || dev->flags&IFF_ALLMULTI) { dev->flags |= IFF_PROMISC; outb(RMD_PROMISC, EDLC_RMODE); /* Enable promiscuous mode */ PRINTK((KERN_DEBUG "%s: Entering promiscuous mode\n", dev->name)); } else if (dev->mc_list) { /* Sorry, multicast not supported */ PRINTK((KERN_DEBUG "%s: No multicast, entering broadcast mode\n", dev->name)); outb(RMD_BROADCAST, EDLC_RMODE); } else { PRINTK((KERN_DEBUG "%s: Entering broadcast mode\n", dev->name)); outb(RMD_BROADCAST, EDLC_RMODE); /* Disable promiscuous mode, use normal mode */ }}static void hardware_send_packet(struct net_device *dev, char *buf, int length){ struct ni5010_local *lp = (struct ni5010_local *)dev->priv; int ioaddr = dev->base_addr; unsigned long flags; unsigned int buf_offs; PRINTK2((KERN_DEBUG "%s: entering hardware_send_packet\n", dev->name)); if (length > ETH_FRAME_LEN) { PRINTK((KERN_WARNING "%s: packet too large, not possible\n", dev->name)); return; } if (NI5010_DEBUG) show_registers(dev); if (inb(IE_ISTAT) & IS_EN_XMT) { PRINTK((KERN_WARNING "%s: sending packet while already transmitting, not possible\n", dev->name)); return; } if (NI5010_DEBUG > 3) dump_packet(buf, length); buf_offs = NI5010_BUFSIZE - length; lp->o_pkt_size = length; save_flags(flags); cli(); outb(0, EDLC_RMASK); /* Mask all receive interrupts */ outb(0, IE_MMODE); /* Put Xmit buffer on system bus */ outb(0xff, EDLC_RCLR); /* Clear out pending rcv interrupts */ outw(buf_offs, IE_GP); /* Point GP at start of packet */ outsb(IE_XBUF, buf, length); /* Put data in buffer */ outw(buf_offs, IE_GP); /* Rewrite where packet starts */ /* should work without that outb() (Crynwr used it) */ /*outb(MM_MUX, IE_MMODE);*/ /* Xmt buffer to EDLC bus */ outb(MM_EN_XMT | MM_MUX, IE_MMODE); /* Begin transmission */ outb(XM_ALL, EDLC_XMASK); /* Cause interrupt after completion or fail */ restore_flags(flags); netif_wake_queue(dev); if (NI5010_DEBUG) show_registers(dev); }static void chipset_init(struct net_device *dev, int startp){ /* FIXME: Move some stuff here */ PRINTK3((KERN_DEBUG "%s: doing NOTHING in chipset_init\n", dev->name));}static void show_registers(struct net_device *dev){ int ioaddr = dev->base_addr; PRINTK3((KERN_DEBUG "%s: XSTAT %#2.2x\n", dev->name, inb(EDLC_XSTAT))); PRINTK3((KERN_DEBUG "%s: XMASK %#2.2x\n", dev->name, inb(EDLC_XMASK))); PRINTK3((KERN_DEBUG "%s: RSTAT %#2.2x\n", dev->name, inb(EDLC_RSTAT))); PRINTK3((KERN_DEBUG "%s: RMASK %#2.2x\n", dev->name, inb(EDLC_RMASK))); PRINTK3((KERN_DEBUG "%s: RMODE %#2.2x\n", dev->name, inb(EDLC_RMODE))); PRINTK3((KERN_DEBUG "%s: XMODE %#2.2x\n", dev->name, inb(EDLC_XMODE))); PRINTK3((KERN_DEBUG "%s: ISTAT %#2.2x\n", dev->name, inb(IE_ISTAT)));}#ifdef MODULEstatic struct net_device dev_ni5010;static int io;static int irq;MODULE_PARM(io, "i");MODULE_PARM(irq, "i");int init_module(void){ int result; PRINTK2((KERN_DEBUG "%s: entering init_module\n", boardname)); /* if(io <= 0 || irq == 0){ printk(KERN_WARNING "%s: Autoprobing not allowed for modules.\n", boardname); printk(KERN_WARNING "%s: Set symbols 'io' and 'irq'\n", boardname); return -EINVAL; } */ if (io <= 0){ printk(KERN_WARNING "%s: Autoprobing for modules is hazardous, trying anyway..\n", boardname); } PRINTK2((KERN_DEBUG "%s: init_module irq=%#2x, io=%#3x\n", boardname, irq, io)); dev_ni5010.irq=irq; dev_ni5010.base_addr=io; dev_ni5010.init=ni5010_probe; if ((result = register_netdev(&dev_ni5010)) != 0) { PRINTK((KERN_WARNING "%s: register_netdev returned %d.\n", boardname, result)); return -EIO; } return 0;}voidcleanup_module(void){ PRINTK2((KERN_DEBUG "%s: entering cleanup_module\n", boardname)); unregister_netdev(&dev_ni5010); release_region(dev_ni5010.base_addr, NI5010_IO_EXTENT); if (dev_ni5010.priv != NULL){ kfree(dev_ni5010.priv); dev_ni5010.priv = NULL; }}#endif /* MODULE *//* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c ni5010.c" * version-control: t * kept-new-versions: 5 * tab-width: 4 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -