]> git.zerfleddert.de Git - hmcfgusb/blob - hmcfgusb.c
d3bec90c791afc17c395e5b4bfe2ffbe177a57d3
[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
62 /* Not in all libusb-1.0 versions, so we have to roll our own :-( */
63 static char * usb_strerror(int e)
64 {
65 static char unknerr[256];
66
67 switch (e) {
68 case LIBUSB_SUCCESS:
69 return "Success";
70 case LIBUSB_ERROR_IO:
71 return "Input/output error";
72 case LIBUSB_ERROR_INVALID_PARAM:
73 return "Invalid parameter";
74 case LIBUSB_ERROR_ACCESS:
75 return "Access denied (insufficient permissions)";
76 case LIBUSB_ERROR_NO_DEVICE:
77 return "No such device (it may have been disconnected)";
78 case LIBUSB_ERROR_NOT_FOUND:
79 return "Entity not found";
80 case LIBUSB_ERROR_BUSY:
81 return "Resource busy";
82 case LIBUSB_ERROR_TIMEOUT:
83 return "Operation timed out";
84 case LIBUSB_ERROR_OVERFLOW:
85 return "Overflow";
86 case LIBUSB_ERROR_PIPE:
87 return "Pipe error";
88 case LIBUSB_ERROR_INTERRUPTED:
89 return "System call interrupted (perhaps due to signal)";
90 case LIBUSB_ERROR_NO_MEM:
91 return "Insufficient memory";
92 case LIBUSB_ERROR_NOT_SUPPORTED:
93 return "Operation not supported or unimplemented on this platform";
94 case LIBUSB_ERROR_OTHER:
95 return "Other error";
96 };
97 snprintf(unknerr, sizeof(unknerr), "Unknown error code %d / 0x%02x", e, e);
98 return unknerr;
99 }
100
101 static libusb_device_handle *hmcfgusb_find() {
102 libusb_device_handle *devh = NULL;
103 libusb_device **list;
104 ssize_t cnt;
105 ssize_t i;
106 int err;
107
108 cnt = libusb_get_device_list(NULL, &list);
109 if (cnt < 0) {
110 fprintf(stderr, "Can't get USB device list: %d\n", (int)cnt);
111 return NULL;
112 }
113
114 for (i = 0; i < cnt; i++){
115 struct libusb_device_descriptor desc;
116
117 err = libusb_get_device_descriptor(list[i], &desc);
118 if (err)
119 continue;
120
121 if ((desc.idVendor == ID_VENDOR) &&
122 ((desc.idProduct == ID_PRODUCT) || (desc.idProduct == ID_PRODUCT_BL))) {
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 return NULL;
129 }
130
131 err = libusb_detach_kernel_driver(devh, INTERFACE);
132 if ((err != 0) && (err != LIBUSB_ERROR_NOT_FOUND)) {
133 fprintf(stderr, "Can't detach kernel driver: %s\n", usb_strerror(err));
134 return NULL;
135 }
136
137 err = libusb_claim_interface(devh, INTERFACE);
138 if ((err != 0)) {
139 fprintf(stderr, "Can't claim interface: %s\n", usb_strerror(err));
140 return NULL;
141 }
142
143 return devh;
144 }
145
146 }
147
148 return NULL;
149 }
150
151 int hmcfgusb_send_null_frame(struct hmcfgusb_dev *usbdev, int silent)
152 {
153 int err;
154 int cnt;
155 unsigned char out[0x40];
156
157 memset(out, 0, sizeof(out));
158
159 err = libusb_interrupt_transfer(usbdev->usb_devh, EP_OUT, out, 0, &cnt, USB_TIMEOUT);
160 if (err && (!silent)) {
161 fprintf(stderr, "Can't send null frame: %s\n", usb_strerror(err));
162 return 0;
163 }
164
165 return 1;
166 }
167
168 int hmcfgusb_send(struct hmcfgusb_dev *usbdev, unsigned char* send_data, int len, int done)
169 {
170 int err;
171 int cnt;
172 struct timeval tv_start, tv_end;
173 int msec;
174
175 if (debug) {
176 hexdump(send_data, len, "USB < ");
177 }
178
179 gettimeofday(&tv_start, NULL);
180
181 err = libusb_interrupt_transfer(usbdev->usb_devh, EP_OUT, send_data, len, &cnt, USB_TIMEOUT);
182 if (err) {
183 fprintf(stderr, "Can't send data: %s\n", usb_strerror(err));
184 return 0;
185 }
186
187 if (done) {
188 if (!hmcfgusb_send_null_frame(usbdev, 0)) {
189 return 0;
190 }
191 }
192
193 gettimeofday(&tv_end, NULL);
194 msec = ((tv_end.tv_sec-tv_start.tv_sec)*1000)+((tv_end.tv_usec-tv_start.tv_usec)/1000);
195
196 if (msec > 100) {
197 fprintf(stderr, "usb-transfer took more than 100ms (%dms), this may lead to timing problems!\n", msec);
198 } else if (debug) {
199 fprintf(stderr, "usb-transfer took %dms!\n", msec);
200 }
201
202 return 1;
203 }
204
205 static struct libusb_transfer *hmcfgusb_prepare_int(libusb_device_handle *devh, libusb_transfer_cb_fn cb, void *data)
206 {
207 unsigned char *data_buf;
208 struct libusb_transfer *transfer;
209 int err;
210
211 data_buf = malloc(ASYNC_SIZE);
212 if (!data_buf) {
213 fprintf(stderr, "Can't allocate memory for data-buffer!\n");
214 return NULL;
215 }
216
217 transfer = libusb_alloc_transfer(0);
218 if (!transfer) {
219 fprintf(stderr, "Can't allocate memory for usb-transfer!\n");
220 free(data_buf);
221 return NULL;
222 }
223
224 libusb_fill_interrupt_transfer(transfer, devh, EP_IN,
225 data_buf, ASYNC_SIZE, cb, data, USB_TIMEOUT);
226
227 transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK | LIBUSB_TRANSFER_FREE_BUFFER;
228
229 err = libusb_submit_transfer(transfer);
230 if (err != 0) {
231 fprintf(stderr, "Can't submit transfer: %s\n", usb_strerror(err));
232 libusb_free_transfer(transfer);
233 return NULL;
234 }
235
236 return transfer;
237 }
238
239 struct hmcfgusb_cb_data {
240 struct hmcfgusb_dev *dev;
241 hmcfgusb_cb_fn cb;
242 void *data;
243 };
244
245 static void LIBUSB_CALL hmcfgusb_interrupt(struct libusb_transfer *transfer)
246 {
247 int err;
248 struct hmcfgusb_cb_data *cb_data;
249
250 cb_data = transfer->user_data;
251
252 if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
253 if (transfer->status != LIBUSB_TRANSFER_TIMED_OUT) {
254 fprintf(stderr, "Interrupt transfer not completed: %s!\n", usb_strerror(transfer->status));
255 quit = EIO;
256
257 if (cb_data && cb_data->dev && cb_data->dev->transfer) {
258 libusb_free_transfer(cb_data->dev->transfer);
259 cb_data->dev->transfer = NULL;
260 free(cb_data);
261 }
262 return;
263 }
264 } else {
265 if (cb_data && cb_data->cb) {
266 if (debug)
267 hexdump(transfer->buffer, transfer->actual_length, "USB > ");
268
269 if (!cb_data->cb(transfer->buffer, transfer->actual_length, cb_data->data)) {
270 quit = EIO;
271
272 if (cb_data && cb_data->dev && cb_data->dev->transfer) {
273 libusb_free_transfer(cb_data->dev->transfer);
274 cb_data->dev->transfer = NULL;
275 free(cb_data);
276 }
277
278 return;
279 }
280 } else {
281 hexdump(transfer->buffer, transfer->actual_length, "> ");
282 }
283 }
284
285 err = libusb_submit_transfer(transfer);
286 if (err != 0) {
287 fprintf(stderr, "Can't re-submit transfer: %s\n", usb_strerror(err));
288 libusb_free_transfer(transfer);
289 cb_data->dev->transfer = NULL;
290 free(cb_data);
291 }
292 }
293
294 struct hmcfgusb_dev *hmcfgusb_init(hmcfgusb_cb_fn cb, void *data)
295 {
296 libusb_device_handle *devh = NULL;
297 const struct libusb_pollfd **usb_pfd = NULL;
298 struct hmcfgusb_dev *dev = NULL;
299 struct hmcfgusb_cb_data *cb_data = NULL;
300 int err;
301 int i;
302
303 err = libusb_init(NULL);
304 if (err != 0) {
305 fprintf(stderr, "Can't initialize libusb: %s\n", usb_strerror(err));
306 return NULL;
307 }
308
309 devh = hmcfgusb_find();
310 if (!devh) {
311 fprintf(stderr, "Can't find/open hmcfgusb!\n");
312 return NULL;
313 }
314
315 dev = malloc(sizeof(struct hmcfgusb_dev));
316 if (!dev) {
317 perror("Can't allocate memory for hmcfgusb_dev");
318 return NULL;
319 }
320
321 memset(dev, 0, sizeof(struct hmcfgusb_dev));
322 dev->usb_devh = devh;
323
324 cb_data = malloc(sizeof(struct hmcfgusb_cb_data));
325 if (!cb_data) {
326 perror("Can't allocate memory for hmcfgusb_cb_data");
327 free(dev);
328 return NULL;
329 }
330
331 memset(cb_data, 0, sizeof(struct hmcfgusb_cb_data));
332
333 cb_data->dev = dev;
334 cb_data->cb = cb;
335 cb_data->data = data;
336
337 dev->transfer = hmcfgusb_prepare_int(devh, hmcfgusb_interrupt, cb_data);
338 if (!dev->transfer) {
339 fprintf(stderr, "Can't prepare async device io!\n");
340 free(dev);
341 free(cb_data);
342 return NULL;
343 }
344
345 usb_pfd = libusb_get_pollfds(NULL);
346 if (!usb_pfd) {
347 fprintf(stderr, "Can't get FDset from libusb!\n");
348 free(dev);
349 free(cb_data);
350 return NULL;
351 }
352
353 dev->n_usb_pfd = 0;
354 for(i = 0; usb_pfd[i]; i++)
355 dev->n_usb_pfd++;
356
357 dev->pfd = malloc(dev->n_usb_pfd * sizeof(struct pollfd));
358 if (!dev->pfd) {
359 perror("Can't allocate memory for poll-fds");
360 free(dev);
361 free(cb_data);
362 return NULL;
363 }
364
365 memset(dev->pfd, 0, dev->n_usb_pfd * sizeof(struct pollfd));
366
367 for (i = 0; i < dev->n_usb_pfd; i++) {
368 dev->pfd[i].fd = usb_pfd[i]->fd;
369 dev->pfd[i].events = usb_pfd[i]->events;
370 dev->pfd[i].revents = 0;
371 }
372
373 free(usb_pfd);
374
375 dev->n_pfd = dev->n_usb_pfd;
376
377 quit = 0;
378
379 return dev;
380 }
381
382 int hmcfgusb_add_pfd(struct hmcfgusb_dev *dev, int fd, short events)
383 {
384 dev->n_pfd++;
385 dev->pfd = realloc(dev->pfd, dev->n_pfd * sizeof(struct pollfd));
386 if (!dev->pfd) {
387 perror("Can't realloc poll-fds");
388 return 0;
389 }
390
391 dev->pfd[dev->n_pfd-1].fd = fd;
392 dev->pfd[dev->n_pfd-1].events = events;
393 dev->pfd[dev->n_pfd-1].revents = 0;
394
395 return 1;
396 }
397
398 int hmcfgusb_poll(struct hmcfgusb_dev *dev, int timeout)
399 {
400 struct timeval tv;
401 int usb_event = 0;
402 int timed_out = 0;
403 int i;
404 int n;
405 int fd_n;
406 int err;
407
408 errno = 0;
409
410 memset(&tv, 0, sizeof(tv));
411 err = libusb_get_next_timeout(NULL, &tv);
412 if (err < 0) {
413 fprintf(stderr, "libusb_get_next_timeout: %s\n", usb_strerror(err));
414 errno = EIO;
415 return -1;
416 } else if (err == 0) {
417 /* No pending timeout or a sane platform */
418 tv.tv_sec = timeout;
419 } else {
420 if ((tv.tv_sec == 0) && (tv.tv_usec == 0)) {
421 usb_event = 1;
422 } else if (tv.tv_sec > timeout) {
423 tv.tv_sec = timeout;
424 tv.tv_usec = 0;
425 }
426 }
427
428 if (!usb_event) {
429 for (i = 0; i < dev->n_pfd; i++) {
430 dev->pfd[i].revents = 0;
431 }
432
433 n = poll(dev->pfd, dev->n_pfd, tv.tv_sec * 1000);
434 if (n < 0) {
435 perror("poll");
436 errno = 0;
437 return -1;
438 } else if (n == 0) {
439 usb_event = 1;
440 timed_out = 1;
441 } else {
442 for (fd_n = 0; fd_n < dev->n_pfd; fd_n++) {
443 if (dev->pfd[fd_n].revents) {
444 if (fd_n < dev->n_usb_pfd) {
445 usb_event = 1;
446 break;
447 } else {
448 errno = 0;
449 return dev->pfd[fd_n].fd;
450 }
451 }
452 }
453 }
454 }
455
456 if (usb_event) {
457 memset(&tv, 0, sizeof(tv));
458 err = libusb_handle_events_timeout_completed(NULL, &tv, NULL);
459 if (err < 0) {
460 fprintf(stderr, "libusb_handle_events_timeout_completed: %s\n", usb_strerror(err));
461 errno = EIO;
462 return -1;
463 }
464 }
465
466 errno = 0;
467 if (quit) {
468 fprintf(stderr, "closing device-connection due to error %d\n", quit);
469 errno = quit;
470 }
471
472 if (timed_out)
473 errno = ETIMEDOUT;
474
475 return -1;
476 }
477
478 void hmcfgusb_close(struct hmcfgusb_dev *dev)
479 {
480 int err;
481
482 if (dev->transfer) {
483 libusb_cancel_transfer(dev->transfer);
484 }
485
486 err = libusb_release_interface(dev->usb_devh, INTERFACE);
487 if ((err != 0)) {
488 fprintf(stderr, "Can't release interface: %s\n", usb_strerror(err));
489 }
490
491 libusb_close(dev->usb_devh);
492 free(dev->pfd);
493 free(dev);
494
495 libusb_exit(NULL);
496 }
497
498 void hmcfgusb_set_debug(int d)
499 {
500 debug = d;
501 }
Impressum, Datenschutz