diff options
-rw-r--r-- | drivers/media/video/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/video/msp3400-driver.c | 1144 | ||||
-rw-r--r-- | drivers/media/video/msp3400.c | 2289 | ||||
-rw-r--r-- | drivers/media/video/msp3400.h | 127 |
4 files changed, 1266 insertions, 2296 deletions
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile index 49aae8a54aa4..dd24896906fe 100644 --- a/drivers/media/video/Makefile +++ b/drivers/media/video/Makefile | |||
@@ -10,6 +10,8 @@ zr36067-objs := zoran_procfs.o zoran_device.o \ | |||
10 | zoran_driver.o zoran_card.o | 10 | zoran_driver.o zoran_card.o |
11 | tuner-objs := tuner-core.o tuner-simple.o mt20xx.o tda8290.o tea5767.o | 11 | tuner-objs := tuner-core.o tuner-simple.o mt20xx.o tda8290.o tea5767.o |
12 | 12 | ||
13 | msp3400-objs := msp3400-driver.o msp3400-kthreads.o | ||
14 | |||
13 | obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o compat_ioctl32.o | 15 | obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-common.o v4l1-compat.o compat_ioctl32.o |
14 | 16 | ||
15 | obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \ | 17 | obj-$(CONFIG_VIDEO_BT848) += bttv.o msp3400.o tvaudio.o \ |
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c new file mode 100644 index 000000000000..de79c641583a --- /dev/null +++ b/drivers/media/video/msp3400-driver.c | |||
@@ -0,0 +1,1144 @@ | |||
1 | /* | ||
2 | * Programming the mspx4xx sound processor family | ||
3 | * | ||
4 | * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org> | ||
5 | * | ||
6 | * what works and what doesn't: | ||
7 | * | ||
8 | * AM-Mono | ||
9 | * Support for Hauppauge cards added (decoding handled by tuner) added by | ||
10 | * Frederic Crozat <fcrozat@mail.dotcom.fr> | ||
11 | * | ||
12 | * FM-Mono | ||
13 | * should work. The stereo modes are backward compatible to FM-mono, | ||
14 | * therefore FM-Mono should be allways available. | ||
15 | * | ||
16 | * FM-Stereo (B/G, used in germany) | ||
17 | * should work, with autodetect | ||
18 | * | ||
19 | * FM-Stereo (satellite) | ||
20 | * should work, no autodetect (i.e. default is mono, but you can | ||
21 | * switch to stereo -- untested) | ||
22 | * | ||
23 | * NICAM (B/G, L , used in UK, Scandinavia, Spain and France) | ||
24 | * should work, with autodetect. Support for NICAM was added by | ||
25 | * Pekka Pietikainen <pp@netppl.fi> | ||
26 | * | ||
27 | * TODO: | ||
28 | * - better SAT support | ||
29 | * | ||
30 | * 980623 Thomas Sailer (sailer@ife.ee.ethz.ch) | ||
31 | * using soundcore instead of OSS | ||
32 | * | ||
33 | * This program is free software; you can redistribute it and/or | ||
34 | * modify it under the terms of the GNU General Public License | ||
35 | * as published by the Free Software Foundation; either version 2 | ||
36 | * of the License, or (at your option) any later version. | ||
37 | * | ||
38 | * This program is distributed in the hope that it will be useful, | ||
39 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
40 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
41 | * GNU General Public License for more details. | ||
42 | * | ||
43 | * You should have received a copy of the GNU General Public License | ||
44 | * along with this program; if not, write to the Free Software | ||
45 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
46 | */ | ||
47 | |||
48 | |||
49 | #include <linux/kernel.h> | ||
50 | #include <linux/module.h> | ||
51 | #include <linux/slab.h> | ||
52 | #include <linux/i2c.h> | ||
53 | #include <linux/videodev.h> | ||
54 | #include <linux/videodev2.h> | ||
55 | #include <media/v4l2-common.h> | ||
56 | #include <media/audiochip.h> | ||
57 | #include <linux/kthread.h> | ||
58 | #include <linux/suspend.h> | ||
59 | #include "msp3400.h" | ||
60 | |||
61 | /* ---------------------------------------------------------------------- */ | ||
62 | |||
63 | MODULE_DESCRIPTION("device driver for msp34xx TV sound processor"); | ||
64 | MODULE_AUTHOR("Gerd Knorr"); | ||
65 | MODULE_LICENSE("GPL"); | ||
66 | |||
67 | /* module parameters */ | ||
68 | static int opmode = OPMODE_AUTO; | ||
69 | int debug = 0; /* debug output */ | ||
70 | int once = 0; /* no continous stereo monitoring */ | ||
71 | int amsound = 0; /* hard-wire AM sound at 6.5 Hz (france), | ||
72 | the autoscan seems work well only with FM... */ | ||
73 | int standard = 1; /* Override auto detect of audio standard, if needed. */ | ||
74 | int dolby = 0; | ||
75 | |||
76 | int stereo_threshold = 0x190; /* a2 threshold for stereo/bilingual | ||
77 | (msp34xxg only) 0x00a0-0x03c0 */ | ||
78 | |||
79 | /* read-only */ | ||
80 | module_param(opmode, int, 0444); | ||
81 | |||
82 | /* read-write */ | ||
83 | module_param(once, int, 0644); | ||
84 | module_param(debug, int, 0644); | ||
85 | module_param(stereo_threshold, int, 0644); | ||
86 | module_param(standard, int, 0644); | ||
87 | module_param(amsound, int, 0644); | ||
88 | module_param(dolby, int, 0644); | ||
89 | |||
90 | MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect"); | ||
91 | MODULE_PARM_DESC(once, "No continuous stereo monitoring"); | ||
92 | MODULE_PARM_DESC(debug, "Enable debug messages [0-3]"); | ||
93 | MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo"); | ||
94 | MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect"); | ||
95 | MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan"); | ||
96 | MODULE_PARM_DESC(dolby, "Activates Dolby processsing"); | ||
97 | |||
98 | /* ---------------------------------------------------------------------- */ | ||
99 | |||
100 | /* control subaddress */ | ||
101 | #define I2C_MSP_CONTROL 0x00 | ||
102 | /* demodulator unit subaddress */ | ||
103 | #define I2C_MSP_DEM 0x10 | ||
104 | /* DSP unit subaddress */ | ||
105 | #define I2C_MSP_DSP 0x12 | ||
106 | |||
107 | /* Addresses to scan */ | ||
108 | static unsigned short normal_i2c[] = { 0x80 >> 1, 0x88 >> 1, I2C_CLIENT_END }; | ||
109 | |||
110 | I2C_CLIENT_INSMOD; | ||
111 | |||
112 | |||
113 | /* ----------------------------------------------------------------------- */ | ||
114 | /* functions for talking to the MSP3400C Sound processor */ | ||
115 | |||
116 | int msp_reset(struct i2c_client *client) | ||
117 | { | ||
118 | /* reset and read revision code */ | ||
119 | static u8 reset_off[3] = { I2C_MSP_CONTROL, 0x80, 0x00 }; | ||
120 | static u8 reset_on[3] = { I2C_MSP_CONTROL, 0x00, 0x00 }; | ||
121 | static u8 write[3] = { I2C_MSP_DSP + 1, 0x00, 0x1e }; | ||
122 | u8 read[2]; | ||
123 | struct i2c_msg reset[2] = { | ||
124 | { client->addr, I2C_M_IGNORE_NAK, 3, reset_off }, | ||
125 | { client->addr, I2C_M_IGNORE_NAK, 3, reset_on }, | ||
126 | }; | ||
127 | struct i2c_msg test[2] = { | ||
128 | { client->addr, 0, 3, write }, | ||
129 | { client->addr, I2C_M_RD, 2, read }, | ||
130 | }; | ||
131 | |||
132 | msp_dbg3("msp_reset\n"); | ||
133 | if (i2c_transfer(client->adapter, &reset[0], 1) != 1 || | ||
134 | i2c_transfer(client->adapter, &reset[1], 1) != 1 || | ||
135 | i2c_transfer(client->adapter, test, 2) != 2) { | ||
136 | msp_err("chip reset failed\n"); | ||
137 | return -1; | ||
138 | } | ||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | static int msp_read(struct i2c_client *client, int dev, int addr) | ||
143 | { | ||
144 | int err, retval; | ||
145 | u8 write[3]; | ||
146 | u8 read[2]; | ||
147 | struct i2c_msg msgs[2] = { | ||
148 | { client->addr, 0, 3, write }, | ||
149 | { client->addr, I2C_M_RD, 2, read } | ||
150 | }; | ||
151 | |||
152 | write[0] = dev + 1; | ||
153 | write[1] = addr >> 8; | ||
154 | write[2] = addr & 0xff; | ||
155 | |||
156 | for (err = 0; err < 3; err++) { | ||
157 | if (i2c_transfer(client->adapter, msgs, 2) == 2) | ||
158 | break; | ||
159 | msp_warn("I/O error #%d (read 0x%02x/0x%02x)\n", err, | ||
160 | dev, addr); | ||
161 | current->state = TASK_INTERRUPTIBLE; | ||
162 | schedule_timeout(msecs_to_jiffies(10)); | ||
163 | } | ||
164 | if (err == 3) { | ||
165 | msp_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n"); | ||
166 | msp_reset(client); | ||
167 | return -1; | ||
168 | } | ||
169 | retval = read[0] << 8 | read[1]; | ||
170 | msp_dbg3("msp_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval); | ||
171 | return retval; | ||
172 | } | ||
173 | |||
174 | int msp_read_dem(struct i2c_client *client, int addr) | ||
175 | { | ||
176 | return msp_read(client, I2C_MSP_DEM, addr); | ||
177 | } | ||
178 | |||
179 | int msp_read_dsp(struct i2c_client *client, int addr) | ||
180 | { | ||
181 | return msp_read(client, I2C_MSP_DSP, addr); | ||
182 | } | ||
183 | |||
184 | static int msp_write(struct i2c_client *client, int dev, int addr, int val) | ||
185 | { | ||
186 | int err; | ||
187 | u8 buffer[5]; | ||
188 | |||
189 | buffer[0] = dev; | ||
190 | buffer[1] = addr >> 8; | ||
191 | buffer[2] = addr & 0xff; | ||
192 | buffer[3] = val >> 8; | ||
193 | buffer[4] = val & 0xff; | ||
194 | |||
195 | msp_dbg3("msp_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val); | ||
196 | for (err = 0; err < 3; err++) { | ||
197 | if (i2c_master_send(client, buffer, 5) == 5) | ||
198 | break; | ||
199 | msp_warn("I/O error #%d (write 0x%02x/0x%02x)\n", err, | ||
200 | dev, addr); | ||
201 | current->state = TASK_INTERRUPTIBLE; | ||
202 | schedule_timeout(msecs_to_jiffies(10)); | ||
203 | } | ||
204 | if (err == 3) { | ||
205 | msp_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n"); | ||
206 | msp_reset(client); | ||
207 | return -1; | ||
208 | } | ||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | int msp_write_dem(struct i2c_client *client, int addr, int val) | ||
213 | { | ||
214 | return msp_write(client, I2C_MSP_DEM, addr, val); | ||
215 | } | ||
216 | |||
217 | int msp_write_dsp(struct i2c_client *client, int addr, int val) | ||
218 | { | ||
219 | return msp_write(client, I2C_MSP_DSP, addr, val); | ||
220 | } | ||
221 | |||
222 | /* ----------------------------------------------------------------------- * | ||
223 | * bits 9 8 5 - SCART DSP input Select: | ||
224 | * 0 0 0 - SCART 1 to DSP input (reset position) | ||
225 | * 0 1 0 - MONO to DSP input | ||
226 | * 1 0 0 - SCART 2 to DSP input | ||
227 | * 1 1 1 - Mute DSP input | ||
228 | * | ||
229 | * bits 11 10 6 - SCART 1 Output Select: | ||
230 | * 0 0 0 - undefined (reset position) | ||
231 | * 0 1 0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS) | ||
232 | * 1 0 0 - MONO input to SCART 1 Output | ||
233 | * 1 1 0 - SCART 1 DA to SCART 1 Output | ||
234 | * 0 0 1 - SCART 2 DA to SCART 1 Output | ||
235 | * 0 1 1 - SCART 1 Input to SCART 1 Output | ||
236 | * 1 1 1 - Mute SCART 1 Output | ||
237 | * | ||
238 | * bits 13 12 7 - SCART 2 Output Select (for devices with 2 Output SCART): | ||
239 | * 0 0 0 - SCART 1 DA to SCART 2 Output (reset position) | ||
240 | * 0 1 0 - SCART 1 Input to SCART 2 Output | ||
241 | * 1 0 0 - MONO input to SCART 2 Output | ||
242 | * 0 0 1 - SCART 2 DA to SCART 2 Output | ||
243 | * 0 1 1 - SCART 2 Input to SCART 2 Output | ||
244 | * 1 1 0 - Mute SCART 2 Output | ||
245 | * | ||
246 | * Bits 4 to 0 should be zero. | ||
247 | * ----------------------------------------------------------------------- */ | ||
248 | |||
249 | static int scarts[3][9] = { | ||
250 | /* MASK IN1 IN2 IN1_DA IN2_DA IN3 IN4 MONO MUTE */ | ||
251 | /* SCART DSP Input select */ | ||
252 | { 0x0320, 0x0000, 0x0200, -1, -1, 0x0300, 0x0020, 0x0100, 0x0320 }, | ||
253 | /* SCART1 Output select */ | ||
254 | { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 }, | ||
255 | /* SCART2 Output select */ | ||
256 | { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 }, | ||
257 | }; | ||
258 | |||
259 | static char *scart_names[] = { | ||
260 | "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute" | ||
261 | }; | ||
262 | |||
263 | void msp_set_scart(struct i2c_client *client, int in, int out) | ||
264 | { | ||
265 | struct msp_state *state = i2c_get_clientdata(client); | ||
266 | |||
267 | state->in_scart=in; | ||
268 | |||
269 | if (in >= 1 && in <= 8 && out >= 0 && out <= 2) { | ||
270 | if (-1 == scarts[out][in]) | ||
271 | return; | ||
272 | |||
273 | state->acb &= ~scarts[out][SCART_MASK]; | ||
274 | state->acb |= scarts[out][in]; | ||
275 | } else | ||
276 | state->acb = 0xf60; /* Mute Input and SCART 1 Output */ | ||
277 | |||
278 | msp_dbg1("scart switch: %s => %d (ACB=0x%04x)\n", | ||
279 | scart_names[in], out, state->acb); | ||
280 | msp_write_dsp(client, 0x13, state->acb); | ||
281 | |||
282 | /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */ | ||
283 | msp_write_dem(client, 0x40, state->i2s_mode); | ||
284 | } | ||
285 | |||
286 | void msp_set_mute(struct i2c_client *client) | ||
287 | { | ||
288 | msp_dbg1("mute audio\n"); | ||
289 | msp_write_dsp(client, 0x0000, 0); /* loudspeaker */ | ||
290 | msp_write_dsp(client, 0x0006, 0); /* headphones */ | ||
291 | } | ||
292 | |||
293 | void msp_set_audio(struct i2c_client *client) | ||
294 | { | ||
295 | struct msp_state *state = i2c_get_clientdata(client); | ||
296 | int val = 0, bal = 0, bass, treble; | ||
297 | |||
298 | if (!state->muted) | ||
299 | val = (state->volume * 0x7f / 65535) << 8; | ||
300 | if (val) | ||
301 | bal = (state->balance / 256) - 128; | ||
302 | bass = ((state->bass - 32768) * 0x60 / 65535) << 8; | ||
303 | treble = ((state->treble - 32768) * 0x60 / 65535) << 8; | ||
304 | |||
305 | msp_dbg1("mute=%s volume=%d balance=%d bass=%d treble=%d\n", | ||
306 | state->muted ? "on" : "off", state->volume, state->balance, | ||
307 | state->bass, state->treble); | ||
308 | |||
309 | msp_write_dsp(client, 0x0000, val); /* loudspeaker */ | ||
310 | msp_write_dsp(client, 0x0006, val); /* headphones */ | ||
311 | msp_write_dsp(client, 0x0007, state->muted ? 0x1 : (val | 0x1)); | ||
312 | msp_write_dsp(client, 0x0001, bal << 8); | ||
313 | msp_write_dsp(client, 0x0002, bass); /* loudspeaker */ | ||
314 | msp_write_dsp(client, 0x0003, treble); /* loudspeaker */ | ||
315 | } | ||
316 | |||
317 | int msp_modus(struct i2c_client *client, int norm) | ||
318 | { | ||
319 | switch (norm) { | ||
320 | case VIDEO_MODE_PAL: | ||
321 | msp_dbg1("video mode selected to PAL\n"); | ||
322 | |||
323 | #if 1 | ||
324 | /* experimental: not sure this works with all chip versions */ | ||
325 | return 0x7003; | ||
326 | #else | ||
327 | /* previous value, try this if it breaks ... */ | ||
328 | return 0x1003; | ||
329 | #endif | ||
330 | case VIDEO_MODE_NTSC: /* BTSC */ | ||
331 | msp_dbg1("video mode selected to NTSC\n"); | ||
332 | return 0x2003; | ||
333 | case VIDEO_MODE_SECAM: | ||
334 | msp_dbg1("video mode selected to SECAM\n"); | ||
335 | return 0x0003; | ||
336 | case VIDEO_MODE_RADIO: | ||
337 | msp_dbg1("video mode selected to Radio\n"); | ||
338 | return 0x0003; | ||
339 | case VIDEO_MODE_AUTO: | ||
340 | msp_dbg1("video mode selected to Auto\n"); | ||
341 | return 0x2003; | ||
342 | default: | ||
343 | return 0x0003; | ||
344 | } | ||
345 | } | ||
346 | |||
347 | int msp_standard(int norm) | ||
348 | { | ||
349 | switch (norm) { | ||
350 | case VIDEO_MODE_PAL: | ||
351 | return 1; | ||
352 | case VIDEO_MODE_NTSC: /* BTSC */ | ||
353 | return 0x0020; | ||
354 | case VIDEO_MODE_SECAM: | ||
355 | return 1; | ||
356 | case VIDEO_MODE_RADIO: | ||
357 | return 0x0040; | ||
358 | default: | ||
359 | return 1; | ||
360 | } | ||
361 | } | ||
362 | |||
363 | /* ------------------------------------------------------------------------ */ | ||
364 | |||
365 | |||
366 | static void msp_wake_thread(struct i2c_client *client) | ||
367 | { | ||
368 | struct msp_state *state = i2c_get_clientdata(client); | ||
369 | |||
370 | if (NULL == state->kthread) | ||
371 | return; | ||
372 | msp_set_mute(client); | ||
373 | state->watch_stereo = 0; | ||
374 | state->restart = 1; | ||
375 | wake_up_interruptible(&state->wq); | ||
376 | } | ||
377 | |||
378 | int msp_sleep(struct msp_state *state, int timeout) | ||
379 | { | ||
380 | DECLARE_WAITQUEUE(wait, current); | ||
381 | |||
382 | add_wait_queue(&state->wq, &wait); | ||
383 | if (!kthread_should_stop()) { | ||
384 | if (timeout < 0) { | ||
385 | set_current_state(TASK_INTERRUPTIBLE); | ||
386 | schedule(); | ||
387 | } else { | ||
388 | schedule_timeout_interruptible | ||
389 | (msecs_to_jiffies(timeout)); | ||
390 | } | ||
391 | } | ||
392 | |||
393 | remove_wait_queue(&state->wq, &wait); | ||
394 | try_to_freeze(); | ||
395 | return state->restart; | ||
396 | } | ||
397 | |||
398 | /* ------------------------------------------------------------------------ */ | ||
399 | |||
400 | static int msp_mode_v4l2_to_v4l1(int rxsubchans) | ||
401 | { | ||
402 | int mode = 0; | ||
403 | |||
404 | if (rxsubchans & V4L2_TUNER_SUB_STEREO) | ||
405 | mode |= VIDEO_SOUND_STEREO; | ||
406 | if (rxsubchans & V4L2_TUNER_SUB_LANG2) | ||
407 | mode |= VIDEO_SOUND_LANG2; | ||
408 | if (rxsubchans & V4L2_TUNER_SUB_LANG1) | ||
409 | mode |= VIDEO_SOUND_LANG1; | ||
410 | if (mode == 0) | ||
411 | mode |= VIDEO_SOUND_MONO; | ||
412 | return mode; | ||
413 | } | ||
414 | |||
415 | static int msp_mode_v4l1_to_v4l2(int mode) | ||
416 | { | ||
417 | if (mode & VIDEO_SOUND_STEREO) | ||
418 | return V4L2_TUNER_MODE_STEREO; | ||
419 | if (mode & VIDEO_SOUND_LANG2) | ||
420 | return V4L2_TUNER_MODE_LANG2; | ||
421 | if (mode & VIDEO_SOUND_LANG1) | ||
422 | return V4L2_TUNER_MODE_LANG1; | ||
423 | return V4L2_TUNER_MODE_MONO; | ||
424 | } | ||
425 | |||
426 | static void msp_any_detect_stereo(struct i2c_client *client) | ||
427 | { | ||
428 | struct msp_state *state = i2c_get_clientdata(client); | ||
429 | |||
430 | switch (state->opmode) { | ||
431 | case OPMODE_MANUAL: | ||
432 | case OPMODE_AUTODETECT: | ||
433 | autodetect_stereo(client); | ||
434 | break; | ||
435 | case OPMODE_AUTOSELECT: | ||
436 | msp34xxg_detect_stereo(client); | ||
437 | break; | ||
438 | } | ||
439 | } | ||
440 | |||
441 | static struct v4l2_queryctrl msp_qctrl[] = { | ||
442 | { | ||
443 | .id = V4L2_CID_AUDIO_VOLUME, | ||
444 | .name = "Volume", | ||
445 | .minimum = 0, | ||
446 | .maximum = 65535, | ||
447 | .step = 65535/100, | ||
448 | .default_value = 58880, | ||
449 | .flags = 0, | ||
450 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
451 | },{ | ||
452 | .id = V4L2_CID_AUDIO_BALANCE, | ||
453 | .name = "Balance", | ||
454 | .minimum = 0, | ||
455 | .maximum = 65535, | ||
456 | .step = 65535/100, | ||
457 | .default_value = 32768, | ||
458 | .flags = 0, | ||
459 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
460 | },{ | ||
461 | .id = V4L2_CID_AUDIO_MUTE, | ||
462 | .name = "Mute", | ||
463 | .minimum = 0, | ||
464 | .maximum = 1, | ||
465 | .step = 1, | ||
466 | .default_value = 1, | ||
467 | .flags = 0, | ||
468 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
469 | },{ | ||
470 | .id = V4L2_CID_AUDIO_BASS, | ||
471 | .name = "Bass", | ||
472 | .minimum = 0, | ||
473 | .maximum = 65535, | ||
474 | .step = 65535/100, | ||
475 | .default_value = 32768, | ||
476 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
477 | },{ | ||
478 | .id = V4L2_CID_AUDIO_TREBLE, | ||
479 | .name = "Treble", | ||
480 | .minimum = 0, | ||
481 | .maximum = 65535, | ||
482 | .step = 65535/100, | ||
483 | .default_value = 32768, | ||
484 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
485 | }, | ||
486 | }; | ||
487 | |||
488 | |||
489 | static void msp_any_set_audmode(struct i2c_client *client, int audmode) | ||
490 | { | ||
491 | struct msp_state *state = i2c_get_clientdata(client); | ||
492 | |||
493 | switch (state->opmode) { | ||
494 | case OPMODE_MANUAL: | ||
495 | case OPMODE_AUTODETECT: | ||
496 | state->watch_stereo = 0; | ||
497 | msp3400c_setstereo(client, audmode); | ||
498 | break; | ||
499 | case OPMODE_AUTOSELECT: | ||
500 | msp34xxg_set_audmode(client, audmode); | ||
501 | break; | ||
502 | } | ||
503 | } | ||
504 | |||
505 | static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) | ||
506 | { | ||
507 | struct msp_state *state = i2c_get_clientdata(client); | ||
508 | |||
509 | switch (ctrl->id) { | ||
510 | case V4L2_CID_AUDIO_MUTE: | ||
511 | ctrl->value = state->muted; | ||
512 | break; | ||
513 | |||
514 | case V4L2_CID_AUDIO_BALANCE: | ||
515 | ctrl->value = state->balance; | ||
516 | break; | ||
517 | |||
518 | case V4L2_CID_AUDIO_BASS: | ||
519 | ctrl->value = state->bass; | ||
520 | break; | ||
521 | |||
522 | case V4L2_CID_AUDIO_TREBLE: | ||
523 | ctrl->value = state->treble; | ||
524 | break; | ||
525 | |||
526 | case V4L2_CID_AUDIO_VOLUME: | ||
527 | ctrl->value = state->volume; | ||
528 | break; | ||
529 | |||
530 | default: | ||
531 | return -EINVAL; | ||
532 | } | ||
533 | return 0; | ||
534 | } | ||
535 | |||
536 | static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) | ||
537 | { | ||
538 | struct msp_state *state = i2c_get_clientdata(client); | ||
539 | |||
540 | switch (ctrl->id) { | ||
541 | case V4L2_CID_AUDIO_MUTE: | ||
542 | if (ctrl->value < 0 || ctrl->value >= 2) | ||
543 | return -ERANGE; | ||
544 | state->muted = ctrl->value; | ||
545 | break; | ||
546 | |||
547 | case V4L2_CID_AUDIO_BASS: | ||
548 | state->bass = ctrl->value; | ||
549 | break; | ||
550 | |||
551 | case V4L2_CID_AUDIO_TREBLE: | ||
552 | state->treble = ctrl->value; | ||
553 | break; | ||
554 | |||
555 | case V4L2_CID_AUDIO_BALANCE: | ||
556 | state->balance = ctrl->value; | ||
557 | break; | ||
558 | |||
559 | case V4L2_CID_AUDIO_VOLUME: | ||
560 | state->volume = ctrl->value; | ||
561 | if (state->volume == 0) | ||
562 | state->balance = 32768; | ||
563 | break; | ||
564 | |||
565 | default: | ||
566 | return -EINVAL; | ||
567 | } | ||
568 | msp_set_audio(client); | ||
569 | return 0; | ||
570 | } | ||
571 | |||
572 | static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) | ||
573 | { | ||
574 | struct msp_state *state = i2c_get_clientdata(client); | ||
575 | u16 *sarg = arg; | ||
576 | int scart = 0; | ||
577 | |||
578 | if (debug >= 2) | ||
579 | v4l_i2c_print_ioctl(client, cmd); | ||
580 | |||
581 | switch (cmd) { | ||
582 | case AUDC_SET_INPUT: | ||
583 | if (*sarg == state->input) | ||
584 | break; | ||
585 | state->input = *sarg; | ||
586 | switch (*sarg) { | ||
587 | case AUDIO_RADIO: | ||
588 | /* Hauppauge uses IN2 for the radio */ | ||
589 | state->mode = MSP_MODE_FM_RADIO; | ||
590 | scart = SCART_IN2; | ||
591 | break; | ||
592 | case AUDIO_EXTERN_1: | ||
593 | /* IN1 is often used for external input ... */ | ||
594 | state->mode = MSP_MODE_EXTERN; | ||
595 | scart = SCART_IN1; | ||
596 | break; | ||
597 | case AUDIO_EXTERN_2: | ||
598 | /* ... sometimes it is IN2 through ;) */ | ||
599 | state->mode = MSP_MODE_EXTERN; | ||
600 | scart = SCART_IN2; | ||
601 | break; | ||
602 | case AUDIO_TUNER: | ||
603 | state->mode = -1; | ||
604 | break; | ||
605 | default: | ||
606 | if (*sarg & AUDIO_MUTE) | ||
607 | msp_set_scart(client, SCART_MUTE, 0); | ||
608 | break; | ||
609 | } | ||
610 | if (scart) { | ||
611 | state->rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
612 | state->audmode = V4L2_TUNER_MODE_STEREO; | ||
613 | msp_set_scart(client, scart, 0); | ||
614 | msp_write_dsp(client, 0x000d, 0x1900); | ||
615 | if (state->opmode != OPMODE_AUTOSELECT) | ||
616 | msp3400c_setstereo(client, state->audmode); | ||
617 | } | ||
618 | msp_wake_thread(client); | ||
619 | break; | ||
620 | |||
621 | case AUDC_SET_RADIO: | ||
622 | state->norm = VIDEO_MODE_RADIO; | ||
623 | msp_dbg1("switching to radio mode\n"); | ||
624 | state->watch_stereo = 0; | ||
625 | switch (state->opmode) { | ||
626 | case OPMODE_MANUAL: | ||
627 | /* set msp3400 to FM radio mode */ | ||
628 | msp3400c_setmode(client, MSP_MODE_FM_RADIO); | ||
629 | msp3400c_setcarrier(client, MSP_CARRIER(10.7), | ||
630 | MSP_CARRIER(10.7)); | ||
631 | msp_set_audio(client); | ||
632 | break; | ||
633 | case OPMODE_AUTODETECT: | ||
634 | case OPMODE_AUTOSELECT: | ||
635 | /* the thread will do for us */ | ||
636 | msp_wake_thread(client); | ||
637 | break; | ||
638 | } | ||
639 | break; | ||
640 | |||
641 | /* --- v4l ioctls --- */ | ||
642 | /* take care: bttv does userspace copying, we'll get a | ||
643 | kernel pointer here... */ | ||
644 | case VIDIOCGAUDIO: | ||
645 | { | ||
646 | struct video_audio *va = arg; | ||
647 | |||
648 | va->flags |= VIDEO_AUDIO_VOLUME | | ||
649 | VIDEO_AUDIO_BASS | | ||
650 | VIDEO_AUDIO_TREBLE | | ||
651 | VIDEO_AUDIO_MUTABLE; | ||
652 | if (state->muted) | ||
653 | va->flags |= VIDEO_AUDIO_MUTE; | ||
654 | |||
655 | if (state->muted) | ||
656 | va->flags |= VIDEO_AUDIO_MUTE; | ||
657 | va->volume = state->volume; | ||
658 | va->balance = state->volume ? state->balance : 32768; | ||
659 | va->bass = state->bass; | ||
660 | va->treble = state->treble; | ||
661 | |||
662 | msp_any_detect_stereo(client); | ||
663 | va->mode = msp_mode_v4l2_to_v4l1(state->rxsubchans); | ||
664 | break; | ||
665 | } | ||
666 | |||
667 | case VIDIOCSAUDIO: | ||
668 | { | ||
669 | struct video_audio *va = arg; | ||
670 | |||
671 | state->muted = (va->flags & VIDEO_AUDIO_MUTE); | ||
672 | state->volume = va->volume; | ||
673 | state->balance = va->balance; | ||
674 | state->bass = va->bass; | ||
675 | state->treble = va->treble; | ||
676 | msp_set_audio(client); | ||
677 | |||
678 | if (va->mode != 0 && state->norm != VIDEO_MODE_RADIO) | ||
679 | msp_any_set_audmode(client, msp_mode_v4l1_to_v4l2(va->mode)); | ||
680 | break; | ||
681 | } | ||
682 | |||
683 | case VIDIOCSCHAN: | ||
684 | { | ||
685 | struct video_channel *vc = arg; | ||
686 | |||
687 | state->norm = vc->norm; | ||
688 | msp_wake_thread(client); | ||
689 | break; | ||
690 | } | ||
691 | |||
692 | case VIDIOCSFREQ: | ||
693 | case VIDIOC_S_FREQUENCY: | ||
694 | { | ||
695 | /* new channel -- kick audio carrier scan */ | ||
696 | msp_wake_thread(client); | ||
697 | break; | ||
698 | } | ||
699 | |||
700 | /* msp34xx specific */ | ||
701 | case MSP_SET_MATRIX: | ||
702 | { | ||
703 | struct msp_matrix *mspm = arg; | ||
704 | |||
705 | msp_set_scart(client, mspm->input, mspm->output); | ||
706 | break; | ||
707 | } | ||
708 | |||
709 | /* --- v4l2 ioctls --- */ | ||
710 | case VIDIOC_S_STD: | ||
711 | { | ||
712 | v4l2_std_id *id = arg; | ||
713 | |||
714 | /*FIXME: use V4L2 mode flags on msp3400 instead of V4L1*/ | ||
715 | if (*id & V4L2_STD_PAL) { | ||
716 | state->norm = VIDEO_MODE_PAL; | ||
717 | } else if (*id & V4L2_STD_SECAM) { | ||
718 | state->norm = VIDEO_MODE_SECAM; | ||
719 | } else { | ||
720 | state->norm = VIDEO_MODE_NTSC; | ||
721 | } | ||
722 | |||
723 | msp_wake_thread(client); | ||
724 | return 0; | ||
725 | } | ||
726 | |||
727 | case VIDIOC_ENUMINPUT: | ||
728 | { | ||
729 | struct v4l2_input *i = arg; | ||
730 | |||
731 | if (i->index != 0) | ||
732 | return -EINVAL; | ||
733 | |||
734 | i->type = V4L2_INPUT_TYPE_TUNER; | ||
735 | switch (i->index) { | ||
736 | case AUDIO_RADIO: | ||
737 | strcpy(i->name, "Radio"); | ||
738 | break; | ||
739 | case AUDIO_EXTERN_1: | ||
740 | strcpy(i->name, "Extern 1"); | ||
741 | break; | ||
742 | case AUDIO_EXTERN_2: | ||
743 | strcpy(i->name, "Extern 2"); | ||
744 | break; | ||
745 | case AUDIO_TUNER: | ||
746 | strcpy(i->name, "Television"); | ||
747 | break; | ||
748 | default: | ||
749 | return -EINVAL; | ||
750 | } | ||
751 | return 0; | ||
752 | } | ||
753 | |||
754 | case VIDIOC_G_AUDIO: | ||
755 | { | ||
756 | struct v4l2_audio *a = arg; | ||
757 | |||
758 | memset(a, 0, sizeof(*a)); | ||
759 | |||
760 | switch (a->index) { | ||
761 | case AUDIO_RADIO: | ||
762 | strcpy(a->name, "Radio"); | ||
763 | break; | ||
764 | case AUDIO_EXTERN_1: | ||
765 | strcpy(a->name, "Extern 1"); | ||
766 | break; | ||
767 | case AUDIO_EXTERN_2: | ||
768 | strcpy(a->name, "Extern 2"); | ||
769 | break; | ||
770 | case AUDIO_TUNER: | ||
771 | strcpy(a->name, "Television"); | ||
772 | break; | ||
773 | default: | ||
774 | return -EINVAL; | ||
775 | } | ||
776 | |||
777 | msp_any_detect_stereo(client); | ||
778 | if (state->audmode == V4L2_TUNER_MODE_STEREO) { | ||
779 | a->capability = V4L2_AUDCAP_STEREO; | ||
780 | } | ||
781 | |||
782 | break; | ||
783 | } | ||
784 | |||
785 | case VIDIOC_S_AUDIO: | ||
786 | { | ||
787 | struct v4l2_audio *sarg = arg; | ||
788 | |||
789 | switch (sarg->index) { | ||
790 | case AUDIO_RADIO: | ||
791 | /* Hauppauge uses IN2 for the radio */ | ||
792 | state->mode = MSP_MODE_FM_RADIO; | ||
793 | scart = SCART_IN2; | ||
794 | break; | ||
795 | case AUDIO_EXTERN_1: | ||
796 | /* IN1 is often used for external input ... */ | ||
797 | state->mode = MSP_MODE_EXTERN; | ||
798 | scart = SCART_IN1; | ||
799 | break; | ||
800 | case AUDIO_EXTERN_2: | ||
801 | /* ... sometimes it is IN2 through ;) */ | ||
802 | state->mode = MSP_MODE_EXTERN; | ||
803 | scart = SCART_IN2; | ||
804 | break; | ||
805 | case AUDIO_TUNER: | ||
806 | state->mode = -1; | ||
807 | break; | ||
808 | } | ||
809 | if (scart) { | ||
810 | state->rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
811 | state->audmode = V4L2_TUNER_MODE_STEREO; | ||
812 | msp_set_scart(client, scart, 0); | ||
813 | msp_write_dsp(client, 0x000d, 0x1900); | ||
814 | } | ||
815 | if (sarg->capability == V4L2_AUDCAP_STEREO) { | ||
816 | state->audmode = V4L2_TUNER_MODE_STEREO; | ||
817 | } else { | ||
818 | state->audmode &= ~V4L2_TUNER_MODE_STEREO; | ||
819 | } | ||
820 | msp_any_set_audmode(client, state->audmode); | ||
821 | msp_wake_thread(client); | ||
822 | break; | ||
823 | } | ||
824 | |||
825 | case VIDIOC_G_TUNER: | ||
826 | { | ||
827 | struct v4l2_tuner *vt = arg; | ||
828 | |||
829 | msp_any_detect_stereo(client); | ||
830 | vt->audmode = state->audmode; | ||
831 | vt->rxsubchans = state->rxsubchans; | ||
832 | vt->capability = V4L2_TUNER_CAP_STEREO | | ||
833 | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; | ||
834 | break; | ||
835 | } | ||
836 | |||
837 | case VIDIOC_S_TUNER: | ||
838 | { | ||
839 | struct v4l2_tuner *vt = (struct v4l2_tuner *)arg; | ||
840 | |||
841 | /* only set audmode */ | ||
842 | if (vt->audmode != -1 && vt->audmode != 0) | ||
843 | msp_any_set_audmode(client, vt->audmode); | ||
844 | break; | ||
845 | } | ||
846 | |||
847 | case VIDIOC_G_AUDOUT: | ||
848 | { | ||
849 | struct v4l2_audioout *a = (struct v4l2_audioout *)arg; | ||
850 | int idx = a->index; | ||
851 | |||
852 | memset(a, 0, sizeof(*a)); | ||
853 | |||
854 | switch (idx) { | ||
855 | case 0: | ||
856 | strcpy(a->name, "Scart1 Out"); | ||
857 | break; | ||
858 | case 1: | ||
859 | strcpy(a->name, "Scart2 Out"); | ||
860 | break; | ||
861 | case 2: | ||
862 | strcpy(a->name, "I2S Out"); | ||
863 | break; | ||
864 | default: | ||
865 | return -EINVAL; | ||
866 | } | ||
867 | break; | ||
868 | |||
869 | } | ||
870 | |||
871 | case VIDIOC_S_AUDOUT: | ||
872 | { | ||
873 | struct v4l2_audioout *a = (struct v4l2_audioout *)arg; | ||
874 | |||
875 | if (a->index < 0 || a->index > 2) | ||
876 | return -EINVAL; | ||
877 | |||
878 | msp_dbg1("Setting audio out on msp34xx to input %i\n", a->index); | ||
879 | msp_set_scart(client, state->in_scart, a->index + 1); | ||
880 | |||
881 | break; | ||
882 | } | ||
883 | |||
884 | case VIDIOC_INT_I2S_CLOCK_FREQ: | ||
885 | { | ||
886 | u32 *a = (u32 *)arg; | ||
887 | |||
888 | msp_dbg1("Setting I2S speed to %d\n", *a); | ||
889 | |||
890 | switch (*a) { | ||
891 | case 1024000: | ||
892 | state->i2s_mode = 0; | ||
893 | break; | ||
894 | case 2048000: | ||
895 | state->i2s_mode = 1; | ||
896 | break; | ||
897 | default: | ||
898 | return -EINVAL; | ||
899 | } | ||
900 | break; | ||
901 | } | ||
902 | |||
903 | case VIDIOC_QUERYCTRL: | ||
904 | { | ||
905 | struct v4l2_queryctrl *qc = arg; | ||
906 | int i; | ||
907 | |||
908 | for (i = 0; i < ARRAY_SIZE(msp_qctrl); i++) | ||
909 | if (qc->id && qc->id == msp_qctrl[i].id) { | ||
910 | memcpy(qc, &msp_qctrl[i], sizeof(*qc)); | ||
911 | return 0; | ||
912 | } | ||
913 | return -EINVAL; | ||
914 | } | ||
915 | |||
916 | case VIDIOC_G_CTRL: | ||
917 | return msp_get_ctrl(client, arg); | ||
918 | |||
919 | case VIDIOC_S_CTRL: | ||
920 | return msp_set_ctrl(client, arg); | ||
921 | |||
922 | case VIDIOC_LOG_STATUS: | ||
923 | msp_any_detect_stereo(client); | ||
924 | msp_info("%s rev1 = 0x%04x rev2 = 0x%04x\n", | ||
925 | client->name, state->rev1, state->rev2); | ||
926 | msp_info("Audio: volume %d balance %d bass %d treble %d%s\n", | ||
927 | state->volume, state->balance, | ||
928 | state->bass, state->treble, | ||
929 | state->muted ? " (muted)" : ""); | ||
930 | msp_info("Mode: %s (%s%s)\n", msp_standard_mode_name(state->mode), | ||
931 | (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", | ||
932 | (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); | ||
933 | msp_info("ACB: 0x%04x\n", state->acb); | ||
934 | break; | ||
935 | |||
936 | default: | ||
937 | /* nothing */ | ||
938 | break; | ||
939 | } | ||
940 | return 0; | ||
941 | } | ||
942 | |||
943 | static int msp_suspend(struct device * dev, pm_message_t state) | ||
944 | { | ||
945 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
946 | |||
947 | msp_dbg1("suspend\n"); | ||
948 | msp_reset(client); | ||
949 | return 0; | ||
950 | } | ||
951 | |||
952 | static int msp_resume(struct device * dev) | ||
953 | { | ||
954 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
955 | |||
956 | msp_dbg1("resume\n"); | ||
957 | msp_wake_thread(client); | ||
958 | return 0; | ||
959 | } | ||
960 | |||
961 | /* ----------------------------------------------------------------------- */ | ||
962 | |||
963 | static struct i2c_driver i2c_driver; | ||
964 | |||
965 | static int msp_attach(struct i2c_adapter *adapter, int address, int kind) | ||
966 | { | ||
967 | struct i2c_client *client; | ||
968 | struct msp_state *state; | ||
969 | int (*thread_func)(void *data) = NULL; | ||
970 | |||
971 | client = kmalloc(sizeof(*client), GFP_KERNEL); | ||
972 | if (client == NULL) | ||
973 | return -ENOMEM; | ||
974 | memset(client, 0, sizeof(*client)); | ||
975 | client->addr = address; | ||
976 | client->adapter = adapter; | ||
977 | client->driver = &i2c_driver; | ||
978 | client->flags = I2C_CLIENT_ALLOW_USE; | ||
979 | snprintf(client->name, sizeof(client->name) - 1, "msp3400"); | ||
980 | |||
981 | if (msp_reset(client) == -1) { | ||
982 | msp_dbg1("msp3400 not found\n"); | ||
983 | kfree(client); | ||
984 | return -1; | ||
985 | } | ||
986 | |||
987 | state = kmalloc(sizeof(*state), GFP_KERNEL); | ||
988 | if (state == NULL) { | ||
989 | kfree(client); | ||
990 | return -ENOMEM; | ||
991 | } | ||
992 | i2c_set_clientdata(client, state); | ||
993 | |||
994 | memset(state, 0, sizeof(*state)); | ||
995 | state->norm = VIDEO_MODE_NTSC; | ||
996 | state->volume = 58880; /* 0db gain */ | ||
997 | state->balance = 32768; /* 0db gain */ | ||
998 | state->bass = 32768; | ||
999 | state->treble = 32768; | ||
1000 | state->input = -1; | ||
1001 | state->muted = 0; | ||
1002 | state->i2s_mode = 0; | ||
1003 | init_waitqueue_head(&state->wq); | ||
1004 | |||
1005 | state->rev1 = msp_read_dsp(client, 0x1e); | ||
1006 | if (state->rev1 != -1) | ||
1007 | state->rev2 = msp_read_dsp(client, 0x1f); | ||
1008 | msp_dbg1("rev1=0x%04x, rev2=0x%04x\n", state->rev1, state->rev2); | ||
1009 | if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) { | ||
1010 | msp_dbg1("not an msp3400 (cannot read chip version)\n"); | ||
1011 | kfree(state); | ||
1012 | kfree(client); | ||
1013 | return -1; | ||
1014 | } | ||
1015 | |||
1016 | msp_set_audio(client); | ||
1017 | |||
1018 | snprintf(client->name, sizeof(client->name), "MSP%c4%02d%c-%c%d", | ||
1019 | ((state->rev1 >> 4) & 0x0f) + '3', | ||
1020 | (state->rev2 >> 8) & 0xff, | ||
1021 | (state->rev1 & 0x0f) + '@', | ||
1022 | ((state->rev1 >> 8) & 0xff) + '@', | ||
1023 | state->rev2 & 0x1f); | ||
1024 | |||
1025 | state->opmode = opmode; | ||
1026 | if (state->opmode == OPMODE_AUTO) { | ||
1027 | /* MSP revision G and up have both autodetect and autoselect */ | ||
1028 | if ((state->rev1 & 0x0f) >= 'G'-'@') | ||
1029 | state->opmode = OPMODE_AUTOSELECT; | ||
1030 | /* MSP revision D and up have autodetect */ | ||
1031 | else if ((state->rev1 & 0x0f) >= 'D'-'@') | ||
1032 | state->opmode = OPMODE_AUTODETECT; | ||
1033 | else | ||
1034 | state->opmode = OPMODE_MANUAL; | ||
1035 | } | ||
1036 | |||
1037 | /* hello world :-) */ | ||
1038 | msp_info("%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name); | ||
1039 | msp_info("%s ", client->name); | ||
1040 | if (HAVE_NICAM(state) && HAVE_RADIO(state)) | ||
1041 | printk("supports nicam and radio, "); | ||
1042 | else if (HAVE_NICAM(state)) | ||
1043 | printk("supports nicam, "); | ||
1044 | else if (HAVE_RADIO(state)) | ||
1045 | printk("supports radio, "); | ||
1046 | printk("mode is "); | ||
1047 | |||
1048 | /* version-specific initialization */ | ||
1049 | switch (state->opmode) { | ||
1050 | case OPMODE_MANUAL: | ||
1051 | printk("manual"); | ||
1052 | thread_func = msp3400c_thread; | ||
1053 | break; | ||
1054 | case OPMODE_AUTODETECT: | ||
1055 | printk("autodetect"); | ||
1056 | thread_func = msp3410d_thread; | ||
1057 | break; | ||
1058 | case OPMODE_AUTOSELECT: | ||
1059 | printk("autodetect and autoselect"); | ||
1060 | thread_func = msp34xxg_thread; | ||
1061 | break; | ||
1062 | } | ||
1063 | printk("\n"); | ||
1064 | |||
1065 | /* startup control thread if needed */ | ||
1066 | if (thread_func) { | ||
1067 | state->kthread = kthread_run(thread_func, client, "msp34xx"); | ||
1068 | |||
1069 | if (state->kthread == NULL) | ||
1070 | msp_warn("kernel_thread() failed\n"); | ||
1071 | msp_wake_thread(client); | ||
1072 | } | ||
1073 | |||
1074 | /* done */ | ||
1075 | i2c_attach_client(client); | ||
1076 | |||
1077 | return 0; | ||
1078 | } | ||
1079 | |||
1080 | static int msp_probe(struct i2c_adapter *adapter) | ||
1081 | { | ||
1082 | if (adapter->class & I2C_CLASS_TV_ANALOG) | ||
1083 | return i2c_probe(adapter, &addr_data, msp_attach); | ||
1084 | return 0; | ||
1085 | } | ||
1086 | |||
1087 | static int msp_detach(struct i2c_client *client) | ||
1088 | { | ||
1089 | struct msp_state *state = i2c_get_clientdata(client); | ||
1090 | int err; | ||
1091 | |||
1092 | /* shutdown control thread */ | ||
1093 | if (state->kthread) { | ||
1094 | state->restart = 1; | ||
1095 | kthread_stop(state->kthread); | ||
1096 | } | ||
1097 | msp_reset(client); | ||
1098 | |||
1099 | err = i2c_detach_client(client); | ||
1100 | if (err) { | ||
1101 | return err; | ||
1102 | } | ||
1103 | |||
1104 | kfree(state); | ||
1105 | kfree(client); | ||
1106 | return 0; | ||
1107 | } | ||
1108 | |||
1109 | /* ----------------------------------------------------------------------- */ | ||
1110 | |||
1111 | /* i2c implementation */ | ||
1112 | static struct i2c_driver i2c_driver = { | ||
1113 | .id = I2C_DRIVERID_MSP3400, | ||
1114 | .attach_adapter = msp_probe, | ||
1115 | .detach_client = msp_detach, | ||
1116 | .command = msp_command, | ||
1117 | .driver = { | ||
1118 | .name = "msp3400", | ||
1119 | .suspend = msp_suspend, | ||
1120 | .resume = msp_resume, | ||
1121 | }, | ||
1122 | .owner = THIS_MODULE, | ||
1123 | }; | ||
1124 | |||
1125 | static int __init msp3400_init_module(void) | ||
1126 | { | ||
1127 | return i2c_add_driver(&i2c_driver); | ||
1128 | } | ||
1129 | |||
1130 | static void __exit msp3400_cleanup_module(void) | ||
1131 | { | ||
1132 | i2c_del_driver(&i2c_driver); | ||
1133 | } | ||
1134 | |||
1135 | module_init(msp3400_init_module); | ||
1136 | module_exit(msp3400_cleanup_module); | ||
1137 | |||
1138 | /* | ||
1139 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
1140 | * --------------------------------------------------------------------------- | ||
1141 | * Local variables: | ||
1142 | * c-basic-offset: 8 | ||
1143 | * End: | ||
1144 | */ | ||
diff --git a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c deleted file mode 100644 index 627c3110d3e3..000000000000 --- a/drivers/media/video/msp3400.c +++ /dev/null | |||
@@ -1,2289 +0,0 @@ | |||
1 | /* | ||
2 | * programming the msp34* sound processor family | ||
3 | * | ||
4 | * (c) 1997-2001 Gerd Knorr <kraxel@bytesex.org> | ||
5 | * | ||
6 | * what works and what doesn't: | ||
7 | * | ||
8 | * AM-Mono | ||
9 | * Support for Hauppauge cards added (decoding handled by tuner) added by | ||
10 | * Frederic Crozat <fcrozat@mail.dotcom.fr> | ||
11 | * | ||
12 | * FM-Mono | ||
13 | * should work. The stereo modes are backward compatible to FM-mono, | ||
14 | * therefore FM-Mono should be allways available. | ||
15 | * | ||
16 | * FM-Stereo (B/G, used in germany) | ||
17 | * should work, with autodetect | ||
18 | * | ||
19 | * FM-Stereo (satellite) | ||
20 | * should work, no autodetect (i.e. default is mono, but you can | ||
21 | * switch to stereo -- untested) | ||
22 | * | ||
23 | * NICAM (B/G, L , used in UK, Scandinavia, Spain and France) | ||
24 | * should work, with autodetect. Support for NICAM was added by | ||
25 | * Pekka Pietikainen <pp@netppl.fi> | ||
26 | * | ||
27 | * | ||
28 | * TODO: | ||
29 | * - better SAT support | ||
30 | * | ||
31 | * | ||
32 | * 980623 Thomas Sailer (sailer@ife.ee.ethz.ch) | ||
33 | * using soundcore instead of OSS | ||
34 | * | ||
35 | */ | ||
36 | |||
37 | #include <linux/config.h> | ||
38 | #include <linux/module.h> | ||
39 | #include <linux/moduleparam.h> | ||
40 | #include <linux/kernel.h> | ||
41 | #include <linux/sched.h> | ||
42 | #include <linux/string.h> | ||
43 | #include <linux/timer.h> | ||
44 | #include <linux/delay.h> | ||
45 | #include <linux/errno.h> | ||
46 | #include <linux/slab.h> | ||
47 | #include <linux/i2c.h> | ||
48 | #include <linux/init.h> | ||
49 | #include <linux/smp_lock.h> | ||
50 | #include <linux/kthread.h> | ||
51 | #include <linux/suspend.h> | ||
52 | #include <asm/semaphore.h> | ||
53 | #include <asm/pgtable.h> | ||
54 | |||
55 | #include <linux/videodev.h> | ||
56 | #include <media/audiochip.h> | ||
57 | #include <media/v4l2-common.h> | ||
58 | #include "msp3400.h" | ||
59 | |||
60 | /* ---------------------------------------------------------------------- */ | ||
61 | |||
62 | MODULE_DESCRIPTION("device driver for msp34xx TV sound processor"); | ||
63 | MODULE_AUTHOR("Gerd Knorr"); | ||
64 | MODULE_LICENSE("GPL"); | ||
65 | |||
66 | #define OPMODE_AUTO -1 | ||
67 | #define OPMODE_MANUAL 0 | ||
68 | #define OPMODE_AUTODETECT 1 /* use autodetect (>= msp3410 only) */ | ||
69 | #define OPMODE_AUTOSELECT 2 /* use autodetect & autoselect (>= msp34xxG) */ | ||
70 | |||
71 | /* module parameters */ | ||
72 | static int opmode = OPMODE_AUTO; | ||
73 | static int debug = 0; /* debug output */ | ||
74 | static int once = 0; /* no continous stereo monitoring */ | ||
75 | static int amsound = 0; /* hard-wire AM sound at 6.5 Hz (france), | ||
76 | the autoscan seems work well only with FM... */ | ||
77 | static int standard = 1; /* Override auto detect of audio standard, if needed. */ | ||
78 | static int dolby = 0; | ||
79 | |||
80 | static int stereo_threshold = 0x190; /* a2 threshold for stereo/bilingual | ||
81 | (msp34xxg only) 0x00a0-0x03c0 */ | ||
82 | |||
83 | /* read-only */ | ||
84 | module_param(opmode, int, 0444); | ||
85 | |||
86 | /* read-write */ | ||
87 | module_param(once, int, 0644); | ||
88 | module_param(debug, int, 0644); | ||
89 | module_param(stereo_threshold, int, 0644); | ||
90 | module_param(standard, int, 0644); | ||
91 | module_param(amsound, int, 0644); | ||
92 | module_param(dolby, int, 0644); | ||
93 | |||
94 | MODULE_PARM_DESC(opmode, "Forces a MSP3400 opmode. 0=Manual, 1=Autodetect, 2=Autodetect and autoselect"); | ||
95 | MODULE_PARM_DESC(once, "No continuous stereo monitoring"); | ||
96 | MODULE_PARM_DESC(debug, "Enable debug messages"); | ||
97 | MODULE_PARM_DESC(stereo_threshold, "Sets signal threshold to activate stereo"); | ||
98 | MODULE_PARM_DESC(standard, "Specify audio standard: 32 = NTSC, 64 = radio, Default: Autodetect"); | ||
99 | MODULE_PARM_DESC(amsound, "Hardwire AM sound at 6.5Hz (France), FM can autoscan"); | ||
100 | MODULE_PARM_DESC(dolby, "Activates Dolby processsing"); | ||
101 | |||
102 | /* ---------------------------------------------------------------------- */ | ||
103 | |||
104 | #define msp3400_err(fmt, arg...) do { \ | ||
105 | printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \ | ||
106 | i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) | ||
107 | #define msp3400_warn(fmt, arg...) do { \ | ||
108 | printk(KERN_WARNING "%s %d-%04x: " fmt, client->driver->driver.name, \ | ||
109 | i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) | ||
110 | #define msp3400_info(fmt, arg...) do { \ | ||
111 | printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \ | ||
112 | i2c_adapter_id(client->adapter), client->addr , ## arg); } while (0) | ||
113 | |||
114 | /* level 1 debug. */ | ||
115 | #define msp_dbg1(fmt, arg...) \ | ||
116 | do { \ | ||
117 | if (debug) \ | ||
118 | printk(KERN_INFO "%s debug %d-%04x: " fmt, \ | ||
119 | client->driver->driver.name, \ | ||
120 | i2c_adapter_id(client->adapter), client->addr , ## arg); \ | ||
121 | } while (0) | ||
122 | |||
123 | /* level 2 debug. */ | ||
124 | #define msp_dbg2(fmt, arg...) \ | ||
125 | do { \ | ||
126 | if (debug >= 2) \ | ||
127 | printk(KERN_INFO "%s debug %d-%04x: " fmt, \ | ||
128 | client->driver->driver.name, \ | ||
129 | i2c_adapter_id(client->adapter), client->addr , ## arg); \ | ||
130 | } while (0) | ||
131 | |||
132 | /* level 3 debug. Use with care. */ | ||
133 | #define msp_dbg3(fmt, arg...) \ | ||
134 | do { \ | ||
135 | if (debug >= 16) \ | ||
136 | printk(KERN_INFO "%s debug %d-%04x: " fmt, \ | ||
137 | client->driver->driver.name, \ | ||
138 | i2c_adapter_id(client->adapter), client->addr , ## arg); \ | ||
139 | } while (0) | ||
140 | |||
141 | /* control subaddress */ | ||
142 | #define I2C_MSP_CONTROL 0x00 | ||
143 | /* demodulator unit subaddress */ | ||
144 | #define I2C_MSP_DEM 0x10 | ||
145 | /* DSP unit subaddress */ | ||
146 | #define I2C_MSP_DSP 0x12 | ||
147 | |||
148 | /* Addresses to scan */ | ||
149 | static unsigned short normal_i2c[] = { 0x80 >> 1, 0x88 >> 1, I2C_CLIENT_END }; | ||
150 | >>>>>>> remote | ||
151 | |||
152 | |||
153 | I2C_CLIENT_INSMOD; | ||
154 | |||
155 | #define DFP_COUNT 0x41 | ||
156 | static const int bl_dfp[] = { | ||
157 | 0x00, 0x01, 0x02, 0x03, 0x06, 0x08, 0x09, 0x0a, | ||
158 | 0x0b, 0x0d, 0x0e, 0x10 | ||
159 | }; | ||
160 | |||
161 | #define HAVE_NICAM(state) (((state->rev2 >> 8) & 0xff) != 0) | ||
162 | #define HAVE_RADIO(state) ((state->rev1 & 0x0f) >= 'G'-'@') | ||
163 | |||
164 | struct msp_state { | ||
165 | int rev1, rev2; | ||
166 | |||
167 | int opmode; | ||
168 | int mode; | ||
169 | int norm; | ||
170 | int stereo; | ||
171 | int nicam_on; | ||
172 | int acb; | ||
173 | int in_scart; | ||
174 | int i2s_mode; | ||
175 | int main, second; /* sound carrier */ | ||
176 | int input; | ||
177 | int source; /* see msp34xxg_set_source */ | ||
178 | |||
179 | /* v4l2 */ | ||
180 | int audmode; | ||
181 | int rxsubchans; | ||
182 | |||
183 | int muted; | ||
184 | int volume, balance; | ||
185 | int bass, treble; | ||
186 | |||
187 | /* shadow register set */ | ||
188 | int dfp_regs[DFP_COUNT]; | ||
189 | |||
190 | /* thread */ | ||
191 | struct task_struct *kthread; | ||
192 | wait_queue_head_t wq; | ||
193 | int restart:1; | ||
194 | int watch_stereo:1; | ||
195 | }; | ||
196 | |||
197 | #define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */ | ||
198 | |||
199 | |||
200 | /* ----------------------------------------------------------------------- */ | ||
201 | /* functions for talking to the MSP3400C Sound processor */ | ||
202 | |||
203 | static int msp_reset(struct i2c_client *client) | ||
204 | { | ||
205 | /* reset and read revision code */ | ||
206 | static u8 reset_off[3] = { I2C_MSP_CONTROL, 0x80, 0x00 }; | ||
207 | static u8 reset_on[3] = { I2C_MSP_CONTROL, 0x00, 0x00 }; | ||
208 | static u8 write[3] = { I2C_MSP_DSP + 1, 0x00, 0x1e }; | ||
209 | u8 read[2]; | ||
210 | struct i2c_msg reset[2] = { | ||
211 | { client->addr, I2C_M_IGNORE_NAK, 3, reset_off }, | ||
212 | { client->addr, I2C_M_IGNORE_NAK, 3, reset_on }, | ||
213 | }; | ||
214 | struct i2c_msg test[2] = { | ||
215 | { client->addr, 0, 3, write }, | ||
216 | { client->addr, I2C_M_RD, 2, read }, | ||
217 | }; | ||
218 | |||
219 | msp_dbg3("msp_reset\n"); | ||
220 | if (i2c_transfer(client->adapter, &reset[0], 1) != 1 || | ||
221 | i2c_transfer(client->adapter, &reset[1], 1) != 1 || | ||
222 | i2c_transfer(client->adapter, test, 2) != 2) { | ||
223 | msp_err("chip reset failed\n"); | ||
224 | return -1; | ||
225 | } | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int msp_read(struct i2c_client *client, int dev, int addr) | ||
230 | { | ||
231 | int err, retval; | ||
232 | u8 write[3]; | ||
233 | u8 read[2]; | ||
234 | struct i2c_msg msgs[2] = { | ||
235 | { client->addr, 0, 3, write }, | ||
236 | { client->addr, I2C_M_RD, 2, read } | ||
237 | }; | ||
238 | |||
239 | write[0] = dev + 1; | ||
240 | write[1] = addr >> 8; | ||
241 | write[2] = addr & 0xff; | ||
242 | |||
243 | for (err = 0; err < 3; err++) { | ||
244 | if (i2c_transfer(client->adapter, msgs, 2) == 2) | ||
245 | break; | ||
246 | msp_warn("I/O error #%d (read 0x%02x/0x%02x)\n", err, | ||
247 | dev, addr); | ||
248 | current->state = TASK_INTERRUPTIBLE; | ||
249 | schedule_timeout(msecs_to_jiffies(10)); | ||
250 | } | ||
251 | if (err == 3) { | ||
252 | msp_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n"); | ||
253 | msp_reset(client); | ||
254 | return -1; | ||
255 | } | ||
256 | retval = read[0] << 8 | read[1]; | ||
257 | msp_dbg3("msp_read(0x%x, 0x%x): 0x%x\n", dev, addr, retval); | ||
258 | return retval; | ||
259 | } | ||
260 | |||
261 | static inline int msp_read_dem(struct i2c_client *client, int addr) | ||
262 | { | ||
263 | return msp_read(client, I2C_MSP_DEM, addr); | ||
264 | } | ||
265 | |||
266 | static inline int msp_read_dsp(struct i2c_client *client, int addr) | ||
267 | { | ||
268 | return msp_read(client, I2C_MSP_DSP, addr); | ||
269 | } | ||
270 | |||
271 | static int msp_write(struct i2c_client *client, int dev, int addr, int val) | ||
272 | { | ||
273 | int err; | ||
274 | u8 buffer[5]; | ||
275 | |||
276 | buffer[0] = dev; | ||
277 | buffer[1] = addr >> 8; | ||
278 | buffer[2] = addr & 0xff; | ||
279 | buffer[3] = val >> 8; | ||
280 | buffer[4] = val & 0xff; | ||
281 | |||
282 | msp_dbg3("msp_write(0x%x, 0x%x, 0x%x)\n", dev, addr, val); | ||
283 | for (err = 0; err < 3; err++) { | ||
284 | if (i2c_master_send(client, buffer, 5) == 5) | ||
285 | break; | ||
286 | msp_warn("I/O error #%d (write 0x%02x/0x%02x)\n", err, | ||
287 | dev, addr); | ||
288 | current->state = TASK_INTERRUPTIBLE; | ||
289 | schedule_timeout(msecs_to_jiffies(10)); | ||
290 | } | ||
291 | if (err == 3) { | ||
292 | msp_warn("giving up, resetting chip. Sound will go off, sorry folks :-|\n"); | ||
293 | msp_reset(client); | ||
294 | return -1; | ||
295 | } | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | static inline int msp_write_dem(struct i2c_client *client, int addr, int val) | ||
300 | { | ||
301 | return msp_write(client, I2C_MSP_DEM, addr, val); | ||
302 | } | ||
303 | |||
304 | static inline int msp_write_dsp(struct i2c_client *client, int addr, int val) | ||
305 | { | ||
306 | return msp_write(client, I2C_MSP_DSP, addr, val); | ||
307 | } | ||
308 | |||
309 | /* ----------------------------------------------------------------------- * | ||
310 | * bits 9 8 5 - SCART DSP input Select: | ||
311 | * 0 0 0 - SCART 1 to DSP input (reset position) | ||
312 | * 0 1 0 - MONO to DSP input | ||
313 | * 1 0 0 - SCART 2 to DSP input | ||
314 | * 1 1 1 - Mute DSP input | ||
315 | * | ||
316 | * bits 11 10 6 - SCART 1 Output Select: | ||
317 | * 0 0 0 - undefined (reset position) | ||
318 | * 0 1 0 - SCART 2 Input to SCART 1 Output (for devices with 2 SCARTS) | ||
319 | * 1 0 0 - MONO input to SCART 1 Output | ||
320 | * 1 1 0 - SCART 1 DA to SCART 1 Output | ||
321 | * 0 0 1 - SCART 2 DA to SCART 1 Output | ||
322 | * 0 1 1 - SCART 1 Input to SCART 1 Output | ||
323 | * 1 1 1 - Mute SCART 1 Output | ||
324 | * | ||
325 | * bits 13 12 7 - SCART 2 Output Select (for devices with 2 Output SCART): | ||
326 | * 0 0 0 - SCART 1 DA to SCART 2 Output (reset position) | ||
327 | * 0 1 0 - SCART 1 Input to SCART 2 Output | ||
328 | * 1 0 0 - MONO input to SCART 2 Output | ||
329 | * 0 0 1 - SCART 2 DA to SCART 2 Output | ||
330 | * 0 1 1 - SCART 2 Input to SCART 2 Output | ||
331 | * 1 1 0 - Mute SCART 2 Output | ||
332 | * | ||
333 | * Bits 4 to 0 should be zero. | ||
334 | * ----------------------------------------------------------------------- */ | ||
335 | |||
336 | static int scarts[3][9] = { | ||
337 | /* MASK IN1 IN2 IN1_DA IN2_DA IN3 IN4 MONO MUTE */ | ||
338 | /* SCART DSP Input select */ | ||
339 | { 0x0320, 0x0000, 0x0200, -1, -1, 0x0300, 0x0020, 0x0100, 0x0320 }, | ||
340 | /* SCART1 Output select */ | ||
341 | { 0x0c40, 0x0440, 0x0400, 0x0c00, 0x0040, 0x0000, 0x0840, 0x0800, 0x0c40 }, | ||
342 | /* SCART2 Output select */ | ||
343 | { 0x3080, 0x1000, 0x1080, 0x0000, 0x0080, 0x2080, 0x3080, 0x2000, 0x3000 }, | ||
344 | }; | ||
345 | |||
346 | static char *scart_names[] = { | ||
347 | "mask", "in1", "in2", "in1 da", "in2 da", "in3", "in4", "mono", "mute" | ||
348 | }; | ||
349 | |||
350 | static void msp_set_scart(struct i2c_client *client, int in, int out) | ||
351 | { | ||
352 | struct msp_state *state = i2c_get_clientdata(client); | ||
353 | |||
354 | state->in_scart=in; | ||
355 | |||
356 | if (in >= 1 && in <= 8 && out >= 0 && out <= 2) { | ||
357 | if (-1 == scarts[out][in]) | ||
358 | return; | ||
359 | |||
360 | state->acb &= ~scarts[out][SCART_MASK]; | ||
361 | state->acb |= scarts[out][in]; | ||
362 | } else | ||
363 | state->acb = 0xf60; /* Mute Input and SCART 1 Output */ | ||
364 | |||
365 | msp_dbg1("scart switch: %s => %d (ACB=0x%04x)\n", | ||
366 | scart_names[in], out, state->acb); | ||
367 | msp_write_dsp(client, 0x13, state->acb); | ||
368 | |||
369 | /* Sets I2S speed 0 = 1.024 Mbps, 1 = 2.048 Mbps */ | ||
370 | msp_write_dem(client, 0x40, state->i2s_mode); | ||
371 | } | ||
372 | |||
373 | /* ------------------------------------------------------------------------ */ | ||
374 | |||
375 | /* This macro is allowed for *constants* only, gcc must calculate it | ||
376 | at compile time. Remember -- no floats in kernel mode */ | ||
377 | #define MSP_CARRIER(freq) ((int)((float)(freq / 18.432) * (1 << 24))) | ||
378 | |||
379 | #define MSP_MODE_AM_DETECT 0 | ||
380 | #define MSP_MODE_FM_RADIO 2 | ||
381 | #define MSP_MODE_FM_TERRA 3 | ||
382 | #define MSP_MODE_FM_SAT 4 | ||
383 | #define MSP_MODE_FM_NICAM1 5 | ||
384 | #define MSP_MODE_FM_NICAM2 6 | ||
385 | #define MSP_MODE_AM_NICAM 7 | ||
386 | #define MSP_MODE_BTSC 8 | ||
387 | #define MSP_MODE_EXTERN 9 | ||
388 | |||
389 | static struct msp3400c_init_data_dem { | ||
390 | int fir1[6]; | ||
391 | int fir2[6]; | ||
392 | int cdo1; | ||
393 | int cdo2; | ||
394 | int ad_cv; | ||
395 | int mode_reg; | ||
396 | int dfp_src; | ||
397 | int dfp_matrix; | ||
398 | } msp3400c_init_data[] = { | ||
399 | { /* AM (for carrier detect / msp3400) */ | ||
400 | {75, 19, 36, 35, 39, 40}, | ||
401 | {75, 19, 36, 35, 39, 40}, | ||
402 | MSP_CARRIER(5.5), MSP_CARRIER(5.5), | ||
403 | 0x00d0, 0x0500, 0x0020, 0x3000 | ||
404 | },{ /* AM (for carrier detect / msp3410) */ | ||
405 | {-1, -1, -8, 2, 59, 126}, | ||
406 | {-1, -1, -8, 2, 59, 126}, | ||
407 | MSP_CARRIER(5.5), MSP_CARRIER(5.5), | ||
408 | 0x00d0, 0x0100, 0x0020, 0x3000 | ||
409 | },{ /* FM Radio */ | ||
410 | {-8, -8, 4, 6, 78, 107}, | ||
411 | {-8, -8, 4, 6, 78, 107}, | ||
412 | MSP_CARRIER(10.7), MSP_CARRIER(10.7), | ||
413 | 0x00d0, 0x0480, 0x0020, 0x3000 | ||
414 | },{ /* Terrestial FM-mono + FM-stereo */ | ||
415 | {3, 18, 27, 48, 66, 72}, | ||
416 | {3, 18, 27, 48, 66, 72}, | ||
417 | MSP_CARRIER(5.5), MSP_CARRIER(5.5), | ||
418 | 0x00d0, 0x0480, 0x0030, 0x3000 | ||
419 | },{ /* Sat FM-mono */ | ||
420 | { 1, 9, 14, 24, 33, 37}, | ||
421 | { 3, 18, 27, 48, 66, 72}, | ||
422 | MSP_CARRIER(6.5), MSP_CARRIER(6.5), | ||
423 | 0x00c6, 0x0480, 0x0000, 0x3000 | ||
424 | },{ /* NICAM/FM -- B/G (5.5/5.85), D/K (6.5/5.85) */ | ||
425 | {-2, -8, -10, 10, 50, 86}, | ||
426 | {3, 18, 27, 48, 66, 72}, | ||
427 | MSP_CARRIER(5.5), MSP_CARRIER(5.5), | ||
428 | 0x00d0, 0x0040, 0x0120, 0x3000 | ||
429 | },{ /* NICAM/FM -- I (6.0/6.552) */ | ||
430 | {2, 4, -6, -4, 40, 94}, | ||
431 | {3, 18, 27, 48, 66, 72}, | ||
432 | MSP_CARRIER(6.0), MSP_CARRIER(6.0), | ||
433 | 0x00d0, 0x0040, 0x0120, 0x3000 | ||
434 | },{ /* NICAM/AM -- L (6.5/5.85) */ | ||
435 | {-2, -8, -10, 10, 50, 86}, | ||
436 | {-4, -12, -9, 23, 79, 126}, | ||
437 | MSP_CARRIER(6.5), MSP_CARRIER(6.5), | ||
438 | 0x00c6, 0x0140, 0x0120, 0x7c03 | ||
439 | }, | ||
440 | }; | ||
441 | |||
442 | struct msp3400c_carrier_detect { | ||
443 | int cdo; | ||
444 | char *name; | ||
445 | }; | ||
446 | |||
447 | static struct msp3400c_carrier_detect msp3400c_carrier_detect_main[] = { | ||
448 | /* main carrier */ | ||
449 | { MSP_CARRIER(4.5), "4.5 NTSC" }, | ||
450 | { MSP_CARRIER(5.5), "5.5 PAL B/G" }, | ||
451 | { MSP_CARRIER(6.0), "6.0 PAL I" }, | ||
452 | { MSP_CARRIER(6.5), "6.5 PAL D/K + SAT + SECAM" } | ||
453 | }; | ||
454 | |||
455 | static struct msp3400c_carrier_detect msp3400c_carrier_detect_55[] = { | ||
456 | /* PAL B/G */ | ||
457 | { MSP_CARRIER(5.7421875), "5.742 PAL B/G FM-stereo" }, | ||
458 | { MSP_CARRIER(5.85), "5.85 PAL B/G NICAM" } | ||
459 | }; | ||
460 | |||
461 | static struct msp3400c_carrier_detect msp3400c_carrier_detect_65[] = { | ||
462 | /* PAL SAT / SECAM */ | ||
463 | { MSP_CARRIER(5.85), "5.85 PAL D/K + SECAM NICAM" }, | ||
464 | { MSP_CARRIER(6.2578125), "6.25 PAL D/K1 FM-stereo" }, | ||
465 | { MSP_CARRIER(6.7421875), "6.74 PAL D/K2 FM-stereo" }, | ||
466 | { MSP_CARRIER(7.02), "7.02 PAL SAT FM-stereo s/b" }, | ||
467 | { MSP_CARRIER(7.20), "7.20 PAL SAT FM-stereo s" }, | ||
468 | { MSP_CARRIER(7.38), "7.38 PAL SAT FM-stereo b" }, | ||
469 | }; | ||
470 | |||
471 | /* ------------------------------------------------------------------------ */ | ||
472 | |||
473 | static void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2) | ||
474 | { | ||
475 | msp_write_dem(client, 0x0093, cdo1 & 0xfff); | ||
476 | msp_write_dem(client, 0x009b, cdo1 >> 12); | ||
477 | msp_write_dem(client, 0x00a3, cdo2 & 0xfff); | ||
478 | msp_write_dem(client, 0x00ab, cdo2 >> 12); | ||
479 | msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/ | ||
480 | } | ||
481 | |||
482 | static void msp_set_mute(struct i2c_client *client) | ||
483 | { | ||
484 | msp_dbg1("mute audio\n"); | ||
485 | msp_write_dsp(client, 0x0000, 0); /* loudspeaker */ | ||
486 | msp_write_dsp(client, 0x0006, 0); /* headphones */ | ||
487 | } | ||
488 | |||
489 | static void msp_set_audio(struct i2c_client *client) | ||
490 | { | ||
491 | struct msp_state *state = i2c_get_clientdata(client); | ||
492 | int val = 0, bal = 0, bass, treble; | ||
493 | |||
494 | if (!state->muted) | ||
495 | val = (state->volume * 0x7f / 65535) << 8; | ||
496 | if (val) | ||
497 | bal = (state->balance / 256) - 128; | ||
498 | bass = ((state->bass - 32768) * 0x60 / 65535) << 8; | ||
499 | treble = ((state->treble - 32768) * 0x60 / 65535) << 8; | ||
500 | |||
501 | msp_dbg1("mute=%s volume=%d balance=%d bass=%d treble=%d\n", | ||
502 | state->muted ? "on" : "off", state->volume, state->balance, | ||
503 | state->bass, state->treble); | ||
504 | |||
505 | msp_write_dsp(client, 0x0000, val); /* loudspeaker */ | ||
506 | msp_write_dsp(client, 0x0006, val); /* headphones */ | ||
507 | msp_write_dsp(client, 0x0007, state->muted ? 0x1 : (val | 0x1)); | ||
508 | msp_write_dsp(client, 0x0001, bal << 8); | ||
509 | msp_write_dsp(client, 0x0002, bass); /* loudspeaker */ | ||
510 | msp_write_dsp(client, 0x0003, treble); /* loudspeaker */ | ||
511 | } | ||
512 | |||
513 | static void msp3400c_setmode(struct i2c_client *client, int type) | ||
514 | { | ||
515 | struct msp_state *state = i2c_get_clientdata(client); | ||
516 | int i; | ||
517 | |||
518 | msp_dbg1("setmode: %d\n",type); | ||
519 | state->mode = type; | ||
520 | state->audmode = V4L2_TUNER_MODE_MONO; | ||
521 | state->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
522 | |||
523 | msp_write_dem(client, 0x00bb, /* ad_cv */ | ||
524 | msp3400c_init_data[type].ad_cv); | ||
525 | |||
526 | for (i = 5; i >= 0; i--) /* fir 1 */ | ||
527 | msp_write_dem(client, 0x0001, | ||
528 | msp3400c_init_data[type].fir1[i]); | ||
529 | |||
530 | msp_write_dem(client, 0x0005, 0x0004); /* fir 2 */ | ||
531 | msp_write_dem(client, 0x0005, 0x0040); | ||
532 | msp_write_dem(client, 0x0005, 0x0000); | ||
533 | for (i = 5; i >= 0; i--) | ||
534 | msp_write_dem(client, 0x0005, | ||
535 | msp3400c_init_data[type].fir2[i]); | ||
536 | |||
537 | msp_write_dem(client, 0x0083, /* MODE_REG */ | ||
538 | msp3400c_init_data[type].mode_reg); | ||
539 | |||
540 | msp3400c_setcarrier(client, msp3400c_init_data[type].cdo1, | ||
541 | msp3400c_init_data[type].cdo2); | ||
542 | |||
543 | msp_write_dem(client, 0x0056, 0); /*LOAD_REG_1/2*/ | ||
544 | |||
545 | if (dolby) { | ||
546 | msp_write_dsp(client, 0x0008, | ||
547 | 0x0520); /* I2S1 */ | ||
548 | msp_write_dsp(client, 0x0009, | ||
549 | 0x0620); /* I2S2 */ | ||
550 | msp_write_dsp(client, 0x000b, | ||
551 | msp3400c_init_data[type].dfp_src); | ||
552 | } else { | ||
553 | msp_write_dsp(client, 0x0008, | ||
554 | msp3400c_init_data[type].dfp_src); | ||
555 | msp_write_dsp(client, 0x0009, | ||
556 | msp3400c_init_data[type].dfp_src); | ||
557 | msp_write_dsp(client, 0x000b, | ||
558 | msp3400c_init_data[type].dfp_src); | ||
559 | } | ||
560 | msp_write_dsp(client, 0x000a, | ||
561 | msp3400c_init_data[type].dfp_src); | ||
562 | msp_write_dsp(client, 0x000e, | ||
563 | msp3400c_init_data[type].dfp_matrix); | ||
564 | |||
565 | if (HAVE_NICAM(state)) { | ||
566 | /* nicam prescale */ | ||
567 | msp_write_dsp(client, 0x0010, 0x5a00); /* was: 0x3000 */ | ||
568 | } | ||
569 | } | ||
570 | |||
571 | /* given a bitmask of VIDEO_SOUND_XXX returns the "best" in the bitmask */ | ||
572 | static int msp3400c_best_video_sound(int rxsubchans) | ||
573 | { | ||
574 | if (rxsubchans & V4L2_TUNER_SUB_STEREO) | ||
575 | return V4L2_TUNER_MODE_STEREO; | ||
576 | if (rxsubchans & V4L2_TUNER_SUB_LANG1) | ||
577 | return V4L2_TUNER_MODE_LANG1; | ||
578 | if (rxsubchans & V4L2_TUNER_SUB_LANG2) | ||
579 | return V4L2_TUNER_MODE_LANG2; | ||
580 | return V4L2_TUNER_MODE_MONO; | ||
581 | } | ||
582 | |||
583 | /* turn on/off nicam + stereo */ | ||
584 | static void msp3400c_setstereo(struct i2c_client *client, int mode) | ||
585 | { | ||
586 | static char *strmode[] = { "0", "mono", "stereo", "3", | ||
587 | "lang1", "5", "6", "7", "lang2" | ||
588 | }; | ||
589 | struct msp_state *state = i2c_get_clientdata(client); | ||
590 | int nicam = 0; /* channel source: FM/AM or nicam */ | ||
591 | int src = 0; | ||
592 | |||
593 | if (state->opmode == OPMODE_AUTOSELECT) { | ||
594 | /* this method would break everything, let's make sure | ||
595 | * it's never called | ||
596 | */ | ||
597 | msp_dbg1("setstereo called with mode=%d instead of set_source (ignored)\n", | ||
598 | mode); | ||
599 | return; | ||
600 | } | ||
601 | |||
602 | /* switch demodulator */ | ||
603 | switch (state->mode) { | ||
604 | case MSP_MODE_FM_TERRA: | ||
605 | msp_dbg1("FM setstereo: %s\n", strmode[mode]); | ||
606 | msp3400c_setcarrier(client,state->second,state->main); | ||
607 | switch (mode) { | ||
608 | case V4L2_TUNER_MODE_STEREO: | ||
609 | msp_write_dsp(client, 0x000e, 0x3001); | ||
610 | break; | ||
611 | case V4L2_TUNER_MODE_MONO: | ||
612 | case V4L2_TUNER_MODE_LANG1: | ||
613 | case V4L2_TUNER_MODE_LANG2: | ||
614 | msp_write_dsp(client, 0x000e, 0x3000); | ||
615 | break; | ||
616 | } | ||
617 | break; | ||
618 | case MSP_MODE_FM_SAT: | ||
619 | msp_dbg1("SAT setstereo: %s\n", strmode[mode]); | ||
620 | switch (mode) { | ||
621 | case V4L2_TUNER_MODE_MONO: | ||
622 | msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5)); | ||
623 | break; | ||
624 | case V4L2_TUNER_MODE_STEREO: | ||
625 | msp3400c_setcarrier(client, MSP_CARRIER(7.2), MSP_CARRIER(7.02)); | ||
626 | break; | ||
627 | case V4L2_TUNER_MODE_LANG1: | ||
628 | msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); | ||
629 | break; | ||
630 | case V4L2_TUNER_MODE_LANG2: | ||
631 | msp3400c_setcarrier(client, MSP_CARRIER(7.38), MSP_CARRIER(7.02)); | ||
632 | break; | ||
633 | } | ||
634 | break; | ||
635 | case MSP_MODE_FM_NICAM1: | ||
636 | case MSP_MODE_FM_NICAM2: | ||
637 | case MSP_MODE_AM_NICAM: | ||
638 | msp_dbg1("NICAM setstereo: %s\n",strmode[mode]); | ||
639 | msp3400c_setcarrier(client,state->second,state->main); | ||
640 | if (state->nicam_on) | ||
641 | nicam=0x0100; | ||
642 | break; | ||
643 | case MSP_MODE_BTSC: | ||
644 | msp_dbg1("BTSC setstereo: %s\n",strmode[mode]); | ||
645 | nicam=0x0300; | ||
646 | break; | ||
647 | case MSP_MODE_EXTERN: | ||
648 | msp_dbg1("extern setstereo: %s\n",strmode[mode]); | ||
649 | nicam = 0x0200; | ||
650 | break; | ||
651 | case MSP_MODE_FM_RADIO: | ||
652 | msp_dbg1("FM-Radio setstereo: %s\n",strmode[mode]); | ||
653 | break; | ||
654 | default: | ||
655 | msp_dbg1("mono setstereo\n"); | ||
656 | return; | ||
657 | } | ||
658 | |||
659 | /* switch audio */ | ||
660 | switch (msp3400c_best_video_sound(mode)) { | ||
661 | case V4L2_TUNER_MODE_STEREO: | ||
662 | src = 0x0020 | nicam; | ||
663 | break; | ||
664 | case V4L2_TUNER_MODE_MONO: | ||
665 | if (state->mode == MSP_MODE_AM_NICAM) { | ||
666 | msp_dbg1("switching to AM mono\n"); | ||
667 | /* AM mono decoding is handled by tuner, not MSP chip */ | ||
668 | /* SCART switching control register */ | ||
669 | msp_set_scart(client,SCART_MONO,0); | ||
670 | src = 0x0200; | ||
671 | break; | ||
672 | } | ||
673 | case V4L2_TUNER_MODE_LANG1: | ||
674 | src = 0x0000 | nicam; | ||
675 | break; | ||
676 | case V4L2_TUNER_MODE_LANG2: | ||
677 | src = 0x0010 | nicam; | ||
678 | break; | ||
679 | } | ||
680 | msp_dbg1("setstereo final source/matrix = 0x%x\n", src); | ||
681 | |||
682 | if (dolby) { | ||
683 | msp_write_dsp(client, 0x0008,0x0520); | ||
684 | msp_write_dsp(client, 0x0009,0x0620); | ||
685 | msp_write_dsp(client, 0x000a,src); | ||
686 | msp_write_dsp(client, 0x000b,src); | ||
687 | } else { | ||
688 | msp_write_dsp(client, 0x0008,src); | ||
689 | msp_write_dsp(client, 0x0009,src); | ||
690 | msp_write_dsp(client, 0x000a,src); | ||
691 | msp_write_dsp(client, 0x000b,src); | ||
692 | } | ||
693 | } | ||
694 | |||
695 | static void msp3400c_print_mode(struct i2c_client *client) | ||
696 | { | ||
697 | struct msp_state *state = i2c_get_clientdata(client); | ||
698 | |||
699 | if (state->main == state->second) { | ||
700 | msp_dbg1("mono sound carrier: %d.%03d MHz\n", | ||
701 | state->main/910000,(state->main/910)%1000); | ||
702 | } else { | ||
703 | msp_dbg1("main sound carrier: %d.%03d MHz\n", | ||
704 | state->main/910000,(state->main/910)%1000); | ||
705 | } | ||
706 | if (state->mode == MSP_MODE_FM_NICAM1 || state->mode == MSP_MODE_FM_NICAM2) | ||
707 | msp_dbg1("NICAM/FM carrier : %d.%03d MHz\n", | ||
708 | state->second/910000,(state->second/910)%1000); | ||
709 | if (state->mode == MSP_MODE_AM_NICAM) | ||
710 | msp_dbg1("NICAM/AM carrier : %d.%03d MHz\n", | ||
711 | state->second/910000,(state->second/910)%1000); | ||
712 | if (state->mode == MSP_MODE_FM_TERRA && | ||
713 | state->main != state->second) { | ||
714 | msp_dbg1("FM-stereo carrier : %d.%03d MHz\n", | ||
715 | state->second/910000,(state->second/910)%1000); | ||
716 | } | ||
717 | } | ||
718 | |||
719 | static void msp3400c_restore_dfp(struct i2c_client *client) | ||
720 | { | ||
721 | struct msp_state *state = i2c_get_clientdata(client); | ||
722 | int i; | ||
723 | |||
724 | for (i = 0; i < DFP_COUNT; i++) { | ||
725 | if (-1 == state->dfp_regs[i]) | ||
726 | continue; | ||
727 | msp_write_dsp(client, i, state->dfp_regs[i]); | ||
728 | } | ||
729 | } | ||
730 | |||
731 | /* if the dfp_regs is set, set what's in there. Otherwise, set the default value */ | ||
732 | static int msp34xxg_write_dfp_with_default(struct i2c_client *client, | ||
733 | int addr, int default_value) | ||
734 | { | ||
735 | struct msp_state *state = i2c_get_clientdata(client); | ||
736 | int value = default_value; | ||
737 | if (addr < DFP_COUNT && -1 != state->dfp_regs[addr]) | ||
738 | value = state->dfp_regs[addr]; | ||
739 | return msp_write_dsp(client, addr, value); | ||
740 | } | ||
741 | |||
742 | /* ----------------------------------------------------------------------- */ | ||
743 | |||
744 | static int autodetect_stereo(struct i2c_client *client) | ||
745 | { | ||
746 | struct msp_state *state = i2c_get_clientdata(client); | ||
747 | int val; | ||
748 | int rxsubchans = state->rxsubchans; | ||
749 | int newnicam = state->nicam_on; | ||
750 | int update = 0; | ||
751 | |||
752 | switch (state->mode) { | ||
753 | case MSP_MODE_FM_TERRA: | ||
754 | val = msp_read_dsp(client, 0x18); | ||
755 | if (val > 32767) | ||
756 | val -= 65536; | ||
757 | msp_dbg2("stereo detect register: %d\n",val); | ||
758 | if (val > 4096) { | ||
759 | rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO; | ||
760 | } else if (val < -4096) { | ||
761 | rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; | ||
762 | } else { | ||
763 | rxsubchans = V4L2_TUNER_SUB_MONO; | ||
764 | } | ||
765 | newnicam = 0; | ||
766 | break; | ||
767 | case MSP_MODE_FM_NICAM1: | ||
768 | case MSP_MODE_FM_NICAM2: | ||
769 | case MSP_MODE_AM_NICAM: | ||
770 | val = msp_read_dem(client, 0x23); | ||
771 | msp_dbg2("nicam sync=%d, mode=%d\n", | ||
772 | val & 1, (val & 0x1e) >> 1); | ||
773 | |||
774 | if (val & 1) { | ||
775 | /* nicam synced */ | ||
776 | switch ((val & 0x1e) >> 1) { | ||
777 | case 0: | ||
778 | case 8: | ||
779 | rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
780 | break; | ||
781 | case 1: | ||
782 | case 9: | ||
783 | rxsubchans = V4L2_TUNER_SUB_MONO | ||
784 | | V4L2_TUNER_SUB_LANG1; | ||
785 | break; | ||
786 | case 2: | ||
787 | case 10: | ||
788 | rxsubchans = V4L2_TUNER_SUB_MONO | ||
789 | | V4L2_TUNER_SUB_LANG1 | ||
790 | | V4L2_TUNER_SUB_LANG2; | ||
791 | break; | ||
792 | default: | ||
793 | rxsubchans = V4L2_TUNER_SUB_MONO; | ||
794 | break; | ||
795 | } | ||
796 | newnicam=1; | ||
797 | } else { | ||
798 | newnicam = 0; | ||
799 | rxsubchans = V4L2_TUNER_SUB_MONO; | ||
800 | } | ||
801 | break; | ||
802 | case MSP_MODE_BTSC: | ||
803 | val = msp_read_dem(client, 0x200); | ||
804 | msp_dbg2("status=0x%x (pri=%s, sec=%s, %s%s%s)\n", | ||
805 | val, | ||
806 | (val & 0x0002) ? "no" : "yes", | ||
807 | (val & 0x0004) ? "no" : "yes", | ||
808 | (val & 0x0040) ? "stereo" : "mono", | ||
809 | (val & 0x0080) ? ", nicam 2nd mono" : "", | ||
810 | (val & 0x0100) ? ", bilingual/SAP" : ""); | ||
811 | rxsubchans = V4L2_TUNER_SUB_MONO; | ||
812 | if (val & 0x0040) rxsubchans |= V4L2_TUNER_SUB_STEREO; | ||
813 | if (val & 0x0100) rxsubchans |= V4L2_TUNER_SUB_LANG1; | ||
814 | break; | ||
815 | } | ||
816 | if (rxsubchans != state->rxsubchans) { | ||
817 | update = 1; | ||
818 | msp_dbg1("watch: rxsubchans %d => %d\n", | ||
819 | state->rxsubchans,rxsubchans); | ||
820 | state->rxsubchans = rxsubchans; | ||
821 | } | ||
822 | if (newnicam != state->nicam_on) { | ||
823 | update = 1; | ||
824 | msp_dbg1("watch: nicam %d => %d\n", | ||
825 | state->nicam_on,newnicam); | ||
826 | state->nicam_on = newnicam; | ||
827 | } | ||
828 | return update; | ||
829 | } | ||
830 | |||
831 | /* | ||
832 | * A kernel thread for msp3400 control -- we don't want to block the | ||
833 | * in the ioctl while doing the sound carrier & stereo detect | ||
834 | */ | ||
835 | |||
836 | static int msp_sleep(struct msp_state *state, int timeout) | ||
837 | { | ||
838 | DECLARE_WAITQUEUE(wait, current); | ||
839 | |||
840 | add_wait_queue(&state->wq, &wait); | ||
841 | if (!kthread_should_stop()) { | ||
842 | if (timeout < 0) { | ||
843 | set_current_state(TASK_INTERRUPTIBLE); | ||
844 | schedule(); | ||
845 | } else { | ||
846 | schedule_timeout_interruptible | ||
847 | (msecs_to_jiffies(timeout)); | ||
848 | } | ||
849 | } | ||
850 | |||
851 | remove_wait_queue(&state->wq, &wait); | ||
852 | try_to_freeze(); | ||
853 | return state->restart; | ||
854 | } | ||
855 | |||
856 | /* stereo/multilang monitoring */ | ||
857 | static void watch_stereo(struct i2c_client *client) | ||
858 | { | ||
859 | struct msp_state *state = i2c_get_clientdata(client); | ||
860 | |||
861 | if (autodetect_stereo(client)) { | ||
862 | if (state->stereo & V4L2_TUNER_MODE_STEREO) | ||
863 | msp3400c_setstereo(client, V4L2_TUNER_MODE_STEREO); | ||
864 | else if (state->stereo & VIDEO_SOUND_LANG1) | ||
865 | msp3400c_setstereo(client, V4L2_TUNER_MODE_LANG1); | ||
866 | else | ||
867 | msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); | ||
868 | } | ||
869 | |||
870 | if (once) | ||
871 | state->watch_stereo = 0; | ||
872 | } | ||
873 | |||
874 | |||
875 | static int msp3400c_thread(void *data) | ||
876 | { | ||
877 | struct i2c_client *client = data; | ||
878 | struct msp_state *state = i2c_get_clientdata(client); | ||
879 | struct msp3400c_carrier_detect *cd; | ||
880 | int count, max1,max2,val1,val2, val,this; | ||
881 | |||
882 | |||
883 | msp_info("msp3400 daemon started\n"); | ||
884 | for (;;) { | ||
885 | msp_dbg2("msp3400 thread: sleep\n"); | ||
886 | msp_sleep(state, -1); | ||
887 | msp_dbg2("msp3400 thread: wakeup\n"); | ||
888 | |||
889 | restart: | ||
890 | msp_dbg1("thread: restart scan\n"); | ||
891 | state->restart = 0; | ||
892 | if (kthread_should_stop()) | ||
893 | break; | ||
894 | |||
895 | if (VIDEO_MODE_RADIO == state->norm || | ||
896 | MSP_MODE_EXTERN == state->mode) { | ||
897 | /* no carrier scan, just unmute */ | ||
898 | msp_info("thread: no carrier scan\n"); | ||
899 | msp_set_audio(client); | ||
900 | continue; | ||
901 | } | ||
902 | |||
903 | /* mute */ | ||
904 | msp_set_mute(client); | ||
905 | msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ ); | ||
906 | val1 = val2 = 0; | ||
907 | max1 = max2 = -1; | ||
908 | state->watch_stereo = 0; | ||
909 | |||
910 | /* some time for the tuner to sync */ | ||
911 | if (msp_sleep(state,200)) | ||
912 | goto restart; | ||
913 | |||
914 | /* carrier detect pass #1 -- main carrier */ | ||
915 | cd = msp3400c_carrier_detect_main; | ||
916 | count = ARRAY_SIZE(msp3400c_carrier_detect_main); | ||
917 | |||
918 | if (amsound && (state->norm == VIDEO_MODE_SECAM)) { | ||
919 | /* autodetect doesn't work well with AM ... */ | ||
920 | max1 = 3; | ||
921 | count = 0; | ||
922 | msp_dbg1("AM sound override\n"); | ||
923 | } | ||
924 | |||
925 | for (this = 0; this < count; this++) { | ||
926 | msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); | ||
927 | if (msp_sleep(state,100)) | ||
928 | goto restart; | ||
929 | val = msp_read_dsp(client, 0x1b); | ||
930 | if (val > 32767) | ||
931 | val -= 65536; | ||
932 | if (val1 < val) | ||
933 | val1 = val, max1 = this; | ||
934 | msp_dbg1("carrier1 val: %5d / %s\n", val,cd[this].name); | ||
935 | } | ||
936 | |||
937 | /* carrier detect pass #2 -- second (stereo) carrier */ | ||
938 | switch (max1) { | ||
939 | case 1: /* 5.5 */ | ||
940 | cd = msp3400c_carrier_detect_55; | ||
941 | count = ARRAY_SIZE(msp3400c_carrier_detect_55); | ||
942 | break; | ||
943 | case 3: /* 6.5 */ | ||
944 | cd = msp3400c_carrier_detect_65; | ||
945 | count = ARRAY_SIZE(msp3400c_carrier_detect_65); | ||
946 | break; | ||
947 | case 0: /* 4.5 */ | ||
948 | case 2: /* 6.0 */ | ||
949 | default: | ||
950 | cd = NULL; | ||
951 | count = 0; | ||
952 | break; | ||
953 | } | ||
954 | |||
955 | if (amsound && (state->norm == VIDEO_MODE_SECAM)) { | ||
956 | /* autodetect doesn't work well with AM ... */ | ||
957 | cd = NULL; | ||
958 | count = 0; | ||
959 | max2 = 0; | ||
960 | } | ||
961 | for (this = 0; this < count; this++) { | ||
962 | msp3400c_setcarrier(client, cd[this].cdo,cd[this].cdo); | ||
963 | if (msp_sleep(state,100)) | ||
964 | goto restart; | ||
965 | val = msp_read_dsp(client, 0x1b); | ||
966 | if (val > 32767) | ||
967 | val -= 65536; | ||
968 | if (val2 < val) | ||
969 | val2 = val, max2 = this; | ||
970 | msp_dbg1("carrier2 val: %5d / %s\n", val,cd[this].name); | ||
971 | } | ||
972 | |||
973 | /* program the msp3400 according to the results */ | ||
974 | state->main = msp3400c_carrier_detect_main[max1].cdo; | ||
975 | switch (max1) { | ||
976 | case 1: /* 5.5 */ | ||
977 | if (max2 == 0) { | ||
978 | /* B/G FM-stereo */ | ||
979 | state->second = msp3400c_carrier_detect_55[max2].cdo; | ||
980 | msp3400c_setmode(client, MSP_MODE_FM_TERRA); | ||
981 | state->nicam_on = 0; | ||
982 | msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); | ||
983 | state->watch_stereo = 1; | ||
984 | } else if (max2 == 1 && HAVE_NICAM(state)) { | ||
985 | /* B/G NICAM */ | ||
986 | state->second = msp3400c_carrier_detect_55[max2].cdo; | ||
987 | msp3400c_setmode(client, MSP_MODE_FM_NICAM1); | ||
988 | state->nicam_on = 1; | ||
989 | msp3400c_setcarrier(client, state->second, state->main); | ||
990 | state->watch_stereo = 1; | ||
991 | } else { | ||
992 | goto no_second; | ||
993 | } | ||
994 | break; | ||
995 | case 2: /* 6.0 */ | ||
996 | /* PAL I NICAM */ | ||
997 | state->second = MSP_CARRIER(6.552); | ||
998 | msp3400c_setmode(client, MSP_MODE_FM_NICAM2); | ||
999 | state->nicam_on = 1; | ||
1000 | msp3400c_setcarrier(client, state->second, state->main); | ||
1001 | state->watch_stereo = 1; | ||
1002 | break; | ||
1003 | case 3: /* 6.5 */ | ||
1004 | if (max2 == 1 || max2 == 2) { | ||
1005 | /* D/K FM-stereo */ | ||
1006 | state->second = msp3400c_carrier_detect_65[max2].cdo; | ||
1007 | msp3400c_setmode(client, MSP_MODE_FM_TERRA); | ||
1008 | state->nicam_on = 0; | ||
1009 | msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); | ||
1010 | state->watch_stereo = 1; | ||
1011 | } else if (max2 == 0 && | ||
1012 | state->norm == VIDEO_MODE_SECAM) { | ||
1013 | /* L NICAM or AM-mono */ | ||
1014 | state->second = msp3400c_carrier_detect_65[max2].cdo; | ||
1015 | msp3400c_setmode(client, MSP_MODE_AM_NICAM); | ||
1016 | state->nicam_on = 0; | ||
1017 | msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); | ||
1018 | msp3400c_setcarrier(client, state->second, state->main); | ||
1019 | /* volume prescale for SCART (AM mono input) */ | ||
1020 | msp_write_dsp(client, 0x000d, 0x1900); | ||
1021 | state->watch_stereo = 1; | ||
1022 | } else if (max2 == 0 && HAVE_NICAM(state)) { | ||
1023 | /* D/K NICAM */ | ||
1024 | state->second = msp3400c_carrier_detect_65[max2].cdo; | ||
1025 | msp3400c_setmode(client, MSP_MODE_FM_NICAM1); | ||
1026 | state->nicam_on = 1; | ||
1027 | msp3400c_setcarrier(client, state->second, state->main); | ||
1028 | state->watch_stereo = 1; | ||
1029 | } else { | ||
1030 | goto no_second; | ||
1031 | } | ||
1032 | break; | ||
1033 | case 0: /* 4.5 */ | ||
1034 | default: | ||
1035 | no_second: | ||
1036 | state->second = msp3400c_carrier_detect_main[max1].cdo; | ||
1037 | msp3400c_setmode(client, MSP_MODE_FM_TERRA); | ||
1038 | state->nicam_on = 0; | ||
1039 | msp3400c_setcarrier(client, state->second, state->main); | ||
1040 | state->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
1041 | msp3400c_setstereo(client, V4L2_TUNER_MODE_MONO); | ||
1042 | break; | ||
1043 | } | ||
1044 | |||
1045 | /* unmute */ | ||
1046 | msp_set_audio(client); | ||
1047 | msp3400c_restore_dfp(client); | ||
1048 | |||
1049 | if (debug) | ||
1050 | msp3400c_print_mode(client); | ||
1051 | |||
1052 | /* monitor tv audio mode */ | ||
1053 | while (state->watch_stereo) { | ||
1054 | if (msp_sleep(state,5000)) | ||
1055 | goto restart; | ||
1056 | watch_stereo(client); | ||
1057 | } | ||
1058 | } | ||
1059 | msp_dbg1("thread: exit\n"); | ||
1060 | return 0; | ||
1061 | } | ||
1062 | |||
1063 | /* ----------------------------------------------------------------------- */ | ||
1064 | /* this one uses the automatic sound standard detection of newer */ | ||
1065 | /* msp34xx chip versions */ | ||
1066 | |||
1067 | static struct MODES { | ||
1068 | int retval; | ||
1069 | int main, second; | ||
1070 | char *name; | ||
1071 | } modelist[] = { | ||
1072 | { 0x0000, 0, 0, "could not detect sound standard" }, | ||
1073 | { 0x0001, 0, 0, "autodetect started" }, | ||
1074 | { 0x0002, MSP_CARRIER(4.5), MSP_CARRIER(4.72), "4.5/4.72 M Dual FM-Stereo" }, | ||
1075 | { 0x0003, MSP_CARRIER(5.5), MSP_CARRIER(5.7421875), "5.5/5.74 B/G Dual FM-Stereo" }, | ||
1076 | { 0x0004, MSP_CARRIER(6.5), MSP_CARRIER(6.2578125), "6.5/6.25 D/K1 Dual FM-Stereo" }, | ||
1077 | { 0x0005, MSP_CARRIER(6.5), MSP_CARRIER(6.7421875), "6.5/6.74 D/K2 Dual FM-Stereo" }, | ||
1078 | { 0x0006, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 D/K FM-Mono (HDEV3)" }, | ||
1079 | { 0x0008, MSP_CARRIER(5.5), MSP_CARRIER(5.85), "5.5/5.85 B/G NICAM FM" }, | ||
1080 | { 0x0009, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 L NICAM AM" }, | ||
1081 | { 0x000a, MSP_CARRIER(6.0), MSP_CARRIER(6.55), "6.0/6.55 I NICAM FM" }, | ||
1082 | { 0x000b, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM" }, | ||
1083 | { 0x000c, MSP_CARRIER(6.5), MSP_CARRIER(5.85), "6.5/5.85 D/K NICAM FM (HDEV2)" }, | ||
1084 | { 0x0020, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Stereo" }, | ||
1085 | { 0x0021, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M BTSC-Mono + SAP" }, | ||
1086 | { 0x0030, MSP_CARRIER(4.5), MSP_CARRIER(4.5), "4.5 M EIA-J Japan Stereo" }, | ||
1087 | { 0x0040, MSP_CARRIER(10.7), MSP_CARRIER(10.7), "10.7 FM-Stereo Radio" }, | ||
1088 | { 0x0050, MSP_CARRIER(6.5), MSP_CARRIER(6.5), "6.5 SAT-Mono" }, | ||
1089 | { 0x0051, MSP_CARRIER(7.02), MSP_CARRIER(7.20), "7.02/7.20 SAT-Stereo" }, | ||
1090 | { 0x0060, MSP_CARRIER(7.2), MSP_CARRIER(7.2), "7.2 SAT ADR" }, | ||
1091 | { -1, 0, 0, NULL }, /* EOF */ | ||
1092 | }; | ||
1093 | |||
1094 | static inline const char *msp_standard_mode_name(int mode) | ||
1095 | { | ||
1096 | int i; | ||
1097 | for (i = 0; modelist[i].name != NULL; i++) | ||
1098 | if (modelist[i].retval == mode) | ||
1099 | return modelist[i].name; | ||
1100 | return "unknown"; | ||
1101 | } | ||
1102 | |||
1103 | static int msp_modus(struct i2c_client *client, int norm) | ||
1104 | { | ||
1105 | switch (norm) { | ||
1106 | case VIDEO_MODE_PAL: | ||
1107 | msp_dbg1("video mode selected to PAL\n"); | ||
1108 | |||
1109 | #if 1 | ||
1110 | /* experimental: not sure this works with all chip versions */ | ||
1111 | return 0x7003; | ||
1112 | #else | ||
1113 | /* previous value, try this if it breaks ... */ | ||
1114 | return 0x1003; | ||
1115 | #endif | ||
1116 | case VIDEO_MODE_NTSC: /* BTSC */ | ||
1117 | msp_dbg1("video mode selected to NTSC\n"); | ||
1118 | return 0x2003; | ||
1119 | case VIDEO_MODE_SECAM: | ||
1120 | msp_dbg1("video mode selected to SECAM\n"); | ||
1121 | return 0x0003; | ||
1122 | case VIDEO_MODE_RADIO: | ||
1123 | msp_dbg1("video mode selected to Radio\n"); | ||
1124 | return 0x0003; | ||
1125 | case VIDEO_MODE_AUTO: | ||
1126 | msp_dbg1("video mode selected to Auto\n"); | ||
1127 | return 0x2003; | ||
1128 | default: | ||
1129 | return 0x0003; | ||
1130 | } | ||
1131 | } | ||
1132 | |||
1133 | static int msp_standard(int norm) | ||
1134 | { | ||
1135 | switch (norm) { | ||
1136 | case VIDEO_MODE_PAL: | ||
1137 | return 1; | ||
1138 | case VIDEO_MODE_NTSC: /* BTSC */ | ||
1139 | return 0x0020; | ||
1140 | case VIDEO_MODE_SECAM: | ||
1141 | return 1; | ||
1142 | case VIDEO_MODE_RADIO: | ||
1143 | return 0x0040; | ||
1144 | default: | ||
1145 | return 1; | ||
1146 | } | ||
1147 | } | ||
1148 | |||
1149 | static int msp3410d_thread(void *data) | ||
1150 | { | ||
1151 | struct i2c_client *client = data; | ||
1152 | struct msp_state *state = i2c_get_clientdata(client); | ||
1153 | int mode,val,i,std; | ||
1154 | |||
1155 | msp_info("msp3410 daemon started\n"); | ||
1156 | |||
1157 | for (;;) { | ||
1158 | msp_dbg2("msp3410 thread: sleep\n"); | ||
1159 | msp_sleep(state,-1); | ||
1160 | msp_dbg2("msp3410 thread: wakeup\n"); | ||
1161 | |||
1162 | restart: | ||
1163 | msp_dbg1("thread: restart scan\n"); | ||
1164 | state->restart = 0; | ||
1165 | if (kthread_should_stop()) | ||
1166 | break; | ||
1167 | |||
1168 | if (state->mode == MSP_MODE_EXTERN) { | ||
1169 | /* no carrier scan needed, just unmute */ | ||
1170 | msp_dbg1("thread: no carrier scan\n"); | ||
1171 | msp_set_audio(client); | ||
1172 | continue; | ||
1173 | } | ||
1174 | |||
1175 | /* put into sane state (and mute) */ | ||
1176 | msp_reset(client); | ||
1177 | |||
1178 | /* some time for the tuner to sync */ | ||
1179 | if (msp_sleep(state,200)) | ||
1180 | goto restart; | ||
1181 | |||
1182 | /* start autodetect */ | ||
1183 | mode = msp_modus(client, state->norm); | ||
1184 | std = msp_standard(state->norm); | ||
1185 | msp_write_dem(client, 0x30, mode); | ||
1186 | msp_write_dem(client, 0x20, std); | ||
1187 | state->watch_stereo = 0; | ||
1188 | |||
1189 | if (debug) | ||
1190 | msp_dbg1("setting mode: %s (0x%04x)\n", | ||
1191 | msp_standard_mode_name(std) ,std); | ||
1192 | |||
1193 | if (std != 1) { | ||
1194 | /* programmed some specific mode */ | ||
1195 | val = std; | ||
1196 | } else { | ||
1197 | /* triggered autodetect */ | ||
1198 | for (;;) { | ||
1199 | if (msp_sleep(state,100)) | ||
1200 | goto restart; | ||
1201 | |||
1202 | /* check results */ | ||
1203 | val = msp_read_dem(client, 0x7e); | ||
1204 | if (val < 0x07ff) | ||
1205 | break; | ||
1206 | msp_dbg1("detection still in progress\n"); | ||
1207 | } | ||
1208 | } | ||
1209 | for (i = 0; modelist[i].name != NULL; i++) | ||
1210 | if (modelist[i].retval == val) | ||
1211 | break; | ||
1212 | msp_dbg1("current mode: %s (0x%04x)\n", | ||
1213 | modelist[i].name ? modelist[i].name : "unknown", | ||
1214 | val); | ||
1215 | state->main = modelist[i].main; | ||
1216 | state->second = modelist[i].second; | ||
1217 | |||
1218 | if (amsound && (state->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) { | ||
1219 | /* autodetection has failed, let backup */ | ||
1220 | msp_dbg1("autodetection failed," | ||
1221 | " switching to backup mode: %s (0x%04x)\n", | ||
1222 | modelist[8].name ? modelist[8].name : "unknown",val); | ||
1223 | val = 0x0009; | ||
1224 | msp_write_dem(client, 0x20, val); | ||
1225 | } | ||
1226 | |||
1227 | /* set various prescales */ | ||
1228 | msp_write_dsp(client, 0x0d, 0x1900); /* scart */ | ||
1229 | msp_write_dsp(client, 0x0e, 0x2403); /* FM */ | ||
1230 | msp_write_dsp(client, 0x10, 0x5a00); /* nicam */ | ||
1231 | |||
1232 | /* set stereo */ | ||
1233 | switch (val) { | ||
1234 | case 0x0008: /* B/G NICAM */ | ||
1235 | case 0x000a: /* I NICAM */ | ||
1236 | if (val == 0x0008) | ||
1237 | state->mode = MSP_MODE_FM_NICAM1; | ||
1238 | else | ||
1239 | state->mode = MSP_MODE_FM_NICAM2; | ||
1240 | /* just turn on stereo */ | ||
1241 | state->rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
1242 | state->nicam_on = 1; | ||
1243 | state->watch_stereo = 1; | ||
1244 | msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO); | ||
1245 | break; | ||
1246 | case 0x0009: | ||
1247 | state->mode = MSP_MODE_AM_NICAM; | ||
1248 | state->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
1249 | state->nicam_on = 1; | ||
1250 | msp3400c_setstereo(client,V4L2_TUNER_MODE_MONO); | ||
1251 | state->watch_stereo = 1; | ||
1252 | break; | ||
1253 | case 0x0020: /* BTSC */ | ||
1254 | /* just turn on stereo */ | ||
1255 | state->mode = MSP_MODE_BTSC; | ||
1256 | state->rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
1257 | state->nicam_on = 0; | ||
1258 | state->watch_stereo = 1; | ||
1259 | msp3400c_setstereo(client,V4L2_TUNER_MODE_STEREO); | ||
1260 | break; | ||
1261 | case 0x0040: /* FM radio */ | ||
1262 | state->mode = MSP_MODE_FM_RADIO; | ||
1263 | state->rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
1264 | state->audmode = V4L2_TUNER_MODE_STEREO; | ||
1265 | state->nicam_on = 0; | ||
1266 | state->watch_stereo = 0; | ||
1267 | /* not needed in theory if HAVE_RADIO(), but | ||
1268 | short programming enables carrier mute */ | ||
1269 | msp3400c_setmode(client,MSP_MODE_FM_RADIO); | ||
1270 | msp3400c_setcarrier(client, MSP_CARRIER(10.7), | ||
1271 | MSP_CARRIER(10.7)); | ||
1272 | /* scart routing */ | ||
1273 | msp_set_scart(client,SCART_IN2,0); | ||
1274 | /* msp34xx does radio decoding */ | ||
1275 | msp_write_dsp(client, 0x08, 0x0020); | ||
1276 | msp_write_dsp(client, 0x09, 0x0020); | ||
1277 | msp_write_dsp(client, 0x0b, 0x0020); | ||
1278 | break; | ||
1279 | case 0x0003: | ||
1280 | case 0x0004: | ||
1281 | case 0x0005: | ||
1282 | state->mode = MSP_MODE_FM_TERRA; | ||
1283 | state->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
1284 | state->audmode = V4L2_TUNER_MODE_MONO; | ||
1285 | state->nicam_on = 0; | ||
1286 | state->watch_stereo = 1; | ||
1287 | break; | ||
1288 | } | ||
1289 | |||
1290 | /* unmute, restore misc registers */ | ||
1291 | msp_set_audio(client); | ||
1292 | msp_write_dsp(client, 0x13, state->acb); | ||
1293 | msp_write_dem(client, 0x40, state->i2s_mode); | ||
1294 | msp3400c_restore_dfp(client); | ||
1295 | |||
1296 | /* monitor tv audio mode */ | ||
1297 | while (state->watch_stereo) { | ||
1298 | if (msp_sleep(state,5000)) | ||
1299 | goto restart; | ||
1300 | watch_stereo(client); | ||
1301 | } | ||
1302 | } | ||
1303 | msp_dbg1("thread: exit\n"); | ||
1304 | return 0; | ||
1305 | } | ||
1306 | |||
1307 | /* ----------------------------------------------------------------------- */ | ||
1308 | /* msp34xxG + (autoselect no-thread) */ | ||
1309 | /* this one uses both automatic standard detection and automatic sound */ | ||
1310 | /* select which are available in the newer G versions */ | ||
1311 | /* struct msp: only norm, acb and source are really used in this mode */ | ||
1312 | |||
1313 | /* set the same 'source' for the loudspeaker, scart and quasi-peak detector | ||
1314 | * the value for source is the same as bit 15:8 of DFP registers 0x08, | ||
1315 | * 0x0a and 0x0c: 0=mono, 1=stereo or A|B, 2=SCART, 3=stereo or A, 4=stereo or B | ||
1316 | * | ||
1317 | * this function replaces msp3400c_setstereo | ||
1318 | */ | ||
1319 | static void msp34xxg_set_source(struct i2c_client *client, int source) | ||
1320 | { | ||
1321 | struct msp_state *state = i2c_get_clientdata(client); | ||
1322 | |||
1323 | /* fix matrix mode to stereo and let the msp choose what | ||
1324 | * to output according to 'source', as recommended | ||
1325 | * for MONO (source==0) downmixing set bit[7:0] to 0x30 | ||
1326 | */ | ||
1327 | int value = (source & 0x07) << 8 | (source == 0 ? 0x30 : 0x20); | ||
1328 | |||
1329 | msp_dbg1("set source to %d (0x%x)\n", source, value); | ||
1330 | /* Loudspeaker Output */ | ||
1331 | msp_write_dsp(client, 0x08, value); | ||
1332 | /* SCART1 DA Output */ | ||
1333 | msp_write_dsp(client, 0x0a, value); | ||
1334 | /* Quasi-peak detector */ | ||
1335 | msp_write_dsp(client, 0x0c, value); | ||
1336 | /* | ||
1337 | * set identification threshold. Personally, I | ||
1338 | * I set it to a higher value that the default | ||
1339 | * of 0x190 to ignore noisy stereo signals. | ||
1340 | * this needs tuning. (recommended range 0x00a0-0x03c0) | ||
1341 | * 0x7f0 = forced mono mode | ||
1342 | */ | ||
1343 | /* a2 threshold for stereo/bilingual */ | ||
1344 | msp_write_dem(client, 0x22, stereo_threshold); | ||
1345 | state->source = source; | ||
1346 | } | ||
1347 | |||
1348 | /* (re-)initialize the msp34xxg, according to the current norm in state->norm | ||
1349 | * return 0 if it worked, -1 if it failed | ||
1350 | */ | ||
1351 | static int msp34xxg_reset(struct i2c_client *client) | ||
1352 | { | ||
1353 | struct msp_state *state = i2c_get_clientdata(client); | ||
1354 | int modus, std; | ||
1355 | |||
1356 | if (msp_reset(client)) | ||
1357 | return -1; | ||
1358 | |||
1359 | /* make sure that input/output is muted (paranoid mode) */ | ||
1360 | /* ACB, mute DSP input, mute SCART 1 */ | ||
1361 | if (msp_write_dsp(client, 0x13, 0x0f20)) | ||
1362 | return -1; | ||
1363 | |||
1364 | msp_write_dem(client, 0x40, state->i2s_mode); | ||
1365 | |||
1366 | /* step-by-step initialisation, as described in the manual */ | ||
1367 | modus = msp_modus(client, state->norm); | ||
1368 | std = msp_standard(state->norm); | ||
1369 | modus &= ~0x03; /* STATUS_CHANGE = 0 */ | ||
1370 | modus |= 0x01; /* AUTOMATIC_SOUND_DETECTION = 1 */ | ||
1371 | if (msp_write_dem(client, 0x30, modus)) | ||
1372 | return -1; | ||
1373 | if (msp_write_dem(client, 0x20, std)) | ||
1374 | return -1; | ||
1375 | |||
1376 | /* write the dfps that may have an influence on | ||
1377 | standard/audio autodetection right now */ | ||
1378 | msp34xxg_set_source(client, state->source); | ||
1379 | |||
1380 | /* AM/FM Prescale, default: [15:8] 75khz deviation */ | ||
1381 | if (msp34xxg_write_dfp_with_default(client, 0x0e, 0x3000)) | ||
1382 | return -1; | ||
1383 | |||
1384 | /* NICAM Prescale, default: 9db gain (as recommended) */ | ||
1385 | if (msp34xxg_write_dfp_with_default(client, 0x10, 0x5a00)) | ||
1386 | return -1; | ||
1387 | |||
1388 | return 0; | ||
1389 | } | ||
1390 | |||
1391 | static int msp34xxg_thread(void *data) | ||
1392 | { | ||
1393 | struct i2c_client *client = data; | ||
1394 | struct msp_state *state = i2c_get_clientdata(client); | ||
1395 | int val, std, i; | ||
1396 | |||
1397 | msp_info("msp34xxg daemon started\n"); | ||
1398 | |||
1399 | state->source = 1; /* default */ | ||
1400 | for (;;) { | ||
1401 | msp_dbg2("msp34xxg thread: sleep\n"); | ||
1402 | msp_sleep(state, -1); | ||
1403 | msp_dbg2("msp34xxg thread: wakeup\n"); | ||
1404 | |||
1405 | restart: | ||
1406 | msp_dbg1("thread: restart scan\n"); | ||
1407 | state->restart = 0; | ||
1408 | if (kthread_should_stop()) | ||
1409 | break; | ||
1410 | |||
1411 | /* setup the chip*/ | ||
1412 | msp34xxg_reset(client); | ||
1413 | std = standard; | ||
1414 | if (std != 0x01) | ||
1415 | goto unmute; | ||
1416 | |||
1417 | /* watch autodetect */ | ||
1418 | msp_dbg1("triggered autodetect, waiting for result\n"); | ||
1419 | for (i = 0; i < 10; i++) { | ||
1420 | if (msp_sleep(state, 100)) | ||
1421 | goto restart; | ||
1422 | |||
1423 | /* check results */ | ||
1424 | val = msp_read_dem(client, 0x7e); | ||
1425 | if (val < 0x07ff) { | ||
1426 | std = val; | ||
1427 | break; | ||
1428 | } | ||
1429 | msp_dbg1("detection still in progress\n"); | ||
1430 | } | ||
1431 | if (std == 1) { | ||
1432 | msp_dbg1("detection still in progress after 10 tries. giving up.\n"); | ||
1433 | continue; | ||
1434 | } | ||
1435 | |||
1436 | unmute: | ||
1437 | state->mode = std; | ||
1438 | msp_dbg1("current mode: %s (0x%04x)\n", | ||
1439 | msp_standard_mode_name(std), std); | ||
1440 | |||
1441 | /* unmute: dispatch sound to scart output, set scart volume */ | ||
1442 | msp_set_audio(client); | ||
1443 | |||
1444 | /* restore ACB */ | ||
1445 | if (msp_write_dsp(client, 0x13, state->acb)) | ||
1446 | return -1; | ||
1447 | |||
1448 | msp_write_dem(client, 0x40, state->i2s_mode); | ||
1449 | } | ||
1450 | msp_dbg1("thread: exit\n"); | ||
1451 | return 0; | ||
1452 | } | ||
1453 | |||
1454 | static void msp34xxg_detect_stereo(struct i2c_client *client) | ||
1455 | { | ||
1456 | struct msp_state *state = i2c_get_clientdata(client); | ||
1457 | |||
1458 | int status = msp_read_dem(client, 0x0200); | ||
1459 | int is_bilingual = status & 0x100; | ||
1460 | int is_stereo = status & 0x40; | ||
1461 | |||
1462 | state->rxsubchans = 0; | ||
1463 | if (is_stereo) | ||
1464 | state->rxsubchans |= V4L2_TUNER_SUB_STEREO; | ||
1465 | else | ||
1466 | state->rxsubchans |= V4L2_TUNER_SUB_MONO; | ||
1467 | if (is_bilingual) { | ||
1468 | state->rxsubchans |= V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; | ||
1469 | /* I'm supposed to check whether it's SAP or not | ||
1470 | * and set only LANG2/SAP in this case. Yet, the MSP | ||
1471 | * does a lot of work to hide this and handle everything | ||
1472 | * the same way. I don't want to work around it so unless | ||
1473 | * this is a problem, I'll handle SAP just like lang1/lang2. | ||
1474 | */ | ||
1475 | } | ||
1476 | msp_dbg1("status=0x%x, stereo=%d, bilingual=%d -> rxsubchans=%d\n", | ||
1477 | status, is_stereo, is_bilingual, state->rxsubchans); | ||
1478 | } | ||
1479 | |||
1480 | static void msp34xxg_set_audmode(struct i2c_client *client, int audmode) | ||
1481 | { | ||
1482 | struct msp_state *state = i2c_get_clientdata(client); | ||
1483 | int source; | ||
1484 | |||
1485 | switch (audmode) { | ||
1486 | case V4L2_TUNER_MODE_MONO: | ||
1487 | source = 0; /* mono only */ | ||
1488 | break; | ||
1489 | case V4L2_TUNER_MODE_STEREO: | ||
1490 | source = 1; /* stereo or A|B, see comment in msp34xxg_get_v4l2_stereo() */ | ||
1491 | /* problem: that could also mean 2 (scart input) */ | ||
1492 | break; | ||
1493 | case V4L2_TUNER_MODE_LANG1: | ||
1494 | source = 3; /* stereo or A */ | ||
1495 | break; | ||
1496 | case V4L2_TUNER_MODE_LANG2: | ||
1497 | source = 4; /* stereo or B */ | ||
1498 | break; | ||
1499 | default: | ||
1500 | audmode = 0; | ||
1501 | source = 1; | ||
1502 | break; | ||
1503 | } | ||
1504 | state->audmode = audmode; | ||
1505 | msp34xxg_set_source(client, source); | ||
1506 | } | ||
1507 | |||
1508 | |||
1509 | /* ----------------------------------------------------------------------- */ | ||
1510 | |||
1511 | static void msp_wake_thread(struct i2c_client *client) | ||
1512 | { | ||
1513 | struct msp_state *state = i2c_get_clientdata(client); | ||
1514 | |||
1515 | if (NULL == state->kthread) | ||
1516 | return; | ||
1517 | msp_set_mute(client); | ||
1518 | state->watch_stereo = 0; | ||
1519 | state->restart = 1; | ||
1520 | wake_up_interruptible(&state->wq); | ||
1521 | } | ||
1522 | |||
1523 | /* ----------------------------------------------------------------------- */ | ||
1524 | |||
1525 | static int mode_v4l2_to_v4l1(int rxsubchans) | ||
1526 | { | ||
1527 | int mode = 0; | ||
1528 | |||
1529 | if (rxsubchans & V4L2_TUNER_SUB_STEREO) | ||
1530 | mode |= VIDEO_SOUND_STEREO; | ||
1531 | if (rxsubchans & V4L2_TUNER_SUB_LANG2) | ||
1532 | mode |= VIDEO_SOUND_LANG2; | ||
1533 | if (rxsubchans & V4L2_TUNER_SUB_LANG1) | ||
1534 | mode |= VIDEO_SOUND_LANG1; | ||
1535 | if (mode == 0) | ||
1536 | mode |= VIDEO_SOUND_MONO; | ||
1537 | return mode; | ||
1538 | } | ||
1539 | |||
1540 | static int mode_v4l1_to_v4l2(int mode) | ||
1541 | { | ||
1542 | if (mode & VIDEO_SOUND_STEREO) | ||
1543 | return V4L2_TUNER_MODE_STEREO; | ||
1544 | if (mode & VIDEO_SOUND_LANG2) | ||
1545 | return V4L2_TUNER_MODE_LANG2; | ||
1546 | if (mode & VIDEO_SOUND_LANG1) | ||
1547 | return V4L2_TUNER_MODE_LANG1; | ||
1548 | return V4L2_TUNER_MODE_MONO; | ||
1549 | } | ||
1550 | |||
1551 | static void msp_any_detect_stereo(struct i2c_client *client) | ||
1552 | { | ||
1553 | struct msp_state *state = i2c_get_clientdata(client); | ||
1554 | |||
1555 | switch (state->opmode) { | ||
1556 | case OPMODE_MANUAL: | ||
1557 | case OPMODE_AUTODETECT: | ||
1558 | autodetect_stereo(client); | ||
1559 | break; | ||
1560 | case OPMODE_AUTOSELECT: | ||
1561 | msp34xxg_detect_stereo(client); | ||
1562 | break; | ||
1563 | } | ||
1564 | } | ||
1565 | |||
1566 | static struct v4l2_queryctrl msp_qctrl[] = { | ||
1567 | { | ||
1568 | .id = V4L2_CID_AUDIO_VOLUME, | ||
1569 | .name = "Volume", | ||
1570 | .minimum = 0, | ||
1571 | .maximum = 65535, | ||
1572 | .step = 65535/100, | ||
1573 | .default_value = 58880, | ||
1574 | .flags = 0, | ||
1575 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
1576 | },{ | ||
1577 | .id = V4L2_CID_AUDIO_MUTE, | ||
1578 | .name = "Mute", | ||
1579 | .minimum = 0, | ||
1580 | .maximum = 1, | ||
1581 | .step = 1, | ||
1582 | .default_value = 1, | ||
1583 | .flags = 0, | ||
1584 | .type = V4L2_CTRL_TYPE_BOOLEAN, | ||
1585 | },{ | ||
1586 | .id = V4L2_CID_AUDIO_BASS, | ||
1587 | .name = "Bass", | ||
1588 | .minimum = 0, | ||
1589 | .maximum = 65535, | ||
1590 | .step = 65535/100, | ||
1591 | .default_value = 32768, | ||
1592 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
1593 | },{ | ||
1594 | .id = V4L2_CID_AUDIO_TREBLE, | ||
1595 | .name = "Treble", | ||
1596 | .minimum = 0, | ||
1597 | .maximum = 65535, | ||
1598 | .step = 65535/100, | ||
1599 | .default_value = 32768, | ||
1600 | .type = V4L2_CTRL_TYPE_INTEGER, | ||
1601 | }, | ||
1602 | }; | ||
1603 | |||
1604 | |||
1605 | static void msp_any_set_audmode(struct i2c_client *client, int audmode) | ||
1606 | { | ||
1607 | struct msp_state *state = i2c_get_clientdata(client); | ||
1608 | |||
1609 | switch (state->opmode) { | ||
1610 | case OPMODE_MANUAL: | ||
1611 | case OPMODE_AUTODETECT: | ||
1612 | state->watch_stereo = 0; | ||
1613 | msp3400c_setstereo(client, audmode); | ||
1614 | break; | ||
1615 | case OPMODE_AUTOSELECT: | ||
1616 | msp34xxg_set_audmode(client, audmode); | ||
1617 | break; | ||
1618 | } | ||
1619 | } | ||
1620 | |||
1621 | static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) | ||
1622 | { | ||
1623 | struct msp_state *state = i2c_get_clientdata(client); | ||
1624 | |||
1625 | switch (ctrl->id) { | ||
1626 | case V4L2_CID_AUDIO_MUTE: | ||
1627 | ctrl->value = state->muted; | ||
1628 | break; | ||
1629 | |||
1630 | case V4L2_CID_AUDIO_BALANCE: | ||
1631 | ctrl->value = state->balance; | ||
1632 | break; | ||
1633 | |||
1634 | case V4L2_CID_AUDIO_BASS: | ||
1635 | ctrl->value = state->bass; | ||
1636 | break; | ||
1637 | |||
1638 | case V4L2_CID_AUDIO_TREBLE: | ||
1639 | ctrl->value = state->treble; | ||
1640 | break; | ||
1641 | |||
1642 | case V4L2_CID_AUDIO_VOLUME: | ||
1643 | ctrl->value = state->volume; | ||
1644 | break; | ||
1645 | |||
1646 | default: | ||
1647 | return -EINVAL; | ||
1648 | } | ||
1649 | return 0; | ||
1650 | } | ||
1651 | |||
1652 | static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl) | ||
1653 | { | ||
1654 | struct msp_state *state = i2c_get_clientdata(client); | ||
1655 | |||
1656 | switch (ctrl->id) { | ||
1657 | case V4L2_CID_AUDIO_MUTE: | ||
1658 | if (ctrl->value < 0 || ctrl->value >= 2) | ||
1659 | return -ERANGE; | ||
1660 | state->muted = ctrl->value; | ||
1661 | break; | ||
1662 | |||
1663 | case V4L2_CID_AUDIO_BASS: | ||
1664 | state->bass = ctrl->value; | ||
1665 | break; | ||
1666 | |||
1667 | case V4L2_CID_AUDIO_TREBLE: | ||
1668 | state->treble = ctrl->value; | ||
1669 | break; | ||
1670 | |||
1671 | case V4L2_CID_AUDIO_BALANCE: | ||
1672 | state->balance = ctrl->value; | ||
1673 | break; | ||
1674 | |||
1675 | case V4L2_CID_AUDIO_VOLUME: | ||
1676 | state->volume = ctrl->value; | ||
1677 | if (state->volume == 0) | ||
1678 | state->balance = 32768; | ||
1679 | break; | ||
1680 | |||
1681 | default: | ||
1682 | return -EINVAL; | ||
1683 | } | ||
1684 | msp_set_audio(client); | ||
1685 | return 0; | ||
1686 | } | ||
1687 | |||
1688 | static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg) | ||
1689 | { | ||
1690 | struct msp_state *state = i2c_get_clientdata(client); | ||
1691 | u16 *sarg = arg; | ||
1692 | int scart = 0; | ||
1693 | |||
1694 | if (debug >= 2) | ||
1695 | v4l_i2c_print_ioctl(client, cmd); | ||
1696 | |||
1697 | switch (cmd) { | ||
1698 | case AUDC_SET_INPUT: | ||
1699 | if (*sarg == state->input) | ||
1700 | break; | ||
1701 | state->input = *sarg; | ||
1702 | switch (*sarg) { | ||
1703 | case AUDIO_RADIO: | ||
1704 | /* Hauppauge uses IN2 for the radio */ | ||
1705 | state->mode = MSP_MODE_FM_RADIO; | ||
1706 | scart = SCART_IN2; | ||
1707 | break; | ||
1708 | case AUDIO_EXTERN_1: | ||
1709 | /* IN1 is often used for external input ... */ | ||
1710 | state->mode = MSP_MODE_EXTERN; | ||
1711 | scart = SCART_IN1; | ||
1712 | break; | ||
1713 | case AUDIO_EXTERN_2: | ||
1714 | /* ... sometimes it is IN2 through ;) */ | ||
1715 | state->mode = MSP_MODE_EXTERN; | ||
1716 | scart = SCART_IN2; | ||
1717 | break; | ||
1718 | case AUDIO_TUNER: | ||
1719 | state->mode = -1; | ||
1720 | break; | ||
1721 | default: | ||
1722 | if (*sarg & AUDIO_MUTE) | ||
1723 | msp_set_scart(client, SCART_MUTE, 0); | ||
1724 | break; | ||
1725 | } | ||
1726 | if (scart) { | ||
1727 | state->rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
1728 | state->audmode = V4L2_TUNER_MODE_STEREO; | ||
1729 | msp_set_scart(client, scart, 0); | ||
1730 | msp_write_dsp(client, 0x000d, 0x1900); | ||
1731 | if (state->opmode != OPMODE_AUTOSELECT) | ||
1732 | msp3400c_setstereo(client, state->audmode); | ||
1733 | } | ||
1734 | msp_wake_thread(client); | ||
1735 | break; | ||
1736 | |||
1737 | case AUDC_SET_RADIO: | ||
1738 | state->norm = VIDEO_MODE_RADIO; | ||
1739 | msp_dbg1("switching to radio mode\n"); | ||
1740 | state->watch_stereo = 0; | ||
1741 | switch (state->opmode) { | ||
1742 | case OPMODE_MANUAL: | ||
1743 | /* set msp3400 to FM radio mode */ | ||
1744 | msp3400c_setmode(client, MSP_MODE_FM_RADIO); | ||
1745 | msp3400c_setcarrier(client, MSP_CARRIER(10.7), | ||
1746 | MSP_CARRIER(10.7)); | ||
1747 | msp_set_audio(client); | ||
1748 | break; | ||
1749 | case OPMODE_AUTODETECT: | ||
1750 | case OPMODE_AUTOSELECT: | ||
1751 | /* the thread will do for us */ | ||
1752 | msp_wake_thread(client); | ||
1753 | break; | ||
1754 | } | ||
1755 | break; | ||
1756 | /* work-in-progress: hook to control the DFP registers */ | ||
1757 | case MSP_SET_DFPREG: | ||
1758 | { | ||
1759 | struct msp_dfpreg *r = arg; | ||
1760 | int i; | ||
1761 | |||
1762 | if (r->reg < 0 || r->reg >= DFP_COUNT) | ||
1763 | return -EINVAL; | ||
1764 | for (i = 0; i < sizeof(bl_dfp) / sizeof(int); i++) | ||
1765 | if (r->reg == bl_dfp[i]) | ||
1766 | return -EINVAL; | ||
1767 | state->dfp_regs[r->reg] = r->value; | ||
1768 | msp_write_dsp(client, r->reg, r->value); | ||
1769 | return 0; | ||
1770 | } | ||
1771 | |||
1772 | case MSP_GET_DFPREG: | ||
1773 | { | ||
1774 | struct msp_dfpreg *r = arg; | ||
1775 | |||
1776 | if (r->reg < 0 || r->reg >= DFP_COUNT) | ||
1777 | return -EINVAL; | ||
1778 | r->value = msp_read_dsp(client, r->reg); | ||
1779 | return 0; | ||
1780 | } | ||
1781 | |||
1782 | /* --- v4l ioctls --- */ | ||
1783 | /* take care: bttv does userspace copying, we'll get a | ||
1784 | kernel pointer here... */ | ||
1785 | case VIDIOCGAUDIO: | ||
1786 | { | ||
1787 | struct video_audio *va = arg; | ||
1788 | |||
1789 | va->flags |= VIDEO_AUDIO_VOLUME | | ||
1790 | VIDEO_AUDIO_BASS | | ||
1791 | VIDEO_AUDIO_TREBLE | | ||
1792 | VIDEO_AUDIO_MUTABLE; | ||
1793 | if (state->muted) | ||
1794 | va->flags |= VIDEO_AUDIO_MUTE; | ||
1795 | |||
1796 | if (state->muted) | ||
1797 | va->flags |= VIDEO_AUDIO_MUTE; | ||
1798 | va->volume = state->volume; | ||
1799 | va->balance = state->volume ? state->balance : 32768; | ||
1800 | va->bass = state->bass; | ||
1801 | va->treble = state->treble; | ||
1802 | |||
1803 | msp_any_detect_stereo(client); | ||
1804 | va->mode = mode_v4l2_to_v4l1(state->rxsubchans); | ||
1805 | break; | ||
1806 | } | ||
1807 | |||
1808 | case VIDIOCSAUDIO: | ||
1809 | { | ||
1810 | struct video_audio *va = arg; | ||
1811 | |||
1812 | state->muted = (va->flags & VIDEO_AUDIO_MUTE); | ||
1813 | state->volume = va->volume; | ||
1814 | state->balance = va->balance; | ||
1815 | state->bass = va->bass; | ||
1816 | state->treble = va->treble; | ||
1817 | msp_set_audio(client); | ||
1818 | |||
1819 | if (va->mode != 0 && state->norm != VIDEO_MODE_RADIO) | ||
1820 | msp_any_set_audmode(client,mode_v4l1_to_v4l2(va->mode)); | ||
1821 | break; | ||
1822 | } | ||
1823 | |||
1824 | case VIDIOCSCHAN: | ||
1825 | { | ||
1826 | struct video_channel *vc = arg; | ||
1827 | |||
1828 | state->norm = vc->norm; | ||
1829 | msp_wake_thread(client); | ||
1830 | break; | ||
1831 | } | ||
1832 | |||
1833 | case VIDIOCSFREQ: | ||
1834 | case VIDIOC_S_FREQUENCY: | ||
1835 | { | ||
1836 | /* new channel -- kick audio carrier scan */ | ||
1837 | msp_wake_thread(client); | ||
1838 | break; | ||
1839 | } | ||
1840 | |||
1841 | /* msp34xx specific */ | ||
1842 | case MSP_SET_MATRIX: | ||
1843 | { | ||
1844 | struct msp_matrix *mspm = arg; | ||
1845 | |||
1846 | msp_set_scart(client, mspm->input, mspm->output); | ||
1847 | break; | ||
1848 | } | ||
1849 | |||
1850 | /* --- v4l2 ioctls --- */ | ||
1851 | case VIDIOC_S_STD: | ||
1852 | { | ||
1853 | v4l2_std_id *id = arg; | ||
1854 | |||
1855 | /*FIXME: use V4L2 mode flags on msp3400 instead of V4L1*/ | ||
1856 | if (*id & V4L2_STD_PAL) { | ||
1857 | state->norm = VIDEO_MODE_PAL; | ||
1858 | } else if (*id & V4L2_STD_SECAM) { | ||
1859 | state->norm = VIDEO_MODE_SECAM; | ||
1860 | } else { | ||
1861 | state->norm = VIDEO_MODE_NTSC; | ||
1862 | } | ||
1863 | |||
1864 | msp_wake_thread(client); | ||
1865 | return 0; | ||
1866 | } | ||
1867 | |||
1868 | case VIDIOC_ENUMINPUT: | ||
1869 | { | ||
1870 | struct v4l2_input *i = arg; | ||
1871 | |||
1872 | if (i->index != 0) | ||
1873 | return -EINVAL; | ||
1874 | |||
1875 | i->type = V4L2_INPUT_TYPE_TUNER; | ||
1876 | switch (i->index) { | ||
1877 | case AUDIO_RADIO: | ||
1878 | strcpy(i->name, "Radio"); | ||
1879 | break; | ||
1880 | case AUDIO_EXTERN_1: | ||
1881 | strcpy(i->name, "Extern 1"); | ||
1882 | break; | ||
1883 | case AUDIO_EXTERN_2: | ||
1884 | strcpy(i->name, "Extern 2"); | ||
1885 | break; | ||
1886 | case AUDIO_TUNER: | ||
1887 | strcpy(i->name, "Television"); | ||
1888 | break; | ||
1889 | default: | ||
1890 | return -EINVAL; | ||
1891 | } | ||
1892 | return 0; | ||
1893 | } | ||
1894 | |||
1895 | case VIDIOC_G_AUDIO: | ||
1896 | { | ||
1897 | struct v4l2_audio *a = arg; | ||
1898 | |||
1899 | memset(a, 0, sizeof(*a)); | ||
1900 | |||
1901 | switch (a->index) { | ||
1902 | case AUDIO_RADIO: | ||
1903 | strcpy(a->name, "Radio"); | ||
1904 | break; | ||
1905 | case AUDIO_EXTERN_1: | ||
1906 | strcpy(a->name, "Extern 1"); | ||
1907 | break; | ||
1908 | case AUDIO_EXTERN_2: | ||
1909 | strcpy(a->name, "Extern 2"); | ||
1910 | break; | ||
1911 | case AUDIO_TUNER: | ||
1912 | strcpy(a->name, "Television"); | ||
1913 | break; | ||
1914 | default: | ||
1915 | return -EINVAL; | ||
1916 | } | ||
1917 | |||
1918 | msp_any_detect_stereo(client); | ||
1919 | if (state->audmode == V4L2_TUNER_MODE_STEREO) { | ||
1920 | a->capability = V4L2_AUDCAP_STEREO; | ||
1921 | } | ||
1922 | |||
1923 | break; | ||
1924 | } | ||
1925 | |||
1926 | case VIDIOC_S_AUDIO: | ||
1927 | { | ||
1928 | struct v4l2_audio *sarg = arg; | ||
1929 | |||
1930 | switch (sarg->index) { | ||
1931 | case AUDIO_RADIO: | ||
1932 | /* Hauppauge uses IN2 for the radio */ | ||
1933 | state->mode = MSP_MODE_FM_RADIO; | ||
1934 | scart = SCART_IN2; | ||
1935 | break; | ||
1936 | case AUDIO_EXTERN_1: | ||
1937 | /* IN1 is often used for external input ... */ | ||
1938 | state->mode = MSP_MODE_EXTERN; | ||
1939 | scart = SCART_IN1; | ||
1940 | break; | ||
1941 | case AUDIO_EXTERN_2: | ||
1942 | /* ... sometimes it is IN2 through ;) */ | ||
1943 | state->mode = MSP_MODE_EXTERN; | ||
1944 | scart = SCART_IN2; | ||
1945 | break; | ||
1946 | case AUDIO_TUNER: | ||
1947 | state->mode = -1; | ||
1948 | break; | ||
1949 | } | ||
1950 | if (scart) { | ||
1951 | state->rxsubchans = V4L2_TUNER_SUB_STEREO; | ||
1952 | state->audmode = V4L2_TUNER_MODE_STEREO; | ||
1953 | msp_set_scart(client, scart, 0); | ||
1954 | msp_write_dsp(client, 0x000d, 0x1900); | ||
1955 | } | ||
1956 | if (sarg->capability == V4L2_AUDCAP_STEREO) { | ||
1957 | state->audmode = V4L2_TUNER_MODE_STEREO; | ||
1958 | } else { | ||
1959 | state->audmode &= ~V4L2_TUNER_MODE_STEREO; | ||
1960 | } | ||
1961 | msp_any_set_audmode(client, state->audmode); | ||
1962 | msp_wake_thread(client); | ||
1963 | break; | ||
1964 | } | ||
1965 | |||
1966 | case VIDIOC_G_TUNER: | ||
1967 | { | ||
1968 | struct v4l2_tuner *vt = arg; | ||
1969 | |||
1970 | msp_any_detect_stereo(client); | ||
1971 | vt->audmode = state->audmode; | ||
1972 | vt->rxsubchans = state->rxsubchans; | ||
1973 | vt->capability = V4L2_TUNER_CAP_STEREO | | ||
1974 | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; | ||
1975 | break; | ||
1976 | } | ||
1977 | |||
1978 | case VIDIOC_S_TUNER: | ||
1979 | { | ||
1980 | struct v4l2_tuner *vt = (struct v4l2_tuner *)arg; | ||
1981 | |||
1982 | /* only set audmode */ | ||
1983 | if (vt->audmode != -1 && vt->audmode != 0) | ||
1984 | msp_any_set_audmode(client, vt->audmode); | ||
1985 | break; | ||
1986 | } | ||
1987 | |||
1988 | case VIDIOC_G_AUDOUT: | ||
1989 | { | ||
1990 | struct v4l2_audioout *a = (struct v4l2_audioout *)arg; | ||
1991 | int idx = a->index; | ||
1992 | |||
1993 | memset(a, 0, sizeof(*a)); | ||
1994 | |||
1995 | switch (idx) { | ||
1996 | case 0: | ||
1997 | strcpy(a->name, "Scart1 Out"); | ||
1998 | break; | ||
1999 | case 1: | ||
2000 | strcpy(a->name, "Scart2 Out"); | ||
2001 | break; | ||
2002 | case 2: | ||
2003 | strcpy(a->name, "I2S Out"); | ||
2004 | break; | ||
2005 | default: | ||
2006 | return -EINVAL; | ||
2007 | } | ||
2008 | break; | ||
2009 | |||
2010 | } | ||
2011 | |||
2012 | case VIDIOC_S_AUDOUT: | ||
2013 | { | ||
2014 | struct v4l2_audioout *a = (struct v4l2_audioout *)arg; | ||
2015 | |||
2016 | if (a->index < 0 || a->index > 2) | ||
2017 | return -EINVAL; | ||
2018 | |||
2019 | msp_dbg1("Setting audio out on msp34xx to input %i\n", a->index); | ||
2020 | msp_set_scart(client, state->in_scart, a->index + 1); | ||
2021 | |||
2022 | break; | ||
2023 | } | ||
2024 | |||
2025 | case VIDIOC_INT_I2S_CLOCK_FREQ: | ||
2026 | { | ||
2027 | u32 *a = (u32 *)arg; | ||
2028 | |||
2029 | msp_dbg1("Setting I2S speed to %d\n", *a); | ||
2030 | |||
2031 | switch (*a) { | ||
2032 | case 1024000: | ||
2033 | state->i2s_mode = 0; | ||
2034 | break; | ||
2035 | case 2048000: | ||
2036 | state->i2s_mode = 1; | ||
2037 | break; | ||
2038 | default: | ||
2039 | return -EINVAL; | ||
2040 | } | ||
2041 | break; | ||
2042 | } | ||
2043 | |||
2044 | case VIDIOC_QUERYCTRL: | ||
2045 | { | ||
2046 | struct v4l2_queryctrl *qc = arg; | ||
2047 | int i; | ||
2048 | |||
2049 | for (i = 0; i < ARRAY_SIZE(msp_qctrl); i++) | ||
2050 | if (qc->id && qc->id == msp_qctrl[i].id) { | ||
2051 | memcpy(qc, &msp_qctrl[i], sizeof(*qc)); | ||
2052 | return 0; | ||
2053 | } | ||
2054 | return -EINVAL; | ||
2055 | } | ||
2056 | |||
2057 | case VIDIOC_G_CTRL: | ||
2058 | return msp_get_ctrl(client, arg); | ||
2059 | |||
2060 | case VIDIOC_S_CTRL: | ||
2061 | return msp_set_ctrl(client, arg); | ||
2062 | |||
2063 | case VIDIOC_LOG_STATUS: | ||
2064 | msp_any_detect_stereo(client); | ||
2065 | msp_info("%s rev1 = 0x%04x rev2 = 0x%04x\n", | ||
2066 | client->name, state->rev1, state->rev2); | ||
2067 | msp_info("Audio: volume %d balance %d bass %d treble %d%s\n", | ||
2068 | state->volume, state->balance, | ||
2069 | state->bass, state->treble, | ||
2070 | state->muted ? " (muted)" : ""); | ||
2071 | msp_info("Mode: %s (%s%s)\n", msp_standard_mode_name(state->mode), | ||
2072 | (state->rxsubchans & V4L2_TUNER_SUB_STEREO) ? "stereo" : "mono", | ||
2073 | (state->rxsubchans & V4L2_TUNER_SUB_LANG2) ? ", dual" : ""); | ||
2074 | msp_info("ACB: 0x%04x\n", state->acb); | ||
2075 | break; | ||
2076 | |||
2077 | default: | ||
2078 | /* nothing */ | ||
2079 | break; | ||
2080 | } | ||
2081 | return 0; | ||
2082 | } | ||
2083 | |||
2084 | static int msp_suspend(struct device * dev, pm_message_t state) | ||
2085 | { | ||
2086 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
2087 | |||
2088 | msp_dbg1("suspend\n"); | ||
2089 | msp_reset(client); | ||
2090 | return 0; | ||
2091 | } | ||
2092 | |||
2093 | static int msp_resume(struct device * dev) | ||
2094 | { | ||
2095 | struct i2c_client *client = container_of(dev, struct i2c_client, dev); | ||
2096 | |||
2097 | msp_dbg1("resume\n"); | ||
2098 | msp_wake_thread(client); | ||
2099 | return 0; | ||
2100 | } | ||
2101 | |||
2102 | /* ----------------------------------------------------------------------- */ | ||
2103 | |||
2104 | static struct i2c_driver i2c_driver; | ||
2105 | |||
2106 | static int msp_attach(struct i2c_adapter *adapter, int address, int kind) | ||
2107 | { | ||
2108 | struct i2c_client *client; | ||
2109 | struct msp_state *state; | ||
2110 | int (*thread_func)(void *data) = NULL; | ||
2111 | int i; | ||
2112 | |||
2113 | client = kmalloc(sizeof(*client), GFP_KERNEL); | ||
2114 | if (client == NULL) | ||
2115 | return -ENOMEM; | ||
2116 | memset(client, 0, sizeof(*client)); | ||
2117 | client->addr = address; | ||
2118 | client->adapter = adapter; | ||
2119 | client->driver = &i2c_driver; | ||
2120 | client->flags = I2C_CLIENT_ALLOW_USE; | ||
2121 | snprintf(client->name, sizeof(client->name) - 1, "msp3400"); | ||
2122 | |||
2123 | if (msp_reset(client) == -1) { | ||
2124 | msp_dbg1("msp3400 not found\n"); | ||
2125 | kfree(client); | ||
2126 | return -1; | ||
2127 | } | ||
2128 | |||
2129 | state = kmalloc(sizeof(*state), GFP_KERNEL); | ||
2130 | if (state == NULL) { | ||
2131 | kfree(client); | ||
2132 | return -ENOMEM; | ||
2133 | } | ||
2134 | i2c_set_clientdata(client, state); | ||
2135 | |||
2136 | memset(state, 0, sizeof(*state)); | ||
2137 | state->norm = VIDEO_MODE_NTSC; | ||
2138 | state->volume = 58880; /* 0db gain */ | ||
2139 | state->balance = 32768; /* 0db gain */ | ||
2140 | state->bass = 32768; | ||
2141 | state->treble = 32768; | ||
2142 | state->input = -1; | ||
2143 | state->muted = 0; | ||
2144 | state->i2s_mode = 0; | ||
2145 | for (i = 0; i < DFP_COUNT; i++) | ||
2146 | state->dfp_regs[i] = -1; | ||
2147 | init_waitqueue_head(&state->wq); | ||
2148 | |||
2149 | state->rev1 = msp_read_dsp(client, 0x1e); | ||
2150 | if (state->rev1 != -1) | ||
2151 | state->rev2 = msp_read_dsp(client, 0x1f); | ||
2152 | msp_dbg1("rev1=0x%04x, rev2=0x%04x\n", state->rev1, state->rev2); | ||
2153 | if (state->rev1 == -1 || (state->rev1 == 0 && state->rev2 == 0)) { | ||
2154 | msp_dbg1("error while reading chip version\n"); | ||
2155 | kfree(state); | ||
2156 | kfree(client); | ||
2157 | return -1; | ||
2158 | } | ||
2159 | |||
2160 | msp_set_audio(client); | ||
2161 | |||
2162 | snprintf(client->name, sizeof(client->name), "MSP%c4%02d%c-%c%d", | ||
2163 | ((state->rev1 >> 4) & 0x0f) + '3', | ||
2164 | (state->rev2 >> 8) & 0xff, | ||
2165 | (state->rev1 & 0x0f) + '@', | ||
2166 | ((state->rev1 >> 8) & 0xff) + '@', | ||
2167 | state->rev2 & 0x1f); | ||
2168 | |||
2169 | state->opmode = opmode; | ||
2170 | if (state->opmode == OPMODE_AUTO) { | ||
2171 | /* MSP revision G and up have both autodetect and autoselect */ | ||
2172 | if ((state->rev1 & 0x0f) >= 'G'-'@') | ||
2173 | state->opmode = OPMODE_AUTOSELECT; | ||
2174 | /* MSP revision D and up have autodetect */ | ||
2175 | else if ((state->rev1 & 0x0f) >= 'D'-'@') | ||
2176 | state->opmode = OPMODE_AUTODETECT; | ||
2177 | else | ||
2178 | state->opmode = OPMODE_MANUAL; | ||
2179 | } | ||
2180 | |||
2181 | /* hello world :-) */ | ||
2182 | msp_info("%s found @ 0x%x (%s)\n", client->name, address << 1, adapter->name); | ||
2183 | msp_info("%s ", client->name); | ||
2184 | if (HAVE_NICAM(state) && HAVE_RADIO(state)) | ||
2185 | printk("supports nicam and radio, "); | ||
2186 | else if (HAVE_NICAM(state)) | ||
2187 | printk("supports nicam, "); | ||
2188 | else if (HAVE_RADIO(state)) | ||
2189 | printk("supports radio, "); | ||
2190 | printk("mode is "); | ||
2191 | |||
2192 | /* version-specific initialization */ | ||
2193 | switch (state->opmode) { | ||
2194 | case OPMODE_MANUAL: | ||
2195 | printk("manual"); | ||
2196 | thread_func = msp3400c_thread; | ||
2197 | break; | ||
2198 | case OPMODE_AUTODETECT: | ||
2199 | printk("autodetect"); | ||
2200 | thread_func = msp3410d_thread; | ||
2201 | break; | ||
2202 | case OPMODE_AUTOSELECT: | ||
2203 | printk("autodetect and autoselect"); | ||
2204 | thread_func = msp34xxg_thread; | ||
2205 | break; | ||
2206 | } | ||
2207 | printk("\n"); | ||
2208 | |||
2209 | /* startup control thread if needed */ | ||
2210 | if (thread_func) { | ||
2211 | state->kthread = kthread_run(thread_func, client, "msp34xx"); | ||
2212 | |||
2213 | if (state->kthread == NULL) | ||
2214 | msp_warn("kernel_thread() failed\n"); | ||
2215 | msp_wake_thread(client); | ||
2216 | } | ||
2217 | |||
2218 | /* done */ | ||
2219 | i2c_attach_client(client); | ||
2220 | |||
2221 | return 0; | ||
2222 | } | ||
2223 | |||
2224 | static int msp_probe(struct i2c_adapter *adapter) | ||
2225 | { | ||
2226 | if (adapter->class & I2C_CLASS_TV_ANALOG) | ||
2227 | return i2c_probe(adapter, &addr_data, msp_attach); | ||
2228 | return 0; | ||
2229 | } | ||
2230 | |||
2231 | static int msp_detach(struct i2c_client *client) | ||
2232 | { | ||
2233 | struct msp_state *state = i2c_get_clientdata(client); | ||
2234 | int err; | ||
2235 | |||
2236 | /* shutdown control thread */ | ||
2237 | if (state->kthread) { | ||
2238 | state->restart = 1; | ||
2239 | kthread_stop(state->kthread); | ||
2240 | } | ||
2241 | msp_reset(client); | ||
2242 | |||
2243 | err = i2c_detach_client(client); | ||
2244 | if (err) { | ||
2245 | return err; | ||
2246 | } | ||
2247 | |||
2248 | kfree(state); | ||
2249 | kfree(client); | ||
2250 | return 0; | ||
2251 | } | ||
2252 | |||
2253 | /* ----------------------------------------------------------------------- */ | ||
2254 | |||
2255 | /* i2c implementation */ | ||
2256 | static struct i2c_driver i2c_driver = { | ||
2257 | .name = "msp3400", | ||
2258 | .id = I2C_DRIVERID_MSP3400, | ||
2259 | .flags = I2C_DF_NOTIFY, | ||
2260 | .attach_adapter = msp_probe, | ||
2261 | .detach_client = msp_detach, | ||
2262 | .command = msp_command, | ||
2263 | .driver = { | ||
2264 | .suspend = msp_suspend, | ||
2265 | .resume = msp_resume, | ||
2266 | }, | ||
2267 | .owner = THIS_MODULE, | ||
2268 | }; | ||
2269 | |||
2270 | static int __init msp3400_init_module(void) | ||
2271 | { | ||
2272 | return i2c_add_driver(&i2c_driver); | ||
2273 | } | ||
2274 | |||
2275 | static void __exit msp3400_cleanup_module(void) | ||
2276 | { | ||
2277 | i2c_del_driver(&i2c_driver); | ||
2278 | } | ||
2279 | |||
2280 | module_init(msp3400_init_module); | ||
2281 | module_exit(msp3400_cleanup_module); | ||
2282 | |||
2283 | /* | ||
2284 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
2285 | * --------------------------------------------------------------------------- | ||
2286 | * Local variables: | ||
2287 | * c-basic-offset: 8 | ||
2288 | * End: | ||
2289 | */ | ||
diff --git a/drivers/media/video/msp3400.h b/drivers/media/video/msp3400.h index 2d9ff40f0b09..33d64ac75d37 100644 --- a/drivers/media/video/msp3400.h +++ b/drivers/media/video/msp3400.h | |||
@@ -6,22 +6,62 @@ | |||
6 | 6 | ||
7 | /* ---------------------------------------------------------------------- */ | 7 | /* ---------------------------------------------------------------------- */ |
8 | 8 | ||
9 | struct msp_dfpreg { | 9 | #define msp_err(fmt, arg...) \ |
10 | int reg; | 10 | printk(KERN_ERR "%s %d-%04x: " fmt, client->driver->driver.name, \ |
11 | int value; | 11 | i2c_adapter_id(client->adapter), client->addr , ## arg) |
12 | }; | 12 | #define msp_warn(fmt, arg...) \ |
13 | printk(KERN_WARNING "%s %d-%04x: " fmt, client->driver->driver.name, \ | ||
14 | i2c_adapter_id(client->adapter), client->addr , ## arg) | ||
15 | #define msp_info(fmt, arg...) \ | ||
16 | printk(KERN_INFO "%s %d-%04x: " fmt, client->driver->driver.name, \ | ||
17 | i2c_adapter_id(client->adapter), client->addr , ## arg) | ||
18 | |||
19 | /* level 1 debug. */ | ||
20 | #define msp_dbg1(fmt, arg...) \ | ||
21 | do { \ | ||
22 | if (debug) \ | ||
23 | printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->driver.name, \ | ||
24 | i2c_adapter_id(client->adapter), client->addr , ## arg); \ | ||
25 | } while (0) | ||
26 | |||
27 | /* level 2 debug. */ | ||
28 | #define msp_dbg2(fmt, arg...) \ | ||
29 | do { \ | ||
30 | if (debug >= 2) \ | ||
31 | printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \ | ||
32 | i2c_adapter_id(client->adapter), client->addr , ## arg); \ | ||
33 | } while (0) | ||
34 | |||
35 | /* level 3 debug. Use with care. */ | ||
36 | #define msp_dbg3(fmt, arg...) \ | ||
37 | do { \ | ||
38 | if (debug >= 16) \ | ||
39 | printk(KERN_INFO "%s debug %d-%04x: " fmt, client->driver->name, \ | ||
40 | i2c_adapter_id(client->adapter), client->addr , ## arg); \ | ||
41 | } while (0) | ||
13 | 42 | ||
14 | struct msp_matrix { | 43 | struct msp_matrix { |
15 | int input; | 44 | int input; |
16 | int output; | 45 | int output; |
17 | }; | 46 | }; |
18 | 47 | ||
19 | #define MSP_SET_DFPREG _IOW('m',15,struct msp_dfpreg) | ||
20 | #define MSP_GET_DFPREG _IOW('m',16,struct msp_dfpreg) | ||
21 | |||
22 | /* ioctl for MSP_SET_MATRIX will have to be registered */ | 48 | /* ioctl for MSP_SET_MATRIX will have to be registered */ |
23 | #define MSP_SET_MATRIX _IOW('m',17,struct msp_matrix) | 49 | #define MSP_SET_MATRIX _IOW('m',17,struct msp_matrix) |
24 | 50 | ||
51 | /* This macro is allowed for *constants* only, gcc must calculate it | ||
52 | at compile time. Remember -- no floats in kernel mode */ | ||
53 | #define MSP_CARRIER(freq) ((int)((float)(freq / 18.432) * (1 << 24))) | ||
54 | |||
55 | #define MSP_MODE_AM_DETECT 0 | ||
56 | #define MSP_MODE_FM_RADIO 2 | ||
57 | #define MSP_MODE_FM_TERRA 3 | ||
58 | #define MSP_MODE_FM_SAT 4 | ||
59 | #define MSP_MODE_FM_NICAM1 5 | ||
60 | #define MSP_MODE_FM_NICAM2 6 | ||
61 | #define MSP_MODE_AM_NICAM 7 | ||
62 | #define MSP_MODE_BTSC 8 | ||
63 | #define MSP_MODE_EXTERN 9 | ||
64 | |||
25 | #define SCART_MASK 0 | 65 | #define SCART_MASK 0 |
26 | #define SCART_IN1 1 | 66 | #define SCART_IN1 1 |
27 | #define SCART_IN2 2 | 67 | #define SCART_IN2 2 |
@@ -36,4 +76,77 @@ struct msp_matrix { | |||
36 | #define SCART1_OUT 1 | 76 | #define SCART1_OUT 1 |
37 | #define SCART2_OUT 2 | 77 | #define SCART2_OUT 2 |
38 | 78 | ||
79 | #define OPMODE_AUTO -1 | ||
80 | #define OPMODE_MANUAL 0 | ||
81 | #define OPMODE_AUTODETECT 1 /* use autodetect (>= msp3410 only) */ | ||
82 | #define OPMODE_AUTOSELECT 2 /* use autodetect & autoselect (>= msp34xxG) */ | ||
83 | |||
84 | /* module parameters */ | ||
85 | extern int debug; | ||
86 | extern int once; | ||
87 | extern int amsound; | ||
88 | extern int standard; | ||
89 | extern int dolby; | ||
90 | extern int stereo_threshold; | ||
91 | |||
92 | struct msp_state { | ||
93 | int rev1, rev2; | ||
94 | |||
95 | int opmode; | ||
96 | int mode; | ||
97 | int norm; | ||
98 | int stereo; | ||
99 | int nicam_on; | ||
100 | int acb; | ||
101 | int in_scart; | ||
102 | int i2s_mode; | ||
103 | int main, second; /* sound carrier */ | ||
104 | int input; | ||
105 | int source; /* see msp34xxg_set_source */ | ||
106 | |||
107 | /* v4l2 */ | ||
108 | int audmode; | ||
109 | int rxsubchans; | ||
110 | |||
111 | int muted; | ||
112 | int volume, balance; | ||
113 | int bass, treble; | ||
114 | |||
115 | /* thread */ | ||
116 | struct task_struct *kthread; | ||
117 | wait_queue_head_t wq; | ||
118 | int restart:1; | ||
119 | int watch_stereo:1; | ||
120 | }; | ||
121 | |||
122 | #define VIDEO_MODE_RADIO 16 /* norm magic for radio mode */ | ||
123 | |||
124 | #define HAVE_NICAM(state) (((state->rev2 >> 8) & 0xff) != 0) | ||
125 | #define HAVE_RADIO(state) ((state->rev1 & 0x0f) >= 'G'-'@') | ||
126 | |||
127 | /* msp3400-driver.c */ | ||
128 | int msp_write_dem(struct i2c_client *client, int addr, int val); | ||
129 | int msp_write_dsp(struct i2c_client *client, int addr, int val); | ||
130 | int msp_read_dem(struct i2c_client *client, int addr); | ||
131 | int msp_read_dsp(struct i2c_client *client, int addr); | ||
132 | int msp_reset(struct i2c_client *client); | ||
133 | void msp_set_scart(struct i2c_client *client, int in, int out); | ||
134 | void msp_set_mute(struct i2c_client *client); | ||
135 | void msp_set_audio(struct i2c_client *client); | ||
136 | int msp_modus(struct i2c_client *client, int norm); | ||
137 | int msp_standard(int norm); | ||
138 | int msp_sleep(struct msp_state *state, int timeout); | ||
139 | |||
140 | /* msp3400-kthreads.c */ | ||
141 | const char *msp_standard_mode_name(int mode); | ||
142 | void msp3400c_setcarrier(struct i2c_client *client, int cdo1, int cdo2); | ||
143 | void msp3400c_setmode(struct i2c_client *client, int type); | ||
144 | void msp3400c_setstereo(struct i2c_client *client, int mode); | ||
145 | int autodetect_stereo(struct i2c_client *client); | ||
146 | int msp3400c_thread(void *data); | ||
147 | int msp3410d_thread(void *data); | ||
148 | int msp34xxg_thread(void *data); | ||
149 | void msp34xxg_detect_stereo(struct i2c_client *client); | ||
150 | void msp34xxg_set_audmode(struct i2c_client *client, int audmode); | ||
151 | |||
39 | #endif /* MSP3400_H */ | 152 | #endif /* MSP3400_H */ |