1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* Driver for Philips webcam
3 Functions that send various control messages to the webcam, including
5 (C) 1999-2003 Nemosoft Unv.
6 (C) 2004-2006 Luc Saillard (luc@saillard.org)
7 (C) 2011 Hans de Goede <hdegoede@redhat.com>
9 NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
10 driver and thus may have bugs that are not present in the original version.
11 Please send bug reports and support requests to <luc@saillard.org>.
13 NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
14 driver and thus may have bugs that are not present in the original version.
15 Please send bug reports and support requests to <luc@saillard.org>.
16 The decompression routines have been implemented by reverse-engineering the
17 Nemosoft binary pwcx module. Caveat emptor.
23 2001/08/03 Alvarado Added methods for changing white balance and
27 /* Control functions for the cam; brightness, contrast, video mode, etc. */
30 #include <linux/uaccess.h>
32 #include <asm/errno.h>
35 #include "pwc-kiara.h"
36 #include "pwc-timon.h"
38 #include "pwc-dec23.h"
40 /* Selectors for status controls used only in this file */
41 #define GET_STATUS_B00 0x0B00
42 #define SENSOR_TYPE_FORMATTER1 0x0C00
43 #define GET_STATUS_3000 0x3000
44 #define READ_RAW_Y_MEAN_FORMATTER 0x3100
45 #define SET_POWER_SAVE_MODE_FORMATTER 0x3200
46 #define MIRROR_IMAGE_FORMATTER 0x3300
47 #define LED_FORMATTER 0x3400
48 #define LOWLIGHT 0x3500
49 #define GET_STATUS_3600 0x3600
50 #define SENSOR_TYPE_FORMATTER2 0x3700
51 #define GET_STATUS_3800 0x3800
52 #define GET_STATUS_4000 0x4000
53 #define GET_STATUS_4100 0x4100 /* Get */
54 #define CTL_STATUS_4200 0x4200 /* [GS] 1 */
56 /* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
57 #define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100
59 static const char *size2name
[PSZ_MAX
] =
71 /* Entries for the Nala (645/646) camera; the Nala doesn't have compression
72 preferences, so you either get compressed or non-compressed streams.
74 An alternate value of 0 means this mode is not available at all.
77 #define PWC_FPS_MAX_NALA 8
79 struct Nala_table_entry
{
80 char alternate
; /* USB alternate setting */
81 int compressed
; /* Compressed yes/no */
83 unsigned char mode
[3]; /* precomputed mode table */
86 static unsigned int Nala_fps_vector
[PWC_FPS_MAX_NALA
] = { 4, 5, 7, 10, 12, 15, 20, 24 };
88 static struct Nala_table_entry Nala_table
[PSZ_MAX
][PWC_FPS_MAX_NALA
] =
93 /****************************************************************************/
95 static int recv_control_msg(struct pwc_device
*pdev
,
96 u8 request
, u16 value
, int recv_count
)
100 rc
= usb_control_msg(pdev
->udev
, usb_rcvctrlpipe(pdev
->udev
, 0),
102 USB_DIR_IN
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
103 value
, pdev
->vcinterface
,
104 pdev
->ctrl_buf
, recv_count
, USB_CTRL_GET_TIMEOUT
);
106 PWC_ERROR("recv_control_msg error %d req %02x val %04x\n",
111 static inline int send_video_command(struct pwc_device
*pdev
,
112 int index
, const unsigned char *buf
, int buflen
)
116 memcpy(pdev
->ctrl_buf
, buf
, buflen
);
118 rc
= usb_control_msg(pdev
->udev
, usb_sndctrlpipe(pdev
->udev
, 0),
120 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
121 VIDEO_OUTPUT_CONTROL_FORMATTER
, index
,
122 pdev
->ctrl_buf
, buflen
, USB_CTRL_SET_TIMEOUT
);
124 memcpy(pdev
->cmd_buf
, buf
, buflen
);
126 PWC_ERROR("send_video_command error %d\n", rc
);
131 int send_control_msg(struct pwc_device
*pdev
,
132 u8 request
, u16 value
, void *buf
, int buflen
)
134 return usb_control_msg(pdev
->udev
, usb_sndctrlpipe(pdev
->udev
, 0),
136 USB_DIR_OUT
| USB_TYPE_VENDOR
| USB_RECIP_DEVICE
,
137 value
, pdev
->vcinterface
,
138 buf
, buflen
, USB_CTRL_SET_TIMEOUT
);
141 static int set_video_mode_Nala(struct pwc_device
*pdev
, int size
, int pixfmt
,
142 int frames
, int *compression
, int send_to_cam
)
145 struct Nala_table_entry
*pEntry
;
146 int frames2frames
[31] =
147 { /* closest match of framerate */
148 0, 0, 0, 0, 4, /* 0-4 */
149 5, 5, 7, 7, 10, /* 5-9 */
150 10, 10, 12, 12, 15, /* 10-14 */
151 15, 15, 15, 20, 20, /* 15-19 */
152 20, 20, 20, 24, 24, /* 20-24 */
153 24, 24, 24, 24, 24, /* 25-29 */
156 int frames2table
[31] =
157 { 0, 0, 0, 0, 0, /* 0-4 */
158 1, 1, 1, 2, 2, /* 5-9 */
159 3, 3, 4, 4, 4, /* 10-14 */
160 5, 5, 5, 5, 5, /* 15-19 */
161 6, 6, 6, 6, 7, /* 20-24 */
162 7, 7, 7, 7, 7, /* 25-29 */
166 if (size
< 0 || size
> PSZ_CIF
)
170 else if (size
> PSZ_QCIF
&& frames
> 15)
172 else if (frames
> 25)
174 frames
= frames2frames
[frames
];
175 fps
= frames2table
[frames
];
176 pEntry
= &Nala_table
[size
][fps
];
177 if (pEntry
->alternate
== 0)
181 ret
= send_video_command(pdev
, pdev
->vendpoint
,
186 if (pEntry
->compressed
&& pixfmt
== V4L2_PIX_FMT_YUV420
)
187 pwc_dec1_init(pdev
, pEntry
->mode
);
189 /* Set various parameters */
190 pdev
->pixfmt
= pixfmt
;
191 pdev
->vframes
= frames
;
192 pdev
->valternate
= pEntry
->alternate
;
193 pdev
->width
= pwc_image_sizes
[size
][0];
194 pdev
->height
= pwc_image_sizes
[size
][1];
195 pdev
->frame_size
= (pdev
->width
* pdev
->height
* 3) / 2;
196 if (pEntry
->compressed
) {
197 if (pdev
->release
< 5) { /* 4 fold compression */
198 pdev
->vbandlength
= 528;
199 pdev
->frame_size
/= 4;
202 pdev
->vbandlength
= 704;
203 pdev
->frame_size
/= 3;
207 pdev
->vbandlength
= 0;
209 /* Let pwc-if.c:isoc_init know we don't support higher compression */
216 static int set_video_mode_Timon(struct pwc_device
*pdev
, int size
, int pixfmt
,
217 int frames
, int *compression
, int send_to_cam
)
219 const struct Timon_table_entry
*pChoose
;
222 if (size
>= PSZ_MAX
|| *compression
< 0 || *compression
> 3)
226 else if (size
== PSZ_VGA
&& frames
> 15)
228 else if (frames
> 30)
230 fps
= (frames
/ 5) - 1;
232 /* Find a supported framerate with progressively higher compression */
234 pChoose
= &Timon_table
[size
][fps
][*compression
];
235 if (pChoose
->alternate
!= 0)
238 } while (*compression
<= 3);
240 if (pChoose
->alternate
== 0)
241 return -ENOENT
; /* Not supported. */
244 ret
= send_video_command(pdev
, pdev
->vendpoint
,
249 if (pChoose
->bandlength
> 0 && pixfmt
== V4L2_PIX_FMT_YUV420
)
250 pwc_dec23_init(pdev
, pChoose
->mode
);
252 /* Set various parameters */
253 pdev
->pixfmt
= pixfmt
;
254 pdev
->vframes
= (fps
+ 1) * 5;
255 pdev
->valternate
= pChoose
->alternate
;
256 pdev
->width
= pwc_image_sizes
[size
][0];
257 pdev
->height
= pwc_image_sizes
[size
][1];
258 pdev
->vbandlength
= pChoose
->bandlength
;
259 if (pChoose
->bandlength
> 0)
260 pdev
->frame_size
= (pChoose
->bandlength
* pdev
->height
) / 4;
262 pdev
->frame_size
= (pdev
->width
* pdev
->height
* 12) / 8;
267 static int set_video_mode_Kiara(struct pwc_device
*pdev
, int size
, int pixfmt
,
268 int frames
, int *compression
, int send_to_cam
)
270 const struct Kiara_table_entry
*pChoose
;
273 if (size
>= PSZ_MAX
|| *compression
< 0 || *compression
> 3)
277 else if (size
== PSZ_VGA
&& frames
> 15)
279 else if (frames
> 30)
281 fps
= (frames
/ 5) - 1;
283 /* Find a supported framerate with progressively higher compression */
285 pChoose
= &Kiara_table
[size
][fps
][*compression
];
286 if (pChoose
->alternate
!= 0)
289 } while (*compression
<= 3);
291 if (pChoose
->alternate
== 0)
292 return -ENOENT
; /* Not supported. */
294 /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */
296 ret
= send_video_command(pdev
, 4, pChoose
->mode
, 12);
300 if (pChoose
->bandlength
> 0 && pixfmt
== V4L2_PIX_FMT_YUV420
)
301 pwc_dec23_init(pdev
, pChoose
->mode
);
304 pdev
->pixfmt
= pixfmt
;
305 pdev
->vframes
= (fps
+ 1) * 5;
306 pdev
->valternate
= pChoose
->alternate
;
307 pdev
->width
= pwc_image_sizes
[size
][0];
308 pdev
->height
= pwc_image_sizes
[size
][1];
309 pdev
->vbandlength
= pChoose
->bandlength
;
310 if (pdev
->vbandlength
> 0)
311 pdev
->frame_size
= (pdev
->vbandlength
* pdev
->height
) / 4;
313 pdev
->frame_size
= (pdev
->width
* pdev
->height
* 12) / 8;
314 PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vbandlength=%d\n",
315 pdev
->frame_size
, pdev
->vframes
, size
, pdev
->vbandlength
);
319 int pwc_set_video_mode(struct pwc_device
*pdev
, int width
, int height
,
320 int pixfmt
, int frames
, int *compression
, int send_to_cam
)
324 PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n",
325 width
, height
, frames
, pixfmt
);
326 size
= pwc_get_size(pdev
, width
, height
);
327 PWC_TRACE("decode_size = %d.\n", size
);
329 if (DEVICE_USE_CODEC1(pdev
->type
)) {
330 ret
= set_video_mode_Nala(pdev
, size
, pixfmt
, frames
,
331 compression
, send_to_cam
);
332 } else if (DEVICE_USE_CODEC3(pdev
->type
)) {
333 ret
= set_video_mode_Kiara(pdev
, size
, pixfmt
, frames
,
334 compression
, send_to_cam
);
336 ret
= set_video_mode_Timon(pdev
, size
, pixfmt
, frames
,
337 compression
, send_to_cam
);
340 PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name
[size
], frames
, ret
);
343 pdev
->frame_total_size
= pdev
->frame_size
+ pdev
->frame_header_size
+ pdev
->frame_trailer_size
;
344 PWC_DEBUG_SIZE("Set resolution to %dx%d\n", pdev
->width
, pdev
->height
);
348 static unsigned int pwc_get_fps_Nala(struct pwc_device
*pdev
, unsigned int index
, unsigned int size
)
352 for (i
= 0; i
< PWC_FPS_MAX_NALA
; i
++) {
353 if (Nala_table
[size
][i
].alternate
) {
354 if (index
--==0) return Nala_fps_vector
[i
];
360 static unsigned int pwc_get_fps_Kiara(struct pwc_device
*pdev
, unsigned int index
, unsigned int size
)
364 for (i
= 0; i
< PWC_FPS_MAX_KIARA
; i
++) {
365 if (Kiara_table
[size
][i
][3].alternate
) {
366 if (index
--==0) return Kiara_fps_vector
[i
];
372 static unsigned int pwc_get_fps_Timon(struct pwc_device
*pdev
, unsigned int index
, unsigned int size
)
376 for (i
=0; i
< PWC_FPS_MAX_TIMON
; i
++) {
377 if (Timon_table
[size
][i
][3].alternate
) {
378 if (index
--==0) return Timon_fps_vector
[i
];
384 unsigned int pwc_get_fps(struct pwc_device
*pdev
, unsigned int index
, unsigned int size
)
388 if (DEVICE_USE_CODEC1(pdev
->type
)) {
389 ret
= pwc_get_fps_Nala(pdev
, index
, size
);
391 } else if (DEVICE_USE_CODEC3(pdev
->type
)) {
392 ret
= pwc_get_fps_Kiara(pdev
, index
, size
);
395 ret
= pwc_get_fps_Timon(pdev
, index
, size
);
401 int pwc_get_u8_ctrl(struct pwc_device
*pdev
, u8 request
, u16 value
, int *data
)
405 ret
= recv_control_msg(pdev
, request
, value
, 1);
409 *data
= pdev
->ctrl_buf
[0];
413 int pwc_set_u8_ctrl(struct pwc_device
*pdev
, u8 request
, u16 value
, u8 data
)
417 pdev
->ctrl_buf
[0] = data
;
418 ret
= send_control_msg(pdev
, request
, value
, pdev
->ctrl_buf
, 1);
425 int pwc_get_s8_ctrl(struct pwc_device
*pdev
, u8 request
, u16 value
, int *data
)
429 ret
= recv_control_msg(pdev
, request
, value
, 1);
433 *data
= ((s8
*)pdev
->ctrl_buf
)[0];
437 int pwc_get_u16_ctrl(struct pwc_device
*pdev
, u8 request
, u16 value
, int *data
)
441 ret
= recv_control_msg(pdev
, request
, value
, 2);
445 *data
= (pdev
->ctrl_buf
[1] << 8) | pdev
->ctrl_buf
[0];
449 int pwc_set_u16_ctrl(struct pwc_device
*pdev
, u8 request
, u16 value
, u16 data
)
453 pdev
->ctrl_buf
[0] = data
& 0xff;
454 pdev
->ctrl_buf
[1] = data
>> 8;
455 ret
= send_control_msg(pdev
, request
, value
, pdev
->ctrl_buf
, 2);
462 int pwc_button_ctrl(struct pwc_device
*pdev
, u16 value
)
466 ret
= send_control_msg(pdev
, SET_STATUS_CTL
, value
, NULL
, 0);
474 void pwc_camera_power(struct pwc_device
*pdev
, int power
)
478 if (!pdev
->power_save
)
481 if (pdev
->type
< 675 || (pdev
->type
< 730 && pdev
->release
< 6))
482 return; /* Not supported by Nala or Timon < release 6 */
485 pdev
->ctrl_buf
[0] = 0x00; /* active */
487 pdev
->ctrl_buf
[0] = 0xFF; /* power save */
488 r
= send_control_msg(pdev
, SET_STATUS_CTL
,
489 SET_POWER_SAVE_MODE_FORMATTER
, pdev
->ctrl_buf
, 1);
491 PWC_ERROR("Failed to power %s camera (%d)\n",
492 power
? "on" : "off", r
);
495 int pwc_set_leds(struct pwc_device
*pdev
, int on_value
, int off_value
)
499 if (pdev
->type
< 730)
509 if (off_value
> 0xff)
512 pdev
->ctrl_buf
[0] = on_value
;
513 pdev
->ctrl_buf
[1] = off_value
;
515 r
= send_control_msg(pdev
,
516 SET_STATUS_CTL
, LED_FORMATTER
, pdev
->ctrl_buf
, 2);
518 PWC_ERROR("Failed to set LED on/off time (%d)\n", r
);
523 #ifdef CONFIG_USB_PWC_DEBUG
524 int pwc_get_cmos_sensor(struct pwc_device
*pdev
, int *sensor
)
526 int ret
= -1, request
;
528 if (pdev
->type
< 675)
529 request
= SENSOR_TYPE_FORMATTER1
;
530 else if (pdev
->type
< 730)
531 return -1; /* The Vesta series doesn't have this call */
533 request
= SENSOR_TYPE_FORMATTER2
;
535 ret
= recv_control_msg(pdev
, GET_STATUS_CTL
, request
, 1);
538 if (pdev
->type
< 675)
539 *sensor
= pdev
->ctrl_buf
[0] | 0x100;
541 *sensor
= pdev
->ctrl_buf
[0];