linux/drivers/media/video/gspca/sunplus.c
<<
>>
Prefs
   1/*
   2 *              Sunplus spca504(abc) spca533 spca536 library
   3 *              Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
   4 *
   5 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  20 */
  21
  22#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  23
  24#define MODULE_NAME "sunplus"
  25
  26#include "gspca.h"
  27#include "jpeg.h"
  28
  29MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
  30MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver");
  31MODULE_LICENSE("GPL");
  32
  33/* specific webcam descriptor */
  34struct sd {
  35        struct gspca_dev gspca_dev;     /* !! must be the first item */
  36
  37        s8 brightness;
  38        u8 contrast;
  39        u8 colors;
  40        u8 autogain;
  41        u8 quality;
  42#define QUALITY_MIN 70
  43#define QUALITY_MAX 95
  44#define QUALITY_DEF 85
  45
  46        u8 bridge;
  47#define BRIDGE_SPCA504 0
  48#define BRIDGE_SPCA504B 1
  49#define BRIDGE_SPCA504C 2
  50#define BRIDGE_SPCA533 3
  51#define BRIDGE_SPCA536 4
  52        u8 subtype;
  53#define AiptekMiniPenCam13 1
  54#define LogitechClickSmart420 2
  55#define LogitechClickSmart820 3
  56#define MegapixV4 4
  57#define MegaImageVI 5
  58
  59        u8 jpeg_hdr[JPEG_HDR_SZ];
  60};
  61
  62/* V4L2 controls supported by the driver */
  63static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
  64static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
  65static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
  66static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
  67static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
  68static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
  69static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
  70static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
  71
  72static const struct ctrl sd_ctrls[] = {
  73        {
  74            {
  75                .id      = V4L2_CID_BRIGHTNESS,
  76                .type    = V4L2_CTRL_TYPE_INTEGER,
  77                .name    = "Brightness",
  78                .minimum = -128,
  79                .maximum = 127,
  80                .step    = 1,
  81#define BRIGHTNESS_DEF 0
  82                .default_value = BRIGHTNESS_DEF,
  83            },
  84            .set = sd_setbrightness,
  85            .get = sd_getbrightness,
  86        },
  87        {
  88            {
  89                .id      = V4L2_CID_CONTRAST,
  90                .type    = V4L2_CTRL_TYPE_INTEGER,
  91                .name    = "Contrast",
  92                .minimum = 0,
  93                .maximum = 0xff,
  94                .step    = 1,
  95#define CONTRAST_DEF 0x20
  96                .default_value = CONTRAST_DEF,
  97            },
  98            .set = sd_setcontrast,
  99            .get = sd_getcontrast,
 100        },
 101        {
 102            {
 103                .id      = V4L2_CID_SATURATION,
 104                .type    = V4L2_CTRL_TYPE_INTEGER,
 105                .name    = "Color",
 106                .minimum = 0,
 107                .maximum = 0xff,
 108                .step    = 1,
 109#define COLOR_DEF 0x1a
 110                .default_value = COLOR_DEF,
 111            },
 112            .set = sd_setcolors,
 113            .get = sd_getcolors,
 114        },
 115        {
 116            {
 117                .id      = V4L2_CID_AUTOGAIN,
 118                .type    = V4L2_CTRL_TYPE_BOOLEAN,
 119                .name    = "Auto Gain",
 120                .minimum = 0,
 121                .maximum = 1,
 122                .step    = 1,
 123#define AUTOGAIN_DEF 1
 124                .default_value = AUTOGAIN_DEF,
 125            },
 126            .set = sd_setautogain,
 127            .get = sd_getautogain,
 128        },
 129};
 130
 131static const struct v4l2_pix_format vga_mode[] = {
 132        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 133                .bytesperline = 320,
 134                .sizeimage = 320 * 240 * 3 / 8 + 590,
 135                .colorspace = V4L2_COLORSPACE_JPEG,
 136                .priv = 2},
 137        {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 138                .bytesperline = 640,
 139                .sizeimage = 640 * 480 * 3 / 8 + 590,
 140                .colorspace = V4L2_COLORSPACE_JPEG,
 141                .priv = 1},
 142};
 143
 144static const struct v4l2_pix_format custom_mode[] = {
 145        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 146                .bytesperline = 320,
 147                .sizeimage = 320 * 240 * 3 / 8 + 590,
 148                .colorspace = V4L2_COLORSPACE_JPEG,
 149                .priv = 2},
 150        {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 151                .bytesperline = 464,
 152                .sizeimage = 464 * 480 * 3 / 8 + 590,
 153                .colorspace = V4L2_COLORSPACE_JPEG,
 154                .priv = 1},
 155};
 156
 157static const struct v4l2_pix_format vga_mode2[] = {
 158        {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 159                .bytesperline = 176,
 160                .sizeimage = 176 * 144 * 3 / 8 + 590,
 161                .colorspace = V4L2_COLORSPACE_JPEG,
 162                .priv = 4},
 163        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 164                .bytesperline = 320,
 165                .sizeimage = 320 * 240 * 3 / 8 + 590,
 166                .colorspace = V4L2_COLORSPACE_JPEG,
 167                .priv = 3},
 168        {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 169                .bytesperline = 352,
 170                .sizeimage = 352 * 288 * 3 / 8 + 590,
 171                .colorspace = V4L2_COLORSPACE_JPEG,
 172                .priv = 2},
 173        {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
 174                .bytesperline = 640,
 175                .sizeimage = 640 * 480 * 3 / 8 + 590,
 176                .colorspace = V4L2_COLORSPACE_JPEG,
 177                .priv = 1},
 178};
 179
 180#define SPCA50X_OFFSET_DATA 10
 181#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
 182#define SPCA504_PCCAM600_OFFSET_COMPRESS 4
 183#define SPCA504_PCCAM600_OFFSET_MODE     5
 184#define SPCA504_PCCAM600_OFFSET_DATA     14
 185 /* Frame packet header offsets for the spca533 */
 186#define SPCA533_OFFSET_DATA     16
 187#define SPCA533_OFFSET_FRAMSEQ  15
 188/* Frame packet header offsets for the spca536 */
 189#define SPCA536_OFFSET_DATA     4
 190#define SPCA536_OFFSET_FRAMSEQ  1
 191
 192struct cmd {
 193        u8 req;
 194        u16 val;
 195        u16 idx;
 196};
 197
 198/* Initialisation data for the Creative PC-CAM 600 */
 199static const struct cmd spca504_pccam600_init_data[] = {
 200/*      {0xa0, 0x0000, 0x0503},  * capture mode */
 201        {0x00, 0x0000, 0x2000},
 202        {0x00, 0x0013, 0x2301},
 203        {0x00, 0x0003, 0x2000},
 204        {0x00, 0x0001, 0x21ac},
 205        {0x00, 0x0001, 0x21a6},
 206        {0x00, 0x0000, 0x21a7}, /* brightness */
 207        {0x00, 0x0020, 0x21a8}, /* contrast */
 208        {0x00, 0x0001, 0x21ac}, /* sat/hue */
 209        {0x00, 0x0000, 0x21ad}, /* hue */
 210        {0x00, 0x001a, 0x21ae}, /* saturation */
 211        {0x00, 0x0002, 0x21a3}, /* gamma */
 212        {0x30, 0x0154, 0x0008},
 213        {0x30, 0x0004, 0x0006},
 214        {0x30, 0x0258, 0x0009},
 215        {0x30, 0x0004, 0x0000},
 216        {0x30, 0x0093, 0x0004},
 217        {0x30, 0x0066, 0x0005},
 218        {0x00, 0x0000, 0x2000},
 219        {0x00, 0x0013, 0x2301},
 220        {0x00, 0x0003, 0x2000},
 221        {0x00, 0x0013, 0x2301},
 222        {0x00, 0x0003, 0x2000},
 223};
 224
 225/* Creative PC-CAM 600 specific open data, sent before using the
 226 * generic initialisation data from spca504_open_data.
 227 */
 228static const struct cmd spca504_pccam600_open_data[] = {
 229        {0x00, 0x0001, 0x2501},
 230        {0x20, 0x0500, 0x0001}, /* snapshot mode */
 231        {0x00, 0x0003, 0x2880},
 232        {0x00, 0x0001, 0x2881},
 233};
 234
 235/* Initialisation data for the logitech clicksmart 420 */
 236static const struct cmd spca504A_clicksmart420_init_data[] = {
 237/*      {0xa0, 0x0000, 0x0503},  * capture mode */
 238        {0x00, 0x0000, 0x2000},
 239        {0x00, 0x0013, 0x2301},
 240        {0x00, 0x0003, 0x2000},
 241        {0x00, 0x0001, 0x21ac},
 242        {0x00, 0x0001, 0x21a6},
 243        {0x00, 0x0000, 0x21a7}, /* brightness */
 244        {0x00, 0x0020, 0x21a8}, /* contrast */
 245        {0x00, 0x0001, 0x21ac}, /* sat/hue */
 246        {0x00, 0x0000, 0x21ad}, /* hue */
 247        {0x00, 0x001a, 0x21ae}, /* saturation */
 248        {0x00, 0x0002, 0x21a3}, /* gamma */
 249        {0x30, 0x0004, 0x000a},
 250        {0xb0, 0x0001, 0x0000},
 251
 252        {0xa1, 0x0080, 0x0001},
 253        {0x30, 0x0049, 0x0000},
 254        {0x30, 0x0060, 0x0005},
 255        {0x0c, 0x0004, 0x0000},
 256        {0x00, 0x0000, 0x0000},
 257        {0x00, 0x0000, 0x2000},
 258        {0x00, 0x0013, 0x2301},
 259        {0x00, 0x0003, 0x2000},
 260};
 261
 262/* clicksmart 420 open data ? */
 263static const struct cmd spca504A_clicksmart420_open_data[] = {
 264        {0x00, 0x0001, 0x2501},
 265        {0x20, 0x0502, 0x0000},
 266        {0x06, 0x0000, 0x0000},
 267        {0x00, 0x0004, 0x2880},
 268        {0x00, 0x0001, 0x2881},
 269
 270        {0xa0, 0x0000, 0x0503},
 271};
 272
 273static const u8 qtable_creative_pccam[2][64] = {
 274        {                               /* Q-table Y-components */
 275         0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
 276         0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
 277         0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
 278         0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
 279         0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
 280         0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
 281         0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
 282         0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
 283        {                               /* Q-table C-components */
 284         0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
 285         0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
 286         0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
 287         0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
 288         0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
 289         0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
 290         0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
 291         0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
 292};
 293
 294/* FIXME: This Q-table is identical to the Creative PC-CAM one,
 295 *              except for one byte. Possibly a typo?
 296 *              NWG: 18/05/2003.
 297 */
 298static const u8 qtable_spca504_default[2][64] = {
 299        {                               /* Q-table Y-components */
 300         0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
 301         0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
 302         0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
 303         0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
 304         0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
 305         0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
 306         0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
 307         0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
 308         },
 309        {                               /* Q-table C-components */
 310         0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
 311         0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
 312         0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
 313         0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
 314         0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
 315         0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
 316         0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
 317         0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
 318};
 319
 320/* read <len> bytes to gspca_dev->usb_buf */
 321static void reg_r(struct gspca_dev *gspca_dev,
 322                  u8 req,
 323                  u16 index,
 324                  u16 len)
 325{
 326        int ret;
 327
 328#ifdef GSPCA_DEBUG
 329        if (len > USB_BUF_SZ) {
 330                pr_err("reg_r: buffer overflow\n");
 331                return;
 332        }
 333#endif
 334        if (gspca_dev->usb_err < 0)
 335                return;
 336        ret = usb_control_msg(gspca_dev->dev,
 337                        usb_rcvctrlpipe(gspca_dev->dev, 0),
 338                        req,
 339                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 340                        0,              /* value */
 341                        index,
 342                        len ? gspca_dev->usb_buf : NULL, len,
 343                        500);
 344        if (ret < 0) {
 345                pr_err("reg_r err %d\n", ret);
 346                gspca_dev->usb_err = ret;
 347        }
 348}
 349
 350/* write one byte */
 351static void reg_w_1(struct gspca_dev *gspca_dev,
 352                   u8 req,
 353                   u16 value,
 354                   u16 index,
 355                   u16 byte)
 356{
 357        int ret;
 358
 359        if (gspca_dev->usb_err < 0)
 360                return;
 361        gspca_dev->usb_buf[0] = byte;
 362        ret = usb_control_msg(gspca_dev->dev,
 363                        usb_sndctrlpipe(gspca_dev->dev, 0),
 364                        req,
 365                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 366                        value, index,
 367                        gspca_dev->usb_buf, 1,
 368                        500);
 369        if (ret < 0) {
 370                pr_err("reg_w_1 err %d\n", ret);
 371                gspca_dev->usb_err = ret;
 372        }
 373}
 374
 375/* write req / index / value */
 376static void reg_w_riv(struct gspca_dev *gspca_dev,
 377                     u8 req, u16 index, u16 value)
 378{
 379        struct usb_device *dev = gspca_dev->dev;
 380        int ret;
 381
 382        if (gspca_dev->usb_err < 0)
 383                return;
 384        ret = usb_control_msg(dev,
 385                        usb_sndctrlpipe(dev, 0),
 386                        req,
 387                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 388                        value, index, NULL, 0, 500);
 389        if (ret < 0) {
 390                pr_err("reg_w_riv err %d\n", ret);
 391                gspca_dev->usb_err = ret;
 392                return;
 393        }
 394        PDEBUG(D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x",
 395                req, index, value);
 396}
 397
 398static void write_vector(struct gspca_dev *gspca_dev,
 399                        const struct cmd *data, int ncmds)
 400{
 401        while (--ncmds >= 0) {
 402                reg_w_riv(gspca_dev, data->req, data->idx, data->val);
 403                data++;
 404        }
 405}
 406
 407static void setup_qtable(struct gspca_dev *gspca_dev,
 408                        const u8 qtable[2][64])
 409{
 410        int i;
 411
 412        /* loop over y components */
 413        for (i = 0; i < 64; i++)
 414                reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
 415
 416        /* loop over c components */
 417        for (i = 0; i < 64; i++)
 418                reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]);
 419}
 420
 421static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
 422                             u8 req, u16 idx, u16 val)
 423{
 424        reg_w_riv(gspca_dev, req, idx, val);
 425        reg_r(gspca_dev, 0x01, 0x0001, 1);
 426        PDEBUG(D_FRAM, "before wait 0x%04x", gspca_dev->usb_buf[0]);
 427        reg_w_riv(gspca_dev, req, idx, val);
 428
 429        msleep(200);
 430        reg_r(gspca_dev, 0x01, 0x0001, 1);
 431        PDEBUG(D_FRAM, "after wait 0x%04x", gspca_dev->usb_buf[0]);
 432}
 433
 434#ifdef GSPCA_DEBUG
 435static void spca504_read_info(struct gspca_dev *gspca_dev)
 436{
 437        int i;
 438        u8 info[6];
 439
 440        for (i = 0; i < 6; i++) {
 441                reg_r(gspca_dev, 0, i, 1);
 442                info[i] = gspca_dev->usb_buf[0];
 443        }
 444        PDEBUG(D_STREAM,
 445                "Read info: %d %d %d %d %d %d."
 446                " Should be 1,0,2,2,0,0",
 447                info[0], info[1], info[2],
 448                info[3], info[4], info[5]);
 449}
 450#endif
 451
 452static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
 453                        u8 req,
 454                        u16 idx, u16 val, u8 endcode, u8 count)
 455{
 456        u16 status;
 457
 458        reg_w_riv(gspca_dev, req, idx, val);
 459        reg_r(gspca_dev, 0x01, 0x0001, 1);
 460        if (gspca_dev->usb_err < 0)
 461                return;
 462        PDEBUG(D_FRAM, "Status 0x%02x Need 0x%02x",
 463                        gspca_dev->usb_buf[0], endcode);
 464        if (!count)
 465                return;
 466        count = 200;
 467        while (--count > 0) {
 468                msleep(10);
 469                /* gsmart mini2 write a each wait setting 1 ms is enough */
 470/*              reg_w_riv(gspca_dev, req, idx, val); */
 471                reg_r(gspca_dev, 0x01, 0x0001, 1);
 472                status = gspca_dev->usb_buf[0];
 473                if (status == endcode) {
 474                        PDEBUG(D_FRAM, "status 0x%04x after wait %d",
 475                                status, 200 - count);
 476                                break;
 477                }
 478        }
 479}
 480
 481static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
 482{
 483        int count = 10;
 484
 485        while (--count > 0) {
 486                reg_r(gspca_dev, 0x21, 0, 1);
 487                if ((gspca_dev->usb_buf[0] & 0x01) == 0)
 488                        break;
 489                msleep(10);
 490        }
 491}
 492
 493static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
 494{
 495        int count = 50;
 496
 497        while (--count > 0) {
 498                reg_r(gspca_dev, 0x21, 1, 1);
 499                if (gspca_dev->usb_buf[0] != 0) {
 500                        reg_w_1(gspca_dev, 0x21, 0, 1, 0);
 501                        reg_r(gspca_dev, 0x21, 1, 1);
 502                        spca504B_PollingDataReady(gspca_dev);
 503                        break;
 504                }
 505                msleep(10);
 506        }
 507}
 508
 509#ifdef GSPCA_DEBUG
 510static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
 511{
 512        u8 *data;
 513
 514        data = gspca_dev->usb_buf;
 515        reg_r(gspca_dev, 0x20, 0, 5);
 516        PDEBUG(D_STREAM, "FirmWare: %d %d %d %d %d",
 517                data[0], data[1], data[2], data[3], data[4]);
 518        reg_r(gspca_dev, 0x23, 0, 64);
 519        reg_r(gspca_dev, 0x23, 1, 64);
 520}
 521#endif
 522
 523static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
 524{
 525        struct sd *sd = (struct sd *) gspca_dev;
 526        u8 Size;
 527
 528        Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
 529        switch (sd->bridge) {
 530        case BRIDGE_SPCA533:
 531                reg_w_riv(gspca_dev, 0x31, 0, 0);
 532                spca504B_WaitCmdStatus(gspca_dev);
 533                spca504B_PollingDataReady(gspca_dev);
 534#ifdef GSPCA_DEBUG
 535                spca50x_GetFirmware(gspca_dev);
 536#endif
 537                reg_w_1(gspca_dev, 0x24, 0, 8, 2);              /* type */
 538                reg_r(gspca_dev, 0x24, 8, 1);
 539
 540                reg_w_1(gspca_dev, 0x25, 0, 4, Size);
 541                reg_r(gspca_dev, 0x25, 4, 1);                   /* size */
 542                spca504B_PollingDataReady(gspca_dev);
 543
 544                /* Init the cam width height with some values get on init ? */
 545                reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
 546                spca504B_WaitCmdStatus(gspca_dev);
 547                spca504B_PollingDataReady(gspca_dev);
 548                break;
 549        default:
 550/* case BRIDGE_SPCA504B: */
 551/* case BRIDGE_SPCA536: */
 552                reg_w_1(gspca_dev, 0x25, 0, 4, Size);
 553                reg_r(gspca_dev, 0x25, 4, 1);                   /* size */
 554                reg_w_1(gspca_dev, 0x27, 0, 0, 6);
 555                reg_r(gspca_dev, 0x27, 0, 1);                   /* type */
 556                spca504B_PollingDataReady(gspca_dev);
 557                break;
 558        case BRIDGE_SPCA504:
 559                Size += 3;
 560                if (sd->subtype == AiptekMiniPenCam13) {
 561                        /* spca504a aiptek */
 562                        spca504A_acknowledged_command(gspca_dev,
 563                                                0x08, Size, 0,
 564                                                0x80 | (Size & 0x0f), 1);
 565                        spca504A_acknowledged_command(gspca_dev,
 566                                                        1, 3, 0, 0x9f, 0);
 567                } else {
 568                        spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
 569                }
 570                break;
 571        case BRIDGE_SPCA504C:
 572                /* capture mode */
 573                reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
 574                reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
 575                break;
 576        }
 577}
 578
 579static void spca504_wait_status(struct gspca_dev *gspca_dev)
 580{
 581        int cnt;
 582
 583        cnt = 256;
 584        while (--cnt > 0) {
 585                /* With this we get the status, when return 0 it's all ok */
 586                reg_r(gspca_dev, 0x06, 0x00, 1);
 587                if (gspca_dev->usb_buf[0] == 0)
 588                        return;
 589                msleep(10);
 590        }
 591}
 592
 593static void spca504B_setQtable(struct gspca_dev *gspca_dev)
 594{
 595        reg_w_1(gspca_dev, 0x26, 0, 0, 3);
 596        reg_r(gspca_dev, 0x26, 0, 1);
 597        spca504B_PollingDataReady(gspca_dev);
 598}
 599
 600static void setbrightness(struct gspca_dev *gspca_dev)
 601{
 602        struct sd *sd = (struct sd *) gspca_dev;
 603        u16 reg;
 604
 605        reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
 606        reg_w_riv(gspca_dev, 0x00, reg, sd->brightness);
 607}
 608
 609static void setcontrast(struct gspca_dev *gspca_dev)
 610{
 611        struct sd *sd = (struct sd *) gspca_dev;
 612        u16 reg;
 613
 614        reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
 615        reg_w_riv(gspca_dev, 0x00, reg, sd->contrast);
 616}
 617
 618static void setcolors(struct gspca_dev *gspca_dev)
 619{
 620        struct sd *sd = (struct sd *) gspca_dev;
 621        u16 reg;
 622
 623        reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
 624        reg_w_riv(gspca_dev, 0x00, reg, sd->colors);
 625}
 626
 627static void init_ctl_reg(struct gspca_dev *gspca_dev)
 628{
 629        struct sd *sd = (struct sd *) gspca_dev;
 630        int pollreg = 1;
 631
 632        setbrightness(gspca_dev);
 633        setcontrast(gspca_dev);
 634        setcolors(gspca_dev);
 635
 636        switch (sd->bridge) {
 637        case BRIDGE_SPCA504:
 638        case BRIDGE_SPCA504C:
 639                pollreg = 0;
 640                /* fall thru */
 641        default:
 642/*      case BRIDGE_SPCA533: */
 643/*      case BRIDGE_SPCA504B: */
 644                reg_w_riv(gspca_dev, 0, 0x21ad, 0x00);  /* hue */
 645                reg_w_riv(gspca_dev, 0, 0x21ac, 0x01);  /* sat/hue */
 646                reg_w_riv(gspca_dev, 0, 0x21a3, 0x00);  /* gamma */
 647                break;
 648        case BRIDGE_SPCA536:
 649                reg_w_riv(gspca_dev, 0, 0x20f5, 0x40);
 650                reg_w_riv(gspca_dev, 0, 0x20f4, 0x01);
 651                reg_w_riv(gspca_dev, 0, 0x2089, 0x00);
 652                break;
 653        }
 654        if (pollreg)
 655                spca504B_PollingDataReady(gspca_dev);
 656}
 657
 658/* this function is called at probe time */
 659static int sd_config(struct gspca_dev *gspca_dev,
 660                        const struct usb_device_id *id)
 661{
 662        struct sd *sd = (struct sd *) gspca_dev;
 663        struct cam *cam;
 664
 665        cam = &gspca_dev->cam;
 666
 667        sd->bridge = id->driver_info >> 8;
 668        sd->subtype = id->driver_info;
 669
 670        if (sd->subtype == AiptekMiniPenCam13) {
 671
 672                /* try to get the firmware as some cam answer 2.0.1.2.2
 673                 * and should be a spca504b then overwrite that setting */
 674                reg_r(gspca_dev, 0x20, 0, 1);
 675                switch (gspca_dev->usb_buf[0]) {
 676                case 1:
 677                        break;          /* (right bridge/subtype) */
 678                case 2:
 679                        sd->bridge = BRIDGE_SPCA504B;
 680                        sd->subtype = 0;
 681                        break;
 682                default:
 683                        return -ENODEV;
 684                }
 685        }
 686
 687        switch (sd->bridge) {
 688        default:
 689/*      case BRIDGE_SPCA504B: */
 690/*      case BRIDGE_SPCA504: */
 691/*      case BRIDGE_SPCA536: */
 692                cam->cam_mode = vga_mode;
 693                cam->nmodes = ARRAY_SIZE(vga_mode);
 694                break;
 695        case BRIDGE_SPCA533:
 696                cam->cam_mode = custom_mode;
 697                if (sd->subtype == MegaImageVI)         /* 320x240 only */
 698                        cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
 699                else
 700                        cam->nmodes = ARRAY_SIZE(custom_mode);
 701                break;
 702        case BRIDGE_SPCA504C:
 703                cam->cam_mode = vga_mode2;
 704                cam->nmodes = ARRAY_SIZE(vga_mode2);
 705                break;
 706        }
 707        sd->brightness = BRIGHTNESS_DEF;
 708        sd->contrast = CONTRAST_DEF;
 709        sd->colors = COLOR_DEF;
 710        sd->autogain = AUTOGAIN_DEF;
 711        sd->quality = QUALITY_DEF;
 712        return 0;
 713}
 714
 715/* this function is called at probe and resume time */
 716static int sd_init(struct gspca_dev *gspca_dev)
 717{
 718        struct sd *sd = (struct sd *) gspca_dev;
 719
 720        switch (sd->bridge) {
 721        case BRIDGE_SPCA504B:
 722                reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
 723                reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01);
 724                reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00);
 725                reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00);
 726                reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13);
 727                reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00);
 728                /* fall thru */
 729        case BRIDGE_SPCA533:
 730                spca504B_PollingDataReady(gspca_dev);
 731#ifdef GSPCA_DEBUG
 732                spca50x_GetFirmware(gspca_dev);
 733#endif
 734                break;
 735        case BRIDGE_SPCA536:
 736#ifdef GSPCA_DEBUG
 737                spca50x_GetFirmware(gspca_dev);
 738#endif
 739                reg_r(gspca_dev, 0x00, 0x5002, 1);
 740                reg_w_1(gspca_dev, 0x24, 0, 0, 0);
 741                reg_r(gspca_dev, 0x24, 0, 1);
 742                spca504B_PollingDataReady(gspca_dev);
 743                reg_w_riv(gspca_dev, 0x34, 0, 0);
 744                spca504B_WaitCmdStatus(gspca_dev);
 745                break;
 746        case BRIDGE_SPCA504C:   /* pccam600 */
 747                PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
 748                reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000);
 749                reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001);     /* reset */
 750                spca504_wait_status(gspca_dev);
 751                if (sd->subtype == LogitechClickSmart420)
 752                        write_vector(gspca_dev,
 753                                spca504A_clicksmart420_open_data,
 754                                ARRAY_SIZE(spca504A_clicksmart420_open_data));
 755                else
 756                        write_vector(gspca_dev, spca504_pccam600_open_data,
 757                                ARRAY_SIZE(spca504_pccam600_open_data));
 758                setup_qtable(gspca_dev, qtable_creative_pccam);
 759                break;
 760        default:
 761/*      case BRIDGE_SPCA504: */
 762                PDEBUG(D_STREAM, "Opening SPCA504");
 763                if (sd->subtype == AiptekMiniPenCam13) {
 764#ifdef GSPCA_DEBUG
 765                        spca504_read_info(gspca_dev);
 766#endif
 767
 768                        /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
 769                        spca504A_acknowledged_command(gspca_dev, 0x24,
 770                                                        8, 3, 0x9e, 1);
 771                        /* Twice sequential need status 0xff->0x9e->0x9d */
 772                        spca504A_acknowledged_command(gspca_dev, 0x24,
 773                                                        8, 3, 0x9e, 0);
 774
 775                        spca504A_acknowledged_command(gspca_dev, 0x24,
 776                                                        0, 0, 0x9d, 1);
 777                        /******************************/
 778                        /* spca504a aiptek */
 779                        spca504A_acknowledged_command(gspca_dev, 0x08,
 780                                                        6, 0, 0x86, 1);
 781/*                      reg_write (dev, 0, 0x2000, 0); */
 782/*                      reg_write (dev, 0, 0x2883, 1); */
 783/*                      spca504A_acknowledged_command (gspca_dev, 0x08,
 784                                                        6, 0, 0x86, 1); */
 785/*                      spca504A_acknowledged_command (gspca_dev, 0x24,
 786                                                        0, 0, 0x9D, 1); */
 787                        reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
 788                                                        /* L92 sno1t.txt */
 789                        reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
 790                        spca504A_acknowledged_command(gspca_dev, 0x01,
 791                                                        0x0f, 0, 0xff, 0);
 792                }
 793                /* setup qtable */
 794                reg_w_riv(gspca_dev, 0, 0x2000, 0);
 795                reg_w_riv(gspca_dev, 0, 0x2883, 1);
 796                setup_qtable(gspca_dev, qtable_spca504_default);
 797                break;
 798        }
 799        return gspca_dev->usb_err;
 800}
 801
 802static int sd_start(struct gspca_dev *gspca_dev)
 803{
 804        struct sd *sd = (struct sd *) gspca_dev;
 805        int enable;
 806
 807        /* create the JPEG header */
 808        jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
 809                        0x22);          /* JPEG 411 */
 810        jpeg_set_qual(sd->jpeg_hdr, sd->quality);
 811
 812        if (sd->bridge == BRIDGE_SPCA504B)
 813                spca504B_setQtable(gspca_dev);
 814        spca504B_SetSizeType(gspca_dev);
 815        switch (sd->bridge) {
 816        default:
 817/*      case BRIDGE_SPCA504B: */
 818/*      case BRIDGE_SPCA533: */
 819/*      case BRIDGE_SPCA536: */
 820                switch (sd->subtype) {
 821                case MegapixV4:
 822                case LogitechClickSmart820:
 823                case MegaImageVI:
 824                        reg_w_riv(gspca_dev, 0xf0, 0, 0);
 825                        spca504B_WaitCmdStatus(gspca_dev);
 826                        reg_r(gspca_dev, 0xf0, 4, 0);
 827                        spca504B_WaitCmdStatus(gspca_dev);
 828                        break;
 829                default:
 830                        reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
 831                        spca504B_WaitCmdStatus(gspca_dev);
 832                        spca504B_PollingDataReady(gspca_dev);
 833                        break;
 834                }
 835                break;
 836        case BRIDGE_SPCA504:
 837                if (sd->subtype == AiptekMiniPenCam13) {
 838#ifdef GSPCA_DEBUG
 839                        spca504_read_info(gspca_dev);
 840#endif
 841
 842                        /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
 843                        spca504A_acknowledged_command(gspca_dev, 0x24,
 844                                                        8, 3, 0x9e, 1);
 845                        /* Twice sequential need status 0xff->0x9e->0x9d */
 846                        spca504A_acknowledged_command(gspca_dev, 0x24,
 847                                                        8, 3, 0x9e, 0);
 848                        spca504A_acknowledged_command(gspca_dev, 0x24,
 849                                                        0, 0, 0x9d, 1);
 850                } else {
 851                        spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
 852#ifdef GSPCA_DEBUG
 853                        spca504_read_info(gspca_dev);
 854#endif
 855                        spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
 856                        spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
 857                }
 858                spca504B_SetSizeType(gspca_dev);
 859                reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
 860                                                        /* L92 sno1t.txt */
 861                reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
 862                break;
 863        case BRIDGE_SPCA504C:
 864                if (sd->subtype == LogitechClickSmart420) {
 865                        write_vector(gspca_dev,
 866                                spca504A_clicksmart420_init_data,
 867                                ARRAY_SIZE(spca504A_clicksmart420_init_data));
 868                } else {
 869                        write_vector(gspca_dev, spca504_pccam600_init_data,
 870                                ARRAY_SIZE(spca504_pccam600_init_data));
 871                }
 872                enable = (sd->autogain ? 0x04 : 0x01);
 873                reg_w_riv(gspca_dev, 0x0c, 0x0000, enable);
 874                                                        /* auto exposure */
 875                reg_w_riv(gspca_dev, 0xb0, 0x0000, enable);
 876                                                        /* auto whiteness */
 877
 878                /* set default exposure compensation and whiteness balance */
 879                reg_w_riv(gspca_dev, 0x30, 0x0001, 800);        /* ~ 20 fps */
 880                reg_w_riv(gspca_dev, 0x30, 0x0002, 1600);
 881                spca504B_SetSizeType(gspca_dev);
 882                break;
 883        }
 884        init_ctl_reg(gspca_dev);
 885        return gspca_dev->usb_err;
 886}
 887
 888static void sd_stopN(struct gspca_dev *gspca_dev)
 889{
 890        struct sd *sd = (struct sd *) gspca_dev;
 891
 892        switch (sd->bridge) {
 893        default:
 894/*      case BRIDGE_SPCA533: */
 895/*      case BRIDGE_SPCA536: */
 896/*      case BRIDGE_SPCA504B: */
 897                reg_w_riv(gspca_dev, 0x31, 0, 0);
 898                spca504B_WaitCmdStatus(gspca_dev);
 899                spca504B_PollingDataReady(gspca_dev);
 900                break;
 901        case BRIDGE_SPCA504:
 902        case BRIDGE_SPCA504C:
 903                reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000);
 904
 905                if (sd->subtype == AiptekMiniPenCam13) {
 906                        /* spca504a aiptek */
 907/*                      spca504A_acknowledged_command(gspca_dev, 0x08,
 908                                                         6, 0, 0x86, 1); */
 909                        spca504A_acknowledged_command(gspca_dev, 0x24,
 910                                                        0x00, 0x00, 0x9d, 1);
 911                        spca504A_acknowledged_command(gspca_dev, 0x01,
 912                                                        0x0f, 0x00, 0xff, 1);
 913                } else {
 914                        spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
 915                        reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000);
 916                }
 917                break;
 918        }
 919}
 920
 921static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 922                        u8 *data,                       /* isoc packet */
 923                        int len)                        /* iso packet length */
 924{
 925        struct sd *sd = (struct sd *) gspca_dev;
 926        int i, sof = 0;
 927        static u8 ffd9[] = {0xff, 0xd9};
 928
 929/* frames are jpeg 4.1.1 without 0xff escape */
 930        switch (sd->bridge) {
 931        case BRIDGE_SPCA533:
 932                if (data[0] == 0xff) {
 933                        if (data[1] != 0x01) {  /* drop packet */
 934/*                              gspca_dev->last_packet_type = DISCARD_PACKET; */
 935                                return;
 936                        }
 937                        sof = 1;
 938                        data += SPCA533_OFFSET_DATA;
 939                        len -= SPCA533_OFFSET_DATA;
 940                } else {
 941                        data += 1;
 942                        len -= 1;
 943                }
 944                break;
 945        case BRIDGE_SPCA536:
 946                if (data[0] == 0xff) {
 947                        sof = 1;
 948                        data += SPCA536_OFFSET_DATA;
 949                        len -= SPCA536_OFFSET_DATA;
 950                } else {
 951                        data += 2;
 952                        len -= 2;
 953                }
 954                break;
 955        default:
 956/*      case BRIDGE_SPCA504: */
 957/*      case BRIDGE_SPCA504B: */
 958                switch (data[0]) {
 959                case 0xfe:                      /* start of frame */
 960                        sof = 1;
 961                        data += SPCA50X_OFFSET_DATA;
 962                        len -= SPCA50X_OFFSET_DATA;
 963                        break;
 964                case 0xff:                      /* drop packet */
 965/*                      gspca_dev->last_packet_type = DISCARD_PACKET; */
 966                        return;
 967                default:
 968                        data += 1;
 969                        len -= 1;
 970                        break;
 971                }
 972                break;
 973        case BRIDGE_SPCA504C:
 974                switch (data[0]) {
 975                case 0xfe:                      /* start of frame */
 976                        sof = 1;
 977                        data += SPCA504_PCCAM600_OFFSET_DATA;
 978                        len -= SPCA504_PCCAM600_OFFSET_DATA;
 979                        break;
 980                case 0xff:                      /* drop packet */
 981/*                      gspca_dev->last_packet_type = DISCARD_PACKET; */
 982                        return;
 983                default:
 984                        data += 1;
 985                        len -= 1;
 986                        break;
 987                }
 988                break;
 989        }
 990        if (sof) {              /* start of frame */
 991                gspca_frame_add(gspca_dev, LAST_PACKET,
 992                                ffd9, 2);
 993
 994                /* put the JPEG header in the new frame */
 995                gspca_frame_add(gspca_dev, FIRST_PACKET,
 996                        sd->jpeg_hdr, JPEG_HDR_SZ);
 997        }
 998
 999        /* add 0x00 after 0xff */
1000        i = 0;
1001        do {
1002                if (data[i] == 0xff) {
1003                        gspca_frame_add(gspca_dev, INTER_PACKET,
1004                                        data, i + 1);
1005                        len -= i;
1006                        data += i;
1007                        *data = 0x00;
1008                        i = 0;
1009                }
1010                i++;
1011        } while (i < len);
1012        gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
1013}
1014
1015static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1016{
1017        struct sd *sd = (struct sd *) gspca_dev;
1018
1019        sd->brightness = val;
1020        if (gspca_dev->streaming)
1021                setbrightness(gspca_dev);
1022        return gspca_dev->usb_err;
1023}
1024
1025static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1026{
1027        struct sd *sd = (struct sd *) gspca_dev;
1028
1029        *val = sd->brightness;
1030        return 0;
1031}
1032
1033static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1034{
1035        struct sd *sd = (struct sd *) gspca_dev;
1036
1037        sd->contrast = val;
1038        if (gspca_dev->streaming)
1039                setcontrast(gspca_dev);
1040        return gspca_dev->usb_err;
1041}
1042
1043static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1044{
1045        struct sd *sd = (struct sd *) gspca_dev;
1046
1047        *val = sd->contrast;
1048        return 0;
1049}
1050
1051static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1052{
1053        struct sd *sd = (struct sd *) gspca_dev;
1054
1055        sd->colors = val;
1056        if (gspca_dev->streaming)
1057                setcolors(gspca_dev);
1058        return gspca_dev->usb_err;
1059}
1060
1061static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1062{
1063        struct sd *sd = (struct sd *) gspca_dev;
1064
1065        *val = sd->colors;
1066        return 0;
1067}
1068
1069static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1070{
1071        struct sd *sd = (struct sd *) gspca_dev;
1072
1073        sd->autogain = val;
1074        return 0;
1075}
1076
1077static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1078{
1079        struct sd *sd = (struct sd *) gspca_dev;
1080
1081        *val = sd->autogain;
1082        return 0;
1083}
1084
1085static int sd_set_jcomp(struct gspca_dev *gspca_dev,
1086                        struct v4l2_jpegcompression *jcomp)
1087{
1088        struct sd *sd = (struct sd *) gspca_dev;
1089
1090        if (jcomp->quality < QUALITY_MIN)
1091                sd->quality = QUALITY_MIN;
1092        else if (jcomp->quality > QUALITY_MAX)
1093                sd->quality = QUALITY_MAX;
1094        else
1095                sd->quality = jcomp->quality;
1096        if (gspca_dev->streaming)
1097                jpeg_set_qual(sd->jpeg_hdr, sd->quality);
1098        return gspca_dev->usb_err;
1099}
1100
1101static int sd_get_jcomp(struct gspca_dev *gspca_dev,
1102                        struct v4l2_jpegcompression *jcomp)
1103{
1104        struct sd *sd = (struct sd *) gspca_dev;
1105
1106        memset(jcomp, 0, sizeof *jcomp);
1107        jcomp->quality = sd->quality;
1108        jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
1109                        | V4L2_JPEG_MARKER_DQT;
1110        return 0;
1111}
1112
1113/* sub-driver description */
1114static const struct sd_desc sd_desc = {
1115        .name = MODULE_NAME,
1116        .ctrls = sd_ctrls,
1117        .nctrls = ARRAY_SIZE(sd_ctrls),
1118        .config = sd_config,
1119        .init = sd_init,
1120        .start = sd_start,
1121        .stopN = sd_stopN,
1122        .pkt_scan = sd_pkt_scan,
1123        .get_jcomp = sd_get_jcomp,
1124        .set_jcomp = sd_set_jcomp,
1125};
1126
1127/* -- module initialisation -- */
1128#define BS(bridge, subtype) \
1129        .driver_info = (BRIDGE_ ## bridge << 8) \
1130                        | (subtype)
1131static const struct usb_device_id device_table[] = {
1132        {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
1133        {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
1134        {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
1135        {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
1136        {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
1137        {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
1138        {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
1139        {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
1140        {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
1141        {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
1142        {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1143        {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1144        {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1145        {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1146        {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1147        {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1148        {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1149        {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
1150        {USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)},
1151        {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
1152        {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
1153        {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1154        {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1155        {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1156        {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1157        {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1158        {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1159        {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1160        {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1161        {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1162        {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1163        {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1164        {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1165        {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1166        {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1167        {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1168        {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1169        {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1170        {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1171        {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1172        {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1173        {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1174        {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1175        {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1176        {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1177        {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1178        {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1179        {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1180        {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1181        {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1182        {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1183        {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1184        {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1185        {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1186        {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1187        {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1188        {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1189        {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1190        {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
1191        {}
1192};
1193MODULE_DEVICE_TABLE(usb, device_table);
1194
1195/* -- device connect -- */
1196static int sd_probe(struct usb_interface *intf,
1197                        const struct usb_device_id *id)
1198{
1199        return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1200                                THIS_MODULE);
1201}
1202
1203static struct usb_driver sd_driver = {
1204        .name = MODULE_NAME,
1205        .id_table = device_table,
1206        .probe = sd_probe,
1207        .disconnect = gspca_disconnect,
1208#ifdef CONFIG_PM
1209        .suspend = gspca_suspend,
1210        .resume = gspca_resume,
1211#endif
1212};
1213
1214/* -- module insert / remove -- */
1215static int __init sd_mod_init(void)
1216{
1217        return usb_register(&sd_driver);
1218}
1219static void __exit sd_mod_exit(void)
1220{
1221        usb_deregister(&sd_driver);
1222}
1223
1224module_init(sd_mod_init);
1225module_exit(sd_mod_exit);
1226
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.