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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
53
54#define MODULE_NAME "pac7311"
55
56#include <linux/input.h>
57#include "gspca.h"
58
59MODULE_AUTHOR("Thomas Kaiser thomas@kaiser-linux.li");
60MODULE_DESCRIPTION("Pixart PAC7311");
61MODULE_LICENSE("GPL");
62
63
64struct sd {
65 struct gspca_dev gspca_dev;
66
67 unsigned char contrast;
68 unsigned char gain;
69 unsigned char exposure;
70 unsigned char autogain;
71 __u8 hflip;
72 __u8 vflip;
73
74 u8 sof_read;
75 u8 autogain_ignore_frames;
76
77 atomic_t avg_lum;
78};
79
80
81static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
82static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
83static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
84static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
85static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val);
86static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val);
87static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val);
88static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
89static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
90static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
91static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
92static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
93
94static const struct ctrl sd_ctrls[] = {
95
96 {
97 {
98 .id = V4L2_CID_CONTRAST,
99 .type = V4L2_CTRL_TYPE_INTEGER,
100 .name = "Contrast",
101 .minimum = 0,
102#define CONTRAST_MAX 255
103 .maximum = CONTRAST_MAX,
104 .step = 1,
105#define CONTRAST_DEF 127
106 .default_value = CONTRAST_DEF,
107 },
108 .set = sd_setcontrast,
109 .get = sd_getcontrast,
110 },
111
112 {
113 {
114 .id = V4L2_CID_GAIN,
115 .type = V4L2_CTRL_TYPE_INTEGER,
116 .name = "Gain",
117 .minimum = 0,
118#define GAIN_MAX 255
119 .maximum = GAIN_MAX,
120 .step = 1,
121#define GAIN_DEF 127
122#define GAIN_KNEE 255
123 .default_value = GAIN_DEF,
124 },
125 .set = sd_setgain,
126 .get = sd_getgain,
127 },
128 {
129 {
130 .id = V4L2_CID_EXPOSURE,
131 .type = V4L2_CTRL_TYPE_INTEGER,
132 .name = "Exposure",
133 .minimum = 0,
134#define EXPOSURE_MAX 255
135 .maximum = EXPOSURE_MAX,
136 .step = 1,
137#define EXPOSURE_DEF 16
138#define EXPOSURE_KNEE 50
139 .default_value = EXPOSURE_DEF,
140 },
141 .set = sd_setexposure,
142 .get = sd_getexposure,
143 },
144 {
145 {
146 .id = V4L2_CID_AUTOGAIN,
147 .type = V4L2_CTRL_TYPE_BOOLEAN,
148 .name = "Auto Gain",
149 .minimum = 0,
150 .maximum = 1,
151 .step = 1,
152#define AUTOGAIN_DEF 1
153 .default_value = AUTOGAIN_DEF,
154 },
155 .set = sd_setautogain,
156 .get = sd_getautogain,
157 },
158 {
159 {
160 .id = V4L2_CID_HFLIP,
161 .type = V4L2_CTRL_TYPE_BOOLEAN,
162 .name = "Mirror",
163 .minimum = 0,
164 .maximum = 1,
165 .step = 1,
166#define HFLIP_DEF 0
167 .default_value = HFLIP_DEF,
168 },
169 .set = sd_sethflip,
170 .get = sd_gethflip,
171 },
172 {
173 {
174 .id = V4L2_CID_VFLIP,
175 .type = V4L2_CTRL_TYPE_BOOLEAN,
176 .name = "Vflip",
177 .minimum = 0,
178 .maximum = 1,
179 .step = 1,
180#define VFLIP_DEF 0
181 .default_value = VFLIP_DEF,
182 },
183 .set = sd_setvflip,
184 .get = sd_getvflip,
185 },
186};
187
188static const struct v4l2_pix_format vga_mode[] = {
189 {160, 120, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
190 .bytesperline = 160,
191 .sizeimage = 160 * 120 * 3 / 8 + 590,
192 .colorspace = V4L2_COLORSPACE_JPEG,
193 .priv = 2},
194 {320, 240, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
195 .bytesperline = 320,
196 .sizeimage = 320 * 240 * 3 / 8 + 590,
197 .colorspace = V4L2_COLORSPACE_JPEG,
198 .priv = 1},
199 {640, 480, V4L2_PIX_FMT_PJPG, V4L2_FIELD_NONE,
200 .bytesperline = 640,
201 .sizeimage = 640 * 480 * 3 / 8 + 590,
202 .colorspace = V4L2_COLORSPACE_JPEG,
203 .priv = 0},
204};
205
206#define LOAD_PAGE4 254
207#define END_OF_SEQUENCE 0
208
209
210static const __u8 init_7311[] = {
211 0x78, 0x40,
212 0x78, 0x40,
213 0x78, 0x44,
214 0xff, 0x04,
215 0x27, 0x80,
216 0x28, 0xca,
217 0x29, 0x53,
218 0x2a, 0x0e,
219 0xff, 0x01,
220 0x3e, 0x20,
221};
222
223static const __u8 start_7311[] = {
224
225 0xff, 1, 0x01,
226 0x02, 43, 0x48, 0x0a, 0x40, 0x08, 0x00, 0x00, 0x08, 0x00,
227 0x06, 0xff, 0x11, 0xff, 0x5a, 0x30, 0x90, 0x4c,
228 0x00, 0x07, 0x00, 0x0a, 0x10, 0x00, 0xa0, 0x10,
229 0x02, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x01, 0x00,
230 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231 0x00, 0x00, 0x00,
232 0x3e, 42, 0x00, 0x00, 0x78, 0x52, 0x4a, 0x52, 0x78, 0x6e,
233 0x48, 0x46, 0x48, 0x6e, 0x5f, 0x49, 0x42, 0x49,
234 0x5f, 0x5f, 0x49, 0x42, 0x49, 0x5f, 0x6e, 0x48,
235 0x46, 0x48, 0x6e, 0x78, 0x52, 0x4a, 0x52, 0x78,
236 0x00, 0x00, 0x09, 0x1b, 0x34, 0x49, 0x5c, 0x9b,
237 0xd0, 0xff,
238 0x78, 6, 0x44, 0x00, 0xf2, 0x01, 0x01, 0x80,
239 0x7f, 18, 0x2a, 0x1c, 0x00, 0xc8, 0x02, 0x58, 0x03, 0x84,
240 0x12, 0x00, 0x1a, 0x04, 0x08, 0x0c, 0x10, 0x14,
241 0x18, 0x20,
242 0x96, 3, 0x01, 0x08, 0x04,
243 0xa0, 4, 0x44, 0x44, 0x44, 0x04,
244 0xf0, 13, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x20, 0x00,
245 0x3f, 0x00, 0x0a, 0x01, 0x00,
246 0xff, 1, 0x04,
247 0, LOAD_PAGE4,
248 0x11, 1, 0x01,
249 0, END_OF_SEQUENCE
250};
251
252#define SKIP 0xaa
253
254static const __u8 page4_7311[] = {
255 SKIP, SKIP, 0x04, 0x54, 0x07, 0x2b, 0x09, 0x0f,
256 0x09, 0x00, SKIP, SKIP, 0x07, 0x00, 0x00, 0x62,
257 0x08, SKIP, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
258 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, SKIP,
259 SKIP, 0x00, 0x08, SKIP, 0x03, SKIP, 0x00, 0x68,
260 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00,
261 0x23, 0x28, 0x04, 0x11, 0x00, 0x00
262};
263
264static void reg_w_buf(struct gspca_dev *gspca_dev,
265 __u8 index,
266 const u8 *buffer, int len)
267{
268 int ret;
269
270 if (gspca_dev->usb_err < 0)
271 return;
272 memcpy(gspca_dev->usb_buf, buffer, len);
273 ret = usb_control_msg(gspca_dev->dev,
274 usb_sndctrlpipe(gspca_dev->dev, 0),
275 0,
276 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
277 0,
278 index, gspca_dev->usb_buf, len,
279 500);
280 if (ret < 0) {
281 pr_err("reg_w_buf() failed index 0x%02x, error %d\n",
282 index, ret);
283 gspca_dev->usb_err = ret;
284 }
285}
286
287
288static void reg_w(struct gspca_dev *gspca_dev,
289 __u8 index,
290 __u8 value)
291{
292 int ret;
293
294 if (gspca_dev->usb_err < 0)
295 return;
296 gspca_dev->usb_buf[0] = value;
297 ret = usb_control_msg(gspca_dev->dev,
298 usb_sndctrlpipe(gspca_dev->dev, 0),
299 0,
300 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
301 0, index, gspca_dev->usb_buf, 1,
302 500);
303 if (ret < 0) {
304 pr_err("reg_w() failed index 0x%02x, value 0x%02x, error %d\n",
305 index, value, ret);
306 gspca_dev->usb_err = ret;
307 }
308}
309
310static void reg_w_seq(struct gspca_dev *gspca_dev,
311 const __u8 *seq, int len)
312{
313 while (--len >= 0) {
314 reg_w(gspca_dev, seq[0], seq[1]);
315 seq += 2;
316 }
317}
318
319
320static void reg_w_page(struct gspca_dev *gspca_dev,
321 const __u8 *page, int len)
322{
323 int index;
324 int ret = 0;
325
326 if (gspca_dev->usb_err < 0)
327 return;
328 for (index = 0; index < len; index++) {
329 if (page[index] == SKIP)
330 continue;
331 gspca_dev->usb_buf[0] = page[index];
332 ret = usb_control_msg(gspca_dev->dev,
333 usb_sndctrlpipe(gspca_dev->dev, 0),
334 0,
335 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
336 0, index, gspca_dev->usb_buf, 1,
337 500);
338 if (ret < 0) {
339 pr_err("reg_w_page() failed index 0x%02x, value 0x%02x, error %d\n",
340 index, page[index], ret);
341 gspca_dev->usb_err = ret;
342 break;
343 }
344 }
345}
346
347
348static void reg_w_var(struct gspca_dev *gspca_dev,
349 const __u8 *seq,
350 const __u8 *page4, unsigned int page4_len)
351{
352 int index, len;
353
354 for (;;) {
355 index = *seq++;
356 len = *seq++;
357 switch (len) {
358 case END_OF_SEQUENCE:
359 return;
360 case LOAD_PAGE4:
361 reg_w_page(gspca_dev, page4, page4_len);
362 break;
363 default:
364 if (len > USB_BUF_SZ) {
365 PDEBUG(D_ERR|D_STREAM,
366 "Incorrect variable sequence");
367 return;
368 }
369 while (len > 0) {
370 if (len < 8) {
371 reg_w_buf(gspca_dev,
372 index, seq, len);
373 seq += len;
374 break;
375 }
376 reg_w_buf(gspca_dev, index, seq, 8);
377 seq += 8;
378 index += 8;
379 len -= 8;
380 }
381 }
382 }
383
384}
385
386
387static int sd_config(struct gspca_dev *gspca_dev,
388 const struct usb_device_id *id)
389{
390 struct sd *sd = (struct sd *) gspca_dev;
391 struct cam *cam;
392
393 cam = &gspca_dev->cam;
394
395 PDEBUG(D_CONF, "Find Sensor PAC7311");
396 cam->cam_mode = vga_mode;
397 cam->nmodes = ARRAY_SIZE(vga_mode);
398
399 sd->contrast = CONTRAST_DEF;
400 sd->gain = GAIN_DEF;
401 sd->exposure = EXPOSURE_DEF;
402 sd->autogain = AUTOGAIN_DEF;
403 sd->hflip = HFLIP_DEF;
404 sd->vflip = VFLIP_DEF;
405 return 0;
406}
407
408
409static void setcontrast(struct gspca_dev *gspca_dev)
410{
411 struct sd *sd = (struct sd *) gspca_dev;
412
413 reg_w(gspca_dev, 0xff, 0x04);
414 reg_w(gspca_dev, 0x10, sd->contrast >> 4);
415
416 reg_w(gspca_dev, 0x11, 0x01);
417}
418
419static void setgain(struct gspca_dev *gspca_dev)
420{
421 struct sd *sd = (struct sd *) gspca_dev;
422 int gain = GAIN_MAX - sd->gain;
423
424 if (gain < 1)
425 gain = 1;
426 else if (gain > 245)
427 gain = 245;
428 reg_w(gspca_dev, 0xff, 0x04);
429 reg_w(gspca_dev, 0x0e, 0x00);
430 reg_w(gspca_dev, 0x0f, gain);
431
432
433 reg_w(gspca_dev, 0x11, 0x01);
434}
435
436static void setexposure(struct gspca_dev *gspca_dev)
437{
438 struct sd *sd = (struct sd *) gspca_dev;
439 __u8 reg;
440
441
442
443
444 reg = 120 * sd->exposure / 1000;
445 if (reg < 2)
446 reg = 2;
447 else if (reg > 63)
448 reg = 63;
449
450 reg_w(gspca_dev, 0xff, 0x04);
451 reg_w(gspca_dev, 0x02, reg);
452
453
454
455 reg_w(gspca_dev, 0xff, 0x01);
456 if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv &&
457 reg <= 3) {
458 reg_w(gspca_dev, 0x08, 0x09);
459 } else {
460 reg_w(gspca_dev, 0x08, 0x08);
461 }
462
463
464 reg_w(gspca_dev, 0x11, 0x01);
465}
466
467static void sethvflip(struct gspca_dev *gspca_dev)
468{
469 struct sd *sd = (struct sd *) gspca_dev;
470 __u8 data;
471
472 reg_w(gspca_dev, 0xff, 0x04);
473 data = (sd->hflip ? 0x04 : 0x00) | (sd->vflip ? 0x08 : 0x00);
474 reg_w(gspca_dev, 0x21, data);
475
476
477 reg_w(gspca_dev, 0x11, 0x01);
478}
479
480
481static int sd_init(struct gspca_dev *gspca_dev)
482{
483 reg_w_seq(gspca_dev, init_7311, sizeof(init_7311)/2);
484 return gspca_dev->usb_err;
485}
486
487static int sd_start(struct gspca_dev *gspca_dev)
488{
489 struct sd *sd = (struct sd *) gspca_dev;
490
491 sd->sof_read = 0;
492
493 reg_w_var(gspca_dev, start_7311,
494 page4_7311, sizeof(page4_7311));
495 setcontrast(gspca_dev);
496 setgain(gspca_dev);
497 setexposure(gspca_dev);
498 sethvflip(gspca_dev);
499
500
501 switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
502 case 2:
503 reg_w(gspca_dev, 0xff, 0x01);
504 reg_w(gspca_dev, 0x17, 0x20);
505 reg_w(gspca_dev, 0x87, 0x10);
506 break;
507 case 1:
508 reg_w(gspca_dev, 0xff, 0x01);
509 reg_w(gspca_dev, 0x17, 0x30);
510 reg_w(gspca_dev, 0x87, 0x11);
511 break;
512 case 0:
513 reg_w(gspca_dev, 0xff, 0x01);
514 reg_w(gspca_dev, 0x17, 0x00);
515 reg_w(gspca_dev, 0x87, 0x12);
516 break;
517 }
518
519 sd->sof_read = 0;
520 sd->autogain_ignore_frames = 0;
521 atomic_set(&sd->avg_lum, -1);
522
523
524 reg_w(gspca_dev, 0xff, 0x01);
525 reg_w(gspca_dev, 0x78, 0x05);
526
527 return gspca_dev->usb_err;
528}
529
530static void sd_stopN(struct gspca_dev *gspca_dev)
531{
532 reg_w(gspca_dev, 0xff, 0x04);
533 reg_w(gspca_dev, 0x27, 0x80);
534 reg_w(gspca_dev, 0x28, 0xca);
535 reg_w(gspca_dev, 0x29, 0x53);
536 reg_w(gspca_dev, 0x2a, 0x0e);
537 reg_w(gspca_dev, 0xff, 0x01);
538 reg_w(gspca_dev, 0x3e, 0x20);
539 reg_w(gspca_dev, 0x78, 0x44);
540 reg_w(gspca_dev, 0x78, 0x44);
541 reg_w(gspca_dev, 0x78, 0x44);
542}
543
544
545static void sd_stop0(struct gspca_dev *gspca_dev)
546{
547}
548
549
550#include "pac_common.h"
551
552static void do_autogain(struct gspca_dev *gspca_dev)
553{
554 struct sd *sd = (struct sd *) gspca_dev;
555 int avg_lum = atomic_read(&sd->avg_lum);
556 int desired_lum, deadzone;
557
558 if (avg_lum == -1)
559 return;
560
561 desired_lum = 200;
562 deadzone = 20;
563
564 if (sd->autogain_ignore_frames > 0)
565 sd->autogain_ignore_frames--;
566 else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum,
567 deadzone, GAIN_KNEE, EXPOSURE_KNEE))
568 sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES;
569}
570
571
572static const unsigned char pac_jpeg_header1[] = {
573 0xff, 0xd8,
574
575 0xff, 0xc0,
576 0x00, 0x11,
577 0x08
578
579
580};
581
582
583static const unsigned char pac_jpeg_header2[] = {
584 0x03,
585 0x01, 0x21, 0x00,
586 0x02, 0x11, 0x01,
587 0x03, 0x11, 0x01,
588
589 0xff, 0xda,
590 0x00, 0x0c,
591 0x03,
592 0x01, 0x00,
593 0x02, 0x11,
594 0x03, 0x11,
595 0x00, 0x3f,
596 0x00
597};
598
599static void pac_start_frame(struct gspca_dev *gspca_dev,
600 __u16 lines, __u16 samples_per_line)
601{
602 unsigned char tmpbuf[4];
603
604 gspca_frame_add(gspca_dev, FIRST_PACKET,
605 pac_jpeg_header1, sizeof(pac_jpeg_header1));
606
607 tmpbuf[0] = lines >> 8;
608 tmpbuf[1] = lines & 0xff;
609 tmpbuf[2] = samples_per_line >> 8;
610 tmpbuf[3] = samples_per_line & 0xff;
611
612 gspca_frame_add(gspca_dev, INTER_PACKET,
613 tmpbuf, sizeof(tmpbuf));
614 gspca_frame_add(gspca_dev, INTER_PACKET,
615 pac_jpeg_header2, sizeof(pac_jpeg_header2));
616}
617
618
619static void sd_pkt_scan(struct gspca_dev *gspca_dev,
620 u8 *data,
621 int len)
622{
623 struct sd *sd = (struct sd *) gspca_dev;
624 u8 *image;
625 unsigned char *sof;
626
627 sof = pac_find_sof(&sd->sof_read, data, len);
628 if (sof) {
629 int n, lum_offset, footer_length;
630
631
632
633
634
635 lum_offset = 24 + sizeof pac_sof_marker;
636 footer_length = 26;
637
638
639 n = (sof - data) - (footer_length + sizeof pac_sof_marker);
640 if (n < 0) {
641 gspca_dev->image_len += n;
642 n = 0;
643 } else {
644 gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
645 }
646 image = gspca_dev->image;
647 if (image != NULL
648 && image[gspca_dev->image_len - 2] == 0xff
649 && image[gspca_dev->image_len - 1] == 0xd9)
650 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
651
652 n = sof - data;
653 len -= n;
654 data = sof;
655
656
657 if (gspca_dev->last_packet_type == LAST_PACKET &&
658 n >= lum_offset)
659 atomic_set(&sd->avg_lum, data[-lum_offset] +
660 data[-lum_offset + 1]);
661 else
662 atomic_set(&sd->avg_lum, -1);
663
664
665 pac_start_frame(gspca_dev,
666 gspca_dev->height, gspca_dev->width);
667 }
668 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
669}
670
671static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
672{
673 struct sd *sd = (struct sd *) gspca_dev;
674
675 sd->contrast = val;
676 if (gspca_dev->streaming)
677 setcontrast(gspca_dev);
678 return gspca_dev->usb_err;
679}
680
681static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
682{
683 struct sd *sd = (struct sd *) gspca_dev;
684
685 *val = sd->contrast;
686 return 0;
687}
688
689static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
690{
691 struct sd *sd = (struct sd *) gspca_dev;
692
693 sd->gain = val;
694 if (gspca_dev->streaming)
695 setgain(gspca_dev);
696 return gspca_dev->usb_err;
697}
698
699static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
700{
701 struct sd *sd = (struct sd *) gspca_dev;
702
703 *val = sd->gain;
704 return 0;
705}
706
707static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
708{
709 struct sd *sd = (struct sd *) gspca_dev;
710
711 sd->exposure = val;
712 if (gspca_dev->streaming)
713 setexposure(gspca_dev);
714 return gspca_dev->usb_err;
715}
716
717static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
718{
719 struct sd *sd = (struct sd *) gspca_dev;
720
721 *val = sd->exposure;
722 return 0;
723}
724
725static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
726{
727 struct sd *sd = (struct sd *) gspca_dev;
728
729 sd->autogain = val;
730
731
732
733
734 if (sd->autogain) {
735 sd->exposure = EXPOSURE_DEF;
736 sd->gain = GAIN_DEF;
737 if (gspca_dev->streaming) {
738 sd->autogain_ignore_frames =
739 PAC_AUTOGAIN_IGNORE_FRAMES;
740 setexposure(gspca_dev);
741 setgain(gspca_dev);
742 }
743 }
744
745 return gspca_dev->usb_err;
746}
747
748static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
749{
750 struct sd *sd = (struct sd *) gspca_dev;
751
752 *val = sd->autogain;
753 return 0;
754}
755
756static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
757{
758 struct sd *sd = (struct sd *) gspca_dev;
759
760 sd->hflip = val;
761 if (gspca_dev->streaming)
762 sethvflip(gspca_dev);
763 return gspca_dev->usb_err;
764}
765
766static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
767{
768 struct sd *sd = (struct sd *) gspca_dev;
769
770 *val = sd->hflip;
771 return 0;
772}
773
774static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
775{
776 struct sd *sd = (struct sd *) gspca_dev;
777
778 sd->vflip = val;
779 if (gspca_dev->streaming)
780 sethvflip(gspca_dev);
781 return gspca_dev->usb_err;
782}
783
784static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
785{
786 struct sd *sd = (struct sd *) gspca_dev;
787
788 *val = sd->vflip;
789 return 0;
790}
791
792#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
793static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
794 u8 *data,
795 int len)
796{
797 int ret = -EINVAL;
798 u8 data0, data1;
799
800 if (len == 2) {
801 data0 = data[0];
802 data1 = data[1];
803 if ((data0 == 0x00 && data1 == 0x11) ||
804 (data0 == 0x22 && data1 == 0x33) ||
805 (data0 == 0x44 && data1 == 0x55) ||
806 (data0 == 0x66 && data1 == 0x77) ||
807 (data0 == 0x88 && data1 == 0x99) ||
808 (data0 == 0xaa && data1 == 0xbb) ||
809 (data0 == 0xcc && data1 == 0xdd) ||
810 (data0 == 0xee && data1 == 0xff)) {
811 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
812 input_sync(gspca_dev->input_dev);
813 input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
814 input_sync(gspca_dev->input_dev);
815 ret = 0;
816 }
817 }
818
819 return ret;
820}
821#endif
822
823
824static const struct sd_desc sd_desc = {
825 .name = MODULE_NAME,
826 .ctrls = sd_ctrls,
827 .nctrls = ARRAY_SIZE(sd_ctrls),
828 .config = sd_config,
829 .init = sd_init,
830 .start = sd_start,
831 .stopN = sd_stopN,
832 .stop0 = sd_stop0,
833 .pkt_scan = sd_pkt_scan,
834 .dq_callback = do_autogain,
835#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
836 .int_pkt_scan = sd_int_pkt_scan,
837#endif
838};
839
840
841static const struct usb_device_id device_table[] = {
842 {USB_DEVICE(0x093a, 0x2600)},
843 {USB_DEVICE(0x093a, 0x2601)},
844 {USB_DEVICE(0x093a, 0x2603)},
845 {USB_DEVICE(0x093a, 0x2608)},
846 {USB_DEVICE(0x093a, 0x260e)},
847 {USB_DEVICE(0x093a, 0x260f)},
848 {}
849};
850MODULE_DEVICE_TABLE(usb, device_table);
851
852
853static int sd_probe(struct usb_interface *intf,
854 const struct usb_device_id *id)
855{
856 return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
857 THIS_MODULE);
858}
859
860static struct usb_driver sd_driver = {
861 .name = MODULE_NAME,
862 .id_table = device_table,
863 .probe = sd_probe,
864 .disconnect = gspca_disconnect,
865#ifdef CONFIG_PM
866 .suspend = gspca_suspend,
867 .resume = gspca_resume,
868#endif
869};
870
871module_usb_driver(sd_driver);
872