You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by ph...@apache.org on 2017/11/08 20:32:58 UTC

[3/9] nifi-minifi-cpp git commit: MINIFICPP-283 Created a USB camera sensor processor

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/2d9e5719/thirdparty/libuvc-0.0.6/src/ctrl-gen.c
----------------------------------------------------------------------
diff --git a/thirdparty/libuvc-0.0.6/src/ctrl-gen.c b/thirdparty/libuvc-0.0.6/src/ctrl-gen.c
new file mode 100644
index 0000000..30c0ab6
--- /dev/null
+++ b/thirdparty/libuvc-0.0.6/src/ctrl-gen.c
@@ -0,0 +1,2259 @@
+/* This is an AUTO-GENERATED file! Update it with the output of `ctrl-gen.py def`. */
+#include "libuvc/libuvc.h"
+#include "libuvc/libuvc_internal.h"
+
+static const int REQ_TYPE_SET = 0x21;
+static const int REQ_TYPE_GET = 0xa1;
+
+/** @ingroup ctrl
+ * @brief Reads the SCANNING_MODE control.
+ * @param devh UVC device handle
+ * @param[out] mode 0: interlaced, 1: progressive
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_scanning_mode(uvc_device_handle_t *devh, uint8_t* mode, enum uvc_req_code req_code) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_CT_SCANNING_MODE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *mode = data[0];
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the SCANNING_MODE control.
+ * @param devh UVC device handle
+ * @param mode 0: interlaced, 1: progressive
+ */
+uvc_error_t uvc_set_scanning_mode(uvc_device_handle_t *devh, uint8_t mode) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  data[0] = mode;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_CT_SCANNING_MODE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads camera's auto-exposure mode.
+ * 
+ * See uvc_set_ae_mode() for a description of the available modes.
+ * @param devh UVC device handle
+ * @param[out] mode 1: manual mode; 2: auto mode; 4: shutter priority mode; 8: aperture priority mode
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_ae_mode(uvc_device_handle_t *devh, uint8_t* mode, enum uvc_req_code req_code) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_CT_AE_MODE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *mode = data[0];
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets camera's auto-exposure mode.
+ * 
+ * Cameras may support any of the following AE modes:
+ *  * UVC_AUTO_EXPOSURE_MODE_MANUAL (1) - manual exposure time, manual iris
+ *  * UVC_AUTO_EXPOSURE_MODE_AUTO (2) - auto exposure time, auto iris
+ *  * UVC_AUTO_EXPOSURE_MODE_SHUTTER_PRIORITY (4) - manual exposure time, auto iris
+ *  * UVC_AUTO_EXPOSURE_MODE_APERTURE_PRIORITY (8) - auto exposure time, manual iris
+ * 
+ * Most cameras provide manual mode and aperture priority mode.
+ * @param devh UVC device handle
+ * @param mode 1: manual mode; 2: auto mode; 4: shutter priority mode; 8: aperture priority mode
+ */
+uvc_error_t uvc_set_ae_mode(uvc_device_handle_t *devh, uint8_t mode) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  data[0] = mode;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_CT_AE_MODE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Checks whether the camera may vary the frame rate for exposure control reasons.
+ * See uvc_set_ae_priority() for a description of the `priority` field.
+ * @param devh UVC device handle
+ * @param[out] priority 0: frame rate must remain constant; 1: frame rate may be varied for AE purposes
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_ae_priority(uvc_device_handle_t *devh, uint8_t* priority, enum uvc_req_code req_code) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_CT_AE_PRIORITY_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *priority = data[0];
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Chooses whether the camera may vary the frame rate for exposure control reasons.
+ * A `priority` value of zero means the camera may not vary its frame rate. A value of 1
+ * means the frame rate is variable. This setting has no effect outside of the `auto` and
+ * `shutter_priority` auto-exposure modes.
+ * @param devh UVC device handle
+ * @param priority 0: frame rate must remain constant; 1: frame rate may be varied for AE purposes
+ */
+uvc_error_t uvc_set_ae_priority(uvc_device_handle_t *devh, uint8_t priority) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  data[0] = priority;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_CT_AE_PRIORITY_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Gets the absolute exposure time.
+ * 
+ * See uvc_set_exposure_abs() for a description of the `time` field.
+ * @param devh UVC device handle
+ * @param[out] time 
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_exposure_abs(uvc_device_handle_t *devh, uint32_t* time, enum uvc_req_code req_code) {
+  uint8_t data[4];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *time = DW_TO_INT(data + 0);
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the absolute exposure time.
+ * 
+ * The `time` parameter should be provided in units of 0.0001 seconds (e.g., use the value 100
+ * for a 10ms exposure period). Auto exposure should be set to `manual` or `shutter_priority`
+ * before attempting to change this setting.
+ * @param devh UVC device handle
+ * @param time 
+ */
+uvc_error_t uvc_set_exposure_abs(uvc_device_handle_t *devh, uint32_t time) {
+  uint8_t data[4];
+  uvc_error_t ret;
+
+  INT_TO_DW(time, data + 0);
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the exposure time relative to the current setting.
+ * @param devh UVC device handle
+ * @param[out] step number of steps by which to change the exposure time, or zero to set the default exposure time
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_exposure_rel(uvc_device_handle_t *devh, int8_t* step, enum uvc_req_code req_code) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *step = data[0];
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the exposure time relative to the current setting.
+ * @param devh UVC device handle
+ * @param step number of steps by which to change the exposure time, or zero to set the default exposure time
+ */
+uvc_error_t uvc_set_exposure_rel(uvc_device_handle_t *devh, int8_t step) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  data[0] = step;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the distance at which an object is optimally focused.
+ * @param devh UVC device handle
+ * @param[out] focus focal target distance in millimeters
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_focus_abs(uvc_device_handle_t *devh, uint16_t* focus, enum uvc_req_code req_code) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_CT_FOCUS_ABSOLUTE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *focus = SW_TO_SHORT(data + 0);
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the distance at which an object is optimally focused.
+ * @param devh UVC device handle
+ * @param focus focal target distance in millimeters
+ */
+uvc_error_t uvc_set_focus_abs(uvc_device_handle_t *devh, uint16_t focus) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  SHORT_TO_SW(focus, data + 0);
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_CT_FOCUS_ABSOLUTE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the FOCUS_RELATIVE control.
+ * @param devh UVC device handle
+ * @param[out] focus_rel TODO
+ * @param[out] speed TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_focus_rel(uvc_device_handle_t *devh, int8_t* focus_rel, uint8_t* speed, enum uvc_req_code req_code) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_CT_FOCUS_RELATIVE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *focus_rel = data[0];
+    *speed = data[1];
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the FOCUS_RELATIVE control.
+ * @param devh UVC device handle
+ * @param focus_rel TODO
+ * @param speed TODO
+ */
+uvc_error_t uvc_set_focus_rel(uvc_device_handle_t *devh, int8_t focus_rel, uint8_t speed) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  data[0] = focus_rel;
+  data[1] = speed;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_CT_FOCUS_RELATIVE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the FOCUS_SIMPLE control.
+ * @param devh UVC device handle
+ * @param[out] focus TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_focus_simple_range(uvc_device_handle_t *devh, uint8_t* focus, enum uvc_req_code req_code) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_CT_FOCUS_SIMPLE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *focus = data[0];
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the FOCUS_SIMPLE control.
+ * @param devh UVC device handle
+ * @param focus TODO
+ */
+uvc_error_t uvc_set_focus_simple_range(uvc_device_handle_t *devh, uint8_t focus) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  data[0] = focus;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_CT_FOCUS_SIMPLE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the FOCUS_AUTO control.
+ * @param devh UVC device handle
+ * @param[out] state TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_focus_auto(uvc_device_handle_t *devh, uint8_t* state, enum uvc_req_code req_code) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_CT_FOCUS_AUTO_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *state = data[0];
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the FOCUS_AUTO control.
+ * @param devh UVC device handle
+ * @param state TODO
+ */
+uvc_error_t uvc_set_focus_auto(uvc_device_handle_t *devh, uint8_t state) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  data[0] = state;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_CT_FOCUS_AUTO_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the IRIS_ABSOLUTE control.
+ * @param devh UVC device handle
+ * @param[out] iris TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_iris_abs(uvc_device_handle_t *devh, uint16_t* iris, enum uvc_req_code req_code) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_CT_IRIS_ABSOLUTE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *iris = SW_TO_SHORT(data + 0);
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the IRIS_ABSOLUTE control.
+ * @param devh UVC device handle
+ * @param iris TODO
+ */
+uvc_error_t uvc_set_iris_abs(uvc_device_handle_t *devh, uint16_t iris) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  SHORT_TO_SW(iris, data + 0);
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_CT_IRIS_ABSOLUTE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the IRIS_RELATIVE control.
+ * @param devh UVC device handle
+ * @param[out] iris_rel TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_iris_rel(uvc_device_handle_t *devh, uint8_t* iris_rel, enum uvc_req_code req_code) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_CT_IRIS_RELATIVE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *iris_rel = data[0];
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the IRIS_RELATIVE control.
+ * @param devh UVC device handle
+ * @param iris_rel TODO
+ */
+uvc_error_t uvc_set_iris_rel(uvc_device_handle_t *devh, uint8_t iris_rel) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  data[0] = iris_rel;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_CT_IRIS_RELATIVE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the ZOOM_ABSOLUTE control.
+ * @param devh UVC device handle
+ * @param[out] focal_length TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_zoom_abs(uvc_device_handle_t *devh, uint16_t* focal_length, enum uvc_req_code req_code) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_CT_ZOOM_ABSOLUTE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *focal_length = SW_TO_SHORT(data + 0);
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the ZOOM_ABSOLUTE control.
+ * @param devh UVC device handle
+ * @param focal_length TODO
+ */
+uvc_error_t uvc_set_zoom_abs(uvc_device_handle_t *devh, uint16_t focal_length) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  SHORT_TO_SW(focal_length, data + 0);
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_CT_ZOOM_ABSOLUTE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the ZOOM_RELATIVE control.
+ * @param devh UVC device handle
+ * @param[out] zoom_rel TODO
+ * @param[out] digital_zoom TODO
+ * @param[out] speed TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_zoom_rel(uvc_device_handle_t *devh, int8_t* zoom_rel, uint8_t* digital_zoom, uint8_t* speed, enum uvc_req_code req_code) {
+  uint8_t data[3];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_CT_ZOOM_RELATIVE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *zoom_rel = data[0];
+    *digital_zoom = data[1];
+    *speed = data[2];
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the ZOOM_RELATIVE control.
+ * @param devh UVC device handle
+ * @param zoom_rel TODO
+ * @param digital_zoom TODO
+ * @param speed TODO
+ */
+uvc_error_t uvc_set_zoom_rel(uvc_device_handle_t *devh, int8_t zoom_rel, uint8_t digital_zoom, uint8_t speed) {
+  uint8_t data[3];
+  uvc_error_t ret;
+
+  data[0] = zoom_rel;
+  data[1] = digital_zoom;
+  data[2] = speed;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_CT_ZOOM_RELATIVE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the PANTILT_ABSOLUTE control.
+ * @param devh UVC device handle
+ * @param[out] pan TODO
+ * @param[out] tilt TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_pantilt_abs(uvc_device_handle_t *devh, int32_t* pan, int32_t* tilt, enum uvc_req_code req_code) {
+  uint8_t data[8];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_CT_PANTILT_ABSOLUTE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *pan = DW_TO_INT(data + 0);
+    *tilt = DW_TO_INT(data + 4);
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the PANTILT_ABSOLUTE control.
+ * @param devh UVC device handle
+ * @param pan TODO
+ * @param tilt TODO
+ */
+uvc_error_t uvc_set_pantilt_abs(uvc_device_handle_t *devh, int32_t pan, int32_t tilt) {
+  uint8_t data[8];
+  uvc_error_t ret;
+
+  INT_TO_DW(pan, data + 0);
+  INT_TO_DW(tilt, data + 4);
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_CT_PANTILT_ABSOLUTE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the PANTILT_RELATIVE control.
+ * @param devh UVC device handle
+ * @param[out] pan_rel TODO
+ * @param[out] pan_speed TODO
+ * @param[out] tilt_rel TODO
+ * @param[out] tilt_speed TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_pantilt_rel(uvc_device_handle_t *devh, int8_t* pan_rel, uint8_t* pan_speed, int8_t* tilt_rel, uint8_t* tilt_speed, enum uvc_req_code req_code) {
+  uint8_t data[4];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_CT_PANTILT_RELATIVE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *pan_rel = data[0];
+    *pan_speed = data[1];
+    *tilt_rel = data[2];
+    *tilt_speed = data[3];
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the PANTILT_RELATIVE control.
+ * @param devh UVC device handle
+ * @param pan_rel TODO
+ * @param pan_speed TODO
+ * @param tilt_rel TODO
+ * @param tilt_speed TODO
+ */
+uvc_error_t uvc_set_pantilt_rel(uvc_device_handle_t *devh, int8_t pan_rel, uint8_t pan_speed, int8_t tilt_rel, uint8_t tilt_speed) {
+  uint8_t data[4];
+  uvc_error_t ret;
+
+  data[0] = pan_rel;
+  data[1] = pan_speed;
+  data[2] = tilt_rel;
+  data[3] = tilt_speed;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_CT_PANTILT_RELATIVE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the ROLL_ABSOLUTE control.
+ * @param devh UVC device handle
+ * @param[out] roll TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_roll_abs(uvc_device_handle_t *devh, int16_t* roll, enum uvc_req_code req_code) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_CT_ROLL_ABSOLUTE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *roll = SW_TO_SHORT(data + 0);
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the ROLL_ABSOLUTE control.
+ * @param devh UVC device handle
+ * @param roll TODO
+ */
+uvc_error_t uvc_set_roll_abs(uvc_device_handle_t *devh, int16_t roll) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  SHORT_TO_SW(roll, data + 0);
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_CT_ROLL_ABSOLUTE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the ROLL_RELATIVE control.
+ * @param devh UVC device handle
+ * @param[out] roll_rel TODO
+ * @param[out] speed TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_roll_rel(uvc_device_handle_t *devh, int8_t* roll_rel, uint8_t* speed, enum uvc_req_code req_code) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_CT_ROLL_RELATIVE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *roll_rel = data[0];
+    *speed = data[1];
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the ROLL_RELATIVE control.
+ * @param devh UVC device handle
+ * @param roll_rel TODO
+ * @param speed TODO
+ */
+uvc_error_t uvc_set_roll_rel(uvc_device_handle_t *devh, int8_t roll_rel, uint8_t speed) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  data[0] = roll_rel;
+  data[1] = speed;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_CT_ROLL_RELATIVE_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the PRIVACY control.
+ * @param devh UVC device handle
+ * @param[out] privacy TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_privacy(uvc_device_handle_t *devh, uint8_t* privacy, enum uvc_req_code req_code) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_CT_PRIVACY_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *privacy = data[0];
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the PRIVACY control.
+ * @param devh UVC device handle
+ * @param privacy TODO
+ */
+uvc_error_t uvc_set_privacy(uvc_device_handle_t *devh, uint8_t privacy) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  data[0] = privacy;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_CT_PRIVACY_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the DIGITAL_WINDOW control.
+ * @param devh UVC device handle
+ * @param[out] window_top TODO
+ * @param[out] window_left TODO
+ * @param[out] window_bottom TODO
+ * @param[out] window_right TODO
+ * @param[out] num_steps TODO
+ * @param[out] num_steps_units TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_digital_window(uvc_device_handle_t *devh, uint16_t* window_top, uint16_t* window_left, uint16_t* window_bottom, uint16_t* window_right, uint16_t* num_steps, uint16_t* num_steps_units, enum uvc_req_code req_code) {
+  uint8_t data[12];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_CT_DIGITAL_WINDOW_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *window_top = SW_TO_SHORT(data + 0);
+    *window_left = SW_TO_SHORT(data + 2);
+    *window_bottom = SW_TO_SHORT(data + 4);
+    *window_right = SW_TO_SHORT(data + 6);
+    *num_steps = SW_TO_SHORT(data + 8);
+    *num_steps_units = SW_TO_SHORT(data + 10);
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the DIGITAL_WINDOW control.
+ * @param devh UVC device handle
+ * @param window_top TODO
+ * @param window_left TODO
+ * @param window_bottom TODO
+ * @param window_right TODO
+ * @param num_steps TODO
+ * @param num_steps_units TODO
+ */
+uvc_error_t uvc_set_digital_window(uvc_device_handle_t *devh, uint16_t window_top, uint16_t window_left, uint16_t window_bottom, uint16_t window_right, uint16_t num_steps, uint16_t num_steps_units) {
+  uint8_t data[12];
+  uvc_error_t ret;
+
+  SHORT_TO_SW(window_top, data + 0);
+  SHORT_TO_SW(window_left, data + 2);
+  SHORT_TO_SW(window_bottom, data + 4);
+  SHORT_TO_SW(window_right, data + 6);
+  SHORT_TO_SW(num_steps, data + 8);
+  SHORT_TO_SW(num_steps_units, data + 10);
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_CT_DIGITAL_WINDOW_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the REGION_OF_INTEREST control.
+ * @param devh UVC device handle
+ * @param[out] roi_top TODO
+ * @param[out] roi_left TODO
+ * @param[out] roi_bottom TODO
+ * @param[out] roi_right TODO
+ * @param[out] auto_controls TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_digital_roi(uvc_device_handle_t *devh, uint16_t* roi_top, uint16_t* roi_left, uint16_t* roi_bottom, uint16_t* roi_right, uint16_t* auto_controls, enum uvc_req_code req_code) {
+  uint8_t data[10];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_CT_REGION_OF_INTEREST_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *roi_top = SW_TO_SHORT(data + 0);
+    *roi_left = SW_TO_SHORT(data + 2);
+    *roi_bottom = SW_TO_SHORT(data + 4);
+    *roi_right = SW_TO_SHORT(data + 6);
+    *auto_controls = SW_TO_SHORT(data + 8);
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the REGION_OF_INTEREST control.
+ * @param devh UVC device handle
+ * @param roi_top TODO
+ * @param roi_left TODO
+ * @param roi_bottom TODO
+ * @param roi_right TODO
+ * @param auto_controls TODO
+ */
+uvc_error_t uvc_set_digital_roi(uvc_device_handle_t *devh, uint16_t roi_top, uint16_t roi_left, uint16_t roi_bottom, uint16_t roi_right, uint16_t auto_controls) {
+  uint8_t data[10];
+  uvc_error_t ret;
+
+  SHORT_TO_SW(roi_top, data + 0);
+  SHORT_TO_SW(roi_left, data + 2);
+  SHORT_TO_SW(roi_bottom, data + 4);
+  SHORT_TO_SW(roi_right, data + 6);
+  SHORT_TO_SW(auto_controls, data + 8);
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_CT_REGION_OF_INTEREST_CONTROL << 8,
+    uvc_get_camera_terminal(devh)->bTerminalID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the BACKLIGHT_COMPENSATION control.
+ * @param devh UVC device handle
+ * @param[out] backlight_compensation device-dependent backlight compensation mode; zero means backlight compensation is disabled
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_backlight_compensation(uvc_device_handle_t *devh, uint16_t* backlight_compensation, enum uvc_req_code req_code) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_PU_BACKLIGHT_COMPENSATION_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *backlight_compensation = SW_TO_SHORT(data + 0);
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the BACKLIGHT_COMPENSATION control.
+ * @param devh UVC device handle
+ * @param backlight_compensation device-dependent backlight compensation mode; zero means backlight compensation is disabled
+ */
+uvc_error_t uvc_set_backlight_compensation(uvc_device_handle_t *devh, uint16_t backlight_compensation) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  SHORT_TO_SW(backlight_compensation, data + 0);
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_PU_BACKLIGHT_COMPENSATION_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the BRIGHTNESS control.
+ * @param devh UVC device handle
+ * @param[out] brightness TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_brightness(uvc_device_handle_t *devh, int16_t* brightness, enum uvc_req_code req_code) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_PU_BRIGHTNESS_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *brightness = SW_TO_SHORT(data + 0);
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the BRIGHTNESS control.
+ * @param devh UVC device handle
+ * @param brightness TODO
+ */
+uvc_error_t uvc_set_brightness(uvc_device_handle_t *devh, int16_t brightness) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  SHORT_TO_SW(brightness, data + 0);
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_PU_BRIGHTNESS_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the CONTRAST control.
+ * @param devh UVC device handle
+ * @param[out] contrast TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_contrast(uvc_device_handle_t *devh, uint16_t* contrast, enum uvc_req_code req_code) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_PU_CONTRAST_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *contrast = SW_TO_SHORT(data + 0);
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the CONTRAST control.
+ * @param devh UVC device handle
+ * @param contrast TODO
+ */
+uvc_error_t uvc_set_contrast(uvc_device_handle_t *devh, uint16_t contrast) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  SHORT_TO_SW(contrast, data + 0);
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_PU_CONTRAST_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the CONTRAST_AUTO control.
+ * @param devh UVC device handle
+ * @param[out] contrast_auto TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_contrast_auto(uvc_device_handle_t *devh, uint8_t* contrast_auto, enum uvc_req_code req_code) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_PU_CONTRAST_AUTO_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *contrast_auto = data[0];
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the CONTRAST_AUTO control.
+ * @param devh UVC device handle
+ * @param contrast_auto TODO
+ */
+uvc_error_t uvc_set_contrast_auto(uvc_device_handle_t *devh, uint8_t contrast_auto) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  data[0] = contrast_auto;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_PU_CONTRAST_AUTO_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the GAIN control.
+ * @param devh UVC device handle
+ * @param[out] gain TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_gain(uvc_device_handle_t *devh, uint16_t* gain, enum uvc_req_code req_code) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_PU_GAIN_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *gain = SW_TO_SHORT(data + 0);
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the GAIN control.
+ * @param devh UVC device handle
+ * @param gain TODO
+ */
+uvc_error_t uvc_set_gain(uvc_device_handle_t *devh, uint16_t gain) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  SHORT_TO_SW(gain, data + 0);
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_PU_GAIN_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the POWER_LINE_FREQUENCY control.
+ * @param devh UVC device handle
+ * @param[out] power_line_frequency TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_power_line_frequency(uvc_device_handle_t *devh, uint8_t* power_line_frequency, enum uvc_req_code req_code) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_PU_POWER_LINE_FREQUENCY_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *power_line_frequency = data[0];
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the POWER_LINE_FREQUENCY control.
+ * @param devh UVC device handle
+ * @param power_line_frequency TODO
+ */
+uvc_error_t uvc_set_power_line_frequency(uvc_device_handle_t *devh, uint8_t power_line_frequency) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  data[0] = power_line_frequency;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_PU_POWER_LINE_FREQUENCY_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the HUE control.
+ * @param devh UVC device handle
+ * @param[out] hue TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_hue(uvc_device_handle_t *devh, int16_t* hue, enum uvc_req_code req_code) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_PU_HUE_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *hue = SW_TO_SHORT(data + 0);
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the HUE control.
+ * @param devh UVC device handle
+ * @param hue TODO
+ */
+uvc_error_t uvc_set_hue(uvc_device_handle_t *devh, int16_t hue) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  SHORT_TO_SW(hue, data + 0);
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_PU_HUE_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the HUE_AUTO control.
+ * @param devh UVC device handle
+ * @param[out] hue_auto TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_hue_auto(uvc_device_handle_t *devh, uint8_t* hue_auto, enum uvc_req_code req_code) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_PU_HUE_AUTO_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *hue_auto = data[0];
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the HUE_AUTO control.
+ * @param devh UVC device handle
+ * @param hue_auto TODO
+ */
+uvc_error_t uvc_set_hue_auto(uvc_device_handle_t *devh, uint8_t hue_auto) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  data[0] = hue_auto;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_PU_HUE_AUTO_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the SATURATION control.
+ * @param devh UVC device handle
+ * @param[out] saturation TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_saturation(uvc_device_handle_t *devh, uint16_t* saturation, enum uvc_req_code req_code) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_PU_SATURATION_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *saturation = SW_TO_SHORT(data + 0);
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the SATURATION control.
+ * @param devh UVC device handle
+ * @param saturation TODO
+ */
+uvc_error_t uvc_set_saturation(uvc_device_handle_t *devh, uint16_t saturation) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  SHORT_TO_SW(saturation, data + 0);
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_PU_SATURATION_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the SHARPNESS control.
+ * @param devh UVC device handle
+ * @param[out] sharpness TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_sharpness(uvc_device_handle_t *devh, uint16_t* sharpness, enum uvc_req_code req_code) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_PU_SHARPNESS_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *sharpness = SW_TO_SHORT(data + 0);
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the SHARPNESS control.
+ * @param devh UVC device handle
+ * @param sharpness TODO
+ */
+uvc_error_t uvc_set_sharpness(uvc_device_handle_t *devh, uint16_t sharpness) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  SHORT_TO_SW(sharpness, data + 0);
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_PU_SHARPNESS_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the GAMMA control.
+ * @param devh UVC device handle
+ * @param[out] gamma TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_gamma(uvc_device_handle_t *devh, uint16_t* gamma, enum uvc_req_code req_code) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_PU_GAMMA_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *gamma = SW_TO_SHORT(data + 0);
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the GAMMA control.
+ * @param devh UVC device handle
+ * @param gamma TODO
+ */
+uvc_error_t uvc_set_gamma(uvc_device_handle_t *devh, uint16_t gamma) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  SHORT_TO_SW(gamma, data + 0);
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_PU_GAMMA_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the WHITE_BALANCE_TEMPERATURE control.
+ * @param devh UVC device handle
+ * @param[out] temperature TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_white_balance_temperature(uvc_device_handle_t *devh, uint16_t* temperature, enum uvc_req_code req_code) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *temperature = SW_TO_SHORT(data + 0);
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the WHITE_BALANCE_TEMPERATURE control.
+ * @param devh UVC device handle
+ * @param temperature TODO
+ */
+uvc_error_t uvc_set_white_balance_temperature(uvc_device_handle_t *devh, uint16_t temperature) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  SHORT_TO_SW(temperature, data + 0);
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the WHITE_BALANCE_TEMPERATURE_AUTO control.
+ * @param devh UVC device handle
+ * @param[out] temperature_auto TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_white_balance_temperature_auto(uvc_device_handle_t *devh, uint8_t* temperature_auto, enum uvc_req_code req_code) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *temperature_auto = data[0];
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the WHITE_BALANCE_TEMPERATURE_AUTO control.
+ * @param devh UVC device handle
+ * @param temperature_auto TODO
+ */
+uvc_error_t uvc_set_white_balance_temperature_auto(uvc_device_handle_t *devh, uint8_t temperature_auto) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  data[0] = temperature_auto;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the WHITE_BALANCE_COMPONENT control.
+ * @param devh UVC device handle
+ * @param[out] blue TODO
+ * @param[out] red TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_white_balance_component(uvc_device_handle_t *devh, uint16_t* blue, uint16_t* red, enum uvc_req_code req_code) {
+  uint8_t data[4];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *blue = SW_TO_SHORT(data + 0);
+    *red = SW_TO_SHORT(data + 2);
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the WHITE_BALANCE_COMPONENT control.
+ * @param devh UVC device handle
+ * @param blue TODO
+ * @param red TODO
+ */
+uvc_error_t uvc_set_white_balance_component(uvc_device_handle_t *devh, uint16_t blue, uint16_t red) {
+  uint8_t data[4];
+  uvc_error_t ret;
+
+  SHORT_TO_SW(blue, data + 0);
+  SHORT_TO_SW(red, data + 2);
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the WHITE_BALANCE_COMPONENT_AUTO control.
+ * @param devh UVC device handle
+ * @param[out] white_balance_component_auto TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_white_balance_component_auto(uvc_device_handle_t *devh, uint8_t* white_balance_component_auto, enum uvc_req_code req_code) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *white_balance_component_auto = data[0];
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the WHITE_BALANCE_COMPONENT_AUTO control.
+ * @param devh UVC device handle
+ * @param white_balance_component_auto TODO
+ */
+uvc_error_t uvc_set_white_balance_component_auto(uvc_device_handle_t *devh, uint8_t white_balance_component_auto) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  data[0] = white_balance_component_auto;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the DIGITAL_MULTIPLIER control.
+ * @param devh UVC device handle
+ * @param[out] multiplier_step TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_digital_multiplier(uvc_device_handle_t *devh, uint16_t* multiplier_step, enum uvc_req_code req_code) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_PU_DIGITAL_MULTIPLIER_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *multiplier_step = SW_TO_SHORT(data + 0);
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the DIGITAL_MULTIPLIER control.
+ * @param devh UVC device handle
+ * @param multiplier_step TODO
+ */
+uvc_error_t uvc_set_digital_multiplier(uvc_device_handle_t *devh, uint16_t multiplier_step) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  SHORT_TO_SW(multiplier_step, data + 0);
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_PU_DIGITAL_MULTIPLIER_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the DIGITAL_MULTIPLIER_LIMIT control.
+ * @param devh UVC device handle
+ * @param[out] multiplier_step TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_digital_multiplier_limit(uvc_device_handle_t *devh, uint16_t* multiplier_step, enum uvc_req_code req_code) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *multiplier_step = SW_TO_SHORT(data + 0);
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the DIGITAL_MULTIPLIER_LIMIT control.
+ * @param devh UVC device handle
+ * @param multiplier_step TODO
+ */
+uvc_error_t uvc_set_digital_multiplier_limit(uvc_device_handle_t *devh, uint16_t multiplier_step) {
+  uint8_t data[2];
+  uvc_error_t ret;
+
+  SHORT_TO_SW(multiplier_step, data + 0);
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the ANALOG_VIDEO_STANDARD control.
+ * @param devh UVC device handle
+ * @param[out] video_standard TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_analog_video_standard(uvc_device_handle_t *devh, uint8_t* video_standard, enum uvc_req_code req_code) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *video_standard = data[0];
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the ANALOG_VIDEO_STANDARD control.
+ * @param devh UVC device handle
+ * @param video_standard TODO
+ */
+uvc_error_t uvc_set_analog_video_standard(uvc_device_handle_t *devh, uint8_t video_standard) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  data[0] = video_standard;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the ANALOG_LOCK_STATUS control.
+ * @param devh UVC device handle
+ * @param[out] status TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_analog_video_lock_status(uvc_device_handle_t *devh, uint8_t* status, enum uvc_req_code req_code) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_PU_ANALOG_LOCK_STATUS_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *status = data[0];
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the ANALOG_LOCK_STATUS control.
+ * @param devh UVC device handle
+ * @param status TODO
+ */
+uvc_error_t uvc_set_analog_video_lock_status(uvc_device_handle_t *devh, uint8_t status) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  data[0] = status;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_PU_ANALOG_LOCK_STATUS_CONTROL << 8,
+    uvc_get_processing_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @ingroup ctrl
+ * @brief Reads the INPUT_SELECT control.
+ * @param devh UVC device handle
+ * @param[out] selector TODO
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_input_select(uvc_device_handle_t *devh, uint8_t* selector, enum uvc_req_code req_code) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_SU_INPUT_SELECT_CONTROL << 8,
+    uvc_get_selector_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {
+    *selector = data[0];
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+
+/** @ingroup ctrl
+ * @brief Sets the INPUT_SELECT control.
+ * @param devh UVC device handle
+ * @param selector TODO
+ */
+uvc_error_t uvc_set_input_select(uvc_device_handle_t *devh, uint8_t selector) {
+  uint8_t data[1];
+  uvc_error_t ret;
+
+  data[0] = selector;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_SU_INPUT_SELECT_CONTROL << 8,
+    uvc_get_selector_units(devh)->bUnitID << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/2d9e5719/thirdparty/libuvc-0.0.6/src/ctrl-gen.py
----------------------------------------------------------------------
diff --git a/thirdparty/libuvc-0.0.6/src/ctrl-gen.py b/thirdparty/libuvc-0.0.6/src/ctrl-gen.py
new file mode 100755
index 0000000..d349a73
--- /dev/null
+++ b/thirdparty/libuvc-0.0.6/src/ctrl-gen.py
@@ -0,0 +1,302 @@
+#!/usr/bin/env python
+from __future__ import print_function
+from collections import OrderedDict
+import getopt
+import sys
+import yaml
+
+class quoted(str): pass
+
+def quoted_presenter(dumper, data):
+    return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='"')
+yaml.add_representer(quoted, quoted_presenter)
+
+class literal(str): pass
+
+def literal_presenter(dumper, data):
+    return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|')
+yaml.add_representer(literal, literal_presenter)
+
+def ordered_dict_presenter(dumper, data):
+    return dumper.represent_dict(data.items())
+yaml.add_representer(OrderedDict, ordered_dict_presenter)
+
+def dict_constructor(loader, node):
+    return OrderedDict(loader.construct_pairs(node))
+_mapping_tag = yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG
+yaml.add_constructor(_mapping_tag, dict_constructor)
+
+class IntField(object):
+    def __init__(self, name, position, length, signed):
+        self.name = name
+        self.position = position
+        self.length = length
+        self.signed = signed
+
+        if not self.length in [1, 2, 4]:
+            raise Exception("bad length " + str(self.length))
+
+        self.user_type = ('u' if not signed else '') + 'int' + str(length * 8) + '_t'
+
+    def getter_sig(self):
+        return "{0}* {1}".format(self.user_type, self.name)
+
+    def unpack(self):
+        if self.length == 1:
+            return "*{0} = data[{1}];".format(self.name, self.position)
+        elif self.length == 2:
+            return "*{0} = SW_TO_SHORT(data + {1});".format(self.name, self.position)
+        elif self.length == 4:
+            return "*{0} = DW_TO_INT(data + {1});".format(self.name, self.position)
+
+    def setter_sig(self):
+        return "{0} {1}".format(self.user_type, self.name)
+
+    def pack(self):
+        if self.length == 1:
+            return "data[{0}] = {1};".format(self.position, self.name)
+        elif self.length == 2:
+            return "SHORT_TO_SW({0}, data + {1});".format(self.name, self.position)
+        elif self.length == 4:
+            return "INT_TO_DW({0}, data + {1});".format(self.name, self.position)
+
+    def spec(self):
+        rep = [('position', self.position), ('length', self.length)]
+        if self.signed:
+            rep.append(('signed', True))
+        return rep
+
+    @staticmethod
+    def load(spec):
+        return IntField(spec['name'], spec['position'], spec['length'], spec['signed'] if signed in spec else False)
+
+def load_field(name, spec):
+    if spec['type'] == 'int':
+        return IntField(name, spec['position'], spec['length'], spec.get('signed', False))
+    else:
+        raise Exception("unknown field type '{0}'".format(spec['type']))
+
+GETTER_TEMPLATE = """/** @ingroup ctrl
+ * {gen_doc}
+ * @param devh UVC device handle
+ * {args_doc}
+ * @param req_code UVC_GET_* request to execute
+ */
+uvc_error_t uvc_get_{control_name}(uvc_device_handle_t *devh, {args_signature}, enum uvc_req_code req_code) {{
+  uint8_t data[{control_length}];
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    {control_code} << 8,
+    {unit_fn} << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data)) {{
+    {unpack}
+    return UVC_SUCCESS;
+  }} else {{
+    return ret;
+  }}
+}}
+"""
+
+SETTER_TEMPLATE = """/** @ingroup ctrl
+ * {gen_doc}
+ * @param devh UVC device handle
+ * {args_doc}
+ */
+uvc_error_t uvc_set_{control_name}(uvc_device_handle_t *devh, {args_signature}) {{
+  uint8_t data[{control_length}];
+  uvc_error_t ret;
+
+  {pack}
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    {control_code} << 8,
+    {unit_fn} << 8 | devh->info->ctrl_if.bInterfaceNumber,
+    data,
+    sizeof(data),
+    0);
+
+  if (ret == sizeof(data))
+    return UVC_SUCCESS;
+  else
+    return ret;
+}}
+"""
+
+def gen_decl(unit_name, unit, control_name, control):
+    fields = [(load_field(field_name, field_details), field_details['doc']) for field_name, field_details in control['fields'].items()] if 'fields' in control else []
+
+    get_args_signature = ', '.join([field.getter_sig() for (field, desc) in fields])
+    set_args_signature = ', '.join([field.setter_sig() for (field, desc) in fields])
+
+    return "uvc_error_t uvc_get_{function_name}(uvc_device_handle_t *devh, {args_signature}, enum uvc_req_code req_code);\n".format(**{
+        "function_name": control_name,
+        "args_signature": get_args_signature
+    }) + "uvc_error_t uvc_set_{function_name}(uvc_device_handle_t *devh, {args_signature});\n".format(**{
+        "function_name": control_name,
+        "args_signature": set_args_signature
+    })
+
+def gen_ctrl(unit_name, unit, control_name, control):
+    fields = [(load_field(field_name, field_details), field_details['doc']) for field_name, field_details in control['fields'].items()] if 'fields' in control else []
+
+    get_args_signature = ', '.join([field.getter_sig() for (field, desc) in fields])
+    set_args_signature = ', '.join([field.setter_sig() for (field, desc) in fields])
+    unpack = "\n    ".join([field.unpack() for (field, desc) in fields])
+    pack = "\n  ".join([field.pack() for (field, desc) in fields])
+
+    get_gen_doc_raw = None
+    set_gen_doc_raw = None
+
+    if 'doc' in control:
+        doc = control['doc']
+
+        if isinstance(doc, str):
+            get_gen_doc_raw = "\n * ".join(doc.splitlines())
+            set_gen_doc_raw = get_gen_doc_raw
+        else:
+            if 'get' in doc:
+                get_gen_doc_raw = "\n * ".join(doc['get'].splitlines())
+            if 'set' in doc:
+                set_gen_doc_raw = "\n * ".join(doc['set'].splitlines())
+
+    if get_gen_doc_raw is not None:
+        get_gen_doc = get_gen_doc_raw.format(gets_sets='Reads')
+    else:
+        get_gen_doc = '@brief Reads the ' + control['control'] + ' control.'
+
+    if set_gen_doc_raw is not None:
+        set_gen_doc = set_gen_doc_raw.format(gets_sets='Sets')
+    else:
+        set_gen_doc = '@brief Sets the ' + control['control'] + ' control.'
+
+    get_args_doc = "\n * ".join(["@param[out] {0} {1}".format(field.name, desc) for (field, desc) in fields])
+    set_args_doc = "\n * ".join(["@param {0} {1}".format(field.name, desc) for (field, desc) in fields])
+
+    control_code = 'UVC_' + unit['control_prefix'] + '_' + control['control'] + '_CONTROL'
+
+    unit_fn = "uvc_get_camera_terminal(devh)->bTerminalID" if (unit_name == "camera_terminal") else ("uvc_get_" + unit_name + "s(devh)->bUnitID")
+
+    return GETTER_TEMPLATE.format(
+        unit=unit,
+        unit_fn=unit_fn,
+        control_name=control_name,
+        control_code=control_code,
+        control_length=control['length'],
+        args_signature=get_args_signature,
+        args_doc=get_args_doc,
+        gen_doc=get_gen_doc,
+        unpack=unpack) + "\n\n" + SETTER_TEMPLATE.format(
+            unit=unit,
+            unit_fn=unit_fn,
+            control_name=control_name,
+            control_code=control_code,
+            control_length=control['length'],
+            args_signature=set_args_signature,
+            args_doc=set_args_doc,
+            gen_doc=set_gen_doc,
+            pack=pack
+        )
+
+def export_unit(unit):
+    def fmt_doc(doc):
+        def wrap_doc_entry(entry):
+            if "\n" in entry:
+                return literal(entry)
+            else:
+                return entry
+
+        if isinstance(doc, str):
+            return wrap_doc_entry(doc)
+        else:
+            return OrderedDict([(mode, wrap_doc_entry(text)) for mode, text in doc.items()])
+
+    def fmt_ctrl(control_name, control_details):
+        contents = OrderedDict()
+        contents['control'] = control_details['control']
+        contents['length'] = control_details['length']
+        contents['fields'] = control_details['fields']
+
+        if 'doc' in control_details:
+            contents['doc'] = fmt_doc(control_details['doc'])
+
+        return (control_name, contents)
+
+    unit_out = OrderedDict()
+    unit_out['type'] = unit['type']
+    if 'guid' in unit:
+        unit_out['guid'] = unit['guid']
+    if 'description' in unit:
+        unit_out['description'] = unit['description']
+    if 'control_prefix' in unit:
+        unit_out['control_prefix'] = unit['control_prefix']
+    unit_out['controls'] = OrderedDict([fmt_ctrl(ctrl_name, ctrl_details) for ctrl_name, ctrl_details in unit['controls'].items()])
+    return unit_out
+
+if __name__ == '__main__':
+    try:
+        opts, args = getopt.getopt(sys.argv[1:], "hi:", ["help", "input="])
+    except getopt.GetoptError as err:
+        print(str(err))
+        usage()
+        sys.exit(-1)
+
+    inputs = []
+
+    for opt, val in opts:
+        if opt in ('-h', '--help'):
+            usage()
+            sys.exit(0)
+        elif opt in ('-i', '--input'):
+            inputs.append(val)
+
+    mode = None
+    for arg in args:
+        if arg in ('def', 'decl', 'yaml'):
+            if mode is None:
+                mode = arg
+            else:
+                print("Can't specify more than one mode")
+                sys.exit(-1)
+        else:
+            print("Invalid mode '{0}'".format(arg))
+            sys.exit(-1)
+
+    def iterunits():
+        for input_file in inputs:
+            with open(input_file, "r") as fp:
+                units = yaml.load(fp)['units']
+                for unit_name, unit_details in units.iteritems():
+                    yield unit_name, unit_details
+
+    if mode == 'def':
+        print("""/* This is an AUTO-GENERATED file! Update it with the output of `ctrl-gen.py def`. */
+#include "libuvc/libuvc.h"
+#include "libuvc/libuvc_internal.h"
+
+static const int REQ_TYPE_SET = 0x21;
+static const int REQ_TYPE_GET = 0xa1;
+""")
+        fun = gen_ctrl
+    elif mode == 'decl':
+        fun = gen_decl
+    elif mode == 'yaml':
+        exported_units = OrderedDict()
+        for unit_name, unit_details in iterunits():
+            exported_units[unit_name] = export_unit(unit_details)
+
+        yaml.dump({'units': exported_units}, sys.stdout, default_flow_style=False)
+        sys.exit(0)
+
+    for unit_name, unit_details in iterunits():
+        for control_name, control_details in unit_details['controls'].iteritems():
+            code = fun(unit_name, unit_details, control_name, control_details)
+            print(code)

http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/2d9e5719/thirdparty/libuvc-0.0.6/src/ctrl.c
----------------------------------------------------------------------
diff --git a/thirdparty/libuvc-0.0.6/src/ctrl.c b/thirdparty/libuvc-0.0.6/src/ctrl.c
new file mode 100644
index 0000000..3dffe79
--- /dev/null
+++ b/thirdparty/libuvc-0.0.6/src/ctrl.c
@@ -0,0 +1,165 @@
+/*********************************************************************
+* Software License Agreement (BSD License)
+*
+*  Copyright (C) 2010-2012 Ken Tossell
+*  All rights reserved.
+*
+*  Redistribution and use in source and binary forms, with or without
+*  modification, are permitted provided that the following conditions
+*  are met:
+*
+*   * Redistributions of source code must retain the above copyright
+*     notice, this list of conditions and the following disclaimer.
+*   * Redistributions in binary form must reproduce the above
+*     copyright notice, this list of conditions and the following
+*     disclaimer in the documentation and/or other materials provided
+*     with the distribution.
+*   * Neither the name of the author nor other contributors may be
+*     used to endorse or promote products derived from this software
+*     without specific prior written permission.
+*
+*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+*  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+*  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+*  POSSIBILITY OF SUCH DAMAGE.
+*********************************************************************/
+/**
+ * @defgroup ctrl Video capture and processing controls
+ * @brief Functions for manipulating device settings and stream parameters
+ *
+ * The `uvc_get_*` and `uvc_set_*` functions are used to read and write the settings associated
+ * with the device's input, processing and output units.
+ */
+
+#include "libuvc/libuvc.h"
+#include "libuvc/libuvc_internal.h"
+
+static const int REQ_TYPE_SET = 0x21;
+static const int REQ_TYPE_GET = 0xa1;
+
+/***** GENERIC CONTROLS *****/
+/**
+ * @brief Get the length of a control on a terminal or unit.
+ * 
+ * @param devh UVC device handle
+ * @param unit Unit or Terminal ID; obtain this from the uvc_extension_unit_t describing the extension unit
+ * @param ctrl Vendor-specific control number to query
+ * @return On success, the length of the control as reported by the device. Otherwise,
+ *   a uvc_error_t error describing the error encountered.
+ * @ingroup ctrl
+ */
+int uvc_get_ctrl_len(uvc_device_handle_t *devh, uint8_t unit, uint8_t ctrl) {
+  unsigned char buf[2];
+
+  int ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, UVC_GET_LEN,
+    ctrl << 8,
+    unit << 8 | devh->info->ctrl_if.bInterfaceNumber,		// XXX saki
+    buf,
+    2,
+    0 /* timeout */);
+
+  if (ret < 0)
+    return ret;
+  else
+    return (unsigned short)SW_TO_SHORT(buf);
+}
+
+/**
+ * @brief Perform a GET_* request from an extension unit.
+ * 
+ * @param devh UVC device handle
+ * @param unit Unit ID; obtain this from the uvc_extension_unit_t describing the extension unit
+ * @param ctrl Control number to query
+ * @param data Data buffer to be filled by the device
+ * @param len Size of data buffer
+ * @param req_code GET_* request to execute
+ * @return On success, the number of bytes actually transferred. Otherwise,
+ *   a uvc_error_t error describing the error encountered.
+ * @ingroup ctrl
+ */
+int uvc_get_ctrl(uvc_device_handle_t *devh, uint8_t unit, uint8_t ctrl, void *data, int len, enum uvc_req_code req_code) {
+  return libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    ctrl << 8,
+    unit << 8 | devh->info->ctrl_if.bInterfaceNumber,		// XXX saki
+    data,
+    len,
+    0 /* timeout */);
+}
+
+/**
+ * @brief Perform a SET_CUR request to a terminal or unit.
+ * 
+ * @param devh UVC device handle
+ * @param unit Unit or Terminal ID
+ * @param ctrl Control number to set
+ * @param data Data buffer to be sent to the device
+ * @param len Size of data buffer
+ * @return On success, the number of bytes actually transferred. Otherwise,
+ *   a uvc_error_t error describing the error encountered.
+ * @ingroup ctrl
+ */
+int uvc_set_ctrl(uvc_device_handle_t *devh, uint8_t unit, uint8_t ctrl, void *data, int len) {
+  return libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    ctrl << 8,
+    unit << 8 | devh->info->ctrl_if.bInterfaceNumber,		// XXX saki
+    data,
+    len,
+    0 /* timeout */);
+}
+
+/***** INTERFACE CONTROLS *****/
+uvc_error_t uvc_get_power_mode(uvc_device_handle_t *devh, enum uvc_device_power_mode *mode, enum uvc_req_code req_code) {
+  uint8_t mode_char;
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_GET, req_code,
+    UVC_VC_VIDEO_POWER_MODE_CONTROL << 8,
+    devh->info->ctrl_if.bInterfaceNumber,	// XXX saki
+    &mode_char,
+    sizeof(mode_char),
+    0);
+
+  if (ret == 1) {
+    *mode = mode_char;
+    return UVC_SUCCESS;
+  } else {
+    return ret;
+  }
+}
+
+uvc_error_t uvc_set_power_mode(uvc_device_handle_t *devh, enum uvc_device_power_mode mode) {
+  uint8_t mode_char = mode;
+  uvc_error_t ret;
+
+  ret = libusb_control_transfer(
+    devh->usb_devh,
+    REQ_TYPE_SET, UVC_SET_CUR,
+    UVC_VC_VIDEO_POWER_MODE_CONTROL << 8,
+    devh->info->ctrl_if.bInterfaceNumber,	// XXX saki
+    &mode_char,
+    sizeof(mode_char),
+    0);
+
+  if (ret == 1)
+    return UVC_SUCCESS;
+  else
+    return ret;
+}
+
+/** @todo Request Error Code Control (UVC 1.5, 4.2.1.2) */