sdk-world v2026.11.05
PS2 SDK - world tier (copyleft-allowed, non-essential packages)
Loading...
Searching...
No Matches
mmcedrv.c
1#include <intrman.h>
2#include <stdio.h>
3#include <string.h>
4#include <sysclib.h>
5
6#include "ioplib.h"
7#include "irx_imports.h"
8
9#include "mmce_cmds.h"
10#include "mmce_fs.h"
11#include "mmce_sio2.h"
12#include "mmcedrv_config.h"
13#include "sio2man_hook.h"
14
15#include "module_debug.h"
16
17#define MAJOR 0
18#define MINOR 1
19
20IRX_ID("mmcedrv", MAJOR, MINOR);
21
22extern struct irx_export_table _exp_mmcedrv;
23
24s64 mmcedrv_get_size(int fd)
25{
26 int res;
27 s64 position = -1;
28
29 u8 wrbuf[0xd];
30 u8 rdbuf[0x16];
31
32 wrbuf[0x0] = MMCE_ID; //Identifier
33 wrbuf[0x1] = MMCE_CMD_FS_LSEEK64; //Command
34 wrbuf[0x2] = MMCE_RESERVED; //Reserved
35 wrbuf[0x3] = fd; //File descriptor
36
37 wrbuf[0x4] = 0; //Offset
38 wrbuf[0x5] = 0;
39 wrbuf[0x6] = 0;
40 wrbuf[0x7] = 0;
41 wrbuf[0x8] = 0;
42 wrbuf[0x9] = 0;
43 wrbuf[0xa] = 0;
44 wrbuf[0xb] = 0;
45
46 wrbuf[0xc] = 2; //Whence SEEK_END
47
48 //Packet #1: Command, file descriptor, offset, and whence
49 mmce_sio2_lock();
50 res = mmce_sio2_tx_rx_pio(0xd, 0x16, wrbuf, rdbuf, &timeout_1s);
51 mmce_sio2_unlock();
52 if (res == -1) {
53 DPRINTF("%s ERROR: P1 - Timedout waiting for /ACK\n", __func__);
54 return -1;
55 }
56
57 if (rdbuf[0x1] != MMCE_REPLY_CONST) {
58 DPRINTF("%s ERROR: Invalid response from card. Got 0x%x, Expected 0x%x\n", __func__, rdbuf[0x1], MMCE_REPLY_CONST);
59 return -1;
60 }
61
62 position = (s64)rdbuf[0xd] << 56;
63 position |= (s64)rdbuf[0xe] << 48;
64 position |= (s64)rdbuf[0xf] << 40;
65 position |= (s64)rdbuf[0x10] << 32;
66 position |= (s64)rdbuf[0x11] << 24;
67 position |= (s64)rdbuf[0x12] << 16;
68 position |= (s64)rdbuf[0x13] << 8;
69 position |= (s64)rdbuf[0x14];
70
71 DPRINTF("%s position %lli\n", __func__, position);
72
73 return position;
74}
75
76int mmcedrv_read_sector(int fd, u32 sector, u32 count, void *buffer)
77{
78 int res;
79 int sectors_read = 0;
80
81 u8 wrbuf[0xB];
82 u8 rdbuf[0xB];
83
84 DPRINTF("%s fd: %i, starting sector: %i, count: %i\n", __func__, fd, sector, count);
85
86 wrbuf[0x0] = MMCE_ID; //Identifier
87 wrbuf[0x1] = MMCE_CMD_FS_READ_SECTOR; //Command
88 wrbuf[0x2] = MMCE_RESERVED; //Reserved
89 wrbuf[0x3] = fd; //File Descriptor
90
91 wrbuf[0x4] = (sector & 0x00FF0000) >> 16;
92 wrbuf[0x5] = (sector & 0x0000FF00) >> 8;
93 wrbuf[0x6] = (sector & 0x000000FF);
94
95 wrbuf[0x7] = (count & 0x00FF0000) >> 16;
96 wrbuf[0x8] = (count & 0x0000FF00) >> 8;
97 wrbuf[0x9] = (count & 0x000000FF);
98
99 wrbuf[0xA] = 0xff;
100
101 mmce_sio2_lock();
102
103 //Packet #1: Command, file descriptor, and size
104 res = mmce_sio2_tx_rx_pio(0xB, 0xB, wrbuf, rdbuf, &timeout_2s);
105 if (res == -1) {
106 DPRINTF("%s ERROR: P1 - Timedout waiting for /ACK\n", __func__);
107 mmce_sio2_unlock();
108 return -1;
109 }
110
111 if (rdbuf[0x1] != MMCE_REPLY_CONST) {
112 DPRINTF("%s ERROR: Invalid response from card. Got 0x%x, Expected 0x%x\n", __func__, rdbuf[0x1], MMCE_REPLY_CONST);
113 mmce_sio2_unlock();
114 return -1;
115 }
116
117 if (rdbuf[0x9] != 0x0) {
118 DPRINTF("%s ERROR: P1 - Got bad return value from card, res %i\n", __func__, rdbuf[0x9]);
119 mmce_sio2_unlock();
120 return -1;
121 }
122
123 //Packet #2 - n: Read data
124 res = mmce_sio2_rx_dma(buffer, (count * 2048));
125 if (res == -1) {
126 DPRINTF("%s ERROR: P2 - Timedout waiting for /ACK\n", __func__);
127 mmce_sio2_unlock();
128 return -1;
129 }
130
131 //Packet #n + 1: Sectors read
132 res = mmce_sio2_tx_rx_pio(0x0, 0x5, wrbuf, rdbuf, &timeout_1s);
133 if (res == -1) {
134 DPRINTF("%s ERROR: P3 - Timedout waiting for /ACK\n", __func__);
135 mmce_sio2_unlock();
136 return -1;
137 }
138
139 mmce_sio2_unlock();
140
141 sectors_read = rdbuf[0x1] << 16;
142 sectors_read |= rdbuf[0x2] << 8;
143 sectors_read |= rdbuf[0x3];
144
145 if (sectors_read != count) {
146 DPRINTF("%s ERROR: Sectors read: %i, expected: %i\n", __func__, sectors_read, count);
147 }
148
149 return sectors_read;
150}
151
152int mmcedrv_read(int fd, int size, void *ptr)
153{
154 int res;
155 int bytes_read;
156
157 DPRINTF("%s: fd: %i, size: %i\n", __func__, fd, size);
158
159 u8 wrbuf[0xA];
160 u8 rdbuf[0xA];
161
162 wrbuf[0x0] = MMCE_ID; //Identifier
163 wrbuf[0x1] = MMCE_CMD_FS_READ; //Command
164 wrbuf[0x2] = MMCE_RESERVED; //Reserved
165 wrbuf[0x3] = 0x0; //Transfer mode (unused)
166 wrbuf[0x4] = fd; //File Descriptor
167 wrbuf[0x5] = (size & 0xFF000000) >> 24; //Size
168 wrbuf[0x6] = (size & 0x00FF0000) >> 16;
169 wrbuf[0x7] = (size & 0x0000FF00) >> 8;
170 wrbuf[0x8] = (size & 0x000000FF);
171 wrbuf[0x9] = 0xff;
172
173 mmce_sio2_lock();
174
175 //Packet #1: Command, file descriptor, and size
176 res = mmce_sio2_tx_rx_pio(0xA, 0xA, wrbuf, rdbuf, &timeout_2s);
177 if (res == -1) {
178 DPRINTF("%s ERROR: P1 - Timedout waiting for /ACK\n", __func__);
179 mmce_sio2_unlock();
180 return -1;
181 }
182
183 if (rdbuf[0x1] != MMCE_REPLY_CONST) {
184 DPRINTF("%s ERROR: Invalid response from card. Got 0x%x, Expected 0x%x\n", __func__, rdbuf[0x1], MMCE_REPLY_CONST);
185 mmce_sio2_unlock();
186 return -1;
187 }
188
189 if (rdbuf[0x9] != 0x0) {
190 DPRINTF("%s ERROR: P1 - Got bad return value from card, res %i\n", __func__, rdbuf[0x9]);
191 mmce_sio2_unlock();
192 return -1;
193 }
194
195 //Packet #2 - n: Raw read data
196 res = mmce_sio2_rx_mixed(ptr, size);
197 if (res == -1) {
198 DPRINTF("%s ERROR: P2 - Timedout waiting for /ACK\n", __func__);
199 mmce_sio2_unlock();
200 return -1;
201 }
202
203 //Packet #n + 1: Bytes read
204 res = mmce_sio2_tx_rx_pio(0x0, 0x6, wrbuf, rdbuf, &timeout_1s);
205 if (res == -1) {
206 DPRINTF("%s ERROR: P3 - Timedout waiting for /ACK\n", __func__);
207 mmce_sio2_unlock();
208 return -1;
209 }
210
211 mmce_sio2_unlock();
212
213 bytes_read = rdbuf[0x1] << 24;
214 bytes_read |= rdbuf[0x2] << 16;
215 bytes_read |= rdbuf[0x3] << 8;
216 bytes_read |= rdbuf[0x4];
217
218 if (bytes_read != size) {
219 DPRINTF("%s WARN: bytes read: %i, expected: %i\n", __func__, bytes_read, size);
220
221 if (bytes_read > size)
222 bytes_read = size;
223
224 }
225
226 return bytes_read;
227}
228
229int mmcedrv_write(int fd, int size, void *ptr)
230{
231 int res;
232 int bytes_written;
233
234 DPRINTF("%s: fd: %i, size: %i\n", __func__, fd, size);
235
236 u8 wrbuf[0xA];
237 u8 rdbuf[0xA];
238
239 wrbuf[0x0] = MMCE_ID; //Identifier
240 wrbuf[0x1] = MMCE_CMD_FS_WRITE; //Command
241 wrbuf[0x2] = MMCE_RESERVED; //Reserved
242 wrbuf[0x3] = 0x0; //Transfer mode (unimplemented)
243 wrbuf[0x4] = fd; //File Descriptor
244 wrbuf[0x5] = (size & 0xFF000000) >> 24;
245 wrbuf[0x6] = (size & 0x00FF0000) >> 16;
246 wrbuf[0x7] = (size & 0x0000FF00) >> 8;
247 wrbuf[0x8] = (size & 0x000000FF);
248 wrbuf[0x9] = 0xff;
249
250 mmce_sio2_lock();
251
252 //Packet #1: Command, file descriptor, and size
253 res = mmce_sio2_tx_rx_pio(0xA, 0xA, wrbuf, rdbuf, &timeout_1s);
254 if (res == -1) {
255 DPRINTF("%s ERROR: P1 - Timedout waiting for /ACK\n", __func__);
256 mmce_sio2_unlock();
257 return -1;
258 }
259
260 if (rdbuf[0x1] != MMCE_REPLY_CONST) {
261 DPRINTF("%s ERROR: Invalid response from card. Got 0x%x, Expected 0x%x\n", __func__, rdbuf[0x1], MMCE_REPLY_CONST);
262 mmce_sio2_unlock();
263 return -1;
264 }
265
266 if (rdbuf[0x9] != 0x0) {
267 DPRINTF("%s ERROR: P1 - Got bad return value from card 0x%x\n", __func__, rdbuf[0x9]);
268 mmce_sio2_unlock();
269 return -1;
270 }
271
272 //Packet #2 - n: Raw write data
273 res = mmce_sio2_tx_mixed(ptr, size);
274 if (res == -1) {
275 DPRINTF("%s ERROR: P2 - Timedout waiting for /ACK\n", __func__);
276 mmce_sio2_unlock();
277 return -1;
278 }
279
280 //Packets #n + 1: Bytes written
281 res = mmce_sio2_tx_rx_pio(0x0, 0x6, wrbuf, rdbuf, &timeout_1s);
282 if (res == -1) {
283 DPRINTF("%s ERROR: P3 - Timedout waiting for /ACK\n", __func__);
284 mmce_sio2_unlock();
285 return -1;
286 }
287
288 mmce_sio2_unlock();
289
290 bytes_written = rdbuf[0x1] << 24;
291 bytes_written |= rdbuf[0x2] << 16;
292 bytes_written |= rdbuf[0x3] << 8;
293 bytes_written |= rdbuf[0x4];
294
295 if (bytes_written != size) {
296 DPRINTF("%s bytes written: %i, expected: %i\n", __func__, bytes_written, size);
297 }
298
299 return bytes_written;
300}
301
302int mmcedrv_lseek(int fd, int offset, int whence)
303{
304 int res;
305 int position = -1;
306
307 DPRINTF("%s: fd: %i, offset: %i, whence: %i\n", __func__, fd, offset, whence);
308
309 u8 wrbuf[0x9];
310 u8 rdbuf[0xe];
311
312 wrbuf[0x0] = MMCE_ID; //Identifier
313 wrbuf[0x1] = MMCE_CMD_FS_LSEEK; //Command
314 wrbuf[0x2] = MMCE_RESERVED; //Reserved
315 wrbuf[0x3] = fd; //File descriptor
316 wrbuf[0x4] = (offset & 0xFF000000) >> 24; //Offset
317 wrbuf[0x5] = (offset & 0x00FF0000) >> 16;
318 wrbuf[0x6] = (offset & 0x0000FF00) >> 8;
319 wrbuf[0x7] = (offset & 0x000000FF);
320 wrbuf[0x8] = (u8)(whence); //Whence
321
322 //Packet #1: Command, file descriptor, offset, and whence
323 mmce_sio2_lock();
324 res = mmce_sio2_tx_rx_pio(0x9, 0xe, wrbuf, rdbuf, &timeout_1s);
325 mmce_sio2_unlock();
326
327 if (res == -1) {
328 DPRINTF("%s ERROR: P1 - Timedout waiting for /ACK\n", __func__);
329 return -1;
330 }
331
332 if (rdbuf[0x1] != MMCE_REPLY_CONST) {
333 DPRINTF("%s ERROR: Invalid response from card. Got 0x%x, Expected 0x%x\n", __func__, rdbuf[0x1], MMCE_REPLY_CONST);
334 return -1;
335 }
336
337 position = rdbuf[0x9] << 24;
338 position |= rdbuf[0xa] << 16;
339 position |= rdbuf[0xb] << 8;
340 position |= rdbuf[0xc];
341
342 DPRINTF("%s position %i\n", __func__, position);
343
344 return position;
345}
346
347//For OPL, called through CDVDMAN Device
348void mmcedrv_config_set(int setting, int value)
349{
350 switch (setting) {
351 case MMCEDRV_SETTING_PORT:
352 if (value == 2 || value == 3)
353 mmce_sio2_set_port(value);
354 else
355 DPRINTF("Invalid port setting: %i\n", value);
356 break;
357
358 case MMCEDRV_SETTING_ACK_WAIT_CYCLES:
359 if (value < 5) {
360 mmce_sio2_update_ack_wait_cycles(value);
361 }
362 break;
363
364 case MMCEDRV_SETTING_USE_ALARMS:
365 mmce_sio2_set_use_alarm(value);
366 break;
367
368 default:
369 break;
370 }
371}
372
373int __start(int argc, char *argv[])
374{
375 int rv;
376
377 DPRINTF("Multipurpose Memory Card Emulator Driver (MMCEDRV) v%d.%d by the MMCE team\n", MAJOR, MINOR);
378
379 //Install hooks
380 rv = mmce_sio2_init();
381 if (rv != 0) {
382 DPRINTF("mmce_sio2_init failed, rv %i\n", rv);
383 return MODULE_NO_RESIDENT_END;
384 }
385
386 //Register exports
387 if (RegisterLibraryEntries(&_exp_mmcedrv) != 0) {
388 DPRINTF("ERROR: library already registered\n");
389 return MODULE_NO_RESIDENT_END;
390 }
391
392 iop_library_t * lib_modload = ioplib_getByName("modload");
393 if (lib_modload != NULL) {
394 DPRINTF("modload 0x%x detected\n", lib_modload->version);
395 if (lib_modload->version > 0x102) //IOP is running a MODLOAD version which supports unloading IRX Modules
396 return MODULE_REMOVABLE_END; // and we do support getting unloaded...
397 } else {
398 DPRINTF("modload not detected! this is serious!\n");
399 }
400
401 return MODULE_RESIDENT_END;
402}
403
404int __stop(int argc, char *argv[])
405{
406 DPRINTF("Unloading module\n");
407
408 mmce_sio2_deinit();
409
410 return MODULE_NO_RESIDENT_END;
411}
412
413int _start(int argc, char *argv[])
414{
415 if (argc >= 0)
416 return __start(argc, argv);
417 else
418 return __stop(-argc, argv);
419}
iop_library_t * ioplib_getByName(const char *name)
get library object of any IRX Module
Definition ioplib.c:17