aboutsummaryrefslogtreecommitdiff
path: root/drivers/media/video/uvc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/uvc')
-rw-r--r--drivers/media/video/uvc/Kconfig19
-rw-r--r--drivers/media/video/uvc/Makefile6
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c2165
-rw-r--r--drivers/media/video/uvc/uvc_debugfs.c136
-rw-r--r--drivers/media/video/uvc/uvc_driver.c2472
-rw-r--r--drivers/media/video/uvc/uvc_entity.c126
-rw-r--r--drivers/media/video/uvc/uvc_isight.c137
-rw-r--r--drivers/media/video/uvc/uvc_queue.c359
-rw-r--r--drivers/media/video/uvc/uvc_status.c237
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c1317
-rw-r--r--drivers/media/video/uvc/uvc_video.c1879
-rw-r--r--drivers/media/video/uvc/uvcvideo.h718
12 files changed, 0 insertions, 9571 deletions
diff --git a/drivers/media/video/uvc/Kconfig b/drivers/media/video/uvc/Kconfig
deleted file mode 100644
index 541c9f1e4c6..00000000000
--- a/drivers/media/video/uvc/Kconfig
+++ /dev/null
@@ -1,19 +0,0 @@
-config USB_VIDEO_CLASS
- tristate "USB Video Class (UVC)"
- select VIDEOBUF2_VMALLOC
- ---help---
- Support for the USB Video Class (UVC). Currently only video
- input devices, such as webcams, are supported.
-
- For more information see: <http://linux-uvc.berlios.de/>
-
-config USB_VIDEO_CLASS_INPUT_EVDEV
- bool "UVC input events device support"
- default y
- depends on USB_VIDEO_CLASS
- depends on USB_VIDEO_CLASS=INPUT || INPUT=y
- ---help---
- This option makes USB Video Class devices register an input device
- to report button events.
-
- If you are in doubt, say Y.
diff --git a/drivers/media/video/uvc/Makefile b/drivers/media/video/uvc/Makefile
deleted file mode 100644
index c26d12fdb8f..00000000000
--- a/drivers/media/video/uvc/Makefile
+++ /dev/null
@@ -1,6 +0,0 @@
-uvcvideo-objs := uvc_driver.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_ctrl.o \
- uvc_status.o uvc_isight.o uvc_debugfs.o
-ifeq ($(CONFIG_MEDIA_CONTROLLER),y)
-uvcvideo-objs += uvc_entity.o
-endif
-obj-$(CONFIG_USB_VIDEO_CLASS) += uvcvideo.o
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
deleted file mode 100644
index f7061a5ef1d..00000000000
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ /dev/null
@@ -1,2165 +0,0 @@
-/*
- * uvc_ctrl.c -- USB Video Class driver - Controls
- *
- * Copyright (C) 2005-2010
- * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/uaccess.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <linux/vmalloc.h>
-#include <linux/wait.h>
-#include <linux/atomic.h>
-#include <media/v4l2-ctrls.h>
-
-#include "uvcvideo.h"
-
-#define UVC_CTRL_DATA_CURRENT 0
-#define UVC_CTRL_DATA_BACKUP 1
-#define UVC_CTRL_DATA_MIN 2
-#define UVC_CTRL_DATA_MAX 3
-#define UVC_CTRL_DATA_RES 4
-#define UVC_CTRL_DATA_DEF 5
-#define UVC_CTRL_DATA_LAST 6
-
-/* ------------------------------------------------------------------------
- * Controls
- */
-
-static struct uvc_control_info uvc_ctrls[] = {
- {
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_BRIGHTNESS_CONTROL,
- .index = 0,
- .size = 2,
- .flags = UVC_CTRL_FLAG_SET_CUR
- | UVC_CTRL_FLAG_GET_RANGE
- | UVC_CTRL_FLAG_RESTORE,
- },
- {
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_CONTRAST_CONTROL,
- .index = 1,
- .size = 2,
- .flags = UVC_CTRL_FLAG_SET_CUR
- | UVC_CTRL_FLAG_GET_RANGE
- | UVC_CTRL_FLAG_RESTORE,
- },
- {
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_HUE_CONTROL,
- .index = 2,
- .size = 2,
- .flags = UVC_CTRL_FLAG_SET_CUR
- | UVC_CTRL_FLAG_GET_RANGE
- | UVC_CTRL_FLAG_RESTORE
- | UVC_CTRL_FLAG_AUTO_UPDATE,
- },
- {
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_SATURATION_CONTROL,
- .index = 3,
- .size = 2,
- .flags = UVC_CTRL_FLAG_SET_CUR
- | UVC_CTRL_FLAG_GET_RANGE
- | UVC_CTRL_FLAG_RESTORE,
- },
- {
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_SHARPNESS_CONTROL,
- .index = 4,
- .size = 2,
- .flags = UVC_CTRL_FLAG_SET_CUR
- | UVC_CTRL_FLAG_GET_RANGE
- | UVC_CTRL_FLAG_RESTORE,
- },
- {
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_GAMMA_CONTROL,
- .index = 5,
- .size = 2,
- .flags = UVC_CTRL_FLAG_SET_CUR
- | UVC_CTRL_FLAG_GET_RANGE
- | UVC_CTRL_FLAG_RESTORE,
- },
- {
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
- .index = 6,
- .size = 2,
- .flags = UVC_CTRL_FLAG_SET_CUR
- | UVC_CTRL_FLAG_GET_RANGE
- | UVC_CTRL_FLAG_RESTORE
- | UVC_CTRL_FLAG_AUTO_UPDATE,
- },
- {
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL,
- .index = 7,
- .size = 4,
- .flags = UVC_CTRL_FLAG_SET_CUR
- | UVC_CTRL_FLAG_GET_RANGE
- | UVC_CTRL_FLAG_RESTORE
- | UVC_CTRL_FLAG_AUTO_UPDATE,
- },
- {
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_BACKLIGHT_COMPENSATION_CONTROL,
- .index = 8,
- .size = 2,
- .flags = UVC_CTRL_FLAG_SET_CUR
- | UVC_CTRL_FLAG_GET_RANGE
- | UVC_CTRL_FLAG_RESTORE,
- },
- {
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_GAIN_CONTROL,
- .index = 9,
- .size = 2,
- .flags = UVC_CTRL_FLAG_SET_CUR
- | UVC_CTRL_FLAG_GET_RANGE
- | UVC_CTRL_FLAG_RESTORE,
- },
- {
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
- .index = 10,
- .size = 1,
- .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
- | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE,
- },
- {
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_HUE_AUTO_CONTROL,
- .index = 11,
- .size = 1,
- .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
- | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE,
- },
- {
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
- .index = 12,
- .size = 1,
- .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
- | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE,
- },
- {
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
- .index = 13,
- .size = 1,
- .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
- | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE,
- },
- {
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_DIGITAL_MULTIPLIER_CONTROL,
- .index = 14,
- .size = 2,
- .flags = UVC_CTRL_FLAG_SET_CUR
- | UVC_CTRL_FLAG_GET_RANGE
- | UVC_CTRL_FLAG_RESTORE,
- },
- {
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL,
- .index = 15,
- .size = 2,
- .flags = UVC_CTRL_FLAG_SET_CUR
- | UVC_CTRL_FLAG_GET_RANGE
- | UVC_CTRL_FLAG_RESTORE,
- },
- {
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL,
- .index = 16,
- .size = 1,
- .flags = UVC_CTRL_FLAG_GET_CUR,
- },
- {
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_ANALOG_LOCK_STATUS_CONTROL,
- .index = 17,
- .size = 1,
- .flags = UVC_CTRL_FLAG_GET_CUR,
- },
- {
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_SCANNING_MODE_CONTROL,
- .index = 0,
- .size = 1,
- .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
- | UVC_CTRL_FLAG_RESTORE,
- },
- {
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_AE_MODE_CONTROL,
- .index = 1,
- .size = 1,
- .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
- | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_GET_RES
- | UVC_CTRL_FLAG_RESTORE,
- },
- {
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_AE_PRIORITY_CONTROL,
- .index = 2,
- .size = 1,
- .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
- | UVC_CTRL_FLAG_RESTORE,
- },
- {
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
- .index = 3,
- .size = 4,
- .flags = UVC_CTRL_FLAG_SET_CUR
- | UVC_CTRL_FLAG_GET_RANGE
- | UVC_CTRL_FLAG_RESTORE,
- },
- {
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL,
- .index = 4,
- .size = 1,
- .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_RESTORE,
- },
- {
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_FOCUS_ABSOLUTE_CONTROL,
- .index = 5,
- .size = 2,
- .flags = UVC_CTRL_FLAG_SET_CUR
- | UVC_CTRL_FLAG_GET_RANGE
- | UVC_CTRL_FLAG_RESTORE
- | UVC_CTRL_FLAG_AUTO_UPDATE,
- },
- {
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_FOCUS_RELATIVE_CONTROL,
- .index = 6,
- .size = 2,
- .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN
- | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES
- | UVC_CTRL_FLAG_GET_DEF
- | UVC_CTRL_FLAG_AUTO_UPDATE,
- },
- {
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_IRIS_ABSOLUTE_CONTROL,
- .index = 7,
- .size = 2,
- .flags = UVC_CTRL_FLAG_SET_CUR
- | UVC_CTRL_FLAG_GET_RANGE
- | UVC_CTRL_FLAG_RESTORE
- | UVC_CTRL_FLAG_AUTO_UPDATE,
- },
- {
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_IRIS_RELATIVE_CONTROL,
- .index = 8,
- .size = 1,
- .flags = UVC_CTRL_FLAG_SET_CUR
- | UVC_CTRL_FLAG_AUTO_UPDATE,
- },
- {
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_ZOOM_ABSOLUTE_CONTROL,
- .index = 9,
- .size = 2,
- .flags = UVC_CTRL_FLAG_SET_CUR
- | UVC_CTRL_FLAG_GET_RANGE
- | UVC_CTRL_FLAG_RESTORE
- | UVC_CTRL_FLAG_AUTO_UPDATE,
- },
- {
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_ZOOM_RELATIVE_CONTROL,
- .index = 10,
- .size = 3,
- .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN
- | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES
- | UVC_CTRL_FLAG_GET_DEF
- | UVC_CTRL_FLAG_AUTO_UPDATE,
- },
- {
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL,
- .index = 11,
- .size = 8,
- .flags = UVC_CTRL_FLAG_SET_CUR
- | UVC_CTRL_FLAG_GET_RANGE
- | UVC_CTRL_FLAG_RESTORE
- | UVC_CTRL_FLAG_AUTO_UPDATE,
- },
- {
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_PANTILT_RELATIVE_CONTROL,
- .index = 12,
- .size = 4,
- .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN
- | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES
- | UVC_CTRL_FLAG_GET_DEF
- | UVC_CTRL_FLAG_AUTO_UPDATE,
- },
- {
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_ROLL_ABSOLUTE_CONTROL,
- .index = 13,
- .size = 2,
- .flags = UVC_CTRL_FLAG_SET_CUR
- | UVC_CTRL_FLAG_GET_RANGE
- | UVC_CTRL_FLAG_RESTORE
- | UVC_CTRL_FLAG_AUTO_UPDATE,
- },
- {
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_ROLL_RELATIVE_CONTROL,
- .index = 14,
- .size = 2,
- .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_MIN
- | UVC_CTRL_FLAG_GET_MAX | UVC_CTRL_FLAG_GET_RES
- | UVC_CTRL_FLAG_GET_DEF
- | UVC_CTRL_FLAG_AUTO_UPDATE,
- },
- {
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_FOCUS_AUTO_CONTROL,
- .index = 17,
- .size = 1,
- .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
- | UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_RESTORE,
- },
- {
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_PRIVACY_CONTROL,
- .index = 18,
- .size = 1,
- .flags = UVC_CTRL_FLAG_SET_CUR | UVC_CTRL_FLAG_GET_CUR
- | UVC_CTRL_FLAG_RESTORE
- | UVC_CTRL_FLAG_AUTO_UPDATE,
- },
-};
-
-static struct uvc_menu_info power_line_frequency_controls[] = {
- { 0, "Disabled" },
- { 1, "50 Hz" },
- { 2, "60 Hz" },
-};
-
-static struct uvc_menu_info exposure_auto_controls[] = {
- { 2, "Auto Mode" },
- { 1, "Manual Mode" },
- { 4, "Shutter Priority Mode" },
- { 8, "Aperture Priority Mode" },
-};
-
-static __s32 uvc_ctrl_get_zoom(struct uvc_control_mapping *mapping,
- __u8 query, const __u8 *data)
-{
- __s8 zoom = (__s8)data[0];
-
- switch (query) {
- case UVC_GET_CUR:
- return (zoom == 0) ? 0 : (zoom > 0 ? data[2] : -data[2]);
-
- case UVC_GET_MIN:
- case UVC_GET_MAX:
- case UVC_GET_RES:
- case UVC_GET_DEF:
- default:
- return data[2];
- }
-}
-
-static void uvc_ctrl_set_zoom(struct uvc_control_mapping *mapping,
- __s32 value, __u8 *data)
-{
- data[0] = value == 0 ? 0 : (value > 0) ? 1 : 0xff;
- data[2] = min((int)abs(value), 0xff);
-}
-
-static struct uvc_control_mapping uvc_ctrl_mappings[] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .name = "Brightness",
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_BRIGHTNESS_CONTROL,
- .size = 16,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_SIGNED,
- },
- {
- .id = V4L2_CID_CONTRAST,
- .name = "Contrast",
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_CONTRAST_CONTROL,
- .size = 16,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
- },
- {
- .id = V4L2_CID_HUE,
- .name = "Hue",
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_HUE_CONTROL,
- .size = 16,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_SIGNED,
- .master_id = V4L2_CID_HUE_AUTO,
- .master_manual = 0,
- },
- {
- .id = V4L2_CID_SATURATION,
- .name = "Saturation",
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_SATURATION_CONTROL,
- .size = 16,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
- },
- {
- .id = V4L2_CID_SHARPNESS,
- .name = "Sharpness",
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_SHARPNESS_CONTROL,
- .size = 16,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
- },
- {
- .id = V4L2_CID_GAMMA,
- .name = "Gamma",
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_GAMMA_CONTROL,
- .size = 16,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
- },
- {
- .id = V4L2_CID_BACKLIGHT_COMPENSATION,
- .name = "Backlight Compensation",
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_BACKLIGHT_COMPENSATION_CONTROL,
- .size = 16,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
- },
- {
- .id = V4L2_CID_GAIN,
- .name = "Gain",
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_GAIN_CONTROL,
- .size = 16,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
- },
- {
- .id = V4L2_CID_POWER_LINE_FREQUENCY,
- .name = "Power Line Frequency",
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
- .size = 2,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_MENU,
- .data_type = UVC_CTRL_DATA_TYPE_ENUM,
- .menu_info = power_line_frequency_controls,
- .menu_count = ARRAY_SIZE(power_line_frequency_controls),
- },
- {
- .id = V4L2_CID_HUE_AUTO,
- .name = "Hue, Auto",
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_HUE_AUTO_CONTROL,
- .size = 1,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
- .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
- .slave_ids = { V4L2_CID_HUE, },
- },
- {
- .id = V4L2_CID_EXPOSURE_AUTO,
- .name = "Exposure, Auto",
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_AE_MODE_CONTROL,
- .size = 4,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_MENU,
- .data_type = UVC_CTRL_DATA_TYPE_BITMASK,
- .menu_info = exposure_auto_controls,
- .menu_count = ARRAY_SIZE(exposure_auto_controls),
- .slave_ids = { V4L2_CID_EXPOSURE_ABSOLUTE, },
- },
- {
- .id = V4L2_CID_EXPOSURE_AUTO_PRIORITY,
- .name = "Exposure, Auto Priority",
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_AE_PRIORITY_CONTROL,
- .size = 1,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
- .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
- },
- {
- .id = V4L2_CID_EXPOSURE_ABSOLUTE,
- .name = "Exposure (Absolute)",
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL,
- .size = 32,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
- .master_id = V4L2_CID_EXPOSURE_AUTO,
- .master_manual = V4L2_EXPOSURE_MANUAL,
- },
- {
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .name = "White Balance Temperature, Auto",
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL,
- .size = 1,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
- .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
- .slave_ids = { V4L2_CID_WHITE_BALANCE_TEMPERATURE, },
- },
- {
- .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
- .name = "White Balance Temperature",
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL,
- .size = 16,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
- .master_id = V4L2_CID_AUTO_WHITE_BALANCE,
- .master_manual = 0,
- },
- {
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .name = "White Balance Component, Auto",
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL,
- .size = 1,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
- .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
- .slave_ids = { V4L2_CID_BLUE_BALANCE,
- V4L2_CID_RED_BALANCE },
- },
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .name = "White Balance Blue Component",
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL,
- .size = 16,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_SIGNED,
- .master_id = V4L2_CID_AUTO_WHITE_BALANCE,
- .master_manual = 0,
- },
- {
- .id = V4L2_CID_RED_BALANCE,
- .name = "White Balance Red Component",
- .entity = UVC_GUID_UVC_PROCESSING,
- .selector = UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL,
- .size = 16,
- .offset = 16,
- .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_SIGNED,
- .master_id = V4L2_CID_AUTO_WHITE_BALANCE,
- .master_manual = 0,
- },
- {
- .id = V4L2_CID_FOCUS_ABSOLUTE,
- .name = "Focus (absolute)",
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_FOCUS_ABSOLUTE_CONTROL,
- .size = 16,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
- .master_id = V4L2_CID_FOCUS_AUTO,
- .master_manual = 0,
- },
- {
- .id = V4L2_CID_FOCUS_AUTO,
- .name = "Focus, Auto",
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_FOCUS_AUTO_CONTROL,
- .size = 1,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
- .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
- .slave_ids = { V4L2_CID_FOCUS_ABSOLUTE, },
- },
- {
- .id = V4L2_CID_IRIS_ABSOLUTE,
- .name = "Iris, Absolute",
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_IRIS_ABSOLUTE_CONTROL,
- .size = 16,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
- },
- {
- .id = V4L2_CID_IRIS_RELATIVE,
- .name = "Iris, Relative",
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_IRIS_RELATIVE_CONTROL,
- .size = 8,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_SIGNED,
- },
- {
- .id = V4L2_CID_ZOOM_ABSOLUTE,
- .name = "Zoom, Absolute",
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_ZOOM_ABSOLUTE_CONTROL,
- .size = 16,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
- },
- {
- .id = V4L2_CID_ZOOM_CONTINUOUS,
- .name = "Zoom, Continuous",
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_ZOOM_RELATIVE_CONTROL,
- .size = 0,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_SIGNED,
- .get = uvc_ctrl_get_zoom,
- .set = uvc_ctrl_set_zoom,
- },
- {
- .id = V4L2_CID_PAN_ABSOLUTE,
- .name = "Pan (Absolute)",
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL,
- .size = 32,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
- },
- {
- .id = V4L2_CID_TILT_ABSOLUTE,
- .name = "Tilt (Absolute)",
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL,
- .size = 32,
- .offset = 32,
- .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
- .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
- },
- {
- .id = V4L2_CID_PRIVACY,
- .name = "Privacy",
- .entity = UVC_GUID_UVC_CAMERA,
- .selector = UVC_CT_PRIVACY_CONTROL,
- .size = 1,
- .offset = 0,
- .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
- .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
- },
-};
-
-/* ------------------------------------------------------------------------
- * Utility functions
- */
-
-static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id)
-{
- return ctrl->uvc_data + id * ctrl->info.size;
-}
-
-static inline int uvc_test_bit(const __u8 *data, int bit)
-{
- return (data[bit >> 3] >> (bit & 7)) & 1;
-}
-
-static inline void uvc_clear_bit(__u8 *data, int bit)
-{
- data[bit >> 3] &= ~(1 << (bit & 7));
-}
-
-/* Extract the bit string specified by mapping->offset and mapping->size
- * from the little-endian data stored at 'data' and return the result as
- * a signed 32bit integer. Sign extension will be performed if the mapping
- * references a signed data type.
- */
-static __s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
- __u8 query, const __u8 *data)
-{
- int bits = mapping->size;
- int offset = mapping->offset;
- __s32 value = 0;
- __u8 mask;
-
- data += offset / 8;
- offset &= 7;
- mask = ((1LL << bits) - 1) << offset;
-
- for (; bits > 0; data++) {
- __u8 byte = *data & mask;
- value |= offset > 0 ? (byte >> offset) : (byte << (-offset));
- bits -= 8 - (offset > 0 ? offset : 0);
- offset -= 8;
- mask = (1 << bits) - 1;
- }
-
- /* Sign-extend the value if needed. */
- if (mapping->data_type == UVC_CTRL_DATA_TYPE_SIGNED)
- value |= -(value & (1 << (mapping->size - 1)));
-
- return value;
-}
-
-/* Set the bit string specified by mapping->offset and mapping->size
- * in the little-endian data stored at 'data' to the value 'value'.
- */
-static void uvc_set_le_value(struct uvc_control_mapping *mapping,
- __s32 value, __u8 *data)
-{
- int bits = mapping->size;
- int offset = mapping->offset;
- __u8 mask;
-
- /* According to the v4l2 spec, writing any value to a button control
- * should result in the action belonging to the button control being
- * triggered. UVC devices however want to see a 1 written -> override
- * value.
- */
- if (mapping->v4l2_type == V4L2_CTRL_TYPE_BUTTON)
- value = -1;
-
- data += offset / 8;
- offset &= 7;
-
- for (; bits > 0; data++) {
- mask = ((1LL << bits) - 1) << offset;
- *data = (*data & ~mask) | ((value << offset) & mask);
- value >>= offset ? offset : 8;
- bits -= 8 - offset;
- offset = 0;
- }
-}
-
-/* ------------------------------------------------------------------------
- * Terminal and unit management
- */
-
-static const __u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING;
-static const __u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA;
-static const __u8 uvc_media_transport_input_guid[16] =
- UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT;
-
-static int uvc_entity_match_guid(const struct uvc_entity *entity,
- const __u8 guid[16])
-{
- switch (UVC_ENTITY_TYPE(entity)) {
- case UVC_ITT_CAMERA:
- return memcmp(uvc_camera_guid, guid, 16) == 0;
-
- case UVC_ITT_MEDIA_TRANSPORT_INPUT:
- return memcmp(uvc_media_transport_input_guid, guid, 16) == 0;
-
- case UVC_VC_PROCESSING_UNIT:
- return memcmp(uvc_processing_guid, guid, 16) == 0;
-
- case UVC_VC_EXTENSION_UNIT:
- return memcmp(entity->extension.guidExtensionCode,
- guid, 16) == 0;
-
- default:
- return 0;
- }
-}
-
-/* ------------------------------------------------------------------------
- * UVC Controls
- */
-
-static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id,
- struct uvc_control_mapping **mapping, struct uvc_control **control,
- int next)
-{
- struct uvc_control *ctrl;
- struct uvc_control_mapping *map;
- unsigned int i;
-
- if (entity == NULL)
- return;
-
- for (i = 0; i < entity->ncontrols; ++i) {
- ctrl = &entity->controls[i];
- if (!ctrl->initialized)
- continue;
-
- list_for_each_entry(map, &ctrl->info.mappings, list) {
- if ((map->id == v4l2_id) && !next) {
- *control = ctrl;
- *mapping = map;
- return;
- }
-
- if ((*mapping == NULL || (*mapping)->id > map->id) &&
- (map->id > v4l2_id) && next) {
- *control = ctrl;
- *mapping = map;
- }
- }
- }
-}
-
-static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
- __u32 v4l2_id, struct uvc_control_mapping **mapping)
-{
- struct uvc_control *ctrl = NULL;
- struct uvc_entity *entity;
- int next = v4l2_id & V4L2_CTRL_FLAG_NEXT_CTRL;
-
- *mapping = NULL;
-
- /* Mask the query flags. */
- v4l2_id &= V4L2_CTRL_ID_MASK;
-
- /* Find the control. */
- list_for_each_entry(entity, &chain->entities, chain) {
- __uvc_find_control(entity, v4l2_id, mapping, &ctrl, next);
- if (ctrl && !next)
- return ctrl;
- }
-
- if (ctrl == NULL && !next)
- uvc_trace(UVC_TRACE_CONTROL, "Control 0x%08x not found.\n",
- v4l2_id);
-
- return ctrl;
-}
-
-static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
- struct uvc_control *ctrl)
-{
- int ret;
-
- if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
- ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info.selector,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF),
- ctrl->info.size);
- if (ret < 0)
- return ret;
- }
-
- if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN) {
- ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info.selector,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
- ctrl->info.size);
- if (ret < 0)
- return ret;
- }
- if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MAX) {
- ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info.selector,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
- ctrl->info.size);
- if (ret < 0)
- return ret;
- }
- if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES) {
- ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info.selector,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
- ctrl->info.size);
- if (ret < 0) {
- if (UVC_ENTITY_TYPE(ctrl->entity) !=
- UVC_VC_EXTENSION_UNIT)
- return ret;
-
- /* GET_RES is mandatory for XU controls, but some
- * cameras still choke on it. Ignore errors and set the
- * resolution value to zero.
- */
- uvc_warn_once(chain->dev, UVC_WARN_XU_GET_RES,
- "UVC non compliance - GET_RES failed on "
- "an XU control. Enabling workaround.\n");
- memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES), 0,
- ctrl->info.size);
- }
- }
-
- ctrl->cached = 1;
- return 0;
-}
-
-static int __uvc_ctrl_get(struct uvc_video_chain *chain,
- struct uvc_control *ctrl, struct uvc_control_mapping *mapping,
- s32 *value)
-{
- struct uvc_menu_info *menu;
- unsigned int i;
- int ret;
-
- if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0)
- return -EINVAL;
-
- if (!ctrl->loaded) {
- ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info.selector,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
- ctrl->info.size);
- if (ret < 0)
- return ret;
-
- ctrl->loaded = 1;
- }
-
- *value = mapping->get(mapping, UVC_GET_CUR,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
-
- if (mapping->v4l2_type == V4L2_CTRL_TYPE_MENU) {
- menu = mapping->menu_info;
- for (i = 0; i < mapping->menu_count; ++i, ++menu) {
- if (menu->value == *value) {
- *value = i;
- break;
- }
- }
- }
-
- return 0;
-}
-
-static int __uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
- struct uvc_control *ctrl,
- struct uvc_control_mapping *mapping,
- struct v4l2_queryctrl *v4l2_ctrl)
-{
- struct uvc_control_mapping *master_map = NULL;
- struct uvc_control *master_ctrl = NULL;
- struct uvc_menu_info *menu;
- unsigned int i;
-
- memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl);
- v4l2_ctrl->id = mapping->id;
- v4l2_ctrl->type = mapping->v4l2_type;
- strlcpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);
- v4l2_ctrl->flags = 0;
-
- if (!(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
- v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
- if (!(ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR))
- v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
-
- if (mapping->master_id)
- __uvc_find_control(ctrl->entity, mapping->master_id,
- &master_map, &master_ctrl, 0);
- if (master_ctrl && (master_ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR)) {
- s32 val;
- int ret = __uvc_ctrl_get(chain, master_ctrl, master_map, &val);
- if (ret < 0)
- return ret;
-
- if (val != mapping->master_manual)
- v4l2_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
- }
-
- if (!ctrl->cached) {
- int ret = uvc_ctrl_populate_cache(chain, ctrl);
- if (ret < 0)
- return ret;
- }
-
- if (ctrl->info.flags & UVC_CTRL_FLAG_GET_DEF) {
- v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
- }
-
- switch (mapping->v4l2_type) {
- case V4L2_CTRL_TYPE_MENU:
- v4l2_ctrl->minimum = 0;
- v4l2_ctrl->maximum = mapping->menu_count - 1;
- v4l2_ctrl->step = 1;
-
- menu = mapping->menu_info;
- for (i = 0; i < mapping->menu_count; ++i, ++menu) {
- if (menu->value == v4l2_ctrl->default_value) {
- v4l2_ctrl->default_value = i;
- break;
- }
- }
-
- return 0;
-
- case V4L2_CTRL_TYPE_BOOLEAN:
- v4l2_ctrl->minimum = 0;
- v4l2_ctrl->maximum = 1;
- v4l2_ctrl->step = 1;
- return 0;
-
- case V4L2_CTRL_TYPE_BUTTON:
- v4l2_ctrl->minimum = 0;
- v4l2_ctrl->maximum = 0;
- v4l2_ctrl->step = 0;
- return 0;
-
- default:
- break;
- }
-
- if (ctrl->info.flags & UVC_CTRL_FLAG_GET_MIN)
- 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)
- v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
-
- if (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)
- v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
-
- return 0;
-}
-
-int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
- struct v4l2_queryctrl *v4l2_ctrl)
-{
- struct uvc_control *ctrl;
- struct uvc_control_mapping *mapping;
- int ret;
-
- ret = mutex_lock_interruptible(&chain->ctrl_mutex);
- if (ret < 0)
- return -ERESTARTSYS;
-
- ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
- if (ctrl == NULL) {
- ret = -EINVAL;
- goto done;
- }
-
- ret = __uvc_query_v4l2_ctrl(chain, ctrl, mapping, v4l2_ctrl);
-done:
- mutex_unlock(&chain->ctrl_mutex);
- return ret;
-}
-
-/*
- * Mapping V4L2 controls to UVC controls can be straighforward if done well.
- * Most of the UVC controls exist in V4L2, and can be mapped directly. Some
- * must be grouped (for instance the Red Balance, Blue Balance and Do White
- * Balance V4L2 controls use the White Balance Component UVC control) or
- * otherwise translated. The approach we take here is to use a translation
- * table for the controls that can be mapped directly, and handle the others
- * manually.
- */
-int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
- struct v4l2_querymenu *query_menu)
-{
- struct uvc_menu_info *menu_info;
- struct uvc_control_mapping *mapping;
- struct uvc_control *ctrl;
- u32 index = query_menu->index;
- u32 id = query_menu->id;
- int ret;
-
- memset(query_menu, 0, sizeof(*query_menu));
- query_menu->id = id;
- query_menu->index = index;
-
- ret = mutex_lock_interruptible(&chain->ctrl_mutex);
- if (ret < 0)
- return -ERESTARTSYS;
-
- ctrl = uvc_find_control(chain, query_menu->id, &mapping);
- if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) {
- ret = -EINVAL;
- goto done;
- }
-
- if (query_menu->index >= mapping->menu_count) {
- ret = -EINVAL;
- goto done;
- }
-
- menu_info = &mapping->menu_info[query_menu->index];
-
- if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK &&
- (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)) {
- s32 bitmap;
-
- if (!ctrl->cached) {
- ret = uvc_ctrl_populate_cache(chain, ctrl);
- if (ret < 0)
- goto done;
- }
-
- bitmap = mapping->get(mapping, UVC_GET_RES,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
- if (!(bitmap & menu_info->value)) {
- ret = -EINVAL;
- goto done;
- }
- }
-
- strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
-
-done:
- mutex_unlock(&chain->ctrl_mutex);
- return ret;
-}
-
-/* --------------------------------------------------------------------------
- * Ctrl event handling
- */
-
-static void uvc_ctrl_fill_event(struct uvc_video_chain *chain,
- struct v4l2_event *ev,
- struct uvc_control *ctrl,
- struct uvc_control_mapping *mapping,
- s32 value, u32 changes)
-{
- struct v4l2_queryctrl v4l2_ctrl;
-
- __uvc_query_v4l2_ctrl(chain, ctrl, mapping, &v4l2_ctrl);
-
- memset(ev->reserved, 0, sizeof(ev->reserved));
- ev->type = V4L2_EVENT_CTRL;
- ev->id = v4l2_ctrl.id;
- ev->u.ctrl.value = value;
- ev->u.ctrl.changes = changes;
- ev->u.ctrl.type = v4l2_ctrl.type;
- ev->u.ctrl.flags = v4l2_ctrl.flags;
- ev->u.ctrl.minimum = v4l2_ctrl.minimum;
- ev->u.ctrl.maximum = v4l2_ctrl.maximum;
- ev->u.ctrl.step = v4l2_ctrl.step;
- ev->u.ctrl.default_value = v4l2_ctrl.default_value;
-}
-
-static void uvc_ctrl_send_event(struct uvc_fh *handle,
- struct uvc_control *ctrl, struct uvc_control_mapping *mapping,
- s32 value, u32 changes)
-{
- struct v4l2_subscribed_event *sev;
- struct v4l2_event ev;
-
- if (list_empty(&mapping->ev_subs))
- return;
-
- uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, value, changes);
-
- list_for_each_entry(sev, &mapping->ev_subs, node) {
- if (sev->fh && (sev->fh != &handle->vfh ||
- (sev->flags & V4L2_EVENT_SUB_FL_ALLOW_FEEDBACK) ||
- (changes & V4L2_EVENT_CTRL_CH_FLAGS)))
- v4l2_event_queue_fh(sev->fh, &ev);
- }
-}
-
-static void uvc_ctrl_send_slave_event(struct uvc_fh *handle,
- struct uvc_control *master, u32 slave_id,
- const struct v4l2_ext_control *xctrls, unsigned int xctrls_count)
-{
- struct uvc_control_mapping *mapping = NULL;
- struct uvc_control *ctrl = NULL;
- u32 changes = V4L2_EVENT_CTRL_CH_FLAGS;
- unsigned int i;
- s32 val = 0;
-
- /*
- * We can skip sending an event for the slave if the slave
- * is being modified in the same transaction.
- */
- for (i = 0; i < xctrls_count; i++) {
- if (xctrls[i].id == slave_id)
- return;
- }
-
- __uvc_find_control(master->entity, slave_id, &mapping, &ctrl, 0);
- if (ctrl == NULL)
- return;
-
- if (__uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0)
- changes |= V4L2_EVENT_CTRL_CH_VALUE;
-
- uvc_ctrl_send_event(handle, ctrl, mapping, val, changes);
-}
-
-static void uvc_ctrl_send_events(struct uvc_fh *handle,
- const struct v4l2_ext_control *xctrls, unsigned int xctrls_count)
-{
- struct uvc_control_mapping *mapping;
- struct uvc_control *ctrl;
- u32 changes = V4L2_EVENT_CTRL_CH_VALUE;
- unsigned int i;
- unsigned int j;
-
- for (i = 0; i < xctrls_count; ++i) {
- ctrl = uvc_find_control(handle->chain, xctrls[i].id, &mapping);
-
- for (j = 0; j < ARRAY_SIZE(mapping->slave_ids); ++j) {
- if (!mapping->slave_ids[j])
- break;
- uvc_ctrl_send_slave_event(handle, ctrl,
- mapping->slave_ids[j],
- xctrls, xctrls_count);
- }
-
- /*
- * If the master is being modified in the same transaction
- * flags may change too.
- */
- if (mapping->master_id) {
- for (j = 0; j < xctrls_count; j++) {
- if (xctrls[j].id == mapping->master_id) {
- changes |= V4L2_EVENT_CTRL_CH_FLAGS;
- break;
- }
- }
- }
-
- uvc_ctrl_send_event(handle, ctrl, mapping, xctrls[i].value,
- changes);
- }
-}
-
-static int uvc_ctrl_add_event(struct v4l2_subscribed_event *sev, unsigned elems)
-{
- struct uvc_fh *handle = container_of(sev->fh, struct uvc_fh, vfh);
- struct uvc_control_mapping *mapping;
- struct uvc_control *ctrl;
- int ret;
-
- ret = mutex_lock_interruptible(&handle->chain->ctrl_mutex);
- if (ret < 0)
- return -ERESTARTSYS;
-
- ctrl = uvc_find_control(handle->chain, sev->id, &mapping);
- if (ctrl == NULL) {
- ret = -EINVAL;
- goto done;
- }
-
- list_add_tail(&sev->node, &mapping->ev_subs);
- if (sev->flags & V4L2_EVENT_SUB_FL_SEND_INITIAL) {
- struct v4l2_event ev;
- u32 changes = V4L2_EVENT_CTRL_CH_FLAGS;
- s32 val = 0;
-
- if (__uvc_ctrl_get(handle->chain, ctrl, mapping, &val) == 0)
- changes |= V4L2_EVENT_CTRL_CH_VALUE;
-
- uvc_ctrl_fill_event(handle->chain, &ev, ctrl, mapping, val,
- changes);
- /* Mark the queue as active, allowing this initial
- event to be accepted. */
- sev->elems = elems;
- v4l2_event_queue_fh(sev->fh, &ev);
- }
-
-done:
- mutex_unlock(&handle->chain->ctrl_mutex);
- return ret;
-}
-
-static void uvc_ctrl_del_event(struct v4l2_subscribed_event *sev)
-{
- struct uvc_fh *handle = container_of(sev->fh, struct uvc_fh, vfh);
-
- mutex_lock(&handle->chain->ctrl_mutex);
- list_del(&sev->node);
- mutex_unlock(&handle->chain->ctrl_mutex);
-}
-
-const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops = {
- .add = uvc_ctrl_add_event,
- .del = uvc_ctrl_del_event,
- .replace = v4l2_ctrl_replace,
- .merge = v4l2_ctrl_merge,
-};
-
-/* --------------------------------------------------------------------------
- * Control transactions
- *
- * To make extended set operations as atomic as the hardware allows, controls
- * are handled using begin/commit/rollback operations.
- *
- * At the beginning of a set request, uvc_ctrl_begin should be called to
- * initialize the request. This function acquires the control lock.
- *
- * When setting a control, the new value is stored in the control data field
- * at position UVC_CTRL_DATA_CURRENT. The control is then marked as dirty for
- * later processing. If the UVC and V4L2 control sizes differ, the current
- * value is loaded from the hardware before storing the new value in the data
- * field.
- *
- * After processing all controls in the transaction, uvc_ctrl_commit or
- * uvc_ctrl_rollback must be called to apply the pending changes to the
- * hardware or revert them. When applying changes, all controls marked as
- * dirty will be modified in the UVC device, and the dirty flag will be
- * cleared. When reverting controls, the control data field
- * UVC_CTRL_DATA_CURRENT is reverted to its previous value
- * (UVC_CTRL_DATA_BACKUP) for all dirty controls. Both functions release the
- * control lock.
- */
-int uvc_ctrl_begin(struct uvc_video_chain *chain)
-{
- return mutex_lock_interruptible(&chain->ctrl_mutex) ? -ERESTARTSYS : 0;
-}
-
-static int uvc_ctrl_commit_entity(struct uvc_device *dev,
- struct uvc_entity *entity, int rollback)
-{
- struct uvc_control *ctrl;
- unsigned int i;
- int ret;
-
- if (entity == NULL)
- return 0;
-
- for (i = 0; i < entity->ncontrols; ++i) {
- ctrl = &entity->controls[i];
- if (!ctrl->initialized)
- continue;
-
- /* Reset the loaded flag for auto-update controls that were
- * marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent
- * uvc_ctrl_get from using the cached value, and for write-only
- * controls to prevent uvc_ctrl_set from setting bits not
- * explicitly set by the user.
- */
- if (ctrl->info.flags & UVC_CTRL_FLAG_AUTO_UPDATE ||
- !(ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR))
- ctrl->loaded = 0;
-
- if (!ctrl->dirty)
- continue;
-
- if (!rollback)
- ret = uvc_query_ctrl(dev, UVC_SET_CUR, ctrl->entity->id,
- dev->intfnum, ctrl->info.selector,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
- ctrl->info.size);
- else
- ret = 0;
-
- if (rollback || ret < 0)
- memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
- ctrl->info.size);
-
- ctrl->dirty = 0;
-
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
-
-int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
- const struct v4l2_ext_control *xctrls,
- unsigned int xctrls_count)
-{
- struct uvc_video_chain *chain = handle->chain;
- struct uvc_entity *entity;
- int ret = 0;
-
- /* Find the control. */
- list_for_each_entry(entity, &chain->entities, chain) {
- ret = uvc_ctrl_commit_entity(chain->dev, entity, rollback);
- if (ret < 0)
- goto done;
- }
-
- if (!rollback)
- uvc_ctrl_send_events(handle, xctrls, xctrls_count);
-done:
- mutex_unlock(&chain->ctrl_mutex);
- return ret;
-}
-
-int uvc_ctrl_get(struct uvc_video_chain *chain,
- struct v4l2_ext_control *xctrl)
-{
- struct uvc_control *ctrl;
- struct uvc_control_mapping *mapping;
-
- ctrl = uvc_find_control(chain, xctrl->id, &mapping);
- if (ctrl == NULL)
- return -EINVAL;
-
- return __uvc_ctrl_get(chain, ctrl, mapping, &xctrl->value);
-}
-
-int uvc_ctrl_set(struct uvc_video_chain *chain,
- struct v4l2_ext_control *xctrl)
-{
- struct uvc_control *ctrl;
- struct uvc_control_mapping *mapping;
- s32 value;
- u32 step;
- s32 min;
- s32 max;
- int ret;
-
- ctrl = uvc_find_control(chain, xctrl->id, &mapping);
- if (ctrl == NULL || (ctrl->info.flags & UVC_CTRL_FLAG_SET_CUR) == 0)
- return -EINVAL;
-
- /* Clamp out of range values. */
- switch (mapping->v4l2_type) {
- case V4L2_CTRL_TYPE_INTEGER:
- if (!ctrl->cached) {
- ret = uvc_ctrl_populate_cache(chain, ctrl);
- if (ret < 0)
- return ret;
- }
-
- min = mapping->get(mapping, UVC_GET_MIN,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
- max = mapping->get(mapping, UVC_GET_MAX,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
- step = mapping->get(mapping, UVC_GET_RES,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
- if (step == 0)
- step = 1;
-
- xctrl->value = min + (xctrl->value - min + step/2) / step * step;
- xctrl->value = clamp(xctrl->value, min, max);
- value = xctrl->value;
- break;
-
- case V4L2_CTRL_TYPE_BOOLEAN:
- xctrl->value = clamp(xctrl->value, 0, 1);
- value = xctrl->value;
- break;
-
- case V4L2_CTRL_TYPE_MENU:
- if (xctrl->value < 0 || xctrl->value >= mapping->menu_count)
- return -ERANGE;
- value = mapping->menu_info[xctrl->value].value;
-
- /* Valid menu indices are reported by the GET_RES request for
- * UVC controls that support it.
- */
- if (mapping->data_type == UVC_CTRL_DATA_TYPE_BITMASK &&
- (ctrl->info.flags & UVC_CTRL_FLAG_GET_RES)) {
- if (!ctrl->cached) {
- ret = uvc_ctrl_populate_cache(chain, ctrl);
- if (ret < 0)
- return ret;
- }
-
- step = mapping->get(mapping, UVC_GET_RES,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
- if (!(step & value))
- return -ERANGE;
- }
-
- break;
-
- default:
- value = xctrl->value;
- break;
- }
-
- /* If the mapping doesn't span the whole UVC control, the current value
- * needs to be loaded from the device to perform the read-modify-write
- * operation.
- */
- if (!ctrl->loaded && (ctrl->info.size * 8) != mapping->size) {
- if ((ctrl->info.flags & UVC_CTRL_FLAG_GET_CUR) == 0) {
- memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
- 0, ctrl->info.size);
- } else {
- ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR,
- ctrl->entity->id, chain->dev->intfnum,
- ctrl->info.selector,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
- ctrl->info.size);
- if (ret < 0)
- return ret;
- }
-
- ctrl->loaded = 1;
- }
-
- /* Backup the current value in case we need to rollback later. */
- if (!ctrl->dirty) {
- memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
- ctrl->info.size);
- }
-
- mapping->set(mapping, value,
- uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT));
-
- ctrl->dirty = 1;
- ctrl->modified = 1;
- return 0;
-}
-
-/* --------------------------------------------------------------------------
- * Dynamic controls
- */
-
-static void uvc_ctrl_fixup_xu_info(struct uvc_device *dev,
- const struct uvc_control *ctrl, struct uvc_control_info *info)
-{
- struct uvc_ctrl_fixup {
- struct usb_device_id id;
- u8 entity;
- u8 selector;
- u8 flags;
- };
-
- static const struct uvc_ctrl_fixup fixups[] = {
- { { USB_DEVICE(0x046d, 0x08c2) }, 9, 1,
- UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX |
- UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR |
- UVC_CTRL_FLAG_AUTO_UPDATE },
- { { USB_DEVICE(0x046d, 0x08cc) }, 9, 1,
- UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX |
- UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR |
- UVC_CTRL_FLAG_AUTO_UPDATE },
- { { USB_DEVICE(0x046d, 0x0994) }, 9, 1,
- UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX |
- UVC_CTRL_FLAG_GET_DEF | UVC_CTRL_FLAG_SET_CUR |
- UVC_CTRL_FLAG_AUTO_UPDATE },
- };
-
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(fixups); ++i) {
- if (!usb_match_one_id(dev->intf, &fixups[i].id))
- continue;
-
- if (fixups[i].entity == ctrl->entity->id &&
- fixups[i].selector == info->selector) {
- info->flags = fixups[i].flags;
- return;
- }
- }
-}
-
-/*
- * Query control information (size and flags) for XU controls.
- */
-static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
- const struct uvc_control *ctrl, struct uvc_control_info *info)
-{
- u8 *data;
- int ret;
-
- data = kmalloc(2, GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
-
- memcpy(info->entity, ctrl->entity->extension.guidExtensionCode,
- sizeof(info->entity));
- info->index = ctrl->index;
- info->selector = ctrl->index + 1;
-
- /* Query and verify the control length (GET_LEN) */
- ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id, dev->intfnum,
- info->selector, data, 2);
- if (ret < 0) {
- uvc_trace(UVC_TRACE_CONTROL,
- "GET_LEN failed on control %pUl/%u (%d).\n",
- info->entity, info->selector, ret);
- goto done;
- }
-
- info->size = le16_to_cpup((__le16 *)data);
-
- /* Query the control information (GET_INFO) */
- ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
- info->selector, data, 1);
- if (ret < 0) {
- uvc_trace(UVC_TRACE_CONTROL,
- "GET_INFO failed on control %pUl/%u (%d).\n",
- info->entity, info->selector, ret);
- goto done;
- }
-
- info->flags = UVC_CTRL_FLAG_GET_MIN | UVC_CTRL_FLAG_GET_MAX
- | UVC_CTRL_FLAG_GET_RES | UVC_CTRL_FLAG_GET_DEF
- | (data[0] & UVC_CONTROL_CAP_GET ?
- UVC_CTRL_FLAG_GET_CUR : 0)
- | (data[0] & UVC_CONTROL_CAP_SET ?
- UVC_CTRL_FLAG_SET_CUR : 0)
- | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
- UVC_CTRL_FLAG_AUTO_UPDATE : 0);
-
- uvc_ctrl_fixup_xu_info(dev, ctrl, info);
-
- uvc_trace(UVC_TRACE_CONTROL, "XU control %pUl/%u queried: len %u, "
- "flags { get %u set %u auto %u }.\n",
- info->entity, info->selector, info->size,
- (info->flags & UVC_CTRL_FLAG_GET_CUR) ? 1 : 0,
- (info->flags & UVC_CTRL_FLAG_SET_CUR) ? 1 : 0,
- (info->flags & UVC_CTRL_FLAG_AUTO_UPDATE) ? 1 : 0);
-
-done:
- kfree(data);
- return ret;
-}
-
-static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
- const struct uvc_control_info *info);
-
-static int uvc_ctrl_init_xu_ctrl(struct uvc_device *dev,
- struct uvc_control *ctrl)
-{
- struct uvc_control_info info;
- int ret;
-
- if (ctrl->initialized)
- return 0;
-
- ret = uvc_ctrl_fill_xu_info(dev, ctrl, &info);
- if (ret < 0)
- return ret;
-
- ret = uvc_ctrl_add_info(dev, ctrl, &info);
- if (ret < 0)
- uvc_trace(UVC_TRACE_CONTROL, "Failed to initialize control "
- "%pUl/%u on device %s entity %u\n", info.entity,
- info.selector, dev->udev->devpath, ctrl->entity->id);
-
- return ret;
-}
-
-int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
- struct uvc_xu_control_query *xqry)
-{
- struct uvc_entity *entity;
- struct uvc_control *ctrl;
- unsigned int i, found = 0;
- __u32 reqflags;
- __u16 size;
- __u8 *data = NULL;
- int ret;
-
- /* Find the extension unit. */
- list_for_each_entry(entity, &chain->entities, chain) {
- if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT &&
- entity->id == xqry->unit)
- break;
- }
-
- if (entity->id != xqry->unit) {
- uvc_trace(UVC_TRACE_CONTROL, "Extension unit %u not found.\n",
- xqry->unit);
- return -ENOENT;
- }
-
- /* Find the control and perform delayed initialization if needed. */
- for (i = 0; i < entity->ncontrols; ++i) {
- ctrl = &entity->controls[i];
- if (ctrl->index == xqry->selector - 1) {
- found = 1;
- break;
- }
- }
-
- if (!found) {
- uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u not found.\n",
- entity->extension.guidExtensionCode, xqry->selector);
- return -ENOENT;
- }
-
- if (mutex_lock_interruptible(&chain->ctrl_mutex))
- return -ERESTARTSYS;
-
- ret = uvc_ctrl_init_xu_ctrl(chain->dev, ctrl);
- if (ret < 0) {
- ret = -ENOENT;
- goto done;
- }
-
- /* Validate the required buffer size and flags for the request */
- reqflags = 0;
- size = ctrl->info.size;
-
- switch (xqry->query) {
- case UVC_GET_CUR:
- reqflags = UVC_CTRL_FLAG_GET_CUR;
- break;
- case UVC_GET_MIN:
- reqflags = UVC_CTRL_FLAG_GET_MIN;
- break;
- case UVC_GET_MAX:
- reqflags = UVC_CTRL_FLAG_GET_MAX;
- break;
- case UVC_GET_DEF:
- reqflags = UVC_CTRL_FLAG_GET_DEF;
- break;
- case UVC_GET_RES:
- reqflags = UVC_CTRL_FLAG_GET_RES;
- break;
- case UVC_SET_CUR:
- reqflags = UVC_CTRL_FLAG_SET_CUR;
- break;
- case UVC_GET_LEN:
- size = 2;
- break;
- case UVC_GET_INFO:
- size = 1;
- break;
- default:
- ret = -EINVAL;
- goto done;
- }
-
- if (size != xqry->size) {
- ret = -ENOBUFS;
- goto done;
- }
-
- if (reqflags && !(ctrl->info.flags & reqflags)) {
- ret = -EBADRQC;
- goto done;
- }
-
- data = kmalloc(size, GFP_KERNEL);
- if (data == NULL) {
- ret = -ENOMEM;
- goto done;
- }
-
- if (xqry->query == UVC_SET_CUR &&
- copy_from_user(data, xqry->data, size)) {
- ret = -EFAULT;
- goto done;
- }
-
- ret = uvc_query_ctrl(chain->dev, xqry->query, xqry->unit,
- chain->dev->intfnum, xqry->selector, data, size);
- if (ret < 0)
- goto done;
-
- if (xqry->query != UVC_SET_CUR &&
- copy_to_user(xqry->data, data, size))
- ret = -EFAULT;
-done:
- kfree(data);
- mutex_unlock(&chain->ctrl_mutex);
- return ret;
-}
-
-/* --------------------------------------------------------------------------
- * Suspend/resume
- */
-
-/*
- * Restore control values after resume, skipping controls that haven't been
- * changed.
- *
- * TODO
- * - Don't restore modified controls that are back to their default value.
- * - Handle restore order (Auto-Exposure Mode should be restored before
- * Exposure Time).
- */
-int uvc_ctrl_resume_device(struct uvc_device *dev)
-{
- struct uvc_control *ctrl;
- struct uvc_entity *entity;
- unsigned int i;
- int ret;
-
- /* Walk the entities list and restore controls when possible. */
- list_for_each_entry(entity, &dev->entities, list) {
-
- for (i = 0; i < entity->ncontrols; ++i) {
- ctrl = &entity->controls[i];
-
- if (!ctrl->initialized || !ctrl->modified ||
- (ctrl->info.flags & UVC_CTRL_FLAG_RESTORE) == 0)
- continue;
-
- printk(KERN_INFO "restoring control %pUl/%u/%u\n",
- ctrl->info.entity, ctrl->info.index,
- ctrl->info.selector);
- ctrl->dirty = 1;
- }
-
- ret = uvc_ctrl_commit_entity(dev, entity, 0);
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
-
-/* --------------------------------------------------------------------------
- * Control and mapping handling
- */
-
-/*
- * Add control information to a given control.
- */
-static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
- const struct uvc_control_info *info)
-{
- int ret = 0;
-
- memcpy(&ctrl->info, info, sizeof(*info));
- INIT_LIST_HEAD(&ctrl->info.mappings);
-
- /* Allocate an array to save control values (cur, def, max, etc.) */
- ctrl->uvc_data = kzalloc(ctrl->info.size * UVC_CTRL_DATA_LAST + 1,
- GFP_KERNEL);
- if (ctrl->uvc_data == NULL) {
- ret = -ENOMEM;
- goto done;
- }
-
- ctrl->initialized = 1;
-
- uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "
- "entity %u\n", ctrl->info.entity, ctrl->info.selector,
- dev->udev->devpath, ctrl->entity->id);
-
-done:
- if (ret < 0)
- kfree(ctrl->uvc_data);
- return ret;
-}
-
-/*
- * Add a control mapping to a given control.
- */
-static int __uvc_ctrl_add_mapping(struct uvc_device *dev,
- struct uvc_control *ctrl, const struct uvc_control_mapping *mapping)
-{
- struct uvc_control_mapping *map;
- unsigned int size;
-
- /* Most mappings come from static kernel data and need to be duplicated.
- * Mappings that come from userspace will be unnecessarily duplicated,
- * this could be optimized.
- */
- map = kmemdup(mapping, sizeof(*mapping), GFP_KERNEL);
- if (map == NULL)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&map->ev_subs);
-
- size = sizeof(*mapping->menu_info) * mapping->menu_count;
- map->menu_info = kmemdup(mapping->menu_info, size, GFP_KERNEL);
- if (map->menu_info == NULL) {
- kfree(map);
- return -ENOMEM;
- }
-
- if (map->get == NULL)
- map->get = uvc_get_le_value;
- if (map->set == NULL)
- map->set = uvc_set_le_value;
-
- list_add_tail(&map->list, &ctrl->info.mappings);
- uvc_trace(UVC_TRACE_CONTROL,
- "Adding mapping '%s' to control %pUl/%u.\n",
- map->name, ctrl->info.entity, ctrl->info.selector);
-
- return 0;
-}
-
-int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
- const struct uvc_control_mapping *mapping)
-{
- struct uvc_device *dev = chain->dev;
- struct uvc_control_mapping *map;
- struct uvc_entity *entity;
- struct uvc_control *ctrl;
- int found = 0;
- int ret;
-
- if (mapping->id & ~V4L2_CTRL_ID_MASK) {
- uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', control "
- "id 0x%08x is invalid.\n", mapping->name,
- mapping->id);
- return -EINVAL;
- }
-
- /* Search for the matching (GUID/CS) control on the current chain */
- list_for_each_entry(entity, &chain->entities, chain) {
- unsigned int i;
-
- if (UVC_ENTITY_TYPE(entity) != UVC_VC_EXTENSION_UNIT ||
- !uvc_entity_match_guid(entity, mapping->entity))
- continue;
-
- for (i = 0; i < entity->ncontrols; ++i) {
- ctrl = &entity->controls[i];
- if (ctrl->index == mapping->selector - 1) {
- found = 1;
- break;
- }
- }
-
- if (found)
- break;
- }
- if (!found)
- return -ENOENT;
-
- if (mutex_lock_interruptible(&chain->ctrl_mutex))
- return -ERESTARTSYS;
-
- /* Perform delayed initialization of XU controls */
- ret = uvc_ctrl_init_xu_ctrl(dev, ctrl);
- if (ret < 0) {
- ret = -ENOENT;
- goto done;
- }
-
- list_for_each_entry(map, &ctrl->info.mappings, list) {
- if (mapping->id == map->id) {
- uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', "
- "control id 0x%08x already exists.\n",
- mapping->name, mapping->id);
- ret = -EEXIST;
- goto done;
- }
- }
-
- /* Prevent excess memory consumption */
- if (atomic_inc_return(&dev->nmappings) > UVC_MAX_CONTROL_MAPPINGS) {
- atomic_dec(&dev->nmappings);
- uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', maximum "
- "mappings count (%u) exceeded.\n", mapping->name,
- UVC_MAX_CONTROL_MAPPINGS);
- ret = -ENOMEM;
- goto done;
- }
-
- ret = __uvc_ctrl_add_mapping(dev, ctrl, mapping);
- if (ret < 0)
- atomic_dec(&dev->nmappings);
-
-done:
- mutex_unlock(&chain->ctrl_mutex);
- return ret;
-}
-
-/*
- * Prune an entity of its bogus controls using a blacklist. Bogus controls
- * are currently the ones that crash the camera or unconditionally return an
- * error when queried.
- */
-static void uvc_ctrl_prune_entity(struct uvc_device *dev,
- struct uvc_entity *entity)
-{
- struct uvc_ctrl_blacklist {
- struct usb_device_id id;
- u8 index;
- };
-
- static const struct uvc_ctrl_blacklist processing_blacklist[] = {
- { { USB_DEVICE(0x13d3, 0x509b) }, 9 }, /* Gain */
- { { USB_DEVICE(0x1c4f, 0x3000) }, 6 }, /* WB Temperature */
- { { USB_DEVICE(0x5986, 0x0241) }, 2 }, /* Hue */
- };
- static const struct uvc_ctrl_blacklist camera_blacklist[] = {
- { { USB_DEVICE(0x06f8, 0x3005) }, 9 }, /* Zoom, Absolute */
- };
-
- const struct uvc_ctrl_blacklist *blacklist;
- unsigned int size;
- unsigned int count;
- unsigned int i;
- u8 *controls;
-
- switch (UVC_ENTITY_TYPE(entity)) {
- case UVC_VC_PROCESSING_UNIT:
- blacklist = processing_blacklist;
- count = ARRAY_SIZE(processing_blacklist);
- controls = entity->processing.bmControls;
- size = entity->processing.bControlSize;
- break;
-
- case UVC_ITT_CAMERA:
- blacklist = camera_blacklist;
- count = ARRAY_SIZE(camera_blacklist);
- controls = entity->camera.bmControls;
- size = entity->camera.bControlSize;
- break;
-
- default:
- return;
- }
-
- for (i = 0; i < count; ++i) {
- if (!usb_match_one_id(dev->intf, &blacklist[i].id))
- continue;
-
- if (blacklist[i].index >= 8 * size ||
- !uvc_test_bit(controls, blacklist[i].index))
- continue;
-
- uvc_trace(UVC_TRACE_CONTROL, "%u/%u control is black listed, "
- "removing it.\n", entity->id, blacklist[i].index);
-
- uvc_clear_bit(controls, blacklist[i].index);
- }
-}
-
-/*
- * Add control information and hardcoded stock control mappings to the given
- * device.
- */
-static void uvc_ctrl_init_ctrl(struct uvc_device *dev, struct uvc_control *ctrl)
-{
- const struct uvc_control_info *info = uvc_ctrls;
- const struct uvc_control_info *iend = info + ARRAY_SIZE(uvc_ctrls);
- const struct uvc_control_mapping *mapping = uvc_ctrl_mappings;
- const struct uvc_control_mapping *mend =
- mapping + ARRAY_SIZE(uvc_ctrl_mappings);
-
- /* XU controls initialization requires querying the device for control
- * information. As some buggy UVC devices will crash when queried
- * repeatedly in a tight loop, delay XU controls initialization until
- * first use.
- */
- if (UVC_ENTITY_TYPE(ctrl->entity) == UVC_VC_EXTENSION_UNIT)
- return;
-
- for (; info < iend; ++info) {
- if (uvc_entity_match_guid(ctrl->entity, info->entity) &&
- ctrl->index == info->index) {
- uvc_ctrl_add_info(dev, ctrl, info);
- break;
- }
- }
-
- if (!ctrl->initialized)
- return;
-
- for (; mapping < mend; ++mapping) {
- if (uvc_entity_match_guid(ctrl->entity, mapping->entity) &&
- ctrl->info.selector == mapping->selector)
- __uvc_ctrl_add_mapping(dev, ctrl, mapping);
- }
-}
-
-/*
- * Initialize device controls.
- */
-int uvc_ctrl_init_device(struct uvc_device *dev)
-{
- struct uvc_entity *entity;
- unsigned int i;
-
- /* Walk the entities list and instantiate controls */
- list_for_each_entry(entity, &dev->entities, list) {
- struct uvc_control *ctrl;
- unsigned int bControlSize = 0, ncontrols;
- __u8 *bmControls = NULL;
-
- if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) {
- bmControls = entity->extension.bmControls;
- bControlSize = entity->extension.bControlSize;
- } else if (UVC_ENTITY_TYPE(entity) == UVC_VC_PROCESSING_UNIT) {
- bmControls = entity->processing.bmControls;
- bControlSize = entity->processing.bControlSize;
- } else if (UVC_ENTITY_TYPE(entity) == UVC_ITT_CAMERA) {
- bmControls = entity->camera.bmControls;
- bControlSize = entity->camera.bControlSize;
- }
-
- /* Remove bogus/blacklisted controls */
- uvc_ctrl_prune_entity(dev, entity);
-
- /* Count supported controls and allocate the controls array */
- ncontrols = memweight(bmControls, bControlSize);
- if (ncontrols == 0)
- continue;
-
- entity->controls = kcalloc(ncontrols, sizeof(*ctrl),
- GFP_KERNEL);
- if (entity->controls == NULL)
- return -ENOMEM;
- entity->ncontrols = ncontrols;
-
- /* Initialize all supported controls */
- ctrl = entity->controls;
- for (i = 0; i < bControlSize * 8; ++i) {
- if (uvc_test_bit(bmControls, i) == 0)
- continue;
-
- ctrl->entity = entity;
- ctrl->index = i;
-
- uvc_ctrl_init_ctrl(dev, ctrl);
- ctrl++;
- }
- }
-
- return 0;
-}
-
-/*
- * Cleanup device controls.
- */
-static void uvc_ctrl_cleanup_mappings(struct uvc_device *dev,
- struct uvc_control *ctrl)
-{
- struct uvc_control_mapping *mapping, *nm;
-
- list_for_each_entry_safe(mapping, nm, &ctrl->info.mappings, list) {
- list_del(&mapping->list);
- kfree(mapping->menu_info);
- kfree(mapping);
- }
-}
-
-void uvc_ctrl_cleanup_device(struct uvc_device *dev)
-{
- struct uvc_entity *entity;
- unsigned int i;
-
- /* Free controls and control mappings for all entities. */
- list_for_each_entry(entity, &dev->entities, list) {
- for (i = 0; i < entity->ncontrols; ++i) {
- struct uvc_control *ctrl = &entity->controls[i];
-
- if (!ctrl->initialized)
- continue;
-
- uvc_ctrl_cleanup_mappings(dev, ctrl);
- kfree(ctrl->uvc_data);
- }
-
- kfree(entity->controls);
- }
-}
diff --git a/drivers/media/video/uvc/uvc_debugfs.c b/drivers/media/video/uvc/uvc_debugfs.c
deleted file mode 100644
index 14561a5abb7..00000000000
--- a/drivers/media/video/uvc/uvc_debugfs.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * uvc_debugfs.c -- USB Video Class driver - Debugging support
- *
- * Copyright (C) 2011
- * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-#include <linux/module.h>
-#include <linux/debugfs.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-
-#include "uvcvideo.h"
-
-/* -----------------------------------------------------------------------------
- * Statistics
- */
-
-#define UVC_DEBUGFS_BUF_SIZE 1024
-
-struct uvc_debugfs_buffer {
- size_t count;
- char data[UVC_DEBUGFS_BUF_SIZE];
-};
-
-static int uvc_debugfs_stats_open(struct inode *inode, struct file *file)
-{
- struct uvc_streaming *stream = inode->i_private;
- struct uvc_debugfs_buffer *buf;
-
- buf = kmalloc(sizeof(*buf), GFP_KERNEL);
- if (buf == NULL)
- return -ENOMEM;
-
- buf->count = uvc_video_stats_dump(stream, buf->data, sizeof(buf->data));
-
- file->private_data = buf;
- return 0;
-}
-
-static ssize_t uvc_debugfs_stats_read(struct file *file, char __user *user_buf,
- size_t nbytes, loff_t *ppos)
-{
- struct uvc_debugfs_buffer *buf = file->private_data;
-
- return simple_read_from_buffer(user_buf, nbytes, ppos, buf->data,
- buf->count);
-}
-
-static int uvc_debugfs_stats_release(struct inode *inode, struct file *file)
-{
- kfree(file->private_data);
- file->private_data = NULL;
-
- return 0;
-}
-
-static const struct file_operations uvc_debugfs_stats_fops = {
- .owner = THIS_MODULE,
- .open = uvc_debugfs_stats_open,
- .llseek = no_llseek,
- .read = uvc_debugfs_stats_read,
- .release = uvc_debugfs_stats_release,
-};
-
-/* -----------------------------------------------------------------------------
- * Global and stream initialization/cleanup
- */
-
-static struct dentry *uvc_debugfs_root_dir;
-
-int uvc_debugfs_init_stream(struct uvc_streaming *stream)
-{
- struct usb_device *udev = stream->dev->udev;
- struct dentry *dent;
- char dir_name[32];
-
- if (uvc_debugfs_root_dir == NULL)
- return -ENODEV;
-
- sprintf(dir_name, "%u-%u", udev->bus->busnum, udev->devnum);
-
- dent = debugfs_create_dir(dir_name, uvc_debugfs_root_dir);
- if (IS_ERR_OR_NULL(dent)) {
- uvc_printk(KERN_INFO, "Unable to create debugfs %s "
- "directory.\n", dir_name);
- return -ENODEV;
- }
-
- stream->debugfs_dir = dent;
-
- dent = debugfs_create_file("stats", 0444, stream->debugfs_dir,
- stream, &uvc_debugfs_stats_fops);
- if (IS_ERR_OR_NULL(dent)) {
- uvc_printk(KERN_INFO, "Unable to create debugfs stats file.\n");
- uvc_debugfs_cleanup_stream(stream);
- return -ENODEV;
- }
-
- return 0;
-}
-
-void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream)
-{
- if (stream->debugfs_dir == NULL)
- return;
-
- debugfs_remove_recursive(stream->debugfs_dir);
- stream->debugfs_dir = NULL;
-}
-
-int uvc_debugfs_init(void)
-{
- struct dentry *dir;
-
- dir = debugfs_create_dir("uvcvideo", usb_debug_root);
- if (IS_ERR_OR_NULL(dir)) {
- uvc_printk(KERN_INFO, "Unable to create debugfs directory\n");
- return -ENODATA;
- }
-
- uvc_debugfs_root_dir = dir;
- return 0;
-}
-
-void uvc_debugfs_cleanup(void)
-{
- if (uvc_debugfs_root_dir != NULL)
- debugfs_remove_recursive(uvc_debugfs_root_dir);
-}
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
deleted file mode 100644
index 45d7aa162d9..00000000000
--- a/drivers/media/video/uvc/uvc_driver.c
+++ /dev/null
@@ -1,2472 +0,0 @@
-/*
- * uvc_driver.c -- USB Video Class driver
- *
- * Copyright (C) 2005-2010
- * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-/*
- * This driver aims to support video input and ouput devices compliant with the
- * 'USB Video Class' specification.
- *
- * The driver doesn't support the deprecated v4l1 interface. It implements the
- * mmap capture method only, and doesn't do any image format conversion in
- * software. If your user-space application doesn't support YUYV or MJPEG, fix
- * it :-). Please note that the MJPEG data have been stripped from their
- * Huffman tables (DHT marker), you will need to add it back if your JPEG
- * codec can't handle MJPEG data.
- */
-
-#include <linux/atomic.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <linux/vmalloc.h>
-#include <linux/wait.h>
-#include <linux/version.h>
-#include <asm/unaligned.h>
-
-#include <media/v4l2-common.h>
-
-#include "uvcvideo.h"
-
-#define DRIVER_AUTHOR "Laurent Pinchart " \
- "<laurent.pinchart@ideasonboard.com>"
-#define DRIVER_DESC "USB Video Class driver"
-
-unsigned int uvc_clock_param = CLOCK_MONOTONIC;
-unsigned int uvc_no_drop_param;
-static unsigned int uvc_quirks_param = -1;
-unsigned int uvc_trace_param;
-unsigned int uvc_timeout_param = UVC_CTRL_STREAMING_TIMEOUT;
-
-/* ------------------------------------------------------------------------
- * Video formats
- */
-
-static struct uvc_format_desc uvc_fmts[] = {
- {
- .name = "YUV 4:2:2 (YUYV)",
- .guid = UVC_GUID_FORMAT_YUY2,
- .fcc = V4L2_PIX_FMT_YUYV,
- },
- {
- .name = "YUV 4:2:2 (YUYV)",
- .guid = UVC_GUID_FORMAT_YUY2_ISIGHT,
- .fcc = V4L2_PIX_FMT_YUYV,
- },
- {
- .name = "YUV 4:2:0 (NV12)",
- .guid = UVC_GUID_FORMAT_NV12,
- .fcc = V4L2_PIX_FMT_NV12,
- },
- {
- .name = "MJPEG",
- .guid = UVC_GUID_FORMAT_MJPEG,
- .fcc = V4L2_PIX_FMT_MJPEG,
- },
- {
- .name = "YVU 4:2:0 (YV12)",
- .guid = UVC_GUID_FORMAT_YV12,
- .fcc = V4L2_PIX_FMT_YVU420,
- },
- {
- .name = "YUV 4:2:0 (I420)",
- .guid = UVC_GUID_FORMAT_I420,
- .fcc = V4L2_PIX_FMT_YUV420,
- },
- {
- .name = "YUV 4:2:0 (M420)",
- .guid = UVC_GUID_FORMAT_M420,
- .fcc = V4L2_PIX_FMT_M420,
- },
- {
- .name = "YUV 4:2:2 (UYVY)",
- .guid = UVC_GUID_FORMAT_UYVY,
- .fcc = V4L2_PIX_FMT_UYVY,
- },
- {
- .name = "Greyscale 8-bit (Y800)",
- .guid = UVC_GUID_FORMAT_Y800,
- .fcc = V4L2_PIX_FMT_GREY,
- },
- {
- .name = "Greyscale 8-bit (Y8 )",
- .guid = UVC_GUID_FORMAT_Y8,
- .fcc = V4L2_PIX_FMT_GREY,
- },
- {
- .name = "Greyscale 10-bit (Y10 )",
- .guid = UVC_GUID_FORMAT_Y10,
- .fcc = V4L2_PIX_FMT_Y10,
- },
- {
- .name = "Greyscale 12-bit (Y12 )",
- .guid = UVC_GUID_FORMAT_Y12,
- .fcc = V4L2_PIX_FMT_Y12,
- },
- {
- .name = "Greyscale 16-bit (Y16 )",
- .guid = UVC_GUID_FORMAT_Y16,
- .fcc = V4L2_PIX_FMT_Y16,
- },
- {
- .name = "RGB Bayer",
- .guid = UVC_GUID_FORMAT_BY8,
- .fcc = V4L2_PIX_FMT_SBGGR8,
- },
- {
- .name = "RGB565",
- .guid = UVC_GUID_FORMAT_RGBP,
- .fcc = V4L2_PIX_FMT_RGB565,
- },
- {
- .name = "H.264",
- .guid = UVC_GUID_FORMAT_H264,
- .fcc = V4L2_PIX_FMT_H264,
- },
-};
-
-/* ------------------------------------------------------------------------
- * Utility functions
- */
-
-struct usb_host_endpoint *uvc_find_endpoint(struct usb_host_interface *alts,
- __u8 epaddr)
-{
- struct usb_host_endpoint *ep;
- unsigned int i;
-
- for (i = 0; i < alts->desc.bNumEndpoints; ++i) {
- ep = &alts->endpoint[i];
- if (ep->desc.bEndpointAddress == epaddr)
- return ep;
- }
-
- return NULL;
-}
-
-static struct uvc_format_desc *uvc_format_by_guid(const __u8 guid[16])
-{
- unsigned int len = ARRAY_SIZE(uvc_fmts);
- unsigned int i;
-
- for (i = 0; i < len; ++i) {
- if (memcmp(guid, uvc_fmts[i].guid, 16) == 0)
- return &uvc_fmts[i];
- }
-
- return NULL;
-}
-
-static __u32 uvc_colorspace(const __u8 primaries)
-{
- static const __u8 colorprimaries[] = {
- 0,
- V4L2_COLORSPACE_SRGB,
- V4L2_COLORSPACE_470_SYSTEM_M,
- V4L2_COLORSPACE_470_SYSTEM_BG,
- V4L2_COLORSPACE_SMPTE170M,
- V4L2_COLORSPACE_SMPTE240M,
- };
-
- if (primaries < ARRAY_SIZE(colorprimaries))
- return colorprimaries[primaries];
-
- return 0;
-}
-
-/* Simplify a fraction using a simple continued fraction decomposition. The
- * idea here is to convert fractions such as 333333/10000000 to 1/30 using
- * 32 bit arithmetic only. The algorithm is not perfect and relies upon two
- * arbitrary parameters to remove non-significative terms from the simple
- * continued fraction decomposition. Using 8 and 333 for n_terms and threshold
- * respectively seems to give nice results.
- */
-void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
- unsigned int n_terms, unsigned int threshold)
-{
- uint32_t *an;
- uint32_t x, y, r;
- unsigned int i, n;
-
- an = kmalloc(n_terms * sizeof *an, GFP_KERNEL);
- if (an == NULL)
- return;
-
- /* Convert the fraction to a simple continued fraction. See
- * http://mathforum.org/dr.math/faq/faq.fractions.html
- * Stop if the current term is bigger than or equal to the given
- * threshold.
- */
- x = *numerator;
- y = *denominator;
-
- for (n = 0; n < n_terms && y != 0; ++n) {
- an[n] = x / y;
- if (an[n] >= threshold) {
- if (n < 2)
- n++;
- break;
- }
-
- r = x - an[n] * y;
- x = y;
- y = r;
- }
-
- /* Expand the simple continued fraction back to an integer fraction. */
- x = 0;
- y = 1;
-
- for (i = n; i > 0; --i) {
- r = y;
- y = an[i-1] * y + x;
- x = r;
- }
-
- *numerator = y;
- *denominator = x;
- kfree(an);
-}
-
-/* Convert a fraction to a frame interval in 100ns multiples. The idea here is
- * to compute numerator / denominator * 10000000 using 32 bit fixed point
- * arithmetic only.
- */
-uint32_t uvc_fraction_to_interval(uint32_t numerator, uint32_t denominator)
-{
- uint32_t multiplier;
-
- /* Saturate the result if the operation would overflow. */
- if (denominator == 0 ||
- numerator/denominator >= ((uint32_t)-1)/10000000)
- return (uint32_t)-1;
-
- /* Divide both the denominator and the multiplier by two until
- * numerator * multiplier doesn't overflow. If anyone knows a better
- * algorithm please let me know.
- */
- multiplier = 10000000;
- while (numerator > ((uint32_t)-1)/multiplier) {
- multiplier /= 2;
- denominator /= 2;
- }
-
- return denominator ? numerator * multiplier / denominator : 0;
-}
-
-/* ------------------------------------------------------------------------
- * Terminal and unit management
- */
-
-struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id)
-{
- struct uvc_entity *entity;
-
- list_for_each_entry(entity, &dev->entities, list) {
- if (entity->id == id)
- return entity;
- }
-
- return NULL;
-}
-
-static struct uvc_entity *uvc_entity_by_reference(struct uvc_device *dev,
- int id, struct uvc_entity *entity)
-{
- unsigned int i;
-
- if (entity == NULL)
- entity = list_entry(&dev->entities, struct uvc_entity, list);
-
- list_for_each_entry_continue(entity, &dev->entities, list) {
- for (i = 0; i < entity->bNrInPins; ++i)
- if (entity->baSourceID[i] == id)
- return entity;
- }
-
- return NULL;
-}
-
-static struct uvc_streaming *uvc_stream_by_id(struct uvc_device *dev, int id)
-{
- struct uvc_streaming *stream;
-
- list_for_each_entry(stream, &dev->streams, list) {
- if (stream->header.bTerminalLink == id)
- return stream;
- }
-
- return NULL;
-}
-
-/* ------------------------------------------------------------------------
- * Descriptors parsing
- */
-
-static int uvc_parse_format(struct uvc_device *dev,
- struct uvc_streaming *streaming, struct uvc_format *format,
- __u32 **intervals, unsigned char *buffer, int buflen)
-{
- struct usb_interface *intf = streaming->intf;
- struct usb_host_interface *alts = intf->cur_altsetting;
- struct uvc_format_desc *fmtdesc;
- struct uvc_frame *frame;
- const unsigned char *start = buffer;
- unsigned int interval;
- unsigned int i, n;
- __u8 ftype;
-
- format->type = buffer[2];
- format->index = buffer[3];
-
- switch (buffer[2]) {
- case UVC_VS_FORMAT_UNCOMPRESSED:
- case UVC_VS_FORMAT_FRAME_BASED:
- n = buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED ? 27 : 28;
- if (buflen < n) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
- "interface %d FORMAT error\n",
- dev->udev->devnum,
- alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- /* Find the format descriptor from its GUID. */
- fmtdesc = uvc_format_by_guid(&buffer[5]);
-
- if (fmtdesc != NULL) {
- strlcpy(format->name, fmtdesc->name,
- sizeof format->name);
- format->fcc = fmtdesc->fcc;
- } else {
- uvc_printk(KERN_INFO, "Unknown video format %pUl\n",
- &buffer[5]);
- snprintf(format->name, sizeof(format->name), "%pUl\n",
- &buffer[5]);
- format->fcc = 0;
- }
-
- format->bpp = buffer[21];
- if (buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED) {
- ftype = UVC_VS_FRAME_UNCOMPRESSED;
- } else {
- ftype = UVC_VS_FRAME_FRAME_BASED;
- if (buffer[27])
- format->flags = UVC_FMT_FLAG_COMPRESSED;
- }
- break;
-
- case UVC_VS_FORMAT_MJPEG:
- if (buflen < 11) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
- "interface %d FORMAT error\n",
- dev->udev->devnum,
- alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- strlcpy(format->name, "MJPEG", sizeof format->name);
- format->fcc = V4L2_PIX_FMT_MJPEG;
- format->flags = UVC_FMT_FLAG_COMPRESSED;
- format->bpp = 0;
- ftype = UVC_VS_FRAME_MJPEG;
- break;
-
- case UVC_VS_FORMAT_DV:
- if (buflen < 9) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
- "interface %d FORMAT error\n",
- dev->udev->devnum,
- alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- switch (buffer[8] & 0x7f) {
- case 0:
- strlcpy(format->name, "SD-DV", sizeof format->name);
- break;
- case 1:
- strlcpy(format->name, "SDL-DV", sizeof format->name);
- break;
- case 2:
- strlcpy(format->name, "HD-DV", sizeof format->name);
- break;
- default:
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
- "interface %d: unknown DV format %u\n",
- dev->udev->devnum,
- alts->desc.bInterfaceNumber, buffer[8]);
- return -EINVAL;
- }
-
- strlcat(format->name, buffer[8] & (1 << 7) ? " 60Hz" : " 50Hz",
- sizeof format->name);
-
- format->fcc = V4L2_PIX_FMT_DV;
- format->flags = UVC_FMT_FLAG_COMPRESSED | UVC_FMT_FLAG_STREAM;
- format->bpp = 0;
- ftype = 0;
-
- /* Create a dummy frame descriptor. */
- frame = &format->frame[0];
- memset(&format->frame[0], 0, sizeof format->frame[0]);
- frame->bFrameIntervalType = 1;
- frame->dwDefaultFrameInterval = 1;
- frame->dwFrameInterval = *intervals;
- *(*intervals)++ = 1;
- format->nframes = 1;
- break;
-
- case UVC_VS_FORMAT_MPEG2TS:
- case UVC_VS_FORMAT_STREAM_BASED:
- /* Not supported yet. */
- default:
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
- "interface %d unsupported format %u\n",
- dev->udev->devnum, alts->desc.bInterfaceNumber,
- buffer[2]);
- return -EINVAL;
- }
-
- uvc_trace(UVC_TRACE_DESCR, "Found format %s.\n", format->name);
-
- buflen -= buffer[0];
- buffer += buffer[0];
-
- /* Parse the frame descriptors. Only uncompressed, MJPEG and frame
- * based formats have frame descriptors.
- */
- while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
- buffer[2] == ftype) {
- frame = &format->frame[format->nframes];
- if (ftype != UVC_VS_FRAME_FRAME_BASED)
- n = buflen > 25 ? buffer[25] : 0;
- else
- n = buflen > 21 ? buffer[21] : 0;
-
- n = n ? n : 3;
-
- if (buflen < 26 + 4*n) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
- "interface %d FRAME error\n", dev->udev->devnum,
- alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- frame->bFrameIndex = buffer[3];
- frame->bmCapabilities = buffer[4];
- frame->wWidth = get_unaligned_le16(&buffer[5]);
- frame->wHeight = get_unaligned_le16(&buffer[7]);
- frame->dwMinBitRate = get_unaligned_le32(&buffer[9]);
- frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]);
- if (ftype != UVC_VS_FRAME_FRAME_BASED) {
- frame->dwMaxVideoFrameBufferSize =
- get_unaligned_le32(&buffer[17]);
- frame->dwDefaultFrameInterval =
- get_unaligned_le32(&buffer[21]);
- frame->bFrameIntervalType = buffer[25];
- } else {
- frame->dwMaxVideoFrameBufferSize = 0;
- frame->dwDefaultFrameInterval =
- get_unaligned_le32(&buffer[17]);
- frame->bFrameIntervalType = buffer[21];
- }
- frame->dwFrameInterval = *intervals;
-
- /* Several UVC chipsets screw up dwMaxVideoFrameBufferSize
- * completely. Observed behaviours range from setting the
- * value to 1.1x the actual frame size to hardwiring the
- * 16 low bits to 0. This results in a higher than necessary
- * memory usage as well as a wrong image size information. For
- * uncompressed formats this can be fixed by computing the
- * value from the frame size.
- */
- if (!(format->flags & UVC_FMT_FLAG_COMPRESSED))
- frame->dwMaxVideoFrameBufferSize = format->bpp
- * frame->wWidth * frame->wHeight / 8;
-
- /* Some bogus devices report dwMinFrameInterval equal to
- * dwMaxFrameInterval and have dwFrameIntervalStep set to
- * zero. Setting all null intervals to 1 fixes the problem and
- * some other divisions by zero that could happen.
- */
- for (i = 0; i < n; ++i) {
- interval = get_unaligned_le32(&buffer[26+4*i]);
- *(*intervals)++ = interval ? interval : 1;
- }
-
- /* Make sure that the default frame interval stays between
- * the boundaries.
- */
- n -= frame->bFrameIntervalType ? 1 : 2;
- frame->dwDefaultFrameInterval =
- min(frame->dwFrameInterval[n],
- max(frame->dwFrameInterval[0],
- frame->dwDefaultFrameInterval));
-
- if (dev->quirks & UVC_QUIRK_RESTRICT_FRAME_RATE) {
- frame->bFrameIntervalType = 1;
- frame->dwFrameInterval[0] =
- frame->dwDefaultFrameInterval;
- }
-
- uvc_trace(UVC_TRACE_DESCR, "- %ux%u (%u.%u fps)\n",
- frame->wWidth, frame->wHeight,
- 10000000/frame->dwDefaultFrameInterval,
- (100000000/frame->dwDefaultFrameInterval)%10);
-
- format->nframes++;
- buflen -= buffer[0];
- buffer += buffer[0];
- }
-
- if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
- buffer[2] == UVC_VS_STILL_IMAGE_FRAME) {
- buflen -= buffer[0];
- buffer += buffer[0];
- }
-
- if (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
- buffer[2] == UVC_VS_COLORFORMAT) {
- if (buflen < 6) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
- "interface %d COLORFORMAT error\n",
- dev->udev->devnum,
- alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- format->colorspace = uvc_colorspace(buffer[3]);
-
- buflen -= buffer[0];
- buffer += buffer[0];
- }
-
- return buffer - start;
-}
-
-static int uvc_parse_streaming(struct uvc_device *dev,
- struct usb_interface *intf)
-{
- struct uvc_streaming *streaming = NULL;
- struct uvc_format *format;
- struct uvc_frame *frame;
- struct usb_host_interface *alts = &intf->altsetting[0];
- unsigned char *_buffer, *buffer = alts->extra;
- int _buflen, buflen = alts->extralen;
- unsigned int nformats = 0, nframes = 0, nintervals = 0;
- unsigned int size, i, n, p;
- __u32 *interval;
- __u16 psize;
- int ret = -EINVAL;
-
- if (intf->cur_altsetting->desc.bInterfaceSubClass
- != UVC_SC_VIDEOSTREAMING) {
- uvc_trace(UVC_TRACE_DESCR, "device %d interface %d isn't a "
- "video streaming interface\n", dev->udev->devnum,
- intf->altsetting[0].desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- if (usb_driver_claim_interface(&uvc_driver.driver, intf, dev)) {
- uvc_trace(UVC_TRACE_DESCR, "device %d interface %d is already "
- "claimed\n", dev->udev->devnum,
- intf->altsetting[0].desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- streaming = kzalloc(sizeof *streaming, GFP_KERNEL);
- if (streaming == NULL) {
- usb_driver_release_interface(&uvc_driver.driver, intf);
- return -EINVAL;
- }
-
- mutex_init(&streaming->mutex);
- streaming->dev = dev;
- streaming->intf = usb_get_intf(intf);
- streaming->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
-
- /* The Pico iMage webcam has its class-specific interface descriptors
- * after the endpoint descriptors.
- */
- if (buflen == 0) {
- for (i = 0; i < alts->desc.bNumEndpoints; ++i) {
- struct usb_host_endpoint *ep = &alts->endpoint[i];
-
- if (ep->extralen == 0)
- continue;
-
- if (ep->extralen > 2 &&
- ep->extra[1] == USB_DT_CS_INTERFACE) {
- uvc_trace(UVC_TRACE_DESCR, "trying extra data "
- "from endpoint %u.\n", i);
- buffer = alts->endpoint[i].extra;
- buflen = alts->endpoint[i].extralen;
- break;
- }
- }
- }
-
- /* Skip the standard interface descriptors. */
- while (buflen > 2 && buffer[1] != USB_DT_CS_INTERFACE) {
- buflen -= buffer[0];
- buffer += buffer[0];
- }
-
- if (buflen <= 2) {
- uvc_trace(UVC_TRACE_DESCR, "no class-specific streaming "
- "interface descriptors found.\n");
- goto error;
- }
-
- /* Parse the header descriptor. */
- switch (buffer[2]) {
- case UVC_VS_OUTPUT_HEADER:
- streaming->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- size = 9;
- break;
-
- case UVC_VS_INPUT_HEADER:
- streaming->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- size = 13;
- break;
-
- default:
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
- "%d HEADER descriptor not found.\n", dev->udev->devnum,
- alts->desc.bInterfaceNumber);
- goto error;
- }
-
- p = buflen >= 4 ? buffer[3] : 0;
- n = buflen >= size ? buffer[size-1] : 0;
-
- if (buflen < size + p*n) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
- "interface %d HEADER descriptor is invalid.\n",
- dev->udev->devnum, alts->desc.bInterfaceNumber);
- goto error;
- }
-
- streaming->header.bNumFormats = p;
- streaming->header.bEndpointAddress = buffer[6];
- if (buffer[2] == UVC_VS_INPUT_HEADER) {
- streaming->header.bmInfo = buffer[7];
- streaming->header.bTerminalLink = buffer[8];
- streaming->header.bStillCaptureMethod = buffer[9];
- streaming->header.bTriggerSupport = buffer[10];
- streaming->header.bTriggerUsage = buffer[11];
- } else {
- streaming->header.bTerminalLink = buffer[7];
- }
- streaming->header.bControlSize = n;
-
- streaming->header.bmaControls = kmemdup(&buffer[size], p * n,
- GFP_KERNEL);
- if (streaming->header.bmaControls == NULL) {
- ret = -ENOMEM;
- goto error;
- }
-
- buflen -= buffer[0];
- buffer += buffer[0];
-
- _buffer = buffer;
- _buflen = buflen;
-
- /* Count the format and frame descriptors. */
- while (_buflen > 2 && _buffer[1] == USB_DT_CS_INTERFACE) {
- switch (_buffer[2]) {
- case UVC_VS_FORMAT_UNCOMPRESSED:
- case UVC_VS_FORMAT_MJPEG:
- case UVC_VS_FORMAT_FRAME_BASED:
- nformats++;
- break;
-
- case UVC_VS_FORMAT_DV:
- /* DV format has no frame descriptor. We will create a
- * dummy frame descriptor with a dummy frame interval.
- */
- nformats++;
- nframes++;
- nintervals++;
- break;
-
- case UVC_VS_FORMAT_MPEG2TS:
- case UVC_VS_FORMAT_STREAM_BASED:
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
- "interface %d FORMAT %u is not supported.\n",
- dev->udev->devnum,
- alts->desc.bInterfaceNumber, _buffer[2]);
- break;
-
- case UVC_VS_FRAME_UNCOMPRESSED:
- case UVC_VS_FRAME_MJPEG:
- nframes++;
- if (_buflen > 25)
- nintervals += _buffer[25] ? _buffer[25] : 3;
- break;
-
- case UVC_VS_FRAME_FRAME_BASED:
- nframes++;
- if (_buflen > 21)
- nintervals += _buffer[21] ? _buffer[21] : 3;
- break;
- }
-
- _buflen -= _buffer[0];
- _buffer += _buffer[0];
- }
-
- if (nformats == 0) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
- "%d has no supported formats defined.\n",
- dev->udev->devnum, alts->desc.bInterfaceNumber);
- goto error;
- }
-
- size = nformats * sizeof *format + nframes * sizeof *frame
- + nintervals * sizeof *interval;
- format = kzalloc(size, GFP_KERNEL);
- if (format == NULL) {
- ret = -ENOMEM;
- goto error;
- }
-
- frame = (struct uvc_frame *)&format[nformats];
- interval = (__u32 *)&frame[nframes];
-
- streaming->format = format;
- streaming->nformats = nformats;
-
- /* Parse the format descriptors. */
- while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE) {
- switch (buffer[2]) {
- case UVC_VS_FORMAT_UNCOMPRESSED:
- case UVC_VS_FORMAT_MJPEG:
- case UVC_VS_FORMAT_DV:
- case UVC_VS_FORMAT_FRAME_BASED:
- format->frame = frame;
- ret = uvc_parse_format(dev, streaming, format,
- &interval, buffer, buflen);
- if (ret < 0)
- goto error;
-
- frame += format->nframes;
- format++;
-
- buflen -= ret;
- buffer += ret;
- continue;
-
- default:
- break;
- }
-
- buflen -= buffer[0];
- buffer += buffer[0];
- }
-
- if (buflen)
- uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface "
- "%d has %u bytes of trailing descriptor garbage.\n",
- dev->udev->devnum, alts->desc.bInterfaceNumber, buflen);
-
- /* Parse the alternate settings to find the maximum bandwidth. */
- for (i = 0; i < intf->num_altsetting; ++i) {
- struct usb_host_endpoint *ep;
- alts = &intf->altsetting[i];
- ep = uvc_find_endpoint(alts,
- streaming->header.bEndpointAddress);
- if (ep == NULL)
- continue;
-
- psize = le16_to_cpu(ep->desc.wMaxPacketSize);
- psize = (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
- if (psize > streaming->maxpsize)
- streaming->maxpsize = psize;
- }
-
- list_add_tail(&streaming->list, &dev->streams);
- return 0;
-
-error:
- usb_driver_release_interface(&uvc_driver.driver, intf);
- usb_put_intf(intf);
- kfree(streaming->format);
- kfree(streaming->header.bmaControls);
- kfree(streaming);
- return ret;
-}
-
-static struct uvc_entity *uvc_alloc_entity(u16 type, u8 id,
- unsigned int num_pads, unsigned int extra_size)
-{
- struct uvc_entity *entity;
- unsigned int num_inputs;
- unsigned int size;
- unsigned int i;
-
- extra_size = ALIGN(extra_size, sizeof(*entity->pads));
- num_inputs = (type & UVC_TERM_OUTPUT) ? num_pads : num_pads - 1;
- size = sizeof(*entity) + extra_size + sizeof(*entity->pads) * num_pads
- + num_inputs;
- entity = kzalloc(size, GFP_KERNEL);
- if (entity == NULL)
- return NULL;
-
- entity->id = id;
- entity->type = type;
-
- entity->num_links = 0;
- entity->num_pads = num_pads;
- entity->pads = ((void *)(entity + 1)) + extra_size;
-
- for (i = 0; i < num_inputs; ++i)
- entity->pads[i].flags = MEDIA_PAD_FL_SINK;
- if (!UVC_ENTITY_IS_OTERM(entity))
- entity->pads[num_pads-1].flags = MEDIA_PAD_FL_SOURCE;
-
- entity->bNrInPins = num_inputs;
- entity->baSourceID = (__u8 *)(&entity->pads[num_pads]);
-
- return entity;
-}
-
-/* Parse vendor-specific extensions. */
-static int uvc_parse_vendor_control(struct uvc_device *dev,
- const unsigned char *buffer, int buflen)
-{
- struct usb_device *udev = dev->udev;
- struct usb_host_interface *alts = dev->intf->cur_altsetting;
- struct uvc_entity *unit;
- unsigned int n, p;
- int handled = 0;
-
- switch (le16_to_cpu(dev->udev->descriptor.idVendor)) {
- case 0x046d: /* Logitech */
- if (buffer[1] != 0x41 || buffer[2] != 0x01)
- break;
-
- /* Logitech implements several vendor specific functions
- * through vendor specific extension units (LXU).
- *
- * The LXU descriptors are similar to XU descriptors
- * (see "USB Device Video Class for Video Devices", section
- * 3.7.2.6 "Extension Unit Descriptor") with the following
- * differences:
- *
- * ----------------------------------------------------------
- * 0 bLength 1 Number
- * Size of this descriptor, in bytes: 24+p+n*2
- * ----------------------------------------------------------
- * 23+p+n bmControlsType N Bitmap
- * Individual bits in the set are defined:
- * 0: Absolute
- * 1: Relative
- *
- * This bitset is mapped exactly the same as bmControls.
- * ----------------------------------------------------------
- * 23+p+n*2 bReserved 1 Boolean
- * ----------------------------------------------------------
- * 24+p+n*2 iExtension 1 Index
- * Index of a string descriptor that describes this
- * extension unit.
- * ----------------------------------------------------------
- */
- p = buflen >= 22 ? buffer[21] : 0;
- n = buflen >= 25 + p ? buffer[22+p] : 0;
-
- if (buflen < 25 + p + 2*n) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
- "interface %d EXTENSION_UNIT error\n",
- udev->devnum, alts->desc.bInterfaceNumber);
- break;
- }
-
- unit = uvc_alloc_entity(UVC_VC_EXTENSION_UNIT, buffer[3],
- p + 1, 2*n);
- if (unit == NULL)
- return -ENOMEM;
-
- memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
- unit->extension.bNumControls = buffer[20];
- memcpy(unit->baSourceID, &buffer[22], p);
- unit->extension.bControlSize = buffer[22+p];
- unit->extension.bmControls = (__u8 *)unit + sizeof(*unit);
- unit->extension.bmControlsType = (__u8 *)unit + sizeof(*unit)
- + n;
- memcpy(unit->extension.bmControls, &buffer[23+p], 2*n);
-
- if (buffer[24+p+2*n] != 0)
- usb_string(udev, buffer[24+p+2*n], unit->name,
- sizeof unit->name);
- else
- sprintf(unit->name, "Extension %u", buffer[3]);
-
- list_add_tail(&unit->list, &dev->entities);
- handled = 1;
- break;
- }
-
- return handled;
-}
-
-static int uvc_parse_standard_control(struct uvc_device *dev,
- const unsigned char *buffer, int buflen)
-{
- struct usb_device *udev = dev->udev;
- struct uvc_entity *unit, *term;
- struct usb_interface *intf;
- struct usb_host_interface *alts = dev->intf->cur_altsetting;
- unsigned int i, n, p, len;
- __u16 type;
-
- switch (buffer[2]) {
- case UVC_VC_HEADER:
- n = buflen >= 12 ? buffer[11] : 0;
-
- if (buflen < 12 || buflen < 12 + n) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
- "interface %d HEADER error\n", udev->devnum,
- alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- dev->uvc_version = get_unaligned_le16(&buffer[3]);
- dev->clock_frequency = get_unaligned_le32(&buffer[7]);
-
- /* Parse all USB Video Streaming interfaces. */
- for (i = 0; i < n; ++i) {
- intf = usb_ifnum_to_if(udev, buffer[12+i]);
- if (intf == NULL) {
- uvc_trace(UVC_TRACE_DESCR, "device %d "
- "interface %d doesn't exists\n",
- udev->devnum, i);
- continue;
- }
-
- uvc_parse_streaming(dev, intf);
- }
- break;
-
- case UVC_VC_INPUT_TERMINAL:
- if (buflen < 8) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
- "interface %d INPUT_TERMINAL error\n",
- udev->devnum, alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- /* Make sure the terminal type MSB is not null, otherwise it
- * could be confused with a unit.
- */
- type = get_unaligned_le16(&buffer[4]);
- if ((type & 0xff00) == 0) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
- "interface %d INPUT_TERMINAL %d has invalid "
- "type 0x%04x, skipping\n", udev->devnum,
- alts->desc.bInterfaceNumber,
- buffer[3], type);
- return 0;
- }
-
- n = 0;
- p = 0;
- len = 8;
-
- if (type == UVC_ITT_CAMERA) {
- n = buflen >= 15 ? buffer[14] : 0;
- len = 15;
-
- } else if (type == UVC_ITT_MEDIA_TRANSPORT_INPUT) {
- n = buflen >= 9 ? buffer[8] : 0;
- p = buflen >= 10 + n ? buffer[9+n] : 0;
- len = 10;
- }
-
- if (buflen < len + n + p) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
- "interface %d INPUT_TERMINAL error\n",
- udev->devnum, alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- term = uvc_alloc_entity(type | UVC_TERM_INPUT, buffer[3],
- 1, n + p);
- if (term == NULL)
- return -ENOMEM;
-
- if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) {
- term->camera.bControlSize = n;
- term->camera.bmControls = (__u8 *)term + sizeof *term;
- term->camera.wObjectiveFocalLengthMin =
- get_unaligned_le16(&buffer[8]);
- term->camera.wObjectiveFocalLengthMax =
- get_unaligned_le16(&buffer[10]);
- term->camera.wOcularFocalLength =
- get_unaligned_le16(&buffer[12]);
- memcpy(term->camera.bmControls, &buffer[15], n);
- } else if (UVC_ENTITY_TYPE(term) ==
- UVC_ITT_MEDIA_TRANSPORT_INPUT) {
- term->media.bControlSize = n;
- term->media.bmControls = (__u8 *)term + sizeof *term;
- term->media.bTransportModeSize = p;
- term->media.bmTransportModes = (__u8 *)term
- + sizeof *term + n;
- memcpy(term->media.bmControls, &buffer[9], n);
- memcpy(term->media.bmTransportModes, &buffer[10+n], p);
- }
-
- if (buffer[7] != 0)
- usb_string(udev, buffer[7], term->name,
- sizeof term->name);
- else if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA)
- sprintf(term->name, "Camera %u", buffer[3]);
- else if (UVC_ENTITY_TYPE(term) == UVC_ITT_MEDIA_TRANSPORT_INPUT)
- sprintf(term->name, "Media %u", buffer[3]);
- else
- sprintf(term->name, "Input %u", buffer[3]);
-
- list_add_tail(&term->list, &dev->entities);
- break;
-
- case UVC_VC_OUTPUT_TERMINAL:
- if (buflen < 9) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
- "interface %d OUTPUT_TERMINAL error\n",
- udev->devnum, alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- /* Make sure the terminal type MSB is not null, otherwise it
- * could be confused with a unit.
- */
- type = get_unaligned_le16(&buffer[4]);
- if ((type & 0xff00) == 0) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
- "interface %d OUTPUT_TERMINAL %d has invalid "
- "type 0x%04x, skipping\n", udev->devnum,
- alts->desc.bInterfaceNumber, buffer[3], type);
- return 0;
- }
-
- term = uvc_alloc_entity(type | UVC_TERM_OUTPUT, buffer[3],
- 1, 0);
- if (term == NULL)
- return -ENOMEM;
-
- memcpy(term->baSourceID, &buffer[7], 1);
-
- if (buffer[8] != 0)
- usb_string(udev, buffer[8], term->name,
- sizeof term->name);
- else
- sprintf(term->name, "Output %u", buffer[3]);
-
- list_add_tail(&term->list, &dev->entities);
- break;
-
- case UVC_VC_SELECTOR_UNIT:
- p = buflen >= 5 ? buffer[4] : 0;
-
- if (buflen < 5 || buflen < 6 + p) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
- "interface %d SELECTOR_UNIT error\n",
- udev->devnum, alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, 0);
- if (unit == NULL)
- return -ENOMEM;
-
- memcpy(unit->baSourceID, &buffer[5], p);
-
- if (buffer[5+p] != 0)
- usb_string(udev, buffer[5+p], unit->name,
- sizeof unit->name);
- else
- sprintf(unit->name, "Selector %u", buffer[3]);
-
- list_add_tail(&unit->list, &dev->entities);
- break;
-
- case UVC_VC_PROCESSING_UNIT:
- n = buflen >= 8 ? buffer[7] : 0;
- p = dev->uvc_version >= 0x0110 ? 10 : 9;
-
- if (buflen < p + n) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
- "interface %d PROCESSING_UNIT error\n",
- udev->devnum, alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- unit = uvc_alloc_entity(buffer[2], buffer[3], 2, n);
- if (unit == NULL)
- return -ENOMEM;
-
- memcpy(unit->baSourceID, &buffer[4], 1);
- unit->processing.wMaxMultiplier =
- get_unaligned_le16(&buffer[5]);
- unit->processing.bControlSize = buffer[7];
- unit->processing.bmControls = (__u8 *)unit + sizeof *unit;
- memcpy(unit->processing.bmControls, &buffer[8], n);
- if (dev->uvc_version >= 0x0110)
- unit->processing.bmVideoStandards = buffer[9+n];
-
- if (buffer[8+n] != 0)
- usb_string(udev, buffer[8+n], unit->name,
- sizeof unit->name);
- else
- sprintf(unit->name, "Processing %u", buffer[3]);
-
- list_add_tail(&unit->list, &dev->entities);
- break;
-
- case UVC_VC_EXTENSION_UNIT:
- p = buflen >= 22 ? buffer[21] : 0;
- n = buflen >= 24 + p ? buffer[22+p] : 0;
-
- if (buflen < 24 + p + n) {
- uvc_trace(UVC_TRACE_DESCR, "device %d videocontrol "
- "interface %d EXTENSION_UNIT error\n",
- udev->devnum, alts->desc.bInterfaceNumber);
- return -EINVAL;
- }
-
- unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, n);
- if (unit == NULL)
- return -ENOMEM;
-
- memcpy(unit->extension.guidExtensionCode, &buffer[4], 16);
- unit->extension.bNumControls = buffer[20];
- memcpy(unit->baSourceID, &buffer[22], p);
- unit->extension.bControlSize = buffer[22+p];
- unit->extension.bmControls = (__u8 *)unit + sizeof *unit;
- memcpy(unit->extension.bmControls, &buffer[23+p], n);
-
- if (buffer[23+p+n] != 0)
- usb_string(udev, buffer[23+p+n], unit->name,
- sizeof unit->name);
- else
- sprintf(unit->name, "Extension %u", buffer[3]);
-
- list_add_tail(&unit->list, &dev->entities);
- break;
-
- default:
- uvc_trace(UVC_TRACE_DESCR, "Found an unknown CS_INTERFACE "
- "descriptor (%u)\n", buffer[2]);
- break;
- }
-
- return 0;
-}
-
-static int uvc_parse_control(struct uvc_device *dev)
-{
- struct usb_host_interface *alts = dev->intf->cur_altsetting;
- unsigned char *buffer = alts->extra;
- int buflen = alts->extralen;
- int ret;
-
- /* Parse the default alternate setting only, as the UVC specification
- * defines a single alternate setting, the default alternate setting
- * zero.
- */
-
- while (buflen > 2) {
- if (uvc_parse_vendor_control(dev, buffer, buflen) ||
- buffer[1] != USB_DT_CS_INTERFACE)
- goto next_descriptor;
-
- if ((ret = uvc_parse_standard_control(dev, buffer, buflen)) < 0)
- return ret;
-
-next_descriptor:
- buflen -= buffer[0];
- buffer += buffer[0];
- }
-
- /* Check if the optional status endpoint is present. Built-in iSight
- * webcams have an interrupt endpoint but spit proprietary data that
- * don't conform to the UVC status endpoint messages. Don't try to
- * handle the interrupt endpoint for those cameras.
- */
- if (alts->desc.bNumEndpoints == 1 &&
- !(dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)) {
- struct usb_host_endpoint *ep = &alts->endpoint[0];
- struct usb_endpoint_descriptor *desc = &ep->desc;
-
- if (usb_endpoint_is_int_in(desc) &&
- le16_to_cpu(desc->wMaxPacketSize) >= 8 &&
- desc->bInterval != 0) {
- uvc_trace(UVC_TRACE_DESCR, "Found a Status endpoint "
- "(addr %02x).\n", desc->bEndpointAddress);
- dev->int_ep = ep;
- }
- }
-
- return 0;
-}
-
-/* ------------------------------------------------------------------------
- * UVC device scan
- */
-
-/*
- * Scan the UVC descriptors to locate a chain starting at an Output Terminal
- * and containing the following units:
- *
- * - one or more Output Terminals (USB Streaming or Display)
- * - zero or one Processing Unit
- * - zero, one or more single-input Selector Units
- * - zero or one multiple-input Selector Units, provided all inputs are
- * connected to input terminals
- * - zero, one or mode single-input Extension Units
- * - one or more Input Terminals (Camera, External or USB Streaming)
- *
- * The terminal and units must match on of the following structures:
- *
- * ITT_*(0) -> +---------+ +---------+ +---------+ -> TT_STREAMING(0)
- * ... | SU{0,1} | -> | PU{0,1} | -> | XU{0,n} | ...
- * ITT_*(n) -> +---------+ +---------+ +---------+ -> TT_STREAMING(n)
- *
- * +---------+ +---------+ -> OTT_*(0)
- * TT_STREAMING -> | PU{0,1} | -> | XU{0,n} | ...
- * +---------+ +---------+ -> OTT_*(n)
- *
- * The Processing Unit and Extension Units can be in any order. Additional
- * Extension Units connected to the main chain as single-unit branches are
- * also supported. Single-input Selector Units are ignored.
- */
-static int uvc_scan_chain_entity(struct uvc_video_chain *chain,
- struct uvc_entity *entity)
-{
- switch (UVC_ENTITY_TYPE(entity)) {
- case UVC_VC_EXTENSION_UNIT:
- if (uvc_trace_param & UVC_TRACE_PROBE)
- printk(" <- XU %d", entity->id);
-
- if (entity->bNrInPins != 1) {
- uvc_trace(UVC_TRACE_DESCR, "Extension unit %d has more "
- "than 1 input pin.\n", entity->id);
- return -1;
- }
-
- break;
-
- case UVC_VC_PROCESSING_UNIT:
- if (uvc_trace_param & UVC_TRACE_PROBE)
- printk(" <- PU %d", entity->id);
-
- if (chain->processing != NULL) {
- uvc_trace(UVC_TRACE_DESCR, "Found multiple "
- "Processing Units in chain.\n");
- return -1;
- }
-
- chain->processing = entity;
- break;
-
- case UVC_VC_SELECTOR_UNIT:
- if (uvc_trace_param & UVC_TRACE_PROBE)
- printk(" <- SU %d", entity->id);
-
- /* Single-input selector units are ignored. */
- if (entity->bNrInPins == 1)
- break;
-
- if (chain->selector != NULL) {
- uvc_trace(UVC_TRACE_DESCR, "Found multiple Selector "
- "Units in chain.\n");
- return -1;
- }
-
- chain->selector = entity;
- break;
-
- case UVC_ITT_VENDOR_SPECIFIC:
- case UVC_ITT_CAMERA:
- case UVC_ITT_MEDIA_TRANSPORT_INPUT:
- if (uvc_trace_param & UVC_TRACE_PROBE)
- printk(" <- IT %d\n", entity->id);
-
- break;
-
- case UVC_OTT_VENDOR_SPECIFIC:
- case UVC_OTT_DISPLAY:
- case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
- if (uvc_trace_param & UVC_TRACE_PROBE)
- printk(" OT %d", entity->id);
-
- break;
-
- case UVC_TT_STREAMING:
- if (UVC_ENTITY_IS_ITERM(entity)) {
- if (uvc_trace_param & UVC_TRACE_PROBE)
- printk(" <- IT %d\n", entity->id);
- } else {
- if (uvc_trace_param & UVC_TRACE_PROBE)
- printk(" OT %d", entity->id);
- }
-
- break;
-
- default:
- uvc_trace(UVC_TRACE_DESCR, "Unsupported entity type "
- "0x%04x found in chain.\n", UVC_ENTITY_TYPE(entity));
- return -1;
- }
-
- list_add_tail(&entity->chain, &chain->entities);
- return 0;
-}
-
-static int uvc_scan_chain_forward(struct uvc_video_chain *chain,
- struct uvc_entity *entity, struct uvc_entity *prev)
-{
- struct uvc_entity *forward;
- int found;
-
- /* Forward scan */
- forward = NULL;
- found = 0;
-
- while (1) {
- forward = uvc_entity_by_reference(chain->dev, entity->id,
- forward);
- if (forward == NULL)
- break;
- if (forward == prev)
- continue;
-
- switch (UVC_ENTITY_TYPE(forward)) {
- case UVC_VC_EXTENSION_UNIT:
- if (forward->bNrInPins != 1) {
- uvc_trace(UVC_TRACE_DESCR, "Extension unit %d "
- "has more than 1 input pin.\n",
- entity->id);
- return -EINVAL;
- }
-
- list_add_tail(&forward->chain, &chain->entities);
- if (uvc_trace_param & UVC_TRACE_PROBE) {
- if (!found)
- printk(" (->");
-
- printk(" XU %d", forward->id);
- found = 1;
- }
- break;
-
- case UVC_OTT_VENDOR_SPECIFIC:
- case UVC_OTT_DISPLAY:
- case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
- case UVC_TT_STREAMING:
- if (UVC_ENTITY_IS_ITERM(forward)) {
- uvc_trace(UVC_TRACE_DESCR, "Unsupported input "
- "terminal %u.\n", forward->id);
- return -EINVAL;
- }
-
- list_add_tail(&forward->chain, &chain->entities);
- if (uvc_trace_param & UVC_TRACE_PROBE) {
- if (!found)
- printk(" (->");
-
- printk(" OT %d", forward->id);
- found = 1;
- }
- break;
- }
- }
- if (found)
- printk(")");
-
- return 0;
-}
-
-static int uvc_scan_chain_backward(struct uvc_video_chain *chain,
- struct uvc_entity **_entity)
-{
- struct uvc_entity *entity = *_entity;
- struct uvc_entity *term;
- int id = -EINVAL, i;
-
- switch (UVC_ENTITY_TYPE(entity)) {
- case UVC_VC_EXTENSION_UNIT:
- case UVC_VC_PROCESSING_UNIT:
- id = entity->baSourceID[0];
- break;
-
- case UVC_VC_SELECTOR_UNIT:
- /* Single-input selector units are ignored. */
- if (entity->bNrInPins == 1) {
- id = entity->baSourceID[0];
- break;
- }
-
- if (uvc_trace_param & UVC_TRACE_PROBE)
- printk(" <- IT");
-
- chain->selector = entity;
- for (i = 0; i < entity->bNrInPins; ++i) {
- id = entity->baSourceID[i];
- term = uvc_entity_by_id(chain->dev, id);
- if (term == NULL || !UVC_ENTITY_IS_ITERM(term)) {
- uvc_trace(UVC_TRACE_DESCR, "Selector unit %d "
- "input %d isn't connected to an "
- "input terminal\n", entity->id, i);
- return -1;
- }
-
- if (uvc_trace_param & UVC_TRACE_PROBE)
- printk(" %d", term->id);
-
- list_add_tail(&term->chain, &chain->entities);
- uvc_scan_chain_forward(chain, term, entity);
- }
-
- if (uvc_trace_param & UVC_TRACE_PROBE)
- printk("\n");
-
- id = 0;
- break;
-
- case UVC_ITT_VENDOR_SPECIFIC:
- case UVC_ITT_CAMERA:
- case UVC_ITT_MEDIA_TRANSPORT_INPUT:
- case UVC_OTT_VENDOR_SPECIFIC:
- case UVC_OTT_DISPLAY:
- case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
- case UVC_TT_STREAMING:
- id = UVC_ENTITY_IS_OTERM(entity) ? entity->baSourceID[0] : 0;
- break;
- }
-
- if (id <= 0) {
- *_entity = NULL;
- return id;
- }
-
- entity = uvc_entity_by_id(chain->dev, id);
- if (entity == NULL) {
- uvc_trace(UVC_TRACE_DESCR, "Found reference to "
- "unknown entity %d.\n", id);
- return -EINVAL;
- }
-
- *_entity = entity;
- return 0;
-}
-
-static int uvc_scan_chain(struct uvc_video_chain *chain,
- struct uvc_entity *term)
-{
- struct uvc_entity *entity, *prev;
-
- uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain:");
-
- entity = term;
- prev = NULL;
-
- while (entity != NULL) {
- /* Entity must not be part of an existing chain */
- if (entity->chain.next || entity->chain.prev) {
- uvc_trace(UVC_TRACE_DESCR, "Found reference to "
- "entity %d already in chain.\n", entity->id);
- return -EINVAL;
- }
-
- /* Process entity */
- if (uvc_scan_chain_entity(chain, entity) < 0)
- return -EINVAL;
-
- /* Forward scan */
- if (uvc_scan_chain_forward(chain, entity, prev) < 0)
- return -EINVAL;
-
- /* Backward scan */
- prev = entity;
- if (uvc_scan_chain_backward(chain, &entity) < 0)
- return -EINVAL;
- }
-
- return 0;
-}
-
-static unsigned int uvc_print_terms(struct list_head *terms, u16 dir,
- char *buffer)
-{
- struct uvc_entity *term;
- unsigned int nterms = 0;
- char *p = buffer;
-
- list_for_each_entry(term, terms, chain) {
- if (!UVC_ENTITY_IS_TERM(term) ||
- UVC_TERM_DIRECTION(term) != dir)
- continue;
-
- if (nterms)
- p += sprintf(p, ",");
- if (++nterms >= 4) {
- p += sprintf(p, "...");
- break;
- }
- p += sprintf(p, "%u", term->id);
- }
-
- return p - buffer;
-}
-
-static const char *uvc_print_chain(struct uvc_video_chain *chain)
-{
- static char buffer[43];
- char *p = buffer;
-
- p += uvc_print_terms(&chain->entities, UVC_TERM_INPUT, p);
- p += sprintf(p, " -> ");
- uvc_print_terms(&chain->entities, UVC_TERM_OUTPUT, p);
-
- return buffer;
-}
-
-/*
- * Scan the device for video chains and register video devices.
- *
- * Chains are scanned starting at their output terminals and walked backwards.
- */
-static int uvc_scan_device(struct uvc_device *dev)
-{
- struct uvc_video_chain *chain;
- struct uvc_entity *term;
-
- list_for_each_entry(term, &dev->entities, list) {
- if (!UVC_ENTITY_IS_OTERM(term))
- continue;
-
- /* If the terminal is already included in a chain, skip it.
- * This can happen for chains that have multiple output
- * terminals, where all output terminals beside the first one
- * will be inserted in the chain in forward scans.
- */
- if (term->chain.next || term->chain.prev)
- continue;
-
- chain = kzalloc(sizeof(*chain), GFP_KERNEL);
- if (chain == NULL)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&chain->entities);
- mutex_init(&chain->ctrl_mutex);
- chain->dev = dev;
-
- if (uvc_scan_chain(chain, term) < 0) {
- kfree(chain);
- continue;
- }
-
- uvc_trace(UVC_TRACE_PROBE, "Found a valid video chain (%s).\n",
- uvc_print_chain(chain));
-
- list_add_tail(&chain->list, &dev->chains);
- }
-
- if (list_empty(&dev->chains)) {
- uvc_printk(KERN_INFO, "No valid video chain found.\n");
- return -1;
- }
-
- return 0;
-}
-
-/* ------------------------------------------------------------------------
- * Video device registration and unregistration
- */
-
-/*
- * Delete the UVC device.
- *
- * Called by the kernel when the last reference to the uvc_device structure
- * is released.
- *
- * As this function is called after or during disconnect(), all URBs have
- * already been canceled by the USB core. There is no need to kill the
- * interrupt URB manually.
- */
-static void uvc_delete(struct uvc_device *dev)
-{
- struct list_head *p, *n;
-
- usb_put_intf(dev->intf);
- usb_put_dev(dev->udev);
-
- uvc_status_cleanup(dev);
- uvc_ctrl_cleanup_device(dev);
-
- if (dev->vdev.dev)
- v4l2_device_unregister(&dev->vdev);
-#ifdef CONFIG_MEDIA_CONTROLLER
- if (media_devnode_is_registered(&dev->mdev.devnode))
- media_device_unregister(&dev->mdev);
-#endif
-
- list_for_each_safe(p, n, &dev->chains) {
- struct uvc_video_chain *chain;
- chain = list_entry(p, struct uvc_video_chain, list);
- kfree(chain);
- }
-
- list_for_each_safe(p, n, &dev->entities) {
- struct uvc_entity *entity;
- entity = list_entry(p, struct uvc_entity, list);
-#ifdef CONFIG_MEDIA_CONTROLLER
- uvc_mc_cleanup_entity(entity);
-#endif
- if (entity->vdev) {
- video_device_release(entity->vdev);
- entity->vdev = NULL;
- }
- kfree(entity);
- }
-
- list_for_each_safe(p, n, &dev->streams) {
- struct uvc_streaming *streaming;
- streaming = list_entry(p, struct uvc_streaming, list);
- usb_driver_release_interface(&uvc_driver.driver,
- streaming->intf);
- usb_put_intf(streaming->intf);
- kfree(streaming->format);
- kfree(streaming->header.bmaControls);
- kfree(streaming);
- }
-
- kfree(dev);
-}
-
-static void uvc_release(struct video_device *vdev)
-{
- struct uvc_streaming *stream = video_get_drvdata(vdev);
- struct uvc_device *dev = stream->dev;
-
- /* Decrement the registered streams count and delete the device when it
- * reaches zero.
- */
- if (atomic_dec_and_test(&dev->nstreams))
- uvc_delete(dev);
-}
-
-/*
- * Unregister the video devices.
- */
-static void uvc_unregister_video(struct uvc_device *dev)
-{
- struct uvc_streaming *stream;
-
- /* Unregistering all video devices might result in uvc_delete() being
- * called from inside the loop if there's no open file handle. To avoid
- * that, increment the stream count before iterating over the streams
- * and decrement it when done.
- */
- atomic_inc(&dev->nstreams);
-
- list_for_each_entry(stream, &dev->streams, list) {
- if (stream->vdev == NULL)
- continue;
-
- video_unregister_device(stream->vdev);
- stream->vdev = NULL;
-
- uvc_debugfs_cleanup_stream(stream);
- }
-
- /* Decrement the stream count and call uvc_delete explicitly if there
- * are no stream left.
- */
- if (atomic_dec_and_test(&dev->nstreams))
- uvc_delete(dev);
-}
-
-static int uvc_register_video(struct uvc_device *dev,
- struct uvc_streaming *stream)
-{
- struct video_device *vdev;
- int ret;
-
- /* Initialize the streaming interface with default streaming
- * parameters.
- */
- ret = uvc_video_init(stream);
- if (ret < 0) {
- uvc_printk(KERN_ERR, "Failed to initialize the device "
- "(%d).\n", ret);
- return ret;
- }
-
- uvc_debugfs_init_stream(stream);
-
- /* Register the device with V4L. */
- vdev = video_device_alloc();
- if (vdev == NULL) {
- uvc_printk(KERN_ERR, "Failed to allocate video device (%d).\n",
- ret);
- return -ENOMEM;
- }
-
- /* We already hold a reference to dev->udev. The video device will be
- * unregistered before the reference is released, so we don't need to
- * get another one.
- */
- vdev->v4l2_dev = &dev->vdev;
- vdev->fops = &uvc_fops;
- vdev->release = uvc_release;
- strlcpy(vdev->name, dev->name, sizeof vdev->name);
-
- /* Set the driver data before calling video_register_device, otherwise
- * uvc_v4l2_open might race us.
- */
- stream->vdev = vdev;
- video_set_drvdata(vdev, stream);
-
- ret = video_register_device(vdev, VFL_TYPE_GRABBER, -1);
- if (ret < 0) {
- uvc_printk(KERN_ERR, "Failed to register video device (%d).\n",
- ret);
- stream->vdev = NULL;
- video_device_release(vdev);
- return ret;
- }
-
- atomic_inc(&dev->nstreams);
- return 0;
-}
-
-/*
- * Register all video devices in all chains.
- */
-static int uvc_register_terms(struct uvc_device *dev,
- struct uvc_video_chain *chain)
-{
- struct uvc_streaming *stream;
- struct uvc_entity *term;
- int ret;
-
- list_for_each_entry(term, &chain->entities, chain) {
- if (UVC_ENTITY_TYPE(term) != UVC_TT_STREAMING)
- continue;
-
- stream = uvc_stream_by_id(dev, term->id);
- if (stream == NULL) {
- uvc_printk(KERN_INFO, "No streaming interface found "
- "for terminal %u.", term->id);
- continue;
- }
-
- stream->chain = chain;
- ret = uvc_register_video(dev, stream);
- if (ret < 0)
- return ret;
-
- term->vdev = stream->vdev;
- }
-
- return 0;
-}
-
-static int uvc_register_chains(struct uvc_device *dev)
-{
- struct uvc_video_chain *chain;
- int ret;
-
- list_for_each_entry(chain, &dev->chains, list) {
- ret = uvc_register_terms(dev, chain);
- if (ret < 0)
- return ret;
-
-#ifdef CONFIG_MEDIA_CONTROLLER
- ret = uvc_mc_register_entities(chain);
- if (ret < 0) {
- uvc_printk(KERN_INFO, "Failed to register entites "
- "(%d).\n", ret);
- }
-#endif
- }
-
- return 0;
-}
-
-/* ------------------------------------------------------------------------
- * USB probe, disconnect, suspend and resume
- */
-
-static int uvc_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_device *udev = interface_to_usbdev(intf);
- struct uvc_device *dev;
- int ret;
-
- if (id->idVendor && id->idProduct)
- uvc_trace(UVC_TRACE_PROBE, "Probing known UVC device %s "
- "(%04x:%04x)\n", udev->devpath, id->idVendor,
- id->idProduct);
- else
- uvc_trace(UVC_TRACE_PROBE, "Probing generic UVC device %s\n",
- udev->devpath);
-
- /* Allocate memory for the device and initialize it. */
- if ((dev = kzalloc(sizeof *dev, GFP_KERNEL)) == NULL)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&dev->entities);
- INIT_LIST_HEAD(&dev->chains);
- INIT_LIST_HEAD(&dev->streams);
- atomic_set(&dev->nstreams, 0);
- atomic_set(&dev->users, 0);
- atomic_set(&dev->nmappings, 0);
-
- dev->udev = usb_get_dev(udev);
- dev->intf = usb_get_intf(intf);
- dev->intfnum = intf->cur_altsetting->desc.bInterfaceNumber;
- dev->quirks = (uvc_quirks_param == -1)
- ? id->driver_info : uvc_quirks_param;
-
- if (udev->product != NULL)
- strlcpy(dev->name, udev->product, sizeof dev->name);
- else
- snprintf(dev->name, sizeof dev->name,
- "UVC Camera (%04x:%04x)",
- le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct));
-
- /* Parse the Video Class control descriptor. */
- if (uvc_parse_control(dev) < 0) {
- uvc_trace(UVC_TRACE_PROBE, "Unable to parse UVC "
- "descriptors.\n");
- goto error;
- }
-
- uvc_printk(KERN_INFO, "Found UVC %u.%02x device %s (%04x:%04x)\n",
- dev->uvc_version >> 8, dev->uvc_version & 0xff,
- udev->product ? udev->product : "<unnamed>",
- le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct));
-
- if (dev->quirks != id->driver_info) {
- uvc_printk(KERN_INFO, "Forcing device quirks to 0x%x by module "
- "parameter for testing purpose.\n", dev->quirks);
- uvc_printk(KERN_INFO, "Please report required quirks to the "
- "linux-uvc-devel mailing list.\n");
- }
-
- /* Register the media and V4L2 devices. */
-#ifdef CONFIG_MEDIA_CONTROLLER
- dev->mdev.dev = &intf->dev;
- strlcpy(dev->mdev.model, dev->name, sizeof(dev->mdev.model));
- if (udev->serial)
- strlcpy(dev->mdev.serial, udev->serial,
- sizeof(dev->mdev.serial));
- strcpy(dev->mdev.bus_info, udev->devpath);
- dev->mdev.hw_revision = le16_to_cpu(udev->descriptor.bcdDevice);
- dev->mdev.driver_version = LINUX_VERSION_CODE;
- if (media_device_register(&dev->mdev) < 0)
- goto error;
-
- dev->vdev.mdev = &dev->mdev;
-#endif
- if (v4l2_device_register(&intf->dev, &dev->vdev) < 0)
- goto error;
-
- /* Initialize controls. */
- if (uvc_ctrl_init_device(dev) < 0)
- goto error;
-
- /* Scan the device for video chains. */
- if (uvc_scan_device(dev) < 0)
- goto error;
-
- /* Register video device nodes. */
- if (uvc_register_chains(dev) < 0)
- goto error;
-
- /* Save our data pointer in the interface data. */
- usb_set_intfdata(intf, dev);
-
- /* Initialize the interrupt URB. */
- if ((ret = uvc_status_init(dev)) < 0) {
- uvc_printk(KERN_INFO, "Unable to initialize the status "
- "endpoint (%d), status interrupt will not be "
- "supported.\n", ret);
- }
-
- uvc_trace(UVC_TRACE_PROBE, "UVC device initialized.\n");
- usb_enable_autosuspend(udev);
- return 0;
-
-error:
- uvc_unregister_video(dev);
- return -ENODEV;
-}
-
-static void uvc_disconnect(struct usb_interface *intf)
-{
- struct uvc_device *dev = usb_get_intfdata(intf);
-
- /* Set the USB interface data to NULL. This can be done outside the
- * lock, as there's no other reader.
- */
- usb_set_intfdata(intf, NULL);
-
- if (intf->cur_altsetting->desc.bInterfaceSubClass ==
- UVC_SC_VIDEOSTREAMING)
- return;
-
- dev->state |= UVC_DEV_DISCONNECTED;
-
- uvc_unregister_video(dev);
-}
-
-static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
-{
- struct uvc_device *dev = usb_get_intfdata(intf);
- struct uvc_streaming *stream;
-
- uvc_trace(UVC_TRACE_SUSPEND, "Suspending interface %u\n",
- intf->cur_altsetting->desc.bInterfaceNumber);
-
- /* Controls are cached on the fly so they don't need to be saved. */
- if (intf->cur_altsetting->desc.bInterfaceSubClass ==
- UVC_SC_VIDEOCONTROL)
- return uvc_status_suspend(dev);
-
- list_for_each_entry(stream, &dev->streams, list) {
- if (stream->intf == intf)
- return uvc_video_suspend(stream);
- }
-
- uvc_trace(UVC_TRACE_SUSPEND, "Suspend: video streaming USB interface "
- "mismatch.\n");
- return -EINVAL;
-}
-
-static int __uvc_resume(struct usb_interface *intf, int reset)
-{
- struct uvc_device *dev = usb_get_intfdata(intf);
- struct uvc_streaming *stream;
-
- uvc_trace(UVC_TRACE_SUSPEND, "Resuming interface %u\n",
- intf->cur_altsetting->desc.bInterfaceNumber);
-
- if (intf->cur_altsetting->desc.bInterfaceSubClass ==
- UVC_SC_VIDEOCONTROL) {
- if (reset) {
- int ret = uvc_ctrl_resume_device(dev);
-
- if (ret < 0)
- return ret;
- }
-
- return uvc_status_resume(dev);
- }
-
- list_for_each_entry(stream, &dev->streams, list) {
- if (stream->intf == intf)
- return uvc_video_resume(stream, reset);
- }
-
- uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface "
- "mismatch.\n");
- return -EINVAL;
-}
-
-static int uvc_resume(struct usb_interface *intf)
-{
- return __uvc_resume(intf, 0);
-}
-
-static int uvc_reset_resume(struct usb_interface *intf)
-{
- return __uvc_resume(intf, 1);
-}
-
-/* ------------------------------------------------------------------------
- * Module parameters
- */
-
-static int uvc_clock_param_get(char *buffer, struct kernel_param *kp)
-{
- if (uvc_clock_param == CLOCK_MONOTONIC)
- return sprintf(buffer, "CLOCK_MONOTONIC");
- else
- return sprintf(buffer, "CLOCK_REALTIME");
-}
-
-static int uvc_clock_param_set(const char *val, struct kernel_param *kp)
-{
- if (strncasecmp(val, "clock_", strlen("clock_")) == 0)
- val += strlen("clock_");
-
- if (strcasecmp(val, "monotonic") == 0)
- uvc_clock_param = CLOCK_MONOTONIC;
- else if (strcasecmp(val, "realtime") == 0)
- uvc_clock_param = CLOCK_REALTIME;
- else
- return -EINVAL;
-
- return 0;
-}
-
-module_param_call(clock, uvc_clock_param_set, uvc_clock_param_get,
- &uvc_clock_param, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(clock, "Video buffers timestamp clock");
-module_param_named(nodrop, uvc_no_drop_param, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(nodrop, "Don't drop incomplete frames");
-module_param_named(quirks, uvc_quirks_param, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(quirks, "Forced device quirks");
-module_param_named(trace, uvc_trace_param, uint, S_IRUGO|S_IWUSR);
-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");
-
-/* ------------------------------------------------------------------------
- * Driver initialization and cleanup
- */
-
-/*
- * The Logitech cameras listed below have their interface class set to
- * VENDOR_SPEC because they don't announce themselves as UVC devices, even
- * though they are compliant.
- */
-static struct usb_device_id uvc_ids[] = {
- /* LogiLink Wireless Webcam */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x0416,
- .idProduct = 0xa91a,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Genius eFace 2025 */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x0458,
- .idProduct = 0x706e,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Microsoft Lifecam NX-6000 */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x045e,
- .idProduct = 0x00f8,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Microsoft Lifecam VX-7000 */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x045e,
- .idProduct = 0x0723,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Logitech Quickcam Fusion */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x046d,
- .idProduct = 0x08c1,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0 },
- /* Logitech Quickcam Orbit MP */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x046d,
- .idProduct = 0x08c2,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0 },
- /* Logitech Quickcam Pro for Notebook */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x046d,
- .idProduct = 0x08c3,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0 },
- /* Logitech Quickcam Pro 5000 */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x046d,
- .idProduct = 0x08c5,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0 },
- /* Logitech Quickcam OEM Dell Notebook */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x046d,
- .idProduct = 0x08c6,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0 },
- /* Logitech Quickcam OEM Cisco VT Camera II */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x046d,
- .idProduct = 0x08c7,
- .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0 },
- /* Chicony CNF7129 (Asus EEE 100HE) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x04f2,
- .idProduct = 0xb071,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_RESTRICT_FRAME_RATE },
- /* Alcor Micro AU3820 (Future Boy PC USB Webcam) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x058f,
- .idProduct = 0x3820,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Dell XPS m1530 */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x05a9,
- .idProduct = 0x2640,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_DEF },
- /* Apple Built-In iSight */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x05ac,
- .idProduct = 0x8501,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX
- | UVC_QUIRK_BUILTIN_ISIGHT },
- /* Foxlink ("HP Webcam" on HP Mini 5103) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x05c8,
- .idProduct = 0x0403,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
- /* Genesys Logic USB 2.0 PC Camera */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x05e3,
- .idProduct = 0x0505,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Hercules Classic Silver */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x06f8,
- .idProduct = 0x300c,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
- /* ViMicro Vega */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x0ac8,
- .idProduct = 0x332d,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
- /* ViMicro - Minoru3D */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x0ac8,
- .idProduct = 0x3410,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
- /* ViMicro Venus - Minoru3D */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x0ac8,
- .idProduct = 0x3420,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_FIX_BANDWIDTH },
- /* Ophir Optronics - SPCAM 620U */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x0bd3,
- .idProduct = 0x0555,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* MT6227 */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x0e8d,
- .idProduct = 0x0004,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX
- | UVC_QUIRK_PROBE_DEF },
- /* IMC Networks (Medion Akoya) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x13d3,
- .idProduct = 0x5103,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* JMicron USB2.0 XGA WebCam */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x152d,
- .idProduct = 0x0310,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Syntek (HP Spartan) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x174f,
- .idProduct = 0x5212,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Syntek (Samsung Q310) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x174f,
- .idProduct = 0x5931,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Syntek (Packard Bell EasyNote MX52 */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x174f,
- .idProduct = 0x8a12,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Syntek (Asus F9SG) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x174f,
- .idProduct = 0x8a31,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Syntek (Asus U3S) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x174f,
- .idProduct = 0x8a33,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Syntek (JAOtech Smart Terminal) */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x174f,
- .idProduct = 0x8a34,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Miricle 307K */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x17dc,
- .idProduct = 0x0202,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Lenovo Thinkpad SL400/SL500 */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x17ef,
- .idProduct = 0x480b,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STREAM_NO_FID },
- /* Aveo Technology USB 2.0 Camera */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x1871,
- .idProduct = 0x0306,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX
- | UVC_QUIRK_PROBE_EXTRAFIELDS },
- /* Ecamm Pico iMage */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x18cd,
- .idProduct = 0xcafe,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_EXTRAFIELDS },
- /* Manta MM-353 Plako */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x18ec,
- .idProduct = 0x3188,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* FSC WebCam V30S */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x18ec,
- .idProduct = 0x3288,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* Arkmicro unbranded */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x18ec,
- .idProduct = 0x3290,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_DEF },
- /* 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 },
- /* Bodelin ProScopeHR */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_DEV_HI
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x19ab,
- .idProduct = 0x1000,
- .bcdDevice_hi = 0x0126,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_STATUS_INTERVAL },
- /* MSI StarCam 370i */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x1b3b,
- .idProduct = 0x2951,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX },
- /* SiGma Micro USB Web Camera */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x1c4f,
- .idProduct = 0x3000,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = UVC_QUIRK_PROBE_MINMAX
- | UVC_QUIRK_IGNORE_SELECTOR_UNIT },
- /* Generic USB Video Class */
- { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
- {}
-};
-
-MODULE_DEVICE_TABLE(usb, uvc_ids);
-
-struct uvc_driver uvc_driver = {
- .driver = {
- .name = "uvcvideo",
- .probe = uvc_probe,
- .disconnect = uvc_disconnect,
- .suspend = uvc_suspend,
- .resume = uvc_resume,
- .reset_resume = uvc_reset_resume,
- .id_table = uvc_ids,
- .supports_autosuspend = 1,
- },
-};
-
-static int __init uvc_init(void)
-{
- int ret;
-
- uvc_debugfs_init();
-
- ret = usb_register(&uvc_driver.driver);
- if (ret < 0) {
- uvc_debugfs_cleanup();
- return ret;
- }
-
- printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n");
- return 0;
-}
-
-static void __exit uvc_cleanup(void)
-{
- usb_deregister(&uvc_driver.driver);
- uvc_debugfs_cleanup();
-}
-
-module_init(uvc_init);
-module_exit(uvc_cleanup);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRIVER_VERSION);
-
diff --git a/drivers/media/video/uvc/uvc_entity.c b/drivers/media/video/uvc/uvc_entity.c
deleted file mode 100644
index 29e239911d0..00000000000
--- a/drivers/media/video/uvc/uvc_entity.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * uvc_entity.c -- USB Video Class driver
- *
- * Copyright (C) 2005-2011
- * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/videodev2.h>
-
-#include <media/v4l2-common.h>
-
-#include "uvcvideo.h"
-
-/* ------------------------------------------------------------------------
- * Video subdevices registration and unregistration
- */
-
-static int uvc_mc_register_entity(struct uvc_video_chain *chain,
- struct uvc_entity *entity)
-{
- const u32 flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE;
- struct media_entity *sink;
- unsigned int i;
- int ret;
-
- sink = (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING)
- ? (entity->vdev ? &entity->vdev->entity : NULL)
- : &entity->subdev.entity;
- if (sink == NULL)
- return 0;
-
- for (i = 0; i < entity->num_pads; ++i) {
- struct media_entity *source;
- struct uvc_entity *remote;
- u8 remote_pad;
-
- if (!(entity->pads[i].flags & MEDIA_PAD_FL_SINK))
- continue;
-
- remote = uvc_entity_by_id(chain->dev, entity->baSourceID[i]);
- if (remote == NULL)
- return -EINVAL;
-
- source = (UVC_ENTITY_TYPE(remote) == UVC_TT_STREAMING)
- ? (remote->vdev ? &remote->vdev->entity : NULL)
- : &remote->subdev.entity;
- if (source == NULL)
- continue;
-
- remote_pad = remote->num_pads - 1;
- ret = media_entity_create_link(source, remote_pad,
- sink, i, flags);
- if (ret < 0)
- return ret;
- }
-
- if (UVC_ENTITY_TYPE(entity) == UVC_TT_STREAMING)
- return 0;
-
- return v4l2_device_register_subdev(&chain->dev->vdev, &entity->subdev);
-}
-
-static struct v4l2_subdev_ops uvc_subdev_ops = {
-};
-
-void uvc_mc_cleanup_entity(struct uvc_entity *entity)
-{
- if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING)
- media_entity_cleanup(&entity->subdev.entity);
- else if (entity->vdev != NULL)
- media_entity_cleanup(&entity->vdev->entity);
-}
-
-static int uvc_mc_init_entity(struct uvc_entity *entity)
-{
- int ret;
-
- if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) {
- v4l2_subdev_init(&entity->subdev, &uvc_subdev_ops);
- strlcpy(entity->subdev.name, entity->name,
- sizeof(entity->subdev.name));
-
- ret = media_entity_init(&entity->subdev.entity,
- entity->num_pads, entity->pads, 0);
- } else if (entity->vdev != NULL) {
- ret = media_entity_init(&entity->vdev->entity,
- entity->num_pads, entity->pads, 0);
- } else
- ret = 0;
-
- return ret;
-}
-
-int uvc_mc_register_entities(struct uvc_video_chain *chain)
-{
- struct uvc_entity *entity;
- int ret;
-
- list_for_each_entry(entity, &chain->entities, chain) {
- ret = uvc_mc_init_entity(entity);
- if (ret < 0) {
- uvc_printk(KERN_INFO, "Failed to initialize entity for "
- "entity %u\n", entity->id);
- return ret;
- }
- }
-
- list_for_each_entry(entity, &chain->entities, chain) {
- ret = uvc_mc_register_entity(chain, entity);
- if (ret < 0) {
- uvc_printk(KERN_INFO, "Failed to register entity for "
- "entity %u\n", entity->id);
- return ret;
- }
- }
-
- return 0;
-}
diff --git a/drivers/media/video/uvc/uvc_isight.c b/drivers/media/video/uvc/uvc_isight.c
deleted file mode 100644
index 8510e7259e7..00000000000
--- a/drivers/media/video/uvc/uvc_isight.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * uvc_isight.c -- USB Video Class driver - iSight support
- *
- * Copyright (C) 2006-2007
- * Ivan N. Zlatev <contact@i-nz.net>
- * Copyright (C) 2008-2009
- * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-#include <linux/usb.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-
-#include "uvcvideo.h"
-
-/* Built-in iSight webcams implements most of UVC 1.0 except a
- * different packet format. Instead of sending a header at the
- * beginning of each isochronous transfer payload, the webcam sends a
- * single header per image (on its own in a packet), followed by
- * packets containing data only.
- *
- * Offset Size (bytes) Description
- * ------------------------------------------------------------------
- * 0x00 1 Header length
- * 0x01 1 Flags (UVC-compliant)
- * 0x02 4 Always equal to '11223344'
- * 0x06 8 Always equal to 'deadbeefdeadface'
- * 0x0e 16 Unknown
- *
- * The header can be prefixed by an optional, unknown-purpose byte.
- */
-
-static int isight_decode(struct uvc_video_queue *queue, struct uvc_buffer *buf,
- const __u8 *data, unsigned int len)
-{
- static const __u8 hdr[] = {
- 0x11, 0x22, 0x33, 0x44,
- 0xde, 0xad, 0xbe, 0xef,
- 0xde, 0xad, 0xfa, 0xce
- };
-
- unsigned int maxlen, nbytes;
- __u8 *mem;
- int is_header = 0;
-
- if (buf == NULL)
- return 0;
-
- if ((len >= 14 && memcmp(&data[2], hdr, 12) == 0) ||
- (len >= 15 && memcmp(&data[3], hdr, 12) == 0)) {
- uvc_trace(UVC_TRACE_FRAME, "iSight header found\n");
- is_header = 1;
- }
-
- /* Synchronize to the input stream by waiting for a header packet. */
- if (buf->state != UVC_BUF_STATE_ACTIVE) {
- if (!is_header) {
- uvc_trace(UVC_TRACE_FRAME, "Dropping packet (out of "
- "sync).\n");
- return 0;
- }
-
- buf->state = UVC_BUF_STATE_ACTIVE;
- }
-
- /* Mark the buffer as done if we're at the beginning of a new frame.
- *
- * Empty buffers (bytesused == 0) don't trigger end of frame detection
- * as it doesn't make sense to return an empty buffer.
- */
- if (is_header && buf->bytesused != 0) {
- buf->state = UVC_BUF_STATE_DONE;
- return -EAGAIN;
- }
-
- /* Copy the video data to the buffer. Skip header packets, as they
- * contain no data.
- */
- if (!is_header) {
- maxlen = buf->length - buf->bytesused;
- mem = buf->mem + buf->bytesused;
- nbytes = min(len, maxlen);
- memcpy(mem, data, nbytes);
- buf->bytesused += nbytes;
-
- if (len > maxlen || buf->bytesused == buf->length) {
- uvc_trace(UVC_TRACE_FRAME, "Frame complete "
- "(overflow).\n");
- buf->state = UVC_BUF_STATE_DONE;
- }
- }
-
- return 0;
-}
-
-void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream,
- struct uvc_buffer *buf)
-{
- int ret, i;
-
- for (i = 0; i < urb->number_of_packets; ++i) {
- if (urb->iso_frame_desc[i].status < 0) {
- uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame "
- "lost (%d).\n",
- urb->iso_frame_desc[i].status);
- }
-
- /* Decode the payload packet.
- * uvc_video_decode is entered twice when a frame transition
- * has been detected because the end of frame can only be
- * reliably detected when the first packet of the new frame
- * is processed. The first pass detects the transition and
- * closes the previous frame's buffer, the second pass
- * processes the data of the first payload of the new frame.
- */
- do {
- ret = isight_decode(&stream->queue, buf,
- urb->transfer_buffer +
- urb->iso_frame_desc[i].offset,
- urb->iso_frame_desc[i].actual_length);
-
- if (buf == NULL)
- break;
-
- if (buf->state == UVC_BUF_STATE_DONE ||
- buf->state == UVC_BUF_STATE_ERROR)
- buf = uvc_queue_next_buffer(&stream->queue,
- buf);
- } while (ret == -EAGAIN);
- }
-}
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
deleted file mode 100644
index 9288fbd5001..00000000000
--- a/drivers/media/video/uvc/uvc_queue.c
+++ /dev/null
@@ -1,359 +0,0 @@
-/*
- * uvc_queue.c -- USB Video Class driver - Buffers management
- *
- * Copyright (C) 2005-2010
- * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-#include <linux/atomic.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <linux/vmalloc.h>
-#include <linux/wait.h>
-#include <media/videobuf2-vmalloc.h>
-
-#include "uvcvideo.h"
-
-/* ------------------------------------------------------------------------
- * Video buffers queue management.
- *
- * Video queues is initialized by uvc_queue_init(). The function performs
- * basic initialization of the uvc_video_queue struct and never fails.
- *
- * Video buffers are managed by videobuf2. The driver uses a mutex to protect
- * the videobuf2 queue operations by serializing calls to videobuf2 and a
- * spinlock to protect the IRQ queue that holds the buffers to be processed by
- * the driver.
- */
-
-/* -----------------------------------------------------------------------------
- * videobuf2 queue operations
- */
-
-static int uvc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
- unsigned int *nbuffers, unsigned int *nplanes,
- unsigned int sizes[], void *alloc_ctxs[])
-{
- struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
- struct uvc_streaming *stream =
- container_of(queue, struct uvc_streaming, queue);
-
- if (*nbuffers > UVC_MAX_VIDEO_BUFFERS)
- *nbuffers = UVC_MAX_VIDEO_BUFFERS;
-
- *nplanes = 1;
-
- sizes[0] = stream->ctrl.dwMaxVideoFrameSize;
-
- return 0;
-}
-
-static int uvc_buffer_prepare(struct vb2_buffer *vb)
-{
- struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
- struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
-
- if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
- vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0)) {
- uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n");
- return -EINVAL;
- }
-
- if (unlikely(queue->flags & UVC_QUEUE_DISCONNECTED))
- return -ENODEV;
-
- buf->state = UVC_BUF_STATE_QUEUED;
- buf->error = 0;
- buf->mem = vb2_plane_vaddr(vb, 0);
- buf->length = vb2_plane_size(vb, 0);
- if (vb->v4l2_buf.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- buf->bytesused = 0;
- else
- buf->bytesused = vb2_get_plane_payload(vb, 0);
-
- return 0;
-}
-
-static void uvc_buffer_queue(struct vb2_buffer *vb)
-{
- struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
- struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
- unsigned long flags;
-
- spin_lock_irqsave(&queue->irqlock, flags);
- if (likely(!(queue->flags & UVC_QUEUE_DISCONNECTED))) {
- list_add_tail(&buf->queue, &queue->irqqueue);
- } else {
- /* If the device is disconnected return the buffer to userspace
- * directly. The next QBUF call will fail with -ENODEV.
- */
- buf->state = UVC_BUF_STATE_ERROR;
- vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
- }
-
- spin_unlock_irqrestore(&queue->irqlock, flags);
-}
-
-static int uvc_buffer_finish(struct vb2_buffer *vb)
-{
- struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
- struct uvc_streaming *stream =
- container_of(queue, struct uvc_streaming, queue);
- struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
-
- uvc_video_clock_update(stream, &vb->v4l2_buf, buf);
- return 0;
-}
-
-static struct vb2_ops uvc_queue_qops = {
- .queue_setup = uvc_queue_setup,
- .buf_prepare = uvc_buffer_prepare,
- .buf_queue = uvc_buffer_queue,
- .buf_finish = uvc_buffer_finish,
-};
-
-void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
- int drop_corrupted)
-{
- queue->queue.type = type;
- queue->queue.io_modes = VB2_MMAP | VB2_USERPTR;
- queue->queue.drv_priv = queue;
- queue->queue.buf_struct_size = sizeof(struct uvc_buffer);
- queue->queue.ops = &uvc_queue_qops;
- queue->queue.mem_ops = &vb2_vmalloc_memops;
- vb2_queue_init(&queue->queue);
-
- mutex_init(&queue->mutex);
- spin_lock_init(&queue->irqlock);
- INIT_LIST_HEAD(&queue->irqqueue);
- queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0;
-}
-
-/* -----------------------------------------------------------------------------
- * V4L2 queue operations
- */
-
-int uvc_alloc_buffers(struct uvc_video_queue *queue,
- struct v4l2_requestbuffers *rb)
-{
- int ret;
-
- mutex_lock(&queue->mutex);
- ret = vb2_reqbufs(&queue->queue, rb);
- mutex_unlock(&queue->mutex);
-
- return ret ? ret : rb->count;
-}
-
-void uvc_free_buffers(struct uvc_video_queue *queue)
-{
- mutex_lock(&queue->mutex);
- vb2_queue_release(&queue->queue);
- mutex_unlock(&queue->mutex);
-}
-
-int uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
-{
- int ret;
-
- mutex_lock(&queue->mutex);
- ret = vb2_querybuf(&queue->queue, buf);
- mutex_unlock(&queue->mutex);
-
- return ret;
-}
-
-int uvc_queue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
-{
- int ret;
-
- mutex_lock(&queue->mutex);
- ret = vb2_qbuf(&queue->queue, buf);
- mutex_unlock(&queue->mutex);
-
- return ret;
-}
-
-int uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf,
- int nonblocking)
-{
- int ret;
-
- mutex_lock(&queue->mutex);
- ret = vb2_dqbuf(&queue->queue, buf, nonblocking);
- mutex_unlock(&queue->mutex);
-
- return ret;
-}
-
-int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
-{
- int ret;
-
- mutex_lock(&queue->mutex);
- ret = vb2_mmap(&queue->queue, vma);
- mutex_unlock(&queue->mutex);
-
- return ret;
-}
-
-#ifndef CONFIG_MMU
-unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
- unsigned long pgoff)
-{
- unsigned long ret;
-
- mutex_lock(&queue->mutex);
- ret = vb2_get_unmapped_area(&queue->queue, 0, 0, pgoff, 0);
- mutex_unlock(&queue->mutex);
- return ret;
-}
-#endif
-
-unsigned int uvc_queue_poll(struct uvc_video_queue *queue, struct file *file,
- poll_table *wait)
-{
- unsigned int ret;
-
- mutex_lock(&queue->mutex);
- ret = vb2_poll(&queue->queue, file, wait);
- mutex_unlock(&queue->mutex);
-
- return ret;
-}
-
-/* -----------------------------------------------------------------------------
- *
- */
-
-/*
- * Check if buffers have been allocated.
- */
-int uvc_queue_allocated(struct uvc_video_queue *queue)
-{
- int allocated;
-
- mutex_lock(&queue->mutex);
- allocated = vb2_is_busy(&queue->queue);
- mutex_unlock(&queue->mutex);
-
- return allocated;
-}
-
-/*
- * Enable or disable the video buffers queue.
- *
- * The queue must be enabled before starting video acquisition and must be
- * disabled after stopping it. This ensures that the video buffers queue
- * state can be properly initialized before buffers are accessed from the
- * interrupt handler.
- *
- * Enabling the video queue returns -EBUSY if the queue is already enabled.
- *
- * Disabling the video queue cancels the queue and removes all buffers from
- * the main queue.
- *
- * This function can't be called from interrupt context. Use
- * uvc_queue_cancel() instead.
- */
-int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
-{
- unsigned long flags;
- int ret;
-
- mutex_lock(&queue->mutex);
- if (enable) {
- ret = vb2_streamon(&queue->queue, queue->queue.type);
- if (ret < 0)
- goto done;
-
- queue->buf_used = 0;
- } else {
- ret = vb2_streamoff(&queue->queue, queue->queue.type);
- if (ret < 0)
- goto done;
-
- spin_lock_irqsave(&queue->irqlock, flags);
- INIT_LIST_HEAD(&queue->irqqueue);
- spin_unlock_irqrestore(&queue->irqlock, flags);
- }
-
-done:
- mutex_unlock(&queue->mutex);
- return ret;
-}
-
-/*
- * Cancel the video buffers queue.
- *
- * Cancelling the queue marks all buffers on the irq queue as erroneous,
- * wakes them up and removes them from the queue.
- *
- * If the disconnect parameter is set, further calls to uvc_queue_buffer will
- * fail with -ENODEV.
- *
- * This function acquires the irq spinlock and can be called from interrupt
- * context.
- */
-void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
-{
- struct uvc_buffer *buf;
- unsigned long flags;
-
- spin_lock_irqsave(&queue->irqlock, flags);
- while (!list_empty(&queue->irqqueue)) {
- buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
- queue);
- list_del(&buf->queue);
- buf->state = UVC_BUF_STATE_ERROR;
- vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
- }
- /* This must be protected by the irqlock spinlock to avoid race
- * conditions between uvc_buffer_queue and the disconnection event that
- * could result in an interruptible wait in uvc_dequeue_buffer. Do not
- * blindly replace this logic by checking for the UVC_QUEUE_DISCONNECTED
- * state outside the queue code.
- */
- if (disconnect)
- queue->flags |= UVC_QUEUE_DISCONNECTED;
- spin_unlock_irqrestore(&queue->irqlock, flags);
-}
-
-struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
- struct uvc_buffer *buf)
-{
- struct uvc_buffer *nextbuf;
- unsigned long flags;
-
- if ((queue->flags & UVC_QUEUE_DROP_CORRUPTED) && buf->error) {
- buf->error = 0;
- buf->state = UVC_BUF_STATE_QUEUED;
- vb2_set_plane_payload(&buf->buf, 0, 0);
- return buf;
- }
-
- spin_lock_irqsave(&queue->irqlock, flags);
- list_del(&buf->queue);
- if (!list_empty(&queue->irqqueue))
- nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
- queue);
- else
- nextbuf = NULL;
- spin_unlock_irqrestore(&queue->irqlock, flags);
-
- buf->state = buf->error ? VB2_BUF_STATE_ERROR : UVC_BUF_STATE_DONE;
- vb2_set_plane_payload(&buf->buf, 0, buf->bytesused);
- vb2_buffer_done(&buf->buf, VB2_BUF_STATE_DONE);
-
- return nextbuf;
-}
diff --git a/drivers/media/video/uvc/uvc_status.c b/drivers/media/video/uvc/uvc_status.c
deleted file mode 100644
index b7492775e6a..00000000000
--- a/drivers/media/video/uvc/uvc_status.c
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * uvc_status.c -- USB Video Class driver - Status endpoint
- *
- * Copyright (C) 2005-2009
- * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/input.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/usb/input.h>
-
-#include "uvcvideo.h"
-
-/* --------------------------------------------------------------------------
- * Input device
- */
-#ifdef CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV
-static int uvc_input_init(struct uvc_device *dev)
-{
- struct input_dev *input;
- int ret;
-
- input = input_allocate_device();
- if (input == NULL)
- return -ENOMEM;
-
- usb_make_path(dev->udev, dev->input_phys, sizeof(dev->input_phys));
- strlcat(dev->input_phys, "/button", sizeof(dev->input_phys));
-
- input->name = dev->name;
- input->phys = dev->input_phys;
- usb_to_input_id(dev->udev, &input->id);
- input->dev.parent = &dev->intf->dev;
-
- __set_bit(EV_KEY, input->evbit);
- __set_bit(KEY_CAMERA, input->keybit);
-
- if ((ret = input_register_device(input)) < 0)
- goto error;
-
- dev->input = input;
- return 0;
-
-error:
- input_free_device(input);
- return ret;
-}
-
-static void uvc_input_cleanup(struct uvc_device *dev)
-{
- if (dev->input)
- input_unregister_device(dev->input);
-}
-
-static void uvc_input_report_key(struct uvc_device *dev, unsigned int code,
- int value)
-{
- if (dev->input) {
- input_report_key(dev->input, code, value);
- input_sync(dev->input);
- }
-}
-
-#else
-#define uvc_input_init(dev)
-#define uvc_input_cleanup(dev)
-#define uvc_input_report_key(dev, code, value)
-#endif /* CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV */
-
-/* --------------------------------------------------------------------------
- * Status interrupt endpoint
- */
-static void uvc_event_streaming(struct uvc_device *dev, __u8 *data, int len)
-{
- if (len < 3) {
- uvc_trace(UVC_TRACE_STATUS, "Invalid streaming status event "
- "received.\n");
- return;
- }
-
- if (data[2] == 0) {
- if (len < 4)
- return;
- uvc_trace(UVC_TRACE_STATUS, "Button (intf %u) %s len %d\n",
- data[1], data[3] ? "pressed" : "released", len);
- uvc_input_report_key(dev, KEY_CAMERA, data[3]);
- } else {
- uvc_trace(UVC_TRACE_STATUS, "Stream %u error event %02x %02x "
- "len %d.\n", data[1], data[2], data[3], len);
- }
-}
-
-static void uvc_event_control(struct uvc_device *dev, __u8 *data, int len)
-{
- char *attrs[3] = { "value", "info", "failure" };
-
- if (len < 6 || data[2] != 0 || data[4] > 2) {
- uvc_trace(UVC_TRACE_STATUS, "Invalid control status event "
- "received.\n");
- return;
- }
-
- uvc_trace(UVC_TRACE_STATUS, "Control %u/%u %s change len %d.\n",
- data[1], data[3], attrs[data[4]], len);
-}
-
-static void uvc_status_complete(struct urb *urb)
-{
- struct uvc_device *dev = urb->context;
- int len, ret;
-
- switch (urb->status) {
- case 0:
- break;
-
- case -ENOENT: /* usb_kill_urb() called. */
- case -ECONNRESET: /* usb_unlink_urb() called. */
- case -ESHUTDOWN: /* The endpoint is being disabled. */
- case -EPROTO: /* Device is disconnected (reported by some
- * host controller). */
- return;
-
- default:
- uvc_printk(KERN_WARNING, "Non-zero status (%d) in status "
- "completion handler.\n", urb->status);
- return;
- }
-
- len = urb->actual_length;
- if (len > 0) {
- switch (dev->status[0] & 0x0f) {
- case UVC_STATUS_TYPE_CONTROL:
- uvc_event_control(dev, dev->status, len);
- break;
-
- case UVC_STATUS_TYPE_STREAMING:
- uvc_event_streaming(dev, dev->status, len);
- break;
-
- default:
- uvc_trace(UVC_TRACE_STATUS, "Unknown status event "
- "type %u.\n", dev->status[0]);
- break;
- }
- }
-
- /* Resubmit the URB. */
- urb->interval = dev->int_ep->desc.bInterval;
- if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
- uvc_printk(KERN_ERR, "Failed to resubmit status URB (%d).\n",
- ret);
- }
-}
-
-int uvc_status_init(struct uvc_device *dev)
-{
- struct usb_host_endpoint *ep = dev->int_ep;
- unsigned int pipe;
- int interval;
-
- if (ep == NULL)
- return 0;
-
- uvc_input_init(dev);
-
- dev->status = kzalloc(UVC_MAX_STATUS_SIZE, GFP_KERNEL);
- if (dev->status == NULL)
- return -ENOMEM;
-
- dev->int_urb = usb_alloc_urb(0, GFP_KERNEL);
- if (dev->int_urb == NULL) {
- kfree(dev->status);
- return -ENOMEM;
- }
-
- pipe = usb_rcvintpipe(dev->udev, ep->desc.bEndpointAddress);
-
- /* For high-speed interrupt endpoints, the bInterval value is used as
- * an exponent of two. Some developers forgot about it.
- */
- interval = ep->desc.bInterval;
- if (interval > 16 && dev->udev->speed == USB_SPEED_HIGH &&
- (dev->quirks & UVC_QUIRK_STATUS_INTERVAL))
- interval = fls(interval) - 1;
-
- usb_fill_int_urb(dev->int_urb, dev->udev, pipe,
- dev->status, UVC_MAX_STATUS_SIZE, uvc_status_complete,
- dev, interval);
-
- return 0;
-}
-
-void uvc_status_cleanup(struct uvc_device *dev)
-{
- usb_kill_urb(dev->int_urb);
- usb_free_urb(dev->int_urb);
- kfree(dev->status);
- uvc_input_cleanup(dev);
-}
-
-int uvc_status_start(struct uvc_device *dev)
-{
- if (dev->int_urb == NULL)
- return 0;
-
- return usb_submit_urb(dev->int_urb, GFP_KERNEL);
-}
-
-void uvc_status_stop(struct uvc_device *dev)
-{
- usb_kill_urb(dev->int_urb);
-}
-
-int uvc_status_suspend(struct uvc_device *dev)
-{
- if (atomic_read(&dev->users))
- usb_kill_urb(dev->int_urb);
-
- return 0;
-}
-
-int uvc_status_resume(struct uvc_device *dev)
-{
- if (dev->int_urb == NULL || atomic_read(&dev->users) == 0)
- return 0;
-
- return usb_submit_urb(dev->int_urb, GFP_NOIO);
-}
-
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
deleted file mode 100644
index f00db3060e0..00000000000
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ /dev/null
@@ -1,1317 +0,0 @@
-/*
- * uvc_v4l2.c -- USB Video Class driver - V4L2 API
- *
- * Copyright (C) 2005-2010
- * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-#include <linux/compat.h>
-#include <linux/kernel.h>
-#include <linux/version.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <linux/vmalloc.h>
-#include <linux/mm.h>
-#include <linux/wait.h>
-#include <linux/atomic.h>
-
-#include <media/v4l2-common.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-ioctl.h>
-
-#include "uvcvideo.h"
-
-/* ------------------------------------------------------------------------
- * UVC ioctls
- */
-static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
- struct uvc_xu_control_mapping *xmap)
-{
- struct uvc_control_mapping *map;
- unsigned int size;
- int ret;
-
- map = kzalloc(sizeof *map, GFP_KERNEL);
- if (map == NULL)
- return -ENOMEM;
-
- map->id = xmap->id;
- memcpy(map->name, xmap->name, sizeof map->name);
- memcpy(map->entity, xmap->entity, sizeof map->entity);
- map->selector = xmap->selector;
- map->size = xmap->size;
- map->offset = xmap->offset;
- map->v4l2_type = xmap->v4l2_type;
- map->data_type = xmap->data_type;
-
- switch (xmap->v4l2_type) {
- case V4L2_CTRL_TYPE_INTEGER:
- case V4L2_CTRL_TYPE_BOOLEAN:
- case V4L2_CTRL_TYPE_BUTTON:
- break;
-
- case V4L2_CTRL_TYPE_MENU:
- /* Prevent excessive memory consumption, as well as integer
- * overflows.
- */
- if (xmap->menu_count == 0 ||
- xmap->menu_count > UVC_MAX_CONTROL_MENU_ENTRIES) {
- ret = -EINVAL;
- goto done;
- }
-
- size = xmap->menu_count * sizeof(*map->menu_info);
- map->menu_info = kmalloc(size, GFP_KERNEL);
- if (map->menu_info == NULL) {
- ret = -ENOMEM;
- goto done;
- }
-
- if (copy_from_user(map->menu_info, xmap->menu_info, size)) {
- ret = -EFAULT;
- goto done;
- }
-
- map->menu_count = xmap->menu_count;
- break;
-
- default:
- uvc_trace(UVC_TRACE_CONTROL, "Unsupported V4L2 control type "
- "%u.\n", xmap->v4l2_type);
- ret = -ENOTTY;
- goto done;
- }
-
- ret = uvc_ctrl_add_mapping(chain, map);
-
-done:
- kfree(map->menu_info);
- kfree(map);
-
- return ret;
-}
-
-/* ------------------------------------------------------------------------
- * V4L2 interface
- */
-
-/*
- * Find the frame interval closest to the requested frame interval for the
- * given frame format and size. This should be done by the device as part of
- * the Video Probe and Commit negotiation, but some hardware don't implement
- * that feature.
- */
-static __u32 uvc_try_frame_interval(struct uvc_frame *frame, __u32 interval)
-{
- unsigned int i;
-
- if (frame->bFrameIntervalType) {
- __u32 best = -1, dist;
-
- for (i = 0; i < frame->bFrameIntervalType; ++i) {
- dist = interval > frame->dwFrameInterval[i]
- ? interval - frame->dwFrameInterval[i]
- : frame->dwFrameInterval[i] - interval;
-
- if (dist > best)
- break;
-
- best = dist;
- }
-
- interval = frame->dwFrameInterval[i-1];
- } else {
- const __u32 min = frame->dwFrameInterval[0];
- const __u32 max = frame->dwFrameInterval[1];
- const __u32 step = frame->dwFrameInterval[2];
-
- interval = min + (interval - min + step/2) / step * step;
- if (interval > max)
- interval = max;
- }
-
- return interval;
-}
-
-static int uvc_v4l2_try_format(struct uvc_streaming *stream,
- struct v4l2_format *fmt, struct uvc_streaming_control *probe,
- struct uvc_format **uvc_format, struct uvc_frame **uvc_frame)
-{
- struct uvc_format *format = NULL;
- struct uvc_frame *frame = NULL;
- __u16 rw, rh;
- unsigned int d, maxd;
- unsigned int i;
- __u32 interval;
- int ret = 0;
- __u8 *fcc;
-
- if (fmt->type != stream->type)
- return -EINVAL;
-
- fcc = (__u8 *)&fmt->fmt.pix.pixelformat;
- uvc_trace(UVC_TRACE_FORMAT, "Trying format 0x%08x (%c%c%c%c): %ux%u.\n",
- fmt->fmt.pix.pixelformat,
- fcc[0], fcc[1], fcc[2], fcc[3],
- fmt->fmt.pix.width, fmt->fmt.pix.height);
-
- /* Check if the hardware supports the requested format. */
- for (i = 0; i < stream->nformats; ++i) {
- format = &stream->format[i];
- if (format->fcc == fmt->fmt.pix.pixelformat)
- break;
- }
-
- if (format == NULL || format->fcc != fmt->fmt.pix.pixelformat) {
- uvc_trace(UVC_TRACE_FORMAT, "Unsupported format 0x%08x.\n",
- fmt->fmt.pix.pixelformat);
- return -EINVAL;
- }
-
- /* Find the closest image size. The distance between image sizes is
- * the size in pixels of the non-overlapping regions between the
- * requested size and the frame-specified size.
- */
- rw = fmt->fmt.pix.width;
- rh = fmt->fmt.pix.height;
- maxd = (unsigned int)-1;
-
- for (i = 0; i < format->nframes; ++i) {
- __u16 w = format->frame[i].wWidth;
- __u16 h = format->frame[i].wHeight;
-
- d = min(w, rw) * min(h, rh);
- d = w*h + rw*rh - 2*d;
- if (d < maxd) {
- maxd = d;
- frame = &format->frame[i];
- }
-
- if (maxd == 0)
- break;
- }
-
- if (frame == NULL) {
- uvc_trace(UVC_TRACE_FORMAT, "Unsupported size %ux%u.\n",
- fmt->fmt.pix.width, fmt->fmt.pix.height);
- return -EINVAL;
- }
-
- /* Use the default frame interval. */
- interval = frame->dwDefaultFrameInterval;
- uvc_trace(UVC_TRACE_FORMAT, "Using default frame interval %u.%u us "
- "(%u.%u fps).\n", interval/10, interval%10, 10000000/interval,
- (100000000/interval)%10);
-
- /* Set the format index, frame index and frame interval. */
- memset(probe, 0, sizeof *probe);
- probe->bmHint = 1; /* dwFrameInterval */
- probe->bFormatIndex = format->index;
- probe->bFrameIndex = frame->bFrameIndex;
- probe->dwFrameInterval = uvc_try_frame_interval(frame, interval);
- /* Some webcams stall the probe control set request when the
- * dwMaxVideoFrameSize field is set to zero. The UVC specification
- * clearly states that the field is read-only from the host, so this
- * is a webcam bug. Set dwMaxVideoFrameSize to the value reported by
- * the webcam to work around the problem.
- *
- * The workaround could probably be enabled for all webcams, so the
- * quirk can be removed if needed. It's currently useful to detect
- * webcam bugs and fix them before they hit the market (providing
- * developers test their webcams with the Linux driver as well as with
- * the Windows driver).
- */
- mutex_lock(&stream->mutex);
- if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
- probe->dwMaxVideoFrameSize =
- stream->ctrl.dwMaxVideoFrameSize;
-
- /* Probe the device. */
- ret = uvc_probe_video(stream, probe);
- mutex_unlock(&stream->mutex);
- if (ret < 0)
- goto done;
-
- fmt->fmt.pix.width = frame->wWidth;
- fmt->fmt.pix.height = frame->wHeight;
- fmt->fmt.pix.field = V4L2_FIELD_NONE;
- fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8;
- fmt->fmt.pix.sizeimage = probe->dwMaxVideoFrameSize;
- fmt->fmt.pix.colorspace = format->colorspace;
- fmt->fmt.pix.priv = 0;
-
- if (uvc_format != NULL)
- *uvc_format = format;
- if (uvc_frame != NULL)
- *uvc_frame = frame;
-
-done:
- return ret;
-}
-
-static int uvc_v4l2_get_format(struct uvc_streaming *stream,
- struct v4l2_format *fmt)
-{
- struct uvc_format *format;
- struct uvc_frame *frame;
- int ret = 0;
-
- if (fmt->type != stream->type)
- return -EINVAL;
-
- mutex_lock(&stream->mutex);
- format = stream->cur_format;
- frame = stream->cur_frame;
-
- if (format == NULL || frame == NULL) {
- ret = -EINVAL;
- goto done;
- }
-
- fmt->fmt.pix.pixelformat = format->fcc;
- fmt->fmt.pix.width = frame->wWidth;
- fmt->fmt.pix.height = frame->wHeight;
- fmt->fmt.pix.field = V4L2_FIELD_NONE;
- fmt->fmt.pix.bytesperline = format->bpp * frame->wWidth / 8;
- fmt->fmt.pix.sizeimage = stream->ctrl.dwMaxVideoFrameSize;
- fmt->fmt.pix.colorspace = format->colorspace;
- fmt->fmt.pix.priv = 0;
-
-done:
- mutex_unlock(&stream->mutex);
- return ret;
-}
-
-static int uvc_v4l2_set_format(struct uvc_streaming *stream,
- struct v4l2_format *fmt)
-{
- struct uvc_streaming_control probe;
- struct uvc_format *format;
- struct uvc_frame *frame;
- int ret;
-
- if (fmt->type != stream->type)
- return -EINVAL;
-
- ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame);
- if (ret < 0)
- return ret;
-
- mutex_lock(&stream->mutex);
-
- if (uvc_queue_allocated(&stream->queue)) {
- ret = -EBUSY;
- goto done;
- }
-
- memcpy(&stream->ctrl, &probe, sizeof probe);
- stream->cur_format = format;
- stream->cur_frame = frame;
-
-done:
- mutex_unlock(&stream->mutex);
- return ret;
-}
-
-static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
- struct v4l2_streamparm *parm)
-{
- uint32_t numerator, denominator;
-
- if (parm->type != stream->type)
- return -EINVAL;
-
- mutex_lock(&stream->mutex);
- numerator = stream->ctrl.dwFrameInterval;
- mutex_unlock(&stream->mutex);
-
- denominator = 10000000;
- uvc_simplify_fraction(&numerator, &denominator, 8, 333);
-
- memset(parm, 0, sizeof *parm);
- parm->type = stream->type;
-
- if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
- parm->parm.capture.capturemode = 0;
- parm->parm.capture.timeperframe.numerator = numerator;
- parm->parm.capture.timeperframe.denominator = denominator;
- parm->parm.capture.extendedmode = 0;
- parm->parm.capture.readbuffers = 0;
- } else {
- parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
- parm->parm.output.outputmode = 0;
- parm->parm.output.timeperframe.numerator = numerator;
- parm->parm.output.timeperframe.denominator = denominator;
- }
-
- return 0;
-}
-
-static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
- struct v4l2_streamparm *parm)
-{
- struct uvc_streaming_control probe;
- struct v4l2_fract timeperframe;
- uint32_t interval;
- int ret;
-
- if (parm->type != stream->type)
- return -EINVAL;
-
- if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- timeperframe = parm->parm.capture.timeperframe;
- else
- timeperframe = parm->parm.output.timeperframe;
-
- interval = uvc_fraction_to_interval(timeperframe.numerator,
- timeperframe.denominator);
- uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n",
- timeperframe.numerator, timeperframe.denominator, interval);
-
- mutex_lock(&stream->mutex);
-
- if (uvc_queue_streaming(&stream->queue)) {
- mutex_unlock(&stream->mutex);
- return -EBUSY;
- }
-
- memcpy(&probe, &stream->ctrl, sizeof probe);
- probe.dwFrameInterval =
- uvc_try_frame_interval(stream->cur_frame, interval);
-
- /* Probe the device with the new settings. */
- ret = uvc_probe_video(stream, &probe);
- if (ret < 0) {
- mutex_unlock(&stream->mutex);
- return ret;
- }
-
- memcpy(&stream->ctrl, &probe, sizeof probe);
- mutex_unlock(&stream->mutex);
-
- /* Return the actual frame period. */
- timeperframe.numerator = probe.dwFrameInterval;
- timeperframe.denominator = 10000000;
- uvc_simplify_fraction(&timeperframe.numerator,
- &timeperframe.denominator, 8, 333);
-
- if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- parm->parm.capture.timeperframe = timeperframe;
- else
- parm->parm.output.timeperframe = timeperframe;
-
- return 0;
-}
-
-/* ------------------------------------------------------------------------
- * Privilege management
- */
-
-/*
- * Privilege management is the multiple-open implementation basis. The current
- * implementation is completely transparent for the end-user and doesn't
- * require explicit use of the VIDIOC_G_PRIORITY and VIDIOC_S_PRIORITY ioctls.
- * Those ioctls enable finer control on the device (by making possible for a
- * user to request exclusive access to a device), but are not mature yet.
- * Switching to the V4L2 priority mechanism might be considered in the future
- * if this situation changes.
- *
- * Each open instance of a UVC device can either be in a privileged or
- * unprivileged state. Only a single instance can be in a privileged state at
- * a given time. Trying to perform an operation that requires privileges will
- * automatically acquire the required privileges if possible, or return -EBUSY
- * otherwise. Privileges are dismissed when closing the instance or when
- * freeing the video buffers using VIDIOC_REQBUFS.
- *
- * Operations that require privileges are:
- *
- * - VIDIOC_S_INPUT
- * - VIDIOC_S_PARM
- * - VIDIOC_S_FMT
- * - VIDIOC_REQBUFS
- */
-static int uvc_acquire_privileges(struct uvc_fh *handle)
-{
- /* Always succeed if the handle is already privileged. */
- if (handle->state == UVC_HANDLE_ACTIVE)
- return 0;
-
- /* Check if the device already has a privileged handle. */
- if (atomic_inc_return(&handle->stream->active) != 1) {
- atomic_dec(&handle->stream->active);
- return -EBUSY;
- }
-
- handle->state = UVC_HANDLE_ACTIVE;
- return 0;
-}
-
-static void uvc_dismiss_privileges(struct uvc_fh *handle)
-{
- if (handle->state == UVC_HANDLE_ACTIVE)
- atomic_dec(&handle->stream->active);
-
- handle->state = UVC_HANDLE_PASSIVE;
-}
-
-static int uvc_has_privileges(struct uvc_fh *handle)
-{
- return handle->state == UVC_HANDLE_ACTIVE;
-}
-
-/* ------------------------------------------------------------------------
- * V4L2 file operations
- */
-
-static int uvc_v4l2_open(struct file *file)
-{
- struct uvc_streaming *stream;
- struct uvc_fh *handle;
- int ret = 0;
-
- uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_open\n");
- stream = video_drvdata(file);
-
- if (stream->dev->state & UVC_DEV_DISCONNECTED)
- return -ENODEV;
-
- ret = usb_autopm_get_interface(stream->dev->intf);
- if (ret < 0)
- return ret;
-
- /* Create the device handle. */
- handle = kzalloc(sizeof *handle, GFP_KERNEL);
- if (handle == NULL) {
- usb_autopm_put_interface(stream->dev->intf);
- return -ENOMEM;
- }
-
- if (atomic_inc_return(&stream->dev->users) == 1) {
- ret = uvc_status_start(stream->dev);
- if (ret < 0) {
- usb_autopm_put_interface(stream->dev->intf);
- atomic_dec(&stream->dev->users);
- kfree(handle);
- return ret;
- }
- }
-
- v4l2_fh_init(&handle->vfh, stream->vdev);
- v4l2_fh_add(&handle->vfh);
- handle->chain = stream->chain;
- handle->stream = stream;
- handle->state = UVC_HANDLE_PASSIVE;
- file->private_data = handle;
-
- return 0;
-}
-
-static int uvc_v4l2_release(struct file *file)
-{
- struct uvc_fh *handle = file->private_data;
- struct uvc_streaming *stream = handle->stream;
-
- uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n");
-
- /* Only free resources if this is a privileged handle. */
- if (uvc_has_privileges(handle)) {
- uvc_video_enable(stream, 0);
- uvc_free_buffers(&stream->queue);
- }
-
- /* Release the file handle. */
- uvc_dismiss_privileges(handle);
- v4l2_fh_del(&handle->vfh);
- v4l2_fh_exit(&handle->vfh);
- kfree(handle);
- file->private_data = NULL;
-
- if (atomic_dec_return(&stream->dev->users) == 0)
- uvc_status_stop(stream->dev);
-
- usb_autopm_put_interface(stream->dev->intf);
- return 0;
-}
-
-static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
-{
- struct video_device *vdev = video_devdata(file);
- struct uvc_fh *handle = file->private_data;
- struct uvc_video_chain *chain = handle->chain;
- struct uvc_streaming *stream = handle->stream;
- long ret = 0;
-
- switch (cmd) {
- /* Query capabilities */
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *cap = arg;
-
- memset(cap, 0, sizeof *cap);
- strlcpy(cap->driver, "uvcvideo", sizeof cap->driver);
- strlcpy(cap->card, vdev->name, sizeof cap->card);
- usb_make_path(stream->dev->udev,
- cap->bus_info, sizeof(cap->bus_info));
- cap->version = LINUX_VERSION_CODE;
- if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
- | V4L2_CAP_STREAMING;
- else
- cap->capabilities = V4L2_CAP_VIDEO_OUTPUT
- | V4L2_CAP_STREAMING;
- break;
- }
-
- /* Get, Set & Query control */
- case VIDIOC_QUERYCTRL:
- return uvc_query_v4l2_ctrl(chain, arg);
-
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- struct v4l2_ext_control xctrl;
-
- memset(&xctrl, 0, sizeof xctrl);
- xctrl.id = ctrl->id;
-
- ret = uvc_ctrl_begin(chain);
- if (ret < 0)
- return ret;
-
- ret = uvc_ctrl_get(chain, &xctrl);
- uvc_ctrl_rollback(handle);
- if (ret >= 0)
- ctrl->value = xctrl.value;
- break;
- }
-
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- struct v4l2_ext_control xctrl;
-
- memset(&xctrl, 0, sizeof xctrl);
- xctrl.id = ctrl->id;
- xctrl.value = ctrl->value;
-
- ret = uvc_ctrl_begin(chain);
- if (ret < 0)
- return ret;
-
- ret = uvc_ctrl_set(chain, &xctrl);
- if (ret < 0) {
- uvc_ctrl_rollback(handle);
- return ret;
- }
- ret = uvc_ctrl_commit(handle, &xctrl, 1);
- if (ret == 0)
- ctrl->value = xctrl.value;
- break;
- }
-
- case VIDIOC_QUERYMENU:
- return uvc_query_v4l2_menu(chain, arg);
-
- case VIDIOC_G_EXT_CTRLS:
- {
- struct v4l2_ext_controls *ctrls = arg;
- struct v4l2_ext_control *ctrl = ctrls->controls;
- unsigned int i;
-
- ret = uvc_ctrl_begin(chain);
- if (ret < 0)
- return ret;
-
- for (i = 0; i < ctrls->count; ++ctrl, ++i) {
- ret = uvc_ctrl_get(chain, ctrl);
- if (ret < 0) {
- uvc_ctrl_rollback(handle);
- ctrls->error_idx = i;
- return ret;
- }
- }
- ctrls->error_idx = 0;
- ret = uvc_ctrl_rollback(handle);
- break;
- }
-
- case VIDIOC_S_EXT_CTRLS:
- case VIDIOC_TRY_EXT_CTRLS:
- {
- struct v4l2_ext_controls *ctrls = arg;
- struct v4l2_ext_control *ctrl = ctrls->controls;
- unsigned int i;
-
- ret = uvc_ctrl_begin(chain);
- if (ret < 0)
- return ret;
-
- for (i = 0; i < ctrls->count; ++ctrl, ++i) {
- ret = uvc_ctrl_set(chain, ctrl);
- if (ret < 0) {
- uvc_ctrl_rollback(handle);
- ctrls->error_idx = i;
- return ret;
- }
- }
-
- ctrls->error_idx = 0;
-
- if (cmd == VIDIOC_S_EXT_CTRLS)
- ret = uvc_ctrl_commit(handle,
- ctrls->controls, ctrls->count);
- else
- ret = uvc_ctrl_rollback(handle);
- break;
- }
-
- /* Get, Set & Enum input */
- case VIDIOC_ENUMINPUT:
- {
- const struct uvc_entity *selector = chain->selector;
- struct v4l2_input *input = arg;
- struct uvc_entity *iterm = NULL;
- u32 index = input->index;
- int pin = 0;
-
- if (selector == NULL ||
- (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
- if (index != 0)
- return -EINVAL;
- list_for_each_entry(iterm, &chain->entities, chain) {
- if (UVC_ENTITY_IS_ITERM(iterm))
- break;
- }
- pin = iterm->id;
- } else if (index < selector->bNrInPins) {
- pin = selector->baSourceID[index];
- list_for_each_entry(iterm, &chain->entities, chain) {
- if (!UVC_ENTITY_IS_ITERM(iterm))
- continue;
- if (iterm->id == pin)
- break;
- }
- }
-
- if (iterm == NULL || iterm->id != pin)
- return -EINVAL;
-
- memset(input, 0, sizeof *input);
- input->index = index;
- strlcpy(input->name, iterm->name, sizeof input->name);
- if (UVC_ENTITY_TYPE(iterm) == UVC_ITT_CAMERA)
- input->type = V4L2_INPUT_TYPE_CAMERA;
- break;
- }
-
- case VIDIOC_G_INPUT:
- {
- u8 input;
-
- if (chain->selector == NULL ||
- (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
- *(int *)arg = 0;
- break;
- }
-
- ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR,
- chain->selector->id, chain->dev->intfnum,
- UVC_SU_INPUT_SELECT_CONTROL, &input, 1);
- if (ret < 0)
- return ret;
-
- *(int *)arg = input - 1;
- break;
- }
-
- case VIDIOC_S_INPUT:
- {
- u32 input = *(u32 *)arg + 1;
-
- if ((ret = uvc_acquire_privileges(handle)) < 0)
- return ret;
-
- if (chain->selector == NULL ||
- (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
- if (input != 1)
- return -EINVAL;
- break;
- }
-
- if (input == 0 || input > chain->selector->bNrInPins)
- return -EINVAL;
-
- return uvc_query_ctrl(chain->dev, UVC_SET_CUR,
- chain->selector->id, chain->dev->intfnum,
- UVC_SU_INPUT_SELECT_CONTROL, &input, 1);
- }
-
- /* Try, Get, Set & Enum format */
- case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *fmt = arg;
- struct uvc_format *format;
- enum v4l2_buf_type type = fmt->type;
- __u32 index = fmt->index;
-
- if (fmt->type != stream->type ||
- fmt->index >= stream->nformats)
- return -EINVAL;
-
- memset(fmt, 0, sizeof(*fmt));
- fmt->index = index;
- fmt->type = type;
-
- format = &stream->format[fmt->index];
- fmt->flags = 0;
- if (format->flags & UVC_FMT_FLAG_COMPRESSED)
- fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
- strlcpy(fmt->description, format->name,
- sizeof fmt->description);
- fmt->description[sizeof fmt->description - 1] = 0;
- fmt->pixelformat = format->fcc;
- break;
- }
-
- case VIDIOC_TRY_FMT:
- {
- struct uvc_streaming_control probe;
-
- return uvc_v4l2_try_format(stream, arg, &probe, NULL, NULL);
- }
-
- case VIDIOC_S_FMT:
- if ((ret = uvc_acquire_privileges(handle)) < 0)
- return ret;
-
- return uvc_v4l2_set_format(stream, arg);
-
- case VIDIOC_G_FMT:
- return uvc_v4l2_get_format(stream, arg);
-
- /* Frame size enumeration */
- case VIDIOC_ENUM_FRAMESIZES:
- {
- struct v4l2_frmsizeenum *fsize = arg;
- struct uvc_format *format = NULL;
- struct uvc_frame *frame;
- int i;
-
- /* Look for the given pixel format */
- for (i = 0; i < stream->nformats; i++) {
- if (stream->format[i].fcc ==
- fsize->pixel_format) {
- format = &stream->format[i];
- break;
- }
- }
- if (format == NULL)
- return -EINVAL;
-
- if (fsize->index >= format->nframes)
- return -EINVAL;
-
- frame = &format->frame[fsize->index];
- fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
- fsize->discrete.width = frame->wWidth;
- fsize->discrete.height = frame->wHeight;
- break;
- }
-
- /* Frame interval enumeration */
- case VIDIOC_ENUM_FRAMEINTERVALS:
- {
- struct v4l2_frmivalenum *fival = arg;
- struct uvc_format *format = NULL;
- struct uvc_frame *frame = NULL;
- int i;
-
- /* Look for the given pixel format and frame size */
- for (i = 0; i < stream->nformats; i++) {
- if (stream->format[i].fcc ==
- fival->pixel_format) {
- format = &stream->format[i];
- break;
- }
- }
- if (format == NULL)
- return -EINVAL;
-
- for (i = 0; i < format->nframes; i++) {
- if (format->frame[i].wWidth == fival->width &&
- format->frame[i].wHeight == fival->height) {
- frame = &format->frame[i];
- break;
- }
- }
- if (frame == NULL)
- return -EINVAL;
-
- if (frame->bFrameIntervalType) {
- if (fival->index >= frame->bFrameIntervalType)
- return -EINVAL;
-
- fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
- fival->discrete.numerator =
- frame->dwFrameInterval[fival->index];
- fival->discrete.denominator = 10000000;
- uvc_simplify_fraction(&fival->discrete.numerator,
- &fival->discrete.denominator, 8, 333);
- } else {
- fival->type = V4L2_FRMIVAL_TYPE_STEPWISE;
- fival->stepwise.min.numerator =
- frame->dwFrameInterval[0];
- fival->stepwise.min.denominator = 10000000;
- fival->stepwise.max.numerator =
- frame->dwFrameInterval[1];
- fival->stepwise.max.denominator = 10000000;
- fival->stepwise.step.numerator =
- frame->dwFrameInterval[2];
- fival->stepwise.step.denominator = 10000000;
- uvc_simplify_fraction(&fival->stepwise.min.numerator,
- &fival->stepwise.min.denominator, 8, 333);
- uvc_simplify_fraction(&fival->stepwise.max.numerator,
- &fival->stepwise.max.denominator, 8, 333);
- uvc_simplify_fraction(&fival->stepwise.step.numerator,
- &fival->stepwise.step.denominator, 8, 333);
- }
- break;
- }
-
- /* Get & Set streaming parameters */
- case VIDIOC_G_PARM:
- return uvc_v4l2_get_streamparm(stream, arg);
-
- case VIDIOC_S_PARM:
- if ((ret = uvc_acquire_privileges(handle)) < 0)
- return ret;
-
- return uvc_v4l2_set_streamparm(stream, arg);
-
- /* Cropping and scaling */
- case VIDIOC_CROPCAP:
- {
- struct v4l2_cropcap *ccap = arg;
-
- if (ccap->type != stream->type)
- return -EINVAL;
-
- ccap->bounds.left = 0;
- ccap->bounds.top = 0;
-
- mutex_lock(&stream->mutex);
- ccap->bounds.width = stream->cur_frame->wWidth;
- ccap->bounds.height = stream->cur_frame->wHeight;
- mutex_unlock(&stream->mutex);
-
- ccap->defrect = ccap->bounds;
-
- ccap->pixelaspect.numerator = 1;
- ccap->pixelaspect.denominator = 1;
- break;
- }
-
- case VIDIOC_G_CROP:
- case VIDIOC_S_CROP:
- return -EINVAL;
-
- /* Buffers & streaming */
- case VIDIOC_REQBUFS:
- if ((ret = uvc_acquire_privileges(handle)) < 0)
- return ret;
-
- mutex_lock(&stream->mutex);
- ret = uvc_alloc_buffers(&stream->queue, arg);
- mutex_unlock(&stream->mutex);
- if (ret < 0)
- return ret;
-
- if (ret == 0)
- uvc_dismiss_privileges(handle);
-
- ret = 0;
- break;
-
- case VIDIOC_QUERYBUF:
- {
- struct v4l2_buffer *buf = arg;
-
- if (!uvc_has_privileges(handle))
- return -EBUSY;
-
- return uvc_query_buffer(&stream->queue, buf);
- }
-
- case VIDIOC_QBUF:
- if (!uvc_has_privileges(handle))
- return -EBUSY;
-
- return uvc_queue_buffer(&stream->queue, arg);
-
- case VIDIOC_DQBUF:
- if (!uvc_has_privileges(handle))
- return -EBUSY;
-
- return uvc_dequeue_buffer(&stream->queue, arg,
- file->f_flags & O_NONBLOCK);
-
- case VIDIOC_STREAMON:
- {
- int *type = arg;
-
- if (*type != stream->type)
- return -EINVAL;
-
- if (!uvc_has_privileges(handle))
- return -EBUSY;
-
- mutex_lock(&stream->mutex);
- ret = uvc_video_enable(stream, 1);
- mutex_unlock(&stream->mutex);
- if (ret < 0)
- return ret;
- break;
- }
-
- case VIDIOC_STREAMOFF:
- {
- int *type = arg;
-
- if (*type != stream->type)
- return -EINVAL;
-
- if (!uvc_has_privileges(handle))
- return -EBUSY;
-
- return uvc_video_enable(stream, 0);
- }
-
- case VIDIOC_SUBSCRIBE_EVENT:
- {
- struct v4l2_event_subscription *sub = arg;
-
- switch (sub->type) {
- case V4L2_EVENT_CTRL:
- return v4l2_event_subscribe(&handle->vfh, sub, 0,
- &uvc_ctrl_sub_ev_ops);
- default:
- return -EINVAL;
- }
- }
-
- case VIDIOC_UNSUBSCRIBE_EVENT:
- return v4l2_event_unsubscribe(&handle->vfh, arg);
-
- case VIDIOC_DQEVENT:
- return v4l2_event_dequeue(&handle->vfh, arg,
- file->f_flags & O_NONBLOCK);
-
- /* Analog video standards make no sense for digital cameras. */
- case VIDIOC_ENUMSTD:
- case VIDIOC_QUERYSTD:
- case VIDIOC_G_STD:
- case VIDIOC_S_STD:
-
- case VIDIOC_OVERLAY:
-
- case VIDIOC_ENUMAUDIO:
- case VIDIOC_ENUMAUDOUT:
-
- case VIDIOC_ENUMOUTPUT:
- uvc_trace(UVC_TRACE_IOCTL, "Unsupported ioctl 0x%08x\n", cmd);
- return -EINVAL;
-
- case UVCIOC_CTRL_MAP:
- return uvc_ioctl_ctrl_map(chain, arg);
-
- case UVCIOC_CTRL_QUERY:
- return uvc_xu_ctrl_query(chain, arg);
-
- default:
- uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n", cmd);
- return -ENOTTY;
- }
-
- return ret;
-}
-
-static long uvc_v4l2_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- if (uvc_trace_param & UVC_TRACE_IOCTL) {
- uvc_printk(KERN_DEBUG, "uvc_v4l2_ioctl(");
- v4l_printk_ioctl(NULL, cmd);
- printk(")\n");
- }
-
- return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl);
-}
-
-#ifdef CONFIG_COMPAT
-struct uvc_xu_control_mapping32 {
- __u32 id;
- __u8 name[32];
- __u8 entity[16];
- __u8 selector;
-
- __u8 size;
- __u8 offset;
- __u32 v4l2_type;
- __u32 data_type;
-
- compat_caddr_t menu_info;
- __u32 menu_count;
-
- __u32 reserved[4];
-};
-
-static int uvc_v4l2_get_xu_mapping(struct uvc_xu_control_mapping *kp,
- const struct uvc_xu_control_mapping32 __user *up)
-{
- struct uvc_menu_info __user *umenus;
- struct uvc_menu_info __user *kmenus;
- compat_caddr_t p;
-
- if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
- __copy_from_user(kp, up, offsetof(typeof(*up), menu_info)) ||
- __get_user(kp->menu_count, &up->menu_count))
- return -EFAULT;
-
- memset(kp->reserved, 0, sizeof(kp->reserved));
-
- if (kp->menu_count == 0) {
- kp->menu_info = NULL;
- return 0;
- }
-
- if (__get_user(p, &up->menu_info))
- return -EFAULT;
- umenus = compat_ptr(p);
- if (!access_ok(VERIFY_READ, umenus, kp->menu_count * sizeof(*umenus)))
- return -EFAULT;
-
- kmenus = compat_alloc_user_space(kp->menu_count * sizeof(*kmenus));
- if (kmenus == NULL)
- return -EFAULT;
- kp->menu_info = kmenus;
-
- if (copy_in_user(kmenus, umenus, kp->menu_count * sizeof(*umenus)))
- return -EFAULT;
-
- return 0;
-}
-
-static int uvc_v4l2_put_xu_mapping(const struct uvc_xu_control_mapping *kp,
- struct uvc_xu_control_mapping32 __user *up)
-{
- struct uvc_menu_info __user *umenus;
- struct uvc_menu_info __user *kmenus = kp->menu_info;
- compat_caddr_t p;
-
- if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
- __copy_to_user(up, kp, offsetof(typeof(*up), menu_info)) ||
- __put_user(kp->menu_count, &up->menu_count))
- return -EFAULT;
-
- if (__clear_user(up->reserved, sizeof(up->reserved)))
- return -EFAULT;
-
- if (kp->menu_count == 0)
- return 0;
-
- if (get_user(p, &up->menu_info))
- return -EFAULT;
- umenus = compat_ptr(p);
-
- if (copy_in_user(umenus, kmenus, kp->menu_count * sizeof(*umenus)))
- return -EFAULT;
-
- return 0;
-}
-
-struct uvc_xu_control_query32 {
- __u8 unit;
- __u8 selector;
- __u8 query;
- __u16 size;
- compat_caddr_t data;
-};
-
-static int uvc_v4l2_get_xu_query(struct uvc_xu_control_query *kp,
- const struct uvc_xu_control_query32 __user *up)
-{
- u8 __user *udata;
- u8 __user *kdata;
- compat_caddr_t p;
-
- if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
- __copy_from_user(kp, up, offsetof(typeof(*up), data)))
- return -EFAULT;
-
- if (kp->size == 0) {
- kp->data = NULL;
- return 0;
- }
-
- if (__get_user(p, &up->data))
- return -EFAULT;
- udata = compat_ptr(p);
- if (!access_ok(VERIFY_READ, udata, kp->size))
- return -EFAULT;
-
- kdata = compat_alloc_user_space(kp->size);
- if (kdata == NULL)
- return -EFAULT;
- kp->data = kdata;
-
- if (copy_in_user(kdata, udata, kp->size))
- return -EFAULT;
-
- return 0;
-}
-
-static int uvc_v4l2_put_xu_query(const struct uvc_xu_control_query *kp,
- struct uvc_xu_control_query32 __user *up)
-{
- u8 __user *udata;
- u8 __user *kdata = kp->data;
- compat_caddr_t p;
-
- if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
- __copy_to_user(up, kp, offsetof(typeof(*up), data)))
- return -EFAULT;
-
- if (kp->size == 0)
- return 0;
-
- if (get_user(p, &up->data))
- return -EFAULT;
- udata = compat_ptr(p);
- if (!access_ok(VERIFY_READ, udata, kp->size))
- return -EFAULT;
-
- if (copy_in_user(udata, kdata, kp->size))
- return -EFAULT;
-
- return 0;
-}
-
-#define UVCIOC_CTRL_MAP32 _IOWR('u', 0x20, struct uvc_xu_control_mapping32)
-#define UVCIOC_CTRL_QUERY32 _IOWR('u', 0x21, struct uvc_xu_control_query32)
-
-static long uvc_v4l2_compat_ioctl32(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- union {
- struct uvc_xu_control_mapping xmap;
- struct uvc_xu_control_query xqry;
- } karg;
- void __user *up = compat_ptr(arg);
- mm_segment_t old_fs;
- long ret;
-
- switch (cmd) {
- case UVCIOC_CTRL_MAP32:
- cmd = UVCIOC_CTRL_MAP;
- ret = uvc_v4l2_get_xu_mapping(&karg.xmap, up);
- break;
-
- case UVCIOC_CTRL_QUERY32:
- cmd = UVCIOC_CTRL_QUERY;
- ret = uvc_v4l2_get_xu_query(&karg.xqry, up);
- break;
-
- default:
- return -ENOIOCTLCMD;
- }
-
- old_fs = get_fs();
- set_fs(KERNEL_DS);
- ret = uvc_v4l2_ioctl(file, cmd, (unsigned long)&karg);
- set_fs(old_fs);
-
- if (ret < 0)
- return ret;
-
- switch (cmd) {
- case UVCIOC_CTRL_MAP:
- ret = uvc_v4l2_put_xu_mapping(&karg.xmap, up);
- break;
-
- case UVCIOC_CTRL_QUERY:
- ret = uvc_v4l2_put_xu_query(&karg.xqry, up);
- break;
- }
-
- return ret;
-}
-#endif
-
-static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
- size_t count, loff_t *ppos)
-{
- uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_read: not implemented.\n");
- return -EINVAL;
-}
-
-static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct uvc_fh *handle = file->private_data;
- struct uvc_streaming *stream = handle->stream;
-
- uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_mmap\n");
-
- return uvc_queue_mmap(&stream->queue, vma);
-}
-
-static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
-{
- struct uvc_fh *handle = file->private_data;
- struct uvc_streaming *stream = handle->stream;
-
- uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_poll\n");
-
- return uvc_queue_poll(&stream->queue, file, wait);
-}
-
-#ifndef CONFIG_MMU
-static unsigned long uvc_v4l2_get_unmapped_area(struct file *file,
- unsigned long addr, unsigned long len, unsigned long pgoff,
- unsigned long flags)
-{
- struct uvc_fh *handle = file->private_data;
- struct uvc_streaming *stream = handle->stream;
-
- uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_get_unmapped_area\n");
-
- return uvc_queue_get_unmapped_area(&stream->queue, pgoff);
-}
-#endif
-
-const struct v4l2_file_operations uvc_fops = {
- .owner = THIS_MODULE,
- .open = uvc_v4l2_open,
- .release = uvc_v4l2_release,
- .unlocked_ioctl = uvc_v4l2_ioctl,
-#ifdef CONFIG_COMPAT
- .compat_ioctl32 = uvc_v4l2_compat_ioctl32,
-#endif
- .read = uvc_v4l2_read,
- .mmap = uvc_v4l2_mmap,
- .poll = uvc_v4l2_poll,
-#ifndef CONFIG_MMU
- .get_unmapped_area = uvc_v4l2_get_unmapped_area,
-#endif
-};
-
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
deleted file mode 100644
index 1c15b4227bd..00000000000
--- a/drivers/media/video/uvc/uvc_video.c
+++ /dev/null
@@ -1,1879 +0,0 @@
-/*
- * uvc_video.c -- USB Video Class driver - Video handling
- *
- * Copyright (C) 2005-2010
- * Laurent Pinchart (laurent.pinchart@ideasonboard.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <linux/vmalloc.h>
-#include <linux/wait.h>
-#include <linux/atomic.h>
-#include <asm/unaligned.h>
-
-#include <media/v4l2-common.h>
-
-#include "uvcvideo.h"
-
-/* ------------------------------------------------------------------------
- * UVC Controls
- */
-
-static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
- __u8 intfnum, __u8 cs, void *data, __u16 size,
- int timeout)
-{
- __u8 type = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
- unsigned int pipe;
-
- pipe = (query & 0x80) ? usb_rcvctrlpipe(dev->udev, 0)
- : usb_sndctrlpipe(dev->udev, 0);
- type |= (query & 0x80) ? USB_DIR_IN : USB_DIR_OUT;
-
- return usb_control_msg(dev->udev, pipe, query, type, cs << 8,
- unit << 8 | intfnum, data, size, timeout);
-}
-
-static const char *uvc_query_name(__u8 query)
-{
- switch (query) {
- case UVC_SET_CUR:
- return "SET_CUR";
- case UVC_GET_CUR:
- return "GET_CUR";
- case UVC_GET_MIN:
- return "GET_MIN";
- case UVC_GET_MAX:
- return "GET_MAX";
- case UVC_GET_RES:
- return "GET_RES";
- case UVC_GET_LEN:
- return "GET_LEN";
- case UVC_GET_INFO:
- return "GET_INFO";
- case UVC_GET_DEF:
- return "GET_DEF";
- default:
- return "<invalid>";
- }
-}
-
-int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
- __u8 intfnum, __u8 cs, void *data, __u16 size)
-{
- int ret;
-
- ret = __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size,
- UVC_CTRL_CONTROL_TIMEOUT);
- 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,
- unit, ret, size);
- return -EIO;
- }
-
- return 0;
-}
-
-static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
- struct uvc_streaming_control *ctrl)
-{
- struct uvc_format *format = NULL;
- struct uvc_frame *frame = NULL;
- unsigned int i;
-
- for (i = 0; i < stream->nformats; ++i) {
- if (stream->format[i].index == ctrl->bFormatIndex) {
- format = &stream->format[i];
- break;
- }
- }
-
- if (format == NULL)
- return;
-
- for (i = 0; i < format->nframes; ++i) {
- if (format->frame[i].bFrameIndex == ctrl->bFrameIndex) {
- frame = &format->frame[i];
- break;
- }
- }
-
- if (frame == NULL)
- return;
-
- if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) ||
- (ctrl->dwMaxVideoFrameSize == 0 &&
- stream->dev->uvc_version < 0x0110))
- ctrl->dwMaxVideoFrameSize =
- frame->dwMaxVideoFrameBufferSize;
-
- if (!(format->flags & UVC_FMT_FLAG_COMPRESSED) &&
- stream->dev->quirks & UVC_QUIRK_FIX_BANDWIDTH &&
- stream->intf->num_altsetting > 1) {
- u32 interval;
- u32 bandwidth;
-
- interval = (ctrl->dwFrameInterval > 100000)
- ? ctrl->dwFrameInterval
- : frame->dwFrameInterval[0];
-
- /* Compute a bandwidth estimation by multiplying the frame
- * size by the number of video frames per second, divide the
- * result by the number of USB frames (or micro-frames for
- * high-speed devices) per second and add the UVC header size
- * (assumed to be 12 bytes long).
- */
- bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp;
- bandwidth *= 10000000 / interval + 1;
- bandwidth /= 1000;
- if (stream->dev->udev->speed == USB_SPEED_HIGH)
- bandwidth /= 8;
- bandwidth += 12;
-
- /* The bandwidth estimate is too low for many cameras. Don't use
- * maximum packet sizes lower than 1024 bytes to try and work
- * around the problem. According to measurements done on two
- * different camera models, the value is high enough to get most
- * resolutions working while not preventing two simultaneous
- * VGA streams at 15 fps.
- */
- bandwidth = max_t(u32, bandwidth, 1024);
-
- ctrl->dwMaxPayloadTransferSize = bandwidth;
- }
-}
-
-static int uvc_get_video_ctrl(struct uvc_streaming *stream,
- struct uvc_streaming_control *ctrl, int probe, __u8 query)
-{
- __u8 *data;
- __u16 size;
- int ret;
-
- size = stream->dev->uvc_version >= 0x0110 ? 34 : 26;
- if ((stream->dev->quirks & UVC_QUIRK_PROBE_DEF) &&
- query == UVC_GET_DEF)
- return -EIO;
-
- data = kmalloc(size, GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
-
- ret = __uvc_query_ctrl(stream->dev, query, 0, stream->intfnum,
- probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data,
- size, uvc_timeout_param);
-
- if ((query == UVC_GET_MIN || query == UVC_GET_MAX) && ret == 2) {
- /* Some cameras, mostly based on Bison Electronics chipsets,
- * answer a GET_MIN or GET_MAX request with the wCompQuality
- * field only.
- */
- uvc_warn_once(stream->dev, UVC_WARN_MINMAX, "UVC non "
- "compliance - GET_MIN/MAX(PROBE) incorrectly "
- "supported. Enabling workaround.\n");
- memset(ctrl, 0, sizeof *ctrl);
- ctrl->wCompQuality = le16_to_cpup((__le16 *)data);
- ret = 0;
- goto out;
- } else if (query == UVC_GET_DEF && probe == 1 && ret != size) {
- /* Many cameras don't support the GET_DEF request on their
- * video probe control. Warn once and return, the caller will
- * fall back to GET_CUR.
- */
- uvc_warn_once(stream->dev, UVC_WARN_PROBE_DEF, "UVC non "
- "compliance - GET_DEF(PROBE) not supported. "
- "Enabling workaround.\n");
- ret = -EIO;
- goto out;
- } else if (ret != size) {
- uvc_printk(KERN_ERR, "Failed to query (%u) UVC %s control : "
- "%d (exp. %u).\n", query, probe ? "probe" : "commit",
- ret, size);
- ret = -EIO;
- goto out;
- }
-
- ctrl->bmHint = le16_to_cpup((__le16 *)&data[0]);
- ctrl->bFormatIndex = data[2];
- ctrl->bFrameIndex = data[3];
- ctrl->dwFrameInterval = le32_to_cpup((__le32 *)&data[4]);
- ctrl->wKeyFrameRate = le16_to_cpup((__le16 *)&data[8]);
- ctrl->wPFrameRate = le16_to_cpup((__le16 *)&data[10]);
- ctrl->wCompQuality = le16_to_cpup((__le16 *)&data[12]);
- ctrl->wCompWindowSize = le16_to_cpup((__le16 *)&data[14]);
- ctrl->wDelay = le16_to_cpup((__le16 *)&data[16]);
- ctrl->dwMaxVideoFrameSize = get_unaligned_le32(&data[18]);
- ctrl->dwMaxPayloadTransferSize = get_unaligned_le32(&data[22]);
-
- if (size == 34) {
- ctrl->dwClockFrequency = get_unaligned_le32(&data[26]);
- ctrl->bmFramingInfo = data[30];
- ctrl->bPreferedVersion = data[31];
- ctrl->bMinVersion = data[32];
- ctrl->bMaxVersion = data[33];
- } else {
- ctrl->dwClockFrequency = stream->dev->clock_frequency;
- ctrl->bmFramingInfo = 0;
- ctrl->bPreferedVersion = 0;
- ctrl->bMinVersion = 0;
- ctrl->bMaxVersion = 0;
- }
-
- /* Some broken devices return null or wrong dwMaxVideoFrameSize and
- * dwMaxPayloadTransferSize fields. Try to get the value from the
- * format and frame descriptors.
- */
- uvc_fixup_video_ctrl(stream, ctrl);
- ret = 0;
-
-out:
- kfree(data);
- return ret;
-}
-
-static int uvc_set_video_ctrl(struct uvc_streaming *stream,
- struct uvc_streaming_control *ctrl, int probe)
-{
- __u8 *data;
- __u16 size;
- int ret;
-
- size = stream->dev->uvc_version >= 0x0110 ? 34 : 26;
- data = kzalloc(size, GFP_KERNEL);
- if (data == NULL)
- return -ENOMEM;
-
- *(__le16 *)&data[0] = cpu_to_le16(ctrl->bmHint);
- data[2] = ctrl->bFormatIndex;
- data[3] = ctrl->bFrameIndex;
- *(__le32 *)&data[4] = cpu_to_le32(ctrl->dwFrameInterval);
- *(__le16 *)&data[8] = cpu_to_le16(ctrl->wKeyFrameRate);
- *(__le16 *)&data[10] = cpu_to_le16(ctrl->wPFrameRate);
- *(__le16 *)&data[12] = cpu_to_le16(ctrl->wCompQuality);
- *(__le16 *)&data[14] = cpu_to_le16(ctrl->wCompWindowSize);
- *(__le16 *)&data[16] = cpu_to_le16(ctrl->wDelay);
- put_unaligned_le32(ctrl->dwMaxVideoFrameSize, &data[18]);
- put_unaligned_le32(ctrl->dwMaxPayloadTransferSize, &data[22]);
-
- if (size == 34) {
- put_unaligned_le32(ctrl->dwClockFrequency, &data[26]);
- data[30] = ctrl->bmFramingInfo;
- data[31] = ctrl->bPreferedVersion;
- data[32] = ctrl->bMinVersion;
- data[33] = ctrl->bMaxVersion;
- }
-
- ret = __uvc_query_ctrl(stream->dev, UVC_SET_CUR, 0, stream->intfnum,
- probe ? UVC_VS_PROBE_CONTROL : UVC_VS_COMMIT_CONTROL, data,
- size, uvc_timeout_param);
- if (ret != size) {
- uvc_printk(KERN_ERR, "Failed to set UVC %s control : "
- "%d (exp. %u).\n", probe ? "probe" : "commit",
- ret, size);
- ret = -EIO;
- }
-
- kfree(data);
- return ret;
-}
-
-int uvc_probe_video(struct uvc_streaming *stream,
- struct uvc_streaming_control *probe)
-{
- struct uvc_streaming_control probe_min, probe_max;
- __u16 bandwidth;
- unsigned int i;
- int ret;
-
- /* Perform probing. The device should adjust the requested values
- * according to its capabilities. However, some devices, namely the
- * first generation UVC Logitech webcams, don't implement the Video
- * Probe control properly, and just return the needed bandwidth. For
- * that reason, if the needed bandwidth exceeds the maximum available
- * bandwidth, try to lower the quality.
- */
- ret = uvc_set_video_ctrl(stream, probe, 1);
- if (ret < 0)
- goto done;
-
- /* Get the minimum and maximum values for compression settings. */
- if (!(stream->dev->quirks & UVC_QUIRK_PROBE_MINMAX)) {
- ret = uvc_get_video_ctrl(stream, &probe_min, 1, UVC_GET_MIN);
- if (ret < 0)
- goto done;
- ret = uvc_get_video_ctrl(stream, &probe_max, 1, UVC_GET_MAX);
- if (ret < 0)
- goto done;
-
- probe->wCompQuality = probe_max.wCompQuality;
- }
-
- for (i = 0; i < 2; ++i) {
- ret = uvc_set_video_ctrl(stream, probe, 1);
- if (ret < 0)
- goto done;
- ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR);
- if (ret < 0)
- goto done;
-
- if (stream->intf->num_altsetting == 1)
- break;
-
- bandwidth = probe->dwMaxPayloadTransferSize;
- if (bandwidth <= stream->maxpsize)
- break;
-
- if (stream->dev->quirks & UVC_QUIRK_PROBE_MINMAX) {
- ret = -ENOSPC;
- goto done;
- }
-
- /* TODO: negotiate compression parameters */
- probe->wKeyFrameRate = probe_min.wKeyFrameRate;
- probe->wPFrameRate = probe_min.wPFrameRate;
- probe->wCompQuality = probe_max.wCompQuality;
- probe->wCompWindowSize = probe_min.wCompWindowSize;
- }
-
-done:
- return ret;
-}
-
-static int uvc_commit_video(struct uvc_streaming *stream,
- struct uvc_streaming_control *probe)
-{
- return uvc_set_video_ctrl(stream, probe, 0);
-}
-
-/* -----------------------------------------------------------------------------
- * Clocks and timestamps
- */
-
-static void
-uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
- const __u8 *data, int len)
-{
- struct uvc_clock_sample *sample;
- unsigned int header_size;
- bool has_pts = false;
- bool has_scr = false;
- unsigned long flags;
- struct timespec ts;
- u16 host_sof;
- u16 dev_sof;
-
- switch (data[1] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) {
- case UVC_STREAM_PTS | UVC_STREAM_SCR:
- header_size = 12;
- has_pts = true;
- has_scr = true;
- break;
- case UVC_STREAM_PTS:
- header_size = 6;
- has_pts = true;
- break;
- case UVC_STREAM_SCR:
- header_size = 8;
- has_scr = true;
- break;
- default:
- header_size = 2;
- break;
- }
-
- /* Check for invalid headers. */
- if (len < header_size)
- return;
-
- /* Extract the timestamps:
- *
- * - store the frame PTS in the buffer structure
- * - if the SCR field is present, retrieve the host SOF counter and
- * kernel timestamps and store them with the SCR STC and SOF fields
- * in the ring buffer
- */
- if (has_pts && buf != NULL)
- buf->pts = get_unaligned_le32(&data[2]);
-
- if (!has_scr)
- return;
-
- /* To limit the amount of data, drop SCRs with an SOF identical to the
- * previous one.
- */
- dev_sof = get_unaligned_le16(&data[header_size - 2]);
- if (dev_sof == stream->clock.last_sof)
- return;
-
- stream->clock.last_sof = dev_sof;
-
- host_sof = usb_get_current_frame_number(stream->dev->udev);
- ktime_get_ts(&ts);
-
- /* The UVC specification allows device implementations that can't obtain
- * the USB frame number to keep their own frame counters as long as they
- * match the size and frequency of the frame number associated with USB
- * SOF tokens. The SOF values sent by such devices differ from the USB
- * SOF tokens by a fixed offset that needs to be estimated and accounted
- * for to make timestamp recovery as accurate as possible.
- *
- * The offset is estimated the first time a device SOF value is received
- * as the difference between the host and device SOF values. As the two
- * SOF values can differ slightly due to transmission delays, consider
- * that the offset is null if the difference is not higher than 10 ms
- * (negative differences can not happen and are thus considered as an
- * offset). The video commit control wDelay field should be used to
- * compute a dynamic threshold instead of using a fixed 10 ms value, but
- * devices don't report reliable wDelay values.
- *
- * See uvc_video_clock_host_sof() for an explanation regarding why only
- * the 8 LSBs of the delta are kept.
- */
- if (stream->clock.sof_offset == (u16)-1) {
- u16 delta_sof = (host_sof - dev_sof) & 255;
- if (delta_sof >= 10)
- stream->clock.sof_offset = delta_sof;
- else
- stream->clock.sof_offset = 0;
- }
-
- dev_sof = (dev_sof + stream->clock.sof_offset) & 2047;
-
- spin_lock_irqsave(&stream->clock.lock, flags);
-
- sample = &stream->clock.samples[stream->clock.head];
- sample->dev_stc = get_unaligned_le32(&data[header_size - 6]);
- sample->dev_sof = dev_sof;
- sample->host_sof = host_sof;
- sample->host_ts = ts;
-
- /* Update the sliding window head and count. */
- stream->clock.head = (stream->clock.head + 1) % stream->clock.size;
-
- if (stream->clock.count < stream->clock.size)
- stream->clock.count++;
-
- spin_unlock_irqrestore(&stream->clock.lock, flags);
-}
-
-static void uvc_video_clock_reset(struct uvc_streaming *stream)
-{
- struct uvc_clock *clock = &stream->clock;
-
- clock->head = 0;
- clock->count = 0;
- clock->last_sof = -1;
- clock->sof_offset = -1;
-}
-
-static int uvc_video_clock_init(struct uvc_streaming *stream)
-{
- struct uvc_clock *clock = &stream->clock;
-
- spin_lock_init(&clock->lock);
- clock->size = 32;
-
- clock->samples = kmalloc(clock->size * sizeof(*clock->samples),
- GFP_KERNEL);
- if (clock->samples == NULL)
- return -ENOMEM;
-
- uvc_video_clock_reset(stream);
-
- return 0;
-}
-
-static void uvc_video_clock_cleanup(struct uvc_streaming *stream)
-{
- kfree(stream->clock.samples);
- stream->clock.samples = NULL;
-}
-
-/*
- * uvc_video_clock_host_sof - Return the host SOF value for a clock sample
- *
- * Host SOF counters reported by usb_get_current_frame_number() usually don't
- * cover the whole 11-bits SOF range (0-2047) but are limited to the HCI frame
- * schedule window. They can be limited to 8, 9 or 10 bits depending on the host
- * controller and its configuration.
- *
- * We thus need to recover the SOF value corresponding to the host frame number.
- * As the device and host frame numbers are sampled in a short interval, the
- * difference between their values should be equal to a small delta plus an
- * integer multiple of 256 caused by the host frame number limited precision.
- *
- * To obtain the recovered host SOF value, compute the small delta by masking
- * the high bits of the host frame counter and device SOF difference and add it
- * to the device SOF value.
- */
-static u16 uvc_video_clock_host_sof(const struct uvc_clock_sample *sample)
-{
- /* The delta value can be negative. */
- s8 delta_sof;
-
- delta_sof = (sample->host_sof - sample->dev_sof) & 255;
-
- return (sample->dev_sof + delta_sof) & 2047;
-}
-
-/*
- * uvc_video_clock_update - Update the buffer timestamp
- *
- * This function converts the buffer PTS timestamp to the host clock domain by
- * going through the USB SOF clock domain and stores the result in the V4L2
- * buffer timestamp field.
- *
- * The relationship between the device clock and the host clock isn't known.
- * However, the device and the host share the common USB SOF clock which can be
- * used to recover that relationship.
- *
- * The relationship between the device clock and the USB SOF clock is considered
- * to be linear over the clock samples sliding window and is given by
- *
- * SOF = m * PTS + p
- *
- * Several methods to compute the slope (m) and intercept (p) can be used. As
- * the clock drift should be small compared to the sliding window size, we
- * assume that the line that goes through the points at both ends of the window
- * is a good approximation. Naming those points P1 and P2, we get
- *
- * SOF = (SOF2 - SOF1) / (STC2 - STC1) * PTS
- * + (SOF1 * STC2 - SOF2 * STC1) / (STC2 - STC1)
- *
- * or
- *
- * SOF = ((SOF2 - SOF1) * PTS + SOF1 * STC2 - SOF2 * STC1) / (STC2 - STC1) (1)
- *
- * to avoid loosing precision in the division. Similarly, the host timestamp is
- * computed with
- *
- * TS = ((TS2 - TS1) * PTS + TS1 * SOF2 - TS2 * SOF1) / (SOF2 - SOF1) (2)
- *
- * SOF values are coded on 11 bits by USB. We extend their precision with 16
- * decimal bits, leading to a 11.16 coding.
- *
- * TODO: To avoid surprises with device clock values, PTS/STC timestamps should
- * be normalized using the nominal device clock frequency reported through the
- * UVC descriptors.
- *
- * Both the PTS/STC and SOF counters roll over, after a fixed but device
- * specific amount of time for PTS/STC and after 2048ms for SOF. As long as the
- * sliding window size is smaller than the rollover period, differences computed
- * on unsigned integers will produce the correct result. However, the p term in
- * the linear relations will be miscomputed.
- *
- * To fix the issue, we subtract a constant from the PTS and STC values to bring
- * PTS to half the 32 bit STC range. The sliding window STC values then fit into
- * the 32 bit range without any rollover.
- *
- * Similarly, we add 2048 to the device SOF values to make sure that the SOF
- * computed by (1) will never be smaller than 0. This offset is then compensated
- * by adding 2048 to the SOF values used in (2). However, this doesn't prevent
- * rollovers between (1) and (2): the SOF value computed by (1) can be slightly
- * lower than 4096, and the host SOF counters can have rolled over to 2048. This
- * case is handled by subtracting 2048 from the SOF value if it exceeds the host
- * SOF value at the end of the sliding window.
- *
- * Finally we subtract a constant from the host timestamps to bring the first
- * timestamp of the sliding window to 1s.
- */
-void uvc_video_clock_update(struct uvc_streaming *stream,
- struct v4l2_buffer *v4l2_buf,
- struct uvc_buffer *buf)
-{
- struct uvc_clock *clock = &stream->clock;
- struct uvc_clock_sample *first;
- struct uvc_clock_sample *last;
- unsigned long flags;
- struct timespec ts;
- u32 delta_stc;
- u32 y1, y2;
- u32 x1, x2;
- u32 mean;
- u32 sof;
- u32 div;
- u32 rem;
- u64 y;
-
- spin_lock_irqsave(&clock->lock, flags);
-
- if (clock->count < clock->size)
- goto done;
-
- first = &clock->samples[clock->head];
- last = &clock->samples[(clock->head - 1) % clock->size];
-
- /* First step, PTS to SOF conversion. */
- delta_stc = buf->pts - (1UL << 31);
- x1 = first->dev_stc - delta_stc;
- x2 = last->dev_stc - delta_stc;
- if (x1 == x2)
- goto done;
-
- y1 = (first->dev_sof + 2048) << 16;
- y2 = (last->dev_sof + 2048) << 16;
- if (y2 < y1)
- y2 += 2048 << 16;
-
- y = (u64)(y2 - y1) * (1ULL << 31) + (u64)y1 * (u64)x2
- - (u64)y2 * (u64)x1;
- y = div_u64(y, x2 - x1);
-
- sof = y;
-
- uvc_trace(UVC_TRACE_CLOCK, "%s: PTS %u y %llu.%06llu SOF %u.%06llu "
- "(x1 %u x2 %u y1 %u y2 %u SOF offset %u)\n",
- stream->dev->name, buf->pts,
- y >> 16, div_u64((y & 0xffff) * 1000000, 65536),
- sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536),
- x1, x2, y1, y2, clock->sof_offset);
-
- /* Second step, SOF to host clock conversion. */
- x1 = (uvc_video_clock_host_sof(first) + 2048) << 16;
- x2 = (uvc_video_clock_host_sof(last) + 2048) << 16;
- if (x2 < x1)
- x2 += 2048 << 16;
- if (x1 == x2)
- goto done;
-
- ts = timespec_sub(last->host_ts, first->host_ts);
- y1 = NSEC_PER_SEC;
- y2 = (ts.tv_sec + 1) * NSEC_PER_SEC + ts.tv_nsec;
-
- /* Interpolated and host SOF timestamps can wrap around at slightly
- * different times. Handle this by adding or removing 2048 to or from
- * the computed SOF value to keep it close to the SOF samples mean
- * value.
- */
- mean = (x1 + x2) / 2;
- if (mean - (1024 << 16) > sof)
- sof += 2048 << 16;
- else if (sof > mean + (1024 << 16))
- sof -= 2048 << 16;
-
- y = (u64)(y2 - y1) * (u64)sof + (u64)y1 * (u64)x2
- - (u64)y2 * (u64)x1;
- y = div_u64(y, x2 - x1);
-
- div = div_u64_rem(y, NSEC_PER_SEC, &rem);
- ts.tv_sec = first->host_ts.tv_sec - 1 + div;
- ts.tv_nsec = first->host_ts.tv_nsec + rem;
- if (ts.tv_nsec >= NSEC_PER_SEC) {
- ts.tv_sec++;
- ts.tv_nsec -= NSEC_PER_SEC;
- }
-
- uvc_trace(UVC_TRACE_CLOCK, "%s: SOF %u.%06llu y %llu ts %lu.%06lu "
- "buf ts %lu.%06lu (x1 %u/%u/%u x2 %u/%u/%u y1 %u y2 %u)\n",
- stream->dev->name,
- sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536),
- y, ts.tv_sec, ts.tv_nsec / NSEC_PER_USEC,
- v4l2_buf->timestamp.tv_sec, v4l2_buf->timestamp.tv_usec,
- x1, first->host_sof, first->dev_sof,
- x2, last->host_sof, last->dev_sof, y1, y2);
-
- /* Update the V4L2 buffer. */
- v4l2_buf->timestamp.tv_sec = ts.tv_sec;
- v4l2_buf->timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
-
-done:
- spin_unlock_irqrestore(&stream->clock.lock, flags);
-}
-
-/* ------------------------------------------------------------------------
- * Stream statistics
- */
-
-static void uvc_video_stats_decode(struct uvc_streaming *stream,
- const __u8 *data, int len)
-{
- unsigned int header_size;
- bool has_pts = false;
- bool has_scr = false;
- u16 uninitialized_var(scr_sof);
- u32 uninitialized_var(scr_stc);
- u32 uninitialized_var(pts);
-
- if (stream->stats.stream.nb_frames == 0 &&
- stream->stats.frame.nb_packets == 0)
- ktime_get_ts(&stream->stats.stream.start_ts);
-
- switch (data[1] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) {
- case UVC_STREAM_PTS | UVC_STREAM_SCR:
- header_size = 12;
- has_pts = true;
- has_scr = true;
- break;
- case UVC_STREAM_PTS:
- header_size = 6;
- has_pts = true;
- break;
- case UVC_STREAM_SCR:
- header_size = 8;
- has_scr = true;
- break;
- default:
- header_size = 2;
- break;
- }
-
- /* Check for invalid headers. */
- if (len < header_size || data[0] < header_size) {
- stream->stats.frame.nb_invalid++;
- return;
- }
-
- /* Extract the timestamps. */
- if (has_pts)
- pts = get_unaligned_le32(&data[2]);
-
- if (has_scr) {
- scr_stc = get_unaligned_le32(&data[header_size - 6]);
- scr_sof = get_unaligned_le16(&data[header_size - 2]);
- }
-
- /* Is PTS constant through the whole frame ? */
- if (has_pts && stream->stats.frame.nb_pts) {
- if (stream->stats.frame.pts != pts) {
- stream->stats.frame.nb_pts_diffs++;
- stream->stats.frame.last_pts_diff =
- stream->stats.frame.nb_packets;
- }
- }
-
- if (has_pts) {
- stream->stats.frame.nb_pts++;
- stream->stats.frame.pts = pts;
- }
-
- /* Do all frames have a PTS in their first non-empty packet, or before
- * their first empty packet ?
- */
- if (stream->stats.frame.size == 0) {
- if (len > header_size)
- stream->stats.frame.has_initial_pts = has_pts;
- if (len == header_size && has_pts)
- stream->stats.frame.has_early_pts = true;
- }
-
- /* Do the SCR.STC and SCR.SOF fields vary through the frame ? */
- if (has_scr && stream->stats.frame.nb_scr) {
- if (stream->stats.frame.scr_stc != scr_stc)
- stream->stats.frame.nb_scr_diffs++;
- }
-
- if (has_scr) {
- /* Expand the SOF counter to 32 bits and store its value. */
- if (stream->stats.stream.nb_frames > 0 ||
- stream->stats.frame.nb_scr > 0)
- stream->stats.stream.scr_sof_count +=
- (scr_sof - stream->stats.stream.scr_sof) % 2048;
- stream->stats.stream.scr_sof = scr_sof;
-
- stream->stats.frame.nb_scr++;
- stream->stats.frame.scr_stc = scr_stc;
- stream->stats.frame.scr_sof = scr_sof;
-
- if (scr_sof < stream->stats.stream.min_sof)
- stream->stats.stream.min_sof = scr_sof;
- if (scr_sof > stream->stats.stream.max_sof)
- stream->stats.stream.max_sof = scr_sof;
- }
-
- /* Record the first non-empty packet number. */
- if (stream->stats.frame.size == 0 && len > header_size)
- stream->stats.frame.first_data = stream->stats.frame.nb_packets;
-
- /* Update the frame size. */
- stream->stats.frame.size += len - header_size;
-
- /* Update the packets counters. */
- stream->stats.frame.nb_packets++;
- if (len > header_size)
- stream->stats.frame.nb_empty++;
-
- if (data[1] & UVC_STREAM_ERR)
- stream->stats.frame.nb_errors++;
-}
-
-static void uvc_video_stats_update(struct uvc_streaming *stream)
-{
- struct uvc_stats_frame *frame = &stream->stats.frame;
-
- uvc_trace(UVC_TRACE_STATS, "frame %u stats: %u/%u/%u packets, "
- "%u/%u/%u pts (%searly %sinitial), %u/%u scr, "
- "last pts/stc/sof %u/%u/%u\n",
- stream->sequence, frame->first_data,
- frame->nb_packets - frame->nb_empty, frame->nb_packets,
- frame->nb_pts_diffs, frame->last_pts_diff, frame->nb_pts,
- frame->has_early_pts ? "" : "!",
- frame->has_initial_pts ? "" : "!",
- frame->nb_scr_diffs, frame->nb_scr,
- frame->pts, frame->scr_stc, frame->scr_sof);
-
- stream->stats.stream.nb_frames++;
- stream->stats.stream.nb_packets += stream->stats.frame.nb_packets;
- stream->stats.stream.nb_empty += stream->stats.frame.nb_empty;
- stream->stats.stream.nb_errors += stream->stats.frame.nb_errors;
- stream->stats.stream.nb_invalid += stream->stats.frame.nb_invalid;
-
- if (frame->has_early_pts)
- stream->stats.stream.nb_pts_early++;
- if (frame->has_initial_pts)
- stream->stats.stream.nb_pts_initial++;
- if (frame->last_pts_diff <= frame->first_data)
- stream->stats.stream.nb_pts_constant++;
- if (frame->nb_scr >= frame->nb_packets - frame->nb_empty)
- stream->stats.stream.nb_scr_count_ok++;
- if (frame->nb_scr_diffs + 1 == frame->nb_scr)
- stream->stats.stream.nb_scr_diffs_ok++;
-
- memset(&stream->stats.frame, 0, sizeof(stream->stats.frame));
-}
-
-size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf,
- size_t size)
-{
- unsigned int scr_sof_freq;
- unsigned int duration;
- struct timespec ts;
- size_t count = 0;
-
- ts.tv_sec = stream->stats.stream.stop_ts.tv_sec
- - stream->stats.stream.start_ts.tv_sec;
- ts.tv_nsec = stream->stats.stream.stop_ts.tv_nsec
- - stream->stats.stream.start_ts.tv_nsec;
- if (ts.tv_nsec < 0) {
- ts.tv_sec--;
- ts.tv_nsec += 1000000000;
- }
-
- /* Compute the SCR.SOF frequency estimate. At the nominal 1kHz SOF
- * frequency this will not overflow before more than 1h.
- */
- duration = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
- if (duration != 0)
- scr_sof_freq = stream->stats.stream.scr_sof_count * 1000
- / duration;
- else
- scr_sof_freq = 0;
-
- count += scnprintf(buf + count, size - count,
- "frames: %u\npackets: %u\nempty: %u\n"
- "errors: %u\ninvalid: %u\n",
- stream->stats.stream.nb_frames,
- stream->stats.stream.nb_packets,
- stream->stats.stream.nb_empty,
- stream->stats.stream.nb_errors,
- stream->stats.stream.nb_invalid);
- count += scnprintf(buf + count, size - count,
- "pts: %u early, %u initial, %u ok\n",
- stream->stats.stream.nb_pts_early,
- stream->stats.stream.nb_pts_initial,
- stream->stats.stream.nb_pts_constant);
- count += scnprintf(buf + count, size - count,
- "scr: %u count ok, %u diff ok\n",
- stream->stats.stream.nb_scr_count_ok,
- stream->stats.stream.nb_scr_diffs_ok);
- count += scnprintf(buf + count, size - count,
- "sof: %u <= sof <= %u, freq %u.%03u kHz\n",
- stream->stats.stream.min_sof,
- stream->stats.stream.max_sof,
- scr_sof_freq / 1000, scr_sof_freq % 1000);
-
- return count;
-}
-
-static void uvc_video_stats_start(struct uvc_streaming *stream)
-{
- memset(&stream->stats, 0, sizeof(stream->stats));
- stream->stats.stream.min_sof = 2048;
-}
-
-static void uvc_video_stats_stop(struct uvc_streaming *stream)
-{
- ktime_get_ts(&stream->stats.stream.stop_ts);
-}
-
-/* ------------------------------------------------------------------------
- * Video codecs
- */
-
-/* Video payload decoding is handled by uvc_video_decode_start(),
- * uvc_video_decode_data() and uvc_video_decode_end().
- *
- * uvc_video_decode_start is called with URB data at the start of a bulk or
- * isochronous payload. It processes header data and returns the header size
- * in bytes if successful. If an error occurs, it returns a negative error
- * code. The following error codes have special meanings.
- *
- * - EAGAIN informs the caller that the current video buffer should be marked
- * as done, and that the function should be called again with the same data
- * and a new video buffer. This is used when end of frame conditions can be
- * reliably detected at the beginning of the next frame only.
- *
- * If an error other than -EAGAIN is returned, the caller will drop the current
- * payload. No call to uvc_video_decode_data and uvc_video_decode_end will be
- * made until the next payload. -ENODATA can be used to drop the current
- * payload if no other error code is appropriate.
- *
- * uvc_video_decode_data is called for every URB with URB data. It copies the
- * data to the video buffer.
- *
- * uvc_video_decode_end is called with header data at the end of a bulk or
- * isochronous payload. It performs any additional header data processing and
- * returns 0 or a negative error code if an error occurred. As header data have
- * already been processed by uvc_video_decode_start, this functions isn't
- * required to perform sanity checks a second time.
- *
- * For isochronous transfers where a payload is always transferred in a single
- * URB, the three functions will be called in a row.
- *
- * To let the decoder process header data and update its internal state even
- * when no video buffer is available, uvc_video_decode_start must be prepared
- * to be called with a NULL buf parameter. uvc_video_decode_data and
- * uvc_video_decode_end will never be called with a NULL buffer.
- */
-static int uvc_video_decode_start(struct uvc_streaming *stream,
- struct uvc_buffer *buf, const __u8 *data, int len)
-{
- __u8 fid;
-
- /* Sanity checks:
- * - packet must be at least 2 bytes long
- * - bHeaderLength value must be at least 2 bytes (see above)
- * - bHeaderLength value can't be larger than the packet size.
- */
- if (len < 2 || data[0] < 2 || data[0] > len) {
- stream->stats.frame.nb_invalid++;
- return -EINVAL;
- }
-
- fid = data[1] & UVC_STREAM_FID;
-
- /* Increase the sequence number regardless of any buffer states, so
- * that discontinuous sequence numbers always indicate lost frames.
- */
- if (stream->last_fid != fid) {
- stream->sequence++;
- if (stream->sequence)
- uvc_video_stats_update(stream);
- }
-
- uvc_video_clock_decode(stream, buf, data, len);
- uvc_video_stats_decode(stream, data, len);
-
- /* Store the payload FID bit and return immediately when the buffer is
- * NULL.
- */
- if (buf == NULL) {
- stream->last_fid = fid;
- return -ENODATA;
- }
-
- /* Mark the buffer as bad if the error bit is set. */
- if (data[1] & UVC_STREAM_ERR) {
- uvc_trace(UVC_TRACE_FRAME, "Marking buffer as bad (error bit "
- "set).\n");
- buf->error = 1;
- }
-
- /* Synchronize to the input stream by waiting for the FID bit to be
- * toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE.
- * stream->last_fid is initialized to -1, so the first isochronous
- * frame will always be in sync.
- *
- * If the device doesn't toggle the FID bit, invert stream->last_fid
- * when the EOF bit is set to force synchronisation on the next packet.
- */
- if (buf->state != UVC_BUF_STATE_ACTIVE) {
- struct timespec ts;
-
- if (fid == stream->last_fid) {
- uvc_trace(UVC_TRACE_FRAME, "Dropping payload (out of "
- "sync).\n");
- if ((stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID) &&
- (data[1] & UVC_STREAM_EOF))
- stream->last_fid ^= UVC_STREAM_FID;
- return -ENODATA;
- }
-
- if (uvc_clock_param == CLOCK_MONOTONIC)
- ktime_get_ts(&ts);
- else
- ktime_get_real_ts(&ts);
-
- buf->buf.v4l2_buf.sequence = stream->sequence;
- buf->buf.v4l2_buf.timestamp.tv_sec = ts.tv_sec;
- buf->buf.v4l2_buf.timestamp.tv_usec =
- ts.tv_nsec / NSEC_PER_USEC;
-
- /* TODO: Handle PTS and SCR. */
- buf->state = UVC_BUF_STATE_ACTIVE;
- }
-
- /* Mark the buffer as done if we're at the beginning of a new frame.
- * End of frame detection is better implemented by checking the EOF
- * bit (FID bit toggling is delayed by one frame compared to the EOF
- * bit), but some devices don't set the bit at end of frame (and the
- * last payload can be lost anyway). We thus must check if the FID has
- * been toggled.
- *
- * stream->last_fid is initialized to -1, so the first isochronous
- * frame will never trigger an end of frame detection.
- *
- * Empty buffers (bytesused == 0) don't trigger end of frame detection
- * as it doesn't make sense to return an empty buffer. This also
- * avoids detecting end of frame conditions at FID toggling if the
- * previous payload had the EOF bit set.
- */
- if (fid != stream->last_fid && buf->bytesused != 0) {
- uvc_trace(UVC_TRACE_FRAME, "Frame complete (FID bit "
- "toggled).\n");
- buf->state = UVC_BUF_STATE_READY;
- return -EAGAIN;
- }
-
- stream->last_fid = fid;
-
- return data[0];
-}
-
-static void uvc_video_decode_data(struct uvc_streaming *stream,
- struct uvc_buffer *buf, const __u8 *data, int len)
-{
- unsigned int maxlen, nbytes;
- void *mem;
-
- if (len <= 0)
- return;
-
- /* Copy the video data to the buffer. */
- maxlen = buf->length - buf->bytesused;
- mem = buf->mem + buf->bytesused;
- nbytes = min((unsigned int)len, maxlen);
- memcpy(mem, data, nbytes);
- buf->bytesused += nbytes;
-
- /* Complete the current frame if the buffer size was exceeded. */
- if (len > maxlen) {
- uvc_trace(UVC_TRACE_FRAME, "Frame complete (overflow).\n");
- buf->state = UVC_BUF_STATE_READY;
- }
-}
-
-static void uvc_video_decode_end(struct uvc_streaming *stream,
- struct uvc_buffer *buf, const __u8 *data, int len)
-{
- /* Mark the buffer as done if the EOF marker is set. */
- if (data[1] & UVC_STREAM_EOF && buf->bytesused != 0) {
- uvc_trace(UVC_TRACE_FRAME, "Frame complete (EOF found).\n");
- if (data[0] == len)
- uvc_trace(UVC_TRACE_FRAME, "EOF in empty payload.\n");
- buf->state = UVC_BUF_STATE_READY;
- if (stream->dev->quirks & UVC_QUIRK_STREAM_NO_FID)
- stream->last_fid ^= UVC_STREAM_FID;
- }
-}
-
-/* Video payload encoding is handled by uvc_video_encode_header() and
- * uvc_video_encode_data(). Only bulk transfers are currently supported.
- *
- * uvc_video_encode_header is called at the start of a payload. It adds header
- * data to the transfer buffer and returns the header size. As the only known
- * UVC output device transfers a whole frame in a single payload, the EOF bit
- * is always set in the header.
- *
- * uvc_video_encode_data is called for every URB and copies the data from the
- * video buffer to the transfer buffer.
- */
-static int uvc_video_encode_header(struct uvc_streaming *stream,
- struct uvc_buffer *buf, __u8 *data, int len)
-{
- data[0] = 2; /* Header length */
- data[1] = UVC_STREAM_EOH | UVC_STREAM_EOF
- | (stream->last_fid & UVC_STREAM_FID);
- return 2;
-}
-
-static int uvc_video_encode_data(struct uvc_streaming *stream,
- struct uvc_buffer *buf, __u8 *data, int len)
-{
- struct uvc_video_queue *queue = &stream->queue;
- unsigned int nbytes;
- void *mem;
-
- /* Copy video data to the URB buffer. */
- mem = buf->mem + queue->buf_used;
- nbytes = min((unsigned int)len, buf->bytesused - queue->buf_used);
- nbytes = min(stream->bulk.max_payload_size - stream->bulk.payload_size,
- nbytes);
- memcpy(data, mem, nbytes);
-
- queue->buf_used += nbytes;
-
- return nbytes;
-}
-
-/* ------------------------------------------------------------------------
- * URB handling
- */
-
-/*
- * Completion handler for video URBs.
- */
-static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
- struct uvc_buffer *buf)
-{
- u8 *mem;
- int ret, i;
-
- for (i = 0; i < urb->number_of_packets; ++i) {
- if (urb->iso_frame_desc[i].status < 0) {
- uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame "
- "lost (%d).\n", urb->iso_frame_desc[i].status);
- /* Mark the buffer as faulty. */
- if (buf != NULL)
- buf->error = 1;
- continue;
- }
-
- /* Decode the payload header. */
- mem = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
- do {
- ret = uvc_video_decode_start(stream, buf, mem,
- urb->iso_frame_desc[i].actual_length);
- if (ret == -EAGAIN)
- buf = uvc_queue_next_buffer(&stream->queue,
- buf);
- } while (ret == -EAGAIN);
-
- if (ret < 0)
- continue;
-
- /* Decode the payload data. */
- uvc_video_decode_data(stream, buf, mem + ret,
- urb->iso_frame_desc[i].actual_length - ret);
-
- /* Process the header again. */
- uvc_video_decode_end(stream, buf, mem,
- urb->iso_frame_desc[i].actual_length);
-
- if (buf->state == UVC_BUF_STATE_READY) {
- if (buf->length != buf->bytesused &&
- !(stream->cur_format->flags &
- UVC_FMT_FLAG_COMPRESSED))
- buf->error = 1;
-
- buf = uvc_queue_next_buffer(&stream->queue, buf);
- }
- }
-}
-
-static void uvc_video_decode_bulk(struct urb *urb, struct uvc_streaming *stream,
- struct uvc_buffer *buf)
-{
- u8 *mem;
- int len, ret;
-
- /*
- * Ignore ZLPs if they're not part of a frame, otherwise process them
- * to trigger the end of payload detection.
- */
- if (urb->actual_length == 0 && stream->bulk.header_size == 0)
- return;
-
- mem = urb->transfer_buffer;
- len = urb->actual_length;
- stream->bulk.payload_size += len;
-
- /* If the URB is the first of its payload, decode and save the
- * header.
- */
- if (stream->bulk.header_size == 0 && !stream->bulk.skip_payload) {
- do {
- ret = uvc_video_decode_start(stream, buf, mem, len);
- if (ret == -EAGAIN)
- buf = uvc_queue_next_buffer(&stream->queue,
- buf);
- } while (ret == -EAGAIN);
-
- /* If an error occurred skip the rest of the payload. */
- if (ret < 0 || buf == NULL) {
- stream->bulk.skip_payload = 1;
- } else {
- memcpy(stream->bulk.header, mem, ret);
- stream->bulk.header_size = ret;
-
- mem += ret;
- len -= ret;
- }
- }
-
- /* The buffer queue might have been cancelled while a bulk transfer
- * was in progress, so we can reach here with buf equal to NULL. Make
- * sure buf is never dereferenced if NULL.
- */
-
- /* Process video data. */
- if (!stream->bulk.skip_payload && buf != NULL)
- uvc_video_decode_data(stream, buf, mem, len);
-
- /* Detect the payload end by a URB smaller than the maximum size (or
- * a payload size equal to the maximum) and process the header again.
- */
- if (urb->actual_length < urb->transfer_buffer_length ||
- stream->bulk.payload_size >= stream->bulk.max_payload_size) {
- if (!stream->bulk.skip_payload && buf != NULL) {
- uvc_video_decode_end(stream, buf, stream->bulk.header,
- stream->bulk.payload_size);
- if (buf->state == UVC_BUF_STATE_READY)
- buf = uvc_queue_next_buffer(&stream->queue,
- buf);
- }
-
- stream->bulk.header_size = 0;
- stream->bulk.skip_payload = 0;
- stream->bulk.payload_size = 0;
- }
-}
-
-static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream,
- struct uvc_buffer *buf)
-{
- u8 *mem = urb->transfer_buffer;
- int len = stream->urb_size, ret;
-
- if (buf == NULL) {
- urb->transfer_buffer_length = 0;
- return;
- }
-
- /* If the URB is the first of its payload, add the header. */
- if (stream->bulk.header_size == 0) {
- ret = uvc_video_encode_header(stream, buf, mem, len);
- stream->bulk.header_size = ret;
- stream->bulk.payload_size += ret;
- mem += ret;
- len -= ret;
- }
-
- /* Process video data. */
- ret = uvc_video_encode_data(stream, buf, mem, len);
-
- stream->bulk.payload_size += ret;
- len -= ret;
-
- if (buf->bytesused == stream->queue.buf_used ||
- stream->bulk.payload_size == stream->bulk.max_payload_size) {
- if (buf->bytesused == stream->queue.buf_used) {
- stream->queue.buf_used = 0;
- buf->state = UVC_BUF_STATE_READY;
- buf->buf.v4l2_buf.sequence = ++stream->sequence;
- uvc_queue_next_buffer(&stream->queue, buf);
- stream->last_fid ^= UVC_STREAM_FID;
- }
-
- stream->bulk.header_size = 0;
- stream->bulk.payload_size = 0;
- }
-
- urb->transfer_buffer_length = stream->urb_size - len;
-}
-
-static void uvc_video_complete(struct urb *urb)
-{
- struct uvc_streaming *stream = urb->context;
- struct uvc_video_queue *queue = &stream->queue;
- struct uvc_buffer *buf = NULL;
- unsigned long flags;
- int ret;
-
- switch (urb->status) {
- case 0:
- break;
-
- default:
- uvc_printk(KERN_WARNING, "Non-zero status (%d) in video "
- "completion handler.\n", urb->status);
-
- case -ENOENT: /* usb_kill_urb() called. */
- if (stream->frozen)
- return;
-
- case -ECONNRESET: /* usb_unlink_urb() called. */
- case -ESHUTDOWN: /* The endpoint is being disabled. */
- uvc_queue_cancel(queue, urb->status == -ESHUTDOWN);
- return;
- }
-
- spin_lock_irqsave(&queue->irqlock, flags);
- if (!list_empty(&queue->irqqueue))
- buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
- queue);
- spin_unlock_irqrestore(&queue->irqlock, flags);
-
- stream->decode(urb, stream, buf);
-
- if ((ret = usb_submit_urb(urb, GFP_ATOMIC)) < 0) {
- uvc_printk(KERN_ERR, "Failed to resubmit video URB (%d).\n",
- ret);
- }
-}
-
-/*
- * Free transfer buffers.
- */
-static void uvc_free_urb_buffers(struct uvc_streaming *stream)
-{
- unsigned int i;
-
- for (i = 0; i < UVC_URBS; ++i) {
- if (stream->urb_buffer[i]) {
-#ifndef CONFIG_DMA_NONCOHERENT
- usb_free_coherent(stream->dev->udev, stream->urb_size,
- stream->urb_buffer[i], stream->urb_dma[i]);
-#else
- kfree(stream->urb_buffer[i]);
-#endif
- stream->urb_buffer[i] = NULL;
- }
- }
-
- stream->urb_size = 0;
-}
-
-/*
- * Allocate transfer buffers. This function can be called with buffers
- * already allocated when resuming from suspend, in which case it will
- * return without touching the buffers.
- *
- * Limit the buffer size to UVC_MAX_PACKETS bulk/isochronous packets. If the
- * system is too low on memory try successively smaller numbers of packets
- * until allocation succeeds.
- *
- * Return the number of allocated packets on success or 0 when out of memory.
- */
-static int uvc_alloc_urb_buffers(struct uvc_streaming *stream,
- unsigned int size, unsigned int psize, gfp_t gfp_flags)
-{
- unsigned int npackets;
- unsigned int i;
-
- /* Buffers are already allocated, bail out. */
- if (stream->urb_size)
- return stream->urb_size / psize;
-
- /* Compute the number of packets. Bulk endpoints might transfer UVC
- * payloads across multiple URBs.
- */
- npackets = DIV_ROUND_UP(size, psize);
- if (npackets > UVC_MAX_PACKETS)
- npackets = UVC_MAX_PACKETS;
-
- /* Retry allocations until one succeed. */
- for (; npackets > 1; npackets /= 2) {
- for (i = 0; i < UVC_URBS; ++i) {
- stream->urb_size = psize * npackets;
-#ifndef CONFIG_DMA_NONCOHERENT
- stream->urb_buffer[i] = usb_alloc_coherent(
- stream->dev->udev, stream->urb_size,
- gfp_flags | __GFP_NOWARN, &stream->urb_dma[i]);
-#else
- stream->urb_buffer[i] =
- kmalloc(stream->urb_size, gfp_flags | __GFP_NOWARN);
-#endif
- if (!stream->urb_buffer[i]) {
- uvc_free_urb_buffers(stream);
- break;
- }
- }
-
- if (i == UVC_URBS) {
- uvc_trace(UVC_TRACE_VIDEO, "Allocated %u URB buffers "
- "of %ux%u bytes each.\n", UVC_URBS, npackets,
- psize);
- return npackets;
- }
- }
-
- uvc_trace(UVC_TRACE_VIDEO, "Failed to allocate URB buffers (%u bytes "
- "per packet).\n", psize);
- return 0;
-}
-
-/*
- * Uninitialize isochronous/bulk URBs and free transfer buffers.
- */
-static void uvc_uninit_video(struct uvc_streaming *stream, int free_buffers)
-{
- struct urb *urb;
- unsigned int i;
-
- uvc_video_stats_stop(stream);
-
- for (i = 0; i < UVC_URBS; ++i) {
- urb = stream->urb[i];
- if (urb == NULL)
- continue;
-
- usb_kill_urb(urb);
- usb_free_urb(urb);
- stream->urb[i] = NULL;
- }
-
- if (free_buffers)
- uvc_free_urb_buffers(stream);
-}
-
-/*
- * Compute the maximum number of bytes per interval for an endpoint.
- */
-static unsigned int uvc_endpoint_max_bpi(struct usb_device *dev,
- struct usb_host_endpoint *ep)
-{
- u16 psize;
-
- switch (dev->speed) {
- case USB_SPEED_SUPER:
- return ep->ss_ep_comp.wBytesPerInterval;
- case USB_SPEED_HIGH:
- psize = usb_endpoint_maxp(&ep->desc);
- return (psize & 0x07ff) * (1 + ((psize >> 11) & 3));
- default:
- psize = usb_endpoint_maxp(&ep->desc);
- return psize & 0x07ff;
- }
-}
-
-/*
- * Initialize isochronous URBs and allocate transfer buffers. The packet size
- * is given by the endpoint.
- */
-static int uvc_init_video_isoc(struct uvc_streaming *stream,
- struct usb_host_endpoint *ep, gfp_t gfp_flags)
-{
- struct urb *urb;
- unsigned int npackets, i, j;
- u16 psize;
- u32 size;
-
- psize = uvc_endpoint_max_bpi(stream->dev->udev, ep);
- size = stream->ctrl.dwMaxVideoFrameSize;
-
- npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);
- if (npackets == 0)
- return -ENOMEM;
-
- size = npackets * psize;
-
- for (i = 0; i < UVC_URBS; ++i) {
- urb = usb_alloc_urb(npackets, gfp_flags);
- if (urb == NULL) {
- uvc_uninit_video(stream, 1);
- return -ENOMEM;
- }
-
- urb->dev = stream->dev->udev;
- urb->context = stream;
- urb->pipe = usb_rcvisocpipe(stream->dev->udev,
- ep->desc.bEndpointAddress);
-#ifndef CONFIG_DMA_NONCOHERENT
- urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
- urb->transfer_dma = stream->urb_dma[i];
-#else
- urb->transfer_flags = URB_ISO_ASAP;
-#endif
- urb->interval = ep->desc.bInterval;
- urb->transfer_buffer = stream->urb_buffer[i];
- urb->complete = uvc_video_complete;
- urb->number_of_packets = npackets;
- urb->transfer_buffer_length = size;
-
- for (j = 0; j < npackets; ++j) {
- urb->iso_frame_desc[j].offset = j * psize;
- urb->iso_frame_desc[j].length = psize;
- }
-
- stream->urb[i] = urb;
- }
-
- return 0;
-}
-
-/*
- * Initialize bulk URBs and allocate transfer buffers. The packet size is
- * given by the endpoint.
- */
-static int uvc_init_video_bulk(struct uvc_streaming *stream,
- struct usb_host_endpoint *ep, gfp_t gfp_flags)
-{
- struct urb *urb;
- unsigned int npackets, pipe, i;
- u16 psize;
- u32 size;
-
- psize = usb_endpoint_maxp(&ep->desc) & 0x7ff;
- size = stream->ctrl.dwMaxPayloadTransferSize;
- stream->bulk.max_payload_size = size;
-
- npackets = uvc_alloc_urb_buffers(stream, size, psize, gfp_flags);
- if (npackets == 0)
- return -ENOMEM;
-
- size = npackets * psize;
-
- if (usb_endpoint_dir_in(&ep->desc))
- pipe = usb_rcvbulkpipe(stream->dev->udev,
- ep->desc.bEndpointAddress);
- else
- pipe = usb_sndbulkpipe(stream->dev->udev,
- ep->desc.bEndpointAddress);
-
- if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
- size = 0;
-
- for (i = 0; i < UVC_URBS; ++i) {
- urb = usb_alloc_urb(0, gfp_flags);
- if (urb == NULL) {
- uvc_uninit_video(stream, 1);
- return -ENOMEM;
- }
-
- usb_fill_bulk_urb(urb, stream->dev->udev, pipe,
- stream->urb_buffer[i], size, uvc_video_complete,
- stream);
-#ifndef CONFIG_DMA_NONCOHERENT
- urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
- urb->transfer_dma = stream->urb_dma[i];
-#endif
-
- stream->urb[i] = urb;
- }
-
- return 0;
-}
-
-/*
- * Initialize isochronous/bulk URBs and allocate transfer buffers.
- */
-static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
-{
- struct usb_interface *intf = stream->intf;
- struct usb_host_endpoint *ep;
- unsigned int i;
- int ret;
-
- stream->sequence = -1;
- stream->last_fid = -1;
- stream->bulk.header_size = 0;
- stream->bulk.skip_payload = 0;
- stream->bulk.payload_size = 0;
-
- uvc_video_stats_start(stream);
-
- if (intf->num_altsetting > 1) {
- struct usb_host_endpoint *best_ep = NULL;
- unsigned int best_psize = UINT_MAX;
- unsigned int bandwidth;
- unsigned int uninitialized_var(altsetting);
- int intfnum = stream->intfnum;
-
- /* Isochronous endpoint, select the alternate setting. */
- bandwidth = stream->ctrl.dwMaxPayloadTransferSize;
-
- if (bandwidth == 0) {
- uvc_trace(UVC_TRACE_VIDEO, "Device requested null "
- "bandwidth, defaulting to lowest.\n");
- bandwidth = 1;
- } else {
- uvc_trace(UVC_TRACE_VIDEO, "Device requested %u "
- "B/frame bandwidth.\n", bandwidth);
- }
-
- for (i = 0; i < intf->num_altsetting; ++i) {
- struct usb_host_interface *alts;
- unsigned int psize;
-
- alts = &intf->altsetting[i];
- ep = uvc_find_endpoint(alts,
- stream->header.bEndpointAddress);
- if (ep == NULL)
- continue;
-
- /* Check if the bandwidth is high enough. */
- psize = uvc_endpoint_max_bpi(stream->dev->udev, ep);
- if (psize >= bandwidth && psize <= best_psize) {
- altsetting = alts->desc.bAlternateSetting;
- best_psize = psize;
- best_ep = ep;
- }
- }
-
- if (best_ep == NULL) {
- uvc_trace(UVC_TRACE_VIDEO, "No fast enough alt setting "
- "for requested bandwidth.\n");
- return -EIO;
- }
-
- uvc_trace(UVC_TRACE_VIDEO, "Selecting alternate setting %u "
- "(%u B/frame bandwidth).\n", altsetting, best_psize);
-
- ret = usb_set_interface(stream->dev->udev, intfnum, altsetting);
- if (ret < 0)
- return ret;
-
- ret = uvc_init_video_isoc(stream, best_ep, gfp_flags);
- } else {
- /* Bulk endpoint, proceed to URB initialization. */
- ep = uvc_find_endpoint(&intf->altsetting[0],
- stream->header.bEndpointAddress);
- if (ep == NULL)
- return -EIO;
-
- ret = uvc_init_video_bulk(stream, ep, gfp_flags);
- }
-
- if (ret < 0)
- return ret;
-
- /* Submit the URBs. */
- for (i = 0; i < UVC_URBS; ++i) {
- ret = usb_submit_urb(stream->urb[i], gfp_flags);
- if (ret < 0) {
- uvc_printk(KERN_ERR, "Failed to submit URB %u "
- "(%d).\n", i, ret);
- uvc_uninit_video(stream, 1);
- return ret;
- }
- }
-
- return 0;
-}
-
-/* --------------------------------------------------------------------------
- * Suspend/resume
- */
-
-/*
- * Stop streaming without disabling the video queue.
- *
- * To let userspace applications resume without trouble, we must not touch the
- * video buffers in any way. We mark the device as frozen to make sure the URB
- * completion handler won't try to cancel the queue when we kill the URBs.
- */
-int uvc_video_suspend(struct uvc_streaming *stream)
-{
- if (!uvc_queue_streaming(&stream->queue))
- return 0;
-
- stream->frozen = 1;
- uvc_uninit_video(stream, 0);
- usb_set_interface(stream->dev->udev, stream->intfnum, 0);
- return 0;
-}
-
-/*
- * Reconfigure the video interface and restart streaming if it was enabled
- * before suspend.
- *
- * If an error occurs, disable the video queue. This will wake all pending
- * buffers, making sure userspace applications are notified of the problem
- * instead of waiting forever.
- */
-int uvc_video_resume(struct uvc_streaming *stream, int reset)
-{
- int ret;
-
- /* If the bus has been reset on resume, set the alternate setting to 0.
- * This should be the default value, but some devices crash or otherwise
- * misbehave if they don't receive a SET_INTERFACE request before any
- * other video control request.
- */
- if (reset)
- usb_set_interface(stream->dev->udev, stream->intfnum, 0);
-
- stream->frozen = 0;
-
- uvc_video_clock_reset(stream);
-
- ret = uvc_commit_video(stream, &stream->ctrl);
- if (ret < 0) {
- uvc_queue_enable(&stream->queue, 0);
- return ret;
- }
-
- if (!uvc_queue_streaming(&stream->queue))
- return 0;
-
- ret = uvc_init_video(stream, GFP_NOIO);
- if (ret < 0)
- uvc_queue_enable(&stream->queue, 0);
-
- return ret;
-}
-
-/* ------------------------------------------------------------------------
- * Video device
- */
-
-/*
- * Initialize the UVC video device by switching to alternate setting 0 and
- * retrieve the default format.
- *
- * Some cameras (namely the Fuji Finepix) set the format and frame
- * indexes to zero. The UVC standard doesn't clearly make this a spec
- * violation, so try to silently fix the values if possible.
- *
- * This function is called before registering the device with V4L.
- */
-int uvc_video_init(struct uvc_streaming *stream)
-{
- struct uvc_streaming_control *probe = &stream->ctrl;
- struct uvc_format *format = NULL;
- struct uvc_frame *frame = NULL;
- unsigned int i;
- int ret;
-
- if (stream->nformats == 0) {
- uvc_printk(KERN_INFO, "No supported video formats found.\n");
- return -EINVAL;
- }
-
- atomic_set(&stream->active, 0);
-
- /* Initialize the video buffers queue. */
- uvc_queue_init(&stream->queue, stream->type, !uvc_no_drop_param);
-
- /* Alternate setting 0 should be the default, yet the XBox Live Vision
- * Cam (and possibly other devices) crash or otherwise misbehave if
- * they don't receive a SET_INTERFACE request before any other video
- * control request.
- */
- usb_set_interface(stream->dev->udev, stream->intfnum, 0);
-
- /* Set the streaming probe control with default streaming parameters
- * retrieved from the device. Webcams that don't suport GET_DEF
- * requests on the probe control will just keep their current streaming
- * parameters.
- */
- if (uvc_get_video_ctrl(stream, probe, 1, UVC_GET_DEF) == 0)
- uvc_set_video_ctrl(stream, probe, 1);
-
- /* Initialize the streaming parameters with the probe control current
- * value. This makes sure SET_CUR requests on the streaming commit
- * control will always use values retrieved from a successful GET_CUR
- * request on the probe control, as required by the UVC specification.
- */
- ret = uvc_get_video_ctrl(stream, probe, 1, UVC_GET_CUR);
- if (ret < 0)
- return ret;
-
- /* Check if the default format descriptor exists. Use the first
- * available format otherwise.
- */
- for (i = stream->nformats; i > 0; --i) {
- format = &stream->format[i-1];
- if (format->index == probe->bFormatIndex)
- break;
- }
-
- if (format->nframes == 0) {
- uvc_printk(KERN_INFO, "No frame descriptor found for the "
- "default format.\n");
- return -EINVAL;
- }
-
- /* Zero bFrameIndex might be correct. Stream-based formats (including
- * MPEG-2 TS and DV) do not support frames but have a dummy frame
- * descriptor with bFrameIndex set to zero. If the default frame
- * descriptor is not found, use the first available frame.
- */
- for (i = format->nframes; i > 0; --i) {
- frame = &format->frame[i-1];
- if (frame->bFrameIndex == probe->bFrameIndex)
- break;
- }
-
- probe->bFormatIndex = format->index;
- probe->bFrameIndex = frame->bFrameIndex;
-
- stream->cur_format = format;
- stream->cur_frame = frame;
-
- /* Select the video decoding function */
- if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (stream->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)
- stream->decode = uvc_video_decode_isight;
- else if (stream->intf->num_altsetting > 1)
- stream->decode = uvc_video_decode_isoc;
- else
- stream->decode = uvc_video_decode_bulk;
- } else {
- if (stream->intf->num_altsetting == 1)
- stream->decode = uvc_video_encode_bulk;
- else {
- uvc_printk(KERN_INFO, "Isochronous endpoints are not "
- "supported for video output devices.\n");
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-/*
- * Enable or disable the video stream.
- */
-int uvc_video_enable(struct uvc_streaming *stream, int enable)
-{
- int ret;
-
- if (!enable) {
- uvc_uninit_video(stream, 1);
- usb_set_interface(stream->dev->udev, stream->intfnum, 0);
- uvc_queue_enable(&stream->queue, 0);
- uvc_video_clock_cleanup(stream);
- return 0;
- }
-
- ret = uvc_video_clock_init(stream);
- if (ret < 0)
- return ret;
-
- ret = uvc_queue_enable(&stream->queue, 1);
- if (ret < 0)
- goto error_queue;
-
- /* Commit the streaming parameters. */
- ret = uvc_commit_video(stream, &stream->ctrl);
- if (ret < 0)
- goto error_commit;
-
- ret = uvc_init_video(stream, GFP_KERNEL);
- if (ret < 0)
- goto error_video;
-
- return 0;
-
-error_video:
- usb_set_interface(stream->dev->udev, stream->intfnum, 0);
-error_commit:
- uvc_queue_enable(&stream->queue, 0);
-error_queue:
- uvc_video_clock_cleanup(stream);
-
- return ret;
-}
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
deleted file mode 100644
index 3764040475b..00000000000
--- a/drivers/media/video/uvc/uvcvideo.h
+++ /dev/null
@@ -1,718 +0,0 @@
-#ifndef _USB_VIDEO_H_
-#define _USB_VIDEO_H_
-
-#ifndef __KERNEL__
-#error "The uvcvideo.h header is deprecated, use linux/uvcvideo.h instead."
-#endif /* __KERNEL__ */
-
-#include <linux/kernel.h>
-#include <linux/poll.h>
-#include <linux/usb.h>
-#include <linux/usb/video.h>
-#include <linux/uvcvideo.h>
-#include <linux/videodev2.h>
-#include <media/media-device.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-fh.h>
-#include <media/videobuf2-core.h>
-
-/* --------------------------------------------------------------------------
- * UVC constants
- */
-
-#define UVC_TERM_INPUT 0x0000
-#define UVC_TERM_OUTPUT 0x8000
-#define UVC_TERM_DIRECTION(term) ((term)->type & 0x8000)
-
-#define UVC_ENTITY_TYPE(entity) ((entity)->type & 0x7fff)
-#define UVC_ENTITY_IS_UNIT(entity) (((entity)->type & 0xff00) == 0)
-#define UVC_ENTITY_IS_TERM(entity) (((entity)->type & 0xff00) != 0)
-#define UVC_ENTITY_IS_ITERM(entity) \
- (UVC_ENTITY_IS_TERM(entity) && \
- ((entity)->type & 0x8000) == UVC_TERM_INPUT)
-#define UVC_ENTITY_IS_OTERM(entity) \
- (UVC_ENTITY_IS_TERM(entity) && \
- ((entity)->type & 0x8000) == UVC_TERM_OUTPUT)
-
-
-/* ------------------------------------------------------------------------
- * GUIDs
- */
-#define UVC_GUID_UVC_CAMERA \
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}
-#define UVC_GUID_UVC_OUTPUT \
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}
-#define UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT \
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
-#define UVC_GUID_UVC_PROCESSING \
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01}
-#define UVC_GUID_UVC_SELECTOR \
- {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02}
-
-#define UVC_GUID_FORMAT_MJPEG \
- { 'M', 'J', 'P', 'G', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_YUY2 \
- { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_YUY2_ISIGHT \
- { 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0x00, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_NV12 \
- { 'N', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_YV12 \
- { 'Y', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_I420 \
- { 'I', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_UYVY \
- { 'U', 'Y', 'V', 'Y', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y800 \
- { 'Y', '8', '0', '0', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y8 \
- { 'Y', '8', ' ', ' ', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y10 \
- { 'Y', '1', '0', ' ', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y12 \
- { 'Y', '1', '2', ' ', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_Y16 \
- { 'Y', '1', '6', ' ', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_BY8 \
- { 'B', 'Y', '8', ' ', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_RGBP \
- { 'R', 'G', 'B', 'P', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-#define UVC_GUID_FORMAT_M420 \
- { 'M', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-
-#define UVC_GUID_FORMAT_H264 \
- { 'H', '2', '6', '4', 0x00, 0x00, 0x10, 0x00, \
- 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
-
-/* ------------------------------------------------------------------------
- * Driver specific constants.
- */
-
-#define DRIVER_VERSION "1.1.1"
-
-/* Number of isochronous URBs. */
-#define UVC_URBS 5
-/* Maximum number of packets per URB. */
-#define UVC_MAX_PACKETS 32
-/* Maximum number of video buffers. */
-#define UVC_MAX_VIDEO_BUFFERS 32
-/* Maximum status buffer size in bytes of interrupt URB. */
-#define UVC_MAX_STATUS_SIZE 16
-
-#define UVC_CTRL_CONTROL_TIMEOUT 300
-#define UVC_CTRL_STREAMING_TIMEOUT 5000
-
-/* Maximum allowed number of control mappings per device */
-#define UVC_MAX_CONTROL_MAPPINGS 1024
-#define UVC_MAX_CONTROL_MENU_ENTRIES 32
-
-/* Devices quirks */
-#define UVC_QUIRK_STATUS_INTERVAL 0x00000001
-#define UVC_QUIRK_PROBE_MINMAX 0x00000002
-#define UVC_QUIRK_PROBE_EXTRAFIELDS 0x00000004
-#define UVC_QUIRK_BUILTIN_ISIGHT 0x00000008
-#define UVC_QUIRK_STREAM_NO_FID 0x00000010
-#define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
-#define UVC_QUIRK_FIX_BANDWIDTH 0x00000080
-#define UVC_QUIRK_PROBE_DEF 0x00000100
-#define UVC_QUIRK_RESTRICT_FRAME_RATE 0x00000200
-
-/* Format flags */
-#define UVC_FMT_FLAG_COMPRESSED 0x00000001
-#define UVC_FMT_FLAG_STREAM 0x00000002
-
-/* ------------------------------------------------------------------------
- * Structures.
- */
-
-struct uvc_device;
-
-/* TODO: Put the most frequently accessed fields at the beginning of
- * structures to maximize cache efficiency.
- */
-struct uvc_control_info {
- struct list_head mappings;
-
- __u8 entity[16];
- __u8 index; /* Bit index in bmControls */
- __u8 selector;
-
- __u16 size;
- __u32 flags;
-};
-
-struct uvc_control_mapping {
- struct list_head list;
- struct list_head ev_subs;
-
- __u32 id;
- __u8 name[32];
- __u8 entity[16];
- __u8 selector;
-
- __u8 size;
- __u8 offset;
- enum v4l2_ctrl_type v4l2_type;
- __u32 data_type;
-
- struct uvc_menu_info *menu_info;
- __u32 menu_count;
-
- __u32 master_id;
- __s32 master_manual;
- __u32 slave_ids[2];
-
- __s32 (*get) (struct uvc_control_mapping *mapping, __u8 query,
- const __u8 *data);
- void (*set) (struct uvc_control_mapping *mapping, __s32 value,
- __u8 *data);
-};
-
-struct uvc_control {
- struct uvc_entity *entity;
- struct uvc_control_info info;
-
- __u8 index; /* Used to match the uvc_control entry with a
- uvc_control_info. */
- __u8 dirty:1,
- loaded:1,
- modified:1,
- cached:1,
- initialized:1;
-
- __u8 *uvc_data;
-};
-
-struct uvc_format_desc {
- char *name;
- __u8 guid[16];
- __u32 fcc;
-};
-
-/* The term 'entity' refers to both UVC units and UVC terminals.
- *
- * The type field is either the terminal type (wTerminalType in the terminal
- * descriptor), or the unit type (bDescriptorSubtype in the unit descriptor).
- * As the bDescriptorSubtype field is one byte long, the type value will
- * always have a null MSB for units. All terminal types defined by the UVC
- * specification have a non-null MSB, so it is safe to use the MSB to
- * differentiate between units and terminals as long as the descriptor parsing
- * code makes sure terminal types have a non-null MSB.
- *
- * For terminals, the type's most significant bit stores the terminal
- * direction (either UVC_TERM_INPUT or UVC_TERM_OUTPUT). The type field should
- * always be accessed with the UVC_ENTITY_* macros and never directly.
- */
-
-struct uvc_entity {
- struct list_head list; /* Entity as part of a UVC device. */
- struct list_head chain; /* Entity as part of a video device
- * chain. */
- __u8 id;
- __u16 type;
- char name[64];
-
- /* Media controller-related fields. */
- struct video_device *vdev;
- struct v4l2_subdev subdev;
- unsigned int num_pads;
- unsigned int num_links;
- struct media_pad *pads;
-
- union {
- struct {
- __u16 wObjectiveFocalLengthMin;
- __u16 wObjectiveFocalLengthMax;
- __u16 wOcularFocalLength;
- __u8 bControlSize;
- __u8 *bmControls;
- } camera;
-
- struct {
- __u8 bControlSize;
- __u8 *bmControls;
- __u8 bTransportModeSize;
- __u8 *bmTransportModes;
- } media;
-
- struct {
- } output;
-
- struct {
- __u16 wMaxMultiplier;
- __u8 bControlSize;
- __u8 *bmControls;
- __u8 bmVideoStandards;
- } processing;
-
- struct {
- } selector;
-
- struct {
- __u8 guidExtensionCode[16];
- __u8 bNumControls;
- __u8 bControlSize;
- __u8 *bmControls;
- __u8 *bmControlsType;
- } extension;
- };
-
- __u8 bNrInPins;
- __u8 *baSourceID;
-
- unsigned int ncontrols;
- struct uvc_control *controls;
-};
-
-struct uvc_frame {
- __u8 bFrameIndex;
- __u8 bmCapabilities;
- __u16 wWidth;
- __u16 wHeight;
- __u32 dwMinBitRate;
- __u32 dwMaxBitRate;
- __u32 dwMaxVideoFrameBufferSize;
- __u8 bFrameIntervalType;
- __u32 dwDefaultFrameInterval;
- __u32 *dwFrameInterval;
-};
-
-struct uvc_format {
- __u8 type;
- __u8 index;
- __u8 bpp;
- __u8 colorspace;
- __u32 fcc;
- __u32 flags;
-
- char name[32];
-
- unsigned int nframes;
- struct uvc_frame *frame;
-};
-
-struct uvc_streaming_header {
- __u8 bNumFormats;
- __u8 bEndpointAddress;
- __u8 bTerminalLink;
- __u8 bControlSize;
- __u8 *bmaControls;
- /* The following fields are used by input headers only. */
- __u8 bmInfo;
- __u8 bStillCaptureMethod;
- __u8 bTriggerSupport;
- __u8 bTriggerUsage;
-};
-
-enum uvc_buffer_state {
- UVC_BUF_STATE_IDLE = 0,
- UVC_BUF_STATE_QUEUED = 1,
- UVC_BUF_STATE_ACTIVE = 2,
- UVC_BUF_STATE_READY = 3,
- UVC_BUF_STATE_DONE = 4,
- UVC_BUF_STATE_ERROR = 5,
-};
-
-struct uvc_buffer {
- struct vb2_buffer buf;
- struct list_head queue;
-
- enum uvc_buffer_state state;
- unsigned int error;
-
- void *mem;
- unsigned int length;
- unsigned int bytesused;
-
- u32 pts;
-};
-
-#define UVC_QUEUE_DISCONNECTED (1 << 0)
-#define UVC_QUEUE_DROP_CORRUPTED (1 << 1)
-
-struct uvc_video_queue {
- struct vb2_queue queue;
- struct mutex mutex; /* Protects queue */
-
- unsigned int flags;
- unsigned int buf_used;
-
- spinlock_t irqlock; /* Protects irqqueue */
- struct list_head irqqueue;
-};
-
-struct uvc_video_chain {
- struct uvc_device *dev;
- struct list_head list;
-
- struct list_head entities; /* All entities */
- struct uvc_entity *processing; /* Processing unit */
- struct uvc_entity *selector; /* Selector unit */
-
- struct mutex ctrl_mutex; /* Protects ctrl.info */
-};
-
-struct uvc_stats_frame {
- unsigned int size; /* Number of bytes captured */
- unsigned int first_data; /* Index of the first non-empty packet */
-
- unsigned int nb_packets; /* Number of packets */
- unsigned int nb_empty; /* Number of empty packets */
- unsigned int nb_invalid; /* Number of packets with an invalid header */
- unsigned int nb_errors; /* Number of packets with the error bit set */
-
- unsigned int nb_pts; /* Number of packets with a PTS timestamp */
- unsigned int nb_pts_diffs; /* Number of PTS differences inside a frame */
- unsigned int last_pts_diff; /* Index of the last PTS difference */
- bool has_initial_pts; /* Whether the first non-empty packet has a PTS */
- bool has_early_pts; /* Whether a PTS is present before the first non-empty packet */
- u32 pts; /* PTS of the last packet */
-
- unsigned int nb_scr; /* Number of packets with a SCR timestamp */
- unsigned int nb_scr_diffs; /* Number of SCR.STC differences inside a frame */
- u16 scr_sof; /* SCR.SOF of the last packet */
- u32 scr_stc; /* SCR.STC of the last packet */
-};
-
-struct uvc_stats_stream {
- struct timespec start_ts; /* Stream start timestamp */
- struct timespec stop_ts; /* Stream stop timestamp */
-
- unsigned int nb_frames; /* Number of frames */
-
- unsigned int nb_packets; /* Number of packets */
- unsigned int nb_empty; /* Number of empty packets */
- unsigned int nb_invalid; /* Number of packets with an invalid header */
- unsigned int nb_errors; /* Number of packets with the error bit set */
-
- unsigned int nb_pts_constant; /* Number of frames with constant PTS */
- unsigned int nb_pts_early; /* Number of frames with early PTS */
- unsigned int nb_pts_initial; /* Number of frames with initial PTS */
-
- unsigned int nb_scr_count_ok; /* Number of frames with at least one SCR per non empty packet */
- unsigned int nb_scr_diffs_ok; /* Number of frames with varying SCR.STC */
- unsigned int scr_sof_count; /* STC.SOF counter accumulated since stream start */
- unsigned int scr_sof; /* STC.SOF of the last packet */
- unsigned int min_sof; /* Minimum STC.SOF value */
- unsigned int max_sof; /* Maximum STC.SOF value */
-};
-
-struct uvc_streaming {
- struct list_head list;
- struct uvc_device *dev;
- struct video_device *vdev;
- struct uvc_video_chain *chain;
- atomic_t active;
-
- struct usb_interface *intf;
- int intfnum;
- __u16 maxpsize;
-
- struct uvc_streaming_header header;
- enum v4l2_buf_type type;
-
- unsigned int nformats;
- struct uvc_format *format;
-
- struct uvc_streaming_control ctrl;
- struct uvc_format *cur_format;
- struct uvc_frame *cur_frame;
- /* Protect access to ctrl, cur_format, cur_frame and hardware video
- * probe control.
- */
- struct mutex mutex;
-
- /* Buffers queue. */
- unsigned int frozen : 1;
- struct uvc_video_queue queue;
- void (*decode) (struct urb *urb, struct uvc_streaming *video,
- struct uvc_buffer *buf);
-
- /* Context data used by the bulk completion handler. */
- struct {
- __u8 header[256];
- unsigned int header_size;
- int skip_payload;
- __u32 payload_size;
- __u32 max_payload_size;
- } bulk;
-
- struct urb *urb[UVC_URBS];
- char *urb_buffer[UVC_URBS];
- dma_addr_t urb_dma[UVC_URBS];
- unsigned int urb_size;
-
- __u32 sequence;
- __u8 last_fid;
-
- /* debugfs */
- struct dentry *debugfs_dir;
- struct {
- struct uvc_stats_frame frame;
- struct uvc_stats_stream stream;
- } stats;
-
- /* Timestamps support. */
- struct uvc_clock {
- struct uvc_clock_sample {
- u32 dev_stc;
- u16 dev_sof;
- struct timespec host_ts;
- u16 host_sof;
- } *samples;
-
- unsigned int head;
- unsigned int count;
- unsigned int size;
-
- u16 last_sof;
- u16 sof_offset;
-
- spinlock_t lock;
- } clock;
-};
-
-enum uvc_device_state {
- UVC_DEV_DISCONNECTED = 1,
-};
-
-struct uvc_device {
- struct usb_device *udev;
- struct usb_interface *intf;
- unsigned long warnings;
- __u32 quirks;
- int intfnum;
- char name[32];
-
- enum uvc_device_state state;
- atomic_t users;
- atomic_t nmappings;
-
- /* Video control interface */
-#ifdef CONFIG_MEDIA_CONTROLLER
- struct media_device mdev;
-#endif
- struct v4l2_device vdev;
- __u16 uvc_version;
- __u32 clock_frequency;
-
- struct list_head entities;
- struct list_head chains;
-
- /* Video Streaming interfaces */
- struct list_head streams;
- atomic_t nstreams;
-
- /* Status Interrupt Endpoint */
- struct usb_host_endpoint *int_ep;
- struct urb *int_urb;
- __u8 *status;
- struct input_dev *input;
- char input_phys[64];
-};
-
-enum uvc_handle_state {
- UVC_HANDLE_PASSIVE = 0,
- UVC_HANDLE_ACTIVE = 1,
-};
-
-struct uvc_fh {
- struct v4l2_fh vfh;
- struct uvc_video_chain *chain;
- struct uvc_streaming *stream;
- enum uvc_handle_state state;
-};
-
-struct uvc_driver {
- struct usb_driver driver;
-};
-
-/* ------------------------------------------------------------------------
- * Debugging, printing and logging
- */
-
-#define UVC_TRACE_PROBE (1 << 0)
-#define UVC_TRACE_DESCR (1 << 1)
-#define UVC_TRACE_CONTROL (1 << 2)
-#define UVC_TRACE_FORMAT (1 << 3)
-#define UVC_TRACE_CAPTURE (1 << 4)
-#define UVC_TRACE_CALLS (1 << 5)
-#define UVC_TRACE_IOCTL (1 << 6)
-#define UVC_TRACE_FRAME (1 << 7)
-#define UVC_TRACE_SUSPEND (1 << 8)
-#define UVC_TRACE_STATUS (1 << 9)
-#define UVC_TRACE_VIDEO (1 << 10)
-#define UVC_TRACE_STATS (1 << 11)
-#define UVC_TRACE_CLOCK (1 << 12)
-
-#define UVC_WARN_MINMAX 0
-#define UVC_WARN_PROBE_DEF 1
-#define UVC_WARN_XU_GET_RES 2
-
-extern unsigned int uvc_clock_param;
-extern unsigned int uvc_no_drop_param;
-extern unsigned int uvc_trace_param;
-extern unsigned int uvc_timeout_param;
-
-#define uvc_trace(flag, msg...) \
- do { \
- if (uvc_trace_param & flag) \
- printk(KERN_DEBUG "uvcvideo: " msg); \
- } while (0)
-
-#define uvc_warn_once(dev, warn, msg...) \
- do { \
- if (!test_and_set_bit(warn, &dev->warnings)) \
- printk(KERN_INFO "uvcvideo: " msg); \
- } while (0)
-
-#define uvc_printk(level, msg...) \
- printk(level "uvcvideo: " msg)
-
-/* --------------------------------------------------------------------------
- * Internal functions.
- */
-
-/* Core driver */
-extern struct uvc_driver uvc_driver;
-
-extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);
-
-/* Video buffers queue management. */
-extern void uvc_queue_init(struct uvc_video_queue *queue,
- enum v4l2_buf_type type, int drop_corrupted);
-extern int uvc_alloc_buffers(struct uvc_video_queue *queue,
- struct v4l2_requestbuffers *rb);
-extern void uvc_free_buffers(struct uvc_video_queue *queue);
-extern int uvc_query_buffer(struct uvc_video_queue *queue,
- struct v4l2_buffer *v4l2_buf);
-extern int uvc_queue_buffer(struct uvc_video_queue *queue,
- struct v4l2_buffer *v4l2_buf);
-extern int uvc_dequeue_buffer(struct uvc_video_queue *queue,
- struct v4l2_buffer *v4l2_buf, int nonblocking);
-extern int uvc_queue_enable(struct uvc_video_queue *queue, int enable);
-extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect);
-extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
- struct uvc_buffer *buf);
-extern int uvc_queue_mmap(struct uvc_video_queue *queue,
- struct vm_area_struct *vma);
-extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
- struct file *file, poll_table *wait);
-#ifndef CONFIG_MMU
-extern unsigned long uvc_queue_get_unmapped_area(struct uvc_video_queue *queue,
- unsigned long pgoff);
-#endif
-extern int uvc_queue_allocated(struct uvc_video_queue *queue);
-static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
-{
- return vb2_is_streaming(&queue->queue);
-}
-
-/* V4L2 interface */
-extern const struct v4l2_file_operations uvc_fops;
-
-/* Media controller */
-extern int uvc_mc_register_entities(struct uvc_video_chain *chain);
-extern void uvc_mc_cleanup_entity(struct uvc_entity *entity);
-
-/* Video */
-extern int uvc_video_init(struct uvc_streaming *stream);
-extern int uvc_video_suspend(struct uvc_streaming *stream);
-extern int uvc_video_resume(struct uvc_streaming *stream, int reset);
-extern int uvc_video_enable(struct uvc_streaming *stream, int enable);
-extern int uvc_probe_video(struct uvc_streaming *stream,
- struct uvc_streaming_control *probe);
-extern int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
- __u8 intfnum, __u8 cs, void *data, __u16 size);
-void uvc_video_clock_update(struct uvc_streaming *stream,
- struct v4l2_buffer *v4l2_buf,
- struct uvc_buffer *buf);
-
-/* Status */
-extern int uvc_status_init(struct uvc_device *dev);
-extern void uvc_status_cleanup(struct uvc_device *dev);
-extern int uvc_status_start(struct uvc_device *dev);
-extern void uvc_status_stop(struct uvc_device *dev);
-extern int uvc_status_suspend(struct uvc_device *dev);
-extern int uvc_status_resume(struct uvc_device *dev);
-
-/* Controls */
-extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops;
-
-extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
- struct v4l2_queryctrl *v4l2_ctrl);
-extern int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
- struct v4l2_querymenu *query_menu);
-
-extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
- const struct uvc_control_mapping *mapping);
-extern int uvc_ctrl_init_device(struct uvc_device *dev);
-extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
-extern int uvc_ctrl_resume_device(struct uvc_device *dev);
-
-extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
-extern int __uvc_ctrl_commit(struct uvc_fh *handle, int rollback,
- const struct v4l2_ext_control *xctrls,
- unsigned int xctrls_count);
-static inline int uvc_ctrl_commit(struct uvc_fh *handle,
- const struct v4l2_ext_control *xctrls,
- unsigned int xctrls_count)
-{
- return __uvc_ctrl_commit(handle, 0, xctrls, xctrls_count);
-}
-static inline int uvc_ctrl_rollback(struct uvc_fh *handle)
-{
- return __uvc_ctrl_commit(handle, 1, NULL, 0);
-}
-
-extern int uvc_ctrl_get(struct uvc_video_chain *chain,
- struct v4l2_ext_control *xctrl);
-extern int uvc_ctrl_set(struct uvc_video_chain *chain,
- struct v4l2_ext_control *xctrl);
-
-extern int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
- struct uvc_xu_control_query *xqry);
-
-/* Utility functions */
-extern void uvc_simplify_fraction(uint32_t *numerator, uint32_t *denominator,
- unsigned int n_terms, unsigned int threshold);
-extern uint32_t uvc_fraction_to_interval(uint32_t numerator,
- uint32_t denominator);
-extern struct usb_host_endpoint *uvc_find_endpoint(
- struct usb_host_interface *alts, __u8 epaddr);
-
-/* Quirks support */
-void uvc_video_decode_isight(struct urb *urb, struct uvc_streaming *stream,
- struct uvc_buffer *buf);
-
-/* debugfs and statistics */
-int uvc_debugfs_init(void);
-void uvc_debugfs_cleanup(void);
-int uvc_debugfs_init_stream(struct uvc_streaming *stream);
-void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream);
-
-size_t uvc_video_stats_dump(struct uvc_streaming *stream, char *buf,
- size_t size);
-
-#endif