lkml.org 
[lkml]   [2010]   [Nov]   [18]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v6] usb: Adding SuperSpeed support to dummy_hcd
    Date
    USB 3.0 hub includes 2 hubs - HS and SS ones.
    Thus, when dummy_hcd enabled it will register 2 root hubs (SS and HS).

    Signed-off-by: Tatyana Brokhman <tlinder@codeaurora.org>
    ---
    drivers/usb/gadget/dummy_hcd.c | 488 +++++++++++++++++++++++++++++++++++++++-
    1 files changed, 480 insertions(+), 8 deletions(-)

    diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
    index 13b9f47..2073e8d 100644
    --- a/drivers/usb/gadget/dummy_hcd.c
    +++ b/drivers/usb/gadget/dummy_hcd.c
    @@ -62,9 +62,12 @@
    #define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */

    static const char driver_name [] = "dummy_hcd";
    +static const char ss_driver_name[] = "ss_dummy_hcd";
    static const char driver_desc [] = "USB Host+Gadget Emulator";
    +static const char ss_driver_desc[] = "SS USB Host+Gadget Emulator";

    static const char gadget_name [] = "dummy_udc";
    +static const char ss_gadget_name[] = "ss_dummy_udc";

    MODULE_DESCRIPTION (DRIVER_DESC);
    MODULE_AUTHOR ("David Brownell");
    @@ -220,6 +223,7 @@ static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
    }

    static struct dummy *the_controller;
    +static struct dummy *the_ss_controller;

    /*-------------------------------------------------------------------------*/

    @@ -259,10 +263,94 @@ stop_activity (struct dummy *dum)
    /* driver now does any non-usb quiescing necessary */
    }

    -/* caller must hold lock */
    +/**
    + * set_ss_link_state() - Sets the current state of the SuperSpeed link
    + * @dum: pointer to the dummy_hcd structure to update the link
    + * state for
    + *
    + * This function updates the port_status according to the link
    + * state. The old status is saved befor updating.
    + * Note: this function should be called only for SuperSpeed
    + * master and the caller must hold the lock.
    + */
    +static void
    +set_ss_link_state(struct dummy *dum)
    +{
    + dum->active = 0;
    + if ((dum->port_status & USB_SS_PORT_STAT_POWER) == 0)
    + dum->port_status = 0;
    +
    + /* UDC suspend must cause a disconnect */
    + else if (!dum->pullup || dum->udc_suspended) {
    + dum->port_status &= ~(USB_PORT_STAT_CONNECTION |
    + USB_PORT_STAT_ENABLE);
    + if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0)
    + dum->port_status |=
    + (USB_PORT_STAT_C_CONNECTION << 16);
    + } else {
    + /* device is connected and not suspended */
    + dum->port_status |= (USB_PORT_STAT_CONNECTION |
    + USB_PORT_STAT_SUPER_SPEED);
    + if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0)
    + dum->port_status |=
    + (USB_PORT_STAT_C_CONNECTION << 16);
    + if ((dum->port_status & USB_PORT_STAT_ENABLE) == 1 &&
    + (dum->port_status & USB_SS_PORT_LS_U0) == 1 &&
    + dum->rh_state != DUMMY_RH_SUSPENDED)
    + dum->active = 1;
    + }
    +
    +
    + if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active)
    + dum->resuming = 0;
    +
    + /* if !connected or reset */
    + if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
    + (dum->port_status & USB_PORT_STAT_RESET) != 0) {
    + /*
    + * We're connected and not reseted (reset occured now),
    + * and driver attached - disconnect!
    + */
    + if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
    + (dum->old_status & USB_PORT_STAT_RESET) == 0 &&
    + dum->driver) {
    + stop_activity(dum);
    + spin_unlock(&dum->lock);
    + dum->driver->disconnect(&dum->gadget);
    + spin_lock(&dum->lock);
    + }
    + } else if (dum->active != dum->old_active) {
    + if (dum->old_active && dum->driver->suspend) {
    + spin_unlock(&dum->lock);
    + dum->driver->suspend(&dum->gadget);
    + spin_lock(&dum->lock);
    + } else if (!dum->old_active && dum->driver->resume) {
    + spin_unlock(&dum->lock);
    + dum->driver->resume(&dum->gadget);
    + spin_lock(&dum->lock);
    + }
    + }
    +
    + dum->old_status = dum->port_status;
    + dum->old_active = dum->active;
    +}
    +
    +/**
    + * set_link_state() - Sets the current state of the link
    + * @dum: pointer to the dummy_hcd structure to update the link
    + * state for
    + *
    + * This function updates the port_status according to the link
    + * state. The old status is saved befor updating.
    + * Note: caller must hold the lock.
    + */
    static void
    set_link_state (struct dummy *dum)
    {
    + if (dum == the_ss_controller) {
    + set_ss_link_state(dum);
    + return;
    + }
    dum->active = 0;
    if ((dum->port_status & USB_PORT_STAT_POWER) == 0)
    dum->port_status = 0;
    @@ -343,7 +431,13 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
    dum = ep_to_dummy (ep);
    if (!dum->driver || !is_enabled (dum))
    return -ESHUTDOWN;
    - max = le16_to_cpu(desc->wMaxPacketSize) & 0x3ff;
    + max = le16_to_cpu(desc->wMaxPacketSize) ;
    + /*
    + * For HS/FS devices only bits 0..9 of the wMaxPacketSize represent the
    + * maximum packet size
    + */
    + if (dum->gadget.speed < USB_SPEED_SUPER)
    + max &= 0x3ff;

    /* drivers must not request bad settings, since lower levels
    * (hardware or its drivers) may not check. some endpoints
    @@ -361,6 +455,10 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
    goto done;
    }
    switch (dum->gadget.speed) {
    + case USB_SPEED_SUPER:
    + if (max == 1024)
    + break;
    + goto done;
    case USB_SPEED_HIGH:
    if (max == 512)
    break;
    @@ -379,6 +477,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
    goto done;
    /* real hardware might not handle all packet sizes */
    switch (dum->gadget.speed) {
    + case USB_SPEED_SUPER:
    case USB_SPEED_HIGH:
    if (max <= 1024)
    break;
    @@ -399,6 +498,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
    goto done;
    /* real hardware might not handle all packet sizes */
    switch (dum->gadget.speed) {
    + case USB_SPEED_SUPER:
    case USB_SPEED_HIGH:
    if (max <= 1024)
    break;
    @@ -751,9 +851,14 @@ int
    usb_gadget_probe_driver(struct usb_gadget_driver *driver,
    int (*bind)(struct usb_gadget *))
    {
    - struct dummy *dum = the_controller;
    + struct dummy *dum;
    int retval, i;

    + if (driver->speed == USB_SPEED_SUPER)
    + dum = the_ss_controller;
    + else
    + dum = the_controller;
    +
    if (!dum)
    return -EINVAL;
    if (dum->driver)
    @@ -787,7 +892,11 @@ usb_gadget_probe_driver(struct usb_gadget_driver *driver,
    }

    dum->gadget.ep0 = &dum->ep [0].ep;
    - dum->ep [0].ep.maxpacket = 64;
    + dum->gadget.speed = driver->speed;
    + if (driver->speed == USB_SPEED_SUPER)
    + dum->ep[0].ep.maxpacket = 9;
    + else
    + dum->ep[0].ep.maxpacket = 64;
    list_del_init (&dum->ep [0].ep.ep_list);
    INIT_LIST_HEAD(&dum->fifo_req.queue);

    @@ -817,12 +926,20 @@ EXPORT_SYMBOL(usb_gadget_probe_driver);
    int
    usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
    {
    - struct dummy *dum = the_controller;
    + struct dummy *dum ;
    unsigned long flags;

    + if (!driver || !driver->unbind)
    + return -EINVAL;
    +
    + if (driver->speed == USB_SPEED_SUPER)
    + dum = the_ss_controller;
    + else
    + dum = the_controller;
    +
    if (!dum)
    return -ENODEV;
    - if (!driver || driver != dum->driver || !driver->unbind)
    + if (driver != dum->driver)
    return -EINVAL;

    dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
    @@ -899,6 +1016,34 @@ static int dummy_udc_probe (struct platform_device *pdev)
    return rc;
    }

    +static int dummy_ss_udc_probe(struct platform_device *pdev)
    +{
    + struct dummy *dum = the_ss_controller;
    + int rc;
    +
    + dum->gadget.name = gadget_name;
    + dum->gadget.ops = &dummy_ops;
    + dum->gadget.is_dualspeed = 1;
    +
    + /* maybe claim OTG support, though we won't complete HNP */
    + dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0);
    +
    + dev_set_name(&dum->gadget.dev, "ss_gadget");
    + dum->gadget.dev.parent = &pdev->dev;
    + dum->gadget.dev.release = dummy_gadget_release;
    + rc = device_register(&dum->gadget.dev);
    + if (rc < 0)
    + return rc;
    +
    + usb_get_hcd(dummy_to_hcd(dum));
    +
    + platform_set_drvdata(pdev, dum);
    + rc = device_create_file(&dum->gadget.dev, &dev_attr_function);
    + if (rc < 0)
    + device_unregister(&dum->gadget.dev);
    + return rc;
    +}
    +
    static int dummy_udc_remove (struct platform_device *pdev)
    {
    struct dummy *dum = platform_get_drvdata (pdev);
    @@ -948,6 +1093,17 @@ static struct platform_driver dummy_udc_driver = {
    },
    };

    +static struct platform_driver dummy_ss_udc_driver = {
    + .probe = dummy_ss_udc_probe,
    + .remove = dummy_udc_remove,
    + .suspend = dummy_udc_suspend,
    + .resume = dummy_udc_resume,
    + .driver = {
    + .name = (char *) ss_gadget_name,
    + .owner = THIS_MODULE,
    + },
    +};
    +
    /*-------------------------------------------------------------------------*/

    /* MASTER/HOST SIDE DRIVER
    @@ -1246,6 +1402,24 @@ static int handle_control_request(struct dummy *dum, struct urb *urb,
    case USB_DEVICE_A_ALT_HNP_SUPPORT:
    dum->gadget.a_alt_hnp_support = 1;
    break;
    + case USB_DEVICE_U1_ENABLE:
    + if (dum->gadget.speed == USB_SPEED_SUPER)
    + w_value = USB_DEV_STAT_U1_ENABLED;
    + else
    + ret_val = -EOPNOTSUPP;
    + break;
    + case USB_DEVICE_U2_ENABLE:
    + if (dum->gadget.speed == USB_SPEED_SUPER)
    + w_value = USB_DEV_STAT_U2_ENABLED;
    + else
    + ret_val = -EOPNOTSUPP;
    + break;
    + case USB_DEVICE_LTM_ENABLE:
    + if (dum->gadget.speed == USB_SPEED_SUPER)
    + w_value = USB_DEV_STAT_LTM_ENABLED;
    + else
    + ret_val = -EOPNOTSUPP;
    + break;
    default:
    ret_val = -EOPNOTSUPP;
    }
    @@ -1272,6 +1446,24 @@ static int handle_control_request(struct dummy *dum, struct urb *urb,
    case USB_DEVICE_REMOTE_WAKEUP:
    w_value = USB_DEVICE_REMOTE_WAKEUP;
    break;
    + case USB_DEVICE_U1_ENABLE:
    + if (dum->gadget.speed == USB_SPEED_SUPER)
    + w_value = USB_DEV_STAT_U1_ENABLED;
    + else
    + ret_val = -EOPNOTSUPP;
    + break;
    + case USB_DEVICE_U2_ENABLE:
    + if (dum->gadget.speed == USB_SPEED_SUPER)
    + w_value = USB_DEV_STAT_U2_ENABLED;
    + else
    + ret_val = -EOPNOTSUPP;
    + break;
    + case USB_DEVICE_LTM_ENABLE:
    + if (dum->gadget.speed == USB_SPEED_SUPER)
    + w_value = USB_DEV_STAT_LTM_ENABLED;
    + else
    + ret_val = -EOPNOTSUPP;
    + break;
    default:
    ret_val = -EOPNOTSUPP;
    break;
    @@ -1352,6 +1544,9 @@ static void dummy_timer (unsigned long _dum)
    case USB_SPEED_HIGH:
    total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
    break;
    + case USB_SPEED_SUPER:
    + total = 400 << 20; /* 400MB = 400*(2^20) bytes */
    + break;
    default:
    dev_err (dummy_dev(dum), "bogus device speed\n");
    return;
    @@ -1597,7 +1792,172 @@ hub_descriptor (struct usb_hub_descriptor *desc)
    desc->bitmap [1] = 0xff;
    }

    -static int dummy_hub_control (
    +/**
    + * dummy_ss_hub_control() - handles the control requests of the dummy (ss hub)
    + * master.
    + * @hcd: pointer to the hcd to handle
    + * @typeReq: type of the request
    + * @wValue: wValue of the request
    + * @wIndex: wIndex of the request
    + * @buf: buffer for reply in case of an IN request
    + * @wLength: wLength of the request
    + *
    + * Return int - 0 on success, error code otherwise
    + *
    + * This function handles the control requests of the dummy (ss
    + * hub) master. All control requests that are part of the
    + * enumeration are handled by the dummy_timer
    + * Note: this function is used only for the SS root hub
    + */
    +static int dummy_ss_hub_control(
    + struct usb_hcd *hcd,
    + u16 typeReq,
    + u16 wValue,
    + u16 wIndex,
    + char *buf,
    + u16 wLength)
    +{
    + struct dummy *dum;
    + int retval = 0;
    + unsigned long flags;
    +
    + if (!HCD_HW_ACCESSIBLE(hcd))
    + return -ETIMEDOUT;
    +
    + dum = hcd_to_dummy(hcd);
    + spin_lock_irqsave(&dum->lock, flags);
    + switch (typeReq) {
    + case ClearHubFeature:
    + break;
    + case ClearPortFeature:
    + switch (wValue) {
    + case USB_PORT_FEAT_POWER:
    + if (dum->port_status & USB_SS_PORT_STAT_POWER)
    + dev_dbg(dummy_dev(dum), "power-off\n");
    + /* FALLS THROUGH */
    + default:
    + dum->port_status &= ~(1 << wValue);
    + set_link_state(dum);
    + }
    + break;
    + case GetHubDescriptor:
    + hub_descriptor((struct usb_hub_descriptor *) buf);
    + break;
    + case GetHubStatus:
    + /*
    + * We report that no change occured in the hub status
    + * (power and overcurent conditions)
    + */
    + *(__le32 *) buf = cpu_to_le32 (0);
    + break;
    + case GetPortStatus:
    + /* We have only one port */
    + if (wIndex != 1)
    + retval = -EPIPE;
    +
    + /*
    + * whoever resets or resumes must GetPortStatus to
    + * complete it!!
    + */
    + /* TODO: add support for suspend/resume */
    + if ((dum->port_status & USB_PORT_STAT_RESET) != 0 &&
    + time_after_eq(jiffies, dum->re_timeout)) {
    + dum->port_status |= (USB_PORT_STAT_C_RESET << 16);
    + dum->port_status &= ~USB_PORT_STAT_RESET;
    + }
    + if (dum->pullup)
    + dum->port_status |= USB_PORT_STAT_ENABLE;
    +
    + set_link_state(dum);
    +
    + ((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status);
    + ((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
    + break;
    + case SetHubFeature:
    + retval = -EPIPE;
    + break;
    + case SetPortFeature:
    + switch (wValue) {
    + case USB_PORT_FEAT_LINK_STATE:
    + /*
    + * Since this is dummy we don't have an actual link so
    + * there is nothing to do for the SET_LINK_STATE cmd
    + */
    + break;
    + case USB_PORT_FEAT_U1_TIMEOUT:
    + case USB_PORT_FEAT_U2_TIMEOUT:
    + /* TODO: add suspend/resume support! */
    + break;
    + case USB_PORT_FEAT_POWER:
    + dum->port_status |= USB_SS_PORT_STAT_POWER;
    + set_link_state(dum);
    + break;
    + case USB_PORT_FEAT_BH_PORT_RESET:
    + case USB_PORT_FEAT_RESET:
    + /* if it's already enabled, disable */
    + dum->port_status = 0;
    + dum->port_status = (USB_SS_PORT_STAT_POWER |
    + USB_PORT_STAT_CONNECTION |
    + USB_PORT_STAT_RESET);
    + /*
    + * We want to reset device status. All but the
    + * Self powered feature
    + */
    + dum->devstatus &= 0x0000 |
    + (1 << USB_DEVICE_SELF_POWERED);
    + /*
    + * FIXME: what is the correct reset signaling interval?
    + * Is it still 50msec as for HS?
    + */
    + dum->re_timeout = jiffies + msecs_to_jiffies(50);
    + /* FALLS THROUGH */
    + default:
    + if ((dum->port_status &
    + USB_SS_PORT_STAT_POWER) != 0) {
    + dum->port_status |= (1 << wValue);
    + set_link_state(dum);
    + }
    + }
    + break;
    + case GetPortErrorCount:
    + /* We'll always return 0 since this is a dummy hub */
    + *(__le32 *) buf = cpu_to_le32 (0);
    + break;
    + case SetHubDepth:
    + break;
    + default:
    + dev_dbg(dummy_dev(dum),
    + "hub control req%04x v%04x i%04x l%d\n",
    + typeReq, wValue, wIndex, wLength);
    + /* "protocol stall" on error */
    + retval = -EPIPE;
    + }
    + spin_unlock_irqrestore(&dum->lock, flags);
    +
    + if ((dum->port_status & PORT_C_MASK) != 0)
    + usb_hcd_poll_rh_status(hcd);
    + return retval;
    +}
    +
    +
    +/**
    + * dummy_hub_control() - handles the control requests of the dummy (hs hub)
    + * master.
    + * @hcd: pointer to the hcd to handle
    + * @typeReq: type of the request
    + * @wValue: wValue of the request
    + * @wIndex: wIndex of the request
    + * @buf: buffer for reply in case of an IN request
    + * @wLength: wLength of the request
    + *
    + * Return int - 0 on success, error code otherwise
    + *
    + * This function handles the control requests of the dummy (hs
    + * hub) master. All control requests that are part of the
    + * enumeration are handled by the dummy_timer
    + * Note: this function is used only for the HS root hub
    + */
    +static int dummy_hub_control(
    struct usb_hcd *hcd,
    u16 typeReq,
    u16 wValue,
    @@ -1711,7 +2071,11 @@ static int dummy_hub_control (
    dum->port_status &= ~(USB_PORT_STAT_ENABLE
    | USB_PORT_STAT_LOW_SPEED
    | USB_PORT_STAT_HIGH_SPEED);
    - dum->devstatus = 0;
    + /*
    + * We want to reset device status. All but the
    + * Self powered feature
    + */
    + dum->devstatus &= (1 << USB_DEVICE_SELF_POWERED);
    /* 50msec reset signaling */
    dum->re_timeout = jiffies + msecs_to_jiffies(50);
    /* FALLS THROUGH */
    @@ -1894,6 +2258,27 @@ static const struct hc_driver dummy_hcd = {
    .bus_resume = dummy_bus_resume,
    };

    +static const struct hc_driver dummy_ss_hcd = {
    + .description = (char *) ss_driver_name,
    + .product_desc = "Dummy SS host controller",
    + .hcd_priv_size = sizeof(struct dummy),
    +
    + .flags = HCD_USB3,
    +
    + .start = dummy_start,
    + .stop = dummy_stop,
    +
    + .urb_enqueue = dummy_urb_enqueue,
    + .urb_dequeue = dummy_urb_dequeue,
    +
    + .get_frame_number = dummy_h_get_frame,
    +
    + .hub_status_data = dummy_hub_status,
    + .hub_control = dummy_ss_hub_control,
    + .bus_suspend = dummy_bus_suspend,
    + .bus_resume = dummy_bus_resume,
    +};
    +
    static int dummy_hcd_probe(struct platform_device *pdev)
    {
    struct usb_hcd *hcd;
    @@ -1914,6 +2299,26 @@ static int dummy_hcd_probe(struct platform_device *pdev)
    return retval;
    }

    +static int dummy_hcd_probe_ss(struct platform_device *pdev)
    +{
    + struct usb_hcd *hcd;
    + int retval;
    +
    + dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", ss_driver_desc);
    +
    + hcd = usb_create_hcd(&dummy_ss_hcd, &pdev->dev, dev_name(&pdev->dev));
    + if (!hcd)
    + return -ENOMEM;
    + the_ss_controller = hcd_to_dummy(hcd);
    +
    + retval = usb_add_hcd(hcd, 0, 0);
    + if (retval != 0) {
    + usb_put_hcd(hcd);
    + the_ss_controller = NULL;
    + }
    + return retval;
    +}
    +
    static int dummy_hcd_remove (struct platform_device *pdev)
    {
    struct usb_hcd *hcd;
    @@ -1925,6 +2330,17 @@ static int dummy_hcd_remove (struct platform_device *pdev)
    return 0;
    }

    +static int dummy_ss_hcd_remove(struct platform_device *pdev)
    +{
    + struct usb_hcd *hcd;
    +
    + hcd = platform_get_drvdata(pdev);
    + usb_remove_hcd(hcd);
    + usb_put_hcd(hcd);
    + the_ss_controller = NULL;
    + return 0;
    +}
    +
    static int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
    {
    struct usb_hcd *hcd;
    @@ -1966,10 +2382,23 @@ static struct platform_driver dummy_hcd_driver = {
    },
    };

    +static struct platform_driver dummy_ss_hcd_driver = {
    + .probe = dummy_hcd_probe_ss,
    + .remove = dummy_ss_hcd_remove,
    + .suspend = dummy_hcd_suspend,
    + .resume = dummy_hcd_resume,
    + .driver = {
    + .name = (char *) ss_driver_name,
    + .owner = THIS_MODULE,
    + },
    +};
    +
    /*-------------------------------------------------------------------------*/

    static struct platform_device *the_udc_pdev;
    +static struct platform_device *the_ss_udc_pdev;
    static struct platform_device *the_hcd_pdev;
    +static struct platform_device *the_ss_hcd_pdev;

    static int __init init (void)
    {
    @@ -1981,34 +2410,73 @@ static int __init init (void)
    the_hcd_pdev = platform_device_alloc(driver_name, -1);
    if (!the_hcd_pdev)
    return retval;
    +
    + the_ss_hcd_pdev = platform_device_alloc(ss_driver_name, -1);
    + if (!the_ss_hcd_pdev)
    + goto err_alloc_ss_hcd;
    +
    the_udc_pdev = platform_device_alloc(gadget_name, -1);
    if (!the_udc_pdev)
    goto err_alloc_udc;

    + the_ss_udc_pdev = platform_device_alloc(ss_gadget_name, -1);
    + if (!the_ss_udc_pdev)
    + goto err_alloc_ss_udc;
    +
    retval = platform_driver_register(&dummy_hcd_driver);
    if (retval < 0)
    goto err_register_hcd_driver;
    +
    + retval = platform_driver_register(&dummy_ss_hcd_driver);
    + if (retval < 0)
    + goto err_register_ss_hcd_driver;
    +
    retval = platform_driver_register(&dummy_udc_driver);
    if (retval < 0)
    goto err_register_udc_driver;

    + retval = platform_driver_register(&dummy_ss_udc_driver);
    + if (retval < 0)
    + goto err_register_ss_udc_driver;
    +
    retval = platform_device_add(the_hcd_pdev);
    if (retval < 0)
    goto err_add_hcd;
    +
    + retval = platform_device_add(the_ss_hcd_pdev);
    + if (retval < 0)
    + goto err_add_ss_hcd;
    +
    retval = platform_device_add(the_udc_pdev);
    if (retval < 0)
    goto err_add_udc;
    +
    + retval = platform_device_add(the_ss_udc_pdev);
    + if (retval < 0)
    + goto err_add_ss_udc;
    return retval;

    +err_add_ss_udc:
    + platform_device_unregister(the_udc_pdev);
    err_add_udc:
    + platform_device_del(the_ss_hcd_pdev);
    +err_add_ss_hcd:
    platform_device_del(the_hcd_pdev);
    err_add_hcd:
    + platform_driver_unregister(&dummy_ss_udc_driver);
    +err_register_ss_udc_driver:
    platform_driver_unregister(&dummy_udc_driver);
    err_register_udc_driver:
    + platform_driver_unregister(&dummy_ss_hcd_driver);
    +err_register_ss_hcd_driver:
    platform_driver_unregister(&dummy_hcd_driver);
    err_register_hcd_driver:
    + platform_device_put(the_ss_udc_pdev);
    +err_alloc_ss_udc:
    platform_device_put(the_udc_pdev);
    err_alloc_udc:
    + platform_device_put(the_ss_hcd_pdev);
    +err_alloc_ss_hcd:
    platform_device_put(the_hcd_pdev);
    return retval;
    }
    @@ -2017,8 +2485,12 @@ module_init (init);
    static void __exit cleanup (void)
    {
    platform_device_unregister(the_udc_pdev);
    + platform_device_unregister(the_ss_udc_pdev);
    platform_device_unregister(the_hcd_pdev);
    + platform_device_unregister(the_ss_hcd_pdev);
    platform_driver_unregister(&dummy_udc_driver);
    + platform_driver_unregister(&dummy_ss_udc_driver);
    platform_driver_unregister(&dummy_hcd_driver);
    + platform_driver_unregister(&dummy_ss_hcd_driver);
    }
    module_exit (cleanup);
    --
    1.6.3.3
    --
    Sent by a consultant of the Qualcomm Innovation Center, Inc.
    The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum.


    \
     
     \ /
      Last update: 2010-11-18 14:01    [W:0.055 / U:34.304 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site