1 /* Driver for Philips webcam
2 Functions that send various control messages to the webcam, including
4 (C) 1999-2003 Nemosoft Unv.
5 (C) 2004-2006 Luc Saillard (luc@saillard.org)
6 (C) 2011 Hans de Goede <hdegoede@redhat.com>
8 NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
9 driver and thus may have bugs that are not present in the original version.
10 Please send bug reports and support requests to <luc@saillard.org>.
12 NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
13 driver and thus may have bugs that are not present in the original version.
14 Please send bug reports and support requests to <luc@saillard.org>.
15 The decompression routines have been implemented by reverse-engineering the
16 Nemosoft binary pwcx module. Caveat emptor.
18 This program is free software; you can redistribute it and/or modify
19 it under the terms of the GNU General Public License as published by
20 the Free Software Foundation; either version 2 of the License, or
21 (at your option) any later version.
23 This program is distributed in the hope that it will be useful,
24 but WITHOUT ANY WARRANTY; without even the implied warranty of
25 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 GNU General Public License for more details.
28 You should have received a copy of the GNU General Public License
29 along with this program; if not, write to the Free Software
30 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
35 2001/08/03 Alvarado Added methods for changing white balance and
39 /* Control functions for the cam; brightness, contrast, video mode, etc. */
42 #include <asm/uaccess.h>
44 #include <asm/errno.h>
47 #include "pwc-kiara.h"
48 #include "pwc-timon.h"
50 #include "pwc-dec23.h"
52 /* Selectors for status controls used only in this file */
53 #define GET_STATUS_B00 0x0B00
54 #define SENSOR_TYPE_FORMATTER1 0x0C00
55 #define GET_STATUS_3000 0x3000
56 #define READ_RAW_Y_MEAN_FORMATTER 0x3100
57 #define SET_POWER_SAVE_MODE_FORMATTER 0x3200
58 #define MIRROR_IMAGE_FORMATTER 0x3300
59 #define LED_FORMATTER 0x3400
60 #define LOWLIGHT 0x3500
61 #define GET_STATUS_3600 0x3600
62 #define SENSOR_TYPE_FORMATTER2 0x3700
63 #define GET_STATUS_3800 0x3800
64 #define GET_STATUS_4000 0x4000
65 #define GET_STATUS_4100 0x4100 /* Get */
66 #define CTL_STATUS_4200 0x4200 /* [GS] 1 */
68 /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
69 #define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100
71 static const char *size2name
[PSZ_MAX
] =
83 /* Entries for the Nala (645/646) camera; the Nala doesn't have compression
84 preferences, so you either get compressed or non-compressed streams.
86 An alternate value of 0 means this mode is not available at all.
89 #define PWC_FPS_MAX_NALA 8
91 struct Nala_table_entry
{
92 char alternate
; /* USB alternate setting */
93 int compressed
; /* Compressed yes/no */
95 unsigned char mode
[3]; /* precomputed mode table */
98 static unsigned int Nala_fps_vector
[PWC_FPS_MAX_NALA
] = { 4, 5, 7, 10, 12, 15, 20, 24 };
100 static struct Nala_table_entry Nala_table
[PSZ_MAX
][PWC_FPS_MAX_NALA
] =
102 #include "pwc-nala.h"
105 /****************************************************************************/
107 static int recv_control_msg(struct pwc_device
*pdev
,
108 u8 request
, u16 value
, int recv_count
)
112 rc
= usb_control_msg(pdev
->udev
, usb_rcvctrlpipe(pdev
->udev
, 0),
114 USB_DIR_IN
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
115 value
, pdev
->vcinterface
,
116 pdev
->ctrl_buf
, recv_count
, USB_CTRL_GET_TIMEOUT
);
118 PWC_ERROR("recv_control_msg error %d req %02x val %04x\n",
123 static inline int send_video_command(struct pwc_device
*pdev
,
124 int index
, const unsigned char *buf
, int buflen
)
128 memcpy(pdev
->ctrl_buf
, buf
, buflen
);
130 rc
= usb_control_msg(pdev
->udev
, usb_sndctrlpipe(pdev
->udev
, 0),
132 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
133 VIDEO_OUTPUT_CONTROL_FORMATTER
, index
,
134 pdev
->ctrl_buf
, buflen
, USB_CTRL_SET_TIMEOUT
);
136 memcpy(pdev
->cmd_buf
, buf
, buflen
);
138 PWC_ERROR("send_video_command error %d\n", rc
);
143 int send_control_msg(struct pwc_device
*pdev
,
144 u8 request
, u16 value
, void *buf
, int buflen
)
146 return usb_control_msg(pdev
->udev
, usb_sndctrlpipe(pdev
->udev
, 0),
148 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
149 value
, pdev
->vcinterface
,
150 buf
, buflen
, USB_CTRL_SET_TIMEOUT
);
153 static int set_video_mode_Nala(struct pwc_device
*pdev
, int size
, int pixfmt
,
154 int frames
, int *compression
, int send_to_cam
)
157 struct Nala_table_entry
*pEntry
;
158 int frames2frames
[31] =
159 { /* closest match of framerate */
160 0, 0, 0, 0, 4, /* 0-4 */
161 5, 5, 7, 7, 10, /* 5-9 */
162 10, 10, 12, 12, 15, /* 10-14 */
163 15, 15, 15, 20, 20, /* 15-19 */
164 20, 20, 20, 24, 24, /* 20-24 */
165 24, 24, 24, 24, 24, /* 25-29 */
168 int frames2table
[31] =
169 { 0, 0, 0, 0, 0, /* 0-4 */
170 1, 1, 1, 2, 2, /* 5-9 */
171 3, 3, 4, 4, 4, /* 10-14 */
172 5, 5, 5, 5, 5, /* 15-19 */
173 6, 6, 6, 6, 7, /* 20-24 */
174 7, 7, 7, 7, 7, /* 25-29 */
178 if (size
< 0 || size
> PSZ_CIF
)
182 else if (size
> PSZ_QCIF
&& frames
> 15)
184 else if (frames
> 25)
186 frames
= frames2frames
[frames
];
187 fps
= frames2table
[frames
];
188 pEntry
= &Nala_table
[size
][fps
];
189 if (pEntry
->alternate
== 0)
193 ret
= send_video_command(pdev
, pdev
->vendpoint
,
198 if (pEntry
->compressed
&& pixfmt
== V4L2_PIX_FMT_YUV420
)
199 pwc_dec1_init(pdev
, pEntry
->mode
);
201 /* Set various parameters */
202 pdev
->pixfmt
= pixfmt
;
203 pdev
->vframes
= frames
;
204 pdev
->valternate
= pEntry
->alternate
;
205 pdev
->width
= pwc_image_sizes
[size
][0];
206 pdev
->height
= pwc_image_sizes
[size
][1];
207 pdev
->frame_size
= (pdev
->width
* pdev
->height
* 3) / 2;
208 if (pEntry
->compressed
) {
209 if (pdev
->release
< 5) { /* 4 fold compression */
210 pdev
->vbandlength
= 528;
211 pdev
->frame_size
/= 4;
214 pdev
->vbandlength
= 704;
215 pdev
->frame_size
/= 3;
219 pdev
->vbandlength
= 0;
221 /* Let pwc-if.c:isoc_init know we don't support higher compression */
228 static int set_video_mode_Timon(struct pwc_device
*pdev
, int size
, int pixfmt
,
229 int frames
, int *compression
, int send_to_cam
)
231 const struct Timon_table_entry
*pChoose
;
234 if (size
>= PSZ_MAX
|| *compression
< 0 || *compression
> 3)
238 else if (size
== PSZ_VGA
&& frames
> 15)
240 else if (frames
> 30)
242 fps
= (frames
/ 5) - 1;
244 /* Find a supported framerate with progressively higher compression */
246 while (*compression
<= 3) {
247 pChoose
= &Timon_table
[size
][fps
][*compression
];
248 if (pChoose
->alternate
!= 0)
252 if (pChoose
== NULL
|| pChoose
->alternate
== 0)
253 return -ENOENT
; /* Not supported. */
256 ret
= send_video_command(pdev
, pdev
->vendpoint
,
261 if (pChoose
->bandlength
> 0 && pixfmt
== V4L2_PIX_FMT_YUV420
)
262 pwc_dec23_init(pdev
, pChoose
->mode
);
264 /* Set various parameters */
265 pdev
->pixfmt
= pixfmt
;
266 pdev
->vframes
= (fps
+ 1) * 5;
267 pdev
->valternate
= pChoose
->alternate
;
268 pdev
->width
= pwc_image_sizes
[size
][0];
269 pdev
->height
= pwc_image_sizes
[size
][1];
270 pdev
->vbandlength
= pChoose
->bandlength
;
271 if (pChoose
->bandlength
> 0)
272 pdev
->frame_size
= (pChoose
->bandlength
* pdev
->height
) / 4;
274 pdev
->frame_size
= (pdev
->width
* pdev
->height
* 12) / 8;
279 static int set_video_mode_Kiara(struct pwc_device
*pdev
, int size
, int pixfmt
,
280 int frames
, int *compression
, int send_to_cam
)
282 const struct Kiara_table_entry
*pChoose
= NULL
;
285 if (size
>= PSZ_MAX
|| *compression
< 0 || *compression
> 3)
289 else if (size
== PSZ_VGA
&& frames
> 15)
291 else if (frames
> 30)
293 fps
= (frames
/ 5) - 1;
295 /* Find a supported framerate with progressively higher compression */
296 while (*compression
<= 3) {
297 pChoose
= &Kiara_table
[size
][fps
][*compression
];
298 if (pChoose
->alternate
!= 0)
302 if (pChoose
== NULL
|| pChoose
->alternate
== 0)
303 return -ENOENT
; /* Not supported. */
305 /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */
307 ret
= send_video_command(pdev
, 4, pChoose
->mode
, 12);
311 if (pChoose
->bandlength
> 0 && pixfmt
== V4L2_PIX_FMT_YUV420
)
312 pwc_dec23_init(pdev
, pChoose
->mode
);
315 pdev
->pixfmt
= pixfmt
;
316 pdev
->vframes
= (fps
+ 1) * 5;
317 pdev
->valternate
= pChoose
->alternate
;
318 pdev
->width
= pwc_image_sizes
[size
][0];
319 pdev
->height
= pwc_image_sizes
[size
][1];
320 pdev
->vbandlength
= pChoose
->bandlength
;
321 if (pdev
->vbandlength
> 0)
322 pdev
->frame_size
= (pdev
->vbandlength
* pdev
->height
) / 4;
324 pdev
->frame_size
= (pdev
->width
* pdev
->height
* 12) / 8;
325 PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vbandlength=%d\n",
326 pdev
->frame_size
, pdev
->vframes
, size
, pdev
->vbandlength
);
330 int pwc_set_video_mode(struct pwc_device
*pdev
, int width
, int height
,
331 int pixfmt
, int frames
, int *compression
, int send_to_cam
)
335 PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n",
336 width
, height
, frames
, pixfmt
);
337 size
= pwc_get_size(pdev
, width
, height
);
338 PWC_TRACE("decode_size = %d.\n", size
);
340 if (DEVICE_USE_CODEC1(pdev
->type
)) {
341 ret
= set_video_mode_Nala(pdev
, size
, pixfmt
, frames
,
342 compression
, send_to_cam
);
343 } else if (DEVICE_USE_CODEC3(pdev
->type
)) {
344 ret
= set_video_mode_Kiara(pdev
, size
, pixfmt
, frames
,
345 compression
, send_to_cam
);
347 ret
= set_video_mode_Timon(pdev
, size
, pixfmt
, frames
,
348 compression
, send_to_cam
);
351 PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name
[size
], frames
, ret
);
354 pdev
->frame_total_size
= pdev
->frame_size
+ pdev
->frame_header_size
+ pdev
->frame_trailer_size
;
355 PWC_DEBUG_SIZE("Set resolution to %dx%d\n", pdev
->width
, pdev
->height
);
359 static unsigned int pwc_get_fps_Nala(struct pwc_device
*pdev
, unsigned int index
, unsigned int size
)
363 for (i
= 0; i
< PWC_FPS_MAX_NALA
; i
++) {
364 if (Nala_table
[size
][i
].alternate
) {
365 if (index
--==0) return Nala_fps_vector
[i
];
371 static unsigned int pwc_get_fps_Kiara(struct pwc_device
*pdev
, unsigned int index
, unsigned int size
)
375 for (i
= 0; i
< PWC_FPS_MAX_KIARA
; i
++) {
376 if (Kiara_table
[size
][i
][3].alternate
) {
377 if (index
--==0) return Kiara_fps_vector
[i
];
383 static unsigned int pwc_get_fps_Timon(struct pwc_device
*pdev
, unsigned int index
, unsigned int size
)
387 for (i
=0; i
< PWC_FPS_MAX_TIMON
; i
++) {
388 if (Timon_table
[size
][i
][3].alternate
) {
389 if (index
--==0) return Timon_fps_vector
[i
];
395 unsigned int pwc_get_fps(struct pwc_device
*pdev
, unsigned int index
, unsigned int size
)
399 if (DEVICE_USE_CODEC1(pdev
->type
)) {
400 ret
= pwc_get_fps_Nala(pdev
, index
, size
);
402 } else if (DEVICE_USE_CODEC3(pdev
->type
)) {
403 ret
= pwc_get_fps_Kiara(pdev
, index
, size
);
406 ret
= pwc_get_fps_Timon(pdev
, index
, size
);
412 int pwc_get_u8_ctrl(struct pwc_device
*pdev
, u8 request
, u16 value
, int *data
)
416 ret
= recv_control_msg(pdev
, request
, value
, 1);
420 *data
= pdev
->ctrl_buf
[0];
424 int pwc_set_u8_ctrl(struct pwc_device
*pdev
, u8 request
, u16 value
, u8 data
)
428 pdev
->ctrl_buf
[0] = data
;
429 ret
= send_control_msg(pdev
, request
, value
, pdev
->ctrl_buf
, 1);
436 int pwc_get_s8_ctrl(struct pwc_device
*pdev
, u8 request
, u16 value
, int *data
)
440 ret
= recv_control_msg(pdev
, request
, value
, 1);
444 *data
= ((s8
*)pdev
->ctrl_buf
)[0];
448 int pwc_get_u16_ctrl(struct pwc_device
*pdev
, u8 request
, u16 value
, int *data
)
452 ret
= recv_control_msg(pdev
, request
, value
, 2);
456 *data
= (pdev
->ctrl_buf
[1] << 8) | pdev
->ctrl_buf
[0];
460 int pwc_set_u16_ctrl(struct pwc_device
*pdev
, u8 request
, u16 value
, u16 data
)
464 pdev
->ctrl_buf
[0] = data
& 0xff;
465 pdev
->ctrl_buf
[1] = data
>> 8;
466 ret
= send_control_msg(pdev
, request
, value
, pdev
->ctrl_buf
, 2);
473 int pwc_button_ctrl(struct pwc_device
*pdev
, u16 value
)
477 ret
= send_control_msg(pdev
, SET_STATUS_CTL
, value
, NULL
, 0);
485 void pwc_camera_power(struct pwc_device
*pdev
, int power
)
489 if (!pdev
->power_save
)
492 if (pdev
->type
< 675 || (pdev
->type
< 730 && pdev
->release
< 6))
493 return; /* Not supported by Nala or Timon < release 6 */
496 pdev
->ctrl_buf
[0] = 0x00; /* active */
498 pdev
->ctrl_buf
[0] = 0xFF; /* power save */
499 r
= send_control_msg(pdev
, SET_STATUS_CTL
,
500 SET_POWER_SAVE_MODE_FORMATTER
, pdev
->ctrl_buf
, 1);
502 PWC_ERROR("Failed to power %s camera (%d)\n",
503 power
? "on" : "off", r
);
506 int pwc_set_leds(struct pwc_device
*pdev
, int on_value
, int off_value
)
510 if (pdev
->type
< 730)
520 if (off_value
> 0xff)
523 pdev
->ctrl_buf
[0] = on_value
;
524 pdev
->ctrl_buf
[1] = off_value
;
526 r
= send_control_msg(pdev
,
527 SET_STATUS_CTL
, LED_FORMATTER
, pdev
->ctrl_buf
, 2);
529 PWC_ERROR("Failed to set LED on/off time (%d)\n", r
);
534 #ifdef CONFIG_USB_PWC_DEBUG
535 int pwc_get_cmos_sensor(struct pwc_device
*pdev
, int *sensor
)
537 int ret
= -1, request
;
539 if (pdev
->type
< 675)
540 request
= SENSOR_TYPE_FORMATTER1
;
541 else if (pdev
->type
< 730)
542 return -1; /* The Vesta series doesn't have this call */
544 request
= SENSOR_TYPE_FORMATTER2
;
546 ret
= recv_control_msg(pdev
, GET_STATUS_CTL
, request
, 1);
549 if (pdev
->type
< 675)
550 *sensor
= pdev
->ctrl_buf
[0] | 0x100;
552 *sensor
= pdev
->ctrl_buf
[0];