📄 etherelnk3x.c
字号:
}typedef struct Adapter { int port; int irq; int tbdf;} Adapter;static Block* adapter;static voidtcmadapter(int port, int irq, int tbdf){ Block *bp; Adapter *ap; bp = allocb(sizeof(Adapter)); ap = (Adapter*)bp->rp; ap->port = port; ap->irq = irq; ap->tbdf = tbdf; bp->next = adapter; adapter = bp;}/* * Write two 0 bytes to identify the IDport and then reset the * ID sequence. Then send the ID sequence to the card to get * the card into command state. */static voididseq(void){ int i; uchar al; static int reset, untag; /* * One time only: * reset any adapters listening */ if(reset == 0){ outb(IDport, 0); outb(IDport, 0); outb(IDport, 0xC0); delay(20); reset = 1; } outb(IDport, 0); outb(IDport, 0); for(al = 0xFF, i = 0; i < 255; i++){ outb(IDport, al); if(al & 0x80){ al <<= 1; al ^= 0xCF; } else al <<= 1; } /* * One time only: * write ID sequence to get the attention of all adapters; * untag all adapters. * If we do a global reset here on all adapters we'll confuse any * ISA cards configured for EISA mode. */ if(untag == 0){ outb(IDport, 0xD0); untag = 1; }}static ulongactivate(void){ int i; ushort x, acr; /* * Do the little configuration dance: * * 2. write the ID sequence to get to command state. */ idseq(); /* * 3. Read the Manufacturer ID from the EEPROM. * This is done by writing the IDPort with 0x87 (0x80 * is the 'read EEPROM' command, 0x07 is the offset of * the Manufacturer ID field in the EEPROM). * The data comes back 1 bit at a time. * We seem to need a delay here between reading the bits. * * If the ID doesn't match, there are no more adapters. */ outb(IDport, 0x87); delay(20); for(x = 0, i = 0; i < 16; i++){ delay(20); x <<= 1; x |= inb(IDport) & 0x01; } if(x != 0x6D50) return 0; /* * 3. Read the Address Configuration from the EEPROM. * The Address Configuration field is at offset 0x08 in the EEPROM). */ outb(IDport, 0x88); for(acr = 0, i = 0; i < 16; i++){ delay(20); acr <<= 1; acr |= inb(IDport) & 0x01; } return (acr & 0x1F)*0x10 + 0x200;}#ifdef notjustpcmciastatic voidtcm509isa(void){ int irq, port; /* * Attempt to activate all adapters. If adapter is set for * EISA mode (0x3F0), tag it and ignore. Otherwise, activate * it fully. */ while(port = activate()){ /* * 6. Tag the adapter so it won't respond in future. */ outb(IDport, 0xD1); if(port == 0x3F0) continue; /* * 6. Activate the adapter by writing the Activate command * (0xFF). */ outb(IDport, 0xFF); delay(20); /* * 8. Can now talk to the adapter's I/O base addresses. * Use the I/O base address from the acr just read. * * Enable the adapter and clear out any lingering status * and interrupts. */ while(STATUS(port) & commandInProgress) ; COMMAND(port, SelectRegisterWindow, Wsetup); outs(port+ConfigControl, Ena); COMMAND(port, TxReset, 0); COMMAND(port, RxReset, 0); COMMAND(port, AcknowledgeInterrupt, 0xFF); irq = (ins(port+ResourceConfig)>>12) & 0x0F; tcmadapter(port, irq, BUSUNKNOWN); }}static voidtcm5XXeisa(void){ ushort x; int irq, port, slot; /* * Check if this is an EISA machine. * If not, nothing to do. */ if(strncmp((char*)(KZERO|0xFFFD9), "EISA", 4)) return; /* * Continue through the EISA slots looking for a match on both * 3COM as the manufacturer and 3C579-* or 3C59[27]-* as the product. * If an adapter is found, select window 0, enable it and clear * out any lingering status and interrupts. */ for(slot = 1; slot < MaxEISA; slot++){ port = slot*0x1000; if(ins(port+0xC80+ManufacturerID) != 0x6D50) continue; x = ins(port+0xC80+ProductID); if((x & 0xF0FF) != 0x9050 && (x & 0xFF00) != 0x5900) continue; COMMAND(port, SelectRegisterWindow, Wsetup); outs(port+ConfigControl, Ena); COMMAND(port, TxReset, 0); COMMAND(port, RxReset, 0); COMMAND(port, AcknowledgeInterrupt, 0xFF); irq = (ins(port+ResourceConfig)>>12) & 0x0F; tcmadapter(port, irq, BUSUNKNOWN); }}static voidtcm59Xpci(void){ Pcidev *p; int irq, port; p = nil; while(p = pcimatch(p, 0x10B7, 0)){ port = p->mem[0].bar & ~0x01; irq = p->intl; COMMAND(port, GlobalReset, 0); while(STATUS(port) & commandInProgress) ; tcmadapter(port, irq, p->tbdf); }}#endif /* notjustpcmcia */static char* tcmpcmcia[] = { "3C589", /* 3COM 589[ABCD] */ "3C562", /* 3COM 562 */ "589E", /* 3COM Megahertz 589E */ nil,};static inttcm5XXpcmcia(Ether* ether){ int i; for(i = 0; tcmpcmcia[i] != nil; i++){ if(!cistrcmp(ether->type, tcmpcmcia[i])) return ether->port; } return 0;}static intautoselect(int port, int rxstatus9){ int media, x; /* * Pathetic attempt at automatic media selection. * Really just to get the Fast Etherlink 10BASE-T/100BASE-TX * cards operational. */ media = auiAvailable|coaxAvailable|base10TAvailable; if(rxstatus9 == 0){ COMMAND(port, SelectRegisterWindow, Wfifo); media = ins(port+ResetOptions); } if(media & miiConnector) return xcvrMii; if(media & baseTXAvailable){ /* * Must have InternalConfig register. */ COMMAND(port, SelectRegisterWindow, Wfifo); x = inl(port+InternalConfig) & ~xcvrMask; x |= xcvr100BaseTX; outl(port+InternalConfig, x); COMMAND(port, TxReset, 0); while(STATUS(port) & commandInProgress) ; COMMAND(port, RxReset, 0); while(STATUS(port) & commandInProgress) ; COMMAND(port, SelectRegisterWindow, Wdiagnostic); x = ins(port+MediaStatus) & ~(dcConverterEnabled|jabberGuardEnable); outs(port+MediaStatus, linkBeatEnable|x); delay(10);{ int i, v; for(i = 0; i < 10000; i++){ v = ins(port+MediaStatus); if(v & linkBeatDetect){ print("count %d v %uX\n", i, v); return xcvr100BaseTX; } delay(1); }print("count %d v %uX\n", i, ins(port+MediaStatus));} if(ins(port+MediaStatus) & linkBeatDetect) return xcvr100BaseTX; outs(port+MediaStatus, x); } if(media & base10TAvailable){ if(rxstatus9 == 0){ COMMAND(port, SelectRegisterWindow, Wfifo); x = inl(port+InternalConfig) & ~xcvrMask; x |= xcvr10BaseT; outl(port+InternalConfig, x); } else{ COMMAND(port, SelectRegisterWindow, Wsetup); x = ins(port+AddressConfig) & ~xcvrMask9; x |= (xcvr10BaseT>>20)<<14; outs(port+AddressConfig, x); } COMMAND(port, TxReset, 0); while(STATUS(port) & commandInProgress) ; COMMAND(port, RxReset, 0); while(STATUS(port) & commandInProgress) ; COMMAND(port, SelectRegisterWindow, Wdiagnostic); x = ins(port+MediaStatus) & ~dcConverterEnabled; outs(port+MediaStatus, linkBeatEnable|jabberGuardEnable|x); delay(10); if(ins(port+MediaStatus) & linkBeatDetect) return xcvr10BaseT; outs(port+MediaStatus, x); } /* * Botch. */ return autoSelect;}static inteepromdata(int port, int offset){ COMMAND(port, SelectRegisterWindow, Wsetup); while(EEPROMBUSY(port)) ; EEPROMCMD(port, EepromReadRegister, offset); while(EEPROMBUSY(port)) ; return EEPROMDATA(port);}intelnk3reset(Ether* ether){ int did, i, port, rxstatus9, x, xcvr; Block *bp, **bpp; Adapter *ap; uchar ea[Eaddrlen]; Ctlr *ctlr;#ifdef notjustpcmcia static int scandone; /* * Scan for adapter on PCI, EISA and finally * using the little ISA configuration dance. */ if(scandone == 0){ tcm59Xpci(); tcm5XXeisa(); tcm509isa(); scandone = 1; }#endif /* notjustpcmcia */ /* * Any adapter matches if no ether->port is supplied, * otherwise the ports must match. */ port = 0; bpp = &adapter; for(bp = *bpp; bp; bp = bp->next){ ap = (Adapter*)bp->rp; if(ether->port == 0 || ether->port == ap->port){ port = ap->port; ether->irq = ap->irq; ether->tbdf = ap->tbdf; *bpp = bp->next; freeb(bp); break; } bpp = &bp->next; } if(port == 0 && (port = tcm5XXpcmcia(ether)) == 0) return -1; /* * Read the DeviceID from the EEPROM, it's at offset 0x03, * and do something depending on capabilities. */ switch(did = eepromdata(port, 0x03)){ case 0x9000: case 0x9001: case 0x9050: case 0x9051: if(BUSTYPE(ether->tbdf) != BusPCI) goto buggery; goto vortex; case 0x5900: case 0x5920: case 0x5950: case 0x5951: case 0x5952: case 0x5970: case 0x5971: case 0x5972: vortex: COMMAND(port, SelectRegisterWindow, Wfifo); xcvr = inl(port+InternalConfig) & (autoSelect|xcvrMask); rxstatus9 = 0; break; buggery: default: COMMAND(port, SelectRegisterWindow, Wsetup); x = ins(port+AddressConfig); xcvr = ((x & xcvrMask9)>>14)<<20; if(x & autoSelect9) xcvr |= autoSelect; rxstatus9 = 1; break; } USED(did); /* * Check if the adapter's station address is to be overridden. * If not, read it from the EEPROM and set in ether->ea prior to loading the * station address in Wstation. The EEPROM returns 16-bits at a time. */ memset(ea, 0, Eaddrlen); if(memcmp(ea, ether->ea, Eaddrlen) == 0){ for(i = 0; i < Eaddrlen/2; i++){ x = eepromdata(port, i); ether->ea[2*i] = x>>8; ether->ea[2*i+1] = x; } } COMMAND(port, SelectRegisterWindow, Wstation); for(i = 0; i < Eaddrlen; i++) outb(port+i, ether->ea[i]); /* * Enable the transceiver if necessary. */ if(xcvr & autoSelect) xcvr = autoselect(port, rxstatus9); switch(xcvr){ case xcvrMii: break; case xcvr100BaseTX: case xcvr100BaseFX: COMMAND(port, SelectRegisterWindow, Wfifo); x = inl(port+InternalConfig) & ~ramPartitionMask; outl(port+InternalConfig, x|ramPartition1to1); COMMAND(port, SelectRegisterWindow, Wdiagnostic); x = ins(port+MediaStatus) & ~(dcConverterEnabled|jabberGuardEnable); x |= linkBeatEnable; outs(port+MediaStatus, x); break; case xcvr10BaseT: /* * Enable Link Beat and Jabber to start the * transceiver. */ COMMAND(port, SelectRegisterWindow, Wdiagnostic); x = ins(port+MediaStatus) & ~dcConverterEnabled; x |= linkBeatEnable|jabberGuardEnable; outs(port+MediaStatus, x); break; case xcvr10Base2: COMMAND(port, SelectRegisterWindow, Wdiagnostic); x = ins(port+MediaStatus) & ~(linkBeatEnable|jabberGuardEnable); outs(port+MediaStatus, x); /* * Start the DC-DC converter. * Wait > 800 microseconds. */ COMMAND(port, EnableDcConverter, 0); delay(1); break; } /* * Wop is the normal operating register set. * The 3C59[0257] adapters allow access to more than one register window * at a time, but there are situations where switching still needs to be * done, so just do it. * Clear out any lingering Tx status. */ COMMAND(port, SelectRegisterWindow, Wop); while(inb(port+TxStatus)) outb(port+TxStatus, 0); /* * Allocate a controller structure and start * to initialise it. */ ether->ctlr = malloc(sizeof(Ctlr)); ctlr = ether->ctlr; memset(ctlr, 0, sizeof(Ctlr)); /* * Set a base TxStartThresh which will be incremented * if any txUnderrun errors occur and ensure no RxEarly * interrupts happen. */ ctlr->txthreshold = ETHERMINTU; COMMAND(port, SetTxStartThresh, ETHERMINTU); COMMAND(port, SetRxEarlyThresh, ETHERMAXTU); /* * Set up the software configuration. */ ether->port = port; ether->attach = attach; ether->transmit = transmit; ether->interrupt = interrupt; return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -