atapi progress

This commit is contained in:
Aaron Hance 2025-03-10 22:38:50 +00:00
parent 920aca5bbf
commit fd0de9f1d2
2 changed files with 256 additions and 25 deletions

View File

@ -4,6 +4,7 @@ interface
uses uses
ata, ata,
atapi,
util, util,
drivertypes, drivertypes,
console, console,
@ -243,10 +244,12 @@ var
buffer : puint8; buffer : puint8;
storageDevice : PStorage_device; storageDevice : PStorage_device;
success : boolean; success : boolean;
size : uint32;
begin begin
push_trace('ide.load_device()'); push_trace('ide.load_device()');
success := check_device_type(device); success := check_device_type(device);
select_device(device);
if (is_device_present(device) and success) then begin if (is_device_present(device) and success) then begin
console.writestringln('[IDE] (load_device) Device is present'); console.writestringln('[IDE] (load_device) Device is present');
@ -254,9 +257,28 @@ begin
if (device.isATAPI) then begin if (device.isATAPI) then begin
console.writestringln('[IDE] (load_device) Device is ATAPI'); console.writestringln('[IDE] (load_device) Device is ATAPI');
//todo load device info //todo load device info
success := atapi.identify_device(device);
device.exists := true;
device.isATAPI := true;
end else begin end else begin
console.writestringln('[IDE] (load_device) Device is ATA'); console.writestringln('[IDE] (load_device) Device is ATA');
success:= ata.identify_device(device); success:= ata.identify_device(device);
//check if atapi device using info from identify_device
console.writestringln('[IDE] (load_device) Device info: ');
console.writecharln(char(puint8(device.info)[252]));
console.writecharln(char(puint8(device.info)[253]));
if (puint8(device.info)[253] = $FF) then begin
console.writestringln('[IDE] (load_device) Device is ATAPI');
device.isATAPI := true;
device.exists := true;
success := atapi.identify_device(device);
end;
end; end;
if not success then begin if not success then begin
@ -273,6 +295,36 @@ begin
if (device.isATAPI) then begin if (device.isATAPI) then begin
storageDevice^.controller := TControllerType.ControllerATAPI; storageDevice^.controller := TControllerType.ControllerATAPI;
storageDevice^.writable := false; //TODO atapi storageDevice^.writable := false; //TODO atapi
size := atapi.get_device_size(device);
storageDevice^.maxSectorCount := size;
storageDevice^.sectorSize := 2048; //todo
if (device.isMaster) then begin
storageDevice^.controllerId0 := 0;
end else begin
storageDevice^.controllerId0 := 1;
end;
//read and print first sector
buffer := puint8(kalloc(2048));
memset(uint32(buffer), 11, 2048);
atapi.read_pio28(device, 11, 1, puint16(buffer));
console.writestringln('[IDE] (load_device) First sector of ATAPI device: ');
for i:=0 to 16 do begin
console.writehexln(buffer[i]);
end;
memset(uint32(buffer), 0, 2048);
atapi.read_pio28(device, 5200, 1, puint16(buffer));
console.writestringln('[IDE] (load_device) First sector of ATAPI device: ');
for i:=0 to 16 do begin
console.writehexln(buffer[i]);
end;
end else begin end else begin
storageDevice^.controller := TControllerType.ControllerATA; storageDevice^.controller := TControllerType.ControllerATA;
storageDevice^.writable := true; storageDevice^.writable := true;
@ -292,30 +344,30 @@ begin
exit; exit;
end; end;
//wrtie test, 1F2F1F2F repeated // //wrtie test, 1F2F1F2F repeated
buffer := puint8(kalloc(1024)); // buffer := puint8(kalloc(1024));
memset(uint32(buffer), $02, 1024); // memset(uint32(buffer), $02, 1024);
uint8(buffer[0]) := $1F; // uint8(buffer[0]) := $1F;
uint8(buffer[1]) := $2F; // uint8(buffer[1]) := $2F;
uint8(buffer[2]) := $3F; // uint8(buffer[2]) := $3F;
uint8(buffer[3]) := $4F; // uint8(buffer[3]) := $4F;
uint8(buffer[4]) := $5F; // uint8(buffer[4]) := $5F;
uint8(buffer[5]) := $6F; // uint8(buffer[5]) := $6F;
uint8(buffer[6]) := $7F; // uint8(buffer[6]) := $7F;
uint8(buffer[7]) := $8F; // uint8(buffer[7]) := $8F;
//write to the first sector // //write to the first sector
ata.write_pio28(device, 10, 2, puint16(buffer)); // ata.write_pio28(device, 10, 2, puint16(buffer));
//read the first sector // //read the first sector
memset(uint32(buffer), 0, 512); // memset(uint32(buffer), 0, 512);
ata.read_pio28(device, 10, 1, puint16(buffer)); // ata.read_pio28(device, 10, 1, puint16(buffer));
//check if the data is the same // //check if the data is the same
for i:=0 to 10 do begin // for i:=0 to 10 do begin
console.writehexln(buffer[i]); // console.writehexln(buffer[i]);
end; // end;
end; end;
//register the device //register the device

View File

@ -24,11 +24,20 @@ var
function identify_device(var device : TIDE_Device) : Boolean; function identify_device(var device : TIDE_Device) : Boolean;
function read_pio28(device : TIDE_Device; lba : uint32; count : uint8; buffer : puint16) : 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; function write_pio28(device : TIDE_Device; lba : uint32; count : uint8; buffer : puint16) : boolean;
function get_device_size(device : TIDE_Device) : uint32;
implementation implementation
uses uses
ide; ide, ata;
procedure outb(port : uint16; value : uint8);
begin
util.outb(port, value);
psleep(1);
// get_status(primaryDevices[0]);
end;
{ {
Identify the device on the IDE bus Identify the device on the IDE bus
@ -46,6 +55,10 @@ begin
select_device(device); select_device(device);
no_interrupt(device.isPrimary); no_interrupt(device.isPrimary);
outb(ATA_PRIMARY_BASE1, $04);
outb(ATA_SECONDARY_BASE1, $04);
sleep(1);
status := get_status(device); status := get_status(device);
outb(device.base + ATA_REG_SECCOUNT, 0); outb(device.base + ATA_REG_SECCOUNT, 0);
@ -81,16 +94,77 @@ begin
identify_device := true; identify_device := true;
end; end;
function read_pio28(device : TIDE_Device; lba : uint32; count : uint8; buffer : puint16) : boolean; function read_PIO28(device : TIDE_Device; lba : uint32; count : uint8; buffer : puint16) : boolean;
var var
i : uint16; i, j : uint16;
ii : uint16;
status : TIDE_Status; status : TIDE_Status;
ready : boolean; ready : boolean;
packet : array[0..11] of uint8;
begin begin
push_trace('read_PIO28()');
if not device.isATAPI then begin
console.writestringln('[ATAPI] Device is not an ATAPI device!');
read_PIO28 := false;
exit;
end;
select_device(device);
no_interrupt(device.isPrimary);
// Step 1: Send PACKET command
outb(device.base + ATA_REG_FEATURES, 0); // No special features
outb(device.base + ATA_REG_SECCOUNT, 0); // ATAPI requires this to be 0
outb(device.base + ATA_REG_LBA0, (2048 shr 0) and $FF); // Byte size of transfer (2048 for CDs)
outb(device.base + ATA_REG_LBA1, (2048 shr 8) and $FF);
outb(device.base + ATA_REG_LBA2, 0); // Reserved
outb(device.base + ATA_REG_COMMAND, ATA_CMD_PACKET);
// Step 2: Wait for DRQ=1 (drive wants a command packet)
ready := wait_for_device(device, true);
if not ready then begin
console.writestringln('[ATAPI] Timeout waiting for PACKET DRQ!');
read_PIO28 := false;
exit;
end;
// Step 3: Prepare 12-byte SCSI CDB (Read Sectors Command 0xA8)
packet[0] := $A8; // ATAPI READ (10) command
packet[1] := 0; // Reserved
packet[2] := (lba shr 24) and $FF; // LBA high byte
packet[3] := (lba shr 16) and $FF;
packet[4] := (lba shr 8) and $FF;
packet[5] := (lba shr 0) and $FF;
packet[6] := 0; // Reserved
packet[7] := count; // Number of sectors to read
packet[8] := 0; // Reserved
packet[9] := 0; // Control
// Step 4: Send the command packet
for i := 0 to 5 do
outw(device.base + ATA_REG_DATA, (packet[i*2] or (packet[i*2+1] shl 8)));
// Step 5: Wait for DRQ=1 (data ready)
ready := wait_for_device(device, true);
if not ready then begin
console.writestringln('[ATAPI] Timeout waiting for data DRQ!');
read_PIO28 := false;
exit;
end;
// Step 6: Read the data (count * 2048 bytes)
for i := 0 to (count * 1024) - 1 do begin
for j := 0 to 255 do begin
buffer[i * 256 + j] := inw(device.base + ATA_REG_DATA);
end;
end;
// Success
read_PIO28 := true;
pop_trace();
end; end;
function write_pio28(device : TIDE_Device; lba : uint32; count : uint8; buffer : puint16) : boolean; function write_pio28(device : TIDE_Device; lba : uint32; count : uint8; buffer : puint16) : boolean;
var var
i : uint16; i : uint16;
@ -98,7 +172,112 @@ var
status : TIDE_Status; status : TIDE_Status;
ready : boolean; ready : boolean;
begin begin
write_pio28 := false;
end; end;
function get_device_size(device: TIDE_Device): uint32;
var
i: uint8;
ready: boolean;
packet: puint16; // Will hold our 10-byte CDB (as 5 words)
response: puint16; // Will hold the 8-byte capacity response
xferCount: uint16;
begin
get_device_size := 0;
// 1) Select the device (Master/Slave) - presumably your function
select_device(device);
// 2) We set "no special features" for ATAPI
outb(device.base + ATA_REG_FEATURES, 0);
// 3) Indicate how many bytes we expect from the drive.
// Usually we place "MaxByteCount" in LBA1:LBA2.
// We need at least 8 bytes for READ CAPACITY(10).
// We'll do 8 => low byte in LBA1, high byte in LBA2.
outb(device.base + ATA_REG_LBA1, $08);
outb(device.base + ATA_REG_LBA2, $00);
// 4) Send the "PACKET" command (0xA0) to start an ATAPI packet transfer
outb(device.base + ATA_REG_COMMAND, ATA_CMD_PACKET);
// 5) Build our 10-byte SCSI "READ CAPACITY(10)" command descriptor block (CDB)
// We'll store it in 5 words = 10 bytes
packet := puint16(kalloc(10)); // 5 * 2 = 10 bytes
memset(uint32(packet), 0, 10);
// READ CAPACITY(10) = opcode 0x25
// The rest can be 0 for a basic capacity read
// We'll store it as little-endian 16-bit words:
// packet[0] = 0x0025 means low byte=0x25 (opcode), high byte=0x00
packet[0] := $0025; // cdb[0..1]
packet[1] := 0; // cdb[2..3]
packet[2] := 0; // cdb[4..5]
packet[3] := 0; // cdb[6..7]
packet[4] := 0; // cdb[8..9]
// 6) Wait for drive to be ready to receive the CDB
ready := wait_for_device(device, false);
if not ready then
begin
console.writestringln('Device not ready to receive READ CAPACITY(10) CDB.');
exit;
end;
// 7) Write our 5 words (10 bytes) of CDB to the drive
for i := 0 to 4 do
begin
outw(device.base + ATA_REG_DATA, packet[i]);
psleep(1); // short delay
end;
// Free the CDB memory
// kfree(uint32(packet));
// 8) Wait for next phase (the data phase). The device should assert DRQ
// if it has data to send. We'll poll again.
ready := wait_for_device(device, false);
if not ready then
begin
console.writestringln('Drive not ready after sending the CDB.');
exit;
end;
// 9) The drive indicates how many bytes its about to send in LBA1:LBA2
xferCount := (inb(device.base + ATA_REG_LBA2) shl 8) or inb(device.base + ATA_REG_LBA1);
if xferCount < 8 then
begin
console.writestringln('Drive is returning less than 8 bytes for capacity!');
exit;
end;
// 10) Allocate space for the 8-byte result
response := puint16(kalloc(8));
memset(uint32(response), 0, 8);
// We'll read 4 words = 8 bytes from the data register
for i := 0 to 3 do
begin
response[i] := inw(device.base + ATA_REG_DATA);
psleep(1);
ready := wait_for_device(device, false);
if not ready then
begin
console.writestringln('Device got stuck while reading capacity data!');
exit;
end;
end;
// 11) Now parse the returned 8 bytes:
// - first 4 bytes = last LBA
// - next 4 bytes = block size
console.writestring('Device sector count: ');
console.writeintln(puint32(response)[0]); // last LBA
console.writestring('Device sector size: ');
console.writeintln(puint32(response)[1]); // block size
// Return the LBA as "size" (some drivers do lastLBA+1).
get_device_size := puint32(response)[1];
end;
end. end.