USB: fsl_qe_udc: Fix oops on QE UDC probe failure
[safe/jmp/linux-2.6] / drivers / usb / gadget / dummy_hcd.c
index e454775..9064696 100644 (file)
@@ -82,6 +82,7 @@ struct dummy_ep {
        const struct usb_endpoint_descriptor *desc;
        struct usb_ep                   ep;
        unsigned                        halted : 1;
+       unsigned                        wedged : 1;
        unsigned                        already_seen : 1;
        unsigned                        setup_stage : 1;
 };
@@ -365,16 +366,14 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
                case USB_SPEED_HIGH:
                        if (max == 512)
                                break;
-                       /* conserve return statements */
-               default:
-                       switch (max) {
-                       case 8: case 16: case 32: case 64:
+                       goto done;
+               case USB_SPEED_FULL:
+                       if (max == 8 || max == 16 || max == 32 || max == 64)
                                /* we'll fake any legal size */
                                break;
-                       default:
-               case USB_SPEED_LOW:
-                               goto done;
-                       }
+                       /* save a return statement */
+               default:
+                       goto done;
                }
                break;
        case USB_ENDPOINT_XFER_INT:
@@ -438,6 +437,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
        /* at this point real hardware should be NAKing transfers
         * to that endpoint, until a buffer is queued to it.
         */
+       ep->halted = ep->wedged = 0;
        retval = 0;
 done:
        return retval;
@@ -544,13 +544,14 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
                req->req.context = dum;
                req->req.complete = fifo_complete;
 
+               list_add_tail(&req->queue, &ep->queue);
                spin_unlock (&dum->lock);
                _req->actual = _req->length;
                _req->status = 0;
                _req->complete (_ep, _req);
                spin_lock (&dum->lock);
-       }
-       list_add_tail (&req->queue, &ep->queue);
+       }  else
+               list_add_tail(&req->queue, &ep->queue);
        spin_unlock_irqrestore (&dum->lock, flags);
 
        /* real hardware would likely enable transfers here, in case
@@ -598,7 +599,7 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
 }
 
 static int
-dummy_set_halt (struct usb_ep *_ep, int value)
+dummy_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
 {
        struct dummy_ep         *ep;
        struct dummy            *dum;
@@ -610,16 +611,32 @@ dummy_set_halt (struct usb_ep *_ep, int value)
        if (!dum->driver)
                return -ESHUTDOWN;
        if (!value)
-               ep->halted = 0;
+               ep->halted = ep->wedged = 0;
        else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
                        !list_empty (&ep->queue))
                return -EAGAIN;
-       else
+       else {
                ep->halted = 1;
+               if (wedged)
+                       ep->wedged = 1;
+       }
        /* FIXME clear emulated data toggle too */
        return 0;
 }
 
+static int
+dummy_set_halt(struct usb_ep *_ep, int value)
+{
+       return dummy_set_halt_and_wedge(_ep, value, 0);
+}
+
+static int dummy_set_wedge(struct usb_ep *_ep)
+{
+       if (!_ep || _ep->name == ep0name)
+               return -EINVAL;
+       return dummy_set_halt_and_wedge(_ep, 1, 1);
+}
+
 static const struct usb_ep_ops dummy_ep_ops = {
        .enable         = dummy_enable,
        .disable        = dummy_disable,
@@ -631,6 +648,7 @@ static const struct usb_ep_ops dummy_ep_ops = {
        .dequeue        = dummy_dequeue,
 
        .set_halt       = dummy_set_halt,
+       .set_wedge      = dummy_set_wedge,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -761,7 +779,8 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
                ep->ep.name = ep_name [i];
                ep->ep.ops = &dummy_ep_ops;
                list_add_tail (&ep->ep.ep_list, &dum->gadget.ep_list);
-               ep->halted = ep->already_seen = ep->setup_stage = 0;
+               ep->halted = ep->wedged = ep->already_seen =
+                               ep->setup_stage = 0;
                ep->ep.maxpacket = ~0;
                ep->last_io = jiffies;
                ep->gadget = &dum->gadget;
@@ -864,7 +883,7 @@ static int dummy_udc_probe (struct platform_device *pdev)
        /* maybe claim OTG support, though we won't complete HNP */
        dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0);
 
-       strcpy (dum->gadget.dev.bus_id, "gadget");
+       dev_set_name(&dum->gadget.dev, "gadget");
        dum->gadget.dev.parent = &pdev->dev;
        dum->gadget.dev.release = dummy_gadget_release;
        rc = device_register (&dum->gadget.dev);
@@ -894,7 +913,7 @@ static int dummy_udc_suspend (struct platform_device *pdev, pm_message_t state)
 {
        struct dummy    *dum = platform_get_drvdata(pdev);
 
-       dev_dbg (&pdev->dev, "%s\n", __FUNCTION__);
+       dev_dbg (&pdev->dev, "%s\n", __func__);
        spin_lock_irq (&dum->lock);
        dum->udc_suspended = 1;
        set_link_state (dum);
@@ -908,7 +927,7 @@ static int dummy_udc_resume (struct platform_device *pdev)
 {
        struct dummy    *dum = platform_get_drvdata(pdev);
 
-       dev_dbg (&pdev->dev, "%s\n", __FUNCTION__);
+       dev_dbg (&pdev->dev, "%s\n", __func__);
        spin_lock_irq (&dum->lock);
        dum->udc_suspended = 0;
        set_link_state (dum);
@@ -1352,7 +1371,7 @@ restart:
                                } else if (setup.bRequestType == Ep_Request) {
                                        // endpoint halt
                                        ep2 = find_endpoint (dum, w_index);
-                                       if (!ep2) {
+                                       if (!ep2 || ep2->ep.name == ep0name) {
                                                value = -EOPNOTSUPP;
                                                break;
                                        }
@@ -1381,7 +1400,8 @@ restart:
                                                value = -EOPNOTSUPP;
                                                break;
                                        }
-                                       ep2->halted = 0;
+                                       if (!ep2->wedged)
+                                               ep2->halted = 0;
                                        value = 0;
                                        status = 0;
                                }
@@ -1557,8 +1577,7 @@ hub_descriptor (struct usb_hub_descriptor *desc)
        memset (desc, 0, sizeof *desc);
        desc->bDescriptorType = 0x29;
        desc->bDescLength = 9;
-       desc->wHubCharacteristics = (__force __u16)
-                       (__constant_cpu_to_le16 (0x0001));
+       desc->wHubCharacteristics = cpu_to_le16(0x0001);
        desc->bNbrPorts = 1;
        desc->bitmap [0] = 0xff;
        desc->bitmap [1] = 0xff;
@@ -1709,7 +1728,7 @@ static int dummy_bus_suspend (struct usb_hcd *hcd)
 {
        struct dummy *dum = hcd_to_dummy (hcd);
 
-       dev_dbg (&hcd->self.root_hub->dev, "%s\n", __FUNCTION__);
+       dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
 
        spin_lock_irq (&dum->lock);
        dum->rh_state = DUMMY_RH_SUSPENDED;
@@ -1724,7 +1743,7 @@ static int dummy_bus_resume (struct usb_hcd *hcd)
        struct dummy *dum = hcd_to_dummy (hcd);
        int rc = 0;
 
-       dev_dbg (&hcd->self.root_hub->dev, "%s\n", __FUNCTION__);
+       dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
 
        spin_lock_irq (&dum->lock);
        if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
@@ -1868,7 +1887,7 @@ static int dummy_hcd_probe(struct platform_device *pdev)
 
        dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
 
-       hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, pdev->dev.bus_id);
+       hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
        if (!hcd)
                return -ENOMEM;
        the_controller = hcd_to_dummy (hcd);
@@ -1898,7 +1917,7 @@ static int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
        struct dummy            *dum;
        int                     rc = 0;
 
-       dev_dbg (&pdev->dev, "%s\n", __FUNCTION__);
+       dev_dbg (&pdev->dev, "%s\n", __func__);
 
        hcd = platform_get_drvdata (pdev);
        dum = hcd_to_dummy (hcd);
@@ -1914,7 +1933,7 @@ static int dummy_hcd_resume (struct platform_device *pdev)
 {
        struct usb_hcd          *hcd;
 
-       dev_dbg (&pdev->dev, "%s\n", __FUNCTION__);
+       dev_dbg (&pdev->dev, "%s\n", __func__);
 
        hcd = platform_get_drvdata (pdev);
        set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
@@ -1935,69 +1954,57 @@ static struct platform_driver dummy_hcd_driver = {
 
 /*-------------------------------------------------------------------------*/
 
-/* These don't need to do anything because the pdev structures are
- * statically allocated. */
-static void
-dummy_udc_release (struct device *dev) {}
-
-static void
-dummy_hcd_release (struct device *dev) {}
-
-static struct platform_device          the_udc_pdev = {
-       .name           = (char *) gadget_name,
-       .id             = -1,
-       .dev            = {
-               .release        = dummy_udc_release,
-       },
-};
-
-static struct platform_device          the_hcd_pdev = {
-       .name           = (char *) driver_name,
-       .id             = -1,
-       .dev            = {
-               .release        = dummy_hcd_release,
-       },
-};
+static struct platform_device *the_udc_pdev;
+static struct platform_device *the_hcd_pdev;
 
 static int __init init (void)
 {
-       int     retval;
+       int     retval = -ENOMEM;
 
        if (usb_disabled ())
                return -ENODEV;
 
-       retval = platform_driver_register (&dummy_hcd_driver);
-       if (retval < 0)
+       the_hcd_pdev = platform_device_alloc(driver_name, -1);
+       if (!the_hcd_pdev)
                return retval;
+       the_udc_pdev = platform_device_alloc(gadget_name, -1);
+       if (!the_udc_pdev)
+               goto err_alloc_udc;
 
-       retval = platform_driver_register (&dummy_udc_driver);
+       retval = platform_driver_register(&dummy_hcd_driver);
+       if (retval < 0)
+               goto err_register_hcd_driver;
+       retval = platform_driver_register(&dummy_udc_driver);
        if (retval < 0)
                goto err_register_udc_driver;
 
-       retval = platform_device_register (&the_hcd_pdev);
+       retval = platform_device_add(the_hcd_pdev);
        if (retval < 0)
-               goto err_register_hcd;
-
-       retval = platform_device_register (&the_udc_pdev);
+               goto err_add_hcd;
+       retval = platform_device_add(the_udc_pdev);
        if (retval < 0)
-               goto err_register_udc;
+               goto err_add_udc;
        return retval;
 
-err_register_udc:
-       platform_device_unregister (&the_hcd_pdev);
-err_register_hcd:
-       platform_driver_unregister (&dummy_udc_driver);
+err_add_udc:
+       platform_device_del(the_hcd_pdev);
+err_add_hcd:
+       platform_driver_unregister(&dummy_udc_driver);
 err_register_udc_driver:
-       platform_driver_unregister (&dummy_hcd_driver);
+       platform_driver_unregister(&dummy_hcd_driver);
+err_register_hcd_driver:
+       platform_device_put(the_udc_pdev);
+err_alloc_udc:
+       platform_device_put(the_hcd_pdev);
        return retval;
 }
 module_init (init);
 
 static void __exit cleanup (void)
 {
-       platform_device_unregister (&the_udc_pdev);
-       platform_device_unregister (&the_hcd_pdev);
-       platform_driver_unregister (&dummy_udc_driver);
-       platform_driver_unregister (&dummy_hcd_driver);
+       platform_device_unregister(the_udc_pdev);
+       platform_device_unregister(the_hcd_pdev);
+       platform_driver_unregister(&dummy_udc_driver);
+       platform_driver_unregister(&dummy_hcd_driver);
 }
 module_exit (cleanup);