Cosmos/source/Archive/Cosmos.Hardware/Network/Devices/ViaRhine/VT6102.cs

338 lines
10 KiB
C#

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<ManagedMemorySpace> mRxBuffers;
private ManagedMemorySpace mRxDescriptors;
private ManagedMemorySpace mTxDescriptors;
protected Queue<byte[]> mRecvBuffer;
protected Queue<byte[]> 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<ManagedMemorySpace>();
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<byte[]>();
mRecvBuffer = new Queue<byte[]>();
}
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);
}
/// <summary>
/// Retrieve all VIA Rhine-II network cards found on computer.
/// </summary>
/// <returns>List of all VIA Rhine-II cards</returns>
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
}
}