writehost.c 6.79 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>
#include <ultraerror.h>

#ifndef _FINALROM

#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif

static int		writeHostInitialized = 0;
static OSMesgQueue	writeHostMesgQueue;
#ifdef BBPLAYER
static OSMesg		writeHostMesgBuf[2];
#else
static OSMesg		writeHostMesgBuf[1];
#endif

/*
 * Name:   osWriteHost
 *
 * Description:
 *	Send nbytes of data starting at dramAddr to the host.
 *
 * CAUTION: Application must insure that only one call to osWriteHost at a time!!!
 *          Application on host must have opened /dev/u64_data before osWriteHost
 *          is called!
 *
 * How it works:
 *   An application on the indy must open /dev/u64_data before osWriteHost is called.
 *   After the device is opened, either osWriteHost, or uhReadGame may be called in either
 *   order. When uhReadGame is called by the host application, it will block until data 
 *   begins to arrive. When osWriteHost is called, it will send a message indicating 
 *   how many bytes it will send, before expecting an ack back. It will follow this message
 *   with the data. Once the data has been read out of the kernel driver buffers, and into
 *   the host application buffers, the kernel will send a signal back, acknowledging the 
 *   transfer, and indicating it is ready for the next block.
 *
 */
#ifndef BBPLAYER /* Original N64 version */

void osWriteHost(void *dramAddr, u32 nbytes)
{
    u8     *tPtr = (u8*)dramAddr;
    u32    sent;
    u8     dCount[3];
    u32    count;
 
#ifdef _DEBUG
    /*
     * Size must be non-zero
     */
    if (nbytes == 0)
    {
        __osError(ERR_OSWRITEHOST_SIZE, 1, nbytes);
        return;
    }
#endif
                                                                                                    
    if(!writeHostInitialized)
    {
        osCreateMesgQueue(&writeHostMesgQueue, writeHostMesgBuf, 1);
        osSetEventMesg(OS_EVENT_RDB_DATA_DONE, &writeHostMesgQueue, NULL);
        writeHostInitialized = 1;
    }
 
    while(nbytes)  /* break into blocks of RDB_DATA_MAX_BLOCK_SIZE */
    {              /* this is to insure that kernal buffers don't overflow */
 
        count = MIN(nbytes,RDB_DATA_MAX_BLOCK_SIZE);
        dCount[0] = (u8)((count & 0x00FF0000) >> 16);
        dCount[1] = (u8)((count & 0x0000FF00) >> 8);
        dCount[2] = (u8)(count & 0x000000FF);
 
        sent = 0;
        while(sent < 3)
            sent += __osRdbSend(&dCount[sent],3-sent,RDB_TYPE_GtoH_DATA_CT);
 
        sent = 0;
        while(sent < count)
            sent += __osRdbSend(&tPtr[sent],count-sent,RDB_TYPE_GtoH_DATA);
 
        nbytes -= count;
        tPtr += count;
 
        osRecvMesg(&writeHostMesgQueue, NULL, OS_MESG_BLOCK);
    }
 
}

#else /* BBPLAYER */
 
/*
 * Name: osBbInitWriteHost
 * Description: Function to  initializes data structures for osWriteHost
 */
void osBbInitWriteHost()
{
    osCreateMesgQueue(&writeHostMesgQueue, writeHostMesgBuf, 2);
    osSetEventMesg(OS_EVENT_RDB_DATA_DONE, &writeHostMesgQueue, 
                   (OSMesg) OS_MESG_TYPE_RDB_DATA_DONE);
    osSetEventMesg(OS_EVENT_RDB_DATA_RESET, &writeHostMesgQueue,
                   (OSMesg) OS_MESG_TYPE_RDB_DATA_RESET);
    writeHostInitialized = 1;
}

/*
 * Name: __osWriteHost
 * Description: Internal helper function that attempts to write nbytes from
 *              dramAddr.  Will exit if when nbytes written or error occurred.
 * Returns: Number of bytes written.
 */
u32 __osWriteHost(void *dramAddr, u32 nbytes)
{
    OSMesg msg;
    u8     *tPtr = (u8*)dramAddr;
    u32    sent;
    u8     dCount[3];
    u32    count;
    u32    nOrigBytes;

#ifdef _DEBUG
    /*
     * Size must be non-zero
     */
    if (nbytes == 0)
    {
	__osError(ERR_OSWRITEHOST_SIZE, 1, nbytes);
	return 0;
    }
#endif

    if(!writeHostInitialized)
    {
        osBbInitWriteHost();
    }

    nOrigBytes = nbytes;
    while(nbytes)  /* break into blocks of RDB_DATA_MAX_BLOCK_SIZE */
    {              /* this is to insure that kernal buffers don't overflow */

	count = MIN(nbytes,RDB_DATA_MAX_BLOCK_SIZE);
	dCount[0] = (u8)((count & 0x00FF0000) >> 16);
	dCount[1] = (u8)((count & 0x0000FF00) >> 8);
	dCount[2] = (u8)(count & 0x000000FF);
	
	sent = 0;
	while(sent < 3)
	    sent += __osRdbSend(&dCount[sent],3-sent,RDB_TYPE_GtoH_DATA_CT);        
	sent = 0;
	while(sent < count)
	    sent += __osRdbSend(&tPtr[sent],count-sent,RDB_TYPE_GtoH_DATA);

	osRecvMesg(&writeHostMesgQueue, (OSMesg *)&msg, OS_MESG_BLOCK);
        if ( (int) msg != OS_MESG_TYPE_RDB_DATA_DONE ) {
	    /*
	     * If there is a DATA_DONE message on the queue also,
	     * receive and discard it.
	     */
	    osRecvMesg(&writeHostMesgQueue, NULL, OS_MESG_NOBLOCK);
            break;
	}

	nbytes -= count;
	tPtr += count;

    }

    return nOrigBytes - nbytes;
}

/*
 * Name: osWriteHost
 * Description: Backward compatible version of osWriteHost that
 *              blocks until all nbytes from dramAddr has been written.
 * NOTE: Only one call to osWriteHost, osBbWriteHost, or osSyncHost at a time!!!
 */
void osWriteHost(void *dramAddr, u32 nbytes)
{
    u32 nBytesSent = 0;
    while (nBytesSent < nbytes)
    {
        nBytesSent += __osWriteHost(dramAddr, nbytes);
    }
}

/*
 * Name: osBbWriteHost
 * Description: Version of osWriteHost for the BB that will
 *              return if there is an error.
 * Returns: < 0 if error
 *            0 if nbytes successfully written from dramAddr
 * NOTE: Only one call to osWriteHost, osBbWriteHost, or osSyncHost at a time!!!
 */
s32 osBbWriteHost(void *dramAddr, u32 nbytes)
{
    u32 nBytesSent = __osWriteHost(dramAddr, nbytes);
    if (nBytesSent < nbytes)
        return -1;
    return 0;
}

/*
 * Used to make sure all osSyncPrintf output has been received by the host.
 * It is the responsibility of the caller to make sure that two threads don't
 * call osWriteHost and osBbSyncHost at the same time.
 */
void osBbSyncHost(void)
{
    u32 sent;
    u8 junk[3];
    if(!writeHostInitialized) {
        osBbInitWriteHost();
    }

    junk[0] = junk[1] = junk[2] = 0;
    sent = 0;
    while (sent < 3)
        sent += __osRdbSend(&junk[sent],3,RDB_TYPE_GtoH_SYNC);
    osRecvMesg(&writeHostMesgQueue, NULL, OS_MESG_BLOCK);
}
#endif /* BBPLAYER */
#endif /* ifndef _FINALROM */