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