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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
57
58#define MODULE_NAME "pac7311"
59
60#include <linux/input.h>
61#include "gspca.h"
62
63#include "pac_common.h"
64
65#define PAC7311_GAIN_DEFAULT 122
66#define PAC7311_EXPOSURE_DEFAULT 3
67
68MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
69MODULE_DESCRIPTION("Pixart PAC7311");
70MODULE_LICENSE("GPL");
71
72struct sd {
73 struct gspca_dev gspca_dev;
74
75 struct v4l2_ctrl *contrast;
76 struct v4l2_ctrl *hflip;
77
78 u8 sof_read;
79 u8 autogain_ignore_frames;
80
81 atomic_t avg_lum;
82};
83
84static const struct v4l2_pix_format vga_mode[] = {
85 {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
86 .bytesperline = 160,
87 .sizeimage = 160 * 120 * 3 / 8 + 590,
88 .colorspace = V4L2_COLORSPACE_JPEG,
89 .priv = 2},
90 {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
91 .bytesperline = 320,
92 .sizeimage = 320 * 240 * 3 / 8 + 590,
93 .colorspace = V4L2_COLORSPACE_JPEG,
94 .priv = 1},
95 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
96 .bytesperline = 640,
97 .sizeimage = 640 * 480 * 3 / 8 + 590,
98 .colorspace = V4L2_COLORSPACE_JPEG,
99 .priv = 0},
100};
101
102#define LOAD_PAGE4 254
103#define END_OF_SEQUENCE 0
104
105static const __u8 init_7311[] = {
106 0xff, 0x01,
107 0x78, 0x40,
108 0x78, 0x40,
109 0x78, 0x44,
110 0xff, 0x04,
111 0x27, 0x80,
112 0x28, 0xca,
113 0x29, 0x53,
114 0x2a, 0x0e,
115 0xff, 0x01,
116 0x3e, 0x20,
117};
118
119static const __u8 start_7311[] = {
120
121 0xff, 1, 0x01,
122 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
123 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
124 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
125 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127 0x00, 0x00, 0x00,
128 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
129 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
130 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
131 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
132 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
133 0xd0, 0xff,
134 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
135 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
136 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
137 0x18, 0x20,
138 0x96, 3, 0x01, 0x08, 0x04,
139 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
140 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
141 0x3f, 0x00, 0x0a, 0x01, 0x00,
142 0xff, 1, 0x04,
143 0, LOAD_PAGE4,
144 0x11, 1, 0x01,
145 0, END_OF_SEQUENCE
146};
147
148#define SKIP 0xaa
149
150static const __u8 page4_7311[] = {
151 SKIP, SKIP, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
152 0x09, 0x00, SKIP, SKIP, 0x07, 0x00, 0x00, 0x62,
153 0x08, SKIP, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
154 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, SKIP,
155 SKIP, 0x00, 0x08, SKIP, 0x03, SKIP, 0x00, 0x68,
156 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
157 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
158};
159
160static void reg_w_buf(struct gspca_dev *gspca_dev,
161 __u8 index,
162 const u8 *buffer, int len)
163{
164 int ret;
165
166 if (gspca_dev->usb_err < 0)
167 return;
168 memcpy(gspca_dev->usb_buf, buffer, len);
169 ret = usb_control_msg(gspca_dev->dev,
170 usb_sndctrlpipe(gspca_dev->dev, 0),
171 0,
172 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
173 0,
174 index, gspca_dev->usb_buf, len,
175 500);
176 if (ret < 0) {
177 pr_err("reg_w_buf() failed index 0x%02x, error %d\n",
178 index, ret);
179 gspca_dev->usb_err = ret;
180 }
181}
182
183
184static void reg_w(struct gspca_dev *gspca_dev,
185 __u8 index,
186 __u8 value)
187{
188 int ret;
189
190 if (gspca_dev->usb_err < 0)
191 return;
192 gspca_dev->usb_buf[0] = value;
193 ret = usb_control_msg(gspca_dev->dev,
194 usb_sndctrlpipe(gspca_dev->dev, 0),
195 0,
196 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
197 0, index, gspca_dev->usb_buf, 1,
198 500);
199 if (ret < 0) {
200 pr_err("reg_w() failed index 0x%02x, value 0x%02x, error %d\n",
201 index, value, ret);
202 gspca_dev->usb_err = ret;
203 }
204}
205
206static void reg_w_seq(struct gspca_dev *gspca_dev,
207 const __u8 *seq, int len)
208{
209 while (--len >= 0) {
210 reg_w(gspca_dev, seq[0], seq[1]);
211 seq += 2;
212 }
213}
214
215
216static void reg_w_page(struct gspca_dev *gspca_dev,
217 const __u8 *page, int len)
218{
219 int index;
220 int ret = 0;
221
222 if (gspca_dev->usb_err < 0)
223 return;
224 for (index = 0; index < len; index++) {
225 if (page[index] == SKIP)
226 continue;
227 gspca_dev->usb_buf[0] = page[index];
228 ret = usb_control_msg(gspca_dev->dev,
229 usb_sndctrlpipe(gspca_dev->dev, 0),
230 0,
231 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
232 0, index, gspca_dev->usb_buf, 1,
233 500);
234 if (ret < 0) {
235 pr_err("reg_w_page() failed index 0x%02x, value 0x%02x, error %d\n",
236 index, page[index], ret);
237 gspca_dev->usb_err = ret;
238 break;
239 }
240 }
241}
242
243
244static void reg_w_var(struct gspca_dev *gspca_dev,
245 const __u8 *seq,
246 const __u8 *page4, unsigned int page4_len)
247{
248 int index, len;
249
250 for (;;) {
251 index = *seq++;
252 len = *seq++;
253 switch (len) {
254 case END_OF_SEQUENCE:
255 return;
256 case LOAD_PAGE4:
257 reg_w_page(gspca_dev, page4, page4_len);
258 break;
259 default:
260 if (len > USB_BUF_SZ) {
261 gspca_err(gspca_dev, "Incorrect variable sequence\n");
262 return;
263 }
264 while (len > 0) {
265 if (len < 8) {
266 reg_w_buf(gspca_dev,
267 index, seq, len);
268 seq += len;
269 break;
270 }
271 reg_w_buf(gspca_dev, index, seq, 8);
272 seq += 8;
273 index += 8;
274 len -= 8;
275 }
276 }
277 }
278
279}
280
281
282static int sd_config(struct gspca_dev *gspca_dev,
283 const struct usb_device_id *id)
284{
285 struct cam *cam = &gspca_dev->cam;
286
287 cam->cam_mode = vga_mode;
288 cam->nmodes = ARRAY_SIZE(vga_mode);
289 cam->input_flags = V4L2_IN_ST_VFLIP;
290
291 return 0;
292}
293
294static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
295{
296 reg_w(gspca_dev, 0xff, 0x04);
297 reg_w(gspca_dev, 0x10, val);
298
299 reg_w(gspca_dev, 0x11, 0x01);
300}
301
302static void setgain(struct gspca_dev *gspca_dev, s32 val)
303{
304 reg_w(gspca_dev, 0xff, 0x04);
305 reg_w(gspca_dev, 0x0e, 0x00);
306 reg_w(gspca_dev, 0x0f, gspca_dev->gain->maximum - val + 1);
307
308
309 reg_w(gspca_dev, 0x11, 0x01);
310}
311
312static void setexposure(struct gspca_dev *gspca_dev, s32 val)
313{
314 reg_w(gspca_dev, 0xff, 0x04);
315 reg_w(gspca_dev, 0x02, val);
316
317
318 reg_w(gspca_dev, 0x11, 0x01);
319
320
321
322
323
324 reg_w(gspca_dev, 0xff, 0x01);
325 if (gspca_dev->pixfmt.width != 640 && val <= 3)
326 reg_w(gspca_dev, 0x08, 0x09);
327 else
328 reg_w(gspca_dev, 0x08, 0x08);
329
330
331
332
333
334
335
336 if (gspca_dev->pixfmt.width == 640 && val == 2)
337 reg_w(gspca_dev, 0x80, 0x01);
338 else
339 reg_w(gspca_dev, 0x80, 0x1c);
340
341
342 reg_w(gspca_dev, 0x11, 0x01);
343}
344
345static void sethvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip)
346{
347 __u8 data;
348
349 reg_w(gspca_dev, 0xff, 0x04);
350 data = (hflip ? 0x04 : 0x00) |
351 (vflip ? 0x08 : 0x00);
352 reg_w(gspca_dev, 0x21, data);
353
354
355 reg_w(gspca_dev, 0x11, 0x01);
356}
357
358
359static int sd_init(struct gspca_dev *gspca_dev)
360{
361 reg_w_seq(gspca_dev, init_7311, sizeof(init_7311)/2);
362 return gspca_dev->usb_err;
363}
364
365static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
366{
367 struct gspca_dev *gspca_dev =
368 container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
369 struct sd *sd = (struct sd *)gspca_dev;
370
371 gspca_dev->usb_err = 0;
372
373 if (ctrl->id == V4L2_CID_AUTOGAIN && ctrl->is_new && ctrl->val) {
374
375
376
377
378 gspca_dev->exposure->val = PAC7311_EXPOSURE_DEFAULT;
379 gspca_dev->gain->val = PAC7311_GAIN_DEFAULT;
380 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
381 }
382
383 if (!gspca_dev->streaming)
384 return 0;
385
386 switch (ctrl->id) {
387 case V4L2_CID_CONTRAST:
388 setcontrast(gspca_dev, ctrl->val);
389 break;
390 case V4L2_CID_AUTOGAIN:
391 if (gspca_dev->exposure->is_new || (ctrl->is_new && ctrl->val))
392 setexposure(gspca_dev, gspca_dev->exposure->val);
393 if (gspca_dev->gain->is_new || (ctrl->is_new && ctrl->val))
394 setgain(gspca_dev, gspca_dev->gain->val);
395 break;
396 case V4L2_CID_HFLIP:
397 sethvflip(gspca_dev, sd->hflip->val, 1);
398 break;
399 default:
400 return -EINVAL;
401 }
402 return gspca_dev->usb_err;
403}
404
405static const struct v4l2_ctrl_ops sd_ctrl_ops = {
406 .s_ctrl = sd_s_ctrl,
407};
408
409
410static int sd_init_controls(struct gspca_dev *gspca_dev)
411{
412 struct sd *sd = (struct sd *) gspca_dev;
413 struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
414
415 gspca_dev->vdev.ctrl_handler = hdl;
416 v4l2_ctrl_handler_init(hdl, 5);
417
418 sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
419 V4L2_CID_CONTRAST, 0, 15, 1, 7);
420 gspca_dev->autogain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
421 V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
422 gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
423 V4L2_CID_EXPOSURE, 2, 63, 1,
424 PAC7311_EXPOSURE_DEFAULT);
425 gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
426 V4L2_CID_GAIN, 0, 244, 1,
427 PAC7311_GAIN_DEFAULT);
428 sd->hflip = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
429 V4L2_CID_HFLIP, 0, 1, 1, 0);
430
431 if (hdl->error) {
432 pr_err("Could not initialize controls\n");
433 return hdl->error;
434 }
435
436 v4l2_ctrl_auto_cluster(3, &gspca_dev->autogain, 0, false);
437 return 0;
438}
439
440
441static int sd_start(struct gspca_dev *gspca_dev)
442{
443 struct sd *sd = (struct sd *) gspca_dev;
444
445 sd->sof_read = 0;
446
447 reg_w_var(gspca_dev, start_7311,
448 page4_7311, sizeof(page4_7311));
449 setcontrast(gspca_dev, v4l2_ctrl_g_ctrl(sd->contrast));
450 setgain(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->gain));
451 setexposure(gspca_dev, v4l2_ctrl_g_ctrl(gspca_dev->exposure));
452 sethvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip), 1);
453
454
455 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
456 case 2:
457 reg_w(gspca_dev, 0xff, 0x01);
458 reg_w(gspca_dev, 0x17, 0x20);
459 reg_w(gspca_dev, 0x87, 0x10);
460 break;
461 case 1:
462 reg_w(gspca_dev, 0xff, 0x01);
463 reg_w(gspca_dev, 0x17, 0x30);
464 reg_w(gspca_dev, 0x87, 0x11);
465 break;
466 case 0:
467 reg_w(gspca_dev, 0xff, 0x01);
468 reg_w(gspca_dev, 0x17, 0x00);
469 reg_w(gspca_dev, 0x87, 0x12);
470 break;
471 }
472
473 sd->sof_read = 0;
474 sd->autogain_ignore_frames = 0;
475 atomic_set(&sd->avg_lum, -1);
476
477
478 reg_w(gspca_dev, 0xff, 0x01);
479 reg_w(gspca_dev, 0x78, 0x05);
480
481 return gspca_dev->usb_err;
482}
483
484static void sd_stopN(struct gspca_dev *gspca_dev)
485{
486 reg_w(gspca_dev, 0xff, 0x04);
487 reg_w(gspca_dev, 0x27, 0x80);
488 reg_w(gspca_dev, 0x28, 0xca);
489 reg_w(gspca_dev, 0x29, 0x53);
490 reg_w(gspca_dev, 0x2a, 0x0e);
491 reg_w(gspca_dev, 0xff, 0x01);
492 reg_w(gspca_dev, 0x3e, 0x20);
493 reg_w(gspca_dev, 0x78, 0x44);
494 reg_w(gspca_dev, 0x78, 0x44);
495 reg_w(gspca_dev, 0x78, 0x44);
496}
497
498static void do_autogain(struct gspca_dev *gspca_dev)
499{
500 struct sd *sd = (struct sd *) gspca_dev;
501 int avg_lum = atomic_read(&sd->avg_lum);
502 int desired_lum, deadzone;
503
504 if (avg_lum == -1)
505 return;
506
507 desired_lum = 170;
508 deadzone = 20;
509
510 if (sd->autogain_ignore_frames > 0)
511 sd->autogain_ignore_frames--;
512 else if (gspca_coarse_grained_expo_autogain(gspca_dev, avg_lum,
513 desired_lum, deadzone))
514 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
515}
516
517
518static const unsigned char pac_jpeg_header1[] = {
519 0xff, 0xd8,
520
521 0xff, 0xc0,
522 0x00, 0x11,
523 0x08
524
525
526};
527
528
529static const unsigned char pac_jpeg_header2[] = {
530 0x03,
531 0x01, 0x21, 0x00,
532 0x02, 0x11, 0x01,
533 0x03, 0x11, 0x01,
534
535 0xff, 0xda,
536 0x00, 0x0c,
537 0x03,
538 0x01, 0x00,
539 0x02, 0x11,
540 0x03, 0x11,
541 0x00, 0x3f,
542 0x00
543};
544
545static void pac_start_frame(struct gspca_dev *gspca_dev,
546 __u16 lines, __u16 samples_per_line)
547{
548 unsigned char tmpbuf[4];
549
550 gspca_frame_add(gspca_dev, FIRST_PACKET,
551 pac_jpeg_header1, sizeof(pac_jpeg_header1));
552
553 tmpbuf[0] = lines >> 8;
554 tmpbuf[1] = lines & 0xff;
555 tmpbuf[2] = samples_per_line >> 8;
556 tmpbuf[3] = samples_per_line & 0xff;
557
558 gspca_frame_add(gspca_dev, INTER_PACKET,
559 tmpbuf, sizeof(tmpbuf));
560 gspca_frame_add(gspca_dev, INTER_PACKET,
561 pac_jpeg_header2, sizeof(pac_jpeg_header2));
562}
563
564
565static void sd_pkt_scan(struct gspca_dev *gspca_dev,
566 u8 *data,
567 int len)
568{
569 struct sd *sd = (struct sd *) gspca_dev;
570 u8 *image;
571 unsigned char *sof;
572
573 sof = pac_find_sof(gspca_dev, &sd->sof_read, data, len);
574 if (sof) {
575 int n, lum_offset, footer_length;
576
577
578
579
580
581
582
583 lum_offset = 24 + sizeof pac_sof_marker;
584 footer_length = 26;
585
586
587 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
588 if (n < 0) {
589 gspca_dev->image_len += n;
590 n = 0;
591 } else {
592 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
593 }
594 image = gspca_dev->image;
595 if (image != NULL
596 && image[gspca_dev->image_len - 2] == 0xff
597 && image[gspca_dev->image_len - 1] == 0xd9)
598 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
599
600 n = sof - data;
601 len -= n;
602 data = sof;
603
604
605 if (gspca_dev->last_packet_type == LAST_PACKET &&
606 n >= lum_offset)
607 atomic_set(&sd->avg_lum, data[-lum_offset] +
608 data[-lum_offset + 1]);
609 else
610 atomic_set(&sd->avg_lum, -1);
611
612
613 pac_start_frame(gspca_dev,
614 gspca_dev->pixfmt.height, gspca_dev->pixfmt.width);
615 }
616 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
617}
618
619#if IS_ENABLED(CONFIG_INPUT)
620static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
621 u8 *data,
622 int len)
623{
624 int ret = -EINVAL;
625 u8 data0, data1;
626
627 if (len == 2) {
628 data0 = data[0];
629 data1 = data[1];
630 if ((data0 == 0x00 && data1 == 0x11) ||
631 (data0 == 0x22 && data1 == 0x33) ||
632 (data0 == 0x44 && data1 == 0x55) ||
633 (data0 == 0x66 && data1 == 0x77) ||
634 (data0 == 0x88 && data1 == 0x99) ||
635 (data0 == 0xaa && data1 == 0xbb) ||
636 (data0 == 0xcc && data1 == 0xdd) ||
637 (data0 == 0xee && data1 == 0xff)) {
638 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
639 input_sync(gspca_dev->input_dev);
640 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
641 input_sync(gspca_dev->input_dev);
642 ret = 0;
643 }
644 }
645
646 return ret;
647}
648#endif
649
650static const struct sd_desc sd_desc = {
651 .name = MODULE_NAME,
652 .config = sd_config,
653 .init = sd_init,
654 .init_controls = sd_init_controls,
655 .start = sd_start,
656 .stopN = sd_stopN,
657 .pkt_scan = sd_pkt_scan,
658 .dq_callback = do_autogain,
659#if IS_ENABLED(CONFIG_INPUT)
660 .int_pkt_scan = sd_int_pkt_scan,
661#endif
662};
663
664
665static const struct usb_device_id device_table[] = {
666 {USB_DEVICE(0x093a, 0x2600)},
667 {USB_DEVICE(0x093a, 0x2601)},
668 {USB_DEVICE(0x093a, 0x2603)},
669 {USB_DEVICE(0x093a, 0x2608)},
670 {USB_DEVICE(0x093a, 0x260e)},
671 {USB_DEVICE(0x093a, 0x260f)},
672 {}
673};
674MODULE_DEVICE_TABLE(usb, device_table);
675
676
677static int sd_probe(struct usb_interface *intf,
678 const struct usb_device_id *id)
679{
680 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
681 THIS_MODULE);
682}
683
684static struct usb_driver sd_driver = {
685 .name = MODULE_NAME,
686 .id_table = device_table,
687 .probe = sd_probe,
688 .disconnect = gspca_disconnect,
689#ifdef CONFIG_PM
690 .suspend = gspca_suspend,
691 .resume = gspca_resume,
692 .reset_resume = gspca_resume,
693#endif
694};
695
696module_usb_driver(sd_driver);
697