]> git.zerfleddert.de Git - hmcfgusb/blob - hmcfgusb.c
e3cde0f74a6897eb9009f19d23e3f25b292fcd1f
[hmcfgusb] / hmcfgusb.c
1 /* HM-CFG-USB libusb-driver
2 *
3 * Copyright (c) 2013 Michael Gernoth <michael@gernoth.net>
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21 * IN THE SOFTWARE.
22 */
23
24 #include <string.h>
25 #include <stdio.h>
26 #include <stdint.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <math.h>
30 #include <poll.h>
31 #include <errno.h>
32 #include <sys/time.h>
33 #include <libusb-1.0/libusb.h>
34
35 /* Workaround for old libusb-1.0 */
36 #ifndef LIBUSB_CALL
37 #define LIBUSB_CALL
38 #define libusb_handle_events_timeout_completed(ctx, tv, x) libusb_handle_events_timeout(ctx, tv)
39 #endif
40
41 #include "hexdump.h"
42 #include "hmcfgusb.h"
43
44 #define USB_TIMEOUT 10000
45
46 #define ID_VENDOR 0x1b1f
47 #define ID_PRODUCT 0xc00f
48 #define ID_PRODUCT_BL 0xc010
49
50 /* TODO: dynamic */
51 #define ASYNC_SIZE 0x0040
52 #define ASYNC_INTERVAL 32
53
54 #define EP_OUT 0x02
55 #define EP_IN 0x83
56
57 #define INTERFACE 0
58
59 static int quit = 0;
60 static int debug = 0;
61 static int libusb_initialized = 0;
62
63 /* Not in all libusb-1.0 versions, so we have to roll our own :-( */
64 static char * usb_strerror(int e)
65 {
66 static char unknerr[256];
67
68 switch (e) {
69 case LIBUSB_SUCCESS:
70 return "Success";
71 case LIBUSB_ERROR_IO:
72 return "Input/output error";
73 case LIBUSB_ERROR_INVALID_PARAM:
74 return "Invalid parameter";
75 case LIBUSB_ERROR_ACCESS:
76 return "Access denied (insufficient permissions)";
77 case LIBUSB_ERROR_NO_DEVICE:
78 return "No such device (it may have been disconnected)";
79 case LIBUSB_ERROR_NOT_FOUND:
80 return "Entity not found";
81 case LIBUSB_ERROR_BUSY:
82 return "Resource busy";
83 case LIBUSB_ERROR_TIMEOUT:
84 return "Operation timed out";
85 case LIBUSB_ERROR_OVERFLOW:
86 return "Overflow";
87 case LIBUSB_ERROR_PIPE:
88 return "Pipe error";
89 case LIBUSB_ERROR_INTERRUPTED:
90 return "System call interrupted (perhaps due to signal)";
91 case LIBUSB_ERROR_NO_MEM:
92 return "Insufficient memory";
93 case LIBUSB_ERROR_NOT_SUPPORTED:
94 return "Operation not supported or unimplemented on this platform";
95 case LIBUSB_ERROR_OTHER:
96 return "Other error";
97 };
98 snprintf(unknerr, sizeof(unknerr), "Unknown error code %d / 0x%02x", e, e);
99 return unknerr;
100 }
101
102 static libusb_device_handle *hmcfgusb_find(int vid, int pid) {
103 libusb_device_handle *devh = NULL;
104 libusb_device **list;
105 ssize_t cnt;
106 ssize_t i;
107 int err;
108
109 cnt = libusb_get_device_list(NULL, &list);
110 if (cnt < 0) {
111 fprintf(stderr, "Can't get USB device list: %d\n", (int)cnt);
112 return NULL;
113 }
114
115 for (i = 0; i < cnt; i++){
116 struct libusb_device_descriptor desc;
117
118 err = libusb_get_device_descriptor(list[i], &desc);
119 if (err)
120 continue;
121
122 if ((desc.idVendor == vid) && (desc.idProduct == pid)) {
123 libusb_device *dev = list[i];
124
125 err = libusb_open(dev, &devh);
126 if (err) {
127 fprintf(stderr, "Can't open device: %s\n", usb_strerror(err));
128 libusb_free_device_list(list, 1);
129 return NULL;
130 }
131
132 err = libusb_detach_kernel_driver(devh, INTERFACE);
133 if ((err != 0) && (err != LIBUSB_ERROR_NOT_FOUND)) {
134 fprintf(stderr, "Can't detach kernel driver: %s\n", usb_strerror(err));
135 libusb_close(devh);
136 libusb_free_device_list(list, 1);
137 return NULL;
138 }
139
140 err = libusb_claim_interface(devh, INTERFACE);
141 if ((err != 0)) {
142 fprintf(stderr, "Can't claim interface: %s\n", usb_strerror(err));
143 libusb_close(devh);
144 libusb_free_device_list(list, 1);
145 return NULL;
146 }
147
148 libusb_free_device_list(list, 0);
149 return devh;
150 }
151
152 }
153
154 libusb_free_device_list(list, 1);
155 return NULL;
156 }
157
158 int hmcfgusb_send_null_frame(struct hmcfgusb_dev *usbdev, int silent)
159 {
160 int err;
161 int cnt;
162 unsigned char out[0x40];
163
164 memset(out, 0, sizeof(out));
165
166 err = libusb_interrupt_transfer(usbdev->usb_devh, EP_OUT, out, 0, &cnt, USB_TIMEOUT);
167 if (err && (!silent)) {
168 fprintf(stderr, "Can't send null frame: %s\n", usb_strerror(err));
169 return 0;
170 }
171
172 return 1;
173 }
174
175 int hmcfgusb_send(struct hmcfgusb_dev *usbdev, unsigned char* send_data, int len, int done)
176 {
177 int err;
178 int cnt;
179 struct timeval tv_start, tv_end;
180 int msec;
181
182 if (debug) {
183 hexdump(send_data, len, "USB < ");
184 }
185
186 gettimeofday(&tv_start, NULL);
187
188 err = libusb_interrupt_transfer(usbdev->usb_devh, EP_OUT, send_data, len, &cnt, USB_TIMEOUT);
189 if (err) {
190 fprintf(stderr, "Can't send data: %s\n", usb_strerror(err));
191 return 0;
192 }
193
194 if (done) {
195 if (!hmcfgusb_send_null_frame(usbdev, 0)) {
196 return 0;
197 }
198 }
199
200 gettimeofday(&tv_end, NULL);
201 msec = ((tv_end.tv_sec-tv_start.tv_sec)*1000)+((tv_end.tv_usec-tv_start.tv_usec)/1000);
202
203 if (msec > 100) {
204 fprintf(stderr, "usb-transfer took more than 100ms (%dms), this may lead to timing problems!\n", msec);
205 } else if (debug) {
206 fprintf(stderr, "usb-transfer took %dms!\n", msec);
207 }
208
209 return 1;
210 }
211
212 static struct libusb_transfer *hmcfgusb_prepare_int(libusb_device_handle *devh, libusb_transfer_cb_fn cb, void *data, int in_size)
213 {
214 unsigned char *data_buf;
215 struct libusb_transfer *transfer;
216 int err;
217
218 data_buf = malloc(in_size);
219 if (!data_buf) {
220 fprintf(stderr, "Can't allocate memory for data-buffer!\n");
221 return NULL;
222 }
223
224 transfer = libusb_alloc_transfer(0);
225 if (!transfer) {
226 fprintf(stderr, "Can't allocate memory for usb-transfer!\n");
227 free(data_buf);
228 return NULL;
229 }
230
231 libusb_fill_interrupt_transfer(transfer, devh, EP_IN,
232 data_buf, in_size, cb, data, USB_TIMEOUT);
233
234 transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER;
235
236 err = libusb_submit_transfer(transfer);
237 if (err != 0) {
238 fprintf(stderr, "Can't submit transfer: %s\n", usb_strerror(err));
239 libusb_free_transfer(transfer);
240 return NULL;
241 }
242
243 return transfer;
244 }
245
246 struct hmcfgusb_cb_data {
247 struct hmcfgusb_dev *dev;
248 hmcfgusb_cb_fn cb;
249 void *data;
250 };
251
252 static void LIBUSB_CALL hmcfgusb_interrupt(struct libusb_transfer *transfer)
253 {
254 int err;
255 struct hmcfgusb_cb_data *cb_data;
256
257 cb_data = transfer->user_data;
258
259 if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
260 if (transfer->status != LIBUSB_TRANSFER_TIMED_OUT) {
261 if (transfer->status != LIBUSB_TRANSFER_CANCELLED)
262 fprintf(stderr, "Interrupt transfer not completed: %s!\n", usb_strerror(transfer->status));
263
264 quit = EIO;
265
266 libusb_free_transfer(transfer);
267 if (cb_data) {
268 if (cb_data->dev && cb_data->dev->transfer) {
269 cb_data->dev->transfer = NULL;
270 }
271 free(cb_data);
272 }
273 return;
274 }
275 } else {
276 if (cb_data && cb_data->cb) {
277 if (debug)
278 hexdump(transfer->buffer, transfer->actual_length, "USB > ");
279
280 if (!cb_data->cb(transfer->buffer, transfer->actual_length, cb_data->data)) {
281 quit = EIO;
282
283 libusb_free_transfer(transfer);
284 if (cb_data && cb_data->dev && cb_data->dev->transfer) {
285 cb_data->dev->transfer = NULL;
286 free(cb_data);
287 }
288
289 return;
290 }
291 } else {
292 hexdump(transfer->buffer, transfer->actual_length, "> ");
293 }
294 }
295
296 err = libusb_submit_transfer(transfer);
297 if (err != 0) {
298 fprintf(stderr, "Can't re-submit transfer: %s\n", usb_strerror(err));
299 libusb_free_transfer(transfer);
300 if (cb_data) {
301 if (cb_data->dev)
302 cb_data->dev->transfer = NULL;
303 free(cb_data);
304 }
305 }
306 }
307
308 struct hmcfgusb_dev *hmcfgusb_init(hmcfgusb_cb_fn cb, void *data)
309 {
310 libusb_device_handle *devh = NULL;
311 const struct libusb_pollfd **usb_pfd = NULL;
312 struct hmcfgusb_dev *dev = NULL;
313 struct hmcfgusb_cb_data *cb_data = NULL;
314 int bootloader = 0;
315 int err;
316 int i;
317
318 if (!libusb_initialized) {
319 err = libusb_init(NULL);
320 if (err != 0) {
321 fprintf(stderr, "Can't initialize libusb: %s\n", usb_strerror(err));
322 return NULL;
323 }
324 }
325 libusb_initialized = 1;
326
327 devh = hmcfgusb_find(ID_VENDOR, ID_PRODUCT);
328 if (!devh) {
329 devh = hmcfgusb_find(ID_VENDOR, ID_PRODUCT_BL);
330 if (!devh) {
331 fprintf(stderr, "Can't find/open hmcfgusb!\n");
332 #ifdef NEED_LIBUSB_EXIT
333 hmcfgusb_exit();
334 #endif
335 return NULL;
336 }
337 bootloader = 1;
338 }
339
340 dev = malloc(sizeof(struct hmcfgusb_dev));
341 if (!dev) {
342 perror("Can't allocate memory for hmcfgusb_dev");
343 libusb_close(devh);
344 #ifdef NEED_LIBUSB_EXIT
345 hmcfgusb_exit();
346 #endif
347 return NULL;
348 }
349
350 memset(dev, 0, sizeof(struct hmcfgusb_dev));
351 dev->usb_devh = devh;
352 dev->bootloader = bootloader;
353 dev->opened_at = time(NULL);
354
355 cb_data = malloc(sizeof(struct hmcfgusb_cb_data));
356 if (!cb_data) {
357 perror("Can't allocate memory for hmcfgusb_cb_data");
358 free(dev);
359 libusb_close(devh);
360 #ifdef NEED_LIBUSB_EXIT
361 hmcfgusb_exit();
362 #endif
363 return NULL;
364 }
365
366 memset(cb_data, 0, sizeof(struct hmcfgusb_cb_data));
367
368 cb_data->dev = dev;
369 cb_data->cb = cb;
370 cb_data->data = data;
371
372 dev->transfer = hmcfgusb_prepare_int(devh, hmcfgusb_interrupt, cb_data, ASYNC_SIZE);
373
374 if (!dev->transfer) {
375 fprintf(stderr, "Can't prepare async device io!\n");
376 free(dev);
377 free(cb_data);
378 libusb_close(devh);
379 #ifdef NEED_LIBUSB_EXIT
380 hmcfgusb_exit();
381 #endif
382 return NULL;
383 }
384
385 usb_pfd = libusb_get_pollfds(NULL);
386 if (!usb_pfd) {
387 fprintf(stderr, "Can't get FDset from libusb!\n");
388 libusb_cancel_transfer(dev->transfer);
389 libusb_handle_events(NULL);
390 free(dev);
391 free(cb_data);
392 libusb_close(devh);
393 #ifdef NEED_LIBUSB_EXIT
394 hmcfgusb_exit();
395 #endif
396 return NULL;
397 }
398
399 dev->n_usb_pfd = 0;
400 for(i = 0; usb_pfd[i]; i++)
401 dev->n_usb_pfd++;
402
403 dev->pfd = malloc(dev->n_usb_pfd * sizeof(struct pollfd));
404 if (!dev->pfd) {
405 perror("Can't allocate memory for poll-fds");
406 libusb_cancel_transfer(dev->transfer);
407 libusb_handle_events(NULL);
408 free(dev);
409 free(cb_data);
410 libusb_close(devh);
411 #ifdef NEED_LIBUSB_EXIT
412 hmcfgusb_exit();
413 #endif
414 return NULL;
415 }
416
417 memset(dev->pfd, 0, dev->n_usb_pfd * sizeof(struct pollfd));
418
419 for (i = 0; i < dev->n_usb_pfd; i++) {
420 dev->pfd[i].fd = usb_pfd[i]->fd;
421 dev->pfd[i].events = usb_pfd[i]->events;
422 dev->pfd[i].revents = 0;
423 }
424
425 free(usb_pfd);
426
427 dev->n_pfd = dev->n_usb_pfd;
428
429 quit = 0;
430
431 return dev;
432 }
433
434 int hmcfgusb_add_pfd(struct hmcfgusb_dev *dev, int fd, short events)
435 {
436 dev->n_pfd++;
437 dev->pfd = realloc(dev->pfd, dev->n_pfd * sizeof(struct pollfd));
438 if (!dev->pfd) {
439 perror("Can't realloc poll-fds");
440 return 0;
441 }
442
443 dev->pfd[dev->n_pfd-1].fd = fd;
444 dev->pfd[dev->n_pfd-1].events = events;
445 dev->pfd[dev->n_pfd-1].revents = 0;
446
447 return 1;
448 }
449
450 int hmcfgusb_poll(struct hmcfgusb_dev *dev, int timeout)
451 {
452 struct timeval tv;
453 int usb_event = 0;
454 int timed_out = 0;
455 int i;
456 int n;
457 int fd_n;
458 int err;
459
460 errno = 0;
461
462 memset(&tv, 0, sizeof(tv));
463 err = libusb_get_next_timeout(NULL, &tv);
464 if (err < 0) {
465 fprintf(stderr, "libusb_get_next_timeout: %s\n", usb_strerror(err));
466 errno = EIO;
467 return -1;
468 } else if (err == 0) {
469 /* No pending timeout or a sane platform */
470 } else {
471 if ((tv.tv_sec == 0) && (tv.tv_usec == 0)) {
472 usb_event = 1;
473 } else if ((tv.tv_sec * 1000) < timeout) {
474 timeout = tv.tv_sec * 1000;
475 }
476 }
477
478 if (!usb_event) {
479 for (i = 0; i < dev->n_pfd; i++) {
480 dev->pfd[i].revents = 0;
481 }
482
483 n = poll(dev->pfd, dev->n_pfd, timeout);
484 if (n < 0) {
485 perror("poll");
486 errno = 0;
487 return -1;
488 } else if (n == 0) {
489 usb_event = 1;
490 timed_out = 1;
491 } else {
492 for (fd_n = 0; fd_n < dev->n_pfd; fd_n++) {
493 if (dev->pfd[fd_n].revents) {
494 if (fd_n < dev->n_usb_pfd) {
495 usb_event = 1;
496 break;
497 } else {
498 errno = 0;
499 return dev->pfd[fd_n].fd;
500 }
501 }
502 }
503 }
504 }
505
506 if (usb_event) {
507 memset(&tv, 0, sizeof(tv));
508 err = libusb_handle_events_timeout_completed(NULL, &tv, NULL);
509 if (err < 0) {
510 fprintf(stderr, "libusb_handle_events_timeout_completed: %s\n", usb_strerror(err));
511 errno = EIO;
512 return -1;
513 }
514 }
515
516 errno = 0;
517 if (quit) {
518 fprintf(stderr, "closing device-connection due to error %d\n", quit);
519 errno = quit;
520 }
521
522 if (timed_out)
523 errno = ETIMEDOUT;
524
525 return -1;
526 }
527
528 void hmcfgusb_enter_bootloader(struct hmcfgusb_dev *dev)
529 {
530 uint8_t out[ASYNC_SIZE];
531
532 if (dev->bootloader) {
533 fprintf(stderr, "request for bootloader mode, but device already in bootloader!\n");
534 return;
535 }
536
537 memset(out, 0, sizeof(out));
538 out[0] = 'B';
539 hmcfgusb_send(dev, out, sizeof(out), 1);
540
541 return;
542 }
543
544 void hmcfgusb_leave_bootloader(struct hmcfgusb_dev *dev)
545 {
546 uint8_t out[ASYNC_SIZE];
547
548 if (!dev->bootloader) {
549 fprintf(stderr, "request for leaving bootloader mode, but device already in normal mode!\n");
550 return;
551 }
552
553 memset(out, 0, sizeof(out));
554 out[0] = 'K';
555 hmcfgusb_send(dev, out, sizeof(out), 1);
556
557 return;
558 }
559
560 void hmcfgusb_close(struct hmcfgusb_dev *dev)
561 {
562 int err;
563
564 if (dev->transfer) {
565 libusb_cancel_transfer(dev->transfer);
566 libusb_handle_events(NULL);
567 }
568
569 err = libusb_release_interface(dev->usb_devh, INTERFACE);
570 if ((err != 0)) {
571 fprintf(stderr, "Can't release interface: %s\n", usb_strerror(err));
572 }
573
574 libusb_close(dev->usb_devh);
575 #ifdef NEED_LIBUSB_EXIT
576 hmcfgusb_exit();
577 #endif
578 free(dev->pfd);
579 free(dev);
580 }
581
582 void hmcfgusb_exit(void)
583 {
584 if (libusb_initialized) {
585 libusb_exit(NULL);
586 libusb_initialized = 0;
587 }
588 }
589
590 void hmcfgusb_set_debug(int d)
591 {
592 debug = d;
593 }
Impressum, Datenschutz