static struct usb_descriptor_header ** __init uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) { struct uvc_input_header_descriptor *uvc_streaming_header; struct uvc_header_descriptor *uvc_control_header; const struct uvc_descriptor_header * const *uvc_control_desc; const struct uvc_descriptor_header * const *uvc_streaming_cls; const struct usb_descriptor_header * const *uvc_streaming_std; const struct usb_descriptor_header * const *src; struct usb_descriptor_header **dst; struct usb_descriptor_header **hdr; unsigned int control_size; unsigned int streaming_size; unsigned int n_desc; unsigned int bytes; void *mem; switch (speed) { case USB_SPEED_SUPER: uvc_control_desc = uvc->desc.ss_control; uvc_streaming_cls = uvc->desc.ss_streaming; uvc_streaming_std = uvc_ss_streaming; break; case USB_SPEED_HIGH: uvc_control_desc = uvc->desc.fs_control; uvc_streaming_cls = uvc->desc.hs_streaming; uvc_streaming_std = uvc_hs_streaming; break; case USB_SPEED_FULL: default: uvc_control_desc = uvc->desc.fs_control; uvc_streaming_cls = uvc->desc.fs_streaming; uvc_streaming_std = uvc_fs_streaming; break; } /* Descriptors layout * * uvc_iad * uvc_control_intf * Class-specific UVC control descriptors * uvc_control_ep * uvc_control_cs_ep * uvc_ss_control_comp (for SS only) * uvc_streaming_intf_alt0 * Class-specific UVC streaming descriptors * uvc_{fs|hs}_streaming */ /* Count descriptors and compute their size. */ control_size = 0; streaming_size = 0; bytes = uvc_iad.bLength + uvc_control_intf.bLength + uvc_control_ep.bLength + uvc_control_cs_ep.bLength + uvc_streaming_intf_alt0.bLength; if (speed == USB_SPEED_SUPER) { bytes += uvc_ss_control_comp.bLength; n_desc = 6; } else { n_desc = 5; } for (src = (const struct usb_descriptor_header **)uvc_control_desc; *src; ++src) { control_size += (*src)->bLength; bytes += (*src)->bLength; n_desc++; } for (src = (const struct usb_descriptor_header **)uvc_streaming_cls; *src; ++src) { streaming_size += (*src)->bLength; bytes += (*src)->bLength; n_desc++; } for (src = uvc_streaming_std; *src; ++src) { bytes += (*src)->bLength; n_desc++; } mem = kmalloc((n_desc + 1) * sizeof(*src) + bytes, GFP_KERNEL); if (mem == NULL) return NULL; hdr = mem; dst = mem; mem += (n_desc + 1) * sizeof(*src); /* Copy the descriptors. */ UVC_COPY_DESCRIPTOR(mem, dst, &uvc_iad); UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_intf); uvc_control_header = mem; UVC_COPY_DESCRIPTORS(mem, dst, (const struct usb_descriptor_header **)uvc_control_desc); uvc_control_header->wTotalLength = cpu_to_le16(control_size); uvc_control_header->bInCollection = 1; uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf; UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_ep); if (speed == USB_SPEED_SUPER) UVC_COPY_DESCRIPTOR(mem, dst, &uvc_ss_control_comp); UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep); UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0); uvc_streaming_header = mem; UVC_COPY_DESCRIPTORS(mem, dst, (const struct usb_descriptor_header**)uvc_streaming_cls); uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size); uvc_streaming_header->bEndpointAddress = uvc->video.ep->address; UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std); *dst = NULL; return hdr; }
static struct usb_descriptor_header ** __init uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) { struct uvc_input_header_descriptor *uvc_streaming_header; struct uvc_header_descriptor *uvc_control_header; const struct uvc_descriptor_header * const *uvc_streaming_cls; const struct usb_descriptor_header * const *uvc_streaming_std; const struct usb_descriptor_header * const *src; struct usb_descriptor_header **dst; struct usb_descriptor_header **hdr; unsigned int control_size; unsigned int streaming_size; unsigned int n_desc; unsigned int bytes; void *mem; uvc_streaming_cls = (speed == USB_SPEED_FULL) ? uvc->desc.fs_streaming : uvc->desc.hs_streaming; uvc_streaming_std = (speed == USB_SPEED_FULL) ? uvc_fs_streaming : uvc_hs_streaming; control_size = 0; streaming_size = 0; bytes = uvc_iad.bLength + uvc_control_intf.bLength + uvc_control_ep.bLength + uvc_control_cs_ep.bLength + uvc_streaming_intf_alt0.bLength; n_desc = 5; for (src = (const struct usb_descriptor_header**)uvc->desc.control; *src; ++src) { control_size += (*src)->bLength; bytes += (*src)->bLength; n_desc++; } for (src = (const struct usb_descriptor_header**)uvc_streaming_cls; *src; ++src) { streaming_size += (*src)->bLength; bytes += (*src)->bLength; n_desc++; } for (src = uvc_streaming_std; *src; ++src) { bytes += (*src)->bLength; n_desc++; } mem = kmalloc((n_desc + 1) * sizeof(*src) + bytes, GFP_KERNEL); if (mem == NULL) return NULL; hdr = mem; dst = mem; mem += (n_desc + 1) * sizeof(*src); UVC_COPY_DESCRIPTOR(mem, dst, &uvc_iad); UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_intf); uvc_control_header = mem; UVC_COPY_DESCRIPTORS(mem, dst, (const struct usb_descriptor_header**)uvc->desc.control); uvc_control_header->wTotalLength = cpu_to_le16(control_size); uvc_control_header->bInCollection = 1; uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf; UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_ep); UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_cs_ep); UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0); uvc_streaming_header = mem; UVC_COPY_DESCRIPTORS(mem, dst, (const struct usb_descriptor_header**)uvc_streaming_cls); uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size); uvc_streaming_header->bEndpointAddress = uvc_streaming_ep.bEndpointAddress; UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std); *dst = NULL; return hdr; }