mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-25 09:24:19 +00:00
822 lines
19 KiB
Plaintext
822 lines
19 KiB
Plaintext
|
||
; *** SERIN.RSP ***
|
||
|
||
; A Concurrent CP/M-86
|
||
; Resident System Process for
|
||
; Queue Driven Serial Character Input
|
||
|
||
; Oct 19, 1983 Dean Ballard
|
||
|
||
|
||
; This program reads characters from a circular buffer and
|
||
; writes them to the serial input queue for consumption by
|
||
; an application program. The characters are put into the
|
||
; buffer by an interrupt routine which is contained within
|
||
; this module. The interrupt routine also serves to alert
|
||
; the serial output routine when it is waiting on transmit
|
||
; buffer empty.
|
||
|
||
|
||
; First the hardware independent equate values.
|
||
; These have to do with the queue management, and generally
|
||
; pertain to the application program side of things.
|
||
|
||
q_mes_size equ 17 ; byte count plus 16 characters
|
||
in_q_num equ 4 ; number of in queue messages
|
||
out_q_num equ 2 ; number of out queue messages
|
||
|
||
c_buf_size equ 300 ; receive int circular buffer
|
||
stack_size equ 64 ; for interrupt routine
|
||
|
||
bdos equ 0E0h ; bdos interrupt number
|
||
|
||
c_detach equ 93h ; detach console
|
||
dev_flag_wait equ 84h ; wait for a flag
|
||
dev_flag_set equ 85h ; release a flag
|
||
p_delay equ 8Dh ; delay dx ticks
|
||
p_priority equ 91h ; set process priority
|
||
p_term equ 8Fh ; terminate a process
|
||
q_make equ 86h ; create queue code
|
||
q_open equ 87h ; open queue code
|
||
q_read equ 89h ; read queue code
|
||
q_write equ 8Bh ; write queue code
|
||
s_sysdat equ 9Ah ; get system data seg
|
||
|
||
; RSP data origin addresses
|
||
|
||
rsp_header equ 00h ; start of data segment
|
||
rsp_pd equ 10h ; process descriptor offset
|
||
rsp_uda equ 40h ; user data area offset
|
||
rsp_stack_top equ 13Ah ; at the end of uda
|
||
rsp_data_end equ 140h ; end of rsp stuff
|
||
|
||
; protocol constants
|
||
|
||
dtr_dsr equ 01h ; bit for dsr/dtr protocol
|
||
rts_cts equ 02h ; bit for rts/cts protocol
|
||
xon_xoff equ 04h ; bit for xon/xoff protocol
|
||
|
||
xon equ 11h ; start transmission
|
||
xoff equ 13h ; stop transmission
|
||
|
||
; system data page address pointers
|
||
|
||
dseg
|
||
|
||
org 00h
|
||
sup_o rw 1 ; supervisor offset
|
||
sup_s rw 1 ; supervisor segment
|
||
|
||
org 38h
|
||
disp_o rw 1 ; dispatcher offset
|
||
disp_s rw 1 ; dispatcher segment
|
||
|
||
|
||
; Now the hardware specific equates
|
||
; These have to do with the I/O port and interrupt management,
|
||
; and are, for the most part, specific to the IBM PC
|
||
|
||
; async port bit patterns
|
||
|
||
dr equ 01h ; data ready
|
||
tbe equ 20h ; xmit buf empty
|
||
r_t_mask equ 03h ; rec/trans int en
|
||
rec_int equ 04h ; from int id reg
|
||
tran_int equ 02h ; from int id reg
|
||
no_int equ 01h ; no hardware interrupt
|
||
dsr_bit equ 20h ; from modem status
|
||
cts_bit equ 10h ; from modem status
|
||
rts_bit equ 02h ; also with int en
|
||
dtr_bit equ 01h ; to modem control
|
||
i_en equ 08h ; interrupt enable
|
||
|
||
; 8259 programmable interrupt ports and patterns
|
||
|
||
pic_ack equ 20h ; 8259 acknowledge address
|
||
pic_mask equ pic_ack + 1 ; 8259 int mask address
|
||
ns_eoi equ 20h ; non specific end of int
|
||
|
||
|
||
|
||
; **************************
|
||
; *** Code begins here ***
|
||
; **************************
|
||
|
||
cseg
|
||
|
||
org 00h ; small model
|
||
|
||
serial_in:
|
||
call which_port ; are we port 0 or port 1 ?
|
||
call is_it_there ; if the port is not present
|
||
jnz terminate_in ; then terminate the process
|
||
|
||
call get_sys_data ; read supervisor, dispatcher
|
||
call make_queues ; input, output, and mx queues
|
||
call open_queues ; open all queues
|
||
call write_mx_queue ; set up the mx queue
|
||
call write_t_block ; send address to serial out
|
||
call install_int ; prepare for interrupts
|
||
|
||
in_loop:
|
||
call read_c_buf ; get char(s) from buffer
|
||
call pause ; wait if there's no hurry
|
||
call write_q ; write message to queue
|
||
jmps in_loop ; go forever
|
||
|
||
terminate_in:
|
||
mov pd_flag,0 ; turn off the keep flag
|
||
mov cl,p_term
|
||
mov dl,0
|
||
int bdos ; back to bdos
|
||
|
||
|
||
; ***************************
|
||
; *** Setup Subroutines ***
|
||
; ***************************
|
||
|
||
; see which port we are, and adjust params if necessary
|
||
|
||
which_port:
|
||
mov al,ncp ; get copy number
|
||
cmp al,0 ; if port = 0
|
||
jz which_port_done ; then leave params alone
|
||
|
||
push ds
|
||
pop es ; local move
|
||
mov si,offset qn_list ; list of queue names
|
||
mov cx,qn_list_size ; count of names to change
|
||
add al,'0' ; change port number to ascii
|
||
|
||
qn_list_loop:
|
||
mov di,[si]
|
||
stosb ; change to '1'
|
||
inc si ! inc si
|
||
loop qn_list_loop
|
||
|
||
mov si,offset port1_params ; now adjust parameters
|
||
mov di,offset port0_params
|
||
mov cx,port_param_size
|
||
cld
|
||
rep movsb ; copy port1 over port0
|
||
|
||
which_port_done:
|
||
ret
|
||
|
||
|
||
; check to see if the port is present
|
||
; exit: zf set if port is present
|
||
|
||
is_it_there:
|
||
mov dx,port_int_id ; interrupt ident port
|
||
in al,dx
|
||
test al,0F8h ; should be zero if present
|
||
ret
|
||
|
||
|
||
; fetch pointers to supervisor and dispatcher entries
|
||
|
||
get_sys_data:
|
||
mov cl,s_sysdat
|
||
int bdos ; es:bx points to sysdat
|
||
mov sys_data_s,es ; save system data segment
|
||
|
||
mov ax,es:sup_o[bx]
|
||
mov i_sup_o,ax ; save supervisor offset
|
||
mov ax,es:sup_s[bx]
|
||
mov i_sup_s,ax ; save supervisor segment
|
||
|
||
mov ax,es:disp_o[bx]
|
||
mov i_disp_o,ax ; save dispatcher offset
|
||
mov ax,es:disp_s[bx]
|
||
mov i_disp_s,ax ; save dispatcher segment
|
||
ret
|
||
|
||
|
||
; create input, output, and mx queues
|
||
|
||
make_queues:
|
||
mov dx,offset qd_in
|
||
call make_one ; make the input queue
|
||
|
||
mov dx,offset qd_out
|
||
call make_one ; make the output queue
|
||
|
||
mov dx,offset qd_mx ; and the mx queue too
|
||
make_one:
|
||
mov cl,q_make
|
||
int bdos ; make it
|
||
ret
|
||
|
||
|
||
; open all three queues
|
||
|
||
open_queues:
|
||
mov dx,offset qpb_in
|
||
call open_one ; open the input queue
|
||
|
||
mov dx,offset qpb_out
|
||
call open_one ; open the output queue
|
||
|
||
mov dx,offset qpb_mx ; and the mx queue too
|
||
open_one:
|
||
mov cl,q_open
|
||
int bdos ; open it
|
||
ret
|
||
|
||
|
||
; perform the initial write to the mx queue
|
||
|
||
write_mx_queue:
|
||
mov cl,q_write
|
||
mov dx,offset qpb_mx
|
||
int bdos ; port is now available
|
||
ret
|
||
|
||
|
||
; write the address of the shared data block to the out queue
|
||
; to enable the Serial Out process access
|
||
|
||
write_t_block:
|
||
mov t_block_s,ds ; our data segment
|
||
mov cl,q_write ; offset is already there
|
||
mov dx,offset qpb_out
|
||
int bdos ; start up the out routine
|
||
ret
|
||
|
||
|
||
; set up interrupt vector and hardware
|
||
|
||
install_int:
|
||
mov di,ser_ds_ptr ; point to the place to
|
||
mov cs:[di],ds ; store our data segment
|
||
; store it in the code seg
|
||
sub ax,ax
|
||
mov es,ax ; base page extra segment
|
||
mov di,ser_int_vect ; vector destination
|
||
mov ax,ser_int_entry ; for port 0 or port 1
|
||
stosw ; store offset
|
||
mov ax,cs
|
||
stosw ; store segment
|
||
|
||
in al,pic_mask ; now program the 8259
|
||
and al,ser_pic_mask ; to allow this interrupt
|
||
out pic_mask,al
|
||
|
||
mov dx,port_int_en ; which comm ints to use
|
||
mov al,r_t_mask ; allow receive and transmit
|
||
out dx,al
|
||
|
||
mov dx,port_modem_ctrl
|
||
mov al,dtr_bit + rts_bit + i_en
|
||
out dx,al ; set up modem control
|
||
|
||
mov dx,port_int_id
|
||
in al,dx ; clear a pending xmit int
|
||
ret ; ready to go
|
||
|
||
|
||
; **************************
|
||
; *** Loop Subroutines ***
|
||
; **************************
|
||
|
||
; read characters from the circular buffer
|
||
|
||
read_c_buf:
|
||
cli ;; critical section
|
||
mov si,buf_out_ptr ;; for reading
|
||
mov ax,buf_in_ptr ;; used by int routine
|
||
cmp ax,si ;; if they're different
|
||
jnz read_now ;; then something's there
|
||
|
||
mov r_wait,0FFh ;; if not, then wait
|
||
sti ; interrupts are ok
|
||
call rec_prot_on ; enable handshakes
|
||
mov cl,dev_flag_wait
|
||
mov dl,r_flag
|
||
int bdos ; wait for c_buf to fill
|
||
jmps read_c_buf ; go back and set it up
|
||
|
||
read_now:
|
||
sti
|
||
push ds
|
||
pop es ; local extra seg
|
||
mov cx,q_mes_size - 1 ; max number of chars
|
||
mov di,offset msg_in + 1 ; start of char message
|
||
|
||
read_loop:
|
||
movsb ; from c_buf to message
|
||
cmp si,c_buf_end ; check for wrap around
|
||
jb read_no_wrap
|
||
mov si,offset c_buf
|
||
read_no_wrap:
|
||
cmp ax,si ; are there more chars?
|
||
loopnz read_loop ; if so, loop up to max
|
||
|
||
mov buf_out_ptr,si ; update the pointer
|
||
mov al,q_mes_size - 1
|
||
sub al,cl ; al = char count
|
||
mov msg_in,al ; store in the message
|
||
ret
|
||
|
||
|
||
; pause to fill the buffer a bit
|
||
; this maximizes the use of full queue messages
|
||
; and frees up the processor for other tasks
|
||
|
||
pause:
|
||
cmp msg_in,q_mes_size - 1 ; if last message was full
|
||
jz pause_done ; then don't wait
|
||
|
||
mov cl,p_delay
|
||
mov dx,1 ; wait at least 1 tick
|
||
int bdos
|
||
pause_done:
|
||
ret
|
||
|
||
|
||
; write one message to the queue
|
||
|
||
write_q:
|
||
mov cl,q_write
|
||
mov dx,offset qpb_in ; input queue param block
|
||
int bdos ; wait here if not ready
|
||
ret ; return when ready to send
|
||
|
||
|
||
; receive protocol handler
|
||
|
||
rec_prot_on:
|
||
mov bx,offset r_on_prot ; receive on data
|
||
mov al,0FFh ; state = true
|
||
xchg al,r_prot_state ; test and set state
|
||
test al,al ; if protocol if off now
|
||
jz receive_prot ; then turn it on
|
||
ret ; else just return
|
||
|
||
rec_prot_off:
|
||
mov bx,offset r_off_prot ; receive stop data
|
||
mov r_prot_state,0 ; protocol is off now
|
||
; jmps receive_prot
|
||
|
||
receive_prot:
|
||
mov al,rec_prot_code ; code for which protocol
|
||
test al,al ; if none being used
|
||
jz rec_prot_done ; then just skip it
|
||
|
||
and al,03h ; if not hardware handshake
|
||
jz rec_prot_x ; then do xon/xoff
|
||
|
||
xlat bx ; turn code into control bits
|
||
mov dx,port_modem_ctrl ; to control dtr, rts
|
||
out dx,al ; set modem lines
|
||
jmps rec_prot_done
|
||
|
||
rec_prot_x:
|
||
mov al,[bx]
|
||
mov send_x,al ; either xon or xoff
|
||
cmp al,xon
|
||
jnz rec_prot_done ; if we're sending an xon
|
||
call fake_int ; then fake an interrupt
|
||
; to kick it off
|
||
rec_prot_done:
|
||
ret
|
||
|
||
|
||
; Interrupt entries to kick off an xon transmit
|
||
|
||
fake_int0:
|
||
int 12 ; port 0 interrupt
|
||
ret
|
||
|
||
fake_int1:
|
||
int 11 ; port 1 interrupt
|
||
ret
|
||
|
||
|
||
serin_code_top equ offset $
|
||
|
||
|
||
; *****************************
|
||
; *** RSP header, pd, uda ***
|
||
; *****************************
|
||
|
||
dseg
|
||
|
||
org rsp_header ; header start
|
||
|
||
dw 0,0
|
||
ncp db 1,0 ; one copy
|
||
dw 0,0,0
|
||
dw 0,0
|
||
|
||
|
||
org rsp_pd ; process descriptor
|
||
|
||
dw 0,0 ; link, thread
|
||
db 0 ; ready to run
|
||
db 180 ; priority better than PIN's
|
||
pd_flag dw 2 ; process flag "keep"
|
||
db 'SerIn ' ; process name
|
||
dw rsp_uda/10h ; uda segment
|
||
dw 0,0 ; disk, user, reserved
|
||
dw 1 ; for shared code
|
||
dw 0,0,0 ; and a mess of zeros
|
||
dw 0,0,0
|
||
dw 0,0,0
|
||
dw 0,0,0
|
||
|
||
|
||
org rsp_uda ; user data area
|
||
|
||
dw 0,0,0,0,0,0 ; no dma buffer
|
||
dw 0,0,0,0,0,0
|
||
dw 0,0,0,0,0,0
|
||
dw 0,0,0,0,0,0
|
||
dw 0,0,rsp_stack_top,0,0,0
|
||
dw 0,0,0,0,0,0
|
||
dw 0,0,0,0,0,0
|
||
dw 0,0,0,0,0,0
|
||
db 1,0,0,0,0,0 ; don't switch from UDA
|
||
; stack at SUP entry
|
||
|
||
org rsp_stack_top
|
||
|
||
dw offset serial_in ; code start
|
||
dw 0 ; code seg (genccpm)
|
||
dw 0 ; flags (genccpm)
|
||
|
||
|
||
; ******************************
|
||
; *** Our data begins here ***
|
||
; ******************************
|
||
|
||
org rsp_data_end ; above the rsp stuff
|
||
|
||
; first we have parameters for port 0
|
||
|
||
port0_params rb 0
|
||
p0_base equ 03F8h ; port base address
|
||
port_data dw p0_base ; rw data
|
||
port_int_en dw p0_base + 1 ; wo int enable
|
||
port_int_id dw p0_base + 2 ; ro int ident
|
||
port_modem_ctrl dw p0_base + 4 ; wo bit 3 = en int
|
||
port_status dw p0_base + 5 ; ro tbe and da
|
||
port_modem_stat dw p0_base + 6 ; ro dsr cts
|
||
fake_int dw fake_int0 ; for software interrupt
|
||
ser_int_vect dw 12 * 4 ; interrupt vector location
|
||
ser_int_entry dw i_serial_0 ; interrupt entry point
|
||
ser_ds_ptr dw data_seg_0 ; port 0's data segment
|
||
ser_pic_mask db 0EFh ; enable pic interrupt
|
||
r_flag db 08h ; XIOS receive flag
|
||
t_flag db 09h ; XIOS transmit flag
|
||
|
||
; if using port 1, these values are copied over port 0's
|
||
|
||
port1_params rb 0
|
||
p1_base equ 02F8h ; port base address
|
||
dw p1_base ; rw data
|
||
dw p1_base + 1 ; wo int enable
|
||
dw p1_base + 2 ; ro int ident
|
||
dw p1_base + 4 ; wo bit 3 = en int
|
||
dw p1_base + 5 ; ro tbe and da
|
||
dw p1_base + 6 ; ro dsr cts
|
||
dw fake_int1 ; soft int
|
||
dw 11 * 4 ; int vector location
|
||
dw i_serial_1 ; int entry point
|
||
dw data_seg_1 ; port 1's data seg
|
||
db 0F7h ; pic interrupt mask
|
||
db 0Ah ; rec flag
|
||
db 0Bh ; xmit flag
|
||
|
||
port_param_size equ offset $ - offset port1_params
|
||
|
||
|
||
; queue descriptors, buffers, and parameter blocks
|
||
|
||
q_in_buf rb q_mes_size * in_q_num
|
||
|
||
qd_in dw 0,0,02h
|
||
db 'SerIn'
|
||
qd_in_p db '0 '
|
||
dw q_mes_size,in_q_num,0
|
||
dw 0,0,0
|
||
dw q_in_buf
|
||
|
||
|
||
q_out_buf rb q_mes_size * out_q_num
|
||
|
||
qd_out dw 0,0,02h
|
||
db 'SerOut'
|
||
qd_out_p db '0 '
|
||
dw q_mes_size,out_q_num,0
|
||
dw 0,0,0
|
||
dw q_out_buf
|
||
|
||
|
||
qd_mx dw 0,0,03h
|
||
db 'MXSer'
|
||
qd_mx_p db '0 '
|
||
dw 0,1,0
|
||
dw 0,0,0,0
|
||
|
||
qpb_in dw 0,0,0,msg_in
|
||
db 'SerIn'
|
||
qpb_in_p db '0 '
|
||
|
||
qpb_out dw 0,0,0,t_block_o
|
||
db 'SerOut'
|
||
qpb_out_p db '0 '
|
||
|
||
qpb_mx dw 0,0,0,0
|
||
db 'MXSer'
|
||
qpb_mx_p db '0 '
|
||
|
||
; queue name adjustment list for port numbers
|
||
|
||
qn_list dw qd_in_p
|
||
dw qd_out_p
|
||
dw qd_mx_p
|
||
dw qpb_in_p
|
||
dw qpb_out_p
|
||
dw qpb_mx_p
|
||
|
||
qn_list_size equ (offset $ - offset qn_list) / 2
|
||
|
||
|
||
t_block_o dw t_block
|
||
t_block_s rw 1 ; filled by write t_block
|
||
|
||
msg_in rb q_mes_size
|
||
|
||
r_prot_state db 0FFh ; 0FFh => rec protocol on
|
||
|
||
all_on equ i_en+dtr_bit+rts_bit
|
||
r_on_prot db xon, all_on, all_on, all_on
|
||
r_off_prot db xoff, rts_bit+i_en, dtr_bit+i_en, i_en
|
||
|
||
serin_data_top equ offset $
|
||
|
||
eject
|
||
|
||
; ***************************************
|
||
; *** Interrupt routine begins here ***
|
||
; ***************************************
|
||
|
||
cseg
|
||
|
||
org serin_code_top
|
||
|
||
; this collection of data must be in the code segment
|
||
; and it must not change, or reentrancy is blown
|
||
|
||
data_seg0 rw 1 ; port 0's data segment
|
||
data_seg1 rw 1 ; port 1's data segment
|
||
|
||
i_sup_o rw 1 ; supervisor offset
|
||
i_sup_s rw 1 ; supervisor segment
|
||
supervisor equ dword ptr i_sup_o
|
||
|
||
; serial char interrupt entry for port 0
|
||
|
||
i_serial_0:
|
||
push ds ; on user's stack
|
||
mov ds,data_seg0 ; get port zero's data seg
|
||
jmps i_serial_shared ; and share the rest
|
||
|
||
; serial char interrupt entry for port 1
|
||
|
||
i_serial_1:
|
||
push ds ; on user's stack
|
||
mov ds,data_seg1 ; get port 1's data seg
|
||
; jmps i_serial_shared ; and share the rest
|
||
|
||
; shared serial char interrupt code
|
||
|
||
i_serial_shared:
|
||
mov save_ax,ax ; first switch stacks
|
||
mov save_ss,ss
|
||
mov save_sp,sp
|
||
mov ax,ds ; set up local stack
|
||
mov ss,ax
|
||
mov sp,local_stack
|
||
push bx ! push cx ! push dx ! push bp
|
||
push si ! push di ! push es
|
||
mov es,ax ; for receive stosb
|
||
|
||
mov dx,port_int_id ; int identification reg
|
||
in al,dx ; this says which int it is
|
||
and al,07h ; 3 lsb's only
|
||
mov int_id,al ; save for pic reset
|
||
cmp al,rec_int ; if not from char received
|
||
jnz i_transmit ; then skip
|
||
|
||
i_receive:
|
||
mov dx,port_status ; just to double check
|
||
in al,dx ; we look at line status
|
||
test al,dr ; if not data ready
|
||
jz i_rec_wait ; then skip buffer write
|
||
i_rec_char:
|
||
mov dx,port_data
|
||
in al,dx ; fetch the data char
|
||
test tran_prot_code,xon_xoff ; check to see if this is
|
||
jz i_rec_to_buf ; an xon/xoff character
|
||
cmp al,xon ; for the transmit side
|
||
jz i_rec_x ; if it is, get out of here
|
||
cmp al,xoff
|
||
jz i_rec_x
|
||
|
||
i_rec_to_buf: ; a valid data char rec'd
|
||
mov di,buf_in_ptr
|
||
stosb ; store to circular buffer
|
||
cmp di,c_buf_end ; check for wrap around
|
||
jb i_rec_no_wrap
|
||
mov di,offset c_buf ; wrap to beginning
|
||
i_rec_no_wrap:
|
||
mov ax,di
|
||
sub ax,buf_out_ptr ; check buffer fullness
|
||
jz i_rec_too_full ; right to the brim
|
||
mov buf_in_ptr,di ; update if any room at all
|
||
jnc i_rec_valid ; subtraction worked
|
||
add ax,c_buf_size ; ax = chars in buffer
|
||
i_rec_valid:
|
||
cmp ax,c_buf_size - 10h ; if not too full
|
||
jb i_rec_wait ; then carry on
|
||
i_rec_too_full:
|
||
call rec_prot_off ; else, try to stop the stream
|
||
|
||
i_rec_wait:
|
||
mov al,0
|
||
xchg al,r_wait ; test and set wait flag
|
||
test al,al ; if Serial In isn't waiting
|
||
jz i_transmit ; then check for transmit
|
||
|
||
mov dl,r_flag ; if it is waiting
|
||
call i_set_flag ; then set the flag
|
||
jmps i_transmit ; check for xmit message
|
||
|
||
i_rec_x:
|
||
mov rec_x,al ; save xon/xoff for transmit
|
||
; jmps i_transmit ; and carry on
|
||
|
||
; in case a character was received just before transmit is to
|
||
; be checked, we always check for a pending transmit message.
|
||
|
||
i_transmit:
|
||
cmp send_x,0 ; if there is an xon/xoff
|
||
jz i_tran_from_buf ; to send, it has top priority
|
||
|
||
call trans_ready ; check tbe
|
||
jz i_exit ; if not ready, come back again
|
||
|
||
mov dx,port_data
|
||
mov al,send_x
|
||
out dx,al ; send an xon/xoff char
|
||
mov send_x,0 ; don't do it again
|
||
jmps i_exit ; and depart
|
||
|
||
i_tran_from_buf:
|
||
cmp t_count,0 ; if transmit message is empty
|
||
jz i_tran_wait ; see if serout is waiting
|
||
|
||
call trans_prot ; if protocol blocks transmission
|
||
jz i_tran_wait ; then skip the output
|
||
|
||
call trans_ready ; check tbe
|
||
jz i_tran_wait ; for a flag wait on serout
|
||
|
||
les si,t_pointer ; point to transmit message
|
||
mov al,es:[si] ; grab the character
|
||
mov dx,port_data
|
||
out dx,al ; ship the character
|
||
inc si ; bump and
|
||
mov t_ptr_off,si ; update the pointer
|
||
dec t_count ; and if characters remain
|
||
jnz i_exit ; then don't set the flag
|
||
|
||
i_tran_wait:
|
||
mov al,0
|
||
xchg al,t_wait ; test and set wait flag
|
||
test al,al ; if Serial Out not waiting
|
||
jz i_exit ; then we're done
|
||
|
||
mov dl,t_flag ; if it is waiting
|
||
call i_set_flag ; then set flag
|
||
|
||
i_exit:
|
||
cmp int_id,no_int ; if interrupt was soft
|
||
jz i_no_pic ; then don't reset pic
|
||
mov al,ns_eoi ; reset the pic
|
||
out pic_ack,al
|
||
|
||
i_no_pic:
|
||
pop es ! pop di ! pop si
|
||
pop bp ! pop dx ! pop cx ! pop bx
|
||
|
||
mov ax,save_ax
|
||
mov ss,save_ss ; restore the stack
|
||
mov sp,save_sp
|
||
pop ds ; get back user's ds
|
||
iret ; do not dispatch!
|
||
|
||
|
||
; check for transmit buffer empty. zf set if not
|
||
|
||
trans_ready:
|
||
mov dx,port_status ; if message pending, see if
|
||
in al,dx ; the port is ready
|
||
test al,tbe ; if not ready, then check
|
||
ret
|
||
|
||
; check for transmit protocol ready. zf set if not
|
||
|
||
trans_prot:
|
||
mov ah,tran_prot_code ; which protocol to use
|
||
test ah,ah ; if zero
|
||
jz trans_prot_ok ; then skip the works
|
||
|
||
mov dx,port_modem_stat
|
||
in al,dx ; get the status bits
|
||
test ah,dtr_dsr
|
||
jz trans_prot1 ; if dsr/dtr protocol
|
||
test al,dsr_bit ; see if dsr is on
|
||
jz trans_prot_done ; if not, it's no good
|
||
|
||
trans_prot1:
|
||
test ah,rts_cts
|
||
jz trans_prot2 ; if rts/cts protocol
|
||
test al,cts_bit ; see if cts is on
|
||
jz trans_prot_done ; if not, forget it
|
||
|
||
trans_prot2:
|
||
test ah,xon_xoff
|
||
jz trans_prot_ok ; if xon/xoff protocol
|
||
cmp rec_x,xoff ; see if we've got an xoff
|
||
jz trans_prot_done ; if so, go back
|
||
|
||
trans_prot_ok:
|
||
or al,0FFh ; clear the zero flag
|
||
trans_prot_done:
|
||
ret ; with zf
|
||
|
||
; set the flag passed in register dl
|
||
|
||
i_set_flag:
|
||
mov dh,0 ; ensure dx = flag num
|
||
mov cx,dev_flag_set
|
||
push ds
|
||
mov ds,sys_data_s
|
||
callf supervisor ; right to the sup
|
||
pop ds
|
||
ret
|
||
|
||
|
||
; ************************************
|
||
; *** Interrupt data begins here ***
|
||
; ************************************
|
||
|
||
dseg
|
||
|
||
org serin_data_top
|
||
|
||
save_ax rw 1 ; for stack switch
|
||
save_ss rw 1
|
||
save_sp rw 1
|
||
|
||
int_id rb 1 ; saves the int_id_reg
|
||
r_wait db 00h ; is Serial In waiting?
|
||
|
||
; this is the data block which is shared with SerOut
|
||
|
||
t_block equ offset $
|
||
t_wait db 00h ; is Serial Out waiting?
|
||
t_count db 00h ; message byte count
|
||
t_ptr_off rw 1 ; offset of trans message
|
||
t_ptr_seg rw 1 ; segment of trans message
|
||
t_pointer equ dword ptr t_ptr_off
|
||
rec_prot_code db 00h ; receive protocol code
|
||
tran_prot_code db dtr_dsr + xon_xoff ; transmit protocol code
|
||
|
||
|
||
buf_in_ptr dw c_buf ; used by int to fill
|
||
buf_out_ptr dw c_buf ; used by Serial In to empty
|
||
|
||
rec_x db xon ; our received xon/xoff
|
||
send_x db 00h ; an xon/xoff to send
|
||
|
||
sys_data_s rw 1 ; system data seg
|
||
|
||
i_disp_o rw 1 ; dispatcher offset
|
||
i_disp_s rw 1 ; dispatcher segment
|
||
dispatcher equ dword ptr i_disp_o
|
||
|
||
c_buf rb c_buf_size ; receive circular buffer
|
||
c_buf_end equ offset $
|
||
|
||
rb stack_size ; local interrupt stack
|
||
local_stack equ offset $
|
||
|
||
db 00h ; for gencmd
|
||
|
||
end
|
||
|