1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * SPCA505 chip based cameras initialization data |
4 | * |
5 | * V4L2 by Jean-Francis Moine <http://moinejf.free.fr> |
6 | */ |
7 | |
8 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
9 | |
10 | #define MODULE_NAME "spca505" |
11 | |
12 | #include "gspca.h" |
13 | |
14 | MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>" ); |
15 | MODULE_DESCRIPTION("GSPCA/SPCA505 USB Camera Driver" ); |
16 | MODULE_LICENSE("GPL" ); |
17 | |
18 | /* specific webcam descriptor */ |
19 | struct sd { |
20 | struct gspca_dev gspca_dev; /* !! must be the first item */ |
21 | |
22 | u8 subtype; |
23 | #define IntelPCCameraPro 0 |
24 | #define Nxultra 1 |
25 | }; |
26 | |
27 | static const struct v4l2_pix_format vga_mode[] = { |
28 | {160, 120, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, |
29 | .bytesperline = 160, |
30 | .sizeimage = 160 * 120 * 3 / 2, |
31 | .colorspace = V4L2_COLORSPACE_SRGB, |
32 | .priv = 4}, |
33 | {176, 144, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, |
34 | .bytesperline = 176, |
35 | .sizeimage = 176 * 144 * 3 / 2, |
36 | .colorspace = V4L2_COLORSPACE_SRGB, |
37 | .priv = 3}, |
38 | {320, 240, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, |
39 | .bytesperline = 320, |
40 | .sizeimage = 320 * 240 * 3 / 2, |
41 | .colorspace = V4L2_COLORSPACE_SRGB, |
42 | .priv = 2}, |
43 | {352, 288, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, |
44 | .bytesperline = 352, |
45 | .sizeimage = 352 * 288 * 3 / 2, |
46 | .colorspace = V4L2_COLORSPACE_SRGB, |
47 | .priv = 1}, |
48 | {640, 480, V4L2_PIX_FMT_SPCA505, V4L2_FIELD_NONE, |
49 | .bytesperline = 640, |
50 | .sizeimage = 640 * 480 * 3 / 2, |
51 | .colorspace = V4L2_COLORSPACE_SRGB, |
52 | .priv = 0}, |
53 | }; |
54 | |
55 | #define SPCA50X_OFFSET_DATA 10 |
56 | |
57 | #define SPCA50X_REG_USB 0x02 /* spca505 501 */ |
58 | |
59 | #define SPCA50X_USB_CTRL 0x00 /* spca505 */ |
60 | #define SPCA50X_CUSB_ENABLE 0x01 /* spca505 */ |
61 | |
62 | #define SPCA50X_REG_GLOBAL 0x03 /* spca505 */ |
63 | #define SPCA50X_GMISC0_IDSEL 0x01 /* Global control device ID select spca505 */ |
64 | #define SPCA50X_GLOBAL_MISC0 0x00 /* Global control miscellaneous 0 spca505 */ |
65 | |
66 | #define SPCA50X_GLOBAL_MISC1 0x01 /* 505 */ |
67 | #define SPCA50X_GLOBAL_MISC3 0x03 /* 505 */ |
68 | #define SPCA50X_GMISC3_SAA7113RST 0x20 /* Not sure about this one spca505 */ |
69 | |
70 | /* Image format and compression control */ |
71 | #define SPCA50X_REG_COMPRESS 0x04 |
72 | |
73 | /* |
74 | * Data to initialize a SPCA505. Common to the CCD and external modes |
75 | */ |
76 | static const u8 spca505_init_data[][3] = { |
77 | /* bmRequest,value,index */ |
78 | {SPCA50X_REG_GLOBAL, SPCA50X_GMISC3_SAA7113RST, SPCA50X_GLOBAL_MISC3}, |
79 | /* Sensor reset */ |
80 | {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC3}, |
81 | {SPCA50X_REG_GLOBAL, 0x00, SPCA50X_GLOBAL_MISC1}, |
82 | /* Block USB reset */ |
83 | {SPCA50X_REG_GLOBAL, SPCA50X_GMISC0_IDSEL, SPCA50X_GLOBAL_MISC0}, |
84 | |
85 | {0x05, 0x01, 0x10}, |
86 | /* Maybe power down some stuff */ |
87 | {0x05, 0x0f, 0x11}, |
88 | |
89 | /* Setup internal CCD ? */ |
90 | {0x06, 0x10, 0x08}, |
91 | {0x06, 0x00, 0x09}, |
92 | {0x06, 0x00, 0x0a}, |
93 | {0x06, 0x00, 0x0b}, |
94 | {0x06, 0x10, 0x0c}, |
95 | {0x06, 0x00, 0x0d}, |
96 | {0x06, 0x00, 0x0e}, |
97 | {0x06, 0x00, 0x0f}, |
98 | {0x06, 0x10, 0x10}, |
99 | {0x06, 0x02, 0x11}, |
100 | {0x06, 0x00, 0x12}, |
101 | {0x06, 0x04, 0x13}, |
102 | {0x06, 0x02, 0x14}, |
103 | {0x06, 0x8a, 0x51}, |
104 | {0x06, 0x40, 0x52}, |
105 | {0x06, 0xb6, 0x53}, |
106 | {0x06, 0x3d, 0x54}, |
107 | {} |
108 | }; |
109 | |
110 | /* |
111 | * Data to initialize the camera using the internal CCD |
112 | */ |
113 | static const u8 spca505_open_data_ccd[][3] = { |
114 | /* bmRequest,value,index */ |
115 | /* Internal CCD data set */ |
116 | {0x03, 0x04, 0x01}, |
117 | /* This could be a reset */ |
118 | {0x03, 0x00, 0x01}, |
119 | |
120 | /* Setup compression and image registers. 0x6 and 0x7 seem to be |
121 | related to H&V hold, and are resolution mode specific */ |
122 | {0x04, 0x10, 0x01}, |
123 | /* DIFF(0x50), was (0x10) */ |
124 | {0x04, 0x00, 0x04}, |
125 | {0x04, 0x00, 0x05}, |
126 | {0x04, 0x20, 0x06}, |
127 | {0x04, 0x20, 0x07}, |
128 | |
129 | {0x08, 0x0a, 0x00}, |
130 | /* DIFF (0x4a), was (0xa) */ |
131 | |
132 | {0x05, 0x00, 0x10}, |
133 | {0x05, 0x00, 0x11}, |
134 | {0x05, 0x00, 0x00}, |
135 | /* DIFF not written */ |
136 | {0x05, 0x00, 0x01}, |
137 | /* DIFF not written */ |
138 | {0x05, 0x00, 0x02}, |
139 | /* DIFF not written */ |
140 | {0x05, 0x00, 0x03}, |
141 | /* DIFF not written */ |
142 | {0x05, 0x00, 0x04}, |
143 | /* DIFF not written */ |
144 | {0x05, 0x80, 0x05}, |
145 | /* DIFF not written */ |
146 | {0x05, 0xe0, 0x06}, |
147 | /* DIFF not written */ |
148 | {0x05, 0x20, 0x07}, |
149 | /* DIFF not written */ |
150 | {0x05, 0xa0, 0x08}, |
151 | /* DIFF not written */ |
152 | {0x05, 0x0, 0x12}, |
153 | /* DIFF not written */ |
154 | {0x05, 0x02, 0x0f}, |
155 | /* DIFF not written */ |
156 | {0x05, 0x10, 0x46}, |
157 | /* DIFF not written */ |
158 | {0x05, 0x8, 0x4a}, |
159 | /* DIFF not written */ |
160 | |
161 | {0x03, 0x08, 0x03}, |
162 | /* DIFF (0x3,0x28,0x3) */ |
163 | {0x03, 0x08, 0x01}, |
164 | {0x03, 0x0c, 0x03}, |
165 | /* DIFF not written */ |
166 | {0x03, 0x21, 0x00}, |
167 | /* DIFF (0x39) */ |
168 | |
169 | /* Extra block copied from init to hopefully ensure CCD is in a sane state */ |
170 | {0x06, 0x10, 0x08}, |
171 | {0x06, 0x00, 0x09}, |
172 | {0x06, 0x00, 0x0a}, |
173 | {0x06, 0x00, 0x0b}, |
174 | {0x06, 0x10, 0x0c}, |
175 | {0x06, 0x00, 0x0d}, |
176 | {0x06, 0x00, 0x0e}, |
177 | {0x06, 0x00, 0x0f}, |
178 | {0x06, 0x10, 0x10}, |
179 | {0x06, 0x02, 0x11}, |
180 | {0x06, 0x00, 0x12}, |
181 | {0x06, 0x04, 0x13}, |
182 | {0x06, 0x02, 0x14}, |
183 | {0x06, 0x8a, 0x51}, |
184 | {0x06, 0x40, 0x52}, |
185 | {0x06, 0xb6, 0x53}, |
186 | {0x06, 0x3d, 0x54}, |
187 | /* End of extra block */ |
188 | |
189 | {0x06, 0x3f, 0x1}, |
190 | /* Block skipped */ |
191 | {0x06, 0x10, 0x02}, |
192 | {0x06, 0x64, 0x07}, |
193 | {0x06, 0x10, 0x08}, |
194 | {0x06, 0x00, 0x09}, |
195 | {0x06, 0x00, 0x0a}, |
196 | {0x06, 0x00, 0x0b}, |
197 | {0x06, 0x10, 0x0c}, |
198 | {0x06, 0x00, 0x0d}, |
199 | {0x06, 0x00, 0x0e}, |
200 | {0x06, 0x00, 0x0f}, |
201 | {0x06, 0x10, 0x10}, |
202 | {0x06, 0x02, 0x11}, |
203 | {0x06, 0x00, 0x12}, |
204 | {0x06, 0x04, 0x13}, |
205 | {0x06, 0x02, 0x14}, |
206 | {0x06, 0x8a, 0x51}, |
207 | {0x06, 0x40, 0x52}, |
208 | {0x06, 0xb6, 0x53}, |
209 | {0x06, 0x3d, 0x54}, |
210 | {0x06, 0x60, 0x57}, |
211 | {0x06, 0x20, 0x58}, |
212 | {0x06, 0x15, 0x59}, |
213 | {0x06, 0x05, 0x5a}, |
214 | |
215 | {0x05, 0x01, 0xc0}, |
216 | {0x05, 0x10, 0xcb}, |
217 | {0x05, 0x80, 0xc1}, |
218 | /* */ |
219 | {0x05, 0x0, 0xc2}, |
220 | /* 4 was 0 */ |
221 | {0x05, 0x00, 0xca}, |
222 | {0x05, 0x80, 0xc1}, |
223 | /* */ |
224 | {0x05, 0x04, 0xc2}, |
225 | {0x05, 0x00, 0xca}, |
226 | {0x05, 0x0, 0xc1}, |
227 | /* */ |
228 | {0x05, 0x00, 0xc2}, |
229 | {0x05, 0x00, 0xca}, |
230 | {0x05, 0x40, 0xc1}, |
231 | /* */ |
232 | {0x05, 0x17, 0xc2}, |
233 | {0x05, 0x00, 0xca}, |
234 | {0x05, 0x80, 0xc1}, |
235 | /* */ |
236 | {0x05, 0x06, 0xc2}, |
237 | {0x05, 0x00, 0xca}, |
238 | {0x05, 0x80, 0xc1}, |
239 | /* */ |
240 | {0x05, 0x04, 0xc2}, |
241 | {0x05, 0x00, 0xca}, |
242 | |
243 | {0x03, 0x4c, 0x3}, |
244 | {0x03, 0x18, 0x1}, |
245 | |
246 | {0x06, 0x70, 0x51}, |
247 | {0x06, 0xbe, 0x53}, |
248 | {0x06, 0x71, 0x57}, |
249 | {0x06, 0x20, 0x58}, |
250 | {0x06, 0x05, 0x59}, |
251 | {0x06, 0x15, 0x5a}, |
252 | |
253 | {0x04, 0x00, 0x08}, |
254 | /* Compress = OFF (0x1 to turn on) */ |
255 | {0x04, 0x12, 0x09}, |
256 | {0x04, 0x21, 0x0a}, |
257 | {0x04, 0x10, 0x0b}, |
258 | {0x04, 0x21, 0x0c}, |
259 | {0x04, 0x05, 0x00}, |
260 | /* was 5 (Image Type ? ) */ |
261 | {0x04, 0x00, 0x01}, |
262 | |
263 | {0x06, 0x3f, 0x01}, |
264 | |
265 | {0x04, 0x00, 0x04}, |
266 | {0x04, 0x00, 0x05}, |
267 | {0x04, 0x40, 0x06}, |
268 | {0x04, 0x40, 0x07}, |
269 | |
270 | {0x06, 0x1c, 0x17}, |
271 | {0x06, 0xe2, 0x19}, |
272 | {0x06, 0x1c, 0x1b}, |
273 | {0x06, 0xe2, 0x1d}, |
274 | {0x06, 0xaa, 0x1f}, |
275 | {0x06, 0x70, 0x20}, |
276 | |
277 | {0x05, 0x01, 0x10}, |
278 | {0x05, 0x00, 0x11}, |
279 | {0x05, 0x01, 0x00}, |
280 | {0x05, 0x05, 0x01}, |
281 | {0x05, 0x00, 0xc1}, |
282 | /* */ |
283 | {0x05, 0x00, 0xc2}, |
284 | {0x05, 0x00, 0xca}, |
285 | |
286 | {0x06, 0x70, 0x51}, |
287 | {0x06, 0xbe, 0x53}, |
288 | {} |
289 | }; |
290 | |
291 | /* |
292 | * Made by Tomasz Zablocki (skalamandra@poczta.onet.pl) |
293 | * SPCA505b chip based cameras initialization data |
294 | */ |
295 | /* jfm */ |
296 | #define initial_brightness 0x7f /* 0x0(white)-0xff(black) */ |
297 | /* #define initial_brightness 0x0 //0x0(white)-0xff(black) */ |
298 | /* |
299 | * Data to initialize a SPCA505. Common to the CCD and external modes |
300 | */ |
301 | static const u8 spca505b_init_data[][3] = { |
302 | /* start */ |
303 | {0x02, 0x00, 0x00}, /* init */ |
304 | {0x02, 0x00, 0x01}, |
305 | {0x02, 0x00, 0x02}, |
306 | {0x02, 0x00, 0x03}, |
307 | {0x02, 0x00, 0x04}, |
308 | {0x02, 0x00, 0x05}, |
309 | {0x02, 0x00, 0x06}, |
310 | {0x02, 0x00, 0x07}, |
311 | {0x02, 0x00, 0x08}, |
312 | {0x02, 0x00, 0x09}, |
313 | {0x03, 0x00, 0x00}, |
314 | {0x03, 0x00, 0x01}, |
315 | {0x03, 0x00, 0x02}, |
316 | {0x03, 0x00, 0x03}, |
317 | {0x03, 0x00, 0x04}, |
318 | {0x03, 0x00, 0x05}, |
319 | {0x03, 0x00, 0x06}, |
320 | {0x04, 0x00, 0x00}, |
321 | {0x04, 0x00, 0x02}, |
322 | {0x04, 0x00, 0x04}, |
323 | {0x04, 0x00, 0x05}, |
324 | {0x04, 0x00, 0x06}, |
325 | {0x04, 0x00, 0x07}, |
326 | {0x04, 0x00, 0x08}, |
327 | {0x04, 0x00, 0x09}, |
328 | {0x04, 0x00, 0x0a}, |
329 | {0x04, 0x00, 0x0b}, |
330 | {0x04, 0x00, 0x0c}, |
331 | {0x07, 0x00, 0x00}, |
332 | {0x07, 0x00, 0x03}, |
333 | {0x08, 0x00, 0x00}, |
334 | {0x08, 0x00, 0x01}, |
335 | {0x08, 0x00, 0x02}, |
336 | {0x06, 0x18, 0x08}, |
337 | {0x06, 0xfc, 0x09}, |
338 | {0x06, 0xfc, 0x0a}, |
339 | {0x06, 0xfc, 0x0b}, |
340 | {0x06, 0x18, 0x0c}, |
341 | {0x06, 0xfc, 0x0d}, |
342 | {0x06, 0xfc, 0x0e}, |
343 | {0x06, 0xfc, 0x0f}, |
344 | {0x06, 0x18, 0x10}, |
345 | {0x06, 0xfe, 0x12}, |
346 | {0x06, 0x00, 0x11}, |
347 | {0x06, 0x00, 0x14}, |
348 | {0x06, 0x00, 0x13}, |
349 | {0x06, 0x28, 0x51}, |
350 | {0x06, 0xff, 0x53}, |
351 | {0x02, 0x00, 0x08}, |
352 | |
353 | {0x03, 0x00, 0x03}, |
354 | {0x03, 0x10, 0x03}, |
355 | {} |
356 | }; |
357 | |
358 | /* |
359 | * Data to initialize the camera using the internal CCD |
360 | */ |
361 | static const u8 spca505b_open_data_ccd[][3] = { |
362 | |
363 | /* {0x02,0x00,0x00}, */ |
364 | {0x03, 0x04, 0x01}, /* rst */ |
365 | {0x03, 0x00, 0x01}, |
366 | {0x03, 0x00, 0x00}, |
367 | {0x03, 0x21, 0x00}, |
368 | {0x03, 0x00, 0x04}, |
369 | {0x03, 0x00, 0x03}, |
370 | {0x03, 0x18, 0x03}, |
371 | {0x03, 0x08, 0x01}, |
372 | {0x03, 0x1c, 0x03}, |
373 | {0x03, 0x5c, 0x03}, |
374 | {0x03, 0x5c, 0x03}, |
375 | {0x03, 0x18, 0x01}, |
376 | |
377 | /* same as 505 */ |
378 | {0x04, 0x10, 0x01}, |
379 | {0x04, 0x00, 0x04}, |
380 | {0x04, 0x00, 0x05}, |
381 | {0x04, 0x20, 0x06}, |
382 | {0x04, 0x20, 0x07}, |
383 | |
384 | {0x08, 0x0a, 0x00}, |
385 | |
386 | {0x05, 0x00, 0x10}, |
387 | {0x05, 0x00, 0x11}, |
388 | {0x05, 0x00, 0x12}, |
389 | {0x05, 0x6f, 0x00}, |
390 | {0x05, initial_brightness >> 6, 0x00}, |
391 | {0x05, (initial_brightness << 2) & 0xff, 0x01}, |
392 | {0x05, 0x00, 0x02}, |
393 | {0x05, 0x01, 0x03}, |
394 | {0x05, 0x00, 0x04}, |
395 | {0x05, 0x03, 0x05}, |
396 | {0x05, 0xe0, 0x06}, |
397 | {0x05, 0x20, 0x07}, |
398 | {0x05, 0xa0, 0x08}, |
399 | {0x05, 0x00, 0x12}, |
400 | {0x05, 0x02, 0x0f}, |
401 | {0x05, 0x80, 0x14}, /* max exposure off (0=on) */ |
402 | {0x05, 0x01, 0xb0}, |
403 | {0x05, 0x01, 0xbf}, |
404 | {0x03, 0x02, 0x06}, |
405 | {0x05, 0x10, 0x46}, |
406 | {0x05, 0x08, 0x4a}, |
407 | |
408 | {0x06, 0x00, 0x01}, |
409 | {0x06, 0x10, 0x02}, |
410 | {0x06, 0x64, 0x07}, |
411 | {0x06, 0x18, 0x08}, |
412 | {0x06, 0xfc, 0x09}, |
413 | {0x06, 0xfc, 0x0a}, |
414 | {0x06, 0xfc, 0x0b}, |
415 | {0x04, 0x00, 0x01}, |
416 | {0x06, 0x18, 0x0c}, |
417 | {0x06, 0xfc, 0x0d}, |
418 | {0x06, 0xfc, 0x0e}, |
419 | {0x06, 0xfc, 0x0f}, |
420 | {0x06, 0x11, 0x10}, /* contrast */ |
421 | {0x06, 0x00, 0x11}, |
422 | {0x06, 0xfe, 0x12}, |
423 | {0x06, 0x00, 0x13}, |
424 | {0x06, 0x00, 0x14}, |
425 | {0x06, 0x9d, 0x51}, |
426 | {0x06, 0x40, 0x52}, |
427 | {0x06, 0x7c, 0x53}, |
428 | {0x06, 0x40, 0x54}, |
429 | {0x06, 0x02, 0x57}, |
430 | {0x06, 0x03, 0x58}, |
431 | {0x06, 0x15, 0x59}, |
432 | {0x06, 0x05, 0x5a}, |
433 | {0x06, 0x03, 0x56}, |
434 | {0x06, 0x02, 0x3f}, |
435 | {0x06, 0x00, 0x40}, |
436 | {0x06, 0x39, 0x41}, |
437 | {0x06, 0x69, 0x42}, |
438 | {0x06, 0x87, 0x43}, |
439 | {0x06, 0x9e, 0x44}, |
440 | {0x06, 0xb1, 0x45}, |
441 | {0x06, 0xbf, 0x46}, |
442 | {0x06, 0xcc, 0x47}, |
443 | {0x06, 0xd5, 0x48}, |
444 | {0x06, 0xdd, 0x49}, |
445 | {0x06, 0xe3, 0x4a}, |
446 | {0x06, 0xe8, 0x4b}, |
447 | {0x06, 0xed, 0x4c}, |
448 | {0x06, 0xf2, 0x4d}, |
449 | {0x06, 0xf7, 0x4e}, |
450 | {0x06, 0xfc, 0x4f}, |
451 | {0x06, 0xff, 0x50}, |
452 | |
453 | {0x05, 0x01, 0xc0}, |
454 | {0x05, 0x10, 0xcb}, |
455 | {0x05, 0x40, 0xc1}, |
456 | {0x05, 0x04, 0xc2}, |
457 | {0x05, 0x00, 0xca}, |
458 | {0x05, 0x40, 0xc1}, |
459 | {0x05, 0x09, 0xc2}, |
460 | {0x05, 0x00, 0xca}, |
461 | {0x05, 0xc0, 0xc1}, |
462 | {0x05, 0x09, 0xc2}, |
463 | {0x05, 0x00, 0xca}, |
464 | {0x05, 0x40, 0xc1}, |
465 | {0x05, 0x59, 0xc2}, |
466 | {0x05, 0x00, 0xca}, |
467 | {0x04, 0x00, 0x01}, |
468 | {0x05, 0x80, 0xc1}, |
469 | {0x05, 0xec, 0xc2}, |
470 | {0x05, 0x0, 0xca}, |
471 | |
472 | {0x06, 0x02, 0x57}, |
473 | {0x06, 0x01, 0x58}, |
474 | {0x06, 0x15, 0x59}, |
475 | {0x06, 0x0a, 0x5a}, |
476 | {0x06, 0x01, 0x57}, |
477 | {0x06, 0x8a, 0x03}, |
478 | {0x06, 0x0a, 0x6c}, |
479 | {0x06, 0x30, 0x01}, |
480 | {0x06, 0x20, 0x02}, |
481 | {0x06, 0x00, 0x03}, |
482 | |
483 | {0x05, 0x8c, 0x25}, |
484 | |
485 | {0x06, 0x4d, 0x51}, /* maybe saturation (4d) */ |
486 | {0x06, 0x84, 0x53}, /* making green (84) */ |
487 | {0x06, 0x00, 0x57}, /* sharpness (1) */ |
488 | {0x06, 0x18, 0x08}, |
489 | {0x06, 0xfc, 0x09}, |
490 | {0x06, 0xfc, 0x0a}, |
491 | {0x06, 0xfc, 0x0b}, |
492 | {0x06, 0x18, 0x0c}, /* maybe hue (18) */ |
493 | {0x06, 0xfc, 0x0d}, |
494 | {0x06, 0xfc, 0x0e}, |
495 | {0x06, 0xfc, 0x0f}, |
496 | {0x06, 0x18, 0x10}, /* maybe contrast (18) */ |
497 | |
498 | {0x05, 0x01, 0x02}, |
499 | |
500 | {0x04, 0x00, 0x08}, /* compression */ |
501 | {0x04, 0x12, 0x09}, |
502 | {0x04, 0x21, 0x0a}, |
503 | {0x04, 0x10, 0x0b}, |
504 | {0x04, 0x21, 0x0c}, |
505 | {0x04, 0x1d, 0x00}, /* imagetype (1d) */ |
506 | {0x04, 0x41, 0x01}, /* hardware snapcontrol */ |
507 | |
508 | {0x04, 0x00, 0x04}, |
509 | {0x04, 0x00, 0x05}, |
510 | {0x04, 0x10, 0x06}, |
511 | {0x04, 0x10, 0x07}, |
512 | {0x04, 0x40, 0x06}, |
513 | {0x04, 0x40, 0x07}, |
514 | {0x04, 0x00, 0x04}, |
515 | {0x04, 0x00, 0x05}, |
516 | |
517 | {0x06, 0x1c, 0x17}, |
518 | {0x06, 0xe2, 0x19}, |
519 | {0x06, 0x1c, 0x1b}, |
520 | {0x06, 0xe2, 0x1d}, |
521 | {0x06, 0x5f, 0x1f}, |
522 | {0x06, 0x32, 0x20}, |
523 | |
524 | {0x05, initial_brightness >> 6, 0x00}, |
525 | {0x05, (initial_brightness << 2) & 0xff, 0x01}, |
526 | {0x05, 0x06, 0xc1}, |
527 | {0x05, 0x58, 0xc2}, |
528 | {0x05, 0x00, 0xca}, |
529 | {0x05, 0x00, 0x11}, |
530 | {} |
531 | }; |
532 | |
533 | static int reg_write(struct gspca_dev *gspca_dev, |
534 | u16 req, u16 index, u16 value) |
535 | { |
536 | int ret; |
537 | struct usb_device *dev = gspca_dev->dev; |
538 | |
539 | ret = usb_control_msg(dev, |
540 | usb_sndctrlpipe(dev, 0), |
541 | request: req, |
542 | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
543 | value, index, NULL, size: 0, timeout: 500); |
544 | gspca_dbg(gspca_dev, D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d\n" , |
545 | req, index, value, ret); |
546 | if (ret < 0) |
547 | pr_err("reg write: error %d\n" , ret); |
548 | return ret; |
549 | } |
550 | |
551 | /* returns: negative is error, pos or zero is data */ |
552 | static int reg_read(struct gspca_dev *gspca_dev, |
553 | u16 req, /* bRequest */ |
554 | u16 index) /* wIndex */ |
555 | { |
556 | int ret; |
557 | |
558 | ret = usb_control_msg(dev: gspca_dev->dev, |
559 | usb_rcvctrlpipe(gspca_dev->dev, 0), |
560 | request: req, |
561 | USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, |
562 | value: 0, /* value */ |
563 | index, |
564 | data: gspca_dev->usb_buf, size: 2, |
565 | timeout: 500); /* timeout */ |
566 | if (ret < 0) |
567 | return ret; |
568 | return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0]; |
569 | } |
570 | |
571 | static int write_vector(struct gspca_dev *gspca_dev, |
572 | const u8 data[][3]) |
573 | { |
574 | int ret, i = 0; |
575 | |
576 | while (data[i][0] != 0) { |
577 | ret = reg_write(gspca_dev, req: data[i][0], index: data[i][2], |
578 | value: data[i][1]); |
579 | if (ret < 0) |
580 | return ret; |
581 | i++; |
582 | } |
583 | return 0; |
584 | } |
585 | |
586 | /* this function is called at probe time */ |
587 | static int sd_config(struct gspca_dev *gspca_dev, |
588 | const struct usb_device_id *id) |
589 | { |
590 | struct sd *sd = (struct sd *) gspca_dev; |
591 | struct cam *cam; |
592 | |
593 | cam = &gspca_dev->cam; |
594 | cam->cam_mode = vga_mode; |
595 | sd->subtype = id->driver_info; |
596 | if (sd->subtype != IntelPCCameraPro) |
597 | cam->nmodes = ARRAY_SIZE(vga_mode); |
598 | else /* no 640x480 for IntelPCCameraPro */ |
599 | cam->nmodes = ARRAY_SIZE(vga_mode) - 1; |
600 | |
601 | return 0; |
602 | } |
603 | |
604 | /* this function is called at probe and resume time */ |
605 | static int sd_init(struct gspca_dev *gspca_dev) |
606 | { |
607 | struct sd *sd = (struct sd *) gspca_dev; |
608 | |
609 | if (write_vector(gspca_dev, |
610 | data: sd->subtype == Nxultra |
611 | ? spca505b_init_data |
612 | : spca505_init_data)) |
613 | return -EIO; |
614 | return 0; |
615 | } |
616 | |
617 | static void setbrightness(struct gspca_dev *gspca_dev, s32 brightness) |
618 | { |
619 | reg_write(gspca_dev, req: 0x05, index: 0x00, value: (255 - brightness) >> 6); |
620 | reg_write(gspca_dev, req: 0x05, index: 0x01, value: (255 - brightness) << 2); |
621 | } |
622 | |
623 | static int sd_start(struct gspca_dev *gspca_dev) |
624 | { |
625 | struct sd *sd = (struct sd *) gspca_dev; |
626 | int ret, mode; |
627 | static u8 mode_tb[][3] = { |
628 | /* r00 r06 r07 */ |
629 | {0x00, 0x10, 0x10}, /* 640x480 */ |
630 | {0x01, 0x1a, 0x1a}, /* 352x288 */ |
631 | {0x02, 0x1c, 0x1d}, /* 320x240 */ |
632 | {0x04, 0x34, 0x34}, /* 176x144 */ |
633 | {0x05, 0x40, 0x40} /* 160x120 */ |
634 | }; |
635 | |
636 | if (sd->subtype == Nxultra) |
637 | write_vector(gspca_dev, data: spca505b_open_data_ccd); |
638 | else |
639 | write_vector(gspca_dev, data: spca505_open_data_ccd); |
640 | ret = reg_read(gspca_dev, req: 0x06, index: 0x16); |
641 | |
642 | if (ret < 0) { |
643 | gspca_err(gspca_dev, "register read failed err: %d\n" , ret); |
644 | return ret; |
645 | } |
646 | if (ret != 0x0101) { |
647 | pr_err("After vector read returns 0x%04x should be 0x0101\n" , |
648 | ret); |
649 | } |
650 | |
651 | ret = reg_write(gspca_dev, req: 0x06, index: 0x16, value: 0x0a); |
652 | if (ret < 0) |
653 | return ret; |
654 | reg_write(gspca_dev, req: 0x05, index: 0xc2, value: 0x12); |
655 | |
656 | /* necessary because without it we can see stream |
657 | * only once after loading module */ |
658 | /* stopping usb registers Tomasz change */ |
659 | reg_write(gspca_dev, req: 0x02, index: 0x00, value: 0x00); |
660 | |
661 | mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv; |
662 | reg_write(gspca_dev, SPCA50X_REG_COMPRESS, index: 0x00, value: mode_tb[mode][0]); |
663 | reg_write(gspca_dev, SPCA50X_REG_COMPRESS, index: 0x06, value: mode_tb[mode][1]); |
664 | reg_write(gspca_dev, SPCA50X_REG_COMPRESS, index: 0x07, value: mode_tb[mode][2]); |
665 | |
666 | return reg_write(gspca_dev, SPCA50X_REG_USB, |
667 | SPCA50X_USB_CTRL, |
668 | SPCA50X_CUSB_ENABLE); |
669 | } |
670 | |
671 | static void sd_stopN(struct gspca_dev *gspca_dev) |
672 | { |
673 | /* Disable ISO packet machine */ |
674 | reg_write(gspca_dev, req: 0x02, index: 0x00, value: 0x00); |
675 | } |
676 | |
677 | /* called on streamoff with alt 0 and on disconnect */ |
678 | static void sd_stop0(struct gspca_dev *gspca_dev) |
679 | { |
680 | if (!gspca_dev->present) |
681 | return; |
682 | |
683 | /* This maybe reset or power control */ |
684 | reg_write(gspca_dev, req: 0x03, index: 0x03, value: 0x20); |
685 | reg_write(gspca_dev, req: 0x03, index: 0x01, value: 0x00); |
686 | reg_write(gspca_dev, req: 0x03, index: 0x00, value: 0x01); |
687 | reg_write(gspca_dev, req: 0x05, index: 0x10, value: 0x01); |
688 | reg_write(gspca_dev, req: 0x05, index: 0x11, value: 0x0f); |
689 | } |
690 | |
691 | static void sd_pkt_scan(struct gspca_dev *gspca_dev, |
692 | u8 *data, /* isoc packet */ |
693 | int len) /* iso packet length */ |
694 | { |
695 | switch (data[0]) { |
696 | case 0: /* start of frame */ |
697 | gspca_frame_add(gspca_dev, packet_type: LAST_PACKET, NULL, len: 0); |
698 | data += SPCA50X_OFFSET_DATA; |
699 | len -= SPCA50X_OFFSET_DATA; |
700 | gspca_frame_add(gspca_dev, packet_type: FIRST_PACKET, data, len); |
701 | break; |
702 | case 0xff: /* drop */ |
703 | break; |
704 | default: |
705 | data += 1; |
706 | len -= 1; |
707 | gspca_frame_add(gspca_dev, packet_type: INTER_PACKET, data, len); |
708 | break; |
709 | } |
710 | } |
711 | |
712 | static int sd_s_ctrl(struct v4l2_ctrl *ctrl) |
713 | { |
714 | struct gspca_dev *gspca_dev = |
715 | container_of(ctrl->handler, struct gspca_dev, ctrl_handler); |
716 | |
717 | gspca_dev->usb_err = 0; |
718 | |
719 | if (!gspca_dev->streaming) |
720 | return 0; |
721 | |
722 | switch (ctrl->id) { |
723 | case V4L2_CID_BRIGHTNESS: |
724 | setbrightness(gspca_dev, brightness: ctrl->val); |
725 | break; |
726 | } |
727 | return gspca_dev->usb_err; |
728 | } |
729 | |
730 | static const struct v4l2_ctrl_ops sd_ctrl_ops = { |
731 | .s_ctrl = sd_s_ctrl, |
732 | }; |
733 | |
734 | static int sd_init_controls(struct gspca_dev *gspca_dev) |
735 | { |
736 | struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler; |
737 | |
738 | gspca_dev->vdev.ctrl_handler = hdl; |
739 | v4l2_ctrl_handler_init(hdl, 5); |
740 | v4l2_ctrl_new_std(hdl, ops: &sd_ctrl_ops, |
741 | V4L2_CID_BRIGHTNESS, min: 0, max: 255, step: 1, def: 127); |
742 | |
743 | if (hdl->error) { |
744 | pr_err("Could not initialize controls\n" ); |
745 | return hdl->error; |
746 | } |
747 | return 0; |
748 | } |
749 | |
750 | /* sub-driver description */ |
751 | static const struct sd_desc sd_desc = { |
752 | .name = MODULE_NAME, |
753 | .config = sd_config, |
754 | .init_controls = sd_init_controls, |
755 | .init = sd_init, |
756 | .start = sd_start, |
757 | .stopN = sd_stopN, |
758 | .stop0 = sd_stop0, |
759 | .pkt_scan = sd_pkt_scan, |
760 | }; |
761 | |
762 | /* -- module initialisation -- */ |
763 | static const struct usb_device_id device_table[] = { |
764 | {USB_DEVICE(0x041e, 0x401d), .driver_info = Nxultra}, |
765 | {USB_DEVICE(0x0733, 0x0430), .driver_info = IntelPCCameraPro}, |
766 | /*fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */ |
767 | {} |
768 | }; |
769 | MODULE_DEVICE_TABLE(usb, device_table); |
770 | |
771 | /* -- device connect -- */ |
772 | static int sd_probe(struct usb_interface *intf, |
773 | const struct usb_device_id *id) |
774 | { |
775 | return gspca_dev_probe(intf, id, sd_desc: &sd_desc, dev_size: sizeof(struct sd), |
776 | THIS_MODULE); |
777 | } |
778 | |
779 | static struct usb_driver sd_driver = { |
780 | .name = MODULE_NAME, |
781 | .id_table = device_table, |
782 | .probe = sd_probe, |
783 | .disconnect = gspca_disconnect, |
784 | #ifdef CONFIG_PM |
785 | .suspend = gspca_suspend, |
786 | .resume = gspca_resume, |
787 | .reset_resume = gspca_resume, |
788 | #endif |
789 | }; |
790 | |
791 | module_usb_driver(sd_driver); |
792 | |