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 (frames
> 25)
184 frames
= frames2frames
[frames
];
185 fps
= frames2table
[frames
];
186 pEntry
= &Nala_table
[size
][fps
];
187 if (pEntry
->alternate
== 0)
191 ret
= send_video_command(pdev
, pdev
->vendpoint
,
196 if (pEntry
->compressed
&& pixfmt
== V4L2_PIX_FMT_YUV420
)
197 pwc_dec1_init(pdev
, pEntry
->mode
);
199 /* Set various parameters */
200 pdev
->pixfmt
= pixfmt
;
201 pdev
->vframes
= frames
;
202 pdev
->valternate
= pEntry
->alternate
;
203 pdev
->width
= pwc_image_sizes
[size
][0];
204 pdev
->height
= pwc_image_sizes
[size
][1];
205 pdev
->frame_size
= (pdev
->width
* pdev
->height
* 3) / 2;
206 if (pEntry
->compressed
) {
207 if (pdev
->release
< 5) { /* 4 fold compression */
208 pdev
->vbandlength
= 528;
209 pdev
->frame_size
/= 4;
212 pdev
->vbandlength
= 704;
213 pdev
->frame_size
/= 3;
217 pdev
->vbandlength
= 0;
219 /* Let pwc-if.c:isoc_init know we don't support higher compression */
226 static int set_video_mode_Timon(struct pwc_device
*pdev
, int size
, int pixfmt
,
227 int frames
, int *compression
, int send_to_cam
)
229 const struct Timon_table_entry
*pChoose
;
232 if (size
>= PSZ_MAX
|| *compression
< 0 || *compression
> 3)
236 else if (size
== PSZ_VGA
&& frames
> 15)
238 else if (frames
> 30)
240 fps
= (frames
/ 5) - 1;
242 /* Find a supported framerate with progressively higher compression */
244 while (*compression
<= 3) {
245 pChoose
= &Timon_table
[size
][fps
][*compression
];
246 if (pChoose
->alternate
!= 0)
250 if (pChoose
== NULL
|| pChoose
->alternate
== 0)
251 return -ENOENT
; /* Not supported. */
254 ret
= send_video_command(pdev
, pdev
->vendpoint
,
259 if (pChoose
->bandlength
> 0 && pixfmt
== V4L2_PIX_FMT_YUV420
)
260 pwc_dec23_init(pdev
, pChoose
->mode
);
262 /* Set various parameters */
263 pdev
->pixfmt
= pixfmt
;
264 pdev
->vframes
= (fps
+ 1) * 5;
265 pdev
->valternate
= pChoose
->alternate
;
266 pdev
->width
= pwc_image_sizes
[size
][0];
267 pdev
->height
= pwc_image_sizes
[size
][1];
268 pdev
->vbandlength
= pChoose
->bandlength
;
269 if (pChoose
->bandlength
> 0)
270 pdev
->frame_size
= (pChoose
->bandlength
* pdev
->height
) / 4;
272 pdev
->frame_size
= (pdev
->width
* pdev
->height
* 12) / 8;
277 static int set_video_mode_Kiara(struct pwc_device
*pdev
, int size
, int pixfmt
,
278 int frames
, int *compression
, int send_to_cam
)
280 const struct Kiara_table_entry
*pChoose
= NULL
;
283 if (size
>= PSZ_MAX
|| *compression
< 0 || *compression
> 3)
287 else if (size
== PSZ_VGA
&& frames
> 15)
289 else if (frames
> 30)
291 fps
= (frames
/ 5) - 1;
293 /* Find a supported framerate with progressively higher compression */
294 while (*compression
<= 3) {
295 pChoose
= &Kiara_table
[size
][fps
][*compression
];
296 if (pChoose
->alternate
!= 0)
300 if (pChoose
== NULL
|| pChoose
->alternate
== 0)
301 return -ENOENT
; /* Not supported. */
303 /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */
305 ret
= send_video_command(pdev
, 4, pChoose
->mode
, 12);
309 if (pChoose
->bandlength
> 0 && pixfmt
== V4L2_PIX_FMT_YUV420
)
310 pwc_dec23_init(pdev
, pChoose
->mode
);
313 pdev
->pixfmt
= pixfmt
;
314 pdev
->vframes
= (fps
+ 1) * 5;
315 pdev
->valternate
= pChoose
->alternate
;
316 pdev
->width
= pwc_image_sizes
[size
][0];
317 pdev
->height
= pwc_image_sizes
[size
][1];
318 pdev
->vbandlength
= pChoose
->bandlength
;
319 if (pdev
->vbandlength
> 0)
320 pdev
->frame_size
= (pdev
->vbandlength
* pdev
->height
) / 4;
322 pdev
->frame_size
= (pdev
->width
* pdev
->height
* 12) / 8;
323 PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vbandlength=%d\n",
324 pdev
->frame_size
, pdev
->vframes
, size
, pdev
->vbandlength
);
328 int pwc_set_video_mode(struct pwc_device
*pdev
, int width
, int height
,
329 int pixfmt
, int frames
, int *compression
, int send_to_cam
)
333 PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n",
334 width
, height
, frames
, pixfmt
);
335 size
= pwc_get_size(pdev
, width
, height
);
336 PWC_TRACE("decode_size = %d.\n", size
);
338 if (DEVICE_USE_CODEC1(pdev
->type
)) {
339 ret
= set_video_mode_Nala(pdev
, size
, pixfmt
, frames
,
340 compression
, send_to_cam
);
341 } else if (DEVICE_USE_CODEC3(pdev
->type
)) {
342 ret
= set_video_mode_Kiara(pdev
, size
, pixfmt
, frames
,
343 compression
, send_to_cam
);
345 ret
= set_video_mode_Timon(pdev
, size
, pixfmt
, frames
,
346 compression
, send_to_cam
);
349 PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name
[size
], frames
, ret
);
352 pdev
->frame_total_size
= pdev
->frame_size
+ pdev
->frame_header_size
+ pdev
->frame_trailer_size
;
353 PWC_DEBUG_SIZE("Set resolution to %dx%d\n", pdev
->width
, pdev
->height
);
357 static unsigned int pwc_get_fps_Nala(struct pwc_device
*pdev
, unsigned int index
, unsigned int size
)
361 for (i
= 0; i
< PWC_FPS_MAX_NALA
; i
++) {
362 if (Nala_table
[size
][i
].alternate
) {
363 if (index
--==0) return Nala_fps_vector
[i
];
369 static unsigned int pwc_get_fps_Kiara(struct pwc_device
*pdev
, unsigned int index
, unsigned int size
)
373 for (i
= 0; i
< PWC_FPS_MAX_KIARA
; i
++) {
374 if (Kiara_table
[size
][i
][3].alternate
) {
375 if (index
--==0) return Kiara_fps_vector
[i
];
381 static unsigned int pwc_get_fps_Timon(struct pwc_device
*pdev
, unsigned int index
, unsigned int size
)
385 for (i
=0; i
< PWC_FPS_MAX_TIMON
; i
++) {
386 if (Timon_table
[size
][i
][3].alternate
) {
387 if (index
--==0) return Timon_fps_vector
[i
];
393 unsigned int pwc_get_fps(struct pwc_device
*pdev
, unsigned int index
, unsigned int size
)
397 if (DEVICE_USE_CODEC1(pdev
->type
)) {
398 ret
= pwc_get_fps_Nala(pdev
, index
, size
);
400 } else if (DEVICE_USE_CODEC3(pdev
->type
)) {
401 ret
= pwc_get_fps_Kiara(pdev
, index
, size
);
404 ret
= pwc_get_fps_Timon(pdev
, index
, size
);
410 int pwc_get_u8_ctrl(struct pwc_device
*pdev
, u8 request
, u16 value
, int *data
)
414 ret
= recv_control_msg(pdev
, request
, value
, 1);
418 *data
= pdev
->ctrl_buf
[0];
422 int pwc_set_u8_ctrl(struct pwc_device
*pdev
, u8 request
, u16 value
, u8 data
)
426 pdev
->ctrl_buf
[0] = data
;
427 ret
= send_control_msg(pdev
, request
, value
, pdev
->ctrl_buf
, 1);
434 int pwc_get_s8_ctrl(struct pwc_device
*pdev
, u8 request
, u16 value
, int *data
)
438 ret
= recv_control_msg(pdev
, request
, value
, 1);
442 *data
= ((s8
*)pdev
->ctrl_buf
)[0];
446 int pwc_get_u16_ctrl(struct pwc_device
*pdev
, u8 request
, u16 value
, int *data
)
450 ret
= recv_control_msg(pdev
, request
, value
, 2);
454 *data
= (pdev
->ctrl_buf
[1] << 8) | pdev
->ctrl_buf
[0];
458 int pwc_set_u16_ctrl(struct pwc_device
*pdev
, u8 request
, u16 value
, u16 data
)
462 pdev
->ctrl_buf
[0] = data
& 0xff;
463 pdev
->ctrl_buf
[1] = data
>> 8;
464 ret
= send_control_msg(pdev
, request
, value
, pdev
->ctrl_buf
, 2);
471 int pwc_button_ctrl(struct pwc_device
*pdev
, u16 value
)
475 ret
= send_control_msg(pdev
, SET_STATUS_CTL
, value
, NULL
, 0);
483 void pwc_camera_power(struct pwc_device
*pdev
, int power
)
487 if (!pdev
->power_save
)
490 if (pdev
->type
< 675 || (pdev
->type
< 730 && pdev
->release
< 6))
491 return; /* Not supported by Nala or Timon < release 6 */
494 pdev
->ctrl_buf
[0] = 0x00; /* active */
496 pdev
->ctrl_buf
[0] = 0xFF; /* power save */
497 r
= send_control_msg(pdev
, SET_STATUS_CTL
,
498 SET_POWER_SAVE_MODE_FORMATTER
, pdev
->ctrl_buf
, 1);
500 PWC_ERROR("Failed to power %s camera (%d)\n",
501 power
? "on" : "off", r
);
504 int pwc_set_leds(struct pwc_device
*pdev
, int on_value
, int off_value
)
508 if (pdev
->type
< 730)
518 if (off_value
> 0xff)
521 pdev
->ctrl_buf
[0] = on_value
;
522 pdev
->ctrl_buf
[1] = off_value
;
524 r
= send_control_msg(pdev
,
525 SET_STATUS_CTL
, LED_FORMATTER
, pdev
->ctrl_buf
, 2);
527 PWC_ERROR("Failed to set LED on/off time (%d)\n", r
);
532 #ifdef CONFIG_USB_PWC_DEBUG
533 int pwc_get_cmos_sensor(struct pwc_device
*pdev
, int *sensor
)
535 int ret
= -1, request
;
537 if (pdev
->type
< 675)
538 request
= SENSOR_TYPE_FORMATTER1
;
539 else if (pdev
->type
< 730)
540 return -1; /* The Vesta series doesn't have this call */
542 request
= SENSOR_TYPE_FORMATTER2
;
544 ret
= recv_control_msg(pdev
, GET_STATUS_CTL
, request
, 1);
547 if (pdev
->type
< 675)
548 *sensor
= pdev
->ctrl_buf
[0] | 0x100;
550 *sensor
= pdev
->ctrl_buf
[0];