From nobody Thu Dec 25 16:32:45 2025 Received: from metis.whiteo.stw.pengutronix.de (metis.whiteo.stw.pengutronix.de [185.203.201.7]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BD7BF111B0 for ; Tue, 16 Jan 2024 01:49:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=pengutronix.de Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=pengutronix.de Received: from drehscheibe.grey.stw.pengutronix.de ([2a0a:edc0:0:c01:1d::a2]) by metis.whiteo.stw.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1rPYaJ-0000l1-8h; Tue, 16 Jan 2024 02:49:47 +0100 Received: from [2a0a:edc0:0:1101:1d::ac] (helo=dude04.red.stw.pengutronix.de) by drehscheibe.grey.stw.pengutronix.de with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1rPYaI-0008V9-1k; Tue, 16 Jan 2024 02:49:46 +0100 Received: from localhost ([::1] helo=dude04.red.stw.pengutronix.de) by dude04.red.stw.pengutronix.de with esmtp (Exim 4.96) (envelope-from ) id 1rPYaI-001Ipo-2n; Tue, 16 Jan 2024 02:49:45 +0100 From: Michael Grzeschik Date: Tue, 16 Jan 2024 02:49:42 +0100 Subject: [PATCH 2/3] usb: gadget: legacy: add 9pfs multi gadget Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20240116-ml-topic-u9p-v1-2-ad8c306f9a4e@pengutronix.de> References: <20240116-ml-topic-u9p-v1-0-ad8c306f9a4e@pengutronix.de> In-Reply-To: <20240116-ml-topic-u9p-v1-0-ad8c306f9a4e@pengutronix.de> To: Eric Van Hensbergen , Latchesar Ionkov , Dominique Martinet , Christian Schoenebeck , Jonathan Corbet , Greg Kroah-Hartman Cc: v9fs@lists.linux.dev, linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org, kernel@pengutronix.de, Michael Grzeschik X-Mailer: b4 0.12.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=9509; i=m.grzeschik@pengutronix.de; h=from:subject:message-id; bh=Xu6jhE/WKBDfZroRTls+7q0f0LPBQz+JPndm2l4PnmI=; b=owEBbQKS/ZANAwAKAb9pWET5cfSrAcsmYgBlpeC5YN8375TXaFRS2Zh/6M+xFr4mcr/zcDuAF m5uMeRl+9OJAjMEAAEKAB0WIQQV2+2Fpbqd6fvv0Gi/aVhE+XH0qwUCZaXguQAKCRC/aVhE+XH0 q0qeEACJaHVRsNJiBecygz2LA35PwtVSan7Op3Mx8Dgd7xOVjfdUBaL/3ejGQnIQ7oENHAWXS1i u09Ke/QPKXtxg2smvCsVlhvqSAgGaD1pSBw8b3efOUMmsRqhECh8Ywk9PZ6S1ALlNhScShOYL8Q GQy3LSDOCnXcr7gIpgKss8RSfWSGX5AIg5SGglYa8sY0wqSJ8RsRQLWffjfcd/CnTrbrZjZGXls IM/bJicMstrAaM8W8TchY7Vvh3mo+KHRNc4iTSlym+6k7SYgrIARmUdjNy6UYIh8uxdAvUxEi3h 2M1TDzj6DTvQJ+G70EYN4JS2LE/Ztr5/tIJ6ZtZxfrLOV2WzP1sKnMDZd6H+9s7pGYawilHSeMh 4fdI129wmmZTNCFcU7LV6YD8GYKP2/OCvoKNqYoS2o3r13mVfvgosChL33jZLW3D8Em6AGITi8Q pEAyFQXlff1z6i8yOgdS2rs/fqRFYfI+vZH2d6JkqDLh+FV8KKasCYxNtS5kVdi4YXcsOREGV89 awPtNxC+tvGXymyrEFCvVMBIohsfboMcaPEgfdteFeCPh36AaznJNPu2CrBsHaqctPKpqQ+27hS zi9v9Pe0dWu0ruQtJNtT+T8w2YFC2ag2WJ+9JWtNSbI9xOHFwhWy94NU8W9AgDp1uQ2ERTBXJux rXOKdZJ3ogPSDIQ== X-Developer-Key: i=m.grzeschik@pengutronix.de; a=openpgp; fpr=957BC452CE953D7EA60CF4FC0BE9E3157A1E2C64 X-SA-Exim-Connect-IP: 2a0a:edc0:0:c01:1d::a2 X-SA-Exim-Mail-From: m.grzeschik@pengutronix.de X-SA-Exim-Scanned: No (on metis.whiteo.stw.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-kernel@vger.kernel.org Add the newly introduced 9pfs transport gadget interface with an new multi composed gadget together with acm and eem. The usb forwarding can be started as follows: Start the Network export via diod to localhost: $ diod -f -n -d 0 -S -l 0.0.0.0:9999 -e $PWD Start the python transport: $ python p9_fwd.py The gadget can then mount the exported filesystem: $ mount -t 9p -o trans=3Dusbg,aname=3D$PWD usb9pfs0 /mnt/9p When using this legacy module, it is also possible to mount the 9PFS usb dir as root filesystem. The kernel commandline looks like this: root=3Dusb9pfs0 rootfstype=3D9p rootflags=3Dtrans=3Dusbg,cache=3Dloose,unam= e=3Droot,access=3D0,dfltuid=3D0,dfltgid=3D0,aname=3D/path/to/rootfs Signed-off-by: Michael Grzeschik --- drivers/usb/gadget/legacy/9pfs.c | 260 +++++++++++++++++++++++++++++++++= ++++ drivers/usb/gadget/legacy/Kconfig | 15 +++ drivers/usb/gadget/legacy/Makefile | 2 + 3 files changed, 277 insertions(+) diff --git a/drivers/usb/gadget/legacy/9pfs.c b/drivers/usb/gadget/legacy/9= pfs.c new file mode 100644 index 0000000000000..e38fc89c89ded --- /dev/null +++ b/drivers/usb/gadget/legacy/9pfs.c @@ -0,0 +1,260 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * usb9pfs.c -- Gadget usb9pfs + * + * Copyright (C) 2023 Michael Grzeschik + */ + +/* + * Gadget usb9pfs only needs two bulk endpoints, and will use the usb9pfs = usb + * transport to mount host filesystem via usb gadget. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "u_eem.h" +#include "u_ether.h" + +/*------------------------------------------------------------------------= -*/ +USB_GADGET_COMPOSITE_OPTIONS(); + +USB_ETHERNET_MODULE_PARAMETERS(); + +/* Defines */ + +#define DRIVER_VERSION_STR "v1.0" +#define DRIVER_VERSION_NUM 0x1000 + +#define DRIVER_DESC "Composite Gadget (9P + ACM + NCM)" + +/*------------------------------------------------------------------------= -*/ + +#define DRIVER_VENDOR_NUM 0x1d6b /* Linux Foundation */ +#define DRIVER_PRODUCT_NUM 0x0109 /* Linux-USB 9PFS Gadget */ + +/*------------------------------------------------------------------------= -*/ + +static struct usb_device_descriptor device_desc =3D { + .bLength =3D sizeof(device_desc), + .bDescriptorType =3D USB_DT_DEVICE, + + /* .bcdUSB =3D DYNAMIC */ + + .bDeviceClass =3D USB_CLASS_MISC, + .bDeviceSubClass =3D 2, + .bDeviceProtocol =3D 1, + + /* .bMaxPacketSize0 =3D f(hardware) */ + + /* Vendor and product id can be overridden by module parameters. */ + .idVendor =3D cpu_to_le16(DRIVER_VENDOR_NUM), + .idProduct =3D cpu_to_le16(DRIVER_PRODUCT_NUM), + /* .bcdDevice =3D f(hardware) */ + /* .iManufacturer =3D DYNAMIC */ + /* .iProduct =3D DYNAMIC */ + /* NO SERIAL NUMBER */ + /*.bNumConfigurations =3D DYNAMIC*/ +}; + +static const struct usb_descriptor_header *otg_desc[2]; + +static struct usb_string strings_dev[] =3D { + [USB_GADGET_MANUFACTURER_IDX].s =3D "", + [USB_GADGET_PRODUCT_IDX].s =3D DRIVER_DESC, + [USB_GADGET_SERIAL_IDX].s =3D "", + { } /* end of list */ +}; + +static struct usb_gadget_strings stringtab_dev =3D { + .language =3D 0x0409, /* en-us */ + .strings =3D strings_dev, +}; + +static struct usb_gadget_strings *dev_strings[] =3D { + &stringtab_dev, + NULL, +}; + +static struct usb_configuration cdc_driver_conf =3D { + .label =3D DRIVER_DESC, + .bConfigurationValue =3D 1, + /* .iConfiguration =3D DYNAMIC */ + .bmAttributes =3D USB_CONFIG_ATT_SELFPOWER, +}; + +static struct usb_function *f_9pfs; +static struct usb_function_instance *fi_9pfs; + +static struct usb_function *f_acm; +static struct usb_function_instance *fi_acm; + +static struct usb_function *f_eem; +static struct usb_function_instance *fi_eem; + +static int cdc_do_config(struct usb_configuration *c) +{ + int ret; + + if (gadget_is_otg(c->cdev->gadget)) { + c->descriptors =3D otg_desc; + c->bmAttributes |=3D USB_CONFIG_ATT_WAKEUP; + } + + f_9pfs =3D usb_get_function(fi_9pfs); + if (IS_ERR(f_9pfs)) + return PTR_ERR(f_9pfs); + + ret =3D usb_add_function(c, f_9pfs); + if (ret < 0) + goto err_func_9pfs; + + f_acm =3D usb_get_function(fi_acm); + if (IS_ERR(f_acm)) { + ret =3D PTR_ERR(f_acm); + goto err_func_acm; + } + + ret =3D usb_add_function(c, f_acm); + if (ret) + goto err_conf; + + f_eem =3D usb_get_function(fi_eem); + if (IS_ERR(f_eem)) { + ret =3D PTR_ERR(f_eem); + goto err_eem; + } + + ret =3D usb_add_function(c, f_eem); + if (ret) + goto err_run; + + return 0; +err_run: + usb_put_function(f_eem); +err_eem: + usb_remove_function(c, f_acm); +err_conf: + usb_put_function(f_acm); +err_func_acm: + usb_remove_function(c, f_9pfs); +err_func_9pfs: + usb_put_function(f_9pfs); + return ret; +} + +static int usb9pfs_bind(struct usb_composite_dev *cdev) +{ + struct f_eem_opts *eem_opts =3D NULL; + int status; + + fi_9pfs =3D usb_get_function_instance("usb9pfs"); + if (IS_ERR(fi_9pfs)) + return PTR_ERR(fi_9pfs); + + /* set up serial link layer */ + fi_acm =3D usb_get_function_instance("acm"); + if (IS_ERR(fi_acm)) { + status =3D PTR_ERR(fi_acm); + goto err_conf_acm; + } + + fi_eem =3D usb_get_function_instance("eem"); + if (IS_ERR(fi_eem)) { + status =3D PTR_ERR(fi_eem); + goto err_conf_eem; + } + + eem_opts =3D container_of(fi_eem, struct f_eem_opts, func_inst); + + gether_set_qmult(eem_opts->net, qmult); + if (!gether_set_host_addr(eem_opts->net, host_addr)) + pr_info("using host ethernet address: %s", host_addr); + if (!gether_set_dev_addr(eem_opts->net, dev_addr)) + pr_info("using self ethernet address: %s", dev_addr); + + /* Allocate string descriptor numbers ... note that string + * contents can be overridden by the composite_dev glue. + */ + status =3D usb_string_ids_tab(cdev, strings_dev); + if (status < 0) + return status; + + device_desc.iManufacturer =3D strings_dev[USB_GADGET_MANUFACTURER_IDX].id; + device_desc.iProduct =3D strings_dev[USB_GADGET_PRODUCT_IDX].id; + device_desc.iSerialNumber =3D strings_dev[USB_GADGET_SERIAL_IDX].id; + + /* support OTG systems */ + if (gadget_is_otg(cdev->gadget)) { + if (!otg_desc[0]) { + struct usb_descriptor_header *usb_desc; + + usb_desc =3D usb_otg_descriptor_alloc(cdev->gadget); + if (!usb_desc) { + status =3D -ENOMEM; + goto err_conf_otg; + } + usb_otg_descriptor_init(cdev->gadget, usb_desc); + otg_desc[0] =3D usb_desc; + otg_desc[1] =3D NULL; + } + } + + status =3D usb_add_config(cdev, &cdc_driver_conf, cdc_do_config); + if (status) + goto err_free_otg_desc; + + usb_ep_autoconfig_reset(cdev->gadget); + usb_composite_overwrite_options(cdev, &coverwrite); + + dev_info(&cdev->gadget->dev, DRIVER_DESC " version: " DRIVER_VERSION_STR = "\n"); + + return 0; + +err_free_otg_desc: + kfree(otg_desc[0]); + otg_desc[0] =3D NULL; +err_conf_otg: + usb_put_function_instance(fi_eem); +err_conf_eem: + usb_put_function_instance(fi_acm); +err_conf_acm: + usb_put_function_instance(fi_9pfs); + return status; +} + +static int usb9pfs_unbind(struct usb_composite_dev *cdev) +{ + if (!IS_ERR_OR_NULL(f_eem)) + usb_put_function(f_eem); + usb_put_function_instance(fi_eem); + if (!IS_ERR_OR_NULL(f_acm)) + usb_put_function(f_acm); + usb_put_function_instance(fi_acm); + if (!IS_ERR_OR_NULL(f_9pfs)) + usb_put_function(f_9pfs); + usb_put_function_instance(fi_9pfs); + kfree(otg_desc[0]); + otg_desc[0] =3D NULL; + + return 0; +} + +static struct usb_composite_driver usb9pfs_driver =3D { + .name =3D "usb9pfs", + .dev =3D &device_desc, + .strings =3D dev_strings, + .max_speed =3D USB_SPEED_SUPER, + .bind =3D usb9pfs_bind, + .unbind =3D usb9pfs_unbind, +}; + +module_usb_composite_driver(usb9pfs_driver); + +MODULE_AUTHOR("Michael Grzeschik"); +MODULE_LICENSE("GPL"); diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/= Kconfig index 0a7b382fbe27c..8569aecc1487b 100644 --- a/drivers/usb/gadget/legacy/Kconfig +++ b/drivers/usb/gadget/legacy/Kconfig @@ -62,6 +62,21 @@ config USB_ZERO Say "y" to link the driver statically, or "m" to build a dynamically linked module called "g_zero". =20 +config USB_9PFS + tristate "Gadget 9PFS" + select USB_LIBCOMPOSITE + select USB_U_SERIAL + select USB_U_ETHER + select USB_F_ACM + select USB_F_EEM + select USB_F_9PFS + select NET_9P + help + 9PFS Transport Layer + + Say "y" to link the driver statically, or "m" to build a + dynamically linked module called "g_9pfs". + config USB_ZERO_HNPTEST bool "HNP Test Device" depends on USB_ZERO && USB_OTG diff --git a/drivers/usb/gadget/legacy/Makefile b/drivers/usb/gadget/legacy= /Makefile index 4d864bf82799d..99c098800d898 100644 --- a/drivers/usb/gadget/legacy/Makefile +++ b/drivers/usb/gadget/legacy/Makefile @@ -8,6 +8,7 @@ ccflags-y +=3D -I$(srctree)/drivers/usb/gadget/udc/ ccflags-y +=3D -I$(srctree)/drivers/usb/gadget/function/ =20 g_zero-y :=3D zero.o +g_9pfs-y :=3D 9pfs.o g_audio-y :=3D audio.o g_ether-y :=3D ether.o g_serial-y :=3D serial.o @@ -26,6 +27,7 @@ g_acm_ms-y :=3D acm_ms.o g_tcm_usb_gadget-y :=3D tcm_usb_gadget.o =20 obj-$(CONFIG_USB_ZERO) +=3D g_zero.o +obj-$(CONFIG_USB_9PFS) +=3D g_9pfs.o obj-$(CONFIG_USB_AUDIO) +=3D g_audio.o obj-$(CONFIG_USB_ETH) +=3D g_ether.o obj-$(CONFIG_USB_GADGETFS) +=3D gadgetfs.o --=20 2.39.2