[media] cx231xx: reset pipe endpoint when it is stalled
authorTerry Heo <terryheo@google.com>
Thu, 28 Jul 2016 09:52:04 +0000 (06:52 -0300)
committerMauro Carvalho Chehab <mchehab@s-opensource.com>
Sat, 6 Aug 2016 11:32:17 +0000 (08:32 -0300)
Sometimes, the USB pipe could enter into a stalled state,
and may need a reset to rework.

Add such logic.

[mchehab@osg.samsung.com: ported from Android's source:
 https://android.googlesource.com/kernel/x86_64/+/3a322adc0084fd277b43070712c7dc0dc9245435%5E%21]

Signed-off-by: Terry Heo <terryheo@google.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
drivers/media/usb/cx231xx/cx231xx-core.c

index 630f4fc..3e304ba 100644 (file)
@@ -799,7 +799,7 @@ static void cx231xx_isoc_irq_callback(struct urb *urb)
        case -ESHUTDOWN:
                return;
        default:                /* error */
-               cx231xx_isocdbg("urb completition error %d.\n", urb->status);
+               cx231xx_isocdbg("urb completion error %d.\n", urb->status);
                break;
        }
 
@@ -842,8 +842,11 @@ static void cx231xx_bulk_irq_callback(struct urb *urb)
        case -ENOENT:
        case -ESHUTDOWN:
                return;
+       case -EPIPE:            /* stall */
+               cx231xx_isocdbg("urb completion error - device is stalled.\n");
+               return;
        default:                /* error */
-               cx231xx_isocdbg("urb completition error %d.\n", urb->status);
+               cx231xx_isocdbg("urb completion error %d.\n", urb->status);
                break;
        }
 
@@ -867,6 +870,7 @@ void cx231xx_uninit_isoc(struct cx231xx *dev)
        struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq;
        struct urb *urb;
        int i;
+       bool broken_pipe = false;
 
        cx231xx_isocdbg("cx231xx: called cx231xx_uninit_isoc\n");
 
@@ -886,12 +890,19 @@ void cx231xx_uninit_isoc(struct cx231xx *dev)
                                                  transfer_buffer[i],
                                                  urb->transfer_dma);
                        }
+                       if (urb->status == -EPIPE) {
+                               broken_pipe = true;
+                       }
                        usb_free_urb(urb);
                        dev->video_mode.isoc_ctl.urb[i] = NULL;
                }
                dev->video_mode.isoc_ctl.transfer_buffer[i] = NULL;
        }
 
+       if (broken_pipe) {
+               cx231xx_isocdbg("Reset endpoint to recover broken pipe.");
+               usb_reset_endpoint(dev->udev, dev->video_mode.end_point_addr);
+       }
        kfree(dev->video_mode.isoc_ctl.urb);
        kfree(dev->video_mode.isoc_ctl.transfer_buffer);
        kfree(dma_q->p_left_data);
@@ -918,6 +929,7 @@ void cx231xx_uninit_bulk(struct cx231xx *dev)
        struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq;
        struct urb *urb;
        int i;
+       bool broken_pipe = false;
 
        cx231xx_isocdbg("cx231xx: called cx231xx_uninit_bulk\n");
 
@@ -937,12 +949,19 @@ void cx231xx_uninit_bulk(struct cx231xx *dev)
                                                transfer_buffer[i],
                                                urb->transfer_dma);
                        }
+                       if (urb->status == -EPIPE) {
+                               broken_pipe = true;
+                       }
                        usb_free_urb(urb);
                        dev->video_mode.bulk_ctl.urb[i] = NULL;
                }
                dev->video_mode.bulk_ctl.transfer_buffer[i] = NULL;
        }
 
+       if (broken_pipe) {
+               cx231xx_isocdbg("Reset endpoint to recover broken pipe.");
+               usb_reset_endpoint(dev->udev, dev->video_mode.end_point_addr);
+       }
        kfree(dev->video_mode.bulk_ctl.urb);
        kfree(dev->video_mode.bulk_ctl.transfer_buffer);
        kfree(dma_q->p_left_data);