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 7 NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx 8 driver and thus may have bugs that are not present in the original version. 9 Please send bug reports and support requests to <luc@saillard.org>. 10 11 NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx 12 driver and thus may have bugs that are not present in the original version. 13 Please send bug reports and support requests to <luc@saillard.org>. 14 The decompression routines have been implemented by reverse-engineering the 15 Nemosoft binary pwcx module. Caveat emptor. 16 17 This program is free software; you can redistribute it and/or modify 18 it under the terms of the GNU General Public License as published by 19 the Free Software Foundation; either version 2 of the License, or 20 (at your option) any later version. 21 22 This program is distributed in the hope that it will be useful, 23 but WITHOUT ANY WARRANTY; without even the implied warranty of 24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 GNU General Public License for more details. 26 27 You should have received a copy of the GNU General Public License 28 along with this program; if not, write to the Free Software 29 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 30*/ 31 32/* 33 Changes 34 2001/08/03 Alvarado Added methods for changing white balance and 35 red/green gains 36 */ 37 38/* Control functions for the cam; brightness, contrast, video mode, etc. */ 39 40#ifdef __KERNEL__ 41#include <asm/uaccess.h> 42#endif 43#include <asm/errno.h> 44#include <linux/version.h> 45 46#include "pwc.h" 47#include "pwc-uncompress.h" 48#include "pwc-kiara.h" 49#include "pwc-timon.h" 50#include "pwc-dec1.h" 51#include "pwc-dec23.h" 52 53/* Request types: video */ 54#define SET_LUM_CTL 0x01 55#define GET_LUM_CTL 0x02 56#define SET_CHROM_CTL 0x03 57#define GET_CHROM_CTL 0x04 58#define SET_STATUS_CTL 0x05 59#define GET_STATUS_CTL 0x06 60#define SET_EP_STREAM_CTL 0x07 61#define GET_EP_STREAM_CTL 0x08 62#define GET_XX_CTL 0x09 63#define SET_XX_CTL 0x0A 64#define GET_XY_CTL 0x0B 65#define SET_XY_CTL 0x0C 66#define SET_MPT_CTL 0x0D 67#define GET_MPT_CTL 0x0E 68 69/* Selectors for the Luminance controls [GS]ET_LUM_CTL */ 70#define AGC_MODE_FORMATTER 0x2000 71#define PRESET_AGC_FORMATTER 0x2100 72#define SHUTTER_MODE_FORMATTER 0x2200 73#define PRESET_SHUTTER_FORMATTER 0x2300 74#define PRESET_CONTOUR_FORMATTER 0x2400 75#define AUTO_CONTOUR_FORMATTER 0x2500 76#define BACK_LIGHT_COMPENSATION_FORMATTER 0x2600 77#define CONTRAST_FORMATTER 0x2700 78#define DYNAMIC_NOISE_CONTROL_FORMATTER 0x2800 79#define FLICKERLESS_MODE_FORMATTER 0x2900 80#define AE_CONTROL_SPEED 0x2A00 81#define BRIGHTNESS_FORMATTER 0x2B00 82#define GAMMA_FORMATTER 0x2C00 83 84/* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */ 85#define WB_MODE_FORMATTER 0x1000 86#define AWB_CONTROL_SPEED_FORMATTER 0x1100 87#define AWB_CONTROL_DELAY_FORMATTER 0x1200 88#define PRESET_MANUAL_RED_GAIN_FORMATTER 0x1300 89#define PRESET_MANUAL_BLUE_GAIN_FORMATTER 0x1400 90#define COLOUR_MODE_FORMATTER 0x1500 91#define SATURATION_MODE_FORMATTER1 0x1600 92#define SATURATION_MODE_FORMATTER2 0x1700 93 94/* Selectors for the Status controls [GS]ET_STATUS_CTL */ 95#define SAVE_USER_DEFAULTS_FORMATTER 0x0200 96#define RESTORE_USER_DEFAULTS_FORMATTER 0x0300 97#define RESTORE_FACTORY_DEFAULTS_FORMATTER 0x0400 98#define READ_AGC_FORMATTER 0x0500 99#define READ_SHUTTER_FORMATTER 0x0600 100#define READ_RED_GAIN_FORMATTER 0x0700 101#define READ_BLUE_GAIN_FORMATTER 0x0800 102#define GET_STATUS_B00 0x0B00 103#define SENSOR_TYPE_FORMATTER1 0x0C00 104#define GET_STATUS_3000 0x3000 105#define READ_RAW_Y_MEAN_FORMATTER 0x3100 106#define SET_POWER_SAVE_MODE_FORMATTER 0x3200 107#define MIRROR_IMAGE_FORMATTER 0x3300 108#define LED_FORMATTER 0x3400 109#define LOWLIGHT 0x3500 110#define GET_STATUS_3600 0x3600 111#define SENSOR_TYPE_FORMATTER2 0x3700 112#define GET_STATUS_3800 0x3800 113#define GET_STATUS_4000 0x4000 114#define GET_STATUS_4100 0x4100 /* Get */ 115#define CTL_STATUS_4200 0x4200 /* [GS] 1 */ 116 117/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */ 118#define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100 119 120/* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */ 121#define PT_RELATIVE_CONTROL_FORMATTER 0x01 122#define PT_RESET_CONTROL_FORMATTER 0x02 123#define PT_STATUS_FORMATTER 0x03 124 125static const char *size2name[PSZ_MAX] = 126{ 127 "subQCIF", 128 "QSIF", 129 "QCIF", 130 "SIF", 131 "CIF", 132 "VGA", 133}; 134 135/********/ 136 137/* Entries for the Nala (645/646) camera; the Nala doesn't have compression 138 preferences, so you either get compressed or non-compressed streams. 139 140 An alternate value of 0 means this mode is not available at all. 141 */ 142 143#define PWC_FPS_MAX_NALA 8 144 145struct Nala_table_entry { 146 char alternate; /* USB alternate setting */ 147 int compressed; /* Compressed yes/no */ 148 149 unsigned char mode[3]; /* precomputed mode table */ 150}; 151 152static unsigned int Nala_fps_vector[PWC_FPS_MAX_NALA] = { 4, 5, 7, 10, 12, 15, 20, 24 }; 153 154static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] = 155{ 156#include "pwc-nala.h" 157}; 158 159static void pwc_set_image_buffer_size(struct pwc_device *pdev); 160 161/****************************************************************************/ 162 163 164#define SendControlMsg(request, value, buflen) \ 165 usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \ 166 request, \ 167 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ 168 value, \ 169 pdev->vcinterface, \ 170 &buf, buflen, 500) 171 172#define RecvControlMsg(request, value, buflen) \ 173 usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \ 174 request, \ 175 USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ 176 value, \ 177 pdev->vcinterface, \ 178 &buf, buflen, 500) 179 180 181static int send_video_command(struct usb_device *udev, int index, void *buf, int buflen) 182{ 183 return usb_control_msg(udev, 184 usb_sndctrlpipe(udev, 0), 185 SET_EP_STREAM_CTL, 186 USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, 187 VIDEO_OUTPUT_CONTROL_FORMATTER, 188 index, 189 buf, buflen, 1000); 190} 191 192 193 194static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) 195{ 196 unsigned char buf[3]; 197 int ret, fps; 198 struct Nala_table_entry *pEntry; 199 int frames2frames[31] = 200 { /* closest match of framerate */ 201 0, 0, 0, 0, 4, /* 0-4 */ 202 5, 5, 7, 7, 10, /* 5-9 */ 203 10, 10, 12, 12, 15, /* 10-14 */ 204 15, 15, 15, 20, 20, /* 15-19 */ 205 20, 20, 20, 24, 24, /* 20-24 */ 206 24, 24, 24, 24, 24, /* 25-29 */ 207 24 /* 30 */ 208 }; 209 int frames2table[31] = 210 { 0, 0, 0, 0, 0, /* 0-4 */ 211 1, 1, 1, 2, 2, /* 5-9 */ 212 3, 3, 4, 4, 4, /* 10-14 */ 213 5, 5, 5, 5, 5, /* 15-19 */ 214 6, 6, 6, 6, 7, /* 20-24 */ 215 7, 7, 7, 7, 7, /* 25-29 */ 216 7 /* 30 */ 217 }; 218 219 if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25) 220 return -EINVAL; 221 frames = frames2frames[frames]; 222 fps = frames2table[frames]; 223 pEntry = &Nala_table[size][fps]; 224 if (pEntry->alternate == 0) 225 return -EINVAL; 226 227 memcpy(buf, pEntry->mode, 3); 228 ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3); 229 if (ret < 0) { 230 PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret); 231 return ret; 232 } 233 if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW) 234 pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); 235 236 pdev->cmd_len = 3; 237 memcpy(pdev->cmd_buf, buf, 3); 238 239 /* Set various parameters */ 240 pdev->vframes = frames; 241 pdev->vsize = size; 242 pdev->valternate = pEntry->alternate; 243 pdev->image = pwc_image_sizes[size]; 244 pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2; 245 if (pEntry->compressed) { 246 if (pdev->release < 5) { /* 4 fold compression */ 247 pdev->vbandlength = 528; 248 pdev->frame_size /= 4; 249 } 250 else { 251 pdev->vbandlength = 704; 252 pdev->frame_size /= 3; 253 } 254 } 255 else 256 pdev->vbandlength = 0; 257 return 0; 258} 259 260 261static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) 262{ 263 unsigned char buf[13]; 264 const struct Timon_table_entry *pChoose; 265 int ret, fps; 266 267 if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) 268 return -EINVAL; 269 if (size == PSZ_VGA && frames > 15) 270 return -EINVAL; 271 fps = (frames / 5) - 1; 272 273 /* Find a supported framerate with progressively higher compression ratios 274 if the preferred ratio is not available. 275 */ 276 pChoose = NULL; 277 while (compression <= 3) { 278 pChoose = &Timon_table[size][fps][compression]; 279 if (pChoose->alternate != 0) 280 break; 281 compression++; 282 } 283 if (pChoose == NULL || pChoose->alternate == 0) 284 return -ENOENT; /* Not supported. */ 285 286 memcpy(buf, pChoose->mode, 13); 287 if (snapshot) 288 buf[0] |= 0x80; 289 ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 13); 290 if (ret < 0) 291 return ret; 292 293 if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW) 294 pwc_dec23_init(pdev, pdev->type, buf); 295 296 pdev->cmd_len = 13; 297 memcpy(pdev->cmd_buf, buf, 13); 298 299 /* Set various parameters */ 300 pdev->vframes = frames; 301 pdev->vsize = size; 302 pdev->vsnapshot = snapshot; 303 pdev->valternate = pChoose->alternate; 304 pdev->image = pwc_image_sizes[size]; 305 pdev->vbandlength = pChoose->bandlength; 306 if (pChoose->bandlength > 0) 307 pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4; 308 else 309 pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; 310 return 0; 311} 312 313 314static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) 315{ 316 const struct Kiara_table_entry *pChoose = NULL; 317 int fps, ret; 318 unsigned char buf[12]; 319 struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}; 320 321 if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) 322 return -EINVAL; 323 if (size == PSZ_VGA && frames > 15) 324 return -EINVAL; 325 fps = (frames / 5) - 1; 326 327 /* special case: VGA @ 5 fps and snapshot is raw bayer mode */ 328 if (size == PSZ_VGA && frames == 5 && snapshot && pdev->vpalette == VIDEO_PALETTE_RAW) 329 { 330 /* Only available in case the raw palette is selected or 331 we have the decompressor available. This mode is 332 only available in compressed form 333 */ 334 PWC_DEBUG_SIZE("Choosing VGA/5 BAYER mode.\n"); 335 pChoose = &RawEntry; 336 } 337 else 338 { 339 /* Find a supported framerate with progressively higher compression ratios 340 if the preferred ratio is not available. 341 Skip this step when using RAW modes. 342 */ 343 snapshot = 0; 344 while (compression <= 3) { 345 pChoose = &Kiara_table[size][fps][compression]; 346 if (pChoose->alternate != 0) 347 break; 348 compression++; 349 } 350 } 351 if (pChoose == NULL || pChoose->alternate == 0) 352 return -ENOENT; /* Not supported. */ 353 354 PWC_TRACE("Using alternate setting %d.\n", pChoose->alternate); 355 356 /* usb_control_msg won't take staticly allocated arrays as argument?? */ 357 memcpy(buf, pChoose->mode, 12); 358 if (snapshot) 359 buf[0] |= 0x80; 360 361 /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ 362 ret = send_video_command(pdev->udev, 4 /* pdev->vendpoint */, buf, 12); 363 if (ret < 0) 364 return ret; 365 366 if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW) 367 pwc_dec23_init(pdev, pdev->type, buf); 368 369 pdev->cmd_len = 12; 370 memcpy(pdev->cmd_buf, buf, 12); 371 /* All set and go */ 372 pdev->vframes = frames; 373 pdev->vsize = size; 374 pdev->vsnapshot = snapshot; 375 pdev->valternate = pChoose->alternate; 376 pdev->image = pwc_image_sizes[size]; 377 pdev->vbandlength = pChoose->bandlength; 378 if (pdev->vbandlength > 0) 379 pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4; 380 else 381 pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; 382 PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vsnapshot=%d, vbandlength=%d\n", 383 pdev->frame_size,pdev->vframes,pdev->vsize,pdev->vsnapshot,pdev->vbandlength); 384 return 0; 385} 386 387 388 389/** 390 @pdev: device structure 391 @width: viewport width 392 @height: viewport height 393 @frame: framerate, in fps 394 @compression: preferred compression ratio 395 @snapshot: snapshot mode or streaming 396 */ 397int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot) 398{ 399 int ret, size; 400 401 PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette); 402 size = pwc_decode_size(pdev, width, height); 403 if (size < 0) { 404 PWC_DEBUG_MODULE("Could not find suitable size.\n"); 405 return -ERANGE; 406 } 407 PWC_TRACE("decode_size = %d.\n", size); 408 409 if (DEVICE_USE_CODEC1(pdev->type)) { 410 ret = set_video_mode_Nala(pdev, size, frames); 411 412 } else if (DEVICE_USE_CODEC3(pdev->type)) { 413 ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot); 414 415 } else { 416 ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot); 417 } 418 if (ret < 0) { 419 PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); 420 return ret; 421 } 422 pdev->view.x = width; 423 pdev->view.y = height; 424 pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; 425 pwc_set_image_buffer_size(pdev); 426 PWC_DEBUG_SIZE("Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y); 427 return 0; 428} 429 430static unsigned int pwc_get_fps_Nala(struct pwc_device *pdev, unsigned int index, unsigned int size) 431{ 432 unsigned int i; 433 434 for (i = 0; i < PWC_FPS_MAX_NALA; i++) { 435 if (Nala_table[size][i].alternate) { 436 if (index--==0) return Nala_fps_vector[i]; 437 } 438 } 439 return 0; 440} 441 442static unsigned int pwc_get_fps_Kiara(struct pwc_device *pdev, unsigned int index, unsigned int size) 443{ 444 unsigned int i; 445 446 for (i = 0; i < PWC_FPS_MAX_KIARA; i++) { 447 if (Kiara_table[size][i][3].alternate) { 448 if (index--==0) return Kiara_fps_vector[i]; 449 } 450 } 451 return 0; 452} 453 454static unsigned int pwc_get_fps_Timon(struct pwc_device *pdev, unsigned int index, unsigned int size) 455{ 456 unsigned int i; 457 458 for (i=0; i < PWC_FPS_MAX_TIMON; i++) { 459 if (Timon_table[size][i][3].alternate) { 460 if (index--==0) return Timon_fps_vector[i]; 461 } 462 } 463 return 0; 464} 465 466unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size) 467{ 468 unsigned int ret; 469 470 if (DEVICE_USE_CODEC1(pdev->type)) { 471 ret = pwc_get_fps_Nala(pdev, index, size); 472 473 } else if (DEVICE_USE_CODEC3(pdev->type)) { 474 ret = pwc_get_fps_Kiara(pdev, index, size); 475 476 } else { 477 ret = pwc_get_fps_Timon(pdev, index, size); 478 } 479 480 return ret; 481} 482 483#define BLACK_Y 0 484#define BLACK_U 128 485#define BLACK_V 128 486 487static void pwc_set_image_buffer_size(struct pwc_device *pdev) 488{ 489 int i, factor = 0; 490 491 /* for PALETTE_YUV420P */ 492 switch(pdev->vpalette) 493 { 494 case VIDEO_PALETTE_YUV420P: 495 factor = 6; 496 break; 497 case VIDEO_PALETTE_RAW: 498 factor = 6; /* can be uncompressed YUV420P */ 499 break; 500 } 501 502 /* Set sizes in bytes */ 503 pdev->image.size = pdev->image.x * pdev->image.y * factor / 4; 504 pdev->view.size = pdev->view.x * pdev->view.y * factor / 4; 505 506 /* Align offset, or you'll get some very weird results in 507 YUV420 mode... x must be multiple of 4 (to get the Y's in 508 place), and y even (or you'll mixup U & V). This is less of a 509 problem for YUV420P. 510 */ 511 pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC; 512 pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; 513 514 /* Fill buffers with black colors */ 515 for (i = 0; i < pwc_mbufs; i++) { 516 unsigned char *p = pdev->image_data + pdev->images[i].offset; 517 memset(p, BLACK_Y, pdev->view.x * pdev->view.y); 518 p += pdev->view.x * pdev->view.y; 519 memset(p, BLACK_U, pdev->view.x * pdev->view.y/4); 520 p += pdev->view.x * pdev->view.y/4; 521 memset(p, BLACK_V, pdev->view.x * pdev->view.y/4); 522 } 523} 524 525 526 527/* BRIGHTNESS */ 528 529int pwc_get_brightness(struct pwc_device *pdev) 530{ 531 char buf; 532 int ret; 533 534 ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1); 535 if (ret < 0) 536 return ret; 537 return buf; 538} 539 540int pwc_set_brightness(struct pwc_device *pdev, int value) 541{ 542 char buf; 543 544 if (value < 0) 545 value = 0; 546 if (value > 0xffff) 547 value = 0xffff; 548 buf = (value >> 9) & 0x7f; 549 return SendControlMsg(SET_LUM_CTL, BRIGHTNESS_FORMATTER, 1); 550} 551 552/* CONTRAST */ 553 554int pwc_get_contrast(struct pwc_device *pdev) 555{ 556 char buf; 557 int ret; 558 559 ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1); 560 if (ret < 0) 561 return ret; 562 return buf; 563} 564 565int pwc_set_contrast(struct pwc_device *pdev, int value) 566{ 567 char buf; 568 569 if (value < 0) 570 value = 0; 571 if (value > 0xffff) 572 value = 0xffff; 573 buf = (value >> 10) & 0x3f; 574 return SendControlMsg(SET_LUM_CTL, CONTRAST_FORMATTER, 1); 575} 576 577/* GAMMA */ 578 579int pwc_get_gamma(struct pwc_device *pdev) 580{ 581 char buf; 582 int ret; 583 584 ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1); 585 if (ret < 0) 586 return ret; 587 return buf; 588} 589 590int pwc_set_gamma(struct pwc_device *pdev, int value) 591{ 592 char buf; 593 594 if (value < 0) 595 value = 0; 596 if (value > 0xffff) 597 value = 0xffff; 598 buf = (value >> 11) & 0x1f; 599 return SendControlMsg(SET_LUM_CTL, GAMMA_FORMATTER, 1); 600} 601 602 603/* SATURATION */ 604 605/* return a value between [-100 , 100] */ 606int pwc_get_saturation(struct pwc_device *pdev, int *value) 607{ 608 char buf; 609 int ret, saturation_register; 610 611 if (pdev->type < 675) 612 return -EINVAL; 613 if (pdev->type < 730) 614 saturation_register = SATURATION_MODE_FORMATTER2; 615 else 616 saturation_register = SATURATION_MODE_FORMATTER1; 617 ret = RecvControlMsg(GET_CHROM_CTL, saturation_register, 1); 618 if (ret < 0) 619 return ret; 620 *value = (signed)buf; 621 return 0; 622} 623 624/* @param value saturation color between [-100 , 100] */ 625int pwc_set_saturation(struct pwc_device *pdev, int value) 626{ 627 char buf; 628 int saturation_register; 629 630 if (pdev->type < 675) 631 return -EINVAL; 632 if (value < -100) 633 value = -100; 634 if (value > 100) 635 value = 100; 636 if (pdev->type < 730) 637 saturation_register = SATURATION_MODE_FORMATTER2; 638 else 639 saturation_register = SATURATION_MODE_FORMATTER1; 640 return SendControlMsg(SET_CHROM_CTL, saturation_register, 1); 641} 642 643/* AGC */ 644 645int pwc_set_agc(struct pwc_device *pdev, int mode, int value) 646{ 647 char buf; 648 int ret; 649 650 if (mode) 651 buf = 0x0; /* auto */ 652 else 653 buf = 0xff; /* fixed */ 654 655 ret = SendControlMsg(SET_LUM_CTL, AGC_MODE_FORMATTER, 1); 656 657 if (!mode && ret >= 0) { 658 if (value < 0) 659 value = 0; 660 if (value > 0xffff) 661 value = 0xffff; 662 buf = (value >> 10) & 0x3F; 663 ret = SendControlMsg(SET_LUM_CTL, PRESET_AGC_FORMATTER, 1); 664 } 665 if (ret < 0) 666 return ret; 667 return 0; 668} 669 670int pwc_get_agc(struct pwc_device *pdev, int *value) 671{ 672 unsigned char buf; 673 int ret; 674 675 ret = RecvControlMsg(GET_LUM_CTL, AGC_MODE_FORMATTER, 1); 676 if (ret < 0) 677 return ret; 678 679 if (buf != 0) { /* fixed */ 680 ret = RecvControlMsg(GET_LUM_CTL, PRESET_AGC_FORMATTER, 1); 681 if (ret < 0) 682 return ret; 683 if (buf > 0x3F) 684 buf = 0x3F; 685 *value = (buf << 10); 686 } 687 else { /* auto */ 688 ret = RecvControlMsg(GET_STATUS_CTL, READ_AGC_FORMATTER, 1); 689 if (ret < 0) 690 return ret; 691 /* Gah... this value ranges from 0x00 ... 0x9F */ 692 if (buf > 0x9F) 693 buf = 0x9F; 694 *value = -(48 + buf * 409); 695 } 696 697 return 0; 698} 699 700int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value) 701{ 702 char buf[2]; 703 int speed, ret; 704 705 706 if (mode) 707 buf[0] = 0x0; /* auto */ 708 else 709 buf[0] = 0xff; /* fixed */ 710 711 ret = SendControlMsg(SET_LUM_CTL, SHUTTER_MODE_FORMATTER, 1); 712 713 if (!mode && ret >= 0) { 714 if (value < 0) 715 value = 0; 716 if (value > 0xffff) 717 value = 0xffff; 718 719 if (DEVICE_USE_CODEC2(pdev->type)) { 720 /* speed ranges from 0x0 to 0x290 (656) */ 721 speed = (value / 100); 722 buf[1] = speed >> 8; 723 buf[0] = speed & 0xff; 724 } else if (DEVICE_USE_CODEC3(pdev->type)) { 725 /* speed seems to range from 0x0 to 0xff */ 726 buf[1] = 0; 727 buf[0] = value >> 8; 728 } 729 730 ret = SendControlMsg(SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, 2); 731 } 732 return ret; 733} 734 735/* This function is not exported to v4l1, so output values between 0 -> 256 */ 736int pwc_get_shutter_speed(struct pwc_device *pdev, int *value) 737{ 738 unsigned char buf[2]; 739 int ret; 740 741 ret = RecvControlMsg(GET_STATUS_CTL, READ_SHUTTER_FORMATTER, 2); 742 if (ret < 0) 743 return ret; 744 *value = buf[0] + (buf[1] << 8); 745 if (DEVICE_USE_CODEC2(pdev->type)) { 746 /* speed ranges from 0x0 to 0x290 (656) */ 747 *value *= 256/656; 748 } else if (DEVICE_USE_CODEC3(pdev->type)) { 749 /* speed seems to range from 0x0 to 0xff */ 750 } 751 return 0; 752} 753 754 755/* POWER */ 756 757int pwc_camera_power(struct pwc_device *pdev, int power) 758{ 759 char buf; 760 761 if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6)) 762 return 0; /* Not supported by Nala or Timon < release 6 */ 763 764 if (power) 765 buf = 0x00; /* active */ 766 else 767 buf = 0xFF; /* power save */ 768 return SendControlMsg(SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER, 1); 769} 770 771 772 773/* private calls */ 774 775int pwc_restore_user(struct pwc_device *pdev) 776{ 777 char buf; /* dummy */ 778 return SendControlMsg(SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, 0); 779} 780 781int pwc_save_user(struct pwc_device *pdev) 782{ 783 char buf; /* dummy */ 784 return SendControlMsg(SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, 0); 785} 786 787int pwc_restore_factory(struct pwc_device *pdev) 788{ 789 char buf; /* dummy */ 790 return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0); 791} 792 793 /* ************************************************* */ 794 /* Patch by Alvarado: (not in the original version */ 795 796 /* 797 * the camera recognizes modes from 0 to 4: 798 * 799 * 00: indoor (incandescant lighting) 800 * 01: outdoor (sunlight) 801 * 02: fluorescent lighting 802 * 03: manual 803 * 04: auto 804 */ 805int pwc_set_awb(struct pwc_device *pdev, int mode) 806{ 807 char buf; 808 int ret; 809 810 if (mode < 0) 811 mode = 0; 812 813 if (mode > 4) 814 mode = 4; 815 816 buf = mode & 0x07; /* just the lowest three bits */ 817 818 ret = SendControlMsg(SET_CHROM_CTL, WB_MODE_FORMATTER, 1); 819 820 if (ret < 0) 821 return ret; 822 return 0; 823} 824 825int pwc_get_awb(struct pwc_device *pdev) 826{ 827 unsigned char buf; 828 int ret; 829 830 ret = RecvControlMsg(GET_CHROM_CTL, WB_MODE_FORMATTER, 1); 831 832 if (ret < 0) 833 return ret; 834 return buf; 835} 836 837int pwc_set_red_gain(struct pwc_device *pdev, int value) 838{ 839 unsigned char buf; 840 841 if (value < 0) 842 value = 0; 843 if (value > 0xffff) 844 value = 0xffff; 845 /* only the msb is considered */ 846 buf = value >> 8; 847 return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1); 848} 849 850int pwc_get_red_gain(struct pwc_device *pdev, int *value) 851{ 852 unsigned char buf; 853 int ret; 854 855 ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1); 856 if (ret < 0) 857 return ret; 858 *value = buf << 8; 859 return 0; 860} 861 862 863int pwc_set_blue_gain(struct pwc_device *pdev, int value) 864{ 865 unsigned char buf; 866 867 if (value < 0) 868 value = 0; 869 if (value > 0xffff) 870 value = 0xffff; 871 /* only the msb is considered */ 872 buf = value >> 8; 873 return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1); 874} 875 876int pwc_get_blue_gain(struct pwc_device *pdev, int *value) 877{ 878 unsigned char buf; 879 int ret; 880 881 ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1); 882 if (ret < 0) 883 return ret; 884 *value = buf << 8; 885 return 0; 886} 887 888 889/* The following two functions are different, since they only read the 890 internal red/blue gains, which may be different from the manual 891 gains set or read above. 892 */ 893static int pwc_read_red_gain(struct pwc_device *pdev, int *value) 894{ 895 unsigned char buf; 896 int ret; 897 898 ret = RecvControlMsg(GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, 1); 899 if (ret < 0) 900 return ret; 901 *value = buf << 8; 902 return 0; 903} 904 905static int pwc_read_blue_gain(struct pwc_device *pdev, int *value) 906{ 907 unsigned char buf; 908 int ret; 909 910 ret = RecvControlMsg(GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, 1); 911 if (ret < 0) 912 return ret; 913 *value = buf << 8; 914 return 0; 915} 916 917 918static int pwc_set_wb_speed(struct pwc_device *pdev, int speed) 919{ 920 unsigned char buf; 921 922 /* useful range is 0x01..0x20 */ 923 buf = speed / 0x7f0; 924 return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1); 925} 926 927static int pwc_get_wb_speed(struct pwc_device *pdev, int *value) 928{ 929 unsigned char buf; 930 int ret; 931 932 ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1); 933 if (ret < 0) 934 return ret; 935 *value = buf * 0x7f0; 936 return 0; 937} 938 939 940static int pwc_set_wb_delay(struct pwc_device *pdev, int delay) 941{ 942 unsigned char buf; 943 944 /* useful range is 0x01..0x3F */ 945 buf = (delay >> 10); 946 return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1); 947} 948 949static int pwc_get_wb_delay(struct pwc_device *pdev, int *value) 950{ 951 unsigned char buf; 952 int ret; 953 954 ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1); 955 if (ret < 0) 956 return ret; 957 *value = buf << 10; 958 return 0; 959} 960 961 962int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) 963{ 964 unsigned char buf[2]; 965 966 if (pdev->type < 730) 967 return 0; 968 on_value /= 100; 969 off_value /= 100; 970 if (on_value < 0) 971 on_value = 0; 972 if (on_value > 0xff) 973 on_value = 0xff; 974 if (off_value < 0) 975 off_value = 0; 976 if (off_value > 0xff) 977 off_value = 0xff; 978 979 buf[0] = on_value; 980 buf[1] = off_value; 981 982 return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2); 983} 984 985static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) 986{ 987 unsigned char buf[2]; 988 int ret; 989 990 if (pdev->type < 730) { 991 *on_value = -1; 992 *off_value = -1; 993 return 0; 994 } 995 996 ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2); 997 if (ret < 0) 998 return ret; 999 *on_value = buf[0] * 100; 1000 *off_value = buf[1] * 100; 1001 return 0; 1002} 1003 1004int pwc_set_contour(struct pwc_device *pdev, int contour) 1005{ 1006 unsigned char buf; 1007 int ret; 1008 1009 if (contour < 0) 1010 buf = 0xff; /* auto contour on */ 1011 else 1012 buf = 0x0; /* auto contour off */ 1013 ret = SendControlMsg(SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1); 1014 if (ret < 0) 1015 return ret; 1016 1017 if (contour < 0) 1018 return 0; 1019 if (contour > 0xffff) 1020 contour = 0xffff; 1021 1022 buf = (contour >> 10); /* contour preset is [0..3f] */ 1023 ret = SendControlMsg(SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1); 1024 if (ret < 0) 1025 return ret; 1026 return 0; 1027} 1028 1029int pwc_get_contour(struct pwc_device *pdev, int *contour) 1030{ 1031 unsigned char buf; 1032 int ret; 1033 1034 ret = RecvControlMsg(GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1); 1035 if (ret < 0) 1036 return ret; 1037 1038 if (buf == 0) { 1039 /* auto mode off, query current preset value */ 1040 ret = RecvControlMsg(GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1); 1041 if (ret < 0) 1042 return ret; 1043 *contour = buf << 10; 1044 } 1045 else 1046 *contour = -1; 1047 return 0; 1048} 1049 1050 1051int pwc_set_backlight(struct pwc_device *pdev, int backlight) 1052{ 1053 unsigned char buf; 1054 1055 if (backlight) 1056 buf = 0xff; 1057 else 1058 buf = 0x0; 1059 return SendControlMsg(SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1); 1060} 1061 1062int pwc_get_backlight(struct pwc_device *pdev, int *backlight) 1063{ 1064 int ret; 1065 unsigned char buf; 1066 1067 ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1); 1068 if (ret < 0) 1069 return ret; 1070 *backlight = !!buf; 1071 return 0; 1072} 1073 1074int pwc_set_colour_mode(struct pwc_device *pdev, int colour) 1075{ 1076 unsigned char buf; 1077 1078 if (colour) 1079 buf = 0xff; 1080 else 1081 buf = 0x0; 1082 return SendControlMsg(SET_CHROM_CTL, COLOUR_MODE_FORMATTER, 1); 1083} 1084 1085int pwc_get_colour_mode(struct pwc_device *pdev, int *colour) 1086{ 1087 int ret; 1088 unsigned char buf; 1089 1090 ret = RecvControlMsg(GET_CHROM_CTL, COLOUR_MODE_FORMATTER, 1); 1091 if (ret < 0) 1092 return ret; 1093 *colour = !!buf; 1094 return 0; 1095} 1096 1097 1098int pwc_set_flicker(struct pwc_device *pdev, int flicker) 1099{ 1100 unsigned char buf; 1101 1102 if (flicker) 1103 buf = 0xff; 1104 else 1105 buf = 0x0; 1106 return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); 1107} 1108 1109int pwc_get_flicker(struct pwc_device *pdev, int *flicker) 1110{ 1111 int ret; 1112 unsigned char buf; 1113 1114 ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); 1115 if (ret < 0) 1116 return ret; 1117 *flicker = !!buf; 1118 return 0; 1119} 1120 1121int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise) 1122{ 1123 unsigned char buf; 1124 1125 if (noise < 0) 1126 noise = 0; 1127 if (noise > 3) 1128 noise = 3; 1129 buf = noise; 1130 return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); 1131} 1132 1133int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise) 1134{ 1135 int ret; 1136 unsigned char buf; 1137 1138 ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); 1139 if (ret < 0) 1140 return ret; 1141 *noise = buf; 1142 return 0; 1143} 1144 1145static int _pwc_mpt_reset(struct pwc_device *pdev, int flags) 1146{ 1147 unsigned char buf; 1148 1149 buf = flags & 0x03; // only lower two bits are currently used 1150 return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1); 1151} 1152 1153int pwc_mpt_reset(struct pwc_device *pdev, int flags) 1154{ 1155 int ret; 1156 ret = _pwc_mpt_reset(pdev, flags); 1157 if (ret >= 0) { 1158 pdev->pan_angle = 0; 1159 pdev->tilt_angle = 0; 1160 } 1161 return ret; 1162} 1163 1164static int _pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt) 1165{ 1166 unsigned char buf[4]; 1167 1168 /* set new relative angle; angles are expressed in degrees * 100, 1169 but cam as .5 degree resolution, hence divide by 200. Also 1170 the angle must be multiplied by 64 before it's send to 1171 the cam (??) 1172 */ 1173 pan = 64 * pan / 100; 1174 tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */ 1175 buf[0] = pan & 0xFF; 1176 buf[1] = (pan >> 8) & 0xFF; 1177 buf[2] = tilt & 0xFF; 1178 buf[3] = (tilt >> 8) & 0xFF; 1179 return SendControlMsg(SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, 4); 1180} 1181 1182int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt) 1183{ 1184 int ret; 1185 1186 /* check absolute ranges */ 1187 if (pan < pdev->angle_range.pan_min || 1188 pan > pdev->angle_range.pan_max || 1189 tilt < pdev->angle_range.tilt_min || 1190 tilt > pdev->angle_range.tilt_max) 1191 return -ERANGE; 1192 1193 /* go to relative range, check again */ 1194 pan -= pdev->pan_angle; 1195 tilt -= pdev->tilt_angle; 1196 /* angles are specified in degrees * 100, thus the limit = 36000 */ 1197 if (pan < -36000 || pan > 36000 || tilt < -36000 || tilt > 36000) 1198 return -ERANGE; 1199 1200 ret = _pwc_mpt_set_angle(pdev, pan, tilt); 1201 if (ret >= 0) { 1202 pdev->pan_angle += pan; 1203 pdev->tilt_angle += tilt; 1204 } 1205 if (ret == -EPIPE) /* stall -> out of range */ 1206 ret = -ERANGE; 1207 return ret; 1208} 1209 1210static int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status) 1211{ 1212 int ret; 1213 unsigned char buf[5]; 1214 1215 ret = RecvControlMsg(GET_MPT_CTL, PT_STATUS_FORMATTER, 5); 1216 if (ret < 0) 1217 return ret; 1218 status->status = buf[0] & 0x7; // 3 bits are used for reporting 1219 status->time_pan = (buf[1] << 8) + buf[2]; 1220 status->time_tilt = (buf[3] << 8) + buf[4]; 1221 return 0; 1222} 1223 1224 1225int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) 1226{ 1227 unsigned char buf; 1228 int ret = -1, request; 1229 1230 if (pdev->type < 675) 1231 request = SENSOR_TYPE_FORMATTER1; 1232 else if (pdev->type < 730) 1233 return -1; /* The Vesta series doesn't have this call */ 1234 else 1235 request = SENSOR_TYPE_FORMATTER2; 1236 1237 ret = RecvControlMsg(GET_STATUS_CTL, request, 1); 1238 if (ret < 0) 1239 return ret; 1240 if (pdev->type < 675) 1241 *sensor = buf | 0x100; 1242 else 1243 *sensor = buf; 1244 return 0; 1245} 1246 1247 1248 /* End of Add-Ons */ 1249 /* ************************************************* */ 1250 1251/* Linux 2.5.something and 2.6 pass direct pointers to arguments of 1252 ioctl() calls. With 2.4, you have to do tedious copy_from_user() 1253 and copy_to_user() calls. With these macros we circumvent this, 1254 and let me maintain only one source file. The functionality is 1255 exactly the same otherwise. 1256 */ 1257 1258 1259/* define local variable for arg */ 1260#define ARG_DEF(ARG_type, ARG_name)\ 1261 ARG_type *ARG_name = arg; 1262/* copy arg to local variable */ 1263#define ARG_IN(ARG_name) /* nothing */ 1264/* argument itself (referenced) */ 1265#define ARGR(ARG_name) (*ARG_name) 1266/* argument address */ 1267#define ARGA(ARG_name) ARG_name 1268/* copy local variable to arg */ 1269#define ARG_OUT(ARG_name) /* nothing */ 1270 1271 1272int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) 1273{ 1274 int ret = 0; 1275 1276 switch(cmd) { 1277 case VIDIOCPWCRUSER: 1278 { 1279 if (pwc_restore_user(pdev)) 1280 ret = -EINVAL; 1281 break; 1282 } 1283 1284 case VIDIOCPWCSUSER: 1285 { 1286 if (pwc_save_user(pdev)) 1287 ret = -EINVAL; 1288 break; 1289 } 1290 1291 case VIDIOCPWCFACTORY: 1292 { 1293 if (pwc_restore_factory(pdev)) 1294 ret = -EINVAL; 1295 break; 1296 } 1297 1298 case VIDIOCPWCSCQUAL: 1299 { 1300 ARG_DEF(int, qual) 1301 1302 ARG_IN(qual) 1303 if (ARGR(qual) < 0 || ARGR(qual) > 3) 1304 ret = -EINVAL; 1305 else 1306 ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot); 1307 if (ret >= 0) 1308 pdev->vcompression = ARGR(qual); 1309 break; 1310 } 1311 1312 case VIDIOCPWCGCQUAL: 1313 { 1314 ARG_DEF(int, qual) 1315 1316 ARGR(qual) = pdev->vcompression; 1317 ARG_OUT(qual) 1318 break; 1319 } 1320 1321 case VIDIOCPWCPROBE: 1322 { 1323 ARG_DEF(struct pwc_probe, probe) 1324 1325 strcpy(ARGR(probe).name, pdev->vdev->name); 1326 ARGR(probe).type = pdev->type; 1327 ARG_OUT(probe) 1328 break; 1329 } 1330 1331 case VIDIOCPWCGSERIAL: 1332 { 1333 ARG_DEF(struct pwc_serial, serial) 1334 1335 strcpy(ARGR(serial).serial, pdev->serial); 1336 ARG_OUT(serial) 1337 break; 1338 } 1339 1340 case VIDIOCPWCSAGC: 1341 { 1342 ARG_DEF(int, agc) 1343 1344 ARG_IN(agc) 1345 if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc))) 1346 ret = -EINVAL; 1347 break; 1348 } 1349 1350 case VIDIOCPWCGAGC: 1351 { 1352 ARG_DEF(int, agc) 1353 1354 if (pwc_get_agc(pdev, ARGA(agc))) 1355 ret = -EINVAL; 1356 ARG_OUT(agc) 1357 break; 1358 } 1359 1360 case VIDIOCPWCSSHUTTER: 1361 { 1362 ARG_DEF(int, shutter_speed) 1363 1364 ARG_IN(shutter_speed) 1365 ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed)); 1366 break; 1367 } 1368 1369 case VIDIOCPWCSAWB: 1370 { 1371 ARG_DEF(struct pwc_whitebalance, wb) 1372 1373 ARG_IN(wb) 1374 ret = pwc_set_awb(pdev, ARGR(wb).mode); 1375 if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) { 1376 pwc_set_red_gain(pdev, ARGR(wb).manual_red); 1377 pwc_set_blue_gain(pdev, ARGR(wb).manual_blue); 1378 } 1379 break; 1380 } 1381 1382 case VIDIOCPWCGAWB: 1383 { 1384 ARG_DEF(struct pwc_whitebalance, wb) 1385 1386 memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance)); 1387 ARGR(wb).mode = pwc_get_awb(pdev); 1388 if (ARGR(wb).mode < 0) 1389 ret = -EINVAL; 1390 else { 1391 if (ARGR(wb).mode == PWC_WB_MANUAL) { 1392 ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red); 1393 if (ret < 0) 1394 break; 1395 ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue); 1396 if (ret < 0) 1397 break; 1398 } 1399 if (ARGR(wb).mode == PWC_WB_AUTO) { 1400 ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red); 1401 if (ret < 0) 1402 break; 1403 ret = pwc_read_blue_gain(pdev, &ARGR(wb).read_blue); 1404 if (ret < 0) 1405 break; 1406 } 1407 } 1408 ARG_OUT(wb) 1409 break; 1410 } 1411 1412 case VIDIOCPWCSAWBSPEED: 1413 { 1414 ARG_DEF(struct pwc_wb_speed, wbs) 1415 1416 if (ARGR(wbs).control_speed > 0) { 1417 ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed); 1418 } 1419 if (ARGR(wbs).control_delay > 0) { 1420 ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay); 1421 } 1422 break; 1423 } 1424 1425 case VIDIOCPWCGAWBSPEED: 1426 { 1427 ARG_DEF(struct pwc_wb_speed, wbs) 1428 1429 ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed); 1430 if (ret < 0) 1431 break; 1432 ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay); 1433 if (ret < 0) 1434 break; 1435 ARG_OUT(wbs) 1436 break; 1437 } 1438 1439 case VIDIOCPWCSLED: 1440 { 1441 ARG_DEF(struct pwc_leds, leds) 1442 1443 ARG_IN(leds) 1444 ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off); 1445 break; 1446 } 1447 1448 1449 case VIDIOCPWCGLED: 1450 { 1451 ARG_DEF(struct pwc_leds, leds) 1452 1453 ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off); 1454 ARG_OUT(leds) 1455 break; 1456 } 1457 1458 case VIDIOCPWCSCONTOUR: 1459 { 1460 ARG_DEF(int, contour) 1461 1462 ARG_IN(contour) 1463 ret = pwc_set_contour(pdev, ARGR(contour)); 1464 break; 1465 } 1466 1467 case VIDIOCPWCGCONTOUR: 1468 { 1469 ARG_DEF(int, contour) 1470 1471 ret = pwc_get_contour(pdev, ARGA(contour)); 1472 ARG_OUT(contour) 1473 break; 1474 } 1475 1476 case VIDIOCPWCSBACKLIGHT: 1477 { 1478 ARG_DEF(int, backlight) 1479 1480 ARG_IN(backlight) 1481 ret = pwc_set_backlight(pdev, ARGR(backlight)); 1482 break; 1483 } 1484 1485 case VIDIOCPWCGBACKLIGHT: 1486 { 1487 ARG_DEF(int, backlight) 1488 1489 ret = pwc_get_backlight(pdev, ARGA(backlight)); 1490 ARG_OUT(backlight) 1491 break; 1492 } 1493 1494 case VIDIOCPWCSFLICKER: 1495 { 1496 ARG_DEF(int, flicker) 1497 1498 ARG_IN(flicker) 1499 ret = pwc_set_flicker(pdev, ARGR(flicker)); 1500 break; 1501 } 1502 1503 case VIDIOCPWCGFLICKER: 1504 { 1505 ARG_DEF(int, flicker) 1506 1507 ret = pwc_get_flicker(pdev, ARGA(flicker)); 1508 ARG_OUT(flicker) 1509 break; 1510 } 1511 1512 case VIDIOCPWCSDYNNOISE: 1513 { 1514 ARG_DEF(int, dynnoise) 1515 1516 ARG_IN(dynnoise) 1517 ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise)); 1518 break; 1519 } 1520 1521 case VIDIOCPWCGDYNNOISE: 1522 { 1523 ARG_DEF(int, dynnoise) 1524 1525 ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise)); 1526 ARG_OUT(dynnoise); 1527 break; 1528 } 1529 1530 case VIDIOCPWCGREALSIZE: 1531 { 1532 ARG_DEF(struct pwc_imagesize, size) 1533 1534 ARGR(size).width = pdev->image.x; 1535 ARGR(size).height = pdev->image.y; 1536 ARG_OUT(size) 1537 break; 1538 } 1539 1540 case VIDIOCPWCMPTRESET: 1541 { 1542 if (pdev->features & FEATURE_MOTOR_PANTILT) 1543 { 1544 ARG_DEF(int, flags) 1545 1546 ARG_IN(flags) 1547 ret = pwc_mpt_reset(pdev, ARGR(flags)); 1548 } 1549 else 1550 { 1551 ret = -ENXIO; 1552 } 1553 break; 1554 } 1555 1556 case VIDIOCPWCMPTGRANGE: 1557 { 1558 if (pdev->features & FEATURE_MOTOR_PANTILT) 1559 { 1560 ARG_DEF(struct pwc_mpt_range, range) 1561 1562 ARGR(range) = pdev->angle_range; 1563 ARG_OUT(range) 1564 } 1565 else 1566 { 1567 ret = -ENXIO; 1568 } 1569 break; 1570 } 1571 1572 case VIDIOCPWCMPTSANGLE: 1573 { 1574 int new_pan, new_tilt; 1575 1576 if (pdev->features & FEATURE_MOTOR_PANTILT) 1577 { 1578 ARG_DEF(struct pwc_mpt_angles, angles) 1579 1580 ARG_IN(angles) 1581 /* The camera can only set relative angles, so 1582 do some calculations when getting an absolute angle . 1583 */ 1584 if (ARGR(angles).absolute) 1585 { 1586 new_pan = ARGR(angles).pan; 1587 new_tilt = ARGR(angles).tilt; 1588 } 1589 else 1590 { 1591 new_pan = pdev->pan_angle + ARGR(angles).pan; 1592 new_tilt = pdev->tilt_angle + ARGR(angles).tilt; 1593 } 1594 ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt); 1595 } 1596 else 1597 { 1598 ret = -ENXIO; 1599 } 1600 break; 1601 } 1602 1603 case VIDIOCPWCMPTGANGLE: 1604 { 1605 1606 if (pdev->features & FEATURE_MOTOR_PANTILT) 1607 { 1608 ARG_DEF(struct pwc_mpt_angles, angles) 1609 1610 ARGR(angles).absolute = 1; 1611 ARGR(angles).pan = pdev->pan_angle; 1612 ARGR(angles).tilt = pdev->tilt_angle; 1613 ARG_OUT(angles) 1614 } 1615 else 1616 { 1617 ret = -ENXIO; 1618 } 1619 break; 1620 } 1621 1622 case VIDIOCPWCMPTSTATUS: 1623 { 1624 if (pdev->features & FEATURE_MOTOR_PANTILT) 1625 { 1626 ARG_DEF(struct pwc_mpt_status, status) 1627 1628 ret = pwc_mpt_get_status(pdev, ARGA(status)); 1629 ARG_OUT(status) 1630 } 1631 else 1632 { 1633 ret = -ENXIO; 1634 } 1635 break; 1636 } 1637 1638 case VIDIOCPWCGVIDCMD: 1639 { 1640 ARG_DEF(struct pwc_video_command, cmd); 1641 1642 ARGR(cmd).type = pdev->type; 1643 ARGR(cmd).release = pdev->release; 1644 ARGR(cmd).command_len = pdev->cmd_len; 1645 memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len); 1646 ARGR(cmd).bandlength = pdev->vbandlength; 1647 ARGR(cmd).frame_size = pdev->frame_size; 1648 ARG_OUT(cmd) 1649 break; 1650 } 1651 /* 1652 case VIDIOCPWCGVIDTABLE: 1653 { 1654 ARG_DEF(struct pwc_table_init_buffer, table); 1655 ARGR(table).len = pdev->cmd_len; 1656 memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size); 1657 ARG_OUT(table) 1658 break; 1659 } 1660 */ 1661 1662 default: 1663 ret = -ENOIOCTLCMD; 1664 break; 1665 } 1666 1667 if (ret > 0) 1668 return 0; 1669 return ret; 1670} 1671 1672 1673/* vim: set cinoptions= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ 1674