1 /*
2  * (C) Gražvydas "notaz" Ignotas, 2009-2012
3  *
4  * This work is licensed under the terms of the GNU GPLv2 or later.
5  * See the COPYING file in the top-level directory.
6  *
7  * GPH claims:
8  *  Main Memory  : Wiz = 0       ~ 2A00000,      Caanoo = 0       ~ 5600000 (86M)
9  *  Frame Buffer : Wiz = 2A00000 ~ 2E00000 (4M), Caanoo = 5600000 ~ 5700000 (1M)
10  *  Sound Buffer : Wiz = 2E00000 ~ 3000000 (2M), Caanoo = 5700000 ~ 5800000 (1M)
11  *  YUV Buffer   :                               Caanoo = 5800000 ~ 6000000 (8M)
12  *  3D Buffer    : Wiz = 3000000 ~ 4000000 (16M),Caanoo = 6000000 ~ 8000000 (32M)
13  *
14  * Caanoo dram column (or row?) is 1024 bytes?
15  *
16  * pollux display array:
17  * 27:24 |  23:18  |  17:11  |  10:6  |  5:0
18  *  seg  | y[11:5] | x[11:6] | y[4:0] | x[5:0]
19  *       |  blk_index[12:0]  |   block[10:0]
20  */
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <sys/ioctl.h>
29 #include <unistd.h>
30 #include <linux/fb.h>
31 #include <sys/mman.h>
32 #include <linux/soundcard.h>
33 #include <linux/input.h>
34 
35 #include "libpicofe/plat.h"
36 #include "libpicofe/input.h"
37 #include "libpicofe/gp2x/in_gp2x.h"
38 #include "libpicofe/gp2x/soc_pollux.h"
39 #include "libpicofe/linux/in_evdev.h"
40 #include "libpicofe/menu.h"
41 #include "warm/warm.h"
42 #include "plugin_lib.h"
43 #include "pl_gun_ts.h"
44 #include "blit320.h"
45 #include "in_tsbutton.h"
46 #include "main.h"
47 #include "menu.h"
48 #include "plat.h"
49 #include "cspace.h"
50 #include "../libpcsxcore/psxmem_map.h"
51 
52 
53 static int fbdev = -1;
54 static void *fb_vaddrs[2];
55 static unsigned int fb_paddrs[2];
56 static int fb_work_buf;
57 static int have_warm;
58 #define FB_VRAM_SIZE (320*240*2*2*2) // 2 buffers with space for 24bpp mode
59 static unsigned int uppermem_pbase, vram_pbase;
60 
61 static unsigned short *psx_vram;
62 static int psx_step, psx_width, psx_height, psx_bpp;
63 static int psx_offset_x, psx_offset_y, psx_src_width, psx_src_height;
64 static int fb_offset_x, fb_offset_y;
65 
66 static void caanoo_init(void);
67 static void wiz_init(void);
68 
69 
70 static const struct in_default_bind in_evdev_defbinds[] = {
71 	{ KEY_UP,	IN_BINDTYPE_PLAYER12, DKEY_UP },
72 	{ KEY_DOWN,	IN_BINDTYPE_PLAYER12, DKEY_DOWN },
73 	{ KEY_LEFT,	IN_BINDTYPE_PLAYER12, DKEY_LEFT },
74 	{ KEY_RIGHT,	IN_BINDTYPE_PLAYER12, DKEY_RIGHT },
75 	{ BTN_TOP,	IN_BINDTYPE_PLAYER12, DKEY_TRIANGLE },
76 	{ BTN_THUMB,	IN_BINDTYPE_PLAYER12, DKEY_CROSS },
77 	{ BTN_THUMB2,	IN_BINDTYPE_PLAYER12, DKEY_CIRCLE },
78 	{ BTN_TRIGGER,	IN_BINDTYPE_PLAYER12, DKEY_SQUARE },
79 	{ BTN_BASE3,	IN_BINDTYPE_PLAYER12, DKEY_START },
80 	{ BTN_BASE4,	IN_BINDTYPE_PLAYER12, DKEY_SELECT },
81 	{ BTN_TOP2,	IN_BINDTYPE_PLAYER12, DKEY_L1 },
82 	{ BTN_PINKIE,	IN_BINDTYPE_PLAYER12, DKEY_R1 },
83 	{ BTN_BASE,	IN_BINDTYPE_EMU, SACTION_ENTER_MENU },
84 	{ 0, 0, 0 },
85 };
86 
87 static const struct menu_keymap key_pbtn_map[] =
88 {
89 	{ KEY_UP,	PBTN_UP },
90 	{ KEY_DOWN,	PBTN_DOWN },
91 	{ KEY_LEFT,	PBTN_LEFT },
92 	{ KEY_RIGHT,	PBTN_RIGHT },
93 	/* Caanoo */
94 	{ BTN_THUMB2,	PBTN_MOK },
95 	{ BTN_THUMB,	PBTN_MBACK },
96 	{ BTN_TRIGGER,	PBTN_MA2 },
97 	{ BTN_TOP,	PBTN_MA3 },
98 	{ BTN_BASE,	PBTN_MENU },
99 	{ BTN_TOP2,	PBTN_L },
100 	{ BTN_PINKIE,	PBTN_R },
101 	/* "normal" keyboards */
102 	{ KEY_ENTER,	PBTN_MOK },
103 	{ KEY_ESC,	PBTN_MBACK },
104 	{ KEY_SEMICOLON,  PBTN_MA2 },
105 	{ KEY_APOSTROPHE, PBTN_MA3 },
106 	{ KEY_BACKSLASH,  PBTN_MENU },
107 	{ KEY_LEFTBRACE,  PBTN_L },
108 	{ KEY_RIGHTBRACE, PBTN_R },
109 };
110 
111 static const struct in_pdata gp2x_evdev_pdata = {
112 	.defbinds = in_evdev_defbinds,
113 	.key_map = key_pbtn_map,
114 	.kmap_size = sizeof(key_pbtn_map) / sizeof(key_pbtn_map[0]),
115 };
116 
fb_flip(void)117 static void *fb_flip(void)
118 {
119 	memregl[0x406C>>2] = memregl[0x446C>>2] = fb_paddrs[fb_work_buf];
120 	memregl[0x4058>>2] |= 0x10;
121 	memregl[0x4458>>2] |= 0x10;
122 	fb_work_buf ^= 1;
123 	return fb_vaddrs[fb_work_buf];
124 }
125 
pollux_changemode(int bpp,int is_bgr)126 static void pollux_changemode(int bpp, int is_bgr)
127 {
128 	int code = 0, bytes = 2;
129 	unsigned int r;
130 
131 	printf("changemode: %dbpp %s\n", bpp, is_bgr ? "bgr" : "rgb");
132 
133 	memregl[0x4004>>2] = 0x00ef013f;
134 	memregl[0x4000>>2] |= 1 << 3;
135 
136 	switch (bpp)
137 	{
138 		case 8:
139 			code = 0x443a;
140 			bytes = 1;
141 			break;
142 		case 16:
143 			code = is_bgr ? 0xc342 : 0x4432;
144 			bytes = 2;
145 			break;
146 		case 24:
147 			code = is_bgr ? 0xc653 : 0x4653;
148 			bytes = 3;
149 			break;
150 		default:
151 			printf("unhandled bpp request: %d\n", bpp);
152 			return;
153 	}
154 
155 	// program both MLCs so that TV-out works
156 	memregl[0x405c>>2] = memregl[0x445c>>2] = bytes;
157 	memregl[0x4060>>2] = memregl[0x4460>>2] = 320 * bytes;
158 
159 	r = memregl[0x4058>>2];
160 	r = (r & 0xffff) | (code << 16) | 0x10;
161 	memregl[0x4058>>2] = r;
162 
163 	r = memregl[0x4458>>2];
164 	r = (r & 0xffff) | (code << 16) | 0x10;
165 	memregl[0x4458>>2] = r;
166 }
167 
cpu_clock_wrapper(int mhz)168 static int cpu_clock_wrapper(int mhz)
169 {
170 	// stupid pll share hack - must restart audio
171 	int pollux_cpu_clock_set(int cpu_clock);
172 	extern long SPUopen(void);
173 	extern long SPUclose(void);
174 
175 	pollux_cpu_clock_set(mhz);
176 	SPUclose();
177 	SPUopen();
178 
179 	return 0;
180 }
181 
182 #define TIMER_BASE3 0x1980
183 #define TIMER_REG(x) memregl[(TIMER_BASE3 + x) >> 2]
184 
timer_get(void)185 static __attribute__((unused)) unsigned int timer_get(void)
186 {
187 	TIMER_REG(0x08) |= 0x48;  /* run timer, latch value */
188 	return TIMER_REG(0);
189 }
190 
plat_video_menu_enter(int is_rom_loaded)191 void plat_video_menu_enter(int is_rom_loaded)
192 {
193 	if (pl_vout_buf != NULL) {
194 		if (psx_bpp == 16)
195 			// have to do rgb conversion for menu bg
196 			bgr555_to_rgb565(pl_vout_buf, pl_vout_buf, 320*240*2);
197 		else
198 			memset(pl_vout_buf, 0, 320*240*2);
199 	}
200 
201 	pollux_changemode(16, 0);
202 }
203 
plat_video_menu_begin(void)204 void plat_video_menu_begin(void)
205 {
206 }
207 
plat_video_menu_end(void)208 void plat_video_menu_end(void)
209 {
210 	g_menuscreen_ptr = fb_flip();
211 }
212 
plat_video_menu_leave(void)213 void plat_video_menu_leave(void)
214 {
215 	if (psx_vram == NULL) {
216 		fprintf(stderr, "GPU plugin did not provide vram\n");
217 		exit(1);
218 	}
219 
220 	if (gp2x_dev_id == GP2X_DEV_CAANOO)
221 		in_set_config_int(in_name_to_id("evdev:pollux-analog"),
222 			IN_CFG_ABS_DEAD_ZONE, analog_deadzone);
223 
224 	memset(g_menuscreen_ptr, 0, 320*240 * psx_bpp/8);
225 	g_menuscreen_ptr = fb_flip();
226 	memset(g_menuscreen_ptr, 0, 320*240 * psx_bpp/8);
227 }
228 
plat_prepare_screenshot(int * w,int * h,int * bpp)229 void *plat_prepare_screenshot(int *w, int *h, int *bpp)
230 {
231 	bgr555_to_rgb565(pl_vout_buf, pl_vout_buf, 320*240*2);
232 	*w = 320;
233 	*h = 240;
234 	*bpp = psx_bpp;
235 	return pl_vout_buf;
236 }
237 
plat_minimize(void)238 void plat_minimize(void)
239 {
240 }
241 
spend_cycles(int loops)242 static void spend_cycles(int loops)
243 {
244 	asm volatile (
245 		"   mov  r0,%0    ;\n"
246 		"0: subs r0,r0,#1 ;\n"
247 		"   bgt  0b"
248 		:: "r" (loops) : "cc", "r0");
249 }
250 
251 #define DMA_BASE6 0x0300
252 #define DMA_REG(x) memregl[(DMA_BASE6 + x) >> 2]
253 
254 /* this takes ~1.5ms, while ldm/stm ~1.95ms */
raw_blit_dma(int doffs,const void * vram,int w,int h,int sstride,int bgr24)255 static void raw_blit_dma(int doffs, const void *vram, int w, int h,
256 			 int sstride, int bgr24)
257 {
258 	unsigned int pixel_offset = (unsigned short *)vram - psx_vram;
259 	unsigned int dst = fb_paddrs[fb_work_buf] +
260 			(fb_offset_y * 320 + fb_offset_x) * psx_bpp / 8;
261 	int spsx_line = pixel_offset / 1024 + psx_offset_y;
262 	int spsx_offset = (pixel_offset + psx_offset_x) & 0x3f8;
263 	unsigned int vram_byte_pos, vram_byte_step;
264 	int dst_stride = 320 * psx_bpp / 8;
265 	int len = psx_src_width * psx_bpp / 8;
266 	int i;
267 
268 	//warm_cache_op_all(WOP_D_CLEAN);
269 
270 	dst &= ~7;
271 	len &= ~7;
272 
273 	if (DMA_REG(0x0c) & 0x90000) {
274 		printf("already runnig DMA?\n");
275 		DMA_REG(0x0c) = 0x100000;
276 	}
277 	if ((DMA_REG(0x2c) & 0x0f) < 5) {
278 		printf("DMA queue busy?\n");
279 		DMA_REG(0x24) = 1;
280 	}
281 
282 	vram_byte_pos = vram_pbase;
283 	vram_byte_pos += (spsx_line & 511) * 2 * 1024 + spsx_offset * 2;
284 	vram_byte_step = psx_step * 2 * 1024;
285 
286 	for (i = psx_src_height; i > 0;
287 	     i--, vram_byte_pos += vram_byte_step, dst += dst_stride)
288 	{
289 		while ((DMA_REG(0x2c) & 0x0f) < 4)
290 			spend_cycles(10);
291 
292 		// XXX: it seems we must always set all regs, what is autoincrement there for?
293 		DMA_REG(0x20) = 1;		// queue wait cmd
294 		DMA_REG(0x10) = vram_byte_pos;	// DMA src
295 		DMA_REG(0x14) = dst;		// DMA dst
296 		DMA_REG(0x18) = len - 1;	// len
297 		DMA_REG(0x1c) = 0x80000;	// go
298 	}
299 }
300 
301 #define make_flip_func(name, blitfunc)                                                  \
302 static void name(int doffs, const void *vram_, int w, int h, int sstride, int bgr24)    \
303 {                                                                                       \
304         const unsigned short *vram = vram_;                                             \
305         unsigned char *dst = (unsigned char *)g_menuscreen_ptr +                        \
306                         (fb_offset_y * 320 + fb_offset_x) * psx_bpp / 8;                \
307         int dst_stride = 320 * psx_bpp / 8;                                             \
308         int len = psx_src_width * psx_bpp / 8;                                          \
309         int i;                                                                          \
310                                                                                         \
311         vram += psx_offset_y * 1024 + psx_offset_x;                                     \
312         for (i = psx_src_height; i > 0; i--, vram += psx_step * 1024, dst += dst_stride)\
313                 blitfunc(dst, vram, len);                                               \
314 }
315 
make_flip_func(raw_blit_soft,memcpy)316 make_flip_func(raw_blit_soft, memcpy)
317 make_flip_func(raw_blit_soft_368, blit320_368)
318 make_flip_func(raw_blit_soft_512, blit320_512)
319 make_flip_func(raw_blit_soft_640, blit320_640)
320 
321 void *plat_gvideo_set_mode(int *w_, int *h_, int *bpp_)
322 {
323 	int poff_w, poff_h, w_max;
324 	int w = *w_, h = *h_, bpp = *bpp_;
325 
326 	if (!w || !h || !bpp)
327 		return NULL;
328 
329 	printf("psx mode: %dx%d@%d\n", w, h, bpp);
330 	psx_width = w;
331 	psx_height = h;
332 	psx_bpp = bpp;
333 
334 	switch (w + (bpp != 16) + !soft_scaling) {
335 	case 640:
336 		pl_plat_blit = raw_blit_soft_640;
337 		w_max = 640;
338 		break;
339 	case 512:
340 		pl_plat_blit = raw_blit_soft_512;
341 		w_max = 512;
342 		break;
343 	case 384:
344 	case 368:
345 		pl_plat_blit = raw_blit_soft_368;
346 		w_max = 368;
347 		break;
348 	default:
349 		pl_plat_blit = have_warm ? raw_blit_dma : raw_blit_soft;
350 		w_max = 320;
351 		break;
352 	}
353 
354 	psx_step = 1;
355 	if (h > 256) {
356 		psx_step = 2;
357 		h /= 2;
358 	}
359 
360 	poff_w = poff_h = 0;
361 	if (w > w_max) {
362 		poff_w = w / 2 - w_max / 2;
363 		w = w_max;
364 	}
365 	fb_offset_x = 0;
366 	if (w < 320)
367 		fb_offset_x = 320/2 - w / 2;
368 	if (h > 240) {
369 		poff_h = h / 2 - 240/2;
370 		h = 240;
371 	}
372 	fb_offset_y = 240/2 - h / 2;
373 
374 	psx_offset_x = poff_w * psx_bpp/8 / 2;
375 	psx_offset_y = poff_h;
376 	psx_src_width = w;
377 	psx_src_height = h;
378 
379 	if (fb_offset_x || fb_offset_y) {
380 		// not fullscreen, must clear borders
381 		memset(g_menuscreen_ptr, 0, 320*240 * psx_bpp/8);
382 		g_menuscreen_ptr = fb_flip();
383 		memset(g_menuscreen_ptr, 0, 320*240 * psx_bpp/8);
384 	}
385 
386 	pollux_changemode(bpp, 1);
387 
388 	pl_set_gun_rect(fb_offset_x, fb_offset_y, w > 320 ? 320 : w, h);
389 
390 	// adjust for hud
391 	*w_ = 320;
392 	*h_ = fb_offset_y + psx_src_height;
393 
394 	return g_menuscreen_ptr;
395 }
396 
397 /* not really used, we do raw_flip */
plat_gvideo_open(int is_pal)398 void plat_gvideo_open(int is_pal)
399 {
400 }
401 
plat_gvideo_flip(void)402 void *plat_gvideo_flip(void)
403 {
404 	g_menuscreen_ptr = fb_flip();
405 	return g_menuscreen_ptr;
406 }
407 
plat_gvideo_close(void)408 void plat_gvideo_close(void)
409 {
410 }
411 
pl_emu_mmap(unsigned long addr,size_t size,int is_fixed,enum psxMapTag tag)412 static void *pl_emu_mmap(unsigned long addr, size_t size, int is_fixed,
413 	enum psxMapTag tag)
414 {
415 	unsigned int pbase;
416 	void *retval;
417 	int ret;
418 
419 	if (!have_warm)
420 		goto basic_map;
421 
422 	switch (tag) {
423 	case MAP_TAG_RAM:
424 		if (size > 0x400000) {
425 			fprintf(stderr, "unexpected ram map request: %08lx %x\n",
426 				addr, size);
427 			exit(1);
428 		}
429 		pbase = (uppermem_pbase + 0xffffff) & ~0xffffff;
430 		pbase += 0x400000;
431 		retval = (void *)addr;
432 		ret = warm_mmap_section(retval, pbase, size, WCB_C_BIT);
433 		if (ret != 0) {
434 			fprintf(stderr, "ram section map failed\n");
435 			exit(1);
436 		}
437 		goto out;
438 	case MAP_TAG_VRAM:
439 		if (size > 0x400000) {
440 			fprintf(stderr, "unexpected vram map request: %08lx %x\n",
441 				addr, size);
442 			exit(1);
443 		}
444 		if (addr == 0)
445 			addr = 0x60000000;
446 		vram_pbase = (uppermem_pbase + 0xffffff) & ~0xffffff;
447 		retval = (void *)addr;
448 
449 		ret = warm_mmap_section(retval, vram_pbase, size, WCB_C_BIT);
450 		if (ret != 0) {
451 			fprintf(stderr, "vram section map failed\n");
452 			exit(1);
453 		}
454 		goto out;
455 	case MAP_TAG_LUTS:
456 		// mostly for Wiz to not run out of RAM
457 		if (size > 0x800000) {
458 			fprintf(stderr, "unexpected LUT map request: %08lx %x\n",
459 				addr, size);
460 			exit(1);
461 		}
462 		pbase = (uppermem_pbase + 0xffffff) & ~0xffffff;
463 		pbase += 0x800000;
464 		retval = (void *)addr;
465 		ret = warm_mmap_section(retval, pbase, size, WCB_C_BIT);
466 		if (ret != 0) {
467 			fprintf(stderr, "LUT section map failed\n");
468 			exit(1);
469 		}
470 		goto out;
471 	default:
472 		break;
473 	}
474 
475 basic_map:
476 	retval = plat_mmap(addr, size, 0, is_fixed);
477 
478 out:
479 	if (tag == MAP_TAG_VRAM)
480 		psx_vram = retval;
481 	return retval;
482 }
483 
pl_emu_munmap(void * ptr,size_t size,enum psxMapTag tag)484 static void pl_emu_munmap(void *ptr, size_t size, enum psxMapTag tag)
485 {
486 	switch (tag) {
487 	case MAP_TAG_RAM:
488 	case MAP_TAG_VRAM:
489 	case MAP_TAG_LUTS:
490 		warm_munmap_section(ptr, size);
491 		break;
492 	default:
493 		plat_munmap(ptr, size);
494 		break;
495 	}
496 }
497 
plat_init(void)498 void plat_init(void)
499 {
500 	const char *main_fb_name = "/dev/fb0";
501 	struct fb_fix_screeninfo fbfix;
502 	int ret;
503 
504 	plat_target_init();
505 
506 	fbdev = open(main_fb_name, O_RDWR);
507 	if (fbdev == -1) {
508 		fprintf(stderr, "%s: ", main_fb_name);
509 		perror("open");
510 		exit(1);
511 	}
512 
513 	ret = ioctl(fbdev, FBIOGET_FSCREENINFO, &fbfix);
514 	if (ret == -1) {
515 		perror("ioctl(fbdev) failed");
516 		exit(1);
517 	}
518 	uppermem_pbase = fbfix.smem_start;
519 
520 	printf("framebuffer: \"%s\" @ %08lx\n", fbfix.id, fbfix.smem_start);
521 	fb_paddrs[0] = fbfix.smem_start;
522 	fb_paddrs[1] = fb_paddrs[0] + 320*240*4; // leave space for 24bpp
523 
524 	ret = warm_init();
525 	have_warm = (ret == 0);
526 
527 	if (have_warm) {
528 		// map fb as write-through cached section
529 		fb_vaddrs[0] = (void *)0x7fe00000;
530 		ret = warm_mmap_section(fb_vaddrs[0], fb_paddrs[0],
531 			FB_VRAM_SIZE, WCB_C_BIT);
532 		if (ret != 0) {
533 			fprintf(stderr, "fb section map failed\n");
534 			fb_vaddrs[0] = NULL;
535 
536 			// we could continue but it would just get messy
537 			exit(1);
538 		}
539 	}
540 	if (fb_vaddrs[0] == NULL) {
541 		fb_vaddrs[0] = mmap(0, FB_VRAM_SIZE, PROT_READ|PROT_WRITE,
542 				MAP_SHARED, memdev, fb_paddrs[0]);
543 		if (fb_vaddrs[0] == MAP_FAILED) {
544 			perror("mmap(fb_vaddrs) failed");
545 			exit(1);
546 		}
547 
548 		memset(fb_vaddrs[0], 0, FB_VRAM_SIZE);
549 		warm_change_cb_range(WCB_C_BIT, 1, fb_vaddrs[0], FB_VRAM_SIZE);
550 	}
551 	printf("  mapped @%p\n", fb_vaddrs[0]);
552 
553 	fb_vaddrs[1] = (char *)fb_vaddrs[0] + 320*240*4;
554 
555 	memset(fb_vaddrs[0], 0, FB_VRAM_SIZE);
556 
557 	pollux_changemode(16, 0);
558 	g_menuscreen_w = 320;
559 	g_menuscreen_h = 240;
560 	g_menuscreen_ptr = fb_flip();
561 
562 	/* setup DMA */
563 	DMA_REG(0x0c) = 0x20000; // pending IRQ clear
564 
565 	in_tsbutton_init();
566 	in_evdev_init(&gp2x_evdev_pdata);
567 	if (gp2x_dev_id == GP2X_DEV_CAANOO)
568 		caanoo_init();
569 	else
570 		wiz_init();
571 
572 	pl_plat_blit = have_warm ? raw_blit_dma : raw_blit_soft;
573 
574 	psx_src_width = 320;
575 	psx_src_height = 240;
576 	psx_bpp = 16;
577 
578 	pl_rearmed_cbs.screen_w = 320;
579 	pl_rearmed_cbs.screen_h = 240;
580 
581 	plat_target_setup_input();
582 
583 	plat_target.cpu_clock_set = cpu_clock_wrapper;
584 
585 	psxMapHook = pl_emu_mmap;
586 	psxUnmapHook = pl_emu_munmap;
587 }
588 
plat_finish(void)589 void plat_finish(void)
590 {
591 	warm_finish();
592 	memset(fb_vaddrs[0], 0, FB_VRAM_SIZE);
593 	munmap(fb_vaddrs[0], FB_VRAM_SIZE);
594 	close(fbdev);
595 	plat_target_finish();
596 }
597 
598 /* Caanoo stuff, perhaps move later */
599 static const char * const caanoo_keys[KEY_MAX + 1] = {
600 	[0 ... KEY_MAX] = NULL,
601 	[KEY_UP]        = "Up",
602 	[KEY_LEFT]      = "Left",
603 	[KEY_RIGHT]     = "Right",
604 	[KEY_DOWN]      = "Down",
605 	[BTN_TRIGGER]   = "A",
606 	[BTN_THUMB]     = "X",
607 	[BTN_THUMB2]    = "B",
608 	[BTN_TOP]       = "Y",
609 	[BTN_TOP2]      = "L",
610 	[BTN_PINKIE]    = "R",
611 	[BTN_BASE]      = "Home",
612 	[BTN_BASE2]     = "Lock",
613 	[BTN_BASE3]     = "I",
614 	[BTN_BASE4]     = "II",
615 	[BTN_BASE5]     = "Push",
616 };
617 
618 struct haptic_data {
619 	int count;
620 	struct {
621 		short time, strength;
622 	} actions[120];
623 };
624 
625 #define HAPTIC_IOCTL_MAGIC	'I'
626 #define HAPTIC_PLAY_PATTERN	_IOW(HAPTIC_IOCTL_MAGIC, 4, struct haptic_data)
627 #define HAPTIC_INDIVIDUAL_MODE	_IOW(HAPTIC_IOCTL_MAGIC, 5, unsigned int)
628 #define HAPTIC_SET_VIB_LEVEL	_IOW(HAPTIC_IOCTL_MAGIC, 9, unsigned int)
629 
630 static int hapticdev = -1;
631 static struct haptic_data haptic_seq[2];
632 
haptic_read(const char * fname,struct haptic_data * data)633 static int haptic_read(const char *fname, struct haptic_data *data)
634 {
635 	int i, ret, v1, v2;
636 	char buf[128], *p;
637 	FILE *f;
638 
639 	f = fopen(fname, "r");
640 	if (f == NULL) {
641 		fprintf(stderr, "fopen(%s)", fname);
642 		perror("");
643 		return -1;
644 	}
645 
646 	for (i = 0; i < sizeof(data->actions) / sizeof(data->actions[0]); ) {
647 		p = fgets(buf, sizeof(buf), f);
648 		if (p == NULL)
649 			break;
650 		while (*p != 0 && *p == ' ')
651 			p++;
652 		if (*p == 0 || *p == ';' || *p == '#')
653 			continue;
654 
655 		ret = sscanf(buf, "%d %d", &v1, &v2);
656 		if (ret != 2) {
657 			fprintf(stderr, "can't parse: %s", buf);
658 			continue;
659 		}
660 
661 		data->actions[i].time = v1;
662 		data->actions[i].strength = v2;
663 		i++;
664 	}
665 	fclose(f);
666 
667 	if (i == 0) {
668 		fprintf(stderr, "bad haptic file: %s\n", fname);
669 		return -1;
670 	}
671 	data->count = i;
672 
673 	return 0;
674 }
675 
haptic_init(void)676 static int haptic_init(void)
677 {
678 	int ret, i;
679 
680 	ret = haptic_read("haptic_w.cfg", &haptic_seq[0]);
681 	if (ret != 0)
682 		return -1;
683 	ret = haptic_read("haptic_s.cfg", &haptic_seq[1]);
684 	if (ret != 0)
685 		return -1;
686 
687 	hapticdev = open("/dev/isa1200", O_RDWR | O_NONBLOCK);
688 	if (hapticdev == -1) {
689 		perror("open(/dev/isa1200)");
690 		return -1;
691 	}
692 
693 	i = 0;
694 	ret  = ioctl(hapticdev, HAPTIC_INDIVIDUAL_MODE, &i);	/* use 2 of them */
695 	i = 3;
696 	ret |= ioctl(hapticdev, HAPTIC_SET_VIB_LEVEL, &i);	/* max */
697 	if (ret != 0) {
698 		fprintf(stderr, "haptic ioctls failed\n");
699 		close(hapticdev);
700 		hapticdev = -1;
701 		return -1;
702 	}
703 
704 	return 0;
705 }
706 
plat_trigger_vibrate(int pad,int low,int high)707 void plat_trigger_vibrate(int pad, int low, int high)
708 {
709 	int is_strong;
710 	int ret;
711 
712 	if (low == 0 && high == 0)
713 		return;
714 	is_strong = (high >= 0xf0);
715 
716 	if (hapticdev == -2)
717 		return; // it's broken
718 	if (hapticdev < 0) {
719 		ret = haptic_init();
720 		if (ret < 0) {
721 			hapticdev = -2;
722 			return;
723 		}
724 	}
725 
726 	ioctl(hapticdev, HAPTIC_PLAY_PATTERN, &haptic_seq[!!is_strong]);
727 }
728 
caanoo_init(void)729 static void caanoo_init(void)
730 {
731 	in_probe();
732 	in_set_config(in_name_to_id("evdev:pollux-analog"), IN_CFG_KEY_NAMES,
733 		      caanoo_keys, sizeof(caanoo_keys));
734 }
735 
736 /* Wiz stuff */
737 static const struct in_default_bind in_gp2x_defbinds[] =
738 {
739 	/* MXYZ SACB RLDU */
740 	{ GP2X_BTN_UP,		IN_BINDTYPE_PLAYER12, DKEY_UP },
741 	{ GP2X_BTN_DOWN,	IN_BINDTYPE_PLAYER12, DKEY_DOWN },
742 	{ GP2X_BTN_LEFT,	IN_BINDTYPE_PLAYER12, DKEY_LEFT },
743 	{ GP2X_BTN_RIGHT,	IN_BINDTYPE_PLAYER12, DKEY_RIGHT },
744 	{ GP2X_BTN_X,		IN_BINDTYPE_PLAYER12, DKEY_CROSS },
745 	{ GP2X_BTN_B,		IN_BINDTYPE_PLAYER12, DKEY_CIRCLE },
746 	{ GP2X_BTN_A,		IN_BINDTYPE_PLAYER12, DKEY_SQUARE },
747 	{ GP2X_BTN_Y,		IN_BINDTYPE_PLAYER12, DKEY_TRIANGLE },
748 	{ GP2X_BTN_L,		IN_BINDTYPE_PLAYER12, DKEY_L1 },
749 	{ GP2X_BTN_R,		IN_BINDTYPE_PLAYER12, DKEY_R1 },
750 	{ GP2X_BTN_START,	IN_BINDTYPE_PLAYER12, DKEY_START },
751 	{ GP2X_BTN_SELECT,	IN_BINDTYPE_EMU, SACTION_ENTER_MENU },
752 	{ GP2X_BTN_VOL_UP,	IN_BINDTYPE_EMU, SACTION_VOLUME_UP },
753 	{ GP2X_BTN_VOL_DOWN,	IN_BINDTYPE_EMU, SACTION_VOLUME_DOWN },
754 	{ 0, 0, 0 },
755 };
756 
757 // unused dummy for in_gp2x
758 volatile unsigned short *gp2x_memregs;
759 
wiz_init(void)760 static void wiz_init(void)
761 {
762 	in_gp2x_init(in_gp2x_defbinds);
763 	in_probe();
764 }
765