xref: /openbmc/linux/drivers/media/usb/gspca/t613.c (revision ddc141e5)
1 /*
2  * T613 subdriver
3  *
4  * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr)
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  *Notes: * t613  + tas5130A
17  *	* Focus to light do not balance well as in win.
18  *	  Quality in win is not good, but its kinda better.
19  *	 * Fix some "extraneous bytes", most of apps will show the image anyway
20  *	 * Gamma table, is there, but its really doing something?
21  *	 * 7~8 Fps, its ok, max on win its 10.
22  *			Costantino Leandro
23  */
24 
25 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
26 
27 #define MODULE_NAME "t613"
28 
29 #include <linux/input.h>
30 #include <linux/slab.h>
31 #include "gspca.h"
32 
33 MODULE_AUTHOR("Leandro Costantino <le_costantino@pixartargentina.com.ar>");
34 MODULE_DESCRIPTION("GSPCA/T613 (JPEG Compliance) USB Camera Driver");
35 MODULE_LICENSE("GPL");
36 
37 struct sd {
38 	struct gspca_dev gspca_dev;	/* !! must be the first item */
39 	struct v4l2_ctrl *freq;
40 	struct { /* awb / color gains control cluster */
41 		struct v4l2_ctrl *awb;
42 		struct v4l2_ctrl *gain;
43 		struct v4l2_ctrl *red_balance;
44 		struct v4l2_ctrl *blue_balance;
45 	};
46 
47 	u8 sensor;
48 	u8 button_pressed;
49 };
50 enum sensors {
51 	SENSOR_OM6802,
52 	SENSOR_OTHER,
53 	SENSOR_TAS5130A,
54 	SENSOR_LT168G,		/* must verify if this is the actual model */
55 };
56 
57 static const struct v4l2_pix_format vga_mode_t16[] = {
58 	{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
59 		.bytesperline = 160,
60 		.sizeimage = 160 * 120 * 4 / 8 + 590,
61 		.colorspace = V4L2_COLORSPACE_JPEG,
62 		.priv = 4},
63 #if 0 /* HDG: broken with my test cam, so lets disable it */
64 	{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
65 		.bytesperline = 176,
66 		.sizeimage = 176 * 144 * 3 / 8 + 590,
67 		.colorspace = V4L2_COLORSPACE_JPEG,
68 		.priv = 3},
69 #endif
70 	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
71 		.bytesperline = 320,
72 		.sizeimage = 320 * 240 * 3 / 8 + 590,
73 		.colorspace = V4L2_COLORSPACE_JPEG,
74 		.priv = 2},
75 #if 0 /* HDG: broken with my test cam, so lets disable it */
76 	{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
77 		.bytesperline = 352,
78 		.sizeimage = 352 * 288 * 3 / 8 + 590,
79 		.colorspace = V4L2_COLORSPACE_JPEG,
80 		.priv = 1},
81 #endif
82 	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
83 		.bytesperline = 640,
84 		.sizeimage = 640 * 480 * 3 / 8 + 590,
85 		.colorspace = V4L2_COLORSPACE_JPEG,
86 		.priv = 0},
87 };
88 
89 /* sensor specific data */
90 struct additional_sensor_data {
91 	const u8 n3[6];
92 	const u8 *n4, n4sz;
93 	const u8 reg80, reg8e;
94 	const u8 nset8[6];
95 	const u8 data1[10];
96 	const u8 data2[9];
97 	const u8 data3[9];
98 	const u8 data5[6];
99 	const u8 stream[4];
100 };
101 
102 static const u8 n4_om6802[] = {
103 	0x09, 0x01, 0x12, 0x04, 0x66, 0x8a, 0x80, 0x3c,
104 	0x81, 0x22, 0x84, 0x50, 0x8a, 0x78, 0x8b, 0x68,
105 	0x8c, 0x88, 0x8e, 0x33, 0x8f, 0x24, 0xaa, 0xb1,
106 	0xa2, 0x60, 0xa5, 0x30, 0xa6, 0x3a, 0xa8, 0xe8,
107 	0xae, 0x05, 0xb1, 0x00, 0xbb, 0x04, 0xbc, 0x48,
108 	0xbe, 0x36, 0xc6, 0x88, 0xe9, 0x00, 0xc5, 0xc0,
109 	0x65, 0x0a, 0xbb, 0x86, 0xaf, 0x58, 0xb0, 0x68,
110 	0x87, 0x40, 0x89, 0x2b, 0x8d, 0xff, 0x83, 0x40,
111 	0xac, 0x84, 0xad, 0x86, 0xaf, 0x46
112 };
113 static const u8 n4_other[] = {
114 	0x66, 0x00, 0x7f, 0x00, 0x80, 0xac, 0x81, 0x69,
115 	0x84, 0x40, 0x85, 0x70, 0x86, 0x20, 0x8a, 0x68,
116 	0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xff, 0x8e, 0xb8,
117 	0x8f, 0x28, 0xa2, 0x60, 0xa5, 0x40, 0xa8, 0xa8,
118 	0xac, 0x84, 0xad, 0x84, 0xae, 0x24, 0xaf, 0x56,
119 	0xb0, 0x68, 0xb1, 0x00, 0xb2, 0x88, 0xbb, 0xc5,
120 	0xbc, 0x4a, 0xbe, 0x36, 0xc2, 0x88, 0xc5, 0xc0,
121 	0xc6, 0xda, 0xe9, 0x26, 0xeb, 0x00
122 };
123 static const u8 n4_tas5130a[] = {
124 	0x80, 0x3c, 0x81, 0x68, 0x83, 0xa0, 0x84, 0x20,
125 	0x8a, 0x68, 0x8b, 0x58, 0x8c, 0x88, 0x8e, 0xb4,
126 	0x8f, 0x24, 0xa1, 0xb1, 0xa2, 0x30, 0xa5, 0x10,
127 	0xa6, 0x4a, 0xae, 0x03, 0xb1, 0x44, 0xb2, 0x08,
128 	0xb7, 0x06, 0xb9, 0xe7, 0xbb, 0xc4, 0xbc, 0x4a,
129 	0xbe, 0x36, 0xbf, 0xff, 0xc2, 0x88, 0xc5, 0xc8,
130 	0xc6, 0xda
131 };
132 static const u8 n4_lt168g[] = {
133 	0x66, 0x01, 0x7f, 0x00, 0x80, 0x7c, 0x81, 0x28,
134 	0x83, 0x44, 0x84, 0x20, 0x86, 0x20, 0x8a, 0x70,
135 	0x8b, 0x58, 0x8c, 0x88, 0x8d, 0xa0, 0x8e, 0xb3,
136 	0x8f, 0x24, 0xa1, 0xb0, 0xa2, 0x38, 0xa5, 0x20,
137 	0xa6, 0x4a, 0xa8, 0xe8, 0xaf, 0x38, 0xb0, 0x68,
138 	0xb1, 0x44, 0xb2, 0x88, 0xbb, 0x86, 0xbd, 0x40,
139 	0xbe, 0x26, 0xc1, 0x05, 0xc2, 0x88, 0xc5, 0xc0,
140 	0xda, 0x8e, 0xdb, 0xca, 0xdc, 0xa8, 0xdd, 0x8c,
141 	0xde, 0x44, 0xdf, 0x0c, 0xe9, 0x80
142 };
143 
144 static const struct additional_sensor_data sensor_data[] = {
145 [SENSOR_OM6802] = {
146 	.n3 =
147 		{0x61, 0x68, 0x65, 0x0a, 0x60, 0x04},
148 	.n4 = n4_om6802,
149 	.n4sz = sizeof n4_om6802,
150 	.reg80 = 0x3c,
151 	.reg8e = 0x33,
152 	.nset8 = {0xa8, 0xf0, 0xc6, 0x88, 0xc0, 0x00},
153 	.data1 =
154 		{0xc2, 0x28, 0x0f, 0x22, 0xcd, 0x27, 0x2c, 0x06,
155 		 0xb3, 0xfc},
156 	.data2 =
157 		{0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
158 		 0xff},
159 	.data3 =
160 		{0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
161 		 0xff},
162 	.data5 =	/* this could be removed later */
163 		{0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
164 	.stream =
165 		{0x0b, 0x04, 0x0a, 0x78},
166     },
167 [SENSOR_OTHER] = {
168 	.n3 =
169 		{0x61, 0xc2, 0x65, 0x88, 0x60, 0x00},
170 	.n4 = n4_other,
171 	.n4sz = sizeof n4_other,
172 	.reg80 = 0xac,
173 	.reg8e = 0xb8,
174 	.nset8 = {0xa8, 0xa8, 0xc6, 0xda, 0xc0, 0x00},
175 	.data1 =
176 		{0xc1, 0x48, 0x04, 0x1b, 0xca, 0x2e, 0x33, 0x3a,
177 		 0xe8, 0xfc},
178 	.data2 =
179 		{0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
180 		 0xd9},
181 	.data3 =
182 		{0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
183 		 0xd9},
184 	.data5 =
185 		{0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},
186 	.stream =
187 		{0x0b, 0x04, 0x0a, 0x00},
188     },
189 [SENSOR_TAS5130A] = {
190 	.n3 =
191 		{0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08},
192 	.n4 = n4_tas5130a,
193 	.n4sz = sizeof n4_tas5130a,
194 	.reg80 = 0x3c,
195 	.reg8e = 0xb4,
196 	.nset8 = {0xa8, 0xf0, 0xc6, 0xda, 0xc0, 0x00},
197 	.data1 =
198 		{0xbb, 0x28, 0x10, 0x10, 0xbb, 0x28, 0x1e, 0x27,
199 		 0xc8, 0xfc},
200 	.data2 =
201 		{0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
202 		 0xe0},
203 	.data3 =
204 		{0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
205 		 0xe0},
206 	.data5 =
207 		{0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
208 	.stream =
209 		{0x0b, 0x04, 0x0a, 0x40},
210     },
211 [SENSOR_LT168G] = {
212 	.n3 = {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00},
213 	.n4 = n4_lt168g,
214 	.n4sz = sizeof n4_lt168g,
215 	.reg80 = 0x7c,
216 	.reg8e = 0xb3,
217 	.nset8 = {0xa8, 0xf0, 0xc6, 0xba, 0xc0, 0x00},
218 	.data1 = {0xc0, 0x38, 0x08, 0x10, 0xc0, 0x30, 0x10, 0x40,
219 		 0xb0, 0xf4},
220 	.data2 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
221 		 0xff},
222 	.data3 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
223 		 0xff},
224 	.data5 = {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b},
225 	.stream = {0x0b, 0x04, 0x0a, 0x28},
226     },
227 };
228 
229 #define MAX_EFFECTS 7
230 static const u8 effects_table[MAX_EFFECTS][6] = {
231 	{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00},	/* Normal */
232 	{0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04},	/* Repujar */
233 	{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x20},	/* Monochrome */
234 	{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x80},	/* Sepia */
235 	{0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x02},	/* Croquis */
236 	{0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x10},	/* Sun Effect */
237 	{0xa8, 0xc8, 0xc6, 0xd2, 0xc0, 0x40},	/* Negative */
238 };
239 
240 #define GAMMA_MAX (15)
241 static const u8 gamma_table[GAMMA_MAX+1][17] = {
242 /* gamma table from cam1690.ini */
243 	{0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21,	/* 0 */
244 	 0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb,
245 	 0xff},
246 	{0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d,	/* 1 */
247 	 0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1,
248 	 0xff},
249 	{0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35,	/* 2 */
250 	 0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3,
251 	 0xff},
252 	{0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f,	/* 3 */
253 	 0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6,
254 	 0xff},
255 	{0x00, 0x04, 0x0b, 0x15, 0x20, 0x2d, 0x3b, 0x4a,	/* 4 */
256 	 0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9,
257 	 0xff},
258 	{0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58,	/* 5 */
259 	 0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec,
260 	 0xff},
261 	{0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67,	/* 6 */
262 	 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
263 	 0xff},
264 	{0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,	/* 7 */
265 	 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
266 	 0xff},
267 	{0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79,	/* 8 */
268 	 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0,
269 	 0xff},
270 	{0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84,	/* 9 */
271 	 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2,
272 	 0xff},
273 	{0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e,	/* 10 */
274 	 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3,
275 	 0xff},
276 	{0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b,	/* 11 */
277 	 0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
278 	 0xff},
279 	{0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8,	/* 12 */
280 	 0xb4, 0xbf, 0xc9, 0xd3, 0xdc, 0xe5, 0xee, 0xf6,
281 	 0xff},
282 	{0x00, 0x54, 0x6f, 0x83, 0x93, 0xa0, 0xad, 0xb7,	/* 13 */
283 	 0xc2, 0xcb, 0xd4, 0xdc, 0xe4, 0xeb, 0xf2, 0xf9,
284 	 0xff},
285 	{0x00, 0x6e, 0x88, 0x9a, 0xa8, 0xb3, 0xbd, 0xc6,	/* 14 */
286 	 0xcf, 0xd6, 0xdd, 0xe3, 0xe9, 0xef, 0xf4, 0xfa,
287 	 0xff},
288 	{0x00, 0x93, 0xa8, 0xb7, 0xc1, 0xca, 0xd2, 0xd8,	/* 15 */
289 	 0xde, 0xe3, 0xe8, 0xed, 0xf1, 0xf5, 0xf8, 0xfc,
290 	 0xff}
291 };
292 
293 static const u8 tas5130a_sensor_init[][8] = {
294 	{0x62, 0x08, 0x63, 0x70, 0x64, 0x1d, 0x60, 0x09},
295 	{0x62, 0x20, 0x63, 0x01, 0x64, 0x02, 0x60, 0x09},
296 	{0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09},
297 };
298 
299 static u8 sensor_reset[] = {0x61, 0x68, 0x62, 0xff, 0x60, 0x07};
300 
301 /* read 1 byte */
302 static u8 reg_r(struct gspca_dev *gspca_dev,
303 		   u16 index)
304 {
305 	usb_control_msg(gspca_dev->dev,
306 			usb_rcvctrlpipe(gspca_dev->dev, 0),
307 			0,		/* request */
308 			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
309 			0,		/* value */
310 			index,
311 			gspca_dev->usb_buf, 1, 500);
312 	return gspca_dev->usb_buf[0];
313 }
314 
315 static void reg_w(struct gspca_dev *gspca_dev,
316 		  u16 index)
317 {
318 	usb_control_msg(gspca_dev->dev,
319 			usb_sndctrlpipe(gspca_dev->dev, 0),
320 			0,
321 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
322 			0, index,
323 			NULL, 0, 500);
324 }
325 
326 static void reg_w_buf(struct gspca_dev *gspca_dev,
327 		  const u8 *buffer, u16 len)
328 {
329 	if (len <= USB_BUF_SZ) {
330 		memcpy(gspca_dev->usb_buf, buffer, len);
331 		usb_control_msg(gspca_dev->dev,
332 				usb_sndctrlpipe(gspca_dev->dev, 0),
333 				0,
334 			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
335 				0x01, 0,
336 				gspca_dev->usb_buf, len, 500);
337 	} else {
338 		u8 *tmpbuf;
339 
340 		tmpbuf = kmemdup(buffer, len, GFP_KERNEL);
341 		if (!tmpbuf) {
342 			pr_err("Out of memory\n");
343 			return;
344 		}
345 		usb_control_msg(gspca_dev->dev,
346 				usb_sndctrlpipe(gspca_dev->dev, 0),
347 				0,
348 			   USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
349 				0x01, 0,
350 				tmpbuf, len, 500);
351 		kfree(tmpbuf);
352 	}
353 }
354 
355 /* write values to consecutive registers */
356 static void reg_w_ixbuf(struct gspca_dev *gspca_dev,
357 			u8 reg,
358 			const u8 *buffer, u16 len)
359 {
360 	int i;
361 	u8 *p, *tmpbuf;
362 
363 	if (len * 2 <= USB_BUF_SZ) {
364 		p = tmpbuf = gspca_dev->usb_buf;
365 	} else {
366 		p = tmpbuf = kmalloc(len * 2, GFP_KERNEL);
367 		if (!tmpbuf) {
368 			pr_err("Out of memory\n");
369 			return;
370 		}
371 	}
372 	i = len;
373 	while (--i >= 0) {
374 		*p++ = reg++;
375 		*p++ = *buffer++;
376 	}
377 	usb_control_msg(gspca_dev->dev,
378 			usb_sndctrlpipe(gspca_dev->dev, 0),
379 			0,
380 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
381 			0x01, 0,
382 			tmpbuf, len * 2, 500);
383 	if (len * 2 > USB_BUF_SZ)
384 		kfree(tmpbuf);
385 }
386 
387 static void om6802_sensor_init(struct gspca_dev *gspca_dev)
388 {
389 	int i;
390 	const u8 *p;
391 	u8 byte;
392 	u8 val[6] = {0x62, 0, 0x64, 0, 0x60, 0x05};
393 	static const u8 sensor_init[] = {
394 		0xdf, 0x6d,
395 		0xdd, 0x18,
396 		0x5a, 0xe0,
397 		0x5c, 0x07,
398 		0x5d, 0xb0,
399 		0x5e, 0x1e,
400 		0x60, 0x71,
401 		0xef, 0x00,
402 		0xe9, 0x00,
403 		0xea, 0x00,
404 		0x90, 0x24,
405 		0x91, 0xb2,
406 		0x82, 0x32,
407 		0xfd, 0x41,
408 		0x00			/* table end */
409 	};
410 
411 	reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
412 	msleep(100);
413 	i = 4;
414 	while (--i > 0) {
415 		byte = reg_r(gspca_dev, 0x0060);
416 		if (!(byte & 0x01))
417 			break;
418 		msleep(100);
419 	}
420 	byte = reg_r(gspca_dev, 0x0063);
421 	if (byte != 0x17) {
422 		pr_err("Bad sensor reset %02x\n", byte);
423 		/* continue? */
424 	}
425 
426 	p = sensor_init;
427 	while (*p != 0) {
428 		val[1] = *p++;
429 		val[3] = *p++;
430 		if (*p == 0)
431 			reg_w(gspca_dev, 0x3c80);
432 		reg_w_buf(gspca_dev, val, sizeof val);
433 		i = 4;
434 		while (--i >= 0) {
435 			msleep(15);
436 			byte = reg_r(gspca_dev, 0x60);
437 			if (!(byte & 0x01))
438 				break;
439 		}
440 	}
441 	msleep(15);
442 	reg_w(gspca_dev, 0x3c80);
443 }
444 
445 /* this function is called at probe time */
446 static int sd_config(struct gspca_dev *gspca_dev,
447 		     const struct usb_device_id *id)
448 {
449 	struct cam *cam  = &gspca_dev->cam;
450 
451 	cam->cam_mode = vga_mode_t16;
452 	cam->nmodes = ARRAY_SIZE(vga_mode_t16);
453 
454 	return 0;
455 }
456 
457 static void setbrightness(struct gspca_dev *gspca_dev, s32 brightness)
458 {
459 	u8 set6[4] = { 0x8f, 0x24, 0xc3, 0x00 };
460 
461 	if (brightness < 7) {
462 		set6[1] = 0x26;
463 		set6[3] = 0x70 - brightness * 0x10;
464 	} else {
465 		set6[3] = 0x00 + ((brightness - 7) * 0x10);
466 	}
467 
468 	reg_w_buf(gspca_dev, set6, sizeof set6);
469 }
470 
471 static void setcontrast(struct gspca_dev *gspca_dev, s32 contrast)
472 {
473 	u16 reg_to_write;
474 
475 	if (contrast < 7)
476 		reg_to_write = 0x8ea9 - contrast * 0x200;
477 	else
478 		reg_to_write = 0x00a9 + (contrast - 7) * 0x200;
479 
480 	reg_w(gspca_dev, reg_to_write);
481 }
482 
483 static void setcolors(struct gspca_dev *gspca_dev, s32 val)
484 {
485 	u16 reg_to_write;
486 
487 	reg_to_write = 0x80bb + val * 0x100;	/* was 0xc0 */
488 	reg_w(gspca_dev, reg_to_write);
489 }
490 
491 static void setgamma(struct gspca_dev *gspca_dev, s32 val)
492 {
493 	gspca_dbg(gspca_dev, D_CONF, "Gamma: %d\n", val);
494 	reg_w_ixbuf(gspca_dev, 0x90,
495 		gamma_table[val], sizeof gamma_table[0]);
496 }
497 
498 static void setawb_n_RGB(struct gspca_dev *gspca_dev)
499 {
500 	struct sd *sd = (struct sd *) gspca_dev;
501 	u8 all_gain_reg[8] = {
502 		0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00 };
503 	s32 red_gain, blue_gain, green_gain;
504 
505 	green_gain = sd->gain->val;
506 
507 	red_gain = green_gain + sd->red_balance->val;
508 	if (red_gain > 0x40)
509 		red_gain = 0x40;
510 	else if (red_gain < 0x10)
511 		red_gain = 0x10;
512 
513 	blue_gain = green_gain + sd->blue_balance->val;
514 	if (blue_gain > 0x40)
515 		blue_gain = 0x40;
516 	else if (blue_gain < 0x10)
517 		blue_gain = 0x10;
518 
519 	all_gain_reg[1] = red_gain;
520 	all_gain_reg[3] = blue_gain;
521 	all_gain_reg[5] = green_gain;
522 	all_gain_reg[7] = sensor_data[sd->sensor].reg80;
523 	if (!sd->awb->val)
524 		all_gain_reg[7] &= ~0x04; /* AWB off */
525 
526 	reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);
527 }
528 
529 static void setsharpness(struct gspca_dev *gspca_dev, s32 val)
530 {
531 	u16 reg_to_write;
532 
533 	reg_to_write = 0x0aa6 + 0x1000 * val;
534 
535 	reg_w(gspca_dev, reg_to_write);
536 }
537 
538 static void setfreq(struct gspca_dev *gspca_dev, s32 val)
539 {
540 	struct sd *sd = (struct sd *) gspca_dev;
541 	u8 reg66;
542 	u8 freq[4] = { 0x66, 0x00, 0xa8, 0xe8 };
543 
544 	switch (sd->sensor) {
545 	case SENSOR_LT168G:
546 		if (val != 0)
547 			freq[3] = 0xa8;
548 		reg66 = 0x41;
549 		break;
550 	case SENSOR_OM6802:
551 		reg66 = 0xca;
552 		break;
553 	default:
554 		reg66 = 0x40;
555 		break;
556 	}
557 	switch (val) {
558 	case 0:				/* no flicker */
559 		freq[3] = 0xf0;
560 		break;
561 	case 2:				/* 60Hz */
562 		reg66 &= ~0x40;
563 		break;
564 	}
565 	freq[1] = reg66;
566 
567 	reg_w_buf(gspca_dev, freq, sizeof freq);
568 }
569 
570 /* this function is called at probe and resume time */
571 static int sd_init(struct gspca_dev *gspca_dev)
572 {
573 	/* some of this registers are not really needed, because
574 	 * they are overridden by setbrigthness, setcontrast, etc.,
575 	 * but won't hurt anyway, and can help someone with similar webcam
576 	 * to see the initial parameters.*/
577 	struct sd *sd = (struct sd *) gspca_dev;
578 	const struct additional_sensor_data *sensor;
579 	int i;
580 	u16 sensor_id;
581 	u8 test_byte = 0;
582 
583 	static const u8 read_indexs[] =
584 		{ 0x0a, 0x0b, 0x66, 0x80, 0x81, 0x8e, 0x8f, 0xa5,
585 		  0xa6, 0xa8, 0xbb, 0xbc, 0xc6, 0x00 };
586 	static const u8 n1[] =
587 			{0x08, 0x03, 0x09, 0x03, 0x12, 0x04};
588 	static const u8 n2[] =
589 			{0x08, 0x00};
590 
591 	sensor_id = (reg_r(gspca_dev, 0x06) << 8)
592 			| reg_r(gspca_dev, 0x07);
593 	switch (sensor_id & 0xff0f) {
594 	case 0x0801:
595 		gspca_dbg(gspca_dev, D_PROBE, "sensor tas5130a\n");
596 		sd->sensor = SENSOR_TAS5130A;
597 		break;
598 	case 0x0802:
599 		gspca_dbg(gspca_dev, D_PROBE, "sensor lt168g\n");
600 		sd->sensor = SENSOR_LT168G;
601 		break;
602 	case 0x0803:
603 		gspca_dbg(gspca_dev, D_PROBE, "sensor 'other'\n");
604 		sd->sensor = SENSOR_OTHER;
605 		break;
606 	case 0x0807:
607 		gspca_dbg(gspca_dev, D_PROBE, "sensor om6802\n");
608 		sd->sensor = SENSOR_OM6802;
609 		break;
610 	default:
611 		pr_err("unknown sensor %04x\n", sensor_id);
612 		return -EINVAL;
613 	}
614 
615 	if (sd->sensor == SENSOR_OM6802) {
616 		reg_w_buf(gspca_dev, n1, sizeof n1);
617 		i = 5;
618 		while (--i >= 0) {
619 			reg_w_buf(gspca_dev, sensor_reset, sizeof sensor_reset);
620 			test_byte = reg_r(gspca_dev, 0x0063);
621 			msleep(100);
622 			if (test_byte == 0x17)
623 				break;		/* OK */
624 		}
625 		if (i < 0) {
626 			pr_err("Bad sensor reset %02x\n", test_byte);
627 			return -EIO;
628 		}
629 		reg_w_buf(gspca_dev, n2, sizeof n2);
630 	}
631 
632 	i = 0;
633 	while (read_indexs[i] != 0x00) {
634 		test_byte = reg_r(gspca_dev, read_indexs[i]);
635 		gspca_dbg(gspca_dev, D_STREAM, "Reg 0x%02x = 0x%02x\n",
636 			  read_indexs[i], test_byte);
637 		i++;
638 	}
639 
640 	sensor = &sensor_data[sd->sensor];
641 	reg_w_buf(gspca_dev, sensor->n3, sizeof sensor->n3);
642 	reg_w_buf(gspca_dev, sensor->n4, sensor->n4sz);
643 
644 	if (sd->sensor == SENSOR_LT168G) {
645 		test_byte = reg_r(gspca_dev, 0x80);
646 		gspca_dbg(gspca_dev, D_STREAM, "Reg 0x%02x = 0x%02x\n", 0x80,
647 			  test_byte);
648 		reg_w(gspca_dev, 0x6c80);
649 	}
650 
651 	reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
652 	reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
653 	reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
654 
655 	reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
656 	reg_w(gspca_dev, (sensor->reg80 << 8) + 0x80);
657 	reg_w(gspca_dev, (sensor->reg8e << 8) + 0x8e);
658 	reg_w(gspca_dev, (0x20 << 8) + 0x87);
659 	reg_w(gspca_dev, (0x20 << 8) + 0x88);
660 	reg_w(gspca_dev, (0x20 << 8) + 0x89);
661 
662 	reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5);
663 	reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8);
664 	reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
665 
666 	if (sd->sensor == SENSOR_LT168G) {
667 		test_byte = reg_r(gspca_dev, 0x80);
668 		gspca_dbg(gspca_dev, D_STREAM, "Reg 0x%02x = 0x%02x\n", 0x80,
669 			  test_byte);
670 		reg_w(gspca_dev, 0x6c80);
671 	}
672 
673 	reg_w_ixbuf(gspca_dev, 0xd0, sensor->data1, sizeof sensor->data1);
674 	reg_w_ixbuf(gspca_dev, 0xc7, sensor->data2, sizeof sensor->data2);
675 	reg_w_ixbuf(gspca_dev, 0xe0, sensor->data3, sizeof sensor->data3);
676 
677 	return 0;
678 }
679 
680 static void setmirror(struct gspca_dev *gspca_dev, s32 val)
681 {
682 	u8 hflipcmd[8] =
683 		{0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
684 
685 	if (val)
686 		hflipcmd[3] = 0x01;
687 
688 	reg_w_buf(gspca_dev, hflipcmd, sizeof hflipcmd);
689 }
690 
691 static void seteffect(struct gspca_dev *gspca_dev, s32 val)
692 {
693 	int idx = 0;
694 
695 	switch (val) {
696 	case V4L2_COLORFX_NONE:
697 		break;
698 	case V4L2_COLORFX_BW:
699 		idx = 2;
700 		break;
701 	case V4L2_COLORFX_SEPIA:
702 		idx = 3;
703 		break;
704 	case V4L2_COLORFX_SKETCH:
705 		idx = 4;
706 		break;
707 	case V4L2_COLORFX_NEGATIVE:
708 		idx = 6;
709 		break;
710 	default:
711 		break;
712 	}
713 
714 	reg_w_buf(gspca_dev, effects_table[idx],
715 				sizeof effects_table[0]);
716 
717 	if (val == V4L2_COLORFX_SKETCH)
718 		reg_w(gspca_dev, 0x4aa6);
719 	else
720 		reg_w(gspca_dev, 0xfaa6);
721 }
722 
723 /* Is this really needed?
724  * i added some module parameters for test with some users */
725 static void poll_sensor(struct gspca_dev *gspca_dev)
726 {
727 	static const u8 poll1[] =
728 		{0x67, 0x05, 0x68, 0x81, 0x69, 0x80, 0x6a, 0x82,
729 		 0x6b, 0x68, 0x6c, 0x69, 0x72, 0xd9, 0x73, 0x34,
730 		 0x74, 0x32, 0x75, 0x92, 0x76, 0x00, 0x09, 0x01,
731 		 0x60, 0x14};
732 	static const u8 poll2[] =
733 		{0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
734 		 0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
735 	static const u8 noise03[] =	/* (some differences / ms-drv) */
736 		{0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
737 		 0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
738 		 0xc2, 0x80, 0xc3, 0x10};
739 
740 	gspca_dbg(gspca_dev, D_STREAM, "[Sensor requires polling]\n");
741 	reg_w_buf(gspca_dev, poll1, sizeof poll1);
742 	reg_w_buf(gspca_dev, poll2, sizeof poll2);
743 	reg_w_buf(gspca_dev, noise03, sizeof noise03);
744 }
745 
746 static int sd_start(struct gspca_dev *gspca_dev)
747 {
748 	struct sd *sd = (struct sd *) gspca_dev;
749 	const struct additional_sensor_data *sensor;
750 	int i, mode;
751 	u8 t2[] = { 0x07, 0x00, 0x0d, 0x60, 0x0e, 0x80 };
752 	static const u8 t3[] =
753 		{ 0x07, 0x00, 0x88, 0x02, 0x06, 0x00, 0xe7, 0x01 };
754 
755 	mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
756 	switch (mode) {
757 	case 0:		/* 640x480 (0x00) */
758 		break;
759 	case 1:		/* 352x288 */
760 		t2[1] = 0x40;
761 		break;
762 	case 2:		/* 320x240 */
763 		t2[1] = 0x10;
764 		break;
765 	case 3:		/* 176x144 */
766 		t2[1] = 0x50;
767 		break;
768 	default:
769 /*	case 4:		 * 160x120 */
770 		t2[1] = 0x20;
771 		break;
772 	}
773 
774 	switch (sd->sensor) {
775 	case SENSOR_OM6802:
776 		om6802_sensor_init(gspca_dev);
777 		break;
778 	case SENSOR_TAS5130A:
779 		i = 0;
780 		for (;;) {
781 			reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
782 					 sizeof tas5130a_sensor_init[0]);
783 			if (i >= ARRAY_SIZE(tas5130a_sensor_init) - 1)
784 				break;
785 			i++;
786 		}
787 		reg_w(gspca_dev, 0x3c80);
788 		/* just in case and to keep sync with logs (for mine) */
789 		reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
790 				 sizeof tas5130a_sensor_init[0]);
791 		reg_w(gspca_dev, 0x3c80);
792 		break;
793 	}
794 	sensor = &sensor_data[sd->sensor];
795 	setfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->freq));
796 	reg_r(gspca_dev, 0x0012);
797 	reg_w_buf(gspca_dev, t2, sizeof t2);
798 	reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3);
799 	reg_w(gspca_dev, 0x0013);
800 	msleep(15);
801 	reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
802 	reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
803 
804 	if (sd->sensor == SENSOR_OM6802)
805 		poll_sensor(gspca_dev);
806 
807 	return 0;
808 }
809 
810 static void sd_stopN(struct gspca_dev *gspca_dev)
811 {
812 	struct sd *sd = (struct sd *) gspca_dev;
813 
814 	reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
815 			sizeof sensor_data[sd->sensor].stream);
816 	reg_w_buf(gspca_dev, sensor_data[sd->sensor].stream,
817 			sizeof sensor_data[sd->sensor].stream);
818 	if (sd->sensor == SENSOR_OM6802) {
819 		msleep(20);
820 		reg_w(gspca_dev, 0x0309);
821 	}
822 #if IS_ENABLED(CONFIG_INPUT)
823 	/* If the last button state is pressed, release it now! */
824 	if (sd->button_pressed) {
825 		input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
826 		input_sync(gspca_dev->input_dev);
827 		sd->button_pressed = 0;
828 	}
829 #endif
830 }
831 
832 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
833 			u8 *data,			/* isoc packet */
834 			int len)			/* iso packet length */
835 {
836 	struct sd *sd __maybe_unused = (struct sd *) gspca_dev;
837 	int pkt_type;
838 
839 	if (data[0] == 0x5a) {
840 #if IS_ENABLED(CONFIG_INPUT)
841 		if (len > 20) {
842 			u8 state = (data[20] & 0x80) ? 1 : 0;
843 			if (sd->button_pressed != state) {
844 				input_report_key(gspca_dev->input_dev,
845 						 KEY_CAMERA, state);
846 				input_sync(gspca_dev->input_dev);
847 				sd->button_pressed = state;
848 			}
849 		}
850 #endif
851 		/* Control Packet, after this came the header again,
852 		 * but extra bytes came in the packet before this,
853 		 * sometimes an EOF arrives, sometimes not... */
854 		return;
855 	}
856 	data += 2;
857 	len -= 2;
858 	if (data[0] == 0xff && data[1] == 0xd8)
859 		pkt_type = FIRST_PACKET;
860 	else if (data[len - 2] == 0xff && data[len - 1] == 0xd9)
861 		pkt_type = LAST_PACKET;
862 	else
863 		pkt_type = INTER_PACKET;
864 	gspca_frame_add(gspca_dev, pkt_type, data, len);
865 }
866 
867 static int sd_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
868 {
869 	struct gspca_dev *gspca_dev =
870 		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
871 	struct sd *sd = (struct sd *)gspca_dev;
872 	s32 red_gain, blue_gain, green_gain;
873 
874 	gspca_dev->usb_err = 0;
875 
876 	switch (ctrl->id) {
877 	case V4L2_CID_AUTO_WHITE_BALANCE:
878 		red_gain = reg_r(gspca_dev, 0x0087);
879 		if (red_gain > 0x40)
880 			red_gain = 0x40;
881 		else if (red_gain < 0x10)
882 			red_gain = 0x10;
883 
884 		blue_gain = reg_r(gspca_dev, 0x0088);
885 		if (blue_gain > 0x40)
886 			blue_gain = 0x40;
887 		else if (blue_gain < 0x10)
888 			blue_gain = 0x10;
889 
890 		green_gain = reg_r(gspca_dev, 0x0089);
891 		if (green_gain > 0x40)
892 			green_gain = 0x40;
893 		else if (green_gain < 0x10)
894 			green_gain = 0x10;
895 
896 		sd->gain->val = green_gain;
897 		sd->red_balance->val = red_gain - green_gain;
898 		sd->blue_balance->val = blue_gain - green_gain;
899 		break;
900 	}
901 	return 0;
902 }
903 
904 static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
905 {
906 	struct gspca_dev *gspca_dev =
907 		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
908 
909 	gspca_dev->usb_err = 0;
910 
911 	if (!gspca_dev->streaming)
912 		return 0;
913 
914 	switch (ctrl->id) {
915 	case V4L2_CID_BRIGHTNESS:
916 		setbrightness(gspca_dev, ctrl->val);
917 		break;
918 	case V4L2_CID_CONTRAST:
919 		setcontrast(gspca_dev, ctrl->val);
920 		break;
921 	case V4L2_CID_SATURATION:
922 		setcolors(gspca_dev, ctrl->val);
923 		break;
924 	case V4L2_CID_GAMMA:
925 		setgamma(gspca_dev, ctrl->val);
926 		break;
927 	case V4L2_CID_HFLIP:
928 		setmirror(gspca_dev, ctrl->val);
929 		break;
930 	case V4L2_CID_SHARPNESS:
931 		setsharpness(gspca_dev, ctrl->val);
932 		break;
933 	case V4L2_CID_POWER_LINE_FREQUENCY:
934 		setfreq(gspca_dev, ctrl->val);
935 		break;
936 	case V4L2_CID_BACKLIGHT_COMPENSATION:
937 		reg_w(gspca_dev, ctrl->val ? 0xf48e : 0xb48e);
938 		break;
939 	case V4L2_CID_AUTO_WHITE_BALANCE:
940 		setawb_n_RGB(gspca_dev);
941 		break;
942 	case V4L2_CID_COLORFX:
943 		seteffect(gspca_dev, ctrl->val);
944 		break;
945 	}
946 	return gspca_dev->usb_err;
947 }
948 
949 static const struct v4l2_ctrl_ops sd_ctrl_ops = {
950 	.g_volatile_ctrl = sd_g_volatile_ctrl,
951 	.s_ctrl = sd_s_ctrl,
952 };
953 
954 static int sd_init_controls(struct gspca_dev *gspca_dev)
955 {
956 	struct sd *sd = (struct sd *)gspca_dev;
957 	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
958 
959 	gspca_dev->vdev.ctrl_handler = hdl;
960 	v4l2_ctrl_handler_init(hdl, 12);
961 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
962 			V4L2_CID_BRIGHTNESS, 0, 14, 1, 8);
963 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
964 			V4L2_CID_CONTRAST, 0, 0x0d, 1, 7);
965 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
966 			V4L2_CID_SATURATION, 0, 0xf, 1, 5);
967 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
968 			V4L2_CID_GAMMA, 0, GAMMA_MAX, 1, 10);
969 	/* Activate lowlight, some apps dont bring up the
970 	   backlight_compensation control) */
971 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
972 			V4L2_CID_BACKLIGHT_COMPENSATION, 0, 1, 1, 1);
973 	if (sd->sensor == SENSOR_TAS5130A)
974 		v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
975 				V4L2_CID_HFLIP, 0, 1, 1, 0);
976 	sd->awb = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
977 			V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1);
978 	sd->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
979 			V4L2_CID_GAIN, 0x10, 0x40, 1, 0x20);
980 	sd->blue_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
981 			V4L2_CID_BLUE_BALANCE, -0x30, 0x30, 1, 0);
982 	sd->red_balance = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
983 			V4L2_CID_RED_BALANCE, -0x30, 0x30, 1, 0);
984 	v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
985 			V4L2_CID_SHARPNESS, 0, 15, 1, 6);
986 	v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
987 			V4L2_CID_COLORFX, V4L2_COLORFX_SKETCH,
988 			~((1 << V4L2_COLORFX_NONE) |
989 			  (1 << V4L2_COLORFX_BW) |
990 			  (1 << V4L2_COLORFX_SEPIA) |
991 			  (1 << V4L2_COLORFX_SKETCH) |
992 			  (1 << V4L2_COLORFX_NEGATIVE)),
993 			V4L2_COLORFX_NONE);
994 	sd->freq = v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
995 			V4L2_CID_POWER_LINE_FREQUENCY,
996 			V4L2_CID_POWER_LINE_FREQUENCY_60HZ, 1,
997 			V4L2_CID_POWER_LINE_FREQUENCY_50HZ);
998 
999 	if (hdl->error) {
1000 		pr_err("Could not initialize controls\n");
1001 		return hdl->error;
1002 	}
1003 
1004 	v4l2_ctrl_auto_cluster(4, &sd->awb, 0, true);
1005 
1006 	return 0;
1007 }
1008 
1009 /* sub-driver description */
1010 static const struct sd_desc sd_desc = {
1011 	.name = MODULE_NAME,
1012 	.config = sd_config,
1013 	.init = sd_init,
1014 	.init_controls = sd_init_controls,
1015 	.start = sd_start,
1016 	.stopN = sd_stopN,
1017 	.pkt_scan = sd_pkt_scan,
1018 #if IS_ENABLED(CONFIG_INPUT)
1019 	.other_input = 1,
1020 #endif
1021 };
1022 
1023 /* -- module initialisation -- */
1024 static const struct usb_device_id device_table[] = {
1025 	{USB_DEVICE(0x17a1, 0x0128)},
1026 	{}
1027 };
1028 MODULE_DEVICE_TABLE(usb, device_table);
1029 
1030 /* -- device connect -- */
1031 static int sd_probe(struct usb_interface *intf,
1032 		    const struct usb_device_id *id)
1033 {
1034 	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
1035 			       THIS_MODULE);
1036 }
1037 
1038 static struct usb_driver sd_driver = {
1039 	.name = MODULE_NAME,
1040 	.id_table = device_table,
1041 	.probe = sd_probe,
1042 	.disconnect = gspca_disconnect,
1043 #ifdef CONFIG_PM
1044 	.suspend = gspca_suspend,
1045 	.resume = gspca_resume,
1046 	.reset_resume = gspca_resume,
1047 #endif
1048 };
1049 
1050 module_usb_driver(sd_driver);
1051