📄 netdrv.cpp
字号:
BOOL txp;
BOOL resend;
UCHAR tempc;
// following lines are according to 88796 data sheet which
// says very detailed about what to do when buffer overflows.
// I change a little with throwing away all the packets waiting
// on the buffer link and make buffer empty.
// step 1, save TXP in
tempc = inportb(CRADD);
if ( tempc & 0x04 )
txp = TRUE;
else
txp = FALSE;
// step 2, stop 796
outportb(CRADD,0x21);
// step 3. wait for at least 1.5 ms.
Sleep(10);
// step 4, clear RBCR0 and RBCR1.
SETTOPAGE0();
outportb(RBCR0ADD,0x00);
outportb(RBCR1ADD,0x00);
// step 5
if ( TRUE == txp )
{
tempc = inportb(ISRADD);
if ( ( tempc & 0x02 ) || ( tempc & 0x08 ) )
resend = FALSE;
else
resend = TRUE;
}
else
{
resend = FALSE;
}
// step 6 loop, i know, this will shut the data link from out side.
outportb( TCRADD, 0x20);
// step 8. remove all the packet from the receive buffer.
// as the packet has already been lost, just throw
// all the packets in the buffer away.
// the method is set the two dynamic read and write
// registers.
outportb(BNRYADD,0x46);
SETTOPAGE1();
outportb(CPRADD,0x47);
SETTOPAGE0();
ReadPage = 0x47;
// step 9.
outportb(ISRADD,0x10);
// step 10.
outportb(TCRADD, 0x20);
// step 7. start. data sheet got some errors here,
// if i start it really in step 7, data could
// still be flowed in of step 8,9,10, that could
// make trouble.
// step 6 will do this, but why do i find problems?
outportb(CRADD,0x22);
// step 11.
if ( TRUE == resend )
{
outportb(CRADD,0x26);
}
// step 12. this is for my application environment.
// when buffer shortage happens, there should be
// also an receive interrupt.
ReceiveIntHappen = 0;
BufShortHappen = 0;
return;
}
*/
/*
Name: RemoteRead
Description: read data into a buffer use remote DMA.
Parameters: cur_page: current page to start, may start at the middle
possition of a page.
len: lenth of the DMA, words.
buf: where to save data.
Return: NET_NO_ERROR or error code.
Test and Revision: Ason, 2001.5
*/
INT16 RemoteRead(UINT16 cur_page, UINT16 len, UINT16 *buf)
{
UCHAR tempc;
UCHAR regtemp;
UINT16 i;
UINT16 tempss;
UINT32 pre_int_level;
// pre_int_level = NU_Control_Interrupts( MACINTLEVEL << 8 );
SETTOPAGE0();
regtemp = (cur_page & 0xff00) >> 8;
outportb(RSAR1ADD, regtemp);
regtemp = cur_page & 0xff;
outportb(RSAR0ADD,regtemp);
regtemp = (( (len<<1) & 0xff00) >> 8) & 0xff;
outportb(RBCR1ADD,regtemp);
regtemp = (len<<1) & 0xff;
outportb(RBCR0ADD,regtemp);
// start remote DMA to read.
outportb( CRADD,0x0a );
for (i = 0; i <len; i++ )
*( buf + i ) = inport( DATAPORTADD );
// wait for the read DMA to finish.
i = 0;
while(1)
{
tempc = inportb(ISRADD);
if ( tempc & 0x40 )
{
// MacState.RemoteDMACompleteTimes++;
break;
}
Sleep(1);
if ( i++ > NET_TMO_DMA )
break;
}
if ( i > NET_TMO_DMA )
{
//NU_Control_Interrupts( pre_int_level );
return( NET_ERROR_DMATMO );
}
outportb( ISRADD, 0x40 );
//NU_Control_Interrupts( pre_int_level );
return( NET_NO_ERROR );
}
/*
Name: RemoteWrite
Description: write data into a buffer using remote DMA.
Parameters: cur_page: current page to start, may start at the middle
possition of a page.
len: lenth of the DMA, words.
buf: where to copy the data.
Return: NET_NO_ERROR or Error code.
Test and Revision: Ason, 2001.5
*/
BOOL RemoteWrite(UINT16 cur_page, UINT16 len, UINT16 *buf)
{
CHAR tempc;
UCHAR regtemp;
UINT16 i;
SETTOPAGE0();
regtemp = (cur_page & 0xff00) >> 8;
outportb(RSAR1ADD, regtemp);
regtemp = cur_page & 0xff;
outportb(RSAR0ADD,regtemp);
regtemp = (( (len<<1) & 0xff00) >> 8) & 0xff;
outportb(RBCR1ADD,regtemp);
regtemp = (len<<1) & 0xff;
outportb(RBCR0ADD,regtemp);
// start remote DMA to write.
outportb( CRADD,0x12 );
// buf maybe exceed the scope for adding pads, but
// it just read, do no harm.
for (i = 0; i <len; i++ )
outport(DATAPORTADD, *(buf + i));
// wait for the read DMA to finish.
i = 0;
while(1)
{
tempc = inportb(ISRADD);
if ( 0x40 & tempc )
{
// MacState.RemoteDMACompleteTimes++;
break;
}
Sleep(1);
if ( i++ > NET_TMO_DMA )
break;
}
if ( i > NET_TMO_DMA )
{
return( NET_ERROR_DMATMO );
}
outportb(ISRADD,0x40); // clear DMA interrupt.
return( NET_NO_ERROR );
}
/*
Name: TransmitAPacket
Description: Transmit a packet promptly.
Parameters: buf - buffer to hold the packet, point to word.
length - length in word
Returns: NET_NO_ERROR or Error code.
Test and revision:
Ason. 2001.7
*/
INT16 TransmitAPacket( UCHAR *pInfoBuf, UINT16 length )
{
UCHAR tempc,regtemp;
UINT16 temps;
INT16 return_value,i;
UINT32 pre_int_level;
UINT16 tempss;
UINT16 length1;
// UCHAR acOldInfo[512];
// 构造UDP包
length1 = length;
// memcpy(acOldInfo, pInfoBuf, length);
// ConstructEtherNetFrame(acOldInfo, &length1, pInfoBuf, &length);
// 检查发送长度
if ( length % 2 )
length++;
if ( length < TRANSMIT_BUF_MIN_SIZE )
length = TRANSMIT_BUF_MIN_SIZE; // add PAD.
else if ( length > TRANSMIT_BUF_MAX_SIZE )
return( NET_ERROR_EXCEEDMTU ); // MTU exceeded.
length /= 2;
UINT16* buf = (UINT16*)pInfoBuf;
// I am pretty sure this will be called only in
// tasks, so, change to NO_PREEMPTION to solve
// conflict of the two protocols.( TCP/IP and VB)
// NU_Change_Preemption( NU_NO_PREEMPT );
// I could not use IMR in 88796(don't know why?), and
// I don't wanna disabling of this interrupt influence
// low level interrupts, so, I just use CPU IMR. IMR could
// only mask low level interrupt, back to CR.
//
//pre_int_lev = NU_Control_Interrupts( MACINTLEVEL << 8 );
DISABLENETINTERRUPT;
return_value = RemoteWrite( ((UINT16)WritePage) << 8 , length, buf );
if ( NET_NO_ERROR != return_value )
{
//NU_Change_Preemption( NU_PREEMPT );
//NU_Control_Interrupts( pre_int_lev );
ENABLENETINTERRUPT;
return( return_value );
}
outportb( TPSRADD,WritePage );
// length is destined to be even.
outportb(TBCR0ADD,(length<<1) % 256);
outportb(TBCR1ADD,(length<<1) / 256);
PacketDelivered = 0;
STARTTRANSMIT
// This is also very important, as if we enable interrupt here
// and in interrupt service, there destined to be a "SETTOPAGE0();".
// refer to SETTOPAGE0();, read CR out(TXP bit still exist), then
// write CR in( now TXP don't exist), dual-transmition occur!!!
i = 0;
while( TRUE )
{
regtemp = inportb( CRADD );
if ( !(regtemp & 0x04) )
break;
Sleep(1);
if ( i++ > NET_TMO_TMIT )
break;
}
if ( i > NET_TMO_TMIT )
{
//NU_Control_Interrupts( pre_int_lev );
ENABLENETINTERRUPT;
// NU_Change_Preemption( NU_PREEMPT );
return ( NET_ERROR_TRANSBLOCK );
}
// first of all, open interrupt to make sure we
// can receive now.
//NU_Control_Interrupts( pre_int_lev );
// See if we get the packet delivered, if it is not delivered,
// just wait for a while, and when we are waiting, other
// tasks who should call "TransmitAPacket" will not be allowed.
// Attention!!! transmit interrupt may happen here, in this case,
// we will not get ISR set in the following lines, so, we use
// "PacketDelivered" to help us out.
i = 0;
while( TRUE )
{
// No need to SETTOPAGE0(); and mask interrupt, as in interrupt service,
// after each time of "SETTOPAGE1();", there is a "SETTOPAGE0();".
regtemp = inportb( ISRADD );
if ( ( regtemp & 0x08 ) || ( regtemp & 0x02 ) || ( 1 == PacketDelivered ) )
break;
Sleep(1);
if ( i++ > NET_TMO_TMIT )
break;
}
ENABLENETINTERRUPT;
// NU_Change_Preemption( NU_PREEMPT );
if ( i > NET_TMO_TMIT )
return( NET_ERROR_TRANSBLOCK );
else
return( length1 );
}
/*
Name: ConfigMacMii
Description: set neccessary things in MII register set,
as 10M/100M, duplex and such staff.
Parameters: mode, 0 - 10M, 1-100M, 2- autonegotiation.
Return: TRUE, success, FALSE, fail.
Test and revision:
Ason, 2001.7.
*/
INT16 ConfigMacMii(INT16 mode)
{
INT16 return_value;
UINT32 i;
UINT16 tempus;
UCHAR tempc;
SETTOPAGE0();
outportb(CRADD,0x21);
Sleep(10);
// reset MII register set.
tempus = 0x8000;
WriteMiiRegister(0x10,0x00,tempus); // 0x10 is the PHY ID of our internal PHY,
// you may refer to 88796 data sheet.
i = 0;
while( TRUE )
{
return_value = ReadMiiRegister(0x10,0x00,&tempus);
if ( NET_NO_ERROR != return_value )
return( NET_ERROR_PHYREAD );
if ( ! ( tempus & 0x8000 ) )
break;
Sleep(1);
if ( i++ > NET_TMO_MIIRST )
return( NET_ERROR_MIIRST );
}
tempus &= 0xcfff; // clear 10/100/auto-negotiation bit.
if ( 2 == mode)
tempus |= 0x1000; // set auto negotiation.
else if ( 1 == mode )
tempus |= 0x2000; // set to 100M.
tempus &= 0xfeff; // set to half duplex.
WriteMiiRegister(0x10,0x00,tempus);
// say i am not capable of 100Base-TX and 100Base-T.
// Why say I am not capable of 100M?s
// WriteMiiRegister(0x10,0x04,0x0061);
// say i will see interrupt of link state/jabber/remote fault/false carrier.
// but i don't know why the two bits writable can not be set.
// WriteMiiRegister(0x10,31,0x0);
return( NET_NO_ERROR );
}
/************************************************************************
Name: ReceiveAPacket
Description: This routine will received a packet now
dangling on the MAC buffer, and "ReadPage" is
a global thing.
Parameters: buf - the buffer used to hold the packet.
Returns: 0 - A packet is successfully received.
1 - No packet is found.
2 - this is a viewbed packet, and we care about it, saved.
3 - this is a viewbed packet, but we don't care about it, discard.
-1 - NET_ERROR_PAKLEN.
Test and revision:
Ason. 2001.7
*************************************************************************/
INT16 ReceiveAPacket( UCHAR *tcpip_buf, UINT16 nLength)
{
UCHAR tempc, cur_page;
UINT16 packet_len = 0;
int return_value;
UCHAR temp_buf[50]; // temporary buffer to hold packet head.
char acTempAddr[6];
packet_len = 0;
DISABLENETINTERRUPT;
//*type = packet_type = NET_PTL_NOONE;
SETTOPAGE0();
tempc = inportb(RSRADD);
// when set to page1, there should be an interrupt entry protection.
SETTOPAGE1();
cur_page = inportb(CPRADD);
SETTOPAGE0();
if ( ReadPage == cur_page )
{
ENABLENETINTERRUPT;
return( NET_ERROR_NOPAKIN );
}
//
// read packet head, refer to "STORAGE FORMAT FOR RECEIVED PACKETS" in AX88796-16.pdf
return_value = RemoteRead( ((UINT16)ReadPage) << 8 , 25, (UINT16*)temp_buf );
if( NET_NO_ERROR != return_value )
{
ENABLENETINTERRUPT;
return( return_value );
}
memset(acTempAddr, 0xFF, 6);
//////////////////////////////////////////////////////////
// DEBUG:直连网线升级错误, modify by shiliangcai
// 原因:因为使用直连网线升级时,网络时断时续,所以会有ARP包,而判断条件中,
// IP包不是必要条件,导致ARP包当作IP包处理,结果长度错误,导致读越界
// 修改:将IP包判断做为必要条件
// 通过判断以太网地址,源地址(PC网卡)相同,目标地址是0xffffffffffff(广播)
// 而且需要判断是IP包, *(temp_buf + 16) == 0x08 && *(temp_buf + 17) == 0x00
if ( (*(temp_buf + 16) == 0x08 && *(temp_buf + 17) == 0x00)
&& ((s_nUpateProcessFlag == 0)
|| (s_nUpateProcessFlag == 1)
|| (!memcmp(g_stNetFrameHead.stETHead.ucDstAddr, temp_buf + 10, 6)
&&!memcmp((UINT8*)acTempAddr, temp_buf + 4, 6))))
// DEBUG:直连网线升级错误 end
//////////////////////////////////////////////////////////////////////////////////////
{
s_nDstPort = *(UINT16*)(temp_buf + 38);
packet_len = *(UINT16*)(temp_buf + 42);
packet_len -= 8; // UDP head
#ifdef BIOS_DEBUG
if (packet_len > RECEIVE_BUF_MAX_SIZE - 8)
{
packet_len = RECEIVE_BUF_MAX_SIZE - 8;
}
#endif
// (((UINT16)ReadPage) << 8) + 46, how 46 get is (access)4+6+6+2 (ip)20 udp(8)
return_value = RemoteRead( (((UINT16)ReadPage) << 8) + 46, ( packet_len + 1) >> 1, (UINT16 *)(tcpip_buf) );
if (tcpip_buf[0] != 0xaa || tcpip_buf[1] != 0x55 || tcpip_buf[2] != 0xa5
|| packet_len < 35)
{
packet_len = 0;
}
else
{
// 下面不用switch语句的原因是大部分情况都是 == 2,如果用switch会降低中断效率
if (s_nUpateProcessFlag == 2)
{
if (memcmp(tcpip_buf + 3, g_stSysFlag.stFSysFlag.acFlashID, 8))
{
packet_len = 0;
}
}
else
{
if (s_nUpateProcessFlag == 1)
{
if (packet_len == 55
&& !memcmp(tcpip_buf + 3, g_stSysFlag.stFSysFlag.acFlashID, 8))
{
memcpy(g_stNetFrameHead.stIPHead.ucDstAddr, temp_buf + 30, 4);
memcpy(g_stNetFrameHead.stIPHead.ucSrcAddr, temp_buf + 34, 4);
memcpy(g_stNetFrameHead.stETHead.ucDstAddr, temp_buf + 10, 6);
if( g_stNetFrameHead.stIPHead.ucDstAddr[3] == 1 )
g_stNetFrameHead.stIPHead.ucSrcAddr[3] = g_stNetFrameHead.stIPHead.ucDstAddr[3] + 1;
else
g_stNetFrameHead.stIPHead.ucSrcAddr[3] = g_stNetFrameHead.stIPHead.ucDstAddr[3] - 1;
s_nUpateProcessFlag = 2;
}
else
{
packet_len = 0;
}
}
else // == 0
{
UCHAR actempMonitorID[8];
memset(actempMonitorID, 0x00, 8);
if (packet_len == 55 && !memcmp(tcpip_buf + 3, actempMonitorID, 8)
&& *(tcpip_buf + 3 + 8 + 7) == 0x80 // CPT_CMD
&& *(tcpip_buf + 3 + 8 + 8) == 0x36 // VERSION
&& *(tcpip_buf + 3 + 8 + 8 + 13) == g_stSysFlag.stFSysFlag.ucSelfMachineID)
{
memcpy(g_stNetFrameHead.stIPHead.ucDstAddr, temp_buf + 30, 4);
memcpy(g_stNetFrameHead.stIPHead.ucSrcAddr, temp_buf + 34, 4);
memcpy(g_stNetFrameHead.stETHead.ucDstAddr, temp_buf + 10, 6);
if( g_stNetFrameHead.stIPHead.ucDstAddr[3] == 1 )
g_stNetFrameHead.stIPHead.ucSrcAddr[3] = g_stNetFrameHead.stIPHead.ucDstAddr[3] + 1;
else
g_stNetFrameHead.stIPHead.ucSrcAddr[3] = g_stNetFrameHead.stIPHead.ucDstAddr[3] - 1;
s_nUpateProcessFlag = 2;
}
else
{
packet_len = 0;
}
}
}
}
}
SETTOPAGE0();
outportb( BNRYADD,ReadPage );
ReadPage = temp_buf[1];
SETTOPAGE1();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -