📄 apricot.c
字号:
printk("%s: command unit timed out, status resetting.\n", dev->name); i596_reset(dev, lp, ioaddr); }}static inti596_open(struct device *dev){ int i; if (i596_debug > 1) printk("%s: i596_open() irq %d.\n", dev->name, dev->irq); if (request_irq(dev->irq, &i596_interrupt, 0, "apricot", NULL)) return -EAGAIN; irq2dev_map[dev->irq] = dev; i = init_rx_bufs(dev, RX_RING_SIZE); if ((i = init_rx_bufs(dev, RX_RING_SIZE)) < RX_RING_SIZE) printk("%s: only able to allocate %d receive buffers\n", dev->name, i); if (i < 4) { free_irq(dev->irq, NULL); irq2dev_map[dev->irq] = 0; return -EAGAIN; } dev->tbusy = 0; dev->interrupt = 0; dev->start = 1; MOD_INC_USE_COUNT; /* Initialize the 82596 memory */ init_i596_mem(dev); return 0; /* Always succeed */}static inti596_start_xmit(struct sk_buff *skb, struct device *dev){ struct i596_private *lp = (struct i596_private *)dev->priv; int ioaddr = dev->base_addr; struct tx_cmd *tx_cmd; if (i596_debug > 2) printk ("%s: Apricot start xmit\n", dev->name); /* Transmitter timeout, serious problems. */ if (dev->tbusy) { int tickssofar = jiffies - dev->trans_start; if (tickssofar < 5) return 1; printk("%s: transmit timed out, status resetting.\n", dev->name); lp->stats.tx_errors++; /* Try to restart the adaptor */ if (lp->last_restart == lp->stats.tx_packets) { if (i596_debug > 1) printk ("Resetting board.\n"); /* Shutdown and restart */ i596_reset(dev,lp, ioaddr); } else { /* Issue a channel attention signal */ if (i596_debug > 1) printk ("Kicking board.\n"); lp->scb.command = CUC_START|RX_START; outw(0, ioaddr+4); lp->last_restart = lp->stats.tx_packets; } dev->tbusy = 0; dev->trans_start = jiffies; } /* If some higher level thinks we've misses a tx-done interrupt we are passed NULL. n.b. dev_tint handles the cli()/sti() itself. */ if (skb == NULL) { dev_tint(dev); return 0; } /* shouldn't happen */ if (skb->len <= 0) return 0; if (i596_debug > 3) printk("%s: i596_start_xmit() called\n", dev->name); /* 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; dev->trans_start = jiffies; tx_cmd = (struct tx_cmd *) kmalloc ((sizeof (struct tx_cmd) + sizeof (struct i596_tbd)), GFP_ATOMIC); if (tx_cmd == NULL) { printk ("%s: i596_xmit Memory squeeze, dropping packet.\n", dev->name); lp->stats.tx_dropped++; dev_kfree_skb(skb, FREE_WRITE); } else { tx_cmd->tbd = (struct i596_tbd *) (tx_cmd + 1); tx_cmd->tbd->next = (struct i596_tbd *) I596_NULL; tx_cmd->cmd.command = CMD_FLEX|CmdTx; tx_cmd->pad = 0; tx_cmd->size = 0; tx_cmd->tbd->pad = 0; tx_cmd->tbd->size = EOF | length; tx_cmd->tbd->data = skb->data; if (i596_debug > 3) print_eth(skb->data); i596_add_cmd(dev, (struct i596_cmd *)tx_cmd); lp->stats.tx_packets++; } } dev->tbusy = 0; return 0;}static void print_eth(char *add){ int i; printk ("Dest "); for (i = 0; i < 6; i++) printk(" %2.2X", (unsigned char)add[i]); printk ("\n"); printk ("Source"); for (i = 0; i < 6; i++) printk(" %2.2X", (unsigned char)add[i+6]); printk ("\n"); printk ("type %2.2X%2.2X\n", (unsigned char)add[12], (unsigned char)add[13]);}int apricot_probe(struct device *dev){ int i; struct i596_private *lp; int checksum = 0; int ioaddr = 0x300; char eth_addr[6]; /* this is easy the ethernet interface can only be at 0x300 */ /* first check nothing is already registered here */ if (check_region(ioaddr, APRICOT_TOTAL_SIZE)) return ENODEV; for (i = 0; i < 8; i++) { eth_addr[i] = inb(ioaddr+8+i); checksum += eth_addr[i]; } /* checksum is a multiple of 0x100, got this wrong first time some machines have 0x100, some 0x200. The DOS driver doesn't even bother with the checksum */ if (checksum % 0x100) return ENODEV; /* Some other boards trip the checksum.. but then appear as ether address 0. Trap these - AC */ if(memcmp(eth_addr,"\x00\x00\x49",3)!= 0) return ENODEV; request_region(ioaddr, APRICOT_TOTAL_SIZE, "apricot"); dev->base_addr = ioaddr; ether_setup(dev); printk("%s: Apricot 82596 at %#3x,", dev->name, ioaddr); for (i = 0; i < 6; i++) printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]); dev->base_addr = ioaddr; dev->irq = 10; printk(" IRQ %d.\n", dev->irq); if (i596_debug > 0) printk(version); /* The APRICOT-specific entries in the device structure. */ dev->open = &i596_open; dev->stop = &i596_close; dev->hard_start_xmit = &i596_start_xmit; dev->get_stats = &i596_get_stats; dev->set_multicast_list = &set_multicast_list; dev->mem_start = (int)kmalloc(sizeof(struct i596_private)+ 0x0f, GFP_KERNEL); /* align for scp */ dev->priv = (void *)((dev->mem_start + 0xf) & 0xfffffff0); lp = (struct i596_private *)dev->priv; memset((void *)lp, 0, sizeof(struct i596_private)); lp->scb.command = 0; lp->scb.cmd = (struct i596_cmd *) I596_NULL; lp->scb.rfd = (struct i596_rfd *)I596_NULL; return 0;}static voidi596_interrupt(int irq, void *dev_id, struct pt_regs *regs){ struct device *dev = (struct device *)(irq2dev_map[irq]); struct i596_private *lp; short ioaddr; int boguscnt = 200; unsigned short status, ack_cmd = 0; if (dev == NULL) { printk ("i596_interrupt(): irq %d for unknown device.\n", irq); return; } if (i596_debug > 3) printk ("%s: i596_interrupt(): irq %d\n",dev->name, irq); if (dev->interrupt) printk("%s: Re-entering the interrupt handler.\n", dev->name); dev->interrupt = 1; ioaddr = dev->base_addr; lp = (struct i596_private *)dev->priv; while (lp->scb.status, lp->scb.command) if (--boguscnt == 0) { printk("%s: i596 interrupt, timeout status %4.4x command %4.4x.\n", dev->name, lp->scb.status, lp->scb.command); break; } status = lp->scb.status; if (i596_debug > 4) printk("%s: i596 interrupt, status %4.4x.\n", dev->name, status); ack_cmd = status & 0xf000; if ((status & 0x8000) || (status & 0x2000)) { struct i596_cmd *ptr; if ((i596_debug > 4) && (status & 0x8000)) printk("%s: i596 interrupt completed command.\n", dev->name); if ((i596_debug > 4) && (status & 0x2000)) printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700); while ((lp->cmd_head != (struct i596_cmd *) I596_NULL) && (lp->cmd_head->status & STAT_C)) { ptr = lp->cmd_head; lp->cmd_head = lp->cmd_head->next; lp->cmd_backlog--; switch ((ptr->command) & 0x7) { case CmdTx: { struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr; struct sk_buff *skb = ((struct sk_buff *)(tx_cmd->tbd->data)) -1; dev_kfree_skb(skb, FREE_WRITE); if ((ptr->status) & STAT_OK) { if (i596_debug >2) print_eth(skb->data); } else { lp->stats.tx_errors++; if ((ptr->status) & 0x0020) lp->stats.collisions++; if (!((ptr->status) & 0x0040)) lp->stats.tx_heartbeat_errors++; if ((ptr->status) & 0x0400) lp->stats.tx_carrier_errors++; if ((ptr->status) & 0x0800) lp->stats.collisions++; if ((ptr->status) & 0x1000) lp->stats.tx_aborted_errors++; } ptr->next = (struct i596_cmd * ) I596_NULL; kfree_s((unsigned char *)tx_cmd, (sizeof (struct tx_cmd) + sizeof (struct i596_tbd))); break; } case CmdMulticastList: { unsigned short count = *((unsigned short *) (ptr + 1)); ptr->next = (struct i596_cmd * ) I596_NULL; kfree_s((unsigned char *)ptr, (sizeof (struct i596_cmd) + count + 2)); break; } case CmdTDR: { unsigned long status = *((unsigned long *) (ptr + 1)); if (status & 0x8000) { if (i596_debug > 3) printk("%s: link ok.\n", dev->name); } else { if (status & 0x4000) printk("%s: Transceiver problem.\n", dev->name); if (status & 0x2000) printk("%s: Termination problem.\n", dev->name); if (status & 0x1000) printk("%s: Short circuit.\n", dev->name); printk("%s: Time %ld.\n", dev->name, status & 0x07ff); } } default: ptr->next = (struct i596_cmd * ) I596_NULL; lp->last_cmd = jiffies; } } ptr = lp->cmd_head; while ((ptr != (struct i596_cmd *) I596_NULL) && (ptr != lp->cmd_tail)) { ptr->command &= 0x1fff; ptr = ptr->next; } if ((lp->cmd_head != (struct i596_cmd *) I596_NULL) && (dev->start)) ack_cmd |= CUC_START; lp->scb.cmd = lp->cmd_head; } if ((status & 0x1000) || (status & 0x4000)) { if ((i596_debug > 4) && (status & 0x4000)) printk("%s: i596 interrupt received a frame.\n", dev->name); if ((i596_debug > 4) && (status & 0x1000)) printk("%s: i596 interrupt receive unit inactive %x.\n", dev->name, status & 0x0070); i596_rx(dev); if (dev->start) ack_cmd |= RX_START; } /* acknowledge the interrupt *//* if ((lp->scb.cmd != (struct i596_cmd *) I596_NULL) && (dev->start)) ack_cmd | = CUC_START;*/ boguscnt = 100; while (lp->scb.status, lp->scb.command) if (--boguscnt == 0) { printk("%s: i596 interrupt, timeout status %4.4x command %4.4x.\n", dev->name, lp->scb.status, lp->scb.command); break; } lp->scb.command = ack_cmd; (void) inb (ioaddr+0x10); outb (4, ioaddr+0xf); outw (0, ioaddr+4); if (i596_debug > 4) printk("%s: exiting interrupt.\n", dev->name); dev->interrupt = 0; return;}static inti596_close(struct device *dev){ int ioaddr = dev->base_addr; struct i596_private *lp = (struct i596_private *)dev->priv; int boguscnt = 200; dev->start = 0; dev->tbusy = 1; if (i596_debug > 1) printk("%s: Shutting down ethercard, status was %4.4x.\n", dev->name, lp->scb.status); lp->scb.command = CUC_ABORT|RX_ABORT; outw(0, ioaddr+4); i596_cleanup_cmd(lp); while (lp->scb.status, lp->scb.command) if (--boguscnt == 0) { printk("%s: close timed out with status %4.4x, cmd %4.4x.\n", dev->name, lp->scb.status, lp->scb.command); break; } free_irq(dev->irq, NULL); irq2dev_map[dev->irq] = 0; remove_rx_bufs(dev); MOD_DEC_USE_COUNT; return 0;}static struct enet_statistics *i596_get_stats(struct device *dev){ struct i596_private *lp = (struct i596_private *)dev->priv; return &lp->stats;}/* * Set or clear the multicast filter for this adaptor. */ static void set_multicast_list(struct device *dev){ struct i596_private *lp = (struct i596_private *)dev->priv; struct i596_cmd *cmd; if (i596_debug > 1) printk ("%s: set multicast list %d\n", dev->name, dev->mc_count); if (dev->mc_count > 0) { struct dev_mc_list *dmi; char *cp; cmd = (struct i596_cmd *) kmalloc(sizeof(struct i596_cmd)+2+dev->mc_count*6, GFP_ATOMIC); if (cmd == NULL) { printk ("%s: set_multicast Memory squeeze.\n", dev->name); return; } cmd->command = CmdMulticastList; *((unsigned short *) (cmd + 1)) = dev->mc_count * 6; cp=((char *)(cmd + 1))+2; for(dmi=dev->mc_list;dmi!=NULL;dmi=dmi->next) { memcpy(cp, dmi,6); cp+=6; } print_eth (((char *)(cmd + 1)) + 2); i596_add_cmd(dev, cmd); } else { if (lp->set_conf.next != (struct i596_cmd * ) I596_NULL) return; if (dev->mc_count == 0 && !(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))) { if(dev->flags&IFF_ALLMULTI) dev->flags|=IFF_PROMISC; lp->i596_config[8] &= ~0x01; } else lp->i596_config[8] |= 0x01; i596_add_cmd(dev, &lp->set_conf); }}#ifdef HAVE_DEVLISTstatic unsigned int apricot_portlist[] = {0x300, 0};struct netdev_entry apricot_drv = {"apricot", apricot_probe, APRICOT_TOTAL_SIZE, apricot_portlist};#endif#ifdef MODULEstatic char devicename[9] = { 0, };static struct device dev_apricot = { devicename, /* device name inserted by /linux/drivers/net/net_init.c */ 0, 0, 0, 0, 0x300, 10, 0, 0, 0, NULL, apricot_probe };static int io = 0x300;static int irq = 10;intinit_module(void){ dev_apricot.base_addr = io; dev_apricot.irq = irq; if (register_netdev(&dev_apricot) != 0) return -EIO; return 0;}voidcleanup_module(void){ unregister_netdev(&dev_apricot); kfree_s((void *)dev_apricot.mem_start, sizeof(struct i596_private) + 0xf); dev_apricot.priv = NULL; /* If we don't do this, we can't re-insmod it later. */ release_region(dev_apricot.base_addr, APRICOT_TOTAL_SIZE);}#endif /* MODULE *//* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c apricot.c" * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -