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 71 static 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 91 struct 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 98 static unsigned int Nala_fps_vector[PWC_FPS_MAX_NALA] = { 4, 5, 7, 10, 12, 15, 20, 24 }; 99 100 static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] = 101 { 102 #include "pwc-nala.h" 103 }; 104 105 /****************************************************************************/ 106 107 static 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 123 static 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 143 int 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 153 static 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 (frames > 25) 183 frames = 25; 184 frames = frames2frames[frames]; 185 fps = frames2table[frames]; 186 pEntry = &Nala_table[size][fps]; 187 if (pEntry->alternate == 0) 188 return -EINVAL; 189 190 if (send_to_cam) 191 ret = send_video_command(pdev, pdev->vendpoint, 192 pEntry->mode, 3); 193 if (ret < 0) 194 return ret; 195 196 if (pEntry->compressed && pixfmt == V4L2_PIX_FMT_YUV420) 197 pwc_dec1_init(pdev, pEntry->mode); 198 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; 210 } 211 else { 212 pdev->vbandlength = 704; 213 pdev->frame_size /= 3; 214 } 215 } 216 else 217 pdev->vbandlength = 0; 218 219 /* Let pwc-if.c:isoc_init know we don't support higher compression */ 220 *compression = 3; 221 222 return 0; 223 } 224 225 226 static int set_video_mode_Timon(struct pwc_device *pdev, int size, int pixfmt, 227 int frames, int *compression, int send_to_cam) 228 { 229 const struct Timon_table_entry *pChoose; 230 int fps, ret = 0; 231 232 if (size >= PSZ_MAX || *compression < 0 || *compression > 3) 233 return -EINVAL; 234 if (frames < 5) 235 frames = 5; 236 else if (size == PSZ_VGA && frames > 15) 237 frames = 15; 238 else if (frames > 30) 239 frames = 30; 240 fps = (frames / 5) - 1; 241 242 /* Find a supported framerate with progressively higher compression */ 243 pChoose = NULL; 244 while (*compression <= 3) { 245 pChoose = &Timon_table[size][fps][*compression]; 246 if (pChoose->alternate != 0) 247 break; 248 (*compression)++; 249 } 250 if (pChoose == NULL || pChoose->alternate == 0) 251 return -ENOENT; /* Not supported. */ 252 253 if (send_to_cam) 254 ret = send_video_command(pdev, pdev->vendpoint, 255 pChoose->mode, 13); 256 if (ret < 0) 257 return ret; 258 259 if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420) 260 pwc_dec23_init(pdev, pChoose->mode); 261 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; 271 else 272 pdev->frame_size = (pdev->width * pdev->height * 12) / 8; 273 return 0; 274 } 275 276 277 static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int pixfmt, 278 int frames, int *compression, int send_to_cam) 279 { 280 const struct Kiara_table_entry *pChoose = NULL; 281 int fps, ret = 0; 282 283 if (size >= PSZ_MAX || *compression < 0 || *compression > 3) 284 return -EINVAL; 285 if (frames < 5) 286 frames = 5; 287 else if (size == PSZ_VGA && frames > 15) 288 frames = 15; 289 else if (frames > 30) 290 frames = 30; 291 fps = (frames / 5) - 1; 292 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) 297 break; 298 (*compression)++; 299 } 300 if (pChoose == NULL || pChoose->alternate == 0) 301 return -ENOENT; /* Not supported. */ 302 303 /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ 304 if (send_to_cam) 305 ret = send_video_command(pdev, 4, pChoose->mode, 12); 306 if (ret < 0) 307 return ret; 308 309 if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420) 310 pwc_dec23_init(pdev, pChoose->mode); 311 312 /* All set and go */ 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; 321 else 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); 325 return 0; 326 } 327 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) 330 { 331 int ret, size; 332 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); 337 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); 344 } else { 345 ret = set_video_mode_Timon(pdev, size, pixfmt, frames, 346 compression, send_to_cam); 347 } 348 if (ret < 0) { 349 PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); 350 return ret; 351 } 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); 354 return 0; 355 } 356 357 static unsigned int pwc_get_fps_Nala(struct pwc_device *pdev, unsigned int index, unsigned int size) 358 { 359 unsigned int i; 360 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]; 364 } 365 } 366 return 0; 367 } 368 369 static unsigned int pwc_get_fps_Kiara(struct pwc_device *pdev, unsigned int index, unsigned int size) 370 { 371 unsigned int i; 372 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]; 376 } 377 } 378 return 0; 379 } 380 381 static unsigned int pwc_get_fps_Timon(struct pwc_device *pdev, unsigned int index, unsigned int size) 382 { 383 unsigned int i; 384 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]; 388 } 389 } 390 return 0; 391 } 392 393 unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size) 394 { 395 unsigned int ret; 396 397 if (DEVICE_USE_CODEC1(pdev->type)) { 398 ret = pwc_get_fps_Nala(pdev, index, size); 399 400 } else if (DEVICE_USE_CODEC3(pdev->type)) { 401 ret = pwc_get_fps_Kiara(pdev, index, size); 402 403 } else { 404 ret = pwc_get_fps_Timon(pdev, index, size); 405 } 406 407 return ret; 408 } 409 410 int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) 411 { 412 int ret; 413 414 ret = recv_control_msg(pdev, request, value, 1); 415 if (ret < 0) 416 return ret; 417 418 *data = pdev->ctrl_buf[0]; 419 return 0; 420 } 421 422 int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data) 423 { 424 int ret; 425 426 pdev->ctrl_buf[0] = data; 427 ret = send_control_msg(pdev, request, value, pdev->ctrl_buf, 1); 428 if (ret < 0) 429 return ret; 430 431 return 0; 432 } 433 434 int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) 435 { 436 int ret; 437 438 ret = recv_control_msg(pdev, request, value, 1); 439 if (ret < 0) 440 return ret; 441 442 *data = ((s8 *)pdev->ctrl_buf)[0]; 443 return 0; 444 } 445 446 int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) 447 { 448 int ret; 449 450 ret = recv_control_msg(pdev, request, value, 2); 451 if (ret < 0) 452 return ret; 453 454 *data = (pdev->ctrl_buf[1] << 8) | pdev->ctrl_buf[0]; 455 return 0; 456 } 457 458 int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data) 459 { 460 int ret; 461 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); 465 if (ret < 0) 466 return ret; 467 468 return 0; 469 } 470 471 int pwc_button_ctrl(struct pwc_device *pdev, u16 value) 472 { 473 int ret; 474 475 ret = send_control_msg(pdev, SET_STATUS_CTL, value, NULL, 0); 476 if (ret < 0) 477 return ret; 478 479 return 0; 480 } 481 482 /* POWER */ 483 void pwc_camera_power(struct pwc_device *pdev, int power) 484 { 485 int r; 486 487 if (!pdev->power_save) 488 return; 489 490 if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6)) 491 return; /* Not supported by Nala or Timon < release 6 */ 492 493 if (power) 494 pdev->ctrl_buf[0] = 0x00; /* active */ 495 else 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); 499 if (r < 0) 500 PWC_ERROR("Failed to power %s camera (%d)\n", 501 power ? "on" : "off", r); 502 } 503 504 int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) 505 { 506 int r; 507 508 if (pdev->type < 730) 509 return 0; 510 on_value /= 100; 511 off_value /= 100; 512 if (on_value < 0) 513 on_value = 0; 514 if (on_value > 0xff) 515 on_value = 0xff; 516 if (off_value < 0) 517 off_value = 0; 518 if (off_value > 0xff) 519 off_value = 0xff; 520 521 pdev->ctrl_buf[0] = on_value; 522 pdev->ctrl_buf[1] = off_value; 523 524 r = send_control_msg(pdev, 525 SET_STATUS_CTL, LED_FORMATTER, pdev->ctrl_buf, 2); 526 if (r < 0) 527 PWC_ERROR("Failed to set LED on/off time (%d)\n", r); 528 529 return r; 530 } 531 532 #ifdef CONFIG_USB_PWC_DEBUG 533 int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) 534 { 535 int ret = -1, request; 536 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 */ 541 else 542 request = SENSOR_TYPE_FORMATTER2; 543 544 ret = recv_control_msg(pdev, GET_STATUS_CTL, request, 1); 545 if (ret < 0) 546 return ret; 547 if (pdev->type < 675) 548 *sensor = pdev->ctrl_buf[0] | 0x100; 549 else 550 *sensor = pdev->ctrl_buf[0]; 551 return 0; 552 } 553 #endif 554