*
* See: ~/Sources/bochs/bochs.../iodev/ne2k.cc
*/
-#define DEBUG 0
+#define DEBUG 1
#define VERSION ((0<<8)|50)
#include <acess.h>
#include <modules.h>
#include <fs_devfs.h>
#include <drv_pci.h>
#include <tpl_drv_network.h>
+#include <semaphore.h>
// === CONSTANTS ===
#define MEM_START 0x40
{0x10EC, 0x8029}, // Realtek 8029
{0x10EC, 0x8129} // Realtek 8129
};
-#define NUM_COMPAT_DEVICES (sizeof(csaCOMPAT_DEVICES)/sizeof(csaCOMPAT_DEVICES[0]))
+#define NUM_COMPAT_DEVICES ((int)(sizeof(csaCOMPAT_DEVICES)/sizeof(csaCOMPAT_DEVICES[0])))
enum eNe2k_Page0Read {
CMD = 0, //!< the master command register
Uint16 IOBase; //!< IO Port Address from PCI
Uint8 IRQ; //!< IRQ Assigned from PCI
- int NumWaitingPackets;
- int NextRXPage;
+ tSemaphore Semaphore; //!< Semaphore for incoming packets
+ int NextRXPage; //!< Next expected RX page
int NextMemPage; //!< Next Card Memory page to use
-
- Uint8 Buffer[RX_BUF_SIZE];
-
+
char Name[2]; // "0"
- tVFS_Node Node;
- Uint8 MacAddr[6];
+ tVFS_Node Node; //!< VFS Node
+ Uint8 MacAddr[6]; //!< Cached MAC address
} tCard;
// === PROTOTYPES ===
int Ne2k_Install(char **Arguments);
char *Ne2k_ReadDir(tVFS_Node *Node, int Pos);
-tVFS_Node *Ne2k_FindDir(tVFS_Node *Node, char *Name);
+tVFS_Node *Ne2k_FindDir(tVFS_Node *Node, const char *Name);
int Ne2k_IOCtl(tVFS_Node *Node, int ID, void *Data);
Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
Uint64 Ne2k_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer);
+
+ int Ne2k_int_ReadDMA(tCard *Card, int FirstPage, int NumPages, void *Buffer);
Uint8 Ne2k_int_GetWritePage(tCard *Card, Uint16 Length);
void Ne2k_IRQHandler(int IntNum);
int Ne2k_Install(char **Options)
{
int i, j, k;
- int count, id, base;
+ int count, base;
+ tPCIDev id;
// --- Scan PCI Bus ---
// Count Cards
giNe2k_CardCount = 0;
for( i = 0; i < NUM_COMPAT_DEVICES; i ++ )
{
- giNe2k_CardCount += PCI_CountDevices( csaCOMPAT_DEVICES[i].Vendor, csaCOMPAT_DEVICES[i].Device, 0 );
+ giNe2k_CardCount += PCI_CountDevices( csaCOMPAT_DEVICES[i].Vendor, csaCOMPAT_DEVICES[i].Device );
+ }
+
+ if( giNe2k_CardCount == 0 ) {
+ Log_Warning("Ne2k", "No cards detected");
+ return MODULE_ERR_NOTNEEDED;
}
// Enumerate Cards
for( i = 0; i < NUM_COMPAT_DEVICES; i ++ )
{
- count = PCI_CountDevices( csaCOMPAT_DEVICES[i].Vendor, csaCOMPAT_DEVICES[i].Device, 0 );
+ count = PCI_CountDevices( csaCOMPAT_DEVICES[i].Vendor, csaCOMPAT_DEVICES[i].Device );
for( j = 0; j < count; j ++,k ++ )
{
- id = PCI_GetDevice( csaCOMPAT_DEVICES[i].Vendor, csaCOMPAT_DEVICES[i].Device, 0, j );
+ id = PCI_GetDevice( csaCOMPAT_DEVICES[i].Vendor, csaCOMPAT_DEVICES[i].Device, j );
// Create Structure
- base = PCI_AssignPort( id, 0, 0x20 );
+ base = PCI_GetBAR( id, 0 );
gpNe2k_Cards[ k ].IOBase = base;
gpNe2k_Cards[ k ].IRQ = PCI_GetIRQ( id );
gpNe2k_Cards[ k ].NextMemPage = 64;
outb( base + CURR, RX_FIRST ); // Current RX page
outb( base + CMD, 0x21 ); // No DMA and Stop
outb( base + DCR, 0x49 ); // Set WORD mode
- outb( base + IMR, 0x00 );
+ outb( base + IMR, 0x00 ); // Interrupt Mask Register
outb( base + ISR, 0xFF );
outb( base + RCR, 0x20 ); // Reciever to Monitor
outb( base + TCR, 0x02 ); // Transmitter OFF (TCR.LB = 1, Internal Loopback)
+
+ // Read MAC Address
outb( base + RBCR0, 6*4 ); // Remote Byte Count
outb( base + RBCR1, 0 );
outb( base + RSAR0, 0 ); // Clear Source Address
outb( base + RSAR1, 0 );
outb( base + CMD, 0x0A ); // Remote Read, Start
-
- // Read MAC Address
gpNe2k_Cards[ k ].MacAddr[0] = inb(base+0x10);// inb(base+0x10);
gpNe2k_Cards[ k ].MacAddr[1] = inb(base+0x10);// inb(base+0x10);
gpNe2k_Cards[ k ].MacAddr[2] = inb(base+0x10);// inb(base+0x10);
outb( base+RCR, 0x0F ); // Set WRAP and allow all packet matches
outb( base+TCR, 0x00 ); // Set Normal Transmitter mode
outb( base+TPSR, 0x40); // Set Transmit Start
- // Set MAC Address
- /*
- Ne2k_WriteReg(base, MAC0, gpNe2k_Cards[ k ].MacAddr[0]);
- Ne2k_WriteReg(base, MAC1, gpNe2k_Cards[ k ].MacAddr[1]);
- Ne2k_WriteReg(base, MAC2, gpNe2k_Cards[ k ].MacAddr[2]);
- Ne2k_WriteReg(base, MAC3, gpNe2k_Cards[ k ].MacAddr[3]);
- Ne2k_WriteReg(base, MAC4, gpNe2k_Cards[ k ].MacAddr[4]);
- Ne2k_WriteReg(base, MAC5, gpNe2k_Cards[ k ].MacAddr[5]);
- */
- Log("[NE2K]: Card #%i: IRQ=%i, IOBase=0x%x",
- k, gpNe2k_Cards[ k ].IRQ, gpNe2k_Cards[ k ].IOBase);
- Log("MAC Address %x:%x:%x:%x:%x:%x",
- gpNe2k_Cards[ k ].MacAddr[0], gpNe2k_Cards[ k ].MacAddr[1],
- gpNe2k_Cards[ k ].MacAddr[2], gpNe2k_Cards[ k ].MacAddr[3],
- gpNe2k_Cards[ k ].MacAddr[4], gpNe2k_Cards[ k ].MacAddr[5]
+ Log_Log("Ne2k", "Card %i 0x%04x IRQ%i %02x:%02x:%02x:%02x:%02x:%02x",
+ k, base, gpNe2k_Cards[ k ].IRQ,
+ gpNe2k_Cards[k].MacAddr[0], gpNe2k_Cards[k].MacAddr[1],
+ gpNe2k_Cards[k].MacAddr[2], gpNe2k_Cards[k].MacAddr[3],
+ gpNe2k_Cards[k].MacAddr[4], gpNe2k_Cards[k].MacAddr[5]
);
// Set VFS Node
gpNe2k_Cards[ k ].Node.Write = Ne2k_Write;
gpNe2k_Cards[ k ].Node.Read = Ne2k_Read;
gpNe2k_Cards[ k ].Node.IOCtl = Ne2k_IOCtl;
+
+ // Initialise packet semaphore
+ // - Start at zero, no max
+ Semaphore_Init( &gpNe2k_Cards[k].Semaphore, 0, 0, "NE2000", gpNe2k_Cards[ k ].Name );
}
}
gNe2k_DriverInfo.RootNode.Size = giNe2k_CardCount;
DevFS_AddDevice( &gNe2k_DriverInfo );
- return 1;
+ return MODULE_ERR_OK;
}
/**
}
/**
- * \fn tVFS_Node *Ne2k_FindDir(tVFS_Node *Node, char *Name)
+ * \fn tVFS_Node *Ne2k_FindDir(tVFS_Node *Node, const char *Name)
*/
-tVFS_Node *Ne2k_FindDir(tVFS_Node *Node, char *Name)
+tVFS_Node *Ne2k_FindDir(tVFS_Node *Node, const char *Name)
{
if(Name[0] == '\0' || Name[1] != '\0') return NULL;
*/
int Ne2k_IOCtl(tVFS_Node *Node, int ID, void *Data)
{
- int tmp;
ENTER("pNode iID pData", Node, ID, Data);
switch( ID )
{
- case DRV_IOCTL_TYPE:
- LEAVE('i', DRV_TYPE_NETWORK);
- return DRV_TYPE_NETWORK;
-
- case DRV_IOCTL_IDENT:
- tmp = ModUtil_SetIdent(Data, "Ne2k");
- LEAVE('i', tmp);
- return tmp;
-
- case DRV_IOCTL_VERSION:
- LEAVE('x', VERSION);
- return VERSION;
-
- case DRV_IOCTL_LOOKUP:
- tmp = ModUtil_LookupString( (char**)casIOCtls, Data );
- LEAVE('i', tmp);
- return tmp;
+ BASE_IOCTLS(DRV_TYPE_NETWORK, "NE2000", VERSION, casIOCtls);
}
// If this is the root, return
tCard *Card = (tCard*)Node->ImplPtr;
Uint16 *buf = Buffer;
int rem = Length;
+ int page;
ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
+ // TODO: Lock
+
// Sanity Check Length
- if(Length > TX_BUF_SIZE) {
+ if(Length > TX_BUF_SIZE*256) {
+ Log_Warning(
+ "Ne2k",
+ "Ne2k_Write - Attempting to send over TX_BUF_SIZE*256 (%i) bytes (%i)",
+ TX_BUF_SIZE*256, Length
+ );
LEAVE('i', 0);
return 0;
}
// Clear Remote DMA Flag
outb(Card->IOBase + ISR, 0x40); // Bit 6
- // Send Size - Remote Byte Count Register
+ // Send Size - Transfer Byte Count Register
outb(Card->IOBase + TBCR0, Length & 0xFF);
outb(Card->IOBase + TBCR1, Length >> 8);
// Set up transfer
outb(Card->IOBase + RSAR0, 0x00); // Page Offset
- outb(Card->IOBase + RSAR1, Ne2k_int_GetWritePage(Card, Length)); // Page Offset
+ page = Ne2k_int_GetWritePage(Card, Length);
+ outb(Card->IOBase + RSAR1, page); // Page Offset
// Start
- //outb(Card->IOBase + CMD, 0|0x18|0x4|0x2); // Page 0, Transmit Packet, TXP, Start
outb(Card->IOBase + CMD, 0|0x10|0x2); // Page 0, Remote Write, Start
// Send Data
- for(rem = Length; rem; rem -= 2)
+ for(rem = Length; rem > 0; rem -= 2) {
outw(Card->IOBase + 0x10, *buf++);
+ }
- while( inb(Card->IOBase + ISR) == 0 ) // Wait for Remote DMA Complete
+ while( !(inb(Card->IOBase + ISR) & 0x40) ) // Wait for Remote DMA Complete
; //Proc_Yield();
outb( Card->IOBase + ISR, 0x40 ); // ACK Interrupt
// Send Packet
+ outb(Card->IOBase + TPSR, page);
outb(Card->IOBase + CMD, 0|0x10|0x4|0x2);
// Complete DMA
tCard *Card = (tCard*)Node->ImplPtr;
Uint8 page;
Uint8 data[256];
- int i;
struct {
Uint8 Status;
Uint8 NextPacketPage;
ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
- while(Card->NumWaitingPackets == 0) Threads_Yield();
+ // Wait for packets
+ if( Semaphore_Wait( &Card->Semaphore, 1 ) != 1 )
+ {
+ // Error or interrupted
+ LEAVE_RET('i', 0);
+ }
- // Make sure that the card is in page 0
- outb(Card->IOBase + CMD, 0|0x22); // Page 0, Start, NoDMA
+ outb(Card->IOBase, 0x22 | (1 << 6)); // Page 6
+ LOG("CURR : 0x%02x", inb(Card->IOBase + CURR));
- // Get BOUNDARY
+ // Get current read page
page = Card->NextRXPage;
+ LOG("page = %i", page);
- // Set up transfer
- outb(Card->IOBase + RBCR0, 0);
- outb(Card->IOBase + RBCR1, 1); // 256-bytes
- outb(Card->IOBase + RSAR0, 0x00); // Page Offset
- outb(Card->IOBase + RSAR1, page); // Page Number
-
- outb(Card->IOBase + CMD, 0|0x08|0x2); // Page 0, Remote Read, Start
-
- // Clear Remote DMA Flag
- outb(Card->IOBase + ISR, 0x40); // Bit 6
-
- // Read data
- for(i = 0; i < 128; i ++)
- ((Uint16*)data)[i] = inw(Card->IOBase + 0x10);
+ Ne2k_int_ReadDMA(Card, page, 1, data);
pktHdr = (void*)data;
- //Log("Ne2k_Read: Recieved packet (%i bytes)", pktHdr->Length);
+
+ LOG("pktHdr->Status = 0x%x", pktHdr->Status);
+ LOG("pktHdr->NextPacketPage = %i", pktHdr->NextPacketPage);
+ LOG("pktHdr->Length = 0x%03x", pktHdr->Length);
// Have we read all the required bytes yet?
if(pktHdr->Length < 256 - 4)
if(Length > pktHdr->Length)
Length = pktHdr->Length;
memcpy(Buffer, &data[4], Length);
- page ++;
- if(page == RX_LAST+1) page = RX_FIRST;
}
// No? oh damn, now we need to allocate a buffer
- else {
- int j = 256/2;
- char *buf = malloc( (pktHdr->Length + 4 + 255) & ~255 );
+ else
+ {
+ int pages = pktHdr->NextPacketPage - page;
+ char *buf = malloc( pages*256 );
- if(!buf) {
- LEAVE('i', -1);
- return -1;
- }
+ LOG("pktHdr->Length (%i) > 256 - 4, allocated buffer %p", pktHdr->Length, buf);
+ if(!buf) LEAVE_RET('i', -1);
+
+ // Copy the already read data
memcpy(buf, data, 256);
+ // Read all the needed pages
page ++;
- while(page != pktHdr->NextPacketPage)
+ if(page == RX_LAST+1) page = RX_FIRST;
+
+ if( page + pages > RX_LAST )
{
- if(page == RX_LAST+1) page = RX_FIRST;
-
- outb(Card->IOBase + RBCR0, 0);
- outb(Card->IOBase + RBCR1, 1); // 256-bytes
- outb(Card->IOBase + RSAR0, 0x00); // Page Offset
- outb(Card->IOBase + RSAR1, page); // Page Number
- outb(Card->IOBase + CMD, 0|0x08|0x2); // Page 0, Remote Read, Start
-
- for(i = 0; i < 128; i ++)
- ((Uint16*)buf)[j+i] = inw(Card->IOBase + 0x10);
- j += 128;
- page ++;
+ int first_count = RX_LAST+1 - page;
+ int tmp = 0;
+ tmp += Ne2k_int_ReadDMA(Card, page, first_count, buf+256);
+ tmp += Ne2k_int_ReadDMA(Card, RX_FIRST, pages-1-first_count, buf+(first_count+1)*256);
+ LOG("composite return count = %i", tmp);
}
+ else
+ Ne2k_int_ReadDMA(Card, page, pages-1, buf+256);
+ // Wrap length to the packet length
if(Length > pktHdr->Length)
Length = pktHdr->Length;
+ else if( Length < pktHdr->Length ) {
+ Log_Warning("NE2000", "Packet truncated! (%i bytes truncated to %i)",
+ pktHdr->Length, Length);
+ }
memcpy(Buffer, &buf[4], Length);
+
+ free(buf);
}
- // Write BNRY
- if(page == RX_FIRST)
- outb( Card->IOBase + BNRY, RX_LAST );
+ // Write BNRY (maximum page for incoming packets)
+ if(pktHdr->NextPacketPage == RX_FIRST)
+ outb( Card->IOBase + BNRY, RX_LAST-1 );
else
- outb( Card->IOBase + BNRY, page-1 );
+ outb( Card->IOBase + BNRY, pktHdr->NextPacketPage-1 );
// Set next RX Page and decrement the waiting list
- Card->NextRXPage = page;
- Card->NumWaitingPackets --;
+ Card->NextRXPage = pktHdr->NextPacketPage;
LEAVE('i', Length);
return Length;
}
+int Ne2k_int_ReadDMA(tCard *Card, int FirstPage, int NumPages, void *Buffer)
+{
+ int i;
+
+ // Sanity check
+ if( !(0 <= FirstPage && FirstPage < 256) ) {
+ Log_Warning("NE2000", "Ne2k_int_ReadDMA: BUG - FirstPage(%i) not 8-bit", FirstPage);
+ return -1;
+ }
+ if( !(0 <= NumPages && NumPages < 256) ) {
+ Log_Warning("NE2000", "Ne2k_int_ReadDMA: BUG - NumPages(%i) not 8-bit", NumPages);
+ return -1;
+ }
+
+ ENTER("pCard iFirstPage iNumPages pBuffer", Card, FirstPage, NumPages, Buffer);
+
+ // Make sure that the card is in bank 0
+ outb(Card->IOBase + CMD, 0|0x22); // Bank 0, Start, NoDMA
+ outb(Card->IOBase + ISR, 0x40); // Clear Remote DMA Flag
+
+ // Set up transfer
+ outb(Card->IOBase + RBCR0, 0);
+ outb(Card->IOBase + RBCR1, NumPages); // page count
+ outb(Card->IOBase + RSAR0, 0x00); // Page Offset
+ outb(Card->IOBase + RSAR1, FirstPage); // Page Number
+ outb(Card->IOBase + CMD, 0|0x08|0x2); // Bank 0, Remote Read, Start
+
+ // TODO: Less expensive
+ //while( !(inb(Card->IOBase + ISR) & 0x40) ) {
+ // HALT();
+ // LOG("inb(ISR) = 0x%02x", inb(Card->IOBase + ISR));
+ //}
+ HALT(); // Small delay?
+
+ // Read data
+ for(i = 0; i < 128*NumPages; i ++)
+ ((Uint16*)Buffer)[i] = inw(Card->IOBase + 0x10);
+
+
+ outb(Card->IOBase + ISR, 0x40); // Clear Remote DMA Flag
+
+ LEAVE('i', NumPages);
+ return NumPages;
+}
+
/**
* \fn Uint8 Ne2k_int_GetWritePage(tCard *Card, Uint16 Length)
*/
{
byte = inb( gpNe2k_Cards[i].IOBase + ISR );
+ LOG("byte = 0x%02x", byte);
+
+
+ // Reset All (save for RDMA), that's polled
+ outb( gpNe2k_Cards[i].IOBase + ISR, 0xFF&(~0x40) );
+
// 0: Packet recieved (no error)
if( byte & 1 )
{
- gpNe2k_Cards[i].NumWaitingPackets ++;
- if( gpNe2k_Cards[i].NumWaitingPackets > MAX_PACKET_QUEUE )
- gpNe2k_Cards[i].NumWaitingPackets = MAX_PACKET_QUEUE;
+ //if( gpNe2k_Cards[i].NumWaitingPackets > MAX_PACKET_QUEUE )
+ // gpNe2k_Cards[i].NumWaitingPackets = MAX_PACKET_QUEUE;
+ if( Semaphore_Signal( &gpNe2k_Cards[i].Semaphore, 1 ) != 1 ) {
+ // Oops?
+ }
}
// 1: Packet sent (no error)
// 2: Recieved with error
// 5:
// 6: Remote DMA Complete
// 7: Reset
- //LOG("Clearing interrupts on card %i (was 0x%x)\n", i, byte);
- outb( gpNe2k_Cards[i].IOBase + ISR, 0xFF ); // Reset All
+
return ;
}
}
- Warning("[NE2K ] Recieved Unknown IRQ %i", IntNum);
+ Log_Warning("Ne2k", "Recieved Unknown IRQ %i", IntNum);
}