Du bist hier: Snippet-Verzeichnis » DOS (8)
Sprache:

ATAPI for DOS

Sprache: English
Programmiersprache: Pascal
Veröffentlicht von: cinek [nicht registriert]
Letzte Änderung: 15.05.2006
Aufrufe: 1123


Beschreibung

This is a Pascal Unit for DOS.Look at the way how ATAPI commandsare structured.

Code

1 unit ATAPI; 2 3 interface uses Ide,Dos; 4 5 const DRV_MASTER =FALSE; 6 DRV_SLAVE =TRUE; 7 RESET_DRIVE =TRUE; 8 NORESET_DRIVE =FALSE; 9 10 {GetStatus} 11 AST_BSY =$80; 12 AST_DRDY =$40; 13 AST_DMAREADY =$20; 14 AST_DF =$20; {overlapped} 15 AST_SERVICE =$10; 16 AST_DSC =$10; {overlapped} 17 AST_DRQ =$08; 18 AST_CORR =$04; 19 AST_CHECK =$01; 20 21 {GetError} 22 AER_SENSEKEY =$F0; 23 AER_MCR =$08; 24 AER_ABRT =$04; 25 AER_EOM =$02; 26 AER_ILI =$01; 27 28 {SetFeatures} 29 AFT_OVERLAP =$02; 30 AFT_DMA =$01; 31 32 {GetInterruptReason} 33 AIR_RELEASE =$04; 34 AIR_IO =$02; 35 AIR_COD =$01; 36 37 {SetDeviceControl} 38 ADC_SRST =$04; {Muss maskiert werden: } 39 ADC_NIEN =$02; {Bit0 immer 0 } 40 {Bit3 immer 1 } 41 42 43 {ATAPI COMMANDS} 44 45 AC_INQUIRY =$12; 46 AC_READTOC =$43; 47 AC_PLAYAUDIO =$45; 48 AC_STARTSTOPUNIT =$1B; 49 AC_READCD =$BE; 50 AC_READSUBCHANNEL =$42; 51 AC_SETCDSPEED =$BB; 52 AC_MODESENSE =$5A; 53 AC_MODESELECT =$55; 54 AC_REQUESTSENSE =$03; 55 AC_WRITE10 =$2A; 56 AC_SYNCCACHE =$35; 57 AC_TESTUNITREADY =$00; 58 AC_BLANK =$A1; 59 AC_CLOSETRACKSESSION =$5B; 60 AC_READDISCINFO =$51; 61 AC_READTRACKINFO =$52; 62 AC_RESERVETRACK =$53; 63 64 65 66 67 {Some constants} 68 MAX_TOCDATALEN =804; 69 MAX_DATABLOCK =$8000; 70 MAX_CDDATABLOCK =2048; 71 MAX_CDDADATABLOCK =2352; 72 MAX_RAWDATABLOCK =2368; 73 MAX_SENSEBUFFER =$FFF8; 74 PACKETCOMMANDSIZE =12; 75 76 77 {sector types for READCD} 78 SECTYPE_ANYTYPE =0; 79 SECTYPE_CDDA =1; 80 SECTYPE_MODE1 =2; 81 SECTYPE_MODE2 =3; 82 SECTYPE_MODE1FORM2=4; 83 SECTYPE_MODE2FORM2=5; 84 85 {flags for READCD} 86 RCDF_SYNCH =$80; 87 RCDF_NOHDR =$00; 88 RCDF_HDRONLY =$20; 89 RCDF_SUBHDRONLY =$40; 90 RCDF_HDR =$60; 91 RCDF_USERDATA =$10; 92 RCDF_EDCECC =$08; 93 RCDF_NOERRINF =$00; 94 RCDF_ERRC2INF =$02; 95 RCDF_ERRC2ANDBLOCKINF=$04; 96 97 {SetCDSpeed} 98 SCDS_MAXSPEED =$FFFF; 99 SCDS_NONE =0; 100 101 {subchannel data selection field for READCD} 102 RCDSC_NOSUBCHDATA =$0; {all other values are reserved !} 103 RCDSC_RAW =$1; 104 RCDSC_Q =$2; 105 RCDSC_RW =$4; 106 107 {ModeParametersHeader -> Medium types} 108 MT_UNKNOWN =$00; 109 MT_CDROMDATA120 =$01; 110 MT_CDAUDIO120 =$02; 111 MT_CDROMMIXED120 =$03; 112 MT_CDROMHYBRID120 =$04; 113 MT_CDROMDATA80 =$05; 114 MT_CDAUDIO80 =$06; 115 MT_CDROMMIXED80 =$07; 116 MT_CDROMHYBRID80 =$08; 117 MT_CDRUNKNOWN =$10; 118 MT_CDRDATA120 =$11; 119 MT_CDRAUDIO120 =$12; 120 MT_CDRMIXED120 =$13; 121 MT_CDRHYBRID120 =$14; 122 MT_CDRDATA80 =$15; 123 MT_CDRAUDIO80 =$16; 124 MT_CDRMIXED80 =$17; 125 MT_CDRHYBRID80 =$18; 126 MT_CDRWUNKNOWN =$20; 127 MT_CDRWDATA120 =$21; 128 MT_CDRWAUDIO120 =$22; 129 MT_CDRWMIXED120 =$23; 130 MT_CDRWHYBRID120 =$24; 131 MT_CDRWDATA80 =$25; 132 MT_CDRWAUDIO80 =$26; 133 MT_CDRWMIXED80 =$27; 134 MT_CDRWHYBRID80 =$28; 135 MT_NODISC =$70; 136 MT_DOOROPEN =$71; 137 138 {CloseTrackSession CloseTypes} 139 140 CTST_TRACK =$01; 141 CTST_SESSION =$02; 142 143 {ReadTrackInformation} 144 RTI_TRACK =TRUE; 145 RTI_LBA =FALSE; 146 147 {ReadSubChannel Data-Format} 148 RSC_CURPOS =$01; 149 RSC_MCN =$02; 150 RSC_ISRC =$03; 151 152 {ReadSubChannel Flags} 153 RSCF_MSF =$01; 154 RSCF_SUBQ =$02; 155 156 {Blank} 157 BLANK_DISC =0; 158 BLANK_MINIMAL =1; 159 BLANK_TRACK =2; 160 161 162 type PPacketCommand=^TPacketCommand; 163 TPacketCommand=array[0..11] of byte; 164 165 type PPacketCommandData=^TPacketCommandData; 166 TPacketCommandData=array[0..5] of word; 167 168 type PTOCHeader=^TTOCHeader; 169 TTOCHeader=record 170 TocDataLength:word; 171 FirstTrackNr,LastTrackNr:byte; 172 end; 173 type PTOC=^TTOC; 174 TTOC=record 175 TocDataLength:word; 176 FirstTrack,LastTrack:byte; 177 Entry:array[0..255] of record 178 Reserved1:byte; 179 ADRControl:byte; 180 TrackNr:byte; 181 Reserved2:byte; 182 LBA:longint; 183 end; 184 end; 185 186 type TModeParametersHeader=record 187 ModeDataLength:word; 188 MediumType:byte; 189 Reserved:array[1..5] of byte; 190 end; 191 192 type TPC_ReadTOC=record 193 OpCode :byte; {=$43} 194 MSF :byte; {bit 1} 195 FormatMMC :byte; {bits 0-2} 196 Reserved1 :array[1..3] of byte; 197 StartTrackOrSession :byte; 198 AllocLength :word; {swapped !} 199 Format :byte; {bits 6-7} 200 Reserved2 :array[1..2] of byte; 201 end; 202 type TPC_Inquiry=record 203 OpCode :byte; {=$12} 204 Reserved1 :array[1..3] of byte; 205 AllocLength :byte; 206 Reserved2 :array[1..7] of byte; 207 end; 208 type TPC_ModeSense=record 209 OpCode :byte; {=$5A} 210 Reserved1 :byte; 211 PageControlCode :byte; {bits 6-7 -> Ctrl} 212 {bits 0-5 -> Code} 213 Reserved2 :array[1..4] of byte; 214 AllocLength :word; 215 Reserved3 :array[1..3] of byte; 216 end; 217 type TPC_ModeSelect=record 218 OpCode :byte; {=$55} 219 PFSP :byte; {=$10} 220 Reserved1 :array[1..5] of byte; 221 AllocLength :word; 222 Reserved3 :array[1..3] of byte; 223 end; 224 type TPC_PlayAudio=record 225 OpCode :byte; {=$45} 226 Reserved1 :byte; 227 StartLBA :longint; 228 Reserved2 :byte; 229 TransferLength :word; 230 Reserved3 :array[1..3] of byte; 231 end; 232 type TPC_StartStopUnit=record 233 OpCode :byte; {=$1B} 234 Immed :byte; {bit 0} 235 Reserved1 :array[1..2] of byte; 236 LoadUnloadAndStart :byte; {bits 0-1} 237 Reserved2 :array[1..7] of byte; 238 end; 239 type TPC_ReadCD=record 240 OpCode:byte; {=$BE} 241 ExpectedSectorType:byte; {bits 2-4} 242 StartLBA:longint; 243 TransferLength:array[0..2] of byte; 244 FlagBits:byte; 245 SubChannelDataSel:byte; {bits 0-2} 246 Reserved1:byte; 247 248 end; 249 type TPC_ReadSubChannel=record 250 Opcode :byte; {=$42} 251 MSF :byte; {bit 1} 252 SubQ :byte; {bit 6} 253 SubChannelDataFormat :byte; { $01 -> current pos} 254 { $02 -> MCN/UPC} 255 { $03 -> ISRC} 256 Reserved1 :array[1..2] of byte; 257 TrackNr :byte; {only for ISRC !} 258 AllocLength :word; {swapped !} 259 Reserved2 :array[1..3] of byte; 260 end; 261 type TPC_Write10=record 262 OpCode:byte; {=$2A} 263 DPOFUARELADR:byte; {bit 4 -> DPO} 264 {bit 3 -> FUA} 265 {bit 0 -> RELADR} 266 LBA:longint; 267 Reserved1:byte; 268 TransferLength:word; 269 Reserved2:array[1..3] of byte; 270 end; 271 type TPC_SyncCache=record 272 OpCode:byte; {=$35} 273 Immed:byte; {bit 1} 274 Reserved:array[1..10] of byte; 275 end; 276 type TPC_SetCDSpeed=record 277 OpCode :byte; {=$BB} 278 Reserved1 :byte; 279 ReadDriveSpeed :word; 280 WriteDriveSpeed :word; 281 Reserved2 :array[1..6] of byte; 282 end; 283 type TPC_RequestSense=record 284 OpCode :byte; {=$03} 285 Reserved1 :array[1..3] of byte; 286 AllocLength :byte; 287 Reserved2 :array[1..7] of byte; 288 end; 289 type TPC_TestUnitReady=record 290 OpCode :byte; {=$00} 291 Reserved :array[1..11] of byte; 292 end; 293 type TPC_Blank=record 294 OpCode :byte; {=$A1} 295 ImmedBlankType :byte; {bit 4 Immed} 296 {bits 0-2 Type} 297 StartLBA :longint; 298 Reserved :array[1..6] of byte; 299 end; 300 type TPC_CloseTrackSession=record 301 OpCode :byte; {=$5B} 302 Immed :byte; {bit 0 Immed} 303 SessionTrack :byte; {bit 0 Track} 304 {bit 1 Session} 305 Reserved1 :array[1..2] of byte; 306 TrackNr :byte; 307 Reserved2 :array[1..6] of byte; 308 end; 309 type TPC_ReadDiscInformation=record 310 OpCode :byte; {=$51} 311 Reserved1 :array[1..6] of byte; 312 AllocLength :word; 313 Reserved2 :array[1..3] of byte; 314 end; 315 type TPC_ReadTrackInformation=record 316 OpCode :byte; {=$52} 317 Track :byte; {bit 0 trackflag} 318 LBAOrTrackNr :longint; 319 Reserved1 :byte; 320 AllocLength :word; 321 Reserved2 :array[1..3] of byte; 322 end; 323 type TPC_ReserveTrack=record 324 OpCode :byte; {=$53} 325 Reserved1 :array[1..4] of byte; 326 ReservationSize :longint; 327 Reserved2 :array[1..3] of byte; 328 end; 329 330 type PResponseBuffer=^TResponseBuffer; 331 TResponseBuffer=array[0..32760] of word; 332 333 type PSenseBuffer=^TSenseBuffer; 334 TSenseBuffer=record 335 ErrorCode:byte; {bit 7 -> valid} 336 {bits 0-6 -> error code} 337 SegmentNumber:byte; {reserved} 338 ILISenseKey:byte; {bit 5 -> ILI} 339 {bits 0-3 -> sense key} 340 Information:byte; 341 Reserved1:array[1..3] of byte; 342 AdditionalSenseLength:byte; 343 CommandSpecificInformation:byte; 344 Reserved2:array[1..3] of byte; 345 ASC:byte; 346 ASCQ:byte; 347 SenseKeySpecific:byte; {bit 7 -> valid} 348 {bits 0-6 -> SKS} 349 Reserved3:array[1..2] of byte; 350 AdditionalSenseBytes:array[0..255-17] of byte; 351 end; 352 353 type PDiscInformation=^TDiscInformation; 354 TDiscInformation=record 355 DataLength:word; 356 DiscFlags:byte; {bit 4 -> erasable} 357 {bits 2-3 -> status of last 358 session} 359 {bits 0-1 -> disc status} 360 FirstTrackNr:byte; 361 SessionCount:byte; 362 FirstTrackInLastSession:byte; 363 LastTrackInLastSession:byte; 364 IDFlags:byte; {bit 7 -> disc id valid} 365 {bit 6 -> disc bar code 366 valid} 367 {bit 5 -> unrestricted use} 368 DiscType:byte; 369 Reserved1:array[1..3] of byte; 370 DiscID:longint; 371 LeadInStartInLastSession:longint; 372 LastPossibleLeadOut:longint; 373 DiscBarCode:array[0..5] of byte; 374 Reserved:byte; 375 OPCEntryCount:byte; 376 OPCEntry:array[0..$FF] of record 377 Speed:word; 378 OPCVal:array[0..5] of byte; 379 end; 380 end; 381 382 type PTrackInformation=^TTrackInformation; 383 TTrackInformation=record 384 DataLength:word; 385 TrackNr:byte; 386 SessionNr:byte; 387 Reserved1:byte; 388 TrackFlags:byte; {bit 5 -> damaged} 389 {bit 4 -> copy} 390 {bits 0-3 -> track mode} 391 TrackType:byte; {bit 7 -> reserved track} 392 {bit 6 -> blank} 393 {bit 5 -> packet} 394 {bit 4 -> fixed packet} 395 {bits 0-3 -> data mode} 396 NWAValid:byte; {bit 0 -> NWA valid} 397 StartLBA:longint; 398 NextWritableAddr:longint; 399 FreeBlocks:longint; 400 FixedPacketSize:longint; 401 TrackSize:longint; 402 end; 403 404 type PWritePageParameters=^TWritePageParameters; 405 TWritePageParameters=record 406 Header:TModeParametersHeader; 407 PSPageCode:byte; {PS bit 7} 408 {PageCode bits 0-6} 409 PageLength:byte; {=$32} 410 TestFlagWriteType:byte; {TestFlag bit 4} 411 {Write type bits 0-3} 412 MSFPCopyTrackMode:byte; {MS (Multisession) bits 6-7} 413 {FP bit 5} 414 {Copy bit 4} 415 {Track mode bits 0-3} 416 DataBlockType:byte; {bits 0-3} 417 Reserved1:array[1..2] of byte; 418 HostApplicationCode:byte; {bits 0-5} 419 SessionFormat:byte; 420 Reserved2:byte; 421 PacketSize:longint; 422 AudioPauseLength:word; 423 MCVAL:byte; {bit 7} 424 MediaCatalogNumber:array[1..13] of byte; 425 ZeroMC:byte; 426 AFRAMEMC:byte; {=$00} 427 TCVAL:byte; {bit 7} 428 CountryCode:byte; 429 InternationalStandardRecordingCode:byte; 430 OwnerCode:array[1..3] of byte; 431 YearOfRecording:word; 432 SerialNumber:array[1..5] of byte; 433 ZeroTC:byte; 434 AFRAMETC:byte; 435 Reserved3:byte; 436 SubHeader:array[0..3] of byte; 437 438 end; 439 440 441 type PATAPIDevice=^TATAPIDevice; 442 TATAPIDevice=object 443 444 ATAPIPort:word; 445 Drv,Int,IntMsg:byte; 446 ResponseBuffer:PResponseBuffer; 447 SenseBuffer:PSenseBuffer; 448 ResponseSize,SenseSize:word; 449 OldIntHandler:pointer; 450 IntDetected:boolean; 451 452 constructor Init(Drive:boolean;IDEPort:byte;ResetDrv:boolean); 453 destructor Done;virtual; 454 455 procedure SoftReset; 456 function Identify:boolean; 457 function PacketCommand(PC:PPacketCommand;BufferSize:word):boolean; 458 function PIODataIn:boolean; 459 function PIODataOut(var Data;Size:word):boolean; 460 function InATAPIBytes:boolean; 461 function OutATAPIBytes(var Data;Size:word):boolean; 462 463 464 function GetStatus:byte; 465 function GetStatusEx:byte; 466 function GetError:byte; 467 function GetInterruptReason:byte; 468 function GetSelectedDrive:boolean; 469 function GetByteCount:word; 470 471 procedure SetFeatures(Features:byte); 472 procedure SetByteCount(ByteCount:word); 473 procedure SetDeviceControl(DeviceControl:byte); 474 475 procedure SelectDrive; 476 477 procedure AllocResponseBuffer(Size:word); 478 procedure FreeResponseBuffer; 479 procedure RegisterIntHandler(InterruptNr:byte); 480 procedure UnregisterIntHandler; 481 482 {ATAPI Commands} 483 484 procedure Inquiry (var Data;var Size:word); 485 function TestUnitReady:boolean; 486 function WaitUnitReady(Wait:longint):boolean; 487 procedure RequestSense; 488 procedure ModeSense(PageCtrl,PageCode:byte;var Data;var Size:word); 489 function ModeSelect(var Data;Size:word):boolean; 490 procedure ReadTOC(var TOC:PTOC;var Size:word);{will be alloc'd} 491 procedure PlayAudio(Start:longint;Len:word); 492 procedure StartStopUnit(Load,Start,Immediat:boolean); 493 procedure SetCDSpeed(ReadSpeed:word;WriteSpeed:word); 494 procedure ReadSubChannel(var Buffer;Track,DataFormat, 495 Flags:byte;Size:word); 496 497 function ReadCDInit(SectorType:byte;Start,Len:longint;Flags:byte;SubCh:byte;TransferSize:word):boolean; 498 function WriteCDInit(Start:longint;Len,TransferSize:word):boolean; 499 procedure CloseTrackSession(CloseType:byte;Track:byte;Immedb:boolean); 500 function SyncCache(ImmedBit:boolean):boolean; 501 procedure ReadDiscInformation(var Buffer;Size:word); 502 procedure ReadTrackInformation(var Buffer;TrackInfo:boolean;TrackOrLBA:longint;Size:word); 503 procedure ReserveTrack(Size:longint); 504 505 procedure Blank(BlankType:byte;LBA:longint;Immed:boolean); 506 end; 507 508 type PByteArray=^TByteArray; 509 TByteArray=array[0..65530] of byte; 510 PWordArray=^TWordArray; 511 TWordArray=array[0..32700] of word; 512 513 type TWaveHeader=record 514 Riff:array[1..4] of char; 515 Length:longint; 516 Wavefmt:array[1..8] of char; 517 Dummy1:longint; 518 Dummy2,Channels:integer; 519 Freq,BperSec:longint; 520 BperSmp,SmpRes:integer; 521 Data:array[1..4] of char; 522 DataSize:longint; 523 end; 524 525 function BigEndianLongint(l:longint):longint; 526 function BigEndianWord(w:word):word; 527 528 implementation 529 530 var RegisteredObj:PATAPIDevice; 531 Timer:longint; 532 533 {---------------------------------------------------------------------------} 534 535 function BigEndianLongint(l:longint):longint; 536 begin 537 BigEndianLongint:= (l shl 24) or 538 ((l shl 8) and $FF0000) or 539 (l shr 24) or 540 ((l shr 8) and $FF00 ); 541 542 end; 543 function BigEndianWord(w:word):word; 544 begin 545 BigEndianWord:=(w shl 8)or(w shr 8); 546 547 end; 548 549 {---------------------------------------------------------------------------} 550 551 552 procedure DummyInt;interrupt; 553 begin 554 with RegisteredObj^ do 555 begin 556 if (GetStatus and AST_DRQ) >0 then IntDetected:=true; 557 if Int>7 then Port[$A0]:=$20; 558 Port[$20]:=$20; 559 end; 560 end; 561 562 procedure TimerInt;interrupt; 563 begin 564 Inc(Timer); 565 end; 566 567 {---------------------------------------------------------------------------} 568 569 constructor TATAPIDevice.Init(Drive:boolean;IDEPort:byte;ResetDrv:boolean); 570 begin 571 ATAPIPort:=IDE_PORT[IDEPort]; 572 if Drive then Drv:=1 else Drv:=0; 573 ResponseBuffer:=nil; 574 OldIntHandler:=nil; 575 GetMem(SenseBuffer,Sizeof(TSenseBuffer)); 576 if ResetDrv then SoftReset; 577 end; 578 destructor TATAPIDevice.Done; 579 begin 580 FreeResponseBuffer; 581 if OldIntHandler<>nil then UnregisterIntHandler; 582 FreeMem(SenseBuffer,Sizeof(TSenseBuffer)); 583 end; 584 585 {---------------------------------------------------------------------------} 586 587 function TATAPIDevice.GetStatus:byte; 588 begin 589 GetStatus:=Port[ATAPIPort+IDEPORT_STATUS]; 590 end; 591 function TATAPIDevice.GetStatusEx:byte; 592 begin 593 GetStatusEx:=Port[ATAPIPort+IDEPORT_STATUSEX]; 594 end; 595 function TATAPIDevice.GetError:byte; 596 begin 597 GetError:=Port[ATAPIPort+IDEPORT_ERROR]; 598 end; 599 function TATAPIDevice.GetInterruptReason:byte; 600 begin 601 GetInterruptReason:=Port[ATAPIPort+IDEPORT_SECTORCOUNT]; 602 end; 603 function TATAPIDevice.GetSelectedDrive:boolean; 604 begin 605 if (Port[ATAPIPort+IDEPORT_DRIVE] and $10)>0 then 606 GetSelectedDrive:=DRV_SLAVE else 607 GetSelectedDrive:=DRV_MASTER; 608 end; 609 function TATAPIDevice.GetByteCount:word; 610 begin 611 GetByteCount:=Port[ATAPIPort+IDEPORT_CYLLO] or 612 (word(Port[ATAPIPort+IDEPORT_CYLHI])shl 8) 613 { GetByteCount:=Portw[ATAPIPort+IDEPORT_CYL];} 614 end; 615 616 procedure TATAPIDevice.SetFeatures(Features:byte); 617 begin 618 Port[ATAPIPort+IDEPORT_FEATURE]:=Features; 619 end; 620 procedure TATAPIDevice.SetByteCount(ByteCount:word); 621 begin 622 Port[ATAPIPort+IDEPORT_CYLLO]:=LO(ByteCount); 623 Port[ATAPIPort+IDEPORT_CYLHI]:=HI(ByteCount); 624 { Portw[ATAPIPort+IDEPORT_CYL]:=ByteCount;} 625 end; 626 procedure TATAPIDevice.SetDeviceControl(DeviceControl:byte); 627 begin 628 Port[ATAPIPort+IDEPORT_CONTROL]:=DeviceControl; 629 end; 630 631 procedure TATAPIDevice.SelectDrive; 632 begin 633 Port[ATAPIPort+IDEPORT_DRIVE]:=(Port[ATAPIPort+IDEPORT_DRIVE] and $EF) 634 or (Drv shl 4); 635 end; 636 637 638 639 {---------------------------------------------------------------------------} 640 641 procedure TATAPIDevice.SoftReset; 642 begin 643 SelectDrive; 644 645 Port[ATAPIPort+IDEPORT_COMMAND]:=CMD_ATAPI_SOFTRESET; 646 647 while (GetStatus and AST_BSY)>0 do; 648 649 WaitUnitReady(100000); 650 end; 651 652 function TATAPIDevice.Identify:boolean; 653 var rs,i,timer:word; 654 begin 655 if (ResponseSize>=512) then 656 begin 657 SelectDrive; 658 while (GetStatus and (AST_BSY or AST_DRDY))= 659 (AST_BSY or AST_DRDY) do; 660 SetFeatures(0); 661 Port[ATAPIPort+IDEPORT_SECTORCOUNT]:=0; 662 Port[ATAPIPort+IDEPORT_SEC]:=0; 663 SetByteCount(ResponseSize); 664 Port[ATAPIPort+IDEPORT_COMMAND]:=$A1; {Identify_Packet_Device} 665 666 timer:=$FFFF; 667 while (timer>0)and((GetStatus and AST_BSY)>0) do Dec(timer); 668 669 if timer=0 then 670