ide driver seq

From: Nick (nick_s2004_at_yahoo.co.in)
Date: 01/28/04


Date: 28 Jan 2004 07:16:44 -0800

Hi,
 Can you please look into the following sequence.
I think the sequence is not correct. May be there are a lot more
corrections to be made.
 
/* The printf is similar to printk.printk can be subsituted for printf
in the below code. The code works upto some extent. When using the
code while booting i can see the harddisk light blinking (red light) .
So the controller is moving . But it is unable to read sectors
somehow. Is the sequence correct for ide. It works correctly in vmware
under linux(checked with hexdump /dev/hda in linux).But when tried to
boot independently it causes error (atleast doesn't match with the
correct data. It produces d0 1 d0 1 d0 1 d0 1 d0 1 d0 ...d9 1 d9 ...)
which doesn't tally with hexdump /dev/hda.
My guess is that sequence is not correct or i have made some error.So
if someone experienced can tell me where the error is and make it work
it would be very helpful in moving forward.
 */
 
static inline void insw (unsigned short port, void * addr, unsigned \
long count)
{
__asm__ __volatile__ (" rep ; ins" "w" : "=D" (addr), "=c" (count) : \
 "d" (port),"0" (addr),"1" (count));
}

static int drive_busy(void)
{
unsigned int i;
unsigned char c;

for(i=0;i<10000;i++)
if(0x40 == (inb(0x1f7)&(0x80|0x40)))
break;
i=inb(0x1f7);
i&=0x80|0x40|0x10;
if(i==0x40|0x10)
return 0;
printf("Hd controller times out\n");

}

void reset_controller(void)
{
unsigned int i;
outb(4,0x3f6);
for(i=0;i<1000;i++)
__asm__ __volatile__ ("nop");

outb(0x,0x3f6);
for(i=0;i<10000&&drive_busy();i++);
if(drive_busy())
printf("HD controller still busy\n");
if((i=inb(0x1f1)!=1)
printf("HD controller reset failed \n");
if(!controller_ready())
printf("HD controller not ready\n");
}
 
void hd_out(unsigned int drive,unsigned char nsect,unsigned char
sect,unsigned char head,unsigned char cyl,unsigned char cmd)
{
 unsigned short port;
port=0x1f0;
++port;
outb(nsect,++port); /*1f2 */
outb(sect,++port); /*1f3 */
outb(cyl,++port); /*1f4 */
outb(cyl>>8,++port); /*1f5 */
outb(0xA0|(drive <<4),0x1f6);
outb(cmd,++port);
}
 
void hd_init(void)
{
unsigned char *s;
unsigned int i=0;
hd_out(0,2,0,0,0,0x10);
hd_out(0,2,0,0,0,0x20);
insw(0x1f0,s,10);
for(i=0;i<10;i++)
printf("%x\n",*(s+i));
}



Relevant Pages