Files
TempleOS-Rijn/LT/OSMain/Disk/DiskATA.CPZ
T
2018-09-08 21:45:20 +02:00

599 lines
17 KiB
Plaintext

//The following definitions were copied from Linux source code
/* ATA/ATAPI Cmds pre T13 Spec */
#define WIN_NOP 0x00
#define CFA_REQ_EXT_ERROR_CODE 0x03 /* CFA Request Extended Error Code */
#define WIN_SRST 0x08 /* ATAPI soft reset cmd */
#define WIN_DEV_RESET 0x08
#define WIN_RESTORE 0x10
#define WIN_READ 0x20 /* 28-Bit */
#define WIN_READ_EXT 0x24 /* 48-Bit */
#define WIN_READDMA_EXT 0x25 /* 48-Bit */
#define WIN_READDMA_QUEUED_EXT 0x26 /* 48-Bit */
#define WIN_READ_NATIVE_MAX_EXT 0x27 /* 48-Bit */
#define WIN_MULTREAD_EXT 0x29 /* 48-Bit */
#define WIN_WRITE 0x30 /* 28-Bit */
#define WIN_WRITE_EXT 0x34 /* 48-Bit */
#define WIN_WRITEDMA_EXT 0x35 /* 48-Bit */
#define WIN_WRITEDMA_QUEUED_EXT 0x36 /* 48-Bit */
#define WIN_SET_MAX_EXT 0x37 /* 48-Bit */
#define CFA_WRITE_SECT_WO_ERASE 0x38 /* CFA Write Sectors without erase */
#define WIN_MULTWRITE_EXT 0x39 /* 48-Bit */
#define WIN_WRITE_VERIFY 0x3C /* 28-Bit */
#define WIN_VERIFY 0x40 /* 28-Bit - Read Verify Sectors */
#define WIN_VERIFY_EXT 0x42 /* 48-Bit */
#define WIN_FORMAT 0x50
#define WIN_INIT 0x60
#define WIN_SEEK 0x70
#define CFA_TRANSLATE_SECTOR 0x87 /* CFA Translate Sector */
#define WIN_DIAGNOSE 0x90
#define WIN_SPECIFY 0x91 /* set Drive geometry translation */
#define WIN_DOWNLOAD_MICROCODE 0x92
#define WIN_STANDBYNOW2 0x94
#define WIN_SETIDLE2 0x97
#define WIN_CHECKPOWERMODE2 0x98
#define WIN_SLEEPNOW2 0x99
#define WIN_PACKETCMD 0xA0 /* Send a packet cmd. */
#define WIN_PIDENTIFY 0xA1 /* IDEntify ATAPI dev */
#define WIN_QUEUED_SERVICE 0xA2
#define WIN_SMART 0xB0 /* self-monitoring and reporting */
#define CFA_ERASE_SECTORS 0xC0
#define WIN_MULTREAD 0xC4 /* read sectors using multiple mode*/
#define WIN_MULTWRITE 0xC5 /* write sectors using multiple mode */
#define WIN_SETMULT 0xC6 /* enable/disable multiple mode */
#define WIN_READDMA_QUEUED 0xC7 /* read sectors using Queued DMA transfers */
#define WIN_READDMA 0xC8 /* read sectors using DMA transfers */
#define WIN_WRITEDMA 0xCA /* write sectors using DMA transfers */
#define WIN_WRITEDMA_QUEUED 0xCC /* write sectors using Queued DMA transfers */
#define CFA_WRITE_MULTI_WO_ERASE 0xCD /* CFA Write multiple without erase */
#define WIN_GETMEDIASTATUS 0xDA
#define WIN_DOORLOCK 0xDE /* lock door ON removable drives */
#define WIN_DOORUNLOCK 0xDF /* unlock door ON removable drives */
#define WIN_STANDBYNOW1 0xE0
#define WIN_IDLEIMMEDIATE 0xE1 /* force Drive to become "ready" */
#define WIN_STANDBY 0xE2 /* Set dev in Standby Mode */
#define WIN_SETIDLE1 0xE3
#define WIN_READ_BUFFER 0xE4 /* force read only 1 sector */
#define WIN_CHECKPOWERMODE1 0xE5
#define WIN_SLEEPNOW1 0xE6
#define WIN_FLUSH_CACHE 0xE7
#define WIN_WRITE_BUFFER 0xE8 /* force write only 1 sector */
#define WIN_FLUSH_CACHE_EXT 0xEA /* 48-Bit */
#define WIN_IDENTIFY 0xEC /* ask Drive to IDEntify itself */
#define WIN_MEDIAELTECT 0xED
#define WIN_IDENTIFY_DMA 0xEE /* same as WIN_IDENTIFY, but DMA */
#define WIN_SETFEATURES 0xEF /* set special Drive features */
#define EXAU1_ENABLE_NEST 0xF0
#define WIN_SECURITY_SET_PASS 0xF1
#define WIN_SECURITY_UNLOCK 0xF2
#define WIN_SECURITY_ERASE_PREPARE 0xF3
#define WIN_SECURITY_ERASE_UNIT 0xF4
#define WIN_SECURITY_FREEZE_LOCK 0xF5
#define WIN_SECURITY_DISABLE 0xF6
#define WIN_READ_NATIVE_MAX 0xF8 /* return the native maximum address */
#define WIN_SET_MAX 0xF9
#define DISABLE_SEAGATE 0xFB
/* Bits of HD_STATUS */
#define ERR_STAT 0x01
#define INDEX_STAT 0x02
#define ECC_STAT 0x04 /* Corrected error */
#define DRQ_STAT 0x08
#define SEEK_STAT 0x10
#define WRERR_STAT 0x20
#define READY_STAT 0x40
#define BUSY_STAT 0x80
#define BAD_R_STAT (BUSY_STAT | ERR_STAT)
#define BAD_W_STAT (BAD_R_STAT | WRERR_STAT)
#define BAD_STAT (BAD_R_STAT | DRQ_STAT)
#define DRIVE_READY (READY_STAT | SEEK_STAT)
#define DATA_READY (DRQ_STAT)
#define IDE_DATA_REG 0
#define IDE_FEATURE_REG 1
#define IDE_NSECTOR_REG 2
#define IDE_SECTOR_REG 3
#define IDE_LCYL_REG 4
#define IDE_HCYL_REG 5
#define IDE_SELECT_REG 6
#define IDE_STATUS 7
#define IDE_CMD 7
#define IDE_CONTROL_REG 0
void Irq0BHandler()
{
// LBts(&sema_irqs[11],0);
}
void Irq0EHandler()
{
// LBts(&sema_irqs[14],0);
}
void Irq0FHandler()
{
// LBts(&sema_irqs[15],0);
}
void ATASelectBlk28(LTBlkDev *bdev,U8 blk,U8 cnt)
{
OutP(bdev->base1+IDE_CONTROL_REG,0x8);
OutP(bdev->base0+IDE_SECTOR_REG,blk);
OutP(bdev->base0+IDE_NSECTOR_REG,cnt);
OutP(bdev->base0+IDE_LCYL_REG,blk.u1[1]);
OutP(bdev->base0+IDE_HCYL_REG,blk.u1[2]);
OutP(bdev->base0+IDE_SELECT_REG,0xE0|bdev->unit<<4|blk.u1[3]);
}
U8 ATAGetBlkNum28(LTBlkDev *bdev)
{
U8 result=0;
result.u1[0]=InP(bdev->base0+IDE_SECTOR_REG);
result.u1[1]=InP(bdev->base0+IDE_LCYL_REG);
result.u1[2]=InP(bdev->base0+IDE_HCYL_REG);
result.u1[3]=InP(bdev->base0+IDE_SELECT_REG) & 0xF;
return result;
}
void ATASelectBlk48(LTBlkDev *bdev,U8 blk,U8 cnt)
{//Untested
OutP(bdev->base1+IDE_CONTROL_REG,0x8);
OutP(bdev->base0+IDE_NSECTOR_REG,cnt.u1[1]);
OutP(bdev->base0+IDE_SECTOR_REG,blk.u1[3]);
OutP(bdev->base0+IDE_LCYL_REG,blk.u1[4]);
OutP(bdev->base0+IDE_HCYL_REG,blk.u1[5]);
OutP(bdev->base0+IDE_NSECTOR_REG,cnt);
OutP(bdev->base0+IDE_SECTOR_REG,blk);
OutP(bdev->base0+IDE_LCYL_REG,blk.u1[1]);
OutP(bdev->base0+IDE_HCYL_REG,blk.u1[2]);
OutP(bdev->base0+IDE_SELECT_REG,0xE0|bdev->unit<<4);
}
void IDEWaitNotBusy(LTBlkDev *bdev)
{
while (InP(bdev->base0+IDE_STATUS) & BUSY_STAT)
SwapInNext;
}
void ATANop(LTBlkDev *bdev)
{
OutP(bdev->base0+IDE_SELECT_REG,0xE0|bdev->unit<<4);
OutP(bdev->base0+IDE_FEATURE_REG,0);
OutP(bdev->base0+IDE_CMD,WIN_NOP);
IDEWaitNotBusy(bdev);
}
void ATACmd(LTBlkDev *bdev,U1 cmd)
{
OutP(bdev->base0+IDE_FEATURE_REG,0);
OutP(bdev->base0+IDE_CMD,cmd);
bdev->last_jiffy=Jiffies;
}
/*******
U8 ATAPIStat(LTBlkDev *bdev)
{
return InP(bdev->base0+IDE_STATUS)+
256*(InP(bdev->base0+IDE_NSECTOR_REG)+
256* InP(bdev->base0+IDE_FEATURE_REG) );
}
**********/
void ATAPIWritePktWord(LTBlkDev *bdev,U2 w)
{
while (!(InP(bdev->base0+IDE_STATUS)&DATA_READY))
SwapInNext;
OutPW(bdev->base0+IDE_DATA_REG,w.u1[1]+256*w.u1[0]);
bdev->last_jiffy=Jiffies;
}
void IDEWaitForDrive(LTBlkDev *bdev)
{
while (LBts(&sema_irq_busy[bdev->irq],0))
SwapInNext;
LBtr(&sema_irqs[bdev->irq],0);
}
/********
void IDEWaitForIrq(LTBlkDev *bdev)
{
BoolU4 old_flags=GetFlags;
Sti;
while (!LBtr(&sema_irqs[bdev->irq],0))
SwapInNext;
SetFlags(old_flags);
}
*********/
void ATAPISetMaxSpeed(LTBlkDev *bdev)
{
OutP(bdev->base1+IDE_CONTROL_REG,0x8);
OutP(bdev->base0+IDE_SELECT_REG,0xE0|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,WIN_PACKETCMD);
ATAPIWritePktWord(bdev,0xBB00); //Set speed
ATAPIWritePktWord(bdev,0xFFFF); //read at max
ATAPIWritePktWord(bdev,0xFFFF); //write at max
ATAPIWritePktWord(bdev,0);
ATAPIWritePktWord(bdev,0);
ATAPIWritePktWord(bdev,0);
IDEWaitNotBusy(bdev);
}
void ATAPISeek(LTBlkDev *bdev,U8 blk)
{
OutP(bdev->base1+IDE_CONTROL_REG,0x8);
OutP(bdev->base0+IDE_SELECT_REG,0xE0|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,WIN_PACKETCMD);
ATAPIWritePktWord(bdev,0x2B00); //Seek
ATAPIWritePktWord(bdev,blk>>16);
ATAPIWritePktWord(bdev,blk);
ATAPIWritePktWord(bdev,0);
ATAPIWritePktWord(bdev,0);
ATAPIWritePktWord(bdev,0x0000);
IDEWaitNotBusy(bdev);
}
void ATAPIStartStop(LTBlkDev *bdev,BoolU4 start)
{
OutP(bdev->base0+IDE_SELECT_REG,0xE0|bdev->unit<<4);
ATACmd(bdev,WIN_PACKETCMD);
ATAPIWritePktWord(bdev,0x1B00); //Start/Stop
ATAPIWritePktWord(bdev,0x0000);
if (start)
ATAPIWritePktWord(bdev,0x0100);
else
ATAPIWritePktWord(bdev,0x0000);
ATAPIWritePktWord(bdev,0x0000);
ATAPIWritePktWord(bdev,0x0000);
ATAPIWritePktWord(bdev,0x0000);
IDEWaitNotBusy(bdev);
}
void IDEInit(LTBlkDev *bdev,BoolU4 unlock)
{
CheckLTBlkDev(bdev);
if (unlock)
IDEWaitForDrive(bdev);
LBtr(&sema_irqs[bdev->irq],0);
if (!(bdev->flags & LTBDF_HAS_BEEN_RESET)) {
OutP(bdev->base1+IDE_CONTROL_REG,0x8);
OutP(bdev->base0+IDE_SELECT_REG,0xE0|bdev->unit<<4);
ATACmd(bdev,WIN_DEV_RESET);
IDEWaitNotBusy(bdev);
bdev->flags=bdev->flags | LTBDF_HAS_BEEN_RESET;
}
OutP(bdev->base1+IDE_CONTROL_REG,0x8);
OutP(bdev->base0+IDE_SELECT_REG,0xE0|bdev->unit<<4);
ATACmd(bdev,WIN_READ_NATIVE_MAX);
IDEWaitNotBusy(bdev);
bdev->max_blk=ATAGetBlkNum28(bdev);
ATASelectBlk28(bdev,bdev->max_blk,0);
ATACmd(bdev,WIN_SET_MAX);
IDEWaitNotBusy(bdev);
if (bdev->type==LTBDT_ATAPI) {
ATAPIStartStop(bdev,TRUE);
ATAPISetMaxSpeed(bdev);
}
LBtr(&sema_irqs[bdev->irq],0);
if (unlock)
LBtr(&sema_irq_busy[bdev->irq],0);
}
/**********
void IDEWaitReady(LTBlkDev *bdev)
{
U8 i=0;
while (!(InP(bdev->base0+IDE_STATUS) & READY_STAT)) {
if (!(++i & 0xFFF))
IDEInit(bdev,FALSE);
ATANop(bdev);
SwapInNext;
}
}
***********/
void ATAPIWaitReady(LTBlkDev *bdev)
{
U8 pass=0;
BoolU4 cont;
do {
IDEWaitNotBusy(bdev);
if (pass)
SwapInNext;
ATANop(bdev);
if (InP(bdev->base0+IDE_STATUS) & READY_STAT) {
if (!bdev->last_jiffy || pass>16 ||
(Jiffies>bdev->last_jiffy+JIFFY_FREQ<<1)) {
ATAPIStartStop(bdev,TRUE);
}
cont=FALSE;
} else {
if (pass>16)
IDEInit(bdev,FALSE);
cont=TRUE;
}
pass++;
} while (cont || InP(bdev->base0+IDE_FEATURE_REG));
}
void ATAReadBlks2(LTBlkDev *bdev,U1 *buf, U8 cnt)
{
U8 U2s_avail,sectors_avail;
while (cnt) {
while (!(InP(bdev->base0+IDE_STATUS) & DATA_READY))
SwapInNext;
sectors_avail=1;
U2s_avail=sectors_avail<<BLK_SIZE_BITS>>1;
RepInSW(buf,U2s_avail,bdev->base0+IDE_DATA_REG);
buf+=U2s_avail<<1;
cnt-=sectors_avail;
}
IDEWaitNotBusy(bdev);
LBtr(&sema_irqs[bdev->irq],0);
}
/***********
void ATAReadBlksExt(LTBlkDev *bdev,U1 *buf, U8 blk, U8 cnt)
{// Untested
IDEWaitForDrive(bdev);
ATASelectBlk48(bdev,blk,0,cnt);
ATACmd(bdev,WIN_MULTREAD_EXT);
ATAReadBlks2(bdev,buf,cnt);
LBtr(&sema_irq_busy[bdev->irq],0);
}
*************/
void ATAReadBlks(LTBlkDev *bdev,U1 *buf, U8 blk, U8 cnt)
{
IDEWaitForDrive(bdev);
while ((InP(bdev->base0+IDE_STATUS) & DATA_READY))
SwapInNext;
ATASelectBlk28(bdev,blk,cnt);
ATACmd(bdev,WIN_MULTREAD);
ATAReadBlks2(bdev,buf,cnt);
LBtr(&sema_irq_busy[bdev->irq],0);
}
I8 IDEProbe(I8 base0,I8 base1,I8 unit)
{
nounusedwarn base1;
I8 timeout=0;
OutP(base0+IDE_SELECT_REG,0xE0|unit<<4);
OutP(base0+IDE_CMD,WIN_NOP);
while (InP(base0+IDE_STATUS) & BUSY_STAT) {
if (timeout++>5000)
return LTBDT_NULL;
PortNop;
}
if (timeout)
return LTBDT_ATA;
else
return LTBDT_NULL;
}
void ATAPIReadBlks2(LTBlkDev *bdev,U1 *buf, U8 blk, U8 cnt)
{
U8 U2s_avail;
U1 *done_add=buf+cnt*bdev->blk_size;
if (!cnt)
return;
IDEWaitForDrive(bdev);
while ((InP(bdev->base0+IDE_STATUS) & DATA_READY))
SwapInNext;
ATAPIWaitReady(bdev);
OutP(bdev->base1+IDE_CONTROL_REG,0x8);
OutP(bdev->base0+IDE_SELECT_REG,0xE0|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,WIN_PACKETCMD);
ATAPIWritePktWord(bdev,0xA800);
ATAPIWritePktWord(bdev,blk.u2[1]);
ATAPIWritePktWord(bdev,blk);
ATAPIWritePktWord(bdev,cnt.u2[1]);
ATAPIWritePktWord(bdev,cnt);
ATAPIWritePktWord(bdev,0x0000);
while (buf<done_add) {
while (!(InP(bdev->base0+IDE_STATUS) & DATA_READY))
SwapInNext;
if (U2s_avail=(InP(bdev->base0+IDE_HCYL_REG)<<8+InP(bdev->base0+IDE_LCYL_REG))>>1) {
if (buf+U2s_avail<<1>done_add)
U2s_avail=(done_add-buf)>>1;
RepInSW(buf,U2s_avail,bdev->base0+IDE_DATA_REG);
buf+=U2s_avail<<1;
}
}
IDEWaitNotBusy(bdev);
// ATAPIStartStop(bdev,FALSE);
LBtr(&sema_irq_busy[bdev->irq],0);
}
void ATAPIReadBlks(LTBlkDev *bdev,U1 *buf, U8 blk, U8 cnt)
{
LTPartition *p=DriveToPartition(bdev->partition_base);
U8 dv=bdev->blk_size>>BLK_SIZE_BITS,n,blk2,
l2=bdev->max_reads<<1+dv<<1;
U1 *cd_buf=MAlloc(l2<<BLK_SIZE_BITS);
if (cnt) {
if (blk<=bdev->max_reads)
blk2=0;
else
blk2=((blk-bdev->max_reads)/dv)*dv;
if (blk2+l2>p->size)
l2=p->size-blk2;
n=(l2+dv-1)/dv;
ATAPIReadBlks2(bdev,cd_buf,blk2/dv,n);
if (bdev->flags & LTBDF_READ_CACHE)
LTDCAdd(p,cd_buf,blk2,n*dv);
MemCpy(buf,cd_buf+(blk-blk2)<<BLK_SIZE_BITS,cnt<<BLK_SIZE_BITS);
}
Free(cd_buf);
}
void IDERBlks(LTPartition *p,U1 *buf, U8 blk, U8 cnt)
{
U8 n;
LTBlkDev *bdev=p->bdev;
CheckLTBlkDev(bdev);
while (cnt>0) {
n=cnt;
if (n>bdev->max_reads)
n=bdev->max_reads;
if (bdev->type==LTBDT_ATAPI)
ATAPIReadBlks(bdev,buf,blk,n);
else
ATAReadBlks(bdev,buf,blk,n);
buf+=n<<BLK_SIZE_BITS;
blk+=n;
cnt-=n;
}
}
//This is for low level disk access
//Call WBlks() instead
void ATAWriteBlks(LTBlkDev *bdev,U1 *buf, U8 blk, U8 cnt)
{
U8 i,U2s_avail,sectors_avail;
IDEWaitForDrive(bdev);
ATASelectBlk28(bdev,blk,cnt);
ATACmd(bdev,WIN_MULTWRITE);
while (cnt) {
do {
i=InP(bdev->base0+IDE_STATUS);
if (i & DRIVE_READY!=DRIVE_READY ||
!(i & DATA_READY)) {
SwapInNext;
} else
break;
} while (TRUE);
//TODO
sectors_avail=1;
U2s_avail=sectors_avail<<BLK_SIZE_BITS>>1;
RepOutSW(buf,U2s_avail,bdev->base0+IDE_DATA_REG);
buf+=U2s_avail<<1;
cnt-=sectors_avail;
}
IDEWaitNotBusy(bdev);
LBtr(&sema_irq_busy[bdev->irq],0);
}
void ATAPISync(LTBlkDev *bdev)
{
IDEWaitNotBusy(bdev);
OutP(bdev->base1+IDE_CONTROL_REG,0x8);
OutP(bdev->base0+IDE_SELECT_REG,0xE0|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,WIN_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)
{
OutP(bdev->base1+IDE_CONTROL_REG,0x8);
OutP(bdev->base0+IDE_SELECT_REG,0xE0|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,WIN_PACKETCMD);
ATAPIWritePktWord(bdev,0x5B00); //Close
ATAPIWritePktWord(bdev,0x0200);
ATAPIWritePktWord(bdev,0x0000);
ATAPIWritePktWord(bdev,0x0000);
ATAPIWritePktWord(bdev,0x0000);
ATAPIWritePktWord(bdev,0x0000);
IDEWaitNotBusy(bdev);
}
void ATAPIWriteBlks(LTBlkDev *bdev,U1 *buf, U8 blk, U8 cnt)
{
U8 U2s_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,0xE0|bdev->unit<<4);
OutP(bdev->base0+IDE_CMD,WIN_PACKETCMD);
ATAPIWritePktWord(bdev,0x0400); //FMT
ATAPIWritePktWord(bdev,blk.u2[1]);
ATAPIWritePktWord(bdev,blk);
ATAPIWritePktWord(bdev,cnt.u2[1]);
ATAPIWritePktWord(bdev,cnt);
ATAPIWritePktWord(bdev,0x0000);
IDEWaitNotBusy(bdev);
ATAPISeek(bdev,blk);
OutP(bdev->base1+IDE_CONTROL_REG,0x8);
OutP(bdev->base0+IDE_SELECT_REG,0xE0|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,WIN_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) & DATA_READY))
SwapInNext;
U2s_avail=(InP(bdev->base0+IDE_HCYL_REG)<<8+InP(bdev->base0+IDE_LCYL_REG))>>1;
if (buf+U2s_avail<<1>buf2)
U2s_avail=(buf2-buf)>>1;
if (U2s_avail) {
RepOutSW(buf,U2s_avail,bdev->base0+IDE_DATA_REG);
buf+=U2s_avail<<1;
}
}
}
//TODO: needs to be fixed so it does more than one blk at
//a time when it calls ATAWriteBlks.
void IDEWBlks(LTPartition *p,U1 *buf, U8 blk, U8 cnt)
{
U8 n,dv;
LTBlkDev *bdev=p->bdev;
CheckLTBlkDev(bdev);
dv=bdev->blk_size>>BLK_SIZE_BITS;
if (bdev->type==LTBDT_ATAPI) {
IDEWaitForDrive(bdev);
ATAPIWaitReady(bdev);
}
while (cnt>0) {
n=cnt;
if (n>bdev->max_writes)
n=bdev->max_writes;
if (bdev->type==LTBDT_ATAPI)
ATAPIWriteBlks(bdev,buf,blk/dv,(n+dv-1)/dv);
else
ATAWriteBlks(bdev,buf,blk,n);
buf+=n<<BLK_SIZE_BITS;
blk+=n;
cnt-=n;
}
if (bdev->type==LTBDT_ATAPI) {
ATAPISync(bdev);
// ATAPIStartStop(bdev,FALSE);
LBtr(&sema_irq_busy[bdev->irq],0);
}
}