readhost.c 5.91 KB
/**************************************************************************
 *									  *
 *		 Copyright (C) 1995, Silicon Graphics, Inc.		  *
 *									  *
 *  These coded instructions, statements, and computer programs  contain  *
 *  unpublished  proprietary  information of Silicon Graphics, Inc., and  *
 *  are protected by Federal copyright law.  They  may  not be disclosed  *
 *  to  third  parties  or copied or duplicated in any form, in whole or  *
 *  in part, without the prior written consent of Silicon Graphics, Inc.  *
 *									  *
 **************************************************************************/

#include <os.h>
#include <os_bb.h>
#include <os_internal.h>
#include <rdb.h>


#ifndef _FINALROM
static int		readHostInitialized = 0;
static OSMesgQueue	readHostMesgQueue;
#ifdef BBPLAYER
static OSMesg		readHostMesgBuf[2];
#else
static OSMesg		readHostMesgBuf[1];
#endif

/*
 * Name:   osReadHost
 *
 * Description:
 *	Copy nbytes of data from the host to DRAM starting at dramAddr
 *
 * CAUTION: Application must insure that only one call to osReadHost at a time!!!
 * 
 * How it works:
 *   An application on the indy must open /dev/u64_data. Then the host app
 *   calls uhWriteGame with the data to be sent. The write call will block until
 *   the game sends a signal, indicating that it is ready to receive the data.
 *   When the write call receives the signal, it will start sending data over the
 *   rdb port, which will be stored in the buffer pointed to by __osRdb_Read_Data_Buf.
 *   When __osRdb_Read_Data_Ct is reached, exceptasm will generate a message of
 *   OS_EVENT_RDB_READ_DONE.   
 *
 *   Timing of which call is made first, osReadHost, or uhWriteGame is not critical. 
 *   If uhWriteGame occurs first, host will block, if osReadHost occurs first, host 
 *   kernal will save the ready message, and start once uhWriteGame occurs. Meanwhile,
 *   osReadHost will block waiting for done message. Note that osReadHost does block, 
 *   and stops the running of the thread that called it.
 *
 *   Potential problems occur if osReadHost is called, but not matched by an equivilent
 *   uhWriteGame call from the host.
 */

u8   *__osRdb_Read_Data_Buf;
u32  __osRdb_Read_Data_Ct;

#ifndef BBPLAYER /* Original N64 version */

void osReadHost(void *dramAddr, u32 nbytes)
{
    unsigned char  tstr[4];
    u32  sent = 0;
 
    /* The first time through, initialize a message queue for completion ack  */
    if (!readHostInitialized)
    {
        osCreateMesgQueue(&readHostMesgQueue, readHostMesgBuf, 1);
        osSetEventMesg(OS_EVENT_RDB_READ_DONE, &readHostMesgQueue,NULL);
        readHostInitialized = 1;
    }
 
    /* set up pointers and counters used by exceptasm */
    __osRdb_Read_Data_Buf = (u8*)dramAddr;
    __osRdb_Read_Data_Ct = nbytes;
    /* send message to host telling host, you are ready for data */
    while(sent < 1)
        sent += __osRdbSend(&tstr[0],1,RDB_TYPE_GtoH_READY_FOR_DATA);
    /* block waiting for all data to be transferred */
    (void)osRecvMesg(&readHostMesgQueue, NULL, OS_MESG_BLOCK);
    return;
}

#else /* BBPLAYER */

/*
 * Name:__osReadHost 
 * Description: Internal helper function that attempts to read nbytes into
 *              dramAddr.  Will exit if when nbytes read or error occurred.
 * Returns: Number of bytes read.
 */
u32 __osReadHost(void *dramAddr, u32 nbytes)
{
    unsigned char  tstr[4];
    u32  sent = 0, nBytesRead = 0;
    u32  saveMask;

    /* The first time through, initialize a message queue for completion ack  */
    if (!readHostInitialized) 
    {
	osCreateMesgQueue(&readHostMesgQueue, readHostMesgBuf, 2);
	osSetEventMesg(OS_EVENT_RDB_READ_DONE, &readHostMesgQueue, 
                       (OSMesg) OS_MESG_TYPE_RDB_READ_DONE);
	osSetEventMesg(OS_EVENT_RDB_READ_RESET, &readHostMesgQueue,
                       (OSMesg) OS_MESG_TYPE_RDB_READ_RESET);
	readHostInitialized = 1;
    }

    /* set up pointers and counters used by exceptasm */
    saveMask = __osDisableInt();    
    __osRdb_Read_Data_Buf = (u8*)dramAddr;
    __osRdb_Read_Data_Ct = nbytes;
    __osRestoreInt(saveMask);

    /* send message to host telling host, you are ready for data */
    while(sent < 1) {
        if (osRecvMesg(&readHostMesgQueue, NULL, OS_MESG_NOBLOCK) == 0) {
            /* Ooh, we already got a message */
	    /* If there are two, get the other one also */
            (void)osRecvMesg(&readHostMesgQueue, NULL, OS_MESG_NOBLOCK);
            break;
        }
	tstr[0] = 0;
	sent += __osRdbSend(&tstr[0],1,RDB_TYPE_GtoH_READY_FOR_DATA);
    }

    if (sent >= 1) {
        /* block waiting for all data to be transferred */
        (void)osRecvMesg(&readHostMesgQueue, NULL, OS_MESG_BLOCK); 
	/* if there are two messages, snag them both */
        (void)osRecvMesg(&readHostMesgQueue, NULL, OS_MESG_NOBLOCK); 
    }

    /* Reset the Rdb read pointers and counters */
    saveMask = __osDisableInt();    
    nBytesRead = nbytes - __osRdb_Read_Data_Ct;
    __osRdb_Read_Data_Buf = 0;
    __osRdb_Read_Data_Ct = 0;
    __osRestoreInt(saveMask);

    /* Return number of bytes read */
    return nBytesRead;
}

/*
 * Name: osReadHost
 * Description: Backward compatible version of osReadHost that
 *              blocks until all nbytes have been read into dramAddr.
 * NOTE: Only one call to osReadHost or osBbReadHost at a time!!!
 */
void osReadHost(void *dramAddr, u32 nbytes)
{
    u32 nBytesRead = 0;
    while (nBytesRead < nbytes) {
        nBytesRead += __osReadHost(((u8*)dramAddr)+nBytesRead, nbytes);
    }
}

/*
 * Name: osBbReadHost
 * Description: Version of osReadHost for the BB that will
 *              return if there is an error.
 * Returns: < 0 if error
 *            0 if nbytes successfully read into dramAddr
 * NOTE: Only one call to osReadHost or osBbReadHost at a time!!!
 */
s32 osBbReadHost(void *dramAddr, u32 nbytes)
{
    u32 nBytesRead = __osReadHost(dramAddr, nbytes);
    if (nBytesRead < nbytes)
        return -1;
    return 0;
}

#endif /* BBPLAYER */ 

#endif /* ifndef _FINALROM */