PS2SDK
PS2 Homebrew Libraries
mciomanx_backing.c
1 /*
2 # _____ ___ ____ ___ ____
3 # ____| | ____| | | |____|
4 # | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5 #-----------------------------------------------------------------------
6 # Copyright (c) 2009 jimmikaelkael
7 # Licenced under Academic Free License version 2.0
8 # Review ps2sdk README & LICENSE files for further details.
9 */
10 
11 #include <mcman.h>
12 #include "mcman-internal.h"
13 
14 #if defined(BUILDING_VMCMAN)
15 typedef struct vmc_cardinfo_
16 {
17  int mounted;
18  int has_ecc;
19  int fd;
20  s16 pagesize;
21  u16 blocksize;
22  int cardsize;
23  u8 flags;
24 } vmc_cardinfo_t;
25 
26 static vmc_cardinfo_t mcman_vmc_cardinfo[MCMAN_MAXSLOT];
27 
28 static void mcman_iomanx_backing_clear_slot(int slot)
29 {
30  vmc_cardinfo_t *cardinfo;
31  cardinfo = &mcman_vmc_cardinfo[slot];
32  if (cardinfo->fd >= 0) {
33  iomanX_close(cardinfo->fd);
34  }
35  memset(cardinfo, 0, sizeof(vmc_cardinfo_t));
36  cardinfo->fd = -1;
37 
38  // Just to clear any cached information
39  mcman_probePS2Card(0, slot);
40 }
41 
42 static int mcman_iomanx_backing_validate(int slot, int check_mounted)
43 {
44  vmc_cardinfo_t *cardinfo;
45 
46  if (slot > MCMAN_MAXSLOT) {
47  return -EOVERFLOW;
48  }
49 
50  cardinfo = &mcman_vmc_cardinfo[slot];
51 
52  if (check_mounted) {
53  if (cardinfo->mounted == 0) {
54  return -ENXIO;
55  }
56  }
57  return 0;
58 }
59 
60 int mcman_iomanx_backing_mount(int port, int slot, const char *filename)
61 {
62  int fd;
63  int cardsize;
64  int r;
65  vmc_cardinfo_t *cardinfo;
66 
67  (void)port;
68 
69  r = mcman_iomanx_backing_validate(slot, 0);
70  if (r < 0) {
71  goto cleanup;
72  }
73 
74  r = -EINVAL;
75 
76  cardinfo = &mcman_vmc_cardinfo[slot];
77 
78  fd = iomanX_open(filename, FIO_O_RDWR, 0);
79  if (fd < 0) {
80  // Propogate open error
81  r = fd;
82  goto cleanup;
83  }
84  cardinfo->fd = fd;
85 
86  cardsize = iomanX_lseek(fd, 0, FIO_SEEK_END);
87  cardinfo->cardsize = cardsize;
88  iomanX_lseek(fd, 0, FIO_SEEK_SET);
89 
90  // Check superblock for correct parameters
91  {
92  MCDevInfo superblock;
93  int read_result;
94  int total_pages;
95 
96  read_result = iomanX_read(fd, &superblock, sizeof(superblock));
97  if (read_result != sizeof(superblock)) {
98  if (read_result >= 0) {
99  r = -EINVAL;
100  }
101  else {
102  r = read_result;
103  }
104  goto cleanup;
105  }
106  // Check magic
107  if (strncmp(superblock.magic, SUPERBLOCK_MAGIC, 28) != 0) {
108  r = -EINVAL;
109  goto cleanup;
110  }
111  // Check card type
112  if (superblock.cardtype != sceMcTypePS2) {
113  r = -EINVAL;
114  goto cleanup;
115  }
116  total_pages = superblock.pages_per_cluster * superblock.blocksize;
117  // Check card ECC
118  if (cardsize == ((superblock.pagesize + 0x10) * total_pages)) {
119  cardinfo->has_ecc = 1;
120  }
121  else if (cardsize == ((superblock.pagesize) * total_pages)) {
122  cardinfo->has_ecc = 0;
123  }
124  else {
125  // size is invalid
126  r = -EINVAL;
127  goto cleanup;
128  }
129  // Check page size
130  if (superblock.pagesize != 512 && superblock.pagesize != 528) {
131  // Not a tested page size
132  r = -EINVAL;
133  goto cleanup;
134  }
135 
136  // Retrieve rest of info
137  cardinfo->pagesize = superblock.pagesize;
138  cardinfo->blocksize = superblock.blocksize;
139  cardinfo->flags = superblock.cardflags;
140  }
141 
142  mcman_probePS2Card(port, slot);
143  if (McGetFormat(port, slot) > 0) {
144  r = 0; // Success
145  goto cleanup;
146  }
147  if (McGetFormat(port, slot) < 0) {
148  r = -EIO;
149  goto cleanup;
150  }
151 
152 cleanup:
153  if (r < 0) {
154  mcman_iomanx_backing_clear_slot(slot);
155  }
156  return r;
157 }
158 
159 int mcman_iomanx_backing_umount(int port, int slot)
160 {
161  int r;
162 
163  (void)port;
164 
165  r = mcman_iomanx_backing_validate(slot, 1);
166  if (r < 0) {
167  goto cleanup;
168  }
169 
170  mcman_iomanx_backing_clear_slot(slot);
171 
172 cleanup:
173  return r;
174 }
175 
176 int mcman_iomanx_backing_getcardspec(int port, int slot, s16 *pagesize, u16 *blocksize, int *cardsize, u8 *flags)
177 {
178  int r;
179  vmc_cardinfo_t *cardinfo;
180 
181  (void)port;
182 
183  r = mcman_iomanx_backing_validate(slot, 1);
184  if (r < 0) {
185  return 1;
186  }
187 
188  cardinfo = &mcman_vmc_cardinfo[slot];
189 
190  if (pagesize) {
191  *pagesize = cardinfo->pagesize;
192  }
193 
194  if (blocksize) {
195  *blocksize = cardinfo->blocksize;
196  }
197 
198  if (cardsize) {
199  *cardsize = cardinfo->cardsize;
200  }
201 
202  if (flags) {
203  *flags = cardinfo->flags;
204  }
205 
206  return 0;
207 }
208 
209 int mcman_iomanx_backing_erase(int port, int slot, int page)
210 {
211  int r;
212  vmc_cardinfo_t *cardinfo;
213 
214  (void)port;
215 
216  r = mcman_iomanx_backing_validate(slot, 1);
217  if (r < 0) {
218  return 1;
219  }
220 
221  cardinfo = &mcman_vmc_cardinfo[slot];
222 
223  {
224  char buf[528];
225  int effective_page_size;
226 
227  memset(buf, ((cardinfo->flags & CF_ERASE_ZEROES) != 0) ? 0x0 : 0xFF, sizeof(buf));
228  effective_page_size = (cardinfo->pagesize + (cardinfo->has_ecc ? 0x10 : 0));
229  iomanX_lseek(cardinfo->fd, page * effective_page_size, FIO_SEEK_SET);
230  iomanX_write(cardinfo->fd, buf, effective_page_size);
231  }
232 
233  return 0;
234 }
235 
236 int mcman_iomanx_backing_write(int port, int slot, int page, void *pagebuf, void *eccbuf)
237 {
238  int r;
239  vmc_cardinfo_t *cardinfo;
240 
241  (void)port;
242 
243  r = mcman_iomanx_backing_validate(slot, 1);
244  if (r < 0) {
245  return 1;
246  }
247 
248  cardinfo = &mcman_vmc_cardinfo[slot];
249 
250  {
251  int effective_page_size;
252 
253  effective_page_size = (cardinfo->pagesize + (cardinfo->has_ecc ? 0x10 : 0));
254  iomanX_lseek(cardinfo->fd, page * effective_page_size, FIO_SEEK_SET);
255  if (pagebuf != NULL) {
256  iomanX_write(cardinfo->fd, pagebuf, 512);
257  }
258  else {
259  iomanX_lseek(cardinfo->fd, 512, FIO_SEEK_CUR);
260  }
261 
262  if (cardinfo->has_ecc) {
263  if (eccbuf != NULL) {
264  iomanX_write(cardinfo->fd, eccbuf, 16);
265  }
266  else {
267  iomanX_lseek(cardinfo->fd, 16, FIO_SEEK_CUR);
268  }
269  }
270  }
271 
272  // FIXME: implement
273 
274  return 0;
275 }
276 
277 int mcman_iomanx_backing_read(int port, int slot, int page, void *pagebuf, void *eccbuf)
278 {
279  int r;
280  vmc_cardinfo_t *cardinfo;
281 
282  (void)port;
283 
284  r = mcman_iomanx_backing_validate(slot, 1);
285  if (r < 0) {
286  return 1;
287  }
288 
289  cardinfo = &mcman_vmc_cardinfo[slot];
290 
291  {
292  int pagesize;
293  int effective_page_size;
294 
295  pagesize = cardinfo->pagesize;
296 
297  effective_page_size = (cardinfo->pagesize + (cardinfo->has_ecc ? 0x10 : 0));
298  iomanX_lseek(cardinfo->fd, page * effective_page_size, FIO_SEEK_SET);
299  if (pagebuf != NULL) {
300  iomanX_read(cardinfo->fd, pagebuf, 512);
301  }
302  else {
303  iomanX_lseek(cardinfo->fd, 512, FIO_SEEK_CUR);
304  }
305 
306  if (cardinfo->has_ecc) {
307  if (eccbuf != NULL) {
308  iomanX_read(cardinfo->fd, eccbuf, 16);
309  }
310  else {
311  iomanX_lseek(cardinfo->fd, 16, FIO_SEEK_CUR);
312  }
313  } else if (pagebuf != NULL && eccbuf != NULL) {
314  int i;
315  int ecc_count;
316  u8 *p_page, *p_ecc;
317 
318  // Make our own ECC
319 
320  memset(eccbuf, ((cardinfo->flags & CF_ERASE_ZEROES) != 0) ? 0x0 : 0xFF, 16);
321  p_page = pagebuf;
322  p_ecc = eccbuf;
323 
324  i = 0; //s1
325  do {
326  if (pagesize < 0)
327  ecc_count = (pagesize + 0x7f) >> 7;
328  else
329  ecc_count = pagesize >> 7;
330 
331  if (i >= ecc_count)
332  break;
333 
334  McDataChecksum(p_page, p_ecc);
335 
336  p_ecc = (void *)((u8 *)p_ecc + 3);
337  p_page = (void *)((u8 *)p_page + 128);
338  i++;
339  } while (1);
340  }
341  }
342 
343  return 0;
344 }
345 #endif
EOVERFLOW
#define EOVERFLOW
Definition: errno.h:269
ENXIO
#define ENXIO
Definition: errno.h:31
EIO
#define EIO
Definition: errno.h:29
EINVAL
#define EINVAL
Definition: errno.h:63
MCDevInfo
Definition: mcman-internal.h:295
mcman.h