1 #include "sysconfig.h"
2 #include "sysdeps.h"
3
4 #ifdef CAPS
5
6 #ifdef _WIN32
7 #include <shlobj.h>
8 #endif
9
10 #include "caps_win32.h"
11 #include "zfile.h"
12 #include "gui.h"
13 #include "uae.h"
14 #include "uae/dlopen.h"
15
16 #include "Comtype.h"
17 #include "CapsAPI.h"
18
19 #define CAPS_TRACKTIMING 1
20 #define LOG_REVOLUTION 0
21
22 static SDWORD caps_cont[4]= {-1, -1, -1, -1};
23 static bool caps_revolution_hack[4];
24 static int caps_locked[4];
25 static int caps_flags = DI_LOCK_DENVAR|DI_LOCK_DENNOISE|DI_LOCK_NOISE|DI_LOCK_UPDATEFD|DI_LOCK_TYPE|DI_LOCK_OVLBIT;
26 static struct CapsVersionInfo cvi;
27 static bool oldlib, canseed;
28
29 #ifdef _WIN32
30 #define CAPSCALL __cdecl
31 #else
32 #define CAPSCALL
33 #endif
34
35 typedef SDWORD (CAPSCALL * CAPSINIT)(void);
36 static CAPSINIT pCAPSInit;
37 typedef SDWORD (CAPSCALL * CAPSADDIMAGE)(void);
38 static CAPSADDIMAGE pCAPSAddImage;
39 typedef SDWORD (CAPSCALL * CAPSLOCKIMAGEMEMORY)(SDWORD,PUBYTE,UDWORD,UDWORD);
40 static CAPSLOCKIMAGEMEMORY pCAPSLockImageMemory;
41 typedef SDWORD (CAPSCALL * CAPSUNLOCKIMAGE)(SDWORD);
42 static CAPSUNLOCKIMAGE pCAPSUnlockImage;
43 typedef SDWORD (CAPSCALL * CAPSLOADIMAGE)(SDWORD,UDWORD);
44 static CAPSLOADIMAGE pCAPSLoadImage;
45 typedef SDWORD (CAPSCALL * CAPSGETIMAGEINFO)(PCAPSIMAGEINFO,SDWORD);
46 static CAPSGETIMAGEINFO pCAPSGetImageInfo;
47 typedef SDWORD (CAPSCALL * CAPSLOCKTRACK)(PCAPSTRACKINFO,SDWORD,UDWORD,UDWORD,UDWORD);
48 static CAPSLOCKTRACK pCAPSLockTrack;
49 typedef SDWORD (CAPSCALL * CAPSUNLOCKTRACK)(SDWORD,UDWORD);
50 static CAPSUNLOCKTRACK pCAPSUnlockTrack;
51 typedef SDWORD (CAPSCALL * CAPSUNLOCKALLTRACKS)(SDWORD);
52 static CAPSUNLOCKALLTRACKS pCAPSUnlockAllTracks;
53 typedef SDWORD (CAPSCALL * CAPSGETVERSIONINFO)(PCAPSVERSIONINFO,UDWORD);
54 static CAPSGETVERSIONINFO pCAPSGetVersionInfo;
55 typedef SDWORD (CAPSCALL * CAPSGETINFO)(PVOID pinfo, SDWORD id, UDWORD cylinder, UDWORD head, UDWORD inftype, UDWORD infid);
56 static CAPSGETINFO pCAPSGetInfo;
57 typedef SDWORD (CAPSCALL * CAPSSETREVOLUTION)(SDWORD id, UDWORD value);
58 static CAPSSETREVOLUTION pCAPSSetRevolution;
59 typedef SDWORD (CAPSCALL * CAPSGETIMAGETYPEMEMORY)(PUBYTE buffer, UDWORD length);
60 static CAPSGETIMAGETYPEMEMORY pCAPSGetImageTypeMemory;
61
caps_init(void)62 int caps_init (void)
63 {
64 static int init, noticed;
65 int i;
66
67 if (init)
68 return 1;
69 #ifdef FSUAE
70 UAE_DLHANDLE h = uae_dlopen_plugin(_T("capsimg"));
71 #else
72 UAE_DLHANDLE h = uae_dlopen_plugin(_T("CAPSImg"));
73 if (!h) {
74 TCHAR tmp[MAX_DPATH];
75 if (SUCCEEDED (SHGetFolderPath (NULL, CSIDL_PROGRAM_FILES_COMMON, NULL, 0, tmp))) {
76 _tcscat (tmp, _T("\\Software Preservation Society\\"));
77 _tcscat (tmp, _T("CAPSImg.dll"));
78 h = uae_dlopen(tmp);
79 }
80 }
81 #endif
82 if (!h) {
83 if (noticed)
84 return 0;
85 notify_user (NUMSG_NOCAPS);
86 noticed = 1;
87 return 0;
88 }
89
90 if (uae_dlsym(h, "CAPSLockImageMemory") == 0 || uae_dlsym(h, "CAPSGetVersionInfo") == 0) {
91 if (noticed)
92 return 0;
93 notify_user (NUMSG_OLDCAPS);
94 noticed = 1;
95 return 0;
96 }
97
98 pCAPSInit = (CAPSINIT) uae_dlsym(h, "CAPSInit");
99 pCAPSAddImage = (CAPSADDIMAGE) uae_dlsym(h, "CAPSAddImage");
100 pCAPSLockImageMemory = (CAPSLOCKIMAGEMEMORY) uae_dlsym(h, "CAPSLockImageMemory");
101 pCAPSUnlockImage = (CAPSUNLOCKIMAGE) uae_dlsym(h, "CAPSUnlockImage");
102 pCAPSLoadImage = (CAPSLOADIMAGE) uae_dlsym(h, "CAPSLoadImage");
103 pCAPSGetImageInfo = (CAPSGETIMAGEINFO) uae_dlsym(h, "CAPSGetImageInfo");
104 pCAPSLockTrack = (CAPSLOCKTRACK) uae_dlsym(h, "CAPSLockTrack");
105 pCAPSUnlockTrack = (CAPSUNLOCKTRACK) uae_dlsym(h, "CAPSUnlockTrack");
106 pCAPSUnlockAllTracks = (CAPSUNLOCKALLTRACKS) uae_dlsym(h, "CAPSUnlockAllTracks");
107 pCAPSGetVersionInfo = (CAPSGETVERSIONINFO) uae_dlsym(h, "CAPSGetVersionInfo");
108 pCAPSGetInfo = (CAPSGETINFO) uae_dlsym(h, "CAPSGetInfo");
109 pCAPSSetRevolution = (CAPSSETREVOLUTION) uae_dlsym(h, "CAPSSetRevolution");
110 pCAPSGetImageTypeMemory = (CAPSGETIMAGETYPEMEMORY) uae_dlsym(h, "CAPSGetImageTypeMemory");
111
112 init = 1;
113 cvi.type = 1;
114 pCAPSGetVersionInfo (&cvi, 0);
115 write_log (_T("CAPS: library version %d.%d (flags=%08X)\n"), cvi.release, cvi.revision, cvi.flag);
116 oldlib = (cvi.flag & (DI_LOCK_TRKBIT | DI_LOCK_OVLBIT)) != (DI_LOCK_TRKBIT | DI_LOCK_OVLBIT);
117 if (!oldlib)
118 caps_flags |= DI_LOCK_TRKBIT | DI_LOCK_OVLBIT;
119 canseed = (cvi.flag & DI_LOCK_SETWSEED) != 0;
120 for (i = 0; i < 4; i++)
121 caps_cont[i] = pCAPSAddImage ();
122 return 1;
123 }
124
caps_unloadimage(int drv)125 void caps_unloadimage (int drv)
126 {
127 if (!caps_locked[drv])
128 return;
129 pCAPSUnlockAllTracks (caps_cont[drv]);
130 pCAPSUnlockImage (caps_cont[drv]);
131 caps_locked[drv] = 0;
132 }
133
caps_loadimage(struct zfile * zf,int drv,int * num_tracks)134 int caps_loadimage (struct zfile *zf, int drv, int *num_tracks)
135 {
136 static int notified;
137 struct CapsImageInfo ci;
138 int len, ret;
139 uae_u8 *buf;
140 TCHAR s1[100];
141 struct CapsDateTimeExt *cdt;
142 int type;
143
144 if (!caps_init ())
145 return 0;
146 caps_unloadimage (drv);
147 zfile_fseek (zf, 0, SEEK_END);
148 len = zfile_ftell (zf);
149 zfile_fseek (zf, 0, SEEK_SET);
150 if (len <= 0)
151 return 0;
152 buf = xmalloc (uae_u8, len);
153 if (!buf)
154 return 0;
155 if (zfile_fread (buf, len, 1, zf) == 0)
156 return 0;
157 type = -1;
158 if (pCAPSGetImageTypeMemory) {
159 type = pCAPSGetImageTypeMemory(buf, len);
160 if (type == citError || type == citUnknown) {
161 write_log(_T("caps: CAPSGetImageTypeMemory() returned %d\n"), type);
162 return 0;
163 }
164 if (type == citKFStream || type == citDraft) {
165 write_log(_T("caps: CAPSGetImageTypeMemory() returned unsupported image type %d\n"), type);
166 return 0;
167 }
168 }
169 ret = pCAPSLockImageMemory (caps_cont[drv], buf, len, 0);
170 xfree (buf);
171 if (ret != imgeOk) {
172 if (ret == imgeIncompatible || ret == imgeUnsupported) {
173 if (!notified)
174 notify_user (NUMSG_OLDCAPS);
175 notified = 1;
176 }
177 write_log (_T("caps: CAPSLockImageMemory() returned %d\n"), ret);
178 return 0;
179 }
180 caps_locked[drv] = 1;
181 ret = pCAPSGetImageInfo(&ci, caps_cont[drv]);
182 *num_tracks = (ci.maxcylinder - ci.mincylinder + 1) * (ci.maxhead - ci.minhead + 1);
183
184 if (cvi.release < 4) { // pre-4.x bug workaround
185 struct CapsTrackInfoT1 cit;
186 cit.type = 1;
187 if (pCAPSLockTrack ((PCAPSTRACKINFO)&cit, caps_cont[drv], 0, 0, caps_flags) == imgeIncompatible) {
188 if (!notified)
189 notify_user (NUMSG_OLDCAPS);
190 notified = 1;
191 caps_unloadimage (drv);
192 return 0;
193 }
194 pCAPSUnlockAllTracks (caps_cont[drv]);
195 }
196
197 ret = pCAPSLoadImage(caps_cont[drv], caps_flags);
198 caps_revolution_hack[drv] = type == citCTRaw;
199 cdt = &ci.crdt;
200 _stprintf (s1, _T("%d.%d.%d %d:%d:%d"), cdt->day, cdt->month, cdt->year, cdt->hour, cdt->min, cdt->sec);
201 write_log (_T("caps: type:%d imagetype:%d date:%s rel:%d rev:%d\n"), ci.type, type, s1, ci.release, ci.revision);
202 return 1;
203 }
204
205 #if 0
206 static void outdisk (void)
207 {
208 struct CapsTrackInfo ci;
209 int tr;
210 FILE *f;
211 static int done;
212
213 if (done)
214 return;
215 done = 1;
216 f = fopen("c:\\out3.dat", "wb");
217 if (!f)
218 return;
219 for (tr = 0; tr < 160; tr++) {
220 pCAPSLockTrack(&ci, caps_cont[0], tr / 2, tr & 1, caps_flags);
221 fwrite (ci.trackdata[0], ci.tracksize[0], 1, f);
222 fwrite ("XXXX", 4, 1, f);
223 }
224 fclose (f);
225 }
226 #endif
227
mfmcopy(uae_u16 * mfm,uae_u8 * data,int len)228 static void mfmcopy (uae_u16 *mfm, uae_u8 *data, int len)
229 {
230 int memlen = (len + 7) / 8;
231 for (int i = 0; i < memlen; i+=2) {
232 if (i + 1 < memlen)
233 *mfm++ = (data[i] << 8) + data[i + 1];
234 else
235 *mfm++ = (data[i] << 8);
236 }
237 }
238
load(struct CapsTrackInfoT2 * ci,int drv,int track,bool seed,bool newtrack)239 static int load (struct CapsTrackInfoT2 *ci, int drv, int track, bool seed, bool newtrack)
240 {
241 int flags = caps_flags;
242 if (canseed) {
243 ci->type = 2;
244 if (seed) {
245 flags |= DI_LOCK_SETWSEED;
246 ci->wseed = uaerand ();
247 }
248 } else {
249 ci->type = 1;
250 }
251 #if 0
252 if (newtrack)
253 flags |= DI_LOCK_NOUPDATE;
254 #endif
255 if (pCAPSLockTrack ((PCAPSTRACKINFO)ci, caps_cont[drv], track / 2, track & 1, flags) != imgeOk)
256 return 0;
257 return 1;
258 }
259
caps_loadrevolution(uae_u16 * mfmbuf,uae_u16 * tracktiming,int drv,int track,int * tracklength,int * nextrev,bool track_access_done)260 int caps_loadrevolution (uae_u16 *mfmbuf, uae_u16 *tracktiming, int drv, int track, int *tracklength, int *nextrev, bool track_access_done)
261 {
262 int len;
263 struct CapsTrackInfoT2 ci;
264
265 if (!track_access_done && caps_revolution_hack[drv]) {
266 #if LOG_REVOLUTION
267 CapsRevolutionInfo pinfo;
268 pCAPSGetInfo(&pinfo, caps_cont[drv], track / 2, track & 1, cgiitRevolution, 0);
269 write_log(_T("%03d skipped revolution increase. Next = %d\n"), track, pinfo.next);
270 #endif
271 return 1;
272 }
273 if (!load (&ci, drv, track, false, false))
274 return 0;
275 if (oldlib)
276 len = ci.tracklen * 8;
277 else
278 len = ci.tracklen;
279 *tracklength = len;
280 mfmcopy (mfmbuf, ci.trackbuf, len);
281 #if CAPS_TRACKTIMING
282 if (ci.timelen > 0 && tracktiming) {
283 for (int i = 0; i < ci.timelen; i++)
284 tracktiming[i] = (uae_u16)ci.timebuf[i];
285 }
286 #endif
287 if (nextrev && pCAPSGetInfo) {
288 CapsRevolutionInfo pinfo;
289 *nextrev = 0;
290 pCAPSGetInfo(&pinfo, caps_cont[drv], track / 2, track & 1, cgiitRevolution, 0);
291 #if LOG_REVOLUTION
292 write_log (_T("%03d load next rev = %d\n"), track, pinfo.next);
293 #endif
294 if (pinfo.max > 0)
295 *nextrev = pinfo.next;
296 }
297 return 1;
298 }
299
caps_loadtrack(uae_u16 * mfmbuf,uae_u16 * tracktiming,int drv,int track,int * tracklength,int * multirev,int * gapoffset,int * nextrev,bool sametrack)300 int caps_loadtrack (uae_u16 *mfmbuf, uae_u16 *tracktiming, int drv, int track, int *tracklength, int *multirev, int *gapoffset, int *nextrev, bool sametrack)
301 {
302 int len;
303 struct CapsTrackInfoT2 ci;
304 CapsRevolutionInfo pinfo;
305
306 if (tracktiming)
307 *tracktiming = 0;
308
309 if (nextrev && pCAPSSetRevolution) {
310 if (sametrack) {
311 pCAPSSetRevolution(caps_cont[drv], *nextrev);
312 #if LOG_REVOLUTION
313 write_log(_T("%03d set rev = %d\n"), track, *nextrev);
314 #endif
315 } else {
316 pCAPSSetRevolution(caps_cont[drv], 0);
317 #if LOG_REVOLUTION
318 write_log(_T("%03d clear rev\n"), track, *nextrev);
319 #endif
320 }
321 }
322
323 if (!load (&ci, drv, track, true, sametrack != true))
324 return 0;
325
326 if (pCAPSGetInfo) {
327 if (nextrev)
328 *nextrev = 0;
329 pCAPSGetInfo(&pinfo, caps_cont[drv], track / 2, track & 1, cgiitRevolution, 0);
330 #if LOG_REVOLUTION
331 write_log(_T("%03d get next rev = %d\n"), track, pinfo.next);
332 #endif
333 if (nextrev && sametrack && pinfo.max > 0)
334 *nextrev = pinfo.next;
335 }
336
337 *multirev = (ci.type & CTIT_FLAG_FLAKEY) ? 1 : 0;
338 if (oldlib) {
339 len = ci.tracklen * 8;
340 *gapoffset = ci.overlap >= 0 ? ci.overlap * 8 : -1;
341 } else {
342 len = ci.tracklen;
343 *gapoffset = ci.overlap >= 0 ? ci.overlap : -1;
344 }
345 //write_log (_T("%d %d %d %d\n"), track, len, ci.tracklen, ci.overlap);
346 *tracklength = len;
347 mfmcopy (mfmbuf, ci.trackbuf, len);
348 #if 0
349 {
350 FILE *f=fopen("c:\\1.txt","wb");
351 fwrite (ci.trackbuf, len, 1, f);
352 fclose (f);
353 }
354 #endif
355 #if CAPS_TRACKTIMING
356 if (ci.timelen > 0 && tracktiming) {
357 for (int i = 0; i < ci.timelen; i++)
358 tracktiming[i] = (uae_u16)ci.timebuf[i];
359 }
360 #endif
361 #if 0
362 write_log (_T("caps: drive:%d track:%d len:%d multi:%d timing:%d type:%d overlap:%d\n"),
363 drv, track, len, *multirev, ci.timelen, type, ci.overlap);
364 #endif
365 return 1;
366 }
367
368 #endif /* CAPS */
369