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