Minix1.5/kernel/rs2.x
|*===========================================================================*
|* rs232 interrupt handlers for real and protected modes *
|*===========================================================================*
| This is a fairly direct translation of the interrupt handlers in rs232.c.
| See the comments there.
| It is about 5 times as efficient, by avoiding save/restart and slow function
| calls for port i/o as well as the compiler!
#include <minix/config.h>
#if !C_RS232_INT_HANDLERS /* otherwise, don't use anything in this file */
#include <minix/const.h>
#include "const.h"
#include "sconst.h"
| exported functions
.text
.define _prs232_int
.define _psecondary_int
.define _rs232_int | used only for real mode
.define _secondary_int | used only for real mode
| imported functions
.extern kernel_ds
.extern save
.extern _tty_wakeup
| imported variables
.bss
.extern _rs_lines
.extern _tty_events
#undef MINOR
#if !INTEL_32BITS
#define eax ax /* use 32-bit register names throughout */
#define ebx bx /* but modify them for 16-bit mode/CPU */
#define edx dx
#define esi si
#define iretd iret
#endif
#if ASLD
#define add1_and_align(n) [[[n]+SIZEOF_INT] / SIZEOF_INT * SIZEOF_INT]
#else
#define add1_and_align(n) (((n)+SIZEOF_INT) / SIZEOF_INT * SIZEOF_INT)
#endif
| These constants are defined in tty.h. That has C stuff so can't be included.
EVENT_THRESHOLD = 64
RS_IBUFSIZE = 256
| These constants are defined in rs232.c.
IS_LINE_STATUS_CHANGE = 6
IS_MODEM_STATUS_CHANGE = 0
IS_NO_INTERRUPT = 1
IS_RECEIVER_READY = 4
IS_TRANSMITTER_READY = 2
LS_OVERRUN_ERR = 2
LS_PARITY_ERR = 4
LS_FRAMING_ERR = 8
LS_BREAK_INTERRUPT = 0x10
LS_TRANSMITTER_READY = 0x20
MC_DTR = 1
MC_OUT2 = 8
MS_CTS = 0x10
ODEVREADY = MS_CTS
ODONE = 1
OQUEUED = 0x20
ORAW = 2
OSWREADY = 0x40
OWAKEUP = 4
RS_IHIGHWATER = 3*RS_IBUFSIZE/4
| These port offsets are hard-coded in rs232.c.
XMIT_OFFSET = 0
RECV_OFFSET = 0
INT_ID_OFFSET = 2
MODEM_CTL_OFFSET = 4
LINE_STATUS_OFFSET = 5
MODEM_STATUS_OFFSET = 6
| Offsets in struct rs232_s. They must match rs232.c
MINOR = 0
IDEVREADY = MINOR+SIZEOF_INT
ITTYREADY = IDEVREADY+1
IBUF = add1_and_align(ITTYREADY)
IBUFEND = IBUF+SIZEOF_INT
IHIGHWATER = IBUFEND+SIZEOF_INT
IPTR = IHIGHWATER+SIZEOF_INT
OSTATE = IPTR+SIZEOF_INT
OXOFF = OSTATE+1
OBUFEND = add1_and_align(OXOFF)
OPTR = OBUFEND+SIZEOF_INT
XMIT_PORT = OPTR+SIZEOF_INT
RECV_PORT = XMIT_PORT+SIZEOF_INT
DIV_LOW_PORT = RECV_PORT+SIZEOF_INT
DIV_HI_PORT = DIV_LOW_PORT+SIZEOF_INT
INT_ENAB_PORT = DIV_HI_PORT+SIZEOF_INT
INT_ID_PORT = INT_ENAB_PORT+SIZEOF_INT
LINE_CTL_PORT = INT_ID_PORT+SIZEOF_INT
MODEMCTL_PORT = LINE_CTL_PORT+SIZEOF_INT
LINESTATUS_PORT = MODEMCTL_PORT+SIZEOF_INT
MODEMSTATUS_PORT = LINESTATUS_PORT+SIZEOF_INT
LSTATUS = MODEMSTATUS_PORT+SIZEOF_INT
FRAMING_ERRORS = add1_and_align(LSTATUS)
OVERRUN_ERRORS = FRAMING_ERRORS+SIZEOF_INT
PARITY_ERRORS = OVERRUN_ERRORS+SIZEOF_INT
BREAK_INTERRUPTS = PARITY_ERRORS+SIZEOF_INT
IBUF1 = BREAK_INTERRUPTS+SIZEOF_INT
IBUF2 = IBUF1+RS_IBUFSIZE+1
SIZEOF_STRUCT_RS232_S = add1_and_align(IBUF2+RS_IBUFSIZE)
.text
| PUBLIC void interrupt _psecondary_int();
_psecondary_int:
push ds
push esi
mov si,ss
mov ds,si
mov esi,#_rs_lines+SIZEOF_STRUCT_RS232_S
j common
| PUBLIC void interrupt _secondary_int();
_secondary_int:
push ds
push esi
mov esi,#_rs_lines+SIZEOF_STRUCT_RS232_S
seg cs
mov ds,kernel_ds
j common
| PUBLIC void interrupt _prs232_int();
_prs232_int:
push ds
push esi
mov si,ss
mov ds,si
mov esi,#_rs_lines
j common
| input interrupt
inint:
addb dl,#RECV_OFFSET-INT_ID_OFFSET
in
mov ebx,IPTR(esi)
movb (ebx),al
cmp ebx,IBUFEND(esi)
jge checkxoff
inc _tty_events
inc ebx
mov IPTR(esi),ebx
cmp ebx,IHIGHWATER(esi)
jne checkxoff
addb dl,#MODEM_CTL_OFFSET-RECV_OFFSET
movb al,#MC_OUT2+MC_DTR
out
movb IDEVREADY(esi),#FALSE
checkxoff:
testb ah,#ORAW
jne rsnext
cmpb al,OXOFF(esi)
je gotxoff
testb ah,#OSWREADY
jne rsnext
orb ah,#OSWREADY
mov edx,LINESTATUS_PORT(esi)
in
testb al,#LS_TRANSMITTER_READY
je rsnext
addb dl,#XMIT_OFFSET-LINE_STATUS_OFFSET
j outint1
gotxoff:
andb ah,#notop(OSWREADY)
j rsnext
| PUBLIC void interrupt rs232_int();
_rs232_int:
push ds
push esi
mov esi,#_rs_lines
seg cs
mov ds,kernel_ds
common:
push eax
push ebx
push edx
movb ah,OSTATE(esi)
mov edx,INT_ID_PORT(esi)
in
rsmore:
cmpb al,#IS_RECEIVER_READY
je inint
cmpb al,#IS_TRANSMITTER_READY
je outint
cmpb al,#IS_MODEM_STATUS_CHANGE
je modemint
cmpb al,#IS_LINE_STATUS_CHANGE
jne rsdone | fishy
| line status change interrupt
addb dl,#LINE_STATUS_OFFSET-INT_ID_OFFSET
in
testb al,#LS_FRAMING_ERR
je over_framing_error
inc FRAMING_ERRORS(esi)
over_framing_error:
testb al,#LS_OVERRUN_ERR
je over_overrun_error
inc OVERRUN_ERRORS(esi)
over_overrun_error:
testb al,#LS_PARITY_ERR
je over_parity_error
inc PARITY_ERRORS(esi)
over_parity_error:
testb al,#LS_BREAK_INTERRUPT
je over_break_interrupt
inc BREAK_INTERRUPTS(esi)
over_break_interrupt:
rsnext:
mov edx,INT_ID_PORT(esi)
in
cmpb al,#IS_NO_INTERRUPT
jne rsmore
rsdone:
movb al,#ENABLE
out INT_CTL
testb ah,#OWAKEUP
jne owakeup
movb OSTATE(esi),ah
pop edx
pop ebx
pop eax
pop esi
pop ds
iretd
| output interrupt
outint:
addb dl,#XMIT_OFFSET-INT_ID_OFFSET
outint1:
cmpb ah,#ODEVREADY+OQUEUED+OSWREADY
jb rsnext | not all are set
mov ebx,OPTR(esi)
movb al,(ebx)
out
inc ebx
mov OPTR(esi),ebx
cmp ebx,OBUFEND(esi)
jb rsnext
add _tty_events,#EVENT_THRESHOLD
xorb ah,#ODONE+OQUEUED+OWAKEUP | OQUEUED off, others on
j rsnext | direct exit might lose interrupt
| modem status change interrupt
modemint:
addb dl,#MODEM_STATUS_OFFSET-INT_ID_OFFSET
in
#if NO_HANDSHAKE
orb al,#MS_CTS
#endif
testb al,#MS_CTS
jne m_devready
andb ah,#notop(ODEVREADY)
j rsnext
m_devready:
testb ah,#ODEVREADY
jne rsnext
orb ah,#ODEVREADY
addb dl,#LINE_STATUS_OFFSET-MODEM_STATUS_OFFSET
in
testb al,#LS_TRANSMITTER_READY
je rsnext
addb dl,#XMIT_OFFSET-LINE_STATUS_OFFSET
j outint1
| special exit for output just completed
owakeup:
andb ah,#notop(OWAKEUP)
movb OSTATE(esi),ah
| determine mask bit (it would be better to precalculate it in the struct)
movb ah,#SECONDARY_MASK
cmp esi,#_rs_lines
jne got_rs_mask
movb ah,#RS232_MASK
got_rs_mask:
mov rs_mask,eax | save mask to clear later
in INT_CTLMASK
orb al,ah
out INT_CTLMASK
| rearrange context to call tty_wakeup()
pop edx
pop ebx
pop eax
pop esi
pop ds
call save
push rs_mask | save the mask again, reentrantly
sti
call _tty_wakeup
cli
pop eax
notb ah | return this
in INT_CTLMASK
andb al,ah
out INT_CTLMASK
ret
.data
rs_mask:
.space 2
.space 2 | align
#endif /* !C_RS232_INT_HANDLERS */