; File : $CIO.A86$ ; ; Description : ; ; Original Author : DIGITAL RESEARCH ; ; Last Edited By : $CALDERA$ ; ;-----------------------------------------------------------------------; ; Copyright Work of Caldera, Inc. All Rights Reserved. ; ; THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL, ; PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC. ; ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES ; WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF ; THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO ; HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE ; AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE ; AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED, ; COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED, ; CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST, ; TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF ; CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT ; AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND ; CIVIL LIABILITY. ;-----------------------------------------------------------------------; ; ; *** Current Edit History *** ; *** End of Current Edit History *** ; $Log: $ ; CIO.A86 1.20 94/12/01 10:05:21 ; Made cooked_write and is_device aware of FCB writes; ; CIO.A86 1.19 94/06/28 12:21:07 ; Fix last_key_ext bug ; CIO.A86 1.18 94/05/12 14:06:22 ; The routine cooked_status now sets a flag last_key_ext if the keycode is 0. ; On entry, it checks this flag to see if the last one was 0, and if so does ; not do the checks for the control keys. In this way, Alt-R and Alt-Q can ; be distinguished from Ctrl-S and Ctrl-P. ; CIO.A86 1.17 93/12/21 17:58:15 ; Preserve BX round clock read ; Update char_error so DS:SI -> device driver header itself ; CIO.A86 1.10 93/05/06 19:28:03 ; Move int 23/28 support to CIO. ; Read the clock in idle_dev, not int 28 loop. ; CIO.A86 1.9 93/05/05 23:30:44 ; int 2A/84 is now only generated on input-and-wait functions ; CIO.A86 1.8 93/03/25 15:05:56 ; tweak console block output ; ENDLOG ; ; This module contains all the Character I/O functions used by PCMODE ; ; 12 Nov 87 Disable Control-Break when the Console Output mode is RAW ; 24 Feb 88 Display Control characters correctly. ie "^X" ; 23 May 88 Support ^S to Pause screen output. ; 25 May 88 Support Control-P for Cooked_Write and remove Kanji Character ; check. ; 26 May 88 Check for CTLC on CON_DEV when character input is redirected. ; Correctly detect EOF on redirected input. ; 17 Aug 88 Call PRN device with Open/Close on ^P ; 30 Aug 88 Jump to correct exit when Open/Close is not supported by a ; device driver for ^P. ; 14 Sep 88 Break checking should only be carried out when the INDOS_FLAG ; is 1. (Novell and Cntrl-C). ; 03 Sep 88 Return the character output by INT21/04,05,06 in AL. ; 10 Nov 88 Preserve ES when calling any Device Driver (Revalation DEVDRVR) ; 15 Dec 88 Check STDERR for Control-C if it is a Device. ; 15 Mar 89 Check for CTLC during Cooked Write. ; 16 Mar 89 Explicitly allow INT 28 during char reads (SmartNotes bug) ; 25 Apr 89 Execute break_check after getting the console status INT21/0B ; 2 May 89 Save Device driver STRAT and INT address's on the stack ; 10 May 89 Now check keyboard more often during cooked write ; 25 May 89 Move INT28 flag to PCMIF.PCM ; 6 Sep 89 Enter/Exit critical region round device request ; 26 Oct 89 saving some bytes again... ; 25 Jan 90 Insert IDLE Detection Code ; 29 Jan 90 Int 2A critical section support added to device_callf ; 7 Mar 90 Convert to register preserved function calls ; 27 Mar 90 cooked_write checks STD_OUT for ctl-s ctl-p etc (STD_IN may ; have been redirected) ; 29 Mar 90 preserve BX round device_callf (3+Share CLOCK$ bug) ; 12 Jun 90 get_doshndl parameter BX not AX ; 15 Oct 90 Added support for Return Interim Character flag (see PSP_RIC). ; 26 Oct 90 handle PSP=0 (ie. FCB device I/O) ; 1 mar 91 break_check now goes to con_device, not STDERR ; 17 jun 91 ij fix to cooked_out to avoid status checks if STDOUT redirected include pcmode.equ include i:driver.equ include i:reqhdr.equ include i:msdos.equ include i:fdos.equ include i:psp.def include i:mserror.equ include i:char.def include i:redir.equ include i:doshndl.def CIO_CTLP equ 0000$0001b ; Printer Echo State CIO_HANDLE equ 0000$0010b ; use handle rather than Int 29 CIO_RAW equ 0000$0100b ; no "cooked_status" checks CHECK_EVERY equ 80 ; check keyboard every "n" characters PCM_CODE CSEG BYTE extrn char_error:near extrn device_driver:near extrn dos_entry:near extrn get_dseg:near extrn ifn2dhndl:near extrn int21_entry:near extrn int21_func:near extrn read_line:near extrn ReadTimeAndDate:near extrn reload_registers:near ; ***************************** ; *** DOS Function 01 *** ; *** Keybd Input W/Echo *** ; ***************************** ; Public func01 func01: ; ; Entry: ; AH == 01h ; Exit: ; AL == char ; call func08 ; Read 1 character from Standard Input ; and check for Control-C xchg ax,dx ; echo using common code ; ***************************** ; *** DOS Function 02 *** ; *** Display Output *** ; ***************************** ; Public func02 func02: ; ; Entry: ; AH == 02h ; DL == char to display ; push dx ; char on stack push ss ! pop es mov si,sp ; ES:DX -> character mov cx,1 call stdout_cooked_write ; write character pop ax ; recover char ret ; ***************************** ; *** DOS Function 03 *** ; *** Auxiliary Input *** ; ***************************** ; Public func03 func03: ; ; Entry: ; AH == 03h ; Exit: ; AL == Char ; mov bx,STDAUX ; Read 1 character from Standard AUX f03_10: jmp raw_read ; ***************************** ; *** DOS Function 04 *** ; *** Auxiliary Output *** ; ***************************** ; Public func04 func04: ; ; Entry: ; AH == 04h ; DL == Character to output ; mov bx,STDAUX ; write the character passed in DL jmps f456common ; to the STDAUX Handle ; ***************************** ; *** DOS Function 05 *** ; *** Printer Output *** ; ***************************** ; Public func05 func05: ; ; Entry: ; AH == 05h ; DL == character to output to printer ; mov bx,STDPRN ; write the character passed in DL ; jmp f456common ; to the STDPRN Handle f456common: xchg ax,dx ; character in AL ; jmp hndl_write hndl_write: ;---------- ; On Entry: ; AL = character to write ; BX = handle ; On Exit: ; AL preserved ; call is_device ; Does this handle refer to a device jc hndl_w10 test es:DH_ATTRIB[si],DA_SPECIAL jz hndl_w10 ; Fast Console Output Using Int 29? int 29h ; This device supports FAST console ret ; output so write this using Int29 hndl_w10: push ax ; character on stack mov dx,sp ; SS:DX -> char mov cx,1 ; do a single character jc hndl_w20 ; was it a file ? call device_write ; send to device driver jmps hndl_w30 hndl_w20: push ss ! pop es ; ES:DX -> character mov ah,MS_X_WRITE ; otherwise call the FDOS to do all call dos_entry ; the hard work hndl_w30: pop ax ret ; ***************************** ; *** DOS Function 06 *** ; *** Direct Console I/O *** ; ***************************** ; Public func06 func06: ; ; Entry: ; AH == 06h ; DL == 0FFh or Output char ; Exit: ; AL == Input char, if DL was 0FFh on input ; mov bx,STDOUT ; Assume output DL to console cmp dl,0FFH ; or is it input ? jne f456common dec bx ; mov bx,STDIN ; is there a character ready call char_check ; to be input jz func07 mov ax,RHS_IC ; set AL=0 and also set ZF on jmps funcICexit ; exit as incomplete char ; ***************************** ; *** DOS Function 07 *** ; *** Raw Input w/o echo *** ; ***************************** ; Public func07 func07: ; ; Entry: ; AH == 07h ; Exit: ; AL == character ; mov bx,STDIN call raw_read ; extra status call made jmps funcICexit ; set incomplete char ; ***************************** ; *** DOS Function 08 *** ; *** Input w/o echo *** ; ***************************** ; Public func08 func08: ; ; Entry: ; AH == 08h ; Exit: ; AL == character ; mov bx,STDIN ; Read 1 character from Standard Input call cooked_read funcICexit: ; exit point for incomplete character support ; On Entry: ; AL = character ; AH = request header status (RHS_IC as on return from device driver) ; On Exit: ; AL = character ; dos_FLAGS ZF set if incomplete character ; les di,int21regs_ptr ; point to callers registers and es:reg_FLAGS[di],not ZERO_FLAG ; clear ZF test ah,RHS_IC/256 ; is it an incomplete char ? jz funcIC10 ; no - exit or es:reg_FLAGS[di],ZERO_FLAG ; yes - set ZF funcIC10: ret ; ***************************** ; *** DOS Function 09 *** ; *** Print String *** ; ***************************** ; Public func09 func09: ; ; Entry: ; AH == 09h ; DS:DX == address of character string ; mov al,'$' ; it's terminated with a '$' mov di,dx ; locate the end of the string mov cx,0FFFFh ; and calculate its length repnz scasb not cx dec cx ; CX is the character count mov si,dx call stdout_cooked_write ; ES:SI -> character buffer mov al,'$' ret ; ***************************** ; *** DOS Function 0A *** ; *** Read String *** ; ***************************** ; Public func0A func0A: ; ; Entry: ; AH == 0Ah ; DS:DX == pointer to input buffer ; mov bx,STDIN ; Read the editted line from STDIN mov cx,STDOUT ; and display the results on STDOUT jmp read_line ; Read the Line ; ***************************** ; *** DOS Function 0B *** ; *** Console Status *** ; ***************************** ; Public func0B func0B: ; ; Entry: ; AH == 0Bh ; Exit: ; AL == 0FFh if char available ; == 00h otherwise ; mov bx,STDIN call cooked_status ; Get the current handle status mov al,0FFh ; Assume that the handle is ready jz f0B_exit ; and return 0FFh in AL mov al,00 ; Not Ready f0B_exit: jmps funcICexit ; exit thru incomplete char support ; ***************************** ; *** DOS Function 0C *** ; *** Flush and Execute *** ; ***************************** ; Public func0C func0C: ; ; Entry: ; AH == 0Ch ; AL == function to execute: 1,6,7,8 or A ; Exit: ; AL = 0 if function in AL is invalid ; push ax ; save sub-function mov bx,STDIN ; Is this Standard Input Handle a call is_device ; file or device. Do not flush the jc f0C_20 ; buffer contents for a FILE f0C_10: call hndl_instat ; check if any characters are left jnz f0C_20 ; and quit when buffer empty call raw_read ; read the character jmps f0C_10 ; loop till the buffer is empty f0C_20: pop ax cmp al,01h ! je al_ok ; is legal for this command cmp al,0ah ! je al_ok cmp al,06h ! jb al_nogo cmp al,08h ! ja al_nogo al_ok: ; Valid function so now execute call reload_registers ; all register reloaded as per entry mov ah,al ; Get the requested sub-function in AH jmp int21_func ; execute the function al_nogo: ; Illegal command to execute xor ax,ax ; from this function so return error ret eject ; ; BREAK_CHECK checks for a CNTRL-C and is called by functions 01h to ; 0Ch. Or by the entry code if the break flag is non zero. ; Public break_check break_check: cmp indos_flag,01 ; Skip the check if we are jnz break_c15 ; already in the emulator push ax push es push si les si,con_device call device_instat ; get the input status pop si pop es jnz break_c10 ; No Character Ready cmp al,CTLC ; Is the character a Control-C jz break_c20 ; Yes break_c10: pop ax break_c15: ret break_c20: ; The User has Typed Control-C so flush mov bx,0FFFFh ; input buffer (FFFF=con_device) call char_get go_int23: push cs ! pop es ; ES:DX -> Character Buffer mov si,offset cntrl_c_msg ; Message Offset mov cx,length cntrl_c_msg ; Message Length call stdout_cooked_write ; write the ^C String to console ; ; Prepare to execute an Interrupt 23 (Break Check) and process ; the return values. If the called routine returns with an IRET ; or with a RETF and the carry flag reset continue the function ; otherwise Abort. ; mov es,current_psp ; Get the Entry SS and SP mov ax,PSP_USERSP ; Get the Users Stack Pointer add ax,18 - 2 ; Compensate for the User Registers mov break_sp,ax ; and save for RETF check cli dec indos_flag ; Exit the PCDOS emulator mov ss,PSP_USERSS ; Switch to the Users Stack mov sp,PSP_USERSP ; and Restore the registers POP$DOS ; Update the registers then ; set the flags and return ; to the user clc ; Default to continue function int 23h ; Call the Break Handler cli ; Check the Flag State jnc do23_10 ; If CARRY then Abort this process call get_dseg ; Get our data segment mov exit_type,TERM_BREAK ; Force EXIT_TYPE to TERM_BREAK mov ax,4C00h ; "Good-Bye Cruel World" jmps do23_20 do23_10: push ds ; Otherwise restart the aborted func call get_dseg cmp sp,break_sp pop ds ; Restore the the USER DS correct jz do23_30 ; Did we Use a RETF or Not do23_20: add sp,2 ; Yes so correct the stack pointer do23_30: ; and restart the aborted function jmp int21_entry ; re-start the function call eject ; ; cooked_status is called on input or output and looks for live keys ^C,^P,^S. ; If any of these are found they are dealt with. ; If ^P is encountered it is swallowed. ; If ^C is encountered we always do an Int23. ; If ^S is pressed we swallow it, and the next character (checking for ^C, but ; not for ^P), then say a character is ready. ; Note that this can lead to status calls (func0B) hanging inside the OS, ; or the return of ^S characters from input calls (func01), but this is ; intentional. ; cooked_status: ;------------- ; check input ; On Entry: ; BX = handle to check ; On Exit: ; ZF set if character available ; AL = character ; AH = RHS_IC ; call break_check ; check for a ^C on console call char_check ; is there a character ready jnz cooked_s50 ; no so keep scanning cmp last_key_ext,0 ; was last char an zero ? mov last_key_ext,0 ; (clear flag for next time) jne cooked_s40 ; skip ^P,^S,^C checks if so cmp al,CTLP ; has the user typed ^P jne cooked_s10 ; flush the buffer and xor cio_state,CIO_CTLP ; toggle ^P flag call char_get ; flush the character from buffer call open_or_close_prn ; open/close printer device test ax,ax ; ZF clear, ie. no char available jmps cooked_s50 cooked_s10: cmp al,CTLC jnz cooked_s30 ; has the user typed ^C call char_get ; so get the RAW character cooked_s20: jmp go_int23 ; and terminate the function cooked_s30: cmp al,CTLS ; pause if the user has typed jnz cooked_s40 ; a ^S call char_get ; remove ^S and resume when call raw_read_wait ; the next character is typed cmp al,CTLC je cooked_s20 ; has the user typed ^C cooked_s40: cmp al,0 jne cooked_s45 mov last_key_ext,1 cooked_s45: cmp ax,ax ; ZF set, ie. char available cooked_s50: ret eject ; ; The COOKED, CMDLINE and RAW Read functions are basically the same ; except in their treatment of 'live' characters ^C,^P, and ^S. ; COOKED will look for and act upon all three live characters. ; CMDLINE will look for and act upon ^C and ^P, but ^S will be returned ; so we can use it as a line editing key. ; RAW will not check for any live keys. ; public cmdline_read, raw_read ; for CMDLINE.PCM cmdline_read_wait: ; Waiting for a device to become call idle_dev ; ready. So call IDLE routines to ; put the processor to sleep. cmdline_read: call break_check ; check for a ^C on console call char_check ; is there a character ready jnz cmdline_read_wait ; no so keep scanning cmp al,CTLS ; if the user has typed ^S jne cooked_read ; we have to do a raw read ; jmps raw_read ; else we do a cooked read raw_read_wait: ; Waiting for a device to become call idle_dev ; ready. So call IDLE routines to ; put the processor to sleep. raw_read: call char_check ; Is there a character Ready jnz raw_read_wait ; loop until character available jmps char_get cooked_read_wait: ; Waiting for a device to become call idle_dev ; ready. So call IDLE routines to ; put the processor to sleep. cooked_read: call break_check ; check for a ^C on console call cooked_status ; check for a ^S,^P,^C on handle BX jnz cooked_read_wait ; wait until char is available ; jmps char_get ; else get the character char_get: push es ! push ax ; Input one character and mov dx,sp ; return it in AL call is_device ; Does this handle refer to a device mov cx,1 jc char_get30 ; if it's a device then call device_read ; use device_read char_get20: pop ax ! pop es ret char_get30: ; We are redirected, so call to the FDOS to get a character push ss ! pop es ; EX:DX -> character to read mov ah,MS_X_READ ; call the FDOS to do all call dos_entry ; the hard work jmps char_get20 eject stdout_cooked_write: mov bx,STDOUT ; output to the console device ; jmp cooked_write ; ; The COOKED_WRITE routine will expand TABS etc in the string ; passed passed by the calling routine. ; ; On Entry: ; ES:SI Buffer Address ; CX Character Count ; BX Output Handle ; On Exit: ; AL = last char written ; Public cooked_write cooked_write: push es push bx mov ah,cio_state ; get CIO_CTLP status or ah,CIO_RAW+CIO_HANDLE ; assume we will want raw handle output mov al,bl test byte ptr remote_call+1,DHM_FCB/100h jnz cook_w03 mov es,current_psp ; get our PSP cmp bx,PSP_XFNMAX ; range check our handle jae cook_w05 les di,PSP_XFTPTR mov al,es:byte ptr [bx+di] ; AL = Internal File Handle cook_w03: call ifn2dhndl ; ES:BX -> DHNDL_ jc cook_w05 ; skip if bad handle mov dx,es:DHNDL_WATTR[bx] ; get handle attributes and dx,DHAT_DEV+DHAT_CIN+DHAT_COT+DHAT_BIN+DHAT_REMOTE cmp dx,DHAT_DEV+DHAT_CIN+DHAT_COT+DHAT_BIN je cook_w04 ; accept binary console device cmp dx,DHAT_DEV+DHAT_CIN+DHAT_COT jne cook_w05 ; skip if not cooked console device and ah,not CIO_RAW ; we want cooked output cook_w04: les bx,es:DHNDL_DEVPTR[bx] ; its the console - but is it FAST ? test es:DH_ATTRIB[bx],DA_SPECIAL jz cook_w05 ; skip if not and ah,not CIO_HANDLE ; don't use handle functions cook_w05: pop bx pop es jcxz cook_w80 cook_w10: lods es:al ; Read the next character cmp al,DEL ! je cook_w60 ; DEL is a NON Printing Character cmp al,' ' ! jae cook_w50 ; Space and Above are Normal cmp al,LF ! je cook_w60 ; Just print LineFeeds cmp al,ESC ! je cook_w60 ; Just print Escape cmp al,BELL! je cook_w60 ; Just ring the Bell cmp al,CR ! jne cook_w20 ; CR zeros the column number mov column,0 mov char_count,1 ; check for ^S etc NOW jmps cook_w60 cook_w20: cmp al,CTLH ! jne cook_w30 ; BackSpace decrements the dec column ; column count by one jmps cook_w60 cook_w30: cmp al,TAB ! jne cook_w60 ; is it a TAB ? cook_w40: mov al,' ' ; spaces call cooked_out ; output a space char inc column test column,7 ; are we at a TAB stop yet ? jnz cook_w40 jmps cook_w70 cook_w50: inc column ; Update the column count and cook_w60: call cooked_out ; output the character cook_w70: loop cook_w10 ; onto the next character cook_w80: ret cooked_out: ; On Entry: ; AH = handle status ; AL = character ; BX = handle ; On Exit: ; AX, BX, CX, ES:SI preserved ; dec char_count ; time to check keyboard input ? jz cooked_o10 ; no, skip status check test ah,CIO_HANDLE+CIO_CTLP ; is it complicated ? jnz cooked_o10 int 29h ; This device supports FAST console ret cooked_o10: push es push ax push cx push si call hndl_write ; display the character test ah,CIO_CTLP ; Check for Printer Echo jz cooked_o20 ; Off so No Echo push bx ; Save Output Handle mov bx,STDPRN ; and output the same data to the call hndl_write ; to the Printer Handle pop bx cooked_o20: test ah,CIO_RAW ; is it a cooked console ? jnz cooked_o30 ; skip check if not call cooked_status ; look for keyboard input mov char_count,CHECK_EVERY ; look again in a while cooked_o30: pop si pop cx pop ax pop es ret eject ; IDLE_DEV is called when the PCMODE is waiting for a character. ; This routine must determine if the request is for a device or not ; and call the IDLE interface for device requests to the system can be ; put to sleep until a character is ready. ; ; On Entry:- BX Handle Number ; idle_dev: push bx ; preserve handle mov ax,8400h int 2ah ; Server hook for idle dec clock_count jnz idle_dev10 ; Zero if NO skip delay and execute call ReadTimeAndDate ; for PC BIOS's who must read every day idle_dev10: if IDLE_DETECT test idle_flags,IDLE_DISABLE ; Has Idle Checking been enabled jnz idle_dev40 ; Skip if NO push es ! push si call is_device ; The requested handle a file or device jc idle_dev30 ; File Access skip IDLE mov ax,PROC_KEYIN ; Assume this is the REAL Console test es:DH_ATTRIB[si],DA_ISCIN; Test Attribute Bits jnz idle_dev20 ; Yes this is Default Console Device mov ax,PROC_DEVIN ; Input from Another Device idle_dev20: callf idle_vec ; Call the IDLE Handler idle_dev30: pop si ! pop es idle_dev40: endif pop bx ; recover handle ret eject ; The following routine reads CX bytes from the device whose address ; is held in the DWORD pointer passed by DS:SI. A Request Header ; is built on the stack and the command is executed. ; ; On Entry: ; ES:SI DWORD Pointer to Device Header ; SS:DX Buffer Address ; CX Character Count ; ; On Exit: ; AX Request Header Status ; Zero No Error ; Public device_read device_read: mov al,CMD_INPUT ; we want input jmps device_common ; now use common code eject ; The following routine writes CX bytes to the device whose address ; is held in the DWORD pointer passed by DS:SI. A Request Header ; is built on the stack and the command is executed. ; ; On Entry: ; ES:SI DWORD Pointer to Device Header ; SS:DX Buffer Address ; CX Character Count ; ; On Exit: ; AX Request Header Status ; Zero No Error ; Public device_write device_write: mov al,CMD_OUTPUT ; we want output device_common: push bx sub sp,RH4_LEN ; reserve space on the stack mov bx,sp ; request header offset mov ss:RH_LEN,RH4_LEN ; request header length mov ss:RH4_BUFOFF,dx ; buffer offset mov ss:RH4_BUFSEG,ss ; buffer segment device_common10: mov ss:RH4_COUNT,cx ; character count call device_req ; execute command jns device_common20 ; if no errors return to the caller sub cx,ss:RH4_COUNT ; CX = chars remaining push ax ; save the error code call char_error ; ask int 24 what to do cmp al,ERR_RETRY ; should we retry the operation ? pop ax ; recover the error code ja device_common20 ; Fail/Abort return error mov al,ss:RH_CMD ; reload the command je device_common10 ; Retry, re-issue the device request mov ax,RHS_DONE ; Ignore, pretend no errors device_common20: add sp,RH4_LEN ; restore the stack to its normal test ax,RHS_ERROR ; state and return the status. pop bx ret char_check: ; On Entry: ; BX = handle to check ; On Exit: ; ZF set if character ready ; AL = character (if device handle) ; AH = RIC status ; push bx ; Save the current handle status if IDLE_DETECT test idle_flags,IDLE_DISABLE ; Has Idle Checking been enabled jnz char_check10 ; Skip if NO dec int28_delay ; Has the INT28 Loop count reached jnz char_check10 ; Zero if NO skip delay and execute mov ax,int28_reload ; INT28. Otherwise DELAY/DISPATCH mov int28_delay,ax mov ax,PROC_INT28 ; Process is IDLE callf idle_vec ; Call the IDLE Handler char_check10: endif cmp indos_flag,1 ; Only execute an INT 28 jnz char_check20 ; when the INDOS flag is 1 cmp int28_flag,TRUE ; Only generate INT 28s for the jnz char_check20 ; selected functions push remote_call push machine_id mov es,current_psp ; Get the PSP push PSP_USERSP ; Save the SS:SP pointer to push PSP_USERSS ; the register image if IDLE_DETECT ; Set IDLE_INT28 so $IDLE$ knows or idle_flags,IDLE_INT28 ; that we are nolonger inside DOS endif int 28h ; Execute an INT 28 for SideKick and ; the PRINT utility. INDOS flag is 1 if IDLE_DETECT ; Reset IDLE_INT28 so $IDLE$ knows and idle_flags,not IDLE_INT28; that we are back DOS endif mov int28_flag,TRUE ; Restore INT28_FLAG mov es,current_psp ; Get the PSP pop PSP_USERSS ; Restore the SS:SP pointer to pop PSP_USERSP ; the register image pop machine_id pop remote_call char_check20: pop bx ; jmp hndl_instat ; Check Input Status. ZERO == Ready ; ; hndl_instat: call is_device ; Does this handle refer to a device jnc device_instat mov ax,(MS_X_IOCTL shl 8)+6 ; Get the file status call dos_entry ; for the specified handle cmp al,0FFh ; and return ZERO until the EOF ret ; The following routine executes the Non Destructive Input ; command to the device whose address passed in ES:SI. ; ; On Entry: ; ES:SI DWORD Pointer to Device Header ; ; On Exit: ; Zero Character Ready ; AH Top Byte Request Header Status ; AL Next Character if ZERO ; device_instat: push bx sub sp,RH5_LEN ; Reserve Space on the Stack mov bx,sp ; Request Header Offset mov ss:RH_LEN,RH5_LEN ; Set Request Header Length mov al,CMD_INPUT_NOWAIT ; Command Number call device_req ; Execute the Command mov al,ss:RH5_CHAR ; Assume a character is ready add sp,RH5_LEN ; Restore the Stack to its normal test ax,RHS_BUSY ; state and return the status. pop bx ; Zero if a Character is ready ret ; The following routine handles the low level device interface to ; the character device drivers. All the generic Request Header ; initialization is carried out here. ; ; On Entry: ; AL Command ; ES:SI Device Header ; SS:BX Current Request Header ; ; On Exit: ; AX Request Header Status ; device_req: ;---------- mov ss:RH_CMD,al ; save the command push ds push es push es ! pop ds ; DS:SI -> device driver mov es,ss:current_psp ; es = current PSP mov al,es:PSP_RIC ; al = Return Interim Character flag mov ss:RH4_RIC,al ; Return Interim Char flag push ss ! pop es ; ES:BX -> RH_ call device_driver pop es pop ds ret eject ; ; IS_DEVICE checks the internal handle structures to determine ; if the handle referenced in BX is a file or device. Invalid ; handles all map to the default console device. ; ; On Entry: ; BX Handle Number ; ; On Exit: ; CY set if handle is for a file ; CY clear if handle is for device at ES:SI ; is_device: push ax push bx ; Convert the Standard Handle number mov ax,bx ; get XFN in AL ; mov cx,current_psp ; into an internal handle number ; jcxz is_dev10 ; no PSP, we have IFN already ; mov es,cx test byte ptr remote_call+1,DHM_FCB/100h; if FCB initiated access jnz is_dev10 ; we have IFN already mov es,current_psp cmp bx,es:PSP_XFNMAX ; Check if the handle is in range for jae is_dev_bad ; this PSP. les si,es:PSP_XFTPTR mov al,es:byte ptr [bx+si] ; AL = Internal File Handle is_dev10: call ifn2dhndl ; ES:BX -> DHNDL_ jc is_dev_bad mov ax,es:DHNDL_WATTR[bx] ; get file attributes and ax,DHAT_REMOTE+DHAT_DEV cmp ax,DHAT_DEV ; is it a local device ? stc ; assume it's a file jne is_dev30 les si,es:DHNDL_DEVPTR[bx] ; its a device is_dev20: clc is_dev30: pop bx pop ax ret is_dev_bad: les si,con_device ; bad handles map to console jmps is_dev20 open_or_close_prn: ;----------------- ; called when CIO_CTLP toggled - call prn device with Open or Close as appropriate ; push ds ! push ax ! push bx mov ax,CTLP push ax ; ^P on stack mov cx,current_psp ; look in PSP jcxz oc_prn30 ; no PSP, forget it mov es,cx cmp bx,PSP_XFNMAX ; Check if the handle is in range for jae oc_prn30 ; this PSP. les si,es:PSP_XFTPTR ; for the internal handle number mov al,es:byte ptr STDPRN[si] cmp al,0FFh ; AL = Internal File Handle je oc_prn30 ; skip if invalid Handle Number call ifn2dhndl ; ES:BX -> doshndl jc oc_prn30 test es:DHNDL_WATTR[bx],DHAT_NETPRN jz oc_prn10 mov ax,I2F_CTLP ; turn on the network printer int 2fh ; with a magic INT 2F call jnc oc_prn10 and cio_state,not CIO_CTLP ; make sure Printer Echo is off mov ax,I2F_CTLP_ERR int 2fh jmps oc_prn30 oc_prn10: mov ax,es:DHNDL_WATTR[bx] ; get file attributes and ax,DHAT_REMOTE+DHAT_DEV cmp ax,DHAT_DEV ; is it a local device ? jne oc_prn30 mov al,CMD_DEVICE_OPEN ; assume we've just opened test cio_state,CIO_CTLP ; Check for Printer Echo jnz oc_prn20 ; yes, skip next bit mov al,CMD_DEVICE_CLOSE ; no, we must close oc_prn20: les si,es:DHNDL_DEVPTR[bx] ; get the device driver address test es:DH_ATTRIB[si],DA_REMOVE jz oc_prn30 ; no, skip call if not supported sub sp,RH13_LEN ; Reserve Space on the Stack mov bx,sp ; and point to it mov ss:RH_LEN,RH13_LEN ; Set Request Header Length mov ss:RH_CMD,al ; Command Number call device_driver ; issue the command add sp,RH13_LEN ; Restore the Stack to its normal oc_prn30: pop ax ; discard ^P from stack pop bx ! pop ax ! pop ds ret PCM_RODATA CSEG WORD cntrl_c_msg db '^C', CR, LF ; Control-Break Message GLOBAL_DATA dseg clock_count db 0 PCMODE_DATA DSEG WORD extrn break_sp:word ; For Control-Break handler extrn char_count:byte extrn cio_state:byte ; Character I/O State extrn column:byte ; Console Cursor Location extrn con_device:dword ; Current Console Device extrn current_psp:word ; Current PSP Address extrn exit_type:byte extrn last_key_ext:byte extrn indos_flag:byte ; INDOS Count extrn int21regs_ptr:dword ; pointer to callers registers extrn machine_id:word extrn remote_call:word if IDLE_DETECT extrn idle_flags:word ; IDLE State Flags extrn idle_vec:dword ; IDLE routine Vector extrn int28_delay:word extrn int28_reload:word extrn int28_flag:byte endif end