📄 at1700.c
字号:
static int net_open(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; int i; /* Powerup the chip, initialize config register 1, and select bank 0. */ outb(0xe0, ioaddr + CONFIG_1); /* Set the station address in bank zero. */ for (i = 0; i < 6; i++) outb(dev->dev_addr[i], ioaddr + 8 + i); /* Switch to bank 1 and set the multicast table to accept none. */ outb(0xe4, ioaddr + 7); for (i = 0; i < 8; i++) outb(0x00, ioaddr + 8 + i); /* Set the configuration register 0 to 32K 100ns. byte-wide memory, 16 bit bus access, and two 4K Tx queues. */ outb(0xda, ioaddr + CONFIG_0); /* Same config 0, except enable the Rx and Tx. */ outb(0x5a, ioaddr + CONFIG_0); /* Switch to register bank 2 for the run-time registers. */ outb(0xe8, ioaddr + CONFIG_1); /* Turn on Rx interrupts, leave Tx interrupts off until packet Tx. */ outb(0x00, ioaddr + TX_INTR); outb(0x81, ioaddr + RX_INTR); lp->open_time = jiffies; dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; return 0;}static intnet_send_packet(struct sk_buff *skb, struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; if (dev->tbusy) { /* If we get here, some higher level has decided we are broken. There should really be a "kick me" function call instead. */ int tickssofar = jiffies - dev->trans_start; if (tickssofar < 10) return 1; printk("%s: transmit timed out with status %04x, %s?\n", dev->name, inw(ioaddr + STATUS), inb(ioaddr + TX_STATUS) & 0x80 ? "IRQ conflict" : "network cable problem"); printk("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n", dev->name, inw(ioaddr + 0), inw(ioaddr + 2), inw(ioaddr + 4), inw(ioaddr + 6), inw(ioaddr + 8), inw(ioaddr + 10), inw(ioaddr + 12), inw(ioaddr + 14)); lp->stats.tx_errors++; /* ToDo: We should try to restart the adaptor... */ outw(0xffff, ioaddr + 24); outw(0xffff, ioaddr + TX_STATUS); outw(0xe85a, ioaddr + CONFIG_0); outw(0x8100, ioaddr + TX_INTR); dev->tbusy=0; dev->trans_start = jiffies; } /* If some higher layer thinks we've missed an tx-done interrupt we are passed NULL. Caution: dev_tint() handles the cli()/sti() itself. */ if (skb == NULL) { dev_tint(dev); return 0; } /* For ethernet, fill in the header. This should really be done by a higher level, rather than duplicated for each ethernet adaptor. */ if (!skb->arp && dev->rebuild_header(skb->data, dev)) { skb->dev = dev; arp_queue (skb); return 0; } skb->arp=1; /* Block a timer-based transmit from overlapping. This could better be done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ if (set_bit(0, (void*)&dev->tbusy) != 0) printk("%s: Transmitter access conflict.\n", dev->name); else { short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; unsigned char *buf = skb->data; /* Turn off the possible Tx interrupts. */ outb(0x00, ioaddr + TX_INTR); outw(length, ioaddr + DATAPORT); outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1); lp->tx_queue++; lp->tx_queue_len += length + 2; if (lp->tx_started == 0) { /* If the Tx is idle, always trigger a transmit. */ outb(0x80 | lp->tx_queue, ioaddr + TX_START); lp->tx_queue = 0; lp->tx_queue_len = 0; dev->trans_start = jiffies; lp->tx_started = 1; } else if (lp->tx_queue_len < 4096 - 1502) /* Room for one more packet? */ dev->tbusy = 0; /* Turn on Tx interrupts back on. */ outb(0x82, ioaddr + TX_INTR); } if (skb->free) kfree_skb (skb, FREE_WRITE); return 0;}/* The typical workload of the driver: Handle the network interface interrupts. */static voidnet_interrupt(int reg_ptr){ int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2); struct device *dev = (struct device *)(irq2dev_map[irq]); struct net_local *lp; int ioaddr, status; if (dev == NULL) { printk ("at1700_interrupt(): irq %d for unknown device.\n", irq); return; } dev->interrupt = 1; ioaddr = dev->base_addr; lp = (struct net_local *)dev->priv; status = inw(ioaddr + TX_STATUS); outw(status, ioaddr + TX_STATUS); if (net_debug > 4) printk("%s: Interrupt with status %04x.\n", dev->name, status); if (status & 0xff00 || (inb(ioaddr + RX_MODE) & 0x40) == 0) { /* Got a packet(s). */ net_rx(dev); } if (status & 0x00ff) { if (status & 0x80) { lp->stats.tx_packets++; if (lp->tx_queue) { outb(0x80 | lp->tx_queue, ioaddr + TX_START); lp->tx_queue = 0; lp->tx_queue_len = 0; dev->trans_start = jiffies; dev->tbusy = 0; mark_bh(INET_BH); /* Inform upper layers. */ } else { lp->tx_started = 0; /* Turn on Tx interrupts off. */ outb(0x00, ioaddr + TX_INTR); dev->tbusy = 0; } } } return;}/* We have a good packet(s), get it/them out of the buffers. */static voidnet_rx(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; int boguscount = 5; while ((inb(ioaddr + RX_MODE) & 0x40) == 0) { ushort status = inw(ioaddr + DATAPORT); if (net_debug > 4) printk("%s: Rxing packet mode %02x status %04x.\n", dev->name, inb(ioaddr + RX_MODE), status);#ifndef final_version if (status == 0) { outb(0x05, ioaddr + 14); break; }#endif if ((status & 0xF0) != 0x20) { /* There was an error. */ lp->stats.rx_errors++; if (status & 0x08) lp->stats.rx_length_errors++; if (status & 0x04) lp->stats.rx_frame_errors++; if (status & 0x02) lp->stats.rx_crc_errors++; if (status & 0x01) lp->stats.rx_over_errors++; } else { ushort pkt_len = inw(ioaddr + DATAPORT); /* Malloc up new buffer. */ int sksize = sizeof(struct sk_buff) + pkt_len; struct sk_buff *skb; if (pkt_len > 1550) { printk("%s: The AT1700 claimed a very large packet, size %d.\n", dev->name, pkt_len); outb(0x05, ioaddr + 14); lp->stats.rx_errors++; break; } skb = alloc_skb(sksize, GFP_ATOMIC); if (skb == NULL) { printk("%s: Memory squeeze, dropping packet (len %d).\n", dev->name, pkt_len); outb(0x05, ioaddr + 14); lp->stats.rx_dropped++; break; } skb->mem_len = sksize; skb->mem_addr = skb; skb->len = pkt_len; skb->dev = dev; insw(ioaddr + DATAPORT, skb->data, (pkt_len + 1) >> 1); if (net_debug > 5) { int i; printk("%s: Rxed packet of length %d: ", dev->name, pkt_len); for (i = 0; i < 14; i++) printk(" %02x", skb->data[i]); printk(".\n"); }#ifdef HAVE_NETIF_RX netif_rx(skb);#else skb->lock = 0; if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) { kfree_s(skb, sksize); lp->stats.rx_dropped++; break; }#endif lp->stats.rx_packets++; } if (--boguscount <= 0) break; } /* If any worth-while packets have been received, dev_rint() has done a mark_bh(INET_BH) for us and will work on them when we get to the bottom-half routine. */ { int i; for (i = 0; i < 20; i++) { if ((inb(ioaddr + RX_MODE) & 0x40) == 0x40) break; outb(0x05, ioaddr + 14); } if (net_debug > 5) printk("%s: Exint Rx packet with mode %02x after %d ticks.\n", dev->name, inb(ioaddr + RX_MODE), i); } return;}/* The inverse routine to net_open(). */static int net_close(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; int ioaddr = dev->base_addr; lp->open_time = 0; dev->tbusy = 1; dev->start = 0; /* Set configuration register 0 to disable Tx and Rx. */ outb(0xda, ioaddr + CONFIG_0); /* Update the statistics -- ToDo. */ /* Power-down the chip. Green, green, green! */ outb(0x00, ioaddr + CONFIG_1); return 0;}/* Get the current statistics. This may be called with the card open or closed. */static struct enet_statistics *net_get_stats(struct device *dev){ struct net_local *lp = (struct net_local *)dev->priv; cli(); /* ToDo: Update the statistics from the device registers. */ sti(); return &lp->stats;}#ifdef HAVE_MULTICAST/* 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 voidset_multicast_list(struct device *dev, int num_addrs, void *addrs){ short ioaddr = dev->base_addr; if (num_addrs) { outw(3, ioaddr + RX_MODE); /* Enable promiscuous mode */ } else outw(2, ioaddr + RX_MODE); /* Disable promiscuous, use normal mode */}#endif/* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c at1700.c" * version-control: t * kept-new-versions: 5 * tab-width: 4 * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -