X-Git-Url: http://cvs.zerfleddert.de/cgi-bin/gitweb.cgi/hmcfgusb/blobdiff_plain/27bb301b7f08c691d95bed7b935a0c0a0144373d..5e961a89167e50682e5ae87cf352a484de09ae64:/hmcfgusb.c diff --git a/hmcfgusb.c b/hmcfgusb.c index 9b00c84..0bcb5ae 100644 --- a/hmcfgusb.c +++ b/hmcfgusb.c @@ -34,7 +34,7 @@ #include "hexdump.h" #include "hmcfgusb.h" -#define USB_TIMEOUT 10000 +#define USB_TIMEOUT 10000 #define ID_VENDOR 0x1b1f #define ID_PRODUCT 0xc00f @@ -46,7 +46,10 @@ #define EP_OUT 0x02 #define EP_IN 0x83 +#define INTERFACE 0 + static int quit = 0; +static int debug = 0; /* Not in all libusb-1.0 versions, so we have to roll our own :-( */ static char * usb_strerror(int e) @@ -116,13 +119,13 @@ static libusb_device_handle *hmcfgusb_find() { return NULL; } - err = libusb_detach_kernel_driver(devh, 0); + err = libusb_detach_kernel_driver(devh, INTERFACE); if ((err != 0) && (err != LIBUSB_ERROR_NOT_FOUND)) { fprintf(stderr, "Can't detach kernel driver: %s\n", usb_strerror(err)); return NULL; } - err = libusb_claim_interface(devh, 0); + err = libusb_claim_interface(devh, INTERFACE); if ((err != 0)) { fprintf(stderr, "Can't claim interface: %s\n", usb_strerror(err)); return NULL; @@ -140,13 +143,12 @@ int hmcfgusb_send(struct hmcfgusb_dev *usbdev, unsigned char* send_data, int len { int err; int cnt; - int ret; + if (debug) + hexdump(send_data, len, "USB < "); err = libusb_interrupt_transfer(usbdev->usb_devh, EP_OUT, send_data, len, &cnt, USB_TIMEOUT); if (err) { fprintf(stderr, "Can't send data: %s\n", usb_strerror(err)); - if (err == LIBUSB_ERROR_NO_DEVICE) - exit(EXIT_FAILURE); return 0; } @@ -154,13 +156,11 @@ int hmcfgusb_send(struct hmcfgusb_dev *usbdev, unsigned char* send_data, int len err = libusb_interrupt_transfer(usbdev->usb_devh, EP_OUT, send_data, 0, &cnt, USB_TIMEOUT); if (err) { fprintf(stderr, "Can't send data: %s\n", usb_strerror(err)); - if (err == LIBUSB_ERROR_NO_DEVICE) - exit(EXIT_FAILURE); return 0; } } - return ret; + return 1; } static struct libusb_transfer *hmcfgusb_prepare_int(libusb_device_handle *devh, libusb_transfer_cb_fn cb, void *data) @@ -185,13 +185,12 @@ static struct libusb_transfer *hmcfgusb_prepare_int(libusb_device_handle *devh, libusb_fill_interrupt_transfer(transfer, devh, EP_IN, data_buf, ASYNC_SIZE, cb, data, USB_TIMEOUT); - transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK; + transfer->flags = LIBUSB_TRANSFER_SHORT_NOT_OK | LIBUSB_TRANSFER_FREE_BUFFER; err = libusb_submit_transfer(transfer); if (err != 0) { fprintf(stderr, "Can't submit transfer: %s\n", usb_strerror(err)); libusb_free_transfer(transfer); - free(data_buf); return NULL; } @@ -199,6 +198,7 @@ static struct libusb_transfer *hmcfgusb_prepare_int(libusb_device_handle *devh, } struct hmcfgusb_cb_data { + struct hmcfgusb_dev *dev; hmcfgusb_cb_fn cb; void *data; }; @@ -208,26 +208,47 @@ static void LIBUSB_CALL hmcfgusb_interrupt(struct libusb_transfer *transfer) int err; struct hmcfgusb_cb_data *cb_data; + cb_data = transfer->user_data; + if (transfer->status != LIBUSB_TRANSFER_COMPLETED) { if (transfer->status != LIBUSB_TRANSFER_TIMED_OUT) { fprintf(stderr, "Interrupt transfer not completed: %d!\n", transfer->status); quit = EIO; + + if (cb_data && cb_data->dev && cb_data->dev->transfer) { + libusb_free_transfer(cb_data->dev->transfer); + cb_data->dev->transfer = NULL; + free(cb_data); + } return; } } else { - cb_data = transfer->user_data; if (cb_data && cb_data->cb) { - cb_data->cb(transfer->buffer, transfer->actual_length, cb_data->data); + if (debug) + hexdump(transfer->buffer, transfer->actual_length, "USB > "); + + if (!cb_data->cb(transfer->buffer, transfer->actual_length, cb_data->data)) { + quit = EIO; + + if (cb_data && cb_data->dev && cb_data->dev->transfer) { + libusb_free_transfer(cb_data->dev->transfer); + cb_data->dev->transfer = NULL; + free(cb_data); + } + + return; + } } else { - hexdump(transfer->buffer, transfer->actual_length, "RECV> "); + hexdump(transfer->buffer, transfer->actual_length, "> "); } } err = libusb_submit_transfer(transfer); if (err != 0) { fprintf(stderr, "Can't re-submit transfer: %s\n", usb_strerror(err)); - free(transfer->buffer); libusb_free_transfer(transfer); + cb_data->dev->transfer = NULL; + free(cb_data); } } @@ -264,17 +285,21 @@ struct hmcfgusb_dev *hmcfgusb_init(hmcfgusb_cb_fn cb, void *data) cb_data = malloc(sizeof(struct hmcfgusb_cb_data)); if (!cb_data) { perror("Can't allocate memory for hmcfgusb_cb_data"); + free(dev); return NULL; } memset(cb_data, 0, sizeof(struct hmcfgusb_cb_data)); + cb_data->dev = dev; cb_data->cb = cb; cb_data->data = data; dev->transfer = hmcfgusb_prepare_int(devh, hmcfgusb_interrupt, cb_data); if (!dev->transfer) { fprintf(stderr, "Can't prepare async device io!\n"); + free(dev); + free(cb_data); return NULL; } @@ -282,6 +307,7 @@ struct hmcfgusb_dev *hmcfgusb_init(hmcfgusb_cb_fn cb, void *data) if (!usb_pfd) { fprintf(stderr, "Can't get FDset from libusb!\n"); free(dev); + free(cb_data); return NULL; } @@ -292,6 +318,8 @@ struct hmcfgusb_dev *hmcfgusb_init(hmcfgusb_cb_fn cb, void *data) dev->pfd = malloc(dev->n_usb_pfd * sizeof(struct pollfd)); if (!dev->pfd) { perror("Can't allocate memory for poll-fds"); + free(dev); + free(cb_data); return NULL; } @@ -307,6 +335,8 @@ struct hmcfgusb_dev *hmcfgusb_init(hmcfgusb_cb_fn cb, void *data) dev->n_pfd = dev->n_usb_pfd; + quit = 0; + return dev; } @@ -360,6 +390,7 @@ int hmcfgusb_poll(struct hmcfgusb_dev *dev, int timeout) n = poll(dev->pfd, dev->n_pfd, tv.tv_sec * 1000); if (n < 0) { perror("poll"); + errno = 0; return -1; } else if (n == 0) { usb_event = 1; @@ -370,6 +401,7 @@ int hmcfgusb_poll(struct hmcfgusb_dev *dev, int timeout) usb_event = 1; break; } else { + errno = 0; return dev->pfd[fd_n].fd; } } @@ -387,8 +419,36 @@ int hmcfgusb_poll(struct hmcfgusb_dev *dev, int timeout) } } - if (quit) + errno = 0; + if (quit) { + fprintf(stderr, "closing device-connection due to error %d\n", quit); errno = quit; + } return -1; } + +void hmcfgusb_close(struct hmcfgusb_dev *dev) +{ + int err; + + if (dev->transfer) { + libusb_cancel_transfer(dev->transfer); + } + + err = libusb_release_interface(dev->usb_devh, INTERFACE); + if ((err != 0)) { + fprintf(stderr, "Can't release interface: %s\n", usb_strerror(err)); + } + + libusb_close(dev->usb_devh); + free(dev->pfd); + free(dev); + + libusb_exit(NULL); +} + +void hmcfgusb_set_debug(int d) +{ + debug = d; +}