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