932302ef |
1 | #include <stdio.h> |
932302ef |
2 | #include <string.h> |
3 | #include <stdint.h> |
932302ef |
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> |
f359b935 |
11 | #include <signal.h> |
12 | #include <termios.h> |
932302ef |
13 | #include <errno.h> |
14 | #include <linux/usbdevice_fs.h> |
15 | #include <linux/usb/ch9.h> |
1cb2822f |
16 | #include <linux/input.h> |
f20de073 |
17 | #include "../pkts.h" |
932302ef |
18 | |
19 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) |
20 | |
932302ef |
21 | struct teensy_dev { |
22 | int fd; |
23 | struct { |
24 | int ep_in; |
25 | int ep_out; |
26 | } ifaces[2]; |
27 | }; |
28 | |
29 | /* return 1 if founf, 0 if not, < 0 on error */ |
30 | static int find_device(struct teensy_dev *dev, |
31 | uint16_t vendor, uint16_t product) |
32 | { |
33 | const char path_root[] = "/dev/bus/usb"; |
34 | union { |
35 | struct usb_descriptor_header hdr; |
36 | struct usb_device_descriptor d; |
37 | struct usb_config_descriptor c; |
38 | struct usb_interface_descriptor i; |
39 | struct usb_endpoint_descriptor e; |
40 | char space[0x100]; /* enough? */ |
41 | } desc; |
42 | char path_bus[256], path_dev[256]; |
43 | struct dirent *ent, *ent_bus; |
44 | DIR *dir = NULL, *dir_bus = NULL; |
45 | int num, fd = -1; |
46 | int iface = -1; |
47 | int retval = -1; |
48 | int ret; |
49 | |
50 | memset(dev, 0xff, sizeof(*dev)); |
51 | |
52 | dir = opendir(path_root); |
53 | if (dir == NULL) { |
54 | perror("opendir"); |
55 | return -1; |
56 | } |
57 | |
58 | for (ent = readdir(dir); ent != NULL; ent = readdir(dir)) { |
59 | /* should be a number like 000 */ |
60 | if (sscanf(ent->d_name, "%03d", &num) != 1) |
61 | continue; |
62 | |
63 | snprintf(path_bus, sizeof(path_bus), "%s/%s", |
64 | path_root, ent->d_name); |
65 | |
66 | dir_bus = opendir(path_bus); |
67 | if (dir_bus == NULL) |
68 | continue; |
69 | |
70 | ent_bus = readdir(dir_bus); |
71 | for (; ent_bus != NULL; ent_bus = readdir(dir_bus)) { |
72 | if (sscanf(ent->d_name, "%03d", &num) != 1) |
73 | continue; |
74 | |
75 | snprintf(path_dev, sizeof(path_dev), "%s/%s/%s", |
76 | path_root, ent->d_name, ent_bus->d_name); |
77 | |
78 | fd = open(path_dev, O_RDWR); |
79 | if (fd == -1) |
80 | continue; |
81 | |
82 | ret = read(fd, &desc.d, sizeof(desc.d)); |
83 | if (ret != sizeof(desc.d)) { |
84 | fprintf(stderr, "desc read: %d/%zd: ", ret, sizeof(desc.d)); |
85 | perror(""); |
86 | goto next; |
87 | } |
88 | |
89 | if (desc.d.bDescriptorType != USB_DT_DEVICE) { |
90 | fprintf(stderr, "%s: bad DT: 0x%02x\n", |
91 | path_dev, desc.d.bDescriptorType); |
92 | goto next; |
93 | } |
94 | |
95 | if (desc.d.idVendor == vendor && desc.d.idProduct == product) |
96 | goto found; |
97 | |
98 | next: |
99 | close(fd); |
100 | fd = -1; |
101 | } |
102 | |
103 | closedir(dir_bus); |
104 | dir_bus = NULL; |
105 | } |
106 | |
107 | /* not found */ |
108 | retval = 0; |
109 | goto out; |
110 | |
111 | found: |
112 | if (desc.d.bNumConfigurations != 1) { |
113 | fprintf(stderr, "unexpected bNumConfigurations: %u\n", |
114 | desc.d.bNumConfigurations); |
115 | goto out; |
116 | } |
117 | |
118 | /* walk through all descriptors */ |
119 | while (1) |
120 | { |
121 | ret = read(fd, &desc.hdr, sizeof(desc.hdr)); |
122 | if (ret == 0) |
123 | break; |
124 | if (ret != sizeof(desc.hdr)) { |
125 | fprintf(stderr, "desc.hdr read: %d/%zd: ", ret, sizeof(desc.hdr)); |
126 | perror(""); |
127 | break; |
128 | } |
129 | |
130 | ret = (int)lseek(fd, -sizeof(desc.hdr), SEEK_CUR); |
131 | if (ret == -1) { |
132 | perror("lseek"); |
133 | break; |
134 | } |
135 | |
136 | ret = read(fd, &desc, desc.hdr.bLength); |
137 | if (ret != desc.hdr.bLength) { |
138 | fprintf(stderr, "desc read: %d/%u: ", ret, desc.hdr.bLength); |
139 | perror(""); |
140 | break; |
141 | } |
142 | |
143 | switch (desc.hdr.bDescriptorType) { |
144 | case USB_DT_CONFIG: |
145 | if (desc.c.bNumInterfaces != 2) { |
146 | fprintf(stderr, "unexpected bNumInterfaces: %u\n", |
147 | desc.c.bNumInterfaces); |
148 | goto out; |
149 | } |
150 | break; |
151 | |
152 | case USB_DT_INTERFACE: |
153 | if (desc.i.bInterfaceClass != USB_CLASS_HID |
154 | || desc.i.bInterfaceSubClass != 0 |
155 | || desc.i.bInterfaceProtocol != 0) { |
156 | fprintf(stderr, "unexpected interface %x:%x:%x\n", |
157 | desc.i.bInterfaceClass, desc.i.bInterfaceSubClass, |
158 | desc.i.bInterfaceProtocol); |
159 | goto out; |
160 | } |
161 | if (desc.i.bNumEndpoints != 2) { |
162 | fprintf(stderr, "unexpected bNumEndpoints: %u\n", |
163 | desc.i.bNumEndpoints); |
164 | goto out; |
165 | } |
166 | iface++; |
167 | break; |
168 | |
169 | case USB_DT_ENDPOINT: |
170 | if (iface < 0 || iface >= ARRAY_SIZE(dev->ifaces)) { |
171 | fprintf(stderr, "bad iface: %d\n", iface); |
172 | goto out; |
173 | } |
174 | if (desc.e.wMaxPacketSize != 64 && desc.e.wMaxPacketSize != 32) { |
175 | fprintf(stderr, "iface %d, EP %02x: " |
176 | "unexpected wMaxPacketSize: %u\n", |
177 | iface, desc.e.bEndpointAddress, desc.e.wMaxPacketSize); |
178 | goto out; |
179 | } |
180 | if (desc.e.bEndpointAddress & 0x80) |
181 | dev->ifaces[iface].ep_in = desc.e.bEndpointAddress; // & 0x7F; |
182 | else |
183 | dev->ifaces[iface].ep_out = desc.e.bEndpointAddress; |
184 | break; |
185 | |
186 | case 0x21: |
187 | /* ignore */ |
188 | break; |
189 | |
190 | default: |
191 | fprintf(stderr, "skipping desc 0x%02x\n", |
192 | desc.hdr.bDescriptorType); |
193 | break; |
194 | } |
195 | } |
196 | |
197 | /* claim interfaces */ |
198 | for (iface = 0; iface < ARRAY_SIZE(dev->ifaces); iface++) { |
199 | struct usbdevfs_ioctl usbio; |
200 | |
201 | if (dev->ifaces[iface].ep_in == -1) { |
202 | fprintf(stderr, "missing ep_in, iface: %d\n", iface); |
203 | goto out; |
204 | } |
205 | if (dev->ifaces[iface].ep_out == -1) { |
206 | fprintf(stderr, "missing ep_out, iface: %d\n", iface); |
207 | goto out; |
208 | } |
209 | |
210 | /* disconnect default driver */ |
211 | memset(&usbio, 0, sizeof(usbio)); |
212 | usbio.ifno = iface; |
213 | usbio.ioctl_code = USBDEVFS_DISCONNECT; |
214 | ret = ioctl(fd, USBDEVFS_IOCTL, &usbio); |
215 | if (ret != 0 && errno != ENODATA) |
216 | perror("USBDEVFS_DISCONNECT"); |
217 | |
218 | ret = ioctl(fd, USBDEVFS_CLAIMINTERFACE, &iface); |
219 | if (ret != 0) |
220 | perror("USBDEVFS_CLAIMINTERFACE"); |
221 | } |
222 | |
223 | dev->fd = fd; |
224 | fd = -1; |
225 | retval = 1; |
226 | |
227 | out: |
228 | if (fd != -1) |
229 | close(fd); |
230 | if (dir_bus != NULL) |
231 | closedir(dir_bus); |
232 | if (dir != NULL) |
233 | closedir(dir); |
234 | |
235 | return retval; |
236 | } |
237 | |
f359b935 |
238 | static int enable_echo(int enable) |
239 | { |
240 | const char *portname = "/dev/tty"; |
241 | struct termios tty; |
242 | int retval = -1; |
243 | int ret; |
244 | int fd; |
245 | |
246 | memset(&tty, 0, sizeof(tty)); |
247 | |
248 | fd = open(portname, O_RDWR | O_NOCTTY | O_SYNC); |
249 | if (fd < 0) { |
250 | fprintf(stderr, "open %s: ", portname); |
251 | perror(""); |
252 | return 1; |
253 | } |
254 | |
255 | ret = tcgetattr(fd, &tty); |
256 | if (ret != 0) { |
257 | perror("tcgetattr"); |
258 | goto out; |
259 | } |
260 | |
261 | // printf("lflag: 0%o\n", tty.c_lflag); |
262 | if (enable) |
263 | tty.c_lflag |= ECHO; |
264 | else |
265 | tty.c_lflag &= ~ECHO; |
266 | |
267 | ret = tcsetattr(fd, TCSANOW, &tty); |
268 | if (ret != 0) { |
269 | perror("tcsetattr"); |
270 | goto out; |
271 | } |
272 | |
273 | retval = 0; |
274 | out: |
275 | close(fd); |
276 | |
277 | return retval; |
278 | } |
279 | |
280 | static void signal_handler(int sig) |
281 | { |
282 | enable_echo(1); |
283 | signal(sig, SIG_DFL); |
284 | raise(sig); |
285 | } |
286 | |
1cb2822f |
287 | /* ?0SA 00DU, ?1CB RLDU */ |
288 | #define STATE_BYTES 2 |
289 | |
290 | static uint8_t fixed_input_state[STATE_BYTES] = { 0x33, 0x3f }; |
291 | |
292 | enum mdbtn { |
293 | MDBTN_UP = 1, |
294 | MDBTN_DOWN, |
295 | MDBTN_LEFT, |
296 | MDBTN_RIGHT, |
297 | MDBTN_A, |
298 | MDBTN_B, |
299 | MDBTN_C, |
300 | MDBTN_START, |
301 | }; |
302 | |
303 | static const enum mdbtn evdev_md_map[KEY_CNT] = { |
304 | [KEY_UP] = MDBTN_UP, |
305 | [KEY_DOWN] = MDBTN_DOWN, |
306 | [KEY_LEFT] = MDBTN_LEFT, |
307 | [KEY_RIGHT] = MDBTN_RIGHT, |
308 | [KEY_HOME] = MDBTN_A, |
309 | [KEY_PAGEDOWN] = MDBTN_B, |
310 | [KEY_END] = MDBTN_C, |
311 | [KEY_LEFTALT] = MDBTN_START, |
312 | }; |
313 | |
314 | int do_evdev_input(int fd) |
315 | { |
316 | uint8_t old_state[STATE_BYTES]; |
317 | uint8_t changed_bits[STATE_BYTES] = { 0, }; |
318 | struct input_event ev; |
319 | enum mdbtn mdbtn; |
320 | int i, ret; |
321 | |
322 | ret = read(fd, &ev, sizeof(ev)); |
323 | if (ret != sizeof(ev)) { |
324 | fprintf(stderr, "evdev read %d/%zd: ", ret, sizeof(ev)); |
325 | perror(""); |
326 | return 0; |
327 | } |
328 | |
329 | if (ev.type != EV_KEY) |
330 | return 0; |
331 | |
332 | if (ev.value != 0 && ev.value != 1) |
333 | return 0; |
334 | |
335 | if ((uint32_t)ev.code >= ARRAY_SIZE(evdev_md_map)) { |
336 | fprintf(stderr, "evdev read bad key: %u\n", ev.code); |
337 | return 0; |
338 | } |
339 | |
340 | mdbtn = evdev_md_map[ev.code]; |
341 | if (mdbtn == 0) |
342 | return 0; |
343 | |
344 | memcpy(old_state, fixed_input_state, STATE_BYTES); |
345 | |
346 | /* ?0SA 00DU, ?1CB RLDU */ |
347 | switch (mdbtn) { |
348 | case MDBTN_UP: |
349 | changed_bits[0] = 0x01; |
350 | changed_bits[1] = 0x01; |
351 | break; |
352 | case MDBTN_DOWN: |
353 | changed_bits[0] = 0x02; |
354 | changed_bits[1] = 0x02; |
355 | break; |
356 | case MDBTN_LEFT: |
357 | changed_bits[0] = 0x00; |
358 | changed_bits[1] = 0x04; |
359 | break; |
360 | case MDBTN_RIGHT: |
361 | changed_bits[0] = 0x00; |
362 | changed_bits[1] = 0x08; |
363 | break; |
364 | case MDBTN_A: |
365 | changed_bits[0] = 0x10; |
366 | changed_bits[1] = 0x00; |
367 | break; |
368 | case MDBTN_B: |
369 | changed_bits[0] = 0x00; |
370 | changed_bits[1] = 0x10; |
371 | break; |
372 | case MDBTN_C: |
373 | changed_bits[0] = 0x00; |
374 | changed_bits[1] = 0x20; |
375 | break; |
376 | case MDBTN_START: |
377 | changed_bits[0] = 0x20; |
378 | changed_bits[1] = 0x00; |
379 | break; |
380 | } |
381 | |
382 | if (ev.value) { |
383 | // key press |
384 | for (i = 0; i < STATE_BYTES; i++) |
385 | fixed_input_state[i] &= ~changed_bits[i]; |
386 | } |
387 | else { |
388 | // key release |
389 | for (i = 0; i < STATE_BYTES; i++) |
390 | fixed_input_state[i] |= changed_bits[i]; |
391 | } |
392 | |
393 | return memcmp(old_state, fixed_input_state, STATE_BYTES) ? 1 : 0; |
394 | } |
395 | |
f20de073 |
396 | struct gmv_tas { |
397 | char sig[15]; |
398 | char ver; |
399 | uint32_t rerecord_count; |
400 | char ctrl1; |
401 | char ctrl2; |
402 | uint16_t flags; |
403 | char name[40]; |
404 | uint8_t data[0][3]; |
405 | }; |
406 | |
407 | static int submit_urb(int fd, struct usbdevfs_urb *urb, int ep, |
408 | void *buf, size_t buf_size) |
409 | { |
410 | memset(urb, 0, sizeof(*urb)); |
411 | urb->type = USBDEVFS_URB_TYPE_INTERRUPT; |
412 | urb->endpoint = ep; |
413 | urb->buffer = buf; |
414 | urb->buffer_length = buf_size; |
415 | |
416 | return ioctl(fd, USBDEVFS_SUBMITURB, urb); |
417 | } |
418 | |
932302ef |
419 | enum my_urbs { |
420 | URB_DATA_IN, |
421 | URB_DATA_OUT, |
422 | URB_DBG_IN, |
423 | URB_CNT |
424 | }; |
425 | |
426 | int main(int argc, char *argv[]) |
427 | { |
f20de073 |
428 | const char *tasfn = NULL; |
932302ef |
429 | struct teensy_dev dev; |
430 | struct usbdevfs_urb urb[URB_CNT]; |
431 | struct usbdevfs_urb *reaped_urb; |
1cb2822f |
432 | int fixed_input_changed; |
433 | int evdev_fds[16]; |
434 | int evdev_fd_cnt = 0; |
435 | int evdev_support; |
932302ef |
436 | int wait_device = 0; |
437 | int dbg_in_sent = 0; |
438 | int data_in_sent = 0; |
1cb2822f |
439 | fd_set rfds, wfds; |
f20de073 |
440 | struct gmv_tas *gmv = NULL; |
441 | int enable_sent = 0; |
442 | int frame_count = 0; |
443 | int frames_sent = 0; |
444 | char buf_dbg[64 + 1]; |
445 | struct tas_pkt pkt_in; |
446 | struct tas_pkt pkt_out; |
447 | struct timeval *timeout = NULL; |
448 | struct timeval tout; |
1cb2822f |
449 | int i, ret; |
450 | int fd; |
451 | |
452 | for (i = 1; i < argc; i++) { |
f20de073 |
453 | if (argv[i][0] == '-') { |
454 | if (strcmp(argv[i], "-m") != 0) { |
455 | fprintf(stderr, "bad arg: %s\n", argv[i]); |
456 | return 1; |
457 | } |
458 | i++; |
459 | if (argv[i] == NULL) { |
460 | fprintf(stderr, "missing arg\n"); |
461 | return 1; |
462 | } |
463 | tasfn = argv[i]; |
464 | continue; |
465 | } |
1cb2822f |
466 | if (evdev_fd_cnt >= ARRAY_SIZE(evdev_fds)) { |
467 | fprintf(stderr, "too many evdevs\n"); |
468 | break; |
469 | } |
f20de073 |
470 | fd = open(argv[i], O_RDONLY); |
1cb2822f |
471 | if (fd == -1) { |
472 | fprintf(stderr, "open %s: ", argv[i]); |
473 | perror(""); |
474 | continue; |
475 | } |
476 | evdev_support = 0; |
f20de073 |
477 | ret = ioctl(fd, EVIOCGBIT(0, sizeof(evdev_support)), |
1cb2822f |
478 | &evdev_support); |
479 | if (ret < 0) |
480 | perror("EVIOCGBIT"); |
481 | if (!(evdev_support & (1 << EV_KEY))) { |
482 | fprintf(stderr, "%s doesn't have keys\n", argv[i]); |
483 | close(fd); |
484 | continue; |
485 | } |
486 | evdev_fds[evdev_fd_cnt++] = fd; |
487 | } |
932302ef |
488 | |
f20de073 |
489 | if (tasfn != NULL) { |
490 | long size; |
491 | FILE *f; |
492 | |
493 | f = fopen(tasfn, "rb"); |
494 | if (f == NULL) { |
495 | fprintf(stderr, "fopen %s: ", tasfn); |
496 | perror(""); |
497 | return 1; |
498 | } |
499 | |
500 | fseek(f, 0, SEEK_END); |
501 | size = ftell(f); |
502 | fseek(f, 0, SEEK_SET); |
503 | if (size < (long)sizeof(*gmv)) { |
504 | fprintf(stderr, "bad gmv size: %ld\n", size); |
505 | return 1; |
506 | } |
507 | gmv = malloc(size); |
508 | if (gmv == NULL) { |
509 | fprintf(stderr, "OOM?\n"); |
510 | return 1; |
511 | } |
512 | ret = fread(gmv, 1, size, f); |
513 | if (ret != size) { |
514 | fprintf(stderr, "fread %d/%ld: ", ret, size); |
515 | perror(""); |
516 | return 1; |
517 | } |
518 | fclose(f); |
519 | frame_count = (size - sizeof(*gmv)) / 3; |
520 | |
521 | /* check the GMV.. */ |
522 | if (frame_count <= 0 || size != sizeof(*gmv) + frame_count * 3) { |
523 | fprintf(stderr, "broken gmv? frames=%d\n", frame_count); |
524 | return 1; |
525 | } |
526 | |
527 | if (strncmp(gmv->sig, "Gens Movie TEST", 15) != 0) { |
528 | fprintf(stderr, "bad GMV sig\n"); |
529 | return 1; |
530 | } |
531 | if (gmv->ctrl1 != '3') { |
532 | fprintf(stderr, "unhandled controlled config: '%c'\n", gmv->ctrl1); |
533 | //return 1; |
534 | } |
535 | if (gmv->ver >= 'A') { |
536 | if (gmv->flags & 0x40) { |
537 | fprintf(stderr, "unhandled flag: movie requires a savestate\n"); |
538 | return 1; |
539 | } |
540 | if (gmv->flags & 0x20) { |
541 | fprintf(stderr, "unhandled flag: 3-player movie\n"); |
542 | return 1; |
543 | } |
544 | if (gmv->flags & ~0x80) { |
545 | fprintf(stderr, "unhandled flag(s): %04x\n", gmv->flags); |
546 | //return 1; |
547 | } |
548 | } |
549 | gmv->name[39] = 0; |
550 | printf("loaded GMV: %s\n", gmv->name); |
551 | printf("%d frames, %u rerecords\n", |
552 | frame_count, gmv->rerecord_count); |
553 | } |
554 | |
f359b935 |
555 | enable_echo(0); |
556 | signal(SIGINT, signal_handler); |
557 | |
932302ef |
558 | dev.fd = -1; |
559 | |
560 | while (1) |
561 | { |
562 | if (dev.fd == -1) { |
563 | ret = find_device(&dev, 0x16C0, 0x0486); |
564 | if (ret < 0) |
f359b935 |
565 | break; |
932302ef |
566 | |
567 | if (ret == 0) { |
568 | if (!wait_device) { |
569 | printf("waiting for device..\n"); |
570 | wait_device = 1; |
571 | } |
572 | usleep(250000); |
573 | continue; |
574 | } |
575 | |
576 | wait_device = 0; |
577 | data_in_sent = 0; |
578 | dbg_in_sent = 0; |
f20de073 |
579 | enable_sent = 0; |
580 | frames_sent = 0; |
581 | |
582 | /* we wait first, then send commands, but if teensy |
583 | * is started already, it won't send anything */ |
584 | tout.tv_sec = 1; |
585 | tout.tv_usec = 0; |
586 | timeout = &tout; |
932302ef |
587 | } |
588 | |
589 | if (!data_in_sent) { |
f20de073 |
590 | memset(&pkt_in, 0, sizeof(pkt_in)); |
591 | ret = submit_urb(dev.fd, &urb[URB_DATA_IN], dev.ifaces[0].ep_in, |
592 | &pkt_in, sizeof(pkt_in)); |
932302ef |
593 | if (ret != 0) { |
594 | perror("USBDEVFS_SUBMITURB URB_DATA_IN"); |
f359b935 |
595 | break; |
932302ef |
596 | } |
f20de073 |
597 | |
932302ef |
598 | data_in_sent = 1; |
599 | } |
600 | if (!dbg_in_sent) { |
f20de073 |
601 | ret = submit_urb(dev.fd, &urb[URB_DBG_IN], dev.ifaces[1].ep_in, |
602 | buf_dbg, sizeof(buf_dbg) - 1); |
932302ef |
603 | if (ret != 0) { |
604 | perror("USBDEVFS_SUBMITURB URB_DBG_IN"); |
f359b935 |
605 | break; |
932302ef |
606 | } |
f20de073 |
607 | |
932302ef |
608 | dbg_in_sent = 1; |
609 | } |
610 | |
1cb2822f |
611 | FD_ZERO(&rfds); |
612 | for (i = 0; i < evdev_fd_cnt; i++) |
613 | FD_SET(evdev_fds[i], &rfds); |
614 | |
932302ef |
615 | FD_ZERO(&wfds); |
616 | FD_SET(dev.fd, &wfds); |
617 | |
f20de073 |
618 | ret = select(dev.fd + 1, &rfds, &wfds, NULL, timeout); |
932302ef |
619 | if (ret < 0) { |
620 | perror("select"); |
f359b935 |
621 | break; |
932302ef |
622 | } |
f20de073 |
623 | timeout = NULL; |
932302ef |
624 | |
1cb2822f |
625 | /* something from input devices? */ |
626 | fixed_input_changed = 0; |
627 | for (i = 0; i < evdev_fd_cnt; i++) { |
628 | if (FD_ISSET(evdev_fds[i], &rfds)) { |
629 | fixed_input_changed |= |
630 | do_evdev_input(evdev_fds[i]); |
631 | } |
632 | } |
633 | |
634 | /* something from USB? */ |
f20de073 |
635 | if (FD_ISSET(dev.fd, &wfds)) |
636 | { |
932302ef |
637 | reaped_urb = NULL; |
638 | ret = ioctl(dev.fd, USBDEVFS_REAPURB, &reaped_urb); |
639 | if (ret != 0) { |
640 | if (errno == ENODEV) |
641 | goto dev_close; |
642 | perror("USBDEVFS_REAPURB"); |
f359b935 |
643 | break; |
932302ef |
644 | } |
645 | |
646 | if (reaped_urb != NULL && reaped_urb->status != 0) { |
647 | errno = -reaped_urb->status; |
f20de073 |
648 | if ((unsigned long)(reaped_urb - urb) < ARRAY_SIZE(urb)) |
649 | fprintf(stderr, "urb #%zu: ", reaped_urb - urb); |
650 | else |
651 | fprintf(stderr, "unknown urb: "); |
652 | perror(""); |
932302ef |
653 | if (reaped_urb->status == -EILSEQ) { |
654 | /* this is usually a sign of disconnect.. */ |
655 | usleep(250000); |
656 | goto dev_close; |
657 | } |
658 | } |
659 | |
660 | if (reaped_urb == &urb[URB_DATA_IN]) { |
f20de073 |
661 | /* some request from teensy */ |
662 | int count; |
663 | uint8_t b; |
664 | |
665 | switch (pkt_in.type) { |
666 | case PKT_STREAM_REQ: |
667 | printf("%d/%d\n", frames_sent, frame_count); |
668 | |
669 | for (i = 0; i < sizeof(pkt_out.data); i++) { |
670 | pkt_out.data[i * 2 + 0] = 0x33; |
671 | pkt_out.data[i * 2 + 1] = 0x3f; |
672 | } |
673 | if (frames_sent < frame_count) { |
674 | pkt_out.type = PKT_STREAM_DATA; |
675 | |
676 | count = frame_count - frames_sent; |
677 | if (count > sizeof(pkt_out.data) / 2) |
678 | count = sizeof(pkt_out.data) / 2; |
679 | for (i = 0; i < count; i++) { |
680 | /* SCBA RLDU */ |
681 | b = gmv->data[frames_sent][0]; |
682 | |
683 | /* ?0SA 00DU, ?1CB RLDU */ |
684 | pkt_out.data[i * 2 + 0] = (b & 0x13) | ((b >> 2) & 0x20); |
685 | pkt_out.data[i * 2 + 1] = (b & 0x0f) | ((b >> 1) & 0x30); |
686 | |
687 | if (gmv->data[frames_sent][1] != 0xff |
688 | || gmv->data[frames_sent][2] != 0xff) |
689 | { |
690 | fprintf(stderr, "f %d: unhandled byte(s) %02x %02x\n", |
691 | frames_sent, gmv->data[frames_sent][1], |
692 | gmv->data[frames_sent][2]); |
693 | } |
694 | |
695 | frames_sent++; |
696 | } |
697 | } |
698 | else |
699 | pkt_out.type = PKT_STREAM_END; |
700 | |
701 | ret = submit_urb(dev.fd, &urb[URB_DATA_OUT], |
702 | dev.ifaces[0].ep_out, &pkt_out, sizeof(pkt_out)); |
703 | if (ret != 0) |
704 | perror("USBDEVFS_SUBMITURB URB_DATA_OUT PKT_STREAM_DATA"); |
705 | break; |
706 | |
707 | default: |
708 | printf("host: got unknown pkt type: %04x\n", pkt_in.type); |
709 | break; |
710 | } |
711 | |
932302ef |
712 | data_in_sent = 0; |
713 | } |
f20de073 |
714 | else if (reaped_urb == &urb[URB_DATA_OUT]) { |
1cb2822f |
715 | } |
932302ef |
716 | else if (reaped_urb == &urb[URB_DBG_IN]) { |
717 | /* debug text */ |
718 | buf_dbg[reaped_urb->actual_length] = 0; |
719 | printf("%s", buf_dbg); |
720 | dbg_in_sent = 0; |
721 | } |
722 | else { |
f20de073 |
723 | fprintf(stderr, "reaped unknown urb? %p #%zu\n", |
724 | reaped_urb, reaped_urb - urb); |
932302ef |
725 | } |
726 | } |
1cb2822f |
727 | |
728 | /* something to send? */ |
f20de073 |
729 | if (gmv != NULL && !enable_sent) { |
730 | memset(&pkt_out, 0, sizeof(pkt_out)); |
731 | pkt_out.type = PKT_STREAM_ENABLE; |
732 | ret = submit_urb(dev.fd, &urb[URB_DATA_OUT], dev.ifaces[0].ep_out, |
733 | &pkt_out, sizeof(pkt_out)); |
734 | if (ret != 0) { |
735 | perror("USBDEVFS_SUBMITURB PKT_STREAM_ENABLE"); |
736 | continue; |
737 | } |
738 | enable_sent = 1; |
739 | } |
740 | if (gmv == NULL && fixed_input_changed) { |
741 | memset(&pkt_out, 0, sizeof(pkt_out)); |
742 | pkt_out.type = PKT_FIXED_STATE; |
743 | memcpy(pkt_out.data, fixed_input_state, sizeof(fixed_input_state)); |
1cb2822f |
744 | |
f20de073 |
745 | ret = submit_urb(dev.fd, &urb[URB_DATA_OUT], dev.ifaces[0].ep_out, |
746 | &pkt_out, sizeof(pkt_out)); |
1cb2822f |
747 | if (ret != 0) { |
748 | perror("USBDEVFS_SUBMITURB URB_DATA_OUT"); |
f359b935 |
749 | break; |
1cb2822f |
750 | } |
751 | } |
752 | |
932302ef |
753 | continue; |
754 | |
755 | dev_close: |
756 | close(dev.fd); |
757 | dev.fd = -1; |
758 | } |
759 | |
f359b935 |
760 | enable_echo(1); |
761 | |
762 | return ret; |
932302ef |
763 | } |
764 | |
765 | // vim: ts=2:sw=2:expandtab |