1/*
2 *		Sunplus spca504(abc) spca533 spca536 library
3 *		Copyright (C) 2005 Michel Xhaard mxhaard@magic.fr
4 *
5 * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
23
24#define MODULE_NAME "sunplus"
25
26#include "gspca.h"
27#include "jpeg.h"
28
29MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
30MODULE_DESCRIPTION("GSPCA/SPCA5xx USB Camera Driver");
31MODULE_LICENSE("GPL");
32
33/* specific webcam descriptor */
34struct sd {
35	struct gspca_dev gspca_dev;	/* !! must be the first item */
36
37	s8 brightness;
38	u8 contrast;
39	u8 colors;
40	u8 autogain;
41	u8 quality;
42#define QUALITY_MIN 70
43#define QUALITY_MAX 95
44#define QUALITY_DEF 85
45
46	u8 bridge;
47#define BRIDGE_SPCA504 0
48#define BRIDGE_SPCA504B 1
49#define BRIDGE_SPCA504C 2
50#define BRIDGE_SPCA533 3
51#define BRIDGE_SPCA536 4
52	u8 subtype;
53#define AiptekMiniPenCam13 1
54#define LogitechClickSmart420 2
55#define LogitechClickSmart820 3
56#define MegapixV4 4
57#define MegaImageVI 5
58
59	u8 jpeg_hdr[JPEG_HDR_SZ];
60};
61
62/* V4L2 controls supported by the driver */
63static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
64static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
65static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
66static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
67static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
68static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
69static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
70static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
71
72static const struct ctrl sd_ctrls[] = {
73	{
74	    {
75		.id      = V4L2_CID_BRIGHTNESS,
76		.type    = V4L2_CTRL_TYPE_INTEGER,
77		.name    = "Brightness",
78		.minimum = -128,
79		.maximum = 127,
80		.step    = 1,
81#define BRIGHTNESS_DEF 0
82		.default_value = BRIGHTNESS_DEF,
83	    },
84	    .set = sd_setbrightness,
85	    .get = sd_getbrightness,
86	},
87	{
88	    {
89		.id      = V4L2_CID_CONTRAST,
90		.type    = V4L2_CTRL_TYPE_INTEGER,
91		.name    = "Contrast",
92		.minimum = 0,
93		.maximum = 0xff,
94		.step    = 1,
95#define CONTRAST_DEF 0x20
96		.default_value = CONTRAST_DEF,
97	    },
98	    .set = sd_setcontrast,
99	    .get = sd_getcontrast,
100	},
101	{
102	    {
103		.id      = V4L2_CID_SATURATION,
104		.type    = V4L2_CTRL_TYPE_INTEGER,
105		.name    = "Color",
106		.minimum = 0,
107		.maximum = 0xff,
108		.step    = 1,
109#define COLOR_DEF 0x1a
110		.default_value = COLOR_DEF,
111	    },
112	    .set = sd_setcolors,
113	    .get = sd_getcolors,
114	},
115	{
116	    {
117		.id      = V4L2_CID_AUTOGAIN,
118		.type    = V4L2_CTRL_TYPE_BOOLEAN,
119		.name    = "Auto Gain",
120		.minimum = 0,
121		.maximum = 1,
122		.step    = 1,
123#define AUTOGAIN_DEF 1
124		.default_value = AUTOGAIN_DEF,
125	    },
126	    .set = sd_setautogain,
127	    .get = sd_getautogain,
128	},
129};
130
131static const struct v4l2_pix_format vga_mode[] = {
132	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
133		.bytesperline = 320,
134		.sizeimage = 320 * 240 * 3 / 8 + 590,
135		.colorspace = V4L2_COLORSPACE_JPEG,
136		.priv = 2},
137	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
138		.bytesperline = 640,
139		.sizeimage = 640 * 480 * 3 / 8 + 590,
140		.colorspace = V4L2_COLORSPACE_JPEG,
141		.priv = 1},
142};
143
144static const struct v4l2_pix_format custom_mode[] = {
145	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
146		.bytesperline = 320,
147		.sizeimage = 320 * 240 * 3 / 8 + 590,
148		.colorspace = V4L2_COLORSPACE_JPEG,
149		.priv = 2},
150	{464, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
151		.bytesperline = 464,
152		.sizeimage = 464 * 480 * 3 / 8 + 590,
153		.colorspace = V4L2_COLORSPACE_JPEG,
154		.priv = 1},
155};
156
157static const struct v4l2_pix_format vga_mode2[] = {
158	{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
159		.bytesperline = 176,
160		.sizeimage = 176 * 144 * 3 / 8 + 590,
161		.colorspace = V4L2_COLORSPACE_JPEG,
162		.priv = 4},
163	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
164		.bytesperline = 320,
165		.sizeimage = 320 * 240 * 3 / 8 + 590,
166		.colorspace = V4L2_COLORSPACE_JPEG,
167		.priv = 3},
168	{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
169		.bytesperline = 352,
170		.sizeimage = 352 * 288 * 3 / 8 + 590,
171		.colorspace = V4L2_COLORSPACE_JPEG,
172		.priv = 2},
173	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
174		.bytesperline = 640,
175		.sizeimage = 640 * 480 * 3 / 8 + 590,
176		.colorspace = V4L2_COLORSPACE_JPEG,
177		.priv = 1},
178};
179
180#define SPCA50X_OFFSET_DATA 10
181#define SPCA504_PCCAM600_OFFSET_SNAPSHOT 3
182#define SPCA504_PCCAM600_OFFSET_COMPRESS 4
183#define SPCA504_PCCAM600_OFFSET_MODE	 5
184#define SPCA504_PCCAM600_OFFSET_DATA	 14
185 /* Frame packet header offsets for the spca533 */
186#define SPCA533_OFFSET_DATA	16
187#define SPCA533_OFFSET_FRAMSEQ	15
188/* Frame packet header offsets for the spca536 */
189#define SPCA536_OFFSET_DATA	4
190#define SPCA536_OFFSET_FRAMSEQ	1
191
192struct cmd {
193	u8 req;
194	u16 val;
195	u16 idx;
196};
197
198/* Initialisation data for the Creative PC-CAM 600 */
199static const struct cmd spca504_pccam600_init_data[] = {
200/*	{0xa0, 0x0000, 0x0503},  * capture mode */
201	{0x00, 0x0000, 0x2000},
202	{0x00, 0x0013, 0x2301},
203	{0x00, 0x0003, 0x2000},
204	{0x00, 0x0001, 0x21ac},
205	{0x00, 0x0001, 0x21a6},
206	{0x00, 0x0000, 0x21a7},	/* brightness */
207	{0x00, 0x0020, 0x21a8},	/* contrast */
208	{0x00, 0x0001, 0x21ac},	/* sat/hue */
209	{0x00, 0x0000, 0x21ad},	/* hue */
210	{0x00, 0x001a, 0x21ae},	/* saturation */
211	{0x00, 0x0002, 0x21a3},	/* gamma */
212	{0x30, 0x0154, 0x0008},
213	{0x30, 0x0004, 0x0006},
214	{0x30, 0x0258, 0x0009},
215	{0x30, 0x0004, 0x0000},
216	{0x30, 0x0093, 0x0004},
217	{0x30, 0x0066, 0x0005},
218	{0x00, 0x0000, 0x2000},
219	{0x00, 0x0013, 0x2301},
220	{0x00, 0x0003, 0x2000},
221	{0x00, 0x0013, 0x2301},
222	{0x00, 0x0003, 0x2000},
223};
224
225/* Creative PC-CAM 600 specific open data, sent before using the
226 * generic initialisation data from spca504_open_data.
227 */
228static const struct cmd spca504_pccam600_open_data[] = {
229	{0x00, 0x0001, 0x2501},
230	{0x20, 0x0500, 0x0001},	/* snapshot mode */
231	{0x00, 0x0003, 0x2880},
232	{0x00, 0x0001, 0x2881},
233};
234
235/* Initialisation data for the logitech clicksmart 420 */
236static const struct cmd spca504A_clicksmart420_init_data[] = {
237/*	{0xa0, 0x0000, 0x0503},  * capture mode */
238	{0x00, 0x0000, 0x2000},
239	{0x00, 0x0013, 0x2301},
240	{0x00, 0x0003, 0x2000},
241	{0x00, 0x0001, 0x21ac},
242	{0x00, 0x0001, 0x21a6},
243	{0x00, 0x0000, 0x21a7},	/* brightness */
244	{0x00, 0x0020, 0x21a8},	/* contrast */
245	{0x00, 0x0001, 0x21ac},	/* sat/hue */
246	{0x00, 0x0000, 0x21ad},	/* hue */
247	{0x00, 0x001a, 0x21ae},	/* saturation */
248	{0x00, 0x0002, 0x21a3},	/* gamma */
249	{0x30, 0x0004, 0x000a},
250	{0xb0, 0x0001, 0x0000},
251
252	{0xa1, 0x0080, 0x0001},
253	{0x30, 0x0049, 0x0000},
254	{0x30, 0x0060, 0x0005},
255	{0x0c, 0x0004, 0x0000},
256	{0x00, 0x0000, 0x0000},
257	{0x00, 0x0000, 0x2000},
258	{0x00, 0x0013, 0x2301},
259	{0x00, 0x0003, 0x2000},
260};
261
262/* clicksmart 420 open data ? */
263static const struct cmd spca504A_clicksmart420_open_data[] = {
264	{0x00, 0x0001, 0x2501},
265	{0x20, 0x0502, 0x0000},
266	{0x06, 0x0000, 0x0000},
267	{0x00, 0x0004, 0x2880},
268	{0x00, 0x0001, 0x2881},
269
270	{0xa0, 0x0000, 0x0503},
271};
272
273static const u8 qtable_creative_pccam[2][64] = {
274	{				/* Q-table Y-components */
275	 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
276	 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
277	 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
278	 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
279	 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
280	 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
281	 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
282	 0x16, 0x1c, 0x1d, 0x1d, 0x22, 0x1e, 0x1f, 0x1e},
283	{				/* Q-table C-components */
284	 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
285	 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
286	 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
287	 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
288	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
289	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
290	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
291	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
292};
293
294/* FIXME: This Q-table is identical to the Creative PC-CAM one,
295 *		except for one byte. Possibly a typo?
296 *		NWG: 18/05/2003.
297 */
298static const u8 qtable_spca504_default[2][64] = {
299	{				/* Q-table Y-components */
300	 0x05, 0x03, 0x03, 0x05, 0x07, 0x0c, 0x0f, 0x12,
301	 0x04, 0x04, 0x04, 0x06, 0x08, 0x11, 0x12, 0x11,
302	 0x04, 0x04, 0x05, 0x07, 0x0c, 0x11, 0x15, 0x11,
303	 0x04, 0x05, 0x07, 0x09, 0x0f, 0x1a, 0x18, 0x13,
304	 0x05, 0x07, 0x0b, 0x11, 0x14, 0x21, 0x1f, 0x17,
305	 0x07, 0x0b, 0x11, 0x13, 0x18, 0x1f, 0x22, 0x1c,
306	 0x0f, 0x13, 0x17, 0x1a, 0x1f, 0x24, 0x24, 0x1e,
307	 0x16, 0x1c, 0x1d, 0x1d, 0x1d /* 0x22 */ , 0x1e, 0x1f, 0x1e,
308	 },
309	{				/* Q-table C-components */
310	 0x05, 0x05, 0x07, 0x0e, 0x1e, 0x1e, 0x1e, 0x1e,
311	 0x05, 0x06, 0x08, 0x14, 0x1e, 0x1e, 0x1e, 0x1e,
312	 0x07, 0x08, 0x11, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
313	 0x0e, 0x14, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
314	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
315	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
316	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
317	 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e}
318};
319
320/* read <len> bytes to gspca_dev->usb_buf */
321static void reg_r(struct gspca_dev *gspca_dev,
322		  u8 req,
323		  u16 index,
324		  u16 len)
325{
326	int ret;
327
328#ifdef GSPCA_DEBUG
329	if (len > USB_BUF_SZ) {
330		pr_err("reg_r: buffer overflow\n");
331		return;
332	}
333#endif
334	if (gspca_dev->usb_err < 0)
335		return;
336	ret = usb_control_msg(gspca_dev->dev,
337			usb_rcvctrlpipe(gspca_dev->dev, 0),
338			req,
339			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
340			0,		/* value */
341			index,
342			len ? gspca_dev->usb_buf : NULL, len,
343			500);
344	if (ret < 0) {
345		pr_err("reg_r err %d\n", ret);
346		gspca_dev->usb_err = ret;
347	}
348}
349
350/* write one byte */
351static void reg_w_1(struct gspca_dev *gspca_dev,
352		   u8 req,
353		   u16 value,
354		   u16 index,
355		   u16 byte)
356{
357	int ret;
358
359	if (gspca_dev->usb_err < 0)
360		return;
361	gspca_dev->usb_buf[0] = byte;
362	ret = usb_control_msg(gspca_dev->dev,
363			usb_sndctrlpipe(gspca_dev->dev, 0),
364			req,
365			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
366			value, index,
367			gspca_dev->usb_buf, 1,
368			500);
369	if (ret < 0) {
370		pr_err("reg_w_1 err %d\n", ret);
371		gspca_dev->usb_err = ret;
372	}
373}
374
375/* write req / index / value */
376static void reg_w_riv(struct gspca_dev *gspca_dev,
377		     u8 req, u16 index, u16 value)
378{
379	struct usb_device *dev = gspca_dev->dev;
380	int ret;
381
382	if (gspca_dev->usb_err < 0)
383		return;
384	ret = usb_control_msg(dev,
385			usb_sndctrlpipe(dev, 0),
386			req,
387			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
388			value, index, NULL, 0, 500);
389	if (ret < 0) {
390		pr_err("reg_w_riv err %d\n", ret);
391		gspca_dev->usb_err = ret;
392		return;
393	}
394	PDEBUG(D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x",
395		req, index, value);
396}
397
398static void write_vector(struct gspca_dev *gspca_dev,
399			const struct cmd *data, int ncmds)
400{
401	while (--ncmds >= 0) {
402		reg_w_riv(gspca_dev, data->req, data->idx, data->val);
403		data++;
404	}
405}
406
407static void setup_qtable(struct gspca_dev *gspca_dev,
408			const u8 qtable[2][64])
409{
410	int i;
411
412	/* loop over y components */
413	for (i = 0; i < 64; i++)
414		reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
415
416	/* loop over c components */
417	for (i = 0; i < 64; i++)
418		reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]);
419}
420
421static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
422			     u8 req, u16 idx, u16 val)
423{
424	reg_w_riv(gspca_dev, req, idx, val);
425	reg_r(gspca_dev, 0x01, 0x0001, 1);
426	PDEBUG(D_FRAM, "before wait 0x%04x", gspca_dev->usb_buf[0]);
427	reg_w_riv(gspca_dev, req, idx, val);
428
429	msleep(200);
430	reg_r(gspca_dev, 0x01, 0x0001, 1);
431	PDEBUG(D_FRAM, "after wait 0x%04x", gspca_dev->usb_buf[0]);
432}
433
434#ifdef GSPCA_DEBUG
435static void spca504_read_info(struct gspca_dev *gspca_dev)
436{
437	int i;
438	u8 info[6];
439
440	for (i = 0; i < 6; i++) {
441		reg_r(gspca_dev, 0, i, 1);
442		info[i] = gspca_dev->usb_buf[0];
443	}
444	PDEBUG(D_STREAM,
445		"Read info: %d %d %d %d %d %d."
446		" Should be 1,0,2,2,0,0",
447		info[0], info[1], info[2],
448		info[3], info[4], info[5]);
449}
450#endif
451
452static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
453			u8 req,
454			u16 idx, u16 val, u8 endcode, u8 count)
455{
456	u16 status;
457
458	reg_w_riv(gspca_dev, req, idx, val);
459	reg_r(gspca_dev, 0x01, 0x0001, 1);
460	if (gspca_dev->usb_err < 0)
461		return;
462	PDEBUG(D_FRAM, "Status 0x%02x Need 0x%02x",
463			gspca_dev->usb_buf[0], endcode);
464	if (!count)
465		return;
466	count = 200;
467	while (--count > 0) {
468		msleep(10);
469		/* gsmart mini2 write a each wait setting 1 ms is enough */
470/*		reg_w_riv(gspca_dev, req, idx, val); */
471		reg_r(gspca_dev, 0x01, 0x0001, 1);
472		status = gspca_dev->usb_buf[0];
473		if (status == endcode) {
474			PDEBUG(D_FRAM, "status 0x%04x after wait %d",
475				status, 200 - count);
476				break;
477		}
478	}
479}
480
481static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
482{
483	int count = 10;
484
485	while (--count > 0) {
486		reg_r(gspca_dev, 0x21, 0, 1);
487		if ((gspca_dev->usb_buf[0] & 0x01) == 0)
488			break;
489		msleep(10);
490	}
491}
492
493static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
494{
495	int count = 50;
496
497	while (--count > 0) {
498		reg_r(gspca_dev, 0x21, 1, 1);
499		if (gspca_dev->usb_buf[0] != 0) {
500			reg_w_1(gspca_dev, 0x21, 0, 1, 0);
501			reg_r(gspca_dev, 0x21, 1, 1);
502			spca504B_PollingDataReady(gspca_dev);
503			break;
504		}
505		msleep(10);
506	}
507}
508
509#ifdef GSPCA_DEBUG
510static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
511{
512	u8 *data;
513
514	data = gspca_dev->usb_buf;
515	reg_r(gspca_dev, 0x20, 0, 5);
516	PDEBUG(D_STREAM, "FirmWare: %d %d %d %d %d",
517		data[0], data[1], data[2], data[3], data[4]);
518	reg_r(gspca_dev, 0x23, 0, 64);
519	reg_r(gspca_dev, 0x23, 1, 64);
520}
521#endif
522
523static void spca504B_SetSizeType(struct gspca_dev *gspca_dev)
524{
525	struct sd *sd = (struct sd *) gspca_dev;
526	u8 Size;
527
528	Size = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
529	switch (sd->bridge) {
530	case BRIDGE_SPCA533:
531		reg_w_riv(gspca_dev, 0x31, 0, 0);
532		spca504B_WaitCmdStatus(gspca_dev);
533		spca504B_PollingDataReady(gspca_dev);
534#ifdef GSPCA_DEBUG
535		spca50x_GetFirmware(gspca_dev);
536#endif
537		reg_w_1(gspca_dev, 0x24, 0, 8, 2);		/* type */
538		reg_r(gspca_dev, 0x24, 8, 1);
539
540		reg_w_1(gspca_dev, 0x25, 0, 4, Size);
541		reg_r(gspca_dev, 0x25, 4, 1);			/* size */
542		spca504B_PollingDataReady(gspca_dev);
543
544		/* Init the cam width height with some values get on init ? */
545		reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
546		spca504B_WaitCmdStatus(gspca_dev);
547		spca504B_PollingDataReady(gspca_dev);
548		break;
549	default:
550/* case BRIDGE_SPCA504B: */
551/* case BRIDGE_SPCA536: */
552		reg_w_1(gspca_dev, 0x25, 0, 4, Size);
553		reg_r(gspca_dev, 0x25, 4, 1);			/* size */
554		reg_w_1(gspca_dev, 0x27, 0, 0, 6);
555		reg_r(gspca_dev, 0x27, 0, 1);			/* type */
556		spca504B_PollingDataReady(gspca_dev);
557		break;
558	case BRIDGE_SPCA504:
559		Size += 3;
560		if (sd->subtype == AiptekMiniPenCam13) {
561			/* spca504a aiptek */
562			spca504A_acknowledged_command(gspca_dev,
563						0x08, Size, 0,
564						0x80 | (Size & 0x0f), 1);
565			spca504A_acknowledged_command(gspca_dev,
566							1, 3, 0, 0x9f, 0);
567		} else {
568			spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
569		}
570		break;
571	case BRIDGE_SPCA504C:
572		/* capture mode */
573		reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
574		reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
575		break;
576	}
577}
578
579static void spca504_wait_status(struct gspca_dev *gspca_dev)
580{
581	int cnt;
582
583	cnt = 256;
584	while (--cnt > 0) {
585		/* With this we get the status, when return 0 it's all ok */
586		reg_r(gspca_dev, 0x06, 0x00, 1);
587		if (gspca_dev->usb_buf[0] == 0)
588			return;
589		msleep(10);
590	}
591}
592
593static void spca504B_setQtable(struct gspca_dev *gspca_dev)
594{
595	reg_w_1(gspca_dev, 0x26, 0, 0, 3);
596	reg_r(gspca_dev, 0x26, 0, 1);
597	spca504B_PollingDataReady(gspca_dev);
598}
599
600static void setbrightness(struct gspca_dev *gspca_dev)
601{
602	struct sd *sd = (struct sd *) gspca_dev;
603	u16 reg;
604
605	reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
606	reg_w_riv(gspca_dev, 0x00, reg, sd->brightness);
607}
608
609static void setcontrast(struct gspca_dev *gspca_dev)
610{
611	struct sd *sd = (struct sd *) gspca_dev;
612	u16 reg;
613
614	reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
615	reg_w_riv(gspca_dev, 0x00, reg, sd->contrast);
616}
617
618static void setcolors(struct gspca_dev *gspca_dev)
619{
620	struct sd *sd = (struct sd *) gspca_dev;
621	u16 reg;
622
623	reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
624	reg_w_riv(gspca_dev, 0x00, reg, sd->colors);
625}
626
627static void init_ctl_reg(struct gspca_dev *gspca_dev)
628{
629	struct sd *sd = (struct sd *) gspca_dev;
630	int pollreg = 1;
631
632	setbrightness(gspca_dev);
633	setcontrast(gspca_dev);
634	setcolors(gspca_dev);
635
636	switch (sd->bridge) {
637	case BRIDGE_SPCA504:
638	case BRIDGE_SPCA504C:
639		pollreg = 0;
640		/* fall thru */
641	default:
642/*	case BRIDGE_SPCA533: */
643/*	case BRIDGE_SPCA504B: */
644		reg_w_riv(gspca_dev, 0, 0x21ad, 0x00);	/* hue */
645		reg_w_riv(gspca_dev, 0, 0x21ac, 0x01);	/* sat/hue */
646		reg_w_riv(gspca_dev, 0, 0x21a3, 0x00);	/* gamma */
647		break;
648	case BRIDGE_SPCA536:
649		reg_w_riv(gspca_dev, 0, 0x20f5, 0x40);
650		reg_w_riv(gspca_dev, 0, 0x20f4, 0x01);
651		reg_w_riv(gspca_dev, 0, 0x2089, 0x00);
652		break;
653	}
654	if (pollreg)
655		spca504B_PollingDataReady(gspca_dev);
656}
657
658/* this function is called at probe time */
659static int sd_config(struct gspca_dev *gspca_dev,
660			const struct usb_device_id *id)
661{
662	struct sd *sd = (struct sd *) gspca_dev;
663	struct cam *cam;
664
665	cam = &gspca_dev->cam;
666
667	sd->bridge = id->driver_info >> 8;
668	sd->subtype = id->driver_info;
669
670	if (sd->subtype == AiptekMiniPenCam13) {
671
672		/* try to get the firmware as some cam answer 2.0.1.2.2
673		 * and should be a spca504b then overwrite that setting */
674		reg_r(gspca_dev, 0x20, 0, 1);
675		switch (gspca_dev->usb_buf[0]) {
676		case 1:
677			break;		/* (right bridge/subtype) */
678		case 2:
679			sd->bridge = BRIDGE_SPCA504B;
680			sd->subtype = 0;
681			break;
682		default:
683			return -ENODEV;
684		}
685	}
686
687	switch (sd->bridge) {
688	default:
689/*	case BRIDGE_SPCA504B: */
690/*	case BRIDGE_SPCA504: */
691/*	case BRIDGE_SPCA536: */
692		cam->cam_mode = vga_mode;
693		cam->nmodes = ARRAY_SIZE(vga_mode);
694		break;
695	case BRIDGE_SPCA533:
696		cam->cam_mode = custom_mode;
697		if (sd->subtype == MegaImageVI)		/* 320x240 only */
698			cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
699		else
700			cam->nmodes = ARRAY_SIZE(custom_mode);
701		break;
702	case BRIDGE_SPCA504C:
703		cam->cam_mode = vga_mode2;
704		cam->nmodes = ARRAY_SIZE(vga_mode2);
705		break;
706	}
707	sd->brightness = BRIGHTNESS_DEF;
708	sd->contrast = CONTRAST_DEF;
709	sd->colors = COLOR_DEF;
710	sd->autogain = AUTOGAIN_DEF;
711	sd->quality = QUALITY_DEF;
712	return 0;
713}
714
715/* this function is called at probe and resume time */
716static int sd_init(struct gspca_dev *gspca_dev)
717{
718	struct sd *sd = (struct sd *) gspca_dev;
719
720	switch (sd->bridge) {
721	case BRIDGE_SPCA504B:
722		reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
723		reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01);
724		reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00);
725		reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00);
726		reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13);
727		reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00);
728		/* fall thru */
729	case BRIDGE_SPCA533:
730		spca504B_PollingDataReady(gspca_dev);
731#ifdef GSPCA_DEBUG
732		spca50x_GetFirmware(gspca_dev);
733#endif
734		break;
735	case BRIDGE_SPCA536:
736#ifdef GSPCA_DEBUG
737		spca50x_GetFirmware(gspca_dev);
738#endif
739		reg_r(gspca_dev, 0x00, 0x5002, 1);
740		reg_w_1(gspca_dev, 0x24, 0, 0, 0);
741		reg_r(gspca_dev, 0x24, 0, 1);
742		spca504B_PollingDataReady(gspca_dev);
743		reg_w_riv(gspca_dev, 0x34, 0, 0);
744		spca504B_WaitCmdStatus(gspca_dev);
745		break;
746	case BRIDGE_SPCA504C:	/* pccam600 */
747		PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
748		reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000);
749		reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001);	/* reset */
750		spca504_wait_status(gspca_dev);
751		if (sd->subtype == LogitechClickSmart420)
752			write_vector(gspca_dev,
753				spca504A_clicksmart420_open_data,
754				ARRAY_SIZE(spca504A_clicksmart420_open_data));
755		else
756			write_vector(gspca_dev, spca504_pccam600_open_data,
757				ARRAY_SIZE(spca504_pccam600_open_data));
758		setup_qtable(gspca_dev, qtable_creative_pccam);
759		break;
760	default:
761/*	case BRIDGE_SPCA504: */
762		PDEBUG(D_STREAM, "Opening SPCA504");
763		if (sd->subtype == AiptekMiniPenCam13) {
764#ifdef GSPCA_DEBUG
765			spca504_read_info(gspca_dev);
766#endif
767
768			/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
769			spca504A_acknowledged_command(gspca_dev, 0x24,
770							8, 3, 0x9e, 1);
771			/* Twice sequential need status 0xff->0x9e->0x9d */
772			spca504A_acknowledged_command(gspca_dev, 0x24,
773							8, 3, 0x9e, 0);
774
775			spca504A_acknowledged_command(gspca_dev, 0x24,
776							0, 0, 0x9d, 1);
777			/******************************/
778			/* spca504a aiptek */
779			spca504A_acknowledged_command(gspca_dev, 0x08,
780							6, 0, 0x86, 1);
781/*			reg_write (dev, 0, 0x2000, 0); */
782/*			reg_write (dev, 0, 0x2883, 1); */
783/*			spca504A_acknowledged_command (gspca_dev, 0x08,
784							6, 0, 0x86, 1); */
785/*			spca504A_acknowledged_command (gspca_dev, 0x24,
786							0, 0, 0x9D, 1); */
787			reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
788							/* L92 sno1t.txt */
789			reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
790			spca504A_acknowledged_command(gspca_dev, 0x01,
791							0x0f, 0, 0xff, 0);
792		}
793		/* setup qtable */
794		reg_w_riv(gspca_dev, 0, 0x2000, 0);
795		reg_w_riv(gspca_dev, 0, 0x2883, 1);
796		setup_qtable(gspca_dev, qtable_spca504_default);
797		break;
798	}
799	return gspca_dev->usb_err;
800}
801
802static int sd_start(struct gspca_dev *gspca_dev)
803{
804	struct sd *sd = (struct sd *) gspca_dev;
805	int enable;
806
807	/* create the JPEG header */
808	jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
809			0x22);		/* JPEG 411 */
810	jpeg_set_qual(sd->jpeg_hdr, sd->quality);
811
812	if (sd->bridge == BRIDGE_SPCA504B)
813		spca504B_setQtable(gspca_dev);
814	spca504B_SetSizeType(gspca_dev);
815	switch (sd->bridge) {
816	default:
817/*	case BRIDGE_SPCA504B: */
818/*	case BRIDGE_SPCA533: */
819/*	case BRIDGE_SPCA536: */
820		switch (sd->subtype) {
821		case MegapixV4:
822		case LogitechClickSmart820:
823		case MegaImageVI:
824			reg_w_riv(gspca_dev, 0xf0, 0, 0);
825			spca504B_WaitCmdStatus(gspca_dev);
826			reg_r(gspca_dev, 0xf0, 4, 0);
827			spca504B_WaitCmdStatus(gspca_dev);
828			break;
829		default:
830			reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
831			spca504B_WaitCmdStatus(gspca_dev);
832			spca504B_PollingDataReady(gspca_dev);
833			break;
834		}
835		break;
836	case BRIDGE_SPCA504:
837		if (sd->subtype == AiptekMiniPenCam13) {
838#ifdef GSPCA_DEBUG
839			spca504_read_info(gspca_dev);
840#endif
841
842			/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
843			spca504A_acknowledged_command(gspca_dev, 0x24,
844							8, 3, 0x9e, 1);
845			/* Twice sequential need status 0xff->0x9e->0x9d */
846			spca504A_acknowledged_command(gspca_dev, 0x24,
847							8, 3, 0x9e, 0);
848			spca504A_acknowledged_command(gspca_dev, 0x24,
849							0, 0, 0x9d, 1);
850		} else {
851			spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
852#ifdef GSPCA_DEBUG
853			spca504_read_info(gspca_dev);
854#endif
855			spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
856			spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
857		}
858		spca504B_SetSizeType(gspca_dev);
859		reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
860							/* L92 sno1t.txt */
861		reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
862		break;
863	case BRIDGE_SPCA504C:
864		if (sd->subtype == LogitechClickSmart420) {
865			write_vector(gspca_dev,
866				spca504A_clicksmart420_init_data,
867				ARRAY_SIZE(spca504A_clicksmart420_init_data));
868		} else {
869			write_vector(gspca_dev, spca504_pccam600_init_data,
870				ARRAY_SIZE(spca504_pccam600_init_data));
871		}
872		enable = (sd->autogain ? 0x04 : 0x01);
873		reg_w_riv(gspca_dev, 0x0c, 0x0000, enable);
874							/* auto exposure */
875		reg_w_riv(gspca_dev, 0xb0, 0x0000, enable);
876							/* auto whiteness */
877
878		/* set default exposure compensation and whiteness balance */
879		reg_w_riv(gspca_dev, 0x30, 0x0001, 800);	/* ~ 20 fps */
880		reg_w_riv(gspca_dev, 0x30, 0x0002, 1600);
881		spca504B_SetSizeType(gspca_dev);
882		break;
883	}
884	init_ctl_reg(gspca_dev);
885	return gspca_dev->usb_err;
886}
887
888static void sd_stopN(struct gspca_dev *gspca_dev)
889{
890	struct sd *sd = (struct sd *) gspca_dev;
891
892	switch (sd->bridge) {
893	default:
894/*	case BRIDGE_SPCA533: */
895/*	case BRIDGE_SPCA536: */
896/*	case BRIDGE_SPCA504B: */
897		reg_w_riv(gspca_dev, 0x31, 0, 0);
898		spca504B_WaitCmdStatus(gspca_dev);
899		spca504B_PollingDataReady(gspca_dev);
900		break;
901	case BRIDGE_SPCA504:
902	case BRIDGE_SPCA504C:
903		reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000);
904
905		if (sd->subtype == AiptekMiniPenCam13) {
906			/* spca504a aiptek */
907/*			spca504A_acknowledged_command(gspca_dev, 0x08,
908							 6, 0, 0x86, 1); */
909			spca504A_acknowledged_command(gspca_dev, 0x24,
910							0x00, 0x00, 0x9d, 1);
911			spca504A_acknowledged_command(gspca_dev, 0x01,
912							0x0f, 0x00, 0xff, 1);
913		} else {
914			spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
915			reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000);
916		}
917		break;
918	}
919}
920
921static void sd_pkt_scan(struct gspca_dev *gspca_dev,
922			u8 *data,			/* isoc packet */
923			int len)			/* iso packet length */
924{
925	struct sd *sd = (struct sd *) gspca_dev;
926	int i, sof = 0;
927	static u8 ffd9[] = {0xff, 0xd9};
928
929/* frames are jpeg 4.1.1 without 0xff escape */
930	switch (sd->bridge) {
931	case BRIDGE_SPCA533:
932		if (data[0] == 0xff) {
933			if (data[1] != 0x01) {	/* drop packet */
934/*				gspca_dev->last_packet_type = DISCARD_PACKET; */
935				return;
936			}
937			sof = 1;
938			data += SPCA533_OFFSET_DATA;
939			len -= SPCA533_OFFSET_DATA;
940		} else {
941			data += 1;
942			len -= 1;
943		}
944		break;
945	case BRIDGE_SPCA536:
946		if (data[0] == 0xff) {
947			sof = 1;
948			data += SPCA536_OFFSET_DATA;
949			len -= SPCA536_OFFSET_DATA;
950		} else {
951			data += 2;
952			len -= 2;
953		}
954		break;
955	default:
956/*	case BRIDGE_SPCA504: */
957/*	case BRIDGE_SPCA504B: */
958		switch (data[0]) {
959		case 0xfe:			/* start of frame */
960			sof = 1;
961			data += SPCA50X_OFFSET_DATA;
962			len -= SPCA50X_OFFSET_DATA;
963			break;
964		case 0xff:			/* drop packet */
965/*			gspca_dev->last_packet_type = DISCARD_PACKET; */
966			return;
967		default:
968			data += 1;
969			len -= 1;
970			break;
971		}
972		break;
973	case BRIDGE_SPCA504C:
974		switch (data[0]) {
975		case 0xfe:			/* start of frame */
976			sof = 1;
977			data += SPCA504_PCCAM600_OFFSET_DATA;
978			len -= SPCA504_PCCAM600_OFFSET_DATA;
979			break;
980		case 0xff:			/* drop packet */
981/*			gspca_dev->last_packet_type = DISCARD_PACKET; */
982			return;
983		default:
984			data += 1;
985			len -= 1;
986			break;
987		}
988		break;
989	}
990	if (sof) {		/* start of frame */
991		gspca_frame_add(gspca_dev, LAST_PACKET,
992				ffd9, 2);
993
994		/* put the JPEG header in the new frame */
995		gspca_frame_add(gspca_dev, FIRST_PACKET,
996			sd->jpeg_hdr, JPEG_HDR_SZ);
997	}
998
999	/* add 0x00 after 0xff */
1000	i = 0;
1001	do {
1002		if (data[i] == 0xff) {
1003			gspca_frame_add(gspca_dev, INTER_PACKET,
1004					data, i + 1);
1005			len -= i;
1006			data += i;
1007			*data = 0x00;
1008			i = 0;
1009		}
1010		i++;
1011	} while (i < len);
1012	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
1013}
1014
1015static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
1016{
1017	struct sd *sd = (struct sd *) gspca_dev;
1018
1019	sd->brightness = val;
1020	if (gspca_dev->streaming)
1021		setbrightness(gspca_dev);
1022	return gspca_dev->usb_err;
1023}
1024
1025static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
1026{
1027	struct sd *sd = (struct sd *) gspca_dev;
1028
1029	*val = sd->brightness;
1030	return 0;
1031}
1032
1033static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
1034{
1035	struct sd *sd = (struct sd *) gspca_dev;
1036
1037	sd->contrast = val;
1038	if (gspca_dev->streaming)
1039		setcontrast(gspca_dev);
1040	return gspca_dev->usb_err;
1041}
1042
1043static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
1044{
1045	struct sd *sd = (struct sd *) gspca_dev;
1046
1047	*val = sd->contrast;
1048	return 0;
1049}
1050
1051static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
1052{
1053	struct sd *sd = (struct sd *) gspca_dev;
1054
1055	sd->colors = val;
1056	if (gspca_dev->streaming)
1057		setcolors(gspca_dev);
1058	return gspca_dev->usb_err;
1059}
1060
1061static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
1062{
1063	struct sd *sd = (struct sd *) gspca_dev;
1064
1065	*val = sd->colors;
1066	return 0;
1067}
1068
1069static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
1070{
1071	struct sd *sd = (struct sd *) gspca_dev;
1072
1073	sd->autogain = val;
1074	return 0;
1075}
1076
1077static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
1078{
1079	struct sd *sd = (struct sd *) gspca_dev;
1080
1081	*val = sd->autogain;
1082	return 0;
1083}
1084
1085static int sd_set_jcomp(struct gspca_dev *gspca_dev,
1086			struct v4l2_jpegcompression *jcomp)
1087{
1088	struct sd *sd = (struct sd *) gspca_dev;
1089
1090	if (jcomp->quality < QUALITY_MIN)
1091		sd->quality = QUALITY_MIN;
1092	else if (jcomp->quality > QUALITY_MAX)
1093		sd->quality = QUALITY_MAX;
1094	else
1095		sd->quality = jcomp->quality;
1096	if (gspca_dev->streaming)
1097		jpeg_set_qual(sd->jpeg_hdr, sd->quality);
1098	return gspca_dev->usb_err;
1099}
1100
1101static int sd_get_jcomp(struct gspca_dev *gspca_dev,
1102			struct v4l2_jpegcompression *jcomp)
1103{
1104	struct sd *sd = (struct sd *) gspca_dev;
1105
1106	memset(jcomp, 0, sizeof *jcomp);
1107	jcomp->quality = sd->quality;
1108	jcomp->jpeg_markers = V4L2_JPEG_MARKER_DHT
1109			| V4L2_JPEG_MARKER_DQT;
1110	return 0;
1111}
1112
1113/* sub-driver description */
1114static const struct sd_desc sd_desc = {
1115	.name = MODULE_NAME,
1116	.ctrls = sd_ctrls,
1117	.nctrls = ARRAY_SIZE(sd_ctrls),
1118	.config = sd_config,
1119	.init = sd_init,
1120	.start = sd_start,
1121	.stopN = sd_stopN,
1122	.pkt_scan = sd_pkt_scan,
1123	.get_jcomp = sd_get_jcomp,
1124	.set_jcomp = sd_set_jcomp,
1125};
1126
1127/* -- module initialisation -- */
1128#define BS(bridge, subtype) \
1129	.driver_info = (BRIDGE_ ## bridge << 8) \
1130			| (subtype)
1131static const struct usb_device_id device_table[] = {
1132	{USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
1133	{USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
1134	{USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
1135	{USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
1136	{USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
1137	{USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
1138	{USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
1139	{USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
1140	{USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
1141	{USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
1142	{USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1143	{USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1144	{USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1145	{USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1146	{USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1147	{USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1148	{USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1149	{USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
1150	{USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)},
1151	{USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
1152	{USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
1153	{USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1154	{USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1155	{USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1156	{USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1157	{USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1158	{USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1159	{USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1160	{USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1161	{USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1162	{USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1163	{USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1164	{USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1165	{USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1166	{USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1167	{USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1168	{USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1169	{USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1170	{USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1171	{USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1172	{USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1173	{USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1174	{USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1175	{USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1176	{USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1177	{USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1178	{USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1179	{USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1180	{USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1181	{USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1182	{USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1183	{USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1184	{USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1185	{USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1186	{USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1187	{USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1188	{USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1189	{USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1190	{USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
1191	{}
1192};
1193MODULE_DEVICE_TABLE(usb, device_table);
1194
1195/* -- device connect -- */
1196static int sd_probe(struct usb_interface *intf,
1197			const struct usb_device_id *id)
1198{
1199	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1200				THIS_MODULE);
1201}
1202
1203static struct usb_driver sd_driver = {
1204	.name = MODULE_NAME,
1205	.id_table = device_table,
1206	.probe = sd_probe,
1207	.disconnect = gspca_disconnect,
1208#ifdef CONFIG_PM
1209	.suspend = gspca_suspend,
1210	.resume = gspca_resume,
1211#endif
1212};
1213
1214module_usb_driver(sd_driver);
1215