diff options
Diffstat (limited to 'drivers/media/video/gspca/pac7302.c')
-rw-r--r-- | drivers/media/video/gspca/pac7302.c | 411 |
1 files changed, 188 insertions, 223 deletions
diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c index de0b66c4b56e..2a68220d1ada 100644 --- a/drivers/media/video/gspca/pac7302.c +++ b/drivers/media/video/gspca/pac7302.c | |||
@@ -4,7 +4,9 @@ | |||
4 | * | 4 | * |
5 | * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> | 5 | * V4L2 by Jean-Francois Moine <http://moinejf.free.fr> |
6 | * | 6 | * |
7 | * Separated from Pixart PAC7311 library by Márton Németh <nm127@freemail.hu> | 7 | * Separated from Pixart PAC7311 library by Márton Németh |
8 | * Camera button input handling by Márton Németh <nm127@freemail.hu> | ||
9 | * Copyright (C) 2009-2010 Márton Németh <nm127@freemail.hu> | ||
8 | * | 10 | * |
9 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
@@ -22,33 +24,26 @@ | |||
22 | */ | 24 | */ |
23 | 25 | ||
24 | /* Some documentation about various registers as determined by trial and error. | 26 | /* Some documentation about various registers as determined by trial and error. |
25 | When the register addresses differ between the 7202 and the 7311 the 2 | ||
26 | different addresses are written as 7302addr/7311addr, when one of the 2 | ||
27 | addresses is a - sign that register description is not valid for the | ||
28 | matching IC. | ||
29 | 27 | ||
30 | Register page 1: | 28 | Register page 1: |
31 | 29 | ||
32 | Address Description | 30 | Address Description |
33 | -/0x08 Unknown compressor related, must always be 8 except when not | ||
34 | in 640x480 resolution and page 4 reg 2 <= 3 then set it to 9 ! | ||
35 | -/0x1b Auto white balance related, bit 0 is AWB enable (inverted) | ||
36 | bits 345 seem to toggle per color gains on/off (inverted) | ||
37 | 0x78 Global control, bit 6 controls the LED (inverted) | 31 | 0x78 Global control, bit 6 controls the LED (inverted) |
38 | -/0x80 JPEG compression ratio ? Best not touched | ||
39 | 32 | ||
40 | Register page 3/4: | 33 | Register page 3: |
41 | 34 | ||
42 | Address Description | 35 | Address Description |
43 | 0x02 Clock divider 2-63, fps =~ 60 / val. Must be a multiple of 3 on | 36 | 0x02 Clock divider 3-63, fps = 90 / val. Must be a multiple of 3 on |
44 | the 7302, so one of 3, 6, 9, ..., except when between 6 and 12? | 37 | the 7302, so one of 3, 6, 9, ..., except when between 6 and 12? |
45 | -/0x0f Master gain 1-245, low value = high gain | 38 | 0x03 Variable framerate ctrl reg2==3: 0 -> ~30 fps, 255 -> ~22fps |
46 | 0x10/- Master gain 0-31 | 39 | 0x04 Another var framerate ctrl reg2==3, reg3==0: 0 -> ~30 fps, |
47 | -/0x10 Another gain 0-15, limited influence (1-2x gain I guess) | 40 | 63 -> ~27 fps, the 2 msb's must always be 1 !! |
41 | 0x05 Another var framerate ctrl reg2==3, reg3==0, reg4==0xc0: | ||
42 | 1 -> ~30 fps, 2 -> ~20 fps | ||
43 | 0x0e Exposure bits 0-7, 0-448, 0 = use full frame time | ||
44 | 0x0f Exposure bit 8, 0-448, 448 = no exposure at all | ||
45 | 0x10 Master gain 0-31 | ||
48 | 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused | 46 | 0x21 Bitfield: 0-1 unused, 2-3 vflip/hflip, 4-5 unknown, 6-7 unused |
49 | -/0x27 Seems to toggle various gains on / off, Setting bit 7 seems to | ||
50 | completely disable the analog amplification block. Set to 0x68 | ||
51 | for max gain, 0x14 for minimal gain. | ||
52 | 47 | ||
53 | The registers are accessed in the following functions: | 48 | The registers are accessed in the following functions: |
54 | 49 | ||
@@ -68,6 +63,7 @@ | |||
68 | 63 | ||
69 | #define MODULE_NAME "pac7302" | 64 | #define MODULE_NAME "pac7302" |
70 | 65 | ||
66 | #include <linux/input.h> | ||
71 | #include <media/v4l2-chip-ident.h> | 67 | #include <media/v4l2-chip-ident.h> |
72 | #include "gspca.h" | 68 | #include "gspca.h" |
73 | 69 | ||
@@ -86,8 +82,8 @@ struct sd { | |||
86 | unsigned char red_balance; | 82 | unsigned char red_balance; |
87 | unsigned char blue_balance; | 83 | unsigned char blue_balance; |
88 | unsigned char gain; | 84 | unsigned char gain; |
89 | unsigned char exposure; | ||
90 | unsigned char autogain; | 85 | unsigned char autogain; |
86 | unsigned short exposure; | ||
91 | __u8 hflip; | 87 | __u8 hflip; |
92 | __u8 vflip; | 88 | __u8 vflip; |
93 | u8 flags; | 89 | u8 flags; |
@@ -124,8 +120,7 @@ static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); | |||
124 | static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); | 120 | static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); |
125 | static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); | 121 | static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); |
126 | 122 | ||
127 | static struct ctrl sd_ctrls[] = { | 123 | static const struct ctrl sd_ctrls[] = { |
128 | /* This control is pac7302 only */ | ||
129 | { | 124 | { |
130 | { | 125 | { |
131 | .id = V4L2_CID_BRIGHTNESS, | 126 | .id = V4L2_CID_BRIGHTNESS, |
@@ -141,7 +136,6 @@ static struct ctrl sd_ctrls[] = { | |||
141 | .set = sd_setbrightness, | 136 | .set = sd_setbrightness, |
142 | .get = sd_getbrightness, | 137 | .get = sd_getbrightness, |
143 | }, | 138 | }, |
144 | /* This control is for both the 7302 and the 7311 */ | ||
145 | { | 139 | { |
146 | { | 140 | { |
147 | .id = V4L2_CID_CONTRAST, | 141 | .id = V4L2_CID_CONTRAST, |
@@ -157,7 +151,6 @@ static struct ctrl sd_ctrls[] = { | |||
157 | .set = sd_setcontrast, | 151 | .set = sd_setcontrast, |
158 | .get = sd_getcontrast, | 152 | .get = sd_getcontrast, |
159 | }, | 153 | }, |
160 | /* This control is pac7302 only */ | ||
161 | { | 154 | { |
162 | { | 155 | { |
163 | .id = V4L2_CID_SATURATION, | 156 | .id = V4L2_CID_SATURATION, |
@@ -215,7 +208,6 @@ static struct ctrl sd_ctrls[] = { | |||
215 | .set = sd_setbluebalance, | 208 | .set = sd_setbluebalance, |
216 | .get = sd_getbluebalance, | 209 | .get = sd_getbluebalance, |
217 | }, | 210 | }, |
218 | /* All controls below are for both the 7302 and the 7311 */ | ||
219 | { | 211 | { |
220 | { | 212 | { |
221 | .id = V4L2_CID_GAIN, | 213 | .id = V4L2_CID_GAIN, |
@@ -238,11 +230,10 @@ static struct ctrl sd_ctrls[] = { | |||
238 | .type = V4L2_CTRL_TYPE_INTEGER, | 230 | .type = V4L2_CTRL_TYPE_INTEGER, |
239 | .name = "Exposure", | 231 | .name = "Exposure", |
240 | .minimum = 0, | 232 | .minimum = 0, |
241 | #define EXPOSURE_MAX 255 | 233 | .maximum = 1023, |
242 | .maximum = EXPOSURE_MAX, | ||
243 | .step = 1, | 234 | .step = 1, |
244 | #define EXPOSURE_DEF 16 /* 32 ms / 30 fps */ | 235 | #define EXPOSURE_DEF 66 /* 33 ms / 30 fps */ |
245 | #define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */ | 236 | #define EXPOSURE_KNEE 133 /* 66 ms / 15 fps */ |
246 | .default_value = EXPOSURE_DEF, | 237 | .default_value = EXPOSURE_DEF, |
247 | }, | 238 | }, |
248 | .set = sd_setexposure, | 239 | .set = sd_setexposure, |
@@ -301,7 +292,6 @@ static const struct v4l2_pix_format vga_mode[] = { | |||
301 | }; | 292 | }; |
302 | 293 | ||
303 | #define LOAD_PAGE3 255 | 294 | #define LOAD_PAGE3 255 |
304 | #define LOAD_PAGE4 254 | ||
305 | #define END_OF_SEQUENCE 0 | 295 | #define END_OF_SEQUENCE 0 |
306 | 296 | ||
307 | /* pac 7302 */ | 297 | /* pac 7302 */ |
@@ -379,7 +369,7 @@ static const __u8 start_7302[] = { | |||
379 | #define SKIP 0xaa | 369 | #define SKIP 0xaa |
380 | /* page 3 - the value SKIP says skip the index - see reg_w_page() */ | 370 | /* page 3 - the value SKIP says skip the index - see reg_w_page() */ |
381 | static const __u8 page3_7302[] = { | 371 | static const __u8 page3_7302[] = { |
382 | 0x90, 0x40, 0x03, 0x50, 0xc2, 0x01, 0x14, 0x16, | 372 | 0x90, 0x40, 0x03, 0x00, 0xc0, 0x01, 0x14, 0x16, |
383 | 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00, | 373 | 0x14, 0x12, 0x00, 0x00, 0x00, 0x02, 0x33, 0x00, |
384 | 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 374 | 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
385 | 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00, | 375 | 0x00, 0x00, 0x00, 0x47, 0x01, 0xb3, 0x01, 0x00, |
@@ -388,7 +378,7 @@ static const __u8 page3_7302[] = { | |||
388 | 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00, | 378 | 0xa4, 0xb8, 0xe0, 0x2a, 0xf6, 0x00, 0x00, 0x00, |
389 | 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 379 | 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
390 | 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00, | 380 | 0x00, 0xfc, 0x00, 0xf2, 0x1f, 0x04, 0x00, 0x00, |
391 | 0x00, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00, | 381 | SKIP, 0x00, 0x00, 0xc0, 0xc0, 0x10, 0x00, 0x00, |
392 | 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 382 | 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
393 | 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00, | 383 | 0x00, 0x40, 0xff, 0x03, 0x19, 0x00, 0x00, 0x00, |
394 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | 384 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
@@ -401,12 +391,14 @@ static const __u8 page3_7302[] = { | |||
401 | 0x00 | 391 | 0x00 |
402 | }; | 392 | }; |
403 | 393 | ||
404 | static int reg_w_buf(struct gspca_dev *gspca_dev, | 394 | static void reg_w_buf(struct gspca_dev *gspca_dev, |
405 | __u8 index, | 395 | __u8 index, |
406 | const char *buffer, int len) | 396 | const char *buffer, int len) |
407 | { | 397 | { |
408 | int ret; | 398 | int ret; |
409 | 399 | ||
400 | if (gspca_dev->usb_err < 0) | ||
401 | return; | ||
410 | memcpy(gspca_dev->usb_buf, buffer, len); | 402 | memcpy(gspca_dev->usb_buf, buffer, len); |
411 | ret = usb_control_msg(gspca_dev->dev, | 403 | ret = usb_control_msg(gspca_dev->dev, |
412 | usb_sndctrlpipe(gspca_dev->dev, 0), | 404 | usb_sndctrlpipe(gspca_dev->dev, 0), |
@@ -415,20 +407,23 @@ static int reg_w_buf(struct gspca_dev *gspca_dev, | |||
415 | 0, /* value */ | 407 | 0, /* value */ |
416 | index, gspca_dev->usb_buf, len, | 408 | index, gspca_dev->usb_buf, len, |
417 | 500); | 409 | 500); |
418 | if (ret < 0) | 410 | if (ret < 0) { |
419 | PDEBUG(D_ERR, "reg_w_buf(): " | 411 | PDEBUG(D_ERR, "reg_w_buf(): " |
420 | "Failed to write registers to index 0x%x, error %i", | 412 | "Failed to write registers to index 0x%x, error %i", |
421 | index, ret); | 413 | index, ret); |
422 | return ret; | 414 | gspca_dev->usb_err = ret; |
415 | } | ||
423 | } | 416 | } |
424 | 417 | ||
425 | 418 | ||
426 | static int reg_w(struct gspca_dev *gspca_dev, | 419 | static void reg_w(struct gspca_dev *gspca_dev, |
427 | __u8 index, | 420 | __u8 index, |
428 | __u8 value) | 421 | __u8 value) |
429 | { | 422 | { |
430 | int ret; | 423 | int ret; |
431 | 424 | ||
425 | if (gspca_dev->usb_err < 0) | ||
426 | return; | ||
432 | gspca_dev->usb_buf[0] = value; | 427 | gspca_dev->usb_buf[0] = value; |
433 | ret = usb_control_msg(gspca_dev->dev, | 428 | ret = usb_control_msg(gspca_dev->dev, |
434 | usb_sndctrlpipe(gspca_dev->dev, 0), | 429 | usb_sndctrlpipe(gspca_dev->dev, 0), |
@@ -436,32 +431,32 @@ static int reg_w(struct gspca_dev *gspca_dev, | |||
436 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | 431 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
437 | 0, index, gspca_dev->usb_buf, 1, | 432 | 0, index, gspca_dev->usb_buf, 1, |
438 | 500); | 433 | 500); |
439 | if (ret < 0) | 434 | if (ret < 0) { |
440 | PDEBUG(D_ERR, "reg_w(): " | 435 | PDEBUG(D_ERR, "reg_w(): " |
441 | "Failed to write register to index 0x%x, value 0x%x, error %i", | 436 | "Failed to write register to index 0x%x, value 0x%x, error %i", |
442 | index, value, ret); | 437 | index, value, ret); |
443 | return ret; | 438 | gspca_dev->usb_err = ret; |
439 | } | ||
444 | } | 440 | } |
445 | 441 | ||
446 | static int reg_w_seq(struct gspca_dev *gspca_dev, | 442 | static void reg_w_seq(struct gspca_dev *gspca_dev, |
447 | const __u8 *seq, int len) | 443 | const __u8 *seq, int len) |
448 | { | 444 | { |
449 | int ret = 0; | ||
450 | while (--len >= 0) { | 445 | while (--len >= 0) { |
451 | if (0 <= ret) | 446 | reg_w(gspca_dev, seq[0], seq[1]); |
452 | ret = reg_w(gspca_dev, seq[0], seq[1]); | ||
453 | seq += 2; | 447 | seq += 2; |
454 | } | 448 | } |
455 | return ret; | ||
456 | } | 449 | } |
457 | 450 | ||
458 | /* load the beginning of a page */ | 451 | /* load the beginning of a page */ |
459 | static int reg_w_page(struct gspca_dev *gspca_dev, | 452 | static void reg_w_page(struct gspca_dev *gspca_dev, |
460 | const __u8 *page, int len) | 453 | const __u8 *page, int len) |
461 | { | 454 | { |
462 | int index; | 455 | int index; |
463 | int ret = 0; | 456 | int ret = 0; |
464 | 457 | ||
458 | if (gspca_dev->usb_err < 0) | ||
459 | return; | ||
465 | for (index = 0; index < len; index++) { | 460 | for (index = 0; index < len; index++) { |
466 | if (page[index] == SKIP) /* skip this index */ | 461 | if (page[index] == SKIP) /* skip this index */ |
467 | continue; | 462 | continue; |
@@ -477,56 +472,47 @@ static int reg_w_page(struct gspca_dev *gspca_dev, | |||
477 | "Failed to write register to index 0x%x, " | 472 | "Failed to write register to index 0x%x, " |
478 | "value 0x%x, error %i", | 473 | "value 0x%x, error %i", |
479 | index, page[index], ret); | 474 | index, page[index], ret); |
475 | gspca_dev->usb_err = ret; | ||
480 | break; | 476 | break; |
481 | } | 477 | } |
482 | } | 478 | } |
483 | return ret; | ||
484 | } | 479 | } |
485 | 480 | ||
486 | /* output a variable sequence */ | 481 | /* output a variable sequence */ |
487 | static int reg_w_var(struct gspca_dev *gspca_dev, | 482 | static void reg_w_var(struct gspca_dev *gspca_dev, |
488 | const __u8 *seq, | 483 | const __u8 *seq, |
489 | const __u8 *page3, unsigned int page3_len, | 484 | const __u8 *page3, unsigned int page3_len) |
490 | const __u8 *page4, unsigned int page4_len) | ||
491 | { | 485 | { |
492 | int index, len; | 486 | int index, len; |
493 | int ret = 0; | ||
494 | 487 | ||
495 | for (;;) { | 488 | for (;;) { |
496 | index = *seq++; | 489 | index = *seq++; |
497 | len = *seq++; | 490 | len = *seq++; |
498 | switch (len) { | 491 | switch (len) { |
499 | case END_OF_SEQUENCE: | 492 | case END_OF_SEQUENCE: |
500 | return ret; | 493 | return; |
501 | case LOAD_PAGE4: | ||
502 | ret = reg_w_page(gspca_dev, page4, page4_len); | ||
503 | break; | ||
504 | case LOAD_PAGE3: | 494 | case LOAD_PAGE3: |
505 | ret = reg_w_page(gspca_dev, page3, page3_len); | 495 | reg_w_page(gspca_dev, page3, page3_len); |
506 | break; | 496 | break; |
507 | default: | 497 | default: |
508 | if (len > USB_BUF_SZ) { | 498 | if (len > USB_BUF_SZ) { |
509 | PDEBUG(D_ERR|D_STREAM, | 499 | PDEBUG(D_ERR|D_STREAM, |
510 | "Incorrect variable sequence"); | 500 | "Incorrect variable sequence"); |
511 | return -EINVAL; | 501 | return; |
512 | } | 502 | } |
513 | while (len > 0) { | 503 | while (len > 0) { |
514 | if (len < 8) { | 504 | if (len < 8) { |
515 | ret = reg_w_buf(gspca_dev, | 505 | reg_w_buf(gspca_dev, |
516 | index, seq, len); | 506 | index, seq, len); |
517 | if (ret < 0) | ||
518 | return ret; | ||
519 | seq += len; | 507 | seq += len; |
520 | break; | 508 | break; |
521 | } | 509 | } |
522 | ret = reg_w_buf(gspca_dev, index, seq, 8); | 510 | reg_w_buf(gspca_dev, index, seq, 8); |
523 | seq += 8; | 511 | seq += 8; |
524 | index += 8; | 512 | index += 8; |
525 | len -= 8; | 513 | len -= 8; |
526 | } | 514 | } |
527 | } | 515 | } |
528 | if (ret < 0) | ||
529 | return ret; | ||
530 | } | 516 | } |
531 | /* not reached */ | 517 | /* not reached */ |
532 | } | 518 | } |
@@ -560,11 +546,10 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
560 | } | 546 | } |
561 | 547 | ||
562 | /* This function is used by pac7302 only */ | 548 | /* This function is used by pac7302 only */ |
563 | static int setbrightcont(struct gspca_dev *gspca_dev) | 549 | static void setbrightcont(struct gspca_dev *gspca_dev) |
564 | { | 550 | { |
565 | struct sd *sd = (struct sd *) gspca_dev; | 551 | struct sd *sd = (struct sd *) gspca_dev; |
566 | int i, v; | 552 | int i, v; |
567 | int ret; | ||
568 | static const __u8 max[10] = | 553 | static const __u8 max[10] = |
569 | {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb, | 554 | {0x29, 0x33, 0x42, 0x5a, 0x6e, 0x80, 0x9f, 0xbb, |
570 | 0xd4, 0xec}; | 555 | 0xd4, 0xec}; |
@@ -572,7 +557,7 @@ static int setbrightcont(struct gspca_dev *gspca_dev) | |||
572 | {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17, | 557 | {0x35, 0x33, 0x33, 0x2f, 0x2a, 0x25, 0x1e, 0x17, |
573 | 0x11, 0x0b}; | 558 | 0x11, 0x0b}; |
574 | 559 | ||
575 | ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ | 560 | reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ |
576 | for (i = 0; i < 10; i++) { | 561 | for (i = 0; i < 10; i++) { |
577 | v = max[i]; | 562 | v = max[i]; |
578 | v += (sd->brightness - BRIGHTNESS_MAX) | 563 | v += (sd->brightness - BRIGHTNESS_MAX) |
@@ -582,136 +567,121 @@ static int setbrightcont(struct gspca_dev *gspca_dev) | |||
582 | v = 0; | 567 | v = 0; |
583 | else if (v > 0xff) | 568 | else if (v > 0xff) |
584 | v = 0xff; | 569 | v = 0xff; |
585 | if (0 <= ret) | 570 | reg_w(gspca_dev, 0xa2 + i, v); |
586 | ret = reg_w(gspca_dev, 0xa2 + i, v); | ||
587 | } | 571 | } |
588 | if (0 <= ret) | 572 | reg_w(gspca_dev, 0xdc, 0x01); |
589 | ret = reg_w(gspca_dev, 0xdc, 0x01); | ||
590 | return ret; | ||
591 | } | 573 | } |
592 | 574 | ||
593 | /* This function is used by pac7302 only */ | 575 | /* This function is used by pac7302 only */ |
594 | static int setcolors(struct gspca_dev *gspca_dev) | 576 | static void setcolors(struct gspca_dev *gspca_dev) |
595 | { | 577 | { |
596 | struct sd *sd = (struct sd *) gspca_dev; | 578 | struct sd *sd = (struct sd *) gspca_dev; |
597 | int i, v; | 579 | int i, v; |
598 | int ret; | ||
599 | static const int a[9] = | 580 | static const int a[9] = |
600 | {217, -212, 0, -101, 170, -67, -38, -315, 355}; | 581 | {217, -212, 0, -101, 170, -67, -38, -315, 355}; |
601 | static const int b[9] = | 582 | static const int b[9] = |
602 | {19, 106, 0, 19, 106, 1, 19, 106, 1}; | 583 | {19, 106, 0, 19, 106, 1, 19, 106, 1}; |
603 | 584 | ||
604 | ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ | 585 | reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ |
605 | if (0 <= ret) | 586 | reg_w(gspca_dev, 0x11, 0x01); |
606 | ret = reg_w(gspca_dev, 0x11, 0x01); | 587 | reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ |
607 | if (0 <= ret) | ||
608 | ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ | ||
609 | for (i = 0; i < 9; i++) { | 588 | for (i = 0; i < 9; i++) { |
610 | v = a[i] * sd->colors / COLOR_MAX + b[i]; | 589 | v = a[i] * sd->colors / COLOR_MAX + b[i]; |
611 | if (0 <= ret) | 590 | reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07); |
612 | ret = reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07); | 591 | reg_w(gspca_dev, 0x0f + 2 * i + 1, v); |
613 | if (0 <= ret) | ||
614 | ret = reg_w(gspca_dev, 0x0f + 2 * i + 1, v); | ||
615 | } | 592 | } |
616 | if (0 <= ret) | 593 | reg_w(gspca_dev, 0xdc, 0x01); |
617 | ret = reg_w(gspca_dev, 0xdc, 0x01); | ||
618 | PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors); | 594 | PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors); |
619 | return ret; | ||
620 | } | 595 | } |
621 | 596 | ||
622 | static int setwhitebalance(struct gspca_dev *gspca_dev) | 597 | static void setwhitebalance(struct gspca_dev *gspca_dev) |
623 | { | 598 | { |
624 | struct sd *sd = (struct sd *) gspca_dev; | 599 | struct sd *sd = (struct sd *) gspca_dev; |
625 | int ret; | ||
626 | 600 | ||
627 | ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ | 601 | reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ |
628 | if (0 <= ret) | 602 | reg_w(gspca_dev, 0xc6, sd->white_balance); |
629 | ret = reg_w(gspca_dev, 0xc6, sd->white_balance); | ||
630 | 603 | ||
631 | if (0 <= ret) | 604 | reg_w(gspca_dev, 0xdc, 0x01); |
632 | ret = reg_w(gspca_dev, 0xdc, 0x01); | ||
633 | PDEBUG(D_CONF|D_STREAM, "white_balance: %i", sd->white_balance); | 605 | PDEBUG(D_CONF|D_STREAM, "white_balance: %i", sd->white_balance); |
634 | return ret; | ||
635 | } | 606 | } |
636 | 607 | ||
637 | static int setredbalance(struct gspca_dev *gspca_dev) | 608 | static void setredbalance(struct gspca_dev *gspca_dev) |
638 | { | 609 | { |
639 | struct sd *sd = (struct sd *) gspca_dev; | 610 | struct sd *sd = (struct sd *) gspca_dev; |
640 | int ret; | ||
641 | 611 | ||
642 | ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ | 612 | reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ |
643 | if (0 <= ret) | 613 | reg_w(gspca_dev, 0xc5, sd->red_balance); |
644 | ret = reg_w(gspca_dev, 0xc5, sd->red_balance); | ||
645 | 614 | ||
646 | if (0 <= ret) | 615 | reg_w(gspca_dev, 0xdc, 0x01); |
647 | ret = reg_w(gspca_dev, 0xdc, 0x01); | ||
648 | PDEBUG(D_CONF|D_STREAM, "red_balance: %i", sd->red_balance); | 616 | PDEBUG(D_CONF|D_STREAM, "red_balance: %i", sd->red_balance); |
649 | return ret; | ||
650 | } | 617 | } |
651 | 618 | ||
652 | static int setbluebalance(struct gspca_dev *gspca_dev) | 619 | static void setbluebalance(struct gspca_dev *gspca_dev) |
653 | { | 620 | { |
654 | struct sd *sd = (struct sd *) gspca_dev; | 621 | struct sd *sd = (struct sd *) gspca_dev; |
655 | int ret; | ||
656 | 622 | ||
657 | ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ | 623 | reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ |
658 | if (0 <= ret) | 624 | reg_w(gspca_dev, 0xc7, sd->blue_balance); |
659 | ret = reg_w(gspca_dev, 0xc7, sd->blue_balance); | ||
660 | 625 | ||
661 | if (0 <= ret) | 626 | reg_w(gspca_dev, 0xdc, 0x01); |
662 | ret = reg_w(gspca_dev, 0xdc, 0x01); | ||
663 | PDEBUG(D_CONF|D_STREAM, "blue_balance: %i", sd->blue_balance); | 627 | PDEBUG(D_CONF|D_STREAM, "blue_balance: %i", sd->blue_balance); |
664 | return ret; | ||
665 | } | 628 | } |
666 | 629 | ||
667 | static int setgain(struct gspca_dev *gspca_dev) | 630 | static void setgain(struct gspca_dev *gspca_dev) |
668 | { | 631 | { |
669 | struct sd *sd = (struct sd *) gspca_dev; | 632 | struct sd *sd = (struct sd *) gspca_dev; |
670 | int ret; | ||
671 | 633 | ||
672 | ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ | 634 | reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ |
673 | if (0 <= ret) | 635 | reg_w(gspca_dev, 0x10, sd->gain >> 3); |
674 | ret = reg_w(gspca_dev, 0x10, sd->gain >> 3); | ||
675 | 636 | ||
676 | /* load registers to sensor (Bit 0, auto clear) */ | 637 | /* load registers to sensor (Bit 0, auto clear) */ |
677 | if (0 <= ret) | 638 | reg_w(gspca_dev, 0x11, 0x01); |
678 | ret = reg_w(gspca_dev, 0x11, 0x01); | ||
679 | return ret; | ||
680 | } | 639 | } |
681 | 640 | ||
682 | static int setexposure(struct gspca_dev *gspca_dev) | 641 | static void setexposure(struct gspca_dev *gspca_dev) |
683 | { | 642 | { |
684 | struct sd *sd = (struct sd *) gspca_dev; | 643 | struct sd *sd = (struct sd *) gspca_dev; |
685 | int ret; | 644 | __u8 clockdiv; |
686 | __u8 reg; | 645 | __u16 exposure; |
687 | 646 | ||
688 | /* register 2 of frame 3/4 contains the clock divider configuring the | 647 | /* register 2 of frame 3 contains the clock divider configuring the |
689 | no fps according to the formula: 60 / reg. sd->exposure is the | 648 | no fps according to the formula: 90 / reg. sd->exposure is the |
690 | desired exposure time in ms. */ | 649 | desired exposure time in 0.5 ms. */ |
691 | reg = 120 * sd->exposure / 1000; | 650 | clockdiv = (90 * sd->exposure + 1999) / 2000; |
692 | if (reg < 2) | 651 | |
693 | reg = 2; | 652 | /* Note clockdiv = 3 also works, but when running at 30 fps, depending |
694 | else if (reg > 63) | 653 | on the scene being recorded, the camera switches to another |
695 | reg = 63; | 654 | quantization table for certain JPEG blocks, and we don't know how |
696 | 655 | to decompress these blocks. So we cap the framerate at 15 fps */ | |
697 | /* On the pac7302 reg2 MUST be a multiple of 3, so round it to | 656 | if (clockdiv < 6) |
698 | the nearest multiple of 3, except when between 6 and 12? */ | 657 | clockdiv = 6; |
699 | if (reg < 6 || reg > 12) | 658 | else if (clockdiv > 63) |
700 | reg = ((reg + 1) / 3) * 3; | 659 | clockdiv = 63; |
701 | ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ | 660 | |
702 | if (0 <= ret) | 661 | /* reg2 MUST be a multiple of 3, except when between 6 and 12? |
703 | ret = reg_w(gspca_dev, 0x02, reg); | 662 | Always round up, otherwise we cannot get the desired frametime |
663 | using the partial frame time exposure control */ | ||
664 | if (clockdiv < 6 || clockdiv > 12) | ||
665 | clockdiv = ((clockdiv + 2) / 3) * 3; | ||
666 | |||
667 | /* frame exposure time in ms = 1000 * clockdiv / 90 -> | ||
668 | exposure = (sd->exposure / 2) * 448 / (1000 * clockdiv / 90) */ | ||
669 | exposure = (sd->exposure * 45 * 448) / (1000 * clockdiv); | ||
670 | /* 0 = use full frametime, 448 = no exposure, reverse it */ | ||
671 | exposure = 448 - exposure; | ||
672 | |||
673 | reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ | ||
674 | reg_w(gspca_dev, 0x02, clockdiv); | ||
675 | reg_w(gspca_dev, 0x0e, exposure & 0xff); | ||
676 | reg_w(gspca_dev, 0x0f, exposure >> 8); | ||
704 | 677 | ||
705 | /* load registers to sensor (Bit 0, auto clear) */ | 678 | /* load registers to sensor (Bit 0, auto clear) */ |
706 | if (0 <= ret) | 679 | reg_w(gspca_dev, 0x11, 0x01); |
707 | ret = reg_w(gspca_dev, 0x11, 0x01); | ||
708 | return ret; | ||
709 | } | 680 | } |
710 | 681 | ||
711 | static int sethvflip(struct gspca_dev *gspca_dev) | 682 | static void sethvflip(struct gspca_dev *gspca_dev) |
712 | { | 683 | { |
713 | struct sd *sd = (struct sd *) gspca_dev; | 684 | struct sd *sd = (struct sd *) gspca_dev; |
714 | int ret; | ||
715 | u8 data, hflip, vflip; | 685 | u8 data, hflip, vflip; |
716 | 686 | ||
717 | hflip = sd->hflip; | 687 | hflip = sd->hflip; |
@@ -721,48 +691,37 @@ static int sethvflip(struct gspca_dev *gspca_dev) | |||
721 | if (sd->flags & FL_VFLIP) | 691 | if (sd->flags & FL_VFLIP) |
722 | vflip = !vflip; | 692 | vflip = !vflip; |
723 | 693 | ||
724 | ret = reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ | 694 | reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ |
725 | data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00); | 695 | data = (hflip ? 0x08 : 0x00) | (vflip ? 0x04 : 0x00); |
726 | if (0 <= ret) | 696 | reg_w(gspca_dev, 0x21, data); |
727 | ret = reg_w(gspca_dev, 0x21, data); | 697 | |
728 | /* load registers to sensor (Bit 0, auto clear) */ | 698 | /* load registers to sensor (Bit 0, auto clear) */ |
729 | if (0 <= ret) | 699 | reg_w(gspca_dev, 0x11, 0x01); |
730 | ret = reg_w(gspca_dev, 0x11, 0x01); | ||
731 | return ret; | ||
732 | } | 700 | } |
733 | 701 | ||
734 | /* this function is called at probe and resume time for pac7302 */ | 702 | /* this function is called at probe and resume time for pac7302 */ |
735 | static int sd_init(struct gspca_dev *gspca_dev) | 703 | static int sd_init(struct gspca_dev *gspca_dev) |
736 | { | 704 | { |
737 | return reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2); | 705 | reg_w_seq(gspca_dev, init_7302, sizeof(init_7302)/2); |
706 | return gspca_dev->usb_err; | ||
738 | } | 707 | } |
739 | 708 | ||
740 | static int sd_start(struct gspca_dev *gspca_dev) | 709 | static int sd_start(struct gspca_dev *gspca_dev) |
741 | { | 710 | { |
742 | struct sd *sd = (struct sd *) gspca_dev; | 711 | struct sd *sd = (struct sd *) gspca_dev; |
743 | int ret = 0; | ||
744 | 712 | ||
745 | sd->sof_read = 0; | 713 | sd->sof_read = 0; |
746 | 714 | ||
747 | ret = reg_w_var(gspca_dev, start_7302, | 715 | reg_w_var(gspca_dev, start_7302, |
748 | page3_7302, sizeof(page3_7302), | 716 | page3_7302, sizeof(page3_7302)); |
749 | NULL, 0); | 717 | setbrightcont(gspca_dev); |
750 | if (0 <= ret) | 718 | setcolors(gspca_dev); |
751 | ret = setbrightcont(gspca_dev); | 719 | setwhitebalance(gspca_dev); |
752 | if (0 <= ret) | 720 | setredbalance(gspca_dev); |
753 | ret = setcolors(gspca_dev); | 721 | setbluebalance(gspca_dev); |
754 | if (0 <= ret) | 722 | setgain(gspca_dev); |
755 | ret = setwhitebalance(gspca_dev); | 723 | setexposure(gspca_dev); |
756 | if (0 <= ret) | 724 | sethvflip(gspca_dev); |
757 | ret = setredbalance(gspca_dev); | ||
758 | if (0 <= ret) | ||
759 | ret = setbluebalance(gspca_dev); | ||
760 | if (0 <= ret) | ||
761 | ret = setgain(gspca_dev); | ||
762 | if (0 <= ret) | ||
763 | ret = setexposure(gspca_dev); | ||
764 | if (0 <= ret) | ||
765 | ret = sethvflip(gspca_dev); | ||
766 | 725 | ||
767 | /* only resolution 640x480 is supported for pac7302 */ | 726 | /* only resolution 640x480 is supported for pac7302 */ |
768 | 727 | ||
@@ -771,34 +730,27 @@ static int sd_start(struct gspca_dev *gspca_dev) | |||
771 | atomic_set(&sd->avg_lum, -1); | 730 | atomic_set(&sd->avg_lum, -1); |
772 | 731 | ||
773 | /* start stream */ | 732 | /* start stream */ |
774 | if (0 <= ret) | 733 | reg_w(gspca_dev, 0xff, 0x01); |
775 | ret = reg_w(gspca_dev, 0xff, 0x01); | 734 | reg_w(gspca_dev, 0x78, 0x01); |
776 | if (0 <= ret) | ||
777 | ret = reg_w(gspca_dev, 0x78, 0x01); | ||
778 | 735 | ||
779 | return ret; | 736 | return gspca_dev->usb_err; |
780 | } | 737 | } |
781 | 738 | ||
782 | static void sd_stopN(struct gspca_dev *gspca_dev) | 739 | static void sd_stopN(struct gspca_dev *gspca_dev) |
783 | { | 740 | { |
784 | int ret; | ||
785 | 741 | ||
786 | /* stop stream */ | 742 | /* stop stream */ |
787 | ret = reg_w(gspca_dev, 0xff, 0x01); | 743 | reg_w(gspca_dev, 0xff, 0x01); |
788 | if (0 <= ret) | 744 | reg_w(gspca_dev, 0x78, 0x00); |
789 | ret = reg_w(gspca_dev, 0x78, 0x00); | ||
790 | } | 745 | } |
791 | 746 | ||
792 | /* called on streamoff with alt 0 and on disconnect for pac7302 */ | 747 | /* called on streamoff with alt 0 and on disconnect for pac7302 */ |
793 | static void sd_stop0(struct gspca_dev *gspca_dev) | 748 | static void sd_stop0(struct gspca_dev *gspca_dev) |
794 | { | 749 | { |
795 | int ret; | ||
796 | |||
797 | if (!gspca_dev->present) | 750 | if (!gspca_dev->present) |
798 | return; | 751 | return; |
799 | ret = reg_w(gspca_dev, 0xff, 0x01); | 752 | reg_w(gspca_dev, 0xff, 0x01); |
800 | if (0 <= ret) | 753 | reg_w(gspca_dev, 0x78, 0x40); |
801 | ret = reg_w(gspca_dev, 0x78, 0x40); | ||
802 | } | 754 | } |
803 | 755 | ||
804 | /* Include pac common sof detection functions */ | 756 | /* Include pac common sof detection functions */ |
@@ -808,22 +760,13 @@ static void do_autogain(struct gspca_dev *gspca_dev) | |||
808 | { | 760 | { |
809 | struct sd *sd = (struct sd *) gspca_dev; | 761 | struct sd *sd = (struct sd *) gspca_dev; |
810 | int avg_lum = atomic_read(&sd->avg_lum); | 762 | int avg_lum = atomic_read(&sd->avg_lum); |
811 | int desired_lum, deadzone; | 763 | int desired_lum; |
764 | const int deadzone = 30; | ||
812 | 765 | ||
813 | if (avg_lum == -1) | 766 | if (avg_lum == -1) |
814 | return; | 767 | return; |
815 | 768 | ||
816 | desired_lum = 270 + sd->brightness * 4; | 769 | desired_lum = 270 + sd->brightness; |
817 | /* Hack hack, with the 7202 the first exposure step is | ||
818 | pretty large, so if we're about to make the first | ||
819 | exposure increase make the deadzone large to avoid | ||
820 | oscilating */ | ||
821 | if (desired_lum > avg_lum && sd->gain == GAIN_DEF && | ||
822 | sd->exposure > EXPOSURE_DEF && | ||
823 | sd->exposure < 42) | ||
824 | deadzone = 90; | ||
825 | else | ||
826 | deadzone = 30; | ||
827 | 770 | ||
828 | if (sd->autogain_ignore_frames > 0) | 771 | if (sd->autogain_ignore_frames > 0) |
829 | sd->autogain_ignore_frames--; | 772 | sd->autogain_ignore_frames--; |
@@ -947,7 +890,7 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) | |||
947 | sd->brightness = val; | 890 | sd->brightness = val; |
948 | if (gspca_dev->streaming) | 891 | if (gspca_dev->streaming) |
949 | setbrightcont(gspca_dev); | 892 | setbrightcont(gspca_dev); |
950 | return 0; | 893 | return gspca_dev->usb_err; |
951 | } | 894 | } |
952 | 895 | ||
953 | static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) | 896 | static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) |
@@ -966,7 +909,7 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) | |||
966 | if (gspca_dev->streaming) { | 909 | if (gspca_dev->streaming) { |
967 | setbrightcont(gspca_dev); | 910 | setbrightcont(gspca_dev); |
968 | } | 911 | } |
969 | return 0; | 912 | return gspca_dev->usb_err; |
970 | } | 913 | } |
971 | 914 | ||
972 | static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) | 915 | static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) |
@@ -984,7 +927,7 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val) | |||
984 | sd->colors = val; | 927 | sd->colors = val; |
985 | if (gspca_dev->streaming) | 928 | if (gspca_dev->streaming) |
986 | setcolors(gspca_dev); | 929 | setcolors(gspca_dev); |
987 | return 0; | 930 | return gspca_dev->usb_err; |
988 | } | 931 | } |
989 | 932 | ||
990 | static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) | 933 | static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) |
@@ -998,14 +941,11 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) | |||
998 | static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val) | 941 | static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val) |
999 | { | 942 | { |
1000 | struct sd *sd = (struct sd *) gspca_dev; | 943 | struct sd *sd = (struct sd *) gspca_dev; |
1001 | int ret = 0; | ||
1002 | 944 | ||
1003 | sd->white_balance = val; | 945 | sd->white_balance = val; |
1004 | if (gspca_dev->streaming) | 946 | if (gspca_dev->streaming) |
1005 | ret = setwhitebalance(gspca_dev); | 947 | setwhitebalance(gspca_dev); |
1006 | if (0 <= ret) | 948 | return gspca_dev->usb_err; |
1007 | ret = 0; | ||
1008 | return ret; | ||
1009 | } | 949 | } |
1010 | 950 | ||
1011 | static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val) | 951 | static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val) |
@@ -1019,14 +959,11 @@ static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val) | |||
1019 | static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val) | 959 | static int sd_setredbalance(struct gspca_dev *gspca_dev, __s32 val) |
1020 | { | 960 | { |
1021 | struct sd *sd = (struct sd *) gspca_dev; | 961 | struct sd *sd = (struct sd *) gspca_dev; |
1022 | int ret = 0; | ||
1023 | 962 | ||
1024 | sd->red_balance = val; | 963 | sd->red_balance = val; |
1025 | if (gspca_dev->streaming) | 964 | if (gspca_dev->streaming) |
1026 | ret = setredbalance(gspca_dev); | 965 | setredbalance(gspca_dev); |
1027 | if (0 <= ret) | 966 | return gspca_dev->usb_err; |
1028 | ret = 0; | ||
1029 | return ret; | ||
1030 | } | 967 | } |
1031 | 968 | ||
1032 | static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val) | 969 | static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val) |
@@ -1040,14 +977,11 @@ static int sd_getredbalance(struct gspca_dev *gspca_dev, __s32 *val) | |||
1040 | static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val) | 977 | static int sd_setbluebalance(struct gspca_dev *gspca_dev, __s32 val) |
1041 | { | 978 | { |
1042 | struct sd *sd = (struct sd *) gspca_dev; | 979 | struct sd *sd = (struct sd *) gspca_dev; |
1043 | int ret = 0; | ||
1044 | 980 | ||
1045 | sd->blue_balance = val; | 981 | sd->blue_balance = val; |
1046 | if (gspca_dev->streaming) | 982 | if (gspca_dev->streaming) |
1047 | ret = setbluebalance(gspca_dev); | 983 | setbluebalance(gspca_dev); |
1048 | if (0 <= ret) | 984 | return gspca_dev->usb_err; |
1049 | ret = 0; | ||
1050 | return ret; | ||
1051 | } | 985 | } |
1052 | 986 | ||
1053 | static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val) | 987 | static int sd_getbluebalance(struct gspca_dev *gspca_dev, __s32 *val) |
@@ -1065,7 +999,7 @@ static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) | |||
1065 | sd->gain = val; | 999 | sd->gain = val; |
1066 | if (gspca_dev->streaming) | 1000 | if (gspca_dev->streaming) |
1067 | setgain(gspca_dev); | 1001 | setgain(gspca_dev); |
1068 | return 0; | 1002 | return gspca_dev->usb_err; |
1069 | } | 1003 | } |
1070 | 1004 | ||
1071 | static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) | 1005 | static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) |
@@ -1083,7 +1017,7 @@ static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) | |||
1083 | sd->exposure = val; | 1017 | sd->exposure = val; |
1084 | if (gspca_dev->streaming) | 1018 | if (gspca_dev->streaming) |
1085 | setexposure(gspca_dev); | 1019 | setexposure(gspca_dev); |
1086 | return 0; | 1020 | return gspca_dev->usb_err; |
1087 | } | 1021 | } |
1088 | 1022 | ||
1089 | static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) | 1023 | static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) |
@@ -1114,7 +1048,7 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) | |||
1114 | } | 1048 | } |
1115 | } | 1049 | } |
1116 | 1050 | ||
1117 | return 0; | 1051 | return gspca_dev->usb_err; |
1118 | } | 1052 | } |
1119 | 1053 | ||
1120 | static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) | 1054 | static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val) |
@@ -1132,7 +1066,7 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val) | |||
1132 | sd->hflip = val; | 1066 | sd->hflip = val; |
1133 | if (gspca_dev->streaming) | 1067 | if (gspca_dev->streaming) |
1134 | sethvflip(gspca_dev); | 1068 | sethvflip(gspca_dev); |
1135 | return 0; | 1069 | return gspca_dev->usb_err; |
1136 | } | 1070 | } |
1137 | 1071 | ||
1138 | static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) | 1072 | static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val) |
@@ -1150,7 +1084,7 @@ static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val) | |||
1150 | sd->vflip = val; | 1084 | sd->vflip = val; |
1151 | if (gspca_dev->streaming) | 1085 | if (gspca_dev->streaming) |
1152 | sethvflip(gspca_dev); | 1086 | sethvflip(gspca_dev); |
1153 | return 0; | 1087 | return gspca_dev->usb_err; |
1154 | } | 1088 | } |
1155 | 1089 | ||
1156 | static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) | 1090 | static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) |
@@ -1165,7 +1099,6 @@ static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val) | |||
1165 | static int sd_dbg_s_register(struct gspca_dev *gspca_dev, | 1099 | static int sd_dbg_s_register(struct gspca_dev *gspca_dev, |
1166 | struct v4l2_dbg_register *reg) | 1100 | struct v4l2_dbg_register *reg) |
1167 | { | 1101 | { |
1168 | int ret = -EINVAL; | ||
1169 | __u8 index; | 1102 | __u8 index; |
1170 | __u8 value; | 1103 | __u8 value; |
1171 | 1104 | ||
@@ -1185,14 +1118,12 @@ static int sd_dbg_s_register(struct gspca_dev *gspca_dev, | |||
1185 | /* Note that there shall be no access to other page | 1118 | /* Note that there shall be no access to other page |
1186 | by any other function between the page swith and | 1119 | by any other function between the page swith and |
1187 | the actual register write */ | 1120 | the actual register write */ |
1188 | ret = reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ | 1121 | reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ |
1189 | if (0 <= ret) | 1122 | reg_w(gspca_dev, index, value); |
1190 | ret = reg_w(gspca_dev, index, value); | ||
1191 | 1123 | ||
1192 | if (0 <= ret) | 1124 | reg_w(gspca_dev, 0xdc, 0x01); |
1193 | ret = reg_w(gspca_dev, 0xdc, 0x01); | ||
1194 | } | 1125 | } |
1195 | return ret; | 1126 | return gspca_dev->usb_err; |
1196 | } | 1127 | } |
1197 | 1128 | ||
1198 | static int sd_chip_ident(struct gspca_dev *gspca_dev, | 1129 | static int sd_chip_ident(struct gspca_dev *gspca_dev, |
@@ -1210,8 +1141,39 @@ static int sd_chip_ident(struct gspca_dev *gspca_dev, | |||
1210 | } | 1141 | } |
1211 | #endif | 1142 | #endif |
1212 | 1143 | ||
1144 | #ifdef CONFIG_INPUT | ||
1145 | static int sd_int_pkt_scan(struct gspca_dev *gspca_dev, | ||
1146 | u8 *data, /* interrupt packet data */ | ||
1147 | int len) /* interrput packet length */ | ||
1148 | { | ||
1149 | int ret = -EINVAL; | ||
1150 | u8 data0, data1; | ||
1151 | |||
1152 | if (len == 2) { | ||
1153 | data0 = data[0]; | ||
1154 | data1 = data[1]; | ||
1155 | if ((data0 == 0x00 && data1 == 0x11) || | ||
1156 | (data0 == 0x22 && data1 == 0x33) || | ||
1157 | (data0 == 0x44 && data1 == 0x55) || | ||
1158 | (data0 == 0x66 && data1 == 0x77) || | ||
1159 | (data0 == 0x88 && data1 == 0x99) || | ||
1160 | (data0 == 0xaa && data1 == 0xbb) || | ||
1161 | (data0 == 0xcc && data1 == 0xdd) || | ||
1162 | (data0 == 0xee && data1 == 0xff)) { | ||
1163 | input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1); | ||
1164 | input_sync(gspca_dev->input_dev); | ||
1165 | input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0); | ||
1166 | input_sync(gspca_dev->input_dev); | ||
1167 | ret = 0; | ||
1168 | } | ||
1169 | } | ||
1170 | |||
1171 | return ret; | ||
1172 | } | ||
1173 | #endif | ||
1174 | |||
1213 | /* sub-driver description for pac7302 */ | 1175 | /* sub-driver description for pac7302 */ |
1214 | static struct sd_desc sd_desc = { | 1176 | static const struct sd_desc sd_desc = { |
1215 | .name = MODULE_NAME, | 1177 | .name = MODULE_NAME, |
1216 | .ctrls = sd_ctrls, | 1178 | .ctrls = sd_ctrls, |
1217 | .nctrls = ARRAY_SIZE(sd_ctrls), | 1179 | .nctrls = ARRAY_SIZE(sd_ctrls), |
@@ -1226,6 +1188,9 @@ static struct sd_desc sd_desc = { | |||
1226 | .set_register = sd_dbg_s_register, | 1188 | .set_register = sd_dbg_s_register, |
1227 | .get_chip_ident = sd_chip_ident, | 1189 | .get_chip_ident = sd_chip_ident, |
1228 | #endif | 1190 | #endif |
1191 | #ifdef CONFIG_INPUT | ||
1192 | .int_pkt_scan = sd_int_pkt_scan, | ||
1193 | #endif | ||
1229 | }; | 1194 | }; |
1230 | 1195 | ||
1231 | /* -- module initialisation -- */ | 1196 | /* -- module initialisation -- */ |