summaryrefslogtreecommitdiff
path: root/v4.0-ozzie/bin/DISK2/BIOS/IBMDSK.ASM
diff options
context:
space:
mode:
authorGravatar Mark Zbikowski2024-04-25 21:24:10 +0100
committerGravatar Microsoft Open Source2024-04-25 22:32:27 +0000
commit2d04cacc5322951f187bb17e017c12920ac8ebe2 (patch)
tree80ee017efa878dfd5344b44249e6a241f2a7f6e2 /v4.0-ozzie/bin/DISK2/BIOS/IBMDSK.ASM
parentMerge pull request #430 from jpbaltazar/typoptbr (diff)
downloadms-dos-main.tar.gz
ms-dos-main.tar.xz
ms-dos-main.zip
MZ is back!HEADmain
Diffstat (limited to 'v4.0-ozzie/bin/DISK2/BIOS/IBMDSK.ASM')
-rw-r--r--v4.0-ozzie/bin/DISK2/BIOS/IBMDSK.ASM2551
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 @@
1TITLE DISK - MS-DOS 4.0 disk drivers for IBM
2NAME DISK
3
4 PAGE ,132
5
6;DEBUGFLG=1
7
8.xlist
9 INCLUDE DEFDBUG.INC
10.list
11
12; Constants
13
14ErrLim= 5 ; Number of retries on error
15
16; Floppy delay constants
17
18DelayLoad= 35 ; 35 milliseconds to load head
19
20; Constants for floppy disk controller
21
22Rate99= 000H ; Step rate 96tpi disk in 96tpi drive
23Rate49= 001H ; Step rate 48tpi disk in 96tpi drive
24Rate44= 002H ; Step rate 48tpi disk in 48tpi drive
25
26; Commands to floppy disk controller
27
28FD_CRESET= 007H ; Recalibrate drive
29FD_CSENSE= 008H ; Sense interrupt status
30FD_CSEEK= 00FH ; Seek to another track
31FD_CREAD= 046H ; MFM read, skip deleted data
32FD_CWRITE= 045H ; MFM write, skip deleted data
33FD_CSPEC= 003H ; Special - step rate, head load/unload
34
35; Status codes
36
37FD_SDIO= 01000000B ; Transfer direction (0 -> controller)
38FD_SRQM= 10000000B ; Controller ready for next data
39
40; Hard disk controller commands
41HD_CSENS= 03H ; request sense block
42HD_CREAD= 08H ; read
43HD_CWRITE= 0AH ; write
44
45HDcontrolbyte= 05H ; step rate = 70 us.
46
47; I/O ports
48
49FD_PSEL= 03F2H ; Controls drive select and motors
50FD_PDAT= 03F5H ; Data transfer to/from controller
51FD_PSTAT= 03F4H ; Controller status
52FD_PCMD= 03F7H ; Controller command register
53
54HD_PDAT= 0320H ; read/write data
55HD_PSTAT= 0321H ; controller status
56HD_PSEL= 0322H ; controller select
57HD_PMSK= 0323H ; DMA and interrupt mask bits
58
59PDMA= 0 ; Base of ports for DMA control
60PDMAX= 7FH ; Address extension regs for DMA
61 ;NOTE base address suitable for ch. 2 & 3 only
62FD_DMA= 2 ; floppy disk DMA channel
63HD_DMA= 3 ; hard disk DMA channel
64
65DMA_READ= 44H ; DMA read command
66DMA_WRITE= 48H ; DMA write command
67
68; Misc
69
70DORmask= 00CH ; Not reset, enable DMA & interrupt
71
72
73
74SUBTTL Data for performing requests
75PAGE +
76
77;* Dos Request Packet structure
78
79DosPacket 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
91DosPacket 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
98Start= 0 ; Starting I/O
99Calc= 1 ; Calculate position on disk
100Done= 7 ; I/O is done
101Idle= 8 ; Drive is inactive
102Error= 9 ; Have an error
103; The following states are used by the floppy driver only
104Select= 2 ; Select drive, start motor, seek
105Recal= 3 ; Drive was just recalibrated
106Seek= 4 ; Seek just finished
107Settle= 5 ; Head has settled
108RdWri= 6 ; Read/write is done
109; The following states are used by the fixed driver only
110Verify= 6 ; Start verify portion of write
111
112
113DeviceStruc 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
138DeviceStruc 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
150BiosSeg GROUP Code,BiosInit
151
152Code SEGMENT BYTE PUBLIC 'CODE'
153 ASSUME CS:BiosSeg
154
155IFDEF DEBUGFLG
156 EXTRN BUGBITS:BYTE,DPRINTF:NEAR
157ENDIF
158
159SUBTTL Device data
160PAGE +
161
162Floppy DeviceStruc <>
163Fixed DeviceStruc <>
164
165;* Per drive information, including BPBs
166
167DriveStruc 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
183DriveStruc ENDS
184
185; DrvFlag values
186Frestor= 1 ; restore needed
187Fmotoron= 2 ; motor is on
188
189DriveA DriveStruc <> ; floppy drive 0
190DriveB DriveStruc <> ; floppy drive 1 or 0
191DriveC DriveStruc <> ; hard drive 0 or floppy drive 2
192DriveD DriveStruc <> ; hard drive 1 or floppy drive 3
193
194FDinfo DW DriveA
195 DW DriveB
196HDinfo DW DriveC
197 DW DriveD
198
199
200; Structure of parameter block for floppy pointed to by 0:4*1E
201
202FloppyParameter 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
216FloppyParameter ENDS
217
218
219ScratchBuffer DB 512 DUP(?) ; Scratch buffer for when DMA fails
220 ; Hope we don't handle >512 sector
221 ; size
222
223;* Miscellaneous data
224
225Single DB 0 ; non-zero if 1 floppy disk system
226 ; in this case, NumFloppy will be 2
227
228SUBTTL Data for interface to 4.0
229PAGE +
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
240int_savregs= 32H ; interrupt routine which saves all regs
241
242
243SwapSem1 DB 0 ; non-zero if waiting to swap disks
244SwapSem2 DB 0 ; non-zero if waiting to prompt for swap
245ScratchBufSem DB 0 ; semaphore controlling ScratchBuffer
246
247SEM_WANT= 2
248SEM_BUSY= 1
249
250SemWait Macro wchan
251local l1,l2
252 pushf
253l1: 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
263l2: or wchan,SEM_BUSY ;;claim semaphore
264 popf
265 endm
266
267SemSig Macro wchan
268local 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]
275l: and wchan,NOT (SEM_WANT+SEM_BUSY)
276 endm
277
278
279FloppyQueue DD 0 ; List of requests for floppy
280FixedQueue DD 0 ; List of requests for fixed disk
281
282; Device driver headers
283
284 PUBLIC FloppyDevice
285FloppyDevice 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
290NumFloppy DB 4 ; Handle 4 floppys maximum
291 DB 0 ; can be addressed as word also
292
293 EXTRN Com1Dev:NEAR
294
295FixedDevice 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)
300NumFixed 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
312JustReturn PROC FAR
313 RET
314JustReturn ENDP
315
316FloppyRequest 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
321FloppyRequest ENDP
322
323; Dispatch table for actions of the floppy requested by 4.0
324
325FloppyFunction 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
344FixedRequest 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
349FixedRequest ENDP
350
351; Dispatch table for actions of the hard disk requested by 4.0
352
353FixedFunction 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
373SUBTTL Data for routines that make direct Int 13 requests
374PAGE +
375
376
377RealInt13Vec dw 0 ; Used to make Int 13 requests
378 dw 0
379OldIntDVec dw 0 ; Must be reset when Int 13's on hard
380 dw 0 ; disk.
381OldIntEVec dw 0 ; Must be reset when Int 13's on floppy
382 dw 0 ; disk.
383SemDiskIO db 0 ; Semaphore controlling disk io
384SemInt13 db 0 ; Semaphore controlling Int 13's
385
386
387SUBTTL 4.0 device driver routines (system entry points)
388PAGE +
389
390BiosInit SEGMENT PARA PUBLIC 'CODE'
391 ASSUME CS:BiosSeg
392
393 PUBLIC Disk_Init
394Disk_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
424NOTSNGL:
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.
437ENDDRV:
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
453NOTOK:
454 MOV DI,OFFSET DriveC
455 DEC [NumFixed]
456 CMP [NumFixed],0
457 JZ ITSOK
458SETIT: CALL SETHRD ;SET UP SECOND HARDFILE
459 JNC ITSOK
460 DEC [NumFixed]
461ITSOK:
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
466itsok2:
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
487Disk_Init ENDP
488
489;
490; READ A BOOT RECORD INTO Scratch buffer
491;
492GETBOOT:
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;
509SETHRD: 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
522SET1: CMP BYTE PTR ES:[BX],1
523 JZ SET2
524 ADD BX,16
525 loop SET1
526SETRET: STC ;NOT FOUND SO USE DEFAULTS
527 debug 8,3,<Sethrd err rtn: drive $x stat $x\n>,<dx,ax>
528 RET
529
530SET2: 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
562SET3:
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
587BiosInit ENDS
588
589 ASSUME CS:BiosSeg,DS:NOTHING,ES:NOTHING
590
591FloppyInit 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
603DBBEG 4,3
604 jmp SHORT iniret
605DBEND
606 jmp bpbret
607ELSE
608 jmp SHORT bpbret
609ENDIF
610FloppyInit ENDP
611
612FixedInit 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
629DBBEG 8,3
630iniret: debug 12,3,< - Num=$x BPB table=$x:$x\n>,<ax,cs,di>
631DBEND
632ENDIF
633 jmp SHORT bpbret
634FixedInit ENDP
635
636FloppyBuild PROC
637 mov ah,byte ptr es:[di]
638 call FDGetBPB
639bpbret: mov [bx.RqMedia],ah
640 mov [bx.RqCount],di
641 mov [bx.RqCount+2],CS
642 jmp StatusComplete
643FloppyBuild ENDP
644
645FixedBuild PROC
646 mov ah,byte ptr es:[di]
647 call HDGetBPB
648 jmp SHORT bpbret
649FixedBuild 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
661FloppyCheck 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
671flchk1: 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
679FloppyCheckDone:
680 MOV BYTE PTR DS:[BX].RqAddr,DL
681 JMP StatusComplete ; Return whether media changed
682FloppyCheck ENDP
683
684
685FixedCheck PROC
686 MOV DL,1
687 JMP FloppyCheckDone
688FixedCheck 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
709FloppyRead LABEL NEAR
710FloppyWrite LABEL NEAR
711FloppyWriteV 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
725flrw1: OR CX,CX ; Anything to do?
726 JNZ flrw2 ; Yes
727 JMP StatusComplete ; No, all done now
728flrw2:
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
732flrw3:
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
754flrw4: test DS:[BX].RqStatus,0100H ; IO completed?
755 JNZ FloppyIOdone ; yes
756
757FloppyActive:
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
765FloppyIOdone:
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
771FloppyWriteV ENDP
772
773
774FixedRead LABEL NEAR
775FixedWrite LABEL NEAR
776FixedWriteV 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
790fxrw1: OR CX,CX ; Anything to do?
791 JNZ fxrw2 ; Yes
792 JMP StatusComplete ; No, all done now
793fxrw2:
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
815fxrw4: test DS:[BX].RqStatus,0100H ; IO completed?
816 JNZ FixedIOdone ; yes
817
818FixedActive:
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
826FixedIOdone:
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
832FixedWriteV 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
849CheckWrap 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
866chkw8: pop cx
867 pop dx
868 ret
869CheckWrap 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
892FloppyChange PROC
893 push cx
894 pushf
895 push bx
896 SemWait SwapSem1 ; Currently waiting to switch disk?
897 pop bx
898
899flcha1: 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
911flcha2:
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
922flcha4:
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
929flcha5:
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
938flcha7:
939 push bx
940 SemSig SwapSem1 ; Allow blocked processes to continue
941 pop bx
942flcha8:
943 popf
944 pop cx
945 RET
946
947FloppyChange ENDP
948
949
950SwitchMsg LABEL WORD
951 DB 13,10,"Insert diskette for drive "
952DriveLetter LABEL BYTE
953 DB "A: and strike",13,10,"any key when ready",13,10,10,0
954
955
956Int13Handler Proc Far
957 push dx ; Save regs used in local processing
958 push cx
959 push bx
960 push ax
961 pushf
962LockCheck:
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
972NotLocked:
973 mov SemInt13,1 ; Lock out other disk requests
974 popf
975 pushf
976BusyCheck:
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
986DiskFree:
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
1011Int13Handler endp
1012
1013
1014SUBTTL Fixed disk startup routine
1015PAGE +
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
1023FixedDispatch 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
1035FixedExecute 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
1054FxExStart:
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
1073FxExCalc:
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
1084fxxc1: mov al,DMA_write
1085 mov Fixed.DCB,HD_CWRITE
1086fxxc2: 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
1109fxxc3: 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
1118FxExVerify:
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
1131FxExDone:
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
1145fxxd1:
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
1153fxexj4: JMP FixedExecute
1154
1155fxxd3:
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
1166FxExIdle:
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
1177FxExError:
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
1192fxxe1:
1193 mov ah,12
1194fxxe2: 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
1206FixedExecute ENDP
1207
1208;* Traslation of controller error codes to DOS error codes
1209
1210HDErrType DW HDErrTyp0
1211 DW HDErrTyp1
1212 DW HDErrTyp2
1213 DW HDErrTyp3
1214
1215HDErrTyp0 DB 9, 12, 2, 6,10, 2,12, 6,12, 6
1216HDErrTyp1 DB 10, 4, 4, 8,12, 8, 6,12,12, 4, 6
1217HDErrTyp2 DB 2, 3, 8
1218HDErrTyp3 DB 3, 4, 4, 4
1219
1220 ASSUME CS:BiosSeg,DS:NOTHING,ES:NOTHING
1221
1222FixedInterrupt 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
1243fxinot13:
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
1265fxin0: 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
1272fxin1: 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
1280fxin4: CALL FixedExecute
1281fxinret: push ax
1282 MOV AL,20H ; send EOI to 8259
1283 OUT 20H,AL
1284 pop ax
1285 IRET
1286FixedInterrupt ENDP
1287
1288SUBTTL Floppy disk startup routine
1289PAGE +
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
1298FloppyDispatch 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
1310FloppyExecute 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
1329FlExStart:
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
1340flexj1: 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
1352FlExCalc:
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
1372FlExSelect:
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
1382NoRestore: ; 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
1397FlExRecal:
1398 CALL Sense765
1399 OR AX,AX ; Error in recal?
1400 JNZ SeekErr ; Yes
1401RecalOK:
1402 CALL Spec765 ; Load drive specs
1403 MOV Floppy.State,Select ; Back to select state now
1404flexj2: 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
1413FlExSeek:
1414 CALL Sense765 ; Get status of seek
1415 OR AX,AX ; Any error?
1416 JZ SeekOK ; No
1417SeekErr:
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
1424SeekOK:
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
1439FlExSettle:
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
1452FlExRdWri:
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
1459RdWriOK:
1460 MOV Floppy.State,Done ; I/O is done
1461flexj3: 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
1472FlExDone:
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
1486DoneNotWrap:
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
1494DoneNotWritePart:
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
1498DoneNotVerify:
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
1506flexj4: JMP flexj3
1507
1508flxd3:
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
1519FlExIdle:
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
1533FlExError:
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
1541FloppyFails:
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
1563ErrorFound:
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
1573FloppyExecute ENDP
1574
1575
1576 ASSUME CS:BiosSeg,DS:NOTHING,ES:NOTHING
1577
1578FloppyInterrupt 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
1588flinot13:
1589 TEST Floppy.Flags,Factive ; device active?
1590 JZ flinret ; no, go away
1591 INT int_savregs ; save registers
1592 CALL FloppyExecute
1593flinret: push ax
1594 MOV AL,20H ; send EOI to 8259
1595 OUT 20H,AL
1596 pop ax
1597 IRET
1598FloppyInterrupt ENDP
1599
1600SUBTTL Timing routines for floppy disk
1601PAGE +
1602
1603;* Data for timers
1604TimerActive DB 0 ; bit flags for active timers
1605TimerConv DB 50 ; conversion factor for ms => ticks
1606Timer1 DB 0 ; One-shot time till restart intr. rtn.
1607Timer2 DB 0 ; Repetitive 1 Hz timer
1608Timer2count = 20 ; Reload value for timer2
1609
1610MOFFDELAY= 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
1624SetTimer1 PROC
1625 TEST AX,AX ; zero count?
1626 JNZ sett10 ; no
1627 CLC
1628 RET
1629
1630sett10: DIV TimerConv
1631 TEST AH,AH ; remainder?
1632 JZ sett11
1633 INC AL ; yes, round up
1634sett11: MOV Timer1,AL
1635 OR TimerActive,1
1636 debug 4,8,<SetTimer1 $b\n>,<ax>
1637 STC
1638 RET
1639SetTimer1 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
1651SetTimer2 PROC
1652 TEST TimerActive,2
1653 JNZ sett21
1654 MOV Timer2,Timer2Count
1655 OR TimerActive,2
1656sett21: MOV CS:[BX].Timer,MOFFDELAY
1657 debug 4,8,<SetTimer2\n>,<>
1658 RET
1659SetTimer2 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
1675FloppyTimer PROC FAR
1676 TEST TimerActive,0ffH ; any timers active?
1677 JNZ fltim1 ; yes
1678 RET ; no, return quickly
1679fltim1: 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
1689fltim3: TEST TimerActive,2 ; Timer2 active?
1690 JZ fltim4 ; no
1691 DEC Timer2 ; 1 Hz clock time?
1692 JZ fltim5 ; no
1693fltim4: JMP fltim9
1694fltim5:
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
1702TimeOutLoop:
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
1721fltim6:
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
1741fltim7: INC CH ; Flag still active
1742fltim8: 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
1748fltim9: RET
1749
1750FloppyTimer ENDP
1751
1752
1753IFDEF DEBUGFLG
1754DumpRegs 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
1784dmpr0: jmp dmpr0
1785DumpRegs ENDP
1786ENDIF ;DEUBGFLAG
1787
1788SUBTTL Routines shared between Floppy and Hard disk drivers
1789PAGE +
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
1816Setup 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
1835SetupDone:
1836 RET
1837Setup 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
1869MapSector 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
1902maps2:
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
1914maps4:
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
1943REP MOVSB ; Copy the write buffer
1944 POP SI
1945 POP DS
1946 POP ES
1947maps6:
1948 RET
1949MapSector 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
1962DMAsetup 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
2000DMAsetup 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
2016DoneRequest 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
2034dnrq2:
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
2039dnrq4: ; 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
2050dnrq5:
2051 pop bx
2052 ret
2053DoneRequest 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
2068FDGetBPB 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
2079BPBgood:
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
2095BPBKnowSectors:
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
2102BPBKnowHeads:
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
2110BPBdone:
2111 POP DX
2112 POP CX
2113 POP BX
2114 POP AX
2115 RET
2116FDGetBPB 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
2130HDGetBPB 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
2138HDGetBPB ENDP
2139
2140
2141 ASSUME DS:NOTHING,ES:NOTHING
2142
2143BlockIfLocked Proc Near ; Block the current process if it has
2144 pushf ; been locked out by an Int 13 request.
2145bifl1: 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
2162bifl2:
2163 mov SemDiskIO,1
2164 popf
2165 ret
2166BlockIfLocked endp
2167
2168SUBTTL Routines that interface to hard disk controller
2169PAGE +
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
2180HDCommand 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
2188hdcom1: 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
2196hdcom2: 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
2204HDCommand 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
2215HDWaitReq PROC
2216 mov dx,HD_PSTAT
2217 in al,dx
2218 test al,01h ; request bit?
2219 jz HDWaitReq
2220 ret
2221HDWaitReq ENDP
2222SUBTTL Routines that interface to floppy disk controller
2223PAGE +
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
2234GetDrivePtr PROC
2235 mov bx,cs:Floppy.Current
2236 add bx,bx
2237 mov bx,cs:FDinfo[bx]
2238 ret
2239GetDrivePtr 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
2250GetFloppyParam 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
2263GetFloppyParam 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
2273Rcl765 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
2281Rcl765 ENDP
2282
2283
2284; Reset the controller.
2285;
2286; Destroys: AX,CX,DX
2287;
2288
2289Rst765 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
2295RstDelayLoop:
2296 loop RstDelayLoop
2297 OR AL,DORmask
2298 MOV CS:Floppy.DOR,AL ; Update value
2299 OUT DX,AL
2300 RET
2301Rst765 ENDP
2302
2303
2304; Load the drive specs into the controller.
2305;
2306; Destroys: AX,DX
2307;
2308
2309Spec765 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
2319Spec765 ENDP
2320
2321
2322; Get the interrupt status from the controller and into AX
2323;
2324; Destroys: AX,CX,DX
2325;
2326
2327Sense765 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
2338Sense765 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
2349Sel765 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
2356Sel765Double:
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
2370SelectUnit:
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
2388SelectStartMotor:
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
2398Sel765 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
2407Seek765 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
2423SeekNoDouble:
2424 CALL Put765 ; Give controller the cylinder
2425 STC ; Set carry, must wait for seek intr.
2426SeekDone:
2427 RET
2428Seek765 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
2438RdWr765 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
2448WriteSetup:
2449 MOV AL,DMA_WRITE
2450 CALL DMAsetup ; Set DMA up for write
2451 MOV AL,FD_CWRITE ; Want to write
2452RdWrLoc:
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
2481RdWr765 ENDP
2482
2483
2484
2485; Fini765 gets the completion status.
2486;
2487; Destroys: AX,CX,DX
2488; Returns: AL
2489;
2490
2491Fini765 PROC
2492 push es
2493 push di
2494 push cs
2495 pop es
2496 mov di,OFFSET Floppy.ST0
2497 MOV CX,7
2498fini1: 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
2508Fini765 ENDP
2509
2510
2511
2512; Put765 writes a command to the controller.
2513;
2514; Input: AL = value
2515; Destroys: AX,DX
2516;
2517
2518Put765 PROC
2519 PUSH AX ; Save the value to write
2520PutWaitLoop:
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
2530Put765 ENDP
2531
2532
2533; Get765 gets a value back from the controller into AL.
2534;
2535; Destroys: AX,DX
2536; Returns: AL
2537;
2538
2539Get765 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
2548Get765 ENDP
2549
2550Code ENDS
2551 END