Page 1 of 1
Detecting ATAPI drives
Posted: Sat Jun 19, 2010 4:05 pm
by AUsername
Hey again, I have a simple script that grabs if a drive is active or not but it doesn't grab if it's an HDD or an ODD. I can't find anything on how to detect that other than checking the vendor string which I won't do for obvious reasons.
This is my current code:
Code: Select all
uint8_t odd_find_drive(uint32_t bus, uint32_t drive){
uint8_t status;
//Select the drive
//Channel = bus, device = drive
outportb(ATA_DRIVE_SELECT(bus),drive & (1 << 4));
status = inportb(ATA_COMMAND(bus));
if ((!status) || status == 0xFF)
return 0;
printf("features = 0x%x\n",status);
return 1;
}
It always returns 0x50 (
http://i45.tinypic.com/25r18i8.png , please ignore the ugly debugging messages
)
Any ideas how I'm SUPPOSED to grab it because I'm pretty sure what I'm doing only returns if the drive exists or not (since that works).
Also here's my bochsrc.txt:
#Boot from HDD -------------------------------------------------------
ata0-master: type=disk, path="C:\Coras\coras_slim.img", mode=flat, cylinders=65, heads=16, spt=63
ata1-slave: type=disk, path="C:\Coras\hd1.img", mode=flat, cylinders=65, heads=16, spt=63
ata1-master: type=cdrom, mode=flat, path="C:\Coras\od0.iso"
ata0-slave: type=cdrom, mode=flat, path="C:\Coras\od1.iso"
Thanks in advance.
Re: Detecting ATAPI drives
Posted: Sat Jun 19, 2010 5:05 pm
by -m32
Do an ATA IDENTIFY, then check if the high-order bit of word 0 is set to one. If so, it's a packet (ATAPI) device. If it's set to 0, it's an ATA device.
Re: Detecting ATAPI drives
Posted: Sat Jun 19, 2010 5:46 pm
by AUsername
Awesome, thanks, it worked. =D
Re: Detecting ATAPI drives
Posted: Sat Jun 19, 2010 6:05 pm
by ~
Some time ago I posted a method for reliably detecting ATA/ATAPI devices. Actually, there are several required tests that must always work together for being able to detect the drives across differently behaved chipsets and drives.
That is a lot of little theoric and practical details, and you must be aware that it can be very frustrating being able to detect correctly in a computer but not in other, but it should help greatly:
http://forum.osdev.org/viewtopic.php?f=1&t=20690
I also attached a compiled DOS COM file and its sample source code.
-------------------------------
Note that SATA drives in AHCI controllers can be programmed in this way as well, and the only thing you need to do is scan the PCI bus for a Class/Subclass/Interface controller with corresponding 01/06/01 values. Then look for its base address registers (BARs) of type I/O. But this is only if that controller actually has these I/O spaces, because it looks like the AHCI specification states that they are optional.
The interesting thing is that if the range of that I/O base address register is 8 (meaning 8 ports in this case) you can be more than sure that those are the first eight ATA registers, as listed in the standards. (
By the way, does anybody know if a SATA controller of this kind has the 9th, Alternate Status//Device Control Register in I/O space and where?)
This can work if the controller is in ATA mode, and in the computer I have, it also works in SATA mode using these non-standard 8-register ranges.
Re: Detecting ATAPI drives
Posted: Sat Jun 19, 2010 9:34 pm
by AUsername
Thanks for the help ~, but now I have another... annoying problem.
In Bochs I can read sectors off of the CD drive but it doesn't work in VBox or VPC (meaning it won't work on real hardware).
I believe it's timing but I've made it wait for a second each sector read so it can't be. I have NO idea what I'm missing and nothing I'm looking at is helping. The documentation on ATA/ATAPI is really bad...
Code based off of tutorial found at
http://wiki.osdev.org/ATAPI
Code: Select all
drvextern uint8_t* odd_read_sector(uint32_t lba){
uint8_t status;
int size;
if (!bus || !drive)
return 0;
printf("ReadSector[");
//Select drive
outportb(ATA_DRIVE_SELECT(bus),drive & (1 << 4));
tvga_putc('1');
//wait 400ns
for(int i = 0; i < 4; i++)
inportb(ATA_DCR(bus));
outportb(ATA_FEATURES(bus),0x0);
outportb(ATA_ADDRESS2(bus),SECTOR_SIZE & 0xFF);
outportb(ATA_ADDRESS3(bus),SECTOR_SIZE >> 8);
outportb(ATA_COMMAND(bus),ATA_CMD_PACKET);
while((status = inportb(ATA_COMMAND(bus))) & 0x80);
while(!((status = inportb(ATA_COMMAND(bus))) & 0x8) && !(status & 0x1));
tvga_putc('4');
if ((status & 0x1))
return 0x0;
ata_packet[0] = ATAPI_CMD_READ;
//ata_packet[1] = ata_packet[6] = ata_packet[7] = ata_packet[8] = 0;
ata_packet[9] = 1;
ata_packet[2] = (lba >> 0x18) & 0xFF;
ata_packet[3] = (lba >> 0x10) & 0xFF;
ata_packet[4] = (lba >> 0x8) & 0xFF;
ata_packet[5] = lba & 0xFF;
tvga_putc('5');
outsw(ATA_DATA(bus),(uint16_t*)ata_packet,6);
irq_wait();
tvga_putc('6');
size = (((int)inportb(ATA_ADDRESS3(bus))) << 8) | (int)(inportb(ATA_ADDRESS2(bus)));
insw(ATA_DATA(bus),(uint16_t*)buffer,size / 2);
printf("9]\n");
return buffer;
}
See anything wrong there? Cause I've been going in circles for about 2 hours now and it's starting to get on my nerves.