Re: [PATCH v5 1/1] usb: gadget: add raw-gadget interface
From: Felipe Balbi
Date: Fri Jan 31 2020 - 08:42:22 EST
Hi,
Andrey Konovalov <andreyknvl@xxxxxxxxxx> writes:
> USB Raw Gadget is a kernel module that provides a userspace interface for
> the USB Gadget subsystem. Essentially it allows to emulate USB devices
> from userspace. Enabled with CONFIG_USB_RAW_GADGET. Raw Gadget is
> currently a strictly debugging feature and shouldn't be used in
> production.
>
> Raw Gadget is similar to GadgetFS, but provides a more low-level and
> direct access to the USB Gadget layer for the userspace. The key
> differences are:
>
> 1. Every USB request is passed to the userspace to get a response, while
> GadgetFS responds to some USB requests internally based on the provided
> descriptors. However note, that the UDC driver might respond to some
> requests on its own and never forward them to the Gadget layer.
>
> 2. GadgetFS performs some sanity checks on the provided USB descriptors,
> while Raw Gadget allows you to provide arbitrary data as responses to
> USB requests.
>
> 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).
>
> 5. Raw Gadget has ioctl-based interface instead of a filesystem-based one.
>
> Reviewed-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
> Signed-off-by: Andrey Konovalov <andreyknvl@xxxxxxxxxx>
> ---
>
> Greg, I've assumed your LGTM meant that I can add a Reviewed-by from you.
>
> Felipe, looking forward to your review, thanks!
>
> Documentation/usb/index.rst | 1 +
> Documentation/usb/raw-gadget.rst | 59 ++
> drivers/usb/gadget/legacy/Kconfig | 11 +
> drivers/usb/gadget/legacy/Makefile | 1 +
> drivers/usb/gadget/legacy/raw_gadget.c | 1068 ++++++++++++++++++++++++
> include/uapi/linux/usb/raw_gadget.h | 167 ++++
> 6 files changed, 1307 insertions(+)
> create mode 100644 Documentation/usb/raw-gadget.rst
> create mode 100644 drivers/usb/gadget/legacy/raw_gadget.c
> create mode 100644 include/uapi/linux/usb/raw_gadget.h
>
> diff --git a/Documentation/usb/index.rst b/Documentation/usb/index.rst
> index e55386a4abfb..90310e2a0c1f 100644
> --- a/Documentation/usb/index.rst
> +++ b/Documentation/usb/index.rst
> @@ -22,6 +22,7 @@ USB support
> misc_usbsevseg
> mtouchusb
> ohci
> + raw-gadget
> rio
> usbip_protocol
> usbmon
> diff --git a/Documentation/usb/raw-gadget.rst b/Documentation/usb/raw-gadget.rst
> new file mode 100644
> index 000000000000..cbedf5451ed3
> --- /dev/null
> +++ b/Documentation/usb/raw-gadget.rst
> @@ -0,0 +1,59 @@
> +==============
> +USB Raw Gadget
> +==============
> +
> +USB Raw Gadget is a kernel module that provides a userspace interface for
> +the USB Gadget subsystem. Essentially it allows to emulate USB devices
> +from userspace. Enabled with CONFIG_USB_RAW_GADGET. Raw Gadget is
> +currently a strictly debugging feature and shouldn't be used in
> +production, use GadgetFS instead.
> +
> +Comparison to GadgetFS
> +~~~~~~~~~~~~~~~~~~~~~~
> +
> +Raw Gadget is similar to GadgetFS, but provides a more low-level and
> +direct access to the USB Gadget layer for the userspace. The key
> +differences are:
> +
> +1. Every USB request is passed to the userspace to get a response, while
> + GadgetFS responds to some USB requests internally based on the provided
> + descriptors. However note, that the UDC driver might respond to some
> + requests on its own and never forward them to the Gadget layer.
> +
> +2. GadgetFS performs some sanity checks on the provided USB descriptors,
> + while Raw Gadget allows you to provide arbitrary data as responses to
> + USB requests.
> +
> +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).
> +
> +5. Raw Gadget has ioctl-based interface instead of a filesystem-based one.
> +
> +Userspace interface
> +~~~~~~~~~~~~~~~~~~~
> +
> +To create a Raw Gadget instance open /dev/raw-gadget. Multiple raw-gadget
> +instances (bound to different UDCs) can be used at the same time. The
> +interaction with the opened file happens through the ioctl() calls, see
> +comments in include/uapi/linux/usb/raw_gadget.h for details.
> +
> +The typical usage of Raw Gadget looks like:
> +
> +1. Open Raw Gadget instance via /dev/raw-gadget.
> +2. Initialize the instance via USB_RAW_IOCTL_INIT.
> +3. Launch the instance with USB_RAW_IOCTL_RUN.
> +4. In a loop issue USB_RAW_IOCTL_EVENT_FETCH calls to receive events from
> + Raw Gadget and react to those depending on what kind of USB device
> + needs to be emulated.
> +
> +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/Kconfig b/drivers/usb/gadget/legacy/Kconfig
> index 119a4e47681f..55e495f5d103 100644
> --- a/drivers/usb/gadget/legacy/Kconfig
> +++ b/drivers/usb/gadget/legacy/Kconfig
> @@ -489,3 +489,14 @@ config USB_G_WEBCAM
>
> Say "y" to link the driver statically, or "m" to build a
> dynamically linked module called "g_webcam".
> +
> +config USB_RAW_GADGET
> + tristate "USB Raw Gadget"
> + help
> + USB Raw Gadget is a kernel module that provides a userspace interface
> + for the USB Gadget subsystem. Essentially it allows to emulate USB
> + devices from userspace. See Documentation/usb/raw-gadget.rst for
> + details.
> +
> + Say "y" to link the driver statically, or "m" to build a
> + dynamically linked module called "raw_gadget".
> diff --git a/drivers/usb/gadget/legacy/Makefile b/drivers/usb/gadget/legacy/Makefile
> index abd0c3e66a05..4d864bf82799 100644
> --- a/drivers/usb/gadget/legacy/Makefile
> +++ b/drivers/usb/gadget/legacy/Makefile
> @@ -43,3 +43,4 @@ obj-$(CONFIG_USB_G_WEBCAM) += g_webcam.o
> obj-$(CONFIG_USB_G_NCM) += g_ncm.o
> obj-$(CONFIG_USB_G_ACM_MS) += g_acm_ms.o
> obj-$(CONFIG_USB_GADGET_TARGET) += tcm_usb_gadget.o
> +obj-$(CONFIG_USB_RAW_GADGET) += raw_gadget.o
> diff --git a/drivers/usb/gadget/legacy/raw_gadget.c b/drivers/usb/gadget/legacy/raw_gadget.c
> new file mode 100644
> index 000000000000..51796af48069
> --- /dev/null
> +++ b/drivers/usb/gadget/legacy/raw_gadget.c
> @@ -0,0 +1,1068 @@
> +// SPDX-License-Identifier: GPL-2.0
V2 only
> +/*
> + * USB Raw Gadget driver.
> + * See Documentation/usb/raw-gadget.rst for more details.
> + *
> + * Andrey Konovalov <andreyknvl@xxxxxxxxx>
> + */
> +
> +#include <linux/compiler.h>
> +#include <linux/debugfs.h>
> +#include <linux/delay.h>
> +#include <linux/kref.h>
> +#include <linux/miscdevice.h>
> +#include <linux/module.h>
> +#include <linux/semaphore.h>
> +#include <linux/sched.h>
> +#include <linux/slab.h>
> +#include <linux/uaccess.h>
> +#include <linux/wait.h>
> +
> +#include <linux/usb.h>
> +#include <linux/usb/ch9.h>
> +#include <linux/usb/ch11.h>
> +#include <linux/usb/gadget.h>
> +
> +#include <uapi/linux/usb/raw_gadget.h>
> +
> +#define DRIVER_DESC "USB Raw Gadget"
> +#define DRIVER_NAME "raw-gadget"
> +
> +MODULE_DESCRIPTION(DRIVER_DESC);
> +MODULE_AUTHOR("Andrey Konovalov");
> +MODULE_LICENSE("GPL");
v2+. Care to fix?
> +
> +/*----------------------------------------------------------------------*/
> +
> +#define RAW_EVENT_QUEUE_SIZE 128
> +
> +struct raw_event_queue {
> + /* See the comment in raw_event_queue_fetch() for locking details. */
> + spinlock_t lock;
> + struct semaphore sema;
> + struct usb_raw_event *events[RAW_EVENT_QUEUE_SIZE];
> + int size;
> +};
> +
> +static void raw_event_queue_init(struct raw_event_queue *queue)
> +{
> + spin_lock_init(&queue->lock);
> + sema_init(&queue->sema, 0);
> + queue->size = 0;
> +}
> +
> +static int raw_event_queue_add(struct raw_event_queue *queue,
> + enum usb_raw_event_type type, size_t length, const void *data)
> +{
> + unsigned long flags;
> + struct usb_raw_event *event;
> +
> + spin_lock_irqsave(&queue->lock, flags);
> + if (WARN_ON(queue->size >= RAW_EVENT_QUEUE_SIZE)) {
> + spin_unlock_irqrestore(&queue->lock, flags);
> + return -ENOMEM;
> + }
> + event = kmalloc(sizeof(*event) + length, GFP_ATOMIC);
I would very much prefer dropping GFP_ATOMIC here. Must you have this
allocation under a spinlock?
--
balbi
Attachment:
signature.asc
Description: PGP signature