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