Detecting of discs works perfectly but I have a lot of problems while acessing to it.
Code: Select all
BYTE ataAcess(ataDevice& dev, int direction, DWORD lba, BYTE sects, WORD sel, DWORD offset)
{
unsigned char lba_mode /* 0: CHS, 1:LBA28, 2: LBA48 */, dma /* 0: No DMA, 1: DMA */, cmd;
unsigned char lba_io[6];
ataChannel& channel = contr[dev.controllerId].chann[dev.channelId]; // ataChannel is structure with port base, bmide base...
unsigned int words = 256;
unsigned short cyl, i;
unsigned char head, sect, err;
// turn off IRQ
writeReg(channel, ataREG_CONTROL, channel.nIEN = (ide_irq_invoked = 0x0) + 0x02);
// choose adressing and params
if (lba >= 0x10000000)
{
// LBA48:
lba_mode = 2;
lba_io[0] = (lba & 0x000000FF) >> 0;
lba_io[1] = (lba & 0x0000FF00) >> 8;
lba_io[2] = (lba & 0x00FF0000) >> 16;
lba_io[3] = (lba & 0xFF000000) >> 24;
lba_io[4] = 0;
lba_io[5] = 0;
head = 0;
}
else if (dev.capabilities & 0x200)
{
// LBA28:
lba_mode = 1;
lba_io[0] = (lba & 0x00000FF) >> 0;
lba_io[1] = (lba & 0x000FF00) >> 8;
lba_io[2] = (lba & 0x0FF0000) >> 16;
lba_io[3] = 0; //
lba_io[4] = 0; //
lba_io[5] = 0; //
head = (lba & 0xF000000) >> 24;
}
else
{
// CHS:
lba_mode = 0;
sect = (lba % 63) + 1;
cyl = (lba + 1 - sect) / (16 * 63);
lba_io[0] = sect;
lba_io[1] = (cyl >> 0) & 0xFF;
lba_io[2] = (cyl >> 8) & 0xFF;
lba_io[3] = 0;
lba_io[4] = 0;
lba_io[5] = 0;
head = (lba + 1 - sect) % (16 * 63) / (63);
}
// NO DMA
dma = 0;
// wait until disc is ready
while (readReg(channel, ataREG_STATUS) & ataSR_BSY)
;
// choose disc
if (lba_mode == 0)
writeReg(channel, ataREG_HDDEVSEL, 0xA0 | (dev.id << 4) | head); // Drive & CHS.
else
writeReg(channel, ataREG_HDDEVSEL, 0xE0 | (dev.id << 4) | head); // Drive & LBA
// set params
if (lba_mode == 2)
{
writeReg(channel, ataREG_SECCOUNT1, 0);
writeReg(channel, ataREG_LBA3, lba_io[3]);
writeReg(channel, ataREG_LBA4, lba_io[4]);
writeReg(channel, ataREG_LBA5, lba_io[5]);
}
writeReg(channel, ataREG_SECCOUNT0, sects);
writeReg(channel, ataREG_LBA0, lba_io[0]);
writeReg(channel, ataREG_LBA1, lba_io[1]);
writeReg(channel, ataREG_LBA2, lba_io[2]);
// choose right command
if (lba_mode == 0 && dma == 0 && direction == 0) cmd = ataCMD_READ_PIO;
if (lba_mode == 1 && dma == 0 && direction == 0) cmd = ataCMD_READ_PIO;
if (lba_mode == 2 && dma == 0 && direction == 0) cmd = ataCMD_READ_PIO_EXT;
if (lba_mode == 0 && dma == 1 && direction == 0) cmd = ataCMD_READ_DMA;
if (lba_mode == 1 && dma == 1 && direction == 0) cmd = ataCMD_READ_DMA;
if (lba_mode == 2 && dma == 1 && direction == 0) cmd = ataCMD_READ_DMA_EXT;
if (lba_mode == 0 && dma == 0 && direction == 1) cmd = ataCMD_WRITE_PIO;
if (lba_mode == 1 && dma == 0 && direction == 1) cmd = ataCMD_WRITE_PIO;
if (lba_mode == 2 && dma == 0 && direction == 1) cmd = ataCMD_WRITE_PIO_EXT;
if (lba_mode == 0 && dma == 1 && direction == 1) cmd = ataCMD_WRITE_DMA;
if (lba_mode == 1 && dma == 1 && direction == 1) cmd = ataCMD_WRITE_DMA;
if (lba_mode == 2 && dma == 1 && direction == 1) cmd = ataCMD_WRITE_DMA_EXT;
writeReg(channel, ataREG_COMMAND, cmd); // ... and send it
if (dma)
// NO DMA
if (direction == 0);
// DMA Read.
else;
// DMA Write.
else
if (direction == 0)
// reading
for (i = 0; i < sects; i++)
{
if (err = readPolling(channel, 1))
return err; // error
// receive data
asm("pushw %ds");
asm("mov %%ax, %%ds" : : "a"(sel));
asm("rep insw" : : "c"(words), "d"(channel.base), "D"(offset));
asm("popw %ds");
offset += (words*2);
}
else
{
// write
for (i = 0; i < sects; i++)
{
readPolling(channel, 0);
// send data
asm("pushw %ds");
asm("mov %%ax, %%ds" : : "a"(sel));
asm("rep outsw" : : "c"(words), "d"(channel.base), "S"(offset));
asm("popw %ds");
offset += (words*2);
}
// cache flush
writeReg(channel, ataREG_COMMAND, (BYTE []) { ataCMD_CACHE_FLUSH,
ataCMD_CACHE_FLUSH,
ataCMD_CACHE_FLUSH_EXT}[lba_mode]);
readPolling(channel, 0); // Polling.
}
return 0;
}
And writing... it causes Global Protection Fault. I readed in ATA PIO article on wiki, that I shoudn't use rep outsw, maybe this is reason?
Thanks for help!