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