Category : Assembly Language Source Code
Archive   : USRSPOOL.ZIP
Filename : USRSPOOL.ASM
Output of file : USRSPOOL.ASM contained in archive : USRSPOOL.ZIP
title spool - printer buffer for ibm-pc
;14may85 lmp minor changes, release for production
;xxmay85 jdn added rate command, fixed xon/xoff, upgraded parser
exit macro
int 20h
endm
EOL equ '$'
TRUE equ 0ffh
FALSE equ 000h
CR equ 00dh
LF equ 00ah
COM1 equ 0
COM2 equ 1
LPT1 equ 2
LPT2 equ 3
LPT3 equ 4
NONE equ 0
D_PORT equ LPT1 ;default port
D_PROTOCOL equ NONE ;default protocol
D_BUFFSIZE equ 20 ;K bytes
CTS equ 010h ;mask for 8250
DSR equ 020h ;mask for 8250
ITxRdy equ 002h ;TxRdy int id from PIC
IRxRdy equ 004h
EOI equ 020h ;EOI cmd for PIC
_MSTATUS equ 006h ;offset to modem status register
XON equ 011h
XOFF equ 013h
SPECIAL equ 0fh
STATUS_OK equ 90h ;selected, not busy
subttl segment 0 defined
page
abs0 segment at 0
org 17h * 4
int_17 dd ? ;bios print_char interrupt
org 408h
printer_base dw ? ;bios printer base addresses (3)
org 478h
print_tim_out db ? ;bios printer time out values (4?)
abs0 ends
subttl Main program begins here
page
code segment byte public
org 100h
assume cs:code
start:
jmp init
subttl srv17 - Int 17 (bios print-char) handler
page
;Resident Data Area
;These areas are initialized by the loader portion of this program.
data_start equ $ ;start of global data storage
buff_head dw offset buffer
buff_tail dw offset buffer
buff_start dw buffer
buff_end dw ?
buff_size dw D_BUFFSIZE*1024 ;parm set by parse - default = 4k
stopped db TRUE ;true if buffer empty and last char done
prot_ready db TRUE ;true if protocol says go.
port db D_PORT ;port code - 0=COM1, 1=COM2, 2=LPT1
; 3=LPT2, 4=LPT3
protocol db D_PROTOCOL ;protocol code - see init routines
noparms db TRUE ;used by parse
status db STATUS_OK
data_len equ $-data_start ;length of global data
es_save dw 0 ;es save area
;This is the Signature. Do NOT move or change it.
Signature dw 'SP'
srv17 proc near
assume cs:code,ds:nothing,es:nothing
;on entry:
; ah = opcode
; 0 - print
; 1 - init
; 2 - status
; al = char (if opcode = print)
;on exit:
; ah = status
;
push dx
push si
push cx
push bx
lea bx, srv17exit ;no conditional calls, so
push bx ;fake return address & jump
cmp dx,3
jnz skip_mess
jmp message_int
skip_mess:
or ah, ah ;print char?
jz put_buff
dec ah
jz init_port
;if we get here, it was status, or error, so fall thru to status
pop bx ;clear faked return address
srv17exit:
call return_status ;everybody must do this
pop bx
pop cx
pop si
pop dx
iret
srv17 endp
;
; ==========================
;
message_int proc near
cmp ah,0
jnz mess1
;
push cs
pop es
pop bx ;return address
pop bx ;b register
;
cmp bx,signature
jnz not_me
;
mov bx,0
not_me:
push bx ;put it back on the stack
jmp srv17exit ;return
mess1:
ret
;
message_int endp
subttl put_buff - put a char in our buffer
page
put_buff proc near
assume cs:code, ds:nothing, es:nothing
;put the char (al) into the printer buffer
cmp stopped, FALSE ;stopped?
jz pb_not_stopped
mov stopped, FALSE
call out_char ;send char manually
ret
pb_not_stopped:
put_buff_wait:
mov bx, buff_tail
mov si, bx
call inc_ptr
cmp bx, buff_head ;buffer full?
je put_buff_full ;yes - wait...
mov cs:[si], al ;buffer character
mov buff_tail, bx ;upd tail ptr
ret
put_buff_full:
sti ;enable interrupts
nop ;allow an interrupt
nop
cli
jmp put_buff_wait
put_buff endp
subttl return_status - return the printer status in ah
page
return_status proc near
assume cs:code, ds:nothing, es:nothing
; return code bits (ah)
; 0 timeout
; 1 0
; 2 0
; 3 i/o error
; 4 selected
; 5 out of paper
; 6 acknowledge
; 7 not busy
mov ah, status ;return code
mov status, STATUS_OK ;set up for next time
ret ;for now
return_status endp
subttl init_port - init the selected printer port
page
init_port proc near
assume cs:code, ds:nothing, es:nothing
;uses:
; port
; protocol
;
;enable int on PIC
mov bl, port
xor bh, bh
lea si, init_PIC_table[bx]
mov dl, cs:[si]
in al, 21h
and al, dl ;enable (clear) int bit
out 21h, al
mov al, protocol
mov ah, port
or ah, ah ;just COM1 for now
jz COM1_init
dec ah
jz COM2_init
jmp PAR_init
;-------------------------------------
;Hardware / Setup dependent routines go here
;-------------------------------------
;
init_PIC_table:
; these bytes enable (clear bit) the appropriate bit on the PIC.
db 0efh ;COM1 (IRQ 4)
db 0f7h ;COM2 (IRQ 3)
db 07fh ;PAR (IRQ 7)
db 07fh ;all par ports share this int
db 07fh
;-------------------------------------
;
;Init Routines. Protocol type is passed in al.
; 0 None
; 1 XON/XOFF
; 2 CTS
; 3 ETX/ACK
; 4 DSR
;-------------------------------------
COM1_init: ;initialize com1 port
;-------------------------------------
mov bx, 3f8h ;base for COM1
jmp COMx_init
;--------------------------------------
COM2_init: ;initialize com2 port
;--------------------------------------
mov bx, 2f8h ;base for COM2
;fall through to COMx_init
;--------------------------------------
COMx_init: ;common routine to init an 8250
;---------------------------------------
mov dx, bx
inc dx ;int enable reg
xor ah, ah
mov bx, ax
lea si, COMx_int_table[bx]
mov al, cs:[si]
out dx, al ;set it
add dx, 3 ;CR reg
mov al, 0bh
out dx, al ;DTR + Int Enable (user 1 pin)
ret
;-------------------------------------
COMx_int_table:
db 02h ;no protocol txrdy only
db 03h ;xon/xoff txrdy, rxrdy
db 0ah ;cts txrdy, delta modstat
db 03h ;etx/ack txrdy, rxrdy
db 0ah ;dsr txrdy, delta modstat
;
PAR_init:
ret ;for now
;
init_port endp
subttl srvUART - handle the printer (hardware) interrupts
page
srvUART proc near
; Entry via hardware interrupt
; Exit -none-
;this routine handles the printer interrupt
assume cs:code, ds:nothing, es:nothing
push ax
push bx
push cx
push dx
push si
call protocol_check
jz notus
cmp prot_ready, FALSE
je notus
mov bx, buff_head ;buffer check
cmp bx, buff_tail ;empty?
jz su_empty ;-yep..
mov al, cs:[bx] ;get char to print
call inc_ptr
mov buff_head, bx ;store updated pointer
call out_char
jmp notus
su_empty:
mov stopped, TRUE ;set stopped flag
notus:
pop si
pop dx
pop cx
pop bx
mov al, EOI
out 20h, al ;send eoi to PIC
pop ax
iret
srvUART endp
subttl protocol_check - see if protocol is ready or blocked
page
protocol_check proc near
; Entry -none-
; Exit ZR if not TxRdy int.
; Protocol flag set/reset by protocol routines if COMx port.
assume cs:code, ds:nothing, es:nothing
;uses:
; protocol
;
; Protocol routines set 'stopped' when protocol is disabled.
; Reset 'stopped' when protocol is enabled.
; Return Zero flag set if no character should be printed on
; this interrupt. (ie. this was not a txrdy)
;
push ax
push dx
cmp port, 02h ;LPT# port?
jae pc_ret2 ;yes - no protocol, always ready
mov bl, port ;set up int id byte for prot routines
and bl, 1
mov bh, 0
add bl, bl
lea si, port_base[bx]
mov dx, cs:[si]
inc dx
inc dx
in al, dx ;grab int id register
dec dx
dec dx ;leave base port in dx for protocol routines
lea bx, pc_return ;ON protocol GOSUB ....
push bx
mov bl, protocol
add bl, bl
mov bh, 0
lea si, pc_offset[bx]
jmp word ptr cs:[si]
pc_return:
and al, ITxRdy ;set zr flag if not TxRdy
;prot routines will force TxRdy if restarting...
pop dx
pop ax
ret
pc_ret2:
mov al, ITxRdy ;force TxRdy for parallel port
jmp pc_return
pc_offset:
dw offset p_None
dw offset p_XON
dw offset p_CTS
dw offset p_ETX
dw offset p_DSR
protocol_check endp
subttl p_None - handle no-protocol option
page
p_None proc near
assume cs:code, ds:nothing, es:nothing
; Entry al = int id byte
; Exit -same-
;supports printers with no protocol.
;assumes they can handle full UART speed.
ret ;Nothing needed here...
p_None endp
subttl p_XON - XON/XOFF protocol
page
p_XON proc near
; Entry al = int id byte
; dx = base port address
; Exit -all regs intact-
assume cs:code, ds:nothing, es:nothing
push bx
mov bl, al
and al, IRxRdy ;was it RxRdy?
jz pxreturn
in al, dx ;read the character
and al, 07fh ;strip hi bit if present
mov bh, FALSE ;flag for 'prot_ready' if XOFF
cmp al,SPECIAL ;a cntr p
jnz try_xon_off
mov bh,prot_ready
xor bh,0ffh
jmp pxset
try_xon_off:
cmp al, XOFF
je pxset
mov bh, TRUE ;flag if XON
cmp al, XON
jne pxreturn ;char not valid in protocol, ignore
or bl, ITxRdy ;we have to print a char to get started again.
pxset:
mov prot_ready, bh
pxreturn:
mov al, bl ;restore int id byte
pop bx
ret
p_XON endp
subttl p_CTS - handle CTS protocol
page
p_CTS proc near
; Entry al = int id byte
; dx = base port address
; Exit -intact-
assume cs:code, ds:nothing, es:nothing
push bx
mov bl, al
or al, al ;al = 0?
jnz pcreturn
add dx, 6
in al, dx ;modem status register
sub dx, 6 ;put it back
and al, CTS ;cts bit
mov bh, FALSE
jz pcset
mov bh, TRUE
or bl, ITxRdy
pcset:
mov prot_ready, bh
pcreturn:
mov al, bl
pop bx
ret
p_CTS endp
subttl p_ETX - handle ETX/ACK protocol
page
p_ETX proc near
assume cs:code, ds:nothing, es:nothing
xor ah, ah
ret
p_ETX endp
subttl p_DSR - handle DSR protocol
page
p_DSR proc near
; Entry
;
; Exit
assume cs:code, ds:nothing, es:nothing
push bx
mov bl, al
or al, al
jnz pdreturn
add dx, 6
in al, dx ;modem status register
sub dx, 6
and al, DSR ;dsr
mov bh, FALSE
jz pdset
mov bh, TRUE
or bl, ITxRdy
pdset:
mov prot_ready, bh
pdreturn:
mov al, bl
pop bx
ret
p_DSR endp
subttl out_char - send char in al to appropriate port
page
out_char proc near
; Entry al = char to print
; Exit -none-
assume cs:code, ds:nothing, es:nothing
;uses:
; port
push bx
push dx
push si
cmp port, 02h ;LPT#?
jae oc_par ;yes - special handling
mov bl, port
add bl, bl
mov bh, 0
lea si, port_base[bx]
mov dx, cs:[si]
oc_cont1:
out dx, al
oc_ret:
pop si
pop dx
pop bx
ret
oc_par:
push es
mov cl, port
mov ch, 0
mov si, cx ;printer number
dec si ;-2 to index par printer table
dec si
shl si, 1
mov bx, 0
mov es, bx
assume es:abs0
mov dx, es:printer_base[si]
pop es
or dx, dx ;is it there?
jz oc_ret ;nope - bit bucket
out dx, al ;send char
inc dx ;status port
in al, dx ;get status for later use
mov ah, al
mov al, 1dh ;strobe + int enable
inc dx
out dx, al
mov al, 1ch ;strobe off + int enable
out dx, al
jmp oc_ret
port_base label word
dw 3f8h ;COM1
dw 2f8h ;COM2
out_char endp
;
; =================================================================
;
subttl inc_ptr - increment a buffer pointer
page
inc_ptr proc near
; Entry bx = buffer pointer
; Exit bx = (bx + 1) mod buffer size
assume cs:code, ds:nothing, es:nothing
inc bx
cmp bx, buff_end
jne inc_ptr_ret
mov bx, buff_start
inc_ptr_ret:
ret
inc_ptr endp
;
; ================================================================
;
subttl buffer area - init routines are placed here
page
buffer label byte
; These routines are overlayed by the data buffer
init proc near
; Entry From command.com - ds = c
; Exit Spooler installed or status returned.
assume cs:code, ds:code, es:nothing
lea dx, signon
mov ah, 09h ;print sign-on msg (w/ cpyrght)
int 021h
call parse ;parse the command line
cli
call set_uart_int
call init_port ;enable interrupts on port, PIC
call init_protocol ;do any first time stuff
xor ax, ax
mov es, ax
assume es:abs0
mov word ptr int_17, offset srv17
mov word ptr int_17+2, cs
lea dx, buffer ;set up buffer ptrs
mov buff_start, dx
add dx, buff_size ;make pointer to end of buffer
mov buff_end, dx
push cs
pop ds
call show_status ;say whats going on
sti ;re-enable interrupts
int 27h ;term_resident
signon db CR,LF,'SPOOL - (C) Copyright 1985 USRobotics',CR,LF,'$'
init endp
subttl parse - parse the command line options
page
parse proc near
; Entry ds = cs
; Exit Returns if spool needs to be installed.
; Else displays proper msgs and prog term
assume cs:code, ds:code, es:nothing
;this routine sets the following parms:
; port
; protocol
; buff_size
push ds
pop es
call chkinst ;set up es_save
cld
mov noparms, byte ptr 0ffh ;none found yet
mov cl, byte ptr ds:[80h] ;parm string length
cmp cl,0
jnz parm_there
jmp parse_no_more
parm_there:
xor ch, ch
mov di, 81h ;ds:di = parm string addr
parse1:
cmp byte ptr ds:[di],'/'
jz found_switch
cmp byte ptr ds:[di],'-'
jz found_switch
cmp byte ptr ds:[di],'?'
jnz not_usage
call usage
mov noparms,0 ;we got a switch
not_usage:
inc di
loop parse1
jmp parse_no_more
found_switch:
inc di
dec cx
or cx, cx ;hit end of string?
jz parse_no_more
mov bl, ds:[di] ;grab the parm
and bl, 0dfh ;force upper case
lea dx, parse_cont ;fake on_gosub
push dx
cmp bl, 'C' ;clear buff cmd
jnz not_clear ;** fake conditional long jump **
jmp clearbuff
not_clear:
mov noparms, byte ptr 000h
cmp bl, 'P' ;port
jnz not_port
jmp setport
not_port:
cmp bl, 'H' ;handshaking (protocol)
jnz not_prot
jmp setprotocol
not_prot:
cmp bl, 'B' ;buffer size
jnz not_buff
jmp setbuffsize
not_buff:
cmp bl, 'R' ;Rate =
jnz not_rate
jmp set_rate
not_rate:
pop dx ;trash faked return address
call usage ;give help message and quit
exit
parse_cont:
jmp parse1 ;parse the next command
parse_no_more:
cmp noparms, byte ptr 00h ;any parms?
jz pnm2 ; -we got parms, go install
call chkinst ;are we installed?
jnz pnm3 ;nope - give usage msg
call show_status
exit
pnm3:
call usage
exit
pnm2:
call chkinst ;are we already installed?
jnz pnm4
lea dx, msgalrdyin
mov ah, 09h
int 021h
exit
pnm4:
cmp port, 2
jl pnm5
mov protocol, 0 ;force no protocol for parallel ports
pnm5:
;everythings ok - return and install.
ret
msgalrdyin db '** Already Installed **',CR,LF,'$'
parse endp
subttl usage - print usage message
page
usage proc near
; Entry ds = cs
; Exit -none-
assume cs:code, ds:code
lea dx, msguse
mov ah, 09h ;print string
int 021h ;do it
ret
msguse:
db 'Usage:',CR,LF,LF
db ' spool
db LF
db ' spool /P /H /B /R Install Spool With Options',CR,LF
db ' /P L=LPT [1,2,3] Port',CR,LF
db ' C=COM [1,2]',CR,LF
db ' /H X=Xon/Xoff Protocol',CR,LF
db ' C=CTS',CR,LF
db ' D=DSR',CR,LF
db ' N=NONE',CR,LF
db ' /B #=SIZE Buffer Size',CR,LF
db ' /R=baud,parity,wordlen,stopbits',CR,LF
db LF
db ' spool /C Clear current spool buffer',CR,LF
db eol
;; db '
;; db ' ? HELP SCREEN',CR,LF,LF,LF,eol
;; db ' /C Clear Current Print Buffer',CR,LF
;; db ' E=ETX/ACK',CR,LF
usage endp
subttl show_status - display current spooler status
page
show_status proc near
; Entry -none-
; Exit Status displayed on stdout
assume cs:code, ds:code, es:code
push ax
push cx
push dx
push si
push di
push ds
push es
push cs
pop es
mov ds,es_save
mov cx,data_len
mov si,offset data_start
mov di,si
rep movsb
push cs
pop ds
mov cx, buff_size
lea si, msgstatusbs
call itoa
mov cx, buff_tail
cmp cx, buff_head
jae st2
add cx, buff_size
st2:
sub cx, buff_head
lea si, msgstatusused
call itoa
mov ax, cx
mov cx, buff_size
sub cx, ax
lea si, msgstatusleft
call itoa
mov al, port
cbw
mov si, ax
shl si, 1
shl si, 1
add si, offset s_ptab
lea di, msgstatusp
mov cx, 4
repz movsb
mov al, protocol
cbw
mov si, ax
mov cl, 3
shl si, cl ;* 8 for table index
add si, offset s_htab
lea di, msgstatush
mov cx, 8
repz movsb
lea dx, msgstatus
mov ah, 09h
int 21h
pop es
pop ds
pop di
pop si
pop dx
pop cx
pop ax
ret
msgstatus db 'Buffer size: '
msgstatusbs db '00000 bytes', CR, LF
db 'Used: '
msgstatusused db '00000 bytes', CR, LF
db 'Left: '
msgstatusleft db '00000 bytes', CR, LF
db CR, LF
db 'Output Port: '
msgstatusp db 'pppp', CR, LF
db 'Protocol: '
msgstatush db 'hhhhhhhh', CR, LF
db '$'
s_ptab db 'COM1','COM2','LPT1','LPT2','LPT3'
s_htab db 'None ','XON/XOFF','CTS ','ETX/ACK ','DSR '
show_status endp
subttl chkinst - return z if already installed
page
chkinst proc near
; Entry ds = cs
; Exit ZR set if already installed, else NZ.
assume cs:code, ds:code
push es
push ds
mov ah,0
mov dx,3 ;printer # 3
mov bx,'S'*256+'P'
int 17h
mov es_save,es ;save this segment
cmp bx,0 ;is it there?
jz installed ;already installed
mov es_save,ds ;here we are now
installed:
pop ds
pop es
ret
chkinst endp
subttl clearbuff - clear spool buffer
page
clearbuff proc near
; Entry Spool must be loaded.
; Exit Buffer ptrs set back to buffer start
push ds
mov ds,es_save
assume ds:code
mov ax, word ptr buff_start ;ptr to beginning of buffer
mov word ptr buff_head, ax ;stuff into head and tail ptrs
mov word ptr buff_tail, ax
pop ds
ret
clearbuff endp
subttl setprotocol - set the protocol for the command line
page
setprotocol proc near
; Entry ds:di = ptr to 'h' on command line
; Exit 'protocol' set if valid, else prog term
assume cs:code, ds:code
push ax
push di
push cx
inc di
mov al, ds:[di] ;grab protocol parm (char)
cmp al, CR ;look for premature EOL
je sp_bad2
mov msgbadhc, al ;put in err msg just in case
and al, 0dfh ;force upper case
lea di, sp_tab1
mov cx, sp_tab1len
repnz scasb ;find table entry
jnz sp_bad ;not found - not valid
sub di, offset sp_tab1 ;get table position
dec di ;went 1 too far.
mov ax, di
mov protocol, al
pop cx
pop di
pop ax
ret
sp_bad:
lea dx, msgbadh
sp_msg:
mov ah, 09h
int 021h
exit
sp_bad2:
lea dx, msgnoh
jmp sp_msg
msgnoh db '** Missing protocol parm **',CR,LF,'$'
msgbadh db '** Bad protocol parm ('
msgbadhc db 20,') **',CR,LF,'$'
sp_tab1 db 'NXCND'
;Note: ^ this char should be 'e' when etx/ack is enabled.
;sp_tab1 db 'NXCED'
sp_tab1len equ $-sp_tab1
setprotocol endp
subttl setport - set 'port' from command line
page
setport proc near
; Entry ds:[di] = ptr to 'p' on cmd line
; Exit 'port' set if valid, else prog term
push ax
push bx
push cx
push dx
push si
push di
mov si, di
inc si
lodsb ;get port type (lpt, com)
cmp al, CR ;look for early EOL
je spnoparm
mov msgbadportc, al ;put char in error msg, just in case
and al, 0dfh ;make upper case
mov bl, 0 ;base code for com ports
cmp al, 'C'
je spok
mov bl, 2 ;base code for par ports
cmp al, 'L' ;was it lpt?
jne spexit ;nope - print error msg
spok:
lodsb ;grab port number 1,2,3
cmp al, CR ;check for early EOL
je spnoparm
mov msgbadportc+1, al ;just in case
sub al, '1' ;make it binary, zero based
mov bh, 2 ;max for lpt ports
cmp bl, 2 ;lpt port specified?
je spok2
dec bh ;max for com ports = 1
spok2:
cmp al, bh ;valid port number?
ja spexit ;with error msg
add al, bl ;final port code
mov port, al ;store port code for int routines
pop di
pop si
pop dx
pop cx
pop bx
pop ax
ret
spexit:
lea dx, msgbadport
spexit2:
mov ah, 09h
int 021h
exit
spnoparm:
lea dx, msgnoparm
jmp spexit2
msgnoparm db '** Missing port parm **',CR,LF,'$'
msgbadport db '** Bad port parm ('
msgbadportc db ' ) **',CR,LF,'$'
setport endp
subttl setbuffsize - set buffer size from command line
page
setbuffsize proc near
; Entry ds:[si] = ptr to 'b'
; Exit 'buff_size' set if valid, else prog term
push ax
push cx
push dx
push si
push di
mov si, di
inc si
call atoi
cmp cx, 64 ;max 64k buffer
ja sbexit ;req'ed too much
cmp cx, 0 ;zero not valid either
je sbexit
mov ax, cx ;make it Kbytes
mov cl, 10 ;log 10 1024
shl ax, cl
mov cx,0fff0h
sub cx,offset buffer
cmp ax, 0 ;see if they wanted 64k
je sbs3 ;yes - set max buffer size
cmp ax,cx
jb sbs2
sbs3:
mov ax,cx
sbs2:
mov buff_size, ax ;set buff size for int routines
pop di
pop si
pop dx
pop cx
pop ax
ret
sbexit:
lea si, msgsbc
call itoa ;insert number into msg
lea dx, msgsb
mov ah, 09h
int 021h
exit
msgsb db '** Bad buffer size ('
msgsbc db ' ) **',CR,LF,'$'
setbuffsize endp
subttl itoa - convert an unsigned integer to its ASCII representation
page
itoa proc near
; Entry cx = unsigned integer to be converted
; ds:[si] = destination of ASCII string
; Exit ds:[si] = end of string +1
; Trashes -none-
push ax
push bx
push cx
push dx
push di
mov di, si ;need to use di for string ops
mov ax, cx
mov cx, 10000 ;max int = 64k
mov bx, 10 ;constant for finding new power of ten
itoa1:
mov dx, 0 ;zap hi byte for 32-bit divide
div cx ;calc next digit
add al, '0' ;make ASCII
stosb ;out to buffer, auto inc
push dx ;dx = ax mod cx
mov dx, 0
mov ax, cx ;calc new power of 10
div bx
or ax, ax ;done yet?
jz itoadone
mov cx, ax ;load new power of ten
pop ax ;remainder from previous calc for new calc
jmp itoa1 ;do next digit
itoadone:
pop ax ;trash final remainder of zero
mov si, di
pop di
pop dx
pop cx
pop bx
pop ax
ret
itoa endp
subttl atoi - convert ASCII char string to unsigned int
page
atoi proc near
; Entry ds:[si] = ptr to ASCII string
; Exit cx = integer representation of string
; ds:[si] = end of string +1
; Trashed -none-
push ax
push bx
push dx
mov bx, 10 ;constant
mov ax, 0 ;init sum
atoiagain:
push ax ;hold intermediate result
lodsb ;grab nexr char
cmp al, '0' ;range check
jb atoidone
cmp al, '9'
ja atoidone
sub al, '0' ;make binary
cbw ;make it a full word
mov dx, ax ;hold it...
pop ax
push dx ;current digit onto stack
mul bx ;intermediate result * 10
pop dx ;ignore anything above 16 bits
add ax, dx ;add in current digit
jmp atoiagain ;do next character
atoidone:
dec si ;bring bad char back into si range
pop cx ;put result into return register
pop dx
pop bx
pop ax
ret
atoi endp
subttl set_uart_int - stuff addr of srvUART in vector table
page
set_uart_int proc near
assume cs:code, ds:nothing, es:nothing
xor ax, ax
mov es, ax
mov bl, port
xor bh, bh
shl bx, 1 ;*2 for word indexing
mov bx, cs:word ptr comint_table[bx]
mov ax,offset srvUART
mov es:[bx], ax
mov es:[bx][2], cs
ret
comint_table:
dw 0ch * 4 ;com1 int
dw 0bh * 4 ;com2 int
dw 0fh * 4 ;par int
dw 0fh * 4 ;all par ports share this int
dw 0fh * 4
set_uart_int endp
;
; ================================================
;
subttl init_protocol - first time setup stuff for protocols
page
init_protocol proc near
assume cs:code, ds:code, es:nothing
; Entry -none-
; Uses protocol, port
; Exit -Protocol initialazation completed-
push ax
push bx
push dx
cmp port, LPT1
jae ip_exit ;no init for parallel ports
mov bl, protocol
mov bh, 0
shl bx, 1
call ip_tab[bx]
ip_exit:
pop dx
pop bx
pop ax
ret
ip_tab label word
dw offset ip_none ;no protocol
dw offset ip_none ;xon/xoff
dw offset ip_CTS ;cts
dw offset ip_none ;etx/ack
dw offset ip_DSR ;dsr
init_protocol endp
;
; ======================================
;
subttl ip_xxxx - protocol init routines
page
ip_none proc near
mov prot_ready, TRUE ;always ready
ret
ip_none endp
;
; ======================================
;
ip_CTS proc near
mov bl, port ;get printer base address
mov bh, 0
mov dx, port_base[bx]
mov al, 0 ;force int type 'mod status int'
call p_CTS ;do the real work
ret ;ignore return value
ip_CTS endp
;
; ======================================
;
ip_DSR proc near
mov bl, port
mov bh, 0
mov dx, port_base[bx]
mov al, 0
call p_DSR
ret
ip_DSR endp
;
; =====================================
; SET_RATE - set baud rate etc.
; =====================================
;
baud_rate dw 0
bauds dw 110,150,300,600,1200,2400,4800,9600 ;,1200
bauds_b dw 0,1,2,3,4,5,6,7 ;,4
baud_rate_str dw rate1,rate2,rate3,rate4,rate5,rate6,rate7,rate8;,rate5
rate1 db '110,',eol
rate2 db '150,',eol
rate3 db '300,',eol
rate4 db '600,',eol
rate5 db '1200,',eol
rate6 db '2400,',eol
rate7 db '4800,',eol
rate8 db '9600,',eol
;
parity db 0
parity_str dw parity1,parity2,0,parity3 ;,parity1
parity1 db 'N,',eol
parity2 db 'O,',eol
parity3 db 'E,',eol
;
stop_bit dw 0
stop_bit_str dw stop1,stop2 ;,stop1
stop1 db '1',CR,LF,LF,eol
stop2 db '2',CR,LF,LF,eol
;
wordlen dw 0
wordlen_str dw word1,word2 ;,word1
word1 db '7,',eol
word2 db '8,',eol
;
baud_str db CR,LF,'Com'
com_num db '#: Set to ',eol
;
set_rate proc near
;
assume cs:code,ds:code,es:code
;
push cs
pop ds
;
push es
mov es,es_save
;
mov al,es:port
mov ds:port,al
;
cmp al,2
pop es
;
jb go_rate
ret
go_rate:
mov si,di
;
; Find the '=' sign
;
rate_loop:
cmp byte ptr ds:[si],'=' ;well?
jz rate_found
cmp byte ptr ds:[si],CR ;done?
jz rate_ret
inc si
jmp rate_loop
rate_found:
inc si
cmp byte ptr ds:[si],' ' ;any spaces?
jz rate_found
;
call atoi
mov baud_rate,cx ;save the baud rate
parity_find:
cmp byte ptr ds:[si],','
jz comma
cmp byte ptr ds:[si],CR
jz rate_ret
inc si
jmp parity_find
;
comma:
inc si
cmp byte ptr ds:[si],CR
jz rate_ret
cmp byte ptr ds:[si],' '
jz comma
;
mov al,byte ptr ds:[si]
and al,0dfh
;
xor ah,ah
cmp al,'N'
jz got_parity
;
inc ah
cmp al,'O'
jz got_parity
;
add ah,2
cmp al,'E'
jz got_parity
;
mov ah,0 ;default none
got_parity:
mov parity,ah
;
get_wordlen:
cmp byte ptr ds:[si],CR
jz rate_ret
cmp byte ptr ds:[si],','
jz comma2
inc si
jmp get_wordlen
comma2:
inc si
cmp byte ptr ds:[si],' '
jz comma2
;
call atoi
mov wordlen,cx
get_stop_bit:
cmp byte ptr ds:[si],CR
jz rate_ret
cmp byte ptr ds:[si],','
jz comma3
inc si
jmp get_stop_bit
comma3:
inc si
cmp byte ptr ds:[si],' '
jz comma3
call atoi
mov stop_bit,cx
rate_ret:
;
; If invalid, set to default
;
mov ax,baud_rate
mov bx,0 ;offset of bauds
b_rate_test:
cmp bauds[bx],ax
jz got_rate
add bx,2
cmp bx,16
jnz b_rate_test
mov bx,10
got_rate:
mov ax,bauds_b[bx] ;get what is there
mov baud_rate,ax ;set it
;
; ======
; skip do parity
; ======
;
mov ax,wordlen
cmp ax,8
jz ok_wl
cmp ax,7
jz ok_wl
mov ax,8
ok_wl:
sub ax,5 ;2 or 3 (7,8)
mov wordlen,ax
;
; ======
; do the stop bits
; ======
;
mov ax,stop_bit
cmp ax,1
jz ok_st
cmp ax,2
jz ok_st
mov ax,1
ok_st:
dec ax
mov stop_bit,ax
;
mov al,port
mov com_num,al
add com_num,'1'
;
lea dx,baud_str ;Comm Port Set to
mov ah,9
int 21h
;
mov bx,baud_rate
shl bx,1
mov dx,baud_rate_str[bx]
mov ah,9
int 21h
;
mov bl,parity
xor bh,bh
;
shl bx,1
mov dx,parity_str[bx]
mov ah,9
int 21h
;
mov bx,wordlen
sub bx,2
shl bx,1
mov dx,wordlen_str[bx]
mov ah,9
int 21h
;
mov bx,stop_bit
shl bx,1
mov dx,stop_bit_str[bx]
mov ah,9
int 21h
;
mov ax,baud_rate
mov cl,2
shl ax,cl
or al,parity
shl ax,1
or ax,stop_bit
mov cl,2
shl ax,cl
or ax,wordlen
;
mov dl,port
xor dh,dh
;
int 14h
;
ret
set_rate endp
code ends
end start
Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!
This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.
But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/