[realtek] Help about DOS Driver demo(RTL8139) from Realtek ?
Konstantin V. Grudnev
Konstantin V. Grudnev" <grudnevkv@yandex.ru
Mon Oct 21 08:26:01 2002
Dear All,
I've cutted source code from DOS Driver demo for RTL8139, but it doesn't
work,
I checked out Interrupt Status Register and it had the next values:
0x0 - initial value, changes very quickly to 0x1.
after some time I had
0x11 and then
0x51.
Please help to find error.
---------------------------------------------------------------
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include "rtl8139.h"
#include "demo.h"
void interrupt (*OldFunction)(void);
void interrupt NewFunction(void);
int INTR;
extern far void outpdw(unsigned int,unsigned long);
extern far unsigned long inpdw(unsigned int);
void InitHardware();
void InitSoftware();
void IssueCMD();
void TxInterruptHandler();
BOOLEAN RxInterruptHandler();
file://Transmit variables
#define TX_SW_BUFFER_NUM 4
TX_DESCRIPTOR TxDesc[TX_SW_BUFFER_NUM];
unsigned char TxHwSetupPtr;
unsigned char TxHwFinishPtr;
unsigned char TxHwFreeDesc;
file://Receive variables
unsigned char *RxBuffer,*RxBufferOriginal;
unsigned long RxBufferPhysicalAddress;
unsigned int RxReadPtrOffset;
PPACKET pLeadingReadPacket; file://should be a link list
unsigned long PacketReceivedGood = 0;
unsigned long ByteReceived = 0;
#define RX_BUFFER_SIZE 16*1024
#define RX_MAX_PACKET_LENGTH 1600
#define RX_MIN_PACKET_LENGTH 64
#define RX_READ_POINTER_MASK 0x3FFC
ULONG IOBase,Irq;
unsigned char *Buffer;
ULONG PhysicalAddrBuffer;
void ShowStatistics(
)
{
gotoxy(2,22); printf("Packet Received:: %u",PacketReceivedGood);
gotoxy(2,23); printf("Byte Received:: %9lu",ByteReceived);
}
BOOLEAN
FindIOIRQ(ULONG *IOBase,ULONG *IRQ)
{
ULONG i,j,PciData,BaseAddr,Interrupt;
for(i=0;i<32;i++)
{
j=0x80000000+(i<<11);
outpdw(0xcf8,j);
PciData=inpdw(0xcfc);
if(PciData==0x813910ec)
{
outpdw(0xcf8,j+0x10);
*IOBase=inpdw(0xcfc);
*IOBase &= 0xfffffff0;
outpdw(0xcf8,j+0x3c);
*IRQ=inpdw(0xcfc);
*IRQ &= 0xff;
return TRUE;
}
}
return FALSE;
}
int
ComputeInterrupt(
int IrqNumber
)
{
if(IrqNumber <=8) return IrqNumber+8;
else return IrqNumber+0x68;
}
/////////////////////////////////////////////////////////////////////////
file://Our Interrupt Service Routine (ISR)
/////////////////////////////////////////////////////////////////////////
void interrupt NewFunction(void)
{
unsigned int curISR;
disable(); // == _asm cli
curISR = inport(IOBase + ISR);
if( (curISR & R39_INTERRUPT_MASK) != 0)
{
do
{
if(curISR & ISR_PUN)
{
// ProcessLingChange(); file://should write this code someday
outport(IOBase + ISR , ISR_PUN);
}
if(curISR & ISR_TOK)
{
TxInterruptHandler();
outport(IOBase + ISR, ISR_TOK);
}
if(curISR & ISR_TER)
{
outportb(IOBase + TCR , TCR_CLRABT);
outport(IOBase + ISR , ISR_TER);
}
if( curISR & (ISR_ROK|ISR_RER|ISR_RXOVW|ISR_FIFOOVW) )
{
if(curISR & ISR_ROK)
{
RxInterruptHandler();
}
outport(IOBase + ISR, ISR_ROK | ISR_RER |ISR_RXOVW | ISR_FIFOOVW);
}
curISR = inport(IOBase + ISR);
}while( (curISR & R39_INTERRUPT_MASK) != 0);
// _asm int 3;
_asm mov al,020h
_asm out 0a0h,al file://;issue EOI to 2nd 8259
_asm out 20h,al file://;Issue EOI to 1nd 8259
}
else
{//not our interrupt, should call original interrupt service routine.
// OldFunction();
}
enable(); // == _asm sti
}
//////////////////////////////////////////////////////////////////////////
file://Initialization part
//////////////////////////////////////////////////////////////////////////
void
InitHardware()
{
outportb(IOBase + CR, CR_RST); file://reset
outportb(IOBase + CR, CR_RE + CR_TE); file://enable Tx/Rx
outpdw(IOBase + TCR, TCR_IFG0 |
TCR_IFG1 |
TCR_MXDMA2 |
TCR_MXDMA1);
outpdw(IOBase + RCR, RCR_RBLEN0 |
RCR_MXDMA2 |
RCR_MXDMA1 |
RCR_AB |
RCR_AM |
RCR_APM );
outpdw(IOBase + RBSTART , RxBufferPhysicalAddress);
outport(IOBase + IMR, R39_INTERRUPT_MASK);//enable interrupt
}
void
InitSoftware()
{
ULONG Offset,Segment,Delta,i;
unsigned char *tmpBuffer;
file://Init Tx Variables
TxHwSetupPtr = 0;
TxHwFinishPtr = 0;
TxHwFreeDesc = TX_SW_BUFFER_NUM;
file://initialize TX descriptor
for(i=0;i<TX_SW_BUFFER_NUM;i++)
{ file://allocate memory
Buffer=(unsigned char *)malloc( 1600 / sizeof(int) );
TxDesc[i].OriginalBufferAddress = Buffer;
Offset=FP_OFF(Buffer);
file://align to DWORD
if( Offset & 0x3 )
{
Delta = 4 - (Offset & 0x3);
Offset = Offset + Delta;
Buffer = Buffer + Delta;
}
TxDesc[i].buffer = Buffer;
Segment=FP_SEG(Buffer);
PhysicalAddrBuffer = (Segment << 4) + Offset;
TxDesc[i].PhysicalAddress = PhysicalAddrBuffer;
// TxDesc[i].DescriptorStatus = TXDESC_INIT;
}
file://Init Rx Buffer
RxBufferOriginal =
tmpBuffer = (unsigned char *)malloc( RX_BUFFER_SIZE + 2000 );
Offset=FP_OFF(tmpBuffer);
file://align to DWORD
if( Offset & 0x3 )
{
Delta = 4 - (Offset & 0x3);
Offset = Offset + Delta;
tmpBuffer = tmpBuffer + Delta;
}
RxBuffer = tmpBuffer;
Segment=FP_SEG(tmpBuffer);
RxBufferPhysicalAddress = (Segment << 4) + Offset;
file://Init Rx Variable
RxReadPtrOffset = 0;
}
//////////////////////////////////////////////////////////////////////////
file://Transmit part
//////////////////////////////////////////////////////////////////////////
unsigned char
NextDesc(
unsigned char CurrentDescriptor
)
{
// (CurrentDescriptor == TX_SW_BUFFER_NUM-1) ? 0 : (1 +
CurrentDescriptor);
if(CurrentDescriptor == TX_SW_BUFFER_NUM-1)
{
return 0;
}
else
{
return ( 1 + CurrentDescriptor);
}
}
unsigned char
CheckTSDStatus(
unsigned char Desc
)
{
ULONG Offset = Desc << 2;
ULONG tmpTSD;
tmpTSD=inpdw(IOBase + TSD0 + Offset);
switch ( tmpTSD & (TSD_OWN | TSD_TOK) )
{
case (TSD_OWN | TSD_TOK): return TSDSTATUS_BOTH;
case (TSD_TOK) : return TSDSTATUS_TOK;
case (TSD_OWN) : return TSDSTATUS_OWN;
case 0 : return TSDSTATUS_0;
}
return 0;
}
void
IssueCMD(unsigned char descriptor)
{
unsigned long offset = descriptor << 2;
outpdw(IOBase + TSAD0 + offset, TxDesc[TxHwSetupPtr].PhysicalAddress);
outpdw(IOBase + TSD0 + offset , TxDesc[TxHwSetupPtr].PacketLength);
}
int
SendPacket(
PPACKET pPacket
)
{
disable();
if( TxHwFreeDesc>0 )
{
TxDesc[TxHwSetupPtr].PacketLength=
CopyFromPacketToBuffer( pPacket , TxDesc[TxHwSetupPtr].buffer);
IssueCMD(TxHwSetupPtr);
TxHwSetupPtr = NextDesc(TxHwSetupPtr);
TxHwFreeDesc--;
enable();
return TRUE;//success
}
else
{
enable();
return FALSE;//out of resource
}
}
void
TxInterruptHandler()
{
while( (CheckTSDStatus(TxHwFinishPtr) == TSDSTATUS_BOTH ) &&
(TxHwFreeDesc < 4 ) )
{
file://can Release this buffer now
TxHwFinishPtr = NextDesc(TxHwFinishPtr);
TxHwFreeDesc++;
}
}
////////////////////////////////////////////////////////////////////////
// Start of Rx Path
////////////////////////////////////////////////////////////////////////
void
ReadPacket(
PPACKET RxPacket
)
{
pLeadingReadPacket = RxPacket;
}
void
CopyPacket(
unsigned char *pIncomePacket,
unsigned int PktLength
)
{
if( (pLeadingReadPacket != NULL) &&
(pLeadingReadPacket->PacketLength == 0) )
{
memcpy(pLeadingReadPacket->Buffers.Buffer , pIncomePacket , PktLength);
pLeadingReadPacket->PacketLength = PktLength;
}
}
BOOLEAN
PacketOK(
PPACKETHEADER pPktHdr
)
{
BOOLEAN BadPacket = pPktHdr->RUNT ||
pPktHdr->LONG ||
pPktHdr->CRC ||
pPktHdr->FAE;
if( ( !BadPacket ) &&
( pPktHdr->ROK ) )
{
if ( (pPktHdr->PacketLength > RX_MAX_PACKET_LENGTH ) ||
(pPktHdr->PacketLength < RX_MIN_PACKET_LENGTH ) )
{
return(FALSE);
}
PacketReceivedGood++;
ByteReceived += pPktHdr->PacketLength;
return TRUE ;
}
else
{
return FALSE;
}
}
BOOLEAN
RxInterruptHandler(
)
{
unsigned char TmpCMD;
unsigned int PktLength;
unsigned char *pIncomePacket, *RxReadPtr;
PPACKETHEADER pPacketHeader;
while (TRUE)
{
TmpCMD = inportb(IOBase + CR);
if (TmpCMD & CR_BUFE)
{
break;
}
do
{
RxReadPtr = RxBuffer + RxReadPtrOffset;
pPacketHeader = (PPACKETHEADER) RxReadPtr;
pIncomePacket = RxReadPtr + 4;
PktLength = pPacketHeader->PacketLength; file://this length include
CRC
if ( PacketOK( pPacketHeader ) )
{
if ( (RxReadPtrOffset + PktLength) > RX_BUFFER_SIZE )
{ file://wrap around to end of RxBuffer
file://_asm int 3;
memcpy( RxBuffer + RX_BUFFER_SIZE , RxBuffer,
(RxReadPtrOffset + PktLength - RX_BUFFER_SIZE) );
}
file://copy the packet out here
CopyPacket(pIncomePacket,PktLength - 4);//don't copy 4 bytes CRC
file://update Read Pointer
RxReadPtrOffset = (RxReadPtrOffset + PktLength + 4 + 3) &
RX_READ_POINTER_MASK;
file://4:for header length(PktLength include 4 bytes CRC)
file://3:for dword alignment
outport( IOBase + CAPR, RxReadPtrOffset - 0x10); file://-4:avoid overflow
}
else
{
// ResetRx();
break;
}
TmpCMD = inportb(IOBase + CR);
} while (!(TmpCMD & CR_BUFE));
}
return (TRUE); file://Done
}
/////////////////////////////////////////////////////////////////////////
file://Load / Unload
/////////////////////////////////////////////////////////////////////////
BOOLEAN
LoadDriver()
{
int INTR;
FindIOIRQ( &IOBase , &Irq );
INTR = ComputeInterrupt( Irq );
OldFunction = getvect( INTR );
file://hook interrupt vector
disable();
setvect(INTR,NewFunction);
enable();
file://initialize chip
InitSoftware();
InitHardware();
return TRUE;
}
BOOLEAN
UnloadDriver()
{
disable();
setvect(INTR,OldFunction);
enable();
return TRUE;
}
///////////////////////////////////////////////////////////////////////////
// End Of Demo driver
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////
// Start of Test Program (only for demo)
///////////////////////////////////////////////////////////////////////////
PPACKET
BuildPacket(
)
{
int i;
PPACKET tmpPacket = (PPACKET) malloc(sizeof(PACKET));
tmpPacket->BufferCount = 1;
tmpPacket->PacketLength = 64;
tmpPacket->Buffers.Buffer = (unsigned char *) malloc(2000);
tmpPacket->Buffers.Next = NULL;
tmpPacket->Buffers.BufferLength = 64;
for(i=0;i<12;i++)
{
tmpPacket->Buffers.Buffer[i] = 0xff;
}
for(i=12;i<2000;i++)
{
tmpPacket->Buffers.Buffer[i] = i & 0xff;
}
return tmpPacket;
}
PPACKET
PreparePacket(
)
{
PPACKET tmpPacket = (PPACKET) malloc(sizeof(PACKET));
tmpPacket->BufferCount = 1;
tmpPacket->PacketLength = 0;
tmpPacket->Buffers.Buffer = (unsigned char *) malloc(2000);
tmpPacket->Buffers.Next = NULL;
tmpPacket->Buffers.BufferLength = 0;
return tmpPacket;
}
void
ShowPacket(
PPACKET pPacket
)
{
unsigned char *PktBuf = pPacket->Buffers.Buffer;
unsigned int i,PktLength = pPacket->PacketLength;
clrscr();
ShowStatistics();
printf("Packet Length = %d\n",PktLength);
for(i=0;i<PktLength;i++)
{
printf("%02X ",PktBuf[i]);
if( (i&0xf) == 0xf )
{
printf(" %4X\n", (i&0xfffffff0) );
}
if( (i&0xff) == 0xff )
{
getchar();
clrscr();
}
}
}
BOOLEAN
Send(
)
{
PPACKET pTestPacket;
int i;
// Send Test
pTestPacket = BuildPacket();
for(i=0;i<2000;i++)
{
pTestPacket->PacketLength=pTestPacket->Buffers.BufferLength = 64 +
(i%1430);
while( !SendPacket(pTestPacket) )
{
};
// delay(5);
}
return TRUE;
}
void
Receive()
{
PPACKET pTestPacket;
int i;
file://Read Test
pTestPacket = PreparePacket();
ReadPacket(pTestPacket);
do
{
/* while(pTestPacket->PacketLength == 0)
{
}
// ShowPacket(pTestPacket);*/
ShowStatistics();
pTestPacket->PacketLength = 0;
}while(!kbhit());
}
main()
{
clrscr();
directvideo = 1;
LoadDriver();
Send();
Receive();
UnloadDriver();
return 0;
}
------------------------------------------------------