1 /*
2 * UAE - The Un*x Amiga Emulator
3 *
4 * Support for IPF/CAPS disk images
5 *
6 * Copyright 2004-2007 Richard Drummond
7 *
8 * Based on Win32 CAPS code by Toni Wilen
9 */
10
11 #include "sysconfig.h"
12 #include "sysdeps.h"
13
14 #ifdef CAPS
15
16 #include "caps.h"
17 #include "zfile.h"
18 #include "caps/capsimage.h"
19
20 static CapsLong caps_cont[4]= {-1, -1, -1, -1};
21 static int caps_locked[4];
22 static int caps_flags = DI_LOCK_DENVAR|DI_LOCK_DENNOISE|DI_LOCK_NOISE|DI_LOCK_UPDATEFD|DI_LOCK_TYPE;
23 #define LIB_TYPE 1
24
25
26 #if !defined HAVE_FRAMEWORK_CAPSIMAGE
27
28 #include "uae_dlopen.h"
29
30 #ifdef __LIBRETRO__
31 #include "retro_files.h"
32 extern char *retro_system_directory;
33 char CAPSLIB_PATH[RETRO_PATH_MAX];
34 #endif
35
36 #ifdef _WIN32
37 #define CAPSLIB_NAME "capsimg.dll"
38 #define DIR_SEP_CHR '\\'
39 #else
40 #define CAPSLIB_NAME "capsimg.so"
41 #define DIR_SEP_CHR '/'
42 #endif
43
44 /*
45 * Repository for function pointers to the CAPSLib routines
46 * which gets filled when we link at run-time
47 *
48 * We don't symbolically link on the Amiga, so don't need
49 * this there
50 */
51 struct {
52 void *handle;
53 CapsLong (*CAPSInit)(void);
54 CapsLong (*CAPSExit)(void);
55 CapsLong (*CAPSAddImage)(void);
56 CapsLong (*CAPSRemImage)(CapsLong id);
57 CapsLong (*CAPSLockImage)(CapsLong id, char *name);
58 CapsLong (*CAPSLockImageMemory)(CapsLong id, CapsUByte *buffer, CapsULong length, CapsULong flag);
59 CapsLong (*CAPSUnlockImage)(CapsLong id);
60 CapsLong (*CAPSLoadImage)(CapsLong id, CapsULong flag);
61 CapsLong (*CAPSGetImageInfo)(struct CapsImageInfo *pi, CapsLong id);
62 CapsLong (*CAPSLockTrack)(struct CapsTrackInfo *pi, CapsLong id, CapsULong cylinder, CapsULong head, CapsULong flag);
63 CapsLong (*CAPSUnlockTrack)(CapsLong id, CapsULong cylinder, CapsULong head);
64 CapsLong (*CAPSUnlockAllTracks)(CapsLong id);
65 char *(*CAPSGetPlatformName)(CapsULong pid);
66 CapsLong (*CAPSGetVersionInfo)(struct CapsVersionInfo *pi, CapsULong flag);
67 } capslib;
68
69 /*
70 * The Unix/dlopen method for loading and linking the CAPSLib plug-in
71 */
load_capslib(void)72 static int load_capslib (void)
73 {
74 /* This could be done more elegantly ;-) */
75
76 #ifdef __LIBRETRO__
77 snprintf(CAPSLIB_PATH, RETRO_PATH_MAX, "%s%c%s", retro_system_directory, DIR_SEP_CHR, CAPSLIB_NAME);
78 if ((capslib.handle = uae_dlopen(CAPSLIB_PATH))) {
79 #else
80 if ((capslib.handle = uae_dlopen(CAPSLIB_NAME))) {
81 #endif
82 write_log (CAPSLIB_NAME " opened\n");
83 capslib.CAPSInit = uae_dlsym (capslib.handle, "CAPSInit"); if (capslib.CAPSInit == NULL) return 0;
84 capslib.CAPSExit = uae_dlsym (capslib.handle, "CAPSExit"); if (capslib.CAPSExit == NULL) return 0;
85 capslib.CAPSAddImage = uae_dlsym (capslib.handle, "CAPSAddImage"); if (capslib.CAPSAddImage == NULL) return 0;
86 capslib.CAPSRemImage = uae_dlsym (capslib.handle, "CAPSRemImage"); if (capslib.CAPSRemImage == NULL) return 0;
87 capslib.CAPSLockImage = uae_dlsym (capslib.handle, "CAPSLockImage"); if (capslib.CAPSLockImage == NULL) return 0;
88 capslib.CAPSLockImageMemory = uae_dlsym (capslib.handle, "CAPSLockImageMemory"); if (capslib.CAPSLockImageMemory == NULL) return 0;
89 capslib.CAPSUnlockImage = uae_dlsym (capslib.handle, "CAPSUnlockImage"); if (capslib.CAPSUnlockImage == NULL) return 0;
90 capslib.CAPSLoadImage = uae_dlsym (capslib.handle, "CAPSLoadImage"); if (capslib.CAPSLoadImage == NULL) return 0;
91 capslib.CAPSGetImageInfo = uae_dlsym (capslib.handle, "CAPSGetImageInfo"); if (capslib.CAPSGetImageInfo == NULL) return 0;
92 capslib.CAPSLockTrack = uae_dlsym (capslib.handle, "CAPSLockTrack"); if (capslib.CAPSLockTrack == NULL) return 0;
93 capslib.CAPSUnlockTrack = uae_dlsym (capslib.handle, "CAPSUnlockTrack"); if (capslib.CAPSUnlockTrack == NULL) return 0;
94 capslib.CAPSUnlockAllTracks = uae_dlsym (capslib.handle, "CAPSUnlockAllTracks"); if (capslib.CAPSUnlockAllTracks == NULL) return 0;
95 capslib.CAPSGetPlatformName = uae_dlsym (capslib.handle, "CAPSGetPlatformName"); if (capslib.CAPSGetPlatformName == NULL) return 0;
96 capslib.CAPSGetVersionInfo = uae_dlsym (capslib.handle, "CAPSGetVersionInfo"); if (capslib.CAPSGetVersionInfo == NULL) return 0;
97 if (capslib.CAPSInit() != imgeOk)
98 write_log ("Error while opening " CAPSLIB_NAME "\n");
99 return 1;
100 }
101 write_log ("Unable to open " CAPSLIB_NAME "\n");
102 return 0;
103 }
104
105 /*
106 * Some defines so that we don't care that CAPSLib
107 * isn't statically linked
108 */
109 #define CAPSInit capslib.CAPSInit
110 #define CAPSExit capslib.CAPSExit
111 #define CAPSAddImage capslib.CAPSAddImage
112 #define CAPSRemImage capslib.CAPSRemImage
113 #define CAPSLockImage capslib.CAPSLockImage
114 #define CAPSLockImageMemory capslib.CAPSLockImageMemory
115 #define CAPSUnlockImage capslib.CAPSUnlockImage
116 #define CAPSLoadImage capslib.CAPSLoadImage
117 #define CAPSGetImageInfo capslib.CAPSGetImageInfo
118 #define CAPSLockTrack capslib.CAPSLockTrack
119 #define CAPSUnlockTrack capslib.CAPSUnlockTrack
120 #define CAPSUnlockAllTracks capslib.CAPSUnlockAllTracks
121 #define CAPSGetPlatformName capslib.CAPSGetPlatformName
122 #define CAPSGetVersionInfo capslib.CAPSGetVersionInfo
123
124 #else
125 #ifdef HAVE_FRAMEWORK_CAPSIMAGE
126
127 /*
128 * On OS X we link weakly to the CAPSImage framework. Thus we can
129 * let the dynamic linker take care of everything.
130 */
131
132 /* We check for the existence of this symbol to tell whether the
133 * the framework could be linked or not.
134 */
135 extern CapsLong CAPSInit(void) __attribute__((weak));
136
137 static int load_capslib (void)
138 {
139 if (CAPSInit != NULL)
140 return 1;
141 else
142 return 0;
143 }
144
145 #else
146
147 #ifdef TARGET_AMIGAOS
148 #ifdef __amigaos4__
149 #define __USE_BASETYPE__
150 #include <exec/emulation.h>
151 #include <proto/exec.h>
152
153 static struct Device *CapsImageBase;
154
155 /* Emulation stubs for AmigaOS4. Ideally this should be in a separate
156 * link library (until a native CAPS plug-in becomes available), but I
157 * haven't been able to get that to work.
158 *
159 * This stuff is adapated from the machine-generated output from fdtrans.
160 */
161 LONG CAPSInit (void)
162 {
163 struct Library *LibBase = (struct Library *)CapsImageBase;
164 LONG retval;
165 ULONG *regs = (ULONG *)(SysBase->EmuWS);
166 ULONG save_A6 = regs[14];
167
168 retval = (LONG)EmulateTags ((APTR)LibBase,
169 ET_Offset, -42, /* Hex: -0x2A */
170 ET_RegisterA6, LibBase,
171 TAG_DONE);
172 regs[14] = save_A6;
173 return retval;
174 }
175
176 LONG CAPSExit (void)
177 {
178 struct Library *LibBase = (struct Library *)CapsImageBase;
179 LONG retval;
180 ULONG *regs = (ULONG *)(SysBase->EmuWS);
181 ULONG save_A6 = regs[14];
182
183 retval = (LONG)EmulateTags ((APTR)LibBase,
184 ET_Offset, -48, /* Hex: -0x30 */
185 ET_RegisterA6, LibBase,
186 TAG_DONE);
187 regs[14] = save_A6;
188 return retval;
189 }
190
191 LONG CAPSAddImage (void)
192 {
193 struct Library *LibBase = (struct Library *)CapsImageBase;
194 LONG retval;
195 ULONG *regs = (ULONG *)(SysBase->EmuWS);
196 ULONG save_A6 = regs[14];
197
198 retval = (LONG)EmulateTags ((APTR)LibBase,
199 ET_Offset, -54, /* Hex: -0x36 */
200 ET_RegisterA6, LibBase,
201 TAG_DONE);
202 regs[14] = save_A6;
203 return retval;
204 }
205
206 LONG CAPSRemImage (LONG id)
207 {
208 struct Library *LibBase = (struct Library*) CapsImageBase;
209 LONG retval;
210 ULONG *regs = (ULONG *)(SysBase->EmuWS);
211 ULONG save_A6 = regs[14];
212
213 retval = (LONG)EmulateTags ((APTR)LibBase,
214 ET_Offset, -60, /* Hex: -0x3C */
215 ET_RegisterD0, id,
216 ET_RegisterA6, LibBase,
217 TAG_DONE);
218 regs[14] = save_A6;
219 return retval;
220 }
221
222 CapsLong CAPSLockImage (CapsLong id, char *name)
223 {
224 struct Library *LibBase = (struct Library*)CapsImageBase;
225 LONG retval;
226 ULONG *regs = (ULONG *)(SysBase->EmuWS);
227 ULONG save_a0 = regs[8];
228 ULONG save_A6 = regs[14];
229
230 retval = (LONG)EmulateTags ((APTR)LibBase,
231 ET_Offset, -66, /* Hex: -0x42 */
232 ET_RegisterD0, id,
233 ET_RegisterA0, name,
234 ET_RegisterA6, LibBase,
235 TAG_DONE);
236 regs[8] = save_a0;
237 regs[14] = save_A6;
238 return retval;
239 }
240
241 LONG CAPSLockImageMemory (LONG id,
242 UBYTE * buffer,
243 ULONG length,
244 ULONG flag)
245 {
246 struct Library *LibBase = (struct Library*)CapsImageBase;
247 LONG retval;
248 ULONG *regs = (ULONG *)(SysBase->EmuWS);
249 ULONG save_a0 = regs[8];
250 ULONG save_d2 = regs[2];
251 ULONG save_A6 = regs[14];
252
253 retval = (LONG)EmulateTags ((APTR)LibBase,
254 ET_Offset, -72, /* Hex: -0x48 */
255 ET_RegisterD0, id,
256 ET_RegisterA0, buffer,
257 ET_RegisterD1, length,
258 ET_RegisterD2, flag,
259 ET_RegisterA6, LibBase,
260 TAG_DONE);
261 regs[8] = save_a0;
262 regs[2] = save_d2;
263 regs[14] = save_A6;
264 return retval;
265 }
266
267 LONG CAPSUnlockImage (LONG id)
268 {
269 struct Library *LibBase = (struct Library*)CapsImageBase;
270 LONG retval;
271 ULONG *regs = (ULONG *)(SysBase->EmuWS);
272 ULONG save_A6 = regs[14];
273
274 retval = (LONG)EmulateTags ((APTR)LibBase,
275 ET_Offset, -78, /* Hex: -0x4E */
276 ET_RegisterD0, id,
277 ET_RegisterA6, LibBase,
278 TAG_DONE);
279 regs[14] = save_A6;
280 return retval;
281 }
282
283 LONG CAPSLoadImage (LONG id, ULONG flag)
284 {
285 struct Library *LibBase = (struct Library *)CapsImageBase;
286 LONG retval;
287 ULONG *regs = (ULONG *)(SysBase->EmuWS);
288 ULONG save_A6 = regs[14];
289
290 retval = (LONG)EmulateTags ((APTR)LibBase,
291 ET_Offset, -84, /* Hex: -0x54 */
292 ET_RegisterD0, id,
293 ET_RegisterD1, flag,
294 ET_RegisterA6, LibBase,
295 TAG_DONE);
296 regs[14] = save_A6;
297 return retval;
298 }
299
300 LONG CAPSGetImageInfo (struct CapsImageInfo * pi, LONG id)
301 {
302 struct Library *LibBase = (struct Library*)CapsImageBase;
303 LONG retval;
304 ULONG *regs = (ULONG *)(SysBase->EmuWS);
305 ULONG save_a0 = regs[8];
306 ULONG save_A6 = regs[14];
307
308 retval = (LONG)EmulateTags ((APTR)LibBase,
309 ET_Offset, -90, /* Hex: -0x5A */
310 ET_RegisterA0, pi,
311 ET_RegisterD0, id,
312 ET_RegisterA6, LibBase,
313 TAG_DONE);
314 regs[8] = save_a0;
315 regs[14] = save_A6;
316 return retval;
317 }
318
319 LONG CAPSLockTrack (struct CapsTrackInfo * pi,
320 LONG id,
321 ULONG cylinder,
322 ULONG head,
323 ULONG flag)
324 {
325 struct Library *LibBase = (struct Library*)CapsImageBase;
326 LONG retval;
327 ULONG *regs = (ULONG *)(SysBase->EmuWS);
328 ULONG save_a0 = regs[8];
329 ULONG save_d2 = regs[2];
330 ULONG save_d3 = regs[3];
331 ULONG save_A6 = regs[14];
332
333 retval = (LONG) EmulateTags((APTR)LibBase,
334 ET_Offset, -96, /* Hex: -0x60 */
335 ET_RegisterA0, pi,
336 ET_RegisterD0, id,
337 ET_RegisterD1, cylinder,
338 ET_RegisterD2, head,
339 ET_RegisterD3, flag,
340 ET_RegisterA6, LibBase,
341 TAG_DONE);
342 regs[8] = save_a0;
343 regs[2] = save_d2;
344 regs[3] = save_d3;
345 regs[14] = save_A6;
346 return retval;
347 }
348
349 LONG CAPSUnlockAllTracks (LONG id)
350 {
351 struct Library *LibBase = (struct Library*)CapsImageBase;
352 LONG retval;
353 ULONG *regs = (ULONG *)(SysBase->EmuWS);
354 ULONG save_A6 = regs[14];
355
356 retval = (LONG) EmulateTags ((APTR)LibBase,
357 ET_Offset, -108, /* Hex: -0x6C */
358 ET_RegisterD0, id,
359 ET_RegisterA6, LibBase,
360 TAG_DONE);
361 regs[14] = save_A6;
362 return retval;
363 }
364
365 LONG CAPSGetVersionInfo (struct CapsVersionInfo *pi, CapsULong flag)
366 {
367 struct Library *LibBase = (struct Library*)CapsImageBase;
368 LONG retval;
369 ULONG *regs = (ULONG *)(SysBase->EmuWS);
370 ULONG save_a0 = regs[8];
371 ULONG save_A6 = regs[14];
372
373 retval = (LONG) EmulateTags ((APTR)LibBase,
374 ET_Offset, -120, /* Hex: -0x78 */
375 ET_RegisterA0, pi,
376 ET_RegisterD0, flag,
377 ET_RegisterA6, LibBase,
378 TAG_DONE);
379 regs[8] = save_a0;
380 regs[14] = save_A6;
381 return retval;
382 }
383
384 #else
385
386 #if 0
387 /* proto file is broken in current CAPS API */
388 #include <proto/capsimage.h>
389 #else
390 #if defined __GNUC__ && !defined __amigaos4__
391 #include <inline/capsimage.h>
392 static struct Device *CapsImageBase;
393 #endif
394 #endif
395 #endif
396
397 #include <proto/exec.h>
398
399 static struct MsgPort *CAPS_MsgPort;
400 static struct IORequest *CAPS_IOReq;
401
402 static void unload_capslib (void)
403 {
404 CloseDevice (CAPS_IOReq);
405 DeleteIORequest (CAPS_IOReq);
406 DeleteMsgPort (CAPS_MsgPort);
407 }
408
409 static int load_capslib (void)
410 {
411 if ((CAPS_MsgPort = CreateMsgPort ())) {
412 if ((CAPS_IOReq = CreateIORequest (CAPS_MsgPort, sizeof(struct IORequest)))) {
413 if (!OpenDevice(CAPS_NAME, 0, CAPS_IOReq, 0)) {
414 CapsImageBase = CAPS_IOReq->io_Device;
415 if (CapsImageBase->dd_Library.lib_Version >= 2) {
416 if (CAPSInit () == imgeOk) {
417 atexit (unload_capslib);
418 return 1;
419 }
420 } else
421 write_log ("CAPS: Please install capsimage.device version 2 or newer.\n");
422
423 CloseDevice (CAPS_IOReq);
424 }
425 DeleteIORequest (CAPS_IOReq);
426 }
427 DeleteMsgPort (CAPS_MsgPort);
428 }
429 return 0;
430 }
431
432 #else
433
434 /*
435 * Sorry, we don't know how to load the CAPSLib plug-in
436 * on other systems yet . ..
437 */
438 static int load_capslib (void)
439 {
440 return 0;
441 }
442
443 #endif
444 #endif
445 #endif
446
447 /*
448 * CAPS support proper starts here
449 *
450 * This is more or less a straight copy of Toni's Win32 code
451 */
452 int caps_init (void)
453 {
454 static int init, noticed;
455 unsigned int i;
456 struct CapsVersionInfo cvi;
457
458 if (init)
459 return 1;
460
461 if (!load_capslib ()) {
462 write_log ("Failed to load CAPS plug-in.\n");
463 if (noticed)
464 return 0;
465 gui_message ("This disk image needs the C.A.P.S. plugin "
466 "which is available from "
467 "http://www.softpres.org/download");
468 noticed = 1;
469 return 0;
470 }
471 init = 1;
472 cvi.type = LIB_TYPE;
473 CAPSGetVersionInfo (&cvi, 0);
474 write_log ("CAPS: library version %d.%d\n", cvi.release, cvi.revision);
475 for (i = 0; i < 4; i++)
476 caps_cont[i] = CAPSAddImage ();
477
478 return 1;
479 }
480
481 void caps_unloadimage (unsigned int drv)
482 {
483 if (!caps_locked[drv])
484 return;
485 CAPSUnlockAllTracks (caps_cont[drv]);
486 CAPSUnlockImage (caps_cont[drv]);
487 caps_locked[drv] = 0;
488 }
489
490 int caps_loadimage (struct zfile *zf, unsigned int drv, unsigned int *num_tracks)
491 {
492 struct CapsImageInfo ci;
493 int len, ret;
494 uae_u8 *buf;
495 char s1[100];
496 struct CapsDateTimeExt *cdt;
497
498 if (!caps_init ())
499 return 0;
500 caps_unloadimage (drv);
501 zfile_fseek (zf, 0, SEEK_END);
502 len = zfile_ftell (zf);
503 zfile_fseek (zf, 0, SEEK_SET);
504 buf = xmalloc (uae_u8, len);
505 if (!buf)
506 return 0;
507 if (zfile_fread (buf, len, 1, zf) == 0)
508 return 0;
509 ret = CAPSLockImageMemory (caps_cont[drv], buf, len, 0);
510 xfree (buf);
511 if (ret != imgeOk)
512 return 0;
513 caps_locked[drv] = 1;
514 CAPSGetImageInfo (&ci, caps_cont[drv]);
515 *num_tracks = (ci.maxcylinder - ci.mincylinder + 1) * (ci.maxhead - ci.minhead + 1);
516 CAPSLoadImage (caps_cont[drv], caps_flags);
517 cdt = &ci.crdt;
518 sprintf (s1, "%d.%d.%d %d:%d:%d", cdt->day, cdt->month, cdt->year, cdt->hour, cdt->min, cdt->sec);
519 write_log ("CAPS: type:%d date:%s rel:%d rev:%d\n",
520 ci.type, s1, ci.release, ci.revision);
521 return 1;
522 }
523
524 int caps_loadrevolution (uae_u16 *mfmbuf, unsigned int drv, unsigned int track, unsigned int *tracklength)
525 {
526 unsigned int len, i;
527 uae_u16 *mfm;
528 struct CapsTrackInfoT1 ci;
529
530 ci.type = LIB_TYPE;
531 CAPSLockTrack ((struct CapsTrackInfo *)&ci, caps_cont[drv], track / 2, track & 1, caps_flags);
532 len = ci.tracklen;
533 *tracklength = len * 8;
534 mfm = mfmbuf;
535 for (i = 0; i < (len + 1) / 2; i++) {
536 uae_u8 *data = ci.trackbuf + i * 2;
537 *mfm++ = 256 * *data + *(data + 1);
538 }
539 return 1;
540 }
541
542 int caps_loadtrack (uae_u16 *mfmbuf, uae_u16 *tracktiming, unsigned int drv, unsigned int track, unsigned int *tracklength, int *multirev, unsigned int *gapoffset)
543 {
544 unsigned int i, len, type;
545 uae_u16 *mfm;
546 struct CapsTrackInfoT1 ci;
547
548 ci.type = LIB_TYPE;
549 if (tracktiming)
550 *tracktiming = 0;
551 CAPSLockTrack ((struct CapsTrackInfo *)&ci, caps_cont[drv], track / 2, track & 1, caps_flags);
552 mfm = mfmbuf;
553 *multirev = (ci.type & CTIT_FLAG_FLAKEY) ? 1 : 0;
554 type = ci.type & CTIT_MASK_TYPE;
555 len = ci.tracklen;
556 *tracklength = len * 8;
557 *gapoffset = ci.overlap >= 0 ? ci.overlap * 8 : -1;
558 for (i = 0; i < (len + 1) / 2; i++) {
559 uae_u8 *data = ci.trackbuf + i * 2;
560 *mfm++ = 256 * *data + *(data + 1);
561 }
562 if (ci.timelen > 0 && tracktiming) {
563 for (i = 0; i < ci.timelen; i++)
564 tracktiming[i] = (uae_u16)ci.timebuf[i];
565 }
566 return 1;
567 }
568
569 #else /* #ifdef CAPS */
570
571 /* Stop OS X linker complaining about empty link library */
572
573 void caps_dummy (void);
574 void caps_dummy (void)
575 {
576 }
577
578 #endif
579