From a16d2c044f5e8bf9fc16727d2c6a6055812b366c Mon Sep 17 00:00:00 2001
From: Arne Caspari <arne@unicap-imaging.org>
Date: Sat, 30 Jul 2011 13:29:11 +0200
Subject: [PATCH 1/4] [media] uvcvideo: Detect The Imaging Source CCD cameras by vendor and product ID

The Imaging Source CCD cameras use a vendor specific interface class
even though they are actually UVC compliant.
---
 drivers/media/video/uvc/uvc_driver.c |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index d29f9c2..339ded4 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -2361,6 +2361,14 @@ static struct usb_device_id uvc_ids[] = {
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_QUIRK_PROBE_MINMAX
 				| UVC_QUIRK_IGNORE_SELECTOR_UNIT },
+	/* The Imaging Source USB CCD cameras */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x199e,
+	  .idProduct		= 0x8102,
+	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0 },
 	/* Generic USB Video Class */
 	{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
 	{}
-- 
1.7.4.1


From 96d8892518c9b67e0cacd65e1957485f8a28b7b2 Mon Sep 17 00:00:00 2001
From: Arne Caspari <arne@unicap-imaging.org>
Date: Sat, 30 Jul 2011 13:51:56 +0200
Subject: [PATCH 2/4] [media] uvcvideo: Add support for The Imaging Source Dxx21UC04 cameras

The Imaging Source CMOS cameras are almost UVC compliant, but not quite.
They report a broken video format descriptor which announces YUV formats
of half the actual size. The correct formats would be BY8 and Y800 twice
the sice reported by the descriptor. Also the only functional format index
of the two reported is 1 - the other one will yield video data with an
incorrect byte order.

This patch maps the video formats of the camera to BY8 and Y800 and fixes
the width. For this, a new quirk UVC_QUIRK_TIS_RAW_CMOS is introduced.
---
 drivers/media/video/uvc/uvc_driver.c |   34 ++++++++++++++++++++++++++++++++--
 drivers/media/video/uvc/uvc_video.c  |    7 ++++++-
 drivers/media/video/uvc/uvcvideo.h   |    1 +
 3 files changed, 39 insertions(+), 3 deletions(-)

diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 339ded4..ff7719e 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -322,8 +322,20 @@ static int uvc_parse_format(struct uvc_device *dev,
 			return -EINVAL;
 		}
 
-		/* Find the format descriptor from its GUID. */
-		fmtdesc = uvc_format_by_guid(&buffer[5]);
+		if (dev->quirks & UVC_QUIRK_TIS_RAW_CMOS){
+			__u8 guid_by8[] = UVC_GUID_FORMAT_BY8;
+			__u8 guid_mono[] = UVC_GUID_FORMAT_Y800;
+			__u8 guid_uyvy[] = UVC_GUID_FORMAT_UYVY;
+			__u8 *guid = guid_mono;
+			if (memcmp (&buffer[5], guid_uyvy, 16))
+				guid = guid_by8;
+			/* The Imaging Source CMOS cameras always output
+			   RAW Bayer data, regardles of the descriptor */
+			fmtdesc = uvc_format_by_guid(guid);
+		} else {
+			/* Find the format descriptor from its GUID. */
+			fmtdesc = uvc_format_by_guid(&buffer[5]);
+		}
 
 		if (fmtdesc != NULL) {
 			strlcpy(format->name, fmtdesc->name,
@@ -447,6 +459,14 @@ static int uvc_parse_format(struct uvc_device *dev,
 		frame->bFrameIndex = buffer[3];
 		frame->bmCapabilities = buffer[4];
 		frame->wWidth = get_unaligned_le16(&buffer[5]);
+		if (dev->quirks & UVC_QUIRK_TIS_RAW_CMOS){
+			/* TIS CMOS camera report a broken video format
+			   descriptor. It reports an UYVY format with
+			   half the actual width whereas the actual video 
+			   format is 8-bit RGB Bayer ( or 8-bit Monochrome )
+			 */
+			frame->wWidth *= 2;
+		}
 		frame->wHeight = get_unaligned_le16(&buffer[7]);
 		frame->dwMinBitRate = get_unaligned_le32(&buffer[9]);
 		frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]);
@@ -2369,6 +2389,16 @@ static struct usb_device_id uvc_ids[] = {
 	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0 },
+	/* The Imaging Source USB CMOS cameras */
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x199e,
+	  .idProduct		= 0x8202,
+	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0, 
+	  .driver_info          = UVC_QUIRK_TIS_RAW_CMOS },
+	
 	/* Generic USB Video Class */
 	{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
 	{}
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 8244167..85d19cb 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -256,7 +256,12 @@ static int uvc_set_video_ctrl(struct uvc_streaming *stream,
 		return -ENOMEM;
 
 	*(__le16 *)&data[0] = cpu_to_le16(ctrl->bmHint);
-	data[2] = ctrl->bFormatIndex;
+	if (stream->dev->quirks & UVC_QUIRK_TIS_RAW_CMOS){
+		/* 1 is the only correctly working format*/
+		data[2] = 1;
+	} else {
+		data[2] = ctrl->bFormatIndex;
+	}
 	data[3] = ctrl->bFrameIndex;
 	*(__le32 *)&data[4] = cpu_to_le32(ctrl->dwFrameInterval);
 	*(__le16 *)&data[8] = cpu_to_le16(ctrl->wKeyFrameRate);
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index df32a43..ad4eeb7 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -210,6 +210,7 @@ struct uvc_xu_control {
 #define UVC_QUIRK_FIX_BANDWIDTH		0x00000080
 #define UVC_QUIRK_PROBE_DEF		0x00000100
 #define UVC_QUIRK_RESTRICT_FRAME_RATE	0x00000200
+#define UVC_QUIRK_TIS_RAW_CMOS          0x00000800
 
 /* Format flags */
 #define UVC_FMT_FLAG_COMPRESSED		0x00000001
-- 
1.7.4.1


From eba9289588ae1b268e70e34b41cbbfeca1d3c2e0 Mon Sep 17 00:00:00 2001
From: Arne Caspari <arne@unicap-imaging.org>
Date: Sat, 30 Jul 2011 19:34:48 +0200
Subject: [PATCH 3/4] [media] uvcvideo: Add support for Dxx72UC

---
 drivers/media/video/uvc/uvc_driver.c |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index ff7719e..047494c 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -2398,6 +2398,14 @@ static struct usb_device_id uvc_ids[] = {
 	  .bInterfaceSubClass	= 1,
 	  .bInterfaceProtocol	= 0, 
 	  .driver_info          = UVC_QUIRK_TIS_RAW_CMOS },
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE
+				| USB_DEVICE_ID_MATCH_INT_INFO,
+	  .idVendor		= 0x199e,
+	  .idProduct		= 0x8207,
+	  .bInterfaceClass	= USB_CLASS_VENDOR_SPEC,
+	  .bInterfaceSubClass	= 1,
+	  .bInterfaceProtocol	= 0, 
+	  .driver_info          = UVC_QUIRK_TIS_RAW_CMOS },
 	
 	/* Generic USB Video Class */
 	{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
-- 
1.7.4.1


From 85c70002572f339ff1af48477cde2006a02c9815 Mon Sep 17 00:00:00 2001
From: Arne Caspari <arne@unicap-imaging.org>
Date: Sat, 30 Jul 2011 19:36:45 +0200
Subject: [PATCH 4/4] [media] uvcvideo: Add Pixel Clock control for TIS CMOS cameras

---
 drivers/media/video/uvc/uvc_ctrl.c |   51 +++++++++++++++++++++++++++++++++++-
 1 files changed, 50 insertions(+), 1 deletions(-)

diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index 10c2364..f808a2b 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -32,6 +32,9 @@
 #define UVC_CTRL_DATA_DEF	5
 #define UVC_CTRL_DATA_LAST	6
 
+#define UVC_TIS_CT_PIXEL_CLOCK  0x24
+
+
 /* ------------------------------------------------------------------------
  * Controls
  */
@@ -350,6 +353,17 @@ static struct uvc_control_info uvc_ctrls[] = {
 				| UVC_CTRL_FLAG_RESTORE
 				| UVC_CTRL_FLAG_AUTO_UPDATE,
 	},
+
+	{
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= UVC_TIS_CT_PIXEL_CLOCK,
+		.index		= 19,
+		.size		= 4,
+		.flags		= UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
+		                | UVC_CTRL_FLAG_GET_RANGE
+				| UVC_CTRL_FLAG_RESTORE
+				| UVC_CTRL_FLAG_AUTO_UPDATE,
+	},
 };
 
 static struct uvc_menu_info power_line_frequency_controls[] = {
@@ -667,6 +681,16 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
 		.v4l2_type	= V4L2_CTRL_TYPE_BOOLEAN,
 		.data_type	= UVC_CTRL_DATA_TYPE_BOOLEAN,
 	},
+	{
+		.id		= V4L2_CID_USER_BASE + 0,
+		.name		= "Pixel Clock",
+		.entity		= UVC_GUID_UVC_CAMERA,
+		.selector	= UVC_TIS_CT_PIXEL_CLOCK,
+		.size		= 4,
+		.offset		= 0,
+		.v4l2_type	= V4L2_CTRL_TYPE_INTEGER,
+		.data_type	= UVC_CTRL_DATA_TYPE_UNSIGNED,
+	},
 };
 
 /* ------------------------------------------------------------------------
@@ -971,6 +995,16 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
 		v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
 				  uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
 
+
+	if ((chain->dev->quirks & UVC_QUIRK_TIS_RAW_CMOS) && (v4l2_ctrl->id == V4L2_CID_USER_BASE)){
+		/*
+		  TIS CMOS pixel clock control has no valid range
+		 */
+		v4l2_ctrl->minimum = 5000000;
+		v4l2_ctrl->maximum = 42000000;
+		v4l2_ctrl->step = 1000000;
+	}
+	
 done:
 	mutex_unlock(&chain->ctrl_mutex);
 	return ret;
@@ -1204,6 +1238,16 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
 				   uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
 		step = mapping->get(mapping, UVC_GET_RES,
 				    uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
+
+		if ((chain->dev->quirks & UVC_QUIRK_TIS_RAW_CMOS) && (mapping->id == V4L2_CID_USER_BASE)){
+			/*
+			  TIS CMOS pixel clock control has no valid range
+			*/
+			min = 5000000;
+			max = 42000000;
+			step = 1000000;
+		}
+		
 		if (step == 0)
 			step = 1;
 
@@ -1859,6 +1903,9 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
 		if (ncontrols == 0)
 			continue;
 
+		if (dev->quirks & UVC_QUIRK_TIS_RAW_CMOS)
+			ncontrols++;
+
 		entity->controls = kzalloc(ncontrols * sizeof(*ctrl),
 					   GFP_KERNEL);
 		if (entity->controls == NULL)
@@ -1868,7 +1915,9 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
 		/* Initialize all supported controls */
 		ctrl = entity->controls;
 		for (i = 0; i < bControlSize * 8; ++i) {
-			if (uvc_test_bit(bmControls, i) == 0)
+			if ((uvc_test_bit(bmControls, i) == 0) && !(
+				    (dev->quirks & UVC_QUIRK_TIS_RAW_CMOS) &&
+				    (i == 19)))
 				continue;
 
 			ctrl->entity = entity;
-- 
1.7.4.1


