xref: /openbmc/linux/drivers/media/usb/gspca/sunplus.c (revision 9d749629)
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 #ifdef GSPCA_DEBUG
255 	if (len > USB_BUF_SZ) {
256 		pr_err("reg_r: buffer overflow\n");
257 		return;
258 	}
259 #endif
260 	if (gspca_dev->usb_err < 0)
261 		return;
262 	ret = usb_control_msg(gspca_dev->dev,
263 			usb_rcvctrlpipe(gspca_dev->dev, 0),
264 			req,
265 			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
266 			0,		/* value */
267 			index,
268 			len ? gspca_dev->usb_buf : NULL, len,
269 			500);
270 	if (ret < 0) {
271 		pr_err("reg_r err %d\n", ret);
272 		gspca_dev->usb_err = ret;
273 	}
274 }
275 
276 /* write one byte */
277 static void reg_w_1(struct gspca_dev *gspca_dev,
278 		   u8 req,
279 		   u16 value,
280 		   u16 index,
281 		   u16 byte)
282 {
283 	int ret;
284 
285 	if (gspca_dev->usb_err < 0)
286 		return;
287 	gspca_dev->usb_buf[0] = byte;
288 	ret = usb_control_msg(gspca_dev->dev,
289 			usb_sndctrlpipe(gspca_dev->dev, 0),
290 			req,
291 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
292 			value, index,
293 			gspca_dev->usb_buf, 1,
294 			500);
295 	if (ret < 0) {
296 		pr_err("reg_w_1 err %d\n", ret);
297 		gspca_dev->usb_err = ret;
298 	}
299 }
300 
301 /* write req / index / value */
302 static void reg_w_riv(struct gspca_dev *gspca_dev,
303 		     u8 req, u16 index, u16 value)
304 {
305 	struct usb_device *dev = gspca_dev->dev;
306 	int ret;
307 
308 	if (gspca_dev->usb_err < 0)
309 		return;
310 	ret = usb_control_msg(dev,
311 			usb_sndctrlpipe(dev, 0),
312 			req,
313 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
314 			value, index, NULL, 0, 500);
315 	if (ret < 0) {
316 		pr_err("reg_w_riv err %d\n", ret);
317 		gspca_dev->usb_err = ret;
318 		return;
319 	}
320 	PDEBUG(D_USBO, "reg_w_riv: 0x%02x,0x%04x:0x%04x",
321 		req, index, value);
322 }
323 
324 static void write_vector(struct gspca_dev *gspca_dev,
325 			const struct cmd *data, int ncmds)
326 {
327 	while (--ncmds >= 0) {
328 		reg_w_riv(gspca_dev, data->req, data->idx, data->val);
329 		data++;
330 	}
331 }
332 
333 static void setup_qtable(struct gspca_dev *gspca_dev,
334 			const u8 qtable[2][64])
335 {
336 	int i;
337 
338 	/* loop over y components */
339 	for (i = 0; i < 64; i++)
340 		reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
341 
342 	/* loop over c components */
343 	for (i = 0; i < 64; i++)
344 		reg_w_riv(gspca_dev, 0x00, 0x2840 + i, qtable[1][i]);
345 }
346 
347 static void spca504_acknowledged_command(struct gspca_dev *gspca_dev,
348 			     u8 req, u16 idx, u16 val)
349 {
350 	reg_w_riv(gspca_dev, req, idx, val);
351 	reg_r(gspca_dev, 0x01, 0x0001, 1);
352 	PDEBUG(D_FRAM, "before wait 0x%04x", gspca_dev->usb_buf[0]);
353 	reg_w_riv(gspca_dev, req, idx, val);
354 
355 	msleep(200);
356 	reg_r(gspca_dev, 0x01, 0x0001, 1);
357 	PDEBUG(D_FRAM, "after wait 0x%04x", gspca_dev->usb_buf[0]);
358 }
359 
360 #ifdef GSPCA_DEBUG
361 static void spca504_read_info(struct gspca_dev *gspca_dev)
362 {
363 	int i;
364 	u8 info[6];
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 #endif
377 
378 static void spca504A_acknowledged_command(struct gspca_dev *gspca_dev,
379 			u8 req,
380 			u16 idx, u16 val, u8 endcode, u8 count)
381 {
382 	u16 status;
383 
384 	reg_w_riv(gspca_dev, req, idx, val);
385 	reg_r(gspca_dev, 0x01, 0x0001, 1);
386 	if (gspca_dev->usb_err < 0)
387 		return;
388 	PDEBUG(D_FRAM, "Status 0x%02x Need 0x%02x",
389 			gspca_dev->usb_buf[0], endcode);
390 	if (!count)
391 		return;
392 	count = 200;
393 	while (--count > 0) {
394 		msleep(10);
395 		/* gsmart mini2 write a each wait setting 1 ms is enough */
396 /*		reg_w_riv(gspca_dev, req, idx, val); */
397 		reg_r(gspca_dev, 0x01, 0x0001, 1);
398 		status = gspca_dev->usb_buf[0];
399 		if (status == endcode) {
400 			PDEBUG(D_FRAM, "status 0x%04x after wait %d",
401 				status, 200 - count);
402 				break;
403 		}
404 	}
405 }
406 
407 static void spca504B_PollingDataReady(struct gspca_dev *gspca_dev)
408 {
409 	int count = 10;
410 
411 	while (--count > 0) {
412 		reg_r(gspca_dev, 0x21, 0, 1);
413 		if ((gspca_dev->usb_buf[0] & 0x01) == 0)
414 			break;
415 		msleep(10);
416 	}
417 }
418 
419 static void spca504B_WaitCmdStatus(struct gspca_dev *gspca_dev)
420 {
421 	int count = 50;
422 
423 	while (--count > 0) {
424 		reg_r(gspca_dev, 0x21, 1, 1);
425 		if (gspca_dev->usb_buf[0] != 0) {
426 			reg_w_1(gspca_dev, 0x21, 0, 1, 0);
427 			reg_r(gspca_dev, 0x21, 1, 1);
428 			spca504B_PollingDataReady(gspca_dev);
429 			break;
430 		}
431 		msleep(10);
432 	}
433 }
434 
435 #ifdef GSPCA_DEBUG
436 static void spca50x_GetFirmware(struct gspca_dev *gspca_dev)
437 {
438 	u8 *data;
439 
440 	data = gspca_dev->usb_buf;
441 	reg_r(gspca_dev, 0x20, 0, 5);
442 	PDEBUG(D_STREAM, "FirmWare: %d %d %d %d %d",
443 		data[0], data[1], data[2], data[3], data[4]);
444 	reg_r(gspca_dev, 0x23, 0, 64);
445 	reg_r(gspca_dev, 0x23, 1, 64);
446 }
447 #endif
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 #ifdef GSPCA_DEBUG
461 		spca50x_GetFirmware(gspca_dev);
462 #endif
463 		reg_w_1(gspca_dev, 0x24, 0, 8, 2);		/* type */
464 		reg_r(gspca_dev, 0x24, 8, 1);
465 
466 		reg_w_1(gspca_dev, 0x25, 0, 4, Size);
467 		reg_r(gspca_dev, 0x25, 4, 1);			/* size */
468 		spca504B_PollingDataReady(gspca_dev);
469 
470 		/* Init the cam width height with some values get on init ? */
471 		reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
472 		spca504B_WaitCmdStatus(gspca_dev);
473 		spca504B_PollingDataReady(gspca_dev);
474 		break;
475 	default:
476 /* case BRIDGE_SPCA504B: */
477 /* case BRIDGE_SPCA536: */
478 		reg_w_1(gspca_dev, 0x25, 0, 4, Size);
479 		reg_r(gspca_dev, 0x25, 4, 1);			/* size */
480 		reg_w_1(gspca_dev, 0x27, 0, 0, 6);
481 		reg_r(gspca_dev, 0x27, 0, 1);			/* type */
482 		spca504B_PollingDataReady(gspca_dev);
483 		break;
484 	case BRIDGE_SPCA504:
485 		Size += 3;
486 		if (sd->subtype == AiptekMiniPenCam13) {
487 			/* spca504a aiptek */
488 			spca504A_acknowledged_command(gspca_dev,
489 						0x08, Size, 0,
490 						0x80 | (Size & 0x0f), 1);
491 			spca504A_acknowledged_command(gspca_dev,
492 							1, 3, 0, 0x9f, 0);
493 		} else {
494 			spca504_acknowledged_command(gspca_dev, 0x08, Size, 0);
495 		}
496 		break;
497 	case BRIDGE_SPCA504C:
498 		/* capture mode */
499 		reg_w_riv(gspca_dev, 0xa0, (0x0500 | (Size & 0x0f)), 0x00);
500 		reg_w_riv(gspca_dev, 0x20, 0x01, 0x0500 | (Size & 0x0f));
501 		break;
502 	}
503 }
504 
505 static void spca504_wait_status(struct gspca_dev *gspca_dev)
506 {
507 	int cnt;
508 
509 	cnt = 256;
510 	while (--cnt > 0) {
511 		/* With this we get the status, when return 0 it's all ok */
512 		reg_r(gspca_dev, 0x06, 0x00, 1);
513 		if (gspca_dev->usb_buf[0] == 0)
514 			return;
515 		msleep(10);
516 	}
517 }
518 
519 static void spca504B_setQtable(struct gspca_dev *gspca_dev)
520 {
521 	reg_w_1(gspca_dev, 0x26, 0, 0, 3);
522 	reg_r(gspca_dev, 0x26, 0, 1);
523 	spca504B_PollingDataReady(gspca_dev);
524 }
525 
526 static void setbrightness(struct gspca_dev *gspca_dev, s32 val)
527 {
528 	struct sd *sd = (struct sd *) gspca_dev;
529 	u16 reg;
530 
531 	reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f0 : 0x21a7;
532 	reg_w_riv(gspca_dev, 0x00, reg, val);
533 }
534 
535 static void setcontrast(struct gspca_dev *gspca_dev, s32 val)
536 {
537 	struct sd *sd = (struct sd *) gspca_dev;
538 	u16 reg;
539 
540 	reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f1 : 0x21a8;
541 	reg_w_riv(gspca_dev, 0x00, reg, val);
542 }
543 
544 static void setcolors(struct gspca_dev *gspca_dev, s32 val)
545 {
546 	struct sd *sd = (struct sd *) gspca_dev;
547 	u16 reg;
548 
549 	reg = sd->bridge == BRIDGE_SPCA536 ? 0x20f6 : 0x21ae;
550 	reg_w_riv(gspca_dev, 0x00, reg, val);
551 }
552 
553 static void init_ctl_reg(struct gspca_dev *gspca_dev)
554 {
555 	struct sd *sd = (struct sd *) gspca_dev;
556 	int pollreg = 1;
557 
558 	switch (sd->bridge) {
559 	case BRIDGE_SPCA504:
560 	case BRIDGE_SPCA504C:
561 		pollreg = 0;
562 		/* fall thru */
563 	default:
564 /*	case BRIDGE_SPCA533: */
565 /*	case BRIDGE_SPCA504B: */
566 		reg_w_riv(gspca_dev, 0, 0x21ad, 0x00);	/* hue */
567 		reg_w_riv(gspca_dev, 0, 0x21ac, 0x01);	/* sat/hue */
568 		reg_w_riv(gspca_dev, 0, 0x21a3, 0x00);	/* gamma */
569 		break;
570 	case BRIDGE_SPCA536:
571 		reg_w_riv(gspca_dev, 0, 0x20f5, 0x40);
572 		reg_w_riv(gspca_dev, 0, 0x20f4, 0x01);
573 		reg_w_riv(gspca_dev, 0, 0x2089, 0x00);
574 		break;
575 	}
576 	if (pollreg)
577 		spca504B_PollingDataReady(gspca_dev);
578 }
579 
580 /* this function is called at probe time */
581 static int sd_config(struct gspca_dev *gspca_dev,
582 			const struct usb_device_id *id)
583 {
584 	struct sd *sd = (struct sd *) gspca_dev;
585 	struct cam *cam;
586 
587 	cam = &gspca_dev->cam;
588 
589 	sd->bridge = id->driver_info >> 8;
590 	sd->subtype = id->driver_info;
591 
592 	if (sd->subtype == AiptekMiniPenCam13) {
593 
594 		/* try to get the firmware as some cam answer 2.0.1.2.2
595 		 * and should be a spca504b then overwrite that setting */
596 		reg_r(gspca_dev, 0x20, 0, 1);
597 		switch (gspca_dev->usb_buf[0]) {
598 		case 1:
599 			break;		/* (right bridge/subtype) */
600 		case 2:
601 			sd->bridge = BRIDGE_SPCA504B;
602 			sd->subtype = 0;
603 			break;
604 		default:
605 			return -ENODEV;
606 		}
607 	}
608 
609 	switch (sd->bridge) {
610 	default:
611 /*	case BRIDGE_SPCA504B: */
612 /*	case BRIDGE_SPCA504: */
613 /*	case BRIDGE_SPCA536: */
614 		cam->cam_mode = vga_mode;
615 		cam->nmodes = ARRAY_SIZE(vga_mode);
616 		break;
617 	case BRIDGE_SPCA533:
618 		cam->cam_mode = custom_mode;
619 		if (sd->subtype == MegaImageVI)		/* 320x240 only */
620 			cam->nmodes = ARRAY_SIZE(custom_mode) - 1;
621 		else
622 			cam->nmodes = ARRAY_SIZE(custom_mode);
623 		break;
624 	case BRIDGE_SPCA504C:
625 		cam->cam_mode = vga_mode2;
626 		cam->nmodes = ARRAY_SIZE(vga_mode2);
627 		break;
628 	}
629 	return 0;
630 }
631 
632 /* this function is called at probe and resume time */
633 static int sd_init(struct gspca_dev *gspca_dev)
634 {
635 	struct sd *sd = (struct sd *) gspca_dev;
636 
637 	switch (sd->bridge) {
638 	case BRIDGE_SPCA504B:
639 		reg_w_riv(gspca_dev, 0x1d, 0x00, 0);
640 		reg_w_riv(gspca_dev, 0x00, 0x2306, 0x01);
641 		reg_w_riv(gspca_dev, 0x00, 0x0d04, 0x00);
642 		reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00);
643 		reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13);
644 		reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00);
645 		/* fall thru */
646 	case BRIDGE_SPCA533:
647 		spca504B_PollingDataReady(gspca_dev);
648 #ifdef GSPCA_DEBUG
649 		spca50x_GetFirmware(gspca_dev);
650 #endif
651 		break;
652 	case BRIDGE_SPCA536:
653 #ifdef GSPCA_DEBUG
654 		spca50x_GetFirmware(gspca_dev);
655 #endif
656 		reg_r(gspca_dev, 0x00, 0x5002, 1);
657 		reg_w_1(gspca_dev, 0x24, 0, 0, 0);
658 		reg_r(gspca_dev, 0x24, 0, 1);
659 		spca504B_PollingDataReady(gspca_dev);
660 		reg_w_riv(gspca_dev, 0x34, 0, 0);
661 		spca504B_WaitCmdStatus(gspca_dev);
662 		break;
663 	case BRIDGE_SPCA504C:	/* pccam600 */
664 		PDEBUG(D_STREAM, "Opening SPCA504 (PC-CAM 600)");
665 		reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0000);
666 		reg_w_riv(gspca_dev, 0xe0, 0x0000, 0x0001);	/* reset */
667 		spca504_wait_status(gspca_dev);
668 		if (sd->subtype == LogitechClickSmart420)
669 			write_vector(gspca_dev,
670 				spca504A_clicksmart420_open_data,
671 				ARRAY_SIZE(spca504A_clicksmart420_open_data));
672 		else
673 			write_vector(gspca_dev, spca504_pccam600_open_data,
674 				ARRAY_SIZE(spca504_pccam600_open_data));
675 		setup_qtable(gspca_dev, qtable_creative_pccam);
676 		break;
677 	default:
678 /*	case BRIDGE_SPCA504: */
679 		PDEBUG(D_STREAM, "Opening SPCA504");
680 		if (sd->subtype == AiptekMiniPenCam13) {
681 #ifdef GSPCA_DEBUG
682 			spca504_read_info(gspca_dev);
683 #endif
684 
685 			/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
686 			spca504A_acknowledged_command(gspca_dev, 0x24,
687 							8, 3, 0x9e, 1);
688 			/* Twice sequential need status 0xff->0x9e->0x9d */
689 			spca504A_acknowledged_command(gspca_dev, 0x24,
690 							8, 3, 0x9e, 0);
691 
692 			spca504A_acknowledged_command(gspca_dev, 0x24,
693 							0, 0, 0x9d, 1);
694 			/******************************/
695 			/* spca504a aiptek */
696 			spca504A_acknowledged_command(gspca_dev, 0x08,
697 							6, 0, 0x86, 1);
698 /*			reg_write (dev, 0, 0x2000, 0); */
699 /*			reg_write (dev, 0, 0x2883, 1); */
700 /*			spca504A_acknowledged_command (gspca_dev, 0x08,
701 							6, 0, 0x86, 1); */
702 /*			spca504A_acknowledged_command (gspca_dev, 0x24,
703 							0, 0, 0x9D, 1); */
704 			reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
705 							/* L92 sno1t.txt */
706 			reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
707 			spca504A_acknowledged_command(gspca_dev, 0x01,
708 							0x0f, 0, 0xff, 0);
709 		}
710 		/* setup qtable */
711 		reg_w_riv(gspca_dev, 0, 0x2000, 0);
712 		reg_w_riv(gspca_dev, 0, 0x2883, 1);
713 		setup_qtable(gspca_dev, qtable_spca504_default);
714 		break;
715 	}
716 	return gspca_dev->usb_err;
717 }
718 
719 static int sd_start(struct gspca_dev *gspca_dev)
720 {
721 	struct sd *sd = (struct sd *) gspca_dev;
722 	int enable;
723 
724 	/* create the JPEG header */
725 	jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
726 			0x22);		/* JPEG 411 */
727 	jpeg_set_qual(sd->jpeg_hdr, QUALITY);
728 
729 	if (sd->bridge == BRIDGE_SPCA504B)
730 		spca504B_setQtable(gspca_dev);
731 	spca504B_SetSizeType(gspca_dev);
732 	switch (sd->bridge) {
733 	default:
734 /*	case BRIDGE_SPCA504B: */
735 /*	case BRIDGE_SPCA533: */
736 /*	case BRIDGE_SPCA536: */
737 		switch (sd->subtype) {
738 		case MegapixV4:
739 		case LogitechClickSmart820:
740 		case MegaImageVI:
741 			reg_w_riv(gspca_dev, 0xf0, 0, 0);
742 			spca504B_WaitCmdStatus(gspca_dev);
743 			reg_r(gspca_dev, 0xf0, 4, 0);
744 			spca504B_WaitCmdStatus(gspca_dev);
745 			break;
746 		default:
747 			reg_w_riv(gspca_dev, 0x31, 0x0004, 0x00);
748 			spca504B_WaitCmdStatus(gspca_dev);
749 			spca504B_PollingDataReady(gspca_dev);
750 			break;
751 		}
752 		break;
753 	case BRIDGE_SPCA504:
754 		if (sd->subtype == AiptekMiniPenCam13) {
755 #ifdef GSPCA_DEBUG
756 			spca504_read_info(gspca_dev);
757 #endif
758 
759 			/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
760 			spca504A_acknowledged_command(gspca_dev, 0x24,
761 							8, 3, 0x9e, 1);
762 			/* Twice sequential need status 0xff->0x9e->0x9d */
763 			spca504A_acknowledged_command(gspca_dev, 0x24,
764 							8, 3, 0x9e, 0);
765 			spca504A_acknowledged_command(gspca_dev, 0x24,
766 							0, 0, 0x9d, 1);
767 		} else {
768 			spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
769 #ifdef GSPCA_DEBUG
770 			spca504_read_info(gspca_dev);
771 #endif
772 			spca504_acknowledged_command(gspca_dev, 0x24, 8, 3);
773 			spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
774 		}
775 		spca504B_SetSizeType(gspca_dev);
776 		reg_w_riv(gspca_dev, 0x00, 0x270c, 0x05);
777 							/* L92 sno1t.txt */
778 		reg_w_riv(gspca_dev, 0x00, 0x2310, 0x05);
779 		break;
780 	case BRIDGE_SPCA504C:
781 		if (sd->subtype == LogitechClickSmart420) {
782 			write_vector(gspca_dev,
783 				spca504A_clicksmart420_init_data,
784 				ARRAY_SIZE(spca504A_clicksmart420_init_data));
785 		} else {
786 			write_vector(gspca_dev, spca504_pccam600_init_data,
787 				ARRAY_SIZE(spca504_pccam600_init_data));
788 		}
789 		enable = (sd->autogain ? 0x04 : 0x01);
790 		reg_w_riv(gspca_dev, 0x0c, 0x0000, enable);
791 							/* auto exposure */
792 		reg_w_riv(gspca_dev, 0xb0, 0x0000, enable);
793 							/* auto whiteness */
794 
795 		/* set default exposure compensation and whiteness balance */
796 		reg_w_riv(gspca_dev, 0x30, 0x0001, 800);	/* ~ 20 fps */
797 		reg_w_riv(gspca_dev, 0x30, 0x0002, 1600);
798 		spca504B_SetSizeType(gspca_dev);
799 		break;
800 	}
801 	init_ctl_reg(gspca_dev);
802 	return gspca_dev->usb_err;
803 }
804 
805 static void sd_stopN(struct gspca_dev *gspca_dev)
806 {
807 	struct sd *sd = (struct sd *) gspca_dev;
808 
809 	switch (sd->bridge) {
810 	default:
811 /*	case BRIDGE_SPCA533: */
812 /*	case BRIDGE_SPCA536: */
813 /*	case BRIDGE_SPCA504B: */
814 		reg_w_riv(gspca_dev, 0x31, 0, 0);
815 		spca504B_WaitCmdStatus(gspca_dev);
816 		spca504B_PollingDataReady(gspca_dev);
817 		break;
818 	case BRIDGE_SPCA504:
819 	case BRIDGE_SPCA504C:
820 		reg_w_riv(gspca_dev, 0x00, 0x2000, 0x0000);
821 
822 		if (sd->subtype == AiptekMiniPenCam13) {
823 			/* spca504a aiptek */
824 /*			spca504A_acknowledged_command(gspca_dev, 0x08,
825 							 6, 0, 0x86, 1); */
826 			spca504A_acknowledged_command(gspca_dev, 0x24,
827 							0x00, 0x00, 0x9d, 1);
828 			spca504A_acknowledged_command(gspca_dev, 0x01,
829 							0x0f, 0x00, 0xff, 1);
830 		} else {
831 			spca504_acknowledged_command(gspca_dev, 0x24, 0, 0);
832 			reg_w_riv(gspca_dev, 0x01, 0x000f, 0x0000);
833 		}
834 		break;
835 	}
836 }
837 
838 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
839 			u8 *data,			/* isoc packet */
840 			int len)			/* iso packet length */
841 {
842 	struct sd *sd = (struct sd *) gspca_dev;
843 	int i, sof = 0;
844 	static u8 ffd9[] = {0xff, 0xd9};
845 
846 /* frames are jpeg 4.1.1 without 0xff escape */
847 	switch (sd->bridge) {
848 	case BRIDGE_SPCA533:
849 		if (data[0] == 0xff) {
850 			if (data[1] != 0x01) {	/* drop packet */
851 /*				gspca_dev->last_packet_type = DISCARD_PACKET; */
852 				return;
853 			}
854 			sof = 1;
855 			data += SPCA533_OFFSET_DATA;
856 			len -= SPCA533_OFFSET_DATA;
857 		} else {
858 			data += 1;
859 			len -= 1;
860 		}
861 		break;
862 	case BRIDGE_SPCA536:
863 		if (data[0] == 0xff) {
864 			sof = 1;
865 			data += SPCA536_OFFSET_DATA;
866 			len -= SPCA536_OFFSET_DATA;
867 		} else {
868 			data += 2;
869 			len -= 2;
870 		}
871 		break;
872 	default:
873 /*	case BRIDGE_SPCA504: */
874 /*	case BRIDGE_SPCA504B: */
875 		switch (data[0]) {
876 		case 0xfe:			/* start of frame */
877 			sof = 1;
878 			data += SPCA50X_OFFSET_DATA;
879 			len -= SPCA50X_OFFSET_DATA;
880 			break;
881 		case 0xff:			/* drop packet */
882 /*			gspca_dev->last_packet_type = DISCARD_PACKET; */
883 			return;
884 		default:
885 			data += 1;
886 			len -= 1;
887 			break;
888 		}
889 		break;
890 	case BRIDGE_SPCA504C:
891 		switch (data[0]) {
892 		case 0xfe:			/* start of frame */
893 			sof = 1;
894 			data += SPCA504_PCCAM600_OFFSET_DATA;
895 			len -= SPCA504_PCCAM600_OFFSET_DATA;
896 			break;
897 		case 0xff:			/* drop packet */
898 /*			gspca_dev->last_packet_type = DISCARD_PACKET; */
899 			return;
900 		default:
901 			data += 1;
902 			len -= 1;
903 			break;
904 		}
905 		break;
906 	}
907 	if (sof) {		/* start of frame */
908 		gspca_frame_add(gspca_dev, LAST_PACKET,
909 				ffd9, 2);
910 
911 		/* put the JPEG header in the new frame */
912 		gspca_frame_add(gspca_dev, FIRST_PACKET,
913 			sd->jpeg_hdr, JPEG_HDR_SZ);
914 	}
915 
916 	/* add 0x00 after 0xff */
917 	i = 0;
918 	do {
919 		if (data[i] == 0xff) {
920 			gspca_frame_add(gspca_dev, INTER_PACKET,
921 					data, i + 1);
922 			len -= i;
923 			data += i;
924 			*data = 0x00;
925 			i = 0;
926 		}
927 		i++;
928 	} while (i < len);
929 	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
930 }
931 
932 static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
933 {
934 	struct gspca_dev *gspca_dev =
935 		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
936 	struct sd *sd = (struct sd *)gspca_dev;
937 
938 	gspca_dev->usb_err = 0;
939 
940 	if (!gspca_dev->streaming)
941 		return 0;
942 
943 	switch (ctrl->id) {
944 	case V4L2_CID_BRIGHTNESS:
945 		setbrightness(gspca_dev, ctrl->val);
946 		break;
947 	case V4L2_CID_CONTRAST:
948 		setcontrast(gspca_dev, ctrl->val);
949 		break;
950 	case V4L2_CID_SATURATION:
951 		setcolors(gspca_dev, ctrl->val);
952 		break;
953 	case V4L2_CID_AUTOGAIN:
954 		sd->autogain = ctrl->val;
955 		break;
956 	}
957 	return gspca_dev->usb_err;
958 }
959 
960 static const struct v4l2_ctrl_ops sd_ctrl_ops = {
961 	.s_ctrl = sd_s_ctrl,
962 };
963 
964 static int sd_init_controls(struct gspca_dev *gspca_dev)
965 {
966 	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
967 
968 	gspca_dev->vdev.ctrl_handler = hdl;
969 	v4l2_ctrl_handler_init(hdl, 4);
970 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
971 			V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
972 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
973 			V4L2_CID_CONTRAST, 0, 255, 1, 0x20);
974 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
975 			V4L2_CID_SATURATION, 0, 255, 1, 0x1a);
976 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
977 			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
978 
979 	if (hdl->error) {
980 		pr_err("Could not initialize controls\n");
981 		return hdl->error;
982 	}
983 	return 0;
984 }
985 
986 /* sub-driver description */
987 static const struct sd_desc sd_desc = {
988 	.name = MODULE_NAME,
989 	.config = sd_config,
990 	.init = sd_init,
991 	.init_controls = sd_init_controls,
992 	.start = sd_start,
993 	.stopN = sd_stopN,
994 	.pkt_scan = sd_pkt_scan,
995 };
996 
997 /* -- module initialisation -- */
998 #define BS(bridge, subtype) \
999 	.driver_info = (BRIDGE_ ## bridge << 8) \
1000 			| (subtype)
1001 static const struct usb_device_id device_table[] = {
1002 	{USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
1003 	{USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
1004 	{USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
1005 	{USB_DEVICE(0x0458, 0x7006), BS(SPCA504B, 0)},
1006 	{USB_DEVICE(0x0461, 0x0821), BS(SPCA533, 0)},
1007 	{USB_DEVICE(0x046d, 0x0905), BS(SPCA533, LogitechClickSmart820)},
1008 	{USB_DEVICE(0x046d, 0x0960), BS(SPCA504C, LogitechClickSmart420)},
1009 	{USB_DEVICE(0x0471, 0x0322), BS(SPCA504B, 0)},
1010 	{USB_DEVICE(0x04a5, 0x3003), BS(SPCA504B, 0)},
1011 	{USB_DEVICE(0x04a5, 0x3008), BS(SPCA533, 0)},
1012 	{USB_DEVICE(0x04a5, 0x300a), BS(SPCA533, 0)},
1013 	{USB_DEVICE(0x04f1, 0x1001), BS(SPCA504B, 0)},
1014 	{USB_DEVICE(0x04fc, 0x500c), BS(SPCA504B, 0)},
1015 	{USB_DEVICE(0x04fc, 0x504a), BS(SPCA504, AiptekMiniPenCam13)},
1016 	{USB_DEVICE(0x04fc, 0x504b), BS(SPCA504B, 0)},
1017 	{USB_DEVICE(0x04fc, 0x5330), BS(SPCA533, 0)},
1018 	{USB_DEVICE(0x04fc, 0x5360), BS(SPCA536, 0)},
1019 	{USB_DEVICE(0x04fc, 0xffff), BS(SPCA504B, 0)},
1020 	{USB_DEVICE(0x052b, 0x1507), BS(SPCA533, MegapixV4)},
1021 	{USB_DEVICE(0x052b, 0x1513), BS(SPCA533, MegapixV4)},
1022 	{USB_DEVICE(0x052b, 0x1803), BS(SPCA533, MegaImageVI)},
1023 	{USB_DEVICE(0x0546, 0x3155), BS(SPCA533, 0)},
1024 	{USB_DEVICE(0x0546, 0x3191), BS(SPCA504B, 0)},
1025 	{USB_DEVICE(0x0546, 0x3273), BS(SPCA504B, 0)},
1026 	{USB_DEVICE(0x055f, 0xc211), BS(SPCA536, 0)},
1027 	{USB_DEVICE(0x055f, 0xc230), BS(SPCA533, 0)},
1028 	{USB_DEVICE(0x055f, 0xc232), BS(SPCA533, 0)},
1029 	{USB_DEVICE(0x055f, 0xc360), BS(SPCA536, 0)},
1030 	{USB_DEVICE(0x055f, 0xc420), BS(SPCA504, 0)},
1031 	{USB_DEVICE(0x055f, 0xc430), BS(SPCA533, 0)},
1032 	{USB_DEVICE(0x055f, 0xc440), BS(SPCA533, 0)},
1033 	{USB_DEVICE(0x055f, 0xc520), BS(SPCA504, 0)},
1034 	{USB_DEVICE(0x055f, 0xc530), BS(SPCA533, 0)},
1035 	{USB_DEVICE(0x055f, 0xc540), BS(SPCA533, 0)},
1036 	{USB_DEVICE(0x055f, 0xc630), BS(SPCA533, 0)},
1037 	{USB_DEVICE(0x055f, 0xc650), BS(SPCA533, 0)},
1038 	{USB_DEVICE(0x05da, 0x1018), BS(SPCA504B, 0)},
1039 	{USB_DEVICE(0x06d6, 0x0031), BS(SPCA533, 0)},
1040 	{USB_DEVICE(0x0733, 0x1311), BS(SPCA533, 0)},
1041 	{USB_DEVICE(0x0733, 0x1314), BS(SPCA533, 0)},
1042 	{USB_DEVICE(0x0733, 0x2211), BS(SPCA533, 0)},
1043 	{USB_DEVICE(0x0733, 0x2221), BS(SPCA533, 0)},
1044 	{USB_DEVICE(0x0733, 0x3261), BS(SPCA536, 0)},
1045 	{USB_DEVICE(0x0733, 0x3281), BS(SPCA536, 0)},
1046 	{USB_DEVICE(0x08ca, 0x0104), BS(SPCA533, 0)},
1047 	{USB_DEVICE(0x08ca, 0x0106), BS(SPCA533, 0)},
1048 	{USB_DEVICE(0x08ca, 0x2008), BS(SPCA504B, 0)},
1049 	{USB_DEVICE(0x08ca, 0x2010), BS(SPCA533, 0)},
1050 	{USB_DEVICE(0x08ca, 0x2016), BS(SPCA504B, 0)},
1051 	{USB_DEVICE(0x08ca, 0x2018), BS(SPCA504B, 0)},
1052 	{USB_DEVICE(0x08ca, 0x2020), BS(SPCA533, 0)},
1053 	{USB_DEVICE(0x08ca, 0x2022), BS(SPCA533, 0)},
1054 	{USB_DEVICE(0x08ca, 0x2024), BS(SPCA536, 0)},
1055 	{USB_DEVICE(0x08ca, 0x2028), BS(SPCA533, 0)},
1056 	{USB_DEVICE(0x08ca, 0x2040), BS(SPCA536, 0)},
1057 	{USB_DEVICE(0x08ca, 0x2042), BS(SPCA536, 0)},
1058 	{USB_DEVICE(0x08ca, 0x2050), BS(SPCA536, 0)},
1059 	{USB_DEVICE(0x08ca, 0x2060), BS(SPCA536, 0)},
1060 	{USB_DEVICE(0x0d64, 0x0303), BS(SPCA536, 0)},
1061 	{}
1062 };
1063 MODULE_DEVICE_TABLE(usb, device_table);
1064 
1065 /* -- device connect -- */
1066 static int sd_probe(struct usb_interface *intf,
1067 			const struct usb_device_id *id)
1068 {
1069 	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1070 				THIS_MODULE);
1071 }
1072 
1073 static struct usb_driver sd_driver = {
1074 	.name = MODULE_NAME,
1075 	.id_table = device_table,
1076 	.probe = sd_probe,
1077 	.disconnect = gspca_disconnect,
1078 #ifdef CONFIG_PM
1079 	.suspend = gspca_suspend,
1080 	.resume = gspca_resume,
1081 	.reset_resume = gspca_resume,
1082 #endif
1083 };
1084 
1085 module_usb_driver(sd_driver);
1086