blob: 0380babed22c02b62db3c8f7ceb1096ad24d4190 [file] [log] [blame]
R.M. Thomas702422b2010-06-18 12:29:49 -07001/*****************************************************************************
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
R.M. Thomas702422b2010-06-18 12:29:49 -070041#include "easycap.h"
42
Tomas Winkler98680552011-11-09 08:26:32 -030043
Tomas Winkler73132ce2011-02-09 01:12:49 +020044#define GET(X, Y, Z) do { \
45 int __rc; \
46 *(Z) = (u16)0; \
Tomas Winkler32851b32011-02-09 01:12:50 +020047 __rc = regget(X, Y, Z, sizeof(u8)); \
Tomas Winkler73132ce2011-02-09 01:12:49 +020048 if (0 > __rc) { \
49 JOT(8, ":-(%i\n", __LINE__); return __rc; \
50 } \
51} while (0)
52
53#define SET(X, Y, Z) do { \
54 int __rc; \
55 __rc = regset(X, Y, Z); \
56 if (0 > __rc) { \
57 JOT(8, ":-(%i\n", __LINE__); return __rc; \
58 } \
59} while (0)
60
R.M. Thomas702422b2010-06-18 12:29:49 -070061/*--------------------------------------------------------------------------*/
Tomas Winklerdbf48052011-01-23 01:13:52 +020062static const struct stk1160config {
Tomas Winkler7dbb3922011-11-09 08:26:34 -030063 u16 reg;
64 u16 set;
65} stk1160configPAL[] = {
Mike Thomasf36bc372010-11-07 20:00:35 +000066 {0x000, 0x0098},
67 {0x002, 0x0093},
R.M. Thomas702422b2010-06-18 12:29:49 -070068
Mike Thomasf36bc372010-11-07 20:00:35 +000069 {0x001, 0x0003},
70 {0x003, 0x0080},
71 {0x00D, 0x0000},
72 {0x00F, 0x0002},
73 {0x018, 0x0010},
74 {0x019, 0x0000},
75 {0x01A, 0x0014},
76 {0x01B, 0x000E},
77 {0x01C, 0x0046},
R.M. Thomas702422b2010-06-18 12:29:49 -070078
Mike Thomasf36bc372010-11-07 20:00:35 +000079 {0x100, 0x0033},
80 {0x103, 0x0000},
81 {0x104, 0x0000},
82 {0x105, 0x0000},
83 {0x106, 0x0000},
R.M. Thomas702422b2010-06-18 12:29:49 -070084
Mike Thomasf36bc372010-11-07 20:00:35 +000085/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
86/*
87 * RESOLUTION 640x480
88*/
89/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
90 {0x110, 0x0008},
91 {0x111, 0x0000},
92 {0x112, 0x0020},
93 {0x113, 0x0000},
94 {0x114, 0x0508},
95 {0x115, 0x0005},
96 {0x116, 0x0110},
97 {0x117, 0x0001},
98/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
R.M. Thomas702422b2010-06-18 12:29:49 -070099
Mike Thomasf36bc372010-11-07 20:00:35 +0000100 {0x202, 0x000F},
101 {0x203, 0x004A},
102 {0x2FF, 0x0000},
R.M. Thomas702422b2010-06-18 12:29:49 -0700103
Mike Thomasf36bc372010-11-07 20:00:35 +0000104 {0xFFF, 0xFFFF}
105};
R.M. Thomas702422b2010-06-18 12:29:49 -0700106/*--------------------------------------------------------------------------*/
Tomas Winkler7dbb3922011-11-09 08:26:34 -0300107static const struct stk1160config stk1160configNTSC[] = {
Mike Thomasf36bc372010-11-07 20:00:35 +0000108 {0x000, 0x0098},
109 {0x002, 0x0093},
110
111 {0x001, 0x0003},
112 {0x003, 0x0080},
113 {0x00D, 0x0000},
114 {0x00F, 0x0002},
115 {0x018, 0x0010},
116 {0x019, 0x0000},
117 {0x01A, 0x0014},
118 {0x01B, 0x000E},
119 {0x01C, 0x0046},
120
121 {0x100, 0x0033},
122 {0x103, 0x0000},
123 {0x104, 0x0000},
124 {0x105, 0x0000},
125 {0x106, 0x0000},
126
127/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
128/*
129 * RESOLUTION 640x480
130*/
131/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
132 {0x110, 0x0008},
133 {0x111, 0x0000},
134 {0x112, 0x0003},
135 {0x113, 0x0000},
136 {0x114, 0x0508},
137 {0x115, 0x0005},
138 {0x116, 0x00F3},
139 {0x117, 0x0000},
140/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
141
142 {0x202, 0x000F},
143 {0x203, 0x004A},
144 {0x2FF, 0x0000},
145
146 {0xFFF, 0xFFFF}
147};
148/*--------------------------------------------------------------------------*/
Tomas Winkler3e17e392011-02-10 14:55:24 +0200149static const struct saa7113config {
Tomas Winkler7dbb3922011-11-09 08:26:34 -0300150 u8 reg;
151 u8 set;
152} saa7113configPAL[] = {
Mike Thomasf36bc372010-11-07 20:00:35 +0000153 {0x01, 0x08},
Mike Thomasf36bc372010-11-07 20:00:35 +0000154 {0x02, 0x80},
Mike Thomasf36bc372010-11-07 20:00:35 +0000155 {0x03, 0x33},
156 {0x04, 0x00},
157 {0x05, 0x00},
158 {0x06, 0xE9},
159 {0x07, 0x0D},
160 {0x08, 0x38},
161 {0x09, 0x00},
162 {0x0A, SAA_0A_DEFAULT},
163 {0x0B, SAA_0B_DEFAULT},
164 {0x0C, SAA_0C_DEFAULT},
165 {0x0D, SAA_0D_DEFAULT},
166 {0x0E, 0x01},
167 {0x0F, 0x36},
168 {0x10, 0x00},
169 {0x11, 0x0C},
170 {0x12, 0xE7},
171 {0x13, 0x00},
172 {0x15, 0x00},
173 {0x16, 0x00},
174 {0x40, 0x02},
175 {0x41, 0xFF},
176 {0x42, 0xFF},
177 {0x43, 0xFF},
178 {0x44, 0xFF},
179 {0x45, 0xFF},
180 {0x46, 0xFF},
181 {0x47, 0xFF},
182 {0x48, 0xFF},
183 {0x49, 0xFF},
184 {0x4A, 0xFF},
185 {0x4B, 0xFF},
186 {0x4C, 0xFF},
187 {0x4D, 0xFF},
188 {0x4E, 0xFF},
189 {0x4F, 0xFF},
190 {0x50, 0xFF},
191 {0x51, 0xFF},
192 {0x52, 0xFF},
193 {0x53, 0xFF},
194 {0x54, 0xFF},
195 {0x55, 0xFF},
196 {0x56, 0xFF},
197 {0x57, 0xFF},
198 {0x58, 0x40},
199 {0x59, 0x54},
200 {0x5A, 0x07},
201 {0x5B, 0x83},
202
203 {0xFF, 0xFF}
204};
205/*--------------------------------------------------------------------------*/
Tomas Winkler7dbb3922011-11-09 08:26:34 -0300206static const struct saa7113config saa7113configNTSC[] = {
Mike Thomasf36bc372010-11-07 20:00:35 +0000207 {0x01, 0x08},
Mike Thomasf36bc372010-11-07 20:00:35 +0000208 {0x02, 0x80},
Mike Thomasf36bc372010-11-07 20:00:35 +0000209 {0x03, 0x33},
210 {0x04, 0x00},
211 {0x05, 0x00},
212 {0x06, 0xE9},
213 {0x07, 0x0D},
214 {0x08, 0x78},
215 {0x09, 0x00},
216 {0x0A, SAA_0A_DEFAULT},
217 {0x0B, SAA_0B_DEFAULT},
218 {0x0C, SAA_0C_DEFAULT},
219 {0x0D, SAA_0D_DEFAULT},
220 {0x0E, 0x01},
221 {0x0F, 0x36},
222 {0x10, 0x00},
223 {0x11, 0x0C},
224 {0x12, 0xE7},
225 {0x13, 0x00},
226 {0x15, 0x00},
227 {0x16, 0x00},
228 {0x40, 0x82},
229 {0x41, 0xFF},
230 {0x42, 0xFF},
231 {0x43, 0xFF},
232 {0x44, 0xFF},
233 {0x45, 0xFF},
234 {0x46, 0xFF},
235 {0x47, 0xFF},
236 {0x48, 0xFF},
237 {0x49, 0xFF},
238 {0x4A, 0xFF},
239 {0x4B, 0xFF},
240 {0x4C, 0xFF},
241 {0x4D, 0xFF},
242 {0x4E, 0xFF},
243 {0x4F, 0xFF},
244 {0x50, 0xFF},
245 {0x51, 0xFF},
246 {0x52, 0xFF},
247 {0x53, 0xFF},
248 {0x54, 0xFF},
249 {0x55, 0xFF},
250 {0x56, 0xFF},
251 {0x57, 0xFF},
252 {0x58, 0x40},
253 {0x59, 0x54},
254 {0x5A, 0x0A},
255 {0x5B, 0x83},
256
257 {0xFF, 0xFF}
258};
Tomas Winkler73132ce2011-02-09 01:12:49 +0200259
Tomas Winkler32851b32011-02-09 01:12:50 +0200260static int regget(struct usb_device *pusb_device,
261 u16 index, void *reg, int reg_size)
Tomas Winkler73132ce2011-02-09 01:12:49 +0200262{
263 int rc;
264
265 if (!pusb_device)
266 return -ENODEV;
267
268 rc = usb_control_msg(pusb_device, usb_rcvctrlpipe(pusb_device, 0),
Tomas Winkler32851b32011-02-09 01:12:50 +0200269 0x00,
270 (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
271 0x00,
272 index, reg, reg_size, 50000);
Tomas Winkler73132ce2011-02-09 01:12:49 +0200273
Tomas Winklerccb6d2e2011-02-10 14:55:23 +0200274 return rc;
Tomas Winkler73132ce2011-02-09 01:12:49 +0200275}
276
277static int regset(struct usb_device *pusb_device, u16 index, u16 value)
278{
Tomas Winkler2ef0c052011-02-09 01:12:51 +0200279 int rc;
Tomas Winkler73132ce2011-02-09 01:12:49 +0200280
281 if (!pusb_device)
282 return -ENODEV;
283
Tomas Winkler2ef0c052011-02-09 01:12:51 +0200284 rc = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0),
Tomas Winkler32851b32011-02-09 01:12:50 +0200285 0x01,
286 (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
287 value, index, NULL, 0, 500);
Tomas Winkler73132ce2011-02-09 01:12:49 +0200288
Tomas Winkler2ef0c052011-02-09 01:12:51 +0200289 if (rc < 0)
290 return rc;
Tomas Winkler73132ce2011-02-09 01:12:49 +0200291
Tomas Winkler2ef0c052011-02-09 01:12:51 +0200292 if (easycap_readback) {
293 u16 igot = 0;
294 rc = regget(pusb_device, index, &igot, sizeof(igot));
295 igot = 0xFF & igot;
296 switch (index) {
297 case 0x000:
298 case 0x500:
299 case 0x502:
300 case 0x503:
301 case 0x504:
302 case 0x506:
303 case 0x507:
304 break;
Tomas Winkler73132ce2011-02-09 01:12:49 +0200305
Tomas Winkler2ef0c052011-02-09 01:12:51 +0200306 case 0x204:
307 case 0x205:
308 case 0x350:
309 case 0x351:
310 if (igot)
311 JOT(8, "unexpected 0x%02X "
312 "for STK register 0x%03X\n",
313 igot, index);
314 break;
315
316 default:
317 if ((0xFF & value) != igot)
318 JOT(8, "unexpected 0x%02X != 0x%02X "
319 "for STK register 0x%03X\n",
Tomas Winkler73132ce2011-02-09 01:12:49 +0200320 igot, value, index);
Tomas Winkler2ef0c052011-02-09 01:12:51 +0200321 break;
Tomas Winkler73132ce2011-02-09 01:12:49 +0200322 }
Tomas Winkler73132ce2011-02-09 01:12:49 +0200323 }
Tomas Winkler73132ce2011-02-09 01:12:49 +0200324
Tomas Winkler2ef0c052011-02-09 01:12:51 +0200325 return rc;
Tomas Winkler73132ce2011-02-09 01:12:49 +0200326}
Tomas Winklerfd49b782011-03-06 00:55:20 +0200327/*--------------------------------------------------------------------------*/
328/*
329 * FUNCTION wait_i2c() RETURNS 0 ON SUCCESS
330*/
331/*--------------------------------------------------------------------------*/
332static int wait_i2c(struct usb_device *p)
333{
334 u16 get0;
335 u8 igot;
336 const int max = 2;
337 int k;
338
339 if (!p)
340 return -ENODEV;
341
342 for (k = 0; k < max; k++) {
343 GET(p, 0x0201, &igot); get0 = igot;
344 switch (get0) {
345 case 0x04:
346 case 0x01:
347 return 0;
348 case 0x00:
349 msleep(20);
350 continue;
351 default:
352 return get0 - 1;
353 }
354 }
355 return -1;
356}
R.M. Thomas702422b2010-06-18 12:29:49 -0700357
358/****************************************************************************/
Tomas Winkler72075782011-02-10 14:55:22 +0200359int write_saa(struct usb_device *p, u16 reg0, u16 set0)
R.M. Thomas702422b2010-06-18 12:29:49 -0700360{
Tomas Winkler68883932011-03-03 00:10:51 +0200361 if (!p)
Tomas Winkler72075782011-02-10 14:55:22 +0200362 return -ENODEV;
363 SET(p, 0x200, 0x00);
364 SET(p, 0x204, reg0);
365 SET(p, 0x205, set0);
366 SET(p, 0x200, 0x01);
367 return wait_i2c(p);
R.M. Thomas702422b2010-06-18 12:29:49 -0700368}
369/****************************************************************************/
370/*--------------------------------------------------------------------------*/
371/*
372 * REGISTER 500: SETTING VALUE TO 0x008B READS FROM VT1612A (?)
373 * REGISTER 500: SETTING VALUE TO 0x008C WRITES TO VT1612A
374 * REGISTER 502: LEAST SIGNIFICANT BYTE OF VALUE TO SET
375 * REGISTER 503: MOST SIGNIFICANT BYTE OF VALUE TO SET
376 * REGISTER 504: TARGET ADDRESS ON VT1612A
377 */
378/*--------------------------------------------------------------------------*/
Tomas Winkler98680552011-11-09 08:26:32 -0300379static int write_vt(struct usb_device *p, u16 reg0, u16 set0)
R.M. Thomas702422b2010-06-18 12:29:49 -0700380{
Tomas Winkler72075782011-02-10 14:55:22 +0200381 u8 igot;
382 u16 got502, got503;
383 u16 set502, set503;
R.M. Thomas702422b2010-06-18 12:29:49 -0700384
Tomas Winkler68883932011-03-03 00:10:51 +0200385 if (!p)
Tomas Winkler72075782011-02-10 14:55:22 +0200386 return -ENODEV;
387 SET(p, 0x0504, reg0);
388 SET(p, 0x0500, 0x008B);
R.M. Thomas702422b2010-06-18 12:29:49 -0700389
Tomas Winkler72075782011-02-10 14:55:22 +0200390 GET(p, 0x0502, &igot); got502 = (0xFF & igot);
391 GET(p, 0x0503, &igot); got503 = (0xFF & igot);
R.M. Thomas702422b2010-06-18 12:29:49 -0700392
Tomas Winkler72075782011-02-10 14:55:22 +0200393 JOT(16, "write_vt(., 0x%04X, 0x%04X): was 0x%04X\n",
394 reg0, set0, ((got503 << 8) | got502));
R.M. Thomas702422b2010-06-18 12:29:49 -0700395
Tomas Winkler72075782011-02-10 14:55:22 +0200396 set502 = (0x00FF & set0);
397 set503 = ((0xFF00 & set0) >> 8);
R.M. Thomas702422b2010-06-18 12:29:49 -0700398
Tomas Winkler72075782011-02-10 14:55:22 +0200399 SET(p, 0x0504, reg0);
400 SET(p, 0x0502, set502);
401 SET(p, 0x0503, set503);
402 SET(p, 0x0500, 0x008C);
R.M. Thomas702422b2010-06-18 12:29:49 -0700403
Tomas Winkler72075782011-02-10 14:55:22 +0200404 return 0;
R.M. Thomas702422b2010-06-18 12:29:49 -0700405}
406/****************************************************************************/
407/*--------------------------------------------------------------------------*/
408/*
409 * REGISTER 500: SETTING VALUE TO 0x008B READS FROM VT1612A (?)
410 * REGISTER 500: SETTING VALUE TO 0x008C WRITES TO VT1612A
411 * REGISTER 502: LEAST SIGNIFICANT BYTE OF VALUE TO GET
412 * REGISTER 503: MOST SIGNIFICANT BYTE OF VALUE TO GET
413 * REGISTER 504: TARGET ADDRESS ON VT1612A
414 */
415/*--------------------------------------------------------------------------*/
Tomas Winkler98680552011-11-09 08:26:32 -0300416static int read_vt(struct usb_device *p, u16 reg0)
R.M. Thomas702422b2010-06-18 12:29:49 -0700417{
Tomas Winkler72075782011-02-10 14:55:22 +0200418 u8 igot;
419 u16 got502, got503;
R.M. Thomas702422b2010-06-18 12:29:49 -0700420
Tomas Winkler68883932011-03-03 00:10:51 +0200421 if (!p)
Tomas Winkler72075782011-02-10 14:55:22 +0200422 return -ENODEV;
423 SET(p, 0x0504, reg0);
424 SET(p, 0x0500, 0x008B);
R.M. Thomas702422b2010-06-18 12:29:49 -0700425
Tomas Winkler72075782011-02-10 14:55:22 +0200426 GET(p, 0x0502, &igot); got502 = (0xFF & igot);
427 GET(p, 0x0503, &igot); got503 = (0xFF & igot);
R.M. Thomas702422b2010-06-18 12:29:49 -0700428
Tomas Winkler72075782011-02-10 14:55:22 +0200429 JOT(16, "read_vt(., 0x%04X): has 0x%04X\n",
430 reg0, ((got503 << 8) | got502));
R.M. Thomas702422b2010-06-18 12:29:49 -0700431
Tomas Winkler72075782011-02-10 14:55:22 +0200432 return (got503 << 8) | got502;
R.M. Thomas702422b2010-06-18 12:29:49 -0700433}
434/****************************************************************************/
435/*--------------------------------------------------------------------------*/
436/*
437 * THESE APPEAR TO HAVE NO EFFECT ON EITHER VIDEO OR AUDIO.
438 */
439/*--------------------------------------------------------------------------*/
Tomas Winkler98680552011-11-09 08:26:32 -0300440static int write_300(struct usb_device *p)
R.M. Thomas702422b2010-06-18 12:29:49 -0700441{
Tomas Winkler68883932011-03-03 00:10:51 +0200442 if (!p)
Tomas Winkler72075782011-02-10 14:55:22 +0200443 return -ENODEV;
444 SET(p, 0x300, 0x0012);
445 SET(p, 0x350, 0x002D);
446 SET(p, 0x351, 0x0001);
447 SET(p, 0x352, 0x0000);
448 SET(p, 0x353, 0x0000);
449 SET(p, 0x300, 0x0080);
450 return 0;
R.M. Thomas702422b2010-06-18 12:29:49 -0700451}
452/****************************************************************************/
Tomas Winkler98680552011-11-09 08:26:32 -0300453/****************************************************************************/
454int setup_stk(struct usb_device *p, bool ntsc)
R.M. Thomas702422b2010-06-18 12:29:49 -0700455{
Tomas Winkler98680552011-11-09 08:26:32 -0300456 int i;
457 const struct stk1160config *cfg;
Tomas Winkler68883932011-03-03 00:10:51 +0200458 if (!p)
Tomas Winkler72075782011-02-10 14:55:22 +0200459 return -ENODEV;
Tomas Winkler98680552011-11-09 08:26:32 -0300460 cfg = (ntsc) ? stk1160configNTSC : stk1160configPAL;
461 for (i = 0; cfg[i].reg != 0xFFF; i++)
462 SET(p, cfg[i].reg, cfg[i].set);
R.M. Thomas702422b2010-06-18 12:29:49 -0700463
Tomas Winkler98680552011-11-09 08:26:32 -0300464 write_300(p);
Tomas Winklerc0b3a8a2011-03-06 00:55:21 +0200465
Tomas Winkler98680552011-11-09 08:26:32 -0300466 return 0;
467}
468/****************************************************************************/
469int setup_saa(struct usb_device *p, bool ntsc)
470{
Tomas Winklera6ff0a02011-11-09 08:26:42 -0300471 int i, rc;
Tomas Winkler98680552011-11-09 08:26:32 -0300472 const struct saa7113config *cfg;
473 if (!p)
474 return -ENODEV;
475 cfg = (ntsc) ? saa7113configNTSC : saa7113configPAL;
Tomas Winklera6ff0a02011-11-09 08:26:42 -0300476 for (i = 0; cfg[i].reg != 0xFF; i++) {
477 rc = write_saa(p, cfg[i].reg, cfg[i].set);
478 if (rc)
479 dev_err(&p->dev,
480 "Failed to set SAA register %d", cfg[i].reg);
481 }
Tomas Winkler98680552011-11-09 08:26:32 -0300482 return 0;
R.M. Thomas702422b2010-06-18 12:29:49 -0700483}
484/****************************************************************************/
Tomas Winkler72075782011-02-10 14:55:22 +0200485int merit_saa(struct usb_device *p)
R.M. Thomas702422b2010-06-18 12:29:49 -0700486{
Tomas Winkler72075782011-02-10 14:55:22 +0200487 int rc;
R.M. Thomas702422b2010-06-18 12:29:49 -0700488
Tomas Winkler68883932011-03-03 00:10:51 +0200489 if (!p)
Tomas Winkler72075782011-02-10 14:55:22 +0200490 return -ENODEV;
491 rc = read_saa(p, 0x1F);
Tomas Winkler3e17e392011-02-10 14:55:24 +0200492 return ((0 > rc) || (0x02 & rc)) ? 1 : 0;
R.M. Thomas702422b2010-06-18 12:29:49 -0700493}
494/****************************************************************************/
Tomas Winkler72075782011-02-10 14:55:22 +0200495int ready_saa(struct usb_device *p)
R.M. Thomas702422b2010-06-18 12:29:49 -0700496{
Tomas Winkler72075782011-02-10 14:55:22 +0200497 int j, rc, rate;
498 const int max = 5, marktime = PATIENCE/5;
Mike Thomasf36bc372010-11-07 20:00:35 +0000499/*--------------------------------------------------------------------------*/
500/*
501 * RETURNS 0 FOR INTERLACED 50 Hz
502 * 1 FOR NON-INTERLACED 50 Hz
503 * 2 FOR INTERLACED 60 Hz
504 * 3 FOR NON-INTERLACED 60 Hz
505*/
506/*--------------------------------------------------------------------------*/
Tomas Winkler68883932011-03-03 00:10:51 +0200507 if (!p)
Tomas Winkler72075782011-02-10 14:55:22 +0200508 return -ENODEV;
509 j = 0;
510 while (max > j) {
511 rc = read_saa(p, 0x1F);
512 if (0 <= rc) {
513 if (0 == (0x40 & rc))
514 break;
515 if (1 == (0x01 & rc))
516 break;
517 }
518 msleep(marktime);
519 j++;
R.M. Thomas702422b2010-06-18 12:29:49 -0700520 }
Tomas Winkler101dca42011-11-09 08:26:35 -0300521
Tomas Winkler72075782011-02-10 14:55:22 +0200522 if (max == j)
523 return -1;
Tomas Winkler101dca42011-11-09 08:26:35 -0300524
525 if (0x20 & rc) {
526 rate = 2;
527 JOT(8, "hardware detects 60 Hz\n");
528 } else {
529 rate = 0;
530 JOT(8, "hardware detects 50 Hz\n");
531 }
532 if (0x80 & rc)
533 JOT(8, "hardware detects interlacing\n");
Mike Thomasf36bc372010-11-07 20:00:35 +0000534 else {
Tomas Winkler101dca42011-11-09 08:26:35 -0300535 rate++;
536 JOT(8, "hardware detects no interlacing\n");
Mike Thomasf36bc372010-11-07 20:00:35 +0000537 }
Tomas Winkler72075782011-02-10 14:55:22 +0200538 return 0;
R.M. Thomas702422b2010-06-18 12:29:49 -0700539}
540/****************************************************************************/
Tomas Winkler72075782011-02-10 14:55:22 +0200541int read_saa(struct usb_device *p, u16 reg0)
R.M. Thomas702422b2010-06-18 12:29:49 -0700542{
Tomas Winkler72075782011-02-10 14:55:22 +0200543 u8 igot;
R.M. Thomas702422b2010-06-18 12:29:49 -0700544
Tomas Winkler68883932011-03-03 00:10:51 +0200545 if (!p)
Tomas Winkler72075782011-02-10 14:55:22 +0200546 return -ENODEV;
547 SET(p, 0x208, reg0);
548 SET(p, 0x200, 0x20);
549 if (0 != wait_i2c(p))
550 return -1;
551 igot = 0;
552 GET(p, 0x0209, &igot);
553 return igot;
R.M. Thomas702422b2010-06-18 12:29:49 -0700554}
555/****************************************************************************/
Tomas Winkler98680552011-11-09 08:26:32 -0300556static int read_stk(struct usb_device *p, u32 reg0)
R.M. Thomas702422b2010-06-18 12:29:49 -0700557{
Tomas Winkler72075782011-02-10 14:55:22 +0200558 u8 igot;
R.M. Thomas702422b2010-06-18 12:29:49 -0700559
Tomas Winkler68883932011-03-03 00:10:51 +0200560 if (!p)
Tomas Winkler72075782011-02-10 14:55:22 +0200561 return -ENODEV;
562 igot = 0;
563 GET(p, reg0, &igot);
564 return igot;
R.M. Thomas702422b2010-06-18 12:29:49 -0700565}
Tomas Winkler98680552011-11-09 08:26:32 -0300566int select_input(struct usb_device *p, int input, int mode)
R.M. Thomas702422b2010-06-18 12:29:49 -0700567{
Tomas Winkler72075782011-02-10 14:55:22 +0200568 int ir;
R.M. Thomas702422b2010-06-18 12:29:49 -0700569
Tomas Winkler68883932011-03-03 00:10:51 +0200570 if (!p)
Tomas Winkler72075782011-02-10 14:55:22 +0200571 return -ENODEV;
572 stop_100(p);
573 switch (input) {
574 case 0:
575 case 1: {
Tomas Winkler3e17e392011-02-10 14:55:24 +0200576 if (0 != write_saa(p, 0x02, 0x80))
Tomas Winkler1dc6e412011-01-19 00:24:06 +0200577 SAY("ERROR: failed to set SAA register 0x02 "
Mike Thomasf36bc372010-11-07 20:00:35 +0000578 "for input %i\n", input);
Tomas Winkler3e17e392011-02-10 14:55:24 +0200579
Tomas Winkler72075782011-02-10 14:55:22 +0200580 SET(p, 0x0000, 0x0098);
581 SET(p, 0x0002, 0x0078);
R.M. Thomas702422b2010-06-18 12:29:49 -0700582 break;
583 }
Tomas Winkler72075782011-02-10 14:55:22 +0200584 case 2: {
Tomas Winkler3e17e392011-02-10 14:55:24 +0200585 if (0 != write_saa(p, 0x02, 0x80))
Tomas Winkler1dc6e412011-01-19 00:24:06 +0200586 SAY("ERROR: failed to set SAA register 0x02 "
Mike Thomasf36bc372010-11-07 20:00:35 +0000587 "for input %i\n", input);
Tomas Winkler3e17e392011-02-10 14:55:24 +0200588
Tomas Winkler72075782011-02-10 14:55:22 +0200589 SET(p, 0x0000, 0x0090);
590 SET(p, 0x0002, 0x0078);
591 break;
592 }
593 case 3: {
Tomas Winkler3e17e392011-02-10 14:55:24 +0200594 if (0 != write_saa(p, 0x02, 0x80))
Tomas Winkler72075782011-02-10 14:55:22 +0200595 SAY("ERROR: failed to set SAA register 0x02 "
596 " for input %i\n", input);
Tomas Winkler3e17e392011-02-10 14:55:24 +0200597
Tomas Winkler72075782011-02-10 14:55:22 +0200598 SET(p, 0x0000, 0x0088);
599 SET(p, 0x0002, 0x0078);
600 break;
601 }
602 case 4: {
603 if (0 != write_saa(p, 0x02, 0x80)) {
604 SAY("ERROR: failed to set SAA register 0x02 "
Mike Thomasf36bc372010-11-07 20:00:35 +0000605 "for input %i\n", input);
R.M. Thomas702422b2010-06-18 12:29:49 -0700606 }
Tomas Winkler72075782011-02-10 14:55:22 +0200607 SET(p, 0x0000, 0x0080);
608 SET(p, 0x0002, 0x0078);
609 break;
610 }
611 case 5: {
612 if (9 != mode)
613 mode = 7;
614 switch (mode) {
615 case 7: {
Tomas Winkler3e17e392011-02-10 14:55:24 +0200616 if (0 != write_saa(p, 0x02, 0x87))
Tomas Winkler72075782011-02-10 14:55:22 +0200617 SAY("ERROR: failed to set SAA register 0x02 "
618 "for input %i\n", input);
Tomas Winkler3e17e392011-02-10 14:55:24 +0200619
620 if (0 != write_saa(p, 0x05, 0xFF))
Tomas Winkler72075782011-02-10 14:55:22 +0200621 SAY("ERROR: failed to set SAA register 0x05 "
622 "for input %i\n", input);
Tomas Winkler3e17e392011-02-10 14:55:24 +0200623
Tomas Winkler72075782011-02-10 14:55:22 +0200624 break;
625 }
626 case 9: {
Tomas Winkler3e17e392011-02-10 14:55:24 +0200627 if (0 != write_saa(p, 0x02, 0x89))
Tomas Winkler72075782011-02-10 14:55:22 +0200628 SAY("ERROR: failed to set SAA register 0x02 "
629 "for input %i\n", input);
Tomas Winkler3e17e392011-02-10 14:55:24 +0200630
631 if (0 != write_saa(p, 0x05, 0x00))
Tomas Winkler72075782011-02-10 14:55:22 +0200632 SAY("ERROR: failed to set SAA register 0x05 "
633 "for input %i\n", input);
Tomas Winkler3e17e392011-02-10 14:55:24 +0200634
635 break;
Tomas Winkler72075782011-02-10 14:55:22 +0200636 }
Tomas Winkler3e17e392011-02-10 14:55:24 +0200637 default:
Tomas Winkler72075782011-02-10 14:55:22 +0200638 SAY("MISTAKE: bad mode: %i\n", mode);
639 return -1;
640 }
Tomas Winkler3e17e392011-02-10 14:55:24 +0200641
642 if (0 != write_saa(p, 0x04, 0x00))
Tomas Winkler72075782011-02-10 14:55:22 +0200643 SAY("ERROR: failed to set SAA register 0x04 "
644 "for input %i\n", input);
Tomas Winkler3e17e392011-02-10 14:55:24 +0200645
646 if (0 != write_saa(p, 0x09, 0x80))
Tomas Winkler72075782011-02-10 14:55:22 +0200647 SAY("ERROR: failed to set SAA register 0x09 "
648 "for input %i\n", input);
Tomas Winkler3e17e392011-02-10 14:55:24 +0200649
Tomas Winkler72075782011-02-10 14:55:22 +0200650 SET(p, 0x0002, 0x0093);
651 break;
R.M. Thomas702422b2010-06-18 12:29:49 -0700652 }
Tomas Winkler3e17e392011-02-10 14:55:24 +0200653 default:
Tomas Winkler72075782011-02-10 14:55:22 +0200654 SAY("ERROR: bad input: %i\n", input);
R.M. Thomas702422b2010-06-18 12:29:49 -0700655 return -1;
Mike Thomasf36bc372010-11-07 20:00:35 +0000656 }
Tomas Winkler3e17e392011-02-10 14:55:24 +0200657
Tomas Winkler72075782011-02-10 14:55:22 +0200658 ir = read_stk(p, 0x00);
659 JOT(8, "STK register 0x00 has 0x%02X\n", ir);
660 ir = read_saa(p, 0x02);
661 JOT(8, "SAA register 0x02 has 0x%02X\n", ir);
R.M. Thomas702422b2010-06-18 12:29:49 -0700662
Tomas Winkler72075782011-02-10 14:55:22 +0200663 start_100(p);
R.M. Thomas702422b2010-06-18 12:29:49 -0700664
Tomas Winkler72075782011-02-10 14:55:22 +0200665 return 0;
R.M. Thomas702422b2010-06-18 12:29:49 -0700666}
667/****************************************************************************/
Tomas Winkler72075782011-02-10 14:55:22 +0200668int set_resolution(struct usb_device *p,
669 u16 set0, u16 set1, u16 set2, u16 set3)
R.M. Thomas702422b2010-06-18 12:29:49 -0700670{
Tomas Winkler72075782011-02-10 14:55:22 +0200671 u16 u0x0111, u0x0113, u0x0115, u0x0117;
R.M. Thomas702422b2010-06-18 12:29:49 -0700672
Tomas Winkler68883932011-03-03 00:10:51 +0200673 if (!p)
Tomas Winkler72075782011-02-10 14:55:22 +0200674 return -ENODEV;
675 u0x0111 = ((0xFF00 & set0) >> 8);
676 u0x0113 = ((0xFF00 & set1) >> 8);
677 u0x0115 = ((0xFF00 & set2) >> 8);
678 u0x0117 = ((0xFF00 & set3) >> 8);
R.M. Thomas702422b2010-06-18 12:29:49 -0700679
Tomas Winkler72075782011-02-10 14:55:22 +0200680 SET(p, 0x0110, (0x00FF & set0));
681 SET(p, 0x0111, u0x0111);
682 SET(p, 0x0112, (0x00FF & set1));
683 SET(p, 0x0113, u0x0113);
684 SET(p, 0x0114, (0x00FF & set2));
685 SET(p, 0x0115, u0x0115);
686 SET(p, 0x0116, (0x00FF & set3));
687 SET(p, 0x0117, u0x0117);
R.M. Thomas702422b2010-06-18 12:29:49 -0700688
Tomas Winkler72075782011-02-10 14:55:22 +0200689 return 0;
R.M. Thomas702422b2010-06-18 12:29:49 -0700690}
691/****************************************************************************/
Tomas Winkler72075782011-02-10 14:55:22 +0200692int start_100(struct usb_device *p)
R.M. Thomas702422b2010-06-18 12:29:49 -0700693{
Tomas Winkler72075782011-02-10 14:55:22 +0200694 u16 get116, get117, get0;
695 u8 igot116, igot117, igot;
R.M. Thomas702422b2010-06-18 12:29:49 -0700696
Tomas Winkler68883932011-03-03 00:10:51 +0200697 if (!p)
Tomas Winkler72075782011-02-10 14:55:22 +0200698 return -ENODEV;
699 GET(p, 0x0116, &igot116);
700 get116 = igot116;
701 GET(p, 0x0117, &igot117);
702 get117 = igot117;
703 SET(p, 0x0116, 0x0000);
704 SET(p, 0x0117, 0x0000);
Mike Thomasf36bc372010-11-07 20:00:35 +0000705
Tomas Winkler72075782011-02-10 14:55:22 +0200706 GET(p, 0x0100, &igot);
707 get0 = igot;
708 SET(p, 0x0100, (0x80 | get0));
Mike Thomasf36bc372010-11-07 20:00:35 +0000709
Tomas Winkler72075782011-02-10 14:55:22 +0200710 SET(p, 0x0116, get116);
711 SET(p, 0x0117, get117);
Mike Thomasf36bc372010-11-07 20:00:35 +0000712
Tomas Winkler72075782011-02-10 14:55:22 +0200713 return 0;
R.M. Thomas702422b2010-06-18 12:29:49 -0700714}
715/****************************************************************************/
Tomas Winkler72075782011-02-10 14:55:22 +0200716int stop_100(struct usb_device *p)
R.M. Thomas702422b2010-06-18 12:29:49 -0700717{
Tomas Winkler72075782011-02-10 14:55:22 +0200718 u16 get0;
719 u8 igot;
R.M. Thomas702422b2010-06-18 12:29:49 -0700720
Tomas Winkler68883932011-03-03 00:10:51 +0200721 if (!p)
Tomas Winkler72075782011-02-10 14:55:22 +0200722 return -ENODEV;
723 GET(p, 0x0100, &igot);
724 get0 = igot;
725 SET(p, 0x0100, (0x7F & get0));
726 return 0;
R.M. Thomas702422b2010-06-18 12:29:49 -0700727}
728/****************************************************************************/
R.M. Thomas702422b2010-06-18 12:29:49 -0700729/****************************************************************************/
R.M. Thomas702422b2010-06-18 12:29:49 -0700730/*****************************************************************************/
Tomas Winkler96bec7d2011-11-09 08:26:40 -0300731int easycap_wakeup_device(struct usb_device *pusb_device)
R.M. Thomas702422b2010-06-18 12:29:49 -0700732{
Tomas Winkler72075782011-02-10 14:55:22 +0200733 if (!pusb_device)
734 return -ENODEV;
Tomas Winkler96bec7d2011-11-09 08:26:40 -0300735
Tomas Winkler72075782011-02-10 14:55:22 +0200736 return usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0),
Tomas Winkler3e17e392011-02-10 14:55:24 +0200737 USB_REQ_SET_FEATURE,
Tomas Winkler72075782011-02-10 14:55:22 +0200738 USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE,
739 USB_DEVICE_REMOTE_WAKEUP,
Tomas Winkler3e17e392011-02-10 14:55:24 +0200740 0, NULL, 0, 50000);
R.M. Thomas702422b2010-06-18 12:29:49 -0700741}
742/*****************************************************************************/
Tomas Winkler96bec7d2011-11-09 08:26:40 -0300743int easycap_audio_setup(struct easycap *peasycap)
Mike Thomase68703c2010-11-07 19:58:55 +0000744{
Tomas Winkler72075782011-02-10 14:55:22 +0200745 struct usb_device *pusb_device;
Tomas Winkler3e17e392011-02-10 14:55:24 +0200746 u8 buffer[1];
Tomas Winkler72075782011-02-10 14:55:22 +0200747 int rc, id1, id2;
R.M. Thomas702422b2010-06-18 12:29:49 -0700748/*---------------------------------------------------------------------------*/
749/*
750 * IMPORTANT:
751 * THE MESSAGE OF TYPE (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE)
752 * CAUSES MUTING IF THE VALUE 0x0100 IS SENT.
753 * TO ENABLE AUDIO THE VALUE 0x0200 MUST BE SENT.
754 */
755/*---------------------------------------------------------------------------*/
Tomas Winkler72075782011-02-10 14:55:22 +0200756 const u8 request = 0x01;
757 const u8 requesttype = USB_DIR_OUT |
758 USB_TYPE_CLASS |
759 USB_RECIP_INTERFACE;
760 const u16 value_unmute = 0x0200;
761 const u16 index = 0x0301;
762 const u16 length = 1;
R.M. Thomas702422b2010-06-18 12:29:49 -0700763
Tomas Winkler68883932011-03-03 00:10:51 +0200764 if (!peasycap)
Tomas Winkler72075782011-02-10 14:55:22 +0200765 return -EFAULT;
R.M. Thomas702422b2010-06-18 12:29:49 -0700766
Tomas Winkler72075782011-02-10 14:55:22 +0200767 pusb_device = peasycap->pusb_device;
Tomas Winkler68883932011-03-03 00:10:51 +0200768 if (!pusb_device)
Tomas Winkler72075782011-02-10 14:55:22 +0200769 return -ENODEV;
R.M. Thomas702422b2010-06-18 12:29:49 -0700770
Tomas Winkler72075782011-02-10 14:55:22 +0200771 JOM(8, "%02X %02X %02X %02X %02X %02X %02X %02X\n",
772 requesttype, request,
773 (0x00FF & value_unmute),
774 (0xFF00 & value_unmute) >> 8,
775 (0x00FF & index),
776 (0xFF00 & index) >> 8,
777 (0x00FF & length),
778 (0xFF00 & length) >> 8);
R.M. Thomas702422b2010-06-18 12:29:49 -0700779
Tomas Winkler72075782011-02-10 14:55:22 +0200780 buffer[0] = 0x01;
R.M. Thomas702422b2010-06-18 12:29:49 -0700781
Tomas Winkler72075782011-02-10 14:55:22 +0200782 rc = usb_control_msg(pusb_device, usb_sndctrlpipe(pusb_device, 0),
Tomas Winkler3e17e392011-02-10 14:55:24 +0200783 request, requesttype, value_unmute,
784 index, &buffer[0], length, 50000);
R.M. Thomas702422b2010-06-18 12:29:49 -0700785
Tomas Winkler3e17e392011-02-10 14:55:24 +0200786 JOT(8, "0x%02X=buffer\n", buffer[0]);
Tomas Winkler72075782011-02-10 14:55:22 +0200787 if (rc != (int)length) {
788 switch (rc) {
Tomas Winkler3e17e392011-02-10 14:55:24 +0200789 case -EPIPE:
Tomas Winkler72075782011-02-10 14:55:22 +0200790 SAY("usb_control_msg returned -EPIPE\n");
791 break;
Tomas Winkler3e17e392011-02-10 14:55:24 +0200792 default:
Tomas Winkler72075782011-02-10 14:55:22 +0200793 SAY("ERROR: usb_control_msg returned %i\n", rc);
794 break;
795 }
Mike Thomasa9855912011-01-10 18:41:11 +0000796 }
R.M. Thomas702422b2010-06-18 12:29:49 -0700797/*--------------------------------------------------------------------------*/
798/*
799 * REGISTER 500: SETTING VALUE TO 0x0094 RESETS AUDIO CONFIGURATION ???
800 * REGISTER 506: ANALOGUE AUDIO ATTENTUATOR ???
801 * FOR THE CVBS+S-VIDEO HARDWARE:
802 * SETTING VALUE TO 0x0000 GIVES QUIET SOUND.
803 * THE UPPER BYTE SEEMS TO HAVE NO EFFECT.
804 * FOR THE FOUR-CVBS HARDWARE:
805 * SETTING VALUE TO 0x0000 SEEMS TO HAVE NO EFFECT.
806 * REGISTER 507: ANALOGUE AUDIO PREAMPLIFIER ON/OFF ???
807 * FOR THE CVBS-S-VIDEO HARDWARE:
808 * SETTING VALUE TO 0x0001 GIVES VERY LOUD, DISTORTED SOUND.
809 * THE UPPER BYTE SEEMS TO HAVE NO EFFECT.
810 */
811/*--------------------------------------------------------------------------*/
Tomas Winkler72075782011-02-10 14:55:22 +0200812 SET(pusb_device, 0x0500, 0x0094);
813 SET(pusb_device, 0x0500, 0x008C);
814 SET(pusb_device, 0x0506, 0x0001);
815 SET(pusb_device, 0x0507, 0x0000);
816 id1 = read_vt(pusb_device, 0x007C);
817 id2 = read_vt(pusb_device, 0x007E);
818 SAM("0x%04X:0x%04X is audio vendor id\n", id1, id2);
Mike Thomas7ebc8762010-07-11 10:54:51 +0100819/*---------------------------------------------------------------------------*/
820/*
Mike Thomas94155cf2010-11-07 20:05:51 +0000821 * SELECT AUDIO SOURCE "LINE IN" AND SET THE AUDIO GAIN.
Mike Thomas7ebc8762010-07-11 10:54:51 +0100822*/
823/*---------------------------------------------------------------------------*/
Tomas Winkler96bec7d2011-11-09 08:26:40 -0300824 if (easycap_audio_gainset(pusb_device, peasycap->gain))
Tomas Winkler72075782011-02-10 14:55:22 +0200825 SAY("ERROR: audio_gainset() failed\n");
826 check_vt(pusb_device);
827 return 0;
R.M. Thomas702422b2010-06-18 12:29:49 -0700828}
829/*****************************************************************************/
Tomas Winkler72075782011-02-10 14:55:22 +0200830int check_vt(struct usb_device *pusb_device)
R.M. Thomas702422b2010-06-18 12:29:49 -0700831{
Tomas Winkler72075782011-02-10 14:55:22 +0200832 int igot;
R.M. Thomas702422b2010-06-18 12:29:49 -0700833
Tomas Winkler72075782011-02-10 14:55:22 +0200834 if (!pusb_device)
835 return -ENODEV;
836 igot = read_vt(pusb_device, 0x0002);
837 if (0 > igot)
838 SAY("ERROR: failed to read VT1612A register 0x02\n");
839 if (0x8000 & igot)
840 SAY("register 0x%02X muted\n", 0x02);
R.M. Thomas702422b2010-06-18 12:29:49 -0700841
Tomas Winkler72075782011-02-10 14:55:22 +0200842 igot = read_vt(pusb_device, 0x000E);
843 if (0 > igot)
844 SAY("ERROR: failed to read VT1612A register 0x0E\n");
845 if (0x8000 & igot)
846 SAY("register 0x%02X muted\n", 0x0E);
R.M. Thomas702422b2010-06-18 12:29:49 -0700847
Tomas Winkler72075782011-02-10 14:55:22 +0200848 igot = read_vt(pusb_device, 0x0010);
849 if (0 > igot)
850 SAY("ERROR: failed to read VT1612A register 0x10\n");
851 if (0x8000 & igot)
852 SAY("register 0x%02X muted\n", 0x10);
R.M. Thomas702422b2010-06-18 12:29:49 -0700853
Tomas Winkler72075782011-02-10 14:55:22 +0200854 igot = read_vt(pusb_device, 0x0012);
855 if (0 > igot)
856 SAY("ERROR: failed to read VT1612A register 0x12\n");
857 if (0x8000 & igot)
858 SAY("register 0x%02X muted\n", 0x12);
R.M. Thomas702422b2010-06-18 12:29:49 -0700859
Tomas Winkler72075782011-02-10 14:55:22 +0200860 igot = read_vt(pusb_device, 0x0014);
861 if (0 > igot)
862 SAY("ERROR: failed to read VT1612A register 0x14\n");
863 if (0x8000 & igot)
864 SAY("register 0x%02X muted\n", 0x14);
Mike Thomas94155cf2010-11-07 20:05:51 +0000865
Tomas Winkler72075782011-02-10 14:55:22 +0200866 igot = read_vt(pusb_device, 0x0016);
867 if (0 > igot)
868 SAY("ERROR: failed to read VT1612A register 0x16\n");
869 if (0x8000 & igot)
870 SAY("register 0x%02X muted\n", 0x16);
R.M. Thomas702422b2010-06-18 12:29:49 -0700871
Tomas Winkler72075782011-02-10 14:55:22 +0200872 igot = read_vt(pusb_device, 0x0018);
873 if (0 > igot)
874 SAY("ERROR: failed to read VT1612A register 0x18\n");
875 if (0x8000 & igot)
876 SAY("register 0x%02X muted\n", 0x18);
R.M. Thomas702422b2010-06-18 12:29:49 -0700877
Tomas Winkler72075782011-02-10 14:55:22 +0200878 igot = read_vt(pusb_device, 0x001C);
879 if (0 > igot)
880 SAY("ERROR: failed to read VT1612A register 0x1C\n");
881 if (0x8000 & igot)
882 SAY("register 0x%02X muted\n", 0x1C);
R.M. Thomas702422b2010-06-18 12:29:49 -0700883
Tomas Winkler72075782011-02-10 14:55:22 +0200884 return 0;
R.M. Thomas702422b2010-06-18 12:29:49 -0700885}
886/*****************************************************************************/
887/*---------------------------------------------------------------------------*/
Mike Thomas94155cf2010-11-07 20:05:51 +0000888/* NOTE: THIS DOES INCREASE THE VOLUME DRAMATICALLY:
889 * audio_gainset(pusb_device, 0x000F);
R.M. Thomas702422b2010-06-18 12:29:49 -0700890 *
Mike Thomas94155cf2010-11-07 20:05:51 +0000891 * loud dB register 0x10 dB register 0x1C dB total
892 * 0 -34.5 0 -34.5
893 * .. .... . ....
894 * 15 10.5 0 10.5
895 * 16 12.0 0 12.0
896 * 17 12.0 1.5 13.5
897 * .. .... .... ....
898 * 31 12.0 22.5 34.5
899*/
R.M. Thomas702422b2010-06-18 12:29:49 -0700900/*---------------------------------------------------------------------------*/
Tomas Winkler96bec7d2011-11-09 08:26:40 -0300901int easycap_audio_gainset(struct usb_device *pusb_device, s8 loud)
R.M. Thomas702422b2010-06-18 12:29:49 -0700902{
Tomas Winkler72075782011-02-10 14:55:22 +0200903 int igot;
904 u8 tmp;
905 u16 mute;
R.M. Thomas702422b2010-06-18 12:29:49 -0700906
Tomas Winkler68883932011-03-03 00:10:51 +0200907 if (!pusb_device)
Tomas Winkler72075782011-02-10 14:55:22 +0200908 return -ENODEV;
909 if (0 > loud)
910 loud = 0;
911 if (31 < loud)
912 loud = 31;
R.M. Thomas702422b2010-06-18 12:29:49 -0700913
Tomas Winkler72075782011-02-10 14:55:22 +0200914 write_vt(pusb_device, 0x0002, 0x8000);
Mike Thomas94155cf2010-11-07 20:05:51 +0000915/*---------------------------------------------------------------------------*/
Tomas Winkler72075782011-02-10 14:55:22 +0200916 igot = read_vt(pusb_device, 0x000E);
917 if (0 > igot) {
918 SAY("ERROR: failed to read VT1612A register 0x0E\n");
919 mute = 0x0000;
920 } else
921 mute = 0x8000 & ((unsigned int)igot);
922 mute = 0;
R.M. Thomas702422b2010-06-18 12:29:49 -0700923
Tomas Winkler72075782011-02-10 14:55:22 +0200924 if (16 > loud)
925 tmp = 0x01 | (0x001F & (((u8)(15 - loud)) << 1));
926 else
927 tmp = 0;
Mike Thomas94155cf2010-11-07 20:05:51 +0000928
Tomas Winkler72075782011-02-10 14:55:22 +0200929 JOT(8, "0x%04X=(mute|tmp) for VT1612A register 0x0E\n", mute | tmp);
930 write_vt(pusb_device, 0x000E, (mute | tmp));
Mike Thomas94155cf2010-11-07 20:05:51 +0000931/*---------------------------------------------------------------------------*/
Tomas Winkler72075782011-02-10 14:55:22 +0200932 igot = read_vt(pusb_device, 0x0010);
933 if (0 > igot) {
934 SAY("ERROR: failed to read VT1612A register 0x10\n");
935 mute = 0x0000;
936 } else
937 mute = 0x8000 & ((unsigned int)igot);
938 mute = 0;
Mike Thomas94155cf2010-11-07 20:05:51 +0000939
Tomas Winkler72075782011-02-10 14:55:22 +0200940 JOT(8, "0x%04X=(mute|tmp|(tmp<<8)) for VT1612A register 0x10,...0x18\n",
Tomas Winkler0117f772011-02-03 13:42:45 +0200941 mute | tmp | (tmp << 8));
Tomas Winkler72075782011-02-10 14:55:22 +0200942 write_vt(pusb_device, 0x0010, (mute | tmp | (tmp << 8)));
943 write_vt(pusb_device, 0x0012, (mute | tmp | (tmp << 8)));
944 write_vt(pusb_device, 0x0014, (mute | tmp | (tmp << 8)));
945 write_vt(pusb_device, 0x0016, (mute | tmp | (tmp << 8)));
946 write_vt(pusb_device, 0x0018, (mute | tmp | (tmp << 8)));
Mike Thomas94155cf2010-11-07 20:05:51 +0000947/*---------------------------------------------------------------------------*/
Tomas Winkler72075782011-02-10 14:55:22 +0200948 igot = read_vt(pusb_device, 0x001C);
949 if (0 > igot) {
950 SAY("ERROR: failed to read VT1612A register 0x1C\n");
951 mute = 0x0000;
952 } else
953 mute = 0x8000 & ((unsigned int)igot);
954 mute = 0;
R.M. Thomas702422b2010-06-18 12:29:49 -0700955
Tomas Winkler72075782011-02-10 14:55:22 +0200956 if (16 <= loud)
957 tmp = 0x000F & (u8)(loud - 16);
958 else
959 tmp = 0;
R.M. Thomas702422b2010-06-18 12:29:49 -0700960
Tomas Winkler72075782011-02-10 14:55:22 +0200961 JOT(8, "0x%04X=(mute|tmp|(tmp<<8)) for VT1612A register 0x1C\n",
962 mute | tmp | (tmp << 8));
963 write_vt(pusb_device, 0x001C, (mute | tmp | (tmp << 8)));
964 write_vt(pusb_device, 0x001A, 0x0404);
965 write_vt(pusb_device, 0x0002, 0x0000);
966 return 0;
R.M. Thomas702422b2010-06-18 12:29:49 -0700967}
968/*****************************************************************************/