Cosmos/source/MatthijsTest/MyATAController.cs
mterwoord_cp 2161a9fb06
2010-02-17 10:04:52 +00:00

328 lines
9.4 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Cosmos.Hardware;
using Cosmos.Kernel;
namespace MatthijsTest
{
public class MyATAController : Device
{
private const ushort PrimaryControllerBaseAddress = 0x1F0;
public static void Scan()
{
var xController = new MyATAController(PrimaryControllerBaseAddress);
xController.Identify(true);
xController.Identify(false);
Device.Devices.Add(xController);
}
private void Identify(bool masterDrive)
{
// Select the drive to identify
DriveSelectPort = (byte)(masterDrive ? 0xA0 : 0xB0);
// read status
var xStatus = StatusPort;
xStatus = StatusPort;
xStatus = StatusPort;
xStatus = StatusPort;
xStatus = StatusPort;
CommandPort = CommandEnum.Identify;
if (StatusPort == RegularStatusFlagsEnum.None)
{
return;
}
var xError = false;
var xReady = false;
while (true)
{
xStatus = StatusPort;
if (xStatus.HasFlags(RegularStatusFlagsEnum.Error))
{
xError = true;
break;
}
if (xStatus.HasFlags(RegularStatusFlagsEnum.DataRequest)
& !xStatus.HasFlags(RegularStatusFlagsEnum.Busy))
{
xReady = true;
break;
}
}
if (xError)
{
// preliminary abort, means it's ATAPI or SATA
// todo: implement support for SATA and ATAPI detection
return;
}
if (!xReady)
{
Console.WriteLine("Weird error. Situation not handled in ATAController.Identify!");
while (true)
;
}
// not busy anymore.
var xName = masterDrive
? "Master drive"
: "Slave drive";
var xDevice = new MyATADevice(this, xName, masterDrive);
Devices.Add(xDevice);
if (masterDrive)
{
HasMasterDevice = true;
}
else
{
HasSlaveDevice = true;
}
}
private MyATAController(ushort baseAddress)
{
mType = DeviceType.Storage;
mAddressSpace = new IOAddressSpace(baseAddress, 8);
}
private IOAddressSpace mAddressSpace;
#region IO Ports
private ushort DataPort_Word
{
get
{
return mAddressSpace.Read16(0);
}
set
{
mAddressSpace.Write16(0, value);
}
}
private byte SectorCountPort
{
set
{
mAddressSpace.Write8(2, value);
}
}
private byte SectorAddress1Port
{
set
{
mAddressSpace.Write8(3, value);
}
}
private byte SectorAddress2Port
{
set
{
mAddressSpace.Write8(4, value);
}
}
private byte SectorAddress3Port
{
set
{
mAddressSpace.Write8(5, value);
}
}
private RegularStatusFlagsEnum StatusPort
{
get
{
return (RegularStatusFlagsEnum)mAddressSpace.Read8(7);
}
}
private CommandEnum CommandPort
{
set
{
mAddressSpace.Write8(7, (byte)value);
}
}
private byte DriveSelectPort
{
get
{
return mAddressSpace.Read8(6);
}
set
{
mAddressSpace.Write8(6, value);
}
}
#endregion
public bool HasMasterDevice
{
get;
private set;
}
public bool HasSlaveDevice
{
get;
private set;
}
public override string Name
{
get
{
return "ATA Storage Controller";
}
}
#region PIO
internal void RealReadBlock_PIO(AddressSpace target)
{
for (uint i = 0; i < 256; i++)
{
target.Write16(i * 2, DataPort_Word);
}
}
internal void RealWriteBlock_PIO(byte[] source)
{
for (uint i = 0; i < 256; i++)
{
DataPort_Word = (ushort)(source[i *2] | (source[(i*2)+1] << 8));
}
}
internal void RealWriteBlock_PIO(AddressSpace source)
{
for (uint i = 0; i < 256; i++)
{
DataPort_Word = source.Read16Unchecked(i * 2);
}
}
internal void ReadSector_LBA28(bool masterDrive, uint block, AddressSpace target)
{
var xDriveSelect = (byte)0xE0;
if (!masterDrive)
{
xDriveSelect = 0xF0;
}
DriveSelectPort = (byte)(xDriveSelect | ((block >> 24) & 0xF));
SectorCountPort = 1;
SectorAddress1Port = (byte)block;
SectorAddress2Port = (byte)(block >> 8);
SectorAddress3Port = (byte)(block >> 16);
CommandPort = CommandEnum.ReadSectors;
bool xPoll = true;
bool xError = false;
do
{
var xStatus = StatusPort;
if ((!xStatus.HasFlags(RegularStatusFlagsEnum.Busy))
&& xStatus.HasFlags(RegularStatusFlagsEnum.DataRequest))
{
xPoll = false;
}
if (xStatus.HasFlags(RegularStatusFlagsEnum.Error)
|| xStatus.HasFlags(RegularStatusFlagsEnum.DriveFault))
{
xPoll = false;
xError = true;
}
}
while (xPoll);
if (xError)
{
throw new Exception("Error while reading sector!");
}
RealReadBlock_PIO(target);
}
internal void WriteSector_LBA28(bool masterDrive, uint block, byte[] source)
{
var xDriveSelect = (byte)0xE0;
if (!masterDrive)
{
xDriveSelect = 0xF0;
}
DriveSelectPort = (byte)(xDriveSelect | ((block >> 24) & 0xF));
SectorCountPort = 1;
SectorAddress1Port = (byte)block;
SectorAddress2Port = (byte)(block >> 8);
SectorAddress3Port = (byte)(block >> 16);
CommandPort = CommandEnum.WriteSectors;
bool xPoll = true;
bool xError = false;
do
{
var xStatus = StatusPort;
if ((!xStatus.HasFlags(RegularStatusFlagsEnum.Busy))
&& xStatus.HasFlags(RegularStatusFlagsEnum.DataRequest))
{
xPoll = false;
}
if (xStatus.HasFlags(RegularStatusFlagsEnum.Error)
|| xStatus.HasFlags(RegularStatusFlagsEnum.DriveFault))
{
xPoll = false;
xError = true;
}
}
while (xPoll);
if (xError)
{
throw new Exception("Error while writing sector!");
}
RealWriteBlock_PIO(source);
}
internal void WriteSector_LBA28(bool masterDrive, uint block, AddressSpace source)
{
var xDriveSelect = (byte)0xE0;
if (!masterDrive)
{
xDriveSelect = 0xF0;
}
DriveSelectPort = (byte)(xDriveSelect | ((block >> 24) & 0xF));
SectorCountPort = 1;
SectorAddress1Port = (byte)block;
SectorAddress2Port = (byte)(block >> 8);
SectorAddress3Port = (byte)(block >> 16);
CommandPort = CommandEnum.WriteSectors;
bool xPoll = true;
bool xError = false;
do
{
var xStatus = StatusPort;
if ((!xStatus.HasFlags(RegularStatusFlagsEnum.Busy))
&& xStatus.HasFlags(RegularStatusFlagsEnum.DataRequest))
{
xPoll = false;
}
if (xStatus.HasFlags(RegularStatusFlagsEnum.Error)
|| xStatus.HasFlags(RegularStatusFlagsEnum.DriveFault))
{
xPoll = false;
xError = true;
}
}
while (xPoll);
if (xError)
{
throw new Exception("Error while writing sector!");
}
RealWriteBlock_PIO(source);
}
#endregion
}
}