📄 3c90x.c
字号:
/** Burn the new data into the eeprom, and wait for completion. **/
NETCARD_OUTW(address + ((0x01)<<6), ioaddr + regEepromCommand_0_w);
while((1<<15) & NETCARD_INW(ioaddr + regEepromCommand_0_w));
return 0;
}
/*** a3c90x_internal_WriteEeprom - write data to the serial eeprom,
*** and re-compute the eeprom checksum.
***/
static int
a3c90x_internal_WriteEeprom(unsigned short ioaddr, int address, unsigned short value)
{
int cksum = 0,v;
int i;
int maxAddress, cksumAddress;
if (INF_3C90X.isBrev)
{
maxAddress=0x1f;
cksumAddress=0x20;
}
else
{
maxAddress=0x16;
cksumAddress=0x17;
}
/** Write the value. **/
if (a3c90x_internal_WriteEepromWord(ioaddr, address, value) == -1)
return -1;
/** Recompute the checksum. **/
for(i=0;i<=maxAddress;i++)
{
v = a3c90x_internal_ReadEeprom(ioaddr, i);
cksum ^= (v & 0xFF);
cksum ^= ((v>>8) & 0xFF);
}
/** Write the checksum to the location in the eeprom **/
if (a3c90x_internal_WriteEepromWord(ioaddr, cksumAddress, cksum) == -1)
return -1;
return 0;
}
#if 0
/*** a3c90x_reset: exported function that resets the card to its default
*** state. This is so the Linux driver can re-set the card up the way
*** it wants to. If CFG_3C90X_PRESERVE_XCVR is defined, then the reset will
*** not alter the selected transceiver that we used to download the boot
*** image.
***/
static void
a3c90x_reset(struct nic *nic)
{
int cfg;
#ifdef CFG_3C90X_PRESERVE_XCVR
/** Read the current InternalConfig value. **/
a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winTxRxOptions3);
cfg = NETCARD_IND(INF_3C90X.IOAddr + regInternalConfig_3_l);
#endif
/** Send the reset command to the card **/
debug_print("Issuing RESET:\n");
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdGlobalReset, 0);
/** wait for reset command to complete **/
while (NETCARD_INW(INF_3C90X.IOAddr + regCommandIntStatus_w) & INT_CMDINPROGRESS);
/** global reset command resets station mask, non-B revision cards
** require explicit reset of values
**/
a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winAddressing2);
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);
#ifdef CFG_3C90X_PRESERVE_XCVR
/** Re-set the original InternalConfig value from before reset **/
a3c90x_internal_SetWindow(INF_3C90X.IOAddr, winTxRxOptions3);
NETCARD_OUTD(cfg, INF_3C90X.IOAddr + regInternalConfig_3_l);
/** enable DC converter for 10-Base-T **/
if ((cfg&0x0300) == 0x0300)
{
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdEnableDcConverter, 0);
}
#endif
/** Issue transmit reset, wait for command completion **/
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdTxReset, 0);
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);
;
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdRxEnable, 0);
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr,
cmdSetInterruptEnable, 0);
/** enable rxComplete and txComplete **/
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr,
cmdSetIndicationEnable, 0x0014);
/** acknowledge any pending status flags **/
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr,
cmdAcknowledgeInterrupt, 0x661);
return;
}
/*** a3c90x_transmit: exported function that transmits a packet. Does not
*** return any particular status. Parameters are:
*** d[6] - destination address, ethernet;
*** t - protocol type (ARP, IP, etc);
*** s - size of the non-header part of the packet that needs transmitted;
*** p - the pointer to the packet data itself.
***/
static void
a3c90x_transmit(struct nic *nic, const char *d, unsigned long t,
unsigned long s, const char *p)
{
struct eth_hdr
{
unsigned char dst_addr[ETH_ALEN];
unsigned char src_addr[ETH_ALEN];
unsigned short type;
} hdr;
unsigned char status;
unsigned i, retries;
for (retries=0; retries < XMIT_RETRIES ; retries++)
{
/** Stall the download engine **/
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdStallCtl, 2);
/** Make sure the card is not waiting on us **/
NETCARD_INW(INF_3C90X.IOAddr + regCommandIntStatus_w);
NETCARD_INW(INF_3C90X.IOAddr + regCommandIntStatus_w);
while (NETCARD_INW(INF_3C90X.IOAddr+regCommandIntStatus_w) &
INT_CMDINPROGRESS)
;
/** Set the ethernet packet type **/
hdr.type = htons(t);
/** Copy the destination address **/
memcpy(hdr.dst_addr, d, ETH_ALEN);
/** Copy our MAC address **/
memcpy(hdr.src_addr, INF_3C90X.HWAddr, ETH_ALEN);
/** Setup the DPD (download descriptor) **/
INF_3C90X.TransmitDPD.DnNextPtr = 0;
/** set notification for transmission completion (bit 15) **/
INF_3C90X.TransmitDPD.FrameStartHeader = (s + sizeof(hdr)) | 0x8000;
INF_3C90X.TransmitDPD.HdrAddr = virt_to_bus(&hdr);
INF_3C90X.TransmitDPD.HdrLength = sizeof(hdr);
INF_3C90X.TransmitDPD.DataAddr = virt_to_bus(p);
INF_3C90X.TransmitDPD.DataLength = s + (1<<31);
/** Send the packet **/
NETCARD_OUTD(virt_to_bus(&(INF_3C90X.TransmitDPD)),
INF_3C90X.IOAddr + regDnListPtr_l);
/** End Stall and Wait for upload to complete. **/
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdStallCtl, 3);
while(NETCARD_IND(INF_3C90X.IOAddr + regDnListPtr_l) != 0)
;
/** Wait for NIC Transmit to Complete **/
load_timer2(10*TICKS_PER_MS); /* Give it 10 ms */
while (!(NETCARD_INW(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004) &&
timer2_running())
;
if (!(NETCARD_INW(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0004))
{
debug_print("3C90X: Tx Timeout\n");
continue;
}
status = NETCARD_INB(INF_3C90X.IOAddr + regTxStatus_b);
/** acknowledge transmit interrupt by writing status **/
NETCARD_OUTB(0x00, INF_3C90X.IOAddr + regTxStatus_b);
/** successful completion (sans "interrupt Requested" bit) **/
if ((status & 0xbf) == 0x80)
return;
debug_print("3C90X: Status (%hhX)\n", status);
/** check error codes **/
if (status & 0x02)
{
debug_print("3C90X: Tx Reclaim Error (%hhX)\n", status);
a3c90x_reset(NULL);
}
else if (status & 0x04)
{
debug_print("3C90X: Tx Status Overflow (%hhX)\n", status);
for (i=0; i<32; i++)
NETCARD_OUTB(0x00, INF_3C90X.IOAddr + regTxStatus_b);
/** must re-enable after max collisions before re-issuing tx **/
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdTxEnable, 0);
}
else if (status & 0x08)
{
debug_print("3C90X: Tx Max Collisions (%hhX)\n", status);
/** must re-enable after max collisions before re-issuing tx **/
a3c90x_internal_IssueCommand(INF_3C90X.IOAddr, cmdTxEnable, 0);
}
else if (status & 0x10)
{
debug_print("3C90X: Tx Underrun (%hhX)\n", status);
a3c90x_reset(NULL);
}
else if (status & 0x20)
{
debug_print("3C90X: Tx Jabber (%hhX)\n", status);
a3c90x_reset(NULL);
}
else if ((status & 0x80) != 0x80)
{
debug_print("3C90X: Internal Error - Incomplete Transmission (%hhX)\n",
status);
a3c90x_reset(NULL);
}
}
/** failed after RETRY attempts **/
debug_print("Failed to send after %d retries\n", retries);
return;
}
#endif
/*** a3c90x_poll: exported routine that waits for a certain length of time
*** for a packet, and if it sees none, returns 0. This routine should
*** copy the packet to nic->packet if it gets a packet and set the size
*** in nic->packetlen. Return 1 if a packet was found.
***/
static int
a3c90x_poll(struct nic *nic,unsigned char *buf,int *buflen)
{
unsigned long i;
int errcode;
if (!(NETCARD_INW(INF_3C90X.IOAddr + regCommandIntStatus_w)&0x0010))
{
return 0;
}
/** we don't need to acknowledge rxComplete -- the upload engine
** does it for us.
**/
printf("step 1 \n");
/** Build the up-load descriptor **/
INF_3C90X.ReceiveUPD.UpNextPtr = 0;
INF_3C90X.ReceiveUPD.UpPktStatus = 0;
INF_3C90X.ReceiveUPD.DataAddr = virt_to_bus(buf);
INF_3C90X.ReceiveUPD.DataLength = 1536 + (1<<31);
printf("step 2 . \n");
/** Submit the upload descriptor to the NIC **/
NETCARD_OUTD(virt_to_bus(&(INF_3C90X.ReceiveUPD)),
INF_3C90X.IOAddr + regUpListPtr_l);
printf("step . \n");
/** 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++);
printf("step 4 \n");
/** Check for Error (else we have good packet) **/
if (INF_3C90X.ReceiveUPD.UpPktStatus & (1<<14))
{
errcode = INF_3C90X.ReceiveUPD.UpPktStatus;
if (errcode & (1<<16))
debug_print("3C90X: Rx Overrun (%hX)\n",errcode>>16);
else if (errcode & (1<<17))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -