mirror of
https://github.com/stevenhowes/wbios.git
synced 2026-05-26 15:53:34 +01:00
d410ad0acb
Original source https://www.pcengines.ch/file/wbios111s.zip
329 lines
7.1 KiB
Plaintext
329 lines
7.1 KiB
Plaintext
;
|
|
; Serial BIOS
|
|
;
|
|
; (C)1997-2001 Pascal Dornier / PC Engines; All rights reserved.
|
|
; This file is licensed pursuant to the COMMON PUBLIC LICENSE 0.5.
|
|
;
|
|
; pd 050417 enable outside override for con_init
|
|
; pd 010207 integrate serial console support here
|
|
; pd 991127 fix m_devflg
|
|
;
|
|
; Serial console notes:
|
|
;
|
|
; Variable CONSOLE must be equal to the I/O port of the COM port used.
|
|
; Define CONINT=3 or CONINT=4 to select the serial port interrupt.
|
|
; VGA BIOS will take over Int 10, and inhibit serial console output.
|
|
|
|
#if ! def COM_INIT ;default value:
|
|
COM_INIT equ 11100011xb ;9600 8N1 serial port initialization
|
|
#endif
|
|
;
|
|
; INT 14 entry
|
|
;
|
|
int14: sti ;reenable interrupts
|
|
push ds ;save registers
|
|
push si
|
|
push dx
|
|
push cx
|
|
push bx
|
|
mov bx,ax ;save AX
|
|
xor ax,ax ;access BIOS segment
|
|
mov ds,ax
|
|
cmp dx,4 ;max port ?
|
|
jae rs_exit ;:return
|
|
mov si,dx ;-> table index
|
|
mov cl,[si.m_rstime] ;get time-out value
|
|
shl si,1
|
|
mov dx,[si.m_rsio] ;get I/O port base
|
|
and dx,dx ;0 -> not present
|
|
jz rs_exit
|
|
mov al,bh ;get command code
|
|
and al,al
|
|
jz rs_init ;AH=0 -> initialize
|
|
dec ax
|
|
jz rs_xmit ;AH=1 -> transmit
|
|
dec ax
|
|
jz rs_recv ;AH=2 -> receive
|
|
dec ax
|
|
jz rs_stat ;AH=3 -> get status
|
|
rs_exit: pop bx ;restore registers
|
|
pop cx
|
|
pop dx
|
|
pop si
|
|
pop ds
|
|
iret
|
|
;
|
|
; AH=0: initialize serial port
|
|
;
|
|
rs_init: mov al,bl ;AH=0; get baud rate
|
|
shr al,4 ;-> table index
|
|
and al,1110b
|
|
#if def CONSOLE
|
|
cmp dx,CONSOLE ;console ?
|
|
jz rs_stat ;if yes, don't let DOS change the
|
|
;parameters
|
|
#endif
|
|
#if def COM_NO2400 ;lock out DOS 2400 baud setting...
|
|
cmp al,10 ;2400 baud ?
|
|
jz rs_stat ;yes - don't do it
|
|
#endif
|
|
mov si,ax
|
|
add dl,3
|
|
mov al,80h ;base+3 DLAB=1: access baud rate register
|
|
out dx,al
|
|
dec dx
|
|
dec dx
|
|
mov ax,word [cs:si+rs_baud] ;get baudrate
|
|
out dx,al ;base+1 baudrate MSB
|
|
mov al,ah
|
|
dec dx
|
|
out dx,al ;base+0 baudrate LSB
|
|
add dl,3
|
|
mov al,bl
|
|
and al,1fh ;set parameters
|
|
out dx,al ;base+3
|
|
dec dx
|
|
dec dx
|
|
#if def CONSOLE ;don't disable interrupt on console
|
|
in al,dx ;base+1
|
|
and al,1
|
|
cmp dx,CONSOLE+1
|
|
jz rs_init1
|
|
#endif
|
|
mov al,0 ;disable interrupts
|
|
rs_init1: out dx,al ;base+1
|
|
dec dx ;base+0
|
|
;
|
|
; AH=3: get status
|
|
;
|
|
rs_stat: add dl,5
|
|
in al,dx
|
|
mov ah,al
|
|
inc dx
|
|
in al,dx
|
|
jmp rs_exit
|
|
;
|
|
; AH=1: transmit character
|
|
;
|
|
rs_xmit: mov al,3 ;modem control: set DTR, RTS
|
|
add dl,4
|
|
out dx,al
|
|
inc dx ;modem status: wait for DSR, CTS
|
|
inc dx
|
|
mov bh,30h
|
|
call rs_wait
|
|
jnz rs_xmtime ;:time-out
|
|
dec dx
|
|
mov bh,20h ;line status: wait for xmit ready
|
|
call rs_wait
|
|
jnz rs_xmtime
|
|
sub dl,5
|
|
mov al,bl ;character to send
|
|
out dx,al ;send it
|
|
jmp rs_exit
|
|
;
|
|
; time-out error
|
|
;
|
|
rs_xmtime: mov al,bl ;restore character
|
|
rs_rxtime: or ah,80h ;set time-out flag
|
|
jmp rs_exit
|
|
;
|
|
; AH=2: receive character
|
|
;
|
|
rs_recv: mov al,1 ;modem control: set DTR
|
|
add dl,4
|
|
out dx,al
|
|
inc dx ;modem status: wait for DSR
|
|
inc dx
|
|
mov bh,20h
|
|
call rs_wait
|
|
jnz rs_rxtime ;:time-out
|
|
dec dx
|
|
mov bh,1 ;line status: wait for receive data
|
|
call rs_wait
|
|
jnz rs_rxtime ;:time-out
|
|
and ah,1eh ;mask status
|
|
and dl,0f8h ;receive register
|
|
in al,dx ;read character
|
|
jmp rs_exit ;exit
|
|
;
|
|
; serial port wait
|
|
;
|
|
rs_wait: mov ch,cl ;copy time-out value
|
|
xor si,si ;clear counter
|
|
rs_wait2: in al,dx
|
|
mov ah,al ;save status
|
|
and al,bh ;check status
|
|
cmp al,bh ;set ?
|
|
jz rs_wait9 ;:yes
|
|
dec si
|
|
jnz rs_wait2 ;:try again
|
|
dec ch
|
|
jnz rs_wait2
|
|
or bh,bh ;time-out
|
|
rs_wait9: ret
|
|
;
|
|
; test & initialize serial ports
|
|
;
|
|
rs_test: mov ax,0101h ;init serial port time-out
|
|
mov [m_rstime],ax
|
|
mov [m_rstime+2],ax
|
|
|
|
mov di,m_rsio ;destination for I/O port value
|
|
mov si,offset rs_ports ;port addresses
|
|
rs_test1: lods word [cs:si] ;get port address
|
|
and ax,ax ;end of table ?
|
|
jz rs_test3 ;:end
|
|
xchg dx,ax ;AX -> DX, points to scratch register
|
|
mov ax,0aa55h
|
|
out dx,al
|
|
out iowait,ax ;invert bus
|
|
out iowait,ax
|
|
in al,dx
|
|
cmp al,55h ;pattern ok ?
|
|
jnz rs_test1 ;:no, port not present, try next
|
|
and dl,0f8h ;clear low bits of I/O address
|
|
mov [di],dx ;write port address
|
|
inc di
|
|
inc di
|
|
add byte ptr [m_devflg+1],2 ;increment serial port count
|
|
cmp di,m_rsio+8 ;space for more ports ?
|
|
jnz rs_test1 ;:yes
|
|
rs_test3: mov dx,3 ;init serial ports
|
|
rs_test4: mov ax,COM_INIT
|
|
int 14h
|
|
dec dx
|
|
jns rs_test4
|
|
ret
|
|
;
|
|
; serial port console
|
|
;
|
|
#if def CONSOLE
|
|
#if ! def con_init
|
|
|
|
con_init: mov byte [m_conkey],0 ;clear key buffer
|
|
mov byte [m_console],0 ;disable serial console
|
|
|
|
; hook serial interrupt
|
|
|
|
#if def CONINT
|
|
cli ;set INT 3 vector = COM2
|
|
xor ax,ax
|
|
mov ds,ax
|
|
#if CONINT = 3
|
|
mov word [11*4],con_int
|
|
mov word [11*4+2],cs
|
|
#endif
|
|
#if CONINT = 4
|
|
mov word [12*4],con_int
|
|
mov word [12*4+2],cs
|
|
#endif
|
|
#if CONINT = 5
|
|
mov word [13*4],con_int
|
|
mov word [13*4+2],cs
|
|
#endif
|
|
sti
|
|
|
|
mov dx,CONSOLE
|
|
in al,dx ;clear receive buffer
|
|
out iowait,ax
|
|
mov dl,low(CONSOLE+1)
|
|
mov al,1 ;enable receive interrupt
|
|
out dx,al
|
|
out iowait,ax
|
|
mov dl,low(CONSOLE+4) ;enable interrupt driver
|
|
in al,dx
|
|
or al,8
|
|
out dx,al
|
|
|
|
in al,pic0+1 ;enable serial interrupt (int 3)
|
|
#if CONINT = 3
|
|
and al,0f7
|
|
#endif
|
|
#if CONINT = 4
|
|
and al,0ef
|
|
#endif
|
|
#if CONINT = 5
|
|
and al,0df
|
|
#endif
|
|
out iowait,ax
|
|
out pic0+1,al
|
|
#endif
|
|
mov byte [m_conkey],0 ;clear key buffer
|
|
mov byte [m_console],1 ;set serial console flag
|
|
ret
|
|
#endif ; con_init
|
|
|
|
;
|
|
; serial interrupt handler for serial console
|
|
;
|
|
con_int: pusha
|
|
push ds
|
|
xor ax,ax
|
|
mov ds,ax
|
|
|
|
mov dx,CONSOLE ;read data
|
|
in al,dx
|
|
test byte [m_console],1 ;serial console enabled ?
|
|
jz con_int49 ;:no, ignore
|
|
|
|
; we need to handle Esc xx and Esc Esc sequences to emulate
|
|
; function / cursor keys
|
|
|
|
xor ah,ah ;clear high part of scan code
|
|
cmp al,27 ;escape ?
|
|
jz con_int41
|
|
cmp byte [m_conkey],1 ;Esc previous character ?
|
|
jb con_int48 ;0: take this key
|
|
jz con_int43 ;store key, need another for sequence
|
|
mov ah,al ;current key -> AH
|
|
mov al,[m_conkey] ;previous key -> AL
|
|
mov si,offset ansitab
|
|
mov cx,(ansitab9-ansitab) / 4
|
|
con_int44: cmp ax,[cs:si] ;compare with sequence
|
|
jz con_int45
|
|
lea si,[si+4] ;skip to next
|
|
loop con_int44 ;try next
|
|
jmp short con_int47 ;not found - skip
|
|
|
|
con_int45: mov ax,[cs:si+2] ;get scan code from table
|
|
con_int48: call putbuf ;place in keyboard buffer
|
|
con_int47: mov byte [m_conkey],0 ;clear key buffer
|
|
|
|
con_int49: mov al,eoi ;end of interrupt
|
|
out pic0,al
|
|
pop ds
|
|
popa
|
|
iret
|
|
|
|
; handle escape
|
|
|
|
con_int41: cmp byte [m_conkey],1 ;Esc previous key ?
|
|
jz con_int48 ;yes: enter escape
|
|
mov byte [m_conkey],1 ;set escape flag
|
|
jmp con_int49
|
|
|
|
con_int43: mov byte [m_conkey],al ;store key
|
|
jmp con_int49 ;skip
|
|
;
|
|
; ANSI to scan code translation table
|
|
;
|
|
even
|
|
ansitab: db "OP",000,03b ;F1
|
|
db "OQ",000,03c ;F2
|
|
db "Ow",000,03d ;F3
|
|
db "Ox",000,03e ;F4
|
|
db "Ot",000,03f ;F5
|
|
db "Ou",000,040 ;F6
|
|
db "Oq",000,041 ;F7
|
|
db "Or",000,042 ;F8
|
|
db "Op",000,043 ;F9 (F10 gives same)
|
|
db "[A",000,048 ;cursor up
|
|
db "[B",000,050 ;cursor down
|
|
db "[D",000,04b ;cursor left
|
|
db "[C",000,04d ;cursor right
|
|
db "[H",000,047 ;home
|
|
db "[K",000,04f ;end
|
|
ansitab9:
|
|
#endif ;CONSOLE
|