Add files to repository
This commit is contained in:
parent
443c63b64d
commit
12553eeeb1
7 changed files with 1489 additions and 1 deletions
601
Src/DskATA.HC
Normal file
601
Src/DskATA.HC
Normal file
|
@ -0,0 +1,601 @@
|
|||
U0 ATABlkSel(CBlkDev *bd, I64 blk, I64 cnt) {
|
||||
if (bd->type != BDT_ATAPI && bd->base1)
|
||||
OutU8(bd->base1 + ATAR1_CTRL, 0x8);
|
||||
if (bd->flags & BDF_EXT_SIZE) { // 48 Bit LBA?
|
||||
OutU8(bd->base0 + ATAR0_NSECT, cnt.u8[1]);
|
||||
OutU8(bd->base0 + ATAR0_SECT, blk.u8[3]);
|
||||
OutU8(bd->base0 + ATAR0_LCYL, blk.u8[4]);
|
||||
OutU8(bd->base0 + ATAR0_HCYL, blk.u8[5]);
|
||||
OutU8(bd->base0 + ATAR0_NSECT, cnt);
|
||||
OutU8(bd->base0 + ATAR0_SECT, blk);
|
||||
OutU8(bd->base0 + ATAR0_LCYL, blk.u8[1]);
|
||||
OutU8(bd->base0 + ATAR0_HCYL, blk.u8[2]);
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xEF | bd->unit << 4);
|
||||
} else { // 28 Bit LBA
|
||||
OutU8(bd->base0 + ATAR0_NSECT, cnt);
|
||||
OutU8(bd->base0 + ATAR0_SECT, blk);
|
||||
OutU8(bd->base0 + ATAR0_LCYL, blk.u8[1]);
|
||||
OutU8(bd->base0 + ATAR0_HCYL, blk.u8[2]);
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xE0 | bd->unit << 4 | blk.u8[3]);
|
||||
}
|
||||
}
|
||||
|
||||
Bool ATAWaitNotBUSY(CBlkDev *bd, F64 timeout) {
|
||||
I64 i;
|
||||
do {
|
||||
for (i = 0; i < 3; i++)
|
||||
if (!(InU8(bd->base0 + ATAR0_STAT) & ATAS_BSY))
|
||||
return TRUE;
|
||||
Yield;
|
||||
} while (!(0 < timeout < tS));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool ATAWaitDRQ(CBlkDev *bd, F64 timeout) {
|
||||
I64 i;
|
||||
do {
|
||||
for (i = 0; i < 3; i++)
|
||||
if (InU8(bd->base0 + ATAR0_STAT) & ATAS_DRQ)
|
||||
return TRUE;
|
||||
Yield;
|
||||
} while (!(0 < timeout < tS));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Bool ATANop(CBlkDev *bd, F64 timeout) {
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xEF | bd->unit << 4);
|
||||
else
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xE0 | bd->unit << 4);
|
||||
OutU8(bd->base0 + ATAR0_FEAT, 0);
|
||||
OutU8(bd->base0 + ATAR0_CMD, ATA_NOP);
|
||||
return ATAWaitNotBUSY(bd, timeout);
|
||||
}
|
||||
|
||||
U0 ATACmd(CBlkDev *bd, U8 cmd) {
|
||||
OutU8(bd->base0 + ATAR0_FEAT, 0);
|
||||
OutU8(bd->base0 + ATAR0_CMD, cmd);
|
||||
bd->last_time = tS;
|
||||
PortNop;
|
||||
}
|
||||
|
||||
Bool ATAGetRes(CBlkDev *bd, F64 timeout, U8 *buf, I64 cnt, I64 _avail,
|
||||
Bool one_read) {
|
||||
I64 avail, overflow;
|
||||
bd->flags &= ~BDF_LAST_WAS_WRITE;
|
||||
MemSet(buf, 0, cnt);
|
||||
while (cnt > 0) {
|
||||
if (!ATAWaitDRQ(bd, timeout))
|
||||
return FALSE;
|
||||
if (_avail)
|
||||
avail = _avail;
|
||||
else
|
||||
avail = InU8(bd->base0 + ATAR0_HCYL) << 8 + InU8(bd->base0 + ATAR0_LCYL);
|
||||
if (avail) {
|
||||
if (avail > cnt) {
|
||||
overflow = avail - cnt;
|
||||
avail = cnt;
|
||||
} else
|
||||
overflow = 0;
|
||||
if (avail & 2)
|
||||
RepInU16(buf, avail >> 1, bd->base0 + ATAR0_DATA);
|
||||
else
|
||||
RepInU32(buf, avail >> 2, bd->base0 + ATAR0_DATA);
|
||||
cnt -= avail;
|
||||
buf += avail;
|
||||
while (overflow > 0) {
|
||||
InU16(bd->base0 + ATAR0_DATA);
|
||||
overflow -= 2;
|
||||
if (0 < timeout < tS)
|
||||
return FALSE;
|
||||
}
|
||||
if (one_read)
|
||||
break;
|
||||
} else
|
||||
Yield;
|
||||
}
|
||||
return ATAWaitNotBUSY(bd, timeout);
|
||||
}
|
||||
|
||||
Bool ATAPIWritePktWord(CBlkDev *bd, F64 timeout, ...) {
|
||||
I64 i;
|
||||
for (i = 0; i < argc; i++) {
|
||||
if (!ATAWaitDRQ(bd, timeout))
|
||||
return FALSE;
|
||||
OutU16(bd->base0 + ATAR0_DATA, EndianU16(argv[i]));
|
||||
bd->last_time = tS;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Bool ATAPISetMaxSpeed(CBlkDev *bd) {
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xEF | bd->unit << 4);
|
||||
else
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xE0 | bd->unit << 4);
|
||||
OutU8(bd->base0 + ATAR0_LCYL, 0);
|
||||
OutU8(bd->base0 + ATAR0_HCYL, 0);
|
||||
ATACmd(bd, ATA_PACKET);
|
||||
ATAPIWritePktWord(bd, 0, 0xBB00, 0xFFFF, 0xFFFF, 0, 0, 0);
|
||||
return ATAWaitNotBUSY(bd, 0);
|
||||
}
|
||||
|
||||
Bool ATAPISeek(CBlkDev *bd, I64 native_blk) {
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xEF | bd->unit << 4);
|
||||
else
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xE0 | bd->unit << 4);
|
||||
OutU8(bd->base0 + ATAR0_LCYL, 0);
|
||||
OutU8(bd->base0 + ATAR0_HCYL, 0);
|
||||
ATACmd(bd, ATA_PACKET);
|
||||
ATAPIWritePktWord(bd, 0, 0x2B00, native_blk >> 16, native_blk, 0, 0, 0);
|
||||
return ATAWaitNotBUSY(bd, 0);
|
||||
}
|
||||
|
||||
Bool ATAPIStartStop(CBlkDev *bd, F64 timeout, Bool start) {
|
||||
I64 i;
|
||||
if (start)
|
||||
i = 0x100;
|
||||
else
|
||||
i = 0;
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xEF | bd->unit << 4);
|
||||
else
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xE0 | bd->unit << 4);
|
||||
ATACmd(bd, ATA_PACKET);
|
||||
// Start/Stop
|
||||
if (ATAPIWritePktWord(bd, timeout, 0x1B00, 0, i, 0, 0, 0))
|
||||
return ATAWaitNotBUSY(bd, timeout);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
I64 ATAGetDevId(CBlkDev *bd, F64 timeout, Bool keep_id_record) {
|
||||
I64 res = BDT_NULL;
|
||||
U16 *id_record = NULL;
|
||||
if (bd->type != BDT_ATAPI && bd->base1)
|
||||
OutU8(bd->base1 + ATAR1_CTRL, 0x8);
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xEF | bd->unit << 4);
|
||||
else
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xE0 | bd->unit << 4);
|
||||
ATACmd(bd, ATA_ID_DEV);
|
||||
ATAWaitNotBUSY(bd, timeout);
|
||||
if (InU8(bd->base0 + ATAR0_STAT) & ATAS_ERR)
|
||||
res = BDT_ATAPI;
|
||||
else {
|
||||
id_record = ACAlloc(512);
|
||||
if (ATAGetRes(bd, timeout, id_record, 512, 512, FALSE))
|
||||
res = BDT_ATA;
|
||||
else {
|
||||
Free(id_record);
|
||||
id_record = NULL;
|
||||
}
|
||||
}
|
||||
if (keep_id_record) {
|
||||
Free(bd->dev_id_record);
|
||||
bd->dev_id_record = id_record;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
I64 ATAReadNativeMax(CBlkDev *bd, F64 timeout) { // Returns zero on err
|
||||
I64 res = 0;
|
||||
Bool okay = TRUE;
|
||||
if (bd->type == BDT_ATAPI) {
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xEF | bd->unit << 4);
|
||||
else
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xE0 | bd->unit << 4);
|
||||
ATACmd(bd, ATA_DEV_RST);
|
||||
if (!ATAWaitNotBUSY(bd, 0))
|
||||
okay = FALSE;
|
||||
} else {
|
||||
while (InU8(bd->base0 + ATAR0_STAT) & ATAS_BSY) {
|
||||
if (bd->flags & BDF_LAST_WAS_WRITE)
|
||||
OutU16(bd->base0 + ATAR0_DATA, 0);
|
||||
else
|
||||
InU16(bd->base0 + ATAR0_DATA);
|
||||
Yield;
|
||||
if (0 < timeout < tS)
|
||||
return FALSE;
|
||||
}
|
||||
if (ATAGetDevId(bd, timeout, TRUE) == BDT_NULL)
|
||||
okay = FALSE;
|
||||
else
|
||||
BEqu(&bd->flags, BDf_EXT_SIZE, Bt(&bd->dev_id_record[86], 10));
|
||||
}
|
||||
if (okay) {
|
||||
if (bd->flags & BDF_EXT_SIZE && bd->base1) {
|
||||
OutU8(bd->base1 + ATAR1_CTRL, 0x8);
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xEF | bd->unit << 4);
|
||||
ATACmd(bd, ATA_READ_NATIVE_MAX_EXT);
|
||||
if (ATAWaitNotBUSY(bd, timeout)) {
|
||||
res.u8[0] = InU8(bd->base0 + ATAR0_SECT);
|
||||
res.u8[1] = InU8(bd->base0 + ATAR0_LCYL);
|
||||
res.u8[2] = InU8(bd->base0 + ATAR0_HCYL);
|
||||
|
||||
OutU8(bd->base1 + ATAR1_CTRL, 0x80);
|
||||
res.u8[3] = InU8(bd->base0 + ATAR0_SECT);
|
||||
res.u8[4] = InU8(bd->base0 + ATAR0_LCYL);
|
||||
res.u8[5] = InU8(bd->base0 + ATAR0_HCYL);
|
||||
|
||||
if (res >> 24 == res & 0xFFFFFF) { // Kludge to make QEMU work
|
||||
bd->flags &= ~BDF_EXT_SIZE;
|
||||
res &= 0xFFFFFF;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (bd->type != BDT_ATAPI && bd->base1)
|
||||
OutU8(bd->base1 + ATAR1_CTRL, 0x8);
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xE0 | bd->unit << 4);
|
||||
ATACmd(bd, ATA_READ_NATIVE_MAX);
|
||||
if (ATAWaitNotBUSY(bd, timeout)) {
|
||||
res.u8[0] = InU8(bd->base0 + ATAR0_SECT);
|
||||
res.u8[1] = InU8(bd->base0 + ATAR0_LCYL);
|
||||
res.u8[2] = InU8(bd->base0 + ATAR0_HCYL);
|
||||
res.u8[3] = InU8(bd->base0 + ATAR0_SEL) & 0xF;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bd->max_blk = res;
|
||||
}
|
||||
|
||||
I64 ATAPIReadCapacity(
|
||||
CBlkDev *bd,
|
||||
I64 *_blk_size = NULL) { // Supposedly this can return a res +/- 75 sects.
|
||||
// Error might just be for music.
|
||||
Bool unlock = BlkDevLock(bd);
|
||||
U32 buf[2];
|
||||
if (ATAWaitNotBUSY(bd, 0)) {
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xEF | bd->unit << 4);
|
||||
else
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xE0 | bd->unit << 4);
|
||||
OutU8(bd->base0 + ATAR0_LCYL, 8);
|
||||
OutU8(bd->base0 + ATAR0_HCYL, 0);
|
||||
ATACmd(bd, ATA_PACKET);
|
||||
ATAPIWritePktWord(bd, 0, 0x2500, 0, 0, 0, 0, 0);
|
||||
if (!ATAGetRes(bd, 0, buf, 8, 0, TRUE))
|
||||
buf[0] = buf[1] = 0;
|
||||
} else
|
||||
buf[0] = buf[1] = 0;
|
||||
|
||||
if (unlock)
|
||||
BlkDevUnlock(bd);
|
||||
if (_blk_size)
|
||||
*_blk_size = EndianU32(buf[1]);
|
||||
return EndianU32(buf[0]);
|
||||
}
|
||||
|
||||
CATAPITrack *ATAPIReadTrackInfo(CBlkDev *bd, I64 blk) {
|
||||
CATAPITrack *res = CAlloc(sizeof(CATAPITrack));
|
||||
Bool unlock = BlkDevLock(bd);
|
||||
if (ATAWaitNotBUSY(bd, 0)) {
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xEF | bd->unit << 4);
|
||||
else
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xE0 | bd->unit << 4);
|
||||
OutU8(bd->base0 + ATAR0_LCYL, sizeof(CATAPITrack) & 0xFF);
|
||||
OutU8(bd->base0 + ATAR0_HCYL, sizeof(CATAPITrack) >> 8);
|
||||
ATACmd(bd, ATA_PACKET);
|
||||
ATAPIWritePktWord(bd, 0, 0x5200, blk.u16[1], blk.u16[0],
|
||||
(sizeof(CATAPITrack) & 0xFF00) >> 8,
|
||||
(sizeof(CATAPITrack) & 0x00FF) << 8, 0);
|
||||
if (!ATAGetRes(bd, 0, res, sizeof(CATAPITrack), 0, TRUE)) {
|
||||
Free(res);
|
||||
res = NULL;
|
||||
}
|
||||
} else {
|
||||
Free(res);
|
||||
res = NULL;
|
||||
}
|
||||
if (unlock)
|
||||
BlkDevUnlock(bd);
|
||||
return res;
|
||||
}
|
||||
|
||||
Bool ATAInit(CBlkDev *bd) {
|
||||
Bool unlock = BlkDevLock(bd), okay = FALSE;
|
||||
|
||||
if (bd->type == BDT_ATAPI)
|
||||
bd->flags &= ~BDF_EXT_SIZE;
|
||||
else
|
||||
bd->flags |= BDF_EXT_SIZE;
|
||||
|
||||
if (ATAReadNativeMax(bd, tS + 0.1)) {
|
||||
ATABlkSel(bd, bd->max_blk, 0);
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
ATACmd(bd, ATA_SET_MAX_EXT);
|
||||
else
|
||||
ATACmd(bd, ATA_SET_MAX);
|
||||
if (ATAWaitNotBUSY(bd, 0)) {
|
||||
okay = TRUE;
|
||||
if (bd->type == BDT_ATAPI) {
|
||||
if (ATAPIStartStop(bd, 0, TRUE)) {
|
||||
if (!ATAPISetMaxSpeed(bd))
|
||||
okay = FALSE;
|
||||
} else
|
||||
okay = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (unlock)
|
||||
BlkDevUnlock(bd);
|
||||
return okay;
|
||||
}
|
||||
|
||||
Bool ATAPIWaitReady(CBlkDev *bd, F64 timeout) {
|
||||
do {
|
||||
if (!ATAWaitNotBUSY(bd, timeout) || !ATANop(bd, timeout) ||
|
||||
!ATAPIStartStop(bd, timeout, TRUE))
|
||||
return FALSE;
|
||||
if (InU8(bd->base0 + ATAR0_STAT) & ATAS_DRDY &&
|
||||
!InU8(bd->base0 + ATAR0_FEAT))
|
||||
;
|
||||
return TRUE;
|
||||
ATAInit(bd);
|
||||
Yield;
|
||||
} while (!(0 < timeout < tS));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
U0 ATAReadBlks(CBlkDev *bd, U8 *buf, I64 blk, I64 cnt) {
|
||||
I64 retries = 3;
|
||||
Bool unlock = BlkDevLock(bd);
|
||||
|
||||
retry:
|
||||
ATABlkSel(bd, blk, cnt);
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
ATACmd(bd, ATA_READ_MULTI_EXT);
|
||||
else
|
||||
ATACmd(bd, ATA_READ_MULTI);
|
||||
if (!ATAGetRes(bd, tS + 1.0, buf, cnt * bd->blk_size, BLK_SIZE, FALSE)) {
|
||||
if (retries--) {
|
||||
ATAWaitNotBUSY(bd, 0);
|
||||
goto retry;
|
||||
} else
|
||||
throw('BlkDev');
|
||||
}
|
||||
|
||||
blkdev.read_cnt += (cnt * bd->blk_size) >> BLK_SIZE_BITS;
|
||||
if (unlock)
|
||||
BlkDevUnlock(bd);
|
||||
}
|
||||
|
||||
I64 ATAProbe(I64 base0, I64 base1, I64 unit) {
|
||||
CBlkDev bd;
|
||||
MemSet(&bd, 0, sizeof(CBlkDev));
|
||||
bd.type = BDT_ATAPI;
|
||||
bd.base0 = base0;
|
||||
bd.base1 = base1;
|
||||
bd.unit = unit;
|
||||
bd.blk_size = DVD_BLK_SIZE;
|
||||
return ATAGetDevId(&bd, tS + 0.1, FALSE);
|
||||
}
|
||||
|
||||
Bool ATAPIReadBlks2(CBlkDev *bd, F64 timeout, U8 *buf, I64 native_blk, I64 cnt,
|
||||
Bool lock) {
|
||||
Bool res = FALSE, unlock;
|
||||
if (cnt <= 0)
|
||||
return FALSE;
|
||||
if (lock)
|
||||
unlock = BlkDevLock(bd);
|
||||
if (ATAPIWaitReady(bd, timeout)) {
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xEF | bd->unit << 4);
|
||||
else
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xE0 | bd->unit << 4);
|
||||
OutU8(bd->base0 + ATAR0_LCYL, bd->blk_size);
|
||||
OutU8(bd->base0 + ATAR0_HCYL, bd->blk_size.u8[1]);
|
||||
ATACmd(bd, ATA_PACKET);
|
||||
if (ATAPIWritePktWord(bd, timeout, 0xA800, native_blk.u16[1], native_blk,
|
||||
cnt.u16[1], cnt, 0) &&
|
||||
ATAGetRes(bd, timeout, buf, cnt * bd->blk_size, 0, FALSE)) {
|
||||
blkdev.read_cnt += (cnt * bd->blk_size) >> BLK_SIZE_BITS;
|
||||
res = TRUE;
|
||||
}
|
||||
}
|
||||
// ATAPIStartStop(bd,0,FALSE);
|
||||
if (lock && unlock)
|
||||
BlkDevUnlock(bd);
|
||||
return res;
|
||||
}
|
||||
|
||||
U0 ATAPIReadBlks(CBlkDev *bd, U8 *buf, I64 blk, I64 cnt) {
|
||||
CDrv *dv = Let2Drv(bd->first_drv_let);
|
||||
I64 retry, spc = bd->blk_size >> BLK_SIZE_BITS, n, blk2,
|
||||
l2 = bd->max_reads << 1 + spc << 1;
|
||||
U8 *dvd_buf = MAlloc(l2 << BLK_SIZE_BITS);
|
||||
if (cnt > 0) {
|
||||
if (blk <= bd->max_reads)
|
||||
blk2 = 0;
|
||||
else
|
||||
blk2 = FloorU64(blk - bd->max_reads, spc);
|
||||
if (blk2 + l2 > dv->size + dv->drv_offset)
|
||||
l2 = dv->size + dv->drv_offset - blk2;
|
||||
n = (l2 + spc - 1) / spc;
|
||||
|
||||
retry = 4;
|
||||
while (--retry)
|
||||
if (ATAPIReadBlks2(bd, tS + 7.0 + 0.004 * n, dvd_buf, blk2 / spc, n,
|
||||
TRUE))
|
||||
// n is 0x800 if max_reads. Up to 8 additional seconds
|
||||
break;
|
||||
if (!retry)
|
||||
ATAPIReadBlks2(bd, 0, dvd_buf, blk2 / spc, n, TRUE);
|
||||
if (bd->flags & BDF_READ_CACHE)
|
||||
DskCacheAdd(dv, dvd_buf, blk2, n * spc);
|
||||
MemCpy(buf, dvd_buf + (blk - blk2) << BLK_SIZE_BITS, cnt << BLK_SIZE_BITS);
|
||||
}
|
||||
Free(dvd_buf);
|
||||
}
|
||||
|
||||
Bool ATARBlks(CDrv *dv, U8 *buf, I64 blk, I64 cnt) {
|
||||
I64 n;
|
||||
CBlkDev *bd = dv->bd;
|
||||
while (cnt > 0) {
|
||||
n = cnt;
|
||||
if (n > bd->max_reads)
|
||||
n = bd->max_reads;
|
||||
if (bd->type == BDT_ATAPI)
|
||||
ATAPIReadBlks(bd, buf, blk, n);
|
||||
else
|
||||
ATAReadBlks(bd, buf, blk, n);
|
||||
buf += n << BLK_SIZE_BITS;
|
||||
blk += n;
|
||||
cnt -= n;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
U0 ATAWriteBlks(CBlkDev *bd, U8 *buf, I64 blk,
|
||||
I64 cnt) { // For low level disk access.
|
||||
// Use BlkWrite() instead.
|
||||
I64 i, U32s_avail, sects_avail, retries = 3;
|
||||
F64 timeout;
|
||||
Bool unlock = BlkDevLock(bd);
|
||||
retry:
|
||||
ATABlkSel(bd, blk, cnt);
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
ATACmd(bd, ATA_WRITE_MULTI_EXT);
|
||||
else
|
||||
ATACmd(bd, ATA_WRITE_MULTI);
|
||||
bd->flags |= BDF_LAST_WAS_WRITE;
|
||||
while (cnt > 0) {
|
||||
timeout = tS + 1.0;
|
||||
while (TRUE) {
|
||||
i = InU8(bd->base0 + ATAR0_STAT);
|
||||
if (!(i & ATAS_DRDY) || !(i & ATAS_DRQ)) {
|
||||
Yield;
|
||||
} else
|
||||
break;
|
||||
if (/* i&ATAS_ERR||*/ tS > timeout) {
|
||||
if (retries--) {
|
||||
ATAWaitNotBUSY(bd, 0);
|
||||
goto retry;
|
||||
} else
|
||||
throw('BlkDev');
|
||||
}
|
||||
}
|
||||
sects_avail = 1;
|
||||
U32s_avail = sects_avail << BLK_SIZE_BITS >> 2;
|
||||
RepOutU32(buf, U32s_avail, bd->base0 + ATAR0_DATA);
|
||||
buf += U32s_avail << 2;
|
||||
cnt -= sects_avail;
|
||||
retries = 3;
|
||||
}
|
||||
ATAWaitNotBUSY(bd, 0);
|
||||
if (unlock)
|
||||
BlkDevUnlock(bd);
|
||||
}
|
||||
|
||||
Bool ATAPISync(CBlkDev *bd) {
|
||||
Bool okay = TRUE;
|
||||
if (!ATAWaitNotBUSY(bd, 0))
|
||||
okay = FALSE;
|
||||
else {
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xEF | bd->unit << 4);
|
||||
else
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xE0 | bd->unit << 4);
|
||||
OutU8(bd->base0 + ATAR0_LCYL, 0);
|
||||
OutU8(bd->base0 + ATAR0_HCYL, 0);
|
||||
ATACmd(bd, ATA_PACKET);
|
||||
ATAPIWritePktWord(bd, 0, 0x3500, 0, 0, 0, 0, 0);
|
||||
if (!ATAWaitNotBUSY(bd, 0))
|
||||
okay = FALSE;
|
||||
}
|
||||
return okay;
|
||||
}
|
||||
|
||||
U0 ATAPIClose(CBlkDev *bd, I64 close_field = 0x200,
|
||||
I64 track = 0) { // 0x200 CD/DVD part 1
|
||||
// 0x300 DVD part 2
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xEF | bd->unit << 4);
|
||||
else
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xE0 | bd->unit << 4);
|
||||
OutU8(bd->base0 + ATAR0_LCYL, 0);
|
||||
OutU8(bd->base0 + ATAR0_HCYL, 0);
|
||||
ATACmd(bd, ATA_PACKET);
|
||||
ATAPIWritePktWord(bd, 0, 0x5B00, close_field, track, 0, 0, 0);
|
||||
ATAWaitNotBUSY(bd, 0);
|
||||
}
|
||||
|
||||
U0 ATAPIWriteBlks(CBlkDev *bd, U8 *buf, I64 native_blk, I64 cnt) {
|
||||
I64 U32s_avail;
|
||||
U8 *buf2;
|
||||
ATAWaitNotBUSY(bd, 0);
|
||||
ATAPISeek(bd, native_blk);
|
||||
|
||||
OutU8(bd->base0 + ATAR0_FEAT, 0);
|
||||
OutU8(bd->base0 + ATAR0_LCYL, bd->blk_size);
|
||||
OutU8(bd->base0 + ATAR0_HCYL, bd->blk_size.u8[1]);
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xEF | bd->unit << 4);
|
||||
else
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xE0 | bd->unit << 4);
|
||||
OutU8(bd->base0 + ATAR0_CMD, ATA_PACKET);
|
||||
ATAPIWritePktWord(bd, 0, 0x0400, native_blk.u16[1], native_blk, cnt.u16[1],
|
||||
cnt, 0);
|
||||
bd->flags |= BDF_LAST_WAS_WRITE;
|
||||
ATAWaitNotBUSY(bd, 0);
|
||||
|
||||
ATAPISeek(bd, native_blk);
|
||||
|
||||
if (bd->flags & BDF_EXT_SIZE)
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xEF | bd->unit << 4);
|
||||
else
|
||||
OutU8(bd->base0 + ATAR0_SEL, 0xE0 | bd->unit << 4);
|
||||
OutU8(bd->base0 + ATAR0_LCYL, bd->blk_size);
|
||||
OutU8(bd->base0 + ATAR0_HCYL, bd->blk_size.u8[1]);
|
||||
ATACmd(bd, ATA_PACKET);
|
||||
ATAPIWritePktWord(bd, 0, 0xAA00, native_blk.u16[1], native_blk, cnt.u16[1],
|
||||
cnt, 0);
|
||||
buf2 = buf + bd->blk_size * cnt;
|
||||
while (buf < buf2) {
|
||||
ATAWaitDRQ(bd, 0);
|
||||
U32s_avail =
|
||||
(InU8(bd->base0 + ATAR0_HCYL) << 8 + InU8(bd->base0 + ATAR0_LCYL)) >> 2;
|
||||
if (buf + U32s_avail << 2 > buf2)
|
||||
U32s_avail = (buf2 - buf) >> 2;
|
||||
if (U32s_avail) {
|
||||
RepOutU32(buf, U32s_avail, bd->base0 + ATAR0_DATA);
|
||||
buf += U32s_avail << 2;
|
||||
blkdev.write_cnt += U32s_avail >> (BLK_SIZE_BITS - 2);
|
||||
}
|
||||
}
|
||||
ATAWaitNotBUSY(bd, 0);
|
||||
}
|
||||
|
||||
Bool ATAWBlks(CDrv *dv, U8 *buf, I64 blk, I64 cnt) {
|
||||
I64 n, spc;
|
||||
CBlkDev *bd = dv->bd;
|
||||
Bool unlock;
|
||||
spc = bd->blk_size >> BLK_SIZE_BITS;
|
||||
if (bd->type == BDT_ATAPI) {
|
||||
unlock = BlkDevLock(bd);
|
||||
ATAPIWaitReady(bd, 0);
|
||||
}
|
||||
while (cnt > 0) {
|
||||
n = cnt;
|
||||
if (n > bd->max_writes)
|
||||
n = bd->max_writes;
|
||||
if (bd->type == BDT_ATAPI)
|
||||
ATAPIWriteBlks(bd, buf, blk / spc, (n + spc - 1) / spc);
|
||||
else
|
||||
ATAWriteBlks(bd, buf, blk, n);
|
||||
buf += n << BLK_SIZE_BITS;
|
||||
blk += n;
|
||||
cnt -= n;
|
||||
blkdev.write_cnt += n;
|
||||
}
|
||||
if (bd->type == BDT_ATAPI) {
|
||||
ATAPISync(bd);
|
||||
// ATAPIStartStop(bd,0,FALSE);
|
||||
if (unlock)
|
||||
BlkDevUnlock(bd);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue