auxdata.c
7.7 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
#include "os.h"
#include "os_bb.h"
#include "os_bbfs.h"
#include "bcp.h"
#include "bbint.h"
#include "state.h"
#define NIBBLE_TO_ASCII(v) ((v)<10?('0'+(v)):('a'+(v)-10))
#define TMP_FILE "temp.tmp"
#define NAME_LEN BB_STATENAME_LEN
/* NOTE: The file system will overwrite PI_FLASH_CTRL_REG, which is
* also used for DMA to/from the card. To ensure that FS accesses
* by a game does not break DMA, it is important to save and restore
* this register every time the file system is accessed.
*/
/* Does not use FS */
char*
__osBbGameGetStateName()
{
if (STASH_OKAY(__osBbStashMagic)) {
return __osBbStateName;
}
return NULL;
}
/* Does not use FS */
static s32
__osBbGetAuxDataFilename(u8 id, char *file_name)
{
int i;
const char* state_name;
if (id >= BB_MAX_AUXDATA) return BBFS_ERR_INVALID;
if (file_name == NULL) return BBFS_ERR_INVALID;
state_name = __osBbGameGetStateName();
if (state_name == NULL || !state_name[0])
return BBFS_ERR_STATE; /* No state information - wrong viewer? */
for(i = 0; i < 8 && state_name[i] != '.' && state_name[i]; i++) {
file_name[i] = state_name[i];
}
file_name[i] = '.';
file_name[i+1] = 'u';
file_name[i+2] = NIBBLE_TO_ASCII( (id >> 4) & 0xf);
file_name[i+3] = NIBBLE_TO_ASCII( id & 0xf );
file_name[i+4] = '\0';
return 0;
}
/*
* Initializes the card for auxiliary game data. Must be called each
* time a new card is inserted, before any other auxiliary game data
* functions or osBbGameCommitState can be used.
* Parameters:
* buf - Buffer for internal state. Must be 16 byte aligned.
* NOTE: buf should not be reused by the calling application
* for any other purpose
* len - Length of the buffer, must be at least 32KB.
* Returns: 0 if successful, <0 if unsuccessful
*/
s32
osBbAuxDataInit(void* buf, u32 len)
{
s32 rv;
u32 old;
if (buf == NULL) return BBFS_ERR_INVALID;
if ((u32)buf&15) return BBFS_ERR_INVALID;
if (len < sizeof(OSBbFs)) return BBFS_ERR_INVALID;
old = IO_READ(PI_FLASH_CTRL_REG); // Save reg
rv = osBbFInit((OSBbFs*) buf);
IO_WRITE(PI_FLASH_CTRL_REG, old); // Restore reg
return rv;
}
/*
* Provides a list of user defined data ids on the card for the game
* Parameters:
* ids - Buffer to write the ids into
* Returns: # of ids if successful, <0 if unsuccessful
*/
s32
osBbAuxDataIds(u8 ids[BB_MAX_AUXDATA])
{
char file_name[NAME_LEN];
int rv, i, fd;
int count=0;
u32 old = IO_READ(PI_FLASH_CTRL_REG); // Save reg
bzero(ids, BB_MAX_AUXDATA);
if (__osBbGameGetStateName() == NULL) {
// No FS access yet
return BBFS_ERR_STATE; /* No state information - wrong viewer? */
}
for (i=0; i < BB_MAX_AUXDATA; i++) {
rv = __osBbGetAuxDataFilename(i, file_name);
if (rv >= 0) {
if ((fd = osBbFOpen(file_name, "r")) >= 0) {
ids[count++] = i;
osBbFClose(fd);
}
else if (fd != BBFS_ERR_ENTRY) {
/* Abort if any error other than file not found */
IO_WRITE(PI_FLASH_CTRL_REG, old); // Restore reg
return fd;
}
}
}
IO_WRITE(PI_FLASH_CTRL_REG, old); // Restore reg
return count;
}
/*
* Provides the size of the user defined data
* Parameters:
* id - Aux Data ID (0-15)
* Returns: size of user data if successful, <0 if unsuccessful
*/
s32
osBbAuxDataSize(u8 id)
{
s32 rv = 0;
OSBbStatBuf sb;
char file_name[NAME_LEN];
int fd;
u32 old = IO_READ(PI_FLASH_CTRL_REG); // Save reg
rv = __osBbGetAuxDataFilename(id, file_name);
if (rv < 0)
return rv; // No FS access yet
if ((fd = osBbFOpen(file_name, "r")) >= 0) {
rv = osBbFStat(fd, &sb, NULL, 0);
osBbFClose(fd);
if (rv >= 0) {
rv = sb.size;
}
}
else {
rv = fd;
}
IO_WRITE(PI_FLASH_CTRL_REG, old); // Restore reg
return rv;
}
/*
* Loads the user defined data from the card
* Parameters:
* buf - Buffer to load the data info (must be 16 byte aligned)
* len - Length of the buffer, must be a multiple of 16K
* id - Aux Data ID (0-15)
* Returns: number of bytes read if successful, <0 if unsuccessful
*/
s32
osBbAuxDataLoad(u8 id, void* buf, u32 len) {
s32 rv = 0;
char file_name[NAME_LEN];
int fd;
u32 old = IO_READ(PI_FLASH_CTRL_REG); // Save reg
if (buf == NULL) return BBFS_ERR_INVALID;
if ((u32)buf&15) return BBFS_ERR_INVALID;
if (len > BB_MAX_AUXDATA_SIZE) return BBFS_ERR_INVALID;
if (len & (BB_FL_BLOCK_SIZE-1)) return BBFS_ERR_INVALID;
rv = __osBbGetAuxDataFilename(id, file_name);
if (rv < 0)
return rv; // No FS access yet
if ((fd = osBbFOpen(file_name, "r")) >= 0) {
rv = osBbFRead(fd, 0, buf, len);
osBbFClose(fd);
}
else {
rv = fd;
bzero(buf, len);
}
IO_WRITE(PI_FLASH_CTRL_REG, old); // Restore reg
return rv;
}
/*
* Saves the user defined data to the card. If a file with the
* specifed id already exists, that file will be overwritten.
* NOTE: skExit() should be called after all user defined data
* has been saved to force a save to card of the main game state.
* Parameters:
* buf - Data to write (must be 16 byte aligned)
* len - Length of the buffer, must be a multiple of 16K and <= 32K
* id - Aux Data ID (0-15)
* Returns: number of bytes saved if successful,
* <0 (see FS error codes) if unsuccessful
*/
s32
osBbAuxDataSave(u8 id, const void* buf, u32 len) {
s32 rv = 0;
char file_name[NAME_LEN];
int fd;
u32 old = IO_READ(PI_FLASH_CTRL_REG); // Save reg
if ((id < BB_MAX_AUXDATA) && (id >= osBbAuxDataGetLimit()))
return BBFS_ERR_STATE_LIMIT;
if (buf == NULL) return BBFS_ERR_INVALID;
if ((u32)buf&15) return BBFS_ERR_INVALID;
if (len > BB_MAX_AUXDATA_SIZE) return BBFS_ERR_INVALID;
if (len & (BB_FL_BLOCK_SIZE-1)) return BBFS_ERR_INVALID;
rv = __osBbGetAuxDataFilename(id, file_name);
if (rv < 0)
return rv; // No FS access yet
osBbFDelete(TMP_FILE);
if ((fd = osBbFCreate(TMP_FILE, 1, len)) >= 0) {
rv = osBbFWrite(fd, 0, buf, len);
osBbFClose(fd);
if (rv == len) {
rv = osBbFRename(TMP_FILE, file_name);
if (rv >= 0) {
rv = len;
}
}
else {
/* Something went wrong */
osBbFDelete(TMP_FILE);
if (rv >= 0) rv = BBFS_ERR_FAIL;
}
}
else rv = fd;
IO_WRITE(PI_FLASH_CTRL_REG, old); // Restore reg
return rv;
}
/*
* Remove the user defined data from the card
* Parameters:
* id - Aux Data ID (0-15)
* Returns: 0 if successful, <0 if unsuccessful
*/
s32
osBbAuxDataDelete(u8 id) {
s32 rv = 0;
char file_name[NAME_LEN];
u32 old = IO_READ(PI_FLASH_CTRL_REG); // Save reg
rv = __osBbGetAuxDataFilename(id, file_name);
if (rv < 0)
return rv; // No FS access yet
rv = osBbFDelete(file_name);
IO_WRITE(PI_FLASH_CTRL_REG, old); // Restore reg
return rv;
}
/* Limits the number of aux data files that a game can create */
/* Valid aux data ids are then restricted from 0 to limit-1 */
s32
osBbAuxDataSetLimit(u8 limit)
{
__osBbAuxDataLimit = (limit > BB_MAX_AUXDATA)? BB_MAX_AUXDATA: limit;
return __osBbAuxDataLimit;
}
s32
osBbAuxDataGetLimit()
{
/* __osBbAuxDataLimit added in version 2 */
if ( STASH_OKAY(__osBbStashMagic) &&
(STASH_VERSION(__osBbStashMagic) >= 2) )
return __osBbAuxDataLimit;
else return 0;
}