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