📄 3c515.c
字号:
vp->cur_rx = vp->dirty_rx = 0; if (corkscrew_debug > 2) printf(" Filling in the Rx ring.\n"); for (i = 0; i < RX_RING_SIZE; i++) { printf("FIXME: Is this if necessary"); } } 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++) vp->tx_skbuff[i] = 0; outl(0, ioaddr + DownListPtr); } /* Set receiver mode: presumably accept b-case and phys addr only. */ outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm, ioaddr + EL3_CMD); outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */ outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */ /* Allow status bits to be seen. */ outw(SetStatusEnb | AdapterFailure | IntReq | StatsFull | (vp->full_bus_master_tx ? DownComplete : TxAvailable) | (vp->full_bus_master_rx ? UpComplete : RxComplete) | (vp->bus_master ? DMADone : 0), ioaddr + EL3_CMD); /* Ack all pending events, and set active indicator mask. */ outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, ioaddr + EL3_CMD); outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull | (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete, ioaddr + EL3_CMD);}/**************************************************************************POLL - Wait for a frame***************************************************************************/static int t515_poll(struct nic *nic){ short status, cst; register short rx_fifo; cst = inw(BASE + EL3_STATUS); if ((cst & RxComplete) == 0) { /* Ack all pending events, and set active indicator mask. */ outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq, BASE + EL3_CMD); outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull | (vp-> bus_master ? DMADone : 0) | UpComplete | DownComplete, BASE + EL3_CMD); return 0; } status = inw(BASE + RxStatus); if (status & RxDError) { printf("RxDError\n"); outw(RxDiscard, BASE + EL3_CMD); return 0; } rx_fifo = status & RX_BYTES_MASK; if (rx_fifo == 0) return 0;#ifdef EDEBUG printf("[l=%d", rx_fifo);#endif insw(BASE + RX_FIFO, nic->packet, rx_fifo / 2); if (rx_fifo & 1) nic->packet[rx_fifo - 1] = inb(BASE + RX_FIFO); nic->packetlen = rx_fifo; while (1) { status = inw(BASE + RxStatus);#ifdef EDEBUG printf("0x%hX*", status);#endif rx_fifo = status & RX_BYTES_MASK; if (rx_fifo > 0) { insw(BASE + RX_FIFO, nic->packet + nic->packetlen, rx_fifo / 2); if (rx_fifo & 1) nic->packet[nic->packetlen + rx_fifo - 1] = inb(BASE + RX_FIFO); nic->packetlen += rx_fifo;#ifdef EDEBUG printf("+%d", rx_fifo);#endif } if ((status & RxComplete) == 0) {#ifdef EDEBUG printf("=%d", nic->packetlen);#endif break; } udelay(1000); } /* acknowledge reception of packet */ outw(RxDiscard, BASE + EL3_CMD); while (inw(BASE + EL3_STATUS) & CmdInProgress);#ifdef EDEBUG { unsigned short type = 0; type = (nic->packet[12] << 8) | nic->packet[13]; if (nic->packet[0] + nic->packet[1] + nic->packet[2] + nic->packet[3] + nic->packet[4] + nic->packet[5] == 0xFF * ETH_ALEN) printf(",t=0x%hX,b]", type); else printf(",t=0x%hX]", type); }#endif return 1;}/************************************************************************* 3Com 515 - specific routines**************************************************************************/static char padmap[] = { 0, 3, 2, 1};/**************************************************************************TRANSMIT - Transmit a frame***************************************************************************/static void t515_transmit(struct nic *nic, const char *d, /* Destination */ unsigned int t, /* Type */ unsigned int s, /* size */ const char *p){ /* Packet */ register int len; int pad; int status;#ifdef EDEBUG printf("{l=%d,t=0x%hX}", s + ETH_HLEN, t);#endif /* swap bytes of type */ t = htons(t); len = s + ETH_HLEN; /* actual length of packet */ pad = padmap[len & 3]; /* * The 3c515 automatically pads short packets to minimum ethernet length, * but we drop packets that are too large. Perhaps we should truncate * them instead? Copied from 3c595. Is this true for the 3c515? */ if (len + pad > ETH_FRAME_LEN) { return; } /* drop acknowledgements */ while ((status = inb(BASE + TxStatus)) & TxComplete) { /*if(status & (TXS_UNDERRUN|0x88|TXS_STATUS_OVERFLOW)) { */ outw(TxReset, BASE + EL3_CMD); outw(TxEnable, BASE + EL3_CMD);/* } */ outb(0x0, BASE + TxStatus); } while (inw(BASE + TxFree) < len + pad + 4) { /* no room in FIFO */ } outw(len, BASE + TX_FIFO); outw(0x0, BASE + TX_FIFO); /* Second dword meaningless */ /* write packet */ outsw(BASE + TX_FIFO, d, ETH_ALEN / 2); outsw(BASE + TX_FIFO, nic->node_addr, ETH_ALEN / 2); outw(t, BASE + TX_FIFO); outsw(BASE + TX_FIFO, p, s / 2); if (s & 1) outb(*(p + s - 1), BASE + TX_FIFO); while (pad--) outb(0, BASE + TX_FIFO); /* Padding */ /* wait for Tx complete */ while ((inw(BASE + EL3_STATUS) & CmdInProgress) != 0);}/**************************************************************************DISABLE - Turn off ethernet interface***************************************************************************/static void t515_disable(struct dev *dev){ struct nic *nic = (struct nic *) dev; /* merge reset an disable */ t515_reset(nic); /* This is a hack. Since ltsp worked on my system without any disable functionality I have no way to determine if this works */ /* Disable the receiver and transmitter. */ outw(RxDisable, BASE + EL3_CMD); outw(TxDisable, BASE + EL3_CMD); if (if_port == XCVR_10base2) /* Turn off thinnet power. Green! */ outw(StopCoax, BASE + EL3_CMD); outw(SetIntrEnb | 0x0000, BASE + EL3_CMD);#ifdef ISA_PNP /*Deactivate *//* ACTIVATE; WRITE_DATA(0); */#endif return;}/**************************************************************************PROBE - Look for an adapter, this routine's visible to the outsideYou should omit the last argument struct pci_device * for a non-PCI NIC***************************************************************************/void config_pnp_device(void);static int t515_probe(struct dev *dev, unsigned short *probe_addrs __unused){ struct nic *nic = (struct nic *) dev; /* Direct copy from Beckers 3c515.c removing any ISAPNP sections */ int cards_found = 0; static int ioaddr;#ifdef ISA_PNP config_pnp_device();#endif /* Check all locations on the ISA bus -- evil! */ for (ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20) { int irq; /* 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--) { t3c515_wait(1); if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0) break; } if (inw(ioaddr + Wn0EepromData) != 0x6d50) continue; } printf ("3c515 Resource configuration register 0x%hX, DCR 0x%hX.\n", inl(ioaddr + 0x2002), inw(ioaddr + 0x2000)); irq = inw(ioaddr + 0x2002) & 15; BASE = ioaddr; corkscrew_found_device(BASE, irq, CORKSCREW_ID, options[cards_found], nic); cards_found++; } if (corkscrew_debug) printf("%d 3c515 cards found.\n", cards_found); if (cards_found > 0) { t515_reset(nic); dev->disable = t515_disable; nic->poll = t515_poll; nic->transmit = t515_transmit; /* Based on PnP ISA map */ dev->devid.vendor_id = htons(ISAPNP_VENDOR('T', 'C', 'M')); dev->devid.device_id = htons(0x5051); return 1; } else return 0;}static intcorkscrew_found_device(int ioaddr, int irq, int product_index, int options, struct nic *nic){ /* Direct copy from Becker 3c515.c with unecessary parts removed */ 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(ioaddr, irq, product_index, nic); return 0;}static intcorkscrew_probe1(int ioaddr, int irq, int product_index __unused, struct nic *nic){ unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ int i; ioaddr = BASE; printf("3Com %s at 0x%hX, ", vp->product_name, ioaddr); /* Read the station address from the EEPROM. */ EL3WINDOW(0); for (i = 0; i < 0x18; i++) { short *phys_addr = (short *) nic->node_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--) { t3c515_wait(1); if ((inw(ioaddr + Wn0EepromCmd) & 0x0200) == 0) break; } eeprom[i] = inw(ioaddr + Wn0EepromData);#ifdef EDEBUG1 printf("Value %d: %hX ", i, eeprom[i]);#endif checksum ^= eeprom[i]; if (i < 3) phys_addr[i] = htons(eeprom[i]); } checksum = (checksum ^ (checksum >> 8)) & 0xff; if (checksum != 0x00) printf(" ***INVALID CHECKSUM 0x%hX*** ", checksum); printf("%!", nic->node_addr); if (eeprom[16] == 0x11c7) { /* Corkscrew */ } printf(", IRQ %d\n", irq); /* Tell them about an invalid IRQ. */ if (corkscrew_debug && (irq <= 0 || irq > 15)) printf (" *** 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) printf (" Internal config register is %4.4x, transceivers 0x%hX.\n", config.i, inw(ioaddr + Wn3_Options)); printf (" %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); if_port = config.u.xcvr; vp->default_media = config.u.xcvr; vp->autoselect = config.u.autoselect; } if (vp->media_override != 7) { printf(" Media override to transceiver type %d (%s).\n", vp->media_override, media_tbl[vp->media_override].name); 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; return 0;}static struct isa_driver t515_driver __isa_driver = { .type = NIC_DRIVER, .name = "3C515", .probe = t515_probe, .ioaddrs = 0,};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -