Files
Digital-Research-Source-Code/CPM OPERATING SYSTEMS/CPM 86/CONCURRENT/CCPM-86 3.1 SOURCE/D4/XCHAR.LIB
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

1212 lines
28 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

eject ; Dec 13, 1983
; SERIAL I/O
; ----------
;************************************************
;* *
;* CONSOLE INPUT *
;* *
;************************************************
reorg6 equ offset $
cseg
org reorg6
;========
io_const:
;========
xor ax,ax
ret
wake_key equ 7DH ;window manager alarm clock
full_key equ 7EH ;full/partial window toggle
; console input entry point
; entry: dl = console number
io_conin:
mov dl,top_screen ; current foreground console
call point_vs ; point to console structure
cmp vs_pfk_count,0 ; check for pfk's waiting
jz conin_wait ; skip if none
mov si,vs_pfk_ptr ; else get the current ptr
lodsb ; grab the value
test al,al ; if valid, then skip
jnz conin_pfk
mov vs_pfk_count,al ; if not, zap the count
jmps conin_wait ; and wait for key
conin_pfk:
mov vs_pfk_ptr,si ; update pointer
dec vs_pfk_count ; decrement the count
mov ah,0 ; clear out the flag
ret ; and return with value
conin_wait:
push bx
push cx
mov dx,ci_flag ; get the flag number
call flagwait ; wait for a key
pop cx ; recover the virtual cons #
pop bx ; recover vs_ pointer
mov ax,key ; get the character and type
test ah,ah ; set the flags
jz conin_done ; normal ascii then leap
cmp al,wake_key ; switch to window manager?
jz w_wake
cmp al,full_key ; switch to full screen?
jz w_full
cmp al,070h
jb new_pfk ; set pfk pointer and count
and al,0Fh ; keep it to 16 vc's
conin_done:
ret
pfk_l_size equ 20 ; chars per pfk in low table
pfk_h_size equ 4 ; chars per pfk in high table
low_pfks equ 10 ; number of 20 char pfk codes
high_pfks equ 40 ; number of 4 char pfk codes
; a pfk has just been typed, set pointers and count
new_pfk:
cmp al,low_pfks + high_pfks ; if pfk code is too big
jae conin_wait ; then ignore it
cmp vs_pfk_exp,0 ; if pfk expansion flag off
jz no_pfk_exp ; then just return code
call point_pfk ; set pointer and count
jmps io_conin ; back to return the value
no_pfk_exp:
mov bx,offset pfk_code_tbl
xlat bx ; convert to code
or al,80h ; put the msb back
mov ah,0 ; zero the flag
ret ; and return the code
; point to pfk table - public, called by z_prog_pfk
; entry: al = pfk table index
; bx -> vs_
; exit: vs_pfk_ptr -> pfk value
; vs_pfk_count = maximum char count
point_pfk:
sub si,si ; zero offset for low table
mov cl,pfk_l_size ; chars per low pfk
cmp al,low_pfks ; check for low table
jb point_pfk1 ; skip if F1 - F10
sub al,low_pfks ; index into high table
mov si,pfk_l_size * low_pfks ; offset for high table
mov cl,pfk_h_size ; chars per high pfk
point_pfk1:
mul cl ; index into table
add si,ax
add si,vs_pfk_tbl ; add table offset
mov vs_pfk_ptr,si ; set initial pointer
mov vs_pfk_count,cl ; and initial count
ret
; wake up the window manager
w_wake:
cmp im_here,1 ; see if manager is resident
jb conin_wait ; ignore if not
call check_no_switch ; if console is no switch
jnz conin_wait ; then ignore wmenu key
cmp graphic_bits,0 ; if anyone is in graphics
jnz conin_wait ; then block out wmenu
mov im_here,2 ; resident and active
mov dx,ww_flag
mov key_flag,dx ; redirect the keyboard
mov ww_stat_flag,true ; for ww_key status check
call flagset ; wake up the manager
pushf ; now fake an interrupt
callf dword ptr dispatcher ; and a return
jmp conin_wait ; wait for keyboard restore
; if current window is small, switch to full
; if current window is full, switch to previous window
w_full:
mov dl,top_screen ; get active console num
call ww_full_window ; full/small switch
jmp conin_wait ; get another character
; check for console in no switch mode
; exit: zf set switch is allowed
check_no_switch:
mov al,top_screen
cbw
shl ax,1
xchg bx,ax ; bx = screen word ptr
mov bx,ccb_list[bx] ; get foreground ccb
test c_state[bx],csm_noswitch ; set flag if switchable
ret
; XIOS back door entry to pass window manager a keystroke.
; Window manager will go to sleep on this call if cl < 0FEH.
; entry: cl = 0FFH => input/status
; exit: al = char if char ready
; al = 0 if no char ready
; cl = 0FEH => status only
; exit: al = 0FFH if char ready
; al = 0 if no char ready
; cl < 0FEH => wait for input
; exit: al = char when ready
; exit: if al = char then
; ah = key type
; 0 => regular
; 0FFH => special
ww_key:
mov ah,0
mov al,ww_stat_flag ;true if a character is ready
cmp cl,0FEH ;if status check, just return
jz ww_key_exit
jb ww_get_key ;if cl < FE, then read a key
test al,al ;if cl = FF, then
jz ww_key_exit ; return a 0 if not ready
ww_get_key: ;else read a key
mov dx,ww_flag ;get window flag
call flagwait ;wait till awakened
mov ww_stat_flag,false ;turn off status byte
mov ax,key ;get char and type
ww_key_exit:
ret ;and just return it
;************************************************
;* *
;* PROGRAMMABLE FUNCTION KEY TABLES *
;* *
;************************************************
reorg7 equ (offset $ + 1) and -2
dseg
org reorg7
; pfk codes used for programming and no-exp returns
pfk_code_tbl db ';<=>?@ABCD' ; F1 - F10
db 'GHIKMOPQRS' ; numeric pad
db 'abcdefghij' ; alt F1 - F10
db 'klmnopqrst' ; shift F1 - F10
db 'uvwxyz{|}~' ; crtl F1 - F10
pfk_tbl0: ; for virtual console #0
; F1 - F10
db 'DIR A:',cr,0,' '
db 'DIR B:',cr,0,' '
db 'SDIR A:',cr,0,' '
db 'SDIR B:',cr,0,' '
db 'SHOW A:',cr,0,' '
db 'SHOW B:',cr,0,' '
db 'DSKMAINT',cr,0,' '
db 'PIP',cr,0,' '
db 'FUNCTION',cr,0,' '
db 'CONFIG',cr,0,' '
; numeric keypad
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7Fh,0
; alt F1 - alt F10
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
; shift F1 - shift F10
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
; ctrl F1 - crtl F10
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
pfk_tbl1: ; for virtual console #1
; F1 - F10
db 'DIR A:',cr,0,' '
db 'DIR B:',cr,0,' '
db 'SDIR A:',cr,0,' '
db 'SDIR B:',cr,0,' '
db 'SHOW A:',cr,0,' '
db 'SHOW B:',cr,0,' '
db 'DSKMAINT',cr,0,' '
db 'PIP',cr,0,' '
db 'FUNCTION',cr,0,' '
db 'CONFIG',cr,0,' '
; numeric keypad
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7Fh,0
; alt F1 - alt F10
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
; shift F1 - shift F10
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
; ctrl F1 - crtl F10
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
pfk_tbl2: ; for virtual console #2
; F1 - F10
db 'DIR A:',cr,0,' '
db 'DIR B:',cr,0,' '
db 'SDIR A:',cr,0,' '
db 'SDIR B:',cr,0,' '
db 'SHOW A:',cr,0,' '
db 'SHOW B:',cr,0,' '
db 'DSKMAINT',cr,0,' '
db 'PIP',cr,0,' '
db 'FUNCTION',cr,0,' '
db 'CONFIG',cr,0,' '
; numeric keypad
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7Fh,0
; alt F1 - alt F10
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
; shift F1 - shift F10
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
; ctrl F1 - crtl F10
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
pfk_tbl3: ; for virtual console #3
; F1 - F10
db 'DIR A:',cr,0,' '
db 'DIR B:',cr,0,' '
db 'SDIR A:',cr,0,' '
db 'SDIR B:',cr,0,' '
db 'SHOW A:',cr,0,' '
db 'SHOW B:',cr,0,' '
db 'DSKMAINT',cr,0,' '
db 'PIP',cr,0,' '
db 'FUNCTION',cr,0,' '
db 'CONFIG',cr,0,' '
; numeric keypad
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7Fh,0
; alt F1 - alt F10
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
; shift F1 - shift F10
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
; ctrl F1 - crtl F10
dw 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;********************************************************
;* *
;* STATUS LINE ROUTINE *
;* *
;********************************************************
; Display status line on 25th line of IBM PC monochrome
; screen. First gather information into local string
; and then copy to the video display RAM.
; The format of the status line is:
;Console=1 Buffered FILENAME ABCDM* ^S ^P=0 Printer=2 Win Caps Num 12:34:56 am
; Dynamic ^O
sl_mono_bit equ 01h ; if status goes to monochrome
sl_color_bit equ 02h ; if status goes to color
reorg8 equ offset $
cseg
org reorg8
; quick return. status line is being used
ret_statline:
ret
; window manager status line call. the same as a normal call
; except that source data is char/attrib (160 bytes)
ww_statline:
mov si,offset sl_get_160 ;for char/attrib fetch
jmps sl_free ;go to it
; normal io status line call
; entry: if cx = 0 normal status update
; if cx = offset, print 80 chars at cx:dx
; if cx = 0FFFFh, resume normal status
; exit: al = 0 if call was successful
; al = 0FFh if call was blocked
io_statline:
mov si,offset sl_get_80 ;for char/attrib fetch
sl_shared:
mov al,true
xchg sline_locked,al ;is in io_statline at time
test al,al ;sline_locked = 0ffh if locked
jz sl_free ;sline_locked = 0 if not
cmp sl_exit_value,al ;if not locked on exit
jnz ret_statline ;then just return
sl_free:
push es ;save UDA
jcxz sl_keep ;if cx=0, skip source update
mov sl_off,cx ;store offset
mov sl_seg,dx ; and segment of source data
sl_keep:
cmp sl_off,0ffffh ;if normal status line
jz sl_norm ; then skip
jcxz sl_ex ;if cx=0, ignore the call
mov sl_get_char,si ;save fetch call
mov si,sl_off ;source offset
mov dl,sl_crt_flag ;which crt bits
call sl_disp_prep ;ready reg's for display
sl_ext_loop:
mov es,sl_seg ;source segment
call sl_get_char ;either get_80 or get_160
call sl_put_char ;put one char to status line
loop sl_ext_loop ;80 times
sl_ex:
jmp sl_exit
sl_get_80:
mov al,es:[si] ;fetch character only
mov ah,sl_attrib ;status line attribute
inc si ;bump once
ret
sl_get_160:
mov ax,es:[si] ;fetch character / attribute
inc si ;and bump twice
inc si
ret
; normal status line update
sl_norm:
push ds ! pop es
mov di,offset smsg_cnum
mov al,' ' ! mov cx,offset smsg_pstr - offset smsg_cnum
rep stosb ;blank out local status string
mov di,offset smsg_pnum
mov cx,offset smsg_hour - offset smsg_pnum
rep stosb
mov al,top_screen
cbw ;ah=0
mov bx,ax ;for ccb fetch
add al,'0' ;console numbers 0-3
mov smsg_cnum,al ;set console number
add bx,bx ;word pointer
mov bx,ccb_list[bx] ;get process which owns the
mov si,c_owner[bx] ;top console
test si,si ! jz s_nopd ;make sure a process is currently
mov al,p_list[si]
add al,'0' ! mov smsg_pnum,al
lea si,p_name[si] ;offset of process name
mov di,offset smsg_pd
mov cx,4 ! rep movsw
s_nopd:
s_ctrlS:
mov ax,c_state[bx]
test ax,csm_ctrlS ! jz s_ctrlO
mov s_msgctrlS,'S^' ! jmps s_ctrlP
s_ctrlO:
test ax,csm_ctrlO ! jz s_ctrlP ;ctrl S and ctrl O are mutally
mov s_msgctrlS,'O^' ;exclusive print one of ^S or ^O
s_ctrlP:
test ax,csm_ctrlP ! jz s_mode
mov s_msgctrlP,'P^'
mov dl,'=' ! mov dh,c_mimic[bx]
add dh,'0' ! mov smsg_ctrlP_num,dx
s_mode:
mov di,offset s_msgmode
mov cx,length dynstr
mov si,offset noswstr
test ax,csm_noswitch ! jnz s_movmode ;if 1 noswitch
mov si,offset dynstr
test ax,csm_buffered ! jz s_movmode ;if 0 dynamic
mov si,offset bufstr
test ax,csm_purging ! jz s_movmode ;if 0 buffered
mov si,offset purstr ;else purging
s_movmode:
rep movsb
s_get_openvec: ; display a letter for each drive
; with open files ABCDM*
mov dx,open_vec ; BDOS sets this vector in SYSDAT
mov di,offset smsg_openvec
mov si,offset sl_drive_list
mov cx,6 ; drives to check
s_get_open1:
lodsw ; get test mask
test dx,ax ; if this drive is not on
jz s_get_open2 ; then skip
movsb ; store the drive letter
jmps s_get_open3 ; skip the pointer bump
s_get_open2:
inc si
inc di
s_get_open3:
loop s_get_open1
s_window:
cmp im_here,0 ! jz s_capslock
mov si,offset winstr
mov di,offset smsg_window
mov cx,length winstr
rep movsb
s_capslock:
mov al,toggle_bits
test al,capslock_bit ! jz s_numlock
mov si,offset capstr
mov di,offset smsg_capslock
mov cx,length capstr
rep movsb
s_numlock:
test al,numlock_bit ! jz sl_time
mov si,offset numstr
mov di,offset smsg_numlock
mov cx,length numstr
rep movsb
sl_time:
cmp sl_clk_flag,0 ; if clocks disabled
jz sl_display ; then skip
sl_hours:
mov al,tod_hour ; get current hour from sysdat
cmp al,sl_hour_save ; if no change
jz sl_minutes ; then skip
mov sl_hour_save,al ; save for future skip
mov dx,'ma' ; assume 'am'
cmp al,12h ; if in the morning
jb sl_hour1 ; then skip
sub al,12h ; correct the hour
das ; (it's decimal dummy!)
mov dx,'mp' ; and make it 'pm'
sl_hour1:
cmp al,0 ; if hour = 0
jnz sl_hour2 ; then make it 12
mov al,12h
sl_hour2:
mov smsg_ampm,dx ; save 'am' or 'pm'
call sl_ascii ; convert bcd to ascii
cmp al,'0' ; blank a leading zero
jnz sl_hour3
mov al,' '
sl_hour3:
mov smsg_hour,ax ; and store the hour
sl_minutes:
mov al,tod_min
cmp al,sl_min_save ; if no change in minutes
jz sl_seconds ; then skip
mov sl_min_save,al ; save the value
call sl_ascii ; convert bcd to ascii
mov smsg_min,ax ; and store the minute
sl_seconds:
mov al,tod_sec ; always do seconds
call sl_ascii ; convert bcd to ascii
mov smsg_sec,ax ; and store the second
sl_display:
mov dl,sl_crt_flag ; get allowable crt bits
test dl,sl_mono_bit + sl_color_bit
jz sl_exit ; if both off, bag it
mov si,offset status_msg
call sl_disp_prep ; get the reg's ready
mov ah,sl_attrib ; status line attribute
sl_disp1:
lodsb ; get character
call sl_put_char ; put ax to status line
loop sl_disp1
sl_exit:
pop es
mov al,sl_exit_value ; successful update
mov sline_locked,al ; free the semaphore
ret
; set up pointers and count for status display
sl_disp_prep:
mov di,sl_offset * 2
mov bx,offset status_copy
mov cx,80 ; character count
ret
; put one char/attrib to either or both status lines
; entry: ax = char/attrib
; dl = crt code mask 01 => mono 02 => color
sl_put_char:
cmp ax,[bx] ; if character is the same
jz sl_put4 ; then just bump pointers
mov [bx],ax ; save the copy
test dl,sl_mono_bit
jz sl_put1 ; skip if not to mono
mov es,sl_mono_seg
mov es:[di],ax ; store if mono on
sl_put1:
test dl,sl_color_bit
jz sl_put4 ; back to loop if off
cmp graphic_bits,0 ; if anyone is in graphics
jnz sl_put4 ; then don't show color
; color status line character output
push bx ; get some room
push cx
push dx
mov es,sl_color_seg
mov bx,ax ; save char in bx
mov dx,color_port+6 ; crt status
mov cx,3 ; maximum wait
cli ;; hold the interrupts
sl_c_norm1:
in al,dx ;; wait for horiz retrace
test al,hrt ;; to go away
loopnz sl_c_norm1 ;; but don't wait too long
sl_c_norm2:
in al,dx ;; wait for a fresh
test al,hrt ;; horiz retrace
jz sl_c_norm2
xchg ax,bx ;; char to ax
stosw ;; store and bump di
sti ;; ints back on
pop dx ; recover registers
pop cx
pop bx
jmps sl_put_5 ; di already bumped
sl_put4:
inc di ; bump the crt pointer
inc di
sl_put5:
inc bx ; bump the copy pointer
inc bx
ret ; back to loop
; convert bcd in al to ascii in ax
sl_ascii:
mov ah,33h ; the ms nibbles
mov cl,4
ror ax,cl ; al = 10's digit
mov cl,4
ror ah,cl ; ah = 1's digit
ret
; *** Status line error message entry ***
;
; entry: si -> error message
; di -> allowable responses (count,string..)
; exit: al = response character
sl_error_out:
mov al,true
xchg al,sline_locked ; test and set status semaphore
test al,al
jnz sl_error_out ; if somebody's using it, wait
mov sl_exit_value,true
mov sl_error_msg,si ; save message offset
mov sl_error_resp,di ; and responses
push sl_off ; save offset address
push sl_seg ; and segment
push key_flag ; save keyboard state
push es
push ds ! pop es ; for local moves
mov si,offset status_copy
mov di,offset sl_error_save
mov cx,80
rep movsw ; save the current status line
pop es
mov dx,ds
mov cx,sl_error_msg
call io_statline ; print the error message
inc beep_counter
er_response:
inc beep_counter ; beep once
mov dx,er_flag
mov key_flag,dx ; now keyboard is ours
call flagwait ; wait here for a key
mov ax,key ; get the ascii key value
and al,0DFh ; convert to upper case
mov di,sl_error_resp
mov cl,[di]
mov ch,0
jcxz er_resp_good ; if di -> 0, take anything
push es
push ds ! pop es
inc di ; to response chars
repnz scasb ; check for legal value
pop es
jnz er_response ; if bad, try again
er_resp_good:
mov sl_error_key,al ; save the value
mov dx,ds
mov cx,offset sl_error_save
call ww_statline ; full 160 byte write
pop key_flag
pop sl_seg
pop sl_off
mov sline_locked,false
mov sl_exit_value,false
mov al,sl_error_key ; return value
ret
reorg_sl1 equ offset $
dseg
org reorg_sl1
; status line data area
sline_locked db 0 ; semaphore for status line code
sl_clk_flag db 0FFh ; do we show the clock?
sl_exit_value db 0 ; restore semaphore on exit
sl_attrib db 0Bh ; enhanced cyan for PC
sl_off dw 0ffffh ; offset of source
sl_seg dw 0 ; segment of source
sl_get_char rw 1 ; variable fetch vector
sl_mono_seg dw 0B000h ; monochrome crt base address
sl_color_seg dw 0B800h ; color crt base address
sl_hour_save db 0 ; current bcd hour
sl_min_save db 0 ; current bcd minute
sl_error_msg rw 1 ; error message offset
sl_error_resp rw 1 ; allowable response table offset
sl_error_key rb 1 ; response key
; status line message image
status_msg rb 0
db 'Console=' ;0-7
smsg_cnum rb 1 ;8
db ' ' ;9
smsg_mode rb 8 ;10-17
db ' ' ;18-19
smsg_pd rb 8 ;20-27
db ' ' ;28
smsg_openvec rb 6 ;29-34
db ' ' ;35
smsg_ctrlS rw 0 ;36-37
smsg_ctrlO rw 1 ;36-37
db ' ' ;38
smsg_ctrlP rw 1 ;39-40
smsg_ctrlP_num rw 1 ;41-42
db ' ' ;43
smsg_pstr db 'Printer=' ;44-51
smsg_pnum rb 1 ;52
db ' ' ;53-54
smsg_window rb 3 ;55-57
db ' ' ;58
smsg_capslock rb 4 ;59-62
db ' ' ;63
smsg_numlock rb 3 ;64-66
db ' ' ;67-68
smsg_hour dw '0 ' ;69-70
smsg_c1 db ':' ;71
smsg_min dw '00' ;72-73
smsg_c2 db ':' ;74
smsg_sec dw '00' ;75-76
db ' '
smsg_ampm dw ' ' ;78-79
; String constants for status line
dynstr db 'Dynamic ' ;these 4
bufstr db 'Buffered' ;messages must
purstr db 'Purging ' ;be the
noswstr db 'NoSwitch' ;same length
; Test masks and drive names for get_openvec
sl_drive_list db 01,00,'A',02,00,'B'
db 04,00,'C',08,00,'D'
db 00,10h,'M',0F0h,0EFh,'*'
; window, capslock, and numlock indicators
winstr db 'Win'
capstr db 'Caps'
numstr db 'Num'
status_copy rw 80 ; keep a copy of status line
sl_error_save rw 80 ; back up for error messages
reorg_sl2 equ offset $
cseg
org reorg_sl2
eject
;************************************************
;* *
;* LIST DEVICES *
;* *
;************************************************
; Character to list out device
; Entry: CL = character
; DL = device
; Exit: character sent
io_list:
mov bl,dl ; get device number
mov bh,0
add bx,bx ; bx = word pointer
jmp ds:list_out[bx] ; branch out
; This table is set up in Init depending on available equipment
list_out dw null_out ; printer 0
dw null_out ; printer 1
dw null_out ; printer 2
dw null_out ; printer 3
dw null_out ; printer 4
; Character to parallel printer
parallel_out:
push cx ! push dx ; save the character and device
call poll ; wait for device to be ready
pop dx ! pop cx ; device and character
mov ax,par_stat_word[bx] ; what was the status?
cmp al,98h ; ready/select
jz par_out_yes ; skip if it's a go
xor ah,al ; if status = ignore code
and ah,7Fh ; except for busy bit
jnz par_out_fault ; then just quit
ret
; printer fault requires a status line error message
par_out_fault:
push bx ! push cx ! push dx
mov si,offset par_no_paper ; out of paper message
cmp al,20h ; -ready/paper/error
jz par_out_error
mov si,offset par_off_line ; not on-line message
par_out_error:
mov di,offset par_sub_msg
mov cx,par_sub_len ; length of sub message
push es
push ds ! pop es
rep movsb ; save the sub message
pop es
mov si,offset par_error_msg
mov al,dl ; get printer number
or al,'0' ; convert to ascii
mov .8[si],al ; set printer number
mov di,offset par_error_resp
call sl_error_out ; get response
pop dx ! pop cx ! pop bx
cmp al,'R' ; if retry
jz parallel_out ; then go again
mov al,par_stat_code[bx] ; if ignore, then
mov par_ignore_code[bx],al ; save for future ignores
ret ; and just return
par_out_yes:
mov par_ignore_code[bx],1 ; reset the ignore status
mov al,cl ; AL = character
mov dx,ds:list_data[bx] ; get the port for this device
out dx,al ; send character
inc dx ! inc dx ; reset it
mov al,0dh ; printer strobe on
out dx,al
mov al,0ch ; printer strobe off
out dx,al
ret
; Parallel printer status line error data
par_error_msg db 'Printer n '
par_sub_msg db 'Out of Paper ' ; for instance
db 'Retry, Ignore? '
db ' '
db ' '
par_no_paper db 'Out of Paper'
par_off_line db 'Not On-Line '
par_sub_len equ offset $ - offset par_off_line
par_error_resp db 2,'RI'
; Serial printer init routine
; This is called the first time
; that a port is to print a character
; entry: bx = device# * 2
; cl = char
serial_init:
push bx ! push cx ; save the data
mov dx,ds:list_data[bx] ; get our qpb
mov cl,q_open
call supif ; open the output queue
pop cx ! pop bx
test ax,ax ; see if open succeeded
jz serial_init_good ; skip if it worked
mov ds:list_out[bx],offset null_out
ret ; wipe us out
serial_init_good:
mov ds:list_out[bx],offset serial_out
; jmps serial_out ; now the queue is open
; Serial printer output routine
; This is called forever after the first time
; that a port is to print a character.
; entry: bx = device# * 2
; cl = char
serial_out:
mov dx,ds:list_data[bx] ; get qpb offset
mov si,dx
dec si ; point to character
mov [si],cl ; store the character
mov cl,q_write
call supif ; write char to queue
ret
; This is for nonexistent printer numbers
null_out:
ret
; List data table This is the port number for parallel ports
; and the offset of the qpb for serial ports
list_data dw 03BCh ; BW card parallel port
dw 0378H ; 0378h parallel port card as shipped
dw 0278h ; 0278h parallel port card option
dw qpb0 ; SerOut0 queue paramater block
dw qpb1 ; SerOut1 queue parameter block
; Parallel port status code and status to ignore for 3 printers
par_stat_code db 0
par_ignore_code db 1
db 0,1,0,1
par_stat_word equ word ptr par_stat_code
; Queue parameter blocks for serial printers
q_msg0 db 1,0 ; count, char
qpb0 dw 0,0,0,q_msg0
db 'SerOut0 '
q_msg1 db 1,0 ; count, char
qpb1 dw 0,0,0,q_msg1
db 'SerOut1 '
; List status entry point
; entry: DL = device
; exit: AX = 0 if not ready
; 0FFFFh if ready
; BX = device# * 2
io_listst:
mov bl,dl ; get device number
mov bh,0
add bx,bx ; bx = word pointer
jmp ds:list_stat[bx] ; branch out
; This table is set up in Init depending on available equipment
list_stat dw null_stat ; printer 0
dw null_stat ; printer 1
dw null_stat ; printer 2
dw serial_stat ; printer 3
dw serial_stat ; printer 4
; Get status from parallel printer
; Called from io_listst and from io_poll
; Entry: BX = device# * 2
; DL = device#
; Exit: AX = 0 if not ready
; 0ffffh if ready
; BX = device# * 2
parallel_stat:
push dx ; save device #
mov dx,ds:list_data[bx] ; port for parallel printer
inc dx
in al,dx ; DX=status register, get status
pop dx ; restore device number
and al,0B8h ; mask ready/paper/select/error
mov ds:par_stat_code[bx],al ; save the status port value
cmp al,18h ; if -ready/select
mov ax,0 ; then set ax to zero and
jz par_stat_done ; continue with polling
dec ax ; else ready => ax=ffff
par_stat_done:
ret
; Status for serial device always indicates ready
; because dispatch is handled by the queue mechanism
; Also used by non-existent printers
; exit: ax = 0FFFFh => ready
serial_stat:
null_stat:
mov ax,0FFFFh ; ready
ret
;************************************************
;* *
;* POLL ROUTINES *
;* *
;************************************************
; Check device for ready status, call dev_poll if not ready
poll: ;poll device
;----
; Entry: DL = device number
; Exit: device ready
; BX = device# * 2
call io_poll ;check hardware first
test ax,ax ;AX=0 if not ready
jnz poll_done ;BX=device# * 2 set by io_poll
push bx ;save device# * 2
mov cl,dev_poll ;give up the CPU resource
call supif
pop bx ;device# * 2
poll_done:
ret
; io_poll is called from the dispatcher after a process makes
; a dev_poll call to the O.S. During system dispatches, a
; a call to io_poll is made for each polling process.
; Entry: DL = device #
; Exit: AX = 0 if not ready, 0FFFFH if ready
; BX = device# * 2
io_poll:
xor bx,bx
mov bl,dl
shl bx,1
jmp poll_table[bx]
poll_table dw parallel_stat ;each of these must
dw parallel_stat ;preserve BX and DX
dw parallel_stat
; auxiliary input/output routines are just no-ops
io_auxin:
ret
io_auxout:
ret
; a general xios information pointer return function
; entry: cx = which pointer
; 0 => equipment data
; 1 => setup data
io_pointer:
mov bx,cx
add bx,bx ; word index
mov ax,ptr_list[bx] ; here's the return value
ret
reorg11 equ (offset $ + 1) and -2
dseg
org reorg11
;************************************************
;* *
;* PUBLIC DATA BLOCKS *
;* *
;************************************************
ptr_list dw equip_data
dw setup_data
; Equipment configuration data block
equip_data rb 0
num_flop dw 0 ; number of floppy disks 1-4
num_hard dw 0 ; number of hard disks 0-2
num_print dw 0 ; number of parallel printers 0-3
num_port dw 0 ; number of serial ports 0-2
num_mono dw 0 ; number of monochrome crts 0-1
num_color dw 0 ; number of color crts 0-1
num_ndp dw 0 ; number of 8087's 0-1
num_mmkb dw 0 ; main memory in Kilobytes 256-640
num_mdkb dw 0 ; memory disk in Kilobytes 0-384
; Setup data block
setup_data rb 0
disk_int_off rw 1 ; disk interrupt offset
disk_int_seg rw 1 ; disk interrupt segment
dw pfk_tbl0
dw pfk_tbl1
dw pfk_tbl2
dw pfk_tbl3
lo_mem_top dw 0 ; main mem seg ceiling 4000-A000
hi_mem_start dw 0 ; high mem seg beginning C000-E000
hi_mem_top dw 0 ; high mem seg ceiling D000-F000
boot_disk rb 1 ; from whence we came
rb 0 ; pad
;********************************************************
;* *
;* CONSOLE CONTROL BLOCKS *
;* *
;********************************************************
; ccb_list used by io_statline routine
ccb_list dw ccb0,ccb1,ccb2,ccb3
ccb_tab rb 0
CCB0 DW 0 ;OWNER
dw 0,0,0
db 0ffh, 0ffh ;mimic, msource
db 0
db 0 ;virtual console number
dw 0
dw 0 ;foreground and dynamic
;be the foreground console
dw 10h ;max buffer file size
dw 0,0,0,0,0,0
dw 0,0,0,0,0
dw ccb1,0 ;first link
ccb1 dw 0 ;owner
dw 0,0,0
db 0ffh, 0ffh ;mimic, msource
db 0
db 1 ;virtual console number
dw 0
dw csm_background ;background and dynamic
dw 10h ;max buffer file size
dw 0,0,0,0,0,0
dw 0,0,0,0,0
dw ccb2,0 ;link to next
ccb2 dw 0 ;owner
dw 0,0,0
db 0ffh, 0ffh ;mimic, msource
db 0
db 2 ;virtual console number
dw 0
dw csm_background ;background and dynamic
dw 10h ;max buffer file size
dw 0,0,0,0,0,0
dw 0,0,0,0,0
dw ccb3,0 ;link to next
ccb3 dw 0 ;owner
dw 0,0,0
db 0ffh, 0ffh ;mimic, msource
db 0
db 3 ;virtual console number
dw 0
dw csm_background ;background and dynamic
dw 10h ;max buffer file size
dw 0,0,0,0,0,0
dw 0,0,0,0,0
dw 0,0 ;end of link list
;********************************************************
;* *
;* LIST CONTROL BLOCK TABLE *
;* *
;********************************************************
lcb_tab rb 0
lcb0 dw 0,0,0,0
db 0ffh, 0ffh ;mimic, msource
lcb1 dw 0,0,0,0
db 0ffh
db 0ffh
lcb2 dw 0,0,0,0
db 0ffh
db 0ffh
lcb3 dw 0,0,0,0
db 0ffh
db 0ffh
lcb4 dw 0,0,0,0
db 0ffh
db 0ffh
; This little garbage patch is to protect io_conout from a system bug
; which happens when a list device detaches. If you can detach printer
; number 4 without affecting this table, then it may be safely removed.
dw 0FFFFh,0FFFFh,0FFFFh
dw 0FFFFh,0FFFFh,0FFFFh
dw 0FFFFh,0FFFFh,0FFFFh
dw 0FFFFh,0FFFFh,0FFFFh