evdev input forwarder
[megadrive.git] / host / main.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdint.h>
4 #include <sys/types.h>
5 #include <sys/stat.h>
6 #include <fcntl.h>
7 #include <sys/ioctl.h>
8 #include <sys/select.h>
9 #include <unistd.h>
10 #include <dirent.h>
11 #include <errno.h>
12 #include <linux/usbdevice_fs.h>
13 #include <linux/usb/ch9.h>
14 #include <linux/input.h>
15
16 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
17
18 struct teensy_dev {
19   int fd;
20   struct {
21     int ep_in;
22     int ep_out;
23   } ifaces[2];
24 };
25
26 /* return 1 if founf, 0 if not, < 0 on error */
27 static int find_device(struct teensy_dev *dev,
28   uint16_t vendor, uint16_t product)
29 {
30   const char path_root[] = "/dev/bus/usb";
31   union {
32     struct usb_descriptor_header hdr;
33     struct usb_device_descriptor d;
34     struct usb_config_descriptor c;
35     struct usb_interface_descriptor i;
36     struct usb_endpoint_descriptor e;
37     char space[0x100]; /* enough? */
38   } desc;
39   char path_bus[256], path_dev[256];
40   struct dirent *ent, *ent_bus;
41   DIR *dir = NULL, *dir_bus = NULL;
42   int num, fd = -1;
43   int iface = -1;
44   int retval = -1;
45   int ret;
46
47   memset(dev, 0xff, sizeof(*dev));
48
49   dir = opendir(path_root);
50   if (dir == NULL) {
51     perror("opendir");
52     return -1;
53   }
54
55   for (ent = readdir(dir); ent != NULL; ent = readdir(dir)) {
56     /* should be a number like 000 */
57     if (sscanf(ent->d_name, "%03d", &num) != 1)
58       continue;
59
60     snprintf(path_bus, sizeof(path_bus), "%s/%s",
61         path_root, ent->d_name);
62
63     dir_bus = opendir(path_bus);
64     if (dir_bus == NULL)
65       continue;
66
67     ent_bus = readdir(dir_bus);
68     for (; ent_bus != NULL; ent_bus = readdir(dir_bus)) {
69       if (sscanf(ent->d_name, "%03d", &num) != 1)
70         continue;
71
72       snprintf(path_dev, sizeof(path_dev), "%s/%s/%s",
73           path_root, ent->d_name, ent_bus->d_name);
74
75       fd = open(path_dev, O_RDWR);
76       if (fd == -1)
77         continue;
78
79       ret = read(fd, &desc.d, sizeof(desc.d));
80       if (ret != sizeof(desc.d)) {
81         fprintf(stderr, "desc read: %d/%zd: ", ret, sizeof(desc.d));
82         perror("");
83         goto next;
84       }
85
86       if (desc.d.bDescriptorType != USB_DT_DEVICE) {
87         fprintf(stderr, "%s: bad DT: 0x%02x\n",
88             path_dev, desc.d.bDescriptorType);
89         goto next;
90       }
91
92       if (desc.d.idVendor == vendor && desc.d.idProduct == product)
93         goto found;
94
95 next:
96       close(fd);
97       fd = -1;
98     }
99
100     closedir(dir_bus);
101     dir_bus = NULL;
102   }
103
104   /* not found */
105   retval = 0;
106   goto out;
107
108 found:
109   if (desc.d.bNumConfigurations != 1) {
110     fprintf(stderr, "unexpected bNumConfigurations: %u\n",
111         desc.d.bNumConfigurations);
112     goto out;
113   }
114
115   /* walk through all descriptors */
116   while (1)
117   {
118     ret = read(fd, &desc.hdr, sizeof(desc.hdr));
119     if (ret == 0)
120       break;
121     if (ret != sizeof(desc.hdr)) {
122       fprintf(stderr, "desc.hdr read: %d/%zd: ", ret, sizeof(desc.hdr));
123       perror("");
124       break;
125     }
126
127     ret = (int)lseek(fd, -sizeof(desc.hdr), SEEK_CUR);
128     if (ret == -1) {
129       perror("lseek");
130       break;
131     }
132
133     ret = read(fd, &desc, desc.hdr.bLength);
134     if (ret != desc.hdr.bLength) {
135       fprintf(stderr, "desc read: %d/%u: ", ret, desc.hdr.bLength);
136       perror("");
137       break;
138     }
139
140     switch (desc.hdr.bDescriptorType) {
141       case USB_DT_CONFIG:
142         if (desc.c.bNumInterfaces != 2) {
143           fprintf(stderr, "unexpected bNumInterfaces: %u\n",
144               desc.c.bNumInterfaces);
145           goto out;
146         }
147         break;
148
149       case USB_DT_INTERFACE:
150         if (desc.i.bInterfaceClass != USB_CLASS_HID
151             || desc.i.bInterfaceSubClass != 0
152             || desc.i.bInterfaceProtocol != 0) {
153           fprintf(stderr, "unexpected interface %x:%x:%x\n",
154             desc.i.bInterfaceClass, desc.i.bInterfaceSubClass,
155             desc.i.bInterfaceProtocol);
156           goto out;
157         }
158         if (desc.i.bNumEndpoints != 2) {
159           fprintf(stderr, "unexpected bNumEndpoints: %u\n",
160             desc.i.bNumEndpoints);
161           goto out;
162         }
163         iface++;
164         break;
165
166       case USB_DT_ENDPOINT:
167         if (iface < 0 || iface >= ARRAY_SIZE(dev->ifaces)) {
168           fprintf(stderr, "bad iface: %d\n", iface);
169           goto out;
170         }
171         if (desc.e.wMaxPacketSize != 64 && desc.e.wMaxPacketSize != 32) {
172           fprintf(stderr, "iface %d, EP %02x: "
173             "unexpected wMaxPacketSize: %u\n",
174             iface, desc.e.bEndpointAddress, desc.e.wMaxPacketSize);
175           goto out;
176         }
177         if (desc.e.bEndpointAddress & 0x80)
178           dev->ifaces[iface].ep_in = desc.e.bEndpointAddress; // & 0x7F;
179         else
180           dev->ifaces[iface].ep_out = desc.e.bEndpointAddress;
181         break;
182
183       case 0x21:
184         /* ignore */
185         break;
186
187       default:
188         fprintf(stderr, "skipping desc 0x%02x\n",
189           desc.hdr.bDescriptorType);
190         break;
191     }
192   }
193
194   /* claim interfaces */
195   for (iface = 0; iface < ARRAY_SIZE(dev->ifaces); iface++) {
196     struct usbdevfs_ioctl usbio;
197
198     if (dev->ifaces[iface].ep_in == -1) {
199       fprintf(stderr, "missing ep_in, iface: %d\n", iface);
200       goto out;
201     }
202     if (dev->ifaces[iface].ep_out == -1) {
203       fprintf(stderr, "missing ep_out, iface: %d\n", iface);
204       goto out;
205     }
206
207     /* disconnect default driver */
208     memset(&usbio, 0, sizeof(usbio));
209     usbio.ifno = iface;
210     usbio.ioctl_code = USBDEVFS_DISCONNECT;
211     ret = ioctl(fd, USBDEVFS_IOCTL, &usbio);
212     if (ret != 0 && errno != ENODATA)
213       perror("USBDEVFS_DISCONNECT");
214
215     ret = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &iface);
216     if (ret != 0)
217       perror("USBDEVFS_CLAIMINTERFACE");
218   }
219
220   dev->fd = fd;
221   fd = -1;
222   retval = 1;
223
224 out:
225   if (fd != -1)
226     close(fd);
227   if (dir_bus != NULL)
228     closedir(dir_bus);
229   if (dir != NULL)
230     closedir(dir);
231
232   return retval;
233 }
234
235 /* ?0SA 00DU, ?1CB RLDU */
236 #define STATE_BYTES 2
237
238 static uint8_t fixed_input_state[STATE_BYTES] = { 0x33, 0x3f };
239
240 enum mdbtn {
241   MDBTN_UP = 1,
242   MDBTN_DOWN,
243   MDBTN_LEFT,
244   MDBTN_RIGHT,
245   MDBTN_A,
246   MDBTN_B,
247   MDBTN_C,
248   MDBTN_START,
249 };
250
251 static const enum mdbtn evdev_md_map[KEY_CNT] = {
252   [KEY_UP]       = MDBTN_UP,
253   [KEY_DOWN]     = MDBTN_DOWN,
254   [KEY_LEFT]     = MDBTN_LEFT,
255   [KEY_RIGHT]    = MDBTN_RIGHT,
256   [KEY_HOME]     = MDBTN_A,
257   [KEY_PAGEDOWN] = MDBTN_B,
258   [KEY_END]      = MDBTN_C,
259   [KEY_LEFTALT]  = MDBTN_START,
260 };
261
262 int do_evdev_input(int fd)
263 {
264   uint8_t old_state[STATE_BYTES];
265   uint8_t changed_bits[STATE_BYTES] = { 0, };
266   struct input_event ev;
267   enum mdbtn mdbtn;
268   int i, ret;
269
270   ret = read(fd, &ev, sizeof(ev));
271   if (ret != sizeof(ev)) {
272     fprintf(stderr, "evdev read %d/%zd: ", ret, sizeof(ev));
273     perror("");
274     return 0;
275   }
276
277   if (ev.type != EV_KEY)
278     return 0;
279
280   if (ev.value != 0 && ev.value != 1)
281     return 0;
282
283   if ((uint32_t)ev.code >= ARRAY_SIZE(evdev_md_map)) {
284     fprintf(stderr, "evdev read bad key: %u\n", ev.code);
285     return 0;
286   }
287
288   mdbtn = evdev_md_map[ev.code];
289   if (mdbtn == 0)
290     return 0;
291
292   memcpy(old_state, fixed_input_state, STATE_BYTES);
293
294   /* ?0SA 00DU, ?1CB RLDU */
295   switch (mdbtn) {
296   case MDBTN_UP:
297     changed_bits[0] = 0x01;
298     changed_bits[1] = 0x01;
299     break;
300   case MDBTN_DOWN:
301     changed_bits[0] = 0x02;
302     changed_bits[1] = 0x02;
303     break;
304   case MDBTN_LEFT:
305     changed_bits[0] = 0x00;
306     changed_bits[1] = 0x04;
307     break;
308   case MDBTN_RIGHT:
309     changed_bits[0] = 0x00;
310     changed_bits[1] = 0x08;
311     break;
312   case MDBTN_A:
313     changed_bits[0] = 0x10;
314     changed_bits[1] = 0x00;
315     break;
316   case MDBTN_B:
317     changed_bits[0] = 0x00;
318     changed_bits[1] = 0x10;
319     break;
320   case MDBTN_C:
321     changed_bits[0] = 0x00;
322     changed_bits[1] = 0x20;
323     break;
324   case MDBTN_START:
325     changed_bits[0] = 0x20;
326     changed_bits[1] = 0x00;
327     break;
328   }
329
330   if (ev.value) {
331     // key press
332     for (i = 0; i < STATE_BYTES; i++)
333       fixed_input_state[i] &= ~changed_bits[i];
334   }
335   else {
336     // key release
337     for (i = 0; i < STATE_BYTES; i++)
338       fixed_input_state[i] |=  changed_bits[i];
339   }
340
341   return memcmp(old_state, fixed_input_state, STATE_BYTES) ? 1 : 0;
342 }
343
344 enum my_urbs {
345   URB_DATA_IN,
346   URB_DATA_OUT,
347   URB_DBG_IN,
348   URB_CNT
349 };
350
351 int main(int argc, char *argv[])
352 {
353   char buf_dbg[64 + 1], buf_in[64], buf_out[64];
354   struct teensy_dev dev;
355   struct usbdevfs_urb urb[URB_CNT];
356   struct usbdevfs_urb *reaped_urb;
357   int fixed_input_changed;
358   int evdev_fds[16];
359   int evdev_fd_cnt = 0;
360   int evdev_support;
361   int wait_device = 0;
362   int dbg_in_sent = 0;
363   int data_in_sent = 0;
364   fd_set rfds, wfds;
365   int i, ret;
366   int fd;
367
368   for (i = 1; i < argc; i++) {
369     if (evdev_fd_cnt >= ARRAY_SIZE(evdev_fds)) {
370       fprintf(stderr, "too many evdevs\n");
371       break;
372     }
373                 fd = open(argv[i], O_RDONLY);
374     if (fd == -1) {
375       fprintf(stderr, "open %s: ", argv[i]);
376       perror("");
377       continue;
378     }
379     evdev_support = 0;
380                 ret = ioctl(fd, EVIOCGBIT(0, sizeof(evdev_support)),
381                 &evdev_support);
382     if (ret < 0)
383       perror("EVIOCGBIT");
384     if (!(evdev_support & (1 << EV_KEY))) {
385       fprintf(stderr, "%s doesn't have keys\n", argv[i]);
386       close(fd);
387       continue;
388     }
389     evdev_fds[evdev_fd_cnt++] = fd;
390   }
391
392   dev.fd = -1;
393
394   while (1)
395   {
396     if (dev.fd == -1) {
397       ret = find_device(&dev, 0x16C0, 0x0486);
398       if (ret < 0)
399         return ret;
400
401       if (ret == 0) {
402         if (!wait_device) {
403           printf("waiting for device..\n");
404           wait_device = 1;
405         }
406         usleep(250000);
407         continue;
408       }
409
410       wait_device = 0;
411       data_in_sent = 0;
412       dbg_in_sent = 0;
413     }
414
415     if (!data_in_sent) {
416       memset(&urb[URB_DATA_IN], 0, sizeof(urb[URB_DATA_IN]));
417       urb[URB_DATA_IN].type = USBDEVFS_URB_TYPE_INTERRUPT;
418       urb[URB_DATA_IN].endpoint = dev.ifaces[0].ep_in;
419       urb[URB_DATA_IN].buffer = buf_in;
420       urb[URB_DATA_IN].buffer_length = sizeof(buf_in);
421
422       ret = ioctl(dev.fd, USBDEVFS_SUBMITURB, &urb[URB_DATA_IN]);
423       if (ret != 0) {
424         perror("USBDEVFS_SUBMITURB URB_DATA_IN");
425         return 1;
426       }
427       data_in_sent = 1;
428     }
429     if (!dbg_in_sent) {
430       memset(&urb[URB_DBG_IN], 0, sizeof(urb[URB_DBG_IN]));
431       urb[URB_DBG_IN].type = USBDEVFS_URB_TYPE_INTERRUPT;
432       urb[URB_DBG_IN].endpoint = dev.ifaces[1].ep_in;
433       urb[URB_DBG_IN].buffer = buf_dbg;
434       urb[URB_DBG_IN].buffer_length = sizeof(buf_dbg) - 1;
435
436       ret = ioctl(dev.fd, USBDEVFS_SUBMITURB, &urb[URB_DBG_IN]);
437       if (ret != 0) {
438         perror("USBDEVFS_SUBMITURB URB_DBG_IN");
439         return 1;
440       }
441       dbg_in_sent = 1;
442     }
443
444     FD_ZERO(&rfds);
445     for (i = 0; i < evdev_fd_cnt; i++)
446       FD_SET(evdev_fds[i], &rfds);
447
448     FD_ZERO(&wfds);
449     FD_SET(dev.fd, &wfds);
450
451     ret = select(dev.fd + 1, &rfds, &wfds, NULL, NULL);
452     if (ret < 0) {
453       perror("select");
454       return 1;
455     }
456
457     /* something from input devices? */
458     fixed_input_changed = 0;
459     for (i = 0; i < evdev_fd_cnt; i++) {
460       if (FD_ISSET(evdev_fds[i], &rfds)) {
461         fixed_input_changed |=
462           do_evdev_input(evdev_fds[i]);
463       }
464     }
465
466     /* something from USB? */
467     if (FD_ISSET(dev.fd, &wfds)) {
468       reaped_urb = NULL;
469       ret = ioctl(dev.fd, USBDEVFS_REAPURB, &reaped_urb);
470       if (ret != 0) {
471         if (errno == ENODEV)
472           goto dev_close;
473         perror("USBDEVFS_REAPURB");
474         return 1;
475       }
476
477       if (reaped_urb != NULL && reaped_urb->status != 0) {
478         errno = -reaped_urb->status;
479         perror("urb status");
480         if (reaped_urb->status == -EILSEQ) {
481           /* this is usually a sign of disconnect.. */
482           usleep(250000);
483           goto dev_close;
484         }
485       }
486
487       if (reaped_urb == &urb[URB_DATA_IN]) {
488         printf("*data*\n");
489         data_in_sent = 0;
490       }
491       if (reaped_urb == &urb[URB_DATA_OUT]) {
492       }
493       else if (reaped_urb == &urb[URB_DBG_IN]) {
494         /* debug text */
495         buf_dbg[reaped_urb->actual_length] = 0;
496         printf("%s", buf_dbg);
497         dbg_in_sent = 0;
498       }
499       else {
500         fprintf(stderr, "reaped unknown urb? %p\n", reaped_urb);
501       }
502     }
503
504     /* something to send? */
505     if (fixed_input_changed) {
506       memset(buf_out, 0, sizeof(buf_out));
507       memcpy(buf_out, fixed_input_state, sizeof(fixed_input_state));
508
509       memset(&urb[URB_DATA_OUT], 0, sizeof(urb[URB_DATA_OUT]));
510       urb[URB_DATA_OUT].type = USBDEVFS_URB_TYPE_INTERRUPT;
511       urb[URB_DATA_OUT].endpoint = dev.ifaces[0].ep_out;
512       urb[URB_DATA_OUT].buffer = buf_out;
513       urb[URB_DATA_OUT].buffer_length = sizeof(buf_out);
514
515       ret = ioctl(dev.fd, USBDEVFS_SUBMITURB, &urb[URB_DATA_OUT]);
516       if (ret != 0) {
517         perror("USBDEVFS_SUBMITURB URB_DATA_OUT");
518         return 1;
519       }
520     }
521
522     continue;
523
524 dev_close:
525     close(dev.fd);
526     dev.fd = -1;
527   }
528
529   return 0;
530 }
531
532 // vim: ts=2:sw=2:expandtab