From e6be8941f44a6561e9d42e759e5644d096bae7c7 Mon Sep 17 00:00:00 2001 From: Mike Lockwood <lockwood@android.com> Date: Fri, 10 Dec 2010 16:30:15 -0800 Subject: [PATCH] USB: gadget: composite: Use separate switches for connected and config state 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 | 45 ++++++++++++++++++++++++---------- include/linux/usb/composite.h | 10 +++++--- 2 files changed, 39 insertions(+), 16 deletions(-) diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c index 96d89870c2f6..75dd00038df5 100644 --- a/drivers/usb/gadget/composite.c +++ b/drivers/usb/gadget/composite.c @@ -114,10 +114,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); @@ -924,6 +921,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 @@ -1154,10 +1159,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); } @@ -1219,7 +1222,8 @@ composite_unbind(struct usb_gadget *gadget) kfree(cdev->req->buf); 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); device_remove_file(&gadget->dev, &dev_attr_suspended); kfree(cdev); set_gadget_data(gadget, NULL); @@ -1245,11 +1249,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) @@ -1301,8 +1316,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); diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h index 37352fc4601a..106c69c7d1a6 100644 --- a/include/linux/usb/composite.h +++ b/include/linux/usb/composite.h @@ -373,9 +373,13 @@ struct usb_composite_dev { /* protects deactivations and delayed_status counts*/ 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; }; -- 2.34.1