[PATCH 4/4] USB: UDC: Implement udc_async_callbacks in net2272

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds a udc_async_callbacks handler to the net2272 UDC
driver, which will prevent a theoretical race during gadget unbinding.

The net2272 driver is sufficiently complicated that I didn't want to
mess around with IRQ settings.  Instead, the patch simply adds a new
flag to control async callbacks, and checks the flag before issuing
any of them.

Signed-off-by: Alan Stern <stern@xxxxxxxxxxxxxxxxxxx>

---


[as1959]


 drivers/usb/gadget/udc/net2272.c |   41 +++++++++++++++++++++++++--------------
 drivers/usb/gadget/udc/net2272.h |    1 
 2 files changed, 28 insertions(+), 14 deletions(-)

Index: usb-devel/drivers/usb/gadget/udc/net2272.c
===================================================================
--- usb-devel.orig/drivers/usb/gadget/udc/net2272.c
+++ usb-devel/drivers/usb/gadget/udc/net2272.c
@@ -1149,6 +1149,7 @@ net2272_pullup(struct usb_gadget *_gadge
 static int net2272_start(struct usb_gadget *_gadget,
 		struct usb_gadget_driver *driver);
 static int net2272_stop(struct usb_gadget *_gadget);
+static void net2272_async_callbacks(struct usb_gadget *_gadget, bool enable);
 
 static const struct usb_gadget_ops net2272_ops = {
 	.get_frame	= net2272_get_frame,
@@ -1157,6 +1158,7 @@ static const struct usb_gadget_ops net22
 	.pullup		= net2272_pullup,
 	.udc_start	= net2272_start,
 	.udc_stop	= net2272_stop,
+	.udc_async_callbacks = net2272_async_callbacks,
 };
 
 /*---------------------------------------------------------------------------*/
@@ -1475,7 +1477,7 @@ stop_activity(struct net2272 *dev, struc
 		net2272_dequeue_all(&dev->ep[i]);
 
 	/* report disconnect; the driver is already quiesced */
-	if (driver) {
+	if (dev->async_callbacks && driver) {
 		spin_unlock(&dev->lock);
 		driver->disconnect(&dev->gadget);
 		spin_lock(&dev->lock);
@@ -1500,6 +1502,15 @@ static int net2272_stop(struct usb_gadge
 	return 0;
 }
 
+static void net2272_async_callbacks(struct usb_gadget *_gadget, bool enable)
+{
+	struct net2272	*dev = container_of(_gadget, struct net2272, gadget);
+
+	spin_lock_irq(&dev->lock);
+	dev->async_callbacks = enable;
+	spin_unlock_irq(&dev->lock);
+}
+
 /*---------------------------------------------------------------------------*/
 /* handle ep-a/ep-b dma completions */
 static void
@@ -1909,9 +1920,11 @@ net2272_handle_stat0_irqs(struct net2272
 				u.r.bRequestType, u.r.bRequest,
 				u.r.wValue, u.r.wIndex,
 				net2272_ep_read(ep, EP_CFG));
-			spin_unlock(&dev->lock);
-			tmp = dev->driver->setup(&dev->gadget, &u.r);
-			spin_lock(&dev->lock);
+			if (dev->async_callbacks) {
+				spin_unlock(&dev->lock);
+				tmp = dev->driver->setup(&dev->gadget, &u.r);
+				spin_lock(&dev->lock);
+			}
 		}
 
 		/* stall ep0 on error */
@@ -1993,14 +2006,14 @@ net2272_handle_stat1_irqs(struct net2272
 			if (disconnect || reset) {
 				stop_activity(dev, dev->driver);
 				net2272_ep0_start(dev);
-				spin_unlock(&dev->lock);
-				if (reset)
-					usb_gadget_udc_reset
-						(&dev->gadget, dev->driver);
-				else
-					(dev->driver->disconnect)
-						(&dev->gadget);
-				spin_lock(&dev->lock);
+				if (dev->async_callbacks) {
+					spin_unlock(&dev->lock);
+					if (reset)
+						usb_gadget_udc_reset(&dev->gadget, dev->driver);
+					else
+						(dev->driver->disconnect)(&dev->gadget);
+					spin_lock(&dev->lock);
+				}
 				return;
 			}
 		}
@@ -2014,14 +2027,14 @@ net2272_handle_stat1_irqs(struct net2272
 	if (stat & tmp) {
 		net2272_write(dev, IRQSTAT1, tmp);
 		if (stat & (1 << SUSPEND_REQUEST_INTERRUPT)) {
-			if (dev->driver->suspend)
+			if (dev->async_callbacks && dev->driver->suspend)
 				dev->driver->suspend(&dev->gadget);
 			if (!enable_suspend) {
 				stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT);
 				dev_dbg(dev->dev, "Suspend disabled, ignoring\n");
 			}
 		} else {
-			if (dev->driver->resume)
+			if (dev->async_callbacks && dev->driver->resume)
 				dev->driver->resume(&dev->gadget);
 		}
 		stat &= ~tmp;
Index: usb-devel/drivers/usb/gadget/udc/net2272.h
===================================================================
--- usb-devel.orig/drivers/usb/gadget/udc/net2272.h
+++ usb-devel/drivers/usb/gadget/udc/net2272.h
@@ -442,6 +442,7 @@ struct net2272 {
 	         softconnect:1,
 	         wakeup:1,
 		 added:1,
+		 async_callbacks:1,
 	         dma_eot_polarity:1,
 	         dma_dack_polarity:1,
 	         dma_dreq_polarity:1,



[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux