Code: Select all
void ATAPIWriteBlks(LTBlkDev *bdev,U1 *buf, U8 blk, U8 cnt)
{
U8 U4s_avail;
U1 *buf2;
IDEWaitNotBusy(bdev);
ATAPISeek(bdev,blk);
OutP(bdev->base0+IDE_FEATURE_REG,0);
OutP(bdev->base0+IDE_LCYL_REG,bdev->blk_size);
OutP(bdev->base0+IDE_HCYL_REG,bdev->blk_size.u1[1]);
OutP(bdev->base0+IDE_SELECT_REG,0xEF|bdev->unit<<4);
OutP(bdev->base0+IDE_CMD,ATA_PACKETCMD);
ATAPIWritePktWord(bdev,0x0400); //FMT
ATAPIWritePktWord(bdev,blk.u2[1]);
ATAPIWritePktWord(bdev,blk);
ATAPIWritePktWord(bdev,cnt.u2[1]);
ATAPIWritePktWord(bdev,cnt);
ATAPIWritePktWord(bdev,0x0000);
bdev->flags|=LTBDF_LAST_WAS_WRITE;
IDEWaitNotBusy(bdev);
ATAPISeek(bdev,blk);
OutP(bdev->base1+IDE_CONTROL_REG,0x8);
OutP(bdev->base0+IDE_SELECT_REG,0xEF|bdev->unit<<4);
OutP(bdev->base0+IDE_LCYL_REG,bdev->blk_size);
OutP(bdev->base0+IDE_HCYL_REG,bdev->blk_size.u1[1]);
ATACmd(bdev,ATA_PACKETCMD);
ATAPIWritePktWord(bdev,0xAA00); //Write
ATAPIWritePktWord(bdev,blk.u2[1]);
ATAPIWritePktWord(bdev,blk);
ATAPIWritePktWord(bdev,cnt.u2[1]);
ATAPIWritePktWord(bdev,cnt);
ATAPIWritePktWord(bdev,0x0000);
buf2=buf+bdev->blk_size*cnt;
while (buf<buf2) {
while (!(InP(bdev->base0+IDE_STATUS) & S_DRQ))
SwapInNextTask;
U4s_avail=(InP(bdev->base0+IDE_HCYL_REG)<<8+InP(bdev->base0+IDE_LCYL_REG))>>2;
if (buf+U4s_avail<<2>buf2)
U4s_avail=(buf2-buf)>>2;
if (U4s_avail) {
RepOutSD(buf,U4s_avail,bdev->base0+IDE_DATA_REG);
buf+=U4s_avail<<2;
disk_writes+=U4s_avail>>(BLK_SIZE_BITS-2);
}
}
IDEWaitNotBusy(bdev);
}
void ATAPISync(LTBlkDev *bdev)
{
IDEWaitNotBusy(bdev);
OutP(bdev->base1+IDE_CONTROL_REG,0x8);
OutP(bdev->base0+IDE_SELECT_REG,0xEF|bdev->unit<<4);
OutP(bdev->base0+IDE_LCYL_REG,bdev->blk_size);
OutP(bdev->base0+IDE_HCYL_REG,bdev->blk_size.u1[1]);
ATACmd(bdev,ATA_PACKETCMD);
ATAPIWritePktWord(bdev,0x3500); //Sync
ATAPIWritePktWord(bdev,0x0000);
ATAPIWritePktWord(bdev,0x0000);
ATAPIWritePktWord(bdev,0x0000);
ATAPIWritePktWord(bdev,0x0000);
ATAPIWritePktWord(bdev,0x0000);
IDEWaitNotBusy(bdev);
}
void ATAPIClose(LTBlkDev *bdev,I8 close_field=0x200)
{
//0x200 CD/DVD part 1
//0x300 DVD part 2
OutP(bdev->base1+IDE_CONTROL_REG,0x8);
OutP(bdev->base0+IDE_SELECT_REG,0xEF|bdev->unit<<4);
OutP(bdev->base0+IDE_LCYL_REG,bdev->blk_size);
OutP(bdev->base0+IDE_HCYL_REG,bdev->blk_size.u1[1]);
ATACmd(bdev,ATA_PACKETCMD);
ATAPIWritePktWord(bdev,0x5B00); //Close
ATAPIWritePktWord(bdev,close_field);
ATAPIWritePktWord(bdev,0x0000);
ATAPIWritePktWord(bdev,0x0000);
ATAPIWritePktWord(bdev,0x0000);
ATAPIWritePktWord(bdev,0x0000);
IDEWaitNotBusy(bdev);
}
//This is the high level code
ATAPIWaitReady(bdev);
while (cnt) {
if (cnt>COPY_BUF_BLKS)
n=COPY_BUF_BLKS;
else
n=cnt;
if (n>bdev->max_writes)
n=bdev->max_writes;
buf=d->out_buf&1 ? d->buf1:d->buf0;
while (d->in_buf<=d->out_buf)
SwapInNextTask;
ATAPIWriteBlks(bdev,buf,blk/dv,(n+dv-1)/dv);
d->out_buf++;
cnt-=n;
blk+=n;
}
ATAPISync(bdev);
ATAPIClose(bdev,0x200);
if (media_type==MT_DVD)
ATAPIClose(bdev,0x300);