; []===========================================================[] ; ; NOTICE: THIS PROGRAM BELONGS TO AWARD SOFTWARE INTERNATIONAL(R) ; INC. IT IS CONSIDERED A TRADE SECRET AND IS NOT TO BE ; DIVULGED OR USED BY PARTIES WHO HAVE NOT RECEIVED ; WRITTEN AUTHORIZATION FROM THE OWNER. ; ; []===========================================================[] ; ;---------------------------------------------------------------------------- ;Rev Date Name Description ;---------------------------------------------------------------------------- ;R29A 03/17/98 KVN Don't process it if DL is over 80h that will cause some ; M/B (2A432I59) boot error from LS120.this time are none ; any HDD ;R14D 01/12/98 KVN Modify R14B coding mistake for same bug fixed correctly ;R14C 01/06/98 KVN Fixed qaplus disk change test fail by R14B ;R30 12/17/97 KVN Dont access floppy if controller be disabled by user ; password ;R14B 11/05/97 KVN Dont report error code 06h(media changed) if FDD 3 mode ; be disable to fix a INT13.EXE test program ;R29 05/01/97 KVN Add LS120 bootable even floppy A exist ;R28 02/01/97 KVN Support IOMEGA ZIP-100 drive active ;R27A 01/24/97 KVN Fixed R27 coding mistake ;R27 01/22/97 KVN Support dual LS120 drive active ;R26 11/01/96 KVN Added LS-120 support ;R25 09/05/96 LAW Added "FORCE_XSPEED_IN_ADISK" define for fixed run ; OS2 "Boot other DOS from A: disk" error ;R24A 08/20/96 LAW Fixed format disk error in QA5xx utility format disk ;R24 07/23/96 LAW Fixed set FDD 3 mode to do format 1.44MB disk error ;R23 07/19/96 KVN Fixed test disk write protect fail in QA529 ;R04A 07/08/96 KVN Fixed software swap A and B drive format error ;R21B 06/07/96 KVN Fixed can't format 1024 bytes/sector use 1024fmt.exe ; utility because this program will call reset floppy ; but DL above 80h (0A3h) then BIOS must return no error ;R22 05/24/96 RCH Move non run-time code to new file MISC.ASM to get ; more space in F8000-FFFFF area ;R21A 05/14/96 KVN Fixed Triton mother board with WDC-AC2850F HDD then HDD ; access error (maybe hang at EMM386.EXE or can't boot) ;R21 04/22/96 KVN Fixed excute [AIC ASPI manager v-3.63] driver in config.sys ; when HDD is none and boot from floppy then system hang ;R20 03/20/96 KVN Fixed format wrong when enable swap floppy function ;R19 03/14/96 KVN Fixed read floppy disk spent a long time when this disk ; is bad ;R18 01/23/95 RAY To prevent some FDD verify error under system over 133Mhz ;R17 01/18/96 RCH The IBM 486 class CPU already gone, so kill that codes ;R16 11/03/95 KVN Added floppy 3 mode 1.2Mb format ;R14A 09/11/95 KVN Added floppy 3 mode standard code FDD3MODE.SIO ;R15 09/06/95 KVN Added floppy write protect function ;R14 09/04/95 KVN Added floppy 3 mode auto switch ;R13 08/09/95 RCH Don't call "Wait_For_Pie" for FDD motor spin up, ; because OS2 failed with FDD access. ;R12 06/20/95 KVN Fixed code mistake ;R11 06/13/95 KVN Reduce Post_func_call and F000_call code size ;R10 05/08/95 KVN Add CD-ROM bootable feature ;R09 12/16/94 RCH Don't hardcode for IODELAY , because some chipset ; use port 0e1H. ;R08 10/18/94 RCH Added alignment for all procedures ;R07 04/26/94 KVN Fixed HT-2000 IDE VL-bus+HT-2000 driver and run ET ; system then floppy can't access. ;R06 01/26/94 KVN Added FDD performance. ;R04 12/05/93 KVN Add swap A and B drive function. ;R03 09/01/93 RAY Add PM hooks as standard features ;R02 08/27/93 KVN When media is 2.88MB must set 3f7h port to high density. ; Set FDC_FIFO_THRES is '0dh'. ;R01 05/28/93 DNL Added IBM 486DLC3 CPU support ;R100 04/22/93 RAY Flush CPU cache if it is IBM CPU ;R00 02/10/93 KVN Recover command "VERIFY" to command "READ". ; ; NOTE: The following items should be defined ; in BIOS.CFG for 2.88 support. ; ; ENABLE_288_SUPPORT EQU 1 ; ENABLE_FDC_FIFO EQU 1 ; (2.88 needs FIFO to avoid slow DMA errors) ; FDC_FIFO_THRES EQU 0dh ; (FIFO threshold set to mid value) ; ; CMOS_FD_288 EQU 5 ; (CMOS value for 2.88, can be changed) ; (FORCE_1MB_CMOS EQU 1) ; (to force first drive to 2.88 for debug) ; ; (FORCE_1MB_PARMS EQU 1) ; (to force 2.88 parms for 1 mbs for debug) ; PAGE 63,132 TITLE ADISK -- FLOPPY DISK AT ROM BIOS .386 ENABLE_288_SUPPORT EQU 1 ENABLE_FDC_FIFO EQU 1 ; (2.88 needs FIFO to avoid slow DMA errors) FDC_FIFO_THRES EQU 0dh ; (FIFO threshold set to mid value) CMOS_FD_288 EQU 5 ; (CMOS value for 2.88, can be changed) ; +---------------+ ; | | ; | FLOPPY DISK | ; | | ; +---------------+ ;PORT DEFINITIONS ; ; o Diskette interface consists of NEC 765 and a digital output register, ; digital input register and diskette control register. ; I/O Ports 3F4-3F5 for NEC 765 ; I/O Port 3F2 for DOR ; I/O Port 3F7 for DCR and DIR ; o Digital output register signals ; Bit 5 Drive 1 motor enable (true) ; Bit 4 Drive 0 motor enable (true) ; Bit 3 NEC 765 DMA and interrupt enable (true) ; Bit 2 T/C to NEC 765 ; Bit 0 Drive 0 select (false) ; o Digital input register signals ; Bit 7 Selected drive has diskette change (true) ; Bit 6 Hard Disk Write Gate enable (true) ; Bit 5 Hard Disk Head 3 Select/Reduced Write Current (true) ; Bit 4 Hard Disk Head 2 Select (true) ; Bit 3 Hard Disk Head 1 Select (true) ; Bit 2 Hard Disk Head 0 Select (true) ; Bit 1 Hard Disk Drive 1 Select (true) ; Bit 0 Hard Disk Drive 0 Select(true) ; o Diskette control register ; Bit 0-1 Data transfer rate for drive (0 is 500K, 1 is 300K, ; 2 is 250K). ;DATA LOCATIONS AT 0: ;Byte 0:43EH is the diskette seek status. Low 4 bits indicate drive is ;to be recalibrated on next seek operation when 0 (bit 0 is drive 0, ;bit 1 is drive 1 etc.). When bit 7 set, interrupt is complete. When ;bit 7 not set, interrupt pending. ; ;Byte 0:43FH is motor status. If bit 0-1 on then drive motor 0-1 is running. ;Bits 4-5 on indicate drive select for drives 0-1. ; ;Byte 0:440H is time out value to turn drive off. Counted down by timer ;tick routine (See 1AH interrupt). ; ;Byte 0:441H is last diskette status code. ; ;Byte 0:442-448H is the NEC 765 result codes from last operation. See NEC 765 ;specs for details. ; ;Byte 0:48BH is the data transfer byte. Bits 6-7 contains the last ;data transfer rate sent to the controller. Bits 2-3 contain ;the first data transfer rate we attempt an operation in. This is ;used to keep track of how many times we retry an operation when the ;state is not determined. ; ;Byte 0:48FH is the physically determined drive capability byte. It ;is divided into two nibbles, with the lower nibble representing drive 0 ;and the upper nibble representing drive 1. The lowest bit of the nibble ;says whether this drive has 40 or 80 track capability (0=40 track, ;1=80 track). The next bit tells us whether the drive is capable of ;performing operations at more than one data rate. If set, then this ;means we have either a 1.2 Meg drive or a 1.44 Meg drive. The next ;bit tells us whether the previous bit is valid or not. ; ; ;Byte 0:490H is diskette drive 0 media state. Bits 6-7 indicate data transfer ;rate (0 is 500K, 1 is 300K, 2 is 250K, 3 is reserved). Bit 5 set means ;double stepping on tracks. Bit 4 set means media/drive is known. Bit 3 is ;reserved. Bits 2-0 indicate present drive state (0 is 360K media in 360K ;drive unestablished, 1 is 360K media in 1.2M drive unestablished, 2 is ;1.2M media in 1.2M drive unestablished, 3 is 360K media in 360K drive ;established, 4 is 360K media in 1.2M drive established, 5 is 1.2M media ;in 1.2M drive established, 7 indicates none of the above or cannot ;be determined.) Bits 2-0 are really only here to maintain compatiblity ;with the old AT. The values in them should not be relied on by the bios. ; ;Byte 0:491H is diskette drive 1 media state. See above for details. ; ;Byte 0:492H is original media state tried in transfer for drive 0. ; ;Byte 0:493H is original media state tried in transfer for drive 1. ; ;Word 0:494H is current cylinder number for drive 0. ; ;Word 0:495H is current cylinder number for drive 1. ;[]------------------------------------------------------------------------ ;Name: Disk_IO_Reset ;Entry: INT 13H ;Input: ah=0 ; dl=0-1 for all diskettes ; dl=80-81H for all hard disks ;Output: none ;Description: ; ;Disk_IO_Reset will: ;1. save environment ;2. Indicate drives need recalibration. Reset controller. Update ; memory values. For hard disk reset drive parameters and recalibrate ; drive. ;3. restore environment ;4. return to POI ;[]------------------------------------------------------------------------ ;[]------------------------------------------------------------------------ ;Name: Disk_IO_Status ;Entry: INT 13H ;Input: ah=1 ; dl=0-1 for diskette ; dl=80-81H for hard disk ;Output: al=status ; Values are: ; CCH write fault on drive ; BBH unknown error occured ; AAH drive not ready ; 80H time out ; 40H bad seek ; 20H bad controller ; 11H data corrected on transfer ; 10H bad ECC or CRC ; BH bad track found ; AH bad sector flag found ; 9H dma boundary error (transfer across 64K bank) ; 8H bad dma transfer occured ; 7H drive failed ; 6H media removed ; 5H reset failed ; 4H sector not found ; 3H write attempted on write protected media ; 2H data address mark not found ; 1H bad command ; 0H no error found ;Description: ; ;Disk_IO_Status will: ;1. save environment ;2. Return indicated status byte. ;3. restore environment ;4. return to POI ;[]------------------------------------------------------------------------ ;;[]------------------------------------------------------------------------ ;Name: Disk_IO_Read ;Entry: INT 13H ;Input: ah=2 ; al=number of sectors ; dl=drive number (0-1 for diskette, 80-81H for hard disk) ; dh=head number ; ch=cylinder number - low 8 bits ; cl=sector number - bits 0-5 ; bits 6-7 are high 2 cylinder bits ; es:bx=transfer address ; ;Output: ah=status (see above) ; cy=1 if error, cy=0 if ok. ;Description: ; ;Disk_IO_Read will: ;1. save environment ;2. Check DMA boundary conditions, setup DMA chip for transfer. Read in ; requested number of sectors starting at ES:BX. Update data values at ; 0:4??H as needed. ;3. restore environment ;4. return to POI ;[]------------------------------------------------------------------------ ;[]------------------------------------------------------------------------ ;Name: Disk_IO_Write ;Entry: INT 13H ;Input: ah=3 ; al=number of sectors ; dl=drive number (0-1 for diskette, 80-81H for hard disk) ; dh=head number ; ch=cylinder number - low 8 bits ; cl=sector number - bits 0-5 ; bits 6-7 are high 2 cylinder bits ; es:bx=transfer address ; ;Output: ah=status (see above) ; cy=1 if error, cy=0 if ok. ;Description: ; ;Disk_IO_Write will: ;1. save environment ;2. Check DMA boundary conditions,setup DMA chip for transfer. Write out ; requested number of sectors starting at ES:BX. Update data values at ; 0:4??H as needed. ;3. restore environment ;4. return to POI ;[]------------------------------------------------------------------------ ;[]------------------------------------------------------------------------ ;Name: Disk_IO_Verify ;Entry: INT 13H ;Input: ah=4 ; al=number of sectors ; dl=drive number (0-1 for diskette, 80-81H for hard disk) ; dh=head number ; ch=cylinder number - low 8 bits ; cl=sector number - bits 0-5 ; bits 6-7 are high 2 cylinder bits ; ;Output: ah=status (see above) ; cy=1 if error, cy=0 if ok. ;Description: ; ;Disk_IO_Verify will: ;1. save environment ;2. see hard disk spec. ;3. Verify the requested number of sectors. Update data values 0:4??H as ; needed. ;4. return to POI ;[]------------------------------------------------------------------------ ;[]------------------------------------------------------------------------ ;Name: Disk_IO_Format ;Entry: INT 13H ;Input: ah=5 ; al=number of sectors ; dl=drive number (0-1 for diskette, 80-81H for hard disk) ; dh=head number ; ch=cylinder number - low 8 bits ; cl=sector number - bits 0-5 ; bits 6-7 are high 2 cylinder bits ; es:bx=transfer address ; if hard drive then es:bx points to 512 byte buffer with ; n pairs of {f,s}. ; where n is number of sectors ; f is flag 0 is good sector, 80H is bad sector ; s is sector number ; if diskette drive then es:bx points to 512 byte buffer ; n pairs of (c,h,s,l) ; where n is number of sectors ; c is cylinder number ; h is head number ; s is sector number ; l is sector length (l = 0 is 128, l = 1 is 256 ; l = 2 is 512, l = 3 is 1024). ;Output: ah=status (see above) ; cy=1 if error, cy=0 if ok. ;Description: ; ;Disk_IO_Format will ;1. save environment ;2. Check DMA boundary conditions,setup DMA chip for transfer. Format ; track given sector pattern starting at ES:BX. Update data values at ; 0:4??H as needed. ;3. restore environment ;4. return to POI ;[]------------------------------------------------------------------------ ;[]------------------------------------------------------------------------ ;Name: Disk_IO_BADC ;Entry: INT 13H ;Input: ah=6,7,E,F,12,13H ;Output: al=1, cy=1 ;Description: ; ;Disk_IO_BADC will: ;1. save environment ;2. see hard disk spec. ;3. return bad command status and update bytes at 0:4??H as needed. ;4. return to POI ;[]------------------------------------------------------------------------ ;[]------------------------------------------------------------------------ ;Name: Disk_IO_Change_Line ;Entry: INT 13H ;Input: ah=16H ; dl=drive (0-1) ;Output: ah=0,cy=0 disk change line not active ; =6,cy=1 disk change line active ; ah=1,cy=1 drive out of bounds ;Description: ;Determine if media has been removed since last operation on specified ;drive. ; ;Disk_IO_Change_Line will ;1. save environment ;2. If drive in bounds then set ah as indicated above else set error. ; Set data values at 0:4??H as needed. ;3. restore environment ;4. return to POI ;[]------------------------------------------------------------------------ PAGE ; minimize segment 0 access in protected mode (exception 5) SEG_0 SEGMENT USE16 AT 1 INCLUDE SEG_0.INC SEG_0 ENDS G_RAM SEGMENT USE16 AT 40H INCLUDE G_RAM.INC G_RAM ENDS ifdef PM_SUPPORT ;128K extrn PM_After_FDD:near ;128K extrn PM_Before_FDD:near ;128K endif; PM_SUPPORT ;128K .XLIST INCLUDE BIOS.CFG INCLUDE CMOS.EQU INCLUDE 82077.EQU INCLUDE ADISK.EQU INCLUDE COMMON.EQU INCLUDE SETSPEED.EXT INCLUDE ATORGS.EXT INCLUDE COMMON.MAC IFDEF POWER_MANAGEMENT INCLUDE PM_GEN.EXT ENDIF ;POWER_MANAGEMENT .LIST DGROUP GROUP FCODE ;R08 FCODE SEGMENT USE16 DWORD PUBLIC 'CODE' FCODE SEGMENT USE16 PARA PUBLIC 'CODE' ;R08 ASSUME CS:DGROUP INCLUDE ADISK.INC PAGE ;[]---------------------------------------------------------------------- ; ;DISKIO: Main entry point for disk io. ; The values in the registers will be put onto the stack and ; made addressable via the BP register. This structure ; will be called the BP_REGISTERS. ; ; BP_REGISTERS are put on the stack in the following order: ; ; FLAGS [bp+22] ; CS RETURN VALUE [bp+20] ; IP RETURN VALUE [bp+18] ; SI [bp+16] ; DS [bp+14] ; ES [bp+12] ; DI [bp+10] ; DX [bp+8] ; CX [bp+6] ; BX [bp+4] ; AX [bp+2] ; BP [bp+0] ; ; SEGMENT REGISTERS: ; CS and DS point to the ROM, 0F000h ; ES will be set to 40h, to access the data area. ; DS INTERNAL POINT TO 0 FOR vectors 303c ; SS points to the stack. ; ; ; Maintenance guidelines: ; REGISTER AND STACK USAGE: ; There are 2 things to be concerned with: ; 1. Register protection ; 2. Access to BP_REGISTERS ; ; There are 4 levels of procedures: ; Level 1: Entry procedure, DISKIO ; Level 2: Function procedures: DISKIO_XFER, etc. ; Level 3: High level Service procedures: NEC_SEEK, for example ; Level 4: Low level service procedures: GET_CURRENT_MEDIA, etc. ; ; Different rules apply to each level: ; Level 1 is the entry point to the system. It knows ; about the BP_REGISTERS structure, and may access ; and change it. DISKIO is the only procedure ; that has permission to change the BP_AH register and ; BP_FLAGS on BP_REGISTERS. ; ; Level 2 procedures are the major functions. They ; are only called once per INT 40h. They also know ; about BP_REGISTERS and may access any of them. They ; do not have permission, however, to change BP_AH ; and BP_FLAGS. This should only be done by DISKIO. ; These routines do not protect any registers except ; for the SEGMENT and BP registers. ; ; Level 3 procedures are large general purpose procedures. ; These routines do not know about BP_REGISTERS because ; May be called from places outside INT 40h, so ; the BP_REGISTERS structure may not be there, and they ; also may be called multiple times, sometimes after ; values in BP_REGISTERS have been changed by Level 1 and ; Level 2 procedures. ; ; Because Level 3 procedures are large, and may ; use many registers, they do not attempt to protect ; any registers except the SEGMENT and BP registers. ; The calling procedure has the responsibility of protecting ; any values in registers it needs to preserve. Calling ; procedures should protect registers if the level ; 3 procedure they are calling does not currently destroy ; that register. This way level 3 procedures can be ; rewritten without affecting the calling procedures. ; ; Level 4 procedures are small, frequently called procedures ; desgined to save code space. Arguments should be passed ; through registers for the same reasons as in level 3. ; All registers that are not part of the interface however, ; will be protected by these procedures. Therefore it is not ; necessary to push registers in the calling procedures, ; unless they are also used by the called procedure to return ; values. ; ;[]------------------------------------------------------------------------- PAGE PUBLIC DISKIO ; * ATORGS.ASM ALIGN 4 DISKIO PROC NEAR ;R03 IFDEF POWER_MANAGEMENT ;R03 call PM_Set_Critical ; inclrment critical setction ;R03 ENDIF ;POWER_MANAGEMENT ; semaphore ;R03 IFDEF PM_DISK_TRIGGER ;R03 EXTRN SET_DISK_TRIGGER:NEAR ;R03 CALL SET_DISK_TRIGGER ;R03 ENDIF ;PM_DISK_TRIGGER ;R03 - Start ifdef PM_SUPPORT ;128K extrn PM_Before_FDD:near ;routine in PMU.ASM call PM_Before_FDD endif; PM_SUPPORT ;R03 - End STI ;R10 start ;R26IFDEF CD_ROM ;;;ifdef ATAPI_COMMAND_SUPPORT ;R26 if ATAPI_COMMAND_SUPPORT eq 1 ;;; ;------------------- check for CD emulation of A -------------- push ds push ax mov ax,G_RAM mov ds,ax ;DS = BIOS data area(40:0) assume ds:G_RAM and byte ptr G_RAM:[CDROM_ALLOCATE],not Change_Floppy_Number ;R29 ;R26 start mov al,byte ptr G_RAM:[ATAPI_Byte] test al,4 ;ZIP or LS120 drive installed ? jz short @F ;no , check CD-ROM mov ah,al ;AH = ATAPI_Byte ;R27 shr al,3 ;check ATAPI emulation drive No. and al,1 ;only drive No. A: or B: cmp al,dl ;drive No. match ? je short Go_Std_Atapi;yes, access ATAPI drive ;no, it may be FDD or CD-ROM access ;R27 start test ah,8 ;ATAPI emulate drive B ?;R27A jnz short @F ;yes,check CD-ROM ;R27A ;R28 shr ah,6 ;R28 and ah,1 ;R28 cmp ah,dl ;R28 je short Go_Std_Atapi test ah,30h ;R28 check ATAPI drive 1 exist? jnz short Go_Std_Atapi;R28 Yes,go ATAPI subroutine ;R27 end or dl,dl ;R29 access drive A? jnz short Go_Std_Floppy;R29 No,skip @@: ;R26 end ;Check if CD-ROM existed and emulated as drive A mov al,byte ptr G_RAM:[CDROM_ALLOCATE] and al,0fh shr al,2 ;bit3-2 = CD-ROM emulation No. cmp al,CD_DRVA ;emulating drive A? ;R26 pop ax ;R26 pop ds jne short no_cd ;not emulate drive A ;yes, emulate drive A cmp dl,0 ;access drive A? jne short @F ;not for CD-ROM access ; calling drive 0 (the CD) extrn std_atapi:near Go_Std_Atapi: ;R26 pop ax ;R26 pop ds ;R26 call std_atapi ;ATAPI service routine retf 2 ; discard flags ; calling drive 1 (the real floppy) @@: Go_Std_Floppy: ;R29 ;mark flag for FDD access due to ATAPI device existed or byte ptr G_RAM:[CDROM_ALLOCATE],Change_Floppy_Number ;R29 ;R29 dec dl no_cd: ;R26ENDIF ; CD_ROM pop ax ;R26 pop ds ;R26 endif ;ATAPI_COMMAND_SUPPORT ;R26 ;R10 end PUSH SI PUSH DS PUSH ES PUSH DI CLD ;R04 start ;Logically swap floppy drive A & B if user enable this feature ;in CMOS setup push ax ;save function No. mov ax,G_RAM mov ds,ax ;DS = BIOS data area (40:0) ASSUME ds:G_RAM ;R29 start cmp dl,80h ;for hard drive access ?;R29A jae short Not_Floppy ;yes, don't swap FDD ;R29A ;Change logical FDD drive number if the system was boot from ATAPI ;device , like LS120 , ZIP/100 or CD-ROM emluated as drive A: test byte ptr G_RAM:[CDROM_ALLOCATE],Change_Floppy_Number jz short @F ;boot from ATAPI ? ;yes, input DL = 1 for FDD 0 ; = 2 for FDD 1 dec dl ;adjust drive No. for FDD ;INT 13H access. @@: ;R29 end ;Check if FDD swap is enabled or not test byte ptr FDD_VERIFY_CMD_FLAG,SWAP_DRIVE jz short @F ;no swap xor dl,1 ;swap drive No. for FDD @@: Not_Floppy: ;R29A pop ax ;restore function No. ;R04 end PUSH DX PUSH CX PUSH BX PUSH AX MOV AX,CS MOV DS,AX ASSUME DS:DGROUP ; dgroup must be here MOV AX,G_RAM ; variables. MOV ES,AX ; ES for addressing data area ASSUME ES:G_RAM ; STAYS IN EFFECT THROUGH CODE ; SEG_0 ifndef FORCE_XSPEED_IN_ADISK ;R25 test CS:[SYSTEM_BYTE],02H JNZ SHORT OPTION_NFS ; 1 IS NO SWITCH endif ;FORCE_XSPEED_IN_ADISK ;R25 XOR AL,AL ; default to low speed ;R12 POST_FUNC_CALL XSPEED ; do it CALL XSPEED ;R12 OPTION_NFS: ;R17 ;R100 Starts ;R17 push di ;R17 mov di,offset @F ;R17 jmp Invalidate_IBM_Cache ;R17 @@: ;R17 pop di ;R17 ;R100 Ends PUSH BP MOV BP,SP OR BP_FLAGS,200H ; SET INT FLAG ON BECAUSE OF ; DOS CODE AT 70:XXXX ;R30 start mov ah,ST_OK test byte ptr G_RAM:[HARDWARE],1 ;have any floppy drive? jz D_LEGAL_FUNCTION ;None any drive then skip ;R30 end ;R21A cmp BP_DRIVE,80h ;R21 ;R21A jae D_ILLEGAL_FUNCTION ;R21 jump, its illegal CMP BP_OPCODE,1 JA SHORT D_NOT_FUNC_0_OR_1 ; function > 2, then jump JE SHORT D_FUNC_1 ; function == 1, then jump ; else fall thru to zero. ;FUNCTION 0: Reset drives. MOV G_RAM:[FD_OP_RESULT],0 ; clear previous errors. CALL RESETDRIVES ; reset the drives JMP short D_COPY_STATUS ; exit to caller. D_FUNC_1: ; FUNCTION 1: Get status of last operation. MOV AH,G_RAM:[FD_OP_RESULT] ; previous status to ah JMP short D_COPY_STATUS ; exit to caller. D_NOT_FUNC_0_OR_1: MOV G_RAM:[FD_OP_RESULT],0 ; functions >2 all ; clear previous errors CMP BP_OPCODE,5 ; if function >5 JA SHORT D_NOT_0_TO_5 ; jump ;FUNCTIONS 2-4: Read/write/verify MOV BX,OFFSET DGROUP:DISK_IO_XFER ; assume 2,3,4 JB SHORT D_NORMAL_CASE ;FUNCTION 5, format. MOV BX,OFFSET DGROUP:DISK_IO_FORMAT ; its format. JMP SHORT D_NORMAL_CASE D_NOT_0_TO_5: CMP BP_OPCODE,8 ; function 8? JNE SHORT D_NOT_8 ; jump if not ;FUNCTION 8: requires special handling because it ;still returns information if drive is ;out of range. Also wipes out BP_DRIVE parameter on stack. MOV AL,BP_DRIVE PUSH AX ; save drive # CALL DISK_IO_GET_PARMS POP BX ; recover drive # PUSH AX ; save results MOV AL,BL ; al=drive # CALL FAKE_UP_MEDIA_BYTE POP AX ; recover results JMP SHORT D_CHECK_CARRY ; doesn't copy error code ; to FD_OP_RESULTS D_NOT_8: MOV BL,BP_OPCODE XOR BH,BH CMP BL,18H ; function >18h ;R55 JA SHORT D_ILLEGAL_FUNCTION ; jump, its illegal JA D_ILLEGAL_FUNCTION ; jump, its illegal ;R55 SUB BX,15H ; reduce function for table JB D_ILLEGAL_FUNCTION ;128k ;128k JB SHORT D_ILLEGAL_FUNCTION ; illegal if 6,7,9-14h SHL BX,1 ; word index MOV BX,FUNC_15_TO_18[BX] ; get proc address D_NORMAL_CASE: CMP BP_DRIVE,1 ; routines 2-5 and 15-18 all JA D_ILLEGAL_FUNCTION ; range check drive. JMP BX ; "virtual" call to save stack ALIGN 4 D_NORMAL_RET: ; space. All procedures "ret" ; by jmping to d_normal_ret PUSH AX ; save RESULTS MOV AL,BP_DRIVE CALL FAKE_UP_MEDIA_BYTE ; 0:490,491, low bits for comp. POP AX ; recover RESULTS CMP BP_OPCODE,015H ; function 15h's value in ah JE SHORT D_CLEAR_CARRY ; is NOT an error code. D_COPY_STATUS: ;R21A start cmp BP_OPCODE,0 ;R21B je D_LEGAL_FUNCTION ;R21B test BP_DRIVE,80h jz D_LEGAL_FUNCTION mov ah,ST_BADCMD D_LEGAL_FUNCTION: ;R21A end MOV G_RAM:[FD_OP_RESULT],AH ; record results in case ; next call is function 1. D_CHECK_CARRY: OR BP_FLAGS,+1 ; assume error.MASM5 REMOVED OR AH,AH ; if AH is zero, indicate JNZ SHORT D_FLAGS_SET ; okay by clearing carry flag D_CLEAR_CARRY: AND BP_FLAGS,0FFFEH ; else clear flags.MASM5 REMOVED D_FLAGS_SET: DISKIO_EXIT: MOV BP_RET_CODE,AH ; put Ah on stack, so it will ; be popped off. MOV AL,2 ; shorten motor count so CALL GET_PARM ; so motor will shutoff in 2 MOV G_RAM:[MOTOR_OFF_WAIT],AL ; rather than 14 seconds. ifndef FORCE_XSPEED_IN_ADISK ;R25 test CS:[SYSTEM_BYTE],02H JNZ SHORT OPTION_NFS1 endif ;FORCE_XSPEED_IN_ADISK ;R25 MOV AX,G_RAM ; retrieve speed G_RAM MOV DS,AX ASSUME DS:G_RAM XOR AL,AL ; assume slow speed TEST INIT_ERR_FLG,80H ; speed switch JZ SHORT SET_SP MOV AL,1 ; set hi speed SET_SP: ;R12 POST_FUNC_CALL XSPEED CALL XSPEED ;R12 OPTION_NFS1: ;R17 ;R100 Starts ;R17 mov di,offset @F ;R17 jmp Invalidate_IBM_Cache ;R17 @@: ;R17 ;R100 Ends MOV SP,BP ; not necessary, but leave in ; in case we want to add local ; variables in future. POP BP ; recover bp POP AX POP BX POP CX POP DX ;R04 start push ax mov ax,G_RAM mov ds,ax ;DS = BIOS data area(40:0) ;R29;R10 start ;R29;R26IFDEF CD_ROM ;R29ifdef ATAPI_COMMAND_SUPPORT ;R26 ;R29 mov al,byte ptr G_RAM:[CDROM_ALLOCATE] ;R29 and al,0fh ;R29 shr al,2 ;R29 cmp al,CD_DRVA ; emulating drive A? ;R29 jne short @F ;R29 inc dl ;R29@@: ;R29;R26ENDIF ;CD_ROM ;R29endif ;ATAPI_COMMAND_SUPPORT ;R26 ;R29;R10 end ;restore drive No.(DL) if FDD swap is enabled test byte ptr FDD_VERIFY_CMD_FLAG,SWAP_DRIVE jz short @F xor dl,1 ;restore drive No. @@: ;R29 start ;;;ifdef ATAPI_COMMAND_SUPPORT if ATAPI_COMMAND_SUPPORT eq 1 ;;; ;restore drive No.(DL) if any ATAPI device emulate drive A: test byte ptr G_RAM:[CDROM_ALLOCATE],Change_Floppy_Number jz short @F inc dl ;restore drive No. @@: endif ;ATAPI_COMMAND_SUPPORT ;R29 end ASSUME ds:NOTHING pop ax ;R04 end POP DI POP ES POP DS POP SI ;R03 - Start ifdef PM_SUPPORT ;128k extrn PM_After_FDD:near call PM_After_FDD endif; PM_SUPPORT ;R03 - End ;R03 IFDEF POWER_MANAGEMENT ;R03 call PM_Clr_Critical ; Decrement critical setction ;R03 ENDIF ;POWER_MANAGEMENT ; semaphore ;R03 IFDEF PM_DISK_TRIGGER ;R03 EXTRN CLR_DISK_TRIGGER:NEAR ;R03 CALL CLR_DISK_TRIGGER ;R03 ENDIF ;PM_DISK_TRIGGER IRET ASSUME DS:DGROUP ; BUG FROM XSPEED D_ILLEGAL_FUNCTION: MOV AH,1 ; error code ;R29 JMP short D_COPY_STATUS JMP D_COPY_STATUS ;R29 DISKIO ENDP PAGE ;!!!!!!!!!!!!!! LEVEL 2 PROCEDURES: The Function calls !!!!!!!!!!!!!!!! ;[]--------------------------------------------------------------------------- ;These procedures have permission to read any of BP_REGISTERS. They ;can also change any BP_REGISTERS except BP_OPCODE,BP_RET_CODE and BP_FLAGS ;These procedures can destroy any registers except BP and Segment registers. ;[]--------------------------------------------------------------------------- ALIGN 4 DISK_IO_XFER PROC NEAR ; SEG_0 MOV AL,BP_DRIVE ; get drive CALL GET_DCAPABILITY ; is there a drive? OR AH,AH JNZ SHORT DIX_MARK_OPERATION ; jump if drive present, MOV AH,ST_TIMEOUT ; if no drive, return timeout. JMP DIX_FAILURE DIX_MARK_OPERATION: AND G_RAM:[MOTOR_ON_IND],NOT 80H ; assume read CMP BP_OPCODE,3 ; is it actually a write? JNE SHORT DIX_START_ENGINES ;R15 start ifdef Support_FDD_Write_Protect test G_RAM:[POST_FLAG],Fdd_Wt_Protect_Status jz short @F mov AH,ST_WRITEPROT ; was in place. JMP DIX_FAILURE @@: endif ;Support_FDD_Write_Protect ;R15 end OR G_RAM:[MOTOR_ON_IND],80H ; mark as write ; for TURNONMOTOR routine. DIX_START_ENGINES: PUSH AX ; save drive CALL TURNONMOTOR ; turn on motor and wait ; if not already on. POP AX ; recover drive. CALL GET_CURRENT_MEDIA TEST AH,010H ; determined? JNZ SHORT DIX_CHECK_DCL ; no retries if determined CALL SET_UP_RETRIES ; prepare xfer rates for ; retries DIX_CHECK_DCL: MOV G_RAM:[MOTOR_OFF_WAIT],0FFH ; keep motor spinning if this ; is a retry. CALL GET_DCAPABILITY ; if forty track drive, TEST AH,01H ; don't check DCL, in JZ SHORT DIX_DCL_OK ; case it's an old controller. CALL READ_AND_CLEAR_DCL ; check the dcl ; note: destroys al OR AH,AH ; exit if active JZ SHORT DIX_DCL_OK JMP DIX_FAILURE ; abort operation if disk ; change line was active, ; if we could clear it. DIX_DCL_OK: ;----Prepare and send a SPECIFY command to controller---- XOR AL,AL CALL GET_PARM MOV BL,AL ; FIRST SPECIFY BYTE - DF MOV AL,1 CALL GET_PARM MOV BH,AL ; SECOND SPECIFY BYTE - 02 MOV AL,BP_DRIVE CALL GET_CURRENT_MEDIA AND AH,0C0H ; isolate xfer rate. IFDEF ENABLE_288_SUPPORT CMP AH,0C0H ; check 1MB JE short DIX_SPEC_1M ; skip if so OR AH,AH ; else set flags on xfer rate ENDIF ;ENABLE_288_SUPPORT JNZ SHORT DIX_SPECIFY ; if not 500 KBS, use default. DIX_SPEC_1M: CALL GET_CMOS_DRIVE ; else if cmos says drive 4 CMP AH,4 JNE SHORT DIX_SPECIFY MOV BL,0AFH ; use 0AFh as 1st specify DIX_SPECIFY: PUSH BX ; parameters on stack MOV SI,SP ; pointer to parameters MOV AH,NC_SPECIFY ; specify command MOV BL,NC_LEN_SPECIFY ; 3 bytes in specify command. CALL SEND_COMMAND ; output specify command POP BX ; clear parameters off stack. OR AH,AH ; error? JZ SHORT DIX_SET_XFER_RATE ; if no error, continue JMP DIX_CHECK_ERROR ; see if error should abort ; operation, or move us to ; next transfer rate. DIX_SET_XFER_RATE: MOV AL,BP_DRIVE ; drive to al CALL RESET_XFER_RATE ; choose appropriate xfer rate CALL CHECK_DSTEP ; see if we need double OR AH,AH ; stepping. directly updates JZ SHORT DIX_SEEK JMP DIX_CHECK_ERROR ; current_media. DIX_SEEK: MOV AL,BP_DRIVE ; get drive MOV AH,BP_CYLINDER ; logical cylinder CALL NEC_SEEK ; position head over cylinder OR AH,AH JZ SHORT DIX_SET_UP_DMA JMP DIX_CHECK_ERROR DIX_SET_UP_DMA: ;xfer size calculation: ;size of xfer = SECTORS * 128 * 2^N, where N comes from ;user parameter table. ; 128 = 2^7 ; so size of xfer = SECTORS * 2^7 * 2^N. ; = SECTORS * 2^(7+N) ; = SECTORS left-shifted 7+N MOV AL,3 ; get "N", as in 128*2^N CALL GET_PARM MOV CL,AL ; move to shift count reg. ADD CL,7 ; add 7 shifts for 128 MOV AL,BP_AL ; get # of sectors. XOR AH,AH ; in ax. SHL AX,CL ; every shift = times 2 DEC AX ; DMA controller wants ; count - 1 PUSH AX ; store xfer size on stack. PUSH BP_ES ; store segment PUSH BP_OFFSET ; store offset. MOV BL,BP_OPCODE XOR BH,BH SUB BX,2 MOV AL,DGROUP:DIX_DMA_TABLE[BX] MOV SI,SP CALL DMA_SETUP ADD SP,6 ; clear the stack. OR AH,AH JZ SHORT DIX_PREPARE_OPERATION JMP short DIX_CHECK_ERROR DIX_PREPARE_OPERATION: MOV AL,6 ; get DTL, byte 9 of CALL GET_PARM ; command. MOV BH,AL ; get gap length, byte 8 MOV BL,01BH ; assume 500 kbs xfer rate MOV AL,BP_DRIVE CALL GET_CURRENT_MEDIA AND AH,0C0H JZ SHORT DIX_GOT_GAP_LEN IFDEF ENABLE_288_SUPPORT CMP AH,0C0H ; check 1 mbs xfer rate JE SHORT DIX_GOT_GAP_LEN ;skip if so ENDIF ;ENABLE_288_SUPPORT MOV BL,02AH ; gap length for 300, 250 kbs DIX_GOT_GAP_LEN: PUSH BX ; bytes 9 and 8 on stack. MOV AL,4 ; get "EOT", last track, from CALL GET_PARM ; user parameter table. IFDEF FORCE_1MB_EOT CALL GET_CURRENT_EOT ; modify EOT in al as necessary ENDIF ;FORCE_1MB_EOT MOV BH,AL MOV AL,3 ; get "N", sector size, from CALL GET_PARM ; user parameter table. MOV BL,AL PUSH BX ; push bytes 7 and 6 on stack. MOV BH,BP_SECTOR ; get "R", starting track. MOV BL,BP_HEAD ; get "H", the head: DO NOT ; range check these-- copy protect ; schemes. PUSH BX ; push bytes 5 and 4 of command MOV BH,BP_CYLINDER ; get "C",cylinder, don't range check. MOV BL,BP_HEAD ; get head AND BL,01H ; range check it. SHL BL,2 OR BL,BP_DRIVE ; or in drive, it is already ; range checked. PUSH BX ; push bytes 3 and 2 of command. MOV AH,NC_READ ;R00 ; assume a read or verify command CMP BP_OPCODE,03H ;R00 ; is it a write JNE SHORT DIX_SEND_COMMAND ;R00 MOV AH,NC_WRITE ;R00 ; change to a write command DIX_SEND_COMMAND: MOV BL,NC_LEN_RW MOV SI,SP ; pointer to rest of parameters. Send_Verify_para: ;R00 CALL SEND_COMMAND ADD SP,8 ; clear stack OR AH,AH JNZ SHORT DIX_CHECK_ERROR DIX_GET_RESULTS: CALL WAIT_FOR_RESULTS ; wait for interrupt, read status DIX_CHECK_ERROR: OR AH,AH ; see if error JZ SHORT DIX_SUCCESS CMP AH,80H ; if timeout, abort operation. JE SHORT DIX_FAILURE CMP AH,09H ; if DMA boundary error, abort JE SHORT DIX_FAILURE ; operation CMP AH,3 ;R23 if write protect then dont retry JE SHORT DIX_FAILURE ;R23 MOV BH,AH ; save error MOV AL,BP_DRIVE CALL GET_CURRENT_MEDIA TEST AH,010H ; determined MOV AH,BH ; recover error JNZ SHORT DIX_FAILURE CALL PREPARE_RETRY ; ah unchanged if no more retries OR AH,AH ; else ah=0 if more retries. JNZ SHORT DIX_FAILURE JMP DIX_CHECK_DCL DIX_FAILURE: MOV BP_AL,0 ; no sectors xferred. JMP SHORT DIX_EXIT ; DIX_SUCCESS: MOV AL,BP_DRIVE CALL UPDATE_MEDIA_INFO ; see if we learned anything MOV CX,BP_SEC_CYL ; cx=starting sector, cylinder MOV DH,BP_HEAD ; dh=starting head CALL CALC_XFER_SIZE ; new about drive capabilities MOV BP_AL,AL ; or current media. XOR AH,AH ; successful operation. DIX_EXIT: JMP D_NORMAL_RET DISK_IO_XFER ENDP IFDEF ENABLE_288_SUPPORT align 4 ;R08 GET_CURRENT_EOT PROC NEAR PUSHA ; save regs MOV AL,BP_DRIVE CALL GET_CURRENT_MEDIA AND AH,0C0H ; isolate data rate field. CMP AH,0C0H ; check 1 mbs JE SHORT GET_EOT_FORCE ; skip if so to force EOT POPA ; else restore entry registers CLC ; signal not 1 mbs RET ; and return no action GET_EOT_FORCE: POPA ; restore entry registers MOV AL,24H ; and force 36 sectors for 1 mbs trnasfer rate STC ; signal 1 mbs RET ; and return new value GET_CURRENT_EOT ENDP ENDIF ;ENABLE_288_SUPPORT PAGE ;[]----------------------------------------------------------------------- ;[]----------------------------------------------------------------------- align 4 ;R08 DISK_IO_FORMAT PROC NEAR MOV AL,BP_DRIVE ; see if a drive is there CALL GET_DCAPABILITY OR AH,AH JNZ SHORT DIF_CHECK_IF_SET MOV AH,ST_TIMEOUT ; if not, return timeout JMP DIF_EXIT ; error. DIF_CHECK_IF_SET: CALL GET_CURRENT_MEDIA TEST AH,010H JNZ SHORT DIF_MEDIA_SET PUSH AX ; save drive CALL GUESS_AT_MEDIA POP AX ; recover drive. DIF_MEDIA_SET: OR G_RAM:[MOTOR_ON_IND],80H PUSH AX CALL TURNONMOTOR ; turn on motor and wait POP AX ; if not already on. CALL GET_DCAPABILITY ; If 40 track drive, TEST AH,1 ; then don't test DCL. JZ SHORT DIF_SEND_SPECIFY CALL READ_AND_CLEAR_DCL OR AH,AH JZ SHORT DIF_SEND_SPECIFY JMP DIF_EXIT ; return with error in ah. DIF_SEND_SPECIFY: ;R24 - start ifdef FDD_3_Mode pusha ;R24A mov al,FloppyB_3_mode cmp byte ptr BP_DRIVE,1 je short @F mov al,FloppyA_3_mode @@: test G_RAM:FDD_VERIFY_CMD_FLAG,al ;detect set 3 mode jz short @F ;No,jmp disable 3 mode mov al,BP_DRIVE ;detect 1.2Mb fdd set call get_cmos_drive cmp ah,2 mov al,1 ;enable FDD_3_Mode je short do_set_3_mode @@: xor al,al ;Disable 3 mode do_set_3_mode: call Set_FDD_3_mode popa ;R24A endif; FDD_3_Mode ;R24 - end ; send a specify command, using external parameter table. MOV BX,DS ; save ds MOV CX,SEG_0 MOV DS,CX ; CX DESTROYED IN SEND_COMMAND ASSUME DS:SEG_0 LDS SI,SEG_0:[DISK_PARM_PTR] ; DS NOW REPLACED PUSH DS:[SI] ; push 1st and 2nd specify MOV DS,BX ; recover ds. ASSUME DS:DGROUP MOV SI,SP ; pointer to args MOV AH,NC_SPECIFY ; specify command MOV BL,NC_LEN_SPECIFY ; 3 byte command CALL SEND_COMMAND ; send it, DESTROYS CX POP BX ; clear stack. OR AH,AH JZ SHORT DIF_SPECIFY_COMPLETE JMP DIF_EXIT DIF_SPECIFY_COMPLETE: MOV AL,BP_DRIVE CALL RESET_XFER_RATE ; SET UP DMA ; xfer size calculation: ; size of xfer = SECTORS * 4, since each sector has a ; 4 byte field. MOV AL,4 ; get EOT parameter. CALL GET_PARM SHL AX,2 ; multiply by 4. DEC AX ; minus 1 for DMA PUSH AX ; store xfer size on stack. PUSH BP_ES ; store segment on stack. PUSH BP_OFFSET ; store offset on stack. MOV SI,SP ; point to parameters. MOV AL,04AH ; write command for DMA CALL DMA_SETUP ADD SP,6 ; clear the stack. OR AH,AH ; exit if boundary error. JZ SHORT DIF_DMA_PREPARED JMP DIX_EXIT DIF_DMA_PREPARED: ; SEEK TO TRACK MOV AL,BP_DRIVE MOV AH,BP_CYLINDER CALL NEC_SEEK OR AH,AH JZ SHORT DIF_ON_CYLINDER JMP DIF_EXIT DIF_ON_CYLINDER: MOV BX,DS ; SEND COMMAND MOV CX,SEG_0 MOV DS,CX ASSUME DS:SEG_0 LDS SI,SEG_0:[DISK_PARM_PTR] ; REPLACES DS, SEG0 NO MORE ASSUME DS:NOTHING PUSH DS:[SI+8] ; store filler byte on stack. ; its byte 6 of command, the last. MOV AH,DS:[SI+7] ; get format gap length, byte 5 MOV AL,DS:[SI+4] ; get "EOT", byte 4. PUSH AX ; push bytes 5 and 4 on stack. MOV AH,DS:[SI+3] ; get "N", sector size, byte 3. MOV DS,BX ; recover ds ASSUME DS:DGROUP MOV AL,BP_HEAD ; get head/drive select AND AL,01H ; range check head SHL AL,2 OR AL,BP_DRIVE ; byte 2 PUSH AX ; push bytes 3 and 2 on stack MOV SI,SP ; pointer to parameters. MOV AH,NC_FORMAT ; format command. MOV BL,NC_LEN_FORMAT ; 6 parameters CALL SEND_COMMAND ; DESTROYS CX ADD SP,6 ; clear stack OR AH,AH JNZ SHORT DIF_EXIT DIF_GET_RESULTS: CALL WAIT_FOR_RESULTS ; wait for interrupt, read status DIF_EXIT: JMP D_NORMAL_RET ; ah=0 or error code. DISK_IO_FORMAT ENDP PAGE ;[]--------------------------------------------------------------------------- ;[]--------------------------------------------------------------------------- align 4 ;R08 DISK_IO_GET_PARMS PROC NEAR ; SEG_0 MOV AL,BYTE PTR G_RAM:HARDWARE TEST AL,1 JNZ SHORT DIGP_SOME_DRIVES XOR AL,AL ; no drives JMP SHORT DIGP_CHECK_DRIVE DIGP_SOME_DRIVES: ROL AL,2 ; bit 6 to bit 0. AND AL,01H ; isolate INC AL ; 0->1, 1->2 DIGP_CHECK_DRIVE: XCHG BP_DRIVE,AL ; # of drives on stack, CMP AL,80H ; al=drive requested JB SHORT DIGP_IN_RANGE ; HDU call? MOV AH,1 ; Error. MOV BP_OFFSET,0 ; Drive type = 0 JMP DIGP_EXIT DIGP_IN_RANGE: CMP BP_DRIVE,0 ; if # of drives = 0, zero out JE SHORT DIGP_ZERO_OUT ; parameters. CMP AL,01H ; if drive >1, zero out. JA SHORT DIGP_ZERO_OUT CALL GET_CMOS_VALUE OR AH,AH ;;;XXXX if zero, out of range or bad JZ SHORT DIGP_GUESS_DRIVE ; bad CMOS, try to guess drive type. IFDEF ENABLE_288_SUPPORT CMP AH,CMOS_FD_288 ; check 2.88 drive JNE SHORT DIGP_NOT_288 ; skip if not MOV AH,CMOS_FD_144 ; get start table for 1.44 drive CALL CALC_PTABLE_OFFSET ADD SI,2*(SIZE FDPARMS) ; use largest capacity. MOV BP_OFFSET,DOS_FD_288 ; drive type returned thru bx. JMP SHORT DIGP_SET_VALUES ; get to common code DIGP_NOT_288: ENDIF ;ENABLE_288_SUPPORT CMP AH,CMOS_FD_144 JA SHORT DIGP_GUESS_DRIVE ;R05 CALL GET_CMOS_DRIVE ;R05 OR AH,AH ; if zero, out of range or bad ;R05 JZ SHORT DIGP_GUESS_DRIVE ; bad CMOS, try to guess drive type. ;R05 CMP AH,4 ;R05 JA SHORT DIGP_GUESS_DRIVE MOV BL,AH XOR BH,BH MOV BP_OFFSET,BX ; drive type returned thru bx. JMP SHORT DIGP_DRIVE_FOUND DIGP_GUESS_DRIVE: CALL GET_CURRENT_MEDIA TEST AH,010H ; see if established. JZ SHORT DIGP_ZERO_OUT ; if not established, return zero. XOR BX,BX ; signal to caller that we guessed MOV BP_OFFSET,BX ; drive by returning BX = 0 MOV BL,AH ; make index out of bx ROL BL,3 ; xfer rate to bits 0 and 1 AND BL,0110B ; isolate xfer rate CALL GET_DCAPABILITY AND AH,01H ; isolate 80/40 track flag OR BL,AH ; add to bl for index MOV AH,DGROUP:DIGP_DRIVE_TABLE[BX] JMP SHORT DIGP_DRIVE_FOUND DIGP_ZERO_OUT: MOV BP_AL,0 ; input: dl=#of drives MOV BP_SEC_CYL,0 MOV BP_HEAD,0 MOV BP_DI,0 MOV BP_ES,0 MOV BP_OFFSET,0 JMP SHORT DIGP_CLEAR_AH DIGP_DRIVE_FOUND: ; input: ah=drive type CALL CALC_PTABLE_OFFSET IFDEF ENABLE_288_SUPPORT CMP AH,LOCAL_FD_288 ; check 2.88 drive JE SHORT DIGP_ADJ_PARMS ; skip if so to use highest capacity ENDIF ;ENABLE_288_SUPPORT TEST AH,1 ; if a dual-capacity drive JNZ SHORT DIGP_SET_VALUES DIGP_ADJ_PARMS: ADD SI,SIZE FDPARMS ; then use larger capacity. DIGP_SET_VALUES: MOV BP_AL,0 ; AL=0 MOV AL,[SI].FD_EOT MOV AH,[SI].FD_LAST_CYL MOV BP_SEC_CYL,AX MOV BP_HEAD,1 ; always 2 heads on a floppy MOV BP_DI,SI MOV BP_ES,CS DIGP_CLEAR_AH: XOR AH,AH ; indicate no error. DIGP_EXIT: RET ; real RET, not a jump back to ; d_normal_ret since 8 is special. DISK_IO_GET_PARMS ENDP PAGE ;[]------------------------------------------------------------------------ ;Name: Disk_IO_Read_DASD ;Entry: INT 13H ;Input: ah=15H ; dl=drive (0-1 diskette, 80H-81H hard) ;Output: ah=0 not present ; =1 diskette - no change line available ; =2 diskette - change line available ; =3 hard ; cy=0 unless drive specified out of bounds. Then cy=1, al=1 ;Description: ; ;Disk_IO_Read_DASD will ;1. save environment ;2. If drive in bounds then set ah as indicated above else set error. ; Set data values at 0:4??H as needed. ;3. restore environment ;4. return to POI ;[]------------------------------------------------------------------------ align 4 ;R08 DISK_IO_READ_DASD PROC NEAR MOV AL,BP_DRIVE ; get current drive CALL GET_DCAPABILITY ; OR AH,AH ; if no drive, exit with JZ SHORT DIRD_EXIT ; ah=0 AND AH,01H ; 40 track drive = 1 INC AH ; 80 track drive = 2 DIRD_EXIT: JMP D_NORMAL_RET DISK_IO_READ_DASD ENDP PAGE align 4 ;R08 DISK_IO_CHANGE_LINE PROC NEAR MOV BH,ST_TIMEOUT ; assume a timeout MOV AL,BP_DRIVE ; get drive CALL GET_DCAPABILITY OR AH,AH ; if no drive JZ SHORT DICL_EXIT MOV BH,ST_MEDIACHANGE ; assume media change error. TEST AH,01H ; a 40 track drive always JZ SHORT DICL_EXIT ; returns media change. PUSH BX ; save ST_MEDIACHANGE in bh. PUSH AX CALL TURNONMOTOR ; must turn motor on to POP AX ; recover drive #. CALL READ_DCL ; read line POP BX ; recover ST_MEDIACHANGE JNZ SHORT DICL_EXIT ; if active, return ST_MEDIA XOR BH,BH ; else return no error. DICL_EXIT: MOV AH,BH ; move code to ah. JMP D_NORMAL_RET DISK_IO_CHANGE_LINE ENDP PAGE ;[]------------------------------------------------------------------------ ;Name: Disk_IO_Write_DASD ;Entry: INT 13H ;Input: ah=17H ; dl=drive (0-1) ; al=0 reserved ; =1 360K media in 360K drive ; =2 360K media in 1.2M drive ; =3 12.M media in 1.2M drive ;Output: ah=status, if error cy=1, else cy=0 ;Description: ; ;Disk_IO_Write_DASD will ;1. save environment ;2. If drive in bounds then set data values at 0:4??H as indicated by al ; above else set error. ;3. restore environment ;4. return to POI ;[]------------------------------------------------------------------------ align 4 ;R08 DISK_IO_WRITE_DASD PROC NEAR MOV AL,BP_DRIVE CMP BP_AL,1 JNE SHORT DIWD_READ_DCL MOV CX,00090H ; cl= 250 kbs, no double stepping ; ch=0, no error. JMP SHORT DIWD_EXIT DIWD_READ_DCL: PUSH AX ; save drive # CALL TURNONMOTOR ; spin up motor for change line. POP AX ; recover drive # PUSH AX ; resave drive # CALL READ_AND_CLEAR_DCL ; check disk change line MOV CH,AH ; copy return code to ch POP AX ; recover drive # CMP CH,80H ; if unable to clear dcl, exit JNE SHORT DIWD_DCL_CLEAR ; with error code 80h XOR CL,CL ; clear current media JMP SHORT DIWD_EXIT DIWD_DCL_CLEAR: XOR BX,BX ; bx=0 OR BL,BP_AL ; bx=index, check for bl=0 JZ SHORT DIWD_BAD_CODE ; bl=0 is invalid. CMP BL,4 ; bx must be below 5 JBE SHORT DIWD_IN_RANGE DIWD_BAD_CODE: MOV CX,0100H JMP SHORT DIWD_EXIT DIWD_IN_RANGE: JNE SHORT DIWD_LOOKUP ; if 2 or 3, go look up xfer rate CALL GET_DCAPABILITY ; get capabilities for drive AND AH,06H ; if dual capability not known CMP AH,06H ; or no dual capability, use JNE SHORT DIWD_LOOKUP ; 4 as index INC BL ; else use 5 if known to have ; dual capability DIWD_LOOKUP: MOV CL,DIWD_LUT[BX] ; look up new setting DIWD_EXIT: CALL GET_CURRENT_MEDIA ; get current media AND AH,0FH ; clear top nibble. OR AH,CL ; add top nibble CALL SET_CURRENT_MEDIA ; store in memory. MOV AH,CH ; return code to ah JMP D_NORMAL_RET DISK_IO_WRITE_DASD ENDP PAGE ;[]------------------------------------------------------------------------ ;Name: Disk_IO_Set_Media ;Entry: INT 13H ;Input: ah=18H ; dl=drive (0-1) ; cl=last sector on cylinder ; ch=last cylinder on diskette. ;Output: ah=status, if error cy=1, else cy=0 ; If ah=0, the ES:DI will point to a parameter table, ; unless no drive exists. ; 0:490[drive], will be update to reflect new drive type. ;Description: ; ;Disk_IO_Set_Media will ;1. save environment ;2. Read CMOS to find drive type. ;3. Check to see if BIOS has a parameter table for the CMOS drive type ; which also matches the last sector and last cylinder as passed ; in cl and ch. ;4. Return AH=0Ch if no match, else return AH=0h, ES:DI pointing to ; parameter table if a match. ;5. restore environment ;6. return to POI ;[]------------------------------------------------------------------------ align 4 ;R08 DISK_IO_SET_MEDIA PROC NEAR MOV AL,BP_DRIVE CALL GET_DCAPABILITY OR AH,AH ; if no drive ;R14 JZ SHORT DISM_OK_EXIT ; return 0, ok. JZ DISM_OK_EXIT ;R14 TEST AH,01H ; a 40 track drive doesn't JZ SHORT DISM_READ_CMOS ; need to check change line PUSH AX ; save drive # CALL TURNONMOTOR ; spin up motor for change line. POP AX ; recover drive # PUSH AX ; resave drive # CALL READ_AND_CLEAR_DCL ; check disk change line MOV CH,AH ; copy return code to ch POP AX ; recover drive # IFNDEF SIEMENS ;***************************************************************************** ;* Kie 04/25/88 If we cannot clear change line we should not return error 80H ; because IBMBIO.COM and FORMAT from MS-DOS 3.2x interpret every ; error as combination or funktion not supported ;***************************************************************************** CMP CH,80H ; if unable to clear dcl, exit JNE SHORT DISM_READ_CMOS ; with error code 80h MOV AH,CH ; CH IS 80H JMP SHORT DISM_RET ; exit. ENDIF ; SIEMENS DISM_READ_CMOS: MOV AL,BP_DRIVE CALL GET_CMOS_VALUE OR AH,AH ; if there is no drive JZ SHORT DISM_OK_EXIT ; return OK IFDEF ENABLE_288_SUPPORT CMP AH,CMOS_FD_288 ; check 2.88 drive JNE SHORT DISM_NOT_288 ; skip if not MOV AH,CMOS_FD_144 ; index tables as 1.44 CALL CALC_PTABLE_OFFSET ; si = pointer to 1st table MOV AH,BYTE PTR NUM_DRIVE_TABLES[LOCAL_FD_288] ; get number of drive tables for 2.88 JMP SHORT DISM_CHECK_SEC_CYL ; get to common code DISM_NOT_288: ENDIF ;ENABLE_288_SUPPORT CMP AH,CMOS_FD_144 ; out of range, or bad cmos JBE SHORT DISM_CMOS_OK ; try to find drive type MOV AH,1 ; if bad CMOS, try type 1. DISM_CMOS_OK: CALL CALC_PTABLE_OFFSET ; si = pointer to 1st table PUSH BX ; save reg MOV BL,AH ; CMOS type as byte index MOV BH,0 MOV AH,BYTE PTR NUM_DRIVE_TABLES[BX] ; get number of drive tables to check for this type POP BX ; restore reg DISM_CHECK_SEC_CYL: MOV CL,[SI].FD_EOT ; get last track MOV CH,[SI].FD_LAST_CYL ; get last cylinder CMP CX,BP_SEC_CYL ; compare to caller's JE SHORT DISM_SET_MEDIA_EXIT DEC AH ; update counter ;R14 JZ SHORT DISM_ERROR_EXIT ; skip if all tables tried ;R14 start jnz short @F cmp si,offset FD_1024_PARMS je short DISM_ERROR_EXIT MOV AL,BP_DRIVE CALL GET_CMOS_VALUE CMP AH,CMOS_FD_144 ; Is 1.44 FDD? jne short DISM_ERROR_EXIT ;No,jump lea si,FD_1024_PARMS mov ah,1 jmp short DISM_CHECK_SEC_CYL @@: ;R14 end ADD SI,SIZE FDPARMS ; else get to next table JMP SHORT DISM_CHECK_SEC_CYL ; and go again DISM_SET_MEDIA_EXIT: MOV AH,[SI].FD_XFER_RATE CMP AH,040H ; 300 kbs? JNE SHORT DISM_UPDATE OR AH,020H ; add double stepping DISM_UPDATE: OR AH,010H ; determined CALL SET_CURRENT_MEDIA ; drive # still in al MOV BP_DI,SI ; es:di will point to table MOV BP_ES,CS ; on return. DISM_OK_EXIT: XOR AX,AX ; no error DISM_RET: JMP D_NORMAL_RET DISM_ERROR_EXIT: MOV AH,0CH JMP SHORT DISM_RET DISK_IO_SET_MEDIA ENDP PAGE ;!!!!!!!!!!!!! LEVEL 3 PROCEDURES: General purpose procedures. !!!!!!!!!!! PAGE ;[]----------------------------------------------------------------------- ; FAKE_UP_MEDIA_BYTE: Changes low 3 bits of CURRENT_MEDIA to match ; older ROMs definitions of these 3 bits. ; INPUT: AL=drive to update, DCAPABILITY, CURRENT_MEDIA ; OUTPUT: CURRENT_MEDIA, low 3 bits. ; = 2 if 500 Kbs, type 2 drive, undetermined ; = 5 if 500 Kbs, type 2 drive, determined ; = 1 if 300 Kbs, double stepping, undetermined ; = 4 if 300 Kbs, double stepping, determined. ; = 0 if 250 Kbs, 40 track drive, undetermined. ; = 3 if 250 Kbs, 40 track drive, determined. ; = 7 if none of above. ;[]------------------------------------------------------------------------ align 4 ;R08 FAKE_UP_MEDIA_BYTE PROC NEAR MOV DL,7 ; assume new drive type CALL GET_DCAPABILITY ; get 40/80 track info. MOV BX,1 AND BL,AH ; bx has 40/80 track info. CALL GET_CURRENT_MEDIA MOV DH,AH ; dh=copy of bits 3-7 MOV CH,AH ; ch=copy for double step/determined. AND AH,0C0H ; ah=xfer rate JZ SHORT FUMB_500_KBS ; if 500 kbs, handle special. CMP AH,80H ; compare to middle xfer rate JA SHORT FUMB_UPDATE ; if invalid, low 3 bits = 7. JE SHORT FUMB_MAKE_INDEX ; if 250, top bit of index = 0 OR BL,08H ; if 300, top bit of index = 1 FUMB_MAKE_INDEX: SHR CH,3 ; move double step and determined AND CH,0110B ; bits to bits 1 and 2 and add OR BL,CH ; to index. MOV DL,FUMB_BIT_TABLE[BX] ; get low 3 bits JMP SHORT FUMB_UPDATE ; add to media. FUMB_500_KBS: CALL GET_CMOS_DRIVE ; if 500 kbs, but not CMP AH,2 ; type 2, then low 3 bits = 7 JNE SHORT FUMB_UPDATE MOV DL,2 ; assume undetermined TEST DH,010H ; test determined. JZ SHORT FUMB_UPDATE ; jump if undetermined MOV DL,5 ; low 3 bits = 5 if determined FUMB_UPDATE: MOV AH,DH ; recover CURRENT_MEDIA AND AH,NOT 07H ; clear low 3 bits OR AH,DL ; combine with new low 3 bits CALL SET_CURRENT_MEDIA ; change CURRENT_MEDIA RET FAKE_UP_MEDIA_BYTE ENDP PAGE ;[]------------------------------------------------------------------------ ;READ_AND_CLEAR_DCL: Reads disk change line, if active, attempts to clear ; it. ;INPUT: AL = drive #, MOTOR MUST ALREADY BE RUNNING FOR VALID RESULTS. ;OUTPUT: AH=0 if disk change line not active ; 6 if was active, but we successfully clear it. ; 80h if active, and unable to clear it. ; CURRENT_MEDIA is set to unestablished. ; May destroy any other register. ;[]------------------------------------------------------------------------ align 4 ;R08 READ_AND_CLEAR_DCL PROC NEAR CALL READ_DCL ; read the change line ; ah=code, al preserved. MOV AH,0 ; assume ok, SAVE FLAGS ;R14 JZ SHORT RACD_EXIT ; exit if okay ;R14 start jnz SHORT DCL_enable ifdef FDD_3_Mode mov cl,FloppyA_3_mode ;R14D mov al,FDD_A_3_mode_detect cmp byte ptr BP_DRIVE,0 je short @F mov cl,FloppyB_3_mode ;R14D mov al,FDD_B_3_mode_detect @@: test G_RAM:FDD_VERIFY_CMD_FLAG,cl ;R14D jz RACD_EXIT ;R14D test G_RAM:FDD_VERIFY_CMD_FLAG,al ;R16 jnz SHORT RACD_EXIT jnz RACD_EXIT ;R16 MOV AH,ST_MEDIACHANGE ;R24 - start ;R24A cmp BP_OPCODE,5 ;if format disk then don't ;R24A je RACD_EXIT ;detect FDD 3 mode ;R24 - end cmp BP_OPCODE,17h je RACD_EXIT cmp BP_OPCODE,18h ;R16 je short RACD_EXIT je RACD_EXIT ;R16 or G_RAM:FDD_VERIFY_CMD_FLAG,al endif ;FDD_3_Mode jmp short Detect_3_mode_media DCL_enable: ;R14 end CALL GET_CURRENT_MEDIA ; User may have changed media. AND AH,NOT 010H ; so we can't rely on rate. CALL SET_CURRENT_MEDIA PUSH AX ; save drive CALL CLEAR_DCL POP AX ; recover drive OR G_RAM:[XFER_INFO],0C0h ;set invalid "last rate" CALL READ_DCL MOV AH,ST_MEDIACHANGE ; assume we cleared it. ;R14 JZ SHORT RACD_EXIT ;R14 start jnz short Some_error Detect_3_mode_media: ifdef FDD_3_Mode cmp BP_OPCODE,17h je RACD_EXIT cmp BP_OPCODE,18h je short RACD_EXIT push ax ;R16 test byte ptr G_RAM:FDD_VERIFY_CMD_FLAG,Floppy_3_mode ;R16 jz short SF3MD_exit mov al,FDD_A_3_mode_detect mov cl,FloppyB_3_mode ;R16 cmp byte ptr BP_DRIVE,1 je short @F mov al,FDD_B_3_mode_detect mov cl,FloppyA_3_mode ;R16 @@: not al and G_RAM:FDD_VERIFY_CMD_FLAG,al ;R16 start test byte ptr G_RAM:FDD_VERIFY_CMD_FLAG,cl jnz short @F xor al,al ;Disable 3 mode call Set_FDD_3_mode ;R14D;R14C pop ax ;R14B get error code (in AH) ;R14D;R14C xor ah,ah ;R14B clear error code ;R14D;R14C push ax ;R14B restore error code jmp short SF3MD_exit @@: mov al,BP_DRIVE CALL GET_CMOS_DRIVE cmp ah,2 je short Force_3mode ;R16 end xor al,al ;Disable 3 mode call Set_FDD_3_mode mov cx,1 ;0 cylinder 1 sector mov dl,BP_DRIVE mov dh,BP_HEAD @@: mov ax,401h int 13h ;check is 720K? jnc short SF3MD_exit ;Yes or disk OK jump cmp ah,ST_MEDIACHANGE je short @B Force_3mode: ;R16 mov al,1 ;Enable 3 mode call Set_FDD_3_mode SF3MD_exit: pop ax endif ;FDD_3_Mode jmp SHORT RACD_EXIT Some_error: ;R14 end MOV AH,ST_TIMEOUT ; can't clear it. RACD_EXIT: RET READ_AND_CLEAR_DCL ENDP ;R14A start ifdef FDD_3_Mode include fdd3mode.sio endif ;FDD_3_Mode ;R14A end PAGE ;[]---------------------------------------------------------------------- ;NEC_SEEK: Moves read head to the requested cylinder. Recalibrates ; drive if drive has not yet been recalibrated. Will take ; care of double stepping if necessary. ; INPUT: AL=Drive # ; AH=Logical Track # (not the double-stepped number) ; CURRENT_MEDIA, bit 5 = +double step bit. ; NEED_RECAL, bit 0-1 to indicate if this drive needs ; recalibration. ; CURCYL to tell us if we are already on the requested drive. ; OUTPUT: ; AH=error code if unable to complete seek. ; AH=0 if successfuly seek operation. ; CURCYL = New physical clinder ; NEED_RECAL, recalibrate bit for this drive set. ; May destroy any general register. ;[]---------------------------------------------------------------------- ALIGN 4 NEC_SEEK PROC NEAR MOV BL,1 ; create mask for testing MOV CL,AL ; seek status recalibrate bit SHL BL,CL ; for this drive. TEST G_RAM:[NEED_RECAL],BL ; fall thru if this JNZ SHORT NS_DO_SEEK ; drive needs recal. OR G_RAM:[NEED_RECAL],BL ; set bit, so next seek ; will not recalibrate. MOV DX,AX ; track, drive to dx. XOR AH,AH ; cylinder will be 0 after CALL SET_CURCYL ; recalibrate. MOV CX,2 ; NEC returns error on ; recal after 77 step pulses, ; so we made need to recal ; twice. NS_RECAL_LOOP: PUSH CX ; save loop counter PUSH DX ; save track, pass drive MOV SI,SP ; to SEND_COMMAND MOV AH,NC_RECAL ; recalibrate command. MOV BL,NC_LEN_RECAL ; 2 byte command. CALL SEND_COMMAND POP DX ; recover track, drive. POP CX ; recover loop counter OR AH,AH JNZ SHORT NS_EXIT ; can't send command. PUSH CX ; save loop counter PUSH DX ; save drive & track CALL SENSESTATINT ; check status POP DX ; recover drive, track. POP CX ; recover loop counter OR AH,AH ; check for error. LOOPNZ SHORT NS_RECAL_LOOP ; try again if error. JNZ SHORT NS_EXIT ; if 2 errors, its a genuine ; error. MOV AX,DX ; ax=cylinder,drive. OR AH,AH ; if cylinder = 0, impose JNZ SHORT NS_DO_SEEK ; head settle time now, CALL HEAD_SETTLE_TIME ; since seek will skip this. JMP SHORT NS_SUCCESS NS_DO_SEEK: MOV BX,AX ; save track. CALL GET_CURRENT_MEDIA TEST AH,020H ; double stepping? JZ SHORT NS_GOT_CYL SHL BH,1 ; then double cylinder. NS_GOT_CYL: CALL GET_CURCYL CMP AH,BH JE SHORT NS_SUCCESS ; no need to seek. MOV AH,BH CALL SET_CURCYL PUSH BX ; drive and track on stack MOV SI,SP ; ss:[si] points to args. MOV AH,NC_SEEK ; ah=seek command MOV BL,NC_LEN_SEEK ; 3 byte command CALL SEND_COMMAND POP BX ; recover drive and track OR AH,AH JNZ SHORT NS_EXIT ; unable to send seek. PUSH BX ; save drive, cylinder CALL SENSESTATINT ; get RESULTS of operation. POP BX ; recover drive track. OR AH,AH JNZ SHORT NS_EXIT ; exit if error. MOV AX,BX ; drive to al CALL HEAD_SETTLE_TIME NS_SUCCESS: XOR AH,AH ; indicate no error. NS_EXIT: RET NEC_SEEK ENDP PAGE ;[]---------------------------------------------------------------------- ;HEAD_SETTLE_TIME: imposes head settle time for drive. ; INPUT: AL=drive, ES=0 ; OUTPUT: none ; may destroy any general register. ;[]---------------------------------------------------------------------- align 4 ;R08 HEAD_SETTLE_TIME PROC NEAR MOV BX,AX ; save drive # MOV AL,9 ; get head settle time CALL GET_PARM OR AL,AL JNE SHORT HST_DO_WAIT ; if not zero, do the wait. TEST G_RAM:[MOTOR_ON_IND],80H ; if zero and a read JZ SHORT HST_EXIT ; skip the wait. MOV AL,BL CALL GET_CURRENT_MEDIA MOV AL,20 ; assume longer wait OR AH,AH ; if 250 kbs or invalid JS SHORT HST_DO_WAIT ; use longer wait. MOV AL,15 ; use shorter wait. HST_DO_WAIT: ;Don't use PIE to implement waiting function, because OS2 failure ;R13 test cs:[SYSTEM2_BYTE],80h ;R08 ;R13 jnz short HST_No_Pie ;R08 ;R13 PUSH AX ; save head settle wait time. ;R13 XOR AH,AH ; increment, as CMOS chip's ;R13 INC AX ; resolution is only 1 ms. ;R13 MOV DX,1000 ; 1000 micros per ms. ;R13 MUL DX ;R13 MOV CX,AX ; dx:cx=dx:ax ;R13 XCHG DX,CX ; msw to cx, lsw to dx ;R13 MOV AH,86H ; wait call. ;R13 INT 15H ; ALLOW OTHER DRIVERS ;R13 sti ;R07 ;R13 POP AX ; recover head settle time ;R13 JNC SHORT HST_EXIT ; if no carry, all done ;R13HST_No_Pie: ;R08 MOV DL,CS:WAIT_FDU_HEAD_SETTLE ; CS: override here! ; units in a millisecond MUL DL ; calculate # of 30 micro MOV CX,AX ; units in AX milliseconds XOR BX,BX ; bx:cx=wait time. CALL WAIT_REFRESH ; perform wait. HST_EXIT: RET HEAD_SETTLE_TIME ENDP PAGE ;[]---------------------------------------------------------------------- ;ERROR_CHECK: Checks the return codes for the NEC to see if any errors ; occurred. If it detects any, then it translates them ; into the BIOS error code. ; INPUT: FDC_RET_CODES ; OUTPUT: AH=0 if no errors, ; AH=error code if error occurred. align 4 ;R08 ERROR_CHECK PROC NEAR ; SEG_0 MOV BL,G_RAM:FDC_RET_CODES[0] ; get ST0 AND BL,0C0H ; bits 7 and 6 = 0 MOV AH,ST_OK ; if normal termination JE SHORT EC_EXIT ; occurred. CMP BL,40H ; Invalid command MOV AH,ST_BADNEC ; or FDD ready line changed. JNZ SHORT EC_EXIT ; blame it on controller. MOV BL,G_RAM:FDC_RET_CODES[1] ; get ST1 TEST BL,84H ; user asked for sector > EOT MOV AH,ST_RNF ; or NEC couldn't find ID JNZ SHORT EC_EXIT ; field that matched. TEST BL,20H ; read an ID or data MOV AH,ST_BADCRC ; field, but the CRC JNZ SHORT EC_EXIT ; didn't add up. TEST BL,10H ; DMA was too slow MOV AH,ST_BADDMA ; too keep up with NEC JNZ SHORT EC_EXIT TEST BL,2 ; write protect tab MOV AH,ST_WRITEPROT ; was in place. JNZ SHORT EC_EXIT TEST BL,1 ; wasn't able to find MOV AH,ST_BAM ; any address mark at all. JNZ SHORT EC_EXIT MOV AH,ST_BADNEC ; everything else, blame ; on the controller. EC_EXIT: RET ERROR_CHECK ENDP PAGE ;RESETDRIVES: Performs a reset of the controller, returning it to a ; known state. ; INPUT: none ; OUTPUT: AH=0 if no error, 20h if controller error, 80h if ; timeout while issuing specify command. ; called by hrdskio too... ; ;[]---------------------------------------------------------------------- PUBLIC RESETDRIVES ; * AHDSK.ASM ALIGN 4 RESETDRIVES PROC NEAR PUSH DS CLI ; stop interrupts while changing ; port 3F2h, so MOTOR_ON_IND ; stays in sync. MOV AX,G_RAM MOV DS,AX ASSUME DS:G_RAM MOV AL,G_RAM:[MOTOR_ON_IND] ; don't shut off any motors ROL AL,4 ; or change selected bits. AND AL,NOT 04H ; -RESET bit, active low OR AL,8 ; +DMA MOV DX,FDC_CTRL_OUT OUT DX,AL MOV G_RAM:[NEED_RECAL],0 ; recalibrate on next seek MOV CX,WAITCPU_RESET_ON ALIGN 4 ; N3.03 @wdw1: NEWIODELAY ;R09 ;R09 out 0e1h,ax loop short @wdw1 OR AL,4 ; refresh off. OUT DX,AL ; dx = FDC_CTRL_OUT IODELAY STI ; reset over, CALL SENSESTATINT ; SENSESTATINT(); MOV AH,ST_BADNEC ; assume bad controller CMP G_RAM:[FDC_RET_CODES],0C0H ; check if controller JNE SHORT RD_EXIT ; detected change in ready XOR AL,AL ; get 1st specify byte CALL GET_PARM MOV BL,AL MOV AL,1 ; get 2nd specify byte CALL GET_PARM MOV BH,AL PUSH BX ; push args on stack. MOV SI,SP ; pointer to args. MOV AH,NC_SPECIFY ; 3=specify command. MOV BL,NC_LEN_SPECIFY ; 3 byte command. CALL SEND_COMMAND POP BX ; clear stack RD_EXIT: XOR AL,AL ; clear al, error code in ah. POP DS ASSUME DS:NOTHING ; ASS-U-ME NEEDS TO BE CLEAR RET RESETDRIVES ENDP PAGE ;[]---------------------------------------------------------------------- ;SENSESTATINT: Called after a SEEK, RECALIBRATE or RESET of the controller. ; It: ; 1. Waits for interrupt from controller ; 2. Sends a Sense interrupt status command to ; get ST0, which it stores in FDC_RET_CODES. ; 3. Evaluates ST0 for SEEK error. ; INPUT: none ; OUTPUT: AH=0 if success ; 80h if no interrupt or problem sending or ; receiving sense interrupt status. ; 40h if bits 5 and 6 of ST0 are set, indicating ; an abnormal termination. ; FDC_RET_CODES = ST0, (the RESET command wants ; to check ST0 for itself). ;[]---------------------------------------------------------------------- ALIGN 4 ; 303A SENSESTATINT PROC NEAR ; SEG_0 CALL WAITNECINT ; wait for interrupt to occur OR AH,AH ; if timeout, exit. JNZ SHORT S_EXIT MOV AH,NC_SIS ; sense interrupt status code MOV BL,NC_LEN_SIS ; 1 byte command CALL SEND_COMMAND OR AH,AH JNZ SHORT S_EXIT CALL RESULTS ; read ST0 and Present ; cylinder number OR AH,AH ; if reading error JNZ SHORT S_EXIT ; return with timeout code. MOV AL,G_RAM:FDC_RET_CODES[0] ; get ST0. Check for AND AL,060H ; abnormal termination of CMP AL,060H ; seek command. MOV AH,ST_BADSEEK JE SHORT S_EXIT XOR AH,AH ; return success S_EXIT: RET SENSESTATINT ENDP PAGE ;[]---------------------------------------------------------------------- ;WAITNECINT: Waits for the controller to generate an IRQ6, which will ; cause INT 0Dh to set bit 7 of NEED_RECAL. ; ; INPUT: NEED_RECAL, bit 7. ; OUTPUT: AH=0 if interrupt occurred. ; AH=80h if interrupt didn't occur, or if INT 15h ; function 9001h returned with carry flag set. ; NEED_RECAL, bit 7 = 0. ;[]---------------------------------------------------------------------- ALIGN 4 ; 303A WAITNECINT PROC NEAR MOV DI,OFFSET G_RAM:NEED_RECAL ; set now, in case int 15 ; sets carry. CODE WILL BREAK ; WITHOUT THIS MOV AX,9001H CLC INT 15H sti ;R07 MOV AH,ST_TIMEOUT ; assume timeout. JC SHORT W_EXIT MOV AH,80H ; check top bit MOV BH,DGROUP:[WAIT_FDU_INT_HI] ; outer loop counter MOV CX,DGROUP:[WAIT_FDU_INT_LO] ; inner loop counter CALL WAIT_FOR_MEM ; returns ah=80h or 0h W_EXIT: AND BYTE PTR G_RAM:[DI],NOT 80H ; di = NEED_RECAL TEST AH,80H JZ W_RET STC W_RET: RET WAITNECINT ENDP PAGE ;[]---------------------------------------------------------------------- ;RESULTS: Reads status bytes back from NEC controller and ; stores them into FDC_RET_CODES array. ; INPUT: none ; OUTPUT: FDC_RET_CODES ; AH=80h if timeout while waiting for Status port ; to give us RQM or direction bit is wrong. ; AH=ST_BADNEC if more than 7 bytes. ; Other general registers may be destroyed. ;[]---------------------------------------------------------------------- public RESULTS ;R22 ALIGN 4 ; 303A RESULTS PROC NEAR MOV DI,OFFSET G_RAM:FDC_RET_CODES ALIGN 4 ; N3.03 R_NEXT_BYTE: MOV CX,DGROUP:[WAIT_FDU_RESULTS_LO] ; length of time for MOV BH,DGROUP:[WAIT_FDU_RESULTS_HI] ; RQM and direction set. MOV AX,0C0C0H ; RQM is bit 7, dir bit 6. MOV DX,NEC_STAT_PORT ; of port 3F4h. CALL WAIT_FOR_PORT ; ah=80h if timeout, 0 otherwise. OR AH,AH JNZ SHORT R_EXIT INC DX ; dx is now NEC_DATA_PORT ;R18IFDEF COMPUADD ;R18 IN AL,DX ; vain attempt to avoid ;R18 SIODELAY ; bus posting timing problem ;R18 STOSB ;R18ELSE IN AL,DX ; es:[di] = status port. NEWIODELAY ;R18 STOSB ; inc di ;R18ENDIF ; COMPUADD XOR BX,BX push cx ;R18 mov cx, 20 mov cx, 30 ;R18 @wdw2: NEWIODELAY ;R09 ;R09 out 0e1h,ax loop short @wdw2 pop cx MOV DX,NEC_STAT_PORT ; get back dx IN AL,DX ; read the status port. NEWIODELAY ;R18 XOR AH,AH ; assume no error, save flag TEST AL,10H ; more? JE SHORT R_EXIT ; quit if no more. MOV AH,ST_BADNEC ; assume error. CMP DI,OFFSET FDC_RET_END ; if we still have room for JBE SHORT R_NEXT_BYTE ; more codes, go get them. R_EXIT: RET RESULTS ENDP PAGE ;[]---------------------------------------------------------------------- ;TURNONMOTOR: Turns on motor and SELECTS drive. In addition, ; it also will impose a motor start up delay if ; the motor was not already spinning. ; INPUT: AL=drive number. ; ;[]---------------------------------------------------------------------- ALIGN 4 ; 303A TURNONMOTOR PROC NEAR XOR CH,CH ; ch = 0, assume drive ; is already running MOV BH,1 ; bh=mask for drive. MOV CL,AL SHL BH,CL CLI ; interrupts off so that ; MOTOR_ON_IND stays in synch ; with port 3f2h MOV BL,G_RAM:[MOTOR_ON_IND] ; get current port 3f2h TEST BL,BH ; is motor already running? JNZ SHORT M_UP_COUNT INC CH ; flag that motor is just ; now being turned on. M_UP_COUNT: MOV G_RAM:[MOTOR_OFF_WAIT],0FFH ; putd(MOTOR_OFF_WAIT,0xff,0) MOV AH,BL ; ah=old motor status AND AH,3 ; save currently running drvs. MOV CL,4 ; shift to upper nibble for SHL AH,CL ; port 3f2, MOV DL,AH ; save in dl for now. AND BL,0CFH ; Clear drive select MOV AH,AL ; drive to ah SHL AH,CL ; shift drive to upper nibble OR BL,BH ; or in the new motor OR BL,AH ; OR in the new drive select MOV G_RAM:[MOTOR_ON_IND],BL ; update motor status MOV AH,DL ; assemble port 3f2h in MOV DL,10H ; ah register. MOV CL,AL OR AH,AL ; or in drive select SHL DL,CL OR AH,DL ; or in the new motor OR AH,0CH ; or no reset, use DMA XCHG AH,AL MOV DX,FDC_CTRL_OUT OUT DX,AL ; out to controller STI ; allow interrupts, now that ; port 3F2h and MOTOR_ON_IND ; are the same again. OR CH,CH ; if motor already running JE SHORT M_NO_WAIT ; don't wait. MOV AX,090FDH ; give multitasker a chance CLC ; to bypass motor spin up. INT 15H sti ;R07 JNC SHORT M_DO_WAIT ; if no multi-tasker, do wait. M_NO_WAIT: RET M_DO_WAIT: MOV AX,10 ; J = getparm(10); CALL GET_PARM TEST G_RAM:[MOTOR_ON_IND],80H ; read operation JE SHORT M_READ_OP ; use shorter minimum CMP AL,7 ; write or format, ensure JA SHORT M_CALC_WAIT ; 1 second minimum MOV AX,8 JMP SHORT M_CALC_WAIT M_READ_OP: ; read, read verify OR AL,AL ; no motor spin up ok on JZ SHORT WAIT_OVER ; reads if DOS does retries. CMP AL,4 ; ensure 5/8 second spin up. JA SHORT M_CALC_WAIT MOV AX,5 M_CALC_WAIT: XOR AH,AH ; ax=1/8 sec. units. ;Don't use PIE to implement waiting function, because OS2 failure ;R13 test cs:[SYSTEM2_BYTE],80h ;R08 ;R13 jnz short Mortor_No_Pie ;R08 ;R13 MOV BX,AX ; copy to bx, if int 15 busy ;R13ifdef NO_SHORT_MOTOR_ON ; R04 ;R13 mov cx,62500 ; R04 ;R13else; NO_SHORT_MOTOR_ON ; R04 ;R13 MOV CX,62500/4 ; cx=number of 2 microsecond ;R13 ; units in 1/8 of a second. ;R13endif; NO_SHORT_MOTOR_ON ; R04 ;R13 MUL CX ; dx:ax=# of 2 microsecond ;R13 ; units to wait ;R13 MOV CX,DX ; MSW to cx ;R13 MOV DX,AX ; LSW to dx ;R13 SHL DX,1 ; mul cx:dx * 2. ;R13 RCL CX,1 ; top bit of dx to low bit of ;R13 ; cx. ;R13 MOV AH,86H ; CMOS chip wait call. ;R13 INT 15H ;R13 sti ;R07 ;R13 JNC SHORT WAIT_OVER ; exit if wait occurred ;R13 ; else use refresh to time ;R13 ; wait. ;R13 MOV AX,BX ; recover 1/8 sec units ;R13Mortor_No_Pie: ;R08 MOV CX,CS:WAIT_FDU_8THS ; located in the CS!! ; in 1/8 of a second MUL CX ; dx:ax=wait_refresh micro units to wait MOV CX,AX ; bx:cx = dx:ax MOV BX,DX CALL WAIT_REFRESH WAIT_OVER: RET TURNONMOTOR ENDP PAGE ;[]---------------------------------------------------------------------- ;CALC_XFER_SIZE: Calculates the number of sectors that were transferred. ; INPUT: CH=starting cylinder ; CL=starting sector ; DH=starting head ; FDC_RET_CODES[3] = ending cylinder ; FDC_RET_CODES[4] = ending head ; FDC_RET_CODES[5] = ending sector. ; OUTPUT: AL=sectors xferred. ; ;[]---------------------------------------------------------------------- ALIGN 4 CALC_XFER_SIZE PROC NEAR ; The return codes supplied by the FDC point to the sector AFTER ; the last one transferred. If the last sector transferred was ; the last sector on the track, the head and possibly the cylinder ; will be moved up, and sector set to 1. MOV AL,4 CALL GET_PARM MOV AH,AL ; ah=EOT MOV AL,G_RAM:FDC_RET_CODES[5] ; al=ending sector. SUB AL,CL ; al=end-start, may be ; negative number. CMP DH,G_RAM:FDC_RET_CODES[4] ; did head advance? JE SHORT CXS_HEAD_SAME ; check cylinder if not ADD AL,AH ; al=end-start + EOT JMP SHORT CXS_EXIT ; if head different, cylinder ; can't have advanced. CXS_HEAD_SAME: CMP CH,G_RAM:FDC_RET_CODES[3] ; did cylinder advance? JE SHORT CXS_EXIT ; exit if not SHL AH,1 ; ah=EOT*2 ADD AL,AH ; al=end-start + (EOT*2) CXS_EXIT: RET ; CALC_XFER_SIZE ENDP PAGE ;[]---------------------------------------------------------------------- ;DMA_SETUP: set up 8237 for disk transfer ; input - AL=command. ; SS:SI = offset ; SS:SI+2 = segment ; SS:SI+4 = size of xfer, in bytes - 1 for DMA ; output: ; AH=0 if no error ; AH=09 if DMA boundary error. ;[]---------------------------------------------------------------------- ALIGN 4 ; 303A DMA_SETUP PROC NEAR ; --- QEMM/WINDOWS FIX --- ; Occasionally, complete sectors were being written with wrong data. ; The problem occurs when (1) we DMA from paged memory, and (2) the ; ES:BX value plus sectors would overlap the "linear" 64K boundary ; (detected by BIOS here), and (3) the transfer also overlaps the 64K ; "physical" boundary in the target (EMS) paged RAM. We note that the ; DMAC writes to "physical" RAM, so when BIOS programs the DMAC with a ; "linear" value, QEMM must reprogram a "physical" address into the ; DMAC. Furthermore, if a 64K "physical" boundary would be crossed, ; then QEMM needs to supply a temporary buffer, then trap the FDC ; completion interrupt and copy the data to the final target (EMS) RAM. ; QEMM has a state-machine bug here: ; (a) DOS asks BIOS to DMA several sectors across a 64K boundary, ; (As this RAM is paged, this is a "linear 64K boundary", and ; does not necessarily correspond to a "physical" 64K boundary). ; (b) BIOS unconditionally programs DMAC according to BIOS request. ; (c) QEMM traps then reprograms DMAC for the actual "physical" address, ; noting the special case here that it also (coincidental to #a) ; will cross a 64K "physical" boundary. ; (d) BIOS then checks and determines the "linear" boundary problem, ; and aborts with error "9" (DMA BOUNDARY FAULT). ; (e) DOS then changes its request to read only the 1st sector. (The ; 2nd sector would actually cross the 64K boundary, and DOS reads ; that one to an internal 70: buffer, then writes it to the user's ; RAM location). ; (f) BIOS honors DOS's request for 1 sector, programs the DMAC. ; (e) QEMM reprograms the DMAC for the "physical" address. ; (g) BIOS programs the FDC and the (correct) data transfer occurs. ; (h) QEMM (incorrectly) remembers that it was double-buffering (to ; solve #c, which is no longer an issue), and overwrites the ; freshly DMAd data with old data from a temporary buffer. ; ----------------------- ; There is a work-around for QEMM's problem, which should be harmless ; to the BIOS. Since writing to the DMAC triggers QEMM, we should only ; do so when we actually intend to do DMA. In other words, we should ; check for the DMA boundary situation, and abort prior to (needlessly) ; programming the DMAC. ; ; ;--------------------------------- ; ; Prior to setting up DMA, confirm that segment overflow won't occur. ; ; The DMA controller only has a 16-bit address register, so will wrap ; to the bottom of the 64K segment if too many bytes are transferred. ; Calculation: translate original ES:BX to a value with format X000:MNPQ ; Then figure out if the desired sectors (512 bytes per) would require ; a final address at X001:RSPQ (ie, incremented segment #). ; PUSH DX MOV DX, SS:[SI+2] ; Expand SEG to 20 bits MOV BL, DH ; SHL DX, 4 ; SHR BL, 4 ; SEG SHL(4) ---> BL:AX ADD DX, SS:[SI] ; Get SEG SHL(4)+OFFSET ADC BL, 0 ; ADD DX, SS:[SI+4] ; Plus #bytes to xfer-1 MOV AH, 9 ; Assume seg overflow JC SHORT DS_EXIT ; Jump if wrap (bad) SUB DX, SS:[SI+4] ; Restore to start addr ; All is ok CLI OUT DMA_PORT+12,AL ; set the first/last f/f IODELAY OUT DMA_PORT+11,AL ; output the mode byte SIODELAY ; COMPUADD XCHG AX, DX ; (saved byte) OUT DMA_PORT+4,AL ; output low 2 nibbles of XCHG AL,AH ; address IODELAY OUT DMA_PORT+4,AL ; out high 2 nibbles of IODELAY ; address. XCHG AX,BX ; save ax, send highest OUT PAGE_PORT,AL ; nibble to page reg SIODELAY ; PCMOS MOV AX,SS:[SI+4] ; and amount to transfer SIODELAY ; PCMOS OUT DMA_PORT+5,AL ; send LSB of xfer to DMA MOV AL,AH IODELAY OUT DMA_PORT+5,AL ; send MSB of xfer to DMA IODELAY STI MOV AL,2 ; initialize diskette channel OUT DMA_PORT+10,AL XOR AX,AX ; no error DS_EXIT: POP DX ; RET DMA_SETUP ENDP PAGE ;[]---------------------------------------------------------------------- ;clear_dcl: Attempts to clear disk change line by doing: ; 1. reset ; 2. seek to track 1 ; 3. seek to track 0 ; ; INPUT: Motor must be running, with appropriate drive selected. ; AL=drive # ; OUTPUT: none ; May destory any general registers ;[]---------------------------------------------------------------------- ALIGN 4 ; 303A CLEAR_DCL PROC NEAR PUSH AX ; save drive # in al CALL RESETDRIVES POP AX ; recover drive #. ; MOV AH,1 ; seek to track 1 MOV AH,4 ; jsz PUSH AX ; save drive # in al CALL NEC_SEEK POP AX ; recover drive # XOR AH,AH CALL NEC_SEEK RET CLEAR_DCL ENDP PAGE ;[]---------------------------------------------------------------------- ;SEND_COMMAND: Sends a complete command sequence to the NEC controller. ; INPUT: ; AH=Command ; SS:SI=parameters for command ; BL=number of bytes (maximum of 7) ; OUTPUT: ; AH=0 if all bytes sent successfully ; 80h if timeout error. ; May destroy any general register. ; DESTROYS CX ;[]---------------------------------------------------------------------- public SEND_COMMAND ;R22 ALIGN 4 ; 303A SEND_COMMAND PROC NEAR SC_NEXT_BYTE: PUSH AX ; save value in ah MOV DX,NEC_STAT_PORT MOV BH,DGROUP:[WAIT_FDU_SEND_HI] ; amount of tme to allow MOV CX,DGROUP:[WAIT_FDU_SEND_LO] ; for RQM and direction . MOV AX,0C080H ; check bits 6,7 = 10b. CALL WAIT_FOR_PORT ; wait til RQM is on. POP CX ; recover value from stack. OR AH,AH ; if TIMEOUT JNZ SHORT SC_EXIT ; abort operation. MOV AL,CH ; al=output data. MOV CX,WAITCPU_RQM_LOW ;R06 push cx ;R06 mov cx, 10 ;R06@wdw3: ;R06 out 0e1h,ax ;R06 loop short @wdw3 ;R06 pop cx ; prepare post-write wait. INC DX ; point to data register OUT DX,AL ; send the data IODELAY DEC DX ; point back to status ;IFNDEF SLOW_DOWN_DISK_FOR_FAST_CPU ; ALIGN 4 ; N3.03 ;SC_RQM_LOW_LP: IN AL,DX ; wait for RQM to go low. ; TEST AL,80H ; RQM might remain incorrectly set ; LOOPNZ SHORT SC_RQM_LOW_LP ;ENDIF ;SLOW_DOWN_DISK_FOR_FAST_CPU DEC BL ; any more bytes to send? JZ SHORT SC_SUCCESS ; exit if done. MOV AH,SS:[SI] ; get next parameter to send INC SI ; point to parameter after this one JMP SHORT SC_NEXT_BYTE SC_SUCCESS: XOR AX,AX ; ah=0, operation a success SC_EXIT: RET SEND_COMMAND ENDP PAGE ;[]---------------------------------------------------------------------- ;CHECK_DSTEP check if double stepping is necessary ; INPUT: AL=drive ; OUTPUT: CURRENT_MEDIA is updated to reflect whether we ; have to double step or not. ;[]---------------------------------------------------------------------- ALIGN 4 ; N3.03 CHECK_DSTEP PROC NEAR CALL GET_CURRENT_MEDIA TEST AH,010H ; established? JNZ SHORT CD_SUCCESS AND AH,NOT 020H ; turn off double stepping, for CALL SET_CURRENT_MEDIA ; NECSEEK routine. CALL GET_DCAPABILITY TEST AH,01H ; if 40 track drive, leave with JZ SHORT CD_SUCCESS ; leave with double stepping off. MOV BL,0FEH MOV CL,AL ROL BL,CL AND G_RAM:[NEED_RECAL],BL ; force recalibrate XOR AH,AH ; start at track 0 MOV DX,AX ; track,drive and head to dx ALIGN 4 CD_READ_ID_LOOP: PUSH DX ; save track, drive # and head MOV AX,DX ; ax=track,drive and head. AND AL,01H ; eliminate head for seek operation CALL NEC_SEEK POP DX ; recover track, drive,head OR AH,AH ; any errors JNZ SHORT CD_EXIT ; failure if errors. PUSH DX ; argument for read id on stack MOV SI,SP ; pointer to argument MOV AH,NC_READ_ID ; read id command MOV BL,NC_LEN_READ_ID ; 2 byte command CALL SEND_COMMAND ; perform read id. POP DX ; recover track,drive head. OR AH,AH JNZ SHORT CD_EXIT ; error if we can't send a command PUSH DX CALL WAIT_FOR_RESULTS ; wait for interrupt, read status CD_TL_READ_ID: ; testing label MOV G_RAM:[MOTOR_OFF_WAIT],0FFH ; keep motor spinning. POP DX ; bytes and check for errors. OR DH,DH ; handle track zero special JZ SHORT CD_CYLINDER_0 OR AH,AH JZ SHORT CD_GOT_ID jmp short CD_EXIT ;R19 ;R19 INC DH ; move to next cylinder ;R19 CMP DH,80 ; last cylinder ;R19 JB SHORT CD_READ_ID_LOOP ; go back if not ;R19 ;R19 TEST DL,04H ; on 2nd head already? ;R19 JNZ SHORT CD_EXIT ; exit with error code in ah ;R19 MOV DH,4 ; move to side 2 ;R19 OR DL,04H ; second head. ;R19 JMP CD_READ_ID_LOOP CD_CYLINDER_0: OR AH,AH ; check for error. JNZ SHORT CD_EXIT ; if we can't read id on track 0, ; then we probably have wrong xfer ; rate or unformatted diskette MOV DH,4 ; start looking on track 4 JMP CD_READ_ID_LOOP CD_GOT_ID: CMP G_RAM:FDC_RET_CODES[3],DH ; if equal, leave JE SHORT CD_SUCCESS ; as single step. MOV AL,DL ; get drive AND AL,01H ; destroy head CALL GET_CURRENT_MEDIA OR AH,020H ; set double stepping CALL SET_CURRENT_MEDIA CD_SUCCESS: XOR AH,AH CD_EXIT: RET CHECK_DSTEP ENDP PAGE ;[]---------------------------------------------------------------------- ;wait_for_results: This routine called after a read/write/verify or ; format command has been issued. IT: ; 1. Waits for completion interrupt from controller. ; 2. Reads status bytes to FDC_RET_CODES ; 3. Checks FDC_RET_CODES for any errors. ; 4. Translates NEC errors into BIOS error interface. ; INPUT: none. ; OUTPUT: FDC_RET_CODES ; AH=error code if some sort of failure ; AH=0 if no error. ;[]---------------------------------------------------------------------- ALIGN 4 ; N3.03 WAIT_FOR_RESULTS PROC NEAR CALL WAITNECINT PUSH AX ; save RESULTS CALL RESULTS ; always read RESULTS to clean up MOV BH,AH ; save RESULTS POP AX ; recover RESULTS from WAITNECINT OR AH,AH ; see if timeout from RESULTS. JNZ SHORT WFR_EXIT MOV AH,BH ; get return code from RESULTS OR AH,AH ; if non-zero, exit. JNZ SHORT WFR_EXIT CALL ERROR_CHECK ; check for errors, convert NEC WFR_EXIT: RET ; errors to BIOS errors. WAIT_FOR_RESULTS ENDP ;[]---------------------------------------------------------------------- ;GUESS_AT_MEDIA: if format is called with CURRENT_MEDIA ; unestablished, this routine looks at CURRENT_MEDIA ; and DCAPABILITY and tries to guess what the ; CURRENT_MEDIA should be, then establishes it. ; INPUT: AL=drive ; OUTPUT: CURRENT_MEDIA updated and established. ; May destroy any general register. ;[]---------------------------------------------------------------------- ALIGN 4 ; N3.03 GUESS_AT_MEDIA PROC NEAR CALL GET_CMOS_VALUE IFDEF ENABLE_288_SUPPORT CMP AH,CMOS_FD_288 ; check for 2.88 drive JNE GAM_NOT_288 MOV AH,LOCAL_FD_288 ; if 2.88 then JMP SHORT GAM_GOT_DRIVE ; set index and get to common code GAM_NOT_288: ENDIF ;ENABLE_288_SUPPORT ;R05 CALL GET_CMOS_DRIVE CMP AH,4 JBE SHORT GAM_GOT_DRIVE XOR BL,BL ; change to 0 JMP SHORT GAM_UPDATE GAM_GOT_DRIVE: MOV BL,AH ; save drive type XOR BH,BH ; make into index MOV BL,DGROUP:GAM_TABLE[BX] ; get new current media CMP AH,3 ; make exception for type 3 JNE SHORT GAM_UPDATE CALL GET_DCAPABILITY AND AH,06H ; if determined dual capability CMP AH,06H JNE SHORT GAM_UPDATE MOV BL,050H ; change to 300 kbs NO DOUBLE STEPPING ; determined GAM_UPDATE: CALL GET_CURRENT_MEDIA MOV AH,BL CALL SET_CURRENT_MEDIA RET GUESS_AT_MEDIA ENDP PAGE ;!!!!!!!!!!!! LEVEL 4 PROCEDURES: these procedure protect registers !!!!! ;[]---------------------------------------------------------------------- ; CALC_PTABLE_OFFSET: calculates offset, from 0F000h, of where ; the parameter table in ah is located, and returns in SI. ; INPUT: AH = drive type, valid values: 1 to 4. ; OUTPUT: SI = offset to start of table. ; SI is only register changed. ; ;[]---------------------------------------------------------------------- ALIGN 4 ; N3.03 CALC_PTABLE_OFFSET PROC NEAR PUSH AX ; save ax. MOV AL,SIZE FDPARMS ; length of a table MUL AH ; multiply by drive type MOV SI,AX ; save result of multiply POP AX ; recover drive type, restore al. CMP AH,2 ; if type 1 or 2, subtract one table JA SHORT CPO_GOT_OFFSET SUB SI,SIZE FDPARMS CPO_GOT_OFFSET: ADD SI,OFFSET DGROUP:FD_BIOS_PARMS RET CALC_PTABLE_OFFSET ENDP ;[]---------------------------------------------------------------------- ;READ_DCL: Reads the disk change line status ; INPUT: AL=drive #. ; Motor is running, drive is already selected. ; OUTPUT: AH=80h if drive active, 0 if inactive ; ZFLAG = ZR if inactive ; NZ if active ; All other registers preserved. ;[]---------------------------------------------------------------------- ALIGN 4 ; N3.03 READ_DCL PROC NEAR PUSH DX XCHG AH,AL ; save drive # in ah MOV DX,FDC_CTRL_IN ; CHECK STATUS IN AL,DX XCHG AH,AL ; drive # back to al AND AH,80H ; SET ZERO FLAG POP DX RET READ_DCL ENDP PAGE ;[]---------------------------------------------------------------------- ;SET_UP_RETRIES: Sets the next xfer rate to try, and also sets the ; last xfer rate to try. ; INPUT: AL=drive. ; AH=current media ; CURRENT_MEDIA, DCAPABILITY, XFER_INFO ; OUTPUT: AH=new current media, after change. ; preserves all registers ; Note: this routine should only be called if media is not ; known. ;[]---------------------------------------------------------------------- align 4 ;R08 SET_UP_RETRIES PROC NEAR PUSH BX ; save bx AND G_RAM:[XFER_INFO],NOT 1100B ; clear stop xfer rate OR G_RAM:[XFER_INFO],1000B ; stop xfer rate is always 250 Kbs MOV BH,AH ; save current media AND BH,NOT 0C0H ; clear starting xfer rate OR BH,040H ; assume starting will be 300 kbs PUSH AX ; save reg CALL GET_CMOS_VALUE ; get CMOS drive type CMP AH,CMOS_FD_144 ; check 1.44 drive JNE SHORT SUR_START_1 ; if NOT 1.44 (or bad cmos) start at 300 kbs AND BH,NOT 0C0H ; if 1.44 start at 500 kbs JMP SHORT SUR_START_2 ; get to common code SUR_START_1: IFDEF ENABLE_288_SUPPORT CMP AH,CMOS_FD_288 ; check 2.88 drive JNE SUR_START_2 ; if NOT 2.88 (or bad cmos) start at 500 kbs OR BH,0C0H ; if 2.88 start at 1 mbs xfer rate ENDIF ;ENABLE_288_SUPPORT SUR_START_2: POP AX ; restore reg CALL GET_DCAPABILITY AND AH,0110B ; isolate dual media capability CMP AH,0100B ; if known to NOT be dual media JNE SHORT SUR_EXIT AND BH,NOT 0C0H ; then change to 250 KBS OR BH,080H SUR_EXIT: MOV AH,BH ; ah=new current media CALL SET_CURRENT_MEDIA POP BX ; recover bx RET SET_UP_RETRIES ENDP PAGE ;[]---------------------------------------------------------------------- ;RESET_XFER_RATE: Checks to see if current xfer rate is the one ; we want, and updates it if it isn't. ; INPUT: AL=drive ; CURRENT_MEDIA, XFER_INFO ; OUTPUT: ; All registers preserved. ;[]---------------------------------------------------------------------- ALIGN 4 ; N3.03 RESET_XFER_RATE PROC NEAR PUSH AX PUSH BX CALL GET_CURRENT_MEDIA ; get xfer rate for this drive AND AH,0C0H ; isolate it. ;R02 MOV BH,G_RAM:[XFER_INFO] ;R02 AND BH,0C0H ;R02 CMP AH,BH ;R02 JE SHORT RXR_EXIT CLI ; suspend interrupts, so ; xfer rate and reflection ; stay in sync. AND G_RAM:[XFER_INFO],NOT 0C0H ; clear old xfer rate OR G_RAM:[XFER_INFO],AH ; or in new one. ROL AX,2 ; shift to position for port. AND AL,03H ; all other bits = 0 MOV BX,DX ; save dx MOV DX,FDC_CTRL_IN ; point to xfer controller. OUT DX,AL ; out new xfer rate. MOV DX,BX ; recover dx STI ;R02 RXR_EXIT: POP BX POP AX RET RESET_XFER_RATE ENDP PAGE ;[]---------------------------------------------------------------------- ;PREPARE_RETRY: After a read/write or verify has been tried and failed ; at one xfer rate, this routine advances to next xfer rate, ; if any. ; INPUT: AL=drive ; AH=error code from last operation. ; OUTPUT: AH=0 if operation should be retried at new xfer rate. ; AH=unchanged if we have done all our retries. ; ;[]---------------------------------------------------------------------- ALIGN 4 PREPARE_RETRY PROC NEAR PUSH BX ; save bx MOV BH,AH ; save error code CALL GET_CURRENT_MEDIA MOV BL,AH ; bl=xfer rate AND BL,0C0H CMP BL,080H ; is it 250 kbs? JNE SHORT PR_MORE_RETRIES ; if not, try next state. MOV AH,BH ; restore error code JMP SHORT PR_EXIT PR_MORE_RETRIES: AND AH,NOT 0C0H ; assume next xfer rate = 500 KBS CMP BL,40H ; if current is 300, next is 500. JE SHORT PR_UPDATE_MEDIA IFDEF ENABLE_288_SUPPORT CMP BL,0C0H ; if current is 1MB next is 500. JE SHORT PR_UPDATE_MEDIA ENDIF ;ENABLE_288_SUPPORT OR AH,80H ; must be 500 or invalid, make into ; 250. PR_UPDATE_MEDIA: CALL SET_CURRENT_MEDIA XOR AH,AH ; indicate we should perform a retry. PR_EXIT: POP BX RET PREPARE_RETRY ENDP PAGE ;[]---------------------------------------------------------------------- ;UPDATE_MEDIA_INFO: checks to see if we've learned anything new about ; current media or the capabilities of the drive. ; If we have, it updates the appropriate variable. ; INPUT: AL=drive ; OUTPUT: CURRENT_MEDIA is determined ; DCAPABILITY's dual capability is determined. ; ;[]---------------------------------------------------------------------- ALIGN 4 ; 303A UPDATE_MEDIA_INFO PROC NEAR PUSH AX PUSH BX CALL GET_CURRENT_MEDIA OR AH,010H ; make it determined CALL SET_CURRENT_MEDIA MOV BH,AH ; save media info CALL GET_DCAPABILITY TEST AH,04H ; is dual capability already known? JNZ SHORT UMI_EXIT ; exit if it is. OR AH,06H ; assume this is a dual drive. AND BH,0C0H ; isolate xfer rate CMP BH,080H ; is it 250? JNE SHORT UMI_UPDATE_CAP ; if 300 or 500, its a dual drive. MOV BL,AH ; save current capability CALL GET_CMOS_DRIVE ; XCHG BL,AH ; recover capability JNZ SHORT UMI_UPDATE_CAP ; if cmos bad, assume dual CMP BL,4 ; if 4, its dual JE SHORT UMI_UPDATE_CAP ; AND AH,NOT 02H ; otherwise assume non-dual UMI_UPDATE_CAP: CALL SET_DCAPABILITY ; UMI_EXIT: POP BX POP AX RET UPDATE_MEDIA_INFO ENDP PAGE ;[]---------------------------------------------------------------------- ;GET_CURRENT_MEDIA: gets CURRENT_MEDIA variable for drive in al ; INPUT: AL= drive #,ES=0 ; OUTPUT: If drive 0, AH=0:490 ; else if drive 1, AH=0:491 ; All other registers preserved. ;[]---------------------------------------------------------------------- ALIGN 4 ; N3.03 GET_CURRENT_MEDIA PROC NEAR MOV AH,G_RAM:[CURRENT_MEDIA] OR AL,AL JZ SHORT GCM_EXIT MOV AH,G_RAM:CURRENT_MEDIA[1] GCM_EXIT: RET GET_CURRENT_MEDIA ENDP ;[]---------------------------------------------------------------------- ;SET_CURRENT_MEDIA: sets CURRENT_MEDIA variable for drive in al ; INPUT: AL= drive #,ES=0 ; OUTPUT: If drive 0, 0:490=AH ; else if drive 1, 0:491=AH ; All other registers preserved. ;[]---------------------------------------------------------------------- ALIGN 4 SET_CURRENT_MEDIA PROC NEAR OR AL,AL ; is it drive 1 JNZ SHORT SCM_DRIVE_1 ; jump if it is MOV CURRENT_MEDIA,AH ; update drive 0 JMP SHORT SCM_EXIT ; return SCM_DRIVE_1: MOV G_RAM:CURRENT_MEDIA[1],AH ; update drive 1 SCM_EXIT: RET SET_CURRENT_MEDIA ENDP PAGE ;[]---------------------------------------------------------------------- ;GET_CURCYL: gets CURCYL variable for drive in al ; INPUT: AL= drive #,ES=0 ; OUTPUT: If drive 0, AH=0:494 ; else if drive 1, AH=0:495 ; All other registers preserved. ;[]---------------------------------------------------------------------- ALIGN 4 GET_CURCYL PROC NEAR MOV AH,G_RAM:[CURCYL] OR AL,AL JZ SHORT GC_EXIT MOV AH,G_RAM:CURCYL[1] GC_EXIT: RET GET_CURCYL ENDP ;[]---------------------------------------------------------------------- ;SET_CURCYL: sets CURCYL variable for drive in al ; INPUT: AL= drive #,ES=0 ; OUTPUT: If drive 0, 0:494=AH ; else if drive 1, 0:495=AH ; All other registers preserved. ;[]---------------------------------------------------------------------- ALIGN 4 SET_CURCYL PROC NEAR OR AL,AL ; is it drive 1 JNZ SHORT SC_DRIVE_1 ; jump if it is MOV G_RAM:[CURCYL],AH ; update drive 0 JMP SHORT SCC_EXIT ; return SC_DRIVE_1: MOV G_RAM:CURCYL[1],AH ; update drive 1 SCC_EXIT: RET SET_CURCYL ENDP PAGE ASSUME DS:NOTHING,ES:G_RAM ;[]---------------------------------------------------------------------- ;GET_DCAPABILITY: gets DCAPABILITY variable for drive in al, ; rotates bits to bottom 3. ; INPUT: AL= drive #,ES=G_RAM ; OUTPUT: If drive 0, AH = 0:48F, bits 0-3. ; else if drive 1, AH=0:48f, bits 4-6, rotated to position 0-3. ; all other bits in AH=0 ; All other registers preserved. ;[]---------------------------------------------------------------------- ALIGN 4 GET_DCAPABILITY PROC NEAR MOV AH,G_RAM:[DCAPABILITY] OR AL,AL ; is it drive 0 JZ SHORT GD_AND_OFF ; jump if it is SHR AH,4 ; shift to low nibble. GD_AND_OFF: AND AH,07H RET GET_DCAPABILITY ENDP ;[]---------------------------------------------------------------------- ;SET_DCAPABILITY: sets DCAPABILITY variable for drive in al, ; from the three low bits in ah. ; INPUT: AL= drive #,AH=3 bits to put in DCAPABILITY,ES=G_RAM ; all other bits in AH = 0 ; OUTPUT: If drive 0, 0:48F, bits 0-3 = AH, bits 0-3. ; else if drive 1, 0:48f, bits 4-6 = AH bits 0-3 ; All registers preserved. ;[]---------------------------------------------------------------------- ALIGN 4 SET_DCAPABILITY PROC NEAR PUSH AX AND AH,07H ; just to be sure no other bits. OR AL,AL ; is it drive 0 JZ SHORT SD_AND_OFF ; jump if it is SHL AH,4 ; mov bits 0-2 to 4-6 AND G_RAM:[DCAPABILITY],NOT 70H ; erase bits 4-6 JMP SHORT SD_OR_ON SD_AND_OFF: AND G_RAM:[DCAPABILITY],NOT 07H ; erase bits 0-2 SD_OR_ON: OR G_RAM:[DCAPABILITY],AH POP AX RET SET_DCAPABILITY ENDP PAGE comment % ;R05 - start ;[]----------------------------------------------------------------------- ;GET_CMOS_DRIVE: gets drive type from CMOS. ; INPUT: AL= drive # ; OUTPUT: If CMOS good: ; AH=drive type from CMOL register 10h ; ZFLAG=ZR ; If CMOS bad: ; ZFLAG=NZ ; AH=0FFh. ; Interrupts enabled. ; All other registers preserved. ;[]------------------------------------------------------------------------ ALIGN 4 GET_CMOS_DRIVE PROC NEAR MOV AH,AL ; save drive CLI ; no interrupts while ; accessing CMOS MOV AL,STATB NMI_ON ; read status register CALL GET_CMOS TEST AL,0C0H ; bad battery or checksum JNZ SHORT GCD_ERROR_EXIT ; jump with zero flag NZ MOV AL,DSKB NMI_ON CALL GET_CMOS OR AH,AH ; drive 0? JNZ SHORT GCD_DRIVE_IN_LOW ; jump if not SHR AL,4 GCD_DRIVE_IN_LOW: AND AL,0FH CMP AH,AH ; set zero flag to zero. GCD_EXIT: XCHG AH,AL ; recover al, the drive # STI ; allow ints again. RET ; put drive type in AH GCD_ERROR_EXIT: MOV AL,0FFH ; illegal drive type JMP SHORT GCD_EXIT ; zero flag is already NZ GET_CMOS_DRIVE ENDP % ;R05 - start ;R05 - Begin ;[]----------------------------------------------------------------------- ;GET_CMOS_DRIVE: gets drive type from CMOS. ; INPUT: AL= drive # ; OUTPUT: If CMOS good: ; AH=drive type from CMOS register 10h ; ZFLAG=ZR ; If CMOS bad: ; ZFLAG=NZ ; AH=0FFh. ; Interrupts enabled. ; All other registers preserved. ;[]------------------------------------------------------------------------ ALIGN 4 GET_CMOS_DRIVE PROC NEAR IFDEF ENABLE_288_SUPPORT CALL GET_CMOS_VALUE ; ah <- value from CMOS PUSHF ; save flags from GET_CMOS_VALUE JNZ GCD_DONE ; skip if CMOS bad CMP AH,CMOS_FD_288 ; check 2.88 drive value JNE GCD_DONE ; skip if not CMOS 2.88 value MOV AH,CMOS_FD_144 ; else force 1.44 value for compatibility GCD_DONE: POPF ; restore flags from GET_CMOS_VALUE RET ; return ah and flags set ENDIF ;ENABLE_288_SUPPORT ; if not 2.88 fall through to GET_CMOS_VALUE GET_CMOS_DRIVE ENDP public GET_CMOS_VALUE ;R22 ALIGN 4 GET_CMOS_VALUE PROC NEAR ;R04A start test byte ptr G_RAM:FDD_VERIFY_CMD_FLAG,SWAP_DRIVE jz short @F xor al,1 @@: ;R04A end IFDEF FORCE_1MB_CMOS CMP AL,0 ; check drive 0 JNE GCD_CMOS ; skip if not MOV AH,CMOS_FD_288 ; else force 2.88 drive type CMP AH,AH ; set zero flag for good CMOS RET GCD_CMOS: ENDIF ;FORCE_1MB_CMOS MOV AH,AL ; save drive CLI ; no interrupts while ; accessing CMOS MOV AL,STATB NMI_ON ; read status register CALL GET_CMOS TEST AL,0C0H ; bad battery or checksum JNZ SHORT GCD_ERROR_EXIT ; jump with zero flag NZ MOV AL,DSKB NMI_ON CALL GET_CMOS OR AH,AH ; drive 0? JNZ SHORT GCD_DRIVE_IN_LOW ; jump if not SHR AL,4 GCD_DRIVE_IN_LOW: AND AL,0FH CMP AH,AH ; set zero flag to zero. GCD_EXIT: XCHG AH,AL ; recover al, the drive # STI ; allow ints again. RET ; put drive type in AH GCD_ERROR_EXIT: MOV AL,0FFH ; illegal drive type JMP SHORT GCD_EXIT ; zero flag is already NZ GET_CMOS_VALUE ENDP PAGE ;[]==================================================================[] ; ; GET_TPI: ; ; Determines how many tracks a drive supports. ; ; Input: AL=drive ;Output: NONE ; ;Author: Award ;Date: 10/02/90 ; ; Name | Date | Description ; --------------------------------------------------------------- ; TIM | 02-Oct-90 | Update for 4.0 ; ;[]==================================================================[] PUBLIC GET_TPI align 4 ;R08 GET_TPI PROC NEAR ;R20 start test byte ptr G_RAM:FDD_VERIFY_CMD_FLAG,SWAP_DRIVE jz short @F xor al,1 @@: ;R20 end PUSH AX ; save drive. CALL TURNONMOTOR ; make sure motor on. POP AX ; recover drive. CALL GET_CURRENT_MEDIA AND AH,NOT 020H ; turn off double stepping CALL SET_CURRENT_MEDIA MOV CL,AL MOV BL,0FEH ROL BL,CL AND G_RAM:[NEED_RECAL],BL ; force recalibrate ; seek to track large enough to engage braking ; mechanism on a 40 track drive, but not to much larger. ; This will cause head position to be out of sync ; with NEC head position register if 40 track, ; but not 80 track. Determine if head and register ; are out of sync by seeking back to track 0 and checking ; for drive 0 signal. If it doesn't come true when we ; expect it, it must be out of sync, and therefore 40 track. MOV AH,50 ; seek to track > 40 PUSH AX ; save drive. CALL NEC_SEEK OR AH,AH POP DX ; recover drive in DL JNZ SHORT GT_NO_DRIVE ; unable to seek out. ; seek to track 10 This will cause controller to issue ; 40 seek pulses, which on a 40 track drive with braking ; mechanism set exactly for 40 tracks will put us on ; track 0. Drive manufacturers may set braking mechanism ; anywhere between track 41-49, so we do 10 extra seeks in ; case. 80 track drives must give drive 0 signal on ; exactly the 10th seek inward. MOV DH,10 ; seek to track 10 GT_RESEEK: MOV AX,DX ; track, drive to ax. PUSH DX ; save drive, track. CALL NEC_SEEK ; POP DX OR AH,AH JNZ SHORT GT_NO_DRIVE PUSH DX ; drive on stack. MOV SI,SP ; pointer to drive parameter. MOV AH,NC_SDS ; sense drive status command MOV BL,NC_LEN_SDS ; two byte command CALL SEND_COMMAND POP DX OR AH,AH JNZ SHORT GT_NO_DRIVE PUSH DX ; no interrupt from status CALL RESULTS ; read ST3 POP DX OR AH,AH JNZ SHORT GT_NO_DRIVE TEST G_RAM:[FDC_RET_CODES],010H ; track 0? JNZ SHORT GT_GOT_CYL_0 DEC DH CMP DH,0FFH JNE SHORT GT_RESEEK JMP SHORT GT_NO_DRIVE ; no track 0, unknown. GT_GOT_CYL_0: MOV BL,1 ; assume 80 track. MOV BH,02H ; unestablished 500 kbs. OR DH,DH ; did we find 0 on track 0 JZ SHORT GT_UPDATE MOV BL,04H ; this is a 40 track drive, and MOV BH,93H ; 40 track drives don't have ; dual capability. MOV DH,0FEH ; force recalibrate, in case 40 track MOV CL,DL ROL DH,CL AND G_RAM:[NEED_RECAL],BL ; force recalibrate GT_UPDATE: MOV AL,DL CALL GET_CURRENT_MEDIA MOV AH,BH CALL SET_CURRENT_MEDIA CALL GET_DCAPABILITY MOV AH,BL CALL SET_DCAPABILITY RET GT_NO_DRIVE: ; dl=drive when jumped to ; unable to determine drive by testing XOR BX,BX ; assume no drive. MOV AL,DL JMP GT_UPDATE CALL GET_CMOS_DRIVE ; find out what CMOS says. OR AH,AH ; if cmos = 0 JZ SHORT GT_UPDATE CMP AH,4 ; or cmos invalid JA SHORT GT_UPDATE ; set to no drive. MOV BX,9304H ; assume type 1 CMP AH,1 JE SHORT GT_UPDATE ; jump if type 1. MOV BX,0201H ; else assume 80 track drive JMP GT_UPDATE GET_TPI ENDP ;[]----------------------------------------------------------------------- ;GET_PARM - ROUTINE RETRIEVES THE DISK PARAMETER BLOCK PTR AT INT 1EH ; - AND USES IT TO RETURN PARAMETER WHOSE INDEX IS PASSED ; INPUT: ; AL = INDEX ; OUTPUT: ; AL=VALUE ; AH=0, in case we want to use value as a word operand ;[]----------------------------------------------------------------------- ALIGN 4 PUBLIC GET_PARM GET_PARM PROC NEAR PUSH DS PUSH SI PUSH BX MOV BX,SEG_0 MOV DS,BX ASSUME DS:SEG_0 LDS SI,SEG_0:[DISK_PARM_PTR] XOR AH,AH ADD SI,AX LODSB POP BX POP SI POP DS ASSUME DS:NOTHING RET GET_PARM ENDP ;R22IFDEF ENABLE_288_SUPPORT ;R22 ;R22 PUBLIC FD_PERP_MODE ;R22 align 4 ;R08 ;R22FD_PERP_MODE PROC NEAR ;R22 ;R22 PUSHA ; save regs ;R22 PUSH DS ;R22 PUSH ES ;R22 ;R22 PUSH CS ; set addressibility ;R22 POP DS ;R22 ASSUME DS:DGROUP ;R22 MOV AX,G_RAM ;R22 MOV ES,AX ;R22 ASSUME ES:G_RAM ;R22 ;R22 ;R22IFDEF FORCE_PERP_MODE ;R22 MOV AL,10000100B ; set perp mode for first drive ;R22 JMP SHORT FPM_FINISH ; get to common finish mode ;R22 ;R22ELSE ;not FORCE_PERP_MODE ;R22 MOV BL,080H ; set for all drives non perp mode ;R22 ;R22 MOV AL,0 ; check drive zero for 2.88 ;R22 CALL GET_CMOS_VALUE ; get CMOS drive type ;R22 CMP AH,CMOS_FD_288 ; check 2.88 drive ;R22 JNE short PERP_1 ; skip if NOT 2.88 (or bad cmos) ;R22 OR BL,004H ; else drive 0 is setup as perp ;R22 ;R22PERP_1: ;R22 MOV AL,1 ; check drive one for 2.88 ;R22 CALL GET_CMOS_VALUE ; get CMOS drive type ;R22 CMP AH,CMOS_FD_288 ; check 2.88 drive ;R22 JNE short PERP_2 ; skip if NOT 2.88 (or bad cmos) ;R22 OR BL,008H ; else drive 1 is setup as perp ;R22 ;R22PERP_2: ;R22 XCHG AX,BX ; parm into al ;R22ENDIF ;FORCE_PERP_MODE ;R22 ;R22FPM_FINISH: ;R22 PUSH AX ; parameters on stack ;R22 MOV SI,SP ; pointer to parameters ;R22 MOV AH,012H ; perpendicular command ;R22 MOV BL,2 ; 2 bytes in perp command ;R22 CALL SEND_COMMAND ; output perp command ;R22 ADD SP,2 ; clear parameters off stack. ;R22 OR AH,AH ; error? ;R22 JNZ SHORT FPM_BAD ; skip if error ;R22 ;R22 CLC ; signal no error ;R22 JMP SHORT FPM_RET ; get to common return ;R22 ;R22FPM_BAD: ;R22 STC ; signal error ;R22 ;R22FPM_RET: ;R22 POP ES ;R22 POP DS ;R22 POPA ;R22 RET ;R22 ;R22FD_PERP_MODE ENDP ;R22 ;R22ENDIF ;ENABLE_288_SUPPORT ;R22 ;R22 ;R22 ;R22IFDEF ENABLE_FDC_FIFO ;R22 ;R22 PUBLIC FD_FIFO_MODE ;R22 align 4 ;R08 ;R22FD_FIFO_MODE PROC NEAR ;R22 ;R22 PUSHA ; save regs ;R22 PUSH DS ;R22 PUSH ES ;R22 ;R22 PUSH CS ; set addressibility ;R22 POP DS ;R22 ASSUME DS:DGROUP ;R22 MOV AX,G_RAM ;R22 MOV ES,AX ;R22 ASSUME ES:G_RAM ;R22 ;R22 MOV AL,00h ; set PRETRK for configure command ;R22 PUSH AX ; parameters on stack ;R22 MOV AL,00h ; set first parm byte for configure command ;R22 MOV AH,00h+FDC_FIFO_THRES ; set FIFO on and set threshold ;R22 PUSH AX ; parameters on stack ;R22 MOV SI,SP ; pointer to parameters ;R22 MOV AH,013H ; configure command ;R22 MOV BL,4 ; 4 bytes in configure command ;R22 CALL SEND_COMMAND ; output configure command ;R22 ADD SP,4 ; clear parameters off stack. ;R22 OR AH,AH ; error? ;R22 JNZ SHORT FFM_BAD ; skip if error to quit ;R22 ;R22 MOV AH,094H ;;;XXXX lock command ;R22 MOV BL,1 ; 1 byte in lock command ;R22 CALL SEND_COMMAND ; output lock command ;R22 OR AH,AH ; error? ;R22 JNZ SHORT FFM_BAD ; skip if error to quit ;R22 CALL RESULTS ; read results ;R22 OR AH,AH ; see if error ;R22 JNZ SHORT FFM_BAD ; skip if error to quit ;R22 ;R22 CLC ; signal no error ;R22 JMP SHORT FFM_RET ; get to common return ;R22 ;R22FFM_BAD: ;R22 STC ; signal error ;R22 ;R22FFM_RET: ;R22 POP ES ;R22 POP DS ;R22 POPA ;R22 RET ;R22 ;R22FD_FIFO_MODE ENDP ;R22 ;R22ENDIF ;ENABLE_FDC_FIFO ;R17 ;R100 Starts ;R17 ;[]============================================[] ;R17 ;Function : Flush IBM CPU cache if IBM CPU ;R17 ;Input : ES = G_RAM ;R17 ; DI = return address ;R17 ;Destroy : AL ;R17 ;[]============================================[] ;R17 Invalidate_IBM_Cache: ;R17 ;R17 mov al,es:[CPU_TYPE_FLAG] ;R17 ;R01 and al,not CPUCACHE+DOUBLECLOCK+COPROCESSOR ;R17 and al,not CPUCACHE+COPROCESSOR ;R01 ;R17 ;R17 cmp al,TYPE_IBM386SLC ;R17 je short Flush_CPU_Cache ;R17 cmp al,TYPE_IBM486SLC2 ;R17 ;R01 jne short Not_IBM_CPU ;R17 je short Flush_CPU_Cache ;R01 ;R17 cmp al,TYPE_IBM486DLC3 ;R17 jne short Not_IBM_CPU ;R01 ;R17 ;R17 Flush_CPU_Cache: ;R17 ;R17 INVD ;R17 WBINVD ;R17 ;R17 Not_IBM_CPU: ;R17 ;R17 jmp di ;R17 ret ;R17 ;R100 Ends FCODE ENDS END