starting host program
[megadrive.git] / host / main.c
1 #include <stdio.h>
2 //#include <stdlib.h>
3 #include <string.h>
4 #include <stdint.h>
5 //#include <pthread.h>
6 #include <sys/types.h>
7 #include <sys/stat.h>
8 #include <fcntl.h>
9 #include <sys/ioctl.h>
10 #include <sys/select.h>
11 #include <unistd.h>
12 #include <dirent.h>
13 #include <errno.h>
14 #include <linux/usbdevice_fs.h>
15 #include <linux/usb/ch9.h>
16
17 #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
18
19 #if 0
20 #include "rawhid/hid.h"
21
22 static int g_quit;
23
24 static void *dbg_reader(void *arg)
25 {
26         char buf[65];
27         int ret;
28
29         buf[64] = 0;
30
31         while (!g_quit) {
32                 ret = rawhid_recv(0, buf, 64, 1000);
33                 if (ret == 0)
34                         continue;
35
36                 if (ret != 64) {
37                         printf("\nrawhid_recv(dbg): %d\n", ret);
38                         return NULL;
39                 }
40                 printf("%s", buf);
41         }
42
43         // rawhid_close(0);
44         return NULL;
45 }
46 #endif
47
48 struct teensy_dev {
49   int fd;
50   struct {
51     int ep_in;
52     int ep_out;
53   } ifaces[2];
54 };
55
56 /* return 1 if founf, 0 if not, < 0 on error */
57 static 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
125 next:
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
138 found:
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
254 out:
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
265 enum my_urbs {
266   URB_DATA_IN,
267   URB_DATA_OUT,
268   URB_DBG_IN,
269   URB_CNT
270 };
271
272 int main(int argc, char *argv[])
273 {
274   struct teensy_dev dev;
275   struct usbdevfs_urb urb[URB_CNT];
276   struct usbdevfs_urb *reaped_urb;
277   char buf_dbg[64 + 1], buf_in[64];
278   int wait_device = 0;
279   int dbg_in_sent = 0;
280   int data_in_sent = 0;
281   fd_set wfds;
282   int ret;
283
284   dev.fd = -1;
285
286   while (1)
287   {
288     if (dev.fd == -1) {
289       ret = find_device(&dev, 0x16C0, 0x0486);
290       if (ret < 0)
291         return ret;
292
293       if (ret == 0) {
294         if (!wait_device) {
295           printf("waiting for device..\n");
296           wait_device = 1;
297         }
298         usleep(250000);
299         continue;
300       }
301
302       wait_device = 0;
303       data_in_sent = 0;
304       dbg_in_sent = 0;
305     }
306
307     if (!data_in_sent) {
308       memset(&urb[URB_DATA_IN], 0, sizeof(urb[URB_DATA_IN]));
309       urb[URB_DATA_IN].type = USBDEVFS_URB_TYPE_INTERRUPT;
310       urb[URB_DATA_IN].endpoint = dev.ifaces[0].ep_in;
311       urb[URB_DATA_IN].buffer = buf_in;
312       urb[URB_DATA_IN].buffer_length = sizeof(buf_in);
313
314       ret = ioctl(dev.fd, USBDEVFS_SUBMITURB, &urb[URB_DATA_IN]);
315       if (ret != 0) {
316         perror("USBDEVFS_SUBMITURB URB_DATA_IN");
317         return 1;
318       }
319       data_in_sent = 1;
320     }
321     if (!dbg_in_sent) {
322       memset(&urb[URB_DBG_IN], 0, sizeof(urb[URB_DBG_IN]));
323       urb[URB_DBG_IN].type = USBDEVFS_URB_TYPE_INTERRUPT;
324       urb[URB_DBG_IN].endpoint = dev.ifaces[1].ep_in;
325       urb[URB_DBG_IN].buffer = buf_dbg;
326       urb[URB_DBG_IN].buffer_length = sizeof(buf_dbg) - 1;
327
328       ret = ioctl(dev.fd, USBDEVFS_SUBMITURB, &urb[URB_DBG_IN]);
329       if (ret != 0) {
330         perror("USBDEVFS_SUBMITURB URB_DBG_IN");
331         return 1;
332       }
333       dbg_in_sent = 1;
334     }
335
336     FD_ZERO(&wfds);
337     FD_SET(dev.fd, &wfds);
338
339     ret = select(dev.fd + 1, NULL, &wfds, NULL, NULL);
340     if (ret < 0) {
341       perror("select");
342       return 1;
343     }
344
345     if (FD_ISSET(dev.fd, &wfds)) {
346       reaped_urb = NULL;
347       ret = ioctl(dev.fd, USBDEVFS_REAPURB, &reaped_urb);
348       if (ret != 0) {
349         if (errno == ENODEV)
350           goto dev_close;
351         perror("USBDEVFS_REAPURB");
352         return 1;
353       }
354
355       if (reaped_urb != NULL && reaped_urb->status != 0) {
356         errno = -reaped_urb->status;
357         perror("urb status");
358         if (reaped_urb->status == -EILSEQ) {
359           /* this is usually a sign of disconnect.. */
360           usleep(250000);
361           goto dev_close;
362         }
363       }
364
365       if (reaped_urb == &urb[URB_DATA_IN]) {
366         printf("*data*\n");
367         data_in_sent = 0;
368       }
369       else if (reaped_urb == &urb[URB_DBG_IN]) {
370         /* debug text */
371         buf_dbg[reaped_urb->actual_length] = 0;
372         printf("%s", buf_dbg);
373         dbg_in_sent = 0;
374       }
375       else {
376         fprintf(stderr, "reaped unknown urb? %p\n", reaped_urb);
377       }
378     }
379     continue;
380
381 dev_close:
382     close(dev.fd);
383     dev.fd = -1;
384   }
385
386 #if 0
387   ret = rawhid_open(1, 0x16C0, 0x0486, 0xFFC9, 0x0004);
388   if (ret <= 0) {
389     fprintf(stderr, "dbg rawhid is missing\n");
390     return 1;
391   }
392
393   ret = rawhid_open(1, 0x16C0, 0x0486, 0xFFAB, 0x0200);
394   if (ret <= 0) {
395     fprintf(stderr, "data rawhid is missing\n");
396     return 1;
397   }
398
399   pthread_t thread;
400   ret = pthread_create(&thread, NULL, dbg_reader, NULL);
401   if (ret) {
402     fprintf(stderr, "pthread_create failed: %d\n", ret);
403     return 1;
404   }
405
406   memset(buf, 0, sizeof(buf));
407   snprintf(buf, sizeof(buf), "hi");
408
409   ret = rawhid_send(1, buf, 64, 220);
410   if (ret != 64) {
411     fprintf(stderr, "send failed: %d\n", ret);
412   }
413
414   while (1) {
415     // check if any Raw HID packet has arrived
416     ret = rawhid_recv(1, buf, 64, 220);
417     if (ret < 0) {
418       fprintf(stderr, "\nrawhid_recv(1): %d\n", ret);
419       break;
420     }
421     if (ret > 0) {
422       printf("\nrecv %d bytes:\n", ret);
423       for (i=0; i<ret; i++) {
424         printf("%02X ", buf[i] & 255);
425         if (i % 16 == 15 && i < ret-1) printf("\n");
426       }
427       printf("\n");
428     }
429   }
430
431   // rawhid_close(1);
432
433   g_quit = 1;
434   pthread_join(thread, NULL);
435 #endif
436
437   return 0;
438 }
439
440 // vim: ts=2:sw=2:expandtab