diff --git a/source/Cosmos.Core/Ports.cs b/source/Cosmos.Core/Ports.cs new file mode 100644 index 0000000000..378ea211b0 --- /dev/null +++ b/source/Cosmos.Core/Ports.cs @@ -0,0 +1,86 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Cosmos.Core +{ + public static class Ports + { + /// + /// Reads a byte + /// + /// + /// + public static byte InB(ushort port) + { + var io = new IOPort(port); + return io.Byte; + } + + /// + /// Reads a 32 bit word + /// + /// + /// + public static uint InD(ushort port) + { + var io = new IOPort(port); + return io.DWord; + } + + /// + /// Reads a 16 bit word + /// + /// + /// + public static ushort InW(ushort port) + { + var io = new IOPort(port); + return io.Word; + } + + /// + /// Writes a byte + /// + /// + /// + public static void OutB(ushort port, byte data) + { + var io = new IOPort(port); + io.Byte = data; + } + + /// + /// Writes a 32 bit word + /// + /// + /// + public static void OutD(ushort port, byte data) + { + var io = new IOPort(port); + io.DWord = data; + } + + /// + /// Writes a 32 bit word + /// + /// + /// + public static void OutD(ushort port, uint data) + { + var io = new IOPort(port); + io.DWord = data; + } + + /// + /// Writes a 16 bit word + /// + /// + /// + public static void OutW(ushort port, ushort data) + { + var io = new IOPort(port); + io.Word = data; + } + } +} diff --git a/source/Cosmos.HAL2/Drivers/PCI/Network/RTL8168.cs b/source/Cosmos.HAL2/Drivers/PCI/Network/RTL8168.cs new file mode 100644 index 0000000000..133dbcbcd9 --- /dev/null +++ b/source/Cosmos.HAL2/Drivers/PCI/Network/RTL8168.cs @@ -0,0 +1,358 @@ +/* +* PROJECT: Aura Operating System Development +* CONTENT: RTL8168 Driver +* PROGRAMMERS: Valentin Charbonnier +*/ + +using System; +using System.Collections.Generic; +using Cosmos.Core; +using Cosmos.HAL; +using Cosmos.HAL.Network; +using static Cosmos.Core.INTs; + +namespace Cosmos.HAL.Drivers.PCI.Network +{ + public class RTL8168 : NetworkDevice + { + protected PCIDevice pciCard; + protected MACAddress mac; + + uint BaseAddress; + + public override CardType CardType => CardType.Ethernet; + + public override string Name => "RTL8168"; + + protected ManagedMemoryBlock mRxDescriptor; + protected ManagedMemoryBlock mTxDescriptor; + + protected List mRxBuffers; + protected List mTxBuffers; + + protected Queue mRecvBuffer; + protected Queue mTransmitBuffer; + + private int mNextTXDesc; + + uint OWN = 0x80000000, EOR = 0x40000000; + + uint GetMacVersion() + { + return Ports.InD((ushort)(BaseAddress + 0x40)); + } + + void InitBuffers() + { + + mNextTXDesc = 0; + + mRxDescriptor = new ManagedMemoryBlock(32 * 16, 256); + mTxDescriptor = new ManagedMemoryBlock(32 * 16, 256); + + mRxBuffers = new List(); + mTxBuffers = new List(); + + mTransmitBuffer = new Queue(); + mRecvBuffer = new Queue(); + + for (int i = 0; i < 32; i++) + { + uint xOffset = (uint)i * 16; + var rxbuffer = new ManagedMemoryBlock(2048, 8); + var txbuffer = new ManagedMemoryBlock(2048, 8); + if (i == (32 - 1)) + { + mRxDescriptor.Write32(xOffset + 0, OWN | EOR | (2048 & 0x3FFF)); + mTxDescriptor.Write32(xOffset + 0, EOR); + } + else + { + mRxDescriptor.Write32(xOffset + 0, OWN | EOR | (2048 & 0x3FFF)); + mTxDescriptor.Write32(xOffset + 0, 0); + } + + mRxBuffers.Add(rxbuffer); + mTxBuffers.Add(txbuffer); + + mRxDescriptor.Write32(xOffset + 4, 0); + mTxDescriptor.Write32(xOffset + 4, 0); + + mRxDescriptor.Write32(xOffset + 8, rxbuffer.Offset); + mTxDescriptor.Write32(xOffset + 8, txbuffer.Offset); + + mRxDescriptor.Write32(xOffset + 12, 0); + mTxDescriptor.Write32(xOffset + 12, 0); + + } + } + + public RTL8168(PCIDevice device) : base() + { + if (device == null) + { + throw new ArgumentException("PCI Device is null. Unable to get Realtek 8168 card"); + } + pciCard = device; + + // We are handling this device + pciCard.Claimed = true; + + BaseAddress = pciCard.BaseAddressBar[0].BaseAddress; + + // Enable the card + pciCard.EnableDevice(); + + SetIrqHandler(device.InterruptLine, HandleNetworkInterrupt); + + Ports.OutB((ushort)(BaseAddress + 0xE0), 0x08); + + Reset(); + + // Get the MAC Address + byte[] eeprom_mac = new byte[6]; + for (uint b = 0; b < 6; b++) + { + eeprom_mac[b] = Ports.InB((ushort)(BaseAddress + b)); + } + + mac = new MACAddress(eeprom_mac); + + InitBuffers(); + + Ports.OutD((ushort)(BaseAddress + 0x44), 0x0000E70F); // Enable RX + + Ports.OutD((ushort)(BaseAddress + 0x37), 0x04); + + Ports.OutD((ushort)(BaseAddress + 0x40), 0x03000700); // Enable TX + + Ports.OutD((ushort)(BaseAddress + 0xDA), 2048); // Max rx packet size + + Ports.OutB((ushort)(BaseAddress + 0xEC), 0x3F); // No early transmit + + Ports.OutD((ushort)(BaseAddress + 0x20), mTxDescriptor.Offset); + Console.WriteLine("addresstx desc: " + mTxDescriptor.Offset); + + Ports.OutD((ushort)(BaseAddress + 0xE4), mRxDescriptor.Offset); + Console.WriteLine("addressrx desc: " + mRxDescriptor.Offset); + + if (((GetMacVersion() & 0x7cf00000) == 0x54100000) || ((GetMacVersion() & 0x7cf00000) == 0x54000000)) + { + Console.WriteLine("8168H Detected!"); + + Ports.OutD((ushort)(BaseAddress + 0x40), Ports.InD((ushort)(BaseAddress + 0x40)) | (1 << 7)); // AUTO TX FIFO + } + + Ports.OutW((ushort)(BaseAddress + 0x3C), 0xC3FF); //Activating all Interrupts + + Ports.OutB((ushort)(BaseAddress + 0x37), 0x0C); // Enabling receive and transmit + + //Console.WriteLine("Netcard version: 0x" + System.Utils.Conversion.DecToHex((int)GetMacVersion() & 0x7cf00000)); + //Console.WriteLine("Netcard version: 0x" + System.Utils.Conversion.DecToHex((int)GetMacVersion() & 0x7c800000)); + + } + + public bool Reset() + { + Ports.OutB((ushort)(BaseAddress + 0x37), 0x10); /* Send the Reset bit to the Command register */ + while ((Ports.InB((ushort)(BaseAddress + 0x37)) & 0x10) != 0) { } /* Wait for the chip to finish resetting */ + return true; + } + + protected void HandleNetworkInterrupt(ref IRQContext aContext) + { + + ushort status = Ports.InW((ushort)(BaseAddress + 0x3E)); + + if ((status & 0x0001) != 0) + { + ReadRawData(); + } + if ((status & 0x0002) != 0) Console.WriteLine("Receive error"); + if (((status & 0x0004) != 0) && ((status & 0x0080) != 0)) + { + } + else + { + if ((status & 0x0004) != 0) Console.WriteLine("Transmit succesfull - descriptor not resetted"); + //if ((status & 0x0080) != 0) Console.WriteLine("Transmit descriptor unavailable"); + } + if ((status & 0x0008) != 0) Console.WriteLine("Transmit error"); + if ((status & 0x0010) != 0) + { + Console.WriteLine("Receive descriptor unavailable"); + } + if ((status & 0x0020) != 0) + { + if ((Ports.InB((ushort)(BaseAddress + 0x6C)) & 0x02) != 0) + { + Console.WriteLine("\nLink is up with "); + if ((Ports.InB((ushort)(BaseAddress + 0x6C)) & 0x04) != 0) Console.WriteLine("10 Mbps and "); + if ((Ports.InB((ushort)(BaseAddress + 0x6C)) & 0x08) != 0) Console.WriteLine("100 Mbps and "); + if ((Ports.InB((ushort)(BaseAddress + 0x6C)) & 0x10) != 0) Console.WriteLine("1000 Mbps and "); + if ((Ports.InB((ushort)(BaseAddress + 0x6C)) & 0x01) != 0) Console.WriteLine("Full-duplex"); + else Console.WriteLine("Half-duplex"); + } + else + { + Console.WriteLine("\nLink is down!"); + } + } + if ((status & 0x0040) != 0) + { + Console.WriteLine("RX FIFO overflow!"); + if ((status & 0x0200) != 0) + { + Console.WriteLine("RX FIFO empty"); + } + } + if ((status & 0x0100) != 0) + { + Console.WriteLine("Software Interrupt"); + } + if ((status & 0x0200) != 0) + { + Console.WriteLine("RX FIFO empty"); + Ports.OutW((ushort)(BaseAddress + status), 0x0040); //https://groups.google.com/forum/#!topic/fa.linux.kernel/Vo8-9W3LoQs + } + if ((status & 0x0400) != 0) Console.WriteLine("Unknown Status (reserved Bit 11)"); + if ((status & 0x0800) != 0) Console.WriteLine("Unknown Status (reserved Bit 12)"); + if ((status & 0x1000) != 0) Console.WriteLine("Unknown Status (reserved Bit 13)"); + if ((status & 0x2000) != 0) Console.WriteLine("Unknown Status (reserved Bit 14)"); + if ((status & 0x4000) != 0) Console.WriteLine("Timeout"); + if ((status & 0x8000) != 0) Console.WriteLine("Unknown Status (reserved Bit 16)"); + + Ports.OutW((ushort)(BaseAddress + 0x3E), status); + + } + + #region Network Device Implementation + public override MACAddress MACAddress + { + get { return this.mac; } + } + + public override bool Enable() + { + return true; + } + + public override bool Ready + { + get { return true; } + } + + public override bool QueueBytes(byte[] buffer, int offset, int length) + { + byte[] data = new byte[length]; + for (int b = 0; b < length; b++) + { + data[b] = buffer[b + offset]; + } + + if (SendBytes(ref data) == false) + { + mTransmitBuffer.Enqueue(data); + } + + return true; + } + + public override bool ReceiveBytes(byte[] buffer, int offset, int max) + { + throw new NotImplementedException(); + } + + public override byte[] ReceivePacket() + { + return new byte[] { }; + } + + public override int BytesAvailable() + { + return 0; + } + + public override bool IsSendBufferFull() + { + return false; + } + + public override bool IsReceiveBufferFull() + { + return false; + } + + protected bool SendBytes(ref byte[] aData) + { + if (aData.Length > 2048) + return false; // Splitting packets not yet supported + + uint xOffset = (uint)(mNextTXDesc * 16); + + if ((mTxDescriptor.Read32(xOffset + 0) & (1 << 31)) != 0) + { + Console.WriteLine("The Tx buffer is busy"); + return false; + } + + for (uint b = 0; b < aData.Length; b++) + { + mTxBuffers[mNextTXDesc][b] = aData[b]; + } + + mTxDescriptor.Write32(xOffset + 0, OWN | mTxDescriptor.Read32(xOffset + 0) & EOR | (uint)(aData.Length & 0x3FFF) | (1 << 29) | (1 << 28)); + + mTxDescriptor.Write32(xOffset + 4, 0); + + Ports.OutB((ushort)(BaseAddress + 0x38), 1 << 6); + + mNextTXDesc++; + mNextTXDesc %= 32; + + return true; + + } + + private void ReadRawData() + { + for (ushort i = 0; i < 32; i++) + { + uint xOffset = (uint)(i * 16); + if ((mRxDescriptor.Read32(xOffset) & 0x80000000) == 0) + { + uint length = mRxDescriptor.Read32(xOffset + 0) & 0x3FFF; + if (length > 4) + { + + byte[] recv_data = new byte[length - 4]; + for (uint b = 0; b < length; b++) + { + recv_data[b] = mRxBuffers[i][b]; + } + + if (DataReceived != null) + { + DataReceived(recv_data); + } + else + { + mRecvBuffer.Enqueue(recv_data); + } + + } + + // Reset descriptor + if (i == (32 - 1)) // Last descriptor? if so, set the EOR bit + mRxDescriptor.Write32(xOffset + 0, OWN | EOR | (2048 & 0x3FFF)); + else + mRxDescriptor.Write32(xOffset + 0, OWN | (2048 & 0x3FFF)); + mRxDescriptor.Write32(xOffset + 4, 0); + } + } + } + + #endregion + + } +} diff --git a/source/Cosmos.HAL2/Network/NetworkInit.cs b/source/Cosmos.HAL2/Network/NetworkInit.cs index 607bfd6566..7135a7f6c9 100644 --- a/source/Cosmos.HAL2/Network/NetworkInit.cs +++ b/source/Cosmos.HAL2/Network/NetworkInit.cs @@ -54,6 +54,24 @@ public static void Init() } #endregion + + #region RTL8168 + + if (device.VendorID == 0x10EC && device.DeviceID == 0x8168) + { + + Console.WriteLine("NIC IRQ: " + device.InterruptLine); + + var RTL8168Device = new RTL8168(device); + + RTL8168Device.NameID = ("eth" + NetworkDeviceID); + + Console.WriteLine("Registered at " + RTL8168Device.NameID + " (" + RTL8168Device.MACAddress.ToString() + ")"); + + RTL8168Device.Enable(); + } + #endregion + #region E1000 if (device.VendorID == 0x8086) @@ -122,8 +140,7 @@ public static void Init() device.DeviceID == (ushort)E1000DeviceID.Intel82562GT_ICH8 || device.DeviceID == (ushort)E1000DeviceID.Intel82562G_ICH8 || device.DeviceID == (ushort)E1000DeviceID.Intel82576 || - device.DeviceID == (ushort)E1000DeviceID.Intel82574L || - device.DeviceID == (ushort)E1000DeviceID.Intel82575_quadcopper || + device.DeviceID == (ushort)E1000DeviceID.Intel82574L || device.DeviceID == (ushort)E1000DeviceID.Intel82575_quadcopper || device.DeviceID == (ushort)E1000DeviceID.Intel82567V_ICH9 || device.DeviceID == (ushort)E1000DeviceID.Intel82567LM_4_ICH9 || device.DeviceID == (ushort)E1000DeviceID.Intel82577LM || @@ -163,8 +180,8 @@ public static void Init() NetworkDeviceID++; } - } + } #endregion } }