Added Novell Eagle 2000 Driver
authorCasper Hornstrup <chorns@users.sourceforge.net>
Sun, 27 Aug 2000 16:35:31 +0000 (16:35 +0000)
committerCasper Hornstrup <chorns@users.sourceforge.net>
Sun, 27 Aug 2000 16:35:31 +0000 (16:35 +0000)
svn path=/trunk/; revision=1319

14 files changed:
reactos/Makefile
reactos/drivers/net/dd/ne2000/DIRS [new file with mode: 0644]
reactos/drivers/net/dd/ne2000/Makefile [new file with mode: 0644]
reactos/drivers/net/dd/ne2000/include/8390.h [new file with mode: 0644]
reactos/drivers/net/dd/ne2000/include/debug.h [new file with mode: 0644]
reactos/drivers/net/dd/ne2000/include/ne2000.h [new file with mode: 0644]
reactos/drivers/net/dd/ne2000/ne2000.def [new file with mode: 0644]
reactos/drivers/net/dd/ne2000/ne2000.rc [new file with mode: 0644]
reactos/drivers/net/dd/ne2000/ne2000/8390.c [new file with mode: 0644]
reactos/drivers/net/dd/ne2000/ne2000/MAKEFILE [new file with mode: 0644]
reactos/drivers/net/dd/ne2000/ne2000/RESOURCE.RC [new file with mode: 0644]
reactos/drivers/net/dd/ne2000/ne2000/SOURCES [new file with mode: 0644]
reactos/drivers/net/dd/ne2000/ne2000/main.c [new file with mode: 0644]
reactos/drivers/net/dd/ne2000/readme.txt [new file with mode: 0644]

index b0d586d..0b0b62e 100644 (file)
@@ -14,7 +14,7 @@ include rules.mak
 # Required to run the system
 #
 COMPONENTS = iface_native iface_additional ntoskrnl
-DLLS = ntdll kernel32 crtdll advapi32 fmifs gdi32 secur32
+DLLS = ntdll kernel32 crtdll advapi32 fmifs gdi32 secur32 user32
 SUBSYS = smss win32k csrss
 
 #
@@ -41,11 +41,13 @@ FS_DRIVERS = vfat
 # ndis tdi tcpip tditest
 NET_DRIVERS = ndis tcpip tditest
 
-KERNEL_SERVICES = $(DEVICE_DRIVERS) $(FS_DRIVERS) $(NET_DRIVERS)
+# ne2000
+NET_DEVICE_DRIVERS = ne2000
 
-APPS = args hello shell test cat bench apc shm lpc thread event file gditest \
-       pteb consume dump_shared_data vmtest
+KERNEL_SERVICES = $(DEVICE_DRIVERS) $(FS_DRIVERS) $(NET_DRIVERS) $(NET_DEVICE_DRIVERS)
 
+APPS = args hello shell test cat bench apc shm lpc thread event file gditest \
+       pteb consume dump_shared_data vmtest wstest
 #       objdir
 
 all: buildno $(COMPONENTS) $(DLLS) $(SUBSYS) $(LOADERS) $(KERNEL_SERVICES) $(APPS)
@@ -183,6 +185,21 @@ $(NET_DRIVERS:%=%_dist): %_dist:
 .PHONY: $(NET_DRIVERS) $(NET_DRIVERS:%=%_clean) $(NET_DRIVERS:%=%_install) \
         $(NET_DRIVERS:%=%_dist)
 
+$(NET_DEVICE_DRIVERS): %:
+       make -C services/net/dd/$*
+
+$(NET_DEVICE_DRIVERS:%=%_clean): %_clean:
+       make -C services/net/dd/$* clean
+
+$(NET_DEVICE_DRIVERS:%=%_install): %_install:
+       make -C services/net/dd/$* install
+
+$(NET_DEVICE_DRIVERS:%=%_dist): %_dist:
+       make -C services/net/dd/$* dist
+
+.PHONY: $(NET_DEVICE_DRIVERS) $(NET_DEVICE_DRIVERS:%=%_clean) \
+        $(NET_DEVICE_DRIVERS:%=%_install) $(NET_DEVICE_DRIVERS:%=%_dist)
+
 #
 # Kernel loaders
 #
diff --git a/reactos/drivers/net/dd/ne2000/DIRS b/reactos/drivers/net/dd/ne2000/DIRS
new file mode 100644 (file)
index 0000000..98e9381
--- /dev/null
@@ -0,0 +1 @@
+DIRS= ne2000
diff --git a/reactos/drivers/net/dd/ne2000/Makefile b/reactos/drivers/net/dd/ne2000/Makefile
new file mode 100644 (file)
index 0000000..3a2f68f
--- /dev/null
@@ -0,0 +1,118 @@
+# $Id: Makefile,v 1.1 2000/08/27 16:35:04 chorns Exp $
+#
+# NE2000.SYS build spec
+#
+
+TARGETNAME=ne2000
+
+BASE_CFLAGS = -I./include -I../../../../include -DNDIS_MINIPORT_DRIVER
+
+RESOURCE_OBJECT  = $(TARGETNAME).coff
+NE2000_OBJECTS   = ne2000/main.o ne2000/8390.o
+IMPORT_LIBS      = ../../ndis/ndis.a ../../../../ntoskrnl/ntoskrnl.a
+
+
+all: objects $(TARGETNAME).sys
+
+objects:
+       mkdir objects
+
+objects/ne2000.o: $(NE2000_OBJECTS)
+       $(LD) -r $(NE2000_OBJECTS) -o objects/ne2000.o
+
+OBJECTS = objects/ne2000.o
+
+$(TARGETNAME).coff: $(TARGETNAME).rc ../../../include/reactos/resource.h
+
+ifeq ($(DOSCLI),yes)
+CLEAN_FILES = \
+               *.o ne2000\*.o objects\*.o $(TARGETNAME).coff \
+        $(TARGETNAME).a junk.tmp base.tmp temp.exp \
+               $(TARGETNAME).sys $(TARGETNAME).sym
+else
+CLEAN_FILES = \
+               *.o ne2000\*.o objects/*.o $(TARGETNAME).coff \
+        $(TARGETNAME).a junk.tmp base.tmp temp.exp \
+               $(TARGETNAME).sys $(TARGETNAME).sym
+endif
+
+
+$(TARGETNAME).sys: $(OBJECTS) $(TARGETNAME).def
+       $(LD) -r $(OBJECTS) -o $(TARGETNAME).o
+       $(DLLTOOL) \
+               --dllname $(TARGETNAME).sys \
+               --def $(TARGETNAME).def \
+               --output-lib $(TARGETNAME).a \
+               --kill-at
+       $(CC) \
+        -specs=../../../../specs \
+               --subsystem=native \
+               -mdll \
+               --dll \
+               -e _DriverEntry@8 \
+               -o junk.tmp \
+               -Wl,--image-base,0x10000 \
+               -Wl,--file-alignment,0x1000 \
+               -Wl,--section-alignment,0x1000 \
+               -Wl,--defsym,_end=end \
+               -Wl,--defsym,_edata=__data_end__ \
+               -Wl,--defsym,_etext=etext \
+               -Wl,--base-file,base.tmp \
+        $(TARGETNAME).o \
+        $(IMPORT_LIBS)
+       - $(RM) junk.tmp
+       $(DLLTOOL) \
+               --dllname $(TARGETNAME).sys \
+               --base-file base.tmp \
+               --output-exp temp.exp \
+               --def $(TARGETNAME).def \
+               --kill-at
+       - $(RM) base.tmp
+       $(CC) \
+        -specs=../../../../specs \
+               --subsystem=native \
+               -mdll \
+               --dll \
+               -e _DriverEntry@8 \
+               -o $(TARGETNAME).sys \
+               -Wl,--image-base,0x0 \
+               -Wl,--file-alignment,0x1000 \
+               -Wl,--section-alignment,0x1000 \
+               -Wl,--defsym,_end=end \
+               -Wl,--defsym,_edata=__data_end__ \
+               -Wl,--defsym,_etext=etext \
+               -Wl,temp.exp \
+               $(TARGETNAME).o \
+        $(IMPORT_LIBS)
+       - $(RM) temp.exp
+       $(NM) --numeric-sort $(TARGETNAME).sys > $(TARGETNAME).sym
+
+clean: $(CLEAN_FILES:%=%_clean)
+
+$(CLEAN_FILES:%=%_clean): %_clean:
+       - $(RM) $*
+
+.PHONY: clean $(CLEAN_FILES:%=%_clean)
+
+install: $(FLOPPY_DIR)/drivers/$(TARGETNAME).sys
+
+$(FLOPPY_DIR)/drivers/$(TARGETNAME).sys: $(TARGETNAME).sys
+ifeq ($(DOSCLI),yes)
+       $(CP) $(TARGETNAME).sys $(FLOPPY_DIR)\drivers\$(TARGETNAME).sys
+else
+       $(CP) $(TARGETNAME).sys $(FLOPPY_DIR)/drivers/$(TARGETNAME).sys
+endif
+
+dist: $(DIST_DIR)/drivers/$(TARGETNAME).sys
+
+$(DIST_DIR)/drivers/$(TARGETNAME).sys: $(TARGETNAME).sys
+ifeq ($(DOSCLI),yes)
+       $(CP) $(TARGETNAME).sys ..\..\$(DIST_DIR)\drivers\$(TARGETNAME).sys
+else
+       $(CP) $(TARGETNAME).sys ../../$(DIST_DIR)/drivers/$(TARGETNAME).sys
+endif
+
+#WITH_DEBUGGING      = yes
+#WIN32_LEAN_AND_MEAN = yes
+#WARNINGS_ARE_ERRORS = yes
+include ../../../../rules.mak
diff --git a/reactos/drivers/net/dd/ne2000/include/8390.h b/reactos/drivers/net/dd/ne2000/include/8390.h
new file mode 100644 (file)
index 0000000..f1e0f7b
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS Novell Eagle 2000 driver
+ * FILE:        include/8390.h
+ * PURPOSE:     National Semiconductor 8390 NIC definitions
+ */
+#ifndef __8390_H
+#define __8390_H
+
+/* Page 0 register layout (PS1 = 0, PS0 = 0) */
+#define PG0_CR      0x00    /* Command Register (R/W) */
+#define PG0_CLDA0   0x01    /* Current Local DMA Address 0 (R) */
+#define PG0_PSTART  0x01    /* Page Start Register (W) */
+#define PG0_CLDA1   0x02    /* Current Local DMA Address 1 (R) */
+#define PG0_PSTOP   0x02    /* Page Stop Register (W) */
+#define PG0_BNRY    0x03    /* Boundary Pointer (R/W) */
+#define PG0_TSR     0x04    /* Transmit Status Register (R) */
+#define PG0_TPSR    0x04    /* Transmit Page Start Register (W) */
+#define PG0_NCR     0x05    /* Number of Collisions Register (R) */
+#define PG0_TBCR0   0x05    /* Transmit Byte Count Register 0 (W) */
+#define PG0_FIFO    0x06    /* FIFO (R) */
+#define PG0_TBCR1   0x06    /* Transmit Byte Count Register 1 (W) */
+#define PG0_ISR     0x07    /* Interrupt Status Register (R/W) */
+#define PG0_CRDA0   0x08    /* Current Remote DMA Address 0 (R) */
+#define PG0_RSAR0   0x08    /* Remote Start Address Register 0 (W) */
+#define PG0_CRDA1   0x09    /* Current Remote DMA Address 1 (R) */
+#define PG0_RSAR1   0x09    /* Remote Start Address Register 1 (W) */
+#define PG0_RBCR0   0x0A    /* Remote Byte Count Register 0 (W) */
+#define PG0_RBCR1   0x0B    /* Remote Byte Count Register 1 (W) */
+#define PG0_RSR     0x0C    /* Receive Status Register (R) */
+#define PG0_RCR     0x0C    /* Receive Configuration Register (W) */
+#define PG0_CNTR0   0x0D    /* Tally Counter 0 (Frame Alignment Errors) (R) */
+#define PG0_TCR     0x0D    /* Transmit Configuration Register (W) */
+#define PG0_CNTR1   0x0E    /* Tally Counter 1 (CRC Errors) (R) */
+#define PG0_DCR     0x0E    /* Data Configuration Register (W) */
+#define PG0_CNTR2   0x0F    /* Tally Counter 2 (Missed Packet Errors) (R) */
+#define PG0_IMR     0x0F    /* Interrupt Mask Register (W) */
+
+/* Page 1 register layout (PS1 = 0, PS0 = 1) */
+#define PG1_CR      0x00    /* Command Register (R/W) */
+#define PG1_PAR     0x01    /* Physical Address Registers (6 registers) (R/W) */
+#define PG1_CURR    0x07    /* Current Page Register (R/W) */
+#define PG1_MAR     0x08    /* Multicast Address Registers (8 registers) (R/W) */
+
+/* Page 2 register layout (PS1 = 1, PS0 = 0) */
+#define PG2_CR      0x00    /* Command Register (R/W) */
+#define PG2_PSTART  0x01    /* Page Start Register (R) */
+#define PG2_CLDA0   0x01    /* Current Local DMA Address 0 (W) */
+#define PG2_PSTOP   0x02    /* Page Stop Register (R) */
+#define PG2_CLDA1   0x02    /* Current Local DMA Address 1 (W) */
+#define PG2_RNPP    0x03    /* Remote Next Packet Pointer (R/W) */
+#define PG2_TPSR    0x04    /* Transmit Page Start Address (R) */
+#define PG2_LNPP    0x05    /* Local Next Packet Pointer (R/W) */
+#define PG2_AC1     0x06    /* Address Counter (Upper) (R/W) */
+#define PG2_AC0     0x07    /* Address Counter (Lower) (R/W) */
+#define PG2_RCR     0x0C    /* Receive Configuration Register (R) */
+#define PG2_TCR     0x0D    /* Transmit Configuration Register (R) */
+#define PG2_DCR     0x0E    /* Data Configuration Register (R) */
+#define PG2_IMR     0x0F    /* Interrupt Mask Register (R) */
+
+/* Bits in PGX_CR - Command Register */
+#define CR_STP      0x01    /* Stop chip */
+#define CR_STA      0x02    /* Start chip */
+#define CR_TXP      0x04    /* Transmit a frame */
+#define CR_RD0      0x08    /* Remote read */
+#define CR_RD1      0x10    /* Remote write */
+#define CR_RD2      0x20    /* Abort/complete remote DMA */
+#define CR_PAGE0    0x00    /* Select page 0 of chip registers */
+#define CR_PAGE1    0x40    /* Select page 1 of chip registers */
+#define CR_PAGE2    0x80    /* Select page 2 of chip registers */
+
+/* Bits in PG0_ISR - Interrupt Status Register */
+#define ISR_PRX     0x01    /* Packet received, no errors */
+#define ISR_PTX     0x02    /* Packet transmitted, no errors */
+#define ISR_RXE     0x04    /* Receive error */
+#define ISR_TXE     0x08    /* Transmit error */
+#define ISR_OVW     0x10    /* Overwrite warning */
+#define ISR_CNT     0x20    /* Counter overflow */
+#define ISR_RDC     0x40    /* Remote DMA complete */
+#define ISR_RST     0x80    /* Reset status */
+
+/* Bits in PG0_TSR - Transmit Status Register */
+#define TSR_PTX     0x01h   /* Packet transmitted without error */
+#define TSR_COL     0x04h   /* Collided at least once */
+#define TSR_ABT     0x08h   /* Collided 16 times and was dropped */
+#define TSR_CRS     0x10h   /* Carrier sense lost */
+#define TSR_FU      0x20h   /* Transmit FIFO Underrun */
+#define TSR_CDH     0x40h   /* Collision detect heartbeat */
+#define TSR_OWC     0x80h   /* Out of window collision */
+
+/* Bits for PG0_RCR - Receive Configuration Register */
+#define RCR_SEP     0x01    /* Save error packets */
+#define RCR_AR      0x02    /* Accept runt packets */
+#define RCR_AB      0x04    /* Accept broadcasts */
+#define RCR_AM      0x08    /* Accept multicast */
+#define RCR_PRO     0x10    /* Promiscuous physical addresses */
+#define RCR_MON     0x20    /* Monitor mode */
+
+/* Bits in PG0_RSR - Receive Status Register */
+#define RSR_PRX     0x01    /* Received packet intact */
+#define RSR_CRC     0x02    /* CRC error */
+#define RSR_FAE     0x04    /* Frame alignment error */
+#define RSR_FO      0x08    /* FIFO overrun */
+#define RSR_MPA     0x10    /* Missed packet */
+#define RSR_PHY     0x20    /* Physical/multicast address */
+#define RSR_DIS     0x40    /* Receiver disabled (monitor mode) */
+#define RSR_DFR     0x80    /* Deferring */
+
+/* Bits in PG0_TCR - Transmit Configuration Register */
+#define TCR_CRC  0x01       /* Inhibit CRC, do not append CRC */
+#define TCR_LOOP 0x02       /* Set loopback mode */
+#define TCR_LB01 0x06       /* Encoded loopback control */
+#define TCR_ATD  0x08       /* Auto transmit disable */
+#define TCR_OFST 0x10       /* Collision offset enable */
+
+/* Bits in PG0_DCR - Data Configuration Register */
+#define DCR_WTS     0x01    /* Word transfer mode selection */
+#define DCR_BOS     0x02    /* Byte order selection */
+#define DCR_LAS     0x04    /* Long address selection */
+#define DCR_LS      0x08    /* Loopback select (when 0) */
+#define DCR_ARM     0x10    /* Autoinitialize remote */
+#define DCR_FT00    0x00    /* Burst length selection (1 word/2 bytes) */
+#define DCR_FT01    0x20    /* burst length selection (2 words/4 bytes) */
+#define DCR_FT10    0x40    /* Burst length selection (4 words/8 bytes) */
+#define DCR_FT11    0x60    /* Burst length selection (6 words/12 bytes) */
+
+/* Bits in PG0_IMR - Interrupt Mask Register */
+#define IMR_PRXE    0x01    /* Packet received interrupt enable */
+#define IMR_PTXE    0x02    /* Packet transmitted interrupt enable */
+#define IMR_RXEE    0x04    /* Receive error interrupt enable */
+#define IMR_TXEE    0x08    /* Transmit error interrupt enable */
+#define IMR_OVWE    0x10    /* Overwrite warning interrupt enable */
+#define IMR_CNTE    0x20    /* Counter overflow interrupt enable */
+#define IMR_RDCE    0x40    /* Remote DMA complete interrupt enable */
+#define IMR_ALLE    0x7F    /* All interrupts enable */
+
+
+/* NIC prepended structure to a received packet */
+typedef struct _PACKET_HEADER {
+    UCHAR Status;           /* See RSR_* constants */
+    UCHAR NextPacket;       /* Pointer to next packet in chain */
+    USHORT PacketLength;    /* Length of packet including this header */
+} PACKET_HEADER, PPACKET_HEADER;
+
+
+#define NICDisableInterrupts(Adapter) \
+    NdisRawWritePortUchar((Adapter)->IOBase + PG0_IMR, 0x00);
+
+#define NICEnableInterrupts(Adapter) \
+    NdisRawWritePortUchar((Adapter)->IOBase + PG0_IMR, (Adapter)->InterruptMask);
+
+VOID MiniportHandleInterrupt(
+    IN  NDIS_HANDLE MiniportAdapterContext);
+
+#endif /* __8390_H */
+
+/* EOF */
diff --git a/reactos/drivers/net/dd/ne2000/include/debug.h b/reactos/drivers/net/dd/ne2000/include/debug.h
new file mode 100644 (file)
index 0000000..5b96c6f
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS Novell Eagle 2000 driver
+ * FILE:        include/debug.h
+ * PURPOSE:     Debugging support macros
+ * DEFINES:     DBG     - Enable debug output
+ *              NASSERT - Disable assertions
+ */
+#ifndef __DEBUG_H
+#define __DEBUG_H
+
+#define NORMAL_MASK    0x000000FF
+#define SPECIAL_MASK   0xFFFFFF00
+#define MIN_TRACE      0x00000001
+#define MID_TRACE      0x00000002
+#define MAX_TRACE      0x00000003
+
+#define DEBUG_MEMORY   0x00000100
+#define DEBUG_ULTRA    0xFFFFFFFF
+
+#ifdef DBG
+
+extern ULONG DebugTraceLevel;
+
+#ifdef _MSC_VER
+
+#define NDIS_DbgPrint(_t_, _x_) \
+    if (((DebugTraceLevel & NORMAL_MASK) >= _t_) || \
+        ((DebugTraceLevel & _t_) > NORMAL_MASK)) { \
+        DbgPrint("(%s:%d) ", __FILE__, __LINE__); \
+        DbgPrint _x_ ; \
+    }
+
+#else /* _MSC_VER */
+
+#define NDIS_DbgPrint(_t_, _x_) \
+    if (((DebugTraceLevel & NORMAL_MASK) >= _t_) || \
+        ((DebugTraceLevel & _t_) > NORMAL_MASK)) { \
+        DbgPrint("(%s:%d)(%s) ", __FILE__, __LINE__, __FUNCTION__); \
+        DbgPrint _x_ ; \
+    }
+
+#endif /* _MSC_VER */
+
+
+#ifdef ASSERT
+#undef ASSERT
+#endif
+
+#ifdef NASSERT
+#define ASSERT(x)
+#else /* NASSERT */
+#define ASSERT(x) if (!(x)) { NDIS_DbgPrint(MIN_TRACE, ("Assertion "#x" failed at %s:%d\n", __FILE__, __LINE__)); KeBugCheck(0); }
+#endif /* NASSERT */
+
+#define ASSERT_IRQL(x) ASSERT(KeGetCurrentIrql() <= (x))
+
+#else /* DBG */
+
+#define NDIS_DbgPrint(_t_, _x_)
+
+#define ASSERT_IRQL(x)
+#define ASSERT(x)
+
+#endif /* DBG */
+
+
+#define assert(x) ASSERT(x)
+#define assert_irql(x) ASSERT_IRQL(x)
+
+
+#ifdef _MSC_VER
+
+#define UNIMPLEMENTED \
+    NDIS_DbgPrint(MIN_TRACE, ("The function at %s:%d is unimplemented, \
+        but come back another day.\n", __FILE__, __LINE__));
+
+#else /* _MSC_VER */
+
+#define UNIMPLEMENTED \
+    NDIS_DbgPrint(MIN_TRACE, ("%s at %s:%d is unimplemented, \
+        but come back another day.\n", __FUNCTION__, __FILE__, __LINE__));
+
+#endif /* _MSC_VER */
+
+
+#define CHECKPOINT \
+    do { NDIS_DbgPrint(MIN_TRACE, ("%s:%d\n", __FILE__, __LINE__)); } while(0);
+
+#endif /* __DEBUG_H */
+
+/* EOF */
diff --git a/reactos/drivers/net/dd/ne2000/include/ne2000.h b/reactos/drivers/net/dd/ne2000/include/ne2000.h
new file mode 100644 (file)
index 0000000..b630afe
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS Novell Eagle 2000 driver
+ * FILE:        include/ne2000.h
+ * PURPOSE:     NE2000 driver definitions
+ */
+#ifndef __NE2000_H
+#define __NE2000_H
+
+#ifdef _MSC_VER
+
+#ifndef ULONG_PTR
+#define ULONG ULONG_PTR
+#endif
+
+#include <ndis.h>
+#else
+#include <net/ndis.h>
+#endif
+#include <8390.h>
+#include <debug.h>
+
+/* Define NOCARD to test NDIS without a card */
+//#define NOCARD
+
+/* NE2000 sepcific constants */
+#define NIC_DATA            0x10    /* Data register */
+#define NIC_RESET           0x1F    /* Reset register */
+
+
+/* Global constants */
+
+#define DRIVER_NDIS_MAJOR_VERSION 3
+#define DRIVER_NDIS_MINOR_VERSION 0
+
+#define DRIVER_DEFAULT_IO_BASE_ADDRESS      0x300
+#define DRIVER_DEFAULT_INTERRUPT_NUMBER     10
+
+#define DRIVER_MAX_MULTICAST_LIST_SIZE  8
+
+#define DRIVER_VENDOR_DESCRIPTION       "Novell Eagle 2000 Adapter."
+#define DRIVER_VENDOR_DRIVER_VERSION    0x0100  /* 1.0 */
+
+#define DRIVER_FRAME_SIZE           1514    /* Size of an ethernet frame */
+#define DRIVER_HEADER_SIZE          14      /* Size of an ethernet header */
+#define DRIVER_LENGTH_OF_ADDRESS    6       /* Size of an ethernet address */
+
+/* Maximum lookahead buffer size */
+#define DRIVER_MAXIMUM_LOOKAHEAD (252 - DRIVER_HEADER_SIZE)
+
+/* Size of a block in a buffer ring */
+#define DRIVER_BLOCK_SIZE   256
+
+
+/* Default number of transmit buffers */
+#define DRIVER_DEFAULT_TX_BUFFER_COUNT 12
+
+/* Interrupt Mask Register value */
+#define DRIVER_INTERRUPT_MASK   IMR_ALLE - IMR_RDCE
+
+
+
+/* Global structures */
+
+typedef struct _MINIPORT_RESERVED
+{
+    PNDIS_PACKET Next;
+} MINIPORT_RESERVED, *PMINIPORT_RESERVED;
+
+#define RESERVED(Packet) ((PMINIPORT_RESERVED)((Packet)->u.s1.MiniportReserved))
+
+typedef UCHAR DRIVER_HARDWARE_ADDRESS[DRIVER_LENGTH_OF_ADDRESS];
+
+/* Information about an adapter */
+typedef struct _NIC_ADAPTER
+{
+    /* Entry on global adapter list */
+    LIST_ENTRY ListEntry;
+    /* Adapter handle */
+    NDIS_HANDLE MiniportAdapterHandle;
+    /* NDIS interrupt object */
+    NDIS_MINIPORT_INTERRUPT Interrupt;
+
+    /* I/O base address and interrupt number of adapter */
+    ULONG IoBaseAddress;
+    ULONG InterruptNumber;
+
+    /* Mapped address of the I/O base port */
+    PUCHAR IOBase;
+
+    /* TRUE if the NIC can transfer in word mode */
+    BOOLEAN WordMode;
+
+    /* Base address and size of the onboard memory window */
+    PUCHAR RamBase;
+    UINT RamSize;
+
+    /* Station Address PROM (SAPROM) */
+    UCHAR SAPROM[16];
+
+    /* Onboard ethernet address from the manufacturer */
+    DRIVER_HARDWARE_ADDRESS PermanentAddress;
+
+    /* Ethernet address currently in use */
+    DRIVER_HARDWARE_ADDRESS StationAddress;
+
+    /* Maximum number of multicast addresses this adapter supports */
+    ULONG MaxMulticastListSize;
+
+    /* List of multicast addresses in use */
+    DRIVER_HARDWARE_ADDRESS Addresses[DRIVER_MAX_MULTICAST_LIST_SIZE];
+
+    /* Current multicast address mask */
+    UCHAR MulticastAddressMask[8];
+
+    /* Masked interrupts (IMR value) */
+    ULONG InterruptMask;
+
+    /* Interrupts that have occurred */
+    UCHAR InterruptStatus;
+
+    /* Current packet filter */
+    ULONG PacketFilter;
+
+    /* Lookahead buffer */
+    UINT LookaheadSize;
+    UCHAR Lookahead[DRIVER_MAXIMUM_LOOKAHEAD + DRIVER_HEADER_SIZE];
+
+    /* Receive buffer ring */
+    UINT PageStart;
+    UINT PageStop;
+    UINT CurrentPage;
+    UINT NextPacket;
+
+    /* TRUE if there was a buffer overflow */
+    BOOLEAN BufferOverflow;
+
+    /* TRUE if an error occurred during reception of a packet */
+    BOOLEAN ReceiveError;
+
+    /* TRUE if an error occurred during transmission of a packet */
+    BOOLEAN TransmitError;
+
+    /* TRUE if a transmit interrupt is pending */
+    BOOLEAN TransmitPending;
+
+    /* Received packet header */
+    PACKET_HEADER PacketHeader;
+
+    /* Offset in onboard RAM of received packet */
+    ULONG PacketOffset;
+
+    /* TRUE if receive indications are done and should be completed */
+    BOOLEAN DoneIndicating;
+
+    /* Transmit buffers */
+    UINT TXStart;   /* Start block of transmit buffer ring */
+    UINT TXCount;   /* Number of blocks in transmit buffer ring */
+    UINT TXFree;    /* Number of free transmit buffers */
+    UINT TXNext;    /* Next buffer to use */
+    /* Length of packet. 0 means buffer is unused */
+    INT TXSize[DRIVER_DEFAULT_TX_BUFFER_COUNT];
+    INT TXCurrent;  /* Current buffer beeing transmitted. -1 means none */
+
+    /* Head of transmit queue */
+    PNDIS_PACKET TXQueueHead;
+    /* Tail of transmit queue */
+    PNDIS_PACKET TXQueueTail;
+
+    /* Statistics */
+    ULONG FrameAlignmentErrors;
+    ULONG CrcErrors;
+    ULONG MissedPackets;
+
+    /* Flags used for driver cleanup */
+    BOOLEAN IOPortRangeRegistered;
+    BOOLEAN InterruptRegistered;
+} NIC_ADAPTER, *PNIC_ADAPTER;
+
+/* Global driver information */
+typedef struct _DRIVER_INFORMATION
+{
+    NDIS_HANDLE NdisWrapperHandle;  /* Returned from NdisInitializeWrapper */
+    NDIS_HANDLE NdisMacHandle;      /* Returned from NdisRegisterMac */
+    LIST_ENTRY  AdapterListHead;    /* Adapters this driver control */
+} DRIVER_INFORMATION, *PDRIVER_INFORMATION;
+
+
+
+/* Global variable */
+
+extern DRIVER_INFORMATION DriverInfo;
+extern NDIS_PHYSICAL_ADDRESS HighestAcceptableMax;
+
+
+
+/* Prototypes */
+
+BOOLEAN NICCheck(
+    PNIC_ADAPTER Adapter);
+
+NDIS_STATUS NICInitialize(
+    PNIC_ADAPTER Adapter);
+
+NDIS_STATUS NICSetup(
+    PNIC_ADAPTER Adapter);
+
+NDIS_STATUS NICStart(
+    PNIC_ADAPTER Adapter);
+
+NDIS_STATUS NICStop(
+    PNIC_ADAPTER Adapter);
+
+NDIS_STATUS NICReset(
+    PNIC_ADAPTER Adapter);
+
+VOID NICUpdateCounters(
+    PNIC_ADAPTER Adapter);
+
+VOID NICReadDataAlign(
+    PNIC_ADAPTER Adapter,
+    PUSHORT Target,
+    ULONG Source,
+    USHORT Length);
+
+VOID NICWriteDataAlign(
+    PNIC_ADAPTER Adapter,
+    ULONG Target,
+    PUSHORT Source,
+    USHORT Length);
+
+VOID NICReadData(
+    PNIC_ADAPTER Adapter,
+    PUCHAR Target,
+    ULONG Source,
+    USHORT Length);
+
+VOID NICWriteData(
+    PNIC_ADAPTER Adapter,
+    ULONG Target,
+    PUCHAR Source,
+    USHORT Length);
+
+VOID NICTransmit(
+    PNIC_ADAPTER Adapter);
+
+#endif /* __NE2000_H */
+
+/* EOF */
diff --git a/reactos/drivers/net/dd/ne2000/ne2000.def b/reactos/drivers/net/dd/ne2000/ne2000.def
new file mode 100644 (file)
index 0000000..cb1da92
--- /dev/null
@@ -0,0 +1,7 @@
+; Novell Eagle 2000 driver - ReactOS Operating System
+
+LIBRARY NE2000.SYS
+
+EXPORTS
+
+; EOF
diff --git a/reactos/drivers/net/dd/ne2000/ne2000.rc b/reactos/drivers/net/dd/ne2000/ne2000.rc
new file mode 100644 (file)
index 0000000..d345102
--- /dev/null
@@ -0,0 +1,38 @@
+#include <defines.h>
+#include <reactos/resource.h>
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+       FILEVERSION     RES_UINT_FV_MAJOR,RES_UINT_FV_MINOR,RES_UINT_FV_REVISION,RES_UINT_FV_BUILD
+       PRODUCTVERSION  RES_UINT_PV_MAJOR,RES_UINT_PV_MINOR,RES_UINT_PV_REVISION,RES_UINT_PV_BUILD
+       FILEFLAGSMASK   0x3fL
+#ifdef _DEBUG
+       FILEFLAGS       0x1L
+#else
+       FILEFLAGS       0x0L
+#endif
+       FILEOS          0x40004L
+       FILETYPE        0x2L
+       FILESUBTYPE     0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "CompanyName",      RES_STR_COMPANY_NAME
+            VALUE "FileDescription",  "Novell NE2000 network driver\0"
+            VALUE "FileVersion",         "0.0.0\0"
+            VALUE "InternalName",        "ne2000\0"
+            VALUE "LegalCopyright",      RES_STR_LEGAL_COPYRIGHT
+            VALUE "OriginalFilename", "ne2000.sys\0"
+            VALUE "ProductName",         RES_STR_PRODUCT_NAME
+            VALUE "ProductVersion",      RES_STR_PRODUCT_VERSION
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
+
diff --git a/reactos/drivers/net/dd/ne2000/ne2000/8390.c b/reactos/drivers/net/dd/ne2000/ne2000/8390.c
new file mode 100644 (file)
index 0000000..9de55f7
--- /dev/null
@@ -0,0 +1,1343 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS Novell Eagle 2000 driver
+ * FILE:        ne2000/8390.c
+ * PURPOSE:     DP8390 NIC specific routines
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 27/08-2000 Created
+ */
+#include <ne2000.h>
+
+
+BOOLEAN NICCheck(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Tests for a NIC
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ * RETURNS:
+ *     TRUE if NIC is believed to be present, FALSE if not
+ * NOTES:
+ *     If the adapter responds correctly to a
+ *     stop command we assume it is present
+ */
+{
+    UCHAR Tmp;
+
+    /* Disable interrupts */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_IMR, 0);
+
+    /* Stop the NIC */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2);
+
+    /* Pause for 1.6ms */
+    NdisStallExecution(1600);
+
+    /* Read NIC response */
+    NdisRawReadPortUchar(Adapter->IOBase + PG0_CR, &Tmp);
+
+    if ((Tmp == (CR_RD2 | CR_STP)) || (Tmp == (CR_RD2 | CR_STP | CR_STA)))
+        return TRUE;
+    else
+        return FALSE;
+}
+
+
+BOOLEAN NICTestAddress(
+    PNIC_ADAPTER Adapter,
+    ULONG Address)
+/*
+ * FUNCTION: Tests if an address is writable
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ * RETURNS:
+ *     TRUE if the RAM size was found, FALSE if not
+ * NOTES:
+ *     Starts at 1KB and tests every 1KB up to 64KB
+ */
+{
+    USHORT Data;
+    USHORT Tmp;
+
+    /* Read one word */
+    NICReadDataAlign(Adapter, &Data, Address, 0x02);
+
+    /* Alter it */
+    Data ^= 0xFFFF;
+
+    /* Write it back */
+    NICWriteDataAlign(Adapter, Address, &Data, 0x02);
+
+    /* Check if it has changed on the NIC */
+    NICReadDataAlign(Adapter, &Tmp, Address, 0x02);
+
+    return (Data == Tmp);
+}
+
+
+BOOLEAN NICTestRAM(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Finds out how much RAM a NIC has
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ * RETURNS:
+ *     TRUE if the RAM size was found, FALSE if not
+ * NOTES:
+ *     Start at 1KB and test for every 1KB up to 64KB
+ */
+{
+    ULONG Base;
+
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    /* Locate RAM base address */
+    for (Base = 0x0400; Base < 0x10000; Base += 0x0400) {
+        if (NICTestAddress(Adapter, Base))
+            break;
+    }
+
+    if (Base == 0x10000) {
+        /* No RAM on this board */
+        NDIS_DbgPrint(MIN_TRACE, ("No RAM found on board.\n"));
+        return FALSE;
+    }
+
+    Adapter->RamBase = (PUCHAR)Base;
+
+    /* Find RAM size */
+    for (; Base < 0x10000; Base += 0x0400) {
+        if (!NICTestAddress(Adapter, Base))
+            break;
+    }
+
+    Adapter->RamSize = (UINT)(Base - (ULONG_PTR)Adapter->RamBase);
+
+    NDIS_DbgPrint(MID_TRACE, ("RAM is at (0x%X). Size is (0x%X).\n",
+        Adapter->RamBase, Adapter->RamSize));
+
+    return TRUE;
+}
+
+
+VOID NICSetPhysicalAddress(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Initializes the physical address on the NIC
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ * NOTES:
+ *     The physical address is taken from Adapter.
+ *     The NIC is stopped by this operation
+ */
+{
+    UINT i;
+
+    /* Select page 1 */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE1);
+
+    /* Initialize PAR - Physical Address Registers */
+    for (i = 0; i < 0x06; i++)
+        NdisRawWritePortUchar(Adapter->IOBase + PG1_PAR + i, Adapter->StationAddress[i]);
+
+    /* Go back to page 0 */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
+}
+
+
+VOID NICSetMulticastAddressMask(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Initializes the multicast address mask on the NIC
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ * NOTES:
+ *     The multicast address mask is taken from Adapter.
+ *     The NIC is stopped by this operation
+ */
+{
+    UINT i;
+
+    /* Select page 1 */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE1);
+
+    /* Initialize MAR - Multicast Address Registers */
+    for (i = 0; i < 0x08; i++)
+        NdisRawWritePortUchar(Adapter->IOBase + PG1_MAR + i, Adapter->MulticastAddressMask[i]);
+
+    /* Go back to page 0 */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
+}
+
+
+BOOLEAN NICReadSAPROM(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Reads the Station Address PROM data from the NIC
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ * RETURNS:
+ *     TRUE if a the NIC is an NE2000
+ * NOTES:
+ *    This routine also determines if the NIC can support word mode transfers
+ *    and if it does initializes the NIC for word mode.
+ *    The station address in the adapter structure is initialized with
+ *    the address from the SAPROM
+ */
+{
+    UINT i;
+    UCHAR Buffer[32];
+    UCHAR WordLength;
+
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    /* Read Station Address PROM (SAPROM) which is 16 bytes at remote DMA address 0.
+       Some cards double the data read which we must compensate for */
+
+    /* Initialize RBCR0 and RBCR1 - Remote Byte Count Registers */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, 0x20);
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, 0x00);
+
+    /* Initialize RSAR0 and RSAR1 - Remote Start Address Registers */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR0, 0x00);
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR1, 0x00);
+
+    /* Select page 0, read and start the NIC */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD0 | CR_PAGE0);
+
+    /* Read one byte at a time */
+    WordLength = 2; /* Assume a word is two bytes */
+    for (i = 0; i < 32; i += 2) {
+        NdisRawReadPortUchar(Adapter->IOBase + NIC_DATA, &Buffer[i]);
+        NdisRawReadPortUchar(Adapter->IOBase + NIC_DATA, &Buffer[i + 1]);
+               if (Buffer[i] != Buffer[i + 1])
+                       WordLength = 1; /* A word is one byte long */
+       }
+
+    /* If WordLength is 2 the data read before was doubled. We must compensate for this */
+    if (WordLength == 2) {
+        NDIS_DbgPrint(MIN_TRACE, ("NE2000 found.\n"));
+
+        Adapter->WordMode = TRUE;
+
+        /* Move the SAPROM data to the adapter object */
+        for (i = 0; i < 16; i++)
+            Adapter->SAPROM[i] = Buffer[i * 2];
+
+        /* Copy the station address */
+        NdisMoveMemory(
+            (PVOID)&Adapter->StationAddress,
+            (PVOID)&Adapter->SAPROM,
+            DRIVER_LENGTH_OF_ADDRESS);
+
+        /* Initialize DCR - Data Configuration Register (word mode/4 words FIFO) */
+        NdisRawWritePortUchar(Adapter->IOBase + PG0_DCR, DCR_WTS | DCR_LS | DCR_FT10);
+
+        return TRUE;
+    } else {
+        NDIS_DbgPrint(MIN_TRACE, ("NE1000 found.\n"));
+
+        Adapter->WordMode = FALSE;
+
+        return FALSE;
+    }
+}
+
+
+NDIS_STATUS NICInitialize(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Initializes a NIC
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ * RETURNS:
+ *     Status of NIC initialization
+ * NOTES:
+ *     The NIC is put into loopback mode
+ */
+{
+    UCHAR Tmp;
+
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    if (!NICCheck(Adapter)) {
+        NDIS_DbgPrint(MIN_TRACE, ("No adapter found at (0x%X).\n", Adapter->IOBase));
+        return NDIS_STATUS_ADAPTER_NOT_FOUND;
+    } else
+        NDIS_DbgPrint(MID_TRACE, ("Adapter found at (0x%X).\n", Adapter->IOBase));
+
+    /* Reset the NIC */
+    NdisRawReadPortUchar(Adapter->IOBase + NIC_RESET, &Tmp);
+
+    /* Wait for 1.6ms */
+    NdisStallExecution(1600);
+
+    /* Write the value back  */
+    NdisRawWritePortUchar(Adapter->IOBase + NIC_RESET, Tmp);
+
+    /* Select page 0 and stop NIC */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
+   
+    /* Initialize DCR - Data Configuration Register (byte mode/8 bytes FIFO) */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_DCR, DCR_LS | DCR_FT10);
+
+    /* Clear RBCR0 and RBCR1 - Remote Byte Count Registers */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, 0x00);
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, 0x00);
+
+    /* Initialize RCR - Receive Configuration Register (monitor mode) */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RCR, RCR_MON);
+
+    /* Enter loopback mode (internal NIC module loopback) */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_TCR, TCR_LOOP);
+
+    /* Read the Station Address PROM */
+    if (!NICReadSAPROM(Adapter))
+        return NDIS_STATUS_ADAPTER_NOT_FOUND;
+
+    NDIS_DbgPrint(MID_TRACE, ("Station address is (%02X %02X %02X %02X %02X %02X).\n",
+        Adapter->StationAddress[0], Adapter->StationAddress[1],
+        Adapter->StationAddress[2], Adapter->StationAddress[3],
+        Adapter->StationAddress[4], Adapter->StationAddress[5]));
+
+    /* Select page 0 and start NIC */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE0);
+
+    /* Clear ISR - Interrupt Status Register */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, 0xFF);
+
+    /* Find NIC RAM size */
+    NICTestRAM(Adapter);
+
+    return NDIS_STATUS_SUCCESS;
+}
+
+
+NDIS_STATUS NICSetup(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Sets up a NIC
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ * RETURNS:
+ *     Status of operation
+ * NOTES:
+ *     The NIC is put into loopback mode
+ */
+{
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    if (Adapter->WordMode ) {
+        /* Initialize DCR - Data Configuration Register (word mode/4 words FIFO) */
+        NdisRawWritePortUchar(Adapter->IOBase + PG0_DCR, DCR_WTS | DCR_LS | DCR_FT10);
+    } else {
+        /* Initialize DCR - Data Configuration Register (byte mode/8 bytes FIFO) */
+        NdisRawWritePortUchar(Adapter->IOBase + PG0_DCR, DCR_LS | DCR_FT10);
+    }
+
+    /* Clear RBCR0 and RBCR1 - Remote Byte Count Registers */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, 0x00);
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, 0x00);
+
+    /* Initialize RCR - Receive Configuration Register (monitor mode) */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RCR, RCR_MON);
+
+    /* Enter loopback mode (internal NIC module loopback) */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_TCR, TCR_LOOP);
+
+    /* Set boundary page */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_BNRY, Adapter->NextPacket);
+
+    /* Set start page */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_PSTART, Adapter->PageStart);
+
+    /* Set stop page */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_PSTOP, Adapter->PageStop);
+
+    /* Program our address on the NIC */
+    NICSetPhysicalAddress(Adapter);
+
+    /* Program the multicast address mask on the NIC */
+    NICSetMulticastAddressMask(Adapter);
+
+    /* Select page 1 and stop NIC */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE1);
+
+    /* Initialize current page register */
+    NdisRawWritePortUchar(Adapter->IOBase + PG1_CURR, Adapter->PageStart + 1);
+
+    /* Select page 0 and stop NIC */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
+
+    /* Clear ISR - Interrupt Status Register */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, 0xFF);
+
+    /* Initialize IMR - Interrupt Mask Register */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_IMR, Adapter->InterruptMask);
+
+    /* Select page 0 and start NIC */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE0);
+
+    Adapter->CurrentPage            = Adapter->PageStart + 1;
+    Adapter->NextPacket             = Adapter->PageStart + 1;
+    Adapter->BufferOverflow         = FALSE;
+    Adapter->ReceiveError           = FALSE;
+    Adapter->TransmitError          = FALSE;
+
+    NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+    return NDIS_STATUS_SUCCESS;
+}
+
+
+NDIS_STATUS NICStart(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Starts a NIC
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    /* Take NIC out of loopback mode */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_TCR, 0x00);
+
+    /* Initialize RCR - Receive Configuration Register (accept all) */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RCR, RCR_AB | RCR_AM | RCR_PRO);
+
+    return NDIS_STATUS_SUCCESS;
+}
+
+
+NDIS_STATUS NICStop(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Stops a NIC
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    UCHAR Tmp;
+    UINT i;
+
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    /* Select page 0 and stop NIC */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
+
+    /* Clear Remote Byte Count Register so ISR_RST will be set */
+    NdisRawWritePortUchar( Adapter->IOBase + PG0_RBCR0, 0x00);
+    NdisRawWritePortUchar( Adapter->IOBase + PG0_RBCR0, 0x00);
+
+    /* Wait for ISR_RST to be set, but timeout after 2ms */
+    for (i = 0; i < 4; i++) {
+        NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &Tmp);
+        if (Tmp & ISR_RST)
+            break;
+
+        NdisStallExecution(500);
+    }
+
+#ifdef DBG
+    if (i == 4)
+        NDIS_DbgPrint(MIN_TRACE, ("NIC was not reset after 2ms.\n"));
+#endif
+
+    /* Initialize RCR - Receive Configuration Register (monitor mode) */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RCR, RCR_MON);
+
+    /* Initialize TCR - Transmit Configuration Register (loopback mode) */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_TCR, TCR_LOOP);
+
+    /* Start NIC */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2);
+
+    return NDIS_STATUS_SUCCESS;
+}
+
+
+NDIS_STATUS NICReset(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Resets a NIC
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    UCHAR Tmp;
+
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    /* Stop the NIC */
+    NICStop(Adapter);
+
+    /* Reset the NIC */
+    NdisRawReadPortUchar(Adapter->IOBase + NIC_RESET, &Tmp);
+
+    /* Wait for 1.6ms */
+    NdisStallExecution(1600);
+
+    /* Write the value back  */
+    NdisRawWritePortUchar(Adapter->IOBase + NIC_RESET, Tmp);
+
+    /* Restart the NIC */
+    NICStart(Adapter);
+
+    return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID NICStartTransmit(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Starts transmitting a packet
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ */
+{
+    UINT Length;
+
+    /* Set start of frame */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_TPSR,
+        Adapter->TXStart + Adapter->TXCurrent * DRIVER_BLOCK_SIZE);
+
+    /* Set length of frame */
+    Length = Adapter->TXSize[Adapter->TXCurrent];
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_TBCR0, Length & 0xFF);
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_TBCR1, Length >> 8);
+
+    /* Start transmitting */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_TXP | CR_RD2);
+
+    NDIS_DbgPrint(MAX_TRACE, ("Transmitting. Buffer (%d)  Size (%d).\n",
+        Adapter->TXCurrent,
+        Length));
+
+}
+
+
+VOID NICSetBoundaryPage(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Sets the boundary page on the adapter to be one less than NextPacket
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ */
+{
+    if (Adapter->NextPacket == Adapter->PageStart) {
+        NdisRawWritePortUchar(Adapter->IOBase + PG0_BNRY,
+            (UCHAR)(Adapter->PageStop - 1));
+    } else {
+        NdisRawWritePortUchar(Adapter->IOBase + PG0_BNRY,
+            (UCHAR)(Adapter->NextPacket - 1));
+    }
+}
+
+
+VOID NICGetCurrentPage(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Retrieves the current page from the adapter
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ */
+{
+    UCHAR Current;
+
+    /* Select page 1 */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE1);
+
+    /* Read current page */
+    NdisRawReadPortUchar(Adapter->IOBase + PG1_CURR, &Current);
+
+    /* Select page 0 */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
+
+    Adapter->CurrentPage = Current;
+}
+
+
+VOID NICUpdateCounters(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Updates counters
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ */
+{
+    UCHAR Tmp;
+
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    NdisRawReadPortUchar(Adapter->IOBase + PG0_CNTR0, &Tmp);
+    Adapter->FrameAlignmentErrors += Tmp;
+
+    NdisRawReadPortUchar(Adapter->IOBase + PG0_CNTR1, &Tmp);
+    Adapter->CrcErrors += Tmp;
+
+    NdisRawReadPortUchar(Adapter->IOBase + PG0_CNTR2, &Tmp);
+    Adapter->MissedPackets += Tmp;
+}
+
+
+VOID NICReadDataAlign(
+    PNIC_ADAPTER Adapter,
+    PUSHORT Target,
+    ULONG Source,
+    USHORT Length)
+/*
+ * FUNCTION: Copies data from a NIC's RAM into a buffer
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ *     Target  = Pointer to buffer to copy data into (in host memory)
+ *     Source  = Offset into NIC's RAM (must be an even number)
+ *     Length  = Number of bytes to copy from NIC's RAM (must be an even number)
+ */
+{
+    UCHAR Tmp;
+    USHORT Count;
+
+    Count = Length;
+
+    /* Select page 0 and start the NIC */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE0);
+
+    /* Initialize RSAR0 and RSAR1 - Remote Start Address Registers */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR0, (UCHAR)(Source & 0xFF));
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR1, (UCHAR)(Source >> 8));
+
+    /* Initialize RBCR0 and RBCR1 - Remote Byte Count Registers */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, (UCHAR)(Count & 0xFF));
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, (UCHAR)(Count >> 8));
+
+    /* Select page 0, read and start the NIC */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD0 | CR_PAGE0);
+    
+    if (Adapter->WordMode)
+        NdisRawReadPortBufferUshort(Adapter->IOBase + NIC_DATA, Target, Count >> 1);
+    else
+        NdisRawReadPortBufferUchar(Adapter->IOBase + NIC_DATA, Target, Count);
+
+    /* Wait for remote DMA to complete, but timeout after some time */
+    for (Count = 0; Count < 0xFFFF; Count++) {
+        NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &Tmp);
+        if (Tmp & ISR_RDC)
+            break;
+
+        NdisStallExecution(4);
+    }
+
+#ifdef DBG
+    if (Count == 0xFFFF)
+        NDIS_DbgPrint(MIN_TRACE, ("Remote DMA did not complete.\n"));
+#endif
+
+    /* Clear remote DMA bit in ISR - Interrupt Status Register */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, ISR_RDC);
+}
+
+
+VOID NICWriteDataAlign(
+    PNIC_ADAPTER Adapter,
+    ULONG Target,
+    PUSHORT Source,
+    USHORT Length)
+/*
+ * FUNCTION: Copies data from a buffer into the NIC's RAM
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ *     Target  = Offset into NIC's RAM (must be an even number)
+ *     Source  = Pointer to buffer to copy data from (in host memory)
+ *     Length  = Number of bytes to copy from the buffer (must be an even number)
+ */
+{
+    UCHAR Tmp;
+    USHORT Count;
+
+    /* Select page 0 and start the NIC */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE0);
+
+    /* Handle read-before-write bug */
+
+    /* Initialize RSAR0 and RSAR1 - Remote Start Address Registers */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR0, (UCHAR)(Target & 0xFF));
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR1, (UCHAR)(Target >> 8));
+
+    /* Initialize RBCR0 and RBCR1 - Remote Byte Count Registers */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, 0x02);
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, 0x00);
+
+    /* Read and start the NIC */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD0 | CR_PAGE0);
+
+    /* Read data */
+    NdisRawReadPortUshort(Adapter->IOBase + NIC_DATA, &Count);
+
+    /* Wait for remote DMA to complete, but timeout after some time */
+    for (Count = 0; Count < 0xFFFF; Count++) {
+        NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &Tmp);
+        if (Tmp & ISR_RDC)
+            break;
+
+        NdisStallExecution(4);
+    }
+
+#ifdef DBG
+    if (Count == 0xFFFF)
+        NDIS_DbgPrint(MIN_TRACE, ("Remote DMA did not complete.\n"));
+#endif
+
+    /* Clear remote DMA bit in ISR - Interrupt Status Register */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, ISR_RDC);
+
+
+    /* Now output some data */
+
+    Count = Length;
+
+    /* Initialize RSAR0 and RSAR1 - Remote Start Address Registers */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR0, (UCHAR)(Target & 0xFF));
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR1, (UCHAR)(Target >> 8));
+
+    /* Initialize RBCR0 and RBCR1 - Remote Byte Count Registers */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, (UCHAR)(Count & 0xFF));
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, (UCHAR)(Count >> 8));
+
+    /* Write and start the NIC */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD1 | CR_PAGE0);
+    
+    if (Adapter->WordMode)
+        NdisRawWritePortBufferUshort(Adapter->IOBase + NIC_DATA, Source, Count >> 1);
+    else
+        NdisRawWritePortBufferUchar(Adapter->IOBase + NIC_DATA, Source, Count);
+
+    /* Wait for remote DMA to complete, but timeout after some time */
+    for (Count = 0; Count < 0xFFFF; Count++) {
+        NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &Tmp);
+        if (Tmp & ISR_RDC)
+            break;
+
+        NdisStallExecution(4);
+    }
+
+#ifdef DBG
+    if (Count == 0xFFFF)
+        NDIS_DbgPrint(MIN_TRACE, ("Remote DMA did not complete.\n"));
+#endif
+
+    /* Clear remote DMA bit in ISR - Interrupt Status Register */
+    NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, ISR_RDC);
+}
+
+
+VOID NICReadData(
+    PNIC_ADAPTER Adapter,
+    PUCHAR Target,
+    ULONG Source,
+    USHORT Length)
+/*
+ * FUNCTION: Copies data from a NIC's RAM into a buffer
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ *     Target  = Pointer to buffer to copy data into (in host memory)
+ *     Source  = Offset into NIC's RAM
+ *     Length  = Number of bytes to copy from NIC's RAM
+ */
+{
+    USHORT Tmp;
+
+    /* Avoid transfers to odd addresses */
+    if (Source & 0x01) {
+        /* Transfer one word and use the MSB */
+        NICReadDataAlign(Adapter, &Tmp, Source - 1, 0x02);
+        *Target = (UCHAR)(Tmp >> 8);
+        Source++;
+        Target++;
+        Length--;
+    }
+
+    if (Length & 0x01) {
+        /* Transfer as many words as we can without exceeding the buffer length */
+        Tmp = Length & 0xFFFE;
+        NICReadDataAlign(Adapter, (PUSHORT)Target, Source, Tmp);
+        Source            += Tmp;
+        (ULONG_PTR)Target += Tmp;
+
+        /* Read one word and keep the LSB */
+        NICReadDataAlign(Adapter, &Tmp, Source, 0x02);
+        *Target = (UCHAR)(Tmp & 0x00FF);
+    } else
+        /* Transfer the rest of the data */
+        NICReadDataAlign(Adapter, (PUSHORT)Target, Source, Length);
+}
+
+
+VOID NICWriteData(
+    PNIC_ADAPTER Adapter,
+    ULONG Target,
+    PUCHAR Source,
+    USHORT Length)
+/*
+ * FUNCTION: Copies data from a buffer into NIC's RAM
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ *     Target  = Offset into NIC's RAM to store data
+ *     Source  = Pointer to buffer to copy data from (in host memory)
+ *     Length  = Number of bytes to copy from buffer
+ */
+{
+    USHORT Tmp;
+
+    /* Avoid transfers to odd addresses */
+    if (Target & 0x01) {
+        /* Read one word */
+        NICReadDataAlign(Adapter, &Tmp, Target - 1, 0x02);
+
+        /* Merge LSB with the new byte which become the new MSB */
+        Tmp = (Tmp & 0x00FF) | (*Source << 8);
+
+        /* Finally write the value back */
+        NICWriteDataAlign(Adapter, Target - 1, &Tmp, 0x02);
+
+        /* Update pointers */
+        (ULONG_PTR)Source += 1;
+        (ULONG_PTR)Target += 1;
+        Length--;
+    }
+
+    if (Length & 0x01) {
+        /* Transfer as many words as we can without exceeding the transfer length */
+        Tmp = Length & 0xFFFE;
+        NICWriteDataAlign(Adapter, Target, (PUSHORT)Source, Tmp);
+        Source            += Tmp;
+        (ULONG_PTR)Target += Tmp;
+
+        /* Read one word */
+        NICReadDataAlign(Adapter, &Tmp, Target, 0x02);
+
+        /* Merge MSB with the new byte which become the new LSB */
+        Tmp = (Tmp & 0xFF00) | (*Source);
+
+        /* Finally write the value back */
+        NICWriteDataAlign(Adapter, Target, &Tmp, 0x02);
+    } else
+        /* Transfer the rest of the data */
+        NICWriteDataAlign(Adapter, Target, (PUSHORT)Source, Length);
+}
+
+
+VOID NICIndicatePacket(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Indicates a packet to the wrapper
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ */
+{
+    UINT IndicateLength;
+
+    IndicateLength = (Adapter->PacketHeader.PacketLength <
+        (Adapter->LookaheadSize + DRIVER_HEADER_SIZE))?
+        (Adapter->PacketHeader.PacketLength) :
+        (Adapter->LookaheadSize + DRIVER_HEADER_SIZE);
+
+    /* Fill the lookahead buffer */
+    NICReadData(Adapter,
+                (PUCHAR)&Adapter->Lookahead,
+                Adapter->PacketOffset + sizeof(PACKET_HEADER),
+                IndicateLength + DRIVER_HEADER_SIZE);
+
+    NDIS_DbgPrint(MAX_TRACE, ("Indicating (%d) bytes.\n", IndicateLength));
+
+#if 0
+    NDIS_DbgPrint(MAX_TRACE, ("FRAME:\n"));
+    for (i = 0; i < (IndicateLength + 7) / 8; i++) {
+        NDIS_DbgPrint(MAX_TRACE, ("%02X %02X %02X %02X %02X %02X %02X %02X\n",
+            Adapter->Lookahead[i*8+0],
+            Adapter->Lookahead[i*8+1],
+            Adapter->Lookahead[i*8+2],
+            Adapter->Lookahead[i*8+3],
+            Adapter->Lookahead[i*8+4],
+            Adapter->Lookahead[i*8+5],
+            Adapter->Lookahead[i*8+6],
+            Adapter->Lookahead[i*8+7]));
+    }
+#endif
+
+    if (IndicateLength >= DRIVER_HEADER_SIZE) {
+        NdisMEthIndicateReceive(Adapter->MiniportAdapterHandle,
+                                NULL,
+                                (PVOID)&Adapter->Lookahead,
+                                DRIVER_HEADER_SIZE,
+                                (PVOID)&Adapter->Lookahead[DRIVER_HEADER_SIZE],
+                                IndicateLength - DRIVER_HEADER_SIZE,
+                                Adapter->PacketHeader.PacketLength - DRIVER_HEADER_SIZE);
+    } else {
+        NdisMEthIndicateReceive(Adapter->MiniportAdapterHandle,
+                                NULL,
+                                (PVOID)&Adapter->Lookahead,
+                                IndicateLength,
+                                NULL,
+                                0,
+                                0);
+    }
+}
+
+
+VOID NICReadPacket(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Reads a full packet from the receive buffer ring
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ */
+{
+    UCHAR Tmp;
+    BOOLEAN SkipPacket = FALSE;
+
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    /* Check if receive buffer ring is empty */
+
+    /* Read boundary page */
+    NdisRawReadPortUchar(Adapter->IOBase + PG0_BNRY, &Tmp);
+
+    /* Get the header of the next packet in the receive ring */
+    Adapter->PacketOffset = Adapter->NextPacket << 8;
+    NICReadData(Adapter,
+                (PUCHAR)&Adapter->PacketHeader,
+                Adapter->PacketOffset,
+                sizeof(PACKET_HEADER));
+
+    NDIS_DbgPrint(MAX_TRACE, ("HEADER: (Status)       (0x%X)\n", Adapter->PacketHeader.Status));
+    NDIS_DbgPrint(MAX_TRACE, ("HEADER: (NextPacket)   (0x%X)\n", Adapter->PacketHeader.NextPacket));
+    NDIS_DbgPrint(MAX_TRACE, ("HEADER: (PacketLength) (0x%X)\n", Adapter->PacketHeader.PacketLength));
+
+    if (Adapter->PacketHeader.PacketLength < 64  ||
+        Adapter->PacketHeader.PacketLength > 1518) {
+        NDIS_DbgPrint(MAX_TRACE, ("Bogus packet size (%d).\n",
+            Adapter->PacketHeader.PacketLength));
+        SkipPacket = TRUE;
+    }
+
+    if (SkipPacket) {
+        /* Skip packet */
+        Adapter->NextPacket = Adapter->CurrentPage;
+    } else {
+        NICIndicatePacket(Adapter);
+
+        /* Go to the next free buffer in receive ring */
+        Adapter->NextPacket = Adapter->PacketHeader.NextPacket;
+    }
+
+    /* Update boundary page */
+    NICSetBoundaryPage(Adapter);
+}
+
+
+VOID NICWritePacket(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Writes a full packet to the transmit buffer ring
+ * ARGUMENTS:
+ *     Adapter  = Pointer to adapter information
+ * NOTES:
+ *     There must be enough free buffers available in the transmit buffer ring.
+ *     The packet is taken from the head of the transmit queue and the position
+ *     into the transmit buffer ring is taken from TXNext
+ */
+{
+    PNDIS_BUFFER SrcBuffer;
+    UINT BytesToCopy, SrcSize, DstSize;
+    PUCHAR SrcData;
+    ULONG DstData;
+    UINT TXStart;
+    UINT TXStop;
+
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    TXStart = Adapter->TXStart * DRIVER_BLOCK_SIZE;
+    TXStop  = (Adapter->TXStart + Adapter->TXCount) * DRIVER_BLOCK_SIZE;
+
+    NdisQueryPacket(Adapter->TXQueueHead,
+                    NULL,
+                    NULL,
+                    &SrcBuffer,
+                    &Adapter->TXSize[Adapter->TXNext]);
+
+    NDIS_DbgPrint(MAX_TRACE, ("Packet Size (%d) is now (%d).\n",
+        Adapter->TXNext,
+        Adapter->TXSize[Adapter->TXNext]));
+
+    NdisQueryBuffer(SrcBuffer, (PVOID)&SrcData, &SrcSize);
+
+    DstData = TXStart + Adapter->TXNext * DRIVER_BLOCK_SIZE;
+    DstSize = TXStop - DstData;
+
+    /* Start copying the data */
+    for (;;) {
+        BytesToCopy = (SrcSize < DstSize)? SrcSize : DstSize;
+
+        NICWriteData(Adapter, DstData, SrcData, BytesToCopy);
+
+        (ULONG_PTR)SrcData += BytesToCopy;
+        SrcSize            -= BytesToCopy;
+        DstData            += BytesToCopy;
+        DstSize            -= BytesToCopy;
+
+        if (SrcSize == 0) {
+            /* No more bytes in source buffer. Proceed to
+               the next buffer in the source buffer chain */
+            NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
+            if (!SrcBuffer)
+                break;
+
+            NdisQueryBuffer(SrcBuffer, (PVOID)&SrcData, &SrcSize);
+        }
+
+        if (DstSize == 0) {
+            /* Wrap around the end of the transmit buffer ring */
+            DstData = TXStart;
+            DstSize = Adapter->TXCount * DRIVER_BLOCK_SIZE;
+        }
+    }
+}
+
+
+BOOLEAN NICPrepareForTransmit(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Prepares a packet for transmission
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ * NOTES:
+ *     There must be at least one packet in the transmit queue
+ * RETURNS:
+ *     TRUE if a packet was prepared, FALSE if not
+ */
+{
+    UINT Length;
+    UINT BufferCount;
+    PNDIS_PACKET Packet;
+
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    /* Calculate number of buffers needed to transmit packet */
+    NdisQueryPacket(Adapter->TXQueueHead,
+                    NULL,
+                    NULL,
+                    NULL,
+                    &Length);
+
+    BufferCount = (Length + DRIVER_BLOCK_SIZE - 1) / DRIVER_BLOCK_SIZE;
+
+    if (BufferCount > Adapter->TXFree) {
+        NDIS_DbgPrint(MID_TRACE, ("No transmit resources. Have (%d) buffers, need (%d).\n",
+            Adapter->TXFree, BufferCount));
+        /* We don't have the resources to transmit this packet right now */
+        return FALSE;
+    }
+
+    /* Write the packet to the card */
+    NICWritePacket(Adapter);
+
+    /* If the NIC is not transmitting, reset the current transmit pointer */
+    if (Adapter->TXCurrent == -1)
+        Adapter->TXCurrent = Adapter->TXNext;
+
+    Adapter->TXNext  = (Adapter->TXNext + BufferCount) % Adapter->TXCount;
+    Adapter->TXFree -= BufferCount;
+
+    /* Remove the packet from the queue */
+    Packet = Adapter->TXQueueHead;
+    Adapter->TXQueueHead = RESERVED(Packet)->Next;
+
+    if (Packet == Adapter->TXQueueTail)
+        Adapter->TXQueueTail = NULL;
+
+    /* Assume the transmit went well */
+    NdisMSendComplete(Adapter->MiniportAdapterHandle,
+                      Packet,
+                      NDIS_STATUS_SUCCESS);
+
+    return TRUE;
+}
+
+
+VOID NICTransmit(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Starts transmitting packets in the transmit queue
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ * NOTES:
+ *     There must be at least one packet in the transmit queue
+ */
+{
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    if (Adapter->TXCurrent == -1) {
+        /* NIC is not transmitting, so start transmitting now */
+
+        /* Load next packet onto the card, and start transmitting */
+        if (NICPrepareForTransmit(Adapter))
+            NICStartTransmit(Adapter);
+    }
+}
+
+
+VOID HandleReceive(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Handles reception of a packet
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ * NOTES:
+ *     Buffer overflows are also handled here
+ */
+{
+    UINT i;
+    UCHAR Tmp;
+    UINT PacketCount;
+
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    Adapter->DoneIndicating = FALSE;
+    PacketCount = 0;
+
+    NICGetCurrentPage(Adapter);
+
+    if (Adapter->BufferOverflow) {
+
+        NDIS_DbgPrint(MAX_TRACE, ("Receive ring overflow.\n"));
+
+        /* Select page 0 and stop the NIC */
+        NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
+        
+        /* Clear RBCR0,RBCR1 - Remote Byte Count Registers */
+        NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, 0x00);
+        NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, 0x00);
+
+        /* Wait for ISR_RST to be set, but timeout after 2ms */
+        for (i = 0; i < 4; i++) {
+            NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &Tmp);
+            if (Tmp & ISR_RST)
+                break;
+
+            NdisStallExecution(500);
+        }
+
+        if ((Adapter->InterruptStatus & (ISR_PTX | ISR_TXE)) == 0) {
+            /* We may need to restart the transmitter */
+            Adapter->TransmitPending = TRUE;
+        }
+
+        /* Initialize TCR - Transmit Configuration Register to loopback mode 1 */
+        NdisRawWritePortUchar(Adapter->IOBase + PG0_TCR, TCR_LOOP);
+
+        /* Start NIC */
+        NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2);
+
+        NICStart(Adapter);
+
+        Adapter->BufferOverflow = FALSE;
+    }
+
+    if (Adapter->ReceiveError) {
+        NDIS_DbgPrint(MAX_TRACE, ("Receive error.\n"));
+
+        /* Skip this packet */
+        Adapter->NextPacket = Adapter->CurrentPage;
+        NICSetBoundaryPage(Adapter);
+
+        Adapter->ReceiveError = FALSE;
+    }
+
+    for (;;) {
+        NICGetCurrentPage(Adapter);
+
+        if (Adapter->CurrentPage == Adapter->NextPacket) {
+            NDIS_DbgPrint(MAX_TRACE, ("No more packets.\n"));
+            break;
+        } else {
+            NDIS_DbgPrint(MAX_TRACE, ("Got a packet in the receive ring.\n"));
+
+            /* Read packet from receive buffer ring */
+            NICReadPacket(Adapter);
+
+            Adapter->DoneIndicating = TRUE;
+
+            PacketCount++;
+            if (PacketCount == 10) {
+                /* Don't starve transmit interrupts */
+                break;
+            }
+        }
+    }
+
+    if ((Adapter->TransmitPending) && (Adapter->TXCurrent != -1)) {
+        NDIS_DbgPrint(MAX_TRACE, ("Retransmitting current packet at (%d).\n", Adapter->TXCurrent));
+        /* Retransmit packet */
+        NICStartTransmit(Adapter);
+        Adapter->TransmitPending = FALSE;
+    }
+
+    if (Adapter->DoneIndicating)
+        NdisMEthIndicateReceiveComplete(Adapter->MiniportAdapterHandle);
+}
+
+
+VOID HandleTransmit(
+    PNIC_ADAPTER Adapter)
+/*
+ * FUNCTION: Handles transmission of a packet
+ * ARGUMENTS:
+ *     Adapter = Pointer to adapter information
+ */
+{
+    UINT Length;
+    UINT BufferCount;
+
+    if (Adapter->TransmitError) {
+        /* FIXME: Retransmit now or let upper layer protocols handle retransmit? */
+        Adapter->TransmitError = FALSE;
+    }
+
+    /* Free transmit buffers */
+    Length      = Adapter->TXSize[Adapter->TXCurrent];
+    BufferCount = (Length + DRIVER_BLOCK_SIZE - 1) / DRIVER_BLOCK_SIZE;
+
+    NDIS_DbgPrint(MAX_TRACE, ("Freeing (%d) buffers at (%d).\n",
+        BufferCount,
+        Adapter->TXCurrent));
+
+    Adapter->TXFree += BufferCount;
+    Adapter->TXSize[Adapter->TXCurrent] = 0;
+    Adapter->TXCurrent = (Adapter->TXCurrent + BufferCount) % Adapter->TXCount;
+
+    if (Adapter->TXSize[Adapter->TXCurrent] == 0) {
+        NDIS_DbgPrint(MAX_TRACE, ("No more packets in transmit buffer.\n"));
+
+        Adapter->TXCurrent = -1;
+    }
+
+    if (Adapter->TXQueueTail) {
+        if (NICPrepareForTransmit(Adapter))
+            NICStartTransmit(Adapter);
+    }
+}
+
+
+VOID MiniportHandleInterrupt(
+    IN  NDIS_HANDLE MiniportAdapterContext)
+/*
+ * FUNCTION: Handler for deferred processing of interrupts
+ * ARGUMENTS:
+ *     MiniportAdapterContext = Pointer to adapter context area
+ * NOTES:
+ *     Interrupt Service Register is read to determine which interrupts
+ *     are pending. All pending interrupts are handled
+ */
+{
+    UCHAR ISRValue;
+    UCHAR ISRMask;
+    UCHAR Mask;
+    PNIC_ADAPTER Adapter = (PNIC_ADAPTER)MiniportAdapterContext;
+
+    ISRMask = Adapter->InterruptMask;
+    NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &ISRValue);
+
+    NDIS_DbgPrint(MAX_TRACE, ("ISRValue (0x%X).\n", ISRValue));
+
+    Adapter->InterruptStatus = (ISRValue & ISRMask);
+
+    if (ISRValue != 0x00)
+        /* Acknowledge interrupts */
+        NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, ISRValue);
+
+    Mask = 0x01;
+    while (Adapter->InterruptStatus != 0x00) {
+
+        NDIS_DbgPrint(MAX_TRACE, ("Adapter->InterruptStatus (0x%X).\n", Adapter->InterruptStatus));
+
+        while (((Adapter->InterruptStatus & Mask) == 0) && (Mask < ISRMask))
+            Mask = (Mask << 1);
+
+        switch (Adapter->InterruptStatus & Mask) {
+        case ISR_OVW:
+            NDIS_DbgPrint(MAX_TRACE, ("Overflow interrupt.\n"));
+            /* Overflow. Handled almost the same way as a receive interrupt */
+            Adapter->BufferOverflow = TRUE;
+
+            HandleReceive(Adapter);
+
+            Adapter->InterruptStatus &= ~ISR_OVW;
+            break;
+
+        case ISR_RXE:
+            NDIS_DbgPrint(MAX_TRACE, ("Receive error interrupt.\n"));
+            NICUpdateCounters(Adapter);
+
+            Adapter->ReceiveError = TRUE;
+            
+        case ISR_PRX:
+            NDIS_DbgPrint(MAX_TRACE, ("Receive interrupt.\n"));
+
+            HandleReceive(Adapter);
+
+            Adapter->InterruptStatus &= ~(ISR_PRX | ISR_RXE);
+            break;
+
+        case ISR_TXE:
+            NDIS_DbgPrint(MAX_TRACE, ("Transmit error interrupt.\n"));
+            NICUpdateCounters(Adapter);
+
+            Adapter->TransmitError = TRUE;
+
+        case ISR_PTX:
+            NDIS_DbgPrint(MAX_TRACE, ("Transmit interrupt.\n"));
+
+            HandleTransmit(Adapter);
+
+            Adapter->InterruptStatus &= ~(ISR_PTX | ISR_TXE);
+            break;
+
+        case ISR_CNT:
+            NDIS_DbgPrint(MAX_TRACE, ("Counter interrupt.\n"));
+            /* Counter overflow. Read counters from the NIC */
+            NICUpdateCounters(Adapter);
+
+            Adapter->InterruptStatus &= ~ISR_CNT;
+            break;
+
+        default:
+            NDIS_DbgPrint(MAX_TRACE, ("Unknown interrupt. Adapter->InterruptStatus (0x%X).\n", Adapter->InterruptStatus));
+            Adapter->InterruptStatus &= ~Mask;
+            break;
+        }
+
+        Mask = (Mask << 1);
+
+        /* Check if new interrupts are generated */
+        NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &ISRValue);
+        Adapter->InterruptStatus |= (ISRValue & ISRMask);
+
+        if (ISRValue != 0x00) {
+            /* Acknowledge interrupts */
+            NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, ISRValue);
+            Mask = 0x01;
+        }
+    }
+
+    NICEnableInterrupts((PNIC_ADAPTER)MiniportAdapterContext);
+}
+
+/* EOF */
diff --git a/reactos/drivers/net/dd/ne2000/ne2000/MAKEFILE b/reactos/drivers/net/dd/ne2000/ne2000/MAKEFILE
new file mode 100644 (file)
index 0000000..6ee4f43
--- /dev/null
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source
+# file to this component.  This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/reactos/drivers/net/dd/ne2000/ne2000/RESOURCE.RC b/reactos/drivers/net/dd/ne2000/ne2000/RESOURCE.RC
new file mode 100644 (file)
index 0000000..cc44c94
--- /dev/null
@@ -0,0 +1,10 @@
+#include <windows.h>
+#include <ntverp.h>
+
+#define        VER_FILETYPE                VFT_DRV
+#define        VER_FILESUBTYPE             VFT2_DRV_NETWORK
+#define VER_FILEDESCRIPTION_STR     "Novell NE2000 network driver"
+#define VER_INTERNALNAME_STR        "NE2000.SYS"
+#define VER_ORIGINALFILENAME_STR    "NE2000.SYS"
+
+#include "common.ver"
diff --git a/reactos/drivers/net/dd/ne2000/ne2000/SOURCES b/reactos/drivers/net/dd/ne2000/ne2000/SOURCES
new file mode 100644 (file)
index 0000000..852122d
--- /dev/null
@@ -0,0 +1,15 @@
+TARGETNAME=ne2000
+TARGETPATH=..\objects
+TARGETTYPE=DRIVER
+
+TARGETLIBS=$(DDK_LIB_PATH)\ndis.lib
+
+C_DEFINES=$(C_DEFINES) -DNDIS_MINIPORT_DRIVER -DDBG
+
+INCLUDES=..\include;..\..\..\..\..\include\net;$(BASEDIR)\inc
+
+SOURCES=main.c   \
+        8390.c \
+        RESOURCE.RC
+
+MSC_WARNING_LEVEL=/W3 /WX
diff --git a/reactos/drivers/net/dd/ne2000/ne2000/main.c b/reactos/drivers/net/dd/ne2000/ne2000/main.c
new file mode 100644 (file)
index 0000000..7f673d7
--- /dev/null
@@ -0,0 +1,806 @@
+/*
+ * COPYRIGHT:   See COPYING in the top level directory
+ * PROJECT:     ReactOS Novell Eagle 2000 driver
+ * FILE:        ne2000/main.c
+ * PURPOSE:     Driver entry point
+ * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * REVISIONS:
+ *   CSH 27/08-2000 Created
+ */
+#include <ne2000.h>
+
+
+#ifdef DBG
+
+/* See debug.h for debug/trace constants */
+ULONG DebugTraceLevel = MIN_TRACE;
+
+#endif /* DBG */
+
+
+/* List of supported OIDs */
+static ULONG MiniportOIDList[] = {
+    OID_GEN_SUPPORTED_LIST,
+    OID_GEN_HARDWARE_STATUS,
+    OID_GEN_MEDIA_SUPPORTED,
+    OID_GEN_MEDIA_IN_USE,
+    OID_GEN_MAXIMUM_LOOKAHEAD,
+    OID_GEN_MAXIMUM_FRAME_SIZE,
+    OID_GEN_LINK_SPEED,
+    OID_GEN_TRANSMIT_BUFFER_SPACE,
+    OID_GEN_RECEIVE_BUFFER_SPACE,
+    OID_GEN_TRANSMIT_BLOCK_SIZE,
+    OID_GEN_RECEIVE_BLOCK_SIZE,
+    OID_GEN_VENDOR_ID,
+    OID_GEN_VENDOR_DESCRIPTION,
+    OID_GEN_VENDOR_DRIVER_VERSION,
+    OID_GEN_CURRENT_PACKET_FILTER,
+    OID_GEN_CURRENT_LOOKAHEAD,
+    OID_GEN_DRIVER_VERSION,
+    OID_GEN_MAXIMUM_TOTAL_SIZE,
+    OID_GEN_PROTOCOL_OPTIONS,
+    OID_GEN_MAC_OPTIONS,
+    OID_GEN_MEDIA_CONNECT_STATUS,
+    OID_GEN_MAXIMUM_SEND_PACKETS,
+    OID_802_3_PERMANENT_ADDRESS,
+    OID_802_3_CURRENT_ADDRESS,
+    OID_802_3_MULTICAST_LIST,
+    OID_802_3_MAXIMUM_LIST_SIZE,
+    OID_802_3_MAC_OPTIONS
+};
+
+DRIVER_INFORMATION      DriverInfo = {0};
+NDIS_PHYSICAL_ADDRESS   HighestAcceptableMax = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
+
+
+BOOLEAN MiniportCheckForHang(
+    IN  NDIS_HANDLE MiniportAdapterContext)
+/*
+ * FUNCTION: Examines if an adapter has hung
+ * ARGUMENTS:
+ *     MiniportAdapterContext = Pointer to adapter context area
+ * RETURNS:
+ *     TRUE if the adapter has hung, FALSE if not
+ */
+{
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    return FALSE;
+}
+
+
+VOID MiniportDisableInterrupt(
+    IN  NDIS_HANDLE MiniportAdapterContext)
+/*
+ * FUNCTION: Disables interrupts from an adapter
+ * ARGUMENTS:
+ *     MiniportAdapterContext = Pointer to adapter context area
+ */
+{
+    NDIS_DbgPrint(MAX_TRACE, ("Called. (MiniportDisableInterrupt).\n"));
+#ifndef NOCARD
+    NICDisableInterrupts((PNIC_ADAPTER)MiniportAdapterContext);
+#endif
+}
+
+
+VOID MiniportEnableInterrupt(
+    IN  NDIS_HANDLE MiniportAdapterContext)
+/*
+ * FUNCTION: Enables interrupts from an adapter
+ * ARGUMENTS:
+ *     MiniportAdapterContext = Pointer to adapter context area
+ */
+{
+    NDIS_DbgPrint(MAX_TRACE, ("Called. (MiniportEnableInterrupt).\n"));
+#ifndef NOCARD
+    NICEnableInterrupts((PNIC_ADAPTER)MiniportAdapterContext);
+#endif
+}
+
+
+VOID MiniportHalt(
+    IN  NDIS_HANDLE MiniportAdapterContext)
+/*
+ * FUNCTION: Deallocates resources for and halts an adapter
+ * ARGUMENTS:
+ *     MiniportAdapterContext = Pointer to adapter context area
+ */
+{
+    PNIC_ADAPTER Adapter = (PNIC_ADAPTER)MiniportAdapterContext;
+
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+#ifndef NOCARD
+    /* Stop the NIC */
+    NICStop(Adapter);
+#endif
+    /* Wait for any DPCs to complete. FIXME: Use something else */
+    NdisStallExecution(250000);
+
+    if (Adapter->InterruptRegistered)
+        /* Deregister interrupt */
+        NdisMDeregisterInterrupt(&Adapter->Interrupt);
+
+    if (Adapter->IOPortRangeRegistered)
+        /* Deregister I/O port range */
+        NdisMDeregisterIoPortRange(
+            Adapter->MiniportAdapterHandle,
+            Adapter->IoBaseAddress,
+            0x20,
+            Adapter->IOBase);
+
+    /* Remove adapter from global adapter list */
+    RemoveEntryList(&Adapter->ListEntry);
+
+    /* Free adapter context area */
+    NdisFreeMemory(Adapter, sizeof(NIC_ADAPTER), 0);
+}
+
+
+NDIS_STATUS MiniportInitialize(
+    OUT PNDIS_STATUS    OpenErrorStatus,
+    OUT PUINT           SelectedMediumIndex,
+    IN  PNDIS_MEDIUM    MediumArray,
+    IN  UINT            MediumArraySize,
+    IN  NDIS_HANDLE     MiniportAdapterHandle,
+    IN  NDIS_HANDLE     WrapperConfigurationContext)
+/*
+ * FUNCTION: Adapter initialization function
+ * ARGUMENTS:
+ *     OpenErrorStatus             = Address of buffer to place additional status information
+ *     SelectedMediumIndex         = Address of buffer to place selected medium index
+ *     MediumArray                 = Pointer to an array of NDIS_MEDIUMs
+ *     MediaArraySize              = Number of elements in MediumArray
+ *     MiniportAdapterHandle       = Miniport adapter handle assigned by NDIS
+ *     WrapperConfigurationContext = Handle used to identify configuration context
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    UINT i;
+    NDIS_STATUS Status;
+    PNIC_ADAPTER Adapter;
+
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    /* Search for 802.3 media which is the only one we support */
+    for (i = 0; i < MediumArraySize; i++) {
+        if (MediumArray[i] == NdisMedium802_3)
+            break;
+    }
+
+    if (i == MediumArraySize) {
+        NDIS_DbgPrint(MIN_TRACE, ("No supported medias.\n"));
+        return NDIS_STATUS_UNSUPPORTED_MEDIA;
+    }
+
+    *SelectedMediumIndex = i;
+
+    Status = NdisAllocateMemory((PVOID)&Adapter,
+                                sizeof(NIC_ADAPTER),
+                                0,
+                                HighestAcceptableMax);
+    if (Status != NDIS_STATUS_SUCCESS) {
+        NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
+        return Status;
+    }
+
+    NdisZeroMemory(Adapter, sizeof(NIC_ADAPTER));
+    Adapter->MiniportAdapterHandle  = MiniportAdapterHandle;
+    Adapter->IoBaseAddress          = DRIVER_DEFAULT_IO_BASE_ADDRESS;
+    Adapter->InterruptNumber        = DRIVER_DEFAULT_INTERRUPT_NUMBER;
+    Adapter->MaxMulticastListSize   = DRIVER_MAX_MULTICAST_LIST_SIZE;
+    Adapter->InterruptMask          = DRIVER_INTERRUPT_MASK;
+    Adapter->LookaheadSize          = DRIVER_MAXIMUM_LOOKAHEAD;
+
+    NdisMSetAttributes(
+        MiniportAdapterHandle,
+        (NDIS_HANDLE)Adapter,
+        FALSE,
+        NdisInterfaceIsa);
+
+    Status = NdisMRegisterIoPortRange(
+        (PVOID*)&Adapter->IOBase,
+        MiniportAdapterHandle,
+        Adapter->IoBaseAddress,
+        0x20);
+
+    if (Status != NDIS_STATUS_SUCCESS) {
+        NDIS_DbgPrint(MIN_TRACE, ("Cannot register port range. Status (0x%X).\n", Status));
+        MiniportHalt((NDIS_HANDLE)Adapter);
+        return Status;
+    }
+
+    Adapter->IOPortRangeRegistered = TRUE;
+
+    /* Initialize NIC */
+#ifndef NOCARD
+    Status = NICInitialize(Adapter);
+    if (Status != NDIS_STATUS_SUCCESS) {
+        NDIS_DbgPrint(MIN_TRACE, ("Cannot find NE2000 NIC. Status (0x%X).\n", Status));
+        MiniportHalt((NDIS_HANDLE)Adapter);
+        return Status;
+    }
+
+    NDIS_DbgPrint(MAX_TRACE, ("BOARDDATA:\n"));
+    for (i = 0; i < 4; i++) {
+        NDIS_DbgPrint(MAX_TRACE, ("%02X %02X %02X %02X\n",
+            Adapter->SAPROM[i*4+0],
+            Adapter->SAPROM[i*4+1],
+            Adapter->SAPROM[i*4+2],
+            Adapter->SAPROM[i*4+3]));
+    }
+
+    /* Setup adapter structure */
+    Adapter->TXStart   = ((ULONG_PTR)Adapter->RamBase >> 8);
+    Adapter->TXCount   = DRIVER_DEFAULT_TX_BUFFER_COUNT;
+    Adapter->TXFree    = DRIVER_DEFAULT_TX_BUFFER_COUNT;
+    Adapter->TXCurrent = -1;
+    Adapter->PageStart = Adapter->TXStart + Adapter->TXCount;
+    Adapter->PageStop  = Adapter->TXStart + (Adapter->RamSize >> 8);
+
+    /* Initialize multicast address mask to accept all */
+    for (i = 0; i < 8; i++)
+        Adapter->MulticastAddressMask[i] = 0xFF;
+
+    /* Setup the NIC */
+    NICSetup(Adapter);
+
+    NDIS_DbgPrint(MIN_TRACE, ("TXStart (0x%X)  TXCount (0x%X)  PageStart (0x%X)\n",
+        Adapter->TXStart,
+        Adapter->TXCount,
+        Adapter->PageStart));
+
+    NDIS_DbgPrint(MIN_TRACE, ("PageStop (0x%X)  CurrentPage (0x%X)  NextPacket (0x%X).\n",
+        Adapter->PageStop,
+        Adapter->CurrentPage,
+        Adapter->NextPacket));
+#endif
+    /* Register the interrupt */
+    Status = NdisMRegisterInterrupt(
+        &Adapter->Interrupt,
+        MiniportAdapterHandle,
+        Adapter->InterruptNumber,
+        Adapter->InterruptNumber,
+        FALSE,
+        FALSE,
+        NdisInterruptLatched);
+    if (Status != NDIS_STATUS_SUCCESS) {
+        NDIS_DbgPrint(MIN_TRACE, ("Cannot register interrupt. Status (0x%X).\n", Status));
+        MiniportHalt((NDIS_HANDLE)Adapter);
+        return Status;
+    }
+
+    Adapter->InterruptRegistered = TRUE;
+#ifndef NOCARD
+    /* Start the NIC */
+    NICStart(Adapter);
+#endif
+    /* Add adapter to the global adapter list */
+    InsertTailList(&DriverInfo.AdapterListHead, &Adapter->ListEntry);
+
+    NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n"));
+
+    return NDIS_STATUS_SUCCESS;
+}
+
+
+VOID MiniportISR(
+    OUT PBOOLEAN    InterruptRecognized,
+    OUT PBOOLEAN    QueueMiniportHandleInterrupt,
+    IN  NDIS_HANDLE MiniportAdapterContext)
+/*
+ * FUNCTION: Interrupt Service Routine for controlled adapters
+ * ARGUMENTS:
+ *     InterruptRecognized          = Address of buffer to place wether
+ *                                    the adapter generated the interrupt
+ *     QueueMiniportHandleInterrupt = Address of buffer to place wether
+ *                                    MiniportHandleInterrupt should be called
+ *     MiniportAdapterContext       = Pointer to adapter context area
+ * NOTES:
+ *     All pending interrupts are handled
+ */
+{
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    NICDisableInterrupts((PNIC_ADAPTER)MiniportAdapterContext);
+
+    *InterruptRecognized          = TRUE;
+    *QueueMiniportHandleInterrupt = TRUE;
+}
+
+
+NDIS_STATUS MiniportQueryInformation(
+    IN  NDIS_HANDLE MiniportAdapterContext,
+    IN  NDIS_OID    Oid,
+    IN  PVOID       InformationBuffer,
+    IN  ULONG       InformationBufferLength,
+    OUT PULONG      BytesWritten,
+    OUT PULONG      BytesNeeded)
+/*
+ * FUNCTION: Handler to process queries
+ * ARGUMENTS:
+ *     MiniportAdapterContext  = Pointer to adapter context area
+ *     Oid                     = OID code designating query operation
+ *     InformationBuffer       = Address of return buffer
+ *     InformationBufferLength = Length of return buffer
+ *     BytesWritten            = Address of buffer to place number of bytes returned
+ *     BytesNeeded             = Address of buffer to place number of bytes needed
+ *                               in InformationBuffer for specified OID
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    NDIS_STATUS Status;
+    PVOID CopyFrom;
+    UINT CopySize;
+    ULONG GenericULONG;
+    USHORT GenericUSHORT;
+    NDIS_MEDIUM Medium   = NdisMedium802_3;
+    PNIC_ADAPTER Adapter = (PNIC_ADAPTER)MiniportAdapterContext;
+
+    NDIS_DbgPrint(MAX_TRACE, ("Called. Oid (0x%X).\n", Oid));
+
+    Status   = NDIS_STATUS_SUCCESS;
+    CopyFrom = (PVOID)&GenericULONG;
+    CopySize = sizeof(ULONG);
+
+    switch (Oid) {
+    case OID_GEN_SUPPORTED_LIST:
+        CopyFrom = (PVOID)&MiniportOIDList;
+        CopySize = sizeof(MiniportOIDList);
+        break;
+    case OID_GEN_HARDWARE_STATUS:
+        GenericULONG = (ULONG)NdisHardwareStatusReady;
+        break;
+    case OID_GEN_MEDIA_SUPPORTED:
+    case OID_GEN_MEDIA_IN_USE:
+        CopyFrom = (PVOID)&Medium;
+        CopySize = sizeof(NDIS_MEDIUM);
+        break;
+    case OID_GEN_MAXIMUM_LOOKAHEAD:
+        GenericULONG = DRIVER_MAXIMUM_LOOKAHEAD;
+        break;
+    case OID_GEN_MAXIMUM_FRAME_SIZE:
+        GenericULONG = DRIVER_FRAME_SIZE - DRIVER_HEADER_SIZE;
+        break;
+    case OID_GEN_LINK_SPEED:
+        GenericULONG = 100000;  /* 10Mbps */
+        break;
+    case OID_GEN_TRANSMIT_BUFFER_SPACE:
+        GenericULONG = Adapter->TXCount * DRIVER_BLOCK_SIZE;
+        break;
+    case OID_GEN_RECEIVE_BUFFER_SPACE:
+        GenericULONG = Adapter->RamSize -
+                       (ULONG_PTR)Adapter->RamBase -
+                       (Adapter->TXCount * DRIVER_BLOCK_SIZE);
+        break;
+    case OID_GEN_TRANSMIT_BLOCK_SIZE:
+        GenericULONG = DRIVER_BLOCK_SIZE;
+        break;
+    case OID_GEN_RECEIVE_BLOCK_SIZE:
+        GenericULONG = DRIVER_BLOCK_SIZE;
+        break;
+    case OID_GEN_VENDOR_ID:
+        NdisMoveMemory(&GenericULONG, &Adapter->PermanentAddress, 3);
+        GenericULONG &= 0xFFFFFF00;
+        GenericULONG |= 0x01;
+        break;
+    case OID_GEN_VENDOR_DESCRIPTION:
+        CopyFrom = (PVOID)&DRIVER_VENDOR_DESCRIPTION;
+        CopySize = sizeof(DRIVER_VENDOR_DESCRIPTION);
+        break;
+    case OID_GEN_VENDOR_DRIVER_VERSION:
+        GenericUSHORT = (USHORT)DRIVER_VENDOR_DRIVER_VERSION;
+        CopyFrom      = (PVOID)&GenericUSHORT;
+        CopySize      = sizeof(USHORT);
+        break;
+    case OID_GEN_CURRENT_PACKET_FILTER:
+        GenericULONG = Adapter->PacketFilter;
+        break;
+    case OID_GEN_CURRENT_LOOKAHEAD:
+        GenericULONG = Adapter->LookaheadSize;
+        break;
+    case OID_GEN_DRIVER_VERSION:
+        GenericUSHORT = ((USHORT)DRIVER_NDIS_MAJOR_VERSION << 8) | DRIVER_NDIS_MINOR_VERSION;
+        CopyFrom      = (PVOID)&GenericUSHORT;
+        CopySize      = sizeof(USHORT);
+        break;
+    case OID_GEN_MAXIMUM_TOTAL_SIZE:
+        GenericULONG = DRIVER_FRAME_SIZE;
+        break;
+    case OID_GEN_PROTOCOL_OPTIONS:
+        NDIS_DbgPrint(MAX_TRACE, ("OID_GEN_PROTOCOL_OPTIONS.\n"));
+        Status = NDIS_STATUS_NOT_SUPPORTED;
+        break;
+    case OID_GEN_MAC_OPTIONS:
+        GenericULONG = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
+                       NDIS_MAC_OPTION_RECEIVE_SERIALIZED  |           
+                       NDIS_MAC_OPTION_TRANSFERS_NOT_PEND  |
+                       NDIS_MAC_OPTION_NO_LOOPBACK;
+        break;
+    case OID_GEN_MEDIA_CONNECT_STATUS:
+        GenericULONG = (ULONG)NdisMediaStateConnected;
+        break;
+    case OID_GEN_MAXIMUM_SEND_PACKETS:
+        GenericULONG = 1;
+        break;
+    case OID_802_3_PERMANENT_ADDRESS:
+        CopyFrom = (PVOID)&Adapter->PermanentAddress;
+        CopySize = DRIVER_LENGTH_OF_ADDRESS;
+        break;
+    case OID_802_3_CURRENT_ADDRESS:
+        CopyFrom = (PVOID)&Adapter->StationAddress;
+        CopySize = DRIVER_LENGTH_OF_ADDRESS;
+        break;
+    case OID_802_3_MULTICAST_LIST:
+        NDIS_DbgPrint(MAX_TRACE, ("OID_802_3_MULTICAST_LIST.\n"));
+        Status = NDIS_STATUS_NOT_SUPPORTED;
+        break;
+    case OID_802_3_MAXIMUM_LIST_SIZE:
+        GenericULONG = Adapter->MaxMulticastListSize;
+        break;
+    case OID_802_3_MAC_OPTIONS:
+        NDIS_DbgPrint(MAX_TRACE, ("OID_802_3_MAC_OPTIONS.\n"));
+        Status = NDIS_STATUS_NOT_SUPPORTED;
+        break;
+    default:
+        NDIS_DbgPrint(MIN_TRACE, ("Unknown OID (0x%X).\n", Oid));
+        Status = NDIS_STATUS_INVALID_OID;
+        break;
+    }
+
+    if (Status == NDIS_STATUS_SUCCESS) {
+        if (CopySize > InformationBufferLength) {
+            *BytesNeeded  = (CopySize - InformationBufferLength);
+            *BytesWritten = 0;
+            Status        = NDIS_STATUS_INVALID_LENGTH;
+        } else {
+            NdisMoveMemory(InformationBuffer, CopyFrom, CopySize);
+            *BytesWritten = CopySize;
+            *BytesNeeded  = 0;
+         }
+    }
+
+    NDIS_DbgPrint(MAX_TRACE, ("Leaving. Status is (0x%X).\n", Status));
+
+    return Status;
+}
+
+
+NDIS_STATUS MiniportReconfigure(
+    OUT PNDIS_STATUS    OpenErrorStatus,
+    IN  NDIS_HANDLE     MiniportAdapterContext,
+    IN  NDIS_HANDLE     WrapperConfigurationContext)
+/*
+ * FUNCTION: Reconfigures an adapter
+ * ARGUMENTS:
+ *     OpenErrorStatus             = Address of buffer to place additional status information
+ *     MiniportAdapterContext      = Pointer to adapter context area
+ *     WrapperConfigurationContext = Handle used to identify configuration context
+ * RETURNS:
+ *     Status of operation
+ * NOTES:
+ *     Never called by NDIS library
+ */
+{
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    return NDIS_STATUS_FAILURE;
+}
+
+
+
+NDIS_STATUS MiniportReset(
+    OUT PBOOLEAN    AddressingReset,
+    IN  NDIS_HANDLE MiniportAdapterContext)
+/*
+ * FUNCTION: Resets an adapter
+ * ARGUMENTS:
+ *     AddressingReset        = Address of a buffer to place value indicating
+ *                              wether NDIS library should call MiniportSetInformation
+ *                              to restore addressing information
+ *     MiniportAdapterContext = Pointer to adapter context area
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    return NDIS_STATUS_FAILURE;
+}
+
+
+NDIS_STATUS MiniportSend(
+    IN  NDIS_HANDLE     MiniportAdapterContext,
+    IN  PNDIS_PACKET    Packet,
+    IN  UINT            Flags)
+/*
+ * FUNCTION: Transmits a packet
+ * ARGUMENTS:
+ *     MiniportAdapterContext = Pointer to adapter context area
+ *     Packet                 = Pointer to a packet descriptor specifying
+ *                              the data to be transmitted
+ *     Flags                  = Specifies optional packet flags
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PNIC_ADAPTER Adapter = (PNIC_ADAPTER)MiniportAdapterContext;
+
+    NDIS_DbgPrint(MAX_TRACE, ("Queueing packet.\n"));
+
+#ifdef NOCARD
+    NdisMSendComplete(Adapter->MiniportAdapterHandle,
+                      Packet,
+                      NDIS_STATUS_SUCCESS);
+#else
+    /* Queue the packet on the transmit queue */
+    RESERVED(Packet)->Next = NULL;
+    if (Adapter->TXQueueHead == NULL) {
+        Adapter->TXQueueHead = Packet;
+    } else {
+        RESERVED(Adapter->TXQueueTail)->Next = Packet;
+    }
+
+    Adapter->TXQueueTail = Packet;
+
+    /* Transmit the packet */
+    NICTransmit(Adapter);
+#endif
+    return NDIS_STATUS_PENDING;
+}
+
+
+NDIS_STATUS MiniportSetInformation(
+    IN  NDIS_HANDLE MiniportAdapterContext,
+    IN  NDIS_OID    Oid,
+    IN  PVOID       InformationBuffer,
+    IN  ULONG       InformationBufferLength,
+    OUT PULONG      BytesRead,
+    OUT PULONG      BytesNeeded)
+/*
+ * FUNCTION: Changes state information in the driver
+ * ARGUMENTS:
+ *     MiniportAdapterContext  = Pointer to adapter context area
+ *     Oid                     = OID code designating set operation
+ *     InformationBuffer       = Pointer to buffer with state information
+ *     InformationBufferLength = Length of InformationBuffer
+ *     BytesRead               = Address of buffer to place number of bytes read
+ *     BytesNeeded             = Address of buffer to place number of extra bytes
+ *                               needed in InformationBuffer for specified OID
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    ULONG GenericULONG;
+    NDIS_STATUS Status   = NDIS_STATUS_SUCCESS;
+    PNIC_ADAPTER Adapter = (PNIC_ADAPTER)MiniportAdapterContext;
+
+    NDIS_DbgPrint(MAX_TRACE, ("Called. Oid (0x%X).\n", Oid));
+
+    switch (Oid) {
+    case OID_GEN_CURRENT_PACKET_FILTER:
+        /* Verify length */
+        if (InformationBufferLength < sizeof(ULONG)) {
+            *BytesRead   = 0;
+            *BytesNeeded = sizeof(ULONG) - InformationBufferLength;
+            Status       = NDIS_STATUS_INVALID_LENGTH;
+            break;
+        }
+
+        NdisMoveMemory(&GenericULONG, InformationBuffer, sizeof(ULONG));
+        /* Check for properties the driver don't support */
+        if (GenericULONG &
+           (NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
+            NDIS_PACKET_TYPE_FUNCTIONAL     |
+            NDIS_PACKET_TYPE_GROUP          |
+            NDIS_PACKET_TYPE_MAC_FRAME      |
+            NDIS_PACKET_TYPE_SMT            |
+            NDIS_PACKET_TYPE_SOURCE_ROUTING)) {
+            *BytesRead   = 4;
+            *BytesNeeded = 0;
+            Status       = NDIS_STATUS_NOT_SUPPORTED;
+            break;
+        }
+            
+        Adapter->PacketFilter = GenericULONG;
+
+        /* FIXME: Set filter on hardware */
+
+        break;
+    case OID_GEN_CURRENT_LOOKAHEAD:
+        /* Verify length */
+        if (InformationBufferLength < sizeof(ULONG)) {
+            *BytesRead   = 0;
+            *BytesNeeded = sizeof(ULONG) - InformationBufferLength;
+            Status = NDIS_STATUS_INVALID_LENGTH;
+            break;
+        }
+
+        NdisMoveMemory(&GenericULONG, InformationBuffer, sizeof(ULONG));
+        if (GenericULONG > DRIVER_MAXIMUM_LOOKAHEAD)
+            Status = NDIS_STATUS_INVALID_LENGTH;
+        else
+            Adapter->LookaheadSize = GenericULONG;
+        break;
+    case OID_802_3_MULTICAST_LIST:
+        /* Verify length. Must be multiplum of hardware address length */
+        if ((InformationBufferLength % DRIVER_LENGTH_OF_ADDRESS) != 0) {
+            *BytesRead   = 0;
+            *BytesNeeded = 0;
+            Status       = NDIS_STATUS_INVALID_LENGTH;
+            break;
+        }
+
+        /* Set new multicast address list */
+        NdisMoveMemory(Adapter->Addresses, InformationBuffer, InformationBufferLength);
+
+        /* FIXME: Update hardware */
+
+        break;
+    default:
+        NDIS_DbgPrint(MIN_TRACE, ("Invalid object ID (0x%X).\n", Oid));
+        *BytesRead   = 0;
+        *BytesNeeded = 0;
+        Status       = NDIS_STATUS_INVALID_OID;
+        break;
+    }
+
+    if (Status == NDIS_STATUS_SUCCESS) {
+        *BytesRead   = InformationBufferLength;
+        *BytesNeeded = 0;
+    }
+
+    NDIS_DbgPrint(MAX_TRACE, ("Leaving. Status (0x%X).\n", Status));
+
+    return Status;
+}
+
+
+NDIS_STATUS MiniportTransferData(
+    OUT PNDIS_PACKET    Packet,
+    OUT PUINT           BytesTransferred,
+    IN  NDIS_HANDLE     MiniportAdapterContext,
+    IN  NDIS_HANDLE     MiniportReceiveContext,
+    IN  UINT            ByteOffset,
+    IN  UINT            BytesToTransfer)
+/*
+ * FUNCTION: Transfers data from a received frame into an NDIS packet
+ * ARGUMENTS:
+ *     Packet                 = Address of packet to copy received data into
+ *     BytesTransferred       = Address of buffer to place number of bytes transmitted
+ *     MiniportAdapterContext = Pointer to adapter context area
+ *     MiniportReceiveContext = Pointer to receive context area (actually NULL)
+ *     ByteOffset             = Offset within received packet to begin copying
+ *     BytesToTransfer        = Number of bytes to copy into packet
+ * RETURNS:
+ *     Status of operation
+ */
+{
+    PNDIS_BUFFER DstBuffer;
+    UINT BytesCopied, BytesToCopy, DstSize;
+    ULONG SrcData;
+    PUCHAR DstData;
+    UINT RecvStart;
+    UINT RecvStop;
+    PNIC_ADAPTER Adapter = (PNIC_ADAPTER)MiniportAdapterContext;
+
+    NDIS_DbgPrint(MAX_TRACE, ("Called. Packet (0x%X)  ByteOffset (0x%X)  BytesToTransfer (%d).\n",
+        Packet, ByteOffset, BytesToTransfer));
+
+    if (BytesToTransfer == 0) {
+        *BytesTransferred = 0;
+        return NDIS_STATUS_SUCCESS;
+    }
+
+    RecvStart = Adapter->PageStart * DRIVER_BLOCK_SIZE;
+    RecvStop  = Adapter->PageStop  * DRIVER_BLOCK_SIZE;
+
+    NdisQueryPacket(Packet, NULL, NULL, &DstBuffer, NULL);
+    NdisQueryBuffer(DstBuffer, (PVOID)&DstData, &DstSize);
+
+    SrcData = Adapter->PacketOffset + sizeof(PACKET_HEADER) + ByteOffset;
+    if (ByteOffset + sizeof(PACKET_HEADER) + BytesToTransfer > Adapter->PacketHeader.PacketLength)
+        BytesToTransfer = Adapter->PacketHeader.PacketLength- sizeof(PACKET_HEADER) - ByteOffset;
+
+    /* Start copying the data */
+    BytesCopied = 0;
+    for (;;) {
+        BytesToCopy = (DstSize < BytesToTransfer)? DstSize : BytesToTransfer;
+        if (SrcData + BytesToCopy > RecvStop)
+            BytesToCopy = (RecvStop - SrcData);
+
+        NICReadData(Adapter, DstData, SrcData, BytesToCopy);
+
+        BytesCopied        += BytesToCopy;
+        SrcData            += BytesToCopy;
+        (ULONG_PTR)DstData += BytesToCopy;
+        BytesToTransfer    -= BytesToCopy;
+        if (BytesToTransfer == 0)
+            break;
+
+        DstSize -= BytesToCopy;
+        if (DstSize == 0) {
+            /* No more bytes in destination buffer. Proceed to
+               the next buffer in the destination buffer chain */
+            NdisGetNextBuffer(DstBuffer, &DstBuffer);
+            if (!DstBuffer)
+                break;
+
+            NdisQueryBuffer(DstBuffer, (PVOID)&DstData, &DstSize);
+        }
+
+        if (SrcData == RecvStop)
+            SrcData = RecvStart;
+    }
+
+    NDIS_DbgPrint(MAX_TRACE, ("Transferred (%d) bytes.\n", BytesToTransfer));
+
+    *BytesTransferred = BytesCopied;
+
+    return NDIS_STATUS_SUCCESS;
+}
+
+
+NTSTATUS
+#ifndef _MSC_VER
+STDCALL
+#endif
+DriverEntry(
+    PDRIVER_OBJECT DriverObject,
+    PUNICODE_STRING RegistryPath)
+/*
+ * FUNCTION: Main driver entry point
+ * ARGUMENTS:
+ *     DriverObject = Pointer to a driver object for this driver
+ *     RegistryPath = Registry node for configuration parameters
+ * RETURNS:
+ *     Status of driver initialization
+ */
+{
+    NDIS_STATUS Status;
+    NDIS_HANDLE NdisWrapperHandle;
+    NDIS_MINIPORT_CHARACTERISTICS Miniport;
+
+    NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
+
+    NdisZeroMemory(&Miniport, sizeof(Miniport));
+    Miniport.MajorNdisVersion           = DRIVER_NDIS_MAJOR_VERSION;
+    Miniport.MinorNdisVersion           = DRIVER_NDIS_MINOR_VERSION;
+    Miniport.CheckForHangHandler        = NULL; //MiniportCheckForHang;
+    Miniport.DisableInterruptHandler    = MiniportDisableInterrupt;
+    Miniport.EnableInterruptHandler     = MiniportEnableInterrupt;
+    Miniport.HaltHandler                = MiniportHalt;
+    Miniport.HandleInterruptHandler     = MiniportHandleInterrupt;
+    Miniport.InitializeHandler          = MiniportInitialize;
+    Miniport.ISRHandler                 = MiniportISR;
+    Miniport.QueryInformationHandler    = MiniportQueryInformation;
+    Miniport.ReconfigureHandler         = MiniportReconfigure;
+    Miniport.ResetHandler               = MiniportReset;
+    Miniport.u1.SendHandler             = MiniportSend;
+    Miniport.SetInformationHandler      = MiniportSetInformation;
+    Miniport.u2.TransferDataHandler     = MiniportTransferData;
+
+    NdisMInitializeWrapper(&NdisWrapperHandle,
+                           DriverObject,
+                           RegistryPath,
+                           NULL);
+
+    DriverInfo.NdisWrapperHandle = NdisWrapperHandle;
+    DriverInfo.NdisMacHandle     = NULL;
+    InitializeListHead(&DriverInfo.AdapterListHead);
+
+    Status = NdisMRegisterMiniport(NdisWrapperHandle,
+                                   &Miniport,
+                                   sizeof(NDIS_MINIPORT_CHARACTERISTICS));
+    if (Status != NDIS_STATUS_SUCCESS) {
+        NDIS_DbgPrint(MIN_TRACE, ("NdisMRegisterMiniport() failed with status code (0x%X).\n", Status));
+        NdisTerminateWrapper(NdisWrapperHandle, NULL);
+        return STATUS_UNSUCCESSFUL;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+/* EOF */
diff --git a/reactos/drivers/net/dd/ne2000/readme.txt b/reactos/drivers/net/dd/ne2000/readme.txt
new file mode 100644 (file)
index 0000000..368289c
--- /dev/null
@@ -0,0 +1,18 @@
+Build instructions for NE2000 driver
+------------------------------------
+
+Building with Visual C++ and Windows NT DDK:
+
+Variables:
+%BASEDIR%     = path to NT4 DDK (e.g. c:\ntddk)
+%DDKBUILDENV% = DDK build environment (free or checked)
+
+DDK environment variables must be set! (run setenv.bat)
+
+    - Create the directory objects/i386/%DDKBUILDENV%
+    - Run "build" to build the driver
+
+
+Building with Mingw32 and ReactOS include files:
+
+    - Run "make ne2000" FROM THE ReactOS ROOT DIRECTORY to build the driver