; ; xenix file calls 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 XENIX - IO system to mimic UNIX NAME XENIX i_need NoSetDir,BYTE i_need CURDRV,BYTE i_need IOCALL,BYTE i_need IOMED,BYTE i_need IOSCNT,WORD i_need IOXAD,DWORD i_need DIRSTART,WORD i_need ATTRIB,BYTE i_need THISFCB,DWORD i_need AuxStack,BYTE i_need Creating,BYTE i_need ThisDRV,BYTE i_need NAME1,BYTE i_need LastEnt,WORD i_need ThisDPB,DWORD i_need EntLast,WORD i_need CurrentPDB,WORD i_need sft_addr,DWORD ; pointer to head of table i_need CURBUF,DWORD ; pointer to current buffer i_need DMAADD,DWORD ; pointer to current dma address BREAK CODE ENDS DATA SEGMENT BYTE PUBLIC 'DATA' PushSave DW ? PushES DW ? PushBX DW ? xenix_count DW ? DATA ENDS CODE SEGMENT BYTE PUBLIC 'CODE' BREAK ; ; get_sf_from_sfn ; input: AX has sfn (0 based) ; DS is DOSGROUP ; output: JNC ; ES:DI is sf entry ; JC ; ES,DI indeterminate ; procedure get_sf_from_sfn,NEAR ASSUME DS:DOSGROUP,ES:NOTHING PUSH AX ; we trash AX in process LES DI,[sft_addr] get_sfn_loop: CMP DI,-1 ; end of chain of tables? JZ get_sf_invalid ; I guess so... SUB AX,ES:[DI].sft_count ; chop number of entries in this table JL get_sf_gotten ; sfn is in this table LES DI,ES:[DI].sft_link ; step to next table JMP get_sfn_loop get_sf_gotten: ADD AX,ES:[DI].sft_count ; reset to index in this table PUSH BX MOV BX,SIZE sf_entry MUL BL ; number of bytes offset into table POP BX ADD AX,sft_table ; offset into sf table structure ADD DI,AX ; offset into memory CLC JMP SHORT get_sf_ret get_sf_jfn_invalid: get_sf_invalid: STC get_sf_jfn_ret: get_sf_ret: POP AX ; remember him? RET get_sf_from_sfn ENDP BREAK ; ; get_sf_from_jfn ; input: BX is jfn 0 based ; DS is DOSGROUP ; output: JNC ; ES:DI is sf entry ; JC ; ES,DI is indeterminate ; procedure get_sf_from_jfn,NEAR ASSUME DS:DOSGROUP,ES:NOTHING PUSH AX ; save him invoke get_jfn_pointer JC get_sf_jfn_invalid MOV AL,ES:[DI] ; get sfn CMP AL,0FFh ; is it free? JZ get_sf_jfn_invalid ; yep... error XOR AH,AH invoke get_sf_from_sfn ; check this sfn out... JMP SHORT get_sf_jfn_ret ; condition codes are properly set get_sf_from_jfn ENDP BREAK ; ; get_jfn_pointer ; input: BX is jfn ; DS is DOSGROUP ; output: JNC ; ES:DI is pointer to jfn ; JC ; procedure Get_jfn_pointer,NEAR ASSUME DS:DOSGROUP,ES:NOTHING CMP BX,FilPerProc JAE get_jfn_bad MOV ES,[CurrentPDB] MOV DI,BX ADD DI,PDB_JFN_Table CLC RET get_jfn_bad: STC RET get_jfn_pointer ENDP BREAK <$Close - release a handle> ; ; Assembler usage: ; MOV BX, handle ; MOV AH, Close ; INT int_command ; ; Error return: ; AX = error_invalid_handle ; procedure $Close,NEAR ASSUME DS:NOTHING,ES:NOTHING context DS invoke get_jfn_pointer ; get jfn loc JNC close_jfn close_bad_handle: error error_invalid_handle close_jfn: MOV AL,BYTE PTR ES:[DI] CMP AL,0FFh JE close_bad_handle MOV BYTE PTR ES:[DI],0FFh; XOR AH,AH invoke get_sf_from_sfn JC close_bad_handle PUSH ES POP DS ASSUME DS:NOTHING DEC [DI].sf_ref_count ; no more reference LEA DX,[DI].sf_fcb ; ; need to restuff Attrib if we are closing a protected file ; TEST [DI.sf_fcb.fcb_DevID],devid_file_clean+devid_device JNZ close_ok PUSH WORD PTR [DI].sf_attr invoke MOVNAMENOSET POP BX MOV [Attrib],BL invoke FCB_CLOSE_INNER CMP AL,0FFh ; file not found error? JNZ close_ok error error_file_not_found close_ok: transfer SYS_RET_OK $Close ENDP BREAK ; PushDMA ; input: DS:DX is DMA ; output: DS:DX is normalized , ES:BX destroyed ; [DMAADD] is now set up to DS:DX ; old DMA is pushed procedure PushDMA,NEAR ASSUME DS:NOTHING,ES:NOTHING MOV PushES,ES MOV PushBX,BX POP PushSave LES BX,DWORD PTR [DMAADD] ; get old dma PUSH ES PUSH BX PUSH PushSave invoke ptr_normalize ; get new dma MOV WORD PTR [DMAADD],DX ; save IT! MOV WORD PTR [DMAADD+2],DS MOV ES,PushES MOV BX,PushBX RET PushDMA ENDP ; PopDMA ; input: old DMA under ret address on stack ; output: [DMAADD] set to old version and stack popped procedure PopDMA,NEAR ASSUME DS:NOTHING,ES:NOTHING POP PushSave POP WORD PTR [DMAADD] POP WORD PTR [DMAADD+2] PUSH PushSave RET PopDMA ENDP ; ptr_normalize ; input: DS:DX is a pointer ; output: DS:DX is normalized (DX < 10h) procedure ptr_normalize,NEAR PUSH CX ; T1 = CX PUSH DX ; T2 = DX MOV CL,4 SHR DX,CL ; DX = (DX >> 4) (using CX) MOV CX,DS ADD CX,DX MOV DS,CX ; DS = DS + DX (using CX) POP DX AND DX,0Fh ; DX = T2 & 0Fh POP CX ; CX = T1 ; PUSH AX ; PUSH DX ; MOV AX,DS ; PUSH CX ; MOV CL,4 ; SHR DX,CL ; get upper part of dx ; POP CX ; ADD AX,DX ; add into seg address ; MOV DS,AX ; POP DX ; AND DX,0Fh ; save low part ; POP AX RET ptr_normalize ENDP BREAK <$Read - Do file/device I/O> ; ; Assembler usage: ; LDS DX, buf ; MOV CX, count ; MOV BX, handle ; MOV AH, Read ; INT int_command ; AX has number of bytes read ; Errors: ; AX = read_invalid_handle ; = read_access_denied ; procedure $Read,NEAR ASSUME DS:NOTHING,ES:NOTHING invoke PushDMA CALL IO_setup JC IO_err CMP ES:[DI].sf_mode,open_for_write JNE read_setup IO_bad_mode: MOV AL,read_access_denied IO_err: invoke PopDMA transfer SYS_RET_ERR read_setup: invoke $FCB_RANDOM_READ_BLOCK ; do read IO_done: invoke get_user_stack ; get old frame MOV AX,[SI].user_CX ; get returned CX MOV CX,xenix_count MOV [SI].user_CX,CX ; stash our CX invoke PopDMA ; get old DMA transfer SYS_RET_OK $Read ENDP BREAK <$Write - Do file/device I/O> ; ; Assembler usage: ; LDS DX, buf ; MOV CX, count ; MOV BX, handle ; MOV AH, Write ; INT int_command ; AX has number of bytes written ; Errors: ; AX = write_invalid_handle ; = write_access_denied ; procedure $Write,NEAR ASSUME DS:NOTHING,ES:NOTHING invoke PushDMA CALL IO_setup JC IO_err CMP ES:[DI].sf_mode,open_for_read JE IO_bad_mode invoke $FCB_RANDOM_WRITE_BLOCK ; do write JMP IO_done $write ENDP IO_setup: ASSUME DS:NOTHING,ES:NOTHING context DS MOV xenix_count,CX invoke Get_sf_from_jfn ; ES:DI is sf pointer MOV AL,read_invalid_handle ;Assume an error MOV CX,xenix_count LEA DX,[DI].sf_fcb PUSH ES POP DS ASSUME DS:NOTHING RET BREAK <$LSEEK - set random record field> ; ; Assembler usage: ; MOV DX, offsetlow ; MOV CX, offsethigh ; MOV BX, handle ; MOV AL, method ; MOV AH, LSeek ; INT int_command ; DX:AX has the new location of the pointer ; Error returns: ; AX = error_invalid_handle ; = error_invalid_function procedure $LSEEK,NEAR ASSUME DS:NOTHING,ES:NOTHING CMP AL,3 JB lseek_get_sf error error_invalid_function lseek_get_sf: context DS invoke get_sf_from_jfn PUSH ES POP DS ASSUME DS:NOTHING JC lseek_bad ; ; don't seek device ; TEST [DI.sf_fcb+fcb_devid],devid_device JZ lseek_dispatch XOR AX,AX XOR DX,DX JMP SHORT lseek_ret lseek_dispatch: DEC AL JL lseek_beginning DEC AL JL lseek_current ; move from end of file ; first, get end of file XCHG AX,DX ; AX <- low XCHG DX,CX ; DX <- high ASSUME DS:NOTHING ADD AX,[DI+sf_fcb+fcb_FILSIZ] ADC DX,[DI+sf_fcb+fcb_FILSIZ+2] JMP SHORT lseek_ret lseek_beginning: XCHG AX,DX ; AX <- low XCHG DX,CX ; DX <- high lseek_ret: MOV WORD PTR [DI+sf_fcb+fcb_RR],AX MOV WORD PTR [DI+sf_fcb+fcb_RR+2],DX invoke get_user_stack MOV [SI.user_DX],DX MOV [SI.user_AX],AX transfer SYS_RET_OK lseek_current: ; ES:DI is pointer to sf... need to invoke set random record for place XCHG AX,DX ; AX <- low XCHG DX,CX ; DX <- high ADD AX,WORD PTR [DI+sf_fcb+fcb_RR] ADC DX,WORD PTR [DI+sf_fcb+fcb_RR+2] JMP lseek_ret lseek_bad: error error_invalid_handle $lseek ENDP BREAK <$IOCTL - return/set device dependent stuff> ; ; Assembler usage: ; MOV BX, Handle ; MOV DX, Data ; ; (or LDS DX,BUF ; MOV CX,COUNT) ; ; MOV AH, Ioctl ; MOV AL, Request ; INT 21h ; ; Error returns: ; AX = error_invalid_handle ; = error_invalid_function ; = error_invalid_data procedure $IOCTL,NEAR ASSUME DS:NOTHING,ES:NOTHING MOV SI,DS ;Stash DS for calls 2,3,4 and 5 context DS CMP AL,3 JA ioctl_check_block ;Block device PUSH DX invoke get_sf_from_jfn POP DX ;Restore DATA JNC ioctl_check_permissions ; have valid handle error error_invalid_handle ioctl_check_permissions: CMP AL,2 JAE ioctl_control_string CMP AL,0 MOV AL,BYTE PTR ES:[DI+sf_fcb+fcb_devid] JZ ioctl_read ; read the byte OR DH,DH JZ ioctl_check_device ; can I set with this data? error error_invalid_data ; no DH <> 0 ioctl_check_device: TEST AL,devid_ISDEV ; can I set this handle? JZ ioctl_bad_fun ; no, it is a file. MOV BYTE PTR ES:[DI+sf_fcb+fcb_devid],DL transfer SYS_RET_OK ioctl_read: XOR AH,AH TEST AL,devid_ISDEV ; Should I set high byte JZ ioctl_no_high ; no LES DI,DWORD PTR ES:[DI+sf_fcb+fcb_FIRCLUS] ;Get device pointer MOV AH,BYTE PTR ES:[DI.SDEVATT+1] ;Get high byte ioctl_no_high: invoke get_user_stack MOV DX,AX MOV [SI.user_DX],DX transfer SYS_RET_OK ioctl_control_string: TEST BYTE PTR ES:[DI+sf_fcb+fcb_devid],devid_ISDEV ; can I? JZ ioctl_bad_fun ; no, it is a file. LES DI,DWORD PTR ES:[DI+sf_fcb+fcb_FIRCLUS] ;Get device pointer XOR BL,BL ; Unit number of char dev = 0 JMP SHORT ioctl_do_string ioctl_check_block: DEC AL DEC AL ;4=2,5=3,6=4,7=5 CMP AL,3 JBE ioctl_get_dev MOV AH,1 SUB AL,4 ;6=0,7=1 JZ ioctl_get_status MOV AH,3 DEC AL JNZ ioctl_bad_fun ioctl_get_status: PUSH AX invoke GET_IO_FCB POP AX JC ioctl_acc_err invoke IOFUNC MOV AH,AL MOV AL,0FFH JNZ ioctl_status_ret INC AL ioctl_status_ret: transfer SYS_RET_OK ioctl_bad_fun: error error_invalid_function ioctl_acc_err: error error_access_denied ioctl_get_dev: PUSH CX PUSH DX PUSH AX PUSH SI ;DS in disguise MOV AL,BL ;Drive invoke GETTHISDRV JC ioctl_bad_drv invoke FATREAD ;"get" the drive MOV BL,ES:[BP.dpb_UNIT] ; Unit number LES DI,ES:[BP.dpb_driver_addr] CLC ;Make sure error jump not taken ioctl_bad_drv: POP SI POP AX POP DX POP CX JC ioctl_acc_err ioctl_do_string: TEST ES:[DI.SDEVATT],DEVIOCTL ;See if device accepts control JZ ioctl_bad_fun ;NO DEC AL DEC AL JZ ioctl_control_read MOV [IOCALL.REQFUNC],DEVWRIOCTL JMP SHORT ioctl_control_call ioctl_control_read: MOV [IOCALL.REQFUNC],DEVRDIOCTL ioctl_control_call: MOV AL,DRDWRHL MOV AH,BL ;Unit number MOV WORD PTR [IOCALL.REQLEN],AX XOR AX,AX MOV [IOCALL.REQSTAT],AX MOV [IOMED],AL MOV [IOSCNT],CX MOV WORD PTR [IOXAD],DX MOV WORD PTR [IOXAD+2],SI PUSH ES POP DS ASSUME DS:NOTHING MOV SI,DI ;DS:SI -> driver PUSH SS POP ES MOV BX,OFFSET DOSGROUP:IOCALL ;ES:BX -> Call header invoke DEVIOCALL2 MOV AX,[IOSCNT] ;Get actual bytes transferred transfer SYS_RET_OK $IOCTL ENDP BREAK ; ; Assembler usage: ; MOV AH, FileTimes ; MOV AL, func ; MOV BX, handle ; ; if AL = 1 then then next two are mandatory ; MOV CX, time ; MOV DX, date ; INT 21h ; ; if AL = 0 then CX/DX has the last write time/date ; ; for the handle. ; ; Error returns: ; AX = error_invalid_function ; = error_invalid_handle ; procedure $File_times,near CMP AL,2 JB filetimes_ok error error_invalid_function filetimes_ok: PUSH SS POP DS CALL Get_sf_from_jfn JNC filetimes_disp error error_invalid_handle filetimes_disp: OR AL,AL JNZ filetimes_set MOV CX,ES:[DI.sf_fcb.fcb_FTIME] MOV DX,ES:[DI.sf_fcb.fcb_FDATE] invoke Get_user_stack MOV [SI.user_CX],CX MOV [SI.user_DX],DX transfer SYS_RET_OK filetimes_set: MOV ES:[DI.sf_fcb.fcb_FTIME],CX MOV ES:[DI.sf_fcb.fcb_FDATE],DX AND ES:[DI.sf_fcb.fcb_DEVID],NOT devid_file_clean transfer SYS_RET_OK $file_times ENDP do_ext CODE ENDS END