Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *      Sunplus spca504(abc) spca533 spca536 library
0004  *      Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
0005  *
0006  * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
0007  */
0008 
0009 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0010 
0011 #define MODULE_NAME "sunplus"
0012 
0013 #include "gspca.h"
0014 #include "jpeg.h"
0015 
0016 MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
0017 MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver");
0018 MODULE_LICENSE("GPL");
0019 
0020 #define QUALITY 85
0021 
0022 /* specific webcam descriptor */
0023 struct sd {
0024     struct gspca_dev gspca_dev; /* !! must be the first item */
0025 
0026     bool autogain;
0027 
0028     u8 bridge;
0029 #define BRIDGE_SPCA504 0
0030 #define BRIDGE_SPCA504B 1
0031 #define BRIDGE_SPCA504C 2
0032 #define BRIDGE_SPCA533 3
0033 #define BRIDGE_SPCA536 4
0034     u8 subtype;
0035 #define AiptekMiniPenCam13 1
0036 #define LogitechClickSmart420 2
0037 #define LogitechClickSmart820 3
0038 #define MegapixV4 4
0039 #define MegaImageVI 5
0040 
0041     u8 jpeg_hdr[JPEG_HDR_SZ];
0042 };
0043 
0044 static const struct v4l2_pix_format vga_mode[] = {
0045     {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
0046         .bytesperline = 320,
0047         .sizeimage = 320 * 240 * 3 / 8 + 590,
0048         .colorspace = V4L2_COLORSPACE_JPEG,
0049         .priv = 2},
0050     {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
0051         .bytesperline = 640,
0052         .sizeimage = 640 * 480 * 3 / 8 + 590,
0053         .colorspace = V4L2_COLORSPACE_JPEG,
0054         .priv = 1},
0055 };
0056 
0057 static const struct v4l2_pix_format custom_mode[] = {
0058     {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
0059         .bytesperline = 320,
0060         .sizeimage = 320 * 240 * 3 / 8 + 590,
0061         .colorspace = V4L2_COLORSPACE_JPEG,
0062         .priv = 2},
0063     {464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
0064         .bytesperline = 464,
0065         .sizeimage = 464 * 480 * 3 / 8 + 590,
0066         .colorspace = V4L2_COLORSPACE_JPEG,
0067         .priv = 1},
0068 };
0069 
0070 static const struct v4l2_pix_format vga_mode2[] = {
0071     {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
0072         .bytesperline = 176,
0073         .sizeimage = 176 * 144 * 3 / 8 + 590,
0074         .colorspace = V4L2_COLORSPACE_JPEG,
0075         .priv = 4},
0076     {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
0077         .bytesperline = 320,
0078         .sizeimage = 320 * 240 * 3 / 8 + 590,
0079         .colorspace = V4L2_COLORSPACE_JPEG,
0080         .priv = 3},
0081     {352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
0082         .bytesperline = 352,
0083         .sizeimage = 352 * 288 * 3 / 8 + 590,
0084         .colorspace = V4L2_COLORSPACE_JPEG,
0085         .priv = 2},
0086     {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
0087         .bytesperline = 640,
0088         .sizeimage = 640 * 480 * 3 / 8 + 590,
0089         .colorspace = V4L2_COLORSPACE_JPEG,
0090         .priv = 1},
0091 };
0092 
0093 #define SPCA50X_OFFSET_DATA 10
0094 #define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
0095 #define SPCA504_PCCAM600_OFFSET_COMPRESS 4
0096 #define SPCA504_PCCAM600_OFFSET_MODE     5
0097 #define SPCA504_PCCAM600_OFFSET_DATA     14
0098  /* Frame packet header offsets for the spca533 */
0099 #define SPCA533_OFFSET_DATA 16
0100 #define SPCA533_OFFSET_FRAMSEQ  15
0101 /* Frame packet header offsets for the spca536 */
0102 #define SPCA536_OFFSET_DATA 4
0103 #define SPCA536_OFFSET_FRAMSEQ  1
0104 
0105 struct cmd {
0106     u8 req;
0107     u16 val;
0108     u16 idx;
0109 };
0110 
0111 /* Initialisation data for the Creative PC-CAM 600 */
0112 static const struct cmd spca504_pccam600_init_data[] = {
0113 /*  {0xa0, 0x0000, 0x0503},  * capture mode */
0114     {0x00, 0x0000, 0x2000},
0115     {0x00, 0x0013, 0x2301},
0116     {0x00, 0x0003, 0x2000},
0117     {0x00, 0x0001, 0x21ac},
0118     {0x00, 0x0001, 0x21a6},
0119     {0x00, 0x0000, 0x21a7}, /* brightness */
0120     {0x00, 0x0020, 0x21a8}, /* contrast */
0121     {0x00, 0x0001, 0x21ac}, /* sat/hue */
0122     {0x00, 0x0000, 0x21ad}, /* hue */
0123     {0x00, 0x001a, 0x21ae}, /* saturation */
0124     {0x00, 0x0002, 0x21a3}, /* gamma */
0125     {0x30, 0x0154, 0x0008},
0126     {0x30, 0x0004, 0x0006},
0127     {0x30, 0x0258, 0x0009},
0128     {0x30, 0x0004, 0x0000},
0129     {0x30, 0x0093, 0x0004},
0130     {0x30, 0x0066, 0x0005},
0131     {0x00, 0x0000, 0x2000},
0132     {0x00, 0x0013, 0x2301},
0133     {0x00, 0x0003, 0x2000},
0134     {0x00, 0x0013, 0x2301},
0135     {0x00, 0x0003, 0x2000},
0136 };
0137 
0138 /* Creative PC-CAM 600 specific open data, sent before using the
0139  * generic initialisation data from spca504_open_data.
0140  */
0141 static const struct cmd spca504_pccam600_open_data[] = {
0142     {0x00, 0x0001, 0x2501},
0143     {0x20, 0x0500, 0x0001}, /* snapshot mode */
0144     {0x00, 0x0003, 0x2880},
0145     {0x00, 0x0001, 0x2881},
0146 };
0147 
0148 /* Initialisation data for the logitech clicksmart 420 */
0149 static const struct cmd spca504A_clicksmart420_init_data[] = {
0150 /*  {0xa0, 0x0000, 0x0503},  * capture mode */
0151     {0x00, 0x0000, 0x2000},
0152     {0x00, 0x0013, 0x2301},
0153     {0x00, 0x0003, 0x2000},
0154     {0x00, 0x0001, 0x21ac},
0155     {0x00, 0x0001, 0x21a6},
0156     {0x00, 0x0000, 0x21a7}, /* brightness */
0157     {0x00, 0x0020, 0x21a8}, /* contrast */
0158     {0x00, 0x0001, 0x21ac}, /* sat/hue */
0159     {0x00, 0x0000, 0x21ad}, /* hue */
0160     {0x00, 0x001a, 0x21ae}, /* saturation */
0161     {0x00, 0x0002, 0x21a3}, /* gamma */
0162     {0x30, 0x0004, 0x000a},
0163     {0xb0, 0x0001, 0x0000},
0164 
0165     {0xa1, 0x0080, 0x0001},
0166     {0x30, 0x0049, 0x0000},
0167     {0x30, 0x0060, 0x0005},
0168     {0x0c, 0x0004, 0x0000},
0169     {0x00, 0x0000, 0x0000},
0170     {0x00, 0x0000, 0x2000},
0171     {0x00, 0x0013, 0x2301},
0172     {0x00, 0x0003, 0x2000},
0173 };
0174 
0175 /* clicksmart 420 open data ? */
0176 static const struct cmd spca504A_clicksmart420_open_data[] = {
0177     {0x00, 0x0001, 0x2501},
0178     {0x20, 0x0502, 0x0000},
0179     {0x06, 0x0000, 0x0000},
0180     {0x00, 0x0004, 0x2880},
0181     {0x00, 0x0001, 0x2881},
0182 
0183     {0xa0, 0x0000, 0x0503},
0184 };
0185 
0186 static const u8 qtable_creative_pccam[2][64] = {
0187     {               /* Q-table Y-components */
0188      0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
0189      0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
0190      0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
0191      0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
0192      0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
0193      0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
0194      0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
0195      0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
0196     {               /* Q-table C-components */
0197      0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
0198      0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
0199      0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0200      0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0201      0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0202      0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0203      0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0204      0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
0205 };
0206 
0207 /* FIXME: This Q-table is identical to the Creative PC-CAM one,
0208  *      except for one byte. Possibly a typo?
0209  *      NWG: 18/05/2003.
0210  */
0211 static const u8 qtable_spca504_default[2][64] = {
0212     {               /* Q-table Y-components */
0213      0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
0214      0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
0215      0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
0216      0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
0217      0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
0218      0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
0219      0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
0220      0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
0221      },
0222     {               /* Q-table C-components */
0223      0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
0224      0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
0225      0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0226      0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0227      0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0228      0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0229      0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
0230      0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
0231 };
0232 
0233 /* read <len> bytes to gspca_dev->usb_buf */
0234 static void reg_r(struct gspca_dev *gspca_dev,
0235           u8 req,
0236           u16 index,
0237           u16 len)
0238 {
0239     int ret;
0240 
0241     if (len > USB_BUF_SZ) {
0242         gspca_err(gspca_dev, "reg_r: buffer overflow\n");
0243         return;
0244     }
0245     if (len == 0) {
0246         gspca_err(gspca_dev, "reg_r: zero-length read\n");
0247         return;
0248     }
0249     if (gspca_dev->usb_err < 0)
0250         return;
0251     ret = usb_control_msg(gspca_dev->dev,
0252             usb_rcvctrlpipe(gspca_dev->dev, 0),
0253             req,
0254             USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0255             0,      /* value */
0256             index,
0257             gspca_dev->usb_buf, len,
0258             500);
0259     if (ret < 0) {
0260         pr_err("reg_r err %d\n", ret);
0261         gspca_dev->usb_err = ret;
0262         /*
0263          * Make sure the buffer is zeroed to avoid uninitialized
0264          * values.
0265          */
0266         memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);
0267     }
0268 }
0269 
0270 /* write one byte */
0271 static void reg_w_1(struct gspca_dev *gspca_dev,
0272            u8 req,
0273            u16 value,
0274            u16 index,
0275            u16 byte)
0276 {
0277     int ret;
0278 
0279     if (gspca_dev->usb_err < 0)
0280         return;
0281     gspca_dev->usb_buf[0] = byte;
0282     ret = usb_control_msg(gspca_dev->dev,
0283             usb_sndctrlpipe(gspca_dev->dev, 0),
0284             req,
0285             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0286             value, index,
0287             gspca_dev->usb_buf, 1,
0288             500);
0289     if (ret < 0) {
0290         pr_err("reg_w_1 err %d\n", ret);
0291         gspca_dev->usb_err = ret;
0292     }
0293 }
0294 
0295 /* write req / index / value */
0296 static void reg_w_riv(struct gspca_dev *gspca_dev,
0297              u8 req, u16 index, u16 value)
0298 {
0299     struct usb_device *dev = gspca_dev->dev;
0300     int ret;
0301 
0302     if (gspca_dev->usb_err < 0)
0303         return;
0304     ret = usb_control_msg(dev,
0305             usb_sndctrlpipe(dev, 0),
0306             req,
0307             USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0308             value, index, NULL, 0, 500);
0309     if (ret < 0) {
0310         pr_err("reg_w_riv err %d\n", ret);
0311         gspca_dev->usb_err = ret;
0312         return;
0313     }
0314     gspca_dbg(gspca_dev, D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x\n",
0315           req, index, value);
0316 }
0317 
0318 static void write_vector(struct gspca_dev *gspca_dev,
0319             const struct cmd *data, int ncmds)
0320 {
0321     while (--ncmds >= 0) {
0322         reg_w_riv(gspca_dev, data->req, data->idx, data->val);
0323         data++;
0324     }
0325 }
0326 
0327 static void setup_qtable(struct gspca_dev *gspca_dev,
0328             const u8 qtable[2][64])
0329 {
0330     int i;
0331 
0332     /* loop over y components */
0333     for (i = 0; i < 64; i++)
0334         reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
0335 
0336     /* loop over c components */
0337     for (i = 0; i < 64; i++)
0338         reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]);
0339 }
0340 
0341 static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
0342                  u8 req, u16 idx, u16 val)
0343 {
0344     reg_w_riv(gspca_dev, req, idx, val);
0345     reg_r(gspca_dev, 0x01, 0x0001, 1);
0346     gspca_dbg(gspca_dev, D_FRAM, "before wait 0x%04x\n",
0347           gspca_dev->usb_buf[0]);
0348     reg_w_riv(gspca_dev, req, idx, val);
0349 
0350     msleep(200);
0351     reg_r(gspca_dev, 0x01, 0x0001, 1);
0352     gspca_dbg(gspca_dev, D_FRAM, "after wait 0x%04x\n",
0353           gspca_dev->usb_buf[0]);
0354 }
0355 
0356 static void spca504_read_info(struct gspca_dev *gspca_dev)
0357 {
0358     int i;
0359     u8 info[6];
0360 
0361     if (gspca_debug < D_STREAM)
0362         return;
0363 
0364     for (i = 0; i < 6; i++) {
0365         reg_r(gspca_dev, 0, i, 1);
0366         info[i] = gspca_dev->usb_buf[0];
0367     }
0368     gspca_dbg(gspca_dev, D_STREAM,
0369           "Read info: %d %d %d %d %d %d. Should be 1,0,2,2,0,0\n",
0370           info[0], info[1], info[2],
0371           info[3], info[4], info[5]);
0372 }
0373 
0374 static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
0375             u8 req,
0376             u16 idx, u16 val, u8 endcode, u8 count)
0377 {
0378     u16 status;
0379 
0380     reg_w_riv(gspca_dev, req, idx, val);
0381     reg_r(gspca_dev, 0x01, 0x0001, 1);
0382     if (gspca_dev->usb_err < 0)
0383         return;
0384     gspca_dbg(gspca_dev, D_FRAM, "Status 0x%02x Need 0x%02x\n",
0385           gspca_dev->usb_buf[0], endcode);
0386     if (!count)
0387         return;
0388     count = 200;
0389     while (--count > 0) {
0390         msleep(10);
0391         /* gsmart mini2 write a each wait setting 1 ms is enough */
0392 /*      reg_w_riv(gspca_dev, req, idx, val); */
0393         reg_r(gspca_dev, 0x01, 0x0001, 1);
0394         status = gspca_dev->usb_buf[0];
0395         if (status == endcode) {
0396             gspca_dbg(gspca_dev, D_FRAM, "status 0x%04x after wait %d\n",
0397                   status, 200 - count);
0398                 break;
0399         }
0400     }
0401 }
0402 
0403 static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
0404 {
0405     int count = 10;
0406 
0407     while (--count > 0) {
0408         reg_r(gspca_dev, 0x21, 0, 1);
0409         if ((gspca_dev->usb_buf[0] & 0x01) == 0)
0410             break;
0411         msleep(10);
0412     }
0413 }
0414 
0415 static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
0416 {
0417     int count = 50;
0418 
0419     while (--count > 0) {
0420         reg_r(gspca_dev, 0x21, 1, 1);
0421         if (gspca_dev->usb_buf[0] != 0) {
0422             reg_w_1(gspca_dev, 0x21, 0, 1, 0);
0423             reg_r(gspca_dev, 0x21, 1, 1);
0424             spca504B_PollingDataReady(gspca_dev);
0425             break;
0426         }
0427         msleep(10);
0428     }
0429 }
0430 
0431 static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
0432 {
0433     u8 *data;
0434 
0435     if (gspca_debug < D_STREAM)
0436         return;
0437 
0438     data = gspca_dev->usb_buf;
0439     reg_r(gspca_dev, 0x20, 0, 5);
0440     gspca_dbg(gspca_dev, D_STREAM, "FirmWare: %d %d %d %d %d\n",
0441           data[0], data[1], data[2], data[3], data[4]);
0442     reg_r(gspca_dev, 0x23, 0, 64);
0443     reg_r(gspca_dev, 0x23, 1, 64);
0444 }
0445 
0446 static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
0447 {
0448     struct sd *sd = (struct sd *) gspca_dev;
0449     u8 Size;
0450 
0451     Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
0452     switch (sd->bridge) {
0453     case BRIDGE_SPCA533:
0454         reg_w_riv(gspca_dev, 0x31, 0, 0);
0455         spca504B_WaitCmdStatus(gspca_dev);
0456         spca504B_PollingDataReady(gspca_dev);
0457         spca50x_GetFirmware(gspca_dev);
0458 
0459         reg_w_1(gspca_dev, 0x24, 0, 8, 2);      /* type */
0460         reg_r(gspca_dev, 0x24, 8, 1);
0461 
0462         reg_w_1(gspca_dev, 0x25, 0, 4, Size);
0463         reg_r(gspca_dev, 0x25, 4, 1);           /* size */
0464         spca504B_PollingDataReady(gspca_dev);
0465 
0466         /* Init the cam width height with some values get on init ? */
0467         reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
0468         spca504B_WaitCmdStatus(gspca_dev);
0469         spca504B_PollingDataReady(gspca_dev);
0470         break;
0471     default:
0472 /* case BRIDGE_SPCA504B: */
0473 /* case BRIDGE_SPCA536: */
0474         reg_w_1(gspca_dev, 0x25, 0, 4, Size);
0475         reg_r(gspca_dev, 0x25, 4, 1);           /* size */
0476         reg_w_1(gspca_dev, 0x27, 0, 0, 6);
0477         reg_r(gspca_dev, 0x27, 0, 1);           /* type */
0478         spca504B_PollingDataReady(gspca_dev);
0479         break;
0480     case BRIDGE_SPCA504:
0481         Size += 3;
0482         if (sd->subtype == AiptekMiniPenCam13) {
0483             /* spca504a aiptek */
0484             spca504A_acknowledged_command(gspca_dev,
0485                         0x08, Size, 0,
0486                         0x80 | (Size & 0x0f), 1);
0487             spca504A_acknowledged_command(gspca_dev,
0488                             1, 3, 0, 0x9f, 0);
0489         } else {
0490             spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
0491         }
0492         break;
0493     case BRIDGE_SPCA504C:
0494         /* capture mode */
0495         reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
0496         reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
0497         break;
0498     }
0499 }
0500 
0501 static void spca504_wait_status(struct gspca_dev *gspca_dev)
0502 {
0503     int cnt;
0504 
0505     cnt = 256;
0506     while (--cnt > 0) {
0507         /* With this we get the status, when return 0 it's all ok */
0508         reg_r(gspca_dev, 0x06, 0x00, 1);
0509         if (gspca_dev->usb_buf[0] == 0)
0510             return;
0511         msleep(10);
0512     }
0513 }
0514 
0515 static void spca504B_setQtable(struct gspca_dev *gspca_dev)
0516 {
0517     reg_w_1(gspca_dev, 0x26, 0, 0, 3);
0518     reg_r(gspca_dev, 0x26, 0, 1);
0519     spca504B_PollingDataReady(gspca_dev);
0520 }
0521 
0522 static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
0523 {
0524     struct sd *sd = (struct sd *) gspca_dev;
0525     u16 reg;
0526 
0527     reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
0528     reg_w_riv(gspca_dev, 0x00, reg, val);
0529 }
0530 
0531 static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
0532 {
0533     struct sd *sd = (struct sd *) gspca_dev;
0534     u16 reg;
0535 
0536     reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
0537     reg_w_riv(gspca_dev, 0x00, reg, val);
0538 }
0539 
0540 static void setcolors(struct gspca_dev *gspca_dev, s32 val)
0541 {
0542     struct sd *sd = (struct sd *) gspca_dev;
0543     u16 reg;
0544 
0545     reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
0546     reg_w_riv(gspca_dev, 0x00, reg, val);
0547 }
0548 
0549 static void init_ctl_reg(struct gspca_dev *gspca_dev)
0550 {
0551     struct sd *sd = (struct sd *) gspca_dev;
0552     int pollreg = 1;
0553 
0554     switch (sd->bridge) {
0555     case BRIDGE_SPCA504:
0556     case BRIDGE_SPCA504C:
0557         pollreg = 0;
0558         fallthrough;
0559     default:
0560 /*  case BRIDGE_SPCA533: */
0561 /*  case BRIDGE_SPCA504B: */
0562         reg_w_riv(gspca_dev, 0, 0x21ad, 0x00);  /* hue */
0563         reg_w_riv(gspca_dev, 0, 0x21ac, 0x01);  /* sat/hue */
0564         reg_w_riv(gspca_dev, 0, 0x21a3, 0x00);  /* gamma */
0565         break;
0566     case BRIDGE_SPCA536:
0567         reg_w_riv(gspca_dev, 0, 0x20f5, 0x40);
0568         reg_w_riv(gspca_dev, 0, 0x20f4, 0x01);
0569         reg_w_riv(gspca_dev, 0, 0x2089, 0x00);
0570         break;
0571     }
0572     if (pollreg)
0573         spca504B_PollingDataReady(gspca_dev);
0574 }
0575 
0576 /* this function is called at probe time */
0577 static int sd_config(struct gspca_dev *gspca_dev,
0578             const struct usb_device_id *id)
0579 {
0580     struct sd *sd = (struct sd *) gspca_dev;
0581     struct cam *cam;
0582 
0583     cam = &gspca_dev->cam;
0584 
0585     sd->bridge = id->driver_info >> 8;
0586     sd->subtype = id->driver_info;
0587 
0588     if (sd->subtype == AiptekMiniPenCam13) {
0589 
0590         /* try to get the firmware as some cam answer 2.0.1.2.2
0591          * and should be a spca504b then overwrite that setting */
0592         reg_r(gspca_dev, 0x20, 0, 1);
0593         switch (gspca_dev->usb_buf[0]) {
0594         case 1:
0595             break;      /* (right bridge/subtype) */
0596         case 2:
0597             sd->bridge = BRIDGE_SPCA504B;
0598             sd->subtype = 0;
0599             break;
0600         default:
0601             return -ENODEV;
0602         }
0603     }
0604 
0605     switch (sd->bridge) {
0606     default:
0607 /*  case BRIDGE_SPCA504B: */
0608 /*  case BRIDGE_SPCA504: */
0609 /*  case BRIDGE_SPCA536: */
0610         cam->cam_mode = vga_mode;
0611         cam->nmodes = ARRAY_SIZE(vga_mode);
0612         break;
0613     case BRIDGE_SPCA533:
0614         cam->cam_mode = custom_mode;
0615         if (sd->subtype == MegaImageVI)     /* 320x240 only */
0616             cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
0617         else
0618             cam->nmodes = ARRAY_SIZE(custom_mode);
0619         break;
0620     case BRIDGE_SPCA504C:
0621         cam->cam_mode = vga_mode2;
0622         cam->nmodes = ARRAY_SIZE(vga_mode2);
0623         break;
0624     }
0625     return 0;
0626 }
0627 
0628 /* this function is called at probe and resume time */
0629 static int sd_init(struct gspca_dev *gspca_dev)
0630 {
0631     struct sd *sd = (struct sd *) gspca_dev;
0632 
0633     switch (sd->bridge) {
0634     case BRIDGE_SPCA504B:
0635         reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
0636         reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01);
0637         reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00);
0638         reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00);
0639         reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13);
0640         reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00);
0641         fallthrough;
0642     case BRIDGE_SPCA533:
0643         spca504B_PollingDataReady(gspca_dev);
0644         spca50x_GetFirmware(gspca_dev);
0645         break;
0646     case BRIDGE_SPCA536:
0647         spca50x_GetFirmware(gspca_dev);
0648         reg_r(gspca_dev, 0x00, 0x5002, 1);
0649         reg_w_1(gspca_dev, 0x24, 0, 0, 0);
0650         reg_r(gspca_dev, 0x24, 0, 1);
0651         spca504B_PollingDataReady(gspca_dev);
0652         reg_w_riv(gspca_dev, 0x34, 0, 0);
0653         spca504B_WaitCmdStatus(gspca_dev);
0654         break;
0655     case BRIDGE_SPCA504C:   /* pccam600 */
0656         gspca_dbg(gspca_dev, D_STREAM, "Opening SPCA504 (PC-CAM 600)\n");
0657         reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000);
0658         reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001); /* reset */
0659         spca504_wait_status(gspca_dev);
0660         if (sd->subtype == LogitechClickSmart420)
0661             write_vector(gspca_dev,
0662                 spca504A_clicksmart420_open_data,
0663                 ARRAY_SIZE(spca504A_clicksmart420_open_data));
0664         else
0665             write_vector(gspca_dev, spca504_pccam600_open_data,
0666                 ARRAY_SIZE(spca504_pccam600_open_data));
0667         setup_qtable(gspca_dev, qtable_creative_pccam);
0668         break;
0669     default:
0670 /*  case BRIDGE_SPCA504: */
0671         gspca_dbg(gspca_dev, D_STREAM, "Opening SPCA504\n");
0672         if (sd->subtype == AiptekMiniPenCam13) {
0673             spca504_read_info(gspca_dev);
0674 
0675             /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
0676             spca504A_acknowledged_command(gspca_dev, 0x24,
0677                             8, 3, 0x9e, 1);
0678             /* Twice sequential need status 0xff->0x9e->0x9d */
0679             spca504A_acknowledged_command(gspca_dev, 0x24,
0680                             8, 3, 0x9e, 0);
0681 
0682             spca504A_acknowledged_command(gspca_dev, 0x24,
0683                             0, 0, 0x9d, 1);
0684             /******************************/
0685             /* spca504a aiptek */
0686             spca504A_acknowledged_command(gspca_dev, 0x08,
0687                             6, 0, 0x86, 1);
0688 /*          reg_write (dev, 0, 0x2000, 0); */
0689 /*          reg_write (dev, 0, 0x2883, 1); */
0690 /*          spca504A_acknowledged_command (gspca_dev, 0x08,
0691                             6, 0, 0x86, 1); */
0692 /*          spca504A_acknowledged_command (gspca_dev, 0x24,
0693                             0, 0, 0x9D, 1); */
0694             reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
0695                             /* L92 sno1t.txt */
0696             reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
0697             spca504A_acknowledged_command(gspca_dev, 0x01,
0698                             0x0f, 0, 0xff, 0);
0699         }
0700         /* setup qtable */
0701         reg_w_riv(gspca_dev, 0, 0x2000, 0);
0702         reg_w_riv(gspca_dev, 0, 0x2883, 1);
0703         setup_qtable(gspca_dev, qtable_spca504_default);
0704         break;
0705     }
0706     return gspca_dev->usb_err;
0707 }
0708 
0709 static int sd_start(struct gspca_dev *gspca_dev)
0710 {
0711     struct sd *sd = (struct sd *) gspca_dev;
0712     int enable;
0713 
0714     /* create the JPEG header */
0715     jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
0716             gspca_dev->pixfmt.width,
0717             0x22);      /* JPEG 411 */
0718     jpeg_set_qual(sd->jpeg_hdr, QUALITY);
0719 
0720     if (sd->bridge == BRIDGE_SPCA504B)
0721         spca504B_setQtable(gspca_dev);
0722     spca504B_SetSizeType(gspca_dev);
0723     switch (sd->bridge) {
0724     default:
0725 /*  case BRIDGE_SPCA504B: */
0726 /*  case BRIDGE_SPCA533: */
0727 /*  case BRIDGE_SPCA536: */
0728         switch (sd->subtype) {
0729         case MegapixV4:
0730         case LogitechClickSmart820:
0731         case MegaImageVI:
0732             reg_w_riv(gspca_dev, 0xf0, 0, 0);
0733             spca504B_WaitCmdStatus(gspca_dev);
0734             reg_w_riv(gspca_dev, 0xf0, 4, 0);
0735             spca504B_WaitCmdStatus(gspca_dev);
0736             break;
0737         default:
0738             reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
0739             spca504B_WaitCmdStatus(gspca_dev);
0740             spca504B_PollingDataReady(gspca_dev);
0741             break;
0742         }
0743         break;
0744     case BRIDGE_SPCA504:
0745         if (sd->subtype == AiptekMiniPenCam13) {
0746             spca504_read_info(gspca_dev);
0747 
0748             /* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
0749             spca504A_acknowledged_command(gspca_dev, 0x24,
0750                             8, 3, 0x9e, 1);
0751             /* Twice sequential need status 0xff->0x9e->0x9d */
0752             spca504A_acknowledged_command(gspca_dev, 0x24,
0753                             8, 3, 0x9e, 0);
0754             spca504A_acknowledged_command(gspca_dev, 0x24,
0755                             0, 0, 0x9d, 1);
0756         } else {
0757             spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
0758             spca504_read_info(gspca_dev);
0759             spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
0760             spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
0761         }
0762         spca504B_SetSizeType(gspca_dev);
0763         reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
0764                             /* L92 sno1t.txt */
0765         reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
0766         break;
0767     case BRIDGE_SPCA504C:
0768         if (sd->subtype == LogitechClickSmart420) {
0769             write_vector(gspca_dev,
0770                 spca504A_clicksmart420_init_data,
0771                 ARRAY_SIZE(spca504A_clicksmart420_init_data));
0772         } else {
0773             write_vector(gspca_dev, spca504_pccam600_init_data,
0774                 ARRAY_SIZE(spca504_pccam600_init_data));
0775         }
0776         enable = (sd->autogain ? 0x04 : 0x01);
0777         reg_w_riv(gspca_dev, 0x0c, 0x0000, enable);
0778                             /* auto exposure */
0779         reg_w_riv(gspca_dev, 0xb0, 0x0000, enable);
0780                             /* auto whiteness */
0781 
0782         /* set default exposure compensation and whiteness balance */
0783         reg_w_riv(gspca_dev, 0x30, 0x0001, 800);    /* ~ 20 fps */
0784         reg_w_riv(gspca_dev, 0x30, 0x0002, 1600);
0785         spca504B_SetSizeType(gspca_dev);
0786         break;
0787     }
0788     init_ctl_reg(gspca_dev);
0789     return gspca_dev->usb_err;
0790 }
0791 
0792 static void sd_stopN(struct gspca_dev *gspca_dev)
0793 {
0794     struct sd *sd = (struct sd *) gspca_dev;
0795 
0796     switch (sd->bridge) {
0797     default:
0798 /*  case BRIDGE_SPCA533: */
0799 /*  case BRIDGE_SPCA536: */
0800 /*  case BRIDGE_SPCA504B: */
0801         reg_w_riv(gspca_dev, 0x31, 0, 0);
0802         spca504B_WaitCmdStatus(gspca_dev);
0803         spca504B_PollingDataReady(gspca_dev);
0804         break;
0805     case BRIDGE_SPCA504:
0806     case BRIDGE_SPCA504C:
0807         reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000);
0808 
0809         if (sd->subtype == AiptekMiniPenCam13) {
0810             /* spca504a aiptek */
0811 /*          spca504A_acknowledged_command(gspca_dev, 0x08,
0812                              6, 0, 0x86, 1); */
0813             spca504A_acknowledged_command(gspca_dev, 0x24,
0814                             0x00, 0x00, 0x9d, 1);
0815             spca504A_acknowledged_command(gspca_dev, 0x01,
0816                             0x0f, 0x00, 0xff, 1);
0817         } else {
0818             spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
0819             reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000);
0820         }
0821         break;
0822     }
0823 }
0824 
0825 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
0826             u8 *data,           /* isoc packet */
0827             int len)            /* iso packet length */
0828 {
0829     struct sd *sd = (struct sd *) gspca_dev;
0830     int i, sof = 0;
0831     static u8 ffd9[] = {0xff, 0xd9};
0832 
0833 /* frames are jpeg 4.1.1 without 0xff escape */
0834     switch (sd->bridge) {
0835     case BRIDGE_SPCA533:
0836         if (data[0] == 0xff) {
0837             if (data[1] != 0x01) {  /* drop packet */
0838 /*              gspca_dev->last_packet_type = DISCARD_PACKET; */
0839                 return;
0840             }
0841             sof = 1;
0842             data += SPCA533_OFFSET_DATA;
0843             len -= SPCA533_OFFSET_DATA;
0844         } else {
0845             data += 1;
0846             len -= 1;
0847         }
0848         break;
0849     case BRIDGE_SPCA536:
0850         if (data[0] == 0xff) {
0851             sof = 1;
0852             data += SPCA536_OFFSET_DATA;
0853             len -= SPCA536_OFFSET_DATA;
0854         } else {
0855             data += 2;
0856             len -= 2;
0857         }
0858         break;
0859     default:
0860 /*  case BRIDGE_SPCA504: */
0861 /*  case BRIDGE_SPCA504B: */
0862         switch (data[0]) {
0863         case 0xfe:          /* start of frame */
0864             sof = 1;
0865             data += SPCA50X_OFFSET_DATA;
0866             len -= SPCA50X_OFFSET_DATA;
0867             break;
0868         case 0xff:          /* drop packet */
0869 /*          gspca_dev->last_packet_type = DISCARD_PACKET; */
0870             return;
0871         default:
0872             data += 1;
0873             len -= 1;
0874             break;
0875         }
0876         break;
0877     case BRIDGE_SPCA504C:
0878         switch (data[0]) {
0879         case 0xfe:          /* start of frame */
0880             sof = 1;
0881             data += SPCA504_PCCAM600_OFFSET_DATA;
0882             len -= SPCA504_PCCAM600_OFFSET_DATA;
0883             break;
0884         case 0xff:          /* drop packet */
0885 /*          gspca_dev->last_packet_type = DISCARD_PACKET; */
0886             return;
0887         default:
0888             data += 1;
0889             len -= 1;
0890             break;
0891         }
0892         break;
0893     }
0894     if (sof) {      /* start of frame */
0895         gspca_frame_add(gspca_dev, LAST_PACKET,
0896                 ffd9, 2);
0897 
0898         /* put the JPEG header in the new frame */
0899         gspca_frame_add(gspca_dev, FIRST_PACKET,
0900             sd->jpeg_hdr, JPEG_HDR_SZ);
0901     }
0902 
0903     /* add 0x00 after 0xff */
0904     i = 0;
0905     do {
0906         if (data[i] == 0xff) {
0907             gspca_frame_add(gspca_dev, INTER_PACKET,
0908                     data, i + 1);
0909             len -= i;
0910             data += i;
0911             *data = 0x00;
0912             i = 0;
0913         }
0914         i++;
0915     } while (i < len);
0916     gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
0917 }
0918 
0919 static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
0920 {
0921     struct gspca_dev *gspca_dev =
0922         container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
0923     struct sd *sd = (struct sd *)gspca_dev;
0924 
0925     gspca_dev->usb_err = 0;
0926 
0927     if (!gspca_dev->streaming)
0928         return 0;
0929 
0930     switch (ctrl->id) {
0931     case V4L2_CID_BRIGHTNESS:
0932         setbrightness(gspca_dev, ctrl->val);
0933         break;
0934     case V4L2_CID_CONTRAST:
0935         setcontrast(gspca_dev, ctrl->val);
0936         break;
0937     case V4L2_CID_SATURATION:
0938         setcolors(gspca_dev, ctrl->val);
0939         break;
0940     case V4L2_CID_AUTOGAIN:
0941         sd->autogain = ctrl->val;
0942         break;
0943     }
0944     return gspca_dev->usb_err;
0945 }
0946 
0947 static const struct v4l2_ctrl_ops sd_ctrl_ops = {
0948     .s_ctrl = sd_s_ctrl,
0949 };
0950 
0951 static int sd_init_controls(struct gspca_dev *gspca_dev)
0952 {
0953     struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
0954 
0955     gspca_dev->vdev.ctrl_handler = hdl;
0956     v4l2_ctrl_handler_init(hdl, 4);
0957     v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0958             V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
0959     v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0960             V4L2_CID_CONTRAST, 0, 255, 1, 0x20);
0961     v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0962             V4L2_CID_SATURATION, 0, 255, 1, 0x1a);
0963     v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
0964             V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
0965 
0966     if (hdl->error) {
0967         pr_err("Could not initialize controls\n");
0968         return hdl->error;
0969     }
0970     return 0;
0971 }
0972 
0973 /* sub-driver description */
0974 static const struct sd_desc sd_desc = {
0975     .name = MODULE_NAME,
0976     .config = sd_config,
0977     .init = sd_init,
0978     .init_controls = sd_init_controls,
0979     .start = sd_start,
0980     .stopN = sd_stopN,
0981     .pkt_scan = sd_pkt_scan,
0982 };
0983 
0984 /* -- module initialisation -- */
0985 #define BS(bridge, subtype) \
0986     .driver_info = (BRIDGE_ ## bridge << 8) \
0987             | (subtype)
0988 static const struct usb_device_id device_table[] = {
0989     {USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
0990     {USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
0991     {USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
0992     {USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
0993     {USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
0994     {USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
0995     {USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
0996     {USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
0997     {USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
0998     {USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
0999     {USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1000     {USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1001     {USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1002     {USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1003     {USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1004     {USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1005     {USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1006     {USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
1007     {USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)},
1008     {USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
1009     {USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
1010     {USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1011     {USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1012     {USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1013     {USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1014     {USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1015     {USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1016     {USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1017     {USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1018     {USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1019     {USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1020     {USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1021     {USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1022     {USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1023     {USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1024     {USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1025     {USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1026     {USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1027     {USB_DEVICE(0x06d6, 0x0041), BS(SPCA504B, 0)},
1028     {USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1029     {USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1030     {USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1031     {USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1032     {USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1033     {USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1034     {USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1035     {USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1036     {USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1037     {USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1038     {USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1039     {USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1040     {USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1041     {USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1042     {USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1043     {USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1044     {USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1045     {USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1046     {USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1047     {USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1048     {USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
1049     {}
1050 };
1051 MODULE_DEVICE_TABLE(usb, device_table);
1052 
1053 /* -- device connect -- */
1054 static int sd_probe(struct usb_interface *intf,
1055             const struct usb_device_id *id)
1056 {
1057     return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1058                 THIS_MODULE);
1059 }
1060 
1061 static struct usb_driver sd_driver = {
1062     .name = MODULE_NAME,
1063     .id_table = device_table,
1064     .probe = sd_probe,
1065     .disconnect = gspca_disconnect,
1066 #ifdef CONFIG_PM
1067     .suspend = gspca_suspend,
1068     .resume = gspca_resume,
1069     .reset_resume = gspca_resume,
1070 #endif
1071 };
1072 
1073 module_usb_driver(sd_driver);