[PATCH 04/10] usb/amd5536udc: convert to new style interface

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

 



This patches converts the driver into the new style start/stop interface.
As a result the driver no longer uses the static global udc variable.
Since the driver is accessing global variables, there can be only one
device served at a time.
Compile tested only.

Cc: Thomas Dahlmann <dahlmann.thomas@xxxxxxxx>
Signed-off-by: Sebastian Andrzej Siewior <sebastian@xxxxxxxxxxxxx>
---
 drivers/usb/gadget/amd5536udc.c |  113 +++++++++++++++------------------------
 1 files changed, 43 insertions(+), 70 deletions(-)

diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index f0a05e3..5e63716 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -64,6 +64,7 @@
 /* udc specific */
 #include "amd5536udc.h"
 
+static atomic_t count_devices = ATOMIC_INIT(0);
 static void udc_tasklet_disconnect(struct udc *dev);
 static void empty_req_queue(struct udc_ep *);
 static int udc_probe(struct udc *dev);
@@ -89,9 +90,6 @@ static const struct usb_ep_ops udc_ep_ops;
 /* received setup data */
 static union udc_setup_data setup_data;
 
-/* pointer to device object */
-static struct udc *udc;
-
 /* irq spin lock for soft reset */
 static DEFINE_SPINLOCK(udc_irq_spinlock);
 /* stall spin lock */
@@ -1297,9 +1295,9 @@ static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq)
 				u32 tmp;
 				u32 dma_sts;
 				/* stop potential receive DMA */
-				tmp = readl(&udc->regs->ctl);
+				tmp = readl(&ep->dev->regs->ctl);
 				writel(tmp & AMD_UNMASK_BIT(UDC_DEVCTL_RDE),
-							&udc->regs->ctl);
+							&ep->dev->regs->ctl);
 				/*
 				 * Cancel transfer later in ISR
 				 * if descriptor was touched.
@@ -1313,7 +1311,7 @@ static int udc_dequeue(struct usb_ep *usbep, struct usb_request *usbreq)
 					writel(ep->bna_dummy_req->td_phys,
 						&ep->regs->desptr);
 				}
-				writel(tmp, &udc->regs->ctl);
+				writel(tmp, &ep->dev->regs->ctl);
 			}
 		}
 	}
@@ -1423,15 +1421,16 @@ static int udc_wakeup(struct usb_gadget *gadget)
 	return 0;
 }
 
-static int amd5536_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *));
-static int amd5536_stop(struct usb_gadget_driver *driver);
+static int amd5536_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver);
+static int amd5536_stop(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver);
 /* gadget operations */
 static const struct usb_gadget_ops udc_ops = {
 	.wakeup		= udc_wakeup,
 	.get_frame	= udc_get_frame,
-	.start		= amd5536_start,
-	.stop		= amd5536_stop,
+	.udc_start	= amd5536_start,
+	.udc_stop	= amd5536_stop,
 };
 
 /* Setups endpoint parameters, adds endpoints to linked list */
@@ -1708,6 +1707,7 @@ static void udc_soft_reset(struct udc *dev)
 /* RDE timer callback to set RDE bit */
 static void udc_timer_function(unsigned long v)
 {
+	struct udc *dev = (struct udc *)v;
 	u32 tmp;
 
 	spin_lock_irq(&udc_irq_spinlock);
@@ -1719,11 +1719,11 @@ static void udc_timer_function(unsigned long v)
 		 */
 		if (set_rde > 1) {
 			/* set RDE to receive setup data */
-			tmp = readl(&udc->regs->ctl);
+			tmp = readl(&dev->regs->ctl);
 			tmp |= AMD_BIT(UDC_DEVCTL_RDE);
-			writel(tmp, &udc->regs->ctl);
+			writel(tmp, &dev->regs->ctl);
 			set_rde = -1;
-		} else if (readl(&udc->regs->sts)
+		} else if (readl(&dev->regs->sts)
 				& AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
 			/*
 			 * if fifo empty setup polling, do not just
@@ -1754,7 +1754,6 @@ static void udc_timer_function(unsigned long v)
 	spin_unlock_irq(&udc_irq_spinlock);
 	if (stop_timer)
 		complete(&on_exit);
-
 }
 
 /* Handle halt state, used in stall poll timer */
@@ -1790,6 +1789,7 @@ static void udc_handle_halt_state(struct udc_ep *ep)
 /* Stall timer callback to poll S bit and set it again after */
 static void udc_pollstall_timer_function(unsigned long v)
 {
+	struct udc *dev = (struct udc *)v;
 	struct udc_ep *ep;
 	int halted = 0;
 
@@ -1798,12 +1798,12 @@ static void udc_pollstall_timer_function(unsigned long v)
 	 * only one IN and OUT endpoints are handled
 	 * IN poll stall
 	 */
-	ep = &udc->ep[UDC_EPIN_IX];
+	ep = &dev->ep[UDC_EPIN_IX];
 	udc_handle_halt_state(ep);
 	if (ep->halted)
 		halted = 1;
 	/* OUT poll stall */
-	ep = &udc->ep[UDC_EPOUT_IX];
+	ep = &dev->ep[UDC_EPOUT_IX];
 	udc_handle_halt_state(ep);
 	if (ep->halted)
 		halted = 1;
@@ -1935,41 +1935,26 @@ static int setup_ep0(struct udc *dev)
 }
 
 /* Called by gadget driver to register itself */
-static int amd5536_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+static int amd5536_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
-	struct udc		*dev = udc;
-	int			retval;
+	struct udc		*dev;
 	u32 tmp;
 
-	if (!driver || !bind || !driver->setup
-			|| driver->max_speed < USB_SPEED_HIGH)
+	if (driver->max_speed < USB_SPEED_HIGH)
 		return -EINVAL;
-	if (!dev)
-		return -ENODEV;
-	if (dev->driver)
-		return -EBUSY;
+	dev = container_of(gadget, struct udc, gadget);
 
 	driver->driver.bus = NULL;
 	dev->driver = driver;
 	dev->gadget.dev.driver = &driver->driver;
 
-	retval = bind(&dev->gadget);
-
 	/* Some gadget drivers use both ep0 directions.
 	 * NOTE: to gadget driver, ep0 is just one endpoint...
 	 */
 	dev->ep[UDC_EP0OUT_IX].ep.driver_data =
 		dev->ep[UDC_EP0IN_IX].ep.driver_data;
 
-	if (retval) {
-		DBG(dev, "binding to %s returning %d\n",
-				driver->driver.name, retval);
-		dev->driver = NULL;
-		dev->gadget.dev.driver = NULL;
-		return retval;
-	}
-
 	/* get ready for ep0 traffic */
 	setup_ep0(dev);
 
@@ -1984,19 +1969,10 @@ static int amd5536_start(struct usb_gadget_driver *driver,
 }
 
 /* shutdown requests and disconnect from gadget */
-static void
-shutdown(struct udc *dev, struct usb_gadget_driver *driver)
-__releases(dev->lock)
-__acquires(dev->lock)
+static void shutdown(struct udc *dev, struct usb_gadget_driver *driver)
 {
 	int tmp;
 
-	if (dev->gadget.speed != USB_SPEED_UNKNOWN) {
-		spin_unlock(&dev->lock);
-		driver->disconnect(&dev->gadget);
-		spin_lock(&dev->lock);
-	}
-
 	/* empty queues and init hardware */
 	udc_basic_init(dev);
 	for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
@@ -2006,23 +1982,20 @@ __acquires(dev->lock)
 }
 
 /* Called by gadget driver to unregister itself */
-static int amd5536_stop(struct usb_gadget_driver *driver)
+static int amd5536_stop(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
-	struct udc	*dev = udc;
+	struct udc	*dev = container_of(gadget, struct udc, gadget);
 	unsigned long	flags;
 	u32 tmp;
 
-	if (!dev)
-		return -ENODEV;
-	if (!driver || driver != dev->driver || !driver->unbind)
-		return -EINVAL;
+	dev = container_of (gadget, struct udc, gadget);
 
 	spin_lock_irqsave(&dev->lock, flags);
 	udc_mask_unused_interrupts(dev);
 	shutdown(dev, driver);
 	spin_unlock_irqrestore(&dev->lock, flags);
 
-	driver->unbind(&dev->gadget);
 	dev->gadget.dev.driver = NULL;
 	dev->driver = NULL;
 
@@ -2031,7 +2004,6 @@ static int amd5536_stop(struct usb_gadget_driver *driver)
 	tmp |= AMD_BIT(UDC_DEVCTL_SD);
 	writel(tmp, &dev->regs->ctl);
 
-
 	DBG(dev, "%s: unregistered\n", driver->driver.name);
 
 	return 0;
@@ -2584,9 +2556,9 @@ __acquires(dev->lock)
 			 * clear stall bits
 			 * only one IN and OUT endpoints are handled
 			 */
-			ep_tmp = &udc->ep[UDC_EPIN_IX];
+			ep_tmp = &dev->ep[UDC_EPIN_IX];
 			udc_set_halt(&ep_tmp->ep, 0);
-			ep_tmp = &udc->ep[UDC_EPOUT_IX];
+			ep_tmp = &dev->ep[UDC_EPOUT_IX];
 			udc_set_halt(&ep_tmp->ep, 0);
 		}
 
@@ -3012,7 +2984,7 @@ __acquires(dev->lock)
 			writel(tmp, &dev->regs->irqmsk);
 			DBG(dev, "USB Disconnect (session valid low)\n");
 			/* cleanup on disconnect */
-			usb_disconnect(udc);
+			usb_disconnect(dev);
 		}
 
 	}
@@ -3096,7 +3068,6 @@ static void udc_remove(struct udc *dev)
 		wait_for_completion(&on_pollstall_exit);
 	if (udc_pollstall_timer.data)
 		del_timer_sync(&udc_pollstall_timer);
-	udc = NULL;
 }
 
 /* Reset all pci context */
@@ -3106,7 +3077,7 @@ static void udc_pci_remove(struct pci_dev *pdev)
 
 	dev = pci_get_drvdata(pdev);
 
-	usb_del_gadget_udc(&udc->gadget);
+	usb_del_gadget_udc(&dev->gadget);
 	/* gadget driver must not be registered */
 	BUG_ON(dev->driver != NULL);
 
@@ -3142,6 +3113,7 @@ static void udc_pci_remove(struct pci_dev *pdev)
 	pci_set_drvdata(pdev, NULL);
 
 	udc_remove(dev);
+	atomic_dec(&count_devices);
 }
 
 /* create dma pools on init */
@@ -3211,11 +3183,13 @@ static int udc_pci_probe(
 	struct udc		*dev;
 	unsigned long		resource;
 	unsigned long		len;
-	int			retval = 0;
+	int			retval;
 
+	retval = atomic_inc_return(&count_devices);
 	/* one udc only */
-	if (udc) {
-		dev_dbg(&pdev->dev, "already probed\n");
+	if (retval > 1) {
+		dev_err(&pdev->dev, "Only one device is supported.\n");
+		atomic_dec(&count_devices);
 		return -EBUSY;
 	}
 
@@ -3307,9 +3281,9 @@ static int udc_pci_probe(
 	dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
 
 	/* general probing */
-	if (udc_probe(dev) == 0)
-		return 0;
-
+	retval = udc_probe(dev);
+	if (!retval)
+		return retval;
 finished:
 	if (dev)
 		udc_pci_remove(pdev);
@@ -3353,9 +3327,8 @@ static int udc_probe(struct udc *dev)
 	}
 	dev_info(&dev->pdev->dev,
 		"driver version: %s(for Geode5536 B1)\n", tmp);
-	udc = dev;
 
-	retval = usb_add_gadget_udc(&udc->pdev->dev, &dev->gadget);
+	retval = usb_add_gadget_udc(&dev->pdev->dev, &dev->gadget);
 	if (retval)
 		goto finished;
 
@@ -3369,11 +3342,11 @@ static int udc_probe(struct udc *dev)
 	/* timer init */
 	init_timer(&udc_timer);
 	udc_timer.function = udc_timer_function;
-	udc_timer.data = 1;
+	udc_timer.data = (unsigned long)dev;
 	/* timer pollstall init */
 	init_timer(&udc_pollstall_timer);
 	udc_pollstall_timer.function = udc_pollstall_timer_function;
-	udc_pollstall_timer.data = 1;
+	udc_pollstall_timer.data = (unsigned long)dev;
 
 	/* set SD */
 	reg = readl(&dev->regs->ctl);
-- 
1.7.8.3

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


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

  Powered by Linux