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