📄 3c90x.c
字号:
INF_3C90X.ReceiveUPD.DataLength = 1536 + (1<<31); /** Submit the upload descriptor to the NIC **/ outl(virt_to_bus(&(INF_3C90X.ReceiveUPD)), INF_3C90X.IOAddr + regUpListPtr_l); /** Wait for upload completion (upComplete(15) or upError (14)) **/ for(i=0;i<40000;i++); while((INF_3C90X.ReceiveUPD.UpPktStatus & ((1<<14) | (1<<15))) == 0) for(i=0;i<40000;i++); /** Check for Error (else we have good packet) **/ if (INF_3C90X.ReceiveUPD.UpPktStatus & (1<<14)) { errcode = INF_3C90X.ReceiveUPD.UpPktStatus; if (errcode & (1<<16)) printf("3C90X: Rx Overrun (%hX)\n",errcode>>16); else if (errcode & (1<<17)) printf("3C90X: Runt Frame (%hX)\n",errcode>>16); else if (errcode & (1<<18)) printf("3C90X: Alignment Error (%hX)\n",errcode>>16); else if (errcode & (1<<19)) printf("3C90X: CRC Error (%hX)\n",errcode>>16); else if (errcode & (1<<20)) printf("3C90X: Oversized Frame (%hX)\n",errcode>>16); else printf("3C90X: Packet error (%hX)\n",errcode>>16); return 0; } /** Ok, got packet. Set length in nic->packetlen. **/ nic->packetlen = (INF_3C90X.ReceiveUPD.UpPktStatus & 0x1FFF); return 1; }/*** a3c90x_disable: exported routine to disable the card. What's this for? *** the eepro100.c driver didn't have one, so I just left this one empty too. *** Ideas anyone? *** Must turn off receiver at least so stray packets will not corrupt memory *** [Ken] ***/static voida3c90x_disable(struct nic *nic) { /* Disable the receiver and transmitter. */ outw(cmdRxDisable, INF_3C90X.IOAddr + regCommandIntStatus_w); outw(cmdTxDisable, INF_3C90X.IOAddr + regCommandIntStatus_w); }/*** a3c90x_probe: exported routine to probe for the 3c905 card and perform *** initialization. If this routine is called, the pci functions did find the *** card. We just have to init it here. ***/struct nic*a3c90x_probe(struct nic *nic, unsigned short *probeaddrs, struct pci_device *pci) { int i, c; unsigned short eeprom[0x21]; unsigned int cfg; unsigned int mopt; unsigned short linktype; if (probeaddrs == 0 || probeaddrs[0] == 0) return 0; adjust_pci_device(pci); INF_3C90X.IOAddr = probeaddrs[0] & ~3; INF_3C90X.CurrentWindow = 255; switch (a3c90x_internal_ReadEeprom(INF_3C90X.IOAddr, 0x03)) { case 0x9000: /** 10 Base TPO **/ case 0x9001: /** 10/100 T4 **/ case 0x9050: /** 10/100 TPO **/ case 0x9051: /** 10 Base Combo **/ INF_3C90X.isBrev = 0; break; case 0x9004: /** 10 Base TPO **/ case 0x9005: /** 10 Base Combo **/ case 0x9006: /** 10 Base TPO and Base2 **/ case 0x900A: /** 10 Base FL **/ case 0x9055: /** 10/100 TPO **/ case 0x9056: /** 10/100 T4 **/ case 0x905A: /** 10 Base FX **/ default: INF_3C90X.isBrev = 1; break; } /** Load the EEPROM contents **/ if (INF_3C90X.isBrev) { for(i=0;i<=0x20;i++) { eeprom[i] = a3c90x_internal_ReadEeprom(INF_3C90X.IOAddr, i); }#ifdef CFG_3C90X_BOOTROM_FIX /** Set xcvrSelect in InternalConfig in eeprom. **/ /* only necessary for 3c905b revision cards with boot PROM bug!!! */ a3c90x_internal_WriteEeprom(INF_3C90X.IOAddr, 0x13, 0x0160);#endif#ifdef CFG_3C90X_XCVR if (CFG_3C90X_XCVR == 255) { /** Clear the LanWorks register **/ a3c90x_internal_WriteEeprom(INF_3C90X.IOAddr, 0x16, 0); } else { /** Set the selected permanent-xcvrSelect in the ** LanWorks register **/ a3c90x_internal_WriteEeprom(INF_3C90X.IOAddr, 0x16, XCVR_MAGIC + ((CFG_3C90X_XCVR) & 0x000F)); }#endif } else { for(i=0;i<=0x17;i++) { eeprom[i] = a3c90x_internal_ReadEeprom(INF_3C90X.IOAddr, i); } } /** Print identification message **/ printf("\n\n3C90X Driver 2.00 " "Copyright 1999 LightSys Technology Services, Inc.\n" "Portions Copyright 1999 Steve Smith\n"); printf("Provided with ABSOLUTELY NO WARRANTY.\n"); printf("-------------------------------------------------------" "------------------------\n"); /** Retrieve the Hardware address and print it on the screen. **/ INF_3C90X.HWAddr[0] = eeprom[0]>>8; INF_3C90X.HWAddr[1] = eeprom[0]&0xFF; INF_3C90X.HWAddr[2] = eeprom[1]>>8; INF_3C90X.HWAddr[3] = eeprom[1]&0xFF; INF_3C90X.HWAddr[4] = eeprom[2]>>8; INF_3C90X.HWAddr[5] = eeprom[2]&0xFF; printf("MAC Address = %!\n", INF_3C90X.HWAddr); /** Program the MAC address into the station address registers **/ a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winAddressing2); outw(htons(eeprom[0]), INF_3C90X.IOAddr + regStationAddress_2_3w); outw(htons(eeprom[1]), INF_3C90X.IOAddr + regStationAddress_2_3w+2); outw(htons(eeprom[2]), INF_3C90X.IOAddr + regStationAddress_2_3w+4); outw(0, INF_3C90X.IOAddr + regStationMask_2_3w+0); outw(0, INF_3C90X.IOAddr + regStationMask_2_3w+2); outw(0, INF_3C90X.IOAddr + regStationMask_2_3w+4); /** Fill in our entry in the etherboot arp table **/ for(i=0;i<ETH_ALEN;i++) nic->node_addr[i] = (eeprom[i/2] >> (8*((i&1)^1))) & 0xff; /** Read the media options register, print a message and set default ** xcvr. ** ** Uses Media Option command on B revision, Reset Option on non-B ** revision cards -- same register address **/ a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winTxRxOptions3); mopt = inw(INF_3C90X.IOAddr + regResetMediaOptions_3_w); /** mask out VCO bit that is defined as 10baseFL bit on B-rev cards **/ if (! INF_3C90X.isBrev) { mopt &= 0x7F; } printf("Connectors present: "); c = 0; linktype = 0x0008; if (mopt & 0x01) { printf("%s100Base-T4",(c++)?", ":""); linktype = 0x0006; } if (mopt & 0x04) { printf("%s100Base-FX",(c++)?", ":""); linktype = 0x0005; } if (mopt & 0x10) { printf("%s10Base-2",(c++)?", ":""); linktype = 0x0003; } if (mopt & 0x20) { printf("%sAUI",(c++)?", ":""); linktype = 0x0001; } if (mopt & 0x40) { printf("%sMII",(c++)?", ":""); linktype = 0x0006; } if ((mopt & 0xA) == 0xA) { printf("%s10Base-T / 100Base-TX",(c++)?", ":""); linktype = 0x0008; } else if ((mopt & 0xA) == 0x2) { printf("%s100Base-TX",(c++)?", ":""); linktype = 0x0008; } else if ((mopt & 0xA) == 0x8) { printf("%s10Base-T",(c++)?", ":""); linktype = 0x0008; } printf(".\n"); /** Determine transceiver type to use, depending on value stored in ** eeprom 0x16 **/ if (INF_3C90X.isBrev) { if ((eeprom[0x16] & 0xFF00) == XCVR_MAGIC) { /** User-defined **/ linktype = eeprom[0x16] & 0x000F; } } else {#ifdef CFG_3C90X_XCVR if (CFG_3C90X_XCVR != 255) linktype = CFG_3C90X_XCVR;#endif /* CFG_3C90X_XCVR */ /** I don't know what MII MAC only mode is!!! **/ if (linktype == 0x0009) { if (INF_3C90X.isBrev) printf("WARNING: MII External MAC Mode only supported on B-revision " "cards!!!!\nFalling Back to MII Mode\n"); linktype = 0x0006; } } /** enable DC converter for 10-Base-T **/ if (linktype == 0x0003) { a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdEnableDcConverter, 0); } /** Set the link to the type we just determined. **/ a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winTxRxOptions3); cfg = inl(INF_3C90X.IOAddr + regInternalConfig_3_l); cfg &= ~(0xF<<20); cfg |= (linktype<<20); outl(cfg, INF_3C90X.IOAddr + regInternalConfig_3_l); /** Now that we set the xcvr type, reset the Tx and Rx, re-enable. **/ a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdTxReset, 0x00); while (inw(INF_3C90X.IOAddr + regCommandIntStatus_w) & INT_CMDINPROGRESS) ; if (!INF_3C90X.isBrev) outb(0x01, INF_3C90X.IOAddr + regTxFreeThresh_b); a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdTxEnable, 0); /** ** reset of the receiver on B-revision cards re-negotiates the link ** takes several seconds (a computer eternity) **/ if (INF_3C90X.isBrev) a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdRxReset, 0x04); else a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdRxReset, 0x00); while (inw(INF_3C90X.IOAddr + regCommandIntStatus_w) & INT_CMDINPROGRESS) ; /** Set the RX filter = receive only individual pkts & bcast. **/ a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdSetRxFilter, 0x01 + 0x04); a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdRxEnable, 0); /** ** set Indication and Interrupt flags , acknowledge any IRQ's **/ a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdSetInterruptEnable, 0); a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdSetIndicationEnable, 0x0014); a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdAcknowledgeInterrupt, 0x661); /** Set our exported functions **/ nic->reset = a3c90x_reset; nic->poll = a3c90x_poll; nic->transmit = a3c90x_transmit; nic->disable = a3c90x_disable; return nic; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -