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