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