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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
94
95#include <linux/input.h>
96#include <media/v4l2-chip-ident.h>
97#include "gspca.h"
98
99#include "pac_common.h"
100
101#define PAC7302_RGB_BALANCE_MIN 0
102#define PAC7302_RGB_BALANCE_MAX 200
103#define PAC7302_RGB_BALANCE_DEFAULT 100
104#define PAC7302_GAIN_DEFAULT 15
105#define PAC7302_GAIN_KNEE 42
106#define PAC7302_EXPOSURE_DEFAULT 66
107#define PAC7302_EXPOSURE_KNEE 133
108
109MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>, "
110 "Thomas Kaiser thomas@kaiser-linux.li");
111MODULE_DESCRIPTION("Pixart PAC7302");
112MODULE_LICENSE("GPL");
113
114struct sd {
115 struct gspca_dev gspca_dev;
116
117 struct {
118 struct v4l2_ctrl *brightness;
119 struct v4l2_ctrl *contrast;
120 };
121 struct v4l2_ctrl *saturation;
122 struct v4l2_ctrl *white_balance;
123 struct v4l2_ctrl *red_balance;
124 struct v4l2_ctrl *blue_balance;
125 struct {
126 struct v4l2_ctrl *hflip;
127 struct v4l2_ctrl *vflip;
128 };
129 struct v4l2_ctrl *sharpness;
130 u8 flags;
131#define FL_HFLIP 0x01
132#define FL_VFLIP 0x02
133
134 u8 sof_read;
135 s8 autogain_ignore_frames;
136
137 atomic_t avg_lum;
138};
139
140static const struct v4l2_pix_format vga_mode[] = {
141 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
142 .bytesperline = 640,
143 .sizeimage = 640 * 480 * 3 / 8 + 590,
144 .colorspace = V4L2_COLORSPACE_JPEG,
145 },
146};
147
148#define LOAD_PAGE3 255
149#define END_OF_SEQUENCE 0
150
151static const u8 init_7302[] = {
152
153 0xff, 0x01,
154 0x78, 0x00,
155 0xff, 0x01,
156 0x78, 0x40,
157};
158static const u8 start_7302[] = {
159
160 0xff, 1, 0x00,
161 0x00, 12, 0x01, 0x40, 0x40, 0x40, 0x01, 0xe0, 0x02, 0x80,
162 0x00, 0x00, 0x00, 0x00,
163 0x0d, 24, 0x03, 0x01, 0x00, 0xb5, 0x07, 0xcb, 0x00, 0x00,
164 0x07, 0xc8, 0x00, 0xea, 0x07, 0xcf, 0x07, 0xf7,
165 0x07, 0x7e, 0x01, 0x0b, 0x00, 0x00, 0x00, 0x11,
166 0x26, 2, 0xaa, 0xaa,
167 0x2e, 1, 0x31,
168 0x38, 1, 0x01,
169 0x3a, 3, 0x14, 0xff, 0x5a,
170 0x43, 11, 0x00, 0x0a, 0x18, 0x11, 0x01, 0x2c, 0x88, 0x11,
171 0x00, 0x54, 0x11,
172 0x55, 1, 0x00,
173 0x62, 4, 0x10, 0x1e, 0x1e, 0x18,
174 0x6b, 1, 0x00,
175 0x6e, 3, 0x08, 0x06, 0x00,
176 0x72, 3, 0x00, 0xff, 0x00,
177 0x7d, 23, 0x01, 0x01, 0x58, 0x46, 0x50, 0x3c, 0x50, 0x3c,
178 0x54, 0x46, 0x54, 0x56, 0x52, 0x50, 0x52, 0x50,
179 0x56, 0x64, 0xa4, 0x00, 0xda, 0x00, 0x00,
180 0xa2, 10, 0x22, 0x2c, 0x3c, 0x54, 0x69, 0x7c, 0x9c, 0xb9,
181 0xd2, 0xeb,
182 0xaf, 1, 0x02,
183 0xb5, 2, 0x08, 0x08,
184 0xb8, 2, 0x08, 0x88,
185 0xc4, 4, 0xae, 0x01, 0x04, 0x01,
186 0xcc, 1, 0x00,
187 0xd1, 11, 0x01, 0x30, 0x49, 0x5e, 0x6f, 0x7f, 0x8e, 0xa9,
188 0xc1, 0xd7, 0xec,
189 0xdc, 1, 0x01,
190 0xff, 1, 0x01,
191 0x12, 3, 0x02, 0x00, 0x01,
192 0x3e, 2, 0x00, 0x00,
193 0x76, 5, 0x01, 0x20, 0x40, 0x00, 0xf2,
194 0x7c, 1, 0x00,
195 0x7f, 10, 0x4b, 0x0f, 0x01, 0x2c, 0x02, 0x58, 0x03, 0x20,
196 0x02, 0x00,
197 0x96, 5, 0x01, 0x10, 0x04, 0x01, 0x04,
198 0xc8, 14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00,
199 0x07, 0x00, 0x01, 0x07, 0x04, 0x01,
200 0xd8, 1, 0x01,
201 0xdb, 2, 0x00, 0x01,
202 0xde, 7, 0x00, 0x01, 0x04, 0x04, 0x00, 0x00, 0x00,
203 0xe6, 4, 0x00, 0x00, 0x00, 0x01,
204 0xeb, 1, 0x00,
205 0xff, 1, 0x02,
206 0x22, 1, 0x00,
207 0xff, 1, 0x03,
208 0, LOAD_PAGE3,
209 0x11, 1, 0x01,
210 0xff, 1, 0x02,
211 0x13, 1, 0x00,
212 0x22, 4, 0x1f, 0xa4, 0xf0, 0x96,
213 0x27, 2, 0x14, 0x0c,
214 0x2a, 5, 0xc8, 0x00, 0x18, 0x12, 0x22,
215 0x64, 8, 0x00, 0x00, 0xf0, 0x01, 0x14, 0x44, 0x44, 0x44,
216 0x6e, 1, 0x08,
217 0xff, 1, 0x01,
218 0x78, 1, 0x00,
219 0, END_OF_SEQUENCE
220};
221
222#define SKIP 0xaa
223
224static const u8 page3_7302[] = {
225 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16,
226 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00,
227 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00,
229 0x00, 0x08, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x21,
230 0x00, 0x00, 0x00, 0x54, 0xf4, 0x02, 0x52, 0x54,
231 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00,
232 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
233 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00,
234 SKIP, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00,
235 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
236 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00,
237 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0xc8, 0xc8,
239 0xc8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50,
240 0x08, 0x10, 0x24, 0x40, 0x00, 0x00, 0x00, 0x00,
241 0x01, 0x00, 0x02, 0x47, 0x00, 0x00, 0x00, 0x00,
242 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
243 0x00, 0x02, 0xfa, 0x00, 0x64, 0x5a, 0x28, 0x00,
244 0x00
245};
246
247static void reg_w_buf(struct gspca_dev *gspca_dev,
248 u8 index,
249 const u8 *buffer, int len)
250{
251 int ret;
252
253 if (gspca_dev->usb_err < 0)
254 return;
255 memcpy(gspca_dev->usb_buf, buffer, len);
256 ret = usb_control_msg(gspca_dev->dev,
257 usb_sndctrlpipe(gspca_dev->dev, 0),
258 0,
259 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
260 0,
261 index, gspca_dev->usb_buf, len,
262 500);
263 if (ret < 0) {
264 pr_err("reg_w_buf failed i: %02x error %d\n",
265 index, ret);
266 gspca_dev->usb_err = ret;
267 }
268}
269
270
271static void reg_w(struct gspca_dev *gspca_dev,
272 u8 index,
273 u8 value)
274{
275 int ret;
276
277 if (gspca_dev->usb_err < 0)
278 return;
279 gspca_dev->usb_buf[0] = value;
280 ret = usb_control_msg(gspca_dev->dev,
281 usb_sndctrlpipe(gspca_dev->dev, 0),
282 0,
283 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
284 0, index, gspca_dev->usb_buf, 1,
285 500);
286 if (ret < 0) {
287 pr_err("reg_w() failed i: %02x v: %02x error %d\n",
288 index, value, ret);
289 gspca_dev->usb_err = ret;
290 }
291}
292
293static void reg_w_seq(struct gspca_dev *gspca_dev,
294 const u8 *seq, int len)
295{
296 while (--len >= 0) {
297 reg_w(gspca_dev, seq[0], seq[1]);
298 seq += 2;
299 }
300}
301
302
303static void reg_w_page(struct gspca_dev *gspca_dev,
304 const u8 *page, int len)
305{
306 int index;
307 int ret = 0;
308
309 if (gspca_dev->usb_err < 0)
310 return;
311 for (index = 0; index < len; index++) {
312 if (page[index] == SKIP)
313 continue;
314 gspca_dev->usb_buf[0] = page[index];
315 ret = usb_control_msg(gspca_dev->dev,
316 usb_sndctrlpipe(gspca_dev->dev, 0),
317 0,
318 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
319 0, index, gspca_dev->usb_buf, 1,
320 500);
321 if (ret < 0) {
322 pr_err("reg_w_page() failed i: %02x v: %02x error %d\n",
323 index, page[index], ret);
324 gspca_dev->usb_err = ret;
325 break;
326 }
327 }
328}
329
330
331static void reg_w_var(struct gspca_dev *gspca_dev,
332 const u8 *seq,
333 const u8 *page3, unsigned int page3_len)
334{
335 int index, len;
336
337 for (;;) {
338 index = *seq++;
339 len = *seq++;
340 switch (len) {
341 case END_OF_SEQUENCE:
342 return;
343 case LOAD_PAGE3:
344 reg_w_page(gspca_dev, page3, page3_len);
345 break;
346 default:
347#ifdef GSPCA_DEBUG
348 if (len > USB_BUF_SZ) {
349 PDEBUG(D_ERR|D_STREAM,
350 "Incorrect variable sequence");
351 return;
352 }
353#endif
354 while (len > 0) {
355 if (len < 8) {
356 reg_w_buf(gspca_dev,
357 index, seq, len);
358 seq += len;
359 break;
360 }
361 reg_w_buf(gspca_dev, index, seq, 8);
362 seq += 8;
363 index += 8;
364 len -= 8;
365 }
366 }
367 }
368
369}
370
371
372static int sd_config(struct gspca_dev *gspca_dev,
373 const struct usb_device_id *id)
374{
375 struct sd *sd = (struct sd *) gspca_dev;
376 struct cam *cam;
377
378 cam = &gspca_dev->cam;
379
380 cam->cam_mode = vga_mode;
381 cam->nmodes = ARRAY_SIZE(vga_mode);
382
383 sd->flags = id->driver_info;
384 return 0;
385}
386
387static void setbrightcont(struct gspca_dev *gspca_dev)
388{
389 struct sd *sd = (struct sd *) gspca_dev;
390 int i, v;
391 static const u8 max[10] =
392 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
393 0xd4, 0xec};
394 static const u8 delta[10] =
395 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
396 0x11, 0x0b};
397
398 reg_w(gspca_dev, 0xff, 0x00);
399 for (i = 0; i < 10; i++) {
400 v = max[i];
401 v += (sd->brightness->val - sd->brightness->maximum)
402 * 150 / sd->brightness->maximum;
403 v -= delta[i] * sd->contrast->val / sd->contrast->maximum;
404 if (v < 0)
405 v = 0;
406 else if (v > 0xff)
407 v = 0xff;
408 reg_w(gspca_dev, 0xa2 + i, v);
409 }
410 reg_w(gspca_dev, 0xdc, 0x01);
411}
412
413static void setcolors(struct gspca_dev *gspca_dev)
414{
415 struct sd *sd = (struct sd *) gspca_dev;
416 int i, v;
417 static const int a[9] =
418 {217, -212, 0, -101, 170, -67, -38, -315, 355};
419 static const int b[9] =
420 {19, 106, 0, 19, 106, 1, 19, 106, 1};
421
422 reg_w(gspca_dev, 0xff, 0x03);
423 reg_w(gspca_dev, 0x11, 0x01);
424 reg_w(gspca_dev, 0xff, 0x00);
425 for (i = 0; i < 9; i++) {
426 v = a[i] * sd->saturation->val / sd->saturation->maximum;
427 v += b[i];
428 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
429 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
430 }
431 reg_w(gspca_dev, 0xdc, 0x01);
432}
433
434static void setwhitebalance(struct gspca_dev *gspca_dev)
435{
436 struct sd *sd = (struct sd *) gspca_dev;
437
438 reg_w(gspca_dev, 0xff, 0x00);
439 reg_w(gspca_dev, 0xc6, sd->white_balance->val);
440
441 reg_w(gspca_dev, 0xdc, 0x01);
442}
443
444static u8 rgbbalance_ctrl_to_reg_value(s32 rgb_ctrl_val)
445{
446 const unsigned int k = 1000;
447 unsigned int norm;
448
449
450 norm = k * (rgb_ctrl_val - PAC7302_RGB_BALANCE_MIN)
451 / (PAC7302_RGB_BALANCE_MAX - PAC7302_RGB_BALANCE_MIN);
452
453 return 64 * norm * norm / (k*k) + 32 * norm / k + 32;
454
455
456
457
458
459
460}
461
462static void setredbalance(struct gspca_dev *gspca_dev)
463{
464 struct sd *sd = (struct sd *) gspca_dev;
465
466 reg_w(gspca_dev, 0xff, 0x00);
467 reg_w(gspca_dev, 0x01,
468 rgbbalance_ctrl_to_reg_value(sd->red_balance->val));
469
470 reg_w(gspca_dev, 0xdc, 0x01);
471}
472
473static void setbluebalance(struct gspca_dev *gspca_dev)
474{
475 struct sd *sd = (struct sd *) gspca_dev;
476
477 reg_w(gspca_dev, 0xff, 0x00);
478 reg_w(gspca_dev, 0x03,
479 rgbbalance_ctrl_to_reg_value(sd->blue_balance->val));
480
481 reg_w(gspca_dev, 0xdc, 0x01);
482}
483
484static void setgain(struct gspca_dev *gspca_dev)
485{
486 u8 reg10, reg12;
487
488 if (gspca_dev->gain->val < 32) {
489 reg10 = gspca_dev->gain->val;
490 reg12 = 0;
491 } else {
492 reg10 = 31;
493 reg12 = gspca_dev->gain->val - 31;
494 }
495
496 reg_w(gspca_dev, 0xff, 0x03);
497 reg_w(gspca_dev, 0x10, reg10);
498 reg_w(gspca_dev, 0x12, reg12);
499
500
501 reg_w(gspca_dev, 0x11, 0x01);
502}
503
504static void setexposure(struct gspca_dev *gspca_dev)
505{
506 u8 clockdiv;
507 u16 exposure;
508
509
510
511
512
513
514 clockdiv = (90 * gspca_dev->exposure->val + 1999) / 2000;
515
516
517
518
519
520
521
522 if (clockdiv < 6)
523 clockdiv = 6;
524 else if (clockdiv > 63)
525 clockdiv = 63;
526
527
528
529
530
531
532 if (clockdiv < 6 || clockdiv > 12)
533 clockdiv = ((clockdiv + 2) / 3) * 3;
534
535
536
537
538
539 exposure = (gspca_dev->exposure->val * 45 * 448) / (1000 * clockdiv);
540
541 exposure = 448 - exposure;
542
543 reg_w(gspca_dev, 0xff, 0x03);
544 reg_w(gspca_dev, 0x02, clockdiv);
545 reg_w(gspca_dev, 0x0e, exposure & 0xff);
546 reg_w(gspca_dev, 0x0f, exposure >> 8);
547
548
549 reg_w(gspca_dev, 0x11, 0x01);
550}
551
552static void sethvflip(struct gspca_dev *gspca_dev)
553{
554 struct sd *sd = (struct sd *) gspca_dev;
555 u8 data, hflip, vflip;
556
557 hflip = sd->hflip->val;
558 if (sd->flags & FL_HFLIP)
559 hflip = !hflip;
560 vflip = sd->vflip->val;
561 if (sd->flags & FL_VFLIP)
562 vflip = !vflip;
563
564 reg_w(gspca_dev, 0xff, 0x03);
565 data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00);
566 reg_w(gspca_dev, 0x21, data);
567
568
569 reg_w(gspca_dev, 0x11, 0x01);
570}
571
572static void setsharpness(struct gspca_dev *gspca_dev)
573{
574 struct sd *sd = (struct sd *) gspca_dev;
575
576 reg_w(gspca_dev, 0xff, 0x00);
577 reg_w(gspca_dev, 0xb6, sd->sharpness->val);
578
579 reg_w(gspca_dev, 0xdc, 0x01);
580}
581
582
583static int sd_init(struct gspca_dev *gspca_dev)
584{
585 reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
586 return gspca_dev->usb_err;
587}
588
589static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
590{
591 struct gspca_dev *gspca_dev =
592 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
593 struct sd *sd = (struct sd *)gspca_dev;
594
595 gspca_dev->usb_err = 0;
596
597 if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
598
599
600
601
602 gspca_dev->exposure->val = PAC7302_EXPOSURE_DEFAULT;
603 gspca_dev->gain->val = PAC7302_GAIN_DEFAULT;
604 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
605 }
606
607 if (!gspca_dev->streaming)
608 return 0;
609
610 switch (ctrl->id) {
611 case V4L2_CID_BRIGHTNESS:
612 setbrightcont(gspca_dev);
613 break;
614 case V4L2_CID_SATURATION:
615 setcolors(gspca_dev);
616 break;
617 case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
618 setwhitebalance(gspca_dev);
619 break;
620 case V4L2_CID_RED_BALANCE:
621 setredbalance(gspca_dev);
622 break;
623 case V4L2_CID_BLUE_BALANCE:
624 setbluebalance(gspca_dev);
625 break;
626 case V4L2_CID_AUTOGAIN:
627 if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
628 setexposure(gspca_dev);
629 if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
630 setgain(gspca_dev);
631 break;
632 case V4L2_CID_HFLIP:
633 sethvflip(gspca_dev);
634 break;
635 case V4L2_CID_SHARPNESS:
636 setsharpness(gspca_dev);
637 break;
638 default:
639 return -EINVAL;
640 }
641 return gspca_dev->usb_err;
642}
643
644static const struct v4l2_ctrl_ops sd_ctrl_ops = {
645 .s_ctrl = sd_s_ctrl,
646};
647
648
649static int sd_init_controls(struct gspca_dev *gspca_dev)
650{
651 struct sd *sd = (struct sd *) gspca_dev;
652 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
653
654 gspca_dev->vdev.ctrl_handler = hdl;
655 v4l2_ctrl_handler_init(hdl, 12);
656
657 sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
658 V4L2_CID_BRIGHTNESS, 0, 32, 1, 16);
659 sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
660 V4L2_CID_CONTRAST, 0, 255, 1, 127);
661
662 sd->saturation = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
663 V4L2_CID_SATURATION, 0, 255, 1, 127);
664 sd->white_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
665 V4L2_CID_WHITE_BALANCE_TEMPERATURE,
666 0, 255, 1, 55);
667 sd->red_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
668 V4L2_CID_RED_BALANCE,
669 PAC7302_RGB_BALANCE_MIN,
670 PAC7302_RGB_BALANCE_MAX,
671 1, PAC7302_RGB_BALANCE_DEFAULT);
672 sd->blue_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
673 V4L2_CID_BLUE_BALANCE,
674 PAC7302_RGB_BALANCE_MIN,
675 PAC7302_RGB_BALANCE_MAX,
676 1, PAC7302_RGB_BALANCE_DEFAULT);
677
678 gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
679 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
680 gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
681 V4L2_CID_EXPOSURE, 0, 1023, 1,
682 PAC7302_EXPOSURE_DEFAULT);
683 gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
684 V4L2_CID_GAIN, 0, 62, 1,
685 PAC7302_GAIN_DEFAULT);
686
687 sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
688 V4L2_CID_HFLIP, 0, 1, 1, 0);
689 sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
690 V4L2_CID_VFLIP, 0, 1, 1, 0);
691
692 sd->sharpness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
693 V4L2_CID_SHARPNESS, 0, 15, 1, 8);
694
695 if (hdl->error) {
696 pr_err("Could not initialize controls\n");
697 return hdl->error;
698 }
699
700 v4l2_ctrl_cluster(2, &sd->brightness);
701 v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false);
702 v4l2_ctrl_cluster(2, &sd->hflip);
703 return 0;
704}
705
706
707static int sd_start(struct gspca_dev *gspca_dev)
708{
709 struct sd *sd = (struct sd *) gspca_dev;
710
711 reg_w_var(gspca_dev, start_7302,
712 page3_7302, sizeof(page3_7302));
713
714 sd->sof_read = 0;
715 sd->autogain_ignore_frames = 0;
716 atomic_set(&sd->avg_lum, 270 + sd->brightness->val);
717
718
719 reg_w(gspca_dev, 0xff, 0x01);
720 reg_w(gspca_dev, 0x78, 0x01);
721
722 return gspca_dev->usb_err;
723}
724
725static void sd_stopN(struct gspca_dev *gspca_dev)
726{
727
728
729 reg_w(gspca_dev, 0xff, 0x01);
730 reg_w(gspca_dev, 0x78, 0x00);
731}
732
733
734static void sd_stop0(struct gspca_dev *gspca_dev)
735{
736 if (!gspca_dev->present)
737 return;
738 reg_w(gspca_dev, 0xff, 0x01);
739 reg_w(gspca_dev, 0x78, 0x40);
740}
741
742static void do_autogain(struct gspca_dev *gspca_dev)
743{
744 struct sd *sd = (struct sd *) gspca_dev;
745 int avg_lum = atomic_read(&sd->avg_lum);
746 int desired_lum;
747 const int deadzone = 30;
748
749 if (sd->autogain_ignore_frames < 0)
750 return;
751
752 if (sd->autogain_ignore_frames > 0) {
753 sd->autogain_ignore_frames--;
754 } else {
755 desired_lum = 270 + sd->brightness->val;
756
757 if (gspca_expo_autogain(gspca_dev, avg_lum, desired_lum,
758 deadzone, PAC7302_GAIN_KNEE,
759 PAC7302_EXPOSURE_KNEE))
760 sd->autogain_ignore_frames =
761 PAC_AUTOGAIN_IGNORE_FRAMES;
762 }
763}
764
765
766static const u8 jpeg_header[] = {
767 0xff, 0xd8,
768
769 0xff, 0xc0,
770 0x00, 0x11,
771 0x08,
772 0x02, 0x80,
773 0x01, 0xe0,
774 0x03,
775 0x01, 0x21, 0x00,
776 0x02, 0x11, 0x01,
777 0x03, 0x11, 0x01,
778
779 0xff, 0xda,
780 0x00, 0x0c,
781 0x03,
782 0x01, 0x00,
783 0x02, 0x11,
784 0x03, 0x11,
785 0x00, 0x3f,
786 0x00
787};
788
789
790static void sd_pkt_scan(struct gspca_dev *gspca_dev,
791 u8 *data,
792 int len)
793{
794 struct sd *sd = (struct sd *) gspca_dev;
795 u8 *image;
796 u8 *sof;
797
798 sof = pac_find_sof(&sd->sof_read, data, len);
799 if (sof) {
800 int n, lum_offset, footer_length;
801
802
803
804
805
806
807
808 lum_offset = 61 + sizeof pac_sof_marker;
809 footer_length = 74;
810
811
812 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
813 if (n < 0) {
814 gspca_dev->image_len += n;
815 n = 0;
816 } else {
817 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
818 }
819
820 image = gspca_dev->image;
821 if (image != NULL
822 && image[gspca_dev->image_len - 2] == 0xff
823 && image[gspca_dev->image_len - 1] == 0xd9)
824 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
825
826 n = sof - data;
827 len -= n;
828 data = sof;
829
830
831 if (gspca_dev->last_packet_type == LAST_PACKET &&
832 n >= lum_offset)
833 atomic_set(&sd->avg_lum, data[-lum_offset] +
834 data[-lum_offset + 1]);
835
836
837
838 gspca_frame_add(gspca_dev, FIRST_PACKET,
839 jpeg_header, sizeof jpeg_header);
840 }
841 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
842}
843
844#ifdef CONFIG_VIDEO_ADV_DEBUG
845static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
846 struct v4l2_dbg_register *reg)
847{
848 u8 index;
849 u8 value;
850
851
852
853
854
855 if (reg->match.type == V4L2_CHIP_MATCH_HOST &&
856 reg->match.addr == 0 &&
857 (reg->reg < 0x000000ff) &&
858 (reg->val <= 0x000000ff)
859 ) {
860
861
862 index = reg->reg;
863 value = reg->val;
864
865
866
867
868
869
870 reg_w(gspca_dev, 0xff, 0x00);
871 reg_w(gspca_dev, index, value);
872
873 reg_w(gspca_dev, 0xdc, 0x01);
874 }
875 return gspca_dev->usb_err;
876}
877
878static int sd_chip_ident(struct gspca_dev *gspca_dev,
879 struct v4l2_dbg_chip_ident *chip)
880{
881 int ret = -EINVAL;
882
883 if (chip->match.type == V4L2_CHIP_MATCH_HOST &&
884 chip->match.addr == 0) {
885 chip->revision = 0;
886 chip->ident = V4L2_IDENT_UNKNOWN;
887 ret = 0;
888 }
889 return ret;
890}
891#endif
892
893#if IS_ENABLED(CONFIG_INPUT)
894static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
895 u8 *data,
896 int len)
897{
898 int ret = -EINVAL;
899 u8 data0, data1;
900
901 if (len == 2) {
902 data0 = data[0];
903 data1 = data[1];
904 if ((data0 == 0x00 && data1 == 0x11) ||
905 (data0 == 0x22 && data1 == 0x33) ||
906 (data0 == 0x44 && data1 == 0x55) ||
907 (data0 == 0x66 && data1 == 0x77) ||
908 (data0 == 0x88 && data1 == 0x99) ||
909 (data0 == 0xaa && data1 == 0xbb) ||
910 (data0 == 0xcc && data1 == 0xdd) ||
911 (data0 == 0xee && data1 == 0xff)) {
912 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
913 input_sync(gspca_dev->input_dev);
914 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
915 input_sync(gspca_dev->input_dev);
916 ret = 0;
917 }
918 }
919
920 return ret;
921}
922#endif
923
924
925static const struct sd_desc sd_desc = {
926 .name = KBUILD_MODNAME,
927 .config = sd_config,
928 .init = sd_init,
929 .init_controls = sd_init_controls,
930 .start = sd_start,
931 .stopN = sd_stopN,
932 .stop0 = sd_stop0,
933 .pkt_scan = sd_pkt_scan,
934 .dq_callback = do_autogain,
935#ifdef CONFIG_VIDEO_ADV_DEBUG
936 .set_register = sd_dbg_s_register,
937 .get_chip_ident = sd_chip_ident,
938#endif
939#if IS_ENABLED(CONFIG_INPUT)
940 .int_pkt_scan = sd_int_pkt_scan,
941#endif
942};
943
944
945static const struct usb_device_id device_table[] = {
946 {USB_DEVICE(0x06f8, 0x3009)},
947 {USB_DEVICE(0x06f8, 0x301b)},
948 {USB_DEVICE(0x093a, 0x2620)},
949 {USB_DEVICE(0x093a, 0x2621)},
950 {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
951 {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
952 {USB_DEVICE(0x093a, 0x2625)},
953 {USB_DEVICE(0x093a, 0x2626)},
954 {USB_DEVICE(0x093a, 0x2627), .driver_info = FL_VFLIP},
955 {USB_DEVICE(0x093a, 0x2628)},
956 {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
957 {USB_DEVICE(0x093a, 0x262a)},
958 {USB_DEVICE(0x093a, 0x262c)},
959 {USB_DEVICE(0x145f, 0x013c)},
960 {USB_DEVICE(0x1ae7, 0x2001)},
961 {}
962};
963MODULE_DEVICE_TABLE(usb, device_table);
964
965
966static int sd_probe(struct usb_interface *intf,
967 const struct usb_device_id *id)
968{
969 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
970 THIS_MODULE);
971}
972
973static struct usb_driver sd_driver = {
974 .name = KBUILD_MODNAME,
975 .id_table = device_table,
976 .probe = sd_probe,
977 .disconnect = gspca_disconnect,
978#ifdef CONFIG_PM
979 .suspend = gspca_suspend,
980 .resume = gspca_resume,
981 .reset_resume = gspca_resume,
982#endif
983};
984
985module_usb_driver(sd_driver);
986