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
17MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
18MODULE_DESCRIPTION("GSPCA USB Conexant Camera Driver");
19MODULE_LICENSE("GPL");
20
21#define QUALITY 50
22
23/* specific webcam descriptor */
24struct 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
33static 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 */
57static 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 */
80static 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
95static 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
118static 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
126static 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};
193static 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
205static 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
220static const __u8 reg20[] = { 0x10, 0x42, 0x81, 0x19, 0xd3, 0xff, 0xa7, 0xff };
221static const __u8 reg28[] = { 0x87, 0x00, 0x87, 0x00, 0x8f, 0xff, 0xea, 0xff };
222static const __u8 reg10[] = { 0xb1, 0xb1 };
223static const __u8 reg71a[] = { 0x08, 0x18, 0x0a, 0x1e };	/* 640 */
224static const __u8 reg71b[] = { 0x04, 0x0c, 0x05, 0x0f };
225	/* 352{0x04,0x0a,0x06,0x12}; //352{0x05,0x0e,0x06,0x11}; //352 */
226static const __u8 reg71c[] = { 0x02, 0x07, 0x03, 0x09 };
227					/* 320{0x04,0x0c,0x05,0x0f}; //320 */
228static const __u8 reg71d[] = { 0x02, 0x07, 0x03, 0x09 };	/* 176 */
229static const __u8 reg7b[] = { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff };
230
231static 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
276static 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};
285static 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};
294static 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};
303static 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
313static 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
360static 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
443static 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};
472static 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};
501static 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};
530static 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 */
560static 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
582static 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
601static const __u8 reg12[] = { 0x0a, 0x05, 0x07, 0x04, 0x19 };
602static const __u8 regE5_8[] =
603		{ 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 };
604static const __u8 regE5a[] = { 0x88, 0x0a, 0x0c, 0x01 };
605static const __u8 regE5b[] = { 0x88, 0x0b, 0x12, 0x01 };
606static const __u8 regE5c[] = { 0x88, 0x05, 0x01, 0x01 };
607static const __u8 reg51[] = { 0x77, 0x03 };
608#define reg70 0x03
609
610static 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
714static 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 */
747static 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 */
759static 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
769static 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 */
787static 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
811static 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
831static 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
849static 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
865static 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
891static const struct v4l2_ctrl_ops sd_ctrl_ops = {
892	.s_ctrl = sd_s_ctrl,
893};
894
895static 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 */
916static 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 -- */
927static const struct usb_device_id device_table[] = {
928	{USB_DEVICE(0x0572, 0x0041)},
929	{}
930};
931MODULE_DEVICE_TABLE(usb, device_table);
932
933/* -- device connect -- */
934static 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
941static 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
953module_usb_driver(sd_driver);
954