1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26
27#define MODULE_NAME "cpia1"
28
29#include <linux/input.h>
30#include <linux/sched/signal.h>
31
32#include "gspca.h"
33
34MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
35MODULE_DESCRIPTION("Vision CPiA");
36MODULE_LICENSE("GPL");
37
38
39#define MAGIC_0 0x19
40#define MAGIC_1 0x68
41#define DATA_IN 0xc0
42#define DATA_OUT 0x40
43#define VIDEOSIZE_QCIF 0
44#define VIDEOSIZE_CIF 1
45#define SUBSAMPLE_420 0
46#define SUBSAMPLE_422 1
47#define YUVORDER_YUYV 0
48#define YUVORDER_UYVY 1
49#define NOT_COMPRESSED 0
50#define COMPRESSED 1
51#define NO_DECIMATION 0
52#define DECIMATION_ENAB 1
53#define EOI 0xff
54#define EOL 0xfd
55#define FRAME_HEADER_SIZE 64
56
57
58#define CPIA_GRAB_SINGLE 0
59#define CPIA_GRAB_CONTINEOUS 1
60
61
62#define CPIA_COMPRESSION_NONE 0
63#define CPIA_COMPRESSION_AUTO 1
64#define CPIA_COMPRESSION_MANUAL 2
65#define CPIA_COMPRESSION_TARGET_QUALITY 0
66#define CPIA_COMPRESSION_TARGET_FRAMERATE 1
67
68
69#define SYSTEMSTATE 0
70#define GRABSTATE 1
71#define STREAMSTATE 2
72#define FATALERROR 3
73#define CMDERROR 4
74#define DEBUGFLAGS 5
75#define VPSTATUS 6
76#define ERRORCODE 7
77
78
79#define UNINITIALISED_STATE 0
80#define PASS_THROUGH_STATE 1
81#define LO_POWER_STATE 2
82#define HI_POWER_STATE 3
83#define WARM_BOOT_STATE 4
84
85
86#define GRAB_IDLE 0
87#define GRAB_ACTIVE 1
88#define GRAB_DONE 2
89
90
91#define STREAM_NOT_READY 0
92#define STREAM_READY 1
93#define STREAM_OPEN 2
94#define STREAM_PAUSED 3
95#define STREAM_FINISHED 4
96
97
98#define CPIA_FLAG 1
99#define SYSTEM_FLAG 2
100#define INT_CTRL_FLAG 4
101#define PROCESS_FLAG 8
102#define COM_FLAG 16
103#define VP_CTRL_FLAG 32
104#define CAPTURE_FLAG 64
105#define DEBUG_FLAG 128
106
107
108#define VP_STATE_OK 0x00
109
110#define VP_STATE_FAILED_VIDEOINIT 0x01
111#define VP_STATE_FAILED_AECACBINIT 0x02
112#define VP_STATE_AEC_MAX 0x04
113#define VP_STATE_ACB_BMAX 0x08
114
115#define VP_STATE_ACB_RMIN 0x10
116#define VP_STATE_ACB_GMIN 0x20
117#define VP_STATE_ACB_RMAX 0x40
118#define VP_STATE_ACB_GMAX 0x80
119
120
121#define COMP_RED 220
122#define COMP_GREEN1 214
123#define COMP_GREEN2 COMP_GREEN1
124#define COMP_BLUE 230
125
126
127#define EXPOSURE_VERY_LIGHT 0
128#define EXPOSURE_LIGHT 1
129#define EXPOSURE_NORMAL 2
130#define EXPOSURE_DARK 3
131#define EXPOSURE_VERY_DARK 4
132
133#define CPIA_MODULE_CPIA (0 << 5)
134#define CPIA_MODULE_SYSTEM (1 << 5)
135#define CPIA_MODULE_VP_CTRL (5 << 5)
136#define CPIA_MODULE_CAPTURE (6 << 5)
137#define CPIA_MODULE_DEBUG (7 << 5)
138
139#define INPUT (DATA_IN << 8)
140#define OUTPUT (DATA_OUT << 8)
141
142#define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)
143#define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)
144#define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)
145#define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)
146#define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)
147#define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)
148#define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)
149#define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
150
151#define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)
152#define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)
153#define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)
154#define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)
155#define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)
156#define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)
157#define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)
158#define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)
159#define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)
160#define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)
161#define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)
162#define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)
163#define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)
164
165#define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)
166#define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2)
167#define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
168#define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
169#define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
170#define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
171#define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
172#define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
173#define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
174#define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
175#define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
176#define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
177#define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
178#define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
179#define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
180#define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
181#define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
182
183#define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
184#define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
185#define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
186#define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
187#define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
188#define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
189#define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
190#define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
191#define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
192#define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
193#define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
194#define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
195#define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
196#define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
197#define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15)
198
199#define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
200#define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
201#define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
202#define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
203#define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
204#define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
205#define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
206#define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11)
207
208#define ROUND_UP_EXP_FOR_FLICKER 15
209
210
211#define MAX_EXP 302
212#define MAX_EXP_102 255
213#define LOW_EXP 140
214#define VERY_LOW_EXP 70
215#define TC 94
216#define EXP_ACC_DARK 50
217#define EXP_ACC_LIGHT 90
218#define HIGH_COMP_102 160
219#define MAX_COMP 239
220#define DARK_TIME 3
221#define LIGHT_TIME 3
222
223#define FIRMWARE_VERSION(x, y) (sd->params.version.firmwareVersion == (x) && \
224 sd->params.version.firmwareRevision == (y))
225
226#define CPIA1_CID_COMP_TARGET (V4L2_CTRL_CLASS_USER + 0x1000)
227#define BRIGHTNESS_DEF 50
228#define CONTRAST_DEF 48
229#define SATURATION_DEF 50
230#define FREQ_DEF V4L2_CID_POWER_LINE_FREQUENCY_50HZ
231#define ILLUMINATORS_1_DEF 0
232#define ILLUMINATORS_2_DEF 0
233#define COMP_TARGET_DEF CPIA_COMPRESSION_TARGET_QUALITY
234
235
236
237static u8 flicker_jumps[2][2][4] =
238{ { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
239 { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
240};
241
242struct cam_params {
243 struct {
244 u8 firmwareVersion;
245 u8 firmwareRevision;
246 u8 vcVersion;
247 u8 vcRevision;
248 } version;
249 struct {
250 u16 vendor;
251 u16 product;
252 u16 deviceRevision;
253 } pnpID;
254 struct {
255 u8 vpVersion;
256 u8 vpRevision;
257 u16 cameraHeadID;
258 } vpVersion;
259 struct {
260 u8 systemState;
261 u8 grabState;
262 u8 streamState;
263 u8 fatalError;
264 u8 cmdError;
265 u8 debugFlags;
266 u8 vpStatus;
267 u8 errorCode;
268 } status;
269 struct {
270 u8 brightness;
271 u8 contrast;
272 u8 saturation;
273 } colourParams;
274 struct {
275 u8 gainMode;
276 u8 expMode;
277 u8 compMode;
278 u8 centreWeight;
279 u8 gain;
280 u8 fineExp;
281 u8 coarseExpLo;
282 u8 coarseExpHi;
283 u8 redComp;
284 u8 green1Comp;
285 u8 green2Comp;
286 u8 blueComp;
287 } exposure;
288 struct {
289 u8 balanceMode;
290 u8 redGain;
291 u8 greenGain;
292 u8 blueGain;
293 } colourBalance;
294 struct {
295 u8 divisor;
296 u8 baserate;
297 } sensorFps;
298 struct {
299 u8 gain1;
300 u8 gain2;
301 u8 gain4;
302 u8 gain8;
303 } apcor;
304 struct {
305 u8 disabled;
306 u8 flickerMode;
307 u8 coarseJump;
308 u8 allowableOverExposure;
309 } flickerControl;
310 struct {
311 u8 gain1;
312 u8 gain2;
313 u8 gain4;
314 u8 gain8;
315 } vlOffset;
316 struct {
317 u8 mode;
318 u8 decimation;
319 } compression;
320 struct {
321 u8 frTargeting;
322 u8 targetFR;
323 u8 targetQ;
324 } compressionTarget;
325 struct {
326 u8 yThreshold;
327 u8 uvThreshold;
328 } yuvThreshold;
329 struct {
330 u8 hysteresis;
331 u8 threshMax;
332 u8 smallStep;
333 u8 largeStep;
334 u8 decimationHysteresis;
335 u8 frDiffStepThresh;
336 u8 qDiffStepThresh;
337 u8 decimationThreshMod;
338 } compressionParams;
339 struct {
340 u8 videoSize;
341 u8 subSample;
342 u8 yuvOrder;
343 } format;
344 struct {
345 u8 qx3_detected;
346 u8 toplight;
347 u8 bottomlight;
348 u8 button;
349 u8 cradled;
350 } qx3;
351 struct {
352 u8 colStart;
353 u8 colEnd;
354 u8 rowStart;
355 u8 rowEnd;
356 } roi;
357 u8 ecpTiming;
358 u8 streamStartLine;
359};
360
361
362struct sd {
363 struct gspca_dev gspca_dev;
364 struct cam_params params;
365
366 atomic_t cam_exposure;
367 atomic_t fps;
368 int exposure_count;
369 u8 exposure_status;
370 struct v4l2_ctrl *freq;
371 u8 mainsFreq;
372 u8 first_frame;
373};
374
375static const struct v4l2_pix_format mode[] = {
376 {160, 120, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE,
377
378
379
380 .bytesperline = 160,
381 .sizeimage = 65536,
382 .colorspace = V4L2_COLORSPACE_SRGB,
383 .priv = 3},
384 {176, 144, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE,
385 .bytesperline = 172,
386 .sizeimage = 65536,
387 .colorspace = V4L2_COLORSPACE_SRGB,
388 .priv = 2},
389 {320, 240, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE,
390 .bytesperline = 320,
391 .sizeimage = 262144,
392 .colorspace = V4L2_COLORSPACE_SRGB,
393 .priv = 1},
394 {352, 288, V4L2_PIX_FMT_CPIA1, V4L2_FIELD_NONE,
395 .bytesperline = 352,
396 .sizeimage = 262144,
397 .colorspace = V4L2_COLORSPACE_SRGB,
398 .priv = 0},
399};
400
401
402
403
404
405
406
407static int cpia_usb_transferCmd(struct gspca_dev *gspca_dev, u8 *command)
408{
409 u8 requesttype;
410 unsigned int pipe;
411 int ret, databytes = command[6] | (command[7] << 8);
412
413 int retries = 3;
414
415 if (command[0] == DATA_IN) {
416 pipe = usb_rcvctrlpipe(gspca_dev->dev, 0);
417 requesttype = USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
418 } else if (command[0] == DATA_OUT) {
419 pipe = usb_sndctrlpipe(gspca_dev->dev, 0);
420 requesttype = USB_TYPE_VENDOR | USB_RECIP_DEVICE;
421 } else {
422 gspca_err(gspca_dev, "Unexpected first byte of command: %x\n",
423 command[0]);
424 return -EINVAL;
425 }
426
427retry:
428 ret = usb_control_msg(gspca_dev->dev, pipe,
429 command[1],
430 requesttype,
431 command[2] | (command[3] << 8),
432 command[4] | (command[5] << 8),
433 gspca_dev->usb_buf, databytes, 1000);
434
435 if (ret < 0)
436 pr_err("usb_control_msg %02x, error %d\n", command[1], ret);
437
438 if (ret == -EPIPE && retries > 0) {
439 retries--;
440 goto retry;
441 }
442
443 return (ret < 0) ? ret : 0;
444}
445
446
447static int do_command(struct gspca_dev *gspca_dev, u16 command,
448 u8 a, u8 b, u8 c, u8 d)
449{
450 struct sd *sd = (struct sd *) gspca_dev;
451 int ret, datasize;
452 u8 cmd[8];
453
454 switch (command) {
455 case CPIA_COMMAND_GetCPIAVersion:
456 case CPIA_COMMAND_GetPnPID:
457 case CPIA_COMMAND_GetCameraStatus:
458 case CPIA_COMMAND_GetVPVersion:
459 case CPIA_COMMAND_GetColourParams:
460 case CPIA_COMMAND_GetColourBalance:
461 case CPIA_COMMAND_GetExposure:
462 datasize = 8;
463 break;
464 case CPIA_COMMAND_ReadMCPorts:
465 case CPIA_COMMAND_ReadVCRegs:
466 datasize = 4;
467 break;
468 default:
469 datasize = 0;
470 break;
471 }
472
473 cmd[0] = command >> 8;
474 cmd[1] = command & 0xff;
475 cmd[2] = a;
476 cmd[3] = b;
477 cmd[4] = c;
478 cmd[5] = d;
479 cmd[6] = datasize;
480 cmd[7] = 0;
481
482 ret = cpia_usb_transferCmd(gspca_dev, cmd);
483 if (ret)
484 return ret;
485
486 switch (command) {
487 case CPIA_COMMAND_GetCPIAVersion:
488 sd->params.version.firmwareVersion = gspca_dev->usb_buf[0];
489 sd->params.version.firmwareRevision = gspca_dev->usb_buf[1];
490 sd->params.version.vcVersion = gspca_dev->usb_buf[2];
491 sd->params.version.vcRevision = gspca_dev->usb_buf[3];
492 break;
493 case CPIA_COMMAND_GetPnPID:
494 sd->params.pnpID.vendor =
495 gspca_dev->usb_buf[0] | (gspca_dev->usb_buf[1] << 8);
496 sd->params.pnpID.product =
497 gspca_dev->usb_buf[2] | (gspca_dev->usb_buf[3] << 8);
498 sd->params.pnpID.deviceRevision =
499 gspca_dev->usb_buf[4] | (gspca_dev->usb_buf[5] << 8);
500 break;
501 case CPIA_COMMAND_GetCameraStatus:
502 sd->params.status.systemState = gspca_dev->usb_buf[0];
503 sd->params.status.grabState = gspca_dev->usb_buf[1];
504 sd->params.status.streamState = gspca_dev->usb_buf[2];
505 sd->params.status.fatalError = gspca_dev->usb_buf[3];
506 sd->params.status.cmdError = gspca_dev->usb_buf[4];
507 sd->params.status.debugFlags = gspca_dev->usb_buf[5];
508 sd->params.status.vpStatus = gspca_dev->usb_buf[6];
509 sd->params.status.errorCode = gspca_dev->usb_buf[7];
510 break;
511 case CPIA_COMMAND_GetVPVersion:
512 sd->params.vpVersion.vpVersion = gspca_dev->usb_buf[0];
513 sd->params.vpVersion.vpRevision = gspca_dev->usb_buf[1];
514 sd->params.vpVersion.cameraHeadID =
515 gspca_dev->usb_buf[2] | (gspca_dev->usb_buf[3] << 8);
516 break;
517 case CPIA_COMMAND_GetColourParams:
518 sd->params.colourParams.brightness = gspca_dev->usb_buf[0];
519 sd->params.colourParams.contrast = gspca_dev->usb_buf[1];
520 sd->params.colourParams.saturation = gspca_dev->usb_buf[2];
521 break;
522 case CPIA_COMMAND_GetColourBalance:
523 sd->params.colourBalance.redGain = gspca_dev->usb_buf[0];
524 sd->params.colourBalance.greenGain = gspca_dev->usb_buf[1];
525 sd->params.colourBalance.blueGain = gspca_dev->usb_buf[2];
526 break;
527 case CPIA_COMMAND_GetExposure:
528 sd->params.exposure.gain = gspca_dev->usb_buf[0];
529 sd->params.exposure.fineExp = gspca_dev->usb_buf[1];
530 sd->params.exposure.coarseExpLo = gspca_dev->usb_buf[2];
531 sd->params.exposure.coarseExpHi = gspca_dev->usb_buf[3];
532 sd->params.exposure.redComp = gspca_dev->usb_buf[4];
533 sd->params.exposure.green1Comp = gspca_dev->usb_buf[5];
534 sd->params.exposure.green2Comp = gspca_dev->usb_buf[6];
535 sd->params.exposure.blueComp = gspca_dev->usb_buf[7];
536 break;
537
538 case CPIA_COMMAND_ReadMCPorts:
539
540 a = ((gspca_dev->usb_buf[1] & 0x02) == 0);
541 if (a != sd->params.qx3.button) {
542#if IS_ENABLED(CONFIG_INPUT)
543 input_report_key(gspca_dev->input_dev, KEY_CAMERA, a);
544 input_sync(gspca_dev->input_dev);
545#endif
546 sd->params.qx3.button = a;
547 }
548 if (sd->params.qx3.button) {
549
550 do_command(gspca_dev, CPIA_COMMAND_WriteMCPort,
551 3, 0xdf, 0xdf, 0);
552 do_command(gspca_dev, CPIA_COMMAND_WriteMCPort,
553 3, 0xff, 0xff, 0);
554 }
555
556
557 sd->params.qx3.cradled = ((gspca_dev->usb_buf[2] & 0x40) == 0);
558 break;
559 }
560
561 return 0;
562}
563
564
565static int do_command_extended(struct gspca_dev *gspca_dev, u16 command,
566 u8 a, u8 b, u8 c, u8 d,
567 u8 e, u8 f, u8 g, u8 h,
568 u8 i, u8 j, u8 k, u8 l)
569{
570 u8 cmd[8];
571
572 cmd[0] = command >> 8;
573 cmd[1] = command & 0xff;
574 cmd[2] = a;
575 cmd[3] = b;
576 cmd[4] = c;
577 cmd[5] = d;
578 cmd[6] = 8;
579 cmd[7] = 0;
580 gspca_dev->usb_buf[0] = e;
581 gspca_dev->usb_buf[1] = f;
582 gspca_dev->usb_buf[2] = g;
583 gspca_dev->usb_buf[3] = h;
584 gspca_dev->usb_buf[4] = i;
585 gspca_dev->usb_buf[5] = j;
586 gspca_dev->usb_buf[6] = k;
587 gspca_dev->usb_buf[7] = l;
588
589 return cpia_usb_transferCmd(gspca_dev, cmd);
590}
591
592
593
594
595
596
597
598
599
600
601#define FLICKER_MAX_EXPOSURE 250
602#define FLICKER_ALLOWABLE_OVER_EXPOSURE 146
603#define FLICKER_BRIGHTNESS_CONSTANT 59
604static int find_over_exposure(int brightness)
605{
606 int MaxAllowableOverExposure, OverExposure;
607
608 MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness -
609 FLICKER_BRIGHTNESS_CONSTANT;
610
611 if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE)
612 OverExposure = MaxAllowableOverExposure;
613 else
614 OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE;
615
616 return OverExposure;
617}
618#undef FLICKER_MAX_EXPOSURE
619#undef FLICKER_ALLOWABLE_OVER_EXPOSURE
620#undef FLICKER_BRIGHTNESS_CONSTANT
621
622
623static void reset_camera_params(struct gspca_dev *gspca_dev)
624{
625 struct sd *sd = (struct sd *) gspca_dev;
626 struct cam_params *params = &sd->params;
627
628
629
630
631 params->colourParams.brightness = BRIGHTNESS_DEF;
632 params->colourParams.contrast = CONTRAST_DEF;
633 params->colourParams.saturation = SATURATION_DEF;
634 params->exposure.gainMode = 4;
635 params->exposure.expMode = 2;
636 params->exposure.compMode = 1;
637 params->exposure.centreWeight = 1;
638 params->exposure.gain = 0;
639 params->exposure.fineExp = 0;
640 params->exposure.coarseExpLo = 185;
641 params->exposure.coarseExpHi = 0;
642 params->exposure.redComp = COMP_RED;
643 params->exposure.green1Comp = COMP_GREEN1;
644 params->exposure.green2Comp = COMP_GREEN2;
645 params->exposure.blueComp = COMP_BLUE;
646 params->colourBalance.balanceMode = 2;
647 params->colourBalance.redGain = 32;
648 params->colourBalance.greenGain = 6;
649 params->colourBalance.blueGain = 92;
650 params->apcor.gain1 = 0x18;
651 params->apcor.gain2 = 0x16;
652 params->apcor.gain4 = 0x24;
653 params->apcor.gain8 = 0x34;
654 params->vlOffset.gain1 = 20;
655 params->vlOffset.gain2 = 24;
656 params->vlOffset.gain4 = 26;
657 params->vlOffset.gain8 = 26;
658 params->compressionParams.hysteresis = 3;
659 params->compressionParams.threshMax = 11;
660 params->compressionParams.smallStep = 1;
661 params->compressionParams.largeStep = 3;
662 params->compressionParams.decimationHysteresis = 2;
663 params->compressionParams.frDiffStepThresh = 5;
664 params->compressionParams.qDiffStepThresh = 3;
665 params->compressionParams.decimationThreshMod = 2;
666
667
668
669
670 params->sensorFps.divisor = 1;
671 params->sensorFps.baserate = 1;
672
673 params->flickerControl.flickerMode = 0;
674 params->flickerControl.disabled = 1;
675 params->flickerControl.coarseJump =
676 flicker_jumps[sd->mainsFreq]
677 [params->sensorFps.baserate]
678 [params->sensorFps.divisor];
679 params->flickerControl.allowableOverExposure =
680 find_over_exposure(params->colourParams.brightness);
681
682 params->yuvThreshold.yThreshold = 6;
683 params->yuvThreshold.uvThreshold = 6;
684
685 params->format.subSample = SUBSAMPLE_420;
686 params->format.yuvOrder = YUVORDER_YUYV;
687
688 params->compression.mode = CPIA_COMPRESSION_AUTO;
689 params->compression.decimation = NO_DECIMATION;
690
691 params->compressionTarget.frTargeting = COMP_TARGET_DEF;
692 params->compressionTarget.targetFR = 15;
693 params->compressionTarget.targetQ = 5;
694
695 params->qx3.qx3_detected = 0;
696 params->qx3.toplight = 0;
697 params->qx3.bottomlight = 0;
698 params->qx3.button = 0;
699 params->qx3.cradled = 0;
700}
701
702static void printstatus(struct gspca_dev *gspca_dev, struct cam_params *params)
703{
704 gspca_dbg(gspca_dev, D_PROBE, "status: %02x %02x %02x %02x %02x %02x %02x %02x\n",
705 params->status.systemState, params->status.grabState,
706 params->status.streamState, params->status.fatalError,
707 params->status.cmdError, params->status.debugFlags,
708 params->status.vpStatus, params->status.errorCode);
709}
710
711static int goto_low_power(struct gspca_dev *gspca_dev)
712{
713 struct sd *sd = (struct sd *) gspca_dev;
714 int ret;
715
716 ret = do_command(gspca_dev, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0);
717 if (ret)
718 return ret;
719
720 ret = do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
721 if (ret)
722 return ret;
723
724 if (sd->params.status.systemState != LO_POWER_STATE) {
725 if (sd->params.status.systemState != WARM_BOOT_STATE) {
726 gspca_err(gspca_dev, "unexpected state after lo power cmd: %02x\n",
727 sd->params.status.systemState);
728 printstatus(gspca_dev, &sd->params);
729 }
730 return -EIO;
731 }
732
733 gspca_dbg(gspca_dev, D_CONF, "camera now in LOW power state\n");
734 return 0;
735}
736
737static int goto_high_power(struct gspca_dev *gspca_dev)
738{
739 struct sd *sd = (struct sd *) gspca_dev;
740 int ret;
741
742 ret = do_command(gspca_dev, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0);
743 if (ret)
744 return ret;
745
746 msleep_interruptible(40);
747
748 if (signal_pending(current))
749 return -EINTR;
750
751 ret = do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
752 if (ret)
753 return ret;
754
755 if (sd->params.status.systemState != HI_POWER_STATE) {
756 gspca_err(gspca_dev, "unexpected state after hi power cmd: %02x\n",
757 sd->params.status.systemState);
758 printstatus(gspca_dev, &sd->params);
759 return -EIO;
760 }
761
762 gspca_dbg(gspca_dev, D_CONF, "camera now in HIGH power state\n");
763 return 0;
764}
765
766static int get_version_information(struct gspca_dev *gspca_dev)
767{
768 int ret;
769
770
771 ret = do_command(gspca_dev, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
772 if (ret)
773 return ret;
774
775
776 return do_command(gspca_dev, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
777}
778
779static int save_camera_state(struct gspca_dev *gspca_dev)
780{
781 int ret;
782
783 ret = do_command(gspca_dev, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
784 if (ret)
785 return ret;
786
787 return do_command(gspca_dev, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
788}
789
790static int command_setformat(struct gspca_dev *gspca_dev)
791{
792 struct sd *sd = (struct sd *) gspca_dev;
793 int ret;
794
795 ret = do_command(gspca_dev, CPIA_COMMAND_SetFormat,
796 sd->params.format.videoSize,
797 sd->params.format.subSample,
798 sd->params.format.yuvOrder, 0);
799 if (ret)
800 return ret;
801
802 return do_command(gspca_dev, CPIA_COMMAND_SetROI,
803 sd->params.roi.colStart, sd->params.roi.colEnd,
804 sd->params.roi.rowStart, sd->params.roi.rowEnd);
805}
806
807static int command_setcolourparams(struct gspca_dev *gspca_dev)
808{
809 struct sd *sd = (struct sd *) gspca_dev;
810 return do_command(gspca_dev, CPIA_COMMAND_SetColourParams,
811 sd->params.colourParams.brightness,
812 sd->params.colourParams.contrast,
813 sd->params.colourParams.saturation, 0);
814}
815
816static int command_setapcor(struct gspca_dev *gspca_dev)
817{
818 struct sd *sd = (struct sd *) gspca_dev;
819 return do_command(gspca_dev, CPIA_COMMAND_SetApcor,
820 sd->params.apcor.gain1,
821 sd->params.apcor.gain2,
822 sd->params.apcor.gain4,
823 sd->params.apcor.gain8);
824}
825
826static int command_setvloffset(struct gspca_dev *gspca_dev)
827{
828 struct sd *sd = (struct sd *) gspca_dev;
829 return do_command(gspca_dev, CPIA_COMMAND_SetVLOffset,
830 sd->params.vlOffset.gain1,
831 sd->params.vlOffset.gain2,
832 sd->params.vlOffset.gain4,
833 sd->params.vlOffset.gain8);
834}
835
836static int command_setexposure(struct gspca_dev *gspca_dev)
837{
838 struct sd *sd = (struct sd *) gspca_dev;
839 int ret;
840
841 ret = do_command_extended(gspca_dev, CPIA_COMMAND_SetExposure,
842 sd->params.exposure.gainMode,
843 1,
844 sd->params.exposure.compMode,
845 sd->params.exposure.centreWeight,
846 sd->params.exposure.gain,
847 sd->params.exposure.fineExp,
848 sd->params.exposure.coarseExpLo,
849 sd->params.exposure.coarseExpHi,
850 sd->params.exposure.redComp,
851 sd->params.exposure.green1Comp,
852 sd->params.exposure.green2Comp,
853 sd->params.exposure.blueComp);
854 if (ret)
855 return ret;
856
857 if (sd->params.exposure.expMode != 1) {
858 ret = do_command_extended(gspca_dev, CPIA_COMMAND_SetExposure,
859 0,
860 sd->params.exposure.expMode,
861 0, 0,
862 sd->params.exposure.gain,
863 sd->params.exposure.fineExp,
864 sd->params.exposure.coarseExpLo,
865 sd->params.exposure.coarseExpHi,
866 0, 0, 0, 0);
867 }
868
869 return ret;
870}
871
872static int command_setcolourbalance(struct gspca_dev *gspca_dev)
873{
874 struct sd *sd = (struct sd *) gspca_dev;
875
876 if (sd->params.colourBalance.balanceMode == 1) {
877 int ret;
878
879 ret = do_command(gspca_dev, CPIA_COMMAND_SetColourBalance,
880 1,
881 sd->params.colourBalance.redGain,
882 sd->params.colourBalance.greenGain,
883 sd->params.colourBalance.blueGain);
884 if (ret)
885 return ret;
886
887 return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance,
888 3, 0, 0, 0);
889 }
890 if (sd->params.colourBalance.balanceMode == 2) {
891 return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance,
892 2, 0, 0, 0);
893 }
894 if (sd->params.colourBalance.balanceMode == 3) {
895 return do_command(gspca_dev, CPIA_COMMAND_SetColourBalance,
896 3, 0, 0, 0);
897 }
898
899 return -EINVAL;
900}
901
902static int command_setcompressiontarget(struct gspca_dev *gspca_dev)
903{
904 struct sd *sd = (struct sd *) gspca_dev;
905
906 return do_command(gspca_dev, CPIA_COMMAND_SetCompressionTarget,
907 sd->params.compressionTarget.frTargeting,
908 sd->params.compressionTarget.targetFR,
909 sd->params.compressionTarget.targetQ, 0);
910}
911
912static int command_setyuvtresh(struct gspca_dev *gspca_dev)
913{
914 struct sd *sd = (struct sd *) gspca_dev;
915
916 return do_command(gspca_dev, CPIA_COMMAND_SetYUVThresh,
917 sd->params.yuvThreshold.yThreshold,
918 sd->params.yuvThreshold.uvThreshold, 0, 0);
919}
920
921static int command_setcompressionparams(struct gspca_dev *gspca_dev)
922{
923 struct sd *sd = (struct sd *) gspca_dev;
924
925 return do_command_extended(gspca_dev,
926 CPIA_COMMAND_SetCompressionParams,
927 0, 0, 0, 0,
928 sd->params.compressionParams.hysteresis,
929 sd->params.compressionParams.threshMax,
930 sd->params.compressionParams.smallStep,
931 sd->params.compressionParams.largeStep,
932 sd->params.compressionParams.decimationHysteresis,
933 sd->params.compressionParams.frDiffStepThresh,
934 sd->params.compressionParams.qDiffStepThresh,
935 sd->params.compressionParams.decimationThreshMod);
936}
937
938static int command_setcompression(struct gspca_dev *gspca_dev)
939{
940 struct sd *sd = (struct sd *) gspca_dev;
941
942 return do_command(gspca_dev, CPIA_COMMAND_SetCompression,
943 sd->params.compression.mode,
944 sd->params.compression.decimation, 0, 0);
945}
946
947static int command_setsensorfps(struct gspca_dev *gspca_dev)
948{
949 struct sd *sd = (struct sd *) gspca_dev;
950
951 return do_command(gspca_dev, CPIA_COMMAND_SetSensorFPS,
952 sd->params.sensorFps.divisor,
953 sd->params.sensorFps.baserate, 0, 0);
954}
955
956static int command_setflickerctrl(struct gspca_dev *gspca_dev)
957{
958 struct sd *sd = (struct sd *) gspca_dev;
959
960 return do_command(gspca_dev, CPIA_COMMAND_SetFlickerCtrl,
961 sd->params.flickerControl.flickerMode,
962 sd->params.flickerControl.coarseJump,
963 sd->params.flickerControl.allowableOverExposure,
964 0);
965}
966
967static int command_setecptiming(struct gspca_dev *gspca_dev)
968{
969 struct sd *sd = (struct sd *) gspca_dev;
970
971 return do_command(gspca_dev, CPIA_COMMAND_SetECPTiming,
972 sd->params.ecpTiming, 0, 0, 0);
973}
974
975static int command_pause(struct gspca_dev *gspca_dev)
976{
977 return do_command(gspca_dev, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
978}
979
980static int command_resume(struct gspca_dev *gspca_dev)
981{
982 struct sd *sd = (struct sd *) gspca_dev;
983
984 return do_command(gspca_dev, CPIA_COMMAND_InitStreamCap,
985 0, sd->params.streamStartLine, 0, 0);
986}
987
988static int command_setlights(struct gspca_dev *gspca_dev)
989{
990 struct sd *sd = (struct sd *) gspca_dev;
991 int ret, p1, p2;
992
993 p1 = (sd->params.qx3.bottomlight == 0) << 1;
994 p2 = (sd->params.qx3.toplight == 0) << 3;
995
996 ret = do_command(gspca_dev, CPIA_COMMAND_WriteVCReg,
997 0x90, 0x8f, 0x50, 0);
998 if (ret)
999 return ret;
1000
1001 return do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, 2, 0,
1002 p1 | p2 | 0xe0, 0);
1003}
1004
1005static int set_flicker(struct gspca_dev *gspca_dev, int on, int apply)
1006{
1007
1008
1009#if 0
1010#define COMPGAIN(base, curexp, newexp) \
1011 (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5)
1012#define EXP_FROM_COMP(basecomp, curcomp, curexp) \
1013 (u16)((float)curexp * (float)(u8)(curcomp + 128) / \
1014 (float)(u8)(basecomp - 128))
1015#else
1016
1017#define COMPGAIN(base, curexp, newexp) \
1018 (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2 * newexp)))
1019#define EXP_FROM_COMP(basecomp, curcomp, curexp) \
1020 (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128)))
1021#endif
1022
1023 struct sd *sd = (struct sd *) gspca_dev;
1024 int currentexp = sd->params.exposure.coarseExpLo +
1025 sd->params.exposure.coarseExpHi * 256;
1026 int ret, startexp;
1027
1028 if (on) {
1029 int cj = sd->params.flickerControl.coarseJump;
1030 sd->params.flickerControl.flickerMode = 1;
1031 sd->params.flickerControl.disabled = 0;
1032 if (sd->params.exposure.expMode != 2) {
1033 sd->params.exposure.expMode = 2;
1034 sd->exposure_status = EXPOSURE_NORMAL;
1035 }
1036 currentexp = currentexp << sd->params.exposure.gain;
1037 sd->params.exposure.gain = 0;
1038
1039 startexp = (currentexp + ROUND_UP_EXP_FOR_FLICKER) / cj;
1040 if (startexp < 1)
1041 startexp = 1;
1042 startexp = (startexp * cj) - 1;
1043 if (FIRMWARE_VERSION(1, 2))
1044 while (startexp > MAX_EXP_102)
1045 startexp -= cj;
1046 else
1047 while (startexp > MAX_EXP)
1048 startexp -= cj;
1049 sd->params.exposure.coarseExpLo = startexp & 0xff;
1050 sd->params.exposure.coarseExpHi = startexp >> 8;
1051 if (currentexp > startexp) {
1052 if (currentexp > (2 * startexp))
1053 currentexp = 2 * startexp;
1054 sd->params.exposure.redComp =
1055 COMPGAIN(COMP_RED, currentexp, startexp);
1056 sd->params.exposure.green1Comp =
1057 COMPGAIN(COMP_GREEN1, currentexp, startexp);
1058 sd->params.exposure.green2Comp =
1059 COMPGAIN(COMP_GREEN2, currentexp, startexp);
1060 sd->params.exposure.blueComp =
1061 COMPGAIN(COMP_BLUE, currentexp, startexp);
1062 } else {
1063 sd->params.exposure.redComp = COMP_RED;
1064 sd->params.exposure.green1Comp = COMP_GREEN1;
1065 sd->params.exposure.green2Comp = COMP_GREEN2;
1066 sd->params.exposure.blueComp = COMP_BLUE;
1067 }
1068 if (FIRMWARE_VERSION(1, 2))
1069 sd->params.exposure.compMode = 0;
1070 else
1071 sd->params.exposure.compMode = 1;
1072
1073 sd->params.apcor.gain1 = 0x18;
1074 sd->params.apcor.gain2 = 0x18;
1075 sd->params.apcor.gain4 = 0x16;
1076 sd->params.apcor.gain8 = 0x14;
1077 } else {
1078 sd->params.flickerControl.flickerMode = 0;
1079 sd->params.flickerControl.disabled = 1;
1080
1081 startexp = EXP_FROM_COMP(COMP_RED,
1082 sd->params.exposure.redComp, currentexp);
1083 startexp += EXP_FROM_COMP(COMP_GREEN1,
1084 sd->params.exposure.green1Comp, currentexp);
1085 startexp += EXP_FROM_COMP(COMP_GREEN2,
1086 sd->params.exposure.green2Comp, currentexp);
1087 startexp += EXP_FROM_COMP(COMP_BLUE,
1088 sd->params.exposure.blueComp, currentexp);
1089 startexp = startexp >> 2;
1090 while (startexp > MAX_EXP && sd->params.exposure.gain <
1091 sd->params.exposure.gainMode - 1) {
1092 startexp = startexp >> 1;
1093 ++sd->params.exposure.gain;
1094 }
1095 if (FIRMWARE_VERSION(1, 2) && startexp > MAX_EXP_102)
1096 startexp = MAX_EXP_102;
1097 if (startexp > MAX_EXP)
1098 startexp = MAX_EXP;
1099 sd->params.exposure.coarseExpLo = startexp & 0xff;
1100 sd->params.exposure.coarseExpHi = startexp >> 8;
1101 sd->params.exposure.redComp = COMP_RED;
1102 sd->params.exposure.green1Comp = COMP_GREEN1;
1103 sd->params.exposure.green2Comp = COMP_GREEN2;
1104 sd->params.exposure.blueComp = COMP_BLUE;
1105 sd->params.exposure.compMode = 1;
1106 sd->params.apcor.gain1 = 0x18;
1107 sd->params.apcor.gain2 = 0x16;
1108 sd->params.apcor.gain4 = 0x24;
1109 sd->params.apcor.gain8 = 0x34;
1110 }
1111 sd->params.vlOffset.gain1 = 20;
1112 sd->params.vlOffset.gain2 = 24;
1113 sd->params.vlOffset.gain4 = 26;
1114 sd->params.vlOffset.gain8 = 26;
1115
1116 if (apply) {
1117 ret = command_setexposure(gspca_dev);
1118 if (ret)
1119 return ret;
1120
1121 ret = command_setapcor(gspca_dev);
1122 if (ret)
1123 return ret;
1124
1125 ret = command_setvloffset(gspca_dev);
1126 if (ret)
1127 return ret;
1128
1129 ret = command_setflickerctrl(gspca_dev);
1130 if (ret)
1131 return ret;
1132 }
1133
1134 return 0;
1135#undef EXP_FROM_COMP
1136#undef COMPGAIN
1137}
1138
1139
1140static void monitor_exposure(struct gspca_dev *gspca_dev)
1141{
1142 struct sd *sd = (struct sd *) gspca_dev;
1143 u8 exp_acc, bcomp, cmd[8];
1144 int ret, light_exp, dark_exp, very_dark_exp;
1145 int old_exposure, new_exposure, framerate;
1146 int setfps = 0, setexp = 0, setflicker = 0;
1147
1148
1149
1150 cmd[0] = CPIA_COMMAND_ReadVPRegs >> 8;
1151 cmd[1] = CPIA_COMMAND_ReadVPRegs & 0xff;
1152 cmd[2] = 30;
1153 cmd[3] = 4;
1154 cmd[4] = 9;
1155 cmd[5] = 8;
1156 cmd[6] = 8;
1157 cmd[7] = 0;
1158 ret = cpia_usb_transferCmd(gspca_dev, cmd);
1159 if (ret) {
1160 pr_err("ReadVPRegs(30,4,9,8) - failed: %d\n", ret);
1161 return;
1162 }
1163 exp_acc = gspca_dev->usb_buf[0];
1164 bcomp = gspca_dev->usb_buf[1];
1165
1166 light_exp = sd->params.colourParams.brightness +
1167 TC - 50 + EXP_ACC_LIGHT;
1168 if (light_exp > 255)
1169 light_exp = 255;
1170 dark_exp = sd->params.colourParams.brightness +
1171 TC - 50 - EXP_ACC_DARK;
1172 if (dark_exp < 0)
1173 dark_exp = 0;
1174 very_dark_exp = dark_exp / 2;
1175
1176 old_exposure = sd->params.exposure.coarseExpHi * 256 +
1177 sd->params.exposure.coarseExpLo;
1178
1179 if (!sd->params.flickerControl.disabled) {
1180
1181 int max_comp = FIRMWARE_VERSION(1, 2) ? MAX_COMP :
1182 HIGH_COMP_102;
1183 bcomp += 128;
1184 if (bcomp >= max_comp && exp_acc < dark_exp) {
1185
1186 if (exp_acc < very_dark_exp) {
1187
1188 if (sd->exposure_status == EXPOSURE_VERY_DARK)
1189 ++sd->exposure_count;
1190 else {
1191 sd->exposure_status =
1192 EXPOSURE_VERY_DARK;
1193 sd->exposure_count = 1;
1194 }
1195 } else {
1196
1197 if (sd->exposure_status == EXPOSURE_DARK)
1198 ++sd->exposure_count;
1199 else {
1200 sd->exposure_status = EXPOSURE_DARK;
1201 sd->exposure_count = 1;
1202 }
1203 }
1204 } else if (old_exposure <= LOW_EXP || exp_acc > light_exp) {
1205
1206 if (old_exposure <= VERY_LOW_EXP) {
1207
1208 if (sd->exposure_status == EXPOSURE_VERY_LIGHT)
1209 ++sd->exposure_count;
1210 else {
1211 sd->exposure_status =
1212 EXPOSURE_VERY_LIGHT;
1213 sd->exposure_count = 1;
1214 }
1215 } else {
1216
1217 if (sd->exposure_status == EXPOSURE_LIGHT)
1218 ++sd->exposure_count;
1219 else {
1220 sd->exposure_status = EXPOSURE_LIGHT;
1221 sd->exposure_count = 1;
1222 }
1223 }
1224 } else {
1225
1226 sd->exposure_status = EXPOSURE_NORMAL;
1227 }
1228 } else {
1229
1230 if (old_exposure >= MAX_EXP && exp_acc < dark_exp) {
1231
1232 if (exp_acc < very_dark_exp) {
1233
1234 if (sd->exposure_status == EXPOSURE_VERY_DARK)
1235 ++sd->exposure_count;
1236 else {
1237 sd->exposure_status =
1238 EXPOSURE_VERY_DARK;
1239 sd->exposure_count = 1;
1240 }
1241 } else {
1242
1243 if (sd->exposure_status == EXPOSURE_DARK)
1244 ++sd->exposure_count;
1245 else {
1246 sd->exposure_status = EXPOSURE_DARK;
1247 sd->exposure_count = 1;
1248 }
1249 }
1250 } else if (old_exposure <= LOW_EXP || exp_acc > light_exp) {
1251
1252 if (old_exposure <= VERY_LOW_EXP) {
1253
1254 if (sd->exposure_status == EXPOSURE_VERY_LIGHT)
1255 ++sd->exposure_count;
1256 else {
1257 sd->exposure_status =
1258 EXPOSURE_VERY_LIGHT;
1259 sd->exposure_count = 1;
1260 }
1261 } else {
1262
1263 if (sd->exposure_status == EXPOSURE_LIGHT)
1264 ++sd->exposure_count;
1265 else {
1266 sd->exposure_status = EXPOSURE_LIGHT;
1267 sd->exposure_count = 1;
1268 }
1269 }
1270 } else {
1271
1272 sd->exposure_status = EXPOSURE_NORMAL;
1273 }
1274 }
1275
1276 framerate = atomic_read(&sd->fps);
1277 if (framerate > 30 || framerate < 1)
1278 framerate = 1;
1279
1280 if (!sd->params.flickerControl.disabled) {
1281
1282 if ((sd->exposure_status == EXPOSURE_VERY_DARK ||
1283 sd->exposure_status == EXPOSURE_DARK) &&
1284 sd->exposure_count >= DARK_TIME * framerate &&
1285 sd->params.sensorFps.divisor < 2) {
1286
1287
1288 ++sd->params.sensorFps.divisor;
1289 setfps = 1;
1290
1291 sd->params.flickerControl.coarseJump =
1292 flicker_jumps[sd->mainsFreq]
1293 [sd->params.sensorFps.baserate]
1294 [sd->params.sensorFps.divisor];
1295 setflicker = 1;
1296
1297 new_exposure = sd->params.flickerControl.coarseJump-1;
1298 while (new_exposure < old_exposure / 2)
1299 new_exposure +=
1300 sd->params.flickerControl.coarseJump;
1301 sd->params.exposure.coarseExpLo = new_exposure & 0xff;
1302 sd->params.exposure.coarseExpHi = new_exposure >> 8;
1303 setexp = 1;
1304 sd->exposure_status = EXPOSURE_NORMAL;
1305 gspca_dbg(gspca_dev, D_CONF, "Automatically decreasing sensor_fps\n");
1306
1307 } else if ((sd->exposure_status == EXPOSURE_VERY_LIGHT ||
1308 sd->exposure_status == EXPOSURE_LIGHT) &&
1309 sd->exposure_count >= LIGHT_TIME * framerate &&
1310 sd->params.sensorFps.divisor > 0) {
1311
1312
1313 int max_exp = FIRMWARE_VERSION(1, 2) ? MAX_EXP_102 :
1314 MAX_EXP;
1315 --sd->params.sensorFps.divisor;
1316 setfps = 1;
1317
1318 sd->params.flickerControl.coarseJump =
1319 flicker_jumps[sd->mainsFreq]
1320 [sd->params.sensorFps.baserate]
1321 [sd->params.sensorFps.divisor];
1322 setflicker = 1;
1323
1324 new_exposure = sd->params.flickerControl.coarseJump-1;
1325 while (new_exposure < 2 * old_exposure &&
1326 new_exposure +
1327 sd->params.flickerControl.coarseJump < max_exp)
1328 new_exposure +=
1329 sd->params.flickerControl.coarseJump;
1330 sd->params.exposure.coarseExpLo = new_exposure & 0xff;
1331 sd->params.exposure.coarseExpHi = new_exposure >> 8;
1332 setexp = 1;
1333 sd->exposure_status = EXPOSURE_NORMAL;
1334 gspca_dbg(gspca_dev, D_CONF, "Automatically increasing sensor_fps\n");
1335 }
1336 } else {
1337
1338 if ((sd->exposure_status == EXPOSURE_VERY_DARK ||
1339 sd->exposure_status == EXPOSURE_DARK) &&
1340 sd->exposure_count >= DARK_TIME * framerate &&
1341 sd->params.sensorFps.divisor < 2) {
1342
1343
1344 ++sd->params.sensorFps.divisor;
1345 setfps = 1;
1346
1347 if (sd->params.exposure.gain > 0) {
1348 --sd->params.exposure.gain;
1349 setexp = 1;
1350 }
1351 sd->exposure_status = EXPOSURE_NORMAL;
1352 gspca_dbg(gspca_dev, D_CONF, "Automatically decreasing sensor_fps\n");
1353
1354 } else if ((sd->exposure_status == EXPOSURE_VERY_LIGHT ||
1355 sd->exposure_status == EXPOSURE_LIGHT) &&
1356 sd->exposure_count >= LIGHT_TIME * framerate &&
1357 sd->params.sensorFps.divisor > 0) {
1358
1359
1360 --sd->params.sensorFps.divisor;
1361 setfps = 1;
1362
1363 if (sd->params.exposure.gain <
1364 sd->params.exposure.gainMode - 1) {
1365 ++sd->params.exposure.gain;
1366 setexp = 1;
1367 }
1368 sd->exposure_status = EXPOSURE_NORMAL;
1369 gspca_dbg(gspca_dev, D_CONF, "Automatically increasing sensor_fps\n");
1370 }
1371 }
1372
1373 if (setexp)
1374 command_setexposure(gspca_dev);
1375
1376 if (setfps)
1377 command_setsensorfps(gspca_dev);
1378
1379 if (setflicker)
1380 command_setflickerctrl(gspca_dev);
1381}
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391static void restart_flicker(struct gspca_dev *gspca_dev)
1392{
1393 struct sd *sd = (struct sd *) gspca_dev;
1394 int cam_exposure, old_exp;
1395
1396 if (!FIRMWARE_VERSION(1, 2))
1397 return;
1398
1399 cam_exposure = atomic_read(&sd->cam_exposure);
1400
1401 if (sd->params.flickerControl.flickerMode == 0 ||
1402 cam_exposure == 0)
1403 return;
1404
1405 old_exp = sd->params.exposure.coarseExpLo +
1406 sd->params.exposure.coarseExpHi*256;
1407
1408
1409
1410
1411 cam_exposure %= sd->params.flickerControl.coarseJump;
1412 if (!sd->params.flickerControl.disabled &&
1413 cam_exposure <= sd->params.flickerControl.coarseJump - 3) {
1414
1415 sd->params.flickerControl.disabled = 1;
1416 }
1417
1418 if (sd->params.flickerControl.disabled &&
1419 old_exp > sd->params.flickerControl.coarseJump +
1420 ROUND_UP_EXP_FOR_FLICKER) {
1421
1422
1423 set_flicker(gspca_dev, 1, 1);
1424 }
1425}
1426
1427
1428static int sd_config(struct gspca_dev *gspca_dev,
1429 const struct usb_device_id *id)
1430{
1431 struct sd *sd = (struct sd *) gspca_dev;
1432 struct cam *cam;
1433
1434 sd->mainsFreq = FREQ_DEF == V4L2_CID_POWER_LINE_FREQUENCY_60HZ;
1435 reset_camera_params(gspca_dev);
1436
1437 gspca_dbg(gspca_dev, D_PROBE, "cpia CPiA camera detected (vid/pid 0x%04X:0x%04X)\n",
1438 id->idVendor, id->idProduct);
1439
1440 cam = &gspca_dev->cam;
1441 cam->cam_mode = mode;
1442 cam->nmodes = ARRAY_SIZE(mode);
1443
1444 goto_low_power(gspca_dev);
1445
1446 sd->params.version.firmwareVersion = 0;
1447 get_version_information(gspca_dev);
1448 if (sd->params.version.firmwareVersion != 1) {
1449 gspca_err(gspca_dev, "only firmware version 1 is supported (got: %d)\n",
1450 sd->params.version.firmwareVersion);
1451 return -ENODEV;
1452 }
1453
1454
1455 if (sd->params.version.firmwareRevision <= 2 &&
1456 sd->params.exposure.gainMode > 2) {
1457 sd->params.exposure.gainMode = 2;
1458 }
1459
1460
1461 sd->params.qx3.qx3_detected = (sd->params.pnpID.vendor == 0x0813 &&
1462 sd->params.pnpID.product == 0x0001);
1463 return 0;
1464}
1465
1466
1467static int sd_start(struct gspca_dev *gspca_dev)
1468{
1469 struct sd *sd = (struct sd *) gspca_dev;
1470 int priv, ret;
1471
1472
1473 if (goto_low_power(gspca_dev)) {
1474 if (sd->params.status.systemState != WARM_BOOT_STATE) {
1475 gspca_err(gspca_dev, "unexpected systemstate: %02x\n",
1476 sd->params.status.systemState);
1477 printstatus(gspca_dev, &sd->params);
1478 return -ENODEV;
1479 }
1480
1481
1482 ret = goto_high_power(gspca_dev);
1483 if (ret)
1484 return ret;
1485
1486 ret = do_command(gspca_dev, CPIA_COMMAND_DiscardFrame,
1487 0, 0, 0, 0);
1488 if (ret)
1489 return ret;
1490
1491 ret = goto_low_power(gspca_dev);
1492 if (ret)
1493 return ret;
1494 }
1495
1496
1497
1498
1499 sd->params.version.firmwareVersion = 0;
1500 get_version_information(gspca_dev);
1501
1502
1503
1504
1505
1506
1507 ret = do_command(gspca_dev, CPIA_COMMAND_ModifyCameraStatus,
1508 STREAMSTATE, 0, STREAM_NOT_READY, 0);
1509 if (ret)
1510 return ret;
1511
1512
1513 ret = goto_high_power(gspca_dev);
1514 if (ret)
1515 return ret;
1516
1517
1518 ret = do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
1519 if (ret)
1520 return ret;
1521
1522 if (sd->params.status.fatalError) {
1523 gspca_err(gspca_dev, "fatal_error: %04x, vp_status: %04x\n",
1524 sd->params.status.fatalError,
1525 sd->params.status.vpStatus);
1526 return -EIO;
1527 }
1528
1529
1530
1531 ret = do_command(gspca_dev, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
1532 if (ret)
1533 return ret;
1534
1535
1536 sd->params.streamStartLine = 120;
1537
1538 priv = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
1539 if (priv & 0x01) {
1540 sd->params.roi.colStart = 2;
1541 sd->params.roi.rowStart = 6;
1542 } else {
1543 sd->params.roi.colStart = 0;
1544 sd->params.roi.rowStart = 0;
1545 }
1546
1547 if (priv & 0x02) {
1548 sd->params.format.videoSize = VIDEOSIZE_QCIF;
1549 sd->params.roi.colStart /= 2;
1550 sd->params.roi.rowStart /= 2;
1551 sd->params.streamStartLine /= 2;
1552 } else
1553 sd->params.format.videoSize = VIDEOSIZE_CIF;
1554
1555 sd->params.roi.colEnd = sd->params.roi.colStart +
1556 (gspca_dev->pixfmt.width >> 3);
1557 sd->params.roi.rowEnd = sd->params.roi.rowStart +
1558 (gspca_dev->pixfmt.height >> 2);
1559
1560
1561 ret = do_command(gspca_dev, CPIA_COMMAND_SetGrabMode,
1562 CPIA_GRAB_CONTINEOUS, 0, 0, 0);
1563 if (ret)
1564 return ret;
1565
1566
1567 ret = do_command(gspca_dev, CPIA_COMMAND_SetCompression,
1568 CPIA_COMPRESSION_NONE,
1569 NO_DECIMATION, 0, 0);
1570 if (ret)
1571 return ret;
1572 ret = command_setcompressiontarget(gspca_dev);
1573 if (ret)
1574 return ret;
1575 ret = command_setcolourparams(gspca_dev);
1576 if (ret)
1577 return ret;
1578 ret = command_setformat(gspca_dev);
1579 if (ret)
1580 return ret;
1581 ret = command_setyuvtresh(gspca_dev);
1582 if (ret)
1583 return ret;
1584 ret = command_setecptiming(gspca_dev);
1585 if (ret)
1586 return ret;
1587 ret = command_setcompressionparams(gspca_dev);
1588 if (ret)
1589 return ret;
1590 ret = command_setexposure(gspca_dev);
1591 if (ret)
1592 return ret;
1593 ret = command_setcolourbalance(gspca_dev);
1594 if (ret)
1595 return ret;
1596 ret = command_setsensorfps(gspca_dev);
1597 if (ret)
1598 return ret;
1599 ret = command_setapcor(gspca_dev);
1600 if (ret)
1601 return ret;
1602 ret = command_setflickerctrl(gspca_dev);
1603 if (ret)
1604 return ret;
1605 ret = command_setvloffset(gspca_dev);
1606 if (ret)
1607 return ret;
1608
1609
1610 ret = command_resume(gspca_dev);
1611 if (ret)
1612 return ret;
1613
1614
1615
1616 sd->first_frame = 6;
1617 sd->exposure_status = EXPOSURE_NORMAL;
1618 sd->exposure_count = 0;
1619 atomic_set(&sd->cam_exposure, 0);
1620 atomic_set(&sd->fps, 0);
1621
1622 return 0;
1623}
1624
1625static void sd_stopN(struct gspca_dev *gspca_dev)
1626{
1627 struct sd *sd __maybe_unused = (struct sd *) gspca_dev;
1628
1629 command_pause(gspca_dev);
1630
1631
1632 save_camera_state(gspca_dev);
1633
1634
1635 goto_low_power(gspca_dev);
1636
1637
1638 do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
1639
1640#if IS_ENABLED(CONFIG_INPUT)
1641
1642 if (sd->params.qx3.button) {
1643
1644
1645
1646 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
1647 input_sync(gspca_dev->input_dev);
1648 }
1649#endif
1650}
1651
1652
1653static int sd_init(struct gspca_dev *gspca_dev)
1654{
1655 struct sd *sd = (struct sd *) gspca_dev;
1656 int ret;
1657
1658
1659
1660
1661 ret = sd_start(gspca_dev);
1662 if (ret)
1663 return ret;
1664
1665
1666
1667 if (sd->params.qx3.qx3_detected)
1668 command_setlights(gspca_dev);
1669
1670 sd_stopN(gspca_dev);
1671
1672 gspca_dbg(gspca_dev, D_PROBE, "CPIA Version: %d.%02d (%d.%d)\n",
1673 sd->params.version.firmwareVersion,
1674 sd->params.version.firmwareRevision,
1675 sd->params.version.vcVersion,
1676 sd->params.version.vcRevision);
1677 gspca_dbg(gspca_dev, D_PROBE, "CPIA PnP-ID: %04x:%04x:%04x",
1678 sd->params.pnpID.vendor, sd->params.pnpID.product,
1679 sd->params.pnpID.deviceRevision);
1680 gspca_dbg(gspca_dev, D_PROBE, "VP-Version: %d.%d %04x",
1681 sd->params.vpVersion.vpVersion,
1682 sd->params.vpVersion.vpRevision,
1683 sd->params.vpVersion.cameraHeadID);
1684
1685 return 0;
1686}
1687
1688static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1689 u8 *data,
1690 int len)
1691{
1692 struct sd *sd = (struct sd *) gspca_dev;
1693
1694
1695 if (len >= 64 &&
1696 data[0] == MAGIC_0 && data[1] == MAGIC_1 &&
1697 data[16] == sd->params.format.videoSize &&
1698 data[17] == sd->params.format.subSample &&
1699 data[18] == sd->params.format.yuvOrder &&
1700 data[24] == sd->params.roi.colStart &&
1701 data[25] == sd->params.roi.colEnd &&
1702 data[26] == sd->params.roi.rowStart &&
1703 data[27] == sd->params.roi.rowEnd) {
1704 u8 *image;
1705
1706 atomic_set(&sd->cam_exposure, data[39] * 2);
1707 atomic_set(&sd->fps, data[41]);
1708
1709
1710 image = gspca_dev->image;
1711 if (image != NULL &&
1712 gspca_dev->image_len > 4 &&
1713 image[gspca_dev->image_len - 4] == 0xff &&
1714 image[gspca_dev->image_len - 3] == 0xff &&
1715 image[gspca_dev->image_len - 2] == 0xff &&
1716 image[gspca_dev->image_len - 1] == 0xff)
1717 gspca_frame_add(gspca_dev, LAST_PACKET,
1718 NULL, 0);
1719
1720 gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
1721 return;
1722 }
1723
1724 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
1725}
1726
1727static void sd_dq_callback(struct gspca_dev *gspca_dev)
1728{
1729 struct sd *sd = (struct sd *) gspca_dev;
1730
1731
1732
1733 if (sd->first_frame) {
1734 sd->first_frame--;
1735 if (sd->first_frame == 0)
1736 command_setcompression(gspca_dev);
1737 }
1738
1739
1740 restart_flicker(gspca_dev);
1741
1742
1743
1744 if (sd->params.exposure.expMode == 2)
1745 monitor_exposure(gspca_dev);
1746
1747
1748 do_command(gspca_dev, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
1749 do_command(gspca_dev, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
1750}
1751
1752static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
1753{
1754 struct gspca_dev *gspca_dev =
1755 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
1756 struct sd *sd = (struct sd *)gspca_dev;
1757
1758 gspca_dev->usb_err = 0;
1759
1760 if (!gspca_dev->streaming && ctrl->id != V4L2_CID_POWER_LINE_FREQUENCY)
1761 return 0;
1762
1763 switch (ctrl->id) {
1764 case V4L2_CID_BRIGHTNESS:
1765 sd->params.colourParams.brightness = ctrl->val;
1766 sd->params.flickerControl.allowableOverExposure =
1767 find_over_exposure(sd->params.colourParams.brightness);
1768 gspca_dev->usb_err = command_setcolourparams(gspca_dev);
1769 if (!gspca_dev->usb_err)
1770 gspca_dev->usb_err = command_setflickerctrl(gspca_dev);
1771 break;
1772 case V4L2_CID_CONTRAST:
1773 sd->params.colourParams.contrast = ctrl->val;
1774 gspca_dev->usb_err = command_setcolourparams(gspca_dev);
1775 break;
1776 case V4L2_CID_SATURATION:
1777 sd->params.colourParams.saturation = ctrl->val;
1778 gspca_dev->usb_err = command_setcolourparams(gspca_dev);
1779 break;
1780 case V4L2_CID_POWER_LINE_FREQUENCY:
1781 sd->mainsFreq = ctrl->val == V4L2_CID_POWER_LINE_FREQUENCY_60HZ;
1782 sd->params.flickerControl.coarseJump =
1783 flicker_jumps[sd->mainsFreq]
1784 [sd->params.sensorFps.baserate]
1785 [sd->params.sensorFps.divisor];
1786
1787 gspca_dev->usb_err = set_flicker(gspca_dev,
1788 ctrl->val != V4L2_CID_POWER_LINE_FREQUENCY_DISABLED,
1789 gspca_dev->streaming);
1790 break;
1791 case V4L2_CID_ILLUMINATORS_1:
1792 sd->params.qx3.bottomlight = ctrl->val;
1793 gspca_dev->usb_err = command_setlights(gspca_dev);
1794 break;
1795 case V4L2_CID_ILLUMINATORS_2:
1796 sd->params.qx3.toplight = ctrl->val;
1797 gspca_dev->usb_err = command_setlights(gspca_dev);
1798 break;
1799 case CPIA1_CID_COMP_TARGET:
1800 sd->params.compressionTarget.frTargeting = ctrl->val;
1801 gspca_dev->usb_err = command_setcompressiontarget(gspca_dev);
1802 break;
1803 }
1804 return gspca_dev->usb_err;
1805}
1806
1807static const struct v4l2_ctrl_ops sd_ctrl_ops = {
1808 .s_ctrl = sd_s_ctrl,
1809};
1810
1811static int sd_init_controls(struct gspca_dev *gspca_dev)
1812{
1813 struct sd *sd = (struct sd *)gspca_dev;
1814 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
1815 static const char * const comp_target_menu[] = {
1816 "Quality",
1817 "Framerate",
1818 NULL
1819 };
1820 static const struct v4l2_ctrl_config comp_target = {
1821 .ops = &sd_ctrl_ops,
1822 .id = CPIA1_CID_COMP_TARGET,
1823 .type = V4L2_CTRL_TYPE_MENU,
1824 .name = "Compression Target",
1825 .qmenu = comp_target_menu,
1826 .max = 1,
1827 .def = COMP_TARGET_DEF,
1828 };
1829
1830 gspca_dev->vdev.ctrl_handler = hdl;
1831 v4l2_ctrl_handler_init(hdl, 7);
1832 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1833 V4L2_CID_BRIGHTNESS, 0, 100, 1, BRIGHTNESS_DEF);
1834 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1835 V4L2_CID_CONTRAST, 0, 96, 8, CONTRAST_DEF);
1836 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1837 V4L2_CID_SATURATION, 0, 100, 1, SATURATION_DEF);
1838 sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
1839 V4L2_CID_POWER_LINE_FREQUENCY,
1840 V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 0,
1841 FREQ_DEF);
1842 if (sd->params.qx3.qx3_detected) {
1843 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1844 V4L2_CID_ILLUMINATORS_1, 0, 1, 1,
1845 ILLUMINATORS_1_DEF);
1846 v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
1847 V4L2_CID_ILLUMINATORS_2, 0, 1, 1,
1848 ILLUMINATORS_2_DEF);
1849 }
1850 v4l2_ctrl_new_custom(hdl, &comp_target, NULL);
1851
1852 if (hdl->error) {
1853 pr_err("Could not initialize controls\n");
1854 return hdl->error;
1855 }
1856 return 0;
1857}
1858
1859
1860static const struct sd_desc sd_desc = {
1861 .name = MODULE_NAME,
1862 .config = sd_config,
1863 .init = sd_init,
1864 .init_controls = sd_init_controls,
1865 .start = sd_start,
1866 .stopN = sd_stopN,
1867 .dq_callback = sd_dq_callback,
1868 .pkt_scan = sd_pkt_scan,
1869#if IS_ENABLED(CONFIG_INPUT)
1870 .other_input = 1,
1871#endif
1872};
1873
1874
1875static const struct usb_device_id device_table[] = {
1876 {USB_DEVICE(0x0553, 0x0002)},
1877 {USB_DEVICE(0x0813, 0x0001)},
1878 {}
1879};
1880MODULE_DEVICE_TABLE(usb, device_table);
1881
1882
1883static int sd_probe(struct usb_interface *intf,
1884 const struct usb_device_id *id)
1885{
1886 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1887 THIS_MODULE);
1888}
1889
1890static struct usb_driver sd_driver = {
1891 .name = MODULE_NAME,
1892 .id_table = device_table,
1893 .probe = sd_probe,
1894 .disconnect = gspca_disconnect,
1895#ifdef CONFIG_PM
1896 .suspend = gspca_suspend,
1897 .resume = gspca_resume,
1898 .reset_resume = gspca_resume,
1899#endif
1900};
1901
1902module_usb_driver(sd_driver);
1903