mirror of
https://github.com/danbulant/Cosmos
synced 2026-05-19 12:30:32 +00:00
337 lines
11 KiB
C#
337 lines
11 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using Cosmos.Common;
|
|
using Cosmos.Core;
|
|
using Cosmos.Core.IOGroup.Network;
|
|
using Cosmos.HAL.Network;
|
|
using CompilerPlugs = Cosmos.IL2CPU.Plugs;
|
|
|
|
namespace Cosmos.HAL.Drivers.PCI.Network
|
|
{
|
|
public class AMDPCNetII : NetworkDevice
|
|
{
|
|
protected PCIDeviceNormal pciCard;
|
|
protected AMDPCNetIIIOGroup io;
|
|
protected MACAddress mac;
|
|
protected bool mInitDone;
|
|
|
|
protected ManagedMemoryBlock mInitBlock;
|
|
protected ManagedMemoryBlock mRxDescriptor;
|
|
protected ManagedMemoryBlock mTxDescriptor;
|
|
protected List<ManagedMemoryBlock> mRxBuffers;
|
|
protected List<ManagedMemoryBlock> mTxBuffers;
|
|
protected Queue<byte[]> mRecvBuffer;
|
|
protected Queue<byte[]> mTransmitBuffer;
|
|
private int mNextTXDesc;
|
|
|
|
public AMDPCNetII(PCIDeviceNormal device)
|
|
: base()
|
|
{
|
|
if (device == null)
|
|
{
|
|
throw new ArgumentException("PCI Device is null. Unable to get AMD PCNet card");
|
|
}
|
|
|
|
this.pciCard = device;
|
|
this.pciCard.Claimed = true;
|
|
this.pciCard.EnableDevice();
|
|
|
|
this.io = new AMDPCNetIIIOGroup((ushort)this.pciCard.BaseAddresses[0].BaseAddress());
|
|
this.io.RegisterData.DWord = 0;
|
|
|
|
// Get the EEPROM MAC Address and set it as the devices MAC
|
|
byte[] eeprom_mac = new byte[6];
|
|
UInt32 result = io.MAC1.DWord;
|
|
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.MAC2.DWord;
|
|
eeprom_mac[4] = BinaryHelper.GetByteFrom32bit(result, 0);
|
|
eeprom_mac[5] = BinaryHelper.GetByteFrom32bit(result, 8);
|
|
|
|
mac = new MACAddress(eeprom_mac);
|
|
|
|
mInitBlock = new ManagedMemoryBlock(28, 4);
|
|
mRxDescriptor = new ManagedMemoryBlock(256, 16);
|
|
mTxDescriptor = new ManagedMemoryBlock(256, 16);
|
|
|
|
mInitBlock.Write32(0x00, (0x4 << 28) | (0x4 << 20));
|
|
mInitBlock.Write32(0x04, (UInt32)(eeprom_mac[0] | (eeprom_mac[1] << 8) | (eeprom_mac[2] << 16) | (eeprom_mac[3] << 24)));
|
|
mInitBlock.Write32(0x08, (UInt32)(eeprom_mac[4] | (eeprom_mac[5] << 8)));
|
|
mInitBlock.Write32(0x0C, 0x0);
|
|
mInitBlock.Write32(0x10, 0x0);
|
|
mInitBlock.Write32(0x14, mRxDescriptor.Offset);
|
|
mInitBlock.Write32(0x18, mTxDescriptor.Offset);
|
|
|
|
InitializationBlockAddress = mInitBlock.Offset;
|
|
SoftwareStyleRegister = 0x03;
|
|
|
|
mRxBuffers = new List<ManagedMemoryBlock>();
|
|
mTxBuffers = new List<ManagedMemoryBlock>();
|
|
for (uint rxd = 0; rxd < 16; rxd++)
|
|
{
|
|
uint xOffset = rxd * 16;
|
|
|
|
ManagedMemoryBlock buffer = new ManagedMemoryBlock(2048);
|
|
mRxDescriptor.Write32(xOffset + 8, buffer.Offset);
|
|
UInt16 buffer_len = (UInt16)(~buffer.Size);
|
|
buffer_len++;
|
|
UInt32 flags = (UInt32)(buffer_len & 0x0FFF) | 0xF000 | 0x80000000;
|
|
mRxDescriptor.Write32(xOffset + 4, flags);
|
|
mRxBuffers.Add(buffer);
|
|
}
|
|
for (uint txd = 0; txd < 16; txd++)
|
|
{
|
|
uint xOffset = txd * 16;
|
|
|
|
ManagedMemoryBlock buffer = new ManagedMemoryBlock(2048);
|
|
mTxDescriptor.Write32(xOffset + 8, buffer.Offset);
|
|
mTxBuffers.Add(buffer);
|
|
}
|
|
|
|
mNextTXDesc = 0;
|
|
|
|
// Setup our Receive and Transmit Queues
|
|
mTransmitBuffer = new Queue<byte[]>();
|
|
mRecvBuffer = new Queue<byte[]>();
|
|
|
|
INTs.SetIrqHandler(device.InterruptLine, HandleNetworkInterrupt);
|
|
}
|
|
|
|
protected void HandleNetworkInterrupt(ref INTs.IRQContext aContext)
|
|
{
|
|
UInt32 cur_status = StatusRegister;
|
|
|
|
//Console.WriteLine("AMD PCNet IRQ raised!");
|
|
if ((cur_status & 0x100) != 0)
|
|
{
|
|
mInitDone = true;
|
|
}
|
|
if ((cur_status & 0x200) != 0)
|
|
{
|
|
if (mTransmitBuffer.Count > 0)
|
|
{
|
|
byte[] data = mTransmitBuffer.Peek();
|
|
if (SendBytes(ref data) == true)
|
|
{
|
|
mTransmitBuffer.Dequeue();
|
|
}
|
|
}
|
|
}
|
|
if ((cur_status & 0x400) != 0)
|
|
{
|
|
ReadRawData();
|
|
}
|
|
|
|
StatusRegister = cur_status;
|
|
Cosmos.Core.Global.PIC.EoiSlave();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Retrieve all AMD PCNetII network cards found on computer.
|
|
/// </summary>
|
|
public static void FindAll()
|
|
{
|
|
Console.WriteLine("Scanning for AMD PCNetII cards...");
|
|
PCIDevice device = Cosmos.HAL.PCI.GetDevice(0x1022, 0x2000);
|
|
if (device != null)
|
|
{
|
|
AMDPCNetII nic = new AMDPCNetII((PCIDeviceNormal)device);
|
|
|
|
Console.WriteLine("Found AMD PCNetII NIC on PCI " + device.bus + ":" + device.slot + ":" + device.function);
|
|
Console.WriteLine("NIC IRQ: " + device.InterruptLine);
|
|
Console.WriteLine("NIC MAC Address: " + nic.MACAddress.ToString());
|
|
}
|
|
}
|
|
|
|
#region Register Access Properties
|
|
protected UInt32 StatusRegister
|
|
{
|
|
get
|
|
{
|
|
io.RegisterAddress.DWord = 0x00;
|
|
return io.RegisterData.DWord;
|
|
}
|
|
set
|
|
{
|
|
io.RegisterAddress.DWord = 0x00;
|
|
io.RegisterData.DWord = value;
|
|
}
|
|
}
|
|
protected UInt32 InitializationBlockAddress
|
|
{
|
|
get
|
|
{
|
|
UInt32 result;
|
|
|
|
io.RegisterAddress.DWord = 0x01;
|
|
result = io.RegisterData.DWord;
|
|
io.RegisterAddress.DWord = 0x02;
|
|
result |= (io.RegisterData.DWord << 16);
|
|
|
|
return result;
|
|
}
|
|
set
|
|
{
|
|
io.RegisterAddress.DWord = 0x01;
|
|
io.RegisterData.DWord = (value & 0xFFFF);
|
|
io.RegisterAddress.DWord = 0x02;
|
|
io.RegisterData.DWord = (value >> 16);
|
|
}
|
|
}
|
|
protected UInt32 SoftwareStyleRegister
|
|
{
|
|
get
|
|
{
|
|
io.RegisterAddress.DWord = 0x14;
|
|
return io.BusData.DWord;
|
|
}
|
|
set
|
|
{
|
|
io.RegisterAddress.DWord = 0x14;
|
|
io.BusData.DWord = value;
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region Network Device Implementation
|
|
public override MACAddress MACAddress
|
|
{
|
|
get { return mac; }
|
|
}
|
|
|
|
public override bool Ready
|
|
{
|
|
get { return mInitDone; }
|
|
}
|
|
|
|
public override bool Enable()
|
|
{
|
|
StatusRegister = 0x43;
|
|
|
|
return true;
|
|
}
|
|
|
|
[CompilerPlugs.DebugStub(Off = 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()
|
|
{
|
|
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;
|
|
}
|
|
#endregion
|
|
|
|
#region Helper Functions
|
|
[CompilerPlugs.DebugStub(Off = true)]
|
|
protected bool SendBytes(ref byte[] aData)
|
|
{
|
|
int txd = mNextTXDesc++;
|
|
if (mNextTXDesc >= 16)
|
|
{
|
|
mNextTXDesc = 0;
|
|
}
|
|
|
|
uint xOffset = (uint)(txd * 16);
|
|
UInt32 status = mTxDescriptor.Read32(xOffset + 4);
|
|
if ((status & 0x80000000) == 0)
|
|
{
|
|
for (uint b = 0; b < aData.Length; b++)
|
|
{
|
|
mTxBuffers[txd][b] = aData[b];
|
|
}
|
|
//UInt16 buffer_len = (UInt16)(aData.Length < 64 ? 64 : aData.Length);
|
|
UInt16 buffer_len = (UInt16)aData.Length;
|
|
buffer_len = (UInt16)(~buffer_len);
|
|
buffer_len++;
|
|
|
|
UInt32 flags = (UInt32)((buffer_len) & 0x0FFF) | 0x0300F000 | 0x80000000;
|
|
|
|
mTxDescriptor.Write32(xOffset + 4, flags);
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
[CompilerPlugs.DebugStub(Off = true)]
|
|
private void ReadRawData()
|
|
{
|
|
uint status;
|
|
UInt16 recv_size;
|
|
byte[] recv_data;
|
|
|
|
for (int rxd = 0; rxd < 16; rxd++)
|
|
{
|
|
uint xOffset = (uint)(rxd * 16);
|
|
status = mRxDescriptor.Read32(xOffset + 4);
|
|
if ((status & 0x80000000) == 0)
|
|
{
|
|
recv_size = (UInt16)(mRxDescriptor[xOffset + 0] & 0xFFF);
|
|
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);
|
|
}
|
|
|
|
mRxDescriptor.Write32(xOffset + 4, status | 0x80000000);
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
}
|
|
}
|