small problem with ATA
Posted: Mon Jul 30, 2007 9:36 pm
new problem, see next post
The Place to Start for Operating System Developers
http://f.osdev.org/
Code: Select all
#define ATA_DATA_REGISTER 0x1F0
#define ATA_ERROR_REGISTER 0x1F1
#define ATA_SECTORS_REGISTER 0x1F2
#define ATA_SECTOR_NUMBER 0x1F3
#define ATA_CYLINDERS_LOW 0x1F4
#define ATA_CYLINDERS_HIGH 0x1F5
#define ATA_DRIVE_HEAD 0x1F6
#define ATA_STATUS_REGISTER 0x1F7
#define ATA_COMMAND_REGISTER 0x1F7
#define ATA_FORMAT_TRACK 0x50
#define ATA_READ_SECTOR_RETRY 0x20
#define ATA_READ_SECTOR 0x21
#define ATA_READ_LONG_RETRY 0x22
#define ATA_READ_LONG 0x23
#define ATA_WRITE_SECTOR_RETRY 0x30
#define ATA_WRITE_SECTOR 0x31
#define ATA_WRITE_LONG_RETRY 0x32
#define ATA_WRITE_LONG 0x33
#define ATA_DRIVE_BUSY 0x80
#define ATA_DRIVE_READY 0x40
#define ATA_WRITE_FAULT 0x20
#define ATA_SEEK_COMPLETE 0x10
#define ATA_BUFFER_SECTOR 0x08
#define ATA_DATA_CORRECTION 0x04
#define ATA_INDEX 0x02
#define ATA_ERROR 0x01
struct ATA_SECTOR get_sector(void);
struct ATA_SECTOR readATAsector(unsigned char drive,unsigned char head,unsigned char cylinders_low,unsigned char cylinders_high,unsigned char sector)
{
unsigned char drive_head;
struct ATA_SECTOR s;
if(drive==0)
{
drive_head=0xA0;
}
else
{
drive_head=0xB0;
}
while(1)
{
if((inportb(ATA_STATUS_REGISTER)&ATA_DRIVE_BUSY)!=ATA_DRIVE_BUSY) break;
}
drive_head=drive_head|head;
outportb(ATA_DRIVE_HEAD,drive_head);
outportb(ATA_SECTORS_REGISTER,1);
outportb(ATA_SECTOR_NUMBER,sector);
outportb(ATA_CYLINDERS_LOW,cylinders_low);
outportb(ATA_CYLINDERS_HIGH,cylinders_high);
outportb(ATA_COMMAND_REGISTER,ATA_READ_SECTOR_RETRY);
s=get_sector();
s.drive=drive;
s.head=head;
s.cylinders_high=cylinders_high;
s.cylinders_low=cylinders_low;
s.sector=sector;
return s;
}
Code: Select all
struct ATA_SECTOR get_sector(void)
{
while(sector.read==0);
sector.read=0;
return sector;
}
Code: Select all
struct ATA_SECTOR
{
unsigned char data;
unsigned char sector;
unsigned char cylinders_high;
unsigned char cylinders_low;
unsigned char drive;
unsigned char head;
unsigned char read;
};
Code: Select all
sector.data=inportb(0x1F0);
sector.read=1;
if((inportb(0x1F7)&0x01)==0x01) sector.data=-1;
Code: Select all
void _main(void* mbd,unsigned int magic)
{
struct ATA_SECTOR s;
struct ATA_SECTOR a;
kinit();
Printf("hello world!\n");
s=readATAsector(0,0,69,69,1);
if(s.data!=-1)
{
putchar(s.data);
}
else
{
Printf("\nATA error\n");
}
a=readATAsector(0,0,69,69,1);
if(a.data!=-1)
{
putchar(a.data);
}
else
{
Printf("\nATA error\n");
}
for(;;);
}
Code: Select all
.StartReadingData:
; When the device is ready to transfer the data, it will clear BSY and set DRQ
MOV EDX , EBX
ADD EDX , IDE_PORT_OFFSET_STATUS
MOV ECX , IDE_TYPICAL_TIMEOUT
XOR EAX , EAX
.WaitForBSYAndDRQ:
NOP
IN AL , DX
AND EAX , (IDE_STATUSREG_BSY | IDE_STATUSREG_DRQ)
XOR EAX , IDE_STATUSREG_DRQ
JZ .PrepareToSenseInterrupt
DEC ECX
JNZ .WaitForBSYAndDRQ
JMP .Failure
.PrepareToSenseInterrupt:
MOV EAX , IRQ_PULSE_IRQ14
CMP EBX , PIDEC_PORT_BASE
JE .SenseInterrupt
MOV EAX , IRQ_PULSE_IRQ15
.SenseInterrupt:
INVOKE __WaitForIRQPulse, EAX
.CheckStatusRegister1:
; EDX = Status Register's port address
IN AL , DX
.ReadData:
; EDI = [Buffer]
CLD
MOV EDX , EBX
ADD EDX , IDE_PORT_OFFSET_DATA
MOV ECX , 512 / 2 ; We are reading 2 bytes at a time and one sector after the other
REP INSW
DEC ESI
JNZ .StartReadingData
; Now that the data is read, we should first read the Alternate Status Register and ignore the result
; EBX = The base port address of the selected controller
.ReadAlternateStatusRegister:
MOV EDX , IDEC_PORT_ALTERNATESTATUS
IN AL , DX
TIMES 0x04 NOP
; Reading the Status Register is also recommended by ATA-4 specifications
.ReadStatusRegister:
; EBX = The base port address of the selected controller
MOV EDX , EBX
ADD EDX , IDE_PORT_OFFSET_STATUS
IN AL , DX
TIMES 0x04 NOP