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