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