/*  osentries.c -- Target Operating System Interface Routines
 *  copyright (c) American Information Systems Corporation
 *	Daniel Steinberg
 *	November, 1984
 *
 */

#include "viosconf.h"
#include "handlers.h"
#include "poolfuncs.h"
#include "pktfuncs.h"
#include "vioslink.h"


    PKT_PTR
vios_iorequest (func, dev, buf, bufsiz, bufmap, aux,
				p1, p2, p3, p4, stat, intrpt, priority, timeout)
    unsigned func;		/* Function code */
    VDD_PTR dev;		/* Device bufptr */
    char *buf;			/* I/O Buffer */
    unsigned bufsiz;		/* Byte count length of buffer */
    char *bufmap;		/* Buffer map flag or Segment Table Address */
    char *aux;			/* Auxiliary string parameter */
    unsigned p1, p2, p3, p4;	/* I/O parameters */
    PKT_IOSTATUS *stat;		/* Address of return status block */
    int (*intrpt)();		/* I/O completion routine address */
    unsigned priority;		/* Request priority (0-31) */
    unsigned timeout;		/* Request timeout count */

/* vios_iorequest (...) -- Issue an I/O request from an O.S. to the VIOS
 *	in:	func		Function code
 *	in:	dev		Device bufptr
 *	in:	buf		I/O Buffer
 *	in:	bufsiz		Byte count length of buffer
 *	in:	bufmap		Buffer map flag or Segment Table Address
 *	in:	aux		Auxiliary string parameter
 *	in:	param[1-4]	I/O parameters
 *	in:	stat		Address of return status block
 *	in:	intrpt		I/O completion routine address
 *	in:	priority	Request priority (0-31)
 *	in:	timeout		Request timeout count
 *	return:	(PKT_PTR)	Queued i/o request number
 *	thrown:	(NONE)
 *
 *	Allocates and constructs an i/o packet and fills it in from the
 *	information in the argument list.  Then queues
 *	it to the VIOS at the main entry (vios_entry() in viomain.c).
 *
 *	This routine must be called from normal VIOS processing state with
 *	interrupts enabled.
 */
{
    register PKT_PTR pkt;
    register IO_PACKET *pk;
    register char **s;

#ifdef DEBUG3   /*************************************************************/
    if (Intstate OR ints_disabled())
    	{
    	error("Vios_iorequest() entered at interrupt state", NULL);
	}
#endif /* DEBUG3 *************************************************************/

    while (TRUE)
    	{
	if (catch() EQ 0)		/* catch allocation failures */
	    {
	    pk = *(pkt = (PKT_PTR) allpkt());	/* allocate an i/o packet */
	    uncatch();			/* allpkt() might throw V_ALL_FAILURE */

	    Function(pk) = (UB16) func;	/* set i/o function */
	    VDevice(pk) = dev;		/* set target device */
	    Ubufaddr(pk) = buf;		/* set i/o buffer address */
	    Ubufmap(pk) = bufmap;	/* set buffer map flag */
	    Ubufsize(pk) = bufsiz;	/* set i/o buffer length */
	    Param1(pk) = p1;		/* copy parameters */
	    Param2(pk) = p2;
	    Param3(pk) = p3;
	    Param4(pk) = p4;
	    Timeout(pk) = timeout;	/* set timeout */
					/* priority must be 0-31 */
	    Priority(pk) = (PKT_PRIORITY) (priority & 0x1F);

	    /* Operating system id is known for now */
	    Compos(pk) = Osid(pk) = (OS_IDENT) Current_os;	/* set OS id */
	    Cstataddr(pk) = (char*) stat;		/* addr to get status */
	    Cstatmap(pk) = (char*) PHYS_BUFFER;		/* flag not mapped */
	    return_stat(pkt);				/* clear user block */
	    Comproutine(pk) = intrpt;		/* completion entry */

	    break;			/* break out of while loop */
	    }
	else		/* if allocation failure, loop forever */
	    {
	    }
	} /*while*/

    if (aux NE NULL)		/* if auxilliary string to copy */
    	{
	/* loop forever, until allocation succeeds */
	while ((s = Auxparam(*pkt) = alloc(1 + strlen(aux))) EQ NULL);

	strcpy(*s, aux);		/* copy auxilliary string */
	}

    q_virtual(pkt);			/* add the packet to the run queue */
    vio_reschedule();			/* start VIOS if not already running */
    return(pkt);			/* and return packet number */
}

    unsigned
dq_oscompletion (argptr)
    unsigned *argptr;

/* dq_oscompletion (argptr) - Dequeue a completion request for the active OS
 *	mod:	argptr		Address of argument to receive the argument
 *				that must be on the stack when the completion
 *				routine is called.
 *	return:	(int*)()	Procedure descriptor of interrupt routine
 *	thrown:	(NONE)
 *
 *	If there are any pending completions for the current OS, the first is
 *	dequeued and released to pool.  The return value is the address of the
 *	completion routine to call, while the location pointed to by 'argptr'
 *	will receive the value of the argument to push prior to calling the
 *	interrupt routine.
 *
 *	This routine is currently called with interrupts disabled, and must
 *	ensure that the VIOS queue management subroutines do not enable them!
 */
{
    register int (*rout)();
    register OS_COMP **c;

    rout = NULL;		/* assume failure below */

    if (OSscheduled)		/* if there are completions queued */
	{
	Intstate++;		/* don't mess with the PSR_I bit */

	/* dequeue the next completion packet, if any, from the current os */

	if ((c = (OS_COMP**) dq_item(&O_cqueue(*Current_os))) NE NULL)
	    {
	    *argptr = O_carg(*c);	/* set the argument value */
	    rout = O_crout(*c);		/* set the completion routine xpd */
	    Intstate--;			/* restore entry conditions */
	    vfree(c);			/* release the packet */
	    }
	else
	    {
	    OSscheduled = FALSE;	/* no more completions to this os */
	    Intstate--;			/* restore entry conditions */
	    }
	} /*if-OSscheduled*/

    return((unsigned)rout);	/* return completion entry point or NULL */
}
