add support for older libusb-1.0 found in debian squeeze
[hmcfgusb] / hmcfgusb.c
CommitLineData
9db2e455
MG
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>
f8718b41 32#include <sys/time.h>
9db2e455
MG
33#include <libusb-1.0/libusb.h>
34
37c97e62
MG
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
9db2e455
MG
41#include "hexdump.h"
42#include "hmcfgusb.h"
43
813afd12 44#define USB_TIMEOUT 10000
9db2e455
MG
45
46#define ID_VENDOR 0x1b1f
47#define ID_PRODUCT 0xc00f
4d0be794 48#define ID_PRODUCT_BL 0xc010
9db2e455
MG
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
813afd12
MG
57#define INTERFACE 0
58
9db2e455 59static int quit = 0;
e75295bb 60static int debug = 0;
9db2e455
MG
61
62/* Not in all libusb-1.0 versions, so we have to roll our own :-( */
63static 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
101static 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
4d0be794
MG
121 if ((desc.idVendor == ID_VENDOR) &&
122 ((desc.idProduct == ID_PRODUCT) || (desc.idProduct == ID_PRODUCT_BL))) {
9db2e455
MG
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
813afd12 131 err = libusb_detach_kernel_driver(devh, INTERFACE);
9db2e455
MG
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
813afd12 137 err = libusb_claim_interface(devh, INTERFACE);
9db2e455
MG
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
6262005e 151int hmcfgusb_send_null_frame(struct hmcfgusb_dev *usbdev, int silent)
2a6eaefc
MG
152{
153 int err;
154 int cnt;
3435bdb6 155 unsigned char out[0x40];
2a6eaefc 156
3435bdb6
MG
157 memset(out, 0, sizeof(out));
158
3d5b8e70 159 err = libusb_interrupt_transfer(usbdev->usb_devh, EP_OUT, out, 0, &cnt, USB_TIMEOUT);
6262005e
MG
160 if (err && (!silent)) {
161 fprintf(stderr, "Can't send null frame: %s\n", usb_strerror(err));
2a6eaefc
MG
162 return 0;
163 }
164
165 return 1;
166}
167
9db2e455
MG
168int hmcfgusb_send(struct hmcfgusb_dev *usbdev, unsigned char* send_data, int len, int done)
169{
170 int err;
171 int cnt;
f8718b41
MG
172 struct timeval tv_start, tv_end;
173 int msec;
9db2e455 174
f8718b41 175 if (debug) {
627e3f33 176 hexdump(send_data, len, "USB < ");
f8718b41
MG
177 }
178
d200d8ca
MG
179 gettimeofday(&tv_start, NULL);
180
9db2e455
MG
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));
9db2e455
MG
184 return 0;
185 }
186
187 if (done) {
6262005e 188 if (!hmcfgusb_send_null_frame(usbdev, 0)) {
9db2e455
MG
189 return 0;
190 }
191 }
192
d200d8ca
MG
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) {
6df7655e 197 fprintf(stderr, "usb-transfer took more than 100ms (%dms), this may lead to timing problems!\n", msec);
d200d8ca
MG
198 } else if (debug) {
199 fprintf(stderr, "usb-transfer took %dms!\n", msec);
f8718b41
MG
200 }
201
e0a7146e 202 return 1;
9db2e455
MG
203}
204
205static 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
813afd12 227 transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK | LIBUSB_TRANSFER_FREE_BUFFER;
9db2e455
MG
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);
9db2e455
MG
233 return NULL;
234 }
235
236 return transfer;
237}
238
239struct hmcfgusb_cb_data {
813afd12 240 struct hmcfgusb_dev *dev;
9db2e455
MG
241 hmcfgusb_cb_fn cb;
242 void *data;
243};
244
245static void LIBUSB_CALL hmcfgusb_interrupt(struct libusb_transfer *transfer)
246{
247 int err;
248 struct hmcfgusb_cb_data *cb_data;
249
813afd12
MG
250 cb_data = transfer->user_data;
251
9db2e455
MG
252 if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
253 if (transfer->status != LIBUSB_TRANSFER_TIMED_OUT) {
032d6050 254 fprintf(stderr, "Interrupt transfer not completed: %s!\n", usb_strerror(transfer->status));
9db2e455 255 quit = EIO;
813afd12
MG
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;
4cadd56d 260 free(cb_data);
813afd12 261 }
9db2e455
MG
262 return;
263 }
9db2e455 264 } else {
27bb301b 265 if (cb_data && cb_data->cb) {
e0a7146e 266 if (debug)
627e3f33 267 hexdump(transfer->buffer, transfer->actual_length, "USB > ");
4371275b
MG
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;
4cadd56d 275 free(cb_data);
4371275b
MG
276 }
277
278 return;
279 }
27bb301b 280 } else {
e0a7146e 281 hexdump(transfer->buffer, transfer->actual_length, "> ");
27bb301b 282 }
9db2e455
MG
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));
9db2e455 288 libusb_free_transfer(transfer);
4cadd56d
MG
289 cb_data->dev->transfer = NULL;
290 free(cb_data);
9db2e455
MG
291 }
292}
293
294struct 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");
4cadd56d 327 free(dev);
9db2e455
MG
328 return NULL;
329 }
330
331 memset(cb_data, 0, sizeof(struct hmcfgusb_cb_data));
332
813afd12 333 cb_data->dev = dev;
9db2e455
MG
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");
4cadd56d
MG
340 free(dev);
341 free(cb_data);
9db2e455
MG
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);
4cadd56d 349 free(cb_data);
9db2e455
MG
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");
4cadd56d
MG
360 free(dev);
361 free(cb_data);
9db2e455
MG
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
f16395da
MG
377 quit = 0;
378
9db2e455
MG
379 return dev;
380}
381
382int 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
398int hmcfgusb_poll(struct hmcfgusb_dev *dev, int timeout)
399{
400 struct timeval tv;
401 int usb_event = 0;
1e79d00a 402 int timed_out = 0;
9db2e455
MG
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;
ec30827c
MG
422 } else if (tv.tv_sec > timeout) {
423 tv.tv_sec = timeout;
424 tv.tv_usec = 0;
9db2e455
MG
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");
816f5cd2 436 errno = 0;
9db2e455
MG
437 return -1;
438 } else if (n == 0) {
439 usb_event = 1;
1e79d00a 440 timed_out = 1;
9db2e455
MG
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 {
816f5cd2 448 errno = 0;
9db2e455
MG
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) {
27bb301b 460 fprintf(stderr, "libusb_handle_events_timeout_completed: %s\n", usb_strerror(err));
9db2e455
MG
461 errno = EIO;
462 return -1;
463 }
464 }
465
816f5cd2
MG
466 errno = 0;
467 if (quit) {
468 fprintf(stderr, "closing device-connection due to error %d\n", quit);
9db2e455 469 errno = quit;
816f5cd2 470 }
9db2e455 471
1e79d00a
MG
472 if (timed_out)
473 errno = ETIMEDOUT;
474
9db2e455
MG
475 return -1;
476}
813afd12
MG
477
478void 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);
e0a7146e 492 free(dev->pfd);
813afd12
MG
493 free(dev);
494
495 libusb_exit(NULL);
496}
e75295bb
MG
497
498void hmcfgusb_set_debug(int d)
499{
500 debug = d;
501}
Impressum, Datenschutz