📄 3c90x.c
字号:
debug_print("3C90X: Runt Frame (%hX)\n",errcode>>16);
else if (errcode & (1<<18))
debug_print("3C90X: Alignment Error (%hX)\n",errcode>>16);
else if (errcode & (1<<19))
debug_print("3C90X: CRC Error (%hX)\n",errcode>>16);
else if (errcode & (1<<20))
debug_print("3C90X: Oversized Frame (%hX)\n",errcode>>16);
else
debug_print("3C90X: Packet error (%hX)\n",errcode>>16);
return 0;
}
/** Ok, got packet. Set length in nic->packetlen. **/
*buflen = (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 void
a3c90x_disable(struct nic *nic)
{
/* Disable the receiver and transmitter. */
NETCARD_OUTW(cmdRxDisable, INF_3C90X.IOAddr + regCommandIntStatus_w);
NETCARD_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.
***/
int
a3c90x_probe(struct nic *nic)
{
int i, c;
struct pci_device *pci = nic->pci_data;
unsigned short eeprom[0x21];
unsigned long cfg;
unsigned long mopt;
unsigned short linktype;
unsigned short pci_command;
unsigned short new_command;
unsigned char pci_latency;
if (nic->ioaddr == 0)
return -1;
if (pci == NULL)
return -1;
/* Make certain the card is properly set up as a bus master. */
pcibios_read_config_word(pci->bus, pci->devfn, PCI_COMMAND, &pci_command);
new_command = pci_command | PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
if (pci_command != new_command) {
debug_print("\nThe PCI BIOS has not enabled this device!\nUpdating PCI command %hX->%hX. pci_bus %hhX pci_device_fn %hhX\n",
pci_command, new_command, pci->bus, pci->devfn);
pcibios_write_config_word(pci->bus, pci->devfn, PCI_COMMAND, new_command);
}
pcibios_read_config_byte(pci->bus, pci->devfn, PCI_LATENCY_TIMER, &pci_latency);
if (pci_latency < 32) {
debug_print("\nPCI latency timer (CFLT) is unreasonably low at %d. Setting to 32 clocks.\n", pci_latency);
pcibios_write_config_byte(pci->bus, pci->devfn, PCI_LATENCY_TIMER, 32);
}
INF_3C90X.IOAddr = nic->ioaddr;
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 **/
debug_print("\n\n3C90X Driver 2.00 "
"Copyright 1999 LightSys Technology Services, Inc.\n"
"Portions Copyright 1999 Steve Smith\n");
debug_print("Provided with ABSOLUTELY NO WARRANTY.\n");
debug_print("-------------------------------------------------------"
"------------------------\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;
debug_print_buf("MAC Address:", INF_3C90X.HWAddr,ETH_ALEN);
/** Program the MAC address into the station address registers **/
a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winAddressing2);
NETCARD_OUTW(htons(eeprom[0]), INF_3C90X.IOAddr + regStationAddress_2_3w);
NETCARD_OUTW(htons(eeprom[1]), INF_3C90X.IOAddr + regStationAddress_2_3w+2);
NETCARD_OUTW(htons(eeprom[2]), INF_3C90X.IOAddr + regStationAddress_2_3w+4);
NETCARD_OUTW(0, INF_3C90X.IOAddr + regStationMask_2_3w+0);
NETCARD_OUTW(0, INF_3C90X.IOAddr + regStationMask_2_3w+2);
NETCARD_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 = NETCARD_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;
}
debug_print("Connectors present: ");
c = 0;
linktype = 0x0008;
if (mopt & 0x01)
{
debug_print("%s100Base-T4",(c++)?", ":"");
linktype = 0x0006;
}
if (mopt & 0x04)
{
debug_print("%s100Base-FX",(c++)?", ":"");
linktype = 0x0005;
}
if (mopt & 0x10)
{
debug_print("%s10Base-2",(c++)?", ":"");
linktype = 0x0003;
}
if (mopt & 0x20)
{
debug_print("%sAUI",(c++)?", ":"");
linktype = 0x0001;
}
if (mopt & 0x40)
{
debug_print("%sMII",(c++)?", ":"");
linktype = 0x0006;
}
if ((mopt & 0xA) == 0xA)
{
debug_print("%s10Base-T / 100Base-TX",(c++)?", ":"");
linktype = 0x0008;
}
else if ((mopt & 0xA) == 0x2)
{
debug_print("%s100Base-TX",(c++)?", ":"");
linktype = 0x0008;
}
else if ((mopt & 0xA) == 0x8)
{
debug_print("%s10Base-T",(c++)?", ":"");
linktype = 0x0008;
}
debug_print(".\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)
debug_print("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 = NETCARD_IND(INF_3C90X.IOAddr + regInternalConfig_3_l);
cfg &= ~(0xF<<20);
cfg |= (linktype<<20);
NETCARD_OUTD(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 (NETCARD_INW(INF_3C90X.IOAddr + regCommandIntStatus_w) & INT_CMDINPROGRESS)
;
if (!INF_3C90X.isBrev)
NETCARD_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 (NETCARD_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);
nic->disable = a3c90x_disable;
nic->poll = a3c90x_poll;
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -