Path: blob/master/drivers/media/video/gspca/cpia1.c
17602 views
/*1* cpia CPiA (1) gspca driver2*3* Copyright (C) 2010-2011 Hans de Goede <[email protected]>4*5* This module is adapted from the in kernel v4l1 cpia driver which is :6*7* (C) Copyright 1999-2000 Peter Pregler8* (C) Copyright 1999-2000 Scott J. Bertin9* (C) Copyright 1999-2000 Johannes Erdfelt <[email protected]>10* (C) Copyright 2000 STMicroelectronics11*12* This program is free software; you can redistribute it and/or modify13* it under the terms of the GNU General Public License as published by14* the Free Software Foundation; either version 2 of the License, or15* (at your option) any later version.16*17* This program is distributed in the hope that it will be useful,18* but WITHOUT ANY WARRANTY; without even the implied warranty of19* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the20* GNU General Public License for more details.21*22* You should have received a copy of the GNU General Public License23* along with this program; if not, write to the Free Software24* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA25*26*/2728#define MODULE_NAME "cpia1"2930#include <linux/input.h>31#include "gspca.h"3233MODULE_AUTHOR("Hans de Goede <[email protected]>");34MODULE_DESCRIPTION("Vision CPiA");35MODULE_LICENSE("GPL");3637/* constant value's */38#define MAGIC_0 0x1939#define MAGIC_1 0x6840#define DATA_IN 0xc041#define DATA_OUT 0x4042#define VIDEOSIZE_QCIF 0 /* 176x144 */43#define VIDEOSIZE_CIF 1 /* 352x288 */44#define SUBSAMPLE_420 045#define SUBSAMPLE_422 146#define YUVORDER_YUYV 047#define YUVORDER_UYVY 148#define NOT_COMPRESSED 049#define COMPRESSED 150#define NO_DECIMATION 051#define DECIMATION_ENAB 152#define EOI 0xff /* End Of Image */53#define EOL 0xfd /* End Of Line */54#define FRAME_HEADER_SIZE 645556/* Image grab modes */57#define CPIA_GRAB_SINGLE 058#define CPIA_GRAB_CONTINEOUS 15960/* Compression parameters */61#define CPIA_COMPRESSION_NONE 062#define CPIA_COMPRESSION_AUTO 163#define CPIA_COMPRESSION_MANUAL 264#define CPIA_COMPRESSION_TARGET_QUALITY 065#define CPIA_COMPRESSION_TARGET_FRAMERATE 16667/* Return offsets for GetCameraState */68#define SYSTEMSTATE 069#define GRABSTATE 170#define STREAMSTATE 271#define FATALERROR 372#define CMDERROR 473#define DEBUGFLAGS 574#define VPSTATUS 675#define ERRORCODE 77677/* SystemState */78#define UNINITIALISED_STATE 079#define PASS_THROUGH_STATE 180#define LO_POWER_STATE 281#define HI_POWER_STATE 382#define WARM_BOOT_STATE 48384/* GrabState */85#define GRAB_IDLE 086#define GRAB_ACTIVE 187#define GRAB_DONE 28889/* StreamState */90#define STREAM_NOT_READY 091#define STREAM_READY 192#define STREAM_OPEN 293#define STREAM_PAUSED 394#define STREAM_FINISHED 49596/* Fatal Error, CmdError, and DebugFlags */97#define CPIA_FLAG 198#define SYSTEM_FLAG 299#define INT_CTRL_FLAG 4100#define PROCESS_FLAG 8101#define COM_FLAG 16102#define VP_CTRL_FLAG 32103#define CAPTURE_FLAG 64104#define DEBUG_FLAG 128105106/* VPStatus */107#define VP_STATE_OK 0x00108109#define VP_STATE_FAILED_VIDEOINIT 0x01110#define VP_STATE_FAILED_AECACBINIT 0x02111#define VP_STATE_AEC_MAX 0x04112#define VP_STATE_ACB_BMAX 0x08113114#define VP_STATE_ACB_RMIN 0x10115#define VP_STATE_ACB_GMIN 0x20116#define VP_STATE_ACB_RMAX 0x40117#define VP_STATE_ACB_GMAX 0x80118119/* default (minimum) compensation values */120#define COMP_RED 220121#define COMP_GREEN1 214122#define COMP_GREEN2 COMP_GREEN1123#define COMP_BLUE 230124125/* exposure status */126#define EXPOSURE_VERY_LIGHT 0127#define EXPOSURE_LIGHT 1128#define EXPOSURE_NORMAL 2129#define EXPOSURE_DARK 3130#define EXPOSURE_VERY_DARK 4131132#define CPIA_MODULE_CPIA (0 << 5)133#define CPIA_MODULE_SYSTEM (1 << 5)134#define CPIA_MODULE_VP_CTRL (5 << 5)135#define CPIA_MODULE_CAPTURE (6 << 5)136#define CPIA_MODULE_DEBUG (7 << 5)137138#define INPUT (DATA_IN << 8)139#define OUTPUT (DATA_OUT << 8)140141#define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)142#define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)143#define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)144#define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)145#define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)146#define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)147#define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)148#define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)149150#define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)151#define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)152#define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)153#define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)154#define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)155#define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)156#define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)157#define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)158#define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)159#define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)160#define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)161#define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)162#define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)163164#define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)165#define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2)166#define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)167#define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)168#define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)169#define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)170#define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)171#define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)172#define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)173#define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)174#define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)175#define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)176#define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)177#define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)178#define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)179#define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)180#define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)181182#define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)183#define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)184#define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)185#define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)186#define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)187#define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)188#define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)189#define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)190#define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)191#define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)192#define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)193#define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)194#define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)195#define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)196#define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15)197198#define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)199#define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)200#define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)201#define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)202#define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)203#define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)204#define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)205#define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11)206207#define ROUND_UP_EXP_FOR_FLICKER 15208209/* Constants for automatic frame rate adjustment */210#define MAX_EXP 302211#define MAX_EXP_102 255212#define LOW_EXP 140213#define VERY_LOW_EXP 70214#define TC 94215#define EXP_ACC_DARK 50216#define EXP_ACC_LIGHT 90217#define HIGH_COMP_102 160218#define MAX_COMP 239219#define DARK_TIME 3220#define LIGHT_TIME 3221222#define FIRMWARE_VERSION(x, y) (sd->params.version.firmwareVersion == (x) && \223sd->params.version.firmwareRevision == (y))224225/* Developer's Guide Table 5 p 3-34226* indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/227static u8 flicker_jumps[2][2][4] =228{ { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },229{ { 64, 32, 16, 8 }, { 76, 38, 19, 9} }230};231232struct cam_params {233struct {234u8 firmwareVersion;235u8 firmwareRevision;236u8 vcVersion;237u8 vcRevision;238} version;239struct {240u16 vendor;241u16 product;242u16 deviceRevision;243} pnpID;244struct {245u8 vpVersion;246u8 vpRevision;247u16 cameraHeadID;248} vpVersion;249struct {250u8 systemState;251u8 grabState;252u8 streamState;253u8 fatalError;254u8 cmdError;255u8 debugFlags;256u8 vpStatus;257u8 errorCode;258} status;259struct {260u8 brightness;261u8 contrast;262u8 saturation;263} colourParams;264struct {265u8 gainMode;266u8 expMode;267u8 compMode;268u8 centreWeight;269u8 gain;270u8 fineExp;271u8 coarseExpLo;272u8 coarseExpHi;273u8 redComp;274u8 green1Comp;275u8 green2Comp;276u8 blueComp;277} exposure;278struct {279u8 balanceMode;280u8 redGain;281u8 greenGain;282u8 blueGain;283} colourBalance;284struct {285u8 divisor;286u8 baserate;287} sensorFps;288struct {289u8 gain1;290u8 gain2;291u8 gain4;292u8 gain8;293} apcor;294struct {295u8 disabled;296u8 flickerMode;297u8 coarseJump;298u8 allowableOverExposure;299} flickerControl;300struct {301u8 gain1;302u8 gain2;303u8 gain4;304u8 gain8;305} vlOffset;306struct {307u8 mode;308u8 decimation;309} compression;310struct {311u8 frTargeting;312u8 targetFR;313u8 targetQ;314} compressionTarget;315struct {316u8 yThreshold;317u8 uvThreshold;318} yuvThreshold;319struct {320u8 hysteresis;321u8 threshMax;322u8 smallStep;323u8 largeStep;324u8 decimationHysteresis;325u8 frDiffStepThresh;326u8 qDiffStepThresh;327u8 decimationThreshMod;328} compressionParams;329struct {330u8 videoSize; /* CIF/QCIF */331u8 subSample;332u8 yuvOrder;333} format;334struct { /* Intel QX3 specific data */335u8 qx3_detected; /* a QX3 is present */336u8 toplight; /* top light lit , R/W */337u8 bottomlight; /* bottom light lit, R/W */338u8 button; /* snapshot button pressed (R/O) */339u8 cradled; /* microscope is in cradle (R/O) */340} qx3;341struct {342u8 colStart; /* skip first 8*colStart pixels */343u8 colEnd; /* finish at 8*colEnd pixels */344u8 rowStart; /* skip first 4*rowStart lines */345u8 rowEnd; /* finish at 4*rowEnd lines */346} roi;347u8 ecpTiming;348u8 streamStartLine;349};350351/* specific webcam descriptor */352struct sd {353struct gspca_dev gspca_dev; /* !! must be the first item */354struct cam_params params; /* camera settings */355356atomic_t cam_exposure;357atomic_t fps;358int exposure_count;359u8 exposure_status;360u8 mainsFreq; /* 0 = 50hz, 1 = 60hz */361u8 first_frame;362u8 freq;363};364365/* V4L2 controls supported by the driver */366static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);367static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);368static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);369static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);370static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val);371static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val);372static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);373static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);374static int sd_setcomptarget(struct gspca_dev *gspca_dev, __s32 val);375static int sd_getcomptarget(struct gspca_dev *gspca_dev, __s32 *val);376static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val);377static int sd_getilluminator1(struct gspca_dev *gspca_dev, __s32 *val);378static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val);379static int sd_getilluminator2(struct gspca_dev *gspca_dev, __s32 *val);380381static const struct ctrl sd_ctrls[] = {382{383#define BRIGHTNESS_IDX 0384{385.id = V4L2_CID_BRIGHTNESS,386.type = V4L2_CTRL_TYPE_INTEGER,387.name = "Brightness",388.minimum = 0,389.maximum = 100,390.step = 1,391#define BRIGHTNESS_DEF 50392.default_value = BRIGHTNESS_DEF,393.flags = 0,394},395.set = sd_setbrightness,396.get = sd_getbrightness,397},398#define CONTRAST_IDX 1399{400{401.id = V4L2_CID_CONTRAST,402.type = V4L2_CTRL_TYPE_INTEGER,403.name = "Contrast",404.minimum = 0,405.maximum = 96,406.step = 8,407#define CONTRAST_DEF 48408.default_value = CONTRAST_DEF,409},410.set = sd_setcontrast,411.get = sd_getcontrast,412},413#define SATURATION_IDX 2414{415{416.id = V4L2_CID_SATURATION,417.type = V4L2_CTRL_TYPE_INTEGER,418.name = "Saturation",419.minimum = 0,420.maximum = 100,421.step = 1,422#define SATURATION_DEF 50423.default_value = SATURATION_DEF,424},425.set = sd_setsaturation,426.get = sd_getsaturation,427},428#define POWER_LINE_FREQUENCY_IDX 3429{430{431.id = V4L2_CID_POWER_LINE_FREQUENCY,432.type = V4L2_CTRL_TYPE_MENU,433.name = "Light frequency filter",434.minimum = 0,435.maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */436.step = 1,437#define FREQ_DEF 1438.default_value = FREQ_DEF,439},440.set = sd_setfreq,441.get = sd_getfreq,442},443#define ILLUMINATORS_1_IDX 4444{445{446.id = V4L2_CID_ILLUMINATORS_1,447.type = V4L2_CTRL_TYPE_BOOLEAN,448.name = "Illuminator 1",449.minimum = 0,450.maximum = 1,451.step = 1,452#define ILLUMINATORS_1_DEF 0453.default_value = ILLUMINATORS_1_DEF,454},455.set = sd_setilluminator1,456.get = sd_getilluminator1,457},458#define ILLUMINATORS_2_IDX 5459{460{461.id = V4L2_CID_ILLUMINATORS_2,462.type = V4L2_CTRL_TYPE_BOOLEAN,463.name = "Illuminator 2",464.minimum = 0,465.maximum = 1,466.step = 1,467#define ILLUMINATORS_2_DEF 0468.default_value = ILLUMINATORS_2_DEF,469},470.set = sd_setilluminator2,471.get = sd_getilluminator2,472},473#define COMP_TARGET_IDX 6474{475{476#define V4L2_CID_COMP_TARGET V4L2_CID_PRIVATE_BASE477.id = V4L2_CID_COMP_TARGET,478.type = V4L2_CTRL_TYPE_MENU,479.name = "Compression Target",480.minimum = 0,481.maximum = 1,482.step = 1,483#define COMP_TARGET_DEF CPIA_COMPRESSION_TARGET_QUALITY484.default_value = COMP_TARGET_DEF,485},486.set = sd_setcomptarget,487.get = sd_getcomptarget,488},489};490491static const struct v4l2_pix_format mode[] = {492{160, 120, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE,493/* The sizeimage is trial and error, as with low framerates494the camera will pad out usb frames, making the image495data larger then strictly necessary */496.bytesperline = 160,497.sizeimage = 65536,498.colorspace = V4L2_COLORSPACE_SRGB,499.priv = 3},500{176, 144, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE,501.bytesperline = 172,502.sizeimage = 65536,503.colorspace = V4L2_COLORSPACE_SRGB,504.priv = 2},505{320, 240, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE,506.bytesperline = 320,507.sizeimage = 262144,508.colorspace = V4L2_COLORSPACE_SRGB,509.priv = 1},510{352, 288, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE,511.bytesperline = 352,512.sizeimage = 262144,513.colorspace = V4L2_COLORSPACE_SRGB,514.priv = 0},515};516517/**********************************************************************518*519* General functions520*521**********************************************************************/522523static int cpia_usb_transferCmd(struct gspca_dev *gspca_dev, u8 *command)524{525u8 requesttype;526unsigned int pipe;527int ret, databytes = command[6] | (command[7] << 8);528/* Sometimes we see spurious EPIPE errors */529int retries = 3;530531if (command[0] == DATA_IN) {532pipe = usb_rcvctrlpipe(gspca_dev->dev, 0);533requesttype = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE;534} else if (command[0] == DATA_OUT) {535pipe = usb_sndctrlpipe(gspca_dev->dev, 0);536requesttype = USB_TYPE_VENDOR | USB_RECIP_DEVICE;537} else {538PDEBUG(D_ERR, "Unexpected first byte of command: %x",539command[0]);540return -EINVAL;541}542543retry:544ret = usb_control_msg(gspca_dev->dev, pipe,545command[1],546requesttype,547command[2] | (command[3] << 8),548command[4] | (command[5] << 8),549gspca_dev->usb_buf, databytes, 1000);550551if (ret < 0)552err("usb_control_msg %02x, error %d", command[1],553ret);554555if (ret == -EPIPE && retries > 0) {556retries--;557goto retry;558}559560return (ret < 0) ? ret : 0;561}562563/* send an arbitrary command to the camera */564static int do_command(struct gspca_dev *gspca_dev, u16 command,565u8 a, u8 b, u8 c, u8 d)566{567struct sd *sd = (struct sd *) gspca_dev;568int ret, datasize;569u8 cmd[8];570571switch (command) {572case CPIA_COMMAND_GetCPIAVersion:573case CPIA_COMMAND_GetPnPID:574case CPIA_COMMAND_GetCameraStatus:575case CPIA_COMMAND_GetVPVersion:576case CPIA_COMMAND_GetColourParams:577case CPIA_COMMAND_GetColourBalance:578case CPIA_COMMAND_GetExposure:579datasize = 8;580break;581case CPIA_COMMAND_ReadMCPorts:582case CPIA_COMMAND_ReadVCRegs:583datasize = 4;584break;585default:586datasize = 0;587break;588}589590cmd[0] = command >> 8;591cmd[1] = command & 0xff;592cmd[2] = a;593cmd[3] = b;594cmd[4] = c;595cmd[5] = d;596cmd[6] = datasize;597cmd[7] = 0;598599ret = cpia_usb_transferCmd(gspca_dev, cmd);600if (ret)601return ret;602603switch (command) {604case CPIA_COMMAND_GetCPIAVersion:605sd->params.version.firmwareVersion = gspca_dev->usb_buf[0];606sd->params.version.firmwareRevision = gspca_dev->usb_buf[1];607sd->params.version.vcVersion = gspca_dev->usb_buf[2];608sd->params.version.vcRevision = gspca_dev->usb_buf[3];609break;610case CPIA_COMMAND_GetPnPID:611sd->params.pnpID.vendor =612gspca_dev->usb_buf[0] | (gspca_dev->usb_buf[1] << 8);613sd->params.pnpID.product =614gspca_dev->usb_buf[2] | (gspca_dev->usb_buf[3] << 8);615sd->params.pnpID.deviceRevision =616gspca_dev->usb_buf[4] | (gspca_dev->usb_buf[5] << 8);617break;618case CPIA_COMMAND_GetCameraStatus:619sd->params.status.systemState = gspca_dev->usb_buf[0];620sd->params.status.grabState = gspca_dev->usb_buf[1];621sd->params.status.streamState = gspca_dev->usb_buf[2];622sd->params.status.fatalError = gspca_dev->usb_buf[3];623sd->params.status.cmdError = gspca_dev->usb_buf[4];624sd->params.status.debugFlags = gspca_dev->usb_buf[5];625sd->params.status.vpStatus = gspca_dev->usb_buf[6];626sd->params.status.errorCode = gspca_dev->usb_buf[7];627break;628case CPIA_COMMAND_GetVPVersion:629sd->params.vpVersion.vpVersion = gspca_dev->usb_buf[0];630sd->params.vpVersion.vpRevision = gspca_dev->usb_buf[1];631sd->params.vpVersion.cameraHeadID =632gspca_dev->usb_buf[2] | (gspca_dev->usb_buf[3] << 8);633break;634case CPIA_COMMAND_GetColourParams:635sd->params.colourParams.brightness = gspca_dev->usb_buf[0];636sd->params.colourParams.contrast = gspca_dev->usb_buf[1];637sd->params.colourParams.saturation = gspca_dev->usb_buf[2];638break;639case CPIA_COMMAND_GetColourBalance:640sd->params.colourBalance.redGain = gspca_dev->usb_buf[0];641sd->params.colourBalance.greenGain = gspca_dev->usb_buf[1];642sd->params.colourBalance.blueGain = gspca_dev->usb_buf[2];643break;644case CPIA_COMMAND_GetExposure:645sd->params.exposure.gain = gspca_dev->usb_buf[0];646sd->params.exposure.fineExp = gspca_dev->usb_buf[1];647sd->params.exposure.coarseExpLo = gspca_dev->usb_buf[2];648sd->params.exposure.coarseExpHi = gspca_dev->usb_buf[3];649sd->params.exposure.redComp = gspca_dev->usb_buf[4];650sd->params.exposure.green1Comp = gspca_dev->usb_buf[5];651sd->params.exposure.green2Comp = gspca_dev->usb_buf[6];652sd->params.exposure.blueComp = gspca_dev->usb_buf[7];653break;654655case CPIA_COMMAND_ReadMCPorts:656/* test button press */657a = ((gspca_dev->usb_buf[1] & 0x02) == 0);658if (a != sd->params.qx3.button) {659#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)660input_report_key(gspca_dev->input_dev, KEY_CAMERA, a);661input_sync(gspca_dev->input_dev);662#endif663sd->params.qx3.button = a;664}665if (sd->params.qx3.button) {666/* button pressed - unlock the latch */667do_command(gspca_dev, CPIA_COMMAND_WriteMCPort,6683, 0xdf, 0xdf, 0);669do_command(gspca_dev, CPIA_COMMAND_WriteMCPort,6703, 0xff, 0xff, 0);671}672673/* test whether microscope is cradled */674sd->params.qx3.cradled = ((gspca_dev->usb_buf[2] & 0x40) == 0);675break;676}677678return 0;679}680681/* send a command to the camera with an additional data transaction */682static int do_command_extended(struct gspca_dev *gspca_dev, u16 command,683u8 a, u8 b, u8 c, u8 d,684u8 e, u8 f, u8 g, u8 h,685u8 i, u8 j, u8 k, u8 l)686{687u8 cmd[8];688689cmd[0] = command >> 8;690cmd[1] = command & 0xff;691cmd[2] = a;692cmd[3] = b;693cmd[4] = c;694cmd[5] = d;695cmd[6] = 8;696cmd[7] = 0;697gspca_dev->usb_buf[0] = e;698gspca_dev->usb_buf[1] = f;699gspca_dev->usb_buf[2] = g;700gspca_dev->usb_buf[3] = h;701gspca_dev->usb_buf[4] = i;702gspca_dev->usb_buf[5] = j;703gspca_dev->usb_buf[6] = k;704gspca_dev->usb_buf[7] = l;705706return cpia_usb_transferCmd(gspca_dev, cmd);707}708709/* find_over_exposure710* Finds a suitable value of OverExposure for use with SetFlickerCtrl711* Some calculation is required because this value changes with the brightness712* set with SetColourParameters713*714* Parameters: Brightness - last brightness value set with SetColourParameters715*716* Returns: OverExposure value to use with SetFlickerCtrl717*/718#define FLICKER_MAX_EXPOSURE 250719#define FLICKER_ALLOWABLE_OVER_EXPOSURE 146720#define FLICKER_BRIGHTNESS_CONSTANT 59721static int find_over_exposure(int brightness)722{723int MaxAllowableOverExposure, OverExposure;724725MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness -726FLICKER_BRIGHTNESS_CONSTANT;727728if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE)729OverExposure = MaxAllowableOverExposure;730else731OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE;732733return OverExposure;734}735#undef FLICKER_MAX_EXPOSURE736#undef FLICKER_ALLOWABLE_OVER_EXPOSURE737#undef FLICKER_BRIGHTNESS_CONSTANT738739/* initialise cam_data structure */740static void reset_camera_params(struct gspca_dev *gspca_dev)741{742struct sd *sd = (struct sd *) gspca_dev;743struct cam_params *params = &sd->params;744745/* The following parameter values are the defaults from746* "Software Developer's Guide for CPiA Cameras". Any changes747* to the defaults are noted in comments. */748params->colourParams.brightness = BRIGHTNESS_DEF;749params->colourParams.contrast = CONTRAST_DEF;750params->colourParams.saturation = SATURATION_DEF;751params->exposure.gainMode = 4;752params->exposure.expMode = 2; /* AEC */753params->exposure.compMode = 1;754params->exposure.centreWeight = 1;755params->exposure.gain = 0;756params->exposure.fineExp = 0;757params->exposure.coarseExpLo = 185;758params->exposure.coarseExpHi = 0;759params->exposure.redComp = COMP_RED;760params->exposure.green1Comp = COMP_GREEN1;761params->exposure.green2Comp = COMP_GREEN2;762params->exposure.blueComp = COMP_BLUE;763params->colourBalance.balanceMode = 2; /* ACB */764params->colourBalance.redGain = 32;765params->colourBalance.greenGain = 6;766params->colourBalance.blueGain = 92;767params->apcor.gain1 = 0x18;768params->apcor.gain2 = 0x16;769params->apcor.gain4 = 0x24;770params->apcor.gain8 = 0x34;771params->flickerControl.flickerMode = 0;772params->flickerControl.disabled = 1;773774params->flickerControl.coarseJump =775flicker_jumps[sd->mainsFreq]776[params->sensorFps.baserate]777[params->sensorFps.divisor];778params->flickerControl.allowableOverExposure =779find_over_exposure(params->colourParams.brightness);780params->vlOffset.gain1 = 20;781params->vlOffset.gain2 = 24;782params->vlOffset.gain4 = 26;783params->vlOffset.gain8 = 26;784params->compressionParams.hysteresis = 3;785params->compressionParams.threshMax = 11;786params->compressionParams.smallStep = 1;787params->compressionParams.largeStep = 3;788params->compressionParams.decimationHysteresis = 2;789params->compressionParams.frDiffStepThresh = 5;790params->compressionParams.qDiffStepThresh = 3;791params->compressionParams.decimationThreshMod = 2;792/* End of default values from Software Developer's Guide */793794/* Set Sensor FPS to 15fps. This seems better than 30fps795* for indoor lighting. */796params->sensorFps.divisor = 1;797params->sensorFps.baserate = 1;798799params->yuvThreshold.yThreshold = 6; /* From windows driver */800params->yuvThreshold.uvThreshold = 6; /* From windows driver */801802params->format.subSample = SUBSAMPLE_420;803params->format.yuvOrder = YUVORDER_YUYV;804805params->compression.mode = CPIA_COMPRESSION_AUTO;806params->compression.decimation = NO_DECIMATION;807808params->compressionTarget.frTargeting = COMP_TARGET_DEF;809params->compressionTarget.targetFR = 15; /* From windows driver */810params->compressionTarget.targetQ = 5; /* From windows driver */811812params->qx3.qx3_detected = 0;813params->qx3.toplight = 0;814params->qx3.bottomlight = 0;815params->qx3.button = 0;816params->qx3.cradled = 0;817}818819static void printstatus(struct cam_params *params)820{821PDEBUG(D_PROBE, "status: %02x %02x %02x %02x %02x %02x %02x %02x",822params->status.systemState, params->status.grabState,823params->status.streamState, params->status.fatalError,824params->status.cmdError, params->status.debugFlags,825params->status.vpStatus, params->status.errorCode);826}827828static int goto_low_power(struct gspca_dev *gspca_dev)829{830struct sd *sd = (struct sd *) gspca_dev;831int ret;832833ret = do_command(gspca_dev, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0);834if (ret)835return ret;836837ret = do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);838if (ret)839return ret;840841if (sd->params.status.systemState != LO_POWER_STATE) {842if (sd->params.status.systemState != WARM_BOOT_STATE) {843PDEBUG(D_ERR,844"unexpected state after lo power cmd: %02x",845sd->params.status.systemState);846printstatus(&sd->params);847}848return -EIO;849}850851PDEBUG(D_CONF, "camera now in LOW power state");852return 0;853}854855static int goto_high_power(struct gspca_dev *gspca_dev)856{857struct sd *sd = (struct sd *) gspca_dev;858int ret;859860ret = do_command(gspca_dev, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0);861if (ret)862return ret;863864msleep_interruptible(40); /* windows driver does it too */865866if (signal_pending(current))867return -EINTR;868869do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);870if (ret)871return ret;872873if (sd->params.status.systemState != HI_POWER_STATE) {874PDEBUG(D_ERR, "unexpected state after hi power cmd: %02x",875sd->params.status.systemState);876printstatus(&sd->params);877return -EIO;878}879880PDEBUG(D_CONF, "camera now in HIGH power state");881return 0;882}883884static int get_version_information(struct gspca_dev *gspca_dev)885{886int ret;887888/* GetCPIAVersion */889ret = do_command(gspca_dev, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);890if (ret)891return ret;892893/* GetPnPID */894return do_command(gspca_dev, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);895}896897static int save_camera_state(struct gspca_dev *gspca_dev)898{899int ret;900901ret = do_command(gspca_dev, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);902if (ret)903return ret;904905return do_command(gspca_dev, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);906}907908static int command_setformat(struct gspca_dev *gspca_dev)909{910struct sd *sd = (struct sd *) gspca_dev;911int ret;912913ret = do_command(gspca_dev, CPIA_COMMAND_SetFormat,914sd->params.format.videoSize,915sd->params.format.subSample,916sd->params.format.yuvOrder, 0);917if (ret)918return ret;919920return do_command(gspca_dev, CPIA_COMMAND_SetROI,921sd->params.roi.colStart, sd->params.roi.colEnd,922sd->params.roi.rowStart, sd->params.roi.rowEnd);923}924925static int command_setcolourparams(struct gspca_dev *gspca_dev)926{927struct sd *sd = (struct sd *) gspca_dev;928return do_command(gspca_dev, CPIA_COMMAND_SetColourParams,929sd->params.colourParams.brightness,930sd->params.colourParams.contrast,931sd->params.colourParams.saturation, 0);932}933934static int command_setapcor(struct gspca_dev *gspca_dev)935{936struct sd *sd = (struct sd *) gspca_dev;937return do_command(gspca_dev, CPIA_COMMAND_SetApcor,938sd->params.apcor.gain1,939sd->params.apcor.gain2,940sd->params.apcor.gain4,941sd->params.apcor.gain8);942}943944static int command_setvloffset(struct gspca_dev *gspca_dev)945{946struct sd *sd = (struct sd *) gspca_dev;947return do_command(gspca_dev, CPIA_COMMAND_SetVLOffset,948sd->params.vlOffset.gain1,949sd->params.vlOffset.gain2,950sd->params.vlOffset.gain4,951sd->params.vlOffset.gain8);952}953954static int command_setexposure(struct gspca_dev *gspca_dev)955{956struct sd *sd = (struct sd *) gspca_dev;957int ret;958959ret = do_command_extended(gspca_dev, CPIA_COMMAND_SetExposure,960sd->params.exposure.gainMode,9611,962sd->params.exposure.compMode,963sd->params.exposure.centreWeight,964sd->params.exposure.gain,965sd->params.exposure.fineExp,966sd->params.exposure.coarseExpLo,967sd->params.exposure.coarseExpHi,968sd->params.exposure.redComp,969sd->params.exposure.green1Comp,970sd->params.exposure.green2Comp,971sd->params.exposure.blueComp);972if (ret)973return ret;974975if (sd->params.exposure.expMode != 1) {976ret = do_command_extended(gspca_dev, CPIA_COMMAND_SetExposure,9770,978sd->params.exposure.expMode,9790, 0,980sd->params.exposure.gain,981sd->params.exposure.fineExp,982sd->params.exposure.coarseExpLo,983sd->params.exposure.coarseExpHi,9840, 0, 0, 0);985}986987return ret;988}989990static int command_setcolourbalance(struct gspca_dev *gspca_dev)991{992struct sd *sd = (struct sd *) gspca_dev;993994if (sd->params.colourBalance.balanceMode == 1) {995int ret;996997ret = do_command(gspca_dev, CPIA_COMMAND_SetColourBalance,9981,999sd->params.colourBalance.redGain,1000sd->params.colourBalance.greenGain,1001sd->params.colourBalance.blueGain);1002if (ret)1003return ret;10041005return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance,10063, 0, 0, 0);1007}1008if (sd->params.colourBalance.balanceMode == 2) {1009return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance,10102, 0, 0, 0);1011}1012if (sd->params.colourBalance.balanceMode == 3) {1013return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance,10143, 0, 0, 0);1015}10161017return -EINVAL;1018}10191020static int command_setcompressiontarget(struct gspca_dev *gspca_dev)1021{1022struct sd *sd = (struct sd *) gspca_dev;10231024return do_command(gspca_dev, CPIA_COMMAND_SetCompressionTarget,1025sd->params.compressionTarget.frTargeting,1026sd->params.compressionTarget.targetFR,1027sd->params.compressionTarget.targetQ, 0);1028}10291030static int command_setyuvtresh(struct gspca_dev *gspca_dev)1031{1032struct sd *sd = (struct sd *) gspca_dev;10331034return do_command(gspca_dev, CPIA_COMMAND_SetYUVThresh,1035sd->params.yuvThreshold.yThreshold,1036sd->params.yuvThreshold.uvThreshold, 0, 0);1037}10381039static int command_setcompressionparams(struct gspca_dev *gspca_dev)1040{1041struct sd *sd = (struct sd *) gspca_dev;10421043return do_command_extended(gspca_dev,1044CPIA_COMMAND_SetCompressionParams,10450, 0, 0, 0,1046sd->params.compressionParams.hysteresis,1047sd->params.compressionParams.threshMax,1048sd->params.compressionParams.smallStep,1049sd->params.compressionParams.largeStep,1050sd->params.compressionParams.decimationHysteresis,1051sd->params.compressionParams.frDiffStepThresh,1052sd->params.compressionParams.qDiffStepThresh,1053sd->params.compressionParams.decimationThreshMod);1054}10551056static int command_setcompression(struct gspca_dev *gspca_dev)1057{1058struct sd *sd = (struct sd *) gspca_dev;10591060return do_command(gspca_dev, CPIA_COMMAND_SetCompression,1061sd->params.compression.mode,1062sd->params.compression.decimation, 0, 0);1063}10641065static int command_setsensorfps(struct gspca_dev *gspca_dev)1066{1067struct sd *sd = (struct sd *) gspca_dev;10681069return do_command(gspca_dev, CPIA_COMMAND_SetSensorFPS,1070sd->params.sensorFps.divisor,1071sd->params.sensorFps.baserate, 0, 0);1072}10731074static int command_setflickerctrl(struct gspca_dev *gspca_dev)1075{1076struct sd *sd = (struct sd *) gspca_dev;10771078return do_command(gspca_dev, CPIA_COMMAND_SetFlickerCtrl,1079sd->params.flickerControl.flickerMode,1080sd->params.flickerControl.coarseJump,1081sd->params.flickerControl.allowableOverExposure,10820);1083}10841085static int command_setecptiming(struct gspca_dev *gspca_dev)1086{1087struct sd *sd = (struct sd *) gspca_dev;10881089return do_command(gspca_dev, CPIA_COMMAND_SetECPTiming,1090sd->params.ecpTiming, 0, 0, 0);1091}10921093static int command_pause(struct gspca_dev *gspca_dev)1094{1095return do_command(gspca_dev, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);1096}10971098static int command_resume(struct gspca_dev *gspca_dev)1099{1100struct sd *sd = (struct sd *) gspca_dev;11011102return do_command(gspca_dev, CPIA_COMMAND_InitStreamCap,11030, sd->params.streamStartLine, 0, 0);1104}11051106static int command_setlights(struct gspca_dev *gspca_dev)1107{1108struct sd *sd = (struct sd *) gspca_dev;1109int ret, p1, p2;11101111if (!sd->params.qx3.qx3_detected)1112return 0;11131114p1 = (sd->params.qx3.bottomlight == 0) << 1;1115p2 = (sd->params.qx3.toplight == 0) << 3;11161117ret = do_command(gspca_dev, CPIA_COMMAND_WriteVCReg,11180x90, 0x8f, 0x50, 0);1119if (ret)1120return ret;11211122return do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, 2, 0,1123p1 | p2 | 0xe0, 0);1124}11251126static int set_flicker(struct gspca_dev *gspca_dev, int on, int apply)1127{1128/* Everything in here is from the Windows driver */1129/* define for compgain calculation */1130#if 01131#define COMPGAIN(base, curexp, newexp) \1132(u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5)1133#define EXP_FROM_COMP(basecomp, curcomp, curexp) \1134(u16)((float)curexp * (float)(u8)(curcomp + 128) / \1135(float)(u8)(basecomp - 128))1136#else1137/* equivalent functions without floating point math */1138#define COMPGAIN(base, curexp, newexp) \1139(u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2 * newexp)))1140#define EXP_FROM_COMP(basecomp, curcomp, curexp) \1141(u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128)))1142#endif11431144struct sd *sd = (struct sd *) gspca_dev;1145int currentexp = sd->params.exposure.coarseExpLo +1146sd->params.exposure.coarseExpHi * 256;1147int ret, startexp;11481149if (on) {1150int cj = sd->params.flickerControl.coarseJump;1151sd->params.flickerControl.flickerMode = 1;1152sd->params.flickerControl.disabled = 0;1153if (sd->params.exposure.expMode != 2) {1154sd->params.exposure.expMode = 2;1155sd->exposure_status = EXPOSURE_NORMAL;1156}1157currentexp = currentexp << sd->params.exposure.gain;1158sd->params.exposure.gain = 0;1159/* round down current exposure to nearest value */1160startexp = (currentexp + ROUND_UP_EXP_FOR_FLICKER) / cj;1161if (startexp < 1)1162startexp = 1;1163startexp = (startexp * cj) - 1;1164if (FIRMWARE_VERSION(1, 2))1165while (startexp > MAX_EXP_102)1166startexp -= cj;1167else1168while (startexp > MAX_EXP)1169startexp -= cj;1170sd->params.exposure.coarseExpLo = startexp & 0xff;1171sd->params.exposure.coarseExpHi = startexp >> 8;1172if (currentexp > startexp) {1173if (currentexp > (2 * startexp))1174currentexp = 2 * startexp;1175sd->params.exposure.redComp =1176COMPGAIN(COMP_RED, currentexp, startexp);1177sd->params.exposure.green1Comp =1178COMPGAIN(COMP_GREEN1, currentexp, startexp);1179sd->params.exposure.green2Comp =1180COMPGAIN(COMP_GREEN2, currentexp, startexp);1181sd->params.exposure.blueComp =1182COMPGAIN(COMP_BLUE, currentexp, startexp);1183} else {1184sd->params.exposure.redComp = COMP_RED;1185sd->params.exposure.green1Comp = COMP_GREEN1;1186sd->params.exposure.green2Comp = COMP_GREEN2;1187sd->params.exposure.blueComp = COMP_BLUE;1188}1189if (FIRMWARE_VERSION(1, 2))1190sd->params.exposure.compMode = 0;1191else1192sd->params.exposure.compMode = 1;11931194sd->params.apcor.gain1 = 0x18;1195sd->params.apcor.gain2 = 0x18;1196sd->params.apcor.gain4 = 0x16;1197sd->params.apcor.gain8 = 0x14;1198} else {1199sd->params.flickerControl.flickerMode = 0;1200sd->params.flickerControl.disabled = 1;1201/* Average equivalent coarse for each comp channel */1202startexp = EXP_FROM_COMP(COMP_RED,1203sd->params.exposure.redComp, currentexp);1204startexp += EXP_FROM_COMP(COMP_GREEN1,1205sd->params.exposure.green1Comp, currentexp);1206startexp += EXP_FROM_COMP(COMP_GREEN2,1207sd->params.exposure.green2Comp, currentexp);1208startexp += EXP_FROM_COMP(COMP_BLUE,1209sd->params.exposure.blueComp, currentexp);1210startexp = startexp >> 2;1211while (startexp > MAX_EXP && sd->params.exposure.gain <1212sd->params.exposure.gainMode - 1) {1213startexp = startexp >> 1;1214++sd->params.exposure.gain;1215}1216if (FIRMWARE_VERSION(1, 2) && startexp > MAX_EXP_102)1217startexp = MAX_EXP_102;1218if (startexp > MAX_EXP)1219startexp = MAX_EXP;1220sd->params.exposure.coarseExpLo = startexp & 0xff;1221sd->params.exposure.coarseExpHi = startexp >> 8;1222sd->params.exposure.redComp = COMP_RED;1223sd->params.exposure.green1Comp = COMP_GREEN1;1224sd->params.exposure.green2Comp = COMP_GREEN2;1225sd->params.exposure.blueComp = COMP_BLUE;1226sd->params.exposure.compMode = 1;1227sd->params.apcor.gain1 = 0x18;1228sd->params.apcor.gain2 = 0x16;1229sd->params.apcor.gain4 = 0x24;1230sd->params.apcor.gain8 = 0x34;1231}1232sd->params.vlOffset.gain1 = 20;1233sd->params.vlOffset.gain2 = 24;1234sd->params.vlOffset.gain4 = 26;1235sd->params.vlOffset.gain8 = 26;12361237if (apply) {1238ret = command_setexposure(gspca_dev);1239if (ret)1240return ret;12411242ret = command_setapcor(gspca_dev);1243if (ret)1244return ret;12451246ret = command_setvloffset(gspca_dev);1247if (ret)1248return ret;12491250ret = command_setflickerctrl(gspca_dev);1251if (ret)1252return ret;1253}12541255return 0;1256#undef EXP_FROM_COMP1257#undef COMPGAIN1258}12591260/* monitor the exposure and adjust the sensor frame rate if needed */1261static void monitor_exposure(struct gspca_dev *gspca_dev)1262{1263struct sd *sd = (struct sd *) gspca_dev;1264u8 exp_acc, bcomp, cmd[8];1265int ret, light_exp, dark_exp, very_dark_exp;1266int old_exposure, new_exposure, framerate;1267int setfps = 0, setexp = 0, setflicker = 0;12681269/* get necessary stats and register settings from camera */1270/* do_command can't handle this, so do it ourselves */1271cmd[0] = CPIA_COMMAND_ReadVPRegs >> 8;1272cmd[1] = CPIA_COMMAND_ReadVPRegs & 0xff;1273cmd[2] = 30;1274cmd[3] = 4;1275cmd[4] = 9;1276cmd[5] = 8;1277cmd[6] = 8;1278cmd[7] = 0;1279ret = cpia_usb_transferCmd(gspca_dev, cmd);1280if (ret) {1281err("ReadVPRegs(30,4,9,8) - failed: %d", ret);1282return;1283}1284exp_acc = gspca_dev->usb_buf[0];1285bcomp = gspca_dev->usb_buf[1];12861287light_exp = sd->params.colourParams.brightness +1288TC - 50 + EXP_ACC_LIGHT;1289if (light_exp > 255)1290light_exp = 255;1291dark_exp = sd->params.colourParams.brightness +1292TC - 50 - EXP_ACC_DARK;1293if (dark_exp < 0)1294dark_exp = 0;1295very_dark_exp = dark_exp / 2;12961297old_exposure = sd->params.exposure.coarseExpHi * 256 +1298sd->params.exposure.coarseExpLo;12991300if (!sd->params.flickerControl.disabled) {1301/* Flicker control on */1302int max_comp = FIRMWARE_VERSION(1, 2) ? MAX_COMP :1303HIGH_COMP_102;1304bcomp += 128; /* decode */1305if (bcomp >= max_comp && exp_acc < dark_exp) {1306/* dark */1307if (exp_acc < very_dark_exp) {1308/* very dark */1309if (sd->exposure_status == EXPOSURE_VERY_DARK)1310++sd->exposure_count;1311else {1312sd->exposure_status =1313EXPOSURE_VERY_DARK;1314sd->exposure_count = 1;1315}1316} else {1317/* just dark */1318if (sd->exposure_status == EXPOSURE_DARK)1319++sd->exposure_count;1320else {1321sd->exposure_status = EXPOSURE_DARK;1322sd->exposure_count = 1;1323}1324}1325} else if (old_exposure <= LOW_EXP || exp_acc > light_exp) {1326/* light */1327if (old_exposure <= VERY_LOW_EXP) {1328/* very light */1329if (sd->exposure_status == EXPOSURE_VERY_LIGHT)1330++sd->exposure_count;1331else {1332sd->exposure_status =1333EXPOSURE_VERY_LIGHT;1334sd->exposure_count = 1;1335}1336} else {1337/* just light */1338if (sd->exposure_status == EXPOSURE_LIGHT)1339++sd->exposure_count;1340else {1341sd->exposure_status = EXPOSURE_LIGHT;1342sd->exposure_count = 1;1343}1344}1345} else {1346/* not dark or light */1347sd->exposure_status = EXPOSURE_NORMAL;1348}1349} else {1350/* Flicker control off */1351if (old_exposure >= MAX_EXP && exp_acc < dark_exp) {1352/* dark */1353if (exp_acc < very_dark_exp) {1354/* very dark */1355if (sd->exposure_status == EXPOSURE_VERY_DARK)1356++sd->exposure_count;1357else {1358sd->exposure_status =1359EXPOSURE_VERY_DARK;1360sd->exposure_count = 1;1361}1362} else {1363/* just dark */1364if (sd->exposure_status == EXPOSURE_DARK)1365++sd->exposure_count;1366else {1367sd->exposure_status = EXPOSURE_DARK;1368sd->exposure_count = 1;1369}1370}1371} else if (old_exposure <= LOW_EXP || exp_acc > light_exp) {1372/* light */1373if (old_exposure <= VERY_LOW_EXP) {1374/* very light */1375if (sd->exposure_status == EXPOSURE_VERY_LIGHT)1376++sd->exposure_count;1377else {1378sd->exposure_status =1379EXPOSURE_VERY_LIGHT;1380sd->exposure_count = 1;1381}1382} else {1383/* just light */1384if (sd->exposure_status == EXPOSURE_LIGHT)1385++sd->exposure_count;1386else {1387sd->exposure_status = EXPOSURE_LIGHT;1388sd->exposure_count = 1;1389}1390}1391} else {1392/* not dark or light */1393sd->exposure_status = EXPOSURE_NORMAL;1394}1395}13961397framerate = atomic_read(&sd->fps);1398if (framerate > 30 || framerate < 1)1399framerate = 1;14001401if (!sd->params.flickerControl.disabled) {1402/* Flicker control on */1403if ((sd->exposure_status == EXPOSURE_VERY_DARK ||1404sd->exposure_status == EXPOSURE_DARK) &&1405sd->exposure_count >= DARK_TIME * framerate &&1406sd->params.sensorFps.divisor < 2) {14071408/* dark for too long */1409++sd->params.sensorFps.divisor;1410setfps = 1;14111412sd->params.flickerControl.coarseJump =1413flicker_jumps[sd->mainsFreq]1414[sd->params.sensorFps.baserate]1415[sd->params.sensorFps.divisor];1416setflicker = 1;14171418new_exposure = sd->params.flickerControl.coarseJump-1;1419while (new_exposure < old_exposure / 2)1420new_exposure +=1421sd->params.flickerControl.coarseJump;1422sd->params.exposure.coarseExpLo = new_exposure & 0xff;1423sd->params.exposure.coarseExpHi = new_exposure >> 8;1424setexp = 1;1425sd->exposure_status = EXPOSURE_NORMAL;1426PDEBUG(D_CONF, "Automatically decreasing sensor_fps");14271428} else if ((sd->exposure_status == EXPOSURE_VERY_LIGHT ||1429sd->exposure_status == EXPOSURE_LIGHT) &&1430sd->exposure_count >= LIGHT_TIME * framerate &&1431sd->params.sensorFps.divisor > 0) {14321433/* light for too long */1434int max_exp = FIRMWARE_VERSION(1, 2) ? MAX_EXP_102 :1435MAX_EXP;1436--sd->params.sensorFps.divisor;1437setfps = 1;14381439sd->params.flickerControl.coarseJump =1440flicker_jumps[sd->mainsFreq]1441[sd->params.sensorFps.baserate]1442[sd->params.sensorFps.divisor];1443setflicker = 1;14441445new_exposure = sd->params.flickerControl.coarseJump-1;1446while (new_exposure < 2 * old_exposure &&1447new_exposure +1448sd->params.flickerControl.coarseJump < max_exp)1449new_exposure +=1450sd->params.flickerControl.coarseJump;1451sd->params.exposure.coarseExpLo = new_exposure & 0xff;1452sd->params.exposure.coarseExpHi = new_exposure >> 8;1453setexp = 1;1454sd->exposure_status = EXPOSURE_NORMAL;1455PDEBUG(D_CONF, "Automatically increasing sensor_fps");1456}1457} else {1458/* Flicker control off */1459if ((sd->exposure_status == EXPOSURE_VERY_DARK ||1460sd->exposure_status == EXPOSURE_DARK) &&1461sd->exposure_count >= DARK_TIME * framerate &&1462sd->params.sensorFps.divisor < 2) {14631464/* dark for too long */1465++sd->params.sensorFps.divisor;1466setfps = 1;14671468if (sd->params.exposure.gain > 0) {1469--sd->params.exposure.gain;1470setexp = 1;1471}1472sd->exposure_status = EXPOSURE_NORMAL;1473PDEBUG(D_CONF, "Automatically decreasing sensor_fps");14741475} else if ((sd->exposure_status == EXPOSURE_VERY_LIGHT ||1476sd->exposure_status == EXPOSURE_LIGHT) &&1477sd->exposure_count >= LIGHT_TIME * framerate &&1478sd->params.sensorFps.divisor > 0) {14791480/* light for too long */1481--sd->params.sensorFps.divisor;1482setfps = 1;14831484if (sd->params.exposure.gain <1485sd->params.exposure.gainMode - 1) {1486++sd->params.exposure.gain;1487setexp = 1;1488}1489sd->exposure_status = EXPOSURE_NORMAL;1490PDEBUG(D_CONF, "Automatically increasing sensor_fps");1491}1492}14931494if (setexp)1495command_setexposure(gspca_dev);14961497if (setfps)1498command_setsensorfps(gspca_dev);14991500if (setflicker)1501command_setflickerctrl(gspca_dev);1502}15031504/*-----------------------------------------------------------------*/1505/* if flicker is switched off, this function switches it back on.It checks,1506however, that conditions are suitable before restarting it.1507This should only be called for firmware version 1.2.15081509It also adjust the colour balance when an exposure step is detected - as1510long as flicker is running1511*/1512static void restart_flicker(struct gspca_dev *gspca_dev)1513{1514struct sd *sd = (struct sd *) gspca_dev;1515int cam_exposure, old_exp;15161517if (!FIRMWARE_VERSION(1, 2))1518return;15191520cam_exposure = atomic_read(&sd->cam_exposure);15211522if (sd->params.flickerControl.flickerMode == 0 ||1523cam_exposure == 0)1524return;15251526old_exp = sd->params.exposure.coarseExpLo +1527sd->params.exposure.coarseExpHi*256;1528/*1529see how far away camera exposure is from a valid1530flicker exposure value1531*/1532cam_exposure %= sd->params.flickerControl.coarseJump;1533if (!sd->params.flickerControl.disabled &&1534cam_exposure <= sd->params.flickerControl.coarseJump - 3) {1535/* Flicker control auto-disabled */1536sd->params.flickerControl.disabled = 1;1537}15381539if (sd->params.flickerControl.disabled &&1540old_exp > sd->params.flickerControl.coarseJump +1541ROUND_UP_EXP_FOR_FLICKER) {1542/* exposure is now high enough to switch1543flicker control back on */1544set_flicker(gspca_dev, 1, 1);1545}1546}15471548/* this function is called at probe time */1549static int sd_config(struct gspca_dev *gspca_dev,1550const struct usb_device_id *id)1551{1552struct cam *cam;15531554reset_camera_params(gspca_dev);15551556PDEBUG(D_PROBE, "cpia CPiA camera detected (vid/pid 0x%04X:0x%04X)",1557id->idVendor, id->idProduct);15581559cam = &gspca_dev->cam;1560cam->cam_mode = mode;1561cam->nmodes = ARRAY_SIZE(mode);15621563sd_setfreq(gspca_dev, FREQ_DEF);15641565return 0;1566}15671568/* -- start the camera -- */1569static int sd_start(struct gspca_dev *gspca_dev)1570{1571struct sd *sd = (struct sd *) gspca_dev;1572int priv, ret;15731574/* Start the camera in low power mode */1575if (goto_low_power(gspca_dev)) {1576if (sd->params.status.systemState != WARM_BOOT_STATE) {1577PDEBUG(D_ERR, "unexpected systemstate: %02x",1578sd->params.status.systemState);1579printstatus(&sd->params);1580return -ENODEV;1581}15821583/* FIXME: this is just dirty trial and error */1584ret = goto_high_power(gspca_dev);1585if (ret)1586return ret;15871588ret = do_command(gspca_dev, CPIA_COMMAND_DiscardFrame,15890, 0, 0, 0);1590if (ret)1591return ret;15921593ret = goto_low_power(gspca_dev);1594if (ret)1595return ret;1596}15971598/* procedure described in developer's guide p3-28 */15991600/* Check the firmware version. */1601sd->params.version.firmwareVersion = 0;1602get_version_information(gspca_dev);1603if (sd->params.version.firmwareVersion != 1) {1604PDEBUG(D_ERR, "only firmware version 1 is supported (got: %d)",1605sd->params.version.firmwareVersion);1606return -ENODEV;1607}16081609/* A bug in firmware 1-02 limits gainMode to 2 */1610if (sd->params.version.firmwareRevision <= 2 &&1611sd->params.exposure.gainMode > 2) {1612sd->params.exposure.gainMode = 2;1613}16141615/* set QX3 detected flag */1616sd->params.qx3.qx3_detected = (sd->params.pnpID.vendor == 0x0813 &&1617sd->params.pnpID.product == 0x0001);16181619/* The fatal error checking should be done after1620* the camera powers up (developer's guide p 3-38) */16211622/* Set streamState before transition to high power to avoid bug1623* in firmware 1-02 */1624ret = do_command(gspca_dev, CPIA_COMMAND_ModifyCameraStatus,1625STREAMSTATE, 0, STREAM_NOT_READY, 0);1626if (ret)1627return ret;16281629/* GotoHiPower */1630ret = goto_high_power(gspca_dev);1631if (ret)1632return ret;16331634/* Check the camera status */1635ret = do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);1636if (ret)1637return ret;16381639if (sd->params.status.fatalError) {1640PDEBUG(D_ERR, "fatal_error: %04x, vp_status: %04x",1641sd->params.status.fatalError,1642sd->params.status.vpStatus);1643return -EIO;1644}16451646/* VPVersion can't be retrieved before the camera is in HiPower,1647* so get it here instead of in get_version_information. */1648ret = do_command(gspca_dev, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);1649if (ret)1650return ret;16511652/* Determine video mode settings */1653sd->params.streamStartLine = 120;16541655priv = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;1656if (priv & 0x01) { /* crop */1657sd->params.roi.colStart = 2;1658sd->params.roi.rowStart = 6;1659} else {1660sd->params.roi.colStart = 0;1661sd->params.roi.rowStart = 0;1662}16631664if (priv & 0x02) { /* quarter */1665sd->params.format.videoSize = VIDEOSIZE_QCIF;1666sd->params.roi.colStart /= 2;1667sd->params.roi.rowStart /= 2;1668sd->params.streamStartLine /= 2;1669} else1670sd->params.format.videoSize = VIDEOSIZE_CIF;16711672sd->params.roi.colEnd = sd->params.roi.colStart +1673(gspca_dev->width >> 3);1674sd->params.roi.rowEnd = sd->params.roi.rowStart +1675(gspca_dev->height >> 2);16761677/* And now set the camera to a known state */1678ret = do_command(gspca_dev, CPIA_COMMAND_SetGrabMode,1679CPIA_GRAB_CONTINEOUS, 0, 0, 0);1680if (ret)1681return ret;1682/* We start with compression disabled, as we need one uncompressed1683frame to handle later compressed frames */1684ret = do_command(gspca_dev, CPIA_COMMAND_SetCompression,1685CPIA_COMPRESSION_NONE,1686NO_DECIMATION, 0, 0);1687if (ret)1688return ret;1689ret = command_setcompressiontarget(gspca_dev);1690if (ret)1691return ret;1692ret = command_setcolourparams(gspca_dev);1693if (ret)1694return ret;1695ret = command_setformat(gspca_dev);1696if (ret)1697return ret;1698ret = command_setyuvtresh(gspca_dev);1699if (ret)1700return ret;1701ret = command_setecptiming(gspca_dev);1702if (ret)1703return ret;1704ret = command_setcompressionparams(gspca_dev);1705if (ret)1706return ret;1707ret = command_setexposure(gspca_dev);1708if (ret)1709return ret;1710ret = command_setcolourbalance(gspca_dev);1711if (ret)1712return ret;1713ret = command_setsensorfps(gspca_dev);1714if (ret)1715return ret;1716ret = command_setapcor(gspca_dev);1717if (ret)1718return ret;1719ret = command_setflickerctrl(gspca_dev);1720if (ret)1721return ret;1722ret = command_setvloffset(gspca_dev);1723if (ret)1724return ret;17251726/* Start stream */1727ret = command_resume(gspca_dev);1728if (ret)1729return ret;17301731/* Wait 6 frames before turning compression on for the sensor to get1732all settings and AEC/ACB to settle */1733sd->first_frame = 6;1734sd->exposure_status = EXPOSURE_NORMAL;1735sd->exposure_count = 0;1736atomic_set(&sd->cam_exposure, 0);1737atomic_set(&sd->fps, 0);17381739return 0;1740}17411742static void sd_stopN(struct gspca_dev *gspca_dev)1743{1744struct sd *sd = (struct sd *) gspca_dev;17451746command_pause(gspca_dev);17471748/* save camera state for later open (developers guide ch 3.5.3) */1749save_camera_state(gspca_dev);17501751/* GotoLoPower */1752goto_low_power(gspca_dev);17531754/* Update the camera status */1755do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);17561757#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)1758/* If the last button state is pressed, release it now! */1759if (sd->params.qx3.button) {1760/* The camera latch will hold the pressed state until we reset1761the latch, so we do not reset sd->params.qx3.button now, to1762avoid a false keypress being reported the next sd_start */1763input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);1764input_sync(gspca_dev->input_dev);1765}1766#endif1767}17681769/* this function is called at probe and resume time */1770static int sd_init(struct gspca_dev *gspca_dev)1771{1772struct sd *sd = (struct sd *) gspca_dev;1773int ret;17741775/* Start / Stop the camera to make sure we are talking to1776a supported camera, and to get some information from it1777to print. */1778ret = sd_start(gspca_dev);1779if (ret)1780return ret;17811782/* Ensure the QX3 illuminators' states are restored upon resume,1783or disable the illuminator controls, if this isn't a QX3 */1784if (sd->params.qx3.qx3_detected)1785command_setlights(gspca_dev);1786else1787gspca_dev->ctrl_dis |=1788((1 << ILLUMINATORS_1_IDX) | (1 << ILLUMINATORS_2_IDX));17891790sd_stopN(gspca_dev);17911792PDEBUG(D_PROBE, "CPIA Version: %d.%02d (%d.%d)",1793sd->params.version.firmwareVersion,1794sd->params.version.firmwareRevision,1795sd->params.version.vcVersion,1796sd->params.version.vcRevision);1797PDEBUG(D_PROBE, "CPIA PnP-ID: %04x:%04x:%04x",1798sd->params.pnpID.vendor, sd->params.pnpID.product,1799sd->params.pnpID.deviceRevision);1800PDEBUG(D_PROBE, "VP-Version: %d.%d %04x",1801sd->params.vpVersion.vpVersion,1802sd->params.vpVersion.vpRevision,1803sd->params.vpVersion.cameraHeadID);18041805return 0;1806}18071808static void sd_pkt_scan(struct gspca_dev *gspca_dev,1809u8 *data,1810int len)1811{1812struct sd *sd = (struct sd *) gspca_dev;18131814/* Check for SOF */1815if (len >= 64 &&1816data[0] == MAGIC_0 && data[1] == MAGIC_1 &&1817data[16] == sd->params.format.videoSize &&1818data[17] == sd->params.format.subSample &&1819data[18] == sd->params.format.yuvOrder &&1820data[24] == sd->params.roi.colStart &&1821data[25] == sd->params.roi.colEnd &&1822data[26] == sd->params.roi.rowStart &&1823data[27] == sd->params.roi.rowEnd) {1824u8 *image;18251826atomic_set(&sd->cam_exposure, data[39] * 2);1827atomic_set(&sd->fps, data[41]);18281829/* Check for proper EOF for last frame */1830image = gspca_dev->image;1831if (image != NULL &&1832gspca_dev->image_len > 4 &&1833image[gspca_dev->image_len - 4] == 0xff &&1834image[gspca_dev->image_len - 3] == 0xff &&1835image[gspca_dev->image_len - 2] == 0xff &&1836image[gspca_dev->image_len - 1] == 0xff)1837gspca_frame_add(gspca_dev, LAST_PACKET,1838NULL, 0);18391840gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);1841return;1842}18431844gspca_frame_add(gspca_dev, INTER_PACKET, data, len);1845}18461847static void sd_dq_callback(struct gspca_dev *gspca_dev)1848{1849struct sd *sd = (struct sd *) gspca_dev;18501851/* Set the normal compression settings once we have captured a1852few uncompressed frames (and AEC has hopefully settled) */1853if (sd->first_frame) {1854sd->first_frame--;1855if (sd->first_frame == 0)1856command_setcompression(gspca_dev);1857}18581859/* Switch flicker control back on if it got turned off */1860restart_flicker(gspca_dev);18611862/* If AEC is enabled, monitor the exposure and1863adjust the sensor frame rate if needed */1864if (sd->params.exposure.expMode == 2)1865monitor_exposure(gspca_dev);18661867/* Update our knowledge of the camera state */1868do_command(gspca_dev, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);1869do_command(gspca_dev, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);1870}18711872static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)1873{1874struct sd *sd = (struct sd *) gspca_dev;1875int ret;18761877sd->params.colourParams.brightness = val;1878sd->params.flickerControl.allowableOverExposure =1879find_over_exposure(sd->params.colourParams.brightness);1880if (gspca_dev->streaming) {1881ret = command_setcolourparams(gspca_dev);1882if (ret)1883return ret;1884return command_setflickerctrl(gspca_dev);1885}1886return 0;1887}18881889static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)1890{1891struct sd *sd = (struct sd *) gspca_dev;18921893*val = sd->params.colourParams.brightness;1894return 0;1895}18961897static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)1898{1899struct sd *sd = (struct sd *) gspca_dev;19001901sd->params.colourParams.contrast = val;1902if (gspca_dev->streaming)1903return command_setcolourparams(gspca_dev);19041905return 0;1906}19071908static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)1909{1910struct sd *sd = (struct sd *) gspca_dev;19111912*val = sd->params.colourParams.contrast;1913return 0;1914}19151916static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val)1917{1918struct sd *sd = (struct sd *) gspca_dev;19191920sd->params.colourParams.saturation = val;1921if (gspca_dev->streaming)1922return command_setcolourparams(gspca_dev);19231924return 0;1925}19261927static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val)1928{1929struct sd *sd = (struct sd *) gspca_dev;19301931*val = sd->params.colourParams.saturation;1932return 0;1933}19341935static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)1936{1937struct sd *sd = (struct sd *) gspca_dev;1938int on;19391940switch (val) {1941case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */1942on = 0;1943break;1944case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */1945on = 1;1946sd->mainsFreq = 0;1947break;1948case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */1949on = 1;1950sd->mainsFreq = 1;1951break;1952default:1953return -EINVAL;1954}19551956sd->freq = val;1957sd->params.flickerControl.coarseJump =1958flicker_jumps[sd->mainsFreq]1959[sd->params.sensorFps.baserate]1960[sd->params.sensorFps.divisor];19611962return set_flicker(gspca_dev, on, gspca_dev->streaming);1963}19641965static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)1966{1967struct sd *sd = (struct sd *) gspca_dev;19681969*val = sd->freq;1970return 0;1971}19721973static int sd_setcomptarget(struct gspca_dev *gspca_dev, __s32 val)1974{1975struct sd *sd = (struct sd *) gspca_dev;19761977sd->params.compressionTarget.frTargeting = val;1978if (gspca_dev->streaming)1979return command_setcompressiontarget(gspca_dev);19801981return 0;1982}19831984static int sd_getcomptarget(struct gspca_dev *gspca_dev, __s32 *val)1985{1986struct sd *sd = (struct sd *) gspca_dev;19871988*val = sd->params.compressionTarget.frTargeting;1989return 0;1990}19911992static int sd_setilluminator(struct gspca_dev *gspca_dev, __s32 val, int n)1993{1994struct sd *sd = (struct sd *) gspca_dev;1995int ret;19961997if (!sd->params.qx3.qx3_detected)1998return -EINVAL;19992000switch (n) {2001case 1:2002sd->params.qx3.bottomlight = val ? 1 : 0;2003break;2004case 2:2005sd->params.qx3.toplight = val ? 1 : 0;2006break;2007default:2008return -EINVAL;2009}20102011ret = command_setlights(gspca_dev);2012if (ret && ret != -EINVAL)2013ret = -EBUSY;20142015return ret;2016}20172018static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val)2019{2020return sd_setilluminator(gspca_dev, val, 1);2021}20222023static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val)2024{2025return sd_setilluminator(gspca_dev, val, 2);2026}20272028static int sd_getilluminator(struct gspca_dev *gspca_dev, __s32 *val, int n)2029{2030struct sd *sd = (struct sd *) gspca_dev;20312032if (!sd->params.qx3.qx3_detected)2033return -EINVAL;20342035switch (n) {2036case 1:2037*val = sd->params.qx3.bottomlight;2038break;2039case 2:2040*val = sd->params.qx3.toplight;2041break;2042default:2043return -EINVAL;2044}2045return 0;2046}20472048static int sd_getilluminator1(struct gspca_dev *gspca_dev, __s32 *val)2049{2050return sd_getilluminator(gspca_dev, val, 1);2051}20522053static int sd_getilluminator2(struct gspca_dev *gspca_dev, __s32 *val)2054{2055return sd_getilluminator(gspca_dev, val, 2);2056}20572058static int sd_querymenu(struct gspca_dev *gspca_dev,2059struct v4l2_querymenu *menu)2060{2061switch (menu->id) {2062case V4L2_CID_POWER_LINE_FREQUENCY:2063switch (menu->index) {2064case 0: /* V4L2_CID_POWER_LINE_FREQUENCY_DISABLED */2065strcpy((char *) menu->name, "NoFliker");2066return 0;2067case 1: /* V4L2_CID_POWER_LINE_FREQUENCY_50HZ */2068strcpy((char *) menu->name, "50 Hz");2069return 0;2070case 2: /* V4L2_CID_POWER_LINE_FREQUENCY_60HZ */2071strcpy((char *) menu->name, "60 Hz");2072return 0;2073}2074break;2075case V4L2_CID_COMP_TARGET:2076switch (menu->index) {2077case CPIA_COMPRESSION_TARGET_QUALITY:2078strcpy((char *) menu->name, "Quality");2079return 0;2080case CPIA_COMPRESSION_TARGET_FRAMERATE:2081strcpy((char *) menu->name, "Framerate");2082return 0;2083}2084break;2085}2086return -EINVAL;2087}20882089/* sub-driver description */2090static const struct sd_desc sd_desc = {2091.name = MODULE_NAME,2092.ctrls = sd_ctrls,2093.nctrls = ARRAY_SIZE(sd_ctrls),2094.config = sd_config,2095.init = sd_init,2096.start = sd_start,2097.stopN = sd_stopN,2098.dq_callback = sd_dq_callback,2099.pkt_scan = sd_pkt_scan,2100.querymenu = sd_querymenu,2101#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)2102.other_input = 1,2103#endif2104};21052106/* -- module initialisation -- */2107static const struct usb_device_id device_table[] = {2108{USB_DEVICE(0x0553, 0x0002)},2109{USB_DEVICE(0x0813, 0x0001)},2110{}2111};2112MODULE_DEVICE_TABLE(usb, device_table);21132114/* -- device connect -- */2115static int sd_probe(struct usb_interface *intf,2116const struct usb_device_id *id)2117{2118return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),2119THIS_MODULE);2120}21212122static struct usb_driver sd_driver = {2123.name = MODULE_NAME,2124.id_table = device_table,2125.probe = sd_probe,2126.disconnect = gspca_disconnect,2127#ifdef CONFIG_PM2128.suspend = gspca_suspend,2129.resume = gspca_resume,2130#endif2131};21322133/* -- module insert / remove -- */2134static int __init sd_mod_init(void)2135{2136return usb_register(&sd_driver);2137}2138static void __exit sd_mod_exit(void)2139{2140usb_deregister(&sd_driver);2141}21422143module_init(sd_mod_init);2144module_exit(sd_mod_exit);214521462147