1 TITLE DISK
- MS-DOS
4.0 disk drivers for IBM
14 ErrLim
= 5 ; Number of retries on error
16 ; Floppy delay constants
18 DelayLoad
= 35 ; 35 milliseconds to load head
20 ; Constants for floppy disk controller
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
26 ; Commands to floppy disk controller
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
37 FD_SDIO
= 01000000B ; Transfer direction (0 -> controller)
38 FD_SRQM
= 10000000B ; Controller ready for next data
40 ; Hard disk controller commands
41 HD_CSENS
= 03H ; request sense block
43 HD_CWRITE
= 0AH ; write
45 HDcontrolbyte
= 05H ; step rate = 70 us.
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
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
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
65 DMA_READ
= 44H
; DMA read command
66 DMA_WRITE
= 48H
; DMA write command
70 DORmask
= 00CH ; Not reset, enable DMA & interrupt
74 SUBTTL
Data for performing requests
77 ;* Dos Request Packet structure
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
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
93 ; The disk drivers work as a state machine performing the various actions
94 ; that make up disk I/O.
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
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.
122 First
DW 0 ; 1st sector of request
123 RealAddr
DD 0 ; Real addr of data when Addr is
125 Count
DW 0 ; Number of sectors to xfer
126 ; Following values are set by MapSector.
128 Sector
DB 0 ; Sector - zero based
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
139 DCB EQU
ST0 ; Fixed disk Device Control Block
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
150 BiosSeg GROUP
Code,BiosInit
152 Code SEGMENT BYTE PUBLIC 'CODE'
156 EXTRN BUGBITS
:BYTE,DPRINTF
:NEAR
162 Floppy DeviceStruc
<>
165 ;* Per drive information, including BPBs
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
186 Frestor
= 1 ; restore needed
187 Fmotoron
= 2 ; motor is on
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
200 ; Structure of parameter block for floppy pointed to by 0:4*1E
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
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
219 ScratchBuffer
DB 512 DUP(?
) ; Scratch buffer for when DMA fails
220 ; Hope we don't handle >512 sector
223 ;* Miscellaneous data
225 Single
DB 0 ; non-zero if 1 floppy disk system
226 ; in this case, NumFloppy will be 2
228 SUBTTL
Data for interface to
4.0
231 EXTRN DosFunction
:DWORD ; Addr of DOS function routine
233 ; Dos helper functions used by disk driver
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
240 int_savregs
= 32H
; interrupt routine which saves all regs
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
254 test wchan
,SEM_BUSY
;;semaphore busy?
256 or wchan
,SEM_WANT
;;say we want it
261 call [DosFunction
] ;;wait till semaphore released
263 l2: or wchan
,SEM_BUSY
;;claim semaphore
269 test wchan
,SEM_WANT
;;anyone waiting on semaphore?
273 mov dx,ContinueProcess
275 l: and wchan
,NOT (SEM_WANT
+SEM_BUSY
)
279 FloppyQueue
DD 0 ; List of requests for floppy
280 FixedQueue
DD 0 ; List of requests for fixed disk
282 ; Device driver headers
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
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
303 ; Utility routines which reside in the BIOS main module
305 EXTRN Interrupt
:NEAR ; BIOS interrupt routine(misnomer)
307 EXTRN StatusDevReady
:NEAR
308 EXTRN StatusComplete
:NEAR
309 EXTRN StatusError
:NEAR
316 FloppyRequest PROC
FAR
317 debug
4,2,<FloppyRequest
, es:bx $x
:$x
, cmd
$d\n>,<es,bx,<word ptr es:[bx.RqCmd
]>>
319 LEA SI,FloppyFunction
; 4.0 function routines
320 JMP Interrupt
; Let BIOS figure out what to do
323 ; Dispatch table for actions of the floppy requested by 4.0
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
344 FixedRequest PROC
FAR
345 debug
8,2,<FixedRequest
, es:bx $x
:$x
, cmd
$d\n>,<es,bx,<word ptr es:[bx.RqCmd
]>>
347 LEA SI,FixedFunction
; 4.0 function routines
348 JMP Interrupt
; Let BIOS figure out what to do
351 ; Dispatch table for actions of the hard disk requested by 4.0
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
373 SUBTTL
Data for routines that make direct
Int 13 requests
377 RealInt13Vec dw 0 ; Used to make Int 13 requests
379 OldIntDVec dw 0 ; Must be reset when Int 13's on hard
381 OldIntEVec dw 0 ; Must be reset when Int 13's on floppy
383 SemDiskIO db 0 ; Semaphore controlling disk io
384 SemInt13 db 0 ; Semaphore controlling Int 13's
387 SUBTTL
4.0 device driver routines
(system
entry points
)
390 BiosInit
SEGMENT PARA
PUBLIC 'CODE'
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.
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:
410 ;**************************************************************
412 debug
12,1,<Performing disk driver pre
-DOS initialization
\n>,<>
417 INT 11H
;GET EQUIPMENT STATUS
418 rol al,1 ; rotate around to low order bits
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
426 MOV [NumFloppy
],AL ;Remember how many drives
429 INT 13H
;Request number of hardfiles attached
430 JC ENDDRV
;Carry indicates old rom, so no hardfile
432 test dl,dl ; any specified?
434 cmp NumFloppy
,2 ; too many floppies?
436 mov NumFloppy
,2 ; limit to two floppies max.
439 ;* Initialize the hard disk BPBs
445 CALL SETHRD
;SET UP FIRST HARDFILE
447 MOV DL,81H
;SET UP FOR NEXT CALL
458 SETIT: CALL SETHRD
;SET UP SECOND HARDFILE
462 cmp [NumFixed
],0 ; any hard disks found?
464 mov ax,[FixedDevice
] ; no, patch device chain to skip fixed disk
465 mov [FloppyDevice
],ax
467 push es ; Install Int 13 handler and save the
468 xor ax,ax ; old value of the interrupt vector.
471 mov [RealInt13Vec
],ax
472 mov ax,OFFSET Int13Handler
475 mov [RealInt13Vec
+2],ax
477 mov ax,es:[4*0dh] ; Save original Int D vector
480 mov [OldIntDVec
+2],ax
481 mov ax,es:[4*0eh] ; Save original Int E vector
484 mov [OldIntEVec
+2],ax
490 ; READ A BOOT RECORD INTO Scratch buffer
497 mov BX,OFFSET ScratchBuffer
501 CMP WORD PTR ES:[BX+1FEH
],0AA55H
505 ; SETUP VARIABLE SIZED HARDFILE
506 ; ON ENTRY DL=DRIVE NUMBER (80 OR 81)
510 MOV AH,8 ;GET DRIVE PARAMETERS
513 MOV BYTE PTR [DI].BPBnhead
,DH
517 MOV BYTE PTR [DI].BPBtrksiz
,CL
518 CALL GETBOOT
;GET THE BOOT RECORD
522 SET1: CMP BYTE PTR ES:[BX],1
526 SETRET: STC ;NOT FOUND SO USE DEFAULTS
527 debug
8,3,<Sethrd
err rtn
: drive $x stat $x
\n>,<dx,ax>
530 SET2: MOV AX,ES:[BX+4]
531 MOV DS:[DI].BPBhidsec
,AX ;SET HIDDEN SECTOR COUNT
533 CMP AX,64 ;HAS TO BE AT LEAST 32K
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
556 CMP AX,32680 ;NOT 32768! MAX NUMBER OF CLUSTERS=4085
564 ; DX=NUMBER OF DIR ENTRIES, CH=NUMBER OF SECTORS PER CLUSTER
565 ; CL=LOG BASE 2 OF CH
567 ; NOW CALCULATE SIZE OF FAT TABLE
569 MOV [DI].BPBndir
,DX ;SAVE NUMBER OF DIR ENTRIES
570 MOV [DI].BPBsecpau
,CH ;SAVE SECTORS PER CLUSTER
575 SHR BX,CL ;DIVIDE BY SECTORS/CLUSTER
577 AND BL,11111110B ;MAKE SURE COUNT IS EVEN
580 ADD BX,SI ;MULTIPY BY 1.5
583 MOV BYTE PTR [DI].BPBnfatsec
,BH ;SAVE NUMBER OF FAT SECTORS
584 MOV [DI].BPBmediab
,0F8H ; set media byte
589 ASSUME
CS:BiosSeg
,DS:NOTHING
,ES:NOTHING
592 debug
4,3,<Diskette initialization
>,<>
593 push ds ; install floppy interrupt routine
596 mov ax,OFFSET FloppyInterrupt
613 debug
8,3,<Hard disk initialization
>,<>
614 push ds ; install fixed disk interrupt routine
617 mov ax,OFFSET FixedInterrupt
621 in al,21H
; unmask fixed disk interrupts
624 mov dx,HD_PMSK
; set interrupt and DMA mask bits
630 iniret: debug
12,3,< - Num
=$x BPB table
=$x
:$x
\n>,<ax,cs,di>
637 mov ah,byte ptr es:[di]
639 bpbret: mov [bx.RqMedia
],ah
641 mov [bx.RqCount
+2],CS
646 mov ah,byte ptr es:[di]
651 ;*** FloppyCheck - check to see if the disk may have been changed.
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
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
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
680 MOV BYTE PTR DS:[BX].RqAddr
,DL
681 JMP StatusComplete
; Return whether media changed
689 ;*** FloppyRead, FloppyWrite, FloppyWriteV - Basic I/O entry points
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.
697 ; ENTRY DS:BX Packet address
698 ; ES:DI Transfer address
704 ; EXIT DS:BX Packet Addr
705 ; CX # of sectors left to do
709 FloppyRead
LABEL NEAR
710 FloppyWrite
LABEL NEAR
712 debug
4,2,<Fl
rd/wt
/ver Req $x
:$x unit
$b sec
$d nsec
$d\n>,<ds,bx,ax,dx,cx>
715 call FDGetBPB
; cs:di => BPB
717 add si,cx ; compute last sector + 1
718 cmp si,cs:[di.BPBnsec
]
722 mov al,8 ; ERROR - Sector not found
725 flrw1: OR CX,CX ; Anything to do?
727 JMP StatusComplete
; No, all done now
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
735 pop es ; ES:BX = Request addr
738 LEA SI,FloppyQueue
; DS:SI = ptr to head of queue
740 CALL DosFunction
; Add request to list
742 pop ds ; Back to DS:BX is request
744 cli ; interrupts off while testing state
745 TEST Floppy
.Flags
,Factive
; Is driver active?
746 JNE FloppyActive
; Yes, driver will get to it
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
753 POP DS ; Restore regs
754 flrw4: test DS:[BX].RqStatus
,0100H ; IO completed?
755 JNZ FloppyIOdone
; yes
758 MOV AX,DS ; AX:BX = request
762 CALL DosFunction
; Block until I/O is done
764 jmp flrw4
; test completion status again
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
775 FixedWrite
LABEL NEAR
777 debug
8,2,<Fix
rd/wt
/ver Req $x
:$x unit
$b sec
$d nsec
$d\n>,<ds,bx,ax,dx,cx>
780 call HDGetBPB
; cs:di => BPB
782 add si,cx ; compute last sector + 1
783 cmp si,cs:[di.BPBnsec
]
787 mov al,8 ; ERROR - Sector not found
790 fxrw1: OR CX,CX ; Anything to do?
792 JMP StatusComplete
; No, all done now
796 pop es ; ES:BX = Request addr
799 LEA SI,FixedQueue
; DS:SI = ptr to head of queue
801 CALL DosFunction
; Add request to list
803 pop ds ; Back to DS:BX is request
805 cli ; interrupts off while testing state
806 TEST Fixed
.Flags
,Factive
; Is driver active?
807 JNE FixedActive
; Yes, driver will get to it
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
814 POP DS ; Restore regs
815 fxrw4: test DS:[BX].RqStatus
,0100H ; IO completed?
816 JNZ FixedIOdone
; yes
819 MOV AX,DS ; AX:BX = request
823 CALL DosFunction
; Block until I/O is done
825 jmp fxrw4
; test completion status again
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
834 ;*** CheckWrap - check whether a request crosses a 64Kb boundary
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.
842 ; ENTRY DS:BX Request header
843 ; ES:DI Transfer address
844 ; CS:SI Pointer to BPB
846 ; EXIT When it's safe to proceed.
853 mul cs:[si.BPBsecsiz
]
854 mov dx,es ; compute offset
858 clc ; now see if offset+nbytes overflows
861 debug
12,10h
,<CheckWrap $x $x
:$x
>,<ax,es,di>
863 SemWait ScratchBufSem
; wait for ScratchBuffer to be available
872 ;*** FloppyChange - check whether floppy disk must be changed
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.
886 ; ENTRY DS:BX Pointer to I/O request
896 SemWait SwapSem1
; Currently waiting to switch disk?
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
912 popf ; restore interrupt state
914 ADD AL,"A" ; Convert to drive letter
915 MOV CS:DriveLetter
,AL ; Set the letter
924 OR AL,AL ; End of message?
926 INT 29H
; No, output char
927 JMP flcha4
; Put out whole msg
930 mov ah,1 ; Flush keyboard input
934 INT 16H
; Wait for a char
940 SemSig SwapSem1
; Allow blocked processes to continue
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
956 Int13Handler Proc
Far
957 push dx ; Save regs used in local processing
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.
967 mov bx,offset SemInt13
973 mov SemInt13
,1 ; Lock out other disk requests
978 cmp SemDiskIO
,0 ; If the disks are busy, block this
979 jz DiskFree
; process till they free up.
981 mov bx,offset SemDiskIO
989 pop ax ; Restore regs for call
997 call dword ptr [RealInt13Vec
]
1001 mov ax,cs ; Unblock anything that is waiting
1002 mov bx,offset SemInt13
1003 mov dx,ContinueProcess
1005 popf ; Restore user regs
1014 SUBTTL Fixed disk startup routine
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
1023 FixedDispatch
LABEL WORD
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
1039 MOV BX,Fixed
.State
; Get current state
1040 debug
8,4,<FxEx state
$d >,<bx>
1042 JMP FixedDispatch
[BX] ; Dispatch to correct routine
1045 ;* Fixed state Start
1047 ; Do setup calculations to figure out sector, start
1048 ; up motor, advance to Calc state.
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?
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
1067 ; Calculate cylinder, head and sector, wait for motor
1068 ; start or head load, advance to Select state.
1070 ; Entered after Start state and also on further sectors of a multiple sector
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
1082 mov Fixed
.DCB
,HD_CREAD
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
1092 mov Fixed
.DCB
+1,al ; set head/unit
1094 mov Fixed
.DCB
+3,al ; set low cylinder
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?
1105 mov al,Done
; assume next state is Done
1106 test Fixed
.Flags
,Fverify
1109 fxxc3: mov BYTE PTR Fixed
.State
,al ; set next state
1113 ;* Fixed state Verify
1115 ; Have executed a write function, must now verify.
1116 ; BUGBUG For now just go to done state.
1119 mov Fixed
.State
,Done
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.
1133 AND AL,Fwrite
+Fwrap1
; Only interested in these bits
1134 CMP AL,Fwrap1
; Just read into scratch?
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
1142 REP MOVSB ; Copy into real buffer
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
1157 mov SI,OFFSET FixedQueue
; DS:SI = head of queue
1164 ; Nothing hapenning, become inactive.
1167 and Fixed
.Flags
,NOT Factive
1171 ;* Fixed state Error
1173 ; Entered when a non-recoverable error is detected.
1174 ; A sense block has been requested and put into the
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
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?
1190 mov ah,ds:[bx+1] ; translate error code
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>
1200 LES DI,FixedQueue
; Get ptr to request
1203 MOV ES:[DI].RqStatus
,AX ; Set error and code
1205 JMP fxxd3
; Advance to Done state
1208 ;* Traslation of controller error codes to DOS error codes
1210 HDErrType
DW HDErrTyp0
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
1220 ASSUME
CS:BiosSeg
,DS:NOTHING
,ES:NOTHING
1222 FixedInterrupt PROC
FAR
1223 debug
8,8,<FxIntr
\n>,<>
1224 cmp word [SemDiskIO
],0001h
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.
1231 ;; in al,21H ; Mask fixed disk interrupts
1235 call dword ptr [OldIntDVec
]
1236 in al,21H
; Unmask fixed disk interrupts
1239 mov dx,HD_PMSK
; set interrupt and DMA mask bits
1244 TEST Fixed
.Flags
,Factive
; device active?
1245 JZ fxinret
; no, go away
1246 INT int_savregs
; save registers
1248 in al,dx ; get status reg.
1252 ;; out dx,al ; turn off intr. and DMA.
1253 ;; test ah,02h ; error bit set?
1254 test al,02h ; error bit set?
1256 ;* error occurred. see if retry, else get error code.
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
1265 fxin0: mov Fixed
.DCB
,HD_CSENS
; send sense command
1266 xor al,al ; reset intr. & DMA masks
1270 mov di,OFFSET Fixed
.DCB
1272 fxin1: call HDWaitReq
; get the sense block back
1277 mov Fixed
.State
,Error
1280 fxin4: CALL FixedExecute
1282 MOV AL,20H
; send EOI to 8259
1288 SUBTTL Floppy disk startup routine
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
1298 FloppyDispatch
LABEL WORD
1314 MOV BX,Floppy
.State
; Get current state
1315 debug
4,4,<FlEx state
$d >,<bx>
1317 JMP FloppyDispatch
[BX] ; Dispatch to correct routine
1320 ;* Floppy state Start
1322 ; Do setup calculations to figure out sector, start
1323 ; up motor, advance to Calc state.
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?
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
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
1344 ;* Floppy state Calc
1346 ; Calculate cylinder, head and sector, wait for motor
1347 ; start or head load, advance to Select state.
1349 ; Entered after Start state and also on further sectors of a multiple sector
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
1366 ;* Floppy state Select
1368 ; Recalibrate the drive if needed. If Seek is
1369 ; needed, start it and advance to Seek state. Otherwise advance to Settle
1374 OR [BX].DrvFlag
,Fmotoron
; we've been selected, so motor is on
1375 TEST [BX].DrvFlag
,Frestor
; Is a restore needed?
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
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
1387 call SetTimer2
; set sanity timer
1388 RET ; Done until interrupt on seek done
1392 ;* Floppy state Recal
1394 ; If error, set state is Error. Else, load drive
1395 ; specs into controller and advance to Select state.
1399 OR AX,AX ; Error in recal?
1402 CALL Spec765
; Load drive specs
1403 MOV Floppy
.State
,Select
; Back to select state now
1408 ;* Floppy state Seek
1410 ; If error, advance to Error state. Otherwise, wait
1411 ; for head to settle and advance to Settle state.
1414 CALL Sense765
; Get status of seek
1415 OR AX,AX ; Any error?
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
1425 MOV Floppy
.State
,Settle
; Next state is Settle
1427 CALL GetFloppyParam
; Get the settle time in Msecs
1429 CALL SetTimer1
; Set the timer
1435 ;* Floppy state Settle
1437 ; Start the read/write request and advance to the RdWri state.
1440 MOV Floppy
.State
,RdWri
; Advance to read/write state
1441 CALL RdWr765
; Start the I/O
1443 call SetTimer2
; set sanity timer
1444 RET ; Done until floppy interrupt
1448 ;* Floppy state RdWri
1450 ; If error, next state is Error. Otherwise next state is Done.
1453 CALL Fini765
; Get status of I/O
1454 OR AX,AX ; Any error?
1456 MOV Floppy
.State
,Error
; Yes, go to error state
1460 MOV Floppy
.State
,Done
; I/O is done
1465 ;* Floppy state Done
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.
1474 AND AL,Fwrite
+Fverify
+Fwrap1
; Only interested in these bits
1475 CMP AL,Fwrap1
; Just read into scratch?
1476 JNE DoneNotWrap
; No
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
1483 REP MOVSB ; Copy into real buffer
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
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
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
1509 mov di,OFFSET Floppy
1510 mov SI,OFFSET FloppyQueue
; DS:SI = head of floppy queue
1515 ;* Floppy state Idle
1517 ; Nothing hapenning except possible motor off timeout.
1521 CALL SetTimer2
; Set the motor timer
1522 and Floppy
.Flags
,NOT Factive
1523 SemSig SwapSem2
; someone waiting to switch drive?
1527 ;* Floppy state Error
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.
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
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?
1550 MOV BL,6 ; Bad seek?
1553 MOV BL,4 ; CRC error?
1556 MOV BL,8 ; Sector not found?
1559 MOV BL,0 ; Write protect?
1562 MOV BL,12 ; Catch-all error
1564 debug
4,4,<FD error
: status $x
code $b\n>,<ax,bx>
1566 LES DI,FloppyQueue
; Get ptr to request
1569 MOV ES:[DI].RqStatus
,AX ; Set error and code
1571 JMP flxd3
; Advance to Done state (via shortcut)
1576 ASSUME
CS:BiosSeg
,DS:NOTHING
,ES:NOTHING
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.
1586 call dword ptr [OldIntEVec
]
1589 TEST Floppy
.Flags
,Factive
; device active?
1590 JZ flinret
; no, go away
1591 INT int_savregs
; save registers
1594 MOV AL,20H
; send EOI to 8259
1598 FloppyInterrupt ENDP
1600 SUBTTL Timing routines for floppy disk
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
1610 MOFFDELAY
= 2 ; turn off motor after 2 sec. inactivity
1612 ;*** SetTimer1 - Arm timer 1
1614 ; SetTimer1 will arm the Timer1. Input parameter
1615 ; values in milliseconds will be converted to timer
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
1625 TEST AX,AX ; zero count?
1630 sett10: DIV TimerConv
1631 TEST AH,AH ; remainder?
1633 INC AL ; yes, round up
1634 sett11: MOV Timer1
,AL
1636 debug
4,8,<SetTimer1
$b\n>,<ax>
1641 ;*** SetTimer2 - Arm timer 2
1643 ; SetTimer2 will set a motor off timeout for the
1644 ; drive whose parameter block is pointed to by
1647 ; ENTRY CS:BX = pointer to per drive info.
1654 MOV Timer2
,Timer2Count
1656 sett21: MOV CS:[BX].Timer
,MOFFDELAY
1657 debug
4,8,<SetTimer2
\n>,<>
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.
1669 ; It's assumed that all registers have been saved by the
1672 ASSUME
CS:BiosSeg
,DS:NOTHING
,ES:NOTHING
1675 FloppyTimer PROC
FAR
1676 TEST TimerActive
,0ffH ; any timers active?
1678 RET ; no, return quickly
1679 fltim1: TEST TimerActive
,1 ; Timer1 active?
1681 DEC Timer1
; Timer1 expired?
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.
1689 fltim3: TEST TimerActive
,2 ; Timer2 active?
1691 DEC Timer2
; 1 Hz clock time?
1695 debug
4,8,<Timer
2 expired
\n>,<>
1696 MOV BL,Timer2count
; reload the counter
1699 ;* Perform Timer2 service
1700 XOR CH,CH ; No active timeouts seen
1701 XOR DI,DI ; Start with drive A
1705 MOV BX,FDinfo
[BX] ; Get ptr to drive info
1706 TEST CS:[BX].DrvFlag
,Fmotoron
; motor on?
1708 CMP CS:[BX].Timer
,0 ; Is timer active for drive?
1710 DEC CS:[BX].Timer
; Yes, another tick has passed
1712 cmp di,Floppy
.Current
; Current drive?
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
1722 AND CS:[BX].DrvFlag
,NOT Fmotoron
; stop drive motor
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
1734 OUT DX,AL ; Turn off motor
1735 ;; cmp di,Floppy.Current ; Current drive?
1737 ;; test Floppy.Flags,Factive ; device active
1738 ;; jz fltim8 ; no, go on to next drive
1739 ;; call DumpRegs ; oops, sanity timeout
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?
1747 AND TimerActive
,NOT 2 ; No, clear timeout is active
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.1
ah],[di.1
ch],[di.1eh
]>
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>,<>
1775 debug
4,0fh,< $b $b $b\n>,<ax,bx,cx>
1776 debug
4,0fh,<765 status
, data\n>,<>
1782 debug
4,0fh,< $b $b\n>,<bx,ax>
1788 SUBTTL Routines shared between Floppy
and Hard disk drivers
1791 ;*** Setup - Set request parameters into local structure.
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
1799 ; Other fields are copied from the DOS request packet.
1801 ; ENTRY SI Pointer to device variables
1802 ; ES:BX Current request
1807 ; EXIT The following variables are set
1809 ; [SI].First The hidden sectors are added
1814 ASSUME
CS:BiosSeg
,DS:BiosSeg
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
1840 ;*** MapSector - compute head, sector, cylinder
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).
1853 ; ENTRY SI Pointer to device variables
1854 ; ES:BX Current request
1858 ; EXIT The following variables are set
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
1876 ; Calculate the head, cylinder and sector of the start of the request
1881 DIV [DI].BPBtrksiz
; Divide by sectors/track
1883 MOV [SI].Sector
,DL ; Set sector to start at
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
>>
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.
1894 MOV AX,[DI].BPBtrksiz
1895 SUB AL,[SI].Sector
; AL = # of sectors left on
1896 ; track after desired.
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
1903 MOV [SI].Numsectors
,AX ; Set number to do this time
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.
1909 MOV AX,WORD PTR([SI].Addr
+2)
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
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
1924 ; If we got here, no sectors can be transferred before the 64K
1925 ; boundary. One sector must be transferred through a scratch buffer.
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
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
1939 MOV ES,AX ; ES:DI = scratch buffer
1940 mov cx,[SI].NumBytes
1941 LDS SI,[SI].RealAddr
; DS:SI = Data buffer
1943 REP MOVSB ; Copy the write buffer
1954 ;*** DMAsetup - Set the DMA channel up to do the I/O
1956 ; ENTRY AL = DMA mode
1957 ; AH = DMA channel number (2 or 3 only)
1958 ; SI = pointer to device parameters
1966 OUT PDMA
+10,AL ; set channel's mask bit
1967 OUT PDMA
+12,AL ; clear byte pointer F/F
1969 push ax ; restore AH, AL
1970 OR AL,AH ; add channel number to command
1971 OUT PDMA
+11,AL ; Set DMA mode
1975 MOV AX,WORD PTR [SI].Addr
+2 ; Get segment of addr
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
1984 OUT DX,AL ; Output high byte of address
1985 inc dx ; address `word' count register
1986 MOV AX,[SI].NumBytes
; # bytes in request
1990 OUT DX,AL ; Tell DMA how many bytes
1991 pop ax ; get back channel number
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
2002 ;*** DoneRequest - Mark a request complete, setup to start next one
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.
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
2020 MOV [DI].ErrCnt
,0 ; Reset error count
2021 MOV [DI].State
,Idle
; Assume will be idle
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
2035 test [DI].Flags
,Fwrap2
; had this request used ScratchBuffer?
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
2047 mov bx,offset SemDiskIO
2048 mov dx,ContinueProcess
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
2061 ; Input: AH = Media byte
2064 ; Output: CS:DI = Pointer to BPB
2066 ASSUME
DS:NOTHING
,ES:NOTHING
2074 MOV CL,AH ; Copy media value
2075 AND CL,0F8H ; Look at just top 5 bits
2076 CMP CL,0F8H ; Valid media byte?
2078 MOV AH,0FEH ; No, make it 8 sector 1 sided
2080 MOV BL,AL ; Get pointer to per drive info.
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
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
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
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
2124 ; Input: AL = Drive number
2126 ; Output: CS:DI = Pointer to BPB
2128 ASSUME
DS:NOTHING
,ES:NOTHING
2132 MOV BL,AL ; Get pointer to per drive info.
2135 MOV DI,CS:HDinfo
[BX]
2141 ASSUME
DS:NOTHING
,ES:NOTHING
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.
2153 mov bx,offset SemInt13
2168 SUBTTL Routines that interface to hard disk controller
2171 ;*** HDCommand - send a command to the hard disk controller
2173 ; HDCommand will send the previously set up command block
2174 ; to the hard disk controller.
2176 ; ENTRY AL = value to be put in interrupt/DMA mask
2177 ; EXIT AL = status port value
2181 mov dx,HD_PSEL
; point to select port
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
2188 hdcom1: in al,dx ; get status
2190 cmp al,0DH ; test for busy, command/data, request
2192 mov si,OFFSET Fixed
.DCB
2195 dec dx ; point to data port
2200 ;; mov cx,10 ;BUGBUG - timing prob. w/ expansion box?
2201 ;;hdcom3: loop hdcom3 ;BUGBUG - timing prob. w/ expansion box?
2206 ;*** HDWaitReq - wait for request bit in status register
2208 ; HDWaitReq will pause until the request bit in the hard disk
2209 ; status register is set.
2212 ; EXIT AL = status byte
2218 test al,01h ; request bit?
2222 SUBTTL Routines that interface to floppy disk controller
2225 ;*** GetDrivePtr - compute ptr to per drive info.
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.
2231 ; EXIT BX = pointer to per drive table
2235 mov bx,cs:Floppy
.Current
2237 mov bx,cs:FDinfo
[bx]
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.
2246 ; Input: AL = parameter desired (see FloppyParam structure)
2248 ; Output: AL = parameter byte desired
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
2267 ; Recalibrate the current drive. Clear Restore flag, set cylinder to
2268 ; unknown and issue command to controller.
2270 ; Destroys: AX,BX,DX
2274 AND CS:[BX].DrvFlag
,NOT Frestor
; Have restored drive
2275 MOV CS:[BX].CurCyl
,-1 ; Flag don't know where we are
2277 CALL Put765
; Put out reset command
2278 MOV AX,Floppy
.Current
; Get current drive
2279 CALL Put765
; Tell controller which drive
2284 ; Reset the controller.
2286 ; Destroys: AX,CX,DX
2290 MOV AL,CS:Floppy
.DOR
2298 MOV CS:Floppy
.DOR
,AL ; Update value
2304 ; Load the drive specs into the controller.
2322 ; Get the interrupt status from the controller and into AX
2324 ; Destroys: AX,CX,DX
2328 MOV AL,FD_CSENSE
; Get status
2330 CALL Get765
; Read ST0
2331 PUSH AX ; Save status
2332 CALL Get765
; Read PCN (present cylinder number)
2333 POP AX ; Restore status
2335 SHR AL,CL ; Shift bits down
2336 AND AX,3 ; Leave only error bits
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.
2346 ; Destroys: AX,BX,CX,DX
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
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
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
2366 OUT DX,AL ; ? For some reason output value again
2367 CLC ; Clear carry, don't have to wait
2371 MOV AL,NOT(3) ; Drive select is low 2 bits
2372 AND AL,Floppy
.DOR
; Lose old select bits
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
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
2383 OUT DX,AL ; Load the head
2384 MOV AX,DelayLoad
; Load head delay
2389 OR Floppy
.DOR
,AL ; Add in motor start bit
2391 OUT DX,AL ; Start the motor
2393 CALL GetFloppyParam
; Get the proper delay time in 1/8 sec
2395 mul cl ; convert to milliseconds
2396 CALL SetTimer1
; Set timer for motor startup
2401 ; Seek to the correct cylinder. Set carry if have to wait for operation
2402 ; to complete (we are not on right cylinder).
2404 ; Destroys: AX,BX,DX
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
2413 CALL Put765
; Seek command
2414 MOV AL,Floppy
.Head
; Get head desired
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
2420 TEST Floppy
.Flags
,F2step
; Need to double step?
2421 JE SeekNoDouble
; No
2422 ADD AX,AX ; Yes, double cylinder number
2424 CALL Put765
; Give controller the cylinder
2425 STC ; Set carry, must wait for seek intr.
2432 ; Start the Read/write. Set up the DMA channel and give a read or write
2433 ; command to the controller depending on flag.
2435 ; Destroys: AX,CX,DX
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
2450 CALL DMAsetup
; Set DMA up for write
2451 MOV AL,FD_CWRITE
; Want to write
2453 CALL Put765
; Put out command
2456 ADD AL,AL ; Form HHxx Binary
2457 ADD AL,BYTE PTR Floppy
.Current
; Form HHUU
2458 CALL Put765
; Output unit and head
2460 CALL Put765
; Output cylinder
2462 CALL Put765
; Output head again?
2463 MOV AL,Floppy
.Sector
2465 CALL Put765
; Output sector
2467 CALL GetFloppyParam
; Get sector size code
2468 CALL Put765
; Tell controller sector size
2470 CALL GetFloppyParam
; Get number of sectors/cylinder
2471 CALL Put765
; Tell controller
2472 MOV AL,DataGap
; Gap length for read/write
2474 CALL Put765
; Tell controller gap length
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
2485 ; Fini765 gets the completion status.
2487 ; Destroys: AX,CX,DX
2496 mov di,OFFSET Floppy
.ST0
2504 AND AX,3 ; Mask down to value to return
2512 ; Put765 writes a command to the controller.
2519 PUSH AX ; Save the value to write
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
2528 OUT DX,AL ; Put out value
2533 ; Get765 gets a value back from the controller into AL.
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
2546 IN AL,DX ; Get value from controller