1 /*
2  * PUAE Catweasel support
3  *
4  * Copyright
5  * Copyright 2011 Mustafa TUFAN
6  *
7  * some parts inspired or taken from cwfloppy
8  * Copyright (C) 1998-2009 Michael Krause
9  *
10  */
11 
12 #include <stdio.h>
13 
14 #include "sysconfig.h"
15 #include "sysdeps.h"
16 
17 #ifdef CATWEASEL
18 
19 #include "options.h"
20 #include "memory_uae.h"
21 #include "ioport.h"
22 #include "catweasel.h"
23 #include "uae.h"
24 #include "zfile.h"
25 
26 #define DRIVER
27 #include <catweasl_usr.h>
28 
29 struct catweasel_contr cwc;
30 
31 static int cwhsync, cwmk3buttonsync;
32 static int cwmk3port, cwmk3port1, cwmk3port2;
33 static int handshake;
34 static int mouse_x[2], mouse_y[2], mouse_px[2], mouse_py[2];
35 
36 static HANDLE handle = INVALID_HANDLE_VALUE;
37 
catweasel_isjoystick(void)38 int catweasel_isjoystick (void)
39 {
40 	uae_u8 b = cwc.can_joy;
41 	if (!cwc.direct_access)
42 		return 0;
43 	if (b) {
44 		if (cwc.type == CATWEASEL_TYPE_MK3 && cwc.sid[0])
45 			b |= 0x80;
46 		if (cwc.type >= CATWEASEL_TYPE_MK4)
47 			b |= 0x80;
48 	}
49 	return b;
50 }
catweasel_ismouse(void)51 int catweasel_ismouse (void)
52 {
53 	if (!cwc.direct_access)
54 		return 0;
55 	return cwc.can_mouse;
56 }
57 
58 static int hsync_requested;
hsync_request(void)59 static void hsync_request (void)
60 {
61 	hsync_requested = 10;
62 };
63 
sid_write(uae_u8 reg,uae_u8 val,int sidnum)64 static void sid_write (uae_u8 reg, uae_u8 val, int sidnum)
65 {
66 	if (sidnum >= cwc.can_sid)
67 		return;
68 	catweasel_do_bput(0xd8, val);
69 	catweasel_do_bput(0xdc, reg | (sidnum << 7));
70 	catweasel_do_bget(0xd8); // dummy read
71 	catweasel_do_bget(0xd8); // dummy read
72 }
73 
sid_read(uae_u8 reg,int sidnum)74 static uae_u8 sid_read (uae_u8 reg, int sidnum)
75 {
76 	if (sidnum >= cwc.can_sid)
77 		return 0;
78 	catweasel_do_bput(0xdc, 0x20 | reg | (sidnum << 7));
79 	catweasel_do_bget(0xd8); // dummy read
80 	catweasel_do_bget(0xd8); // dummy read
81 	return catweasel_do_bget(0xd8);
82 }
83 
get_buttons(void)84 static uae_u8 get_buttons (void)
85 {
86 	uae_u8 b, b2;
87 
88 	b = 0;
89 	if (cwc.type < CATWEASEL_TYPE_MK3 || !cwc.direct_access)
90 		return b;
91 	hsync_request();
92 	b2 = catweasel_do_bget(0xc8) & (0x80 | 0x40);
93 	if (!(b2 & 0x80))
94 		b |= 0x80;
95 	if (!(b2 & 0x40))
96 		b |= 0x08;
97 	if (cwc.type >= CATWEASEL_TYPE_MK4) {
98 		b &= ~0x80;
99 		catweasel_do_bput(3, 0x81);
100 		if (!(catweasel_do_bget(0x07) & 0x10))
101 			b |= 0x80;
102 		b2 = catweasel_do_bget(0xd0) ^ 15;
103 		catweasel_do_bput(3, 0x41);
104 		if (cwc.sid[0]) {
105 			b2 &= ~(1 | 2);
106 			if (sid_read(0x19, 0) > 0x7f)
107 				b2 |= 2;
108 			if (sid_read(0x1a, 0) > 0x7f)
109 				b2 |= 1;
110 		}
111 		if (cwc.sid[1]) {
112 			b2 &= ~(4 | 8);
113 			if (sid_read(0x19, 1) > 0x7f)
114 				b2 |= 8;
115 			if (sid_read(0x1a, 1) > 0x7f)
116 				b2 |= 4;
117 		}
118 	} else {
119 		b2 = cwmk3port1 | (cwmk3port2 << 2);
120 	}
121 	b |= (b2 & (8 | 4)) << 3;
122 	b |= (b2 & (1 | 2)) << 1;
123 	return b;
124 }
125 
catweasel_read_mouse(int port,int * dx,int * dy,int * buttons)126 int catweasel_read_mouse (int port, int *dx, int *dy, int *buttons)
127 {
128 	if (!cwc.can_mouse || !cwc.direct_access)
129 		return 0;
130 	hsync_request();
131 	*dx = mouse_x[port];
132 	mouse_x[port] = 0;
133 	*dy = mouse_y[port];
134 	mouse_y[port] = 0;
135 	*buttons = (get_buttons() >> (port * 4)) & 15;
136 	return 1;
137 }
138 
sid_reset(void)139 static void sid_reset (void)
140 {
141 	int i;
142 	for (i = 0; i < 0x19; i++) {
143 		sid_write(i, 0, 0);
144 		sid_write(i, 0, 1);
145 	}
146 }
147 
catweasel_detect_sid(void)148 static void catweasel_detect_sid (void)
149 {
150 	int i, j;
151 	uae_u8 b1, b2;
152 
153 	cwc.sid[0] = cwc.sid[1] = 0;
154 	if (!cwc.can_sid || !cwc.direct_access)
155 		return;
156 	sid_reset();
157 	if (cwc.type >= CATWEASEL_TYPE_MK4) {
158 		catweasel_do_bput(3, 0x81);
159 		b1 = catweasel_do_bget(0xd0);
160 		for (i = 0; i < 100; i++) {
161 			sid_read(0x19, 0); // delay
162 			b2 = catweasel_do_bget(0xd0);
163 			if ((b1 & 3) != (b2 & 3))
164 				cwc.sid[0] = 6581;
165 			if ((b1 & 12) != (b2 & 12))
166 				cwc.sid[1] = 6581;
167 		}
168 	}
169 	catweasel_do_bput(3, 0x41);
170 	for (i = 0; i < 2 ;i++) {
171 		sid_reset();
172 		sid_write(0x0f, 0xff, i);
173 		sid_write(0x12, 0x10, i);
174 		for(j = 0; j != 1000; j++) {
175 			sid_write(0, 0, i);
176 			if((sid_read(0x1b, i) & 0x80) != 0) {
177 				cwc.sid[i] = 6581;
178 				break;
179 			}
180 		}
181 		sid_reset();
182 		sid_write(0x0f, 0xff, i);
183 		sid_write(0x12, 0x30, i);
184 		for(j = 0; j != 1000; j++) {
185 			sid_write(0, 0, i);
186 			if((sid_read(0x1b, i) & 0x80) != 0) {
187 				cwc.sid[i] = 8580;
188 				break;
189 			}
190 		}
191 	}
192 	sid_reset();
193 }
194 
catweasel_hsync(void)195 void catweasel_hsync (void)
196 {
197 	int i;
198 
199 	if (cwc.type < CATWEASEL_TYPE_MK3 || !cwc.direct_access)
200 		return;
201 	cwhsync--;
202 	if (cwhsync > 0)
203 		return;
204 	cwhsync = 10;
205 	if (handshake) {
206 		/* keyboard handshake */
207 		catweasel_do_bput (0xd0, 0);
208 		handshake = 0;
209 	}
210 	if (hsync_requested < 0)
211 		return;
212 	hsync_requested--;
213 	if (cwc.type == CATWEASEL_TYPE_MK3 && cwc.sid[0]) {
214 		uae_u8 b;
215 		cwmk3buttonsync--;
216 		if (cwmk3buttonsync <= 0) {
217 			cwmk3buttonsync = 30;
218 			b = 0;
219 			if (sid_read (0x19, 0) > 0x7f)
220 				b |= 2;
221 			if (sid_read (0x1a, 0) > 0x7f)
222 				b |= 1;
223 			if (cwmk3port == 0) {
224 				cwmk3port1 = b;
225 				catweasel_do_bput (0xd4, 0); // select port2
226 				cwmk3port = 1;
227 			} else {
228 				cwmk3port2 = b;
229 				catweasel_do_bget (0xd4); // select port1
230 				cwmk3port = 0;
231 			}
232 		}
233 	}
234 	if (!cwc.can_mouse)
235 		return;
236 	/* read MK4 mouse counters */
237 	catweasel_do_bput (3, 0x81);
238 	for (i = 0; i < 2; i++) {
239 		int x, y, dx, dy;
240 		x = (uae_s8)catweasel_do_bget (0xc4 + i * 8);
241 		y = (uae_s8)catweasel_do_bget (0xc0 + i * 8);
242 		dx = mouse_px[i] - x;
243 		if (dx > 127)
244 			dx = 255 - dx;
245 		if (dx < -128)
246 			dx = 255 + dx;
247 		dy = mouse_py[i] - y;
248 		if (dy > 127)
249 			dy = 255 - dy;
250 		if (dy < -128)
251 			dy = 255 + dy;
252 		mouse_x[i] -= dx;
253 		mouse_y[i] -= dy;
254 		mouse_px[i] = x;
255 		mouse_py[i] = y;
256 	}
257 	catweasel_do_bput (3, 0x41);
258 }
259 
catweasel_read_joystick(uae_u8 * dir,uae_u8 * buttons)260 int catweasel_read_joystick (uae_u8 *dir, uae_u8 *buttons)
261 {
262 	if (!cwc.can_joy || !cwc.direct_access)
263 		return 0;
264 	hsync_request ();
265 	*dir = catweasel_do_bget (0xc0);
266 	*buttons = get_buttons ();
267 	return 1;
268 }
269 
catweasel_read_keyboard(uae_u8 * keycode)270 int catweasel_read_keyboard (uae_u8 *keycode)
271 {
272 	uae_u8 v;
273 
274 	if (!cwc.can_kb || !cwc.direct_access)
275 		return 0;
276 	if (!currprefs.catweasel)
277 		return 0;
278 	v = catweasel_do_bget (0xd4);
279 	if (!(v & 0x80))
280 		return 0;
281 	if (handshake)
282 		return 0;
283 	*keycode = catweasel_do_bget (0xd0);
284 	catweasel_do_bput (0xd0, 0);
285 	handshake = 1;
286 	return 1;
287 }
288 
catweasel_do_bget(uaecptr addr)289 uae_u32	catweasel_do_bget (uaecptr addr)
290 {
291 	DWORD did_read = 0;
292 	uae_u8 buf1[1], buf2[1];
293 
294 	if (addr >= 0x100)
295 		return 0;
296 	buf1[0] = (uae_u8)addr;
297 #if 0
298 	if (handle != INVALID_HANDLE_VALUE) {
299 		if (!DeviceIoControl (handle, CW_PEEKREG_FULL, buf1, 1, buf2, 1, &did_read, 0))
300 			write_log (_T("catweasel_do_bget %02x fail err=%d\n"), buf1[0], GetLastError ());
301 	} else {
302 #endif
303 		buf2[0] = ioport_read (cwc.iobase + addr);
304 #if 0
305 	}
306 	//write_log (_T("G %02X %02X %d\n"), buf1[0], buf2[0], did_read);
307 #endif
308 	return buf2[0];
309 }
310 
catweasel_do_bput(uaecptr addr,uae_u32 b)311 void catweasel_do_bput (uaecptr	addr, uae_u32 b)
312 {
313 	if (addr >= 0x100)
314 		return;
315 
316 	uae_u8 buf[2];
317 	DWORD did_read = 0;
318 
319 	buf[0] = (uae_u8)addr;
320 	buf[1] = b;
321 #if 0
322 	if (handle != INVALID_HANDLE_VALUE) {
323 		if (!DeviceIoControl (handle, CW_POKEREG_FULL, buf, 2, 0, 0, &did_read, 0))
324 			write_log (_T("catweasel_do_bput %02x=%02x fail err=%d\n"), buf[0], buf[1], GetLastError ());
325 	} else {
326 #endif
327 		ioport_write (cwc.iobase + addr, b);
328 	}
329 	//write_log (_T("P %02X %02X %d\n"), (uae_u8)addr, (uae_u8)b, did_read);
330 }
331 
332 #include "core.cw4.cpp"
333 
cw_config_done(void)334 static int cw_config_done (void)
335 {
336 	return ioport_read (cwc.iobase + 7) & 4;
337 }
cw_fpga_ready(void)338 static int cw_fpga_ready (void)
339 {
340 	return ioport_read (cwc.iobase + 7) & 8;
341 }
cw_resetFPGA(void)342 static void cw_resetFPGA (void)
343 {
344 	ioport_write (cwc.iobase + 2, 227);
345 	ioport_write (cwc.iobase + 3, 0);
346 	sleep_millis (10);
347 	ioport_write (cwc.iobase + 3, 65);
348 }
349 
catweasel3_configure(void)350 static int catweasel3_configure (void)
351 {
352 	ioport_write (cwc.iobase, 241);
353 	ioport_write (cwc.iobase + 1, 0);
354 	ioport_write (cwc.iobase + 2, 0);
355 	ioport_write (cwc.iobase + 4, 0);
356 	ioport_write (cwc.iobase + 5, 0);
357 	ioport_write (cwc.iobase + 0x29, 0);
358 	ioport_write (cwc.iobase + 0x2b, 0);
359 	return 1;
360 }
361 
catweasel4_configure(void)362 static int catweasel4_configure (void)
363 {
364 	struct zfile *f;
365 	time_t t;
366 
367 	ioport_write (cwc.iobase, 241);
368 	ioport_write (cwc.iobase + 1, 0);
369 	ioport_write (cwc.iobase + 2, 227);
370 	ioport_write (cwc.iobase + 3, 65);
371 	ioport_write (cwc.iobase + 4, 0);
372 	ioport_write (cwc.iobase + 5, 0);
373 	ioport_write (cwc.iobase + 0x29, 0);
374 	ioport_write (cwc.iobase + 0x2b, 0);
375 	sleep_millis(10);
376 
377 	if (cw_config_done()) {
378 		write_log (_T("CW: FPGA already configured, skipping core upload\n"));
379 		return 1;
380 	}
381 	cw_resetFPGA();
382 	sleep_millis(10);
383 	if (cw_config_done()) {
384 		write_log (_T("CW: FPGA failed to reset!\n"));
385 		return 0;
386 	}
387 	f = zfile_fopen(_T("core.cw4"), _T("rb"), ZFD_NORMAL);
388 	if (!f) {
389 		f = zfile_fopen_data (_T("core.cw4.gz"), core_len, core);
390 		f = zfile_gunzip (f, NULL);
391 	}
392 	write_log (_T("CW: starting core upload, this will take few seconds\n"));
393 	t = time(NULL) + 10; // give up if upload takes more than 10s
394 	for (;;) {
395 		uae_u8 b;
396 		if (zfile_fread (&b, 1, 1, f) != 1)
397 			break;
398 		ioport_write (cwc.iobase + 3, (b & 1) ? 67 : 65);
399 		while (!cw_fpga_ready()) {
400 			if (time(NULL) >= t) {
401 				write_log (_T("CW: FPGA core upload got stuck!?\n"));
402 				cw_resetFPGA();
403 				return 0;
404 			}
405 		}
406 		ioport_write (cwc.iobase + 192, b);
407 	}
408 	if (!cw_config_done()) {
409 		write_log (_T("CW: FPGA didn't accept the core!\n"));
410 		cw_resetFPGA();
411 		return 0;
412 	}
413 	sleep_millis(10);
414 	write_log (_T("CW: core uploaded successfully\n"));
415 	return 1;
416 }
417 
418 static int detected;
419 
catweasel_free(void)420 void catweasel_free (void)
421 {
422 }
423 
catweasel_init(void)424 int catweasel_init(void)
425 {
426 fail:
427 	catweasel_free ();
428 	return 0;
429 }
430 
catweasel_detect(void)431 int catweasel_detect (void)
432 {
433 //	static struct cw_controller_struct controllers[2];
434 	int err;
435 
436 	err = pci_register_driver (&cwfloppy_pci_mk3);
437 	if (err && err != -ENODEV)
438 		return err;
439 	err = pci_register_driver (&cwfloppy_pci_mk4);
440 	if (err && err != -ENODEV)
441 		return err;
442 //	if (controllers[0].c.type == CATWEASEL_TYPE_NONE) {
443 //		write_log("No PCI Catweasels found.\n");
444 //	}
445 
446 	pci_unregister_driver(&cwfloppy_pci_mk4);
447 	pci_unregister_driver(&cwfloppy_pci_mk3);
448 
449 	if (detected)
450 		return detected < 0 ? 0 : 1;
451 }
452 
cwfloppy_probe_mk3(struct pci_dev * pcidev,const struct pci_device_id * pciid)453 static int cwfloppy_probe_mk3(struct pci_dev *pcidev, const struct pci_device_id *pciid)
454 {
455 	return 0;
456 }
457 
cwfloppy_probe_mk4(struct pci_dev * pcidev,const struct pci_device_id * pciid)458 static int cwfloppy_probe_mk4(struct pci_dev *pcidev, const struct pci_device_id *pciid)
459 {
460 	return 0;
461 }
462 
463 #define CATWEASEL_TYPE_NONE  -1
464 #define CATWEASEL_TYPE_MK1    1
465 #define CATWEASEL_TYPE_MK3    3
466 #define CATWEASEL_TYPE_MK4    4
467 
468 /* pci ids */
469 #define CW_MK4_VENDOR           0xe159
470 #define CW_MK4_DEVICE           0x0001
471 
472 static struct pci_device_id id_table_mk3[] = {
473 	{ CW_MK4_VENDOR, CW_MK4_DEVICE, 0x1212, 0x0002, },
474 	{ 0, }
475 };
476 MODULE_DEVICE_TABLE(pci, id_table_mk3);
477 static struct pci_driver cwfloppy_pci_mk3 = {
478 	name: "cwfloppy_mk3",
479 	id_table: id_table_mk3,
480 	probe: cwfloppy_probe_mk3
481 };
482 
483 static struct pci_device_id id_table_mk4[] = {
484 	/* The MK4 PCI bridge has a bug where the reported subvendor and
485 	 * subdevice IDs may randomly change between various values. */
486 	{ CW_MK4_VENDOR, CW_MK4_DEVICE, 0x5213, 0x0002, },
487 	{ CW_MK4_VENDOR, CW_MK4_DEVICE, 0x5213, 0x0003, },
488 	{ CW_MK4_VENDOR, CW_MK4_DEVICE, 0x5200, 0x0002, },
489 	{ CW_MK4_VENDOR, CW_MK4_DEVICE, 0x5200, 0x0003, },
490 	{ 0, }
491 };
492 MODULE_DEVICE_TABLE(pci, id_table_mk4);
493 static struct pci_driver cwfloppy_pci_mk4 = {
494 	.name = "cwfloppy_mk4",
495 	.id_table = id_table_mk4,
496 	.probe = cwfloppy_probe_mk4,
497 };
498 
499 #endif
500