ATA Identify drive
ATA Identify drive
Hello,
Is ATA Identify drive command 0xEC is for real mode only?
I have a code for Identifying Drive that works in real mode but not in protected mode. I got the code from Hale Hilandis Ata driver.
Can you suggest something.
Thank u very much in advance.
Is ATA Identify drive command 0xEC is for real mode only?
I have a code for Identifying Drive that works in real mode but not in protected mode. I got the code from Hale Hilandis Ata driver.
Can you suggest something.
Thank u very much in advance.
Re:ATA Identify drive
Without knowing what exactly you're talking about, if it uses BIOS interrupts then no it won't work in protected mode. If it uses direct IO in Assembly then you will probably have to convert it to 32 bit assembly first.
Re:ATA Identify drive
Hi,
It means , if it's not working, you've got something wrong.
Maybe you can post the code.
HTH
DennisCGc.
No, every command is mode independant (that's a GoodThing of using the HDD I/O ports)os_ambition wrote: Is ATA Identify drive command 0xEC is for real mode only?
It means , if it's not working, you've got something wrong.
Maybe you can post the code.
HTH
DennisCGc.
Re:ATA Identify drive
I will send the code in several parts because its too long
Here is Part 1
Here is Part 1
Code: Select all
#define U32 unsigned long
#define S32 long
#define U16 unsigned int
#define S16 int
#define U8 unsigned char
#define S8 char
#define CB_DATA 0 /* data reg in/out pio_base_addr1+0*/
#define CB_ERR 1 /* error in pio_base_addr1+1*/
#define CB_FR 1 /* feature reg out pio_base_addr1+1*/
#define CB_SC 2 /* sector count in/out pio_base_addr1+2*/
#define CB_SN 3 /* sector number in/out pio_base_addr1+3*/
#define CB_CL 4 /* cylinder low in/out pio_base_addr1+4 */
#define CB_CH 5 /* cylinder high in/out pio_base_addr1+5 */
#define CB_DH 6 /* device head in/out pio_base_addr1+6 */
#define CB_STAT 7 /* primary status in pio_base_addr1+7 */
#define CB_CMD 7 /* command out pio_base_addr1+7*/
#define CB_ASTAT 6 /* alternate status in pio_base_addr2+6*/
#define CB_DC 6 /* device control out pio_base_addr2+6*/
#define CB_DH_LBA 0x40 /* LBA bit */
#define CB_DH_DEV0 0x00 /* select device 0 */
#define CB_DH_DEV1 0x10 /* select device 1 */
/* device control reg (CB_DC) bits */
#define CB_DC_HOB 0x80 /*// High Order Byte (48-bit LBA) */
#define CB_DC_HD15 0x00 /*// bit 3 is reserved */
/*// #define CB_DC_HD15 0x08 // (old definition of bit 3) */
#define CB_DC_SRST 0x04 /*// soft reset */
#define CB_DC_NIEN 0x02 /*// disable interrupts*/
#define CMD_IDENTIFY_DEVICE 0xEC
extern far void OutByte(U8 Byte, U16 wPort);
extern far U8 InByte(U16 wPort);
extern far InWords(U32 dPort, U8 *pDataIn, U32 dBytes);
#define BUFFER_SIZE 4096
unsigned char buffer512[512];
void DELAY400NS(U16 HD_APort);
static U32 Identify_Drive(U16 HD_Port, U16 HD_APort, U8 Dev, U8 *pDataRet);
void Wait_Ready(U16 HD_Port);
void Wait_ReadyBusy(U16 HD_Port);
void Wait_DRQ(U16 HD_Port);
void Wait_Busy(U16 HD_Port);
Re:ATA Identify drive
Here is Part 2
Code: Select all
U32 Init_HD_Driver(void)
{
U32 erc;
erc=Identify_Drive(0x1F0, 0x3F0, 0x00, buffer512);
return erc;
}
void DELAY400NS(U16 HD_APort)
{
InByte( HD_APort+ CB_ASTAT );
InByte( HD_APort+ CB_ASTAT);
InByte( HD_APort+ CB_ASTAT);
InByte( HD_APort+ CB_ASTAT);
}
/*
*/
static U32 Identify_Drive(U16 HD_Port, U16 HD_APort, U8 Dev, U8 *pDataRet)
{
U8 dc, dh, int_use_intr_flag, status;
U32 erc;
int_use_intr_flag=1;
dc = int_use_intr_flag ? 0 : CB_DC_NIEN;
Wait_Busy(HD_Port);
OutByte( dc,HD_APort+CB_DC ); /*3F6 device control*/
Wait_ReadyBusy(HD_Port);
/*1F1*/
OutByte( 0,HD_Port + CB_FR );
/*1F2 ,sector count*/
OutByte( 0,HD_Port + CB_SC );
/*1F3 sector number*/
OutByte( 0,HD_Port + CB_SN );
/*cylinder low 1F4*/
OutByte( 0,HD_Port + CB_CL );
/*cylinder hi 1F5*/
OutByte( 0,HD_Port + CB_CH );
dh = CB_DH_LBA | (Dev ? CB_DH_DEV1 : CB_DH_DEV0 );
dh = ( dh & 0xf0 ) | ( 0 & 0x0f );
/*Drive and Head 1F6*/
OutByte( dh, HD_Port +CB_DH );
Wait_Ready( HD_Port) ;
OutByte( CMD_IDENTIFY_DEVICE, HD_Port + CB_CMD );
DELAY400NS(HD_APort);
Wait_DRQ(HD_Port);
InWords(HD_Port, pDataRet, 512);
DELAY400NS(HD_APort); /* delay so device can get the status updated*/
}
/*
//-----------------------------------------------------------------------------
// Wait_Ready: Pauses execution until Ready = 1 in the status register
// A timeout delay should be added to improve this function
//
// Parameters: None
//
// Returns: None
//
// Functions Used: ReadReg
//
//-----------------------------------------------------------------------------
*/
void Wait_Ready(U16 HD_Port) /*input=0x1F7, 0x177*/
{
U8 statbyte;
U8 iflag ;
iflag=0;
while (1)
{
statbyte = InByte(HD_Port + 7); /* Read Status Register*/
statbyte=statbyte & 0x40;
if (statbyte == 0x40)
break; /* Ready bit is in pos 6*/
}
}
/*
//-----------------------------------------------------------------------------
// Wait_ReadyBusy: Halts further execution until Ready = 1 and Busy = 0 in
// status register
//
// Parameters: None
//
// Returns: None
//
// Functions Used: ReadReg
//
//-----------------------------------------------------------------------------
*/
void Wait_ReadyBusy(U16 HD_Port) /*input=0x1F7, 0x177 */
{
U8 statbyte;
U8 iflag;
iflag=0;
while (1)
{
statbyte = InByte(HD_Port + 7); /* Read Status register*/
/* If RDY = 1 and BUSY = 0 leave loop */
/*check bit 6 and bit 7 of 0x1F7*/
if ((statbyte & 0x40) && ((statbyte & 0x80)==0)) break;
}
}
void Wait_Busy(U16 HD_Port) /*input=0x1F7, 0x177 */
{
U8 statbyte;
U8 iflag;
iflag=0;
while (1)
{
statbyte = InByte(HD_Port + 7); /* Read Status register*/
/* If RDY = 1 and BUSY = 0 leave loop */
/*check bit 6 and bit 7 of 0x1F7*/
statbyte=statbyte & 0x80;
/* if (!(statbyte & 0x80))*/
if (statbyte==0)
break;
}
}
/*
//-----------------------------------------------------------------------------
// Wait_DRQ: Halts execution until DRQ is asserted
//
// Parameters: None
//
// Returns: None
//
// Functions Used: ReadReg
//
//-----------------------------------------------------------------------------
*/
void Wait_DRQ(U16 HD_Port) /*input=0x1F7, 0x177*/
{
U8 statbyte;
U8 iflag;
iflag=0;
while (1)
{
statbyte = InByte(HD_Port + 7); /* DRQ is in status register*/
/*check bit 3 */
/*if (statbyte & 0x08) */
statbyte=statbyte & 0x08;
if (statbyte==0x08)
break;
}
}
The external 32-bit assembly code
;===============================================
; InByte(wPort)
; The Byte is read from the I/O Port specified and returned in AL
; wPort = [EBP+12]
;
PUBLIC __InByte:
PUSH EBP
MOV EBP, ESP
MOV DX, WORD PTR [EBP+12]
IN AL, DX
AND EAX, 0FFh ;Only get the byte
MOV ESP, EBP
POP EBP
RETF 4 ;
;
;===============================================
;===============================================
; OutByte(Byte, wPort)
; The Byte is sent out the I/O Port specified.
; Byte = [EBP+16]
; wPort = [EBP+12]
;
PUBLIC __OutByte:
PUSH EBP
MOV EBP, ESP
MOV DX, WORD PTR [EBP+12]
MOV AL, BYTE PTR [EBP+16]
OUT DX, AL
POP EBP
RETF 8
; InWords(wPort, pDataIn, dBytes)
; The dBytes/2 are read in from wPort to pDataIn
; wPort = [EBP+20]
; pDataIn = [EBP+16]
; dBytes = [EBP+12]
;
; ASSUMES ES == DS !!!! (In MMURTL it always does...)
;
PUBLIC __InWords:
PUSH EBP
MOV EBP, ESP
MOV DX, WORD PTR [EBP+20]
MOV EDI, DWORD PTR [EBP+16]
MOV ECX, DWORD PTR [EBP+12]
SHR ECX, 1 ;Make WORDS vice bytes
CLD
REP INSW
MOV ESP, EBP
POP EBP
RETF 12
Re:ATA Identify drive
Very odd. Maybe it has something todo with the fact you're reading from the "normal" status flag. (And if the HD is busy with something you requested, and you're reading the status flag, it'll simply stop.)
To prevent this you should use 0x3f6. (Alternate Status Flag).
Btw, this is merely a guess. Maybe some C guru is able to help him ?
HTH and Gl,
DennisCGc.
To prevent this you should use 0x3f6. (Alternate Status Flag).
Btw, this is merely a guess. Maybe some C guru is able to help him ?
HTH and Gl,
DennisCGc.
Re:ATA Identify drive
You only need to use it in real mode, on start up use it to find all your hdd drives and use 0xA1 to find your cd/dvd drives etc.
And store the port and drive numbers in vars, before moving to pmode.
And store the port and drive numbers in vars, before moving to pmode.
Re:ATA Identify drive
I'm not certain but this looks like a problem:
WORD should break down to 2 bytes, in protected mode it should be a DWORD. Remember that on the x86 the bit order is "High,Low" so you're reading the High off the stack (which will most likely always be 0). [You've got this in the other 2 assembly functions as well]
Something to remember about C/C++: They always use the CPU wordsize for stack objects, if you go char c; This reserves 32bits on the stack for the variable because aligned data is faster to access. So when you declare void func(char param); whenever you call func() you are always passing the equivalent of an INT on the stack. This also points out how futile it is trying to conserve memory using small data types like char and short, if there isn't a specific reason to not use int then just use int.
Two other things, you've got fars in the header, you should probably remove those. And:
Which should be:
An int is 32bits, char is 8, short is 16, long is 32 as well, long long is 64 (In protected mode)
Code: Select all
PUBLIC __OutByte:
PUSH EBP
MOV EBP, ESP
MOV DX, >>WORD<< PTR [EBP+12]
MOV AL, BYTE PTR [EBP+16]
OUT DX, AL
POP EBP
RETF 8
Something to remember about C/C++: They always use the CPU wordsize for stack objects, if you go char c; This reserves 32bits on the stack for the variable because aligned data is faster to access. So when you declare void func(char param); whenever you call func() you are always passing the equivalent of an INT on the stack. This also points out how futile it is trying to conserve memory using small data types like char and short, if there isn't a specific reason to not use int then just use int.
Two other things, you've got fars in the header, you should probably remove those. And:
Code: Select all
#define U16 unsigned int
#define S16 int
Code: Select all
#define U16 unsigned short
#define S16 short
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:ATA Identify drive
actually, no. The Intel CPU stores "0x12345678" as =0x78; [i+1]=0x56; [i+2]=0x34; [i+3]=0x12 ... The fact the stack expands downwards doesn't change this.AR wrote: I'm not certain but this looks like a problem:WORD should break down to 2 bytes, in protected mode it should be a DWORD. Remember that on the x86 the bit order is "High,Low" so you're reading the High off the stack (which will most likely always be 0). [You've got this in the other 2 assembly functions as well]Code: Select all
PUBLIC __OutByte: PUSH EBP MOV EBP, ESP MOV DX, >>WORD<< PTR [EBP+12] MOV AL, BYTE PTR [EBP+16] OUT DX, AL POP EBP RETF 8
Re:ATA Identify drive
Well I wasn't exactly certain, I avoid pure assembly as much as possible
Re:ATA Identify drive
Be careful with that not all architectures have a pointer being equivalent in size to an int. Not all architectures have all pointers the same size. double's are usually larger than int's.AR wrote: Something to remember about C/C++: They always use the CPU wordsize for stack objects...
Just acting out my allergy towards catch-all phrases when it comes to language standards.
Every good solution is obvious once you've found it.
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:ATA Identify drive
glad for you ... maybe you might give us a hint on what was the actual problem (grow knowledge base, etc)os_ambition wrote: Already solved this problem.
Thanks to all who responded.
Re:ATA Identify drive
correction:
remove these two lines
dh = CB_DH_LBA | (Dev ? CB_DH_DEV1 : CB_DH_DEV0 );
dh = ( dh & 0xf0 ) | ( 0 & 0x0f );
and change to these lines
dh = Dev ? CB_DH_DEV1 : CB_DH_DEV0 ;
dh= dh | 0xE0; //0xEF also works
remove this line too
Wait_DRQ(HD_Port);
and change to
do
{
status = InByte( HD_Port + CB_STAT );
}while( ( status & ( CB_STAT_BSY | CB_STAT_DRQ ) ) != CB_STAT_DRQ );
and last add these defines
#define CB_STAT_BSY 0x80 /* busy*/
#define CB_STAT_DRQ 0x08 /* data request*/
that's all.
remove these two lines
dh = CB_DH_LBA | (Dev ? CB_DH_DEV1 : CB_DH_DEV0 );
dh = ( dh & 0xf0 ) | ( 0 & 0x0f );
and change to these lines
dh = Dev ? CB_DH_DEV1 : CB_DH_DEV0 ;
dh= dh | 0xE0; //0xEF also works
remove this line too
Wait_DRQ(HD_Port);
and change to
do
{
status = InByte( HD_Port + CB_STAT );
}while( ( status & ( CB_STAT_BSY | CB_STAT_DRQ ) ) != CB_STAT_DRQ );
and last add these defines
#define CB_STAT_BSY 0x80 /* busy*/
#define CB_STAT_DRQ 0x08 /* data request*/
that's all.