xref: /openbmc/linux/drivers/media/usb/gspca/sunplus.c (revision f35e839a)
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->height, gspca_dev->width,
719 			0x22);		/* JPEG 411 */
720 	jpeg_set_qual(sd->jpeg_hdr, QUALITY);
721 
722 	if (sd->bridge == BRIDGE_SPCA504B)
723 		spca504B_setQtable(gspca_dev);
724 	spca504B_SetSizeType(gspca_dev);
725 	switch (sd->bridge) {
726 	default:
727 /*	case BRIDGE_SPCA504B: */
728 /*	case BRIDGE_SPCA533: */
729 /*	case BRIDGE_SPCA536: */
730 		switch (sd->subtype) {
731 		case MegapixV4:
732 		case LogitechClickSmart820:
733 		case MegaImageVI:
734 			reg_w_riv(gspca_dev, 0xf0, 0, 0);
735 			spca504B_WaitCmdStatus(gspca_dev);
736 			reg_r(gspca_dev, 0xf0, 4, 0);
737 			spca504B_WaitCmdStatus(gspca_dev);
738 			break;
739 		default:
740 			reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
741 			spca504B_WaitCmdStatus(gspca_dev);
742 			spca504B_PollingDataReady(gspca_dev);
743 			break;
744 		}
745 		break;
746 	case BRIDGE_SPCA504:
747 		if (sd->subtype == AiptekMiniPenCam13) {
748 			spca504_read_info(gspca_dev);
749 
750 			/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
751 			spca504A_acknowledged_command(gspca_dev, 0x24,
752 							8, 3, 0x9e, 1);
753 			/* Twice sequential need status 0xff->0x9e->0x9d */
754 			spca504A_acknowledged_command(gspca_dev, 0x24,
755 							8, 3, 0x9e, 0);
756 			spca504A_acknowledged_command(gspca_dev, 0x24,
757 							0, 0, 0x9d, 1);
758 		} else {
759 			spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
760 			spca504_read_info(gspca_dev);
761 			spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
762 			spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
763 		}
764 		spca504B_SetSizeType(gspca_dev);
765 		reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
766 							/* L92 sno1t.txt */
767 		reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
768 		break;
769 	case BRIDGE_SPCA504C:
770 		if (sd->subtype == LogitechClickSmart420) {
771 			write_vector(gspca_dev,
772 				spca504A_clicksmart420_init_data,
773 				ARRAY_SIZE(spca504A_clicksmart420_init_data));
774 		} else {
775 			write_vector(gspca_dev, spca504_pccam600_init_data,
776 				ARRAY_SIZE(spca504_pccam600_init_data));
777 		}
778 		enable = (sd->autogain ? 0x04 : 0x01);
779 		reg_w_riv(gspca_dev, 0x0c, 0x0000, enable);
780 							/* auto exposure */
781 		reg_w_riv(gspca_dev, 0xb0, 0x0000, enable);
782 							/* auto whiteness */
783 
784 		/* set default exposure compensation and whiteness balance */
785 		reg_w_riv(gspca_dev, 0x30, 0x0001, 800);	/* ~ 20 fps */
786 		reg_w_riv(gspca_dev, 0x30, 0x0002, 1600);
787 		spca504B_SetSizeType(gspca_dev);
788 		break;
789 	}
790 	init_ctl_reg(gspca_dev);
791 	return gspca_dev->usb_err;
792 }
793 
794 static void sd_stopN(struct gspca_dev *gspca_dev)
795 {
796 	struct sd *sd = (struct sd *) gspca_dev;
797 
798 	switch (sd->bridge) {
799 	default:
800 /*	case BRIDGE_SPCA533: */
801 /*	case BRIDGE_SPCA536: */
802 /*	case BRIDGE_SPCA504B: */
803 		reg_w_riv(gspca_dev, 0x31, 0, 0);
804 		spca504B_WaitCmdStatus(gspca_dev);
805 		spca504B_PollingDataReady(gspca_dev);
806 		break;
807 	case BRIDGE_SPCA504:
808 	case BRIDGE_SPCA504C:
809 		reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000);
810 
811 		if (sd->subtype == AiptekMiniPenCam13) {
812 			/* spca504a aiptek */
813 /*			spca504A_acknowledged_command(gspca_dev, 0x08,
814 							 6, 0, 0x86, 1); */
815 			spca504A_acknowledged_command(gspca_dev, 0x24,
816 							0x00, 0x00, 0x9d, 1);
817 			spca504A_acknowledged_command(gspca_dev, 0x01,
818 							0x0f, 0x00, 0xff, 1);
819 		} else {
820 			spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
821 			reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000);
822 		}
823 		break;
824 	}
825 }
826 
827 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
828 			u8 *data,			/* isoc packet */
829 			int len)			/* iso packet length */
830 {
831 	struct sd *sd = (struct sd *) gspca_dev;
832 	int i, sof = 0;
833 	static u8 ffd9[] = {0xff, 0xd9};
834 
835 /* frames are jpeg 4.1.1 without 0xff escape */
836 	switch (sd->bridge) {
837 	case BRIDGE_SPCA533:
838 		if (data[0] == 0xff) {
839 			if (data[1] != 0x01) {	/* drop packet */
840 /*				gspca_dev->last_packet_type = DISCARD_PACKET; */
841 				return;
842 			}
843 			sof = 1;
844 			data += SPCA533_OFFSET_DATA;
845 			len -= SPCA533_OFFSET_DATA;
846 		} else {
847 			data += 1;
848 			len -= 1;
849 		}
850 		break;
851 	case BRIDGE_SPCA536:
852 		if (data[0] == 0xff) {
853 			sof = 1;
854 			data += SPCA536_OFFSET_DATA;
855 			len -= SPCA536_OFFSET_DATA;
856 		} else {
857 			data += 2;
858 			len -= 2;
859 		}
860 		break;
861 	default:
862 /*	case BRIDGE_SPCA504: */
863 /*	case BRIDGE_SPCA504B: */
864 		switch (data[0]) {
865 		case 0xfe:			/* start of frame */
866 			sof = 1;
867 			data += SPCA50X_OFFSET_DATA;
868 			len -= SPCA50X_OFFSET_DATA;
869 			break;
870 		case 0xff:			/* drop packet */
871 /*			gspca_dev->last_packet_type = DISCARD_PACKET; */
872 			return;
873 		default:
874 			data += 1;
875 			len -= 1;
876 			break;
877 		}
878 		break;
879 	case BRIDGE_SPCA504C:
880 		switch (data[0]) {
881 		case 0xfe:			/* start of frame */
882 			sof = 1;
883 			data += SPCA504_PCCAM600_OFFSET_DATA;
884 			len -= SPCA504_PCCAM600_OFFSET_DATA;
885 			break;
886 		case 0xff:			/* drop packet */
887 /*			gspca_dev->last_packet_type = DISCARD_PACKET; */
888 			return;
889 		default:
890 			data += 1;
891 			len -= 1;
892 			break;
893 		}
894 		break;
895 	}
896 	if (sof) {		/* start of frame */
897 		gspca_frame_add(gspca_dev, LAST_PACKET,
898 				ffd9, 2);
899 
900 		/* put the JPEG header in the new frame */
901 		gspca_frame_add(gspca_dev, FIRST_PACKET,
902 			sd->jpeg_hdr, JPEG_HDR_SZ);
903 	}
904 
905 	/* add 0x00 after 0xff */
906 	i = 0;
907 	do {
908 		if (data[i] == 0xff) {
909 			gspca_frame_add(gspca_dev, INTER_PACKET,
910 					data, i + 1);
911 			len -= i;
912 			data += i;
913 			*data = 0x00;
914 			i = 0;
915 		}
916 		i++;
917 	} while (i < len);
918 	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
919 }
920 
921 static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
922 {
923 	struct gspca_dev *gspca_dev =
924 		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
925 	struct sd *sd = (struct sd *)gspca_dev;
926 
927 	gspca_dev->usb_err = 0;
928 
929 	if (!gspca_dev->streaming)
930 		return 0;
931 
932 	switch (ctrl->id) {
933 	case V4L2_CID_BRIGHTNESS:
934 		setbrightness(gspca_dev, ctrl->val);
935 		break;
936 	case V4L2_CID_CONTRAST:
937 		setcontrast(gspca_dev, ctrl->val);
938 		break;
939 	case V4L2_CID_SATURATION:
940 		setcolors(gspca_dev, ctrl->val);
941 		break;
942 	case V4L2_CID_AUTOGAIN:
943 		sd->autogain = ctrl->val;
944 		break;
945 	}
946 	return gspca_dev->usb_err;
947 }
948 
949 static const struct v4l2_ctrl_ops sd_ctrl_ops = {
950 	.s_ctrl = sd_s_ctrl,
951 };
952 
953 static int sd_init_controls(struct gspca_dev *gspca_dev)
954 {
955 	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
956 
957 	gspca_dev->vdev.ctrl_handler = hdl;
958 	v4l2_ctrl_handler_init(hdl, 4);
959 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
960 			V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
961 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
962 			V4L2_CID_CONTRAST, 0, 255, 1, 0x20);
963 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
964 			V4L2_CID_SATURATION, 0, 255, 1, 0x1a);
965 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
966 			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
967 
968 	if (hdl->error) {
969 		pr_err("Could not initialize controls\n");
970 		return hdl->error;
971 	}
972 	return 0;
973 }
974 
975 /* sub-driver description */
976 static const struct sd_desc sd_desc = {
977 	.name = MODULE_NAME,
978 	.config = sd_config,
979 	.init = sd_init,
980 	.init_controls = sd_init_controls,
981 	.start = sd_start,
982 	.stopN = sd_stopN,
983 	.pkt_scan = sd_pkt_scan,
984 };
985 
986 /* -- module initialisation -- */
987 #define BS(bridge, subtype) \
988 	.driver_info = (BRIDGE_ ## bridge << 8) \
989 			| (subtype)
990 static const struct usb_device_id device_table[] = {
991 	{USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
992 	{USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
993 	{USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
994 	{USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
995 	{USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
996 	{USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
997 	{USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
998 	{USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
999 	{USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
1000 	{USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
1001 	{USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1002 	{USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1003 	{USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1004 	{USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1005 	{USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1006 	{USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1007 	{USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1008 	{USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
1009 	{USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)},
1010 	{USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
1011 	{USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
1012 	{USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1013 	{USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1014 	{USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1015 	{USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1016 	{USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1017 	{USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1018 	{USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1019 	{USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1020 	{USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1021 	{USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1022 	{USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1023 	{USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1024 	{USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1025 	{USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1026 	{USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1027 	{USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1028 	{USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1029 	{USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1030 	{USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1031 	{USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1032 	{USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1033 	{USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1034 	{USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1035 	{USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1036 	{USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1037 	{USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1038 	{USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1039 	{USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1040 	{USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1041 	{USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1042 	{USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1043 	{USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1044 	{USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1045 	{USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1046 	{USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1047 	{USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1048 	{USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1049 	{USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
1050 	{}
1051 };
1052 MODULE_DEVICE_TABLE(usb, device_table);
1053 
1054 /* -- device connect -- */
1055 static int sd_probe(struct usb_interface *intf,
1056 			const struct usb_device_id *id)
1057 {
1058 	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1059 				THIS_MODULE);
1060 }
1061 
1062 static struct usb_driver sd_driver = {
1063 	.name = MODULE_NAME,
1064 	.id_table = device_table,
1065 	.probe = sd_probe,
1066 	.disconnect = gspca_disconnect,
1067 #ifdef CONFIG_PM
1068 	.suspend = gspca_suspend,
1069 	.resume = gspca_resume,
1070 	.reset_resume = gspca_resume,
1071 #endif
1072 };
1073 
1074 module_usb_driver(sd_driver);
1075