1/* GSPCA subdrivers for Genesys Logic webcams with the GL860 chip
2 * Subdriver core
3 *
4 * 2009/09/24 Olivier Lorin <o.lorin@laposte.net>
5 * GSPCA by Jean-Francois Moine <http://moinejf.free.fr>
6 * Thanks BUGabundo and Malmostoso for your amazing help!
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
23
24#include "gspca.h"
25#include "gl860.h"
26
27MODULE_AUTHOR("Olivier Lorin <o.lorin@laposte.net>");
28MODULE_DESCRIPTION("Genesys Logic USB PC Camera Driver");
29MODULE_LICENSE("GPL");
30
31/*======================== static function declarations ====================*/
32
33static void (*dev_init_settings)(struct gspca_dev *gspca_dev);
34
35static int  sd_config(struct gspca_dev *gspca_dev,
36			const struct usb_device_id *id);
37static int  sd_init(struct gspca_dev *gspca_dev);
38static int  sd_isoc_init(struct gspca_dev *gspca_dev);
39static int  sd_start(struct gspca_dev *gspca_dev);
40static void sd_stop0(struct gspca_dev *gspca_dev);
41static void sd_pkt_scan(struct gspca_dev *gspca_dev,
42			u8 *data, int len);
43static void sd_callback(struct gspca_dev *gspca_dev);
44
45static int gl860_guess_sensor(struct gspca_dev *gspca_dev,
46				u16 vendor_id, u16 product_id);
47
48/*============================ driver options ==============================*/
49
50static s32 AC50Hz = 0xff;
51module_param(AC50Hz, int, 0644);
52MODULE_PARM_DESC(AC50Hz, " Does AC power frequency is 50Hz? (0/1)");
53
54static char sensor[7];
55module_param_string(sensor, sensor, sizeof(sensor), 0644);
56MODULE_PARM_DESC(sensor,
57		" Driver sensor ('MI1320'/'MI2020'/'OV9655'/'OV2640')");
58
59/*============================ webcam controls =============================*/
60
61static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
62{
63	struct gspca_dev *gspca_dev =
64		container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
65	struct sd *sd = (struct sd *) gspca_dev;
66
67	switch (ctrl->id) {
68	case V4L2_CID_BRIGHTNESS:
69		sd->vcur.brightness = ctrl->val;
70		break;
71	case V4L2_CID_CONTRAST:
72		sd->vcur.contrast = ctrl->val;
73		break;
74	case V4L2_CID_SATURATION:
75		sd->vcur.saturation = ctrl->val;
76		break;
77	case V4L2_CID_HUE:
78		sd->vcur.hue = ctrl->val;
79		break;
80	case V4L2_CID_GAMMA:
81		sd->vcur.gamma = ctrl->val;
82		break;
83	case V4L2_CID_HFLIP:
84		sd->vcur.mirror = ctrl->val;
85		break;
86	case V4L2_CID_VFLIP:
87		sd->vcur.flip = ctrl->val;
88		break;
89	case V4L2_CID_POWER_LINE_FREQUENCY:
90		sd->vcur.AC50Hz = ctrl->val;
91		break;
92	case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
93		sd->vcur.whitebal = ctrl->val;
94		break;
95	case V4L2_CID_SHARPNESS:
96		sd->vcur.sharpness = ctrl->val;
97		break;
98	case V4L2_CID_BACKLIGHT_COMPENSATION:
99		sd->vcur.backlight = ctrl->val;
100		break;
101	default:
102		return -EINVAL;
103	}
104
105	if (gspca_dev->streaming)
106		sd->waitSet = 1;
107
108	return 0;
109}
110
111static const struct v4l2_ctrl_ops sd_ctrl_ops = {
112	.s_ctrl = sd_s_ctrl,
113};
114
115static int sd_init_controls(struct gspca_dev *gspca_dev)
116{
117	struct sd *sd = (struct sd *) gspca_dev;
118	struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
119
120	gspca_dev->vdev.ctrl_handler = hdl;
121	v4l2_ctrl_handler_init(hdl, 11);
122
123	if (sd->vmax.brightness)
124		v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_BRIGHTNESS,
125				  0, sd->vmax.brightness, 1,
126				  sd->vcur.brightness);
127
128	if (sd->vmax.contrast)
129		v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_CONTRAST,
130				  0, sd->vmax.contrast, 1,
131				  sd->vcur.contrast);
132
133	if (sd->vmax.saturation)
134		v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_SATURATION,
135				  0, sd->vmax.saturation, 1,
136				  sd->vcur.saturation);
137
138	if (sd->vmax.hue)
139		v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_HUE,
140				  0, sd->vmax.hue, 1, sd->vcur.hue);
141
142	if (sd->vmax.gamma)
143		v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_GAMMA,
144				  0, sd->vmax.gamma, 1, sd->vcur.gamma);
145
146	if (sd->vmax.mirror)
147		v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_HFLIP,
148				  0, sd->vmax.mirror, 1, sd->vcur.mirror);
149
150	if (sd->vmax.flip)
151		v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_VFLIP,
152				  0, sd->vmax.flip, 1, sd->vcur.flip);
153
154	if (sd->vmax.AC50Hz)
155		v4l2_ctrl_new_std_menu(hdl, &sd_ctrl_ops,
156				  V4L2_CID_POWER_LINE_FREQUENCY,
157				  sd->vmax.AC50Hz, 0, sd->vcur.AC50Hz);
158
159	if (sd->vmax.whitebal)
160		v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
161				  V4L2_CID_WHITE_BALANCE_TEMPERATURE,
162				  0, sd->vmax.whitebal, 1, sd->vcur.whitebal);
163
164	if (sd->vmax.sharpness)
165		v4l2_ctrl_new_std(hdl, &sd_ctrl_ops, V4L2_CID_SHARPNESS,
166				  0, sd->vmax.sharpness, 1,
167				  sd->vcur.sharpness);
168
169	if (sd->vmax.backlight)
170		v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
171				  V4L2_CID_BACKLIGHT_COMPENSATION,
172				  0, sd->vmax.backlight, 1,
173				  sd->vcur.backlight);
174
175	if (hdl->error) {
176		pr_err("Could not initialize controls\n");
177		return hdl->error;
178	}
179
180	return 0;
181}
182
183/*==================== sud-driver structure initialisation =================*/
184
185static const struct sd_desc sd_desc_mi1320 = {
186	.name        = MODULE_NAME,
187	.config      = sd_config,
188	.init        = sd_init,
189	.init_controls = sd_init_controls,
190	.isoc_init   = sd_isoc_init,
191	.start       = sd_start,
192	.stop0       = sd_stop0,
193	.pkt_scan    = sd_pkt_scan,
194	.dq_callback = sd_callback,
195};
196
197static const struct sd_desc sd_desc_mi2020 = {
198	.name        = MODULE_NAME,
199	.config      = sd_config,
200	.init        = sd_init,
201	.init_controls = sd_init_controls,
202	.isoc_init   = sd_isoc_init,
203	.start       = sd_start,
204	.stop0       = sd_stop0,
205	.pkt_scan    = sd_pkt_scan,
206	.dq_callback = sd_callback,
207};
208
209static const struct sd_desc sd_desc_ov2640 = {
210	.name        = MODULE_NAME,
211	.config      = sd_config,
212	.init        = sd_init,
213	.init_controls = sd_init_controls,
214	.isoc_init   = sd_isoc_init,
215	.start       = sd_start,
216	.stop0       = sd_stop0,
217	.pkt_scan    = sd_pkt_scan,
218	.dq_callback = sd_callback,
219};
220
221static const struct sd_desc sd_desc_ov9655 = {
222	.name        = MODULE_NAME,
223	.config      = sd_config,
224	.init        = sd_init,
225	.init_controls = sd_init_controls,
226	.isoc_init   = sd_isoc_init,
227	.start       = sd_start,
228	.stop0       = sd_stop0,
229	.pkt_scan    = sd_pkt_scan,
230	.dq_callback = sd_callback,
231};
232
233/*=========================== sub-driver image sizes =======================*/
234
235static struct v4l2_pix_format mi2020_mode[] = {
236	{ 640,  480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
237		.bytesperline = 640,
238		.sizeimage = 640 * 480,
239		.colorspace = V4L2_COLORSPACE_SRGB,
240		.priv = 0
241	},
242	{ 800,  598, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
243		.bytesperline = 800,
244		.sizeimage = 800 * 598,
245		.colorspace = V4L2_COLORSPACE_SRGB,
246		.priv = 1
247	},
248	{1280, 1024, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
249		.bytesperline = 1280,
250		.sizeimage = 1280 * 1024,
251		.colorspace = V4L2_COLORSPACE_SRGB,
252		.priv = 2
253	},
254	{1600, 1198, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
255		.bytesperline = 1600,
256		.sizeimage = 1600 * 1198,
257		.colorspace = V4L2_COLORSPACE_SRGB,
258		.priv = 3
259	},
260};
261
262static struct v4l2_pix_format ov2640_mode[] = {
263	{ 640,  480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
264		.bytesperline = 640,
265		.sizeimage = 640 * 480,
266		.colorspace = V4L2_COLORSPACE_SRGB,
267		.priv = 0
268	},
269	{ 800,  600, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
270		.bytesperline = 800,
271		.sizeimage = 800 * 600,
272		.colorspace = V4L2_COLORSPACE_SRGB,
273		.priv = 1
274	},
275	{1280,  960, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
276		.bytesperline = 1280,
277		.sizeimage = 1280 * 960,
278		.colorspace = V4L2_COLORSPACE_SRGB,
279		.priv = 2
280	},
281	{1600, 1200, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
282		.bytesperline = 1600,
283		.sizeimage = 1600 * 1200,
284		.colorspace = V4L2_COLORSPACE_SRGB,
285		.priv = 3
286	},
287};
288
289static struct v4l2_pix_format mi1320_mode[] = {
290	{ 640,  480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
291		.bytesperline = 640,
292		.sizeimage = 640 * 480,
293		.colorspace = V4L2_COLORSPACE_SRGB,
294		.priv = 0
295	},
296	{ 800,  600, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
297		.bytesperline = 800,
298		.sizeimage = 800 * 600,
299		.colorspace = V4L2_COLORSPACE_SRGB,
300		.priv = 1
301	},
302	{1280,  960, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
303		.bytesperline = 1280,
304		.sizeimage = 1280 * 960,
305		.colorspace = V4L2_COLORSPACE_SRGB,
306		.priv = 2
307	},
308};
309
310static struct v4l2_pix_format ov9655_mode[] = {
311	{ 640,  480, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
312		.bytesperline = 640,
313		.sizeimage = 640 * 480,
314		.colorspace = V4L2_COLORSPACE_SRGB,
315		.priv = 0
316	},
317	{1280,  960, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
318		.bytesperline = 1280,
319		.sizeimage = 1280 * 960,
320		.colorspace = V4L2_COLORSPACE_SRGB,
321		.priv = 1
322	},
323};
324
325/*========================= sud-driver functions ===========================*/
326
327/* This function is called at probe time */
328static int sd_config(struct gspca_dev *gspca_dev,
329			const struct usb_device_id *id)
330{
331	struct sd *sd = (struct sd *) gspca_dev;
332	struct cam *cam;
333	u16 vendor_id, product_id;
334
335	/* Get USB VendorID and ProductID */
336	vendor_id  = id->idVendor;
337	product_id = id->idProduct;
338
339	sd->nbRightUp = 1;
340	sd->nbIm = -1;
341
342	sd->sensor = 0xff;
343	if (strcmp(sensor, "MI1320") == 0)
344		sd->sensor = ID_MI1320;
345	else if (strcmp(sensor, "OV2640") == 0)
346		sd->sensor = ID_OV2640;
347	else if (strcmp(sensor, "OV9655") == 0)
348		sd->sensor = ID_OV9655;
349	else if (strcmp(sensor, "MI2020") == 0)
350		sd->sensor = ID_MI2020;
351
352	/* Get sensor and set the suitable init/start/../stop functions */
353	if (gl860_guess_sensor(gspca_dev, vendor_id, product_id) == -1)
354		return -1;
355
356	cam = &gspca_dev->cam;
357
358	switch (sd->sensor) {
359	case ID_MI1320:
360		gspca_dev->sd_desc = &sd_desc_mi1320;
361		cam->cam_mode = mi1320_mode;
362		cam->nmodes = ARRAY_SIZE(mi1320_mode);
363		dev_init_settings   = mi1320_init_settings;
364		break;
365
366	case ID_MI2020:
367		gspca_dev->sd_desc = &sd_desc_mi2020;
368		cam->cam_mode = mi2020_mode;
369		cam->nmodes = ARRAY_SIZE(mi2020_mode);
370		dev_init_settings   = mi2020_init_settings;
371		break;
372
373	case ID_OV2640:
374		gspca_dev->sd_desc = &sd_desc_ov2640;
375		cam->cam_mode = ov2640_mode;
376		cam->nmodes = ARRAY_SIZE(ov2640_mode);
377		dev_init_settings   = ov2640_init_settings;
378		break;
379
380	case ID_OV9655:
381		gspca_dev->sd_desc = &sd_desc_ov9655;
382		cam->cam_mode = ov9655_mode;
383		cam->nmodes = ARRAY_SIZE(ov9655_mode);
384		dev_init_settings   = ov9655_init_settings;
385		break;
386	}
387
388	dev_init_settings(gspca_dev);
389	if (AC50Hz != 0xff)
390		((struct sd *) gspca_dev)->vcur.AC50Hz = AC50Hz;
391
392	return 0;
393}
394
395/* This function is called at probe time after sd_config */
396static int sd_init(struct gspca_dev *gspca_dev)
397{
398	struct sd *sd = (struct sd *) gspca_dev;
399
400	return sd->dev_init_at_startup(gspca_dev);
401}
402
403/* This function is called before to choose the alt setting */
404static int sd_isoc_init(struct gspca_dev *gspca_dev)
405{
406	struct sd *sd = (struct sd *) gspca_dev;
407
408	return sd->dev_configure_alt(gspca_dev);
409}
410
411/* This function is called to start the webcam */
412static int sd_start(struct gspca_dev *gspca_dev)
413{
414	struct sd *sd = (struct sd *) gspca_dev;
415
416	return sd->dev_init_pre_alt(gspca_dev);
417}
418
419/* This function is called to stop the webcam */
420static void sd_stop0(struct gspca_dev *gspca_dev)
421{
422	struct sd *sd = (struct sd *) gspca_dev;
423
424	if (!sd->gspca_dev.present)
425		return;
426
427	return sd->dev_post_unset_alt(gspca_dev);
428}
429
430/* This function is called when an image is being received */
431static void sd_pkt_scan(struct gspca_dev *gspca_dev,
432			u8 *data, int len)
433{
434	struct sd *sd = (struct sd *) gspca_dev;
435	static s32 nSkipped;
436
437	s32 mode = (s32) gspca_dev->curr_mode;
438	s32 nToSkip =
439		sd->swapRB * (gspca_dev->cam.cam_mode[mode].bytesperline + 1);
440
441	/* Test only against 0202h, so endianness does not matter */
442	switch (*(s16 *) data) {
443	case 0x0202:		/* End of frame, start a new one */
444		gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
445		nSkipped = 0;
446		if (sd->nbIm >= 0 && sd->nbIm < 10)
447			sd->nbIm++;
448		gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
449		break;
450
451	default:
452		data += 2;
453		len  -= 2;
454		if (nSkipped + len <= nToSkip)
455			nSkipped += len;
456		else {
457			if (nSkipped < nToSkip && nSkipped + len > nToSkip) {
458				data += nToSkip - nSkipped;
459				len  -= nToSkip - nSkipped;
460				nSkipped = nToSkip + 1;
461			}
462			gspca_frame_add(gspca_dev,
463				INTER_PACKET, data, len);
464		}
465		break;
466	}
467}
468
469/* This function is called when an image has been read */
470/* This function is used to monitor webcam orientation */
471static void sd_callback(struct gspca_dev *gspca_dev)
472{
473	struct sd *sd = (struct sd *) gspca_dev;
474
475	if (!_OV9655_) {
476		u8 state;
477		u8 upsideDown;
478
479		/* Probe sensor orientation */
480		ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, (void *)&state);
481
482		/* C8/40 means upside-down (looking backwards) */
483		/* D8/50 means right-up (looking onwards) */
484		upsideDown = (state == 0xc8 || state == 0x40);
485
486		if (upsideDown && sd->nbRightUp > -4) {
487			if (sd->nbRightUp > 0)
488				sd->nbRightUp = 0;
489			if (sd->nbRightUp == -3) {
490				sd->mirrorMask = 1;
491				sd->waitSet = 1;
492			}
493			sd->nbRightUp--;
494		}
495		if (!upsideDown && sd->nbRightUp < 4) {
496			if (sd->nbRightUp  < 0)
497				sd->nbRightUp = 0;
498			if (sd->nbRightUp == 3) {
499				sd->mirrorMask = 0;
500				sd->waitSet = 1;
501			}
502			sd->nbRightUp++;
503		}
504	}
505
506	if (sd->waitSet)
507		sd->dev_camera_settings(gspca_dev);
508}
509
510/*=================== USB driver structure initialisation ==================*/
511
512static const struct usb_device_id device_table[] = {
513	{USB_DEVICE(0x05e3, 0x0503)},
514	{USB_DEVICE(0x05e3, 0xf191)},
515	{}
516};
517
518MODULE_DEVICE_TABLE(usb, device_table);
519
520static int sd_probe(struct usb_interface *intf,
521				const struct usb_device_id *id)
522{
523	return gspca_dev_probe(intf, id,
524			&sd_desc_mi1320, sizeof(struct sd), THIS_MODULE);
525}
526
527static void sd_disconnect(struct usb_interface *intf)
528{
529	gspca_disconnect(intf);
530}
531
532static struct usb_driver sd_driver = {
533	.name       = MODULE_NAME,
534	.id_table   = device_table,
535	.probe      = sd_probe,
536	.disconnect = sd_disconnect,
537#ifdef CONFIG_PM
538	.suspend    = gspca_suspend,
539	.resume     = gspca_resume,
540	.reset_resume = gspca_resume,
541#endif
542};
543
544/*====================== Init and Exit module functions ====================*/
545
546module_usb_driver(sd_driver);
547
548/*==========================================================================*/
549
550int gl860_RTx(struct gspca_dev *gspca_dev,
551		unsigned char pref, u32 req, u16 val, u16 index,
552		s32 len, void *pdata)
553{
554	struct usb_device *udev = gspca_dev->dev;
555	s32 r = 0;
556
557	if (pref == 0x40) { /* Send */
558		if (len > 0) {
559			memcpy(gspca_dev->usb_buf, pdata, len);
560			r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
561					req, pref, val, index,
562					gspca_dev->usb_buf,
563					len, 400 + 200 * (len > 1));
564		} else {
565			r = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
566					req, pref, val, index, NULL, len, 400);
567		}
568	} else { /* Receive */
569		if (len > 0) {
570			r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
571					req, pref, val, index,
572					gspca_dev->usb_buf,
573					len, 400 + 200 * (len > 1));
574			memcpy(pdata, gspca_dev->usb_buf, len);
575		} else {
576			r = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
577					req, pref, val, index, NULL, len, 400);
578		}
579	}
580
581	if (r < 0)
582		pr_err("ctrl transfer failed %4d [p%02x r%d v%04x i%04x len%d]\n",
583		       r, pref, req, val, index, len);
584	else if (len > 1 && r < len)
585		PERR("short ctrl transfer %d/%d", r, len);
586
587	msleep(1);
588
589	return r;
590}
591
592int fetch_validx(struct gspca_dev *gspca_dev, struct validx *tbl, int len)
593{
594	int n;
595
596	for (n = 0; n < len; n++) {
597		if (tbl[n].idx != 0xffff)
598			ctrl_out(gspca_dev, 0x40, 1, tbl[n].val,
599					tbl[n].idx, 0, NULL);
600		else if (tbl[n].val == 0xffff)
601			break;
602		else
603			msleep(tbl[n].val);
604	}
605	return n;
606}
607
608int keep_on_fetching_validx(struct gspca_dev *gspca_dev, struct validx *tbl,
609				int len, int n)
610{
611	while (++n < len) {
612		if (tbl[n].idx != 0xffff)
613			ctrl_out(gspca_dev, 0x40, 1, tbl[n].val, tbl[n].idx,
614					0, NULL);
615		else if (tbl[n].val == 0xffff)
616			break;
617		else
618			msleep(tbl[n].val);
619	}
620	return n;
621}
622
623void fetch_idxdata(struct gspca_dev *gspca_dev, struct idxdata *tbl, int len)
624{
625	int n;
626
627	for (n = 0; n < len; n++) {
628		if (memcmp(tbl[n].data, "\xff\xff\xff", 3) != 0)
629			ctrl_out(gspca_dev, 0x40, 3, 0x7a00, tbl[n].idx,
630					3, tbl[n].data);
631		else
632			msleep(tbl[n].idx);
633	}
634}
635
636static int gl860_guess_sensor(struct gspca_dev *gspca_dev,
637				u16 vendor_id, u16 product_id)
638{
639	struct sd *sd = (struct sd *) gspca_dev;
640	u8 probe, nb26, nb96, nOV, ntry;
641
642	if (product_id == 0xf191)
643		sd->sensor = ID_MI1320;
644
645	if (sd->sensor == 0xff) {
646		ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &probe);
647		ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0004, 1, &probe);
648
649		ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x0000, 0, NULL);
650		msleep(3);
651		ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL);
652		msleep(3);
653		ctrl_out(gspca_dev, 0x40, 1, 0x0008, 0x00c0, 0, NULL);
654		msleep(3);
655		ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x00c1, 0, NULL);
656		msleep(3);
657		ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x00c2, 0, NULL);
658		msleep(3);
659		ctrl_out(gspca_dev, 0x40, 1, 0x0020, 0x0006, 0, NULL);
660		msleep(3);
661		ctrl_out(gspca_dev, 0x40, 1, 0x006a, 0x000d, 0, NULL);
662		msleep(56);
663
664		PDEBUG(D_PROBE, "probing for sensor MI2020 or OVXXXX");
665		nOV = 0;
666		for (ntry = 0; ntry < 4; ntry++) {
667			ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
668			msleep(3);
669			ctrl_out(gspca_dev, 0x40, 1, 0x0063, 0x0006, 0, NULL);
670			msleep(3);
671			ctrl_out(gspca_dev, 0x40, 1, 0x7a00, 0x8030, 0, NULL);
672			msleep(10);
673			ctrl_in(gspca_dev, 0xc0, 2, 0x7a00, 0x8030, 1, &probe);
674			PDEBUG(D_PROBE, "probe=0x%02x", probe);
675			if (probe == 0xff)
676				nOV++;
677		}
678
679		if (nOV) {
680			PDEBUG(D_PROBE, "0xff -> OVXXXX");
681			PDEBUG(D_PROBE, "probing for sensor OV2640 or OV9655");
682
683			nb26 = nb96 = 0;
684			for (ntry = 0; ntry < 4; ntry++) {
685				ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000,
686						0, NULL);
687				msleep(3);
688				ctrl_out(gspca_dev, 0x40, 1, 0x6000, 0x800a,
689						0, NULL);
690				msleep(10);
691
692				/* Wait for 26(OV2640) or 96(OV9655) */
693				ctrl_in(gspca_dev, 0xc0, 2, 0x6000, 0x800a,
694						1, &probe);
695
696				if (probe == 0x26 || probe == 0x40) {
697					PDEBUG(D_PROBE,
698						"probe=0x%02x -> OV2640",
699						probe);
700					sd->sensor = ID_OV2640;
701					nb26 += 4;
702					break;
703				}
704				if (probe == 0x96 || probe == 0x55) {
705					PDEBUG(D_PROBE,
706						"probe=0x%02x -> OV9655",
707						probe);
708					sd->sensor = ID_OV9655;
709					nb96 += 4;
710					break;
711				}
712				PDEBUG(D_PROBE, "probe=0x%02x", probe);
713				if (probe == 0x00)
714					nb26++;
715				if (probe == 0xff)
716					nb96++;
717				msleep(3);
718			}
719			if (nb26 < 4 && nb96 < 4)
720				return -1;
721		} else {
722			PDEBUG(D_PROBE, "Not any 0xff -> MI2020");
723			sd->sensor = ID_MI2020;
724		}
725	}
726
727	if (_MI1320_) {
728		PDEBUG(D_PROBE, "05e3:f191 sensor MI1320 (1.3M)");
729	} else if (_MI2020_) {
730		PDEBUG(D_PROBE, "05e3:0503 sensor MI2020 (2.0M)");
731	} else if (_OV9655_) {
732		PDEBUG(D_PROBE, "05e3:0503 sensor OV9655 (1.3M)");
733	} else if (_OV2640_) {
734		PDEBUG(D_PROBE, "05e3:0503 sensor OV2640 (2.0M)");
735	} else {
736		PDEBUG(D_PROBE, "***** Unknown sensor *****");
737		return -1;
738	}
739
740	return 0;
741}
742