diff options
| author | 2024-04-25 21:24:10 +0100 | |
|---|---|---|
| committer | 2024-04-25 22:32:27 +0000 | |
| commit | 2d04cacc5322951f187bb17e017c12920ac8ebe2 (patch) | |
| tree | 80ee017efa878dfd5344b44249e6a241f2a7f6e2 /v4.0-ozzie/bin/DISK2/BIOS/IBMDSK.ASM | |
| parent | Merge pull request #430 from jpbaltazar/typoptbr (diff) | |
| download | ms-dos-main.tar.gz ms-dos-main.tar.xz ms-dos-main.zip | |
Diffstat (limited to 'v4.0-ozzie/bin/DISK2/BIOS/IBMDSK.ASM')
| -rw-r--r-- | v4.0-ozzie/bin/DISK2/BIOS/IBMDSK.ASM | 2551 |
1 files changed, 2551 insertions, 0 deletions
diff --git a/v4.0-ozzie/bin/DISK2/BIOS/IBMDSK.ASM b/v4.0-ozzie/bin/DISK2/BIOS/IBMDSK.ASM new file mode 100644 index 0000000..47869d0 --- /dev/null +++ b/v4.0-ozzie/bin/DISK2/BIOS/IBMDSK.ASM | |||
| @@ -0,0 +1,2551 @@ | |||
| 1 | TITLE DISK - MS-DOS 4.0 disk drivers for IBM | ||
| 2 | NAME DISK | ||
| 3 | |||
| 4 | PAGE ,132 | ||
| 5 | |||
| 6 | ;DEBUGFLG=1 | ||
| 7 | |||
| 8 | .xlist | ||
| 9 | INCLUDE DEFDBUG.INC | ||
| 10 | .list | ||
| 11 | |||
| 12 | ; Constants | ||
| 13 | |||
| 14 | ErrLim= 5 ; Number of retries on error | ||
| 15 | |||
| 16 | ; Floppy delay constants | ||
| 17 | |||
| 18 | DelayLoad= 35 ; 35 milliseconds to load head | ||
| 19 | |||
| 20 | ; Constants for floppy disk controller | ||
| 21 | |||
| 22 | Rate99= 000H ; Step rate 96tpi disk in 96tpi drive | ||
| 23 | Rate49= 001H ; Step rate 48tpi disk in 96tpi drive | ||
| 24 | Rate44= 002H ; Step rate 48tpi disk in 48tpi drive | ||
| 25 | |||
| 26 | ; Commands to floppy disk controller | ||
| 27 | |||
| 28 | FD_CRESET= 007H ; Recalibrate drive | ||
| 29 | FD_CSENSE= 008H ; Sense interrupt status | ||
| 30 | FD_CSEEK= 00FH ; Seek to another track | ||
| 31 | FD_CREAD= 046H ; MFM read, skip deleted data | ||
| 32 | FD_CWRITE= 045H ; MFM write, skip deleted data | ||
| 33 | FD_CSPEC= 003H ; Special - step rate, head load/unload | ||
| 34 | |||
| 35 | ; Status codes | ||
| 36 | |||
| 37 | FD_SDIO= 01000000B ; Transfer direction (0 -> controller) | ||
| 38 | FD_SRQM= 10000000B ; Controller ready for next data | ||
| 39 | |||
| 40 | ; Hard disk controller commands | ||
| 41 | HD_CSENS= 03H ; request sense block | ||
| 42 | HD_CREAD= 08H ; read | ||
| 43 | HD_CWRITE= 0AH ; write | ||
| 44 | |||
| 45 | HDcontrolbyte= 05H ; step rate = 70 us. | ||
| 46 | |||
| 47 | ; I/O ports | ||
| 48 | |||
| 49 | FD_PSEL= 03F2H ; Controls drive select and motors | ||
| 50 | FD_PDAT= 03F5H ; Data transfer to/from controller | ||
| 51 | FD_PSTAT= 03F4H ; Controller status | ||
| 52 | FD_PCMD= 03F7H ; Controller command register | ||
| 53 | |||
| 54 | HD_PDAT= 0320H ; read/write data | ||
| 55 | HD_PSTAT= 0321H ; controller status | ||
| 56 | HD_PSEL= 0322H ; controller select | ||
| 57 | HD_PMSK= 0323H ; DMA and interrupt mask bits | ||
| 58 | |||
| 59 | PDMA= 0 ; Base of ports for DMA control | ||
| 60 | PDMAX= 7FH ; Address extension regs for DMA | ||
| 61 | ;NOTE base address suitable for ch. 2 & 3 only | ||
| 62 | FD_DMA= 2 ; floppy disk DMA channel | ||
| 63 | HD_DMA= 3 ; hard disk DMA channel | ||
| 64 | |||
| 65 | DMA_READ= 44H ; DMA read command | ||
| 66 | DMA_WRITE= 48H ; DMA write command | ||
| 67 | |||
| 68 | ; Misc | ||
| 69 | |||
| 70 | DORmask= 00CH ; Not reset, enable DMA & interrupt | ||
| 71 | |||
| 72 | |||
| 73 | |||
| 74 | SUBTTL Data for performing requests | ||
| 75 | PAGE + | ||
| 76 | |||
| 77 | ;* Dos Request Packet structure | ||
| 78 | |||
| 79 | DosPacket STRUC | ||
| 80 | RqCmdLen DB 0 ; Length of this command | ||
| 81 | RqUnit DB 0 ; Unit in this driver | ||
| 82 | RqCmd DB 0 ; Command to do | ||
| 83 | RqStatus DW 0 ; Status of request | ||
| 84 | DD 0 | ||
| 85 | DD 0 ; Not used | ||
| 86 | RqMedia DB 0 ; Media descriptor | ||
| 87 | RqAddr DW 0 ; Offset of data | ||
| 88 | DW 0 ; Segment of data | ||
| 89 | RqCount DW 0 ; Number of sectors | ||
| 90 | RqFirst DW 0 ; First sector to do | ||
| 91 | DosPacket ENDS | ||
| 92 | |||
| 93 | ; The disk drivers work as a state machine performing the various actions | ||
| 94 | ; that make up disk I/O. | ||
| 95 | |||
| 96 | ; Driver states | ||
| 97 | ; The following states are common to both drivers | ||
| 98 | Start= 0 ; Starting I/O | ||
| 99 | Calc= 1 ; Calculate position on disk | ||
| 100 | Done= 7 ; I/O is done | ||
| 101 | Idle= 8 ; Drive is inactive | ||
| 102 | Error= 9 ; Have an error | ||
| 103 | ; The following states are used by the floppy driver only | ||
| 104 | Select= 2 ; Select drive, start motor, seek | ||
| 105 | Recal= 3 ; Drive was just recalibrated | ||
| 106 | Seek= 4 ; Seek just finished | ||
| 107 | Settle= 5 ; Head has settled | ||
| 108 | RdWri= 6 ; Read/write is done | ||
| 109 | ; The following states are used by the fixed driver only | ||
| 110 | Verify= 6 ; Start verify portion of write | ||
| 111 | |||
| 112 | |||
| 113 | DeviceStruc STRUC | ||
| 114 | State DW Idle ; Current drive state | ||
| 115 | Current DW -1 ; Current active drive | ||
| 116 | ErrCnt DB 0 ; # of errors in doing request | ||
| 117 | Flags DB 0 ; Various bit flags, see below | ||
| 118 | DOR DB 0 ; Copy of select/motor reg | ||
| 119 | ; Following values are set by Setup from the request packet and are | ||
| 120 | ; updated after each transfer is completed. | ||
| 121 | Unit DB 0 ; Unit | ||
| 122 | First DW 0 ; 1st sector of request | ||
| 123 | RealAddr DD 0 ; Real addr of data when Addr is | ||
| 124 | ; scratch buffer. | ||
| 125 | Count DW 0 ; Number of sectors to xfer | ||
| 126 | ; Following values are set by MapSector. | ||
| 127 | Cyl DW 0 ; Cylinder | ||
| 128 | Sector DB 0 ; Sector - zero based | ||
| 129 | Head DB 0 ; Head | ||
| 130 | NumSectors DW 0 ; Number of sectors to do | ||
| 131 | NumBytes DW 0 ; Number of bytes | ||
| 132 | Addr DD 0 ; Pointer to data buffer | ||
| 133 | ; Device dependent data | ||
| 134 | ST0 DB 0 ; floppy controller ST0 | ||
| 135 | ST1 DB 0 ; floppy controller ST1 | ||
| 136 | ST2 DB 0 ; floppy controller ST2 | ||
| 137 | CHRN DB 0,0,0,0 ; other floppy status returns | ||
| 138 | DeviceStruc ENDS | ||
| 139 | DCB EQU ST0 ; Fixed disk Device Control Block | ||
| 140 | |||
| 141 | ; Bits in Flags | ||
| 142 | |||
| 143 | Factive= 1 ; Actively working on something | ||
| 144 | F2step= 2 ; Must double step when seeking | ||
| 145 | Fwrite= 4 ; This is a write, not a read | ||
| 146 | Fverify= 8 ; This is a verify, not a rd/wr | ||
| 147 | Fwrap1= 010H ; We are currently using ScratchBuffer | ||
| 148 | Fwrap2= 020H ; We have used ScratchBuffer in this req | ||
| 149 | |||
| 150 | BiosSeg GROUP Code,BiosInit | ||
| 151 | |||
| 152 | Code SEGMENT BYTE PUBLIC 'CODE' | ||
| 153 | ASSUME CS:BiosSeg | ||
| 154 | |||
| 155 | IFDEF DEBUGFLG | ||
| 156 | EXTRN BUGBITS:BYTE,DPRINTF:NEAR | ||
| 157 | ENDIF | ||
| 158 | |||
| 159 | SUBTTL Device data | ||
| 160 | PAGE + | ||
| 161 | |||
| 162 | Floppy DeviceStruc <> | ||
| 163 | Fixed DeviceStruc <> | ||
| 164 | |||
| 165 | ;* Per drive information, including BPBs | ||
| 166 | |||
| 167 | DriveStruc STRUC | ||
| 168 | BPBsecsiz DW 512 ; Physical sector size | ||
| 169 | BPBsecpau DB 1 ; Sectors/Allocation unit | ||
| 170 | BPBressec DW 1 ; Reserved sectors for DOS | ||
| 171 | BPBnfat DB 2 ; # of allocation tables | ||
| 172 | BPBndir DW 64 ; # of directory entries | ||
| 173 | BPBnsec DW 9*40 ; Number of sectors | ||
| 174 | BPBmediab DB 0FCH ; Media descriptor | ||
| 175 | BPBnfatsec DW 2 ; # of FAT sectors | ||
| 176 | BPBtrksiz DW 9 ; # of sectors/track | ||
| 177 | BPBnhead DW 1 ; # of heads | ||
| 178 | BPBhidsec DW 0 ; Hidden sector count | ||
| 179 | Timer DB 0 ; Countdown for motor off | ||
| 180 | DrvFlag DB 1 ; Per-drive flags, see below | ||
| 181 | TPI DB 0 ; Drive TPI= Not present, 48, 96 | ||
| 182 | CurCyl DW -1 ; Current cylinder | ||
| 183 | DriveStruc ENDS | ||
| 184 | |||
| 185 | ; DrvFlag values | ||
| 186 | Frestor= 1 ; restore needed | ||
| 187 | Fmotoron= 2 ; motor is on | ||
| 188 | |||
| 189 | DriveA DriveStruc <> ; floppy drive 0 | ||
| 190 | DriveB DriveStruc <> ; floppy drive 1 or 0 | ||
| 191 | DriveC DriveStruc <> ; hard drive 0 or floppy drive 2 | ||
| 192 | DriveD DriveStruc <> ; hard drive 1 or floppy drive 3 | ||
| 193 | |||
| 194 | FDinfo DW DriveA | ||
| 195 | DW DriveB | ||
| 196 | HDinfo DW DriveC | ||
| 197 | DW DriveD | ||
| 198 | |||
| 199 | |||
| 200 | ; Structure of parameter block for floppy pointed to by 0:4*1E | ||
| 201 | |||
| 202 | FloppyParameter STRUC | ||
| 203 | Spec1 DB 0 ; 0 1st byte for specify cmd | ||
| 204 | Spec2 DB 0 ; 1 2nd byte for specify cmd | ||
| 205 | DelayOff DB 0 ; 2 # of Ticks(1/18.2) until | ||
| 206 | ; motor shut off | ||
| 207 | SectorSize DB 0 ; 3 Sector size(128,256,512,1024) | ||
| 208 | ; = (O,1,2,3 are put here) | ||
| 209 | CylSize DB 0 ; 4 Number of sectors/cylinder | ||
| 210 | DataGap DB 0 ; 5 Gap length of read/write | ||
| 211 | ValueDTL DB 0 ; 6 Data length (ignored) | ||
| 212 | FormatGap DB 0 ; 7 Gap for format operation | ||
| 213 | FormatFill DB 0 ; 8 Fill char for format | ||
| 214 | DelaySettle DB 0 ; 9 Head settle time in msec | ||
| 215 | DelayMotor DB 0 ; 10 Motor start time in 1/8 sec | ||
| 216 | FloppyParameter ENDS | ||
| 217 | |||
| 218 | |||
| 219 | ScratchBuffer DB 512 DUP(?) ; Scratch buffer for when DMA fails | ||
| 220 | ; Hope we don't handle >512 sector | ||
| 221 | ; size | ||
| 222 | |||
| 223 | ;* Miscellaneous data | ||
| 224 | |||
| 225 | Single DB 0 ; non-zero if 1 floppy disk system | ||
| 226 | ; in this case, NumFloppy will be 2 | ||
| 227 | |||
| 228 | SUBTTL Data for interface to 4.0 | ||
| 229 | PAGE + | ||
| 230 | |||
| 231 | EXTRN DosFunction:DWORD ; Addr of DOS function routine | ||
| 232 | |||
| 233 | ; Dos helper functions used by disk driver | ||
| 234 | |||
| 235 | PullRequest = 2 ; Pull a request from the queue | ||
| 236 | PushRequest = 4 ; Add a request to the queue | ||
| 237 | BlockProcess = 9 ; Block process until I/O done | ||
| 238 | ContinueProcess = 10 ; I/O done, continue process | ||
| 239 | |||
| 240 | int_savregs= 32H ; interrupt routine which saves all regs | ||
| 241 | |||
| 242 | |||
| 243 | SwapSem1 DB 0 ; non-zero if waiting to swap disks | ||
| 244 | SwapSem2 DB 0 ; non-zero if waiting to prompt for swap | ||
| 245 | ScratchBufSem DB 0 ; semaphore controlling ScratchBuffer | ||
| 246 | |||
| 247 | SEM_WANT= 2 | ||
| 248 | SEM_BUSY= 1 | ||
| 249 | |||
| 250 | SemWait Macro wchan | ||
| 251 | local l1,l2 | ||
| 252 | pushf | ||
| 253 | l1: cli | ||
| 254 | test wchan,SEM_BUSY ;;semaphore busy? | ||
| 255 | jz l2 ;;no | ||
| 256 | or wchan,SEM_WANT ;;say we want it | ||
| 257 | mov ax,cs | ||
| 258 | mov bx,OFFSET wchan | ||
| 259 | xor cx,cx | ||
| 260 | mov dx,BlockProcess | ||
| 261 | call [DosFunction] ;;wait till semaphore released | ||
| 262 | jmp l1 | ||
| 263 | l2: or wchan,SEM_BUSY ;;claim semaphore | ||
| 264 | popf | ||
| 265 | endm | ||
| 266 | |||
| 267 | SemSig Macro wchan | ||
| 268 | local l | ||
| 269 | test wchan,SEM_WANT ;;anyone waiting on semaphore? | ||
| 270 | jz l | ||
| 271 | mov ax,cs | ||
| 272 | mov bx,OFFSET wchan | ||
| 273 | mov dx,ContinueProcess | ||
| 274 | call [DosFunction] | ||
| 275 | l: and wchan,NOT (SEM_WANT+SEM_BUSY) | ||
| 276 | endm | ||
| 277 | |||
| 278 | |||
| 279 | FloppyQueue DD 0 ; List of requests for floppy | ||
| 280 | FixedQueue DD 0 ; List of requests for fixed disk | ||
| 281 | |||
| 282 | ; Device driver headers | ||
| 283 | |||
| 284 | PUBLIC FloppyDevice | ||
| 285 | FloppyDevice LABEL WORD | ||
| 286 | DD FixedDevice ; Next device is hard disk | ||
| 287 | DW 100000B ; This is 4.0 driver | ||
| 288 | DW JustReturn ; Strategy does nothing | ||
| 289 | DW FloppyRequest ; Interrupt does the work | ||
| 290 | NumFloppy DB 4 ; Handle 4 floppys maximum | ||
| 291 | DB 0 ; can be addressed as word also | ||
| 292 | |||
| 293 | EXTRN Com1Dev:NEAR | ||
| 294 | |||
| 295 | FixedDevice LABEL WORD | ||
| 296 | DD Com1Dev ; Next device is comm port 1 | ||
| 297 | DW 100000B ; This is 4.0 driver | ||
| 298 | DW JustReturn ; Strategy does nothing | ||
| 299 | DW FixedRequest ; Interrupt does work (misnomer) | ||
| 300 | NumFixed DB 0 ; Handle 2 hard disks maximum | ||
| 301 | |||
| 302 | |||
| 303 | ; Utility routines which reside in the BIOS main module | ||
| 304 | |||
| 305 | EXTRN Interrupt:NEAR ; BIOS interrupt routine(misnomer) | ||
| 306 | EXTRN CmdErr:NEAR | ||
| 307 | EXTRN StatusDevReady:NEAR | ||
| 308 | EXTRN StatusComplete:NEAR | ||
| 309 | EXTRN StatusError:NEAR | ||
| 310 | EXTRN SetStatus:NEAR | ||
| 311 | |||
| 312 | JustReturn PROC FAR | ||
| 313 | RET | ||
| 314 | JustReturn ENDP | ||
| 315 | |||
| 316 | FloppyRequest PROC FAR | ||
| 317 | debug 4,2,<FloppyRequest, es:bx $x:$x, cmd $d\n>,<es,bx,<word ptr es:[bx.RqCmd]>> | ||
| 318 | PUSH SI | ||
| 319 | LEA SI,FloppyFunction ; 4.0 function routines | ||
| 320 | JMP Interrupt ; Let BIOS figure out what to do | ||
| 321 | FloppyRequest ENDP | ||
| 322 | |||
| 323 | ; Dispatch table for actions of the floppy requested by 4.0 | ||
| 324 | |||
| 325 | FloppyFunction LABEL WORD | ||
| 326 | DW FloppyInit ; 0 Initialize | ||
| 327 | DW FloppyCheck ; 1 Check media | ||
| 328 | DW FloppyBuild ; 2 Build BPB | ||
| 329 | DW CmdErr ; 3 IOCTL input | ||
| 330 | DW FloppyRead ; 4 Read | ||
| 331 | DW StatusDevReady ; 5 Non-destructive read | ||
| 332 | DW StatusComplete ; 6 Input status | ||
| 333 | DW StatusComplete ; 7 Input flush | ||
| 334 | DW FloppyWrite ; 8 Write | ||
| 335 | DW FloppyWriteV ; 9 Write with verify | ||
| 336 | DW CmdErr ; 10 Output status | ||
| 337 | DW CmdErr ; 11 Output flush | ||
| 338 | DW CmdErr ; 12 IOCTL output | ||
| 339 | DW CmdErr ; 13 Device open | ||
| 340 | DW CmdErr ; 14 Device close | ||
| 341 | DW CmdErr ; 15 Removable media | ||
| 342 | DW CmdErr ; 16 Generic IOCTL request | ||
| 343 | |||
| 344 | FixedRequest PROC FAR | ||
| 345 | debug 8,2,<FixedRequest, es:bx $x:$x, cmd $d\n>,<es,bx,<word ptr es:[bx.RqCmd]>> | ||
| 346 | PUSH SI | ||
| 347 | LEA SI,FixedFunction ; 4.0 function routines | ||
| 348 | JMP Interrupt ; Let BIOS figure out what to do | ||
| 349 | FixedRequest ENDP | ||
| 350 | |||
| 351 | ; Dispatch table for actions of the hard disk requested by 4.0 | ||
| 352 | |||
| 353 | FixedFunction LABEL WORD | ||
| 354 | DW FixedInit ; 0 Initialize | ||
| 355 | DW FixedCheck ; 1 Check media | ||
| 356 | DW FixedBuild ; 2 Build BPB | ||
| 357 | DW CmdErr ; 3 IOCTL input | ||
| 358 | DW FixedRead ; 4 Read | ||
| 359 | DW StatusDevReady ; 5 Non-destructive read | ||
| 360 | DW StatusComplete ; 6 Input status | ||
| 361 | DW StatusComplete ; 7 Input flush | ||
| 362 | DW FixedWrite ; 8 Write | ||
| 363 | DW FixedWriteV ; 9 Write with verify | ||
| 364 | DW CmdErr ; 10 Output status | ||
| 365 | DW CmdErr ; 11 Output flush | ||
| 366 | DW CmdErr ; 12 IOCTL output | ||
| 367 | DW CmdErr ; 13 Device open | ||
| 368 | DW CmdErr ; 14 Device close | ||
| 369 | DW CmdErr ; 15 Removable media | ||
| 370 | DW CmdErr ; 16 Generic IOCTL request | ||
| 371 | |||
| 372 | |||
| 373 | SUBTTL Data for routines that make direct Int 13 requests | ||
| 374 | PAGE + | ||
| 375 | |||
| 376 | |||
| 377 | RealInt13Vec dw 0 ; Used to make Int 13 requests | ||
| 378 | dw 0 | ||
| 379 | OldIntDVec dw 0 ; Must be reset when Int 13's on hard | ||
| 380 | dw 0 ; disk. | ||
| 381 | OldIntEVec dw 0 ; Must be reset when Int 13's on floppy | ||
| 382 | dw 0 ; disk. | ||
| 383 | SemDiskIO db 0 ; Semaphore controlling disk io | ||
| 384 | SemInt13 db 0 ; Semaphore controlling Int 13's | ||
| 385 | |||
| 386 | |||
| 387 | SUBTTL 4.0 device driver routines (system entry points) | ||
| 388 | PAGE + | ||
| 389 | |||
| 390 | BiosInit SEGMENT PARA PUBLIC 'CODE' | ||
| 391 | ASSUME CS:BiosSeg | ||
| 392 | |||
| 393 | PUBLIC Disk_Init | ||
| 394 | Disk_Init PROC | ||
| 395 | ;************************************************************** | ||
| 396 | ; This routine performs device dependent initialization | ||
| 397 | ; during the BIOS initialization. Not to be confused | ||
| 398 | ; with the device initialization entry points which are | ||
| 399 | ; called later on and perform different functions. | ||
| 400 | ; | ||
| 401 | ; AFTER THE EQUIPMENT CALL (INT 11H) BITS 6&7 WILL TELL | ||
| 402 | ; THE NUMBER OF FLOPPY DISKS IN THE SYSTEM. | ||
| 403 | ; THE INDICATIONS ARE AS FOLLOWS: | ||
| 404 | ; | ||
| 405 | ; BITS 7 6 DRIVES | ||
| 406 | ; 0 0 1 | ||
| 407 | ; 0 1 2 | ||
| 408 | ; 1 0 3 | ||
| 409 | ; 1 1 4 | ||
| 410 | ;************************************************************** | ||
| 411 | |||
| 412 | debug 12,1,<Performing disk driver pre-DOS initialization\n>,<> | ||
| 413 | PUSH CS | ||
| 414 | POP DS | ||
| 415 | |||
| 416 | ASSUME DS:BiosSeg | ||
| 417 | INT 11H ;GET EQUIPMENT STATUS | ||
| 418 | rol al,1 ; rotate around to low order bits | ||
| 419 | rol al,1 | ||
| 420 | AND AL,11B ;MASK DRIVE BITS | ||
| 421 | JNZ NOTSNGL ;Zero means single drive system | ||
| 422 | INC [SINGLE] ;REMEMBER THIS | ||
| 423 | inc al ; make it look like two-drive system | ||
| 424 | NOTSNGL: | ||
| 425 | inc al | ||
| 426 | MOV [NumFloppy],AL ;Remember how many drives | ||
| 427 | MOV AH,8 | ||
| 428 | MOV DL,80H | ||
| 429 | INT 13H ;Request number of hardfiles attached | ||
| 430 | JC ENDDRV ;Carry indicates old rom, so no hardfile | ||
| 431 | MOV [NumFixed],DL | ||
| 432 | test dl,dl ; any specified? | ||
| 433 | jz ENDDRV ; no | ||
| 434 | cmp NumFloppy,2 ; too many floppies? | ||
| 435 | jbe ENDDRV | ||
| 436 | mov NumFloppy,2 ; limit to two floppies max. | ||
| 437 | ENDDRV: | ||
| 438 | |||
| 439 | ;* Initialize the hard disk BPBs | ||
| 440 | |||
| 441 | MOV DL,80H | ||
| 442 | MOV DI,OFFSET DriveC | ||
| 443 | CMP [NumFixed],0 | ||
| 444 | JLE ITSOK | ||
| 445 | CALL SETHRD ;SET UP FIRST HARDFILE | ||
| 446 | |||
| 447 | MOV DL,81H ;SET UP FOR NEXT CALL | ||
| 448 | MOV DI,OFFSET DriveD | ||
| 449 | JC NOTOK | ||
| 450 | CMP [NumFixed],2 | ||
| 451 | JZ SETIT | ||
| 452 | JMP SHORT ITSOK | ||
| 453 | NOTOK: | ||
| 454 | MOV DI,OFFSET DriveC | ||
| 455 | DEC [NumFixed] | ||
| 456 | CMP [NumFixed],0 | ||
| 457 | JZ ITSOK | ||
| 458 | SETIT: CALL SETHRD ;SET UP SECOND HARDFILE | ||
| 459 | JNC ITSOK | ||
| 460 | DEC [NumFixed] | ||
| 461 | ITSOK: | ||
| 462 | cmp [NumFixed],0 ; any hard disks found? | ||
| 463 | jnz itsok2 ; yes | ||
| 464 | mov ax,[FixedDevice] ; no, patch device chain to skip fixed disk | ||
| 465 | mov [FloppyDevice],ax | ||
| 466 | itsok2: | ||
| 467 | push es ; Install Int 13 handler and save the | ||
| 468 | xor ax,ax ; old value of the interrupt vector. | ||
| 469 | mov es,ax | ||
| 470 | mov ax,es:[4*13h] | ||
| 471 | mov [RealInt13Vec],ax | ||
| 472 | mov ax,OFFSET Int13Handler | ||
| 473 | mov es:[4*13H],ax | ||
| 474 | mov ax,es:[4*13h+2] | ||
| 475 | mov [RealInt13Vec+2],ax | ||
| 476 | mov es:[4*13H+2],cs | ||
| 477 | mov ax,es:[4*0dh] ; Save original Int D vector | ||
| 478 | mov [OldIntDVec],ax | ||
| 479 | mov ax,es:[4*0dh+2] | ||
| 480 | mov [OldIntDVec+2],ax | ||
| 481 | mov ax,es:[4*0eh] ; Save original Int E vector | ||
| 482 | mov [OldIntEVec],ax | ||
| 483 | mov ax,es:[4*0eh+2] | ||
| 484 | mov [OldIntEVec+2],ax | ||
| 485 | pop es | ||
| 486 | ret | ||
| 487 | Disk_Init ENDP | ||
| 488 | |||
| 489 | ; | ||
| 490 | ; READ A BOOT RECORD INTO Scratch buffer | ||
| 491 | ; | ||
| 492 | GETBOOT: | ||
| 493 | MOV CX,1 | ||
| 494 | MOV AX,0201H | ||
| 495 | push CS | ||
| 496 | pop es | ||
| 497 | mov BX,OFFSET ScratchBuffer | ||
| 498 | xor DH,DH | ||
| 499 | INT 13H | ||
| 500 | JC SETRET | ||
| 501 | CMP WORD PTR ES:[BX+1FEH],0AA55H | ||
| 502 | JNZ SETRET | ||
| 503 | RET | ||
| 504 | ; | ||
| 505 | ; SETUP VARIABLE SIZED HARDFILE | ||
| 506 | ; ON ENTRY DL=DRIVE NUMBER (80 OR 81) | ||
| 507 | ; DI=PTR TO B.P.B | ||
| 508 | ; | ||
| 509 | SETHRD: PUSH DX | ||
| 510 | MOV AH,8 ;GET DRIVE PARAMETERS | ||
| 511 | INT 13H | ||
| 512 | INC DH | ||
| 513 | MOV BYTE PTR [DI].BPBnhead,DH | ||
| 514 | POP DX | ||
| 515 | JC SETRET | ||
| 516 | AND CL,3FH | ||
| 517 | MOV BYTE PTR [DI].BPBtrksiz,CL | ||
| 518 | CALL GETBOOT ;GET THE BOOT RECORD | ||
| 519 | JC SETRET | ||
| 520 | add BX,1C2H | ||
| 521 | mov cx,4 | ||
| 522 | SET1: CMP BYTE PTR ES:[BX],1 | ||
| 523 | JZ SET2 | ||
| 524 | ADD BX,16 | ||
| 525 | loop SET1 | ||
| 526 | SETRET: STC ;NOT FOUND SO USE DEFAULTS | ||
| 527 | debug 8,3,<Sethrd err rtn: drive $x stat $x\n>,<dx,ax> | ||
| 528 | RET | ||
| 529 | |||
| 530 | SET2: MOV AX,ES:[BX+4] | ||
| 531 | MOV DS:[DI].BPBhidsec,AX ;SET HIDDEN SECTOR COUNT | ||
| 532 | MOV AX,ES:[BX+8] | ||
| 533 | CMP AX,64 ;HAS TO BE AT LEAST 32K | ||
| 534 | JB SETRET | ||
| 535 | MOV DS:[DI].BPBnsec,AX ;SAVE LOGICAL SECTOR COUNT | ||
| 536 | MOV CX,0100H ;SET CLUS SIZE AND SHIFT COUNT | ||
| 537 | MOV DX,64 ;SET NUMBER OF DIR ENTRIES | ||
| 538 | CMP AX,512 | ||
| 539 | JBE SET3 | ||
| 540 | |||
| 541 | ADD CH,CH | ||
| 542 | INC CL | ||
| 543 | MOV DX,112 | ||
| 544 | CMP AX,2048 | ||
| 545 | JBE SET3 | ||
| 546 | |||
| 547 | ADD CH,CH | ||
| 548 | INC CL | ||
| 549 | MOV DX,256 | ||
| 550 | CMP AX,8192 | ||
| 551 | JBE SET3 | ||
| 552 | |||
| 553 | ADD CH,CH | ||
| 554 | INC CL | ||
| 555 | ADD DX,DX | ||
| 556 | CMP AX,32680 ;NOT 32768! MAX NUMBER OF CLUSTERS=4085 | ||
| 557 | JBE SET3 | ||
| 558 | |||
| 559 | ADD CH,CH | ||
| 560 | INC CL | ||
| 561 | ADD DX,DX | ||
| 562 | SET3: | ||
| 563 | ; | ||
| 564 | ; DX=NUMBER OF DIR ENTRIES, CH=NUMBER OF SECTORS PER CLUSTER | ||
| 565 | ; CL=LOG BASE 2 OF CH | ||
| 566 | ; | ||
| 567 | ; NOW CALCULATE SIZE OF FAT TABLE | ||
| 568 | ; | ||
| 569 | MOV [DI].BPBndir,DX ;SAVE NUMBER OF DIR ENTRIES | ||
| 570 | MOV [DI].BPBsecpau,CH ;SAVE SECTORS PER CLUSTER | ||
| 571 | XOR BX,BX | ||
| 572 | MOV BL,CH | ||
| 573 | DEC BX | ||
| 574 | ADD BX,AX | ||
| 575 | SHR BX,CL ;DIVIDE BY SECTORS/CLUSTER | ||
| 576 | INC BX | ||
| 577 | AND BL,11111110B ;MAKE SURE COUNT IS EVEN | ||
| 578 | MOV SI,BX | ||
| 579 | SHR BX,1 | ||
| 580 | ADD BX,SI ;MULTIPY BY 1.5 | ||
| 581 | ADD BX,511 | ||
| 582 | SHR BH,1 | ||
| 583 | MOV BYTE PTR [DI].BPBnfatsec,BH ;SAVE NUMBER OF FAT SECTORS | ||
| 584 | MOV [DI].BPBmediab,0F8H ; set media byte | ||
| 585 | CLC | ||
| 586 | RET | ||
| 587 | BiosInit ENDS | ||
| 588 | |||
| 589 | ASSUME CS:BiosSeg,DS:NOTHING,ES:NOTHING | ||
| 590 | |||
| 591 | FloppyInit PROC | ||
| 592 | debug 4,3,<Diskette initialization>,<> | ||
| 593 | push ds ; install floppy interrupt routine | ||
| 594 | xor ax,ax | ||
| 595 | mov ds,ax | ||
| 596 | mov ax,OFFSET FloppyInterrupt | ||
| 597 | mov ds:[4*0eH],ax | ||
| 598 | mov ds:[4*0eH+2],cs | ||
| 599 | pop ds | ||
| 600 | call Rst765 | ||
| 601 | mov ah,[NumFloppy] | ||
| 602 | mov di,OFFSET FDinfo | ||
| 603 | DBBEG 4,3 | ||
| 604 | jmp SHORT iniret | ||
| 605 | DBEND | ||
| 606 | jmp bpbret | ||
| 607 | ELSE | ||
| 608 | jmp SHORT bpbret | ||
| 609 | ENDIF | ||
| 610 | FloppyInit ENDP | ||
| 611 | |||
| 612 | FixedInit PROC | ||
| 613 | debug 8,3,<Hard disk initialization>,<> | ||
| 614 | push ds ; install fixed disk interrupt routine | ||
| 615 | xor ax,ax | ||
| 616 | mov ds,ax | ||
| 617 | mov ax,OFFSET FixedInterrupt | ||
| 618 | mov ds:[4*0dH],ax | ||
| 619 | mov ds:[4*0dH+2],cs | ||
| 620 | pop ds | ||
| 621 | in al,21H ; unmask fixed disk interrupts | ||
| 622 | and al,0DFH | ||
| 623 | out 21H,al | ||
| 624 | mov dx,HD_PMSK ; set interrupt and DMA mask bits | ||
| 625 | mov al,3 | ||
| 626 | out dx,al | ||
| 627 | mov ah,[NumFixed] | ||
| 628 | mov di,OFFSET HDinfo | ||
| 629 | DBBEG 8,3 | ||
| 630 | iniret: debug 12,3,< - Num=$x BPB table=$x:$x\n>,<ax,cs,di> | ||
| 631 | DBEND | ||
| 632 | ENDIF | ||
| 633 | jmp SHORT bpbret | ||
| 634 | FixedInit ENDP | ||
| 635 | |||
| 636 | FloppyBuild PROC | ||
| 637 | mov ah,byte ptr es:[di] | ||
| 638 | call FDGetBPB | ||
| 639 | bpbret: mov [bx.RqMedia],ah | ||
| 640 | mov [bx.RqCount],di | ||
| 641 | mov [bx.RqCount+2],CS | ||
| 642 | jmp StatusComplete | ||
| 643 | FloppyBuild ENDP | ||
| 644 | |||
| 645 | FixedBuild PROC | ||
| 646 | mov ah,byte ptr es:[di] | ||
| 647 | call HDGetBPB | ||
| 648 | jmp SHORT bpbret | ||
| 649 | FixedBuild ENDP | ||
| 650 | |||
| 651 | ;*** FloppyCheck - check to see if the disk may have been changed. | ||
| 652 | ; | ||
| 653 | ; ENTRY AL = unit # | ||
| 654 | ; AH = media byte | ||
| 655 | ; EXIT Return value in request header set to one of: | ||
| 656 | ; 1 Media may have been changed | ||
| 657 | ; 0 Media not changed | ||
| 658 | ; -1 Media was probably changed | ||
| 659 | ; | ||
| 660 | |||
| 661 | FloppyCheck PROC | ||
| 662 | MOV DL,1 ; Assume not changed | ||
| 663 | cmp AH,0f8H ; Is disk removable? | ||
| 664 | JE FloppyCheckDone ; No, can't be changed then | ||
| 665 | cmp Single,0 ; single drive system? | ||
| 666 | je flchk1 ; no, check drive state | ||
| 667 | cmp Floppy.Unit,al ; unit = current drive? | ||
| 668 | je flchk1 ; yes, check drive state | ||
| 669 | mov DL,-1 ; say media changed for sure | ||
| 670 | jmp FloppyCheckDone | ||
| 671 | flchk1: MOV CX,AX | ||
| 672 | XOR CH,CH | ||
| 673 | MOV SI,CX | ||
| 674 | ADD SI,SI | ||
| 675 | MOV SI,FDinfo[SI] ; Get pointer to drive info | ||
| 676 | TEST CS:[SI].DrvFlag,Fmotoron ; Is motor on? | ||
| 677 | JNZ FloppyCheckDone ; Yes, media not changed then | ||
| 678 | XOR DL,DL ; No, might have been changed | ||
| 679 | FloppyCheckDone: | ||
| 680 | MOV BYTE PTR DS:[BX].RqAddr,DL | ||
| 681 | JMP StatusComplete ; Return whether media changed | ||
| 682 | FloppyCheck ENDP | ||
| 683 | |||
| 684 | |||
| 685 | FixedCheck PROC | ||
| 686 | MOV DL,1 | ||
| 687 | JMP FloppyCheckDone | ||
| 688 | FixedCheck ENDP | ||
| 689 | ;*** FloppyRead, FloppyWrite, FloppyWriteV - Basic I/O entry points | ||
| 690 | ; | ||
| 691 | ; FloppyRead, FloppyWrite and FloppyWriteV are the basic I/O | ||
| 692 | ; routines used by the DOS. They really do not do much except | ||
| 693 | ; queue the request and start the device if it is idle. | ||
| 694 | ; For single drive floppy systems, they also handle the | ||
| 695 | ; switching of disks when I/O changes from A to B or vice-versa. | ||
| 696 | ; | ||
| 697 | ; ENTRY DS:BX Packet address | ||
| 698 | ; ES:DI Transfer address | ||
| 699 | ; AL Unit # | ||
| 700 | ; AH Media Byte | ||
| 701 | ; CX # of sectors | ||
| 702 | ; DX Starting sector | ||
| 703 | ; | ||
| 704 | ; EXIT DS:BX Packet Addr | ||
| 705 | ; CX # of sectors left to do | ||
| 706 | ; | ||
| 707 | ; USES SI | ||
| 708 | |||
| 709 | FloppyRead LABEL NEAR | ||
| 710 | FloppyWrite LABEL NEAR | ||
| 711 | FloppyWriteV PROC | ||
| 712 | debug 4,2,<Fl rd/wt/ver Req $x:$x unit $b sec $d nsec $d\n>,<ds,bx,ax,dx,cx> | ||
| 713 | call BlockIfLocked | ||
| 714 | push di | ||
| 715 | call FDGetBPB ; cs:di => BPB | ||
| 716 | mov si,dx | ||
| 717 | add si,cx ; compute last sector + 1 | ||
| 718 | cmp si,cs:[di.BPBnsec] | ||
| 719 | mov si,di | ||
| 720 | pop di | ||
| 721 | jbe flrw1 | ||
| 722 | mov al,8 ; ERROR - Sector not found | ||
| 723 | jmp StatusError | ||
| 724 | |||
| 725 | flrw1: OR CX,CX ; Anything to do? | ||
| 726 | JNZ flrw2 ; Yes | ||
| 727 | JMP StatusComplete ; No, all done now | ||
| 728 | flrw2: | ||
| 729 | CMP Single,0 ; Is this a single drive system? | ||
| 730 | JE flrw3 ; No, don't check for drive change | ||
| 731 | CALL FloppyChange ; See if should change disks | ||
| 732 | flrw3: | ||
| 733 | call CheckWrap | ||
| 734 | push ds | ||
| 735 | pop es ; ES:BX = Request addr | ||
| 736 | push cs | ||
| 737 | pop ds | ||
| 738 | LEA SI,FloppyQueue ; DS:SI = ptr to head of queue | ||
| 739 | MOV DX,PushRequest | ||
| 740 | CALL DosFunction ; Add request to list | ||
| 741 | push es | ||
| 742 | pop ds ; Back to DS:BX is request | ||
| 743 | pushf | ||
| 744 | cli ; interrupts off while testing state | ||
| 745 | TEST Floppy.Flags,Factive ; Is driver active? | ||
| 746 | JNE FloppyActive ; Yes, driver will get to it | ||
| 747 | PUSH DS | ||
| 748 | PUSH BX ; Save some regs | ||
| 749 | OR Floppy.Flags,Factive | ||
| 750 | MOV Floppy.State,Start ; Want to start I/O | ||
| 751 | CALL FloppyExecute ; Start up the driver | ||
| 752 | POP BX | ||
| 753 | POP DS ; Restore regs | ||
| 754 | flrw4: test DS:[BX].RqStatus,0100H ; IO completed? | ||
| 755 | JNZ FloppyIOdone ; yes | ||
| 756 | |||
| 757 | FloppyActive: | ||
| 758 | MOV AX,DS ; AX:BX = request | ||
| 759 | xor cx,cx | ||
| 760 | push bx | ||
| 761 | MOV DX,BlockProcess | ||
| 762 | CALL DosFunction ; Block until I/O is done | ||
| 763 | pop bx | ||
| 764 | jmp flrw4 ; test completion status again | ||
| 765 | FloppyIOdone: | ||
| 766 | popf | ||
| 767 | MOV AX,DS:[BX].RqStatus ; Need AX = status | ||
| 768 | MOV CX,DS:[BX].RqCount ; Need CX = count left to do | ||
| 769 | debug 4,2,<Fl rd/wt/ver DONE Req $x:$x stat $x resid $d\n>,<ds,bx,ax,cx> | ||
| 770 | JMP SetStatus ; Return to DOS with results | ||
| 771 | FloppyWriteV ENDP | ||
| 772 | |||
| 773 | |||
| 774 | FixedRead LABEL NEAR | ||
| 775 | FixedWrite LABEL NEAR | ||
| 776 | FixedWriteV PROC | ||
| 777 | debug 8,2,<Fix rd/wt/ver Req $x:$x unit $b sec $d nsec $d\n>,<ds,bx,ax,dx,cx> | ||
| 778 | call BlockIfLocked | ||
| 779 | push di | ||
| 780 | call HDGetBPB ; cs:di => BPB | ||
| 781 | mov si,dx | ||
| 782 | add si,cx ; compute last sector + 1 | ||
| 783 | cmp si,cs:[di.BPBnsec] | ||
| 784 | mov si,di | ||
| 785 | pop di | ||
| 786 | jbe fxrw1 | ||
| 787 | mov al,8 ; ERROR - Sector not found | ||
| 788 | jmp StatusError | ||
| 789 | |||
| 790 | fxrw1: OR CX,CX ; Anything to do? | ||
| 791 | JNZ fxrw2 ; Yes | ||
| 792 | JMP StatusComplete ; No, all done now | ||
| 793 | fxrw2: | ||
| 794 | call CheckWrap | ||
| 795 | push ds | ||
| 796 | pop es ; ES:BX = Request addr | ||
| 797 | push cs | ||
| 798 | pop ds | ||
| 799 | LEA SI,FixedQueue ; DS:SI = ptr to head of queue | ||
| 800 | MOV DX,PushRequest | ||
| 801 | CALL DosFunction ; Add request to list | ||
| 802 | push es | ||
| 803 | pop ds ; Back to DS:BX is request | ||
| 804 | pushf | ||
| 805 | cli ; interrupts off while testing state | ||
| 806 | TEST Fixed.Flags,Factive ; Is driver active? | ||
| 807 | JNE FixedActive ; Yes, driver will get to it | ||
| 808 | PUSH DS | ||
| 809 | PUSH BX ; Save some regs | ||
| 810 | OR Fixed.Flags,Factive | ||
| 811 | MOV Fixed.State,Start ; Want to start I/O | ||
| 812 | CALL FixedExecute ; Start up the driver | ||
| 813 | POP BX | ||
| 814 | POP DS ; Restore regs | ||
| 815 | fxrw4: test DS:[BX].RqStatus,0100H ; IO completed? | ||
| 816 | JNZ FixedIOdone ; yes | ||
| 817 | |||
| 818 | FixedActive: | ||
| 819 | MOV AX,DS ; AX:BX = request | ||
| 820 | xor cx,cx | ||
| 821 | push bx | ||
| 822 | MOV DX,BlockProcess | ||
| 823 | CALL DosFunction ; Block until I/O is done | ||
| 824 | pop bx | ||
| 825 | jmp fxrw4 ; test completion status again | ||
| 826 | FixedIOdone: | ||
| 827 | popf | ||
| 828 | MOV AX,DS:[BX].RqStatus ; Need AX = status | ||
| 829 | MOV CX,DS:[BX].RqCount ; Need CX = count left to do | ||
| 830 | debug 8,2,<Fx rd/wt/ver DONE Req $x:$x stat $x resid $d\n>,<ds,bx,ax,cx> | ||
| 831 | JMP SetStatus ; Return to DOS with results | ||
| 832 | FixedWriteV ENDP | ||
| 833 | |||
| 834 | ;*** CheckWrap - check whether a request crosses a 64Kb boundary | ||
| 835 | ; | ||
| 836 | ; CheckWrap will check whether the request given in DS:BX | ||
| 837 | ; crosses a 64Kb boundary. A portion of such requests must | ||
| 838 | ; be done using ScratchBuffer for a single sector transfer. | ||
| 839 | ; This routine ensures that only one such request is put into | ||
| 840 | ; either of the request queues at any time. | ||
| 841 | ; | ||
| 842 | ; ENTRY DS:BX Request header | ||
| 843 | ; ES:DI Transfer address | ||
| 844 | ; CS:SI Pointer to BPB | ||
| 845 | ; CX Sector count | ||
| 846 | ; EXIT When it's safe to proceed. | ||
| 847 | ; USES AX,BP | ||
| 848 | |||
| 849 | CheckWrap PROC | ||
| 850 | push dx | ||
| 851 | push cx | ||
| 852 | mov ax,cx | ||
| 853 | mul cs:[si.BPBsecsiz] | ||
| 854 | mov dx,es ; compute offset | ||
| 855 | mov cl,4 | ||
| 856 | shl dx,cl | ||
| 857 | add dx,di | ||
| 858 | clc ; now see if offset+nbytes overflows | ||
| 859 | add dx,ax | ||
| 860 | jnc chkw8 | ||
| 861 | debug 12,10h,<CheckWrap $x $x:$x >,<ax,es,di> | ||
| 862 | push bx | ||
| 863 | SemWait ScratchBufSem ; wait for ScratchBuffer to be available | ||
| 864 | pop bx | ||
| 865 | |||
| 866 | chkw8: pop cx | ||
| 867 | pop dx | ||
| 868 | ret | ||
| 869 | CheckWrap ENDP | ||
| 870 | |||
| 871 | |||
| 872 | ;*** FloppyChange - check whether floppy disk must be changed | ||
| 873 | ; | ||
| 874 | ; FloppyChange is called on a single drive system to simulate a | ||
| 875 | ; two drive system. The current request for I/O is checked against | ||
| 876 | ; what the driver considers to be the current drive. If they are | ||
| 877 | ; the same, FloppyChange just returns. Otherwise, SwapSem2 is set | ||
| 878 | ; and the current process is blocked on SwapSem2. Any process that | ||
| 879 | ; attempts I/O while SwapSem2 is set is blocked on SwapSem1. When | ||
| 880 | ; SwapSem2 is cleared, these processes are continued. When the | ||
| 881 | ; driver becomes idle and SwapSem2 is set, the Idle state continues | ||
| 882 | ; the blocked process. This process then puts out the message about | ||
| 883 | ; switching disks and waits for a user reply. When it is given, | ||
| 884 | ; FloppyChange clears SwapSem1 and causes the I/O to be started. | ||
| 885 | ; | ||
| 886 | ; ENTRY DS:BX Pointer to I/O request | ||
| 887 | ; | ||
| 888 | ; USES AX,DX | ||
| 889 | ; | ||
| 890 | |||
| 891 | |||
| 892 | FloppyChange PROC | ||
| 893 | push cx | ||
| 894 | pushf | ||
| 895 | push bx | ||
| 896 | SemWait SwapSem1 ; Currently waiting to switch disk? | ||
| 897 | pop bx | ||
| 898 | |||
| 899 | flcha1: and SwapSem1,NOT SEM_BUSY ; reset BUSY for now | ||
| 900 | MOV AL,DS:[BX].RqUnit ; Get desired unit | ||
| 901 | CMP AL,Floppy.Unit ; Switching A and B drive? | ||
| 902 | JE flcha7 ; No, keep using this drive | ||
| 903 | CLI ; ** Disable interrupts | ||
| 904 | OR SwapSem1,SEM_BUSY ; Flag waiting to switch | ||
| 905 | test Floppy.Flags,Factive ; Is driver idle? | ||
| 906 | JE flcha2 ; Yes, don't need to wait | ||
| 907 | push bx | ||
| 908 | SemWait SwapSem2 | ||
| 909 | pop bx | ||
| 910 | jmp flcha1 | ||
| 911 | flcha2: | ||
| 912 | popf ; restore interrupt state | ||
| 913 | pushf | ||
| 914 | ADD AL,"A" ; Convert to drive letter | ||
| 915 | MOV CS:DriveLetter,AL ; Set the letter | ||
| 916 | PUSH DS | ||
| 917 | PUSH SI | ||
| 918 | push bx | ||
| 919 | push cs | ||
| 920 | pop ds | ||
| 921 | LEA SI,SwitchMsg | ||
| 922 | flcha4: | ||
| 923 | LODSB | ||
| 924 | OR AL,AL ; End of message? | ||
| 925 | JZ flcha5 ; Yes | ||
| 926 | INT 29H ; No, output char | ||
| 927 | JMP flcha4 ; Put out whole msg | ||
| 928 | |||
| 929 | flcha5: | ||
| 930 | mov ah,1 ; Flush keyboard input | ||
| 931 | int 16H | ||
| 932 | jz flcha5 | ||
| 933 | XOR AH,AH | ||
| 934 | INT 16H ; Wait for a char | ||
| 935 | pop bx | ||
| 936 | POP SI | ||
| 937 | POP DS | ||
| 938 | flcha7: | ||
| 939 | push bx | ||
| 940 | SemSig SwapSem1 ; Allow blocked processes to continue | ||
| 941 | pop bx | ||
| 942 | flcha8: | ||
| 943 | popf | ||
| 944 | pop cx | ||
| 945 | RET | ||
| 946 | |||
| 947 | FloppyChange ENDP | ||
| 948 | |||
| 949 | |||
| 950 | SwitchMsg LABEL WORD | ||
| 951 | DB 13,10,"Insert diskette for drive " | ||
| 952 | DriveLetter LABEL BYTE | ||
| 953 | DB "A: and strike",13,10,"any key when ready",13,10,10,0 | ||
| 954 | |||
| 955 | |||
| 956 | Int13Handler Proc Far | ||
| 957 | push dx ; Save regs used in local processing | ||
| 958 | push cx | ||
| 959 | push bx | ||
| 960 | push ax | ||
| 961 | pushf | ||
| 962 | LockCheck: | ||
| 963 | cli ; If any Int 13 request is already | ||
| 964 | cmp SemInt13,0 ; pending, block this process until | ||
| 965 | jz NotLocked ; the previous one finishes. | ||
| 966 | mov ax,cs | ||
| 967 | mov bx,offset SemInt13 | ||
| 968 | xor cx,cx | ||
| 969 | mov dx,BlockProcess | ||
| 970 | call DosFunction | ||
| 971 | jmp LockCheck | ||
| 972 | NotLocked: | ||
| 973 | mov SemInt13,1 ; Lock out other disk requests | ||
| 974 | popf | ||
| 975 | pushf | ||
| 976 | BusyCheck: | ||
| 977 | cli | ||
| 978 | cmp SemDiskIO,0 ; If the disks are busy, block this | ||
| 979 | jz DiskFree ; process till they free up. | ||
| 980 | mov ax,cs | ||
| 981 | mov bx,offset SemDiskIO | ||
| 982 | xor cx,cx | ||
| 983 | mov dx,BlockProcess | ||
| 984 | call DosFunction | ||
| 985 | jmp BusyCheck | ||
| 986 | DiskFree: | ||
| 987 | popf | ||
| 988 | sti | ||
| 989 | pop ax ; Restore regs for call | ||
| 990 | pop bx | ||
| 991 | pop cx | ||
| 992 | pop dx | ||
| 993 | push dx | ||
| 994 | push cx | ||
| 995 | push bx | ||
| 996 | pushf | ||
| 997 | call dword ptr [RealInt13Vec] | ||
| 998 | mov SemInt13,0 | ||
| 999 | push ax | ||
| 1000 | pushf | ||
| 1001 | mov ax,cs ; Unblock anything that is waiting | ||
| 1002 | mov bx,offset SemInt13 | ||
| 1003 | mov dx,ContinueProcess | ||
| 1004 | call DosFunction | ||
| 1005 | popf ; Restore user regs | ||
| 1006 | pop ax | ||
| 1007 | pop bx | ||
| 1008 | pop cx | ||
| 1009 | pop dx | ||
| 1010 | ret 2 | ||
| 1011 | Int13Handler endp | ||
| 1012 | |||
| 1013 | |||
| 1014 | SUBTTL Fixed disk startup routine | ||
| 1015 | PAGE + | ||
| 1016 | |||
| 1017 | ; FixedExecute processes a disk request after it has been set up. When the | ||
| 1018 | ; disk is inactive (State = Idle), it is called to start the device. For all | ||
| 1019 | ; subsequent events, it is called on the disk interrupt which signaled the | ||
| 1020 | ; completion of that subfunction. Some states do not involve waiting for an | ||
| 1021 | ; interrupt to occur. This routine runs entirely off the 'Fixed' data structure | ||
| 1022 | |||
| 1023 | FixedDispatch LABEL WORD | ||
| 1024 | DW FxExStart | ||
| 1025 | DW FxExCalc | ||
| 1026 | DW FxExError ;; BUGBUG really error in state machine | ||
| 1027 | DW FxExError ;; BUGBUG really error in state machine | ||
| 1028 | DW FxExError ;; BUGBUG really error in state machine | ||
| 1029 | DW FxExError ;; BUGBUG really error in state machine | ||
| 1030 | DW FxExVerify | ||
| 1031 | DW FxExDone | ||
| 1032 | DW FxExIdle | ||
| 1033 | DW FxExError | ||
| 1034 | |||
| 1035 | FixedExecute PROC | ||
| 1036 | push cs ; CS -> DS | ||
| 1037 | pop ds | ||
| 1038 | ASSUME DS:BiosSeg | ||
| 1039 | MOV BX,Fixed.State ; Get current state | ||
| 1040 | debug 8,4,<FxEx state $d >,<bx> | ||
| 1041 | ADD BX,BX | ||
| 1042 | JMP FixedDispatch[BX] ; Dispatch to correct routine | ||
| 1043 | |||
| 1044 | |||
| 1045 | ;* Fixed state Start | ||
| 1046 | ; | ||
| 1047 | ; Do setup calculations to figure out sector, start | ||
| 1048 | ; up motor, advance to Calc state. | ||
| 1049 | ; | ||
| 1050 | ; Entered on initially picking up a new request to do and on error retries. | ||
| 1051 | ; If error retries start here, then multiple sector requests will always start | ||
| 1052 | ; at the beginning rather than at the point of the error! Why? | ||
| 1053 | |||
| 1054 | FxExStart: | ||
| 1055 | mov si,OFFSET Fixed ; SI = pointer to per-device info. | ||
| 1056 | les bx,FixedQueue ; ES:BX = pointer to current request | ||
| 1057 | mov al,es:[bx].RqUnit | ||
| 1058 | call HDGetBPB ; DI = drive parameters | ||
| 1059 | CALL Setup ; Do setup calculations | ||
| 1060 | MOV Fixed.State,Calc ; Advance to next state | ||
| 1061 | JMP FixedExecute ; Now return to do Calc code | ||
| 1062 | |||
| 1063 | |||
| 1064 | |||
| 1065 | ;* Fixed state Calc | ||
| 1066 | ; | ||
| 1067 | ; Calculate cylinder, head and sector, wait for motor | ||
| 1068 | ; start or head load, advance to Select state. | ||
| 1069 | ; | ||
| 1070 | ; Entered after Start state and also on further sectors of a multiple sector | ||
| 1071 | ; request. | ||
| 1072 | |||
| 1073 | FxExCalc: | ||
| 1074 | mov si,OFFSET Fixed ; SI = pointer to per-device info. | ||
| 1075 | les bx,FixedQueue ; ES:BX = pointer to current request | ||
| 1076 | mov al,es:[bx].RqUnit | ||
| 1077 | call HDGetBPB ; DI = drive parameters | ||
| 1078 | CALL MapSector ; Get head, cylinder and sector | ||
| 1079 | test Fixed.Flags,Fwrite | ||
| 1080 | jnz fxxc1 | ||
| 1081 | mov al,DMA_read | ||
| 1082 | mov Fixed.DCB,HD_CREAD | ||
| 1083 | jmp SHORT fxxc2 | ||
| 1084 | fxxc1: mov al,DMA_write | ||
| 1085 | mov Fixed.DCB,HD_CWRITE | ||
| 1086 | fxxc2: mov ah,HD_DMA | ||
| 1087 | call DMAsetup ; set up DMA transfer | ||
| 1088 | mov al,Fixed.Unit | ||
| 1089 | mov cl,5 | ||
| 1090 | shl ax,cl | ||
| 1091 | or al,Fixed.Head | ||
| 1092 | mov Fixed.DCB+1,al ; set head/unit | ||
| 1093 | mov ax,Fixed.cyl | ||
| 1094 | mov Fixed.DCB+3,al ; set low cylinder | ||
| 1095 | shr ax,1 | ||
| 1096 | shr ax,1 | ||
| 1097 | and al,0C0H | ||
| 1098 | or al,Fixed.Sector | ||
| 1099 | mov Fixed.DCB+2,al ; set high cylinder/sector | ||
| 1100 | mov al,BYTE PTR Fixed.Numsectors | ||
| 1101 | mov Fixed.DCB+4,al ; set sector count | ||
| 1102 | mov Fixed.DCB+5,HDcontrolbyte ;BUGBUG - what do we want here? | ||
| 1103 | mov al,3 | ||
| 1104 | call HDCommand | ||
| 1105 | mov al,Done ; assume next state is Done | ||
| 1106 | test Fixed.Flags,Fverify | ||
| 1107 | jz fxxc3 | ||
| 1108 | mov al,Verify | ||
| 1109 | fxxc3: mov BYTE PTR Fixed.State,al ; set next state | ||
| 1110 | ret | ||
| 1111 | |||
| 1112 | |||
| 1113 | ;* Fixed state Verify | ||
| 1114 | ; | ||
| 1115 | ; Have executed a write function, must now verify. | ||
| 1116 | ; BUGBUG For now just go to done state. | ||
| 1117 | |||
| 1118 | FxExVerify: | ||
| 1119 | mov Fixed.State,Done | ||
| 1120 | jmp FixedExecute | ||
| 1121 | |||
| 1122 | |||
| 1123 | |||
| 1124 | ;* Fixed state Done | ||
| 1125 | ; | ||
| 1126 | ; If whole request is now complete, mark the request | ||
| 1127 | ; as done and then start the next one if there is one. If the request is not | ||
| 1128 | ; yet done, adjust values to show the amount of the request done and then go | ||
| 1129 | ; back to the Calc state to do next part. | ||
| 1130 | |||
| 1131 | FxExDone: | ||
| 1132 | MOV AL,Fixed.Flags | ||
| 1133 | AND AL,Fwrite+Fwrap1 ; Only interested in these bits | ||
| 1134 | CMP AL,Fwrap1 ; Just read into scratch? | ||
| 1135 | JNE fxxd1 ; No | ||
| 1136 | PUSH DS | ||
| 1137 | PUSH ES | ||
| 1138 | MOV CX,Fixed.NumBytes ; CS = # bytes to write from scr | ||
| 1139 | LES DI,Fixed.RealAddr ; ES:DI = real buffer | ||
| 1140 | LDS SI,Fixed.Addr ; DS:SI = scratch buffer | ||
| 1141 | CLD | ||
| 1142 | REP MOVSB ; Copy into real buffer | ||
| 1143 | POP ES | ||
| 1144 | POP DS | ||
| 1145 | fxxd1: | ||
| 1146 | MOV AX,Fixed.NumSectors ; AX = # of sectors we did | ||
| 1147 | SUB Fixed.Count,AX ; Adjust count to number left | ||
| 1148 | JZ fxxd3 ; Request is done, tell DOS | ||
| 1149 | ADD Fixed.First,AX ; Advance sector number | ||
| 1150 | MOV AX,Fixed.NumBytes ; Number of bytes handled | ||
| 1151 | ADD WORD PTR Fixed.RealAddr,AX ; Advance data address | ||
| 1152 | MOV Fixed.State,Calc ; Go to Calc state | ||
| 1153 | fxexj4: JMP FixedExecute | ||
| 1154 | |||
| 1155 | fxxd3: | ||
| 1156 | mov DI,OFFSET Fixed | ||
| 1157 | mov SI,OFFSET FixedQueue ; DS:SI = head of queue | ||
| 1158 | call DoneRequest | ||
| 1159 | JMP fxexj4 | ||
| 1160 | |||
| 1161 | |||
| 1162 | ;* Fixed state Idle | ||
| 1163 | ; | ||
| 1164 | ; Nothing hapenning, become inactive. | ||
| 1165 | |||
| 1166 | FxExIdle: | ||
| 1167 | and Fixed.Flags,NOT Factive | ||
| 1168 | RET | ||
| 1169 | |||
| 1170 | |||
| 1171 | ;* Fixed state Error | ||
| 1172 | ; | ||
| 1173 | ; Entered when a non-recoverable error is detected. | ||
| 1174 | ; A sense block has been requested and put into the | ||
| 1175 | ; DCB. | ||
| 1176 | |||
| 1177 | FxExError: | ||
| 1178 | MOV Fixed.State,Done ; Request is done | ||
| 1179 | ; Set error bits in request packet | ||
| 1180 | MOV AL,Fixed.DCB ; Get status byte | ||
| 1181 | mov bl,al ; isolate error type as word address | ||
| 1182 | and bx,0030h | ||
| 1183 | mov cl,3 | ||
| 1184 | shr bx,cl | ||
| 1185 | mov bx,HDErrType[BX] ; index into error table by type | ||
| 1186 | and ax,0Fh ; get error code | ||
| 1187 | cmp al,ds:[bx] ; outside range of table? | ||
| 1188 | jae fxxe1 | ||
| 1189 | add bx,ax | ||
| 1190 | mov ah,ds:[bx+1] ; translate error code | ||
| 1191 | jmp SHORT fxxe2 | ||
| 1192 | fxxe1: | ||
| 1193 | mov ah,12 | ||
| 1194 | fxxe2: dbbeg 8,4 | ||
| 1195 | mov di,OFFSET Fixed.DCB | ||
| 1196 | debug 8,4,<HD error: sense $b$b$b$b code $x\n>,<<[di]>,<[di+1]>,<[di+2]>,<[di+3]>,ax> | ||
| 1197 | dbend | ||
| 1198 | endif | ||
| 1199 | PUSH ES | ||
| 1200 | LES DI,FixedQueue ; Get ptr to request | ||
| 1201 | MOV AL,ah | ||
| 1202 | MOV AH,10000001B | ||
| 1203 | MOV ES:[DI].RqStatus,AX ; Set error and code | ||
| 1204 | POP ES | ||
| 1205 | JMP fxxd3 ; Advance to Done state | ||
| 1206 | FixedExecute ENDP | ||
| 1207 | |||
| 1208 | ;* Traslation of controller error codes to DOS error codes | ||
| 1209 | |||
| 1210 | HDErrType DW HDErrTyp0 | ||
| 1211 | DW HDErrTyp1 | ||
| 1212 | DW HDErrTyp2 | ||
| 1213 | DW HDErrTyp3 | ||
| 1214 | |||
| 1215 | HDErrTyp0 DB 9, 12, 2, 6,10, 2,12, 6,12, 6 | ||
| 1216 | HDErrTyp1 DB 10, 4, 4, 8,12, 8, 6,12,12, 4, 6 | ||
| 1217 | HDErrTyp2 DB 2, 3, 8 | ||
| 1218 | HDErrTyp3 DB 3, 4, 4, 4 | ||
| 1219 | |||
| 1220 | ASSUME CS:BiosSeg,DS:NOTHING,ES:NOTHING | ||
| 1221 | |||
| 1222 | FixedInterrupt PROC FAR | ||
| 1223 | debug 8,8,<FxIntr\n>,<> | ||
| 1224 | cmp word [SemDiskIO],0001h | ||
| 1225 | jnz fxinot13 | ||
| 1226 | cmp SemInt13,0 ; If a direct Int13 request is being | ||
| 1227 | jz fxinot13 ; made call the ROM floppy interrupt | ||
| 1228 | cmp SemDiskIO,0 ; routine to handle it. | ||
| 1229 | jnz fxinot13 | ||
| 1230 | int int_savregs | ||
| 1231 | ;; in al,21H ; Mask fixed disk interrupts | ||
| 1232 | ;; or al,20h | ||
| 1233 | ;; out 21H,al | ||
| 1234 | pushf | ||
| 1235 | call dword ptr [OldIntDVec] | ||
| 1236 | in al,21H ; Unmask fixed disk interrupts | ||
| 1237 | and al,0DFH | ||
| 1238 | out 21H,al | ||
| 1239 | mov dx,HD_PMSK ; set interrupt and DMA mask bits | ||
| 1240 | mov al,3 | ||
| 1241 | out dx,al | ||
| 1242 | iret | ||
| 1243 | fxinot13: | ||
| 1244 | TEST Fixed.Flags,Factive ; device active? | ||
| 1245 | JZ fxinret ; no, go away | ||
| 1246 | INT int_savregs ; save registers | ||
| 1247 | mov dx,HD_PDAT | ||
| 1248 | in al,dx ; get status reg. | ||
| 1249 | ;; mov ah,al | ||
| 1250 | ;; mov dx,HD_PMSK | ||
| 1251 | ;; xor al,al | ||
| 1252 | ;; out dx,al ; turn off intr. and DMA. | ||
| 1253 | ;; test ah,02h ; error bit set? | ||
| 1254 | test al,02h ; error bit set? | ||
| 1255 | jz fxin4 ; no | ||
| 1256 | ;* error occurred. see if retry, else get error code. | ||
| 1257 | push cs | ||
| 1258 | pop ds | ||
| 1259 | ASSUME ds:BiosSeg | ||
| 1260 | CMP Fixed.ErrCnt,ErrLim ; Reach error limit? | ||
| 1261 | JAE fxin0 ; Yes, request fails | ||
| 1262 | INC Fixed.ErrCnt ; We are doing another try | ||
| 1263 | MOV Fixed.State,Start ; Restart the request | ||
| 1264 | JMP fxin4 | ||
| 1265 | fxin0: mov Fixed.DCB,HD_CSENS ; send sense command | ||
| 1266 | xor al,al ; reset intr. & DMA masks | ||
| 1267 | call HDCommand | ||
| 1268 | push cs | ||
| 1269 | pop es | ||
| 1270 | mov di,OFFSET Fixed.DCB | ||
| 1271 | mov cx,5 | ||
| 1272 | fxin1: call HDWaitReq ; get the sense block back | ||
| 1273 | mov dx,HD_PDAT | ||
| 1274 | in al,dx | ||
| 1275 | stosb | ||
| 1276 | loop fxin1 | ||
| 1277 | mov Fixed.State,Error | ||
| 1278 | |||
| 1279 | ASSUME ds:NOTHING | ||
| 1280 | fxin4: CALL FixedExecute | ||
| 1281 | fxinret: push ax | ||
| 1282 | MOV AL,20H ; send EOI to 8259 | ||
| 1283 | OUT 20H,AL | ||
| 1284 | pop ax | ||
| 1285 | IRET | ||
| 1286 | FixedInterrupt ENDP | ||
| 1287 | |||
| 1288 | SUBTTL Floppy disk startup routine | ||
| 1289 | PAGE + | ||
| 1290 | |||
| 1291 | ; FloppyExecute processes a disk request after it has been set up. | ||
| 1292 | ; When the disk is inactive (State = Idle), it is called to start | ||
| 1293 | ; the device. For all subsequent events, it is called on the disk | ||
| 1294 | ; interrupt which signaled the completion of that subfunction. | ||
| 1295 | ; Some states do not involve waiting for an interrupt to occur. | ||
| 1296 | ; This routine runs entirely off the 'Floppy' data structure | ||
| 1297 | |||
| 1298 | FloppyDispatch LABEL WORD | ||
| 1299 | DW FlExStart | ||
| 1300 | DW FlExCalc | ||
| 1301 | DW FlExSelect | ||
| 1302 | DW FlExRecal | ||
| 1303 | DW FlExSeek | ||
| 1304 | DW FlExSettle | ||
| 1305 | DW FlExRdWri | ||
| 1306 | DW FlExDone | ||
| 1307 | DW FlExIdle | ||
| 1308 | DW FlExError | ||
| 1309 | |||
| 1310 | FloppyExecute PROC | ||
| 1311 | push cs ; CS -> DS | ||
| 1312 | pop ds | ||
| 1313 | ASSUME DS:BiosSeg | ||
| 1314 | MOV BX,Floppy.State ; Get current state | ||
| 1315 | debug 4,4,<FlEx state $d >,<bx> | ||
| 1316 | ADD BX,BX | ||
| 1317 | JMP FloppyDispatch[BX] ; Dispatch to correct routine | ||
| 1318 | |||
| 1319 | |||
| 1320 | ;* Floppy state Start | ||
| 1321 | ; | ||
| 1322 | ; Do setup calculations to figure out sector, start | ||
| 1323 | ; up motor, advance to Calc state. | ||
| 1324 | ; | ||
| 1325 | ; Entered on initially picking up a new request to do and on error retries. | ||
| 1326 | ; If error retries start here, then multiple sector requests will always start | ||
| 1327 | ; at the beginning rather than at the point of the error! Why? | ||
| 1328 | |||
| 1329 | FlExStart: | ||
| 1330 | mov si,OFFSET Floppy ; SI = pointer to per-device info. | ||
| 1331 | les bx,FloppyQueue ; ES:BX = pointer to current request | ||
| 1332 | mov al,es:[bx].RqUnit | ||
| 1333 | mov ah,es:[bx].RqMedia | ||
| 1334 | call FDGetBPB ; DI = drive parameters | ||
| 1335 | CALL Setup ; Do setup calculations | ||
| 1336 | MOV DX,FD_PCMD | ||
| 1337 | MOV AL,Rate44 | ||
| 1338 | OUT DX,AL ; Set step rate | ||
| 1339 | MOV Floppy.State,Calc ; Advance to next state | ||
| 1340 | flexj1: JMP FloppyExecute ; Now return to do Calc code | ||
| 1341 | |||
| 1342 | |||
| 1343 | |||
| 1344 | ;* Floppy state Calc | ||
| 1345 | ; | ||
| 1346 | ; Calculate cylinder, head and sector, wait for motor | ||
| 1347 | ; start or head load, advance to Select state. | ||
| 1348 | ; | ||
| 1349 | ; Entered after Start state and also on further sectors of a multiple sector | ||
| 1350 | ; request. | ||
| 1351 | |||
| 1352 | FlExCalc: | ||
| 1353 | mov si,OFFSET Floppy ; SI = pointer to per-device info. | ||
| 1354 | les bx,FloppyQueue ; ES:BX = pointer to current request | ||
| 1355 | mov al,es:[bx].RqUnit | ||
| 1356 | mov ah,es:[bx].RqMedia | ||
| 1357 | call FDGetBPB ; DI = drive parameters | ||
| 1358 | CALL MapSector ; Get head, cylinder and sector | ||
| 1359 | MOV Floppy.State,Select ; Will advance to Select state | ||
| 1360 | CALL Sel765 ; Select the drive and maybe wait | ||
| 1361 | JNC FloppyExecute ; Did select with no waiting | ||
| 1362 | RET ; Have set a timer, get out | ||
| 1363 | |||
| 1364 | |||
| 1365 | |||
| 1366 | ;* Floppy state Select | ||
| 1367 | ; | ||
| 1368 | ; Recalibrate the drive if needed. If Seek is | ||
| 1369 | ; needed, start it and advance to Seek state. Otherwise advance to Settle | ||
| 1370 | ; state. | ||
| 1371 | |||
| 1372 | FlExSelect: | ||
| 1373 | call GetDrivePtr | ||
| 1374 | OR [BX].DrvFlag,Fmotoron ; we've been selected, so motor is on | ||
| 1375 | TEST [BX].DrvFlag,Frestor ; Is a restore needed? | ||
| 1376 | JE NoRestore ; No | ||
| 1377 | call SetTimer2 ; set a sanity/motor stop timer | ||
| 1378 | MOV Floppy.State,Recal ; Next state will be recalibrate | ||
| 1379 | CALL Rcl765 ; Start the recalibrate | ||
| 1380 | RET ; Done until floppy interrupt arrives | ||
| 1381 | |||
| 1382 | NoRestore: ; Start the seek if any | ||
| 1383 | CALL Seek765 ; Start the seek to cylinder | ||
| 1384 | JNC SeekOK ; Already on correct cylinder | ||
| 1385 | MOV Floppy.State,Seek ; Next state is Seek | ||
| 1386 | call GetDrivePtr | ||
| 1387 | call SetTimer2 ; set sanity timer | ||
| 1388 | RET ; Done until interrupt on seek done | ||
| 1389 | |||
| 1390 | |||
| 1391 | |||
| 1392 | ;* Floppy state Recal | ||
| 1393 | ; | ||
| 1394 | ; If error, set state is Error. Else, load drive | ||
| 1395 | ; specs into controller and advance to Select state. | ||
| 1396 | |||
| 1397 | FlExRecal: | ||
| 1398 | CALL Sense765 | ||
| 1399 | OR AX,AX ; Error in recal? | ||
| 1400 | JNZ SeekErr ; Yes | ||
| 1401 | RecalOK: | ||
| 1402 | CALL Spec765 ; Load drive specs | ||
| 1403 | MOV Floppy.State,Select ; Back to select state now | ||
| 1404 | flexj2: JMP flexj1 | ||
| 1405 | |||
| 1406 | |||
| 1407 | |||
| 1408 | ;* Floppy state Seek | ||
| 1409 | ; | ||
| 1410 | ; If error, advance to Error state. Otherwise, wait | ||
| 1411 | ; for head to settle and advance to Settle state. | ||
| 1412 | |||
| 1413 | FlExSeek: | ||
| 1414 | CALL Sense765 ; Get status of seek | ||
| 1415 | OR AX,AX ; Any error? | ||
| 1416 | JZ SeekOK ; No | ||
| 1417 | SeekErr: | ||
| 1418 | CALL GetDrivePtr | ||
| 1419 | OR [BX].DrvFlag,Frestor ; flag restore needed | ||
| 1420 | MOV Floppy.State,Error ; Yes, next state is Error | ||
| 1421 | or Floppy.ST1,8 ; indicate seek error in an unused bit | ||
| 1422 | JMP flexj2 | ||
| 1423 | |||
| 1424 | SeekOK: | ||
| 1425 | MOV Floppy.State,Settle ; Next state is Settle | ||
| 1426 | MOV AL,DelaySettle | ||
| 1427 | CALL GetFloppyParam ; Get the settle time in Msecs | ||
| 1428 | xor ah,ah | ||
| 1429 | CALL SetTimer1 ; Set the timer | ||
| 1430 | JNC flexj2 | ||
| 1431 | RET | ||
| 1432 | |||
| 1433 | |||
| 1434 | |||
| 1435 | ;* Floppy state Settle | ||
| 1436 | ; | ||
| 1437 | ; Start the read/write request and advance to the RdWri state. | ||
| 1438 | |||
| 1439 | FlExSettle: | ||
| 1440 | MOV Floppy.State,RdWri ; Advance to read/write state | ||
| 1441 | CALL RdWr765 ; Start the I/O | ||
| 1442 | call GetDrivePtr | ||
| 1443 | call SetTimer2 ; set sanity timer | ||
| 1444 | RET ; Done until floppy interrupt | ||
| 1445 | |||
| 1446 | |||
| 1447 | |||
| 1448 | ;* Floppy state RdWri | ||
| 1449 | ; | ||
| 1450 | ; If error, next state is Error. Otherwise next state is Done. | ||
| 1451 | |||
| 1452 | FlExRdWri: | ||
| 1453 | CALL Fini765 ; Get status of I/O | ||
| 1454 | OR AX,AX ; Any error? | ||
| 1455 | JZ RdWriOK ; No | ||
| 1456 | MOV Floppy.State,Error ; Yes, go to error state | ||
| 1457 | JMP flexj2 | ||
| 1458 | |||
| 1459 | RdWriOK: | ||
| 1460 | MOV Floppy.State,Done ; I/O is done | ||
| 1461 | flexj3: JMP flexj2 | ||
| 1462 | |||
| 1463 | |||
| 1464 | |||
| 1465 | ;* Floppy state Done | ||
| 1466 | ; | ||
| 1467 | ; If whole request is now complete, mark the request | ||
| 1468 | ; as done and then start the next one if there is one. If the request is not | ||
| 1469 | ; yet done, adjust values to show the amount of the request done and then go | ||
| 1470 | ; back to the Calc state to do next part. | ||
| 1471 | |||
| 1472 | FlExDone: | ||
| 1473 | MOV AL,Floppy.Flags | ||
| 1474 | AND AL,Fwrite+Fverify+Fwrap1 ; Only interested in these bits | ||
| 1475 | CMP AL,Fwrap1 ; Just read into scratch? | ||
| 1476 | JNE DoneNotWrap ; No | ||
| 1477 | PUSH DS | ||
| 1478 | PUSH ES | ||
| 1479 | MOV CX,Floppy.NumBytes ; CS = # bytes to write from scr | ||
| 1480 | LES DI,Floppy.RealAddr ; ES:DI = real buffer | ||
| 1481 | LDS SI,Floppy.Addr ; DS:SI = scratch buffer | ||
| 1482 | CLD | ||
| 1483 | REP MOVSB ; Copy into real buffer | ||
| 1484 | POP ES | ||
| 1485 | POP DS | ||
| 1486 | DoneNotWrap: | ||
| 1487 | AND AL,Fwrite+Fverify ; Just want to see these bits | ||
| 1488 | CMP AL,Fwrite+Fverify ; Just do write part of write+verify? | ||
| 1489 | JNE DoneNotWritePart ; No | ||
| 1490 | AND Floppy.Flags,NOT Fwrite ; Yes, do verify next | ||
| 1491 | mov Floppy.State,Settle ; don't need to calc or seek | ||
| 1492 | jmp flexj3 | ||
| 1493 | |||
| 1494 | DoneNotWritePart: | ||
| 1495 | CMP AL,Fverify ; Just do verify part of write+verify? | ||
| 1496 | JNE DoneNotVerify ; No | ||
| 1497 | OR Floppy.Flags,Fwrite ; Yes, flip write back up for next | ||
| 1498 | DoneNotVerify: | ||
| 1499 | MOV AX,Floppy.NumSectors ; AX = # of sectors we did | ||
| 1500 | SUB Floppy.Count,AX ; Adjust count to number left | ||
| 1501 | JZ flxd3 ; Request is done, tell DOS | ||
| 1502 | ADD Floppy.First,AX ; Advance sector number | ||
| 1503 | MOV AX,Floppy.NumBytes ; Number of bytes handled | ||
| 1504 | ADD WORD PTR Floppy.RealAddr,AX ; Advance data address | ||
| 1505 | MOV Floppy.State,Calc ; Go to Calc state | ||
| 1506 | flexj4: JMP flexj3 | ||
| 1507 | |||
| 1508 | flxd3: | ||
| 1509 | mov di,OFFSET Floppy | ||
| 1510 | mov SI,OFFSET FloppyQueue ; DS:SI = head of floppy queue | ||
| 1511 | call DoneRequest | ||
| 1512 | JMP flexj4 | ||
| 1513 | |||
| 1514 | |||
| 1515 | ;* Floppy state Idle | ||
| 1516 | ; | ||
| 1517 | ; Nothing hapenning except possible motor off timeout. | ||
| 1518 | |||
| 1519 | FlExIdle: | ||
| 1520 | call GetDrivePtr | ||
| 1521 | CALL SetTimer2 ; Set the motor timer | ||
| 1522 | and Floppy.Flags,NOT Factive | ||
| 1523 | SemSig SwapSem2 ; someone waiting to switch drive? | ||
| 1524 | RET | ||
| 1525 | |||
| 1526 | |||
| 1527 | ;* Floppy state Error | ||
| 1528 | ; | ||
| 1529 | ; If error count not exceeded, restore the drive and start | ||
| 1530 | ; the request over again. Otherwise set error in the packet and | ||
| 1531 | ; advance to the Done state. | ||
| 1532 | |||
| 1533 | FlExError: | ||
| 1534 | CALL Rst765 ; Reset the controller | ||
| 1535 | CMP Floppy.ErrCnt,ErrLim ; Reach error limit? | ||
| 1536 | JAE FloppyFails ; Yes, request fails | ||
| 1537 | INC Floppy.ErrCnt ; We are doing another try | ||
| 1538 | MOV Floppy.State,Start ; Restart the request | ||
| 1539 | JMP flexj4 ; Back to state machine loop | ||
| 1540 | |||
| 1541 | FloppyFails: | ||
| 1542 | call GetDrivePtr | ||
| 1543 | OR CS:[BX].DrvFlag,Frestor ; Set drive needs a restore | ||
| 1544 | MOV Floppy.State,Done ; Request is done | ||
| 1545 | ; Set error bits in request packet | ||
| 1546 | MOV AX, WORD PTR Floppy.ST0 ; Get ST0, ST1 | ||
| 1547 | mov BL,2 ; Drive not ready? | ||
| 1548 | test AL,0cH | ||
| 1549 | jne ErrorFound | ||
| 1550 | MOV BL,6 ; Bad seek? | ||
| 1551 | TEST AH,8 | ||
| 1552 | JNE ErrorFound | ||
| 1553 | MOV BL,4 ; CRC error? | ||
| 1554 | TEST AH,30H | ||
| 1555 | JNE ErrorFound | ||
| 1556 | MOV BL,8 ; Sector not found? | ||
| 1557 | TEST AH,85H | ||
| 1558 | JNE ErrorFound | ||
| 1559 | MOV BL,0 ; Write protect? | ||
| 1560 | TEST AH,2 | ||
| 1561 | JNE ErrorFound | ||
| 1562 | MOV BL,12 ; Catch-all error | ||
| 1563 | ErrorFound: | ||
| 1564 | debug 4,4,<FD error: status $x code $b\n>,<ax,bx> | ||
| 1565 | PUSH ES | ||
| 1566 | LES DI,FloppyQueue ; Get ptr to request | ||
| 1567 | MOV AL,BL | ||
| 1568 | MOV AH,10000001B | ||
| 1569 | MOV ES:[DI].RqStatus,AX ; Set error and code | ||
| 1570 | POP ES | ||
| 1571 | JMP flxd3 ; Advance to Done state (via shortcut) | ||
| 1572 | |||
| 1573 | FloppyExecute ENDP | ||
| 1574 | |||
| 1575 | |||
| 1576 | ASSUME CS:BiosSeg,DS:NOTHING,ES:NOTHING | ||
| 1577 | |||
| 1578 | FloppyInterrupt PROC FAR | ||
| 1579 | debug 4,8,<FlIntr\n>,<> | ||
| 1580 | cmp SemInt13,0 ; If a direct Int13 request is being | ||
| 1581 | jz flinot13 ; made call the ROM floppy interrupt | ||
| 1582 | cmp SemDiskIO,0 ; routine to handle it. | ||
| 1583 | jnz flinot13 | ||
| 1584 | int int_savregs | ||
| 1585 | pushf | ||
| 1586 | call dword ptr [OldIntEVec] | ||
| 1587 | iret | ||
| 1588 | flinot13: | ||
| 1589 | TEST Floppy.Flags,Factive ; device active? | ||
| 1590 | JZ flinret ; no, go away | ||
| 1591 | INT int_savregs ; save registers | ||
| 1592 | CALL FloppyExecute | ||
| 1593 | flinret: push ax | ||
| 1594 | MOV AL,20H ; send EOI to 8259 | ||
| 1595 | OUT 20H,AL | ||
| 1596 | pop ax | ||
| 1597 | IRET | ||
| 1598 | FloppyInterrupt ENDP | ||
| 1599 | |||
| 1600 | SUBTTL Timing routines for floppy disk | ||
| 1601 | PAGE + | ||
| 1602 | |||
| 1603 | ;* Data for timers | ||
| 1604 | TimerActive DB 0 ; bit flags for active timers | ||
| 1605 | TimerConv DB 50 ; conversion factor for ms => ticks | ||
| 1606 | Timer1 DB 0 ; One-shot time till restart intr. rtn. | ||
| 1607 | Timer2 DB 0 ; Repetitive 1 Hz timer | ||
| 1608 | Timer2count = 20 ; Reload value for timer2 | ||
| 1609 | |||
| 1610 | MOFFDELAY= 2 ; turn off motor after 2 sec. inactivity | ||
| 1611 | |||
| 1612 | ;*** SetTimer1 - Arm timer 1 | ||
| 1613 | ; | ||
| 1614 | ; SetTimer1 will arm the Timer1. Input parameter | ||
| 1615 | ; values in milliseconds will be converted to timer | ||
| 1616 | ; ticks. | ||
| 1617 | ; | ||
| 1618 | ; ENTRY AX = delay value in milliseconds | ||
| 1619 | ; EXIT AL = timer ticks | ||
| 1620 | ; CF set if timer armed | ||
| 1621 | ; CF clear if zero count passed | ||
| 1622 | ; USES AX | ||
| 1623 | |||
| 1624 | SetTimer1 PROC | ||
| 1625 | TEST AX,AX ; zero count? | ||
| 1626 | JNZ sett10 ; no | ||
| 1627 | CLC | ||
| 1628 | RET | ||
| 1629 | |||
| 1630 | sett10: DIV TimerConv | ||
| 1631 | TEST AH,AH ; remainder? | ||
| 1632 | JZ sett11 | ||
| 1633 | INC AL ; yes, round up | ||
| 1634 | sett11: MOV Timer1,AL | ||
| 1635 | OR TimerActive,1 | ||
| 1636 | debug 4,8,<SetTimer1 $b\n>,<ax> | ||
| 1637 | STC | ||
| 1638 | RET | ||
| 1639 | SetTimer1 ENDP | ||
| 1640 | |||
| 1641 | ;*** SetTimer2 - Arm timer 2 | ||
| 1642 | ; | ||
| 1643 | ; SetTimer2 will set a motor off timeout for the | ||
| 1644 | ; drive whose parameter block is pointed to by | ||
| 1645 | ; CS:BX | ||
| 1646 | ; | ||
| 1647 | ; ENTRY CS:BX = pointer to per drive info. | ||
| 1648 | ; EXIT | ||
| 1649 | ; USES NONE | ||
| 1650 | |||
| 1651 | SetTimer2 PROC | ||
| 1652 | TEST TimerActive,2 | ||
| 1653 | JNZ sett21 | ||
| 1654 | MOV Timer2,Timer2Count | ||
| 1655 | OR TimerActive,2 | ||
| 1656 | sett21: MOV CS:[BX].Timer,MOFFDELAY | ||
| 1657 | debug 4,8,<SetTimer2\n>,<> | ||
| 1658 | RET | ||
| 1659 | SetTimer2 ENDP | ||
| 1660 | |||
| 1661 | |||
| 1662 | |||
| 1663 | ; FloppyTimer is called every scheduler tick to perform | ||
| 1664 | ; time related services for the floppy driver. There are | ||
| 1665 | ; two services performed; rescheduling of interrupt time | ||
| 1666 | ; service after a head load or motor startup delay, and | ||
| 1667 | ; a motor turn off service when a drive is not active. | ||
| 1668 | ; | ||
| 1669 | ; It's assumed that all registers have been saved by the | ||
| 1670 | ; caller. | ||
| 1671 | |||
| 1672 | ASSUME CS:BiosSeg,DS:NOTHING,ES:NOTHING | ||
| 1673 | |||
| 1674 | PUBLIC FloppyTimer | ||
| 1675 | FloppyTimer PROC FAR | ||
| 1676 | TEST TimerActive,0ffH ; any timers active? | ||
| 1677 | JNZ fltim1 ; yes | ||
| 1678 | RET ; no, return quickly | ||
| 1679 | fltim1: TEST TimerActive,1 ; Timer1 active? | ||
| 1680 | JZ fltim3 ; no | ||
| 1681 | DEC Timer1 ; Timer1 expired? | ||
| 1682 | JNZ fltim3 ; no | ||
| 1683 | ;* Perform Timer1 service | ||
| 1684 | debug 4,8,<Timer 1 expired\n>,<> | ||
| 1685 | AND TimerActive,NOT 1 | ||
| 1686 | CALL FloppyExecute ; push the states around a while | ||
| 1687 | RET ; don't do Timer2 service this time. | ||
| 1688 | |||
| 1689 | fltim3: TEST TimerActive,2 ; Timer2 active? | ||
| 1690 | JZ fltim4 ; no | ||
| 1691 | DEC Timer2 ; 1 Hz clock time? | ||
| 1692 | JZ fltim5 ; no | ||
| 1693 | fltim4: JMP fltim9 | ||
| 1694 | fltim5: | ||
| 1695 | debug 4,8,<Timer 2 expired\n>,<> | ||
| 1696 | MOV BL,Timer2count ; reload the counter | ||
| 1697 | MOV Timer2,BL | ||
| 1698 | |||
| 1699 | ;* Perform Timer2 service | ||
| 1700 | XOR CH,CH ; No active timeouts seen | ||
| 1701 | XOR DI,DI ; Start with drive A | ||
| 1702 | TimeOutLoop: | ||
| 1703 | MOV BX,DI | ||
| 1704 | ADD BX,BX | ||
| 1705 | MOV BX,FDinfo[BX] ; Get ptr to drive info | ||
| 1706 | TEST CS:[BX].DrvFlag,Fmotoron ; motor on? | ||
| 1707 | JZ fltim8 ; no | ||
| 1708 | CMP CS:[BX].Timer,0 ; Is timer active for drive? | ||
| 1709 | JZ fltim8 ; No | ||
| 1710 | DEC CS:[BX].Timer ; Yes, another tick has passed | ||
| 1711 | JNZ fltim7 | ||
| 1712 | cmp di,Floppy.Current ; Current drive? | ||
| 1713 | jnz fltim6 ; no | ||
| 1714 | test Floppy.Flags,Factive ; device active? | ||
| 1715 | jz fltim6 ; no, go ahead | ||
| 1716 | mov Floppy.State,Error | ||
| 1717 | mov Floppy.ErrCnt,ErrLim ; don't retry this one | ||
| 1718 | mov Floppy.ST0,048H ; set not ready error | ||
| 1719 | call FloppyExecute ; oops, sanity timeout | ||
| 1720 | jmp fltim9 | ||
| 1721 | fltim6: | ||
| 1722 | AND CS:[BX].DrvFlag,NOT Fmotoron ; stop drive motor | ||
| 1723 | MOV AX,DI | ||
| 1724 | MOV CL,AL | ||
| 1725 | ADD CL,4 | ||
| 1726 | MOV AL,1 | ||
| 1727 | SHL AL,CL ; Get bit mask for motor on | ||
| 1728 | TEST Floppy.DOR,AL ; Is motor already off? | ||
| 1729 | JE fltim8 ; Yes, go on to next drive | ||
| 1730 | NOT AL ; Get all bits except this motor | ||
| 1731 | AND Floppy.DOR,AL ; Clear this motor on | ||
| 1732 | MOV DX,FD_PSEL | ||
| 1733 | MOV AL,Floppy.DOR | ||
| 1734 | OUT DX,AL ; Turn off motor | ||
| 1735 | ;; cmp di,Floppy.Current ; Current drive? | ||
| 1736 | ;; jnz fltim8 ; no | ||
| 1737 | ;; test Floppy.Flags,Factive ; device active | ||
| 1738 | ;; jz fltim8 ; no, go on to next drive | ||
| 1739 | ;; call DumpRegs ; oops, sanity timeout | ||
| 1740 | |||
| 1741 | fltim7: INC CH ; Flag still active | ||
| 1742 | fltim8: INC DI ; Advance to next drive | ||
| 1743 | CMP DI,WORD PTR NumFloppy ; Any more to check? | ||
| 1744 | JNE TimeOutLoop ; Yes, do them | ||
| 1745 | OR CH,CH ; Need to keep timer active? | ||
| 1746 | JNZ fltim9 ; Yes | ||
| 1747 | AND TimerActive,NOT 2 ; No, clear timeout is active | ||
| 1748 | fltim9: RET | ||
| 1749 | |||
| 1750 | FloppyTimer ENDP | ||
| 1751 | |||
| 1752 | |||
| 1753 | IFDEF DEBUGFLG | ||
| 1754 | DumpRegs PROC | ||
| 1755 | push cs | ||
| 1756 | pop ds | ||
| 1757 | debug 4,0fh,<Sanity Timeout!!\n>,<> | ||
| 1758 | mov di,OFFSET Floppy | ||
| 1759 | debug 4,0fh,<Floppy struct\n $x $x $x $x $x $x $x $x\n>,<[di],[di.2],[di.4],[di.6],[di.8],[di.10],[di.12],[di.14]> | ||
| 1760 | debug 4,0fh,< $x $x $x $x $x $x $x $x\n>,<[di.10h],[di.12h],[di.14h],[di.16h],[di.18h],[di.1ah],[di.1ch],[di.1eh]> | ||
| 1761 | call GetDrivePtr | ||
| 1762 | debug 4,0fh,<Drive struct\n $x $x $x $x $x $x $x $x\n>,<[bx],[bx.2],[bx.4],[bx.6],[bx.8],[bx.10],[bx.12],[bx.14]> | ||
| 1763 | debug 4,0fh,< $x $x $x $x\n>,<[bx.16],[bx.18],[bx.20],[bx.22]> | ||
| 1764 | debug 4,0fh,< IMR IRR ISR 8259 status\n>,<> | ||
| 1765 | mov al,0ah | ||
| 1766 | out 20h,al | ||
| 1767 | in al,20h | ||
| 1768 | mov bl,al | ||
| 1769 | |||
| 1770 | mov al,0bh | ||
| 1771 | out 20h,al | ||
| 1772 | in al,20h | ||
| 1773 | mov cl,al | ||
| 1774 | in al,21h | ||
| 1775 | debug 4,0fh,< $b $b $b\n>,<ax,bx,cx> | ||
| 1776 | debug 4,0fh,<765 status, data\n>,<> | ||
| 1777 | mov dx,FD_PSTAT | ||
| 1778 | in al,dx | ||
| 1779 | mov bl,al | ||
| 1780 | mov dx,FD_PDAT | ||
| 1781 | in al,dx | ||
| 1782 | debug 4,0fh,< $b $b\n>,<bx,ax> | ||
| 1783 | sti | ||
| 1784 | dmpr0: jmp dmpr0 | ||
| 1785 | DumpRegs ENDP | ||
| 1786 | ENDIF ;DEUBGFLAG | ||
| 1787 | |||
| 1788 | SUBTTL Routines shared between Floppy and Hard disk drivers | ||
| 1789 | PAGE + | ||
| 1790 | |||
| 1791 | ;*** Setup - Set request parameters into local structure. | ||
| 1792 | ; | ||
| 1793 | ; Setup sets the Unit, First, Addr, Count and Flags fields in the | ||
| 1794 | ; device structure which are used to drive the I/O. The following | ||
| 1795 | ; flags are affected: | ||
| 1796 | ; Fwrite This is a write request, not a read | ||
| 1797 | ; Fverify This is a write with verify (verify when write | ||
| 1798 | ; is cleared). | ||
| 1799 | ; Other fields are copied from the DOS request packet. | ||
| 1800 | ; | ||
| 1801 | ; ENTRY SI Pointer to device variables | ||
| 1802 | ; ES:BX Current request | ||
| 1803 | ; AL Unit number | ||
| 1804 | ; DI BPB for drive | ||
| 1805 | ; DS CS | ||
| 1806 | ; | ||
| 1807 | ; EXIT The following variables are set | ||
| 1808 | ; [SI].Unit | ||
| 1809 | ; [SI].First The hidden sectors are added | ||
| 1810 | ; [SI].RealAddr | ||
| 1811 | ; [SI].Count | ||
| 1812 | ; [SI].Flags | ||
| 1813 | |||
| 1814 | ASSUME CS:BiosSeg,DS:BiosSeg | ||
| 1815 | |||
| 1816 | Setup PROC | ||
| 1817 | MOV AX,ES:[BX].RqCount | ||
| 1818 | MOV [SI].Count,AX ; Set number of sectors to do | ||
| 1819 | MOV AX,ES:[BX].RqAddr | ||
| 1820 | MOV WORD PTR [SI].RealAddr,AX | ||
| 1821 | MOV AX,ES:[BX].RqAddr+2 | ||
| 1822 | MOV WORD PTR [SI].RealAddr+2,AX ; Copy data address | ||
| 1823 | MOV AL,ES:[BX].RqUnit ; Get unit number | ||
| 1824 | MOV [SI].Unit,AL ; Set drive needed | ||
| 1825 | MOV AX,ES:[BX].RqFirst ; Get the starting sector number | ||
| 1826 | ADD AX,[DI].BPBhidsec ; Add # of hidden sectors | ||
| 1827 | MOV [SI].First,AX ; Set 1st sector of I/O | ||
| 1828 | and [SI].Flags,Factive+F2step ; mask excess flags | ||
| 1829 | CMP ES:[BX].RqCmd,4 ; Is this a read? | ||
| 1830 | JE SetupDone ; Yes, all done | ||
| 1831 | OR [SI].Flags,Fwrite ; No, flag this is a read | ||
| 1832 | CMP ES:[BX].RqCmd,9 ; Write with verify? | ||
| 1833 | JNE SetupDone ; No, just write | ||
| 1834 | OR [SI].Flags,Fverify ; Yes, set to verify too | ||
| 1835 | SetupDone: | ||
| 1836 | RET | ||
| 1837 | Setup ENDP | ||
| 1838 | |||
| 1839 | |||
| 1840 | ;*** MapSector - compute head, sector, cylinder | ||
| 1841 | ; | ||
| 1842 | ; MapSector takes the fields set up by Setup and figures out the | ||
| 1843 | ; head, cylinder and sector involved. If the request involves | ||
| 1844 | ; multiple sectors, it figures out how many can be done at once | ||
| 1845 | ; based on the number of sectors left on the track and that the | ||
| 1846 | ; target address' offset does not wrap around 64k (the DMA on the | ||
| 1847 | ; PC uses a 20 bit address, but the high 4 bits do not change when | ||
| 1848 | ; the low 16 cycle back to 0). If the request wraps around 64k, it | ||
| 1849 | ; is split into 2 or 3 pieces which are all data before wrap, after | ||
| 1850 | ; wrap and the wrap itself. The wrap itself is transferred via a temp | ||
| 1851 | ; buffer (ScratchBuffer). | ||
| 1852 | ; | ||
| 1853 | ; ENTRY SI Pointer to device variables | ||
| 1854 | ; ES:BX Current request | ||
| 1855 | ; AL Unit number | ||
| 1856 | ; DI BPB for drive | ||
| 1857 | ; DS CS | ||
| 1858 | ; EXIT The following variables are set | ||
| 1859 | ; [SI].Flags | ||
| 1860 | ; [SI].Head | ||
| 1861 | ; [SI].Cyl | ||
| 1862 | ; [SI].Sector | ||
| 1863 | ; [SI].NumSectors | ||
| 1864 | ; [SI].NumBytes | ||
| 1865 | ; [SI].Addr | ||
| 1866 | ; USES AX,CX,DX,DI | ||
| 1867 | ; | ||
| 1868 | |||
| 1869 | MapSector PROC | ||
| 1870 | PUSH ES | ||
| 1871 | les CX,[SI].RealAddr | ||
| 1872 | MOV WORD PTR [SI].Addr,CX ; copy RealAddr to Addr | ||
| 1873 | MOV WORD PTR [SI].Addr+2,ES | ||
| 1874 | AND [SI].Flags,NOT Fwrap1 ; Clear buffer wrap flag | ||
| 1875 | |||
| 1876 | ; Calculate the head, cylinder and sector of the start of the request | ||
| 1877 | ; from [SI].First | ||
| 1878 | POP ES | ||
| 1879 | MOV AX,[SI].First | ||
| 1880 | XOR DX,DX | ||
| 1881 | DIV [DI].BPBtrksiz ; Divide by sectors/track | ||
| 1882 | ;; INC DL | ||
| 1883 | MOV [SI].Sector,DL ; Set sector to start at | ||
| 1884 | XOR DX,DX | ||
| 1885 | DIV [DI].BPBnhead ; Divide by number of heads | ||
| 1886 | MOV [SI].Head,DL ; Set head number | ||
| 1887 | MOV [SI].Cyl,AX ; Set cylinder number | ||
| 1888 | debug 8,4,<Cyl $d Hd $b Sec $b >,<ax,dx,<word ptr [SI].Sector>> | ||
| 1889 | ; | ||
| 1890 | ; Now see how many sectors of request can be done. The floppy | ||
| 1891 | ; controller will not advance tracks, but will allow reading or | ||
| 1892 | ; writing the remaining sectors on the track. | ||
| 1893 | ; | ||
| 1894 | MOV AX,[DI].BPBtrksiz | ||
| 1895 | SUB AL,[SI].Sector ; AL = # of sectors left on | ||
| 1896 | ; track after desired. | ||
| 1897 | XOR AH,AH | ||
| 1898 | ;; inc ax | ||
| 1899 | CMP AX,[SI].Count ; Is whole request on this cyl? | ||
| 1900 | JB maps2 ; No, can only do what is left | ||
| 1901 | MOV AX,[SI].Count ; Yes, use the actual # wanted | ||
| 1902 | maps2: | ||
| 1903 | MOV [SI].Numsectors,AX ; Set number to do this time | ||
| 1904 | ; | ||
| 1905 | ; Now have to normalize offset (add in paragraph) and then see if adding | ||
| 1906 | ; [SI].Numsectors causes overflow. If it does, DMA will trash memory, so | ||
| 1907 | ; decrement Numsectors and loop. | ||
| 1908 | ; | ||
| 1909 | MOV AX,WORD PTR([SI].Addr+2) | ||
| 1910 | MOV CL,4 | ||
| 1911 | SHL AX,CL ; Convert para to offset | ||
| 1912 | ADD AX,WORD PTR [SI].Addr ; Add in offset | ||
| 1913 | MOV CX,AX ; Save offset of buffer | ||
| 1914 | maps4: | ||
| 1915 | MOV AX,[DI].BPBsecsiz | ||
| 1916 | MUL [SI].NumSectors ; Get # bytes in transfer | ||
| 1917 | MOV [SI].NumBytes,AX ; Set # bytes involved | ||
| 1918 | ADD AX,CX ; Get final offset | ||
| 1919 | JAE maps6 ; No overflow, DMA will be ok | ||
| 1920 | OR [SI].Flags,Fwrap2 ; Flag we will be using scratch | ||
| 1921 | DEC [SI].NumSectors ; Overflow, try using one less | ||
| 1922 | JNZ maps4 | ||
| 1923 | ; | ||
| 1924 | ; If we got here, no sectors can be transferred before the 64K | ||
| 1925 | ; boundary. One sector must be transferred through a scratch buffer. | ||
| 1926 | ; | ||
| 1927 | debug 12,10h,<MapSector $x $x >,<ax,cx> | ||
| 1928 | INC [SI].NumSectors ; Doing 1 sector of I/O | ||
| 1929 | OR [SI].Flags,Fwrap1 ; Flag we are using scratch | ||
| 1930 | MOV AX,CS | ||
| 1931 | MOV DI,OFFSET ScratchBuffer | ||
| 1932 | MOV WORD PTR([SI].Addr),DI | ||
| 1933 | MOV WORD PTR([SI].Addr+2),AX ; Change buffer to scratch | ||
| 1934 | TEST [SI].Flags,Fwrite ; Doing a write? | ||
| 1935 | JE maps6 ; No, All done | ||
| 1936 | PUSH ES | ||
| 1937 | PUSH DS | ||
| 1938 | PUSH SI | ||
| 1939 | MOV ES,AX ; ES:DI = scratch buffer | ||
| 1940 | mov cx,[SI].NumBytes | ||
| 1941 | LDS SI,[SI].RealAddr ; DS:SI = Data buffer | ||
| 1942 | CLD | ||
| 1943 | REP MOVSB ; Copy the write buffer | ||
| 1944 | POP SI | ||
| 1945 | POP DS | ||
| 1946 | POP ES | ||
| 1947 | maps6: | ||
| 1948 | RET | ||
| 1949 | MapSector ENDP | ||
| 1950 | |||
| 1951 | |||
| 1952 | |||
| 1953 | |||
| 1954 | ;*** DMAsetup - Set the DMA channel up to do the I/O | ||
| 1955 | ; | ||
| 1956 | ; ENTRY AL = DMA mode | ||
| 1957 | ; AH = DMA channel number (2 or 3 only) | ||
| 1958 | ; SI = pointer to device parameters | ||
| 1959 | ; USES AX,CX,DX | ||
| 1960 | ; | ||
| 1961 | |||
| 1962 | DMAsetup PROC | ||
| 1963 | PUSH AX | ||
| 1964 | XCHG AH,AL | ||
| 1965 | OR AL,4 | ||
| 1966 | OUT PDMA+10,AL ; set channel's mask bit | ||
| 1967 | OUT PDMA+12,AL ; clear byte pointer F/F | ||
| 1968 | pop ax | ||
| 1969 | push ax ; restore AH, AL | ||
| 1970 | OR AL,AH ; add channel number to command | ||
| 1971 | OUT PDMA+11,AL ; Set DMA mode | ||
| 1972 | MOV DX,PDMA | ||
| 1973 | ROL AH,1 | ||
| 1974 | ADD DL,AH | ||
| 1975 | MOV AX,WORD PTR [SI].Addr+2 ; Get segment of addr | ||
| 1976 | MOV CL,4 | ||
| 1977 | ROL AX,CL ; Convert para to bytes | ||
| 1978 | MOV CH,AL ; CH = 4 bits ROLed around | ||
| 1979 | AND AL,0F0H ; Lose high bits rotated around | ||
| 1980 | ADD AX,WORD PTR [SI].Addr ; Add in offset value | ||
| 1981 | ADC CH,0 ; Add in any carry | ||
| 1982 | OUT DX,AL ; Output low byte of address | ||
| 1983 | MOV AL,AH | ||
| 1984 | OUT DX,AL ; Output high byte of address | ||
| 1985 | inc dx ; address `word' count register | ||
| 1986 | MOV AX,[SI].NumBytes ; # bytes in request | ||
| 1987 | dec ax | ||
| 1988 | OUT DX,AL | ||
| 1989 | MOV AL,AH | ||
| 1990 | OUT DX,AL ; Tell DMA how many bytes | ||
| 1991 | pop ax ; get back channel number | ||
| 1992 | mov dl,PDMAX | ||
| 1993 | add dl,ah | ||
| 1994 | MOV AL,CH | ||
| 1995 | AND AL,0FH ; Only 4 bits are good | ||
| 1996 | OUT DX,AL ; Output highest 4 bits of address | ||
| 1997 | MOV AL,AH ; Channel to start | ||
| 1998 | OUT PDMA+10,AL ; Clear channel's mask bit | ||
| 1999 | RET | ||
| 2000 | DMAsetup ENDP | ||
| 2001 | |||
| 2002 | ;*** DoneRequest - Mark a request complete, setup to start next one | ||
| 2003 | ; | ||
| 2004 | ; DoneRequest does common processing needed when a request | ||
| 2005 | ; has been completed. It will reset the device state, | ||
| 2006 | ; dequeue the request, mark it complete, restart the | ||
| 2007 | ; process and restart any process waiting on ScratchBuffer | ||
| 2008 | ; if this request had reserved it. | ||
| 2009 | ; | ||
| 2010 | ; ENTRY SI Pointer to head of queue | ||
| 2011 | ; DI Pointer to device information | ||
| 2012 | ; EXIT ES:BX Next request | ||
| 2013 | ; USES AX,BX,DX,BP,ES | ||
| 2014 | |||
| 2015 | |||
| 2016 | DoneRequest PROC | ||
| 2017 | push cs | ||
| 2018 | pop ds | ||
| 2019 | ASSUME ds:BiosSeg | ||
| 2020 | MOV [DI].ErrCnt,0 ; Reset error count | ||
| 2021 | MOV [DI].State,Idle ; Assume will be idle | ||
| 2022 | MOV DX,PullRequest | ||
| 2023 | CALL DosFunction ; Pull the current request out | ||
| 2024 | JZ dnrq2 ; Nothing really completed | ||
| 2025 | MOV AX,[DI].Count ; Get I/O left to do | ||
| 2026 | SUB ES:[BX].RqCount,AX ; Adjust requested count by residual | ||
| 2027 | OR ES:[BX].RqStatus,0100h ; set done bit | ||
| 2028 | MOV AX,ES ; AX:BX = Request completed | ||
| 2029 | MOV DX,ContinueProcess | ||
| 2030 | CALL DosFunction ; Make process run again | ||
| 2031 | CMP WORD PTR [SI]+2,0 ; Is there another request to do? | ||
| 2032 | JZ dnrq2 ; No, let device shut down | ||
| 2033 | MOV [DI].State,Start ; Yes, start up next request | ||
| 2034 | dnrq2: | ||
| 2035 | test [DI].Flags,Fwrap2 ; had this request used ScratchBuffer? | ||
| 2036 | jz dnrq4 ; no | ||
| 2037 | SemSig ScratchBufSem ; let anyone waiting proceed | ||
| 2038 | and [DI].Flags,NOT Fwrap2 | ||
| 2039 | dnrq4: ; If both the fixed and floppy drivers | ||
| 2040 | push bx ; are idle, reset the busy flag and | ||
| 2041 | cmp Floppy.State,Idle ; continue any processes that were | ||
| 2042 | jne dnrq5 ; waiting for it. | ||
| 2043 | cmp Fixed.State,Idle | ||
| 2044 | jne dnrq5 | ||
| 2045 | mov SemDiskIO,0 | ||
| 2046 | mov ax,ds | ||
| 2047 | mov bx,offset SemDiskIO | ||
| 2048 | mov dx,ContinueProcess | ||
| 2049 | call DosFunction | ||
| 2050 | dnrq5: | ||
| 2051 | pop bx | ||
| 2052 | ret | ||
| 2053 | DoneRequest ENDP | ||
| 2054 | |||
| 2055 | |||
| 2056 | ; FDGetBPB returns a pointer to the floppy disk BPB for the | ||
| 2057 | ; selected media byte. The BPB contains various drive parameters | ||
| 2058 | ; such as physical disk dimensions and the size of FATs and the | ||
| 2059 | ; root directory. | ||
| 2060 | ; | ||
| 2061 | ; Input: AH = Media byte | ||
| 2062 | ; AL = Drive number | ||
| 2063 | ; Destroys: None | ||
| 2064 | ; Output: CS:DI = Pointer to BPB | ||
| 2065 | |||
| 2066 | ASSUME DS:NOTHING,ES:NOTHING | ||
| 2067 | |||
| 2068 | FDGetBPB PROC | ||
| 2069 | |||
| 2070 | PUSH AX | ||
| 2071 | PUSH BX | ||
| 2072 | PUSH CX | ||
| 2073 | PUSH DX ; Save regs | ||
| 2074 | MOV CL,AH ; Copy media value | ||
| 2075 | AND CL,0F8H ; Look at just top 5 bits | ||
| 2076 | CMP CL,0F8H ; Valid media byte? | ||
| 2077 | JE BPBGood ; Yes | ||
| 2078 | MOV AH,0FEH ; No, make it 8 sector 1 sided | ||
| 2079 | BPBgood: | ||
| 2080 | MOV BL,AL ; Get pointer to per drive info. | ||
| 2081 | XOR BH,BH | ||
| 2082 | ADD BX,BX | ||
| 2083 | MOV DI,CS:FDinfo[BX] | ||
| 2084 | CMP AH,CS:[DI].BPBmediab ; already set? | ||
| 2085 | JE BPBdone ; yes, don't bother rebuilding | ||
| 2086 | MOV AL,1 ; Assume will have 1 FAT sector | ||
| 2087 | MOV BX,64*256+8 ; Assume # dir = 64, 8 sector | ||
| 2088 | MOV CX,40*8 ; Assume 320 sectors/disk | ||
| 2089 | MOV DX,1*256+1 ; Assume 1 head, 1 sector/allocate | ||
| 2090 | TEST AH,2 ; Is drive 8 or 9 sector? | ||
| 2091 | JNZ BPBKnowSectors ; It's 8, we assumed right | ||
| 2092 | INC AL ; 9 sector, incr # of FAT sectors | ||
| 2093 | INC BL ; Set we have 9 sectors/cylinder | ||
| 2094 | ADD CX,40 ; Increase size to 360 sectors | ||
| 2095 | BPBKnowSectors: | ||
| 2096 | TEST AH,1 ; Is disk double sided? | ||
| 2097 | JE BPBKnowHeads ; No, we guessed right | ||
| 2098 | ADD CX,CX ; Double size of disk | ||
| 2099 | MOV BH,112 ; Increase # of directory entries | ||
| 2100 | INC DH ; Set 2 sectors/allocation unit | ||
| 2101 | INC DL ; Set 2 heads | ||
| 2102 | BPBKnowHeads: | ||
| 2103 | MOV CS:[DI].BPBsecpau,DH ; Set sectors/allocation unit | ||
| 2104 | MOV BYTE PTR CS:[DI].BPBndir,BH ; Set # of directory entries | ||
| 2105 | MOV CS:[DI].BPBnsec,CX ; Set size of disk in sectors | ||
| 2106 | MOV CS:[DI].BPBmediab,AH ; Set media byte | ||
| 2107 | MOV BYTE PTR CS:[DI].BPBnfatsec,AL ; Set number of FAT sectors | ||
| 2108 | MOV BYTE PTR CS:[DI].BPBtrksiz,BL ; Set sectors/track | ||
| 2109 | MOV BYTE PTR CS:[DI].BPBnhead,DL ; Set # of heads | ||
| 2110 | BPBdone: | ||
| 2111 | POP DX | ||
| 2112 | POP CX | ||
| 2113 | POP BX | ||
| 2114 | POP AX | ||
| 2115 | RET | ||
| 2116 | FDGetBPB ENDP | ||
| 2117 | |||
| 2118 | |||
| 2119 | ; HDGetBPB returns a pointer to the hard disk BPB for the | ||
| 2120 | ; selected unit. The BPB contains various drive parameters | ||
| 2121 | ; such as physical disk dimensions and the size of FATs and the | ||
| 2122 | ; root directory. | ||
| 2123 | ; | ||
| 2124 | ; Input: AL = Drive number | ||
| 2125 | ; Destroys: None | ||
| 2126 | ; Output: CS:DI = Pointer to BPB | ||
| 2127 | |||
| 2128 | ASSUME DS:NOTHING,ES:NOTHING | ||
| 2129 | |||
| 2130 | HDGetBPB PROC | ||
| 2131 | PUSH BX | ||
| 2132 | MOV BL,AL ; Get pointer to per drive info. | ||
| 2133 | XOR BH,BH | ||
| 2134 | ADD BX,BX | ||
| 2135 | MOV DI,CS:HDinfo[BX] | ||
| 2136 | POP BX | ||
| 2137 | RET | ||
| 2138 | HDGetBPB ENDP | ||
| 2139 | |||
| 2140 | |||
| 2141 | ASSUME DS:NOTHING,ES:NOTHING | ||
| 2142 | |||
| 2143 | BlockIfLocked Proc Near ; Block the current process if it has | ||
| 2144 | pushf ; been locked out by an Int 13 request. | ||
| 2145 | bifl1: cli ; Otherwise, set the busy flag to block | ||
| 2146 | cmp SemInt13,0 ; out Int 13 requests. | ||
| 2147 | jz bifl2 | ||
| 2148 | push dx | ||
| 2149 | push cx | ||
| 2150 | push bx | ||
| 2151 | push ax | ||
| 2152 | mov ax,cs | ||
| 2153 | mov bx,offset SemInt13 | ||
| 2154 | xor cx,cx | ||
| 2155 | mov dx,BlockProcess | ||
| 2156 | call DosFunction | ||
| 2157 | pop ax | ||
| 2158 | pop bx | ||
| 2159 | pop cx | ||
| 2160 | pop dx | ||
| 2161 | jmp bifl1 | ||
| 2162 | bifl2: | ||
| 2163 | mov SemDiskIO,1 | ||
| 2164 | popf | ||
| 2165 | ret | ||
| 2166 | BlockIfLocked endp | ||
| 2167 | |||
| 2168 | SUBTTL Routines that interface to hard disk controller | ||
| 2169 | PAGE + | ||
| 2170 | |||
| 2171 | ;*** HDCommand - send a command to the hard disk controller | ||
| 2172 | ; | ||
| 2173 | ; HDCommand will send the previously set up command block | ||
| 2174 | ; to the hard disk controller. | ||
| 2175 | ; | ||
| 2176 | ; ENTRY AL = value to be put in interrupt/DMA mask | ||
| 2177 | ; EXIT AL = status port value | ||
| 2178 | ; USES AX,CX,DX,SI | ||
| 2179 | |||
| 2180 | HDCommand PROC | ||
| 2181 | mov dx,HD_PSEL ; point to select port | ||
| 2182 | out dx,al | ||
| 2183 | ;; mov cx,10 ;BUGBUG - timing prob. w/ expansion box? | ||
| 2184 | ;;hdcom0: loop hdcom0 ;BUGBUG - timing prob. w/ expansion box? | ||
| 2185 | inc dx ; point to mask port | ||
| 2186 | out dx,al | ||
| 2187 | mov dx,HD_PSTAT | ||
| 2188 | hdcom1: in al,dx ; get status | ||
| 2189 | and al,0FH | ||
| 2190 | cmp al,0DH ; test for busy, command/data, request | ||
| 2191 | jnz hdcom1 | ||
| 2192 | mov si,OFFSET Fixed.DCB | ||
| 2193 | mov cx,6 | ||
| 2194 | cld | ||
| 2195 | dec dx ; point to data port | ||
| 2196 | hdcom2: lodsb | ||
| 2197 | out dx,al | ||
| 2198 | loop hdcom2 | ||
| 2199 | inc dx | ||
| 2200 | ;; mov cx,10 ;BUGBUG - timing prob. w/ expansion box? | ||
| 2201 | ;;hdcom3: loop hdcom3 ;BUGBUG - timing prob. w/ expansion box? | ||
| 2202 | in al,dx | ||
| 2203 | ret | ||
| 2204 | HDCommand ENDP | ||
| 2205 | |||
| 2206 | ;*** HDWaitReq - wait for request bit in status register | ||
| 2207 | ; | ||
| 2208 | ; HDWaitReq will pause until the request bit in the hard disk | ||
| 2209 | ; status register is set. | ||
| 2210 | ; | ||
| 2211 | ; ENTRY | ||
| 2212 | ; EXIT AL = status byte | ||
| 2213 | ; USES AX,DX | ||
| 2214 | |||
| 2215 | HDWaitReq PROC | ||
| 2216 | mov dx,HD_PSTAT | ||
| 2217 | in al,dx | ||
| 2218 | test al,01h ; request bit? | ||
| 2219 | jz HDWaitReq | ||
| 2220 | ret | ||
| 2221 | HDWaitReq ENDP | ||
| 2222 | SUBTTL Routines that interface to floppy disk controller | ||
| 2223 | PAGE + | ||
| 2224 | |||
| 2225 | ;*** GetDrivePtr - compute ptr to per drive info. | ||
| 2226 | ; | ||
| 2227 | ; GetDrivePtr returns a pointer to the per-drive information | ||
| 2228 | ; for the current drive. Should not be called before the | ||
| 2229 | ; current drive is set up by Sel765 in state CALC. | ||
| 2230 | ; | ||
| 2231 | ; EXIT BX = pointer to per drive table | ||
| 2232 | ; USES BX | ||
| 2233 | |||
| 2234 | GetDrivePtr PROC | ||
| 2235 | mov bx,cs:Floppy.Current | ||
| 2236 | add bx,bx | ||
| 2237 | mov bx,cs:FDinfo[bx] | ||
| 2238 | ret | ||
| 2239 | GetDrivePtr ENDP | ||
| 2240 | |||
| 2241 | |||
| 2242 | ; GetFloppyParam is called to get a disk parameter from the parameter | ||
| 2243 | ; block set up by the BIOS. This block allows disk parameters to be changed | ||
| 2244 | ; from the standard. | ||
| 2245 | ; | ||
| 2246 | ; Input: AL = parameter desired (see FloppyParam structure) | ||
| 2247 | ; Destroys: AX | ||
| 2248 | ; Output: AL = parameter byte desired | ||
| 2249 | |||
| 2250 | GetFloppyParam PROC | ||
| 2251 | PUSH DS | ||
| 2252 | PUSH BX | ||
| 2253 | XOR AH,AH | ||
| 2254 | MOV BX,AX | ||
| 2255 | XOR AX,AX | ||
| 2256 | MOV DS,AX ; Point to INT area | ||
| 2257 | LDS AX,DWORD PTR DS:(4*1EH) ; Get pointer to param block | ||
| 2258 | ADD BX,AX ; Add in block offset | ||
| 2259 | MOV AL,[BX] | ||
| 2260 | POP BX | ||
| 2261 | POP DS | ||
| 2262 | RET | ||
| 2263 | GetFloppyParam ENDP | ||
| 2264 | |||
| 2265 | |||
| 2266 | |||
| 2267 | ; Recalibrate the current drive. Clear Restore flag, set cylinder to | ||
| 2268 | ; unknown and issue command to controller. | ||
| 2269 | ; | ||
| 2270 | ; Destroys: AX,BX,DX | ||
| 2271 | ; | ||
| 2272 | |||
| 2273 | Rcl765 PROC | ||
| 2274 | AND CS:[BX].DrvFlag,NOT Frestor ; Have restored drive | ||
| 2275 | MOV CS:[BX].CurCyl,-1 ; Flag don't know where we are | ||
| 2276 | MOV AL,FD_CRESET | ||
| 2277 | CALL Put765 ; Put out reset command | ||
| 2278 | MOV AX,Floppy.Current ; Get current drive | ||
| 2279 | CALL Put765 ; Tell controller which drive | ||
| 2280 | RET | ||
| 2281 | Rcl765 ENDP | ||
| 2282 | |||
| 2283 | |||
| 2284 | ; Reset the controller. | ||
| 2285 | ; | ||
| 2286 | ; Destroys: AX,CX,DX | ||
| 2287 | ; | ||
| 2288 | |||
| 2289 | Rst765 PROC | ||
| 2290 | MOV AL,CS:Floppy.DOR | ||
| 2291 | AND AL,NOT(DORmask) | ||
| 2292 | MOV DX,FD_PSEL | ||
| 2293 | OUT DX,AL | ||
| 2294 | MOV CX,10000 | ||
| 2295 | RstDelayLoop: | ||
| 2296 | loop RstDelayLoop | ||
| 2297 | OR AL,DORmask | ||
| 2298 | MOV CS:Floppy.DOR,AL ; Update value | ||
| 2299 | OUT DX,AL | ||
| 2300 | RET | ||
| 2301 | Rst765 ENDP | ||
| 2302 | |||
| 2303 | |||
| 2304 | ; Load the drive specs into the controller. | ||
| 2305 | ; | ||
| 2306 | ; Destroys: AX,DX | ||
| 2307 | ; | ||
| 2308 | |||
| 2309 | Spec765 PROC | ||
| 2310 | MOV AL,FD_CSPEC | ||
| 2311 | CALL Put765 | ||
| 2312 | MOV AL,Spec1 | ||
| 2313 | CALL GetFloppyParam | ||
| 2314 | CALL Put765 | ||
| 2315 | MOV AL,Spec2 | ||
| 2316 | CALL GetFloppyParam | ||
| 2317 | CALL Put765 | ||
| 2318 | RET | ||
| 2319 | Spec765 ENDP | ||
| 2320 | |||
| 2321 | |||
| 2322 | ; Get the interrupt status from the controller and into AX | ||
| 2323 | ; | ||
| 2324 | ; Destroys: AX,CX,DX | ||
| 2325 | ; | ||
| 2326 | |||
| 2327 | Sense765 PROC | ||
| 2328 | MOV AL,FD_CSENSE ; Get status | ||
| 2329 | CALL Put765 | ||
| 2330 | CALL Get765 ; Read ST0 | ||
| 2331 | PUSH AX ; Save status | ||
| 2332 | CALL Get765 ; Read PCN (present cylinder number) | ||
| 2333 | POP AX ; Restore status | ||
| 2334 | MOV CL,6 | ||
| 2335 | SHR AL,CL ; Shift bits down | ||
| 2336 | AND AX,3 ; Leave only error bits | ||
| 2337 | RET | ||
| 2338 | Sense765 ENDP | ||
| 2339 | |||
| 2340 | |||
| 2341 | ; Select the current drive. Return carry set if must wait until drive is | ||
| 2342 | ; ready. FloppyExecute will be called again when the drive is ready. The | ||
| 2343 | ; code must wait either for a motor start or head load delay, otherwise it | ||
| 2344 | ; returns with carry clear. | ||
| 2345 | ; | ||
| 2346 | ; Destroys: AX,BX,CX,DX | ||
| 2347 | ; | ||
| 2348 | |||
| 2349 | Sel765 PROC | ||
| 2350 | MOV DX,FD_PSEL ; set DX = Digital Output Register | ||
| 2351 | MOV CL,Floppy.Unit ; Get unit we want to use | ||
| 2352 | XOR CH,CH ; CX = wanted unit | ||
| 2353 | CMP Single,0 ; Single drive system? | ||
| 2354 | JE Sel765Double ; No, Unit is accurate | ||
| 2355 | MOV CL,CH ; Yes, there is only drive 0 | ||
| 2356 | Sel765Double: | ||
| 2357 | CMP CX,Floppy.Current ; Wanted same as current? | ||
| 2358 | MOV Floppy.Current,CX ; Set new current unit | ||
| 2359 | JNE SelectUnit ; No, must select new drive | ||
| 2360 | ADD CL,4 | ||
| 2361 | MOV AL,1 | ||
| 2362 | SHL AL,CL ; AL = Bit for drive's motor on | ||
| 2363 | TEST AL,Floppy.DOR ; Is the drive's motor still on? | ||
| 2364 | JE SelectUnit ; No, must turn it back on | ||
| 2365 | MOV AL,Floppy.DOR | ||
| 2366 | OUT DX,AL ; ? For some reason output value again | ||
| 2367 | CLC ; Clear carry, don't have to wait | ||
| 2368 | RET | ||
| 2369 | |||
| 2370 | SelectUnit: | ||
| 2371 | MOV AL,NOT(3) ; Drive select is low 2 bits | ||
| 2372 | AND AL,Floppy.DOR ; Lose old select bits | ||
| 2373 | OR AL,DORmask | ||
| 2374 | MOV CL,BYTE PTR Floppy.Current ; get unit number | ||
| 2375 | OR AL,CL ; Put in new select bits | ||
| 2376 | MOV Floppy.DOR,AL ; Save new bits | ||
| 2377 | ADD CL,4 | ||
| 2378 | MOV AL,1 | ||
| 2379 | SHL AL,CL ; Get bit for motor is on | ||
| 2380 | TEST AL,Floppy.DOR ; Is drive's motor on? | ||
| 2381 | JE SelectStartMotor ; No, must start motor | ||
| 2382 | MOV AL,Floppy.DOR | ||
| 2383 | OUT DX,AL ; Load the head | ||
| 2384 | MOV AX,DelayLoad ; Load head delay | ||
| 2385 | CALL SetTimer1 | ||
| 2386 | RET | ||
| 2387 | |||
| 2388 | SelectStartMotor: | ||
| 2389 | OR Floppy.DOR,AL ; Add in motor start bit | ||
| 2390 | MOV AL,Floppy.DOR | ||
| 2391 | OUT DX,AL ; Start the motor | ||
| 2392 | MOV AL,DelayMotor | ||
| 2393 | CALL GetFloppyParam ; Get the proper delay time in 1/8 sec | ||
| 2394 | mov cl,125 | ||
| 2395 | mul cl ; convert to milliseconds | ||
| 2396 | CALL SetTimer1 ; Set timer for motor startup | ||
| 2397 | RET | ||
| 2398 | Sel765 ENDP | ||
| 2399 | |||
| 2400 | |||
| 2401 | ; Seek to the correct cylinder. Set carry if have to wait for operation | ||
| 2402 | ; to complete (we are not on right cylinder). | ||
| 2403 | ; | ||
| 2404 | ; Destroys: AX,BX,DX | ||
| 2405 | ; | ||
| 2406 | |||
| 2407 | Seek765 PROC | ||
| 2408 | MOV AX,Floppy.Cyl ; Get cylinder wanted | ||
| 2409 | CMP AX,CS:[BX].CurCyl ; Already on cylinder? | ||
| 2410 | JE SeekDone ; Yes, return with carry clear | ||
| 2411 | MOV CS:[BX].CurCyl,AX ; Set the new current cylinder | ||
| 2412 | MOV AL,FD_CSEEK | ||
| 2413 | CALL Put765 ; Seek command | ||
| 2414 | MOV AL,Floppy.Head ; Get head desired | ||
| 2415 | SHL AL,1 | ||
| 2416 | SHL AL,1 ; Move head # 2 bits left | ||
| 2417 | ADD AL,BYTE PTR Floppy.Current ; Low 2 bits are unit (hhuu) | ||
| 2418 | CALL Put765 ; Put out drive and head select | ||
| 2419 | MOV AX,Floppy.Cyl | ||
| 2420 | TEST Floppy.Flags,F2step ; Need to double step? | ||
| 2421 | JE SeekNoDouble ; No | ||
| 2422 | ADD AX,AX ; Yes, double cylinder number | ||
| 2423 | SeekNoDouble: | ||
| 2424 | CALL Put765 ; Give controller the cylinder | ||
| 2425 | STC ; Set carry, must wait for seek intr. | ||
| 2426 | SeekDone: | ||
| 2427 | RET | ||
| 2428 | Seek765 ENDP | ||
| 2429 | |||
| 2430 | |||
| 2431 | |||
| 2432 | ; Start the Read/write. Set up the DMA channel and give a read or write | ||
| 2433 | ; command to the controller depending on flag. | ||
| 2434 | ; | ||
| 2435 | ; Destroys: AX,CX,DX | ||
| 2436 | ; | ||
| 2437 | |||
| 2438 | RdWr765 PROC | ||
| 2439 | mov ah,FD_DMA | ||
| 2440 | mov si,OFFSET Floppy | ||
| 2441 | TEST Floppy.Flags,Fwrite ; Is this a write? | ||
| 2442 | JNE WriteSetup ; Yes | ||
| 2443 | MOV AL,DMA_READ ; No, read | ||
| 2444 | CALL DMAsetup ; Set up the DMA | ||
| 2445 | MOV AL,FD_CREAD ; Want to read | ||
| 2446 | JMP SHORT RdWrLoc ; Now put out rest of command | ||
| 2447 | |||
| 2448 | WriteSetup: | ||
| 2449 | MOV AL,DMA_WRITE | ||
| 2450 | CALL DMAsetup ; Set DMA up for write | ||
| 2451 | MOV AL,FD_CWRITE ; Want to write | ||
| 2452 | RdWrLoc: | ||
| 2453 | CALL Put765 ; Put out command | ||
| 2454 | MOV AL,Floppy.Head | ||
| 2455 | ADD AL,AL | ||
| 2456 | ADD AL,AL ; Form HHxx Binary | ||
| 2457 | ADD AL,BYTE PTR Floppy.Current ; Form HHUU | ||
| 2458 | CALL Put765 ; Output unit and head | ||
| 2459 | MOV AX,Floppy.Cyl | ||
| 2460 | CALL Put765 ; Output cylinder | ||
| 2461 | MOV AL,Floppy.Head | ||
| 2462 | CALL Put765 ; Output head again? | ||
| 2463 | MOV AL,Floppy.Sector | ||
| 2464 | inc al | ||
| 2465 | CALL Put765 ; Output sector | ||
| 2466 | MOV AL,SectorSize | ||
| 2467 | CALL GetFloppyParam ; Get sector size code | ||
| 2468 | CALL Put765 ; Tell controller sector size | ||
| 2469 | MOV AL,CylSize | ||
| 2470 | CALL GetFloppyParam ; Get number of sectors/cylinder | ||
| 2471 | CALL Put765 ; Tell controller | ||
| 2472 | MOV AL,DataGap ; Gap length for read/write | ||
| 2473 | CALL GetFloppyParam | ||
| 2474 | CALL Put765 ; Tell controller gap length | ||
| 2475 | MOV AL,ValueDTL | ||
| 2476 | CALL GetFloppyParam ; Get value for DTL | ||
| 2477 | CALL Put765 ; Since bytes/sector#0, this is a | ||
| 2478 | ; meaningless value, but controller | ||
| 2479 | ; wants to see something | ||
| 2480 | RET | ||
| 2481 | RdWr765 ENDP | ||
| 2482 | |||
| 2483 | |||
| 2484 | |||
| 2485 | ; Fini765 gets the completion status. | ||
| 2486 | ; | ||
| 2487 | ; Destroys: AX,CX,DX | ||
| 2488 | ; Returns: AL | ||
| 2489 | ; | ||
| 2490 | |||
| 2491 | Fini765 PROC | ||
| 2492 | push es | ||
| 2493 | push di | ||
| 2494 | push cs | ||
| 2495 | pop es | ||
| 2496 | mov di,OFFSET Floppy.ST0 | ||
| 2497 | MOV CX,7 | ||
| 2498 | fini1: CALL Get765 | ||
| 2499 | stosb | ||
| 2500 | loop fini1 | ||
| 2501 | mov al,Floppy.ST0 | ||
| 2502 | mov cl,6 | ||
| 2503 | SHR AL,CL | ||
| 2504 | AND AX,3 ; Mask down to value to return | ||
| 2505 | pop di | ||
| 2506 | pop es | ||
| 2507 | RET | ||
| 2508 | Fini765 ENDP | ||
| 2509 | |||
| 2510 | |||
| 2511 | |||
| 2512 | ; Put765 writes a command to the controller. | ||
| 2513 | ; | ||
| 2514 | ; Input: AL = value | ||
| 2515 | ; Destroys: AX,DX | ||
| 2516 | ; | ||
| 2517 | |||
| 2518 | Put765 PROC | ||
| 2519 | PUSH AX ; Save the value to write | ||
| 2520 | PutWaitLoop: | ||
| 2521 | MOV DX,FD_PSTAT | ||
| 2522 | IN AL,DX ; Get status | ||
| 2523 | AND AL,FD_SDIO+FD_SRQM | ||
| 2524 | CMP AL,FD_SRQM ; Controller ready for data? | ||
| 2525 | JNE PutWaitLoop ; No, keep waiting | ||
| 2526 | POP AX ; Get value back | ||
| 2527 | MOV DX,FD_PDAT | ||
| 2528 | OUT DX,AL ; Put out value | ||
| 2529 | RET | ||
| 2530 | Put765 ENDP | ||
| 2531 | |||
| 2532 | |||
| 2533 | ; Get765 gets a value back from the controller into AL. | ||
| 2534 | ; | ||
| 2535 | ; Destroys: AX,DX | ||
| 2536 | ; Returns: AL | ||
| 2537 | ; | ||
| 2538 | |||
| 2539 | Get765 PROC | ||
| 2540 | MOV DX,FD_PSTAT | ||
| 2541 | IN AL,DX ; Get status | ||
| 2542 | AND AL,FD_SDIO+FD_SRQM | ||
| 2543 | CMP AL,FD_SDIO+FD_SRQM ; Controller data available? | ||
| 2544 | JNE Get765 ; No, wait for it | ||
| 2545 | MOV DX,FD_PDAT | ||
| 2546 | IN AL,DX ; Get value from controller | ||
| 2547 | ret | ||
| 2548 | Get765 ENDP | ||
| 2549 | |||
| 2550 | Code ENDS | ||
| 2551 | END | ||