starting host program
[teensytas.git] / host / main.c
CommitLineData
932302ef 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
22static int g_quit;
23
24static 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
48struct 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 */
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
265enum my_urbs {
266 URB_DATA_IN,
267 URB_DATA_OUT,
268 URB_DBG_IN,
269 URB_CNT
270};
271
272int 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
381dev_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