]> git.zerfleddert.de Git - hmcfgusb/blob - hmcfgusb.c
bcb85a4a75e2417e6c26fa73e1ce5c8824a2e416
[hmcfgusb] / hmcfgusb.c
1 /* HM-CFG-USB libusb-driver
2 *
3 * Copyright (c) 2013-16 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, char *serial) {
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 if (serial) {
133 if (desc.iSerialNumber > 0) {
134 uint8_t devSerial[256];
135 err = libusb_get_string_descriptor_ascii(devh, desc.iSerialNumber, devSerial, sizeof(devSerial));
136 if (err < 0) {
137 fprintf(stderr, "Can't read serial-number: %s\n", usb_strerror(err));
138 libusb_close(devh);
139 libusb_free_device_list(list, 1);
140 return NULL;
141 }
142 if (strcmp((char*)devSerial, (char*)serial)) {
143 libusb_close(devh);
144 continue;
145 }
146 } else {
147 libusb_close(devh);
148 continue;
149 }
150 }
151
152 err = libusb_detach_kernel_driver(devh, INTERFACE);
153 if ((err != 0) && (err != LIBUSB_ERROR_NOT_FOUND)) {
154 fprintf(stderr, "Can't detach kernel driver: %s\n", usb_strerror(err));
155 libusb_close(devh);
156 libusb_free_device_list(list, 1);
157 return NULL;
158 }
159
160 err = libusb_claim_interface(devh, INTERFACE);
161 if ((err != 0)) {
162 fprintf(stderr, "Can't claim interface: %s\n", usb_strerror(err));
163 libusb_close(devh);
164 libusb_free_device_list(list, 1);
165 return NULL;
166 }
167
168 libusb_free_device_list(list, 0);
169 return devh;
170 }
171
172 }
173
174 libusb_free_device_list(list, 1);
175 return NULL;
176 }
177
178 int hmcfgusb_send_null_frame(struct hmcfgusb_dev *usbdev, int silent)
179 {
180 int err;
181 int cnt;
182 unsigned char out[0x40];
183
184 memset(out, 0, sizeof(out));
185
186 err = libusb_interrupt_transfer(usbdev->usb_devh, EP_OUT, out, 0, &cnt, USB_TIMEOUT);
187 if (err && (!silent)) {
188 fprintf(stderr, "Can't send null frame: %s\n", usb_strerror(err));
189 return 0;
190 }
191
192 return 1;
193 }
194
195 int hmcfgusb_send(struct hmcfgusb_dev *usbdev, unsigned char* send_data, int len, int done)
196 {
197 int err;
198 int cnt;
199 struct timeval tv_start, tv_end;
200 int msec;
201
202 if (debug) {
203 hexdump(send_data, len, "USB < ");
204 }
205
206 gettimeofday(&tv_start, NULL);
207
208 err = libusb_interrupt_transfer(usbdev->usb_devh, EP_OUT, send_data, len, &cnt, USB_TIMEOUT);
209 if (err) {
210 fprintf(stderr, "Can't send data: %s\n", usb_strerror(err));
211 return 0;
212 }
213
214 if (done) {
215 if (!hmcfgusb_send_null_frame(usbdev, 0)) {
216 return 0;
217 }
218 }
219
220 gettimeofday(&tv_end, NULL);
221 msec = ((tv_end.tv_sec-tv_start.tv_sec)*1000)+((tv_end.tv_usec-tv_start.tv_usec)/1000);
222
223 if (msec > 100) {
224 fprintf(stderr, "usb-transfer took more than 100ms (%dms), this may lead to timing problems!\n", msec);
225 } else if (debug) {
226 fprintf(stderr, "usb-transfer took %dms!\n", msec);
227 }
228
229 return 1;
230 }
231
232 static struct libusb_transfer *hmcfgusb_prepare_int(libusb_device_handle *devh, libusb_transfer_cb_fn cb, void *data, int in_size)
233 {
234 unsigned char *data_buf;
235 struct libusb_transfer *transfer;
236 int err;
237
238 data_buf = malloc(in_size);
239 if (!data_buf) {
240 fprintf(stderr, "Can't allocate memory for data-buffer!\n");
241 return NULL;
242 }
243
244 transfer = libusb_alloc_transfer(0);
245 if (!transfer) {
246 fprintf(stderr, "Can't allocate memory for usb-transfer!\n");
247 free(data_buf);
248 return NULL;
249 }
250
251 libusb_fill_interrupt_transfer(transfer, devh, EP_IN,
252 data_buf, in_size, cb, data, USB_TIMEOUT);
253
254 transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER;
255
256 err = libusb_submit_transfer(transfer);
257 if (err != 0) {
258 fprintf(stderr, "Can't submit transfer: %s\n", usb_strerror(err));
259 libusb_free_transfer(transfer);
260 return NULL;
261 }
262
263 return transfer;
264 }
265
266 struct hmcfgusb_cb_data {
267 struct hmcfgusb_dev *dev;
268 hmcfgusb_cb_fn cb;
269 void *data;
270 };
271
272 static void LIBUSB_CALL hmcfgusb_interrupt(struct libusb_transfer *transfer)
273 {
274 int err;
275 struct hmcfgusb_cb_data *cb_data;
276
277 cb_data = transfer->user_data;
278
279 if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
280 if (transfer->status != LIBUSB_TRANSFER_TIMED_OUT) {
281 if (transfer->status != LIBUSB_TRANSFER_CANCELLED)
282 fprintf(stderr, "Interrupt transfer not completed: %s!\n", usb_strerror(transfer->status));
283
284 quit = EIO;
285 goto out;
286 }
287 } else {
288 if (cb_data && cb_data->cb) {
289 if (debug)
290 hexdump(transfer->buffer, transfer->actual_length, "USB > ");
291
292 if (!cb_data->cb(transfer->buffer, transfer->actual_length, cb_data->data)) {
293 quit = EIO;
294 goto out;
295 }
296 } else {
297 hexdump(transfer->buffer, transfer->actual_length, "> ");
298 }
299 }
300
301 err = libusb_submit_transfer(transfer);
302 if (err != 0) {
303 fprintf(stderr, "Can't re-submit transfer: %s\n", usb_strerror(err));
304 goto out;
305 }
306
307 return;
308
309 out:
310 libusb_free_transfer(transfer);
311 if (cb_data) {
312 if (cb_data->dev && cb_data->dev->transfer) {
313 cb_data->dev->transfer = NULL;
314 }
315 free(cb_data);
316 }
317 }
318
319 struct hmcfgusb_dev *hmcfgusb_init(hmcfgusb_cb_fn cb, void *data, char *serial)
320 {
321 libusb_device_handle *devh = NULL;
322 const struct libusb_pollfd **usb_pfd = NULL;
323 struct hmcfgusb_dev *dev = NULL;
324 struct hmcfgusb_cb_data *cb_data = NULL;
325 int bootloader = 0;
326 int err;
327 int i;
328
329 if (!libusb_initialized) {
330 err = libusb_init(NULL);
331 if (err != 0) {
332 fprintf(stderr, "Can't initialize libusb: %s\n", usb_strerror(err));
333 return NULL;
334 }
335 }
336 libusb_initialized = 1;
337
338 devh = hmcfgusb_find(ID_VENDOR, ID_PRODUCT, serial);
339 if (!devh) {
340 devh = hmcfgusb_find(ID_VENDOR, ID_PRODUCT_BL, serial);
341 if (!devh) {
342 if (serial) {
343 fprintf(stderr, "Can't find/open HM-CFG-USB with serial %s!\n", serial);
344 } else {
345 fprintf(stderr, "Can't find/open HM-CFG-USB!\n");
346 }
347 #ifdef NEED_LIBUSB_EXIT
348 hmcfgusb_exit();
349 #endif
350 return NULL;
351 }
352 bootloader = 1;
353 }
354
355 dev = malloc(sizeof(struct hmcfgusb_dev));
356 if (!dev) {
357 perror("Can't allocate memory for hmcfgusb_dev");
358 libusb_close(devh);
359 #ifdef NEED_LIBUSB_EXIT
360 hmcfgusb_exit();
361 #endif
362 return NULL;
363 }
364
365 memset(dev, 0, sizeof(struct hmcfgusb_dev));
366 dev->usb_devh = devh;
367 dev->bootloader = bootloader;
368 dev->opened_at = time(NULL);
369
370 cb_data = malloc(sizeof(struct hmcfgusb_cb_data));
371 if (!cb_data) {
372 perror("Can't allocate memory for hmcfgusb_cb_data");
373 free(dev);
374 libusb_close(devh);
375 #ifdef NEED_LIBUSB_EXIT
376 hmcfgusb_exit();
377 #endif
378 return NULL;
379 }
380
381 memset(cb_data, 0, sizeof(struct hmcfgusb_cb_data));
382
383 cb_data->dev = dev;
384 cb_data->cb = cb;
385 cb_data->data = data;
386
387 dev->transfer = hmcfgusb_prepare_int(devh, hmcfgusb_interrupt, cb_data, ASYNC_SIZE);
388
389 if (!dev->transfer) {
390 fprintf(stderr, "Can't prepare async device io!\n");
391 free(dev);
392 free(cb_data);
393 libusb_close(devh);
394 #ifdef NEED_LIBUSB_EXIT
395 hmcfgusb_exit();
396 #endif
397 return NULL;
398 }
399
400 usb_pfd = libusb_get_pollfds(NULL);
401 if (!usb_pfd) {
402 fprintf(stderr, "Can't get FDset from libusb!\n");
403 libusb_cancel_transfer(dev->transfer);
404 libusb_handle_events(NULL);
405 free(dev);
406 free(cb_data);
407 libusb_close(devh);
408 #ifdef NEED_LIBUSB_EXIT
409 hmcfgusb_exit();
410 #endif
411 return NULL;
412 }
413
414 dev->n_usb_pfd = 0;
415 for(i = 0; usb_pfd[i]; i++)
416 dev->n_usb_pfd++;
417
418 dev->pfd = malloc(dev->n_usb_pfd * sizeof(struct pollfd));
419 if (!dev->pfd) {
420 perror("Can't allocate memory for poll-fds");
421 libusb_cancel_transfer(dev->transfer);
422 libusb_handle_events(NULL);
423 free(dev);
424 free(cb_data);
425 libusb_close(devh);
426 #ifdef NEED_LIBUSB_EXIT
427 hmcfgusb_exit();
428 #endif
429 return NULL;
430 }
431
432 memset(dev->pfd, 0, dev->n_usb_pfd * sizeof(struct pollfd));
433
434 for (i = 0; i < dev->n_usb_pfd; i++) {
435 dev->pfd[i].fd = usb_pfd[i]->fd;
436 dev->pfd[i].events = usb_pfd[i]->events;
437 dev->pfd[i].revents = 0;
438 }
439
440 free(usb_pfd);
441
442 dev->n_pfd = dev->n_usb_pfd;
443
444 quit = 0;
445
446 return dev;
447 }
448
449 int hmcfgusb_add_pfd(struct hmcfgusb_dev *dev, int fd, short events)
450 {
451 dev->n_pfd++;
452 dev->pfd = realloc(dev->pfd, dev->n_pfd * sizeof(struct pollfd));
453 if (!dev->pfd) {
454 perror("Can't realloc poll-fds");
455 return 0;
456 }
457
458 dev->pfd[dev->n_pfd-1].fd = fd;
459 dev->pfd[dev->n_pfd-1].events = events;
460 dev->pfd[dev->n_pfd-1].revents = 0;
461
462 return 1;
463 }
464
465 int hmcfgusb_poll(struct hmcfgusb_dev *dev, int timeout)
466 {
467 struct timeval tv;
468 int usb_event = 0;
469 int timed_out = 0;
470 int i;
471 int n;
472 int fd_n;
473 int err;
474
475 errno = 0;
476
477 memset(&tv, 0, sizeof(tv));
478 err = libusb_get_next_timeout(NULL, &tv);
479 if (err < 0) {
480 fprintf(stderr, "libusb_get_next_timeout: %s\n", usb_strerror(err));
481 errno = EIO;
482 return -1;
483 } else if (err == 0) {
484 /* No pending timeout or a sane platform */
485 } else {
486 if ((tv.tv_sec == 0) && (tv.tv_usec == 0)) {
487 usb_event = 1;
488 } else if ((tv.tv_sec * 1000) < timeout) {
489 timeout = tv.tv_sec * 1000;
490 }
491 }
492
493 if (!usb_event) {
494 for (i = 0; i < dev->n_pfd; i++) {
495 dev->pfd[i].revents = 0;
496 }
497
498 n = poll(dev->pfd, dev->n_pfd, timeout);
499 if (n < 0) {
500 perror("poll");
501 errno = 0;
502 return -1;
503 } else if (n == 0) {
504 usb_event = 1;
505 timed_out = 1;
506 } else {
507 for (fd_n = 0; fd_n < dev->n_pfd; fd_n++) {
508 if (dev->pfd[fd_n].revents) {
509 if (fd_n < dev->n_usb_pfd) {
510 usb_event = 1;
511 break;
512 } else {
513 errno = 0;
514 return dev->pfd[fd_n].fd;
515 }
516 }
517 }
518 }
519 }
520
521 if (usb_event) {
522 memset(&tv, 0, sizeof(tv));
523 err = libusb_handle_events_timeout_completed(NULL, &tv, NULL);
524 if (err < 0) {
525 fprintf(stderr, "libusb_handle_events_timeout_completed: %s\n", usb_strerror(err));
526 errno = EIO;
527 return -1;
528 }
529 }
530
531 errno = 0;
532 if (quit) {
533 fprintf(stderr, "closing device-connection due to error %d\n", quit);
534 errno = quit;
535 }
536
537 if (timed_out)
538 errno = ETIMEDOUT;
539
540 return -1;
541 }
542
543 void hmcfgusb_enter_bootloader(struct hmcfgusb_dev *dev)
544 {
545 uint8_t out[ASYNC_SIZE];
546
547 if (dev->bootloader) {
548 fprintf(stderr, "request for bootloader mode, but device already in bootloader!\n");
549 return;
550 }
551
552 memset(out, 0, sizeof(out));
553 out[0] = 'B';
554 hmcfgusb_send(dev, out, sizeof(out), 1);
555
556 return;
557 }
558
559 void hmcfgusb_leave_bootloader(struct hmcfgusb_dev *dev)
560 {
561 uint8_t out[ASYNC_SIZE];
562
563 if (!dev->bootloader) {
564 fprintf(stderr, "request for leaving bootloader mode, but device already in normal mode!\n");
565 return;
566 }
567
568 memset(out, 0, sizeof(out));
569 out[0] = 'K';
570 hmcfgusb_send(dev, out, sizeof(out), 1);
571
572 return;
573 }
574
575 void hmcfgusb_close(struct hmcfgusb_dev *dev)
576 {
577 int err;
578
579 if (dev->transfer) {
580 libusb_cancel_transfer(dev->transfer);
581 libusb_handle_events(NULL);
582 }
583
584 err = libusb_release_interface(dev->usb_devh, INTERFACE);
585 if ((err != 0)) {
586 fprintf(stderr, "Can't release interface: %s\n", usb_strerror(err));
587 }
588
589 libusb_close(dev->usb_devh);
590 #ifdef NEED_LIBUSB_EXIT
591 hmcfgusb_exit();
592 #endif
593 free(dev->pfd);
594 free(dev);
595 }
596
597 void hmcfgusb_exit(void)
598 {
599 if (libusb_initialized) {
600 libusb_exit(NULL);
601 libusb_initialized = 0;
602 }
603 }
604
605 void hmcfgusb_set_debug(int d)
606 {
607 debug = d;
608 }
Impressum, Datenschutz