; ; Device call routines for MSDOS ; INCLUDE DOSSEG.ASM IFNDEF KANJI KANJI EQU 0 ;FALSE ENDIF CODE SEGMENT BYTE PUBLIC 'CODE' ASSUME SS:DOSGROUP,CS:DOSGROUP .xlist .xcref INCLUDE DOSSYM.ASM INCLUDE DEVSYM.ASM .cref .list TITLE DEV - Device call routines NAME Dev i_need IOXAD,DWORD i_need IOSCNT,WORD i_need DEVIOBUF,4 i_need IOCALL,BYTE i_need IOMED,BYTE i_need IORCHR,BYTE i_need CALLSCNT,WORD i_need DMAAdd,DWORD i_need NullDevPt,DWORD i_need CallDevAd,DWORD i_need Attrib,BYTE i_need NULDEV,DWORD i_need Name1,BYTE i_need DevPt,DWORD i_need DPBHead,DWORD i_need NumIO,BYTE i_need ThisDPB,DWORD i_need DevCall,DWORD i_need VerFlg,BYTE SUBTTL IOFUNC -- DO FUNCTION 1-12 I/O PAGE IOFUNC_RETRY: ASSUME DS:NOTHING,ES:NOTHING invoke restore_world procedure IOFUNC,NEAR ASSUME DS:NOTHING,ES:NOTHING ; Inputs: ; DS:SI Points to FCB ; AH is function code ; = 0 Input ; = 1 Input Status ; = 2 Output ; = 3 Output Status ; = 4 Flush ; AL = character if output ; Function: ; Perform indicated I/O to device or file ; Outputs: ; AL is character if input ; If a status call ; zero set if not ready ; zero reset if ready (character in AL for input status) ; For regular files: ; Input Status ; Gets character but restores fcb_RR field ; Zero set on EOF ; Input ; Gets character advances fcb_RR field ; Returns ^Z on EOF ; Output Status ; Always ready ; AX altered, all other registers preserved MOV WORD PTR [IOXAD+2],SS MOV WORD PTR [IOXAD],OFFSET DOSGROUP:DEVIOBUF MOV WORD PTR [IOSCNT],1 MOV WORD PTR [DEVIOBUF],AX IOFUNC2: TEST [SI.fcb_DEVID],080H JNZ IOTODEV JMP IOTOFILE IOTODEV: invoke save_world PUSH DS PUSH SS POP ES PUSH SS POP DS ASSUME DS:DOSGROUP XOR BX,BX MOV [IOCALL.REQSTAT],BX MOV BYTE PTR [IOMED],BL MOV BX,OFFSET DOSGROUP:IOCALL MOV CX,(DEVRD SHL 8) OR DRDWRHL OR AH,AH JZ DCALLR MOV CX,(DEVRDND SHL 8) OR DRDNDHL DEC AH JZ DCALLR MOV CX,(DEVWRT SHL 8) OR DRDWRHL DEC AH JZ DCALLO MOV CX,(DEVOST SHL 8) OR DSTATHL DEC AH JZ DCALLO DFLUSH: MOV CX,(DEVIFL SHL 8) OR DFLSHL DCALLR: MOV AH,86H DCALL: MOV [IOCALL.REQLEN],CL MOV [IOCALL.REQFUNC],CH MOV CL,AH POP DS ASSUME DS:NOTHING CALL DEVIOCALL MOV DI,[IOCALL.REQSTAT] TEST DI,STERR JZ OKDEVIO MOV AH,CL invoke CHARHARD CMP AL,1 JZ IOFUNC_RETRY ;Know user must have wanted ignore. Make sure device shows ready so ;that DOS doesn't get caught in a status loop when user simply wants ;to ignore the error. AND BYTE PTR [IOCALL.REQSTAT+1], NOT (STBUI SHR 8) OKDEVIO: PUSH SS POP DS ASSUME DS:DOSGROUP CMP CH,DEVRDND JNZ DNODRD MOV AL,BYTE PTR [IORCHR] MOV [DEVIOBUF],AL DNODRD: MOV AH,BYTE PTR [IOCALL.REQSTAT+1] NOT AH ; Zero = busy, not zero = ready AND AH,STBUI SHR 8 invoke restore_world ASSUME DS:NOTHING MOV AX,WORD PTR [DEVIOBUF] return DCALLO: MOV AH,87H JMP SHORT DCALL IOTOFILE: ASSUME DS:NOTHING OR AH,AH JZ IOIN DEC AH JZ IOIST DEC AH JZ IOUT return ; NON ZERO FLAG FOR OUTPUT STATUS IOIST: PUSH WORD PTR [SI.fcb_RR] ; Save position PUSH WORD PTR [SI.fcb_RR+2] CALL IOIN POP WORD PTR [SI.fcb_RR+2] ; Restore position POP WORD PTR [SI.fcb_RR] return IOUT: CALL SETXADDR invoke STORE invoke FINNOSAV CALL RESTXADDR ; If you change this into a jmp don't come return ; crying to me when things don't work ARR IOIN: CALL SETXADDR invoke LOAD PUSH CX invoke FINNOSAV POP CX OR CX,CX ; Check EOF CALL RESTXADDR MOV AL,[DEVIOBUF] ; Get byte from trans addr retnz MOV AL,1AH ; ^Z if EOF return SETXADDR: POP WORD PTR [CALLSCNT] ; Return address invoke save_world PUSH WORD PTR [DMAADD] ; Save Disk trans addr PUSH WORD PTR [DMAADD+2] PUSH DS PUSH SS POP DS ASSUME DS:DOSGROUP MOV CX,WORD PTR [IOXAD+2] MOV WORD PTR [DMAADD+2],CX MOV CX,WORD PTR [IOXAD] MOV WORD PTR [DMAADD],CX ; Set byte trans addr MOV CX,[IOSCNT] ; ioscnt specifies length of buffer POP DS ASSUME DS:NOTHING MOV [SI.fcb_RECSIZ],1 ; One byte per record MOV DX,SI ; FCB to DS:DX invoke GETRRPOS JMP SHORT RESTRET ; RETURN ADDRESS RESTXADDR: POP WORD PTR [CALLSCNT] ; Return address POP WORD PTR [DMAADD+2] ; Restore Disk trans addr POP WORD PTR [DMAADD] invoke restore_world RESTRET:JMP WORD PTR [CALLSCNT] ; Return address IOFUNC ENDP SUBTTL DEVIOCALL, DEVIOCALL2 - CALL A DEVICE PAGE procedure DEVIOCALL,NEAR ASSUME DS:NOTHING,ES:NOTHING ; Inputs: ; DS:SI Points to device FCB ; ES:BX Points to request data ; Function: ; Call the device ; Outputs: ; None ; DS:SI,AX destroyed, others preserved LDS SI,DWORD PTR [SI.fcb_FIRCLUS] entry DEVIOCALL2 ; As above only DS:SI points to device header on entry, and DS:SI is preserved MOV AX,[SI.SDEVSTRAT] MOV WORD PTR [CALLDEVAD],AX MOV WORD PTR [CALLDEVAD+2],DS CALL DWORD PTR [CALLDEVAD] MOV AX,[SI.SDEVINT] MOV WORD PTR [CALLDEVAD],AX CALL DWORD PTR [CALLDEVAD] return DEVIOCALL ENDP SUBTTL DEVNAME - LOOK FOR NAME OF DEVICE PAGE procedure DEVNAME,NEAR ASSUME DS:DOSGROUP,ES:DOSGROUP ; Inputs: ; DS,ES:DOSGROUP ; Filename in NAME1 ; Function: ; Determine if file is in list of I/O drivers ; Outputs: ; Carry set if name not found ; ELSE ; Zero flag set ; BH = Bit 7,6 = 1, bit 5 = 0 (cooked mode) ; bits 0-4 set from low byte of attribute word ; DEVPT = DWORD pointer to Device header of device ; Registers BX destroyed PUSH SI PUSH DI PUSH CX IF KANJI PUSH WORD PTR [NAME1] CMP [NAME1],5 JNZ NOKTR MOV [NAME1],0E5H NOKTR: ENDIF TEST BYTE PTR [ATTRIB],attr_volume_id ; If looking for VOL id don't find devs JNZ RET31 MOV SI,OFFSET DOSGROUP:NULDEV LOOKIO: ASSUME DS:NOTHING TEST [SI.SDEVATT],DEVTYP JZ SKIPDEV ; Skip block devices PUSH SI ADD SI,SDEVNAME MOV DI,OFFSET DOSGROUP:NAME1 MOV CX,4 ; All devices are 8 letters REPE CMPSW ; Check for name in list POP SI JZ IOCHK ; Found it? SKIPDEV: LDS SI,DWORD PTR [SI] ; Get address of next device CMP SI,-1 ; At end of list? JNZ LOOKIO RET31: STC ; Not found RETNV: PUSH SS POP DS ASSUME DS:DOSGROUP IF KANJI POP WORD PTR [NAME1] ENDIF POP CX POP DI POP SI RET IOCHK: ASSUME DS:NOTHING MOV WORD PTR [DEVPT+2],DS ; Save pointer to device MOV BH,BYTE PTR [SI.SDEVATT] OR BH,0C0H AND BH,NOT 020H ;Clears Carry MOV WORD PTR [DEVPT],SI JMP RETNV DevName ENDP procedure GetBP,NEAR ASSUME DS:DOSGROUP,ES:NOTHING ; Inputs: ; AL = Logical unit number (A = 0) ; Function: ; Find Drive Parameter Block ; Outputs: ; ES:BP points to DPB ; [THISDPB] = ES:BP ; Carry set if unit number bad ; No other registers altered LES BP,[DPBHEAD] ; Just in case drive isn't valid AND AL,3FH ; Mask out dirty and device bits CMP AL,BYTE PTR [NUMIO] CMC JC GOTDPB ; Get drive A FNDDPB: CMP AL,ES:[BP.dpb_drive] JZ GOTDPB ; Carry is clear if jump executed LES BP,ES:[BP.dpb_next_dpb] JMP SHORT FNDDPB GOTDPB: MOV WORD PTR [THISDPB],BP MOV WORD PTR [THISDPB+2],ES RET GetBP ENDP SUBTTL SETREAD, SETWRITE -- SET UP HEADER BLOCK PAGE procedure SETREAD,NEAR ASSUME DS:NOTHING,ES:NOTHING ; Inputs: ; DS:BX = Transfer Address ; CX = Record Count ; DX = Starting Record ; AH = Media Byte ; AL = Unit Code ; Function: ; Set up the device call header at DEVCALL ; Output: ; ES:BX Points to DEVCALL ; No other registers effected PUSH DI PUSH CX PUSH AX MOV CL,DEVRD SETCALLHEAD: MOV AL,DRDWRHL PUSH SS POP ES MOV DI,OFFSET DOSGROUP:DEVCALL STOSB ; length POP AX STOSB ; Unit PUSH AX MOV AL,CL STOSB ; Command code XOR AX,AX STOSW ; Status ADD DI,8 ; Skip link fields POP AX XCHG AH,AL STOSB ; Media byte XCHG AL,AH PUSH AX MOV AX,BX STOSW MOV AX,DS STOSW ; Transfer addr POP CX ; Real AX POP AX ; Real CX STOSW ; Count XCHG AX,DX ; AX=Real DX, DX=real CX, CX=real AX STOSW ; Start XCHG AX,CX XCHG DX,CX POP DI MOV BX,OFFSET DOSGROUP:DEVCALL RET entry SETWRITE ASSUME DS:NOTHING,ES:NOTHING ; Inputs: ; DS:BX = Transfer Address ; CX = Record Count ; DX = Starting Record ; AH = Media Byte ; AL = Unit Code ; Function: ; Set up the device call header at DEVCALL ; Output: ; ES:BX Points to DEVCALL ; No other registers effected PUSH DI PUSH CX PUSH AX MOV CL,DEVWRT ADD CL,[VERFLG] JMP SHORT SETCALLHEAD SETREAD ENDP do_ext CODE ENDS END