/*
 **************************************************************************
 *
 * Network driver interface for netboot bootrom
 *
 * Module:  fileio.S86
 * Purpose: File I/O functions for DOS simulator
 * Entries: dos3C, dos3D, dos3E, dos3F, dos40, dos44
 *
 **************************************************************************
 *
 * 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: fileio.S86,v 1.6 2007/01/06 18:30:48 gkminix Exp $
 *
 */


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

.file __FILE__
.line __LINE__



/*
 **************************************************************************
 *
 * BSS segment
 *
 */
	.bss

	.extern	curr_psp		# segment of current PSP




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

	.extern	dos02
	.extern	dos03
	.extern	dos04
	.extern	dos05
	.extern	dos07

	.global	dos3C
	.global	dos3D
	.global	dos3E			# define entry points
	.global	dos3F
	.global	dos40
	.global	dos44



/*
 **************************************************************************
 *
 * Create a new file. Since its not possible to create a new file with
 * the DOS simulator, this just returns an error.
 * Input:  CX     -  file attribute
 *         DS:DX  -  pointer to file name
 * Output: AX     -  file handle or error code if carry flag set
 *         Carry flag  -  set if error
 * Registers changed: AX
 *
 */
dos3C:

	mov	ax,DOS_ERR_NODIR	# return with error
	stc
	ret



/*
 **************************************************************************
 *
 * Open file. Since the DOS simulator cannot use files, just return with
 * an error.
 * Input:  DS:DX  -  pointer to file name
 * Output: AX     -  file handle or error code if carry flag set
 *         Carry flag  -  set if error
 * Registers changed: AX
 *
 */
dos3D:

	mov	ax,DOS_ERR_NOFILE	# return with error
	stc
	ret



/*
 **************************************************************************
 *
 * Close file. This just clears the file handle in the PSP. If no file IO
 * is enabled this is just a NOP.
 * Input:  BX  -  file handle
 * Output: AX  -  error code if carry flag set
 *         Carry flag  -  set if error
 * Registers changed: AX
 *
 */
dos3E:

#ifdef NEEDFILEIO

	call	chkhndl				# check file handle
	jc	9f
	mov	fs,[curr_psp]
	mov	byte ptr fs:psp_handles[bx],0	# reset handle

#else

	clc

#endif

9:	ret



/*
 **************************************************************************
 *
 * Read file.
 * Input:  BX     -  file handle
 *         CX     -  number of bytes to read
 *         DS:DX  -  pointer to read buffer
 * Output: AX     -  number of bytes read, or error code if carry flag set
 *         Carry flag  -  set if error
 * Registers changed: AX
 *
 */
dos3F:

#ifdef NEEDFILEIO

	push	fs
	push	es
	push	di
	call	chkhndl			# check file handle
	jc	9f

/*
 * Read the data from the device into the buffer.
 */

# if defined(NEEDKBD) || defined(NEEDEXTIO)

	mov	di,dx
	mov	es,old_ds[bp]
3:
#  if defined(NEEDKBD) && !defined(NEEDEXTIO)
	call	dos07			# read character from keyboard
#  else
	call	readchar		# read character from device
#  endif

/*
 * Handle end-of-line or end-of-file.
 */

4:	cmp	al,CHR_CR		# end of line?
	je	5f
	cmp	al,CHR_LF
	je	5f
	cmp	al,CHR_EOF		# or end of file?
	jne	6f
5:	mov	al,CHR_CR
#  ifdef NEEDEXTIO
	call	writechar		# return to a new line on the screen
#  else
	int	0x29
#  endif
	mov	al,CHR_LF
#  ifdef NEEDEXTIO
	call	writechar
#  else
	int	0x29
#  endif
	mov	ax,di
	sub	ax,dx			# compute actual length of input buffer
	clc
	jmp	9f

/*
 * Handle backspace character
 */

6:	cmp	al,CHR_BS
	jne	7f
	cmp	dx,di			# already at beginning of line
	je	3b
	dec	di
#  ifdef NEEDEXTIO
	call	writechar		# print backspace onto the screen
#  else
	int	0x29
#  endif
	jmp	3b

/*
 * Add character to the end of the line
 */

7:	cmp	al,0x20			# only care for printable characters
	jb	3b
	push	ax
	mov	ax,cx
	add	ax,dx			# check if end of buffer reached
	cmp	ax,di
	pop	ax
	jae	5b
	stosb				# save character into buffer
#  ifdef NEEDEXTIO
	call	writechar		# print character
#  else
	int	0x29
#  endif
	jmp	3b

# else

	xor	ax,ax			# if no keyboard or aux I/O, return 0

# endif

9:	pop	di
	pop	es
	pop	fs

#else

	xor	ax,ax			# if no FILEIO, read just 0 bytes

#endif

	ret



/*
 **************************************************************************
 *
 * Write to file.
 * Input:  BX     -  file handle
 *         CX     -  buffer size
 *         DS:DX  -  output buffer
 * Output: AX     -  number of characters written, or error code if carry set
 *         Carry flag  -  set if error
 * Registers changed: AX
 *
 */
dos40:

#ifdef NEEDFILEIO

	push	fs
	push	si
	call	chkhndl			# check file handle
	jc	9f

/*
 * Write all characters onto the output device
 */

	mov	si,dx
	mov	fs,old_ds[bp]
2:	mov	ax,dx
	add	ax,cx			# check if at end of buffer
	cmp	si,ax
	jae	3f
	lodsb	fs:[si]
# ifdef NEEDEXTIO
	call	writechar		# print character
# else
	int	0x29
# endif
	jmp	2b

3:	mov	ax,si
	sub	ax,dx			# compute number of bytes written
	clc
9:	pop	si
	pop	fs

#else

	mov	ax,cx			# if no FILEIO, wrote all bytes
	clc

#endif

	ret



/*
 **************************************************************************
 *
 * Handle IOCTL request for file.
 * Input:  BX     -  file handle
 * Output: AX     -  error code if carry set
 *         Carry flag  -  set if error
 * Registers changed: AX
 *
 */
dos44:

	mov	ax,DOS_ERR_INVHDL	# return with error
	stc
	ret



#if defined(NEEDFILEIO) && defined(NEEDEXTIO)
/*
 **************************************************************************
 *
 * Read character from device.
 * Input:  BX  -  file handle
 * Output: AL  -  character
 * Registers changed: AX
 *
 */
readchar:

# ifdef NEEDKBD
	cmp	bx,DOS_RES_STDERR	# check for keyboard input
	jbe	dos07			# read character from keyboard
# endif

	cmp	bx,DOS_RES_AUX		# check for serial device
	je	dos03			# receive character

	mov	al,CHR_EOF		# nothing more to read
	ret

#endif



#if defined(NEEDFILEIO) && defined(NEEDEXTIO)
/*
 **************************************************************************
 *
 * Write character to device.
 * Input:  BX  -  file handle
 *         AL  -  character to write
 * Output: none
 * Registers changed: none
 *
 */
writechar:

	push	dx
	cmp	bx,DOS_RES_STDERR	# check for console output
	ja	1f
	int	0x29			# print character
	jmp	9f

1:	mov	dl,al
	cmp	bx,DOS_RES_AUX		# check for serial device
	jne	2f
	call	dos04			# send character
	jmp	9f

2:	cmp	bx,DOS_RES_PRN		# check for printer device
	jne	9f
	call	dos05			# send character

9:	pop	dx
	ret

#endif



#ifdef NEEDFILEIO
/*
 **************************************************************************
 *
 * Check if a file handle is correct
 * Input:  BX  -  file handle
 * Output: AX  -  error code if handle not correct
 *         Carry flag  -  set if file handle not correct
 * Registers changed: AX, FS
 *
 */
chkhndl:

# ifndef NEEDEXTIO
	cmp	bx,DOS_RES_AUX		# we can only use console handles
# else
	cmp	bx,DOS_RES_HANDLES	# we can only use reserved handles
# endif
	jae	8f
	mov	fs,[curr_psp]
	test	byte ptr fs:psp_handles[bx],0x0FF
	jnz	9f			# check if handle is open
8:	mov	ax,DOS_ERR_INVHDL
	stc
9:	ret

#endif




/*
 **************************************************************************
 *
 */
	.end

