Xbox Live Camera on Linux (Part 3)

It seems I made an error in my initial attempt to get the exposure settings working for this camera in the uvcvideo driver. The camera appears to accept a far greater range of settings for exposure than I initially thought. After tinkering the with exposure settings for some time it seems to be the case that for values up to 25,000 the exposure setting actually represents the exposure time in units of 100μsec. Beyond that things get a bit non-linear. Whilst 25,000 looks to give an exposure time of 2.5 seconds, 25,001 suddenly jumps up to about 3.3 seconds, and by the time the setting has reached 35,000 then the exposure time is about 5 seconds. It does not appear to be able to increase the exposure time beyond five seconds, but initially that looks pretty good for a night-time sky camera.

So, my previous UVC driver patch needs modifying. Here’s the entire thing again. This time I’ve set the maximum exposure time to 50000 which seems a reasonable choice given that I can’t get exposures longer than five seconds. I’ve found it’s best to load this with the ctrltimeout and timeout parameters set to 10000. Lower values work for me for 640×480 resolution frames, but when I bumped the resolution up higher then I started getting timeouts again. Once again, be wary of whitespace changes.


--- drivers/media/video/uvc/uvc_ctrl.c~	2012-04-13 22:37:19.278971810 +0100
+++ drivers/media/video/uvc/uvc_ctrl.c	2012-04-18 13:46:46.916464906 +0100
@@ -963,9 +963,17 @@
 		v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN,
 				     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
 
-	if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX)
+	if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) {
 		v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX,
 				     uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
+		if ( v4l2_ctrl->id == V4L2_CID_EXPOSURE_ABSOLUTE &&
+				v4l2_ctrl->maximum == -1 &&
+				chain->dev->quirks &
+				UVC_QUIRK_XBOX_EXPOSURE_FIX ) {
+			uvc_trace(UVC_TRACE_CONTROL, "Xbox queryctl max exp. set to 50000.");
+			v4l2_ctrl->maximum = 50000;
+		}
+        }
 
 	if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)
 		v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
@@ -1202,6 +1210,12 @@
 				   uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
 		max = mapping->get(mapping, UVC_GET_MAX,
 				   uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
+		if ( max == -1 && xctrl->id == V4L2_CID_EXPOSURE_ABSOLUTE &&
+				chain->dev->quirks &
+				UVC_QUIRK_XBOX_EXPOSURE_FIX ) {
+			uvc_trace(UVC_TRACE_CONTROL, "Xbox max exposure set to 50000.");
+			max = 50000;
+		}
 		step = mapping->get(mapping, UVC_GET_RES,
 				    uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
 		if (step == 0)
--- drivers/media/video/uvc/uvc_driver.c~	2012-04-15 15:36:27.858728125 +0100
+++ drivers/media/video/uvc/uvc_driver.c	2012-04-13 22:29:55.556771975 +0100
@@ -47,6 +47,7 @@
 static unsigned int uvc_quirks_param = -1;
 unsigned int uvc_trace_param;
 unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT;
+unsigned int uvc_ctrl_timeout_param = UVC_CTRL_CONTROL_TIMEOUT;
 
 /* ------------------------------------------------------------------------
  * Video formats
@@ -2016,6 +2017,8 @@
 MODULE_PARM_DESC(trace, "Trace level bitmask");
 module_param_named(timeout, uvc_timeout_param, uint, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
+module_param_named(ctrltimeout, uvc_ctrl_timeout_param, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ctrltimeout, "Control control requests timeout");
 
 /* ------------------------------------------------------------------------
  * Driver initialization and cleanup
@@ -2351,6 +2354,15 @@
 	  .bInterfaceProtocol	= 0,
 	  .driver_info		= UVC_QUIRK_PROBE_MINMAX
 				| UVC_QUIRK_IGNORE_SELECTOR_UNIT },
+        /* Microsoft XBox Live USB Web Camera */
+        { .match_flags          = USB_DEVICE_ID_MATCH_DEVICE
+                                | USB_DEVICE_ID_MATCH_INT_INFO,
+          .idVendor             = 0x045e,
+          .idProduct            = 0x0294,
+          .bInterfaceClass      = USB_CLASS_VIDEO,
+          .bInterfaceSubClass   = 1,
+          .bInterfaceProtocol   = 0,
+          .driver_info          = UVC_QUIRK_XBOX_EXPOSURE_FIX },
 	/* Generic USB Video Class */
 	{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
 	{}
--- drivers/media/video/uvc/uvc_video.c~	2012-04-13 22:31:47.037324898 +0100
+++ drivers/media/video/uvc/uvc_video.c	2012-04-13 22:31:04.009110557 +0100
@@ -75,7 +75,7 @@
 	int ret;
 
 	ret = __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size,
-				UVC_CTRL_CONTROL_TIMEOUT);
+				uvc_ctrl_timeout_param);
 	if (ret != size) {
 		uvc_printk(KERN_ERR, "Failed to query (%s) UVC control %u on "
 			"unit %u: %d (exp. %u).\n", uvc_query_name(query), cs,
--- drivers/media/video/uvc/uvcvideo.h~	2012-04-13 22:27:33.248066424 +0100
+++ drivers/media/video/uvc/uvcvideo.h	2012-04-13 22:39:23.599589380 +0100
@@ -212,6 +212,7 @@
 #define UVC_QUIRK_FIX_BANDWIDTH		0x00000080
 #define UVC_QUIRK_PROBE_DEF		0x00000100
 #define UVC_QUIRK_RESTRICT_FRAME_RATE	0x00000200
+#define UVC_QUIRK_XBOX_EXPOSURE_FIX	0x00000400
 
 /* Format flags */
 #define UVC_FMT_FLAG_COMPRESSED		0x00000001
@@ -575,6 +576,7 @@
 extern unsigned int uvc_no_drop_param;
 extern unsigned int uvc_trace_param;
 extern unsigned int uvc_timeout_param;
+extern unsigned int uvc_ctrl_timeout_param;
 
 #define uvc_trace(flag, msg...) \
This entry was posted in Astroimaging, Astronomy, Computing, Linux. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *