vimgr.c 7.37 KB

/*====================================================================
 * vimgr.c
 *
 * Copyright 1995, Silicon Graphics, Inc.
 * All Rights Reserved.
 *
 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
 * Inc.; the contents of this file may not be disclosed to third
 * parties, copied or duplicated in any form, in whole or in part,
 * without the prior written permission of Silicon Graphics, Inc.
 *
 * RESTRICTED RIGHTS LEGEND:
 * Use, duplication or disclosure by the Government is subject to
 * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
 * in Technical Data and Computer Software clause at DFARS
 * 252.227-7013, and/or in similar or successor clauses in the FAR,
 * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
 * Copyright Laws of the United States.
 *====================================================================*/

/**************************************************************************
 *
 *  $Revision: 1.2 $
 *  $Date: 2004/02/06 02:16:47 $
 *  $Source: /root/leakn64/depot/rf/sw/bbplayer/libultra/monegi/vi/vimgr.c,v $
 *
 *  Description:
 *	Video Interface Manager (VIM)
 *	Create a high priority thread to handle Video Interface (VI) 
 *	requests.
 *
 **************************************************************************/


#include "osint.h"
#include "rcp.h"
#include "viint.h"


/**************************************************************************
 *
 * Definitions
 *
 */
#define NUM_EV_MESG	5	/* Number of message entries in event queue */


/**************************************************************************
 *
 * Static variables
 *
 */
static OSThread		viThread;		/* VIM Thread structure */
static char		viThreadStack[OS_VIM_STACKSIZE];

static OSMesgQueue      viEventQueue;           /* Event queue structure */
static OSMesg           viEventBuf[NUM_EV_MESG];

static OSIoMesg		viRetraceMsg, viCounterMsg;


/**************************************************************************
 *
 * Global variables
 */

OSDevMgr		__osViDevMgr = {0};	/* Device Manager structure */
u32 			__additional_scanline = 0;

/**************************************************************************
 *
 * Function prototypes
 *
 */
static void 		viMgrMain(void *);


/*
 * Name:   osCreateViManager
 *
 * Description:
 *	Create and start the Video Interface Manager (VIM). User specifies
 *	the priority at which this thread will run.
 *
 * Globals Referenced: 
 *	__osViDevMgr
 *	viThread
 *	viThreadStack
 *	viEventQueue
 *	viEventBuf
 */
void
osCreateViManager(OSPri pri)
{
    u32		savedMask;
    OSPri	oldPri, myPri;

#ifdef _DEBUG
    if ((pri < OS_PRIORITY_IDLE) || (pri > OS_PRIORITY_MAX)) {
	__osError(ERR_OSCREATEVIMANAGER, 1, pri);
	return;
    }
#endif

    /* If VI Manager is already running, simply return */
    if (__osViDevMgr.active) 
        return;

#ifdef _ULTRA64
    /* Initialize timer services which use VI interrupt handler */
    __osTimerServicesInit();
#endif

    /* Set __additional_scanline */
    __additional_scanline = 0;    

    /* Create the input event queue */
    osCreateMesgQueue(&viEventQueue, viEventBuf, NUM_EV_MESG);

    viRetraceMsg.hdr.type     = OS_MESG_TYPE_VRETRACE;
    viRetraceMsg.hdr.pri      = OS_MESG_PRI_NORMAL;
    viRetraceMsg.hdr.retQueue = NULL;

    viCounterMsg.hdr.type     = OS_MESG_TYPE_COUNTER;
    viCounterMsg.hdr.pri      = OS_MESG_PRI_NORMAL;
    viCounterMsg.hdr.retQueue = NULL;

    /* Take over VI interrupt */
    osSetEventMesg(OS_EVENT_VI, &viEventQueue, (OSMesg)&viRetraceMsg);

    /* Take over COUNTER interrupt */
    osSetEventMesg(OS_EVENT_COUNTER, &viEventQueue, (OSMesg)&viCounterMsg);

    /*
     * Check the current thread priority against the VIM's priority.
     * If current is lower, temporarily increase it to same level as VIM
     */
    oldPri = -1;
    myPri = osGetThreadPri((OSThread *)NULL);
    if (myPri < pri) {
        oldPri = myPri;
        osSetThreadPri(NULL, pri);
    }

    /* Set global to tell that Video Interface Manager is on and active */
    savedMask = __osDisableInt();

    __osViDevMgr.active		= 1;
    __osViDevMgr.thread		= &viThread;
    __osViDevMgr.cmdQueue	= &viEventQueue;
    __osViDevMgr.evtQueue	= &viEventQueue;
    __osViDevMgr.acsQueue	= (OSMesgQueue *)NULL;
    __osViDevMgr.dma		= NULL;
    __osViDevMgr.edma		= NULL;

    /* Create VI manager thread with VI and CPU counter interrupts enabled */
    osCreateThread(&viThread, OS_TID_VIMGR, viMgrMain, (void *)&__osViDevMgr,
		   viThreadStack+OS_VIM_STACKSIZE, (OSPri)pri);

    /* 
     * Initialize internal VI structures and set hardware registers to
     * enable vertical retrace.
     */
    __osViInit();

    osStartThread(&viThread);

    /* Restore original interrupt mask */
    __osRestoreInt(savedMask);

    /* Restore original thread priority */
    if (oldPri != -1)
        osSetThreadPri(NULL, oldPri);

}  /* osCreateViManager */


/*
 * Name:   viMgrMain
 *
 * Description:
 *	This is the main loop for the VI manager.
 *
 * Note:
 * 	As a policy, all messages sent to the command queue are pointers to
 *	an I/O message block.
 *
 * Pseudo-code:
 *	// The idea here is to listen on the vertical retrace message queues,
 *	// for event notification.
 *	while always {
 *	    Listen (w/ blocking) on event queue
 *	    Check for valid message type
 *	    Decode message type
 *	    Process message type (i.e., vertical retrace)
 *	    Send reply message to registered message queue
 *	}
 *
 * Globals Referenced: 
 *	None
 */
static void
viMgrMain(void *arg)
{

    __OSViContext	*vc;
    OSDevMgr		*dm;
    OSIoMesg		*mb = NULL;

    static u16		retrace;
#if !_EMULATOR
    s32			first = 0;
    u32			Count;
#endif /* _EMULATOR */

			/* Initialize retrace counter */
    vc = __osViGetCurrentContext();
    retrace = vc->retraceCount;
    if (retrace == 0)	/* to at least 1 */
        retrace = 1;

    dm = (OSDevMgr *)arg;

    while (1) {

	/* 
	 * Listen on the Event Queue 
	 */
        (void)osRecvMesg(dm->evtQueue, (OSMesg *)&mb, OS_MESG_BLOCK);

        /*
         * This signals either a vertical retrace interrupt or a CPU counter
         * interrupt
         */

        /*
         * Decode the message: (1) vertical retrace, (2) CPU counter
         */
        switch (mb->hdr.type) {
            case OS_MESG_TYPE_VRETRACE: {

                /* Swap the VI current and next context */
                __osViSwapContext();

                /* Decrement retrace counter */
		retrace--;

                /* Signal a thread of a vertical retrace interrupt occurrence */
                if (retrace == 0) {
		    vc = __osViGetCurrentContext();
                    if (vc->msgq != NULL) {
                        (void)osSendMesg(vc->msgq, vc->msg, OS_MESG_NOBLOCK);
                    }
                    retrace = vc->retraceCount; /* Reset counter */
                }
	
#if !_EMULATOR
		__osViIntrCount++;
		if (first) {
		    Count = osGetCount();
		    __osCurrentTime = (OSTime)Count;
		    first = 0;
		}
		Count = __osBaseCounter;
		__osBaseCounter = osGetCount();
		Count = __osBaseCounter - Count;
		__osCurrentTime = __osCurrentTime + (OSTime)Count;
#endif /* _EMULATOR */

                break;
            }
            case OS_MESG_TYPE_COUNTER: {
#if !_EMULATOR
		__osTimerInterrupt();
#endif /* _EMULATOR */
                break;
            }
            default: {  /* ERROR: NOT REACHED */
                break;
            }
        }

    }  /* while */

}  /* viMgrMain */