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