]> git.zerfleddert.de Git - hmcfgusb/blobdiff - hmcfgusb.c
gracefully handle errors on socket-write
[hmcfgusb] / hmcfgusb.c
index 9b00c84eecb43dbd51b88ce33f59dc81140bd213..7ec07142553c45b86a587df47c2213632eb7f7df 100644 (file)
@@ -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
 #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,25 +208,42 @@ 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;
+                       }
                        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;
+                               }
+
+                               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);
        }
 }
@@ -269,6 +286,7 @@ struct hmcfgusb_dev *hmcfgusb_init(hmcfgusb_cb_fn cb, void *data)
 
        memset(cb_data, 0, sizeof(struct hmcfgusb_cb_data));
 
+       cb_data->dev = dev;
        cb_data->cb = cb;
        cb_data->data = data;
 
@@ -307,6 +325,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 +380,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 +391,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 +409,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;
+}
Impressum, Datenschutz