diff options
Diffstat (limited to 'drivers/media/video/pwc')
-rw-r--r-- | drivers/media/video/pwc/Kconfig | 1 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-ctrl.c | 803 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-dec1.c | 28 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-dec1.h | 8 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-dec23.c | 22 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-dec23.h | 10 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-if.c | 1259 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-ioctl.h | 323 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-kiara.c | 1 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-misc.c | 4 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-uncompress.c | 17 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-uncompress.h | 40 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-v4l.c | 1257 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc.h | 409 |
14 files changed, 1473 insertions, 2709 deletions
diff --git a/drivers/media/video/pwc/Kconfig b/drivers/media/video/pwc/Kconfig index 8da42e4f1ba0..d63d0a850035 100644 --- a/drivers/media/video/pwc/Kconfig +++ b/drivers/media/video/pwc/Kconfig | |||
@@ -1,6 +1,7 @@ | |||
1 | config USB_PWC | 1 | config USB_PWC |
2 | tristate "USB Philips Cameras" | 2 | tristate "USB Philips Cameras" |
3 | depends on VIDEO_V4L2 | 3 | depends on VIDEO_V4L2 |
4 | select VIDEOBUF2_VMALLOC | ||
4 | ---help--- | 5 | ---help--- |
5 | Say Y or M here if you want to use one of these Philips & OEM | 6 | Say Y or M here if you want to use one of these Philips & OEM |
6 | webcams: | 7 | webcams: |
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c index 760b4de13adf..3977addf3ba8 100644 --- a/drivers/media/video/pwc/pwc-ctrl.c +++ b/drivers/media/video/pwc/pwc-ctrl.c | |||
@@ -3,6 +3,7 @@ | |||
3 | video modes. | 3 | video modes. |
4 | (C) 1999-2003 Nemosoft Unv. | 4 | (C) 1999-2003 Nemosoft Unv. |
5 | (C) 2004-2006 Luc Saillard (luc@saillard.org) | 5 | (C) 2004-2006 Luc Saillard (luc@saillard.org) |
6 | (C) 2011 Hans de Goede <hdegoede@redhat.com> | ||
6 | 7 | ||
7 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | 8 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx |
8 | driver and thus may have bugs that are not present in the original version. | 9 | driver and thus may have bugs that are not present in the original version. |
@@ -43,61 +44,12 @@ | |||
43 | #include <asm/errno.h> | 44 | #include <asm/errno.h> |
44 | 45 | ||
45 | #include "pwc.h" | 46 | #include "pwc.h" |
46 | #include "pwc-uncompress.h" | ||
47 | #include "pwc-kiara.h" | 47 | #include "pwc-kiara.h" |
48 | #include "pwc-timon.h" | 48 | #include "pwc-timon.h" |
49 | #include "pwc-dec1.h" | 49 | #include "pwc-dec1.h" |
50 | #include "pwc-dec23.h" | 50 | #include "pwc-dec23.h" |
51 | 51 | ||
52 | /* Request types: video */ | 52 | /* Selectors for status controls used only in this file */ |
53 | #define SET_LUM_CTL 0x01 | ||
54 | #define GET_LUM_CTL 0x02 | ||
55 | #define SET_CHROM_CTL 0x03 | ||
56 | #define GET_CHROM_CTL 0x04 | ||
57 | #define SET_STATUS_CTL 0x05 | ||
58 | #define GET_STATUS_CTL 0x06 | ||
59 | #define SET_EP_STREAM_CTL 0x07 | ||
60 | #define GET_EP_STREAM_CTL 0x08 | ||
61 | #define GET_XX_CTL 0x09 | ||
62 | #define SET_XX_CTL 0x0A | ||
63 | #define GET_XY_CTL 0x0B | ||
64 | #define SET_XY_CTL 0x0C | ||
65 | #define SET_MPT_CTL 0x0D | ||
66 | #define GET_MPT_CTL 0x0E | ||
67 | |||
68 | /* Selectors for the Luminance controls [GS]ET_LUM_CTL */ | ||
69 | #define AGC_MODE_FORMATTER 0x2000 | ||
70 | #define PRESET_AGC_FORMATTER 0x2100 | ||
71 | #define SHUTTER_MODE_FORMATTER 0x2200 | ||
72 | #define PRESET_SHUTTER_FORMATTER 0x2300 | ||
73 | #define PRESET_CONTOUR_FORMATTER 0x2400 | ||
74 | #define AUTO_CONTOUR_FORMATTER 0x2500 | ||
75 | #define BACK_LIGHT_COMPENSATION_FORMATTER 0x2600 | ||
76 | #define CONTRAST_FORMATTER 0x2700 | ||
77 | #define DYNAMIC_NOISE_CONTROL_FORMATTER 0x2800 | ||
78 | #define FLICKERLESS_MODE_FORMATTER 0x2900 | ||
79 | #define AE_CONTROL_SPEED 0x2A00 | ||
80 | #define BRIGHTNESS_FORMATTER 0x2B00 | ||
81 | #define GAMMA_FORMATTER 0x2C00 | ||
82 | |||
83 | /* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */ | ||
84 | #define WB_MODE_FORMATTER 0x1000 | ||
85 | #define AWB_CONTROL_SPEED_FORMATTER 0x1100 | ||
86 | #define AWB_CONTROL_DELAY_FORMATTER 0x1200 | ||
87 | #define PRESET_MANUAL_RED_GAIN_FORMATTER 0x1300 | ||
88 | #define PRESET_MANUAL_BLUE_GAIN_FORMATTER 0x1400 | ||
89 | #define COLOUR_MODE_FORMATTER 0x1500 | ||
90 | #define SATURATION_MODE_FORMATTER1 0x1600 | ||
91 | #define SATURATION_MODE_FORMATTER2 0x1700 | ||
92 | |||
93 | /* Selectors for the Status controls [GS]ET_STATUS_CTL */ | ||
94 | #define SAVE_USER_DEFAULTS_FORMATTER 0x0200 | ||
95 | #define RESTORE_USER_DEFAULTS_FORMATTER 0x0300 | ||
96 | #define RESTORE_FACTORY_DEFAULTS_FORMATTER 0x0400 | ||
97 | #define READ_AGC_FORMATTER 0x0500 | ||
98 | #define READ_SHUTTER_FORMATTER 0x0600 | ||
99 | #define READ_RED_GAIN_FORMATTER 0x0700 | ||
100 | #define READ_BLUE_GAIN_FORMATTER 0x0800 | ||
101 | #define GET_STATUS_B00 0x0B00 | 53 | #define GET_STATUS_B00 0x0B00 |
102 | #define SENSOR_TYPE_FORMATTER1 0x0C00 | 54 | #define SENSOR_TYPE_FORMATTER1 0x0C00 |
103 | #define GET_STATUS_3000 0x3000 | 55 | #define GET_STATUS_3000 0x3000 |
@@ -116,11 +68,6 @@ | |||
116 | /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */ | 68 | /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */ |
117 | #define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100 | 69 | #define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100 |
118 | 70 | ||
119 | /* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */ | ||
120 | #define PT_RELATIVE_CONTROL_FORMATTER 0x01 | ||
121 | #define PT_RESET_CONTROL_FORMATTER 0x02 | ||
122 | #define PT_STATUS_FORMATTER 0x03 | ||
123 | |||
124 | static const char *size2name[PSZ_MAX] = | 71 | static const char *size2name[PSZ_MAX] = |
125 | { | 72 | { |
126 | "subQCIF", | 73 | "subQCIF", |
@@ -160,7 +107,7 @@ static void pwc_set_image_buffer_size(struct pwc_device *pdev); | |||
160 | /****************************************************************************/ | 107 | /****************************************************************************/ |
161 | 108 | ||
162 | static int _send_control_msg(struct pwc_device *pdev, | 109 | static int _send_control_msg(struct pwc_device *pdev, |
163 | u8 request, u16 value, int index, void *buf, int buflen, int timeout) | 110 | u8 request, u16 value, int index, void *buf, int buflen) |
164 | { | 111 | { |
165 | int rc; | 112 | int rc; |
166 | void *kbuf = NULL; | 113 | void *kbuf = NULL; |
@@ -177,7 +124,7 @@ static int _send_control_msg(struct pwc_device *pdev, | |||
177 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | 124 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
178 | value, | 125 | value, |
179 | index, | 126 | index, |
180 | kbuf, buflen, timeout); | 127 | kbuf, buflen, USB_CTRL_SET_TIMEOUT); |
181 | 128 | ||
182 | kfree(kbuf); | 129 | kfree(kbuf); |
183 | return rc; | 130 | return rc; |
@@ -197,9 +144,13 @@ static int recv_control_msg(struct pwc_device *pdev, | |||
197 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | 144 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
198 | value, | 145 | value, |
199 | pdev->vcinterface, | 146 | pdev->vcinterface, |
200 | kbuf, buflen, 500); | 147 | kbuf, buflen, USB_CTRL_GET_TIMEOUT); |
201 | memcpy(buf, kbuf, buflen); | 148 | memcpy(buf, kbuf, buflen); |
202 | kfree(kbuf); | 149 | kfree(kbuf); |
150 | |||
151 | if (rc < 0) | ||
152 | PWC_ERROR("recv_control_msg error %d req %02x val %04x\n", | ||
153 | rc, request, value); | ||
203 | return rc; | 154 | return rc; |
204 | } | 155 | } |
205 | 156 | ||
@@ -210,18 +161,16 @@ static inline int send_video_command(struct pwc_device *pdev, | |||
210 | SET_EP_STREAM_CTL, | 161 | SET_EP_STREAM_CTL, |
211 | VIDEO_OUTPUT_CONTROL_FORMATTER, | 162 | VIDEO_OUTPUT_CONTROL_FORMATTER, |
212 | index, | 163 | index, |
213 | buf, buflen, 1000); | 164 | buf, buflen); |
214 | } | 165 | } |
215 | 166 | ||
216 | static inline int send_control_msg(struct pwc_device *pdev, | 167 | int send_control_msg(struct pwc_device *pdev, |
217 | u8 request, u16 value, void *buf, int buflen) | 168 | u8 request, u16 value, void *buf, int buflen) |
218 | { | 169 | { |
219 | return _send_control_msg(pdev, | 170 | return _send_control_msg(pdev, |
220 | request, value, pdev->vcinterface, buf, buflen, 500); | 171 | request, value, pdev->vcinterface, buf, buflen); |
221 | } | 172 | } |
222 | 173 | ||
223 | |||
224 | |||
225 | static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) | 174 | static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) |
226 | { | 175 | { |
227 | unsigned char buf[3]; | 176 | unsigned char buf[3]; |
@@ -261,8 +210,11 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) | |||
261 | PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret); | 210 | PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret); |
262 | return ret; | 211 | return ret; |
263 | } | 212 | } |
264 | if (pEntry->compressed && pdev->pixfmt == V4L2_PIX_FMT_YUV420) | 213 | if (pEntry->compressed && pdev->pixfmt == V4L2_PIX_FMT_YUV420) { |
265 | pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); | 214 | ret = pwc_dec1_init(pdev, pdev->type, pdev->release, buf); |
215 | if (ret < 0) | ||
216 | return ret; | ||
217 | } | ||
266 | 218 | ||
267 | pdev->cmd_len = 3; | 219 | pdev->cmd_len = 3; |
268 | memcpy(pdev->cmd_buf, buf, 3); | 220 | memcpy(pdev->cmd_buf, buf, 3); |
@@ -321,8 +273,11 @@ static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, i | |||
321 | if (ret < 0) | 273 | if (ret < 0) |
322 | return ret; | 274 | return ret; |
323 | 275 | ||
324 | if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) | 276 | if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) { |
325 | pwc_dec23_init(pdev, pdev->type, buf); | 277 | ret = pwc_dec23_init(pdev, pdev->type, buf); |
278 | if (ret < 0) | ||
279 | return ret; | ||
280 | } | ||
326 | 281 | ||
327 | pdev->cmd_len = 13; | 282 | pdev->cmd_len = 13; |
328 | memcpy(pdev->cmd_buf, buf, 13); | 283 | memcpy(pdev->cmd_buf, buf, 13); |
@@ -394,8 +349,11 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, i | |||
394 | if (ret < 0) | 349 | if (ret < 0) |
395 | return ret; | 350 | return ret; |
396 | 351 | ||
397 | if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) | 352 | if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) { |
398 | pwc_dec23_init(pdev, pdev->type, buf); | 353 | ret = pwc_dec23_init(pdev, pdev->type, buf); |
354 | if (ret < 0) | ||
355 | return ret; | ||
356 | } | ||
399 | 357 | ||
400 | pdev->cmd_len = 12; | 358 | pdev->cmd_len = 12; |
401 | memcpy(pdev->cmd_buf, buf, 12); | 359 | memcpy(pdev->cmd_buf, buf, 12); |
@@ -452,6 +410,7 @@ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frame | |||
452 | } | 410 | } |
453 | pdev->view.x = width; | 411 | pdev->view.x = width; |
454 | pdev->view.y = height; | 412 | pdev->view.y = height; |
413 | pdev->vcompression = compression; | ||
455 | pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; | 414 | pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; |
456 | pwc_set_image_buffer_size(pdev); | 415 | pwc_set_image_buffer_size(pdev); |
457 | PWC_DEBUG_SIZE("Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y); | 416 | PWC_DEBUG_SIZE("Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y); |
@@ -511,13 +470,9 @@ unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned i | |||
511 | return ret; | 470 | return ret; |
512 | } | 471 | } |
513 | 472 | ||
514 | #define BLACK_Y 0 | ||
515 | #define BLACK_U 128 | ||
516 | #define BLACK_V 128 | ||
517 | |||
518 | static void pwc_set_image_buffer_size(struct pwc_device *pdev) | 473 | static void pwc_set_image_buffer_size(struct pwc_device *pdev) |
519 | { | 474 | { |
520 | int i, factor = 0; | 475 | int factor = 0; |
521 | 476 | ||
522 | /* for V4L2_PIX_FMT_YUV420 */ | 477 | /* for V4L2_PIX_FMT_YUV420 */ |
523 | switch (pdev->pixfmt) { | 478 | switch (pdev->pixfmt) { |
@@ -541,442 +496,108 @@ static void pwc_set_image_buffer_size(struct pwc_device *pdev) | |||
541 | */ | 496 | */ |
542 | pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC; | 497 | pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC; |
543 | pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; | 498 | pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; |
544 | |||
545 | /* Fill buffers with black colors */ | ||
546 | for (i = 0; i < pwc_mbufs; i++) { | ||
547 | unsigned char *p = pdev->image_data + pdev->images[i].offset; | ||
548 | memset(p, BLACK_Y, pdev->view.x * pdev->view.y); | ||
549 | p += pdev->view.x * pdev->view.y; | ||
550 | memset(p, BLACK_U, pdev->view.x * pdev->view.y/4); | ||
551 | p += pdev->view.x * pdev->view.y/4; | ||
552 | memset(p, BLACK_V, pdev->view.x * pdev->view.y/4); | ||
553 | } | ||
554 | } | 499 | } |
555 | 500 | ||
556 | 501 | int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) | |
557 | |||
558 | /* BRIGHTNESS */ | ||
559 | |||
560 | int pwc_get_brightness(struct pwc_device *pdev) | ||
561 | { | 502 | { |
562 | char buf; | ||
563 | int ret; | 503 | int ret; |
504 | u8 buf; | ||
564 | 505 | ||
565 | ret = recv_control_msg(pdev, | 506 | ret = recv_control_msg(pdev, request, value, &buf, sizeof(buf)); |
566 | GET_LUM_CTL, BRIGHTNESS_FORMATTER, &buf, sizeof(buf)); | ||
567 | if (ret < 0) | 507 | if (ret < 0) |
568 | return ret; | 508 | return ret; |
569 | return buf; | ||
570 | } | ||
571 | 509 | ||
572 | int pwc_set_brightness(struct pwc_device *pdev, int value) | 510 | *data = buf; |
573 | { | 511 | return 0; |
574 | char buf; | ||
575 | |||
576 | if (value < 0) | ||
577 | value = 0; | ||
578 | if (value > 0xffff) | ||
579 | value = 0xffff; | ||
580 | buf = (value >> 9) & 0x7f; | ||
581 | return send_control_msg(pdev, | ||
582 | SET_LUM_CTL, BRIGHTNESS_FORMATTER, &buf, sizeof(buf)); | ||
583 | } | 512 | } |
584 | 513 | ||
585 | /* CONTRAST */ | 514 | int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data) |
586 | |||
587 | int pwc_get_contrast(struct pwc_device *pdev) | ||
588 | { | 515 | { |
589 | char buf; | ||
590 | int ret; | 516 | int ret; |
591 | 517 | ||
592 | ret = recv_control_msg(pdev, | 518 | ret = send_control_msg(pdev, request, value, &data, sizeof(data)); |
593 | GET_LUM_CTL, CONTRAST_FORMATTER, &buf, sizeof(buf)); | ||
594 | if (ret < 0) | 519 | if (ret < 0) |
595 | return ret; | 520 | return ret; |
596 | return buf; | ||
597 | } | ||
598 | 521 | ||
599 | int pwc_set_contrast(struct pwc_device *pdev, int value) | 522 | return 0; |
600 | { | ||
601 | char buf; | ||
602 | |||
603 | if (value < 0) | ||
604 | value = 0; | ||
605 | if (value > 0xffff) | ||
606 | value = 0xffff; | ||
607 | buf = (value >> 10) & 0x3f; | ||
608 | return send_control_msg(pdev, | ||
609 | SET_LUM_CTL, CONTRAST_FORMATTER, &buf, sizeof(buf)); | ||
610 | } | 523 | } |
611 | 524 | ||
612 | /* GAMMA */ | 525 | int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) |
613 | |||
614 | int pwc_get_gamma(struct pwc_device *pdev) | ||
615 | { | 526 | { |
616 | char buf; | ||
617 | int ret; | 527 | int ret; |
528 | s8 buf; | ||
618 | 529 | ||
619 | ret = recv_control_msg(pdev, | 530 | ret = recv_control_msg(pdev, request, value, &buf, sizeof(buf)); |
620 | GET_LUM_CTL, GAMMA_FORMATTER, &buf, sizeof(buf)); | ||
621 | if (ret < 0) | 531 | if (ret < 0) |
622 | return ret; | 532 | return ret; |
623 | return buf; | ||
624 | } | ||
625 | |||
626 | int pwc_set_gamma(struct pwc_device *pdev, int value) | ||
627 | { | ||
628 | char buf; | ||
629 | 533 | ||
630 | if (value < 0) | 534 | *data = buf; |
631 | value = 0; | ||
632 | if (value > 0xffff) | ||
633 | value = 0xffff; | ||
634 | buf = (value >> 11) & 0x1f; | ||
635 | return send_control_msg(pdev, | ||
636 | SET_LUM_CTL, GAMMA_FORMATTER, &buf, sizeof(buf)); | ||
637 | } | ||
638 | |||
639 | |||
640 | /* SATURATION */ | ||
641 | |||
642 | /* return a value between [-100 , 100] */ | ||
643 | int pwc_get_saturation(struct pwc_device *pdev, int *value) | ||
644 | { | ||
645 | char buf; | ||
646 | int ret, saturation_register; | ||
647 | |||
648 | if (pdev->type < 675) | ||
649 | return -EINVAL; | ||
650 | if (pdev->type < 730) | ||
651 | saturation_register = SATURATION_MODE_FORMATTER2; | ||
652 | else | ||
653 | saturation_register = SATURATION_MODE_FORMATTER1; | ||
654 | ret = recv_control_msg(pdev, | ||
655 | GET_CHROM_CTL, saturation_register, &buf, sizeof(buf)); | ||
656 | if (ret < 0) | ||
657 | return ret; | ||
658 | *value = (signed)buf; | ||
659 | return 0; | 535 | return 0; |
660 | } | 536 | } |
661 | 537 | ||
662 | /* @param value saturation color between [-100 , 100] */ | 538 | int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) |
663 | int pwc_set_saturation(struct pwc_device *pdev, int value) | ||
664 | { | 539 | { |
665 | char buf; | ||
666 | int saturation_register; | ||
667 | |||
668 | if (pdev->type < 675) | ||
669 | return -EINVAL; | ||
670 | if (value < -100) | ||
671 | value = -100; | ||
672 | if (value > 100) | ||
673 | value = 100; | ||
674 | if (pdev->type < 730) | ||
675 | saturation_register = SATURATION_MODE_FORMATTER2; | ||
676 | else | ||
677 | saturation_register = SATURATION_MODE_FORMATTER1; | ||
678 | return send_control_msg(pdev, | ||
679 | SET_CHROM_CTL, saturation_register, &buf, sizeof(buf)); | ||
680 | } | ||
681 | |||
682 | /* AGC */ | ||
683 | |||
684 | int pwc_set_agc(struct pwc_device *pdev, int mode, int value) | ||
685 | { | ||
686 | char buf; | ||
687 | int ret; | 540 | int ret; |
541 | u8 buf[2]; | ||
688 | 542 | ||
689 | if (mode) | 543 | ret = recv_control_msg(pdev, request, value, buf, sizeof(buf)); |
690 | buf = 0x0; /* auto */ | ||
691 | else | ||
692 | buf = 0xff; /* fixed */ | ||
693 | |||
694 | ret = send_control_msg(pdev, | ||
695 | SET_LUM_CTL, AGC_MODE_FORMATTER, &buf, sizeof(buf)); | ||
696 | |||
697 | if (!mode && ret >= 0) { | ||
698 | if (value < 0) | ||
699 | value = 0; | ||
700 | if (value > 0xffff) | ||
701 | value = 0xffff; | ||
702 | buf = (value >> 10) & 0x3F; | ||
703 | ret = send_control_msg(pdev, | ||
704 | SET_LUM_CTL, PRESET_AGC_FORMATTER, &buf, sizeof(buf)); | ||
705 | } | ||
706 | if (ret < 0) | 544 | if (ret < 0) |
707 | return ret; | 545 | return ret; |
546 | |||
547 | *data = (buf[1] << 8) | buf[0]; | ||
708 | return 0; | 548 | return 0; |
709 | } | 549 | } |
710 | 550 | ||
711 | int pwc_get_agc(struct pwc_device *pdev, int *value) | 551 | int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data) |
712 | { | 552 | { |
713 | unsigned char buf; | ||
714 | int ret; | 553 | int ret; |
554 | u8 buf[2]; | ||
715 | 555 | ||
716 | ret = recv_control_msg(pdev, | 556 | buf[0] = data & 0xff; |
717 | GET_LUM_CTL, AGC_MODE_FORMATTER, &buf, sizeof(buf)); | 557 | buf[1] = data >> 8; |
558 | ret = send_control_msg(pdev, request, value, buf, sizeof(buf)); | ||
718 | if (ret < 0) | 559 | if (ret < 0) |
719 | return ret; | 560 | return ret; |
720 | 561 | ||
721 | if (buf != 0) { /* fixed */ | ||
722 | ret = recv_control_msg(pdev, | ||
723 | GET_LUM_CTL, PRESET_AGC_FORMATTER, &buf, sizeof(buf)); | ||
724 | if (ret < 0) | ||
725 | return ret; | ||
726 | if (buf > 0x3F) | ||
727 | buf = 0x3F; | ||
728 | *value = (buf << 10); | ||
729 | } | ||
730 | else { /* auto */ | ||
731 | ret = recv_control_msg(pdev, | ||
732 | GET_STATUS_CTL, READ_AGC_FORMATTER, &buf, sizeof(buf)); | ||
733 | if (ret < 0) | ||
734 | return ret; | ||
735 | /* Gah... this value ranges from 0x00 ... 0x9F */ | ||
736 | if (buf > 0x9F) | ||
737 | buf = 0x9F; | ||
738 | *value = -(48 + buf * 409); | ||
739 | } | ||
740 | |||
741 | return 0; | 562 | return 0; |
742 | } | 563 | } |
743 | 564 | ||
744 | int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value) | 565 | int pwc_button_ctrl(struct pwc_device *pdev, u16 value) |
745 | { | ||
746 | char buf[2]; | ||
747 | int speed, ret; | ||
748 | |||
749 | |||
750 | if (mode) | ||
751 | buf[0] = 0x0; /* auto */ | ||
752 | else | ||
753 | buf[0] = 0xff; /* fixed */ | ||
754 | |||
755 | ret = send_control_msg(pdev, | ||
756 | SET_LUM_CTL, SHUTTER_MODE_FORMATTER, &buf, 1); | ||
757 | |||
758 | if (!mode && ret >= 0) { | ||
759 | if (value < 0) | ||
760 | value = 0; | ||
761 | if (value > 0xffff) | ||
762 | value = 0xffff; | ||
763 | |||
764 | if (DEVICE_USE_CODEC2(pdev->type)) { | ||
765 | /* speed ranges from 0x0 to 0x290 (656) */ | ||
766 | speed = (value / 100); | ||
767 | buf[1] = speed >> 8; | ||
768 | buf[0] = speed & 0xff; | ||
769 | } else if (DEVICE_USE_CODEC3(pdev->type)) { | ||
770 | /* speed seems to range from 0x0 to 0xff */ | ||
771 | buf[1] = 0; | ||
772 | buf[0] = value >> 8; | ||
773 | } | ||
774 | |||
775 | ret = send_control_msg(pdev, | ||
776 | SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, | ||
777 | &buf, sizeof(buf)); | ||
778 | } | ||
779 | return ret; | ||
780 | } | ||
781 | |||
782 | /* This function is not exported to v4l1, so output values between 0 -> 256 */ | ||
783 | int pwc_get_shutter_speed(struct pwc_device *pdev, int *value) | ||
784 | { | 566 | { |
785 | unsigned char buf[2]; | ||
786 | int ret; | 567 | int ret; |
787 | 568 | ||
788 | ret = recv_control_msg(pdev, | 569 | ret = send_control_msg(pdev, SET_STATUS_CTL, value, NULL, 0); |
789 | GET_STATUS_CTL, READ_SHUTTER_FORMATTER, &buf, sizeof(buf)); | ||
790 | if (ret < 0) | 570 | if (ret < 0) |
791 | return ret; | 571 | return ret; |
792 | *value = buf[0] + (buf[1] << 8); | 572 | |
793 | if (DEVICE_USE_CODEC2(pdev->type)) { | ||
794 | /* speed ranges from 0x0 to 0x290 (656) */ | ||
795 | *value *= 256/656; | ||
796 | } else if (DEVICE_USE_CODEC3(pdev->type)) { | ||
797 | /* speed seems to range from 0x0 to 0xff */ | ||
798 | } | ||
799 | return 0; | 573 | return 0; |
800 | } | 574 | } |
801 | 575 | ||
802 | |||
803 | /* POWER */ | 576 | /* POWER */ |
804 | 577 | void pwc_camera_power(struct pwc_device *pdev, int power) | |
805 | int pwc_camera_power(struct pwc_device *pdev, int power) | ||
806 | { | 578 | { |
807 | char buf; | 579 | char buf; |
580 | int r; | ||
581 | |||
582 | if (!pdev->power_save) | ||
583 | return; | ||
808 | 584 | ||
809 | if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6)) | 585 | if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6)) |
810 | return 0; /* Not supported by Nala or Timon < release 6 */ | 586 | return; /* Not supported by Nala or Timon < release 6 */ |
811 | 587 | ||
812 | if (power) | 588 | if (power) |
813 | buf = 0x00; /* active */ | 589 | buf = 0x00; /* active */ |
814 | else | 590 | else |
815 | buf = 0xFF; /* power save */ | 591 | buf = 0xFF; /* power save */ |
816 | return send_control_msg(pdev, | 592 | r = send_control_msg(pdev, |
817 | SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER, | 593 | SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER, |
818 | &buf, sizeof(buf)); | 594 | &buf, sizeof(buf)); |
819 | } | ||
820 | |||
821 | |||
822 | |||
823 | /* private calls */ | ||
824 | |||
825 | int pwc_restore_user(struct pwc_device *pdev) | ||
826 | { | ||
827 | return send_control_msg(pdev, | ||
828 | SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, NULL, 0); | ||
829 | } | ||
830 | |||
831 | int pwc_save_user(struct pwc_device *pdev) | ||
832 | { | ||
833 | return send_control_msg(pdev, | ||
834 | SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, NULL, 0); | ||
835 | } | ||
836 | |||
837 | int pwc_restore_factory(struct pwc_device *pdev) | ||
838 | { | ||
839 | return send_control_msg(pdev, | ||
840 | SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, NULL, 0); | ||
841 | } | ||
842 | |||
843 | /* ************************************************* */ | ||
844 | /* Patch by Alvarado: (not in the original version */ | ||
845 | |||
846 | /* | ||
847 | * the camera recognizes modes from 0 to 4: | ||
848 | * | ||
849 | * 00: indoor (incandescant lighting) | ||
850 | * 01: outdoor (sunlight) | ||
851 | * 02: fluorescent lighting | ||
852 | * 03: manual | ||
853 | * 04: auto | ||
854 | */ | ||
855 | int pwc_set_awb(struct pwc_device *pdev, int mode) | ||
856 | { | ||
857 | char buf; | ||
858 | int ret; | ||
859 | |||
860 | if (mode < 0) | ||
861 | mode = 0; | ||
862 | |||
863 | if (mode > 4) | ||
864 | mode = 4; | ||
865 | |||
866 | buf = mode & 0x07; /* just the lowest three bits */ | ||
867 | |||
868 | ret = send_control_msg(pdev, | ||
869 | SET_CHROM_CTL, WB_MODE_FORMATTER, &buf, sizeof(buf)); | ||
870 | |||
871 | if (ret < 0) | ||
872 | return ret; | ||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | int pwc_get_awb(struct pwc_device *pdev) | ||
877 | { | ||
878 | unsigned char buf; | ||
879 | int ret; | ||
880 | |||
881 | ret = recv_control_msg(pdev, | ||
882 | GET_CHROM_CTL, WB_MODE_FORMATTER, &buf, sizeof(buf)); | ||
883 | |||
884 | if (ret < 0) | ||
885 | return ret; | ||
886 | return buf; | ||
887 | } | ||
888 | |||
889 | int pwc_set_red_gain(struct pwc_device *pdev, int value) | ||
890 | { | ||
891 | unsigned char buf; | ||
892 | |||
893 | if (value < 0) | ||
894 | value = 0; | ||
895 | if (value > 0xffff) | ||
896 | value = 0xffff; | ||
897 | /* only the msb is considered */ | ||
898 | buf = value >> 8; | ||
899 | return send_control_msg(pdev, | ||
900 | SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, | ||
901 | &buf, sizeof(buf)); | ||
902 | } | ||
903 | |||
904 | int pwc_get_red_gain(struct pwc_device *pdev, int *value) | ||
905 | { | ||
906 | unsigned char buf; | ||
907 | int ret; | ||
908 | |||
909 | ret = recv_control_msg(pdev, | ||
910 | GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, | ||
911 | &buf, sizeof(buf)); | ||
912 | if (ret < 0) | ||
913 | return ret; | ||
914 | *value = buf << 8; | ||
915 | return 0; | ||
916 | } | ||
917 | |||
918 | |||
919 | int pwc_set_blue_gain(struct pwc_device *pdev, int value) | ||
920 | { | ||
921 | unsigned char buf; | ||
922 | |||
923 | if (value < 0) | ||
924 | value = 0; | ||
925 | if (value > 0xffff) | ||
926 | value = 0xffff; | ||
927 | /* only the msb is considered */ | ||
928 | buf = value >> 8; | ||
929 | return send_control_msg(pdev, | ||
930 | SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, | ||
931 | &buf, sizeof(buf)); | ||
932 | } | ||
933 | |||
934 | int pwc_get_blue_gain(struct pwc_device *pdev, int *value) | ||
935 | { | ||
936 | unsigned char buf; | ||
937 | int ret; | ||
938 | |||
939 | ret = recv_control_msg(pdev, | ||
940 | GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, | ||
941 | &buf, sizeof(buf)); | ||
942 | if (ret < 0) | ||
943 | return ret; | ||
944 | *value = buf << 8; | ||
945 | return 0; | ||
946 | } | ||
947 | |||
948 | 595 | ||
949 | /* The following two functions are different, since they only read the | 596 | if (r < 0) |
950 | internal red/blue gains, which may be different from the manual | 597 | PWC_ERROR("Failed to power %s camera (%d)\n", |
951 | gains set or read above. | 598 | power ? "on" : "off", r); |
952 | */ | ||
953 | static int pwc_read_red_gain(struct pwc_device *pdev, int *value) | ||
954 | { | ||
955 | unsigned char buf; | ||
956 | int ret; | ||
957 | |||
958 | ret = recv_control_msg(pdev, | ||
959 | GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, &buf, sizeof(buf)); | ||
960 | if (ret < 0) | ||
961 | return ret; | ||
962 | *value = buf << 8; | ||
963 | return 0; | ||
964 | } | 599 | } |
965 | 600 | ||
966 | static int pwc_read_blue_gain(struct pwc_device *pdev, int *value) | ||
967 | { | ||
968 | unsigned char buf; | ||
969 | int ret; | ||
970 | |||
971 | ret = recv_control_msg(pdev, | ||
972 | GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, &buf, sizeof(buf)); | ||
973 | if (ret < 0) | ||
974 | return ret; | ||
975 | *value = buf << 8; | ||
976 | return 0; | ||
977 | } | ||
978 | |||
979 | |||
980 | static int pwc_set_wb_speed(struct pwc_device *pdev, int speed) | 601 | static int pwc_set_wb_speed(struct pwc_device *pdev, int speed) |
981 | { | 602 | { |
982 | unsigned char buf; | 603 | unsigned char buf; |
@@ -1028,6 +649,7 @@ static int pwc_get_wb_delay(struct pwc_device *pdev, int *value) | |||
1028 | int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) | 649 | int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) |
1029 | { | 650 | { |
1030 | unsigned char buf[2]; | 651 | unsigned char buf[2]; |
652 | int r; | ||
1031 | 653 | ||
1032 | if (pdev->type < 730) | 654 | if (pdev->type < 730) |
1033 | return 0; | 655 | return 0; |
@@ -1045,8 +667,12 @@ int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) | |||
1045 | buf[0] = on_value; | 667 | buf[0] = on_value; |
1046 | buf[1] = off_value; | 668 | buf[1] = off_value; |
1047 | 669 | ||
1048 | return send_control_msg(pdev, | 670 | r = send_control_msg(pdev, |
1049 | SET_STATUS_CTL, LED_FORMATTER, &buf, sizeof(buf)); | 671 | SET_STATUS_CTL, LED_FORMATTER, &buf, sizeof(buf)); |
672 | if (r < 0) | ||
673 | PWC_ERROR("Failed to set LED on/off time (%d)\n", r); | ||
674 | |||
675 | return r; | ||
1050 | } | 676 | } |
1051 | 677 | ||
1052 | static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) | 678 | static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) |
@@ -1069,164 +695,6 @@ static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) | |||
1069 | return 0; | 695 | return 0; |
1070 | } | 696 | } |
1071 | 697 | ||
1072 | int pwc_set_contour(struct pwc_device *pdev, int contour) | ||
1073 | { | ||
1074 | unsigned char buf; | ||
1075 | int ret; | ||
1076 | |||
1077 | if (contour < 0) | ||
1078 | buf = 0xff; /* auto contour on */ | ||
1079 | else | ||
1080 | buf = 0x0; /* auto contour off */ | ||
1081 | ret = send_control_msg(pdev, | ||
1082 | SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, &buf, sizeof(buf)); | ||
1083 | if (ret < 0) | ||
1084 | return ret; | ||
1085 | |||
1086 | if (contour < 0) | ||
1087 | return 0; | ||
1088 | if (contour > 0xffff) | ||
1089 | contour = 0xffff; | ||
1090 | |||
1091 | buf = (contour >> 10); /* contour preset is [0..3f] */ | ||
1092 | ret = send_control_msg(pdev, | ||
1093 | SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, &buf, sizeof(buf)); | ||
1094 | if (ret < 0) | ||
1095 | return ret; | ||
1096 | return 0; | ||
1097 | } | ||
1098 | |||
1099 | int pwc_get_contour(struct pwc_device *pdev, int *contour) | ||
1100 | { | ||
1101 | unsigned char buf; | ||
1102 | int ret; | ||
1103 | |||
1104 | ret = recv_control_msg(pdev, | ||
1105 | GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, &buf, sizeof(buf)); | ||
1106 | if (ret < 0) | ||
1107 | return ret; | ||
1108 | |||
1109 | if (buf == 0) { | ||
1110 | /* auto mode off, query current preset value */ | ||
1111 | ret = recv_control_msg(pdev, | ||
1112 | GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, | ||
1113 | &buf, sizeof(buf)); | ||
1114 | if (ret < 0) | ||
1115 | return ret; | ||
1116 | *contour = buf << 10; | ||
1117 | } | ||
1118 | else | ||
1119 | *contour = -1; | ||
1120 | return 0; | ||
1121 | } | ||
1122 | |||
1123 | |||
1124 | int pwc_set_backlight(struct pwc_device *pdev, int backlight) | ||
1125 | { | ||
1126 | unsigned char buf; | ||
1127 | |||
1128 | if (backlight) | ||
1129 | buf = 0xff; | ||
1130 | else | ||
1131 | buf = 0x0; | ||
1132 | return send_control_msg(pdev, | ||
1133 | SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, | ||
1134 | &buf, sizeof(buf)); | ||
1135 | } | ||
1136 | |||
1137 | int pwc_get_backlight(struct pwc_device *pdev, int *backlight) | ||
1138 | { | ||
1139 | int ret; | ||
1140 | unsigned char buf; | ||
1141 | |||
1142 | ret = recv_control_msg(pdev, | ||
1143 | GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, | ||
1144 | &buf, sizeof(buf)); | ||
1145 | if (ret < 0) | ||
1146 | return ret; | ||
1147 | *backlight = !!buf; | ||
1148 | return 0; | ||
1149 | } | ||
1150 | |||
1151 | int pwc_set_colour_mode(struct pwc_device *pdev, int colour) | ||
1152 | { | ||
1153 | unsigned char buf; | ||
1154 | |||
1155 | if (colour) | ||
1156 | buf = 0xff; | ||
1157 | else | ||
1158 | buf = 0x0; | ||
1159 | return send_control_msg(pdev, | ||
1160 | SET_CHROM_CTL, COLOUR_MODE_FORMATTER, &buf, sizeof(buf)); | ||
1161 | } | ||
1162 | |||
1163 | int pwc_get_colour_mode(struct pwc_device *pdev, int *colour) | ||
1164 | { | ||
1165 | int ret; | ||
1166 | unsigned char buf; | ||
1167 | |||
1168 | ret = recv_control_msg(pdev, | ||
1169 | GET_CHROM_CTL, COLOUR_MODE_FORMATTER, &buf, sizeof(buf)); | ||
1170 | if (ret < 0) | ||
1171 | return ret; | ||
1172 | *colour = !!buf; | ||
1173 | return 0; | ||
1174 | } | ||
1175 | |||
1176 | |||
1177 | int pwc_set_flicker(struct pwc_device *pdev, int flicker) | ||
1178 | { | ||
1179 | unsigned char buf; | ||
1180 | |||
1181 | if (flicker) | ||
1182 | buf = 0xff; | ||
1183 | else | ||
1184 | buf = 0x0; | ||
1185 | return send_control_msg(pdev, | ||
1186 | SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, &buf, sizeof(buf)); | ||
1187 | } | ||
1188 | |||
1189 | int pwc_get_flicker(struct pwc_device *pdev, int *flicker) | ||
1190 | { | ||
1191 | int ret; | ||
1192 | unsigned char buf; | ||
1193 | |||
1194 | ret = recv_control_msg(pdev, | ||
1195 | GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, &buf, sizeof(buf)); | ||
1196 | if (ret < 0) | ||
1197 | return ret; | ||
1198 | *flicker = !!buf; | ||
1199 | return 0; | ||
1200 | } | ||
1201 | |||
1202 | int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise) | ||
1203 | { | ||
1204 | unsigned char buf; | ||
1205 | |||
1206 | if (noise < 0) | ||
1207 | noise = 0; | ||
1208 | if (noise > 3) | ||
1209 | noise = 3; | ||
1210 | buf = noise; | ||
1211 | return send_control_msg(pdev, | ||
1212 | SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, | ||
1213 | &buf, sizeof(buf)); | ||
1214 | } | ||
1215 | |||
1216 | int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise) | ||
1217 | { | ||
1218 | int ret; | ||
1219 | unsigned char buf; | ||
1220 | |||
1221 | ret = recv_control_msg(pdev, | ||
1222 | GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, | ||
1223 | &buf, sizeof(buf)); | ||
1224 | if (ret < 0) | ||
1225 | return ret; | ||
1226 | *noise = buf; | ||
1227 | return 0; | ||
1228 | } | ||
1229 | |||
1230 | static int _pwc_mpt_reset(struct pwc_device *pdev, int flags) | 698 | static int _pwc_mpt_reset(struct pwc_device *pdev, int flags) |
1231 | { | 699 | { |
1232 | unsigned char buf; | 700 | unsigned char buf; |
@@ -1309,7 +777,7 @@ static int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *st | |||
1309 | return 0; | 777 | return 0; |
1310 | } | 778 | } |
1311 | 779 | ||
1312 | 780 | #ifdef CONFIG_USB_PWC_DEBUG | |
1313 | int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) | 781 | int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) |
1314 | { | 782 | { |
1315 | unsigned char buf; | 783 | unsigned char buf; |
@@ -1332,7 +800,7 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) | |||
1332 | *sensor = buf; | 800 | *sensor = buf; |
1333 | return 0; | 801 | return 0; |
1334 | } | 802 | } |
1335 | 803 | #endif | |
1336 | 804 | ||
1337 | /* End of Add-Ons */ | 805 | /* End of Add-Ons */ |
1338 | /* ************************************************* */ | 806 | /* ************************************************* */ |
@@ -1356,37 +824,41 @@ int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) | |||
1356 | /* copy local variable to arg */ | 824 | /* copy local variable to arg */ |
1357 | #define ARG_OUT(ARG_name) /* nothing */ | 825 | #define ARG_OUT(ARG_name) /* nothing */ |
1358 | 826 | ||
827 | /* | ||
828 | * Our ctrls use native values, but the old custom pwc ioctl interface expects | ||
829 | * values from 0 - 65535, define 2 helper functions to scale things. */ | ||
830 | static int pwc_ioctl_g_ctrl(struct v4l2_ctrl *ctrl) | ||
831 | { | ||
832 | return v4l2_ctrl_g_ctrl(ctrl) * 65535 / ctrl->maximum; | ||
833 | } | ||
834 | |||
835 | static int pwc_ioctl_s_ctrl(struct v4l2_ctrl *ctrl, int val) | ||
836 | { | ||
837 | return v4l2_ctrl_s_ctrl(ctrl, val * ctrl->maximum / 65535); | ||
838 | } | ||
839 | |||
1359 | long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) | 840 | long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) |
1360 | { | 841 | { |
1361 | long ret = 0; | 842 | long ret = 0; |
1362 | 843 | ||
1363 | switch(cmd) { | 844 | switch(cmd) { |
1364 | case VIDIOCPWCRUSER: | 845 | case VIDIOCPWCRUSER: |
1365 | { | 846 | ret = pwc_button_ctrl(pdev, RESTORE_USER_DEFAULTS_FORMATTER); |
1366 | if (pwc_restore_user(pdev)) | ||
1367 | ret = -EINVAL; | ||
1368 | break; | 847 | break; |
1369 | } | ||
1370 | 848 | ||
1371 | case VIDIOCPWCSUSER: | 849 | case VIDIOCPWCSUSER: |
1372 | { | 850 | ret = pwc_button_ctrl(pdev, SAVE_USER_DEFAULTS_FORMATTER); |
1373 | if (pwc_save_user(pdev)) | ||
1374 | ret = -EINVAL; | ||
1375 | break; | 851 | break; |
1376 | } | ||
1377 | 852 | ||
1378 | case VIDIOCPWCFACTORY: | 853 | case VIDIOCPWCFACTORY: |
1379 | { | 854 | ret = pwc_button_ctrl(pdev, RESTORE_FACTORY_DEFAULTS_FORMATTER); |
1380 | if (pwc_restore_factory(pdev)) | ||
1381 | ret = -EINVAL; | ||
1382 | break; | 855 | break; |
1383 | } | ||
1384 | 856 | ||
1385 | case VIDIOCPWCSCQUAL: | 857 | case VIDIOCPWCSCQUAL: |
1386 | { | 858 | { |
1387 | ARG_DEF(int, qual) | 859 | ARG_DEF(int, qual) |
1388 | 860 | ||
1389 | if (pdev->iso_init) { | 861 | if (vb2_is_streaming(&pdev->vb_queue)) { |
1390 | ret = -EBUSY; | 862 | ret = -EBUSY; |
1391 | break; | 863 | break; |
1392 | } | 864 | } |
@@ -1396,8 +868,6 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) | |||
1396 | ret = -EINVAL; | 868 | ret = -EINVAL; |
1397 | else | 869 | else |
1398 | ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot); | 870 | ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot); |
1399 | if (ret >= 0) | ||
1400 | pdev->vcompression = ARGR(qual); | ||
1401 | break; | 871 | break; |
1402 | } | 872 | } |
1403 | 873 | ||
@@ -1432,71 +902,59 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) | |||
1432 | case VIDIOCPWCSAGC: | 902 | case VIDIOCPWCSAGC: |
1433 | { | 903 | { |
1434 | ARG_DEF(int, agc) | 904 | ARG_DEF(int, agc) |
1435 | |||
1436 | ARG_IN(agc) | 905 | ARG_IN(agc) |
1437 | if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc))) | 906 | ret = v4l2_ctrl_s_ctrl(pdev->autogain, ARGR(agc) < 0); |
1438 | ret = -EINVAL; | 907 | if (ret == 0 && ARGR(agc) >= 0) |
908 | ret = pwc_ioctl_s_ctrl(pdev->gain, ARGR(agc)); | ||
1439 | break; | 909 | break; |
1440 | } | 910 | } |
1441 | 911 | ||
1442 | case VIDIOCPWCGAGC: | 912 | case VIDIOCPWCGAGC: |
1443 | { | 913 | { |
1444 | ARG_DEF(int, agc) | 914 | ARG_DEF(int, agc) |
1445 | 915 | if (v4l2_ctrl_g_ctrl(pdev->autogain)) | |
1446 | if (pwc_get_agc(pdev, ARGA(agc))) | 916 | ARGR(agc) = -1; |
1447 | ret = -EINVAL; | 917 | else |
918 | ARGR(agc) = pwc_ioctl_g_ctrl(pdev->gain); | ||
1448 | ARG_OUT(agc) | 919 | ARG_OUT(agc) |
1449 | break; | 920 | break; |
1450 | } | 921 | } |
1451 | 922 | ||
1452 | case VIDIOCPWCSSHUTTER: | 923 | case VIDIOCPWCSSHUTTER: |
1453 | { | 924 | { |
1454 | ARG_DEF(int, shutter_speed) | 925 | ARG_DEF(int, shutter) |
1455 | 926 | ARG_IN(shutter) | |
1456 | ARG_IN(shutter_speed) | 927 | ret = v4l2_ctrl_s_ctrl(pdev->exposure_auto, |
1457 | ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed)); | 928 | /* Menu idx 0 = auto, idx 1 = manual */ |
929 | ARGR(shutter) >= 0); | ||
930 | if (ret == 0 && ARGR(shutter) >= 0) | ||
931 | ret = pwc_ioctl_s_ctrl(pdev->exposure, ARGR(shutter)); | ||
1458 | break; | 932 | break; |
1459 | } | 933 | } |
1460 | 934 | ||
1461 | case VIDIOCPWCSAWB: | 935 | case VIDIOCPWCSAWB: |
1462 | { | 936 | { |
1463 | ARG_DEF(struct pwc_whitebalance, wb) | 937 | ARG_DEF(struct pwc_whitebalance, wb) |
1464 | |||
1465 | ARG_IN(wb) | 938 | ARG_IN(wb) |
1466 | ret = pwc_set_awb(pdev, ARGR(wb).mode); | 939 | ret = v4l2_ctrl_s_ctrl(pdev->auto_white_balance, |
1467 | if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) { | 940 | ARGR(wb).mode); |
1468 | pwc_set_red_gain(pdev, ARGR(wb).manual_red); | 941 | if (ret == 0 && ARGR(wb).mode == PWC_WB_MANUAL) |
1469 | pwc_set_blue_gain(pdev, ARGR(wb).manual_blue); | 942 | ret = pwc_ioctl_s_ctrl(pdev->red_balance, |
1470 | } | 943 | ARGR(wb).manual_red); |
944 | if (ret == 0 && ARGR(wb).mode == PWC_WB_MANUAL) | ||
945 | ret = pwc_ioctl_s_ctrl(pdev->blue_balance, | ||
946 | ARGR(wb).manual_blue); | ||
1471 | break; | 947 | break; |
1472 | } | 948 | } |
1473 | 949 | ||
1474 | case VIDIOCPWCGAWB: | 950 | case VIDIOCPWCGAWB: |
1475 | { | 951 | { |
1476 | ARG_DEF(struct pwc_whitebalance, wb) | 952 | ARG_DEF(struct pwc_whitebalance, wb) |
1477 | 953 | ARGR(wb).mode = v4l2_ctrl_g_ctrl(pdev->auto_white_balance); | |
1478 | memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance)); | 954 | ARGR(wb).manual_red = ARGR(wb).read_red = |
1479 | ARGR(wb).mode = pwc_get_awb(pdev); | 955 | pwc_ioctl_g_ctrl(pdev->red_balance); |
1480 | if (ARGR(wb).mode < 0) | 956 | ARGR(wb).manual_blue = ARGR(wb).read_blue = |
1481 | ret = -EINVAL; | 957 | pwc_ioctl_g_ctrl(pdev->blue_balance); |
1482 | else { | ||
1483 | if (ARGR(wb).mode == PWC_WB_MANUAL) { | ||
1484 | ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red); | ||
1485 | if (ret < 0) | ||
1486 | break; | ||
1487 | ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue); | ||
1488 | if (ret < 0) | ||
1489 | break; | ||
1490 | } | ||
1491 | if (ARGR(wb).mode == PWC_WB_AUTO) { | ||
1492 | ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red); | ||
1493 | if (ret < 0) | ||
1494 | break; | ||
1495 | ret = pwc_read_blue_gain(pdev, &ARGR(wb).read_blue); | ||
1496 | if (ret < 0) | ||
1497 | break; | ||
1498 | } | ||
1499 | } | ||
1500 | ARG_OUT(wb) | 958 | ARG_OUT(wb) |
1501 | break; | 959 | break; |
1502 | } | 960 | } |
@@ -1550,17 +1008,20 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) | |||
1550 | case VIDIOCPWCSCONTOUR: | 1008 | case VIDIOCPWCSCONTOUR: |
1551 | { | 1009 | { |
1552 | ARG_DEF(int, contour) | 1010 | ARG_DEF(int, contour) |
1553 | |||
1554 | ARG_IN(contour) | 1011 | ARG_IN(contour) |
1555 | ret = pwc_set_contour(pdev, ARGR(contour)); | 1012 | ret = v4l2_ctrl_s_ctrl(pdev->autocontour, ARGR(contour) < 0); |
1013 | if (ret == 0 && ARGR(contour) >= 0) | ||
1014 | ret = pwc_ioctl_s_ctrl(pdev->contour, ARGR(contour)); | ||
1556 | break; | 1015 | break; |
1557 | } | 1016 | } |
1558 | 1017 | ||
1559 | case VIDIOCPWCGCONTOUR: | 1018 | case VIDIOCPWCGCONTOUR: |
1560 | { | 1019 | { |
1561 | ARG_DEF(int, contour) | 1020 | ARG_DEF(int, contour) |
1562 | 1021 | if (v4l2_ctrl_g_ctrl(pdev->autocontour)) | |
1563 | ret = pwc_get_contour(pdev, ARGA(contour)); | 1022 | ARGR(contour) = -1; |
1023 | else | ||
1024 | ARGR(contour) = pwc_ioctl_g_ctrl(pdev->contour); | ||
1564 | ARG_OUT(contour) | 1025 | ARG_OUT(contour) |
1565 | break; | 1026 | break; |
1566 | } | 1027 | } |
@@ -1568,17 +1029,15 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) | |||
1568 | case VIDIOCPWCSBACKLIGHT: | 1029 | case VIDIOCPWCSBACKLIGHT: |
1569 | { | 1030 | { |
1570 | ARG_DEF(int, backlight) | 1031 | ARG_DEF(int, backlight) |
1571 | |||
1572 | ARG_IN(backlight) | 1032 | ARG_IN(backlight) |
1573 | ret = pwc_set_backlight(pdev, ARGR(backlight)); | 1033 | ret = v4l2_ctrl_s_ctrl(pdev->backlight, ARGR(backlight)); |
1574 | break; | 1034 | break; |
1575 | } | 1035 | } |
1576 | 1036 | ||
1577 | case VIDIOCPWCGBACKLIGHT: | 1037 | case VIDIOCPWCGBACKLIGHT: |
1578 | { | 1038 | { |
1579 | ARG_DEF(int, backlight) | 1039 | ARG_DEF(int, backlight) |
1580 | 1040 | ARGR(backlight) = v4l2_ctrl_g_ctrl(pdev->backlight); | |
1581 | ret = pwc_get_backlight(pdev, ARGA(backlight)); | ||
1582 | ARG_OUT(backlight) | 1041 | ARG_OUT(backlight) |
1583 | break; | 1042 | break; |
1584 | } | 1043 | } |
@@ -1586,17 +1045,15 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) | |||
1586 | case VIDIOCPWCSFLICKER: | 1045 | case VIDIOCPWCSFLICKER: |
1587 | { | 1046 | { |
1588 | ARG_DEF(int, flicker) | 1047 | ARG_DEF(int, flicker) |
1589 | |||
1590 | ARG_IN(flicker) | 1048 | ARG_IN(flicker) |
1591 | ret = pwc_set_flicker(pdev, ARGR(flicker)); | 1049 | ret = v4l2_ctrl_s_ctrl(pdev->flicker, ARGR(flicker)); |
1592 | break; | 1050 | break; |
1593 | } | 1051 | } |
1594 | 1052 | ||
1595 | case VIDIOCPWCGFLICKER: | 1053 | case VIDIOCPWCGFLICKER: |
1596 | { | 1054 | { |
1597 | ARG_DEF(int, flicker) | 1055 | ARG_DEF(int, flicker) |
1598 | 1056 | ARGR(flicker) = v4l2_ctrl_g_ctrl(pdev->flicker); | |
1599 | ret = pwc_get_flicker(pdev, ARGA(flicker)); | ||
1600 | ARG_OUT(flicker) | 1057 | ARG_OUT(flicker) |
1601 | break; | 1058 | break; |
1602 | } | 1059 | } |
@@ -1604,17 +1061,15 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) | |||
1604 | case VIDIOCPWCSDYNNOISE: | 1061 | case VIDIOCPWCSDYNNOISE: |
1605 | { | 1062 | { |
1606 | ARG_DEF(int, dynnoise) | 1063 | ARG_DEF(int, dynnoise) |
1607 | |||
1608 | ARG_IN(dynnoise) | 1064 | ARG_IN(dynnoise) |
1609 | ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise)); | 1065 | ret = v4l2_ctrl_s_ctrl(pdev->noise_reduction, ARGR(dynnoise)); |
1610 | break; | 1066 | break; |
1611 | } | 1067 | } |
1612 | 1068 | ||
1613 | case VIDIOCPWCGDYNNOISE: | 1069 | case VIDIOCPWCGDYNNOISE: |
1614 | { | 1070 | { |
1615 | ARG_DEF(int, dynnoise) | 1071 | ARG_DEF(int, dynnoise) |
1616 | 1072 | ARGR(dynnoise) = v4l2_ctrl_g_ctrl(pdev->noise_reduction); | |
1617 | ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise)); | ||
1618 | ARG_OUT(dynnoise); | 1073 | ARG_OUT(dynnoise); |
1619 | break; | 1074 | break; |
1620 | } | 1075 | } |
diff --git a/drivers/media/video/pwc/pwc-dec1.c b/drivers/media/video/pwc/pwc-dec1.c index c29593f589eb..be0e02cb487f 100644 --- a/drivers/media/video/pwc/pwc-dec1.c +++ b/drivers/media/video/pwc/pwc-dec1.c | |||
@@ -22,29 +22,19 @@ | |||
22 | along with this program; if not, write to the Free Software | 22 | along with this program; if not, write to the Free Software |
23 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 23 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
24 | */ | 24 | */ |
25 | |||
26 | |||
27 | |||
28 | #include "pwc-dec1.h" | 25 | #include "pwc-dec1.h" |
29 | 26 | ||
30 | 27 | int pwc_dec1_init(struct pwc_device *pwc, int type, int release, void *buffer) | |
31 | void pwc_dec1_init(int type, int release, void *buffer, void *table) | ||
32 | { | 28 | { |
29 | struct pwc_dec1_private *pdec; | ||
33 | 30 | ||
34 | } | 31 | if (pwc->decompress_data == NULL) { |
35 | 32 | pdec = kmalloc(sizeof(struct pwc_dec1_private), GFP_KERNEL); | |
36 | void pwc_dec1_exit(void) | 33 | if (pdec == NULL) |
37 | { | 34 | return -ENOMEM; |
35 | pwc->decompress_data = pdec; | ||
36 | } | ||
37 | pdec = pwc->decompress_data; | ||
38 | 38 | ||
39 | |||
40 | |||
41 | } | ||
42 | |||
43 | int pwc_dec1_alloc(struct pwc_device *pwc) | ||
44 | { | ||
45 | pwc->decompress_data = kmalloc(sizeof(struct pwc_dec1_private), GFP_KERNEL); | ||
46 | if (pwc->decompress_data == NULL) | ||
47 | return -ENOMEM; | ||
48 | return 0; | 39 | return 0; |
49 | } | 40 | } |
50 | |||
diff --git a/drivers/media/video/pwc/pwc-dec1.h b/drivers/media/video/pwc/pwc-dec1.h index 8b62ddcc5c7e..a57d8601080b 100644 --- a/drivers/media/video/pwc/pwc-dec1.h +++ b/drivers/media/video/pwc/pwc-dec1.h | |||
@@ -22,8 +22,6 @@ | |||
22 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | */ | 23 | */ |
24 | 24 | ||
25 | |||
26 | |||
27 | #ifndef PWC_DEC1_H | 25 | #ifndef PWC_DEC1_H |
28 | #define PWC_DEC1_H | 26 | #define PWC_DEC1_H |
29 | 27 | ||
@@ -32,12 +30,8 @@ | |||
32 | struct pwc_dec1_private | 30 | struct pwc_dec1_private |
33 | { | 31 | { |
34 | int version; | 32 | int version; |
35 | |||
36 | }; | 33 | }; |
37 | 34 | ||
38 | int pwc_dec1_alloc(struct pwc_device *pwc); | 35 | int pwc_dec1_init(struct pwc_device *pwc, int type, int release, void *buffer); |
39 | void pwc_dec1_init(int type, int release, void *buffer, void *private_data); | ||
40 | void pwc_dec1_exit(void); | ||
41 | 36 | ||
42 | #endif | 37 | #endif |
43 | |||
diff --git a/drivers/media/video/pwc/pwc-dec23.c b/drivers/media/video/pwc/pwc-dec23.c index 0c801b8f3eca..06a4e877ba40 100644 --- a/drivers/media/video/pwc/pwc-dec23.c +++ b/drivers/media/video/pwc/pwc-dec23.c | |||
@@ -916,27 +916,5 @@ void pwc_dec23_decompress(const struct pwc_device *pwc, | |||
916 | pout_planar_v += pwc->view.x; | 916 | pout_planar_v += pwc->view.x; |
917 | 917 | ||
918 | } | 918 | } |
919 | |||
920 | } | 919 | } |
921 | |||
922 | } | 920 | } |
923 | |||
924 | void pwc_dec23_exit(void) | ||
925 | { | ||
926 | /* Do nothing */ | ||
927 | |||
928 | } | ||
929 | |||
930 | /** | ||
931 | * Allocate a private structure used by lookup table. | ||
932 | * You must call kfree() to free the memory allocated. | ||
933 | */ | ||
934 | int pwc_dec23_alloc(struct pwc_device *pwc) | ||
935 | { | ||
936 | pwc->decompress_data = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); | ||
937 | if (pwc->decompress_data == NULL) | ||
938 | return -ENOMEM; | ||
939 | return 0; | ||
940 | } | ||
941 | |||
942 | /* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ | ||
diff --git a/drivers/media/video/pwc/pwc-dec23.h b/drivers/media/video/pwc/pwc-dec23.h index 1c55298ad153..a0ac4f3dff81 100644 --- a/drivers/media/video/pwc/pwc-dec23.h +++ b/drivers/media/video/pwc/pwc-dec23.h | |||
@@ -49,19 +49,9 @@ struct pwc_dec23_private | |||
49 | 49 | ||
50 | }; | 50 | }; |
51 | 51 | ||
52 | |||
53 | int pwc_dec23_alloc(struct pwc_device *pwc); | ||
54 | int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd); | 52 | int pwc_dec23_init(struct pwc_device *pwc, int type, unsigned char *cmd); |
55 | void pwc_dec23_exit(void); | ||
56 | void pwc_dec23_decompress(const struct pwc_device *pwc, | 53 | void pwc_dec23_decompress(const struct pwc_device *pwc, |
57 | const void *src, | 54 | const void *src, |
58 | void *dst, | 55 | void *dst, |
59 | int flags); | 56 | int flags); |
60 | |||
61 | |||
62 | |||
63 | #endif | 57 | #endif |
64 | |||
65 | |||
66 | /* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ | ||
67 | |||
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index b0bde5a87c8a..51ca3589b1b5 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c | |||
@@ -2,6 +2,7 @@ | |||
2 | USB and Video4Linux interface part. | 2 | USB and Video4Linux interface part. |
3 | (C) 1999-2004 Nemosoft Unv. | 3 | (C) 1999-2004 Nemosoft Unv. |
4 | (C) 2004-2006 Luc Saillard (luc@saillard.org) | 4 | (C) 2004-2006 Luc Saillard (luc@saillard.org) |
5 | (C) 2011 Hans de Goede <hdegoede@redhat.com> | ||
5 | 6 | ||
6 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | 7 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx |
7 | driver and thus may have bugs that are not present in the original version. | 8 | driver and thus may have bugs that are not present in the original version. |
@@ -74,7 +75,6 @@ | |||
74 | #include "pwc-timon.h" | 75 | #include "pwc-timon.h" |
75 | #include "pwc-dec23.h" | 76 | #include "pwc-dec23.h" |
76 | #include "pwc-dec1.h" | 77 | #include "pwc-dec1.h" |
77 | #include "pwc-uncompress.h" | ||
78 | 78 | ||
79 | /* Function prototypes and driver templates */ | 79 | /* Function prototypes and driver templates */ |
80 | 80 | ||
@@ -116,6 +116,7 @@ MODULE_DEVICE_TABLE(usb, pwc_device_table); | |||
116 | 116 | ||
117 | static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id); | 117 | static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id); |
118 | static void usb_pwc_disconnect(struct usb_interface *intf); | 118 | static void usb_pwc_disconnect(struct usb_interface *intf); |
119 | static void pwc_isoc_cleanup(struct pwc_device *pdev); | ||
119 | 120 | ||
120 | static struct usb_driver pwc_driver = { | 121 | static struct usb_driver pwc_driver = { |
121 | .name = "Philips webcam", /* name */ | 122 | .name = "Philips webcam", /* name */ |
@@ -127,14 +128,11 @@ static struct usb_driver pwc_driver = { | |||
127 | #define MAX_DEV_HINTS 20 | 128 | #define MAX_DEV_HINTS 20 |
128 | #define MAX_ISOC_ERRORS 20 | 129 | #define MAX_ISOC_ERRORS 20 |
129 | 130 | ||
130 | static int default_size = PSZ_QCIF; | ||
131 | static int default_fps = 10; | 131 | static int default_fps = 10; |
132 | static int default_fbufs = 3; /* Default number of frame buffers */ | ||
133 | int pwc_mbufs = 2; /* Default number of mmap() buffers */ | ||
134 | #ifdef CONFIG_USB_PWC_DEBUG | 132 | #ifdef CONFIG_USB_PWC_DEBUG |
135 | int pwc_trace = PWC_DEBUG_LEVEL; | 133 | int pwc_trace = PWC_DEBUG_LEVEL; |
136 | #endif | 134 | #endif |
137 | static int power_save; | 135 | static int power_save = -1; |
138 | static int led_on = 100, led_off; /* defaults to LED that is on while in use */ | 136 | static int led_on = 100, led_off; /* defaults to LED that is on while in use */ |
139 | static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */ | 137 | static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */ |
140 | static struct { | 138 | static struct { |
@@ -173,389 +171,20 @@ static struct video_device pwc_template = { | |||
173 | /***************************************************************************/ | 171 | /***************************************************************************/ |
174 | /* Private functions */ | 172 | /* Private functions */ |
175 | 173 | ||
176 | /* Here we want the physical address of the memory. | 174 | struct pwc_frame_buf *pwc_get_next_fill_buf(struct pwc_device *pdev) |
177 | * This is used when initializing the contents of the area. | ||
178 | */ | ||
179 | |||
180 | |||
181 | |||
182 | static void *pwc_rvmalloc(unsigned long size) | ||
183 | { | ||
184 | void * mem; | ||
185 | unsigned long adr; | ||
186 | |||
187 | mem=vmalloc_32(size); | ||
188 | if (!mem) | ||
189 | return NULL; | ||
190 | |||
191 | memset(mem, 0, size); /* Clear the ram out, no junk to the user */ | ||
192 | adr=(unsigned long) mem; | ||
193 | while (size > 0) | ||
194 | { | ||
195 | SetPageReserved(vmalloc_to_page((void *)adr)); | ||
196 | adr += PAGE_SIZE; | ||
197 | size -= PAGE_SIZE; | ||
198 | } | ||
199 | return mem; | ||
200 | } | ||
201 | |||
202 | static void pwc_rvfree(void * mem, unsigned long size) | ||
203 | { | ||
204 | unsigned long adr; | ||
205 | |||
206 | if (!mem) | ||
207 | return; | ||
208 | |||
209 | adr=(unsigned long) mem; | ||
210 | while ((long) size > 0) | ||
211 | { | ||
212 | ClearPageReserved(vmalloc_to_page((void *)adr)); | ||
213 | adr += PAGE_SIZE; | ||
214 | size -= PAGE_SIZE; | ||
215 | } | ||
216 | vfree(mem); | ||
217 | } | ||
218 | |||
219 | |||
220 | |||
221 | |||
222 | static int pwc_allocate_buffers(struct pwc_device *pdev) | ||
223 | { | ||
224 | int i, err; | ||
225 | void *kbuf; | ||
226 | |||
227 | PWC_DEBUG_MEMORY(">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev); | ||
228 | |||
229 | if (pdev == NULL) | ||
230 | return -ENXIO; | ||
231 | |||
232 | /* Allocate Isochronuous pipe buffers */ | ||
233 | for (i = 0; i < MAX_ISO_BUFS; i++) { | ||
234 | if (pdev->sbuf[i].data == NULL) { | ||
235 | kbuf = kzalloc(ISO_BUFFER_SIZE, GFP_KERNEL); | ||
236 | if (kbuf == NULL) { | ||
237 | PWC_ERROR("Failed to allocate iso buffer %d.\n", i); | ||
238 | return -ENOMEM; | ||
239 | } | ||
240 | PWC_DEBUG_MEMORY("Allocated iso buffer at %p.\n", kbuf); | ||
241 | pdev->sbuf[i].data = kbuf; | ||
242 | } | ||
243 | } | ||
244 | |||
245 | /* Allocate frame buffer structure */ | ||
246 | if (pdev->fbuf == NULL) { | ||
247 | kbuf = kzalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL); | ||
248 | if (kbuf == NULL) { | ||
249 | PWC_ERROR("Failed to allocate frame buffer structure.\n"); | ||
250 | return -ENOMEM; | ||
251 | } | ||
252 | PWC_DEBUG_MEMORY("Allocated frame buffer structure at %p.\n", kbuf); | ||
253 | pdev->fbuf = kbuf; | ||
254 | } | ||
255 | |||
256 | /* create frame buffers, and make circular ring */ | ||
257 | for (i = 0; i < default_fbufs; i++) { | ||
258 | if (pdev->fbuf[i].data == NULL) { | ||
259 | kbuf = vzalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */ | ||
260 | if (kbuf == NULL) { | ||
261 | PWC_ERROR("Failed to allocate frame buffer %d.\n", i); | ||
262 | return -ENOMEM; | ||
263 | } | ||
264 | PWC_DEBUG_MEMORY("Allocated frame buffer %d at %p.\n", i, kbuf); | ||
265 | pdev->fbuf[i].data = kbuf; | ||
266 | } | ||
267 | } | ||
268 | |||
269 | /* Allocate decompressor table space */ | ||
270 | if (DEVICE_USE_CODEC1(pdev->type)) | ||
271 | err = pwc_dec1_alloc(pdev); | ||
272 | else | ||
273 | err = pwc_dec23_alloc(pdev); | ||
274 | |||
275 | if (err) { | ||
276 | PWC_ERROR("Failed to allocate decompress table.\n"); | ||
277 | return err; | ||
278 | } | ||
279 | |||
280 | /* Allocate image buffer; double buffer for mmap() */ | ||
281 | kbuf = pwc_rvmalloc(pwc_mbufs * pdev->len_per_image); | ||
282 | if (kbuf == NULL) { | ||
283 | PWC_ERROR("Failed to allocate image buffer(s). needed (%d)\n", | ||
284 | pwc_mbufs * pdev->len_per_image); | ||
285 | return -ENOMEM; | ||
286 | } | ||
287 | PWC_DEBUG_MEMORY("Allocated image buffer at %p.\n", kbuf); | ||
288 | pdev->image_data = kbuf; | ||
289 | for (i = 0; i < pwc_mbufs; i++) { | ||
290 | pdev->images[i].offset = i * pdev->len_per_image; | ||
291 | pdev->images[i].vma_use_count = 0; | ||
292 | } | ||
293 | for (; i < MAX_IMAGES; i++) { | ||
294 | pdev->images[i].offset = 0; | ||
295 | } | ||
296 | |||
297 | kbuf = NULL; | ||
298 | |||
299 | PWC_DEBUG_MEMORY("<< pwc_allocate_buffers()\n"); | ||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static void pwc_free_buffers(struct pwc_device *pdev) | ||
304 | { | ||
305 | int i; | ||
306 | |||
307 | PWC_DEBUG_MEMORY("Entering free_buffers(%p).\n", pdev); | ||
308 | |||
309 | if (pdev == NULL) | ||
310 | return; | ||
311 | /* Release Iso-pipe buffers */ | ||
312 | for (i = 0; i < MAX_ISO_BUFS; i++) | ||
313 | if (pdev->sbuf[i].data != NULL) { | ||
314 | PWC_DEBUG_MEMORY("Freeing ISO buffer at %p.\n", pdev->sbuf[i].data); | ||
315 | kfree(pdev->sbuf[i].data); | ||
316 | pdev->sbuf[i].data = NULL; | ||
317 | } | ||
318 | |||
319 | /* The same for frame buffers */ | ||
320 | if (pdev->fbuf != NULL) { | ||
321 | for (i = 0; i < default_fbufs; i++) { | ||
322 | if (pdev->fbuf[i].data != NULL) { | ||
323 | PWC_DEBUG_MEMORY("Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data); | ||
324 | vfree(pdev->fbuf[i].data); | ||
325 | pdev->fbuf[i].data = NULL; | ||
326 | } | ||
327 | } | ||
328 | kfree(pdev->fbuf); | ||
329 | pdev->fbuf = NULL; | ||
330 | } | ||
331 | |||
332 | /* Intermediate decompression buffer & tables */ | ||
333 | if (pdev->decompress_data != NULL) { | ||
334 | PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n", pdev->decompress_data); | ||
335 | kfree(pdev->decompress_data); | ||
336 | pdev->decompress_data = NULL; | ||
337 | } | ||
338 | |||
339 | /* Release image buffers */ | ||
340 | if (pdev->image_data != NULL) { | ||
341 | PWC_DEBUG_MEMORY("Freeing image buffer at %p.\n", pdev->image_data); | ||
342 | pwc_rvfree(pdev->image_data, pwc_mbufs * pdev->len_per_image); | ||
343 | } | ||
344 | pdev->image_data = NULL; | ||
345 | |||
346 | PWC_DEBUG_MEMORY("Leaving free_buffers().\n"); | ||
347 | } | ||
348 | |||
349 | /* The frame & image buffer mess. | ||
350 | |||
351 | Yes, this is a mess. Well, it used to be simple, but alas... In this | ||
352 | module, 3 buffers schemes are used to get the data from the USB bus to | ||
353 | the user program. The first scheme involves the ISO buffers (called thus | ||
354 | since they transport ISO data from the USB controller), and not really | ||
355 | interesting. Suffices to say the data from this buffer is quickly | ||
356 | gathered in an interrupt handler (pwc_isoc_handler) and placed into the | ||
357 | frame buffer. | ||
358 | |||
359 | The frame buffer is the second scheme, and is the central element here. | ||
360 | It collects the data from a single frame from the camera (hence, the | ||
361 | name). Frames are delimited by the USB camera with a short USB packet, | ||
362 | so that's easy to detect. The frame buffers form a list that is filled | ||
363 | by the camera+USB controller and drained by the user process through | ||
364 | either read() or mmap(). | ||
365 | |||
366 | The image buffer is the third scheme, in which frames are decompressed | ||
367 | and converted into planar format. For mmap() there is more than | ||
368 | one image buffer available. | ||
369 | |||
370 | The frame buffers provide the image buffering. In case the user process | ||
371 | is a bit slow, this introduces lag and some undesired side-effects. | ||
372 | The problem arises when the frame buffer is full. I used to drop the last | ||
373 | frame, which makes the data in the queue stale very quickly. But dropping | ||
374 | the frame at the head of the queue proved to be a litte bit more difficult. | ||
375 | I tried a circular linked scheme, but this introduced more problems than | ||
376 | it solved. | ||
377 | |||
378 | Because filling and draining are completely asynchronous processes, this | ||
379 | requires some fiddling with pointers and mutexes. | ||
380 | |||
381 | Eventually, I came up with a system with 2 lists: an 'empty' frame list | ||
382 | and a 'full' frame list: | ||
383 | * Initially, all frame buffers but one are on the 'empty' list; the one | ||
384 | remaining buffer is our initial fill frame. | ||
385 | * If a frame is needed for filling, we try to take it from the 'empty' | ||
386 | list, unless that list is empty, in which case we take the buffer at | ||
387 | the head of the 'full' list. | ||
388 | * When our fill buffer has been filled, it is appended to the 'full' | ||
389 | list. | ||
390 | * If a frame is needed by read() or mmap(), it is taken from the head of | ||
391 | the 'full' list, handled, and then appended to the 'empty' list. If no | ||
392 | buffer is present on the 'full' list, we wait. | ||
393 | The advantage is that the buffer that is currently being decompressed/ | ||
394 | converted, is on neither list, and thus not in our way (any other scheme | ||
395 | I tried had the problem of old data lingering in the queue). | ||
396 | |||
397 | Whatever strategy you choose, it always remains a tradeoff: with more | ||
398 | frame buffers the chances of a missed frame are reduced. On the other | ||
399 | hand, on slower machines it introduces lag because the queue will | ||
400 | always be full. | ||
401 | */ | ||
402 | |||
403 | /** | ||
404 | \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first. | ||
405 | */ | ||
406 | static int pwc_next_fill_frame(struct pwc_device *pdev) | ||
407 | { | ||
408 | int ret; | ||
409 | unsigned long flags; | ||
410 | |||
411 | ret = 0; | ||
412 | spin_lock_irqsave(&pdev->ptrlock, flags); | ||
413 | if (pdev->fill_frame != NULL) { | ||
414 | /* append to 'full' list */ | ||
415 | if (pdev->full_frames == NULL) { | ||
416 | pdev->full_frames = pdev->fill_frame; | ||
417 | pdev->full_frames_tail = pdev->full_frames; | ||
418 | } | ||
419 | else { | ||
420 | pdev->full_frames_tail->next = pdev->fill_frame; | ||
421 | pdev->full_frames_tail = pdev->fill_frame; | ||
422 | } | ||
423 | } | ||
424 | if (pdev->empty_frames != NULL) { | ||
425 | /* We have empty frames available. That's easy */ | ||
426 | pdev->fill_frame = pdev->empty_frames; | ||
427 | pdev->empty_frames = pdev->empty_frames->next; | ||
428 | } | ||
429 | else { | ||
430 | /* Hmm. Take it from the full list */ | ||
431 | /* sanity check */ | ||
432 | if (pdev->full_frames == NULL) { | ||
433 | PWC_ERROR("Neither empty or full frames available!\n"); | ||
434 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | ||
435 | return -EINVAL; | ||
436 | } | ||
437 | pdev->fill_frame = pdev->full_frames; | ||
438 | pdev->full_frames = pdev->full_frames->next; | ||
439 | ret = 1; | ||
440 | } | ||
441 | pdev->fill_frame->next = NULL; | ||
442 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | ||
443 | return ret; | ||
444 | } | ||
445 | |||
446 | |||
447 | /** | ||
448 | \brief Reset all buffers, pointers and lists, except for the image_used[] buffer. | ||
449 | |||
450 | If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble. | ||
451 | */ | ||
452 | static void pwc_reset_buffers(struct pwc_device *pdev) | ||
453 | { | ||
454 | int i; | ||
455 | unsigned long flags; | ||
456 | |||
457 | PWC_DEBUG_MEMORY(">> %s __enter__\n", __func__); | ||
458 | |||
459 | spin_lock_irqsave(&pdev->ptrlock, flags); | ||
460 | pdev->full_frames = NULL; | ||
461 | pdev->full_frames_tail = NULL; | ||
462 | for (i = 0; i < default_fbufs; i++) { | ||
463 | pdev->fbuf[i].filled = 0; | ||
464 | if (i > 0) | ||
465 | pdev->fbuf[i].next = &pdev->fbuf[i - 1]; | ||
466 | else | ||
467 | pdev->fbuf->next = NULL; | ||
468 | } | ||
469 | pdev->empty_frames = &pdev->fbuf[default_fbufs - 1]; | ||
470 | pdev->empty_frames_tail = pdev->fbuf; | ||
471 | pdev->read_frame = NULL; | ||
472 | pdev->fill_frame = pdev->empty_frames; | ||
473 | pdev->empty_frames = pdev->empty_frames->next; | ||
474 | |||
475 | pdev->image_read_pos = 0; | ||
476 | pdev->fill_image = 0; | ||
477 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | ||
478 | |||
479 | PWC_DEBUG_MEMORY("<< %s __leaving__\n", __func__); | ||
480 | } | ||
481 | |||
482 | |||
483 | /** | ||
484 | \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers. | ||
485 | */ | ||
486 | int pwc_handle_frame(struct pwc_device *pdev) | ||
487 | { | 175 | { |
488 | int ret = 0; | 176 | unsigned long flags = 0; |
489 | unsigned long flags; | 177 | struct pwc_frame_buf *buf = NULL; |
490 | 178 | ||
491 | spin_lock_irqsave(&pdev->ptrlock, flags); | 179 | spin_lock_irqsave(&pdev->queued_bufs_lock, flags); |
492 | /* First grab our read_frame; this is removed from all lists, so | 180 | if (list_empty(&pdev->queued_bufs)) |
493 | we can release the lock after this without problems */ | 181 | goto leave; |
494 | if (pdev->read_frame != NULL) { | 182 | |
495 | /* This can't theoretically happen */ | 183 | buf = list_entry(pdev->queued_bufs.next, struct pwc_frame_buf, list); |
496 | PWC_ERROR("Huh? Read frame still in use?\n"); | 184 | list_del(&buf->list); |
497 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | 185 | leave: |
498 | return ret; | 186 | spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags); |
499 | } | 187 | return buf; |
500 | |||
501 | |||
502 | if (pdev->full_frames == NULL) { | ||
503 | PWC_ERROR("Woops. No frames ready.\n"); | ||
504 | } | ||
505 | else { | ||
506 | pdev->read_frame = pdev->full_frames; | ||
507 | pdev->full_frames = pdev->full_frames->next; | ||
508 | pdev->read_frame->next = NULL; | ||
509 | } | ||
510 | |||
511 | if (pdev->read_frame != NULL) { | ||
512 | /* Decompression is a lengthy process, so it's outside of the lock. | ||
513 | This gives the isoc_handler the opportunity to fill more frames | ||
514 | in the mean time. | ||
515 | */ | ||
516 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | ||
517 | ret = pwc_decompress(pdev); | ||
518 | spin_lock_irqsave(&pdev->ptrlock, flags); | ||
519 | |||
520 | /* We're done with read_buffer, tack it to the end of the empty buffer list */ | ||
521 | if (pdev->empty_frames == NULL) { | ||
522 | pdev->empty_frames = pdev->read_frame; | ||
523 | pdev->empty_frames_tail = pdev->empty_frames; | ||
524 | } | ||
525 | else { | ||
526 | pdev->empty_frames_tail->next = pdev->read_frame; | ||
527 | pdev->empty_frames_tail = pdev->read_frame; | ||
528 | } | ||
529 | pdev->read_frame = NULL; | ||
530 | } | ||
531 | spin_unlock_irqrestore(&pdev->ptrlock, flags); | ||
532 | return ret; | ||
533 | } | ||
534 | |||
535 | /** | ||
536 | \brief Advance pointers of image buffer (after each user request) | ||
537 | */ | ||
538 | void pwc_next_image(struct pwc_device *pdev) | ||
539 | { | ||
540 | pdev->image_used[pdev->fill_image] = 0; | ||
541 | pdev->fill_image = (pdev->fill_image + 1) % pwc_mbufs; | ||
542 | } | ||
543 | |||
544 | /** | ||
545 | * Print debug information when a frame is discarded because all of our buffer | ||
546 | * is full | ||
547 | */ | ||
548 | static void pwc_frame_dumped(struct pwc_device *pdev) | ||
549 | { | ||
550 | pdev->vframes_dumped++; | ||
551 | if (pdev->vframe_count < FRAME_LOWMARK) | ||
552 | return; | ||
553 | |||
554 | if (pdev->vframes_dumped < 20) | ||
555 | PWC_DEBUG_FLOW("Dumping frame %d\n", pdev->vframe_count); | ||
556 | else if (pdev->vframes_dumped == 20) | ||
557 | PWC_DEBUG_FLOW("Dumping frame %d (last message)\n", | ||
558 | pdev->vframe_count); | ||
559 | } | 188 | } |
560 | 189 | ||
561 | static void pwc_snapshot_button(struct pwc_device *pdev, int down) | 190 | static void pwc_snapshot_button(struct pwc_device *pdev, int down) |
@@ -575,9 +204,9 @@ static void pwc_snapshot_button(struct pwc_device *pdev, int down) | |||
575 | #endif | 204 | #endif |
576 | } | 205 | } |
577 | 206 | ||
578 | static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_buf *fbuf) | 207 | static void pwc_frame_complete(struct pwc_device *pdev) |
579 | { | 208 | { |
580 | int awake = 0; | 209 | struct pwc_frame_buf *fbuf = pdev->fill_buf; |
581 | 210 | ||
582 | /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus | 211 | /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus |
583 | frames on the USB wire after an exposure change. This conditition is | 212 | frames on the USB wire after an exposure change. This conditition is |
@@ -589,7 +218,6 @@ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_ | |||
589 | if (ptr[1] == 1 && ptr[0] & 0x10) { | 218 | if (ptr[1] == 1 && ptr[0] & 0x10) { |
590 | PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n"); | 219 | PWC_TRACE("Hyundai CMOS sensor bug. Dropping frame.\n"); |
591 | pdev->drop_frames += 2; | 220 | pdev->drop_frames += 2; |
592 | pdev->vframes_error++; | ||
593 | } | 221 | } |
594 | if ((ptr[0] ^ pdev->vmirror) & 0x01) { | 222 | if ((ptr[0] ^ pdev->vmirror) & 0x01) { |
595 | pwc_snapshot_button(pdev, ptr[0] & 0x01); | 223 | pwc_snapshot_button(pdev, ptr[0] & 0x01); |
@@ -612,8 +240,7 @@ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_ | |||
612 | */ | 240 | */ |
613 | if (fbuf->filled == 4) | 241 | if (fbuf->filled == 4) |
614 | pdev->drop_frames++; | 242 | pdev->drop_frames++; |
615 | } | 243 | } else if (pdev->type == 740 || pdev->type == 720) { |
616 | else if (pdev->type == 740 || pdev->type == 720) { | ||
617 | unsigned char *ptr = (unsigned char *)fbuf->data; | 244 | unsigned char *ptr = (unsigned char *)fbuf->data; |
618 | if ((ptr[0] ^ pdev->vmirror) & 0x01) { | 245 | if ((ptr[0] ^ pdev->vmirror) & 0x01) { |
619 | pwc_snapshot_button(pdev, ptr[0] & 0x01); | 246 | pwc_snapshot_button(pdev, ptr[0] & 0x01); |
@@ -621,33 +248,23 @@ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_ | |||
621 | pdev->vmirror = ptr[0] & 0x03; | 248 | pdev->vmirror = ptr[0] & 0x03; |
622 | } | 249 | } |
623 | 250 | ||
624 | /* In case we were instructed to drop the frame, do so silently. | 251 | /* In case we were instructed to drop the frame, do so silently. */ |
625 | The buffer pointers are not updated either (but the counters are reset below). | 252 | if (pdev->drop_frames > 0) { |
626 | */ | ||
627 | if (pdev->drop_frames > 0) | ||
628 | pdev->drop_frames--; | 253 | pdev->drop_frames--; |
629 | else { | 254 | } else { |
630 | /* Check for underflow first */ | 255 | /* Check for underflow first */ |
631 | if (fbuf->filled < pdev->frame_total_size) { | 256 | if (fbuf->filled < pdev->frame_total_size) { |
632 | PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);" | 257 | PWC_DEBUG_FLOW("Frame buffer underflow (%d bytes);" |
633 | " discarded.\n", fbuf->filled); | 258 | " discarded.\n", fbuf->filled); |
634 | pdev->vframes_error++; | 259 | } else { |
635 | } | 260 | fbuf->vb.v4l2_buf.field = V4L2_FIELD_NONE; |
636 | else { | 261 | fbuf->vb.v4l2_buf.sequence = pdev->vframe_count; |
637 | /* Send only once per EOF */ | 262 | vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE); |
638 | awake = 1; /* delay wake_ups */ | 263 | pdev->fill_buf = NULL; |
639 | 264 | pdev->vsync = 0; | |
640 | /* Find our next frame to fill. This will always succeed, since we | ||
641 | * nick a frame from either empty or full list, but if we had to | ||
642 | * take it from the full list, it means a frame got dropped. | ||
643 | */ | ||
644 | if (pwc_next_fill_frame(pdev)) | ||
645 | pwc_frame_dumped(pdev); | ||
646 | |||
647 | } | 265 | } |
648 | } /* !drop_frames */ | 266 | } /* !drop_frames */ |
649 | pdev->vframe_count++; | 267 | pdev->vframe_count++; |
650 | return awake; | ||
651 | } | 268 | } |
652 | 269 | ||
653 | /* This gets called for the Isochronous pipe (video). This is done in | 270 | /* This gets called for the Isochronous pipe (video). This is done in |
@@ -655,24 +272,20 @@ static int pwc_rcv_short_packet(struct pwc_device *pdev, const struct pwc_frame_ | |||
655 | */ | 272 | */ |
656 | static void pwc_isoc_handler(struct urb *urb) | 273 | static void pwc_isoc_handler(struct urb *urb) |
657 | { | 274 | { |
658 | struct pwc_device *pdev; | 275 | struct pwc_device *pdev = (struct pwc_device *)urb->context; |
659 | int i, fst, flen; | 276 | int i, fst, flen; |
660 | int awake; | 277 | unsigned char *iso_buf = NULL; |
661 | struct pwc_frame_buf *fbuf; | ||
662 | unsigned char *fillptr = NULL, *iso_buf = NULL; | ||
663 | 278 | ||
664 | awake = 0; | 279 | if (urb->status == -ENOENT || urb->status == -ECONNRESET || |
665 | pdev = (struct pwc_device *)urb->context; | 280 | urb->status == -ESHUTDOWN) { |
666 | if (pdev == NULL) { | ||
667 | PWC_ERROR("isoc_handler() called with NULL device?!\n"); | ||
668 | return; | ||
669 | } | ||
670 | |||
671 | if (urb->status == -ENOENT || urb->status == -ECONNRESET) { | ||
672 | PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a"); | 281 | PWC_DEBUG_OPEN("URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a"); |
673 | return; | 282 | return; |
674 | } | 283 | } |
675 | if (urb->status != -EINPROGRESS && urb->status != 0) { | 284 | |
285 | if (pdev->fill_buf == NULL) | ||
286 | pdev->fill_buf = pwc_get_next_fill_buf(pdev); | ||
287 | |||
288 | if (urb->status != 0) { | ||
676 | const char *errmsg; | 289 | const char *errmsg; |
677 | 290 | ||
678 | errmsg = "Unknown"; | 291 | errmsg = "Unknown"; |
@@ -684,29 +297,21 @@ static void pwc_isoc_handler(struct urb *urb) | |||
684 | case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break; | 297 | case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break; |
685 | case -ETIME: errmsg = "Device does not respond"; break; | 298 | case -ETIME: errmsg = "Device does not respond"; break; |
686 | } | 299 | } |
687 | PWC_DEBUG_FLOW("pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg); | 300 | PWC_ERROR("pwc_isoc_handler() called with status %d [%s].\n", |
688 | /* Give up after a number of contiguous errors on the USB bus. | 301 | urb->status, errmsg); |
689 | Appearantly something is wrong so we simulate an unplug event. | 302 | /* Give up after a number of contiguous errors */ |
690 | */ | ||
691 | if (++pdev->visoc_errors > MAX_ISOC_ERRORS) | 303 | if (++pdev->visoc_errors > MAX_ISOC_ERRORS) |
692 | { | 304 | { |
693 | PWC_INFO("Too many ISOC errors, bailing out.\n"); | 305 | PWC_ERROR("Too many ISOC errors, bailing out.\n"); |
694 | pdev->error_status = EIO; | 306 | if (pdev->fill_buf) { |
695 | awake = 1; | 307 | vb2_buffer_done(&pdev->fill_buf->vb, |
696 | wake_up_interruptible(&pdev->frameq); | 308 | VB2_BUF_STATE_ERROR); |
309 | pdev->fill_buf = NULL; | ||
310 | } | ||
697 | } | 311 | } |
698 | goto handler_end; // ugly, but practical | 312 | pdev->vsync = 0; /* Drop the current frame */ |
699 | } | ||
700 | |||
701 | fbuf = pdev->fill_frame; | ||
702 | if (fbuf == NULL) { | ||
703 | PWC_ERROR("pwc_isoc_handler without valid fill frame.\n"); | ||
704 | awake = 1; | ||
705 | goto handler_end; | 313 | goto handler_end; |
706 | } | 314 | } |
707 | else { | ||
708 | fillptr = fbuf->data + fbuf->filled; | ||
709 | } | ||
710 | 315 | ||
711 | /* Reset ISOC error counter. We did get here, after all. */ | 316 | /* Reset ISOC error counter. We did get here, after all. */ |
712 | pdev->visoc_errors = 0; | 317 | pdev->visoc_errors = 0; |
@@ -720,89 +325,73 @@ static void pwc_isoc_handler(struct urb *urb) | |||
720 | fst = urb->iso_frame_desc[i].status; | 325 | fst = urb->iso_frame_desc[i].status; |
721 | flen = urb->iso_frame_desc[i].actual_length; | 326 | flen = urb->iso_frame_desc[i].actual_length; |
722 | iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset; | 327 | iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset; |
723 | if (fst == 0) { | 328 | if (fst != 0) { |
724 | if (flen > 0) { /* if valid data... */ | 329 | PWC_ERROR("Iso frame %d has error %d\n", i, fst); |
725 | if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */ | 330 | continue; |
726 | pdev->vsync = 2; | 331 | } |
727 | 332 | if (flen > 0 && pdev->vsync) { | |
728 | /* ...copy data to frame buffer, if possible */ | 333 | struct pwc_frame_buf *fbuf = pdev->fill_buf; |
729 | if (flen + fbuf->filled > pdev->frame_total_size) { | 334 | |
730 | PWC_DEBUG_FLOW("Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size); | 335 | if (pdev->vsync == 1) { |
731 | pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */ | 336 | do_gettimeofday(&fbuf->vb.v4l2_buf.timestamp); |
732 | pdev->vframes_error++; | 337 | pdev->vsync = 2; |
733 | } | 338 | } |
734 | else { | 339 | |
735 | memmove(fillptr, iso_buf, flen); | 340 | if (flen + fbuf->filled > pdev->frame_total_size) { |
736 | fillptr += flen; | 341 | PWC_ERROR("Frame overflow (%d > %d)\n", |
737 | } | 342 | flen + fbuf->filled, |
738 | } | 343 | pdev->frame_total_size); |
344 | pdev->vsync = 0; /* Let's wait for an EOF */ | ||
345 | } else { | ||
346 | memcpy(fbuf->data + fbuf->filled, iso_buf, | ||
347 | flen); | ||
739 | fbuf->filled += flen; | 348 | fbuf->filled += flen; |
740 | } /* ..flen > 0 */ | 349 | } |
741 | 350 | } | |
742 | if (flen < pdev->vlast_packet_size) { | 351 | if (flen < pdev->vlast_packet_size) { |
743 | /* Shorter packet... We probably have the end of an image-frame; | 352 | /* Shorter packet... end of frame */ |
744 | wake up read() process and let select()/poll() do something. | 353 | if (pdev->vsync == 2) |
745 | Decompression is done in user time over there. | 354 | pwc_frame_complete(pdev); |
746 | */ | 355 | if (pdev->fill_buf == NULL) |
747 | if (pdev->vsync == 2) { | 356 | pdev->fill_buf = pwc_get_next_fill_buf(pdev); |
748 | if (pwc_rcv_short_packet(pdev, fbuf)) { | 357 | if (pdev->fill_buf) { |
749 | awake = 1; | 358 | pdev->fill_buf->filled = 0; |
750 | fbuf = pdev->fill_frame; | ||
751 | } | ||
752 | } | ||
753 | fbuf->filled = 0; | ||
754 | fillptr = fbuf->data; | ||
755 | pdev->vsync = 1; | 359 | pdev->vsync = 1; |
756 | } | 360 | } |
757 | |||
758 | pdev->vlast_packet_size = flen; | ||
759 | } /* ..status == 0 */ | ||
760 | else { | ||
761 | /* This is normally not interesting to the user, unless | ||
762 | * you are really debugging something, default = 0 */ | ||
763 | static int iso_error; | ||
764 | iso_error++; | ||
765 | if (iso_error < 20) | ||
766 | PWC_DEBUG_FLOW("Iso frame %d of USB has error %d\n", i, fst); | ||
767 | } | 361 | } |
362 | pdev->vlast_packet_size = flen; | ||
768 | } | 363 | } |
769 | 364 | ||
770 | handler_end: | 365 | handler_end: |
771 | if (awake) | ||
772 | wake_up_interruptible(&pdev->frameq); | ||
773 | |||
774 | urb->dev = pdev->udev; | ||
775 | i = usb_submit_urb(urb, GFP_ATOMIC); | 366 | i = usb_submit_urb(urb, GFP_ATOMIC); |
776 | if (i != 0) | 367 | if (i != 0) |
777 | PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i); | 368 | PWC_ERROR("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i); |
778 | } | 369 | } |
779 | 370 | ||
780 | 371 | static int pwc_isoc_init(struct pwc_device *pdev) | |
781 | int pwc_isoc_init(struct pwc_device *pdev) | ||
782 | { | 372 | { |
783 | struct usb_device *udev; | 373 | struct usb_device *udev; |
784 | struct urb *urb; | 374 | struct urb *urb; |
785 | int i, j, ret; | 375 | int i, j, ret; |
786 | |||
787 | struct usb_interface *intf; | 376 | struct usb_interface *intf; |
788 | struct usb_host_interface *idesc = NULL; | 377 | struct usb_host_interface *idesc = NULL; |
789 | 378 | ||
790 | if (pdev == NULL) | ||
791 | return -EFAULT; | ||
792 | if (pdev->iso_init) | 379 | if (pdev->iso_init) |
793 | return 0; | 380 | return 0; |
381 | |||
794 | pdev->vsync = 0; | 382 | pdev->vsync = 0; |
383 | pdev->vlast_packet_size = 0; | ||
384 | pdev->fill_buf = NULL; | ||
385 | pdev->vframe_count = 0; | ||
386 | pdev->visoc_errors = 0; | ||
795 | udev = pdev->udev; | 387 | udev = pdev->udev; |
796 | 388 | ||
797 | /* Get the current alternate interface, adjust packet size */ | 389 | /* Get the current alternate interface, adjust packet size */ |
798 | if (!udev->actconfig) | ||
799 | return -EFAULT; | ||
800 | intf = usb_ifnum_to_if(udev, 0); | 390 | intf = usb_ifnum_to_if(udev, 0); |
801 | if (intf) | 391 | if (intf) |
802 | idesc = usb_altnum_to_altsetting(intf, pdev->valternate); | 392 | idesc = usb_altnum_to_altsetting(intf, pdev->valternate); |
803 | |||
804 | if (!idesc) | 393 | if (!idesc) |
805 | return -EFAULT; | 394 | return -EIO; |
806 | 395 | ||
807 | /* Search video endpoint */ | 396 | /* Search video endpoint */ |
808 | pdev->vmax_packet_size = -1; | 397 | pdev->vmax_packet_size = -1; |
@@ -825,34 +414,32 @@ int pwc_isoc_init(struct pwc_device *pdev) | |||
825 | if (ret < 0) | 414 | if (ret < 0) |
826 | return ret; | 415 | return ret; |
827 | 416 | ||
417 | /* Allocate and init Isochronuous urbs */ | ||
828 | for (i = 0; i < MAX_ISO_BUFS; i++) { | 418 | for (i = 0; i < MAX_ISO_BUFS; i++) { |
829 | urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); | 419 | urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); |
830 | if (urb == NULL) { | 420 | if (urb == NULL) { |
831 | PWC_ERROR("Failed to allocate urb %d\n", i); | 421 | PWC_ERROR("Failed to allocate urb %d\n", i); |
832 | ret = -ENOMEM; | 422 | pdev->iso_init = 1; |
833 | break; | 423 | pwc_isoc_cleanup(pdev); |
424 | return -ENOMEM; | ||
834 | } | 425 | } |
835 | pdev->sbuf[i].urb = urb; | 426 | pdev->urbs[i] = urb; |
836 | PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb); | 427 | PWC_DEBUG_MEMORY("Allocated URB at 0x%p\n", urb); |
837 | } | ||
838 | if (ret) { | ||
839 | /* De-allocate in reverse order */ | ||
840 | while (i--) { | ||
841 | usb_free_urb(pdev->sbuf[i].urb); | ||
842 | pdev->sbuf[i].urb = NULL; | ||
843 | } | ||
844 | return ret; | ||
845 | } | ||
846 | |||
847 | /* init URB structure */ | ||
848 | for (i = 0; i < MAX_ISO_BUFS; i++) { | ||
849 | urb = pdev->sbuf[i].urb; | ||
850 | 428 | ||
851 | urb->interval = 1; // devik | 429 | urb->interval = 1; // devik |
852 | urb->dev = udev; | 430 | urb->dev = udev; |
853 | urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint); | 431 | urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint); |
854 | urb->transfer_flags = URB_ISO_ASAP; | 432 | urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; |
855 | urb->transfer_buffer = pdev->sbuf[i].data; | 433 | urb->transfer_buffer = usb_alloc_coherent(udev, |
434 | ISO_BUFFER_SIZE, | ||
435 | GFP_KERNEL, | ||
436 | &urb->transfer_dma); | ||
437 | if (urb->transfer_buffer == NULL) { | ||
438 | PWC_ERROR("Failed to allocate urb buffer %d\n", i); | ||
439 | pdev->iso_init = 1; | ||
440 | pwc_isoc_cleanup(pdev); | ||
441 | return -ENOMEM; | ||
442 | } | ||
856 | urb->transfer_buffer_length = ISO_BUFFER_SIZE; | 443 | urb->transfer_buffer_length = ISO_BUFFER_SIZE; |
857 | urb->complete = pwc_isoc_handler; | 444 | urb->complete = pwc_isoc_handler; |
858 | urb->context = pdev; | 445 | urb->context = pdev; |
@@ -866,14 +453,14 @@ int pwc_isoc_init(struct pwc_device *pdev) | |||
866 | 453 | ||
867 | /* link */ | 454 | /* link */ |
868 | for (i = 0; i < MAX_ISO_BUFS; i++) { | 455 | for (i = 0; i < MAX_ISO_BUFS; i++) { |
869 | ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL); | 456 | ret = usb_submit_urb(pdev->urbs[i], GFP_KERNEL); |
870 | if (ret) { | 457 | if (ret) { |
871 | PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret); | 458 | PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret); |
872 | pdev->iso_init = 1; | 459 | pdev->iso_init = 1; |
873 | pwc_isoc_cleanup(pdev); | 460 | pwc_isoc_cleanup(pdev); |
874 | return ret; | 461 | return ret; |
875 | } | 462 | } |
876 | PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb); | 463 | PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->urbs[i]); |
877 | } | 464 | } |
878 | 465 | ||
879 | /* All is done... */ | 466 | /* All is done... */ |
@@ -888,12 +475,9 @@ static void pwc_iso_stop(struct pwc_device *pdev) | |||
888 | 475 | ||
889 | /* Unlinking ISOC buffers one by one */ | 476 | /* Unlinking ISOC buffers one by one */ |
890 | for (i = 0; i < MAX_ISO_BUFS; i++) { | 477 | for (i = 0; i < MAX_ISO_BUFS; i++) { |
891 | struct urb *urb; | 478 | if (pdev->urbs[i]) { |
892 | 479 | PWC_DEBUG_MEMORY("Unlinking URB %p\n", pdev->urbs[i]); | |
893 | urb = pdev->sbuf[i].urb; | 480 | usb_kill_urb(pdev->urbs[i]); |
894 | if (urb) { | ||
895 | PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb); | ||
896 | usb_kill_urb(urb); | ||
897 | } | 481 | } |
898 | } | 482 | } |
899 | } | 483 | } |
@@ -904,40 +488,51 @@ static void pwc_iso_free(struct pwc_device *pdev) | |||
904 | 488 | ||
905 | /* Freeing ISOC buffers one by one */ | 489 | /* Freeing ISOC buffers one by one */ |
906 | for (i = 0; i < MAX_ISO_BUFS; i++) { | 490 | for (i = 0; i < MAX_ISO_BUFS; i++) { |
907 | struct urb *urb; | 491 | if (pdev->urbs[i]) { |
908 | |||
909 | urb = pdev->sbuf[i].urb; | ||
910 | if (urb) { | ||
911 | PWC_DEBUG_MEMORY("Freeing URB\n"); | 492 | PWC_DEBUG_MEMORY("Freeing URB\n"); |
912 | usb_free_urb(urb); | 493 | if (pdev->urbs[i]->transfer_buffer) { |
913 | pdev->sbuf[i].urb = NULL; | 494 | usb_free_coherent(pdev->udev, |
495 | pdev->urbs[i]->transfer_buffer_length, | ||
496 | pdev->urbs[i]->transfer_buffer, | ||
497 | pdev->urbs[i]->transfer_dma); | ||
498 | } | ||
499 | usb_free_urb(pdev->urbs[i]); | ||
500 | pdev->urbs[i] = NULL; | ||
914 | } | 501 | } |
915 | } | 502 | } |
916 | } | 503 | } |
917 | 504 | ||
918 | void pwc_isoc_cleanup(struct pwc_device *pdev) | 505 | static void pwc_isoc_cleanup(struct pwc_device *pdev) |
919 | { | 506 | { |
920 | PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n"); | 507 | PWC_DEBUG_OPEN(">> pwc_isoc_cleanup()\n"); |
921 | if (pdev == NULL) | 508 | |
922 | return; | ||
923 | if (pdev->iso_init == 0) | 509 | if (pdev->iso_init == 0) |
924 | return; | 510 | return; |
925 | 511 | ||
926 | pwc_iso_stop(pdev); | 512 | pwc_iso_stop(pdev); |
927 | pwc_iso_free(pdev); | 513 | pwc_iso_free(pdev); |
928 | 514 | usb_set_interface(pdev->udev, 0, 0); | |
929 | /* Stop camera, but only if we are sure the camera is still there (unplug | ||
930 | is signalled by EPIPE) | ||
931 | */ | ||
932 | if (pdev->error_status != EPIPE) { | ||
933 | PWC_DEBUG_OPEN("Setting alternate interface 0.\n"); | ||
934 | usb_set_interface(pdev->udev, 0, 0); | ||
935 | } | ||
936 | 515 | ||
937 | pdev->iso_init = 0; | 516 | pdev->iso_init = 0; |
938 | PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n"); | 517 | PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n"); |
939 | } | 518 | } |
940 | 519 | ||
520 | /* | ||
521 | * Release all queued buffers, no need to take queued_bufs_lock, since all | ||
522 | * iso urbs have been killed when we're called so pwc_isoc_handler won't run. | ||
523 | */ | ||
524 | static void pwc_cleanup_queued_bufs(struct pwc_device *pdev) | ||
525 | { | ||
526 | while (!list_empty(&pdev->queued_bufs)) { | ||
527 | struct pwc_frame_buf *buf; | ||
528 | |||
529 | buf = list_entry(pdev->queued_bufs.next, struct pwc_frame_buf, | ||
530 | list); | ||
531 | list_del(&buf->list); | ||
532 | vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); | ||
533 | } | ||
534 | } | ||
535 | |||
941 | /********* | 536 | /********* |
942 | * sysfs | 537 | * sysfs |
943 | *********/ | 538 | *********/ |
@@ -1051,98 +646,15 @@ static const char *pwc_sensor_type_to_string(unsigned int sensor_type) | |||
1051 | 646 | ||
1052 | static int pwc_video_open(struct file *file) | 647 | static int pwc_video_open(struct file *file) |
1053 | { | 648 | { |
1054 | int i, ret; | ||
1055 | struct video_device *vdev = video_devdata(file); | 649 | struct video_device *vdev = video_devdata(file); |
1056 | struct pwc_device *pdev; | 650 | struct pwc_device *pdev; |
1057 | 651 | ||
1058 | PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev); | 652 | PWC_DEBUG_OPEN(">> video_open called(vdev = 0x%p).\n", vdev); |
1059 | 653 | ||
1060 | pdev = video_get_drvdata(vdev); | 654 | pdev = video_get_drvdata(vdev); |
1061 | BUG_ON(!pdev); | 655 | if (!pdev->udev) |
1062 | if (pdev->vopen) { | 656 | return -ENODEV; |
1063 | PWC_DEBUG_OPEN("I'm busy, someone is using the device.\n"); | ||
1064 | return -EBUSY; | ||
1065 | } | ||
1066 | |||
1067 | pwc_construct(pdev); /* set min/max sizes correct */ | ||
1068 | if (!pdev->usb_init) { | ||
1069 | PWC_DEBUG_OPEN("Doing first time initialization.\n"); | ||
1070 | pdev->usb_init = 1; | ||
1071 | |||
1072 | /* Query sensor type */ | ||
1073 | ret = pwc_get_cmos_sensor(pdev, &i); | ||
1074 | if (ret >= 0) | ||
1075 | { | ||
1076 | PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n", | ||
1077 | pdev->vdev.name, | ||
1078 | pwc_sensor_type_to_string(i), i); | ||
1079 | } | ||
1080 | } | ||
1081 | |||
1082 | /* Turn on camera */ | ||
1083 | if (power_save) { | ||
1084 | i = pwc_camera_power(pdev, 1); | ||
1085 | if (i < 0) | ||
1086 | PWC_DEBUG_OPEN("Failed to restore power to the camera! (%d)\n", i); | ||
1087 | } | ||
1088 | /* Set LED on/off time */ | ||
1089 | if (pwc_set_leds(pdev, led_on, led_off) < 0) | ||
1090 | PWC_DEBUG_OPEN("Failed to set LED on/off time.\n"); | ||
1091 | |||
1092 | |||
1093 | /* So far, so good. Allocate memory. */ | ||
1094 | i = pwc_allocate_buffers(pdev); | ||
1095 | if (i < 0) { | ||
1096 | PWC_DEBUG_OPEN("Failed to allocate buffers memory.\n"); | ||
1097 | pwc_free_buffers(pdev); | ||
1098 | return i; | ||
1099 | } | ||
1100 | |||
1101 | /* Reset buffers & parameters */ | ||
1102 | pwc_reset_buffers(pdev); | ||
1103 | for (i = 0; i < pwc_mbufs; i++) | ||
1104 | pdev->image_used[i] = 0; | ||
1105 | pdev->vframe_count = 0; | ||
1106 | pdev->vframes_dumped = 0; | ||
1107 | pdev->vframes_error = 0; | ||
1108 | pdev->visoc_errors = 0; | ||
1109 | pdev->error_status = 0; | ||
1110 | pwc_construct(pdev); /* set min/max sizes correct */ | ||
1111 | |||
1112 | /* Set some defaults */ | ||
1113 | pdev->vsnapshot = 0; | ||
1114 | |||
1115 | /* Set video size, first try the last used video size | ||
1116 | (or the default one); if that fails try QCIF/10 or QSIF/10; | ||
1117 | it that fails too, give up. | ||
1118 | */ | ||
1119 | i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0); | ||
1120 | if (i) { | ||
1121 | unsigned int default_resolution; | ||
1122 | PWC_DEBUG_OPEN("First attempt at set_video_mode failed.\n"); | ||
1123 | if (pdev->type>= 730) | ||
1124 | default_resolution = PSZ_QSIF; | ||
1125 | else | ||
1126 | default_resolution = PSZ_QCIF; | ||
1127 | |||
1128 | i = pwc_set_video_mode(pdev, | ||
1129 | pwc_image_sizes[default_resolution].x, | ||
1130 | pwc_image_sizes[default_resolution].y, | ||
1131 | 10, | ||
1132 | pdev->vcompression, | ||
1133 | 0); | ||
1134 | } | ||
1135 | if (i) { | ||
1136 | PWC_DEBUG_OPEN("Second attempt at set_video_mode failed.\n"); | ||
1137 | pwc_free_buffers(pdev); | ||
1138 | return i; | ||
1139 | } | ||
1140 | |||
1141 | /* Initialize the webcam to sane value */ | ||
1142 | pwc_set_brightness(pdev, 0x7fff); | ||
1143 | pwc_set_agc(pdev, 1, 0); | ||
1144 | 657 | ||
1145 | pdev->vopen++; | ||
1146 | file->private_data = vdev; | 658 | file->private_data = vdev; |
1147 | PWC_DEBUG_OPEN("<< video_open() returns 0.\n"); | 659 | PWC_DEBUG_OPEN("<< video_open() returns 0.\n"); |
1148 | return 0; | 660 | return 0; |
@@ -1158,239 +670,211 @@ static void pwc_video_release(struct video_device *vfd) | |||
1158 | if (device_hint[hint].pdev == pdev) | 670 | if (device_hint[hint].pdev == pdev) |
1159 | device_hint[hint].pdev = NULL; | 671 | device_hint[hint].pdev = NULL; |
1160 | 672 | ||
673 | /* Free intermediate decompression buffer & tables */ | ||
674 | if (pdev->decompress_data != NULL) { | ||
675 | PWC_DEBUG_MEMORY("Freeing decompression buffer at %p.\n", | ||
676 | pdev->decompress_data); | ||
677 | kfree(pdev->decompress_data); | ||
678 | pdev->decompress_data = NULL; | ||
679 | } | ||
680 | |||
681 | v4l2_ctrl_handler_free(&pdev->ctrl_handler); | ||
682 | |||
1161 | kfree(pdev); | 683 | kfree(pdev); |
1162 | } | 684 | } |
1163 | 685 | ||
1164 | /* Note that all cleanup is done in the reverse order as in _open */ | ||
1165 | static int pwc_video_close(struct file *file) | 686 | static int pwc_video_close(struct file *file) |
1166 | { | 687 | { |
1167 | struct video_device *vdev = file->private_data; | 688 | struct video_device *vdev = file->private_data; |
1168 | struct pwc_device *pdev; | 689 | struct pwc_device *pdev; |
1169 | int i; | ||
1170 | 690 | ||
1171 | PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev); | 691 | PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev); |
1172 | 692 | ||
1173 | pdev = video_get_drvdata(vdev); | 693 | pdev = video_get_drvdata(vdev); |
1174 | if (pdev->vopen == 0) | 694 | if (pdev->capt_file == file) { |
1175 | PWC_DEBUG_MODULE("video_close() called on closed device?\n"); | 695 | vb2_queue_release(&pdev->vb_queue); |
1176 | 696 | pdev->capt_file = NULL; | |
1177 | /* Dump statistics, but only if a reasonable amount of frames were | ||
1178 | processed (to prevent endless log-entries in case of snap-shot | ||
1179 | programs) | ||
1180 | */ | ||
1181 | if (pdev->vframe_count > 20) | ||
1182 | PWC_DEBUG_MODULE("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error); | ||
1183 | |||
1184 | if (DEVICE_USE_CODEC1(pdev->type)) | ||
1185 | pwc_dec1_exit(); | ||
1186 | else | ||
1187 | pwc_dec23_exit(); | ||
1188 | |||
1189 | pwc_isoc_cleanup(pdev); | ||
1190 | pwc_free_buffers(pdev); | ||
1191 | |||
1192 | /* Turn off LEDS and power down camera, but only when not unplugged */ | ||
1193 | if (!pdev->unplugged) { | ||
1194 | /* Turn LEDs off */ | ||
1195 | if (pwc_set_leds(pdev, 0, 0) < 0) | ||
1196 | PWC_DEBUG_MODULE("Failed to set LED on/off time.\n"); | ||
1197 | if (power_save) { | ||
1198 | i = pwc_camera_power(pdev, 0); | ||
1199 | if (i < 0) | ||
1200 | PWC_ERROR("Failed to power down camera (%d)\n", i); | ||
1201 | } | ||
1202 | pdev->vopen--; | ||
1203 | PWC_DEBUG_OPEN("<< video_close() vopen=%d\n", pdev->vopen); | ||
1204 | } | 697 | } |
1205 | 698 | ||
699 | PWC_DEBUG_OPEN("<< video_close()\n"); | ||
1206 | return 0; | 700 | return 0; |
1207 | } | 701 | } |
1208 | 702 | ||
1209 | /* | ||
1210 | * FIXME: what about two parallel reads ???? | ||
1211 | * ANSWER: Not supported. You can't open the device more than once, | ||
1212 | despite what the V4L1 interface says. First, I don't see | ||
1213 | the need, second there's no mechanism of alerting the | ||
1214 | 2nd/3rd/... process of events like changing image size. | ||
1215 | And I don't see the point of blocking that for the | ||
1216 | 2nd/3rd/... process. | ||
1217 | In multi-threaded environments reading parallel from any | ||
1218 | device is tricky anyhow. | ||
1219 | */ | ||
1220 | |||
1221 | static ssize_t pwc_video_read(struct file *file, char __user *buf, | 703 | static ssize_t pwc_video_read(struct file *file, char __user *buf, |
1222 | size_t count, loff_t *ppos) | 704 | size_t count, loff_t *ppos) |
1223 | { | 705 | { |
1224 | struct video_device *vdev = file->private_data; | 706 | struct video_device *vdev = file->private_data; |
1225 | struct pwc_device *pdev; | 707 | struct pwc_device *pdev = video_get_drvdata(vdev); |
1226 | int noblock = file->f_flags & O_NONBLOCK; | ||
1227 | DECLARE_WAITQUEUE(wait, current); | ||
1228 | int bytes_to_read, rv = 0; | ||
1229 | void *image_buffer_addr; | ||
1230 | |||
1231 | PWC_DEBUG_READ("pwc_video_read(vdev=0x%p, buf=%p, count=%zd) called.\n", | ||
1232 | vdev, buf, count); | ||
1233 | if (vdev == NULL) | ||
1234 | return -EFAULT; | ||
1235 | pdev = video_get_drvdata(vdev); | ||
1236 | if (pdev == NULL) | ||
1237 | return -EFAULT; | ||
1238 | 708 | ||
1239 | if (pdev->error_status) { | 709 | if (!pdev->udev) |
1240 | rv = -pdev->error_status; /* Something happened, report what. */ | 710 | return -ENODEV; |
1241 | goto err_out; | ||
1242 | } | ||
1243 | 711 | ||
1244 | /* Start the stream (if not already started) */ | 712 | if (pdev->capt_file != NULL && |
1245 | rv = pwc_isoc_init(pdev); | 713 | pdev->capt_file != file) |
1246 | if (rv) | 714 | return -EBUSY; |
1247 | goto err_out; | ||
1248 | |||
1249 | /* In case we're doing partial reads, we don't have to wait for a frame */ | ||
1250 | if (pdev->image_read_pos == 0) { | ||
1251 | /* Do wait queueing according to the (doc)book */ | ||
1252 | add_wait_queue(&pdev->frameq, &wait); | ||
1253 | while (pdev->full_frames == NULL) { | ||
1254 | /* Check for unplugged/etc. here */ | ||
1255 | if (pdev->error_status) { | ||
1256 | remove_wait_queue(&pdev->frameq, &wait); | ||
1257 | set_current_state(TASK_RUNNING); | ||
1258 | rv = -pdev->error_status ; | ||
1259 | goto err_out; | ||
1260 | } | ||
1261 | if (noblock) { | ||
1262 | remove_wait_queue(&pdev->frameq, &wait); | ||
1263 | set_current_state(TASK_RUNNING); | ||
1264 | rv = -EWOULDBLOCK; | ||
1265 | goto err_out; | ||
1266 | } | ||
1267 | if (signal_pending(current)) { | ||
1268 | remove_wait_queue(&pdev->frameq, &wait); | ||
1269 | set_current_state(TASK_RUNNING); | ||
1270 | rv = -ERESTARTSYS; | ||
1271 | goto err_out; | ||
1272 | } | ||
1273 | mutex_unlock(&pdev->modlock); | ||
1274 | schedule(); | ||
1275 | set_current_state(TASK_INTERRUPTIBLE); | ||
1276 | mutex_lock(&pdev->modlock); | ||
1277 | } | ||
1278 | remove_wait_queue(&pdev->frameq, &wait); | ||
1279 | set_current_state(TASK_RUNNING); | ||
1280 | 715 | ||
1281 | /* Decompress and release frame */ | 716 | pdev->capt_file = file; |
1282 | if (pwc_handle_frame(pdev)) { | ||
1283 | rv = -EFAULT; | ||
1284 | goto err_out; | ||
1285 | } | ||
1286 | } | ||
1287 | 717 | ||
1288 | PWC_DEBUG_READ("Copying data to user space.\n"); | 718 | return vb2_read(&pdev->vb_queue, buf, count, ppos, |
1289 | if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) | 719 | file->f_flags & O_NONBLOCK); |
1290 | bytes_to_read = pdev->frame_size + sizeof(struct pwc_raw_frame); | ||
1291 | else | ||
1292 | bytes_to_read = pdev->view.size; | ||
1293 | |||
1294 | /* copy bytes to user space; we allow for partial reads */ | ||
1295 | if (count + pdev->image_read_pos > bytes_to_read) | ||
1296 | count = bytes_to_read - pdev->image_read_pos; | ||
1297 | image_buffer_addr = pdev->image_data; | ||
1298 | image_buffer_addr += pdev->images[pdev->fill_image].offset; | ||
1299 | image_buffer_addr += pdev->image_read_pos; | ||
1300 | if (copy_to_user(buf, image_buffer_addr, count)) { | ||
1301 | rv = -EFAULT; | ||
1302 | goto err_out; | ||
1303 | } | ||
1304 | pdev->image_read_pos += count; | ||
1305 | if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */ | ||
1306 | pdev->image_read_pos = 0; | ||
1307 | pwc_next_image(pdev); | ||
1308 | } | ||
1309 | return count; | ||
1310 | err_out: | ||
1311 | return rv; | ||
1312 | } | 720 | } |
1313 | 721 | ||
1314 | static unsigned int pwc_video_poll(struct file *file, poll_table *wait) | 722 | static unsigned int pwc_video_poll(struct file *file, poll_table *wait) |
1315 | { | 723 | { |
1316 | struct video_device *vdev = file->private_data; | 724 | struct video_device *vdev = file->private_data; |
1317 | struct pwc_device *pdev; | 725 | struct pwc_device *pdev = video_get_drvdata(vdev); |
1318 | int ret; | ||
1319 | 726 | ||
1320 | if (vdev == NULL) | 727 | if (!pdev->udev) |
1321 | return -EFAULT; | 728 | return POLL_ERR; |
1322 | pdev = video_get_drvdata(vdev); | ||
1323 | if (pdev == NULL) | ||
1324 | return -EFAULT; | ||
1325 | 729 | ||
1326 | /* Start the stream (if not already started) */ | 730 | return vb2_poll(&pdev->vb_queue, file, wait); |
1327 | ret = pwc_isoc_init(pdev); | 731 | } |
1328 | if (ret) | 732 | |
1329 | return ret; | 733 | static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) |
734 | { | ||
735 | struct video_device *vdev = file->private_data; | ||
736 | struct pwc_device *pdev = video_get_drvdata(vdev); | ||
737 | |||
738 | if (pdev->capt_file != file) | ||
739 | return -EBUSY; | ||
740 | |||
741 | return vb2_mmap(&pdev->vb_queue, vma); | ||
742 | } | ||
743 | |||
744 | /***************************************************************************/ | ||
745 | /* Videobuf2 operations */ | ||
746 | |||
747 | static int queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, | ||
748 | unsigned int *nplanes, unsigned long sizes[], | ||
749 | void *alloc_ctxs[]) | ||
750 | { | ||
751 | struct pwc_device *pdev = vb2_get_drv_priv(vq); | ||
752 | |||
753 | if (*nbuffers < MIN_FRAMES) | ||
754 | *nbuffers = MIN_FRAMES; | ||
755 | else if (*nbuffers > MAX_FRAMES) | ||
756 | *nbuffers = MAX_FRAMES; | ||
757 | |||
758 | *nplanes = 1; | ||
1330 | 759 | ||
1331 | poll_wait(file, &pdev->frameq, wait); | 760 | sizes[0] = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2); |
1332 | if (pdev->error_status) | ||
1333 | return POLLERR; | ||
1334 | if (pdev->full_frames != NULL) /* we have frames waiting */ | ||
1335 | return (POLLIN | POLLRDNORM); | ||
1336 | 761 | ||
1337 | return 0; | 762 | return 0; |
1338 | } | 763 | } |
1339 | 764 | ||
1340 | static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) | 765 | static int buffer_init(struct vb2_buffer *vb) |
1341 | { | 766 | { |
1342 | struct video_device *vdev = file->private_data; | 767 | struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb); |
1343 | struct pwc_device *pdev; | ||
1344 | unsigned long start; | ||
1345 | unsigned long size; | ||
1346 | unsigned long page, pos = 0; | ||
1347 | int index; | ||
1348 | 768 | ||
1349 | PWC_DEBUG_MEMORY(">> %s\n", __func__); | 769 | /* need vmalloc since frame buffer > 128K */ |
1350 | pdev = video_get_drvdata(vdev); | 770 | buf->data = vzalloc(PWC_FRAME_SIZE); |
1351 | size = vma->vm_end - vma->vm_start; | 771 | if (buf->data == NULL) |
1352 | start = vma->vm_start; | 772 | return -ENOMEM; |
1353 | 773 | ||
1354 | /* Find the idx buffer for this mapping */ | 774 | return 0; |
1355 | for (index = 0; index < pwc_mbufs; index++) { | 775 | } |
1356 | pos = pdev->images[index].offset; | 776 | |
1357 | if ((pos>>PAGE_SHIFT) == vma->vm_pgoff) | 777 | static int buffer_prepare(struct vb2_buffer *vb) |
1358 | break; | 778 | { |
779 | struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue); | ||
780 | |||
781 | /* Don't allow queing new buffers after device disconnection */ | ||
782 | if (!pdev->udev) | ||
783 | return -ENODEV; | ||
784 | |||
785 | return 0; | ||
786 | } | ||
787 | |||
788 | static int buffer_finish(struct vb2_buffer *vb) | ||
789 | { | ||
790 | struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue); | ||
791 | struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb); | ||
792 | |||
793 | /* | ||
794 | * Application has called dqbuf and is getting back a buffer we've | ||
795 | * filled, take the pwc data we've stored in buf->data and decompress | ||
796 | * it into a usable format, storing the result in the vb2_buffer | ||
797 | */ | ||
798 | return pwc_decompress(pdev, buf); | ||
799 | } | ||
800 | |||
801 | static void buffer_cleanup(struct vb2_buffer *vb) | ||
802 | { | ||
803 | struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb); | ||
804 | |||
805 | vfree(buf->data); | ||
806 | } | ||
807 | |||
808 | static void buffer_queue(struct vb2_buffer *vb) | ||
809 | { | ||
810 | struct pwc_device *pdev = vb2_get_drv_priv(vb->vb2_queue); | ||
811 | struct pwc_frame_buf *buf = container_of(vb, struct pwc_frame_buf, vb); | ||
812 | unsigned long flags = 0; | ||
813 | |||
814 | spin_lock_irqsave(&pdev->queued_bufs_lock, flags); | ||
815 | list_add_tail(&buf->list, &pdev->queued_bufs); | ||
816 | spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags); | ||
817 | } | ||
818 | |||
819 | static int start_streaming(struct vb2_queue *vq) | ||
820 | { | ||
821 | struct pwc_device *pdev = vb2_get_drv_priv(vq); | ||
822 | |||
823 | if (!pdev->udev) | ||
824 | return -ENODEV; | ||
825 | |||
826 | /* Turn on camera and set LEDS on */ | ||
827 | pwc_camera_power(pdev, 1); | ||
828 | if (pdev->power_save) { | ||
829 | /* Restore video mode */ | ||
830 | pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, | ||
831 | pdev->vframes, pdev->vcompression, | ||
832 | pdev->vsnapshot); | ||
1359 | } | 833 | } |
1360 | if (index == MAX_IMAGES) | 834 | pwc_set_leds(pdev, led_on, led_off); |
1361 | return -EINVAL; | 835 | |
1362 | if (index == 0) { | 836 | return pwc_isoc_init(pdev); |
1363 | /* | 837 | } |
1364 | * Special case for v4l1. In v4l1, we map only one big buffer, | 838 | |
1365 | * but in v4l2 each buffer is mapped | 839 | static int stop_streaming(struct vb2_queue *vq) |
1366 | */ | 840 | { |
1367 | unsigned long total_size; | 841 | struct pwc_device *pdev = vb2_get_drv_priv(vq); |
1368 | total_size = pwc_mbufs * pdev->len_per_image; | 842 | |
1369 | if (size != pdev->len_per_image && size != total_size) { | 843 | if (pdev->udev) { |
1370 | PWC_ERROR("Wrong size (%lu) needed to be len_per_image=%d or total_size=%lu\n", | 844 | pwc_set_leds(pdev, 0, 0); |
1371 | size, pdev->len_per_image, total_size); | 845 | pwc_camera_power(pdev, 0); |
1372 | return -EINVAL; | 846 | pwc_isoc_cleanup(pdev); |
1373 | } | ||
1374 | } else if (size > pdev->len_per_image) | ||
1375 | return -EINVAL; | ||
1376 | |||
1377 | vma->vm_flags |= VM_IO; /* from 2.6.9-acX */ | ||
1378 | |||
1379 | pos += (unsigned long)pdev->image_data; | ||
1380 | while (size > 0) { | ||
1381 | page = vmalloc_to_pfn((void *)pos); | ||
1382 | if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) | ||
1383 | return -EAGAIN; | ||
1384 | start += PAGE_SIZE; | ||
1385 | pos += PAGE_SIZE; | ||
1386 | if (size > PAGE_SIZE) | ||
1387 | size -= PAGE_SIZE; | ||
1388 | else | ||
1389 | size = 0; | ||
1390 | } | 847 | } |
848 | pwc_cleanup_queued_bufs(pdev); | ||
849 | |||
1391 | return 0; | 850 | return 0; |
1392 | } | 851 | } |
1393 | 852 | ||
853 | static void pwc_lock(struct vb2_queue *vq) | ||
854 | { | ||
855 | struct pwc_device *pdev = vb2_get_drv_priv(vq); | ||
856 | mutex_lock(&pdev->modlock); | ||
857 | } | ||
858 | |||
859 | static void pwc_unlock(struct vb2_queue *vq) | ||
860 | { | ||
861 | struct pwc_device *pdev = vb2_get_drv_priv(vq); | ||
862 | mutex_unlock(&pdev->modlock); | ||
863 | } | ||
864 | |||
865 | static struct vb2_ops pwc_vb_queue_ops = { | ||
866 | .queue_setup = queue_setup, | ||
867 | .buf_init = buffer_init, | ||
868 | .buf_prepare = buffer_prepare, | ||
869 | .buf_finish = buffer_finish, | ||
870 | .buf_cleanup = buffer_cleanup, | ||
871 | .buf_queue = buffer_queue, | ||
872 | .start_streaming = start_streaming, | ||
873 | .stop_streaming = stop_streaming, | ||
874 | .wait_prepare = pwc_unlock, | ||
875 | .wait_finish = pwc_lock, | ||
876 | }; | ||
877 | |||
1394 | /***************************************************************************/ | 878 | /***************************************************************************/ |
1395 | /* USB functions */ | 879 | /* USB functions */ |
1396 | 880 | ||
@@ -1406,6 +890,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1406 | int hint, rc; | 890 | int hint, rc; |
1407 | int features = 0; | 891 | int features = 0; |
1408 | int video_nr = -1; /* default: use next available device */ | 892 | int video_nr = -1; /* default: use next available device */ |
893 | int my_power_save = power_save; | ||
1409 | char serial_number[30], *name; | 894 | char serial_number[30], *name; |
1410 | 895 | ||
1411 | vendor_id = le16_to_cpu(udev->descriptor.idVendor); | 896 | vendor_id = le16_to_cpu(udev->descriptor.idVendor); |
@@ -1513,6 +998,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1513 | PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n"); | 998 | PWC_INFO("Logitech QuickCam 4000 Pro USB webcam detected.\n"); |
1514 | name = "Logitech QuickCam Pro 4000"; | 999 | name = "Logitech QuickCam Pro 4000"; |
1515 | type_id = 740; /* CCD sensor */ | 1000 | type_id = 740; /* CCD sensor */ |
1001 | if (my_power_save == -1) | ||
1002 | my_power_save = 1; | ||
1516 | break; | 1003 | break; |
1517 | case 0x08b3: | 1004 | case 0x08b3: |
1518 | PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n"); | 1005 | PWC_INFO("Logitech QuickCam Zoom USB webcam detected.\n"); |
@@ -1523,12 +1010,15 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1523 | PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n"); | 1010 | PWC_INFO("Logitech QuickCam Zoom (new model) USB webcam detected.\n"); |
1524 | name = "Logitech QuickCam Zoom"; | 1011 | name = "Logitech QuickCam Zoom"; |
1525 | type_id = 740; /* CCD sensor */ | 1012 | type_id = 740; /* CCD sensor */ |
1526 | power_save = 1; | 1013 | if (my_power_save == -1) |
1014 | my_power_save = 1; | ||
1527 | break; | 1015 | break; |
1528 | case 0x08b5: | 1016 | case 0x08b5: |
1529 | PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n"); | 1017 | PWC_INFO("Logitech QuickCam Orbit/Sphere USB webcam detected.\n"); |
1530 | name = "Logitech QuickCam Orbit"; | 1018 | name = "Logitech QuickCam Orbit"; |
1531 | type_id = 740; /* CCD sensor */ | 1019 | type_id = 740; /* CCD sensor */ |
1020 | if (my_power_save == -1) | ||
1021 | my_power_save = 1; | ||
1532 | features |= FEATURE_MOTOR_PANTILT; | 1022 | features |= FEATURE_MOTOR_PANTILT; |
1533 | break; | 1023 | break; |
1534 | case 0x08b6: | 1024 | case 0x08b6: |
@@ -1583,6 +1073,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1583 | PWC_INFO("Creative Labs Webcam 5 detected.\n"); | 1073 | PWC_INFO("Creative Labs Webcam 5 detected.\n"); |
1584 | name = "Creative Labs Webcam 5"; | 1074 | name = "Creative Labs Webcam 5"; |
1585 | type_id = 730; | 1075 | type_id = 730; |
1076 | if (my_power_save == -1) | ||
1077 | my_power_save = 1; | ||
1586 | break; | 1078 | break; |
1587 | case 0x4011: | 1079 | case 0x4011: |
1588 | PWC_INFO("Creative Labs Webcam Pro Ex detected.\n"); | 1080 | PWC_INFO("Creative Labs Webcam Pro Ex detected.\n"); |
@@ -1640,6 +1132,9 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1640 | else | 1132 | else |
1641 | return -ENODEV; /* Not any of the know types; but the list keeps growing. */ | 1133 | return -ENODEV; /* Not any of the know types; but the list keeps growing. */ |
1642 | 1134 | ||
1135 | if (my_power_save == -1) | ||
1136 | my_power_save = 0; | ||
1137 | |||
1643 | memset(serial_number, 0, 30); | 1138 | memset(serial_number, 0, 30); |
1644 | usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29); | 1139 | usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29); |
1645 | PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number); | 1140 | PWC_DEBUG_PROBE("Device serial number is %s\n", serial_number); |
@@ -1654,7 +1149,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1654 | return -ENOMEM; | 1149 | return -ENOMEM; |
1655 | } | 1150 | } |
1656 | pdev->type = type_id; | 1151 | pdev->type = type_id; |
1657 | pdev->vsize = default_size; | ||
1658 | pdev->vframes = default_fps; | 1152 | pdev->vframes = default_fps; |
1659 | strcpy(pdev->serial, serial_number); | 1153 | strcpy(pdev->serial, serial_number); |
1660 | pdev->features = features; | 1154 | pdev->features = features; |
@@ -1668,13 +1162,26 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1668 | pdev->angle_range.tilt_min = -3000; | 1162 | pdev->angle_range.tilt_min = -3000; |
1669 | pdev->angle_range.tilt_max = 2500; | 1163 | pdev->angle_range.tilt_max = 2500; |
1670 | } | 1164 | } |
1165 | pwc_construct(pdev); /* set min/max sizes correct */ | ||
1671 | 1166 | ||
1672 | mutex_init(&pdev->modlock); | 1167 | mutex_init(&pdev->modlock); |
1673 | spin_lock_init(&pdev->ptrlock); | 1168 | mutex_init(&pdev->udevlock); |
1169 | spin_lock_init(&pdev->queued_bufs_lock); | ||
1170 | INIT_LIST_HEAD(&pdev->queued_bufs); | ||
1674 | 1171 | ||
1675 | pdev->udev = udev; | 1172 | pdev->udev = udev; |
1676 | init_waitqueue_head(&pdev->frameq); | ||
1677 | pdev->vcompression = pwc_preferred_compression; | 1173 | pdev->vcompression = pwc_preferred_compression; |
1174 | pdev->power_save = my_power_save; | ||
1175 | |||
1176 | /* Init videobuf2 queue structure */ | ||
1177 | memset(&pdev->vb_queue, 0, sizeof(pdev->vb_queue)); | ||
1178 | pdev->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
1179 | pdev->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; | ||
1180 | pdev->vb_queue.drv_priv = pdev; | ||
1181 | pdev->vb_queue.buf_struct_size = sizeof(struct pwc_frame_buf); | ||
1182 | pdev->vb_queue.ops = &pwc_vb_queue_ops; | ||
1183 | pdev->vb_queue.mem_ops = &vb2_vmalloc_memops; | ||
1184 | vb2_queue_init(&pdev->vb_queue); | ||
1678 | 1185 | ||
1679 | /* Init video_device structure */ | 1186 | /* Init video_device structure */ |
1680 | memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template)); | 1187 | memcpy(&pdev->vdev, &pwc_template, sizeof(pwc_template)); |
@@ -1707,14 +1214,40 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1707 | PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev); | 1214 | PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev); |
1708 | usb_set_intfdata(intf, pdev); | 1215 | usb_set_intfdata(intf, pdev); |
1709 | 1216 | ||
1217 | #ifdef CONFIG_USB_PWC_DEBUG | ||
1218 | /* Query sensor type */ | ||
1219 | if (pwc_get_cmos_sensor(pdev, &rc) >= 0) { | ||
1220 | PWC_DEBUG_OPEN("This %s camera is equipped with a %s (%d).\n", | ||
1221 | pdev->vdev.name, | ||
1222 | pwc_sensor_type_to_string(rc), rc); | ||
1223 | } | ||
1224 | #endif | ||
1225 | |||
1710 | /* Set the leds off */ | 1226 | /* Set the leds off */ |
1711 | pwc_set_leds(pdev, 0, 0); | 1227 | pwc_set_leds(pdev, 0, 0); |
1228 | |||
1229 | /* Setup intial videomode */ | ||
1230 | rc = pwc_set_video_mode(pdev, pdev->view_max.x, pdev->view_max.y, | ||
1231 | pdev->vframes, pdev->vcompression, 0); | ||
1232 | if (rc) | ||
1233 | goto err_free_mem; | ||
1234 | |||
1235 | /* Register controls (and read default values from camera */ | ||
1236 | rc = pwc_init_controls(pdev); | ||
1237 | if (rc) { | ||
1238 | PWC_ERROR("Failed to register v4l2 controls (%d).\n", rc); | ||
1239 | goto err_free_mem; | ||
1240 | } | ||
1241 | |||
1242 | pdev->vdev.ctrl_handler = &pdev->ctrl_handler; | ||
1243 | |||
1244 | /* And powerdown the camera until streaming starts */ | ||
1712 | pwc_camera_power(pdev, 0); | 1245 | pwc_camera_power(pdev, 0); |
1713 | 1246 | ||
1714 | rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr); | 1247 | rc = video_register_device(&pdev->vdev, VFL_TYPE_GRABBER, video_nr); |
1715 | if (rc < 0) { | 1248 | if (rc < 0) { |
1716 | PWC_ERROR("Failed to register as video device (%d).\n", rc); | 1249 | PWC_ERROR("Failed to register as video device (%d).\n", rc); |
1717 | goto err_free_mem; | 1250 | goto err_free_controls; |
1718 | } | 1251 | } |
1719 | rc = pwc_create_sysfs_files(pdev); | 1252 | rc = pwc_create_sysfs_files(pdev); |
1720 | if (rc) | 1253 | if (rc) |
@@ -1757,7 +1290,10 @@ err_video_unreg: | |||
1757 | if (hint < MAX_DEV_HINTS) | 1290 | if (hint < MAX_DEV_HINTS) |
1758 | device_hint[hint].pdev = NULL; | 1291 | device_hint[hint].pdev = NULL; |
1759 | video_unregister_device(&pdev->vdev); | 1292 | video_unregister_device(&pdev->vdev); |
1293 | err_free_controls: | ||
1294 | v4l2_ctrl_handler_free(&pdev->ctrl_handler); | ||
1760 | err_free_mem: | 1295 | err_free_mem: |
1296 | usb_set_intfdata(intf, NULL); | ||
1761 | kfree(pdev); | 1297 | kfree(pdev); |
1762 | return rc; | 1298 | return rc; |
1763 | } | 1299 | } |
@@ -1767,33 +1303,17 @@ static void usb_pwc_disconnect(struct usb_interface *intf) | |||
1767 | { | 1303 | { |
1768 | struct pwc_device *pdev = usb_get_intfdata(intf); | 1304 | struct pwc_device *pdev = usb_get_intfdata(intf); |
1769 | 1305 | ||
1306 | mutex_lock(&pdev->udevlock); | ||
1770 | mutex_lock(&pdev->modlock); | 1307 | mutex_lock(&pdev->modlock); |
1771 | usb_set_intfdata (intf, NULL); | ||
1772 | if (pdev == NULL) { | ||
1773 | PWC_ERROR("pwc_disconnect() Called without private pointer.\n"); | ||
1774 | goto disconnect_out; | ||
1775 | } | ||
1776 | if (pdev->udev == NULL) { | ||
1777 | PWC_ERROR("pwc_disconnect() already called for %p\n", pdev); | ||
1778 | goto disconnect_out; | ||
1779 | } | ||
1780 | if (pdev->udev != interface_to_usbdev(intf)) { | ||
1781 | PWC_ERROR("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n"); | ||
1782 | goto disconnect_out; | ||
1783 | } | ||
1784 | |||
1785 | /* We got unplugged; this is signalled by an EPIPE error code */ | ||
1786 | pdev->error_status = EPIPE; | ||
1787 | pdev->unplugged = 1; | ||
1788 | |||
1789 | /* Alert waiting processes */ | ||
1790 | wake_up_interruptible(&pdev->frameq); | ||
1791 | 1308 | ||
1309 | usb_set_intfdata(intf, NULL); | ||
1792 | /* No need to keep the urbs around after disconnection */ | 1310 | /* No need to keep the urbs around after disconnection */ |
1793 | pwc_isoc_cleanup(pdev); | 1311 | pwc_isoc_cleanup(pdev); |
1312 | pwc_cleanup_queued_bufs(pdev); | ||
1313 | pdev->udev = NULL; | ||
1794 | 1314 | ||
1795 | disconnect_out: | ||
1796 | mutex_unlock(&pdev->modlock); | 1315 | mutex_unlock(&pdev->modlock); |
1316 | mutex_unlock(&pdev->udevlock); | ||
1797 | 1317 | ||
1798 | pwc_remove_sysfs_files(pdev); | 1318 | pwc_remove_sysfs_files(pdev); |
1799 | video_unregister_device(&pdev->vdev); | 1319 | video_unregister_device(&pdev->vdev); |
@@ -1809,36 +1329,27 @@ disconnect_out: | |||
1809 | * Initialization code & module stuff | 1329 | * Initialization code & module stuff |
1810 | */ | 1330 | */ |
1811 | 1331 | ||
1812 | static char *size; | ||
1813 | static int fps; | 1332 | static int fps; |
1814 | static int fbufs; | ||
1815 | static int mbufs; | ||
1816 | static int compression = -1; | 1333 | static int compression = -1; |
1817 | static int leds[2] = { -1, -1 }; | 1334 | static int leds[2] = { -1, -1 }; |
1818 | static unsigned int leds_nargs; | 1335 | static unsigned int leds_nargs; |
1819 | static char *dev_hint[MAX_DEV_HINTS]; | 1336 | static char *dev_hint[MAX_DEV_HINTS]; |
1820 | static unsigned int dev_hint_nargs; | 1337 | static unsigned int dev_hint_nargs; |
1821 | 1338 | ||
1822 | module_param(size, charp, 0444); | ||
1823 | module_param(fps, int, 0444); | 1339 | module_param(fps, int, 0444); |
1824 | module_param(fbufs, int, 0444); | ||
1825 | module_param(mbufs, int, 0444); | ||
1826 | #ifdef CONFIG_USB_PWC_DEBUG | 1340 | #ifdef CONFIG_USB_PWC_DEBUG |
1827 | module_param_named(trace, pwc_trace, int, 0644); | 1341 | module_param_named(trace, pwc_trace, int, 0644); |
1828 | #endif | 1342 | #endif |
1829 | module_param(power_save, int, 0444); | 1343 | module_param(power_save, int, 0644); |
1830 | module_param(compression, int, 0444); | 1344 | module_param(compression, int, 0444); |
1831 | module_param_array(leds, int, &leds_nargs, 0444); | 1345 | module_param_array(leds, int, &leds_nargs, 0444); |
1832 | module_param_array(dev_hint, charp, &dev_hint_nargs, 0444); | 1346 | module_param_array(dev_hint, charp, &dev_hint_nargs, 0444); |
1833 | 1347 | ||
1834 | MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga"); | ||
1835 | MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30"); | 1348 | MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30"); |
1836 | MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve"); | ||
1837 | MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers"); | ||
1838 | #ifdef CONFIG_USB_PWC_DEBUG | 1349 | #ifdef CONFIG_USB_PWC_DEBUG |
1839 | MODULE_PARM_DESC(trace, "For debugging purposes"); | 1350 | MODULE_PARM_DESC(trace, "For debugging purposes"); |
1840 | #endif | 1351 | #endif |
1841 | MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off"); | 1352 | MODULE_PARM_DESC(power_save, "Turn power saving for new cameras on or off"); |
1842 | MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"); | 1353 | MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"); |
1843 | MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); | 1354 | MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); |
1844 | MODULE_PARM_DESC(dev_hint, "Device node hints"); | 1355 | MODULE_PARM_DESC(dev_hint, "Device node hints"); |
@@ -1851,14 +1362,19 @@ MODULE_VERSION( PWC_VERSION ); | |||
1851 | 1362 | ||
1852 | static int __init usb_pwc_init(void) | 1363 | static int __init usb_pwc_init(void) |
1853 | { | 1364 | { |
1854 | int i, sz; | 1365 | int i; |
1855 | char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" }; | ||
1856 | 1366 | ||
1367 | #ifdef CONFIG_USB_PWC_DEBUG | ||
1857 | PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n"); | 1368 | PWC_INFO("Philips webcam module version " PWC_VERSION " loaded.\n"); |
1858 | PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n"); | 1369 | PWC_INFO("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n"); |
1859 | PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n"); | 1370 | PWC_INFO("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n"); |
1860 | PWC_INFO("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n"); | 1371 | PWC_INFO("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n"); |
1861 | 1372 | ||
1373 | if (pwc_trace >= 0) { | ||
1374 | PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace); | ||
1375 | } | ||
1376 | #endif | ||
1377 | |||
1862 | if (fps) { | 1378 | if (fps) { |
1863 | if (fps < 4 || fps > 30) { | 1379 | if (fps < 4 || fps > 30) { |
1864 | PWC_ERROR("Framerate out of bounds (4-30).\n"); | 1380 | PWC_ERROR("Framerate out of bounds (4-30).\n"); |
@@ -1868,41 +1384,6 @@ static int __init usb_pwc_init(void) | |||
1868 | PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps); | 1384 | PWC_DEBUG_MODULE("Default framerate set to %d.\n", default_fps); |
1869 | } | 1385 | } |
1870 | 1386 | ||
1871 | if (size) { | ||
1872 | /* string; try matching with array */ | ||
1873 | for (sz = 0; sz < PSZ_MAX; sz++) { | ||
1874 | if (!strcmp(sizenames[sz], size)) { /* Found! */ | ||
1875 | default_size = sz; | ||
1876 | break; | ||
1877 | } | ||
1878 | } | ||
1879 | if (sz == PSZ_MAX) { | ||
1880 | PWC_ERROR("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n"); | ||
1881 | return -EINVAL; | ||
1882 | } | ||
1883 | PWC_DEBUG_MODULE("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y); | ||
1884 | } | ||
1885 | if (mbufs) { | ||
1886 | if (mbufs < 1 || mbufs > MAX_IMAGES) { | ||
1887 | PWC_ERROR("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES); | ||
1888 | return -EINVAL; | ||
1889 | } | ||
1890 | pwc_mbufs = mbufs; | ||
1891 | PWC_DEBUG_MODULE("Number of image buffers set to %d.\n", pwc_mbufs); | ||
1892 | } | ||
1893 | if (fbufs) { | ||
1894 | if (fbufs < 2 || fbufs > MAX_FRAMES) { | ||
1895 | PWC_ERROR("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES); | ||
1896 | return -EINVAL; | ||
1897 | } | ||
1898 | default_fbufs = fbufs; | ||
1899 | PWC_DEBUG_MODULE("Number of frame buffers set to %d.\n", default_fbufs); | ||
1900 | } | ||
1901 | #ifdef CONFIG_USB_PWC_DEBUG | ||
1902 | if (pwc_trace >= 0) { | ||
1903 | PWC_DEBUG_MODULE("Trace options: 0x%04x\n", pwc_trace); | ||
1904 | } | ||
1905 | #endif | ||
1906 | if (compression >= 0) { | 1387 | if (compression >= 0) { |
1907 | if (compression > 3) { | 1388 | if (compression > 3) { |
1908 | PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n"); | 1389 | PWC_ERROR("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n"); |
@@ -1911,8 +1392,6 @@ static int __init usb_pwc_init(void) | |||
1911 | pwc_preferred_compression = compression; | 1392 | pwc_preferred_compression = compression; |
1912 | PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression); | 1393 | PWC_DEBUG_MODULE("Preferred compression set to %d.\n", pwc_preferred_compression); |
1913 | } | 1394 | } |
1914 | if (power_save) | ||
1915 | PWC_DEBUG_MODULE("Enabling power save on open/close.\n"); | ||
1916 | if (leds[0] >= 0) | 1395 | if (leds[0] >= 0) |
1917 | led_on = leds[0]; | 1396 | led_on = leds[0]; |
1918 | if (leds[1] >= 0) | 1397 | if (leds[1] >= 0) |
diff --git a/drivers/media/video/pwc/pwc-ioctl.h b/drivers/media/video/pwc/pwc-ioctl.h deleted file mode 100644 index 8c0cae7b3daf..000000000000 --- a/drivers/media/video/pwc/pwc-ioctl.h +++ /dev/null | |||
@@ -1,323 +0,0 @@ | |||
1 | #ifndef PWC_IOCTL_H | ||
2 | #define PWC_IOCTL_H | ||
3 | |||
4 | /* (C) 2001-2004 Nemosoft Unv. | ||
5 | (C) 2004-2006 Luc Saillard (luc@saillard.org) | ||
6 | |||
7 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
8 | driver and thus may have bugs that are not present in the original version. | ||
9 | Please send bug reports and support requests to <luc@saillard.org>. | ||
10 | The decompression routines have been implemented by reverse-engineering the | ||
11 | Nemosoft binary pwcx module. Caveat emptor. | ||
12 | |||
13 | This program is free software; you can redistribute it and/or modify | ||
14 | it under the terms of the GNU General Public License as published by | ||
15 | the Free Software Foundation; either version 2 of the License, or | ||
16 | (at your option) any later version. | ||
17 | |||
18 | This program is distributed in the hope that it will be useful, | ||
19 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
21 | GNU General Public License for more details. | ||
22 | |||
23 | You should have received a copy of the GNU General Public License | ||
24 | along with this program; if not, write to the Free Software | ||
25 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
26 | */ | ||
27 | |||
28 | /* This is pwc-ioctl.h belonging to PWC 10.0.10 | ||
29 | It contains structures and defines to communicate from user space | ||
30 | directly to the driver. | ||
31 | */ | ||
32 | |||
33 | /* | ||
34 | Changes | ||
35 | 2001/08/03 Alvarado Added ioctl constants to access methods for | ||
36 | changing white balance and red/blue gains | ||
37 | 2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE | ||
38 | 2003/12/13 Nemosft Unv. Some modifications to make interfacing to | ||
39 | PWCX easier | ||
40 | */ | ||
41 | |||
42 | /* These are private ioctl() commands, specific for the Philips webcams. | ||
43 | They contain functions not found in other webcams, and settings not | ||
44 | specified in the Video4Linux API. | ||
45 | |||
46 | The #define names are built up like follows: | ||
47 | VIDIOC VIDeo IOCtl prefix | ||
48 | PWC Philps WebCam | ||
49 | G optional: Get | ||
50 | S optional: Set | ||
51 | ... the function | ||
52 | */ | ||
53 | |||
54 | #include <linux/types.h> | ||
55 | #include <linux/version.h> | ||
56 | |||
57 | /* Enumeration of image sizes */ | ||
58 | #define PSZ_SQCIF 0x00 | ||
59 | #define PSZ_QSIF 0x01 | ||
60 | #define PSZ_QCIF 0x02 | ||
61 | #define PSZ_SIF 0x03 | ||
62 | #define PSZ_CIF 0x04 | ||
63 | #define PSZ_VGA 0x05 | ||
64 | #define PSZ_MAX 6 | ||
65 | |||
66 | |||
67 | /* The frame rate is encoded in the video_window.flags parameter using | ||
68 | the upper 16 bits, since some flags are defined nowadays. The following | ||
69 | defines provide a mask and shift to filter out this value. | ||
70 | This value can also be passing using the private flag when using v4l2 and | ||
71 | VIDIOC_S_FMT ioctl. | ||
72 | |||
73 | In 'Snapshot' mode the camera freezes its automatic exposure and colour | ||
74 | balance controls. | ||
75 | */ | ||
76 | #define PWC_FPS_SHIFT 16 | ||
77 | #define PWC_FPS_MASK 0x00FF0000 | ||
78 | #define PWC_FPS_FRMASK 0x003F0000 | ||
79 | #define PWC_FPS_SNAPSHOT 0x00400000 | ||
80 | #define PWC_QLT_MASK 0x03000000 | ||
81 | #define PWC_QLT_SHIFT 24 | ||
82 | |||
83 | |||
84 | /* structure for transferring x & y coordinates */ | ||
85 | struct pwc_coord | ||
86 | { | ||
87 | int x, y; /* guess what */ | ||
88 | int size; /* size, or offset */ | ||
89 | }; | ||
90 | |||
91 | |||
92 | /* Used with VIDIOCPWCPROBE */ | ||
93 | struct pwc_probe | ||
94 | { | ||
95 | char name[32]; | ||
96 | int type; | ||
97 | }; | ||
98 | |||
99 | struct pwc_serial | ||
100 | { | ||
101 | char serial[30]; /* String with serial number. Contains terminating 0 */ | ||
102 | }; | ||
103 | |||
104 | /* pwc_whitebalance.mode values */ | ||
105 | #define PWC_WB_INDOOR 0 | ||
106 | #define PWC_WB_OUTDOOR 1 | ||
107 | #define PWC_WB_FL 2 | ||
108 | #define PWC_WB_MANUAL 3 | ||
109 | #define PWC_WB_AUTO 4 | ||
110 | |||
111 | /* Used with VIDIOCPWC[SG]AWB (Auto White Balance). | ||
112 | Set mode to one of the PWC_WB_* values above. | ||
113 | *red and *blue are the respective gains of these colour components inside | ||
114 | the camera; range 0..65535 | ||
115 | When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; | ||
116 | otherwise undefined. | ||
117 | 'read_red' and 'read_blue' are read-only. | ||
118 | */ | ||
119 | struct pwc_whitebalance | ||
120 | { | ||
121 | int mode; | ||
122 | int manual_red, manual_blue; /* R/W */ | ||
123 | int read_red, read_blue; /* R/O */ | ||
124 | }; | ||
125 | |||
126 | /* | ||
127 | 'control_speed' and 'control_delay' are used in automatic whitebalance mode, | ||
128 | and tell the camera how fast it should react to changes in lighting, and | ||
129 | with how much delay. Valid values are 0..65535. | ||
130 | */ | ||
131 | struct pwc_wb_speed | ||
132 | { | ||
133 | int control_speed; | ||
134 | int control_delay; | ||
135 | |||
136 | }; | ||
137 | |||
138 | /* Used with VIDIOCPWC[SG]LED */ | ||
139 | struct pwc_leds | ||
140 | { | ||
141 | int led_on; /* Led on-time; range = 0..25000 */ | ||
142 | int led_off; /* Led off-time; range = 0..25000 */ | ||
143 | }; | ||
144 | |||
145 | /* Image size (used with GREALSIZE) */ | ||
146 | struct pwc_imagesize | ||
147 | { | ||
148 | int width; | ||
149 | int height; | ||
150 | }; | ||
151 | |||
152 | /* Defines and structures for Motorized Pan & Tilt */ | ||
153 | #define PWC_MPT_PAN 0x01 | ||
154 | #define PWC_MPT_TILT 0x02 | ||
155 | #define PWC_MPT_TIMEOUT 0x04 /* for status */ | ||
156 | |||
157 | /* Set angles; when absolute != 0, the angle is absolute and the | ||
158 | driver calculates the relative offset for you. This can only | ||
159 | be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns | ||
160 | absolute angles. | ||
161 | */ | ||
162 | struct pwc_mpt_angles | ||
163 | { | ||
164 | int absolute; /* write-only */ | ||
165 | int pan; /* degrees * 100 */ | ||
166 | int tilt; /* degress * 100 */ | ||
167 | }; | ||
168 | |||
169 | /* Range of angles of the camera, both horizontally and vertically. | ||
170 | */ | ||
171 | struct pwc_mpt_range | ||
172 | { | ||
173 | int pan_min, pan_max; /* degrees * 100 */ | ||
174 | int tilt_min, tilt_max; | ||
175 | }; | ||
176 | |||
177 | struct pwc_mpt_status | ||
178 | { | ||
179 | int status; | ||
180 | int time_pan; | ||
181 | int time_tilt; | ||
182 | }; | ||
183 | |||
184 | |||
185 | /* This is used for out-of-kernel decompression. With it, you can get | ||
186 | all the necessary information to initialize and use the decompressor | ||
187 | routines in standalone applications. | ||
188 | */ | ||
189 | struct pwc_video_command | ||
190 | { | ||
191 | int type; /* camera type (645, 675, 730, etc.) */ | ||
192 | int release; /* release number */ | ||
193 | |||
194 | int size; /* one of PSZ_* */ | ||
195 | int alternate; | ||
196 | int command_len; /* length of USB video command */ | ||
197 | unsigned char command_buf[13]; /* Actual USB video command */ | ||
198 | int bandlength; /* >0 = compressed */ | ||
199 | int frame_size; /* Size of one (un)compressed frame */ | ||
200 | }; | ||
201 | |||
202 | /* Flags for PWCX subroutines. Not all modules honour all flags. */ | ||
203 | #define PWCX_FLAG_PLANAR 0x0001 | ||
204 | #define PWCX_FLAG_BAYER 0x0008 | ||
205 | |||
206 | |||
207 | /* IOCTL definitions */ | ||
208 | |||
209 | /* Restore user settings */ | ||
210 | #define VIDIOCPWCRUSER _IO('v', 192) | ||
211 | /* Save user settings */ | ||
212 | #define VIDIOCPWCSUSER _IO('v', 193) | ||
213 | /* Restore factory settings */ | ||
214 | #define VIDIOCPWCFACTORY _IO('v', 194) | ||
215 | |||
216 | /* You can manipulate the compression factor. A compression preference of 0 | ||
217 | means use uncompressed modes when available; 1 is low compression, 2 is | ||
218 | medium and 3 is high compression preferred. Of course, the higher the | ||
219 | compression, the lower the bandwidth used but more chance of artefacts | ||
220 | in the image. The driver automatically chooses a higher compression when | ||
221 | the preferred mode is not available. | ||
222 | */ | ||
223 | /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */ | ||
224 | #define VIDIOCPWCSCQUAL _IOW('v', 195, int) | ||
225 | /* Get preferred compression quality */ | ||
226 | #define VIDIOCPWCGCQUAL _IOR('v', 195, int) | ||
227 | |||
228 | |||
229 | /* Retrieve serial number of camera */ | ||
230 | #define VIDIOCPWCGSERIAL _IOR('v', 198, struct pwc_serial) | ||
231 | |||
232 | /* This is a probe function; since so many devices are supported, it | ||
233 | becomes difficult to include all the names in programs that want to | ||
234 | check for the enhanced Philips stuff. So in stead, try this PROBE; | ||
235 | it returns a structure with the original name, and the corresponding | ||
236 | Philips type. | ||
237 | To use, fill the structure with zeroes, call PROBE and if that succeeds, | ||
238 | compare the name with that returned from VIDIOCGCAP; they should be the | ||
239 | same. If so, you can be assured it is a Philips (OEM) cam and the type | ||
240 | is valid. | ||
241 | */ | ||
242 | #define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe) | ||
243 | |||
244 | /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */ | ||
245 | #define VIDIOCPWCSAGC _IOW('v', 200, int) | ||
246 | /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */ | ||
247 | #define VIDIOCPWCGAGC _IOR('v', 200, int) | ||
248 | /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */ | ||
249 | #define VIDIOCPWCSSHUTTER _IOW('v', 201, int) | ||
250 | |||
251 | /* Color compensation (Auto White Balance) */ | ||
252 | #define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance) | ||
253 | #define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance) | ||
254 | |||
255 | /* Auto WB speed */ | ||
256 | #define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed) | ||
257 | #define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed) | ||
258 | |||
259 | /* LEDs on/off/blink; int range 0..65535 */ | ||
260 | #define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds) | ||
261 | #define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds) | ||
262 | |||
263 | /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */ | ||
264 | #define VIDIOCPWCSCONTOUR _IOW('v', 206, int) | ||
265 | #define VIDIOCPWCGCONTOUR _IOR('v', 206, int) | ||
266 | |||
267 | /* Backlight compensation; 0 = off, otherwise on */ | ||
268 | #define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int) | ||
269 | #define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int) | ||
270 | |||
271 | /* Flickerless mode; = 0 off, otherwise on */ | ||
272 | #define VIDIOCPWCSFLICKER _IOW('v', 208, int) | ||
273 | #define VIDIOCPWCGFLICKER _IOR('v', 208, int) | ||
274 | |||
275 | /* Dynamic noise reduction; 0 off, 3 = high noise reduction */ | ||
276 | #define VIDIOCPWCSDYNNOISE _IOW('v', 209, int) | ||
277 | #define VIDIOCPWCGDYNNOISE _IOR('v', 209, int) | ||
278 | |||
279 | /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */ | ||
280 | #define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize) | ||
281 | |||
282 | /* Motorized pan & tilt functions */ | ||
283 | #define VIDIOCPWCMPTRESET _IOW('v', 211, int) | ||
284 | #define VIDIOCPWCMPTGRANGE _IOR('v', 211, struct pwc_mpt_range) | ||
285 | #define VIDIOCPWCMPTSANGLE _IOW('v', 212, struct pwc_mpt_angles) | ||
286 | #define VIDIOCPWCMPTGANGLE _IOR('v', 212, struct pwc_mpt_angles) | ||
287 | #define VIDIOCPWCMPTSTATUS _IOR('v', 213, struct pwc_mpt_status) | ||
288 | |||
289 | /* Get the USB set-video command; needed for initializing libpwcx */ | ||
290 | #define VIDIOCPWCGVIDCMD _IOR('v', 215, struct pwc_video_command) | ||
291 | struct pwc_table_init_buffer { | ||
292 | int len; | ||
293 | char *buffer; | ||
294 | |||
295 | }; | ||
296 | #define VIDIOCPWCGVIDTABLE _IOR('v', 216, struct pwc_table_init_buffer) | ||
297 | |||
298 | /* | ||
299 | * This is private command used when communicating with v4l2. | ||
300 | * In the future all private ioctl will be remove/replace to | ||
301 | * use interface offer by v4l2. | ||
302 | */ | ||
303 | |||
304 | #define V4L2_CID_PRIVATE_SAVE_USER (V4L2_CID_PRIVATE_BASE + 0) | ||
305 | #define V4L2_CID_PRIVATE_RESTORE_USER (V4L2_CID_PRIVATE_BASE + 1) | ||
306 | #define V4L2_CID_PRIVATE_RESTORE_FACTORY (V4L2_CID_PRIVATE_BASE + 2) | ||
307 | #define V4L2_CID_PRIVATE_COLOUR_MODE (V4L2_CID_PRIVATE_BASE + 3) | ||
308 | #define V4L2_CID_PRIVATE_AUTOCONTOUR (V4L2_CID_PRIVATE_BASE + 4) | ||
309 | #define V4L2_CID_PRIVATE_CONTOUR (V4L2_CID_PRIVATE_BASE + 5) | ||
310 | #define V4L2_CID_PRIVATE_BACKLIGHT (V4L2_CID_PRIVATE_BASE + 6) | ||
311 | #define V4L2_CID_PRIVATE_FLICKERLESS (V4L2_CID_PRIVATE_BASE + 7) | ||
312 | #define V4L2_CID_PRIVATE_NOISE_REDUCTION (V4L2_CID_PRIVATE_BASE + 8) | ||
313 | |||
314 | struct pwc_raw_frame { | ||
315 | __le16 type; /* type of the webcam */ | ||
316 | __le16 vbandlength; /* Size of 4lines compressed (used by the decompressor) */ | ||
317 | __u8 cmd[4]; /* the four byte of the command (in case of nala, | ||
318 | only the first 3 bytes is filled) */ | ||
319 | __u8 rawframe[0]; /* frame_size = H/4*vbandlength */ | ||
320 | } __attribute__ ((packed)); | ||
321 | |||
322 | |||
323 | #endif | ||
diff --git a/drivers/media/video/pwc/pwc-kiara.c b/drivers/media/video/pwc/pwc-kiara.c index f4ae83c0cf2b..e5f4fd817125 100644 --- a/drivers/media/video/pwc/pwc-kiara.c +++ b/drivers/media/video/pwc/pwc-kiara.c | |||
@@ -40,7 +40,6 @@ | |||
40 | 40 | ||
41 | 41 | ||
42 | #include "pwc-kiara.h" | 42 | #include "pwc-kiara.h" |
43 | #include "pwc-uncompress.h" | ||
44 | 43 | ||
45 | const unsigned int Kiara_fps_vector[PWC_FPS_MAX_KIARA] = { 5, 10, 15, 20, 25, 30 }; | 44 | const unsigned int Kiara_fps_vector[PWC_FPS_MAX_KIARA] = { 5, 10, 15, 20, 25, 30 }; |
46 | 45 | ||
diff --git a/drivers/media/video/pwc/pwc-misc.c b/drivers/media/video/pwc/pwc-misc.c index 6af5bb538358..0b031336eab8 100644 --- a/drivers/media/video/pwc/pwc-misc.c +++ b/drivers/media/video/pwc/pwc-misc.c | |||
@@ -126,8 +126,4 @@ void pwc_construct(struct pwc_device *pdev) | |||
126 | pdev->pixfmt = V4L2_PIX_FMT_YUV420; /* default */ | 126 | pdev->pixfmt = V4L2_PIX_FMT_YUV420; /* default */ |
127 | pdev->view_min.size = pdev->view_min.x * pdev->view_min.y; | 127 | pdev->view_min.size = pdev->view_min.x * pdev->view_min.y; |
128 | pdev->view_max.size = pdev->view_max.x * pdev->view_max.y; | 128 | pdev->view_max.size = pdev->view_max.x * pdev->view_max.y; |
129 | /* length of image, in YUV format; always allocate enough memory. */ | ||
130 | pdev->len_per_image = PAGE_ALIGN((pdev->abs_max.x * pdev->abs_max.y * 3) / 2); | ||
131 | } | 129 | } |
132 | |||
133 | |||
diff --git a/drivers/media/video/pwc/pwc-uncompress.c b/drivers/media/video/pwc/pwc-uncompress.c index 3b73f295f032..51265092bd31 100644 --- a/drivers/media/video/pwc/pwc-uncompress.c +++ b/drivers/media/video/pwc/pwc-uncompress.c | |||
@@ -30,26 +30,17 @@ | |||
30 | #include <asm/types.h> | 30 | #include <asm/types.h> |
31 | 31 | ||
32 | #include "pwc.h" | 32 | #include "pwc.h" |
33 | #include "pwc-uncompress.h" | ||
34 | #include "pwc-dec1.h" | 33 | #include "pwc-dec1.h" |
35 | #include "pwc-dec23.h" | 34 | #include "pwc-dec23.h" |
36 | 35 | ||
37 | int pwc_decompress(struct pwc_device *pdev) | 36 | int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf) |
38 | { | 37 | { |
39 | struct pwc_frame_buf *fbuf; | ||
40 | int n, line, col, stride; | 38 | int n, line, col, stride; |
41 | void *yuv, *image; | 39 | void *yuv, *image; |
42 | u16 *src; | 40 | u16 *src; |
43 | u16 *dsty, *dstu, *dstv; | 41 | u16 *dsty, *dstu, *dstv; |
44 | 42 | ||
45 | if (pdev == NULL) | 43 | image = vb2_plane_vaddr(&fbuf->vb, 0); |
46 | return -EFAULT; | ||
47 | |||
48 | fbuf = pdev->read_frame; | ||
49 | if (fbuf == NULL) | ||
50 | return -EFAULT; | ||
51 | image = pdev->image_data; | ||
52 | image += pdev->images[pdev->fill_image].offset; | ||
53 | 44 | ||
54 | yuv = fbuf->data + pdev->frame_header_size; /* Skip header */ | 45 | yuv = fbuf->data + pdev->frame_header_size; /* Skip header */ |
55 | 46 | ||
@@ -64,9 +55,13 @@ int pwc_decompress(struct pwc_device *pdev) | |||
64 | * determine this using the type of the webcam */ | 55 | * determine this using the type of the webcam */ |
65 | memcpy(raw_frame->cmd, pdev->cmd_buf, 4); | 56 | memcpy(raw_frame->cmd, pdev->cmd_buf, 4); |
66 | memcpy(raw_frame+1, yuv, pdev->frame_size); | 57 | memcpy(raw_frame+1, yuv, pdev->frame_size); |
58 | vb2_set_plane_payload(&fbuf->vb, 0, | ||
59 | pdev->frame_size + sizeof(struct pwc_raw_frame)); | ||
67 | return 0; | 60 | return 0; |
68 | } | 61 | } |
69 | 62 | ||
63 | vb2_set_plane_payload(&fbuf->vb, 0, pdev->view.size); | ||
64 | |||
70 | if (pdev->vbandlength == 0) { | 65 | if (pdev->vbandlength == 0) { |
71 | /* Uncompressed mode. | 66 | /* Uncompressed mode. |
72 | * We copy the data into the output buffer, using the viewport | 67 | * We copy the data into the output buffer, using the viewport |
diff --git a/drivers/media/video/pwc/pwc-uncompress.h b/drivers/media/video/pwc/pwc-uncompress.h deleted file mode 100644 index 43028e74e9e0..000000000000 --- a/drivers/media/video/pwc/pwc-uncompress.h +++ /dev/null | |||
@@ -1,40 +0,0 @@ | |||
1 | /* (C) 1999-2003 Nemosoft Unv. | ||
2 | (C) 2004-2006 Luc Saillard (luc@saillard.org) | ||
3 | |||
4 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | ||
5 | driver and thus may have bugs that are not present in the original version. | ||
6 | Please send bug reports and support requests to <luc@saillard.org>. | ||
7 | The decompression routines have been implemented by reverse-engineering the | ||
8 | Nemosoft binary pwcx module. Caveat emptor. | ||
9 | |||
10 | This program is free software; you can redistribute it and/or modify | ||
11 | it under the terms of the GNU General Public License as published by | ||
12 | the Free Software Foundation; either version 2 of the License, or | ||
13 | (at your option) any later version. | ||
14 | |||
15 | This program is distributed in the hope that it will be useful, | ||
16 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | GNU General Public License for more details. | ||
19 | |||
20 | You should have received a copy of the GNU General Public License | ||
21 | along with this program; if not, write to the Free Software | ||
22 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | */ | ||
24 | |||
25 | /* This file is the bridge between the kernel module and the plugin; it | ||
26 | describes the structures and datatypes used in both modules. Any | ||
27 | significant change should be reflected by increasing the | ||
28 | pwc_decompressor_version major number. | ||
29 | */ | ||
30 | #ifndef PWC_UNCOMPRESS_H | ||
31 | #define PWC_UNCOMPRESS_H | ||
32 | |||
33 | |||
34 | #include <media/pwc-ioctl.h> | ||
35 | |||
36 | /* from pwc-dec.h */ | ||
37 | #define PWCX_FLAG_PLANAR 0x0001 | ||
38 | /* */ | ||
39 | |||
40 | #endif | ||
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index f85c51249c7b..8c70e64444e7 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c | |||
@@ -2,6 +2,7 @@ | |||
2 | USB and Video4Linux interface part. | 2 | USB and Video4Linux interface part. |
3 | (C) 1999-2004 Nemosoft Unv. | 3 | (C) 1999-2004 Nemosoft Unv. |
4 | (C) 2004-2006 Luc Saillard (luc@saillard.org) | 4 | (C) 2004-2006 Luc Saillard (luc@saillard.org) |
5 | (C) 2011 Hans de Goede <hdegoede@redhat.com> | ||
5 | 6 | ||
6 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx | 7 | NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx |
7 | driver and thus may have bugs that are not present in the original version. | 8 | driver and thus may have bugs that are not present in the original version. |
@@ -31,184 +32,330 @@ | |||
31 | #include <linux/module.h> | 32 | #include <linux/module.h> |
32 | #include <linux/poll.h> | 33 | #include <linux/poll.h> |
33 | #include <linux/vmalloc.h> | 34 | #include <linux/vmalloc.h> |
35 | #include <linux/jiffies.h> | ||
34 | #include <asm/io.h> | 36 | #include <asm/io.h> |
35 | 37 | ||
36 | #include "pwc.h" | 38 | #include "pwc.h" |
37 | 39 | ||
38 | static struct v4l2_queryctrl pwc_controls[] = { | 40 | #define PWC_CID_CUSTOM(ctrl) ((V4L2_CID_USER_BASE | 0xf000) + custom_ ## ctrl) |
39 | { | 41 | |
40 | .id = V4L2_CID_BRIGHTNESS, | 42 | static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl); |
41 | .type = V4L2_CTRL_TYPE_INTEGER, | 43 | static int pwc_s_ctrl(struct v4l2_ctrl *ctrl); |
42 | .name = "Brightness", | 44 | |
43 | .minimum = 0, | 45 | static const struct v4l2_ctrl_ops pwc_ctrl_ops = { |
44 | .maximum = 128, | 46 | .g_volatile_ctrl = pwc_g_volatile_ctrl, |
45 | .step = 1, | 47 | .s_ctrl = pwc_s_ctrl, |
46 | .default_value = 64, | 48 | }; |
47 | }, | 49 | |
48 | { | 50 | enum { awb_indoor, awb_outdoor, awb_fl, awb_manual, awb_auto }; |
49 | .id = V4L2_CID_CONTRAST, | 51 | enum { custom_autocontour, custom_contour, custom_noise_reduction, |
50 | .type = V4L2_CTRL_TYPE_INTEGER, | 52 | custom_save_user, custom_restore_user, custom_restore_factory }; |
51 | .name = "Contrast", | 53 | |
52 | .minimum = 0, | 54 | const char * const pwc_auto_whitebal_qmenu[] = { |
53 | .maximum = 64, | 55 | "Indoor (Incandescant Lighting) Mode", |
54 | .step = 1, | 56 | "Outdoor (Sunlight) Mode", |
55 | .default_value = 0, | 57 | "Indoor (Fluorescent Lighting) Mode", |
56 | }, | 58 | "Manual Mode", |
57 | { | 59 | "Auto Mode", |
58 | .id = V4L2_CID_SATURATION, | 60 | NULL |
59 | .type = V4L2_CTRL_TYPE_INTEGER, | 61 | }; |
60 | .name = "Saturation", | 62 | |
61 | .minimum = -100, | 63 | static const struct v4l2_ctrl_config pwc_auto_white_balance_cfg = { |
62 | .maximum = 100, | 64 | .ops = &pwc_ctrl_ops, |
63 | .step = 1, | 65 | .id = V4L2_CID_AUTO_WHITE_BALANCE, |
64 | .default_value = 0, | 66 | .type = V4L2_CTRL_TYPE_MENU, |
65 | }, | 67 | .max = awb_auto, |
66 | { | 68 | .qmenu = pwc_auto_whitebal_qmenu, |
67 | .id = V4L2_CID_GAMMA, | 69 | }; |
68 | .type = V4L2_CTRL_TYPE_INTEGER, | 70 | |
69 | .name = "Gamma", | 71 | static const struct v4l2_ctrl_config pwc_autocontour_cfg = { |
70 | .minimum = 0, | 72 | .ops = &pwc_ctrl_ops, |
71 | .maximum = 32, | 73 | .id = PWC_CID_CUSTOM(autocontour), |
72 | .step = 1, | 74 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
73 | .default_value = 0, | 75 | .name = "Auto contour", |
74 | }, | 76 | .min = 0, |
75 | { | 77 | .max = 1, |
76 | .id = V4L2_CID_RED_BALANCE, | 78 | .step = 1, |
77 | .type = V4L2_CTRL_TYPE_INTEGER, | 79 | }; |
78 | .name = "Red Gain", | 80 | |
79 | .minimum = 0, | 81 | static const struct v4l2_ctrl_config pwc_contour_cfg = { |
80 | .maximum = 256, | 82 | .ops = &pwc_ctrl_ops, |
81 | .step = 1, | 83 | .id = PWC_CID_CUSTOM(contour), |
82 | .default_value = 0, | 84 | .type = V4L2_CTRL_TYPE_INTEGER, |
83 | }, | 85 | .name = "Contour", |
84 | { | 86 | .min = 0, |
85 | .id = V4L2_CID_BLUE_BALANCE, | 87 | .max = 63, |
86 | .type = V4L2_CTRL_TYPE_INTEGER, | 88 | .step = 1, |
87 | .name = "Blue Gain", | 89 | }; |
88 | .minimum = 0, | 90 | |
89 | .maximum = 256, | 91 | static const struct v4l2_ctrl_config pwc_backlight_cfg = { |
90 | .step = 1, | 92 | .ops = &pwc_ctrl_ops, |
91 | .default_value = 0, | 93 | .id = V4L2_CID_BACKLIGHT_COMPENSATION, |
92 | }, | 94 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
93 | { | 95 | .min = 0, |
94 | .id = V4L2_CID_AUTO_WHITE_BALANCE, | 96 | .max = 1, |
95 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 97 | .step = 1, |
96 | .name = "Auto White Balance", | 98 | }; |
97 | .minimum = 0, | 99 | |
98 | .maximum = 1, | 100 | static const struct v4l2_ctrl_config pwc_flicker_cfg = { |
99 | .step = 1, | 101 | .ops = &pwc_ctrl_ops, |
100 | .default_value = 0, | 102 | .id = V4L2_CID_BAND_STOP_FILTER, |
101 | }, | 103 | .type = V4L2_CTRL_TYPE_BOOLEAN, |
102 | { | 104 | .min = 0, |
103 | .id = V4L2_CID_EXPOSURE, | 105 | .max = 1, |
104 | .type = V4L2_CTRL_TYPE_INTEGER, | 106 | .step = 1, |
105 | .name = "Shutter Speed (Exposure)", | 107 | }; |
106 | .minimum = 0, | 108 | |
107 | .maximum = 256, | 109 | static const struct v4l2_ctrl_config pwc_noise_reduction_cfg = { |
108 | .step = 1, | 110 | .ops = &pwc_ctrl_ops, |
109 | .default_value = 200, | 111 | .id = PWC_CID_CUSTOM(noise_reduction), |
110 | }, | 112 | .type = V4L2_CTRL_TYPE_INTEGER, |
111 | { | 113 | .name = "Dynamic Noise Reduction", |
112 | .id = V4L2_CID_AUTOGAIN, | 114 | .min = 0, |
113 | .type = V4L2_CTRL_TYPE_BOOLEAN, | 115 | .max = 3, |
114 | .name = "Auto Gain Enabled", | 116 | .step = 1, |
115 | .minimum = 0, | 117 | }; |
116 | .maximum = 1, | 118 | |
117 | .step = 1, | 119 | static const struct v4l2_ctrl_config pwc_save_user_cfg = { |
118 | .default_value = 1, | 120 | .ops = &pwc_ctrl_ops, |
119 | }, | 121 | .id = PWC_CID_CUSTOM(save_user), |
120 | { | 122 | .type = V4L2_CTRL_TYPE_BUTTON, |
121 | .id = V4L2_CID_GAIN, | 123 | .name = "Save User Settings", |
122 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
123 | .name = "Gain Level", | ||
124 | .minimum = 0, | ||
125 | .maximum = 256, | ||
126 | .step = 1, | ||
127 | .default_value = 0, | ||
128 | }, | ||
129 | { | ||
130 | .id = V4L2_CID_PRIVATE_SAVE_USER, | ||
131 | .type = V4L2_CTRL_TYPE_BUTTON, | ||
132 | .name = "Save User Settings", | ||
133 | .minimum = 0, | ||
134 | .maximum = 0, | ||
135 | .step = 0, | ||
136 | .default_value = 0, | ||
137 | }, | ||
138 | { | ||
139 | .id = V4L2_CID_PRIVATE_RESTORE_USER, | ||
140 | .type = V4L2_CTRL_TYPE_BUTTON, | ||
141 | .name = "Restore User Settings", | ||
142 | .minimum = 0, | ||
143 | .maximum = 0, | ||
144 | .step = 0, | ||
145 | .default_value = 0, | ||
146 | }, | ||
147 | { | ||
148 | .id = V4L2_CID_PRIVATE_RESTORE_FACTORY, | ||
149 | .type = V4L2_CTRL_TYPE_BUTTON, | ||
150 | .name = "Restore Factory Settings", | ||
151 | .minimum = 0, | ||
152 | .maximum = 0, | ||
153 | .step = 0, | ||
154 | .default_value = 0, | ||
155 | }, | ||
156 | { | ||
157 | .id = V4L2_CID_PRIVATE_COLOUR_MODE, | ||
158 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
159 | .name = "Colour mode", | ||
160 | .minimum = 0, | ||
161 | .maximum = 1, | ||
162 | .step = 1, | ||
163 | .default_value = 0, | ||
164 | }, | ||
165 | { | ||
166 | .id = V4L2_CID_PRIVATE_AUTOCONTOUR, | ||
167 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
168 | .name = "Auto contour", | ||
169 | .minimum = 0, | ||
170 | .maximum = 1, | ||
171 | .step = 1, | ||
172 | .default_value = 0, | ||
173 | }, | ||
174 | { | ||
175 | .id = V4L2_CID_PRIVATE_CONTOUR, | ||
176 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
177 | .name = "Contour", | ||
178 | .minimum = 0, | ||
179 | .maximum = 63, | ||
180 | .step = 1, | ||
181 | .default_value = 0, | ||
182 | }, | ||
183 | { | ||
184 | .id = V4L2_CID_PRIVATE_BACKLIGHT, | ||
185 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
186 | .name = "Backlight compensation", | ||
187 | .minimum = 0, | ||
188 | .maximum = 1, | ||
189 | .step = 1, | ||
190 | .default_value = 0, | ||
191 | }, | ||
192 | { | ||
193 | .id = V4L2_CID_PRIVATE_FLICKERLESS, | ||
194 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
195 | .name = "Flickerless", | ||
196 | .minimum = 0, | ||
197 | .maximum = 1, | ||
198 | .step = 1, | ||
199 | .default_value = 0, | ||
200 | }, | ||
201 | { | ||
202 | .id = V4L2_CID_PRIVATE_NOISE_REDUCTION, | ||
203 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
204 | .name = "Noise reduction", | ||
205 | .minimum = 0, | ||
206 | .maximum = 3, | ||
207 | .step = 1, | ||
208 | .default_value = 0, | ||
209 | }, | ||
210 | }; | 124 | }; |
211 | 125 | ||
126 | static const struct v4l2_ctrl_config pwc_restore_user_cfg = { | ||
127 | .ops = &pwc_ctrl_ops, | ||
128 | .id = PWC_CID_CUSTOM(restore_user), | ||
129 | .type = V4L2_CTRL_TYPE_BUTTON, | ||
130 | .name = "Restore User Settings", | ||
131 | }; | ||
132 | |||
133 | static const struct v4l2_ctrl_config pwc_restore_factory_cfg = { | ||
134 | .ops = &pwc_ctrl_ops, | ||
135 | .id = PWC_CID_CUSTOM(restore_factory), | ||
136 | .type = V4L2_CTRL_TYPE_BUTTON, | ||
137 | .name = "Restore Factory Settings", | ||
138 | }; | ||
139 | |||
140 | int pwc_init_controls(struct pwc_device *pdev) | ||
141 | { | ||
142 | struct v4l2_ctrl_handler *hdl; | ||
143 | struct v4l2_ctrl_config cfg; | ||
144 | int r, def; | ||
145 | |||
146 | hdl = &pdev->ctrl_handler; | ||
147 | r = v4l2_ctrl_handler_init(hdl, 20); | ||
148 | if (r) | ||
149 | return r; | ||
150 | |||
151 | /* Brightness, contrast, saturation, gamma */ | ||
152 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, BRIGHTNESS_FORMATTER, &def); | ||
153 | if (r || def > 127) | ||
154 | def = 63; | ||
155 | pdev->brightness = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
156 | V4L2_CID_BRIGHTNESS, 0, 127, 1, def); | ||
157 | |||
158 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, CONTRAST_FORMATTER, &def); | ||
159 | if (r || def > 63) | ||
160 | def = 31; | ||
161 | pdev->contrast = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
162 | V4L2_CID_CONTRAST, 0, 63, 1, def); | ||
163 | |||
164 | if (pdev->type >= 675) { | ||
165 | if (pdev->type < 730) | ||
166 | pdev->saturation_fmt = SATURATION_MODE_FORMATTER2; | ||
167 | else | ||
168 | pdev->saturation_fmt = SATURATION_MODE_FORMATTER1; | ||
169 | r = pwc_get_s8_ctrl(pdev, GET_CHROM_CTL, pdev->saturation_fmt, | ||
170 | &def); | ||
171 | if (r || def < -100 || def > 100) | ||
172 | def = 0; | ||
173 | pdev->saturation = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
174 | V4L2_CID_SATURATION, -100, 100, 1, def); | ||
175 | } | ||
176 | |||
177 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, GAMMA_FORMATTER, &def); | ||
178 | if (r || def > 31) | ||
179 | def = 15; | ||
180 | pdev->gamma = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
181 | V4L2_CID_GAMMA, 0, 31, 1, def); | ||
182 | |||
183 | /* auto white balance, red gain, blue gain */ | ||
184 | r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, WB_MODE_FORMATTER, &def); | ||
185 | if (r || def > awb_auto) | ||
186 | def = awb_auto; | ||
187 | cfg = pwc_auto_white_balance_cfg; | ||
188 | cfg.name = v4l2_ctrl_get_name(cfg.id); | ||
189 | cfg.def = def; | ||
190 | pdev->auto_white_balance = v4l2_ctrl_new_custom(hdl, &cfg, NULL); | ||
191 | /* check auto controls to avoid NULL deref in v4l2_ctrl_auto_cluster */ | ||
192 | if (!pdev->auto_white_balance) | ||
193 | return hdl->error; | ||
194 | |||
195 | r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, | ||
196 | PRESET_MANUAL_RED_GAIN_FORMATTER, &def); | ||
197 | if (r) | ||
198 | def = 127; | ||
199 | pdev->red_balance = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
200 | V4L2_CID_RED_BALANCE, 0, 255, 1, def); | ||
201 | |||
202 | r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, | ||
203 | PRESET_MANUAL_BLUE_GAIN_FORMATTER, &def); | ||
204 | if (r) | ||
205 | def = 127; | ||
206 | pdev->blue_balance = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
207 | V4L2_CID_BLUE_BALANCE, 0, 255, 1, def); | ||
208 | |||
209 | v4l2_ctrl_auto_cluster(3, &pdev->auto_white_balance, awb_manual, | ||
210 | pdev->auto_white_balance->cur.val == awb_auto); | ||
211 | |||
212 | /* autogain, gain */ | ||
213 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, AGC_MODE_FORMATTER, &def); | ||
214 | if (r || (def != 0 && def != 0xff)) | ||
215 | def = 0; | ||
216 | /* Note a register value if 0 means auto gain is on */ | ||
217 | pdev->autogain = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
218 | V4L2_CID_AUTOGAIN, 0, 1, 1, def == 0); | ||
219 | if (!pdev->autogain) | ||
220 | return hdl->error; | ||
221 | |||
222 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, PRESET_AGC_FORMATTER, &def); | ||
223 | if (r || def > 63) | ||
224 | def = 31; | ||
225 | pdev->gain = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
226 | V4L2_CID_GAIN, 0, 63, 1, def); | ||
227 | |||
228 | /* auto exposure, exposure */ | ||
229 | if (DEVICE_USE_CODEC2(pdev->type)) { | ||
230 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, SHUTTER_MODE_FORMATTER, | ||
231 | &def); | ||
232 | if (r || (def != 0 && def != 0xff)) | ||
233 | def = 0; | ||
234 | /* | ||
235 | * def = 0 auto, def = ff manual | ||
236 | * menu idx 0 = auto, idx 1 = manual | ||
237 | */ | ||
238 | pdev->exposure_auto = v4l2_ctrl_new_std_menu(hdl, | ||
239 | &pwc_ctrl_ops, | ||
240 | V4L2_CID_EXPOSURE_AUTO, | ||
241 | 1, 0, def != 0); | ||
242 | if (!pdev->exposure_auto) | ||
243 | return hdl->error; | ||
244 | |||
245 | /* GET_LUM_CTL, PRESET_SHUTTER_FORMATTER is unreliable */ | ||
246 | r = pwc_get_u16_ctrl(pdev, GET_STATUS_CTL, | ||
247 | READ_SHUTTER_FORMATTER, &def); | ||
248 | if (r || def > 655) | ||
249 | def = 655; | ||
250 | pdev->exposure = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
251 | V4L2_CID_EXPOSURE, 0, 655, 1, def); | ||
252 | /* CODEC2: separate auto gain & auto exposure */ | ||
253 | v4l2_ctrl_auto_cluster(2, &pdev->autogain, 0, true); | ||
254 | v4l2_ctrl_auto_cluster(2, &pdev->exposure_auto, | ||
255 | V4L2_EXPOSURE_MANUAL, true); | ||
256 | } else if (DEVICE_USE_CODEC3(pdev->type)) { | ||
257 | /* GET_LUM_CTL, PRESET_SHUTTER_FORMATTER is unreliable */ | ||
258 | r = pwc_get_u16_ctrl(pdev, GET_STATUS_CTL, | ||
259 | READ_SHUTTER_FORMATTER, &def); | ||
260 | if (r || def > 255) | ||
261 | def = 255; | ||
262 | pdev->exposure = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
263 | V4L2_CID_EXPOSURE, 0, 255, 1, def); | ||
264 | /* CODEC3: both gain and exposure controlled by autogain */ | ||
265 | pdev->autogain_expo_cluster[0] = pdev->autogain; | ||
266 | pdev->autogain_expo_cluster[1] = pdev->gain; | ||
267 | pdev->autogain_expo_cluster[2] = pdev->exposure; | ||
268 | v4l2_ctrl_auto_cluster(3, pdev->autogain_expo_cluster, | ||
269 | 0, true); | ||
270 | } | ||
271 | |||
272 | /* color / bw setting */ | ||
273 | r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, COLOUR_MODE_FORMATTER, | ||
274 | &def); | ||
275 | if (r || (def != 0 && def != 0xff)) | ||
276 | def = 0xff; | ||
277 | /* def = 0 bw, def = ff color, menu idx 0 = color, idx 1 = bw */ | ||
278 | pdev->colorfx = v4l2_ctrl_new_std_menu(hdl, &pwc_ctrl_ops, | ||
279 | V4L2_CID_COLORFX, 1, 0, def == 0); | ||
280 | |||
281 | /* autocontour, contour */ | ||
282 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, &def); | ||
283 | if (r || (def != 0 && def != 0xff)) | ||
284 | def = 0; | ||
285 | cfg = pwc_autocontour_cfg; | ||
286 | cfg.def = def == 0; | ||
287 | pdev->autocontour = v4l2_ctrl_new_custom(hdl, &cfg, NULL); | ||
288 | if (!pdev->autocontour) | ||
289 | return hdl->error; | ||
290 | |||
291 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, &def); | ||
292 | if (r || def > 63) | ||
293 | def = 31; | ||
294 | cfg = pwc_contour_cfg; | ||
295 | cfg.def = def; | ||
296 | pdev->contour = v4l2_ctrl_new_custom(hdl, &cfg, NULL); | ||
297 | |||
298 | v4l2_ctrl_auto_cluster(2, &pdev->autocontour, 0, false); | ||
299 | |||
300 | /* backlight */ | ||
301 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, | ||
302 | BACK_LIGHT_COMPENSATION_FORMATTER, &def); | ||
303 | if (r || (def != 0 && def != 0xff)) | ||
304 | def = 0; | ||
305 | cfg = pwc_backlight_cfg; | ||
306 | cfg.name = v4l2_ctrl_get_name(cfg.id); | ||
307 | cfg.def = def == 0; | ||
308 | pdev->backlight = v4l2_ctrl_new_custom(hdl, &cfg, NULL); | ||
309 | |||
310 | /* flikker rediction */ | ||
311 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, | ||
312 | FLICKERLESS_MODE_FORMATTER, &def); | ||
313 | if (r || (def != 0 && def != 0xff)) | ||
314 | def = 0; | ||
315 | cfg = pwc_flicker_cfg; | ||
316 | cfg.name = v4l2_ctrl_get_name(cfg.id); | ||
317 | cfg.def = def == 0; | ||
318 | pdev->flicker = v4l2_ctrl_new_custom(hdl, &cfg, NULL); | ||
319 | |||
320 | /* Dynamic noise reduction */ | ||
321 | r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, | ||
322 | DYNAMIC_NOISE_CONTROL_FORMATTER, &def); | ||
323 | if (r || def > 3) | ||
324 | def = 2; | ||
325 | cfg = pwc_noise_reduction_cfg; | ||
326 | cfg.def = def; | ||
327 | pdev->noise_reduction = v4l2_ctrl_new_custom(hdl, &cfg, NULL); | ||
328 | |||
329 | /* Save / Restore User / Factory Settings */ | ||
330 | pdev->save_user = v4l2_ctrl_new_custom(hdl, &pwc_save_user_cfg, NULL); | ||
331 | pdev->restore_user = v4l2_ctrl_new_custom(hdl, &pwc_restore_user_cfg, | ||
332 | NULL); | ||
333 | if (pdev->restore_user) | ||
334 | pdev->restore_user->flags = V4L2_CTRL_FLAG_UPDATE; | ||
335 | pdev->restore_factory = v4l2_ctrl_new_custom(hdl, | ||
336 | &pwc_restore_factory_cfg, | ||
337 | NULL); | ||
338 | if (pdev->restore_factory) | ||
339 | pdev->restore_factory->flags = V4L2_CTRL_FLAG_UPDATE; | ||
340 | |||
341 | if (!(pdev->features & FEATURE_MOTOR_PANTILT)) | ||
342 | return hdl->error; | ||
343 | |||
344 | /* Motor pan / tilt / reset */ | ||
345 | pdev->motor_pan = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
346 | V4L2_CID_PAN_RELATIVE, -4480, 4480, 64, 0); | ||
347 | if (!pdev->motor_pan) | ||
348 | return hdl->error; | ||
349 | pdev->motor_tilt = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
350 | V4L2_CID_TILT_RELATIVE, -1920, 1920, 64, 0); | ||
351 | pdev->motor_pan_reset = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
352 | V4L2_CID_PAN_RESET, 0, 0, 0, 0); | ||
353 | pdev->motor_tilt_reset = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops, | ||
354 | V4L2_CID_TILT_RESET, 0, 0, 0, 0); | ||
355 | v4l2_ctrl_cluster(4, &pdev->motor_pan); | ||
356 | |||
357 | return hdl->error; | ||
358 | } | ||
212 | 359 | ||
213 | static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f) | 360 | static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f) |
214 | { | 361 | { |
@@ -284,10 +431,21 @@ static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f) | |||
284 | } | 431 | } |
285 | 432 | ||
286 | /* ioctl(VIDIOC_SET_FMT) */ | 433 | /* ioctl(VIDIOC_SET_FMT) */ |
287 | static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f) | 434 | |
435 | static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) | ||
288 | { | 436 | { |
437 | struct pwc_device *pdev = video_drvdata(file); | ||
289 | int ret, fps, snapshot, compression, pixelformat; | 438 | int ret, fps, snapshot, compression, pixelformat; |
290 | 439 | ||
440 | if (!pdev->udev) | ||
441 | return -ENODEV; | ||
442 | |||
443 | if (pdev->capt_file != NULL && | ||
444 | pdev->capt_file != file) | ||
445 | return -EBUSY; | ||
446 | |||
447 | pdev->capt_file = file; | ||
448 | |||
291 | ret = pwc_vidioc_try_fmt(pdev, f); | 449 | ret = pwc_vidioc_try_fmt(pdev, f); |
292 | if (ret<0) | 450 | if (ret<0) |
293 | return ret; | 451 | return ret; |
@@ -309,7 +467,7 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f) | |||
309 | pixelformat != V4L2_PIX_FMT_PWC2) | 467 | pixelformat != V4L2_PIX_FMT_PWC2) |
310 | return -EINVAL; | 468 | return -EINVAL; |
311 | 469 | ||
312 | if (pdev->iso_init) | 470 | if (vb2_is_streaming(&pdev->vb_queue)) |
313 | return -EBUSY; | 471 | return -EBUSY; |
314 | 472 | ||
315 | PWC_DEBUG_IOCTL("Trying to set format to: width=%d height=%d fps=%d " | 473 | PWC_DEBUG_IOCTL("Trying to set format to: width=%d height=%d fps=%d " |
@@ -343,13 +501,14 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f) | |||
343 | 501 | ||
344 | static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) | 502 | static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) |
345 | { | 503 | { |
346 | struct video_device *vdev = video_devdata(file); | ||
347 | struct pwc_device *pdev = video_drvdata(file); | 504 | struct pwc_device *pdev = video_drvdata(file); |
348 | 505 | ||
506 | if (!pdev->udev) | ||
507 | return -ENODEV; | ||
508 | |||
349 | strcpy(cap->driver, PWC_NAME); | 509 | strcpy(cap->driver, PWC_NAME); |
350 | strlcpy(cap->card, vdev->name, sizeof(cap->card)); | 510 | strlcpy(cap->card, pdev->vdev.name, sizeof(cap->card)); |
351 | usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info)); | 511 | usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info)); |
352 | cap->version = PWC_VERSION_CODE; | ||
353 | cap->capabilities = | 512 | cap->capabilities = |
354 | V4L2_CAP_VIDEO_CAPTURE | | 513 | V4L2_CAP_VIDEO_CAPTURE | |
355 | V4L2_CAP_STREAMING | | 514 | V4L2_CAP_STREAMING | |
@@ -377,255 +536,396 @@ static int pwc_s_input(struct file *file, void *fh, unsigned int i) | |||
377 | return i ? -EINVAL : 0; | 536 | return i ? -EINVAL : 0; |
378 | } | 537 | } |
379 | 538 | ||
380 | static int pwc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c) | 539 | static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl) |
381 | { | 540 | { |
382 | int i, idx; | 541 | struct pwc_device *pdev = |
383 | u32 id; | 542 | container_of(ctrl->handler, struct pwc_device, ctrl_handler); |
384 | 543 | int ret = 0; | |
385 | id = c->id; | 544 | |
386 | if (id & V4L2_CTRL_FLAG_NEXT_CTRL) { | 545 | /* |
387 | id &= V4L2_CTRL_ID_MASK; | 546 | * Sometimes it can take quite long for the pwc to complete usb control |
388 | id++; | 547 | * transfers, so release the modlock to give streaming by another |
389 | idx = -1; | 548 | * process / thread the chance to continue with a dqbuf. |
390 | for (i = 0; i < ARRAY_SIZE(pwc_controls); i++) { | 549 | */ |
391 | if (pwc_controls[i].id < id) | 550 | mutex_unlock(&pdev->modlock); |
392 | continue; | 551 | |
393 | if (idx >= 0 | 552 | /* |
394 | && pwc_controls[i].id > pwc_controls[idx].id) | 553 | * Take the udev-lock to protect against the disconnect handler |
395 | continue; | 554 | * completing and setting dev->udev to NULL underneath us. Other code |
396 | idx = i; | 555 | * does not need to do this since it is protected by the modlock. |
556 | */ | ||
557 | mutex_lock(&pdev->udevlock); | ||
558 | |||
559 | if (!pdev->udev) { | ||
560 | ret = -ENODEV; | ||
561 | goto leave; | ||
562 | } | ||
563 | |||
564 | switch (ctrl->id) { | ||
565 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
566 | if (pdev->color_bal_valid && time_before(jiffies, | ||
567 | pdev->last_color_bal_update + HZ / 4)) { | ||
568 | pdev->red_balance->val = pdev->last_red_balance; | ||
569 | pdev->blue_balance->val = pdev->last_blue_balance; | ||
570 | break; | ||
397 | } | 571 | } |
398 | if (idx < 0) | 572 | ret = pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, |
399 | return -EINVAL; | 573 | READ_RED_GAIN_FORMATTER, |
400 | memcpy(c, &pwc_controls[idx], sizeof pwc_controls[0]); | 574 | &pdev->red_balance->val); |
401 | return 0; | 575 | if (ret) |
576 | break; | ||
577 | ret = pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, | ||
578 | READ_BLUE_GAIN_FORMATTER, | ||
579 | &pdev->blue_balance->val); | ||
580 | if (ret) | ||
581 | break; | ||
582 | pdev->last_red_balance = pdev->red_balance->val; | ||
583 | pdev->last_blue_balance = pdev->blue_balance->val; | ||
584 | pdev->last_color_bal_update = jiffies; | ||
585 | pdev->color_bal_valid = true; | ||
586 | break; | ||
587 | case V4L2_CID_AUTOGAIN: | ||
588 | if (pdev->gain_valid && time_before(jiffies, | ||
589 | pdev->last_gain_update + HZ / 4)) { | ||
590 | pdev->gain->val = pdev->last_gain; | ||
591 | break; | ||
592 | } | ||
593 | ret = pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, | ||
594 | READ_AGC_FORMATTER, &pdev->gain->val); | ||
595 | if (ret) | ||
596 | break; | ||
597 | pdev->last_gain = pdev->gain->val; | ||
598 | pdev->last_gain_update = jiffies; | ||
599 | pdev->gain_valid = true; | ||
600 | if (!DEVICE_USE_CODEC3(pdev->type)) | ||
601 | break; | ||
602 | /* Fall through for CODEC3 where autogain also controls expo */ | ||
603 | case V4L2_CID_EXPOSURE_AUTO: | ||
604 | if (pdev->exposure_valid && time_before(jiffies, | ||
605 | pdev->last_exposure_update + HZ / 4)) { | ||
606 | pdev->exposure->val = pdev->last_exposure; | ||
607 | break; | ||
608 | } | ||
609 | ret = pwc_get_u16_ctrl(pdev, GET_STATUS_CTL, | ||
610 | READ_SHUTTER_FORMATTER, | ||
611 | &pdev->exposure->val); | ||
612 | if (ret) | ||
613 | break; | ||
614 | pdev->last_exposure = pdev->exposure->val; | ||
615 | pdev->last_exposure_update = jiffies; | ||
616 | pdev->exposure_valid = true; | ||
617 | break; | ||
618 | default: | ||
619 | ret = -EINVAL; | ||
402 | } | 620 | } |
403 | for (i = 0; i < sizeof(pwc_controls) / sizeof(struct v4l2_queryctrl); i++) { | 621 | |
404 | if (pwc_controls[i].id == c->id) { | 622 | if (ret) |
405 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n"); | 623 | PWC_ERROR("g_ctrl %s error %d\n", ctrl->name, ret); |
406 | memcpy(c, &pwc_controls[i], sizeof(struct v4l2_queryctrl)); | 624 | |
407 | return 0; | 625 | leave: |
626 | mutex_unlock(&pdev->udevlock); | ||
627 | mutex_lock(&pdev->modlock); | ||
628 | return ret; | ||
629 | } | ||
630 | |||
631 | static int pwc_set_awb(struct pwc_device *pdev) | ||
632 | { | ||
633 | int ret = 0; | ||
634 | |||
635 | if (pdev->auto_white_balance->is_new) { | ||
636 | ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, | ||
637 | WB_MODE_FORMATTER, | ||
638 | pdev->auto_white_balance->val); | ||
639 | if (ret) | ||
640 | return ret; | ||
641 | |||
642 | /* Update val when coming from auto or going to a preset */ | ||
643 | if (pdev->red_balance->is_volatile || | ||
644 | pdev->auto_white_balance->val == awb_indoor || | ||
645 | pdev->auto_white_balance->val == awb_outdoor || | ||
646 | pdev->auto_white_balance->val == awb_fl) { | ||
647 | if (!pdev->red_balance->is_new) | ||
648 | pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, | ||
649 | READ_RED_GAIN_FORMATTER, | ||
650 | &pdev->red_balance->val); | ||
651 | if (!pdev->blue_balance->is_new) | ||
652 | pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, | ||
653 | READ_BLUE_GAIN_FORMATTER, | ||
654 | &pdev->blue_balance->val); | ||
655 | } | ||
656 | if (pdev->auto_white_balance->val == awb_auto) { | ||
657 | pdev->red_balance->is_volatile = true; | ||
658 | pdev->blue_balance->is_volatile = true; | ||
659 | pdev->color_bal_valid = false; /* Force cache update */ | ||
660 | } else { | ||
661 | pdev->red_balance->is_volatile = false; | ||
662 | pdev->blue_balance->is_volatile = false; | ||
408 | } | 663 | } |
409 | } | 664 | } |
410 | return -EINVAL; | 665 | |
666 | if (ret == 0 && pdev->red_balance->is_new) { | ||
667 | if (pdev->auto_white_balance->val != awb_manual) | ||
668 | return -EBUSY; | ||
669 | ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, | ||
670 | PRESET_MANUAL_RED_GAIN_FORMATTER, | ||
671 | pdev->red_balance->val); | ||
672 | } | ||
673 | |||
674 | if (ret == 0 && pdev->blue_balance->is_new) { | ||
675 | if (pdev->auto_white_balance->val != awb_manual) | ||
676 | return -EBUSY; | ||
677 | ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, | ||
678 | PRESET_MANUAL_BLUE_GAIN_FORMATTER, | ||
679 | pdev->blue_balance->val); | ||
680 | } | ||
681 | return ret; | ||
411 | } | 682 | } |
412 | 683 | ||
413 | static int pwc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) | 684 | /* For CODEC2 models which have separate autogain and auto exposure */ |
685 | static int pwc_set_autogain(struct pwc_device *pdev) | ||
414 | { | 686 | { |
415 | struct pwc_device *pdev = video_drvdata(file); | 687 | int ret = 0; |
416 | int ret; | 688 | |
689 | if (pdev->autogain->is_new) { | ||
690 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, | ||
691 | AGC_MODE_FORMATTER, | ||
692 | pdev->autogain->val ? 0 : 0xff); | ||
693 | if (ret) | ||
694 | return ret; | ||
695 | if (pdev->autogain->val) | ||
696 | pdev->gain_valid = false; /* Force cache update */ | ||
697 | else if (!pdev->gain->is_new) | ||
698 | pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, | ||
699 | READ_AGC_FORMATTER, | ||
700 | &pdev->gain->val); | ||
701 | } | ||
702 | if (ret == 0 && pdev->gain->is_new) { | ||
703 | if (pdev->autogain->val) | ||
704 | return -EBUSY; | ||
705 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, | ||
706 | PRESET_AGC_FORMATTER, | ||
707 | pdev->gain->val); | ||
708 | } | ||
709 | return ret; | ||
710 | } | ||
417 | 711 | ||
418 | switch (c->id) { | 712 | /* For CODEC2 models which have separate autogain and auto exposure */ |
419 | case V4L2_CID_BRIGHTNESS: | 713 | static int pwc_set_exposure_auto(struct pwc_device *pdev) |
420 | c->value = pwc_get_brightness(pdev); | 714 | { |
421 | if (c->value < 0) | 715 | int ret = 0; |
422 | return -EINVAL; | 716 | int is_auto = pdev->exposure_auto->val == V4L2_EXPOSURE_AUTO; |
423 | return 0; | 717 | |
424 | case V4L2_CID_CONTRAST: | 718 | if (pdev->exposure_auto->is_new) { |
425 | c->value = pwc_get_contrast(pdev); | 719 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, |
426 | if (c->value < 0) | 720 | SHUTTER_MODE_FORMATTER, |
427 | return -EINVAL; | 721 | is_auto ? 0 : 0xff); |
428 | return 0; | 722 | if (ret) |
429 | case V4L2_CID_SATURATION: | 723 | return ret; |
430 | ret = pwc_get_saturation(pdev, &c->value); | 724 | if (is_auto) |
431 | if (ret < 0) | 725 | pdev->exposure_valid = false; /* Force cache update */ |
432 | return -EINVAL; | 726 | else if (!pdev->exposure->is_new) |
433 | return 0; | 727 | pwc_get_u16_ctrl(pdev, GET_STATUS_CTL, |
434 | case V4L2_CID_GAMMA: | 728 | READ_SHUTTER_FORMATTER, |
435 | c->value = pwc_get_gamma(pdev); | 729 | &pdev->exposure->val); |
436 | if (c->value < 0) | 730 | } |
437 | return -EINVAL; | 731 | if (ret == 0 && pdev->exposure->is_new) { |
438 | return 0; | 732 | if (is_auto) |
439 | case V4L2_CID_RED_BALANCE: | 733 | return -EBUSY; |
440 | ret = pwc_get_red_gain(pdev, &c->value); | 734 | ret = pwc_set_u16_ctrl(pdev, SET_LUM_CTL, |
441 | if (ret < 0) | 735 | PRESET_SHUTTER_FORMATTER, |
442 | return -EINVAL; | 736 | pdev->exposure->val); |
443 | c->value >>= 8; | 737 | } |
444 | return 0; | 738 | return ret; |
445 | case V4L2_CID_BLUE_BALANCE: | 739 | } |
446 | ret = pwc_get_blue_gain(pdev, &c->value); | ||
447 | if (ret < 0) | ||
448 | return -EINVAL; | ||
449 | c->value >>= 8; | ||
450 | return 0; | ||
451 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
452 | ret = pwc_get_awb(pdev); | ||
453 | if (ret < 0) | ||
454 | return -EINVAL; | ||
455 | c->value = (ret == PWC_WB_MANUAL) ? 0 : 1; | ||
456 | return 0; | ||
457 | case V4L2_CID_GAIN: | ||
458 | ret = pwc_get_agc(pdev, &c->value); | ||
459 | if (ret < 0) | ||
460 | return -EINVAL; | ||
461 | c->value >>= 8; | ||
462 | return 0; | ||
463 | case V4L2_CID_AUTOGAIN: | ||
464 | ret = pwc_get_agc(pdev, &c->value); | ||
465 | if (ret < 0) | ||
466 | return -EINVAL; | ||
467 | c->value = (c->value < 0) ? 1 : 0; | ||
468 | return 0; | ||
469 | case V4L2_CID_EXPOSURE: | ||
470 | ret = pwc_get_shutter_speed(pdev, &c->value); | ||
471 | if (ret < 0) | ||
472 | return -EINVAL; | ||
473 | return 0; | ||
474 | case V4L2_CID_PRIVATE_COLOUR_MODE: | ||
475 | ret = pwc_get_colour_mode(pdev, &c->value); | ||
476 | if (ret < 0) | ||
477 | return -EINVAL; | ||
478 | return 0; | ||
479 | case V4L2_CID_PRIVATE_AUTOCONTOUR: | ||
480 | ret = pwc_get_contour(pdev, &c->value); | ||
481 | if (ret < 0) | ||
482 | return -EINVAL; | ||
483 | c->value = (c->value == -1 ? 1 : 0); | ||
484 | return 0; | ||
485 | case V4L2_CID_PRIVATE_CONTOUR: | ||
486 | ret = pwc_get_contour(pdev, &c->value); | ||
487 | if (ret < 0) | ||
488 | return -EINVAL; | ||
489 | c->value >>= 10; | ||
490 | return 0; | ||
491 | case V4L2_CID_PRIVATE_BACKLIGHT: | ||
492 | ret = pwc_get_backlight(pdev, &c->value); | ||
493 | if (ret < 0) | ||
494 | return -EINVAL; | ||
495 | return 0; | ||
496 | case V4L2_CID_PRIVATE_FLICKERLESS: | ||
497 | ret = pwc_get_flicker(pdev, &c->value); | ||
498 | if (ret < 0) | ||
499 | return -EINVAL; | ||
500 | c->value = (c->value ? 1 : 0); | ||
501 | return 0; | ||
502 | case V4L2_CID_PRIVATE_NOISE_REDUCTION: | ||
503 | ret = pwc_get_dynamic_noise(pdev, &c->value); | ||
504 | if (ret < 0) | ||
505 | return -EINVAL; | ||
506 | return 0; | ||
507 | 740 | ||
508 | case V4L2_CID_PRIVATE_SAVE_USER: | 741 | /* For CODEC3 models which have autogain controlling both gain and exposure */ |
509 | case V4L2_CID_PRIVATE_RESTORE_USER: | 742 | static int pwc_set_autogain_expo(struct pwc_device *pdev) |
510 | case V4L2_CID_PRIVATE_RESTORE_FACTORY: | 743 | { |
511 | return -EINVAL; | 744 | int ret = 0; |
745 | |||
746 | if (pdev->autogain->is_new) { | ||
747 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, | ||
748 | AGC_MODE_FORMATTER, | ||
749 | pdev->autogain->val ? 0 : 0xff); | ||
750 | if (ret) | ||
751 | return ret; | ||
752 | if (pdev->autogain->val) { | ||
753 | pdev->gain_valid = false; /* Force cache update */ | ||
754 | pdev->exposure_valid = false; /* Force cache update */ | ||
755 | } else { | ||
756 | if (!pdev->gain->is_new) | ||
757 | pwc_get_u8_ctrl(pdev, GET_STATUS_CTL, | ||
758 | READ_AGC_FORMATTER, | ||
759 | &pdev->gain->val); | ||
760 | if (!pdev->exposure->is_new) | ||
761 | pwc_get_u16_ctrl(pdev, GET_STATUS_CTL, | ||
762 | READ_SHUTTER_FORMATTER, | ||
763 | &pdev->exposure->val); | ||
764 | } | ||
512 | } | 765 | } |
513 | return -EINVAL; | 766 | if (ret == 0 && pdev->gain->is_new) { |
767 | if (pdev->autogain->val) | ||
768 | return -EBUSY; | ||
769 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, | ||
770 | PRESET_AGC_FORMATTER, | ||
771 | pdev->gain->val); | ||
772 | } | ||
773 | if (ret == 0 && pdev->exposure->is_new) { | ||
774 | if (pdev->autogain->val) | ||
775 | return -EBUSY; | ||
776 | ret = pwc_set_u16_ctrl(pdev, SET_LUM_CTL, | ||
777 | PRESET_SHUTTER_FORMATTER, | ||
778 | pdev->exposure->val); | ||
779 | } | ||
780 | return ret; | ||
514 | } | 781 | } |
515 | 782 | ||
516 | static int pwc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) | 783 | static int pwc_set_motor(struct pwc_device *pdev) |
517 | { | 784 | { |
518 | struct pwc_device *pdev = video_drvdata(file); | ||
519 | int ret; | 785 | int ret; |
786 | u8 buf[4]; | ||
787 | |||
788 | buf[0] = 0; | ||
789 | if (pdev->motor_pan_reset->is_new) | ||
790 | buf[0] |= 0x01; | ||
791 | if (pdev->motor_tilt_reset->is_new) | ||
792 | buf[0] |= 0x02; | ||
793 | if (pdev->motor_pan_reset->is_new || pdev->motor_tilt_reset->is_new) { | ||
794 | ret = send_control_msg(pdev, SET_MPT_CTL, | ||
795 | PT_RESET_CONTROL_FORMATTER, buf, 1); | ||
796 | if (ret < 0) | ||
797 | return ret; | ||
798 | } | ||
520 | 799 | ||
521 | switch (c->id) { | 800 | memset(buf, 0, sizeof(buf)); |
522 | case V4L2_CID_BRIGHTNESS: | 801 | if (pdev->motor_pan->is_new) { |
523 | c->value <<= 9; | 802 | buf[0] = pdev->motor_pan->val & 0xFF; |
524 | ret = pwc_set_brightness(pdev, c->value); | 803 | buf[1] = (pdev->motor_pan->val >> 8); |
804 | } | ||
805 | if (pdev->motor_tilt->is_new) { | ||
806 | buf[2] = pdev->motor_tilt->val & 0xFF; | ||
807 | buf[3] = (pdev->motor_tilt->val >> 8); | ||
808 | } | ||
809 | if (pdev->motor_pan->is_new || pdev->motor_tilt->is_new) { | ||
810 | ret = send_control_msg(pdev, SET_MPT_CTL, | ||
811 | PT_RELATIVE_CONTROL_FORMATTER, | ||
812 | buf, sizeof(buf)); | ||
525 | if (ret < 0) | 813 | if (ret < 0) |
526 | return -EINVAL; | 814 | return ret; |
527 | return 0; | 815 | } |
816 | |||
817 | return 0; | ||
818 | } | ||
819 | |||
820 | static int pwc_s_ctrl(struct v4l2_ctrl *ctrl) | ||
821 | { | ||
822 | struct pwc_device *pdev = | ||
823 | container_of(ctrl->handler, struct pwc_device, ctrl_handler); | ||
824 | int ret = 0; | ||
825 | |||
826 | /* See the comments on locking in pwc_g_volatile_ctrl */ | ||
827 | mutex_unlock(&pdev->modlock); | ||
828 | mutex_lock(&pdev->udevlock); | ||
829 | |||
830 | if (!pdev->udev) { | ||
831 | ret = -ENODEV; | ||
832 | goto leave; | ||
833 | } | ||
834 | |||
835 | switch (ctrl->id) { | ||
836 | case V4L2_CID_BRIGHTNESS: | ||
837 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, | ||
838 | BRIGHTNESS_FORMATTER, ctrl->val); | ||
839 | break; | ||
528 | case V4L2_CID_CONTRAST: | 840 | case V4L2_CID_CONTRAST: |
529 | c->value <<= 10; | 841 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, |
530 | ret = pwc_set_contrast(pdev, c->value); | 842 | CONTRAST_FORMATTER, ctrl->val); |
531 | if (ret < 0) | 843 | break; |
532 | return -EINVAL; | ||
533 | return 0; | ||
534 | case V4L2_CID_SATURATION: | 844 | case V4L2_CID_SATURATION: |
535 | ret = pwc_set_saturation(pdev, c->value); | 845 | ret = pwc_set_s8_ctrl(pdev, SET_CHROM_CTL, |
536 | if (ret < 0) | 846 | pdev->saturation_fmt, ctrl->val); |
537 | return -EINVAL; | 847 | break; |
538 | return 0; | ||
539 | case V4L2_CID_GAMMA: | 848 | case V4L2_CID_GAMMA: |
540 | c->value <<= 11; | 849 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, |
541 | ret = pwc_set_gamma(pdev, c->value); | 850 | GAMMA_FORMATTER, ctrl->val); |
542 | if (ret < 0) | 851 | break; |
543 | return -EINVAL; | ||
544 | return 0; | ||
545 | case V4L2_CID_RED_BALANCE: | ||
546 | c->value <<= 8; | ||
547 | ret = pwc_set_red_gain(pdev, c->value); | ||
548 | if (ret < 0) | ||
549 | return -EINVAL; | ||
550 | return 0; | ||
551 | case V4L2_CID_BLUE_BALANCE: | ||
552 | c->value <<= 8; | ||
553 | ret = pwc_set_blue_gain(pdev, c->value); | ||
554 | if (ret < 0) | ||
555 | return -EINVAL; | ||
556 | return 0; | ||
557 | case V4L2_CID_AUTO_WHITE_BALANCE: | 852 | case V4L2_CID_AUTO_WHITE_BALANCE: |
558 | c->value = (c->value == 0) ? PWC_WB_MANUAL : PWC_WB_AUTO; | 853 | ret = pwc_set_awb(pdev); |
559 | ret = pwc_set_awb(pdev, c->value); | 854 | break; |
560 | if (ret < 0) | ||
561 | return -EINVAL; | ||
562 | return 0; | ||
563 | case V4L2_CID_EXPOSURE: | ||
564 | c->value <<= 8; | ||
565 | ret = pwc_set_shutter_speed(pdev, c->value ? 0 : 1, c->value); | ||
566 | if (ret < 0) | ||
567 | return -EINVAL; | ||
568 | return 0; | ||
569 | case V4L2_CID_AUTOGAIN: | 855 | case V4L2_CID_AUTOGAIN: |
570 | /* autogain off means nothing without a gain */ | 856 | if (DEVICE_USE_CODEC2(pdev->type)) |
571 | if (c->value == 0) | 857 | ret = pwc_set_autogain(pdev); |
572 | return 0; | 858 | else if (DEVICE_USE_CODEC3(pdev->type)) |
573 | ret = pwc_set_agc(pdev, c->value, 0); | 859 | ret = pwc_set_autogain_expo(pdev); |
574 | if (ret < 0) | 860 | else |
575 | return -EINVAL; | 861 | ret = -EINVAL; |
576 | return 0; | 862 | break; |
577 | case V4L2_CID_GAIN: | 863 | case V4L2_CID_EXPOSURE_AUTO: |
578 | c->value <<= 8; | 864 | if (DEVICE_USE_CODEC2(pdev->type)) |
579 | ret = pwc_set_agc(pdev, 0, c->value); | 865 | ret = pwc_set_exposure_auto(pdev); |
580 | if (ret < 0) | 866 | else |
581 | return -EINVAL; | 867 | ret = -EINVAL; |
582 | return 0; | 868 | break; |
583 | case V4L2_CID_PRIVATE_SAVE_USER: | 869 | case V4L2_CID_COLORFX: |
584 | if (pwc_save_user(pdev)) | 870 | ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL, |
585 | return -EINVAL; | 871 | COLOUR_MODE_FORMATTER, |
586 | return 0; | 872 | ctrl->val ? 0 : 0xff); |
587 | case V4L2_CID_PRIVATE_RESTORE_USER: | 873 | break; |
588 | if (pwc_restore_user(pdev)) | 874 | case PWC_CID_CUSTOM(autocontour): |
589 | return -EINVAL; | 875 | if (pdev->autocontour->is_new) { |
590 | return 0; | 876 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, |
591 | case V4L2_CID_PRIVATE_RESTORE_FACTORY: | 877 | AUTO_CONTOUR_FORMATTER, |
592 | if (pwc_restore_factory(pdev)) | 878 | pdev->autocontour->val ? 0 : 0xff); |
593 | return -EINVAL; | 879 | } |
594 | return 0; | 880 | if (ret == 0 && pdev->contour->is_new) { |
595 | case V4L2_CID_PRIVATE_COLOUR_MODE: | 881 | if (pdev->autocontour->val) { |
596 | ret = pwc_set_colour_mode(pdev, c->value); | 882 | ret = -EBUSY; |
597 | if (ret < 0) | 883 | break; |
598 | return -EINVAL; | 884 | } |
599 | return 0; | 885 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, |
600 | case V4L2_CID_PRIVATE_AUTOCONTOUR: | 886 | PRESET_CONTOUR_FORMATTER, |
601 | c->value = (c->value == 1) ? -1 : 0; | 887 | pdev->contour->val); |
602 | ret = pwc_set_contour(pdev, c->value); | 888 | } |
603 | if (ret < 0) | 889 | break; |
604 | return -EINVAL; | 890 | case V4L2_CID_BACKLIGHT_COMPENSATION: |
605 | return 0; | 891 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, |
606 | case V4L2_CID_PRIVATE_CONTOUR: | 892 | BACK_LIGHT_COMPENSATION_FORMATTER, |
607 | c->value <<= 10; | 893 | ctrl->val ? 0 : 0xff); |
608 | ret = pwc_set_contour(pdev, c->value); | 894 | break; |
609 | if (ret < 0) | 895 | case V4L2_CID_BAND_STOP_FILTER: |
610 | return -EINVAL; | 896 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, |
611 | return 0; | 897 | FLICKERLESS_MODE_FORMATTER, |
612 | case V4L2_CID_PRIVATE_BACKLIGHT: | 898 | ctrl->val ? 0 : 0xff); |
613 | ret = pwc_set_backlight(pdev, c->value); | 899 | break; |
614 | if (ret < 0) | 900 | case PWC_CID_CUSTOM(noise_reduction): |
615 | return -EINVAL; | 901 | ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL, |
616 | return 0; | 902 | DYNAMIC_NOISE_CONTROL_FORMATTER, |
617 | case V4L2_CID_PRIVATE_FLICKERLESS: | 903 | ctrl->val); |
618 | ret = pwc_set_flicker(pdev, c->value); | 904 | break; |
619 | if (ret < 0) | 905 | case PWC_CID_CUSTOM(save_user): |
620 | return -EINVAL; | 906 | ret = pwc_button_ctrl(pdev, SAVE_USER_DEFAULTS_FORMATTER); |
621 | case V4L2_CID_PRIVATE_NOISE_REDUCTION: | 907 | break; |
622 | ret = pwc_set_dynamic_noise(pdev, c->value); | 908 | case PWC_CID_CUSTOM(restore_user): |
623 | if (ret < 0) | 909 | ret = pwc_button_ctrl(pdev, RESTORE_USER_DEFAULTS_FORMATTER); |
624 | return -EINVAL; | 910 | break; |
625 | return 0; | 911 | case PWC_CID_CUSTOM(restore_factory): |
626 | 912 | ret = pwc_button_ctrl(pdev, | |
913 | RESTORE_FACTORY_DEFAULTS_FORMATTER); | ||
914 | break; | ||
915 | case V4L2_CID_PAN_RELATIVE: | ||
916 | ret = pwc_set_motor(pdev); | ||
917 | break; | ||
918 | default: | ||
919 | ret = -EINVAL; | ||
627 | } | 920 | } |
628 | return -EINVAL; | 921 | |
922 | if (ret) | ||
923 | PWC_ERROR("s_ctrl %s error %d\n", ctrl->name, ret); | ||
924 | |||
925 | leave: | ||
926 | mutex_unlock(&pdev->udevlock); | ||
927 | mutex_lock(&pdev->modlock); | ||
928 | return ret; | ||
629 | } | 929 | } |
630 | 930 | ||
631 | static int pwc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) | 931 | static int pwc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) |
@@ -667,157 +967,77 @@ static int pwc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format * | |||
667 | return pwc_vidioc_try_fmt(pdev, f); | 967 | return pwc_vidioc_try_fmt(pdev, f); |
668 | } | 968 | } |
669 | 969 | ||
670 | static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) | 970 | static int pwc_reqbufs(struct file *file, void *fh, |
971 | struct v4l2_requestbuffers *rb) | ||
671 | { | 972 | { |
672 | struct pwc_device *pdev = video_drvdata(file); | 973 | struct pwc_device *pdev = video_drvdata(file); |
673 | 974 | ||
674 | return pwc_vidioc_set_fmt(pdev, f); | 975 | if (pdev->capt_file != NULL && |
675 | } | 976 | pdev->capt_file != file) |
676 | 977 | return -EBUSY; | |
677 | static int pwc_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb) | ||
678 | { | ||
679 | int nbuffers; | ||
680 | 978 | ||
681 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n", rb->count); | 979 | pdev->capt_file = file; |
682 | if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
683 | return -EINVAL; | ||
684 | if (rb->memory != V4L2_MEMORY_MMAP) | ||
685 | return -EINVAL; | ||
686 | 980 | ||
687 | nbuffers = rb->count; | 981 | return vb2_reqbufs(&pdev->vb_queue, rb); |
688 | if (nbuffers < 2) | ||
689 | nbuffers = 2; | ||
690 | else if (nbuffers > pwc_mbufs) | ||
691 | nbuffers = pwc_mbufs; | ||
692 | /* Force to use our # of buffers */ | ||
693 | rb->count = pwc_mbufs; | ||
694 | return 0; | ||
695 | } | 982 | } |
696 | 983 | ||
697 | static int pwc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) | 984 | static int pwc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) |
698 | { | 985 | { |
699 | struct pwc_device *pdev = video_drvdata(file); | 986 | struct pwc_device *pdev = video_drvdata(file); |
700 | int index; | ||
701 | 987 | ||
702 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n", buf->index); | 988 | return vb2_querybuf(&pdev->vb_queue, buf); |
703 | if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | ||
704 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n"); | ||
705 | return -EINVAL; | ||
706 | } | ||
707 | index = buf->index; | ||
708 | if (index < 0 || index >= pwc_mbufs) { | ||
709 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index); | ||
710 | return -EINVAL; | ||
711 | } | ||
712 | |||
713 | buf->m.offset = index * pdev->len_per_image; | ||
714 | if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) | ||
715 | buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); | ||
716 | else | ||
717 | buf->bytesused = pdev->view.size; | ||
718 | buf->field = V4L2_FIELD_NONE; | ||
719 | buf->memory = V4L2_MEMORY_MMAP; | ||
720 | /*buf->flags = V4L2_BUF_FLAG_MAPPED;*/ | ||
721 | buf->length = pdev->len_per_image; | ||
722 | |||
723 | PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n", buf->index); | ||
724 | PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n", buf->m.offset); | ||
725 | PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n", buf->bytesused); | ||
726 | |||
727 | return 0; | ||
728 | } | 989 | } |
729 | 990 | ||
730 | static int pwc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) | 991 | static int pwc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) |
731 | { | 992 | { |
732 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n", buf->index); | 993 | struct pwc_device *pdev = video_drvdata(file); |
733 | if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
734 | return -EINVAL; | ||
735 | if (buf->memory != V4L2_MEMORY_MMAP) | ||
736 | return -EINVAL; | ||
737 | if (buf->index >= pwc_mbufs) | ||
738 | return -EINVAL; | ||
739 | 994 | ||
740 | buf->flags |= V4L2_BUF_FLAG_QUEUED; | 995 | if (!pdev->udev) |
741 | buf->flags &= ~V4L2_BUF_FLAG_DONE; | 996 | return -ENODEV; |
742 | 997 | ||
743 | return 0; | 998 | if (pdev->capt_file != file) |
999 | return -EBUSY; | ||
1000 | |||
1001 | return vb2_qbuf(&pdev->vb_queue, buf); | ||
744 | } | 1002 | } |
745 | 1003 | ||
746 | static int pwc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) | 1004 | static int pwc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) |
747 | { | 1005 | { |
748 | DECLARE_WAITQUEUE(wait, current); | ||
749 | struct pwc_device *pdev = video_drvdata(file); | 1006 | struct pwc_device *pdev = video_drvdata(file); |
750 | int ret; | ||
751 | 1007 | ||
752 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n"); | 1008 | if (!pdev->udev) |
1009 | return -ENODEV; | ||
753 | 1010 | ||
754 | if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 1011 | if (pdev->capt_file != file) |
755 | return -EINVAL; | 1012 | return -EBUSY; |
756 | |||
757 | add_wait_queue(&pdev->frameq, &wait); | ||
758 | while (pdev->full_frames == NULL) { | ||
759 | if (pdev->error_status) { | ||
760 | remove_wait_queue(&pdev->frameq, &wait); | ||
761 | set_current_state(TASK_RUNNING); | ||
762 | return -pdev->error_status; | ||
763 | } | ||
764 | |||
765 | if (signal_pending(current)) { | ||
766 | remove_wait_queue(&pdev->frameq, &wait); | ||
767 | set_current_state(TASK_RUNNING); | ||
768 | return -ERESTARTSYS; | ||
769 | } | ||
770 | mutex_unlock(&pdev->modlock); | ||
771 | schedule(); | ||
772 | set_current_state(TASK_INTERRUPTIBLE); | ||
773 | mutex_lock(&pdev->modlock); | ||
774 | } | ||
775 | remove_wait_queue(&pdev->frameq, &wait); | ||
776 | set_current_state(TASK_RUNNING); | ||
777 | |||
778 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n"); | ||
779 | /* Decompress data in pdev->images[pdev->fill_image] */ | ||
780 | ret = pwc_handle_frame(pdev); | ||
781 | if (ret) | ||
782 | return -EFAULT; | ||
783 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n"); | ||
784 | |||
785 | buf->index = pdev->fill_image; | ||
786 | if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) | ||
787 | buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); | ||
788 | else | ||
789 | buf->bytesused = pdev->view.size; | ||
790 | buf->flags = V4L2_BUF_FLAG_MAPPED; | ||
791 | buf->field = V4L2_FIELD_NONE; | ||
792 | do_gettimeofday(&buf->timestamp); | ||
793 | buf->sequence = 0; | ||
794 | buf->memory = V4L2_MEMORY_MMAP; | ||
795 | buf->m.offset = pdev->fill_image * pdev->len_per_image; | ||
796 | buf->length = pdev->len_per_image; | ||
797 | pwc_next_image(pdev); | ||
798 | |||
799 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n", buf->index); | ||
800 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n", buf->length); | ||
801 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n", buf->m.offset); | ||
802 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n", buf->bytesused); | ||
803 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n"); | ||
804 | return 0; | ||
805 | 1013 | ||
1014 | return vb2_dqbuf(&pdev->vb_queue, buf, file->f_flags & O_NONBLOCK); | ||
806 | } | 1015 | } |
807 | 1016 | ||
808 | static int pwc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) | 1017 | static int pwc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) |
809 | { | 1018 | { |
810 | struct pwc_device *pdev = video_drvdata(file); | 1019 | struct pwc_device *pdev = video_drvdata(file); |
811 | 1020 | ||
812 | return pwc_isoc_init(pdev); | 1021 | if (!pdev->udev) |
1022 | return -ENODEV; | ||
1023 | |||
1024 | if (pdev->capt_file != file) | ||
1025 | return -EBUSY; | ||
1026 | |||
1027 | return vb2_streamon(&pdev->vb_queue, i); | ||
813 | } | 1028 | } |
814 | 1029 | ||
815 | static int pwc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) | 1030 | static int pwc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) |
816 | { | 1031 | { |
817 | struct pwc_device *pdev = video_drvdata(file); | 1032 | struct pwc_device *pdev = video_drvdata(file); |
818 | 1033 | ||
819 | pwc_isoc_cleanup(pdev); | 1034 | if (!pdev->udev) |
820 | return 0; | 1035 | return -ENODEV; |
1036 | |||
1037 | if (pdev->capt_file != file) | ||
1038 | return -EBUSY; | ||
1039 | |||
1040 | return vb2_streamoff(&pdev->vb_queue, i); | ||
821 | } | 1041 | } |
822 | 1042 | ||
823 | static int pwc_enum_framesizes(struct file *file, void *fh, | 1043 | static int pwc_enum_framesizes(struct file *file, void *fh, |
@@ -896,9 +1116,6 @@ const struct v4l2_ioctl_ops pwc_ioctl_ops = { | |||
896 | .vidioc_g_fmt_vid_cap = pwc_g_fmt_vid_cap, | 1116 | .vidioc_g_fmt_vid_cap = pwc_g_fmt_vid_cap, |
897 | .vidioc_s_fmt_vid_cap = pwc_s_fmt_vid_cap, | 1117 | .vidioc_s_fmt_vid_cap = pwc_s_fmt_vid_cap, |
898 | .vidioc_try_fmt_vid_cap = pwc_try_fmt_vid_cap, | 1118 | .vidioc_try_fmt_vid_cap = pwc_try_fmt_vid_cap, |
899 | .vidioc_queryctrl = pwc_queryctrl, | ||
900 | .vidioc_g_ctrl = pwc_g_ctrl, | ||
901 | .vidioc_s_ctrl = pwc_s_ctrl, | ||
902 | .vidioc_reqbufs = pwc_reqbufs, | 1119 | .vidioc_reqbufs = pwc_reqbufs, |
903 | .vidioc_querybuf = pwc_querybuf, | 1120 | .vidioc_querybuf = pwc_querybuf, |
904 | .vidioc_qbuf = pwc_qbuf, | 1121 | .vidioc_qbuf = pwc_qbuf, |
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h index 083f8b15df73..0e4e2d7b7872 100644 --- a/drivers/media/video/pwc/pwc.h +++ b/drivers/media/video/pwc/pwc.h | |||
@@ -29,7 +29,6 @@ | |||
29 | #include <linux/usb.h> | 29 | #include <linux/usb.h> |
30 | #include <linux/spinlock.h> | 30 | #include <linux/spinlock.h> |
31 | #include <linux/wait.h> | 31 | #include <linux/wait.h> |
32 | #include <linux/version.h> | ||
33 | #include <linux/mutex.h> | 32 | #include <linux/mutex.h> |
34 | #include <linux/mm.h> | 33 | #include <linux/mm.h> |
35 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
@@ -37,19 +36,16 @@ | |||
37 | #include <linux/videodev2.h> | 36 | #include <linux/videodev2.h> |
38 | #include <media/v4l2-common.h> | 37 | #include <media/v4l2-common.h> |
39 | #include <media/v4l2-ioctl.h> | 38 | #include <media/v4l2-ioctl.h> |
39 | #include <media/v4l2-ctrls.h> | ||
40 | #include <media/videobuf2-vmalloc.h> | ||
40 | #ifdef CONFIG_USB_PWC_INPUT_EVDEV | 41 | #ifdef CONFIG_USB_PWC_INPUT_EVDEV |
41 | #include <linux/input.h> | 42 | #include <linux/input.h> |
42 | #endif | 43 | #endif |
43 | 44 | ||
44 | #include "pwc-uncompress.h" | ||
45 | #include <media/pwc-ioctl.h> | 45 | #include <media/pwc-ioctl.h> |
46 | 46 | ||
47 | /* Version block */ | 47 | /* Version block */ |
48 | #define PWC_MAJOR 10 | 48 | #define PWC_VERSION "10.0.15" |
49 | #define PWC_MINOR 0 | ||
50 | #define PWC_EXTRAMINOR 12 | ||
51 | #define PWC_VERSION_CODE KERNEL_VERSION(PWC_MAJOR,PWC_MINOR,PWC_EXTRAMINOR) | ||
52 | #define PWC_VERSION "10.0.14" | ||
53 | #define PWC_NAME "pwc" | 49 | #define PWC_NAME "pwc" |
54 | #define PFX PWC_NAME ": " | 50 | #define PFX PWC_NAME ": " |
55 | 51 | ||
@@ -81,9 +77,9 @@ | |||
81 | #define PWC_DEBUG_LEVEL (PWC_DEBUG_LEVEL_MODULE) | 77 | #define PWC_DEBUG_LEVEL (PWC_DEBUG_LEVEL_MODULE) |
82 | 78 | ||
83 | #define PWC_DEBUG(level, fmt, args...) do {\ | 79 | #define PWC_DEBUG(level, fmt, args...) do {\ |
84 | if ((PWC_DEBUG_LEVEL_ ##level) & pwc_trace) \ | 80 | if ((PWC_DEBUG_LEVEL_ ##level) & pwc_trace) \ |
85 | printk(KERN_DEBUG PFX fmt, ##args); \ | 81 | printk(KERN_DEBUG PFX fmt, ##args); \ |
86 | } while(0) | 82 | } while (0) |
87 | 83 | ||
88 | #define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args) | 84 | #define PWC_ERROR(fmt, args...) printk(KERN_ERR PFX fmt, ##args) |
89 | #define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args) | 85 | #define PWC_WARNING(fmt, args...) printk(KERN_WARNING PFX fmt, ##args) |
@@ -110,25 +106,21 @@ | |||
110 | #define FEATURE_CODEC1 0x0002 | 106 | #define FEATURE_CODEC1 0x0002 |
111 | #define FEATURE_CODEC2 0x0004 | 107 | #define FEATURE_CODEC2 0x0004 |
112 | 108 | ||
113 | /* Turn certain features on/off */ | ||
114 | #define PWC_INT_PIPE 0 | ||
115 | |||
116 | /* Ignore errors in the first N frames, to allow for startup delays */ | 109 | /* Ignore errors in the first N frames, to allow for startup delays */ |
117 | #define FRAME_LOWMARK 5 | 110 | #define FRAME_LOWMARK 5 |
118 | 111 | ||
119 | /* Size and number of buffers for the ISO pipe. */ | 112 | /* Size and number of buffers for the ISO pipe. */ |
120 | #define MAX_ISO_BUFS 2 | 113 | #define MAX_ISO_BUFS 3 |
121 | #define ISO_FRAMES_PER_DESC 10 | 114 | #define ISO_FRAMES_PER_DESC 10 |
122 | #define ISO_MAX_FRAME_SIZE 960 | 115 | #define ISO_MAX_FRAME_SIZE 960 |
123 | #define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE) | 116 | #define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE) |
124 | 117 | ||
125 | /* Frame buffers: contains compressed or uncompressed video data. */ | ||
126 | #define MAX_FRAMES 5 | ||
127 | /* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */ | 118 | /* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */ |
128 | #define PWC_FRAME_SIZE (460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE) | 119 | #define PWC_FRAME_SIZE (460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE) |
129 | 120 | ||
130 | /* Absolute maximum number of buffers available for mmap() */ | 121 | /* Absolute minimum and maximum number of buffers available for mmap() */ |
131 | #define MAX_IMAGES 10 | 122 | #define MIN_FRAMES 2 |
123 | #define MAX_FRAMES 16 | ||
132 | 124 | ||
133 | /* Some macros to quickly find the type of a webcam */ | 125 | /* Some macros to quickly find the type of a webcam */ |
134 | #define DEVICE_USE_CODEC1(x) ((x)<675) | 126 | #define DEVICE_USE_CODEC1(x) ((x)<675) |
@@ -136,149 +128,221 @@ | |||
136 | #define DEVICE_USE_CODEC3(x) ((x)>=700) | 128 | #define DEVICE_USE_CODEC3(x) ((x)>=700) |
137 | #define DEVICE_USE_CODEC23(x) ((x)>=675) | 129 | #define DEVICE_USE_CODEC23(x) ((x)>=675) |
138 | 130 | ||
139 | /* The following structures were based on cpia.h. Why reinvent the wheel? :-) */ | 131 | /* from pwc-dec.h */ |
140 | struct pwc_iso_buf | 132 | #define PWCX_FLAG_PLANAR 0x0001 |
141 | { | 133 | |
142 | void *data; | 134 | /* Request types: video */ |
143 | int length; | 135 | #define SET_LUM_CTL 0x01 |
144 | int read; | 136 | #define GET_LUM_CTL 0x02 |
145 | struct urb *urb; | 137 | #define SET_CHROM_CTL 0x03 |
146 | }; | 138 | #define GET_CHROM_CTL 0x04 |
139 | #define SET_STATUS_CTL 0x05 | ||
140 | #define GET_STATUS_CTL 0x06 | ||
141 | #define SET_EP_STREAM_CTL 0x07 | ||
142 | #define GET_EP_STREAM_CTL 0x08 | ||
143 | #define GET_XX_CTL 0x09 | ||
144 | #define SET_XX_CTL 0x0A | ||
145 | #define GET_XY_CTL 0x0B | ||
146 | #define SET_XY_CTL 0x0C | ||
147 | #define SET_MPT_CTL 0x0D | ||
148 | #define GET_MPT_CTL 0x0E | ||
149 | |||
150 | /* Selectors for the Luminance controls [GS]ET_LUM_CTL */ | ||
151 | #define AGC_MODE_FORMATTER 0x2000 | ||
152 | #define PRESET_AGC_FORMATTER 0x2100 | ||
153 | #define SHUTTER_MODE_FORMATTER 0x2200 | ||
154 | #define PRESET_SHUTTER_FORMATTER 0x2300 | ||
155 | #define PRESET_CONTOUR_FORMATTER 0x2400 | ||
156 | #define AUTO_CONTOUR_FORMATTER 0x2500 | ||
157 | #define BACK_LIGHT_COMPENSATION_FORMATTER 0x2600 | ||
158 | #define CONTRAST_FORMATTER 0x2700 | ||
159 | #define DYNAMIC_NOISE_CONTROL_FORMATTER 0x2800 | ||
160 | #define FLICKERLESS_MODE_FORMATTER 0x2900 | ||
161 | #define AE_CONTROL_SPEED 0x2A00 | ||
162 | #define BRIGHTNESS_FORMATTER 0x2B00 | ||
163 | #define GAMMA_FORMATTER 0x2C00 | ||
164 | |||
165 | /* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */ | ||
166 | #define WB_MODE_FORMATTER 0x1000 | ||
167 | #define AWB_CONTROL_SPEED_FORMATTER 0x1100 | ||
168 | #define AWB_CONTROL_DELAY_FORMATTER 0x1200 | ||
169 | #define PRESET_MANUAL_RED_GAIN_FORMATTER 0x1300 | ||
170 | #define PRESET_MANUAL_BLUE_GAIN_FORMATTER 0x1400 | ||
171 | #define COLOUR_MODE_FORMATTER 0x1500 | ||
172 | #define SATURATION_MODE_FORMATTER1 0x1600 | ||
173 | #define SATURATION_MODE_FORMATTER2 0x1700 | ||
174 | |||
175 | /* Selectors for the Status controls [GS]ET_STATUS_CTL */ | ||
176 | #define SAVE_USER_DEFAULTS_FORMATTER 0x0200 | ||
177 | #define RESTORE_USER_DEFAULTS_FORMATTER 0x0300 | ||
178 | #define RESTORE_FACTORY_DEFAULTS_FORMATTER 0x0400 | ||
179 | #define READ_AGC_FORMATTER 0x0500 | ||
180 | #define READ_SHUTTER_FORMATTER 0x0600 | ||
181 | #define READ_RED_GAIN_FORMATTER 0x0700 | ||
182 | #define READ_BLUE_GAIN_FORMATTER 0x0800 | ||
183 | |||
184 | /* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */ | ||
185 | #define PT_RELATIVE_CONTROL_FORMATTER 0x01 | ||
186 | #define PT_RESET_CONTROL_FORMATTER 0x02 | ||
187 | #define PT_STATUS_FORMATTER 0x03 | ||
147 | 188 | ||
148 | /* intermediate buffers with raw data from the USB cam */ | 189 | /* intermediate buffers with raw data from the USB cam */ |
149 | struct pwc_frame_buf | 190 | struct pwc_frame_buf |
150 | { | 191 | { |
151 | void *data; | 192 | struct vb2_buffer vb; /* common v4l buffer stuff -- must be first */ |
152 | volatile int filled; /* number of bytes filled */ | 193 | struct list_head list; |
153 | struct pwc_frame_buf *next; /* list */ | 194 | void *data; |
154 | }; | 195 | int filled; /* number of bytes filled */ |
155 | |||
156 | /* additionnal informations used when dealing image between kernel and userland */ | ||
157 | struct pwc_imgbuf | ||
158 | { | ||
159 | unsigned long offset; /* offset of this buffer in the big array of image_data */ | ||
160 | int vma_use_count; /* count the number of time this memory is mapped */ | ||
161 | }; | 196 | }; |
162 | 197 | ||
163 | struct pwc_device | 198 | struct pwc_device |
164 | { | 199 | { |
165 | struct video_device vdev; | 200 | struct video_device vdev; |
166 | 201 | struct mutex modlock; | |
167 | /* Pointer to our usb_device, may be NULL after unplug */ | 202 | |
168 | struct usb_device *udev; | 203 | /* Pointer to our usb_device, may be NULL after unplug */ |
169 | 204 | struct usb_device *udev; | |
170 | int type; /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ | 205 | /* Protects the setting of udev to NULL by our disconnect handler */ |
171 | int release; /* release number */ | 206 | struct mutex udevlock; |
172 | int features; /* feature bits */ | 207 | |
173 | char serial[30]; /* serial number (string) */ | 208 | /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ |
174 | int error_status; /* set when something goes wrong with the cam (unplugged, USB errors) */ | 209 | int type; |
175 | int usb_init; /* set when the cam has been initialized over USB */ | 210 | int release; /* release number */ |
176 | 211 | int features; /* feature bits */ | |
177 | /*** Video data ***/ | 212 | char serial[30]; /* serial number (string) */ |
178 | int vopen; /* flag */ | 213 | |
179 | int vendpoint; /* video isoc endpoint */ | 214 | /*** Video data ***/ |
180 | int vcinterface; /* video control interface */ | 215 | struct file *capt_file; /* file doing video capture */ |
181 | int valternate; /* alternate interface needed */ | 216 | int vendpoint; /* video isoc endpoint */ |
182 | int vframes, vsize; /* frames-per-second & size (see PSZ_*) */ | 217 | int vcinterface; /* video control interface */ |
183 | int pixfmt; /* pixelformat: V4L2_PIX_FMT_YUV420 or raw: _PWC1, _PWC2 */ | 218 | int valternate; /* alternate interface needed */ |
184 | int vframe_count; /* received frames */ | 219 | int vframes, vsize; /* frames-per-second & size (see PSZ_*) */ |
185 | int vframes_dumped; /* counter for dumped frames */ | 220 | int pixfmt; /* pixelformat: V4L2_PIX_FMT_YUV420 or _PWCX */ |
186 | int vframes_error; /* frames received in error */ | 221 | int vframe_count; /* received frames */ |
187 | int vmax_packet_size; /* USB maxpacket size */ | 222 | int vmax_packet_size; /* USB maxpacket size */ |
188 | int vlast_packet_size; /* for frame synchronisation */ | 223 | int vlast_packet_size; /* for frame synchronisation */ |
189 | int visoc_errors; /* number of contiguous ISOC errors */ | 224 | int visoc_errors; /* number of contiguous ISOC errors */ |
190 | int vcompression; /* desired compression factor */ | 225 | int vcompression; /* desired compression factor */ |
191 | int vbandlength; /* compressed band length; 0 is uncompressed */ | 226 | int vbandlength; /* compressed band length; 0 is uncompressed */ |
192 | char vsnapshot; /* snapshot mode */ | 227 | char vsnapshot; /* snapshot mode */ |
193 | char vsync; /* used by isoc handler */ | 228 | char vsync; /* used by isoc handler */ |
194 | char vmirror; /* for ToUCaM series */ | 229 | char vmirror; /* for ToUCaM series */ |
195 | char unplugged; | 230 | char power_save; /* Do powersaving for this cam */ |
196 | 231 | ||
197 | int cmd_len; | 232 | int cmd_len; |
198 | unsigned char cmd_buf[13]; | 233 | unsigned char cmd_buf[13]; |
199 | 234 | ||
200 | /* The image acquisition requires 3 to 4 steps: | 235 | struct urb *urbs[MAX_ISO_BUFS]; |
201 | 1. data is gathered in short packets from the USB controller | 236 | char iso_init; |
202 | 2. data is synchronized and packed into a frame buffer | 237 | |
203 | 3a. in case data is compressed, decompress it directly into image buffer | 238 | /* videobuf2 queue and queued buffers list */ |
204 | 3b. in case data is uncompressed, copy into image buffer with viewport | 239 | struct vb2_queue vb_queue; |
205 | 4. data is transferred to the user process | 240 | struct list_head queued_bufs; |
206 | 241 | spinlock_t queued_bufs_lock; | |
207 | Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES.... | 242 | |
208 | We have in effect a back-to-back-double-buffer system. | 243 | /* |
209 | */ | 244 | * Frame currently being filled, this only gets touched by the |
210 | /* 1: isoc */ | 245 | * isoc urb complete handler, and by stream start / stop since |
211 | struct pwc_iso_buf sbuf[MAX_ISO_BUFS]; | 246 | * start / stop touch it before / after starting / killing the urbs |
212 | char iso_init; | 247 | * no locking is needed around this |
213 | 248 | */ | |
214 | /* 2: frame */ | 249 | struct pwc_frame_buf *fill_buf; |
215 | struct pwc_frame_buf *fbuf; /* all frames */ | 250 | |
216 | struct pwc_frame_buf *empty_frames, *empty_frames_tail; /* all empty frames */ | 251 | int frame_header_size, frame_trailer_size; |
217 | struct pwc_frame_buf *full_frames, *full_frames_tail; /* all filled frames */ | 252 | int frame_size; |
218 | struct pwc_frame_buf *fill_frame; /* frame currently being filled */ | 253 | int frame_total_size; /* including header & trailer */ |
219 | struct pwc_frame_buf *read_frame; /* frame currently read by user process */ | 254 | int drop_frames; |
220 | int frame_header_size, frame_trailer_size; | 255 | |
221 | int frame_size; | 256 | void *decompress_data; /* private data for decompression engine */ |
222 | int frame_total_size; /* including header & trailer */ | 257 | |
223 | int drop_frames; | 258 | /* |
224 | 259 | * We have an 'image' and a 'view', where 'image' is the fixed-size img | |
225 | /* 3: decompression */ | 260 | * as delivered by the camera, and 'view' is the size requested by the |
226 | void *decompress_data; /* private data for decompression engine */ | 261 | * program. The camera image is centered in this viewport, laced with |
227 | 262 | * a gray or black border. view_min <= image <= view <= view_max; | |
228 | /* 4: image */ | 263 | */ |
229 | /* We have an 'image' and a 'view', where 'image' is the fixed-size image | 264 | int image_mask; /* supported sizes */ |
230 | as delivered by the camera, and 'view' is the size requested by the | 265 | struct pwc_coord view_min, view_max; /* minimum and maximum view */ |
231 | program. The camera image is centered in this viewport, laced with | 266 | struct pwc_coord abs_max; /* maximum supported size */ |
232 | a gray or black border. view_min <= image <= view <= view_max; | 267 | struct pwc_coord image, view; /* image and viewport size */ |
233 | */ | 268 | struct pwc_coord offset; /* offset of the viewport */ |
234 | int image_mask; /* bitmask of supported sizes */ | 269 | |
235 | struct pwc_coord view_min, view_max; /* minimum and maximum viewable sizes */ | 270 | /*** motorized pan/tilt feature */ |
236 | struct pwc_coord abs_max; /* maximum supported size with compression */ | 271 | struct pwc_mpt_range angle_range; |
237 | struct pwc_coord image, view; /* image and viewport size */ | 272 | int pan_angle; /* in degrees * 100 */ |
238 | struct pwc_coord offset; /* offset within the viewport */ | 273 | int tilt_angle; /* absolute angle; 0,0 is home */ |
239 | 274 | ||
240 | void *image_data; /* total buffer, which is subdivided into ... */ | 275 | /* |
241 | struct pwc_imgbuf images[MAX_IMAGES];/* ...several images... */ | 276 | * Set to 1 when the user push the button, reset to 0 |
242 | int fill_image; /* ...which are rotated. */ | 277 | * when this value is read from sysfs. |
243 | int len_per_image; /* length per image */ | 278 | */ |
244 | int image_read_pos; /* In case we read data in pieces, keep track of were we are in the imagebuffer */ | 279 | int snapshot_button_status; |
245 | int image_used[MAX_IMAGES]; /* For MCAPTURE and SYNC */ | ||
246 | |||
247 | struct mutex modlock; /* to prevent races in video_open(), etc */ | ||
248 | spinlock_t ptrlock; /* for manipulating the buffer pointers */ | ||
249 | |||
250 | /*** motorized pan/tilt feature */ | ||
251 | struct pwc_mpt_range angle_range; | ||
252 | int pan_angle; /* in degrees * 100 */ | ||
253 | int tilt_angle; /* absolute angle; 0,0 is home position */ | ||
254 | int snapshot_button_status; /* set to 1 when the user push the button, reset to 0 when this value is read */ | ||
255 | #ifdef CONFIG_USB_PWC_INPUT_EVDEV | 280 | #ifdef CONFIG_USB_PWC_INPUT_EVDEV |
256 | struct input_dev *button_dev; /* webcam snapshot button input */ | 281 | struct input_dev *button_dev; /* webcam snapshot button input */ |
257 | char button_phys[64]; | 282 | char button_phys[64]; |
258 | #endif | 283 | #endif |
259 | 284 | ||
260 | /*** Misc. data ***/ | 285 | /* controls */ |
261 | wait_queue_head_t frameq; /* When waiting for a frame to finish... */ | 286 | struct v4l2_ctrl_handler ctrl_handler; |
262 | #if PWC_INT_PIPE | 287 | u16 saturation_fmt; |
263 | void *usb_int_handler; /* for the interrupt endpoint */ | 288 | struct v4l2_ctrl *brightness; |
264 | #endif | 289 | struct v4l2_ctrl *contrast; |
290 | struct v4l2_ctrl *saturation; | ||
291 | struct v4l2_ctrl *gamma; | ||
292 | struct { | ||
293 | /* awb / red-blue balance cluster */ | ||
294 | struct v4l2_ctrl *auto_white_balance; | ||
295 | struct v4l2_ctrl *red_balance; | ||
296 | struct v4l2_ctrl *blue_balance; | ||
297 | /* usb ctrl transfers are slow, so we cache things */ | ||
298 | int color_bal_valid; | ||
299 | unsigned long last_color_bal_update; /* In jiffies */ | ||
300 | s32 last_red_balance; | ||
301 | s32 last_blue_balance; | ||
302 | }; | ||
303 | struct { | ||
304 | /* autogain / gain cluster */ | ||
305 | struct v4l2_ctrl *autogain; | ||
306 | struct v4l2_ctrl *gain; | ||
307 | int gain_valid; | ||
308 | unsigned long last_gain_update; /* In jiffies */ | ||
309 | s32 last_gain; | ||
310 | }; | ||
311 | struct { | ||
312 | /* exposure_auto / exposure cluster */ | ||
313 | struct v4l2_ctrl *exposure_auto; | ||
314 | struct v4l2_ctrl *exposure; | ||
315 | int exposure_valid; | ||
316 | unsigned long last_exposure_update; /* In jiffies */ | ||
317 | s32 last_exposure; | ||
318 | }; | ||
319 | struct v4l2_ctrl *colorfx; | ||
320 | struct { | ||
321 | /* autocontour/contour cluster */ | ||
322 | struct v4l2_ctrl *autocontour; | ||
323 | struct v4l2_ctrl *contour; | ||
324 | }; | ||
325 | struct v4l2_ctrl *backlight; | ||
326 | struct v4l2_ctrl *flicker; | ||
327 | struct v4l2_ctrl *noise_reduction; | ||
328 | struct v4l2_ctrl *save_user; | ||
329 | struct v4l2_ctrl *restore_user; | ||
330 | struct v4l2_ctrl *restore_factory; | ||
331 | struct { | ||
332 | /* motor control cluster */ | ||
333 | struct v4l2_ctrl *motor_pan; | ||
334 | struct v4l2_ctrl *motor_tilt; | ||
335 | struct v4l2_ctrl *motor_pan_reset; | ||
336 | struct v4l2_ctrl *motor_tilt_reset; | ||
337 | }; | ||
338 | /* CODEC3 models have both gain and exposure controlled by autogain */ | ||
339 | struct v4l2_ctrl *autogain_expo_cluster[3]; | ||
265 | }; | 340 | }; |
266 | 341 | ||
267 | #ifdef __cplusplus | ||
268 | extern "C" { | ||
269 | #endif | ||
270 | |||
271 | /* Global variables */ | 342 | /* Global variables */ |
272 | #ifdef CONFIG_USB_PWC_DEBUG | 343 | #ifdef CONFIG_USB_PWC_DEBUG |
273 | extern int pwc_trace; | 344 | extern int pwc_trace; |
274 | #endif | 345 | #endif |
275 | extern int pwc_mbufs; | ||
276 | |||
277 | /** functions in pwc-if.c */ | ||
278 | int pwc_handle_frame(struct pwc_device *pdev); | ||
279 | void pwc_next_image(struct pwc_device *pdev); | ||
280 | int pwc_isoc_init(struct pwc_device *pdev); | ||
281 | void pwc_isoc_cleanup(struct pwc_device *pdev); | ||
282 | 346 | ||
283 | /** Functions in pwc-misc.c */ | 347 | /** Functions in pwc-misc.c */ |
284 | /* sizes in pixels */ | 348 | /* sizes in pixels */ |
@@ -291,50 +355,25 @@ void pwc_construct(struct pwc_device *pdev); | |||
291 | /* Request a certain video mode. Returns < 0 if not possible */ | 355 | /* Request a certain video mode. Returns < 0 if not possible */ |
292 | extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); | 356 | extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); |
293 | extern unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size); | 357 | extern unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size); |
294 | /* Calculate the number of bytes per image (not frame) */ | ||
295 | extern int pwc_mpt_reset(struct pwc_device *pdev, int flags); | 358 | extern int pwc_mpt_reset(struct pwc_device *pdev, int flags); |
296 | extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt); | 359 | extern int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt); |
297 | |||
298 | /* Various controls; should be obvious. Value 0..65535, or < 0 on error */ | ||
299 | extern int pwc_get_brightness(struct pwc_device *pdev); | ||
300 | extern int pwc_set_brightness(struct pwc_device *pdev, int value); | ||
301 | extern int pwc_get_contrast(struct pwc_device *pdev); | ||
302 | extern int pwc_set_contrast(struct pwc_device *pdev, int value); | ||
303 | extern int pwc_get_gamma(struct pwc_device *pdev); | ||
304 | extern int pwc_set_gamma(struct pwc_device *pdev, int value); | ||
305 | extern int pwc_get_saturation(struct pwc_device *pdev, int *value); | ||
306 | extern int pwc_set_saturation(struct pwc_device *pdev, int value); | ||
307 | extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); | 360 | extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); |
308 | extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); | 361 | extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); |
309 | extern int pwc_restore_user(struct pwc_device *pdev); | 362 | extern int send_control_msg(struct pwc_device *pdev, |
310 | extern int pwc_save_user(struct pwc_device *pdev); | 363 | u8 request, u16 value, void *buf, int buflen); |
311 | extern int pwc_restore_factory(struct pwc_device *pdev); | 364 | |
312 | 365 | /* Control get / set helpers */ | |
313 | /* exported for use by v4l2 controls */ | 366 | int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data); |
314 | extern int pwc_get_red_gain(struct pwc_device *pdev, int *value); | 367 | int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data); |
315 | extern int pwc_set_red_gain(struct pwc_device *pdev, int value); | 368 | int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data); |
316 | extern int pwc_get_blue_gain(struct pwc_device *pdev, int *value); | 369 | #define pwc_set_s8_ctrl pwc_set_u8_ctrl |
317 | extern int pwc_set_blue_gain(struct pwc_device *pdev, int value); | 370 | int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *dat); |
318 | extern int pwc_get_awb(struct pwc_device *pdev); | 371 | int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data); |
319 | extern int pwc_set_awb(struct pwc_device *pdev, int mode); | 372 | int pwc_button_ctrl(struct pwc_device *pdev, u16 value); |
320 | extern int pwc_set_agc(struct pwc_device *pdev, int mode, int value); | 373 | int pwc_init_controls(struct pwc_device *pdev); |
321 | extern int pwc_get_agc(struct pwc_device *pdev, int *value); | ||
322 | extern int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value); | ||
323 | extern int pwc_get_shutter_speed(struct pwc_device *pdev, int *value); | ||
324 | |||
325 | extern int pwc_set_colour_mode(struct pwc_device *pdev, int colour); | ||
326 | extern int pwc_get_colour_mode(struct pwc_device *pdev, int *colour); | ||
327 | extern int pwc_set_contour(struct pwc_device *pdev, int contour); | ||
328 | extern int pwc_get_contour(struct pwc_device *pdev, int *contour); | ||
329 | extern int pwc_set_backlight(struct pwc_device *pdev, int backlight); | ||
330 | extern int pwc_get_backlight(struct pwc_device *pdev, int *backlight); | ||
331 | extern int pwc_set_flicker(struct pwc_device *pdev, int flicker); | ||
332 | extern int pwc_get_flicker(struct pwc_device *pdev, int *flicker); | ||
333 | extern int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise); | ||
334 | extern int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise); | ||
335 | 374 | ||
336 | /* Power down or up the camera; not supported by all models */ | 375 | /* Power down or up the camera; not supported by all models */ |
337 | extern int pwc_camera_power(struct pwc_device *pdev, int power); | 376 | extern void pwc_camera_power(struct pwc_device *pdev, int power); |
338 | 377 | ||
339 | /* Private ioctl()s; see pwc-ioctl.h */ | 378 | /* Private ioctl()s; see pwc-ioctl.h */ |
340 | extern long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg); | 379 | extern long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg); |
@@ -343,12 +382,6 @@ extern const struct v4l2_ioctl_ops pwc_ioctl_ops; | |||
343 | 382 | ||
344 | /** pwc-uncompress.c */ | 383 | /** pwc-uncompress.c */ |
345 | /* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */ | 384 | /* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */ |
346 | extern int pwc_decompress(struct pwc_device *pdev); | 385 | int pwc_decompress(struct pwc_device *pdev, struct pwc_frame_buf *fbuf); |
347 | |||
348 | #ifdef __cplusplus | ||
349 | } | ||
350 | #endif | ||
351 | |||
352 | 386 | ||
353 | #endif | 387 | #endif |
354 | /* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ | ||