Disabling auto-refresh of game list by default, as it is causing bugs sometimes
[open-ps2-loader.git] / modules / vmc / genvmc / genvmc.c
blob63d04c93008ce75847b35ae7d457098c53d1e1aa
1 /*
2 Copyright 2010, jimmikaelkael <jimmikaelkael@wanadoo.fr>
3 Copyright 2010, crazyc
5 Licenced under Academic Free License version 3.0
6 Review Open PS2 Loader README & LICENSE files for further details.
7 */
9 #include <stdio.h>
10 #include <loadcore.h>
11 #include <ioman.h>
12 #include "ioman_add.h"
13 #include <io_common.h>
14 #include <intrman.h>
15 #include <thsemap.h>
16 #include <sysclib.h>
17 #include <sysmem.h>
18 #include <thbase.h>
19 #include <errno.h>
21 #include "genvmc.h"
23 #ifdef DEBUG
24 #define DPRINTF(args...) printf(args)
25 #else
26 #define DPRINTF(args...) do { } while(0)
27 #endif
29 #define MODNAME "genvmc"
30 IRX_ID(MODNAME, 1, 1);
32 // driver ops protypes
33 int genvmc_dummy(void);
34 int genvmc_init(iop_device_t *dev);
35 int genvmc_deinit(iop_device_t *dev);
36 int genvmc_devctl(iop_file_t *f, const char *name, int cmd, void *args, u32 arglen, void *buf, u32 buflen);
38 // driver ops func tab
39 void *genvmc_ops[27] = {
40 (void*)genvmc_init,
41 (void*)genvmc_deinit,
42 (void*)genvmc_dummy,
43 (void*)genvmc_dummy,
44 (void*)genvmc_dummy,
45 (void*)genvmc_dummy,
46 (void*)genvmc_dummy,
47 (void*)genvmc_dummy,
48 (void*)genvmc_dummy,
49 (void*)genvmc_dummy,
50 (void*)genvmc_dummy,
51 (void*)genvmc_dummy,
52 (void*)genvmc_dummy,
53 (void*)genvmc_dummy,
54 (void*)genvmc_dummy,
55 (void*)genvmc_dummy,
56 (void*)genvmc_dummy,
57 (void*)genvmc_dummy,
58 (void*)genvmc_dummy,
59 (void*)genvmc_dummy,
60 (void*)genvmc_dummy,
61 (void*)genvmc_dummy,
62 (void*)genvmc_dummy,
63 (void*)genvmc_devctl,
64 (void*)genvmc_dummy,
65 (void*)genvmc_dummy,
66 (void*)genvmc_dummy
69 // driver descriptor
70 static iop_ext_device_t genvmc_dev = {
71 "genvmc",
72 IOP_DT_FS | IOP_DT_FSEXT,
74 "genvmc",
75 (struct _iop_ext_device_ops *)&genvmc_ops
78 // from cdvdman
79 typedef struct {
80 u8 stat;
81 u8 second;
82 u8 minute;
83 u8 hour;
84 u8 week;
85 u8 day;
86 u8 month;
87 u8 year;
88 } cd_clock_t;
90 int sceCdRC(cd_clock_t *rtc); // #51
92 int sceMcDetectCard(int port, int slot); // #05
93 int sceMcReadPage(int port, int slot, int page, char *mcbuffer); // #18
94 int sceMcGetCardType(int port, int slot); // #39
97 // mc file attributes
98 #define SCE_STM_R 0x01
99 #define SCE_STM_W 0x02
100 #define SCE_STM_X 0x04
101 #define SCE_STM_C 0x08
102 #define SCE_STM_F 0x10
103 #define SCE_STM_D 0x20
104 #define sceMcFileAttrReadable SCE_STM_R
105 #define sceMcFileAttrWriteable SCE_STM_W
106 #define sceMcFileAttrExecutable SCE_STM_X
107 #define sceMcFileAttrDupProhibit SCE_STM_C
108 #define sceMcFileAttrFile SCE_STM_F
109 #define sceMcFileAttrSubdir SCE_STM_D
110 #define sceMcFileCreateDir 0x0040
111 #define sceMcFileAttrClosed 0x0080
112 #define sceMcFileCreateFile 0x0200
113 #define sceMcFile0400 0x0400
114 #define sceMcFileAttrPDAExec 0x0800
115 #define sceMcFileAttrPS1 0x1000
116 #define sceMcFileAttrHidden 0x2000
117 #define sceMcFileAttrExists 0x8000
119 // SONY superblock magic & version
120 static char SUPERBLOCK_MAGIC[] = "Sony PS2 Memory Card Format ";
121 static char SUPERBLOCK_VERSION[] = "1.2.0.0";
123 // superblock struct
124 typedef struct { // size = 384
125 u8 magic[28]; // Superblock magic, on PS2 MC : "Sony PS2 Memory Card Format "
126 u8 version[12]; // Version number of the format used, 1.2 indicates full support for bad_block_list
127 s16 pagesize; // size in bytes of a memory card page
128 u16 pages_per_cluster; // number of pages in a cluster
129 u16 blocksize; // number of pages in an erase block
130 u16 unused; // unused
131 u32 clusters_per_card; // total size in clusters of the memory card
132 u32 alloc_offset; // Cluster offset of the first allocatable cluster. Cluster values in the FAT and directory entries are relative to this. This is the cluster immediately after the FAT
133 u32 alloc_end; // The cluster after the highest allocatable cluster. Relative to alloc_offset. Not used
134 u32 rootdir_cluster; // First cluster of the root directory. Relative to alloc_offset. Must be zero
135 u32 backup_block1; // Erase block used as a backup area during programming. Normally the the last block on the card, it may have a different value if that block was found to be bad
136 u32 backup_block2; // This block should be erased to all ones. Normally the the second last block on the card
137 u8 unused2[8];
138 u32 ifc_list[32]; // List of indirect FAT clusters. On a standard 8M card there's only one indirect FAT cluster
139 int bad_block_list[32]; // List of erase blocks that have errors and shouldn't be used
140 u8 cardtype; // Memory card type. Must be 2, indicating that this is a PS2 memory card
141 u8 cardflags; // Physical characteristics of the memory card
142 u16 unused3;
143 u32 cluster_size;
144 u32 FATentries_per_cluster;
145 u32 clusters_per_block;
146 int cardform;
147 u32 rootdir_cluster2;
148 u32 unknown1;
149 u32 unknown2;
150 u32 max_allocatable_clusters;
151 u32 unknown3;
152 u32 unknown4;
153 int unknown5;
154 } MCDevInfo;
156 typedef struct _sceMcStDateTime {
157 u8 Resv2;
158 u8 Sec;
159 u8 Min;
160 u8 Hour;
161 u8 Day;
162 u8 Month;
163 u16 Year;
164 } sceMcStDateTime;
166 typedef struct { // size = 512
167 u16 mode; // 0
168 u16 unused; // 2
169 u32 length; // 4
170 sceMcStDateTime created; // 8
171 u32 cluster; // 16
172 u32 dir_entry; // 20
173 sceMcStDateTime modified; // 24
174 u32 attr; // 32
175 u32 unused2[7]; // 36
176 char name[32]; // 64
177 u8 unused3[416]; // 96
178 } McFsEntry;
180 #define BLOCKKB 16
182 static MCDevInfo devinfo __attribute__((aligned(64)));
183 static u8 cluster_buf[(BLOCKKB * 1024)+16] __attribute__((aligned(64)));
185 static int genvmc_io_sema = -1;
186 static int genvmc_thread_sema = -1;
187 static int genvmc_abort_sema = -1;
188 static int genvmc_abort_finished_sema = -1;
190 static int genvmc_abort = 0;
192 static statusVMCparam_t genvmc_stats;
194 //--------------------------------------------------------------
195 static void long_multiply(u32 v1, u32 v2, u32 *HI, u32 *LO)
197 register long a, b, c, d;
198 register long x, y;
200 a = (v1 >> 16) & 0xffff;
201 b = v1 & 0xffff;
202 c = (v2 >> 16) & 0xffff;
203 d = v2 & 0xffff;
205 *LO = b * d;
206 x = a * d + c * b;
207 y = ((*LO >> 16) & 0xffff) + x;
209 *LO = (*LO & 0xffff) | ((y & 0xffff) << 16);
210 *HI = (y >> 16) & 0xffff;
212 *HI += a * c;
215 //--------------------------------------------------------------
216 static int mc_getmcrtime(sceMcStDateTime *time)
218 register int retries;
219 cd_clock_t cdtime;
221 retries = 64;
223 do {
224 if (sceCdRC(&cdtime))
225 break;
226 } while (--retries > 0);
228 if (cdtime.stat & 128) {
229 *((u16 *)&cdtime.month) = 0x7d0;
230 cdtime.day = 3;
231 cdtime.week = 4;
232 cdtime.hour = 0;
233 cdtime.minute = 0;
234 cdtime.second = 0;
235 cdtime.stat = 0;
238 time->Resv2 = 0;
239 time->Sec = ((((cdtime.second >> 4) << 2) + (cdtime.second >> 4)) << 1) + (cdtime.second & 0xf);
240 time->Min = ((((cdtime.minute >> 4) << 2) + (cdtime.minute >> 4)) << 1) + (cdtime.minute & 0xf);
241 time->Hour = ((((cdtime.hour >> 4) << 2) + (cdtime.hour >> 4)) << 1) + (cdtime.hour & 0xf);
242 time->Day = ((((cdtime.day >> 4) << 2) + (cdtime.day >> 4)) << 1) + (cdtime.day & 0xf);
244 if ((cdtime.month & 0x10) != 0)
245 time->Month = (cdtime.month & 0xf) + 0xa;
246 else
247 time->Month = cdtime.month & 0xf;
249 time->Year = ((((cdtime.year >> 4) << 2) + (cdtime.year >> 4)) << 1) + ((cdtime.year & 0xf) | 0x7d0);
251 return 0;
254 //--------------------------------------------------------------
255 static int mc_writecluster(int fd, int cluster, void *buf, int dup)
257 register int r, size;
258 MCDevInfo *mcdi = (MCDevInfo *)&devinfo;
260 WaitSema(genvmc_abort_sema);
262 if (genvmc_abort) {
263 SignalSema(genvmc_abort_sema);
264 return -2;
266 else {
267 lseek(fd, cluster * mcdi->cluster_size, SEEK_SET);
268 size = mcdi->cluster_size * dup;
269 r = write(fd, buf, size);
270 if (r != size)
271 return -1;
274 SignalSema(genvmc_abort_sema);
276 return 0;
279 //--------------------------------------------------------------
280 // this is designed to work only with the rom0 mcman for max compatibility
281 // but that means it isn't really possible to lock properly so don't write
282 // to the card during the operation. hints came from mcdump.c by Polo35
283 static int vmc_mccopy(char *filename, int slot, int *progress, char *msg)
285 MCDevInfo *mcdi = (MCDevInfo *)&devinfo;
286 unsigned int blocks, pagesblock, clustersblock, i, j;
287 int ret;
289 strcpy(msg, "Checking memcard...");
290 if ((sceMcDetectCard(slot, 0) < -1) && (sceMcGetCardType(slot, 0) != 2))
291 return -98;
293 if (sceMcReadPage(slot, 0, 0, cluster_buf))
294 return -99;
296 memcpy(mcdi, cluster_buf, sizeof(MCDevInfo));
297 if (memcmp(mcdi->magic, SUPERBLOCK_MAGIC, 28))
298 return -100;
300 pagesblock = (BLOCKKB * 1024) / mcdi->pagesize;
301 clustersblock = pagesblock / mcdi->pages_per_cluster;
302 blocks = mcdi->clusters_per_card / clustersblock;
304 int genvmc_fh = open(filename, O_RDWR|O_CREAT|O_TRUNC);
305 if (genvmc_fh < 0)
306 return -101;
308 strcpy(msg, "Copying memcard to VMC...");
309 for (i = 0; i < blocks; i++) {
310 *progress = i / (blocks / 99);
311 for (j = 0; j < pagesblock; j++) {
312 if(sceMcReadPage(slot, 0, (i * pagesblock) + j, &cluster_buf[j * mcdi->pagesize])) {
313 ret = -102;
314 goto exit;
317 ret = mc_writecluster(genvmc_fh, i * clustersblock, cluster_buf, clustersblock);
318 if (ret < 0) {
319 if (ret == -2) // it's user abort
320 ret = -1000;
321 else
322 ret = -103;
323 goto exit;
326 for (i = (blocks * clustersblock); i < mcdi->clusters_per_card; i++) {
327 for (j = 0; j < mcdi->pages_per_cluster; j++) {
328 if (sceMcReadPage(slot, 0, (i * mcdi->pages_per_cluster) + j, &cluster_buf[j * mcdi->pagesize])) {
329 ret = -102;
330 goto exit;
333 ret = mc_writecluster(genvmc_fh, i, cluster_buf, 1);
334 if (ret < 0) {
335 if (ret == -2) // it's user abort
336 ret = -1000;
337 else
338 ret = -103;
339 goto exit;
342 *progress = 100;
343 ret = 0;
344 exit:
345 close(genvmc_fh);
346 return ret;
349 //--------------------------------------------------------------
350 static int vmc_mcformat(char *filename, int size_kb, int blocksize, int *progress, char *msg)
352 register int i, r, b, ifc_index, fat_index;
353 register int ifc_length, fat_length, alloc_offset;
354 register int j = 0, z = 0;
355 int oldstate;
356 MCDevInfo *mcdi = (MCDevInfo *)&devinfo;
358 strcpy(msg, "Creating VMC file...");
359 int genvmc_fh = open(filename, O_RDWR|O_CREAT|O_TRUNC);
360 if (genvmc_fh < 0)
361 return -101;
363 // set superblock magic & version
364 memset((void *)&mcdi->magic, 0, sizeof (mcdi->magic) + sizeof (mcdi->version));
365 strcpy((char *)&mcdi->magic, SUPERBLOCK_MAGIC);
366 strcat((char *)&mcdi->magic, SUPERBLOCK_VERSION);
368 // set mc specs
369 mcdi->cluster_size = 1024; // size in KB of clusters
370 mcdi->blocksize = blocksize; // how many pages in a block of data
371 mcdi->pages_per_cluster = 2; // how many pages in a cluster
372 mcdi->pagesize = mcdi->cluster_size / mcdi->pages_per_cluster;
373 mcdi->clusters_per_block = mcdi->blocksize / mcdi->pages_per_cluster;
374 mcdi->clusters_per_card = (size_kb*1024) / mcdi->cluster_size;
375 mcdi->cardtype = 0x02; // PlayStation2 card type
376 mcdi->cardflags = 0x2b;
377 mcdi->cardform = -1;
378 mcdi->FATentries_per_cluster = mcdi->cluster_size / sizeof(u32);
380 // clear bad blocks list
381 for (i=0; i<32; i++)
382 mcdi->bad_block_list[i] = -1;
384 // erase all clusters
385 strcpy(msg, "Erasing VMC clusters...");
386 memset(cluster_buf, 0xff, sizeof(cluster_buf));
387 for (i=0; i<mcdi->clusters_per_card; i+=16) {
388 *progress = i / (mcdi->clusters_per_card / 99);
389 r = mc_writecluster(genvmc_fh, i, cluster_buf, 16);
390 if (r < 0) {
391 if (r == -2) // it's user abort
392 r = -1000;
393 else
394 r = -102;
395 goto err_out;
399 // calculate fat & ifc length
400 fat_length = (((mcdi->clusters_per_card << 2) - 1) / mcdi->cluster_size) + 1; // get length of fat in clusters
401 ifc_length = (((fat_length << 2) - 1) / mcdi->cluster_size) + 1; // get number of needed ifc clusters
403 if (!(ifc_length <= 32)) {
404 ifc_length = 32;
405 fat_length = mcdi->FATentries_per_cluster << 5;
408 // clear ifc list
409 for (i=0; i<32; i++)
410 mcdi->ifc_list[i] = -1;
411 ifc_index = mcdi->blocksize / 2;
412 i = ifc_index;
413 for (j=0; j<ifc_length; j++, i++)
414 mcdi->ifc_list[j] = i;
416 // keep fat cluster index
417 fat_index = i;
419 // allocate memory for ifc clusters
420 CpuSuspendIntr(&oldstate);
421 u8 *ifc_mem = AllocSysMemory(ALLOC_FIRST, (ifc_length * mcdi->cluster_size)+0XFF, NULL);
422 CpuResumeIntr(oldstate);
423 if (!ifc_mem) {
424 r = -103;
425 goto err_out;
427 memset(ifc_mem, 0, ifc_length * mcdi->cluster_size);
429 // build ifc clusters
430 u32 *ifc = (u32 *)ifc_mem;
431 for (j=0; j<fat_length; j++, i++) {
432 // just as security...
433 if (i >= mcdi->clusters_per_card) {
434 CpuSuspendIntr(&oldstate);
435 FreeSysMemory(ifc_mem);
436 CpuResumeIntr(oldstate);
437 r = -104;
438 goto err_out;
440 ifc[j] = i;
443 // write ifc clusters
444 strcpy(msg, "Writing ifc clusters...");
445 for (z=0; z<ifc_length; z++) {
446 r = mc_writecluster(genvmc_fh, mcdi->ifc_list[z], &ifc_mem[z * mcdi->cluster_size], 1);
447 if (r < 0) {
448 // freeing ifc clusters memory
449 CpuSuspendIntr(&oldstate);
450 FreeSysMemory(ifc_mem);
451 CpuResumeIntr(oldstate);
452 if (r == -2) // it's user abort
453 r = -1000;
454 else
455 r = -105;
456 goto err_out;
460 // freeing ifc clusters memory
461 CpuSuspendIntr(&oldstate);
462 FreeSysMemory(ifc_mem);
463 CpuResumeIntr(oldstate);
465 // set alloc offset
466 alloc_offset = i;
468 // set backup blocks
469 mcdi->backup_block1 = (mcdi->clusters_per_card / mcdi->clusters_per_block) - 1;
470 mcdi->backup_block2 = (mcdi->clusters_per_card / mcdi->clusters_per_block) - 2;
472 // calculate number of allocatable clusters per card
473 u32 hi, lo, temp;
474 long_multiply(mcdi->clusters_per_card, 0x10624dd3, &hi, &lo);
475 temp = (hi >> 6) - (mcdi->clusters_per_card >> 31);
476 mcdi->max_allocatable_clusters = (((((temp << 5) - temp) << 2) + temp) << 3) + 1;
477 j = alloc_offset;
479 // building/writing FAT clusters
480 strcpy(msg, "Writing fat clusters...");
481 i = (mcdi->clusters_per_card / mcdi->clusters_per_block) - 2; // 2 backup blocks
482 for (z=0; j < (i * mcdi->clusters_per_block); j+=mcdi->FATentries_per_cluster) {
484 memset(cluster_buf, 0, mcdi->cluster_size);
485 u32 *fc = (u32 *)cluster_buf;
486 int sz_u32 = (i * mcdi->clusters_per_block) - j;
487 if (sz_u32 > mcdi->FATentries_per_cluster)
488 sz_u32 = mcdi->FATentries_per_cluster;
489 for (b=0; b<sz_u32; b++)
490 fc[b] = 0x7fffffff; // marking free cluster
492 if (z == 0) {
493 mcdi->alloc_offset = j;
494 mcdi->rootdir_cluster = 0;
495 fc[0] = 0xffffffff; // marking rootdir end
497 z+=sz_u32;
499 r = mc_writecluster(genvmc_fh, fat_index++, cluster_buf, 1);
500 if (r < 0) {
501 if (r == -2) // it's user abort
502 r = -1000;
503 else
504 r = -107;
505 goto err_out;
509 // calculate alloc_end
510 mcdi->alloc_end = (i * mcdi->clusters_per_block) - mcdi->alloc_offset;
512 // just a security...
513 if (z < mcdi->clusters_per_block) {
514 r = -108;
515 goto err_out;
518 mcdi->unknown1 = 0;
519 mcdi->unknown2 = 0;
520 mcdi->unknown5 = -1;
521 mcdi->rootdir_cluster2 = mcdi->rootdir_cluster;
523 // build root directory
524 McFsEntry *rootdir_entry[2];
525 sceMcStDateTime time;
527 mc_getmcrtime(&time);
528 rootdir_entry[0] = (McFsEntry *)&cluster_buf[0];
529 rootdir_entry[1] = (McFsEntry *)&cluster_buf[sizeof(McFsEntry)];
530 memset((void *)rootdir_entry[0], 0, sizeof(McFsEntry));
531 memset((void *)rootdir_entry[1], 0, sizeof(McFsEntry));
532 rootdir_entry[0]->mode = sceMcFileAttrExists | sceMcFile0400 | sceMcFileAttrSubdir | sceMcFileAttrReadable | sceMcFileAttrWriteable | sceMcFileAttrExecutable;
533 rootdir_entry[0]->length = 2;
534 memcpy((void *)&rootdir_entry[0]->created, (void *)&time, sizeof(sceMcStDateTime));
535 memcpy((void *)&rootdir_entry[0]->modified, (void *)&time, sizeof(sceMcStDateTime));
536 rootdir_entry[0]->cluster = 0;
537 rootdir_entry[0]->dir_entry = 0;
538 strcpy(rootdir_entry[0]->name, ".");
539 rootdir_entry[1]->mode = sceMcFileAttrExists | sceMcFileAttrHidden | sceMcFile0400 | sceMcFileAttrSubdir | sceMcFileAttrWriteable | sceMcFileAttrExecutable;
540 rootdir_entry[1]->length = 2;
541 memcpy((void *)&rootdir_entry[1]->created, (void *)&time, sizeof(sceMcStDateTime));
542 memcpy((void *)&rootdir_entry[1]->modified, (void *)&time, sizeof(sceMcStDateTime));
543 rootdir_entry[1]->cluster = 0;
544 rootdir_entry[1]->dir_entry = 0;
545 strcpy(rootdir_entry[1]->name, "..");
547 // write root directory cluster
548 strcpy(msg, "Writing root directory cluster...");
549 r = mc_writecluster(genvmc_fh, mcdi->alloc_offset + mcdi->rootdir_cluster, cluster_buf, 1);
550 if (r < 0) {
551 if (r == -2) // it's user abort
552 r = -1000;
553 else
554 r = -109;
555 goto err_out;
558 // set superblock formatted flag
559 mcdi->cardform = 1;
561 // finally write superblock
562 strcpy(msg, "Writing superblock...");
563 memset(cluster_buf, 0xff, mcdi->cluster_size);
564 memcpy(cluster_buf, (void *)mcdi, sizeof(MCDevInfo));
565 r = mc_writecluster(genvmc_fh, 0, cluster_buf, 1);
566 if (r < 0) {
567 if (r == -2) // it's user abort
568 r = -1000;
569 else
570 r = -110;
571 goto err_out;
574 close(genvmc_fh);
576 *progress = 100;
578 return 0;
581 err_out:
582 close(genvmc_fh);
584 return r;
587 //--------------------------------------------------------------
588 int genvmc_dummy(void)
590 return -EPERM;
593 //--------------------------------------------------------------
594 int genvmc_init(iop_device_t *dev)
596 genvmc_io_sema = CreateMutex(IOP_MUTEX_UNLOCKED);
597 genvmc_thread_sema = CreateMutex(IOP_MUTEX_UNLOCKED);
598 genvmc_abort_sema = CreateMutex(IOP_MUTEX_UNLOCKED);
600 return 0;
603 //--------------------------------------------------------------
604 int genvmc_deinit(iop_device_t *dev)
606 DeleteSema(genvmc_io_sema);
607 DeleteSema(genvmc_thread_sema);
608 DeleteSema(genvmc_abort_sema);
610 return 0;
613 //--------------------------------------------------------------
614 static void VMC_create_thread(void *args)
616 register int r;
617 createVMCparam_t *param = (createVMCparam_t *)args;
619 WaitSema(genvmc_thread_sema);
621 WaitSema(genvmc_abort_sema);
622 genvmc_abort = 0;
623 SignalSema(genvmc_abort_sema);
625 genvmc_stats.VMC_status = GENVMC_STAT_BUSY;
626 genvmc_stats.VMC_error = 0;
627 genvmc_stats.VMC_progress = 0;
628 strcpy(genvmc_stats.VMC_msg, "Initializing...");
630 if (param->VMC_card_slot == -1)
631 r = vmc_mcformat(param->VMC_filename, param->VMC_size_mb * 1024, param->VMC_blocksize, &genvmc_stats.VMC_progress, genvmc_stats.VMC_msg);
632 else
633 r = vmc_mccopy(param->VMC_filename, param->VMC_card_slot, &genvmc_stats.VMC_progress, genvmc_stats.VMC_msg);
635 if (r < 0) {
636 genvmc_stats.VMC_status = GENVMC_STAT_AVAIL;
637 genvmc_stats.VMC_error = r;
639 if (r == -1000) { // user abort
640 remove(param->VMC_filename);
641 strcpy(genvmc_stats.VMC_msg, "VMC file creation aborted");
642 SignalSema(genvmc_abort_finished_sema);
644 else
645 strcpy(genvmc_stats.VMC_msg, "Failed to format VMC file");
647 goto exit;
650 genvmc_stats.VMC_status = GENVMC_STAT_AVAIL;
651 genvmc_stats.VMC_error = 0;
652 genvmc_stats.VMC_progress = 100;
653 strcpy(genvmc_stats.VMC_msg, "VMC file created");
655 exit:
656 SignalSema(genvmc_thread_sema);
657 ExitDeleteThread();
660 //--------------------------------------------------------------
661 static int vmc_create(createVMCparam_t *param)
663 DPRINTF("%s: vmc_create() filename=%s size_MB=%d blocksize=%d th_priority=0x%02x slot=%d\n", MODNAME, \
664 param->VMC_filename, param->VMC_size_mb, param->VMC_blocksize, param->VMC_thread_priority, param->VMC_card_slot);
666 register int r, thid;
667 iop_thread_t thread_param;
669 thread_param.attr = TH_C;
670 thread_param.option = 0;
671 thread_param.thread = (void *)VMC_create_thread;
672 thread_param.stacksize = 0x2000;
673 thread_param.priority = (param->VMC_thread_priority < 0x0f) ? 0x0f : param->VMC_thread_priority;
675 // creating VMC create thread
676 thid = CreateThread(&thread_param);
677 if (thid < 0)
678 return -1;
680 // starting VMC create thread
681 r = StartThread(thid, (void *)param);
682 if (r < 0)
683 return -2;
685 return 0;
688 //--------------------------------------------------------------
689 static int vmc_abort(void)
691 WaitSema(genvmc_abort_sema);
693 DPRINTF("%s: vmc_abort()\n", MODNAME);
695 genvmc_abort = 1;
696 SignalSema(genvmc_abort_sema);
698 genvmc_abort_finished_sema = CreateMutex(IOP_MUTEX_LOCKED);
699 WaitSema(genvmc_abort_finished_sema);
700 DeleteSema(genvmc_abort_finished_sema);
702 return 0;
705 //--------------------------------------------------------------
706 static int vmc_status(statusVMCparam_t *param)
708 // copy global genvmc stats to output param
709 memcpy((void *)param, (void *)&genvmc_stats, sizeof(statusVMCparam_t));
711 return 0;
714 //--------------------------------------------------------------
715 int genvmc_devctl(iop_file_t *f, const char *name, int cmd, void *args, u32 arglen, void *buf, u32 buflen)
717 register int r = 0;
719 if (!name)
720 return -ENOENT;
722 WaitSema(genvmc_io_sema);
724 switch (cmd) {
726 // VMC file creation request command
727 case GENVMC_DEVCTL_CREATE_VMC:
728 r = vmc_create((createVMCparam_t *)args);
729 if (r < 0)
730 r = -EIO;
731 break;
733 // VMC file creation abort command
734 case GENVMC_DEVCTL_ABORT:
735 r = vmc_abort();
736 if (r < 0)
737 r = -EIO;
738 break;
740 // VMC file creation status command
741 case GENVMC_DEVCTL_STATUS:
742 r = vmc_status((statusVMCparam_t *)buf);
743 if (r < 0)
744 r = -EIO;
745 break;
747 default:
748 r = -EINVAL;
751 SignalSema(genvmc_io_sema);
753 return r;
756 //--------------------------------------------------------------
757 int _start(int argc, char** argv)
759 DPRINTF("%s start!\n", MODNAME);
761 DelDrv("genvmc");
763 if (AddDrv((iop_device_t *)&genvmc_dev) < 0)
764 return MODULE_NO_RESIDENT_END;
766 return MODULE_RESIDENT_END;
769 //--------------------------------------------------------------
770 // Extra import tables
772 DECLARE_IMPORT_TABLE(cdvdman, 1, 1)
773 DECLARE_IMPORT(51, sceCdRC)
774 END_IMPORT_TABLE
776 DECLARE_IMPORT_TABLE(mcman, 1, 1)
777 DECLARE_IMPORT(5, sceMcDetectCard)
778 DECLARE_IMPORT(18, sceMcReadPage)
779 DECLARE_IMPORT(39, sceMcGetCardType)
780 END_IMPORT_TABLE