diff options
Diffstat (limited to 'drivers/media/usb/gspca/ov534.c')
-rw-r--r-- | drivers/media/usb/gspca/ov534.c | 1544 |
1 files changed, 1544 insertions, 0 deletions
diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c new file mode 100644 index 000000000000..bb09d7884b89 --- /dev/null +++ b/drivers/media/usb/gspca/ov534.c | |||
@@ -0,0 +1,1544 @@ | |||
1 | /* | ||
2 | * ov534-ov7xxx gspca driver | ||
3 | * | ||
4 | * Copyright (C) 2008 Antonio Ospite <ospite@studenti.unina.it> | ||
5 | * Copyright (C) 2008 Jim Paris <jim@jtan.com> | ||
6 | * Copyright (C) 2009 Jean-Francois Moine http://moinejf.free.fr | ||
7 | * | ||
8 | * Based on a prototype written by Mark Ferrell <majortrips@gmail.com> | ||
9 | * USB protocol reverse engineered by Jim Paris <jim@jtan.com> | ||
10 | * https://jim.sh/svn/jim/devl/playstation/ps3/eye/test/ | ||
11 | * | ||
12 | * PS3 Eye camera enhanced by Richard Kaswy http://kaswy.free.fr | ||
13 | * PS3 Eye camera - brightness, contrast, awb, agc, aec controls | ||
14 | * added by Max Thrun <bear24rw@gmail.com> | ||
15 | * | ||
16 | * This program is free software; you can redistribute it and/or modify | ||
17 | * it under the terms of the GNU General Public License as published by | ||
18 | * the Free Software Foundation; either version 2 of the License, or | ||
19 | * any later version. | ||
20 | * | ||
21 | * This program is distributed in the hope that it will be useful, | ||
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
24 | * GNU General Public License for more details. | ||
25 | * | ||
26 | * You should have received a copy of the GNU General Public License | ||
27 | * along with this program; if not, write to the Free Software | ||
28 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
29 | */ | ||
30 | |||
31 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | ||
32 | |||
33 | #define MODULE_NAME "ov534" | ||
34 | |||
35 | #include "gspca.h" | ||
36 | |||
37 | #include <linux/fixp-arith.h> | ||
38 | #include <media/v4l2-ctrls.h> | ||
39 | |||
40 | #define OV534_REG_ADDRESS 0xf1 /* sensor address */ | ||
41 | #define OV534_REG_SUBADDR 0xf2 | ||
42 | #define OV534_REG_WRITE 0xf3 | ||
43 | #define OV534_REG_READ 0xf4 | ||
44 | #define OV534_REG_OPERATION 0xf5 | ||
45 | #define OV534_REG_STATUS 0xf6 | ||
46 | |||
47 | #define OV534_OP_WRITE_3 0x37 | ||
48 | #define OV534_OP_WRITE_2 0x33 | ||
49 | #define OV534_OP_READ_2 0xf9 | ||
50 | |||
51 | #define CTRL_TIMEOUT 500 | ||
52 | |||
53 | MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>"); | ||
54 | MODULE_DESCRIPTION("GSPCA/OV534 USB Camera Driver"); | ||
55 | MODULE_LICENSE("GPL"); | ||
56 | |||
57 | /* specific webcam descriptor */ | ||
58 | struct sd { | ||
59 | struct gspca_dev gspca_dev; /* !! must be the first item */ | ||
60 | |||
61 | struct v4l2_ctrl_handler ctrl_handler; | ||
62 | struct v4l2_ctrl *hue; | ||
63 | struct v4l2_ctrl *saturation; | ||
64 | struct v4l2_ctrl *brightness; | ||
65 | struct v4l2_ctrl *contrast; | ||
66 | struct { /* gain control cluster */ | ||
67 | struct v4l2_ctrl *autogain; | ||
68 | struct v4l2_ctrl *gain; | ||
69 | }; | ||
70 | struct v4l2_ctrl *autowhitebalance; | ||
71 | struct { /* exposure control cluster */ | ||
72 | struct v4l2_ctrl *autoexposure; | ||
73 | struct v4l2_ctrl *exposure; | ||
74 | }; | ||
75 | struct v4l2_ctrl *sharpness; | ||
76 | struct v4l2_ctrl *hflip; | ||
77 | struct v4l2_ctrl *vflip; | ||
78 | struct v4l2_ctrl *plfreq; | ||
79 | |||
80 | __u32 last_pts; | ||
81 | u16 last_fid; | ||
82 | u8 frame_rate; | ||
83 | |||
84 | u8 sensor; | ||
85 | }; | ||
86 | enum sensors { | ||
87 | SENSOR_OV767x, | ||
88 | SENSOR_OV772x, | ||
89 | NSENSORS | ||
90 | }; | ||
91 | |||
92 | static int sd_start(struct gspca_dev *gspca_dev); | ||
93 | static void sd_stopN(struct gspca_dev *gspca_dev); | ||
94 | |||
95 | |||
96 | static const struct v4l2_pix_format ov772x_mode[] = { | ||
97 | {320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, | ||
98 | .bytesperline = 320 * 2, | ||
99 | .sizeimage = 320 * 240 * 2, | ||
100 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
101 | .priv = 1}, | ||
102 | {640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE, | ||
103 | .bytesperline = 640 * 2, | ||
104 | .sizeimage = 640 * 480 * 2, | ||
105 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
106 | .priv = 0}, | ||
107 | }; | ||
108 | static const struct v4l2_pix_format ov767x_mode[] = { | ||
109 | {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, | ||
110 | .bytesperline = 320, | ||
111 | .sizeimage = 320 * 240 * 3 / 8 + 590, | ||
112 | .colorspace = V4L2_COLORSPACE_JPEG}, | ||
113 | {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE, | ||
114 | .bytesperline = 640, | ||
115 | .sizeimage = 640 * 480 * 3 / 8 + 590, | ||
116 | .colorspace = V4L2_COLORSPACE_JPEG}, | ||
117 | }; | ||
118 | |||
119 | static const u8 qvga_rates[] = {125, 100, 75, 60, 50, 40, 30}; | ||
120 | static const u8 vga_rates[] = {60, 50, 40, 30, 15}; | ||
121 | |||
122 | static const struct framerates ov772x_framerates[] = { | ||
123 | { /* 320x240 */ | ||
124 | .rates = qvga_rates, | ||
125 | .nrates = ARRAY_SIZE(qvga_rates), | ||
126 | }, | ||
127 | { /* 640x480 */ | ||
128 | .rates = vga_rates, | ||
129 | .nrates = ARRAY_SIZE(vga_rates), | ||
130 | }, | ||
131 | }; | ||
132 | |||
133 | struct reg_array { | ||
134 | const u8 (*val)[2]; | ||
135 | int len; | ||
136 | }; | ||
137 | |||
138 | static const u8 bridge_init_767x[][2] = { | ||
139 | /* comments from the ms-win file apollo7670.set */ | ||
140 | /* str1 */ | ||
141 | {0xf1, 0x42}, | ||
142 | {0x88, 0xf8}, | ||
143 | {0x89, 0xff}, | ||
144 | {0x76, 0x03}, | ||
145 | {0x92, 0x03}, | ||
146 | {0x95, 0x10}, | ||
147 | {0xe2, 0x00}, | ||
148 | {0xe7, 0x3e}, | ||
149 | {0x8d, 0x1c}, | ||
150 | {0x8e, 0x00}, | ||
151 | {0x8f, 0x00}, | ||
152 | {0x1f, 0x00}, | ||
153 | {0xc3, 0xf9}, | ||
154 | {0x89, 0xff}, | ||
155 | {0x88, 0xf8}, | ||
156 | {0x76, 0x03}, | ||
157 | {0x92, 0x01}, | ||
158 | {0x93, 0x18}, | ||
159 | {0x1c, 0x00}, | ||
160 | {0x1d, 0x48}, | ||
161 | {0x1d, 0x00}, | ||
162 | {0x1d, 0xff}, | ||
163 | {0x1d, 0x02}, | ||
164 | {0x1d, 0x58}, | ||
165 | {0x1d, 0x00}, | ||
166 | {0x1c, 0x0a}, | ||
167 | {0x1d, 0x0a}, | ||
168 | {0x1d, 0x0e}, | ||
169 | {0xc0, 0x50}, /* HSize 640 */ | ||
170 | {0xc1, 0x3c}, /* VSize 480 */ | ||
171 | {0x34, 0x05}, /* enable Audio Suspend mode */ | ||
172 | {0xc2, 0x0c}, /* Input YUV */ | ||
173 | {0xc3, 0xf9}, /* enable PRE */ | ||
174 | {0x34, 0x05}, /* enable Audio Suspend mode */ | ||
175 | {0xe7, 0x2e}, /* this solves failure of "SuspendResumeTest" */ | ||
176 | {0x31, 0xf9}, /* enable 1.8V Suspend */ | ||
177 | {0x35, 0x02}, /* turn on JPEG */ | ||
178 | {0xd9, 0x10}, | ||
179 | {0x25, 0x42}, /* GPIO[8]:Input */ | ||
180 | {0x94, 0x11}, /* If the default setting is loaded when | ||
181 | * system boots up, this flag is closed here */ | ||
182 | }; | ||
183 | static const u8 sensor_init_767x[][2] = { | ||
184 | {0x12, 0x80}, | ||
185 | {0x11, 0x03}, | ||
186 | {0x3a, 0x04}, | ||
187 | {0x12, 0x00}, | ||
188 | {0x17, 0x13}, | ||
189 | {0x18, 0x01}, | ||
190 | {0x32, 0xb6}, | ||
191 | {0x19, 0x02}, | ||
192 | {0x1a, 0x7a}, | ||
193 | {0x03, 0x0a}, | ||
194 | {0x0c, 0x00}, | ||
195 | {0x3e, 0x00}, | ||
196 | {0x70, 0x3a}, | ||
197 | {0x71, 0x35}, | ||
198 | {0x72, 0x11}, | ||
199 | {0x73, 0xf0}, | ||
200 | {0xa2, 0x02}, | ||
201 | {0x7a, 0x2a}, /* set Gamma=1.6 below */ | ||
202 | {0x7b, 0x12}, | ||
203 | {0x7c, 0x1d}, | ||
204 | {0x7d, 0x2d}, | ||
205 | {0x7e, 0x45}, | ||
206 | {0x7f, 0x50}, | ||
207 | {0x80, 0x59}, | ||
208 | {0x81, 0x62}, | ||
209 | {0x82, 0x6b}, | ||
210 | {0x83, 0x73}, | ||
211 | {0x84, 0x7b}, | ||
212 | {0x85, 0x8a}, | ||
213 | {0x86, 0x98}, | ||
214 | {0x87, 0xb2}, | ||
215 | {0x88, 0xca}, | ||
216 | {0x89, 0xe0}, | ||
217 | {0x13, 0xe0}, | ||
218 | {0x00, 0x00}, | ||
219 | {0x10, 0x00}, | ||
220 | {0x0d, 0x40}, | ||
221 | {0x14, 0x38}, /* gain max 16x */ | ||
222 | {0xa5, 0x05}, | ||
223 | {0xab, 0x07}, | ||
224 | {0x24, 0x95}, | ||
225 | {0x25, 0x33}, | ||
226 | {0x26, 0xe3}, | ||
227 | {0x9f, 0x78}, | ||
228 | {0xa0, 0x68}, | ||
229 | {0xa1, 0x03}, | ||
230 | {0xa6, 0xd8}, | ||
231 | {0xa7, 0xd8}, | ||
232 | {0xa8, 0xf0}, | ||
233 | {0xa9, 0x90}, | ||
234 | {0xaa, 0x94}, | ||
235 | {0x13, 0xe5}, | ||
236 | {0x0e, 0x61}, | ||
237 | {0x0f, 0x4b}, | ||
238 | {0x16, 0x02}, | ||
239 | {0x21, 0x02}, | ||
240 | {0x22, 0x91}, | ||
241 | {0x29, 0x07}, | ||
242 | {0x33, 0x0b}, | ||
243 | {0x35, 0x0b}, | ||
244 | {0x37, 0x1d}, | ||
245 | {0x38, 0x71}, | ||
246 | {0x39, 0x2a}, | ||
247 | {0x3c, 0x78}, | ||
248 | {0x4d, 0x40}, | ||
249 | {0x4e, 0x20}, | ||
250 | {0x69, 0x00}, | ||
251 | {0x6b, 0x4a}, | ||
252 | {0x74, 0x10}, | ||
253 | {0x8d, 0x4f}, | ||
254 | {0x8e, 0x00}, | ||
255 | {0x8f, 0x00}, | ||
256 | {0x90, 0x00}, | ||
257 | {0x91, 0x00}, | ||
258 | {0x96, 0x00}, | ||
259 | {0x9a, 0x80}, | ||
260 | {0xb0, 0x84}, | ||
261 | {0xb1, 0x0c}, | ||
262 | {0xb2, 0x0e}, | ||
263 | {0xb3, 0x82}, | ||
264 | {0xb8, 0x0a}, | ||
265 | {0x43, 0x0a}, | ||
266 | {0x44, 0xf0}, | ||
267 | {0x45, 0x34}, | ||
268 | {0x46, 0x58}, | ||
269 | {0x47, 0x28}, | ||
270 | {0x48, 0x3a}, | ||
271 | {0x59, 0x88}, | ||
272 | {0x5a, 0x88}, | ||
273 | {0x5b, 0x44}, | ||
274 | {0x5c, 0x67}, | ||
275 | {0x5d, 0x49}, | ||
276 | {0x5e, 0x0e}, | ||
277 | {0x6c, 0x0a}, | ||
278 | {0x6d, 0x55}, | ||
279 | {0x6e, 0x11}, | ||
280 | {0x6f, 0x9f}, | ||
281 | {0x6a, 0x40}, | ||
282 | {0x01, 0x40}, | ||
283 | {0x02, 0x40}, | ||
284 | {0x13, 0xe7}, | ||
285 | {0x4f, 0x80}, | ||
286 | {0x50, 0x80}, | ||
287 | {0x51, 0x00}, | ||
288 | {0x52, 0x22}, | ||
289 | {0x53, 0x5e}, | ||
290 | {0x54, 0x80}, | ||
291 | {0x58, 0x9e}, | ||
292 | {0x41, 0x08}, | ||
293 | {0x3f, 0x00}, | ||
294 | {0x75, 0x04}, | ||
295 | {0x76, 0xe1}, | ||
296 | {0x4c, 0x00}, | ||
297 | {0x77, 0x01}, | ||
298 | {0x3d, 0xc2}, | ||
299 | {0x4b, 0x09}, | ||
300 | {0xc9, 0x60}, | ||
301 | {0x41, 0x38}, /* jfm: auto sharpness + auto de-noise */ | ||
302 | {0x56, 0x40}, | ||
303 | {0x34, 0x11}, | ||
304 | {0x3b, 0xc2}, | ||
305 | {0xa4, 0x8a}, /* Night mode trigger point */ | ||
306 | {0x96, 0x00}, | ||
307 | {0x97, 0x30}, | ||
308 | {0x98, 0x20}, | ||
309 | {0x99, 0x20}, | ||
310 | {0x9a, 0x84}, | ||
311 | {0x9b, 0x29}, | ||
312 | {0x9c, 0x03}, | ||
313 | {0x9d, 0x4c}, | ||
314 | {0x9e, 0x3f}, | ||
315 | {0x78, 0x04}, | ||
316 | {0x79, 0x01}, | ||
317 | {0xc8, 0xf0}, | ||
318 | {0x79, 0x0f}, | ||
319 | {0xc8, 0x00}, | ||
320 | {0x79, 0x10}, | ||
321 | {0xc8, 0x7e}, | ||
322 | {0x79, 0x0a}, | ||
323 | {0xc8, 0x80}, | ||
324 | {0x79, 0x0b}, | ||
325 | {0xc8, 0x01}, | ||
326 | {0x79, 0x0c}, | ||
327 | {0xc8, 0x0f}, | ||
328 | {0x79, 0x0d}, | ||
329 | {0xc8, 0x20}, | ||
330 | {0x79, 0x09}, | ||
331 | {0xc8, 0x80}, | ||
332 | {0x79, 0x02}, | ||
333 | {0xc8, 0xc0}, | ||
334 | {0x79, 0x03}, | ||
335 | {0xc8, 0x20}, | ||
336 | {0x79, 0x26}, | ||
337 | }; | ||
338 | static const u8 bridge_start_vga_767x[][2] = { | ||
339 | /* str59 JPG */ | ||
340 | {0x94, 0xaa}, | ||
341 | {0xf1, 0x42}, | ||
342 | {0xe5, 0x04}, | ||
343 | {0xc0, 0x50}, | ||
344 | {0xc1, 0x3c}, | ||
345 | {0xc2, 0x0c}, | ||
346 | {0x35, 0x02}, /* turn on JPEG */ | ||
347 | {0xd9, 0x10}, | ||
348 | {0xda, 0x00}, /* for higher clock rate(30fps) */ | ||
349 | {0x34, 0x05}, /* enable Audio Suspend mode */ | ||
350 | {0xc3, 0xf9}, /* enable PRE */ | ||
351 | {0x8c, 0x00}, /* CIF VSize LSB[2:0] */ | ||
352 | {0x8d, 0x1c}, /* output YUV */ | ||
353 | /* {0x34, 0x05}, * enable Audio Suspend mode (?) */ | ||
354 | {0x50, 0x00}, /* H/V divider=0 */ | ||
355 | {0x51, 0xa0}, /* input H=640/4 */ | ||
356 | {0x52, 0x3c}, /* input V=480/4 */ | ||
357 | {0x53, 0x00}, /* offset X=0 */ | ||
358 | {0x54, 0x00}, /* offset Y=0 */ | ||
359 | {0x55, 0x00}, /* H/V size[8]=0 */ | ||
360 | {0x57, 0x00}, /* H-size[9]=0 */ | ||
361 | {0x5c, 0x00}, /* output size[9:8]=0 */ | ||
362 | {0x5a, 0xa0}, /* output H=640/4 */ | ||
363 | {0x5b, 0x78}, /* output V=480/4 */ | ||
364 | {0x1c, 0x0a}, | ||
365 | {0x1d, 0x0a}, | ||
366 | {0x94, 0x11}, | ||
367 | }; | ||
368 | static const u8 sensor_start_vga_767x[][2] = { | ||
369 | {0x11, 0x01}, | ||
370 | {0x1e, 0x04}, | ||
371 | {0x19, 0x02}, | ||
372 | {0x1a, 0x7a}, | ||
373 | }; | ||
374 | static const u8 bridge_start_qvga_767x[][2] = { | ||
375 | /* str86 JPG */ | ||
376 | {0x94, 0xaa}, | ||
377 | {0xf1, 0x42}, | ||
378 | {0xe5, 0x04}, | ||
379 | {0xc0, 0x80}, | ||
380 | {0xc1, 0x60}, | ||
381 | {0xc2, 0x0c}, | ||
382 | {0x35, 0x02}, /* turn on JPEG */ | ||
383 | {0xd9, 0x10}, | ||
384 | {0xc0, 0x50}, /* CIF HSize 640 */ | ||
385 | {0xc1, 0x3c}, /* CIF VSize 480 */ | ||
386 | {0x8c, 0x00}, /* CIF VSize LSB[2:0] */ | ||
387 | {0x8d, 0x1c}, /* output YUV */ | ||
388 | {0x34, 0x05}, /* enable Audio Suspend mode */ | ||
389 | {0xc2, 0x4c}, /* output YUV and Enable DCW */ | ||
390 | {0xc3, 0xf9}, /* enable PRE */ | ||
391 | {0x1c, 0x00}, /* indirect addressing */ | ||
392 | {0x1d, 0x48}, /* output YUV422 */ | ||
393 | {0x50, 0x89}, /* H/V divider=/2; plus DCW AVG */ | ||
394 | {0x51, 0xa0}, /* DCW input H=640/4 */ | ||
395 | {0x52, 0x78}, /* DCW input V=480/4 */ | ||
396 | {0x53, 0x00}, /* offset X=0 */ | ||
397 | {0x54, 0x00}, /* offset Y=0 */ | ||
398 | {0x55, 0x00}, /* H/V size[8]=0 */ | ||
399 | {0x57, 0x00}, /* H-size[9]=0 */ | ||
400 | {0x5c, 0x00}, /* DCW output size[9:8]=0 */ | ||
401 | {0x5a, 0x50}, /* DCW output H=320/4 */ | ||
402 | {0x5b, 0x3c}, /* DCW output V=240/4 */ | ||
403 | {0x1c, 0x0a}, | ||
404 | {0x1d, 0x0a}, | ||
405 | {0x94, 0x11}, | ||
406 | }; | ||
407 | static const u8 sensor_start_qvga_767x[][2] = { | ||
408 | {0x11, 0x01}, | ||
409 | {0x1e, 0x04}, | ||
410 | {0x19, 0x02}, | ||
411 | {0x1a, 0x7a}, | ||
412 | }; | ||
413 | |||
414 | static const u8 bridge_init_772x[][2] = { | ||
415 | { 0xc2, 0x0c }, | ||
416 | { 0x88, 0xf8 }, | ||
417 | { 0xc3, 0x69 }, | ||
418 | { 0x89, 0xff }, | ||
419 | { 0x76, 0x03 }, | ||
420 | { 0x92, 0x01 }, | ||
421 | { 0x93, 0x18 }, | ||
422 | { 0x94, 0x10 }, | ||
423 | { 0x95, 0x10 }, | ||
424 | { 0xe2, 0x00 }, | ||
425 | { 0xe7, 0x3e }, | ||
426 | |||
427 | { 0x96, 0x00 }, | ||
428 | |||
429 | { 0x97, 0x20 }, | ||
430 | { 0x97, 0x20 }, | ||
431 | { 0x97, 0x20 }, | ||
432 | { 0x97, 0x0a }, | ||
433 | { 0x97, 0x3f }, | ||
434 | { 0x97, 0x4a }, | ||
435 | { 0x97, 0x20 }, | ||
436 | { 0x97, 0x15 }, | ||
437 | { 0x97, 0x0b }, | ||
438 | |||
439 | { 0x8e, 0x40 }, | ||
440 | { 0x1f, 0x81 }, | ||
441 | { 0x34, 0x05 }, | ||
442 | { 0xe3, 0x04 }, | ||
443 | { 0x88, 0x00 }, | ||
444 | { 0x89, 0x00 }, | ||
445 | { 0x76, 0x00 }, | ||
446 | { 0xe7, 0x2e }, | ||
447 | { 0x31, 0xf9 }, | ||
448 | { 0x25, 0x42 }, | ||
449 | { 0x21, 0xf0 }, | ||
450 | |||
451 | { 0x1c, 0x00 }, | ||
452 | { 0x1d, 0x40 }, | ||
453 | { 0x1d, 0x02 }, /* payload size 0x0200 * 4 = 2048 bytes */ | ||
454 | { 0x1d, 0x00 }, /* payload size */ | ||
455 | |||
456 | { 0x1d, 0x02 }, /* frame size 0x025800 * 4 = 614400 */ | ||
457 | { 0x1d, 0x58 }, /* frame size */ | ||
458 | { 0x1d, 0x00 }, /* frame size */ | ||
459 | |||
460 | { 0x1c, 0x0a }, | ||
461 | { 0x1d, 0x08 }, /* turn on UVC header */ | ||
462 | { 0x1d, 0x0e }, /* .. */ | ||
463 | |||
464 | { 0x8d, 0x1c }, | ||
465 | { 0x8e, 0x80 }, | ||
466 | { 0xe5, 0x04 }, | ||
467 | |||
468 | { 0xc0, 0x50 }, | ||
469 | { 0xc1, 0x3c }, | ||
470 | { 0xc2, 0x0c }, | ||
471 | }; | ||
472 | static const u8 sensor_init_772x[][2] = { | ||
473 | { 0x12, 0x80 }, | ||
474 | { 0x11, 0x01 }, | ||
475 | /*fixme: better have a delay?*/ | ||
476 | { 0x11, 0x01 }, | ||
477 | { 0x11, 0x01 }, | ||
478 | { 0x11, 0x01 }, | ||
479 | { 0x11, 0x01 }, | ||
480 | { 0x11, 0x01 }, | ||
481 | { 0x11, 0x01 }, | ||
482 | { 0x11, 0x01 }, | ||
483 | { 0x11, 0x01 }, | ||
484 | { 0x11, 0x01 }, | ||
485 | { 0x11, 0x01 }, | ||
486 | |||
487 | { 0x3d, 0x03 }, | ||
488 | { 0x17, 0x26 }, | ||
489 | { 0x18, 0xa0 }, | ||
490 | { 0x19, 0x07 }, | ||
491 | { 0x1a, 0xf0 }, | ||
492 | { 0x32, 0x00 }, | ||
493 | { 0x29, 0xa0 }, | ||
494 | { 0x2c, 0xf0 }, | ||
495 | { 0x65, 0x20 }, | ||
496 | { 0x11, 0x01 }, | ||
497 | { 0x42, 0x7f }, | ||
498 | { 0x63, 0xaa }, /* AWB - was e0 */ | ||
499 | { 0x64, 0xff }, | ||
500 | { 0x66, 0x00 }, | ||
501 | { 0x13, 0xf0 }, /* com8 */ | ||
502 | { 0x0d, 0x41 }, | ||
503 | { 0x0f, 0xc5 }, | ||
504 | { 0x14, 0x11 }, | ||
505 | |||
506 | { 0x22, 0x7f }, | ||
507 | { 0x23, 0x03 }, | ||
508 | { 0x24, 0x40 }, | ||
509 | { 0x25, 0x30 }, | ||
510 | { 0x26, 0xa1 }, | ||
511 | { 0x2a, 0x00 }, | ||
512 | { 0x2b, 0x00 }, | ||
513 | { 0x6b, 0xaa }, | ||
514 | { 0x13, 0xff }, /* AWB */ | ||
515 | |||
516 | { 0x90, 0x05 }, | ||
517 | { 0x91, 0x01 }, | ||
518 | { 0x92, 0x03 }, | ||
519 | { 0x93, 0x00 }, | ||
520 | { 0x94, 0x60 }, | ||
521 | { 0x95, 0x3c }, | ||
522 | { 0x96, 0x24 }, | ||
523 | { 0x97, 0x1e }, | ||
524 | { 0x98, 0x62 }, | ||
525 | { 0x99, 0x80 }, | ||
526 | { 0x9a, 0x1e }, | ||
527 | { 0x9b, 0x08 }, | ||
528 | { 0x9c, 0x20 }, | ||
529 | { 0x9e, 0x81 }, | ||
530 | |||
531 | { 0xa6, 0x07 }, | ||
532 | { 0x7e, 0x0c }, | ||
533 | { 0x7f, 0x16 }, | ||
534 | { 0x80, 0x2a }, | ||
535 | { 0x81, 0x4e }, | ||
536 | { 0x82, 0x61 }, | ||
537 | { 0x83, 0x6f }, | ||
538 | { 0x84, 0x7b }, | ||
539 | { 0x85, 0x86 }, | ||
540 | { 0x86, 0x8e }, | ||
541 | { 0x87, 0x97 }, | ||
542 | { 0x88, 0xa4 }, | ||
543 | { 0x89, 0xaf }, | ||
544 | { 0x8a, 0xc5 }, | ||
545 | { 0x8b, 0xd7 }, | ||
546 | { 0x8c, 0xe8 }, | ||
547 | { 0x8d, 0x20 }, | ||
548 | |||
549 | { 0x0c, 0x90 }, | ||
550 | |||
551 | { 0x2b, 0x00 }, | ||
552 | { 0x22, 0x7f }, | ||
553 | { 0x23, 0x03 }, | ||
554 | { 0x11, 0x01 }, | ||
555 | { 0x0c, 0xd0 }, | ||
556 | { 0x64, 0xff }, | ||
557 | { 0x0d, 0x41 }, | ||
558 | |||
559 | { 0x14, 0x41 }, | ||
560 | { 0x0e, 0xcd }, | ||
561 | { 0xac, 0xbf }, | ||
562 | { 0x8e, 0x00 }, /* De-noise threshold */ | ||
563 | { 0x0c, 0xd0 } | ||
564 | }; | ||
565 | static const u8 bridge_start_vga_772x[][2] = { | ||
566 | {0x1c, 0x00}, | ||
567 | {0x1d, 0x40}, | ||
568 | {0x1d, 0x02}, | ||
569 | {0x1d, 0x00}, | ||
570 | {0x1d, 0x02}, | ||
571 | {0x1d, 0x58}, | ||
572 | {0x1d, 0x00}, | ||
573 | {0xc0, 0x50}, | ||
574 | {0xc1, 0x3c}, | ||
575 | }; | ||
576 | static const u8 sensor_start_vga_772x[][2] = { | ||
577 | {0x12, 0x00}, | ||
578 | {0x17, 0x26}, | ||
579 | {0x18, 0xa0}, | ||
580 | {0x19, 0x07}, | ||
581 | {0x1a, 0xf0}, | ||
582 | {0x29, 0xa0}, | ||
583 | {0x2c, 0xf0}, | ||
584 | {0x65, 0x20}, | ||
585 | }; | ||
586 | static const u8 bridge_start_qvga_772x[][2] = { | ||
587 | {0x1c, 0x00}, | ||
588 | {0x1d, 0x40}, | ||
589 | {0x1d, 0x02}, | ||
590 | {0x1d, 0x00}, | ||
591 | {0x1d, 0x01}, | ||
592 | {0x1d, 0x4b}, | ||
593 | {0x1d, 0x00}, | ||
594 | {0xc0, 0x28}, | ||
595 | {0xc1, 0x1e}, | ||
596 | }; | ||
597 | static const u8 sensor_start_qvga_772x[][2] = { | ||
598 | {0x12, 0x40}, | ||
599 | {0x17, 0x3f}, | ||
600 | {0x18, 0x50}, | ||
601 | {0x19, 0x03}, | ||
602 | {0x1a, 0x78}, | ||
603 | {0x29, 0x50}, | ||
604 | {0x2c, 0x78}, | ||
605 | {0x65, 0x2f}, | ||
606 | }; | ||
607 | |||
608 | static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val) | ||
609 | { | ||
610 | struct usb_device *udev = gspca_dev->dev; | ||
611 | int ret; | ||
612 | |||
613 | if (gspca_dev->usb_err < 0) | ||
614 | return; | ||
615 | |||
616 | PDEBUG(D_USBO, "SET 01 0000 %04x %02x", reg, val); | ||
617 | gspca_dev->usb_buf[0] = val; | ||
618 | ret = usb_control_msg(udev, | ||
619 | usb_sndctrlpipe(udev, 0), | ||
620 | 0x01, | ||
621 | USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
622 | 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); | ||
623 | if (ret < 0) { | ||
624 | pr_err("write failed %d\n", ret); | ||
625 | gspca_dev->usb_err = ret; | ||
626 | } | ||
627 | } | ||
628 | |||
629 | static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg) | ||
630 | { | ||
631 | struct usb_device *udev = gspca_dev->dev; | ||
632 | int ret; | ||
633 | |||
634 | if (gspca_dev->usb_err < 0) | ||
635 | return 0; | ||
636 | ret = usb_control_msg(udev, | ||
637 | usb_rcvctrlpipe(udev, 0), | ||
638 | 0x01, | ||
639 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, | ||
640 | 0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT); | ||
641 | PDEBUG(D_USBI, "GET 01 0000 %04x %02x", reg, gspca_dev->usb_buf[0]); | ||
642 | if (ret < 0) { | ||
643 | pr_err("read failed %d\n", ret); | ||
644 | gspca_dev->usb_err = ret; | ||
645 | } | ||
646 | return gspca_dev->usb_buf[0]; | ||
647 | } | ||
648 | |||
649 | /* Two bits control LED: 0x21 bit 7 and 0x23 bit 7. | ||
650 | * (direction and output)? */ | ||
651 | static void ov534_set_led(struct gspca_dev *gspca_dev, int status) | ||
652 | { | ||
653 | u8 data; | ||
654 | |||
655 | PDEBUG(D_CONF, "led status: %d", status); | ||
656 | |||
657 | data = ov534_reg_read(gspca_dev, 0x21); | ||
658 | data |= 0x80; | ||
659 | ov534_reg_write(gspca_dev, 0x21, data); | ||
660 | |||
661 | data = ov534_reg_read(gspca_dev, 0x23); | ||
662 | if (status) | ||
663 | data |= 0x80; | ||
664 | else | ||
665 | data &= ~0x80; | ||
666 | |||
667 | ov534_reg_write(gspca_dev, 0x23, data); | ||
668 | |||
669 | if (!status) { | ||
670 | data = ov534_reg_read(gspca_dev, 0x21); | ||
671 | data &= ~0x80; | ||
672 | ov534_reg_write(gspca_dev, 0x21, data); | ||
673 | } | ||
674 | } | ||
675 | |||
676 | static int sccb_check_status(struct gspca_dev *gspca_dev) | ||
677 | { | ||
678 | u8 data; | ||
679 | int i; | ||
680 | |||
681 | for (i = 0; i < 5; i++) { | ||
682 | msleep(10); | ||
683 | data = ov534_reg_read(gspca_dev, OV534_REG_STATUS); | ||
684 | |||
685 | switch (data) { | ||
686 | case 0x00: | ||
687 | return 1; | ||
688 | case 0x04: | ||
689 | return 0; | ||
690 | case 0x03: | ||
691 | break; | ||
692 | default: | ||
693 | PDEBUG(D_ERR, "sccb status 0x%02x, attempt %d/5", | ||
694 | data, i + 1); | ||
695 | } | ||
696 | } | ||
697 | return 0; | ||
698 | } | ||
699 | |||
700 | static void sccb_reg_write(struct gspca_dev *gspca_dev, u8 reg, u8 val) | ||
701 | { | ||
702 | PDEBUG(D_USBO, "sccb write: %02x %02x", reg, val); | ||
703 | ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg); | ||
704 | ov534_reg_write(gspca_dev, OV534_REG_WRITE, val); | ||
705 | ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3); | ||
706 | |||
707 | if (!sccb_check_status(gspca_dev)) { | ||
708 | pr_err("sccb_reg_write failed\n"); | ||
709 | gspca_dev->usb_err = -EIO; | ||
710 | } | ||
711 | } | ||
712 | |||
713 | static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg) | ||
714 | { | ||
715 | ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg); | ||
716 | ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2); | ||
717 | if (!sccb_check_status(gspca_dev)) | ||
718 | pr_err("sccb_reg_read failed 1\n"); | ||
719 | |||
720 | ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2); | ||
721 | if (!sccb_check_status(gspca_dev)) | ||
722 | pr_err("sccb_reg_read failed 2\n"); | ||
723 | |||
724 | return ov534_reg_read(gspca_dev, OV534_REG_READ); | ||
725 | } | ||
726 | |||
727 | /* output a bridge sequence (reg - val) */ | ||
728 | static void reg_w_array(struct gspca_dev *gspca_dev, | ||
729 | const u8 (*data)[2], int len) | ||
730 | { | ||
731 | while (--len >= 0) { | ||
732 | ov534_reg_write(gspca_dev, (*data)[0], (*data)[1]); | ||
733 | data++; | ||
734 | } | ||
735 | } | ||
736 | |||
737 | /* output a sensor sequence (reg - val) */ | ||
738 | static void sccb_w_array(struct gspca_dev *gspca_dev, | ||
739 | const u8 (*data)[2], int len) | ||
740 | { | ||
741 | while (--len >= 0) { | ||
742 | if ((*data)[0] != 0xff) { | ||
743 | sccb_reg_write(gspca_dev, (*data)[0], (*data)[1]); | ||
744 | } else { | ||
745 | sccb_reg_read(gspca_dev, (*data)[1]); | ||
746 | sccb_reg_write(gspca_dev, 0xff, 0x00); | ||
747 | } | ||
748 | data++; | ||
749 | } | ||
750 | } | ||
751 | |||
752 | /* ov772x specific controls */ | ||
753 | static void set_frame_rate(struct gspca_dev *gspca_dev) | ||
754 | { | ||
755 | struct sd *sd = (struct sd *) gspca_dev; | ||
756 | int i; | ||
757 | struct rate_s { | ||
758 | u8 fps; | ||
759 | u8 r11; | ||
760 | u8 r0d; | ||
761 | u8 re5; | ||
762 | }; | ||
763 | const struct rate_s *r; | ||
764 | static const struct rate_s rate_0[] = { /* 640x480 */ | ||
765 | {60, 0x01, 0xc1, 0x04}, | ||
766 | {50, 0x01, 0x41, 0x02}, | ||
767 | {40, 0x02, 0xc1, 0x04}, | ||
768 | {30, 0x04, 0x81, 0x02}, | ||
769 | {15, 0x03, 0x41, 0x04}, | ||
770 | }; | ||
771 | static const struct rate_s rate_1[] = { /* 320x240 */ | ||
772 | {125, 0x02, 0x81, 0x02}, | ||
773 | {100, 0x02, 0xc1, 0x04}, | ||
774 | {75, 0x03, 0xc1, 0x04}, | ||
775 | {60, 0x04, 0xc1, 0x04}, | ||
776 | {50, 0x02, 0x41, 0x04}, | ||
777 | {40, 0x03, 0x41, 0x04}, | ||
778 | {30, 0x04, 0x41, 0x04}, | ||
779 | }; | ||
780 | |||
781 | if (sd->sensor != SENSOR_OV772x) | ||
782 | return; | ||
783 | if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv == 0) { | ||
784 | r = rate_0; | ||
785 | i = ARRAY_SIZE(rate_0); | ||
786 | } else { | ||
787 | r = rate_1; | ||
788 | i = ARRAY_SIZE(rate_1); | ||
789 | } | ||
790 | while (--i > 0) { | ||
791 | if (sd->frame_rate >= r->fps) | ||
792 | break; | ||
793 | r++; | ||
794 | } | ||
795 | |||
796 | sccb_reg_write(gspca_dev, 0x11, r->r11); | ||
797 | sccb_reg_write(gspca_dev, 0x0d, r->r0d); | ||
798 | ov534_reg_write(gspca_dev, 0xe5, r->re5); | ||
799 | |||
800 | PDEBUG(D_PROBE, "frame_rate: %d", r->fps); | ||
801 | } | ||
802 | |||
803 | static void sethue(struct gspca_dev *gspca_dev, s32 val) | ||
804 | { | ||
805 | struct sd *sd = (struct sd *) gspca_dev; | ||
806 | |||
807 | if (sd->sensor == SENSOR_OV767x) { | ||
808 | /* TBD */ | ||
809 | } else { | ||
810 | s16 huesin; | ||
811 | s16 huecos; | ||
812 | |||
813 | /* fixp_sin and fixp_cos accept only positive values, while | ||
814 | * our val is between -90 and 90 | ||
815 | */ | ||
816 | val += 360; | ||
817 | |||
818 | /* According to the datasheet the registers expect HUESIN and | ||
819 | * HUECOS to be the result of the trigonometric functions, | ||
820 | * scaled by 0x80. | ||
821 | * | ||
822 | * The 0x100 here represents the maximun absolute value | ||
823 | * returned byt fixp_sin and fixp_cos, so the scaling will | ||
824 | * consider the result like in the interval [-1.0, 1.0]. | ||
825 | */ | ||
826 | huesin = fixp_sin(val) * 0x80 / 0x100; | ||
827 | huecos = fixp_cos(val) * 0x80 / 0x100; | ||
828 | |||
829 | if (huesin < 0) { | ||
830 | sccb_reg_write(gspca_dev, 0xab, | ||
831 | sccb_reg_read(gspca_dev, 0xab) | 0x2); | ||
832 | huesin = -huesin; | ||
833 | } else { | ||
834 | sccb_reg_write(gspca_dev, 0xab, | ||
835 | sccb_reg_read(gspca_dev, 0xab) & ~0x2); | ||
836 | |||
837 | } | ||
838 | sccb_reg_write(gspca_dev, 0xa9, (u8)huecos); | ||
839 | sccb_reg_write(gspca_dev, 0xaa, (u8)huesin); | ||
840 | } | ||
841 | } | ||
842 | |||
843 | static void setsaturation(struct gspca_dev *gspca_dev, s32 val) | ||
844 | { | ||
845 | struct sd *sd = (struct sd *) gspca_dev; | ||
846 | |||
847 | if (sd->sensor == SENSOR_OV767x) { | ||
848 | int i; | ||
849 | static u8 color_tb[][6] = { | ||
850 | {0x42, 0x42, 0x00, 0x11, 0x30, 0x41}, | ||
851 | {0x52, 0x52, 0x00, 0x16, 0x3c, 0x52}, | ||
852 | {0x66, 0x66, 0x00, 0x1b, 0x4b, 0x66}, | ||
853 | {0x80, 0x80, 0x00, 0x22, 0x5e, 0x80}, | ||
854 | {0x9a, 0x9a, 0x00, 0x29, 0x71, 0x9a}, | ||
855 | {0xb8, 0xb8, 0x00, 0x31, 0x87, 0xb8}, | ||
856 | {0xdd, 0xdd, 0x00, 0x3b, 0xa2, 0xdd}, | ||
857 | }; | ||
858 | |||
859 | for (i = 0; i < ARRAY_SIZE(color_tb[0]); i++) | ||
860 | sccb_reg_write(gspca_dev, 0x4f + i, color_tb[val][i]); | ||
861 | } else { | ||
862 | sccb_reg_write(gspca_dev, 0xa7, val); /* U saturation */ | ||
863 | sccb_reg_write(gspca_dev, 0xa8, val); /* V saturation */ | ||
864 | } | ||
865 | } | ||
866 | |||
867 | static void setbrightness(struct gspca_dev *gspca_dev, s32 val) | ||
868 | { | ||
869 | struct sd *sd = (struct sd *) gspca_dev; | ||
870 | |||
871 | if (sd->sensor == SENSOR_OV767x) { | ||
872 | if (val < 0) | ||
873 | val = 0x80 - val; | ||
874 | sccb_reg_write(gspca_dev, 0x55, val); /* bright */ | ||
875 | } else { | ||
876 | sccb_reg_write(gspca_dev, 0x9b, val); | ||
877 | } | ||
878 | } | ||
879 | |||
880 | static void setcontrast(struct gspca_dev *gspca_dev, s32 val) | ||
881 | { | ||
882 | struct sd *sd = (struct sd *) gspca_dev; | ||
883 | |||
884 | if (sd->sensor == SENSOR_OV767x) | ||
885 | sccb_reg_write(gspca_dev, 0x56, val); /* contras */ | ||
886 | else | ||
887 | sccb_reg_write(gspca_dev, 0x9c, val); | ||
888 | } | ||
889 | |||
890 | static void setgain(struct gspca_dev *gspca_dev, s32 val) | ||
891 | { | ||
892 | switch (val & 0x30) { | ||
893 | case 0x00: | ||
894 | val &= 0x0f; | ||
895 | break; | ||
896 | case 0x10: | ||
897 | val &= 0x0f; | ||
898 | val |= 0x30; | ||
899 | break; | ||
900 | case 0x20: | ||
901 | val &= 0x0f; | ||
902 | val |= 0x70; | ||
903 | break; | ||
904 | default: | ||
905 | /* case 0x30: */ | ||
906 | val &= 0x0f; | ||
907 | val |= 0xf0; | ||
908 | break; | ||
909 | } | ||
910 | sccb_reg_write(gspca_dev, 0x00, val); | ||
911 | } | ||
912 | |||
913 | static s32 getgain(struct gspca_dev *gspca_dev) | ||
914 | { | ||
915 | return sccb_reg_read(gspca_dev, 0x00); | ||
916 | } | ||
917 | |||
918 | static void setexposure(struct gspca_dev *gspca_dev, s32 val) | ||
919 | { | ||
920 | struct sd *sd = (struct sd *) gspca_dev; | ||
921 | |||
922 | if (sd->sensor == SENSOR_OV767x) { | ||
923 | |||
924 | /* set only aec[9:2] */ | ||
925 | sccb_reg_write(gspca_dev, 0x10, val); /* aech */ | ||
926 | } else { | ||
927 | |||
928 | /* 'val' is one byte and represents half of the exposure value | ||
929 | * we are going to set into registers, a two bytes value: | ||
930 | * | ||
931 | * MSB: ((u16) val << 1) >> 8 == val >> 7 | ||
932 | * LSB: ((u16) val << 1) & 0xff == val << 1 | ||
933 | */ | ||
934 | sccb_reg_write(gspca_dev, 0x08, val >> 7); | ||
935 | sccb_reg_write(gspca_dev, 0x10, val << 1); | ||
936 | } | ||
937 | } | ||
938 | |||
939 | static s32 getexposure(struct gspca_dev *gspca_dev) | ||
940 | { | ||
941 | struct sd *sd = (struct sd *) gspca_dev; | ||
942 | |||
943 | if (sd->sensor == SENSOR_OV767x) { | ||
944 | /* get only aec[9:2] */ | ||
945 | return sccb_reg_read(gspca_dev, 0x10); /* aech */ | ||
946 | } else { | ||
947 | u8 hi = sccb_reg_read(gspca_dev, 0x08); | ||
948 | u8 lo = sccb_reg_read(gspca_dev, 0x10); | ||
949 | return (hi << 8 | lo) >> 1; | ||
950 | } | ||
951 | } | ||
952 | |||
953 | static void setagc(struct gspca_dev *gspca_dev, s32 val) | ||
954 | { | ||
955 | if (val) { | ||
956 | sccb_reg_write(gspca_dev, 0x13, | ||
957 | sccb_reg_read(gspca_dev, 0x13) | 0x04); | ||
958 | sccb_reg_write(gspca_dev, 0x64, | ||
959 | sccb_reg_read(gspca_dev, 0x64) | 0x03); | ||
960 | } else { | ||
961 | sccb_reg_write(gspca_dev, 0x13, | ||
962 | sccb_reg_read(gspca_dev, 0x13) & ~0x04); | ||
963 | sccb_reg_write(gspca_dev, 0x64, | ||
964 | sccb_reg_read(gspca_dev, 0x64) & ~0x03); | ||
965 | } | ||
966 | } | ||
967 | |||
968 | static void setawb(struct gspca_dev *gspca_dev, s32 val) | ||
969 | { | ||
970 | struct sd *sd = (struct sd *) gspca_dev; | ||
971 | |||
972 | if (val) { | ||
973 | sccb_reg_write(gspca_dev, 0x13, | ||
974 | sccb_reg_read(gspca_dev, 0x13) | 0x02); | ||
975 | if (sd->sensor == SENSOR_OV772x) | ||
976 | sccb_reg_write(gspca_dev, 0x63, | ||
977 | sccb_reg_read(gspca_dev, 0x63) | 0xc0); | ||
978 | } else { | ||
979 | sccb_reg_write(gspca_dev, 0x13, | ||
980 | sccb_reg_read(gspca_dev, 0x13) & ~0x02); | ||
981 | if (sd->sensor == SENSOR_OV772x) | ||
982 | sccb_reg_write(gspca_dev, 0x63, | ||
983 | sccb_reg_read(gspca_dev, 0x63) & ~0xc0); | ||
984 | } | ||
985 | } | ||
986 | |||
987 | static void setaec(struct gspca_dev *gspca_dev, s32 val) | ||
988 | { | ||
989 | struct sd *sd = (struct sd *) gspca_dev; | ||
990 | u8 data; | ||
991 | |||
992 | data = sd->sensor == SENSOR_OV767x ? | ||
993 | 0x05 : /* agc + aec */ | ||
994 | 0x01; /* agc */ | ||
995 | switch (val) { | ||
996 | case V4L2_EXPOSURE_AUTO: | ||
997 | sccb_reg_write(gspca_dev, 0x13, | ||
998 | sccb_reg_read(gspca_dev, 0x13) | data); | ||
999 | break; | ||
1000 | case V4L2_EXPOSURE_MANUAL: | ||
1001 | sccb_reg_write(gspca_dev, 0x13, | ||
1002 | sccb_reg_read(gspca_dev, 0x13) & ~data); | ||
1003 | break; | ||
1004 | } | ||
1005 | } | ||
1006 | |||
1007 | static void setsharpness(struct gspca_dev *gspca_dev, s32 val) | ||
1008 | { | ||
1009 | sccb_reg_write(gspca_dev, 0x91, val); /* Auto de-noise threshold */ | ||
1010 | sccb_reg_write(gspca_dev, 0x8e, val); /* De-noise threshold */ | ||
1011 | } | ||
1012 | |||
1013 | static void sethvflip(struct gspca_dev *gspca_dev, s32 hflip, s32 vflip) | ||
1014 | { | ||
1015 | struct sd *sd = (struct sd *) gspca_dev; | ||
1016 | u8 val; | ||
1017 | |||
1018 | if (sd->sensor == SENSOR_OV767x) { | ||
1019 | val = sccb_reg_read(gspca_dev, 0x1e); /* mvfp */ | ||
1020 | val &= ~0x30; | ||
1021 | if (hflip) | ||
1022 | val |= 0x20; | ||
1023 | if (vflip) | ||
1024 | val |= 0x10; | ||
1025 | sccb_reg_write(gspca_dev, 0x1e, val); | ||
1026 | } else { | ||
1027 | val = sccb_reg_read(gspca_dev, 0x0c); | ||
1028 | val &= ~0xc0; | ||
1029 | if (hflip == 0) | ||
1030 | val |= 0x40; | ||
1031 | if (vflip == 0) | ||
1032 | val |= 0x80; | ||
1033 | sccb_reg_write(gspca_dev, 0x0c, val); | ||
1034 | } | ||
1035 | } | ||
1036 | |||
1037 | static void setlightfreq(struct gspca_dev *gspca_dev, s32 val) | ||
1038 | { | ||
1039 | struct sd *sd = (struct sd *) gspca_dev; | ||
1040 | |||
1041 | val = val ? 0x9e : 0x00; | ||
1042 | if (sd->sensor == SENSOR_OV767x) { | ||
1043 | sccb_reg_write(gspca_dev, 0x2a, 0x00); | ||
1044 | if (val) | ||
1045 | val = 0x9d; /* insert dummy to 25fps for 50Hz */ | ||
1046 | } | ||
1047 | sccb_reg_write(gspca_dev, 0x2b, val); | ||
1048 | } | ||
1049 | |||
1050 | |||
1051 | /* this function is called at probe time */ | ||
1052 | static int sd_config(struct gspca_dev *gspca_dev, | ||
1053 | const struct usb_device_id *id) | ||
1054 | { | ||
1055 | struct sd *sd = (struct sd *) gspca_dev; | ||
1056 | struct cam *cam; | ||
1057 | |||
1058 | cam = &gspca_dev->cam; | ||
1059 | |||
1060 | cam->cam_mode = ov772x_mode; | ||
1061 | cam->nmodes = ARRAY_SIZE(ov772x_mode); | ||
1062 | |||
1063 | sd->frame_rate = 30; | ||
1064 | |||
1065 | return 0; | ||
1066 | } | ||
1067 | |||
1068 | static int ov534_g_volatile_ctrl(struct v4l2_ctrl *ctrl) | ||
1069 | { | ||
1070 | struct sd *sd = container_of(ctrl->handler, struct sd, ctrl_handler); | ||
1071 | struct gspca_dev *gspca_dev = &sd->gspca_dev; | ||
1072 | |||
1073 | switch (ctrl->id) { | ||
1074 | case V4L2_CID_AUTOGAIN: | ||
1075 | gspca_dev->usb_err = 0; | ||
1076 | if (ctrl->val && sd->gain && gspca_dev->streaming) | ||
1077 | sd->gain->val = getgain(gspca_dev); | ||
1078 | return gspca_dev->usb_err; | ||
1079 | |||
1080 | case V4L2_CID_EXPOSURE_AUTO: | ||
1081 | gspca_dev->usb_err = 0; | ||
1082 | if (ctrl->val == V4L2_EXPOSURE_AUTO && sd->exposure && | ||
1083 | gspca_dev->streaming) | ||
1084 | sd->exposure->val = getexposure(gspca_dev); | ||
1085 | return gspca_dev->usb_err; | ||
1086 | } | ||
1087 | return -EINVAL; | ||
1088 | } | ||
1089 | |||
1090 | static int ov534_s_ctrl(struct v4l2_ctrl *ctrl) | ||
1091 | { | ||
1092 | struct sd *sd = container_of(ctrl->handler, struct sd, ctrl_handler); | ||
1093 | struct gspca_dev *gspca_dev = &sd->gspca_dev; | ||
1094 | |||
1095 | gspca_dev->usb_err = 0; | ||
1096 | if (!gspca_dev->streaming) | ||
1097 | return 0; | ||
1098 | |||
1099 | switch (ctrl->id) { | ||
1100 | case V4L2_CID_HUE: | ||
1101 | sethue(gspca_dev, ctrl->val); | ||
1102 | break; | ||
1103 | case V4L2_CID_SATURATION: | ||
1104 | setsaturation(gspca_dev, ctrl->val); | ||
1105 | break; | ||
1106 | case V4L2_CID_BRIGHTNESS: | ||
1107 | setbrightness(gspca_dev, ctrl->val); | ||
1108 | break; | ||
1109 | case V4L2_CID_CONTRAST: | ||
1110 | setcontrast(gspca_dev, ctrl->val); | ||
1111 | break; | ||
1112 | case V4L2_CID_AUTOGAIN: | ||
1113 | /* case V4L2_CID_GAIN: */ | ||
1114 | setagc(gspca_dev, ctrl->val); | ||
1115 | if (!gspca_dev->usb_err && !ctrl->val && sd->gain) | ||
1116 | setgain(gspca_dev, sd->gain->val); | ||
1117 | break; | ||
1118 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
1119 | setawb(gspca_dev, ctrl->val); | ||
1120 | break; | ||
1121 | case V4L2_CID_EXPOSURE_AUTO: | ||
1122 | /* case V4L2_CID_EXPOSURE: */ | ||
1123 | setaec(gspca_dev, ctrl->val); | ||
1124 | if (!gspca_dev->usb_err && ctrl->val == V4L2_EXPOSURE_MANUAL && | ||
1125 | sd->exposure) | ||
1126 | setexposure(gspca_dev, sd->exposure->val); | ||
1127 | break; | ||
1128 | case V4L2_CID_SHARPNESS: | ||
1129 | setsharpness(gspca_dev, ctrl->val); | ||
1130 | break; | ||
1131 | case V4L2_CID_HFLIP: | ||
1132 | sethvflip(gspca_dev, ctrl->val, sd->vflip->val); | ||
1133 | break; | ||
1134 | case V4L2_CID_VFLIP: | ||
1135 | sethvflip(gspca_dev, sd->hflip->val, ctrl->val); | ||
1136 | break; | ||
1137 | case V4L2_CID_POWER_LINE_FREQUENCY: | ||
1138 | setlightfreq(gspca_dev, ctrl->val); | ||
1139 | break; | ||
1140 | } | ||
1141 | return gspca_dev->usb_err; | ||
1142 | } | ||
1143 | |||
1144 | static const struct v4l2_ctrl_ops ov534_ctrl_ops = { | ||
1145 | .g_volatile_ctrl = ov534_g_volatile_ctrl, | ||
1146 | .s_ctrl = ov534_s_ctrl, | ||
1147 | }; | ||
1148 | |||
1149 | static int sd_init_controls(struct gspca_dev *gspca_dev) | ||
1150 | { | ||
1151 | struct sd *sd = (struct sd *) gspca_dev; | ||
1152 | struct v4l2_ctrl_handler *hdl = &sd->ctrl_handler; | ||
1153 | /* parameters with different values between the supported sensors */ | ||
1154 | int saturation_min; | ||
1155 | int saturation_max; | ||
1156 | int saturation_def; | ||
1157 | int brightness_min; | ||
1158 | int brightness_max; | ||
1159 | int brightness_def; | ||
1160 | int contrast_max; | ||
1161 | int contrast_def; | ||
1162 | int exposure_min; | ||
1163 | int exposure_max; | ||
1164 | int exposure_def; | ||
1165 | int hflip_def; | ||
1166 | |||
1167 | if (sd->sensor == SENSOR_OV767x) { | ||
1168 | saturation_min = 0, | ||
1169 | saturation_max = 6, | ||
1170 | saturation_def = 3, | ||
1171 | brightness_min = -127; | ||
1172 | brightness_max = 127; | ||
1173 | brightness_def = 0; | ||
1174 | contrast_max = 0x80; | ||
1175 | contrast_def = 0x40; | ||
1176 | exposure_min = 0x08; | ||
1177 | exposure_max = 0x60; | ||
1178 | exposure_def = 0x13; | ||
1179 | hflip_def = 1; | ||
1180 | } else { | ||
1181 | saturation_min = 0, | ||
1182 | saturation_max = 255, | ||
1183 | saturation_def = 64, | ||
1184 | brightness_min = 0; | ||
1185 | brightness_max = 255; | ||
1186 | brightness_def = 0; | ||
1187 | contrast_max = 255; | ||
1188 | contrast_def = 32; | ||
1189 | exposure_min = 0; | ||
1190 | exposure_max = 255; | ||
1191 | exposure_def = 120; | ||
1192 | hflip_def = 0; | ||
1193 | } | ||
1194 | |||
1195 | gspca_dev->vdev.ctrl_handler = hdl; | ||
1196 | |||
1197 | v4l2_ctrl_handler_init(hdl, 13); | ||
1198 | |||
1199 | if (sd->sensor == SENSOR_OV772x) | ||
1200 | sd->hue = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, | ||
1201 | V4L2_CID_HUE, -90, 90, 1, 0); | ||
1202 | |||
1203 | sd->saturation = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, | ||
1204 | V4L2_CID_SATURATION, saturation_min, saturation_max, 1, | ||
1205 | saturation_def); | ||
1206 | sd->brightness = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, | ||
1207 | V4L2_CID_BRIGHTNESS, brightness_min, brightness_max, 1, | ||
1208 | brightness_def); | ||
1209 | sd->contrast = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, | ||
1210 | V4L2_CID_CONTRAST, 0, contrast_max, 1, contrast_def); | ||
1211 | |||
1212 | if (sd->sensor == SENSOR_OV772x) { | ||
1213 | sd->autogain = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, | ||
1214 | V4L2_CID_AUTOGAIN, 0, 1, 1, 1); | ||
1215 | sd->gain = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, | ||
1216 | V4L2_CID_GAIN, 0, 63, 1, 20); | ||
1217 | } | ||
1218 | |||
1219 | sd->autoexposure = v4l2_ctrl_new_std_menu(hdl, &ov534_ctrl_ops, | ||
1220 | V4L2_CID_EXPOSURE_AUTO, | ||
1221 | V4L2_EXPOSURE_MANUAL, 0, | ||
1222 | V4L2_EXPOSURE_AUTO); | ||
1223 | sd->exposure = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, | ||
1224 | V4L2_CID_EXPOSURE, exposure_min, exposure_max, 1, | ||
1225 | exposure_def); | ||
1226 | |||
1227 | sd->autowhitebalance = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, | ||
1228 | V4L2_CID_AUTO_WHITE_BALANCE, 0, 1, 1, 1); | ||
1229 | |||
1230 | if (sd->sensor == SENSOR_OV772x) | ||
1231 | sd->sharpness = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, | ||
1232 | V4L2_CID_SHARPNESS, 0, 63, 1, 0); | ||
1233 | |||
1234 | sd->hflip = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, | ||
1235 | V4L2_CID_HFLIP, 0, 1, 1, hflip_def); | ||
1236 | sd->vflip = v4l2_ctrl_new_std(hdl, &ov534_ctrl_ops, | ||
1237 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
1238 | sd->plfreq = v4l2_ctrl_new_std_menu(hdl, &ov534_ctrl_ops, | ||
1239 | V4L2_CID_POWER_LINE_FREQUENCY, | ||
1240 | V4L2_CID_POWER_LINE_FREQUENCY_50HZ, 0, | ||
1241 | V4L2_CID_POWER_LINE_FREQUENCY_DISABLED); | ||
1242 | |||
1243 | if (hdl->error) { | ||
1244 | pr_err("Could not initialize controls\n"); | ||
1245 | return hdl->error; | ||
1246 | } | ||
1247 | |||
1248 | if (sd->sensor == SENSOR_OV772x) | ||
1249 | v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, true); | ||
1250 | |||
1251 | v4l2_ctrl_auto_cluster(2, &sd->autoexposure, V4L2_EXPOSURE_MANUAL, | ||
1252 | true); | ||
1253 | |||
1254 | return 0; | ||
1255 | } | ||
1256 | |||
1257 | /* this function is called at probe and resume time */ | ||
1258 | static int sd_init(struct gspca_dev *gspca_dev) | ||
1259 | { | ||
1260 | struct sd *sd = (struct sd *) gspca_dev; | ||
1261 | u16 sensor_id; | ||
1262 | static const struct reg_array bridge_init[NSENSORS] = { | ||
1263 | [SENSOR_OV767x] = {bridge_init_767x, ARRAY_SIZE(bridge_init_767x)}, | ||
1264 | [SENSOR_OV772x] = {bridge_init_772x, ARRAY_SIZE(bridge_init_772x)}, | ||
1265 | }; | ||
1266 | static const struct reg_array sensor_init[NSENSORS] = { | ||
1267 | [SENSOR_OV767x] = {sensor_init_767x, ARRAY_SIZE(sensor_init_767x)}, | ||
1268 | [SENSOR_OV772x] = {sensor_init_772x, ARRAY_SIZE(sensor_init_772x)}, | ||
1269 | }; | ||
1270 | |||
1271 | /* reset bridge */ | ||
1272 | ov534_reg_write(gspca_dev, 0xe7, 0x3a); | ||
1273 | ov534_reg_write(gspca_dev, 0xe0, 0x08); | ||
1274 | msleep(100); | ||
1275 | |||
1276 | /* initialize the sensor address */ | ||
1277 | ov534_reg_write(gspca_dev, OV534_REG_ADDRESS, 0x42); | ||
1278 | |||
1279 | /* reset sensor */ | ||
1280 | sccb_reg_write(gspca_dev, 0x12, 0x80); | ||
1281 | msleep(10); | ||
1282 | |||
1283 | /* probe the sensor */ | ||
1284 | sccb_reg_read(gspca_dev, 0x0a); | ||
1285 | sensor_id = sccb_reg_read(gspca_dev, 0x0a) << 8; | ||
1286 | sccb_reg_read(gspca_dev, 0x0b); | ||
1287 | sensor_id |= sccb_reg_read(gspca_dev, 0x0b); | ||
1288 | PDEBUG(D_PROBE, "Sensor ID: %04x", sensor_id); | ||
1289 | |||
1290 | if ((sensor_id & 0xfff0) == 0x7670) { | ||
1291 | sd->sensor = SENSOR_OV767x; | ||
1292 | gspca_dev->cam.cam_mode = ov767x_mode; | ||
1293 | gspca_dev->cam.nmodes = ARRAY_SIZE(ov767x_mode); | ||
1294 | } else { | ||
1295 | sd->sensor = SENSOR_OV772x; | ||
1296 | gspca_dev->cam.bulk = 1; | ||
1297 | gspca_dev->cam.bulk_size = 16384; | ||
1298 | gspca_dev->cam.bulk_nurbs = 2; | ||
1299 | gspca_dev->cam.mode_framerates = ov772x_framerates; | ||
1300 | } | ||
1301 | |||
1302 | /* initialize */ | ||
1303 | reg_w_array(gspca_dev, bridge_init[sd->sensor].val, | ||
1304 | bridge_init[sd->sensor].len); | ||
1305 | ov534_set_led(gspca_dev, 1); | ||
1306 | sccb_w_array(gspca_dev, sensor_init[sd->sensor].val, | ||
1307 | sensor_init[sd->sensor].len); | ||
1308 | if (sd->sensor == SENSOR_OV767x) | ||
1309 | sd_start(gspca_dev); | ||
1310 | sd_stopN(gspca_dev); | ||
1311 | /* set_frame_rate(gspca_dev); */ | ||
1312 | |||
1313 | return gspca_dev->usb_err; | ||
1314 | } | ||
1315 | |||
1316 | static int sd_start(struct gspca_dev *gspca_dev) | ||
1317 | { | ||
1318 | struct sd *sd = (struct sd *) gspca_dev; | ||
1319 | int mode; | ||
1320 | static const struct reg_array bridge_start[NSENSORS][2] = { | ||
1321 | [SENSOR_OV767x] = {{bridge_start_qvga_767x, | ||
1322 | ARRAY_SIZE(bridge_start_qvga_767x)}, | ||
1323 | {bridge_start_vga_767x, | ||
1324 | ARRAY_SIZE(bridge_start_vga_767x)}}, | ||
1325 | [SENSOR_OV772x] = {{bridge_start_qvga_772x, | ||
1326 | ARRAY_SIZE(bridge_start_qvga_772x)}, | ||
1327 | {bridge_start_vga_772x, | ||
1328 | ARRAY_SIZE(bridge_start_vga_772x)}}, | ||
1329 | }; | ||
1330 | static const struct reg_array sensor_start[NSENSORS][2] = { | ||
1331 | [SENSOR_OV767x] = {{sensor_start_qvga_767x, | ||
1332 | ARRAY_SIZE(sensor_start_qvga_767x)}, | ||
1333 | {sensor_start_vga_767x, | ||
1334 | ARRAY_SIZE(sensor_start_vga_767x)}}, | ||
1335 | [SENSOR_OV772x] = {{sensor_start_qvga_772x, | ||
1336 | ARRAY_SIZE(sensor_start_qvga_772x)}, | ||
1337 | {sensor_start_vga_772x, | ||
1338 | ARRAY_SIZE(sensor_start_vga_772x)}}, | ||
1339 | }; | ||
1340 | |||
1341 | /* (from ms-win trace) */ | ||
1342 | if (sd->sensor == SENSOR_OV767x) | ||
1343 | sccb_reg_write(gspca_dev, 0x1e, 0x04); | ||
1344 | /* black sun enable ? */ | ||
1345 | |||
1346 | mode = gspca_dev->curr_mode; /* 0: 320x240, 1: 640x480 */ | ||
1347 | reg_w_array(gspca_dev, bridge_start[sd->sensor][mode].val, | ||
1348 | bridge_start[sd->sensor][mode].len); | ||
1349 | sccb_w_array(gspca_dev, sensor_start[sd->sensor][mode].val, | ||
1350 | sensor_start[sd->sensor][mode].len); | ||
1351 | |||
1352 | set_frame_rate(gspca_dev); | ||
1353 | |||
1354 | if (sd->hue) | ||
1355 | sethue(gspca_dev, v4l2_ctrl_g_ctrl(sd->hue)); | ||
1356 | setsaturation(gspca_dev, v4l2_ctrl_g_ctrl(sd->saturation)); | ||
1357 | if (sd->autogain) | ||
1358 | setagc(gspca_dev, v4l2_ctrl_g_ctrl(sd->autogain)); | ||
1359 | setawb(gspca_dev, v4l2_ctrl_g_ctrl(sd->autowhitebalance)); | ||
1360 | setaec(gspca_dev, v4l2_ctrl_g_ctrl(sd->autoexposure)); | ||
1361 | if (sd->gain) | ||
1362 | setgain(gspca_dev, v4l2_ctrl_g_ctrl(sd->gain)); | ||
1363 | setexposure(gspca_dev, v4l2_ctrl_g_ctrl(sd->exposure)); | ||
1364 | setbrightness(gspca_dev, v4l2_ctrl_g_ctrl(sd->brightness)); | ||
1365 | setcontrast(gspca_dev, v4l2_ctrl_g_ctrl(sd->contrast)); | ||
1366 | if (sd->sharpness) | ||
1367 | setsharpness(gspca_dev, v4l2_ctrl_g_ctrl(sd->sharpness)); | ||
1368 | sethvflip(gspca_dev, v4l2_ctrl_g_ctrl(sd->hflip), | ||
1369 | v4l2_ctrl_g_ctrl(sd->vflip)); | ||
1370 | setlightfreq(gspca_dev, v4l2_ctrl_g_ctrl(sd->plfreq)); | ||
1371 | |||
1372 | ov534_set_led(gspca_dev, 1); | ||
1373 | ov534_reg_write(gspca_dev, 0xe0, 0x00); | ||
1374 | return gspca_dev->usb_err; | ||
1375 | } | ||
1376 | |||
1377 | static void sd_stopN(struct gspca_dev *gspca_dev) | ||
1378 | { | ||
1379 | ov534_reg_write(gspca_dev, 0xe0, 0x09); | ||
1380 | ov534_set_led(gspca_dev, 0); | ||
1381 | } | ||
1382 | |||
1383 | /* Values for bmHeaderInfo (Video and Still Image Payload Headers, 2.4.3.3) */ | ||
1384 | #define UVC_STREAM_EOH (1 << 7) | ||
1385 | #define UVC_STREAM_ERR (1 << 6) | ||
1386 | #define UVC_STREAM_STI (1 << 5) | ||
1387 | #define UVC_STREAM_RES (1 << 4) | ||
1388 | #define UVC_STREAM_SCR (1 << 3) | ||
1389 | #define UVC_STREAM_PTS (1 << 2) | ||
1390 | #define UVC_STREAM_EOF (1 << 1) | ||
1391 | #define UVC_STREAM_FID (1 << 0) | ||
1392 | |||
1393 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, | ||
1394 | u8 *data, int len) | ||
1395 | { | ||
1396 | struct sd *sd = (struct sd *) gspca_dev; | ||
1397 | __u32 this_pts; | ||
1398 | u16 this_fid; | ||
1399 | int remaining_len = len; | ||
1400 | int payload_len; | ||
1401 | |||
1402 | payload_len = gspca_dev->cam.bulk ? 2048 : 2040; | ||
1403 | do { | ||
1404 | len = min(remaining_len, payload_len); | ||
1405 | |||
1406 | /* Payloads are prefixed with a UVC-style header. We | ||
1407 | consider a frame to start when the FID toggles, or the PTS | ||
1408 | changes. A frame ends when EOF is set, and we've received | ||
1409 | the correct number of bytes. */ | ||
1410 | |||
1411 | /* Verify UVC header. Header length is always 12 */ | ||
1412 | if (data[0] != 12 || len < 12) { | ||
1413 | PDEBUG(D_PACK, "bad header"); | ||
1414 | goto discard; | ||
1415 | } | ||
1416 | |||
1417 | /* Check errors */ | ||
1418 | if (data[1] & UVC_STREAM_ERR) { | ||
1419 | PDEBUG(D_PACK, "payload error"); | ||
1420 | goto discard; | ||
1421 | } | ||
1422 | |||
1423 | /* Extract PTS and FID */ | ||
1424 | if (!(data[1] & UVC_STREAM_PTS)) { | ||
1425 | PDEBUG(D_PACK, "PTS not present"); | ||
1426 | goto discard; | ||
1427 | } | ||
1428 | this_pts = (data[5] << 24) | (data[4] << 16) | ||
1429 | | (data[3] << 8) | data[2]; | ||
1430 | this_fid = (data[1] & UVC_STREAM_FID) ? 1 : 0; | ||
1431 | |||
1432 | /* If PTS or FID has changed, start a new frame. */ | ||
1433 | if (this_pts != sd->last_pts || this_fid != sd->last_fid) { | ||
1434 | if (gspca_dev->last_packet_type == INTER_PACKET) | ||
1435 | gspca_frame_add(gspca_dev, LAST_PACKET, | ||
1436 | NULL, 0); | ||
1437 | sd->last_pts = this_pts; | ||
1438 | sd->last_fid = this_fid; | ||
1439 | gspca_frame_add(gspca_dev, FIRST_PACKET, | ||
1440 | data + 12, len - 12); | ||
1441 | /* If this packet is marked as EOF, end the frame */ | ||
1442 | } else if (data[1] & UVC_STREAM_EOF) { | ||
1443 | sd->last_pts = 0; | ||
1444 | if (gspca_dev->pixfmt == V4L2_PIX_FMT_YUYV | ||
1445 | && gspca_dev->image_len + len - 12 != | ||
1446 | gspca_dev->width * gspca_dev->height * 2) { | ||
1447 | PDEBUG(D_PACK, "wrong sized frame"); | ||
1448 | goto discard; | ||
1449 | } | ||
1450 | gspca_frame_add(gspca_dev, LAST_PACKET, | ||
1451 | data + 12, len - 12); | ||
1452 | } else { | ||
1453 | |||
1454 | /* Add the data from this payload */ | ||
1455 | gspca_frame_add(gspca_dev, INTER_PACKET, | ||
1456 | data + 12, len - 12); | ||
1457 | } | ||
1458 | |||
1459 | /* Done this payload */ | ||
1460 | goto scan_next; | ||
1461 | |||
1462 | discard: | ||
1463 | /* Discard data until a new frame starts. */ | ||
1464 | gspca_dev->last_packet_type = DISCARD_PACKET; | ||
1465 | |||
1466 | scan_next: | ||
1467 | remaining_len -= len; | ||
1468 | data += len; | ||
1469 | } while (remaining_len > 0); | ||
1470 | } | ||
1471 | |||
1472 | /* get stream parameters (framerate) */ | ||
1473 | static void sd_get_streamparm(struct gspca_dev *gspca_dev, | ||
1474 | struct v4l2_streamparm *parm) | ||
1475 | { | ||
1476 | struct v4l2_captureparm *cp = &parm->parm.capture; | ||
1477 | struct v4l2_fract *tpf = &cp->timeperframe; | ||
1478 | struct sd *sd = (struct sd *) gspca_dev; | ||
1479 | |||
1480 | cp->capability |= V4L2_CAP_TIMEPERFRAME; | ||
1481 | tpf->numerator = 1; | ||
1482 | tpf->denominator = sd->frame_rate; | ||
1483 | } | ||
1484 | |||
1485 | /* set stream parameters (framerate) */ | ||
1486 | static void sd_set_streamparm(struct gspca_dev *gspca_dev, | ||
1487 | struct v4l2_streamparm *parm) | ||
1488 | { | ||
1489 | struct v4l2_captureparm *cp = &parm->parm.capture; | ||
1490 | struct v4l2_fract *tpf = &cp->timeperframe; | ||
1491 | struct sd *sd = (struct sd *) gspca_dev; | ||
1492 | |||
1493 | /* Set requested framerate */ | ||
1494 | sd->frame_rate = tpf->denominator / tpf->numerator; | ||
1495 | if (gspca_dev->streaming) | ||
1496 | set_frame_rate(gspca_dev); | ||
1497 | |||
1498 | /* Return the actual framerate */ | ||
1499 | tpf->numerator = 1; | ||
1500 | tpf->denominator = sd->frame_rate; | ||
1501 | } | ||
1502 | |||
1503 | /* sub-driver description */ | ||
1504 | static const struct sd_desc sd_desc = { | ||
1505 | .name = MODULE_NAME, | ||
1506 | .config = sd_config, | ||
1507 | .init = sd_init, | ||
1508 | .init_controls = sd_init_controls, | ||
1509 | .start = sd_start, | ||
1510 | .stopN = sd_stopN, | ||
1511 | .pkt_scan = sd_pkt_scan, | ||
1512 | .get_streamparm = sd_get_streamparm, | ||
1513 | .set_streamparm = sd_set_streamparm, | ||
1514 | }; | ||
1515 | |||
1516 | /* -- module initialisation -- */ | ||
1517 | static const struct usb_device_id device_table[] = { | ||
1518 | {USB_DEVICE(0x1415, 0x2000)}, | ||
1519 | {USB_DEVICE(0x06f8, 0x3002)}, | ||
1520 | {} | ||
1521 | }; | ||
1522 | |||
1523 | MODULE_DEVICE_TABLE(usb, device_table); | ||
1524 | |||
1525 | /* -- device connect -- */ | ||
1526 | static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) | ||
1527 | { | ||
1528 | return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), | ||
1529 | THIS_MODULE); | ||
1530 | } | ||
1531 | |||
1532 | static struct usb_driver sd_driver = { | ||
1533 | .name = MODULE_NAME, | ||
1534 | .id_table = device_table, | ||
1535 | .probe = sd_probe, | ||
1536 | .disconnect = gspca_disconnect, | ||
1537 | #ifdef CONFIG_PM | ||
1538 | .suspend = gspca_suspend, | ||
1539 | .resume = gspca_resume, | ||
1540 | .reset_resume = gspca_resume, | ||
1541 | #endif | ||
1542 | }; | ||
1543 | |||
1544 | module_usb_driver(sd_driver); | ||