411 lines
10 KiB
PHP
411 lines
10 KiB
PHP
;; $Id: conio.inc,v 1.13 2005/06/16 04:39:19 hpa Exp $
|
|
;; -----------------------------------------------------------------------
|
|
;;
|
|
;; Copyright 1994-2005 H. Peter Anvin - All Rights Reserved
|
|
;;
|
|
;; This program is free software; you can redistribute it and/or modify
|
|
;; it under the terms of the GNU General Public License as published by
|
|
;; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
|
|
;; Boston MA 02111-1307, USA; either version 2 of the License, or
|
|
;; (at your option) any later version; incorporated herein by reference.
|
|
;;
|
|
;; -----------------------------------------------------------------------
|
|
|
|
;;
|
|
;; conio.inc
|
|
;;
|
|
;; Console I/O code, except:
|
|
;; writechr, writestr - module-dependent
|
|
;; cwritestr, crlf - writestr.inc
|
|
;; writehex* - writehex.inc
|
|
;;
|
|
|
|
;
|
|
; loadkeys: Load a LILO-style keymap; SI and DX:AX set by searchdir
|
|
;
|
|
section .text
|
|
|
|
loadkeys:
|
|
and dx,dx ; Should be 256 bytes exactly
|
|
jne loadkeys_ret
|
|
cmp ax,256
|
|
jne loadkeys_ret
|
|
|
|
mov bx,trackbuf
|
|
mov cx,1 ; 1 cluster should be >= 256 bytes
|
|
call getfssec
|
|
|
|
mov si,trackbuf
|
|
mov di,KbdMap
|
|
mov cx,256 >> 2
|
|
rep movsd
|
|
|
|
loadkeys_ret: ret
|
|
|
|
;
|
|
; get_msg_file: Load a text file and write its contents to the screen,
|
|
; interpreting color codes. Is called with SI and DX:AX
|
|
; set by routine searchdir
|
|
;
|
|
get_msg_file:
|
|
push es
|
|
shl edx,16 ; EDX <- DX:AX (length of file)
|
|
mov dx,ax
|
|
mov ax,xfer_buf_seg ; Use for temporary storage
|
|
mov es,ax
|
|
|
|
mov byte [TextAttribute],07h ; Default grey on white
|
|
mov byte [DisplayMask],07h ; Display text in all modes
|
|
call msg_initvars
|
|
|
|
get_msg_chunk: push edx ; EDX = length of file
|
|
xor bx,bx ; == xbs_textbuf
|
|
mov cx,[BufSafe]
|
|
call getfssec
|
|
pop edx
|
|
push si ; Save current cluster
|
|
xor si,si ; == xbs_textbuf
|
|
mov cx,[BufSafeBytes] ; Number of bytes left in chunk
|
|
print_msg_file:
|
|
push cx
|
|
push edx
|
|
es lodsb
|
|
cmp al,1Ah ; DOS EOF?
|
|
je msg_done_pop
|
|
push si
|
|
mov cl,[UsingVGA]
|
|
inc cl ; 01h = text mode, 02h = graphics
|
|
call [NextCharJump] ; Do what shall be done
|
|
pop si
|
|
pop edx
|
|
pop cx
|
|
dec edx
|
|
jz msg_done
|
|
loop print_msg_file
|
|
pop si
|
|
jmp short get_msg_chunk
|
|
msg_done_pop:
|
|
add sp,byte 6 ; Drop pushed EDX, CX
|
|
msg_done:
|
|
pop si
|
|
pop es
|
|
ret
|
|
msg_putchar: ; Normal character
|
|
cmp al,0Fh ; ^O = color code follows
|
|
je msg_ctrl_o
|
|
cmp al,0Dh ; Ignore <CR>
|
|
je msg_ignore
|
|
cmp al,0Ah ; <LF> = newline
|
|
je msg_newline
|
|
cmp al,0Ch ; <FF> = clear screen
|
|
je msg_formfeed
|
|
cmp al,07h ; <BEL> = beep
|
|
je msg_beep
|
|
cmp al,19h ; <EM> = return to text mode
|
|
je msg_novga
|
|
cmp al,18h ; <CAN> = VGA filename follows
|
|
je msg_vga
|
|
jnb .not_modectl
|
|
cmp al,10h ; 10h to 17h are mode controls
|
|
jae msg_modectl
|
|
.not_modectl:
|
|
|
|
msg_normal: call write_serial_displaymask ; Write to serial port
|
|
test [DisplayMask],cl
|
|
jz msg_ignore ; Not screen
|
|
test byte [DisplayCon],01h
|
|
jz msg_ignore
|
|
mov bl,[TextAttribute]
|
|
mov bh,[BIOS_page]
|
|
mov ah,09h ; Write character/attribute
|
|
mov cx,1 ; One character only
|
|
int 10h ; Write to screen
|
|
mov al,[CursorCol]
|
|
inc ax
|
|
cmp al,[VidCols]
|
|
ja msg_line_wrap ; Screen wraparound
|
|
mov [CursorCol],al
|
|
|
|
msg_gotoxy: mov bh,[BIOS_page]
|
|
mov dx,[CursorDX]
|
|
mov ah,02h ; Set cursor position
|
|
int 10h
|
|
msg_ignore: ret
|
|
|
|
msg_beep: mov ax,0E07h ; Beep
|
|
xor bx,bx
|
|
int 10h
|
|
ret
|
|
|
|
msg_ctrl_o: ; ^O = color code follows
|
|
mov word [NextCharJump],msg_setbg
|
|
ret
|
|
msg_newline: ; Newline char or end of line
|
|
mov si,crlf_msg
|
|
call write_serial_str_displaymask
|
|
msg_line_wrap: ; Screen wraparound
|
|
test [DisplayMask],cl
|
|
jz msg_ignore
|
|
mov byte [CursorCol],0
|
|
mov al,[CursorRow]
|
|
inc ax
|
|
cmp al,[VidRows]
|
|
ja msg_scroll
|
|
mov [CursorRow],al
|
|
jmp short msg_gotoxy
|
|
msg_scroll: xor cx,cx ; Upper left hand corner
|
|
mov dx,[ScreenSize]
|
|
mov [CursorRow],dh ; New cursor at the bottom
|
|
mov bh,[ScrollAttribute]
|
|
mov ax,0601h ; Scroll up one line
|
|
int 10h
|
|
jmp short msg_gotoxy
|
|
msg_formfeed: ; Form feed character
|
|
mov si,crff_msg
|
|
call write_serial_str_displaymask
|
|
test [DisplayMask],cl
|
|
jz msg_ignore
|
|
xor cx,cx
|
|
mov [CursorDX],cx ; Upper lefthand corner
|
|
mov dx,[ScreenSize]
|
|
mov bh,[TextAttribute]
|
|
mov ax,0600h ; Clear screen region
|
|
int 10h
|
|
jmp msg_gotoxy
|
|
msg_setbg: ; Color background character
|
|
call unhexchar
|
|
jc msg_color_bad
|
|
shl al,4
|
|
test [DisplayMask],cl
|
|
jz .dontset
|
|
mov [TextAttribute],al
|
|
.dontset:
|
|
mov word [NextCharJump],msg_setfg
|
|
ret
|
|
msg_setfg: ; Color foreground character
|
|
call unhexchar
|
|
jc msg_color_bad
|
|
test [DisplayMask],cl
|
|
jz .dontset
|
|
or [TextAttribute],al ; setbg set foreground to 0
|
|
.dontset:
|
|
jmp short msg_putcharnext
|
|
msg_vga:
|
|
mov word [NextCharJump],msg_filename
|
|
mov di, VGAFileBuf
|
|
jmp short msg_setvgafileptr
|
|
|
|
msg_color_bad:
|
|
mov byte [TextAttribute],07h ; Default attribute
|
|
msg_putcharnext:
|
|
mov word [NextCharJump],msg_putchar
|
|
ret
|
|
|
|
msg_filename: ; Getting VGA filename
|
|
cmp al,0Ah ; <LF> = end of filename
|
|
je msg_viewimage
|
|
cmp al,' '
|
|
jbe msg_ret ; Ignore space/control char
|
|
mov di,[VGAFilePtr]
|
|
cmp di,VGAFileBufEnd
|
|
jnb msg_ret
|
|
mov [di],al ; Can't use stosb (DS:)
|
|
inc di
|
|
msg_setvgafileptr:
|
|
mov [VGAFilePtr],di
|
|
msg_ret: ret
|
|
|
|
msg_novga:
|
|
call vgaclearmode
|
|
jmp short msg_initvars
|
|
|
|
msg_viewimage:
|
|
push es
|
|
push ds
|
|
pop es ; ES <- DS
|
|
mov si,VGAFileBuf
|
|
mov di,VGAFileMBuf
|
|
push di
|
|
call mangle_name
|
|
pop di
|
|
call searchdir
|
|
pop es
|
|
jz msg_putcharnext ; Not there
|
|
call vgadisplayfile
|
|
; Fall through
|
|
|
|
; Subroutine to initialize variables, also needed
|
|
; after loading a graphics file
|
|
msg_initvars:
|
|
pusha
|
|
mov bh,[BIOS_page]
|
|
mov ah,03h ; Read cursor position
|
|
int 10h
|
|
mov [CursorDX],dx
|
|
popa
|
|
jmp short msg_putcharnext ; Initialize state machine
|
|
|
|
msg_modectl:
|
|
and al,07h
|
|
mov [DisplayMask],al
|
|
jmp short msg_putcharnext
|
|
|
|
;
|
|
; write_serial: If serial output is enabled, write character on serial port
|
|
; write_serial_displaymask: d:o, but ignore if DisplayMask & 04h == 0
|
|
;
|
|
write_serial_displaymask:
|
|
test byte [DisplayMask], 04h
|
|
jz write_serial.end
|
|
write_serial:
|
|
pushfd
|
|
pushad
|
|
mov bx,[SerialPort]
|
|
and bx,bx
|
|
je .noserial
|
|
push ax
|
|
mov ah,[FlowInput]
|
|
.waitspace:
|
|
; Wait for space in transmit register
|
|
lea dx,[bx+5] ; DX -> LSR
|
|
in al,dx
|
|
test al,20h
|
|
jz .waitspace
|
|
|
|
; Wait for input flow control
|
|
inc dx ; DX -> MSR
|
|
in al,dx
|
|
and al,ah
|
|
cmp al,ah
|
|
jne .waitspace
|
|
.no_flow:
|
|
|
|
xchg dx,bx ; DX -> THR
|
|
pop ax
|
|
call slow_out ; Send data
|
|
.noserial: popad
|
|
popfd
|
|
.end: ret
|
|
|
|
;
|
|
; write_serial_str: write_serial for strings
|
|
; write_serial_str_displaymask: d:o, but ignore if DisplayMask & 04h == 0
|
|
;
|
|
write_serial_str_displaymask:
|
|
test byte [DisplayMask], 04h
|
|
jz write_serial_str.end
|
|
|
|
write_serial_str:
|
|
.loop lodsb
|
|
and al,al
|
|
jz .end
|
|
call write_serial
|
|
jmp short .loop
|
|
.end: ret
|
|
|
|
;
|
|
; pollchar: check if we have an input character pending (ZF = 0)
|
|
;
|
|
pollchar:
|
|
pushad
|
|
mov ah,11h ; Poll keyboard
|
|
int 16h
|
|
jnz .done ; Keyboard response
|
|
mov dx,[SerialPort]
|
|
and dx,dx
|
|
jz .done ; No serial port -> no input
|
|
add dx,byte 5 ; DX -> LSR
|
|
in al,dx
|
|
test al,1 ; ZF = 0 if data pending
|
|
jz .done
|
|
inc dx ; DX -> MSR
|
|
mov ah,[FlowIgnore] ; Required status bits
|
|
in al,dx
|
|
and al,ah
|
|
cmp al,ah
|
|
setne al
|
|
dec al ; Set ZF = 0 if equal
|
|
.done: popad
|
|
ret
|
|
|
|
;
|
|
; getchar: Read a character from keyboard or serial port
|
|
;
|
|
getchar:
|
|
RESET_IDLE
|
|
.again:
|
|
DO_IDLE
|
|
mov ah,11h ; Poll keyboard
|
|
int 16h
|
|
jnz .kbd ; Keyboard input?
|
|
mov bx,[SerialPort]
|
|
and bx,bx
|
|
jz .again
|
|
lea dx,[bx+5] ; DX -> LSR
|
|
in al,dx
|
|
test al,1
|
|
jz .again
|
|
inc dx ; DX -> MSR
|
|
mov ah,[FlowIgnore]
|
|
in al,dx
|
|
and al,ah
|
|
cmp al,ah
|
|
jne .again
|
|
.serial: xor ah,ah ; Avoid confusion
|
|
xchg dx,bx ; Data port
|
|
in al,dx
|
|
ret
|
|
.kbd: mov ah,10h ; Get keyboard input
|
|
int 16h
|
|
cmp al,0E0h
|
|
jnz .not_ext
|
|
xor al,al
|
|
.not_ext:
|
|
and al,al
|
|
jz .func_key
|
|
mov bx,KbdMap ; Convert character sets
|
|
xlatb
|
|
.func_key: ret
|
|
|
|
%ifdef DEBUG_TRACERS
|
|
;
|
|
; debug hack to print a character with minimal code impact
|
|
;
|
|
debug_tracer: pushad
|
|
pushfd
|
|
mov bp,sp
|
|
mov bx,[bp+9*4] ; Get return address
|
|
mov al,[cs:bx] ; Get data byte
|
|
inc word [bp+9*4] ; Return to after data byte
|
|
call writechr
|
|
popfd
|
|
popad
|
|
ret
|
|
%endif ; DEBUG_TRACERS
|
|
|
|
section .data
|
|
; This is a word to pc_setint16 can set it
|
|
DisplayCon dw 01h ; Console display enabled
|
|
|
|
ScrollAttribute db 07h ; Grey on white (normal text color)
|
|
|
|
section .bss
|
|
alignb 2
|
|
NextCharJump resw 1 ; Routine to interpret next print char
|
|
CursorDX equ $
|
|
CursorCol resb 1 ; Cursor column for message file
|
|
CursorRow resb 1 ; Cursor row for message file
|
|
ScreenSize equ $
|
|
VidCols resb 1 ; Columns on screen-1
|
|
VidRows resb 1 ; Rows on screen-1
|
|
|
|
; Serial console stuff...
|
|
BaudDivisor resw 1 ; Baud rate divisor
|
|
FlowControl equ $
|
|
FlowOutput resb 1 ; Outputs to assert for serial flow
|
|
FlowInput resb 1 ; Input bits for serial flow
|
|
FlowIgnore resb 1 ; Ignore input unless these bits set
|
|
|
|
TextAttribute resb 1 ; Text attribute for message file
|
|
DisplayMask resb 1 ; Display modes mask
|