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