]>
Commit | Line | Data |
---|---|---|
d661e622 KG |
1 | /* |
2 | * Mars MR97310A library | |
3 | * | |
930bf78c | 4 | * The original mr97310a driver, which supported the Aiptek Pencam VGA+, is |
d661e622 KG |
5 | * Copyright (C) 2009 Kyle Guinn <elyk03@gmail.com> |
6 | * | |
89f0863c TK |
7 | * Support for the MR97310A cameras in addition to the Aiptek Pencam VGA+ |
8 | * and for the routines for detecting and classifying these various cameras, | |
930bf78c | 9 | * is Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu> |
89f0863c | 10 | * |
930bf78c | 11 | * Support for the control settings for the CIF cameras is |
1fddcf0e | 12 | * Copyright (C) 2009 Hans de Goede <hdegoede@redhat.com> and |
930bf78c TK |
13 | * Thomas Kaiser <thomas@kaiser-linux.li> |
14 | * | |
15 | * Support for the control settings for the VGA cameras is | |
89f0863c TK |
16 | * Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu> |
17 | * | |
930bf78c | 18 | * Several previously unsupported cameras are owned and have been tested by |
1fddcf0e | 19 | * Hans de Goede <hdegoede@redhat.com> and |
930bf78c | 20 | * Thomas Kaiser <thomas@kaiser-linux.li> and |
1160a381 TK |
21 | * Theodore Kilgore <kilgota@auburn.edu> and |
22 | * Edmond Rodriguez <erodrig_97@yahoo.com> and | |
23 | * Aurelien Jacobs <aurel@gnuage.org> | |
89f0863c TK |
24 | * |
25 | * The MR97311A support in gspca/mars.c has been helpful in understanding some | |
26 | * of the registers in these cameras. | |
27 | * | |
d661e622 KG |
28 | * This program is free software; you can redistribute it and/or modify |
29 | * it under the terms of the GNU General Public License as published by | |
30 | * the Free Software Foundation; either version 2 of the License, or | |
31 | * any later version. | |
32 | * | |
33 | * This program is distributed in the hope that it will be useful, | |
34 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
35 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
36 | * GNU General Public License for more details. | |
37 | * | |
38 | * You should have received a copy of the GNU General Public License | |
39 | * along with this program; if not, write to the Free Software | |
40 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
41 | */ | |
42 | ||
43 | #define MODULE_NAME "mr97310a" | |
44 | ||
45 | #include "gspca.h" | |
46 | ||
89f0863c TK |
47 | #define CAM_TYPE_CIF 0 |
48 | #define CAM_TYPE_VGA 1 | |
49 | ||
89f0863c TK |
50 | #define MR97310A_BRIGHTNESS_DEFAULT 0 |
51 | ||
930bf78c | 52 | #define MR97310A_EXPOSURE_MIN 0 |
89f0863c TK |
53 | #define MR97310A_EXPOSURE_MAX 4095 |
54 | #define MR97310A_EXPOSURE_DEFAULT 1000 | |
55 | ||
56 | #define MR97310A_GAIN_MIN 0 | |
57 | #define MR97310A_GAIN_MAX 31 | |
58 | #define MR97310A_GAIN_DEFAULT 25 | |
59 | ||
9d3103d0 TK |
60 | #define MR97310A_CONTRAST_MIN 0 |
61 | #define MR97310A_CONTRAST_MAX 31 | |
62 | #define MR97310A_CONTRAST_DEFAULT 23 | |
63 | ||
64 | #define MR97310A_CS_GAIN_MIN 0 | |
65 | #define MR97310A_CS_GAIN_MAX 0x7ff | |
66 | #define MR97310A_CS_GAIN_DEFAULT 0x110 | |
67 | ||
065b6f7a HG |
68 | #define MR97310A_MIN_CLOCKDIV_MIN 3 |
69 | #define MR97310A_MIN_CLOCKDIV_MAX 8 | |
70 | #define MR97310A_MIN_CLOCKDIV_DEFAULT 3 | |
71 | ||
89f0863c TK |
72 | MODULE_AUTHOR("Kyle Guinn <elyk03@gmail.com>," |
73 | "Theodore Kilgore <kilgota@auburn.edu>"); | |
d661e622 KG |
74 | MODULE_DESCRIPTION("GSPCA/Mars-Semi MR97310A USB Camera Driver"); |
75 | MODULE_LICENSE("GPL"); | |
76 | ||
78028706 | 77 | /* global parameters */ |
83955556 | 78 | static int force_sensor_type = -1; |
78028706 HG |
79 | module_param(force_sensor_type, int, 0644); |
80 | MODULE_PARM_DESC(force_sensor_type, "Force sensor type (-1 (auto), 0 or 1)"); | |
81 | ||
d661e622 KG |
82 | /* specific webcam descriptor */ |
83 | struct sd { | |
84 | struct gspca_dev gspca_dev; /* !! must be the first item */ | |
d661e622 | 85 | u8 sof_read; |
89f0863c TK |
86 | u8 cam_type; /* 0 is CIF and 1 is VGA */ |
87 | u8 sensor_type; /* We use 0 and 1 here, too. */ | |
88 | u8 do_lcd_stop; | |
64f4d9a3 | 89 | u8 adj_colors; |
89f0863c TK |
90 | |
91 | int brightness; | |
92 | u16 exposure; | |
9d3103d0 TK |
93 | u32 gain; |
94 | u8 contrast; | |
065b6f7a | 95 | u8 min_clockdiv; |
d661e622 KG |
96 | }; |
97 | ||
89f0863c TK |
98 | struct sensor_w_data { |
99 | u8 reg; | |
100 | u8 flags; | |
101 | u8 data[16]; | |
102 | int len; | |
103 | }; | |
104 | ||
930bf78c | 105 | static void sd_stopN(struct gspca_dev *gspca_dev); |
89f0863c TK |
106 | static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val); |
107 | static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val); | |
108 | static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val); | |
109 | static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val); | |
9d3103d0 TK |
110 | static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val); |
111 | static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val); | |
89f0863c TK |
112 | static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val); |
113 | static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val); | |
065b6f7a HG |
114 | static int sd_setmin_clockdiv(struct gspca_dev *gspca_dev, __s32 val); |
115 | static int sd_getmin_clockdiv(struct gspca_dev *gspca_dev, __s32 *val); | |
9ac6978a HG |
116 | static void setbrightness(struct gspca_dev *gspca_dev); |
117 | static void setexposure(struct gspca_dev *gspca_dev); | |
118 | static void setgain(struct gspca_dev *gspca_dev); | |
9d3103d0 | 119 | static void setcontrast(struct gspca_dev *gspca_dev); |
89f0863c | 120 | |
d661e622 | 121 | /* V4L2 controls supported by the driver */ |
7e64dc4c | 122 | static const struct ctrl sd_ctrls[] = { |
1160a381 | 123 | /* Separate brightness control description for Argus QuickClix as it has |
9d3103d0 TK |
124 | * different limits from the other mr97310a cameras, and separate gain |
125 | * control for Sakar CyberPix camera. */ | |
89f0863c | 126 | { |
930bf78c | 127 | #define NORM_BRIGHTNESS_IDX 0 |
89f0863c TK |
128 | { |
129 | .id = V4L2_CID_BRIGHTNESS, | |
130 | .type = V4L2_CTRL_TYPE_INTEGER, | |
131 | .name = "Brightness", | |
930bf78c TK |
132 | .minimum = -254, |
133 | .maximum = 255, | |
89f0863c TK |
134 | .step = 1, |
135 | .default_value = MR97310A_BRIGHTNESS_DEFAULT, | |
136 | .flags = 0, | |
137 | }, | |
138 | .set = sd_setbrightness, | |
139 | .get = sd_getbrightness, | |
140 | }, | |
141 | { | |
930bf78c TK |
142 | #define ARGUS_QC_BRIGHTNESS_IDX 1 |
143 | { | |
144 | .id = V4L2_CID_BRIGHTNESS, | |
145 | .type = V4L2_CTRL_TYPE_INTEGER, | |
146 | .name = "Brightness", | |
147 | .minimum = 0, | |
148 | .maximum = 15, | |
149 | .step = 1, | |
150 | .default_value = MR97310A_BRIGHTNESS_DEFAULT, | |
151 | .flags = 0, | |
152 | }, | |
153 | .set = sd_setbrightness, | |
154 | .get = sd_getbrightness, | |
155 | }, | |
156 | { | |
157 | #define EXPOSURE_IDX 2 | |
89f0863c TK |
158 | { |
159 | .id = V4L2_CID_EXPOSURE, | |
160 | .type = V4L2_CTRL_TYPE_INTEGER, | |
161 | .name = "Exposure", | |
162 | .minimum = MR97310A_EXPOSURE_MIN, | |
163 | .maximum = MR97310A_EXPOSURE_MAX, | |
164 | .step = 1, | |
165 | .default_value = MR97310A_EXPOSURE_DEFAULT, | |
166 | .flags = 0, | |
167 | }, | |
168 | .set = sd_setexposure, | |
169 | .get = sd_getexposure, | |
170 | }, | |
171 | { | |
930bf78c | 172 | #define GAIN_IDX 3 |
89f0863c TK |
173 | { |
174 | .id = V4L2_CID_GAIN, | |
175 | .type = V4L2_CTRL_TYPE_INTEGER, | |
176 | .name = "Gain", | |
177 | .minimum = MR97310A_GAIN_MIN, | |
178 | .maximum = MR97310A_GAIN_MAX, | |
179 | .step = 1, | |
180 | .default_value = MR97310A_GAIN_DEFAULT, | |
181 | .flags = 0, | |
182 | }, | |
183 | .set = sd_setgain, | |
184 | .get = sd_getgain, | |
185 | }, | |
065b6f7a | 186 | { |
9d3103d0 TK |
187 | #define SAKAR_CS_GAIN_IDX 4 |
188 | { | |
189 | .id = V4L2_CID_GAIN, | |
190 | .type = V4L2_CTRL_TYPE_INTEGER, | |
191 | .name = "Gain", | |
192 | .minimum = MR97310A_CS_GAIN_MIN, | |
193 | .maximum = MR97310A_CS_GAIN_MAX, | |
194 | .step = 1, | |
195 | .default_value = MR97310A_CS_GAIN_DEFAULT, | |
196 | .flags = 0, | |
197 | }, | |
198 | .set = sd_setgain, | |
199 | .get = sd_getgain, | |
200 | }, | |
201 | { | |
202 | #define CONTRAST_IDX 5 | |
203 | { | |
204 | .id = V4L2_CID_CONTRAST, | |
205 | .type = V4L2_CTRL_TYPE_INTEGER, | |
206 | .name = "Contrast", | |
207 | .minimum = MR97310A_CONTRAST_MIN, | |
208 | .maximum = MR97310A_CONTRAST_MAX, | |
209 | .step = 1, | |
210 | .default_value = MR97310A_CONTRAST_DEFAULT, | |
211 | .flags = 0, | |
212 | }, | |
213 | .set = sd_setcontrast, | |
214 | .get = sd_getcontrast, | |
215 | }, | |
216 | { | |
217 | #define MIN_CLOCKDIV_IDX 6 | |
065b6f7a HG |
218 | { |
219 | .id = V4L2_CID_PRIVATE_BASE, | |
220 | .type = V4L2_CTRL_TYPE_INTEGER, | |
221 | .name = "Minimum Clock Divider", | |
222 | .minimum = MR97310A_MIN_CLOCKDIV_MIN, | |
223 | .maximum = MR97310A_MIN_CLOCKDIV_MAX, | |
224 | .step = 1, | |
225 | .default_value = MR97310A_MIN_CLOCKDIV_DEFAULT, | |
226 | .flags = 0, | |
227 | }, | |
228 | .set = sd_setmin_clockdiv, | |
229 | .get = sd_getmin_clockdiv, | |
230 | }, | |
d661e622 KG |
231 | }; |
232 | ||
233 | static const struct v4l2_pix_format vga_mode[] = { | |
234 | {160, 120, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE, | |
235 | .bytesperline = 160, | |
236 | .sizeimage = 160 * 120, | |
237 | .colorspace = V4L2_COLORSPACE_SRGB, | |
238 | .priv = 4}, | |
239 | {176, 144, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE, | |
240 | .bytesperline = 176, | |
241 | .sizeimage = 176 * 144, | |
242 | .colorspace = V4L2_COLORSPACE_SRGB, | |
243 | .priv = 3}, | |
244 | {320, 240, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE, | |
245 | .bytesperline = 320, | |
246 | .sizeimage = 320 * 240, | |
247 | .colorspace = V4L2_COLORSPACE_SRGB, | |
248 | .priv = 2}, | |
249 | {352, 288, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE, | |
250 | .bytesperline = 352, | |
251 | .sizeimage = 352 * 288, | |
252 | .colorspace = V4L2_COLORSPACE_SRGB, | |
253 | .priv = 1}, | |
254 | {640, 480, V4L2_PIX_FMT_MR97310A, V4L2_FIELD_NONE, | |
255 | .bytesperline = 640, | |
256 | .sizeimage = 640 * 480, | |
257 | .colorspace = V4L2_COLORSPACE_SRGB, | |
258 | .priv = 0}, | |
259 | }; | |
260 | ||
261 | /* the bytes to write are in gspca_dev->usb_buf */ | |
89f0863c | 262 | static int mr_write(struct gspca_dev *gspca_dev, int len) |
d661e622 KG |
263 | { |
264 | int rc; | |
265 | ||
266 | rc = usb_bulk_msg(gspca_dev->dev, | |
267 | usb_sndbulkpipe(gspca_dev->dev, 4), | |
92e8c91b | 268 | gspca_dev->usb_buf, len, NULL, 500); |
d661e622 | 269 | if (rc < 0) |
0b656321 | 270 | err("reg write [%02x] error %d", |
d661e622 KG |
271 | gspca_dev->usb_buf[0], rc); |
272 | return rc; | |
273 | } | |
274 | ||
89f0863c TK |
275 | /* the bytes are read into gspca_dev->usb_buf */ |
276 | static int mr_read(struct gspca_dev *gspca_dev, int len) | |
277 | { | |
278 | int rc; | |
279 | ||
280 | rc = usb_bulk_msg(gspca_dev->dev, | |
281 | usb_rcvbulkpipe(gspca_dev->dev, 3), | |
282 | gspca_dev->usb_buf, len, NULL, 500); | |
283 | if (rc < 0) | |
0b656321 | 284 | err("reg read [%02x] error %d", |
89f0863c TK |
285 | gspca_dev->usb_buf[0], rc); |
286 | return rc; | |
287 | } | |
288 | ||
289 | static int sensor_write_reg(struct gspca_dev *gspca_dev, u8 reg, u8 flags, | |
290 | const u8 *data, int len) | |
291 | { | |
292 | gspca_dev->usb_buf[0] = 0x1f; | |
293 | gspca_dev->usb_buf[1] = flags; | |
294 | gspca_dev->usb_buf[2] = reg; | |
295 | memcpy(gspca_dev->usb_buf + 3, data, len); | |
296 | ||
297 | return mr_write(gspca_dev, len + 3); | |
298 | } | |
299 | ||
300 | static int sensor_write_regs(struct gspca_dev *gspca_dev, | |
301 | const struct sensor_w_data *data, int len) | |
302 | { | |
303 | int i, rc; | |
304 | ||
305 | for (i = 0; i < len; i++) { | |
306 | rc = sensor_write_reg(gspca_dev, data[i].reg, data[i].flags, | |
307 | data[i].data, data[i].len); | |
308 | if (rc < 0) | |
309 | return rc; | |
310 | } | |
311 | ||
312 | return 0; | |
313 | } | |
314 | ||
315 | static int sensor_write1(struct gspca_dev *gspca_dev, u8 reg, u8 data) | |
316 | { | |
a2e081b6 HG |
317 | struct sd *sd = (struct sd *) gspca_dev; |
318 | u8 buf, confirm_reg; | |
89f0863c TK |
319 | int rc; |
320 | ||
321 | buf = data; | |
930bf78c TK |
322 | if (sd->cam_type == CAM_TYPE_CIF) { |
323 | rc = sensor_write_reg(gspca_dev, reg, 0x01, &buf, 1); | |
324 | confirm_reg = sd->sensor_type ? 0x13 : 0x11; | |
325 | } else { | |
326 | rc = sensor_write_reg(gspca_dev, reg, 0x00, &buf, 1); | |
327 | confirm_reg = 0x11; | |
328 | } | |
89f0863c TK |
329 | if (rc < 0) |
330 | return rc; | |
331 | ||
332 | buf = 0x01; | |
a2e081b6 | 333 | rc = sensor_write_reg(gspca_dev, confirm_reg, 0x00, &buf, 1); |
89f0863c TK |
334 | if (rc < 0) |
335 | return rc; | |
336 | ||
337 | return 0; | |
338 | } | |
339 | ||
930bf78c | 340 | static int cam_get_response16(struct gspca_dev *gspca_dev, u8 reg, int verbose) |
89f0863c | 341 | { |
89f0863c TK |
342 | int err_code; |
343 | ||
930bf78c | 344 | gspca_dev->usb_buf[0] = reg; |
89f0863c TK |
345 | err_code = mr_write(gspca_dev, 1); |
346 | if (err_code < 0) | |
347 | return err_code; | |
348 | ||
349 | err_code = mr_read(gspca_dev, 16); | |
930bf78c TK |
350 | if (err_code < 0) |
351 | return err_code; | |
352 | ||
353 | if (verbose) | |
354 | PDEBUG(D_PROBE, "Register: %02x reads %02x%02x%02x", reg, | |
355 | gspca_dev->usb_buf[0], | |
356 | gspca_dev->usb_buf[1], | |
357 | gspca_dev->usb_buf[2]); | |
358 | ||
359 | return 0; | |
89f0863c TK |
360 | } |
361 | ||
362 | static int zero_the_pointer(struct gspca_dev *gspca_dev) | |
363 | { | |
364 | __u8 *data = gspca_dev->usb_buf; | |
365 | int err_code; | |
366 | u8 status = 0; | |
367 | int tries = 0; | |
368 | ||
930bf78c | 369 | err_code = cam_get_response16(gspca_dev, 0x21, 0); |
89f0863c TK |
370 | if (err_code < 0) |
371 | return err_code; | |
372 | ||
89f0863c TK |
373 | data[0] = 0x19; |
374 | data[1] = 0x51; | |
375 | err_code = mr_write(gspca_dev, 2); | |
376 | if (err_code < 0) | |
377 | return err_code; | |
378 | ||
930bf78c | 379 | err_code = cam_get_response16(gspca_dev, 0x21, 0); |
89f0863c TK |
380 | if (err_code < 0) |
381 | return err_code; | |
382 | ||
383 | data[0] = 0x19; | |
384 | data[1] = 0xba; | |
385 | err_code = mr_write(gspca_dev, 2); | |
386 | if (err_code < 0) | |
387 | return err_code; | |
388 | ||
930bf78c | 389 | err_code = cam_get_response16(gspca_dev, 0x21, 0); |
89f0863c TK |
390 | if (err_code < 0) |
391 | return err_code; | |
392 | ||
393 | data[0] = 0x19; | |
394 | data[1] = 0x00; | |
395 | err_code = mr_write(gspca_dev, 2); | |
396 | if (err_code < 0) | |
397 | return err_code; | |
398 | ||
930bf78c | 399 | err_code = cam_get_response16(gspca_dev, 0x21, 0); |
89f0863c TK |
400 | if (err_code < 0) |
401 | return err_code; | |
402 | ||
403 | data[0] = 0x19; | |
404 | data[1] = 0x00; | |
405 | err_code = mr_write(gspca_dev, 2); | |
406 | if (err_code < 0) | |
407 | return err_code; | |
408 | ||
409 | while (status != 0x0a && tries < 256) { | |
930bf78c | 410 | err_code = cam_get_response16(gspca_dev, 0x21, 0); |
89f0863c TK |
411 | status = data[0]; |
412 | tries++; | |
413 | if (err_code < 0) | |
414 | return err_code; | |
415 | } | |
54943789 HG |
416 | if (status != 0x0a) |
417 | PDEBUG(D_ERR, "status is %02x", status); | |
89f0863c TK |
418 | |
419 | tries = 0; | |
420 | while (tries < 4) { | |
421 | data[0] = 0x19; | |
422 | data[1] = 0x00; | |
423 | err_code = mr_write(gspca_dev, 2); | |
424 | if (err_code < 0) | |
425 | return err_code; | |
426 | ||
930bf78c | 427 | err_code = cam_get_response16(gspca_dev, 0x21, 0); |
89f0863c TK |
428 | status = data[0]; |
429 | tries++; | |
430 | if (err_code < 0) | |
431 | return err_code; | |
432 | } | |
89f0863c TK |
433 | |
434 | data[0] = 0x19; | |
435 | err_code = mr_write(gspca_dev, 1); | |
436 | if (err_code < 0) | |
437 | return err_code; | |
438 | ||
439 | err_code = mr_read(gspca_dev, 16); | |
440 | if (err_code < 0) | |
441 | return err_code; | |
442 | ||
443 | return 0; | |
444 | } | |
445 | ||
930bf78c | 446 | static int stream_start(struct gspca_dev *gspca_dev) |
89f0863c | 447 | { |
930bf78c TK |
448 | gspca_dev->usb_buf[0] = 0x01; |
449 | gspca_dev->usb_buf[1] = 0x01; | |
450 | return mr_write(gspca_dev, 2); | |
451 | } | |
89f0863c | 452 | |
930bf78c TK |
453 | static void stream_stop(struct gspca_dev *gspca_dev) |
454 | { | |
455 | gspca_dev->usb_buf[0] = 0x01; | |
456 | gspca_dev->usb_buf[1] = 0x00; | |
457 | if (mr_write(gspca_dev, 2) < 0) | |
458 | PDEBUG(D_ERR, "Stream Stop failed"); | |
459 | } | |
89f0863c | 460 | |
930bf78c TK |
461 | static void lcd_stop(struct gspca_dev *gspca_dev) |
462 | { | |
463 | gspca_dev->usb_buf[0] = 0x19; | |
464 | gspca_dev->usb_buf[1] = 0x54; | |
465 | if (mr_write(gspca_dev, 2) < 0) | |
466 | PDEBUG(D_ERR, "LCD Stop failed"); | |
467 | } | |
89f0863c | 468 | |
930bf78c TK |
469 | static int isoc_enable(struct gspca_dev *gspca_dev) |
470 | { | |
471 | gspca_dev->usb_buf[0] = 0x00; | |
25985edc | 472 | gspca_dev->usb_buf[1] = 0x4d; /* ISOC transferring enable... */ |
930bf78c | 473 | return mr_write(gspca_dev, 2); |
89f0863c TK |
474 | } |
475 | ||
1160a381 | 476 | /* This function is called at probe time */ |
d661e622 KG |
477 | static int sd_config(struct gspca_dev *gspca_dev, |
478 | const struct usb_device_id *id) | |
479 | { | |
89f0863c | 480 | struct sd *sd = (struct sd *) gspca_dev; |
d661e622 | 481 | struct cam *cam; |
9d3103d0 | 482 | int gain_default = MR97310A_GAIN_DEFAULT; |
5f5e26b1 | 483 | int err_code; |
d661e622 KG |
484 | |
485 | cam = &gspca_dev->cam; | |
486 | cam->cam_mode = vga_mode; | |
487 | cam->nmodes = ARRAY_SIZE(vga_mode); | |
930bf78c TK |
488 | sd->do_lcd_stop = 0; |
489 | ||
1160a381 TK |
490 | /* Several of the supported CIF cameras share the same USB ID but |
491 | * require different initializations and different control settings. | |
492 | * The same is true of the VGA cameras. Therefore, we are forced | |
493 | * to start the initialization process in order to determine which | |
494 | * camera is present. Some of the supported cameras require the | |
930bf78c TK |
495 | * memory pointer to be set to 0 as the very first item of business |
496 | * or else they will not stream. So we do that immediately. | |
497 | */ | |
498 | err_code = zero_the_pointer(gspca_dev); | |
499 | if (err_code < 0) | |
500 | return err_code; | |
9ac6978a | 501 | |
b3e440ee TK |
502 | err_code = stream_start(gspca_dev); |
503 | if (err_code < 0) | |
504 | return err_code; | |
505 | ||
c260fe93 TK |
506 | /* Now, the query for sensor type. */ |
507 | err_code = cam_get_response16(gspca_dev, 0x07, 1); | |
508 | if (err_code < 0) | |
509 | return err_code; | |
510 | ||
8ac246cb | 511 | if (id->idProduct == 0x0110 || id->idProduct == 0x010e) { |
89f0863c | 512 | sd->cam_type = CAM_TYPE_CIF; |
9ac6978a | 513 | cam->nmodes--; |
5f5e26b1 | 514 | /* |
1160a381 TK |
515 | * All but one of the known CIF cameras share the same USB ID, |
516 | * but two different init routines are in use, and the control | |
517 | * settings are different, too. We need to detect which camera | |
518 | * of the two known varieties is connected! | |
5f5e26b1 | 519 | * |
930bf78c | 520 | * A list of known CIF cameras follows. They all report either |
c260fe93 | 521 | * 0200 for type 0 or 0300 for type 1. |
930bf78c TK |
522 | * If you have another to report, please do |
523 | * | |
524 | * Name sd->sensor_type reported by | |
525 | * | |
9d3103d0 | 526 | * Sakar 56379 Spy-shot 0 T. Kilgore |
930bf78c TK |
527 | * Innovage 0 T. Kilgore |
528 | * Vivitar Mini 0 H. De Goede | |
529 | * Vivitar Mini 0 E. Rodriguez | |
530 | * Vivitar Mini 1 T. Kilgore | |
531 | * Elta-Media 8212dc 1 T. Kaiser | |
532 | * Philips dig. keych. 1 T. Kilgore | |
1160a381 | 533 | * Trust Spyc@m 100 1 A. Jacobs |
5f5e26b1 | 534 | */ |
c260fe93 | 535 | switch (gspca_dev->usb_buf[0]) { |
930bf78c | 536 | case 2: |
5f5e26b1 | 537 | sd->sensor_type = 0; |
930bf78c TK |
538 | break; |
539 | case 3: | |
540 | sd->sensor_type = 1; | |
541 | break; | |
542 | default: | |
0b656321 | 543 | err("Unknown CIF Sensor id : %02x", |
930bf78c TK |
544 | gspca_dev->usb_buf[1]); |
545 | return -ENODEV; | |
546 | } | |
54943789 HG |
547 | PDEBUG(D_PROBE, "MR97310A CIF camera detected, sensor: %d", |
548 | sd->sensor_type); | |
930bf78c TK |
549 | } else { |
550 | sd->cam_type = CAM_TYPE_VGA; | |
5f5e26b1 | 551 | |
930bf78c | 552 | /* |
c260fe93 | 553 | * Here is a table of the responses to the query for sensor |
9d3103d0 TK |
554 | * type, from the known MR97310A VGA cameras. Six different |
555 | * cameras of which five share the same USB ID. | |
930bf78c TK |
556 | * |
557 | * Name gspca_dev->usb_buf[] sd->sensor_type | |
b3e440ee TK |
558 | * sd->do_lcd_stop |
559 | * Aiptek Pencam VGA+ 0300 0 1 | |
9d3103d0 | 560 | * ION digital 0300 0 1 |
b3e440ee TK |
561 | * Argus DC-1620 0450 1 0 |
562 | * Argus QuickClix 0420 1 1 | |
9d3103d0 TK |
563 | * Sakar 77379 Digital 0350 0 1 |
564 | * Sakar 1638x CyberPix 0120 0 2 | |
930bf78c | 565 | * |
b3e440ee TK |
566 | * Based upon these results, we assume default settings |
567 | * and then correct as necessary, as follows. | |
930bf78c | 568 | * |
930bf78c TK |
569 | */ |
570 | ||
b3e440ee TK |
571 | sd->sensor_type = 1; |
572 | sd->do_lcd_stop = 0; | |
64f4d9a3 | 573 | sd->adj_colors = 0; |
9d3103d0 TK |
574 | if (gspca_dev->usb_buf[0] == 0x01) { |
575 | sd->sensor_type = 2; | |
576 | } else if ((gspca_dev->usb_buf[0] != 0x03) && | |
b3e440ee | 577 | (gspca_dev->usb_buf[0] != 0x04)) { |
0b656321 | 578 | err("Unknown VGA Sensor id Byte 0: %02x", |
9d3103d0 | 579 | gspca_dev->usb_buf[0]); |
0b656321 JFM |
580 | err("Defaults assumed, may not work"); |
581 | err("Please report this"); | |
b3e440ee | 582 | } |
64f4d9a3 TK |
583 | /* Sakar Digital color needs to be adjusted. */ |
584 | if ((gspca_dev->usb_buf[0] == 0x03) && | |
585 | (gspca_dev->usb_buf[1] == 0x50)) | |
586 | sd->adj_colors = 1; | |
b3e440ee TK |
587 | if (gspca_dev->usb_buf[0] == 0x04) { |
588 | sd->do_lcd_stop = 1; | |
930bf78c TK |
589 | switch (gspca_dev->usb_buf[1]) { |
590 | case 0x50: | |
b3e440ee TK |
591 | sd->sensor_type = 0; |
592 | PDEBUG(D_PROBE, "sensor_type corrected to 0"); | |
930bf78c TK |
593 | break; |
594 | case 0x20: | |
b3e440ee | 595 | /* Nothing to do here. */ |
930bf78c TK |
596 | break; |
597 | default: | |
0b656321 | 598 | err("Unknown VGA Sensor id Byte 1: %02x", |
b3e440ee | 599 | gspca_dev->usb_buf[1]); |
0b656321 JFM |
600 | err("Defaults assumed, may not work"); |
601 | err("Please report this"); | |
930bf78c | 602 | } |
78028706 | 603 | } |
930bf78c TK |
604 | PDEBUG(D_PROBE, "MR97310A VGA camera detected, sensor: %d", |
605 | sd->sensor_type); | |
606 | } | |
c260fe93 | 607 | /* Stop streaming as we've started it only to probe the sensor type. */ |
930bf78c | 608 | sd_stopN(gspca_dev); |
78028706 | 609 | |
930bf78c TK |
610 | if (force_sensor_type != -1) { |
611 | sd->sensor_type = !!force_sensor_type; | |
612 | PDEBUG(D_PROBE, "Forcing sensor type to: %d", | |
613 | sd->sensor_type); | |
614 | } | |
615 | ||
616 | /* Setup controls depending on camera type */ | |
617 | if (sd->cam_type == CAM_TYPE_CIF) { | |
618 | /* No brightness for sensor_type 0 */ | |
5f5e26b1 | 619 | if (sd->sensor_type == 0) |
930bf78c | 620 | gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) | |
9d3103d0 TK |
621 | (1 << ARGUS_QC_BRIGHTNESS_IDX) | |
622 | (1 << CONTRAST_IDX) | | |
623 | (1 << SAKAR_CS_GAIN_IDX); | |
930bf78c | 624 | else |
065b6f7a | 625 | gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX) | |
9d3103d0 TK |
626 | (1 << CONTRAST_IDX) | |
627 | (1 << SAKAR_CS_GAIN_IDX) | | |
065b6f7a | 628 | (1 << MIN_CLOCKDIV_IDX); |
9ac6978a | 629 | } else { |
930bf78c TK |
630 | /* All controls need to be disabled if VGA sensor_type is 0 */ |
631 | if (sd->sensor_type == 0) | |
632 | gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) | | |
633 | (1 << ARGUS_QC_BRIGHTNESS_IDX) | | |
634 | (1 << EXPOSURE_IDX) | | |
065b6f7a | 635 | (1 << GAIN_IDX) | |
9d3103d0 TK |
636 | (1 << CONTRAST_IDX) | |
637 | (1 << SAKAR_CS_GAIN_IDX) | | |
065b6f7a | 638 | (1 << MIN_CLOCKDIV_IDX); |
9d3103d0 TK |
639 | else if (sd->sensor_type == 2) { |
640 | gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) | | |
641 | (1 << ARGUS_QC_BRIGHTNESS_IDX) | | |
642 | (1 << GAIN_IDX) | | |
643 | (1 << MIN_CLOCKDIV_IDX); | |
644 | gain_default = MR97310A_CS_GAIN_DEFAULT; | |
645 | } else if (sd->do_lcd_stop) | |
930bf78c | 646 | /* Argus QuickClix has different brightness limits */ |
9d3103d0 TK |
647 | gspca_dev->ctrl_dis = (1 << NORM_BRIGHTNESS_IDX) | |
648 | (1 << CONTRAST_IDX) | | |
649 | (1 << SAKAR_CS_GAIN_IDX); | |
930bf78c | 650 | else |
9d3103d0 TK |
651 | gspca_dev->ctrl_dis = (1 << ARGUS_QC_BRIGHTNESS_IDX) | |
652 | (1 << CONTRAST_IDX) | | |
653 | (1 << SAKAR_CS_GAIN_IDX); | |
89f0863c | 654 | } |
9ac6978a HG |
655 | |
656 | sd->brightness = MR97310A_BRIGHTNESS_DEFAULT; | |
657 | sd->exposure = MR97310A_EXPOSURE_DEFAULT; | |
9d3103d0 TK |
658 | sd->gain = gain_default; |
659 | sd->contrast = MR97310A_CONTRAST_DEFAULT; | |
065b6f7a | 660 | sd->min_clockdiv = MR97310A_MIN_CLOCKDIV_DEFAULT; |
9ac6978a | 661 | |
d661e622 KG |
662 | return 0; |
663 | } | |
664 | ||
665 | /* this function is called at probe and resume time */ | |
666 | static int sd_init(struct gspca_dev *gspca_dev) | |
667 | { | |
668 | return 0; | |
669 | } | |
670 | ||
89f0863c | 671 | static int start_cif_cam(struct gspca_dev *gspca_dev) |
d661e622 KG |
672 | { |
673 | struct sd *sd = (struct sd *) gspca_dev; | |
674 | __u8 *data = gspca_dev->usb_buf; | |
675 | int err_code; | |
294d8b4a | 676 | static const __u8 startup_string[] = { |
89f0863c TK |
677 | 0x00, |
678 | 0x0d, | |
679 | 0x01, | |
680 | 0x00, /* Hsize/8 for 352 or 320 */ | |
681 | 0x00, /* Vsize/4 for 288 or 240 */ | |
682 | 0x13, /* or 0xbb, depends on sensor */ | |
683 | 0x00, /* Hstart, depends on res. */ | |
684 | 0x00, /* reserved ? */ | |
685 | 0x00, /* Vstart, depends on res. and sensor */ | |
686 | 0x50, /* 0x54 to get 176 or 160 */ | |
687 | 0xc0 | |
688 | }; | |
689 | ||
690 | /* Note: Some of the above descriptions guessed from MR97113A driver */ | |
d661e622 | 691 | |
89f0863c TK |
692 | memcpy(data, startup_string, 11); |
693 | if (sd->sensor_type) | |
694 | data[5] = 0xbb; | |
d661e622 KG |
695 | |
696 | switch (gspca_dev->width) { | |
697 | case 160: | |
89f0863c | 698 | data[9] |= 0x04; /* reg 8, 2:1 scale down from 320 */ |
d661e622 KG |
699 | /* fall thru */ |
700 | case 320: | |
d661e622 | 701 | default: |
89f0863c TK |
702 | data[3] = 0x28; /* reg 2, H size/8 */ |
703 | data[4] = 0x3c; /* reg 3, V size/4 */ | |
704 | data[6] = 0x14; /* reg 5, H start */ | |
705 | data[8] = 0x1a + sd->sensor_type; /* reg 7, V start */ | |
d661e622 | 706 | break; |
d661e622 | 707 | case 176: |
89f0863c | 708 | data[9] |= 0x04; /* reg 8, 2:1 scale down from 352 */ |
d661e622 KG |
709 | /* fall thru */ |
710 | case 352: | |
89f0863c TK |
711 | data[3] = 0x2c; /* reg 2, H size/8 */ |
712 | data[4] = 0x48; /* reg 3, V size/4 */ | |
713 | data[6] = 0x06; /* reg 5, H start */ | |
32345b05 | 714 | data[8] = 0x06 - sd->sensor_type; /* reg 7, V start */ |
d661e622 KG |
715 | break; |
716 | } | |
89f0863c | 717 | err_code = mr_write(gspca_dev, 11); |
d661e622 KG |
718 | if (err_code < 0) |
719 | return err_code; | |
720 | ||
89f0863c | 721 | if (!sd->sensor_type) { |
294d8b4a | 722 | static const struct sensor_w_data cif_sensor0_init_data[] = { |
89f0863c TK |
723 | {0x02, 0x00, {0x03, 0x5a, 0xb5, 0x01, |
724 | 0x0f, 0x14, 0x0f, 0x10}, 8}, | |
725 | {0x0c, 0x00, {0x04, 0x01, 0x01, 0x00, 0x1f}, 5}, | |
726 | {0x12, 0x00, {0x07}, 1}, | |
727 | {0x1f, 0x00, {0x06}, 1}, | |
728 | {0x27, 0x00, {0x04}, 1}, | |
729 | {0x29, 0x00, {0x0c}, 1}, | |
730 | {0x40, 0x00, {0x40, 0x00, 0x04}, 3}, | |
731 | {0x50, 0x00, {0x60}, 1}, | |
732 | {0x60, 0x00, {0x06}, 1}, | |
733 | {0x6b, 0x00, {0x85, 0x85, 0xc8, 0xc8, 0xc8, 0xc8}, 6}, | |
734 | {0x72, 0x00, {0x1e, 0x56}, 2}, | |
735 | {0x75, 0x00, {0x58, 0x40, 0xa2, 0x02, 0x31, 0x02, | |
736 | 0x31, 0x80, 0x00}, 9}, | |
737 | {0x11, 0x00, {0x01}, 1}, | |
738 | {0, 0, {0}, 0} | |
739 | }; | |
740 | err_code = sensor_write_regs(gspca_dev, cif_sensor0_init_data, | |
741 | ARRAY_SIZE(cif_sensor0_init_data)); | |
742 | } else { /* sd->sensor_type = 1 */ | |
294d8b4a | 743 | static const struct sensor_w_data cif_sensor1_init_data[] = { |
9ac6978a | 744 | /* Reg 3,4, 7,8 get set by the controls */ |
89f0863c | 745 | {0x02, 0x00, {0x10}, 1}, |
9ac6978a HG |
746 | {0x05, 0x01, {0x22}, 1}, /* 5/6 also seen as 65h/32h */ |
747 | {0x06, 0x01, {0x00}, 1}, | |
89f0863c TK |
748 | {0x09, 0x02, {0x0e}, 1}, |
749 | {0x0a, 0x02, {0x05}, 1}, | |
750 | {0x0b, 0x02, {0x05}, 1}, | |
751 | {0x0c, 0x02, {0x0f}, 1}, | |
9ac6978a | 752 | {0x0d, 0x02, {0x07}, 1}, |
89f0863c TK |
753 | {0x0e, 0x02, {0x0c}, 1}, |
754 | {0x0f, 0x00, {0x00}, 1}, | |
755 | {0x10, 0x00, {0x06}, 1}, | |
756 | {0x11, 0x00, {0x07}, 1}, | |
757 | {0x12, 0x00, {0x00}, 1}, | |
758 | {0x13, 0x00, {0x01}, 1}, | |
759 | {0, 0, {0}, 0} | |
760 | }; | |
70136081 TK |
761 | /* Without this command the cam won't work with USB-UHCI */ |
762 | gspca_dev->usb_buf[0] = 0x0a; | |
763 | gspca_dev->usb_buf[1] = 0x00; | |
764 | err_code = mr_write(gspca_dev, 2); | |
765 | if (err_code < 0) | |
766 | return err_code; | |
89f0863c TK |
767 | err_code = sensor_write_regs(gspca_dev, cif_sensor1_init_data, |
768 | ARRAY_SIZE(cif_sensor1_init_data)); | |
769 | } | |
930bf78c | 770 | return err_code; |
89f0863c | 771 | } |
d661e622 | 772 | |
89f0863c TK |
773 | static int start_vga_cam(struct gspca_dev *gspca_dev) |
774 | { | |
775 | struct sd *sd = (struct sd *) gspca_dev; | |
776 | __u8 *data = gspca_dev->usb_buf; | |
777 | int err_code; | |
294d8b4a JFM |
778 | static const __u8 startup_string[] = |
779 | {0x00, 0x0d, 0x01, 0x00, 0x00, 0x2b, 0x00, 0x00, | |
780 | 0x00, 0x50, 0xc0}; | |
89f0863c | 781 | /* What some of these mean is explained in start_cif_cam(), above */ |
78028706 | 782 | |
89f0863c TK |
783 | memcpy(data, startup_string, 11); |
784 | if (!sd->sensor_type) { | |
785 | data[5] = 0x00; | |
786 | data[10] = 0x91; | |
787 | } | |
9d3103d0 TK |
788 | if (sd->sensor_type == 2) { |
789 | data[5] = 0x00; | |
790 | data[10] = 0x18; | |
791 | } | |
89f0863c TK |
792 | |
793 | switch (gspca_dev->width) { | |
794 | case 160: | |
795 | data[9] |= 0x0c; /* reg 8, 4:1 scale down */ | |
796 | /* fall thru */ | |
797 | case 320: | |
798 | data[9] |= 0x04; /* reg 8, 2:1 scale down */ | |
799 | /* fall thru */ | |
800 | case 640: | |
801 | default: | |
802 | data[3] = 0x50; /* reg 2, H size/8 */ | |
803 | data[4] = 0x78; /* reg 3, V size/4 */ | |
804 | data[6] = 0x04; /* reg 5, H start */ | |
805 | data[8] = 0x03; /* reg 7, V start */ | |
9d3103d0 TK |
806 | if (sd->sensor_type == 2) { |
807 | data[6] = 2; | |
808 | data[8] = 1; | |
809 | } | |
89f0863c TK |
810 | if (sd->do_lcd_stop) |
811 | data[8] = 0x04; /* Bayer tile shifted */ | |
812 | break; | |
813 | ||
814 | case 176: | |
815 | data[9] |= 0x04; /* reg 8, 2:1 scale down */ | |
816 | /* fall thru */ | |
817 | case 352: | |
818 | data[3] = 0x2c; /* reg 2, H size */ | |
819 | data[4] = 0x48; /* reg 3, V size */ | |
820 | data[6] = 0x94; /* reg 5, H start */ | |
821 | data[8] = 0x63; /* reg 7, V start */ | |
822 | if (sd->do_lcd_stop) | |
823 | data[8] = 0x64; /* Bayer tile shifted */ | |
824 | break; | |
825 | } | |
826 | ||
827 | err_code = mr_write(gspca_dev, 11); | |
d661e622 KG |
828 | if (err_code < 0) |
829 | return err_code; | |
830 | ||
89f0863c | 831 | if (!sd->sensor_type) { |
294d8b4a | 832 | static const struct sensor_w_data vga_sensor0_init_data[] = { |
89f0863c TK |
833 | {0x01, 0x00, {0x0c, 0x00, 0x04}, 3}, |
834 | {0x14, 0x00, {0x01, 0xe4, 0x02, 0x84}, 4}, | |
835 | {0x20, 0x00, {0x00, 0x80, 0x00, 0x08}, 4}, | |
836 | {0x25, 0x00, {0x03, 0xa9, 0x80}, 3}, | |
837 | {0x30, 0x00, {0x30, 0x18, 0x10, 0x18}, 4}, | |
838 | {0, 0, {0}, 0} | |
839 | }; | |
840 | err_code = sensor_write_regs(gspca_dev, vga_sensor0_init_data, | |
841 | ARRAY_SIZE(vga_sensor0_init_data)); | |
9d3103d0 | 842 | } else if (sd->sensor_type == 1) { |
294d8b4a | 843 | static const struct sensor_w_data color_adj[] = { |
64f4d9a3 TK |
844 | {0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00, |
845 | /* adjusted blue, green, red gain correct | |
846 | too much blue from the Sakar Digital */ | |
b31210d7 | 847 | 0x05, 0x01, 0x04}, 8} |
64f4d9a3 TK |
848 | }; |
849 | ||
294d8b4a | 850 | static const struct sensor_w_data color_no_adj[] = { |
89f0863c | 851 | {0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00, |
64f4d9a3 TK |
852 | /* default blue, green, red gain settings */ |
853 | 0x07, 0x00, 0x01}, 8} | |
854 | }; | |
855 | ||
294d8b4a | 856 | static const struct sensor_w_data vga_sensor1_init_data[] = { |
89f0863c | 857 | {0x11, 0x04, {0x01}, 1}, |
542821d8 TK |
858 | {0x0a, 0x00, {0x00, 0x01, 0x00, 0x00, 0x01, |
859 | /* These settings may be better for some cameras */ | |
860 | /* {0x0a, 0x00, {0x01, 0x06, 0x00, 0x00, 0x01, */ | |
89f0863c TK |
861 | 0x00, 0x0a}, 7}, |
862 | {0x11, 0x04, {0x01}, 1}, | |
863 | {0x12, 0x00, {0x00, 0x63, 0x00, 0x70, 0x00, 0x00}, 6}, | |
864 | {0x11, 0x04, {0x01}, 1}, | |
865 | {0, 0, {0}, 0} | |
866 | }; | |
64f4d9a3 TK |
867 | |
868 | if (sd->adj_colors) | |
869 | err_code = sensor_write_regs(gspca_dev, color_adj, | |
870 | ARRAY_SIZE(color_adj)); | |
871 | else | |
872 | err_code = sensor_write_regs(gspca_dev, color_no_adj, | |
873 | ARRAY_SIZE(color_no_adj)); | |
874 | ||
875 | if (err_code < 0) | |
876 | return err_code; | |
877 | ||
89f0863c TK |
878 | err_code = sensor_write_regs(gspca_dev, vga_sensor1_init_data, |
879 | ARRAY_SIZE(vga_sensor1_init_data)); | |
9d3103d0 | 880 | } else { /* sensor type == 2 */ |
294d8b4a | 881 | static const struct sensor_w_data vga_sensor2_init_data[] = { |
9d3103d0 TK |
882 | |
883 | {0x01, 0x00, {0x48}, 1}, | |
884 | {0x02, 0x00, {0x22}, 1}, | |
885 | /* Reg 3 msb and 4 is lsb of the exposure setting*/ | |
886 | {0x05, 0x00, {0x10}, 1}, | |
887 | {0x06, 0x00, {0x00}, 1}, | |
888 | {0x07, 0x00, {0x00}, 1}, | |
889 | {0x08, 0x00, {0x00}, 1}, | |
890 | {0x09, 0x00, {0x00}, 1}, | |
891 | /* The following are used in the gain control | |
892 | * which is BTW completely borked in the OEM driver | |
893 | * The values for each color go from 0 to 0x7ff | |
894 | *{0x0a, 0x00, {0x01}, 1}, green1 gain msb | |
895 | *{0x0b, 0x00, {0x10}, 1}, green1 gain lsb | |
896 | *{0x0c, 0x00, {0x01}, 1}, red gain msb | |
897 | *{0x0d, 0x00, {0x10}, 1}, red gain lsb | |
898 | *{0x0e, 0x00, {0x01}, 1}, blue gain msb | |
899 | *{0x0f, 0x00, {0x10}, 1}, blue gain lsb | |
900 | *{0x10, 0x00, {0x01}, 1}, green2 gain msb | |
901 | *{0x11, 0x00, {0x10}, 1}, green2 gain lsb | |
902 | */ | |
903 | {0x12, 0x00, {0x00}, 1}, | |
904 | {0x13, 0x00, {0x04}, 1}, /* weird effect on colors */ | |
905 | {0x14, 0x00, {0x00}, 1}, | |
906 | {0x15, 0x00, {0x06}, 1}, | |
907 | {0x16, 0x00, {0x01}, 1}, | |
908 | {0x17, 0x00, {0xe2}, 1}, /* vertical alignment */ | |
909 | {0x18, 0x00, {0x02}, 1}, | |
910 | {0x19, 0x00, {0x82}, 1}, /* don't mess with */ | |
911 | {0x1a, 0x00, {0x00}, 1}, | |
912 | {0x1b, 0x00, {0x20}, 1}, | |
913 | /* {0x1c, 0x00, {0x17}, 1}, contrast control */ | |
914 | {0x1d, 0x00, {0x80}, 1}, /* moving causes a mess */ | |
915 | {0x1e, 0x00, {0x08}, 1}, /* moving jams the camera */ | |
916 | {0x1f, 0x00, {0x0c}, 1}, | |
917 | {0x20, 0x00, {0x00}, 1}, | |
918 | {0, 0, {0}, 0} | |
919 | }; | |
920 | err_code = sensor_write_regs(gspca_dev, vga_sensor2_init_data, | |
921 | ARRAY_SIZE(vga_sensor2_init_data)); | |
89f0863c | 922 | } |
89f0863c TK |
923 | return err_code; |
924 | } | |
925 | ||
926 | static int sd_start(struct gspca_dev *gspca_dev) | |
927 | { | |
928 | struct sd *sd = (struct sd *) gspca_dev; | |
929 | int err_code; | |
89f0863c | 930 | |
89f0863c | 931 | sd->sof_read = 0; |
930bf78c TK |
932 | |
933 | /* Some of the VGA cameras require the memory pointer | |
934 | * to be set to 0 again. We have been forced to start the | |
b4b84dee TK |
935 | * stream in sd_config() to detect the hardware, and closed it. |
936 | * Thus, we need here to do a completely fresh and clean start. */ | |
930bf78c TK |
937 | err_code = zero_the_pointer(gspca_dev); |
938 | if (err_code < 0) | |
939 | return err_code; | |
940 | ||
941 | err_code = stream_start(gspca_dev); | |
942 | if (err_code < 0) | |
943 | return err_code; | |
944 | ||
89f0863c | 945 | if (sd->cam_type == CAM_TYPE_CIF) { |
89f0863c TK |
946 | err_code = start_cif_cam(gspca_dev); |
947 | } else { | |
89f0863c TK |
948 | err_code = start_vga_cam(gspca_dev); |
949 | } | |
930bf78c TK |
950 | if (err_code < 0) |
951 | return err_code; | |
952 | ||
953 | setbrightness(gspca_dev); | |
9d3103d0 | 954 | setcontrast(gspca_dev); |
930bf78c TK |
955 | setexposure(gspca_dev); |
956 | setgain(gspca_dev); | |
957 | ||
958 | return isoc_enable(gspca_dev); | |
d661e622 KG |
959 | } |
960 | ||
961 | static void sd_stopN(struct gspca_dev *gspca_dev) | |
962 | { | |
89f0863c | 963 | struct sd *sd = (struct sd *) gspca_dev; |
89f0863c | 964 | |
930bf78c | 965 | stream_stop(gspca_dev); |
89f0863c TK |
966 | /* Not all the cams need this, but even if not, probably a good idea */ |
967 | zero_the_pointer(gspca_dev); | |
930bf78c TK |
968 | if (sd->do_lcd_stop) |
969 | lcd_stop(gspca_dev); | |
89f0863c TK |
970 | } |
971 | ||
972 | static void setbrightness(struct gspca_dev *gspca_dev) | |
973 | { | |
974 | struct sd *sd = (struct sd *) gspca_dev; | |
975 | u8 val; | |
930bf78c TK |
976 | u8 sign_reg = 7; /* This reg and the next one used on CIF cams. */ |
977 | u8 value_reg = 8; /* VGA cams seem to use regs 0x0b and 0x0c */ | |
294d8b4a | 978 | static const u8 quick_clix_table[] = |
930bf78c TK |
979 | /* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */ |
980 | { 0, 4, 8, 12, 1, 2, 3, 5, 6, 9, 7, 10, 13, 11, 14, 15}; | |
981 | /* | |
982 | * This control is disabled for CIF type 1 and VGA type 0 cameras. | |
983 | * It does not quite act linearly for the Argus QuickClix camera, | |
984 | * but it does control brightness. The values are 0 - 15 only, and | |
985 | * the table above makes them act consecutively. | |
986 | */ | |
987 | if ((gspca_dev->ctrl_dis & (1 << NORM_BRIGHTNESS_IDX)) && | |
988 | (gspca_dev->ctrl_dis & (1 << ARGUS_QC_BRIGHTNESS_IDX))) | |
9ac6978a HG |
989 | return; |
990 | ||
930bf78c TK |
991 | if (sd->cam_type == CAM_TYPE_VGA) { |
992 | sign_reg += 4; | |
993 | value_reg += 4; | |
994 | } | |
995 | ||
b4b84dee | 996 | /* Note register 7 is also seen as 0x8x or 0xCx in some dumps */ |
89f0863c | 997 | if (sd->brightness > 0) { |
930bf78c | 998 | sensor_write1(gspca_dev, sign_reg, 0x00); |
89f0863c TK |
999 | val = sd->brightness; |
1000 | } else { | |
930bf78c TK |
1001 | sensor_write1(gspca_dev, sign_reg, 0x01); |
1002 | val = (257 - sd->brightness); | |
89f0863c | 1003 | } |
930bf78c TK |
1004 | /* Use lookup table for funky Argus QuickClix brightness */ |
1005 | if (sd->do_lcd_stop) | |
1006 | val = quick_clix_table[val]; | |
1007 | ||
1008 | sensor_write1(gspca_dev, value_reg, val); | |
89f0863c TK |
1009 | } |
1010 | ||
1011 | static void setexposure(struct gspca_dev *gspca_dev) | |
1012 | { | |
1013 | struct sd *sd = (struct sd *) gspca_dev; | |
9d3103d0 | 1014 | int exposure = MR97310A_EXPOSURE_DEFAULT; |
065b6f7a | 1015 | u8 buf[2]; |
89f0863c | 1016 | |
9ac6978a HG |
1017 | if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX)) |
1018 | return; | |
1019 | ||
930bf78c | 1020 | if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1) { |
b4b84dee | 1021 | /* This cam does not like exposure settings < 300, |
d76f975c HG |
1022 | so scale 0 - 4095 to 300 - 4095 */ |
1023 | exposure = (sd->exposure * 9267) / 10000 + 300; | |
930bf78c TK |
1024 | sensor_write1(gspca_dev, 3, exposure >> 4); |
1025 | sensor_write1(gspca_dev, 4, exposure & 0x0f); | |
9d3103d0 TK |
1026 | } else if (sd->sensor_type == 2) { |
1027 | exposure = sd->exposure; | |
1028 | exposure >>= 3; | |
1029 | sensor_write1(gspca_dev, 3, exposure >> 8); | |
1030 | sensor_write1(gspca_dev, 4, exposure & 0xff); | |
a2e081b6 | 1031 | } else { |
a2e081b6 HG |
1032 | /* We have both a clock divider and an exposure register. |
1033 | We first calculate the clock divider, as that determines | |
b4b84dee | 1034 | the maximum exposure and then we calculate the exposure |
a2e081b6 HG |
1035 | register setting (which goes from 0 - 511). |
1036 | ||
1037 | Note our 0 - 4095 exposure is mapped to 0 - 511 | |
1038 | milliseconds exposure time */ | |
930bf78c | 1039 | u8 clockdiv = (60 * sd->exposure + 7999) / 8000; |
a2e081b6 HG |
1040 | |
1041 | /* Limit framerate to not exceed usb bandwidth */ | |
065b6f7a HG |
1042 | if (clockdiv < sd->min_clockdiv && gspca_dev->width >= 320) |
1043 | clockdiv = sd->min_clockdiv; | |
a2e081b6 HG |
1044 | else if (clockdiv < 2) |
1045 | clockdiv = 2; | |
1046 | ||
930bf78c TK |
1047 | if (sd->cam_type == CAM_TYPE_VGA && clockdiv < 4) |
1048 | clockdiv = 4; | |
1049 | ||
a2e081b6 HG |
1050 | /* Frame exposure time in ms = 1000 * clockdiv / 60 -> |
1051 | exposure = (sd->exposure / 8) * 511 / (1000 * clockdiv / 60) */ | |
1052 | exposure = (60 * 511 * sd->exposure) / (8000 * clockdiv); | |
1053 | if (exposure > 511) | |
1054 | exposure = 511; | |
1055 | ||
1056 | /* exposure register value is reversed! */ | |
1057 | exposure = 511 - exposure; | |
1058 | ||
065b6f7a HG |
1059 | buf[0] = exposure & 0xff; |
1060 | buf[1] = exposure >> 8; | |
1061 | sensor_write_reg(gspca_dev, 0x0e, 0, buf, 2); | |
a2e081b6 | 1062 | sensor_write1(gspca_dev, 0x02, clockdiv); |
a2e081b6 | 1063 | } |
89f0863c TK |
1064 | } |
1065 | ||
1066 | static void setgain(struct gspca_dev *gspca_dev) | |
1067 | { | |
1068 | struct sd *sd = (struct sd *) gspca_dev; | |
9d3103d0 | 1069 | u8 gainreg; |
89f0863c | 1070 | |
9d3103d0 TK |
1071 | if ((gspca_dev->ctrl_dis & (1 << GAIN_IDX)) && |
1072 | (gspca_dev->ctrl_dis & (1 << SAKAR_CS_GAIN_IDX))) | |
9ac6978a HG |
1073 | return; |
1074 | ||
9d3103d0 | 1075 | if (sd->cam_type == CAM_TYPE_CIF && sd->sensor_type == 1) |
823902de | 1076 | sensor_write1(gspca_dev, 0x0e, sd->gain); |
9d3103d0 TK |
1077 | else if (sd->cam_type == CAM_TYPE_VGA && sd->sensor_type == 2) |
1078 | for (gainreg = 0x0a; gainreg < 0x11; gainreg += 2) { | |
1079 | sensor_write1(gspca_dev, gainreg, sd->gain >> 8); | |
1080 | sensor_write1(gspca_dev, gainreg + 1, sd->gain & 0xff); | |
1081 | } | |
1082 | else | |
a2e081b6 | 1083 | sensor_write1(gspca_dev, 0x10, sd->gain); |
89f0863c TK |
1084 | } |
1085 | ||
9d3103d0 TK |
1086 | static void setcontrast(struct gspca_dev *gspca_dev) |
1087 | { | |
1088 | struct sd *sd = (struct sd *) gspca_dev; | |
1089 | ||
1090 | if (gspca_dev->ctrl_dis & (1 << CONTRAST_IDX)) | |
1091 | return; | |
1092 | ||
1093 | sensor_write1(gspca_dev, 0x1c, sd->contrast); | |
1094 | } | |
1095 | ||
1096 | ||
89f0863c TK |
1097 | static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) |
1098 | { | |
1099 | struct sd *sd = (struct sd *) gspca_dev; | |
1100 | ||
1101 | sd->brightness = val; | |
1102 | if (gspca_dev->streaming) | |
1103 | setbrightness(gspca_dev); | |
1104 | return 0; | |
1105 | } | |
1106 | ||
1107 | static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val) | |
1108 | { | |
1109 | struct sd *sd = (struct sd *) gspca_dev; | |
1110 | ||
1111 | *val = sd->brightness; | |
1112 | return 0; | |
1113 | } | |
1114 | ||
1115 | static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val) | |
1116 | { | |
1117 | struct sd *sd = (struct sd *) gspca_dev; | |
1118 | ||
1119 | sd->exposure = val; | |
1120 | if (gspca_dev->streaming) | |
1121 | setexposure(gspca_dev); | |
1122 | return 0; | |
1123 | } | |
1124 | ||
1125 | static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val) | |
1126 | { | |
1127 | struct sd *sd = (struct sd *) gspca_dev; | |
1128 | ||
1129 | *val = sd->exposure; | |
1130 | return 0; | |
1131 | } | |
1132 | ||
1133 | static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val) | |
1134 | { | |
1135 | struct sd *sd = (struct sd *) gspca_dev; | |
1136 | ||
1137 | sd->gain = val; | |
1138 | if (gspca_dev->streaming) | |
1139 | setgain(gspca_dev); | |
1140 | return 0; | |
1141 | } | |
1142 | ||
1143 | static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val) | |
1144 | { | |
1145 | struct sd *sd = (struct sd *) gspca_dev; | |
1146 | ||
1147 | *val = sd->gain; | |
1148 | return 0; | |
d661e622 KG |
1149 | } |
1150 | ||
9d3103d0 TK |
1151 | static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val) |
1152 | { | |
1153 | struct sd *sd = (struct sd *) gspca_dev; | |
1154 | ||
1155 | sd->contrast = val; | |
1156 | if (gspca_dev->streaming) | |
1157 | setcontrast(gspca_dev); | |
1158 | return 0; | |
1159 | } | |
1160 | ||
1161 | ||
1162 | static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val) | |
1163 | { | |
1164 | struct sd *sd = (struct sd *) gspca_dev; | |
1165 | ||
1166 | *val = sd->contrast; | |
1167 | return 0; | |
1168 | } | |
1169 | ||
065b6f7a HG |
1170 | static int sd_setmin_clockdiv(struct gspca_dev *gspca_dev, __s32 val) |
1171 | { | |
1172 | struct sd *sd = (struct sd *) gspca_dev; | |
1173 | ||
1174 | sd->min_clockdiv = val; | |
1175 | if (gspca_dev->streaming) | |
1176 | setexposure(gspca_dev); | |
1177 | return 0; | |
1178 | } | |
1179 | ||
1180 | static int sd_getmin_clockdiv(struct gspca_dev *gspca_dev, __s32 *val) | |
1181 | { | |
1182 | struct sd *sd = (struct sd *) gspca_dev; | |
1183 | ||
1184 | *val = sd->min_clockdiv; | |
1185 | return 0; | |
1186 | } | |
1187 | ||
d661e622 KG |
1188 | /* Include pac common sof detection functions */ |
1189 | #include "pac_common.h" | |
1190 | ||
1191 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | |
76dd272b JFM |
1192 | u8 *data, /* isoc packet */ |
1193 | int len) /* iso packet length */ | |
d661e622 | 1194 | { |
a6b69e40 | 1195 | struct sd *sd = (struct sd *) gspca_dev; |
d661e622 KG |
1196 | unsigned char *sof; |
1197 | ||
a6b69e40 | 1198 | sof = pac_find_sof(&sd->sof_read, data, len); |
d661e622 KG |
1199 | if (sof) { |
1200 | int n; | |
1201 | ||
1202 | /* finish decoding current frame */ | |
1203 | n = sof - data; | |
1204 | if (n > sizeof pac_sof_marker) | |
1205 | n -= sizeof pac_sof_marker; | |
1206 | else | |
1207 | n = 0; | |
76dd272b | 1208 | gspca_frame_add(gspca_dev, LAST_PACKET, |
d661e622 | 1209 | data, n); |
9832d765 | 1210 | /* Start next frame. */ |
76dd272b | 1211 | gspca_frame_add(gspca_dev, FIRST_PACKET, |
9832d765 | 1212 | pac_sof_marker, sizeof pac_sof_marker); |
d661e622 KG |
1213 | len -= sof - data; |
1214 | data = sof; | |
1215 | } | |
76dd272b | 1216 | gspca_frame_add(gspca_dev, INTER_PACKET, data, len); |
d661e622 KG |
1217 | } |
1218 | ||
1219 | /* sub-driver description */ | |
1220 | static const struct sd_desc sd_desc = { | |
1221 | .name = MODULE_NAME, | |
1222 | .ctrls = sd_ctrls, | |
1223 | .nctrls = ARRAY_SIZE(sd_ctrls), | |
1224 | .config = sd_config, | |
1225 | .init = sd_init, | |
1226 | .start = sd_start, | |
1227 | .stopN = sd_stopN, | |
1228 | .pkt_scan = sd_pkt_scan, | |
1229 | }; | |
1230 | ||
1231 | /* -- module initialisation -- */ | |
95c967c1 | 1232 | static const struct usb_device_id device_table[] = { |
8ac246cb | 1233 | {USB_DEVICE(0x08ca, 0x0110)}, /* Trust Spyc@m 100 */ |
89f0863c TK |
1234 | {USB_DEVICE(0x08ca, 0x0111)}, /* Aiptek Pencam VGA+ */ |
1235 | {USB_DEVICE(0x093a, 0x010f)}, /* All other known MR97310A VGA cams */ | |
1236 | {USB_DEVICE(0x093a, 0x010e)}, /* All known MR97310A CIF cams */ | |
d661e622 KG |
1237 | {} |
1238 | }; | |
1239 | MODULE_DEVICE_TABLE(usb, device_table); | |
1240 | ||
1241 | /* -- device connect -- */ | |
1242 | static int sd_probe(struct usb_interface *intf, | |
1243 | const struct usb_device_id *id) | |
1244 | { | |
1245 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), | |
1246 | THIS_MODULE); | |
1247 | } | |
1248 | ||
1249 | static struct usb_driver sd_driver = { | |
1250 | .name = MODULE_NAME, | |
1251 | .id_table = device_table, | |
1252 | .probe = sd_probe, | |
1253 | .disconnect = gspca_disconnect, | |
1254 | #ifdef CONFIG_PM | |
1255 | .suspend = gspca_suspend, | |
1256 | .resume = gspca_resume, | |
1257 | #endif | |
1258 | }; | |
1259 | ||
1260 | /* -- module insert / remove -- */ | |
1261 | static int __init sd_mod_init(void) | |
1262 | { | |
54826437 | 1263 | return usb_register(&sd_driver); |
d661e622 KG |
1264 | } |
1265 | static void __exit sd_mod_exit(void) | |
1266 | { | |
1267 | usb_deregister(&sd_driver); | |
d661e622 KG |
1268 | } |
1269 | ||
1270 | module_init(sd_mod_init); | |
1271 | module_exit(sd_mod_exit); |