; відновлення векторів переривань
_restore_com PROC FAR
push bp
mov bp,sp
push si
; відзначаємо COM порт як не активний
mov si,CURRENT_AREA
mov installed[si],0
; відновлюємо вектор переривання
mov ah,25H
mov al,int_com[si]
mov dx,old_com_off[si]
mov bx,old_com_seg[si]
push ds
mov ds,bx
int 21h
pop ds
pop si
mov sp,bp
pop bp
ret
_restore_com ENDP
; відкрити COM порт
; скидання буферів передавача і приймача,
; ініціалізація регістрів UART 8250
; дозвіл переривань від UART 8250
; (програмування контролера переривань)
; [bp+6] = швидкість обміну
; [bp+8] = спосіб з'єднання - M(Модем), D(Нуль-модем)
; [bp+10] = парність - N(ONE), O(DD), E(VEN), S(PACE), M(ARK)
; [bp+12] = кількість стопових бітів 1, 2
_open_com PROC FAR
push bp
mov bp,sp
push si
mov si,CURRENT_AREA
; забороняємо переривання
cli
mov ax,[bp+6]
mov baud_rate[si],ax
mov bh,[bp+8]
mov device_conn[si],bh
mov bl,[bp+10]
mov parity[si],bl
mov ch,[bp+12]
mov stop_bits[si],CH
; скидаємо буфери і покажчики
mov start_s_data[si],0
mov end_s_data[si],0
mov start_r_data[si],0
mov end_r_data[si],0
mov size_s_data[si],0
mov size_r_data[si],0
; чи перевіряємо установлений вже оброблювач переривань
test installed[si],1
jnz reset_uart
jmp exit_open
reset_uart:
; установлюємо регістри UART 8250
; скидаємо регістр керування модемом
mov al,0
mov dx,MCR[si]
out dx,al
jmp $+2
; скидаємо регістр стану лінії
mov dx,LSR[si]
in al,dx
jmp $+2
; скидаємо регістр даних
mov dx,DATREG[si]
in al,dx
jmp $+2
; скидаємо регістр стану модему
mov dx,MSR[si]
in al,dx
; визначаємо дільник частоти тактового генератора
mov ax,50
mul DIV50
div baud_rate[si]
mov bx,ax
; переключаємо регістир даних і регістр керування перериваннями
; для введення дільника частоти тактового генератора
mov dx,LCR[si]
mov al,80H
out dx,al
jmp $+2
; уводимо молодший байт дільника частоти тактового генератора
mov dx,WORD PTR DLL[si]
mov al,bl
out dx,al
jmp $+2
; уводимо старший байт дільника частоти тактового генератора
mov dx,WORD PTR DLH[si]
mov al,bh
out dx,al
jmp $+2
; визначаємо парність і кількість стоп-бітів
mov al,03H
cmp parity[si],'O'
jne next1
mov al,0ah
jmp short next3
next1:
cmp parity[si],'E'
jne next2
mov al,1ah
jmp short next3
next2:
cmp parity[si],'M'
jne next3
mov al,2ah
next3:
test stop_bits[si],2
jz stop1
or al,4
stop1:
mov dx,LCR[si]
out dx,al
; дозволяємо переривання для 8259 і 8250
; установлюємо регістр маски переривань щоб
; дозволити переривання від асинхронного порту
in al,IMR
and al,d_irq[si]
out IMR,al
; дозволяємо генерацію переривань при готовності прийнятих
; даних, по стані "BREAK" і помилково
mov dx,IER[si]
mov al,0Dh
out dx,al
jmp $+2
; установлюємо DTR, RTS, OUT2
mov dx,MCR[si]
mov al,0bh
out dx,al
exit_open:
sti
pop si
mov sp,bp
pop bp
ret
_open_com ENDP
; забороняємо переривання від асинхронного порту
_close_com PROC FAR
push bp
mov bp,sp
push si
mov si,CURRENT_AREA
test installed[si],1
jz exit_close
; забороняємо переривання UART 8250
mov dx,IER[si]
mov al,0
out dx,al
; маскуємо переривання від UART
mov dx,IMR
in al,dx
or al,e_irq[si]
jmp $+2
out dx,al
exit_close:
pop si
mov sp,bp
pop bp
ret
_close_com ENDP
;процедура повертає 1 якщо з МТМ надійшов дзвінок
_com_ring proc far
push bp
mov bp,sp
push si
mov si,CURRENT_AREA
test installed[si],1
jz exit_com_ring
xor ax,ax
mov al,BYTE PTR RING[si]
nop
mov RING[si],0
nop;
exit_com_ring:
pop si
mov sp,bp
pop bp
ret
_com_ring endp
; ДОПОМІЖНІ ФУНЦІЇ
; знімаємо сигнал DTR
_dtr_off PROC FAR
push bp
mov bp,sp
push si
pushf
push ax
push dx
push si
mov si,CURRENT_AREA
test installed[si],1
jz exit_dtr_off
; установлюємо регістр керування модемом,
; скидаємо сигнали DTR і RTS
mov dx,MCR[si]
mov al,08H
out dx,al
exit_dtr_off:
pop si
pop dx
pop ax
popf
pop si
mov sp,bp
pop bp
ret
_dtr_off ENDP
; установлюємо сигнал DTR
_dtr_on PROC FAR
push bp
mov bp,sp
push si
pushf
push ax
push dx
push si
mov si,CURRENT_AREA
test installed[si],1
jz exit_dtr_on
; установлюємо регістр керування модемом,
; установлюємо сигнали DTR, RTS, OUT2
mov dx,MCR[si]
mov al,0bh
out dx,al
exit_dtr_on:
pop si
pop dx
pop ax
popf
pop si
mov sp,bp
pop bp
ret
_dtr_on ENDP
;
; повертаємо в регістрі ax число байтів у регістрі приймача,
; а в регістрі dx загальний розмір буфера приймача
_r_count PROC FAR
push bp
mov bp,sp
push si
pushf
push si
mov si,CURRENT_AREA
mov ax,0
mov dx,R_SIZE
test installed[si],1
jz exit_r_count
; записуємо в регістр ax число символів у буфері приймача
mov ax,size_r_data[si]
exit_r_count:
pop si
popf
pop si
mov sp,bp
pop bp
ret
_r_count ENDP
; одержуємо черговий символ з буфера приймача,
; отриманий символ віддаляється з буфера
_receive_com PROC FAR
push bp
mov bp,sp
push si
pushf
push bx
push si
mov si,CURRENT_AREA
mov ax,-1
test installed[si],1
jz exit_receive_com
; повертаємося якщо буфер приймача порожній
cmp size_r_data[si],0
je exit_receive_com
mov ah,0
mov bx,start_r_data[si]
mov al,reciave_buf[si][bx]
cmp parity[si],'N'
je no_parity
; якщо виробляється перевірка на парність, то маскуємо старший біт
and al,7FH
no_parity:
inc bx
cmp bx,R_SIZE
jb rec_ptr_no_max
mov bx,0
rec_ptr_no_max:
mov start_r_data[si],bx
dec size_r_data[si]
exit_receive_com:
pop si
pop bx
popf
pop si
mov sp,bp
pop bp
ret
_receive_com ENDP
; функція повертає в регістрі ax число вільних байт у
; буфері передавача, а в регістрі dx загальний розмір буфера передавача
_s_count PROC FAR
push bp
mov bp,sp
push si
pushf
push si
mov si,CURRENT_AREA
mov ax,0
mov dx,S_SIZE
test installed[si],1
jz exit_s_count
mov ax,S_SIZE
sub ax,size_s_data[si]
exit_s_count:
pop si
popf
pop si
mov sp,bp
pop bp
ret
_s_count ENDP
; помістити символ у буфер передавача
; [bp+6] - символ
_send_com PROC FAR
push bp
mov bp,sp
push si
mov al,[bp+6]
pushf
push ax
push bx
push dx
push si
mov si,CURRENT_AREA
test installed[si],1
jz exit_send_com
cmp size_s_data[si],S_SIZE
jl no_s_EOVFLOW
; відбулося переповнення буфера передавача
inc WORD PTR EOVFLOW[si]
jmp short exit_send_com
no_s_EOVFLOW:
mov bx,end_s_data[si]
mov send_buf[si][bx],al
inc bx
cmp bx,S_SIZE
jl no_send_ptr_max
mov bx,0
no_send_ptr_max:
mov end_s_data[si],bx
inc size_s_data[si]
; зчитуємо регістр керування перериваннями
mov dx,IER[si]
in al,dx
; завершуємо функцію якщо дозволені переривання після передачі байта
test al,2
jnz exit_send_com
; дозволяємо переривання після передачі байта, після прииема байта,
; при виявленні стану "BREAK" і при виникненні помилки
mov al,7
out dx,al
exit_send_com:
pop si
pop dx
pop bx
pop ax
popf
pop si
mov sp,bp
pop bp
ret
_send_com ENDP
; передаємо вилученому модему сигнал "BREAK"
_break_com PROC FAR
push bp
mov bp,sp
push si
pushf
push ax
push cx
push dx
mov si,CURRENT_AREA
test installed[si],1
jz exit_break_com
; передаємо сигнал "BREAK"
mov dx,LCR[si]
in al,dx
jmp $+2
or al,40h
out dx,al
mov cx,0C000h
do_BREAK:
loop do_BREAK
and al,0BFh
out dx,al
exit_break_com:
pop dx
pop cx
pop ax
popf
pop si
mov sp,bp
pop bp
ret
_break_com ENDP
; повертаємо в dx:ax покажчик на лічильники помилок
_com_errors PROC FAR
push bp
mov bp,sp
mov ax,OFFSET DGROUP:CURRENT_AREA
add ax,error_block
mov dx,ds
mov sp,bp
pop bp
ret
_com_errors ENDP
; заповнюємо лічильники помилок
set_err PROC NEAR
test al,2
jz test1
inc WORD PTR EOVRUN[si]
test1:
test al,4
jz test2
inc WORD PTR EPARITY[si]
test2:
test al,8
jz test3
inc WORD PTR EFRAME[si]
test3:
test al,16
jz exit_set_err
inc WORD PTR EBREAK[si]
exit_set_err:
ret
set_err ENDP
; протокол модему для передачі даних
modem_protocol PROC NEAR
cmp device_conn[si],'M'
jne no_modem
; установлюємо сигнали DTR, RTS і OUT2
mov dx,MCR[si]
mov al,00001011B
out dx,al
jmp $+2
; очікуємо поки модем відповість про готовність сигналом DSR
mov cx,1000
mov dx,MSR[si]
wait_dsr:
in al,dx
test al,20H
jnz test_cts
loop wait_dsr
; модем не відповів сигналом DSR
inc WORD PTR EDSR[si]
jmp short no_modem
test_cts:
; очікуємо поки модем відповість про готовність сигналом CTS
mov cx,1000
wait_cts:
in al,dx
test al,10H
jnz test_lcr
loop wait_cts
; модем не відповів сигналом CTS
inc WORD PTR ECTS[si]
test_lcr:
no_modem:
; чи перевіряємо порожній регситр збереження передавача
mov dx,LSR[si]
in al,dx
test al,20H
jnz s_reg_empty
; помилка при передачі
inc WORD PTR EXMIT[si]
s_reg_empty:
ret
modem_protocol ENDP
; оброблювач переривань від COM1
int_hndlr1 PROC FAR
push si
mov si,OFFSET DGROUP:AREA1
jmp short handle_int
; оброблювач переривань від COM2
int_hndlr2 PROC FAR
push si
mov si,OFFSET DGROUP:AREA2
jmp short handle_int
; оброблювач переривань від COM3
int_hndlr3 PROC FAR
push si; SAVE si
mov si,OFFSET DGROUP:AREA3
jmp short handle_int
;
; оброблювач переривань від COM4
int_hndlr4 PROC FAR
push si; SAVE si
mov si,OFFSET DGROUP:AREA4
;
; оброблювач переривань
handle_int:
push ax
push bx
push cx
push dx
push bp
push di
push ds
push es
mov ax,DGROUP
mov ds,ax
next_pr:
; передаємо контролеру переривань команду кінця обробки
; переривання
mov dx,OCR
mov al,eoi[si]
out dx,al
next_inter:
; зчитуємо значення регістра ідентифікації переривання
mov dx,IIR[si]
in al,dx
; визначаємо причину переривання
; виявлено сотояние "BREAK" чи відбулася помилка
cmp al,0
je MSTAT_int
; дані прийняті і доступні для читання
cmp al,4
je RX_int
; буфер передавача порожній
cmp al,2
je TX_int
; змінився стан ліній CTS, RI, DCD, DSR
cmp al,6
je LSTAT_int
; завершуємо обробку переривань
jmp FAR PTR exit_handler
LSTAT_int:
; зчитуємо регістр стану лінії і викликаємо функцію
; set_err, що визначить причину переривання
mov dx,LSR[si]
in al,dx
mov al,0FFh
mov RING[si],al
call set_err
jmp next_inter
MSTAT_int:
; зчитуємо регістр стану модему
mov dx,MSR[si]
in al,dx
mov al,0FFh
mov RING[si],al
jmp next_inter
TX_int:
; дивимося їсти чи дані для передачі модему
cmp size_s_data[si],0
jg have_data_for_send
; якщо буфер передавача порожній переустановлюємо регістр
; керування перериваннями
mov dx,IER[si]
mov al,0Dh
out dx,al
jmp next_inter
have_data_for_send:
; передаємо символ модему відповідно до стану
; ліній RS-232-З
call modem_protocol
; передаємо черговий символ з буфера передавача
mov bx,start_s_data[si]
mov al,send_buf[si][bx]
mov dx,DATREG[si]
out dx,al
inc bx
cmp bx,S_SIZE
jb ptr_no_max
mov bx,0
ptr_no_max:
mov start_s_data[si],bx
dec size_s_data[si]
jmp next_inter
; дані прийняті і доступні для читання
RX_int:
; зчитуємо прийнятий байти із регістра даних UART
mov dx,DATREG[si]
in al,dx
cmp size_r_data[si],R_SIZE
jl no_r_EOVFLOW
; буфер приймача переповнений, збільшуємо відповідний
; лічильник помилок
inc WORD PTR EOVFLOW[si]
jmp next_inter
no_r_EOVFLOW:
mov bx,end_r_data[si]
mov reciave_buf[si][bx],al
inc size_r_data[si]
inc bx
cmp bx,R_SIZE
jb no_max_r_ptr
mov bx,0
no_max_r_ptr:
mov end_r_data[si],bx
jmp next_inter
exit_handler:
mov al,20h
out 20h,al
pop es
pop ds
pop di
pop bp
pop dx
pop cx
pop bx
pop ax
pop si
iret
int_hndlr4 ENDP
int_hndlr3 ENDP
int_hndlr2 ENDP
int_hndlr1 ENDP
COM_TEXT ENDS
END