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