bbcfs.c
9.15 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
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
#include "bbclocal.h"
/*
* Utility routine to count the number of zero
* bits in a byte (needed to detect bad block markings)
*/
int
__bbc_zerobits(unsigned char b)
{
int c = 0;
int i;
for (i = 0; i < 8; i++)
if ((b & (1<<i)) == 0) c++;
return c;
}
static int
__uhReadGame(int fd, void *addr, int nbytes)
{
int bytesRead = 0;
int rv = 0;
unsigned char *dPtr = (unsigned char*)addr;
BBC_LOG(MSG_ALL, "__uhReadGame: Reading %d bytes\n", nbytes);
while(bytesRead < nbytes)
{
rv = read(fd, &dPtr[bytesRead], nbytes - bytesRead);
if (rv < 0)
BBC_LOG_PERROR("uhReadGame: read failed");
if (rv <= 0) {
BBC_LOG(MSG_DEBUG, "uhReadGame: 0 bytes read\n");
break;
}
bytesRead += rv;
}
BBC_LOG(MSG_ALL, "__uhReadGame: Done read %d bytes, rv = %d\n",
bytesRead, rv);
return(bytesRead);
}
static int
__uhWriteGame(int fd, void *addr, int nbytes)
{
int retVal;
/* send byte count first */
BBC_LOG(MSG_ALL, "__uhWriteGame: Writing %d bytes\n", nbytes);
if ((retVal = write(fd, &nbytes, sizeof nbytes)) < 0) {
BBC_LOG_PERROR("uhWriteGame: write failed");
BBC_LOG(MSG_DEBUG, "uhWriteGame: Error writing count %d\n", nbytes);
return retVal;
}
/* send data */
retVal = write(fd,addr,nbytes);
if (retVal < 0) {
BBC_LOG_SYSERROR("uhWriteGame: write failed");
}
BBC_LOG(MSG_ALL, "__uhWriteGame: Done writing %d bytes, rv = %d\n",
nbytes, retVal);
return(retVal);
}
static int
__bbc_send_common(int fd, const void* buf, int len, int hton)
{
int rv = BBC_EIO, i;
if (hton) {
for(i = 0; i < len/4; i++)
*((unsigned int*)buf+i) = htonl(*((unsigned int*)buf+i));
}
if ((rv = __uhWriteGame(fd, (void*)buf, len)) < len) {
rv = BBC_EIO;
}
return rv;
}
#ifdef WIN32
static int
__bbc_send_win(int fd, const void* buf, int len, int hton)
{
int rv = BBC_EIO;
DWORD dwWaitResult;
HANDLE hDeviceEvents[2];
hDeviceEvents[0] = hDeviceErrorEvent;
hDeviceEvents[1] = hDeviceReadyEvent;
BBC_LOG(MSG_DEBUG, "__bbc_send_win: Waiting for device ready or error event to send %d bytes\n", len);
dwWaitResult = myWaitForMultipleObjects(
2, /* number of handles in array */
hDeviceEvents, /* array of device-event handles */
FALSE, /* wait until only one is signaled */
WAIT_DEVICE_READY_LONG_TIMEOUT); /* 60 second wait, fix for 2K+SiS chipset */
if (dwWaitResult == WAIT_OBJECT_0 + 1) {
BBC_LOG(MSG_ALL, "__bbc_send_win: Sending %d bytes\n", len);
SetEvent(hDeviceDataSendEvent);
ResetEvent(hDeviceReadyEvent);
rv = __bbc_send_common(fd, buf, len, hton);
BBC_LOG(MSG_ALL, "__bbc_send_win: Send done with %d\n", rv);
}
else {
if (dwWaitResult == WAIT_OBJECT_0) {
rv = BBC_DEVERR;
BBC_LOG(MSG_ERR, "__bbc_send_win: Device error\n");
}
else if (dwWaitResult == WAIT_TIMEOUT) {
rv = BBC_TIMEOUT;
BBC_LOG(MSG_ERR, "__bbc_send_win: Device timeout\n");
}
else {
rv = BBC_EIO;
BBC_LOG(MSG_ERR, "__bbc_send_win: Error waiting for device ready, got %d\n", dwWaitResult);
}
}
return rv;
}
int __bbc_send_cmd(int fd, const void* buf, int len)
{
/* Send with host to network conversion */
return __bbc_send_win(fd, buf, len, 1);
}
int __bbc_send_data(int fd, const void* buf, int len)
{
/* Send without host to network conversion */
return __bbc_send_win(fd, buf, len, 0);
}
#else /* Not WIN32 */
int __bbc_send_cmd(int fd, const void* buf, int len)
{
/* Send with host to network conversion */
return __bbc_send_common(fd, buf, len, 1);
}
int __bbc_send_data(int fd, const void* buf, int len)
{
/* Send without host to network conversion */
return __bbc_send_common(fd, buf, len, 0);
}
#endif
int
__bbc_read_rsp(int fd, void* buf, int len)
{
int rv, i;
BBC_LOG(MSG_DEBUG, "__bbc_read_rsp: Reading %d bytes\n", len);
if ((rv = __uhReadGame(fd, buf, len)) < len) {
return BBC_EIO;
}
for(i = 0; i < len/4; i++)
*((unsigned int*)buf+i) = ntohl(*((unsigned int*)buf+i));
return rv;
}
int
__bbc_read_data(int fd, const void* buf, int len)
{
int rv;
BBC_LOG(MSG_DEBUG, "__bbc_read_data: Reading %d bytes\n", len);
if ((rv = __uhReadGame(fd, (void*)buf, len)) < len) {
rv = BBC_EIO;
}
return rv;
}
int
__bbc_sync_fat(bbc_hand *hp)
{
int rv;
BBC_LOG(MSG_ALL, "__bbc_sync_fat\n");
if (hp->bh_type == BBC_HT_DIRECT) {
int hbuf[2];
hbuf[0] = REQ_FS_INIT;
hbuf[1] = 0;
if ((rv = __bbc_send_cmd(hp->bh_pofd, hbuf, 8)) < 0) return rv;
if ((rv = __bbc_read_rsp(hp->bh_pifd, hbuf, 8)) < 0) return rv;
if (hbuf[0] != 255-REQ_FS_INIT) {
BBC_LOG(MSG_ERR, "__bbc_sync_fat: sync loss on REQ_FS_INIT\n");
return BBC_SYNCLOST;
}
if ((int) hbuf[1] < 0) {
BBC_LOG(MSG_ERR, "__bbc_sync_fat: fs reload failed\n");
hp->bh_fat_valid = 0;
/* Try to map the error codes we got into libbbc error codes */
switch (hbuf[1]) {
case BBCARD_ERR_NO_CARD: return BBC_NOCARD;
case BBCARD_ERR_CHANGED: return BBC_CARDCHANGE;
/* All other errors, treat as bad format */
case BBCARD_ERR_FAIL:
case BBCARD_ERR_INVALID:
default: return BBC_NOFORMAT;
}
}
}
BBC_LOG(MSG_ALL, "__bbc_sync_fat SUCCESS\n");
return BBC_OK;
}
int
__BBC_FStat(bbc_hand *hp, const char *name, OSBbStatBuf *sb, u16 *blist, u32 blen)
{
int fd;
int rv;
BBC_LOG(MSG_ALL, "__BBC_FStat\n");
if ((fd = __bbc_fopen(hp, name, "r")) < 0) {
BBC_LOG(MSG_DEBUG, "__BBC_FStat: __bbc_fopen error %d\n", fd);
BBC_LOG(MSG_DEBUG, "__BBC_FStat %s failed\n", name);
return fd;
}
if ((rv = __bbc_fstat(hp, fd, sb, blist, blen)) != BBC_OK) {
BBC_LOG(MSG_DEBUG, "__BBC_FStat: __bbc_fstat error %d\n", rv);
BBC_LOG(MSG_DEBUG, "__BBC_FStat %s failed\n", name);
return rv;
}
BBC_LOG(MSG_ALL, "__BBC_FStat SUCCESS\n");
return fd;
}
static unsigned int
cksum(const unsigned char *p, int n)
{
unsigned int s = 0;
int i;
for(i = 0; i < n; i++)
s += p[i];
return s;
}
int
__BBC_VerifyFile(bbc_hand *hp, const char *name, const void *buf, int len)
{
unsigned int hbuf[2];
unsigned int csum;
char *rbuf;
int fd;
int rv;
BBC_LOG(MSG_ALL, "__BBC_VerifyFile %s\n", name);
/* Direct (i.e. BBPlayer connected via USB), do checksum check */
if (hp->bh_type == BBC_HT_DIRECT) {
/* BBC_HT_DIRECT */
csum = cksum((unsigned char *)buf, len);
/* Sync the FAT first */
if ((rv = __bbc_sync_fat(hp)) < 0) return rv;
hbuf[0] = REQ_CKSUM_FILE;
hbuf[1] = strlen(name)+1;
if ((rv = __bbc_send_cmd(hp->bh_pofd, hbuf, sizeof hbuf)) < 0) return rv;
if ((rv = __bbc_send_data(hp->bh_pofd, name, RND(strlen(name)+1))) < 0) return rv;
hbuf[0] = csum;
hbuf[1] = len;
if ((rv = __bbc_send_cmd(hp->bh_pofd, hbuf, sizeof hbuf)) < 0) return rv;
if ((rv = __bbc_read_rsp(hp->bh_pifd, hbuf, sizeof hbuf)) < 0) return rv;
if (hbuf[0] != 255-REQ_CKSUM_FILE) {
BBC_LOG(MSG_ERR, "__BBC_VerifyFile %s: sync loss on REQ_CKSUM_FILE\n",
name);
return BBC_SYNCLOST;
}
if (hbuf[1] != 0) {
BBC_LOG(MSG_ERR, "VerifyFile %s fails: cksum error\n", name);
return BBC_VERIFYFAIL;
}
BBC_LOG(MSG_DIAG, "__BBC_VerifyFile %s checksum SUCCESS\n", name);
/* Normally, if checksum okay - we are done. In diag mode, drop
through to actually read back the blocks and double check */
if (!bbc_diag_mode) {
return BBC_OK;
}
}
/* In diag mode or not direct, read back blocks and compare */
if ((fd = __bbc_fopen(hp, name, "r")) < 0) {
BBC_LOG_BBCERROR("__BBC_VerifyFile: __bbc_fopen error", fd);
BBC_LOG(MSG_ERR, "__BBC_VerifyFile %s failed\n", name);
return fd;
}
if ((rbuf = malloc(len)) == NULL) {
BBC_LOG_SYSERROR("__BBC_VerifyFile: malloc failed");
BBC_LOG(MSG_ERR, "__BBC_VerifyFile %s failed\n", name);
return BBC_NOMEM;
}
if ((rv = __BBC_FRead(hp, fd, 0, rbuf, len)) < len) {
BBC_LOG(MSG_ERR, "Verify fread %s length %d returns %d\n", name, len, rv);
if (rv >= 0) {
rv = BBC_ERROR;
}
else {
BBC_LOG_BBCERROR("__BBC_VerifyFile: __BBC_FRead error", rv);
}
goto err;
}
if (memcmp(buf, rbuf, len)) {
BBC_LOG(MSG_ERR, "Verify %s fails: data miscompare\n", name);
rv = BBC_VERIFYFAIL;
} else {
rv = BBC_OK;
BBC_LOG(MSG_DIAG, "__BBC_VerifyFile %s data compare SUCCESS\n", name);
}
err:
free(rbuf);
BBC_LOG(MSG_DEBUG, "Verify %s returns %d\n", name, rv);
return rv;
}