diff options
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/video/cx88/Makefile | 2 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-core.c | 26 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-dsp.c | 299 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88-tvaudio.c | 54 | ||||
-rw-r--r-- | drivers/media/video/cx88/cx88.h | 10 |
5 files changed, 381 insertions, 10 deletions
diff --git a/drivers/media/video/cx88/Makefile b/drivers/media/video/cx88/Makefile index b06b1275a9ec..5b7e26761f0a 100644 --- a/drivers/media/video/cx88/Makefile +++ b/drivers/media/video/cx88/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | cx88xx-objs := cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o \ | 1 | cx88xx-objs := cx88-cards.o cx88-core.o cx88-i2c.o cx88-tvaudio.o \ |
2 | cx88-input.o | 2 | cx88-dsp.o cx88-input.o |
3 | cx8800-objs := cx88-video.o cx88-vbi.o | 3 | cx8800-objs := cx88-video.o cx88-vbi.o |
4 | cx8802-objs := cx88-mpeg.o | 4 | cx8802-objs := cx88-mpeg.o |
5 | 5 | ||
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c index b4049de071a2..cf634606ba9a 100644 --- a/drivers/media/video/cx88/cx88-core.c +++ b/drivers/media/video/cx88/cx88-core.c | |||
@@ -231,7 +231,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf) | |||
231 | * can use the whole SDRAM for the DMA fifos. To simplify things, we | 231 | * can use the whole SDRAM for the DMA fifos. To simplify things, we |
232 | * use a static memory layout. That surely will waste memory in case | 232 | * use a static memory layout. That surely will waste memory in case |
233 | * we don't use all DMA channels at the same time (which will be the | 233 | * we don't use all DMA channels at the same time (which will be the |
234 | * case most of the time). But that still gives us enougth FIFO space | 234 | * case most of the time). But that still gives us enough FIFO space |
235 | * to be able to deal with insane long pci latencies ... | 235 | * to be able to deal with insane long pci latencies ... |
236 | * | 236 | * |
237 | * FIFO space allocations: | 237 | * FIFO space allocations: |
@@ -241,6 +241,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf) | |||
241 | * channel 24 (vbi) - 4.0k | 241 | * channel 24 (vbi) - 4.0k |
242 | * channels 25+26 (audio) - 4.0k | 242 | * channels 25+26 (audio) - 4.0k |
243 | * channel 28 (mpeg) - 4.0k | 243 | * channel 28 (mpeg) - 4.0k |
244 | * channel 27 (audio rds)- 3.0k | ||
244 | * TOTAL = 29.0k | 245 | * TOTAL = 29.0k |
245 | * | 246 | * |
246 | * Every channel has 160 bytes control data (64 bytes instruction | 247 | * Every channel has 160 bytes control data (64 bytes instruction |
@@ -337,6 +338,18 @@ struct sram_channel cx88_sram_channels[] = { | |||
337 | .cnt1_reg = MO_DMA28_CNT1, | 338 | .cnt1_reg = MO_DMA28_CNT1, |
338 | .cnt2_reg = MO_DMA28_CNT2, | 339 | .cnt2_reg = MO_DMA28_CNT2, |
339 | }, | 340 | }, |
341 | [SRAM_CH27] = { | ||
342 | .name = "audio rds", | ||
343 | .cmds_start = 0x1801C0, | ||
344 | .ctrl_start = 0x180860, | ||
345 | .cdt = 0x180860 + 64, | ||
346 | .fifo_start = 0x187400, | ||
347 | .fifo_size = 0x000C00, | ||
348 | .ptr1_reg = MO_DMA27_PTR1, | ||
349 | .ptr2_reg = MO_DMA27_PTR2, | ||
350 | .cnt1_reg = MO_DMA27_CNT1, | ||
351 | .cnt2_reg = MO_DMA27_CNT2, | ||
352 | }, | ||
340 | }; | 353 | }; |
341 | 354 | ||
342 | int cx88_sram_channel_setup(struct cx88_core *core, | 355 | int cx88_sram_channel_setup(struct cx88_core *core, |
@@ -598,6 +611,7 @@ int cx88_reset(struct cx88_core *core) | |||
598 | cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0); | 611 | cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], 128, 0); |
599 | cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0); | 612 | cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], 128, 0); |
600 | cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], 188*4, 0); | 613 | cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28], 188*4, 0); |
614 | cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH27], 128, 0); | ||
601 | 615 | ||
602 | /* misc init ... */ | 616 | /* misc init ... */ |
603 | cx_write(MO_INPUT_FORMAT, ((1 << 13) | // agc enable | 617 | cx_write(MO_INPUT_FORMAT, ((1 << 13) | // agc enable |
@@ -796,6 +810,8 @@ int cx88_start_audio_dma(struct cx88_core *core) | |||
796 | /* constant 128 made buzz in analog Nicam-stereo for bigger fifo_size */ | 810 | /* constant 128 made buzz in analog Nicam-stereo for bigger fifo_size */ |
797 | int bpl = cx88_sram_channels[SRAM_CH25].fifo_size/4; | 811 | int bpl = cx88_sram_channels[SRAM_CH25].fifo_size/4; |
798 | 812 | ||
813 | int rds_bpl = cx88_sram_channels[SRAM_CH27].fifo_size/AUD_RDS_LINES; | ||
814 | |||
799 | /* If downstream RISC is enabled, bail out; ALSA is managing DMA */ | 815 | /* If downstream RISC is enabled, bail out; ALSA is managing DMA */ |
800 | if (cx_read(MO_AUD_DMACNTRL) & 0x10) | 816 | if (cx_read(MO_AUD_DMACNTRL) & 0x10) |
801 | return 0; | 817 | return 0; |
@@ -803,12 +819,14 @@ int cx88_start_audio_dma(struct cx88_core *core) | |||
803 | /* setup fifo + format */ | 819 | /* setup fifo + format */ |
804 | cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], bpl, 0); | 820 | cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH25], bpl, 0); |
805 | cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], bpl, 0); | 821 | cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH26], bpl, 0); |
822 | cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH27], | ||
823 | rds_bpl, 0); | ||
806 | 824 | ||
807 | cx_write(MO_AUDD_LNGTH, bpl); /* fifo bpl size */ | 825 | cx_write(MO_AUDD_LNGTH, bpl); /* fifo bpl size */ |
808 | cx_write(MO_AUDR_LNGTH, bpl); /* fifo bpl size */ | 826 | cx_write(MO_AUDR_LNGTH, rds_bpl); /* fifo bpl size */ |
809 | 827 | ||
810 | /* start dma */ | 828 | /* enable Up, Down and Audio RDS fifo */ |
811 | cx_write(MO_AUD_DMACNTRL, 0x0003); /* Up and Down fifo enable */ | 829 | cx_write(MO_AUD_DMACNTRL, 0x0007); |
812 | 830 | ||
813 | return 0; | 831 | return 0; |
814 | } | 832 | } |
diff --git a/drivers/media/video/cx88/cx88-dsp.c b/drivers/media/video/cx88/cx88-dsp.c new file mode 100644 index 000000000000..a78286e853c3 --- /dev/null +++ b/drivers/media/video/cx88/cx88-dsp.c | |||
@@ -0,0 +1,299 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Stereo and SAP detection for cx88 | ||
4 | * | ||
5 | * Copyright (c) 2009 Marton Balint <cus@fazekas.hu> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License as published by | ||
9 | * the Free Software Foundation; either version 2 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU General Public License | ||
18 | * along with this program; if not, write to the Free Software | ||
19 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
20 | */ | ||
21 | |||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/module.h> | ||
24 | #include <linux/jiffies.h> | ||
25 | |||
26 | #include "cx88.h" | ||
27 | #include "cx88-reg.h" | ||
28 | |||
29 | #define INT_PI ((s32)(3.141592653589 * 32768.0)) | ||
30 | |||
31 | #define compat_remainder(a, b) \ | ||
32 | ((float)(((s32)((a)*100))%((s32)((b)*100)))/100.0) | ||
33 | |||
34 | #define baseband_freq(carrier, srate, tone) ((s32)( \ | ||
35 | (compat_remainder(carrier + tone, srate)) / srate * 2 * INT_PI)) | ||
36 | |||
37 | /* We calculate the baseband frequencies of the carrier and the pilot tones | ||
38 | * based on the the sampling rate of the audio rds fifo. */ | ||
39 | |||
40 | #define FREQ_A2_CARRIER baseband_freq(54687.5, 2689.36, 0.0) | ||
41 | #define FREQ_A2_DUAL baseband_freq(54687.5, 2689.36, 274.1) | ||
42 | #define FREQ_A2_STEREO baseband_freq(54687.5, 2689.36, 117.5) | ||
43 | |||
44 | /* The frequencies below are from the reference driver. They probably need | ||
45 | * further adjustments, because they are not tested at all. You may even need | ||
46 | * to play a bit with the registers of the chip to select the proper signal | ||
47 | * for the input of the audio rds fifo, and measure it's sampling rate to | ||
48 | * calculate the proper baseband frequencies... */ | ||
49 | |||
50 | #define FREQ_A2M_CARRIER ((s32)(2.114516 * 32768.0)) | ||
51 | #define FREQ_A2M_DUAL ((s32)(2.754916 * 32768.0)) | ||
52 | #define FREQ_A2M_STEREO ((s32)(2.462326 * 32768.0)) | ||
53 | |||
54 | #define FREQ_EIAJ_CARRIER ((s32)(1.963495 * 32768.0)) /* 5pi/8 */ | ||
55 | #define FREQ_EIAJ_DUAL ((s32)(2.562118 * 32768.0)) | ||
56 | #define FREQ_EIAJ_STEREO ((s32)(2.601053 * 32768.0)) | ||
57 | |||
58 | #define FREQ_BTSC_DUAL ((s32)(1.963495 * 32768.0)) /* 5pi/8 */ | ||
59 | #define FREQ_BTSC_DUAL_REF ((s32)(1.374446 * 32768.0)) /* 7pi/16 */ | ||
60 | |||
61 | #define FREQ_BTSC_SAP ((s32)(2.471532 * 32768.0)) | ||
62 | #define FREQ_BTSC_SAP_REF ((s32)(1.730072 * 32768.0)) | ||
63 | |||
64 | /* The spectrum of the signal should be empty between these frequencies. */ | ||
65 | #define FREQ_NOISE_START ((s32)(0.100000 * 32768.0)) | ||
66 | #define FREQ_NOISE_END ((s32)(1.200000 * 32768.0)) | ||
67 | |||
68 | static unsigned int dsp_debug; | ||
69 | module_param(dsp_debug, int, 0644); | ||
70 | MODULE_PARM_DESC(dsp_debug, "enable audio dsp debug messages"); | ||
71 | |||
72 | #define dprintk(level, fmt, arg...) if (dsp_debug >= level) \ | ||
73 | printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg) | ||
74 | |||
75 | static s32 int_cos(u32 x) | ||
76 | { | ||
77 | u32 t2, t4, t6, t8; | ||
78 | s32 ret; | ||
79 | u16 period = x / INT_PI; | ||
80 | if (period % 2) | ||
81 | return -int_cos(x - INT_PI); | ||
82 | x = x % INT_PI; | ||
83 | if (x > INT_PI/2) | ||
84 | return -int_cos(INT_PI/2 - (x % (INT_PI/2))); | ||
85 | /* Now x is between 0 and INT_PI/2. | ||
86 | * To calculate cos(x) we use it's Taylor polinom. */ | ||
87 | t2 = x*x/32768/2; | ||
88 | t4 = t2*x/32768*x/32768/3/4; | ||
89 | t6 = t4*x/32768*x/32768/5/6; | ||
90 | t8 = t6*x/32768*x/32768/7/8; | ||
91 | ret = 32768-t2+t4-t6+t8; | ||
92 | return ret; | ||
93 | } | ||
94 | |||
95 | static u32 int_goertzel(s16 x[], u32 N, u32 freq) | ||
96 | { | ||
97 | /* We use the Goertzel algorithm to determine the power of the | ||
98 | * given frequency in the signal */ | ||
99 | s32 s_prev = 0; | ||
100 | s32 s_prev2 = 0; | ||
101 | s32 coeff = 2*int_cos(freq); | ||
102 | u32 i; | ||
103 | for (i = 0; i < N; i++) { | ||
104 | s32 s = x[i] + ((s64)coeff*s_prev/32768) - s_prev2; | ||
105 | s_prev2 = s_prev; | ||
106 | s_prev = s; | ||
107 | } | ||
108 | return (u32)(((s64)s_prev2*s_prev2 + (s64)s_prev*s_prev - | ||
109 | (s64)coeff*s_prev2*s_prev/32768)/N/N); | ||
110 | } | ||
111 | |||
112 | static u32 freq_magnitude(s16 x[], u32 N, u32 freq) | ||
113 | { | ||
114 | u32 sum = int_goertzel(x, N, freq); | ||
115 | return (u32)int_sqrt(sum); | ||
116 | } | ||
117 | |||
118 | static u32 noise_magnitude(s16 x[], u32 N, u32 freq_start, u32 freq_end) | ||
119 | { | ||
120 | int i; | ||
121 | u32 sum = 0; | ||
122 | u32 freq_step; | ||
123 | int samples = 5; | ||
124 | |||
125 | if (N > 192) { | ||
126 | /* The last 192 samples are enough for noise detection */ | ||
127 | x += (N-192); | ||
128 | N = 192; | ||
129 | } | ||
130 | |||
131 | freq_step = (freq_end - freq_start) / (samples - 1); | ||
132 | |||
133 | for (i = 0; i < samples; i++) { | ||
134 | sum += int_goertzel(x, N, freq_start); | ||
135 | freq_start += freq_step; | ||
136 | } | ||
137 | |||
138 | return (u32)int_sqrt(sum / samples); | ||
139 | } | ||
140 | |||
141 | static s32 detect_a2_a2m_eiaj(struct cx88_core *core, s16 x[], u32 N) | ||
142 | { | ||
143 | s32 carrier, stereo, dual, noise; | ||
144 | s32 carrier_freq, stereo_freq, dual_freq; | ||
145 | s32 ret; | ||
146 | |||
147 | switch (core->tvaudio) { | ||
148 | case WW_BG: | ||
149 | case WW_DK: | ||
150 | carrier_freq = FREQ_A2_CARRIER; | ||
151 | stereo_freq = FREQ_A2_STEREO; | ||
152 | dual_freq = FREQ_A2_DUAL; | ||
153 | break; | ||
154 | case WW_M: | ||
155 | carrier_freq = FREQ_A2M_CARRIER; | ||
156 | stereo_freq = FREQ_A2M_STEREO; | ||
157 | dual_freq = FREQ_A2M_DUAL; | ||
158 | break; | ||
159 | case WW_EIAJ: | ||
160 | carrier_freq = FREQ_EIAJ_CARRIER; | ||
161 | stereo_freq = FREQ_EIAJ_STEREO; | ||
162 | dual_freq = FREQ_EIAJ_DUAL; | ||
163 | break; | ||
164 | default: | ||
165 | printk(KERN_WARNING "%s/0: unsupported audio mode %d for %s\n", | ||
166 | core->name, core->tvaudio, __func__); | ||
167 | return UNSET; | ||
168 | } | ||
169 | |||
170 | carrier = freq_magnitude(x, N, carrier_freq); | ||
171 | stereo = freq_magnitude(x, N, stereo_freq); | ||
172 | dual = freq_magnitude(x, N, dual_freq); | ||
173 | noise = noise_magnitude(x, N, FREQ_NOISE_START, FREQ_NOISE_END); | ||
174 | |||
175 | dprintk(1, "detect a2/a2m/eiaj: carrier=%d, stereo=%d, dual=%d, " | ||
176 | "noise=%d\n", carrier, stereo, dual, noise); | ||
177 | |||
178 | if (stereo > dual) | ||
179 | ret = V4L2_TUNER_SUB_STEREO; | ||
180 | else | ||
181 | ret = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2; | ||
182 | |||
183 | if (core->tvaudio == WW_EIAJ) { | ||
184 | /* EIAJ checks may need adjustments */ | ||
185 | if ((carrier > max(stereo, dual)*2) && | ||
186 | (carrier < max(stereo, dual)*6) && | ||
187 | (carrier > 20 && carrier < 200) && | ||
188 | (max(stereo, dual) > min(stereo, dual))) { | ||
189 | /* For EIAJ the carrier is always present, | ||
190 | so we probably don't need noise detection */ | ||
191 | return ret; | ||
192 | } | ||
193 | } else { | ||
194 | if ((carrier > max(stereo, dual)*2) && | ||
195 | (carrier < max(stereo, dual)*8) && | ||
196 | (carrier > 20 && carrier < 200) && | ||
197 | (noise < 10) && | ||
198 | (max(stereo, dual) > min(stereo, dual)*2)) { | ||
199 | return ret; | ||
200 | } | ||
201 | } | ||
202 | return V4L2_TUNER_SUB_MONO; | ||
203 | } | ||
204 | |||
205 | static s32 detect_btsc(struct cx88_core *core, s16 x[], u32 N) | ||
206 | { | ||
207 | s32 sap_ref = freq_magnitude(x, N, FREQ_BTSC_SAP_REF); | ||
208 | s32 sap = freq_magnitude(x, N, FREQ_BTSC_SAP); | ||
209 | s32 dual_ref = freq_magnitude(x, N, FREQ_BTSC_DUAL_REF); | ||
210 | s32 dual = freq_magnitude(x, N, FREQ_BTSC_DUAL); | ||
211 | dprintk(1, "detect btsc: dual_ref=%d, dual=%d, sap_ref=%d, sap=%d" | ||
212 | "\n", dual_ref, dual, sap_ref, sap); | ||
213 | /* FIXME: Currently not supported */ | ||
214 | return UNSET; | ||
215 | } | ||
216 | |||
217 | static s16 *read_rds_samples(struct cx88_core *core, u32 *N) | ||
218 | { | ||
219 | struct sram_channel *srch = &cx88_sram_channels[SRAM_CH27]; | ||
220 | s16 *samples; | ||
221 | |||
222 | unsigned int i; | ||
223 | unsigned int bpl = srch->fifo_size/AUD_RDS_LINES; | ||
224 | unsigned int spl = bpl/4; | ||
225 | unsigned int sample_count = spl*(AUD_RDS_LINES-1); | ||
226 | |||
227 | u32 current_address = cx_read(srch->ptr1_reg); | ||
228 | u32 offset = (current_address - srch->fifo_start + bpl); | ||
229 | |||
230 | dprintk(1, "read RDS samples: current_address=%08x (offset=%08x), " | ||
231 | "sample_count=%d, aud_intstat=%08x\n", current_address, | ||
232 | current_address - srch->fifo_start, sample_count, | ||
233 | cx_read(MO_AUD_INTSTAT)); | ||
234 | |||
235 | samples = kmalloc(sizeof(s16)*sample_count, GFP_KERNEL); | ||
236 | if (!samples) | ||
237 | return NULL; | ||
238 | |||
239 | *N = sample_count; | ||
240 | |||
241 | for (i = 0; i < sample_count; i++) { | ||
242 | offset = offset % (AUD_RDS_LINES*bpl); | ||
243 | samples[i] = cx_read(srch->fifo_start + offset); | ||
244 | offset += 4; | ||
245 | } | ||
246 | |||
247 | if (dsp_debug >= 2) { | ||
248 | dprintk(2, "RDS samples dump: "); | ||
249 | for (i = 0; i < sample_count; i++) | ||
250 | printk("%hd ", samples[i]); | ||
251 | printk(".\n"); | ||
252 | } | ||
253 | |||
254 | return samples; | ||
255 | } | ||
256 | |||
257 | s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core) | ||
258 | { | ||
259 | s16 *samples; | ||
260 | u32 N = 0; | ||
261 | s32 ret = UNSET; | ||
262 | |||
263 | /* If audio RDS fifo is disabled, we can't read the samples */ | ||
264 | if (!(cx_read(MO_AUD_DMACNTRL) & 0x04)) | ||
265 | return ret; | ||
266 | if (!(cx_read(AUD_CTL) & EN_FMRADIO_EN_RDS)) | ||
267 | return ret; | ||
268 | |||
269 | /* Wait at least 500 ms after an audio standard change */ | ||
270 | if (time_before(jiffies, core->last_change + msecs_to_jiffies(500))) | ||
271 | return ret; | ||
272 | |||
273 | samples = read_rds_samples(core, &N); | ||
274 | |||
275 | if (!samples) | ||
276 | return ret; | ||
277 | |||
278 | switch (core->tvaudio) { | ||
279 | case WW_BG: | ||
280 | case WW_DK: | ||
281 | ret = detect_a2_a2m_eiaj(core, samples, N); | ||
282 | break; | ||
283 | case WW_BTSC: | ||
284 | ret = detect_btsc(core, samples, N); | ||
285 | break; | ||
286 | } | ||
287 | |||
288 | kfree(samples); | ||
289 | |||
290 | if (UNSET != ret) | ||
291 | dprintk(1, "stereo/sap detection result:%s%s%s\n", | ||
292 | (ret & V4L2_TUNER_SUB_MONO) ? " mono" : "", | ||
293 | (ret & V4L2_TUNER_SUB_STEREO) ? " stereo" : "", | ||
294 | (ret & V4L2_TUNER_SUB_LANG2) ? " dual" : ""); | ||
295 | |||
296 | return ret; | ||
297 | } | ||
298 | EXPORT_SYMBOL(cx88_dsp_detect_stereo_sap); | ||
299 | |||
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c index 7dd506b987fe..f9501eb8557c 100644 --- a/drivers/media/video/cx88/cx88-tvaudio.c +++ b/drivers/media/video/cx88/cx88-tvaudio.c | |||
@@ -163,6 +163,8 @@ static void set_audio_finish(struct cx88_core *core, u32 ctl) | |||
163 | /* unmute */ | 163 | /* unmute */ |
164 | volume = cx_sread(SHADOW_AUD_VOL_CTL); | 164 | volume = cx_sread(SHADOW_AUD_VOL_CTL); |
165 | cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, volume); | 165 | cx_swrite(SHADOW_AUD_VOL_CTL, AUD_VOL_CTL, volume); |
166 | |||
167 | core->last_change = jiffies; | ||
166 | } | 168 | } |
167 | 169 | ||
168 | /* ----------------------------------------------------------- */ | 170 | /* ----------------------------------------------------------- */ |
@@ -745,6 +747,7 @@ void cx88_set_tvaudio(struct cx88_core *core) | |||
745 | break; | 747 | break; |
746 | case WW_BG: | 748 | case WW_BG: |
747 | case WW_DK: | 749 | case WW_DK: |
750 | case WW_M: | ||
748 | case WW_I: | 751 | case WW_I: |
749 | case WW_L: | 752 | case WW_L: |
750 | /* prepare all dsp registers */ | 753 | /* prepare all dsp registers */ |
@@ -756,6 +759,7 @@ void cx88_set_tvaudio(struct cx88_core *core) | |||
756 | if (0 == cx88_detect_nicam(core)) { | 759 | if (0 == cx88_detect_nicam(core)) { |
757 | /* fall back to fm / am mono */ | 760 | /* fall back to fm / am mono */ |
758 | set_audio_standard_A2(core, EN_A2_FORCE_MONO1); | 761 | set_audio_standard_A2(core, EN_A2_FORCE_MONO1); |
762 | core->audiomode_current = V4L2_TUNER_MODE_MONO; | ||
759 | core->use_nicam = 0; | 763 | core->use_nicam = 0; |
760 | } else { | 764 | } else { |
761 | core->use_nicam = 1; | 765 | core->use_nicam = 1; |
@@ -787,6 +791,7 @@ void cx88_set_tvaudio(struct cx88_core *core) | |||
787 | void cx88_newstation(struct cx88_core *core) | 791 | void cx88_newstation(struct cx88_core *core) |
788 | { | 792 | { |
789 | core->audiomode_manual = UNSET; | 793 | core->audiomode_manual = UNSET; |
794 | core->last_change = jiffies; | ||
790 | } | 795 | } |
791 | 796 | ||
792 | void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) | 797 | void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) |
@@ -805,12 +810,50 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t) | |||
805 | aud_ctl_names[cx_read(AUD_CTL) & 63]); | 810 | aud_ctl_names[cx_read(AUD_CTL) & 63]); |
806 | core->astat = reg; | 811 | core->astat = reg; |
807 | 812 | ||
808 | /* TODO | 813 | t->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_SAP | |
809 | Reading from AUD_STATUS is not enough | 814 | V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2; |
810 | for auto-detecting sap/dual-fm/nicam. | 815 | t->rxsubchans = UNSET; |
811 | Add some code here later. | 816 | t->audmode = V4L2_TUNER_MODE_MONO; |
812 | */ | ||
813 | 817 | ||
818 | switch (mode) { | ||
819 | case 0: | ||
820 | t->audmode = V4L2_TUNER_MODE_STEREO; | ||
821 | break; | ||
822 | case 1: | ||
823 | t->audmode = V4L2_TUNER_MODE_LANG2; | ||
824 | break; | ||
825 | case 2: | ||
826 | t->audmode = V4L2_TUNER_MODE_MONO; | ||
827 | break; | ||
828 | case 3: | ||
829 | t->audmode = V4L2_TUNER_MODE_SAP; | ||
830 | break; | ||
831 | } | ||
832 | |||
833 | switch (core->tvaudio) { | ||
834 | case WW_BTSC: | ||
835 | case WW_BG: | ||
836 | case WW_DK: | ||
837 | case WW_M: | ||
838 | case WW_EIAJ: | ||
839 | if (!core->use_nicam) { | ||
840 | t->rxsubchans = cx88_dsp_detect_stereo_sap(core); | ||
841 | break; | ||
842 | } | ||
843 | break; | ||
844 | default: | ||
845 | /* nothing */ | ||
846 | break; | ||
847 | } | ||
848 | |||
849 | /* If software stereo detection is not supported... */ | ||
850 | if (UNSET == t->rxsubchans) { | ||
851 | t->rxsubchans = V4L2_TUNER_SUB_MONO; | ||
852 | /* If the hardware itself detected stereo, also return | ||
853 | stereo as an available subchannel */ | ||
854 | if (V4L2_TUNER_MODE_STEREO == t->audmode) | ||
855 | t->rxsubchans |= V4L2_TUNER_SUB_STEREO; | ||
856 | } | ||
814 | return; | 857 | return; |
815 | } | 858 | } |
816 | 859 | ||
@@ -847,6 +890,7 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual) | |||
847 | break; | 890 | break; |
848 | case WW_BG: | 891 | case WW_BG: |
849 | case WW_DK: | 892 | case WW_DK: |
893 | case WW_M: | ||
850 | case WW_I: | 894 | case WW_I: |
851 | case WW_L: | 895 | case WW_L: |
852 | if (1 == core->use_nicam) { | 896 | if (1 == core->use_nicam) { |
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h index f55e4eeed78c..9d83762163f5 100644 --- a/drivers/media/video/cx88/cx88.h +++ b/drivers/media/video/cx88/cx88.h | |||
@@ -65,6 +65,8 @@ | |||
65 | #define VBI_LINE_COUNT 17 | 65 | #define VBI_LINE_COUNT 17 |
66 | #define VBI_LINE_LENGTH 2048 | 66 | #define VBI_LINE_LENGTH 2048 |
67 | 67 | ||
68 | #define AUD_RDS_LINES 4 | ||
69 | |||
68 | /* need "shadow" registers for some write-only ones ... */ | 70 | /* need "shadow" registers for some write-only ones ... */ |
69 | #define SHADOW_AUD_VOL_CTL 1 | 71 | #define SHADOW_AUD_VOL_CTL 1 |
70 | #define SHADOW_AUD_BAL_CTL 2 | 72 | #define SHADOW_AUD_BAL_CTL 2 |
@@ -132,6 +134,7 @@ struct cx88_ctrl { | |||
132 | #define SRAM_CH25 4 /* audio */ | 134 | #define SRAM_CH25 4 /* audio */ |
133 | #define SRAM_CH26 5 | 135 | #define SRAM_CH26 5 |
134 | #define SRAM_CH28 6 /* mpeg */ | 136 | #define SRAM_CH28 6 /* mpeg */ |
137 | #define SRAM_CH27 7 /* audio rds */ | ||
135 | /* more */ | 138 | /* more */ |
136 | 139 | ||
137 | struct sram_channel { | 140 | struct sram_channel { |
@@ -352,6 +355,7 @@ struct cx88_core { | |||
352 | u32 input; | 355 | u32 input; |
353 | u32 astat; | 356 | u32 astat; |
354 | u32 use_nicam; | 357 | u32 use_nicam; |
358 | unsigned long last_change; | ||
355 | 359 | ||
356 | /* IR remote control state */ | 360 | /* IR remote control state */ |
357 | struct cx88_IR *ir; | 361 | struct cx88_IR *ir; |
@@ -654,6 +658,7 @@ extern void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl); | |||
654 | #define WW_I2SPT 8 | 658 | #define WW_I2SPT 8 |
655 | #define WW_FM 9 | 659 | #define WW_FM 9 |
656 | #define WW_I2SADC 10 | 660 | #define WW_I2SADC 10 |
661 | #define WW_M 11 | ||
657 | 662 | ||
658 | void cx88_set_tvaudio(struct cx88_core *core); | 663 | void cx88_set_tvaudio(struct cx88_core *core); |
659 | void cx88_newstation(struct cx88_core *core); | 664 | void cx88_newstation(struct cx88_core *core); |
@@ -667,6 +672,11 @@ struct cx8802_dev *cx8802_get_device(int minor); | |||
667 | struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype); | 672 | struct cx8802_driver * cx8802_get_driver(struct cx8802_dev *dev, enum cx88_board_type btype); |
668 | 673 | ||
669 | /* ----------------------------------------------------------- */ | 674 | /* ----------------------------------------------------------- */ |
675 | /* cx88-dsp.c */ | ||
676 | |||
677 | s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core); | ||
678 | |||
679 | /* ----------------------------------------------------------- */ | ||
670 | /* cx88-input.c */ | 680 | /* cx88-input.c */ |
671 | 681 | ||
672 | int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci); | 682 | int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci); |