Now that extension unit support is available through configfs we need to copy the descriptors for the XUs during uvc_function_bind() so that they're exposed to the usb subsystem. Reviewed-by: Laurent Pinchart <laurent.pinchart@xxxxxxxxxxxxxxxx> Signed-off-by: Daniel Scally <dan.scally@xxxxxxxxxxxxxxxx> --- Laurent - I didn't add your tag because having switched it to a function I actually decided I preferred it this way and switched it back; too many pointers to pointers of things made it less easy to follow I think, but if you disagree let me know and I'll go ahead. Changes in v5: - None Changes in v4: - None Changes in v3: - Dropped a local variable. Changes in v2: - none drivers/usb/gadget/function/f_uvc.c | 33 +++++++++++++++++++++++++++++ drivers/usb/gadget/function/uvc.h | 1 + 2 files changed, 34 insertions(+) diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c index 443333471b4d..f6fd5decdcb7 100644 --- a/drivers/usb/gadget/function/f_uvc.c +++ b/drivers/usb/gadget/function/f_uvc.c @@ -478,6 +478,25 @@ uvc_register_video(struct uvc_device *uvc) } \ } while (0) +#define UVC_COPY_XU_DESCRIPTOR(mem, dst, desc) \ + do { \ + *(dst)++ = mem; \ + memcpy(mem, desc, 22); /* bLength to bNrInPins */ \ + mem += 22; \ + \ + memcpy(mem, (desc)->baSourceID, (desc)->bNrInPins); \ + mem += (desc)->bNrInPins; \ + \ + memcpy(mem, &(desc)->bControlSize, 1); \ + mem++; \ + \ + memcpy(mem, (desc)->bmControls, (desc)->bControlSize); \ + mem += (desc)->bControlSize; \ + \ + memcpy(mem, &(desc)->iExtension, 1); \ + mem++; \ + } while (0) + static struct usb_descriptor_header ** uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) { @@ -489,6 +508,7 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) const struct usb_descriptor_header * const *src; struct usb_descriptor_header **dst; struct usb_descriptor_header **hdr; + struct uvcg_extension *xu; unsigned int control_size; unsigned int streaming_size; unsigned int n_desc; @@ -556,6 +576,13 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) bytes += (*src)->bLength; n_desc++; } + + list_for_each_entry(xu, uvc->desc.extension_units, list) { + control_size += xu->desc.bLength; + bytes += xu->desc.bLength; + n_desc++; + } + for (src = (const struct usb_descriptor_header **)uvc_streaming_cls; *src; ++src) { streaming_size += (*src)->bLength; @@ -582,6 +609,10 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) uvc_control_header = mem; UVC_COPY_DESCRIPTORS(mem, dst, (const struct usb_descriptor_header **)uvc_control_desc); + + list_for_each_entry(xu, uvc->desc.extension_units, list) + UVC_COPY_XU_DESCRIPTOR(mem, dst, &xu->desc); + uvc_control_header->wTotalLength = cpu_to_le16(control_size); uvc_control_header->bInCollection = 1; uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf; @@ -1025,6 +1056,8 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi) return ERR_PTR(-EBUSY); } + uvc->desc.extension_units = &opts->extension_units; + ++opts->refcnt; mutex_unlock(&opts->lock); diff --git a/drivers/usb/gadget/function/uvc.h b/drivers/usb/gadget/function/uvc.h index daf226610f49..100475b1363e 100644 --- a/drivers/usb/gadget/function/uvc.h +++ b/drivers/usb/gadget/function/uvc.h @@ -143,6 +143,7 @@ struct uvc_device { const struct uvc_descriptor_header * const *fs_streaming; const struct uvc_descriptor_header * const *hs_streaming; const struct uvc_descriptor_header * const *ss_streaming; + struct list_head *extension_units; } desc; unsigned int control_intf; -- 2.34.1