xref: /openbmc/linux/drivers/media/usb/gspca/conex.c (revision 7effbd18)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  *		Connexant Cx11646 library
4  *		Copyright (C) 2004 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 "conex"
12 
13 #include "gspca.h"
14 #define CONEX_CAM 1		/* special JPEG header */
15 #include "jpeg.h"
16 
17 MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
18 MODULE_DESCRIPTION("GSPCA USB Conexant Camera Driver");
19 MODULE_LICENSE("GPL");
20 
21 #define QUALITY 50
22 
23 /* specific webcam descriptor */
24 struct sd {
25 	struct gspca_dev gspca_dev;	/* !! must be the first item */
26 	struct v4l2_ctrl *brightness;
27 	struct v4l2_ctrl *contrast;
28 	struct v4l2_ctrl *sat;
29 
30 	u8 jpeg_hdr[JPEG_HDR_SZ];
31 };
32 
33 static const struct v4l2_pix_format vga_mode[] = {
34 	{176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
35 		.bytesperline = 176,
36 		.sizeimage = 176 * 144 * 3 / 8 + 590,
37 		.colorspace = V4L2_COLORSPACE_JPEG,
38 		.priv = 3},
39 	{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
40 		.bytesperline = 320,
41 		.sizeimage = 320 * 240 * 3 / 8 + 590,
42 		.colorspace = V4L2_COLORSPACE_JPEG,
43 		.priv = 2},
44 	{352, 288, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
45 		.bytesperline = 352,
46 		.sizeimage = 352 * 288 * 3 / 8 + 590,
47 		.colorspace = V4L2_COLORSPACE_JPEG,
48 		.priv = 1},
49 	{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
50 		.bytesperline = 640,
51 		.sizeimage = 640 * 480 * 3 / 8 + 590,
52 		.colorspace = V4L2_COLORSPACE_JPEG,
53 		.priv = 0},
54 };
55 
56 /* the read bytes are found in gspca_dev->usb_buf */
57 static void reg_r(struct gspca_dev *gspca_dev,
58 		  __u16 index,
59 		  __u16 len)
60 {
61 	struct usb_device *dev = gspca_dev->dev;
62 
63 	if (len > USB_BUF_SZ) {
64 		gspca_err(gspca_dev, "reg_r: buffer overflow\n");
65 		return;
66 	}
67 
68 	usb_control_msg(dev,
69 			usb_rcvctrlpipe(dev, 0),
70 			0,
71 			USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
72 			0,
73 			index, gspca_dev->usb_buf, len,
74 			500);
75 	gspca_dbg(gspca_dev, D_USBI, "reg read [%02x] -> %02x ..\n",
76 		  index, gspca_dev->usb_buf[0]);
77 }
78 
79 /* the bytes to write are in gspca_dev->usb_buf */
80 static void reg_w_val(struct gspca_dev *gspca_dev,
81 			__u16 index,
82 			__u8 val)
83 {
84 	struct usb_device *dev = gspca_dev->dev;
85 
86 	gspca_dev->usb_buf[0] = val;
87 	usb_control_msg(dev,
88 			usb_sndctrlpipe(dev, 0),
89 			0,
90 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
91 			0,
92 			index, gspca_dev->usb_buf, 1, 500);
93 }
94 
95 static void reg_w(struct gspca_dev *gspca_dev,
96 		  __u16 index,
97 		  const __u8 *buffer,
98 		  __u16 len)
99 {
100 	struct usb_device *dev = gspca_dev->dev;
101 
102 	if (len > USB_BUF_SZ) {
103 		gspca_err(gspca_dev, "reg_w: buffer overflow\n");
104 		return;
105 	}
106 	gspca_dbg(gspca_dev, D_USBO, "reg write [%02x] = %02x..\n",
107 		  index, *buffer);
108 
109 	memcpy(gspca_dev->usb_buf, buffer, len);
110 	usb_control_msg(dev,
111 			usb_sndctrlpipe(dev, 0),
112 			0,
113 			USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
114 			0,
115 			index, gspca_dev->usb_buf, len, 500);
116 }
117 
118 static const __u8 cx_sensor_init[][4] = {
119 	{0x88, 0x11, 0x01, 0x01},
120 	{0x88, 0x12, 0x70, 0x01},
121 	{0x88, 0x0f, 0x00, 0x01},
122 	{0x88, 0x05, 0x01, 0x01},
123 	{}
124 };
125 
126 static const __u8 cx11646_fw1[][3] = {
127 	{0x00, 0x02, 0x00},
128 	{0x01, 0x43, 0x00},
129 	{0x02, 0xA7, 0x00},
130 	{0x03, 0x8B, 0x01},
131 	{0x04, 0xE9, 0x02},
132 	{0x05, 0x08, 0x04},
133 	{0x06, 0x08, 0x05},
134 	{0x07, 0x07, 0x06},
135 	{0x08, 0xE7, 0x06},
136 	{0x09, 0xC6, 0x07},
137 	{0x0A, 0x86, 0x08},
138 	{0x0B, 0x46, 0x09},
139 	{0x0C, 0x05, 0x0A},
140 	{0x0D, 0xA5, 0x0A},
141 	{0x0E, 0x45, 0x0B},
142 	{0x0F, 0xE5, 0x0B},
143 	{0x10, 0x85, 0x0C},
144 	{0x11, 0x25, 0x0D},
145 	{0x12, 0xC4, 0x0D},
146 	{0x13, 0x45, 0x0E},
147 	{0x14, 0xE4, 0x0E},
148 	{0x15, 0x64, 0x0F},
149 	{0x16, 0xE4, 0x0F},
150 	{0x17, 0x64, 0x10},
151 	{0x18, 0xE4, 0x10},
152 	{0x19, 0x64, 0x11},
153 	{0x1A, 0xE4, 0x11},
154 	{0x1B, 0x64, 0x12},
155 	{0x1C, 0xE3, 0x12},
156 	{0x1D, 0x44, 0x13},
157 	{0x1E, 0xC3, 0x13},
158 	{0x1F, 0x24, 0x14},
159 	{0x20, 0xA3, 0x14},
160 	{0x21, 0x04, 0x15},
161 	{0x22, 0x83, 0x15},
162 	{0x23, 0xE3, 0x15},
163 	{0x24, 0x43, 0x16},
164 	{0x25, 0xA4, 0x16},
165 	{0x26, 0x23, 0x17},
166 	{0x27, 0x83, 0x17},
167 	{0x28, 0xE3, 0x17},
168 	{0x29, 0x43, 0x18},
169 	{0x2A, 0xA3, 0x18},
170 	{0x2B, 0x03, 0x19},
171 	{0x2C, 0x63, 0x19},
172 	{0x2D, 0xC3, 0x19},
173 	{0x2E, 0x22, 0x1A},
174 	{0x2F, 0x63, 0x1A},
175 	{0x30, 0xC3, 0x1A},
176 	{0x31, 0x23, 0x1B},
177 	{0x32, 0x83, 0x1B},
178 	{0x33, 0xE2, 0x1B},
179 	{0x34, 0x23, 0x1C},
180 	{0x35, 0x83, 0x1C},
181 	{0x36, 0xE2, 0x1C},
182 	{0x37, 0x23, 0x1D},
183 	{0x38, 0x83, 0x1D},
184 	{0x39, 0xE2, 0x1D},
185 	{0x3A, 0x23, 0x1E},
186 	{0x3B, 0x82, 0x1E},
187 	{0x3C, 0xC3, 0x1E},
188 	{0x3D, 0x22, 0x1F},
189 	{0x3E, 0x63, 0x1F},
190 	{0x3F, 0xC1, 0x1F},
191 	{}
192 };
193 static void cx11646_fw(struct gspca_dev*gspca_dev)
194 {
195 	int i = 0;
196 
197 	reg_w_val(gspca_dev, 0x006a, 0x02);
198 	while (cx11646_fw1[i][1]) {
199 		reg_w(gspca_dev, 0x006b, cx11646_fw1[i], 3);
200 		i++;
201 	}
202 	reg_w_val(gspca_dev, 0x006a, 0x00);
203 }
204 
205 static const __u8 cxsensor[] = {
206 	0x88, 0x12, 0x70, 0x01,
207 	0x88, 0x0d, 0x02, 0x01,
208 	0x88, 0x0f, 0x00, 0x01,
209 	0x88, 0x03, 0x71, 0x01, 0x88, 0x04, 0x00, 0x01,	/* 3 */
210 	0x88, 0x02, 0x10, 0x01,
211 	0x88, 0x00, 0xD4, 0x01, 0x88, 0x01, 0x01, 0x01,	/* 5 */
212 	0x88, 0x0B, 0x00, 0x01,
213 	0x88, 0x0A, 0x0A, 0x01,
214 	0x88, 0x00, 0x08, 0x01, 0x88, 0x01, 0x00, 0x01,	/* 8 */
215 	0x88, 0x05, 0x01, 0x01,
216 	0xA1, 0x18, 0x00, 0x01,
217 	0x00
218 };
219 
220 static const __u8 reg20[] = { 0x10, 0x42, 0x81, 0x19, 0xd3, 0xff, 0xa7, 0xff };
221 static const __u8 reg28[] = { 0x87, 0x00, 0x87, 0x00, 0x8f, 0xff, 0xea, 0xff };
222 static const __u8 reg10[] = { 0xb1, 0xb1 };
223 static const __u8 reg71a[] = { 0x08, 0x18, 0x0a, 0x1e };	/* 640 */
224 static const __u8 reg71b[] = { 0x04, 0x0c, 0x05, 0x0f };
225 	/* 352{0x04,0x0a,0x06,0x12}; //352{0x05,0x0e,0x06,0x11}; //352 */
226 static const __u8 reg71c[] = { 0x02, 0x07, 0x03, 0x09 };
227 					/* 320{0x04,0x0c,0x05,0x0f}; //320 */
228 static const __u8 reg71d[] = { 0x02, 0x07, 0x03, 0x09 };	/* 176 */
229 static const __u8 reg7b[] = { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff };
230 
231 static void cx_sensor(struct gspca_dev*gspca_dev)
232 {
233 	int i = 0;
234 	int length;
235 	const __u8 *ptsensor = cxsensor;
236 
237 	reg_w(gspca_dev, 0x0020, reg20, 8);
238 	reg_w(gspca_dev, 0x0028, reg28, 8);
239 	reg_w(gspca_dev, 0x0010, reg10, 2);
240 	reg_w_val(gspca_dev, 0x0092, 0x03);
241 
242 	switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
243 	case 0:
244 		reg_w(gspca_dev, 0x0071, reg71a, 4);
245 		break;
246 	case 1:
247 		reg_w(gspca_dev, 0x0071, reg71b, 4);
248 		break;
249 	default:
250 /*	case 2: */
251 		reg_w(gspca_dev, 0x0071, reg71c, 4);
252 		break;
253 	case 3:
254 		reg_w(gspca_dev, 0x0071, reg71d, 4);
255 		break;
256 	}
257 	reg_w(gspca_dev, 0x007b, reg7b, 6);
258 	reg_w_val(gspca_dev, 0x00f8, 0x00);
259 	reg_w(gspca_dev, 0x0010, reg10, 2);
260 	reg_w_val(gspca_dev, 0x0098, 0x41);
261 	for (i = 0; i < 11; i++) {
262 		if (i == 3 || i == 5 || i == 8)
263 			length = 8;
264 		else
265 			length = 4;
266 		reg_w(gspca_dev, 0x00e5, ptsensor, length);
267 		if (length == 4)
268 			reg_r(gspca_dev, 0x00e8, 1);
269 		else
270 			reg_r(gspca_dev, 0x00e8, length);
271 		ptsensor += length;
272 	}
273 	reg_r(gspca_dev, 0x00e7, 8);
274 }
275 
276 static const __u8 cx_inits_176[] = {
277 	0x33, 0x81, 0xB0, 0x00, 0x90, 0x00, 0x0A, 0x03,	/* 176x144 */
278 	0x00, 0x03, 0x03, 0x03, 0x1B, 0x05, 0x30, 0x03,
279 	0x65, 0x15, 0x18, 0x25, 0x03, 0x25, 0x08, 0x30,
280 	0x3B, 0x25, 0x10, 0x00, 0x04, 0x00, 0x00, 0x00,
281 	0xDC, 0xFF, 0xEE, 0xFF, 0xC5, 0xFF, 0xBF, 0xFF,
282 	0xF7, 0xFF, 0x88, 0xFF, 0x66, 0x02, 0x28, 0x02,
283 	0x1E, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
284 };
285 static const __u8 cx_inits_320[] = {
286 	0x7f, 0x7f, 0x40, 0x01, 0xf0, 0x00, 0x02, 0x01,
287 	0x00, 0x01, 0x01, 0x01, 0x10, 0x00, 0x02, 0x01,
288 	0x65, 0x45, 0xfa, 0x4c, 0x2c, 0xdf, 0xb9, 0x81,
289 	0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
290 	0xe2, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff,
291 	0xf5, 0xff, 0x6d, 0xff, 0xf6, 0x01, 0x43, 0x02,
292 	0xd3, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
293 };
294 static const __u8 cx_inits_352[] = {
295 	0x2e, 0x7c, 0x60, 0x01, 0x20, 0x01, 0x05, 0x03,
296 	0x00, 0x06, 0x03, 0x06, 0x1b, 0x10, 0x05, 0x3b,
297 	0x30, 0x25, 0x18, 0x25, 0x08, 0x30, 0x03, 0x25,
298 	0x3b, 0x30, 0x25, 0x1b, 0x10, 0x05, 0x00, 0x00,
299 	0xe3, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff,
300 	0xf5, 0xff, 0x6b, 0xff, 0xee, 0x01, 0x43, 0x02,
301 	0xe4, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
302 };
303 static const __u8 cx_inits_640[] = {
304 	0x7e, 0x7e, 0x80, 0x02, 0xe0, 0x01, 0x01, 0x01,
305 	0x00, 0x02, 0x01, 0x02, 0x10, 0x30, 0x01, 0x01,
306 	0x65, 0x45, 0xf7, 0x52, 0x2c, 0xdf, 0xb9, 0x81,
307 	0x30, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
308 	0xe2, 0xff, 0xf1, 0xff, 0xc2, 0xff, 0xbc, 0xff,
309 	0xf6, 0xff, 0x7b, 0xff, 0x01, 0x02, 0x43, 0x02,
310 	0x77, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
311 };
312 
313 static void cx11646_initsize(struct gspca_dev *gspca_dev)
314 {
315 	const __u8 *cxinit;
316 	static const __u8 reg12[] = { 0x08, 0x05, 0x07, 0x04, 0x24 };
317 	static const __u8 reg17[] =
318 			{ 0x0a, 0x00, 0xf2, 0x01, 0x0f, 0x00, 0x97, 0x02 };
319 
320 	switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
321 	case 0:
322 		cxinit = cx_inits_640;
323 		break;
324 	case 1:
325 		cxinit = cx_inits_352;
326 		break;
327 	default:
328 /*	case 2: */
329 		cxinit = cx_inits_320;
330 		break;
331 	case 3:
332 		cxinit = cx_inits_176;
333 		break;
334 	}
335 	reg_w_val(gspca_dev, 0x009a, 0x01);
336 	reg_w_val(gspca_dev, 0x0010, 0x10);
337 	reg_w(gspca_dev, 0x0012, reg12, 5);
338 	reg_w(gspca_dev, 0x0017, reg17, 8);
339 	reg_w_val(gspca_dev, 0x00c0, 0x00);
340 	reg_w_val(gspca_dev, 0x00c1, 0x04);
341 	reg_w_val(gspca_dev, 0x00c2, 0x04);
342 
343 	reg_w(gspca_dev, 0x0061, cxinit, 8);
344 	cxinit += 8;
345 	reg_w(gspca_dev, 0x00ca, cxinit, 8);
346 	cxinit += 8;
347 	reg_w(gspca_dev, 0x00d2, cxinit, 8);
348 	cxinit += 8;
349 	reg_w(gspca_dev, 0x00da, cxinit, 6);
350 	cxinit += 8;
351 	reg_w(gspca_dev, 0x0041, cxinit, 8);
352 	cxinit += 8;
353 	reg_w(gspca_dev, 0x0049, cxinit, 8);
354 	cxinit += 8;
355 	reg_w(gspca_dev, 0x0051, cxinit, 2);
356 
357 	reg_r(gspca_dev, 0x0010, 1);
358 }
359 
360 static const __u8 cx_jpeg_init[][8] = {
361 	{0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x15},	/* 1 */
362 	{0x0f, 0x10, 0x12, 0x10, 0x0d, 0x15, 0x12, 0x11},
363 	{0x12, 0x18, 0x16, 0x15, 0x19, 0x20, 0x35, 0x22},
364 	{0x20, 0x1d, 0x1d, 0x20, 0x41, 0x2e, 0x31, 0x26},
365 	{0x35, 0x4d, 0x43, 0x51, 0x4f, 0x4b, 0x43, 0x4a},
366 	{0x49, 0x55, 0x5F, 0x79, 0x67, 0x55, 0x5A, 0x73},
367 	{0x5B, 0x49, 0x4A, 0x6A, 0x90, 0x6B, 0x73, 0x7D},
368 	{0x81, 0x88, 0x89, 0x88, 0x52, 0x66, 0x95, 0xA0},
369 	{0x94, 0x84, 0x9E, 0x79, 0x85, 0x88, 0x83, 0x01},
370 	{0x15, 0x0F, 0x10, 0x12, 0x10, 0x0D, 0x15, 0x12},
371 	{0x11, 0x12, 0x18, 0x16, 0x15, 0x19, 0x20, 0x35},
372 	{0x22, 0x20, 0x1D, 0x1D, 0x20, 0x41, 0x2E, 0x31},
373 	{0x26, 0x35, 0x4D, 0x43, 0x51, 0x4F, 0x4B, 0x43},
374 	{0x4A, 0x49, 0x55, 0x5F, 0x79, 0x67, 0x55, 0x5A},
375 	{0x73, 0x5B, 0x49, 0x4A, 0x6A, 0x90, 0x6B, 0x73},
376 	{0x7D, 0x81, 0x88, 0x89, 0x88, 0x52, 0x66, 0x95},
377 	{0xA0, 0x94, 0x84, 0x9E, 0x79, 0x85, 0x88, 0x83},
378 	{0xFF, 0xC4, 0x01, 0xA2, 0x00, 0x00, 0x01, 0x05},
379 	{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00},
380 	{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02},
381 	{0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A},
382 	{0x0B, 0x01, 0x00, 0x03, 0x01, 0x01, 0x01, 0x01},
383 	{0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00},
384 	{0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05},
385 	{0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x10, 0x00},
386 	{0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05},
387 	{0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7D, 0x01},
388 	{0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12, 0x21},
389 	{0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22},
390 	{0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08, 0x23},
391 	{0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0, 0x24},
392 	{0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17},
393 	{0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28, 0x29},
394 	{0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A},
395 	{0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A},
396 	{0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A},
397 	{0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A},
398 	{0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A},
399 	{0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A},
400 	{0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99},
401 	{0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8},
402 	{0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7},
403 	{0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6},
404 	{0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5},
405 	{0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2, 0xE3},
406 	{0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xF1},
407 	{0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9},
408 	{0xFA, 0x11, 0x00, 0x02, 0x01, 0x02, 0x04, 0x04},
409 	{0x03, 0x04, 0x07, 0x05, 0x04, 0x04, 0x00, 0x01},
410 	{0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04},
411 	{0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07},
412 	{0x61, 0x71, 0x13, 0x22, 0x32, 0x81, 0x08, 0x14},
413 	{0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33},
414 	{0x52, 0xF0, 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16},
415 	{0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19},
416 	{0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36},
417 	{0x37, 0x38, 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46},
418 	{0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55, 0x56},
419 	{0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66},
420 	{0x67, 0x68, 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76},
421 	{0x77, 0x78, 0x79, 0x7A, 0x82, 0x83, 0x84, 0x85},
422 	{0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94},
423 	{0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3},
424 	{0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2},
425 	{0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA},
426 	{0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9},
427 	{0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8},
428 	{0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7},
429 	{0xE8, 0xE9, 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6},
430 	{0xF7, 0xF8, 0xF9, 0xFA, 0xFF, 0x20, 0x00, 0x1F},
431 	{0x02, 0x0C, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x00},
432 	{0x00, 0x00, 0x11, 0x00, 0x11, 0x22, 0x00, 0x22},
433 	{0x22, 0x11, 0x22, 0x22, 0x11, 0x33, 0x33, 0x11},
434 	{0x44, 0x66, 0x22, 0x55, 0x66, 0xFF, 0xDD, 0x00},
435 	{0x04, 0x00, 0x14, 0xFF, 0xC0, 0x00, 0x11, 0x08},
436 	{0x00, 0xF0, 0x01, 0x40, 0x03, 0x00, 0x21, 0x00},
437 	{0x01, 0x11, 0x01, 0x02, 0x11, 0x01, 0xFF, 0xDA},
438 	{0x00, 0x0C, 0x03, 0x00, 0x00, 0x01, 0x11, 0x02},
439 	{0x11, 0x00, 0x3F, 0x00, 0xFF, 0xD9, 0x00, 0x00}	/* 79 */
440 };
441 
442 
443 static const __u8 cxjpeg_640[][8] = {
444 	{0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x10},	/* 1 */
445 	{0x0b, 0x0c, 0x0e, 0x0c, 0x0a, 0x10, 0x0e, 0x0d},
446 	{0x0e, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28, 0x1a},
447 	{0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25, 0x1d},
448 	{0x28, 0x3a, 0x33, 0x3D, 0x3C, 0x39, 0x33, 0x38},
449 	{0x37, 0x40, 0x48, 0x5C, 0x4E, 0x40, 0x44, 0x57},
450 	{0x45, 0x37, 0x38, 0x50, 0x6D, 0x51, 0x57, 0x5F},
451 	{0x62, 0x67, 0x68, 0x67, 0x3E, 0x4D, 0x71, 0x79},
452 	{0x70, 0x64, 0x78, 0x5C, 0x65, 0x67, 0x63, 0x01},
453 	{0x10, 0x0B, 0x0C, 0x0E, 0x0C, 0x0A, 0x10, 0x0E},
454 	{0x0D, 0x0E, 0x12, 0x11, 0x10, 0x13, 0x18, 0x28},
455 	{0x1A, 0x18, 0x16, 0x16, 0x18, 0x31, 0x23, 0x25},
456 	{0x1D, 0x28, 0x3A, 0x33, 0x3D, 0x3C, 0x39, 0x33},
457 	{0x38, 0x37, 0x40, 0x48, 0x5C, 0x4E, 0x40, 0x44},
458 	{0x57, 0x45, 0x37, 0x38, 0x50, 0x6D, 0x51, 0x57},
459 	{0x5F, 0x62, 0x67, 0x68, 0x67, 0x3E, 0x4D, 0x71},
460 	{0x79, 0x70, 0x64, 0x78, 0x5C, 0x65, 0x67, 0x63},
461 	{0xFF, 0x20, 0x00, 0x1F, 0x00, 0x83, 0x00, 0x00},
462 	{0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
463 	{0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
464 	{0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
465 	{0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x28, 0xFF},
466 	{0xC0, 0x00, 0x11, 0x08, 0x01, 0xE0, 0x02, 0x80},
467 	{0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
468 	{0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
469 	{0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
470 	{0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}	/* 27 */
471 };
472 static const __u8 cxjpeg_352[][8] = {
473 	{0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0d},
474 	{0x09, 0x09, 0x0b, 0x09, 0x08, 0x0D, 0x0b, 0x0a},
475 	{0x0b, 0x0e, 0x0d, 0x0d, 0x0f, 0x13, 0x1f, 0x14},
476 	{0x13, 0x11, 0x11, 0x13, 0x26, 0x1b, 0x1d, 0x17},
477 	{0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28, 0x2C},
478 	{0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35, 0x44},
479 	{0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44, 0x4A},
480 	{0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58, 0x5F},
481 	{0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D, 0x01},
482 	{0x0D, 0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B},
483 	{0x0A, 0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F},
484 	{0x14, 0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D},
485 	{0x17, 0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28},
486 	{0x2C, 0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35},
487 	{0x44, 0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44},
488 	{0x4A, 0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58},
489 	{0x5F, 0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D},
490 	{0xFF, 0x20, 0x00, 0x1F, 0x01, 0x83, 0x00, 0x00},
491 	{0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
492 	{0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
493 	{0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
494 	{0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x16, 0xFF},
495 	{0xC0, 0x00, 0x11, 0x08, 0x01, 0x20, 0x01, 0x60},
496 	{0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
497 	{0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
498 	{0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
499 	{0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
500 };
501 static const __u8 cxjpeg_320[][8] = {
502 	{0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x05},
503 	{0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04, 0x04},
504 	{0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0c, 0x08},
505 	{0x07, 0x07, 0x07, 0x07, 0x0f, 0x0b, 0x0b, 0x09},
506 	{0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0f, 0x11},
507 	{0x11, 0x13, 0x16, 0x1C, 0x17, 0x13, 0x14, 0x1A},
508 	{0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A, 0x1D},
509 	{0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17, 0x22, 0x24},
510 	{0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E, 0x01},
511 	{0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04},
512 	{0x04, 0x04, 0x05, 0x05, 0x05, 0x06, 0x07, 0x0C},
513 	{0x08, 0x07, 0x07, 0x07, 0x07, 0x0F, 0x0B, 0x0B},
514 	{0x09, 0x0C, 0x11, 0x0F, 0x12, 0x12, 0x11, 0x0F},
515 	{0x11, 0x11, 0x13, 0x16, 0x1C, 0x17, 0x13, 0x14},
516 	{0x1A, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18, 0x1A},
517 	{0x1D, 0x1D, 0x1F, 0x1F, 0x1F, 0x13, 0x17, 0x22},
518 	{0x24, 0x22, 0x1E, 0x24, 0x1C, 0x1E, 0x1F, 0x1E},
519 	{0xFF, 0x20, 0x00, 0x1F, 0x02, 0x0C, 0x00, 0x00},
520 	{0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
521 	{0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
522 	{0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
523 	{0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x14, 0xFF},
524 	{0xC0, 0x00, 0x11, 0x08, 0x00, 0xF0, 0x01, 0x40},
525 	{0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
526 	{0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
527 	{0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
528 	{0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}	/* 27 */
529 };
530 static const __u8 cxjpeg_176[][8] = {
531 	{0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x0d},
532 	{0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B, 0x0A},
533 	{0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F, 0x14},
534 	{0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D, 0x17},
535 	{0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28, 0x2C},
536 	{0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35, 0x44},
537 	{0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44, 0x4A},
538 	{0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58, 0x5F},
539 	{0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D, 0x01},
540 	{0x0D, 0x09, 0x09, 0x0B, 0x09, 0x08, 0x0D, 0x0B},
541 	{0x0A, 0x0B, 0x0E, 0x0D, 0x0D, 0x0F, 0x13, 0x1F},
542 	{0x14, 0x13, 0x11, 0x11, 0x13, 0x26, 0x1B, 0x1D},
543 	{0x17, 0x1F, 0x2D, 0x28, 0x30, 0x2F, 0x2D, 0x28},
544 	{0x2C, 0x2B, 0x32, 0x38, 0x48, 0x3D, 0x32, 0x35},
545 	{0x44, 0x36, 0x2B, 0x2C, 0x3F, 0x55, 0x3F, 0x44},
546 	{0x4A, 0x4D, 0x50, 0x51, 0x50, 0x30, 0x3C, 0x58},
547 	{0x5F, 0x58, 0x4E, 0x5E, 0x48, 0x4F, 0x50, 0x4D},
548 	{0xFF, 0x20, 0x00, 0x1F, 0x03, 0xA1, 0x00, 0x00},
549 	{0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00},
550 	{0x11, 0x22, 0x00, 0x22, 0x22, 0x11, 0x22, 0x22},
551 	{0x11, 0x33, 0x33, 0x11, 0x44, 0x66, 0x22, 0x55},
552 	{0x66, 0xFF, 0xDD, 0x00, 0x04, 0x00, 0x0B, 0xFF},
553 	{0xC0, 0x00, 0x11, 0x08, 0x00, 0x90, 0x00, 0xB0},
554 	{0x03, 0x00, 0x21, 0x00, 0x01, 0x11, 0x01, 0x02},
555 	{0x11, 0x01, 0xFF, 0xDA, 0x00, 0x0C, 0x03, 0x00},
556 	{0x00, 0x01, 0x11, 0x02, 0x11, 0x00, 0x3F, 0x00},
557 	{0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
558 };
559 /* 640 take with the zcx30x part */
560 static const __u8 cxjpeg_qtable[][8] = {
561 	{0xff, 0xd8, 0xff, 0xdb, 0x00, 0x84, 0x00, 0x08},
562 	{0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07, 0x07},
563 	{0x07, 0x09, 0x09, 0x08, 0x0a, 0x0c, 0x14, 0x0a},
564 	{0x0c, 0x0b, 0x0b, 0x0c, 0x19, 0x12, 0x13, 0x0f},
565 	{0x14, 0x1d, 0x1a, 0x1f, 0x1e, 0x1d, 0x1a, 0x1c},
566 	{0x1c, 0x20, 0x24, 0x2e, 0x27, 0x20, 0x22, 0x2c},
567 	{0x23, 0x1c, 0x1c, 0x28, 0x37, 0x29, 0x2c, 0x30},
568 	{0x31, 0x34, 0x34, 0x34, 0x1f, 0x27, 0x39, 0x3d},
569 	{0x38, 0x32, 0x3c, 0x2e, 0x33, 0x34, 0x32, 0x01},
570 	{0x09, 0x09, 0x09, 0x0c, 0x0b, 0x0c, 0x18, 0x0a},
571 	{0x0a, 0x18, 0x32, 0x21, 0x1c, 0x21, 0x32, 0x32},
572 	{0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
573 	{0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
574 	{0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
575 	{0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
576 	{0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
577 	{0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32},
578 	{0xFF, 0xD9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}	/* 18 */
579 };
580 
581 
582 static void cx11646_jpegInit(struct gspca_dev*gspca_dev)
583 {
584 	int i;
585 	int length;
586 
587 	reg_w_val(gspca_dev, 0x00c0, 0x01);
588 	reg_w_val(gspca_dev, 0x00c3, 0x00);
589 	reg_w_val(gspca_dev, 0x00c0, 0x00);
590 	reg_r(gspca_dev, 0x0001, 1);
591 	length = 8;
592 	for (i = 0; i < 79; i++) {
593 		if (i == 78)
594 			length = 6;
595 		reg_w(gspca_dev, 0x0008, cx_jpeg_init[i], length);
596 	}
597 	reg_r(gspca_dev, 0x0002, 1);
598 	reg_w_val(gspca_dev, 0x0055, 0x14);
599 }
600 
601 static const __u8 reg12[] = { 0x0a, 0x05, 0x07, 0x04, 0x19 };
602 static const __u8 regE5_8[] =
603 		{ 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 };
604 static const __u8 regE5a[] = { 0x88, 0x0a, 0x0c, 0x01 };
605 static const __u8 regE5b[] = { 0x88, 0x0b, 0x12, 0x01 };
606 static const __u8 regE5c[] = { 0x88, 0x05, 0x01, 0x01 };
607 static const __u8 reg51[] = { 0x77, 0x03 };
608 #define reg70 0x03
609 
610 static void cx11646_jpeg(struct gspca_dev*gspca_dev)
611 {
612 	int i;
613 	int length;
614 	__u8 Reg55;
615 	int retry;
616 
617 	reg_w_val(gspca_dev, 0x00c0, 0x01);
618 	reg_w_val(gspca_dev, 0x00c3, 0x00);
619 	reg_w_val(gspca_dev, 0x00c0, 0x00);
620 	reg_r(gspca_dev, 0x0001, 1);
621 	length = 8;
622 	switch (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv) {
623 	case 0:
624 		for (i = 0; i < 27; i++) {
625 			if (i == 26)
626 				length = 2;
627 			reg_w(gspca_dev, 0x0008, cxjpeg_640[i], length);
628 		}
629 		Reg55 = 0x28;
630 		break;
631 	case 1:
632 		for (i = 0; i < 27; i++) {
633 			if (i == 26)
634 				length = 2;
635 			reg_w(gspca_dev, 0x0008, cxjpeg_352[i], length);
636 		}
637 		Reg55 = 0x16;
638 		break;
639 	default:
640 /*	case 2: */
641 		for (i = 0; i < 27; i++) {
642 			if (i == 26)
643 				length = 2;
644 			reg_w(gspca_dev, 0x0008, cxjpeg_320[i], length);
645 		}
646 		Reg55 = 0x14;
647 		break;
648 	case 3:
649 		for (i = 0; i < 27; i++) {
650 			if (i == 26)
651 				length = 2;
652 			reg_w(gspca_dev, 0x0008, cxjpeg_176[i], length);
653 		}
654 		Reg55 = 0x0B;
655 		break;
656 	}
657 
658 	reg_r(gspca_dev, 0x0002, 1);
659 	reg_w_val(gspca_dev, 0x0055, Reg55);
660 	reg_r(gspca_dev, 0x0002, 1);
661 	reg_w(gspca_dev, 0x0010, reg10, 2);
662 	reg_w_val(gspca_dev, 0x0054, 0x02);
663 	reg_w_val(gspca_dev, 0x0054, 0x01);
664 	reg_w_val(gspca_dev, 0x0000, 0x94);
665 	reg_w_val(gspca_dev, 0x0053, 0xc0);
666 	reg_w_val(gspca_dev, 0x00fc, 0xe1);
667 	reg_w_val(gspca_dev, 0x0000, 0x00);
668 	/* wait for completion */
669 	retry = 50;
670 	do {
671 		reg_r(gspca_dev, 0x0002, 1);
672 							/* 0x07 until 0x00 */
673 		if (gspca_dev->usb_buf[0] == 0x00)
674 			break;
675 		reg_w_val(gspca_dev, 0x0053, 0x00);
676 	} while (--retry);
677 	if (retry == 0)
678 		gspca_err(gspca_dev, "Damned Errors sending jpeg Table\n");
679 	/* send the qtable now */
680 	reg_r(gspca_dev, 0x0001, 1);		/* -> 0x18 */
681 	length = 8;
682 	for (i = 0; i < 18; i++) {
683 		if (i == 17)
684 			length = 2;
685 		reg_w(gspca_dev, 0x0008, cxjpeg_qtable[i], length);
686 
687 	}
688 	reg_r(gspca_dev, 0x0002, 1);	/* 0x00 */
689 	reg_r(gspca_dev, 0x0053, 1);	/* 0x00 */
690 	reg_w_val(gspca_dev, 0x0054, 0x02);
691 	reg_w_val(gspca_dev, 0x0054, 0x01);
692 	reg_w_val(gspca_dev, 0x0000, 0x94);
693 	reg_w_val(gspca_dev, 0x0053, 0xc0);
694 
695 	reg_r(gspca_dev, 0x0038, 1);		/* 0x40 */
696 	reg_r(gspca_dev, 0x0038, 1);		/* 0x40 */
697 	reg_r(gspca_dev, 0x001f, 1);		/* 0x38 */
698 	reg_w(gspca_dev, 0x0012, reg12, 5);
699 	reg_w(gspca_dev, 0x00e5, regE5_8, 8);
700 	reg_r(gspca_dev, 0x00e8, 8);
701 	reg_w(gspca_dev, 0x00e5, regE5a, 4);
702 	reg_r(gspca_dev, 0x00e8, 1);		/* 0x00 */
703 	reg_w_val(gspca_dev, 0x009a, 0x01);
704 	reg_w(gspca_dev, 0x00e5, regE5b, 4);
705 	reg_r(gspca_dev, 0x00e8, 1);		/* 0x00 */
706 	reg_w(gspca_dev, 0x00e5, regE5c, 4);
707 	reg_r(gspca_dev, 0x00e8, 1);		/* 0x00 */
708 
709 	reg_w(gspca_dev, 0x0051, reg51, 2);
710 	reg_w(gspca_dev, 0x0010, reg10, 2);
711 	reg_w_val(gspca_dev, 0x0070, reg70);
712 }
713 
714 static void cx11646_init1(struct gspca_dev *gspca_dev)
715 {
716 	int i = 0;
717 
718 	reg_w_val(gspca_dev, 0x0010, 0x00);
719 	reg_w_val(gspca_dev, 0x0053, 0x00);
720 	reg_w_val(gspca_dev, 0x0052, 0x00);
721 	reg_w_val(gspca_dev, 0x009b, 0x2f);
722 	reg_w_val(gspca_dev, 0x009c, 0x10);
723 	reg_r(gspca_dev, 0x0098, 1);
724 	reg_w_val(gspca_dev, 0x0098, 0x40);
725 	reg_r(gspca_dev, 0x0099, 1);
726 	reg_w_val(gspca_dev, 0x0099, 0x07);
727 	reg_w_val(gspca_dev, 0x0039, 0x40);
728 	reg_w_val(gspca_dev, 0x003c, 0xff);
729 	reg_w_val(gspca_dev, 0x003f, 0x1f);
730 	reg_w_val(gspca_dev, 0x003d, 0x40);
731 /*	reg_w_val(gspca_dev, 0x003d, 0x60); */
732 	reg_r(gspca_dev, 0x0099, 1);			/* ->0x07 */
733 
734 	while (cx_sensor_init[i][0]) {
735 		reg_w_val(gspca_dev, 0x00e5, cx_sensor_init[i][0]);
736 		reg_r(gspca_dev, 0x00e8, 1);		/* -> 0x00 */
737 		if (i == 1) {
738 			reg_w_val(gspca_dev, 0x00ed, 0x01);
739 			reg_r(gspca_dev, 0x00ed, 1);	/* -> 0x01 */
740 		}
741 		i++;
742 	}
743 	reg_w_val(gspca_dev, 0x00c3, 0x00);
744 }
745 
746 /* this function is called at probe time */
747 static int sd_config(struct gspca_dev *gspca_dev,
748 			const struct usb_device_id *id)
749 {
750 	struct cam *cam;
751 
752 	cam = &gspca_dev->cam;
753 	cam->cam_mode = vga_mode;
754 	cam->nmodes = ARRAY_SIZE(vga_mode);
755 	return 0;
756 }
757 
758 /* this function is called at probe and resume time */
759 static int sd_init(struct gspca_dev *gspca_dev)
760 {
761 	cx11646_init1(gspca_dev);
762 	cx11646_initsize(gspca_dev);
763 	cx11646_fw(gspca_dev);
764 	cx_sensor(gspca_dev);
765 	cx11646_jpegInit(gspca_dev);
766 	return 0;
767 }
768 
769 static int sd_start(struct gspca_dev *gspca_dev)
770 {
771 	struct sd *sd = (struct sd *) gspca_dev;
772 
773 	/* create the JPEG header */
774 	jpeg_define(sd->jpeg_hdr, gspca_dev->pixfmt.height,
775 			gspca_dev->pixfmt.width,
776 			0x22);		/* JPEG 411 */
777 	jpeg_set_qual(sd->jpeg_hdr, QUALITY);
778 
779 	cx11646_initsize(gspca_dev);
780 	cx11646_fw(gspca_dev);
781 	cx_sensor(gspca_dev);
782 	cx11646_jpeg(gspca_dev);
783 	return 0;
784 }
785 
786 /* called on streamoff with alt 0 and on disconnect */
787 static void sd_stop0(struct gspca_dev *gspca_dev)
788 {
789 	int retry = 50;
790 
791 	if (!gspca_dev->present)
792 		return;
793 	reg_w_val(gspca_dev, 0x0000, 0x00);
794 	reg_r(gspca_dev, 0x0002, 1);
795 	reg_w_val(gspca_dev, 0x0053, 0x00);
796 
797 	while (retry--) {
798 /*		reg_r(gspca_dev, 0x0002, 1);*/
799 		reg_r(gspca_dev, 0x0053, 1);
800 		if (gspca_dev->usb_buf[0] == 0)
801 			break;
802 	}
803 	reg_w_val(gspca_dev, 0x0000, 0x00);
804 	reg_r(gspca_dev, 0x0002, 1);
805 
806 	reg_w_val(gspca_dev, 0x0010, 0x00);
807 	reg_r(gspca_dev, 0x0033, 1);
808 	reg_w_val(gspca_dev, 0x00fc, 0xe0);
809 }
810 
811 static void sd_pkt_scan(struct gspca_dev *gspca_dev,
812 			u8 *data,			/* isoc packet */
813 			int len)			/* iso packet length */
814 {
815 	struct sd *sd = (struct sd *) gspca_dev;
816 
817 	if (data[0] == 0xff && data[1] == 0xd8) {
818 
819 		/* start of frame */
820 		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
821 
822 		/* put the JPEG header in the new frame */
823 		gspca_frame_add(gspca_dev, FIRST_PACKET,
824 				sd->jpeg_hdr, JPEG_HDR_SZ);
825 		data += 2;
826 		len -= 2;
827 	}
828 	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
829 }
830 
831 static void setbrightness(struct gspca_dev *gspca_dev, s32 val, s32 sat)
832 {
833 	__u8 regE5cbx[] = { 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 };
834 	__u8 reg51c[2];
835 
836 	regE5cbx[2] = val;
837 	reg_w(gspca_dev, 0x00e5, regE5cbx, 8);
838 	reg_r(gspca_dev, 0x00e8, 8);
839 	reg_w(gspca_dev, 0x00e5, regE5c, 4);
840 	reg_r(gspca_dev, 0x00e8, 1);		/* 0x00 */
841 
842 	reg51c[0] = 0x77;
843 	reg51c[1] = sat;
844 	reg_w(gspca_dev, 0x0051, reg51c, 2);
845 	reg_w(gspca_dev, 0x0010, reg10, 2);
846 	reg_w_val(gspca_dev, 0x0070, reg70);
847 }
848 
849 static void setcontrast(struct gspca_dev *gspca_dev, s32 val, s32 sat)
850 {
851 	__u8 regE5acx[] = { 0x88, 0x0a, 0x0c, 0x01 };	/* seem MSB */
852 /*	__u8 regE5bcx[] = { 0x88, 0x0b, 0x12, 0x01};	 * LSB */
853 	__u8 reg51c[2];
854 
855 	regE5acx[2] = val;
856 	reg_w(gspca_dev, 0x00e5, regE5acx, 4);
857 	reg_r(gspca_dev, 0x00e8, 1);		/* 0x00 */
858 	reg51c[0] = 0x77;
859 	reg51c[1] = sat;
860 	reg_w(gspca_dev, 0x0051, reg51c, 2);
861 	reg_w(gspca_dev, 0x0010, reg10, 2);
862 	reg_w_val(gspca_dev, 0x0070, reg70);
863 }
864 
865 static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
866 {
867 	struct gspca_dev *gspca_dev =
868 		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
869 	struct sd *sd = (struct sd *)gspca_dev;
870 
871 	gspca_dev->usb_err = 0;
872 
873 	if (!gspca_dev->streaming)
874 		return 0;
875 
876 	switch (ctrl->id) {
877 	case V4L2_CID_BRIGHTNESS:
878 		setbrightness(gspca_dev, ctrl->val, sd->sat->cur.val);
879 		break;
880 	case V4L2_CID_CONTRAST:
881 		setcontrast(gspca_dev, ctrl->val, sd->sat->cur.val);
882 		break;
883 	case V4L2_CID_SATURATION:
884 		setbrightness(gspca_dev, sd->brightness->cur.val, ctrl->val);
885 		setcontrast(gspca_dev, sd->contrast->cur.val, ctrl->val);
886 		break;
887 	}
888 	return gspca_dev->usb_err;
889 }
890 
891 static const struct v4l2_ctrl_ops sd_ctrl_ops = {
892 	.s_ctrl = sd_s_ctrl,
893 };
894 
895 static int sd_init_controls(struct gspca_dev *gspca_dev)
896 {
897 	struct sd *sd = (struct sd *)gspca_dev;
898 	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
899 
900 	gspca_dev->vdev.ctrl_handler = hdl;
901 	v4l2_ctrl_handler_init(hdl, 3);
902 	sd->brightness = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
903 			V4L2_CID_BRIGHTNESS, 0, 255, 1, 0xd4);
904 	sd->contrast = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
905 			V4L2_CID_CONTRAST, 0x0a, 0x1f, 1, 0x0c);
906 	sd->sat = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
907 			V4L2_CID_SATURATION, 0, 7, 1, 3);
908 	if (hdl->error) {
909 		pr_err("Could not initialize controls\n");
910 		return hdl->error;
911 	}
912 	return 0;
913 }
914 
915 /* sub-driver description */
916 static const struct sd_desc sd_desc = {
917 	.name = MODULE_NAME,
918 	.config = sd_config,
919 	.init = sd_init,
920 	.init_controls = sd_init_controls,
921 	.start = sd_start,
922 	.stop0 = sd_stop0,
923 	.pkt_scan = sd_pkt_scan,
924 };
925 
926 /* -- module initialisation -- */
927 static const struct usb_device_id device_table[] = {
928 	{USB_DEVICE(0x0572, 0x0041)},
929 	{}
930 };
931 MODULE_DEVICE_TABLE(usb, device_table);
932 
933 /* -- device connect -- */
934 static int sd_probe(struct usb_interface *intf,
935 			const struct usb_device_id *id)
936 {
937 	return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
938 				THIS_MODULE);
939 }
940 
941 static struct usb_driver sd_driver = {
942 	.name = MODULE_NAME,
943 	.id_table = device_table,
944 	.probe = sd_probe,
945 	.disconnect = gspca_disconnect,
946 #ifdef CONFIG_PM
947 	.suspend = gspca_suspend,
948 	.resume = gspca_resume,
949 	.reset_resume = gspca_resume,
950 #endif
951 };
952 
953 module_usb_driver(sd_driver);
954