2019-01-06 16:03:58

by Paul Elder

[permalink] [raw]
Subject: [PATCH v4 0/6] usb: gadget: add mechanism to asynchronously validate data stage of ctrl out request

This patch series adds a mechanism to allow asynchronously validating
the data stage of a control OUT request, and for stalling or suceeding
the request accordingly. This mechanism is implemented for MUSB, and is
used by UVC. At the same time, UVC packages the setup stage and data
stage data together to send to userspace to save on a pair of context
switches per control out request.

This patch series does change the userspace API. We however believe that
it is justified because the current API is broken, and because it isn't
being used (because it's broken).

The current API is broken such that it is subject to race conditions
that cause fatal errors with a high frequency. This is actually what
motivated this patch series in the first place. In the current API, not
only is there no way to asynchronously validate the data stage of a
control OUT request, but an empty buffer is expected to be provided to
hold the data stage data -- which is more likely than not to be late.
There is even a warning in musb_g_ep0_queue:

/* else for sequence #2 (OUT), caller provides a buffer
* before the next packet arrives. deferred responses
* (after SETUP is acked) are racey.
*/

This problem has never been reported in years, which is a sign that the
API isn't used. Furthermore, the vendor kernels that we have seen using
the UVC gadget driver (such as QC and Huawei) are heavily patched with
local changes to the API. This corroborates the suspicion that the
current mainline API is not being used.

Additionally, this API isn't meant to be used by generic applications,
but by a dedicated userspace helper. uvc-gadget is one such example, but
it has bitrotten and isn't compatible with the current kernel API. The
fact that nobody has submitted patches nor complained for a long time
again shows that it isn't being used.

The conclusion is that since the API hasn't been used for a long time,
it is safe to fix it.

Changes in v4:

- Change wording and fix typo in patch 4/6 "usb: gadget: add mechanism
to specify an explicit status stage"
- Set explicit_status in usb_gadget_control_complete
- Change explicit_status from unsigned int to bool

Changes in v3:

- Function driver send STALL status stage by simply calling
usb_ep_set_halt, and ACK by enqueueing request
- Fix signature of usb_gadget_control_complete to check the status of the
request that was just given back.
- Corresponding changes to musb and uvc gadget

Changes in v2:

Overhaul of status stage delay mechanism/API. Now if a function driver
desires an explicit/delayed status stage, it specifies so in a flag in
the usb_request that is queued for the data stage. The function driver
later enqueues another usb_request for the status stage, also with the
explicit_status flag set, and with the zero flag acting as the status.
If a function driver does not desire an explicit status stage, then it
can set (or ignore) the explicit_status flag in the usb_request that
is queued for the data stage.

To allow the optional explicit status stage, a UDC driver should call
the newly added usb_gadget_control_complete right after
usb_gadget_giveback_request, and in its queue function should check if
the usb_request is for the status stage and if it has been requested to
be explicit, and if so check the status that should be sent. (See 5/6
"usb: musb: gadget: implement optional explicit status stage" for an
implementation for MUSB)

Paul Elder (6):
usb: uvc: include videodev2.h in g_uvc.h
usb: gadget: uvc: enqueue usb request in setup handler for control OUT
usb: gadget: uvc: package setup and data for control OUT requests
usb: gadget: add mechanism to specify an explicit status stage
usb: musb: gadget: implement optional explicit status stage
usb: gadget: uvc: allow ioctl to send response in status stage

drivers/usb/gadget/function/f_uvc.c | 32 ++++++++++++++++++------
drivers/usb/gadget/function/uvc.h | 1 +
drivers/usb/gadget/function/uvc_v4l2.c | 18 ++++++++++++++
drivers/usb/gadget/udc/core.c | 34 ++++++++++++++++++++++++++
drivers/usb/musb/musb_gadget.c | 2 ++
drivers/usb/musb/musb_gadget_ep0.c | 23 +++++++++++++++++
include/linux/usb/gadget.h | 10 ++++++++
include/uapi/linux/usb/g_uvc.h | 4 ++-
8 files changed, 115 insertions(+), 9 deletions(-)

--
2.19.2


Paul Elder (6):
usb: uvc: include videodev2.h in g_uvc.h
usb: gadget: uvc: enqueue usb request in setup handler for control OUT
usb: gadget: uvc: package setup and data for control OUT requests
usb: gadget: add mechanism to specify an explicit status stage
usb: musb: gadget: implement optional explicit status stage
usb: gadget: uvc: allow ioctl to send response in status stage

drivers/usb/gadget/function/f_uvc.c | 32 ++++++++++++++++++------
drivers/usb/gadget/function/uvc.h | 1 +
drivers/usb/gadget/function/uvc_v4l2.c | 18 ++++++++++++++
drivers/usb/gadget/udc/core.c | 34 ++++++++++++++++++++++++++
drivers/usb/musb/musb_gadget.c | 2 ++
drivers/usb/musb/musb_gadget_ep0.c | 23 +++++++++++++++++
include/linux/usb/gadget.h | 10 ++++++++
include/uapi/linux/usb/g_uvc.h | 4 ++-
8 files changed, 115 insertions(+), 9 deletions(-)

--
2.19.2



2019-01-06 16:04:09

by Paul Elder

[permalink] [raw]
Subject: [PATCH v4 4/6] usb: gadget: add mechanism to specify an explicit status stage

A usb gadget function driver may or may not want to delay the status
stage of a control OUT request. An instance where it might want to is to
asynchronously validate the data of a class-specific request.

A function driver that wants an explicit status stage should set the
newly added explicit_status flag of the usb_request corresponding to the
data stage. Later on the function driver can explicitly complete the
status stage by enqueueing a usb_request for ACK, or calling
usb_ep_set_halt() for STALL.

To support both explicit and implicit status stages, a UDC driver must
call the newly added usb_gadget_control_complete function right after
calling usb_gadget_giveback_request. The status of the request that was
just given back must be fed into usb_gadget_control_complete. To support
the explicit status stage, it might then check what stage the
usb_request was queued in, and for control IN ACK the host's zero-length
data packet, or for control OUT send a zero-length DATA1 ACK packet.

Signed-off-by: Paul Elder <[email protected]>
Acked-by: Alan Stern <[email protected]>
v1 Reviewed-by: Laurent Pinchart <[email protected]>
---
Changes from v3:

- More specific in commit message about what to do for udc driver acking
- Set explicit_status in usb_gadget_control_complete
- Make explicit_status type bool

Changes from v2:

Add status parameter to usb_gadget_control_complete, so that a
usb_request is not queued if the status of the just given back request
is nonzero.

Changes from v1:

Complete change of API. Now we use a flag that should be set in the
usb_request that is queued for the data stage to signal to the UDC that
we want to delay the status stage (as opposed to setting a flag in the
UDC itself, that persists across all requests). We now also provide a
function for UDC drivers to very easily allow implicit status stages, to
mitigate the need to convert all function drivers to this new API at
once, and to make it easier for UDC drivers to convert.

drivers/usb/gadget/udc/core.c | 34 ++++++++++++++++++++++++++++++++++
include/linux/usb/gadget.h | 10 ++++++++++
2 files changed, 44 insertions(+)

diff --git a/drivers/usb/gadget/udc/core.c b/drivers/usb/gadget/udc/core.c
index af88b48c1cea..d3071de2b527 100644
--- a/drivers/usb/gadget/udc/core.c
+++ b/drivers/usb/gadget/udc/core.c
@@ -894,6 +894,40 @@ EXPORT_SYMBOL_GPL(usb_gadget_giveback_request);

/* ------------------------------------------------------------------------- */

+/**
+ * usb_gadget_control_complete - complete the status stage of a control
+ * request, or delay it
+ * Context: in_interrupt()
+ *
+ * @gadget: gadget whose control request's status stage should be completed
+ * @explicit_status: true to delay status stage, false to complete here
+ * @status: completion code of previously completed request
+ *
+ * This is called by device controller drivers after returning the completed
+ * request back to the gadget layer, to either complete or delay the status
+ * stage.
+ */
+void usb_gadget_control_complete(struct usb_gadget *gadget,
+ bool explicit_status, int status)
+{
+ struct usb_request *req;
+
+ if (explicit_status || status)
+ return;
+
+ /* Send an implicit status-stage request for ep0 */
+ req = usb_ep_alloc_request(gadget->ep0, GFP_ATOMIC);
+ if (req) {
+ req->length = 0;
+ req->explicit_status = 1;
+ req->complete = usb_ep_free_request;
+ usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
+ }
+}
+EXPORT_SYMBOL_GPL(usb_gadget_control_complete);
+
+/* ------------------------------------------------------------------------- */
+
/**
* gadget_find_ep_by_name - returns ep whose name is the same as sting passed
* in second parameter or NULL if searched endpoint not found
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index e5cd84a0f84a..498e3eaa72f1 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -73,6 +73,7 @@ struct usb_ep;
* Note that for writes (IN transfers) some data bytes may still
* reside in a device-side FIFO when the request is reported as
* complete.
+ * @explicit_status: If true, delays the status stage
*
* These are allocated/freed through the endpoint they're used with. The
* hardware's driver can add extra per-request data to the memory it returns,
@@ -114,6 +115,8 @@ struct usb_request {

int status;
unsigned actual;
+
+ bool explicit_status;
};

/*-------------------------------------------------------------------------*/
@@ -850,6 +853,13 @@ extern void usb_gadget_giveback_request(struct usb_ep *ep,

/*-------------------------------------------------------------------------*/

+/* utility to complete or delay status stage */
+
+void usb_gadget_control_complete(struct usb_gadget *gadget,
+ bool explicit_status, int status);
+
+/*-------------------------------------------------------------------------*/
+
/* utility to find endpoint by name */

extern struct usb_ep *gadget_find_ep_by_name(struct usb_gadget *g,
--
2.19.2


2019-01-06 16:04:15

by Paul Elder

[permalink] [raw]
Subject: [PATCH v4 5/6] usb: musb: gadget: implement optional explicit status stage

Implement the mechanism for optional explicit status stage for the MUSB
driver. This allows a function driver to specify what to reply for the
status stage. The functionality for an implicit status stage is
retained.

Signed-off-by: Paul Elder <[email protected]>
v1 Reviewed-by: Laurent Pinchart <[email protected]>
v1 Acked-by: Bin Liu <[email protected]>
---
No change from v3

Changes from v2:
- update call to usb_gadget_control_complete to include status
- since sending STALL from the function driver is now done with
usb_ep_set_halt, there is no need for the internal ep0_send_response to
take a stall/ack parameter; remove the parameter and make the function
only send ack, and remove checking for the status reply in the
usb_request for the status stage

Changes from v1:
- obvious change to implement v2 mechanism laid out by 4/6 of this
series (send_response, and musb_g_ep0_send_response function has
been removed, call to usb_gadget_control_complete has been added)
- ep0_send_response's ack argument has been changed from stall
- last_packet flag in ep0_rxstate has been removed, since it is equal to
req != NULL

drivers/usb/musb/musb_gadget.c | 2 ++
drivers/usb/musb/musb_gadget_ep0.c | 23 +++++++++++++++++++++++
2 files changed, 25 insertions(+)

diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index d3f33f449445..a7a992ab0c9d 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -145,6 +145,8 @@ __acquires(ep->musb->lock)

trace_musb_req_gb(req);
usb_gadget_giveback_request(&req->ep->end_point, &req->request);
+ usb_gadget_control_complete(&musb->g, request->explicit_status,
+ request->status);
spin_lock(&musb->lock);
ep->busy = busy;
}
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index 91a5027b5c1f..bbce8a9d77e4 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -458,6 +458,23 @@ __acquires(musb->lock)
return handled;
}

+static int ep0_send_ack(struct musb *musb)
+{
+ void __iomem *regs = musb->control_ep->regs;
+ u16 ackpend;
+
+ if (musb->ep0_state != MUSB_EP0_STAGE_RX &&
+ musb->ep0_state != MUSB_EP0_STAGE_STATUSIN)
+ return -EINVAL;
+
+ ackpend = MUSB_CSR0_P_DATAEND | MUSB_CSR0_P_SVDRXPKTRDY;
+
+ musb_ep_select(musb->mregs, 0);
+ musb_writew(regs, MUSB_CSR0, ackpend);
+
+ return 0;
+}
+
/* we have an ep0out data packet
* Context: caller holds controller lock
*/
@@ -504,10 +521,13 @@ static void ep0_rxstate(struct musb *musb)
if (req) {
musb->ackpend = csr;
musb_g_ep0_giveback(musb, req);
+ if (req->explicit_status)
+ return;
if (!musb->ackpend)
return;
musb->ackpend = 0;
}
+
musb_ep_select(musb->mregs, 0);
musb_writew(regs, MUSB_CSR0, csr);
}
@@ -939,6 +959,9 @@ musb_g_ep0_queue(struct usb_ep *e, struct usb_request *r, gfp_t gfp_flags)
case MUSB_EP0_STAGE_ACKWAIT: /* zero-length data */
status = 0;
break;
+ case MUSB_EP0_STAGE_STATUSIN:
+ status = ep0_send_ack(musb);
+ goto cleanup;
default:
musb_dbg(musb, "ep0 request queued in state %d",
musb->ep0_state);
--
2.19.2


2019-01-06 16:04:28

by Paul Elder

[permalink] [raw]
Subject: [PATCH v4 6/6] usb: gadget: uvc: allow ioctl to send response in status stage

We now have a mechanism to signal the UDC driver to reply to a control
OUT request with STALL or ACK, and we have packaged the setup stage data
and the data stage data of a control OUT request into a single
UVC_EVENT_DATA for userspace to consume. The ioctl UVCIOC_SEND_RESPONSE
in the case of a control OUT request sends a response to the data stage,
and so the ioctl now notifies the UDC driver to reply with STALL or ACK.
In the case of a control IN request, the ioctl sends the UVC data as
before.

Also tell the UDC to delay the status stage for this to work.

Signed-off-by: Paul Elder <[email protected]>
---
No change from v3

Changes from v2:
- calling usb_ep_set_halt in uvc_send_response if data->length < 0 is
now common for both IN and OUT transfers so make that check common
- remove now unnecessary field setting for the usb_request to be queued
for the status stage

Changes from v1:
- remove usb_ep_delay_status call from the old proposed API
- changed portions of uvc_send_response to match v2 API
- remove UDC warning that send_response is not implemented

drivers/usb/gadget/function/f_uvc.c | 4 ++--
drivers/usb/gadget/function/uvc_v4l2.c | 23 +++++++++++++++++------
2 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index aa8262c0a650..64180529fb36 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -209,14 +209,13 @@ uvc_function_ep0_complete(struct usb_ep *ep, struct usb_request *req)
struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;

if (uvc->event_setup_out) {
- uvc->event_setup_out = 0;
-
memset(&v4l2_event, 0, sizeof(v4l2_event));
v4l2_event.type = UVC_EVENT_DATA;
uvc_event->data.length = req->actual;
memcpy(&uvc_event->data.data, req->buf, req->actual);
memcpy(&uvc_event->data.setup, &uvc->control_setup,
sizeof(uvc_event->data.setup));
+
v4l2_event_queue(&uvc->vdev, &v4l2_event);
}
}
@@ -251,6 +250,7 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
*/
req->length = uvc->event_length;
req->zero = 0;
+ req->explicit_status = 1;
usb_ep_queue(f->config->cdev->gadget->ep0, req, GFP_KERNEL);
} else {
struct v4l2_event v4l2_event;
diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
index 9f7c67f6f4b2..0bf14891b40a 100644
--- a/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/drivers/usb/gadget/function/uvc_v4l2.c
@@ -35,15 +35,26 @@ uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data)
struct usb_composite_dev *cdev = uvc->func.config->cdev;
struct usb_request *req = uvc->control_req;

+ if (data->length < 0)
+ return usb_ep_set_halt(cdev->gadget->ep0);
+
/*
* For control OUT transfers the request has been enqueued synchronously
- * by the setup handler, there's nothing to be done here.
+ * by the setup handler, we just need to tell the UDC whether to ACK or
+ * STALL the control transfer.
*/
- if (uvc->event_setup_out)
- return 0;
-
- if (data->length < 0)
- return usb_ep_set_halt(cdev->gadget->ep0);
+ if (uvc->event_setup_out) {
+ /*
+ * The length field carries the control request status.
+ * Negative values signal a STALL and zero values an ACK.
+ * Positive values are not valid as there is no data to send
+ * back in the status stage.
+ */
+ if (data->length > 0)
+ return -EINVAL;
+
+ return usb_ep_queue(cdev->gadget->ep0, req, GFP_KERNEL);
+ }

req->length = min_t(unsigned int, uvc->event_length, data->length);
req->zero = data->length < uvc->event_length;
--
2.19.2


2019-01-06 16:05:00

by Paul Elder

[permalink] [raw]
Subject: [PATCH v4 3/6] usb: gadget: uvc: package setup and data for control OUT requests

Since "usb: gadget: uvc: enqueue uvc_request_data in setup handler
for control OUT requests" it is no longer necessary for userspace to
call ioctl UVCIOC_SEND_RESPONSE in response to receiving a
UVC_EVENT_SETUP from the uvc function driver for a control OUT request.

This change means that for control OUT userspace will receive a
UVC_EVENT_SETUP and not do anything with it. This is a waste of a pair
of context switches, so we put the setup and data stage data into a
single UVC_EVENT_DATA to give to userspace. Previously struct
uvc_request_data had 60 bytes allocated for data, and since uvc data at
most is 34 bytes in UVC 1.1 and 48 bytes in UVC 1.5, we can afford to
cut out 8 bytes to store the setup control.

Since the setup control is discarded after the handling of the setup
stage, it must be saved in struct uvc_device during the setup handler in
order for the data stage handler to be able to read it and send it to
userspace.

Signed-off-by: Paul Elder <[email protected]>
Reviewed-by: Laurent Pinchart <[email protected]>
---
No change from v3
No change from v2
No change from v1

drivers/usb/gadget/function/f_uvc.c | 3 +++
drivers/usb/gadget/function/uvc.h | 1 +
include/uapi/linux/usb/g_uvc.h | 3 ++-
3 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 96054403418a..aa8262c0a650 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -215,6 +215,8 @@ uvc_function_ep0_complete(struct usb_ep *ep, struct usb_request *req)
v4l2_event.type = UVC_EVENT_DATA;
uvc_event->data.length = req->actual;
memcpy(&uvc_event->data.data, req->buf, req->actual);
+ memcpy(&uvc_event->data.setup, &uvc->control_setup,
+ sizeof(uvc_event->data.setup));
v4l2_event_queue(&uvc->vdev, &v4l2_event);
}
}
@@ -238,6 +240,7 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
*/
uvc->event_setup_out = !(ctrl->bRequestType & USB_DIR_IN);
uvc->event_length = le16_to_cpu(ctrl->wLength);
+ memcpy(&uvc->control_setup, ctrl, sizeof(uvc->control_setup));

if (uvc->event_setup_out) {
struct usb_request *req = uvc->control_req;
diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h
index 671020c8a836..1d89b1df4ba0 100644
--- a/drivers/usb/gadget/function/uvc.h
+++ b/drivers/usb/gadget/function/uvc.h
@@ -163,6 +163,7 @@ struct uvc_device {
unsigned int control_intf;
struct usb_ep *control_ep;
struct usb_request *control_req;
+ struct usb_ctrlrequest control_setup;
void *control_buf;

unsigned int streaming_intf;
diff --git a/include/uapi/linux/usb/g_uvc.h b/include/uapi/linux/usb/g_uvc.h
index 6698c3263ae8..10fbb4382925 100644
--- a/include/uapi/linux/usb/g_uvc.h
+++ b/include/uapi/linux/usb/g_uvc.h
@@ -24,7 +24,8 @@

struct uvc_request_data {
__s32 length;
- __u8 data[60];
+ struct usb_ctrlrequest setup;
+ __u8 data[52];
};

struct uvc_event {
--
2.19.2


2019-01-06 16:05:10

by Paul Elder

[permalink] [raw]
Subject: [PATCH v4 2/6] usb: gadget: uvc: enqueue usb request in setup handler for control OUT

Currently, for uvc class-specific control IN and OUT requests, in the
setup handler a UVC_EVENT_SETUP with the setup control is enqueued to
userspace. In response to this, the uvc function driver expects
userspace to call ioctl UVCIOC_SEND_RESPONSE containing uvc request
data.

In the case of control IN this is fine, but for control OUT it causes a
problem. Since the host sends data immediately after the setup stage
completes, it is possible that the empty uvc request data is not
enqueued in time for the UDC driver to put the data stage data into
(this causes some UDC drivers, such as MUSB, to reply with a STALL).
This problem is remedied by having the setup handler enqueue the empty
uvc request data, instead of waiting for userspace to do it.

Signed-off-by: Paul Elder <[email protected]>
Reviewed-by: Laurent Pinchart <[email protected]>
---
No change from v3
No change from v2
No change from v1

drivers/usb/gadget/function/f_uvc.c | 25 +++++++++++++++++++------
drivers/usb/gadget/function/uvc_v4l2.c | 7 +++++++
2 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 3472a2863436..96054403418a 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -223,8 +223,6 @@ static int
uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
{
struct uvc_device *uvc = to_uvc(f);
- struct v4l2_event v4l2_event;
- struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;

if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) {
uvcg_info(f, "invalid request type\n");
@@ -241,10 +239,25 @@ uvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
uvc->event_setup_out = !(ctrl->bRequestType & USB_DIR_IN);
uvc->event_length = le16_to_cpu(ctrl->wLength);

- memset(&v4l2_event, 0, sizeof(v4l2_event));
- v4l2_event.type = UVC_EVENT_SETUP;
- memcpy(&uvc_event->req, ctrl, sizeof(uvc_event->req));
- v4l2_event_queue(&uvc->vdev, &v4l2_event);
+ if (uvc->event_setup_out) {
+ struct usb_request *req = uvc->control_req;
+
+ /*
+ * Enqueue the request immediately for control OUT as the
+ * host will start the data stage straight away.
+ */
+ req->length = uvc->event_length;
+ req->zero = 0;
+ usb_ep_queue(f->config->cdev->gadget->ep0, req, GFP_KERNEL);
+ } else {
+ struct v4l2_event v4l2_event;
+ struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
+
+ memset(&v4l2_event, 0, sizeof(v4l2_event));
+ v4l2_event.type = UVC_EVENT_SETUP;
+ memcpy(&uvc_event->req, ctrl, sizeof(uvc_event->req));
+ v4l2_event_queue(&uvc->vdev, &v4l2_event);
+ }

return 0;
}
diff --git a/drivers/usb/gadget/function/uvc_v4l2.c b/drivers/usb/gadget/function/uvc_v4l2.c
index 4b0a82cc4763..9f7c67f6f4b2 100644
--- a/drivers/usb/gadget/function/uvc_v4l2.c
+++ b/drivers/usb/gadget/function/uvc_v4l2.c
@@ -35,6 +35,13 @@ uvc_send_response(struct uvc_device *uvc, struct uvc_request_data *data)
struct usb_composite_dev *cdev = uvc->func.config->cdev;
struct usb_request *req = uvc->control_req;

+ /*
+ * For control OUT transfers the request has been enqueued synchronously
+ * by the setup handler, there's nothing to be done here.
+ */
+ if (uvc->event_setup_out)
+ return 0;
+
if (data->length < 0)
return usb_ep_set_halt(cdev->gadget->ep0);

--
2.19.2


2019-01-06 16:05:18

by Paul Elder

[permalink] [raw]
Subject: [PATCH v4 1/6] usb: uvc: include videodev2.h in g_uvc.h

V4L2_EVENT_PRIVATE_START is used in g_uvc.h but is defined in
videodev2.h, which is not included and causes a compiler warning:

linux/usb/g_uvc.h:15:28: error: ‘V4L2_EVENT_PRIVATE_START’ undeclared here (not in a function)
#define UVC_EVENT_FIRST (V4L2_EVENT_PRIVATE_START + 0)

Include videodev2.h in g_uvc.h.

Signed-off-by: Paul Elder <[email protected]>
Reviewed-by: Laurent Pinchart <[email protected]>
---
No change from v3
No change from v2
No change from v1

include/uapi/linux/usb/g_uvc.h | 1 +
1 file changed, 1 insertion(+)

diff --git a/include/uapi/linux/usb/g_uvc.h b/include/uapi/linux/usb/g_uvc.h
index 3c9ee3020cbb..6698c3263ae8 100644
--- a/include/uapi/linux/usb/g_uvc.h
+++ b/include/uapi/linux/usb/g_uvc.h
@@ -11,6 +11,7 @@
#include <linux/ioctl.h>
#include <linux/types.h>
#include <linux/usb/ch9.h>
+#include <linux/videodev2.h>

#define UVC_EVENT_FIRST (V4L2_EVENT_PRIVATE_START + 0)
#define UVC_EVENT_CONNECT (V4L2_EVENT_PRIVATE_START + 0)
--
2.19.2


2019-01-06 20:04:37

by Alan Stern

[permalink] [raw]
Subject: Re: [PATCH v4 5/6] usb: musb: gadget: implement optional explicit status stage

On Sun, 6 Jan 2019, Paul Elder wrote:

> Implement the mechanism for optional explicit status stage for the MUSB
> driver. This allows a function driver to specify what to reply for the
> status stage. The functionality for an implicit status stage is
> retained.
>
> Signed-off-by: Paul Elder <[email protected]>
> v1 Reviewed-by: Laurent Pinchart <[email protected]>
> v1 Acked-by: Bin Liu <[email protected]>
> ---
> No change from v3
>
> Changes from v2:
> - update call to usb_gadget_control_complete to include status
> - since sending STALL from the function driver is now done with
> usb_ep_set_halt, there is no need for the internal ep0_send_response to
> take a stall/ack parameter; remove the parameter and make the function
> only send ack, and remove checking for the status reply in the
> usb_request for the status stage
>
> Changes from v1:
> - obvious change to implement v2 mechanism laid out by 4/6 of this
> series (send_response, and musb_g_ep0_send_response function has
> been removed, call to usb_gadget_control_complete has been added)
> - ep0_send_response's ack argument has been changed from stall
> - last_packet flag in ep0_rxstate has been removed, since it is equal to
> req != NULL
>
> drivers/usb/musb/musb_gadget.c | 2 ++
> drivers/usb/musb/musb_gadget_ep0.c | 23 +++++++++++++++++++++++
> 2 files changed, 25 insertions(+)
>
> diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
> index d3f33f449445..a7a992ab0c9d 100644
> --- a/drivers/usb/musb/musb_gadget.c
> +++ b/drivers/usb/musb/musb_gadget.c
> @@ -145,6 +145,8 @@ __acquires(ep->musb->lock)
>
> trace_musb_req_gb(req);
> usb_gadget_giveback_request(&req->ep->end_point, &req->request);
> + usb_gadget_control_complete(&musb->g, request->explicit_status,
> + request->status);

I haven't paid much attention to this part of the patch series, not
knowing much about musb. Still, it's clear that
usb_gadget_control_complete should be called only for transfers on
ep0. You need to test the endpoint value.

Another problem: the completion handler may deallocate the request.
Dereferencing request->expicit_status and request->status would then
cause errors. Would it be preferable to call
usb_gadget_control_complete before usb_gadget_giveback_request? If
it gets done that way then the arguments could be simplified: we could
pass a pointer to the request instead of the separate explicit_status
and status values.

Alan Stern


2019-01-08 05:52:01

by Paul Elder

[permalink] [raw]
Subject: Re: [PATCH v4 5/6] usb: musb: gadget: implement optional explicit status stage

On Sun, Jan 06, 2019 at 03:03:09PM -0500, Alan Stern wrote:
> On Sun, 6 Jan 2019, Paul Elder wrote:
>
> > Implement the mechanism for optional explicit status stage for the MUSB
> > driver. This allows a function driver to specify what to reply for the
> > status stage. The functionality for an implicit status stage is
> > retained.
> >
> > Signed-off-by: Paul Elder <[email protected]>
> > v1 Reviewed-by: Laurent Pinchart <[email protected]>
> > v1 Acked-by: Bin Liu <[email protected]>
> > ---
> > No change from v3
> >
> > Changes from v2:
> > - update call to usb_gadget_control_complete to include status
> > - since sending STALL from the function driver is now done with
> > usb_ep_set_halt, there is no need for the internal ep0_send_response to
> > take a stall/ack parameter; remove the parameter and make the function
> > only send ack, and remove checking for the status reply in the
> > usb_request for the status stage
> >
> > Changes from v1:
> > - obvious change to implement v2 mechanism laid out by 4/6 of this
> > series (send_response, and musb_g_ep0_send_response function has
> > been removed, call to usb_gadget_control_complete has been added)
> > - ep0_send_response's ack argument has been changed from stall
> > - last_packet flag in ep0_rxstate has been removed, since it is equal to
> > req != NULL
> >
> > drivers/usb/musb/musb_gadget.c | 2 ++
> > drivers/usb/musb/musb_gadget_ep0.c | 23 +++++++++++++++++++++++
> > 2 files changed, 25 insertions(+)
> >
> > diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
> > index d3f33f449445..a7a992ab0c9d 100644
> > --- a/drivers/usb/musb/musb_gadget.c
> > +++ b/drivers/usb/musb/musb_gadget.c
> > @@ -145,6 +145,8 @@ __acquires(ep->musb->lock)
> >
> > trace_musb_req_gb(req);
> > usb_gadget_giveback_request(&req->ep->end_point, &req->request);
> > + usb_gadget_control_complete(&musb->g, request->explicit_status,
> > + request->status);
>
> I haven't paid much attention to this part of the patch series, not
> knowing much about musb. Still, it's clear that
> usb_gadget_control_complete should be called only for transfers on
> ep0. You need to test the endpoint value.

Oh oops, yeah, you're right.

> Another problem: the completion handler may deallocate the request.
> Dereferencing request->expicit_status and request->status would then
> cause errors. Would it be preferable to call
> usb_gadget_control_complete before usb_gadget_giveback_request? If
> it gets done that way then the arguments could be simplified: we could
> pass a pointer to the request instead of the separate explicit_status
> and status values.

I thought that usb_gadget_control_complete needs to check the status of
the request that was given back. Doesn't that mean that
usb_gadget_giveback_request must be called first?

I was thinking that maybe we could save explicit_status before calling
usb_gadget_giveback_request, and if request is still valid then we can
pull status from it otherwise use 0, but then would that be considered
adding complexity to UDCs that want to implement optional status stage
delay? Or add a wrapper function?

On the other hand, if we do put usb_gadget_control_complete before
usb_gadget_giveback_request, then the control transfer would complete
before the function driver has a chance to complete, but if the function
driver wanted to intervene/determine the status stage then it would have
gone through the new mechanism that we're making here. So it could be
fine to switch the order. My tests for it work too, so I guess we'll go
with usb_gadget_control_complete before usb_gadget_giveback_request
then. In that case usb_gadget_control_complete doesn't need to check the
status of the request, since there isn't any, right?


Thanks,

Paul Elder

2019-01-08 16:41:54

by Alan Stern

[permalink] [raw]
Subject: Re: [PATCH v4 5/6] usb: musb: gadget: implement optional explicit status stage

On Tue, 8 Jan 2019, Paul Elder wrote:

> On Sun, Jan 06, 2019 at 03:03:09PM -0500, Alan Stern wrote:
> > On Sun, 6 Jan 2019, Paul Elder wrote:
> >
> > > Implement the mechanism for optional explicit status stage for the MUSB
> > > driver. This allows a function driver to specify what to reply for the
> > > status stage. The functionality for an implicit status stage is
> > > retained.
> > >
> > > Signed-off-by: Paul Elder <[email protected]>
> > > v1 Reviewed-by: Laurent Pinchart <[email protected]>
> > > v1 Acked-by: Bin Liu <[email protected]>
> > > ---
> > > No change from v3
> > >
> > > Changes from v2:
> > > - update call to usb_gadget_control_complete to include status
> > > - since sending STALL from the function driver is now done with
> > > usb_ep_set_halt, there is no need for the internal ep0_send_response to
> > > take a stall/ack parameter; remove the parameter and make the function
> > > only send ack, and remove checking for the status reply in the
> > > usb_request for the status stage
> > >
> > > Changes from v1:
> > > - obvious change to implement v2 mechanism laid out by 4/6 of this
> > > series (send_response, and musb_g_ep0_send_response function has
> > > been removed, call to usb_gadget_control_complete has been added)
> > > - ep0_send_response's ack argument has been changed from stall
> > > - last_packet flag in ep0_rxstate has been removed, since it is equal to
> > > req != NULL
> > >
> > > drivers/usb/musb/musb_gadget.c | 2 ++
> > > drivers/usb/musb/musb_gadget_ep0.c | 23 +++++++++++++++++++++++
> > > 2 files changed, 25 insertions(+)
> > >
> > > diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
> > > index d3f33f449445..a7a992ab0c9d 100644
> > > --- a/drivers/usb/musb/musb_gadget.c
> > > +++ b/drivers/usb/musb/musb_gadget.c
> > > @@ -145,6 +145,8 @@ __acquires(ep->musb->lock)
> > >
> > > trace_musb_req_gb(req);
> > > usb_gadget_giveback_request(&req->ep->end_point, &req->request);
> > > + usb_gadget_control_complete(&musb->g, request->explicit_status,
> > > + request->status);
> >
> > I haven't paid much attention to this part of the patch series, not
> > knowing much about musb. Still, it's clear that
> > usb_gadget_control_complete should be called only for transfers on
> > ep0. You need to test the endpoint value.
>
> Oh oops, yeah, you're right.
>
> > Another problem: the completion handler may deallocate the request.
> > Dereferencing request->expicit_status and request->status would then
> > cause errors. Would it be preferable to call
> > usb_gadget_control_complete before usb_gadget_giveback_request? If
> > it gets done that way then the arguments could be simplified: we could
> > pass a pointer to the request instead of the separate explicit_status
> > and status values.
>
> I thought that usb_gadget_control_complete needs to check the status of
> the request that was given back. Doesn't that mean that
> usb_gadget_giveback_request must be called first?

You misunderstand. req->status has already been determined by the time
usb_gadget_giveback_request is called. It does not get set by that
call.

> I was thinking that maybe we could save explicit_status before calling
> usb_gadget_giveback_request, and if request is still valid then we can
> pull status from it otherwise use 0, but then would that be considered
> adding complexity to UDCs that want to implement optional status stage
> delay? Or add a wrapper function?
>
> On the other hand, if we do put usb_gadget_control_complete before
> usb_gadget_giveback_request, then the control transfer would complete
> before the function driver has a chance to complete, but if the function
> driver wanted to intervene/determine the status stage then it would have
> gone through the new mechanism that we're making here. So it could be
> fine to switch the order. My tests for it work too, so I guess we'll go
> with usb_gadget_control_complete before usb_gadget_giveback_request
> then. In that case usb_gadget_control_complete doesn't need to check the
> status of the request, since there isn't any, right?

Wrong -- the status has already been set by that time.

Alan Stern