USB: gadget: composite: Use separate switches for connected and config state
authorMike Lockwood <lockwood@android.com>
Sat, 11 Dec 2010 00:30:15 +0000 (16:30 -0800)
committerMike Lockwood <lockwood@android.com>
Tue, 14 Dec 2010 17:24:54 +0000 (09:24 -0800)
Also remove disconnect debouncing, which didn't actually work on some platforms

Signed-off-by: Mike Lockwood <lockwood@android.com>
drivers/usb/gadget/composite.c
include/linux/usb/composite.h

index a664e29946206c204752e409068f95e5f9575f7a..3afbf523259d7476f629d6f7c9b276cc052031e2 100644 (file)
@@ -110,10 +110,7 @@ void usb_composite_force_reset(struct usb_composite_dev *cdev)
 
        spin_lock_irqsave(&cdev->lock, flags);
        /* force reenumeration */
-       if (cdev && cdev->gadget &&
-                       cdev->gadget->speed != USB_SPEED_UNKNOWN) {
-               /* avoid sending a disconnect switch event until after we disconnect */
-               cdev->mute_switch = 1;
+       if (cdev && cdev->gadget && cdev->gadget->speed != USB_SPEED_UNKNOWN) {
                spin_unlock_irqrestore(&cdev->lock, flags);
 
                usb_gadget_disconnect(cdev->gadget);
@@ -885,6 +882,14 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
        u16                             w_length = le16_to_cpu(ctrl->wLength);
        struct usb_function             *f = NULL;
        u8                              endp;
+       unsigned long                   flags;
+
+       spin_lock_irqsave(&cdev->lock, flags);
+       if (!cdev->connected) {
+               cdev->connected = 1;
+               schedule_work(&cdev->switch_work);
+       }
+       spin_unlock_irqrestore(&cdev->lock, flags);
 
        /* partial re-init of the response message; the function or the
         * gadget might need to intercept e.g. a control-OUT completion
@@ -1103,10 +1108,8 @@ static void composite_disconnect(struct usb_gadget *gadget)
        if (composite->disconnect)
                composite->disconnect(cdev);
 
-       if (cdev->mute_switch)
-               cdev->mute_switch = 0;
-       else
-               schedule_work(&cdev->switch_work);
+       cdev->connected = 0;
+       schedule_work(&cdev->switch_work);
        spin_unlock_irqrestore(&cdev->lock, flags);
 }
 
@@ -1169,7 +1172,8 @@ composite_unbind(struct usb_gadget *gadget)
                usb_ep_free_request(gadget->ep0, cdev->req);
        }
 
-       switch_dev_unregister(&cdev->sdev);
+       switch_dev_unregister(&cdev->sw_connected);
+       switch_dev_unregister(&cdev->sw_config);
        kfree(cdev);
        set_gadget_data(gadget, NULL);
        device_remove_file(&gadget->dev, &dev_attr_suspended);
@@ -1204,11 +1208,22 @@ composite_switch_work(struct work_struct *data)
        struct usb_composite_dev        *cdev =
                container_of(data, struct usb_composite_dev, switch_work);
        struct usb_configuration *config = cdev->config;
+       int connected;
+       unsigned long flags;
+
+       spin_lock_irqsave(&cdev->lock, flags);
+       if (cdev->connected != cdev->sw_connected.state) {
+               connected = cdev->connected;
+               spin_unlock_irqrestore(&cdev->lock, flags);
+               switch_set_state(&cdev->sw_connected, connected);
+       } else {
+               spin_unlock_irqrestore(&cdev->lock, flags);
+       }
 
        if (config)
-               switch_set_state(&cdev->sdev, config->bConfigurationValue);
+               switch_set_state(&cdev->sw_config, config->bConfigurationValue);
        else
-               switch_set_state(&cdev->sdev, 0);
+               switch_set_state(&cdev->sw_config, 0);
 }
 
 static int composite_bind(struct usb_gadget *gadget)
@@ -1262,8 +1277,12 @@ static int composite_bind(struct usb_gadget *gadget)
        if (status < 0)
                goto fail;
 
-       cdev->sdev.name = "usb_configuration";
-       status = switch_dev_register(&cdev->sdev);
+       cdev->sw_connected.name = "usb_connected";
+       status = switch_dev_register(&cdev->sw_connected);
+       if (status < 0)
+               goto fail;
+       cdev->sw_config.name = "usb_configuration";
+       status = switch_dev_register(&cdev->sw_config);
        if (status < 0)
                goto fail;
        INIT_WORK(&cdev->switch_work, composite_switch_work);
index f491e48b21e68e3c19da6f801c302a5cc8c9b706..cb28d4302781d00f8da3314d606f74637a8636fe 100644 (file)
@@ -357,9 +357,13 @@ struct usb_composite_dev {
        /* protects at least deactivation count */
        spinlock_t                      lock;
 
-       struct switch_dev sdev;
-       /* used by usb_composite_force_reset to avoid signalling switch changes */
-       bool                            mute_switch;
+       /* switch indicating connected/disconnected state */
+       struct switch_dev               sw_connected;
+       /* switch indicating current configuration */
+       struct switch_dev               sw_config;
+       /* current connected state for sw_connected */
+       bool                            connected;
+
        struct work_struct switch_work;
 };