small problem with ATA
small problem with ATA
new problem, see next post
okay, i fixed the last problem, but now i got another
my readATAsector code
my get_sector function
my ATA_SECTOR struct
my code to handle IRQ 14
and my main
now my problem is that only the first readATAsector function returns anything. I can't figure out why.
my readATAsector code
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(;;);
}
Pyrofan1,
I am not a C programmer but I can tell you that if you don't negate the INTRQ in IDE, you will not be able to read any sectors other than the first sector. The INTRQ (Interrupt Request) can be negated when you use the Status Register of the selected IDE Controller or its Alternate Status Register. When you read a sector using the Read Sector(s) command, read the status register (right before reading one sector) and ignore the results. Reading the Alternate Status Register is also recommended (as stated in ATA-4 specifications).
I have coded many ATA codes and one of them is called [__ATA4IDEReadFromPortsLBA28]. I will put the part that reads the requested sectors below so you can get the idea:
Before reading any sectors, do these:
• Make sure BSY is is 0 (in the Status Register).
• Make sure the DRQ bit is 1 (in the Status Register).
• If the nIEN bit is cleared in the Device Control Register, sense the interrupt (wait for the interrupt).
• Read the Status Register and ignore the result.
• Read one sector from the Data Register.
• If there are more sectors left to be read, repeat the above steps from the beginning.
• Once you are done reading the sectors, read the Status Register and the Alternate Status Register and ignore the results.
And one more thing, make sure the nIEN bit in the Device Control Register is cleared as it will allow you to receive interrupts when they are fired.
Good luck.
I am not a C programmer but I can tell you that if you don't negate the INTRQ in IDE, you will not be able to read any sectors other than the first sector. The INTRQ (Interrupt Request) can be negated when you use the Status Register of the selected IDE Controller or its Alternate Status Register. When you read a sector using the Read Sector(s) command, read the status register (right before reading one sector) and ignore the results. Reading the Alternate Status Register is also recommended (as stated in ATA-4 specifications).
I have coded many ATA codes and one of them is called [__ATA4IDEReadFromPortsLBA28]. I will put the part that reads the requested sectors below so you can get the idea:
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
Before reading any sectors, do these:
• Make sure BSY is is 0 (in the Status Register).
• Make sure the DRQ bit is 1 (in the Status Register).
• If the nIEN bit is cleared in the Device Control Register, sense the interrupt (wait for the interrupt).
• Read the Status Register and ignore the result.
• Read one sector from the Data Register.
• If there are more sectors left to be read, repeat the above steps from the beginning.
• Once you are done reading the sectors, read the Status Register and the Alternate Status Register and ignore the results.
And one more thing, make sure the nIEN bit in the Device Control Register is cleared as it will allow you to receive interrupts when they are fired.
Good luck.
On the field with sword and shield amidst the din of dying of men's wails. War is waged and the battle will rage until only the righteous prevails.