📄 3c515.c
字号:
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 net_device *root_corkscrew_dev = NULL;int init_module(void){ int cards_found; if (debug >= 0) corkscrew_debug = debug; if (corkscrew_debug) printk(version); root_corkscrew_dev = NULL; cards_found = corkscrew_scan(0); return cards_found ? 0 : -ENODEV;}#elseint tc515_probe(struct net_device *dev){ int cards_found = 0; SET_MODULE_OWNER(dev); cards_found = corkscrew_scan(dev); if (corkscrew_debug > 0 && cards_found) printk(version); return cards_found ? 0 : -ENODEV;}#endif /* not MODULE */static int corkscrew_scan(struct net_device *dev){ int cards_found = 0; static int ioaddr;#ifdef __ISAPNP__ short i; static int pnp_cards = 0;#endif#ifdef __ISAPNP__ if(nopnp == 1) goto no_pnp; for(i=0; corkscrew_isapnp_adapters[i].vendor != 0; i++) { struct pci_dev *idev = NULL; int irq; while((idev = isapnp_find_dev(NULL, corkscrew_isapnp_adapters[i].vendor, corkscrew_isapnp_adapters[i].function, idev))) { if(idev->active) idev->deactivate(idev); if(idev->prepare(idev)<0) continue; if (!(idev->resource[0].flags & IORESOURCE_IO)) continue; if(idev->activate(idev)<0) { printk("isapnp configure failed (out of resources?)\n"); return -ENOMEM; } if (!idev->resource[0].start || check_region(idev->resource[0].start,16)) continue; ioaddr = idev->resource[0].start; irq = idev->irq_resource[0].start; if(corkscrew_debug) printk ("ISAPNP reports %s at i/o 0x%x, irq %d\n", corkscrew_isapnp_adapters[i].name,ioaddr, irq); 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(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); /* irq = inw(ioaddr + 0x2002) & 15; */ /* Use the irq from isapnp */ corkscrew_isapnp_phys_addr[pnp_cards] = ioaddr; corkscrew_found_device(dev, ioaddr, irq, CORKSCREW_ID, dev && dev->mem_start ? dev-> mem_start : options[cards_found]); dev = 0; pnp_cards++; cards_found++; } }no_pnp:#endif /* not __ISAPNP__ */ /* Check all locations on the ISA bus -- evil! */ for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) { int irq;#ifdef __ISAPNP__ /* Make sure this was not already picked up by isapnp */ if(ioaddr == corkscrew_isapnp_phys_addr[0]) continue; if(ioaddr == corkscrew_isapnp_phys_addr[1]) continue; if(ioaddr == corkscrew_isapnp_phys_addr[2]) continue;#endif 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(KERN_INFO "3c515 Resource configuration register %#4.4x, DCR %4.4x.\n", inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); irq = inw(ioaddr + 0x2002) & 15; corkscrew_found_device(dev, ioaddr, irq, CORKSCREW_ID, dev && dev->mem_start ? dev-> mem_start : options[cards_found]); dev = 0; cards_found++; } if (corkscrew_debug) printk(KERN_INFO "%d 3c515 cards found.\n", cards_found); return cards_found;}static struct net_device *corkscrew_found_device(struct net_device *dev, int ioaddr, int irq, int product_index, int options){ struct corkscrew_private *vp;#ifdef MODULE /* Allocate and fill new device structure. */ int dev_size = sizeof(struct net_device) + sizeof(struct corkscrew_private) + 15; /* Pad for alignment */ dev = (struct net_device *) kmalloc(dev_size, GFP_KERNEL); if (!dev) return NULL; memset(dev, 0, dev_size); /* Align the Rx and Tx ring entries. */ dev->priv = (void *) (((long) dev + sizeof(struct net_device) + 15) & ~15); vp = (struct corkscrew_private *) dev->priv; dev->base_addr = ioaddr; dev->irq = irq; dev->dma = (product_index == CORKSCREW_ID ? inw(ioaddr + 0x2000) & 7 : 0); dev->init = corkscrew_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_corkscrew_dev; root_corkscrew_dev = dev; if (register_netdev(dev) != 0) { kfree(dev); return NULL; } SET_MODULE_OWNER(dev);#else /* not a MODULE */ /* Caution: quad-word alignment required for rings! */ dev->priv = kmalloc(sizeof(struct corkscrew_private), GFP_KERNEL); memset(dev->priv, 0, sizeof(struct corkscrew_private)); dev = init_etherdev(dev, sizeof(struct corkscrew_private)); dev->base_addr = ioaddr; dev->irq = irq; dev->dma = (product_index == CORKSCREW_ID ? inw(ioaddr + 0x2000) & 7 : 0); vp = (struct corkscrew_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; } corkscrew_probe1(dev);#endif /* MODULE */ return dev;}static int corkscrew_probe1(struct net_device *dev){ int ioaddr = dev->base_addr; struct corkscrew_private *vp = (struct corkscrew_private *) dev->priv; unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ int i; printk(KERN_INFO "%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 (corkscrew_debug && (dev->irq <= 0 || dev->irq > 15)) printk(KERN_WARNING " *** 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 (corkscrew_debug > 1) printk(KERN_INFO " Internal config register is %4.4x, transceivers %#x.\n", config.i, inw(ioaddr + Wn3_Options)); printk(KERN_INFO " %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(KERN_INFO " 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 3c51x-specific entries in the device structure. */ dev->open = &corkscrew_open; dev->hard_start_xmit = &corkscrew_start_xmit; dev->tx_timeout = &corkscrew_timeout; dev->watchdog_timeo = (400 * HZ) / 1000; dev->stop = &corkscrew_close; dev->get_stats = &corkscrew_get_stats; dev->set_multicast_list = &set_rx_mode; return 0;}static int corkscrew_open(struct net_device *dev){ int ioaddr = dev->base_addr; struct corkscrew_private *vp = (struct corkscrew_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 (corkscrew_debug > 1) printk(KERN_INFO "%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 (corkscrew_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 = &corkscrew_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 (corkscrew_debug > 1) { printk("%s: corkscrew_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, &corkscrew_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, &corkscrew_interrupt, SA_SHIRQ, vp->product_name, dev)) { return -EAGAIN; } if (corkscrew_debug > 1) { EL3WINDOW(4); printk("%s: corkscrew_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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -