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