From patchwork Thu Nov 25 17:16:14 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Loic Poulain X-Patchwork-Id: 519671 Delivered-To: patch@linaro.org Received: by 2002:ac0:c605:0:0:0:0:0 with SMTP id p5csp1129337imj; Thu, 25 Nov 2021 09:05:35 -0800 (PST) X-Google-Smtp-Source: ABdhPJyxUCWj47aLBJWOYKTMWhm2+L7YS40g6t30HU4c4zqo4a+wh+DAa5R6iacZqNRB9hQm9Sty X-Received: by 2002:aa7:dc07:: with SMTP id b7mr40447061edu.327.1637859935553; Thu, 25 Nov 2021 09:05:35 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1637859935; cv=none; d=google.com; s=arc-20160816; b=z/seTzmDYvr7KqBJ8LGCEz7Bc1UwfQAeT//dOFxetiPkYqVJhJBDjEzv0xhYWt8l3v we28s0bRVpQJAzQf8ma62069HSzGkuvJ5Wc7+++6m5CEZSEfLZivlRMpuA8nd0LLrdng +vTxg38IcdNppqLWTIXThdy5GGPB0oY/xvXTWcKw5KYY7I0GM8wcbd6z3QLqv+YPtNx/ iE3TsnA+M75Cj4/QIt09TkSDl3k3xEzGaoWYlmi97pudUazV0P1+FVwYUJRqtzU14iH4 Ycs8rNTPDmqaSDZymdSBxgZqYLm/FA9N2QsyJfDZillUaEnr7c7fRh/0kNTfmHEWgpu3 3wZg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:message-id:date:subject:cc:to :from:dkim-signature; bh=mCe2k5C0FCJDW/hGDxg/izd2+wYjexkewawiOP5GbNo=; b=yx7YuiaWkHwReeFQSV008n/LDl+3ZIm7t4eb1jAEzZIxi6yJfUFEsB4KDZaBFuaBpJ dgOJ1rtCqsUs0Lql4s6Yw9TEpb5JQYNhvGNBg24sjN8bU2aSZvoNTuBKVlQ5ahg71z9e ZZTYLXLJ8ndmAqTQcNjSDvVoqzxUeyZdx6XdNWKhEqPksIZy6QNpcoIgOaVZVP4kr2Ec O86C51+lFCGZOhRLJ2jnMeU0xkIW9/o7vQtdWqJ9JiYEc/dZZMBUiuuzHqg5oNLkFXfZ /9FghUgcNQ2M1xlIxVn9u+vC8DPdauLHFISogLa07jtk9CSfzawLpbECJPMoksF0qaEz QAwQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=L5WZbJH1; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from phobos.denx.de (phobos.denx.de. [2a01:238:438b:c500:173d:9f52:ddab:ee01]) by mx.google.com with ESMTPS id f12si10146269edd.293.2021.11.25.09.05.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Nov 2021 09:05:35 -0800 (PST) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=L5WZbJH1; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 2a01:238:438b:c500:173d:9f52:ddab:ee01 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 7027283679; Thu, 25 Nov 2021 18:05:24 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="L5WZbJH1"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id D4FF4835A1; Thu, 25 Nov 2021 18:05:19 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.2 Received: from mail-wr1-x42c.google.com (mail-wr1-x42c.google.com [IPv6:2a00:1450:4864:20::42c]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id E05B4835EA for ; Thu, 25 Nov 2021 18:05:11 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=loic.poulain@linaro.org Received: by mail-wr1-x42c.google.com with SMTP id j3so13082491wrp.1 for ; Thu, 25 Nov 2021 09:05:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id; bh=mCe2k5C0FCJDW/hGDxg/izd2+wYjexkewawiOP5GbNo=; b=L5WZbJH1tuv4xsT5pC3gA+nmmWLP3g/3M0CX2Lxb0yKEnWNSAYp3p73eBekDIcWugY MB3dsh3tpLkb6+vxnXWe1kXz6Nrut0cqPcAA7eXCzoaTW0JwLkDbuUA76hzBZSSRE8x3 /8H3UPP6oZ0Hvog/NEmQ8l7usL5SMQGCuuH2WoEQOhPYmimnsBT9zeeYDUShHUPCv3tB 6oVgRRlLL9akTCSXHtsErqV2k1MqWD7wmhqWN0itq376mFWcKTXEnhJiBOzaah5Ne81e yIwfF9R7k7y7txfAsijuH0uVfgzHCqJ+ZXPzZQC5841OHDYs+3mA5ylXed7fncuQeI8w p+6Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=mCe2k5C0FCJDW/hGDxg/izd2+wYjexkewawiOP5GbNo=; b=PIREK4vXMGd5rJsQ5PS+W8kvfXuLng7YAUtnokEMYEODKvXDtuOQrg9aJxtVNQI8sE hpaZovFK7IjD6UkMoSX1LIPuC7A+nK4sgLv3NercVno/y87wrQ8jbug0uKly+x8lwbfA dAUn56yV1GlRQzR9ZXUwJ98Lj7hl2LGAwWEvmDjv4un+6nN0699zACnVcJPV6bIBSAly bW6DuigAARmakfIlGzWbtLXungUio3jqg9EID8pQgbdtsaQ4gDbB8AsrtCBw+WLAFV24 3OE/l7CbaSF4yO4BwfzQOU1cCcYN2ZO/dUkJj4MAxg3/YTJB6iqNHocdT5tMEm+NWbRB quMA== X-Gm-Message-State: AOAM532mxECTY6EJ37CS1dPqJv4vr9UBtxgTv6IXiBkOGcs+5rm06ERh y0Q5n4Q0O9FLsMqcWkXsNYeKpA== X-Received: by 2002:a5d:6d86:: with SMTP id l6mr8068952wrs.304.1637859909622; Thu, 25 Nov 2021 09:05:09 -0800 (PST) Received: from localhost.localdomain ([88.160.176.23]) by smtp.gmail.com with ESMTPSA id 8sm7815499wmg.24.2021.11.25.09.05.08 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 25 Nov 2021 09:05:09 -0800 (PST) From: Loic Poulain To: marex@denx.de Cc: u-boot@lists.denx.de, pali@kernel.org, Loic Poulain Subject: [PATCH v3 1/2] lib/circbuf: Make circbuf selectable symbol Date: Thu, 25 Nov 2021 18:16:14 +0100 Message-Id: <1637860575-19237-1-git-send-email-loic.poulain@linaro.org> X-Mailer: git-send-email 2.7.4 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.37 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.2 at phobos.denx.de X-Virus-Status: Clean It is currenly only used from usbtty driver but make it properly selectable via Kconfig symbol, for future usage. Signed-off-by: Loic Poulain --- v2: no change v3: add symbol description lib/Kconfig | 3 +++ lib/Makefile | 8 +++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/Kconfig b/lib/Kconfig index c535147..4c6ac2b 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -290,6 +290,9 @@ config TRACE_EARLY_ADDR the size is too small then the message which says the amount of early data being coped will the the same as the +config CIRCBUF + bool "Enable circular buffer support" + source lib/dhry/Kconfig menu "Security support" diff --git a/lib/Makefile b/lib/Makefile index 8ba745f..4daeee2 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -29,7 +29,13 @@ ifneq ($(CONFIG_CHARSET),) obj-y += charset.o endif endif -obj-$(CONFIG_USB_TTY) += circbuf.o + +ifdef CONFIG_USB_TTY +obj-y += circbuf.o +else +obj-$(CONFIG_CIRCBUF) += circbuf.o +endif + obj-y += crc8.o obj-y += crc16.o obj-$(CONFIG_ERRNO_STR) += errno_str.o From patchwork Thu Nov 25 17:16:15 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Loic Poulain X-Patchwork-Id: 519670 Delivered-To: patch@linaro.org Received: by 2002:ac0:c605:0:0:0:0:0 with SMTP id p5csp1129067imj; Thu, 25 Nov 2021 09:05:25 -0800 (PST) X-Google-Smtp-Source: ABdhPJxdi87C2lVZtin06SDtwpZVFNcQ9Z7ikOTR2TXm7uYweCZysIlbrL0eD5o2CRNzCvTbsiKs X-Received: by 2002:a17:906:1697:: with SMTP id s23mr33835804ejd.60.1637859924762; Thu, 25 Nov 2021 09:05:24 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1637859924; cv=none; d=google.com; s=arc-20160816; b=lTPT++ESannNeBsO8Jc+8zw5qPAZDCyKaqOWSYSJRPr4cO0MkIGnU7T9uDJwivnvla sYq1ARvj5SgKYWW/FdFuYzKoxUso/iBKE/wW3wVoFaO6paElhHP5jekAmb9ECNRG3T+z rXxrKcYKGaRYie6V7SiREVGeC1/zcs9oD7iTgPZ+NAvpyyg+bjZuLrbWhN9M1g8SGpCx ZFPms9JrsY8HojCXeRgO+at0I4R7uNwyYRzk+Mk3A5E5vSNI7FY/QAwbeDXHrinmLEXn Qemsz6A5/eMLAWl2FXi1ueTIGBKwGw0i2gPe6LzSrWk0Od3tpqYhHuZ7Hvr0iqK4t8r1 5RLA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:references:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature; bh=Yt+k4SyXufmet1k8qdB+O3JowCxuIej2xXdzsgOaSX4=; b=EZ5jGh6suIYWhHgvwMum+e4wNnPWnGj5vzWMGsPB69uNkYh6pEbIQAxHehMX1qD3Oh k/hHR9fdKwmz2Kr9efIY7itUaxmA1wg+OWkI73qlxYcU2sOt24OpuEPjesz7Kx4crVVX rk/j0ggjoe/l4jvL7Hfl2x+TxuKl7OGXwDFcYWMGrmCZ2PEmY+q3Hh7L4dRS34TPjs9J oDhFf8U3K9YsedU3AV9MQkSEUJosUX3s9P5OUDKAFuguQVFOX55TmwvTenlkWEWuseg/ E6dVjBPTRgQpKTAhLbWq5cfYu716D4u7qNG+cTa6G7Roo7TZgDSCM7Z3EYT/wG+uikSQ ocQw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=nZIMNDW0; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from phobos.denx.de (phobos.denx.de. [85.214.62.61]) by mx.google.com with ESMTPS id i14si7346693eds.314.2021.11.25.09.05.24 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 25 Nov 2021 09:05:24 -0800 (PST) Received-SPF: pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) client-ip=85.214.62.61; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=nZIMNDW0; spf=pass (google.com: domain of u-boot-bounces@lists.denx.de designates 85.214.62.61 as permitted sender) smtp.mailfrom=u-boot-bounces@lists.denx.de; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 74B6B834B9; Thu, 25 Nov 2021 18:05:21 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="nZIMNDW0"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id B098B8370D; Thu, 25 Nov 2021 18:05:18 +0100 (CET) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-wm1-x332.google.com (mail-wm1-x332.google.com [IPv6:2a00:1450:4864:20::332]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id D83E9835A1 for ; Thu, 25 Nov 2021 18:05:11 +0100 (CET) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=loic.poulain@linaro.org Received: by mail-wm1-x332.google.com with SMTP id p3-20020a05600c1d8300b003334fab53afso8834860wms.3 for ; Thu, 25 Nov 2021 09:05:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Yt+k4SyXufmet1k8qdB+O3JowCxuIej2xXdzsgOaSX4=; b=nZIMNDW0OiqRiN+YDggi4FRL+NEKx8ckXvBkC6Qy2pGOjL/IjeDAZ9LKrb7KmM9djM dDRqH/5k6ijvOs3o+qDvYBWvo0yFrPejWMNUjRIeAqTS+vSfF8mrA40v/elzVjqPQzdJ INr9OHGQ09CmJugUkGK/7Zwhf9M1j3HZizgkr08e+7K0qJ0yJykZui6jMaJZH0t6W5cx McS4oxbHyEWDmqnkhPPWbKYgyM3h0htwu6M3Mq4q193s5Hm48I0WfIXA6Y7D9xzAvqOv qp2y0D4ATP/u6ktkIqlCMRxpIZU+OaudMiOuQNkbPzw9gLp4gL4VqGG8xDNpVcYsYs2l bo4g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Yt+k4SyXufmet1k8qdB+O3JowCxuIej2xXdzsgOaSX4=; b=gnXndwPheBk0sL7HHYARUejHkrilyfw/i5C/6e6TlsSyAlaLl0fsvPc/3NpbTIzVAM ihqJRN97+GvF76CTC7iwGYnU0QT7TU/qbs0+l/70mrVhB3Q1nv8YhAozOCVZS43lhTpN yRGdxLloPM3YyXvkB4u7RpfyE9FXU3j7wqqOqu6ONldxr4bFMry3ogW3o01bp2bhCl0s v3KFYHreok67k5VlJXJb5vvuUb6u1tkoIkFGRGCR0TCzsrXJ+GOWUCg+7KaJ6tmtrG+b mMD50TSzaWrQ5O1jdEgGWPd8YvjRE1C4ht2iNYGsHhRfWge4zCYcyIpBA8atmpTlvbRe odWg== X-Gm-Message-State: AOAM532JcrtQUbXlwbKj1jXKmbxcgPorx4DGLwareOONVvDJeIwxjqxv x4cdEeqEBSKR72DRUOktE2yyXQ== X-Received: by 2002:a1c:43c1:: with SMTP id q184mr9221992wma.153.1637859911279; Thu, 25 Nov 2021 09:05:11 -0800 (PST) Received: from localhost.localdomain ([88.160.176.23]) by smtp.gmail.com with ESMTPSA id 8sm7815499wmg.24.2021.11.25.09.05.10 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Thu, 25 Nov 2021 09:05:10 -0800 (PST) From: Loic Poulain To: marex@denx.de Cc: u-boot@lists.denx.de, pali@kernel.org, Loic Poulain Subject: [PATCH v3 2/2] usb: gadget: Add CDC ACM function Date: Thu, 25 Nov 2021 18:16:15 +0100 Message-Id: <1637860575-19237-2-git-send-email-loic.poulain@linaro.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1637860575-19237-1-git-send-email-loic.poulain@linaro.org> References: <1637860575-19237-1-git-send-email-loic.poulain@linaro.org> X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.37 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.2 at phobos.denx.de X-Virus-Status: Clean Add support for CDC ACM using the new UDC and gadget API. This protocol can be used for serial over USB data transfer and is widely supported by various OS (GNU/Linux, MS-Windows, OSX...). The usual purpose of such link is to access device debug console and can be useful for products not exposing regular UART to the user. A default stdio device named 'usbacm' is created, and can be used to redirect console to USB link over CDC ACM: > setenv stdin usbacm; setenv stdout usbacm Signed-off-by: Loic Poulain --- v2: - remove possible infinite recursipe print loop - Remove acmconsole command, start function along the stdio device v3: - Use __constant_cpu_to_le16() when possible - Rename stdio dev to 'usbacm' - Rename init function to drv_usbacm_init common/stdio.c | 3 + drivers/usb/gadget/Kconfig | 9 + drivers/usb/gadget/Makefile | 1 + drivers/usb/gadget/f_acm.c | 672 ++++++++++++++++++++++++++++++++++++++++++++ include/stdio_dev.h | 1 + 5 files changed, 686 insertions(+) create mode 100644 drivers/usb/gadget/f_acm.c diff --git a/common/stdio.c b/common/stdio.c index 4083e4e..e07e4a4 100644 --- a/common/stdio.c +++ b/common/stdio.c @@ -381,6 +381,9 @@ int stdio_add_devices(void) #ifdef CONFIG_USB_TTY drv_usbtty_init(); #endif +#ifdef CONFIG_USB_FUNCTION_ACM + drv_usbacm_init (); +#endif if (IS_ENABLED(CONFIG_NETCONSOLE)) drv_nc_init(); #ifdef CONFIG_JTAG_CONSOLE diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig index 327ea86..d81a9c5 100644 --- a/drivers/usb/gadget/Kconfig +++ b/drivers/usb/gadget/Kconfig @@ -182,6 +182,15 @@ config USB_FUNCTION_THOR Enable Tizen's THOR download protocol support in U-Boot. It allows downloading images into memory and flash them to target device. +config USB_FUNCTION_ACM + bool "Enable CDC ACM gadget" + select SYS_STDIO_DEREGISTER + select CIRCBUF + help + ACM serial link. This function can be used to create a stdio device to + interoperate with MS-Windows hosts or with the Linux-USB "cdc-acm" + driver. + endif # USB_GADGET_DOWNLOAD config USB_ETHER diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile index f560068..d5d891b 100644 --- a/drivers/usb/gadget/Makefile +++ b/drivers/usb/gadget/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_USB_FUNCTION_MASS_STORAGE) += f_mass_storage.o obj-$(CONFIG_USB_FUNCTION_FASTBOOT) += f_fastboot.o obj-$(CONFIG_USB_FUNCTION_SDP) += f_sdp.o obj-$(CONFIG_USB_FUNCTION_ROCKUSB) += f_rockusb.o +obj-$(CONFIG_USB_FUNCTION_ACM) += f_acm.o endif endif ifdef CONFIG_USB_ETHER diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c new file mode 100644 index 0000000..388f73d --- /dev/null +++ b/drivers/usb/gadget/f_acm.c @@ -0,0 +1,672 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * USB CDC serial (ACM) function driver + * + * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) + * Copyright (C) 2008 by David Brownell + * Copyright (C) 2008 by Nokia Corporation + * Copyright (C) 2009 by Samsung Electronics + * Copyright (c) 2021, Linaro Ltd + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define REQ_SIZE_MAX 512 + +struct f_acm { + int ctrl_id; + int data_id; + + struct usb_ep *ep_in; + struct usb_ep *ep_out; + struct usb_ep *ep_notify; + + struct usb_request *req_in; + struct usb_request *req_out; + + bool connected; + bool tx_on; + + circbuf_t rx_buf; + circbuf_t tx_buf; + + struct usb_function usb_function; + + struct usb_cdc_line_coding line_coding; + u16 handshake_bits; +#define ACM_CTRL_RTS BIT(1) /* unused with full duplex */ +#define ACM_CTRL_DTR BIT(0) /* host is ready for data r/w */ + + int controller_index; +}; + +static struct f_acm *default_acm_function; + +static inline struct f_acm *func_to_acm(struct usb_function *f) +{ + return container_of(f, struct f_acm, usb_function); +} + +static inline struct f_acm *stdio_to_acm(struct stdio_dev *s) +{ + /* stdio dev is cloned on registration, do not use container_of */ + return s->priv; +} + +static struct usb_interface_assoc_descriptor +acm_iad_descriptor = { + .bLength = sizeof(acm_iad_descriptor), + .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, + .bFirstInterface = 0, + .bInterfaceCount = 2, // control + data + .bFunctionClass = USB_CLASS_COMM, + .bFunctionSubClass = USB_CDC_SUBCLASS_ACM, + .bFunctionProtocol = USB_CDC_ACM_PROTO_AT_V25TER, +}; + +static struct usb_interface_descriptor acm_control_intf_desc = { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bNumEndpoints = 1, + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM, + .bInterfaceProtocol = USB_CDC_ACM_PROTO_AT_V25TER, +}; + +static struct usb_interface_descriptor acm_data_intf_desc = { + .bLength = sizeof(acm_data_intf_desc), + .bDescriptorType = USB_DT_INTERFACE, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_CDC_DATA, +}; + +static struct usb_cdc_header_desc acm_header_desc = { + .bLength = sizeof(acm_header_desc), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_HEADER_TYPE, + .bcdCDC = __constant_cpu_to_le16(0x0110), +}; + +static struct usb_cdc_call_mgmt_descriptor acm_call_mgmt_desc = { + .bLength = sizeof(acm_call_mgmt_desc), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_CALL_MANAGEMENT_TYPE, + .bmCapabilities = 0, + .bDataInterface = 0x01, +}; + +static struct usb_cdc_acm_descriptor acm_desc = { + .bLength = sizeof(acm_desc), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_ACM_TYPE, + .bmCapabilities = USB_CDC_CAP_LINE, +}; + +static struct usb_cdc_union_desc acm_union_desc = { + .bLength = sizeof(acm_union_desc), + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_UNION_TYPE, + .bMasterInterface0 = 0x00, + .bSlaveInterface0 = 0x01, +}; + +static struct usb_endpoint_descriptor acm_fs_notify_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 3 | USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = __constant_cpu_to_le16(64), + .bInterval = 32, +}; + +static struct usb_endpoint_descriptor acm_fs_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +static struct usb_endpoint_descriptor acm_fs_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +static struct usb_descriptor_header *acm_fs_function[] = { + (struct usb_descriptor_header *)&acm_iad_descriptor, + (struct usb_descriptor_header *)&acm_control_intf_desc, + (struct usb_descriptor_header *)&acm_header_desc, + (struct usb_descriptor_header *)&acm_call_mgmt_desc, + (struct usb_descriptor_header *)&acm_desc, + (struct usb_descriptor_header *)&acm_union_desc, + (struct usb_descriptor_header *)&acm_fs_notify_desc, + (struct usb_descriptor_header *)&acm_data_intf_desc, + (struct usb_descriptor_header *)&acm_fs_in_desc, + (struct usb_descriptor_header *)&acm_fs_out_desc, + NULL, +}; + +static struct usb_endpoint_descriptor acm_hs_notify_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_INT, + .wMaxPacketSize = __constant_cpu_to_le16(64), + .bInterval = 11, +}; + +static struct usb_endpoint_descriptor acm_hs_in_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(512), +}; + +static struct usb_endpoint_descriptor acm_hs_out_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(512), +}; + +static struct usb_descriptor_header *acm_hs_function[] = { + (struct usb_descriptor_header *)&acm_iad_descriptor, + (struct usb_descriptor_header *)&acm_control_intf_desc, + (struct usb_descriptor_header *)&acm_header_desc, + (struct usb_descriptor_header *)&acm_call_mgmt_desc, + (struct usb_descriptor_header *)&acm_desc, + (struct usb_descriptor_header *)&acm_union_desc, + (struct usb_descriptor_header *)&acm_hs_notify_desc, + (struct usb_descriptor_header *)&acm_data_intf_desc, + (struct usb_descriptor_header *)&acm_hs_in_desc, + (struct usb_descriptor_header *)&acm_hs_out_desc, + NULL, +}; + +static inline struct usb_endpoint_descriptor * +ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs, + struct usb_endpoint_descriptor *fs) +{ + if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH) + return hs; + return fs; +} + +static int acm_bind(struct usb_configuration *c, struct usb_function *f) +{ + struct usb_gadget *gadget = c->cdev->gadget; + struct f_acm *f_acm = func_to_acm(f); + struct usb_ep *ep; + int id; + + id = usb_interface_id(c, f); + if (id < 0) + return id; + + acm_iad_descriptor.bFirstInterface = id; + acm_control_intf_desc.bInterfaceNumber = id; + acm_union_desc.bMasterInterface0 = id; + + f_acm->ctrl_id = id; + + id = usb_interface_id(c, f); + if (id < 0) + return id; + + acm_data_intf_desc.bInterfaceNumber = id; + acm_union_desc.bSlaveInterface0 = id; + acm_call_mgmt_desc.bDataInterface = id; + + f_acm->data_id = id; + + /* allocate instance-specific endpoints */ + ep = usb_ep_autoconfig(gadget, &acm_fs_in_desc); + if (!ep) + return -ENODEV; + + f_acm->ep_in = ep; + + ep = usb_ep_autoconfig(gadget, &acm_fs_out_desc); + if (!ep) + return -ENODEV; + + f_acm->ep_out = ep; + + ep = usb_ep_autoconfig(gadget, &acm_fs_notify_desc); + if (!ep) + return -ENODEV; + + f_acm->ep_notify = ep; + + if (gadget_is_dualspeed(gadget)) { + /* Assume endpoint addresses are the same for both speeds */ + acm_hs_in_desc.bEndpointAddress = acm_fs_in_desc.bEndpointAddress; + acm_hs_out_desc.bEndpointAddress = acm_fs_out_desc.bEndpointAddress; + acm_hs_notify_desc.bEndpointAddress = acm_fs_notify_desc.bEndpointAddress; + } + + return 0; +} + +static void acm_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct f_acm *f_acm = func_to_acm(f); + + if (default_acm_function == f_acm) + default_acm_function = NULL; + + buf_free(&f_acm->rx_buf); + buf_free(&f_acm->tx_buf); + + free(f_acm); +} + +static void acm_notify_complete(struct usb_ep *ep, struct usb_request *req) +{ + /* nothing to do */ +} + +static void acm_tx_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_acm *f_acm = req->context; + + f_acm->tx_on = true; +} + +static void acm_rx_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_acm *f_acm = req->context; + + buf_push(&f_acm->rx_buf, req->buf, req->actual); + + /* Queue RX req again */ + req->actual = 0; + usb_ep_queue(ep, req, 0); +} + +static struct usb_request *acm_start_ep(struct usb_ep *ep, void *complete_cb, + void *context) +{ + struct usb_request *req; + + req = usb_ep_alloc_request(ep, 0); + if (!req) + return NULL; + + req->length = REQ_SIZE_MAX; + req->buf = memalign(CONFIG_SYS_CACHELINE_SIZE, REQ_SIZE_MAX); + if (!req->buf) { + usb_ep_free_request(ep, req); + return NULL; + } + + memset(req->buf, 0, req->length); + req->complete = complete_cb; + req->context = context; + + return req; +} + +static int acm_start_data(struct f_acm *f_acm, struct usb_gadget *gadget) +{ + const struct usb_endpoint_descriptor *d; + int ret; + + /* EP IN */ + d = ep_desc(gadget, &acm_hs_in_desc, &acm_fs_in_desc); + ret = usb_ep_enable(f_acm->ep_in, d); + if (ret) + return ret; + + f_acm->req_in = acm_start_ep(f_acm->ep_in, acm_tx_complete, f_acm); + + /* EP OUT */ + d = ep_desc(gadget, &acm_hs_out_desc, &acm_fs_out_desc); + ret = usb_ep_enable(f_acm->ep_out, d); + if (ret) + return ret; + + f_acm->req_out = acm_start_ep(f_acm->ep_out, acm_rx_complete, f_acm); + + /* Start OUT transfer (EP OUT) */ + ret = usb_ep_queue(f_acm->ep_out, f_acm->req_out, 0); + if (ret) + return ret; + + return 0; +} + +static int acm_start_ctrl(struct f_acm *f_acm, struct usb_gadget *gadget) +{ + const struct usb_endpoint_descriptor *d; + + usb_ep_disable(f_acm->ep_notify); + + d = ep_desc(gadget, &acm_hs_notify_desc, &acm_fs_notify_desc); + usb_ep_enable(f_acm->ep_notify, d); + + acm_start_ep(f_acm->ep_notify, acm_notify_complete, f_acm); + + return 0; +} + +static int acm_set_alt(struct usb_function *f, unsigned int intf, unsigned int alt) +{ + struct usb_gadget *gadget = f->config->cdev->gadget; + struct f_acm *f_acm = func_to_acm(f); + + if (intf == f_acm->ctrl_id) { + return acm_start_ctrl(f_acm, gadget); + } else if (intf == f_acm->data_id) { + acm_start_data(f_acm, gadget); + f_acm->connected = true; + f_acm->tx_on = true; + return 0; + } + + return -EINVAL; +} + +static int acm_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) +{ + struct usb_gadget *gadget = f->config->cdev->gadget; + struct usb_request *req = f->config->cdev->req; + u16 w_index = le16_to_cpu(ctrl->wIndex); + u16 w_value = le16_to_cpu(ctrl->wValue); + u16 w_length = le16_to_cpu(ctrl->wLength); + struct f_acm *f_acm = func_to_acm(f); + int value = -1; + + switch ((ctrl->bRequestType << 8) | ctrl->bRequest) { + case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) + | USB_CDC_REQ_SET_LINE_CODING: + /* SET_LINE_CODING */ + + if (w_length != sizeof(f_acm->line_coding) || w_index != f_acm->ctrl_id) + goto invalid; + + value = w_length; + + memcpy(&f_acm->line_coding, req->buf, value); + + break; + case ((USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) + | USB_CDC_REQ_GET_LINE_CODING: + /* GET_LINE_CODING */ + + if (w_length != sizeof(f_acm->line_coding) || w_index != f_acm->ctrl_id) + goto invalid; + + value = w_length; + + memcpy(req->buf, &f_acm->line_coding, value); + + break; + case ((USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) << 8) + | USB_CDC_REQ_SET_CONTROL_LINE_STATE: + /* SET_CONTROL_LINE_STATE */ + + if (w_index != f_acm->ctrl_id) + goto invalid; + + value = 0; + + f_acm->handshake_bits = w_value; + + break; + default: +invalid: + printf("invalid control req%02x.%02x v%04x i%04x l%d\n", + ctrl->bRequestType, ctrl->bRequest, w_value, w_index, + w_length); + } + + /* respond with data transfer or status phase? */ + if (value >= 0) { + req->zero = 0; + req->length = value; + usb_ep_queue(gadget->ep0, req, GFP_ATOMIC); + } + + return 0; +} + +static void acm_disable(struct usb_function *f) +{ + struct f_acm *f_acm = func_to_acm(f); + + usb_ep_disable(f_acm->ep_out); + usb_ep_disable(f_acm->ep_in); + usb_ep_disable(f_acm->ep_notify); + + if (f_acm->req_out) { + free(f_acm->req_out->buf); + usb_ep_free_request(f_acm->ep_out, f_acm->req_out); + f_acm->req_out = NULL; + } + + if (f_acm->req_in) { + free(f_acm->req_in->buf); + usb_ep_free_request(f_acm->ep_in, f_acm->req_in); + f_acm->req_in = NULL; + } +} + +/* static strings, in UTF-8 */ +static struct usb_string acm_string_defs[] = { + [0].s = "CDC Abstract Control Model (ACM)", + [1].s = "CDC ACM Data", + [2].s = "CDC Serial", + { } /* end of list */ +}; + +static struct usb_gadget_strings acm_string_table = { + .language = 0x0409, /* en-us */ + .strings = acm_string_defs, +}; + +static struct usb_gadget_strings *acm_strings[] = { + &acm_string_table, + NULL, +}; + +static void __acm_tx(struct f_acm *f_acm) +{ + int len, ret; + + do { + usb_gadget_handle_interrupts(f_acm->controller_index); + + if (!(f_acm->handshake_bits & ACM_CTRL_DTR)) + break; + + if (!f_acm->tx_on) + continue; + + len = buf_pop(&f_acm->tx_buf, f_acm->req_in->buf, REQ_SIZE_MAX); + if (!len) + break; + + f_acm->req_in->length = len; + + ret = usb_ep_queue(f_acm->ep_in, f_acm->req_in, 0); + if (ret) + break; + + f_acm->tx_on = false; + + /* Do not reset the watchdog, if TX is stuck there is probably + * a real issue. + */ + } while (1); +} + +static bool acm_connected(struct stdio_dev *dev) +{ + struct f_acm *f_acm = stdio_to_acm(dev); + + /* give a chance to process udc irq */ + usb_gadget_handle_interrupts(f_acm->controller_index); + + return f_acm->connected; +} + +static int acm_add(struct usb_configuration *c) +{ + struct f_acm *f_acm; + int status; + + f_acm = calloc(1, sizeof(*f_acm)); + if (!f_acm) + return -ENOMEM; + + f_acm->usb_function.name = "f_acm"; + f_acm->usb_function.bind = acm_bind; + f_acm->usb_function.unbind = acm_unbind; + f_acm->usb_function.set_alt = acm_set_alt; + f_acm->usb_function.disable = acm_disable; + f_acm->usb_function.strings = acm_strings; + f_acm->usb_function.descriptors = acm_fs_function; + f_acm->usb_function.hs_descriptors = acm_hs_function; + f_acm->usb_function.setup = acm_setup; + f_acm->controller_index = 0; + + status = usb_add_function(c, &f_acm->usb_function); + if (status) { + free(f_acm); + return status; + } + + buf_init(&f_acm->rx_buf, 2048); + buf_init(&f_acm->tx_buf, 2048); + + if (!default_acm_function) + default_acm_function = f_acm; + + return status; +} + +DECLARE_GADGET_BIND_CALLBACK(usb_serial_acm, acm_add); + +/* STDIO */ +static int acm_stdio_tstc(struct stdio_dev *dev) +{ + struct f_acm *f_acm = stdio_to_acm(dev); + + usb_gadget_handle_interrupts(f_acm->controller_index); + + return (f_acm->rx_buf.size > 0); +} + +static int acm_stdio_getc(struct stdio_dev *dev) +{ + struct f_acm *f_acm = stdio_to_acm(dev); + char c; + + /* Wait for a character to arrive. */ + while (!acm_stdio_tstc(dev)) + WATCHDOG_RESET(); + + buf_pop(&f_acm->rx_buf, &c, 1); + + return c; +} + +static void acm_stdio_putc(struct stdio_dev *dev, const char c) +{ + struct f_acm *f_acm = stdio_to_acm(dev); + + if (c == '\n') + buf_push(&f_acm->tx_buf, "\r", 1); + + buf_push(&f_acm->tx_buf, &c, 1); + + if (!f_acm->connected) + return; + + __acm_tx(f_acm); +} + +static void acm_stdio_puts(struct stdio_dev *dev, const char *str) +{ + struct f_acm *f_acm = stdio_to_acm(dev); + + while (*str) { + if (*str == '\n') + buf_push(&f_acm->tx_buf, "\r", 1); + + buf_push(&f_acm->tx_buf, str++, 1); + } + + if (!f_acm->connected) + return; + + __acm_tx(f_acm); +} + +static int acm_stdio_start(struct stdio_dev *dev) +{ + int ret; + + if (dev->priv) { /* function already exist */ + return 0; + } + + ret = g_dnl_register("usb_serial_acm"); + if (ret) + return ret; + + if (default_acm_function) + dev->priv = default_acm_function; + else + return -ENODEV; + + while (!acm_connected(dev)) { + if (ctrlc()) + return -ECANCELED; + + WATCHDOG_RESET(); + } + + return 0; +} + +static int acm_stdio_stop(struct stdio_dev *dev) +{ + g_dnl_unregister(); + g_dnl_clear_detach(); + + return 0; +} + +int drv_usbacm_init(void) +{ + struct stdio_dev stdio; + + strcpy(stdio.name, "usbacm"); + stdio.flags = DEV_FLAGS_INPUT | DEV_FLAGS_OUTPUT; + stdio.tstc = acm_stdio_tstc; + stdio.getc = acm_stdio_getc; + stdio.putc = acm_stdio_putc; + stdio.puts = acm_stdio_puts; + stdio.start = acm_stdio_start; + stdio.stop = acm_stdio_stop; + stdio.priv = NULL; + stdio.ext = 0; + + return stdio_register(&stdio); +} diff --git a/include/stdio_dev.h b/include/stdio_dev.h index 8fb9a12..270fa27 100644 --- a/include/stdio_dev.h +++ b/include/stdio_dev.h @@ -103,6 +103,7 @@ int drv_lcd_init(void); int drv_video_init(void); int drv_keyboard_init(void); int drv_usbtty_init(void); +int drv_usbacm_init(void); int drv_nc_init(void); int drv_jtag_console_init(void); int cbmemc_init(void);