From patchwork Thu Sep 22 10:53:12 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "\(Exiting\) Baolin Wang" X-Patchwork-Id: 104671 Delivered-To: patch@linaro.org Received: by 10.140.106.72 with SMTP id d66csp2525458qgf; Thu, 22 Sep 2016 03:54:14 -0700 (PDT) X-Received: by 10.98.87.157 with SMTP id i29mr2145685pfj.97.1474541654529; Thu, 22 Sep 2016 03:54:14 -0700 (PDT) Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id yr6si1656893pab.4.2016.09.22.03.54.14; Thu, 22 Sep 2016 03:54:14 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-usb-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org; spf=pass (google.com: best guess record for domain of linux-usb-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-usb-owner@vger.kernel.org; dmarc=fail (p=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932631AbcIVKyL (ORCPT + 4 others); Thu, 22 Sep 2016 06:54:11 -0400 Received: from mail-pa0-f50.google.com ([209.85.220.50]:34337 "EHLO mail-pa0-f50.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751895AbcIVKyK (ORCPT ); Thu, 22 Sep 2016 06:54:10 -0400 Received: by mail-pa0-f50.google.com with SMTP id wk8so28269338pab.1 for ; Thu, 22 Sep 2016 03:54:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=RDKsHzZU3OwzxmnRA9HT0mX+g/eqVkrDDfBbF5bGdqs=; b=kG/FxWTTt55AWfKgHPt4BlRlKTLAydbTraUEdvJNttwKMowfyyf5Ejj4cJYVzA8WYN n3D/9wqScjYkrq0831rlTAX0wemSMR2+Oi5N3EmiX0aRDe12gq1bphBp2r77GRxo/W5p 9k/Y+JGQuBrk16DfUrMiMd5S+oab/5RcC2Ncs= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=RDKsHzZU3OwzxmnRA9HT0mX+g/eqVkrDDfBbF5bGdqs=; b=Cnb0ycCH62Vo4a0yfR3npRtBbvPnWUMuhb/1MnoaUiESFHeLGHcSAm0CGG/Zq3kfZV AC2QmmuyoGj/vr9N4N5q4DyTsFfPBntL2fjLf0+ZoNarR0We1ZPuf+hNIPuR4JXrBSlU D4IpGUPnxguZ6r5F9ueawLN+pflYkNEhvJ0Z1hstAsBRB9lF3ZIyf38/MTOnvjhyiEC4 mg1iU4GflmY10xSGGoIsPps8rbBOjIZzM1mlDd4FhZY17GQWjbyPJGHz21WKUqx3QMx6 kYRhLaYy+GsRaCU0EKjuvZiWbgfVgFsNNqFxvHUsUqPQFaSNI2Ujby4reHrYu0mbwa+z +X+Q== X-Gm-Message-State: AE9vXwPQQAzqUXpE/2Ry4bGH937UYqYALqQ7d/n/FM06EJjLWCIni5bOoG6c1ixcDq1+nffH X-Received: by 10.67.22.132 with SMTP id hs4mr2192891pad.88.1474541649321; Thu, 22 Sep 2016 03:54:09 -0700 (PDT) Received: from baolinwangubtpc.spreadtrum.com ([175.111.195.49]) by smtp.gmail.com with ESMTPSA id v6sm3242505pfv.8.2016.09.22.03.54.06 (version=TLS1 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Thu, 22 Sep 2016 03:54:08 -0700 (PDT) From: Baolin Wang To: balbi@kernel.org, gregkh@linuxfoundation.org Cc: Badhri@google.com, broonie@kernel.org, linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, baolin.wang@linaro.org Subject: [PATCH] usb: gadget: Add uevent to notify userspace Date: Thu, 22 Sep 2016 18:53:12 +0800 Message-Id: <97a7938a44dc6850dc6c94c36242231f0431210c.1474541017.git.baolin.wang@linaro.org> X-Mailer: git-send-email 1.7.9.5 Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org From: Badhri Jagan Sridharan Some USB managament on userspace (like Android system) rely on the uevents generated by the composition driver to generate user notifications. Thus this patch adds uevents to be generated whenever USB changes its state: connected, disconnected, configured. The original code was created by Badhri Jagan Sridharan, and I did some optimization. CC: Badhri Jagan Sridharan Signed-off-by: Baolin Wang --- drivers/usb/gadget/Kconfig | 8 +++ drivers/usb/gadget/configfs.c | 107 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 2ea3fc3..9f5d0c6 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -223,6 +223,14 @@ config USB_CONFIGFS appropriate symbolic links. For more information see Documentation/usb/gadget_configfs.txt. +config USB_CONFIGFS_UEVENT + boolean "Uevent notification of Gadget state" + depends on USB_CONFIGFS + help + Enable uevent notifications to userspace when the gadget + state changes. The gadget can be in any of the following + three states: "CONNECTED/DISCONNECTED/CONFIGURED" + config USB_CONFIGFS_SERIAL bool "Generic serial bulk in/out" depends on USB_CONFIGFS diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 3984787..4c2bc27 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -60,6 +60,11 @@ struct gadget_info { bool use_os_desc; char b_vendor_code; char qw_sign[OS_STRING_QW_SIGN_LEN]; +#ifdef CONFIG_USB_CONFIGFS_UEVENT + bool connected; + bool sw_connected; + struct work_struct work; +#endif }; static inline struct gadget_info *to_gadget_info(struct config_item *item) @@ -1197,6 +1202,57 @@ int composite_dev_prepare(struct usb_composite_driver *composite, int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, struct usb_ep *ep0); +#ifdef CONFIG_USB_CONFIGFS_UEVENT +static void configfs_work(struct work_struct *data) +{ + struct gadget_info *gi = container_of(data, struct gadget_info, work); + struct usb_composite_dev *cdev = &gi->cdev; + char *disconnected[2] = { "USB_STATE=DISCONNECTED", NULL }; + char *connected[2] = { "USB_STATE=CONNECTED", NULL }; + char *configured[2] = { "USB_STATE=CONFIGURED", NULL }; + /* 0-connected 1-configured 2-disconnected */ + bool status[3] = { false, false, false }; + unsigned long flags; + bool uevent_sent = false; + + spin_lock_irqsave(&cdev->lock, flags); + if (cdev->config && gi->connected) + status[1] = true; + + if (gi->connected != gi->sw_connected) { + if (gi->connected) + status[0] = true; + else + status[2] = true; + gi->sw_connected = gi->connected; + } + spin_unlock_irqrestore(&cdev->lock, flags); + + if (status[0]) { + kobject_uevent_env(&gi->dev->kobj, KOBJ_CHANGE, connected); + pr_info("%s: sent uevent %s\n", __func__, connected[0]); + uevent_sent = true; + } + + if (status[1]) { + kobject_uevent_env(&gi->dev->kobj, KOBJ_CHANGE, configured); + pr_info("%s: sent uevent %s\n", __func__, configured[0]); + uevent_sent = true; + } + + if (status[2]) { + kobject_uevent_env(&gi->dev->kobj, KOBJ_CHANGE, disconnected); + pr_info("%s: sent uevent %s\n", __func__, disconnected[0]); + uevent_sent = true; + } + + if (!uevent_sent) { + pr_info("%s: did not send uevent (%d %d %p)\n", __func__, + gi->connected, gi->sw_connected, cdev->config); + } +} +#endif + static void purge_configs_funcs(struct gadget_info *gi) { struct usb_configuration *c; @@ -1386,13 +1442,60 @@ static void configfs_composite_unbind(struct usb_gadget *gadget) set_gadget_data(gadget, NULL); } +#ifdef CONFIG_USB_CONFIGFS_UEVENT +static int configfs_setup(struct usb_gadget *gadget, + const struct usb_ctrlrequest *c) +{ + struct usb_composite_dev *cdev = get_gadget_data(gadget); + struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev); + int value = -EOPNOTSUPP; + unsigned long flags; + + spin_lock_irqsave(&cdev->lock, flags); + if (!gi->connected) { + gi->connected = 1; + schedule_work(&gi->work); + } + spin_unlock_irqrestore(&cdev->lock, flags); + + value = composite_setup(gadget, c); + + spin_lock_irqsave(&cdev->lock, flags); + if (c->bRequest == USB_REQ_SET_CONFIGURATION && cdev->config) + schedule_work(&gi->work); + spin_unlock_irqrestore(&cdev->lock, flags); + + return value; +} + +static void configfs_disconnect(struct usb_gadget *gadget) +{ + struct usb_composite_dev *cdev = get_gadget_data(gadget); + struct gadget_info *gi = container_of(cdev, struct gadget_info, cdev); + unsigned long flags; + + spin_lock_irqsave(&cdev->lock, flags); + gi->connected = 0; + schedule_work(&gi->work); + spin_unlock_irqrestore(&cdev->lock, flags); + + composite_disconnect(gadget); +} +#endif + static const struct usb_gadget_driver configfs_driver_template = { .bind = configfs_composite_bind, .unbind = configfs_composite_unbind, +#ifdef CONFIG_USB_CONFIGFS_UEVENT + .setup = configfs_setup, + .reset = configfs_disconnect, + .disconnect = configfs_disconnect, +#else .setup = composite_setup, .reset = composite_disconnect, .disconnect = composite_disconnect, +#endif .suspend = composite_suspend, .resume = composite_resume, @@ -1453,6 +1556,10 @@ static struct config_group *gadgets_make( gi->composite.gadget_driver.function = kstrdup(name, GFP_KERNEL); gi->composite.name = gi->composite.gadget_driver.function; +#ifdef CONFIG_USB_CONFIGFS_UEVENT + INIT_WORK(&gi->work, configfs_work); +#endif + if (!gi->composite.gadget_driver.function) goto err;