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