From a8067bafb36f98612767060db856cd6bf36ef940 Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sun, 18 Oct 2009 20:25:46 +0800 Subject: [PATCH] Adding module tree to git, added SYS_LOADMOD to allow usermode module loading --- Kernel/syscalls.lst | 1 + Modules/BochsVBE/Makefile | 7 + Modules/BochsVBE/bochsvbe.c | 449 ++++++++++++++++++++++++++++++++++++ Modules/Makefile.tpl | 29 +++ Modules/NE2000/Makefile | 7 + Modules/NE2000/ne2000.c | 313 +++++++++++++++++++++++++ 6 files changed, 806 insertions(+) create mode 100644 Modules/BochsVBE/Makefile create mode 100644 Modules/BochsVBE/bochsvbe.c create mode 100644 Modules/Makefile.tpl create mode 100644 Modules/NE2000/Makefile create mode 100644 Modules/NE2000/ne2000.c diff --git a/Kernel/syscalls.lst b/Kernel/syscalls.lst index 9b4920a0..a83f5d69 100644 --- a/Kernel/syscalls.lst +++ b/Kernel/syscalls.lst @@ -24,6 +24,7 @@ SYS_SPAWN Spawn a new process SYS_EXECVE Replace the current process SYS_LOADBIN Load a binary into the current address space SYS_UNLOADBIN Unload a loaded binary +SYS_LOADMOD Load a module into the kernel 32 SYS_GETPHYS Get the physical address of a page diff --git a/Modules/BochsVBE/Makefile b/Modules/BochsVBE/Makefile new file mode 100644 index 00000000..add40181 --- /dev/null +++ b/Modules/BochsVBE/Makefile @@ -0,0 +1,7 @@ +# +# + +OBJ = bochsvbe.o +NAME = BochsVBE + +-include ../Makefile.tpl diff --git a/Modules/BochsVBE/bochsvbe.c b/Modules/BochsVBE/bochsvbe.c new file mode 100644 index 00000000..a55e702f --- /dev/null +++ b/Modules/BochsVBE/bochsvbe.c @@ -0,0 +1,449 @@ +/** + * \file drv_bochsvbe.c + * \brief BGA (Bochs Graphic Adapter) Driver + * \note for Acess2 + * \warning This driver does NOT support the Bochs PCI VGA driver +*/ +#define DEBUG 0 +#include +#include +#include +#include +#include +#include +#include + +//#define INT static +#define INT + +// === TYPEDEFS === +typedef struct { + Uint16 width; + Uint16 height; + Uint16 bpp; + Uint16 flags; + Uint32 fbSize; +} t_bga_mode; + +// === CONSTANTS === +enum eMode_Flags { + MODEFLAG_TEXT = 1 +}; +#define BGA_LFB_MAXSIZE (1024*768*4) +#define VBE_DISPI_BANK_ADDRESS 0xA0000 +#define VBE_DISPI_LFB_PHYSICAL_ADDRESS 0xE0000000 +#define VBE_DISPI_IOPORT_INDEX 0x01CE +#define VBE_DISPI_IOPORT_DATA 0x01CF +#define VBE_DISPI_DISABLED 0x00 +#define VBE_DISPI_ENABLED 0x01 +#define VBE_DISPI_LFB_ENABLED 0x40 +#define VBE_DISPI_NOCLEARMEM 0x80 +enum { + VBE_DISPI_INDEX_ID, + VBE_DISPI_INDEX_XRES, + VBE_DISPI_INDEX_YRES, + VBE_DISPI_INDEX_BPP, + VBE_DISPI_INDEX_ENABLE, + VBE_DISPI_INDEX_BANK, + VBE_DISPI_INDEX_VIRT_WIDTH, + VBE_DISPI_INDEX_VIRT_HEIGHT, + VBE_DISPI_INDEX_X_OFFSET, + VBE_DISPI_INDEX_Y_OFFSET +}; + + +// === PROTOTYPES === +// Driver + int BGA_Install(char **Arguments); +void BGA_Uninstall(); +// Internal +void BGA_int_WriteRegister(Uint16 reg, Uint16 value); +Uint16 BGA_int_ReadRegister(Uint16 reg); +void BGA_int_SetBank(Uint16 bank); +void BGA_int_SetMode(Uint16 width, Uint16 height); + int BGA_int_UpdateMode(int id); + int BGA_int_FindMode(tVideo_IOCtl_Mode *info); + int BGA_int_ModeInfo(tVideo_IOCtl_Mode *info); + int BGA_int_MapFB(void *Dest); +// Filesystem +Uint64 BGA_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer); +Uint64 BGA_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer); + int BGA_Ioctl(tVFS_Node *node, int id, void *data); + +// === GLOBALS === +MODULE_DEFINE(0, 0x0032, BochsVBE, BGA_Install, NULL, NULL); +tDevFS_Driver gBGA_DriverStruct = { + NULL, "BochsGA", + { + .Read = BGA_Read, + .Write = BGA_Write, + .IOCtl = BGA_Ioctl + } +}; + int giBGA_CurrentMode = -1; + int giBGA_DriverId = -1; +Uint *gBGA_Framebuffer; +t_bga_mode gBGA_Modes[] = { + {}, + { 80,25, 32, MODEFLAG_TEXT, 80*25*8}, // 640 x 480 + {100,37, 32, MODEFLAG_TEXT, 100*37*8}, // 800 x 600 + {640,480,8, 0, 640*480}, + {640,480,32, 0, 640*480*4}, + {800,600,8, 0, 800*600}, + {800,600,32, 0, 800*600*4}, +}; +#define BGA_MODE_COUNT (sizeof(gBGA_Modes)/sizeof(gBGA_Modes[0])) + +// === CODE === +/** + * \fn int BGA_Install(char **Arguments) + */ +int BGA_Install(char **Arguments) +{ + int bga_version = 0; + + // Check BGA Version + bga_version = BGA_int_ReadRegister(VBE_DISPI_INDEX_ID); + // NOTE: This driver was written for 0xB0C4, but they seem to be backwards compatable + if(bga_version < 0xB0C4 || bga_version > 0xB0C5) { + Warning("[BGA ] Bochs Adapter Version is not 0xB0C4 or 0xB0C5, instead 0x%x", bga_version); + return 0; + } + + // Install Device + giBGA_DriverId = DevFS_AddDevice( &gBGA_DriverStruct ); + if(giBGA_DriverId == -1) { + Warning("[BGA ] Unable to register with DevFS, maybe already loaded?"); + return 0; + } + + // Map Framebuffer to hardware address + gBGA_Framebuffer = (void *) MM_MapHWPage(VBE_DISPI_LFB_PHYSICAL_ADDRESS, 768); // 768 pages (3Mb) + + return 1; +} + +/** + * \fn void BGA_Uninstall() + */ +void BGA_Uninstall() +{ + //DevFS_DelDevice( giBGA_DriverId ); + MM_UnmapHWPage( VBE_DISPI_LFB_PHYSICAL_ADDRESS, 768 ); +} + +/** + * \fn Uint64 BGA_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer) + * \brief Read from the framebuffer + */ +Uint64 BGA_Read(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer) +{ + // Check Mode + if(giBGA_CurrentMode == -1) return -1; + + // Check Offset and Length against Framebuffer Size + if(off+len > gBGA_Modes[giBGA_CurrentMode].fbSize) + return -1; + + // Copy from Framebuffer + memcpy(buffer, (void*)((Uint)gBGA_Framebuffer + (Uint)off), len); + return len; +} + +/** + * \fn Uint64 BGA_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer) + * \brief Write to the framebuffer + */ +Uint64 BGA_Write(tVFS_Node *node, Uint64 off, Uint64 len, void *buffer) +{ + ENTER("xoff xlen", off, len); + + // Check Mode + if(giBGA_CurrentMode == -1) { + LEAVE('i', -1); + return -1; + } + + // Check Input against Frambuffer Size + if(off+len > gBGA_Modes[giBGA_CurrentMode].fbSize) { + LEAVE('i', -1); + return -1; + } + + // Text Mode + if( gBGA_Modes[giBGA_CurrentMode].flags & MODEFLAG_TEXT ) + { + tVT_Char *chars = buffer; + int pitch = gBGA_Modes[giBGA_CurrentMode].width * giVT_CharWidth; + Uint32 *dest; + dest = (void*)gBGA_Framebuffer; + dest += off * giVT_CharWidth; + len /= sizeof(tVT_Char); + while(len--) + { + VT_Font_Render( + chars->Ch, + dest, pitch, + VT_Colour12to24(chars->BGCol), + VT_Colour12to24(chars->FGCol) + ); + dest += giVT_CharWidth; + chars++; + } + } + else + { + Uint8 *destBuf = (Uint8*) ((Uint)gBGA_Framebuffer + (Uint)off); + + LOG("buffer = %p\n", buffer); + LOG("Updating Framebuffer (%p to %p)\n", + destBuf, destBuf + (Uint)len); + + + // Copy to Frambuffer + memcpy(destBuf, buffer, len); + + LOG("BGA Framebuffer updated\n"); + } + + LEAVE('i', len); + return len; +} + +/** + * \fn INT int BGA_Ioctl(tVFS_Node *node, int id, void *data) + * \brief Handle messages to the device + */ +INT int BGA_Ioctl(tVFS_Node *node, int id, void *data) +{ + int ret = -2; + ENTER("pNode iId pData", node, id, data); + + switch(id) + { + case DRV_IOCTL_TYPE: + ret = DRV_TYPE_VIDEO; + break; + case DRV_IOCTL_IDENT: + memcpy(data, "BGA1", 4); + ret = 1; + break; + case DRV_IOCTL_VERSION: + ret = 0x100; + break; + case DRV_IOCTL_LOOKUP: // TODO: Implement + ret = 0; + break; + + case VIDEO_IOCTL_SETMODE: + ret = BGA_int_UpdateMode(*(int*)(data)); + break; + + case VIDEO_IOCTL_GETMODE: + ret = giBGA_CurrentMode; + break; + + case VIDEO_IOCTL_FINDMODE: + ret = BGA_int_FindMode((tVideo_IOCtl_Mode*)data); + break; + + case VIDEO_IOCTL_MODEINFO: + ret = BGA_int_ModeInfo((tVideo_IOCtl_Mode*)data); + break; + + // Request Access to LFB + case VIDEO_IOCTL_REQLFB: + ret = BGA_int_MapFB( *(void**)data ); + break; + + default: + LEAVE('i', -2); + return -2; + } + + LEAVE('i', ret); + return ret; +} + +//== Internal Functions == +/** + * \fn void BGA_int_WriteRegister(Uint16 reg, Uint16 value) + * \brief Writes to a BGA register + */ +void BGA_int_WriteRegister(Uint16 reg, Uint16 value) +{ + outw(VBE_DISPI_IOPORT_INDEX, reg); + outw(VBE_DISPI_IOPORT_DATA, value); +} + +INT Uint16 BGA_int_ReadRegister(Uint16 reg) +{ + outw(VBE_DISPI_IOPORT_INDEX, reg); + return inw(VBE_DISPI_IOPORT_DATA); +} + +#if 0 +INT void BGA_int_SetBank(Uint16 bank) +{ + BGA_int_WriteRegister(VBE_DISPI_INDEX_BANK, bank); +} +#endif + +/** + * \fn void BGA_int_SetMode(Uint16 width, Uint16 height, Uint16 bpp) + * \brief Sets the video mode from the dimensions and bpp given + */ +void BGA_int_SetMode(Uint16 width, Uint16 height) +{ + ENTER("iwidth iheight ibpp", width, height, bpp); + BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_DISABLED); + BGA_int_WriteRegister(VBE_DISPI_INDEX_XRES, width); + BGA_int_WriteRegister(VBE_DISPI_INDEX_YRES, height); + BGA_int_WriteRegister(VBE_DISPI_INDEX_BPP, 32); + BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_NOCLEARMEM | VBE_DISPI_LFB_ENABLED); + //BGA_int_WriteRegister(VBE_DISPI_INDEX_ENABLE, VBE_DISPI_ENABLED | VBE_DISPI_NOCLEARMEM); + LEAVE('-'); +} + +/** + * \fn int BGA_int_UpdateMode(int id) + * \brief Set current vide mode given a mode id + */ +int BGA_int_UpdateMode(int id) +{ + // Sanity Check + if(id < 0 || id >= BGA_MODE_COUNT) return -1; + + // Check if it is a text mode + if( gBGA_Modes[id].flags & MODEFLAG_TEXT ) + BGA_int_SetMode( + gBGA_Modes[id].width*giVT_CharWidth, + gBGA_Modes[id].height*giVT_CharHeight); + else // Graphics? + BGA_int_SetMode( + gBGA_Modes[id].width, + gBGA_Modes[id].height); + + giBGA_CurrentMode = id; + return id; +} + +/** + * \fn int BGA_int_FindMode(tVideo_IOCtl_Mode *info) + * \brief Find a mode matching the given options + */ +int BGA_int_FindMode(tVideo_IOCtl_Mode *info) +{ + int i; + int best = 0, bestFactor = 1000; + int factor, tmp; + int rqdProduct = info->width * info->height * info->bpp; + + ENTER("pinfo", info); + LOG("info = {width:%i,height:%i,bpp:%i})\n", info->width, info->height, info->bpp); + + for(i = 0; i < BGA_MODE_COUNT; i++) + { + #if DEBUG >= 2 + LogF("Mode %i (%ix%ix%i), ", i, gBGA_Modes[i].width, gBGA_Modes[i].height, gBGA_Modes[i].bpp); + #endif + + // Check if this mode is the same type as what we want + if( !(gBGA_Modes[i].flags & MODEFLAG_TEXT) != !(info->flags & VIDEO_FLAG_TEXT) ) + continue; + + // Ooh! A perfect match + if(gBGA_Modes[i].width == info->width + && gBGA_Modes[i].height == info->height + && gBGA_Modes[i].bpp == info->bpp) + { + #if DEBUG >= 2 + LogF("Perfect!\n"); + #endif + best = i; + break; + } + + // If not, how close are we? + tmp = gBGA_Modes[i].width * gBGA_Modes[i].height * gBGA_Modes[i].bpp; + tmp -= rqdProduct; + tmp = tmp < 0 ? -tmp : tmp; // tmp = ABS(tmp) + factor = tmp * 100 / rqdProduct; + + #if DEBUG >= 2 + LogF("factor = %i\n", factor); + #endif + + if(factor < bestFactor) + { + bestFactor = factor; + best = i; + } + } + + info->id = best; + info->width = gBGA_Modes[best].width; + info->height = gBGA_Modes[best].height; + info->bpp = gBGA_Modes[best].bpp; + + info->flags = 0; + if(gBGA_Modes[best].flags & MODEFLAG_TEXT) + info->flags |= VIDEO_FLAG_TEXT; + + return best; +} + +/** + * \fn int BGA_int_ModeInfo(tVideo_IOCtl_Mode *info) + * \brief Get mode information + */ +int BGA_int_ModeInfo(tVideo_IOCtl_Mode *info) +{ + // Sanity Check + if( !MM_IsUser( (Uint)info, sizeof(tVideo_IOCtl_Mode) ) ) { + return -EINVAL; + } + + if(info->id < 0 || info->id >= BGA_MODE_COUNT) return -1; + + info->width = gBGA_Modes[info->id].width; + info->height = gBGA_Modes[info->id].height; + info->bpp = gBGA_Modes[info->id].bpp; + + info->flags = 0; + if(gBGA_Modes[info->id].flags & MODEFLAG_TEXT) + info->flags |= VIDEO_FLAG_TEXT; + + return 1; +} + +/** + * \fn int BGA_int_MapFB(void *Dest) + * \brief Map the framebuffer into a process's space + * \param Dest User address to load to + */ +int BGA_int_MapFB(void *Dest) +{ + Uint i; + Uint pages; + + // Sanity Check + if((Uint)Dest > 0xC0000000) return 0; + if(gBGA_Modes[giBGA_CurrentMode].bpp < 15) return 0; // Only non-pallete modes are supported + + // Count required pages + pages = (gBGA_Modes[giBGA_CurrentMode].fbSize + 0xFFF) >> 12; + + // Check if there is space + for( i = 0; i < pages; i++ ) + { + if(MM_GetPhysAddr( (Uint)Dest + (i << 12) )) + return 0; + } + + // Map + for( i = 0; i < pages; i++ ) + MM_Map( (Uint)Dest + (i<<12), VBE_DISPI_LFB_PHYSICAL_ADDRESS + (i<<12) ); + + return 1; +} diff --git a/Modules/Makefile.tpl b/Modules/Makefile.tpl new file mode 100644 index 00000000..6d22b4c3 --- /dev/null +++ b/Modules/Makefile.tpl @@ -0,0 +1,29 @@ + +# Acess2 Module/Driver Templater Makefile +# Makefile.tpl + +-include ../../Makefile.cfg + +CPPFLAGS = -I../../Kernel/include -I../../Kernel/arch/$(ARCHDIR)/include -DARCH=$(ARCH) +CFLAGS = -Wall -Werror $(CPPFLAGS) + +OBJ := $(addsuffix .$(ARCH),$(OBJ)) +BIN = ../$(NAME).kmd.$(ARCH) + +.PHONY: all clean + +all: $(BIN) + +clean: + $(RM) $(BIN) $(OBJ) + +$(BIN): $(OBJ) + @echo --- $(LD) -o $@ + @$(LD) -T ../link.ld -shared -o $@ $(OBJ) + @echo --- $(LD) -o ../$(NAME).o.$(ARCH) + @$(CC) -Wl,-r -nostdlib -o ../$(NAME).o.$(ARCH) $(OBJ) + +%.o.$(ARCH): %.c Makefile ../Makefile.tpl ../../Makefile.cfg + @echo --- $(CC) -o $@ + @$(CC) $(CFLAGS) -o $@ -c $< + @$(CC) -M $(CPPFLAGS) -MT $@ -o $*.d $< diff --git a/Modules/NE2000/Makefile b/Modules/NE2000/Makefile new file mode 100644 index 00000000..f6f34859 --- /dev/null +++ b/Modules/NE2000/Makefile @@ -0,0 +1,7 @@ +# +# + +OBJ = ne2000.o +NAME = ne2000 + +-include ../Makefile.tpl diff --git a/Modules/NE2000/ne2000.c b/Modules/NE2000/ne2000.c new file mode 100644 index 00000000..a0321912 --- /dev/null +++ b/Modules/NE2000/ne2000.c @@ -0,0 +1,313 @@ +/* Acess2 + * NE2000 Driver + * + * See: ~/Sources/bochs/bochs.../iodev/ne2k.cc + */ +#define DEBUG 1 +#include +#include +#include +#include + +// === CONSTANTS === +#define MEM_START 0x40 +#define MEM_END 0xC0 +#define RX_FIRST (MEM_START) +#define RX_LAST (MEM_START+RX_BUF_SIZE-1) +#define RX_BUF_SIZE 0x40 +#define TX_FIRST (MEM_START+RX_BUF_SIZE) +#define TX_LAST (MEM_END) +#define TX_BUF_SIZE 0x40 + +static const struct { + Uint16 Vendor; + Uint16 Device; +} csaCOMPAT_DEVICES[] = { + {0x10EC, 0x8029}, // Realtek 8029 + {0x10EC, 0x8129} // Realtek 8129 +}; +#define NUM_COMPAT_DEVICES (sizeof(csaCOMPAT_DEVICES)/sizeof(csaCOMPAT_DEVICES[0])) + +enum eNe2k_Page0Read { + CMD = 0, //!< the master command register + CLDA0, //!< Current Local DMA Address 0 + CLDA1, //!< Current Local DMA Address 1 + BNRY, //!< Boundary Pointer (for ringbuffer) + TSR, //!< Transmit Status Register + NCR, //!< collisions counter + FIFO, //!< (for what purpose ??) + ISR, //!< Interrupt Status Register + CRDA0, //!< Current Remote DMA Address 0 + CRDA1, //!< Current Remote DMA Address 1 + RSR = 0xC //!< Receive Status Register +}; + +enum eNe2k_Page0Write { + PSTART = 1, //!< page start (init only) + PSTOP, //!< page stop (init only) + TPSR = 4, //!< transmit page start address + TBCR0, //!< transmit byte count (low) + TBCR1, //!< transmit byte count (high) + RSAR0 = 8, //!< remote start address (lo) + RSAR1, //!< remote start address (hi) + RBCR0, //!< remote byte count (lo) + RBCR1, //!< remote byte count (hi) + RCR, //!< receive config register + TCR, //!< transmit config register + DCR, //!< data config register (init) + IMR //!< interrupt mask register (init) +}; + +// === TYPES === +typedef struct sNe2k_Card { + Uint16 IOBase; //!< IO Port Address from PCI + Uint8 IRQ; //!< IRQ Assigned from PCI + + int NextMemPage; //!< Next Card Memory page to use + + Uint8 Buffer[RX_BUF_SIZE]; + + char Name[2]; // "0" + tVFS_Node Node; + Uint8 MacAddr[6]; +} tCard; + +// === PROTOTYPES === + int Ne2k_Install(char **Arguments); +char *Ne2k_ReadDir(tVFS_Node *Node, int Pos); +tVFS_Node *Ne2k_FindDir(tVFS_Node *Node, char *Name); +Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer); +Uint8 Ne2k_int_GetWritePage(tCard *Card, Uint16 Length); +void Ne2k_IRQHandler(int IntNum); + +// === GLOBALS === +MODULE_DEFINE(0, 0x0032, Ne2k, Ne2k_Install, NULL, NULL); +tDevFS_Driver gNe2k_DriverInfo = { + NULL, "ne2k", + { + .NumACLs = 1, + .ACLs = &gVFS_ACL_EveryoneRX, + .Flags = VFS_FFLAG_DIRECTORY, + .ReadDir = Ne2k_ReadDir, + .FindDir = Ne2k_FindDir + } +}; +Uint16 gNe2k_BaseAddress; + int giNe2k_CardCount = 0; +tCard *gpNe2k_Cards = NULL; + +// === CODE === +/** + * \fn int Ne2k_Install(char **Options) + * \brief Installs the NE2000 Driver + */ +int Ne2k_Install(char **Options) +{ + int i, j, k; + int count, id, base; + + // --- 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 ); + } + + // Enumerate Cards + k = 0; + gpNe2k_Cards = malloc( giNe2k_CardCount * sizeof(tCard) ); + memsetd(gpNe2k_Cards, 0, giNe2k_CardCount * sizeof(tCard) / 4); + for( i = 0; i < NUM_COMPAT_DEVICES; i ++ ) + { + count = PCI_CountDevices( csaCOMPAT_DEVICES[i].Vendor, csaCOMPAT_DEVICES[i].Device, 0 ); + for( j = 0; j < count; j ++,k ++ ) + { + id = PCI_GetDevice( csaCOMPAT_DEVICES[i].Vendor, csaCOMPAT_DEVICES[i].Device, 0, j ); + // Create Structure + base = PCI_AssignPort( id, 0, 0x20 ); + gpNe2k_Cards[ k ].IOBase = base; + gpNe2k_Cards[ k ].IRQ = PCI_GetIRQ( id ); + gpNe2k_Cards[ k ].NextMemPage = 64; + + // Install IRQ Handler + IRQ_AddHandler(gpNe2k_Cards[ k ].IRQ, Ne2k_IRQHandler); + + // Reset Card + outb( base + 0x1F, inb(base + 0x1F) ); + while( (inb( base+ISR ) & 0x80) == 0 ); + outb( base + ISR, 0x80 ); + + // Initialise Card + outb( base + CMD, 0x21 ); // No DMA and Stop + outb( base + DCR, 0x49 ); // Set WORD mode + outb( base + IMR, 0x00 ); + outb( base + ISR, 0xFF ); + outb( base + RCR, 0x20 ); // Reciever to Monitor + outb( base + TCR, 0x02 ); // Transmitter OFF (TCR.LB = 1, Internal Loopback) + 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); + gpNe2k_Cards[ k ].MacAddr[3] = inb(base+0x10); inb(base+0x10); + gpNe2k_Cards[ k ].MacAddr[4] = inb(base+0x10); inb(base+0x10); + gpNe2k_Cards[ k ].MacAddr[5] = inb(base+0x10); inb(base+0x10); + + outb( base+PSTART, RX_FIRST); // Set Receive Start + outb( base+BNRY, RX_LAST-1); // Set Boundary Page + outb( base+PSTOP, RX_LAST); // Set Stop Page + outb( base+ISR, 0xFF ); // Clear all ints + outb( base+CMD, 0x22 ); // No DMA, Start + outb( base+IMR, 0x3F ); // Set Interupt Mask + 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] + ); + + // Set VFS Node + gpNe2k_Cards[ k ].Name[0] = '0'+k; + gpNe2k_Cards[ k ].Name[1] = '\0'; + gpNe2k_Cards[ k ].Node.ImplPtr = &gpNe2k_Cards[ k ]; + gpNe2k_Cards[ k ].Node.NumACLs = 0; // Root Only + gpNe2k_Cards[ k ].Node.CTime = now(); + gpNe2k_Cards[ k ].Node.Write = Ne2k_Write; + } + } + + gNe2k_DriverInfo.RootNode.Size = giNe2k_CardCount; + DevFS_AddDevice( &gNe2k_DriverInfo ); + return 0; +} + +/** + * \fn char *Ne2k_ReadDir(tVFS_Node *Node, int Pos) + */ +char *Ne2k_ReadDir(tVFS_Node *Node, int Pos) +{ + char ret[2]; + if(Pos < 0 || Pos >= giNe2k_CardCount) return NULL; + ret[0] = '0'+Pos; + ret[1] = '\0'; + return strdup(ret); +} + +/** + * \fn tVFS_Node *Ne2k_FindDir(tVFS_Node *Node, char *Name) + */ +tVFS_Node *Ne2k_FindDir(tVFS_Node *Node, char *Name) +{ + if(Name[0] == '\0' || Name[1] != '\0') return NULL; + + return &gpNe2k_Cards[ Name[0]-'0' ].Node; +} + +/** + * \fn Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) + */ +Uint64 Ne2k_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer) +{ + tCard *Card = (tCard*)Node->ImplPtr; + Uint16 *buf = Buffer; + int rem = Length; + + ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer); + + // Sanity Check Length + if(Length > TX_BUF_SIZE) { + LEAVE('i', 0); + return 0; + } + + // Make sure that the card is in page 0 + outb(Card->IOBase + CMD, 0|0x22); // Page 0, Start, NoDMA + + // Clear Remote DMA Flag + outb(Card->IOBase + ISR, 0x40); // Bit 6 + + // Send Size - Remote Byte Count Register + outb(Card->IOBase + TBCR0, Length & 0xFF); + outb(Card->IOBase + TBCR1, Length >> 8); + + // Send Size - Remote Byte Count Register + outb(Card->IOBase + RBCR0, Length & 0xFF); + outb(Card->IOBase + RBCR1, Length >> 8); + + // Set up transfer + outb(Card->IOBase + RSAR0, 0x00); // Page Offset + outb(Card->IOBase + RSAR1, Ne2k_int_GetWritePage(Card, Length)); // 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) + outw(Card->IOBase + 0x10, *buf++); + + while( inb(Card->IOBase + ISR) == 0) // Wait for Remote DMA Complete + ; //Proc_Yield(); + + outb( Card->IOBase + ISR, 0x40 ); // ACK Interrupt + + // Send Packet + outb(Card->IOBase + CMD, 0|0x10|0x4|0x2); + + // Complete DMA + //outb(Card->IOBase + CMD, 0|0x20); + + LEAVE('i', Length); + return Length; +} + +/** + * \fn Uint8 Ne2k_int_GetWritePage(tCard *Card, Uint16 Length) + */ +Uint8 Ne2k_int_GetWritePage(tCard *Card, Uint16 Length) +{ + Uint8 ret = Card->NextMemPage; + + Card->NextMemPage += (Length + 0xFF) >> 8; + if(Card->NextMemPage >= TX_LAST) { + Card->NextMemPage -= TX_BUF_SIZE; + } + + return ret; +} + +/** + * \fn void Ne2k_IRQHandler(int IntNum) + */ +void Ne2k_IRQHandler(int IntNum) +{ + int i; + for( i = 0; i < giNe2k_CardCount; i++ ) + { + if(gpNe2k_Cards[i].IRQ == IntNum) { + LOG("Clearing interrupts on card %i (0x%x)\n", i, inb( gpNe2k_Cards[i].IOBase + ISR )); + outb( gpNe2k_Cards[i].IOBase + ISR, 0xFF ); // Reset All + return ; + } + } + Warning("[NE2K ] Recieved Unknown IRQ %i", IntNum); +} -- 2.20.1