1/* Driver for Philips webcam 2 Functions that send various control messages to the webcam, including 3 video modes. 4 (C) 1999-2003 Nemosoft Unv. 5 (C) 2004-2006 Luc Saillard (luc@saillard.org) 6 (C) 2011 Hans de Goede <hdegoede@redhat.com> 7 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>. 11 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. 17 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. 22 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. 27 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 31*/ 32 33/* 34 Changes 35 2001/08/03 Alvarado Added methods for changing white balance and 36 red/green gains 37 */ 38 39/* Control functions for the cam; brightness, contrast, video mode, etc. */ 40 41#ifdef __KERNEL__ 42#include <asm/uaccess.h> 43#endif 44#include <asm/errno.h> 45 46#include "pwc.h" 47#include "pwc-kiara.h" 48#include "pwc-timon.h" 49#include "pwc-dec1.h" 50#include "pwc-dec23.h" 51 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 */ 67 68/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */ 69#define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100 70 71static const char *size2name[PSZ_MAX] = 72{ 73 "subQCIF", 74 "QSIF", 75 "QCIF", 76 "SIF", 77 "CIF", 78 "VGA", 79}; 80 81/********/ 82 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. 85 86 An alternate value of 0 means this mode is not available at all. 87 */ 88 89#define PWC_FPS_MAX_NALA 8 90 91struct Nala_table_entry { 92 char alternate; /* USB alternate setting */ 93 int compressed; /* Compressed yes/no */ 94 95 unsigned char mode[3]; /* precomputed mode table */ 96}; 97 98static unsigned int Nala_fps_vector[PWC_FPS_MAX_NALA] = { 4, 5, 7, 10, 12, 15, 20, 24 }; 99 100static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] = 101{ 102#include "pwc-nala.h" 103}; 104 105/****************************************************************************/ 106 107static int recv_control_msg(struct pwc_device *pdev, 108 u8 request, u16 value, int recv_count) 109{ 110 int rc; 111 112 rc = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), 113 request, 114 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 115 value, pdev->vcinterface, 116 pdev->ctrl_buf, recv_count, USB_CTRL_GET_TIMEOUT); 117 if (rc < 0) 118 PWC_ERROR("recv_control_msg error %d req %02x val %04x\n", 119 rc, request, value); 120 return rc; 121} 122 123static inline int send_video_command(struct pwc_device *pdev, 124 int index, const unsigned char *buf, int buflen) 125{ 126 int rc; 127 128 memcpy(pdev->ctrl_buf, buf, buflen); 129 130 rc = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), 131 SET_EP_STREAM_CTL, 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); 135 if (rc >= 0) 136 memcpy(pdev->cmd_buf, buf, buflen); 137 else 138 PWC_ERROR("send_video_command error %d\n", rc); 139 140 return rc; 141} 142 143int send_control_msg(struct pwc_device *pdev, 144 u8 request, u16 value, void *buf, int buflen) 145{ 146 return usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), 147 request, 148 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 149 value, pdev->vcinterface, 150 buf, buflen, USB_CTRL_SET_TIMEOUT); 151} 152 153static int set_video_mode_Nala(struct pwc_device *pdev, int size, int pixfmt, 154 int frames, int *compression, int send_to_cam) 155{ 156 int fps, ret = 0; 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 */ 166 24 /* 30 */ 167 }; 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 */ 175 7 /* 30 */ 176 }; 177 178 if (size < 0 || size > PSZ_CIF) 179 return -EINVAL; 180 if (frames < 4) 181 frames = 4; 182 else if (size > PSZ_QCIF && frames > 15) 183 frames = 15; 184 else if (frames > 25) 185 frames = 25; 186 frames = frames2frames[frames]; 187 fps = frames2table[frames]; 188 pEntry = &Nala_table[size][fps]; 189 if (pEntry->alternate == 0) 190 return -EINVAL; 191 192 if (send_to_cam) 193 ret = send_video_command(pdev, pdev->vendpoint, 194 pEntry->mode, 3); 195 if (ret < 0) 196 return ret; 197 198 if (pEntry->compressed && pixfmt == V4L2_PIX_FMT_YUV420) 199 pwc_dec1_init(pdev, pEntry->mode); 200 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; 212 } 213 else { 214 pdev->vbandlength = 704; 215 pdev->frame_size /= 3; 216 } 217 } 218 else 219 pdev->vbandlength = 0; 220 221 /* Let pwc-if.c:isoc_init know we don't support higher compression */ 222 *compression = 3; 223 224 return 0; 225} 226 227 228static int set_video_mode_Timon(struct pwc_device *pdev, int size, int pixfmt, 229 int frames, int *compression, int send_to_cam) 230{ 231 const struct Timon_table_entry *pChoose; 232 int fps, ret = 0; 233 234 if (size >= PSZ_MAX || *compression < 0 || *compression > 3) 235 return -EINVAL; 236 if (frames < 5) 237 frames = 5; 238 else if (size == PSZ_VGA && frames > 15) 239 frames = 15; 240 else if (frames > 30) 241 frames = 30; 242 fps = (frames / 5) - 1; 243 244 /* Find a supported framerate with progressively higher compression */ 245 pChoose = NULL; 246 while (*compression <= 3) { 247 pChoose = &Timon_table[size][fps][*compression]; 248 if (pChoose->alternate != 0) 249 break; 250 (*compression)++; 251 } 252 if (pChoose == NULL || pChoose->alternate == 0) 253 return -ENOENT; /* Not supported. */ 254 255 if (send_to_cam) 256 ret = send_video_command(pdev, pdev->vendpoint, 257 pChoose->mode, 13); 258 if (ret < 0) 259 return ret; 260 261 if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420) 262 pwc_dec23_init(pdev, pChoose->mode); 263 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; 273 else 274 pdev->frame_size = (pdev->width * pdev->height * 12) / 8; 275 return 0; 276} 277 278 279static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int pixfmt, 280 int frames, int *compression, int send_to_cam) 281{ 282 const struct Kiara_table_entry *pChoose = NULL; 283 int fps, ret = 0; 284 285 if (size >= PSZ_MAX || *compression < 0 || *compression > 3) 286 return -EINVAL; 287 if (frames < 5) 288 frames = 5; 289 else if (size == PSZ_VGA && frames > 15) 290 frames = 15; 291 else if (frames > 30) 292 frames = 30; 293 fps = (frames / 5) - 1; 294 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) 299 break; 300 (*compression)++; 301 } 302 if (pChoose == NULL || pChoose->alternate == 0) 303 return -ENOENT; /* Not supported. */ 304 305 /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ 306 if (send_to_cam) 307 ret = send_video_command(pdev, 4, pChoose->mode, 12); 308 if (ret < 0) 309 return ret; 310 311 if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420) 312 pwc_dec23_init(pdev, pChoose->mode); 313 314 /* All set and go */ 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; 323 else 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); 327 return 0; 328} 329 330int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, 331 int pixfmt, int frames, int *compression, int send_to_cam) 332{ 333 int ret, size; 334 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); 339 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); 346 } else { 347 ret = set_video_mode_Timon(pdev, size, pixfmt, frames, 348 compression, send_to_cam); 349 } 350 if (ret < 0) { 351 PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); 352 return ret; 353 } 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); 356 return 0; 357} 358 359static unsigned int pwc_get_fps_Nala(struct pwc_device *pdev, unsigned int index, unsigned int size) 360{ 361 unsigned int i; 362 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]; 366 } 367 } 368 return 0; 369} 370 371static unsigned int pwc_get_fps_Kiara(struct pwc_device *pdev, unsigned int index, unsigned int size) 372{ 373 unsigned int i; 374 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]; 378 } 379 } 380 return 0; 381} 382 383static unsigned int pwc_get_fps_Timon(struct pwc_device *pdev, unsigned int index, unsigned int size) 384{ 385 unsigned int i; 386 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]; 390 } 391 } 392 return 0; 393} 394 395unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size) 396{ 397 unsigned int ret; 398 399 if (DEVICE_USE_CODEC1(pdev->type)) { 400 ret = pwc_get_fps_Nala(pdev, index, size); 401 402 } else if (DEVICE_USE_CODEC3(pdev->type)) { 403 ret = pwc_get_fps_Kiara(pdev, index, size); 404 405 } else { 406 ret = pwc_get_fps_Timon(pdev, index, size); 407 } 408 409 return ret; 410} 411 412int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) 413{ 414 int ret; 415 416 ret = recv_control_msg(pdev, request, value, 1); 417 if (ret < 0) 418 return ret; 419 420 *data = pdev->ctrl_buf[0]; 421 return 0; 422} 423 424int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data) 425{ 426 int ret; 427 428 pdev->ctrl_buf[0] = data; 429 ret = send_control_msg(pdev, request, value, pdev->ctrl_buf, 1); 430 if (ret < 0) 431 return ret; 432 433 return 0; 434} 435 436int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) 437{ 438 int ret; 439 440 ret = recv_control_msg(pdev, request, value, 1); 441 if (ret < 0) 442 return ret; 443 444 *data = ((s8 *)pdev->ctrl_buf)[0]; 445 return 0; 446} 447 448int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) 449{ 450 int ret; 451 452 ret = recv_control_msg(pdev, request, value, 2); 453 if (ret < 0) 454 return ret; 455 456 *data = (pdev->ctrl_buf[1] << 8) | pdev->ctrl_buf[0]; 457 return 0; 458} 459 460int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data) 461{ 462 int ret; 463 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); 467 if (ret < 0) 468 return ret; 469 470 return 0; 471} 472 473int pwc_button_ctrl(struct pwc_device *pdev, u16 value) 474{ 475 int ret; 476 477 ret = send_control_msg(pdev, SET_STATUS_CTL, value, NULL, 0); 478 if (ret < 0) 479 return ret; 480 481 return 0; 482} 483 484/* POWER */ 485void pwc_camera_power(struct pwc_device *pdev, int power) 486{ 487 int r; 488 489 if (!pdev->power_save) 490 return; 491 492 if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6)) 493 return; /* Not supported by Nala or Timon < release 6 */ 494 495 if (power) 496 pdev->ctrl_buf[0] = 0x00; /* active */ 497 else 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); 501 if (r < 0) 502 PWC_ERROR("Failed to power %s camera (%d)\n", 503 power ? "on" : "off", r); 504} 505 506int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) 507{ 508 int r; 509 510 if (pdev->type < 730) 511 return 0; 512 on_value /= 100; 513 off_value /= 100; 514 if (on_value < 0) 515 on_value = 0; 516 if (on_value > 0xff) 517 on_value = 0xff; 518 if (off_value < 0) 519 off_value = 0; 520 if (off_value > 0xff) 521 off_value = 0xff; 522 523 pdev->ctrl_buf[0] = on_value; 524 pdev->ctrl_buf[1] = off_value; 525 526 r = send_control_msg(pdev, 527 SET_STATUS_CTL, LED_FORMATTER, pdev->ctrl_buf, 2); 528 if (r < 0) 529 PWC_ERROR("Failed to set LED on/off time (%d)\n", r); 530 531 return r; 532} 533 534#ifdef CONFIG_USB_PWC_DEBUG 535int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) 536{ 537 int ret = -1, request; 538 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 */ 543 else 544 request = SENSOR_TYPE_FORMATTER2; 545 546 ret = recv_control_msg(pdev, GET_STATUS_CTL, request, 1); 547 if (ret < 0) 548 return ret; 549 if (pdev->type < 675) 550 *sensor = pdev->ctrl_buf[0] | 0x100; 551 else 552 *sensor = pdev->ctrl_buf[0]; 553 return 0; 554} 555#endif 556