Commit | Line | Data |
---|---|---|
702422bd T |
1 | /***************************************************************************** |
2 | * * | |
3 | * * | |
4 | * easycap_low.c * | |
5 | * * | |
6 | * * | |
7 | *****************************************************************************/ | |
8 | /* | |
9 | * | |
10 | * Copyright (C) 2010 R.M. Thomas <rmthomas@sciolus.org> | |
11 | * | |
12 | * | |
13 | * This is free software; you can redistribute it and/or modify | |
14 | * it under the terms of the GNU General Public License as published by | |
15 | * the Free Software Foundation; either version 2 of the License, or | |
16 | * (at your option) any later version. | |
17 | * | |
18 | * The software is distributed in the hope that it will be useful, | |
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 | * GNU General Public License for more details. | |
22 | * | |
23 | * You should have received a copy of the GNU General Public License | |
24 | * along with this software; if not, write to the Free Software | |
25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
26 | * | |
27 | */ | |
28 | /*****************************************************************************/ | |
29 | /* | |
30 | * ACKNOWLEGEMENTS AND REFERENCES | |
31 | * ------------------------------ | |
32 | * This driver makes use of register information contained in the Syntek | |
33 | * Semicon DC-1125 driver hosted at | |
34 | * http://sourceforge.net/projects/syntekdriver/. | |
35 | * Particularly useful has been a patch to the latter driver provided by | |
36 | * Ivor Hewitt in January 2009. The NTSC implementation is taken from the | |
37 | * work of Ben Trask. | |
38 | */ | |
39 | /****************************************************************************/ | |
40 | ||
41 | #include "easycap_debug.h" | |
42 | #include "easycap.h" | |
43 | ||
44 | /*--------------------------------------------------------------------------*/ | |
45 | const struct stk1160config { int reg; int set; } stk1160config[256] = { | |
46 | {0x000, 0x0098}, | |
47 | {0x002, 0x0093}, | |
48 | ||
49 | {0x001, 0x0003}, | |
50 | {0x003, 0x0080}, | |
51 | {0x00D, 0x0000}, | |
52 | {0x00F, 0x0002}, | |
53 | {0x018, 0x0010}, | |
54 | {0x019, 0x0000}, | |
55 | {0x01A, 0x0014}, | |
56 | {0x01B, 0x000E}, | |
57 | {0x01C, 0x0046}, | |
58 | ||
59 | {0x100, 0x0033}, | |
60 | {0x103, 0x0000}, | |
61 | {0x104, 0x0000}, | |
62 | {0x105, 0x0000}, | |
63 | {0x106, 0x0000}, | |
64 | ||
65 | #if defined(PREFER_NTSC) | |
66 | ||
67 | #undef OLDMARGIN | |
68 | #if defined(OLDMARGIN) | |
69 | {0x110, 0x0008}, | |
70 | #else | |
71 | {0x110, 0x0014}, | |
72 | #endif /*OLDMARGIN*/ | |
73 | ||
74 | {0x111, 0x0000}, | |
75 | {0x112, 0x0003}, | |
76 | {0x113, 0x0000}, | |
77 | ||
78 | #if defined(OLDMARGIN) | |
79 | {0x114, 0x0508}, | |
80 | #else | |
81 | {0x114, 0x0514}, | |
82 | #endif /*OLDMARGIN*/ | |
83 | ||
84 | {0x115, 0x0005}, | |
85 | {0x116, 0x00F3}, | |
86 | {0x117, 0x0000}, | |
87 | ||
88 | #else /* ! PREFER_NTSC*/ | |
89 | ||
90 | #if defined(OLDMARGIN) | |
91 | {0x110, 0x0008}, | |
92 | #else | |
93 | {0x110, 0x0014}, | |
94 | #endif /*OLDMARGIN*/ | |
95 | ||
96 | {0x111, 0x0000}, | |
97 | {0x112, 0x0020}, | |
98 | {0x113, 0x0000}, | |
99 | ||
100 | #if defined(OLDMARGIN) | |
101 | {0x114, 0x0508}, | |
102 | #else | |
103 | {0x114, 0x0514}, | |
104 | #endif /*OLDMARGIN*/ | |
105 | ||
106 | {0x115, 0x0005}, | |
107 | {0x116, 0x0110}, | |
108 | {0x117, 0x0001}, | |
109 | ||
110 | #endif /* ! PREFER_NTSC*/ | |
111 | ||
112 | {0x202, 0x000F}, | |
113 | {0x203, 0x004A}, | |
114 | {0x2FF, 0x0000}, | |
115 | /*---------------------------------------------------------------------------*/ | |
116 | {0xFFF, 0xFFFF} | |
117 | }; | |
118 | /*--------------------------------------------------------------------------*/ | |
119 | const struct saa7113config { int reg; int set; } saa7113config[256] = { | |
120 | {0x01, 0x08}, | |
121 | {0x02, 0x80}, | |
122 | {0x03, 0x33}, | |
123 | {0x04, 0x00}, | |
124 | {0x05, 0x00}, | |
125 | {0x06, 0xE9}, | |
126 | {0x07, 0x0D}, | |
127 | #if defined(PREFER_NTSC) | |
128 | {0x08, 0x78}, | |
129 | #else | |
130 | {0x08, 0x38}, | |
131 | #endif /* ! PREFER_NTSC*/ | |
132 | {0x09, 0x00}, | |
133 | {0x0A, SAA_0A_DEFAULT}, | |
134 | {0x0B, SAA_0B_DEFAULT}, | |
135 | {0x0C, SAA_0C_DEFAULT}, | |
136 | {0x0D, SAA_0D_DEFAULT}, | |
137 | {0x0E, 0x01}, | |
138 | {0x0F, 0x36}, | |
139 | {0x10, 0x00}, | |
140 | {0x11, 0x0C}, | |
141 | {0x12, 0xE7}, | |
142 | {0x13, 0x00}, | |
143 | {0x15, 0x00}, | |
144 | {0x16, 0x00}, | |
145 | #if defined(PREFER_NTSC) | |
146 | {0x40, 0x82}, | |
147 | #else | |
148 | {0x40, 0x02}, | |
149 | #endif /* ! PREFER_NTSC*/ | |
150 | {0x41, 0xFF}, | |
151 | {0x42, 0xFF}, | |
152 | {0x43, 0xFF}, | |
153 | {0x44, 0xFF}, | |
154 | {0x45, 0xFF}, | |
155 | {0x46, 0xFF}, | |
156 | {0x47, 0xFF}, | |
157 | {0x48, 0xFF}, | |
158 | {0x49, 0xFF}, | |
159 | {0x4A, 0xFF}, | |
160 | {0x4B, 0xFF}, | |
161 | {0x4C, 0xFF}, | |
162 | {0x4D, 0xFF}, | |
163 | {0x4E, 0xFF}, | |
164 | {0x4F, 0xFF}, | |
165 | {0x50, 0xFF}, | |
166 | {0x51, 0xFF}, | |
167 | {0x52, 0xFF}, | |
168 | {0x53, 0xFF}, | |
169 | {0x54, 0xFF}, | |
170 | {0x55, 0xFF}, | |
171 | {0x56, 0xFF}, | |
172 | {0x57, 0xFF}, | |
173 | {0x58, 0x40}, | |
174 | {0x59, 0x54}, | |
175 | #if defined(PREFER_NTSC) | |
176 | {0x5A, 0x0A}, | |
177 | #else | |
178 | {0x5A, 0x07}, | |
179 | #endif /* ! PREFER_NTSC*/ | |
180 | {0x5B, 0x83}, | |
181 | {0xFF, 0xFF} | |
182 | }; | |
183 | /*--------------------------------------------------------------------------*/ | |
184 | ||
185 | /****************************************************************************/ | |
186 | int | |
187 | confirm_resolution(struct usb_device *p) | |
188 | { | |
189 | __u8 get0, get1, get2, get3, get4, get5, get6, get7; | |
190 | GET(p, 0x0110, &get0); | |
191 | GET(p, 0x0111, &get1); | |
192 | GET(p, 0x0112, &get2); | |
193 | GET(p, 0x0113, &get3); | |
194 | GET(p, 0x0114, &get4); | |
195 | GET(p, 0x0115, &get5); | |
196 | GET(p, 0x0116, &get6); | |
197 | GET(p, 0x0117, &get7); | |
198 | JOT(8, "0x%03X, 0x%03X, " \ | |
199 | "0x%03X, 0x%03X, " \ | |
200 | "0x%03X, 0x%03X, " \ | |
201 | "0x%03X, 0x%03X\n", \ | |
202 | get0, get1, get2, get3, get4, get5, get6, get7); | |
203 | JOT(8, "....cf PAL_720x526: " \ | |
204 | "0x%03X, 0x%03X, " \ | |
205 | "0x%03X, 0x%03X, " \ | |
206 | "0x%03X, 0x%03X, " \ | |
207 | "0x%03X, 0x%03X\n", \ | |
208 | 0x000, 0x000, 0x001, 0x000, 0x5A0, 0x005, 0x121, 0x001); | |
209 | JOT(8, "....cf PAL_704x526: " \ | |
210 | "0x%03X, 0x%03X, " \ | |
211 | "0x%03X, 0x%03X, " \ | |
212 | "0x%03X, 0x%03X, " \ | |
213 | "0x%03X, 0x%03X\n", \ | |
214 | 0x004, 0x000, 0x001, 0x000, 0x584, 0x005, 0x121, 0x001); | |
215 | JOT(8, "....cf VGA_640x480: " \ | |
216 | "0x%03X, 0x%03X, " \ | |
217 | "0x%03X, 0x%03X, " \ | |
218 | "0x%03X, 0x%03X, " \ | |
219 | "0x%03X, 0x%03X\n", \ | |
220 | 0x008, 0x000, 0x020, 0x000, 0x508, 0x005, 0x110, 0x001); | |
221 | return 0; | |
222 | } | |
223 | /****************************************************************************/ | |
224 | int | |
225 | confirm_stream(struct usb_device *p) | |
226 | { | |
227 | __u16 get2; | |
228 | __u8 igot; | |
229 | ||
230 | GET(p, 0x0100, &igot); get2 = 0x80 & igot; | |
231 | if (0x80 == get2) | |
232 | JOT(8, "confirm_stream: OK\n"); | |
233 | else | |
234 | JOT(8, "confirm_stream: STUCK\n"); | |
235 | return 0; | |
236 | } | |
237 | /****************************************************************************/ | |
238 | int | |
239 | setup_stk(struct usb_device *p) | |
240 | { | |
241 | int i0; | |
242 | ||
243 | i0 = 0; | |
244 | while (0xFFF != stk1160config[i0].reg) { | |
245 | SET(p, stk1160config[i0].reg, stk1160config[i0].set); | |
246 | i0++; | |
247 | } | |
248 | ||
249 | write_300(p); | |
250 | ||
251 | return 0; | |
252 | } | |
253 | /****************************************************************************/ | |
254 | int | |
255 | setup_saa(struct usb_device *p) | |
256 | { | |
257 | int i0, ir; | |
258 | ||
259 | ||
260 | set2to78(p); | |
261 | ||
262 | ||
263 | i0 = 0; | |
264 | while (0xFF != saa7113config[i0].reg) { | |
265 | ir = write_saa(p, saa7113config[i0].reg, saa7113config[i0].set); | |
266 | i0++; | |
267 | } | |
268 | return 0; | |
269 | } | |
270 | /****************************************************************************/ | |
271 | int | |
272 | write_000(struct usb_device *p, __u16 set2, __u16 set0) | |
273 | { | |
274 | __u8 igot0, igot2; | |
275 | ||
276 | GET(p, 0x0002, &igot2); | |
277 | GET(p, 0x0000, &igot0); | |
278 | SET(p, 0x0002, set2); | |
279 | SET(p, 0x0000, set0); | |
280 | return 0; | |
281 | } | |
282 | /****************************************************************************/ | |
283 | int | |
284 | write_saa(struct usb_device *p, __u16 reg0, __u16 set0) | |
285 | { | |
286 | SET(p, 0x200, 0x00); | |
287 | SET(p, 0x204, reg0); | |
288 | SET(p, 0x205, set0); | |
289 | SET(p, 0x200, 0x01); | |
290 | return wait_i2c(p); | |
291 | } | |
292 | /****************************************************************************/ | |
293 | /*--------------------------------------------------------------------------*/ | |
294 | /* | |
295 | * REGISTER 500: SETTING VALUE TO 0x008B READS FROM VT1612A (?) | |
296 | * REGISTER 500: SETTING VALUE TO 0x008C WRITES TO VT1612A | |
297 | * REGISTER 502: LEAST SIGNIFICANT BYTE OF VALUE TO SET | |
298 | * REGISTER 503: MOST SIGNIFICANT BYTE OF VALUE TO SET | |
299 | * REGISTER 504: TARGET ADDRESS ON VT1612A | |
300 | */ | |
301 | /*--------------------------------------------------------------------------*/ | |
302 | int | |
303 | write_vt(struct usb_device *p, __u16 reg0, __u16 set0) | |
304 | { | |
305 | __u8 igot; | |
306 | __u16 got502, got503; | |
307 | __u16 set502, set503; | |
308 | ||
309 | SET(p, 0x0504, reg0); | |
310 | SET(p, 0x0500, 0x008B); | |
311 | ||
312 | GET(p, 0x0502, &igot); got502 = (0xFF & igot); | |
313 | GET(p, 0x0503, &igot); got503 = (0xFF & igot); | |
314 | ||
315 | JOT(16, "write_vt(., 0x%04X, 0x%04X): was 0x%04X\n", \ | |
316 | reg0, set0, ((got503 << 8) | got502)); | |
317 | ||
318 | set502 = (0x00FF & set0); | |
319 | set503 = ((0xFF00 & set0) >> 8); | |
320 | ||
321 | SET(p, 0x0504, reg0); | |
322 | SET(p, 0x0502, set502); | |
323 | SET(p, 0x0503, set503); | |
324 | SET(p, 0x0500, 0x008C); | |
325 | ||
326 | return 0; | |
327 | } | |
328 | /****************************************************************************/ | |
329 | /*--------------------------------------------------------------------------*/ | |
330 | /* | |
331 | * REGISTER 500: SETTING VALUE TO 0x008B READS FROM VT1612A (?) | |
332 | * REGISTER 500: SETTING VALUE TO 0x008C WRITES TO VT1612A | |
333 | * REGISTER 502: LEAST SIGNIFICANT BYTE OF VALUE TO GET | |
334 | * REGISTER 503: MOST SIGNIFICANT BYTE OF VALUE TO GET | |
335 | * REGISTER 504: TARGET ADDRESS ON VT1612A | |
336 | */ | |
337 | /*--------------------------------------------------------------------------*/ | |
338 | int | |
339 | read_vt(struct usb_device *p, __u16 reg0) | |
340 | { | |
341 | __u8 igot; | |
342 | __u16 got502, got503; | |
343 | ||
344 | SET(p, 0x0504, reg0); | |
345 | SET(p, 0x0500, 0x008B); | |
346 | ||
347 | GET(p, 0x0502, &igot); got502 = (0xFF & igot); | |
348 | GET(p, 0x0503, &igot); got503 = (0xFF & igot); | |
349 | ||
350 | JOT(16, "read_vt(., 0x%04X): has 0x%04X\n", reg0, ((got503 << 8) | got502)); | |
351 | ||
352 | return (got503 << 8) | got502; | |
353 | } | |
354 | /****************************************************************************/ | |
355 | /*--------------------------------------------------------------------------*/ | |
356 | /* | |
357 | * THESE APPEAR TO HAVE NO EFFECT ON EITHER VIDEO OR AUDIO. | |
358 | */ | |
359 | /*--------------------------------------------------------------------------*/ | |
360 | int | |
361 | write_300(struct usb_device *p) | |
362 | { | |
363 | SET(p, 0x300, 0x0012); | |
364 | SET(p, 0x350, 0x002D); | |
365 | SET(p, 0x351, 0x0001); | |
366 | SET(p, 0x352, 0x0000); | |
367 | SET(p, 0x353, 0x0000); | |
368 | SET(p, 0x300, 0x0080); | |
369 | return 0; | |
370 | } | |
371 | /****************************************************************************/ | |
372 | /*--------------------------------------------------------------------------*/ | |
373 | /* | |
374 | * NOTE: THE FOLLOWING IS NOT CHECKED: | |
375 | * REGISTER 0x0F, WHICH IS INVOLVED IN CHROMINANCE AUTOMATIC GAIN CONTROL. | |
376 | */ | |
377 | /*--------------------------------------------------------------------------*/ | |
378 | int | |
379 | check_saa(struct usb_device *p) | |
380 | { | |
381 | int i0, ir, rc; | |
382 | i0 = 0; | |
383 | ||
384 | rc = 0; | |
385 | while (0xFF != saa7113config[i0].reg) { | |
386 | if (0x0F == saa7113config[i0].reg) { | |
387 | i0++; continue; | |
388 | } | |
389 | ||
390 | ir = read_saa(p, saa7113config[i0].reg); | |
391 | if (ir != saa7113config[i0].set) { | |
392 | SAY("SAA register 0x%02X has 0x%02X, expected 0x%02X\n", \ | |
393 | saa7113config[i0].reg, ir, saa7113config[i0].set); | |
394 | rc--; | |
395 | } | |
396 | i0++; | |
397 | } | |
398 | if (-8 > rc) | |
399 | return rc; | |
400 | else | |
401 | return 0; | |
402 | } | |
403 | /****************************************************************************/ | |
404 | int | |
405 | merit_saa(struct usb_device *p) | |
406 | { | |
407 | int rc; | |
408 | ||
409 | rc = read_saa(p, 0x1F); | |
410 | if ((0 > rc) || (0x02 & rc)) | |
411 | return 1 ; | |
412 | else | |
413 | return 0; | |
414 | } | |
415 | /****************************************************************************/ | |
416 | int | |
417 | ready_saa(struct usb_device *p) | |
418 | { | |
419 | int j, rc; | |
420 | static int max = 10; | |
421 | ||
422 | j = 0; | |
423 | while (max > j) { | |
424 | rc = read_saa(p, 0x1F); | |
425 | if (0 <= rc) { | |
426 | if ((1 == (0x01 & rc))&&(0 == (0x40 & rc))) | |
427 | break; | |
428 | } | |
429 | msleep(100); j++; | |
430 | } | |
431 | if (max == j) | |
432 | return -1; | |
433 | else { | |
434 | if (0x20 & rc) | |
435 | JOT(8, "hardware detects 60 Hz\n"); | |
436 | else | |
437 | JOT(8, "hardware detects 50 Hz\n"); | |
438 | if (0x80 & rc) | |
439 | JOT(8, "hardware detects interlacing\n"); | |
440 | else | |
441 | JOT(8, "hardware detects no interlacing\n"); | |
442 | } | |
443 | return 0; | |
444 | } | |
445 | /****************************************************************************/ | |
446 | /*--------------------------------------------------------------------------*/ | |
447 | /* | |
448 | * NOTE: THE FOLLOWING ARE NOT CHECKED: | |
449 | * REGISTERS 0x000, 0x002: FUNCTIONALITY IS NOT KNOWN | |
450 | * REGISTER 0x100: ACCEPT ALSO (0x80 | stk1160config[.].set) | |
451 | */ | |
452 | /*--------------------------------------------------------------------------*/ | |
453 | int | |
454 | check_stk(struct usb_device *p) | |
455 | { | |
456 | int i0, ir; | |
457 | i0 = 0; | |
458 | while (0xFFF != stk1160config[i0].reg) { | |
459 | if (0x000 == stk1160config[i0].reg) { | |
460 | i0++; continue; | |
461 | } | |
462 | if (0x002 == stk1160config[i0].reg) { | |
463 | i0++; continue; | |
464 | } | |
465 | ||
466 | ir = read_stk(p, stk1160config[i0].reg); | |
467 | ||
468 | if (0x100 == stk1160config[i0].reg) { | |
469 | if ((ir != (0xFF & stk1160config[i0].set)) && \ | |
470 | (ir != (0x80 | (0xFF & stk1160config[i0].set))) && \ | |
471 | (0xFFFF != stk1160config[i0].set)) { | |
472 | SAY("STK register 0x%03X has 0x%02X, " \ | |
473 | "expected 0x%02X\n", \ | |
474 | stk1160config[i0].reg, ir, \ | |
475 | stk1160config[i0].set); | |
476 | } | |
477 | i0++; continue; | |
478 | } | |
479 | ||
480 | if ((ir != (0xFF & stk1160config[i0].set)) && \ | |
481 | (0xFFFF != stk1160config[i0].set)) { | |
482 | SAY("STK register 0x%03X has 0x%02X, " \ | |
483 | "expected 0x%02X\n", \ | |
484 | stk1160config[i0].reg, ir, \ | |
485 | stk1160config[i0].set); | |
486 | } | |
487 | i0++; | |
488 | } | |
489 | return 0; | |
490 | } | |
491 | /****************************************************************************/ | |
492 | int | |
493 | read_saa(struct usb_device *p, __u16 reg0) | |
494 | { | |
495 | __u8 igot; | |
496 | ||
497 | SET(p, 0x208, reg0); | |
498 | SET(p, 0x200, 0x20); | |
499 | if (0 != wait_i2c(p)) | |
500 | return -1; | |
501 | igot = 0; | |
502 | GET(p, 0x0209, &igot); | |
503 | return igot; | |
504 | } | |
505 | /****************************************************************************/ | |
506 | int | |
507 | read_stk(struct usb_device *p, __u32 reg0) | |
508 | { | |
509 | __u8 igot; | |
510 | ||
511 | igot = 0; | |
512 | GET(p, reg0, &igot); | |
513 | return igot; | |
514 | } | |
515 | /*****************************************************************************/ | |
516 | /*---------------------------------------------------------------------------*/ | |
517 | /* | |
518 | * HARDWARE USERSPACE INPUT NUMBER PHYSICAL INPUT DRIVER input VALUE | |
519 | * | |
520 | * CVBS+S-VIDEO 0 or 1 CVBS 1 | |
521 | * FOUR-CVBS 0 or 1 CVBS1 1 | |
522 | * FOUR-CVBS 2 CVBS2 2 | |
523 | * FOUR-CVBS 3 CVBS3 3 | |
524 | * FOUR-CVBS 4 CVBS4 4 | |
525 | * CVBS+S-VIDEO 5 S-VIDEO 5 | |
526 | * | |
527 | * WHEN 5==input THE ARGUMENT mode MUST ALSO BE SUPPLIED: | |
528 | * | |
529 | * mode 7 => GAIN TO BE SET EXPLICITLY USING REGISTER 0x05 (UNTESTED) | |
530 | * mode 9 => USE AUTOMATIC GAIN CONTROL (DEFAULT) | |
531 | * | |
532 | */ | |
533 | /*---------------------------------------------------------------------------*/ | |
534 | int | |
535 | select_input(struct usb_device *p, int input, int mode) | |
536 | { | |
537 | ||
538 | stop_100(p); | |
539 | ||
540 | msleep(20); | |
541 | switch (input) { | |
542 | case 0: | |
543 | case 1: { | |
544 | SET(p, 0x0000, 0x0098); break; | |
545 | } | |
546 | case 2: { | |
547 | SET(p, 0x0000, 0x0090); break; | |
548 | } | |
549 | case 3: { | |
550 | SET(p, 0x0000, 0x0088); break; | |
551 | } | |
552 | case 4: { | |
553 | SET(p, 0x0000, 0x0080); break; | |
554 | } | |
555 | case 5: { | |
556 | if (9 != mode) | |
557 | mode = 7; | |
558 | switch (mode) { | |
559 | case 7: | |
560 | { | |
561 | if (0 != write_saa(p, 0x02, 0x87)) { | |
562 | SAY("ERROR: failed to set SAA " \ | |
563 | "register 0x02 for input " \ | |
564 | "%i\n", input); | |
565 | } | |
566 | if (0 != write_saa(p, 0x05, 0xFF)) { | |
567 | SAY("ERROR: failed to set SAA " \ | |
568 | "register 0x05 for input " \ | |
569 | "%i\n", input); | |
570 | } | |
571 | break; | |
572 | } | |
573 | case 9: | |
574 | { | |
575 | if (0 != write_saa(p, 0x02, 0x89)) { | |
576 | SAY("ERROR: failed to set SAA " \ | |
577 | "register 0x02 for input " \ | |
578 | "%i\n", input); | |
579 | } | |
580 | if (0 != write_saa(p, 0x05, 0x00)) { | |
581 | SAY("ERROR: failed to set SAA " \ | |
582 | "register 0x05 for input " \ | |
583 | "%i\n", input); | |
584 | } | |
585 | break; | |
586 | } | |
587 | default: | |
588 | { | |
589 | SAY("MISTAKE: bad mode: %i\n", mode); | |
590 | return -1; | |
591 | } | |
592 | } | |
593 | if (0 != write_saa(p, 0x04, 0x00)) { | |
594 | SAY("ERROR: failed to set SAA register 0x04 " \ | |
595 | "for input %i\n", input); | |
596 | } | |
597 | if (0 != write_saa(p, 0x09, 0x80)) { | |
598 | SAY("ERROR: failed to set SAA register 0x09 " \ | |
599 | "for input %i\n", input); | |
600 | } | |
601 | break; | |
602 | } | |
603 | default: | |
604 | { | |
605 | SAY("ERROR: bad input: %i\n", input); | |
606 | return -1; | |
607 | } | |
608 | } | |
609 | msleep(20); | |
610 | SET(p, 0x0002, 0x0093); | |
611 | msleep(20); | |
612 | ||
613 | start_100(p); | |
614 | ||
615 | return 0; | |
616 | } | |
617 | /****************************************************************************/ | |
618 | int | |
619 | set_resolution(struct usb_device *p, \ | |
620 | __u16 set0, __u16 set1, __u16 set2, __u16 set3) | |
621 | { | |
622 | __u16 u0x0111, u0x0113, u0x0115, u0x0117; | |
623 | ||
624 | u0x0111 = ((0xFF00 & set0) >> 8); | |
625 | u0x0113 = ((0xFF00 & set1) >> 8); | |
626 | u0x0115 = ((0xFF00 & set2) >> 8); | |
627 | u0x0117 = ((0xFF00 & set3) >> 8); | |
628 | ||
629 | SET(p, 0x0110, (0x00FF & set0)); | |
630 | SET(p, 0x0111, u0x0111); | |
631 | SET(p, 0x0112, (0x00FF & set1)); | |
632 | SET(p, 0x0113, u0x0113); | |
633 | SET(p, 0x0114, (0x00FF & set2)); | |
634 | SET(p, 0x0115, u0x0115); | |
635 | SET(p, 0x0116, (0x00FF & set3)); | |
636 | SET(p, 0x0117, u0x0117); | |
637 | ||
638 | return 0; | |
639 | } | |
640 | /****************************************************************************/ | |
641 | int | |
642 | start_100(struct usb_device *p) | |
643 | { | |
644 | __u16 get0; | |
645 | __u8 igot; | |
646 | ||
647 | GET(p, 0x0100, &igot); get0 = igot; | |
648 | msleep(0x1f4); | |
649 | SET(p, 0x0100, (0x80 | get0)); | |
650 | msleep(0x1f4); | |
651 | return 0; | |
652 | } | |
653 | /****************************************************************************/ | |
654 | int | |
655 | stop_100(struct usb_device *p) | |
656 | { | |
657 | __u16 get0; | |
658 | __u8 igot; | |
659 | ||
660 | GET(p, 0x0100, &igot); get0 = igot; | |
661 | msleep(0x1f4); | |
662 | SET(p, 0x0100, (0x7F & get0)); | |
663 | msleep(0x1f4); | |
664 | return 0; | |
665 | } | |
666 | /****************************************************************************/ | |
667 | /*--------------------------------------------------------------------------*/ | |
668 | /* | |
669 | * FUNCTION wait_i2c() RETURNS 0 ON SUCCESS | |
670 | */ | |
671 | /*--------------------------------------------------------------------------*/ | |
672 | int | |
673 | wait_i2c(struct usb_device *p) | |
674 | { | |
675 | __u16 get0; | |
676 | __u8 igot; | |
677 | const int max = 4; | |
678 | int k; | |
679 | ||
680 | for (k = 0; k < max; k++) { | |
681 | GET(p, 0x0201, &igot); get0 = igot; | |
682 | switch (get0) { | |
683 | case 0x04: | |
684 | case 0x01: { | |
685 | return 0; | |
686 | } | |
687 | case 0x00: { | |
688 | msleep(10); | |
689 | continue; | |
690 | } | |
691 | default: { | |
692 | return get0 - 1; | |
693 | } | |
694 | } | |
695 | } | |
696 | return -1; | |
697 | } | |
698 | /****************************************************************************/ | |
699 | int | |
700 | regset(struct usb_device *pusb_device, __u16 index, __u16 value) | |
701 | { | |
702 | __u16 igot; | |
703 | int rc0, rc1; | |
704 | ||
705 | if (!pusb_device) | |
706 | return -EFAULT; | |
707 | ||
708 | rc1 = 0; igot = 0; | |
709 | rc0 = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \ | |
710 | (__u8)0x01, \ | |
711 | (__u8)(USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE), \ | |
712 | (__u16)value, \ | |
713 | (__u16)index, \ | |
714 | (void *)NULL, \ | |
715 | (__u16)0, \ | |
716 | (int)500); | |
717 | ||
718 | #if defined(NOREADBACK) | |
719 | # | |
720 | #else | |
721 | rc1 = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0), \ | |
722 | (__u8)0x00, \ | |
723 | (__u8)(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE), \ | |
724 | (__u16)0x00, \ | |
725 | (__u16)index, \ | |
726 | (void *)&igot, \ | |
727 | (__u16)sizeof(__u16), \ | |
728 | (int)50000); | |
729 | igot = 0xFF & igot; | |
730 | switch (index) { | |
731 | case 0x000: | |
732 | case 0x500: | |
733 | case 0x502: | |
734 | case 0x503: | |
735 | case 0x504: | |
736 | case 0x506: | |
737 | case 0x507: { | |
738 | break; | |
739 | } | |
740 | case 0x204: | |
741 | case 0x205: | |
742 | case 0x350: | |
743 | case 0x351: { | |
744 | if (0 != igot) { | |
745 | JOT(8, "unexpected 0x%02X for STK register 0x%03X\n", \ | |
746 | igot, index); | |
747 | } | |
748 | break; | |
749 | } | |
750 | case 0x114: | |
751 | case 0x116: { | |
752 | if ((0xFF & value) != igot) { | |
753 | JOT(8, "unexpected 0x%02X != 0x%02X " \ | |
754 | "for STK register 0x%03X\n", \ | |
755 | igot, value, index); | |
756 | } | |
757 | break; | |
758 | } | |
759 | case 0x200: { | |
760 | if (0 == igot) | |
761 | break; | |
762 | } | |
763 | default: { | |
764 | if (value != igot) { | |
765 | JOT(8, "unexpected 0x%02X != 0x%02X " \ | |
766 | "for STK register 0x%03X\n", \ | |
767 | igot, value, index); | |
768 | } | |
769 | break; | |
770 | } | |
771 | } | |
772 | #endif /* ! NOREADBACK*/ | |
773 | ||
774 | return (0 > rc0) ? rc0 : rc1; | |
775 | } | |
776 | /*****************************************************************************/ | |
777 | int | |
778 | regget(struct usb_device *pusb_device, __u16 index, void *pvoid) | |
779 | { | |
780 | int ir; | |
781 | ||
782 | if (!pusb_device) | |
783 | return -EFAULT; | |
784 | ||
785 | ir = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0), \ | |
786 | (__u8)0x00, \ | |
787 | (__u8)(USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE), \ | |
788 | (__u16)0x00, \ | |
789 | (__u16)index, \ | |
790 | (void *)pvoid, \ | |
791 | sizeof(__u8), \ | |
792 | (int)50000); | |
793 | return 0xFF & ir; | |
794 | } | |
795 | /*****************************************************************************/ | |
796 | int | |
797 | wakeup_device(struct usb_device *pusb_device) | |
798 | { | |
799 | return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \ | |
800 | (__u8)USB_REQ_SET_FEATURE, \ | |
801 | (__u8)(USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE), \ | |
802 | USB_DEVICE_REMOTE_WAKEUP, \ | |
803 | (__u16)0, \ | |
804 | (void *) NULL, \ | |
805 | (__u16)0, \ | |
806 | (int)50000); | |
807 | } | |
808 | /*****************************************************************************/ | |
809 | /*---------------------------------------------------------------------------*/ | |
810 | /* | |
811 | * IMPORTANT: | |
812 | * THE MESSAGE OF TYPE (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE) | |
813 | * CAUSES MUTING IF THE VALUE 0x0100 IS SENT. | |
814 | * TO ENABLE AUDIO THE VALUE 0x0200 MUST BE SENT. | |
815 | */ | |
816 | /*---------------------------------------------------------------------------*/ | |
817 | int | |
818 | audio_setup(struct easycap *peasycap) | |
819 | { | |
820 | struct usb_device *pusb_device; | |
821 | static __u8 request = 0x01; | |
822 | static __u8 requesttype = \ | |
823 | (__u8)(USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE); | |
824 | ||
825 | static __u16 value_unmute = 0x0200; | |
826 | static __u16 index = 0x0301; | |
827 | ||
828 | static unsigned char buffer[1]; | |
829 | static __u16 length = 1; | |
7ebc8760 | 830 | int rc, id1, id2; |
702422bd T |
831 | |
832 | if (NULL == peasycap) | |
833 | return -EFAULT; | |
834 | ||
835 | pusb_device = peasycap->pusb_device; | |
836 | if (NULL == pusb_device) | |
837 | return -EFAULT; | |
838 | ||
839 | JOT(8, "%02X %02X %02X %02X %02X %02X %02X %02X\n", \ | |
840 | requesttype, request, \ | |
841 | (0x00FF & value_unmute), \ | |
842 | (0xFF00 & value_unmute) >> 8, \ | |
843 | (0x00FF & index), \ | |
844 | (0xFF00 & index) >> 8, \ | |
845 | (0x00FF & length), \ | |
846 | (0xFF00 & length) >> 8); | |
847 | ||
848 | buffer[0] = 0x01; | |
849 | ||
850 | rc = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0), \ | |
851 | (__u8)request, \ | |
852 | (__u8)requesttype, \ | |
853 | (__u16)value_unmute, \ | |
854 | (__u16)index, \ | |
855 | (void *)&buffer[0], \ | |
856 | (__u16)length, \ | |
857 | (int)50000); | |
858 | ||
859 | JOT(8, "0x%02X=buffer\n", *((__u8 *) &buffer[0])); | |
860 | if (rc != (int)length) | |
861 | SAY("ERROR: usb_control_msg returned %i\n", rc); | |
862 | ||
863 | /*--------------------------------------------------------------------------*/ | |
864 | /* | |
865 | * REGISTER 500: SETTING VALUE TO 0x0094 RESETS AUDIO CONFIGURATION ??? | |
866 | * REGISTER 506: ANALOGUE AUDIO ATTENTUATOR ??? | |
867 | * FOR THE CVBS+S-VIDEO HARDWARE: | |
868 | * SETTING VALUE TO 0x0000 GIVES QUIET SOUND. | |
869 | * THE UPPER BYTE SEEMS TO HAVE NO EFFECT. | |
870 | * FOR THE FOUR-CVBS HARDWARE: | |
871 | * SETTING VALUE TO 0x0000 SEEMS TO HAVE NO EFFECT. | |
872 | * REGISTER 507: ANALOGUE AUDIO PREAMPLIFIER ON/OFF ??? | |
873 | * FOR THE CVBS-S-VIDEO HARDWARE: | |
874 | * SETTING VALUE TO 0x0001 GIVES VERY LOUD, DISTORTED SOUND. | |
875 | * THE UPPER BYTE SEEMS TO HAVE NO EFFECT. | |
876 | */ | |
877 | /*--------------------------------------------------------------------------*/ | |
878 | ||
879 | SET(pusb_device, 0x0500, 0x0094); | |
880 | ||
881 | SET(pusb_device, 0x0500, 0x008C); | |
882 | ||
883 | SET(pusb_device, 0x0506, 0x0001); | |
884 | SET(pusb_device, 0x0507, 0x0000); | |
885 | ||
7ebc8760 MT |
886 | id1 = read_vt(pusb_device, 0x007C); |
887 | id2 = read_vt(pusb_device, 0x007E); | |
888 | SAY("0x%04X:0x%04X is audio vendor id\n", id1, id2); | |
889 | ||
890 | /*---------------------------------------------------------------------------*/ | |
891 | /* | |
892 | * SELECT AUDIO SOURCE "LINE IN" AND SET DEFAULT GAIN TO 0 dB. | |
893 | * | |
894 | * THESE COMMANDS SEEM TO BE ACCEPTED (THOUGH POSSIBLY IGNORED) EVEN WHEN | |
895 | * THERE IS NO SEPARATE AUDIO CHIP PRESENT. | |
896 | */ | |
897 | /*---------------------------------------------------------------------------*/ | |
898 | ||
899 | write_vt(pusb_device, 0x0002, 0x8000); | |
900 | write_vt(pusb_device, 0x001C, 0x8000); | |
901 | ||
902 | write_vt(pusb_device, 0x000E, 0x0000); | |
903 | write_vt(pusb_device, 0x0010, 0x0000); | |
904 | write_vt(pusb_device, 0x0012, 0x8000); | |
905 | write_vt(pusb_device, 0x0016, 0x0000); | |
906 | ||
907 | write_vt(pusb_device, 0x001A, 0x0404); | |
908 | write_vt(pusb_device, 0x0002, 0x0000); | |
909 | write_vt(pusb_device, 0x001C, 0x0000); | |
702422bd T |
910 | |
911 | check_vt(pusb_device); | |
912 | ||
913 | return 0; | |
914 | } | |
915 | /*****************************************************************************/ | |
916 | int | |
917 | check_vt(struct usb_device *pusb_device) | |
918 | { | |
919 | int igot; | |
920 | ||
921 | igot = read_vt(pusb_device, 0x0002); | |
922 | if (0 > igot) | |
923 | SAY("ERROR: failed to read VT1612A register 0x02\n"); | |
924 | if (0x8000 & igot) | |
925 | SAY("register 0x%02X muted\n", 0x02); | |
926 | ||
927 | igot = read_vt(pusb_device, 0x000E); | |
928 | if (0 > igot) | |
929 | SAY("ERROR: failed to read VT1612A register 0x0E\n"); | |
930 | if (0x8000 & igot) | |
931 | SAY("register 0x%02X muted\n", 0x0E); | |
932 | ||
933 | igot = read_vt(pusb_device, 0x0010); | |
934 | if (0 > igot) | |
935 | SAY("ERROR: failed to read VT1612A register 0x10\n"); | |
936 | if (0x8000 & igot) | |
937 | SAY("register 0x%02X muted\n", 0x10); | |
938 | ||
939 | igot = read_vt(pusb_device, 0x0012); | |
940 | if (0 > igot) | |
941 | SAY("ERROR: failed to read VT1612A register 0x12\n"); | |
942 | if (0x8000 & igot) | |
943 | SAY("register 0x%02X muted\n", 0x12); | |
944 | ||
945 | igot = read_vt(pusb_device, 0x0016); | |
946 | if (0 > igot) | |
947 | SAY("ERROR: failed to read VT1612A register 0x16\n"); | |
948 | if (0x8000 & igot) | |
949 | SAY("register 0x%02X muted\n", 0x16); | |
950 | ||
951 | igot = read_vt(pusb_device, 0x001A); | |
952 | if (0 > igot) | |
953 | SAY("ERROR: failed to read VT1612A register 0x1A\n"); | |
954 | if (0x8000 & igot) | |
955 | SAY("register 0x%02X muted\n", 0x1A); | |
956 | ||
957 | igot = read_vt(pusb_device, 0x001C); | |
958 | if (0 > igot) | |
959 | SAY("ERROR: failed to read VT1612A register 0x1C\n"); | |
960 | if (0x8000 & igot) | |
961 | SAY("register 0x%02X muted\n", 0x1C); | |
962 | ||
963 | return 0; | |
964 | } | |
965 | /*****************************************************************************/ | |
966 | /*---------------------------------------------------------------------------*/ | |
967 | /* | |
968 | * NOTE: THIS DOES INCREASE THE VOLUME DRAMATICALLY: | |
969 | * audio_gainset(pusb_device, 0x000F); | |
970 | * | |
971 | * IF 16<loud<31 VT1621A REGISTER 0x1C IS SET FOR POSITIVE GAIN. | |
972 | * IF loud<=16 VT1621A REGISTER 0x1C IS SET FOR ZERO GAIN. | |
973 | * THERE IS NEVER ANY (ADDITIONAL) ATTENUATION. | |
974 | */ | |
975 | /*---------------------------------------------------------------------------*/ | |
976 | int | |
977 | audio_gainset(struct usb_device *pusb_device, __s8 loud) | |
978 | { | |
979 | int igot; | |
980 | __u8 u8; | |
981 | __u16 mute; | |
982 | ||
983 | if (16 > loud) | |
984 | loud = 16; | |
985 | u8 = 0x000F & (__u8)(loud - 16); | |
986 | ||
987 | write_vt(pusb_device, 0x0002, 0x8000); | |
988 | ||
989 | igot = read_vt(pusb_device, 0x001C); | |
990 | if (0 > igot) { | |
991 | SAY("ERROR: failed to read VT1612A register 0x1C\n"); | |
992 | mute = 0x0000; | |
993 | } else | |
994 | mute = 0x8000 & ((unsigned int)igot); | |
995 | ||
996 | JOT(8, "0x%04X=(mute|u8|(u8<<8))\n", mute | u8 | (u8 << 8)); | |
997 | ||
998 | write_vt(pusb_device, 0x001C, 0x8000); | |
999 | write_vt(pusb_device, 0x001C, (mute | u8 | (u8 << 8))); | |
1000 | write_vt(pusb_device, 0x0002, 0x0000); | |
1001 | ||
1002 | return 0; | |
1003 | } | |
1004 | /*****************************************************************************/ | |
1005 | int | |
1006 | audio_gainget(struct usb_device *pusb_device) | |
1007 | { | |
1008 | int igot; | |
1009 | ||
1010 | igot = read_vt(pusb_device, 0x001C); | |
1011 | if (0 > igot) | |
1012 | SAY("ERROR: failed to read VT1612A register 0x1C\n"); | |
1013 | return igot; | |
1014 | } | |
1015 | /*****************************************************************************/ | |
1016 | int | |
1017 | set2to78(struct usb_device *p) | |
1018 | { | |
1019 | int ir; | |
1020 | ||
1021 | msleep(20); | |
1022 | ir = regset(p, 0x0002, 0x0078); | |
1023 | if (0 > ir) | |
1024 | SAY("ERROR: failed to set register 0x0002 to 0x0078\n"); | |
1025 | msleep(20); | |
1026 | return ir; | |
1027 | } | |
1028 | /*****************************************************************************/ | |
1029 | int | |
1030 | set2to93(struct usb_device *p) | |
1031 | { | |
1032 | int ir; | |
1033 | ||
1034 | msleep(20); | |
1035 | ir = regset(p, 0x0002, 0x0093); | |
1036 | if (0 > ir) | |
1037 | SAY("ERROR: failed to set register 0x0002 to 0x0078\n"); | |
1038 | msleep(20); | |
1039 | return ir; | |
1040 | } | |
1041 | /*****************************************************************************/ |