154e8bc5dSHans de Goede /* 254e8bc5dSHans de Goede * cpia CPiA (1) gspca driver 354e8bc5dSHans de Goede * 476fafe78SHans de Goede * Copyright (C) 2010-2011 Hans de Goede <hdegoede@redhat.com> 554e8bc5dSHans de Goede * 654e8bc5dSHans de Goede * This module is adapted from the in kernel v4l1 cpia driver which is : 754e8bc5dSHans de Goede * 854e8bc5dSHans de Goede * (C) Copyright 1999-2000 Peter Pregler 954e8bc5dSHans de Goede * (C) Copyright 1999-2000 Scott J. Bertin 1054e8bc5dSHans de Goede * (C) Copyright 1999-2000 Johannes Erdfelt <johannes@erdfelt.com> 1154e8bc5dSHans de Goede * (C) Copyright 2000 STMicroelectronics 1254e8bc5dSHans de Goede * 1354e8bc5dSHans de Goede * This program is free software; you can redistribute it and/or modify 1454e8bc5dSHans de Goede * it under the terms of the GNU General Public License as published by 1554e8bc5dSHans de Goede * the Free Software Foundation; either version 2 of the License, or 1654e8bc5dSHans de Goede * (at your option) any later version. 1754e8bc5dSHans de Goede * 1854e8bc5dSHans de Goede * This program is distributed in the hope that it will be useful, 1954e8bc5dSHans de Goede * but WITHOUT ANY WARRANTY; without even the implied warranty of 2054e8bc5dSHans de Goede * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2154e8bc5dSHans de Goede * GNU General Public License for more details. 2254e8bc5dSHans de Goede * 2354e8bc5dSHans de Goede * You should have received a copy of the GNU General Public License 2454e8bc5dSHans de Goede * along with this program; if not, write to the Free Software 2554e8bc5dSHans de Goede * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 2654e8bc5dSHans de Goede * 2754e8bc5dSHans de Goede */ 2854e8bc5dSHans de Goede 29133a9fe9SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 30133a9fe9SJoe Perches 3154e8bc5dSHans de Goede #define MODULE_NAME "cpia1" 3254e8bc5dSHans de Goede 33c2f644aeSHans de Goede #include <linux/input.h> 3454e8bc5dSHans de Goede #include "gspca.h" 3554e8bc5dSHans de Goede 361fddcf0eSHans de Goede MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 3754e8bc5dSHans de Goede MODULE_DESCRIPTION("Vision CPiA"); 3854e8bc5dSHans de Goede MODULE_LICENSE("GPL"); 3954e8bc5dSHans de Goede 4054e8bc5dSHans de Goede /* constant value's */ 4154e8bc5dSHans de Goede #define MAGIC_0 0x19 4254e8bc5dSHans de Goede #define MAGIC_1 0x68 431d00d6c1SJean-François Moine #define DATA_IN 0xc0 4454e8bc5dSHans de Goede #define DATA_OUT 0x40 4554e8bc5dSHans de Goede #define VIDEOSIZE_QCIF 0 /* 176x144 */ 4654e8bc5dSHans de Goede #define VIDEOSIZE_CIF 1 /* 352x288 */ 4754e8bc5dSHans de Goede #define SUBSAMPLE_420 0 4854e8bc5dSHans de Goede #define SUBSAMPLE_422 1 4954e8bc5dSHans de Goede #define YUVORDER_YUYV 0 5054e8bc5dSHans de Goede #define YUVORDER_UYVY 1 5154e8bc5dSHans de Goede #define NOT_COMPRESSED 0 5254e8bc5dSHans de Goede #define COMPRESSED 1 5354e8bc5dSHans de Goede #define NO_DECIMATION 0 5454e8bc5dSHans de Goede #define DECIMATION_ENAB 1 5554e8bc5dSHans de Goede #define EOI 0xff /* End Of Image */ 5654e8bc5dSHans de Goede #define EOL 0xfd /* End Of Line */ 5754e8bc5dSHans de Goede #define FRAME_HEADER_SIZE 64 5854e8bc5dSHans de Goede 5954e8bc5dSHans de Goede /* Image grab modes */ 6054e8bc5dSHans de Goede #define CPIA_GRAB_SINGLE 0 6154e8bc5dSHans de Goede #define CPIA_GRAB_CONTINEOUS 1 6254e8bc5dSHans de Goede 6354e8bc5dSHans de Goede /* Compression parameters */ 6454e8bc5dSHans de Goede #define CPIA_COMPRESSION_NONE 0 6554e8bc5dSHans de Goede #define CPIA_COMPRESSION_AUTO 1 6654e8bc5dSHans de Goede #define CPIA_COMPRESSION_MANUAL 2 6754e8bc5dSHans de Goede #define CPIA_COMPRESSION_TARGET_QUALITY 0 6854e8bc5dSHans de Goede #define CPIA_COMPRESSION_TARGET_FRAMERATE 1 6954e8bc5dSHans de Goede 7054e8bc5dSHans de Goede /* Return offsets for GetCameraState */ 7154e8bc5dSHans de Goede #define SYSTEMSTATE 0 7254e8bc5dSHans de Goede #define GRABSTATE 1 7354e8bc5dSHans de Goede #define STREAMSTATE 2 7454e8bc5dSHans de Goede #define FATALERROR 3 7554e8bc5dSHans de Goede #define CMDERROR 4 7654e8bc5dSHans de Goede #define DEBUGFLAGS 5 7754e8bc5dSHans de Goede #define VPSTATUS 6 7854e8bc5dSHans de Goede #define ERRORCODE 7 7954e8bc5dSHans de Goede 8054e8bc5dSHans de Goede /* SystemState */ 8154e8bc5dSHans de Goede #define UNINITIALISED_STATE 0 8254e8bc5dSHans de Goede #define PASS_THROUGH_STATE 1 8354e8bc5dSHans de Goede #define LO_POWER_STATE 2 8454e8bc5dSHans de Goede #define HI_POWER_STATE 3 8554e8bc5dSHans de Goede #define WARM_BOOT_STATE 4 8654e8bc5dSHans de Goede 8754e8bc5dSHans de Goede /* GrabState */ 8854e8bc5dSHans de Goede #define GRAB_IDLE 0 8954e8bc5dSHans de Goede #define GRAB_ACTIVE 1 9054e8bc5dSHans de Goede #define GRAB_DONE 2 9154e8bc5dSHans de Goede 9254e8bc5dSHans de Goede /* StreamState */ 9354e8bc5dSHans de Goede #define STREAM_NOT_READY 0 9454e8bc5dSHans de Goede #define STREAM_READY 1 9554e8bc5dSHans de Goede #define STREAM_OPEN 2 9654e8bc5dSHans de Goede #define STREAM_PAUSED 3 9754e8bc5dSHans de Goede #define STREAM_FINISHED 4 9854e8bc5dSHans de Goede 9954e8bc5dSHans de Goede /* Fatal Error, CmdError, and DebugFlags */ 10054e8bc5dSHans de Goede #define CPIA_FLAG 1 10154e8bc5dSHans de Goede #define SYSTEM_FLAG 2 10254e8bc5dSHans de Goede #define INT_CTRL_FLAG 4 10354e8bc5dSHans de Goede #define PROCESS_FLAG 8 10454e8bc5dSHans de Goede #define COM_FLAG 16 10554e8bc5dSHans de Goede #define VP_CTRL_FLAG 32 10654e8bc5dSHans de Goede #define CAPTURE_FLAG 64 10754e8bc5dSHans de Goede #define DEBUG_FLAG 128 10854e8bc5dSHans de Goede 10954e8bc5dSHans de Goede /* VPStatus */ 11054e8bc5dSHans de Goede #define VP_STATE_OK 0x00 11154e8bc5dSHans de Goede 11254e8bc5dSHans de Goede #define VP_STATE_FAILED_VIDEOINIT 0x01 11354e8bc5dSHans de Goede #define VP_STATE_FAILED_AECACBINIT 0x02 11454e8bc5dSHans de Goede #define VP_STATE_AEC_MAX 0x04 11554e8bc5dSHans de Goede #define VP_STATE_ACB_BMAX 0x08 11654e8bc5dSHans de Goede 11754e8bc5dSHans de Goede #define VP_STATE_ACB_RMIN 0x10 11854e8bc5dSHans de Goede #define VP_STATE_ACB_GMIN 0x20 11954e8bc5dSHans de Goede #define VP_STATE_ACB_RMAX 0x40 12054e8bc5dSHans de Goede #define VP_STATE_ACB_GMAX 0x80 12154e8bc5dSHans de Goede 12254e8bc5dSHans de Goede /* default (minimum) compensation values */ 12354e8bc5dSHans de Goede #define COMP_RED 220 12454e8bc5dSHans de Goede #define COMP_GREEN1 214 12554e8bc5dSHans de Goede #define COMP_GREEN2 COMP_GREEN1 12654e8bc5dSHans de Goede #define COMP_BLUE 230 12754e8bc5dSHans de Goede 12854e8bc5dSHans de Goede /* exposure status */ 12954e8bc5dSHans de Goede #define EXPOSURE_VERY_LIGHT 0 13054e8bc5dSHans de Goede #define EXPOSURE_LIGHT 1 13154e8bc5dSHans de Goede #define EXPOSURE_NORMAL 2 13254e8bc5dSHans de Goede #define EXPOSURE_DARK 3 13354e8bc5dSHans de Goede #define EXPOSURE_VERY_DARK 4 13454e8bc5dSHans de Goede 13554e8bc5dSHans de Goede #define CPIA_MODULE_CPIA (0 << 5) 13654e8bc5dSHans de Goede #define CPIA_MODULE_SYSTEM (1 << 5) 13754e8bc5dSHans de Goede #define CPIA_MODULE_VP_CTRL (5 << 5) 13854e8bc5dSHans de Goede #define CPIA_MODULE_CAPTURE (6 << 5) 13954e8bc5dSHans de Goede #define CPIA_MODULE_DEBUG (7 << 5) 14054e8bc5dSHans de Goede 14154e8bc5dSHans de Goede #define INPUT (DATA_IN << 8) 14254e8bc5dSHans de Goede #define OUTPUT (DATA_OUT << 8) 14354e8bc5dSHans de Goede 14454e8bc5dSHans de Goede #define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1) 14554e8bc5dSHans de Goede #define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2) 14654e8bc5dSHans de Goede #define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3) 14754e8bc5dSHans de Goede #define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4) 14854e8bc5dSHans de Goede #define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5) 14954e8bc5dSHans de Goede #define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7) 15054e8bc5dSHans de Goede #define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8) 15154e8bc5dSHans de Goede #define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10) 15254e8bc5dSHans de Goede 15354e8bc5dSHans de Goede #define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1) 15454e8bc5dSHans de Goede #define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2) 15554e8bc5dSHans de Goede #define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3) 15654e8bc5dSHans de Goede #define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4) 15754e8bc5dSHans de Goede #define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5) 15854e8bc5dSHans de Goede #define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6) 15954e8bc5dSHans de Goede #define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7) 16054e8bc5dSHans de Goede #define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8) 16154e8bc5dSHans de Goede #define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9) 16254e8bc5dSHans de Goede #define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10) 16354e8bc5dSHans de Goede #define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11) 16454e8bc5dSHans de Goede #define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12) 16554e8bc5dSHans de Goede #define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13) 16654e8bc5dSHans de Goede 16754e8bc5dSHans de Goede #define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1) 16854e8bc5dSHans de Goede #define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2) 16954e8bc5dSHans de Goede #define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3) 17054e8bc5dSHans de Goede #define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4) 17154e8bc5dSHans de Goede #define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6) 17254e8bc5dSHans de Goede #define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7) 17354e8bc5dSHans de Goede #define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8) 17454e8bc5dSHans de Goede #define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9) 17554e8bc5dSHans de Goede #define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10) 17654e8bc5dSHans de Goede #define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11) 17754e8bc5dSHans de Goede #define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16) 17854e8bc5dSHans de Goede #define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17) 17954e8bc5dSHans de Goede #define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18) 18054e8bc5dSHans de Goede #define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19) 18154e8bc5dSHans de Goede #define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25) 18254e8bc5dSHans de Goede #define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30) 18354e8bc5dSHans de Goede #define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31) 18454e8bc5dSHans de Goede 18554e8bc5dSHans de Goede #define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1) 18654e8bc5dSHans de Goede #define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2) 18754e8bc5dSHans de Goede #define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3) 18854e8bc5dSHans de Goede #define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4) 18954e8bc5dSHans de Goede #define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5) 19054e8bc5dSHans de Goede #define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6) 19154e8bc5dSHans de Goede #define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7) 19254e8bc5dSHans de Goede #define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8) 19354e8bc5dSHans de Goede #define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9) 19454e8bc5dSHans de Goede #define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10) 19554e8bc5dSHans de Goede #define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11) 19654e8bc5dSHans de Goede #define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12) 19754e8bc5dSHans de Goede #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13) 19854e8bc5dSHans de Goede #define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14) 19954e8bc5dSHans de Goede #define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15) 20054e8bc5dSHans de Goede 20154e8bc5dSHans de Goede #define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1) 20254e8bc5dSHans de Goede #define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4) 20354e8bc5dSHans de Goede #define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5) 20454e8bc5dSHans de Goede #define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6) 20554e8bc5dSHans de Goede #define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8) 20654e8bc5dSHans de Goede #define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9) 20754e8bc5dSHans de Goede #define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10) 20854e8bc5dSHans de Goede #define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11) 20954e8bc5dSHans de Goede 21054e8bc5dSHans de Goede #define ROUND_UP_EXP_FOR_FLICKER 15 21154e8bc5dSHans de Goede 21254e8bc5dSHans de Goede /* Constants for automatic frame rate adjustment */ 21354e8bc5dSHans de Goede #define MAX_EXP 302 21454e8bc5dSHans de Goede #define MAX_EXP_102 255 21554e8bc5dSHans de Goede #define LOW_EXP 140 21654e8bc5dSHans de Goede #define VERY_LOW_EXP 70 21754e8bc5dSHans de Goede #define TC 94 21854e8bc5dSHans de Goede #define EXP_ACC_DARK 50 21954e8bc5dSHans de Goede #define EXP_ACC_LIGHT 90 22054e8bc5dSHans de Goede #define HIGH_COMP_102 160 22154e8bc5dSHans de Goede #define MAX_COMP 239 22254e8bc5dSHans de Goede #define DARK_TIME 3 22354e8bc5dSHans de Goede #define LIGHT_TIME 3 22454e8bc5dSHans de Goede 22554e8bc5dSHans de Goede #define FIRMWARE_VERSION(x, y) (sd->params.version.firmwareVersion == (x) && \ 22654e8bc5dSHans de Goede sd->params.version.firmwareRevision == (y)) 22754e8bc5dSHans de Goede 2281bfea3e4SHans Verkuil #define CPIA1_CID_COMP_TARGET (V4L2_CTRL_CLASS_USER + 0x1000) 2291bfea3e4SHans Verkuil #define BRIGHTNESS_DEF 50 2301bfea3e4SHans Verkuil #define CONTRAST_DEF 48 2311bfea3e4SHans Verkuil #define SATURATION_DEF 50 2321bfea3e4SHans Verkuil #define FREQ_DEF V4L2_CID_POWER_LINE_FREQUENCY_50HZ 2331bfea3e4SHans Verkuil #define ILLUMINATORS_1_DEF 0 2341bfea3e4SHans Verkuil #define ILLUMINATORS_2_DEF 0 2351bfea3e4SHans Verkuil #define COMP_TARGET_DEF CPIA_COMPRESSION_TARGET_QUALITY 2361bfea3e4SHans Verkuil 23754e8bc5dSHans de Goede /* Developer's Guide Table 5 p 3-34 23854e8bc5dSHans de Goede * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/ 23954e8bc5dSHans de Goede static u8 flicker_jumps[2][2][4] = 24054e8bc5dSHans de Goede { { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } }, 24154e8bc5dSHans de Goede { { 64, 32, 16, 8 }, { 76, 38, 19, 9} } 24254e8bc5dSHans de Goede }; 24354e8bc5dSHans de Goede 24454e8bc5dSHans de Goede struct cam_params { 24554e8bc5dSHans de Goede struct { 24654e8bc5dSHans de Goede u8 firmwareVersion; 24754e8bc5dSHans de Goede u8 firmwareRevision; 24854e8bc5dSHans de Goede u8 vcVersion; 24954e8bc5dSHans de Goede u8 vcRevision; 25054e8bc5dSHans de Goede } version; 25154e8bc5dSHans de Goede struct { 25254e8bc5dSHans de Goede u16 vendor; 25354e8bc5dSHans de Goede u16 product; 25454e8bc5dSHans de Goede u16 deviceRevision; 25554e8bc5dSHans de Goede } pnpID; 25654e8bc5dSHans de Goede struct { 25754e8bc5dSHans de Goede u8 vpVersion; 25854e8bc5dSHans de Goede u8 vpRevision; 25954e8bc5dSHans de Goede u16 cameraHeadID; 26054e8bc5dSHans de Goede } vpVersion; 26154e8bc5dSHans de Goede struct { 26254e8bc5dSHans de Goede u8 systemState; 26354e8bc5dSHans de Goede u8 grabState; 26454e8bc5dSHans de Goede u8 streamState; 26554e8bc5dSHans de Goede u8 fatalError; 26654e8bc5dSHans de Goede u8 cmdError; 26754e8bc5dSHans de Goede u8 debugFlags; 26854e8bc5dSHans de Goede u8 vpStatus; 26954e8bc5dSHans de Goede u8 errorCode; 27054e8bc5dSHans de Goede } status; 27154e8bc5dSHans de Goede struct { 27254e8bc5dSHans de Goede u8 brightness; 27354e8bc5dSHans de Goede u8 contrast; 27454e8bc5dSHans de Goede u8 saturation; 27554e8bc5dSHans de Goede } colourParams; 27654e8bc5dSHans de Goede struct { 27754e8bc5dSHans de Goede u8 gainMode; 27854e8bc5dSHans de Goede u8 expMode; 27954e8bc5dSHans de Goede u8 compMode; 28054e8bc5dSHans de Goede u8 centreWeight; 28154e8bc5dSHans de Goede u8 gain; 28254e8bc5dSHans de Goede u8 fineExp; 28354e8bc5dSHans de Goede u8 coarseExpLo; 28454e8bc5dSHans de Goede u8 coarseExpHi; 28554e8bc5dSHans de Goede u8 redComp; 28654e8bc5dSHans de Goede u8 green1Comp; 28754e8bc5dSHans de Goede u8 green2Comp; 28854e8bc5dSHans de Goede u8 blueComp; 28954e8bc5dSHans de Goede } exposure; 29054e8bc5dSHans de Goede struct { 29154e8bc5dSHans de Goede u8 balanceMode; 29254e8bc5dSHans de Goede u8 redGain; 29354e8bc5dSHans de Goede u8 greenGain; 29454e8bc5dSHans de Goede u8 blueGain; 29554e8bc5dSHans de Goede } colourBalance; 29654e8bc5dSHans de Goede struct { 29754e8bc5dSHans de Goede u8 divisor; 29854e8bc5dSHans de Goede u8 baserate; 29954e8bc5dSHans de Goede } sensorFps; 30054e8bc5dSHans de Goede struct { 30154e8bc5dSHans de Goede u8 gain1; 30254e8bc5dSHans de Goede u8 gain2; 30354e8bc5dSHans de Goede u8 gain4; 30454e8bc5dSHans de Goede u8 gain8; 30554e8bc5dSHans de Goede } apcor; 30654e8bc5dSHans de Goede struct { 30754e8bc5dSHans de Goede u8 disabled; 30854e8bc5dSHans de Goede u8 flickerMode; 30954e8bc5dSHans de Goede u8 coarseJump; 31054e8bc5dSHans de Goede u8 allowableOverExposure; 31154e8bc5dSHans de Goede } flickerControl; 31254e8bc5dSHans de Goede struct { 31354e8bc5dSHans de Goede u8 gain1; 31454e8bc5dSHans de Goede u8 gain2; 31554e8bc5dSHans de Goede u8 gain4; 31654e8bc5dSHans de Goede u8 gain8; 31754e8bc5dSHans de Goede } vlOffset; 31854e8bc5dSHans de Goede struct { 31954e8bc5dSHans de Goede u8 mode; 32054e8bc5dSHans de Goede u8 decimation; 32154e8bc5dSHans de Goede } compression; 32254e8bc5dSHans de Goede struct { 32354e8bc5dSHans de Goede u8 frTargeting; 32454e8bc5dSHans de Goede u8 targetFR; 32554e8bc5dSHans de Goede u8 targetQ; 32654e8bc5dSHans de Goede } compressionTarget; 32754e8bc5dSHans de Goede struct { 32854e8bc5dSHans de Goede u8 yThreshold; 32954e8bc5dSHans de Goede u8 uvThreshold; 33054e8bc5dSHans de Goede } yuvThreshold; 33154e8bc5dSHans de Goede struct { 33254e8bc5dSHans de Goede u8 hysteresis; 33354e8bc5dSHans de Goede u8 threshMax; 33454e8bc5dSHans de Goede u8 smallStep; 33554e8bc5dSHans de Goede u8 largeStep; 33654e8bc5dSHans de Goede u8 decimationHysteresis; 33754e8bc5dSHans de Goede u8 frDiffStepThresh; 33854e8bc5dSHans de Goede u8 qDiffStepThresh; 33954e8bc5dSHans de Goede u8 decimationThreshMod; 34054e8bc5dSHans de Goede } compressionParams; 34154e8bc5dSHans de Goede struct { 34254e8bc5dSHans de Goede u8 videoSize; /* CIF/QCIF */ 34354e8bc5dSHans de Goede u8 subSample; 34454e8bc5dSHans de Goede u8 yuvOrder; 34554e8bc5dSHans de Goede } format; 34654e8bc5dSHans de Goede struct { /* Intel QX3 specific data */ 34754e8bc5dSHans de Goede u8 qx3_detected; /* a QX3 is present */ 34854e8bc5dSHans de Goede u8 toplight; /* top light lit , R/W */ 34954e8bc5dSHans de Goede u8 bottomlight; /* bottom light lit, R/W */ 35054e8bc5dSHans de Goede u8 button; /* snapshot button pressed (R/O) */ 35154e8bc5dSHans de Goede u8 cradled; /* microscope is in cradle (R/O) */ 35254e8bc5dSHans de Goede } qx3; 35354e8bc5dSHans de Goede struct { 35454e8bc5dSHans de Goede u8 colStart; /* skip first 8*colStart pixels */ 35554e8bc5dSHans de Goede u8 colEnd; /* finish at 8*colEnd pixels */ 35654e8bc5dSHans de Goede u8 rowStart; /* skip first 4*rowStart lines */ 35754e8bc5dSHans de Goede u8 rowEnd; /* finish at 4*rowEnd lines */ 35854e8bc5dSHans de Goede } roi; 35954e8bc5dSHans de Goede u8 ecpTiming; 36054e8bc5dSHans de Goede u8 streamStartLine; 36154e8bc5dSHans de Goede }; 36254e8bc5dSHans de Goede 36354e8bc5dSHans de Goede /* specific webcam descriptor */ 36454e8bc5dSHans de Goede struct sd { 36554e8bc5dSHans de Goede struct gspca_dev gspca_dev; /* !! must be the first item */ 36654e8bc5dSHans de Goede struct cam_params params; /* camera settings */ 36754e8bc5dSHans de Goede 36854e8bc5dSHans de Goede atomic_t cam_exposure; 36954e8bc5dSHans de Goede atomic_t fps; 37054e8bc5dSHans de Goede int exposure_count; 37154e8bc5dSHans de Goede u8 exposure_status; 3721bfea3e4SHans Verkuil struct v4l2_ctrl *freq; 37354e8bc5dSHans de Goede u8 mainsFreq; /* 0 = 50hz, 1 = 60hz */ 37454e8bc5dSHans de Goede u8 first_frame; 37554e8bc5dSHans de Goede }; 37654e8bc5dSHans de Goede 37754e8bc5dSHans de Goede static const struct v4l2_pix_format mode[] = { 37854e8bc5dSHans de Goede {160, 120, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE, 37954e8bc5dSHans de Goede /* The sizeimage is trial and error, as with low framerates 38054e8bc5dSHans de Goede the camera will pad out usb frames, making the image 38154e8bc5dSHans de Goede data larger then strictly necessary */ 38254e8bc5dSHans de Goede .bytesperline = 160, 38354e8bc5dSHans de Goede .sizeimage = 65536, 38454e8bc5dSHans de Goede .colorspace = V4L2_COLORSPACE_SRGB, 38554e8bc5dSHans de Goede .priv = 3}, 38654e8bc5dSHans de Goede {176, 144, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE, 38754e8bc5dSHans de Goede .bytesperline = 172, 38854e8bc5dSHans de Goede .sizeimage = 65536, 38954e8bc5dSHans de Goede .colorspace = V4L2_COLORSPACE_SRGB, 39054e8bc5dSHans de Goede .priv = 2}, 39154e8bc5dSHans de Goede {320, 240, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE, 39254e8bc5dSHans de Goede .bytesperline = 320, 39354e8bc5dSHans de Goede .sizeimage = 262144, 39454e8bc5dSHans de Goede .colorspace = V4L2_COLORSPACE_SRGB, 39554e8bc5dSHans de Goede .priv = 1}, 39654e8bc5dSHans de Goede {352, 288, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE, 39754e8bc5dSHans de Goede .bytesperline = 352, 39854e8bc5dSHans de Goede .sizeimage = 262144, 39954e8bc5dSHans de Goede .colorspace = V4L2_COLORSPACE_SRGB, 40054e8bc5dSHans de Goede .priv = 0}, 40154e8bc5dSHans de Goede }; 40254e8bc5dSHans de Goede 40354e8bc5dSHans de Goede /********************************************************************** 40454e8bc5dSHans de Goede * 40554e8bc5dSHans de Goede * General functions 40654e8bc5dSHans de Goede * 40754e8bc5dSHans de Goede **********************************************************************/ 40854e8bc5dSHans de Goede 40954e8bc5dSHans de Goede static int cpia_usb_transferCmd(struct gspca_dev *gspca_dev, u8 *command) 41054e8bc5dSHans de Goede { 41154e8bc5dSHans de Goede u8 requesttype; 41254e8bc5dSHans de Goede unsigned int pipe; 41354e8bc5dSHans de Goede int ret, databytes = command[6] | (command[7] << 8); 41454e8bc5dSHans de Goede /* Sometimes we see spurious EPIPE errors */ 41554e8bc5dSHans de Goede int retries = 3; 41654e8bc5dSHans de Goede 41754e8bc5dSHans de Goede if (command[0] == DATA_IN) { 41854e8bc5dSHans de Goede pipe = usb_rcvctrlpipe(gspca_dev->dev, 0); 41954e8bc5dSHans de Goede requesttype = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE; 42054e8bc5dSHans de Goede } else if (command[0] == DATA_OUT) { 42154e8bc5dSHans de Goede pipe = usb_sndctrlpipe(gspca_dev->dev, 0); 42254e8bc5dSHans de Goede requesttype = USB_TYPE_VENDOR | USB_RECIP_DEVICE; 42354e8bc5dSHans de Goede } else { 42454e8bc5dSHans de Goede PDEBUG(D_ERR, "Unexpected first byte of command: %x", 42554e8bc5dSHans de Goede command[0]); 42654e8bc5dSHans de Goede return -EINVAL; 42754e8bc5dSHans de Goede } 42854e8bc5dSHans de Goede 42954e8bc5dSHans de Goede retry: 43054e8bc5dSHans de Goede ret = usb_control_msg(gspca_dev->dev, pipe, 43154e8bc5dSHans de Goede command[1], 43254e8bc5dSHans de Goede requesttype, 43354e8bc5dSHans de Goede command[2] | (command[3] << 8), 43454e8bc5dSHans de Goede command[4] | (command[5] << 8), 43554e8bc5dSHans de Goede gspca_dev->usb_buf, databytes, 1000); 43654e8bc5dSHans de Goede 43754e8bc5dSHans de Goede if (ret < 0) 438133a9fe9SJoe Perches pr_err("usb_control_msg %02x, error %d\n", command[1], ret); 43954e8bc5dSHans de Goede 44054e8bc5dSHans de Goede if (ret == -EPIPE && retries > 0) { 44154e8bc5dSHans de Goede retries--; 44254e8bc5dSHans de Goede goto retry; 44354e8bc5dSHans de Goede } 44454e8bc5dSHans de Goede 44554e8bc5dSHans de Goede return (ret < 0) ? ret : 0; 44654e8bc5dSHans de Goede } 44754e8bc5dSHans de Goede 44854e8bc5dSHans de Goede /* send an arbitrary command to the camera */ 44954e8bc5dSHans de Goede static int do_command(struct gspca_dev *gspca_dev, u16 command, 45054e8bc5dSHans de Goede u8 a, u8 b, u8 c, u8 d) 45154e8bc5dSHans de Goede { 45254e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 45354e8bc5dSHans de Goede int ret, datasize; 45454e8bc5dSHans de Goede u8 cmd[8]; 45554e8bc5dSHans de Goede 45654e8bc5dSHans de Goede switch (command) { 45754e8bc5dSHans de Goede case CPIA_COMMAND_GetCPIAVersion: 45854e8bc5dSHans de Goede case CPIA_COMMAND_GetPnPID: 45954e8bc5dSHans de Goede case CPIA_COMMAND_GetCameraStatus: 46054e8bc5dSHans de Goede case CPIA_COMMAND_GetVPVersion: 46154e8bc5dSHans de Goede case CPIA_COMMAND_GetColourParams: 46254e8bc5dSHans de Goede case CPIA_COMMAND_GetColourBalance: 46354e8bc5dSHans de Goede case CPIA_COMMAND_GetExposure: 46454e8bc5dSHans de Goede datasize = 8; 46554e8bc5dSHans de Goede break; 46654e8bc5dSHans de Goede case CPIA_COMMAND_ReadMCPorts: 46754e8bc5dSHans de Goede case CPIA_COMMAND_ReadVCRegs: 46854e8bc5dSHans de Goede datasize = 4; 46954e8bc5dSHans de Goede break; 47054e8bc5dSHans de Goede default: 47154e8bc5dSHans de Goede datasize = 0; 47254e8bc5dSHans de Goede break; 47354e8bc5dSHans de Goede } 47454e8bc5dSHans de Goede 47554e8bc5dSHans de Goede cmd[0] = command >> 8; 47654e8bc5dSHans de Goede cmd[1] = command & 0xff; 47754e8bc5dSHans de Goede cmd[2] = a; 47854e8bc5dSHans de Goede cmd[3] = b; 47954e8bc5dSHans de Goede cmd[4] = c; 48054e8bc5dSHans de Goede cmd[5] = d; 48154e8bc5dSHans de Goede cmd[6] = datasize; 48254e8bc5dSHans de Goede cmd[7] = 0; 48354e8bc5dSHans de Goede 48454e8bc5dSHans de Goede ret = cpia_usb_transferCmd(gspca_dev, cmd); 48554e8bc5dSHans de Goede if (ret) 48654e8bc5dSHans de Goede return ret; 48754e8bc5dSHans de Goede 48854e8bc5dSHans de Goede switch (command) { 48954e8bc5dSHans de Goede case CPIA_COMMAND_GetCPIAVersion: 49054e8bc5dSHans de Goede sd->params.version.firmwareVersion = gspca_dev->usb_buf[0]; 49154e8bc5dSHans de Goede sd->params.version.firmwareRevision = gspca_dev->usb_buf[1]; 49254e8bc5dSHans de Goede sd->params.version.vcVersion = gspca_dev->usb_buf[2]; 49354e8bc5dSHans de Goede sd->params.version.vcRevision = gspca_dev->usb_buf[3]; 49454e8bc5dSHans de Goede break; 49554e8bc5dSHans de Goede case CPIA_COMMAND_GetPnPID: 49654e8bc5dSHans de Goede sd->params.pnpID.vendor = 49754e8bc5dSHans de Goede gspca_dev->usb_buf[0] | (gspca_dev->usb_buf[1] << 8); 49854e8bc5dSHans de Goede sd->params.pnpID.product = 49954e8bc5dSHans de Goede gspca_dev->usb_buf[2] | (gspca_dev->usb_buf[3] << 8); 50054e8bc5dSHans de Goede sd->params.pnpID.deviceRevision = 50154e8bc5dSHans de Goede gspca_dev->usb_buf[4] | (gspca_dev->usb_buf[5] << 8); 50254e8bc5dSHans de Goede break; 50354e8bc5dSHans de Goede case CPIA_COMMAND_GetCameraStatus: 50454e8bc5dSHans de Goede sd->params.status.systemState = gspca_dev->usb_buf[0]; 50554e8bc5dSHans de Goede sd->params.status.grabState = gspca_dev->usb_buf[1]; 50654e8bc5dSHans de Goede sd->params.status.streamState = gspca_dev->usb_buf[2]; 50754e8bc5dSHans de Goede sd->params.status.fatalError = gspca_dev->usb_buf[3]; 50854e8bc5dSHans de Goede sd->params.status.cmdError = gspca_dev->usb_buf[4]; 50954e8bc5dSHans de Goede sd->params.status.debugFlags = gspca_dev->usb_buf[5]; 51054e8bc5dSHans de Goede sd->params.status.vpStatus = gspca_dev->usb_buf[6]; 51154e8bc5dSHans de Goede sd->params.status.errorCode = gspca_dev->usb_buf[7]; 51254e8bc5dSHans de Goede break; 51354e8bc5dSHans de Goede case CPIA_COMMAND_GetVPVersion: 51454e8bc5dSHans de Goede sd->params.vpVersion.vpVersion = gspca_dev->usb_buf[0]; 51554e8bc5dSHans de Goede sd->params.vpVersion.vpRevision = gspca_dev->usb_buf[1]; 51654e8bc5dSHans de Goede sd->params.vpVersion.cameraHeadID = 51754e8bc5dSHans de Goede gspca_dev->usb_buf[2] | (gspca_dev->usb_buf[3] << 8); 51854e8bc5dSHans de Goede break; 51954e8bc5dSHans de Goede case CPIA_COMMAND_GetColourParams: 52054e8bc5dSHans de Goede sd->params.colourParams.brightness = gspca_dev->usb_buf[0]; 52154e8bc5dSHans de Goede sd->params.colourParams.contrast = gspca_dev->usb_buf[1]; 52254e8bc5dSHans de Goede sd->params.colourParams.saturation = gspca_dev->usb_buf[2]; 52354e8bc5dSHans de Goede break; 52454e8bc5dSHans de Goede case CPIA_COMMAND_GetColourBalance: 52554e8bc5dSHans de Goede sd->params.colourBalance.redGain = gspca_dev->usb_buf[0]; 52654e8bc5dSHans de Goede sd->params.colourBalance.greenGain = gspca_dev->usb_buf[1]; 52754e8bc5dSHans de Goede sd->params.colourBalance.blueGain = gspca_dev->usb_buf[2]; 52854e8bc5dSHans de Goede break; 52954e8bc5dSHans de Goede case CPIA_COMMAND_GetExposure: 53054e8bc5dSHans de Goede sd->params.exposure.gain = gspca_dev->usb_buf[0]; 53154e8bc5dSHans de Goede sd->params.exposure.fineExp = gspca_dev->usb_buf[1]; 53254e8bc5dSHans de Goede sd->params.exposure.coarseExpLo = gspca_dev->usb_buf[2]; 53354e8bc5dSHans de Goede sd->params.exposure.coarseExpHi = gspca_dev->usb_buf[3]; 53454e8bc5dSHans de Goede sd->params.exposure.redComp = gspca_dev->usb_buf[4]; 53554e8bc5dSHans de Goede sd->params.exposure.green1Comp = gspca_dev->usb_buf[5]; 53654e8bc5dSHans de Goede sd->params.exposure.green2Comp = gspca_dev->usb_buf[6]; 53754e8bc5dSHans de Goede sd->params.exposure.blueComp = gspca_dev->usb_buf[7]; 53854e8bc5dSHans de Goede break; 53954e8bc5dSHans de Goede 54054e8bc5dSHans de Goede case CPIA_COMMAND_ReadMCPorts: 54154e8bc5dSHans de Goede /* test button press */ 542c2f644aeSHans de Goede a = ((gspca_dev->usb_buf[1] & 0x02) == 0); 543c2f644aeSHans de Goede if (a != sd->params.qx3.button) { 544c2f644aeSHans de Goede #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) 545c2f644aeSHans de Goede input_report_key(gspca_dev->input_dev, KEY_CAMERA, a); 546c2f644aeSHans de Goede input_sync(gspca_dev->input_dev); 547c2f644aeSHans de Goede #endif 548c2f644aeSHans de Goede sd->params.qx3.button = a; 549c2f644aeSHans de Goede } 55054e8bc5dSHans de Goede if (sd->params.qx3.button) { 55154e8bc5dSHans de Goede /* button pressed - unlock the latch */ 55254e8bc5dSHans de Goede do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, 5531d00d6c1SJean-François Moine 3, 0xdf, 0xdf, 0); 55454e8bc5dSHans de Goede do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, 5551d00d6c1SJean-François Moine 3, 0xff, 0xff, 0); 55654e8bc5dSHans de Goede } 55754e8bc5dSHans de Goede 55854e8bc5dSHans de Goede /* test whether microscope is cradled */ 55954e8bc5dSHans de Goede sd->params.qx3.cradled = ((gspca_dev->usb_buf[2] & 0x40) == 0); 56054e8bc5dSHans de Goede break; 56154e8bc5dSHans de Goede } 56254e8bc5dSHans de Goede 56354e8bc5dSHans de Goede return 0; 56454e8bc5dSHans de Goede } 56554e8bc5dSHans de Goede 56654e8bc5dSHans de Goede /* send a command to the camera with an additional data transaction */ 56754e8bc5dSHans de Goede static int do_command_extended(struct gspca_dev *gspca_dev, u16 command, 56854e8bc5dSHans de Goede u8 a, u8 b, u8 c, u8 d, 56954e8bc5dSHans de Goede u8 e, u8 f, u8 g, u8 h, 57054e8bc5dSHans de Goede u8 i, u8 j, u8 k, u8 l) 57154e8bc5dSHans de Goede { 57254e8bc5dSHans de Goede u8 cmd[8]; 57354e8bc5dSHans de Goede 57454e8bc5dSHans de Goede cmd[0] = command >> 8; 57554e8bc5dSHans de Goede cmd[1] = command & 0xff; 57654e8bc5dSHans de Goede cmd[2] = a; 57754e8bc5dSHans de Goede cmd[3] = b; 57854e8bc5dSHans de Goede cmd[4] = c; 57954e8bc5dSHans de Goede cmd[5] = d; 58054e8bc5dSHans de Goede cmd[6] = 8; 58154e8bc5dSHans de Goede cmd[7] = 0; 58254e8bc5dSHans de Goede gspca_dev->usb_buf[0] = e; 58354e8bc5dSHans de Goede gspca_dev->usb_buf[1] = f; 58454e8bc5dSHans de Goede gspca_dev->usb_buf[2] = g; 58554e8bc5dSHans de Goede gspca_dev->usb_buf[3] = h; 58654e8bc5dSHans de Goede gspca_dev->usb_buf[4] = i; 58754e8bc5dSHans de Goede gspca_dev->usb_buf[5] = j; 58854e8bc5dSHans de Goede gspca_dev->usb_buf[6] = k; 58954e8bc5dSHans de Goede gspca_dev->usb_buf[7] = l; 59054e8bc5dSHans de Goede 59154e8bc5dSHans de Goede return cpia_usb_transferCmd(gspca_dev, cmd); 59254e8bc5dSHans de Goede } 59354e8bc5dSHans de Goede 59454e8bc5dSHans de Goede /* find_over_exposure 59554e8bc5dSHans de Goede * Finds a suitable value of OverExposure for use with SetFlickerCtrl 59654e8bc5dSHans de Goede * Some calculation is required because this value changes with the brightness 59754e8bc5dSHans de Goede * set with SetColourParameters 59854e8bc5dSHans de Goede * 59954e8bc5dSHans de Goede * Parameters: Brightness - last brightness value set with SetColourParameters 60054e8bc5dSHans de Goede * 60154e8bc5dSHans de Goede * Returns: OverExposure value to use with SetFlickerCtrl 60254e8bc5dSHans de Goede */ 60354e8bc5dSHans de Goede #define FLICKER_MAX_EXPOSURE 250 60454e8bc5dSHans de Goede #define FLICKER_ALLOWABLE_OVER_EXPOSURE 146 60554e8bc5dSHans de Goede #define FLICKER_BRIGHTNESS_CONSTANT 59 60654e8bc5dSHans de Goede static int find_over_exposure(int brightness) 60754e8bc5dSHans de Goede { 60854e8bc5dSHans de Goede int MaxAllowableOverExposure, OverExposure; 60954e8bc5dSHans de Goede 61054e8bc5dSHans de Goede MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness - 61154e8bc5dSHans de Goede FLICKER_BRIGHTNESS_CONSTANT; 61254e8bc5dSHans de Goede 61354e8bc5dSHans de Goede if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE) 61454e8bc5dSHans de Goede OverExposure = MaxAllowableOverExposure; 61554e8bc5dSHans de Goede else 61654e8bc5dSHans de Goede OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE; 61754e8bc5dSHans de Goede 61854e8bc5dSHans de Goede return OverExposure; 61954e8bc5dSHans de Goede } 62054e8bc5dSHans de Goede #undef FLICKER_MAX_EXPOSURE 62154e8bc5dSHans de Goede #undef FLICKER_ALLOWABLE_OVER_EXPOSURE 62254e8bc5dSHans de Goede #undef FLICKER_BRIGHTNESS_CONSTANT 62354e8bc5dSHans de Goede 62454e8bc5dSHans de Goede /* initialise cam_data structure */ 62554e8bc5dSHans de Goede static void reset_camera_params(struct gspca_dev *gspca_dev) 62654e8bc5dSHans de Goede { 62754e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 62854e8bc5dSHans de Goede struct cam_params *params = &sd->params; 62954e8bc5dSHans de Goede 63054e8bc5dSHans de Goede /* The following parameter values are the defaults from 63154e8bc5dSHans de Goede * "Software Developer's Guide for CPiA Cameras". Any changes 63254e8bc5dSHans de Goede * to the defaults are noted in comments. */ 63354e8bc5dSHans de Goede params->colourParams.brightness = BRIGHTNESS_DEF; 63454e8bc5dSHans de Goede params->colourParams.contrast = CONTRAST_DEF; 63554e8bc5dSHans de Goede params->colourParams.saturation = SATURATION_DEF; 63654e8bc5dSHans de Goede params->exposure.gainMode = 4; 63754e8bc5dSHans de Goede params->exposure.expMode = 2; /* AEC */ 63854e8bc5dSHans de Goede params->exposure.compMode = 1; 63954e8bc5dSHans de Goede params->exposure.centreWeight = 1; 64054e8bc5dSHans de Goede params->exposure.gain = 0; 64154e8bc5dSHans de Goede params->exposure.fineExp = 0; 64254e8bc5dSHans de Goede params->exposure.coarseExpLo = 185; 64354e8bc5dSHans de Goede params->exposure.coarseExpHi = 0; 64454e8bc5dSHans de Goede params->exposure.redComp = COMP_RED; 64554e8bc5dSHans de Goede params->exposure.green1Comp = COMP_GREEN1; 64654e8bc5dSHans de Goede params->exposure.green2Comp = COMP_GREEN2; 64754e8bc5dSHans de Goede params->exposure.blueComp = COMP_BLUE; 64854e8bc5dSHans de Goede params->colourBalance.balanceMode = 2; /* ACB */ 64954e8bc5dSHans de Goede params->colourBalance.redGain = 32; 65054e8bc5dSHans de Goede params->colourBalance.greenGain = 6; 65154e8bc5dSHans de Goede params->colourBalance.blueGain = 92; 65254e8bc5dSHans de Goede params->apcor.gain1 = 0x18; 65354e8bc5dSHans de Goede params->apcor.gain2 = 0x16; 65454e8bc5dSHans de Goede params->apcor.gain4 = 0x24; 65554e8bc5dSHans de Goede params->apcor.gain8 = 0x34; 65654e8bc5dSHans de Goede params->vlOffset.gain1 = 20; 65754e8bc5dSHans de Goede params->vlOffset.gain2 = 24; 65854e8bc5dSHans de Goede params->vlOffset.gain4 = 26; 65954e8bc5dSHans de Goede params->vlOffset.gain8 = 26; 66054e8bc5dSHans de Goede params->compressionParams.hysteresis = 3; 66154e8bc5dSHans de Goede params->compressionParams.threshMax = 11; 66254e8bc5dSHans de Goede params->compressionParams.smallStep = 1; 66354e8bc5dSHans de Goede params->compressionParams.largeStep = 3; 66454e8bc5dSHans de Goede params->compressionParams.decimationHysteresis = 2; 66554e8bc5dSHans de Goede params->compressionParams.frDiffStepThresh = 5; 66654e8bc5dSHans de Goede params->compressionParams.qDiffStepThresh = 3; 66754e8bc5dSHans de Goede params->compressionParams.decimationThreshMod = 2; 66854e8bc5dSHans de Goede /* End of default values from Software Developer's Guide */ 66954e8bc5dSHans de Goede 67054e8bc5dSHans de Goede /* Set Sensor FPS to 15fps. This seems better than 30fps 67154e8bc5dSHans de Goede * for indoor lighting. */ 67254e8bc5dSHans de Goede params->sensorFps.divisor = 1; 67354e8bc5dSHans de Goede params->sensorFps.baserate = 1; 67454e8bc5dSHans de Goede 6751bfea3e4SHans Verkuil params->flickerControl.flickerMode = 0; 6761bfea3e4SHans Verkuil params->flickerControl.disabled = 1; 6771bfea3e4SHans Verkuil params->flickerControl.coarseJump = 6781bfea3e4SHans Verkuil flicker_jumps[sd->mainsFreq] 6791bfea3e4SHans Verkuil [params->sensorFps.baserate] 6801bfea3e4SHans Verkuil [params->sensorFps.divisor]; 6811bfea3e4SHans Verkuil params->flickerControl.allowableOverExposure = 6821bfea3e4SHans Verkuil find_over_exposure(params->colourParams.brightness); 6831bfea3e4SHans Verkuil 68454e8bc5dSHans de Goede params->yuvThreshold.yThreshold = 6; /* From windows driver */ 68554e8bc5dSHans de Goede params->yuvThreshold.uvThreshold = 6; /* From windows driver */ 68654e8bc5dSHans de Goede 68754e8bc5dSHans de Goede params->format.subSample = SUBSAMPLE_420; 68854e8bc5dSHans de Goede params->format.yuvOrder = YUVORDER_YUYV; 68954e8bc5dSHans de Goede 69054e8bc5dSHans de Goede params->compression.mode = CPIA_COMPRESSION_AUTO; 69154e8bc5dSHans de Goede params->compression.decimation = NO_DECIMATION; 69254e8bc5dSHans de Goede 69354e8bc5dSHans de Goede params->compressionTarget.frTargeting = COMP_TARGET_DEF; 69454e8bc5dSHans de Goede params->compressionTarget.targetFR = 15; /* From windows driver */ 69554e8bc5dSHans de Goede params->compressionTarget.targetQ = 5; /* From windows driver */ 69654e8bc5dSHans de Goede 69754e8bc5dSHans de Goede params->qx3.qx3_detected = 0; 69854e8bc5dSHans de Goede params->qx3.toplight = 0; 69954e8bc5dSHans de Goede params->qx3.bottomlight = 0; 70054e8bc5dSHans de Goede params->qx3.button = 0; 70154e8bc5dSHans de Goede params->qx3.cradled = 0; 70254e8bc5dSHans de Goede } 70354e8bc5dSHans de Goede 70454e8bc5dSHans de Goede static void printstatus(struct cam_params *params) 70554e8bc5dSHans de Goede { 70654e8bc5dSHans de Goede PDEBUG(D_PROBE, "status: %02x %02x %02x %02x %02x %02x %02x %02x", 70754e8bc5dSHans de Goede params->status.systemState, params->status.grabState, 70854e8bc5dSHans de Goede params->status.streamState, params->status.fatalError, 70954e8bc5dSHans de Goede params->status.cmdError, params->status.debugFlags, 71054e8bc5dSHans de Goede params->status.vpStatus, params->status.errorCode); 71154e8bc5dSHans de Goede } 71254e8bc5dSHans de Goede 71354e8bc5dSHans de Goede static int goto_low_power(struct gspca_dev *gspca_dev) 71454e8bc5dSHans de Goede { 71554e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 71654e8bc5dSHans de Goede int ret; 71754e8bc5dSHans de Goede 71854e8bc5dSHans de Goede ret = do_command(gspca_dev, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0); 71954e8bc5dSHans de Goede if (ret) 72054e8bc5dSHans de Goede return ret; 72154e8bc5dSHans de Goede 7229be1d6cdSNicolas Kaiser ret = do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); 72354e8bc5dSHans de Goede if (ret) 72454e8bc5dSHans de Goede return ret; 72554e8bc5dSHans de Goede 72654e8bc5dSHans de Goede if (sd->params.status.systemState != LO_POWER_STATE) { 72754e8bc5dSHans de Goede if (sd->params.status.systemState != WARM_BOOT_STATE) { 72854e8bc5dSHans de Goede PDEBUG(D_ERR, 72954e8bc5dSHans de Goede "unexpected state after lo power cmd: %02x", 73054e8bc5dSHans de Goede sd->params.status.systemState); 73154e8bc5dSHans de Goede printstatus(&sd->params); 73254e8bc5dSHans de Goede } 73354e8bc5dSHans de Goede return -EIO; 73454e8bc5dSHans de Goede } 73554e8bc5dSHans de Goede 73654e8bc5dSHans de Goede PDEBUG(D_CONF, "camera now in LOW power state"); 73754e8bc5dSHans de Goede return 0; 73854e8bc5dSHans de Goede } 73954e8bc5dSHans de Goede 74054e8bc5dSHans de Goede static int goto_high_power(struct gspca_dev *gspca_dev) 74154e8bc5dSHans de Goede { 74254e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 74354e8bc5dSHans de Goede int ret; 74454e8bc5dSHans de Goede 74554e8bc5dSHans de Goede ret = do_command(gspca_dev, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0); 74654e8bc5dSHans de Goede if (ret) 74754e8bc5dSHans de Goede return ret; 74854e8bc5dSHans de Goede 74954e8bc5dSHans de Goede msleep_interruptible(40); /* windows driver does it too */ 75054e8bc5dSHans de Goede 75154e8bc5dSHans de Goede if (signal_pending(current)) 75254e8bc5dSHans de Goede return -EINTR; 75354e8bc5dSHans de Goede 754*8c96f0a2SPeter Senna Tschudin ret = do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); 75554e8bc5dSHans de Goede if (ret) 75654e8bc5dSHans de Goede return ret; 75754e8bc5dSHans de Goede 75854e8bc5dSHans de Goede if (sd->params.status.systemState != HI_POWER_STATE) { 75954e8bc5dSHans de Goede PDEBUG(D_ERR, "unexpected state after hi power cmd: %02x", 76054e8bc5dSHans de Goede sd->params.status.systemState); 76154e8bc5dSHans de Goede printstatus(&sd->params); 76254e8bc5dSHans de Goede return -EIO; 76354e8bc5dSHans de Goede } 76454e8bc5dSHans de Goede 76554e8bc5dSHans de Goede PDEBUG(D_CONF, "camera now in HIGH power state"); 76654e8bc5dSHans de Goede return 0; 76754e8bc5dSHans de Goede } 76854e8bc5dSHans de Goede 76954e8bc5dSHans de Goede static int get_version_information(struct gspca_dev *gspca_dev) 77054e8bc5dSHans de Goede { 77154e8bc5dSHans de Goede int ret; 77254e8bc5dSHans de Goede 77354e8bc5dSHans de Goede /* GetCPIAVersion */ 77454e8bc5dSHans de Goede ret = do_command(gspca_dev, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0); 77554e8bc5dSHans de Goede if (ret) 77654e8bc5dSHans de Goede return ret; 77754e8bc5dSHans de Goede 77854e8bc5dSHans de Goede /* GetPnPID */ 77954e8bc5dSHans de Goede return do_command(gspca_dev, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0); 78054e8bc5dSHans de Goede } 78154e8bc5dSHans de Goede 78254e8bc5dSHans de Goede static int save_camera_state(struct gspca_dev *gspca_dev) 78354e8bc5dSHans de Goede { 78454e8bc5dSHans de Goede int ret; 78554e8bc5dSHans de Goede 78654e8bc5dSHans de Goede ret = do_command(gspca_dev, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0); 78754e8bc5dSHans de Goede if (ret) 78854e8bc5dSHans de Goede return ret; 78954e8bc5dSHans de Goede 79054e8bc5dSHans de Goede return do_command(gspca_dev, CPIA_COMMAND_GetExposure, 0, 0, 0, 0); 79154e8bc5dSHans de Goede } 79254e8bc5dSHans de Goede 793e7c3ee63SMárton Németh static int command_setformat(struct gspca_dev *gspca_dev) 79454e8bc5dSHans de Goede { 79554e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 79654e8bc5dSHans de Goede int ret; 79754e8bc5dSHans de Goede 79854e8bc5dSHans de Goede ret = do_command(gspca_dev, CPIA_COMMAND_SetFormat, 79954e8bc5dSHans de Goede sd->params.format.videoSize, 80054e8bc5dSHans de Goede sd->params.format.subSample, 80154e8bc5dSHans de Goede sd->params.format.yuvOrder, 0); 80254e8bc5dSHans de Goede if (ret) 80354e8bc5dSHans de Goede return ret; 80454e8bc5dSHans de Goede 80554e8bc5dSHans de Goede return do_command(gspca_dev, CPIA_COMMAND_SetROI, 80654e8bc5dSHans de Goede sd->params.roi.colStart, sd->params.roi.colEnd, 80754e8bc5dSHans de Goede sd->params.roi.rowStart, sd->params.roi.rowEnd); 80854e8bc5dSHans de Goede } 80954e8bc5dSHans de Goede 810e7c3ee63SMárton Németh static int command_setcolourparams(struct gspca_dev *gspca_dev) 81154e8bc5dSHans de Goede { 81254e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 81354e8bc5dSHans de Goede return do_command(gspca_dev, CPIA_COMMAND_SetColourParams, 81454e8bc5dSHans de Goede sd->params.colourParams.brightness, 81554e8bc5dSHans de Goede sd->params.colourParams.contrast, 81654e8bc5dSHans de Goede sd->params.colourParams.saturation, 0); 81754e8bc5dSHans de Goede } 81854e8bc5dSHans de Goede 819e7c3ee63SMárton Németh static int command_setapcor(struct gspca_dev *gspca_dev) 82054e8bc5dSHans de Goede { 82154e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 82254e8bc5dSHans de Goede return do_command(gspca_dev, CPIA_COMMAND_SetApcor, 82354e8bc5dSHans de Goede sd->params.apcor.gain1, 82454e8bc5dSHans de Goede sd->params.apcor.gain2, 82554e8bc5dSHans de Goede sd->params.apcor.gain4, 82654e8bc5dSHans de Goede sd->params.apcor.gain8); 82754e8bc5dSHans de Goede } 82854e8bc5dSHans de Goede 829e7c3ee63SMárton Németh static int command_setvloffset(struct gspca_dev *gspca_dev) 83054e8bc5dSHans de Goede { 83154e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 83254e8bc5dSHans de Goede return do_command(gspca_dev, CPIA_COMMAND_SetVLOffset, 83354e8bc5dSHans de Goede sd->params.vlOffset.gain1, 83454e8bc5dSHans de Goede sd->params.vlOffset.gain2, 83554e8bc5dSHans de Goede sd->params.vlOffset.gain4, 83654e8bc5dSHans de Goede sd->params.vlOffset.gain8); 83754e8bc5dSHans de Goede } 83854e8bc5dSHans de Goede 839e7c3ee63SMárton Németh static int command_setexposure(struct gspca_dev *gspca_dev) 84054e8bc5dSHans de Goede { 84154e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 84254e8bc5dSHans de Goede int ret; 84354e8bc5dSHans de Goede 84454e8bc5dSHans de Goede ret = do_command_extended(gspca_dev, CPIA_COMMAND_SetExposure, 84554e8bc5dSHans de Goede sd->params.exposure.gainMode, 84654e8bc5dSHans de Goede 1, 84754e8bc5dSHans de Goede sd->params.exposure.compMode, 84854e8bc5dSHans de Goede sd->params.exposure.centreWeight, 84954e8bc5dSHans de Goede sd->params.exposure.gain, 85054e8bc5dSHans de Goede sd->params.exposure.fineExp, 85154e8bc5dSHans de Goede sd->params.exposure.coarseExpLo, 85254e8bc5dSHans de Goede sd->params.exposure.coarseExpHi, 85354e8bc5dSHans de Goede sd->params.exposure.redComp, 85454e8bc5dSHans de Goede sd->params.exposure.green1Comp, 85554e8bc5dSHans de Goede sd->params.exposure.green2Comp, 85654e8bc5dSHans de Goede sd->params.exposure.blueComp); 85754e8bc5dSHans de Goede if (ret) 85854e8bc5dSHans de Goede return ret; 85954e8bc5dSHans de Goede 86054e8bc5dSHans de Goede if (sd->params.exposure.expMode != 1) { 86154e8bc5dSHans de Goede ret = do_command_extended(gspca_dev, CPIA_COMMAND_SetExposure, 86254e8bc5dSHans de Goede 0, 86354e8bc5dSHans de Goede sd->params.exposure.expMode, 86454e8bc5dSHans de Goede 0, 0, 86554e8bc5dSHans de Goede sd->params.exposure.gain, 86654e8bc5dSHans de Goede sd->params.exposure.fineExp, 86754e8bc5dSHans de Goede sd->params.exposure.coarseExpLo, 86854e8bc5dSHans de Goede sd->params.exposure.coarseExpHi, 86954e8bc5dSHans de Goede 0, 0, 0, 0); 87054e8bc5dSHans de Goede } 87154e8bc5dSHans de Goede 87254e8bc5dSHans de Goede return ret; 87354e8bc5dSHans de Goede } 87454e8bc5dSHans de Goede 875e7c3ee63SMárton Németh static int command_setcolourbalance(struct gspca_dev *gspca_dev) 87654e8bc5dSHans de Goede { 87754e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 87854e8bc5dSHans de Goede 87954e8bc5dSHans de Goede if (sd->params.colourBalance.balanceMode == 1) { 88054e8bc5dSHans de Goede int ret; 88154e8bc5dSHans de Goede 88254e8bc5dSHans de Goede ret = do_command(gspca_dev, CPIA_COMMAND_SetColourBalance, 88354e8bc5dSHans de Goede 1, 88454e8bc5dSHans de Goede sd->params.colourBalance.redGain, 88554e8bc5dSHans de Goede sd->params.colourBalance.greenGain, 88654e8bc5dSHans de Goede sd->params.colourBalance.blueGain); 88754e8bc5dSHans de Goede if (ret) 88854e8bc5dSHans de Goede return ret; 88954e8bc5dSHans de Goede 89054e8bc5dSHans de Goede return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance, 89154e8bc5dSHans de Goede 3, 0, 0, 0); 89254e8bc5dSHans de Goede } 89354e8bc5dSHans de Goede if (sd->params.colourBalance.balanceMode == 2) { 89454e8bc5dSHans de Goede return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance, 89554e8bc5dSHans de Goede 2, 0, 0, 0); 89654e8bc5dSHans de Goede } 89754e8bc5dSHans de Goede if (sd->params.colourBalance.balanceMode == 3) { 89854e8bc5dSHans de Goede return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance, 89954e8bc5dSHans de Goede 3, 0, 0, 0); 90054e8bc5dSHans de Goede } 90154e8bc5dSHans de Goede 90254e8bc5dSHans de Goede return -EINVAL; 90354e8bc5dSHans de Goede } 90454e8bc5dSHans de Goede 905e7c3ee63SMárton Németh static int command_setcompressiontarget(struct gspca_dev *gspca_dev) 90654e8bc5dSHans de Goede { 90754e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 90854e8bc5dSHans de Goede 90954e8bc5dSHans de Goede return do_command(gspca_dev, CPIA_COMMAND_SetCompressionTarget, 91054e8bc5dSHans de Goede sd->params.compressionTarget.frTargeting, 91154e8bc5dSHans de Goede sd->params.compressionTarget.targetFR, 91254e8bc5dSHans de Goede sd->params.compressionTarget.targetQ, 0); 91354e8bc5dSHans de Goede } 91454e8bc5dSHans de Goede 915e7c3ee63SMárton Németh static int command_setyuvtresh(struct gspca_dev *gspca_dev) 91654e8bc5dSHans de Goede { 91754e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 91854e8bc5dSHans de Goede 91954e8bc5dSHans de Goede return do_command(gspca_dev, CPIA_COMMAND_SetYUVThresh, 92054e8bc5dSHans de Goede sd->params.yuvThreshold.yThreshold, 92154e8bc5dSHans de Goede sd->params.yuvThreshold.uvThreshold, 0, 0); 92254e8bc5dSHans de Goede } 92354e8bc5dSHans de Goede 924e7c3ee63SMárton Németh static int command_setcompressionparams(struct gspca_dev *gspca_dev) 92554e8bc5dSHans de Goede { 92654e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 92754e8bc5dSHans de Goede 92854e8bc5dSHans de Goede return do_command_extended(gspca_dev, 92954e8bc5dSHans de Goede CPIA_COMMAND_SetCompressionParams, 93054e8bc5dSHans de Goede 0, 0, 0, 0, 93154e8bc5dSHans de Goede sd->params.compressionParams.hysteresis, 93254e8bc5dSHans de Goede sd->params.compressionParams.threshMax, 93354e8bc5dSHans de Goede sd->params.compressionParams.smallStep, 93454e8bc5dSHans de Goede sd->params.compressionParams.largeStep, 93554e8bc5dSHans de Goede sd->params.compressionParams.decimationHysteresis, 93654e8bc5dSHans de Goede sd->params.compressionParams.frDiffStepThresh, 93754e8bc5dSHans de Goede sd->params.compressionParams.qDiffStepThresh, 93854e8bc5dSHans de Goede sd->params.compressionParams.decimationThreshMod); 93954e8bc5dSHans de Goede } 94054e8bc5dSHans de Goede 941e7c3ee63SMárton Németh static int command_setcompression(struct gspca_dev *gspca_dev) 94254e8bc5dSHans de Goede { 94354e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 94454e8bc5dSHans de Goede 94554e8bc5dSHans de Goede return do_command(gspca_dev, CPIA_COMMAND_SetCompression, 94654e8bc5dSHans de Goede sd->params.compression.mode, 94754e8bc5dSHans de Goede sd->params.compression.decimation, 0, 0); 94854e8bc5dSHans de Goede } 94954e8bc5dSHans de Goede 950e7c3ee63SMárton Németh static int command_setsensorfps(struct gspca_dev *gspca_dev) 95154e8bc5dSHans de Goede { 95254e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 95354e8bc5dSHans de Goede 95454e8bc5dSHans de Goede return do_command(gspca_dev, CPIA_COMMAND_SetSensorFPS, 95554e8bc5dSHans de Goede sd->params.sensorFps.divisor, 95654e8bc5dSHans de Goede sd->params.sensorFps.baserate, 0, 0); 95754e8bc5dSHans de Goede } 95854e8bc5dSHans de Goede 959e7c3ee63SMárton Németh static int command_setflickerctrl(struct gspca_dev *gspca_dev) 96054e8bc5dSHans de Goede { 96154e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 96254e8bc5dSHans de Goede 96354e8bc5dSHans de Goede return do_command(gspca_dev, CPIA_COMMAND_SetFlickerCtrl, 96454e8bc5dSHans de Goede sd->params.flickerControl.flickerMode, 96554e8bc5dSHans de Goede sd->params.flickerControl.coarseJump, 96654e8bc5dSHans de Goede sd->params.flickerControl.allowableOverExposure, 96754e8bc5dSHans de Goede 0); 96854e8bc5dSHans de Goede } 96954e8bc5dSHans de Goede 970e7c3ee63SMárton Németh static int command_setecptiming(struct gspca_dev *gspca_dev) 97154e8bc5dSHans de Goede { 97254e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 97354e8bc5dSHans de Goede 97454e8bc5dSHans de Goede return do_command(gspca_dev, CPIA_COMMAND_SetECPTiming, 97554e8bc5dSHans de Goede sd->params.ecpTiming, 0, 0, 0); 97654e8bc5dSHans de Goede } 97754e8bc5dSHans de Goede 978e7c3ee63SMárton Németh static int command_pause(struct gspca_dev *gspca_dev) 97954e8bc5dSHans de Goede { 98054e8bc5dSHans de Goede return do_command(gspca_dev, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0); 98154e8bc5dSHans de Goede } 98254e8bc5dSHans de Goede 983e7c3ee63SMárton Németh static int command_resume(struct gspca_dev *gspca_dev) 98454e8bc5dSHans de Goede { 98554e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 98654e8bc5dSHans de Goede 98754e8bc5dSHans de Goede return do_command(gspca_dev, CPIA_COMMAND_InitStreamCap, 98854e8bc5dSHans de Goede 0, sd->params.streamStartLine, 0, 0); 98954e8bc5dSHans de Goede } 99054e8bc5dSHans de Goede 991e7c3ee63SMárton Németh static int command_setlights(struct gspca_dev *gspca_dev) 99254e8bc5dSHans de Goede { 99354e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 99454e8bc5dSHans de Goede int ret, p1, p2; 99554e8bc5dSHans de Goede 99654e8bc5dSHans de Goede p1 = (sd->params.qx3.bottomlight == 0) << 1; 99754e8bc5dSHans de Goede p2 = (sd->params.qx3.toplight == 0) << 3; 99854e8bc5dSHans de Goede 99954e8bc5dSHans de Goede ret = do_command(gspca_dev, CPIA_COMMAND_WriteVCReg, 10001d00d6c1SJean-François Moine 0x90, 0x8f, 0x50, 0); 100154e8bc5dSHans de Goede if (ret) 100254e8bc5dSHans de Goede return ret; 100354e8bc5dSHans de Goede 100454e8bc5dSHans de Goede return do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, 2, 0, 10051d00d6c1SJean-François Moine p1 | p2 | 0xe0, 0); 100654e8bc5dSHans de Goede } 100754e8bc5dSHans de Goede 100854e8bc5dSHans de Goede static int set_flicker(struct gspca_dev *gspca_dev, int on, int apply) 100954e8bc5dSHans de Goede { 101054e8bc5dSHans de Goede /* Everything in here is from the Windows driver */ 101154e8bc5dSHans de Goede /* define for compgain calculation */ 101254e8bc5dSHans de Goede #if 0 101354e8bc5dSHans de Goede #define COMPGAIN(base, curexp, newexp) \ 101454e8bc5dSHans de Goede (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5) 101554e8bc5dSHans de Goede #define EXP_FROM_COMP(basecomp, curcomp, curexp) \ 101654e8bc5dSHans de Goede (u16)((float)curexp * (float)(u8)(curcomp + 128) / \ 101754e8bc5dSHans de Goede (float)(u8)(basecomp - 128)) 101854e8bc5dSHans de Goede #else 101954e8bc5dSHans de Goede /* equivalent functions without floating point math */ 102054e8bc5dSHans de Goede #define COMPGAIN(base, curexp, newexp) \ 102154e8bc5dSHans de Goede (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2 * newexp))) 102254e8bc5dSHans de Goede #define EXP_FROM_COMP(basecomp, curcomp, curexp) \ 102354e8bc5dSHans de Goede (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128))) 102454e8bc5dSHans de Goede #endif 102554e8bc5dSHans de Goede 102654e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 102754e8bc5dSHans de Goede int currentexp = sd->params.exposure.coarseExpLo + 102854e8bc5dSHans de Goede sd->params.exposure.coarseExpHi * 256; 102954e8bc5dSHans de Goede int ret, startexp; 103054e8bc5dSHans de Goede 103154e8bc5dSHans de Goede if (on) { 103254e8bc5dSHans de Goede int cj = sd->params.flickerControl.coarseJump; 103354e8bc5dSHans de Goede sd->params.flickerControl.flickerMode = 1; 103454e8bc5dSHans de Goede sd->params.flickerControl.disabled = 0; 103554e8bc5dSHans de Goede if (sd->params.exposure.expMode != 2) { 103654e8bc5dSHans de Goede sd->params.exposure.expMode = 2; 103754e8bc5dSHans de Goede sd->exposure_status = EXPOSURE_NORMAL; 103854e8bc5dSHans de Goede } 103954e8bc5dSHans de Goede currentexp = currentexp << sd->params.exposure.gain; 104054e8bc5dSHans de Goede sd->params.exposure.gain = 0; 104154e8bc5dSHans de Goede /* round down current exposure to nearest value */ 104254e8bc5dSHans de Goede startexp = (currentexp + ROUND_UP_EXP_FOR_FLICKER) / cj; 104354e8bc5dSHans de Goede if (startexp < 1) 104454e8bc5dSHans de Goede startexp = 1; 104554e8bc5dSHans de Goede startexp = (startexp * cj) - 1; 104654e8bc5dSHans de Goede if (FIRMWARE_VERSION(1, 2)) 104754e8bc5dSHans de Goede while (startexp > MAX_EXP_102) 104854e8bc5dSHans de Goede startexp -= cj; 104954e8bc5dSHans de Goede else 105054e8bc5dSHans de Goede while (startexp > MAX_EXP) 105154e8bc5dSHans de Goede startexp -= cj; 105254e8bc5dSHans de Goede sd->params.exposure.coarseExpLo = startexp & 0xff; 105354e8bc5dSHans de Goede sd->params.exposure.coarseExpHi = startexp >> 8; 105454e8bc5dSHans de Goede if (currentexp > startexp) { 105554e8bc5dSHans de Goede if (currentexp > (2 * startexp)) 105654e8bc5dSHans de Goede currentexp = 2 * startexp; 105754e8bc5dSHans de Goede sd->params.exposure.redComp = 105854e8bc5dSHans de Goede COMPGAIN(COMP_RED, currentexp, startexp); 105954e8bc5dSHans de Goede sd->params.exposure.green1Comp = 106054e8bc5dSHans de Goede COMPGAIN(COMP_GREEN1, currentexp, startexp); 106154e8bc5dSHans de Goede sd->params.exposure.green2Comp = 106254e8bc5dSHans de Goede COMPGAIN(COMP_GREEN2, currentexp, startexp); 106354e8bc5dSHans de Goede sd->params.exposure.blueComp = 106454e8bc5dSHans de Goede COMPGAIN(COMP_BLUE, currentexp, startexp); 106554e8bc5dSHans de Goede } else { 106654e8bc5dSHans de Goede sd->params.exposure.redComp = COMP_RED; 106754e8bc5dSHans de Goede sd->params.exposure.green1Comp = COMP_GREEN1; 106854e8bc5dSHans de Goede sd->params.exposure.green2Comp = COMP_GREEN2; 106954e8bc5dSHans de Goede sd->params.exposure.blueComp = COMP_BLUE; 107054e8bc5dSHans de Goede } 107154e8bc5dSHans de Goede if (FIRMWARE_VERSION(1, 2)) 107254e8bc5dSHans de Goede sd->params.exposure.compMode = 0; 107354e8bc5dSHans de Goede else 107454e8bc5dSHans de Goede sd->params.exposure.compMode = 1; 107554e8bc5dSHans de Goede 107654e8bc5dSHans de Goede sd->params.apcor.gain1 = 0x18; 107754e8bc5dSHans de Goede sd->params.apcor.gain2 = 0x18; 107854e8bc5dSHans de Goede sd->params.apcor.gain4 = 0x16; 107954e8bc5dSHans de Goede sd->params.apcor.gain8 = 0x14; 108054e8bc5dSHans de Goede } else { 108154e8bc5dSHans de Goede sd->params.flickerControl.flickerMode = 0; 108254e8bc5dSHans de Goede sd->params.flickerControl.disabled = 1; 108354e8bc5dSHans de Goede /* Average equivalent coarse for each comp channel */ 108454e8bc5dSHans de Goede startexp = EXP_FROM_COMP(COMP_RED, 108554e8bc5dSHans de Goede sd->params.exposure.redComp, currentexp); 108654e8bc5dSHans de Goede startexp += EXP_FROM_COMP(COMP_GREEN1, 108754e8bc5dSHans de Goede sd->params.exposure.green1Comp, currentexp); 108854e8bc5dSHans de Goede startexp += EXP_FROM_COMP(COMP_GREEN2, 108954e8bc5dSHans de Goede sd->params.exposure.green2Comp, currentexp); 109054e8bc5dSHans de Goede startexp += EXP_FROM_COMP(COMP_BLUE, 109154e8bc5dSHans de Goede sd->params.exposure.blueComp, currentexp); 109254e8bc5dSHans de Goede startexp = startexp >> 2; 109354e8bc5dSHans de Goede while (startexp > MAX_EXP && sd->params.exposure.gain < 109454e8bc5dSHans de Goede sd->params.exposure.gainMode - 1) { 109554e8bc5dSHans de Goede startexp = startexp >> 1; 109654e8bc5dSHans de Goede ++sd->params.exposure.gain; 109754e8bc5dSHans de Goede } 109854e8bc5dSHans de Goede if (FIRMWARE_VERSION(1, 2) && startexp > MAX_EXP_102) 109954e8bc5dSHans de Goede startexp = MAX_EXP_102; 110054e8bc5dSHans de Goede if (startexp > MAX_EXP) 110154e8bc5dSHans de Goede startexp = MAX_EXP; 110254e8bc5dSHans de Goede sd->params.exposure.coarseExpLo = startexp & 0xff; 110354e8bc5dSHans de Goede sd->params.exposure.coarseExpHi = startexp >> 8; 110454e8bc5dSHans de Goede sd->params.exposure.redComp = COMP_RED; 110554e8bc5dSHans de Goede sd->params.exposure.green1Comp = COMP_GREEN1; 110654e8bc5dSHans de Goede sd->params.exposure.green2Comp = COMP_GREEN2; 110754e8bc5dSHans de Goede sd->params.exposure.blueComp = COMP_BLUE; 110854e8bc5dSHans de Goede sd->params.exposure.compMode = 1; 110954e8bc5dSHans de Goede sd->params.apcor.gain1 = 0x18; 111054e8bc5dSHans de Goede sd->params.apcor.gain2 = 0x16; 111154e8bc5dSHans de Goede sd->params.apcor.gain4 = 0x24; 111254e8bc5dSHans de Goede sd->params.apcor.gain8 = 0x34; 111354e8bc5dSHans de Goede } 111454e8bc5dSHans de Goede sd->params.vlOffset.gain1 = 20; 111554e8bc5dSHans de Goede sd->params.vlOffset.gain2 = 24; 111654e8bc5dSHans de Goede sd->params.vlOffset.gain4 = 26; 111754e8bc5dSHans de Goede sd->params.vlOffset.gain8 = 26; 111854e8bc5dSHans de Goede 111954e8bc5dSHans de Goede if (apply) { 112054e8bc5dSHans de Goede ret = command_setexposure(gspca_dev); 112154e8bc5dSHans de Goede if (ret) 112254e8bc5dSHans de Goede return ret; 112354e8bc5dSHans de Goede 112454e8bc5dSHans de Goede ret = command_setapcor(gspca_dev); 112554e8bc5dSHans de Goede if (ret) 112654e8bc5dSHans de Goede return ret; 112754e8bc5dSHans de Goede 112854e8bc5dSHans de Goede ret = command_setvloffset(gspca_dev); 112954e8bc5dSHans de Goede if (ret) 113054e8bc5dSHans de Goede return ret; 113154e8bc5dSHans de Goede 113254e8bc5dSHans de Goede ret = command_setflickerctrl(gspca_dev); 113354e8bc5dSHans de Goede if (ret) 113454e8bc5dSHans de Goede return ret; 113554e8bc5dSHans de Goede } 113654e8bc5dSHans de Goede 113754e8bc5dSHans de Goede return 0; 113854e8bc5dSHans de Goede #undef EXP_FROM_COMP 113954e8bc5dSHans de Goede #undef COMPGAIN 114054e8bc5dSHans de Goede } 114154e8bc5dSHans de Goede 114254e8bc5dSHans de Goede /* monitor the exposure and adjust the sensor frame rate if needed */ 114354e8bc5dSHans de Goede static void monitor_exposure(struct gspca_dev *gspca_dev) 114454e8bc5dSHans de Goede { 114554e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 1146cc90b15eSJean-François Moine u8 exp_acc, bcomp, cmd[8]; 114754e8bc5dSHans de Goede int ret, light_exp, dark_exp, very_dark_exp; 114854e8bc5dSHans de Goede int old_exposure, new_exposure, framerate; 114954e8bc5dSHans de Goede int setfps = 0, setexp = 0, setflicker = 0; 115054e8bc5dSHans de Goede 115154e8bc5dSHans de Goede /* get necessary stats and register settings from camera */ 115254e8bc5dSHans de Goede /* do_command can't handle this, so do it ourselves */ 115354e8bc5dSHans de Goede cmd[0] = CPIA_COMMAND_ReadVPRegs >> 8; 115454e8bc5dSHans de Goede cmd[1] = CPIA_COMMAND_ReadVPRegs & 0xff; 115554e8bc5dSHans de Goede cmd[2] = 30; 115654e8bc5dSHans de Goede cmd[3] = 4; 115754e8bc5dSHans de Goede cmd[4] = 9; 115854e8bc5dSHans de Goede cmd[5] = 8; 115954e8bc5dSHans de Goede cmd[6] = 8; 116054e8bc5dSHans de Goede cmd[7] = 0; 116154e8bc5dSHans de Goede ret = cpia_usb_transferCmd(gspca_dev, cmd); 116254e8bc5dSHans de Goede if (ret) { 1163133a9fe9SJoe Perches pr_err("ReadVPRegs(30,4,9,8) - failed: %d\n", ret); 116454e8bc5dSHans de Goede return; 116554e8bc5dSHans de Goede } 116654e8bc5dSHans de Goede exp_acc = gspca_dev->usb_buf[0]; 116754e8bc5dSHans de Goede bcomp = gspca_dev->usb_buf[1]; 116854e8bc5dSHans de Goede 116954e8bc5dSHans de Goede light_exp = sd->params.colourParams.brightness + 117054e8bc5dSHans de Goede TC - 50 + EXP_ACC_LIGHT; 117154e8bc5dSHans de Goede if (light_exp > 255) 117254e8bc5dSHans de Goede light_exp = 255; 117354e8bc5dSHans de Goede dark_exp = sd->params.colourParams.brightness + 117454e8bc5dSHans de Goede TC - 50 - EXP_ACC_DARK; 117554e8bc5dSHans de Goede if (dark_exp < 0) 117654e8bc5dSHans de Goede dark_exp = 0; 117754e8bc5dSHans de Goede very_dark_exp = dark_exp / 2; 117854e8bc5dSHans de Goede 117954e8bc5dSHans de Goede old_exposure = sd->params.exposure.coarseExpHi * 256 + 118054e8bc5dSHans de Goede sd->params.exposure.coarseExpLo; 118154e8bc5dSHans de Goede 118254e8bc5dSHans de Goede if (!sd->params.flickerControl.disabled) { 118354e8bc5dSHans de Goede /* Flicker control on */ 118454e8bc5dSHans de Goede int max_comp = FIRMWARE_VERSION(1, 2) ? MAX_COMP : 118554e8bc5dSHans de Goede HIGH_COMP_102; 118654e8bc5dSHans de Goede bcomp += 128; /* decode */ 118754e8bc5dSHans de Goede if (bcomp >= max_comp && exp_acc < dark_exp) { 118854e8bc5dSHans de Goede /* dark */ 118954e8bc5dSHans de Goede if (exp_acc < very_dark_exp) { 119054e8bc5dSHans de Goede /* very dark */ 119154e8bc5dSHans de Goede if (sd->exposure_status == EXPOSURE_VERY_DARK) 119254e8bc5dSHans de Goede ++sd->exposure_count; 119354e8bc5dSHans de Goede else { 119454e8bc5dSHans de Goede sd->exposure_status = 119554e8bc5dSHans de Goede EXPOSURE_VERY_DARK; 119654e8bc5dSHans de Goede sd->exposure_count = 1; 119754e8bc5dSHans de Goede } 119854e8bc5dSHans de Goede } else { 119954e8bc5dSHans de Goede /* just dark */ 120054e8bc5dSHans de Goede if (sd->exposure_status == EXPOSURE_DARK) 120154e8bc5dSHans de Goede ++sd->exposure_count; 120254e8bc5dSHans de Goede else { 120354e8bc5dSHans de Goede sd->exposure_status = EXPOSURE_DARK; 120454e8bc5dSHans de Goede sd->exposure_count = 1; 120554e8bc5dSHans de Goede } 120654e8bc5dSHans de Goede } 120754e8bc5dSHans de Goede } else if (old_exposure <= LOW_EXP || exp_acc > light_exp) { 120854e8bc5dSHans de Goede /* light */ 120954e8bc5dSHans de Goede if (old_exposure <= VERY_LOW_EXP) { 121054e8bc5dSHans de Goede /* very light */ 121154e8bc5dSHans de Goede if (sd->exposure_status == EXPOSURE_VERY_LIGHT) 121254e8bc5dSHans de Goede ++sd->exposure_count; 121354e8bc5dSHans de Goede else { 121454e8bc5dSHans de Goede sd->exposure_status = 121554e8bc5dSHans de Goede EXPOSURE_VERY_LIGHT; 121654e8bc5dSHans de Goede sd->exposure_count = 1; 121754e8bc5dSHans de Goede } 121854e8bc5dSHans de Goede } else { 121954e8bc5dSHans de Goede /* just light */ 122054e8bc5dSHans de Goede if (sd->exposure_status == EXPOSURE_LIGHT) 122154e8bc5dSHans de Goede ++sd->exposure_count; 122254e8bc5dSHans de Goede else { 122354e8bc5dSHans de Goede sd->exposure_status = EXPOSURE_LIGHT; 122454e8bc5dSHans de Goede sd->exposure_count = 1; 122554e8bc5dSHans de Goede } 122654e8bc5dSHans de Goede } 122754e8bc5dSHans de Goede } else { 122854e8bc5dSHans de Goede /* not dark or light */ 122954e8bc5dSHans de Goede sd->exposure_status = EXPOSURE_NORMAL; 123054e8bc5dSHans de Goede } 123154e8bc5dSHans de Goede } else { 123254e8bc5dSHans de Goede /* Flicker control off */ 123354e8bc5dSHans de Goede if (old_exposure >= MAX_EXP && exp_acc < dark_exp) { 123454e8bc5dSHans de Goede /* dark */ 123554e8bc5dSHans de Goede if (exp_acc < very_dark_exp) { 123654e8bc5dSHans de Goede /* very dark */ 123754e8bc5dSHans de Goede if (sd->exposure_status == EXPOSURE_VERY_DARK) 123854e8bc5dSHans de Goede ++sd->exposure_count; 123954e8bc5dSHans de Goede else { 124054e8bc5dSHans de Goede sd->exposure_status = 124154e8bc5dSHans de Goede EXPOSURE_VERY_DARK; 124254e8bc5dSHans de Goede sd->exposure_count = 1; 124354e8bc5dSHans de Goede } 124454e8bc5dSHans de Goede } else { 124554e8bc5dSHans de Goede /* just dark */ 124654e8bc5dSHans de Goede if (sd->exposure_status == EXPOSURE_DARK) 124754e8bc5dSHans de Goede ++sd->exposure_count; 124854e8bc5dSHans de Goede else { 124954e8bc5dSHans de Goede sd->exposure_status = EXPOSURE_DARK; 125054e8bc5dSHans de Goede sd->exposure_count = 1; 125154e8bc5dSHans de Goede } 125254e8bc5dSHans de Goede } 125354e8bc5dSHans de Goede } else if (old_exposure <= LOW_EXP || exp_acc > light_exp) { 125454e8bc5dSHans de Goede /* light */ 125554e8bc5dSHans de Goede if (old_exposure <= VERY_LOW_EXP) { 125654e8bc5dSHans de Goede /* very light */ 125754e8bc5dSHans de Goede if (sd->exposure_status == EXPOSURE_VERY_LIGHT) 125854e8bc5dSHans de Goede ++sd->exposure_count; 125954e8bc5dSHans de Goede else { 126054e8bc5dSHans de Goede sd->exposure_status = 126154e8bc5dSHans de Goede EXPOSURE_VERY_LIGHT; 126254e8bc5dSHans de Goede sd->exposure_count = 1; 126354e8bc5dSHans de Goede } 126454e8bc5dSHans de Goede } else { 126554e8bc5dSHans de Goede /* just light */ 126654e8bc5dSHans de Goede if (sd->exposure_status == EXPOSURE_LIGHT) 126754e8bc5dSHans de Goede ++sd->exposure_count; 126854e8bc5dSHans de Goede else { 126954e8bc5dSHans de Goede sd->exposure_status = EXPOSURE_LIGHT; 127054e8bc5dSHans de Goede sd->exposure_count = 1; 127154e8bc5dSHans de Goede } 127254e8bc5dSHans de Goede } 127354e8bc5dSHans de Goede } else { 127454e8bc5dSHans de Goede /* not dark or light */ 127554e8bc5dSHans de Goede sd->exposure_status = EXPOSURE_NORMAL; 127654e8bc5dSHans de Goede } 127754e8bc5dSHans de Goede } 127854e8bc5dSHans de Goede 127954e8bc5dSHans de Goede framerate = atomic_read(&sd->fps); 128054e8bc5dSHans de Goede if (framerate > 30 || framerate < 1) 128154e8bc5dSHans de Goede framerate = 1; 128254e8bc5dSHans de Goede 128354e8bc5dSHans de Goede if (!sd->params.flickerControl.disabled) { 128454e8bc5dSHans de Goede /* Flicker control on */ 128554e8bc5dSHans de Goede if ((sd->exposure_status == EXPOSURE_VERY_DARK || 128654e8bc5dSHans de Goede sd->exposure_status == EXPOSURE_DARK) && 128754e8bc5dSHans de Goede sd->exposure_count >= DARK_TIME * framerate && 128876fafe78SHans de Goede sd->params.sensorFps.divisor < 2) { 128954e8bc5dSHans de Goede 129054e8bc5dSHans de Goede /* dark for too long */ 129154e8bc5dSHans de Goede ++sd->params.sensorFps.divisor; 129254e8bc5dSHans de Goede setfps = 1; 129354e8bc5dSHans de Goede 129454e8bc5dSHans de Goede sd->params.flickerControl.coarseJump = 129554e8bc5dSHans de Goede flicker_jumps[sd->mainsFreq] 129654e8bc5dSHans de Goede [sd->params.sensorFps.baserate] 129754e8bc5dSHans de Goede [sd->params.sensorFps.divisor]; 129854e8bc5dSHans de Goede setflicker = 1; 129954e8bc5dSHans de Goede 130054e8bc5dSHans de Goede new_exposure = sd->params.flickerControl.coarseJump-1; 130154e8bc5dSHans de Goede while (new_exposure < old_exposure / 2) 130254e8bc5dSHans de Goede new_exposure += 130354e8bc5dSHans de Goede sd->params.flickerControl.coarseJump; 130454e8bc5dSHans de Goede sd->params.exposure.coarseExpLo = new_exposure & 0xff; 130554e8bc5dSHans de Goede sd->params.exposure.coarseExpHi = new_exposure >> 8; 130654e8bc5dSHans de Goede setexp = 1; 130754e8bc5dSHans de Goede sd->exposure_status = EXPOSURE_NORMAL; 130854e8bc5dSHans de Goede PDEBUG(D_CONF, "Automatically decreasing sensor_fps"); 130954e8bc5dSHans de Goede 131054e8bc5dSHans de Goede } else if ((sd->exposure_status == EXPOSURE_VERY_LIGHT || 131154e8bc5dSHans de Goede sd->exposure_status == EXPOSURE_LIGHT) && 131254e8bc5dSHans de Goede sd->exposure_count >= LIGHT_TIME * framerate && 131354e8bc5dSHans de Goede sd->params.sensorFps.divisor > 0) { 131454e8bc5dSHans de Goede 131554e8bc5dSHans de Goede /* light for too long */ 131654e8bc5dSHans de Goede int max_exp = FIRMWARE_VERSION(1, 2) ? MAX_EXP_102 : 131754e8bc5dSHans de Goede MAX_EXP; 131854e8bc5dSHans de Goede --sd->params.sensorFps.divisor; 131954e8bc5dSHans de Goede setfps = 1; 132054e8bc5dSHans de Goede 132154e8bc5dSHans de Goede sd->params.flickerControl.coarseJump = 132254e8bc5dSHans de Goede flicker_jumps[sd->mainsFreq] 132354e8bc5dSHans de Goede [sd->params.sensorFps.baserate] 132454e8bc5dSHans de Goede [sd->params.sensorFps.divisor]; 132554e8bc5dSHans de Goede setflicker = 1; 132654e8bc5dSHans de Goede 132754e8bc5dSHans de Goede new_exposure = sd->params.flickerControl.coarseJump-1; 132854e8bc5dSHans de Goede while (new_exposure < 2 * old_exposure && 132954e8bc5dSHans de Goede new_exposure + 133054e8bc5dSHans de Goede sd->params.flickerControl.coarseJump < max_exp) 133154e8bc5dSHans de Goede new_exposure += 133254e8bc5dSHans de Goede sd->params.flickerControl.coarseJump; 133354e8bc5dSHans de Goede sd->params.exposure.coarseExpLo = new_exposure & 0xff; 133454e8bc5dSHans de Goede sd->params.exposure.coarseExpHi = new_exposure >> 8; 133554e8bc5dSHans de Goede setexp = 1; 133654e8bc5dSHans de Goede sd->exposure_status = EXPOSURE_NORMAL; 133754e8bc5dSHans de Goede PDEBUG(D_CONF, "Automatically increasing sensor_fps"); 133854e8bc5dSHans de Goede } 133954e8bc5dSHans de Goede } else { 134054e8bc5dSHans de Goede /* Flicker control off */ 134154e8bc5dSHans de Goede if ((sd->exposure_status == EXPOSURE_VERY_DARK || 134254e8bc5dSHans de Goede sd->exposure_status == EXPOSURE_DARK) && 134354e8bc5dSHans de Goede sd->exposure_count >= DARK_TIME * framerate && 134476fafe78SHans de Goede sd->params.sensorFps.divisor < 2) { 134554e8bc5dSHans de Goede 134654e8bc5dSHans de Goede /* dark for too long */ 134754e8bc5dSHans de Goede ++sd->params.sensorFps.divisor; 134854e8bc5dSHans de Goede setfps = 1; 134954e8bc5dSHans de Goede 135054e8bc5dSHans de Goede if (sd->params.exposure.gain > 0) { 135154e8bc5dSHans de Goede --sd->params.exposure.gain; 135254e8bc5dSHans de Goede setexp = 1; 135354e8bc5dSHans de Goede } 135454e8bc5dSHans de Goede sd->exposure_status = EXPOSURE_NORMAL; 135554e8bc5dSHans de Goede PDEBUG(D_CONF, "Automatically decreasing sensor_fps"); 135654e8bc5dSHans de Goede 135754e8bc5dSHans de Goede } else if ((sd->exposure_status == EXPOSURE_VERY_LIGHT || 135854e8bc5dSHans de Goede sd->exposure_status == EXPOSURE_LIGHT) && 135954e8bc5dSHans de Goede sd->exposure_count >= LIGHT_TIME * framerate && 136054e8bc5dSHans de Goede sd->params.sensorFps.divisor > 0) { 136154e8bc5dSHans de Goede 136254e8bc5dSHans de Goede /* light for too long */ 136354e8bc5dSHans de Goede --sd->params.sensorFps.divisor; 136454e8bc5dSHans de Goede setfps = 1; 136554e8bc5dSHans de Goede 136654e8bc5dSHans de Goede if (sd->params.exposure.gain < 136754e8bc5dSHans de Goede sd->params.exposure.gainMode - 1) { 136854e8bc5dSHans de Goede ++sd->params.exposure.gain; 136954e8bc5dSHans de Goede setexp = 1; 137054e8bc5dSHans de Goede } 137154e8bc5dSHans de Goede sd->exposure_status = EXPOSURE_NORMAL; 137254e8bc5dSHans de Goede PDEBUG(D_CONF, "Automatically increasing sensor_fps"); 137354e8bc5dSHans de Goede } 137454e8bc5dSHans de Goede } 137554e8bc5dSHans de Goede 137654e8bc5dSHans de Goede if (setexp) 137754e8bc5dSHans de Goede command_setexposure(gspca_dev); 137854e8bc5dSHans de Goede 137954e8bc5dSHans de Goede if (setfps) 138054e8bc5dSHans de Goede command_setsensorfps(gspca_dev); 138154e8bc5dSHans de Goede 138254e8bc5dSHans de Goede if (setflicker) 138354e8bc5dSHans de Goede command_setflickerctrl(gspca_dev); 138454e8bc5dSHans de Goede } 138554e8bc5dSHans de Goede 138654e8bc5dSHans de Goede /*-----------------------------------------------------------------*/ 138754e8bc5dSHans de Goede /* if flicker is switched off, this function switches it back on.It checks, 138854e8bc5dSHans de Goede however, that conditions are suitable before restarting it. 138954e8bc5dSHans de Goede This should only be called for firmware version 1.2. 139054e8bc5dSHans de Goede 139154e8bc5dSHans de Goede It also adjust the colour balance when an exposure step is detected - as 139254e8bc5dSHans de Goede long as flicker is running 139354e8bc5dSHans de Goede */ 139454e8bc5dSHans de Goede static void restart_flicker(struct gspca_dev *gspca_dev) 139554e8bc5dSHans de Goede { 139654e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 139754e8bc5dSHans de Goede int cam_exposure, old_exp; 139854e8bc5dSHans de Goede 139954e8bc5dSHans de Goede if (!FIRMWARE_VERSION(1, 2)) 140054e8bc5dSHans de Goede return; 140154e8bc5dSHans de Goede 140254e8bc5dSHans de Goede cam_exposure = atomic_read(&sd->cam_exposure); 140354e8bc5dSHans de Goede 140454e8bc5dSHans de Goede if (sd->params.flickerControl.flickerMode == 0 || 140554e8bc5dSHans de Goede cam_exposure == 0) 140654e8bc5dSHans de Goede return; 140754e8bc5dSHans de Goede 140854e8bc5dSHans de Goede old_exp = sd->params.exposure.coarseExpLo + 140954e8bc5dSHans de Goede sd->params.exposure.coarseExpHi*256; 141054e8bc5dSHans de Goede /* 141154e8bc5dSHans de Goede see how far away camera exposure is from a valid 141254e8bc5dSHans de Goede flicker exposure value 141354e8bc5dSHans de Goede */ 141454e8bc5dSHans de Goede cam_exposure %= sd->params.flickerControl.coarseJump; 141554e8bc5dSHans de Goede if (!sd->params.flickerControl.disabled && 141654e8bc5dSHans de Goede cam_exposure <= sd->params.flickerControl.coarseJump - 3) { 141754e8bc5dSHans de Goede /* Flicker control auto-disabled */ 141854e8bc5dSHans de Goede sd->params.flickerControl.disabled = 1; 141954e8bc5dSHans de Goede } 142054e8bc5dSHans de Goede 142154e8bc5dSHans de Goede if (sd->params.flickerControl.disabled && 142254e8bc5dSHans de Goede old_exp > sd->params.flickerControl.coarseJump + 142354e8bc5dSHans de Goede ROUND_UP_EXP_FOR_FLICKER) { 142454e8bc5dSHans de Goede /* exposure is now high enough to switch 142554e8bc5dSHans de Goede flicker control back on */ 142654e8bc5dSHans de Goede set_flicker(gspca_dev, 1, 1); 142754e8bc5dSHans de Goede } 142854e8bc5dSHans de Goede } 142954e8bc5dSHans de Goede 143054e8bc5dSHans de Goede /* this function is called at probe time */ 143154e8bc5dSHans de Goede static int sd_config(struct gspca_dev *gspca_dev, 143254e8bc5dSHans de Goede const struct usb_device_id *id) 143354e8bc5dSHans de Goede { 14341bfea3e4SHans Verkuil struct sd *sd = (struct sd *) gspca_dev; 143554e8bc5dSHans de Goede struct cam *cam; 143654e8bc5dSHans de Goede 14371bfea3e4SHans Verkuil sd->mainsFreq = FREQ_DEF == V4L2_CID_POWER_LINE_FREQUENCY_60HZ; 143854e8bc5dSHans de Goede reset_camera_params(gspca_dev); 143954e8bc5dSHans de Goede 144054e8bc5dSHans de Goede PDEBUG(D_PROBE, "cpia CPiA camera detected (vid/pid 0x%04X:0x%04X)", 144154e8bc5dSHans de Goede id->idVendor, id->idProduct); 144254e8bc5dSHans de Goede 144354e8bc5dSHans de Goede cam = &gspca_dev->cam; 144454e8bc5dSHans de Goede cam->cam_mode = mode; 144554e8bc5dSHans de Goede cam->nmodes = ARRAY_SIZE(mode); 144654e8bc5dSHans de Goede 14471bfea3e4SHans Verkuil goto_low_power(gspca_dev); 14481bfea3e4SHans Verkuil /* Check the firmware version. */ 14491bfea3e4SHans Verkuil sd->params.version.firmwareVersion = 0; 14501bfea3e4SHans Verkuil get_version_information(gspca_dev); 14511bfea3e4SHans Verkuil if (sd->params.version.firmwareVersion != 1) { 14521bfea3e4SHans Verkuil PDEBUG(D_ERR, "only firmware version 1 is supported (got: %d)", 14531bfea3e4SHans Verkuil sd->params.version.firmwareVersion); 14541bfea3e4SHans Verkuil return -ENODEV; 14551bfea3e4SHans Verkuil } 145654e8bc5dSHans de Goede 14571bfea3e4SHans Verkuil /* A bug in firmware 1-02 limits gainMode to 2 */ 14581bfea3e4SHans Verkuil if (sd->params.version.firmwareRevision <= 2 && 14591bfea3e4SHans Verkuil sd->params.exposure.gainMode > 2) { 14601bfea3e4SHans Verkuil sd->params.exposure.gainMode = 2; 14611bfea3e4SHans Verkuil } 14621bfea3e4SHans Verkuil 14631bfea3e4SHans Verkuil /* set QX3 detected flag */ 14641bfea3e4SHans Verkuil sd->params.qx3.qx3_detected = (sd->params.pnpID.vendor == 0x0813 && 14651bfea3e4SHans Verkuil sd->params.pnpID.product == 0x0001); 146654e8bc5dSHans de Goede return 0; 146754e8bc5dSHans de Goede } 146854e8bc5dSHans de Goede 146954e8bc5dSHans de Goede /* -- start the camera -- */ 147054e8bc5dSHans de Goede static int sd_start(struct gspca_dev *gspca_dev) 147154e8bc5dSHans de Goede { 147254e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 147354e8bc5dSHans de Goede int priv, ret; 147454e8bc5dSHans de Goede 147554e8bc5dSHans de Goede /* Start the camera in low power mode */ 147654e8bc5dSHans de Goede if (goto_low_power(gspca_dev)) { 147754e8bc5dSHans de Goede if (sd->params.status.systemState != WARM_BOOT_STATE) { 147854e8bc5dSHans de Goede PDEBUG(D_ERR, "unexpected systemstate: %02x", 147954e8bc5dSHans de Goede sd->params.status.systemState); 148054e8bc5dSHans de Goede printstatus(&sd->params); 148154e8bc5dSHans de Goede return -ENODEV; 148254e8bc5dSHans de Goede } 148354e8bc5dSHans de Goede 148454e8bc5dSHans de Goede /* FIXME: this is just dirty trial and error */ 148554e8bc5dSHans de Goede ret = goto_high_power(gspca_dev); 148654e8bc5dSHans de Goede if (ret) 148754e8bc5dSHans de Goede return ret; 148854e8bc5dSHans de Goede 148954e8bc5dSHans de Goede ret = do_command(gspca_dev, CPIA_COMMAND_DiscardFrame, 149054e8bc5dSHans de Goede 0, 0, 0, 0); 149154e8bc5dSHans de Goede if (ret) 149254e8bc5dSHans de Goede return ret; 149354e8bc5dSHans de Goede 149454e8bc5dSHans de Goede ret = goto_low_power(gspca_dev); 149554e8bc5dSHans de Goede if (ret) 149654e8bc5dSHans de Goede return ret; 149754e8bc5dSHans de Goede } 149854e8bc5dSHans de Goede 149954e8bc5dSHans de Goede /* procedure described in developer's guide p3-28 */ 150054e8bc5dSHans de Goede 150154e8bc5dSHans de Goede /* Check the firmware version. */ 150254e8bc5dSHans de Goede sd->params.version.firmwareVersion = 0; 150354e8bc5dSHans de Goede get_version_information(gspca_dev); 150454e8bc5dSHans de Goede 150554e8bc5dSHans de Goede /* The fatal error checking should be done after 150654e8bc5dSHans de Goede * the camera powers up (developer's guide p 3-38) */ 150754e8bc5dSHans de Goede 150854e8bc5dSHans de Goede /* Set streamState before transition to high power to avoid bug 150954e8bc5dSHans de Goede * in firmware 1-02 */ 151054e8bc5dSHans de Goede ret = do_command(gspca_dev, CPIA_COMMAND_ModifyCameraStatus, 151154e8bc5dSHans de Goede STREAMSTATE, 0, STREAM_NOT_READY, 0); 151254e8bc5dSHans de Goede if (ret) 151354e8bc5dSHans de Goede return ret; 151454e8bc5dSHans de Goede 151554e8bc5dSHans de Goede /* GotoHiPower */ 151654e8bc5dSHans de Goede ret = goto_high_power(gspca_dev); 151754e8bc5dSHans de Goede if (ret) 151854e8bc5dSHans de Goede return ret; 151954e8bc5dSHans de Goede 152054e8bc5dSHans de Goede /* Check the camera status */ 152154e8bc5dSHans de Goede ret = do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); 152254e8bc5dSHans de Goede if (ret) 152354e8bc5dSHans de Goede return ret; 152454e8bc5dSHans de Goede 152554e8bc5dSHans de Goede if (sd->params.status.fatalError) { 152654e8bc5dSHans de Goede PDEBUG(D_ERR, "fatal_error: %04x, vp_status: %04x", 152754e8bc5dSHans de Goede sd->params.status.fatalError, 152854e8bc5dSHans de Goede sd->params.status.vpStatus); 152954e8bc5dSHans de Goede return -EIO; 153054e8bc5dSHans de Goede } 153154e8bc5dSHans de Goede 153254e8bc5dSHans de Goede /* VPVersion can't be retrieved before the camera is in HiPower, 153354e8bc5dSHans de Goede * so get it here instead of in get_version_information. */ 153454e8bc5dSHans de Goede ret = do_command(gspca_dev, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0); 153554e8bc5dSHans de Goede if (ret) 153654e8bc5dSHans de Goede return ret; 153754e8bc5dSHans de Goede 153854e8bc5dSHans de Goede /* Determine video mode settings */ 153954e8bc5dSHans de Goede sd->params.streamStartLine = 120; 154054e8bc5dSHans de Goede 154154e8bc5dSHans de Goede priv = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv; 154254e8bc5dSHans de Goede if (priv & 0x01) { /* crop */ 154354e8bc5dSHans de Goede sd->params.roi.colStart = 2; 154454e8bc5dSHans de Goede sd->params.roi.rowStart = 6; 154554e8bc5dSHans de Goede } else { 154654e8bc5dSHans de Goede sd->params.roi.colStart = 0; 154754e8bc5dSHans de Goede sd->params.roi.rowStart = 0; 154854e8bc5dSHans de Goede } 154954e8bc5dSHans de Goede 155054e8bc5dSHans de Goede if (priv & 0x02) { /* quarter */ 155154e8bc5dSHans de Goede sd->params.format.videoSize = VIDEOSIZE_QCIF; 155254e8bc5dSHans de Goede sd->params.roi.colStart /= 2; 155354e8bc5dSHans de Goede sd->params.roi.rowStart /= 2; 155454e8bc5dSHans de Goede sd->params.streamStartLine /= 2; 155554e8bc5dSHans de Goede } else 155654e8bc5dSHans de Goede sd->params.format.videoSize = VIDEOSIZE_CIF; 155754e8bc5dSHans de Goede 155854e8bc5dSHans de Goede sd->params.roi.colEnd = sd->params.roi.colStart + 155954e8bc5dSHans de Goede (gspca_dev->width >> 3); 156054e8bc5dSHans de Goede sd->params.roi.rowEnd = sd->params.roi.rowStart + 156154e8bc5dSHans de Goede (gspca_dev->height >> 2); 156254e8bc5dSHans de Goede 156354e8bc5dSHans de Goede /* And now set the camera to a known state */ 156454e8bc5dSHans de Goede ret = do_command(gspca_dev, CPIA_COMMAND_SetGrabMode, 156554e8bc5dSHans de Goede CPIA_GRAB_CONTINEOUS, 0, 0, 0); 156654e8bc5dSHans de Goede if (ret) 156754e8bc5dSHans de Goede return ret; 156854e8bc5dSHans de Goede /* We start with compression disabled, as we need one uncompressed 156954e8bc5dSHans de Goede frame to handle later compressed frames */ 157054e8bc5dSHans de Goede ret = do_command(gspca_dev, CPIA_COMMAND_SetCompression, 157154e8bc5dSHans de Goede CPIA_COMPRESSION_NONE, 157254e8bc5dSHans de Goede NO_DECIMATION, 0, 0); 157354e8bc5dSHans de Goede if (ret) 157454e8bc5dSHans de Goede return ret; 157554e8bc5dSHans de Goede ret = command_setcompressiontarget(gspca_dev); 157654e8bc5dSHans de Goede if (ret) 157754e8bc5dSHans de Goede return ret; 157854e8bc5dSHans de Goede ret = command_setcolourparams(gspca_dev); 157954e8bc5dSHans de Goede if (ret) 158054e8bc5dSHans de Goede return ret; 158154e8bc5dSHans de Goede ret = command_setformat(gspca_dev); 158254e8bc5dSHans de Goede if (ret) 158354e8bc5dSHans de Goede return ret; 158454e8bc5dSHans de Goede ret = command_setyuvtresh(gspca_dev); 158554e8bc5dSHans de Goede if (ret) 158654e8bc5dSHans de Goede return ret; 158754e8bc5dSHans de Goede ret = command_setecptiming(gspca_dev); 158854e8bc5dSHans de Goede if (ret) 158954e8bc5dSHans de Goede return ret; 159054e8bc5dSHans de Goede ret = command_setcompressionparams(gspca_dev); 159154e8bc5dSHans de Goede if (ret) 159254e8bc5dSHans de Goede return ret; 159354e8bc5dSHans de Goede ret = command_setexposure(gspca_dev); 159454e8bc5dSHans de Goede if (ret) 159554e8bc5dSHans de Goede return ret; 159654e8bc5dSHans de Goede ret = command_setcolourbalance(gspca_dev); 159754e8bc5dSHans de Goede if (ret) 159854e8bc5dSHans de Goede return ret; 159954e8bc5dSHans de Goede ret = command_setsensorfps(gspca_dev); 160054e8bc5dSHans de Goede if (ret) 160154e8bc5dSHans de Goede return ret; 160254e8bc5dSHans de Goede ret = command_setapcor(gspca_dev); 160354e8bc5dSHans de Goede if (ret) 160454e8bc5dSHans de Goede return ret; 160554e8bc5dSHans de Goede ret = command_setflickerctrl(gspca_dev); 160654e8bc5dSHans de Goede if (ret) 160754e8bc5dSHans de Goede return ret; 160854e8bc5dSHans de Goede ret = command_setvloffset(gspca_dev); 160954e8bc5dSHans de Goede if (ret) 161054e8bc5dSHans de Goede return ret; 161154e8bc5dSHans de Goede 161254e8bc5dSHans de Goede /* Start stream */ 161354e8bc5dSHans de Goede ret = command_resume(gspca_dev); 161454e8bc5dSHans de Goede if (ret) 161554e8bc5dSHans de Goede return ret; 161654e8bc5dSHans de Goede 161754e8bc5dSHans de Goede /* Wait 6 frames before turning compression on for the sensor to get 161854e8bc5dSHans de Goede all settings and AEC/ACB to settle */ 161954e8bc5dSHans de Goede sd->first_frame = 6; 162054e8bc5dSHans de Goede sd->exposure_status = EXPOSURE_NORMAL; 162154e8bc5dSHans de Goede sd->exposure_count = 0; 162254e8bc5dSHans de Goede atomic_set(&sd->cam_exposure, 0); 162354e8bc5dSHans de Goede atomic_set(&sd->fps, 0); 162454e8bc5dSHans de Goede 162554e8bc5dSHans de Goede return 0; 162654e8bc5dSHans de Goede } 162754e8bc5dSHans de Goede 162854e8bc5dSHans de Goede static void sd_stopN(struct gspca_dev *gspca_dev) 162954e8bc5dSHans de Goede { 1630c2f644aeSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 1631c2f644aeSHans de Goede 163254e8bc5dSHans de Goede command_pause(gspca_dev); 163354e8bc5dSHans de Goede 163454e8bc5dSHans de Goede /* save camera state for later open (developers guide ch 3.5.3) */ 163554e8bc5dSHans de Goede save_camera_state(gspca_dev); 163654e8bc5dSHans de Goede 163754e8bc5dSHans de Goede /* GotoLoPower */ 163854e8bc5dSHans de Goede goto_low_power(gspca_dev); 163954e8bc5dSHans de Goede 164054e8bc5dSHans de Goede /* Update the camera status */ 164154e8bc5dSHans de Goede do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0); 1642c2f644aeSHans de Goede 1643c2f644aeSHans de Goede #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) 1644c2f644aeSHans de Goede /* If the last button state is pressed, release it now! */ 1645c2f644aeSHans de Goede if (sd->params.qx3.button) { 1646c2f644aeSHans de Goede /* The camera latch will hold the pressed state until we reset 1647c2f644aeSHans de Goede the latch, so we do not reset sd->params.qx3.button now, to 1648c2f644aeSHans de Goede avoid a false keypress being reported the next sd_start */ 1649c2f644aeSHans de Goede input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); 1650c2f644aeSHans de Goede input_sync(gspca_dev->input_dev); 1651c2f644aeSHans de Goede } 1652c2f644aeSHans de Goede #endif 165354e8bc5dSHans de Goede } 165454e8bc5dSHans de Goede 165554e8bc5dSHans de Goede /* this function is called at probe and resume time */ 165654e8bc5dSHans de Goede static int sd_init(struct gspca_dev *gspca_dev) 165754e8bc5dSHans de Goede { 165854e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 165954e8bc5dSHans de Goede int ret; 166054e8bc5dSHans de Goede 166154e8bc5dSHans de Goede /* Start / Stop the camera to make sure we are talking to 166254e8bc5dSHans de Goede a supported camera, and to get some information from it 166354e8bc5dSHans de Goede to print. */ 166454e8bc5dSHans de Goede ret = sd_start(gspca_dev); 166554e8bc5dSHans de Goede if (ret) 166654e8bc5dSHans de Goede return ret; 166754e8bc5dSHans de Goede 166847399d98SAndy Walls /* Ensure the QX3 illuminators' states are restored upon resume, 166947399d98SAndy Walls or disable the illuminator controls, if this isn't a QX3 */ 1670c67be3ccSAndy Walls if (sd->params.qx3.qx3_detected) 1671c67be3ccSAndy Walls command_setlights(gspca_dev); 1672c67be3ccSAndy Walls 167354e8bc5dSHans de Goede sd_stopN(gspca_dev); 167454e8bc5dSHans de Goede 167554e8bc5dSHans de Goede PDEBUG(D_PROBE, "CPIA Version: %d.%02d (%d.%d)", 167654e8bc5dSHans de Goede sd->params.version.firmwareVersion, 167754e8bc5dSHans de Goede sd->params.version.firmwareRevision, 167854e8bc5dSHans de Goede sd->params.version.vcVersion, 167954e8bc5dSHans de Goede sd->params.version.vcRevision); 168054e8bc5dSHans de Goede PDEBUG(D_PROBE, "CPIA PnP-ID: %04x:%04x:%04x", 168154e8bc5dSHans de Goede sd->params.pnpID.vendor, sd->params.pnpID.product, 168254e8bc5dSHans de Goede sd->params.pnpID.deviceRevision); 168354e8bc5dSHans de Goede PDEBUG(D_PROBE, "VP-Version: %d.%d %04x", 168454e8bc5dSHans de Goede sd->params.vpVersion.vpVersion, 168554e8bc5dSHans de Goede sd->params.vpVersion.vpRevision, 168654e8bc5dSHans de Goede sd->params.vpVersion.cameraHeadID); 168754e8bc5dSHans de Goede 168854e8bc5dSHans de Goede return 0; 168954e8bc5dSHans de Goede } 169054e8bc5dSHans de Goede 169154e8bc5dSHans de Goede static void sd_pkt_scan(struct gspca_dev *gspca_dev, 169254e8bc5dSHans de Goede u8 *data, 169354e8bc5dSHans de Goede int len) 169454e8bc5dSHans de Goede { 169554e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 169654e8bc5dSHans de Goede 169754e8bc5dSHans de Goede /* Check for SOF */ 169854e8bc5dSHans de Goede if (len >= 64 && 169954e8bc5dSHans de Goede data[0] == MAGIC_0 && data[1] == MAGIC_1 && 170054e8bc5dSHans de Goede data[16] == sd->params.format.videoSize && 170154e8bc5dSHans de Goede data[17] == sd->params.format.subSample && 170254e8bc5dSHans de Goede data[18] == sd->params.format.yuvOrder && 170354e8bc5dSHans de Goede data[24] == sd->params.roi.colStart && 170454e8bc5dSHans de Goede data[25] == sd->params.roi.colEnd && 170554e8bc5dSHans de Goede data[26] == sd->params.roi.rowStart && 170654e8bc5dSHans de Goede data[27] == sd->params.roi.rowEnd) { 1707b192ca98SJean-François Moine u8 *image; 170854e8bc5dSHans de Goede 170954e8bc5dSHans de Goede atomic_set(&sd->cam_exposure, data[39] * 2); 171054e8bc5dSHans de Goede atomic_set(&sd->fps, data[41]); 171154e8bc5dSHans de Goede 171254e8bc5dSHans de Goede /* Check for proper EOF for last frame */ 1713f7059eaaSJean-François Moine image = gspca_dev->image; 1714f7059eaaSJean-François Moine if (image != NULL && 1715f7059eaaSJean-François Moine gspca_dev->image_len > 4 && 1716b192ca98SJean-François Moine image[gspca_dev->image_len - 4] == 0xff && 1717b192ca98SJean-François Moine image[gspca_dev->image_len - 3] == 0xff && 1718b192ca98SJean-François Moine image[gspca_dev->image_len - 2] == 0xff && 1719b192ca98SJean-François Moine image[gspca_dev->image_len - 1] == 0xff) 172054e8bc5dSHans de Goede gspca_frame_add(gspca_dev, LAST_PACKET, 172154e8bc5dSHans de Goede NULL, 0); 172254e8bc5dSHans de Goede 172354e8bc5dSHans de Goede gspca_frame_add(gspca_dev, FIRST_PACKET, data, len); 172454e8bc5dSHans de Goede return; 172554e8bc5dSHans de Goede } 172654e8bc5dSHans de Goede 172754e8bc5dSHans de Goede gspca_frame_add(gspca_dev, INTER_PACKET, data, len); 172854e8bc5dSHans de Goede } 172954e8bc5dSHans de Goede 173054e8bc5dSHans de Goede static void sd_dq_callback(struct gspca_dev *gspca_dev) 173154e8bc5dSHans de Goede { 173254e8bc5dSHans de Goede struct sd *sd = (struct sd *) gspca_dev; 173354e8bc5dSHans de Goede 173454e8bc5dSHans de Goede /* Set the normal compression settings once we have captured a 173554e8bc5dSHans de Goede few uncompressed frames (and AEC has hopefully settled) */ 173654e8bc5dSHans de Goede if (sd->first_frame) { 173754e8bc5dSHans de Goede sd->first_frame--; 173854e8bc5dSHans de Goede if (sd->first_frame == 0) 173954e8bc5dSHans de Goede command_setcompression(gspca_dev); 174054e8bc5dSHans de Goede } 174154e8bc5dSHans de Goede 174254e8bc5dSHans de Goede /* Switch flicker control back on if it got turned off */ 174354e8bc5dSHans de Goede restart_flicker(gspca_dev); 174454e8bc5dSHans de Goede 174554e8bc5dSHans de Goede /* If AEC is enabled, monitor the exposure and 174654e8bc5dSHans de Goede adjust the sensor frame rate if needed */ 174754e8bc5dSHans de Goede if (sd->params.exposure.expMode == 2) 174854e8bc5dSHans de Goede monitor_exposure(gspca_dev); 174954e8bc5dSHans de Goede 175054e8bc5dSHans de Goede /* Update our knowledge of the camera state */ 175154e8bc5dSHans de Goede do_command(gspca_dev, CPIA_COMMAND_GetExposure, 0, 0, 0, 0); 175254e8bc5dSHans de Goede do_command(gspca_dev, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0); 175354e8bc5dSHans de Goede } 175454e8bc5dSHans de Goede 17551bfea3e4SHans Verkuil static int sd_s_ctrl(struct v4l2_ctrl *ctrl) 175654e8bc5dSHans de Goede { 17571bfea3e4SHans Verkuil struct gspca_dev *gspca_dev = 17581bfea3e4SHans Verkuil container_of(ctrl->handler, struct gspca_dev, ctrl_handler); 175954e8bc5dSHans de Goede struct sd *sd = (struct sd *)gspca_dev; 176054e8bc5dSHans de Goede 17611bfea3e4SHans Verkuil gspca_dev->usb_err = 0; 17621bfea3e4SHans Verkuil 17631bfea3e4SHans Verkuil if (!gspca_dev->streaming && ctrl->id != V4L2_CID_POWER_LINE_FREQUENCY) 17641bfea3e4SHans Verkuil return 0; 17651bfea3e4SHans Verkuil 17661bfea3e4SHans Verkuil switch (ctrl->id) { 17671bfea3e4SHans Verkuil case V4L2_CID_BRIGHTNESS: 17681bfea3e4SHans Verkuil sd->params.colourParams.brightness = ctrl->val; 176954e8bc5dSHans de Goede sd->params.flickerControl.allowableOverExposure = 177054e8bc5dSHans de Goede find_over_exposure(sd->params.colourParams.brightness); 17711bfea3e4SHans Verkuil gspca_dev->usb_err = command_setcolourparams(gspca_dev); 17721bfea3e4SHans Verkuil if (!gspca_dev->usb_err) 17731bfea3e4SHans Verkuil gspca_dev->usb_err = command_setflickerctrl(gspca_dev); 177454e8bc5dSHans de Goede break; 17751bfea3e4SHans Verkuil case V4L2_CID_CONTRAST: 17761bfea3e4SHans Verkuil sd->params.colourParams.contrast = ctrl->val; 17771bfea3e4SHans Verkuil gspca_dev->usb_err = command_setcolourparams(gspca_dev); 177854e8bc5dSHans de Goede break; 17791bfea3e4SHans Verkuil case V4L2_CID_SATURATION: 17801bfea3e4SHans Verkuil sd->params.colourParams.saturation = ctrl->val; 17811bfea3e4SHans Verkuil gspca_dev->usb_err = command_setcolourparams(gspca_dev); 178254e8bc5dSHans de Goede break; 17831bfea3e4SHans Verkuil case V4L2_CID_POWER_LINE_FREQUENCY: 17841bfea3e4SHans Verkuil sd->mainsFreq = ctrl->val == V4L2_CID_POWER_LINE_FREQUENCY_60HZ; 178554e8bc5dSHans de Goede sd->params.flickerControl.coarseJump = 178654e8bc5dSHans de Goede flicker_jumps[sd->mainsFreq] 178754e8bc5dSHans de Goede [sd->params.sensorFps.baserate] 178854e8bc5dSHans de Goede [sd->params.sensorFps.divisor]; 178954e8bc5dSHans de Goede 17901bfea3e4SHans Verkuil gspca_dev->usb_err = set_flicker(gspca_dev, 17911bfea3e4SHans Verkuil ctrl->val != V4L2_CID_POWER_LINE_FREQUENCY_DISABLED, 17921bfea3e4SHans Verkuil gspca_dev->streaming); 17931bfea3e4SHans Verkuil break; 17941bfea3e4SHans Verkuil case V4L2_CID_ILLUMINATORS_1: 17951bfea3e4SHans Verkuil sd->params.qx3.bottomlight = ctrl->val; 17961bfea3e4SHans Verkuil gspca_dev->usb_err = command_setlights(gspca_dev); 17971bfea3e4SHans Verkuil break; 17981bfea3e4SHans Verkuil case V4L2_CID_ILLUMINATORS_2: 17991bfea3e4SHans Verkuil sd->params.qx3.toplight = ctrl->val; 18001bfea3e4SHans Verkuil gspca_dev->usb_err = command_setlights(gspca_dev); 18011bfea3e4SHans Verkuil break; 18021bfea3e4SHans Verkuil case CPIA1_CID_COMP_TARGET: 18031bfea3e4SHans Verkuil sd->params.compressionTarget.frTargeting = ctrl->val; 18041bfea3e4SHans Verkuil gspca_dev->usb_err = command_setcompressiontarget(gspca_dev); 18051bfea3e4SHans Verkuil break; 18061bfea3e4SHans Verkuil } 18071bfea3e4SHans Verkuil return gspca_dev->usb_err; 180854e8bc5dSHans de Goede } 180954e8bc5dSHans de Goede 18101bfea3e4SHans Verkuil static const struct v4l2_ctrl_ops sd_ctrl_ops = { 18111bfea3e4SHans Verkuil .s_ctrl = sd_s_ctrl, 18121bfea3e4SHans Verkuil }; 18131bfea3e4SHans Verkuil 18141bfea3e4SHans Verkuil static int sd_init_controls(struct gspca_dev *gspca_dev) 181554e8bc5dSHans de Goede { 181654e8bc5dSHans de Goede struct sd *sd = (struct sd *)gspca_dev; 18171bfea3e4SHans Verkuil struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; 18181bfea3e4SHans Verkuil static const char * const comp_target_menu[] = { 18191bfea3e4SHans Verkuil "Quality", 18201bfea3e4SHans Verkuil "Framerate", 18211bfea3e4SHans Verkuil NULL 18221bfea3e4SHans Verkuil }; 18231bfea3e4SHans Verkuil static const struct v4l2_ctrl_config comp_target = { 18241bfea3e4SHans Verkuil .ops = &sd_ctrl_ops, 18251bfea3e4SHans Verkuil .id = CPIA1_CID_COMP_TARGET, 18261bfea3e4SHans Verkuil .type = V4L2_CTRL_TYPE_MENU, 18271bfea3e4SHans Verkuil .name = "Compression Target", 18281bfea3e4SHans Verkuil .qmenu = comp_target_menu, 18291bfea3e4SHans Verkuil .max = 1, 18301bfea3e4SHans Verkuil .def = COMP_TARGET_DEF, 18311bfea3e4SHans Verkuil }; 183254e8bc5dSHans de Goede 18331bfea3e4SHans Verkuil gspca_dev->vdev.ctrl_handler = hdl; 18341bfea3e4SHans Verkuil v4l2_ctrl_handler_init(hdl, 7); 18351bfea3e4SHans Verkuil v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 18361bfea3e4SHans Verkuil V4L2_CID_BRIGHTNESS, 0, 100, 1, BRIGHTNESS_DEF); 18371bfea3e4SHans Verkuil v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 18381bfea3e4SHans Verkuil V4L2_CID_CONTRAST, 0, 96, 8, CONTRAST_DEF); 18391bfea3e4SHans Verkuil v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 18401bfea3e4SHans Verkuil V4L2_CID_SATURATION, 0, 100, 1, SATURATION_DEF); 18411bfea3e4SHans Verkuil sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops, 18421bfea3e4SHans Verkuil V4L2_CID_POWER_LINE_FREQUENCY, 18431bfea3e4SHans Verkuil V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0, 18441bfea3e4SHans Verkuil FREQ_DEF); 18451bfea3e4SHans Verkuil if (sd->params.qx3.qx3_detected) { 18461bfea3e4SHans Verkuil v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 18471bfea3e4SHans Verkuil V4L2_CID_ILLUMINATORS_1, 0, 1, 1, 18481bfea3e4SHans Verkuil ILLUMINATORS_1_DEF); 18491bfea3e4SHans Verkuil v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, 18501bfea3e4SHans Verkuil V4L2_CID_ILLUMINATORS_2, 0, 1, 1, 18511bfea3e4SHans Verkuil ILLUMINATORS_2_DEF); 185254e8bc5dSHans de Goede } 18531bfea3e4SHans Verkuil v4l2_ctrl_new_custom(hdl, &comp_target, NULL); 185454e8bc5dSHans de Goede 18551bfea3e4SHans Verkuil if (hdl->error) { 18561bfea3e4SHans Verkuil pr_err("Could not initialize controls\n"); 18571bfea3e4SHans Verkuil return hdl->error; 185851513353SAndy Walls } 185951513353SAndy Walls return 0; 186051513353SAndy Walls } 186151513353SAndy Walls 186254e8bc5dSHans de Goede /* sub-driver description */ 186354e8bc5dSHans de Goede static const struct sd_desc sd_desc = { 186454e8bc5dSHans de Goede .name = MODULE_NAME, 186554e8bc5dSHans de Goede .config = sd_config, 186654e8bc5dSHans de Goede .init = sd_init, 18671bfea3e4SHans Verkuil .init_controls = sd_init_controls, 186854e8bc5dSHans de Goede .start = sd_start, 186954e8bc5dSHans de Goede .stopN = sd_stopN, 187054e8bc5dSHans de Goede .dq_callback = sd_dq_callback, 187154e8bc5dSHans de Goede .pkt_scan = sd_pkt_scan, 1872c2f644aeSHans de Goede #if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) 1873c2f644aeSHans de Goede .other_input = 1, 1874c2f644aeSHans de Goede #endif 187554e8bc5dSHans de Goede }; 187654e8bc5dSHans de Goede 187754e8bc5dSHans de Goede /* -- module initialisation -- */ 187895c967c1SJean-François Moine static const struct usb_device_id device_table[] = { 187954e8bc5dSHans de Goede {USB_DEVICE(0x0553, 0x0002)}, 188054e8bc5dSHans de Goede {USB_DEVICE(0x0813, 0x0001)}, 188154e8bc5dSHans de Goede {} 188254e8bc5dSHans de Goede }; 188354e8bc5dSHans de Goede MODULE_DEVICE_TABLE(usb, device_table); 188454e8bc5dSHans de Goede 188554e8bc5dSHans de Goede /* -- device connect -- */ 188654e8bc5dSHans de Goede static int sd_probe(struct usb_interface *intf, 188754e8bc5dSHans de Goede const struct usb_device_id *id) 188854e8bc5dSHans de Goede { 188954e8bc5dSHans de Goede return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), 189054e8bc5dSHans de Goede THIS_MODULE); 189154e8bc5dSHans de Goede } 189254e8bc5dSHans de Goede 189354e8bc5dSHans de Goede static struct usb_driver sd_driver = { 189454e8bc5dSHans de Goede .name = MODULE_NAME, 189554e8bc5dSHans de Goede .id_table = device_table, 189654e8bc5dSHans de Goede .probe = sd_probe, 189754e8bc5dSHans de Goede .disconnect = gspca_disconnect, 189854e8bc5dSHans de Goede #ifdef CONFIG_PM 189954e8bc5dSHans de Goede .suspend = gspca_suspend, 190054e8bc5dSHans de Goede .resume = gspca_resume, 19018bb58964SHans de Goede .reset_resume = gspca_resume, 190254e8bc5dSHans de Goede #endif 190354e8bc5dSHans de Goede }; 190454e8bc5dSHans de Goede 1905ecb3b2b3SGreg Kroah-Hartman module_usb_driver(sd_driver); 1906