writehost.c
6.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
/**************************************************************************
* *
* 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 */