linux/drivers/media/usb/gspca/t613.c
<<
>>
Prefs
   1/*
   2 * T613 subdriver
   3 *
   4 * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr)
   5 *
   6 * This program is free software; you can redistribute it and/or modify
   7 * it under the terms of the GNU General Public License as published by
   8 * the Free Software Foundation; either version 2 of the License, or
   9 * any later version.
  10 *
  11 * This program is distributed in the hope that it will be useful,
  12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 * GNU General Public License for more details.
  15 *
  16 *Notes: * t613  + tas5130A
  17 *      * Focus to light do not balance well as in win.
  18 *        Quality in win is not good, but its kinda better.
  19 *       * Fix some "extraneous bytes", most of apps will show the image anyway
  20 *       * Gamma table, is there, but its really doing something?
  21 *       * 7~8 Fps, its ok, max on win its 10.
  22 *                      Costantino Leandro
  23 */
  24
  25#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  26
  27#define MODULE_NAME "t613"
  28
  29#include <linux/input.h>
  30#include <linux/slab.h>
  31#include "gspca.h"
  32
  33MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
  34MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
  35MODULE_LICENSE("GPL");
  36
  37struct sd {
  38        struct gspca_dev gspca_dev;     /* !! must be the first item */
  39        struct v4l2_ctrl *freq;
  40        struct { /* awb / color gains control cluster */
  41                struct v4l2_ctrl *awb;
  42                struct v4l2_ctrl *gain;
  43                struct v4l2_ctrl *red_balance;
  44                struct v4l2_ctrl *blue_balance;
  45        };
  46
  47        u8 sensor;
  48        u8 button_pressed;
  49};
  50enum sensors {
  51        SENSOR_OM6802,
  52        SENSOR_OTHER,
  53        SENSOR_TAS5130A,
  54        SENSOR_LT168G,          /* must verify if this is the actual model */
  55};
  56
  57static const struct v4l2_pix_format vga_mode_t16[] = {
  58        {160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
  59                .bytesperline = 160,
  60                .sizeimage = 160 * 120 * 4 / 8 + 590,
  61                .colorspace = V4L2_COLORSPACE_JPEG,
  62                .priv = 4},
  63#if 0 /* HDG: broken with my test cam, so lets disable it */
  64        {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
  65                .bytesperline = 176,
  66                .sizeimage = 176 * 144 * 3 / 8 + 590,
  67                .colorspace = V4L2_COLORSPACE_JPEG,
  68                .priv = 3},
  69#endif
  70        {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
  71                .bytesperline = 320,
  72                .sizeimage = 320 * 240 * 3 / 8 + 590,
  73                .colorspace = V4L2_COLORSPACE_JPEG,
  74                .priv = 2},
  75#if 0 /* HDG: broken with my test cam, so lets disable it */
  76        {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
  77                .bytesperline = 352,
  78                .sizeimage = 352 * 288 * 3 / 8 + 590,
  79                .colorspace = V4L2_COLORSPACE_JPEG,
  80                .priv = 1},
  81#endif
  82        {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
  83                .bytesperline = 640,
  84                .sizeimage = 640 * 480 * 3 / 8 + 590,
  85                .colorspace = V4L2_COLORSPACE_JPEG,
  86                .priv = 0},
  87};
  88
  89/* sensor specific data */
  90struct additional_sensor_data {
  91        const u8 n3[6];
  92        const u8 *n4, n4sz;
  93        const u8 reg80, reg8e;
  94        const u8 nset8[6];
  95        const u8 data1[10];
  96        const u8 data2[9];
  97        const u8 data3[9];
  98        const u8 data5[6];
  99        const u8 stream[4];
 100};
 101
 102static const u8 n4_om6802[] = {
 103        0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
 104        0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
 105        0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
 106        0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
 107        0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
 108        0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
 109        0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
 110        0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
 111        0xac, 0x84, 0xad, 0x86, 0xaf, 0x46
 112};
 113static const u8 n4_other[] = {
 114        0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,
 115        0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,
 116        0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,
 117        0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,
 118        0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,
 119        0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,
 120        0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,
 121        0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00
 122};
 123static const u8 n4_tas5130a[] = {
 124        0x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20,
 125        0x8a, 0x68, 0x8b, 0x58, 0x8c, 0x88, 0x8e, 0xb4,
 126        0x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x10,
 127        0xa6, 0x4a, 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08,
 128        0xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a,
 129        0xbe, 0x36, 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc8,
 130        0xc6, 0xda
 131};
 132static const u8 n4_lt168g[] = {
 133        0x66, 0x01, 0x7f, 0x00, 0x80, 0x7c, 0x81, 0x28,
 134        0x83, 0x44, 0x84, 0x20, 0x86, 0x20, 0x8a, 0x70,
 135        0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xa0, 0x8e, 0xb3,
 136        0x8f, 0x24, 0xa1, 0xb0, 0xa2, 0x38, 0xa5, 0x20,
 137        0xa6, 0x4a, 0xa8, 0xe8, 0xaf, 0x38, 0xb0, 0x68,
 138        0xb1, 0x44, 0xb2, 0x88, 0xbb, 0x86, 0xbd, 0x40,
 139        0xbe, 0x26, 0xc1, 0x05, 0xc2, 0x88, 0xc5, 0xc0,
 140        0xda, 0x8e, 0xdb, 0xca, 0xdc, 0xa8, 0xdd, 0x8c,
 141        0xde, 0x44, 0xdf, 0x0c, 0xe9, 0x80
 142};
 143
 144static const struct additional_sensor_data sensor_data[] = {
 145[SENSOR_OM6802] = {
 146        .n3 =
 147                {0x61, 0x68, 0x65, 0x0a, 0x60, 0x04},
 148        .n4 = n4_om6802,
 149        .n4sz = sizeof n4_om6802,
 150        .reg80 = 0x3c,
 151        .reg8e = 0x33,
 152        .nset8 = {0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00},
 153        .data1 =
 154                {0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06,
 155                 0xb3, 0xfc},
 156        .data2 =
 157                {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
 158                 0xff},
 159        .data3 =
 160                {0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
 161                 0xff},
 162        .data5 =        /* this could be removed later */
 163                {0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
 164        .stream =
 165                {0x0b, 0x04, 0x0a, 0x78},
 166    },
 167[SENSOR_OTHER] = {
 168        .n3 =
 169                {0x61, 0xc2, 0x65, 0x88, 0x60, 0x00},
 170        .n4 = n4_other,
 171        .n4sz = sizeof n4_other,
 172        .reg80 = 0xac,
 173        .reg8e = 0xb8,
 174        .nset8 = {0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00},
 175        .data1 =
 176                {0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a,
 177                 0xe8, 0xfc},
 178        .data2 =
 179                {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
 180                 0xd9},
 181        .data3 =
 182                {0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
 183                 0xd9},
 184        .data5 =
 185                {0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},
 186        .stream =
 187                {0x0b, 0x04, 0x0a, 0x00},
 188    },
 189[SENSOR_TAS5130A] = {
 190        .n3 =
 191                {0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08},
 192        .n4 = n4_tas5130a,
 193        .n4sz = sizeof n4_tas5130a,
 194        .reg80 = 0x3c,
 195        .reg8e = 0xb4,
 196        .nset8 = {0xa8, 0xf0, 0xc6, 0xda, 0xc0, 0x00},
 197        .data1 =
 198                {0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27,
 199                 0xc8, 0xfc},
 200        .data2 =
 201                {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
 202                 0xe0},
 203        .data3 =
 204                {0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
 205                 0xe0},
 206        .data5 =
 207                {0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
 208        .stream =
 209                {0x0b, 0x04, 0x0a, 0x40},
 210    },
 211[SENSOR_LT168G] = {
 212        .n3 = {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00},
 213        .n4 = n4_lt168g,
 214        .n4sz = sizeof n4_lt168g,
 215        .reg80 = 0x7c,
 216        .reg8e = 0xb3,
 217        .nset8 = {0xa8, 0xf0, 0xc6, 0xba, 0xc0, 0x00},
 218        .data1 = {0xc0, 0x38, 0x08, 0x10, 0xc0, 0x30, 0x10, 0x40,
 219                 0xb0, 0xf4},
 220        .data2 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
 221                 0xff},
 222        .data3 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
 223                 0xff},
 224        .data5 = {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b},
 225        .stream = {0x0b, 0x04, 0x0a, 0x28},
 226    },
 227};
 228
 229#define MAX_EFFECTS 7
 230static const u8 effects_table[MAX_EFFECTS][6] = {
 231        {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00},   /* Normal */
 232        {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04},   /* Repujar */
 233        {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20},   /* Monochrome */
 234        {0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80},   /* Sepia */
 235        {0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02},   /* Croquis */
 236        {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10},   /* Sun Effect */
 237        {0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40},   /* Negative */
 238};
 239
 240#define GAMMA_MAX (15)
 241static const u8 gamma_table[GAMMA_MAX+1][17] = {
 242/* gamma table from cam1690.ini */
 243        {0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21,        /* 0 */
 244         0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb,
 245         0xff},
 246        {0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d,        /* 1 */
 247         0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1,
 248         0xff},
 249        {0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35,        /* 2 */
 250         0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3,
 251         0xff},
 252        {0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f,        /* 3 */
 253         0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6,
 254         0xff},
 255        {0x00, 0x04, 0x0b, 0x15, 0x20, 0x2d, 0x3b, 0x4a,        /* 4 */
 256         0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9,
 257         0xff},
 258        {0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58,        /* 5 */
 259         0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec,
 260         0xff},
 261        {0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67,        /* 6 */
 262         0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
 263         0xff},
 264        {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,        /* 7 */
 265         0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
 266         0xff},
 267        {0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79,        /* 8 */
 268         0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0,
 269         0xff},
 270        {0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84,        /* 9 */
 271         0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2,
 272         0xff},
 273        {0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e,        /* 10 */
 274         0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3,
 275         0xff},
 276        {0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b,        /* 11 */
 277         0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
 278         0xff},
 279        {0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8,        /* 12 */
 280         0xb4, 0xbf, 0xc9, 0xd3, 0xdc, 0xe5, 0xee, 0xf6,
 281         0xff},
 282        {0x00, 0x54, 0x6f, 0x83, 0x93, 0xa0, 0xad, 0xb7,        /* 13 */
 283         0xc2, 0xcb, 0xd4, 0xdc, 0xe4, 0xeb, 0xf2, 0xf9,
 284         0xff},
 285        {0x00, 0x6e, 0x88, 0x9a, 0xa8, 0xb3, 0xbd, 0xc6,        /* 14 */
 286         0xcf, 0xd6, 0xdd, 0xe3, 0xe9, 0xef, 0xf4, 0xfa,
 287         0xff},
 288        {0x00, 0x93, 0xa8, 0xb7, 0xc1, 0xca, 0xd2, 0xd8,        /* 15 */
 289         0xde, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf8, 0xfc,
 290         0xff}
 291};
 292
 293static const u8 tas5130a_sensor_init[][8] = {
 294        {0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
 295        {0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
 296        {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
 297};
 298
 299static u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
 300
 301/* read 1 byte */
 302static u8 reg_r(struct gspca_dev *gspca_dev,
 303                   u16 index)
 304{
 305        usb_control_msg(gspca_dev->dev,
 306                        usb_rcvctrlpipe(gspca_dev->dev, 0),
 307                        0,              /* request */
 308                        USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 309                        0,              /* value */
 310                        index,
 311                        gspca_dev->usb_buf, 1, 500);
 312        return gspca_dev->usb_buf[0];
 313}
 314
 315static void reg_w(struct gspca_dev *gspca_dev,
 316                  u16 index)
 317{
 318        usb_control_msg(gspca_dev->dev,
 319                        usb_sndctrlpipe(gspca_dev->dev, 0),
 320                        0,
 321                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 322                        0, index,
 323                        NULL, 0, 500);
 324}
 325
 326static void reg_w_buf(struct gspca_dev *gspca_dev,
 327                  const u8 *buffer, u16 len)
 328{
 329        if (len <= USB_BUF_SZ) {
 330                memcpy(gspca_dev->usb_buf, buffer, len);
 331                usb_control_msg(gspca_dev->dev,
 332                                usb_sndctrlpipe(gspca_dev->dev, 0),
 333                                0,
 334                           USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 335                                0x01, 0,
 336                                gspca_dev->usb_buf, len, 500);
 337        } else {
 338                u8 *tmpbuf;
 339
 340                tmpbuf = kmemdup(buffer, len, GFP_KERNEL);
 341                if (!tmpbuf) {
 342                        pr_err("Out of memory\n");
 343                        return;
 344                }
 345                usb_control_msg(gspca_dev->dev,
 346                                usb_sndctrlpipe(gspca_dev->dev, 0),
 347                                0,
 348                           USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 349                                0x01, 0,
 350                                tmpbuf, len, 500);
 351                kfree(tmpbuf);
 352        }
 353}
 354
 355/* write values to consecutive registers */
 356static void reg_w_ixbuf(struct gspca_dev *gspca_dev,
 357                        u8 reg,
 358                        const u8 *buffer, u16 len)
 359{
 360        int i;
 361        u8 *p, *tmpbuf;
 362
 363        if (len * 2 <= USB_BUF_SZ) {
 364                p = tmpbuf = gspca_dev->usb_buf;
 365        } else {
 366                p = tmpbuf = kmalloc_array(len, 2, GFP_KERNEL);
 367                if (!tmpbuf) {
 368                        pr_err("Out of memory\n");
 369                        return;
 370                }
 371        }
 372        i = len;
 373        while (--i >= 0) {
 374                *p++ = reg++;
 375                *p++ = *buffer++;
 376        }
 377        usb_control_msg(gspca_dev->dev,
 378                        usb_sndctrlpipe(gspca_dev->dev, 0),
 379                        0,
 380                        USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
 381                        0x01, 0,
 382                        tmpbuf, len * 2, 500);
 383        if (len * 2 > USB_BUF_SZ)
 384                kfree(tmpbuf);
 385}
 386
 387static void om6802_sensor_init(struct gspca_dev *gspca_dev)
 388{
 389        int i;
 390        const u8 *p;
 391        u8 byte;
 392        u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
 393        static const u8 sensor_init[] = {
 394                0xdf, 0x6d,
 395                0xdd, 0x18,
 396                0x5a, 0xe0,
 397                0x5c, 0x07,
 398                0x5d, 0xb0,
 399                0x5e, 0x1e,
 400                0x60, 0x71,
 401                0xef, 0x00,
 402                0xe9, 0x00,
 403                0xea, 0x00,
 404                0x90, 0x24,
 405                0x91, 0xb2,
 406                0x82, 0x32,
 407                0xfd, 0x41,
 408                0x00                    /* table end */
 409        };
 410
 411        reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
 412        msleep(100);
 413        i = 4;
 414        while (--i > 0) {
 415                byte = reg_r(gspca_dev, 0x0060);
 416                if (!(byte & 0x01))
 417                        break;
 418                msleep(100);
 419        }
 420        byte = reg_r(gspca_dev, 0x0063);
 421        if (byte != 0x17) {
 422                pr_err("Bad sensor reset %02x\n", byte);
 423                /* continue? */
 424        }
 425
 426        p = sensor_init;
 427        while (*p != 0) {
 428                val[1] = *p++;
 429                val[3] = *p++;
 430                if (*p == 0)
 431                        reg_w(gspca_dev, 0x3c80);
 432                reg_w_buf(gspca_dev, val, sizeof val);
 433                i = 4;
 434                while (--i >= 0) {
 435                        msleep(15);
 436                        byte = reg_r(gspca_dev, 0x60);
 437                        if (!(byte & 0x01))
 438                                break;
 439                }
 440        }
 441        msleep(15);
 442        reg_w(gspca_dev, 0x3c80);
 443}
 444
 445/* this function is called at probe time */
 446static int sd_config(struct gspca_dev *gspca_dev,
 447                     const struct usb_device_id *id)
 448{
 449        struct cam *cam  = &gspca_dev->cam;
 450
 451        cam->cam_mode = vga_mode_t16;
 452        cam->nmodes = ARRAY_SIZE(vga_mode_t16);
 453
 454        return 0;
 455}
 456
 457static void setbrightness(struct gspca_dev *gspca_dev, s32 brightness)
 458{
 459        u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 };
 460
 461        if (brightness < 7) {
 462                set6[1] = 0x26;
 463                set6[3] = 0x70 - brightness * 0x10;
 464        } else {
 465                set6[3] = 0x00 + ((brightness - 7) * 0x10);
 466        }
 467
 468        reg_w_buf(gspca_dev, set6, sizeof set6);
 469}
 470
 471static void setcontrast(struct gspca_dev *gspca_dev, s32 contrast)
 472{
 473        u16 reg_to_write;
 474
 475        if (contrast < 7)
 476                reg_to_write = 0x8ea9 - contrast * 0x200;
 477        else
 478                reg_to_write = 0x00a9 + (contrast - 7) * 0x200;
 479
 480        reg_w(gspca_dev, reg_to_write);
 481}
 482
 483static void setcolors(struct gspca_dev *gspca_dev, s32 val)
 484{
 485        u16 reg_to_write;
 486
 487        reg_to_write = 0x80bb + val * 0x100;    /* was 0xc0 */
 488        reg_w(gspca_dev, reg_to_write);
 489}
 490
 491static void setgamma(struct gspca_dev *gspca_dev, s32 val)
 492{
 493        gspca_dbg(gspca_dev, D_CONF, "Gamma: %d\n", val);
 494        reg_w_ixbuf(gspca_dev, 0x90,
 495                gamma_table[val], sizeof gamma_table[0]);
 496}
 497
 498static void setawb_n_RGB(struct gspca_dev *gspca_dev)
 499{
 500        struct sd *sd = (struct sd *) gspca_dev;
 501        u8 all_gain_reg[8] = {
 502                0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00 };
 503        s32 red_gain, blue_gain, green_gain;
 504
 505        green_gain = sd->gain->val;
 506
 507        red_gain = green_gain + sd->red_balance->val;
 508        if (red_gain > 0x40)
 509                red_gain = 0x40;
 510        else if (red_gain < 0x10)
 511                red_gain = 0x10;
 512
 513        blue_gain = green_gain + sd->blue_balance->val;
 514        if (blue_gain > 0x40)
 515                blue_gain = 0x40;
 516        else if (blue_gain < 0x10)
 517                blue_gain = 0x10;
 518
 519        all_gain_reg[1] = red_gain;
 520        all_gain_reg[3] = blue_gain;
 521        all_gain_reg[5] = green_gain;
 522        all_gain_reg[7] = sensor_data[sd->sensor].reg80;
 523        if (!sd->awb->val)
 524                all_gain_reg[7] &= ~0x04; /* AWB off */
 525
 526        reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);
 527}
 528
 529static void setsharpness(struct gspca_dev *gspca_dev, s32 val)
 530{
 531        u16 reg_to_write;
 532
 533        reg_to_write = 0x0aa6 + 0x1000 * val;
 534
 535        reg_w(gspca_dev, reg_to_write);
 536}
 537
 538static void setfreq(struct gspca_dev *gspca_dev, s32 val)
 539{
 540        struct sd *sd = (struct sd *) gspca_dev;
 541        u8 reg66;
 542        u8 freq[4] = { 0x66, 0x00, 0xa8, 0xe8 };
 543
 544        switch (sd->sensor) {
 545        case SENSOR_LT168G:
 546                if (val != 0)
 547                        freq[3] = 0xa8;
 548                reg66 = 0x41;
 549                break;
 550        case SENSOR_OM6802:
 551                reg66 = 0xca;
 552                break;
 553        default:
 554                reg66 = 0x40;
 555                break;
 556        }
 557        switch (val) {
 558        case 0:                         /* no flicker */
 559                freq[3] = 0xf0;
 560                break;
 561        case 2:                         /* 60Hz */
 562                reg66 &= ~0x40;
 563                break;
 564        }
 565        freq[1] = reg66;
 566
 567        reg_w_buf(gspca_dev, freq, sizeof freq);
 568}
 569
 570/* this function is called at probe and resume time */
 571static int sd_init(struct gspca_dev *gspca_dev)
 572{
 573        /* some of this registers are not really needed, because
 574         * they are overridden by setbrigthness, setcontrast, etc.,
 575         * but won't hurt anyway, and can help someone with similar webcam
 576         * to see the initial parameters.*/
 577        struct sd *sd = (struct sd *) gspca_dev;
 578        const struct additional_sensor_data *sensor;
 579        int i;
 580        u16 sensor_id;
 581        u8 test_byte = 0;
 582
 583        static const u8 read_indexs[] =
 584                { 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
 585                  0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 };
 586        static const u8 n1[] =
 587                        {0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
 588        static const u8 n2[] =
 589                        {0x08, 0x00};
 590
 591        sensor_id = (reg_r(gspca_dev, 0x06) << 8)
 592                        | reg_r(gspca_dev, 0x07);
 593        switch (sensor_id & 0xff0f) {
 594        case 0x0801:
 595                gspca_dbg(gspca_dev, D_PROBE, "sensor tas5130a\n");
 596                sd->sensor = SENSOR_TAS5130A;
 597                break;
 598        case 0x0802:
 599                gspca_dbg(gspca_dev, D_PROBE, "sensor lt168g\n");
 600                sd->sensor = SENSOR_LT168G;
 601                break;
 602        case 0x0803:
 603                gspca_dbg(gspca_dev, D_PROBE, "sensor 'other'\n");
 604                sd->sensor = SENSOR_OTHER;
 605                break;
 606        case 0x0807:
 607                gspca_dbg(gspca_dev, D_PROBE, "sensor om6802\n");
 608                sd->sensor = SENSOR_OM6802;
 609                break;
 610        default:
 611                pr_err("unknown sensor %04x\n", sensor_id);
 612                return -EINVAL;
 613        }
 614
 615        if (sd->sensor == SENSOR_OM6802) {
 616                reg_w_buf(gspca_dev, n1, sizeof n1);
 617                i = 5;
 618                while (--i >= 0) {
 619                        reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
 620                        test_byte = reg_r(gspca_dev, 0x0063);
 621                        msleep(100);
 622                        if (test_byte == 0x17)
 623                                break;          /* OK */
 624                }
 625                if (i < 0) {
 626                        pr_err("Bad sensor reset %02x\n", test_byte);
 627                        return -EIO;
 628                }
 629                reg_w_buf(gspca_dev, n2, sizeof n2);
 630        }
 631
 632        i = 0;
 633        while (read_indexs[i] != 0x00) {
 634                test_byte = reg_r(gspca_dev, read_indexs[i]);
 635                gspca_dbg(gspca_dev, D_STREAM, "Reg 0x%02x = 0x%02x\n",
 636                          read_indexs[i], test_byte);
 637                i++;
 638        }
 639
 640        sensor = &sensor_data[sd->sensor];
 641        reg_w_buf(gspca_dev, sensor->n3, sizeof sensor->n3);
 642        reg_w_buf(gspca_dev, sensor->n4, sensor->n4sz);
 643
 644        if (sd->sensor == SENSOR_LT168G) {
 645                test_byte = reg_r(gspca_dev, 0x80);
 646                gspca_dbg(gspca_dev, D_STREAM, "Reg 0x%02x = 0x%02x\n", 0x80,
 647                          test_byte);
 648                reg_w(gspca_dev, 0x6c80);
 649        }
 650
 651        reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
 652        reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
 653        reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
 654
 655        reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
 656        reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
 657        reg_w(gspca_dev, (sensor->reg8e << 8) + 0x8e);
 658        reg_w(gspca_dev, (0x20 << 8) + 0x87);
 659        reg_w(gspca_dev, (0x20 << 8) + 0x88);
 660        reg_w(gspca_dev, (0x20 << 8) + 0x89);
 661
 662        reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5);
 663        reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8);
 664        reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
 665
 666        if (sd->sensor == SENSOR_LT168G) {
 667                test_byte = reg_r(gspca_dev, 0x80);
 668                gspca_dbg(gspca_dev, D_STREAM, "Reg 0x%02x = 0x%02x\n", 0x80,
 669                          test_byte);
 670                reg_w(gspca_dev, 0x6c80);
 671        }
 672
 673        reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
 674        reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
 675        reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
 676
 677        return 0;
 678}
 679
 680static void setmirror(struct gspca_dev *gspca_dev, s32 val)
 681{
 682        u8 hflipcmd[8] =
 683                {0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
 684
 685        if (val)
 686                hflipcmd[3] = 0x01;
 687
 688        reg_w_buf(gspca_dev, hflipcmd, sizeof hflipcmd);
 689}
 690
 691static void seteffect(struct gspca_dev *gspca_dev, s32 val)
 692{
 693        int idx = 0;
 694
 695        switch (val) {
 696        case V4L2_COLORFX_NONE:
 697                break;
 698        case V4L2_COLORFX_BW:
 699                idx = 2;
 700                break;
 701        case V4L2_COLORFX_SEPIA:
 702                idx = 3;
 703                break;
 704        case V4L2_COLORFX_SKETCH:
 705                idx = 4;
 706                break;
 707        case V4L2_COLORFX_NEGATIVE:
 708                idx = 6;
 709                break;
 710        default:
 711                break;
 712        }
 713
 714        reg_w_buf(gspca_dev, effects_table[idx],
 715                                sizeof effects_table[0]);
 716
 717        if (val == V4L2_COLORFX_SKETCH)
 718                reg_w(gspca_dev, 0x4aa6);
 719        else
 720                reg_w(gspca_dev, 0xfaa6);
 721}
 722
 723/* Is this really needed?
 724 * i added some module parameters for test with some users */
 725static void poll_sensor(struct gspca_dev *gspca_dev)
 726{
 727        static const u8 poll1[] =
 728                {0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
 729                 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
 730                 0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01,
 731                 0x60, 0x14};
 732        static const u8 poll2[] =
 733                {0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
 734                 0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
 735        static const u8 noise03[] =     /* (some differences / ms-drv) */
 736                {0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
 737                 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
 738                 0xc2, 0x80, 0xc3, 0x10};
 739
 740        gspca_dbg(gspca_dev, D_STREAM, "[Sensor requires polling]\n");
 741        reg_w_buf(gspca_dev, poll1, sizeof poll1);
 742        reg_w_buf(gspca_dev, poll2, sizeof poll2);
 743        reg_w_buf(gspca_dev, noise03, sizeof noise03);
 744}
 745
 746static int sd_start(struct gspca_dev *gspca_dev)
 747{
 748        struct sd *sd = (struct sd *) gspca_dev;
 749        const struct additional_sensor_data *sensor;
 750        int i, mode;
 751        u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
 752        static const u8 t3[] =
 753                { 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 };
 754
 755        mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
 756        switch (mode) {
 757        case 0:         /* 640x480 (0x00) */
 758                break;
 759        case 1:         /* 352x288 */
 760                t2[1] = 0x40;
 761                break;
 762        case 2:         /* 320x240 */
 763                t2[1] = 0x10;
 764                break;
 765        case 3:         /* 176x144 */
 766                t2[1] = 0x50;
 767                break;
 768        default:
 769/*      case 4:          * 160x120 */
 770                t2[1] = 0x20;
 771                break;
 772        }
 773
 774        switch (sd->sensor) {
 775        case SENSOR_OM6802:
 776                om6802_sensor_init(gspca_dev);
 777                break;
 778        case SENSOR_TAS5130A:
 779                i = 0;
 780                for (;;) {
 781                        reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
 782                                         sizeof tas5130a_sensor_init[0]);
 783                        if (i >= ARRAY_SIZE(tas5130a_sensor_init) - 1)
 784                                break;
 785                        i++;
 786                }
 787                reg_w(gspca_dev, 0x3c80);
 788                /* just in case and to keep sync with logs (for mine) */
 789                reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
 790                                 sizeof tas5130a_sensor_init[0]);
 791                reg_w(gspca_dev, 0x3c80);
 792                break;
 793        }
 794        sensor = &sensor_data[sd->sensor];
 795        setfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->freq));
 796        reg_r(gspca_dev, 0x0012);
 797        reg_w_buf(gspca_dev, t2, sizeof t2);
 798        reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3);
 799        reg_w(gspca_dev, 0x0013);
 800        msleep(15);
 801        reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
 802        reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
 803
 804        if (sd->sensor == SENSOR_OM6802)
 805                poll_sensor(gspca_dev);
 806
 807        return 0;
 808}
 809
 810static void sd_stopN(struct gspca_dev *gspca_dev)
 811{
 812        struct sd *sd = (struct sd *) gspca_dev;
 813
 814        reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
 815                        sizeof sensor_data[sd->sensor].stream);
 816        reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
 817                        sizeof sensor_data[sd->sensor].stream);
 818        if (sd->sensor == SENSOR_OM6802) {
 819                msleep(20);
 820                reg_w(gspca_dev, 0x0309);
 821        }
 822#if IS_ENABLED(CONFIG_INPUT)
 823        /* If the last button state is pressed, release it now! */
 824        if (sd->button_pressed) {
 825                input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
 826                input_sync(gspca_dev->input_dev);
 827                sd->button_pressed = 0;
 828        }
 829#endif
 830}
 831
 832static void sd_pkt_scan(struct gspca_dev *gspca_dev,
 833                        u8 *data,                       /* isoc packet */
 834                        int len)                        /* iso packet length */
 835{
 836        struct sd *sd __maybe_unused = (struct sd *) gspca_dev;
 837        int pkt_type;
 838
 839        if (data[0] == 0x5a) {
 840#if IS_ENABLED(CONFIG_INPUT)
 841                if (len > 20) {
 842                        u8 state = (data[20] & 0x80) ? 1 : 0;
 843                        if (sd->button_pressed != state) {
 844                                input_report_key(gspca_dev->input_dev,
 845                                                 KEY_CAMERA, state);
 846                                input_sync(gspca_dev->input_dev);
 847                                sd->button_pressed = state;
 848                        }
 849                }
 850#endif
 851                /* Control Packet, after this came the header again,
 852                 * but extra bytes came in the packet before this,
 853                 * sometimes an EOF arrives, sometimes not... */
 854                return;
 855        }
 856        data += 2;
 857        len -= 2;
 858        if (data[0] == 0xff && data[1] == 0xd8)
 859                pkt_type = FIRST_PACKET;
 860        else if (data[len - 2] == 0xff && data[len - 1] == 0xd9)
 861                pkt_type = LAST_PACKET;
 862        else
 863                pkt_type = INTER_PACKET;
 864        gspca_frame_add(gspca_dev, pkt_type, data, len);
 865}
 866
 867static int sd_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 868{
 869        struct gspca_dev *gspca_dev =
 870                container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
 871        struct sd *sd = (struct sd *)gspca_dev;
 872        s32 red_gain, blue_gain, green_gain;
 873
 874        gspca_dev->usb_err = 0;
 875
 876        switch (ctrl->id) {
 877        case V4L2_CID_AUTO_WHITE_BALANCE:
 878                red_gain = reg_r(gspca_dev, 0x0087);
 879                if (red_gain > 0x40)
 880                        red_gain = 0x40;
 881                else if (red_gain < 0x10)
 882                        red_gain = 0x10;
 883
 884                blue_gain = reg_r(gspca_dev, 0x0088);
 885                if (blue_gain > 0x40)
 886                        blue_gain = 0x40;
 887                else if (blue_gain < 0x10)
 888                        blue_gain = 0x10;
 889
 890                green_gain = reg_r(gspca_dev, 0x0089);
 891                if (green_gain > 0x40)
 892                        green_gain = 0x40;
 893                else if (green_gain < 0x10)
 894                        green_gain = 0x10;
 895
 896                sd->gain->val = green_gain;
 897                sd->red_balance->val = red_gain - green_gain;
 898                sd->blue_balance->val = blue_gain - green_gain;
 899                break;
 900        }
 901        return 0;
 902}
 903
 904static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
 905{
 906        struct gspca_dev *gspca_dev =
 907                container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
 908
 909        gspca_dev->usb_err = 0;
 910
 911        if (!gspca_dev->streaming)
 912                return 0;
 913
 914        switch (ctrl->id) {
 915        case V4L2_CID_BRIGHTNESS:
 916                setbrightness(gspca_dev, ctrl->val);
 917                break;
 918        case V4L2_CID_CONTRAST:
 919                setcontrast(gspca_dev, ctrl->val);
 920                break;
 921        case V4L2_CID_SATURATION:
 922                setcolors(gspca_dev, ctrl->val);
 923                break;
 924        case V4L2_CID_GAMMA:
 925                setgamma(gspca_dev, ctrl->val);
 926                break;
 927        case V4L2_CID_HFLIP:
 928                setmirror(gspca_dev, ctrl->val);
 929                break;
 930        case V4L2_CID_SHARPNESS:
 931                setsharpness(gspca_dev, ctrl->val);
 932                break;
 933        case V4L2_CID_POWER_LINE_FREQUENCY:
 934                setfreq(gspca_dev, ctrl->val);
 935                break;
 936        case V4L2_CID_BACKLIGHT_COMPENSATION:
 937                reg_w(gspca_dev, ctrl->val ? 0xf48e : 0xb48e);
 938                break;
 939        case V4L2_CID_AUTO_WHITE_BALANCE:
 940                setawb_n_RGB(gspca_dev);
 941                break;
 942        case V4L2_CID_COLORFX:
 943                seteffect(gspca_dev, ctrl->val);
 944                break;
 945        }
 946        return gspca_dev->usb_err;
 947}
 948
 949static const struct v4l2_ctrl_ops sd_ctrl_ops = {
 950        .g_volatile_ctrl = sd_g_volatile_ctrl,
 951        .s_ctrl = sd_s_ctrl,
 952};
 953
 954static int sd_init_controls(struct gspca_dev *gspca_dev)
 955{
 956        struct sd *sd = (struct sd *)gspca_dev;
 957        struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
 958
 959        gspca_dev->vdev.ctrl_handler = hdl;
 960        v4l2_ctrl_handler_init(hdl, 12);
 961        v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 962                        V4L2_CID_BRIGHTNESS, 0, 14, 1, 8);
 963        v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 964                        V4L2_CID_CONTRAST, 0, 0x0d, 1, 7);
 965        v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 966                        V4L2_CID_SATURATION, 0, 0xf, 1, 5);
 967        v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 968                        V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 10);
 969        /* Activate lowlight, some apps dont bring up the
 970           backlight_compensation control) */
 971        v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 972                        V4L2_CID_BACKLIGHT_COMPENSATION, 0, 1, 1, 1);
 973        if (sd->sensor == SENSOR_TAS5130A)
 974                v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 975                                V4L2_CID_HFLIP, 0, 1, 1, 0);
 976        sd->awb = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 977                        V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
 978        sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 979                        V4L2_CID_GAIN, 0x10, 0x40, 1, 0x20);
 980        sd->blue_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 981                        V4L2_CID_BLUE_BALANCE, -0x30, 0x30, 1, 0);
 982        sd->red_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 983                        V4L2_CID_RED_BALANCE, -0x30, 0x30, 1, 0);
 984        v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
 985                        V4L2_CID_SHARPNESS, 0, 15, 1, 6);
 986        v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
 987                        V4L2_CID_COLORFX, V4L2_COLORFX_SKETCH,
 988                        ~((1 << V4L2_COLORFX_NONE) |
 989                          (1 << V4L2_COLORFX_BW) |
 990                          (1 << V4L2_COLORFX_SEPIA) |
 991                          (1 << V4L2_COLORFX_SKETCH) |
 992                          (1 << V4L2_COLORFX_NEGATIVE)),
 993                        V4L2_COLORFX_NONE);
 994        sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
 995                        V4L2_CID_POWER_LINE_FREQUENCY,
 996                        V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 1,
 997                        V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
 998
 999        if (hdl->error) {
1000                pr_err("Could not initialize controls\n");
1001                return hdl->error;
1002        }
1003
1004        v4l2_ctrl_auto_cluster(4, &sd->awb, 0, true);
1005
1006        return 0;
1007}
1008
1009/* sub-driver description */
1010static const struct sd_desc sd_desc = {
1011        .name = MODULE_NAME,
1012        .config = sd_config,
1013        .init = sd_init,
1014        .init_controls = sd_init_controls,
1015        .start = sd_start,
1016        .stopN = sd_stopN,
1017        .pkt_scan = sd_pkt_scan,
1018#if IS_ENABLED(CONFIG_INPUT)
1019        .other_input = 1,
1020#endif
1021};
1022
1023/* -- module initialisation -- */
1024static const struct usb_device_id device_table[] = {
1025        {USB_DEVICE(0x17a1, 0x0128)},
1026        {}
1027};
1028MODULE_DEVICE_TABLE(usb, device_table);
1029
1030/* -- device connect -- */
1031static int sd_probe(struct usb_interface *intf,
1032                    const struct usb_device_id *id)
1033{
1034        return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1035                               THIS_MODULE);
1036}
1037
1038static struct usb_driver sd_driver = {
1039        .name = MODULE_NAME,
1040        .id_table = device_table,
1041        .probe = sd_probe,
1042        .disconnect = gspca_disconnect,
1043#ifdef CONFIG_PM
1044        .suspend = gspca_suspend,
1045        .resume = gspca_resume,
1046        .reset_resume = gspca_resume,
1047#endif
1048};
1049
1050module_usb_driver(sd_driver);
1051