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 if (len > USB_BUF_SZ) {
348 PERR("Incorrect variable sequence");
349 return;
350 }
351 while (len > 0) {
352 if (len < 8) {
353 reg_w_buf(gspca_dev,
354 index, seq, len);
355 seq += len;
356 break;
357 }
358 reg_w_buf(gspca_dev, index, seq, 8);
359 seq += 8;
360 index += 8;
361 len -= 8;
362 }
363 }
364 }
365
366}
367
368
369static int sd_config(struct gspca_dev *gspca_dev,
370 const struct usb_device_id *id)
371{
372 struct sd *sd = (struct sd *) gspca_dev;
373 struct cam *cam;
374
375 cam = &gspca_dev->cam;
376
377 cam->cam_mode = vga_mode;
378 cam->nmodes = ARRAY_SIZE(vga_mode);
379
380 sd->flags = id->driver_info;
381 return 0;
382}
383
384static void setbrightcont(struct gspca_dev *gspca_dev)
385{
386 struct sd *sd = (struct sd *) gspca_dev;
387 int i, v;
388 static const u8 max[10] =
389 {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb,
390 0xd4, 0xec};
391 static const u8 delta[10] =
392 {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17,
393 0x11, 0x0b};
394
395 reg_w(gspca_dev, 0xff, 0x00);
396 for (i = 0; i < 10; i++) {
397 v = max[i];
398 v += (sd->brightness->val - sd->brightness->maximum)
399 * 150 / sd->brightness->maximum;
400 v -= delta[i] * sd->contrast->val / sd->contrast->maximum;
401 if (v < 0)
402 v = 0;
403 else if (v > 0xff)
404 v = 0xff;
405 reg_w(gspca_dev, 0xa2 + i, v);
406 }
407 reg_w(gspca_dev, 0xdc, 0x01);
408}
409
410static void setcolors(struct gspca_dev *gspca_dev)
411{
412 struct sd *sd = (struct sd *) gspca_dev;
413 int i, v;
414 static const int a[9] =
415 {217, -212, 0, -101, 170, -67, -38, -315, 355};
416 static const int b[9] =
417 {19, 106, 0, 19, 106, 1, 19, 106, 1};
418
419 reg_w(gspca_dev, 0xff, 0x03);
420 reg_w(gspca_dev, 0x11, 0x01);
421 reg_w(gspca_dev, 0xff, 0x00);
422 for (i = 0; i < 9; i++) {
423 v = a[i] * sd->saturation->val / sd->saturation->maximum;
424 v += b[i];
425 reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07);
426 reg_w(gspca_dev, 0x0f + 2 * i + 1, v);
427 }
428 reg_w(gspca_dev, 0xdc, 0x01);
429}
430
431static void setwhitebalance(struct gspca_dev *gspca_dev)
432{
433 struct sd *sd = (struct sd *) gspca_dev;
434
435 reg_w(gspca_dev, 0xff, 0x00);
436 reg_w(gspca_dev, 0xc6, sd->white_balance->val);
437
438 reg_w(gspca_dev, 0xdc, 0x01);
439}
440
441static u8 rgbbalance_ctrl_to_reg_value(s32 rgb_ctrl_val)
442{
443 const unsigned int k = 1000;
444 unsigned int norm;
445
446
447 norm = k * (rgb_ctrl_val - PAC7302_RGB_BALANCE_MIN)
448 / (PAC7302_RGB_BALANCE_MAX - PAC7302_RGB_BALANCE_MIN);
449
450 return 64 * norm * norm / (k*k) + 32 * norm / k + 32;
451
452
453
454
455
456
457}
458
459static void setredbalance(struct gspca_dev *gspca_dev)
460{
461 struct sd *sd = (struct sd *) gspca_dev;
462
463 reg_w(gspca_dev, 0xff, 0x00);
464 reg_w(gspca_dev, 0x01,
465 rgbbalance_ctrl_to_reg_value(sd->red_balance->val));
466
467 reg_w(gspca_dev, 0xdc, 0x01);
468}
469
470static void setbluebalance(struct gspca_dev *gspca_dev)
471{
472 struct sd *sd = (struct sd *) gspca_dev;
473
474 reg_w(gspca_dev, 0xff, 0x00);
475 reg_w(gspca_dev, 0x03,
476 rgbbalance_ctrl_to_reg_value(sd->blue_balance->val));
477
478 reg_w(gspca_dev, 0xdc, 0x01);
479}
480
481static void setgain(struct gspca_dev *gspca_dev)
482{
483 u8 reg10, reg12;
484
485 if (gspca_dev->gain->val < 32) {
486 reg10 = gspca_dev->gain->val;
487 reg12 = 0;
488 } else {
489 reg10 = 31;
490 reg12 = gspca_dev->gain->val - 31;
491 }
492
493 reg_w(gspca_dev, 0xff, 0x03);
494 reg_w(gspca_dev, 0x10, reg10);
495 reg_w(gspca_dev, 0x12, reg12);
496
497
498 reg_w(gspca_dev, 0x11, 0x01);
499}
500
501static void setexposure(struct gspca_dev *gspca_dev)
502{
503 u8 clockdiv;
504 u16 exposure;
505
506
507
508
509
510
511 clockdiv = (90 * gspca_dev->exposure->val + 1999) / 2000;
512
513
514
515
516
517
518
519 if (clockdiv < 6)
520 clockdiv = 6;
521 else if (clockdiv > 63)
522 clockdiv = 63;
523
524
525
526
527
528
529 if (clockdiv < 6 || clockdiv > 12)
530 clockdiv = ((clockdiv + 2) / 3) * 3;
531
532
533
534
535
536 exposure = (gspca_dev->exposure->val * 45 * 448) / (1000 * clockdiv);
537
538 exposure = 448 - exposure;
539
540 reg_w(gspca_dev, 0xff, 0x03);
541 reg_w(gspca_dev, 0x02, clockdiv);
542 reg_w(gspca_dev, 0x0e, exposure & 0xff);
543 reg_w(gspca_dev, 0x0f, exposure >> 8);
544
545
546 reg_w(gspca_dev, 0x11, 0x01);
547}
548
549static void sethvflip(struct gspca_dev *gspca_dev)
550{
551 struct sd *sd = (struct sd *) gspca_dev;
552 u8 data, hflip, vflip;
553
554 hflip = sd->hflip->val;
555 if (sd->flags & FL_HFLIP)
556 hflip = !hflip;
557 vflip = sd->vflip->val;
558 if (sd->flags & FL_VFLIP)
559 vflip = !vflip;
560
561 reg_w(gspca_dev, 0xff, 0x03);
562 data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00);
563 reg_w(gspca_dev, 0x21, data);
564
565
566 reg_w(gspca_dev, 0x11, 0x01);
567}
568
569static void setsharpness(struct gspca_dev *gspca_dev)
570{
571 struct sd *sd = (struct sd *) gspca_dev;
572
573 reg_w(gspca_dev, 0xff, 0x00);
574 reg_w(gspca_dev, 0xb6, sd->sharpness->val);
575
576 reg_w(gspca_dev, 0xdc, 0x01);
577}
578
579
580static int sd_init(struct gspca_dev *gspca_dev)
581{
582 reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2);
583 return gspca_dev->usb_err;
584}
585
586static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
587{
588 struct gspca_dev *gspca_dev =
589 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
590 struct sd *sd = (struct sd *)gspca_dev;
591
592 gspca_dev->usb_err = 0;
593
594 if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
595
596
597
598
599 gspca_dev->exposure->val = PAC7302_EXPOSURE_DEFAULT;
600 gspca_dev->gain->val = PAC7302_GAIN_DEFAULT;
601 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
602 }
603
604 if (!gspca_dev->streaming)
605 return 0;
606
607 switch (ctrl->id) {
608 case V4L2_CID_BRIGHTNESS:
609 setbrightcont(gspca_dev);
610 break;
611 case V4L2_CID_SATURATION:
612 setcolors(gspca_dev);
613 break;
614 case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
615 setwhitebalance(gspca_dev);
616 break;
617 case V4L2_CID_RED_BALANCE:
618 setredbalance(gspca_dev);
619 break;
620 case V4L2_CID_BLUE_BALANCE:
621 setbluebalance(gspca_dev);
622 break;
623 case V4L2_CID_AUTOGAIN:
624 if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
625 setexposure(gspca_dev);
626 if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
627 setgain(gspca_dev);
628 break;
629 case V4L2_CID_HFLIP:
630 sethvflip(gspca_dev);
631 break;
632 case V4L2_CID_SHARPNESS:
633 setsharpness(gspca_dev);
634 break;
635 default:
636 return -EINVAL;
637 }
638 return gspca_dev->usb_err;
639}
640
641static const struct v4l2_ctrl_ops sd_ctrl_ops = {
642 .s_ctrl = sd_s_ctrl,
643};
644
645
646static int sd_init_controls(struct gspca_dev *gspca_dev)
647{
648 struct sd *sd = (struct sd *) gspca_dev;
649 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
650
651 gspca_dev->vdev.ctrl_handler = hdl;
652 v4l2_ctrl_handler_init(hdl, 12);
653
654 sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
655 V4L2_CID_BRIGHTNESS, 0, 32, 1, 16);
656 sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
657 V4L2_CID_CONTRAST, 0, 255, 1, 127);
658
659 sd->saturation = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
660 V4L2_CID_SATURATION, 0, 255, 1, 127);
661 sd->white_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
662 V4L2_CID_WHITE_BALANCE_TEMPERATURE,
663 0, 255, 1, 55);
664 sd->red_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
665 V4L2_CID_RED_BALANCE,
666 PAC7302_RGB_BALANCE_MIN,
667 PAC7302_RGB_BALANCE_MAX,
668 1, PAC7302_RGB_BALANCE_DEFAULT);
669 sd->blue_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
670 V4L2_CID_BLUE_BALANCE,
671 PAC7302_RGB_BALANCE_MIN,
672 PAC7302_RGB_BALANCE_MAX,
673 1, PAC7302_RGB_BALANCE_DEFAULT);
674
675 gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
676 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
677 gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
678 V4L2_CID_EXPOSURE, 0, 1023, 1,
679 PAC7302_EXPOSURE_DEFAULT);
680 gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
681 V4L2_CID_GAIN, 0, 62, 1,
682 PAC7302_GAIN_DEFAULT);
683
684 sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
685 V4L2_CID_HFLIP, 0, 1, 1, 0);
686 sd->vflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
687 V4L2_CID_VFLIP, 0, 1, 1, 0);
688
689 sd->sharpness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
690 V4L2_CID_SHARPNESS, 0, 15, 1, 8);
691
692 if (hdl->error) {
693 pr_err("Could not initialize controls\n");
694 return hdl->error;
695 }
696
697 v4l2_ctrl_cluster(2, &sd->brightness);
698 v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false);
699 v4l2_ctrl_cluster(2, &sd->hflip);
700 return 0;
701}
702
703
704static int sd_start(struct gspca_dev *gspca_dev)
705{
706 struct sd *sd = (struct sd *) gspca_dev;
707
708 reg_w_var(gspca_dev, start_7302,
709 page3_7302, sizeof(page3_7302));
710
711 sd->sof_read = 0;
712 sd->autogain_ignore_frames = 0;
713 atomic_set(&sd->avg_lum, 270 + sd->brightness->val);
714
715
716 reg_w(gspca_dev, 0xff, 0x01);
717 reg_w(gspca_dev, 0x78, 0x01);
718
719 return gspca_dev->usb_err;
720}
721
722static void sd_stopN(struct gspca_dev *gspca_dev)
723{
724
725
726 reg_w(gspca_dev, 0xff, 0x01);
727 reg_w(gspca_dev, 0x78, 0x00);
728}
729
730
731static void sd_stop0(struct gspca_dev *gspca_dev)
732{
733 if (!gspca_dev->present)
734 return;
735 reg_w(gspca_dev, 0xff, 0x01);
736 reg_w(gspca_dev, 0x78, 0x40);
737}
738
739static void do_autogain(struct gspca_dev *gspca_dev)
740{
741 struct sd *sd = (struct sd *) gspca_dev;
742 int avg_lum = atomic_read(&sd->avg_lum);
743 int desired_lum;
744 const int deadzone = 30;
745
746 if (sd->autogain_ignore_frames < 0)
747 return;
748
749 if (sd->autogain_ignore_frames > 0) {
750 sd->autogain_ignore_frames--;
751 } else {
752 desired_lum = 270 + sd->brightness->val;
753
754 if (gspca_expo_autogain(gspca_dev, avg_lum, desired_lum,
755 deadzone, PAC7302_GAIN_KNEE,
756 PAC7302_EXPOSURE_KNEE))
757 sd->autogain_ignore_frames =
758 PAC_AUTOGAIN_IGNORE_FRAMES;
759 }
760}
761
762
763static const u8 jpeg_header[] = {
764 0xff, 0xd8,
765
766 0xff, 0xc0,
767 0x00, 0x11,
768 0x08,
769 0x02, 0x80,
770 0x01, 0xe0,
771 0x03,
772 0x01, 0x21, 0x00,
773 0x02, 0x11, 0x01,
774 0x03, 0x11, 0x01,
775
776 0xff, 0xda,
777 0x00, 0x0c,
778 0x03,
779 0x01, 0x00,
780 0x02, 0x11,
781 0x03, 0x11,
782 0x00, 0x3f,
783 0x00
784};
785
786
787static void sd_pkt_scan(struct gspca_dev *gspca_dev,
788 u8 *data,
789 int len)
790{
791 struct sd *sd = (struct sd *) gspca_dev;
792 u8 *image;
793 u8 *sof;
794
795 sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len);
796 if (sof) {
797 int n, lum_offset, footer_length;
798
799
800
801
802
803
804
805 lum_offset = 61 + sizeof pac_sof_marker;
806 footer_length = 74;
807
808
809 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
810 if (n < 0) {
811 gspca_dev->image_len += n;
812 n = 0;
813 } else {
814 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
815 }
816
817 image = gspca_dev->image;
818 if (image != NULL
819 && image[gspca_dev->image_len - 2] == 0xff
820 && image[gspca_dev->image_len - 1] == 0xd9)
821 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
822
823 n = sof - data;
824 len -= n;
825 data = sof;
826
827
828 if (gspca_dev->last_packet_type == LAST_PACKET &&
829 n >= lum_offset)
830 atomic_set(&sd->avg_lum, data[-lum_offset] +
831 data[-lum_offset + 1]);
832
833
834
835 gspca_frame_add(gspca_dev, FIRST_PACKET,
836 jpeg_header, sizeof jpeg_header);
837 }
838 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
839}
840
841#ifdef CONFIG_VIDEO_ADV_DEBUG
842static int sd_dbg_s_register(struct gspca_dev *gspca_dev,
843 const struct v4l2_dbg_register *reg)
844{
845 u8 index;
846 u8 value;
847
848
849
850
851
852 if (reg->match.type == V4L2_CHIP_MATCH_HOST &&
853 reg->match.addr == 0 &&
854 (reg->reg < 0x000000ff) &&
855 (reg->val <= 0x000000ff)
856 ) {
857
858
859 index = reg->reg;
860 value = reg->val;
861
862
863
864
865
866
867 reg_w(gspca_dev, 0xff, 0x00);
868 reg_w(gspca_dev, index, value);
869
870 reg_w(gspca_dev, 0xdc, 0x01);
871 }
872 return gspca_dev->usb_err;
873}
874
875static int sd_chip_ident(struct gspca_dev *gspca_dev,
876 struct v4l2_dbg_chip_ident *chip)
877{
878 int ret = -EINVAL;
879
880 if (chip->match.type == V4L2_CHIP_MATCH_HOST &&
881 chip->match.addr == 0) {
882 chip->revision = 0;
883 chip->ident = V4L2_IDENT_UNKNOWN;
884 ret = 0;
885 }
886 return ret;
887}
888#endif
889
890#if IS_ENABLED(CONFIG_INPUT)
891static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
892 u8 *data,
893 int len)
894{
895 int ret = -EINVAL;
896 u8 data0, data1;
897
898 if (len == 2) {
899 data0 = data[0];
900 data1 = data[1];
901 if ((data0 == 0x00 && data1 == 0x11) ||
902 (data0 == 0x22 && data1 == 0x33) ||
903 (data0 == 0x44 && data1 == 0x55) ||
904 (data0 == 0x66 && data1 == 0x77) ||
905 (data0 == 0x88 && data1 == 0x99) ||
906 (data0 == 0xaa && data1 == 0xbb) ||
907 (data0 == 0xcc && data1 == 0xdd) ||
908 (data0 == 0xee && data1 == 0xff)) {
909 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
910 input_sync(gspca_dev->input_dev);
911 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
912 input_sync(gspca_dev->input_dev);
913 ret = 0;
914 }
915 }
916
917 return ret;
918}
919#endif
920
921
922static const struct sd_desc sd_desc = {
923 .name = KBUILD_MODNAME,
924 .config = sd_config,
925 .init = sd_init,
926 .init_controls = sd_init_controls,
927 .start = sd_start,
928 .stopN = sd_stopN,
929 .stop0 = sd_stop0,
930 .pkt_scan = sd_pkt_scan,
931 .dq_callback = do_autogain,
932#ifdef CONFIG_VIDEO_ADV_DEBUG
933 .set_register = sd_dbg_s_register,
934 .get_chip_ident = sd_chip_ident,
935#endif
936#if IS_ENABLED(CONFIG_INPUT)
937 .int_pkt_scan = sd_int_pkt_scan,
938#endif
939};
940
941
942static const struct usb_device_id device_table[] = {
943 {USB_DEVICE(0x06f8, 0x3009)},
944 {USB_DEVICE(0x06f8, 0x301b)},
945 {USB_DEVICE(0x093a, 0x2620)},
946 {USB_DEVICE(0x093a, 0x2621)},
947 {USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
948 {USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
949 {USB_DEVICE(0x093a, 0x2625)},
950 {USB_DEVICE(0x093a, 0x2626)},
951 {USB_DEVICE(0x093a, 0x2627), .driver_info = FL_VFLIP},
952 {USB_DEVICE(0x093a, 0x2628)},
953 {USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
954 {USB_DEVICE(0x093a, 0x262a)},
955 {USB_DEVICE(0x093a, 0x262c)},
956 {USB_DEVICE(0x145f, 0x013c)},
957 {USB_DEVICE(0x1ae7, 0x2001)},
958 {}
959};
960MODULE_DEVICE_TABLE(usb, device_table);
961
962
963static int sd_probe(struct usb_interface *intf,
964 const struct usb_device_id *id)
965{
966 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
967 THIS_MODULE);
968}
969
970static struct usb_driver sd_driver = {
971 .name = KBUILD_MODNAME,
972 .id_table = device_table,
973 .probe = sd_probe,
974 .disconnect = gspca_disconnect,
975#ifdef CONFIG_PM
976 .suspend = gspca_suspend,
977 .resume = gspca_resume,
978 .reset_resume = gspca_resume,
979#endif
980};
981
982module_usb_driver(sd_driver);
983