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