📄 3c515.c
字号:
vortex_probe1() Fill in the device structure -- this is separated so that the modules code can put it in dev->init.*//* This driver uses 'options' to pass the media type, full-duplex flag, etc. *//* Note: this is the only limit on the number of cards supported!! */static int options[8] = { -1, -1, -1, -1, -1, -1, -1, -1,};#ifdef MODULEstatic int debug = -1;/* A list of all installed Vortex devices, for removing the driver module. */static struct device *root_vortex_dev = NULL;intinit_module(void){ int cards_found; if (debug >= 0) vortex_debug = debug; if (vortex_debug) printk(version); root_vortex_dev = NULL; cards_found = vortex_scan(0); return cards_found ? 0 : -ENODEV;}#elseint tc515_probe(struct device *dev){ int cards_found = 0; cards_found = vortex_scan(dev); if (vortex_debug > 0 && cards_found) printk(version); return cards_found ? 0 : -ENODEV;}#endif /* not MODULE */static int vortex_scan(struct device *dev){ int cards_found = 0; static int ioaddr = 0x100; /* Check all locations on the ISA bus -- evil! */ for (; ioaddr < 0x400; ioaddr += 0x20) { int irq; if (check_region(ioaddr, CORKSCREW_TOTAL_SIZE)) continue; /* Check the resource configuration for a matching ioaddr. */ if ((inw(ioaddr + 0x2002) & 0x1f0) != (ioaddr & 0x1f0)) continue; /* Verify by reading the device ID from the EEPROM. */ { int timer; outw(EEPROM_Read + 7, ioaddr + Wn0EepromCmd); /* Pause for at least 162 us. for the read to take place. */ for (timer = 4; timer >= 0; timer--) { udelay(162); if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0) break; } if (inw(ioaddr + Wn0EepromData) != 0x6d50) continue; } printk("3c515 Resource configuraiton register %#4.4x, DCR %4.4x.\n", inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); irq = inw(ioaddr + 0x2002) & 15; vortex_found_device(dev, ioaddr, irq, CORKSCREW_ID, dev && dev->mem_start ? dev->mem_start : options[cards_found]); dev = 0; cards_found++; } if (vortex_debug) printk("%d 3c515 cards found.\n", cards_found); return cards_found;}static struct device *vortex_found_device(struct device *dev, int ioaddr, int irq, int product_index, int options){ struct vortex_private *vp;#ifdef MODULE /* Allocate and fill new device structure. */ int dev_size = sizeof(struct device) + sizeof(struct vortex_private) + 15; /* Pad for alignment */ dev = (struct device *) kmalloc(dev_size, GFP_KERNEL); memset(dev, 0, dev_size); /* Align the Rx and Tx ring entries. */ dev->priv = (void *)(((long)dev + sizeof(struct device) + 15) & ~15); vp = (struct vortex_private *)dev->priv; dev->name = vp->devname; /* An empty string. */ dev->base_addr = ioaddr; dev->irq = irq; dev->dma = (product_index == CORKSCREW_ID ? inw(ioaddr + 0x2000) & 7 : 0); dev->init = vortex_probe1; vp->product_name = "3c515"; vp->options = options; if (options >= 0) { vp->media_override = ((options & 7) == 2) ? 0 : options & 7; vp->full_duplex = (options & 8) ? 1 : 0; vp->bus_master = (options & 16) ? 1 : 0; } else { vp->media_override = 7; vp->full_duplex = 0; vp->bus_master = 0; } ether_setup(dev); vp->next_module = root_vortex_dev; root_vortex_dev = dev; if (register_netdev(dev) != 0) return 0;#else /* not a MODULE */ if (dev) { /* Caution: quad-word alignment required for rings! */ dev->priv = kmalloc(sizeof (struct vortex_private), GFP_KERNEL); memset(dev->priv, 0, sizeof (struct vortex_private)); } dev = init_etherdev(dev, sizeof(struct vortex_private)); dev->base_addr = ioaddr; dev->irq = irq; dev->dma = (product_index == CORKSCREW_ID ? inw(ioaddr + 0x2000) & 7 : 0); vp = (struct vortex_private *)dev->priv; vp->product_name = "3c515"; vp->options = options; if (options >= 0) { vp->media_override = ((options & 7) == 2) ? 0 : options & 7; vp->full_duplex = (options & 8) ? 1 : 0; vp->bus_master = (options & 16) ? 1 : 0; } else { vp->media_override = 7; vp->full_duplex = 0; vp->bus_master = 0; } vortex_probe1(dev);#endif /* MODULE */ return dev;}static int vortex_probe1(struct device *dev){ int ioaddr = dev->base_addr; struct vortex_private *vp = (struct vortex_private *)dev->priv; unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ int i; printk("%s: 3Com %s at %#3x,", dev->name, vp->product_name, ioaddr); /* Read the station address from the EEPROM. */ EL3WINDOW(0); for (i = 0; i < 0x18; i++) { short *phys_addr = (short *)dev->dev_addr; int timer; outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd); /* Pause for at least 162 us. for the read to take place. */ for (timer = 4; timer >= 0; timer--) { udelay(162); if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0) break; } eeprom[i] = inw(ioaddr + Wn0EepromData); checksum ^= eeprom[i]; if (i < 3) phys_addr[i] = htons(eeprom[i]); } checksum = (checksum ^ (checksum >> 8)) & 0xff; if (checksum != 0x00) printk(" ***INVALID CHECKSUM %4.4x*** ", checksum); for (i = 0; i < 6; i++) printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]); if (eeprom[16] == 0x11c7) { /* Corkscrew */ if (request_dma(dev->dma, "3c515")) { printk(", DMA %d allocation failed", dev->dma); dev->dma = 0; } else printk(", DMA %d", dev->dma); } printk(", IRQ %d\n", dev->irq); /* Tell them about an invalid IRQ. */ if (vortex_debug && (dev->irq <= 0 || dev->irq > 15)) printk(" *** Warning: this IRQ is unlikely to work! ***\n"); { char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; union wn3_config config; EL3WINDOW(3); vp->available_media = inw(ioaddr + Wn3_Options); config.i = inl(ioaddr + Wn3_Config); if (vortex_debug > 1) printk(" Internal config register is %4.4x, transceivers %#x.\n", config.i, inw(ioaddr + Wn3_Options)); printk(" %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n", 8 << config.u.ram_size, config.u.ram_width ? "word" : "byte", ram_split[config.u.ram_split], config.u.autoselect ? "autoselect/" : "", media_tbl[config.u.xcvr].name); dev->if_port = config.u.xcvr; vp->default_media = config.u.xcvr; vp->autoselect = config.u.autoselect; } if (vp->media_override != 7) { printk(" Media override to transceiver type %d (%s).\n", vp->media_override, media_tbl[vp->media_override].name); dev->if_port = vp->media_override; } vp->capabilities = eeprom[16]; vp->full_bus_master_tx = (vp->capabilities & 0x20) ? 1 : 0; /* Rx is broken at 10mbps, so we always disable it. */ /* vp->full_bus_master_rx = 0;*/ vp->full_bus_master_rx = (vp->capabilities & 0x20) ? 1 : 0; /* We do a request_region() to register /proc/ioports info. */ request_region(ioaddr, CORKSCREW_TOTAL_SIZE, vp->product_name); /* The 3c59x-specific entries in the device structure. */ dev->open = &vortex_open; dev->hard_start_xmit = &vortex_start_xmit; dev->stop = &vortex_close; dev->get_stats = &vortex_get_stats; dev->set_multicast_list = &set_rx_mode; return 0;}static intvortex_open(struct device *dev){ int ioaddr = dev->base_addr; struct vortex_private *vp = (struct vortex_private *)dev->priv; union wn3_config config; int i; /* Before initializing select the active media port. */ EL3WINDOW(3); if (vp->full_duplex) outb(0x20, ioaddr + Wn3_MAC_Ctrl); /* Set the full-duplex bit. */ config.i = inl(ioaddr + Wn3_Config); if (vp->media_override != 7) { if (vortex_debug > 1) printk("%s: Media override to transceiver %d (%s).\n", dev->name, vp->media_override, media_tbl[vp->media_override].name); dev->if_port = vp->media_override; } else if (vp->autoselect) { /* Find first available media type, starting with 100baseTx. */ dev->if_port = 4; while (! (vp->available_media & media_tbl[dev->if_port].mask)) dev->if_port = media_tbl[dev->if_port].next; if (vortex_debug > 1) printk("%s: Initial media type %s.\n", dev->name, media_tbl[dev->if_port].name); init_timer(&vp->timer); vp->timer.expires = RUN_AT(media_tbl[dev->if_port].wait); vp->timer.data = (unsigned long)dev; vp->timer.function = &vortex_timer; /* timer handler */ add_timer(&vp->timer); } else dev->if_port = vp->default_media; config.u.xcvr = dev->if_port; outl(config.i, ioaddr + Wn3_Config); if (vortex_debug > 1) { printk("%s: vortex_open() InternalConfig %8.8x.\n", dev->name, config.i); } outw(TxReset, ioaddr + EL3_CMD); for (i = 20; i >= 0 ; i--) if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) break; outw(RxReset, ioaddr + EL3_CMD); /* Wait a few ticks for the RxReset command to complete. */ for (i = 20; i >= 0 ; i--) if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress)) break; outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD); /* Use the now-standard shared IRQ implementation. */ if (vp->capabilities == 0x11c7) { /* Corkscrew: Cannot share ISA resources. */ if (dev->irq == 0 || dev->dma == 0 || request_irq(dev->irq, &vortex_interrupt, 0, vp->product_name, dev)) return -EAGAIN; enable_dma(dev->dma); set_dma_mode(dev->dma, DMA_MODE_CASCADE); } else if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, vp->product_name, dev)) { return -EAGAIN; } if (vortex_debug > 1) { EL3WINDOW(4); printk("%s: vortex_open() irq %d media status %4.4x.\n", dev->name, dev->irq, inw(ioaddr + Wn4_Media)); } /* Set the station address and mask in window 2 each time opened. */ EL3WINDOW(2); for (i = 0; i < 6; i++) outb(dev->dev_addr[i], ioaddr + i); for (; i < 12; i+=2) outw(0, ioaddr + i); if (dev->if_port == 3) /* Start the thinnet transceiver. We should really wait 50ms...*/ outw(StartCoax, ioaddr + EL3_CMD); EL3WINDOW(4); outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) | media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media); /* Switch to the stats window, and clear all stats by reading. */ outw(StatsDisable, ioaddr + EL3_CMD); EL3WINDOW(6); for (i = 0; i < 10; i++) inb(ioaddr + i); inw(ioaddr + 10); inw(ioaddr + 12); /* New: On the Vortex we must also clear the BadSSD counter. */ EL3WINDOW(4); inb(ioaddr + 12); /* ..and on the Boomerang we enable the extra statistics bits. */ outw(0x0040, ioaddr + Wn4_NetDiag); /* Switch to register set 7 for normal use. */ EL3WINDOW(7); if (vp->full_bus_master_rx) { /* Boomerang bus master. */ vp->cur_rx = vp->dirty_rx = 0; if (vortex_debug > 2) printk("%s: Filling in the Rx ring.\n", dev->name); for (i = 0; i < RX_RING_SIZE; i++) { struct sk_buff *skb; if (i < (RX_RING_SIZE - 1)) vp->rx_ring[i].next = virt_to_bus(&vp->rx_ring[i+1]); else vp->rx_ring[i].next = 0; vp->rx_ring[i].status = 0; /* Clear complete bit. */ vp->rx_ring[i].length = PKT_BUF_SZ | 0x80000000; skb = dev_alloc_skb(PKT_BUF_SZ); vp->rx_skbuff[i] = skb; if (skb == NULL) break; /* Bad news! */ skb->dev = dev; /* Mark as being used by this device. */ skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ vp->rx_ring[i].addr = virt_to_bus(skb->tail); } vp->rx_ring[i-1].next = virt_to_bus(&vp->rx_ring[0]); /* Wrap the ring. */ outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr); } if (vp->full_bus_master_tx) { /* Boomerang bus master Tx. */ vp->cur_tx = vp->dirty_tx = 0; outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */ /* Clear the Tx ring. */ for (i = 0; i < TX_RING_SIZE; i++)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -