Put linked libraries in LDLIBS
[wiimote-pad] / wiimote-pad.c
1 /*
2  * Wiimote-Pad
3  *
4  * Copyright (C) 2013-2017 Giuseppe Bilotta
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  *
20  */
21
22 #include <libudev.h>
23 #include <linux/input.h>
24 #include <linux/uinput.h>
25
26 #include <sys/select.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <glob.h>
30 #include <errno.h>
31 #include <signal.h>
32
33 #include <string.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <unistd.h>
37
38 #include <xwiimote.h>
39
40 /* These definitions might be missing from older linux/input.h headers */
41 #ifndef BTN_DPAD_UP
42 #define BTN_DPAD_UP 0x220
43 #endif
44 #ifndef BTN_DPAD_DOWN
45 #define BTN_DPAD_DOWN 0x221
46 #endif
47 #ifndef BTN_DPAD_LEFT
48 #define BTN_DPAD_LEFT 0x222
49 #endif
50 #ifndef BTN_DPAD_RIGHT
51 #define BTN_DPAD_RIGHT 0x223
52 #endif
53
54 #define WIIMOTE_PADMODE_VENDOR_ID 0x6181 /* GIuseppe BIlotta */
55 #define WIIMOTE_PADMODE_DEVICE_ID 0x3169 /* WIimote GamePad */
56
57 /* Check if an error \code is negative during \str action */
58 void err_check(int code, char const *str) {
59         if (code < 0) {
60                 int err = errno;
61                 fprintf(stderr, "could not %s (%d): %s\n",
62                         str, err, strerror(err));
63                 exit(-err);
64         }
65 }
66
67 #define DPAD_PORTRAIT \
68         _BUTTON(XWII_KEY_UP, BTN_DPAD_UP); \
69         _BUTTON(XWII_KEY_DOWN, BTN_DPAD_DOWN); \
70         _BUTTON(XWII_KEY_LEFT, BTN_DPAD_LEFT); \
71         _BUTTON(XWII_KEY_RIGHT, BTN_DPAD_RIGHT); \
72
73
74 #define DPAD_LANDSCAPE \
75         _BUTTON(XWII_KEY_UP, BTN_DPAD_LEFT); \
76         _BUTTON(XWII_KEY_DOWN, BTN_DPAD_RIGHT); \
77         _BUTTON(XWII_KEY_LEFT, BTN_DPAD_DOWN); \
78         _BUTTON(XWII_KEY_RIGHT, BTN_DPAD_UP); \
79
80 #define OTHER_BUTTONS \
81         _BUTTON(XWII_KEY_A, BTN_A); \
82         _BUTTON(XWII_KEY_B, BTN_B); \
83         _BUTTON(XWII_KEY_PLUS, BTN_TL); \
84         _BUTTON(XWII_KEY_MINUS, BTN_TR); \
85         _BUTTON(XWII_KEY_HOME, BTN_MODE); \
86         _BUTTON(XWII_KEY_ONE, BTN_1); \
87         _BUTTON(XWII_KEY_TWO, BTN_2); \
88
89 #define BUTTONS_LANDSCAPE do { \
90         DPAD_LANDSCAPE \
91         OTHER_BUTTONS \
92 } while (0)
93
94 #define BUTTONS_PORTRAIT do { \
95         DPAD_PORTRAIT \
96         OTHER_BUTTONS \
97 } while (0)
98
99
100 struct uinput_user_dev padmode;
101
102 /* macros to set evbits and keybits */
103 #define set_ev(key) do { \
104         ret = ioctl(fd, UI_SET_EVBIT, key); \
105         err_check(ret, "set " #key); \
106 } while(0)
107
108 #define set_key(key) do { \
109         ret = ioctl(fd, UI_SET_KEYBIT, key); \
110         err_check(ret, "set " #key); \
111 } while(0)
112
113 #define set_abs(key, min, max, fuzz, flat) do { \
114         ret = ioctl(fd, UI_SET_ABSBIT, key); \
115         err_check(ret, "set " #key); \
116         padmode.absmin[key] = min; \
117         padmode.absmax[key] = max; \
118         padmode.absfuzz[key] = fuzz; \
119         padmode.absflat[key] = flat; \
120 } while(0)
121
122 #define AXIS_MAX 100
123
124 struct wiimote_dev {
125         const char *device;
126         char *root;
127
128         int dev_id;
129
130         int uinput;
131
132         int dpad_portrait;
133
134         struct xwii_iface *iface;
135
136         /* Room for controller keys and two axes, plus SYN */
137         struct input_event iev[XWII_KEY_TWO+2+1+1];
138
139         unsigned int ifs;
140         int fd;
141 };
142
143 #define MAX_WIIMOTES FD_SETSIZE
144 struct wiimote_dev dev[MAX_WIIMOTES];
145 int motes; /* Connected Wiimotes */
146
147 int cli_dpad_portrait; /* D-pad in portrait mode selected on the command-line */
148
149 void dev_init(struct wiimote_dev const *dev, struct input_event *iev) {
150         int ret;
151         int fd = dev->uinput;
152
153 #define _BUTTON(n, bt) do { \
154         set_key(bt); \
155         iev[n].type = EV_KEY; \
156         iev[n].code = bt; \
157 } while (0)
158
159         set_ev(EV_KEY);
160         if (dev->dpad_portrait)
161                 BUTTONS_PORTRAIT;
162         else
163                 BUTTONS_LANDSCAPE;
164         set_ev(EV_SYN);
165
166 #undef _BUTTON
167
168         set_ev(EV_ABS);
169         set_abs(ABS_X, -AXIS_MAX, AXIS_MAX, 2, 4);
170         iev[11].type = EV_ABS;
171         iev[11].code = ABS_X;
172         set_abs(ABS_Y, -AXIS_MAX, AXIS_MAX, 2, 4);
173         iev[12].type = EV_ABS;
174         iev[12].code = ABS_Y;
175
176         iev[13].type = EV_SYN;
177         iev[13].code = iev[13].value = 0;
178
179         snprintf(padmode.name, UINPUT_MAX_NAME_SIZE, XWII_NAME_CORE " in gamepad mode");
180         padmode.id.bustype = BUS_VIRTUAL;
181         /*
182         padmode.id.vendor = 0;
183         padmode.id.product = 0;
184         padmode.id.version = 0;
185         */
186
187         ret = write(fd, &padmode, sizeof(padmode));
188         err_check(ret, "set dev properties");
189         ret = ioctl(fd, UI_DEV_CREATE);
190         err_check(ret, "create device");
191 }
192
193
194 static int wiimote_refresh(struct wiimote_dev *dev)
195 {
196         puts("Refreshing\n");
197         return xwii_iface_open(dev->iface, dev->ifs);
198 }
199
200 static void wiimote_key(struct wiimote_dev *dev, struct xwii_event const *ev)
201 {
202         unsigned int code = ev->v.key.code;
203         unsigned int state = ev->v.key.state;
204         struct input_event *iev = dev->iev;
205
206         if (code > XWII_KEY_TWO)
207                 return;
208         if (state > 1)
209                 return;
210         iev[code].value = state;
211
212         if (dev->uinput > 0) {
213                 int ret = write(dev->uinput, iev + code, sizeof(*iev));
214                 err_check(ret, "report button");
215                 ret = write(dev->uinput, iev + 13, sizeof(*iev));
216                 err_check(ret, "report btn SYN");
217         } else {
218                 fputs("nowhere to report button presses to\n", stderr);
219         }
220 }
221
222 #define CLIP_AXIS(val) do { \
223         if (val < -AXIS_MAX) \
224                 val = -AXIS_MAX; \
225         if (val > AXIS_MAX) \
226                 val = AXIS_MAX; \
227 } while (0)
228
229
230 static void wiimote_accel(struct wiimote_dev *dev, struct xwii_event const *ev)
231 {
232         struct input_event *iev = dev->iev;
233
234         iev[11].value = -(ev->v.abs[0].y);
235         iev[12].value = -(ev->v.abs[0].x);
236
237         CLIP_AXIS(iev[11].value);
238         CLIP_AXIS(iev[12].value);
239
240         if (dev->uinput > 0) {
241                 int ret = write(dev->uinput, iev + 11, sizeof(*iev));
242                 err_check(ret, "report accel X");
243                 ret = write(dev->uinput, iev + 12, sizeof(*iev));
244                 err_check(ret, "report accel Y");
245                 ret = write(dev->uinput, iev + 13, sizeof(*iev));
246                 err_check(ret, "report accel SYN");
247 #if 0
248                 printf("reported J (%d, %d) from ev (%d, %d)\n",
249                         iev[11].value, iev[12].value,
250                         -(ev->v.abs[0].y), ev->v.abs[0].x);
251 #endif
252         } else {
253                 fputs("nowhere to report accel to\n", stderr);
254         }
255 }
256
257 static int wiimote_poll(struct wiimote_dev *dev)
258 {
259         struct xwii_event ev;
260         int ret;
261
262         do {
263                 memset(&ev, 0, sizeof(ev));
264                 ret = xwii_iface_dispatch(dev->iface, &ev, sizeof(ev));
265
266                 if (ret)
267                         break;
268
269                 switch (ev.type) {
270                 case XWII_EVENT_WATCH:
271                         ret = wiimote_refresh(dev);
272                         break;
273                 case XWII_EVENT_KEY:
274                         wiimote_key(dev, &ev);
275                         break;
276                 case XWII_EVENT_ACCEL:
277                         wiimote_accel(dev, &ev);
278                         break;
279                 default:
280                         printf("Unhandled Wiimote event type %d\n", ev.type);
281                 }
282         } while (!ret);
283
284         if (ret == -EAGAIN) {
285                 ret = 0;
286         }
287
288         return ret;
289 }
290
291 int dev_create(struct wiimote_dev *dev) {
292         int ret = 0;
293         struct udev *udev;
294         struct udev_device *d, *p;
295         struct stat st;
296         const char *root, *snum, *driver, *subs;
297         int num;
298
299         dev->dpad_portrait = cli_dpad_portrait;
300
301         if (!dev->device) {
302                 ret = EINVAL;
303                 goto exit;
304         }
305
306         if (stat(dev->device, &st)) {
307                 ret = errno;
308                 goto exit;
309         }
310
311         udev = udev_new();
312         if (!udev) {
313                 fputs("could not connect to udev\n", stderr);
314                 ret = errno;
315                 goto exit;
316         }
317
318         d = udev_device_new_from_devnum(udev, 'c', st.st_rdev);
319         if (!d) {
320                 fputs("could not find udev device\n", stderr);
321                 ret = errno;
322                 goto exit_udev;
323         }
324
325         p = udev_device_get_parent_with_subsystem_devtype(d, "hid", NULL);
326         if (!p) {
327                 fputs("could not find parent HID device\n", stderr);
328                 ret = errno;
329                 goto exit_dev;
330         }
331
332         driver = udev_device_get_driver(p);
333         subs = udev_device_get_subsystem(p);
334         if (!driver || strcmp(driver, "wiimote") || !subs || strcmp(subs, "hid")) {
335                 fputs("parent is not a HID Wiimote\n", stderr);
336                 ret = errno;
337                 goto exit_dev;
338         }
339
340         root = udev_device_get_syspath(p);
341         snum = udev_device_get_sysname(p);
342         snum = snum ? strchr(snum, '.') : NULL;
343         if (!root || !snum) {
344                 fputs("Could not get root path\n", stderr);
345                 ret = errno;
346                 goto exit_dev;
347         }
348
349         num = strtol(&snum[1], NULL, 16);
350         if (num < 0) {
351                 fputs("Negative device number!\n", stderr);
352                 ret = errno;
353                 goto exit_dev;
354         }
355         dev->dev_id = num;
356
357         dev->root = strdup(root);
358         if (!dev->root) {
359                 fputs("Could not set device root\n", stderr);
360                 ret = errno;
361                 goto exit_dev;
362         }
363
364         printf("using device %d from root %s for %s\n",
365                 dev->dev_id, dev->root, dev->device);
366
367         dev->ifs = XWII_IFACE_CORE | XWII_IFACE_ACCEL;
368         ret = xwii_iface_new(&dev->iface, dev->root);
369         if (ret) {
370                 fputs("Could not create xwiimote interface\n", stderr);
371                 ret = errno;
372                 goto exit_wii;
373         }
374
375         ret = xwii_iface_open(dev->iface, dev->ifs);
376         if (ret) {
377                 fputs("Could not open xwiimote interface\n", stderr);
378                 ret = errno;
379                 goto exit_wii;
380         }
381         if (xwii_iface_opened(dev->iface) != dev->ifs) {
382                 fputs("Some interfaces failed to open\n", stderr);
383                 ret = errno;
384                 goto exit_wii;
385         }
386
387         dev->fd = xwii_iface_get_fd(dev->iface);
388
389         goto exit_dev;
390
391 exit_wii:
392         free(dev->root);
393         dev->root = NULL;
394
395 exit_dev:
396         udev_device_unref(d);
397 exit_udev:
398         udev_unref(udev);
399 exit:
400         if (!ret) {
401                 printf("\twith D-pad in %s mode\n",
402                         dev->dpad_portrait ? "portrait" : "landscape");
403         }
404         return ret;
405 }
406
407 static void dev_destroy(struct wiimote_dev *dev) {
408         if (dev->root) {
409                 xwii_iface_unref(dev->iface);
410                 free(dev->root);
411                 dev->root = NULL;
412         }
413         if (dev->uinput > 0) {
414                 ioctl(dev->uinput, UI_DEV_DESTROY);
415                 close(dev->uinput);
416         }
417         printf("deassociated from device %s\n", dev->device);
418 }
419
420 glob_t js_devs;
421
422 static void destroy_all_devs(void) {
423         while (motes-- > 0)
424                 dev_destroy(dev + motes);
425         globfree(&js_devs);
426 }
427
428 static int last_signal;
429
430 static void sig_exit(int _signal) {
431         last_signal = _signal;
432         printf("Interrupted by signal %d\n", last_signal);
433 }
434
435 struct timeval no_wait;
436
437 const char uinput_path[] = "/dev/uinput";
438
439 const char js_glob[] = "/dev/input/js*";
440
441 int check_dpad(int argc, char **argv[])
442 {
443         printf("%d %p\n", argc, *argv);
444         if (argc > 1 && !strcmp((*argv)[1], "--dpad")) {
445                 --argc; ++*argv;
446                 if (argc <= 1) {
447                         fputs("missing --dpad spec\n", stderr);
448                         exit(1);
449                 }
450                 if (!strcmp((*argv)[1], "land") || !strcmp((*argv)[1], "landscape")) {
451                         cli_dpad_portrait = 0;
452                 } else if (!strcmp((*argv)[1], "port") || !strcmp((*argv)[1], "portrait")) {
453                         cli_dpad_portrait = 1;
454                 } else {
455                         fprintf(stderr, "unknown --dpad spec %s\n", (*argv)[1]);
456                         exit(1);
457                 }
458                 --argc; ++*argv;
459                 printf("The next wiimote(s) will be configured with the D-pad in %s mode\n",
460                         cli_dpad_portrait ? "portrait" : "landscape");
461         }
462         return argc;
463 }
464
465 int main(int argc, char *argv[]) {
466         int ret = 0;
467         fd_set input_fds, backup_fds;
468         int max_fd = -1;
469
470         cli_dpad_portrait = 0;
471
472         atexit(destroy_all_devs);
473         signal(SIGINT, sig_exit);
474
475         while (argc > 1) {
476                 /* Check if there is a dpad specification */
477                 ret = argc;
478                 while (1) {
479                         printf("%d %d\n", ret, argc);
480                         ret = check_dpad(ret, &argv);
481                         if (ret == argc)
482                                 break;
483                         argc = ret;
484                 }
485
486                 /* If there are still arguments, assume it's a device specification */
487                 if (argc > 1) {
488                         dev[motes].device = argv[motes+1];
489                         ret = dev_create(dev + motes);
490
491                         if (ret) {
492                                 fprintf(stderr, "could not %s (%d): %s\n",
493                                         "associate", ret, strerror(ret));
494                                 return ret;
495                         }
496                         ++motes;
497                 }
498         }
499
500         if (motes == 0) {
501                 /* No device specified. Since the Linux kernel exposes the
502                  * controller also as a joystick (without axes), we peek at
503                  * all available joysticks looking for one which is a Wiimote
504                  */
505
506                 switch (glob(js_glob, GLOB_NOSORT, NULL, &js_devs)) {
507                 case GLOB_ABORTED:
508                 case GLOB_NOMATCH:
509                 case GLOB_NOSPACE:
510                         fputs("no joysticks found\n", stderr);
511                         exit(ENODEV);
512                 }
513
514                 for (size_t j = 0; j < js_devs.gl_pathc; ++j) {
515                         dev[motes].device = js_devs.gl_pathv[j];
516                         ret = dev_create(dev + motes);
517                         if (!ret) {
518                                 ++motes; /* found */
519                         } else {
520                                 /* not found */
521                                 printf("skipping %s (%d): %s\n",
522                                         dev[motes].device, ret, strerror(ret));
523                         }
524                 }
525         }
526
527         if (motes == 0) {
528                 fputs("no wiimote found\n", stderr);
529                 exit(ENODEV);
530         }
531
532         FD_ZERO(&backup_fds);
533
534         for (int j = 0; j < motes; ++j) {
535                 dev[j].uinput = open(uinput_path, O_WRONLY | O_NONBLOCK);
536                 err_check(dev[j].uinput, "open uinput");
537                 dev_init(dev + j, dev[j].iev);
538
539                 int fd = dev[j].fd;
540                 FD_SET(fd, &backup_fds);
541                 if (max_fd < fd)
542                         max_fd = fd;
543         }
544
545         do {
546                 memset(&no_wait, 0, sizeof(no_wait));
547                 input_fds = backup_fds;
548
549                 if (last_signal)
550                         break;
551                 ret = select(max_fd + 1, &input_fds, NULL, NULL, NULL);
552                 err_check(ret, "poll wiimote fd");
553                 if (ret > 0) {
554                         for (int j = 0; j < motes; ++j) {
555                                 struct wiimote_dev *cur = dev + j;
556                                 if (FD_ISSET(cur->fd, &input_fds)) {
557                                         ret = wiimote_poll(cur);
558                                         err_check(ret, "process wiimote data");
559                                 }
560                         }
561                 }
562         } while (1);
563
564         return ret;
565 }
566