📄 uvc_ctrl.c
字号:
/* * uvcvideo.c -- USB Video Class driver * * Copyright (C) 2005-2006 * Laurent Pinchart (laurent.pinchart@skynet.be) * * 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/version.h>#include <linux/list.h>#include <linux/module.h>#include <linux/usb.h>#include <linux/videodev.h>#include <linux/vmalloc.h>#include <linux/wait.h>#include <asm/atomic.h>#include "uvcvideo.h"#define UVC_CONTROL_SET_CUR (1 << 0)#define UVC_CONTROL_GET_CUR (1 << 1)#define UVC_CONTROL_GET_MIN (1 << 2)#define UVC_CONTROL_GET_MAX (1 << 3)#define UVC_CONTROL_GET_RES (1 << 4)#define UVC_CONTROL_GET_DEF (1 << 5)#define UVC_CONTROL_GET_RANGE (UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_MIN | \ UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | \ UVC_CONTROL_GET_DEF)#define UVC_CTRL_NDATA 2#define UVC_CTRL_DATA_CURRENT 0#define UVC_CTRL_DATA_BACKUP 1/* ------------------------------------------------------------------------ * Control, formats, ... */static struct uvc_control_info uvc_ctrls[] = { { .entity = UVC_GUID_UVC_PROCESSING, .selector = PU_BRIGHTNESS_CONTROL, .index = 0, .size = 2, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE, }, { .entity = UVC_GUID_UVC_PROCESSING, .selector = PU_CONTRAST_CONTROL, .index = 1, .size = 2, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE, }, { .entity = UVC_GUID_UVC_PROCESSING, .selector = PU_HUE_CONTROL, .index = 2, .size = 2, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE, }, { .entity = UVC_GUID_UVC_PROCESSING, .selector = PU_SATURATION_CONTROL, .index = 3, .size = 2, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE, }, { .entity = UVC_GUID_UVC_PROCESSING, .selector = PU_SHARPNESS_CONTROL, .index = 4, .size = 2, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE, }, { .entity = UVC_GUID_UVC_PROCESSING, .selector = PU_GAMMA_CONTROL, .index = 5, .size = 2, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE, }, { .entity = UVC_GUID_UVC_PROCESSING, .selector = PU_BACKLIGHT_COMPENSATION_CONTROL, .index = 8, .size = 2, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE, }, { .entity = UVC_GUID_UVC_PROCESSING, .selector = PU_GAIN_CONTROL, .index = 9, .size = 2, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE, }, { .entity = UVC_GUID_UVC_PROCESSING, .selector = PU_POWER_LINE_FREQUENCY_CONTROL, .index = 10, .size = 1, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE, }, { .entity = UVC_GUID_UVC_PROCESSING, .selector = PU_HUE_AUTO_CONTROL, .index = 11, .size = 1, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_DEF, }, { .entity = UVC_GUID_LOGITECH_MOTOR, .selector = LXU_MOTOR_PANTILT_RELATIVE_CONTROL, .index = 0, .size = 4, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_DEF, }, { .entity = UVC_GUID_LOGITECH_MOTOR, .selector = LXU_MOTOR_PANTILT_RESET_CONTROL, .index = 1, .size = 1, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF, }, { .entity = UVC_GUID_UVC_CAMERA, .selector = CT_AE_MODE_CONTROL, .index = 1, .size = 1, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_DEF | UVC_CONTROL_GET_RES, }, { .entity = UVC_GUID_UVC_CAMERA, .selector = CT_EXPOSURE_TIME_ABSOLUTE_CONTROL, .index = 3, .size = 4, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF, }, { .entity = UVC_GUID_UVC_PROCESSING, .selector = PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, .index = 12, .size = 1, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR | UVC_CONTROL_GET_DEF, }, { .entity = UVC_GUID_UVC_PROCESSING, .selector = PU_WHITE_BALANCE_TEMPERATURE_CONTROL, .index = 6, .size = 2, .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX | UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF, }};static struct uvc_menu_info power_line_frequency_controls[] = { { 0, "Disabled" }, { 1, "50 Hz" }, { 2, "60 Hz" },};static struct uvc_control_mapping uvc_ctrl_mappings[] = { { .id = V4L2_CID_BRIGHTNESS, .name = "Brightness", .entity = UVC_GUID_UVC_PROCESSING, .selector = PU_BRIGHTNESS_CONTROL, .size = 16, .offset = 0, .v4l2_type = V4L2_CTRL_TYPE_INTEGER, .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, }, { .id = V4L2_CID_CONTRAST, .name = "Contrast", .entity = UVC_GUID_UVC_PROCESSING, .selector = 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 = PU_HUE_CONTROL, .size = 16, .offset = 0, .v4l2_type = V4L2_CTRL_TYPE_INTEGER, .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, }, { .id = V4L2_CID_SATURATION, .name = "Saturation", .entity = UVC_GUID_UVC_PROCESSING, .selector = 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 = 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 = 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 = 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 = 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 = 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 = PU_HUE_AUTO_CONTROL, .size = 1, .offset = 0, .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN, .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN, }, { .id = V4L2_CID_PAN_RELATIVE, .name = "Pan (relative)", .entity = UVC_GUID_LOGITECH_MOTOR, .selector = LXU_MOTOR_PANTILT_RELATIVE_CONTROL, .size = 16, .offset = 0, .v4l2_type = V4L2_CTRL_TYPE_INTEGER, .data_type = UVC_CTRL_DATA_TYPE_SIGNED, }, { .id = V4L2_CID_TILT_RELATIVE, .name = "Tilt (relative)", .entity = UVC_GUID_LOGITECH_MOTOR, .selector = LXU_MOTOR_PANTILT_RELATIVE_CONTROL, .size = 16, .offset = 16, .v4l2_type = V4L2_CTRL_TYPE_INTEGER, .data_type = UVC_CTRL_DATA_TYPE_SIGNED, }, { .id = V4L2_CID_PANTILT_RESET, .name = "Pan/Tilt (reset)", .entity = UVC_GUID_LOGITECH_MOTOR, .selector = LXU_MOTOR_PANTILT_RESET_CONTROL, .size = 2, .offset = 0, .v4l2_type = V4L2_CTRL_TYPE_INTEGER, .data_type = UVC_CTRL_DATA_TYPE_ENUM, }, { .id = V4L2_CID_EXPOSURE_AUTO, .name = "Exposure, Auto", .entity = UVC_GUID_UVC_CAMERA, .selector = CT_AE_MODE_CONTROL, .size = 4, .offset = 0, .v4l2_type = V4L2_CTRL_TYPE_INTEGER, .data_type = UVC_CTRL_DATA_TYPE_BITMASK, }, { .id = V4L2_CID_EXPOSURE_ABSOLUTE, .name = "Exposure (Absolute)", .entity = UVC_GUID_UVC_CAMERA, .selector = CT_EXPOSURE_TIME_ABSOLUTE_CONTROL, .size = 32, .offset = 0, .v4l2_type = V4L2_CTRL_TYPE_INTEGER, .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, }, { .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE_AUTO, .name = "White Balance Temperature, Auto", .entity = UVC_GUID_UVC_PROCESSING, .selector = PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL, .size = 1, .offset = 0, .v4l2_type = V4L2_CTRL_TYPE_BOOLEAN, .data_type = UVC_CTRL_DATA_TYPE_BOOLEAN, }, { .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE, .name = "White Balance Temperature", .entity = UVC_GUID_UVC_PROCESSING, .selector = PU_WHITE_BALANCE_TEMPERATURE_CONTROL, .size = 16, .offset = 0, .v4l2_type = V4L2_CTRL_TYPE_INTEGER, .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED, }};/* ------------------------------------------------------------------------ * Utility functions */static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id){ return ctrl->data + id * ctrl->info->size;}static inline int uvc_get_bit(const __u8 *data, int bit){ return (data[bit >> 3] >> (bit & 7)) & 1;}/* 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(const __u8 *data, struct uvc_control_mapping *mapping){ int bits = mapping->size; int offset = mapping->offset; __s32 value = 0; __u8 mask; data += offset / 8; offset &= 7; mask = ((1 << 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(__s32 value, __u8 *data, struct uvc_control_mapping *mapping){ int bits = mapping->size; int offset = mapping->offset; __u8 mask; data += offset / 8; offset &= 7; for (; bits > 0; data++) { mask = ((1 << 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 int uvc_entity_match_guid(struct uvc_entity *entity, __u8 guid[16]){ switch (entity->type) { case ITT_CAMERA: return memcmp(uvc_camera_guid, guid, 16) == 0; case VC_PROCESSING_UNIT: return memcmp(uvc_processing_guid, guid, 16) == 0; case VC_EXTENSION_UNIT: return memcmp(entity->extension.guidExtensionCode, guid, 16) == 0; default: return 0; }}/* ------------------------------------------------------------------------ * UVC Controls */static struct uvc_control *__uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id, struct uvc_control_mapping **mapping){ struct uvc_control *ctrl; struct uvc_control_mapping *map; unsigned int i; for (i = 0; i < entity->ncontrols; ++i) { ctrl = &entity->controls[i]; if (ctrl->info == NULL) continue; list_for_each_entry(map, &ctrl->info->mappings, list) { if (map->id == v4l2_id) { *mapping = map; return ctrl; } } } return NULL;}struct uvc_control *uvc_find_control(struct uvc_video_device *video,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -