ATAPI: Difference between revisions

Jump to navigation Jump to search
53 bytes removed ,  10 years ago
m
Convert to standard ISO data types
[unchecked revision][unchecked revision]
(Added link to new article "Optical Drive")
m (Convert to standard ISO data types)
Line 9:
For instance, reading the table of contents is achieved by sending the following byte string to the device, as a "command".
 
<source lang="c">
<pre>
unsigned charuint8_t atapi_readtoc[]= { 0x43 /* ATAPI_READTOC */, 0, 1, 0, 0, 0, 0, 0, 12, 0x40, 0, 0};
</presource>
 
The ATA PACKET command works in three phases, in PIO mode.
Line 50:
Assume that the command is in words Command1 through Command6. Device is the Primary slave. Select the target device by setting the master/slave bit in the Device Select Register. There are no other bits needed.
 
<source lang="c">
outb (0x1F6, slavebit<<4)
</source>
 
If the command is going to use DMA, set the Features Register to 1, otherwise 0 for PIO.
 
<source lang="c">
outb (0x1F1, isDMA)
</source>
 
The Sectorcount Register and LBA Low Register are unused currently. Send maxByteCount in LBA Mid and LBA High Registers.
 
<source lang="c">
outb (0x1F4, (maxByteCount & 0xff))
outb (0x1F50x1F4, (maxByteCount >>& 80xff))
outb (0x1F40x1F5, (maxByteCount &>> 0xff8))
</source>
 
Send the ATAPI PACKET command to the Command Register
 
<source lang="c">
outb (0x1F7, 0xA0)
</source>
 
Wait for an IRQ, or poll for BSY to clear and DRQ to set.
Line 69 ⟶ 77:
Then send the ATAPI command as 6 words, to the data port.
 
<source lang="c">
outw (0x1F0, Command1)
outw (0x1F0, Command2Command1)
outw (0x1F0, Command3Command2)
outw (0x1F0, Command4Command3)
outw (0x1F0, Command5Command4)
outw (0x1F0, Command6Command5)
outw (0x1F0, Command1Command6)
</source>
 
Then wait for another IRQ. You cannot poll.
Line 85 ⟶ 95:
Once you have the transfer size (bytecount = LBA High << 8 | LBA Mid), do the PIO transfer.
 
<source lang="c">
wordcount = bytecount/2;
</source>
 
loop on inw(0x1F0) or outw(0x1f0) wordcount times.
Line 251 ⟶ 263:
 
<source lang="c">
/* The default and seemingly universal sector size for CD-ROMs. */
#define ATAPI_SECTOR_SIZE 2048
 
/* The default ISA IRQ numbers of the ATA controllers. */
#define ATA_IRQ_PRIMARY 0x0E
#define ATA_IRQ_SECONDARY 0x0F
 
/* The necessary I/O ports, indexed by "bus". */
#define ATA_DATA(x) (x)
#define ATA_FEATURES(x) (x+1)
#define ATA_SECTOR_COUNT(x) (x+2)
#define ATA_ADDRESS1(x) (x+3)
#define ATA_ADDRESS2(x) (x+4)
#define ATA_ADDRESS3(x) (x+5)
#define ATA_DRIVE_SELECT(x) (x+6)
#define ATA_COMMAND(x) (x+7)
#define ATA_DCR(x) (x+0x206) /* device control register */
 
/* valid values for "bus" */
#define ATA_BUS_PRIMARY 0x1F0
#define ATA_BUS_SECONDARY 0x170
/* valid values for "drive" */
#define ATA_DRIVE_MASTER 0xA0
#define ATA_DRIVE_SLAVE 0xB0
 
/* ATA specifies a 400ns delay after drive switching -- often
* implemented as 4 Alternative Status queries. */
#define ATA_SELECT_DELAY(bus) \
{inb(ATA_DCR(bus));inb(ATA_DCR(bus));inb(ATA_DCR(bus));inb(ATA_DCR(bus));}
 
/* Use the ATAPI protocol to read a single sector from the given
* bus/drive into the buffer using logical block address lba. */
int
atapi_drive_read_sector (uint32uint32_t bus, uint32uint32_t drive, uint32uint32_t lba, uint8uint8_t *buffer)
{
/* 0xA8 is READ SECTORS command byte. */
uint8 uint8_t read_cmd[12] = { 0xA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
uint8 uint8_t status;
int size;
/* Tell the scheduler that this process is using the ATA subsystem. */
ata_grab ();
/* Select drive (only the slave-bit is set) */
outb (drive & (1 << 4), ATA_DRIVE_SELECT (bus));
ATA_SELECT_DELAY (bus); /* 400ns delay */
outb (0x0, ATA_FEATURES (bus)); /* PIO mode */
outb (ATAPI_SECTOR_SIZE & 0xFF, ATA_ADDRESS2 (bus));
outb (ATAPI_SECTOR_SIZE >> 8, ATA_ADDRESS3 (bus));
outb (0xA0, ATA_COMMAND (bus)); /* ATA PACKET command */
while ((status = inb (ATA_COMMAND (bus))) & 0x80) /* BUSY */
asm volatile ("pause");
while (!((status = inb (ATA_COMMAND (bus))) & 0x8) && !(status & 0x1))
asm volatile ("pause");
/* DRQ or ERROR set */
if (status & 0x1) {
size = -1;
goto cleanup;
}
}
read_cmd[9] = 1; /* 1 sector */
read_cmd[2] = (lba >> 0x18) & 0xFF; /* most sig. byte of LBA */
read_cmd[3] = (lba >> 0x10) & 0xFF;
read_cmd[4] = (lba >> 0x08) & 0xFF;
read_cmd[5] = (lba >> 0x00) & 0xFF; /* least sig. byte of LBA */
/* Send ATAPI/SCSI command */
outsw (ATA_DATA (bus), (uint16uint16_t *) read_cmd, 6);
/* Wait for IRQ that says the data is ready. */
schedule ();
/* Read actual size */
size =
(((int) inb (ATA_ADDRESS3 (bus))) << 8) |
(int) (inb (ATA_ADDRESS2 (bus)));
/* This example code only supports the case where the data transfer
* of one sector is done in one step. */
ASSERT (size == ATAPI_SECTOR_SIZE);
/* Read data. */
insw (ATA_DATA (bus), buffer, size / 2);
/* The controller will send another IRQ even though we've read all
* the data we want. Wait for it -- so it doesn't interfere with
* subsequent operations: */
schedule ();
/* Wait for BSY and DRQ to clear, indicating Command Finished */
while ((status = inb (ATA_COMMAND (bus))) & 0x88)
asm volatile ("pause");
cleanup:
/* Exit the ATA subsystem */
ata_release ();
return size;
}
</source>
 
Anonymous user
Cookies help us deliver our services. By using our services, you agree to our use of cookies.

Navigation menu