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