/* biosgetdev.S: BIOS call: get PnP ISA sys device node */
/*
 * $Header: /root/pnp/module/RCS/biosgetdev.S,v 1.2 1996/06/12 18:56:34 root Exp $
 *
 * $Log: biosgetdev.S,v $
 * Revision 1.2  1996/06/12  18:56:34  root
 * standard internal i/f & BIOS read/query
 *
 * Revision 1.1  1996/05/27  08:27:10  root
 * initial revision
 *
 * Revision 1.2  1996/05/26  19:07:44  root
 * code restructured & modularized
 *
 * Revision 1.1  1996/05/26  15:33:30  root
 * initial revision
 *
 */

/*
 * (c) Copyright 1996  D.W.Howells <dwh@nexor.co.uk>,
 */

#ifdef __ELF__
  #define ENTRY(x) x
#else
  #define ENTRY(x) _##x
#endif

#define GET_DEVICE_NODE 1

/*
 * int pnp_bios__getdevnode(
 *	u_char *handle,		; device node to retrieve (updated on return)
 *	u_char *buffer,		; buffer for return data
 *	u_int size,		; size of buffer
 *	u_int current		; true:current config | false:config next boot
 *	);
 * returns -ve: error, +ve: size
 */
#define HANDLE	0x08(%ebp)
#define BUFFER	0x0c(%ebp)
#define SIZE	0x10(%ebp)
#define CURRENT	0x14(%ebp)

.globl ENTRY(pnp_bios__getdevnode)
ENTRY(pnp_bios__getdevnode):
	pushl %ebp
	movl %esp,%ebp
	pushl %ebx
	pushl %ecx
	pushl %edx
	pushl %esi
	pushl %edi

	/*===================================================================*/
	/* push the arguments as 16-bit values */
#define ARGBLOCK 0x0e
	subl $ARGBLOCK,%esp
	movl %esp,%edx
	movl ENTRY(pnpbios_ds),%eax		/* BIOS selector */
	movw %ax,0x0c(%edx)

	movl CURRENT,%eax			/* get request type */
	orl %eax,%eax
	jz future
	movw $0x0002,%ax	/* config at next boot */
	jmp stk_request
future:
	movw $0x0001,%ax	/* config now */
stk_request:
	movw %ax,0x0a(%edx)

	movl ENTRY(pnpbios_kdata_ds),%eax	/* seg for buffer */
	movw %ax,0x08(%edx)
	movl $01,%ax				/* offset for buffer */
	movw %ax,0x06(%edx)

	movl HANDLE,%eax			/* the device node handle */
	movb (%eax),%al
	movl pnpbios_buffer,%ecx		/* store the handle */
	movb %al,(%ecx)
	movl ENTRY(pnpbios_kdata_ds),%eax	/* seg for handle */
	movw %ax,0x04(%edx)
	movw $00,%ax				/* offset for handle */
	movw %ax,0x02(%edx)

	movw $GET_DEVICE_NODE,%ax		/* function */
	movw %ax,0x00(%edx)

	/*===================================================================*/
	/* stack the return address to here */
	subl $0x04,%esp
	movl %esp,%edx
	movw ENTRY(pnpbios_ret_cs),%ax
	movw %ax,0x02(%edx)		/* %cs */
	movw $0x0000,%ax
	movw %ax,0x00(%edx)		/* %ip */

	/* stack the BIOS address to be called (32-bit lret!!!!) */
	movw ENTRY(pnpbios_cs),%eax
	andl $0xffff,%eax
	pushl %eax			/* %cs */
	movl ENTRY(pnpbios_entry),%eax
	andl $0xffff,%eax
	pushl %eax			/* %eip */

	/* return address to here placed in registers */
	leal ENTRY(return_from_BIOS),%ebx
	movw %cs,%cx
	andl $0xffff,%ecx

	/* call BIOS */
	lret

/*
 * This is where BIOS indirectly returns to (%ax holds the return value)
 *
 *
 */
ENTRY(return_from_BIOS):
	/* unstack the parameters */
	addl $ARGBLOCK,%esp

	/* make return an int */
	cwtl
	or %eax,%eax
	jnz error

	/* now sort out the arg-returned values */
	movw %es,%bx
	movw ENTRY(pnpbios_kdata_ds),%cx
	movw %cx,%es
	
	/* store the next device handle */
	movb %es:0x0000,%cl
	movl HANDLE,%edx
	movb %cl,(%edx)
	movw %bx,%es

	/* copy data from the BIOS buffer to the kernel buffer */
	movl pnpbios_buffer,%esi
	inc %esi
	movl BUFFER,%edi
	movl SIZE,%ecx
	movw (%esi),%bx			/* get size of this node */
	andl $0xffff,%ebx
	cmpl %ebx,%ecx
	jbe use_min_size		/* jump if %ecx <= %ebx (C=1 || Z=1) */
	movl %ebx,%ecx
use_min_size:
	movl %ecx,%eax			/* this'll be the return value */
	cld
	shrl $1,%ecx
	jnc copy_nobyte
	movsb
copy_nobyte:
	shrl $1,%ecx
	jnc copy_noword
	movsb
copy_noword:
	rep
	movsl

	/*===================================================================*/
	/* tidy the stack */
	jmp ok
error:
	negl %eax			/* error return <0 */
ok:
	popl %edi
	popl %esi 
	popl %edx
	popl %ecx
	popl %ebx
	popl %ebp
	ret
