162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * uvc_gadget.c -- USB Video Class Gadget driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2009-2010 662306a36Sopenharmony_ci * Laurent Pinchart (laurent.pinchart@ideasonboard.com) 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/device.h> 1062306a36Sopenharmony_ci#include <linux/errno.h> 1162306a36Sopenharmony_ci#include <linux/fs.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/list.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/mutex.h> 1662306a36Sopenharmony_ci#include <linux/string.h> 1762306a36Sopenharmony_ci#include <linux/usb/ch9.h> 1862306a36Sopenharmony_ci#include <linux/usb/gadget.h> 1962306a36Sopenharmony_ci#include <linux/usb/g_uvc.h> 2062306a36Sopenharmony_ci#include <linux/usb/video.h> 2162306a36Sopenharmony_ci#include <linux/vmalloc.h> 2262306a36Sopenharmony_ci#include <linux/wait.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include <media/v4l2-dev.h> 2562306a36Sopenharmony_ci#include <media/v4l2-event.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include "uvc.h" 2862306a36Sopenharmony_ci#include "uvc_configfs.h" 2962306a36Sopenharmony_ci#include "uvc_v4l2.h" 3062306a36Sopenharmony_ci#include "uvc_video.h" 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ciunsigned int uvc_gadget_trace_param; 3362306a36Sopenharmony_cimodule_param_named(trace, uvc_gadget_trace_param, uint, 0644); 3462306a36Sopenharmony_ciMODULE_PARM_DESC(trace, "Trace level bitmask"); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* -------------------------------------------------------------------------- 3762306a36Sopenharmony_ci * Function descriptors 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* string IDs are assigned dynamically */ 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic struct usb_string uvc_en_us_strings[] = { 4362306a36Sopenharmony_ci /* [UVC_STRING_CONTROL_IDX].s = DYNAMIC, */ 4462306a36Sopenharmony_ci [UVC_STRING_STREAMING_IDX].s = "Video Streaming", 4562306a36Sopenharmony_ci { } 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cistatic struct usb_gadget_strings uvc_stringtab = { 4962306a36Sopenharmony_ci .language = 0x0409, /* en-us */ 5062306a36Sopenharmony_ci .strings = uvc_en_us_strings, 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic struct usb_gadget_strings *uvc_function_strings[] = { 5462306a36Sopenharmony_ci &uvc_stringtab, 5562306a36Sopenharmony_ci NULL, 5662306a36Sopenharmony_ci}; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define UVC_INTF_VIDEO_CONTROL 0 5962306a36Sopenharmony_ci#define UVC_INTF_VIDEO_STREAMING 1 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define UVC_STATUS_MAX_PACKET_SIZE 16 /* 16 bytes status */ 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic struct usb_interface_assoc_descriptor uvc_iad = { 6462306a36Sopenharmony_ci .bLength = sizeof(uvc_iad), 6562306a36Sopenharmony_ci .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION, 6662306a36Sopenharmony_ci .bFirstInterface = 0, 6762306a36Sopenharmony_ci .bInterfaceCount = 2, 6862306a36Sopenharmony_ci .bFunctionClass = USB_CLASS_VIDEO, 6962306a36Sopenharmony_ci .bFunctionSubClass = UVC_SC_VIDEO_INTERFACE_COLLECTION, 7062306a36Sopenharmony_ci .bFunctionProtocol = 0x00, 7162306a36Sopenharmony_ci .iFunction = 0, 7262306a36Sopenharmony_ci}; 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic struct usb_interface_descriptor uvc_control_intf = { 7562306a36Sopenharmony_ci .bLength = USB_DT_INTERFACE_SIZE, 7662306a36Sopenharmony_ci .bDescriptorType = USB_DT_INTERFACE, 7762306a36Sopenharmony_ci .bInterfaceNumber = UVC_INTF_VIDEO_CONTROL, 7862306a36Sopenharmony_ci .bAlternateSetting = 0, 7962306a36Sopenharmony_ci .bNumEndpoints = 0, 8062306a36Sopenharmony_ci .bInterfaceClass = USB_CLASS_VIDEO, 8162306a36Sopenharmony_ci .bInterfaceSubClass = UVC_SC_VIDEOCONTROL, 8262306a36Sopenharmony_ci .bInterfaceProtocol = 0x00, 8362306a36Sopenharmony_ci .iInterface = 0, 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_cistatic struct usb_endpoint_descriptor uvc_interrupt_ep = { 8762306a36Sopenharmony_ci .bLength = USB_DT_ENDPOINT_SIZE, 8862306a36Sopenharmony_ci .bDescriptorType = USB_DT_ENDPOINT, 8962306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_IN, 9062306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_XFER_INT, 9162306a36Sopenharmony_ci .wMaxPacketSize = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE), 9262306a36Sopenharmony_ci .bInterval = 8, 9362306a36Sopenharmony_ci}; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_cistatic struct usb_ss_ep_comp_descriptor uvc_ss_interrupt_comp = { 9662306a36Sopenharmony_ci .bLength = sizeof(uvc_ss_interrupt_comp), 9762306a36Sopenharmony_ci .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, 9862306a36Sopenharmony_ci /* The following 3 values can be tweaked if necessary. */ 9962306a36Sopenharmony_ci .bMaxBurst = 0, 10062306a36Sopenharmony_ci .bmAttributes = 0, 10162306a36Sopenharmony_ci .wBytesPerInterval = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE), 10262306a36Sopenharmony_ci}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistatic struct uvc_control_endpoint_descriptor uvc_interrupt_cs_ep = { 10562306a36Sopenharmony_ci .bLength = UVC_DT_CONTROL_ENDPOINT_SIZE, 10662306a36Sopenharmony_ci .bDescriptorType = USB_DT_CS_ENDPOINT, 10762306a36Sopenharmony_ci .bDescriptorSubType = UVC_EP_INTERRUPT, 10862306a36Sopenharmony_ci .wMaxTransferSize = cpu_to_le16(UVC_STATUS_MAX_PACKET_SIZE), 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic struct usb_interface_descriptor uvc_streaming_intf_alt0 = { 11262306a36Sopenharmony_ci .bLength = USB_DT_INTERFACE_SIZE, 11362306a36Sopenharmony_ci .bDescriptorType = USB_DT_INTERFACE, 11462306a36Sopenharmony_ci .bInterfaceNumber = UVC_INTF_VIDEO_STREAMING, 11562306a36Sopenharmony_ci .bAlternateSetting = 0, 11662306a36Sopenharmony_ci .bNumEndpoints = 0, 11762306a36Sopenharmony_ci .bInterfaceClass = USB_CLASS_VIDEO, 11862306a36Sopenharmony_ci .bInterfaceSubClass = UVC_SC_VIDEOSTREAMING, 11962306a36Sopenharmony_ci .bInterfaceProtocol = 0x00, 12062306a36Sopenharmony_ci .iInterface = 0, 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistatic struct usb_interface_descriptor uvc_streaming_intf_alt1 = { 12462306a36Sopenharmony_ci .bLength = USB_DT_INTERFACE_SIZE, 12562306a36Sopenharmony_ci .bDescriptorType = USB_DT_INTERFACE, 12662306a36Sopenharmony_ci .bInterfaceNumber = UVC_INTF_VIDEO_STREAMING, 12762306a36Sopenharmony_ci .bAlternateSetting = 1, 12862306a36Sopenharmony_ci .bNumEndpoints = 1, 12962306a36Sopenharmony_ci .bInterfaceClass = USB_CLASS_VIDEO, 13062306a36Sopenharmony_ci .bInterfaceSubClass = UVC_SC_VIDEOSTREAMING, 13162306a36Sopenharmony_ci .bInterfaceProtocol = 0x00, 13262306a36Sopenharmony_ci .iInterface = 0, 13362306a36Sopenharmony_ci}; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cistatic struct usb_endpoint_descriptor uvc_fs_streaming_ep = { 13662306a36Sopenharmony_ci .bLength = USB_DT_ENDPOINT_SIZE, 13762306a36Sopenharmony_ci .bDescriptorType = USB_DT_ENDPOINT, 13862306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_IN, 13962306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_SYNC_ASYNC 14062306a36Sopenharmony_ci | USB_ENDPOINT_XFER_ISOC, 14162306a36Sopenharmony_ci /* 14262306a36Sopenharmony_ci * The wMaxPacketSize and bInterval values will be initialized from 14362306a36Sopenharmony_ci * module parameters. 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_ci}; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic struct usb_endpoint_descriptor uvc_hs_streaming_ep = { 14862306a36Sopenharmony_ci .bLength = USB_DT_ENDPOINT_SIZE, 14962306a36Sopenharmony_ci .bDescriptorType = USB_DT_ENDPOINT, 15062306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_IN, 15162306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_SYNC_ASYNC 15262306a36Sopenharmony_ci | USB_ENDPOINT_XFER_ISOC, 15362306a36Sopenharmony_ci /* 15462306a36Sopenharmony_ci * The wMaxPacketSize and bInterval values will be initialized from 15562306a36Sopenharmony_ci * module parameters. 15662306a36Sopenharmony_ci */ 15762306a36Sopenharmony_ci}; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_cistatic struct usb_endpoint_descriptor uvc_ss_streaming_ep = { 16062306a36Sopenharmony_ci .bLength = USB_DT_ENDPOINT_SIZE, 16162306a36Sopenharmony_ci .bDescriptorType = USB_DT_ENDPOINT, 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci .bEndpointAddress = USB_DIR_IN, 16462306a36Sopenharmony_ci .bmAttributes = USB_ENDPOINT_SYNC_ASYNC 16562306a36Sopenharmony_ci | USB_ENDPOINT_XFER_ISOC, 16662306a36Sopenharmony_ci /* 16762306a36Sopenharmony_ci * The wMaxPacketSize and bInterval values will be initialized from 16862306a36Sopenharmony_ci * module parameters. 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_ci}; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_cistatic struct usb_ss_ep_comp_descriptor uvc_ss_streaming_comp = { 17362306a36Sopenharmony_ci .bLength = sizeof(uvc_ss_streaming_comp), 17462306a36Sopenharmony_ci .bDescriptorType = USB_DT_SS_ENDPOINT_COMP, 17562306a36Sopenharmony_ci /* 17662306a36Sopenharmony_ci * The bMaxBurst, bmAttributes and wBytesPerInterval values will be 17762306a36Sopenharmony_ci * initialized from module parameters. 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_ci}; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic const struct usb_descriptor_header * const uvc_fs_streaming[] = { 18262306a36Sopenharmony_ci (struct usb_descriptor_header *) &uvc_streaming_intf_alt1, 18362306a36Sopenharmony_ci (struct usb_descriptor_header *) &uvc_fs_streaming_ep, 18462306a36Sopenharmony_ci NULL, 18562306a36Sopenharmony_ci}; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cistatic const struct usb_descriptor_header * const uvc_hs_streaming[] = { 18862306a36Sopenharmony_ci (struct usb_descriptor_header *) &uvc_streaming_intf_alt1, 18962306a36Sopenharmony_ci (struct usb_descriptor_header *) &uvc_hs_streaming_ep, 19062306a36Sopenharmony_ci NULL, 19162306a36Sopenharmony_ci}; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic const struct usb_descriptor_header * const uvc_ss_streaming[] = { 19462306a36Sopenharmony_ci (struct usb_descriptor_header *) &uvc_streaming_intf_alt1, 19562306a36Sopenharmony_ci (struct usb_descriptor_header *) &uvc_ss_streaming_ep, 19662306a36Sopenharmony_ci (struct usb_descriptor_header *) &uvc_ss_streaming_comp, 19762306a36Sopenharmony_ci NULL, 19862306a36Sopenharmony_ci}; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci/* -------------------------------------------------------------------------- 20162306a36Sopenharmony_ci * Control requests 20262306a36Sopenharmony_ci */ 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic void 20562306a36Sopenharmony_ciuvc_function_ep0_complete(struct usb_ep *ep, struct usb_request *req) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci struct uvc_device *uvc = req->context; 20862306a36Sopenharmony_ci struct v4l2_event v4l2_event; 20962306a36Sopenharmony_ci struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci if (uvc->event_setup_out) { 21262306a36Sopenharmony_ci uvc->event_setup_out = 0; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci memset(&v4l2_event, 0, sizeof(v4l2_event)); 21562306a36Sopenharmony_ci v4l2_event.type = UVC_EVENT_DATA; 21662306a36Sopenharmony_ci uvc_event->data.length = min_t(unsigned int, req->actual, 21762306a36Sopenharmony_ci sizeof(uvc_event->data.data)); 21862306a36Sopenharmony_ci memcpy(&uvc_event->data.data, req->buf, uvc_event->data.length); 21962306a36Sopenharmony_ci v4l2_event_queue(&uvc->vdev, &v4l2_event); 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic int 22462306a36Sopenharmony_ciuvc_function_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl) 22562306a36Sopenharmony_ci{ 22662306a36Sopenharmony_ci struct uvc_device *uvc = to_uvc(f); 22762306a36Sopenharmony_ci struct v4l2_event v4l2_event; 22862306a36Sopenharmony_ci struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; 22962306a36Sopenharmony_ci unsigned int interface = le16_to_cpu(ctrl->wIndex) & 0xff; 23062306a36Sopenharmony_ci struct usb_ctrlrequest *mctrl; 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if ((ctrl->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS) { 23362306a36Sopenharmony_ci uvcg_info(f, "invalid request type\n"); 23462306a36Sopenharmony_ci return -EINVAL; 23562306a36Sopenharmony_ci } 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* Stall too big requests. */ 23862306a36Sopenharmony_ci if (le16_to_cpu(ctrl->wLength) > UVC_MAX_REQUEST_SIZE) 23962306a36Sopenharmony_ci return -EINVAL; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* 24262306a36Sopenharmony_ci * Tell the complete callback to generate an event for the next request 24362306a36Sopenharmony_ci * that will be enqueued by UVCIOC_SEND_RESPONSE. 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_ci uvc->event_setup_out = !(ctrl->bRequestType & USB_DIR_IN); 24662306a36Sopenharmony_ci uvc->event_length = le16_to_cpu(ctrl->wLength); 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci memset(&v4l2_event, 0, sizeof(v4l2_event)); 24962306a36Sopenharmony_ci v4l2_event.type = UVC_EVENT_SETUP; 25062306a36Sopenharmony_ci memcpy(&uvc_event->req, ctrl, sizeof(uvc_event->req)); 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci /* check for the interface number, fixup the interface number in 25362306a36Sopenharmony_ci * the ctrl request so the userspace doesn't have to bother with 25462306a36Sopenharmony_ci * offset and configfs parsing 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_ci mctrl = &uvc_event->req; 25762306a36Sopenharmony_ci mctrl->wIndex &= ~cpu_to_le16(0xff); 25862306a36Sopenharmony_ci if (interface == uvc->streaming_intf) 25962306a36Sopenharmony_ci mctrl->wIndex = cpu_to_le16(UVC_STRING_STREAMING_IDX); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci v4l2_event_queue(&uvc->vdev, &v4l2_event); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci return 0; 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_civoid uvc_function_setup_continue(struct uvc_device *uvc) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci struct usb_composite_dev *cdev = uvc->func.config->cdev; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci usb_composite_setup_continue(cdev); 27162306a36Sopenharmony_ci} 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_cistatic int 27462306a36Sopenharmony_ciuvc_function_get_alt(struct usb_function *f, unsigned interface) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci struct uvc_device *uvc = to_uvc(f); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci uvcg_info(f, "%s(%u)\n", __func__, interface); 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci if (interface == uvc->control_intf) 28162306a36Sopenharmony_ci return 0; 28262306a36Sopenharmony_ci else if (interface != uvc->streaming_intf) 28362306a36Sopenharmony_ci return -EINVAL; 28462306a36Sopenharmony_ci else 28562306a36Sopenharmony_ci return uvc->video.ep->enabled ? 1 : 0; 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic int 28962306a36Sopenharmony_ciuvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt) 29062306a36Sopenharmony_ci{ 29162306a36Sopenharmony_ci struct uvc_device *uvc = to_uvc(f); 29262306a36Sopenharmony_ci struct usb_composite_dev *cdev = f->config->cdev; 29362306a36Sopenharmony_ci struct v4l2_event v4l2_event; 29462306a36Sopenharmony_ci struct uvc_event *uvc_event = (void *)&v4l2_event.u.data; 29562306a36Sopenharmony_ci int ret; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci uvcg_info(f, "%s(%u, %u)\n", __func__, interface, alt); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (interface == uvc->control_intf) { 30062306a36Sopenharmony_ci if (alt) 30162306a36Sopenharmony_ci return -EINVAL; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci if (uvc->enable_interrupt_ep) { 30462306a36Sopenharmony_ci uvcg_info(f, "reset UVC interrupt endpoint\n"); 30562306a36Sopenharmony_ci usb_ep_disable(uvc->interrupt_ep); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if (!uvc->interrupt_ep->desc) 30862306a36Sopenharmony_ci if (config_ep_by_speed(cdev->gadget, f, 30962306a36Sopenharmony_ci uvc->interrupt_ep)) 31062306a36Sopenharmony_ci return -EINVAL; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci usb_ep_enable(uvc->interrupt_ep); 31362306a36Sopenharmony_ci } 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (uvc->state == UVC_STATE_DISCONNECTED) { 31662306a36Sopenharmony_ci memset(&v4l2_event, 0, sizeof(v4l2_event)); 31762306a36Sopenharmony_ci v4l2_event.type = UVC_EVENT_CONNECT; 31862306a36Sopenharmony_ci uvc_event->speed = cdev->gadget->speed; 31962306a36Sopenharmony_ci v4l2_event_queue(&uvc->vdev, &v4l2_event); 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci uvc->state = UVC_STATE_CONNECTED; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci return 0; 32562306a36Sopenharmony_ci } 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci if (interface != uvc->streaming_intf) 32862306a36Sopenharmony_ci return -EINVAL; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci /* TODO 33162306a36Sopenharmony_ci if (usb_endpoint_xfer_bulk(&uvc->desc.vs_ep)) 33262306a36Sopenharmony_ci return alt ? -EINVAL : 0; 33362306a36Sopenharmony_ci */ 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci switch (alt) { 33662306a36Sopenharmony_ci case 0: 33762306a36Sopenharmony_ci if (uvc->state != UVC_STATE_STREAMING) 33862306a36Sopenharmony_ci return 0; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci if (uvc->video.ep) 34162306a36Sopenharmony_ci usb_ep_disable(uvc->video.ep); 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci memset(&v4l2_event, 0, sizeof(v4l2_event)); 34462306a36Sopenharmony_ci v4l2_event.type = UVC_EVENT_STREAMOFF; 34562306a36Sopenharmony_ci v4l2_event_queue(&uvc->vdev, &v4l2_event); 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci uvc->state = UVC_STATE_CONNECTED; 34862306a36Sopenharmony_ci return 0; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci case 1: 35162306a36Sopenharmony_ci if (uvc->state != UVC_STATE_CONNECTED) 35262306a36Sopenharmony_ci return 0; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (!uvc->video.ep) 35562306a36Sopenharmony_ci return -EINVAL; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci uvcg_info(f, "reset UVC\n"); 35862306a36Sopenharmony_ci usb_ep_disable(uvc->video.ep); 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci ret = config_ep_by_speed(f->config->cdev->gadget, 36162306a36Sopenharmony_ci &(uvc->func), uvc->video.ep); 36262306a36Sopenharmony_ci if (ret) 36362306a36Sopenharmony_ci return ret; 36462306a36Sopenharmony_ci usb_ep_enable(uvc->video.ep); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci memset(&v4l2_event, 0, sizeof(v4l2_event)); 36762306a36Sopenharmony_ci v4l2_event.type = UVC_EVENT_STREAMON; 36862306a36Sopenharmony_ci v4l2_event_queue(&uvc->vdev, &v4l2_event); 36962306a36Sopenharmony_ci return USB_GADGET_DELAYED_STATUS; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci default: 37262306a36Sopenharmony_ci return -EINVAL; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic void 37762306a36Sopenharmony_ciuvc_function_disable(struct usb_function *f) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci struct uvc_device *uvc = to_uvc(f); 38062306a36Sopenharmony_ci struct v4l2_event v4l2_event; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci uvcg_info(f, "%s()\n", __func__); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci memset(&v4l2_event, 0, sizeof(v4l2_event)); 38562306a36Sopenharmony_ci v4l2_event.type = UVC_EVENT_DISCONNECT; 38662306a36Sopenharmony_ci v4l2_event_queue(&uvc->vdev, &v4l2_event); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci uvc->state = UVC_STATE_DISCONNECTED; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci usb_ep_disable(uvc->video.ep); 39162306a36Sopenharmony_ci if (uvc->enable_interrupt_ep) 39262306a36Sopenharmony_ci usb_ep_disable(uvc->interrupt_ep); 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci/* -------------------------------------------------------------------------- 39662306a36Sopenharmony_ci * Connection / disconnection 39762306a36Sopenharmony_ci */ 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_civoid 40062306a36Sopenharmony_ciuvc_function_connect(struct uvc_device *uvc) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci int ret; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci if ((ret = usb_function_activate(&uvc->func)) < 0) 40562306a36Sopenharmony_ci uvcg_info(&uvc->func, "UVC connect failed with %d\n", ret); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_civoid 40962306a36Sopenharmony_ciuvc_function_disconnect(struct uvc_device *uvc) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci int ret; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if ((ret = usb_function_deactivate(&uvc->func)) < 0) 41462306a36Sopenharmony_ci uvcg_info(&uvc->func, "UVC disconnect failed with %d\n", ret); 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci/* -------------------------------------------------------------------------- 41862306a36Sopenharmony_ci * USB probe and disconnect 41962306a36Sopenharmony_ci */ 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic ssize_t function_name_show(struct device *dev, 42262306a36Sopenharmony_ci struct device_attribute *attr, char *buf) 42362306a36Sopenharmony_ci{ 42462306a36Sopenharmony_ci struct uvc_device *uvc = dev_get_drvdata(dev); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci return sprintf(buf, "%s\n", uvc->func.fi->group.cg_item.ci_name); 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(function_name); 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic int 43262306a36Sopenharmony_ciuvc_register_video(struct uvc_device *uvc) 43362306a36Sopenharmony_ci{ 43462306a36Sopenharmony_ci struct usb_composite_dev *cdev = uvc->func.config->cdev; 43562306a36Sopenharmony_ci int ret; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci /* TODO reference counting. */ 43862306a36Sopenharmony_ci memset(&uvc->vdev, 0, sizeof(uvc->vdev)); 43962306a36Sopenharmony_ci uvc->vdev.v4l2_dev = &uvc->v4l2_dev; 44062306a36Sopenharmony_ci uvc->vdev.v4l2_dev->dev = &cdev->gadget->dev; 44162306a36Sopenharmony_ci uvc->vdev.fops = &uvc_v4l2_fops; 44262306a36Sopenharmony_ci uvc->vdev.ioctl_ops = &uvc_v4l2_ioctl_ops; 44362306a36Sopenharmony_ci uvc->vdev.release = video_device_release_empty; 44462306a36Sopenharmony_ci uvc->vdev.vfl_dir = VFL_DIR_TX; 44562306a36Sopenharmony_ci uvc->vdev.lock = &uvc->video.mutex; 44662306a36Sopenharmony_ci uvc->vdev.device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; 44762306a36Sopenharmony_ci strscpy(uvc->vdev.name, cdev->gadget->name, sizeof(uvc->vdev.name)); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci video_set_drvdata(&uvc->vdev, uvc); 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci ret = video_register_device(&uvc->vdev, VFL_TYPE_VIDEO, -1); 45262306a36Sopenharmony_ci if (ret < 0) 45362306a36Sopenharmony_ci return ret; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci ret = device_create_file(&uvc->vdev.dev, &dev_attr_function_name); 45662306a36Sopenharmony_ci if (ret < 0) { 45762306a36Sopenharmony_ci video_unregister_device(&uvc->vdev); 45862306a36Sopenharmony_ci return ret; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci return 0; 46262306a36Sopenharmony_ci} 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci#define UVC_COPY_DESCRIPTOR(mem, dst, desc) \ 46562306a36Sopenharmony_ci do { \ 46662306a36Sopenharmony_ci memcpy(mem, desc, (desc)->bLength); \ 46762306a36Sopenharmony_ci *(dst)++ = mem; \ 46862306a36Sopenharmony_ci mem += (desc)->bLength; \ 46962306a36Sopenharmony_ci } while (0); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci#define UVC_COPY_DESCRIPTORS(mem, dst, src) \ 47262306a36Sopenharmony_ci do { \ 47362306a36Sopenharmony_ci const struct usb_descriptor_header * const *__src; \ 47462306a36Sopenharmony_ci for (__src = src; *__src; ++__src) { \ 47562306a36Sopenharmony_ci memcpy(mem, *__src, (*__src)->bLength); \ 47662306a36Sopenharmony_ci *dst++ = mem; \ 47762306a36Sopenharmony_ci mem += (*__src)->bLength; \ 47862306a36Sopenharmony_ci } \ 47962306a36Sopenharmony_ci } while (0) 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci#define UVC_COPY_XU_DESCRIPTOR(mem, dst, desc) \ 48262306a36Sopenharmony_ci do { \ 48362306a36Sopenharmony_ci *(dst)++ = mem; \ 48462306a36Sopenharmony_ci memcpy(mem, desc, 22); /* bLength to bNrInPins */ \ 48562306a36Sopenharmony_ci mem += 22; \ 48662306a36Sopenharmony_ci \ 48762306a36Sopenharmony_ci memcpy(mem, (desc)->baSourceID, (desc)->bNrInPins); \ 48862306a36Sopenharmony_ci mem += (desc)->bNrInPins; \ 48962306a36Sopenharmony_ci \ 49062306a36Sopenharmony_ci memcpy(mem, &(desc)->bControlSize, 1); \ 49162306a36Sopenharmony_ci mem++; \ 49262306a36Sopenharmony_ci \ 49362306a36Sopenharmony_ci memcpy(mem, (desc)->bmControls, (desc)->bControlSize); \ 49462306a36Sopenharmony_ci mem += (desc)->bControlSize; \ 49562306a36Sopenharmony_ci \ 49662306a36Sopenharmony_ci memcpy(mem, &(desc)->iExtension, 1); \ 49762306a36Sopenharmony_ci mem++; \ 49862306a36Sopenharmony_ci } while (0) 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic struct usb_descriptor_header ** 50162306a36Sopenharmony_ciuvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci struct uvc_input_header_descriptor *uvc_streaming_header; 50462306a36Sopenharmony_ci struct uvc_header_descriptor *uvc_control_header; 50562306a36Sopenharmony_ci const struct uvc_descriptor_header * const *uvc_control_desc; 50662306a36Sopenharmony_ci const struct uvc_descriptor_header * const *uvc_streaming_cls; 50762306a36Sopenharmony_ci const struct usb_descriptor_header * const *uvc_streaming_std; 50862306a36Sopenharmony_ci const struct usb_descriptor_header * const *src; 50962306a36Sopenharmony_ci struct usb_descriptor_header **dst; 51062306a36Sopenharmony_ci struct usb_descriptor_header **hdr; 51162306a36Sopenharmony_ci struct uvcg_extension *xu; 51262306a36Sopenharmony_ci unsigned int control_size; 51362306a36Sopenharmony_ci unsigned int streaming_size; 51462306a36Sopenharmony_ci unsigned int n_desc; 51562306a36Sopenharmony_ci unsigned int bytes; 51662306a36Sopenharmony_ci void *mem; 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci switch (speed) { 51962306a36Sopenharmony_ci case USB_SPEED_SUPER: 52062306a36Sopenharmony_ci uvc_control_desc = uvc->desc.ss_control; 52162306a36Sopenharmony_ci uvc_streaming_cls = uvc->desc.ss_streaming; 52262306a36Sopenharmony_ci uvc_streaming_std = uvc_ss_streaming; 52362306a36Sopenharmony_ci break; 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci case USB_SPEED_HIGH: 52662306a36Sopenharmony_ci uvc_control_desc = uvc->desc.fs_control; 52762306a36Sopenharmony_ci uvc_streaming_cls = uvc->desc.hs_streaming; 52862306a36Sopenharmony_ci uvc_streaming_std = uvc_hs_streaming; 52962306a36Sopenharmony_ci break; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci case USB_SPEED_FULL: 53262306a36Sopenharmony_ci default: 53362306a36Sopenharmony_ci uvc_control_desc = uvc->desc.fs_control; 53462306a36Sopenharmony_ci uvc_streaming_cls = uvc->desc.fs_streaming; 53562306a36Sopenharmony_ci uvc_streaming_std = uvc_fs_streaming; 53662306a36Sopenharmony_ci break; 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci if (!uvc_control_desc || !uvc_streaming_cls) 54062306a36Sopenharmony_ci return ERR_PTR(-ENODEV); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci /* 54362306a36Sopenharmony_ci * Descriptors layout 54462306a36Sopenharmony_ci * 54562306a36Sopenharmony_ci * uvc_iad 54662306a36Sopenharmony_ci * uvc_control_intf 54762306a36Sopenharmony_ci * Class-specific UVC control descriptors 54862306a36Sopenharmony_ci * uvc_interrupt_ep 54962306a36Sopenharmony_ci * uvc_interrupt_cs_ep 55062306a36Sopenharmony_ci * uvc_ss_interrupt_comp (for SS only) 55162306a36Sopenharmony_ci * uvc_streaming_intf_alt0 55262306a36Sopenharmony_ci * Class-specific UVC streaming descriptors 55362306a36Sopenharmony_ci * uvc_{fs|hs}_streaming 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci /* Count descriptors and compute their size. */ 55762306a36Sopenharmony_ci control_size = 0; 55862306a36Sopenharmony_ci streaming_size = 0; 55962306a36Sopenharmony_ci bytes = uvc_iad.bLength + uvc_control_intf.bLength 56062306a36Sopenharmony_ci + uvc_streaming_intf_alt0.bLength; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci n_desc = 3; 56362306a36Sopenharmony_ci if (uvc->enable_interrupt_ep) { 56462306a36Sopenharmony_ci bytes += uvc_interrupt_ep.bLength + uvc_interrupt_cs_ep.bLength; 56562306a36Sopenharmony_ci n_desc += 2; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci if (speed == USB_SPEED_SUPER) { 56862306a36Sopenharmony_ci bytes += uvc_ss_interrupt_comp.bLength; 56962306a36Sopenharmony_ci n_desc += 1; 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci for (src = (const struct usb_descriptor_header **)uvc_control_desc; 57462306a36Sopenharmony_ci *src; ++src) { 57562306a36Sopenharmony_ci control_size += (*src)->bLength; 57662306a36Sopenharmony_ci bytes += (*src)->bLength; 57762306a36Sopenharmony_ci n_desc++; 57862306a36Sopenharmony_ci } 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci list_for_each_entry(xu, uvc->desc.extension_units, list) { 58162306a36Sopenharmony_ci control_size += xu->desc.bLength; 58262306a36Sopenharmony_ci bytes += xu->desc.bLength; 58362306a36Sopenharmony_ci n_desc++; 58462306a36Sopenharmony_ci } 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci for (src = (const struct usb_descriptor_header **)uvc_streaming_cls; 58762306a36Sopenharmony_ci *src; ++src) { 58862306a36Sopenharmony_ci streaming_size += (*src)->bLength; 58962306a36Sopenharmony_ci bytes += (*src)->bLength; 59062306a36Sopenharmony_ci n_desc++; 59162306a36Sopenharmony_ci } 59262306a36Sopenharmony_ci for (src = uvc_streaming_std; *src; ++src) { 59362306a36Sopenharmony_ci bytes += (*src)->bLength; 59462306a36Sopenharmony_ci n_desc++; 59562306a36Sopenharmony_ci } 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci mem = kmalloc((n_desc + 1) * sizeof(*src) + bytes, GFP_KERNEL); 59862306a36Sopenharmony_ci if (mem == NULL) 59962306a36Sopenharmony_ci return NULL; 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci hdr = mem; 60262306a36Sopenharmony_ci dst = mem; 60362306a36Sopenharmony_ci mem += (n_desc + 1) * sizeof(*src); 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci /* Copy the descriptors. */ 60662306a36Sopenharmony_ci UVC_COPY_DESCRIPTOR(mem, dst, &uvc_iad); 60762306a36Sopenharmony_ci UVC_COPY_DESCRIPTOR(mem, dst, &uvc_control_intf); 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci uvc_control_header = mem; 61062306a36Sopenharmony_ci UVC_COPY_DESCRIPTORS(mem, dst, 61162306a36Sopenharmony_ci (const struct usb_descriptor_header **)uvc_control_desc); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci list_for_each_entry(xu, uvc->desc.extension_units, list) 61462306a36Sopenharmony_ci UVC_COPY_XU_DESCRIPTOR(mem, dst, &xu->desc); 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci uvc_control_header->wTotalLength = cpu_to_le16(control_size); 61762306a36Sopenharmony_ci uvc_control_header->bInCollection = 1; 61862306a36Sopenharmony_ci uvc_control_header->baInterfaceNr[0] = uvc->streaming_intf; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (uvc->enable_interrupt_ep) { 62162306a36Sopenharmony_ci UVC_COPY_DESCRIPTOR(mem, dst, &uvc_interrupt_ep); 62262306a36Sopenharmony_ci if (speed == USB_SPEED_SUPER) 62362306a36Sopenharmony_ci UVC_COPY_DESCRIPTOR(mem, dst, &uvc_ss_interrupt_comp); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci UVC_COPY_DESCRIPTOR(mem, dst, &uvc_interrupt_cs_ep); 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci UVC_COPY_DESCRIPTOR(mem, dst, &uvc_streaming_intf_alt0); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci uvc_streaming_header = mem; 63162306a36Sopenharmony_ci UVC_COPY_DESCRIPTORS(mem, dst, 63262306a36Sopenharmony_ci (const struct usb_descriptor_header**)uvc_streaming_cls); 63362306a36Sopenharmony_ci uvc_streaming_header->wTotalLength = cpu_to_le16(streaming_size); 63462306a36Sopenharmony_ci uvc_streaming_header->bEndpointAddress = uvc->video.ep->address; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci UVC_COPY_DESCRIPTORS(mem, dst, uvc_streaming_std); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci *dst = NULL; 63962306a36Sopenharmony_ci return hdr; 64062306a36Sopenharmony_ci} 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_cistatic int 64362306a36Sopenharmony_ciuvc_function_bind(struct usb_configuration *c, struct usb_function *f) 64462306a36Sopenharmony_ci{ 64562306a36Sopenharmony_ci struct usb_composite_dev *cdev = c->cdev; 64662306a36Sopenharmony_ci struct uvc_device *uvc = to_uvc(f); 64762306a36Sopenharmony_ci struct uvcg_extension *xu; 64862306a36Sopenharmony_ci struct usb_string *us; 64962306a36Sopenharmony_ci unsigned int max_packet_mult; 65062306a36Sopenharmony_ci unsigned int max_packet_size; 65162306a36Sopenharmony_ci struct usb_ep *ep; 65262306a36Sopenharmony_ci struct f_uvc_opts *opts; 65362306a36Sopenharmony_ci int ret = -EINVAL; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci uvcg_info(f, "%s()\n", __func__); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci opts = fi_to_f_uvc_opts(f->fi); 65862306a36Sopenharmony_ci /* Sanity check the streaming endpoint module parameters. */ 65962306a36Sopenharmony_ci opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U); 66062306a36Sopenharmony_ci opts->streaming_maxpacket = clamp(opts->streaming_maxpacket, 1U, 3072U); 66162306a36Sopenharmony_ci opts->streaming_maxburst = min(opts->streaming_maxburst, 15U); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* For SS, wMaxPacketSize has to be 1024 if bMaxBurst is not 0 */ 66462306a36Sopenharmony_ci if (opts->streaming_maxburst && 66562306a36Sopenharmony_ci (opts->streaming_maxpacket % 1024) != 0) { 66662306a36Sopenharmony_ci opts->streaming_maxpacket = roundup(opts->streaming_maxpacket, 1024); 66762306a36Sopenharmony_ci uvcg_info(f, "overriding streaming_maxpacket to %d\n", 66862306a36Sopenharmony_ci opts->streaming_maxpacket); 66962306a36Sopenharmony_ci } 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci /* 67262306a36Sopenharmony_ci * Fill in the FS/HS/SS Video Streaming specific descriptors from the 67362306a36Sopenharmony_ci * module parameters. 67462306a36Sopenharmony_ci * 67562306a36Sopenharmony_ci * NOTE: We assume that the user knows what they are doing and won't 67662306a36Sopenharmony_ci * give parameters that their UDC doesn't support. 67762306a36Sopenharmony_ci */ 67862306a36Sopenharmony_ci if (opts->streaming_maxpacket <= 1024) { 67962306a36Sopenharmony_ci max_packet_mult = 1; 68062306a36Sopenharmony_ci max_packet_size = opts->streaming_maxpacket; 68162306a36Sopenharmony_ci } else if (opts->streaming_maxpacket <= 2048) { 68262306a36Sopenharmony_ci max_packet_mult = 2; 68362306a36Sopenharmony_ci max_packet_size = opts->streaming_maxpacket / 2; 68462306a36Sopenharmony_ci } else { 68562306a36Sopenharmony_ci max_packet_mult = 3; 68662306a36Sopenharmony_ci max_packet_size = opts->streaming_maxpacket / 3; 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci uvc_fs_streaming_ep.wMaxPacketSize = 69062306a36Sopenharmony_ci cpu_to_le16(min(opts->streaming_maxpacket, 1023U)); 69162306a36Sopenharmony_ci uvc_fs_streaming_ep.bInterval = opts->streaming_interval; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci uvc_hs_streaming_ep.wMaxPacketSize = 69462306a36Sopenharmony_ci cpu_to_le16(max_packet_size | ((max_packet_mult - 1) << 11)); 69562306a36Sopenharmony_ci 69662306a36Sopenharmony_ci /* A high-bandwidth endpoint must specify a bInterval value of 1 */ 69762306a36Sopenharmony_ci if (max_packet_mult > 1) 69862306a36Sopenharmony_ci uvc_hs_streaming_ep.bInterval = 1; 69962306a36Sopenharmony_ci else 70062306a36Sopenharmony_ci uvc_hs_streaming_ep.bInterval = opts->streaming_interval; 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_ci uvc_ss_streaming_ep.wMaxPacketSize = cpu_to_le16(max_packet_size); 70362306a36Sopenharmony_ci uvc_ss_streaming_ep.bInterval = opts->streaming_interval; 70462306a36Sopenharmony_ci uvc_ss_streaming_comp.bmAttributes = max_packet_mult - 1; 70562306a36Sopenharmony_ci uvc_ss_streaming_comp.bMaxBurst = opts->streaming_maxburst; 70662306a36Sopenharmony_ci uvc_ss_streaming_comp.wBytesPerInterval = 70762306a36Sopenharmony_ci cpu_to_le16(max_packet_size * max_packet_mult * 70862306a36Sopenharmony_ci (opts->streaming_maxburst + 1)); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci /* Allocate endpoints. */ 71162306a36Sopenharmony_ci if (opts->enable_interrupt_ep) { 71262306a36Sopenharmony_ci ep = usb_ep_autoconfig(cdev->gadget, &uvc_interrupt_ep); 71362306a36Sopenharmony_ci if (!ep) { 71462306a36Sopenharmony_ci uvcg_info(f, "Unable to allocate interrupt EP\n"); 71562306a36Sopenharmony_ci goto error; 71662306a36Sopenharmony_ci } 71762306a36Sopenharmony_ci uvc->interrupt_ep = ep; 71862306a36Sopenharmony_ci uvc_control_intf.bNumEndpoints = 1; 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci uvc->enable_interrupt_ep = opts->enable_interrupt_ep; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci /* 72362306a36Sopenharmony_ci * gadget_is_{super|dual}speed() API check UDC controller capitblity. It should pass down 72462306a36Sopenharmony_ci * highest speed endpoint descriptor to UDC controller. So UDC controller driver can reserve 72562306a36Sopenharmony_ci * enough resource at check_config(), especially mult and maxburst. So UDC driver (such as 72662306a36Sopenharmony_ci * cdns3) can know need at least (mult + 1) * (maxburst + 1) * wMaxPacketSize internal 72762306a36Sopenharmony_ci * memory for this uvc functions. This is the only straightforward method to resolve the UDC 72862306a36Sopenharmony_ci * resource allocation issue in the current gadget framework. 72962306a36Sopenharmony_ci */ 73062306a36Sopenharmony_ci if (gadget_is_superspeed(c->cdev->gadget)) 73162306a36Sopenharmony_ci ep = usb_ep_autoconfig_ss(cdev->gadget, &uvc_ss_streaming_ep, 73262306a36Sopenharmony_ci &uvc_ss_streaming_comp); 73362306a36Sopenharmony_ci else if (gadget_is_dualspeed(cdev->gadget)) 73462306a36Sopenharmony_ci ep = usb_ep_autoconfig(cdev->gadget, &uvc_hs_streaming_ep); 73562306a36Sopenharmony_ci else 73662306a36Sopenharmony_ci ep = usb_ep_autoconfig(cdev->gadget, &uvc_fs_streaming_ep); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci if (!ep) { 73962306a36Sopenharmony_ci uvcg_info(f, "Unable to allocate streaming EP\n"); 74062306a36Sopenharmony_ci goto error; 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci uvc->video.ep = ep; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci uvc_fs_streaming_ep.bEndpointAddress = uvc->video.ep->address; 74562306a36Sopenharmony_ci uvc_hs_streaming_ep.bEndpointAddress = uvc->video.ep->address; 74662306a36Sopenharmony_ci uvc_ss_streaming_ep.bEndpointAddress = uvc->video.ep->address; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci /* 74962306a36Sopenharmony_ci * XUs can have an arbitrary string descriptor describing them. If they 75062306a36Sopenharmony_ci * have one pick up the ID. 75162306a36Sopenharmony_ci */ 75262306a36Sopenharmony_ci list_for_each_entry(xu, &opts->extension_units, list) 75362306a36Sopenharmony_ci if (xu->string_descriptor_index) 75462306a36Sopenharmony_ci xu->desc.iExtension = cdev->usb_strings[xu->string_descriptor_index].id; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci /* 75762306a36Sopenharmony_ci * We attach the hard-coded defaults incase the user does not provide 75862306a36Sopenharmony_ci * any more appropriate strings through configfs. 75962306a36Sopenharmony_ci */ 76062306a36Sopenharmony_ci uvc_en_us_strings[UVC_STRING_CONTROL_IDX].s = opts->function_name; 76162306a36Sopenharmony_ci us = usb_gstrings_attach(cdev, uvc_function_strings, 76262306a36Sopenharmony_ci ARRAY_SIZE(uvc_en_us_strings)); 76362306a36Sopenharmony_ci if (IS_ERR(us)) { 76462306a36Sopenharmony_ci ret = PTR_ERR(us); 76562306a36Sopenharmony_ci goto error; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci uvc_iad.iFunction = opts->iad_index ? cdev->usb_strings[opts->iad_index].id : 76962306a36Sopenharmony_ci us[UVC_STRING_CONTROL_IDX].id; 77062306a36Sopenharmony_ci uvc_streaming_intf_alt0.iInterface = opts->vs0_index ? 77162306a36Sopenharmony_ci cdev->usb_strings[opts->vs0_index].id : 77262306a36Sopenharmony_ci us[UVC_STRING_STREAMING_IDX].id; 77362306a36Sopenharmony_ci uvc_streaming_intf_alt1.iInterface = opts->vs1_index ? 77462306a36Sopenharmony_ci cdev->usb_strings[opts->vs1_index].id : 77562306a36Sopenharmony_ci us[UVC_STRING_STREAMING_IDX].id; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci /* Allocate interface IDs. */ 77862306a36Sopenharmony_ci if ((ret = usb_interface_id(c, f)) < 0) 77962306a36Sopenharmony_ci goto error; 78062306a36Sopenharmony_ci uvc_iad.bFirstInterface = ret; 78162306a36Sopenharmony_ci uvc_control_intf.bInterfaceNumber = ret; 78262306a36Sopenharmony_ci uvc->control_intf = ret; 78362306a36Sopenharmony_ci opts->control_interface = ret; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci if ((ret = usb_interface_id(c, f)) < 0) 78662306a36Sopenharmony_ci goto error; 78762306a36Sopenharmony_ci uvc_streaming_intf_alt0.bInterfaceNumber = ret; 78862306a36Sopenharmony_ci uvc_streaming_intf_alt1.bInterfaceNumber = ret; 78962306a36Sopenharmony_ci uvc->streaming_intf = ret; 79062306a36Sopenharmony_ci opts->streaming_interface = ret; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci /* Copy descriptors */ 79362306a36Sopenharmony_ci f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL); 79462306a36Sopenharmony_ci if (IS_ERR(f->fs_descriptors)) { 79562306a36Sopenharmony_ci ret = PTR_ERR(f->fs_descriptors); 79662306a36Sopenharmony_ci f->fs_descriptors = NULL; 79762306a36Sopenharmony_ci goto error; 79862306a36Sopenharmony_ci } 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH); 80162306a36Sopenharmony_ci if (IS_ERR(f->hs_descriptors)) { 80262306a36Sopenharmony_ci ret = PTR_ERR(f->hs_descriptors); 80362306a36Sopenharmony_ci f->hs_descriptors = NULL; 80462306a36Sopenharmony_ci goto error; 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER); 80862306a36Sopenharmony_ci if (IS_ERR(f->ss_descriptors)) { 80962306a36Sopenharmony_ci ret = PTR_ERR(f->ss_descriptors); 81062306a36Sopenharmony_ci f->ss_descriptors = NULL; 81162306a36Sopenharmony_ci goto error; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci /* Preallocate control endpoint request. */ 81562306a36Sopenharmony_ci uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL); 81662306a36Sopenharmony_ci uvc->control_buf = kmalloc(UVC_MAX_REQUEST_SIZE, GFP_KERNEL); 81762306a36Sopenharmony_ci if (uvc->control_req == NULL || uvc->control_buf == NULL) { 81862306a36Sopenharmony_ci ret = -ENOMEM; 81962306a36Sopenharmony_ci goto error; 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci uvc->control_req->buf = uvc->control_buf; 82362306a36Sopenharmony_ci uvc->control_req->complete = uvc_function_ep0_complete; 82462306a36Sopenharmony_ci uvc->control_req->context = uvc; 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (v4l2_device_register(&cdev->gadget->dev, &uvc->v4l2_dev)) { 82762306a36Sopenharmony_ci uvcg_err(f, "failed to register V4L2 device\n"); 82862306a36Sopenharmony_ci goto error; 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci /* Initialise video. */ 83262306a36Sopenharmony_ci ret = uvcg_video_init(&uvc->video, uvc); 83362306a36Sopenharmony_ci if (ret < 0) 83462306a36Sopenharmony_ci goto v4l2_error; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* Register a V4L2 device. */ 83762306a36Sopenharmony_ci ret = uvc_register_video(uvc); 83862306a36Sopenharmony_ci if (ret < 0) { 83962306a36Sopenharmony_ci uvcg_err(f, "failed to register video device\n"); 84062306a36Sopenharmony_ci goto v4l2_error; 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci return 0; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_civ4l2_error: 84662306a36Sopenharmony_ci v4l2_device_unregister(&uvc->v4l2_dev); 84762306a36Sopenharmony_cierror: 84862306a36Sopenharmony_ci if (uvc->control_req) 84962306a36Sopenharmony_ci usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); 85062306a36Sopenharmony_ci kfree(uvc->control_buf); 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci usb_free_all_descriptors(f); 85362306a36Sopenharmony_ci return ret; 85462306a36Sopenharmony_ci} 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci/* -------------------------------------------------------------------------- 85762306a36Sopenharmony_ci * USB gadget function 85862306a36Sopenharmony_ci */ 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_cistatic void uvc_free_inst(struct usb_function_instance *f) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci struct f_uvc_opts *opts = fi_to_f_uvc_opts(f); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci mutex_destroy(&opts->lock); 86562306a36Sopenharmony_ci kfree(opts); 86662306a36Sopenharmony_ci} 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_cistatic struct usb_function_instance *uvc_alloc_inst(void) 86962306a36Sopenharmony_ci{ 87062306a36Sopenharmony_ci struct f_uvc_opts *opts; 87162306a36Sopenharmony_ci struct uvc_camera_terminal_descriptor *cd; 87262306a36Sopenharmony_ci struct uvc_processing_unit_descriptor *pd; 87362306a36Sopenharmony_ci struct uvc_output_terminal_descriptor *od; 87462306a36Sopenharmony_ci struct uvc_descriptor_header **ctl_cls; 87562306a36Sopenharmony_ci int ret; 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci opts = kzalloc(sizeof(*opts), GFP_KERNEL); 87862306a36Sopenharmony_ci if (!opts) 87962306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 88062306a36Sopenharmony_ci opts->func_inst.free_func_inst = uvc_free_inst; 88162306a36Sopenharmony_ci mutex_init(&opts->lock); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci cd = &opts->uvc_camera_terminal; 88462306a36Sopenharmony_ci cd->bLength = UVC_DT_CAMERA_TERMINAL_SIZE(3); 88562306a36Sopenharmony_ci cd->bDescriptorType = USB_DT_CS_INTERFACE; 88662306a36Sopenharmony_ci cd->bDescriptorSubType = UVC_VC_INPUT_TERMINAL; 88762306a36Sopenharmony_ci cd->bTerminalID = 1; 88862306a36Sopenharmony_ci cd->wTerminalType = cpu_to_le16(0x0201); 88962306a36Sopenharmony_ci cd->bAssocTerminal = 0; 89062306a36Sopenharmony_ci cd->iTerminal = 0; 89162306a36Sopenharmony_ci cd->wObjectiveFocalLengthMin = cpu_to_le16(0); 89262306a36Sopenharmony_ci cd->wObjectiveFocalLengthMax = cpu_to_le16(0); 89362306a36Sopenharmony_ci cd->wOcularFocalLength = cpu_to_le16(0); 89462306a36Sopenharmony_ci cd->bControlSize = 3; 89562306a36Sopenharmony_ci cd->bmControls[0] = 2; 89662306a36Sopenharmony_ci cd->bmControls[1] = 0; 89762306a36Sopenharmony_ci cd->bmControls[2] = 0; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci pd = &opts->uvc_processing; 90062306a36Sopenharmony_ci pd->bLength = UVC_DT_PROCESSING_UNIT_SIZE(2); 90162306a36Sopenharmony_ci pd->bDescriptorType = USB_DT_CS_INTERFACE; 90262306a36Sopenharmony_ci pd->bDescriptorSubType = UVC_VC_PROCESSING_UNIT; 90362306a36Sopenharmony_ci pd->bUnitID = 2; 90462306a36Sopenharmony_ci pd->bSourceID = 1; 90562306a36Sopenharmony_ci pd->wMaxMultiplier = cpu_to_le16(16*1024); 90662306a36Sopenharmony_ci pd->bControlSize = 2; 90762306a36Sopenharmony_ci pd->bmControls[0] = 1; 90862306a36Sopenharmony_ci pd->bmControls[1] = 0; 90962306a36Sopenharmony_ci pd->iProcessing = 0; 91062306a36Sopenharmony_ci pd->bmVideoStandards = 0; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci od = &opts->uvc_output_terminal; 91362306a36Sopenharmony_ci od->bLength = UVC_DT_OUTPUT_TERMINAL_SIZE; 91462306a36Sopenharmony_ci od->bDescriptorType = USB_DT_CS_INTERFACE; 91562306a36Sopenharmony_ci od->bDescriptorSubType = UVC_VC_OUTPUT_TERMINAL; 91662306a36Sopenharmony_ci od->bTerminalID = 3; 91762306a36Sopenharmony_ci od->wTerminalType = cpu_to_le16(0x0101); 91862306a36Sopenharmony_ci od->bAssocTerminal = 0; 91962306a36Sopenharmony_ci od->bSourceID = 2; 92062306a36Sopenharmony_ci od->iTerminal = 0; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci /* 92362306a36Sopenharmony_ci * With the ability to add XUs to the UVC function graph, we need to be 92462306a36Sopenharmony_ci * able to allocate unique unit IDs to them. The IDs are 1-based, with 92562306a36Sopenharmony_ci * the CT, PU and OT above consuming the first 3. 92662306a36Sopenharmony_ci */ 92762306a36Sopenharmony_ci opts->last_unit_id = 3; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci /* Prepare fs control class descriptors for configfs-based gadgets */ 93062306a36Sopenharmony_ci ctl_cls = opts->uvc_fs_control_cls; 93162306a36Sopenharmony_ci ctl_cls[0] = NULL; /* assigned elsewhere by configfs */ 93262306a36Sopenharmony_ci ctl_cls[1] = (struct uvc_descriptor_header *)cd; 93362306a36Sopenharmony_ci ctl_cls[2] = (struct uvc_descriptor_header *)pd; 93462306a36Sopenharmony_ci ctl_cls[3] = (struct uvc_descriptor_header *)od; 93562306a36Sopenharmony_ci ctl_cls[4] = NULL; /* NULL-terminate */ 93662306a36Sopenharmony_ci opts->fs_control = 93762306a36Sopenharmony_ci (const struct uvc_descriptor_header * const *)ctl_cls; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci /* Prepare hs control class descriptors for configfs-based gadgets */ 94062306a36Sopenharmony_ci ctl_cls = opts->uvc_ss_control_cls; 94162306a36Sopenharmony_ci ctl_cls[0] = NULL; /* assigned elsewhere by configfs */ 94262306a36Sopenharmony_ci ctl_cls[1] = (struct uvc_descriptor_header *)cd; 94362306a36Sopenharmony_ci ctl_cls[2] = (struct uvc_descriptor_header *)pd; 94462306a36Sopenharmony_ci ctl_cls[3] = (struct uvc_descriptor_header *)od; 94562306a36Sopenharmony_ci ctl_cls[4] = NULL; /* NULL-terminate */ 94662306a36Sopenharmony_ci opts->ss_control = 94762306a36Sopenharmony_ci (const struct uvc_descriptor_header * const *)ctl_cls; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci INIT_LIST_HEAD(&opts->extension_units); 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci opts->streaming_interval = 1; 95262306a36Sopenharmony_ci opts->streaming_maxpacket = 1024; 95362306a36Sopenharmony_ci snprintf(opts->function_name, sizeof(opts->function_name), "UVC Camera"); 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci ret = uvcg_attach_configfs(opts); 95662306a36Sopenharmony_ci if (ret < 0) { 95762306a36Sopenharmony_ci kfree(opts); 95862306a36Sopenharmony_ci return ERR_PTR(ret); 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci return &opts->func_inst; 96262306a36Sopenharmony_ci} 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_cistatic void uvc_free(struct usb_function *f) 96562306a36Sopenharmony_ci{ 96662306a36Sopenharmony_ci struct uvc_device *uvc = to_uvc(f); 96762306a36Sopenharmony_ci struct f_uvc_opts *opts = container_of(f->fi, struct f_uvc_opts, 96862306a36Sopenharmony_ci func_inst); 96962306a36Sopenharmony_ci if (!opts->header) 97062306a36Sopenharmony_ci config_item_put(&uvc->header->item); 97162306a36Sopenharmony_ci --opts->refcnt; 97262306a36Sopenharmony_ci kfree(uvc); 97362306a36Sopenharmony_ci} 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_cistatic void uvc_function_unbind(struct usb_configuration *c, 97662306a36Sopenharmony_ci struct usb_function *f) 97762306a36Sopenharmony_ci{ 97862306a36Sopenharmony_ci struct usb_composite_dev *cdev = c->cdev; 97962306a36Sopenharmony_ci struct uvc_device *uvc = to_uvc(f); 98062306a36Sopenharmony_ci struct uvc_video *video = &uvc->video; 98162306a36Sopenharmony_ci long wait_ret = 1; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci uvcg_info(f, "%s()\n", __func__); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci if (video->async_wq) 98662306a36Sopenharmony_ci destroy_workqueue(video->async_wq); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci /* 98962306a36Sopenharmony_ci * If we know we're connected via v4l2, then there should be a cleanup 99062306a36Sopenharmony_ci * of the device from userspace either via UVC_EVENT_DISCONNECT or 99162306a36Sopenharmony_ci * though the video device removal uevent. Allow some time for the 99262306a36Sopenharmony_ci * application to close out before things get deleted. 99362306a36Sopenharmony_ci */ 99462306a36Sopenharmony_ci if (uvc->func_connected) { 99562306a36Sopenharmony_ci uvcg_dbg(f, "waiting for clean disconnect\n"); 99662306a36Sopenharmony_ci wait_ret = wait_event_interruptible_timeout(uvc->func_connected_queue, 99762306a36Sopenharmony_ci uvc->func_connected == false, msecs_to_jiffies(500)); 99862306a36Sopenharmony_ci uvcg_dbg(f, "done waiting with ret: %ld\n", wait_ret); 99962306a36Sopenharmony_ci } 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci device_remove_file(&uvc->vdev.dev, &dev_attr_function_name); 100262306a36Sopenharmony_ci video_unregister_device(&uvc->vdev); 100362306a36Sopenharmony_ci v4l2_device_unregister(&uvc->v4l2_dev); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci if (uvc->func_connected) { 100662306a36Sopenharmony_ci /* 100762306a36Sopenharmony_ci * Wait for the release to occur to ensure there are no longer any 100862306a36Sopenharmony_ci * pending operations that may cause panics when resources are cleaned 100962306a36Sopenharmony_ci * up. 101062306a36Sopenharmony_ci */ 101162306a36Sopenharmony_ci uvcg_warn(f, "%s no clean disconnect, wait for release\n", __func__); 101262306a36Sopenharmony_ci wait_ret = wait_event_interruptible_timeout(uvc->func_connected_queue, 101362306a36Sopenharmony_ci uvc->func_connected == false, msecs_to_jiffies(1000)); 101462306a36Sopenharmony_ci uvcg_dbg(f, "done waiting for release with ret: %ld\n", wait_ret); 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci usb_ep_free_request(cdev->gadget->ep0, uvc->control_req); 101862306a36Sopenharmony_ci kfree(uvc->control_buf); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci usb_free_all_descriptors(f); 102162306a36Sopenharmony_ci} 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_cistatic struct usb_function *uvc_alloc(struct usb_function_instance *fi) 102462306a36Sopenharmony_ci{ 102562306a36Sopenharmony_ci struct uvc_device *uvc; 102662306a36Sopenharmony_ci struct f_uvc_opts *opts; 102762306a36Sopenharmony_ci struct uvc_descriptor_header **strm_cls; 102862306a36Sopenharmony_ci struct config_item *streaming, *header, *h; 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ci uvc = kzalloc(sizeof(*uvc), GFP_KERNEL); 103162306a36Sopenharmony_ci if (uvc == NULL) 103262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci mutex_init(&uvc->video.mutex); 103562306a36Sopenharmony_ci uvc->state = UVC_STATE_DISCONNECTED; 103662306a36Sopenharmony_ci init_waitqueue_head(&uvc->func_connected_queue); 103762306a36Sopenharmony_ci opts = fi_to_f_uvc_opts(fi); 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci mutex_lock(&opts->lock); 104062306a36Sopenharmony_ci if (opts->uvc_fs_streaming_cls) { 104162306a36Sopenharmony_ci strm_cls = opts->uvc_fs_streaming_cls; 104262306a36Sopenharmony_ci opts->fs_streaming = 104362306a36Sopenharmony_ci (const struct uvc_descriptor_header * const *)strm_cls; 104462306a36Sopenharmony_ci } 104562306a36Sopenharmony_ci if (opts->uvc_hs_streaming_cls) { 104662306a36Sopenharmony_ci strm_cls = opts->uvc_hs_streaming_cls; 104762306a36Sopenharmony_ci opts->hs_streaming = 104862306a36Sopenharmony_ci (const struct uvc_descriptor_header * const *)strm_cls; 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci if (opts->uvc_ss_streaming_cls) { 105162306a36Sopenharmony_ci strm_cls = opts->uvc_ss_streaming_cls; 105262306a36Sopenharmony_ci opts->ss_streaming = 105362306a36Sopenharmony_ci (const struct uvc_descriptor_header * const *)strm_cls; 105462306a36Sopenharmony_ci } 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci uvc->desc.fs_control = opts->fs_control; 105762306a36Sopenharmony_ci uvc->desc.ss_control = opts->ss_control; 105862306a36Sopenharmony_ci uvc->desc.fs_streaming = opts->fs_streaming; 105962306a36Sopenharmony_ci uvc->desc.hs_streaming = opts->hs_streaming; 106062306a36Sopenharmony_ci uvc->desc.ss_streaming = opts->ss_streaming; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci if (opts->header) { 106362306a36Sopenharmony_ci uvc->header = opts->header; 106462306a36Sopenharmony_ci } else { 106562306a36Sopenharmony_ci streaming = config_group_find_item(&opts->func_inst.group, "streaming"); 106662306a36Sopenharmony_ci if (!streaming) 106762306a36Sopenharmony_ci goto err_config; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci header = config_group_find_item(to_config_group(streaming), "header"); 107062306a36Sopenharmony_ci config_item_put(streaming); 107162306a36Sopenharmony_ci if (!header) 107262306a36Sopenharmony_ci goto err_config; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci h = config_group_find_item(to_config_group(header), "h"); 107562306a36Sopenharmony_ci config_item_put(header); 107662306a36Sopenharmony_ci if (!h) 107762306a36Sopenharmony_ci goto err_config; 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci uvc->header = to_uvcg_streaming_header(h); 108062306a36Sopenharmony_ci if (!uvc->header->linked) { 108162306a36Sopenharmony_ci mutex_unlock(&opts->lock); 108262306a36Sopenharmony_ci kfree(uvc); 108362306a36Sopenharmony_ci return ERR_PTR(-EBUSY); 108462306a36Sopenharmony_ci } 108562306a36Sopenharmony_ci } 108662306a36Sopenharmony_ci 108762306a36Sopenharmony_ci uvc->desc.extension_units = &opts->extension_units; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci ++opts->refcnt; 109062306a36Sopenharmony_ci mutex_unlock(&opts->lock); 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci /* Register the function. */ 109362306a36Sopenharmony_ci uvc->func.name = "uvc"; 109462306a36Sopenharmony_ci uvc->func.bind = uvc_function_bind; 109562306a36Sopenharmony_ci uvc->func.unbind = uvc_function_unbind; 109662306a36Sopenharmony_ci uvc->func.get_alt = uvc_function_get_alt; 109762306a36Sopenharmony_ci uvc->func.set_alt = uvc_function_set_alt; 109862306a36Sopenharmony_ci uvc->func.disable = uvc_function_disable; 109962306a36Sopenharmony_ci uvc->func.setup = uvc_function_setup; 110062306a36Sopenharmony_ci uvc->func.free_func = uvc_free; 110162306a36Sopenharmony_ci uvc->func.bind_deactivated = true; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci return &uvc->func; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cierr_config: 110662306a36Sopenharmony_ci mutex_unlock(&opts->lock); 110762306a36Sopenharmony_ci kfree(uvc); 110862306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 110962306a36Sopenharmony_ci} 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ciDECLARE_USB_FUNCTION_INIT(uvc, uvc_alloc_inst, uvc_alloc); 111262306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 111362306a36Sopenharmony_ciMODULE_AUTHOR("Laurent Pinchart"); 1114