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 <linux/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 (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 228 static 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 do { 246 pChoose = &Timon_table[size][fps][*compression]; 247 if (pChoose->alternate != 0) 248 break; 249 (*compression)++; 250 } while (*compression <= 3); 251 252 if (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 279 static 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; 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 do { 297 pChoose = &Kiara_table[size][fps][*compression]; 298 if (pChoose->alternate != 0) 299 break; 300 (*compression)++; 301 } while (*compression <= 3); 302 303 if (pChoose->alternate == 0) 304 return -ENOENT; /* Not supported. */ 305 306 /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ 307 if (send_to_cam) 308 ret = send_video_command(pdev, 4, pChoose->mode, 12); 309 if (ret < 0) 310 return ret; 311 312 if (pChoose->bandlength > 0 && pixfmt == V4L2_PIX_FMT_YUV420) 313 pwc_dec23_init(pdev, pChoose->mode); 314 315 /* All set and go */ 316 pdev->pixfmt = pixfmt; 317 pdev->vframes = (fps + 1) * 5; 318 pdev->valternate = pChoose->alternate; 319 pdev->width = pwc_image_sizes[size][0]; 320 pdev->height = pwc_image_sizes[size][1]; 321 pdev->vbandlength = pChoose->bandlength; 322 if (pdev->vbandlength > 0) 323 pdev->frame_size = (pdev->vbandlength * pdev->height) / 4; 324 else 325 pdev->frame_size = (pdev->width * pdev->height * 12) / 8; 326 PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vbandlength=%d\n", 327 pdev->frame_size, pdev->vframes, size, pdev->vbandlength); 328 return 0; 329 } 330 331 int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, 332 int pixfmt, int frames, int *compression, int send_to_cam) 333 { 334 int ret, size; 335 336 PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", 337 width, height, frames, pixfmt); 338 size = pwc_get_size(pdev, width, height); 339 PWC_TRACE("decode_size = %d.\n", size); 340 341 if (DEVICE_USE_CODEC1(pdev->type)) { 342 ret = set_video_mode_Nala(pdev, size, pixfmt, frames, 343 compression, send_to_cam); 344 } else if (DEVICE_USE_CODEC3(pdev->type)) { 345 ret = set_video_mode_Kiara(pdev, size, pixfmt, frames, 346 compression, send_to_cam); 347 } else { 348 ret = set_video_mode_Timon(pdev, size, pixfmt, frames, 349 compression, send_to_cam); 350 } 351 if (ret < 0) { 352 PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); 353 return ret; 354 } 355 pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; 356 PWC_DEBUG_SIZE("Set resolution to %dx%d\n", pdev->width, pdev->height); 357 return 0; 358 } 359 360 static unsigned int pwc_get_fps_Nala(struct pwc_device *pdev, unsigned int index, unsigned int size) 361 { 362 unsigned int i; 363 364 for (i = 0; i < PWC_FPS_MAX_NALA; i++) { 365 if (Nala_table[size][i].alternate) { 366 if (index--==0) return Nala_fps_vector[i]; 367 } 368 } 369 return 0; 370 } 371 372 static unsigned int pwc_get_fps_Kiara(struct pwc_device *pdev, unsigned int index, unsigned int size) 373 { 374 unsigned int i; 375 376 for (i = 0; i < PWC_FPS_MAX_KIARA; i++) { 377 if (Kiara_table[size][i][3].alternate) { 378 if (index--==0) return Kiara_fps_vector[i]; 379 } 380 } 381 return 0; 382 } 383 384 static unsigned int pwc_get_fps_Timon(struct pwc_device *pdev, unsigned int index, unsigned int size) 385 { 386 unsigned int i; 387 388 for (i=0; i < PWC_FPS_MAX_TIMON; i++) { 389 if (Timon_table[size][i][3].alternate) { 390 if (index--==0) return Timon_fps_vector[i]; 391 } 392 } 393 return 0; 394 } 395 396 unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size) 397 { 398 unsigned int ret; 399 400 if (DEVICE_USE_CODEC1(pdev->type)) { 401 ret = pwc_get_fps_Nala(pdev, index, size); 402 403 } else if (DEVICE_USE_CODEC3(pdev->type)) { 404 ret = pwc_get_fps_Kiara(pdev, index, size); 405 406 } else { 407 ret = pwc_get_fps_Timon(pdev, index, size); 408 } 409 410 return ret; 411 } 412 413 int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) 414 { 415 int ret; 416 417 ret = recv_control_msg(pdev, request, value, 1); 418 if (ret < 0) 419 return ret; 420 421 *data = pdev->ctrl_buf[0]; 422 return 0; 423 } 424 425 int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data) 426 { 427 int ret; 428 429 pdev->ctrl_buf[0] = data; 430 ret = send_control_msg(pdev, request, value, pdev->ctrl_buf, 1); 431 if (ret < 0) 432 return ret; 433 434 return 0; 435 } 436 437 int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) 438 { 439 int ret; 440 441 ret = recv_control_msg(pdev, request, value, 1); 442 if (ret < 0) 443 return ret; 444 445 *data = ((s8 *)pdev->ctrl_buf)[0]; 446 return 0; 447 } 448 449 int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data) 450 { 451 int ret; 452 453 ret = recv_control_msg(pdev, request, value, 2); 454 if (ret < 0) 455 return ret; 456 457 *data = (pdev->ctrl_buf[1] << 8) | pdev->ctrl_buf[0]; 458 return 0; 459 } 460 461 int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data) 462 { 463 int ret; 464 465 pdev->ctrl_buf[0] = data & 0xff; 466 pdev->ctrl_buf[1] = data >> 8; 467 ret = send_control_msg(pdev, request, value, pdev->ctrl_buf, 2); 468 if (ret < 0) 469 return ret; 470 471 return 0; 472 } 473 474 int pwc_button_ctrl(struct pwc_device *pdev, u16 value) 475 { 476 int ret; 477 478 ret = send_control_msg(pdev, SET_STATUS_CTL, value, NULL, 0); 479 if (ret < 0) 480 return ret; 481 482 return 0; 483 } 484 485 /* POWER */ 486 void pwc_camera_power(struct pwc_device *pdev, int power) 487 { 488 int r; 489 490 if (!pdev->power_save) 491 return; 492 493 if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6)) 494 return; /* Not supported by Nala or Timon < release 6 */ 495 496 if (power) 497 pdev->ctrl_buf[0] = 0x00; /* active */ 498 else 499 pdev->ctrl_buf[0] = 0xFF; /* power save */ 500 r = send_control_msg(pdev, SET_STATUS_CTL, 501 SET_POWER_SAVE_MODE_FORMATTER, pdev->ctrl_buf, 1); 502 if (r < 0) 503 PWC_ERROR("Failed to power %s camera (%d)\n", 504 power ? "on" : "off", r); 505 } 506 507 int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) 508 { 509 int r; 510 511 if (pdev->type < 730) 512 return 0; 513 on_value /= 100; 514 off_value /= 100; 515 if (on_value < 0) 516 on_value = 0; 517 if (on_value > 0xff) 518 on_value = 0xff; 519 if (off_value < 0) 520 off_value = 0; 521 if (off_value > 0xff) 522 off_value = 0xff; 523 524 pdev->ctrl_buf[0] = on_value; 525 pdev->ctrl_buf[1] = off_value; 526 527 r = send_control_msg(pdev, 528 SET_STATUS_CTL, LED_FORMATTER, pdev->ctrl_buf, 2); 529 if (r < 0) 530 PWC_ERROR("Failed to set LED on/off time (%d)\n", r); 531 532 return r; 533 } 534 535 #ifdef CONFIG_USB_PWC_DEBUG 536 int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) 537 { 538 int ret = -1, request; 539 540 if (pdev->type < 675) 541 request = SENSOR_TYPE_FORMATTER1; 542 else if (pdev->type < 730) 543 return -1; /* The Vesta series doesn't have this call */ 544 else 545 request = SENSOR_TYPE_FORMATTER2; 546 547 ret = recv_control_msg(pdev, GET_STATUS_CTL, request, 1); 548 if (ret < 0) 549 return ret; 550 if (pdev->type < 675) 551 *sensor = pdev->ctrl_buf[0] | 0x100; 552 else 553 *sensor = pdev->ctrl_buf[0]; 554 return 0; 555 } 556 #endif 557