using System; using System.Collections.Generic; using System.Text; using Cosmos.Kernel; namespace Cosmos.Hardware2.Network.Devices.ViaRhine { public class VT6102 : NetworkDevice { protected PCIDevice pciCard; protected IOAddressSpace io; protected MACAddress mac; protected List mRxBuffers; private ManagedMemorySpace mRxDescriptors; private ManagedMemorySpace mTxDescriptors; protected Queue mRecvBuffer; protected Queue mTransmitBuffer; private int mNextTXDesc; public VT6102(PCIDevice device) { if (device == null) { throw new ArgumentException("PCI Device is null. Unable to get VIA Rhine-II card"); } pciCard = device; // We are handling this device pciCard.Claimed = true; // Setup interrupt handling //Interrupts.IRQ10 += HandleNetworkInterrupt; //Interrupts.AddIRQHandler(device.InterruptLine, HandleNetworkInterrupt); // Get IO Address from PCI Bus io = pciCard.GetAddressSpace(0) as Kernel.IOAddressSpace; // Enable the card pciCard.EnableDevice(); // Get the EEPROM MAC Address and set it as the devices MAC byte[] eeprom_mac = new byte[6]; UInt32 result = io.Read32(0x00); eeprom_mac[0] = BinaryHelper.GetByteFrom32bit(result, 0); eeprom_mac[1] = BinaryHelper.GetByteFrom32bit(result, 8); eeprom_mac[2] = BinaryHelper.GetByteFrom32bit(result, 16); eeprom_mac[3] = BinaryHelper.GetByteFrom32bit(result, 24); result = io.Read32(0x04); eeprom_mac[4] = BinaryHelper.GetByteFrom32bit(result, 0); eeprom_mac[5] = BinaryHelper.GetByteFrom32bit(result, 8); mac = new MACAddress(eeprom_mac); // Software Reset device SoftwareReset(); // Configure Receive Config ReceiveConfigRegister = 0x1C; // Configure Transmit Config TransmitConfigRegister = 0x04; // Setup RX Descriptors mRxDescriptors = new ManagedMemorySpace(256, 16); // Setup TX Descriptors mTxDescriptors = new ManagedMemorySpace(256, 16); /* Initialize the RX and TX buffers, and set up the RX descriptors to point to the buffers. Also, mark the RX descriptors as being owned by the card so data can be received in them */ mRxBuffers = new List(); for (uint rxd = 0; rxd < 16; rxd++) { uint xOffset = rxd * 16; ManagedMemorySpace buffer = new ManagedMemorySpace(2048); mRxDescriptors.Write32(xOffset + 12, mRxDescriptors.Offset + xOffset + 16); mRxDescriptors.Write32(xOffset + 8, buffer.Offset); mRxDescriptors.Write32(xOffset + 4, buffer.Size); mRxDescriptors.Write32(xOffset, 0x80000000); mRxBuffers.Add(buffer); } mRxDescriptors.Write32(252, mRxDescriptors.Offset); for (uint txd = 0; txd < 16; txd++) { uint xOffset = txd * 16; mTxDescriptors.Write32(xOffset + 12, mTxDescriptors.Offset + xOffset + 16); mTxDescriptors.Write32(xOffset + 8, 0); mTxDescriptors.Write32(xOffset + 4, 0); mTxDescriptors.Write32(xOffset, 0); } mTxDescriptors.Write32(252, mTxDescriptors.Offset); mNextTXDesc = 0; RxDescAddressRegister = mRxDescriptors.Offset; TxDescAddressRegister = mTxDescriptors.Offset; // Setup and clear interrupts IntMaskRegister = 0xFFFF; IntStatusRegister = 0xFFFF; // Setup our Receive and Transmit Queues mTransmitBuffer = new Queue(); mRecvBuffer = new Queue(); } private void SoftwareReset() { io.Write16(0x08, 0x8000); while ((io.Read16(0x08) & 0x8000) != 0) { // Wait for device to reset } } public static void InitDriver() { Device.AddDriverInit(FindAll); } /// /// Retrieve all VIA Rhine-II network cards found on computer. /// /// List of all VIA Rhine-II cards public static void FindAll() { Console.WriteLine("Scanning for VIA Rhine-II cards..."); foreach (PCIDevice device in Cosmos.Hardware2.PCIBus.Devices) { if ((device.VendorID == 0x1106) && (device.DeviceID == 0x3065) && (device.Claimed == false)) { VT6102 nic = new VT6102(device); Console.WriteLine("Found VIA Rhine-II NIC on PCI " + device.Bus + ":" + device.Slot + ":" + device.Function); Console.WriteLine("NIC IRQ: " + device.InterruptLine); Console.WriteLine("NIC MAC Address: " + nic.MACAddress.ToString()); NetworkDevice.Add(nic); } } } //protected void HandleNetworkInterrupt(ref IRQContext aContext) //{ // UInt16 cur_status = IntStatusRegister; // if ((cur_status & 0x01) != 0) // { // ReadRawData(); // } // IntStatusRegister = cur_status; //} #region Register Access protected UInt16 CommandRegister { get { return io.Read16(0x08); } set { io.Write16(0x08, value); } } protected UInt16 IntStatusRegister { get { return io.Read16(0x0C); } set { io.Write16(0x0C, value); } } protected UInt16 IntMaskRegister { get { return io.Read16(0x0E); } set { io.Write16(0x0E, value); } } protected byte ReceiveConfigRegister { get { return io.Read8(0x06); } set { io.Write8(0x06, value); } } protected byte TransmitConfigRegister { get { return io.Read8(0x07); } set { io.Write8(0x07, value); } } protected UInt32 RxDescAddressRegister { get { return io.Read32(0x18); } set { io.Write32(0x18, value); } } protected UInt32 TxDescAddressRegister { get { return io.Read32(0x1C); } set { io.Write32(0x1C, value); } } #endregion #region Network Device Implementation public override MACAddress MACAddress { get { return this.mac; } } public override bool Enable() { // Set start,rxon and txon bit on card CommandRegister = 0x1A; return base.Enable(); } public override bool Ready { get { return ((CommandRegister & 0x02) != 0); } } 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() { if (mRecvBuffer.Count < 1) { return null; } byte[] data = mRecvBuffer.Dequeue(); return data; } public override int BytesAvailable() { if (mRecvBuffer.Count < 1) { return 0; } return mRecvBuffer.Peek().Length; } public override bool IsSendBufferFull() { return false; } public override bool IsReceiveBufferFull() { return false; } public override string Name { get { return "VIA Rhine-II Ethernet Adapter"; } } #endregion #region Helper Functions protected bool SendBytes(ref byte[] aData) { int txd = mNextTXDesc++; if (mNextTXDesc >= 16) { mNextTXDesc = 0; } uint xOffset = (uint)(txd * 16); UInt32 status = mTxDescriptors.Read32(xOffset); ManagedMemorySpace txBuffer = new ManagedMemorySpace(aData); if (((txBuffer.Offset % 4) != 0) || (txBuffer.Size < 64) ) { txBuffer = new ManagedMemorySpace((uint)(aData.Length < 64 ? 64 : aData.Length), 4); for (uint b = 0; b < aData.Length; b++) { txBuffer[b] = aData[b]; } } if ((status & 0x80000000) == 0) { mTxDescriptors.Write32(xOffset + 8, txBuffer.Offset); mTxDescriptors.Write32(xOffset + 4, txBuffer.Size | 0x600000 ); mTxDescriptors.Write32(xOffset, status | 0x80000000); return true; } return false; } private void ReadRawData() { uint status; UInt16 recv_size; byte[] recv_data; for (int rxd = 0; rxd < 16; rxd++) { uint xOffset = (uint)(rxd * 16); status = mRxDescriptors.Read32(xOffset); if ((status & 0x80000000) == 0) { recv_size = (UInt16)((status & 0xFFFF0000) >> 16); recv_data = new byte[recv_size]; for (uint b = 0; b < recv_size; b++) { recv_data[b] = mRxBuffers[rxd][b]; } if (DataReceived != null) { DataReceived(recv_data); } else { mRecvBuffer.Enqueue(recv_data); } mRxDescriptors.Write32(xOffset, status | 0x80000000); } } } #endregion } }