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