hschumann2/TempleOS-Source-Code
0847
1 2U0 ATABlkSel(CBlkDev *bd,I64 blk,I64 cnt)3{4 if (bd->type!=BDT_ATAPI && bd->base1)5 OutU8(bd->base1+ATAR1_CTRL,0x8);6 if (bd->flags & BDF_EXT_SIZE) { //48 Bit LBA?7 OutU8(bd->base0+ATAR0_NSECT,cnt.u8[1]);8 OutU8(bd->base0+ATAR0_SECT,blk.u8[3]);9 OutU8(bd->base0+ATAR0_LCYL,blk.u8[4]);10 OutU8(bd->base0+ATAR0_HCYL,blk.u8[5]);11 OutU8(bd->base0+ATAR0_NSECT,cnt);12 OutU8(bd->base0+ATAR0_SECT,blk);13 OutU8(bd->base0+ATAR0_LCYL,blk.u8[1]);14 OutU8(bd->base0+ATAR0_HCYL,blk.u8[2]);15 OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);16 } else { //28 Bit LBA17 OutU8(bd->base0+ATAR0_NSECT,cnt);18 OutU8(bd->base0+ATAR0_SECT,blk);19 OutU8(bd->base0+ATAR0_LCYL,blk.u8[1]);20 OutU8(bd->base0+ATAR0_HCYL,blk.u8[2]);21 OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4|blk.u8[3]);22 }23}24 25Bool ATAWaitNotBUSY(CBlkDev *bd,F64 timeout)26{27 I64 i;28 do {29 for (i=0;i<3;i++)30 if (!(InU8(bd->base0+ATAR0_STAT)&ATAS_BSY))31 return TRUE;32 Yield;33 } while (!(0<timeout<tS));34 return FALSE;35}36 37Bool ATAWaitDRQ(CBlkDev *bd,F64 timeout)38{39 I64 i;40 do {41 for (i=0;i<3;i++)42 if (InU8(bd->base0+ATAR0_STAT)&ATAS_DRQ)43 return TRUE;44 Yield;45 } while (!(0<timeout<tS));46 return FALSE;47}48 49Bool ATANop(CBlkDev *bd,F64 timeout)50{51 if (bd->flags & BDF_EXT_SIZE)52 OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);53 else54 OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);55 OutU8(bd->base0+ATAR0_FEAT,0);56 OutU8(bd->base0+ATAR0_CMD,ATA_NOP);57 return ATAWaitNotBUSY(bd,timeout);58}59 60U0 ATACmd(CBlkDev *bd,U8 cmd)61{62 OutU8(bd->base0+ATAR0_FEAT,0);63 OutU8(bd->base0+ATAR0_CMD,cmd);64 bd->last_time=tS;65 PortNop;66}67 68Bool ATAGetRes(CBlkDev *bd,F64 timeout,U8 *buf,I64 cnt,69 I64 _avail,Bool one_read)70{71 I64 avail,overflow;72 bd->flags&=~BDF_LAST_WAS_WRITE;73 MemSet(buf,0,cnt);74 while (cnt>0) {75 if (!ATAWaitDRQ(bd,timeout))76 return FALSE;77 if (_avail)78 avail=_avail;79 else80 avail=InU8(bd->base0+ATAR0_HCYL)<<8+InU8(bd->base0+ATAR0_LCYL);81 if (avail) {82 if (avail>cnt) {83 overflow=avail-cnt;84 avail=cnt;85 } else86 overflow=0;87 if (avail&2)88 RepInU16(buf,avail>>1,bd->base0+ATAR0_DATA);89 else90 RepInU32(buf,avail>>2,bd->base0+ATAR0_DATA);91 cnt-=avail;92 buf+=avail;93 while (overflow>0) {94 InU16(bd->base0+ATAR0_DATA);95 overflow-=2;96 if (0<timeout<tS)97 return FALSE;98 }99 if (one_read)100 break;101 } else102 Yield;103 }104 return ATAWaitNotBUSY(bd,timeout);105}106 107Bool ATAPIWritePktWord(CBlkDev *bd,F64 timeout,...)108{109 I64 i;110 for (i=0;i<argc;i++) {111 if (!ATAWaitDRQ(bd,timeout))112 return FALSE;113 OutU16(bd->base0+ATAR0_DATA,EndianU16(argv[i]));114 bd->last_time=tS;115 }116 return TRUE;117}118 119Bool ATAPISetMaxSpeed(CBlkDev *bd)120{121 if (bd->flags & BDF_EXT_SIZE)122 OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);123 else124 OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);125 OutU8(bd->base0+ATAR0_LCYL,0);126 OutU8(bd->base0+ATAR0_HCYL,0);127 ATACmd(bd,ATA_PACKET);128 ATAPIWritePktWord(bd,0,0xBB00,0xFFFF,0xFFFF,0,0,0);129 return ATAWaitNotBUSY(bd,0);130}131 132Bool ATAPISeek(CBlkDev *bd,I64 native_blk)133{134 if (bd->flags & BDF_EXT_SIZE)135 OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);136 else137 OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);138 OutU8(bd->base0+ATAR0_LCYL,0);139 OutU8(bd->base0+ATAR0_HCYL,0);140 ATACmd(bd,ATA_PACKET);141 ATAPIWritePktWord(bd,0,0x2B00,native_blk>>16,native_blk,0,0,0);142 return ATAWaitNotBUSY(bd,0);143}144 145Bool ATAPIStartStop(CBlkDev *bd,F64 timeout,Bool start)146{147 I64 i;148 if (start)149 i=0x100;150 else151 i=0;152 if (bd->flags & BDF_EXT_SIZE)153 OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);154 else155 OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);156 ATACmd(bd,ATA_PACKET);157//Start/Stop158 if (ATAPIWritePktWord(bd,timeout,0x1B00,0,i,0,0,0))159 return ATAWaitNotBUSY(bd,timeout);160 else161 return FALSE;162}163 164I64 ATAGetDevId(CBlkDev *bd,F64 timeout,Bool keep_id_record)165{166 I64 res=BDT_NULL;167 U16 *id_record=NULL;168 if (bd->type!=BDT_ATAPI && bd->base1)169 OutU8(bd->base1+ATAR1_CTRL,0x8);170 if (bd->flags & BDF_EXT_SIZE)171 OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);172 else173 OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);174 ATACmd(bd,ATA_ID_DEV);175 if (ATAWaitNotBUSY(bd,timeout)) {176 if (InU8(bd->base0+ATAR0_STAT)&ATAS_ERR)177 res=BDT_ATAPI;178 else {179 id_record=ACAlloc(512);180 if (ATAGetRes(bd,timeout,id_record,512,512,FALSE))181 res=BDT_ATA;182 else {183 Free(id_record);184 id_record=NULL;185 }186 }187 }188 if (keep_id_record) {189 Free(bd->dev_id_record);190 bd->dev_id_record=id_record;191 }192 return res;193}194 195I64 ATAReadNativeMax(CBlkDev *bd,F64 timeout)196{//Returns zero on err197 I64 res=0;198 Bool okay=TRUE;199 if (bd->type==BDT_ATAPI) {200 if (bd->flags & BDF_EXT_SIZE)201 OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);202 else203 OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);204 ATACmd(bd,ATA_DEV_RST);205 if (!ATAWaitNotBUSY(bd,0))206 okay=FALSE;207 } else {208 while (InU8(bd->base0+ATAR0_STAT) & ATAS_BSY) {209 if (bd->flags&BDF_LAST_WAS_WRITE)210 OutU16(bd->base0+ATAR0_DATA,0);211 else212 InU16(bd->base0+ATAR0_DATA);213 Yield;214 if (0<timeout<tS)215 return FALSE;216 }217 if (ATAGetDevId(bd,timeout,TRUE)==BDT_NULL)218 okay=FALSE;219 else220 BEqu(&bd->flags,BDf_EXT_SIZE,Bt(&bd->dev_id_record[86],10));221 }222 if (okay) {223 if (bd->flags & BDF_EXT_SIZE && bd->base1) {224 OutU8(bd->base1+ATAR1_CTRL,0x8);225 OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);226 ATACmd(bd,ATA_READ_NATIVE_MAX_EXT);227 if (ATAWaitNotBUSY(bd,timeout)) {228 res.u8[0]=InU8(bd->base0+ATAR0_SECT);229 res.u8[1]=InU8(bd->base0+ATAR0_LCYL);230 res.u8[2]=InU8(bd->base0+ATAR0_HCYL);231 232 OutU8(bd->base1+ATAR1_CTRL,0x80);233 res.u8[3]=InU8(bd->base0+ATAR0_SECT);234 res.u8[4]=InU8(bd->base0+ATAR0_LCYL);235 res.u8[5]=InU8(bd->base0+ATAR0_HCYL);236 237 if (res>>24==res&0xFFFFFF) {//Kludge to make QEMU work238 bd->flags&=~BDF_EXT_SIZE;239 res&=0xFFFFFF;240 }241 }242 } else {243 if (bd->type!=BDT_ATAPI && bd->base1)244 OutU8(bd->base1+ATAR1_CTRL,0x8);245 OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);246 ATACmd(bd,ATA_READ_NATIVE_MAX);247 if (ATAWaitNotBUSY(bd,timeout)) {248 res.u8[0]=InU8(bd->base0+ATAR0_SECT);249 res.u8[1]=InU8(bd->base0+ATAR0_LCYL);250 res.u8[2]=InU8(bd->base0+ATAR0_HCYL);251 res.u8[3]=InU8(bd->base0+ATAR0_SEL) & 0xF;252 }253 }254 }255 return bd->max_blk=res;256}257 258I64 ATAPIReadCapacity(CBlkDev *bd,I64 *_blk_size=NULL)259{//Supposedly this can return a res +/- 75 sects.260//Error might just be for music.261 Bool unlock=BlkDevLock(bd);262 U32 buf[2];263 if (ATAWaitNotBUSY(bd,0)) {264 if (bd->flags & BDF_EXT_SIZE)265 OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);266 else267 OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);268 OutU8(bd->base0+ATAR0_LCYL,8);269 OutU8(bd->base0+ATAR0_HCYL,0);270 ATACmd(bd,ATA_PACKET);271 ATAPIWritePktWord(bd,0,0x2500,0,0,0,0,0);272 if (!ATAGetRes(bd,0,buf,8,0,TRUE))273 buf[0]=buf[1]=0;274 } else275 buf[0]=buf[1]=0;276 277 if (unlock) BlkDevUnlock(bd);278 if (_blk_size) *_blk_size=EndianU32(buf[1]);279 return EndianU32(buf[0]);280}281 282CATAPITrack *ATAPIReadTrackInfo(CBlkDev *bd,I64 blk)283{284 CATAPITrack *res=CAlloc(sizeof(CATAPITrack));285 Bool unlock=BlkDevLock(bd);286 if (ATAWaitNotBUSY(bd,0)) {287 if (bd->flags & BDF_EXT_SIZE)288 OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);289 else290 OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);291 OutU8(bd->base0+ATAR0_LCYL,sizeof(CATAPITrack)&0xFF);292 OutU8(bd->base0+ATAR0_HCYL,sizeof(CATAPITrack)>>8);293 ATACmd(bd,ATA_PACKET);294 ATAPIWritePktWord(bd,0,0x5200,blk.u16[1],blk.u16[0],295 (sizeof(CATAPITrack)&0xFF00)>>8,(sizeof(CATAPITrack)&0x00FF)<<8,0);296 if (!ATAGetRes(bd,0,res,sizeof(CATAPITrack),0,TRUE)) {297 Free(res);298 res=NULL;299 }300 } else {301 Free(res);302 res=NULL;303 }304 if (unlock) BlkDevUnlock(bd);305 return res;306}307 308Bool ATAInit(CBlkDev *bd)309{310 Bool unlock=BlkDevLock(bd),okay=FALSE;311 312 if (bd->type==BDT_ATAPI)313 bd->flags&=~BDF_EXT_SIZE;314 else315 bd->flags|=BDF_EXT_SIZE;316 317 if (ATAReadNativeMax(bd,tS+0.1)) {318 ATABlkSel(bd,bd->max_blk,0);319 if (bd->flags&BDF_EXT_SIZE)320 ATACmd(bd,ATA_SET_MAX_EXT);321 else322 ATACmd(bd,ATA_SET_MAX);323 if (ATAWaitNotBUSY(bd,0)) {324 okay=TRUE;325 if (bd->type==BDT_ATAPI) {326 if (ATAPIStartStop(bd,0,TRUE)) {327 if(!ATAPISetMaxSpeed(bd))328 okay=FALSE;329 } else330 okay=FALSE;331 }332 }333 }334 if (unlock) BlkDevUnlock(bd);335 return okay;336}337 338Bool ATAPIWaitReady(CBlkDev *bd,F64 timeout)339{340 do {341 if (!ATAWaitNotBUSY(bd,timeout) ||342 !ATANop(bd,timeout) ||343 !ATAPIStartStop(bd,timeout,TRUE))344 return FALSE;345 if (InU8(bd->base0+ATAR0_STAT) & ATAS_DRDY &&346 !InU8(bd->base0+ATAR0_FEAT));347 return TRUE;348 ATAInit(bd);349 Yield;350 } while (!(0<timeout<tS));351 return FALSE;352}353 354U0 ATAReadBlks(CBlkDev *bd,U8 *buf, I64 blk, I64 cnt)355{356 I64 retries=3;357 Bool unlock=BlkDevLock(bd);358 359 retry:360 ATABlkSel(bd,blk,cnt);361 if (bd->flags & BDF_EXT_SIZE)362 ATACmd(bd,ATA_READ_MULTI_EXT);363 else364 ATACmd(bd,ATA_READ_MULTI);365 if (!ATAGetRes(bd,tS+1.0,buf,cnt*bd->blk_size,BLK_SIZE,FALSE)) {366 if (retries--) {367 ATAWaitNotBUSY(bd,0);368 goto retry;369 } else370 throw('BlkDev');371 }372 373 blkdev.read_cnt+=(cnt*bd->blk_size)>>BLK_SIZE_BITS;374 if (unlock) BlkDevUnlock(bd);375}376 377I64 ATAProbe(I64 base0,I64 base1,I64 unit)378{379 CBlkDev bd;380 MemSet(&bd,0,sizeof(CBlkDev));381 bd.type=BDT_ATAPI;382 bd.base0=base0;383 bd.base1=base1;384 bd.unit=unit;385 bd.blk_size=DVD_BLK_SIZE;386 return ATAGetDevId(&bd,tS+0.1,FALSE);387}388 389Bool ATAPIReadBlks2(CBlkDev *bd,F64 timeout,U8 *buf,390 I64 native_blk, I64 cnt,Bool lock)391{392 Bool res=FALSE,unlock;393 if (cnt<=0)394 return FALSE;395 if (lock)396 unlock=BlkDevLock(bd);397 if (ATAPIWaitReady(bd,timeout)) {398 if (bd->flags & BDF_EXT_SIZE)399 OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);400 else401 OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);402 OutU8(bd->base0+ATAR0_LCYL,bd->blk_size);403 OutU8(bd->base0+ATAR0_HCYL,bd->blk_size.u8[1]);404 ATACmd(bd,ATA_PACKET);405 if (ATAPIWritePktWord(bd,timeout,0xA800,406 native_blk.u16[1],native_blk,cnt.u16[1],cnt,0) &&407 ATAGetRes(bd,timeout,buf,cnt*bd->blk_size,0,FALSE)) {408 blkdev.read_cnt+=(cnt*bd->blk_size)>>BLK_SIZE_BITS;409 res=TRUE;410 }411 }412// ATAPIStartStop(bd,0,FALSE);413 if (lock && unlock) BlkDevUnlock(bd);414 return res;415}416 417U0 ATAPIReadBlks(CBlkDev *bd,U8 *buf, I64 blk, I64 cnt)418{419 CDrv *dv=Let2Drv(bd->first_drv_let);420 I64 retry,spc=bd->blk_size>>BLK_SIZE_BITS,n,blk2,421 l2=bd->max_reads<<1+spc<<1;422 U8 *dvd_buf=MAlloc(l2<<BLK_SIZE_BITS);423 if (cnt>0) {424 if (blk<=bd->max_reads)425 blk2=0;426 else427 blk2=FloorU64(blk-bd->max_reads,spc);428 if (blk2+l2>dv->size+dv->drv_offset)429 l2=dv->size+dv->drv_offset-blk2;430 n=(l2+spc-1)/spc;431 432 retry=4;433 while (--retry)434 if (ATAPIReadBlks2(bd,tS+7.0+0.004*n,dvd_buf,blk2/spc,n,TRUE))435//n is 0x800 if max_reads. Up to 8 additional seconds436 break;437 if (!retry)438 ATAPIReadBlks2(bd,0,dvd_buf,blk2/spc,n,TRUE);439 if (bd->flags & BDF_READ_CACHE)440 DskCacheAdd(dv,dvd_buf,blk2,n*spc);441 MemCpy(buf,dvd_buf+(blk-blk2)<<BLK_SIZE_BITS,cnt<<BLK_SIZE_BITS);442 }443 Free(dvd_buf);444}445 446Bool ATARBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt)447{448 I64 n;449 CBlkDev *bd=dv->bd;450 while (cnt>0) {451 n=cnt;452 if (n>bd->max_reads)453 n=bd->max_reads;454 if (bd->type==BDT_ATAPI)455 ATAPIReadBlks(bd,buf,blk,n);456 else457 ATAReadBlks(bd,buf,blk,n);458 buf+=n<<BLK_SIZE_BITS;459 blk+=n;460 cnt-=n;461 }462 return TRUE;463}464 465U0 ATAWriteBlks(CBlkDev *bd,U8 *buf, I64 blk, I64 cnt)466{//For low level disk access.467//Use BlkWrite() instead.468 I64 i,U32s_avail,sects_avail,retries=3;469 F64 timeout;470 Bool unlock=BlkDevLock(bd);471retry:472 ATABlkSel(bd,blk,cnt);473 if (bd->flags&BDF_EXT_SIZE)474 ATACmd(bd,ATA_WRITE_MULTI_EXT);475 else476 ATACmd(bd,ATA_WRITE_MULTI);477 bd->flags|=BDF_LAST_WAS_WRITE;478 while (cnt>0) {479 timeout=tS+1.0;480 while (TRUE) {481 i=InU8(bd->base0+ATAR0_STAT);482 if (!(i & ATAS_DRDY)||!(i & ATAS_DRQ)) {483 Yield;484 } else485 break;486 if (/* i&ATAS_ERR||*/ tS>timeout) {487 if (retries--) {488 ATAWaitNotBUSY(bd,0);489 goto retry;490 } else491 throw('BlkDev');492 }493 }494 sects_avail=1;495 U32s_avail=sects_avail<<BLK_SIZE_BITS>>2;496 RepOutU32(buf,U32s_avail,bd->base0+ATAR0_DATA);497 buf+=U32s_avail<<2;498 cnt-=sects_avail;499 retries=3;500 }501 ATAWaitNotBUSY(bd,0);502 if (unlock) BlkDevUnlock(bd);503}504 505Bool ATAPISync(CBlkDev *bd)506{507 Bool okay=TRUE;508 if (!ATAWaitNotBUSY(bd,0))509 okay=FALSE;510 else {511 if (bd->flags & BDF_EXT_SIZE)512 OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);513 else514 OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);515 OutU8(bd->base0+ATAR0_LCYL,0);516 OutU8(bd->base0+ATAR0_HCYL,0);517 ATACmd(bd,ATA_PACKET);518 ATAPIWritePktWord(bd,0,0x3500,0,0,0,0,0);519 if (!ATAWaitNotBUSY(bd,0))520 okay=FALSE;521 }522 return okay;523}524 525U0 ATAPIClose(CBlkDev *bd,I64 close_field=0x200,I64 track=0)526{//0x200 CD/DVD part 1527// 0x300 DVD part 2528 if (bd->flags & BDF_EXT_SIZE)529 OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);530 else531 OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);532 OutU8(bd->base0+ATAR0_LCYL,0);533 OutU8(bd->base0+ATAR0_HCYL,0);534 ATACmd(bd,ATA_PACKET);535 ATAPIWritePktWord(bd,0,0x5B00,close_field,track,0,0,0);536 ATAWaitNotBUSY(bd,0);537}538 539U0 ATAPIWriteBlks(CBlkDev *bd,U8 *buf, I64 native_blk, I64 cnt)540{541 I64 U32s_avail;542 U8 *buf2;543 ATAWaitNotBUSY(bd,0);544 ATAPISeek(bd,native_blk);545 546 OutU8(bd->base0+ATAR0_FEAT,0);547 OutU8(bd->base0+ATAR0_LCYL,bd->blk_size);548 OutU8(bd->base0+ATAR0_HCYL,bd->blk_size.u8[1]);549 if (bd->flags & BDF_EXT_SIZE)550 OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);551 else552 OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);553 OutU8(bd->base0+ATAR0_CMD,ATA_PACKET);554 ATAPIWritePktWord(bd,0,0x0400,native_blk.u16[1],native_blk,cnt.u16[1],cnt,0);555 bd->flags|=BDF_LAST_WAS_WRITE;556 ATAWaitNotBUSY(bd,0);557 558 ATAPISeek(bd,native_blk);559 560 if (bd->flags & BDF_EXT_SIZE)561 OutU8(bd->base0+ATAR0_SEL,0xEF|bd->unit<<4);562 else563 OutU8(bd->base0+ATAR0_SEL,0xE0|bd->unit<<4);564 OutU8(bd->base0+ATAR0_LCYL,bd->blk_size);565 OutU8(bd->base0+ATAR0_HCYL,bd->blk_size.u8[1]);566 ATACmd(bd,ATA_PACKET);567 ATAPIWritePktWord(bd,0,0xAA00,native_blk.u16[1],native_blk,cnt.u16[1],cnt,0);568 buf2=buf+bd->blk_size*cnt;569 while (buf<buf2) {570 ATAWaitDRQ(bd,0);571 U32s_avail=(InU8(bd->base0+ATAR0_HCYL)<<8+InU8(bd->base0+ATAR0_LCYL))>>2;572 if (buf+U32s_avail<<2>buf2)573 U32s_avail=(buf2-buf)>>2;574 if (U32s_avail) {575 RepOutU32(buf,U32s_avail,bd->base0+ATAR0_DATA);576 buf+=U32s_avail<<2;577 blkdev.write_cnt+=U32s_avail>>(BLK_SIZE_BITS-2);578 }579 }580 ATAWaitNotBUSY(bd,0);581}582 583Bool ATAWBlks(CDrv *dv,U8 *buf, I64 blk, I64 cnt)584{585 I64 n,spc;586 CBlkDev *bd=dv->bd;587 Bool unlock;588 spc=bd->blk_size>>BLK_SIZE_BITS;589 if (bd->type==BDT_ATAPI) {590 unlock=BlkDevLock(bd);591 ATAPIWaitReady(bd,0);592 }593 while (cnt>0) {594 n=cnt;595 if (n>bd->max_writes)596 n=bd->max_writes;597 if (bd->type==BDT_ATAPI)598 ATAPIWriteBlks(bd,buf,blk/spc,(n+spc-1)/spc);599 else600 ATAWriteBlks(bd,buf,blk,n);601 buf+=n<<BLK_SIZE_BITS;602 blk+=n;603 cnt-=n;604 blkdev.write_cnt+=n;605 }606 if (bd->type==BDT_ATAPI) {607 ATAPISync(bd);608// ATAPIStartStop(bd,0,FALSE);609 if (unlock) BlkDevUnlock(bd);610 }611 return TRUE;612}613 