summaryrefslogtreecommitdiffstats
path: root/drivers/usb/gadget/function/f_uvc.c
diff options
context:
space:
mode:
authorAndrzej Pietrasiewicz <andrzej.p@samsung.com>2014-12-10 12:34:02 +0100
committerFelipe Balbi <balbi@ti.com>2015-01-12 12:13:26 -0600
commit46919a23ee87bbc4eeb6d958471174e26836f0e1 (patch)
treef6630c766ed3ebd0efcaf92cb04ceb105760140c /drivers/usb/gadget/function/f_uvc.c
parent6c25955ed632227d28b85db274e519b766e26ddd (diff)
downloadblackbird-op-linux-46919a23ee87bbc4eeb6d958471174e26836f0e1.tar.gz
blackbird-op-linux-46919a23ee87bbc4eeb6d958471174e26836f0e1.zip
usb: gadget: uvc: configfs support in uvc function
Add support for using the uvc function as a component of USB gadgets composed with configfs. Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Andrzej Pietrasiewicz <andrzej.p@samsung.com> Signed-off-by: Felipe Balbi <balbi@ti.com>
Diffstat (limited to 'drivers/usb/gadget/function/f_uvc.c')
-rw-r--r--drivers/usb/gadget/function/f_uvc.c106
1 files changed, 103 insertions, 3 deletions
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 62ca0c5c7f6e..76891adfba7a 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -27,10 +27,11 @@
#include <media/v4l2-dev.h>
#include <media/v4l2-event.h>
+#include "u_uvc.h"
#include "uvc.h"
+#include "uvc_configfs.h"
#include "uvc_v4l2.h"
#include "uvc_video.h"
-#include "u_uvc.h"
unsigned int uvc_gadget_trace_param;
@@ -788,25 +789,104 @@ static void uvc_free_inst(struct usb_function_instance *f)
{
struct f_uvc_opts *opts = fi_to_f_uvc_opts(f);
+ mutex_destroy(&opts->lock);
kfree(opts);
}
static struct usb_function_instance *uvc_alloc_inst(void)
{
struct f_uvc_opts *opts;
+ struct uvc_camera_terminal_descriptor *cd;
+ struct uvc_processing_unit_descriptor *pd;
+ struct uvc_output_terminal_descriptor *od;
+ struct uvc_color_matching_descriptor *md;
+ struct uvc_descriptor_header **ctl_cls;
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
return ERR_PTR(-ENOMEM);
opts->func_inst.free_func_inst = uvc_free_inst;
-
+ mutex_init(&opts->lock);
+
+ cd = &opts->uvc_camera_terminal;
+ cd->bLength = UVC_DT_CAMERA_TERMINAL_SIZE(3);
+ cd->bDescriptorType = USB_DT_CS_INTERFACE;
+ cd->bDescriptorSubType = UVC_VC_INPUT_TERMINAL;
+ cd->bTerminalID = 1;
+ cd->wTerminalType = cpu_to_le16(0x0201);
+ cd->bAssocTerminal = 0;
+ cd->iTerminal = 0;
+ cd->wObjectiveFocalLengthMin = cpu_to_le16(0);
+ cd->wObjectiveFocalLengthMax = cpu_to_le16(0);
+ cd->wOcularFocalLength = cpu_to_le16(0);
+ cd->bControlSize = 3;
+ cd->bmControls[0] = 2;
+ cd->bmControls[1] = 0;
+ cd->bmControls[2] = 0;
+
+ pd = &opts->uvc_processing;
+ pd->bLength = UVC_DT_PROCESSING_UNIT_SIZE(2);
+ pd->bDescriptorType = USB_DT_CS_INTERFACE;
+ pd->bDescriptorSubType = UVC_VC_PROCESSING_UNIT;
+ pd->bUnitID = 2;
+ pd->bSourceID = 1;
+ pd->wMaxMultiplier = cpu_to_le16(16*1024);
+ pd->bControlSize = 2;
+ pd->bmControls[0] = 1;
+ pd->bmControls[1] = 0;
+ pd->iProcessing = 0;
+
+ od = &opts->uvc_output_terminal;
+ od->bLength = UVC_DT_OUTPUT_TERMINAL_SIZE;
+ od->bDescriptorType = USB_DT_CS_INTERFACE;
+ od->bDescriptorSubType = UVC_VC_OUTPUT_TERMINAL;
+ od->bTerminalID = 3;
+ od->wTerminalType = cpu_to_le16(0x0101);
+ od->bAssocTerminal = 0;
+ od->bSourceID = 2;
+ od->iTerminal = 0;
+
+ md = &opts->uvc_color_matching;
+ md->bLength = UVC_DT_COLOR_MATCHING_SIZE;
+ md->bDescriptorType = USB_DT_CS_INTERFACE;
+ md->bDescriptorSubType = UVC_VS_COLORFORMAT;
+ md->bColorPrimaries = 1;
+ md->bTransferCharacteristics = 1;
+ md->bMatrixCoefficients = 4;
+
+ /* Prepare fs control class descriptors for configfs-based gadgets */
+ ctl_cls = opts->uvc_fs_control_cls;
+ ctl_cls[0] = NULL; /* assigned elsewhere by configfs */
+ ctl_cls[1] = (struct uvc_descriptor_header *)cd;
+ ctl_cls[2] = (struct uvc_descriptor_header *)pd;
+ ctl_cls[3] = (struct uvc_descriptor_header *)od;
+ ctl_cls[4] = NULL; /* NULL-terminate */
+ opts->fs_control =
+ (const struct uvc_descriptor_header * const *)ctl_cls;
+
+ /* Prepare hs control class descriptors for configfs-based gadgets */
+ ctl_cls = opts->uvc_ss_control_cls;
+ ctl_cls[0] = NULL; /* assigned elsewhere by configfs */
+ ctl_cls[1] = (struct uvc_descriptor_header *)cd;
+ ctl_cls[2] = (struct uvc_descriptor_header *)pd;
+ ctl_cls[3] = (struct uvc_descriptor_header *)od;
+ ctl_cls[4] = NULL; /* NULL-terminate */
+ opts->ss_control =
+ (const struct uvc_descriptor_header * const *)ctl_cls;
+
+ opts->streaming_interval = 1;
+ opts->streaming_maxpacket = 1024;
+
+ uvcg_attach_configfs(opts);
return &opts->func_inst;
}
static void uvc_free(struct usb_function *f)
{
struct uvc_device *uvc = to_uvc(f);
-
+ struct f_uvc_opts *opts = container_of(f->fi, struct f_uvc_opts,
+ func_inst);
+ --opts->refcnt;
kfree(uvc);
}
@@ -832,6 +912,7 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
{
struct uvc_device *uvc;
struct f_uvc_opts *opts;
+ struct uvc_descriptor_header **strm_cls;
uvc = kzalloc(sizeof(*uvc), GFP_KERNEL);
if (uvc == NULL)
@@ -840,11 +921,30 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
uvc->state = UVC_STATE_DISCONNECTED;
opts = fi_to_f_uvc_opts(fi);
+ mutex_lock(&opts->lock);
+ if (opts->uvc_fs_streaming_cls) {
+ strm_cls = opts->uvc_fs_streaming_cls;
+ opts->fs_streaming =
+ (const struct uvc_descriptor_header * const *)strm_cls;
+ }
+ if (opts->uvc_hs_streaming_cls) {
+ strm_cls = opts->uvc_hs_streaming_cls;
+ opts->hs_streaming =
+ (const struct uvc_descriptor_header * const *)strm_cls;
+ }
+ if (opts->uvc_ss_streaming_cls) {
+ strm_cls = opts->uvc_ss_streaming_cls;
+ opts->ss_streaming =
+ (const struct uvc_descriptor_header * const *)strm_cls;
+ }
+
uvc->desc.fs_control = opts->fs_control;
uvc->desc.ss_control = opts->ss_control;
uvc->desc.fs_streaming = opts->fs_streaming;
uvc->desc.hs_streaming = opts->hs_streaming;
uvc->desc.ss_streaming = opts->ss_streaming;
+ ++opts->refcnt;
+ mutex_unlock(&opts->lock);
/* Register the function. */
uvc->func.name = "uvc";
OpenPOWER on IntegriCloud