cleanup on error/exit
[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 <libusb-1.0/libusb.h>
33
34 #include "hexdump.h"
35 #include "hmcfgusb.h"
36
37 #define USB_TIMEOUT 10000
38
39 #define ID_VENDOR 0x1b1f
40 #define ID_PRODUCT 0xc00f
41
42 /* TODO: dynamic */
43 #define ASYNC_SIZE 0x0040
44 #define ASYNC_INTERVAL 32
45
46 #define EP_OUT 0x02
47 #define EP_IN 0x83
48
49 #define INTERFACE 0
50
51 static int quit = 0;
52
53 /* Not in all libusb-1.0 versions, so we have to roll our own :-( */
54 static char * usb_strerror(int e)
55 {
56 static char unknerr[256];
57
58 switch (e) {
59 case LIBUSB_SUCCESS:
60 return "Success";
61 case LIBUSB_ERROR_IO:
62 return "Input/output error";
63 case LIBUSB_ERROR_INVALID_PARAM:
64 return "Invalid parameter";
65 case LIBUSB_ERROR_ACCESS:
66 return "Access denied (insufficient permissions)";
67 case LIBUSB_ERROR_NO_DEVICE:
68 return "No such device (it may have been disconnected)";
69 case LIBUSB_ERROR_NOT_FOUND:
70 return "Entity not found";
71 case LIBUSB_ERROR_BUSY:
72 return "Resource busy";
73 case LIBUSB_ERROR_TIMEOUT:
74 return "Operation timed out";
75 case LIBUSB_ERROR_OVERFLOW:
76 return "Overflow";
77 case LIBUSB_ERROR_PIPE:
78 return "Pipe error";
79 case LIBUSB_ERROR_INTERRUPTED:
80 return "System call interrupted (perhaps due to signal)";
81 case LIBUSB_ERROR_NO_MEM:
82 return "Insufficient memory";
83 case LIBUSB_ERROR_NOT_SUPPORTED:
84 return "Operation not supported or unimplemented on this platform";
85 case LIBUSB_ERROR_OTHER:
86 return "Other error";
87 };
88 snprintf(unknerr, sizeof(unknerr), "Unknown error code %d / 0x%02x", e, e);
89 return unknerr;
90 }
91
92 static libusb_device_handle *hmcfgusb_find() {
93 libusb_device_handle *devh = NULL;
94 libusb_device **list;
95 ssize_t cnt;
96 ssize_t i;
97 int err;
98
99 cnt = libusb_get_device_list(NULL, &list);
100 if (cnt < 0) {
101 fprintf(stderr, "Can't get USB device list: %d\n", (int)cnt);
102 return NULL;
103 }
104
105 for (i = 0; i < cnt; i++){
106 struct libusb_device_descriptor desc;
107
108 err = libusb_get_device_descriptor(list[i], &desc);
109 if (err)
110 continue;
111
112 if ((desc.idVendor == ID_VENDOR) && (desc.idProduct == ID_PRODUCT)) {
113 libusb_device *dev = list[i];
114
115 err = libusb_open(dev, &devh);
116 if (err) {
117 fprintf(stderr, "Can't open device: %s\n", usb_strerror(err));
118 return NULL;
119 }
120
121 err = libusb_detach_kernel_driver(devh, INTERFACE);
122 if ((err != 0) && (err != LIBUSB_ERROR_NOT_FOUND)) {
123 fprintf(stderr, "Can't detach kernel driver: %s\n", usb_strerror(err));
124 return NULL;
125 }
126
127 err = libusb_claim_interface(devh, INTERFACE);
128 if ((err != 0)) {
129 fprintf(stderr, "Can't claim interface: %s\n", usb_strerror(err));
130 return NULL;
131 }
132
133 return devh;
134 }
135
136 }
137
138 return NULL;
139 }
140
141 int hmcfgusb_send(struct hmcfgusb_dev *usbdev, unsigned char* send_data, int len, int done)
142 {
143 int err;
144 int cnt;
145 int ret;
146
147 err = libusb_interrupt_transfer(usbdev->usb_devh, EP_OUT, send_data, len, &cnt, USB_TIMEOUT);
148 if (err) {
149 fprintf(stderr, "Can't send data: %s\n", usb_strerror(err));
150 if (err == LIBUSB_ERROR_NO_DEVICE)
151 exit(EXIT_FAILURE);
152 return 0;
153 }
154
155 if (done) {
156 err = libusb_interrupt_transfer(usbdev->usb_devh, EP_OUT, send_data, 0, &cnt, USB_TIMEOUT);
157 if (err) {
158 fprintf(stderr, "Can't send data: %s\n", usb_strerror(err));
159 if (err == LIBUSB_ERROR_NO_DEVICE)
160 exit(EXIT_FAILURE);
161 return 0;
162 }
163 }
164
165 return ret;
166 }
167
168 static struct libusb_transfer *hmcfgusb_prepare_int(libusb_device_handle *devh, libusb_transfer_cb_fn cb, void *data)
169 {
170 unsigned char *data_buf;
171 struct libusb_transfer *transfer;
172 int err;
173
174 data_buf = malloc(ASYNC_SIZE);
175 if (!data_buf) {
176 fprintf(stderr, "Can't allocate memory for data-buffer!\n");
177 return NULL;
178 }
179
180 transfer = libusb_alloc_transfer(0);
181 if (!transfer) {
182 fprintf(stderr, "Can't allocate memory for usb-transfer!\n");
183 free(data_buf);
184 return NULL;
185 }
186
187 libusb_fill_interrupt_transfer(transfer, devh, EP_IN,
188 data_buf, ASYNC_SIZE, cb, data, USB_TIMEOUT);
189
190 transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK | LIBUSB_TRANSFER_FREE_BUFFER;
191
192 err = libusb_submit_transfer(transfer);
193 if (err != 0) {
194 fprintf(stderr, "Can't submit transfer: %s\n", usb_strerror(err));
195 libusb_free_transfer(transfer);
196 free(data_buf);
197 return NULL;
198 }
199
200 return transfer;
201 }
202
203 struct hmcfgusb_cb_data {
204 struct hmcfgusb_dev *dev;
205 hmcfgusb_cb_fn cb;
206 void *data;
207 };
208
209 static void LIBUSB_CALL hmcfgusb_interrupt(struct libusb_transfer *transfer)
210 {
211 int err;
212 struct hmcfgusb_cb_data *cb_data;
213
214 cb_data = transfer->user_data;
215
216 if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
217 if (transfer->status != LIBUSB_TRANSFER_TIMED_OUT) {
218 fprintf(stderr, "Interrupt transfer not completed: %d!\n", transfer->status);
219 quit = EIO;
220
221 if (cb_data && cb_data->dev && cb_data->dev->transfer) {
222 libusb_free_transfer(cb_data->dev->transfer);
223 cb_data->dev->transfer = NULL;
224 }
225 return;
226 }
227 } else {
228 if (cb_data && cb_data->cb) {
229 cb_data->cb(transfer->buffer, transfer->actual_length, cb_data->data);
230 } else {
231 hexdump(transfer->buffer, transfer->actual_length, "RECV> ");
232 }
233 }
234
235 err = libusb_submit_transfer(transfer);
236 if (err != 0) {
237 fprintf(stderr, "Can't re-submit transfer: %s\n", usb_strerror(err));
238 free(transfer->buffer);
239 libusb_free_transfer(transfer);
240 }
241 }
242
243 struct hmcfgusb_dev *hmcfgusb_init(hmcfgusb_cb_fn cb, void *data)
244 {
245 libusb_device_handle *devh = NULL;
246 const struct libusb_pollfd **usb_pfd = NULL;
247 struct hmcfgusb_dev *dev = NULL;
248 struct hmcfgusb_cb_data *cb_data = NULL;
249 int err;
250 int i;
251
252 err = libusb_init(NULL);
253 if (err != 0) {
254 fprintf(stderr, "Can't initialize libusb: %s\n", usb_strerror(err));
255 return NULL;
256 }
257
258 devh = hmcfgusb_find();
259 if (!devh) {
260 fprintf(stderr, "Can't find/open hmcfgusb!\n");
261 return NULL;
262 }
263
264 dev = malloc(sizeof(struct hmcfgusb_dev));
265 if (!dev) {
266 perror("Can't allocate memory for hmcfgusb_dev");
267 return NULL;
268 }
269
270 memset(dev, 0, sizeof(struct hmcfgusb_dev));
271 dev->usb_devh = devh;
272
273 cb_data = malloc(sizeof(struct hmcfgusb_cb_data));
274 if (!cb_data) {
275 perror("Can't allocate memory for hmcfgusb_cb_data");
276 return NULL;
277 }
278
279 memset(cb_data, 0, sizeof(struct hmcfgusb_cb_data));
280
281 cb_data->dev = dev;
282 cb_data->cb = cb;
283 cb_data->data = data;
284
285 dev->transfer = hmcfgusb_prepare_int(devh, hmcfgusb_interrupt, cb_data);
286 if (!dev->transfer) {
287 fprintf(stderr, "Can't prepare async device io!\n");
288 return NULL;
289 }
290
291 usb_pfd = libusb_get_pollfds(NULL);
292 if (!usb_pfd) {
293 fprintf(stderr, "Can't get FDset from libusb!\n");
294 free(dev);
295 return NULL;
296 }
297
298 dev->n_usb_pfd = 0;
299 for(i = 0; usb_pfd[i]; i++)
300 dev->n_usb_pfd++;
301
302 dev->pfd = malloc(dev->n_usb_pfd * sizeof(struct pollfd));
303 if (!dev->pfd) {
304 perror("Can't allocate memory for poll-fds");
305 return NULL;
306 }
307
308 memset(dev->pfd, 0, dev->n_usb_pfd * sizeof(struct pollfd));
309
310 for (i = 0; i < dev->n_usb_pfd; i++) {
311 dev->pfd[i].fd = usb_pfd[i]->fd;
312 dev->pfd[i].events = usb_pfd[i]->events;
313 dev->pfd[i].revents = 0;
314 }
315
316 free(usb_pfd);
317
318 dev->n_pfd = dev->n_usb_pfd;
319
320 return dev;
321 }
322
323 int hmcfgusb_add_pfd(struct hmcfgusb_dev *dev, int fd, short events)
324 {
325 dev->n_pfd++;
326 dev->pfd = realloc(dev->pfd, dev->n_pfd * sizeof(struct pollfd));
327 if (!dev->pfd) {
328 perror("Can't realloc poll-fds");
329 return 0;
330 }
331
332 dev->pfd[dev->n_pfd-1].fd = fd;
333 dev->pfd[dev->n_pfd-1].events = events;
334 dev->pfd[dev->n_pfd-1].revents = 0;
335
336 return 1;
337 }
338
339 int hmcfgusb_poll(struct hmcfgusb_dev *dev, int timeout)
340 {
341 struct timeval tv;
342 int usb_event = 0;
343 int i;
344 int n;
345 int fd_n;
346 int err;
347
348 errno = 0;
349
350 memset(&tv, 0, sizeof(tv));
351 err = libusb_get_next_timeout(NULL, &tv);
352 if (err < 0) {
353 fprintf(stderr, "libusb_get_next_timeout: %s\n", usb_strerror(err));
354 errno = EIO;
355 return -1;
356 } else if (err == 0) {
357 /* No pending timeout or a sane platform */
358 tv.tv_sec = timeout;
359 } else {
360 if ((tv.tv_sec == 0) && (tv.tv_usec == 0)) {
361 usb_event = 1;
362 }
363 }
364
365 if (!usb_event) {
366 for (i = 0; i < dev->n_pfd; i++) {
367 dev->pfd[i].revents = 0;
368 }
369
370 n = poll(dev->pfd, dev->n_pfd, tv.tv_sec * 1000);
371 if (n < 0) {
372 perror("poll");
373 return -1;
374 } else if (n == 0) {
375 usb_event = 1;
376 } else {
377 for (fd_n = 0; fd_n < dev->n_pfd; fd_n++) {
378 if (dev->pfd[fd_n].revents) {
379 if (fd_n < dev->n_usb_pfd) {
380 usb_event = 1;
381 break;
382 } else {
383 return dev->pfd[fd_n].fd;
384 }
385 }
386 }
387 }
388 }
389
390 if (usb_event) {
391 memset(&tv, 0, sizeof(tv));
392 err = libusb_handle_events_timeout_completed(NULL, &tv, NULL);
393 if (err < 0) {
394 fprintf(stderr, "libusb_handle_events_timeout_completed: %s\n", usb_strerror(err));
395 errno = EIO;
396 return -1;
397 }
398 }
399
400 if (quit)
401 errno = quit;
402
403 return -1;
404 }
405
406 void hmcfgusb_close(struct hmcfgusb_dev *dev)
407 {
408 int err;
409
410 if (dev->transfer) {
411 libusb_cancel_transfer(dev->transfer);
412 }
413
414 err = libusb_release_interface(dev->usb_devh, INTERFACE);
415 if ((err != 0)) {
416 fprintf(stderr, "Can't release interface: %s\n", usb_strerror(err));
417 }
418
419 libusb_close(dev->usb_devh);
420 free(dev);
421
422 libusb_exit(NULL);
423 }
Impressum, Datenschutz