diff options
author | Hans de Goede <j.w.r.degoede@hhs.nl> | 2008-09-03 16:12:17 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-09-03 17:37:38 -0400 |
commit | 8a5b2e909d56a1d5edec5e8f8848e03aafbc588e (patch) | |
tree | 3be1a890f11988cc75a1883bc9e2bc25bb0283ef | |
parent | a1e8288b1d80130119692818b46694660f28e03a (diff) |
V4L/DVB (8825): gspca: More controls for pac73xx and new webcam 093a:2624.
-Add usb id for 093a:2624 (pac7302)
-Report some controls to userspace with 7302 only, as they are 7302 only
-Add gain and exposure controls
-Add autogain
-Fix 7302 imaged being mirrored by default
Signed-off-by: Hans de Goede <j.w.r.degoede@hhs.nl>
Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | Documentation/video4linux/gspca.txt | 1 | ||||
-rw-r--r-- | drivers/media/video/gspca/pac207.c | 16 | ||||
-rw-r--r-- | drivers/media/video/gspca/pac7311.c | 301 | ||||
-rw-r--r-- | drivers/media/video/gspca/pac_common.h | 9 |
4 files changed, 232 insertions, 95 deletions
diff --git a/Documentation/video4linux/gspca.txt b/Documentation/video4linux/gspca.txt index 2dd2f774dd8e..c503467da25a 100644 --- a/Documentation/video4linux/gspca.txt +++ b/Documentation/video4linux/gspca.txt | |||
@@ -188,6 +188,7 @@ pac7311 093a:2608 Trust WB-3300p | |||
188 | pac7311 093a:260e Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350 | 188 | pac7311 093a:260e Gigaware VGA PC Camera, Trust WB-3350p, SIGMA cam 2350 |
189 | pac7311 093a:260f SnakeCam | 189 | pac7311 093a:260f SnakeCam |
190 | pac7311 093a:2621 PAC731x | 190 | pac7311 093a:2621 PAC731x |
191 | pac7311 093a:2624 PAC7302 | ||
191 | zc3xx 0ac8:0302 Z-star Vimicro zc0302 | 192 | zc3xx 0ac8:0302 Z-star Vimicro zc0302 |
192 | vc032x 0ac8:0321 Vimicro generic vc0321 | 193 | vc032x 0ac8:0321 Vimicro generic vc0321 |
193 | vc032x 0ac8:0323 Vimicro Vc0323 | 194 | vc032x 0ac8:0323 Vimicro Vc0323 |
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c index a15bccad947b..83b5f740c947 100644 --- a/drivers/media/video/gspca/pac207.c +++ b/drivers/media/video/gspca/pac207.c | |||
@@ -56,12 +56,6 @@ MODULE_LICENSE("GPL"); | |||
56 | #define PAC207_GAIN_KNEE 20 | 56 | #define PAC207_GAIN_KNEE 20 |
57 | 57 | ||
58 | #define PAC207_AUTOGAIN_DEADZONE 30 | 58 | #define PAC207_AUTOGAIN_DEADZONE 30 |
59 | /* We calculating the autogain at the end of the transfer of a frame, at this | ||
60 | moment a frame with the old settings is being transmitted, and a frame is | ||
61 | being captured with the old settings. So if we adjust the autogain we must | ||
62 | ignore atleast the 2 next frames for the new settings to come into effect | ||
63 | before doing any other adjustments */ | ||
64 | #define PAC207_AUTOGAIN_IGNORE_FRAMES 3 | ||
65 | 59 | ||
66 | /* specific webcam descriptor */ | 60 | /* specific webcam descriptor */ |
67 | struct sd { | 61 | struct sd { |
@@ -338,6 +332,9 @@ static void sd_stopN(struct gspca_dev *gspca_dev) | |||
338 | pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ | 332 | pac207_write_reg(gspca_dev, 0x0f, 0x00); /* Power Control */ |
339 | } | 333 | } |
340 | 334 | ||
335 | /* Include pac common sof detection functions */ | ||
336 | #include "pac_common.h" | ||
337 | |||
341 | static void pac207_do_auto_gain(struct gspca_dev *gspca_dev) | 338 | static void pac207_do_auto_gain(struct gspca_dev *gspca_dev) |
342 | { | 339 | { |
343 | struct sd *sd = (struct sd *) gspca_dev; | 340 | struct sd *sd = (struct sd *) gspca_dev; |
@@ -351,12 +348,9 @@ static void pac207_do_auto_gain(struct gspca_dev *gspca_dev) | |||
351 | else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, | 348 | else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, |
352 | 100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE, | 349 | 100 + sd->brightness / 2, PAC207_AUTOGAIN_DEADZONE, |
353 | PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE)) | 350 | PAC207_GAIN_KNEE, PAC207_EXPOSURE_KNEE)) |
354 | sd->autogain_ignore_frames = PAC207_AUTOGAIN_IGNORE_FRAMES; | 351 | sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; |
355 | } | 352 | } |
356 | 353 | ||
357 | /* Include pac common sof detection functions */ | ||
358 | #include "pac_common.h" | ||
359 | |||
360 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | 354 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, |
361 | struct gspca_frame *frame, | 355 | struct gspca_frame *frame, |
362 | __u8 *data, | 356 | __u8 *data, |
@@ -500,7 +494,7 @@ static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) | |||
500 | sd->gain = PAC207_GAIN_DEFAULT; | 494 | sd->gain = PAC207_GAIN_DEFAULT; |
501 | if (gspca_dev->streaming) { | 495 | if (gspca_dev->streaming) { |
502 | sd->autogain_ignore_frames = | 496 | sd->autogain_ignore_frames = |
503 | PAC207_AUTOGAIN_IGNORE_FRAMES; | 497 | PAC_AUTOGAIN_IGNORE_FRAMES; |
504 | setexposure(gspca_dev); | 498 | setexposure(gspca_dev); |
505 | setgain(gspca_dev); | 499 | setgain(gspca_dev); |
506 | } | 500 | } |
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c index e22ca610334f..14b98111cd9d 100644 --- a/drivers/media/video/gspca/pac7311.c +++ b/drivers/media/video/gspca/pac7311.c | |||
@@ -44,6 +44,9 @@ | |||
44 | 0x10/- Master gain 0-31 | 44 | 0x10/- Master gain 0-31 |
45 | -/0x10 Another gain 0-15, limited influence (1-2x gain I guess) | 45 | -/0x10 Another gain 0-15, limited influence (1-2x gain I guess) |
46 | 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 |
47 | -/0x27 Seems to toggle various gains on / off, Setting bit 7 seems to | ||
48 | completely disable the analog amplification block. Set to 0x68 | ||
49 | for max gain, 0x14 for minimal gain. | ||
47 | */ | 50 | */ |
48 | 51 | ||
49 | #define MODULE_NAME "pac7311" | 52 | #define MODULE_NAME "pac7311" |
@@ -61,6 +64,8 @@ struct sd { | |||
61 | unsigned char brightness; | 64 | unsigned char brightness; |
62 | unsigned char contrast; | 65 | unsigned char contrast; |
63 | unsigned char colors; | 66 | unsigned char colors; |
67 | unsigned char gain; | ||
68 | unsigned char exposure; | ||
64 | unsigned char autogain; | 69 | unsigned char autogain; |
65 | __u8 hflip; | 70 | __u8 hflip; |
66 | __u8 vflip; | 71 | __u8 vflip; |
@@ -88,8 +93,14 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val); | |||
88 | static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); | 93 | static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val); |
89 | static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); | 94 | static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val); |
90 | static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); | 95 | static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val); |
96 | static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); | ||
97 | static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); | ||
98 | static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); | ||
99 | static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); | ||
91 | 100 | ||
92 | static struct ctrl sd_ctrls[] = { | 101 | static struct ctrl sd_ctrls[] = { |
102 | /* This control is pac7302 only */ | ||
103 | #define BRIGHTNESS_IDX 0 | ||
93 | { | 104 | { |
94 | { | 105 | { |
95 | .id = V4L2_CID_BRIGHTNESS, | 106 | .id = V4L2_CID_BRIGHTNESS, |
@@ -105,6 +116,7 @@ static struct ctrl sd_ctrls[] = { | |||
105 | .set = sd_setbrightness, | 116 | .set = sd_setbrightness, |
106 | .get = sd_getbrightness, | 117 | .get = sd_getbrightness, |
107 | }, | 118 | }, |
119 | /* This control is for both the 7302 and the 7311 */ | ||
108 | { | 120 | { |
109 | { | 121 | { |
110 | .id = V4L2_CID_CONTRAST, | 122 | .id = V4L2_CID_CONTRAST, |
@@ -120,6 +132,8 @@ static struct ctrl sd_ctrls[] = { | |||
120 | .set = sd_setcontrast, | 132 | .set = sd_setcontrast, |
121 | .get = sd_getcontrast, | 133 | .get = sd_getcontrast, |
122 | }, | 134 | }, |
135 | /* This control is pac7302 only */ | ||
136 | #define SATURATION_IDX 2 | ||
123 | { | 137 | { |
124 | { | 138 | { |
125 | .id = V4L2_CID_SATURATION, | 139 | .id = V4L2_CID_SATURATION, |
@@ -135,6 +149,39 @@ static struct ctrl sd_ctrls[] = { | |||
135 | .set = sd_setcolors, | 149 | .set = sd_setcolors, |
136 | .get = sd_getcolors, | 150 | .get = sd_getcolors, |
137 | }, | 151 | }, |
152 | /* All controls below are for both the 7302 and the 7311 */ | ||
153 | { | ||
154 | { | ||
155 | .id = V4L2_CID_GAIN, | ||
156 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
157 | .name = "Gain", | ||
158 | .minimum = 0, | ||
159 | #define GAIN_MAX 255 | ||
160 | .maximum = GAIN_MAX, | ||
161 | .step = 1, | ||
162 | #define GAIN_DEF 127 | ||
163 | #define GAIN_KNEE 255 /* Gain seems to cause little noise on the pac73xx */ | ||
164 | .default_value = GAIN_DEF, | ||
165 | }, | ||
166 | .set = sd_setgain, | ||
167 | .get = sd_getgain, | ||
168 | }, | ||
169 | { | ||
170 | { | ||
171 | .id = V4L2_CID_EXPOSURE, | ||
172 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
173 | .name = "Exposure", | ||
174 | .minimum = 0, | ||
175 | #define EXPOSURE_MAX 255 | ||
176 | .maximum = EXPOSURE_MAX, | ||
177 | .step = 1, | ||
178 | #define EXPOSURE_DEF 16 /* 32 ms / 30 fps */ | ||
179 | #define EXPOSURE_KNEE 50 /* 100 ms / 10 fps */ | ||
180 | .default_value = EXPOSURE_DEF, | ||
181 | }, | ||
182 | .set = sd_setexposure, | ||
183 | .get = sd_getexposure, | ||
184 | }, | ||
138 | { | 185 | { |
139 | { | 186 | { |
140 | .id = V4L2_CID_AUTOGAIN, | 187 | .id = V4L2_CID_AUTOGAIN, |
@@ -149,8 +196,6 @@ static struct ctrl sd_ctrls[] = { | |||
149 | .set = sd_setautogain, | 196 | .set = sd_setautogain, |
150 | .get = sd_getautogain, | 197 | .get = sd_getautogain, |
151 | }, | 198 | }, |
152 | /* next controls work with pac7302 only */ | ||
153 | #define HFLIP_IDX 4 | ||
154 | { | 199 | { |
155 | { | 200 | { |
156 | .id = V4L2_CID_HFLIP, | 201 | .id = V4L2_CID_HFLIP, |
@@ -165,7 +210,6 @@ static struct ctrl sd_ctrls[] = { | |||
165 | .set = sd_sethflip, | 210 | .set = sd_sethflip, |
166 | .get = sd_gethflip, | 211 | .get = sd_gethflip, |
167 | }, | 212 | }, |
168 | #define VFLIP_IDX 5 | ||
169 | { | 213 | { |
170 | { | 214 | { |
171 | .id = V4L2_CID_VFLIP, | 215 | .id = V4L2_CID_VFLIP, |
@@ -345,7 +389,7 @@ static const __u8 page4_7311[] = { | |||
345 | 0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62, | 389 | 0x09, 0x00, 0xaa, 0xaa, 0x07, 0x00, 0x00, 0x62, |
346 | 0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, | 390 | 0x08, 0xaa, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, |
347 | 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa, | 391 | 0x00, 0x00, 0x00, 0x03, 0xa0, 0x01, 0xf4, 0xaa, |
348 | 0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x01, | 392 | 0xaa, 0x00, 0x08, 0xaa, 0x03, 0xaa, 0x00, 0x68, |
349 | 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00, | 393 | 0xca, 0x10, 0x06, 0x78, 0x00, 0x00, 0x00, 0x00, |
350 | 0x23, 0x28, 0x04, 0x11, 0x00, 0x00 | 394 | 0x23, 0x28, 0x04, 0x11, 0x00, 0x00 |
351 | }; | 395 | }; |
@@ -374,7 +418,7 @@ static void reg_w(struct gspca_dev *gspca_dev, | |||
374 | usb_sndctrlpipe(gspca_dev->dev, 0), | 418 | usb_sndctrlpipe(gspca_dev->dev, 0), |
375 | 0, /* request */ | 419 | 0, /* request */ |
376 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | 420 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
377 | value, index, gspca_dev->usb_buf, 1, | 421 | 0, index, gspca_dev->usb_buf, 1, |
378 | 500); | 422 | 500); |
379 | } | 423 | } |
380 | 424 | ||
@@ -469,20 +513,22 @@ static int sd_config(struct gspca_dev *gspca_dev, | |||
469 | 513 | ||
470 | cam->cam_mode = vga_mode; | 514 | cam->cam_mode = vga_mode; |
471 | cam->nmodes = ARRAY_SIZE(vga_mode); | 515 | cam->nmodes = ARRAY_SIZE(vga_mode); |
472 | gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | 516 | gspca_dev->ctrl_dis = (1 << BRIGHTNESS_IDX) |
473 | | (1 << VFLIP_IDX); | 517 | | (1 << SATURATION_IDX); |
474 | } | 518 | } |
475 | 519 | ||
476 | sd->brightness = BRIGHTNESS_DEF; | 520 | sd->brightness = BRIGHTNESS_DEF; |
477 | sd->contrast = CONTRAST_DEF; | 521 | sd->contrast = CONTRAST_DEF; |
478 | sd->colors = COLOR_DEF; | 522 | sd->colors = COLOR_DEF; |
523 | sd->gain = GAIN_DEF; | ||
524 | sd->exposure = EXPOSURE_DEF; | ||
479 | sd->autogain = AUTOGAIN_DEF; | 525 | sd->autogain = AUTOGAIN_DEF; |
480 | sd->hflip = HFLIP_DEF; | 526 | sd->hflip = HFLIP_DEF; |
481 | sd->vflip = VFLIP_DEF; | 527 | sd->vflip = VFLIP_DEF; |
482 | return 0; | 528 | return 0; |
483 | } | 529 | } |
484 | 530 | ||
485 | /* rev 12a only */ | 531 | /* This function is used by pac7302 only */ |
486 | static void setbrightcont(struct gspca_dev *gspca_dev) | 532 | static void setbrightcont(struct gspca_dev *gspca_dev) |
487 | { | 533 | { |
488 | struct sd *sd = (struct sd *) gspca_dev; | 534 | struct sd *sd = (struct sd *) gspca_dev; |
@@ -509,67 +555,95 @@ static void setbrightcont(struct gspca_dev *gspca_dev) | |||
509 | reg_w(gspca_dev, 0xdc, 0x01); | 555 | reg_w(gspca_dev, 0xdc, 0x01); |
510 | } | 556 | } |
511 | 557 | ||
512 | /* This function is used by pac7302 only */ | 558 | /* This function is used by pac7311 only */ |
513 | static void setbrightness(struct gspca_dev *gspca_dev) | 559 | static void setcontrast(struct gspca_dev *gspca_dev) |
514 | { | 560 | { |
515 | struct sd *sd = (struct sd *) gspca_dev; | 561 | struct sd *sd = (struct sd *) gspca_dev; |
516 | int brightness; | ||
517 | |||
518 | if (sd->sensor == SENSOR_PAC7302) { | ||
519 | setbrightcont(gspca_dev); | ||
520 | return; | ||
521 | } | ||
522 | /* HDG: this is not brightness but gain, I'll add gain and exposure controls | ||
523 | in a next patch */ | ||
524 | return; | ||
525 | 562 | ||
526 | brightness = BRIGHTNESS_MAX - sd->brightness; | ||
527 | reg_w(gspca_dev, 0xff, 0x04); | 563 | reg_w(gspca_dev, 0xff, 0x04); |
528 | reg_w(gspca_dev, 0x0e, 0x00); | 564 | reg_w(gspca_dev, 0x10, sd->contrast >> 4); |
529 | reg_w(gspca_dev, 0x0f, brightness); | ||
530 | /* load registers to sensor (Bit 0, auto clear) */ | 565 | /* load registers to sensor (Bit 0, auto clear) */ |
531 | reg_w(gspca_dev, 0x11, 0x01); | 566 | reg_w(gspca_dev, 0x11, 0x01); |
532 | PDEBUG(D_CONF|D_STREAM, "brightness: %i", brightness); | ||
533 | } | 567 | } |
534 | 568 | ||
535 | static void setcontrast(struct gspca_dev *gspca_dev) | 569 | /* This function is used by pac7302 only */ |
570 | static void setcolors(struct gspca_dev *gspca_dev) | ||
571 | { | ||
572 | struct sd *sd = (struct sd *) gspca_dev; | ||
573 | int i, v; | ||
574 | static const int a[9] = | ||
575 | {217, -212, 0, -101, 170, -67, -38, -315, 355}; | ||
576 | static const int b[9] = | ||
577 | {19, 106, 0, 19, 106, 1, 19, 106, 1}; | ||
578 | |||
579 | reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ | ||
580 | reg_w(gspca_dev, 0x11, 0x01); | ||
581 | reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ | ||
582 | reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ | ||
583 | for (i = 0; i < 9; i++) { | ||
584 | v = a[i] * sd->colors / COLOR_MAX + b[i]; | ||
585 | reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07); | ||
586 | reg_w(gspca_dev, 0x0f + 2 * i + 1, v); | ||
587 | } | ||
588 | reg_w(gspca_dev, 0xdc, 0x01); | ||
589 | PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors); | ||
590 | } | ||
591 | |||
592 | static void setgain(struct gspca_dev *gspca_dev) | ||
536 | { | 593 | { |
537 | struct sd *sd = (struct sd *) gspca_dev; | 594 | struct sd *sd = (struct sd *) gspca_dev; |
538 | 595 | ||
539 | if (sd->sensor == SENSOR_PAC7302) { | 596 | if (sd->sensor == SENSOR_PAC7302) { |
540 | setbrightcont(gspca_dev); | 597 | reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ |
541 | return; | 598 | reg_w(gspca_dev, 0x10, sd->gain >> 3); |
599 | } else { | ||
600 | int gain = GAIN_MAX - sd->gain; | ||
601 | if (gain < 1) | ||
602 | gain = 1; | ||
603 | else if (gain > 245) | ||
604 | gain = 245; | ||
605 | reg_w(gspca_dev, 0xff, 0x04); /* page 4 */ | ||
606 | reg_w(gspca_dev, 0x0e, 0x00); | ||
607 | reg_w(gspca_dev, 0x0f, gain); | ||
542 | } | 608 | } |
543 | reg_w(gspca_dev, 0xff, 0x04); | ||
544 | reg_w(gspca_dev, 0x10, sd->contrast >> 4); | ||
545 | /* load registers to sensor (Bit 0, auto clear) */ | 609 | /* load registers to sensor (Bit 0, auto clear) */ |
546 | reg_w(gspca_dev, 0x11, 0x01); | 610 | reg_w(gspca_dev, 0x11, 0x01); |
547 | } | 611 | } |
548 | 612 | ||
549 | /* This function is used by pac7302 only */ | 613 | static void setexposure(struct gspca_dev *gspca_dev) |
550 | static void setcolors(struct gspca_dev *gspca_dev) | ||
551 | { | 614 | { |
552 | struct sd *sd = (struct sd *) gspca_dev; | 615 | struct sd *sd = (struct sd *) gspca_dev; |
616 | __u8 reg; | ||
617 | |||
618 | /* register 2 of frame 3/4 contains the clock divider configuring the | ||
619 | no fps according to the formula: 60 / reg. sd->exposure is the | ||
620 | desired exposure time in ms. */ | ||
621 | reg = 120 * sd->exposure / 1000; | ||
622 | if (reg < 2) | ||
623 | reg = 2; | ||
624 | else if (reg > 63) | ||
625 | reg = 63; | ||
553 | 626 | ||
554 | if (sd->sensor == SENSOR_PAC7302) { | 627 | if (sd->sensor == SENSOR_PAC7302) { |
555 | int i, v; | 628 | /* On the pac7302 reg2 MUST be a multiple of 3, so round it to |
556 | static const int a[9] = | 629 | the nearest multiple of 3 */ |
557 | {217, -212, 0, -101, 170, -67, -38, -315, 355}; | 630 | reg = ((reg + 1) / 3) * 3; |
558 | static const int b[9] = | 631 | reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ |
559 | {19, 106, 0, 19, 106, 1, 19, 106, 1}; | 632 | reg_w(gspca_dev, 0x02, reg); |
560 | 633 | } else { | |
561 | reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ | 634 | reg_w(gspca_dev, 0xff, 0x04); /* page 4 */ |
562 | reg_w(gspca_dev, 0x11, 0x01); | 635 | reg_w(gspca_dev, 0x02, reg); |
563 | reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ | 636 | /* Page 1 register 8 must always be 0x08 except when not in |
564 | reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ | 637 | 640x480 mode and Page3/4 reg 2 <= 3 then it must be 9 */ |
565 | for (i = 0; i < 9; i++) { | 638 | reg_w(gspca_dev, 0xff, 0x01); |
566 | v = a[i] * sd->colors / COLOR_MAX + b[i]; | 639 | if (gspca_dev->cam.cam_mode[(int)gspca_dev->curr_mode].priv && |
567 | reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07); | 640 | reg <= 3) |
568 | reg_w(gspca_dev, 0x0f + 2 * i + 1, v); | 641 | reg_w(gspca_dev, 0x08, 0x09); |
569 | } | 642 | else |
570 | reg_w(gspca_dev, 0xdc, 0x01); | 643 | reg_w(gspca_dev, 0x08, 0x08); |
571 | PDEBUG(D_CONF|D_STREAM, "color: %i", sd->colors); | ||
572 | } | 644 | } |
645 | /* load registers to sensor (Bit 0, auto clear) */ | ||
646 | reg_w(gspca_dev, 0x11, 0x01); | ||
573 | } | 647 | } |
574 | 648 | ||
575 | static void sethvflip(struct gspca_dev *gspca_dev) | 649 | static void sethvflip(struct gspca_dev *gspca_dev) |
@@ -579,14 +653,15 @@ static void sethvflip(struct gspca_dev *gspca_dev) | |||
579 | 653 | ||
580 | if (sd->sensor == SENSOR_PAC7302) { | 654 | if (sd->sensor == SENSOR_PAC7302) { |
581 | reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ | 655 | reg_w(gspca_dev, 0xff, 0x03); /* page 3 */ |
582 | data = (sd->hflip ? 0x00 : 0x08) | 656 | data = (sd->hflip ? 0x08 : 0x00) |
583 | | (sd->vflip ? 0x04 : 0x00); | 657 | | (sd->vflip ? 0x04 : 0x00); |
584 | } else { | 658 | } else { |
585 | reg_w(gspca_dev, 0xff, 0x04); /* page 3 */ | 659 | reg_w(gspca_dev, 0xff, 0x04); /* page 4 */ |
586 | data = (sd->hflip ? 0x04 : 0x00) | 660 | data = (sd->hflip ? 0x04 : 0x00) |
587 | | (sd->vflip ? 0x08 : 0x00); | 661 | | (sd->vflip ? 0x08 : 0x00); |
588 | } | 662 | } |
589 | reg_w(gspca_dev, 0x21, data); | 663 | reg_w(gspca_dev, 0x21, data); |
664 | /* load registers to sensor (Bit 0, auto clear) */ | ||
590 | reg_w(gspca_dev, 0x11, 0x01); | 665 | reg_w(gspca_dev, 0x11, 0x01); |
591 | } | 666 | } |
592 | 667 | ||
@@ -602,61 +677,49 @@ static void sd_start(struct gspca_dev *gspca_dev) | |||
602 | 677 | ||
603 | sd->sof_read = 0; | 678 | sd->sof_read = 0; |
604 | 679 | ||
605 | if (sd->sensor == SENSOR_PAC7302) | 680 | if (sd->sensor == SENSOR_PAC7302) { |
606 | reg_w_var(gspca_dev, start_7302); | 681 | reg_w_var(gspca_dev, start_7302); |
607 | else | 682 | setbrightcont(gspca_dev); |
683 | setcolors(gspca_dev); | ||
684 | } else { | ||
608 | reg_w_var(gspca_dev, start_7311); | 685 | reg_w_var(gspca_dev, start_7311); |
609 | 686 | setcontrast(gspca_dev); | |
610 | setcontrast(gspca_dev); | 687 | } |
611 | setbrightness(gspca_dev); | 688 | setgain(gspca_dev); |
612 | setcolors(gspca_dev); | 689 | setexposure(gspca_dev); |
690 | sethvflip(gspca_dev); | ||
613 | 691 | ||
614 | /* set correct resolution */ | 692 | /* set correct resolution */ |
615 | switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { | 693 | switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) { |
616 | case 2: /* 160x120 pac7311 */ | 694 | case 2: /* 160x120 pac7311 */ |
617 | reg_w(gspca_dev, 0xff, 0x04); | ||
618 | reg_w(gspca_dev, 0x02, 0x03); | ||
619 | reg_w(gspca_dev, 0xff, 0x01); | 695 | reg_w(gspca_dev, 0xff, 0x01); |
620 | reg_w(gspca_dev, 0x08, 0x09); | ||
621 | reg_w(gspca_dev, 0x17, 0x20); | 696 | reg_w(gspca_dev, 0x17, 0x20); |
622 | reg_w(gspca_dev, 0x1b, 0x00); | ||
623 | reg_w(gspca_dev, 0x87, 0x10); | 697 | reg_w(gspca_dev, 0x87, 0x10); |
624 | break; | 698 | break; |
625 | case 1: /* 320x240 pac7311 */ | 699 | case 1: /* 320x240 pac7311 */ |
626 | reg_w(gspca_dev, 0xff, 0x04); | ||
627 | reg_w(gspca_dev, 0x02, 0x03); | ||
628 | reg_w(gspca_dev, 0xff, 0x01); | 700 | reg_w(gspca_dev, 0xff, 0x01); |
629 | reg_w(gspca_dev, 0x08, 0x09); | ||
630 | reg_w(gspca_dev, 0x17, 0x30); | 701 | reg_w(gspca_dev, 0x17, 0x30); |
631 | reg_w(gspca_dev, 0x87, 0x11); | 702 | reg_w(gspca_dev, 0x87, 0x11); |
632 | break; | 703 | break; |
633 | case 0: /* 640x480 */ | 704 | case 0: /* 640x480 */ |
634 | if (sd->sensor == SENSOR_PAC7302) | 705 | if (sd->sensor == SENSOR_PAC7302) |
635 | break; | 706 | break; |
636 | reg_w(gspca_dev, 0xff, 0x04); | ||
637 | reg_w(gspca_dev, 0x02, 0x07); | ||
638 | reg_w(gspca_dev, 0xff, 0x01); | 707 | reg_w(gspca_dev, 0xff, 0x01); |
639 | reg_w(gspca_dev, 0x08, 0x08); | ||
640 | reg_w(gspca_dev, 0x17, 0x00); | 708 | reg_w(gspca_dev, 0x17, 0x00); |
641 | reg_w(gspca_dev, 0x87, 0x12); | 709 | reg_w(gspca_dev, 0x87, 0x12); |
642 | break; | 710 | break; |
643 | } | 711 | } |
644 | 712 | ||
645 | /* start stream */ | ||
646 | reg_w(gspca_dev, 0xff, 0x01); | ||
647 | if (sd->sensor == SENSOR_PAC7302) { | ||
648 | sethvflip(gspca_dev); | ||
649 | reg_w(gspca_dev, 0x78, 0x01); | ||
650 | reg_w(gspca_dev, 0xff, 0x01); | ||
651 | reg_w(gspca_dev, 0x78, 0x01); | ||
652 | } else { | ||
653 | reg_w(gspca_dev, 0x78, 0x44); | ||
654 | reg_w(gspca_dev, 0x78, 0x45); | ||
655 | } | ||
656 | |||
657 | sd->sof_read = 0; | 713 | sd->sof_read = 0; |
658 | sd->autogain_ignore_frames = 0; | 714 | sd->autogain_ignore_frames = 0; |
659 | atomic_set(&sd->avg_lum, -1); | 715 | atomic_set(&sd->avg_lum, -1); |
716 | |||
717 | /* start stream */ | ||
718 | reg_w(gspca_dev, 0xff, 0x01); | ||
719 | if (sd->sensor == SENSOR_PAC7302) | ||
720 | reg_w(gspca_dev, 0x78, 0x01); | ||
721 | else | ||
722 | reg_w(gspca_dev, 0x78, 0x05); | ||
660 | } | 723 | } |
661 | 724 | ||
662 | static void sd_stopN(struct gspca_dev *gspca_dev) | 725 | static void sd_stopN(struct gspca_dev *gspca_dev) |
@@ -691,8 +754,28 @@ static void sd_stop0(struct gspca_dev *gspca_dev) | |||
691 | } | 754 | } |
692 | } | 755 | } |
693 | 756 | ||
757 | /* Include pac common sof detection functions */ | ||
758 | #include "pac_common.h" | ||
759 | |||
694 | static void do_autogain(struct gspca_dev *gspca_dev) | 760 | static void do_autogain(struct gspca_dev *gspca_dev) |
695 | { | 761 | { |
762 | struct sd *sd = (struct sd *) gspca_dev; | ||
763 | int avg_lum = atomic_read(&sd->avg_lum); | ||
764 | int desired_lum; | ||
765 | |||
766 | if (avg_lum == -1) | ||
767 | return; | ||
768 | |||
769 | if (sd->sensor == SENSOR_PAC7302) | ||
770 | desired_lum = 70 + sd->brightness * 2; | ||
771 | else | ||
772 | desired_lum = 200; | ||
773 | |||
774 | if (sd->autogain_ignore_frames > 0) | ||
775 | sd->autogain_ignore_frames--; | ||
776 | else if (gspca_auto_gain_n_exposure(gspca_dev, avg_lum, desired_lum, | ||
777 | 10, GAIN_KNEE, EXPOSURE_KNEE)) | ||
778 | sd->autogain_ignore_frames = PAC_AUTOGAIN_IGNORE_FRAMES; | ||
696 | } | 779 | } |
697 | 780 | ||
698 | static const unsigned char pac7311_jpeg_header1[] = { | 781 | static const unsigned char pac7311_jpeg_header1[] = { |
@@ -704,9 +787,6 @@ static const unsigned char pac7311_jpeg_header2[] = { | |||
704 | 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00 | 787 | 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11, 0x00, 0x3f, 0x00 |
705 | }; | 788 | }; |
706 | 789 | ||
707 | /* Include pac common sof detection functions */ | ||
708 | #include "pac_common.h" | ||
709 | |||
710 | /* this function is run at interrupt level */ | 790 | /* this function is run at interrupt level */ |
711 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | 791 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, |
712 | struct gspca_frame *frame, /* target */ | 792 | struct gspca_frame *frame, /* target */ |
@@ -790,7 +870,7 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) | |||
790 | 870 | ||
791 | sd->brightness = val; | 871 | sd->brightness = val; |
792 | if (gspca_dev->streaming) | 872 | if (gspca_dev->streaming) |
793 | setbrightness(gspca_dev); | 873 | setbrightcont(gspca_dev); |
794 | return 0; | 874 | return 0; |
795 | } | 875 | } |
796 | 876 | ||
@@ -807,8 +887,12 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) | |||
807 | struct sd *sd = (struct sd *) gspca_dev; | 887 | struct sd *sd = (struct sd *) gspca_dev; |
808 | 888 | ||
809 | sd->contrast = val; | 889 | sd->contrast = val; |
810 | if (gspca_dev->streaming) | 890 | if (gspca_dev->streaming) { |
811 | setcontrast(gspca_dev); | 891 | if (sd->sensor == SENSOR_PAC7302) |
892 | setbrightcont(gspca_dev); | ||
893 | else | ||
894 | setcontrast(gspca_dev); | ||
895 | } | ||
812 | return 0; | 896 | return 0; |
813 | } | 897 | } |
814 | 898 | ||
@@ -838,11 +922,61 @@ static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val) | |||
838 | return 0; | 922 | return 0; |
839 | } | 923 | } |
840 | 924 | ||
925 | static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) | ||
926 | { | ||
927 | struct sd *sd = (struct sd *) gspca_dev; | ||
928 | |||
929 | sd->gain = val; | ||
930 | if (gspca_dev->streaming) | ||
931 | setgain(gspca_dev); | ||
932 | return 0; | ||
933 | } | ||
934 | |||
935 | static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) | ||
936 | { | ||
937 | struct sd *sd = (struct sd *) gspca_dev; | ||
938 | |||
939 | *val = sd->gain; | ||
940 | return 0; | ||
941 | } | ||
942 | |||
943 | static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) | ||
944 | { | ||
945 | struct sd *sd = (struct sd *) gspca_dev; | ||
946 | |||
947 | sd->exposure = val; | ||
948 | if (gspca_dev->streaming) | ||
949 | setexposure(gspca_dev); | ||
950 | return 0; | ||
951 | } | ||
952 | |||
953 | static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) | ||
954 | { | ||
955 | struct sd *sd = (struct sd *) gspca_dev; | ||
956 | |||
957 | *val = sd->exposure; | ||
958 | return 0; | ||
959 | } | ||
960 | |||
841 | static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) | 961 | static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val) |
842 | { | 962 | { |
843 | struct sd *sd = (struct sd *) gspca_dev; | 963 | struct sd *sd = (struct sd *) gspca_dev; |
844 | 964 | ||
845 | sd->autogain = val; | 965 | sd->autogain = val; |
966 | /* when switching to autogain set defaults to make sure | ||
967 | we are on a valid point of the autogain gain / | ||
968 | exposure knee graph, and give this change time to | ||
969 | take effect before doing autogain. */ | ||
970 | if (sd->autogain) { | ||
971 | sd->exposure = EXPOSURE_DEF; | ||
972 | sd->gain = GAIN_DEF; | ||
973 | if (gspca_dev->streaming) { | ||
974 | sd->autogain_ignore_frames = | ||
975 | PAC_AUTOGAIN_IGNORE_FRAMES; | ||
976 | setexposure(gspca_dev); | ||
977 | setgain(gspca_dev); | ||
978 | } | ||
979 | } | ||
846 | 980 | ||
847 | return 0; | 981 | return 0; |
848 | } | 982 | } |
@@ -914,6 +1048,7 @@ static __devinitdata struct usb_device_id device_table[] = { | |||
914 | {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311}, | 1048 | {USB_DEVICE(0x093a, 0x260e), .driver_info = SENSOR_PAC7311}, |
915 | {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311}, | 1049 | {USB_DEVICE(0x093a, 0x260f), .driver_info = SENSOR_PAC7311}, |
916 | {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302}, | 1050 | {USB_DEVICE(0x093a, 0x2621), .driver_info = SENSOR_PAC7302}, |
1051 | {USB_DEVICE(0x093a, 0x2624), .driver_info = SENSOR_PAC7302}, | ||
917 | {} | 1052 | {} |
918 | }; | 1053 | }; |
919 | MODULE_DEVICE_TABLE(usb, device_table); | 1054 | MODULE_DEVICE_TABLE(usb, device_table); |
diff --git a/drivers/media/video/gspca/pac_common.h b/drivers/media/video/gspca/pac_common.h index a19b5d44c009..34d4b1494cd5 100644 --- a/drivers/media/video/gspca/pac_common.h +++ b/drivers/media/video/gspca/pac_common.h | |||
@@ -23,6 +23,13 @@ | |||
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | /* We calculate the autogain at the end of the transfer of a frame, at this | ||
27 | moment a frame with the old settings is being transmitted, and a frame is | ||
28 | being captured with the old settings. So if we adjust the autogain we must | ||
29 | ignore atleast the 2 next frames for the new settings to come into effect | ||
30 | before doing any other adjustments */ | ||
31 | #define PAC_AUTOGAIN_IGNORE_FRAMES 3 | ||
32 | |||
26 | static const unsigned char pac_sof_marker[5] = | 33 | static const unsigned char pac_sof_marker[5] = |
27 | { 0xff, 0xff, 0x00, 0xff, 0x96 }; | 34 | { 0xff, 0xff, 0x00, 0xff, 0x96 }; |
28 | 35 | ||
@@ -37,7 +44,7 @@ static unsigned char *pac_find_sof(struct gspca_dev *gspca_dev, | |||
37 | if (m[i] == pac_sof_marker[sd->sof_read]) { | 44 | if (m[i] == pac_sof_marker[sd->sof_read]) { |
38 | sd->sof_read++; | 45 | sd->sof_read++; |
39 | if (sd->sof_read == sizeof(pac_sof_marker)) { | 46 | if (sd->sof_read == sizeof(pac_sof_marker)) { |
40 | PDEBUG(D_STREAM, | 47 | PDEBUG(D_FRAM, |
41 | "SOF found, bytes to analyze: %u." | 48 | "SOF found, bytes to analyze: %u." |
42 | " Frame starts at byte #%u", | 49 | " Frame starts at byte #%u", |
43 | len, i + 1); | 50 | len, i + 1); |