From patchwork Thu May 7 17:06:54 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrey Konovalov X-Patchwork-Id: 11534443 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id C84F5159A for ; Thu, 7 May 2020 17:07:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B01A8215A4 for ; Thu, 7 May 2020 17:07:26 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="mowMqO9i" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727117AbgEGRHG (ORCPT ); Thu, 7 May 2020 13:07:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45686 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1726393AbgEGRHF (ORCPT ); Thu, 7 May 2020 13:07:05 -0400 Received: from mail-qk1-x749.google.com (mail-qk1-x749.google.com [IPv6:2607:f8b0:4864:20::749]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5461DC05BD43 for ; Thu, 7 May 2020 10:07:05 -0700 (PDT) Received: by mail-qk1-x749.google.com with SMTP id p17so5708647qkp.10 for ; Thu, 07 May 2020 10:07:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=ymubhbuUMqo10NP0iRjdqCfzVtS0tpPXFP6hBmZD6a0=; b=mowMqO9im8184u6QOvUBA0wIM78Byr0OqoioGhshWiiwT8nJKONKJJz5svQElVrQKa TYEOuPweh0lLQnIpkM4IlDj46vfTQlhYXqkJ2w078q+zaS+1Kp33l1KLOCjpP+RPMvlc TceMvMFO/x8ng6ELmji6WKn+z5mkB5NSe7j12yp7xLzXV5ucHeZl6pVO4Kv847l4rMrI 5G6pq5PMrPrpIXoFT/XsBKQa9l7gNtgfx6RDn2Ixi7tMhkKC1t9BsJPkfurxniFsVDOH uRyyPpOUsabh/m8iJswGUmZQ7GfmEVMDWrYeChDVkUMTUSkA2hL3wi8Ysur7vzXJ5ATj Pb5w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=ymubhbuUMqo10NP0iRjdqCfzVtS0tpPXFP6hBmZD6a0=; b=G1cd9qF/3BVPc8h2jpwF0aBbUqEwdniImsSq9H9OyuSQwBR+K4P1+O+Z9Hww9Grmq0 WmtA/BAs/WNk9PaloOwA3XACScO0MAx4zVofvyJwTs8jN3dGeRCjgQ5e2EF39gwYHbyC s0gQOrIEERw8mzEP1G9PcOZzvCGw1f+CQiyX16k0YK+FyiZBWZfbq/6wQbQduZdt7w0r z2t3uyyQcUUvhtAaE+JghikHc/8r5XDk3sletspCGAOqinJSG01KdgLCyphgGQK80qnQ KD6xmdguw46/0IJiqlTCp8+EYq7vV7gUtoXrKfVOcoE+XSngr3zOJ6I9ll6QNDDdrA5A EONQ== X-Gm-Message-State: AGi0PubXJtjBOOargema1fHZiBK4TxTS8vyOrtOCo/MUxITdzgcU1v/I knylyFFLTv2kyatfU62F3C/y/LcQ/lQlD6ij X-Google-Smtp-Source: APiQypLvkahc8DkzAjMi93zhah8Vj2AFn3RskThIsYEhnKOwAREgc0dTuM+sVqh9dhx1TvuAjZQlitIsge7llnO1 X-Received: by 2002:a0c:e8c2:: with SMTP id m2mr13550246qvo.24.1588871224508; Thu, 07 May 2020 10:07:04 -0700 (PDT) Date: Thu, 7 May 2020 19:06:54 +0200 In-Reply-To: Message-Id: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.26.2.526.g744177e7f7-goog Subject: [PATCH USB v3 1/5] usb: raw-gadget: fix return value of ep read ioctls From: Andrey Konovalov To: Felipe Balbi Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Greg Kroah-Hartman , Alan Stern , Dmitry Vyukov , Andrey Konovalov Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org They must return the number of bytes transferred during the data stage. Fixes: 068fbff4f860 ("usb: raw-gadget: Fix copy_to/from_user() checks") Fixes: f2c2e717642c ("usb: gadget: add raw-gadget interface") Signed-off-by: Andrey Konovalov --- drivers/usb/gadget/legacy/raw_gadget.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c index ca7d95bf7397..7b241992ad5a 100644 --- a/drivers/usb/gadget/legacy/raw_gadget.c +++ b/drivers/usb/gadget/legacy/raw_gadget.c @@ -669,12 +669,14 @@ static int raw_ioctl_ep0_read(struct raw_dev *dev, unsigned long value) if (IS_ERR(data)) return PTR_ERR(data); ret = raw_process_ep0_io(dev, &io, data, false); - if (ret) + if (ret < 0) goto free; length = min(io.length, (unsigned int)ret); if (copy_to_user((void __user *)(value + sizeof(io)), data, length)) ret = -EFAULT; + else + ret = length; free: kfree(data); return ret; @@ -964,12 +966,14 @@ static int raw_ioctl_ep_read(struct raw_dev *dev, unsigned long value) if (IS_ERR(data)) return PTR_ERR(data); ret = raw_process_ep_io(dev, &io, data, false); - if (ret) + if (ret < 0) goto free; length = min(io.length, (unsigned int)ret); if (copy_to_user((void __user *)(value + sizeof(io)), data, length)) ret = -EFAULT; + else + ret = length; free: kfree(data); return ret; From patchwork Thu May 7 17:06:55 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrey Konovalov X-Patchwork-Id: 11534441 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 33B7B14C0 for ; Thu, 7 May 2020 17:07:26 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1C14A2173E for ; Thu, 7 May 2020 17:07:26 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Xjw3YQDK" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727808AbgEGRHK (ORCPT ); Thu, 7 May 2020 13:07:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45696 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1727799AbgEGRHH (ORCPT ); Thu, 7 May 2020 13:07:07 -0400 Received: from mail-qk1-x74a.google.com (mail-qk1-x74a.google.com [IPv6:2607:f8b0:4864:20::74a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8D6CAC05BD09 for ; Thu, 7 May 2020 10:07:07 -0700 (PDT) Received: by mail-qk1-x74a.google.com with SMTP id a62so6486904qkd.4 for ; Thu, 07 May 2020 10:07:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=UkoJB8mrsXvJ/mhp+/IOB9nRbu0RcDR5Saku4Tm8lGU=; b=Xjw3YQDKpPMme3PoqQQ8vRC+br/9ZRYJ4YydUX3wxHjW+x/HraXRlU2zOvDpyfLcPP Btez9FR8imo7LTgnaUc/gY4ZG86nZRSDftd2/vztY842ug21by/oURrcAcqSsGnVYoDO 0OB5b8lSBjwo0NEDK3Mxh8rGzzb12C4eKxqmHWHVG0xyvLP2j0jGYIbzMgfsWfRv2rmB Nn6m19H0Ja+JeqCrlyMt+GKcqce8aM2cMEmCbpj/RsSaAZeiv+Cb0yF/uYgHcF5OYSLN UUf+j2a6w/QK34V3y37ELg2p9yfZb9LB10hnOoLoC/EVsSr46tfZOxswwqOop86EQgQu SAUQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=UkoJB8mrsXvJ/mhp+/IOB9nRbu0RcDR5Saku4Tm8lGU=; b=HQa01tTmFZFX+mMtznfCv8B4FGKcAOqL7mBzdbTsnRC8BN9SVRi8+jmwwOiRzEpapr Qk2ppjtnnggvwfD+yOc15rSJx8oaJv5/XeMiUwPPvFQu3AFT4NU/z6e3STQOl3i/yYyT jr2w0lxcxMTNbhuY0psyfX8YfWBRlCN6tG/lCyHQTgGmznukDtEbPds3VHhE8ebIWiCB zxevzScm740x6b8NGTdmnDvVFzU+DsUcehmuxZa2ZRM8RD6bwjo/Dt+4UjgXNr0Vp6U7 TthSH4Pww15hl3x1HbOZfURBZS0uiorSyQLanZUO2GUj4mGpIiPIfMUuBrQlZ9cN2PPL +52Q== X-Gm-Message-State: AGi0Pub/YBxONmmkIKUht2Y1yYWyrCkLJYBjGYvGlx9miRX4HyLMmjsA 15qr1vHf9VrlxsFHN2OSt+nyJivDoSG0l48Y X-Google-Smtp-Source: APiQypLZa2bsIo3FGThkD21eG+RwPhgKjDyYY7K5nvsOcHUVUTmz1VXVMJ/cESbH1ZZ09e9oydvFKZ/4Lr/r9CMd X-Received: by 2002:a0c:f2d3:: with SMTP id c19mr14261142qvm.109.1588871226725; Thu, 07 May 2020 10:07:06 -0700 (PDT) Date: Thu, 7 May 2020 19:06:55 +0200 In-Reply-To: Message-Id: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.26.2.526.g744177e7f7-goog Subject: [PATCH USB v3 2/5] usb: raw-gadget: improve uapi headers comments From: Andrey Konovalov To: Felipe Balbi Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Greg Kroah-Hartman , Alan Stern , Dmitry Vyukov , Andrey Konovalov Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Fix typo "trasferred" => "transferred". Don't call USB requests URBs. Fix comment style. Signed-off-by: Andrey Konovalov --- include/uapi/linux/usb/raw_gadget.h | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/include/uapi/linux/usb/raw_gadget.h b/include/uapi/linux/usb/raw_gadget.h index ea375082b3ac..02885e021ee5 100644 --- a/include/uapi/linux/usb/raw_gadget.h +++ b/include/uapi/linux/usb/raw_gadget.h @@ -115,11 +115,11 @@ struct usb_raw_ep_io { #define USB_RAW_IOCTL_EVENT_FETCH _IOR('U', 2, struct usb_raw_event) /* - * Queues an IN (OUT for READ) urb as a response to the last control request - * received on endpoint 0, provided that was an IN (OUT for READ) request and - * waits until the urb is completed. Copies received data to user for READ. + * Queues an IN (OUT for READ) request as a response to the last setup request + * received on endpoint 0 (provided that was an IN (OUT for READ) request), and + * waits until the request is completed. Copies received data to user for READ. * Accepts a pointer to the usb_raw_ep_io struct as an argument. - * Returns length of trasferred data on success or negative error code on + * Returns length of transferred data on success or negative error code on * failure. */ #define USB_RAW_IOCTL_EP0_WRITE _IOW('U', 3, struct usb_raw_ep_io) @@ -133,19 +133,20 @@ struct usb_raw_ep_io { */ #define USB_RAW_IOCTL_EP_ENABLE _IOW('U', 5, struct usb_endpoint_descriptor) -/* Disables specified endpoint. +/* + * Disables specified endpoint. * Accepts endpoint handle as an argument. * Returns 0 on success or negative error code on failure. */ #define USB_RAW_IOCTL_EP_DISABLE _IOW('U', 6, __u32) /* - * Queues an IN (OUT for READ) urb as a response to the last control request - * received on endpoint usb_raw_ep_io.ep, provided that was an IN (OUT for READ) - * request and waits until the urb is completed. Copies received data to user - * for READ. + * Queues an IN (OUT for READ) request as a response to the last setup request + * received on endpoint usb_raw_ep_io.ep (provided that was an IN (OUT for READ) + * request), and waits until the request is completed. Copies received data to + * user for READ. * Accepts a pointer to the usb_raw_ep_io struct as an argument. - * Returns length of trasferred data on success or negative error code on + * Returns length of transferred data on success or negative error code on * failure. */ #define USB_RAW_IOCTL_EP_WRITE _IOW('U', 7, struct usb_raw_ep_io) From patchwork Thu May 7 17:06:56 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrey Konovalov X-Patchwork-Id: 11534437 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id DC04914C0 for ; Thu, 7 May 2020 17:07:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B8AF1207DD for ; Thu, 7 May 2020 17:07:19 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="ZqB6W/cN" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727983AbgEGRHP (ORCPT ); Thu, 7 May 2020 13:07:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45704 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1727902AbgEGRHL (ORCPT ); Thu, 7 May 2020 13:07:11 -0400 Received: from mail-qt1-x84a.google.com (mail-qt1-x84a.google.com [IPv6:2607:f8b0:4864:20::84a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E69CDC05BD43 for ; Thu, 7 May 2020 10:07:09 -0700 (PDT) Received: by mail-qt1-x84a.google.com with SMTP id w6so7476798qtt.21 for ; Thu, 07 May 2020 10:07:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=DU3b+dz/5KdgSh9FXxCXtP/uu/aAeFti+R+6yf8Qf2E=; b=ZqB6W/cNL+1r6XAaa1fmJV9kotYe7vFoVKvY8XBRrEykFOgeaJWUW5cSRaC6nLftjW EYpJR1s6bfv2stZrW/Hd2bCEpY6WscAR1FqqMuF4ZC2lUQM1gjuWEAj7fwlNQSkCb7OJ nU2pPjpFAJuciYpOtQuopLcC3veCluJ8Odyy+MkhxgJ9yKY5wGOTb+lX8yTbkw9iIit1 XSfzVf3AuvAEI/l5UY/wMbaXfMX/3Br/dheRSM2l7Ki3zDc76R10scTbEQYfVjFTkKJW vCeD8vCEcA3t3J9CJiEBZvgd2Lqgv+t7oHs1Wqf68/2BL6IrvAq6Q5+1FGfo71ZpgXrR tf5w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=DU3b+dz/5KdgSh9FXxCXtP/uu/aAeFti+R+6yf8Qf2E=; b=h2MXn5NHkFZ+/i8v0s35FB1NyLmeQg5ydp+5+b1ckMr+6+/6MC9r8gby4t/F0aeReu sC5VBL7LGAp7toyuURT7vpUGSgjJ3Nq8CXVTdtwvzqooHiCGLvhz5irAvxvVqzP0AMSl z0fW5IZvFEWzCstAxUZGblX8N6UdpE67qYeGl7WyEdKaefNHdm8zXsveufxrmjxNpDrG /2BN63XTIcY/fcIQWmM0mKyzAjFymNBh4ON4x2UTyZwK9TofFl0WPzW+nZnEfnSZoad1 tbr8Wiug5MXMwDfIoVvJuRTp2AiJuiEMsrXSxvCuMFUcMGElteMWOoKOd+sRESk1xZmg qtFg== X-Gm-Message-State: AGi0PuZODDJhxm2nnrvaIVqDs9aYtvprbn61z8/LbuUQ4jGJ2gT6dnqg 2ouZrRrlXXs8eJcmnlpNlDsPHRG/HMzrxS35 X-Google-Smtp-Source: APiQypL61gEJdR7K1MAJTj+1gwNLdy0iTVv3dr2I60ZDjiIFwdRiO9up37pKCNfbkh1pb/ihwmGMqYY7q2DrUZ6N X-Received: by 2002:a0c:ffa3:: with SMTP id d3mr14017461qvv.12.1588871229083; Thu, 07 May 2020 10:07:09 -0700 (PDT) Date: Thu, 7 May 2020 19:06:56 +0200 In-Reply-To: Message-Id: <459d02069dedefcc30095748f49ef4a426e15b74.1588870822.git.andreyknvl@google.com> Mime-Version: 1.0 References: X-Mailer: git-send-email 2.26.2.526.g744177e7f7-goog Subject: [PATCH USB v3 3/5] usb: raw-gadget: fix gadget endpoint selection From: Andrey Konovalov To: Felipe Balbi Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Greg Kroah-Hartman , Alan Stern , Dmitry Vyukov , Andrey Konovalov Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Currently automatic gadget endpoint selection based on required features doesn't work. Raw Gadget tries iterating over the list of available endpoints and finding one that has the right direction and transfer type. Unfortunately selecting arbitrary gadget endpoints (even if they satisfy feature requirements) doesn't work, as (depending on the UDC driver) they might have fixed addresses, and one also needs to provide matching endpoint addresses in the descriptors sent to the host. The composite framework deals with this by assigning endpoint addresses in usb_ep_autoconfig() before enumeration starts. This approach won't work with Raw Gadget as the endpoints are supposed to be enabled after a set_configuration/set_interface request from the host, so it's too late to patch the endpoint descriptors that had already been sent to the host. For Raw Gadget we take another approach. Similarly to GadgetFS, we allow the user to make the decision as to which gadget endpoints to use. This patch adds another Raw Gadget ioctl USB_RAW_IOCTL_EPS_INFO that exposes information about all non-control endpoints that a currently connected UDC has. This information includes endpoints addresses, as well as their capabilities and limits to allow the user to choose the most fitting gadget endpoint. The USB_RAW_IOCTL_EP_ENABLE ioctl is updated to use the proper endpoint validation routine usb_gadget_ep_match_desc(). These changes affect the portability of the gadgets that use Raw Gadget when running on different UDCs. Nevertheless, as long as the user relies on the information provided by USB_RAW_IOCTL_EPS_INFO to dynamically choose endpoint addresses, UDC-agnostic gadgets can still be written with Raw Gadget. Fixes: f2c2e717642c ("usb: gadget: add raw-gadget interface") Signed-off-by: Andrey Konovalov --- Documentation/usb/raw-gadget.rst | 5 +- drivers/usb/gadget/legacy/raw_gadget.c | 187 ++++++++++++++++--------- include/uapi/linux/usb/raw_gadget.h | 72 +++++++++- 3 files changed, 194 insertions(+), 70 deletions(-) diff --git a/Documentation/usb/raw-gadget.rst b/Documentation/usb/raw-gadget.rst index 9e78cb858f86..4af8b1f15574 100644 --- a/Documentation/usb/raw-gadget.rst +++ b/Documentation/usb/raw-gadget.rst @@ -27,9 +27,8 @@ differences are: 3. Raw Gadget provides a way to select a UDC device/driver to bind to, while GadgetFS currently binds to the first available UDC. -4. Raw Gadget uses predictable endpoint names (handles) across different - UDCs (as long as UDCs have enough endpoints of each required transfer - type). +4. Raw Gadget explicitly exposes information about endpoints addresses and + capabilities allowing a user to write UDC-agnostic gadgets. 5. Raw Gadget has ioctl-based interface instead of a filesystem-based one. diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c index 7b241992ad5a..775f22184aaf 100644 --- a/drivers/usb/gadget/legacy/raw_gadget.c +++ b/drivers/usb/gadget/legacy/raw_gadget.c @@ -7,6 +7,7 @@ */ #include +#include #include #include #include @@ -123,8 +124,6 @@ static void raw_event_queue_destroy(struct raw_event_queue *queue) struct raw_dev; -#define USB_RAW_MAX_ENDPOINTS 32 - enum ep_state { STATE_EP_DISABLED, STATE_EP_ENABLED, @@ -134,6 +133,7 @@ struct raw_ep { struct raw_dev *dev; enum ep_state state; struct usb_ep *ep; + u8 addr; struct usb_request *req; bool urb_queued; bool disabling; @@ -168,7 +168,8 @@ struct raw_dev { bool ep0_out_pending; bool ep0_urb_queued; ssize_t ep0_status; - struct raw_ep eps[USB_RAW_MAX_ENDPOINTS]; + struct raw_ep eps[USB_RAW_EPS_NUM_MAX]; + int eps_num; struct completion ep0_done; struct raw_event_queue queue; @@ -202,7 +203,7 @@ static void dev_free(struct kref *kref) usb_ep_free_request(dev->gadget->ep0, dev->req); } raw_event_queue_destroy(&dev->queue); - for (i = 0; i < USB_RAW_MAX_ENDPOINTS; i++) { + for (i = 0; i < dev->eps_num; i++) { if (dev->eps[i].state != STATE_EP_ENABLED) continue; usb_ep_disable(dev->eps[i].ep); @@ -249,12 +250,26 @@ static void gadget_ep0_complete(struct usb_ep *ep, struct usb_request *req) complete(&dev->ep0_done); } +static u8 get_ep_addr(const char *name) +{ + /* If the endpoint has fixed function (named as e.g. "ep12out-bulk"), + * parse the endpoint address from its name. We deliberately use + * deprecated simple_strtoul() function here, as the number isn't + * followed by '\0' nor '\n'. + */ + if (isdigit(name[2])) + return simple_strtoul(&name[2], NULL, 10); + /* Otherwise the endpoint is configurable (named as e.g. "ep-a"). */ + return USB_RAW_EP_ADDR_ANY; +} + static int gadget_bind(struct usb_gadget *gadget, struct usb_gadget_driver *driver) { - int ret = 0; + int ret = 0, i = 0; struct raw_dev *dev = container_of(driver, struct raw_dev, driver); struct usb_request *req; + struct usb_ep *ep; unsigned long flags; if (strcmp(gadget->name, dev->udc_name) != 0) @@ -273,6 +288,13 @@ static int gadget_bind(struct usb_gadget *gadget, dev->req->context = dev; dev->req->complete = gadget_ep0_complete; dev->gadget = gadget; + gadget_for_each_ep(ep, dev->gadget) { + dev->eps[i].ep = ep; + dev->eps[i].addr = get_ep_addr(ep->name); + dev->eps[i].state = STATE_EP_DISABLED; + i++; + } + dev->eps_num = i; spin_unlock_irqrestore(&dev->lock, flags); /* Matches kref_put() in gadget_unbind(). */ @@ -555,7 +577,7 @@ static void *raw_alloc_io_data(struct usb_raw_ep_io *io, void __user *ptr, if (copy_from_user(io, ptr, sizeof(*io))) return ERR_PTR(-EFAULT); - if (io->ep >= USB_RAW_MAX_ENDPOINTS) + if (io->ep >= USB_RAW_EPS_NUM_MAX) return ERR_PTR(-EINVAL); if (!usb_raw_io_flags_valid(io->flags)) return ERR_PTR(-EINVAL); @@ -682,40 +704,12 @@ static int raw_ioctl_ep0_read(struct raw_dev *dev, unsigned long value) return ret; } -static bool check_ep_caps(struct usb_ep *ep, - struct usb_endpoint_descriptor *desc) -{ - switch (usb_endpoint_type(desc)) { - case USB_ENDPOINT_XFER_ISOC: - if (!ep->caps.type_iso) - return false; - break; - case USB_ENDPOINT_XFER_BULK: - if (!ep->caps.type_bulk) - return false; - break; - case USB_ENDPOINT_XFER_INT: - if (!ep->caps.type_int) - return false; - break; - default: - return false; - } - - if (usb_endpoint_dir_in(desc) && !ep->caps.dir_in) - return false; - if (usb_endpoint_dir_out(desc) && !ep->caps.dir_out) - return false; - - return true; -} - static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value) { int ret = 0, i; unsigned long flags; struct usb_endpoint_descriptor *desc; - struct usb_ep *ep = NULL; + struct raw_ep *ep; desc = memdup_user((void __user *)value, sizeof(*desc)); if (IS_ERR(desc)) @@ -743,41 +737,32 @@ static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value) goto out_free; } - for (i = 0; i < USB_RAW_MAX_ENDPOINTS; i++) { - if (dev->eps[i].state == STATE_EP_ENABLED) + for (i = 0; i < dev->eps_num; i++) { + ep = &dev->eps[i]; + if (ep->state != STATE_EP_DISABLED) continue; - break; - } - if (i == USB_RAW_MAX_ENDPOINTS) { - dev_dbg(&dev->gadget->dev, - "fail, no device endpoints available\n"); - ret = -EBUSY; - goto out_free; - } - - gadget_for_each_ep(ep, dev->gadget) { - if (ep->enabled) + if (ep->addr != usb_endpoint_num(desc) && + ep->addr != USB_RAW_EP_ADDR_ANY) continue; - if (!check_ep_caps(ep, desc)) + if (!usb_gadget_ep_match_desc(dev->gadget, ep->ep, desc, NULL)) continue; - ep->desc = desc; - ret = usb_ep_enable(ep); + ep->ep->desc = desc; + ret = usb_ep_enable(ep->ep); if (ret < 0) { dev_err(&dev->gadget->dev, "fail, usb_ep_enable returned %d\n", ret); goto out_free; } - dev->eps[i].req = usb_ep_alloc_request(ep, GFP_ATOMIC); - if (!dev->eps[i].req) { + ep->req = usb_ep_alloc_request(ep->ep, GFP_ATOMIC); + if (!ep->req) { dev_err(&dev->gadget->dev, "fail, usb_ep_alloc_request failed\n"); - usb_ep_disable(ep); + usb_ep_disable(ep->ep); ret = -ENOMEM; goto out_free; } - dev->eps[i].ep = ep; - dev->eps[i].state = STATE_EP_ENABLED; - ep->driver_data = &dev->eps[i]; + ep->state = STATE_EP_ENABLED; + ep->ep->driver_data = ep; ret = i; goto out_unlock; } @@ -796,10 +781,6 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value) { int ret = 0, i = value; unsigned long flags; - const void *desc; - - if (i < 0 || i >= USB_RAW_MAX_ENDPOINTS) - return -EINVAL; spin_lock_irqsave(&dev->lock, flags); if (dev->state != STATE_DEV_RUNNING) { @@ -812,6 +793,11 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value) ret = -EBUSY; goto out_unlock; } + if (i < 0 || i >= dev->eps_num) { + dev_dbg(dev->dev, "fail, invalid endpoint\n"); + ret = -EBUSY; + goto out_unlock; + } if (dev->eps[i].state != STATE_EP_ENABLED) { dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n"); ret = -EINVAL; @@ -836,10 +822,9 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value) spin_lock_irqsave(&dev->lock, flags); usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req); - desc = dev->eps[i].ep->desc; + kfree(dev->eps[i].ep->desc); dev->eps[i].ep = NULL; dev->eps[i].state = STATE_EP_DISABLED; - kfree(desc); dev->eps[i].disabling = false; out_unlock: @@ -868,7 +853,7 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io, { int ret = 0; unsigned long flags; - struct raw_ep *ep = &dev->eps[io->ep]; + struct raw_ep *ep; DECLARE_COMPLETION_ONSTACK(done); spin_lock_irqsave(&dev->lock, flags); @@ -882,6 +867,12 @@ static int raw_process_ep_io(struct raw_dev *dev, struct usb_raw_ep_io *io, ret = -EBUSY; goto out_unlock; } + if (io->ep >= dev->eps_num) { + dev_dbg(&dev->gadget->dev, "fail, invalid endpoint\n"); + ret = -EINVAL; + goto out_unlock; + } + ep = &dev->eps[io->ep]; if (ep->state != STATE_EP_ENABLED) { dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n"); ret = -EBUSY; @@ -1027,6 +1018,71 @@ static int raw_ioctl_vbus_draw(struct raw_dev *dev, unsigned long value) return ret; } +static void fill_ep_caps(struct usb_ep_caps *caps, + struct usb_raw_ep_caps *raw_caps) +{ + raw_caps->type_control = caps->type_control; + raw_caps->type_iso = caps->type_iso; + raw_caps->type_bulk = caps->type_bulk; + raw_caps->type_int = caps->type_int; + raw_caps->dir_in = caps->dir_in; + raw_caps->dir_out = caps->dir_out; +} + +static void fill_ep_limits(struct usb_ep *ep, struct usb_raw_ep_limits *limits) +{ + limits->maxpacket_limit = ep->maxpacket_limit; + limits->max_streams = ep->max_streams; +} + +static int raw_ioctl_eps_info(struct raw_dev *dev, unsigned long value) +{ + int ret = 0, i; + unsigned long flags; + struct usb_raw_eps_info *info; + struct raw_ep *ep; + + info = kmalloc(sizeof(*info), GFP_KERNEL); + if (!info) { + ret = -ENOMEM; + goto out; + } + + spin_lock_irqsave(&dev->lock, flags); + if (dev->state != STATE_DEV_RUNNING) { + dev_dbg(dev->dev, "fail, device is not running\n"); + ret = -EINVAL; + spin_unlock_irqrestore(&dev->lock, flags); + goto out_free; + } + if (!dev->gadget) { + dev_dbg(dev->dev, "fail, gadget is not bound\n"); + ret = -EBUSY; + spin_unlock_irqrestore(&dev->lock, flags); + goto out_free; + } + + memset(info, 0, sizeof(*info)); + for (i = 0; i < dev->eps_num; i++) { + ep = &dev->eps[i]; + strscpy(&info->eps[i].name[0], ep->ep->name, + USB_RAW_EP_NAME_MAX); + info->eps[i].addr = ep->addr; + fill_ep_caps(&ep->ep->caps, &info->eps[i].caps); + fill_ep_limits(ep->ep, &info->eps[i].limits); + } + ret = dev->eps_num; + spin_unlock_irqrestore(&dev->lock, flags); + + if (copy_to_user((void __user *)value, info, sizeof(*info))) + ret = -EFAULT; + +out_free: + kfree(info); +out: + return ret; +} + static long raw_ioctl(struct file *fd, unsigned int cmd, unsigned long value) { struct raw_dev *dev = fd->private_data; @@ -1069,6 +1125,9 @@ static long raw_ioctl(struct file *fd, unsigned int cmd, unsigned long value) case USB_RAW_IOCTL_VBUS_DRAW: ret = raw_ioctl_vbus_draw(dev, value); break; + case USB_RAW_IOCTL_EPS_INFO: + ret = raw_ioctl_eps_info(dev, value); + break; default: ret = -EINVAL; } diff --git a/include/uapi/linux/usb/raw_gadget.h b/include/uapi/linux/usb/raw_gadget.h index 02885e021ee5..c89f6341229c 100644 --- a/include/uapi/linux/usb/raw_gadget.h +++ b/include/uapi/linux/usb/raw_gadget.h @@ -93,6 +93,64 @@ struct usb_raw_ep_io { __u8 data[0]; }; +/* Maximum number of non-control endpoints in struct usb_raw_eps_info. */ +#define USB_RAW_EPS_NUM_MAX 30 + +/* Maximum length of UDC endpoint name in struct usb_raw_ep_info. */ +#define USB_RAW_EP_NAME_MAX 16 + +/* Used as addr in struct usb_raw_ep_info if endpoint accepts any address. */ +#define USB_RAW_EP_ADDR_ANY 0xff + +/* + * struct usb_raw_ep_caps - exposes endpoint capabilities from struct usb_ep + * (technically from its member struct usb_ep_caps). + */ +struct usb_raw_ep_caps { + __u32 type_control : 1; + __u32 type_iso : 1; + __u32 type_bulk : 1; + __u32 type_int : 1; + __u32 dir_in : 1; + __u32 dir_out : 1; +}; + +/* + * struct usb_raw_ep_limits - exposes endpoint limits from struct usb_ep. + * @maxpacket_limit: Maximum packet size value supported by this endpoint. + * @max_streams: maximum number of streams supported by this endpoint + * (actual number is 2^n). + * @reserved: Empty, reserved for potential future extensions. + */ +struct usb_raw_ep_limits { + __u16 maxpacket_limit; + __u16 max_streams; + __u32 reserved; +}; + +/* + * struct usb_raw_ep_info - stores information about a gadget endpoint. + * @name: Name of the endpoint as it is defined in the UDC driver. + * @addr: Address of the endpoint that must be specified in the endpoint + * descriptor passed to USB_RAW_IOCTL_EP_ENABLE ioctl. + * @caps: Endpoint capabilities. + * @limits: Endpoint limits. + */ +struct usb_raw_ep_info { + __u8 name[USB_RAW_EP_NAME_MAX]; + __u32 addr; + struct usb_raw_ep_caps caps; + struct usb_raw_ep_limits limits; +}; + +/* + * struct usb_raw_eps_info - argument for USB_RAW_IOCTL_EPS_INFO ioctl. + * eps: Structures that store information about non-control endpoints. + */ +struct usb_raw_eps_info { + struct usb_raw_ep_info eps[USB_RAW_EPS_NUM_MAX]; +}; + /* * Initializes a Raw Gadget instance. * Accepts a pointer to the usb_raw_init struct as an argument. @@ -126,9 +184,9 @@ struct usb_raw_ep_io { #define USB_RAW_IOCTL_EP0_READ _IOWR('U', 4, struct usb_raw_ep_io) /* - * Finds an endpoint that supports the transfer type specified in the - * descriptor and enables it. - * Accepts a pointer to the usb_endpoint_descriptor struct as an argument. + * Finds an endpoint that satisfies the parameters specified in the provided + * descriptors (address, transfer type, etc.) and enables it. + * Accepts a pointer to the usb_raw_ep_descs struct as an argument. * Returns enabled endpoint handle on success or negative error code on failure. */ #define USB_RAW_IOCTL_EP_ENABLE _IOW('U', 5, struct usb_endpoint_descriptor) @@ -165,4 +223,12 @@ struct usb_raw_ep_io { */ #define USB_RAW_IOCTL_VBUS_DRAW _IOW('U', 10, __u32) +/* + * Fills in the usb_raw_eps_info structure with information about non-control + * endpoints available for the currently connected UDC. + * Returns the number of available endpoints on success or negative error code + * on failure. + */ +#define USB_RAW_IOCTL_EPS_INFO _IOR('U', 11, struct usb_raw_eps_info) + #endif /* _UAPI__LINUX_USB_RAW_GADGET_H */ From patchwork Thu May 7 17:06:57 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrey Konovalov X-Patchwork-Id: 11534435 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 1168714C0 for ; Thu, 7 May 2020 17:07:19 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E6A21207DD for ; Thu, 7 May 2020 17:07:18 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Gf8CMGn0" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728018AbgEGRHQ (ORCPT ); Thu, 7 May 2020 13:07:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45712 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1727956AbgEGRHM (ORCPT ); Thu, 7 May 2020 13:07:12 -0400 Received: from mail-qt1-x84a.google.com (mail-qt1-x84a.google.com [IPv6:2607:f8b0:4864:20::84a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 28E86C05BD09 for ; Thu, 7 May 2020 10:07:12 -0700 (PDT) Received: by mail-qt1-x84a.google.com with SMTP id w6so7476910qtt.21 for ; Thu, 07 May 2020 10:07:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=cX88jRwYw6gh/fZ+XYDPimSSS7alrzjsZpkbo4YG8fk=; b=Gf8CMGn0vunTCJB10kQM8G2RHmmbs8MZ8+ODyTiaAMkx6ZTGaLR5//Z9M1VUSTLn4H iRNG6bCcHBw0FWYdJQ8t8NkP/MYNkEjXHPNktPRnwRwBN6bF8FlTib2qP7/0R309uPds g64AVMZ/PxbN1leiEDkv85Vhpxj3x6jbq9nH4dP/TgteXGGEbgIizuxUXLMAPojJbyTX upmqp9/I9vS97PxzurqBiktlQsrusJqt/0sLUkY1LPCNVFv6AJKEvfqLcqmTfed4Al29 HX77uEfxhN5Mu/i+Ks9+erO6rwYnbpSp+sKtEWQh28IJBLkJfIbLyh7CjYn8Z+BeSKGq fTaw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=cX88jRwYw6gh/fZ+XYDPimSSS7alrzjsZpkbo4YG8fk=; b=eQywnSoJ1CqYdcj1+cZgCdIo/qwbWOyH7PFjlkSn41LdEUL4P6cCqewzfa4Xwapxs+ VKvoy7Lc30RT/o0RvudlheUm9Y1yWto/Lf1U+zRqqlo2L43Ay/rSoeccIGUsJBfyqrHI a74BNSPd7fyD7DtOM/G37qhMbrPr55KLSPxrftg3cnOS2vZHDIYfhH80BTF90TlRBhc1 LxZ7gX8O5j294jKYmD6sVOqK2I/zUrI4E22h2kEyfOAOcsVbqtUPCaQ0NdPvDUbLORzm FNTgeJoBqCVYdSDfUeLnvs3V1oYPwpRjw3eQ5zmT/fGXywfS7pYhmGCOOin3TJzLYfeF u/8A== X-Gm-Message-State: AGi0PuYWXXwVc62LLjEWWWMrydYqE9wgoQCBa8Wu9yO4/6uuK7ShG8gu DgnFmVkg/gi/PrdrL+hVj1cocQkyHkTR7r7n X-Google-Smtp-Source: APiQypLvPqv2Xl19ym9PLleKsB/vp9+CCllsZnYITiH2hLCMsiKX4xLf2ACB1MU9t9EU//Zo09RVyvTVjxSu6Vku X-Received: by 2002:ad4:45ac:: with SMTP id y12mr14256274qvu.227.1588871231255; Thu, 07 May 2020 10:07:11 -0700 (PDT) Date: Thu, 7 May 2020 19:06:57 +0200 In-Reply-To: Message-Id: <343c0fee969a2109321dbea65a385656441af736.1588870822.git.andreyknvl@google.com> Mime-Version: 1.0 References: X-Mailer: git-send-email 2.26.2.526.g744177e7f7-goog Subject: [PATCH USB v3 4/5] usb: raw-gadget: support stalling/halting/wedging endpoints From: Andrey Konovalov To: Felipe Balbi Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Greg Kroah-Hartman , Alan Stern , Dmitry Vyukov , Andrey Konovalov Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Raw Gadget is currently unable to stall/halt/wedge gadget endpoints, which is required for proper emulation of certain USB classes. This patch adds a few more ioctls: - USB_RAW_IOCTL_EP0_STALL allows to stall control endpoint #0 when there's a pending setup request for it. - USB_RAW_IOCTL_SET/CLEAR_HALT/WEDGE allow to set/clear halt/wedge status on non-control non-isochronous endpoints. Fixes: f2c2e717642c ("usb: gadget: add raw-gadget interface") Signed-off-by: Andrey Konovalov --- Documentation/usb/raw-gadget.rst | 2 - drivers/usb/gadget/legacy/raw_gadget.c | 131 ++++++++++++++++++++++++- include/uapi/linux/usb/raw_gadget.h | 15 +++ 3 files changed, 144 insertions(+), 4 deletions(-) diff --git a/Documentation/usb/raw-gadget.rst b/Documentation/usb/raw-gadget.rst index 4af8b1f15574..3b3d78e850b2 100644 --- a/Documentation/usb/raw-gadget.rst +++ b/Documentation/usb/raw-gadget.rst @@ -52,8 +52,6 @@ The typical usage of Raw Gadget looks like: Potential future improvements ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- Implement ioctl's for setting/clearing halt status on endpoints. - - Reporting more events (suspend, resume, etc.) through USB_RAW_IOCTL_EVENT_FETCH. diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c index 775f22184aaf..d73ba77014c8 100644 --- a/drivers/usb/gadget/legacy/raw_gadget.c +++ b/drivers/usb/gadget/legacy/raw_gadget.c @@ -204,7 +204,7 @@ static void dev_free(struct kref *kref) } raw_event_queue_destroy(&dev->queue); for (i = 0; i < dev->eps_num; i++) { - if (dev->eps[i].state != STATE_EP_ENABLED) + if (dev->eps[i].state == STATE_EP_DISABLED) continue; usb_ep_disable(dev->eps[i].ep); usb_ep_free_request(dev->eps[i].ep, dev->eps[i].req); @@ -704,6 +704,50 @@ static int raw_ioctl_ep0_read(struct raw_dev *dev, unsigned long value) return ret; } +static int raw_ioctl_ep0_stall(struct raw_dev *dev, unsigned long value) +{ + int ret = 0; + unsigned long flags; + + if (value) + return -EINVAL; + spin_lock_irqsave(&dev->lock, flags); + if (dev->state != STATE_DEV_RUNNING) { + dev_dbg(dev->dev, "fail, device is not running\n"); + ret = -EINVAL; + goto out_unlock; + } + if (!dev->gadget) { + dev_dbg(dev->dev, "fail, gadget is not bound\n"); + ret = -EBUSY; + goto out_unlock; + } + if (dev->ep0_urb_queued) { + dev_dbg(&dev->gadget->dev, "fail, urb already queued\n"); + ret = -EBUSY; + goto out_unlock; + } + if (!dev->ep0_in_pending && !dev->ep0_out_pending) { + dev_dbg(&dev->gadget->dev, "fail, no request pending\n"); + ret = -EBUSY; + goto out_unlock; + } + + ret = usb_ep_set_halt(dev->gadget->ep0); + if (ret < 0) + dev_err(&dev->gadget->dev, + "fail, usb_ep_set_halt returned %d\n", ret); + + if (dev->ep0_in_pending) + dev->ep0_in_pending = false; + else + dev->ep0_out_pending = false; + +out_unlock: + spin_unlock_irqrestore(&dev->lock, flags); + return ret; +} + static int raw_ioctl_ep_enable(struct raw_dev *dev, unsigned long value) { int ret = 0, i; @@ -798,7 +842,7 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value) ret = -EBUSY; goto out_unlock; } - if (dev->eps[i].state != STATE_EP_ENABLED) { + if (dev->eps[i].state == STATE_EP_DISABLED) { dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n"); ret = -EINVAL; goto out_unlock; @@ -832,6 +876,74 @@ static int raw_ioctl_ep_disable(struct raw_dev *dev, unsigned long value) return ret; } +static int raw_ioctl_ep_set_clear_halt_wedge(struct raw_dev *dev, + unsigned long value, bool set, bool halt) +{ + int ret = 0, i = value; + unsigned long flags; + + spin_lock_irqsave(&dev->lock, flags); + if (dev->state != STATE_DEV_RUNNING) { + dev_dbg(dev->dev, "fail, device is not running\n"); + ret = -EINVAL; + goto out_unlock; + } + if (!dev->gadget) { + dev_dbg(dev->dev, "fail, gadget is not bound\n"); + ret = -EBUSY; + goto out_unlock; + } + if (i < 0 || i >= dev->eps_num) { + dev_dbg(dev->dev, "fail, invalid endpoint\n"); + ret = -EBUSY; + goto out_unlock; + } + if (dev->eps[i].state == STATE_EP_DISABLED) { + dev_dbg(&dev->gadget->dev, "fail, endpoint is not enabled\n"); + ret = -EINVAL; + goto out_unlock; + } + if (dev->eps[i].disabling) { + dev_dbg(&dev->gadget->dev, + "fail, disable is in progress\n"); + ret = -EINVAL; + goto out_unlock; + } + if (dev->eps[i].urb_queued) { + dev_dbg(&dev->gadget->dev, + "fail, waiting for urb completion\n"); + ret = -EINVAL; + goto out_unlock; + } + if (usb_endpoint_xfer_isoc(dev->eps[i].ep->desc)) { + dev_dbg(&dev->gadget->dev, + "fail, can't halt/wedge ISO endpoint\n"); + ret = -EINVAL; + goto out_unlock; + } + + if (set && halt) { + ret = usb_ep_set_halt(dev->eps[i].ep); + if (ret < 0) + dev_err(&dev->gadget->dev, + "fail, usb_ep_set_halt returned %d\n", ret); + } else if (!set && halt) { + ret = usb_ep_clear_halt(dev->eps[i].ep); + if (ret < 0) + dev_err(&dev->gadget->dev, + "fail, usb_ep_clear_halt returned %d\n", ret); + } else if (set && !halt) { + ret = usb_ep_set_wedge(dev->eps[i].ep); + if (ret < 0) + dev_err(&dev->gadget->dev, + "fail, usb_ep_set_wedge returned %d\n", ret); + } + +out_unlock: + spin_unlock_irqrestore(&dev->lock, flags); + return ret; +} + static void gadget_ep_complete(struct usb_ep *ep, struct usb_request *req) { struct raw_ep *r_ep = (struct raw_ep *)ep->driver_data; @@ -1128,6 +1240,21 @@ static long raw_ioctl(struct file *fd, unsigned int cmd, unsigned long value) case USB_RAW_IOCTL_EPS_INFO: ret = raw_ioctl_eps_info(dev, value); break; + case USB_RAW_IOCTL_EP0_STALL: + ret = raw_ioctl_ep0_stall(dev, value); + break; + case USB_RAW_IOCTL_EP_SET_HALT: + ret = raw_ioctl_ep_set_clear_halt_wedge( + dev, value, true, true); + break; + case USB_RAW_IOCTL_EP_CLEAR_HALT: + ret = raw_ioctl_ep_set_clear_halt_wedge( + dev, value, false, true); + break; + case USB_RAW_IOCTL_EP_SET_WEDGE: + ret = raw_ioctl_ep_set_clear_halt_wedge( + dev, value, true, false); + break; default: ret = -EINVAL; } diff --git a/include/uapi/linux/usb/raw_gadget.h b/include/uapi/linux/usb/raw_gadget.h index c89f6341229c..0be685272eb1 100644 --- a/include/uapi/linux/usb/raw_gadget.h +++ b/include/uapi/linux/usb/raw_gadget.h @@ -231,4 +231,19 @@ struct usb_raw_eps_info { */ #define USB_RAW_IOCTL_EPS_INFO _IOR('U', 11, struct usb_raw_eps_info) +/* + * Stalls a pending control request on endpoint 0. + * Returns 0 on success or negative error code on failure. + */ +#define USB_RAW_IOCTL_EP0_STALL _IO('U', 12) + +/* + * Sets or clears halt or wedge status of the endpoint. + * Accepts endpoint handle as an argument. + * Returns 0 on success or negative error code on failure. + */ +#define USB_RAW_IOCTL_EP_SET_HALT _IOW('U', 13, __u32) +#define USB_RAW_IOCTL_EP_CLEAR_HALT _IOW('U', 14, __u32) +#define USB_RAW_IOCTL_EP_SET_WEDGE _IOW('U', 15, __u32) + #endif /* _UAPI__LINUX_USB_RAW_GADGET_H */ From patchwork Thu May 7 17:06:58 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andrey Konovalov X-Patchwork-Id: 11534439 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 98EEA912 for ; Thu, 7 May 2020 17:07:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 7E467215A4 for ; Thu, 7 May 2020 17:07:21 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="vJ2cM97l" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728040AbgEGRHU (ORCPT ); Thu, 7 May 2020 13:07:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45722 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-FAIL-OK-FAIL) by vger.kernel.org with ESMTP id S1727972AbgEGRHO (ORCPT ); Thu, 7 May 2020 13:07:14 -0400 Received: from mail-qt1-x849.google.com (mail-qt1-x849.google.com [IPv6:2607:f8b0:4864:20::849]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5C360C05BD43 for ; Thu, 7 May 2020 10:07:14 -0700 (PDT) Received: by mail-qt1-x849.google.com with SMTP id g8so7938075qtq.2 for ; Thu, 07 May 2020 10:07:14 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=7/PrXCrrp5hii78pLoOm9OApKV03tezSTtbf21wn2GQ=; b=vJ2cM97lrsVanMLQWlqZTgaTuRFdaYInxkAXTc1yX40b8vt+T925FTXgJal0sutkm/ Qod3Kghc5YBrrYcrNJdKZwVj5qtIf40beNkJT2yW5S1C0QnqVbWws9SKTPfagLcfREO0 gD5X+dGPLcTZSDKGFGnChODgWTY5EzyAPi3VA+ZD5mmDoS2rduAzlZDc9L0scC8/LOx+ 2qCOly+pNoVVgZZEwX0oZ/iaAYI3wIKJXNyiSIRtdzCGKHRVlnZ6U2ahWUcez0t8gRHy 38s5DeSTRojmMQcMWprmAHfOoWWA77z3TSlb4p86rDN++UNEQNfB3iEnJHTvlHLGMl7Z t4Xw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=7/PrXCrrp5hii78pLoOm9OApKV03tezSTtbf21wn2GQ=; b=b5/bzDrNNHEKlImVta0yZrwckzlenRZyGCPUM/zZvMr+TpN4RISX4QB0CjR36Y8+Jx FvhmWCF1KcABpEvnSCuh8HzwiP7BOM1Z+SCKSuZeVRvCzVDJxR4vwbtyzEP0/Z0kbffH 83fiAJUZibaT8szL3iBCUVHLMKJ1InAH7j8K1gugBki8shP6PK6EQQ5GZfBS3K4bupr/ XzdEVn4lsUV9MpuW+qLwYVtTiPJ7Ao+BoJ8vyGyz6jJMqcutC+WkwC8Bd81/ESdHciHb VlVh9tDrnfMtZFTrCGHP3/NFRpduL0j36DLKqMswlyo4L82zMs1zaPUTJHUlxuy7HTxY SHbQ== X-Gm-Message-State: AGi0PuYUAqXClSrpv7boJnwqrV6Vy/ZFyWGsRcCZYu7z0AUD1PtWNRs1 leqHs4UH0PUUzQqIw4fsMYxl7DzYMJ+sEV6z X-Google-Smtp-Source: APiQypIy9HLMvQvr1IoBhkEe19b6+HAz9x1jbIn1bDPc6Z2265SQK2szy4myS1YuI24410DJjPCvk1IQhD93SQVM X-Received: by 2002:a0c:ffa3:: with SMTP id d3mr14017803qvv.12.1588871233518; Thu, 07 May 2020 10:07:13 -0700 (PDT) Date: Thu, 7 May 2020 19:06:58 +0200 In-Reply-To: Message-Id: Mime-Version: 1.0 References: X-Mailer: git-send-email 2.26.2.526.g744177e7f7-goog Subject: [PATCH USB v3 5/5] usb: raw-gadget: documentation updates From: Andrey Konovalov To: Felipe Balbi Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, Greg Kroah-Hartman , Alan Stern , Dmitry Vyukov , Andrey Konovalov Sender: linux-usb-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-usb@vger.kernel.org Mention the issue with fixed UDC addresses. Links external examples and test suite. Add more implmenetation details and potential improvements. Signed-off-by: Andrey Konovalov --- Documentation/usb/raw-gadget.rst | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/Documentation/usb/raw-gadget.rst b/Documentation/usb/raw-gadget.rst index 3b3d78e850b2..68d879a8009e 100644 --- a/Documentation/usb/raw-gadget.rst +++ b/Documentation/usb/raw-gadget.rst @@ -49,10 +49,36 @@ The typical usage of Raw Gadget looks like: Raw Gadget and react to those depending on what kind of USB device needs to be emulated. +Note, that some UDC drivers have fixed addresses assigned to endpoints, and +therefore arbitrary endpoint addresses can't be used in the descriptors. +Nevertheles, Raw Gadget provides a UDC-agnostic way to write USB gadgets. +Once a USB_RAW_EVENT_CONNECT event is received via USB_RAW_IOCTL_EVENT_FETCH, +the USB_RAW_IOCTL_EPS_INFO ioctl can be used to find out information about +endpoints that the UDC driver has. Based on that information, the user must +chose UDC endpoints that will be used for the gadget being emulated, and +properly assign addresses in endpoint descriptors. + +You can find usage examples (along with a test suite) here: + +https://github.com/xairy/raw-gadget + +Internal details +~~~~~~~~~~~~~~~~ + +Currently every endpoint read/write ioctl submits a USB request and waits until +its completion. This is the desired mode for coverage-guided fuzzing (as we'd +like all USB request processing happen during the lifetime of a syscall), +and must be kept in the implementation. (This might be slow for real world +applications, thus the O_NONBLOCK improvement suggestion below.) + Potential future improvements ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -- Reporting more events (suspend, resume, etc.) through - USB_RAW_IOCTL_EVENT_FETCH. +- Report more events (suspend, resume, etc.) through USB_RAW_IOCTL_EVENT_FETCH. - Support O_NONBLOCK I/O. + +- Support USB 3 features (accept SS endpoint companion descriptor when + enabling endpoints; allow providing stream_id for bulk transfers). + +- Support ISO transfer features (expose frame_number for completed requests).