I have spent about a day in total tinkering with the ATA driver's disk detection routine in the Mattise kernel. It was actual a little tricky, and I am sure others have had problem.
Since I got it working I wanting to share it, and wondering if it actually works well with different hardware and maybe some of your views on better ways to do this.
The idea is to send a value which represents the head and drive to select on a controller, and check for the appropriate values.
Where here we have some defines and a data structure holding all the default controller addresses.
Code: Select all
#define ATA_DATA 0
#define ATA_ERROR 1
#define ATA_SECTORCOUNT 2
#define ATA_SECTORNUMBER 3
#define ATA_CYLINDERLOW 4
#define ATA_CYLINDERHIGH 5
#define ATA_DRIVEHEAD 6
#define ATA_STATUS 7
#define ATA_COMMAND 8
typedef struct{
unsigned short base[2];
}Tata_ctl_info;
static Tata_ctl_info ata_ctl_info[] = {
{ .base = {0x1f0, 0x3f0} },
{ .base = {0x170, 0x370} },
{ .base = {0x1e8, 0x3e0} },
{ .base = {0x168, 0x360} }
};
Code: Select all
for(drvi = 0, x = 0; x < (sizeof(ata_ctl_info) / sizeof(Tata_ctl_info)); ++x)
{
for(z = 0; z < 2; ++z)
{
for(y = 0; y < 2; ++y)
{
outportb(ata_ctl_info[x].base[z] + ATA_DRIVEHEAD, (0xa0 | (y << 4)));
delay(ATA_DELAY_NORMAL);
printf("[ATA] ctl:%x alt:%x drv:%x (%02x)\n",
x, z, y, inportb(ata_ctl_info[x].base[z] + ATA_STATUS));
delay(ATA_DELAY_NORMAL);
if((((unsigned char)inportb(ata_ctl_info[x].base[z] + ATA_STATUS) & (0x40 | 0x10 | 0x20 | 0x01)) == 0x50))
{
printf("[ATA] present ata/%1x:%1x:%1x\n", x, z, y);
}
}
}
}
- drive seek completion bit.(TRUE)
- write fault. (FALSE)
- previous command was error. (FALSE)