cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sunplus.c (29382B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *		Sunplus spca504(abc) spca533 spca536 library
      4 *		Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
      5 *
      6 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
      7 */
      8
      9#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     10
     11#define MODULE_NAME "sunplus"
     12
     13#include "gspca.h"
     14#include "jpeg.h"
     15
     16MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
     17MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver");
     18MODULE_LICENSE("GPL");
     19
     20#define QUALITY 85
     21
     22/* specific webcam descriptor */
     23struct sd {
     24	struct gspca_dev gspca_dev;	/* !! must be the first item */
     25
     26	bool autogain;
     27
     28	u8 bridge;
     29#define BRIDGE_SPCA504 0
     30#define BRIDGE_SPCA504B 1
     31#define BRIDGE_SPCA504C 2
     32#define BRIDGE_SPCA533 3
     33#define BRIDGE_SPCA536 4
     34	u8 subtype;
     35#define AiptekMiniPenCam13 1
     36#define LogitechClickSmart420 2
     37#define LogitechClickSmart820 3
     38#define MegapixV4 4
     39#define MegaImageVI 5
     40
     41	u8 jpeg_hdr[JPEG_HDR_SZ];
     42};
     43
     44static const struct v4l2_pix_format vga_mode[] = {
     45	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
     46		.bytesperline = 320,
     47		.sizeimage = 320 * 240 * 3 / 8 + 590,
     48		.colorspace = V4L2_COLORSPACE_JPEG,
     49		.priv = 2},
     50	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
     51		.bytesperline = 640,
     52		.sizeimage = 640 * 480 * 3 / 8 + 590,
     53		.colorspace = V4L2_COLORSPACE_JPEG,
     54		.priv = 1},
     55};
     56
     57static const struct v4l2_pix_format custom_mode[] = {
     58	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
     59		.bytesperline = 320,
     60		.sizeimage = 320 * 240 * 3 / 8 + 590,
     61		.colorspace = V4L2_COLORSPACE_JPEG,
     62		.priv = 2},
     63	{464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
     64		.bytesperline = 464,
     65		.sizeimage = 464 * 480 * 3 / 8 + 590,
     66		.colorspace = V4L2_COLORSPACE_JPEG,
     67		.priv = 1},
     68};
     69
     70static const struct v4l2_pix_format vga_mode2[] = {
     71	{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
     72		.bytesperline = 176,
     73		.sizeimage = 176 * 144 * 3 / 8 + 590,
     74		.colorspace = V4L2_COLORSPACE_JPEG,
     75		.priv = 4},
     76	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
     77		.bytesperline = 320,
     78		.sizeimage = 320 * 240 * 3 / 8 + 590,
     79		.colorspace = V4L2_COLORSPACE_JPEG,
     80		.priv = 3},
     81	{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
     82		.bytesperline = 352,
     83		.sizeimage = 352 * 288 * 3 / 8 + 590,
     84		.colorspace = V4L2_COLORSPACE_JPEG,
     85		.priv = 2},
     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 = 1},
     91};
     92
     93#define SPCA50X_OFFSET_DATA 10
     94#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
     95#define SPCA504_PCCAM600_OFFSET_COMPRESS 4
     96#define SPCA504_PCCAM600_OFFSET_MODE	 5
     97#define SPCA504_PCCAM600_OFFSET_DATA	 14
     98 /* Frame packet header offsets for the spca533 */
     99#define SPCA533_OFFSET_DATA	16
    100#define SPCA533_OFFSET_FRAMSEQ	15
    101/* Frame packet header offsets for the spca536 */
    102#define SPCA536_OFFSET_DATA	4
    103#define SPCA536_OFFSET_FRAMSEQ	1
    104
    105struct cmd {
    106	u8 req;
    107	u16 val;
    108	u16 idx;
    109};
    110
    111/* Initialisation data for the Creative PC-CAM 600 */
    112static const struct cmd spca504_pccam600_init_data[] = {
    113/*	{0xa0, 0x0000, 0x0503},  * capture mode */
    114	{0x00, 0x0000, 0x2000},
    115	{0x00, 0x0013, 0x2301},
    116	{0x00, 0x0003, 0x2000},
    117	{0x00, 0x0001, 0x21ac},
    118	{0x00, 0x0001, 0x21a6},
    119	{0x00, 0x0000, 0x21a7},	/* brightness */
    120	{0x00, 0x0020, 0x21a8},	/* contrast */
    121	{0x00, 0x0001, 0x21ac},	/* sat/hue */
    122	{0x00, 0x0000, 0x21ad},	/* hue */
    123	{0x00, 0x001a, 0x21ae},	/* saturation */
    124	{0x00, 0x0002, 0x21a3},	/* gamma */
    125	{0x30, 0x0154, 0x0008},
    126	{0x30, 0x0004, 0x0006},
    127	{0x30, 0x0258, 0x0009},
    128	{0x30, 0x0004, 0x0000},
    129	{0x30, 0x0093, 0x0004},
    130	{0x30, 0x0066, 0x0005},
    131	{0x00, 0x0000, 0x2000},
    132	{0x00, 0x0013, 0x2301},
    133	{0x00, 0x0003, 0x2000},
    134	{0x00, 0x0013, 0x2301},
    135	{0x00, 0x0003, 0x2000},
    136};
    137
    138/* Creative PC-CAM 600 specific open data, sent before using the
    139 * generic initialisation data from spca504_open_data.
    140 */
    141static const struct cmd spca504_pccam600_open_data[] = {
    142	{0x00, 0x0001, 0x2501},
    143	{0x20, 0x0500, 0x0001},	/* snapshot mode */
    144	{0x00, 0x0003, 0x2880},
    145	{0x00, 0x0001, 0x2881},
    146};
    147
    148/* Initialisation data for the logitech clicksmart 420 */
    149static const struct cmd spca504A_clicksmart420_init_data[] = {
    150/*	{0xa0, 0x0000, 0x0503},  * capture mode */
    151	{0x00, 0x0000, 0x2000},
    152	{0x00, 0x0013, 0x2301},
    153	{0x00, 0x0003, 0x2000},
    154	{0x00, 0x0001, 0x21ac},
    155	{0x00, 0x0001, 0x21a6},
    156	{0x00, 0x0000, 0x21a7},	/* brightness */
    157	{0x00, 0x0020, 0x21a8},	/* contrast */
    158	{0x00, 0x0001, 0x21ac},	/* sat/hue */
    159	{0x00, 0x0000, 0x21ad},	/* hue */
    160	{0x00, 0x001a, 0x21ae},	/* saturation */
    161	{0x00, 0x0002, 0x21a3},	/* gamma */
    162	{0x30, 0x0004, 0x000a},
    163	{0xb0, 0x0001, 0x0000},
    164
    165	{0xa1, 0x0080, 0x0001},
    166	{0x30, 0x0049, 0x0000},
    167	{0x30, 0x0060, 0x0005},
    168	{0x0c, 0x0004, 0x0000},
    169	{0x00, 0x0000, 0x0000},
    170	{0x00, 0x0000, 0x2000},
    171	{0x00, 0x0013, 0x2301},
    172	{0x00, 0x0003, 0x2000},
    173};
    174
    175/* clicksmart 420 open data ? */
    176static const struct cmd spca504A_clicksmart420_open_data[] = {
    177	{0x00, 0x0001, 0x2501},
    178	{0x20, 0x0502, 0x0000},
    179	{0x06, 0x0000, 0x0000},
    180	{0x00, 0x0004, 0x2880},
    181	{0x00, 0x0001, 0x2881},
    182
    183	{0xa0, 0x0000, 0x0503},
    184};
    185
    186static const u8 qtable_creative_pccam[2][64] = {
    187	{				/* Q-table Y-components */
    188	 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
    189	 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
    190	 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
    191	 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
    192	 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
    193	 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
    194	 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
    195	 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
    196	{				/* Q-table C-components */
    197	 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
    198	 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
    199	 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
    200	 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
    201	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
    202	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
    203	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
    204	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
    205};
    206
    207/* FIXME: This Q-table is identical to the Creative PC-CAM one,
    208 *		except for one byte. Possibly a typo?
    209 *		NWG: 18/05/2003.
    210 */
    211static const u8 qtable_spca504_default[2][64] = {
    212	{				/* Q-table Y-components */
    213	 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
    214	 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
    215	 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
    216	 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
    217	 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
    218	 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
    219	 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
    220	 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
    221	 },
    222	{				/* Q-table C-components */
    223	 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
    224	 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
    225	 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
    226	 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
    227	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
    228	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
    229	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
    230	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
    231};
    232
    233/* read <len> bytes to gspca_dev->usb_buf */
    234static void reg_r(struct gspca_dev *gspca_dev,
    235		  u8 req,
    236		  u16 index,
    237		  u16 len)
    238{
    239	int ret;
    240
    241	if (len > USB_BUF_SZ) {
    242		gspca_err(gspca_dev, "reg_r: buffer overflow\n");
    243		return;
    244	}
    245	if (len == 0) {
    246		gspca_err(gspca_dev, "reg_r: zero-length read\n");
    247		return;
    248	}
    249	if (gspca_dev->usb_err < 0)
    250		return;
    251	ret = usb_control_msg(gspca_dev->dev,
    252			usb_rcvctrlpipe(gspca_dev->dev, 0),
    253			req,
    254			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
    255			0,		/* value */
    256			index,
    257			gspca_dev->usb_buf, len,
    258			500);
    259	if (ret < 0) {
    260		pr_err("reg_r err %d\n", ret);
    261		gspca_dev->usb_err = ret;
    262		/*
    263		 * Make sure the buffer is zeroed to avoid uninitialized
    264		 * values.
    265		 */
    266		memset(gspca_dev->usb_buf, 0, USB_BUF_SZ);
    267	}
    268}
    269
    270/* write one byte */
    271static void reg_w_1(struct gspca_dev *gspca_dev,
    272		   u8 req,
    273		   u16 value,
    274		   u16 index,
    275		   u16 byte)
    276{
    277	int ret;
    278
    279	if (gspca_dev->usb_err < 0)
    280		return;
    281	gspca_dev->usb_buf[0] = byte;
    282	ret = usb_control_msg(gspca_dev->dev,
    283			usb_sndctrlpipe(gspca_dev->dev, 0),
    284			req,
    285			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
    286			value, index,
    287			gspca_dev->usb_buf, 1,
    288			500);
    289	if (ret < 0) {
    290		pr_err("reg_w_1 err %d\n", ret);
    291		gspca_dev->usb_err = ret;
    292	}
    293}
    294
    295/* write req / index / value */
    296static void reg_w_riv(struct gspca_dev *gspca_dev,
    297		     u8 req, u16 index, u16 value)
    298{
    299	struct usb_device *dev = gspca_dev->dev;
    300	int ret;
    301
    302	if (gspca_dev->usb_err < 0)
    303		return;
    304	ret = usb_control_msg(dev,
    305			usb_sndctrlpipe(dev, 0),
    306			req,
    307			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
    308			value, index, NULL, 0, 500);
    309	if (ret < 0) {
    310		pr_err("reg_w_riv err %d\n", ret);
    311		gspca_dev->usb_err = ret;
    312		return;
    313	}
    314	gspca_dbg(gspca_dev, D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x\n",
    315		  req, index, value);
    316}
    317
    318static void write_vector(struct gspca_dev *gspca_dev,
    319			const struct cmd *data, int ncmds)
    320{
    321	while (--ncmds >= 0) {
    322		reg_w_riv(gspca_dev, data->req, data->idx, data->val);
    323		data++;
    324	}
    325}
    326
    327static void setup_qtable(struct gspca_dev *gspca_dev,
    328			const u8 qtable[2][64])
    329{
    330	int i;
    331
    332	/* loop over y components */
    333	for (i = 0; i < 64; i++)
    334		reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
    335
    336	/* loop over c components */
    337	for (i = 0; i < 64; i++)
    338		reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]);
    339}
    340
    341static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
    342			     u8 req, u16 idx, u16 val)
    343{
    344	reg_w_riv(gspca_dev, req, idx, val);
    345	reg_r(gspca_dev, 0x01, 0x0001, 1);
    346	gspca_dbg(gspca_dev, D_FRAM, "before wait 0x%04x\n",
    347		  gspca_dev->usb_buf[0]);
    348	reg_w_riv(gspca_dev, req, idx, val);
    349
    350	msleep(200);
    351	reg_r(gspca_dev, 0x01, 0x0001, 1);
    352	gspca_dbg(gspca_dev, D_FRAM, "after wait 0x%04x\n",
    353		  gspca_dev->usb_buf[0]);
    354}
    355
    356static void spca504_read_info(struct gspca_dev *gspca_dev)
    357{
    358	int i;
    359	u8 info[6];
    360
    361	if (gspca_debug < D_STREAM)
    362		return;
    363
    364	for (i = 0; i < 6; i++) {
    365		reg_r(gspca_dev, 0, i, 1);
    366		info[i] = gspca_dev->usb_buf[0];
    367	}
    368	gspca_dbg(gspca_dev, D_STREAM,
    369		  "Read info: %d %d %d %d %d %d. Should be 1,0,2,2,0,0\n",
    370		  info[0], info[1], info[2],
    371		  info[3], info[4], info[5]);
    372}
    373
    374static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
    375			u8 req,
    376			u16 idx, u16 val, u8 endcode, u8 count)
    377{
    378	u16 status;
    379
    380	reg_w_riv(gspca_dev, req, idx, val);
    381	reg_r(gspca_dev, 0x01, 0x0001, 1);
    382	if (gspca_dev->usb_err < 0)
    383		return;
    384	gspca_dbg(gspca_dev, D_FRAM, "Status 0x%02x Need 0x%02x\n",
    385		  gspca_dev->usb_buf[0], endcode);
    386	if (!count)
    387		return;
    388	count = 200;
    389	while (--count > 0) {
    390		msleep(10);
    391		/* gsmart mini2 write a each wait setting 1 ms is enough */
    392/*		reg_w_riv(gspca_dev, req, idx, val); */
    393		reg_r(gspca_dev, 0x01, 0x0001, 1);
    394		status = gspca_dev->usb_buf[0];
    395		if (status == endcode) {
    396			gspca_dbg(gspca_dev, D_FRAM, "status 0x%04x after wait %d\n",
    397				  status, 200 - count);
    398				break;
    399		}
    400	}
    401}
    402
    403static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
    404{
    405	int count = 10;
    406
    407	while (--count > 0) {
    408		reg_r(gspca_dev, 0x21, 0, 1);
    409		if ((gspca_dev->usb_buf[0] & 0x01) == 0)
    410			break;
    411		msleep(10);
    412	}
    413}
    414
    415static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
    416{
    417	int count = 50;
    418
    419	while (--count > 0) {
    420		reg_r(gspca_dev, 0x21, 1, 1);
    421		if (gspca_dev->usb_buf[0] != 0) {
    422			reg_w_1(gspca_dev, 0x21, 0, 1, 0);
    423			reg_r(gspca_dev, 0x21, 1, 1);
    424			spca504B_PollingDataReady(gspca_dev);
    425			break;
    426		}
    427		msleep(10);
    428	}
    429}
    430
    431static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
    432{
    433	u8 *data;
    434
    435	if (gspca_debug < D_STREAM)
    436		return;
    437
    438	data = gspca_dev->usb_buf;
    439	reg_r(gspca_dev, 0x20, 0, 5);
    440	gspca_dbg(gspca_dev, D_STREAM, "FirmWare: %d %d %d %d %d\n",
    441		  data[0], data[1], data[2], data[3], data[4]);
    442	reg_r(gspca_dev, 0x23, 0, 64);
    443	reg_r(gspca_dev, 0x23, 1, 64);
    444}
    445
    446static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
    447{
    448	struct sd *sd = (struct sd *) gspca_dev;
    449	u8 Size;
    450
    451	Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
    452	switch (sd->bridge) {
    453	case BRIDGE_SPCA533:
    454		reg_w_riv(gspca_dev, 0x31, 0, 0);
    455		spca504B_WaitCmdStatus(gspca_dev);
    456		spca504B_PollingDataReady(gspca_dev);
    457		spca50x_GetFirmware(gspca_dev);
    458
    459		reg_w_1(gspca_dev, 0x24, 0, 8, 2);		/* type */
    460		reg_r(gspca_dev, 0x24, 8, 1);
    461
    462		reg_w_1(gspca_dev, 0x25, 0, 4, Size);
    463		reg_r(gspca_dev, 0x25, 4, 1);			/* size */
    464		spca504B_PollingDataReady(gspca_dev);
    465
    466		/* Init the cam width height with some values get on init ? */
    467		reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
    468		spca504B_WaitCmdStatus(gspca_dev);
    469		spca504B_PollingDataReady(gspca_dev);
    470		break;
    471	default:
    472/* case BRIDGE_SPCA504B: */
    473/* case BRIDGE_SPCA536: */
    474		reg_w_1(gspca_dev, 0x25, 0, 4, Size);
    475		reg_r(gspca_dev, 0x25, 4, 1);			/* size */
    476		reg_w_1(gspca_dev, 0x27, 0, 0, 6);
    477		reg_r(gspca_dev, 0x27, 0, 1);			/* type */
    478		spca504B_PollingDataReady(gspca_dev);
    479		break;
    480	case BRIDGE_SPCA504:
    481		Size += 3;
    482		if (sd->subtype == AiptekMiniPenCam13) {
    483			/* spca504a aiptek */
    484			spca504A_acknowledged_command(gspca_dev,
    485						0x08, Size, 0,
    486						0x80 | (Size & 0x0f), 1);
    487			spca504A_acknowledged_command(gspca_dev,
    488							1, 3, 0, 0x9f, 0);
    489		} else {
    490			spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
    491		}
    492		break;
    493	case BRIDGE_SPCA504C:
    494		/* capture mode */
    495		reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
    496		reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
    497		break;
    498	}
    499}
    500
    501static void spca504_wait_status(struct gspca_dev *gspca_dev)
    502{
    503	int cnt;
    504
    505	cnt = 256;
    506	while (--cnt > 0) {
    507		/* With this we get the status, when return 0 it's all ok */
    508		reg_r(gspca_dev, 0x06, 0x00, 1);
    509		if (gspca_dev->usb_buf[0] == 0)
    510			return;
    511		msleep(10);
    512	}
    513}
    514
    515static void spca504B_setQtable(struct gspca_dev *gspca_dev)
    516{
    517	reg_w_1(gspca_dev, 0x26, 0, 0, 3);
    518	reg_r(gspca_dev, 0x26, 0, 1);
    519	spca504B_PollingDataReady(gspca_dev);
    520}
    521
    522static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
    523{
    524	struct sd *sd = (struct sd *) gspca_dev;
    525	u16 reg;
    526
    527	reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
    528	reg_w_riv(gspca_dev, 0x00, reg, val);
    529}
    530
    531static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
    532{
    533	struct sd *sd = (struct sd *) gspca_dev;
    534	u16 reg;
    535
    536	reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
    537	reg_w_riv(gspca_dev, 0x00, reg, val);
    538}
    539
    540static void setcolors(struct gspca_dev *gspca_dev, s32 val)
    541{
    542	struct sd *sd = (struct sd *) gspca_dev;
    543	u16 reg;
    544
    545	reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
    546	reg_w_riv(gspca_dev, 0x00, reg, val);
    547}
    548
    549static void init_ctl_reg(struct gspca_dev *gspca_dev)
    550{
    551	struct sd *sd = (struct sd *) gspca_dev;
    552	int pollreg = 1;
    553
    554	switch (sd->bridge) {
    555	case BRIDGE_SPCA504:
    556	case BRIDGE_SPCA504C:
    557		pollreg = 0;
    558		fallthrough;
    559	default:
    560/*	case BRIDGE_SPCA533: */
    561/*	case BRIDGE_SPCA504B: */
    562		reg_w_riv(gspca_dev, 0, 0x21ad, 0x00);	/* hue */
    563		reg_w_riv(gspca_dev, 0, 0x21ac, 0x01);	/* sat/hue */
    564		reg_w_riv(gspca_dev, 0, 0x21a3, 0x00);	/* gamma */
    565		break;
    566	case BRIDGE_SPCA536:
    567		reg_w_riv(gspca_dev, 0, 0x20f5, 0x40);
    568		reg_w_riv(gspca_dev, 0, 0x20f4, 0x01);
    569		reg_w_riv(gspca_dev, 0, 0x2089, 0x00);
    570		break;
    571	}
    572	if (pollreg)
    573		spca504B_PollingDataReady(gspca_dev);
    574}
    575
    576/* this function is called at probe time */
    577static int sd_config(struct gspca_dev *gspca_dev,
    578			const struct usb_device_id *id)
    579{
    580	struct sd *sd = (struct sd *) gspca_dev;
    581	struct cam *cam;
    582
    583	cam = &gspca_dev->cam;
    584
    585	sd->bridge = id->driver_info >> 8;
    586	sd->subtype = id->driver_info;
    587
    588	if (sd->subtype == AiptekMiniPenCam13) {
    589
    590		/* try to get the firmware as some cam answer 2.0.1.2.2
    591		 * and should be a spca504b then overwrite that setting */
    592		reg_r(gspca_dev, 0x20, 0, 1);
    593		switch (gspca_dev->usb_buf[0]) {
    594		case 1:
    595			break;		/* (right bridge/subtype) */
    596		case 2:
    597			sd->bridge = BRIDGE_SPCA504B;
    598			sd->subtype = 0;
    599			break;
    600		default:
    601			return -ENODEV;
    602		}
    603	}
    604
    605	switch (sd->bridge) {
    606	default:
    607/*	case BRIDGE_SPCA504B: */
    608/*	case BRIDGE_SPCA504: */
    609/*	case BRIDGE_SPCA536: */
    610		cam->cam_mode = vga_mode;
    611		cam->nmodes = ARRAY_SIZE(vga_mode);
    612		break;
    613	case BRIDGE_SPCA533:
    614		cam->cam_mode = custom_mode;
    615		if (sd->subtype == MegaImageVI)		/* 320x240 only */
    616			cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
    617		else
    618			cam->nmodes = ARRAY_SIZE(custom_mode);
    619		break;
    620	case BRIDGE_SPCA504C:
    621		cam->cam_mode = vga_mode2;
    622		cam->nmodes = ARRAY_SIZE(vga_mode2);
    623		break;
    624	}
    625	return 0;
    626}
    627
    628/* this function is called at probe and resume time */
    629static int sd_init(struct gspca_dev *gspca_dev)
    630{
    631	struct sd *sd = (struct sd *) gspca_dev;
    632
    633	switch (sd->bridge) {
    634	case BRIDGE_SPCA504B:
    635		reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
    636		reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01);
    637		reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00);
    638		reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00);
    639		reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13);
    640		reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00);
    641		fallthrough;
    642	case BRIDGE_SPCA533:
    643		spca504B_PollingDataReady(gspca_dev);
    644		spca50x_GetFirmware(gspca_dev);
    645		break;
    646	case BRIDGE_SPCA536:
    647		spca50x_GetFirmware(gspca_dev);
    648		reg_r(gspca_dev, 0x00, 0x5002, 1);
    649		reg_w_1(gspca_dev, 0x24, 0, 0, 0);
    650		reg_r(gspca_dev, 0x24, 0, 1);
    651		spca504B_PollingDataReady(gspca_dev);
    652		reg_w_riv(gspca_dev, 0x34, 0, 0);
    653		spca504B_WaitCmdStatus(gspca_dev);
    654		break;
    655	case BRIDGE_SPCA504C:	/* pccam600 */
    656		gspca_dbg(gspca_dev, D_STREAM, "Opening SPCA504 (PC-CAM 600)\n");
    657		reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000);
    658		reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001);	/* reset */
    659		spca504_wait_status(gspca_dev);
    660		if (sd->subtype == LogitechClickSmart420)
    661			write_vector(gspca_dev,
    662				spca504A_clicksmart420_open_data,
    663				ARRAY_SIZE(spca504A_clicksmart420_open_data));
    664		else
    665			write_vector(gspca_dev, spca504_pccam600_open_data,
    666				ARRAY_SIZE(spca504_pccam600_open_data));
    667		setup_qtable(gspca_dev, qtable_creative_pccam);
    668		break;
    669	default:
    670/*	case BRIDGE_SPCA504: */
    671		gspca_dbg(gspca_dev, D_STREAM, "Opening SPCA504\n");
    672		if (sd->subtype == AiptekMiniPenCam13) {
    673			spca504_read_info(gspca_dev);
    674
    675			/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
    676			spca504A_acknowledged_command(gspca_dev, 0x24,
    677							8, 3, 0x9e, 1);
    678			/* Twice sequential need status 0xff->0x9e->0x9d */
    679			spca504A_acknowledged_command(gspca_dev, 0x24,
    680							8, 3, 0x9e, 0);
    681
    682			spca504A_acknowledged_command(gspca_dev, 0x24,
    683							0, 0, 0x9d, 1);
    684			/******************************/
    685			/* spca504a aiptek */
    686			spca504A_acknowledged_command(gspca_dev, 0x08,
    687							6, 0, 0x86, 1);
    688/*			reg_write (dev, 0, 0x2000, 0); */
    689/*			reg_write (dev, 0, 0x2883, 1); */
    690/*			spca504A_acknowledged_command (gspca_dev, 0x08,
    691							6, 0, 0x86, 1); */
    692/*			spca504A_acknowledged_command (gspca_dev, 0x24,
    693							0, 0, 0x9D, 1); */
    694			reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
    695							/* L92 sno1t.txt */
    696			reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
    697			spca504A_acknowledged_command(gspca_dev, 0x01,
    698							0x0f, 0, 0xff, 0);
    699		}
    700		/* setup qtable */
    701		reg_w_riv(gspca_dev, 0, 0x2000, 0);
    702		reg_w_riv(gspca_dev, 0, 0x2883, 1);
    703		setup_qtable(gspca_dev, qtable_spca504_default);
    704		break;
    705	}
    706	return gspca_dev->usb_err;
    707}
    708
    709static int sd_start(struct gspca_dev *gspca_dev)
    710{
    711	struct sd *sd = (struct sd *) gspca_dev;
    712	int enable;
    713
    714	/* create the JPEG header */
    715	jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
    716			gspca_dev->pixfmt.width,
    717			0x22);		/* JPEG 411 */
    718	jpeg_set_qual(sd->jpeg_hdr, QUALITY);
    719
    720	if (sd->bridge == BRIDGE_SPCA504B)
    721		spca504B_setQtable(gspca_dev);
    722	spca504B_SetSizeType(gspca_dev);
    723	switch (sd->bridge) {
    724	default:
    725/*	case BRIDGE_SPCA504B: */
    726/*	case BRIDGE_SPCA533: */
    727/*	case BRIDGE_SPCA536: */
    728		switch (sd->subtype) {
    729		case MegapixV4:
    730		case LogitechClickSmart820:
    731		case MegaImageVI:
    732			reg_w_riv(gspca_dev, 0xf0, 0, 0);
    733			spca504B_WaitCmdStatus(gspca_dev);
    734			reg_w_riv(gspca_dev, 0xf0, 4, 0);
    735			spca504B_WaitCmdStatus(gspca_dev);
    736			break;
    737		default:
    738			reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
    739			spca504B_WaitCmdStatus(gspca_dev);
    740			spca504B_PollingDataReady(gspca_dev);
    741			break;
    742		}
    743		break;
    744	case BRIDGE_SPCA504:
    745		if (sd->subtype == AiptekMiniPenCam13) {
    746			spca504_read_info(gspca_dev);
    747
    748			/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
    749			spca504A_acknowledged_command(gspca_dev, 0x24,
    750							8, 3, 0x9e, 1);
    751			/* Twice sequential need status 0xff->0x9e->0x9d */
    752			spca504A_acknowledged_command(gspca_dev, 0x24,
    753							8, 3, 0x9e, 0);
    754			spca504A_acknowledged_command(gspca_dev, 0x24,
    755							0, 0, 0x9d, 1);
    756		} else {
    757			spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
    758			spca504_read_info(gspca_dev);
    759			spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
    760			spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
    761		}
    762		spca504B_SetSizeType(gspca_dev);
    763		reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
    764							/* L92 sno1t.txt */
    765		reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
    766		break;
    767	case BRIDGE_SPCA504C:
    768		if (sd->subtype == LogitechClickSmart420) {
    769			write_vector(gspca_dev,
    770				spca504A_clicksmart420_init_data,
    771				ARRAY_SIZE(spca504A_clicksmart420_init_data));
    772		} else {
    773			write_vector(gspca_dev, spca504_pccam600_init_data,
    774				ARRAY_SIZE(spca504_pccam600_init_data));
    775		}
    776		enable = (sd->autogain ? 0x04 : 0x01);
    777		reg_w_riv(gspca_dev, 0x0c, 0x0000, enable);
    778							/* auto exposure */
    779		reg_w_riv(gspca_dev, 0xb0, 0x0000, enable);
    780							/* auto whiteness */
    781
    782		/* set default exposure compensation and whiteness balance */
    783		reg_w_riv(gspca_dev, 0x30, 0x0001, 800);	/* ~ 20 fps */
    784		reg_w_riv(gspca_dev, 0x30, 0x0002, 1600);
    785		spca504B_SetSizeType(gspca_dev);
    786		break;
    787	}
    788	init_ctl_reg(gspca_dev);
    789	return gspca_dev->usb_err;
    790}
    791
    792static void sd_stopN(struct gspca_dev *gspca_dev)
    793{
    794	struct sd *sd = (struct sd *) gspca_dev;
    795
    796	switch (sd->bridge) {
    797	default:
    798/*	case BRIDGE_SPCA533: */
    799/*	case BRIDGE_SPCA536: */
    800/*	case BRIDGE_SPCA504B: */
    801		reg_w_riv(gspca_dev, 0x31, 0, 0);
    802		spca504B_WaitCmdStatus(gspca_dev);
    803		spca504B_PollingDataReady(gspca_dev);
    804		break;
    805	case BRIDGE_SPCA504:
    806	case BRIDGE_SPCA504C:
    807		reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000);
    808
    809		if (sd->subtype == AiptekMiniPenCam13) {
    810			/* spca504a aiptek */
    811/*			spca504A_acknowledged_command(gspca_dev, 0x08,
    812							 6, 0, 0x86, 1); */
    813			spca504A_acknowledged_command(gspca_dev, 0x24,
    814							0x00, 0x00, 0x9d, 1);
    815			spca504A_acknowledged_command(gspca_dev, 0x01,
    816							0x0f, 0x00, 0xff, 1);
    817		} else {
    818			spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
    819			reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000);
    820		}
    821		break;
    822	}
    823}
    824
    825static void sd_pkt_scan(struct gspca_dev *gspca_dev,
    826			u8 *data,			/* isoc packet */
    827			int len)			/* iso packet length */
    828{
    829	struct sd *sd = (struct sd *) gspca_dev;
    830	int i, sof = 0;
    831	static u8 ffd9[] = {0xff, 0xd9};
    832
    833/* frames are jpeg 4.1.1 without 0xff escape */
    834	switch (sd->bridge) {
    835	case BRIDGE_SPCA533:
    836		if (data[0] == 0xff) {
    837			if (data[1] != 0x01) {	/* drop packet */
    838/*				gspca_dev->last_packet_type = DISCARD_PACKET; */
    839				return;
    840			}
    841			sof = 1;
    842			data += SPCA533_OFFSET_DATA;
    843			len -= SPCA533_OFFSET_DATA;
    844		} else {
    845			data += 1;
    846			len -= 1;
    847		}
    848		break;
    849	case BRIDGE_SPCA536:
    850		if (data[0] == 0xff) {
    851			sof = 1;
    852			data += SPCA536_OFFSET_DATA;
    853			len -= SPCA536_OFFSET_DATA;
    854		} else {
    855			data += 2;
    856			len -= 2;
    857		}
    858		break;
    859	default:
    860/*	case BRIDGE_SPCA504: */
    861/*	case BRIDGE_SPCA504B: */
    862		switch (data[0]) {
    863		case 0xfe:			/* start of frame */
    864			sof = 1;
    865			data += SPCA50X_OFFSET_DATA;
    866			len -= SPCA50X_OFFSET_DATA;
    867			break;
    868		case 0xff:			/* drop packet */
    869/*			gspca_dev->last_packet_type = DISCARD_PACKET; */
    870			return;
    871		default:
    872			data += 1;
    873			len -= 1;
    874			break;
    875		}
    876		break;
    877	case BRIDGE_SPCA504C:
    878		switch (data[0]) {
    879		case 0xfe:			/* start of frame */
    880			sof = 1;
    881			data += SPCA504_PCCAM600_OFFSET_DATA;
    882			len -= SPCA504_PCCAM600_OFFSET_DATA;
    883			break;
    884		case 0xff:			/* drop packet */
    885/*			gspca_dev->last_packet_type = DISCARD_PACKET; */
    886			return;
    887		default:
    888			data += 1;
    889			len -= 1;
    890			break;
    891		}
    892		break;
    893	}
    894	if (sof) {		/* start of frame */
    895		gspca_frame_add(gspca_dev, LAST_PACKET,
    896				ffd9, 2);
    897
    898		/* put the JPEG header in the new frame */
    899		gspca_frame_add(gspca_dev, FIRST_PACKET,
    900			sd->jpeg_hdr, JPEG_HDR_SZ);
    901	}
    902
    903	/* add 0x00 after 0xff */
    904	i = 0;
    905	do {
    906		if (data[i] == 0xff) {
    907			gspca_frame_add(gspca_dev, INTER_PACKET,
    908					data, i + 1);
    909			len -= i;
    910			data += i;
    911			*data = 0x00;
    912			i = 0;
    913		}
    914		i++;
    915	} while (i < len);
    916	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
    917}
    918
    919static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
    920{
    921	struct gspca_dev *gspca_dev =
    922		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
    923	struct sd *sd = (struct sd *)gspca_dev;
    924
    925	gspca_dev->usb_err = 0;
    926
    927	if (!gspca_dev->streaming)
    928		return 0;
    929
    930	switch (ctrl->id) {
    931	case V4L2_CID_BRIGHTNESS:
    932		setbrightness(gspca_dev, ctrl->val);
    933		break;
    934	case V4L2_CID_CONTRAST:
    935		setcontrast(gspca_dev, ctrl->val);
    936		break;
    937	case V4L2_CID_SATURATION:
    938		setcolors(gspca_dev, ctrl->val);
    939		break;
    940	case V4L2_CID_AUTOGAIN:
    941		sd->autogain = ctrl->val;
    942		break;
    943	}
    944	return gspca_dev->usb_err;
    945}
    946
    947static const struct v4l2_ctrl_ops sd_ctrl_ops = {
    948	.s_ctrl = sd_s_ctrl,
    949};
    950
    951static int sd_init_controls(struct gspca_dev *gspca_dev)
    952{
    953	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
    954
    955	gspca_dev->vdev.ctrl_handler = hdl;
    956	v4l2_ctrl_handler_init(hdl, 4);
    957	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
    958			V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
    959	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
    960			V4L2_CID_CONTRAST, 0, 255, 1, 0x20);
    961	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
    962			V4L2_CID_SATURATION, 0, 255, 1, 0x1a);
    963	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
    964			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
    965
    966	if (hdl->error) {
    967		pr_err("Could not initialize controls\n");
    968		return hdl->error;
    969	}
    970	return 0;
    971}
    972
    973/* sub-driver description */
    974static const struct sd_desc sd_desc = {
    975	.name = MODULE_NAME,
    976	.config = sd_config,
    977	.init = sd_init,
    978	.init_controls = sd_init_controls,
    979	.start = sd_start,
    980	.stopN = sd_stopN,
    981	.pkt_scan = sd_pkt_scan,
    982};
    983
    984/* -- module initialisation -- */
    985#define BS(bridge, subtype) \
    986	.driver_info = (BRIDGE_ ## bridge << 8) \
    987			| (subtype)
    988static const struct usb_device_id device_table[] = {
    989	{USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
    990	{USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
    991	{USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
    992	{USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
    993	{USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
    994	{USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
    995	{USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
    996	{USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
    997	{USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
    998	{USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
    999	{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};
   1051MODULE_DEVICE_TABLE(usb, device_table);
   1052
   1053/* -- device connect -- */
   1054static 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
   1061static 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
   1073module_usb_driver(sd_driver);