Modify the URB routine to cause the problem.
authorKim Gunsoo <gunsoo83.kim@samsung.com>
Tue, 7 Jun 2016 07:51:02 +0000 (16:51 +0900)
committerKim Gunsoo <gunsoo83.kim@samsung.com>
Tue, 7 Jun 2016 08:22:43 +0000 (17:22 +0900)
- When transferring USB data with devices in Linux, the packet
  structure is not initialized and shared by another thread.
  Fixed to be initialized at the time of each transfer
  and to manage the packet for each thread.

Change-Id: I65f8fffb5db3e9320b1afa57a993e373be0a7250
Signed-off-by: Kim Gunsoo <gunsoo83.kim@samsung.com>
src/usb_linux.c

index f6ea2172bf980ba2523941bb4bdbffe742d476ef..7d48558a0bd63981b2f0a5281bf9d05a262722e1 100644 (file)
@@ -40,6 +40,9 @@
 #include "transport.h"
 
 #define   TRACE_TAG  TRACE_USB
+#define   DEBUG_URB  0
+#define   LOG_DEBUG_URB(args...)  do { if (DEBUG_URB) LOG_DEBUG(args); } while (0)
+
 #define   URB_TRANSFER_TIMEOUT   0
 #define   USB_DEV_BASE_PATH     "/dev/bus/usb"
 #if SDB_USB_INOTIFY
@@ -52,6 +55,8 @@ SDB_MUTEX_DEFINE( usb_lock);
 
 LIST_NODE* usb_list = NULL;
 
+#define SDB_URB_TYPE_READ   0
+#define SDB_URB_TYPE_WRITE  1
 struct usb_handle {
     LIST_NODE* node;
 
@@ -59,6 +64,9 @@ struct usb_handle {
     int node_fd;
     unsigned char end_point[2]; // 0:in, 1:out
     int interface;
+
+    struct usbdevfs_urb urb_in;
+    struct usbdevfs_urb urb_out;
 };
 
 static int get_usb_device_serial_number(int usb_fd, __u8 serial_index, char* serial)
@@ -593,10 +601,10 @@ void sdb_usb_cleanup() {
 #define URB_USERCONTEXT_COOKIE      ((void *)0x1)
 
 static int usb_urb_transfer(usb_handle *h, int ep, char *bytes, int size,
-        int timeout) {
-    struct usbdevfs_urb urb;
+        int timeout, int rwtype) {
     int bytesdone = 0, requested;
     struct timeval tv, tv_ref, tv_now;
+    struct usbdevfs_urb *p_urb;
     struct usbdevfs_urb *context;
     int ret, waiting;
 
@@ -627,6 +635,7 @@ static int usb_urb_transfer(usb_handle *h, int ep, char *bytes, int size,
     }
 
     do {
+        LOG_DEBUG_URB("URB[%d]: do-while: entered\n", rwtype);
         fd_set writefds;
 
         requested = size - bytesdone;
@@ -635,21 +644,35 @@ static int usb_urb_transfer(usb_handle *h, int ep, char *bytes, int size,
             LOG_DEBUG("requested bytes over than %d\n", MAX_READ_WRITE);
         }
 
-        urb.type = USBDEVFS_URB_TYPE_BULK;
-        urb.endpoint = ep;
-        urb.flags = 0;
-        urb.buffer = bytes + bytesdone;
-        urb.buffer_length = requested;
-        urb.signr = 0;
-        urb.actual_length = 0;
-        urb.number_of_packets = 0; /* don't do isochronous yet */
-        urb.usercontext = NULL;
-
-        ret = ioctl(h->node_fd, USBDEVFS_SUBMITURB, &urb);
+        if ( rwtype == SDB_URB_TYPE_READ ) {
+            memset(&(h->urb_in), 0, sizeof(h->urb_in));
+            p_urb = &(h->urb_in);
+            LOG_DEBUG_URB("URB[%d]: READ urb type: p_urb=%p\n", rwtype, p_urb);
+        } else if ( rwtype == SDB_URB_TYPE_WRITE ) {
+            memset(&(h->urb_out), 0, sizeof(h->urb_out));
+            p_urb = &(h->urb_out);
+            LOG_DEBUG_URB("URB[%d]: WRITE urb type: p_urb=%p\n", rwtype, p_urb);
+        } else {
+            LOG_ERROR("Unknown URB type : %d\n", rwtype);
+            return -1;
+        }
+
+        p_urb->type = USBDEVFS_URB_TYPE_BULK;
+        p_urb->endpoint = ep;
+        p_urb->flags = 0;
+        p_urb->buffer = bytes + bytesdone;
+        p_urb->buffer_length = requested;
+        p_urb->signr = 0;
+        p_urb->actual_length = 0;
+        p_urb->number_of_packets = 0; /* don't do isochronous yet */
+        p_urb->usercontext = NULL;
+
+        ret = ioctl(h->node_fd, USBDEVFS_SUBMITURB, p_urb);
         if (ret < 0) {
             LOG_DEBUG("failed to submit urb: %s\n", strerror(errno));
             return -1;
         }
+        LOG_DEBUG_URB("URB[%d]: urb submit: p_urb=%p requested=%d, size=%d, bytesdone=%d\n", rwtype, p_urb, requested, size, bytesdone);
 
         FD_ZERO(&writefds);
         FD_SET(h->node_fd, &writefds);
@@ -659,7 +682,8 @@ static int usb_urb_transfer(usb_handle *h, int ep, char *bytes, int size,
         for (;;) {
             ret = ioctl(h->node_fd, USBDEVFS_REAPURBNDELAY, &context);
             int saved_errno = errno;
-            if (!urb.usercontext && (ret == -1) && waiting) {
+            LOG_DEBUG_URB("URB[%d]: urb reapndelay: ret=%d, saved_errno=%d, context=%p, waiting=%d, urb.usercontext=%p\n", rwtype, ret, saved_errno, context, waiting, p_urb->usercontext);
+            if (!p_urb->usercontext && (ret == -1) && waiting) {
                 // continue but,
                 if (saved_errno == ENODEV) {
                     LOG_DEBUG("device may be unplugged: %s\n", strerror(saved_errno));
@@ -686,9 +710,11 @@ static int usb_urb_transfer(usb_handle *h, int ep, char *bytes, int size,
             }
         }
 
-        if (context && context != &urb) {
+        LOG_DEBUG_URB("URB[%d]: leave reap loop: context=%p, p_urb=%p\n", rwtype, context, p_urb);
+        if (context && context != p_urb) {
             context->usercontext = URB_USERCONTEXT_COOKIE;
             /* We need to restart since we got a successful URB, but not ours */
+            LOG_DEBUG_URB("URB[%d]: usercontext cookie: not ours\n", rwtype);
             goto restart;
         }
 
@@ -697,25 +723,31 @@ static int usb_urb_transfer(usb_handle *h, int ep, char *bytes, int size,
          * something happened during the reaping and we should return that
          * error now
          */
-        if (ret < 0 && !urb.usercontext && errno != EAGAIN)
+        if (ret < 0 && !p_urb->usercontext && errno != EAGAIN)
             LOG_DEBUG("error reaping URB: %s\n", strerror(errno));
 
-        bytesdone += urb.actual_length;
-    } while ((ret == 0 || urb.usercontext) && bytesdone < size
-            && urb.actual_length == requested);
+        bytesdone += p_urb->actual_length;
+
+        LOG_DEBUG_URB("URB[%d]: do-while: check condition: ret=%d, urb.usercontext=%p, bytesdone=%d, size=%d, urb.actual_length=%d, requested=%d\n", rwtype, ret, p_urb->usercontext, bytesdone, size, p_urb->actual_length, requested);
+    } while ((ret == 0 || p_urb->usercontext) && bytesdone < size
+            && p_urb->actual_length == requested);
+    LOG_DEBUG_URB("URB[%d]: do-while: leaved\n", rwtype);
 
     /* If the URB didn't complete in success or error, then let's unlink it */
-    if (ret < 0 && !urb.usercontext) {
+    if (ret < 0 && !p_urb->usercontext) {
+        LOG_DEBUG_URB("URB[%d]: urb error case: entered\n", rwtype);
         int rc;
         if (!waiting)
             rc = -ETIMEDOUT;
         else
-            rc = urb.status;
+            rc = p_urb->status;
 
-        ret = ioctl(h->node_fd, USBDEVFS_DISCARDURB, &urb);
+        ret = ioctl(h->node_fd, USBDEVFS_DISCARDURB, p_urb);
         if (ret < 0 && errno != EINVAL)
             LOG_DEBUG("error discarding URB: %s\n", strerror(errno));
 
+        LOG_DEBUG_URB("URB[%d]: urb discard: ret=%d, errno=%d\n", rwtype, ret, errno);
+
         /*
          * When the URB is unlinked, it gets moved to the completed list and
          * then we need to reap it or else the next time we call this function,
@@ -725,9 +757,12 @@ static int usb_urb_transfer(usb_handle *h, int ep, char *bytes, int size,
         if (ret < 0 && errno != EINVAL)
             LOG_DEBUG("error reaping URB: %s\n", strerror(errno));
 
+        LOG_DEBUG_URB("URB[%d]: urb reap: ret=%d, errno=%d\n", rwtype, ret, errno);
+
         return rc;
     }
 
+    LOG_DEBUG_URB("URB[%d]: urb transfer done: bytesdone=%d\n", rwtype, bytesdone);
     return bytesdone;
 }
 
@@ -740,7 +775,7 @@ int sdb_usb_write(usb_handle *h, const void *_data, int len) {
     while (len > 0) {
         int xfer = (len > MAX_READ_WRITE) ? MAX_READ_WRITE : len;
 
-        n = usb_urb_transfer(h, h->end_point[1], data, xfer, URB_TRANSFER_TIMEOUT);
+        n = usb_urb_transfer(h, h->end_point[1], data, xfer, URB_TRANSFER_TIMEOUT, SDB_URB_TYPE_WRITE);
         if (n != xfer) {
             LOG_DEBUG("fail to usb write: n = %d, errno = %d (%s)\n", n, errno, strerror(errno));
             return -1;
@@ -764,7 +799,7 @@ int sdb_usb_read(usb_handle *h, void *_data, int len) {
     while (len > 0) {
         int xfer = (len > MAX_READ_WRITE) ? MAX_READ_WRITE : len;
 
-        n = usb_urb_transfer(h, h->end_point[0], data, xfer, URB_TRANSFER_TIMEOUT);
+        n = usb_urb_transfer(h, h->end_point[0], data, xfer, URB_TRANSFER_TIMEOUT, SDB_URB_TYPE_READ);
         if (n != xfer) {
             if ((errno == ETIMEDOUT)) {
                 LOG_DEBUG("usb bulk read timeout\n");