sdk-world v2026.11.05
PS2 SDK - world tier (copyleft-allowed, non-essential packages)
Loading...
Searching...
No Matches
mmce_fs.c
1#include <errno.h>
2#include <iomanX.h>
3#include <string.h>
4#include <tamtypes.h>
5
6#include "mmce_sio2.h"
7#include "mmce_cmds.h"
8
9#include "module_debug.h"
10
11#define MMCE_FS_MAX_FD 16
12#define MMCE_FS_WAIT_TIMEOUT 128000
13
14#define NOT_SUPPORTED_OP (void*)&not_supported_operation
15static int not_supported_operation() {
16 return -ENOTSUP;
17}
18
19static int mmce_fs_fds[MMCE_FS_MAX_FD];
20static int last_unit = -1;
21
22static int *mmce_fs_find_free_handle(void) {
23 for (int i = 0; i < MMCE_FS_MAX_FD; i++)
24 {
25 if (mmce_fs_fds[i] < 0)
26 return &mmce_fs_fds[i];
27 }
28 return NULL;
29}
30
31//Check last used port, update if needed
32static int mmce_fs_update_unit(int unit)
33{
34 int port = 2;
35
36 if (unit != last_unit) {
37 if (unit == 0)
38 port = 2;
39 else if (unit == 1)
40 port = 3;
41
42 last_unit = unit;
43
44 DPRINTF("Unit changed, unit: %i port: %i\n", unit, port);
45 mmce_sio2_set_port(port);
46 }
47
48 return 0;
49}
50
51int mmce_fs_init(iomanX_iop_device_t *f)
52{
53 DPRINTF("%s: init\n", __func__);
54 memset(mmce_fs_fds, -1, sizeof(mmce_fs_fds));
55 return 0;
56}
57
58int mmce_fs_deinit(iomanX_iop_device_t *f)
59{
60 return 0;
61}
62
63int mmce_fs_open(iomanX_iop_file_t *file, const char *name, int flags, int mode)
64{
65 int res;
66
67 u8 wrbuf[0x5];
68 u8 rdbuf[0x3];
69
70 DPRINTF("%s unit: %i name: %s flags: 0x%x\n", __func__, file->unit, name, flags);
71
72 //Update SIO2 port if unit changed ex mmce0: -> mmce1:
73 mmce_fs_update_unit(file->unit);
74
75 //Make sure theres file handles available
76 file->privdata = (int*)mmce_fs_find_free_handle();
77
78 if (file->privdata == NULL) {
79 DPRINTF("%s ERROR: No free file handles available\n", __func__);
80 return -1;
81 }
82
83 u8 packed_flags = 0;
84 u8 filename_len = strlen(name) + 1;
85
86 packed_flags = (flags & 3) - 1; //O_RDONLY, O_WRONLY, O_RDWR
87 packed_flags |= (flags & 0x100) >> 5; //O_APPEND
88 packed_flags |= (flags & 0xE00) >> 4; //O_CREATE, O_TRUNC, O_EXCL
89
90 wrbuf[0x0] = MMCE_ID; //Identifier
91 wrbuf[0x1] = MMCE_CMD_FS_OPEN; //Command
92 wrbuf[0x2] = MMCE_RESERVED; //Reserved
93 wrbuf[0x3] = packed_flags; //8 bit packed flags
94 wrbuf[0x4] = 0xff;
95
96 mmce_sio2_lock(); //Lock SIO2 for transfer
97
98 //Packet #1: Command and flags
99 res = mmce_sio2_tx_rx_pio(0x5, 0x2, wrbuf, rdbuf, &timeout_1s);
100 if (res == -1) {
101 DPRINTF("%s ERROR: P1 - Timedout waiting for /ACK\n", __func__);
102 mmce_sio2_unlock();
103 return -1;
104 }
105
106 if (rdbuf[0x1] != MMCE_REPLY_CONST) {
107 DPRINTF("%s ERROR: Invalid response from card. Got 0x%x, Expected 0x%x\n", __func__, rdbuf[0x1], MMCE_REPLY_CONST);
108 mmce_sio2_unlock();
109 return -1;
110 }
111
112 //Packet #2: Filename
113 res = mmce_sio2_tx_rx_pio(filename_len, 0x0, name, NULL, &timeout_1s);
114 if (res == -1) {
115 DPRINTF("%s ERROR: P2 - Timedout waiting for /ACK\n", __func__);
116 mmce_sio2_unlock();
117 return -1;
118 }
119
120 //Packet #3 - File descriptor
121 res = mmce_sio2_tx_rx_pio(0x0, 0x3, wrbuf, rdbuf, &timeout_1s);
122 mmce_sio2_unlock();
123 if (res == -1) {
124 DPRINTF("%s ERROR: P3 - Timedout waiting for /ACK\n", __func__);
125 return -1;
126 }
127
128 if (rdbuf[0x1] != 0xff) {
129 *(int*)file->privdata = rdbuf[0x1];
130 DPRINTF("%s Opened fd: %i\n", __func__, rdbuf[0x1]);
131 } else {
132 DPRINTF("%s ERROR: Got bad fd: %i\n", __func__, rdbuf[0x1]);
133 file->privdata = NULL;
134 return -1;
135 }
136
137 return 0;
138}
139
140int mmce_fs_close(iomanX_iop_file_t *file)
141{
142 int res = 0;
143
144 u8 wrbuf[0x4];
145 u8 rdbuf[0x6];
146
147 DPRINTF("%s fd: %i\n", __func__, (u8)*(int*)file->privdata);
148
149 mmce_fs_update_unit(file->unit);
150
151 //Reserved fds
152 if (*(int*)file->privdata >= 250)
153 return 0;
154
155 wrbuf[0x0] = MMCE_ID; //Identifier
156 wrbuf[0x1] = MMCE_CMD_FS_CLOSE; //Command
157 wrbuf[0x2] = MMCE_RESERVED; //Reserved
158 wrbuf[0x3] = (u8)*(int*)file->privdata; //File descriptor
159
160 //Packet #1: Command, file descriptor, return value
161 mmce_sio2_lock();
162 res = mmce_sio2_tx_rx_pio(0x4, 0x6, wrbuf, rdbuf, &timeout_1s);
163 mmce_sio2_unlock();
164
165 if (res == -1) {
166 DPRINTF("%s ERROR: P1 - Timedout waiting for /ACK\n", __func__);
167 return -1;
168 }
169
170 if (rdbuf[0x1] != MMCE_REPLY_CONST) {
171 DPRINTF("%s ERROR: Invalid response from card. Got 0x%x, Expected 0x%x\n", __func__, rdbuf[0x1], MMCE_REPLY_CONST);
172 return -1;
173 }
174
175 if (rdbuf[0x4] == 0x0) {
176 *(int*)file->privdata = -1;
177 } else {
178 res = rdbuf[0x4];
179 DPRINTF("%s ERROR: got return value %i\n", __func__, res);
180 }
181
182 return res;
183}
184
185int mmce_fs_read(iomanX_iop_file_t *file, void *ptr, int size)
186{
187 int res;
188 int bytes_read;
189
190 u8 wrbuf[0xA];
191 u8 rdbuf[0xA];
192
193 DPRINTF("%s fd: %i, size: %i\n", __func__, (u8)*(int*)file->privdata, size);
194
195 mmce_fs_update_unit(file->unit);
196
197 wrbuf[0x0] = MMCE_ID; //Identifier
198 wrbuf[0x1] = MMCE_CMD_FS_READ; //Command
199 wrbuf[0x2] = MMCE_RESERVED; //Reserved
200 wrbuf[0x3] = 0x0; //Transfer mode (unused)
201 wrbuf[0x4] = (u8)*(int*)file->privdata; //File Descriptor
202 wrbuf[0x5] = (size & 0xFF000000) >> 24; //Size
203 wrbuf[0x6] = (size & 0x00FF0000) >> 16;
204 wrbuf[0x7] = (size & 0x0000FF00) >> 8;
205 wrbuf[0x8] = (size & 0x000000FF);
206 wrbuf[0x9] = 0xff;
207
208 mmce_sio2_lock();
209
210 //Packet #1: Command, file descriptor, and size
211 res = mmce_sio2_tx_rx_pio(0xA, 0xA, wrbuf, rdbuf, &timeout_2s);
212 if (res == -1) {
213 DPRINTF("%s ERROR: P1 - Timedout waiting for /ACK\n", __func__);
214 mmce_sio2_unlock();
215 return -1;
216 }
217
218 if (rdbuf[0x1] != MMCE_REPLY_CONST) {
219 DPRINTF("%s ERROR: Invalid response from card. Got 0x%x, Expected 0x%x\n", __func__, rdbuf[0x1], MMCE_REPLY_CONST);
220 mmce_sio2_unlock();
221 return -1;
222 }
223
224 if (rdbuf[0x9] != 0x0) {
225 DPRINTF("%s ERROR: P1 - Got bad return value from card, res %i\n", __func__, rdbuf[0x9]);
226 mmce_sio2_unlock();
227 return -1;
228 }
229
230 //Packet #2 - n: Raw read data
231 res = mmce_sio2_rx_mixed(ptr, size);
232 if (res == -1) {
233 DPRINTF("%s ERROR: P2 - Timedout waiting for /ACK\n", __func__);
234 mmce_sio2_unlock();
235 return -1;
236 }
237
238 //Packet #n + 1: Bytes read
239 res = mmce_sio2_tx_rx_pio(0x0, 0x6, wrbuf, rdbuf, &timeout_1s);
240 if (res == -1) {
241 DPRINTF("%s ERROR: P3 - Timedout waiting for /ACK\n", __func__);
242 mmce_sio2_unlock();
243 return -1;
244 }
245
246 mmce_sio2_unlock();
247
248 bytes_read = rdbuf[0x1] << 24;
249 bytes_read |= rdbuf[0x2] << 16;
250 bytes_read |= rdbuf[0x3] << 8;
251 bytes_read |= rdbuf[0x4];
252
253 if (bytes_read != size) {
254 DPRINTF("%s WARN: bytes read: %i, expected: %i\n", __func__, bytes_read, size);
255
256 if (bytes_read > size)
257 bytes_read = size;
258
259 }
260
261 return bytes_read;
262}
263
264int mmce_fs_write(iomanX_iop_file_t *file, void *ptr, int size)
265{
266 int res;
267 int bytes_written;
268
269 u8 wrbuf[0xA];
270 u8 rdbuf[0xA];
271
272 DPRINTF("%s fd: %i, size: %i\n", __func__, (u8)*(int*)file->privdata, size);
273
274 mmce_fs_update_unit(file->unit);
275
276 wrbuf[0x0] = MMCE_ID; //Identifier
277 wrbuf[0x1] = MMCE_CMD_FS_WRITE; //Command
278 wrbuf[0x2] = MMCE_RESERVED; //Reserved
279 wrbuf[0x3] = 0x0; //Transfer mode (unused)
280 wrbuf[0x4] = (u8)*(int*)file->privdata; //File Descriptor
281 wrbuf[0x5] = (size & 0xFF000000) >> 24;
282 wrbuf[0x6] = (size & 0x00FF0000) >> 16;
283 wrbuf[0x7] = (size & 0x0000FF00) >> 8;
284 wrbuf[0x8] = (size & 0x000000FF);
285 wrbuf[0x9] = 0xff;
286
287 mmce_sio2_lock();
288
289 //Packet #1: Command, file descriptor, and size
290 res = mmce_sio2_tx_rx_pio(0xA, 0xA, wrbuf, rdbuf, &timeout_1s);
291 if (res == -1) {
292 DPRINTF("%s ERROR: P1 - Timedout waiting for /ACK\n", __func__);
293 mmce_sio2_unlock();
294 return -1;
295 }
296
297 if (rdbuf[0x1] != MMCE_REPLY_CONST) {
298 DPRINTF("%s ERROR: Invalid response from card. Got 0x%x, Expected 0x%x\n", __func__, rdbuf[0x1], MMCE_REPLY_CONST);
299 mmce_sio2_unlock();
300 return -1;
301 }
302
303 if (rdbuf[0x9] != 0x0) {
304 DPRINTF("%s ERROR: P1 - Got bad return value from card 0x%x\n", __func__, rdbuf[0x9]);
305 mmce_sio2_unlock();
306 return -1;
307 }
308
309 //Packet #2 - n: Raw write data
310 res = mmce_sio2_tx_mixed(ptr, size);
311 if (res == -1) {
312 DPRINTF("%s ERROR: P2 - Timedout waiting for /ACK\n", __func__);
313 mmce_sio2_unlock();
314 return -1;
315 }
316
317 //Packets #n + 1: Bytes written
318 res = mmce_sio2_tx_rx_pio(0x0, 0x6, wrbuf, rdbuf, &timeout_1s);
319 if (res == -1) {
320 DPRINTF("%s ERROR: P3 - Timedout waiting for /ACK\n", __func__);
321 mmce_sio2_unlock();
322 return -1;
323 }
324
325 mmce_sio2_unlock();
326
327 bytes_written = rdbuf[0x1] << 24;
328 bytes_written |= rdbuf[0x2] << 16;
329 bytes_written |= rdbuf[0x3] << 8;
330 bytes_written |= rdbuf[0x4];
331
332 if (bytes_written != size) {
333 DPRINTF("%s bytes written: %i, expected: %i\n", __func__, bytes_written, size);
334 }
335
336 return bytes_written;
337}
338
339int mmce_fs_lseek(iomanX_iop_file_t *file, int offset, int whence)
340{
341 int res;
342 int position = -1;
343
344 u8 wrbuf[0x9];
345 u8 rdbuf[0xe];
346
347 DPRINTF("%s fd: %i, offset: %i, whence: %i\n", __func__, (u8)*(int*)file->privdata, offset, whence);
348
349 mmce_fs_update_unit(file->unit);
350
351 wrbuf[0x0] = MMCE_ID; //Identifier
352 wrbuf[0x1] = MMCE_CMD_FS_LSEEK; //Command
353 wrbuf[0x2] = MMCE_RESERVED; //Reserved
354 wrbuf[0x3] = (u8)(*(int*)file->privdata); //File descriptor
355 wrbuf[0x4] = (offset & 0xFF000000) >> 24; //Offset
356 wrbuf[0x5] = (offset & 0x00FF0000) >> 16;
357 wrbuf[0x6] = (offset & 0x0000FF00) >> 8;
358 wrbuf[0x7] = (offset & 0x000000FF);
359 wrbuf[0x8] = (u8)(whence); //Whence
360
361 //Packet #1: Command, file descriptor, offset, and whence
362 mmce_sio2_lock();
363 res = mmce_sio2_tx_rx_pio(0x9, 0xe, wrbuf, rdbuf, &timeout_1s);
364 mmce_sio2_unlock();
365
366 if (res == -1) {
367 DPRINTF("%s ERROR: P1 - Timedout waiting for /ACK\n", __func__);
368 return -1;
369 }
370
371 if (rdbuf[0x1] != MMCE_REPLY_CONST) {
372 DPRINTF("%s ERROR: Invalid response from card. Got 0x%x, Expected 0x%x\n", __func__, rdbuf[0x1], MMCE_REPLY_CONST);
373 return -1;
374 }
375
376 position = rdbuf[0x9] << 24;
377 position |= rdbuf[0xa] << 16;
378 position |= rdbuf[0xb] << 8;
379 position |= rdbuf[0xc];
380
381 DPRINTF("%s position %i\n", __func__, position);
382
383 return position;
384}
385
386int mmce_fs_ioctl(iomanX_iop_file_t *file, int cmd, void *data)
387{
388 return 0;
389}
390
391/*Note: Due to a bug in FILEIO, mkdir will be called after remove unless
392 sbv_patch_fileio is used. See ps2sdk/ee/sbv/src/patch_fileio.c */
393int mmce_fs_remove(iomanX_iop_file_t *file, const char *name)
394{
395 int res;
396
397 u8 wrbuf[0x4];
398 u8 rdbuf[0x3];
399
400 DPRINTF("%s name: %s\n", __func__, name);
401
402 mmce_fs_update_unit(file->unit);
403
404 u8 filename_len = strlen(name) + 1;
405
406 wrbuf[0x0] = MMCE_ID; //Identifier
407 wrbuf[0x1] = MMCE_CMD_FS_REMOVE; //Command
408 wrbuf[0x2] = MMCE_RESERVED; //Reserved
409 wrbuf[0x3] = 0xff;
410
411 mmce_sio2_lock();
412
413 //Packet #1: Command
414 res = mmce_sio2_tx_rx_pio(0x4, 0x2, wrbuf, rdbuf, &timeout_1s);
415 if (res == -1) {
416 DPRINTF("%s ERROR: P1 - Timedout waiting for /ACK\n", __func__);
417 mmce_sio2_unlock();
418 return -1;
419 }
420
421 if (rdbuf[0x1] != MMCE_REPLY_CONST) {
422 DPRINTF("%s ERROR: Invalid response from card. Got 0x%x, Expected 0x%x\n", __func__, rdbuf[0x1], MMCE_REPLY_CONST);
423 mmce_sio2_unlock();
424 return -1;
425 }
426
427 //Packet #2: Filename
428 res = mmce_sio2_tx_rx_pio(filename_len, 0x0, name, NULL, &timeout_1s);
429 if (res == -1) {
430 DPRINTF("%s ERROR: P2 - Timedout waiting for /ACK\n", __func__);
431 mmce_sio2_unlock();
432 return -1;
433 }
434
435 //Packet #3: Return value
436 res = mmce_sio2_tx_rx_pio(0x0, 0x3, NULL, rdbuf, &timeout_1s);
437 mmce_sio2_unlock();
438
439 if (res == -1) {
440 DPRINTF("%s ERROR: P3 - Timedout waiting for /ACK\n", __func__);
441 return -1;
442 }
443
444 if (rdbuf[0x1] != 0x0) {
445 DPRINTF("%s ERROR: Card failed to remove %s, return value %i\n", __func__, name, rdbuf[0x1]);
446 return -1;
447 }
448
449 return 0;
450}
451
452int mmce_fs_mkdir(iomanX_iop_file_t *file, const char *name, int flags)
453{
454 int res;
455
456 u8 wrbuf[0x4];
457 u8 rdbuf[0x3];
458
459 DPRINTF("%s name: %s\n", __func__, name);
460
461 mmce_fs_update_unit(file->unit);
462
463 u8 dir_len = strlen(name) + 1;
464
465 wrbuf[0x0] = MMCE_ID; //Identifier
466 wrbuf[0x1] = MMCE_CMD_FS_MKDIR; //Command
467 wrbuf[0x2] = MMCE_RESERVED; //Reserved
468 wrbuf[0x3] = 0xff;
469
470 mmce_sio2_lock();
471
472 //Packet #1: Command
473 res = mmce_sio2_tx_rx_pio(0x4, 0x2, wrbuf, rdbuf, &timeout_1s);
474 if (res == -1) {
475 DPRINTF("%s ERROR: P1 - Timedout waiting for /ACK\n", __func__);
476 mmce_sio2_unlock();
477 return -1;
478 }
479
480 if (rdbuf[0x1] != MMCE_REPLY_CONST) {
481 DPRINTF("%s ERROR: Invalid response from card. Got 0x%x, Expected 0x%x\n", __func__, rdbuf[0x1], MMCE_REPLY_CONST);
482 mmce_sio2_unlock();
483 return -1;
484 }
485
486 //Packet #2: Dirname
487 res = mmce_sio2_tx_rx_pio(dir_len, 0x0, name, NULL, &timeout_1s);
488 if (res == -1) {
489 DPRINTF("%s ERROR: P2 - Timedout waiting for /ACK\n", __func__);
490 mmce_sio2_unlock();
491 return -1;
492 }
493
494 //Packet #3: Return value
495 res = mmce_sio2_tx_rx_pio(0x0, 0x3, NULL, rdbuf, &timeout_1s);
496 mmce_sio2_unlock();
497
498 if (res == -1) {
499 DPRINTF("%s ERROR: P3 - Timedout waiting for /ACK\n", __func__);
500 return -1;
501 }
502
503 if (rdbuf[0x1] != 0x0) {
504 DPRINTF("%s ERROR: Card failed to mkdir %s, return value %i\n", __func__, name, rdbuf[0x1]);
505 return -1;
506 }
507
508 return 0;
509}
510
511int mmce_fs_rmdir(iomanX_iop_file_t *file, const char *name)
512{
513 int res;
514
515 u8 wrbuf[0x4];
516 u8 rdbuf[0x3];
517
518 DPRINTF("%s name: %s\n", __func__, name);
519
520 mmce_fs_update_unit(file->unit);
521
522 u8 dir_len = strlen(name) + 1;
523
524 wrbuf[0x0] = MMCE_ID; //Identifier
525 wrbuf[0x1] = MMCE_CMD_FS_RMDIR; //Command
526 wrbuf[0x2] = MMCE_RESERVED; //Reserved
527 wrbuf[0x3] = 0xff;
528
529 mmce_sio2_lock();
530
531 //Packet #1: Command
532 res = mmce_sio2_tx_rx_pio(0x4, 0x2, wrbuf, rdbuf, &timeout_1s);
533 if (res == -1) {
534 DPRINTF("%s ERROR: P1 - Timedout waiting for /ACK\n", __func__);
535 mmce_sio2_unlock();
536 return -1;
537 }
538
539 if (rdbuf[0x1] != MMCE_REPLY_CONST) {
540 DPRINTF("%s ERROR: Invalid response from card. Got 0x%x, Expected 0x%x\n", __func__, rdbuf[0x1], MMCE_REPLY_CONST);
541 mmce_sio2_unlock();
542 return -1;
543 }
544
545 //Packet #2: Dirname
546 res = mmce_sio2_tx_rx_pio(dir_len, 0x0, name, NULL, &timeout_1s);
547 if (res == -1) {
548 DPRINTF("%s ERROR: P2 - Timedout waiting for /ACK\n", __func__);
549 mmce_sio2_unlock();
550 return -1;
551 }
552
553 //Packet #3: Return value
554 res = mmce_sio2_tx_rx_pio(0x0, 0x3, NULL, rdbuf, &timeout_1s);
555 mmce_sio2_unlock();
556
557 if (res == -1) {
558 DPRINTF("%s ERROR: P3 - Timedout waiting for /ACK\n", __func__);
559 return -1;
560 }
561
562 if (rdbuf[0x1] != 0x0) {
563 DPRINTF("%s ERROR: Card failed to rmdir %s, return value %i\n", __func__, name, rdbuf[0x1]);
564 return -1;
565 }
566
567 return 0;
568}
569
570int mmce_fs_dopen(iomanX_iop_file_t *file, const char *name)
571{
572 int res;
573
574 u8 wrbuf[0x5];
575 u8 rdbuf[0x3];
576
577 DPRINTF("%s name: %s\n", __func__, name);
578
579 mmce_fs_update_unit(file->unit);
580
581 file->privdata = (int*)mmce_fs_find_free_handle();
582
583 if (file->privdata == NULL) {
584 DPRINTF("%s ERROR: No free file handles available\n", __func__);
585 return -1;
586 }
587
588 u8 dir_len = strlen(name) + 1;
589
590 wrbuf[0x0] = MMCE_ID; //Identifier
591 wrbuf[0x1] = MMCE_CMD_FS_DOPEN; //Command
592 wrbuf[0x2] = MMCE_RESERVED; //Reserved
593 wrbuf[0x3] = 0xff;
594
595 mmce_sio2_lock();
596
597 //Packet #1: Command
598 res = mmce_sio2_tx_rx_pio(0x4, 0x2, wrbuf, rdbuf, &timeout_1s);
599 if (res == -1) {
600 DPRINTF("%s ERROR: P1 - Timedout waiting for /ACK\n", __func__);
601 mmce_sio2_unlock();
602 return -1;
603 }
604
605 if (rdbuf[0x1] != MMCE_REPLY_CONST) {
606 DPRINTF("%s ERROR: Invalid response from card. Got 0x%x, Expected 0x%x\n", __func__, rdbuf[0x1], MMCE_REPLY_CONST);
607 mmce_sio2_unlock();
608 return -1;
609 }
610
611 //Packet #2: Dirname
612 res = mmce_sio2_tx_rx_pio(dir_len, 0x0, name, NULL, &timeout_1s);
613 if (res == -1) {
614 DPRINTF("%s ERROR: P2 - Timedout waiting for /ACK\n", __func__);
615 mmce_sio2_unlock();
616 return -1;
617 }
618
619 //Packet #n + 1: File descriptor
620 res = mmce_sio2_tx_rx_pio(0x0, 0x3, NULL, rdbuf, &timeout_1s);
621 mmce_sio2_unlock();
622
623 if (res == -1) {
624 DPRINTF("%s ERROR: P3 - Timedout waiting for /ACK\n", __func__);
625 return -1;
626 }
627
628 if (rdbuf[0x1] != 0xff) {
629 *(int*)file->privdata = rdbuf[0x1];
630 } else {
631 DPRINTF("%s ERROR: Got invalid fd: %i\n", __func__, rdbuf[0x1]);
632 file->privdata = NULL;
633 return -1;
634 }
635
636 return 0;
637}
638
639int mmce_fs_dclose(iomanX_iop_file_t *file)
640{
641 int res;
642
643 u8 wrbuf[0x5];
644 u8 rdbuf[0x6];
645
646 mmce_fs_update_unit(file->unit);
647
648 wrbuf[0x0] = MMCE_ID; //Identifier
649 wrbuf[0x1] = MMCE_CMD_FS_DCLOSE; //Command
650 wrbuf[0x2] = MMCE_RESERVED; //Reserved
651 wrbuf[0x3] = (u8)*(int*)file->privdata; //File descriptor
652
653 DPRINTF("%s fd: %i\n", __func__, (u8)*(int*)file->privdata);
654
655 //Packet #1: Command and file descriptor
656 mmce_sio2_lock();
657 res = mmce_sio2_tx_rx_pio(0x4, 0x6, wrbuf, rdbuf, &timeout_1s);
658 mmce_sio2_unlock();
659
660 if (res == -1) {
661 DPRINTF("%s ERROR: P1 - Timedout waiting for /ACK\n", __func__);
662 return -1;
663 }
664
665 if (rdbuf[0x1] != MMCE_REPLY_CONST) {
666 DPRINTF("%s ERROR: Invalid response from card. Got 0x%x, Expected 0x%x\n", __func__, rdbuf[0x1], MMCE_REPLY_CONST);
667 return -1;
668 }
669
670 if (rdbuf[0x4] != 0x0) {
671 DPRINTF("%s ERROR: Card failed to close dir %i, return value %i\n", __func__, (u8)*(int*)file->privdata, rdbuf[0x1]);
672 return -1;
673 }
674
675 *(int*)file->privdata = -1;
676 file->privdata = NULL;
677
678 return 0;
679}
680
681int mmce_fs_dread(iomanX_iop_file_t *file, iox_dirent_t *dirent)
682{
683 int res;
684
685 u8 wrbuf[0x5];
686 u8 rdbuf[0x2B];
687
688 DPRINTF("%s fd: %i\n", __func__, (u8)*(int*)file->privdata);
689
690 mmce_fs_update_unit(file->unit);
691
692 u8 filename_len = 0;
693
694 wrbuf[0x0] = MMCE_ID; //Identifier
695 wrbuf[0x1] = MMCE_CMD_FS_DREAD; //Command
696 wrbuf[0x2] = MMCE_RESERVED; //Reserved
697 wrbuf[0x3] = (u8)*(int*)file->privdata; //File descriptor
698 wrbuf[0x4] = 0xff;
699
700 DPRINTF("%s fd: %i\n", __func__, (u8)*(int*)file->privdata);
701
702 mmce_sio2_lock();
703
704 //Packet #1: Command and file descriptor
705 res = mmce_sio2_tx_rx_pio(0x5, 0x5, wrbuf, rdbuf, &timeout_1s);
706 if (res == -1) {
707 DPRINTF("%s ERROR: P1 - Timedout waiting for /ACK\n", __func__);
708 mmce_sio2_unlock();
709 return -1;
710 }
711
712 if (rdbuf[0x1] != MMCE_REPLY_CONST) {
713 DPRINTF("%s ERROR: Invalid response from card. Got 0x%x, Expected 0x%x\n", __func__, rdbuf[0x1], MMCE_REPLY_CONST);
714 mmce_sio2_unlock();
715 return -1;
716 }
717
718 if (rdbuf[0x4] != 0) {
719 DPRINTF("%s ERROR: Returned %i, Expected 0\n", __func__, rdbuf[0x4]);
720 mmce_sio2_unlock();
721 return -1;
722 }
723
724 //Packet #n + 1: io_stat_t and filename len
725 res = mmce_sio2_tx_rx_pio(0x0, 0x2A, NULL, rdbuf, &timeout_1s);
726 if (res == -1) {
727 DPRINTF("%s ERROR: P3 - Timedout waiting for /ACK\n", __func__);
728 mmce_sio2_unlock();
729 return -1;
730 }
731
732 //Could cast but not sure about alignment?
733 dirent->stat.mode = rdbuf[0x1] << 24;
734 dirent->stat.mode |= rdbuf[0x2] << 16;
735 dirent->stat.mode |= rdbuf[0x3] << 8;
736 dirent->stat.mode |= rdbuf[0x4];
737
738 dirent->stat.attr = rdbuf[0x5] << 24;
739 dirent->stat.attr |= rdbuf[0x6] << 16;
740 dirent->stat.attr |= rdbuf[0x7] << 8;
741 dirent->stat.attr |= rdbuf[0x8];
742
743 dirent->stat.size = rdbuf[0x9] << 24;
744 dirent->stat.size |= rdbuf[0xA] << 16;
745 dirent->stat.size |= rdbuf[0xB] << 8;
746 dirent->stat.size |= rdbuf[0xC];
747
748 dirent->stat.ctime[0] = rdbuf[0xD];
749 dirent->stat.ctime[1] = rdbuf[0xE];
750 dirent->stat.ctime[2] = rdbuf[0xF];
751 dirent->stat.ctime[3] = rdbuf[0x10];
752 dirent->stat.ctime[4] = rdbuf[0x11];
753 dirent->stat.ctime[5] = rdbuf[0x12];
754 dirent->stat.ctime[6] = rdbuf[0x13];
755 dirent->stat.ctime[7] = rdbuf[0x14];
756
757 dirent->stat.atime[0] = rdbuf[0x15];
758 dirent->stat.atime[1] = rdbuf[0x16];
759 dirent->stat.atime[2] = rdbuf[0x17];
760 dirent->stat.atime[3] = rdbuf[0x18];
761 dirent->stat.atime[4] = rdbuf[0x19];
762 dirent->stat.atime[5] = rdbuf[0x1A];
763 dirent->stat.atime[6] = rdbuf[0x1B];
764 dirent->stat.atime[7] = rdbuf[0x1C];
765
766 dirent->stat.mtime[0] = rdbuf[0x1D];
767 dirent->stat.mtime[1] = rdbuf[0x1E];
768 dirent->stat.mtime[2] = rdbuf[0x1F];
769 dirent->stat.mtime[3] = rdbuf[0x20];
770 dirent->stat.mtime[4] = rdbuf[0x21];
771 dirent->stat.mtime[5] = rdbuf[0x22];
772 dirent->stat.mtime[6] = rdbuf[0x23];
773 dirent->stat.mtime[7] = rdbuf[0x24];
774
775 dirent->stat.hisize = rdbuf[0x25] << 24;
776 dirent->stat.hisize |= rdbuf[0x26] << 16;
777 dirent->stat.hisize |= rdbuf[0x27] << 8;
778 dirent->stat.hisize |= rdbuf[0x28];
779
780 filename_len = rdbuf[0x29];
781
782 //Packet #n + 2: Filename
783 res = mmce_sio2_tx_rx_pio(0x0, filename_len, NULL, dirent->name, &timeout_1s);
784 if (res == -1) {
785 DPRINTF("%s ERROR: P4 - Timedout waiting for /ACK\n", __func__);
786 mmce_sio2_unlock();
787 return -1;
788 }
789
790 //Packet #n + 3: Padding, resevered, and term
791 res = mmce_sio2_tx_rx_pio(0x0, 0x3, NULL, rdbuf, &timeout_1s);
792 if (res == -1) {
793 DPRINTF("%s ERROR: P5 - Timedout waiting for /ACK\n", __func__);
794 mmce_sio2_unlock();
795 return -1;
796 }
797
798 mmce_sio2_unlock();
799
800 return rdbuf[0x1]; //itr fd from mmce
801}
802
803int mmce_fs_getstat(iomanX_iop_file_t *file, const char *name, iox_stat_t *stat)
804{
805 int res;
806
807 u8 wrbuf[0xFF];
808 u8 rdbuf[0x2B];
809
810 u8 len = strlen(name) + 1;
811
812 DPRINTF("%s filename: %s\n", __func__, name);
813
814 mmce_fs_update_unit(file->unit);
815
816 wrbuf[0x0] = MMCE_ID; //Identifier
817 wrbuf[0x1] = MMCE_CMD_FS_GETSTAT; //Command
818 wrbuf[0x2] = MMCE_RESERVED; //Reserved
819
820 mmce_sio2_lock();
821
822 //Packet #1: Command and padding
823 res = mmce_sio2_tx_rx_pio(0x4, 0x4, wrbuf, rdbuf, &timeout_1s);
824 if (res == -1) {
825 DPRINTF("%s ERROR: P1 - Timedout waiting for /ACK\n", __func__);
826 mmce_sio2_unlock();
827 return -1;
828 }
829
830 if (rdbuf[0x1] != MMCE_REPLY_CONST) {
831 DPRINTF("%s ERROR: Invalid response from card. Got 0x%x, Expected 0x%x\n", __func__, rdbuf[0x1], MMCE_REPLY_CONST);
832 mmce_sio2_unlock();
833 return -1;
834 }
835
836 //Packet #2: Filename
837 res = mmce_sio2_tx_rx_pio(len, 0x0, name, NULL, &timeout_1s);
838 if (res == -1) {
839 DPRINTF("%s ERROR: P2 - Timedout waiting for /ACK\n", __func__);
840 mmce_sio2_unlock();
841 return -1;
842 }
843
844 //Packet #n + 1: io_stat_t and term
845 res = mmce_sio2_tx_rx_pio(0x0, 0x2b, NULL, rdbuf, &timeout_1s);
846 if (res == -1) {
847 DPRINTF("%s ERROR: P4 - Timedout waiting for /ACK\n", __func__);
848 mmce_sio2_unlock();
849 return -1;
850 }
851
852 mmce_sio2_unlock();
853
854 //Could cast but not sure about alignment?
855 stat->mode = rdbuf[0x1] << 24;
856 stat->mode |= rdbuf[0x2] << 16;
857 stat->mode |= rdbuf[0x3] << 8;
858 stat->mode |= rdbuf[0x4];
859
860 stat->attr = rdbuf[0x5] << 24;
861 stat->attr |= rdbuf[0x6] << 16;
862 stat->attr |= rdbuf[0x7] << 8;
863 stat->attr |= rdbuf[0x8];
864
865 stat->size = rdbuf[0x9] << 24;
866 stat->size |= rdbuf[0xA] << 16;
867 stat->size |= rdbuf[0xB] << 8;
868 stat->size |= rdbuf[0xC];
869
870 stat->ctime[0] = rdbuf[0xD];
871 stat->ctime[1] = rdbuf[0xE];
872 stat->ctime[2] = rdbuf[0xF];
873 stat->ctime[3] = rdbuf[0x10];
874 stat->ctime[4] = rdbuf[0x11];
875 stat->ctime[5] = rdbuf[0x12];
876 stat->ctime[6] = rdbuf[0x13];
877 stat->ctime[7] = rdbuf[0x14];
878
879 stat->atime[0] = rdbuf[0x15];
880 stat->atime[1] = rdbuf[0x16];
881 stat->atime[2] = rdbuf[0x17];
882 stat->atime[3] = rdbuf[0x18];
883 stat->atime[4] = rdbuf[0x19];
884 stat->atime[5] = rdbuf[0x1A];
885 stat->atime[6] = rdbuf[0x1B];
886 stat->atime[7] = rdbuf[0x1C];
887
888 stat->mtime[0] = rdbuf[0x1D];
889 stat->mtime[1] = rdbuf[0x1E];
890 stat->mtime[2] = rdbuf[0x1F];
891 stat->mtime[3] = rdbuf[0x20];
892 stat->mtime[4] = rdbuf[0x21];
893 stat->mtime[5] = rdbuf[0x22];
894 stat->mtime[6] = rdbuf[0x23];
895 stat->mtime[7] = rdbuf[0x24];
896
897 stat->hisize = rdbuf[0x25] << 24;
898 stat->hisize |= rdbuf[0x26] << 16;
899 stat->hisize |= rdbuf[0x27] << 8;
900 stat->hisize |= rdbuf[0x28];
901
902 if (rdbuf[0x29] != 0) {
903 DPRINTF("Got bad return: %i\n", rdbuf[0x29]);
904 return -1;
905 } else {
906 DPRINTF("Got good return\n");
907 }
908
909 return 0;
910}
911
912s64 mmce_fs_lseek64(iomanX_iop_file_t *file, s64 offset, int whence)
913{
914 int res;
915 s64 position = -1;
916
917 u8 wrbuf[0xd];
918 u8 rdbuf[0x16];
919
920 DPRINTF("%s fd: %i, whence: %i\n", __func__, (u8)*(int*)file->privdata, whence);
921
922 mmce_fs_update_unit(file->unit);
923
924 wrbuf[0x0] = MMCE_ID; //Identifier
925 wrbuf[0x1] = MMCE_CMD_FS_LSEEK64; //Command
926 wrbuf[0x2] = MMCE_RESERVED; //Reserved
927 wrbuf[0x3] = (u8)(*(int*)file->privdata); //File descriptor
928
929 wrbuf[0x4] = (offset & 0xFF00000000000000) >> 56; //Offset
930 wrbuf[0x5] = (offset & 0x00FF000000000000) >> 48;
931 wrbuf[0x6] = (offset & 0x0000FF0000000000) >> 40;
932 wrbuf[0x7] = (offset & 0x000000FF00000000) >> 32;
933 wrbuf[0x8] = (offset & 0x00000000FF000000) >> 24;
934 wrbuf[0x9] = (offset & 0x0000000000FF0000) >> 16;
935 wrbuf[0xa] = (offset & 0x000000000000FF00) >> 8;
936 wrbuf[0xb] = (offset & 0x00000000000000FF);
937 wrbuf[0xc] = (u8)(whence); //Whence
938
939 //Packet #1: Command, file descriptor, offset, and whence
940 mmce_sio2_lock();
941 res = mmce_sio2_tx_rx_pio(0xd, 0x16, wrbuf, rdbuf, &timeout_1s);
942 mmce_sio2_unlock();
943 if (res == -1) {
944 DPRINTF("%s ERROR: P1 - Timedout waiting for /ACK\n", __func__);
945 return -1;
946 }
947
948 if (rdbuf[0x1] != MMCE_REPLY_CONST) {
949 DPRINTF("%s ERROR: Invalid response from card. Got 0x%x, Expected 0x%x\n", __func__, rdbuf[0x1], MMCE_REPLY_CONST);
950 return -1;
951 }
952
953 position = (s64)rdbuf[0xd] << 56;
954 position |= (s64)rdbuf[0xe] << 48;
955 position |= (s64)rdbuf[0xf] << 40;
956 position |= (s64)rdbuf[0x10] << 32;
957 position |= (s64)rdbuf[0x11] << 24;
958 position |= (s64)rdbuf[0x12] << 16;
959 position |= (s64)rdbuf[0x13] << 8;
960 position |= (s64)rdbuf[0x14];
961
962 return position;
963}
964
965int mmce_fs_devctl(iomanX_iop_file_t *fd, const char *name, int cmd, void *arg, unsigned int arglen, void *buf, unsigned int buflen)
966{
967 int res = 0;
968
969 int type;
970 int mode;
971 int num;
972
973 int args;
974
975 DPRINTF("%s cmd: %i, arglen, buflen: %i\n", __func__, cmd, arglen, buflen);
976
977 mmce_fs_update_unit(fd->unit);
978
979 switch (cmd) {
980 case MMCE_CMD_PING:
981 res = mmce_cmd_ping();
982 break;
983
984 case MMCE_CMD_GET_STATUS:
985 res = mmce_cmd_get_status();
986 break;
987
988 case MMCE_CMD_GET_CARD:
989 res = mmce_cmd_get_card();
990 break;
991
992 case MMCE_CMD_SET_CARD:
993 args = *(u32*)arg;
994 type = (args & 0xff000000) >> 24;
995 mode = (args & 0x00ff0000) >> 16;
996 num = (args & 0x0000ffff);
997
998 res = mmce_cmd_set_card(type, mode, num);
999 break;
1000
1001 case MMCE_CMD_GET_CHANNEL:
1002 res = mmce_cmd_get_channel();
1003 break;
1004
1005 case MMCE_CMD_SET_CHANNEL:
1006 args = *(u32*)arg;
1007 mode = (args & 0x00ff0000) >> 16;
1008 num = (args & 0x0000ffff);
1009 res = mmce_cmd_set_channel(mode, num);
1010 break;
1011
1012 case MMCE_CMD_GET_GAMEID:
1013 res = mmce_cmd_get_gameid(buf);
1014 break;
1015
1016 case MMCE_CMD_SET_GAMEID:
1017 char *str = (char*)arg;
1018 res = mmce_cmd_set_gameid(str);
1019 break;
1020
1021 case MMCE_CMD_RESET:
1022 res = mmce_cmd_reset();
1023 break;
1024
1025 case MMCE_SETTINGS_ACK_WAIT_CYCLES:
1026 args = *(u32*)arg;
1027 mmce_sio2_update_ack_wait_cycles(args);
1028 break;
1029
1030 case MMCE_SETTINGS_SET_ALARMS:
1031 args = *(u32*)arg;
1032 mmce_sio2_set_use_alarm(args);
1033 break;
1034
1035 default:
1036 break;
1037 }
1038
1039 return res;
1040}
1041
1042int mmce_fs_ioctl2(iomanX_iop_file_t *file, int cmd, void *arg, unsigned int arglen, void *data, unsigned int datalen)
1043{
1044 int res = 0;
1045
1046 switch(cmd) {
1047 //TEMP: Used to get iop side fd of a file
1048 case MMCE_CMD_IOCTL_GET_FD:
1049 res = (u8)*(int*)file->privdata;
1050 break;
1051 default:
1052 }
1053
1054 return res;
1055}
1056
1057static iomanX_iop_device_ops_t mmce_fio_ops =
1058{
1059 &mmce_fs_init, //init
1060 &mmce_fs_deinit, //deinit
1061 NOT_SUPPORTED_OP, //format
1062 &mmce_fs_open, //open
1063 &mmce_fs_close, //close
1064 &mmce_fs_read, //read
1065 &mmce_fs_write, //write
1066 &mmce_fs_lseek, //lseek
1067 &mmce_fs_ioctl, //ioctl
1068 &mmce_fs_remove, //remove
1069 &mmce_fs_mkdir, //mkdir
1070 &mmce_fs_rmdir, //rmdir
1071 &mmce_fs_dopen, //dopen
1072 &mmce_fs_dclose, //dclose
1073 &mmce_fs_dread, //dread
1074 &mmce_fs_getstat, //getstat
1075 NOT_SUPPORTED_OP, //chstat
1076 //EXTENDED OPS
1077 NOT_SUPPORTED_OP, //rename
1078 NOT_SUPPORTED_OP, //chdir
1079 NOT_SUPPORTED_OP, //sync
1080 NOT_SUPPORTED_OP, //mount
1081 NOT_SUPPORTED_OP, //umount
1082 &mmce_fs_lseek64, //lseek64
1083 &mmce_fs_devctl, //devctl
1084 NOT_SUPPORTED_OP, //symlink
1085 NOT_SUPPORTED_OP, //readlink
1086 &mmce_fs_ioctl2, //ioctl2
1087};
1088
1089static iomanX_iop_device_t mmce_dev =
1090{
1091 "mmce",
1092 (IOP_DT_FS | IOP_DT_FSEXT),
1093 1,
1094 "Filesystem access mmce",
1095 &mmce_fio_ops, //fill this with an instance of iomanX_iop_device_ops
1096};
1097
1098int mmce_fs_register(void) {
1099 DPRINTF("Registering %s device\n", mmce_dev.name);
1100 iomanX_DelDrv(mmce_dev.name);
1101
1102 if (iomanX_AddDrv(&mmce_dev)!= 0)
1103 return 0;
1104
1105 return 1;
1106}
1107
1108int mmce_fs_unregister(void) {
1109 iomanX_DelDrv(mmce_dev.name);
1110 return 0;
1111}