ide rework again
This commit is contained in:
parent
f0d5eb21f1
commit
837d69a44b
@ -1,17 +1,9 @@
|
|||||||
{ ************************************************
|
unit ide;
|
||||||
* Asuro
|
|
||||||
* Unit: Drivers/storage/IDE
|
|
||||||
* Description: IDE ATA Driver
|
|
||||||
*
|
|
||||||
************************************************
|
|
||||||
* Author: Aaron Hance
|
|
||||||
* Contributors:
|
|
||||||
************************************************ }
|
|
||||||
unit IDE;
|
|
||||||
|
|
||||||
interface
|
interface
|
||||||
|
|
||||||
uses
|
uses
|
||||||
|
ata,
|
||||||
util,
|
util,
|
||||||
drivertypes,
|
drivertypes,
|
||||||
console,
|
console,
|
||||||
@ -23,226 +15,324 @@ uses
|
|||||||
strings,
|
strings,
|
||||||
tracer,
|
tracer,
|
||||||
drivemanager,
|
drivemanager,
|
||||||
storagetypes;
|
storagetypes,
|
||||||
|
idetypes;
|
||||||
|
|
||||||
type
|
|
||||||
TPortMode = (P_READ, P_WRITE);
|
|
||||||
|
|
||||||
TIdentResponse = array[0..255] of uint16;
|
|
||||||
|
|
||||||
TIDE_Channel_Registers = record
|
|
||||||
base : uint16;
|
|
||||||
ctrl : uint16;
|
|
||||||
bmide : uint16;
|
|
||||||
noInter : uint8
|
|
||||||
end;
|
|
||||||
|
|
||||||
TIDE_Device = record
|
|
||||||
exists : boolean;
|
|
||||||
isPrimary : boolean;
|
|
||||||
isMaster : boolean;
|
|
||||||
isATAPI : boolean;
|
|
||||||
info : TIdentResponse;
|
|
||||||
end;
|
|
||||||
|
|
||||||
TIDE_Status = bitpacked record
|
|
||||||
Busy : Boolean;
|
|
||||||
Ready : Boolean;
|
|
||||||
Fault : Boolean;
|
|
||||||
Seek : Boolean;
|
|
||||||
DRQ : Boolean;
|
|
||||||
CORR : Boolean;
|
|
||||||
IDDEX : Boolean;
|
|
||||||
ERROR : Boolean;
|
|
||||||
end;
|
|
||||||
PIDE_Status = ^TIDE_Status;
|
|
||||||
|
|
||||||
|
|
||||||
const
|
|
||||||
ATA_SR_BUSY = $80; //BUSY
|
|
||||||
ATA_SR_DRDY = $40; //DRIVE READY
|
|
||||||
ATA_SR_DF = $20; //DRIVE WRITE FAULT
|
|
||||||
ATA_SR_DSC = $10; //DRIVE SEEK COMPLETE
|
|
||||||
ATA_SR_DRQ = $08; //DATA REQUEST READY
|
|
||||||
ATA_SR_CORR = $04; //CORRECTED DATA
|
|
||||||
ATA_SR_IDX = $02; //INLEX
|
|
||||||
ATA_SR_ERR = $01; //ERROR
|
|
||||||
|
|
||||||
ATA_ER_BBK = $80; //BAD SECTOR
|
|
||||||
ATA_ER_UNC = $40; //UNCORRECTABLE DATA
|
|
||||||
ATA_ER_MC = $20; //NO MEDIA
|
|
||||||
ATA_ER_IDNF = $10; //ID MARK NOT FOUND
|
|
||||||
ATA_ER_MCR = $08; //NO MEDIA
|
|
||||||
ATA_ER_ABRT = $04; //COMMAND ABORTED
|
|
||||||
ATA_ER_TK0NF = $02; //TRACK 0 NOT FOUND
|
|
||||||
ATA_ER_AMNF = $01; //NO ADDRESS MARK
|
|
||||||
|
|
||||||
ATA_CMD_READ_PIO = $20;
|
|
||||||
ATA_CMD_READ_PIO_EXT = $24;
|
|
||||||
ATA_CMD_READ_DMA = $C8;
|
|
||||||
ATA_CMD_READ_DMA_EXT = $25;
|
|
||||||
ATA_CMD_WRITE_PIO = $30;
|
|
||||||
ATA_CMD_WRITE_PIO_EXT = $34;
|
|
||||||
ATA_CMD_WRITE_DMA = $CA;
|
|
||||||
ATA_CMD_WRITE_DMA_EXT = $35;
|
|
||||||
ATA_CMD_CACHE_FLUSH = $E7;
|
|
||||||
ATA_CMD_CACHE_FLUSH_EXT = $EA;
|
|
||||||
ATA_CMD_PACKET = $A0;
|
|
||||||
ATA_CMD_IDENTIFY_PACKET = $A1;
|
|
||||||
ATA_CMD_IDENTIFY = $EC;
|
|
||||||
|
|
||||||
ATAPI_CMD_READ = $A8;
|
|
||||||
ATAPI_CMD_EJECT = $1B;
|
|
||||||
|
|
||||||
ATA_IDENT_DEVICETYPE = $0;
|
|
||||||
ATA_IDENT_CYLINDERS = $2;
|
|
||||||
ATA_IDENT_HEADS = $6;
|
|
||||||
ATA_IDENT_SECOTRS = $12;
|
|
||||||
ATA_IDENT_SERIAL = $20;
|
|
||||||
ATA_IDENT_MODEL = $54;
|
|
||||||
ATA_IDENT_CAPABILITIES = $98;
|
|
||||||
ATA_IDENT_FIELDVALID = $106;
|
|
||||||
ATA_IDENT_MAX_LBA = $120;
|
|
||||||
ATA_IDENT_COMMANDSETS = $164;
|
|
||||||
ATA_IDENT_MAX_LBA_EXT = $200;
|
|
||||||
|
|
||||||
ATA_REG_DATA = $00;
|
|
||||||
ATA_REG_ERROR = $01;
|
|
||||||
ATA_REG_FEATURES = $01;
|
|
||||||
ATA_REG_SECCOUNT = $02;
|
|
||||||
ATA_REG_LBA0 = $03;
|
|
||||||
ATA_REG_LBA1 = $04;
|
|
||||||
ATA_REG_LBA2 = $05;
|
|
||||||
ATA_REG_HDDEVSEL = $06;
|
|
||||||
ATA_REG_COMMAND = $07;
|
|
||||||
ATA_REG_STATUS = $07;
|
|
||||||
ATA_REG_SECCOUNT1 = $08;
|
|
||||||
ATA_REG_LBA3 = $09;
|
|
||||||
ATA_REG_LBA4 = $0A;
|
|
||||||
ATA_REG_LBA5 = $0B;
|
|
||||||
ATA_REG_CONTROL = $0C;
|
|
||||||
ATA_REG_ALTSTATUS = $0C;
|
|
||||||
ATA_REG_DEVADDRESS = $0D;
|
|
||||||
|
|
||||||
ATA_DEVICE_MASTER = $A0;
|
|
||||||
ATA_DEVICE_SLAVE = $B0;
|
|
||||||
|
|
||||||
ATA_PRIMARY_BASE = $1F0;
|
|
||||||
|
|
||||||
var
|
var
|
||||||
controller : PPCI_Device;
|
primaryDevices: array[0..1] of TIDE_Device = (
|
||||||
|
(exists: false; isPrimary: true; isMaster: true; isATAPI: false;
|
||||||
|
status: (Busy: false; Ready: false; Fault: false; Seek: false; DRQ: false; CORR: false; IDDEX: false; ERROR: false);
|
||||||
|
base: ATA_PRIMARY_BASE; info: nil),
|
||||||
|
|
||||||
bar0 : uint32;
|
(exists: false; isPrimary: true; isMaster: false; isATAPI: false;
|
||||||
bar1 : uint32;
|
status: (Busy: false; Ready: false; Fault: false; Seek: false; DRQ: false; CORR: false; IDDEX: false; ERROR: false);
|
||||||
bar4 : uint32;
|
base: ATA_PRIMARY_BASE; info: nil)
|
||||||
|
);
|
||||||
|
|
||||||
IDEDevices : array[0..3] of TIDE_Device;
|
secondaryDevices: array[0..1] of TIDE_Device = (
|
||||||
|
(exists: false; isPrimary: false; isMaster: true; isATAPI: false;
|
||||||
|
status: (Busy: false; Ready: false; Fault: false; Seek: false; DRQ: false; CORR: false; IDDEX: false; ERROR: false);
|
||||||
|
base: ATA_SECONDARY_BASE; info: nil),
|
||||||
|
|
||||||
buffer : Puint32;
|
(exists: false; isPrimary: false; isMaster: false; isATAPI: false;
|
||||||
|
status: (Busy: false; Ready: false; Fault: false; Seek: false; DRQ: false; CORR: false; IDDEX: false; ERROR: false);
|
||||||
|
base: ATA_SECONDARY_BASE; info: nil)
|
||||||
|
);
|
||||||
|
|
||||||
procedure init();
|
|
||||||
function load(ptr : void) : boolean;
|
|
||||||
function identify_device(bus : uint8; device : uint8) : TIdentResponse;
|
|
||||||
|
|
||||||
// procedure flush();
|
function load(ptr: void) : boolean;
|
||||||
procedure readPIO28(drive : uint8; LBA : uint32; buffer : puint8);
|
procedure init();
|
||||||
procedure writePIO28(drive : uint8; LBA : uint32; buffer : puint8);
|
function get_status(var device : TIDE_Device) : TIDE_Status;
|
||||||
//read/write must be capable of reading/writting any amknt of data upto disk size
|
function wait_for_device(device : TIDE_Device) : boolean;
|
||||||
|
procedure no_interrupt(isPrimary : boolean);
|
||||||
procedure dread(device : PStorage_device; LBA : uint32; sectorCount : uint32; buffer : puint32);
|
procedure select_device(device : TIDE_Device);
|
||||||
procedure dwrite(device : PStorage_device; LBA : uint32; sectorCount : uint32; buffer : puint32);
|
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
function port_read(register : uint8) : uint8;
|
{
|
||||||
|
Disable interrupts on the IDE bus
|
||||||
|
@param(isPrimary The bus to disable interrupts on)
|
||||||
|
}
|
||||||
|
procedure no_interrupt(isPrimary : boolean);
|
||||||
begin
|
begin
|
||||||
port_read:= inb(ATA_PRIMARY_BASE + register);
|
if isPrimary then begin
|
||||||
end;
|
outb(ATA_INTERRUPT_PRIMARY, inb(ATA_INTERRUPT_PRIMARY) or (1 shl 1));
|
||||||
|
end else begin
|
||||||
procedure port_write(register : uint8; data : uint8);
|
outb(ATA_INTERRUPT_SECONDARY, inb(ATA_INTERRUPT_SECONDARY) or (1 shl 1));
|
||||||
var
|
|
||||||
i : uint8;
|
|
||||||
begin
|
|
||||||
outb(ATA_PRIMARY_BASE + register, data);
|
|
||||||
util.psleep(1);
|
|
||||||
if register = ATA_REG_COMMAND then begin
|
|
||||||
for i:= 0 to 5 do begin
|
|
||||||
port_read(ATA_REG_STATUS);
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure no_interrupt(device : uint8);
|
{
|
||||||
begin
|
Wait for the device to be ready on the IDE bus
|
||||||
outb($3F6, inb($3f6) or (1 shl 1));
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure device_select(device : uint8);
|
@param(device The device to wait for)
|
||||||
begin
|
@returns(@True if the device is ready, @False otherwise)
|
||||||
outb($1F6, device); //TODO clean
|
}
|
||||||
end;
|
function wait_for_device(device : TIDE_Device) : boolean;
|
||||||
|
|
||||||
function is_ready() : boolean;
|
|
||||||
var
|
var
|
||||||
status : uint8;
|
status : TIDE_Status;
|
||||||
i : uint32;
|
i : uint32;
|
||||||
begin
|
begin
|
||||||
//wait for drive to be ready
|
push_trace('ide.wait_for_device()');
|
||||||
while true do begin
|
|
||||||
status := port_read(ATA_REG_COMMAND);
|
|
||||||
|
|
||||||
if(status and ATA_SR_ERR) = ATA_SR_ERR then begin
|
i := 0;
|
||||||
console.writestringln('[IDE] (IDENTIFY_DEVICE) DRIVE ERROR!');
|
|
||||||
console.redrawWindows();
|
while (i < 10000) do begin
|
||||||
is_ready := false;
|
status := get_status(device);
|
||||||
break;
|
|
||||||
|
if (status.BUSY = false) then begin //todo test
|
||||||
|
wait_for_device := true;
|
||||||
|
pop_trace();
|
||||||
|
exit;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if (status and ATA_SR_BUSY) <> ATA_SR_BUSY then begin
|
i := i + 1;
|
||||||
is_ready := true;
|
|
||||||
break;
|
|
||||||
end;
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
wait_for_device := false;
|
||||||
|
pop_trace();
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function validate_28bit_address(addr : uint32) : boolean;
|
{
|
||||||
begin
|
Select the active device on the IDE bus
|
||||||
validate_28bit_address := (addr and $F0000000) = 0;
|
@param(device The device to select)
|
||||||
end;
|
|
||||||
|
|
||||||
function identify_device(bus : uint8; device : uint8) : TIdentResponse;
|
Function can set the device to either master or slave,
|
||||||
|
one device per bus/channel can be active at a time.
|
||||||
|
}
|
||||||
|
procedure select_device(device : TIDE_Device);
|
||||||
var
|
var
|
||||||
status : uint8;
|
dev : uint8;
|
||||||
identResponse : TIdentResponse;
|
begin
|
||||||
|
push_trace('ide.select_device()');
|
||||||
|
|
||||||
|
dev := ATA_DEVICE_SLAVE;
|
||||||
|
|
||||||
|
if device.isMaster then begin
|
||||||
|
dev := ATA_DEVICE_MASTER;
|
||||||
|
end;
|
||||||
|
|
||||||
|
outb(device.base + ATA_REG_HDDEVSEL, dev);
|
||||||
|
|
||||||
|
pop_trace();
|
||||||
|
end;
|
||||||
|
|
||||||
|
{
|
||||||
|
Get the status of the device on the IDE bus
|
||||||
|
|
||||||
|
@param(device The device to get the status of)
|
||||||
|
@returns(@TIDE_Device The status of the device on the IDE bus)
|
||||||
|
}
|
||||||
|
function get_status(var device : TIDE_Device) : TIDE_Status;
|
||||||
|
var
|
||||||
|
status : TIDE_Status;
|
||||||
|
begin
|
||||||
|
push_trace('ide.get_status()');
|
||||||
|
|
||||||
|
select_device(device);
|
||||||
|
|
||||||
|
status := TIDE_Status(inb(device.base + ATA_REG_STATUS));
|
||||||
|
|
||||||
|
device.status := status;
|
||||||
|
|
||||||
|
pop_trace();
|
||||||
|
get_status := status;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{
|
||||||
|
Check if the device is present on the IDE bus
|
||||||
|
|
||||||
|
@param(device The device to check)
|
||||||
|
@returns(@True if the device is present, @False otherwise)
|
||||||
|
}
|
||||||
|
function is_device_present(var device : TIDE_Device) : boolean;
|
||||||
|
begin
|
||||||
|
push_trace('ide.is_device_present()');
|
||||||
|
|
||||||
|
get_status(device);
|
||||||
|
|
||||||
|
if (uInt8(device.status) = $FF) then begin //TODO make this more robust
|
||||||
|
is_device_present := false;
|
||||||
|
end else begin
|
||||||
|
is_device_present := true;
|
||||||
|
end;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
{
|
||||||
|
Check if the device is an ATAPI device
|
||||||
|
|
||||||
|
@param(device The device to check)
|
||||||
|
@returns(@True if the device is an ATAPI device, @False otherwise)
|
||||||
|
}
|
||||||
|
function check_device_type(var device : TIDE_Device) : boolean;
|
||||||
|
var
|
||||||
|
sec, lba0, lba1, lba2 : uint8;
|
||||||
|
begin
|
||||||
|
push_trace('ide.check_device_type()');
|
||||||
|
|
||||||
|
select_device(device);
|
||||||
|
|
||||||
|
//TODO make sure dvice signture is set at this time, else reset it
|
||||||
|
|
||||||
|
//read all bytes of LBA address
|
||||||
|
sec := inb(device.base + ATA_REG_SECCOUNT);
|
||||||
|
lba0 := inb(device.base + ATA_REG_LBA0);
|
||||||
|
lba1 := inb(device.base + ATA_REG_LBA1);
|
||||||
|
lba2 := inb(device.base + ATA_REG_LBA2);
|
||||||
|
|
||||||
|
//check if the device is an ATAPI device (01, 01, 14, EB)
|
||||||
|
if (lba1 = $14) and (lba2 = $EB) then begin
|
||||||
|
check_device_type := true;
|
||||||
|
end else begin
|
||||||
|
check_device_type := false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
device.isATAPI := check_device_type;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{
|
||||||
|
Load the device on the IDE bus
|
||||||
|
|
||||||
|
@param(device The device to load)
|
||||||
|
@returns(@True if the device is loaded, @False otherwise)
|
||||||
|
}
|
||||||
|
procedure load_device(var device : TIDE_Device);
|
||||||
|
var
|
||||||
|
i : uint8;
|
||||||
|
buffer : puint8;
|
||||||
|
storageDevice : PStorage_device;
|
||||||
|
success : boolean;
|
||||||
|
begin
|
||||||
|
|
||||||
|
push_trace('ide.load_device()');
|
||||||
|
|
||||||
|
if (is_device_present(device)) then begin
|
||||||
|
console.writestringln('[IDE] (load_device) Device is present');
|
||||||
|
|
||||||
|
if (check_device_type(device)) then begin
|
||||||
|
console.writestringln('[IDE] (load_device) Device is ATAPI');
|
||||||
|
//todo load device info
|
||||||
|
end else begin
|
||||||
|
console.writestringln('[IDE] (load_device) Device is ATA');
|
||||||
|
success:= ata.identify_device(device);
|
||||||
|
end;
|
||||||
|
|
||||||
|
if not success then begin
|
||||||
|
console.writestringln('[IDE] (load_device) Error identifying device'); //todo
|
||||||
|
device.exists := false;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
device.exists := true;
|
||||||
|
|
||||||
|
storageDevice := PStorage_Device(kalloc(sizeof(TStorage_Device)));
|
||||||
|
memset(uint32(storageDevice), 0, sizeof(TStorage_Device));
|
||||||
|
|
||||||
|
if (device.isATAPI) then begin
|
||||||
|
storageDevice^.controller := TControllerType.ControllerATAPI;
|
||||||
|
storageDevice^.writable := false; //TODO atapi
|
||||||
|
end else begin
|
||||||
|
storageDevice^.controller := TControllerType.ControllerATA;
|
||||||
|
storageDevice^.writable := true;
|
||||||
|
|
||||||
|
storageDevice^.maxSectorCount := (device.info^[61] shl 16) or device.info^[60];
|
||||||
|
storageDevice^.sectorSize := 512; //todo
|
||||||
|
|
||||||
|
if (device.isMaster) then begin
|
||||||
|
storageDevice^.controllerId0 := 0;
|
||||||
|
end else begin
|
||||||
|
storageDevice^.controllerId0 := 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
//if secotorcount is 0, then the device is not present
|
||||||
|
if (storageDevice^.maxSectorCount = 0) then begin
|
||||||
|
device.exists := false;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
//wrtie test, 1F2F1F2F repeated
|
||||||
|
buffer := puint8(kalloc(512));
|
||||||
|
memset(uint32(buffer), 0, 512);
|
||||||
|
for i:=0 to 200 do begin
|
||||||
|
if (i mod 4 = 0) then begin
|
||||||
|
buffer[i] := $1F;
|
||||||
|
end else begin
|
||||||
|
buffer[i] := $2F;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
//write to the first sector
|
||||||
|
ata.write_pio28(device, 0, 1, puint16(buffer));
|
||||||
|
|
||||||
|
//read the first sector
|
||||||
|
memset(uint32(buffer), 0, 512);
|
||||||
|
ata.read_pio28(device, 0, 1, puint16(buffer));
|
||||||
|
|
||||||
|
//check if the data is the same
|
||||||
|
for i:=0 to 200 do begin
|
||||||
|
console.writehexln(buffer[i]);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
//register the device
|
||||||
|
drivemanager.register_device(storageDevice);
|
||||||
|
|
||||||
|
end else begin
|
||||||
|
console.writestringln('[IDE] (load_device) Device is not present');
|
||||||
|
device.exists := false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
pop_trace();
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function load(ptr: void) : boolean;
|
||||||
|
var
|
||||||
|
pciDevice : PPCI_Device;
|
||||||
|
buffer : puint8;
|
||||||
i : uint8;
|
i : uint8;
|
||||||
begin
|
begin
|
||||||
push_trace('IDE.Identify_Device');
|
push_trace('ide.load()');
|
||||||
device_select(device);
|
console.writestringln('[IDE] (load) Loading IDE Devices');
|
||||||
no_interrupt(device);
|
|
||||||
port_write(ATA_REG_CONTROL, 0);
|
|
||||||
|
|
||||||
//check if bus is floating
|
pciDevice := PPCI_Device(ptr);
|
||||||
status := port_read(ATA_REG_COMMAND);
|
|
||||||
if status = $FF then exit;
|
|
||||||
|
|
||||||
port_write(ATA_REG_SECCOUNT, 0);
|
load_device(primaryDevices[0]);
|
||||||
port_write(ATA_REG_LBA0, 0);
|
load_device(primaryDevices[1]);
|
||||||
port_write(ATA_REG_LBA1, 0);
|
load_device(secondaryDevices[0]);
|
||||||
port_write(ATA_REG_LBA2, 0);
|
load_device(secondaryDevices[1]);
|
||||||
|
|
||||||
port_write(ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
|
pop_trace();
|
||||||
|
load := true;
|
||||||
|
|
||||||
//check if drive is present
|
console.writestringln('[IDE] (load) IDE Device Loading Finished');
|
||||||
status := port_read(ATA_REG_COMMAND);
|
|
||||||
if status = $00 then exit;
|
|
||||||
|
|
||||||
if not is_ready() then exit;
|
i := 0;
|
||||||
|
|
||||||
for i:=0 to 255 do begin
|
if (primaryDevices[0].exists) then begin
|
||||||
identResponse[i] := inw(ATA_PRIMARY_BASE + ATA_REG_DATA);
|
console.writestringln('[IDE] (load) FOUND Primary Master Device 0');
|
||||||
|
i := i + 1;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
identify_device := identResponse;
|
if (primaryDevices[1].exists) then begin
|
||||||
|
console.writestringln('[IDE] (load) FOUND Primary Slave Device 1');
|
||||||
|
i := i + 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if (secondaryDevices[0].exists) then begin
|
||||||
|
console.writestringln('[IDE] (load) FOUND Secondary Master Device 2');
|
||||||
|
i := i + 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if (secondaryDevices[1].exists) then begin
|
||||||
|
console.writestringln('[IDE] (load) FOUND Secondary Slave Device 3');
|
||||||
|
i := i + 1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// console.writestringln('[IDE] (load) Found ' + i + ' IDE Devices');
|
||||||
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure init();
|
procedure init();
|
||||||
@ -258,208 +348,8 @@ begin
|
|||||||
devID.id3:= idANY;
|
devID.id3:= idANY;
|
||||||
devID.id4:= idANY;
|
devID.id4:= idANY;
|
||||||
devID.ex:= nil;
|
devID.ex:= nil;
|
||||||
drivermanagement.register_driver('IDE ATA Driver', @devID, @load);
|
drivermanagement.register_driver('IDE ATA/ATAPI Driver', @devID, @load);
|
||||||
console.writestringln('[IDE] (INIT) END');
|
console.writestringln('[IDE] (INIT) END');
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function load(ptr : void) : boolean;
|
|
||||||
var
|
|
||||||
controller : PPCI_Device;
|
|
||||||
masterDevice : TStorage_Device;
|
|
||||||
slaveDevice : TStorage_Device;
|
|
||||||
buffer : puint8;
|
|
||||||
i : uint8;
|
|
||||||
test : PStorage_device;
|
|
||||||
begin
|
|
||||||
push_trace('ide.load');
|
|
||||||
console.writestringln('[IDE] (LOAD) BEGIN');
|
|
||||||
controller := PPCI_Device(ptr);
|
|
||||||
|
|
||||||
console.writestringln('[IDE] (INIT) CHECK FLOATING BUS');
|
|
||||||
//check if bus is floating and identify device
|
|
||||||
if inb($1F7) <> $FF then begin
|
|
||||||
//outb($3F6, inb($3f6) or (1 shl 1)); // disable interrupts
|
|
||||||
IDEDevices[0].isMaster:= true;
|
|
||||||
IDEDevices[0].info := identify_device(0, ATA_DEVICE_MASTER);
|
|
||||||
|
|
||||||
masterDevice.controller := ControllerIDE;
|
|
||||||
masterDevice.controllerId0:= 0;
|
|
||||||
masterDevice.maxSectorCount:= (IDEDevices[0].info[60] or (IDEDevices[0].info[61] shl 16) ); //LBA28 SATA
|
|
||||||
|
|
||||||
if IDEDevices[0].info[1] = 0 then begin
|
|
||||||
console.writestringln('[IDE] (INIT) ERROR: DEVICE IDENT FAILED!');
|
|
||||||
exit;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// masterDevice.hpc:= uint32(IDEDevices[0].info[3] DIV IDEDevices[0].info[1]); //TODO wtf is hpc
|
|
||||||
|
|
||||||
masterDevice.sectorSize:= 512;
|
|
||||||
if masterDevice.maxSectorCount <> 0 then begin
|
|
||||||
IDEDevices[0].exists:= true;
|
|
||||||
masterDevice.readCallback:= @dread;
|
|
||||||
masterDevice.writeCallback:= @dwrite;
|
|
||||||
// storagemanagement.register_device(@masterDevice);
|
|
||||||
drivemanager.register_device(@masterDevice);
|
|
||||||
end;
|
|
||||||
|
|
||||||
end;
|
|
||||||
|
|
||||||
// buffer:= puint8(kalloc(512));
|
|
||||||
// buffer[0] := 1;
|
|
||||||
// buffer[1] := 2;
|
|
||||||
// buffer[2] := 3;
|
|
||||||
// buffer[3] := 4;
|
|
||||||
// buffer[4] := 5;
|
|
||||||
// buffer[5] := 6;
|
|
||||||
// writePIO28(0, 3, buffer);
|
|
||||||
// writePIO28(0, 3, buffer);
|
|
||||||
// writePIO28(0, 3, buffer);
|
|
||||||
// writePIO28(0, 4, buffer);
|
|
||||||
// writePIO28(0, 5, buffer);
|
|
||||||
// writePIO28(0, 5, buffer);
|
|
||||||
// writePIO28(0, 5, buffer);
|
|
||||||
// psleep(1000);
|
|
||||||
// writePIO28(0, 5, buffer);
|
|
||||||
// writePIO28(0, 5, buffer);
|
|
||||||
// writePIO28(0, 5, buffer);
|
|
||||||
// kfree(puint32(buffer));
|
|
||||||
|
|
||||||
console.writestringln('[IDE] (LOAD) END');
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure readPIO28(drive : uint8; LBA : uint32; buffer : puint8);
|
|
||||||
var
|
|
||||||
status : uint8;
|
|
||||||
i: uint16;
|
|
||||||
device: uint8;
|
|
||||||
data: uint16;
|
|
||||||
begin
|
|
||||||
push_trace('IDE.readPIO28');
|
|
||||||
|
|
||||||
if not validate_28bit_address(LBA) then begin
|
|
||||||
console.writestringln('IDE (writePIO28) ERROR: Invalid LBA!');
|
|
||||||
end;
|
|
||||||
|
|
||||||
// push_trace('IDE.readPIO28.2');
|
|
||||||
|
|
||||||
//Add last 4 bits of LBA to device port
|
|
||||||
if IDEDevices[drive].isMaster then begin
|
|
||||||
device:= ATA_DEVICE_MASTER;
|
|
||||||
device_select($E0 or ((LBA and $0F000000) shr 24)); //LBA primary master
|
|
||||||
end
|
|
||||||
else begin
|
|
||||||
device:= ATA_DEVICE_SLAVE;
|
|
||||||
device_select($F0 or ((LBA and $0F000000) shr 24)); //LBA primary slave
|
|
||||||
end;
|
|
||||||
|
|
||||||
// push_trace('IDE.readPIO28.3');
|
|
||||||
|
|
||||||
no_interrupt(device);
|
|
||||||
port_write(ATA_REG_ERROR, 0);
|
|
||||||
|
|
||||||
//Write sector count and LBA
|
|
||||||
port_write(ATA_REG_SECCOUNT, 1);
|
|
||||||
port_write(ATA_REG_LBA0, (LBA and $000000FF));
|
|
||||||
port_write(ATA_REG_LBA1, (LBA and $0000FF00) shr 8);
|
|
||||||
port_write(ATA_REG_LBA2, (LBA and $00FF0000) shr 16);
|
|
||||||
|
|
||||||
// push_trace('IDE.readPIO28.4');
|
|
||||||
|
|
||||||
//send read command
|
|
||||||
port_write(ATA_REG_COMMAND, ATA_CMD_READ_PIO);
|
|
||||||
if not is_ready() then exit;
|
|
||||||
|
|
||||||
i:=0;
|
|
||||||
while i < 512 do begin
|
|
||||||
// if not is_ready() then exit;
|
|
||||||
|
|
||||||
data:= inw(ATA_PRIMARY_BASE + ATA_REG_DATA);
|
|
||||||
|
|
||||||
buffer[i+1] := uint8($00ff and (data shr 8));
|
|
||||||
buffer[i] := uint8($00ff and data);
|
|
||||||
|
|
||||||
i:= i + 2;
|
|
||||||
end;
|
|
||||||
|
|
||||||
// push_trace('IDE.readPIO28.5');
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure writePIO28(drive : uint8; LBA : uint32; buffer : puint8);
|
|
||||||
var
|
|
||||||
status : uint8;
|
|
||||||
i: uint16;
|
|
||||||
device: uint8;
|
|
||||||
begin
|
|
||||||
push_trace('IDE.WritePIO28');
|
|
||||||
if not validate_28bit_address(LBA) then begin
|
|
||||||
console.writestringln('IDE (writePIO28) ERROR: Invalid LBA!');
|
|
||||||
end;
|
|
||||||
|
|
||||||
console.writeintln(uint32(drive));
|
|
||||||
console.writeintln(LBA);
|
|
||||||
|
|
||||||
//Add last 4 bits of LBA to device port
|
|
||||||
if IDEDevices[drive].isMaster then begin
|
|
||||||
device:= ATA_DEVICE_MASTER;
|
|
||||||
device_select($E0 or ((LBA and $0F000000) shr 24)); //LBA primary master
|
|
||||||
end
|
|
||||||
else begin
|
|
||||||
device:= ATA_DEVICE_SLAVE;
|
|
||||||
device_select($F0 or ((LBA and $0F000000) shr 24)); //LBA primary slave
|
|
||||||
end;
|
|
||||||
|
|
||||||
// no_interrupt(device);
|
|
||||||
|
|
||||||
port_write(ATA_REG_ERROR, 0);
|
|
||||||
port_write(ATA_REG_CONTROL, 0);
|
|
||||||
|
|
||||||
// check if bus is floating
|
|
||||||
status := port_read(ATA_REG_COMMAND);
|
|
||||||
if status = $FF then exit;
|
|
||||||
|
|
||||||
//Write sector count and LBA
|
|
||||||
port_write(ATA_REG_SECCOUNT, 1);
|
|
||||||
port_write(ATA_REG_LBA0, (LBA and $000000FF));
|
|
||||||
port_write(ATA_REG_LBA1, (LBA and $0000FF00) shr 8);
|
|
||||||
port_write(ATA_REG_LBA2, (LBA and $00FF0000) shr 16);
|
|
||||||
|
|
||||||
//send write command
|
|
||||||
port_write(ATA_REG_COMMAND, ATA_CMD_WRITE_PIO);
|
|
||||||
|
|
||||||
//write data
|
|
||||||
i:=0;
|
|
||||||
while i < 512 do begin
|
|
||||||
outw(ATA_PRIMARY_BASE + ATA_REG_DATA, uint16(buffer[i] or (buffer[i+1] shl 8)));
|
|
||||||
i:= i + 2;
|
|
||||||
end;
|
|
||||||
|
|
||||||
//flush drive cache
|
|
||||||
psleep(1);
|
|
||||||
port_write(ATA_REG_COMMAND, ATA_CMD_CACHE_FLUSH);
|
|
||||||
psleep(1);
|
|
||||||
if not is_ready() then exit;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure dread(device : PStorage_device; LBA : uint32; sectorCount : uint32; buffer : Puint32);
|
|
||||||
var
|
|
||||||
i : uint16;
|
|
||||||
begin
|
|
||||||
push_trace('IDE.dread');
|
|
||||||
for i:=0 to sectorCount-1 do begin
|
|
||||||
readPIO28(device^.controllerId0, LBA + i, puint8(@buffer[512*i]));
|
|
||||||
psleep(100)
|
|
||||||
end;
|
|
||||||
end;
|
|
||||||
|
|
||||||
procedure dwrite(device : PStorage_device; LBA : uint32; sectorCount : uint32; buffer : Puint32);
|
|
||||||
var
|
|
||||||
i : uint16;
|
|
||||||
begin
|
|
||||||
for i:=0 to sectorCount-1 do begin
|
|
||||||
writePIO28(device^.controllerId0, LBA + i, puint8(@buffer[512*i]));
|
|
||||||
psleep(100)
|
|
||||||
end;
|
|
||||||
// writePIO28(device^.controllerId0, LBA, puint8(buffer));
|
|
||||||
end;
|
|
||||||
|
|
||||||
end.
|
end.
|
221
src/driver/storage/ata.pas
Normal file
221
src/driver/storage/ata.pas
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
unit ata;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
util,
|
||||||
|
drivertypes,
|
||||||
|
console,
|
||||||
|
terminal,
|
||||||
|
drivermanagement,
|
||||||
|
vmemorymanager,
|
||||||
|
lmemorymanager,
|
||||||
|
storagemanagement,
|
||||||
|
strings,
|
||||||
|
tracer,
|
||||||
|
drivemanager,
|
||||||
|
storagetypes,
|
||||||
|
idetypes;
|
||||||
|
|
||||||
|
var
|
||||||
|
|
||||||
|
test : uint32;
|
||||||
|
|
||||||
|
function identify_device(var device : TIDE_Device) : Boolean;
|
||||||
|
function read_pio28(device : TIDE_Device; lba : uint32; count : uint8; buffer : puint16) : boolean;
|
||||||
|
function write_pio28(device : TIDE_Device; lba : uint32; count : uint8; buffer : puint16) : boolean;
|
||||||
|
|
||||||
|
|
||||||
|
implementation
|
||||||
|
uses
|
||||||
|
ide;
|
||||||
|
|
||||||
|
{
|
||||||
|
ensure the address is a valid 28 bit address
|
||||||
|
|
||||||
|
@param(addr The address to validate)
|
||||||
|
@returns(@True if the address is valid, @False otherwise)
|
||||||
|
}
|
||||||
|
function validate_28bit_address(addr : uint32) : boolean;
|
||||||
|
begin
|
||||||
|
validate_28bit_address := (addr and $F0000000) = 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{
|
||||||
|
Identify the device on the IDE bus
|
||||||
|
|
||||||
|
@param(device The device to identify)
|
||||||
|
@returns(@True if the device is identified, @False otherwise)
|
||||||
|
}
|
||||||
|
function identify_device(var device : TIDE_Device) : Boolean;
|
||||||
|
var
|
||||||
|
i : uint8;
|
||||||
|
status : TIDE_Status;
|
||||||
|
buffer : TIdentResponse;
|
||||||
|
ready : boolean;
|
||||||
|
begin
|
||||||
|
select_device(device);
|
||||||
|
no_interrupt(device.isPrimary);
|
||||||
|
|
||||||
|
status := get_status(device);
|
||||||
|
|
||||||
|
outb(device.base + ATA_REG_SECCOUNT, 0);
|
||||||
|
outb(device.base + ATA_REG_LBA0, 0);
|
||||||
|
outb(device.base + ATA_REG_LBA1, 0);
|
||||||
|
outb(device.base + ATA_REG_LBA2, 0);
|
||||||
|
|
||||||
|
outb(device.base + ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
|
||||||
|
|
||||||
|
status := get_status(device);
|
||||||
|
|
||||||
|
if status.ERROR then begin
|
||||||
|
console.writestringln('Error identifying device, maybe'); //todo
|
||||||
|
end;
|
||||||
|
|
||||||
|
ready := wait_for_device(device);
|
||||||
|
|
||||||
|
if not ready then begin
|
||||||
|
console.writestringln('Device not ready in time!');
|
||||||
|
//teapot time
|
||||||
|
// BSOD('Device not ready in time!', 'ATA DEVICE NOT READY IN TIME FOR IDENT');
|
||||||
|
exit(false);
|
||||||
|
end;
|
||||||
|
|
||||||
|
for i:=0 to 255 do begin
|
||||||
|
buffer[i] := inw(device.base + ATA_REG_DATA);
|
||||||
|
end;
|
||||||
|
|
||||||
|
device.info := @buffer;
|
||||||
|
|
||||||
|
identify_device := true;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure set_lba_mode(device : TIDE_Device; lba : uint32);
|
||||||
|
begin
|
||||||
|
// if device.isPrimary then begin
|
||||||
|
if device.isMaster then begin
|
||||||
|
outb(device.base + ATA_REG_HDDEVSEL, $E0 or ((lba and $0F000000) shr 24));
|
||||||
|
end else begin
|
||||||
|
outb(device.base + ATA_REG_HDDEVSEL, $F0 or ((lba and $0F000000) shr 24));
|
||||||
|
end;
|
||||||
|
// end else begin //TODO
|
||||||
|
// if device.isMaster then begin
|
||||||
|
// outb(device.base + ATA_REG_HDDEVSEL, $A0);
|
||||||
|
// end else begin
|
||||||
|
// outb(device.base + ATA_REG_HDDEVSEL, $B0);
|
||||||
|
// end;
|
||||||
|
// end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function read_pio28(device : TIDE_Device; lba : uint32; count : uint8; buffer : puint16) : boolean;
|
||||||
|
var
|
||||||
|
i : uint16;
|
||||||
|
ii : uint16;
|
||||||
|
status : TIDE_Status;
|
||||||
|
ready : boolean;
|
||||||
|
begin
|
||||||
|
push_trace('ata.read_pio28()');
|
||||||
|
|
||||||
|
if not validate_28bit_address(lba) then begin
|
||||||
|
console.writestringln('Invalid address for 28 bit read');
|
||||||
|
read_pio28 := false;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
select_device(device);
|
||||||
|
no_interrupt(device.isPrimary);
|
||||||
|
|
||||||
|
set_lba_mode(device, lba);
|
||||||
|
|
||||||
|
outb(device.base + ATA_REG_SECCOUNT, count);
|
||||||
|
outb(device.base + ATA_REG_LBA0, (lba and $000000FF));
|
||||||
|
outb(device.base + ATA_REG_LBA1, (lba and $0000FF00) shr 8);
|
||||||
|
outb(device.base + ATA_REG_LBA2, (lba and $00FF0000) shr 16);
|
||||||
|
|
||||||
|
outb(device.base + ATA_REG_COMMAND, ATA_CMD_READ_PIO);
|
||||||
|
|
||||||
|
ready := wait_for_device(device);
|
||||||
|
|
||||||
|
if not ready then begin
|
||||||
|
console.writestringln('Device not ready in time!');
|
||||||
|
BSOD('Device not ready in time!', 'ATA DEVICE NOT READY IN TIME FOR READ COMMAND');
|
||||||
|
end;
|
||||||
|
|
||||||
|
for i:=0 to count-1 do begin
|
||||||
|
for ii:=0 to 511 do begin //TODO needs to read sector size
|
||||||
|
buffer[i] := inw(device.base + ATA_REG_DATA);
|
||||||
|
|
||||||
|
ready := wait_for_device(device);
|
||||||
|
|
||||||
|
if not ready then begin
|
||||||
|
console.writestringln('Device not ready in time!');
|
||||||
|
BSOD('Device not ready in time!', 'ATA DEVICE NOT READY IN TIME FOR READ');
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
read_pio28 := true;
|
||||||
|
pop_trace();
|
||||||
|
end;
|
||||||
|
|
||||||
|
function write_pio28(device : TIDE_Device; lba : uint32; count : uint8; buffer : puint16) : boolean;
|
||||||
|
var
|
||||||
|
i : uint16;
|
||||||
|
ii : uint16;
|
||||||
|
status : TIDE_Status;
|
||||||
|
ready : boolean;
|
||||||
|
begin
|
||||||
|
push_trace('ata.write_pio28()');
|
||||||
|
|
||||||
|
if not validate_28bit_address(lba) then begin
|
||||||
|
console.writestringln('Invalid address for 28 bit write');
|
||||||
|
write_pio28 := false;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
select_device(device);
|
||||||
|
no_interrupt(device.isPrimary); //maybe not?
|
||||||
|
|
||||||
|
set_lba_mode(device, lba);
|
||||||
|
|
||||||
|
outb(device.base + ATA_REG_SECCOUNT, count);
|
||||||
|
outb(device.base + ATA_REG_LBA0, (lba and $000000FF));
|
||||||
|
outb(device.base + ATA_REG_LBA1, (lba and $0000FF00) shr 8);
|
||||||
|
outb(device.base + ATA_REG_LBA2, (lba and $00FF0000) shr 16);
|
||||||
|
|
||||||
|
outb(device.base + ATA_REG_COMMAND, ATA_CMD_WRITE_PIO);
|
||||||
|
|
||||||
|
ready := wait_for_device(device);
|
||||||
|
|
||||||
|
if not ready then begin
|
||||||
|
console.writestringln('Device not ready in time!');
|
||||||
|
BSOD('Device not ready in time!', 'ATA DEVICE NOT READY IN TIME FOR WRITE COMMAND');
|
||||||
|
end;
|
||||||
|
|
||||||
|
for i:=0 to count-1 do begin
|
||||||
|
for ii:=0 to 511 do begin //TODO needs to read sector size
|
||||||
|
outw(device.base + ATA_REG_DATA, uint16(buffer[i]));
|
||||||
|
|
||||||
|
ready := wait_for_device(device);
|
||||||
|
|
||||||
|
if not ready then begin
|
||||||
|
console.writestringln('Device not ready in time!');
|
||||||
|
BSOD('Device not ready in time!', 'ATA DEVICE NOT READY IN TIME FOR WRITE');
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
psleep(50); //todo check
|
||||||
|
outb(device.base + ATA_REG_COMMAND, ATA_CMD_CACHE_FLUSH);
|
||||||
|
ready := wait_for_device(device);
|
||||||
|
|
||||||
|
// if not ready then begin
|
||||||
|
// console.writestringln('Device not ready in time!');
|
||||||
|
// BSOD('Device not ready in time!', 'ATA DEVICE NOT READY IN TIME FOR CACHE FLUSH');
|
||||||
|
// end;
|
||||||
|
|
||||||
|
write_pio28 := true;
|
||||||
|
pop_trace();
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
0
src/driver/storage/atapi.pas
Normal file
0
src/driver/storage/atapi.pas
Normal file
@ -271,7 +271,7 @@ begin
|
|||||||
PStorage_device(elm)^.volumes := LL_New(sizeof(TStorage_Volume));
|
PStorage_device(elm)^.volumes := LL_New(sizeof(TStorage_Volume));
|
||||||
|
|
||||||
//TODO register with volume manager
|
//TODO register with volume manager
|
||||||
volumemanager.check_for_volumes(PStorage_Device(elm));
|
//volumemanager.check_for_volumes(PStorage_Device(elm));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ Get the drive list }
|
{ Get the drive list }
|
||||||
@ -290,7 +290,8 @@ begin
|
|||||||
|
|
||||||
//return string of controller type
|
//return string of controller type
|
||||||
case controllerType of
|
case controllerType of
|
||||||
ControllerIDE : controller_type_2_string:= 'IDE';
|
ControllerATA : controller_type_2_string:= 'ATA';
|
||||||
|
ControllerATAPI : controller_type_2_string:= 'ATAPI';
|
||||||
ControllerUSB : controller_type_2_string:= 'USB';
|
ControllerUSB : controller_type_2_string:= 'USB';
|
||||||
ControllerAHCI : controller_type_2_string:= 'ACHI (SATA)';
|
ControllerAHCI : controller_type_2_string:= 'ACHI (SATA)';
|
||||||
ControllerNET : controller_type_2_string:= 'Net';
|
ControllerNET : controller_type_2_string:= 'Net';
|
||||||
|
140
src/driver/storage/idetypes.pas
Normal file
140
src/driver/storage/idetypes.pas
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
// Copyright 2021 Aaron Hance
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
{
|
||||||
|
Driver->Storage->IDE->idetypes - IDE device types and constants.
|
||||||
|
|
||||||
|
@author(Aaron Hance <ah@aaronhance.me>)
|
||||||
|
}
|
||||||
|
unit idetypes;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
const
|
||||||
|
|
||||||
|
ATA_SR_BUSY = $80; //BUSY
|
||||||
|
ATA_SR_DRDY = $40; //DRIVE READY
|
||||||
|
ATA_SR_DF = $20; //DRIVE WRITE FAULT
|
||||||
|
ATA_SR_DSC = $10; //DRIVE SEEK COMPLETE
|
||||||
|
ATA_SR_DRQ = $08; //DATA REQUEST READY
|
||||||
|
ATA_SR_CORR = $04; //CORRECTED DATA
|
||||||
|
ATA_SR_IDX = $02; //INLEX
|
||||||
|
ATA_SR_ERR = $01; //ERROR
|
||||||
|
|
||||||
|
ATA_ER_BBK = $80; //BAD SECTOR
|
||||||
|
ATA_ER_UNC = $40; //UNCORRECTABLE DATA
|
||||||
|
ATA_ER_MC = $20; //NO MEDIA
|
||||||
|
ATA_ER_IDNF = $10; //ID MARK NOT FOUND
|
||||||
|
ATA_ER_MCR = $08; //NO MEDIA
|
||||||
|
ATA_ER_ABRT = $04; //COMMAND ABORTED
|
||||||
|
ATA_ER_TK0NF = $02; //TRACK 0 NOT FOUND
|
||||||
|
ATA_ER_AMNF = $01; //NO ADDRESS MARK
|
||||||
|
|
||||||
|
ATA_CMD_READ_PIO = $20;
|
||||||
|
ATA_CMD_READ_PIO_EXT = $24;
|
||||||
|
ATA_CMD_READ_DMA = $C8;
|
||||||
|
ATA_CMD_READ_DMA_EXT = $25;
|
||||||
|
ATA_CMD_WRITE_PIO = $30;
|
||||||
|
ATA_CMD_WRITE_PIO_EXT = $34;
|
||||||
|
ATA_CMD_WRITE_DMA = $CA;
|
||||||
|
ATA_CMD_WRITE_DMA_EXT = $35;
|
||||||
|
ATA_CMD_CACHE_FLUSH = $E7;
|
||||||
|
ATA_CMD_CACHE_FLUSH_EXT = $EA;
|
||||||
|
ATA_CMD_PACKET = $A0;
|
||||||
|
ATA_CMD_IDENTIFY_PACKET = $A1;
|
||||||
|
ATA_CMD_IDENTIFY = $EC;
|
||||||
|
|
||||||
|
ATAPI_CMD_READ = $A8;
|
||||||
|
ATAPI_CMD_EJECT = $1B;
|
||||||
|
|
||||||
|
ATA_IDENT_DEVICETYPE = $0;
|
||||||
|
ATA_IDENT_CYLINDERS = $2;
|
||||||
|
ATA_IDENT_HEADS = $6;
|
||||||
|
ATA_IDENT_SECOTRS = $12;
|
||||||
|
ATA_IDENT_SERIAL = $20;
|
||||||
|
ATA_IDENT_MODEL = $54;
|
||||||
|
ATA_IDENT_CAPABILITIES = $98;
|
||||||
|
ATA_IDENT_FIELDVALID = $106;
|
||||||
|
ATA_IDENT_MAX_LBA = $120;
|
||||||
|
ATA_IDENT_COMMANDSETS = $164;
|
||||||
|
ATA_IDENT_MAX_LBA_EXT = $200;
|
||||||
|
|
||||||
|
ATA_REG_DATA = $00;
|
||||||
|
ATA_REG_ERROR = $01;
|
||||||
|
ATA_REG_FEATURES = $01;
|
||||||
|
ATA_REG_SECCOUNT = $02;
|
||||||
|
ATA_REG_LBA0 = $03;
|
||||||
|
ATA_REG_LBA1 = $04;
|
||||||
|
ATA_REG_LBA2 = $05;
|
||||||
|
ATA_REG_HDDEVSEL = $06;
|
||||||
|
ATA_REG_COMMAND = $07;
|
||||||
|
ATA_REG_STATUS = $07;
|
||||||
|
ATA_REG_SECCOUNT1 = $08;
|
||||||
|
ATA_REG_LBA3 = $09;
|
||||||
|
ATA_REG_LBA4 = $0A;
|
||||||
|
ATA_REG_LBA5 = $0B;
|
||||||
|
ATA_REG_CONTROL = $0C;
|
||||||
|
ATA_REG_ALTSTATUS = $0C;
|
||||||
|
ATA_REG_DEVADDRESS = $0D;
|
||||||
|
|
||||||
|
ATA_DEVICE_MASTER = $A0;
|
||||||
|
ATA_DEVICE_SLAVE = $B0;
|
||||||
|
|
||||||
|
ATA_PRIMARY_BASE = $1F0;
|
||||||
|
ATA_PRIMARY_BASE1 = $3F6;
|
||||||
|
ATA_SECONDARY_BASE = $170; //todo check this
|
||||||
|
ATA_SECONDARY_BASE1 = $376; //todo check this
|
||||||
|
|
||||||
|
ATA_INTERRUPT_PRIMARY = $3F6;
|
||||||
|
ATA_INTERRUPT_SECONDARY = $376;
|
||||||
|
|
||||||
|
type
|
||||||
|
TPortMode = (P_READ, P_WRITE);
|
||||||
|
|
||||||
|
TIdentResponse = array[0..255] of uint16;
|
||||||
|
PIdentResponse = ^TIdentResponse;
|
||||||
|
|
||||||
|
TIDE_Channel_Registers = record
|
||||||
|
base : uint16;
|
||||||
|
ctrl : uint16;
|
||||||
|
bmide : uint16;
|
||||||
|
noInter : uint8
|
||||||
|
end;
|
||||||
|
|
||||||
|
TIDE_Status = bitpacked record
|
||||||
|
Busy : Boolean;
|
||||||
|
Ready : Boolean;
|
||||||
|
Fault : Boolean;
|
||||||
|
Seek : Boolean;
|
||||||
|
DRQ : Boolean;
|
||||||
|
CORR : Boolean;
|
||||||
|
IDDEX : Boolean;
|
||||||
|
ERROR : Boolean;
|
||||||
|
end;
|
||||||
|
PIDE_Status = ^TIDE_Status;
|
||||||
|
|
||||||
|
TIDE_Device = record
|
||||||
|
exists : boolean;
|
||||||
|
isPrimary : boolean;
|
||||||
|
isMaster : boolean;
|
||||||
|
isATAPI : boolean;
|
||||||
|
status : TIDE_Status;
|
||||||
|
base : uint16;
|
||||||
|
info : PIdentResponse;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
end.
|
504
src/driver/storage/oldIDE.pas
Normal file
504
src/driver/storage/oldIDE.pas
Normal file
@ -0,0 +1,504 @@
|
|||||||
|
{ ************************************************
|
||||||
|
* Asuro
|
||||||
|
* Unit: Drivers/storage/IDE
|
||||||
|
* Description: IDE ATA Driver
|
||||||
|
*
|
||||||
|
************************************************
|
||||||
|
* Author: Aaron Hance
|
||||||
|
* Contributors:
|
||||||
|
************************************************ }
|
||||||
|
unit IDE;
|
||||||
|
|
||||||
|
interface
|
||||||
|
|
||||||
|
uses
|
||||||
|
util,
|
||||||
|
drivertypes,
|
||||||
|
console,
|
||||||
|
terminal,
|
||||||
|
drivermanagement,
|
||||||
|
vmemorymanager,
|
||||||
|
lmemorymanager,
|
||||||
|
storagemanagement,
|
||||||
|
strings,
|
||||||
|
tracer,
|
||||||
|
drivemanager,
|
||||||
|
storagetypes;
|
||||||
|
|
||||||
|
type
|
||||||
|
TPortMode = (P_READ, P_WRITE);
|
||||||
|
|
||||||
|
TIdentResponse = array[0..255] of uint16;
|
||||||
|
|
||||||
|
TIDE_Channel_Registers = record
|
||||||
|
base : uint16;
|
||||||
|
ctrl : uint16;
|
||||||
|
bmide : uint16;
|
||||||
|
noInter : uint8
|
||||||
|
end;
|
||||||
|
|
||||||
|
TIDE_Device = record
|
||||||
|
exists : boolean;
|
||||||
|
isPrimary : boolean;
|
||||||
|
isMaster : boolean;
|
||||||
|
isATAPI : boolean;
|
||||||
|
info : TIdentResponse;
|
||||||
|
end;
|
||||||
|
|
||||||
|
TIDE_Status = bitpacked record
|
||||||
|
Busy : Boolean;
|
||||||
|
Ready : Boolean;
|
||||||
|
Fault : Boolean;
|
||||||
|
Seek : Boolean;
|
||||||
|
DRQ : Boolean;
|
||||||
|
CORR : Boolean;
|
||||||
|
IDDEX : Boolean;
|
||||||
|
ERROR : Boolean;
|
||||||
|
end;
|
||||||
|
PIDE_Status = ^TIDE_Status;
|
||||||
|
|
||||||
|
|
||||||
|
const
|
||||||
|
ATA_SR_BUSY = $80; //BUSY
|
||||||
|
ATA_SR_DRDY = $40; //DRIVE READY
|
||||||
|
ATA_SR_DF = $20; //DRIVE WRITE FAULT
|
||||||
|
ATA_SR_DSC = $10; //DRIVE SEEK COMPLETE
|
||||||
|
ATA_SR_DRQ = $08; //DATA REQUEST READY
|
||||||
|
ATA_SR_CORR = $04; //CORRECTED DATA
|
||||||
|
ATA_SR_IDX = $02; //INLEX
|
||||||
|
ATA_SR_ERR = $01; //ERROR
|
||||||
|
|
||||||
|
ATA_ER_BBK = $80; //BAD SECTOR
|
||||||
|
ATA_ER_UNC = $40; //UNCORRECTABLE DATA
|
||||||
|
ATA_ER_MC = $20; //NO MEDIA
|
||||||
|
ATA_ER_IDNF = $10; //ID MARK NOT FOUND
|
||||||
|
ATA_ER_MCR = $08; //NO MEDIA
|
||||||
|
ATA_ER_ABRT = $04; //COMMAND ABORTED
|
||||||
|
ATA_ER_TK0NF = $02; //TRACK 0 NOT FOUND
|
||||||
|
ATA_ER_AMNF = $01; //NO ADDRESS MARK
|
||||||
|
|
||||||
|
ATA_CMD_READ_PIO = $20;
|
||||||
|
ATA_CMD_READ_PIO_EXT = $24;
|
||||||
|
ATA_CMD_READ_DMA = $C8;
|
||||||
|
ATA_CMD_READ_DMA_EXT = $25;
|
||||||
|
ATA_CMD_WRITE_PIO = $30;
|
||||||
|
ATA_CMD_WRITE_PIO_EXT = $34;
|
||||||
|
ATA_CMD_WRITE_DMA = $CA;
|
||||||
|
ATA_CMD_WRITE_DMA_EXT = $35;
|
||||||
|
ATA_CMD_CACHE_FLUSH = $E7;
|
||||||
|
ATA_CMD_CACHE_FLUSH_EXT = $EA;
|
||||||
|
ATA_CMD_PACKET = $A0;
|
||||||
|
ATA_CMD_IDENTIFY_PACKET = $A1;
|
||||||
|
ATA_CMD_IDENTIFY = $EC;
|
||||||
|
|
||||||
|
ATAPI_CMD_READ = $A8;
|
||||||
|
ATAPI_CMD_EJECT = $1B;
|
||||||
|
|
||||||
|
ATA_IDENT_DEVICETYPE = $0;
|
||||||
|
ATA_IDENT_CYLINDERS = $2;
|
||||||
|
ATA_IDENT_HEADS = $6;
|
||||||
|
ATA_IDENT_SECOTRS = $12;
|
||||||
|
ATA_IDENT_SERIAL = $20;
|
||||||
|
ATA_IDENT_MODEL = $54;
|
||||||
|
ATA_IDENT_CAPABILITIES = $98;
|
||||||
|
ATA_IDENT_FIELDVALID = $106;
|
||||||
|
ATA_IDENT_MAX_LBA = $120;
|
||||||
|
ATA_IDENT_COMMANDSETS = $164;
|
||||||
|
ATA_IDENT_MAX_LBA_EXT = $200;
|
||||||
|
|
||||||
|
ATA_REG_DATA = $00;
|
||||||
|
ATA_REG_ERROR = $01;
|
||||||
|
ATA_REG_FEATURES = $01;
|
||||||
|
ATA_REG_SECCOUNT = $02;
|
||||||
|
ATA_REG_LBA0 = $03;
|
||||||
|
ATA_REG_LBA1 = $04;
|
||||||
|
ATA_REG_LBA2 = $05;
|
||||||
|
ATA_REG_HDDEVSEL = $06;
|
||||||
|
ATA_REG_COMMAND = $07;
|
||||||
|
ATA_REG_STATUS = $07;
|
||||||
|
ATA_REG_SECCOUNT1 = $08;
|
||||||
|
ATA_REG_LBA3 = $09;
|
||||||
|
ATA_REG_LBA4 = $0A;
|
||||||
|
ATA_REG_LBA5 = $0B;
|
||||||
|
ATA_REG_CONTROL = $0C;
|
||||||
|
ATA_REG_ALTSTATUS = $0C;
|
||||||
|
ATA_REG_DEVADDRESS = $0D;
|
||||||
|
|
||||||
|
ATA_DEVICE_MASTER = $A0;
|
||||||
|
ATA_DEVICE_SLAVE = $B0;
|
||||||
|
|
||||||
|
ATA_PRIMARY_BASE = $1F0;
|
||||||
|
|
||||||
|
var
|
||||||
|
controller : PPCI_Device;
|
||||||
|
|
||||||
|
bar0 : uint32;
|
||||||
|
bar1 : uint32;
|
||||||
|
bar4 : uint32;
|
||||||
|
|
||||||
|
IDEDevices : array[0..3] of TIDE_Device;
|
||||||
|
|
||||||
|
buffer : Puint32;
|
||||||
|
|
||||||
|
procedure init();
|
||||||
|
function load(ptr : void) : boolean;
|
||||||
|
function identify_device(bus : uint8; device : uint8) : TIdentResponse;
|
||||||
|
|
||||||
|
// procedure flush();
|
||||||
|
procedure readPIO28(drive : uint8; LBA : uint32; buffer : puint8);
|
||||||
|
procedure writePIO28(drive : uint8; LBA : uint32; buffer : puint8);
|
||||||
|
//read/write must be capable of reading/writting any amknt of data upto disk size
|
||||||
|
|
||||||
|
procedure dread(device : PStorage_device; LBA : uint32; sectorCount : uint32; buffer : puint32);
|
||||||
|
procedure dwrite(device : PStorage_device; LBA : uint32; sectorCount : uint32; buffer : puint32);
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
|
function port_read(register : uint8) : uint8;
|
||||||
|
begin
|
||||||
|
port_read:= inb(ATA_PRIMARY_BASE + register);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure port_write(register : uint8; data : uint8);
|
||||||
|
var
|
||||||
|
i : uint8;
|
||||||
|
begin
|
||||||
|
outb(ATA_PRIMARY_BASE + register, data);
|
||||||
|
util.psleep(1);
|
||||||
|
if register = ATA_REG_COMMAND then begin
|
||||||
|
for i:= 0 to 5 do begin
|
||||||
|
port_read(ATA_REG_STATUS);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure no_interrupt(device : uint8);
|
||||||
|
begin
|
||||||
|
outb($3F6, inb($3f6) or (1 shl 1));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure device_select(device : uint8);
|
||||||
|
begin
|
||||||
|
outb($1F6, device); //TODO clean
|
||||||
|
end;
|
||||||
|
|
||||||
|
function is_ready() : boolean;
|
||||||
|
var
|
||||||
|
status : uint8;
|
||||||
|
i : uint32;
|
||||||
|
begin
|
||||||
|
//wait for drive to be ready
|
||||||
|
while true do begin
|
||||||
|
status := port_read(ATA_REG_COMMAND);
|
||||||
|
|
||||||
|
if(status and ATA_SR_ERR) = ATA_SR_ERR then begin
|
||||||
|
console.writestringln('[IDE] (IDENTIFY_DEVICE) DRIVE ERROR!');
|
||||||
|
console.redrawWindows();
|
||||||
|
is_ready := false;
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if (status and ATA_SR_BUSY) <> ATA_SR_BUSY then begin
|
||||||
|
is_ready := true;
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function validate_28bit_address(addr : uint32) : boolean;
|
||||||
|
begin
|
||||||
|
validate_28bit_address := (addr and $F0000000) = 0;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function identify_device(bus : uint8; device : uint8) : TIdentResponse;
|
||||||
|
var
|
||||||
|
status : uint8;
|
||||||
|
identResponse : TIdentResponse;
|
||||||
|
i : uint8;
|
||||||
|
begin
|
||||||
|
push_trace('IDE.Identify_Device');
|
||||||
|
device_select(device);
|
||||||
|
no_interrupt(device);
|
||||||
|
port_write(ATA_REG_CONTROL, 0);
|
||||||
|
|
||||||
|
console.writestringln('[IDE] (IDENTIFY_DEVICE) CHECK FLOATING BUS');
|
||||||
|
|
||||||
|
//check if bus is floating
|
||||||
|
status := port_read(ATA_REG_COMMAND);
|
||||||
|
if status = $FF then exit;
|
||||||
|
|
||||||
|
port_write(ATA_REG_SECCOUNT, 0);
|
||||||
|
port_write(ATA_REG_LBA0, 0);
|
||||||
|
port_write(ATA_REG_LBA1, 0);
|
||||||
|
port_write(ATA_REG_LBA2, 0);
|
||||||
|
|
||||||
|
console.writestringln('[IDE] (IDENTIFY_DEVICE) SEND IDENTIFY COMMAND');
|
||||||
|
|
||||||
|
port_write(ATA_REG_COMMAND, ATA_CMD_IDENTIFY);
|
||||||
|
|
||||||
|
console.writestringln('[IDE] (IDENTIFY_DEVICE) WAIT FOR DRIVE TO BE READY');
|
||||||
|
|
||||||
|
//check if drive is present
|
||||||
|
status := port_read(ATA_REG_COMMAND);
|
||||||
|
if status = $00 then exit;
|
||||||
|
|
||||||
|
console.writestringln('[IDE] (IDENTIFY_DEVICE) WAIT FOR DRIVE TO BE READY');
|
||||||
|
|
||||||
|
if not is_ready() then exit;
|
||||||
|
|
||||||
|
console.writestringln('[IDE] (IDENTIFY_DEVICE) READ IDENTIFY RESPONSE');
|
||||||
|
|
||||||
|
for i:=0 to 255 do begin
|
||||||
|
console.writeint(i);
|
||||||
|
identResponse[i] := inw(ATA_PRIMARY_BASE + ATA_REG_DATA);
|
||||||
|
end;
|
||||||
|
|
||||||
|
console.writestringln('[IDE] (IDENTIFY_DEVICE) IDENTIFY RESPONSE RECEIVED');
|
||||||
|
|
||||||
|
identify_device := identResponse;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure init();
|
||||||
|
var
|
||||||
|
devID : TDeviceIdentifier;
|
||||||
|
begin
|
||||||
|
push_trace('ide.init');
|
||||||
|
console.writestringln('[IDE] (INIT) BEGIN');
|
||||||
|
devID.bus:= biPCI;
|
||||||
|
devID.id0:= idANY;
|
||||||
|
devID.id1:= $00000001;
|
||||||
|
devID.id2:= $00000001;
|
||||||
|
devID.id3:= idANY;
|
||||||
|
devID.id4:= idANY;
|
||||||
|
devID.ex:= nil;
|
||||||
|
drivermanagement.register_driver('IDE ATA Driver', @devID, @load);
|
||||||
|
console.writestringln('[IDE] (INIT) END');
|
||||||
|
end;
|
||||||
|
|
||||||
|
function load(ptr : void) : boolean;
|
||||||
|
var
|
||||||
|
controller : PPCI_Device;
|
||||||
|
masterDevice : TStorage_Device;
|
||||||
|
slaveDevice : TStorage_Device;
|
||||||
|
buffer : puint8;
|
||||||
|
i : uint8;
|
||||||
|
test : PStorage_device;
|
||||||
|
tbuf : puint8;
|
||||||
|
begin
|
||||||
|
push_trace('ide.load');
|
||||||
|
console.writestringln('[IDE] (LOAD) BEGIN');
|
||||||
|
controller := PPCI_Device(ptr);
|
||||||
|
|
||||||
|
console.writestringln('[IDE] (INIT) CHECK FLOATING BUS');
|
||||||
|
//check if bus is floating and identify device
|
||||||
|
if inb($1F7) <> $FF then begin
|
||||||
|
//outb($3F6, inb($3f6) or (1 shl 1)); // disable interrupts
|
||||||
|
IDEDevices[0].isMaster:= true;
|
||||||
|
IDEDevices[0].info := identify_device(0, ATA_DEVICE_MASTER);
|
||||||
|
e
|
||||||
|
mastrDevice.controller := ControllerIDE;
|
||||||
|
masterDevice.controllerId0:= 0;
|
||||||
|
masterDevice.maxSectorCount:= (IDEDevices[0].info[60] or (IDEDevices[0].info[61] shl 16) ); //LBA28 SATA
|
||||||
|
|
||||||
|
if IDEDevices[0].info[1] = 0 then begin
|
||||||
|
console.writestringln('[IDE] (INIT) ERROR: DEVICE IDENT FAILED!');
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// masterDevice.hpc:= uint32(IDEDevices[0].info[3] DIV IDEDevices[0].info[1]); //TODO wtf is hpc
|
||||||
|
|
||||||
|
masterDevice.sectorSize:= 512;
|
||||||
|
if masterDevice.maxSectorCount <> 0 then begin
|
||||||
|
IDEDevices[0].exists:= true;
|
||||||
|
masterDevice.readCallback:= @dread;
|
||||||
|
masterDevice.writeCallback:= @dwrite;
|
||||||
|
// storagemanagement.register_device(@masterDevice);
|
||||||
|
drivemanager.register_device(@masterDevice);
|
||||||
|
end;
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
// buffer:= puint8(kalloc(512));
|
||||||
|
// buffer[0] := 1;
|
||||||
|
// buffer[1] := 2;
|
||||||
|
// buffer[2] := 3;
|
||||||
|
// buffer[3] := 4;
|
||||||
|
// buffer[4] := 5;
|
||||||
|
// buffer[5] := 6;
|
||||||
|
// writePIO28(0, 3, buffer);
|
||||||
|
// writePIO28(0, 3, buffer);
|
||||||
|
// writePIO28(0, 3, buffer);
|
||||||
|
// writePIO28(0, 4, buffer);
|
||||||
|
// writePIO28(0, 5, buffer);
|
||||||
|
// writePIO28(0, 5, buffer);
|
||||||
|
// writePIO28(0, 5, buffer);
|
||||||
|
// psleep(1000);
|
||||||
|
// writePIO28(0, 5, buffer);
|
||||||
|
// writePIO28(0, 5, buffer);
|
||||||
|
// writePIO28(0, 5, buffer);
|
||||||
|
// kfree(puint32(buffer));
|
||||||
|
|
||||||
|
console.writestringln('[IDE] (LOAD) END');
|
||||||
|
|
||||||
|
//read first 16 bytes of disk
|
||||||
|
tbuf:= puint8(kalloc(512));
|
||||||
|
|
||||||
|
//set buffer to 1F1F repeating
|
||||||
|
for i:=0 to 200 do begin
|
||||||
|
tbuf[i] := 31;
|
||||||
|
end;
|
||||||
|
|
||||||
|
//write buffer to disk
|
||||||
|
writePIO28(0, 0, tbuf);
|
||||||
|
|
||||||
|
memset(uint32(tbuf), 0, 512);
|
||||||
|
readPIO28(0, 0, puint8(tbuf));
|
||||||
|
console.writestringln('[IDE] (INIT) READ FIRST 4 BYTES OF DISK');
|
||||||
|
console.writehexln(tbuf[0]);
|
||||||
|
console.writehexln(tbuf[1]);
|
||||||
|
console.writehexln(tbuf[2]);
|
||||||
|
console.writehexln(tbuf[3]);
|
||||||
|
kfree(puint32(tbuf));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure readPIO28(drive : uint8; LBA : uint32; buffer : puint8);
|
||||||
|
var
|
||||||
|
status : uint8;
|
||||||
|
i: uint16;
|
||||||
|
device: uint8;
|
||||||
|
data: uint16;
|
||||||
|
begin
|
||||||
|
push_trace('IDE.readPIO28');
|
||||||
|
|
||||||
|
if not validate_28bit_address(LBA) then begin
|
||||||
|
console.writestringln('IDE (writePIO28) ERROR: Invalid LBA!');
|
||||||
|
end;
|
||||||
|
|
||||||
|
// push_trace('IDE.readPIO28.2');
|
||||||
|
|
||||||
|
//Add last 4 bits of LBA to device port
|
||||||
|
if IDEDevices[drive].isMaster then begin
|
||||||
|
device:= ATA_DEVICE_MASTER;
|
||||||
|
device_select($E0 or ((LBA and $0F000000) shr 24)); //LBA primary master
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
device:= ATA_DEVICE_SLAVE;
|
||||||
|
device_select($F0 or ((LBA and $0F000000) shr 24)); //LBA primary slave
|
||||||
|
end;
|
||||||
|
|
||||||
|
// push_trace('IDE.readPIO28.3');
|
||||||
|
|
||||||
|
no_interrupt(device);
|
||||||
|
port_write(ATA_REG_ERROR, 0);
|
||||||
|
|
||||||
|
//Write sector count and LBA
|
||||||
|
port_write(ATA_REG_SECCOUNT, 1);
|
||||||
|
port_write(ATA_REG_LBA0, (LBA and $000000FF));
|
||||||
|
port_write(ATA_REG_LBA1, (LBA and $0000FF00) shr 8);
|
||||||
|
port_write(ATA_REG_LBA2, (LBA and $00FF0000) shr 16);
|
||||||
|
|
||||||
|
// push_trace('IDE.readPIO28.4');
|
||||||
|
|
||||||
|
//send read command
|
||||||
|
port_write(ATA_REG_COMMAND, ATA_CMD_READ_PIO);
|
||||||
|
if not is_ready() then exit;
|
||||||
|
|
||||||
|
i:=0;
|
||||||
|
while i < 512 do begin
|
||||||
|
// if not is_ready() then exit;
|
||||||
|
|
||||||
|
data:= inw(ATA_PRIMARY_BASE + ATA_REG_DATA);
|
||||||
|
|
||||||
|
buffer[i+1] := uint8($00ff and (data shr 8));
|
||||||
|
buffer[i] := uint8($00ff and data);
|
||||||
|
|
||||||
|
i:= i + 2;
|
||||||
|
|
||||||
|
if not is_ready() then exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
// push_trace('IDE.readPIO28.5');
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure writePIO28(drive : uint8; LBA : uint32; buffer : puint8);
|
||||||
|
var
|
||||||
|
status : uint8;
|
||||||
|
i: uint16;
|
||||||
|
device: uint8;
|
||||||
|
begin
|
||||||
|
push_trace('IDE.WritePIO28');
|
||||||
|
if not validate_28bit_address(LBA) then begin
|
||||||
|
console.writestringln('IDE (writePIO28) ERROR: Invalid LBA!');
|
||||||
|
end;
|
||||||
|
|
||||||
|
console.writeintln(uint32(drive));
|
||||||
|
console.writeintln(LBA);
|
||||||
|
|
||||||
|
//Add last 4 bits of LBA to device port
|
||||||
|
if IDEDevices[drive].isMaster then begin
|
||||||
|
device:= ATA_DEVICE_MASTER;
|
||||||
|
device_select($E0 or ((LBA and $0F000000) shr 24)); //LBA primary master
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
device:= ATA_DEVICE_SLAVE;
|
||||||
|
device_select($F0 or ((LBA and $0F000000) shr 24)); //LBA primary slave
|
||||||
|
end;
|
||||||
|
|
||||||
|
// no_interrupt(device);
|
||||||
|
|
||||||
|
port_write(ATA_REG_ERROR, 0);
|
||||||
|
port_write(ATA_REG_CONTROL, 0);
|
||||||
|
|
||||||
|
// check if bus is floating
|
||||||
|
status := port_read(ATA_REG_COMMAND);
|
||||||
|
if status = $FF then exit;
|
||||||
|
|
||||||
|
//Write sector count and LBA
|
||||||
|
port_write(ATA_REG_SECCOUNT, 1);
|
||||||
|
port_write(ATA_REG_LBA0, (LBA and $000000FF));
|
||||||
|
port_write(ATA_REG_LBA1, (LBA and $0000FF00) shr 8);
|
||||||
|
port_write(ATA_REG_LBA2, (LBA and $00FF0000) shr 16);
|
||||||
|
|
||||||
|
//send write command
|
||||||
|
port_write(ATA_REG_COMMAND, ATA_CMD_WRITE_PIO);
|
||||||
|
|
||||||
|
//write data
|
||||||
|
i:=0;
|
||||||
|
while i < 512 do begin
|
||||||
|
outw(ATA_PRIMARY_BASE + ATA_REG_DATA, uint16(buffer[i] or (buffer[i+1] shl 8)));
|
||||||
|
i:= i + 2;
|
||||||
|
end;
|
||||||
|
|
||||||
|
//flush drive cache
|
||||||
|
psleep(1);
|
||||||
|
port_write(ATA_REG_COMMAND, ATA_CMD_CACHE_FLUSH);
|
||||||
|
psleep(1);
|
||||||
|
if not is_ready() then exit;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure dread(device : PStorage_device; LBA : uint32; sectorCount : uint32; buffer : Puint32);
|
||||||
|
var
|
||||||
|
i : uint16;
|
||||||
|
begin
|
||||||
|
push_trace('IDE.dread');
|
||||||
|
for i:=0 to sectorCount-1 do begin
|
||||||
|
readPIO28(device^.controllerId0, LBA + i, puint8(@buffer[512*i]));
|
||||||
|
psleep(100)
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure dwrite(device : PStorage_device; LBA : uint32; sectorCount : uint32; buffer : Puint32);
|
||||||
|
var
|
||||||
|
i : uint16;
|
||||||
|
begin
|
||||||
|
for i:=0 to sectorCount-1 do begin
|
||||||
|
writePIO28(device^.controllerId0, LBA + i, puint8(@buffer[512*i]));
|
||||||
|
psleep(100)
|
||||||
|
end;
|
||||||
|
// writePIO28(device^.controllerId0, LBA, puint8(buffer));
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
@ -82,7 +82,8 @@ implementation
|
|||||||
function controller_type_2_string(controllerType : TControllerType) : pchar;
|
function controller_type_2_string(controllerType : TControllerType) : pchar;
|
||||||
begin
|
begin
|
||||||
case controllerType of
|
case controllerType of
|
||||||
ControllerIDE : controller_type_2_string:= 'IDE';
|
ControllerATA : controller_type_2_string:= 'ATA';
|
||||||
|
ControllerATAPI : controller_type_2_string:= 'ATAPI';
|
||||||
ControllerUSB : controller_type_2_string:= 'USB';
|
ControllerUSB : controller_type_2_string:= 'USB';
|
||||||
ControllerAHCI : controller_type_2_string:= 'ACHI (SATA)';
|
ControllerAHCI : controller_type_2_string:= 'ACHI (SATA)';
|
||||||
ControllerNET : controller_type_2_string:= 'Net';
|
ControllerNET : controller_type_2_string:= 'Net';
|
||||||
|
@ -26,7 +26,7 @@ uses
|
|||||||
|
|
||||||
type
|
type
|
||||||
|
|
||||||
TControllerType = (ControllerIDE, ControllerUSB, ControllerAHCI,
|
TControllerType = (ControllerATA, ControllerATAPI, ControllerUSB, ControllerAHCI,
|
||||||
ControllerNET, ControllerRAM, rsvctr1, rsvctr2, rsvctr3);
|
ControllerNET, ControllerRAM, rsvctr1, rsvctr2, rsvctr3);
|
||||||
|
|
||||||
PStorage_device = ^TStorage_Device;
|
PStorage_device = ^TStorage_Device;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user