?? pwc-ctrl.c
字號:
/* Driver for Philips webcam Functions that send various control messages to the webcam, including video modes. (C) 1999-2003 Nemosoft Unv. (C) 2004-2006 Luc Saillard (luc@saillard.org) NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx driver and thus may have bugs that are not present in the original version. Please send bug reports and support requests to <luc@saillard.org>. NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx driver and thus may have bugs that are not present in the original version. Please send bug reports and support requests to <luc@saillard.org>. The decompression routines have been implemented by reverse-engineering the Nemosoft binary pwcx module. Caveat emptor. 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 program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*//* Changes 2001/08/03 Alvarado Added methods for changing white balance and red/green gains *//* Control functions for the cam; brightness, contrast, video mode, etc. */#ifdef __KERNEL__#include <asm/uaccess.h> #endif#include <asm/errno.h>#include <linux/version.h> #include "pwc.h"#include "pwc-ioctl.h"#include "pwc-uncompress.h"#include "pwc-kiara.h"#include "pwc-timon.h"#include "pwc-dec1.h"#include "pwc-dec23.h"/* Request types: video */#define SET_LUM_CTL 0x01#define GET_LUM_CTL 0x02#define SET_CHROM_CTL 0x03#define GET_CHROM_CTL 0x04#define SET_STATUS_CTL 0x05#define GET_STATUS_CTL 0x06#define SET_EP_STREAM_CTL 0x07#define GET_EP_STREAM_CTL 0x08#define GET_XX_CTL 0x09#define SET_XX_CTL 0x0A#define GET_XY_CTL 0x0B#define SET_XY_CTL 0x0C#define SET_MPT_CTL 0x0D#define GET_MPT_CTL 0x0E/* Selectors for the Luminance controls [GS]ET_LUM_CTL */#define AGC_MODE_FORMATTER 0x2000#define PRESET_AGC_FORMATTER 0x2100#define SHUTTER_MODE_FORMATTER 0x2200#define PRESET_SHUTTER_FORMATTER 0x2300#define PRESET_CONTOUR_FORMATTER 0x2400#define AUTO_CONTOUR_FORMATTER 0x2500#define BACK_LIGHT_COMPENSATION_FORMATTER 0x2600#define CONTRAST_FORMATTER 0x2700#define DYNAMIC_NOISE_CONTROL_FORMATTER 0x2800#define FLICKERLESS_MODE_FORMATTER 0x2900#define AE_CONTROL_SPEED 0x2A00#define BRIGHTNESS_FORMATTER 0x2B00#define GAMMA_FORMATTER 0x2C00/* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */#define WB_MODE_FORMATTER 0x1000#define AWB_CONTROL_SPEED_FORMATTER 0x1100#define AWB_CONTROL_DELAY_FORMATTER 0x1200#define PRESET_MANUAL_RED_GAIN_FORMATTER 0x1300#define PRESET_MANUAL_BLUE_GAIN_FORMATTER 0x1400#define COLOUR_MODE_FORMATTER 0x1500#define SATURATION_MODE_FORMATTER1 0x1600#define SATURATION_MODE_FORMATTER2 0x1700/* Selectors for the Status controls [GS]ET_STATUS_CTL */#define SAVE_USER_DEFAULTS_FORMATTER 0x0200#define RESTORE_USER_DEFAULTS_FORMATTER 0x0300#define RESTORE_FACTORY_DEFAULTS_FORMATTER 0x0400#define READ_AGC_FORMATTER 0x0500#define READ_SHUTTER_FORMATTER 0x0600#define READ_RED_GAIN_FORMATTER 0x0700#define READ_BLUE_GAIN_FORMATTER 0x0800#define GET_STATUS_B00 0x0B00#define SENSOR_TYPE_FORMATTER1 0x0C00#define GET_STATUS_3000 0x3000#define READ_RAW_Y_MEAN_FORMATTER 0x3100#define SET_POWER_SAVE_MODE_FORMATTER 0x3200#define MIRROR_IMAGE_FORMATTER 0x3300#define LED_FORMATTER 0x3400#define LOWLIGHT 0x3500#define GET_STATUS_3600 0x3600#define SENSOR_TYPE_FORMATTER2 0x3700#define GET_STATUS_3800 0x3800#define GET_STATUS_4000 0x4000#define GET_STATUS_4100 0x4100 /* Get */#define CTL_STATUS_4200 0x4200 /* [GS] 1 *//* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */#define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100/* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */#define PT_RELATIVE_CONTROL_FORMATTER 0x01#define PT_RESET_CONTROL_FORMATTER 0x02#define PT_STATUS_FORMATTER 0x03static const char *size2name[PSZ_MAX] ={ "subQCIF", "QSIF", "QCIF", "SIF", "CIF", "VGA",}; /********//* Entries for the Nala (645/646) camera; the Nala doesn't have compression preferences, so you either get compressed or non-compressed streams. An alternate value of 0 means this mode is not available at all. */struct Nala_table_entry { char alternate; /* USB alternate setting */ int compressed; /* Compressed yes/no */ unsigned char mode[3]; /* precomputed mode table */};static struct Nala_table_entry Nala_table[PSZ_MAX][8] ={#include "pwc-nala.h"};static void pwc_set_image_buffer_size(struct pwc_device *pdev);/****************************************************************************/#define SendControlMsg(request, value, buflen) \ usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \ request, \ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ value, \ pdev->vcinterface, \ &buf, buflen, 500)#define RecvControlMsg(request, value, buflen) \ usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \ request, \ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ value, \ pdev->vcinterface, \ &buf, buflen, 500)static int send_video_command(struct usb_device *udev, int index, void *buf, int buflen){ return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), SET_EP_STREAM_CTL, USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, VIDEO_OUTPUT_CONTROL_FORMATTER, index, buf, buflen, 1000);}static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames){ unsigned char buf[3]; int ret, fps; struct Nala_table_entry *pEntry; int frames2frames[31] = { /* closest match of framerate */ 0, 0, 0, 0, 4, /* 0-4 */ 5, 5, 7, 7, 10, /* 5-9 */ 10, 10, 12, 12, 15, /* 10-14 */ 15, 15, 15, 20, 20, /* 15-19 */ 20, 20, 20, 24, 24, /* 20-24 */ 24, 24, 24, 24, 24, /* 25-29 */ 24 /* 30 */ }; int frames2table[31] = { 0, 0, 0, 0, 0, /* 0-4 */ 1, 1, 1, 2, 2, /* 5-9 */ 3, 3, 4, 4, 4, /* 10-14 */ 5, 5, 5, 5, 5, /* 15-19 */ 6, 6, 6, 6, 7, /* 20-24 */ 7, 7, 7, 7, 7, /* 25-29 */ 7 /* 30 */ }; if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25) return -EINVAL; frames = frames2frames[frames]; fps = frames2table[frames]; pEntry = &Nala_table[size][fps]; if (pEntry->alternate == 0) return -EINVAL; memcpy(buf, pEntry->mode, 3); ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3); if (ret < 0) { PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret); return ret; } if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW) pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); pdev->cmd_len = 3; memcpy(pdev->cmd_buf, buf, 3); /* Set various parameters */ pdev->vframes = frames; pdev->vsize = size; pdev->valternate = pEntry->alternate; pdev->image = pwc_image_sizes[size]; pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2; if (pEntry->compressed) { if (pdev->release < 5) { /* 4 fold compression */ pdev->vbandlength = 528; pdev->frame_size /= 4; } else { pdev->vbandlength = 704; pdev->frame_size /= 3; } } else pdev->vbandlength = 0; return 0;}static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot){ unsigned char buf[13]; const struct Timon_table_entry *pChoose; int ret, fps; if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) return -EINVAL; if (size == PSZ_VGA && frames > 15) return -EINVAL; fps = (frames / 5) - 1; /* Find a supported framerate with progressively higher compression ratios if the preferred ratio is not available. */ pChoose = NULL; while (compression <= 3) { pChoose = &Timon_table[size][fps][compression]; if (pChoose->alternate != 0) break; compression++; } if (pChoose == NULL || pChoose->alternate == 0) return -ENOENT; /* Not supported. */ memcpy(buf, pChoose->mode, 13); if (snapshot) buf[0] |= 0x80; ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 13); if (ret < 0) return ret; if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW) pwc_dec23_init(pdev, pdev->type, buf); pdev->cmd_len = 13; memcpy(pdev->cmd_buf, buf, 13); /* Set various parameters */ pdev->vframes = frames; pdev->vsize = size; pdev->vsnapshot = snapshot; pdev->valternate = pChoose->alternate; pdev->image = pwc_image_sizes[size]; pdev->vbandlength = pChoose->bandlength; if (pChoose->bandlength > 0) pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4; else pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; return 0;}static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot){ const struct Kiara_table_entry *pChoose = NULL; int fps, ret; unsigned char buf[12]; struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}; if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) return -EINVAL; if (size == PSZ_VGA && frames > 15) return -EINVAL; fps = (frames / 5) - 1; /* special case: VGA @ 5 fps and snapshot is raw bayer mode */ if (size == PSZ_VGA && frames == 5 && snapshot && pdev->vpalette == VIDEO_PALETTE_RAW) { /* Only available in case the raw palette is selected or we have the decompressor available. This mode is only available in compressed form */ PWC_DEBUG_SIZE("Choosing VGA/5 BAYER mode.\n"); pChoose = &RawEntry; } else { /* Find a supported framerate with progressively higher compression ratios if the preferred ratio is not available. Skip this step when using RAW modes. */ snapshot = 0; while (compression <= 3) { pChoose = &Kiara_table[size][fps][compression]; if (pChoose->alternate != 0) break; compression++; } } if (pChoose == NULL || pChoose->alternate == 0) return -ENOENT; /* Not supported. */ PWC_TRACE("Using alternate setting %d.\n", pChoose->alternate); /* usb_control_msg won't take staticly allocated arrays as argument?? */ memcpy(buf, pChoose->mode, 12); if (snapshot) buf[0] |= 0x80; /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ ret = send_video_command(pdev->udev, 4 /* pdev->vendpoint */, buf, 12); if (ret < 0) return ret; if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW) pwc_dec23_init(pdev, pdev->type, buf); pdev->cmd_len = 12; memcpy(pdev->cmd_buf, buf, 12); /* All set and go */ pdev->vframes = frames; pdev->vsize = size; pdev->vsnapshot = snapshot; pdev->valternate = pChoose->alternate; pdev->image = pwc_image_sizes[size]; pdev->vbandlength = pChoose->bandlength; if (pdev->vbandlength > 0) pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4; else pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vsnapshot=%d, vbandlength=%d\n", pdev->frame_size,pdev->vframes,pdev->vsize,pdev->vsnapshot,pdev->vbandlength); return 0;}/** @pdev: device structure @width: viewport width @height: viewport height @frame: framerate, in fps @compression: preferred compression ratio @snapshot: snapshot mode or streaming */int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot){ int ret, size; PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette); size = pwc_decode_size(pdev, width, height); if (size < 0) { PWC_DEBUG_MODULE("Could not find suitable size.\n"); return -ERANGE; } PWC_TRACE("decode_size = %d.\n", size); if (DEVICE_USE_CODEC1(pdev->type)) { ret = set_video_mode_Nala(pdev, size, frames); } else if (DEVICE_USE_CODEC3(pdev->type)) { ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot); } else { ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot); } if (ret < 0) { PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); return ret; } pdev->view.x = width; pdev->view.y = height; pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; pwc_set_image_buffer_size(pdev); PWC_DEBUG_SIZE("Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y); return 0;}#define BLACK_Y 0#define BLACK_U 128#define BLACK_V 128static void pwc_set_image_buffer_size(struct pwc_device *pdev){ int i, factor = 0; /* for PALETTE_YUV420P */ switch(pdev->vpalette) { case VIDEO_PALETTE_YUV420P: factor = 6; break; case VIDEO_PALETTE_RAW: factor = 6; /* can be uncompressed YUV420P */ break; } /* Set sizes in bytes */ pdev->image.size = pdev->image.x * pdev->image.y * factor / 4; pdev->view.size = pdev->view.x * pdev->view.y * factor / 4; /* Align offset, or you'll get some very weird results in YUV420 mode... x must be multiple of 4 (to get the Y's in place), and y even (or you'll mixup U & V). This is less of a problem for YUV420P. */ pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC; pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; /* Fill buffers with black colors */ for (i = 0; i < pwc_mbufs; i++) { unsigned char *p = pdev->image_data + pdev->images[i].offset; memset(p, BLACK_Y, pdev->view.x * pdev->view.y); p += pdev->view.x * pdev->view.y; memset(p, BLACK_U, pdev->view.x * pdev->view.y/4); p += pdev->view.x * pdev->view.y/4; memset(p, BLACK_V, pdev->view.x * pdev->view.y/4); }}/* BRIGHTNESS */int pwc_get_brightness(struct pwc_device *pdev){ char buf; int ret; ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1); if (ret < 0) return ret; return buf;}int pwc_set_brightness(struct pwc_device *pdev, int value){ char buf; if (value < 0) value = 0; if (value > 0xffff) value = 0xffff; buf = (value >> 9) & 0x7f; return SendControlMsg(SET_LUM_CTL, BRIGHTNESS_FORMATTER, 1);}/* CONTRAST */int pwc_get_contrast(struct pwc_device *pdev){ char buf; int ret; ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1); if (ret < 0) return ret; return buf;}int pwc_set_contrast(struct pwc_device *pdev, int value){ char buf; if (value < 0) value = 0; if (value > 0xffff) value = 0xffff; buf = (value >> 10) & 0x3f; return SendControlMsg(SET_LUM_CTL, CONTRAST_FORMATTER, 1);}/* GAMMA */int pwc_get_gamma(struct pwc_device *pdev){ char buf; int ret; ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1); if (ret < 0) return ret; return buf;}int pwc_set_gamma(struct pwc_device *pdev, int value){ char buf; if (value < 0) value = 0; if (value > 0xffff) value = 0xffff; buf = (value >> 11) & 0x1f; return SendControlMsg(SET_LUM_CTL, GAMMA_FORMATTER, 1);}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -