[RTL8139]

- Add an RTL8139 driver based on documentation on OSDev, our existing drivers, and some prior work by Z98
- It should fully work on emulated and real RTL8139 hardware (I developed against QEMU's RTL8139)
- It's not 100% complete (some reset and halt paths aren't done) but everything I tested worked (ping, dwnl, rapps, Firefox)

svn path=/trunk/; revision=59427
This commit is contained in:
Cameron Gutman 2013-07-05 04:18:32 +00:00
parent 3fb662667c
commit 50c8f14805
13 changed files with 1646 additions and 276 deletions

View file

@ -1,3 +1,4 @@
add_subdirectory(ne2000)
add_subdirectory(pcnet)
add_subdirectory(rtl8139)

View file

@ -0,0 +1,18 @@
add_definitions(
-DNDIS50_MINIPORT
-DNDIS_MINIPORT_DRIVER
-DNDIS_LEGACY_MINIPORT)
list(APPEND SOURCE
ndis.c
hardware.c
info.c
interrupt.c
rtl8139.rc)
add_library(rtl8139 SHARED ${SOURCE})
add_pch(rtl8139 pcnet.h)
set_module_type(rtl8139 kernelmodedriver)
add_importlibs(rtl8139 ndis ntoskrnl hal)
add_cd_file(TARGET rtl8139 DESTINATION reactos/system32/drivers FOR all)

View file

@ -0,0 +1,235 @@
/*
* ReactOS Realtek 8139 Driver
*
* Copyright (C) 2013 Cameron Gutman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "nic.h"
#define NDEBUG
#include <debug.h>
NDIS_STATUS
NTAPI
NICPowerOn (
IN PRTL_ADAPTER Adapter
)
{
//
// Send 0x00 to the CONFIG_1 register (0x52) to set the LWAKE + LWPTN to active high.
// This should essentially *power on* the device.
// -- OSDev Wiki
//
NdisRawWritePortUchar(Adapter->IoBase + R_CFG1, 0x00);
return NDIS_STATUS_SUCCESS;
}
NDIS_STATUS
NTAPI
NICSoftReset (
IN PRTL_ADAPTER Adapter
)
{
UCHAR commandReg;
UINT resetAttempts;
//
// Sending 0x10 to the Command register (0x37) will send the RTL8139 into a software reset.
// Once that byte is sent, the RST bit must be checked to make sure that the chip has finished the reset.
// If the RST bit is high (1), then the reset is still in operation.
// -- OSDev Wiki
NdisRawWritePortUchar(Adapter->IoBase + R_CMD, B_CMD_RST);
for (resetAttempts = 0; resetAttempts < MAX_RESET_ATTEMPTS; resetAttempts++)
{
NdisRawReadPortUchar(Adapter->IoBase + R_CMD, &commandReg);
if (!(commandReg & B_CMD_RST))
{
return NDIS_STATUS_SUCCESS;
}
NdisMSleep(100);
}
return NDIS_STATUS_FAILURE;
}
NDIS_STATUS
NTAPI
NICRegisterReceiveBuffer (
IN PRTL_ADAPTER Adapter
)
{
ASSERT(NdisGetPhysicalAddressHigh(Adapter->ReceiveBufferPa) == 0);
NdisRawWritePortUlong(Adapter->IoBase + R_RXSA, Adapter->ReceiveBufferPa.LowPart);
return NDIS_STATUS_SUCCESS;
}
NDIS_STATUS
NTAPI
NICRemoveReceiveBuffer (
IN PRTL_ADAPTER Adapter
)
{
NdisRawWritePortUlong(Adapter->IoBase + R_RXSA, 0);
return NDIS_STATUS_SUCCESS;
}
NDIS_STATUS
NTAPI
NICEnableTxRx (
IN PRTL_ADAPTER Adapter
)
{
NdisRawWritePortUchar(Adapter->IoBase + R_CMD, B_CMD_TXE | B_CMD_RXE);
//
// TX and RX must be enabled before setting these
//
NdisRawWritePortUlong(Adapter->IoBase + R_RC, RC_VAL);
NdisRawWritePortUlong(Adapter->IoBase + R_TC, TC_VAL);
return NDIS_STATUS_SUCCESS;
}
NDIS_STATUS
NTAPI
NICGetPermanentMacAddress (
IN PRTL_ADAPTER Adapter,
OUT PUCHAR MacAddress
)
{
UINT i;
for (i = 0; i < IEEE_802_ADDR_LENGTH; i++)
{
NdisRawReadPortUchar(Adapter->IoBase + R_MAC + i, &MacAddress[i]);
}
return NDIS_STATUS_SUCCESS;
}
NDIS_STATUS
NTAPI
NICApplyInterruptMask (
IN PRTL_ADAPTER Adapter
)
{
NdisRawWritePortUshort(Adapter->IoBase + R_IM, Adapter->InterruptMask);
return NDIS_STATUS_SUCCESS;
}
NDIS_STATUS
NTAPI
NICDisableInterrupts (
IN PRTL_ADAPTER Adapter
)
{
NdisRawWritePortUshort(Adapter->IoBase + R_IM, 0);
return NDIS_STATUS_SUCCESS;
}
USHORT
NTAPI
NICInterruptRecognized (
IN PRTL_ADAPTER Adapter,
OUT PBOOLEAN InterruptRecognized
)
{
USHORT interruptStatus;
NdisRawReadPortUshort(Adapter->IoBase + R_IS, &interruptStatus);
*InterruptRecognized = (interruptStatus & Adapter->InterruptMask) != 0;
return (interruptStatus & Adapter->InterruptMask);
}
VOID
NTAPI
NICAcknowledgeInterrupts (
IN PRTL_ADAPTER Adapter
)
{
NdisRawWritePortUshort(Adapter->IoBase + R_IS, Adapter->InterruptPending);
}
VOID
NTAPI
NICUpdateLinkStatus (
IN PRTL_ADAPTER Adapter
)
{
UCHAR mediaState;
NdisRawReadPortUchar(Adapter->IoBase + R_MS, &mediaState);
Adapter->MediaState = (mediaState & R_MS_LINKDWN) ? NdisMediaStateDisconnected :
NdisMediaStateConnected;
Adapter->LinkSpeedMbps = (mediaState & R_MS_SPEED_10) ? 10 : 100;
}
NDIS_STATUS
NTAPI
NICApplyPacketFilter (
IN PRTL_ADAPTER Adapter
)
{
ULONG filterMask;
filterMask = RC_VAL;
if (Adapter->PacketFilter & NDIS_PACKET_TYPE_DIRECTED)
{
filterMask |= B_RC_APM;
}
if (Adapter->PacketFilter & NDIS_PACKET_TYPE_MULTICAST)
{
filterMask |= B_RC_AM;
}
if (Adapter->PacketFilter & NDIS_PACKET_TYPE_BROADCAST)
{
filterMask |= B_RC_AB;
}
if (Adapter->PacketFilter & NDIS_PACKET_TYPE_PROMISCUOUS)
{
filterMask |= B_RC_AAP;
}
NdisRawWritePortUlong(Adapter->IoBase + R_RC, filterMask);
return NDIS_STATUS_SUCCESS;
}
NDIS_STATUS
NTAPI
NICTransmitPacket (
IN PRTL_ADAPTER Adapter,
IN UCHAR TxDesc,
IN ULONG PhysicalAddress,
IN ULONG Length
)
{
NdisRawWritePortUlong(Adapter->IoBase + R_TXSAD0 + (TxDesc * sizeof(ULONG)), PhysicalAddress);
NdisRawWritePortUlong(Adapter->IoBase + R_TXSTS0 + (TxDesc * sizeof(ULONG)), Length);
return NDIS_STATUS_SUCCESS;
}

View file

@ -1,247 +0,0 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Novell Eagle 2000 driver
* FILE: include/ne2000.h
* PURPOSE: NE2000 driver definitions
*/
#define NDIS_MINIPORT_DRIVER 1
#define NDIS_LEGACY_MINIPORT 1
#define NDIS51_MINIPORT 1
#include <ndis.h>
#include <8139.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 0x05
#define DRIVER_NDIS_MINOR_VERSION 0
#define DRIVER_DEFAULT_IO_BASE_ADDRESS 0x280 /* bochs default */
#define DRIVER_DEFAULT_INTERRUPT_NUMBER 9 /* bochs default */
#define DRIVER_DEFAULT_INTERRUPT_SHARED FALSE
#define DRIVER_DEFAULT_INTERRUPT_MODE NdisInterruptLatched
#define DRIVER_MAX_MULTICAST_LIST_SIZE 8
#define DRIVER_VENDOR_DESCRIPTION "RTL 8139 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
#define BUFFERS_PER_TX_BUF 1
/* Interrupt Mask Register value */
#define DRIVER_INTERRUPT_MASK IMR_ALLE - IMR_RDCE
/* Maximum number of interrupts handled per call to MiniportHandleInterrupt */
#define INTERRUPT_LIMIT 10
/* Global structures */
typedef struct _MINIPORT_RESERVED
{
PNDIS_PACKET Next;
} MINIPORT_RESERVED, *PMINIPORT_RESERVED;
#define RESERVED(Packet) ((PMINIPORT_RESERVED)((Packet)->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_PTR IoBaseAddress;
ULONG InterruptLevel;
ULONG InterruptVector;
BOOLEAN InterruptShared;
KINTERRUPT_MODE InterruptMode;
/* 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 */
UINT 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;
BOOLEAN ShutdownHandlerRegistered;
} 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_PTR Source,
USHORT Length);
VOID NICWriteDataAlign(
PNIC_ADAPTER Adapter,
ULONG_PTR Target,
PUSHORT Source,
USHORT Length);
VOID NICReadData(
PNIC_ADAPTER Adapter,
PUCHAR Target,
ULONG_PTR Source,
USHORT Length);
VOID NICWriteData(
PNIC_ADAPTER Adapter,
ULONG_PTR Target,
PUCHAR Source,
USHORT Length);
VOID NICTransmit(
PNIC_ADAPTER Adapter);
/* EOF */

View file

@ -0,0 +1,394 @@
/*
* ReactOS Realtek 8139 Driver
*
* Copyright (C) 2013 Cameron Gutman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "nic.h"
#define NDEBUG
#include <debug.h>
static ULONG SupportedOidList[] =
{
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_RECEIVE_BLOCK_SIZE,
OID_GEN_TRANSMIT_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_GEN_XMIT_OK,
OID_GEN_RCV_OK,
OID_GEN_XMIT_ERROR,
OID_GEN_RCV_ERROR,
OID_GEN_RCV_NO_BUFFER,
OID_GEN_RCV_CRC_ERROR,
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,
OID_802_3_RCV_ERROR_ALIGNMENT,
OID_802_3_XMIT_ONE_COLLISION,
OID_802_3_XMIT_MORE_COLLISIONS
};
NDIS_STATUS
NTAPI
MiniportQueryInformation (
IN NDIS_HANDLE MiniportAdapterContext,
IN NDIS_OID Oid,
IN PVOID InformationBuffer,
IN ULONG InformationBufferLength,
OUT PULONG BytesWritten,
OUT PULONG BytesNeeded
)
{
PRTL_ADAPTER adapter = (PRTL_ADAPTER)MiniportAdapterContext;
ULONG genericUlong;
ULONG copyLength;
PVOID copySource;
NDIS_STATUS status;
status = NDIS_STATUS_SUCCESS;
copySource = &genericUlong;
copyLength = sizeof(ULONG);
NdisAcquireSpinLock(&adapter->Lock);
switch (Oid)
{
case OID_GEN_SUPPORTED_LIST:
copySource = (PVOID)&SupportedOidList;
copyLength = sizeof(SupportedOidList);
break;
case OID_GEN_CURRENT_PACKET_FILTER:
genericUlong = adapter->PacketFilter;
break;
case OID_GEN_HARDWARE_STATUS:
genericUlong = (ULONG)NdisHardwareStatusReady; //FIXME
break;
case OID_GEN_MEDIA_SUPPORTED:
case OID_GEN_MEDIA_IN_USE:
{
static const NDIS_MEDIUM medium = NdisMedium802_3;
copySource = (PVOID)&medium;
copyLength = sizeof(medium);
break;
}
case OID_GEN_RECEIVE_BLOCK_SIZE:
case OID_GEN_TRANSMIT_BLOCK_SIZE:
case OID_GEN_CURRENT_LOOKAHEAD:
case OID_GEN_MAXIMUM_LOOKAHEAD:
case OID_GEN_MAXIMUM_FRAME_SIZE:
genericUlong = MAXIMUM_FRAME_SIZE - sizeof(ETH_HEADER);
break;
case OID_GEN_LINK_SPEED:
genericUlong = adapter->LinkSpeedMbps * 1000;
break;
case OID_GEN_TRANSMIT_BUFFER_SPACE:
genericUlong = MAXIMUM_FRAME_SIZE;
break;
case OID_GEN_RECEIVE_BUFFER_SPACE:
genericUlong = RECEIVE_BUFFER_SIZE;
break;
case OID_GEN_VENDOR_ID:
//
// The 3 bytes of the MAC address is the vendor ID
//
genericUlong = 0;
genericUlong |= (adapter->PermanentMacAddress[0] << 16);
genericUlong |= (adapter->PermanentMacAddress[1] << 8);
genericUlong |= (adapter->PermanentMacAddress[2] & 0xFF);
break;
case OID_GEN_VENDOR_DESCRIPTION:
{
static UCHAR vendorDesc[] = "ReactOS Team";
copySource = vendorDesc;
copyLength = sizeof(vendorDesc);
break;
}
case OID_GEN_VENDOR_DRIVER_VERSION:
genericUlong = DRIVER_VERSION;
break;
case OID_GEN_DRIVER_VERSION:
{
static const USHORT driverVersion =
(NDIS_MINIPORT_MAJOR_VERSION << 8) + NDIS_MINIPORT_MINOR_VERSION;
copySource = (PVOID)&driverVersion;
copyLength = sizeof(driverVersion);
break;
}
case OID_GEN_MAXIMUM_TOTAL_SIZE:
genericUlong = MAXIMUM_FRAME_SIZE;
break;
case OID_GEN_PROTOCOL_OPTIONS:
NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_PROTOCOL_OPTIONS is unimplemented\n"));
status = NDIS_STATUS_NOT_SUPPORTED;
break;
case OID_GEN_MAC_OPTIONS:
genericUlong = NDIS_MAC_OPTION_RECEIVE_SERIALIZED |
NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
NDIS_MAC_OPTION_TRANSFERS_NOT_PEND |
NDIS_MAC_OPTION_NO_LOOPBACK;
break;
case OID_GEN_MEDIA_CONNECT_STATUS:
genericUlong = adapter->MediaState;
break;
case OID_GEN_MAXIMUM_SEND_PACKETS:
genericUlong = 1;
break;
case OID_802_3_CURRENT_ADDRESS:
copySource = adapter->CurrentMacAddress;
copyLength = IEEE_802_ADDR_LENGTH;
break;
case OID_802_3_PERMANENT_ADDRESS:
copySource = adapter->PermanentMacAddress;
copyLength = IEEE_802_ADDR_LENGTH;
break;
case OID_802_3_MAXIMUM_LIST_SIZE:
genericUlong = MAXIMUM_MULTICAST_ADDRESSES;
break;
case OID_GEN_XMIT_OK:
genericUlong = adapter->TransmitOk;
break;
case OID_GEN_RCV_OK:
genericUlong = adapter->ReceiveOk;
break;
case OID_GEN_XMIT_ERROR:
genericUlong = adapter->TransmitError;
break;
case OID_GEN_RCV_ERROR:
genericUlong = adapter->ReceiveError;
break;
case OID_GEN_RCV_NO_BUFFER:
genericUlong = adapter->ReceiveNoBufferSpace;
break;
case OID_GEN_RCV_CRC_ERROR:
genericUlong = adapter->ReceiveCrcError;
break;
case OID_802_3_RCV_ERROR_ALIGNMENT:
genericUlong = adapter->ReceiveAlignmentError;
break;
case OID_802_3_XMIT_ONE_COLLISION:
genericUlong = adapter->TransmitOneCollision;
break;
case OID_802_3_XMIT_MORE_COLLISIONS:
genericUlong = adapter->TransmitMoreCollisions;
break;
default:
NDIS_DbgPrint(MIN_TRACE, ("Unknown OID\n"));
status = NDIS_STATUS_NOT_SUPPORTED;
break;
}
if (status == NDIS_STATUS_SUCCESS)
{
if (copyLength > InformationBufferLength)
{
*BytesNeeded = copyLength;
*BytesWritten = 0;
status = NDIS_STATUS_INVALID_LENGTH;
}
else
{
NdisMoveMemory(InformationBuffer, copySource, copyLength);
*BytesWritten = copyLength;
*BytesNeeded = copyLength;
}
}
else
{
*BytesWritten = 0;
*BytesNeeded = 0;
}
NdisReleaseSpinLock(&adapter->Lock);
NDIS_DbgPrint(MAX_TRACE, ("Query OID 0x%x: Completed with status 0x%x (%d, %d)\n",
Oid, status, *BytesWritten, *BytesNeeded));
return status;
}
NDIS_STATUS
NTAPI
MiniportSetInformation (
IN NDIS_HANDLE MiniportAdapterContext,
IN NDIS_OID Oid,
IN PVOID InformationBuffer,
IN ULONG InformationBufferLength,
OUT PULONG BytesRead,
OUT PULONG BytesNeeded
)
{
PRTL_ADAPTER adapter = (PRTL_ADAPTER)MiniportAdapterContext;
ULONG genericUlong;
NDIS_STATUS status;
status = NDIS_STATUS_SUCCESS;
NdisAcquireSpinLock(&adapter->Lock);
switch (Oid)
{
case OID_GEN_CURRENT_PACKET_FILTER:
if (InformationBufferLength < sizeof(ULONG))
{
*BytesRead = 0;
*BytesNeeded = sizeof(ULONG);
status = NDIS_STATUS_INVALID_LENGTH;
break;
}
NdisMoveMemory(&genericUlong, InformationBuffer, sizeof(ULONG));
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 = sizeof(ULONG);
*BytesNeeded = sizeof(ULONG);
status = NDIS_STATUS_NOT_SUPPORTED;
break;
}
adapter->PacketFilter = genericUlong;
status = NICApplyPacketFilter(adapter);
if (status != NDIS_STATUS_SUCCESS)
{
NDIS_DbgPrint(MIN_TRACE, ("Failed to apply new packet filter\n"));
break;
}
break;
case OID_GEN_CURRENT_LOOKAHEAD:
if (InformationBufferLength < sizeof(ULONG))
{
*BytesRead = 0;
*BytesNeeded = sizeof(ULONG);
status = NDIS_STATUS_INVALID_LENGTH;
break;
}
NdisMoveMemory(&genericUlong, InformationBuffer, sizeof(ULONG));
if (genericUlong > MAXIMUM_FRAME_SIZE - sizeof(ETH_HEADER))
{
status = NDIS_STATUS_INVALID_DATA;
}
else
{
// Ignore this...
}
break;
case OID_802_3_MULTICAST_LIST:
if (InformationBufferLength % IEEE_802_ADDR_LENGTH)
{
*BytesRead = 0;
*BytesNeeded = InformationBufferLength + (InformationBufferLength % IEEE_802_ADDR_LENGTH);
status = NDIS_STATUS_INVALID_LENGTH;
break;
}
if (InformationBufferLength / 6 > MAXIMUM_MULTICAST_ADDRESSES)
{
*BytesNeeded = MAXIMUM_MULTICAST_ADDRESSES * IEEE_802_ADDR_LENGTH;
*BytesRead = 0;
status = NDIS_STATUS_INVALID_LENGTH;
break;
}
NdisMoveMemory(adapter->MulticastList, InformationBuffer, InformationBufferLength);
// FIXME: Write to device
break;
default:
NDIS_DbgPrint(MIN_TRACE, ("Unknown OID\n"));
status = NDIS_STATUS_NOT_SUPPORTED;
*BytesRead = 0;
*BytesNeeded = 0;
break;
}
if (status == NDIS_STATUS_SUCCESS)
{
*BytesRead = InformationBufferLength;
*BytesNeeded = 0;
}
NdisReleaseSpinLock(&adapter->Lock);
return status;
}

View file

@ -0,0 +1,210 @@
/*
* ReactOS Realtek 8139 Driver
*
* Copyright (C) 2013 Cameron Gutman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "nic.h"
#define NDEBUG
#include <debug.h>
VOID
NTAPI
MiniportISR (
OUT PBOOLEAN InterruptRecognized,
OUT PBOOLEAN QueueMiniportHandleInterrupt,
IN NDIS_HANDLE MiniportAdapterContext
)
{
PRTL_ADAPTER adapter = (PRTL_ADAPTER)MiniportAdapterContext;
ULONG csConfig;
//
// FIXME: We need to synchronize with this ISR for changes to InterruptPending,
// LinkChange, MediaState, and LinkSpeedMbps. We can get away with IRQL
// synchronization on non-SMP machines because we run a DIRQL here.
//
adapter->InterruptPending |= NICInterruptRecognized(adapter, InterruptRecognized);
if (!(*InterruptRecognized))
{
//
// This is not ours.
//
*QueueMiniportHandleInterrupt = FALSE;
return;
}
//
// We have to check for a special link change interrupt before acknowledging
//
if (adapter->InterruptPending & R_I_RXUNDRUN)
{
NdisRawReadPortUlong(adapter->IoBase + R_CSCFG, &csConfig);
if (csConfig & R_CSCR_LINKCHNG)
{
adapter->LinkChange = TRUE;
NICUpdateLinkStatus(adapter);
}
}
//
// Acknowledge the interrupt and mark the events pending service
//
NICAcknowledgeInterrupts(adapter);
*QueueMiniportHandleInterrupt = TRUE;
}
VOID
NTAPI
MiniportHandleInterrupt (
IN NDIS_HANDLE MiniportAdapterContext
)
{
PRTL_ADAPTER adapter = (PRTL_ADAPTER)MiniportAdapterContext;
ULONG i;
ULONG txStatus;
UCHAR command;
PPACKET_HEADER nicHeader;
PETH_HEADER ethHeader;
NdisDprAcquireSpinLock(&adapter->Lock);
NDIS_DbgPrint(MAX_TRACE, ("Interrupts pending: 0x%x\n", adapter->InterruptPending));
//
// Handle a link change
//
if (adapter->LinkChange)
{
NdisDprReleaseSpinLock(&adapter->Lock);
NdisMIndicateStatus(adapter->MiniportAdapterHandle,
adapter->MediaState == NdisMediaStateConnected ?
NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT,
NULL,
0);
NdisMIndicateStatusComplete(adapter->MiniportAdapterHandle);
NdisDprAcquireSpinLock(&adapter->Lock);
adapter->LinkChange = FALSE;
}
//
// Handle a TX interrupt
//
if (adapter->InterruptPending & (R_I_TXOK | R_I_TXERR))
{
while (adapter->TxFull || adapter->DirtyTxDesc != adapter->CurrentTxDesc)
{
NdisRawReadPortUlong(adapter->IoBase + R_TXSTS0 +
(adapter->DirtyTxDesc * sizeof(ULONG)), &txStatus);
if (!(txStatus & (R_TXS_STATOK | R_TXS_UNDERRUN | R_TXS_ABORTED)))
{
//
// Not sent yet
//
break;
}
NDIS_DbgPrint(MAX_TRACE, ("Transmission for desc %d complete: 0x%x\n",
adapter->DirtyTxDesc, txStatus));
if (txStatus & R_TXS_STATOK)
{
adapter->TransmitOk++;
}
else
{
adapter->TransmitError++;
}
adapter->DirtyTxDesc++;
adapter->DirtyTxDesc %= TX_DESC_COUNT;
adapter->InterruptPending &= ~(R_I_TXOK | R_I_TXERR);
adapter->TxFull = FALSE;
}
}
//
// Handle a good RX interrupt
//
if (adapter->InterruptPending & (R_I_RXOK | R_I_RXERR))
{
for (i = 0; i < MAX_RECEIVES_PER_INT; i++)
{
NdisRawReadPortUchar(adapter->IoBase + R_CMD, &command);
if (command & R_CMD_RXEMPTY)
{
//
// The buffer is empty
//
adapter->InterruptPending &= ~(R_I_RXOK | R_I_RXERR);
break;
}
adapter->ReceiveOffset %= RECEIVE_BUFFER_SIZE;
NDIS_DbgPrint(MAX_TRACE, ("Looking for a packet at offset 0x%x\n",
adapter->ReceiveOffset));
nicHeader = (PPACKET_HEADER)(adapter->ReceiveBuffer + adapter->ReceiveOffset);
if (!(nicHeader->Status & RSR_ROK))
{
//
// Receive failed
//
NDIS_DbgPrint(MIN_TRACE, ("Receive failed: 0x%x\n", nicHeader->Status));
if (nicHeader->Status & RSR_FAE)
{
adapter->ReceiveAlignmentError++;
}
else if (nicHeader->Status & RSR_CRC)
{
adapter->ReceiveCrcError++;
}
adapter->ReceiveError++;
goto NextPacket;
}
NDIS_DbgPrint(MAX_TRACE, ("Indicating %d byte packet to NDIS\n",
nicHeader->PacketLength - RECV_CRC_LENGTH));
ethHeader = (PETH_HEADER)(nicHeader + 1);
NdisMEthIndicateReceive(adapter->MiniportAdapterHandle,
NULL,
(PVOID)(ethHeader),
sizeof(ETH_HEADER),
(PVOID)(ethHeader + 1),
nicHeader->PacketLength - sizeof(ETH_HEADER) - RECV_CRC_LENGTH,
nicHeader->PacketLength - sizeof(ETH_HEADER) - RECV_CRC_LENGTH);
adapter->ReceiveOk++;
NextPacket:
adapter->ReceiveOffset += nicHeader->PacketLength + sizeof(PACKET_HEADER);
adapter->ReceiveOffset = (adapter->ReceiveOffset + 3) & ~3;
NdisRawWritePortUshort(adapter->IoBase + R_CAPR, adapter->ReceiveOffset - 0x10);
}
NdisMEthIndicateReceiveComplete(adapter->MiniportAdapterHandle);
}
NdisDprReleaseSpinLock(&adapter->Lock);
}

View file

@ -0,0 +1,525 @@
/*
* ReactOS Realtek 8139 Driver
*
* Copyright (C) 2013 Cameron Gutman
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "nic.h"
#define NDEBUG
#include <debug.h>
ULONG DebugTraceLevel = MIN_TRACE;
NDIS_STATUS
NTAPI
MiniportReset (
OUT PBOOLEAN AddressingReset,
IN NDIS_HANDLE MiniportAdapterContext
)
{
*AddressingReset = FALSE;
return NDIS_STATUS_FAILURE;
}
NDIS_STATUS
NTAPI
MiniportSend (
IN NDIS_HANDLE MiniportAdapterContext,
IN PNDIS_PACKET Packet,
IN UINT Flags
)
{
PRTL_ADAPTER adapter = (PRTL_ADAPTER)MiniportAdapterContext;
NDIS_STATUS status;
PSCATTER_GATHER_LIST sgList = NDIS_PER_PACKET_INFO_FROM_PACKET(Packet,
ScatterGatherListPacketInfo);
ULONG transmitLength;
ULONG transmitBuffer;
PNDIS_BUFFER firstBuffer;
PVOID firstBufferVa;
UINT firstBufferLength, totalBufferLength;
PUCHAR runtBuffer;
ASSERT(sgList != NULL);
ASSERT(sgList->NumberOfElements == 1);
ASSERT(sgList->Elements[0].Address.HighPart == 0);
ASSERT((sgList->Elements[0].Address.LowPart & 3) == 0);
ASSERT(sgList->Elements[0].Length <= MAXIMUM_FRAME_SIZE);
NDIS_DbgPrint(MAX_TRACE, ("Sending %d byte packet\n", sgList->Elements[0].Length));
NdisAcquireSpinLock(&adapter->Lock);
if (adapter->TxFull)
{
NDIS_DbgPrint(MIN_TRACE, ("All TX descriptors are full\n"));
NdisReleaseSpinLock(&adapter->Lock);
return NDIS_STATUS_RESOURCES;
}
NDIS_DbgPrint(MAX_TRACE, ("Sending packet on TX desc %d\n", adapter->CurrentTxDesc));
//
// If this is a runt, we need to pad it manually for the RTL8139
//
if (sgList->Elements[0].Length < MINIMUM_FRAME_SIZE)
{
transmitLength = MINIMUM_FRAME_SIZE;
transmitBuffer = adapter->RuntTxBuffersPa.LowPart +
(MINIMUM_FRAME_SIZE * adapter->CurrentTxDesc);
NdisGetFirstBufferFromPacketSafe(Packet,
&firstBuffer,
&firstBufferVa,
&firstBufferLength,
&totalBufferLength,
NormalPagePriority);
if (firstBufferVa == NULL)
{
NDIS_DbgPrint(MIN_TRACE, ("Unable to get buffer from packet\n"));
NdisReleaseSpinLock(&adapter->Lock);
return NDIS_STATUS_RESOURCES;
}
ASSERT(firstBufferLength == totalBufferLength);
runtBuffer = adapter->RuntTxBuffers + (MINIMUM_FRAME_SIZE * adapter->CurrentTxDesc);
RtlCopyMemory(runtBuffer, firstBufferVa, firstBufferLength);
RtlFillMemory(runtBuffer + firstBufferLength, MINIMUM_FRAME_SIZE - firstBufferLength, 0x00);
}
else
{
transmitLength = sgList->Elements[0].Length;
transmitBuffer = sgList->Elements[0].Address.LowPart;
}
status = NICTransmitPacket(adapter, adapter->CurrentTxDesc, transmitBuffer, transmitLength);
if (status != NDIS_STATUS_SUCCESS)
{
NDIS_DbgPrint(MIN_TRACE, ("Transmit packet failed\n"));
NdisReleaseSpinLock(&adapter->Lock);
return status;
}
adapter->CurrentTxDesc++;
adapter->CurrentTxDesc %= TX_DESC_COUNT;
if (adapter->CurrentTxDesc == adapter->DirtyTxDesc)
{
NDIS_DbgPrint(MID_TRACE, ("All TX descriptors are full now\n"));
adapter->TxFull = TRUE;
}
NdisReleaseSpinLock(&adapter->Lock);
return NDIS_STATUS_SUCCESS;
}
VOID
NTAPI
MiniportHalt (
IN NDIS_HANDLE MiniportAdapterContext
)
{
PRTL_ADAPTER adapter = (PRTL_ADAPTER)MiniportAdapterContext;
ASSERT(adapter != NULL);
//
// Interrupts need to stop first
//
if (adapter->InterruptRegistered != FALSE)
{
NdisMDeregisterInterrupt(&adapter->Interrupt);
}
//
// If we have a mapped IO port range, we can talk to the NIC
//
if (adapter->IoBase != NULL)
{
if (adapter->ReceiveBuffer != NULL)
{
//
// Disassociate our shared buffer before freeing it to avoid
// NIC-induced memory corruption
//
NICRemoveReceiveBuffer(adapter);
NdisMFreeSharedMemory(adapter->MiniportAdapterHandle,
adapter->ReceiveBufferLength,
FALSE,
adapter->ReceiveBuffer,
adapter->ReceiveBufferPa);
}
if (adapter->RuntTxBuffers != NULL)
{
NdisMFreeSharedMemory(adapter->MiniportAdapterHandle,
MINIMUM_FRAME_SIZE * TX_DESC_COUNT,
FALSE,
adapter->RuntTxBuffers,
adapter->RuntTxBuffersPa);
}
//
// Unregister the IO range
//
NdisMDeregisterIoPortRange(adapter->MiniportAdapterHandle,
adapter->IoRangeStart,
adapter->IoRangeLength,
adapter->IoBase);
}
//
// Destroy the adapter context
//
NdisFreeMemory(adapter, sizeof(*adapter), 0);
}
NDIS_STATUS
NTAPI
MiniportInitialize (
OUT PNDIS_STATUS OpenErrorStatus,
OUT PUINT SelectedMediumIndex,
IN PNDIS_MEDIUM MediumArray,
IN UINT MediumArraySize,
IN NDIS_HANDLE MiniportAdapterHandle,
IN NDIS_HANDLE WrapperConfigurationContext
)
{
PRTL_ADAPTER adapter;
NDIS_STATUS status;
UINT i;
PNDIS_RESOURCE_LIST resourceList;
UINT resourceListSize;
//
// Make sure the medium is supported
//
for (i = 0; i < MediumArraySize; i++)
{
if (MediumArray[i] == NdisMedium802_3)
{
*SelectedMediumIndex = i;
break;
}
}
if (i == MediumArraySize)
{
NDIS_DbgPrint(MIN_TRACE, ("802.3 medium was not found in the medium array\n"));
return NDIS_STATUS_UNSUPPORTED_MEDIA;
}
//
// Allocate our adapter context
//
status = NdisAllocateMemoryWithTag((PVOID*)&adapter,
sizeof(*adapter),
ADAPTER_TAG);
if (status != NDIS_STATUS_SUCCESS)
{
NDIS_DbgPrint(MIN_TRACE, ("Failed to allocate adapter context\n"));
return NDIS_STATUS_RESOURCES;
}
RtlZeroMemory(adapter, sizeof(*adapter));
adapter->MiniportAdapterHandle = MiniportAdapterHandle;
NdisAllocateSpinLock(&adapter->Lock);
//
// Notify NDIS of some characteristics of our NIC
//
NdisMSetAttributesEx(MiniportAdapterHandle,
adapter,
0,
NDIS_ATTRIBUTE_BUS_MASTER,
NdisInterfacePci);
//
// Get our resources for IRQ and IO base information
//
resourceList = NULL;
resourceListSize = 0;
NdisMQueryAdapterResources(&status,
WrapperConfigurationContext,
resourceList,
&resourceListSize);
if (status != NDIS_STATUS_RESOURCES)
{
NDIS_DbgPrint(MIN_TRACE, ("Unexpected failure of NdisMQueryAdapterResources #1\n"));
status = NDIS_STATUS_FAILURE;
goto Cleanup;
}
status = NdisAllocateMemoryWithTag((PVOID*)&resourceList,
resourceListSize,
RESOURCE_LIST_TAG);
if (status != NDIS_STATUS_SUCCESS)
{
NDIS_DbgPrint(MIN_TRACE, ("Failed to allocate resource list\n"));
goto Cleanup;
}
NdisMQueryAdapterResources(&status,
WrapperConfigurationContext,
resourceList,
&resourceListSize);
if (status != NDIS_STATUS_SUCCESS)
{
NDIS_DbgPrint(MIN_TRACE, ("Unexpected failure of NdisMQueryAdapterResources #2\n"));
goto Cleanup;
}
ASSERT(resourceList->Version == 1);
ASSERT(resourceList->Revision == 1);
for (i = 0; i < resourceList->Count; i++)
{
switch (resourceList->PartialDescriptors[i].Type)
{
case CmResourceTypePort:
ASSERT(adapter->IoRangeStart == 0);
ASSERT(resourceList->PartialDescriptors[i].u.Port.Start.HighPart == 0);
adapter->IoRangeStart = resourceList->PartialDescriptors[i].u.Port.Start.LowPart;
adapter->IoRangeLength = resourceList->PartialDescriptors[i].u.Port.Length;
NDIS_DbgPrint(MID_TRACE, ("I/O port range is %p to %p\n",
adapter->IoRangeStart, adapter->IoRangeStart + adapter->IoRangeLength));
break;
case CmResourceTypeInterrupt:
ASSERT(adapter->InterruptVector == 0);
ASSERT(adapter->InterruptLevel == 0);
adapter->InterruptVector = resourceList->PartialDescriptors[i].u.Interrupt.Vector;
adapter->InterruptLevel = resourceList->PartialDescriptors[i].u.Interrupt.Level;
adapter->InterruptShared = (resourceList->PartialDescriptors[i].ShareDisposition == CmResourceShareShared);
adapter->InterruptFlags = resourceList->PartialDescriptors[i].Flags;
NDIS_DbgPrint(MID_TRACE, ("IRQ vector is %d\n", adapter->InterruptVector));
break;
default:
NDIS_DbgPrint(MIN_TRACE, ("Unrecognized resource type: 0x%x\n", resourceList->PartialDescriptors[i].Type));
break;
}
}
NdisFreeMemory(resourceList, resourceListSize, 0);
resourceList = NULL;
if (adapter->IoRangeStart == 0 || adapter->InterruptVector == 0)
{
NDIS_DbgPrint(MIN_TRACE, ("Adapter didn't receive enough resources\n"));
goto Cleanup;
}
//
// Allocate the DMA resources
//
status = NdisMInitializeScatterGatherDma(MiniportAdapterHandle,
FALSE, // RTL8139 only supports 32-bit addresses
MAXIMUM_FRAME_SIZE);
if (status != NDIS_STATUS_SUCCESS)
{
NDIS_DbgPrint(MIN_TRACE, ("Unable to configure DMA\n"));
goto Cleanup;
}
adapter->ReceiveBufferLength = FULL_RECEIVE_BUFFER_SIZE;
NdisMAllocateSharedMemory(MiniportAdapterHandle,
adapter->ReceiveBufferLength,
FALSE,
(PVOID*)&adapter->ReceiveBuffer,
&adapter->ReceiveBufferPa);
if (adapter->ReceiveBuffer == NULL)
{
NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate receive buffer\n"));
goto Cleanup;
}
NdisMAllocateSharedMemory(MiniportAdapterHandle,
MINIMUM_FRAME_SIZE * TX_DESC_COUNT,
FALSE,
(PVOID*)&adapter->RuntTxBuffers,
&adapter->RuntTxBuffersPa);
if (adapter->RuntTxBuffers == NULL)
{
NDIS_DbgPrint(MIN_TRACE, ("Unable to allocate runt TX buffer\n"));
goto Cleanup;
}
//
// Register the I/O port range and configure the NIC
//
status = NdisMRegisterIoPortRange((PVOID*)&adapter->IoBase,
MiniportAdapterHandle,
adapter->IoRangeStart,
adapter->IoRangeLength);
if (status != NDIS_STATUS_SUCCESS)
{
NDIS_DbgPrint(MIN_TRACE, ("Unable to register IO port range (0x%x)\n", status));
goto Cleanup;
}
//
// Adapter setup
//
status = NICPowerOn(adapter);
if (status != NDIS_STATUS_SUCCESS)
{
NDIS_DbgPrint(MIN_TRACE, ("Unable to power on NIC (0x%x)\n", status));
goto Cleanup;
}
status = NICSoftReset(adapter);
if (status != NDIS_STATUS_SUCCESS)
{
NDIS_DbgPrint(MIN_TRACE, ("Unable to reset the NIC (0x%x)\n", status));
goto Cleanup;
}
status = NICGetPermanentMacAddress(adapter, adapter->PermanentMacAddress);
if (status != NDIS_STATUS_SUCCESS)
{
NDIS_DbgPrint(MIN_TRACE, ("Unable to get the fixed MAC address (0x%x)\n", status));
goto Cleanup;
}
RtlCopyMemory(adapter->CurrentMacAddress, adapter->PermanentMacAddress, IEEE_802_ADDR_LENGTH);
//
// Update link state and speed
//
NICUpdateLinkStatus(adapter);
status = NICRegisterReceiveBuffer(adapter);
if (status != NDIS_STATUS_SUCCESS)
{
NDIS_DbgPrint(MIN_TRACE, ("Unable to setup receive buffer (0x%x)\n", status));
goto Cleanup;
}
//
// We're ready to handle interrupts now
//
status = NdisMRegisterInterrupt(&adapter->Interrupt,
MiniportAdapterHandle,
adapter->InterruptVector,
adapter->InterruptLevel,
TRUE, // We always want ISR calls
adapter->InterruptShared,
(adapter->InterruptFlags & CM_RESOURCE_INTERRUPT_LATCHED) ?
NdisInterruptLatched : NdisInterruptLevelSensitive);
if (status != NDIS_STATUS_SUCCESS)
{
NDIS_DbgPrint(MIN_TRACE, ("Unable to register interrupt (0x%x)\n", status));
goto Cleanup;
}
adapter->InterruptRegistered = TRUE;
//
// Enable interrupts on the NIC
//
adapter->InterruptMask = DEFAULT_INTERRUPT_MASK;
status = NICApplyInterruptMask(adapter);
if (status != NDIS_STATUS_SUCCESS)
{
NDIS_DbgPrint(MIN_TRACE, ("Unable to apply interrupt mask (0x%x)\n", status));
goto Cleanup;
}
//
// Turn on TX and RX now
//
status = NICEnableTxRx(adapter);
if (status != NDIS_STATUS_SUCCESS)
{
NDIS_DbgPrint(MIN_TRACE, ("Unable to enable TX and RX (0x%x)\n", status));
goto Cleanup;
}
return NDIS_STATUS_SUCCESS;
Cleanup:
if (resourceList != NULL)
{
NdisFreeMemory(resourceList, resourceListSize, 0);
}
if (adapter != NULL)
{
MiniportHalt(adapter);
}
return status;
}
NTSTATUS
NTAPI
DriverEntry (
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
NDIS_HANDLE wrapperHandle;
NDIS_MINIPORT_CHARACTERISTICS characteristics;
NDIS_STATUS status;
RtlZeroMemory(&characteristics, sizeof(characteristics));
characteristics.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
characteristics.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
characteristics.CheckForHangHandler = NULL;
characteristics.DisableInterruptHandler = NULL;
characteristics.EnableInterruptHandler = NULL;
characteristics.HaltHandler = MiniportHalt;
characteristics.HandleInterruptHandler = MiniportHandleInterrupt;
characteristics.InitializeHandler = MiniportInitialize;
characteristics.ISRHandler = MiniportISR;
characteristics.QueryInformationHandler = MiniportQueryInformation;
characteristics.ReconfigureHandler = NULL;
characteristics.ResetHandler = MiniportReset;
characteristics.SendHandler = MiniportSend;
characteristics.SetInformationHandler = MiniportSetInformation;
characteristics.TransferDataHandler = NULL;
characteristics.ReturnPacketHandler = NULL;
characteristics.SendPacketsHandler = NULL;
characteristics.AllocateCompleteHandler = NULL;
NdisMInitializeWrapper(&wrapperHandle, DriverObject, RegistryPath, NULL);
if (!wrapperHandle)
{
return NDIS_STATUS_FAILURE;
}
status = NdisMRegisterMiniport(wrapperHandle, &characteristics, sizeof(characteristics));
if (status != NDIS_STATUS_SUCCESS)
{
NdisTerminateWrapper(wrapperHandle, 0);
return NDIS_STATUS_FAILURE;
}
return NDIS_STATUS_SUCCESS;
}

View file

@ -0,0 +1,204 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Realtek 8139 driver
* FILE: rtl8139.h
* PURPOSE: RTL8139 driver definitions
*/
#include <ndis.h>
#include <rtlhw.h>
#define ADAPTER_TAG 'Altr'
#define RESOURCE_LIST_TAG 'Rltr'
#define MAX_RESET_ATTEMPTS 25
#define MAX_RECEIVES_PER_INT 10
#define RECEIVE_BUFFER_SIZE (32768)
#define FULL_RECEIVE_BUFFER_SIZE (32768 + 16 + 2048)
#define RECV_CRC_LENGTH 4
#define MINIMUM_FRAME_SIZE 60
#define MAXIMUM_FRAME_SIZE 1514
#define DRIVER_VERSION 1
// 32K RX buffer, 512 byte DMA bursts
#define RC_VAL (0x0001680)
// 1024 byte DMA bursts
#define TC_VAL (0x600)
typedef struct _RTL_ADAPTER {
NDIS_HANDLE MiniportAdapterHandle;
NDIS_SPIN_LOCK Lock;
ULONG IoRangeStart;
ULONG IoRangeLength;
ULONG InterruptVector;
ULONG InterruptLevel;
BOOLEAN InterruptShared;
ULONG InterruptFlags;
PUCHAR IoBase;
NDIS_MINIPORT_INTERRUPT Interrupt;
BOOLEAN InterruptRegistered;
UCHAR PermanentMacAddress[IEEE_802_ADDR_LENGTH];
UCHAR CurrentMacAddress[IEEE_802_ADDR_LENGTH];
struct {
UCHAR MacAddress[IEEE_802_ADDR_LENGTH];
} MulticastList[MAXIMUM_MULTICAST_ADDRESSES];
ULONG ReceiveBufferLength;
PUCHAR ReceiveBuffer;
NDIS_PHYSICAL_ADDRESS ReceiveBufferPa;
USHORT ReceiveOffset;
ULONG LinkSpeedMbps;
ULONG MediaState;
BOOLEAN LinkChange;
ULONG PacketFilter;
USHORT InterruptMask;
USHORT InterruptPending;
UCHAR DirtyTxDesc;
UCHAR CurrentTxDesc;
BOOLEAN TxFull;
PUCHAR RuntTxBuffers;
NDIS_PHYSICAL_ADDRESS RuntTxBuffersPa;
ULONG ReceiveOk;
ULONG TransmitOk;
ULONG ReceiveError;
ULONG TransmitError;
ULONG ReceiveNoBufferSpace;
ULONG ReceiveCrcError;
ULONG ReceiveAlignmentError;
ULONG TransmitOneCollision;
ULONG TransmitMoreCollisions;
} RTL_ADAPTER, *PRTL_ADAPTER;
NDIS_STATUS
NTAPI
NICPowerOn (
IN PRTL_ADAPTER Adapter
);
NDIS_STATUS
NTAPI
NICSoftReset (
IN PRTL_ADAPTER Adapter
);
NDIS_STATUS
NTAPI
NICRegisterReceiveBuffer (
IN PRTL_ADAPTER Adapter
);
NDIS_STATUS
NTAPI
NICRemoveReceiveBuffer (
IN PRTL_ADAPTER Adapter
);
NDIS_STATUS
NTAPI
NICEnableTxRx (
IN PRTL_ADAPTER Adapter
);
NDIS_STATUS
NTAPI
NICGetPermanentMacAddress (
IN PRTL_ADAPTER Adapter,
OUT PUCHAR MacAddress
);
NDIS_STATUS
NTAPI
NICApplyPacketFilter (
IN PRTL_ADAPTER Adapter
);
NDIS_STATUS
NTAPI
NICApplyInterruptMask (
IN PRTL_ADAPTER Adapter
);
NDIS_STATUS
NTAPI
NICDisableInterrupts (
IN PRTL_ADAPTER Adapter
);
USHORT
NTAPI
NICInterruptRecognized (
IN PRTL_ADAPTER Adapter,
OUT PBOOLEAN InterruptRecognized
);
VOID
NTAPI
NICAcknowledgeInterrupts (
IN PRTL_ADAPTER Adapter
);
VOID
NTAPI
NICUpdateLinkStatus (
IN PRTL_ADAPTER Adapter
);
NDIS_STATUS
NTAPI
NICTransmitPacket (
IN PRTL_ADAPTER Adapter,
IN UCHAR TxDesc,
IN ULONG PhysicalAddress,
IN ULONG Length
);
NDIS_STATUS
NTAPI
MiniportSetInformation (
IN NDIS_HANDLE MiniportAdapterContext,
IN NDIS_OID Oid,
IN PVOID InformationBuffer,
IN ULONG InformationBufferLength,
OUT PULONG BytesRead,
OUT PULONG BytesNeeded
);
NDIS_STATUS
NTAPI
MiniportQueryInformation (
IN NDIS_HANDLE MiniportAdapterContext,
IN NDIS_OID Oid,
IN PVOID InformationBuffer,
IN ULONG InformationBufferLength,
OUT PULONG BytesWritten,
OUT PULONG BytesNeeded
);
VOID
NTAPI
MiniportISR (
OUT PBOOLEAN InterruptRecognized,
OUT PBOOLEAN QueueMiniportHandleInterrupt,
IN NDIS_HANDLE MiniportAdapterContext
);
VOID
NTAPI
MiniportHandleInterrupt (
IN NDIS_HANDLE MiniportAdapterContext
);
/* EOF */

View file

@ -0,0 +1,6 @@
#define REACTOS_VERSION_DLL
#define REACTOS_STR_FILE_DESCRIPTION "Realtek 8139 Ethernet Driver\0"
#define REACTOS_STR_INTERNAL_NAME "rtl8139\0"
#define REACTOS_STR_ORIGINAL_FILENAME "rtl8139.sys\0"
#include <reactos/version.rc>

View file

@ -1,11 +1,18 @@
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS RTL8139 Driver
* FILE: include/8139.h
* FILE: rtlhw.h
* PURPOSE: 8139 NIC definitions
*/
#pragma once
#define MAXIMUM_MULTICAST_ADDRESSES 8
#define DEFAULT_INTERRUPT_MASK (R_I_RXOK | R_I_RXERR | R_I_TXOK | \
R_I_TXERR | R_I_RXOVRFLW | R_I_RXUNDRUN | \
R_I_FIFOOVR | R_I_PCSTMOUT | R_I_PCIERR)
#define TX_DESC_COUNT 4
//Register addresses
#define R_MAC 0x00 //MAC address uses bytes 0-5, 6 and 7 are reserved
#define R_MCAST0 0x08 //Multicast registers
@ -28,7 +35,15 @@
#define R_ERXBC 0x34 //Early RX byte count register
#define R_ERXSTS 0x36 //Early RX status register
#define R_TXS_HOSTOWNS 0x00002000 //Driver still owns the buffer
#define R_TXS_UNDERRUN 0x00004000 //TX underrun
#define R_TXS_STATOK 0x00008000 //Successful TX
#define R_TXS_OOW 0x20000000 //Out of window
#define R_TXS_ABORTED 0x40000000 //TX aborted
#define R_TXS_CARLOST 0x80000000 //Carrier lost
#define R_CMD 0x37 //Command register
#define R_CMD_RXEMPTY 0x01 //Receive buffer empty
#define B_CMD_TXE 0x04 //Enable TX
#define B_CMD_RXE 0x08 //Enable RX
#define B_CMD_RST 0x10 //Reset bit
@ -39,6 +54,16 @@
#define R_IS 0x3E //Interrupt status register
#define R_TC 0x40 //Transmit configuration register
#define R_I_RXOK 0x0001 //Receive OK
#define R_I_RXERR 0x0002 //Receive error
#define R_I_TXOK 0x0004 //Transmit OK
#define R_I_TXERR 0x0008 //Trasmit error
#define R_I_RXOVRFLW 0x0010 //Receive overflow
#define R_I_RXUNDRUN 0x0020 //Receive underrun
#define R_I_FIFOOVR 0x0040 //FIFO overflow
#define R_I_PCSTMOUT 0x4000 //PCS timeout
#define R_I_PCIERR 0x8000 //PCI error
#define R_RC 0x44 //Receive configuration register
#define B_RC_AAP 0x01 //Accept all packets
#define B_RC_APM 0x02 //Accept packets sent to device MAC
@ -53,6 +78,10 @@
#define R_CFG1 0x52
#define R_TINTR 0x54 //Timer interrupt register
#define R_MS 0x58 //Media status register
#define R_MS_LINKDWN 0x04 //Link is down
#define R_MS_SPEED_10 0x08 //Media is at 10mbps
#define R_CFG3 0x59 //Configuration register 3
#define R_CFG4 0x5A //Configuration register 4
#define R_MINTS 0x5C //Multiple interrupt select
@ -68,6 +97,10 @@
#define R_NWT 0x70 //N-way test register
#define R_RXERRCTR 0x72 //RX error counter
#define R_CSCFG 0x74 //CS configuration register
#define R_CSCR_LINKOK 0x00400 //Link up
#define R_CSCR_LINKCHNG 0x00800 //Link changed
#define R_PHYP1 0x78 //PHY parameter 1
#define R_TWP 0x7C //Twister parameter
#define R_PHYP2 0x80 //PHY parameter 2
@ -88,13 +121,13 @@
#define R_WAKE6 0xBC
#define R_WAKE7 0xC4
#define R_LSBCRC0 0xCC //LSB of the mask byte of wakeup frame 0 within offset 12 to 75
#define R_LSBCRC0 0xCD
#define R_LSBCRC0 0xCE
#define R_LSBCRC0 0xCF
#define R_LSBCRC0 0xD0
#define R_LSBCRC0 0xD1
#define R_LSBCRC0 0xD2
#define R_LSBCRC0 0xD3
#define R_LSBCRC1 0xCD
#define R_LSBCRC2 0xCE
#define R_LSBCRC3 0xCF
#define R_LSBCRC4 0xD0
#define R_LSBCRC5 0xD1
#define R_LSBCRC6 0xD2
#define R_LSBCRC7 0xD3
#define R_CFG5 0xD8 //Configuration register 5
//EEPROM Control Bytes
@ -108,12 +141,20 @@
//EEPROM Commands
#define EE_READ_CMD 0x06
#define RSR_MAR 0x8000 //Mulicast receive
#define RSR_PAM 0x4000 //Physical address match (directed packet)
#define RSR_BAR 0x2000 //Broadcast receive
#define RSR_ISE 0x0020 //Invalid symbol
#define RSR_RUNT 0x0010 //Runt packet
#define RSR_LONG 0x0008 //Long packet
#define RSR_CRC 0x0004 //CRC error
#define RSR_FAE 0x0002 //Frame alignment error
#define RSR_ROK 0x0001 //Receive OK
/* 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 */
USHORT Status; /* See RSR_* constants */
USHORT PacketLength; /* Length of packet NOT including this header */
} PACKET_HEADER, *PPACKET_HEADER;
#define IEEE_802_ADDR_LENGTH 6
@ -125,22 +166,4 @@ typedef struct _ETH_HEADER {
USHORT PayloadType;
} ETH_HEADER, *PETH_HEADER;
typedef struct _DISCARD_HEADER {
PACKET_HEADER HWHeader;
ETH_HEADER EthernetHeader;
} DISCARD_HEADER, *PDISCARD_HEADER;
#define NICDisableInterrupts(Adapter) { \
NDIS_DbgPrint(MAX_TRACE, ("NICDisableInterrupts()\n")); \
NdisRawWritePortUchar((Adapter)->IOBase + PG0_IMR, 0x00); \
}
#define NICEnableInterrupts(Adapter) { \
NDIS_DbgPrint(MAX_TRACE, ("NICEnableInterrupts() Mask (0x%X)\n", (Adapter)->InterruptMask)); \
NdisRawWritePortUchar((Adapter)->IOBase + PG0_IMR, (Adapter)->InterruptMask); \
}
VOID NTAPI MiniportHandleInterrupt(
IN NDIS_HANDLE MiniportAdapterContext);
/* EOF */

View file

@ -27,6 +27,7 @@ list(APPEND INF_FILES
NET_NIC.inf
netamd.inf
netisa.inf
netrtl.inf
netrtpnt.inf
nettcpip.inf
ports.inf

Binary file not shown.