mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-25 09:24:19 +00:00
1212 lines
28 KiB
Plaintext
1212 lines
28 KiB
Plaintext
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
|
||
|