teensytp: configurable gamepads
[megadrive.git] / teensytp / host / main.c
CommitLineData
c28a7c81 1/*
ebeef6c6 2 * TeensyTP, Team Player/4-Player Adaptor implementation for Teensy3
3 * host part
4 * Copyright (c) 2015 notaz
c28a7c81 5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
21 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
22 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 * SOFTWARE.
25 */
26
932302ef 27#include <stdio.h>
61172125 28#include <stdlib.h>
932302ef 29#include <string.h>
30#include <stdint.h>
932302ef 31#include <sys/types.h>
32#include <sys/stat.h>
33#include <fcntl.h>
34#include <sys/ioctl.h>
35#include <sys/select.h>
36#include <unistd.h>
37#include <dirent.h>
f359b935 38#include <signal.h>
39#include <termios.h>
932302ef 40#include <errno.h>
41#include <linux/usbdevice_fs.h>
42#include <linux/usb/ch9.h>
1cb2822f 43#include <linux/input.h>
f20de073 44#include "../pkts.h"
932302ef 45
46#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
47
932302ef 48struct teensy_dev {
49 int fd;
50 struct {
51 int ep_in;
52 int ep_out;
53 } ifaces[2];
54};
55
ebeef6c6 56/* return 1 if found, 0 if not, < 0 on error */
932302ef 57static int find_device(struct teensy_dev *dev,
58 uint16_t vendor, uint16_t product)
59{
60 const char path_root[] = "/dev/bus/usb";
61 union {
62 struct usb_descriptor_header hdr;
63 struct usb_device_descriptor d;
64 struct usb_config_descriptor c;
65 struct usb_interface_descriptor i;
66 struct usb_endpoint_descriptor e;
67 char space[0x100]; /* enough? */
68 } desc;
69 char path_bus[256], path_dev[256];
70 struct dirent *ent, *ent_bus;
71 DIR *dir = NULL, *dir_bus = NULL;
72 int num, fd = -1;
73 int iface = -1;
74 int retval = -1;
75 int ret;
76
77 memset(dev, 0xff, sizeof(*dev));
78
79 dir = opendir(path_root);
80 if (dir == NULL) {
81 perror("opendir");
82 return -1;
83 }
84
85 for (ent = readdir(dir); ent != NULL; ent = readdir(dir)) {
86 /* should be a number like 000 */
87 if (sscanf(ent->d_name, "%03d", &num) != 1)
88 continue;
89
90 snprintf(path_bus, sizeof(path_bus), "%s/%s",
91 path_root, ent->d_name);
92
93 dir_bus = opendir(path_bus);
94 if (dir_bus == NULL)
95 continue;
96
97 ent_bus = readdir(dir_bus);
98 for (; ent_bus != NULL; ent_bus = readdir(dir_bus)) {
99 if (sscanf(ent->d_name, "%03d", &num) != 1)
100 continue;
101
102 snprintf(path_dev, sizeof(path_dev), "%s/%s/%s",
103 path_root, ent->d_name, ent_bus->d_name);
104
105 fd = open(path_dev, O_RDWR);
106 if (fd == -1)
107 continue;
108
109 ret = read(fd, &desc.d, sizeof(desc.d));
110 if (ret != sizeof(desc.d)) {
111 fprintf(stderr, "desc read: %d/%zd: ", ret, sizeof(desc.d));
112 perror("");
113 goto next;
114 }
115
116 if (desc.d.bDescriptorType != USB_DT_DEVICE) {
117 fprintf(stderr, "%s: bad DT: 0x%02x\n",
118 path_dev, desc.d.bDescriptorType);
119 goto next;
120 }
121
122 if (desc.d.idVendor == vendor && desc.d.idProduct == product)
123 goto found;
124
125next:
126 close(fd);
127 fd = -1;
128 }
129
130 closedir(dir_bus);
131 dir_bus = NULL;
132 }
133
134 /* not found */
135 retval = 0;
136 goto out;
137
138found:
139 if (desc.d.bNumConfigurations != 1) {
140 fprintf(stderr, "unexpected bNumConfigurations: %u\n",
141 desc.d.bNumConfigurations);
142 goto out;
143 }
144
145 /* walk through all descriptors */
146 while (1)
147 {
148 ret = read(fd, &desc.hdr, sizeof(desc.hdr));
149 if (ret == 0)
150 break;
151 if (ret != sizeof(desc.hdr)) {
152 fprintf(stderr, "desc.hdr read: %d/%zd: ", ret, sizeof(desc.hdr));
153 perror("");
154 break;
155 }
156
157 ret = (int)lseek(fd, -sizeof(desc.hdr), SEEK_CUR);
158 if (ret == -1) {
159 perror("lseek");
160 break;
161 }
162
163 ret = read(fd, &desc, desc.hdr.bLength);
164 if (ret != desc.hdr.bLength) {
165 fprintf(stderr, "desc read: %d/%u: ", ret, desc.hdr.bLength);
166 perror("");
167 break;
168 }
169
170 switch (desc.hdr.bDescriptorType) {
171 case USB_DT_CONFIG:
172 if (desc.c.bNumInterfaces != 2) {
173 fprintf(stderr, "unexpected bNumInterfaces: %u\n",
174 desc.c.bNumInterfaces);
175 goto out;
176 }
177 break;
178
179 case USB_DT_INTERFACE:
180 if (desc.i.bInterfaceClass != USB_CLASS_HID
181 || desc.i.bInterfaceSubClass != 0
182 || desc.i.bInterfaceProtocol != 0) {
183 fprintf(stderr, "unexpected interface %x:%x:%x\n",
184 desc.i.bInterfaceClass, desc.i.bInterfaceSubClass,
185 desc.i.bInterfaceProtocol);
186 goto out;
187 }
188 if (desc.i.bNumEndpoints != 2) {
189 fprintf(stderr, "unexpected bNumEndpoints: %u\n",
190 desc.i.bNumEndpoints);
191 goto out;
192 }
193 iface++;
194 break;
195
196 case USB_DT_ENDPOINT:
197 if (iface < 0 || iface >= ARRAY_SIZE(dev->ifaces)) {
198 fprintf(stderr, "bad iface: %d\n", iface);
199 goto out;
200 }
201 if (desc.e.wMaxPacketSize != 64 && desc.e.wMaxPacketSize != 32) {
202 fprintf(stderr, "iface %d, EP %02x: "
203 "unexpected wMaxPacketSize: %u\n",
204 iface, desc.e.bEndpointAddress, desc.e.wMaxPacketSize);
205 goto out;
206 }
207 if (desc.e.bEndpointAddress & 0x80)
208 dev->ifaces[iface].ep_in = desc.e.bEndpointAddress; // & 0x7F;
209 else
210 dev->ifaces[iface].ep_out = desc.e.bEndpointAddress;
211 break;
212
213 case 0x21:
214 /* ignore */
215 break;
216
217 default:
218 fprintf(stderr, "skipping desc 0x%02x\n",
219 desc.hdr.bDescriptorType);
220 break;
221 }
222 }
223
224 /* claim interfaces */
225 for (iface = 0; iface < ARRAY_SIZE(dev->ifaces); iface++) {
226 struct usbdevfs_ioctl usbio;
227
228 if (dev->ifaces[iface].ep_in == -1) {
229 fprintf(stderr, "missing ep_in, iface: %d\n", iface);
230 goto out;
231 }
232 if (dev->ifaces[iface].ep_out == -1) {
233 fprintf(stderr, "missing ep_out, iface: %d\n", iface);
234 goto out;
235 }
236
237 /* disconnect default driver */
238 memset(&usbio, 0, sizeof(usbio));
239 usbio.ifno = iface;
240 usbio.ioctl_code = USBDEVFS_DISCONNECT;
241 ret = ioctl(fd, USBDEVFS_IOCTL, &usbio);
242 if (ret != 0 && errno != ENODATA)
243 perror("USBDEVFS_DISCONNECT");
244
245 ret = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &iface);
246 if (ret != 0)
247 perror("USBDEVFS_CLAIMINTERFACE");
248 }
249
250 dev->fd = fd;
251 fd = -1;
252 retval = 1;
253
254out:
255 if (fd != -1)
256 close(fd);
257 if (dir_bus != NULL)
258 closedir(dir_bus);
259 if (dir != NULL)
260 closedir(dir);
261
262 return retval;
263}
264
f359b935 265static int enable_echo(int enable)
266{
267 const char *portname = "/dev/tty";
268 struct termios tty;
269 int retval = -1;
270 int ret;
271 int fd;
272
273 memset(&tty, 0, sizeof(tty));
274
275 fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC);
276 if (fd < 0) {
277 fprintf(stderr, "open %s: ", portname);
278 perror("");
279 return 1;
280 }
281
282 ret = tcgetattr(fd, &tty);
283 if (ret != 0) {
284 perror("tcgetattr");
285 goto out;
286 }
287
288 // printf("lflag: 0%o\n", tty.c_lflag);
289 if (enable)
de3f807e 290 tty.c_lflag |= ECHO | ICANON;
291 else {
292 tty.c_lflag &= ~(ECHO | ICANON);
293 tty.c_cc[VMIN] = tty.c_cc[VTIME] = 0;
294 }
f359b935 295
296 ret = tcsetattr(fd, TCSANOW, &tty);
297 if (ret != 0) {
298 perror("tcsetattr");
299 goto out;
300 }
301
302 retval = 0;
303out:
304 close(fd);
305
306 return retval;
307}
308
96b9855a 309static int g_exit;
310
f359b935 311static void signal_handler(int sig)
312{
96b9855a 313 g_exit = 1;
f359b935 314 signal(sig, SIG_DFL);
f359b935 315}
316
ebeef6c6 317/* MXYZ SACB RLDU */
1cb2822f 318enum mdbtn {
ebeef6c6 319 MDBTN_UP = (1 << 0),
320 MDBTN_DOWN = (1 << 1),
321 MDBTN_LEFT = (1 << 2),
322 MDBTN_RIGHT = (1 << 3),
323 MDBTN_A = (1 << 6),
324 MDBTN_B = (1 << 4),
325 MDBTN_C = (1 << 5),
326 MDBTN_START = (1 << 7),
327 MDBTN_X = (1 << 10),
328 MDBTN_Y = (1 << 9),
329 MDBTN_Z = (1 << 8),
330 MDBTN_MODE = (1 << 11),
1cb2822f 331};
332
ebeef6c6 333#define BTN_JOY BTN_JOYSTICK
156c3647 334#define BTN_GP BTN_GAMEPAD
ebeef6c6 335
336static const uint32_t evdev_md_default_map[KEY_CNT] = {
1cb2822f 337 [KEY_UP] = MDBTN_UP,
338 [KEY_DOWN] = MDBTN_DOWN,
339 [KEY_LEFT] = MDBTN_LEFT,
340 [KEY_RIGHT] = MDBTN_RIGHT,
ebeef6c6 341 [KEY_Z] = MDBTN_A,
342 [KEY_X] = MDBTN_B,
343 [KEY_C] = MDBTN_C,
344 [KEY_A] = MDBTN_X,
345 [KEY_S] = MDBTN_Y,
346 [KEY_D] = MDBTN_Z,
347 [KEY_F] = MDBTN_MODE,
348 [KEY_ENTER] = MDBTN_START,
156c3647 349 // joystick, assume diamond face button layout 1
350 // 4 2
351 // 3
352 [BTN_JOY + 0] = MDBTN_X,
353 [BTN_JOY + 1] = MDBTN_C,
354 [BTN_JOY + 2] = MDBTN_B,
355 [BTN_JOY + 3] = MDBTN_A,
356 [BTN_JOY + 4] = MDBTN_Y,
357 [BTN_JOY + 5] = MDBTN_Z,
358 [BTN_JOY + 6] = MDBTN_START,
359 [BTN_JOY + 7] = MDBTN_MODE,
360 [BTN_JOY + 9] = MDBTN_START,
ebeef6c6 361 // gamepad
156c3647 362 [BTN_GP + 0] = MDBTN_A,
363 [BTN_GP + 1] = MDBTN_B,
364 [BTN_GP + 2] = MDBTN_C,
365 [BTN_GP + 3] = MDBTN_X,
366 [BTN_GP + 4] = MDBTN_Y,
367 [BTN_GP + 5] = MDBTN_Z,
368 [BTN_GP + 6] = MDBTN_START,
369 [BTN_GP + 7] = MDBTN_MODE,
370 [BTN_GP + 9] = MDBTN_START,
ebeef6c6 371 // pandora
1cb2822f 372 [KEY_HOME] = MDBTN_A,
373 [KEY_PAGEDOWN] = MDBTN_B,
374 [KEY_END] = MDBTN_C,
375 [KEY_LEFTALT] = MDBTN_START,
376};
377
156c3647 378static const uint16_t bind_to_mask[256] = {
379 ['u'] = MDBTN_UP,
380 ['d'] = MDBTN_DOWN,
381 ['l'] = MDBTN_LEFT,
382 ['r'] = MDBTN_RIGHT,
383 ['a'] = MDBTN_A,
384 ['b'] = MDBTN_B,
385 ['c'] = MDBTN_C,
386 ['s'] = MDBTN_START,
387 ['x'] = MDBTN_X,
388 ['y'] = MDBTN_Y,
389 ['z'] = MDBTN_Z,
390 ['m'] = MDBTN_MODE,
391 ['0'] = 0, // to unbind a key
392};
393
ebeef6c6 394static struct player_state {
ebeef6c6 395 uint32_t state;
396 int dirty;
397} players[4];
398
156c3647 399struct evdev_dev {
400 uint32_t kc_map[KEY_CNT];
401 uint32_t player;
402 int fd;
403 struct {
404 int min, max, zone;
405 } abs[2]; // more abs on TODO (problems like noisy analogs)
406} devs[16];
407
408static int verbose;
409
410#define printf_v(l_, fmt_, ...) do { \
411 if (verbose >= (l_)) \
412 fprintf(stderr, fmt_, ##__VA_ARGS__); \
413} while (0)
414
415static int do_evdev_input(struct evdev_dev *dev)
1cb2822f 416{
ebeef6c6 417 struct player_state *player;
1cb2822f 418 struct input_event ev;
ebeef6c6 419 uint32_t mask_clear = 0;
420 uint32_t mask_set = 0;
421 uint32_t old_state;
422 int ret;
1cb2822f 423
156c3647 424 ret = read(dev->fd, &ev, sizeof(ev));
1cb2822f 425 if (ret != sizeof(ev)) {
156c3647 426 fprintf(stderr, "%tu, p%u: evdev read %d/%zd: ",
427 dev - devs, dev->player, ret, sizeof(ev));
1cb2822f 428 perror("");
156c3647 429 if (ret < 0) {
430 close(dev->fd);
431 dev->fd = -1;
432 }
1cb2822f 433 return 0;
434 }
435
156c3647 436 if (dev->player >= ARRAY_SIZE(players)) {
437 fprintf(stderr, "bad player: %u\n", dev->player);
1cb2822f 438 return 0;
439 }
156c3647 440 player = &players[dev->player];
ebeef6c6 441 old_state = player->state;
1cb2822f 442
ebeef6c6 443 if (ev.type == EV_ABS) {
156c3647 444 uint32_t l, h;
445
446 if (ev.code >= ARRAY_SIZE(dev->abs)) {
447 printf_v(2, "abs id %u is too large\n", ev.code);
448 return 0;
ebeef6c6 449 }
156c3647 450 printf_v(1, "%tu p%u: abs %u: %4d %4d %4d (%d)\n",
451 dev - devs, dev->player, ev.code,
452 dev->abs[ev.code].min, ev.value,
453 dev->abs[ev.code].max, dev->abs[ev.code].zone);
454
455 l = (ev.code & 1) ? MDBTN_UP : MDBTN_LEFT;
456 h = (ev.code & 1) ? MDBTN_DOWN : MDBTN_RIGHT;
457 mask_clear = l | h;
458 if (ev.value < dev->abs[ev.code].min + dev->abs[ev.code].zone)
459 mask_set = l;
460 else if (ev.value > dev->abs[ev.code].max - dev->abs[ev.code].zone)
461 mask_set = h;
1cb2822f 462 }
ebeef6c6 463 else if (ev.type == EV_KEY) {
464 if (ev.value != 0 && ev.value != 1)
465 return 0;
1cb2822f 466
156c3647 467 if ((uint32_t)ev.code >= ARRAY_SIZE(dev->kc_map)) {
ebeef6c6 468 fprintf(stderr, "evdev read bad key: %u\n", ev.code);
469 return 0;
470 }
ec7c7d4a 471
ebeef6c6 472 if (ev.value) // press?
156c3647 473 mask_set = dev->kc_map[ev.code];
ebeef6c6 474 else
156c3647 475 mask_clear = dev->kc_map[ev.code];
ec7c7d4a 476 }
156c3647 477 else {
478 return 0;
479 }
480
481 printf_v(1, "%tu p%u: c %03x, s %03x\n",
482 dev - devs, dev->player, mask_clear, mask_set);
ec7c7d4a 483
ebeef6c6 484 player->state &= ~mask_clear;
485 player->state |= mask_set;
ec7c7d4a 486
ebeef6c6 487 player->dirty |= old_state != player->state;
488 return player->dirty;
489}
f20de073 490
156c3647 491static int open_evdev(struct evdev_dev *dev, char *str_in)
01f5cc9e 492{
156c3647 493 uint32_t event_support = 0;
494 uint32_t abs_support = 0;
495 struct input_absinfo absi;
496 const char *name = str_in;
497 char *p, *s, *binds = NULL;
498 int i, fd, ret;
499 char buf[64];
500
501 p = strchr(str_in, ',');
502 if (p != NULL) {
503 *p++ = 0;
504 binds = p;
505 }
506
507 p = NULL;
508 i = strtol(name, &p, 0);
509 if (p != NULL && *p == 0) {
510 snprintf(buf, sizeof(buf), "/dev/input/event%d", i);
511 name = buf;
512 }
ec7c7d4a 513
ebeef6c6 514 fd = open(name, O_RDONLY);
515 if (fd == -1) {
516 fprintf(stderr, "open %s: ", name);
01f5cc9e 517 perror("");
19560e5f 518 return -1;
01f5cc9e 519 }
156c3647 520 ret = ioctl(fd, EVIOCGBIT(0, sizeof(event_support)),
521 &event_support);
ebeef6c6 522 if (ret < 0)
523 perror("EVIOCGBIT");
156c3647 524 if (!(event_support & ((1 << EV_KEY) | (1 << EV_ABS)))) {
525 fprintf(stderr, "%s doesn't have keys or abs\n", name);
ebeef6c6 526 close(fd);
19560e5f 527 return -1;
01f5cc9e 528 }
529
156c3647 530 dev->fd = fd;
531
532 if (event_support & (1 << EV_ABS)) {
533 ret = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_support)),
534 &abs_support);
535 if (ret < 0)
536 perror("EVIOCGBIT");
537 for (i = 0; i < ARRAY_SIZE(dev->abs); i++) {
538 if (!(abs_support & (1 << i)))
539 continue;
540 ret = ioctl(fd, EVIOCGABS(i), &absi);
541 if (ret != 0) {
542 perror("EVIOCGABS");
543 continue;
544 }
545 dev->abs[i].min = absi.minimum;
546 dev->abs[i].max = absi.maximum;
547 dev->abs[i].zone = (absi.maximum - absi.minimum) / 3;
548 }
549 }
550
551 memcpy(dev->kc_map, evdev_md_default_map, sizeof(dev->kc_map));
552 if (binds != NULL) {
553 unsigned int kc, end = 0;
554
555 p = binds;
556 do {
557 s = p;
558 for (; *p != 0 && *p != ','; p++)
559 ;
560 if (*p == 0)
561 end = 1;
562 else
563 *p++ = 0;
564 if (strncmp(s, "j=", 2) == 0) {
565 kc = BTN_JOYSTICK;
566 s += 2;
567 }
568 else if (strncmp(s, "g=", 2) == 0) {
569 kc = BTN_GAMEPAD;
570 s += 2;
571 }
572 else {
573 ret = sscanf(s, "%u=", &kc);
574 if (ret != 1 || (s = strchr(s, '=')) == NULL) {
575 fprintf(stderr, "parse failed: '%s'\n", s);
576 break;
577 }
578 s++;
579 }
580 // bind
581 for (; *s != 0 && kc < sizeof(dev->kc_map); s++, kc++) {
582 uint32_t mask = bind_to_mask[(uint8_t)*s];
583 if (mask == 0 && *s != '0') {
584 fprintf(stderr, "%s: '%c' is not a valid MD btn\n", name, *s);
585 continue;
586 }
587 dev->kc_map[kc] = mask;
588 }
589 }
590 while (!end);
591 }
592
593 return 0;
01f5cc9e 594}
595
ebeef6c6 596static void do_stdin_input(uint32_t *mode, int *changed)
01f5cc9e 597{
ebeef6c6 598 char c = 0;
599 int ret;
01f5cc9e 600
ebeef6c6 601 ret = read(STDIN_FILENO, &c, 1);
602 if (ret <= 0) {
603 perror("read stdin");
604 return;
01f5cc9e 605 }
606
ebeef6c6 607 switch (c) {
608 case '1':
609 printf("3btn mode\n");
610 *mode = OP_MODE_3BTN;
611 *changed = 1;
612 break;
613 case '2':
614 printf("6btn mode\n");
615 *mode = OP_MODE_6BTN;
616 *changed = 1;
617 break;
618 case '3':
619 printf("teamplayer mode\n");
620 *mode = OP_MODE_TEAMPLAYER;
621 *changed = 1;
622 break;
19560e5f 623 }
ec7c7d4a 624}
625
f20de073 626static int submit_urb(int fd, struct usbdevfs_urb *urb, int ep,
627 void *buf, size_t buf_size)
628{
629 memset(urb, 0, sizeof(*urb));
630 urb->type = USBDEVFS_URB_TYPE_INTERRUPT;
631 urb->endpoint = ep;
632 urb->buffer = buf;
633 urb->buffer_length = buf_size;
634
635 return ioctl(fd, USBDEVFS_SUBMITURB, urb);
636}
637
932302ef 638enum my_urbs {
639 URB_DATA_IN,
640 URB_DATA_OUT,
641 URB_DBG_IN,
642 URB_CNT
643};
644
ebeef6c6 645static void usage(const char *argv0)
61172125 646{
156c3647 647 fprintf(stderr, "usage:\n%s <-e player /dev/input/node[,binds]>*\n"
648 " [-m <mode>] [-v]\n\n"
649 " binds: <keycode=mdbtns>[,keycode=mdbtns]*\n"
650 " keycode: first keycode (int), can be j,g for joy,gamepad btn0\n"
651 " mdbtns: sequence of chars from: udlrabcsxyzm0\n"
652 " (u=up, d=down, ..., 0=unbind)\n"
653 " mode: int 0-2: 3btn 6btn teamplayer\n", argv0);
61172125 654 exit(1);
655}
656
ebeef6c6 657static void bad_arg(char *argv[], int a)
658{
659 fprintf(stderr, "bad arg %d: '%s'\n", a, argv[a]);
660 usage(argv[0]);
661}
662
932302ef 663int main(int argc, char *argv[])
664{
665 struct teensy_dev dev;
666 struct usbdevfs_urb urb[URB_CNT];
667 struct usbdevfs_urb *reaped_urb;
156c3647 668 int dev_cnt = 0;
932302ef 669 int wait_device = 0;
96b9855a 670 int pending_urbs = 0;
ebeef6c6 671 int had_input = 0;
1cb2822f 672 fd_set rfds, wfds;
ebeef6c6 673 int mode_changed = 0;
f20de073 674 char buf_dbg[64 + 1];
ebeef6c6 675 struct tp_pkt pkt_in;
676 struct tp_pkt pkt_out;
f20de073 677 struct timeval *timeout = NULL;
678 struct timeval tout;
ebeef6c6 679 uint32_t mode = OP_MODE_3BTN;
680 uint32_t player;
96b9855a 681 int i, ret = -1;
ebeef6c6 682
1cb2822f 683 for (i = 1; i < argc; i++) {
f20de073 684 if (argv[i][0] == '-') {
61172125 685 switch (argv[i][1] | (argv[i][2] << 8)) {
ebeef6c6 686 case 'e':
687 if (argv[++i] == NULL)
688 bad_arg(argv, i);
689 player = strtoul(argv[i], NULL, 0);
690 if (player >= ARRAY_SIZE(players))
691 bad_arg(argv, i);
692
693 if (argv[++i] == NULL)
694 bad_arg(argv, i);
156c3647 695 if (dev_cnt >= ARRAY_SIZE(devs)) {
ebeef6c6 696 fprintf(stderr, "too many evdevs\n");
697 break;
698 }
156c3647 699 ret = open_evdev(&devs[dev_cnt], argv[i]);
ebeef6c6 700 if (ret != 0)
701 bad_arg(argv, i);
156c3647 702 devs[dev_cnt].player = player;
703 dev_cnt++;
4af6d4e5 704 continue;
ebeef6c6 705 case 'm':
706 if (argv[++i] == NULL)
707 bad_arg(argv, i);
708 mode = strtoul(argv[i], NULL, 0);
709 mode_changed = 1;
6d4349fc 710 continue;
156c3647 711 case 'v':
712 verbose++;
713 continue;
be48e888 714 }
715 }
ebeef6c6 716 bad_arg(argv, i);
f20de073 717 }
718
156c3647 719 if (dev_cnt == 0)
ebeef6c6 720 usage(argv[0]);
32f257c5 721
f359b935 722 enable_echo(0);
723 signal(SIGINT, signal_handler);
724
932302ef 725 dev.fd = -1;
726
e8e66d02 727 while (!g_exit || (pending_urbs & (1 << URB_DATA_OUT)))
932302ef 728 {
729 if (dev.fd == -1) {
730 ret = find_device(&dev, 0x16C0, 0x0486);
731 if (ret < 0)
f359b935 732 break;
932302ef 733
734 if (ret == 0) {
735 if (!wait_device) {
ebeef6c6 736 printf("waiting for device...\n");
932302ef 737 wait_device = 1;
738 }
739 usleep(250000);
740 continue;
741 }
742
743 wait_device = 0;
96b9855a 744 pending_urbs = 0;
f20de073 745
746 /* we wait first, then send commands, but if teensy
ebeef6c6 747 * is started already, it won't send anything back */
f20de073 748 tout.tv_sec = 1;
749 tout.tv_usec = 0;
750 timeout = &tout;
932302ef 751 }
752
96b9855a 753 if (!(pending_urbs & (1 << URB_DATA_IN))) {
f20de073 754 memset(&pkt_in, 0, sizeof(pkt_in));
755 ret = submit_urb(dev.fd, &urb[URB_DATA_IN], dev.ifaces[0].ep_in,
756 &pkt_in, sizeof(pkt_in));
932302ef 757 if (ret != 0) {
758 perror("USBDEVFS_SUBMITURB URB_DATA_IN");
f359b935 759 break;
932302ef 760 }
f20de073 761
96b9855a 762 pending_urbs |= 1 << URB_DATA_IN;
932302ef 763 }
96b9855a 764 if (!(pending_urbs & (1 << URB_DBG_IN))) {
f20de073 765 ret = submit_urb(dev.fd, &urb[URB_DBG_IN], dev.ifaces[1].ep_in,
766 buf_dbg, sizeof(buf_dbg) - 1);
932302ef 767 if (ret != 0) {
768 perror("USBDEVFS_SUBMITURB URB_DBG_IN");
f359b935 769 break;
932302ef 770 }
f20de073 771
96b9855a 772 pending_urbs |= 1 << URB_DBG_IN;
932302ef 773 }
774
1cb2822f 775 FD_ZERO(&rfds);
de3f807e 776 FD_SET(STDIN_FILENO, &rfds);
156c3647 777 for (i = 0; i < dev_cnt; i++)
778 if (devs[i].fd != -1)
779 FD_SET(devs[i].fd, &rfds);
1cb2822f 780
932302ef 781 FD_ZERO(&wfds);
782 FD_SET(dev.fd, &wfds);
783
f20de073 784 ret = select(dev.fd + 1, &rfds, &wfds, NULL, timeout);
932302ef 785 if (ret < 0) {
786 perror("select");
f359b935 787 break;
932302ef 788 }
f20de073 789 timeout = NULL;
932302ef 790
ebeef6c6 791 /* something form stdin? */
792 if (FD_ISSET(STDIN_FILENO, &rfds))
793 do_stdin_input(&mode, &mode_changed);
de3f807e 794
e8e66d02 795 /* something from input devices? */
ebeef6c6 796 had_input = 0;
156c3647 797 for (i = 0; i < dev_cnt; i++) {
798 if (devs[i].fd != -1 && FD_ISSET(devs[i].fd, &rfds)) {
799 do_evdev_input(&devs[i]);
ebeef6c6 800 had_input = 1;
1cb2822f 801 }
802 }
ebeef6c6 803 if (had_input) {
804 /* collect any other input changes before starting
156c3647 805 * the slow USB transfer to teensy */
ebeef6c6 806 tout.tv_sec = tout.tv_usec = 0;
807 timeout = &tout;
808 continue;
809 }
1cb2822f 810
811 /* something from USB? */
f20de073 812 if (FD_ISSET(dev.fd, &wfds))
813 {
96b9855a 814 unsigned int which_urb;
815
932302ef 816 reaped_urb = NULL;
817 ret = ioctl(dev.fd, USBDEVFS_REAPURB, &reaped_urb);
818 if (ret != 0) {
819 if (errno == ENODEV)
820 goto dev_close;
821 perror("USBDEVFS_REAPURB");
f359b935 822 break;
932302ef 823 }
96b9855a 824 which_urb = reaped_urb - urb;
825 if (which_urb < ARRAY_SIZE(urb))
826 pending_urbs &= ~(1 << which_urb);
827 else {
828 fprintf(stderr, "reaped unknown urb: %p #%u",
829 reaped_urb, which_urb);
830 }
932302ef 831
832 if (reaped_urb != NULL && reaped_urb->status != 0) {
833 errno = -reaped_urb->status;
96b9855a 834 fprintf(stderr, "urb #%u: ", which_urb);
f20de073 835 perror("");
932302ef 836 if (reaped_urb->status == -EILSEQ) {
837 /* this is usually a sign of disconnect.. */
838 usleep(250000);
839 goto dev_close;
840 }
841 }
96b9855a 842 else if (reaped_urb == &urb[URB_DATA_IN])
843 {
f20de073 844 /* some request from teensy */
ebeef6c6 845 printf("rx data?\n");
932302ef 846 }
96b9855a 847 else if (reaped_urb == &urb[URB_DATA_OUT])
848 {
1cb2822f 849 }
96b9855a 850 else if (reaped_urb == &urb[URB_DBG_IN])
851 {
932302ef 852 /* debug text */
853 buf_dbg[reaped_urb->actual_length] = 0;
854 printf("%s", buf_dbg);
e4d23548 855
856 // continue receiving debug before sending out stuff
857 tout.tv_sec = 0;
858 tout.tv_usec = 1000;
859 timeout = &tout;
860 continue;
932302ef 861 }
862 else {
f20de073 863 fprintf(stderr, "reaped unknown urb? %p #%zu\n",
864 reaped_urb, reaped_urb - urb);
932302ef 865 }
866 }
1cb2822f 867
868 /* something to send? */
96b9855a 869 if (pending_urbs & (1 << URB_DATA_OUT))
ebeef6c6 870 // can't do that yet - out urb still busy
96b9855a 871 continue;
872
ebeef6c6 873 if (mode_changed) {
f20de073 874 memset(&pkt_out, 0, sizeof(pkt_out));
ebeef6c6 875 pkt_out.type = PKT_UPD_MODE;
876 pkt_out.mode = mode;
4af6d4e5 877
f20de073 878 ret = submit_urb(dev.fd, &urb[URB_DATA_OUT], dev.ifaces[0].ep_out,
879 &pkt_out, sizeof(pkt_out));
880 if (ret != 0) {
881 perror("USBDEVFS_SUBMITURB PKT_STREAM_ENABLE");
882 continue;
883 }
e8e66d02 884 pending_urbs |= 1 << URB_DATA_OUT;
ebeef6c6 885 mode_changed = 0;
e8e66d02 886 continue;
f20de073 887 }
1cb2822f 888
ebeef6c6 889 /* send buttons if there were any changes */
890 memset(&pkt_out, 0, sizeof(pkt_out));
891 for (i = 0; i < ARRAY_SIZE(players); i++) {
892 if (players[i].dirty)
893 pkt_out.changed_players |= 1 << i;
894 players[i].dirty = 0;
895
896 pkt_out.bnts[i] = players[i].state;
e8e66d02 897 }
ebeef6c6 898 if (pkt_out.changed_players != 0) {
899 pkt_out.type = PKT_UPD_BTNS;
e8e66d02 900
901 ret = submit_urb(dev.fd, &urb[URB_DATA_OUT], dev.ifaces[0].ep_out,
902 &pkt_out, sizeof(pkt_out));
903 if (ret != 0) {
ebeef6c6 904 perror("USBDEVFS_SUBMITURB PKT_FIXED_STATE");
f359b935 905 break;
1cb2822f 906 }
96b9855a 907 pending_urbs |= 1 << URB_DATA_OUT;
908 continue;
1cb2822f 909 }
910
932302ef 911 continue;
912
913dev_close:
914 close(dev.fd);
915 dev.fd = -1;
916 }
917
f359b935 918 enable_echo(1);
919
96b9855a 920 if (dev.fd != -1) {
921 /* deal with pending URBs */
922 if (pending_urbs & (1 << URB_DATA_IN))
923 ioctl(dev.fd, USBDEVFS_DISCARDURB, &urb[URB_DATA_IN]);
924 if (pending_urbs & (1 << URB_DBG_IN))
925 ioctl(dev.fd, USBDEVFS_DISCARDURB, &urb[URB_DBG_IN]);
926 for (i = 0; i < URB_CNT; i++) {
927 if (pending_urbs & (1 << i)) {
928 ret = ioctl(dev.fd, USBDEVFS_REAPURB, &reaped_urb);
929 if (ret != 0)
930 perror("USBDEVFS_REAPURB");
931 }
932 }
933
934 close(dev.fd);
935 }
936
f359b935 937 return ret;
932302ef 938}
939
940// vim: ts=2:sw=2:expandtab