/*
 **************************************************************************
 *
 * Network driver interface for netboot bootrom
 *
 * Module:  basicio.S86
 * Purpose: Basic I/O functions for DOS simulator
 * Entries: dos01, dos02, dos03, dos04, dos05, dos06, dos07, dos08, dos09,
 *          dos0A, dos0B, dos0C
 *
 **************************************************************************
 *
 * Copyright (C) 1995-2007 Gero Kuhlmann <gero@gkminix.han.de>
 *
 *  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; either version 2 of the License, or
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * $Id: basicio.S86,v 1.5 2007/01/06 18:30:48 gkminix Exp $
 *
 */


/*
 **************************************************************************
 *
 * Include assembler macros:
 *
 */
#include <common.i86>
#include <romconfig.i86>
#include <i386/ctype.i86>
#include "dossim.i86"

.file __FILE__
.line __LINE__



/*
 **************************************************************************
 *
 * Definition of device codes, which are internal to the mini-DOS
 + simulator:
 *
 */
#define	DEV_CON		0		/* console */
#define	DEV_AUX		1		/* serial port */
#define	DEV_PRN		2		/* printer port */



/*
 **************************************************************************
 *
 * Miscalleneous equates
 *
 */
#define	AUX_INIT	0xA3		/* AUX port initialization value:
					 *  2400 Baud, no parity,
					 *  1 stop bit, 8 data bits
					 */



.line __LINE__
/*
 **************************************************************************
 *
 * BSS segment
 *
 */
	.bss

	.extern	dos1_regs
	.extern	dos2_regs

#ifdef NEEDEXTIO
	.lcomm	auxflag,1		# flag if serial port initialized
	.lcomm	prnflag,1		# flag if printer port initialized
#endif




/*
 **************************************************************************
 *
 * Start code segment.
 *
 */
	.text

	.global	dos01, dos02, dos03	# define entry points
	.global	dos04, dos05, dos06
	.global	dos07, dos08, dos09
	.global	dos0A, dos0B, dos0C



#if !defined(NEEDKBD) || !defined(NEEDEXTIO)
/*
 **************************************************************************
 *
 * Dummy routine for keyboard and extended I/O
 * Input:  none
 * Output: AL  -  dummy character value
 * Registers changed: AL
 *
 */
# ifndef NEEDKBD
dos0C:
dos0B:
dos08:
dos07:
dos01:
# endif

# ifndef NEEDEXTIO
dos03:
# endif

	xor	al,al

# ifndef NEEDEXTIO
dos05:
dos04:
# endif

	ret

#endif



#ifdef NEEDKBD
/*
 **************************************************************************
 *
 * Read character from keyboard and then send it to the screen
 * Input:  none
 * Output: AL  -  character
 * Registers changed: AL
 *
 */
dos08:
dos07:
dos01:
	push	bx
	mov	bh,ah			# save AH
	call	keywait			# wait for character from keyboard
	mov	bl,al
	cmp	bh,0x01			# only print character with fn 0x01
	jne	1f
	int	0x29			# print character
1:	mov	ax,bx			# restore AH
	pop	bx
	ret

#endif



/*
 **************************************************************************
 *
 * Print character onto screen
 * Input:  DL  -  character
 * Output: none
 * Registers changed: none
 *
 */
dos02:

	push	ax
	mov	al,dl
	int	0x29			# print character
	pop	ax
	ret



#ifdef NEEDEXTIO
/*
 **************************************************************************
 *
 * Receive character on serial port COM1
 * Input:  none
 * Output: AL  -  character
 * Registers changed: AL
 *
 */
dos03:

	push	bx
	mov	bh,ah
	mov	al,DEV_AUX
	call	devinit			# initialize serial device
	mov	ah,0x02
	int	INT_AUX			# receive character
	mov	ah,bh			# restore AH
	pop	bx
	ret

#endif



#ifdef NEEDEXTIO
/*
 **************************************************************************
 *
 * Send character to serial port COM1
 * Input:  DL  -  character
 * Output: none
 * Registers changed: none
 *
 */
dos04:

	push	ax
	mov	al,DEV_AUX
	call	devinit			# initialize serial device
	mov	al,dl
	mov	ah,0x01
	int	INT_AUX			# send character
	pop	ax
	ret

#endif



#ifdef NEEDEXTIO
/*
 **************************************************************************
 *
 * Send character to printer port
 * Input:  DL  -  character
 * Output: none
 * Registers changed: none
 *
 */
dos05:

	push	ax
	mov	al,DEV_PRN
	call	devinit			# initialize parallel port
	mov	al,dl
	xor	ah,ah
	int	INT_PRINT		# send character
	pop	ax
	ret

#endif



/*
 **************************************************************************
 *
 * Direct console I/O
 * Input:  DL  -  character for console output, or $FF for console input
 * Output: AL  -  character from console input, or 0 for console output
 * Changed registers: AL
 *
 */
dos06:

	xor	al,al
	cmp	dl,0xFF			# check for function
	jne	dos02			# print character

#ifdef NEEDKBD
	call	keycheck		# get character from keyboard
	jz	8f			# got no character
	xor	ah,ah
	int	INT_KBD			# get character from buffer
	or	dl,dl			# reset zero flag
	jmp	9f
8:	xor	al,al			# set return value 0
9:	mov	ah,0x06			# restore AH
#endif

	ret



/*
 **************************************************************************
 *
 * Print character string onto screen. String is terminated by '$' character.
 * Input:  DS:DX  -  pointer to string
 * Output: none
 * Registers changed: none
 *
 */
dos09:

	cld
	push	ax
	push	si
	push	ds
	mov	ds,old_ds[bp]		# get callers DS
	mov	si,dx
1:	lodsb				# get next character
	cmp	al,0x24			# end of string?
	je	2f
	int	0x29			# print character
	jmp	1b			# proceed with next character

2:	pop	ds
	pop	si
	pop	ax
	ret



/*
 **************************************************************************
 *
 * Read string from keyboard. The first character of the buffer contains
 * the buffer size, the next character will receive the actual number
 * of characters read.
 * Input:  DS:DX  -  pointer to buffer
 * Output: none
 * Registers changed: none
 *
 */
dos0A:

#if !defined(NEEDLINEIO) || !defined(NEEDKBD)

	push	bx
	mov	fs,old_ds[bp]
	mov	bx,dx			# simply mark the buffer as
	mov	byte ptr fs:[bx + 1],0	# empty
	pop	bx
	ret

#else

	push	ax
	push	bx
	push	di
	push	fs
	mov	fs,old_ds[bp]
	mov	di,dx
	xor	bx,bx			# BX - offset into buffer

1:	cmp	bl,fs:[di]		# end of buffer reached?
	jae	4f

	call	keywait			# get next character
	cmp	al,CHR_BS		# backspace?
	jne	2f
	or	bx,bx			# dont delete past beginning of
	jz	1b			# buffer
	dec	bx			# kill character in the buffer and
	jmp	5f			# on the screen

2:	cmp	al,CHR_CR		# carriage return?
	je	3f
	mov	fs:[bx + di + 2],al	# save character
	inc	bx
5:	int	0x29			# and print it
	jmp	1b

3:	int	0x29
	mov	al,CHR_LF		# print CR/LF
	int	0x29
4:	mov	fs:[di + 1],bl		# save length in the buffer
	pop	fs
	pop	di
	pop	bx
	pop	ax
	ret

#endif



#ifdef NEEDKBD
/*
 **************************************************************************
 *
 * Get keyboard status
 * Input:  none
 * Output: AL  -  $FF -> key pressed, $00 -> no key pressed
 * Changed registers: AL
 *
 */
dos0B:

	call	keycheck		# check BIOS keyboard buffer
	jz	9f			# no character in buffer
	mov	al,0xFF			# yes, we have a character available
9:	mov	ah,0x0B			# restore AH
	ret

#endif



#ifdef NEEDKBD
/*
 **************************************************************************
 *
 * Clear input buffer and then call input routine.
 * Input:  AL  -  input function number
 * Output: AL  -  input character
 * Registers changed: depending on input function
 *
 */
dos0C:

	push	ax
1:	mov	ah,0x01			# get keyboard status (dont use
	int	INT_KBD			# keycheck here - not necessary)
	jz	2f			# no more characters in buffer
	xor	ah,ah
	int	INT_KBD			# get character from input buffer
	jmp	1b			# repeat until buffer empty

2:	pop	ax
	mov	ah,al
	cmp	al,0x06
	je	dos06			# call DOS function 06
	cmp	al,0x0A
	je	dos0A			# call DOS function 0A
	cmp	al,0x01
	je	dos01			# call DOS function 01
	cmp	al,0x07
	je	dos07			# call DOS function 07
	cmp	al,0x08
	je	dos08			# call DOS function 08
	ret

#endif



#ifdef NEEDKBD
/*
 **************************************************************************
 *
 * Check BIOS for a key press
 * Input:  none
 * Output: AL  -  character
 *         Zero flag reset if character found in buffer
 * Registers changed: AX
 *
 */
keycheck:

	cmp	bp,offset dos1_regs
	jne	1f
	int	0x28			# care for "multitasking" interrupt
1:	mov	ah,0x01
	int	INT_KBD			# check BIOS keyboard buffer
	jnz	9f			# found character in buffer
	xor	al,al			# no character found in buffer
9:	ret

#endif



#ifdef NEEDKBD
/*
 **************************************************************************
 *
 * Wait for a key press
 * Input:  none
 * Output: AL  -  character
 * Registers changed: AX
 *
 */
keywait:

1:	call	keycheck		# wait for key to be pressed
	jz	1b
	xor	ah,ah
	int	INT_KBD			# get character from keyboard
	ret

#endif



#ifdef NEEDEXTIO
/*
 **************************************************************************
 *
 * Initialize a device.
 * Input:  AL  -  device type (CON, AUX, PRN)
 * Output: none
 * Registers changed: AX
 *
 */
devinit:

	push	dx
	mov	ah,1			# default device flag
	xor	dx,dx			# default device number

/*
 * Initialize serial port
 */

	cmp	al,DEV_AUX
	jne	2f
	xchg	ah,[auxflag]		# already initialized?
	or	ah,ah
	jnz	9f
	mov	ax,AUX_INIT
	int	INT_AUX			# initialize serial port
	jmp	9f

/*
 * Initialize parallel port
 */

2:	cmp	al,DEV_PRN
	jne	9f
	xchg	ah,[prnflag]		# already initialized?
	or	ah,ah
	jnz	9f
	mov	ah,0x01
	int	INT_PRINT		# initialize printer port

9:	pop	dx
	ret

#endif




/*
 **************************************************************************
 *
 */

	.end

