xpp: fix usb "clear_halt" problem
authorOron Peled <oron.peled@xorcom.com>
Sun, 11 May 2014 13:41:46 +0000 (09:41 -0400)
committerTzafrir Cohen <tzafrir.cohen@xorcom.com>
Sun, 11 May 2014 15:03:11 +0000 (18:03 +0300)
 * Don't use "usb_clear_halt" by default anymore
   - It caused problems with specific devices in the past
   - Now it cause problems with specific servers as well (64 bits, USB3)

 * Add an "XTALK_OPTIONS" environment variable to pass options:
   - Use it to implement a "use-clear-halt" boolean option that
     restore original behavior.
   - Also use it for "no-lock" option which replace the legacy
     environment variable "XUSB_NOLOCK".

xpp/xtalk/xusb.c

index 70bc656..dcc694a 100644 (file)
@@ -61,6 +61,21 @@ struct xusb {
 
 static void xusb_init();
 
+/*
+ * XTALK_OPTIONS:
+ *     A white-space separated list of options, read from the environment
+ *     variable of that name. Existing options:
+ *
+ *     - "use-clear-halt" -- force USB "clear_halt" operation during
+ *                           device initialization
+ *     - "no-lock" -- prevent using global sempahore to serialize libusb
+ *                    initialization. Previously done via "XUSB_NOLOCK"
+ *                    environment variable.
+ */
+int xtalk_parse_options(void);
+int xtalk_option_use_clear_halt(void);
+int xtalk_option_no_lock(void);
+
 void xusb_init_spec(struct xusb_spec *spec, char *name,
                uint16_t vendor_id, uint16_t product_id,
                int nifaces, int iface, int nep, int ep_out, int ep_in)
@@ -257,13 +272,16 @@ int xusb_claim_interface(struct xusb *xusb)
                xusb->iProduct,
                xusb->iSerialNumber,
                xusb->iInterface);
-       if (usb_clear_halt(xusb->handle, EP_OUT(xusb)) != 0) {
-               ERR("Clearing output endpoint: %s\n", usb_strerror());
-               return 0;
-       }
-       if (usb_clear_halt(xusb->handle, EP_IN(xusb)) != 0) {
-               ERR("Clearing input endpoint: %s\n", usb_strerror());
-               return 0;
+       if (xtalk_option_use_clear_halt()) {
+               DBG("Using clear_halt()\n");
+               if (usb_clear_halt(xusb->handle, EP_OUT(xusb)) != 0) {
+                       ERR("Clearing output endpoint: %s\n", usb_strerror());
+                       return 0;
+               }
+               if (usb_clear_halt(xusb->handle, EP_IN(xusb)) != 0) {
+                       ERR("Clearing input endpoint: %s\n", usb_strerror());
+                       return 0;
+               }
        }
        ret = xusb_flushread(xusb);
        if (ret < 0) {
@@ -857,13 +875,63 @@ static int                initizalized;
 static void xusb_init()
 {
        if (!initizalized) {
-               if (!getenv("XUSB_NOLOCK"))
+               xtalk_parse_options();
+               if (!xtalk_option_no_lock())
                        xusb_lock_usb();
                usb_init();
                usb_find_busses();
                usb_find_devices();
                initizalized = 1;
-               if (!getenv("XUSB_NOLOCK"))
+               if (!xtalk_option_no_lock())
                        xusb_unlock_usb();
        }
 }
+
+/* XTALK option handling */
+static int use_clear_halt = 0;
+static int libusb_no_lock = 0;
+
+static int xtalk_one_option(const char *option_string)
+{
+       if (strcmp(option_string, "use-clear-halt") == 0) {
+               use_clear_halt = 1;
+               return 0;
+       }
+       if (strcmp(option_string, "no-lock") == 0) {
+               libusb_no_lock = 1;
+               return 0;
+       }
+       ERR("Unknown XTALK_OPTIONS content: '%s'\n", option_string);
+       return -EINVAL;
+}
+
+int xtalk_option_use_clear_halt(void)
+{
+       return use_clear_halt;
+}
+
+int xtalk_option_no_lock(void)
+{
+       return libusb_no_lock;
+}
+
+int xtalk_parse_options(void)
+{
+       char *xtalk_options;
+       char *saveptr;
+       char *token;
+       int ret;
+
+       xtalk_options = getenv("XTALK_OPTIONS");
+       if (!xtalk_options)
+               return 0;
+       token = strtok_r(xtalk_options, " \t", &saveptr);
+       while (token) {
+               ret = xtalk_one_option(token);
+               if (ret < 0)
+                       return ret;
+               token = strtok_r(NULL, " \t", &saveptr);
+       }
+       return 0;
+}
+