linux/drivers/media/video/pwc/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.
   5   (C) 2004-2006 Luc Saillard (luc@saillard.org)
   6   (C) 2011 Hans de Goede <hdegoede@redhat.com>
   7
   8   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
   9   driver and thus may have bugs that are not present in the original version.
  10   Please send bug reports and support requests to <luc@saillard.org>.
  11
  12   NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
  13   driver and thus may have bugs that are not present in the original version.
  14   Please send bug reports and support requests to <luc@saillard.org>.
  15   The decompression routines have been implemented by reverse-engineering the
  16   Nemosoft binary pwcx module. Caveat emptor.
  17
  18   This program is free software; you can redistribute it and/or modify
  19   it under the terms of the GNU General Public License as published by
  20   the Free Software Foundation; either version 2 of the License, or
  21   (at your option) any later version.
  22
  23   This program is distributed in the hope that it will be useful,
  24   but WITHOUT ANY WARRANTY; without even the implied warranty of
  25   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  26   GNU General Public License for more details.
  27
  28   You should have received a copy of the GNU General Public License
  29   along with this program; if not, write to the Free Software
  30   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  31*/
  32
  33/*
  34   Changes
  35   2001/08/03  Alvarado   Added methods for changing white balance and
  36                          red/green gains
  37 */
  38
  39/* Control functions for the cam; brightness, contrast, video mode, etc. */
  40
  41#ifdef __KERNEL__
  42#include <asm/uaccess.h>
  43#endif
  44#include <asm/errno.h>
  45
  46#include "pwc.h"
  47#include "pwc-kiara.h"
  48#include "pwc-timon.h"
  49#include "pwc-dec1.h"
  50#include "pwc-dec23.h"
  51
  52/* Selectors for status controls used only in this file */
  53#define GET_STATUS_B00                          0x0B00
  54#define SENSOR_TYPE_FORMATTER1                  0x0C00
  55#define GET_STATUS_3000                         0x3000
  56#define READ_RAW_Y_MEAN_FORMATTER               0x3100
  57#define SET_POWER_SAVE_MODE_FORMATTER           0x3200
  58#define MIRROR_IMAGE_FORMATTER                  0x3300
  59#define LED_FORMATTER                           0x3400
  60#define LOWLIGHT                                0x3500
  61#define GET_STATUS_3600                         0x3600
  62#define SENSOR_TYPE_FORMATTER2                  0x3700
  63#define GET_STATUS_3800                         0x3800
  64#define GET_STATUS_4000                         0x4000
  65#define GET_STATUS_4100                         0x4100  /* Get */
  66#define CTL_STATUS_4200                         0x4200  /* [GS] 1 */
  67
  68/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */
  69#define VIDEO_OUTPUT_CONTROL_FORMATTER          0x0100
  70
  71static const char *size2name[PSZ_MAX] =
  72{
  73        "subQCIF",
  74        "QSIF",
  75        "QCIF",
  76        "SIF",
  77        "CIF",
  78        "VGA",
  79};
  80
  81/********/
  82
  83/* Entries for the Nala (645/646) camera; the Nala doesn't have compression
  84   preferences, so you either get compressed or non-compressed streams.
  85
  86   An alternate value of 0 means this mode is not available at all.
  87 */
  88
  89#define PWC_FPS_MAX_NALA 8
  90
  91struct Nala_table_entry {
  92        char alternate;                 /* USB alternate setting */
  93        int compressed;                 /* Compressed yes/no */
  94
  95        unsigned char mode[3];          /* precomputed mode table */
  96};
  97
  98static unsigned int Nala_fps_vector[PWC_FPS_MAX_NALA] = { 4, 5, 7, 10, 12, 15, 20, 24 };
  99
 100static struct Nala_table_entry Nala_table[PSZ_MAX][PWC_FPS_MAX_NALA] =
 101{
 102#include "pwc-nala.h"
 103};
 104
 105static void pwc_set_image_buffer_size(struct pwc_device *pdev);
 106
 107/****************************************************************************/
 108
 109static int _send_control_msg(struct pwc_device *pdev,
 110        u8 request, u16 value, int index, void *buf, int buflen)
 111{
 112        int rc;
 113        void *kbuf = NULL;
 114
 115        if (buflen) {
 116                kbuf = kmalloc(buflen, GFP_KERNEL); /* not allowed on stack */
 117                if (kbuf == NULL)
 118                        return -ENOMEM;
 119                memcpy(kbuf, buf, buflen);
 120        }
 121
 122        rc = usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0),
 123                request,
 124                USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 125                value,
 126                index,
 127                kbuf, buflen, USB_CTRL_SET_TIMEOUT);
 128
 129        kfree(kbuf);
 130        return rc;
 131}
 132
 133static int recv_control_msg(struct pwc_device *pdev,
 134        u8 request, u16 value, void *buf, int buflen)
 135{
 136        int rc;
 137        void *kbuf = kmalloc(buflen, GFP_KERNEL); /* not allowed on stack */
 138
 139        if (kbuf == NULL)
 140                return -ENOMEM;
 141
 142        rc = usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0),
 143                request,
 144                USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 145                value,
 146                pdev->vcinterface,
 147                kbuf, buflen, USB_CTRL_GET_TIMEOUT);
 148        memcpy(buf, kbuf, buflen);
 149        kfree(kbuf);
 150
 151        if (rc < 0)
 152                PWC_ERROR("recv_control_msg error %d req %02x val %04x\n",
 153                          rc, request, value);
 154        return rc;
 155}
 156
 157static inline int send_video_command(struct pwc_device *pdev,
 158        int index, void *buf, int buflen)
 159{
 160        return _send_control_msg(pdev,
 161                SET_EP_STREAM_CTL,
 162                VIDEO_OUTPUT_CONTROL_FORMATTER,
 163                index,
 164                buf, buflen);
 165}
 166
 167int send_control_msg(struct pwc_device *pdev,
 168        u8 request, u16 value, void *buf, int buflen)
 169{
 170        return _send_control_msg(pdev,
 171                request, value, pdev->vcinterface, buf, buflen);
 172}
 173
 174static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
 175{
 176        unsigned char buf[3];
 177        int ret, fps;
 178        struct Nala_table_entry *pEntry;
 179        int frames2frames[31] =
 180        { /* closest match of framerate */
 181           0,  0,  0,  0,  4,  /*  0-4  */
 182           5,  5,  7,  7, 10,  /*  5-9  */
 183          10, 10, 12, 12, 15,  /* 10-14 */
 184          15, 15, 15, 20, 20,  /* 15-19 */
 185          20, 20, 20, 24, 24,  /* 20-24 */
 186          24, 24, 24, 24, 24,  /* 25-29 */
 187          24                   /* 30    */
 188        };
 189        int frames2table[31] =
 190        { 0, 0, 0, 0, 0, /*  0-4  */
 191          1, 1, 1, 2, 2, /*  5-9  */
 192          3, 3, 4, 4, 4, /* 10-14 */
 193          5, 5, 5, 5, 5, /* 15-19 */
 194          6, 6, 6, 6, 7, /* 20-24 */
 195          7, 7, 7, 7, 7, /* 25-29 */
 196          7              /* 30    */
 197        };
 198
 199        if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25)
 200                return -EINVAL;
 201        frames = frames2frames[frames];
 202        fps = frames2table[frames];
 203        pEntry = &Nala_table[size][fps];
 204        if (pEntry->alternate == 0)
 205                return -EINVAL;
 206
 207        memcpy(buf, pEntry->mode, 3);
 208        ret = send_video_command(pdev, pdev->vendpoint, buf, 3);
 209        if (ret < 0) {
 210                PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret);
 211                return ret;
 212        }
 213        if (pEntry->compressed && pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
 214                ret = pwc_dec1_init(pdev, pdev->type, pdev->release, buf);
 215                if (ret < 0)
 216                        return ret;
 217        }
 218
 219        pdev->cmd_len = 3;
 220        memcpy(pdev->cmd_buf, buf, 3);
 221
 222        /* Set various parameters */
 223        pdev->vframes = frames;
 224        pdev->vsize = size;
 225        pdev->valternate = pEntry->alternate;
 226        pdev->image = pwc_image_sizes[size];
 227        pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2;
 228        if (pEntry->compressed) {
 229                if (pdev->release < 5) { /* 4 fold compression */
 230                        pdev->vbandlength = 528;
 231                        pdev->frame_size /= 4;
 232                }
 233                else {
 234                        pdev->vbandlength = 704;
 235                        pdev->frame_size /= 3;
 236                }
 237        }
 238        else
 239                pdev->vbandlength = 0;
 240        return 0;
 241}
 242
 243
 244static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
 245{
 246        unsigned char buf[13];
 247        const struct Timon_table_entry *pChoose;
 248        int ret, fps;
 249
 250        if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
 251                return -EINVAL;
 252        if (size == PSZ_VGA && frames > 15)
 253                return -EINVAL;
 254        fps = (frames / 5) - 1;
 255
 256        /* Find a supported framerate with progressively higher compression ratios
 257           if the preferred ratio is not available.
 258        */
 259        pChoose = NULL;
 260        while (compression <= 3) {
 261           pChoose = &Timon_table[size][fps][compression];
 262           if (pChoose->alternate != 0)
 263             break;
 264           compression++;
 265        }
 266        if (pChoose == NULL || pChoose->alternate == 0)
 267                return -ENOENT; /* Not supported. */
 268
 269        memcpy(buf, pChoose->mode, 13);
 270        if (snapshot)
 271                buf[0] |= 0x80;
 272        ret = send_video_command(pdev, pdev->vendpoint, buf, 13);
 273        if (ret < 0)
 274                return ret;
 275
 276        if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
 277                ret = pwc_dec23_init(pdev, pdev->type, buf);
 278                if (ret < 0)
 279                        return ret;
 280        }
 281
 282        pdev->cmd_len = 13;
 283        memcpy(pdev->cmd_buf, buf, 13);
 284
 285        /* Set various parameters */
 286        pdev->vframes = frames;
 287        pdev->vsize = size;
 288        pdev->vsnapshot = snapshot;
 289        pdev->valternate = pChoose->alternate;
 290        pdev->image = pwc_image_sizes[size];
 291        pdev->vbandlength = pChoose->bandlength;
 292        if (pChoose->bandlength > 0)
 293                pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4;
 294        else
 295                pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
 296        return 0;
 297}
 298
 299
 300static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot)
 301{
 302        const struct Kiara_table_entry *pChoose = NULL;
 303        int fps, ret;
 304        unsigned char buf[12];
 305        struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}};
 306
 307        if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3)
 308                return -EINVAL;
 309        if (size == PSZ_VGA && frames > 15)
 310                return -EINVAL;
 311        fps = (frames / 5) - 1;
 312
 313        /* special case: VGA @ 5 fps and snapshot is raw bayer mode */
 314        if (size == PSZ_VGA && frames == 5 && snapshot && pdev->pixfmt != V4L2_PIX_FMT_YUV420)
 315        {
 316                /* Only available in case the raw palette is selected or
 317                   we have the decompressor available. This mode is
 318                   only available in compressed form
 319                */
 320                PWC_DEBUG_SIZE("Choosing VGA/5 BAYER mode.\n");
 321                pChoose = &RawEntry;
 322        }
 323        else
 324        {
 325                /* Find a supported framerate with progressively higher compression ratios
 326                   if the preferred ratio is not available.
 327                   Skip this step when using RAW modes.
 328                */
 329                snapshot = 0;
 330                while (compression <= 3) {
 331                        pChoose = &Kiara_table[size][fps][compression];
 332                        if (pChoose->alternate != 0)
 333                                break;
 334                        compression++;
 335                }
 336        }
 337        if (pChoose == NULL || pChoose->alternate == 0)
 338                return -ENOENT; /* Not supported. */
 339
 340        PWC_TRACE("Using alternate setting %d.\n", pChoose->alternate);
 341
 342        /* usb_control_msg won't take staticly allocated arrays as argument?? */
 343        memcpy(buf, pChoose->mode, 12);
 344        if (snapshot)
 345                buf[0] |= 0x80;
 346
 347        /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */
 348        ret = send_video_command(pdev, 4 /* pdev->vendpoint */, buf, 12);
 349        if (ret < 0)
 350                return ret;
 351
 352        if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
 353                ret = pwc_dec23_init(pdev, pdev->type, buf);
 354                if (ret < 0)
 355                        return ret;
 356        }
 357
 358        pdev->cmd_len = 12;
 359        memcpy(pdev->cmd_buf, buf, 12);
 360        /* All set and go */
 361        pdev->vframes = frames;
 362        pdev->vsize = size;
 363        pdev->vsnapshot = snapshot;
 364        pdev->valternate = pChoose->alternate;
 365        pdev->image = pwc_image_sizes[size];
 366        pdev->vbandlength = pChoose->bandlength;
 367        if (pdev->vbandlength > 0)
 368                pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4;
 369        else
 370                pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8;
 371        PWC_TRACE("frame_size=%d, vframes=%d, vsize=%d, vsnapshot=%d, vbandlength=%d\n",
 372            pdev->frame_size,pdev->vframes,pdev->vsize,pdev->vsnapshot,pdev->vbandlength);
 373        return 0;
 374}
 375
 376
 377
 378/**
 379   @pdev: device structure
 380   @width: viewport width
 381   @height: viewport height
 382   @frame: framerate, in fps
 383   @compression: preferred compression ratio
 384   @snapshot: snapshot mode or streaming
 385 */
 386int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot)
 387{
 388        int ret, size;
 389
 390        PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", width, height, frames, pdev->pixfmt);
 391        size = pwc_decode_size(pdev, width, height);
 392        if (size < 0) {
 393                PWC_DEBUG_MODULE("Could not find suitable size.\n");
 394                return -ERANGE;
 395        }
 396        PWC_TRACE("decode_size = %d.\n", size);
 397
 398        if (DEVICE_USE_CODEC1(pdev->type)) {
 399                ret = set_video_mode_Nala(pdev, size, frames);
 400
 401        } else if (DEVICE_USE_CODEC3(pdev->type)) {
 402                ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot);
 403
 404        } else {
 405                ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot);
 406        }
 407        if (ret < 0) {
 408                PWC_ERROR("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret);
 409                return ret;
 410        }
 411        pdev->view.x = width;
 412        pdev->view.y = height;
 413        pdev->vcompression = compression;
 414        pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size;
 415        pwc_set_image_buffer_size(pdev);
 416        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);
 417        return 0;
 418}
 419
 420static unsigned int pwc_get_fps_Nala(struct pwc_device *pdev, unsigned int index, unsigned int size)
 421{
 422        unsigned int i;
 423
 424        for (i = 0; i < PWC_FPS_MAX_NALA; i++) {
 425                if (Nala_table[size][i].alternate) {
 426                        if (index--==0) return Nala_fps_vector[i];
 427                }
 428        }
 429        return 0;
 430}
 431
 432static unsigned int pwc_get_fps_Kiara(struct pwc_device *pdev, unsigned int index, unsigned int size)
 433{
 434        unsigned int i;
 435
 436        for (i = 0; i < PWC_FPS_MAX_KIARA; i++) {
 437                if (Kiara_table[size][i][3].alternate) {
 438                        if (index--==0) return Kiara_fps_vector[i];
 439                }
 440        }
 441        return 0;
 442}
 443
 444static unsigned int pwc_get_fps_Timon(struct pwc_device *pdev, unsigned int index, unsigned int size)
 445{
 446        unsigned int i;
 447
 448        for (i=0; i < PWC_FPS_MAX_TIMON; i++) {
 449                if (Timon_table[size][i][3].alternate) {
 450                        if (index--==0) return Timon_fps_vector[i];
 451                }
 452        }
 453        return 0;
 454}
 455
 456unsigned int pwc_get_fps(struct pwc_device *pdev, unsigned int index, unsigned int size)
 457{
 458        unsigned int ret;
 459
 460        if (DEVICE_USE_CODEC1(pdev->type)) {
 461                ret = pwc_get_fps_Nala(pdev, index, size);
 462
 463        } else if (DEVICE_USE_CODEC3(pdev->type)) {
 464                ret = pwc_get_fps_Kiara(pdev, index, size);
 465
 466        } else {
 467                ret = pwc_get_fps_Timon(pdev, index, size);
 468        }
 469
 470        return ret;
 471}
 472
 473static void pwc_set_image_buffer_size(struct pwc_device *pdev)
 474{
 475        int factor = 0;
 476
 477        /* for V4L2_PIX_FMT_YUV420 */
 478        switch (pdev->pixfmt) {
 479        case V4L2_PIX_FMT_YUV420:
 480                factor = 6;
 481                break;
 482        case V4L2_PIX_FMT_PWC1:
 483        case V4L2_PIX_FMT_PWC2:
 484                factor = 6; /* can be uncompressed YUV420P */
 485                break;
 486        }
 487
 488        /* Set sizes in bytes */
 489        pdev->image.size = pdev->image.x * pdev->image.y * factor / 4;
 490        pdev->view.size  = pdev->view.x  * pdev->view.y  * factor / 4;
 491
 492        /* Align offset, or you'll get some very weird results in
 493           YUV420 mode... x must be multiple of 4 (to get the Y's in
 494           place), and y even (or you'll mixup U & V). This is less of a
 495           problem for YUV420P.
 496         */
 497        pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC;
 498        pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE;
 499}
 500
 501int pwc_get_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
 502{
 503        int ret;
 504        u8 buf;
 505
 506        ret = recv_control_msg(pdev, request, value, &buf, sizeof(buf));
 507        if (ret < 0)
 508                return ret;
 509
 510        *data = buf;
 511        return 0;
 512}
 513
 514int pwc_set_u8_ctrl(struct pwc_device *pdev, u8 request, u16 value, u8 data)
 515{
 516        int ret;
 517
 518        ret = send_control_msg(pdev, request, value, &data, sizeof(data));
 519        if (ret < 0)
 520                return ret;
 521
 522        return 0;
 523}
 524
 525int pwc_get_s8_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
 526{
 527        int ret;
 528        s8 buf;
 529
 530        ret = recv_control_msg(pdev, request, value, &buf, sizeof(buf));
 531        if (ret < 0)
 532                return ret;
 533
 534        *data = buf;
 535        return 0;
 536}
 537
 538int pwc_get_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, int *data)
 539{
 540        int ret;
 541        u8 buf[2];
 542
 543        ret = recv_control_msg(pdev, request, value, buf, sizeof(buf));
 544        if (ret < 0)
 545                return ret;
 546
 547        *data = (buf[1] << 8) | buf[0];
 548        return 0;
 549}
 550
 551int pwc_set_u16_ctrl(struct pwc_device *pdev, u8 request, u16 value, u16 data)
 552{
 553        int ret;
 554        u8 buf[2];
 555
 556        buf[0] = data & 0xff;
 557        buf[1] = data >> 8;
 558        ret = send_control_msg(pdev, request, value, buf, sizeof(buf));
 559        if (ret < 0)
 560                return ret;
 561
 562        return 0;
 563}
 564
 565int pwc_button_ctrl(struct pwc_device *pdev, u16 value)
 566{
 567        int ret;
 568
 569        ret = send_control_msg(pdev, SET_STATUS_CTL, value, NULL, 0);
 570        if (ret < 0)
 571                return ret;
 572
 573        return 0;
 574}
 575
 576/* POWER */
 577void pwc_camera_power(struct pwc_device *pdev, int power)
 578{
 579        char buf;
 580        int r;
 581
 582        if (!pdev->power_save)
 583                return;
 584
 585        if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6))
 586                return; /* Not supported by Nala or Timon < release 6 */
 587
 588        if (power)
 589                buf = 0x00; /* active */
 590        else
 591                buf = 0xFF; /* power save */
 592        r = send_control_msg(pdev,
 593                SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER,
 594                &buf, sizeof(buf));
 595
 596        if (r < 0)
 597                PWC_ERROR("Failed to power %s camera (%d)\n",
 598                          power ? "on" : "off", r);
 599}
 600
 601static int pwc_set_wb_speed(struct pwc_device *pdev, int speed)
 602{
 603        unsigned char buf;
 604
 605        /* useful range is 0x01..0x20 */
 606        buf = speed / 0x7f0;
 607        return send_control_msg(pdev,
 608                SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, &buf, sizeof(buf));
 609}
 610
 611static int pwc_get_wb_speed(struct pwc_device *pdev, int *value)
 612{
 613        unsigned char buf;
 614        int ret;
 615
 616        ret = recv_control_msg(pdev,
 617                GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, &buf, sizeof(buf));
 618        if (ret < 0)
 619                return ret;
 620        *value = buf * 0x7f0;
 621        return 0;
 622}
 623
 624
 625static int pwc_set_wb_delay(struct pwc_device *pdev, int delay)
 626{
 627        unsigned char buf;
 628
 629        /* useful range is 0x01..0x3F */
 630        buf = (delay >> 10);
 631        return send_control_msg(pdev,
 632                SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, &buf, sizeof(buf));
 633}
 634
 635static int pwc_get_wb_delay(struct pwc_device *pdev, int *value)
 636{
 637        unsigned char buf;
 638        int ret;
 639
 640        ret = recv_control_msg(pdev,
 641                GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, &buf, sizeof(buf));
 642        if (ret < 0)
 643                return ret;
 644        *value = buf << 10;
 645        return 0;
 646}
 647
 648
 649int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value)
 650{
 651        unsigned char buf[2];
 652        int r;
 653
 654        if (pdev->type < 730)
 655                return 0;
 656        on_value /= 100;
 657        off_value /= 100;
 658        if (on_value < 0)
 659                on_value = 0;
 660        if (on_value > 0xff)
 661                on_value = 0xff;
 662        if (off_value < 0)
 663                off_value = 0;
 664        if (off_value > 0xff)
 665                off_value = 0xff;
 666
 667        buf[0] = on_value;
 668        buf[1] = off_value;
 669
 670        r = send_control_msg(pdev,
 671                SET_STATUS_CTL, LED_FORMATTER, &buf, sizeof(buf));
 672        if (r < 0)
 673                PWC_ERROR("Failed to set LED on/off time (%d)\n", r);
 674
 675        return r;
 676}
 677
 678static int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value)
 679{
 680        unsigned char buf[2];
 681        int ret;
 682
 683        if (pdev->type < 730) {
 684                *on_value = -1;
 685                *off_value = -1;
 686                return 0;
 687        }
 688
 689        ret = recv_control_msg(pdev,
 690                GET_STATUS_CTL, LED_FORMATTER, &buf, sizeof(buf));
 691        if (ret < 0)
 692                return ret;
 693        *on_value = buf[0] * 100;
 694        *off_value = buf[1] * 100;
 695        return 0;
 696}
 697
 698static int _pwc_mpt_reset(struct pwc_device *pdev, int flags)
 699{
 700        unsigned char buf;
 701
 702        buf = flags & 0x03; // only lower two bits are currently used
 703        return send_control_msg(pdev,
 704                SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, &buf, sizeof(buf));
 705}
 706
 707int pwc_mpt_reset(struct pwc_device *pdev, int flags)
 708{
 709        int ret;
 710        ret = _pwc_mpt_reset(pdev, flags);
 711        if (ret >= 0) {
 712                pdev->pan_angle = 0;
 713                pdev->tilt_angle = 0;
 714        }
 715        return ret;
 716}
 717
 718static int _pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
 719{
 720        unsigned char buf[4];
 721
 722        /* set new relative angle; angles are expressed in degrees * 100,
 723           but cam as .5 degree resolution, hence divide by 200. Also
 724           the angle must be multiplied by 64 before it's send to
 725           the cam (??)
 726         */
 727        pan  =  64 * pan  / 100;
 728        tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */
 729        buf[0] = pan & 0xFF;
 730        buf[1] = (pan >> 8) & 0xFF;
 731        buf[2] = tilt & 0xFF;
 732        buf[3] = (tilt >> 8) & 0xFF;
 733        return send_control_msg(pdev,
 734                SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, &buf, sizeof(buf));
 735}
 736
 737int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt)
 738{
 739        int ret;
 740
 741        /* check absolute ranges */
 742        if (pan  < pdev->angle_range.pan_min  ||
 743            pan  > pdev->angle_range.pan_max  ||
 744            tilt < pdev->angle_range.tilt_min ||
 745            tilt > pdev->angle_range.tilt_max)
 746                return -ERANGE;
 747
 748        /* go to relative range, check again */
 749        pan  -= pdev->pan_angle;
 750        tilt -= pdev->tilt_angle;
 751        /* angles are specified in degrees * 100, thus the limit = 36000 */
 752        if (pan < -36000 || pan > 36000 || tilt < -36000 || tilt > 36000)
 753                return -ERANGE;
 754
 755        ret = _pwc_mpt_set_angle(pdev, pan, tilt);
 756        if (ret >= 0) {
 757                pdev->pan_angle  += pan;
 758                pdev->tilt_angle += tilt;
 759        }
 760        if (ret == -EPIPE) /* stall -> out of range */
 761                ret = -ERANGE;
 762        return ret;
 763}
 764
 765static int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status)
 766{
 767        int ret;
 768        unsigned char buf[5];
 769
 770        ret = recv_control_msg(pdev,
 771                GET_MPT_CTL, PT_STATUS_FORMATTER, &buf, sizeof(buf));
 772        if (ret < 0)
 773                return ret;
 774        status->status = buf[0] & 0x7; // 3 bits are used for reporting
 775        status->time_pan = (buf[1] << 8) + buf[2];
 776        status->time_tilt = (buf[3] << 8) + buf[4];
 777        return 0;
 778}
 779
 780#ifdef CONFIG_USB_PWC_DEBUG
 781int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor)
 782{
 783        unsigned char buf;
 784        int ret = -1, request;
 785
 786        if (pdev->type < 675)
 787                request = SENSOR_TYPE_FORMATTER1;
 788        else if (pdev->type < 730)
 789                return -1; /* The Vesta series doesn't have this call */
 790        else
 791                request = SENSOR_TYPE_FORMATTER2;
 792
 793        ret = recv_control_msg(pdev,
 794                GET_STATUS_CTL, request, &buf, sizeof(buf));
 795        if (ret < 0)
 796                return ret;
 797        if (pdev->type < 675)
 798                *sensor = buf | 0x100;
 799        else
 800                *sensor = buf;
 801        return 0;
 802}
 803#endif
 804
 805 /* End of Add-Ons                                    */
 806 /* ************************************************* */
 807
 808/* Linux 2.5.something and 2.6 pass direct pointers to arguments of
 809   ioctl() calls. With 2.4, you have to do tedious copy_from_user()
 810   and copy_to_user() calls. With these macros we circumvent this,
 811   and let me maintain only one source file. The functionality is
 812   exactly the same otherwise.
 813 */
 814
 815/* define local variable for arg */
 816#define ARG_DEF(ARG_type, ARG_name)\
 817        ARG_type *ARG_name = arg;
 818/* copy arg to local variable */
 819#define ARG_IN(ARG_name) /* nothing */
 820/* argument itself (referenced) */
 821#define ARGR(ARG_name) (*ARG_name)
 822/* argument address */
 823#define ARGA(ARG_name) ARG_name
 824/* copy local variable to arg */
 825#define ARG_OUT(ARG_name) /* nothing */
 826
 827/*
 828 * Our ctrls use native values, but the old custom pwc ioctl interface expects
 829 * values from 0 - 65535, define 2 helper functions to scale things. */
 830static int pwc_ioctl_g_ctrl(struct v4l2_ctrl *ctrl)
 831{
 832        return v4l2_ctrl_g_ctrl(ctrl) * 65535 / ctrl->maximum;
 833}
 834
 835static int pwc_ioctl_s_ctrl(struct v4l2_ctrl *ctrl, int val)
 836{
 837        return v4l2_ctrl_s_ctrl(ctrl, val * ctrl->maximum / 65535);
 838}
 839
 840long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
 841{
 842        long ret = 0;
 843
 844        switch(cmd) {
 845        case VIDIOCPWCRUSER:
 846                ret = pwc_button_ctrl(pdev, RESTORE_USER_DEFAULTS_FORMATTER);
 847                break;
 848
 849        case VIDIOCPWCSUSER:
 850                ret = pwc_button_ctrl(pdev, SAVE_USER_DEFAULTS_FORMATTER);
 851                break;
 852
 853        case VIDIOCPWCFACTORY:
 854                ret = pwc_button_ctrl(pdev, RESTORE_FACTORY_DEFAULTS_FORMATTER);
 855                break;
 856
 857        case VIDIOCPWCSCQUAL:
 858        {
 859                ARG_DEF(int, qual)
 860
 861                if (vb2_is_streaming(&pdev->vb_queue)) {
 862                        ret = -EBUSY;
 863                        break;
 864                }
 865
 866                ARG_IN(qual)
 867                if (ARGR(qual) < 0 || ARGR(qual) > 3)
 868                        ret = -EINVAL;
 869                else
 870                        ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot);
 871                break;
 872        }
 873
 874        case VIDIOCPWCGCQUAL:
 875        {
 876                ARG_DEF(int, qual)
 877
 878                ARGR(qual) = pdev->vcompression;
 879                ARG_OUT(qual)
 880                break;
 881        }
 882
 883        case VIDIOCPWCPROBE:
 884        {
 885                ARG_DEF(struct pwc_probe, probe)
 886
 887                strcpy(ARGR(probe).name, pdev->vdev.name);
 888                ARGR(probe).type = pdev->type;
 889                ARG_OUT(probe)
 890                break;
 891        }
 892
 893        case VIDIOCPWCGSERIAL:
 894        {
 895                ARG_DEF(struct pwc_serial, serial)
 896
 897                strcpy(ARGR(serial).serial, pdev->serial);
 898                ARG_OUT(serial)
 899                break;
 900        }
 901
 902        case VIDIOCPWCSAGC:
 903        {
 904                ARG_DEF(int, agc)
 905                ARG_IN(agc)
 906                ret = v4l2_ctrl_s_ctrl(pdev->autogain, ARGR(agc) < 0);
 907                if (ret == 0 && ARGR(agc) >= 0)
 908                        ret = pwc_ioctl_s_ctrl(pdev->gain, ARGR(agc));
 909                break;
 910        }
 911
 912        case VIDIOCPWCGAGC:
 913        {
 914                ARG_DEF(int, agc)
 915                if (v4l2_ctrl_g_ctrl(pdev->autogain))
 916                        ARGR(agc) = -1;
 917                else
 918                        ARGR(agc) = pwc_ioctl_g_ctrl(pdev->gain);
 919                ARG_OUT(agc)
 920                break;
 921        }
 922
 923        case VIDIOCPWCSSHUTTER:
 924        {
 925                ARG_DEF(int, shutter)
 926                ARG_IN(shutter)
 927                ret = v4l2_ctrl_s_ctrl(pdev->exposure_auto,
 928                                       /* Menu idx 0 = auto, idx 1 = manual */
 929                                       ARGR(shutter) >= 0);
 930                if (ret == 0 && ARGR(shutter) >= 0)
 931                        ret = pwc_ioctl_s_ctrl(pdev->exposure, ARGR(shutter));
 932                break;
 933        }
 934
 935        case VIDIOCPWCSAWB:
 936        {
 937                ARG_DEF(struct pwc_whitebalance, wb)
 938                ARG_IN(wb)
 939                ret = v4l2_ctrl_s_ctrl(pdev->auto_white_balance,
 940                                       ARGR(wb).mode);
 941                if (ret == 0 && ARGR(wb).mode == PWC_WB_MANUAL)
 942                        ret = pwc_ioctl_s_ctrl(pdev->red_balance,
 943                                               ARGR(wb).manual_red);
 944                if (ret == 0 && ARGR(wb).mode == PWC_WB_MANUAL)
 945                        ret = pwc_ioctl_s_ctrl(pdev->blue_balance,
 946                                               ARGR(wb).manual_blue);
 947                break;
 948        }
 949
 950        case VIDIOCPWCGAWB:
 951        {
 952                ARG_DEF(struct pwc_whitebalance, wb)
 953                ARGR(wb).mode = v4l2_ctrl_g_ctrl(pdev->auto_white_balance);
 954                ARGR(wb).manual_red = ARGR(wb).read_red =
 955                        pwc_ioctl_g_ctrl(pdev->red_balance);
 956                ARGR(wb).manual_blue = ARGR(wb).read_blue =
 957                        pwc_ioctl_g_ctrl(pdev->blue_balance);
 958                ARG_OUT(wb)
 959                break;
 960        }
 961
 962        case VIDIOCPWCSAWBSPEED:
 963        {
 964                ARG_DEF(struct pwc_wb_speed, wbs)
 965
 966                if (ARGR(wbs).control_speed > 0) {
 967                        ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed);
 968                }
 969                if (ARGR(wbs).control_delay > 0) {
 970                        ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay);
 971                }
 972                break;
 973        }
 974
 975        case VIDIOCPWCGAWBSPEED:
 976        {
 977                ARG_DEF(struct pwc_wb_speed, wbs)
 978
 979                ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed);
 980                if (ret < 0)
 981                        break;
 982                ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay);
 983                if (ret < 0)
 984                        break;
 985                ARG_OUT(wbs)
 986                break;
 987        }
 988
 989        case VIDIOCPWCSLED:
 990        {
 991                ARG_DEF(struct pwc_leds, leds)
 992
 993                ARG_IN(leds)
 994                ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off);
 995                break;
 996        }
 997
 998
 999        case VIDIOCPWCGLED:
1000        {
1001                ARG_DEF(struct pwc_leds, leds)
1002
1003                ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off);
1004                ARG_OUT(leds)
1005                break;
1006        }
1007
1008        case VIDIOCPWCSCONTOUR:
1009        {
1010                ARG_DEF(int, contour)
1011                ARG_IN(contour)
1012                ret = v4l2_ctrl_s_ctrl(pdev->autocontour, ARGR(contour) < 0);
1013                if (ret == 0 && ARGR(contour) >= 0)
1014                        ret = pwc_ioctl_s_ctrl(pdev->contour, ARGR(contour));
1015                break;
1016        }
1017
1018        case VIDIOCPWCGCONTOUR:
1019        {
1020                ARG_DEF(int, contour)
1021                if (v4l2_ctrl_g_ctrl(pdev->autocontour))
1022                        ARGR(contour) = -1;
1023                else
1024                        ARGR(contour) = pwc_ioctl_g_ctrl(pdev->contour);
1025                ARG_OUT(contour)
1026                break;
1027        }
1028
1029        case VIDIOCPWCSBACKLIGHT:
1030        {
1031                ARG_DEF(int, backlight)
1032                ARG_IN(backlight)
1033                ret = v4l2_ctrl_s_ctrl(pdev->backlight, ARGR(backlight));
1034                break;
1035        }
1036
1037        case VIDIOCPWCGBACKLIGHT:
1038        {
1039                ARG_DEF(int, backlight)
1040                ARGR(backlight) = v4l2_ctrl_g_ctrl(pdev->backlight);
1041                ARG_OUT(backlight)
1042                break;
1043        }
1044
1045        case VIDIOCPWCSFLICKER:
1046        {
1047                ARG_DEF(int, flicker)
1048                ARG_IN(flicker)
1049                ret = v4l2_ctrl_s_ctrl(pdev->flicker, ARGR(flicker));
1050                break;
1051        }
1052
1053        case VIDIOCPWCGFLICKER:
1054        {
1055                ARG_DEF(int, flicker)
1056                ARGR(flicker) = v4l2_ctrl_g_ctrl(pdev->flicker);
1057                ARG_OUT(flicker)
1058                break;
1059        }
1060
1061        case VIDIOCPWCSDYNNOISE:
1062        {
1063                ARG_DEF(int, dynnoise)
1064                ARG_IN(dynnoise)
1065                ret = v4l2_ctrl_s_ctrl(pdev->noise_reduction, ARGR(dynnoise));
1066                break;
1067        }
1068
1069        case VIDIOCPWCGDYNNOISE:
1070        {
1071                ARG_DEF(int, dynnoise)
1072                ARGR(dynnoise) = v4l2_ctrl_g_ctrl(pdev->noise_reduction);
1073                ARG_OUT(dynnoise);
1074                break;
1075        }
1076
1077        case VIDIOCPWCGREALSIZE:
1078        {
1079                ARG_DEF(struct pwc_imagesize, size)
1080
1081                ARGR(size).width = pdev->image.x;
1082                ARGR(size).height = pdev->image.y;
1083                ARG_OUT(size)
1084                break;
1085        }
1086
1087        case VIDIOCPWCMPTRESET:
1088        {
1089                if (pdev->features & FEATURE_MOTOR_PANTILT)
1090                {
1091                        ARG_DEF(int, flags)
1092
1093                        ARG_IN(flags)
1094                        ret = pwc_mpt_reset(pdev, ARGR(flags));
1095                }
1096                else
1097                {
1098                        ret = -ENXIO;
1099                }
1100                break;
1101        }
1102
1103        case VIDIOCPWCMPTGRANGE:
1104        {
1105                if (pdev->features & FEATURE_MOTOR_PANTILT)
1106                {
1107                        ARG_DEF(struct pwc_mpt_range, range)
1108
1109                        ARGR(range) = pdev->angle_range;
1110                        ARG_OUT(range)
1111                }
1112                else
1113                {
1114                        ret = -ENXIO;
1115                }
1116                break;
1117        }
1118
1119        case VIDIOCPWCMPTSANGLE:
1120        {
1121                int new_pan, new_tilt;
1122
1123                if (pdev->features & FEATURE_MOTOR_PANTILT)
1124                {
1125                        ARG_DEF(struct pwc_mpt_angles, angles)
1126
1127                        ARG_IN(angles)
1128                        /* The camera can only set relative angles, so
1129                           do some calculations when getting an absolute angle .
1130                         */
1131                        if (ARGR(angles).absolute)
1132                        {
1133                                new_pan  = ARGR(angles).pan;
1134                                new_tilt = ARGR(angles).tilt;
1135                        }
1136                        else
1137                        {
1138                                new_pan  = pdev->pan_angle  + ARGR(angles).pan;
1139                                new_tilt = pdev->tilt_angle + ARGR(angles).tilt;
1140                        }
1141                        ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt);
1142                }
1143                else
1144                {
1145                        ret = -ENXIO;
1146                }
1147                break;
1148        }
1149
1150        case VIDIOCPWCMPTGANGLE:
1151        {
1152
1153                if (pdev->features & FEATURE_MOTOR_PANTILT)
1154                {
1155                        ARG_DEF(struct pwc_mpt_angles, angles)
1156
1157                        ARGR(angles).absolute = 1;
1158                        ARGR(angles).pan  = pdev->pan_angle;
1159                        ARGR(angles).tilt = pdev->tilt_angle;
1160                        ARG_OUT(angles)
1161                }
1162                else
1163                {
1164                        ret = -ENXIO;
1165                }
1166                break;
1167        }
1168
1169        case VIDIOCPWCMPTSTATUS:
1170        {
1171                if (pdev->features & FEATURE_MOTOR_PANTILT)
1172                {
1173                        ARG_DEF(struct pwc_mpt_status, status)
1174
1175                        ret = pwc_mpt_get_status(pdev, ARGA(status));
1176                        ARG_OUT(status)
1177                }
1178                else
1179                {
1180                        ret = -ENXIO;
1181                }
1182                break;
1183        }
1184
1185        case VIDIOCPWCGVIDCMD:
1186        {
1187                ARG_DEF(struct pwc_video_command, vcmd);
1188
1189                ARGR(vcmd).type = pdev->type;
1190                ARGR(vcmd).release = pdev->release;
1191                ARGR(vcmd).command_len = pdev->cmd_len;
1192                memcpy(&ARGR(vcmd).command_buf, pdev->cmd_buf, pdev->cmd_len);
1193                ARGR(vcmd).bandlength = pdev->vbandlength;
1194                ARGR(vcmd).frame_size = pdev->frame_size;
1195                ARG_OUT(vcmd)
1196                break;
1197        }
1198        /*
1199        case VIDIOCPWCGVIDTABLE:
1200        {
1201                ARG_DEF(struct pwc_table_init_buffer, table);
1202                ARGR(table).len = pdev->cmd_len;
1203                memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size);
1204                ARG_OUT(table)
1205                break;
1206        }
1207        */
1208
1209        default:
1210                ret = -ENOIOCTLCMD;
1211                break;
1212        }
1213
1214        if (ret > 0)
1215                return 0;
1216        return ret;
1217}
1218
1219
1220/* vim: set cinoptions= formatoptions=croql cindent shiftwidth=8 tabstop=8: */
1221