From patchwork Tue Apr 17 01:17:41 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerry Zhang X-Patchwork-Id: 10344129 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 8546F60216 for ; Tue, 17 Apr 2018 01:18:18 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 7E8D5288FE for ; Tue, 17 Apr 2018 01:18:18 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 7366D28915; Tue, 17 Apr 2018 01:18:18 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.8 required=2.0 tests=BAYES_00, DKIM_ADSP_CUSTOM_MED, DKIM_SIGNED, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DD6FB288FE for ; Tue, 17 Apr 2018 01:18:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751793AbeDQBSQ (ORCPT ); Mon, 16 Apr 2018 21:18:16 -0400 Received: from mail-pf0-f196.google.com ([209.85.192.196]:41582 "EHLO mail-pf0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751086AbeDQBSP (ORCPT ); Mon, 16 Apr 2018 21:18:15 -0400 Received: by mail-pf0-f196.google.com with SMTP id a2so11370485pff.8 for ; Mon, 16 Apr 2018 18:18:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=MsAu37nUbGaO15o/yAicmH3L9MUV06IdCBDVeRPbIdA=; b=jSAsBWlRTnwVik9JR31nlL6fnwANSxK5pBK1hzbrxik2HSCdqBvCeYmBWytJrNTmgF BIMHx2AR9ZuGrCALDetne0FANq797LQW8HO1A30sxQXgw6LX1CMJNoHgUGl20s5G3IH+ FgL7MDzn/3uPZVRMt4jH8CaR5BFKudLj8LQPhp73GZRalhH8L/ctgLOcf0UR5Re+Yn4Y B3tIMI55V/D9pkhh9R32WqTOM6lzmQb1w6ehpX242yDr5L/tvGaEj1JCeOwNXiUFVoJs k0iONSSv3lVdoWl65+XTeI5XNAJIHyj/ogdCBnf053jItd+OpiTzH8hybm5Ow/DT5ttB K90w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=MsAu37nUbGaO15o/yAicmH3L9MUV06IdCBDVeRPbIdA=; b=E85mNJjbM8Ib0xKFviiyG2rePxf+gAOABZwGZbAN/3g5q4ByWOpWu9Rwt3SjLvoha2 6Zyjvk1J3E0YzUaFDaGM5G3DX1v9/1l7aLAQRBxoI27e9oqLgTRSVMgPaR9rD3vPuAdU huIRFk6JKQQTvB5k07JiLh55BtQEBAxH5xyOtfBsMWP/vXNCg4/rCl9G2DIQwJVwDHCx Bd4hj9bPFMXSrHX9apc6Nm4NzCNqUJmsOF7i868Y+wBWy2aFefEhd2nt0ty8Dk/jH697 yfjhto4mGYFzb2XAeKMhdwtwSLXtfqHzSULK8c4Hf/XfnXUR0MlYKjNGVCBGMcWzfRCJ i1aA== X-Gm-Message-State: ALQs6tDUSI3NbXawOpgAiIm4xSosQbeMci8FZt2qMLkCARBSJ3hEDus1 aQtg5lhhV+kzovJu2CRhmvwSIA== X-Google-Smtp-Source: AIpwx49bH+2yeTccvgnEk+y0e1wZ6RqG+f1OFQPN3U92Yb91+mEWQAQsjZlUew6HEJYpzHAubGp+XA== X-Received: by 10.98.0.15 with SMTP id 15mr95817pfa.72.1523927894080; Mon, 16 Apr 2018 18:18:14 -0700 (PDT) Received: from zhangjerry.mtv.corp.google.com ([2620:0:1000:1611:ee20:2649:babf:1d14]) by smtp.gmail.com with ESMTPSA id x14sm12694919pgq.50.2018.04.16.18.18.13 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 16 Apr 2018 18:18:13 -0700 (PDT) From: Jerry Zhang To: Felipe Balbi , Greg Kroah-Hartman , linux-usb@vger.kernel.org Cc: Michal Nazarewicz , Krzysztof Opasiak , Badhri Jagan Sridharan , Andrzej Pietrasiewicz , Lars-Peter Clausen , felixhaedicke@web.de, Jerry Zhang Subject: [PATCH 2/3] usb: gadget: configfs: Create control_config group Date: Mon, 16 Apr 2018 18:17:41 -0700 Message-Id: <20180417011742.192184-3-zhangjerry@google.com> X-Mailer: git-send-email 2.17.0.484.g0c8726318c-goog In-Reply-To: <20180417011742.192184-1-zhangjerry@google.com> References: <20180417011742.192184-1-zhangjerry@google.com> Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Control_config is a group under gadget that acts as a normal config group, except it does not appear in cdev->configs. Functions can be linked into the config as normal, and those functions are bound and unbound with the rest of the gadget. Create configfs_setup(), which will first attempt composite setup. If that fails, it will go through functions in control_config and use req_match to find one that can handle the control request. This allows the user to create a functionfs instance dedicated to handling non-standard control requests no matter what functions or configurations are currently active. Signed-off-by: Jerry Zhang --- drivers/usb/gadget/configfs.c | 86 +++++++++++++++++++++++++++-------- 1 file changed, 68 insertions(+), 18 deletions(-) diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index efba66ca0719..b3acddda24c1 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -44,12 +44,22 @@ int check_user_usb_string(const char *name, static const struct usb_descriptor_header *otg_desc[2]; +struct config_usb_cfg { + struct config_group group; + struct config_group strings_group; + struct list_head string_list; + struct usb_configuration c; + struct list_head func_list; + struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1]; +}; + struct gadget_info { struct config_group group; struct config_group functions_group; struct config_group configs_group; struct config_group strings_group; struct config_group os_desc_group; + struct config_usb_cfg control_config; struct mutex lock; struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1]; @@ -68,15 +78,6 @@ static inline struct gadget_info *to_gadget_info(struct config_item *item) return container_of(to_config_group(item), struct gadget_info, group); } -struct config_usb_cfg { - struct config_group group; - struct config_group strings_group; - struct list_head string_list; - struct usb_configuration c; - struct list_head func_list; - struct usb_gadget_strings *gstrings[MAX_USB_STRING_LANGS + 1]; -}; - static inline struct config_usb_cfg *to_config_usb_cfg(struct config_item *item) { return container_of(to_config_group(item), struct config_usb_cfg, @@ -1205,11 +1206,10 @@ int composite_os_desc_req_prepare(struct usb_composite_dev *cdev, static void purge_configs_funcs(struct gadget_info *gi) { struct usb_configuration *c; + struct usb_function *f, *tmp; + struct config_usb_cfg *cfg; list_for_each_entry(c, &gi->cdev.configs, list) { - struct usb_function *f, *tmp; - struct config_usb_cfg *cfg; - cfg = container_of(c, struct config_usb_cfg, c); list_for_each_entry_safe(f, tmp, &c->functions, list) { @@ -1229,6 +1229,14 @@ static void purge_configs_funcs(struct gadget_info *gi) c->highspeed = 0; c->fullspeed = 0; } + + cfg = &gi->control_config; + c = &cfg->c; + list_for_each_entry_safe(f, tmp, &c->functions, list) { + list_move_tail(&f->list, &cfg->func_list); + if (f->unbind) + f->unbind(c, f); + } } static int configfs_composite_bind(struct usb_gadget *gadget, @@ -1242,6 +1250,9 @@ static int configfs_composite_bind(struct usb_gadget *gadget, struct usb_string *s; unsigned i; int ret; + struct config_usb_cfg *cfg; + struct usb_function *f; + struct usb_function *tmp; /* the gi->lock is hold by the caller */ cdev->gadget = gadget; @@ -1260,8 +1271,6 @@ static int configfs_composite_bind(struct usb_gadget *gadget, list_for_each_entry(c, &gi->cdev.configs, list) { - struct config_usb_cfg *cfg; - cfg = container_of(c, struct config_usb_cfg, c); if (list_empty(&cfg->func_list)) { pr_err("Config %s/%d of %s needs at least one function.\n", @@ -1320,9 +1329,6 @@ static int configfs_composite_bind(struct usb_gadget *gadget, /* Go through all configs, attach all functions */ list_for_each_entry(c, &gi->cdev.configs, list) { - struct config_usb_cfg *cfg; - struct usb_function *f; - struct usb_function *tmp; struct gadget_config_name *cn; if (gadget_is_otg(gadget)) @@ -1362,6 +1368,16 @@ static int configfs_composite_bind(struct usb_gadget *gadget, goto err_purge_funcs; } + cfg = &gi->control_config; + c = &cfg->c; + list_for_each_entry_safe(f, tmp, &cfg->func_list, list) { + if (f->req_match && f->setup) { + list_del(&f->list); + if (usb_add_function(&cfg->c, f)) + list_add(&f->list, &cfg->func_list); + } + } + usb_ep_autoconfig_reset(cdev->gadget); return 0; @@ -1391,11 +1407,33 @@ static void configfs_composite_unbind(struct usb_gadget *gadget) set_gadget_data(gadget, NULL); } +static int configfs_composite_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); + + struct config_usb_cfg *cfg = &gi->control_config; + struct usb_function *f; + int value = composite_setup(gadget, c); + + if (value >= 0) + return value; + + list_for_each_entry(f, &cfg->c.functions, list) { + if (f->req_match(f, c, false)) { + value = f->setup(f, c); + break; + } + } + return value; +} + static const struct usb_gadget_driver configfs_driver_template = { .bind = configfs_composite_bind, .unbind = configfs_composite_unbind, - .setup = composite_setup, + .setup = configfs_composite_setup, .reset = composite_disconnect, .disconnect = composite_disconnect, @@ -1461,6 +1499,18 @@ static struct config_group *gadgets_make( if (!gi->composite.gadget_driver.function) goto err; + gi->control_config.c.label = "control_config"; + /* composite requires some value, but it doesn't matter */ + gi->control_config.c.bConfigurationValue = 42; + INIT_LIST_HEAD(&gi->control_config.func_list); + config_group_init_type_name(&gi->control_config.group, + "control_config", &gadget_config_type); + configfs_add_default_group(&gi->control_config.group, &gi->group); + + if (usb_add_config_only(&gi->cdev, &gi->control_config.c)) + goto err; + list_del(&gi->control_config.c.list); + return &gi->group; err: kfree(gi);