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