aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx18
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2008-04-28 19:24:33 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2008-04-29 17:41:41 -0400
commit1c1e45d17b663d4749af456ab7c2fc1f36405ef8 (patch)
tree03704d6fd888c4c617baa81a60df0d80815b2607 /drivers/media/video/cx18
parentd74bee8b4776b5051c650a90f49a2022d46d8588 (diff)
V4L/DVB (7786): cx18: new driver for the Conexant CX23418 MPEG encoder chip
Many thanks to Steve Toth from Hauppauge and Nattu Dakshinamurthy from Conexant for their support. I am in particular thankful to Hauppauge since without their help this driver would not exist. It should also be noted that Steve did the work to get the DVB part up and running. Thank you! Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Steven Toth <stoth@hauppauge.com> Signed-off-by: Michael Krufky <mkrufky@linuxtv.org> Signed-off-by: G. Andrew Walls <awalls@radix.net> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/cx18')
-rw-r--r--drivers/media/video/cx18/Kconfig20
-rw-r--r--drivers/media/video/cx18/Makefile11
-rw-r--r--drivers/media/video/cx18/cx18-audio.c73
-rw-r--r--drivers/media/video/cx18/cx18-audio.h26
-rw-r--r--drivers/media/video/cx18/cx18-av-audio.c361
-rw-r--r--drivers/media/video/cx18/cx18-av-core.c879
-rw-r--r--drivers/media/video/cx18/cx18-av-core.h318
-rw-r--r--drivers/media/video/cx18/cx18-av-firmware.c120
-rw-r--r--drivers/media/video/cx18/cx18-av-vbi.c413
-rw-r--r--drivers/media/video/cx18/cx18-cards.c277
-rw-r--r--drivers/media/video/cx18/cx18-cards.h170
-rw-r--r--drivers/media/video/cx18/cx18-controls.c306
-rw-r--r--drivers/media/video/cx18/cx18-controls.h24
-rw-r--r--drivers/media/video/cx18/cx18-driver.c971
-rw-r--r--drivers/media/video/cx18/cx18-driver.h500
-rw-r--r--drivers/media/video/cx18/cx18-dvb.c288
-rw-r--r--drivers/media/video/cx18/cx18-dvb.h25
-rw-r--r--drivers/media/video/cx18/cx18-fileops.c711
-rw-r--r--drivers/media/video/cx18/cx18-fileops.h45
-rw-r--r--drivers/media/video/cx18/cx18-firmware.c373
-rw-r--r--drivers/media/video/cx18/cx18-firmware.h25
-rw-r--r--drivers/media/video/cx18/cx18-gpio.c74
-rw-r--r--drivers/media/video/cx18/cx18-gpio.h24
-rw-r--r--drivers/media/video/cx18/cx18-i2c.c431
-rw-r--r--drivers/media/video/cx18/cx18-i2c.h33
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c851
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.h30
-rw-r--r--drivers/media/video/cx18/cx18-irq.c179
-rw-r--r--drivers/media/video/cx18/cx18-irq.h37
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.c372
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.h73
-rw-r--r--drivers/media/video/cx18/cx18-queue.c282
-rw-r--r--drivers/media/video/cx18/cx18-queue.h59
-rw-r--r--drivers/media/video/cx18/cx18-scb.c121
-rw-r--r--drivers/media/video/cx18/cx18-scb.h285
-rw-r--r--drivers/media/video/cx18/cx18-streams.c566
-rw-r--r--drivers/media/video/cx18/cx18-streams.h33
-rw-r--r--drivers/media/video/cx18/cx18-vbi.c208
-rw-r--r--drivers/media/video/cx18/cx18-vbi.h26
-rw-r--r--drivers/media/video/cx18/cx18-version.h34
-rw-r--r--drivers/media/video/cx18/cx18-video.c45
-rw-r--r--drivers/media/video/cx18/cx18-video.h22
-rw-r--r--drivers/media/video/cx18/cx23418.h458
43 files changed, 10179 insertions, 0 deletions
diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig
new file mode 100644
index 000000000000..be654a27bd3c
--- /dev/null
+++ b/drivers/media/video/cx18/Kconfig
@@ -0,0 +1,20 @@
1config VIDEO_CX18
2 tristate "Conexant cx23418 MPEG encoder support"
3 depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL
4 select I2C_ALGOBIT
5 select FW_LOADER
6 select VIDEO_IR
7 select VIDEO_TUNER
8 select VIDEO_TVEEPROM
9 select VIDEO_CX2341X
10 select VIDEO_CS5345
11 select DVB_S5H1409
12 ---help---
13 This is a video4linux driver for Conexant cx23418 based
14 PCI combo video recorder devices.
15
16 This is used in devices such as the Hauppauge HVR-1600
17 cards.
18
19 To compile this driver as a module, choose M here: the
20 module will be called cx18.
diff --git a/drivers/media/video/cx18/Makefile b/drivers/media/video/cx18/Makefile
new file mode 100644
index 000000000000..b23d2e26120f
--- /dev/null
+++ b/drivers/media/video/cx18/Makefile
@@ -0,0 +1,11 @@
1cx18-objs := cx18-driver.o cx18-cards.o cx18-i2c.o cx18-firmware.o cx18-gpio.o \
2 cx18-queue.o cx18-streams.o cx18-fileops.o cx18-ioctl.o cx18-controls.o \
3 cx18-mailbox.o cx18-vbi.o cx18-audio.o cx18-video.o cx18-irq.o \
4 cx18-av-core.o cx18-av-audio.o cx18-av-firmware.o cx18-av-vbi.o cx18-scb.o \
5 cx18-dvb.o
6
7obj-$(CONFIG_VIDEO_CX18) += cx18.o
8
9EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
10EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
11EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/video/cx18/cx18-audio.c b/drivers/media/video/cx18/cx18-audio.c
new file mode 100644
index 000000000000..1adc404d955e
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-audio.c
@@ -0,0 +1,73 @@
1/*
2 * cx18 audio-related functions
3 *
4 * Derived from ivtv-audio.c
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 */
23
24#include "cx18-driver.h"
25#include "cx18-i2c.h"
26#include "cx18-cards.h"
27#include "cx18-audio.h"
28
29/* Selects the audio input and output according to the current
30 settings. */
31int cx18_audio_set_io(struct cx18 *cx)
32{
33 struct v4l2_routing route;
34 u32 audio_input;
35 int mux_input;
36
37 /* Determine which input to use */
38 if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
39 audio_input = cx->card->radio_input.audio_input;
40 mux_input = cx->card->radio_input.muxer_input;
41 } else {
42 audio_input =
43 cx->card->audio_inputs[cx->audio_input].audio_input;
44 mux_input =
45 cx->card->audio_inputs[cx->audio_input].muxer_input;
46 }
47
48 /* handle muxer chips */
49 route.input = mux_input;
50 route.output = 0;
51 cx18_i2c_hw(cx, cx->card->hw_muxer, VIDIOC_INT_S_AUDIO_ROUTING, &route);
52
53 route.input = audio_input;
54 return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
55 VIDIOC_INT_S_AUDIO_ROUTING, &route);
56}
57
58void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route)
59{
60 cx18_i2c_hw(cx, cx->card->hw_audio_ctrl,
61 VIDIOC_INT_S_AUDIO_ROUTING, route);
62}
63
64void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq)
65{
66 static u32 freqs[3] = { 44100, 48000, 32000 };
67
68 /* The audio clock of the digitizer must match the codec sample
69 rate otherwise you get some very strange effects. */
70 if (freq > 2)
71 return;
72 cx18_call_i2c_clients(cx, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[freq]);
73}
diff --git a/drivers/media/video/cx18/cx18-audio.h b/drivers/media/video/cx18/cx18-audio.h
new file mode 100644
index 000000000000..cb569a69379c
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-audio.h
@@ -0,0 +1,26 @@
1/*
2 * cx18 audio-related functions
3 *
4 * Derived from ivtv-audio.c
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 */
23
24int cx18_audio_set_io(struct cx18 *cx);
25void cx18_audio_set_route(struct cx18 *cx, struct v4l2_routing *route);
26void cx18_audio_set_audio_clock_freq(struct cx18 *cx, u8 freq);
diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c
new file mode 100644
index 000000000000..2dc3a5dd170e
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-av-audio.c
@@ -0,0 +1,361 @@
1/*
2 * cx18 ADEC audio functions
3 *
4 * Derived from cx25840-audio.c
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23
24#include "cx18-driver.h"
25
26static int set_audclk_freq(struct cx18 *cx, u32 freq)
27{
28 struct cx18_av_state *state = &cx->av_state;
29
30 if (freq != 32000 && freq != 44100 && freq != 48000)
31 return -EINVAL;
32
33 /* common for all inputs and rates */
34 /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x10 */
35 cx18_av_write(cx, 0x127, 0x50);
36
37 if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
38 switch (freq) {
39 case 32000:
40 /* VID_PLL and AUX_PLL */
41 cx18_av_write4(cx, 0x108, 0x1006040f);
42
43 /* AUX_PLL_FRAC */
44 cx18_av_write4(cx, 0x110, 0x01bb39ee);
45
46 /* src3/4/6_ctl = 0x0801f77f */
47 cx18_av_write4(cx, 0x900, 0x0801f77f);
48 cx18_av_write4(cx, 0x904, 0x0801f77f);
49 cx18_av_write4(cx, 0x90c, 0x0801f77f);
50 break;
51
52 case 44100:
53 /* VID_PLL and AUX_PLL */
54 cx18_av_write4(cx, 0x108, 0x1009040f);
55
56 /* AUX_PLL_FRAC */
57 cx18_av_write4(cx, 0x110, 0x00ec6bd6);
58
59 /* src3/4/6_ctl = 0x08016d59 */
60 cx18_av_write4(cx, 0x900, 0x08016d59);
61 cx18_av_write4(cx, 0x904, 0x08016d59);
62 cx18_av_write4(cx, 0x90c, 0x08016d59);
63 break;
64
65 case 48000:
66 /* VID_PLL and AUX_PLL */
67 cx18_av_write4(cx, 0x108, 0x100a040f);
68
69 /* AUX_PLL_FRAC */
70 cx18_av_write4(cx, 0x110, 0x0098d6e5);
71
72 /* src3/4/6_ctl = 0x08014faa */
73 cx18_av_write4(cx, 0x900, 0x08014faa);
74 cx18_av_write4(cx, 0x904, 0x08014faa);
75 cx18_av_write4(cx, 0x90c, 0x08014faa);
76 break;
77 }
78 } else {
79 switch (freq) {
80 case 32000:
81 /* VID_PLL and AUX_PLL */
82 cx18_av_write4(cx, 0x108, 0x1e08040f);
83
84 /* AUX_PLL_FRAC */
85 cx18_av_write4(cx, 0x110, 0x012a0869);
86
87 /* src1_ctl = 0x08010000 */
88 cx18_av_write4(cx, 0x8f8, 0x08010000);
89
90 /* src3/4/6_ctl = 0x08020000 */
91 cx18_av_write4(cx, 0x900, 0x08020000);
92 cx18_av_write4(cx, 0x904, 0x08020000);
93 cx18_av_write4(cx, 0x90c, 0x08020000);
94
95 /* SA_MCLK_SEL=1, SA_MCLK_DIV=0x14 */
96 cx18_av_write(cx, 0x127, 0x54);
97 break;
98
99 case 44100:
100 /* VID_PLL and AUX_PLL */
101 cx18_av_write4(cx, 0x108, 0x1809040f);
102
103 /* AUX_PLL_FRAC */
104 cx18_av_write4(cx, 0x110, 0x00ec6bd6);
105
106 /* src1_ctl = 0x08010000 */
107 cx18_av_write4(cx, 0x8f8, 0x080160cd);
108
109 /* src3/4/6_ctl = 0x08020000 */
110 cx18_av_write4(cx, 0x900, 0x08017385);
111 cx18_av_write4(cx, 0x904, 0x08017385);
112 cx18_av_write4(cx, 0x90c, 0x08017385);
113 break;
114
115 case 48000:
116 /* VID_PLL and AUX_PLL */
117 cx18_av_write4(cx, 0x108, 0x180a040f);
118
119 /* AUX_PLL_FRAC */
120 cx18_av_write4(cx, 0x110, 0x0098d6e5);
121
122 /* src1_ctl = 0x08010000 */
123 cx18_av_write4(cx, 0x8f8, 0x08018000);
124
125 /* src3/4/6_ctl = 0x08020000 */
126 cx18_av_write4(cx, 0x900, 0x08015555);
127 cx18_av_write4(cx, 0x904, 0x08015555);
128 cx18_av_write4(cx, 0x90c, 0x08015555);
129 break;
130 }
131 }
132
133 state->audclk_freq = freq;
134
135 return 0;
136}
137
138void cx18_av_audio_set_path(struct cx18 *cx)
139{
140 struct cx18_av_state *state = &cx->av_state;
141
142 /* stop microcontroller */
143 cx18_av_and_or(cx, 0x803, ~0x10, 0);
144
145 /* assert soft reset */
146 cx18_av_and_or(cx, 0x810, ~0x1, 0x01);
147
148 /* Mute everything to prevent the PFFT! */
149 cx18_av_write(cx, 0x8d3, 0x1f);
150
151 if (state->aud_input == CX18_AV_AUDIO_SERIAL) {
152 /* Set Path1 to Serial Audio Input */
153 cx18_av_write4(cx, 0x8d0, 0x01011012);
154
155 /* The microcontroller should not be started for the
156 * non-tuner inputs: autodetection is specific for
157 * TV audio. */
158 } else {
159 /* Set Path1 to Analog Demod Main Channel */
160 cx18_av_write4(cx, 0x8d0, 0x1f063870);
161 }
162
163 set_audclk_freq(cx, state->audclk_freq);
164
165 /* deassert soft reset */
166 cx18_av_and_or(cx, 0x810, ~0x1, 0x00);
167
168 if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
169 /* When the microcontroller detects the
170 * audio format, it will unmute the lines */
171 cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
172 }
173}
174
175static int get_volume(struct cx18 *cx)
176{
177 /* Volume runs +18dB to -96dB in 1/2dB steps
178 * change to fit the msp3400 -114dB to +12dB range */
179
180 /* check PATH1_VOLUME */
181 int vol = 228 - cx18_av_read(cx, 0x8d4);
182 vol = (vol / 2) + 23;
183 return vol << 9;
184}
185
186static void set_volume(struct cx18 *cx, int volume)
187{
188 /* First convert the volume to msp3400 values (0-127) */
189 int vol = volume >> 9;
190 /* now scale it up to cx18_av values
191 * -114dB to -96dB maps to 0
192 * this should be 19, but in my testing that was 4dB too loud */
193 if (vol <= 23)
194 vol = 0;
195 else
196 vol -= 23;
197
198 /* PATH1_VOLUME */
199 cx18_av_write(cx, 0x8d4, 228 - (vol * 2));
200}
201
202static int get_bass(struct cx18 *cx)
203{
204 /* bass is 49 steps +12dB to -12dB */
205
206 /* check PATH1_EQ_BASS_VOL */
207 int bass = cx18_av_read(cx, 0x8d9) & 0x3f;
208 bass = (((48 - bass) * 0xffff) + 47) / 48;
209 return bass;
210}
211
212static void set_bass(struct cx18 *cx, int bass)
213{
214 /* PATH1_EQ_BASS_VOL */
215 cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
216}
217
218static int get_treble(struct cx18 *cx)
219{
220 /* treble is 49 steps +12dB to -12dB */
221
222 /* check PATH1_EQ_TREBLE_VOL */
223 int treble = cx18_av_read(cx, 0x8db) & 0x3f;
224 treble = (((48 - treble) * 0xffff) + 47) / 48;
225 return treble;
226}
227
228static void set_treble(struct cx18 *cx, int treble)
229{
230 /* PATH1_EQ_TREBLE_VOL */
231 cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
232}
233
234static int get_balance(struct cx18 *cx)
235{
236 /* balance is 7 bit, 0 to -96dB */
237
238 /* check PATH1_BAL_LEVEL */
239 int balance = cx18_av_read(cx, 0x8d5) & 0x7f;
240 /* check PATH1_BAL_LEFT */
241 if ((cx18_av_read(cx, 0x8d5) & 0x80) == 0)
242 balance = 0x80 - balance;
243 else
244 balance = 0x80 + balance;
245 return balance << 8;
246}
247
248static void set_balance(struct cx18 *cx, int balance)
249{
250 int bal = balance >> 8;
251 if (bal > 0x80) {
252 /* PATH1_BAL_LEFT */
253 cx18_av_and_or(cx, 0x8d5, 0x7f, 0x80);
254 /* PATH1_BAL_LEVEL */
255 cx18_av_and_or(cx, 0x8d5, ~0x7f, bal & 0x7f);
256 } else {
257 /* PATH1_BAL_LEFT */
258 cx18_av_and_or(cx, 0x8d5, 0x7f, 0x00);
259 /* PATH1_BAL_LEVEL */
260 cx18_av_and_or(cx, 0x8d5, ~0x7f, 0x80 - bal);
261 }
262}
263
264static int get_mute(struct cx18 *cx)
265{
266 /* check SRC1_MUTE_EN */
267 return cx18_av_read(cx, 0x8d3) & 0x2 ? 1 : 0;
268}
269
270static void set_mute(struct cx18 *cx, int mute)
271{
272 struct cx18_av_state *state = &cx->av_state;
273
274 if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
275 /* Must turn off microcontroller in order to mute sound.
276 * Not sure if this is the best method, but it does work.
277 * If the microcontroller is running, then it will undo any
278 * changes to the mute register. */
279 if (mute) {
280 /* disable microcontroller */
281 cx18_av_and_or(cx, 0x803, ~0x10, 0x00);
282 cx18_av_write(cx, 0x8d3, 0x1f);
283 } else {
284 /* enable microcontroller */
285 cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
286 }
287 } else {
288 /* SRC1_MUTE_EN */
289 cx18_av_and_or(cx, 0x8d3, ~0x2, mute ? 0x02 : 0x00);
290 }
291}
292
293int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg)
294{
295 struct cx18_av_state *state = &cx->av_state;
296 struct v4l2_control *ctrl = arg;
297 int retval;
298
299 switch (cmd) {
300 case VIDIOC_INT_AUDIO_CLOCK_FREQ:
301 if (state->aud_input != CX18_AV_AUDIO_SERIAL) {
302 cx18_av_and_or(cx, 0x803, ~0x10, 0);
303 cx18_av_write(cx, 0x8d3, 0x1f);
304 }
305 cx18_av_and_or(cx, 0x810, ~0x1, 1);
306 retval = set_audclk_freq(cx, *(u32 *)arg);
307 cx18_av_and_or(cx, 0x810, ~0x1, 0);
308 if (state->aud_input != CX18_AV_AUDIO_SERIAL)
309 cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
310 return retval;
311
312 case VIDIOC_G_CTRL:
313 switch (ctrl->id) {
314 case V4L2_CID_AUDIO_VOLUME:
315 ctrl->value = get_volume(cx);
316 break;
317 case V4L2_CID_AUDIO_BASS:
318 ctrl->value = get_bass(cx);
319 break;
320 case V4L2_CID_AUDIO_TREBLE:
321 ctrl->value = get_treble(cx);
322 break;
323 case V4L2_CID_AUDIO_BALANCE:
324 ctrl->value = get_balance(cx);
325 break;
326 case V4L2_CID_AUDIO_MUTE:
327 ctrl->value = get_mute(cx);
328 break;
329 default:
330 return -EINVAL;
331 }
332 break;
333
334 case VIDIOC_S_CTRL:
335 switch (ctrl->id) {
336 case V4L2_CID_AUDIO_VOLUME:
337 set_volume(cx, ctrl->value);
338 break;
339 case V4L2_CID_AUDIO_BASS:
340 set_bass(cx, ctrl->value);
341 break;
342 case V4L2_CID_AUDIO_TREBLE:
343 set_treble(cx, ctrl->value);
344 break;
345 case V4L2_CID_AUDIO_BALANCE:
346 set_balance(cx, ctrl->value);
347 break;
348 case V4L2_CID_AUDIO_MUTE:
349 set_mute(cx, ctrl->value);
350 break;
351 default:
352 return -EINVAL;
353 }
354 break;
355
356 default:
357 return -EINVAL;
358 }
359
360 return 0;
361}
diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c
new file mode 100644
index 000000000000..66864904c99b
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-av-core.c
@@ -0,0 +1,879 @@
1/*
2 * cx18 ADEC audio functions
3 *
4 * Derived from cx25840-core.c
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23
24#include "cx18-driver.h"
25
26int cx18_av_write(struct cx18 *cx, u16 addr, u8 value)
27{
28 u32 x = readl(cx->reg_mem + 0xc40000 + (addr & ~3));
29 u32 mask = 0xff;
30 int shift = (addr & 3) * 8;
31
32 x = (x & ~(mask << shift)) | ((u32)value << shift);
33 writel(x, cx->reg_mem + 0xc40000 + (addr & ~3));
34 return 0;
35}
36
37int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value)
38{
39 writel(value, cx->reg_mem + 0xc40000 + addr);
40 return 0;
41}
42
43u8 cx18_av_read(struct cx18 *cx, u16 addr)
44{
45 u32 x = readl(cx->reg_mem + 0xc40000 + (addr & ~3));
46 int shift = (addr & 3) * 8;
47
48 return (x >> shift) & 0xff;
49}
50
51u32 cx18_av_read4(struct cx18 *cx, u16 addr)
52{
53 return readl(cx->reg_mem + 0xc40000 + addr);
54}
55
56int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned and_mask,
57 u8 or_value)
58{
59 return cx18_av_write(cx, addr,
60 (cx18_av_read(cx, addr) & and_mask) |
61 or_value);
62}
63
64int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 and_mask,
65 u32 or_value)
66{
67 return cx18_av_write4(cx, addr,
68 (cx18_av_read4(cx, addr) & and_mask) |
69 or_value);
70}
71
72/* ----------------------------------------------------------------------- */
73
74static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
75 enum cx18_av_audio_input aud_input);
76static void log_audio_status(struct cx18 *cx);
77static void log_video_status(struct cx18 *cx);
78
79/* ----------------------------------------------------------------------- */
80
81static void cx18_av_initialize(struct cx18 *cx)
82{
83 u32 v;
84
85 cx18_av_loadfw(cx);
86 /* Stop 8051 code execution */
87 cx18_av_write4(cx, CXADEC_DL_CTL, 0x03000000);
88
89 /* initallize the PLL by toggling sleep bit */
90 v = cx18_av_read4(cx, CXADEC_HOST_REG1);
91 /* enable sleep mode */
92 cx18_av_write4(cx, CXADEC_HOST_REG1, v | 1);
93 /* disable sleep mode */
94 cx18_av_write4(cx, CXADEC_HOST_REG1, v & 0xfffe);
95
96 /* initialize DLLs */
97 v = cx18_av_read4(cx, CXADEC_DLL1_DIAG_CTRL) & 0xE1FFFEFF;
98 /* disable FLD */
99 cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v);
100 /* enable FLD */
101 cx18_av_write4(cx, CXADEC_DLL1_DIAG_CTRL, v | 0x10000100);
102
103 v = cx18_av_read4(cx, CXADEC_DLL2_DIAG_CTRL) & 0xE1FFFEFF;
104 /* disable FLD */
105 cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v);
106 /* enable FLD */
107 cx18_av_write4(cx, CXADEC_DLL2_DIAG_CTRL, v | 0x06000100);
108
109 /* set analog bias currents. Set Vreg to 1.20V. */
110 cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL1, 0x000A1802);
111
112 v = cx18_av_read4(cx, CXADEC_AFE_DIAG_CTRL3) | 1;
113 /* enable TUNE_FIL_RST */
114 cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v);
115 /* disable TUNE_FIL_RST */
116 cx18_av_write4(cx, CXADEC_AFE_DIAG_CTRL3, v & 0xFFFFFFFE);
117
118 /* enable 656 output */
119 cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x040C00);
120
121 /* video output drive strength */
122 cx18_av_and_or4(cx, CXADEC_PIN_CTRL2, ~0, 0x2);
123
124 /* reset video */
125 cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0x8000);
126 cx18_av_write4(cx, CXADEC_SOFT_RST_CTRL, 0);
127
128 /* set video to auto-detect */
129 /* Clear bits 11-12 to enable slow locking mode. Set autodetect mode */
130 /* set the comb notch = 1 */
131 cx18_av_and_or4(cx, CXADEC_MODE_CTRL, 0xFFF7E7F0, 0x02040800);
132
133 /* Enable wtw_en in CRUSH_CTRL (Set bit 22) */
134 /* Enable maj_sel in CRUSH_CTRL (Set bit 20) */
135 cx18_av_and_or4(cx, CXADEC_CRUSH_CTRL, ~0, 0x00500000);
136
137 /* Set VGA_TRACK_RANGE to 0x20 */
138 cx18_av_and_or4(cx, CXADEC_DFE_CTRL2, 0xFFFF00FF, 0x00002000);
139
140 /* Enable VBI capture */
141 cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253F);
142 /* cx18_av_write4(cx, CXADEC_OUT_CTRL1, 0x4010253E); */
143
144 /* Set the video input.
145 The setting in MODE_CTRL gets lost when we do the above setup */
146 /* EncSetSignalStd(dwDevNum, pEnc->dwSigStd); */
147 /* EncSetVideoInput(dwDevNum, pEnc->VidIndSelection); */
148
149 v = cx18_av_read4(cx, CXADEC_AFE_CTRL);
150 v &= 0xFFFBFFFF; /* turn OFF bit 18 for droop_comp_ch1 */
151 v &= 0xFFFF7FFF; /* turn OFF bit 9 for clamp_sel_ch1 */
152 v &= 0xFFFFFFFE; /* turn OFF bit 0 for 12db_ch1 */
153 /* v |= 0x00000001;*/ /* turn ON bit 0 for 12db_ch1 */
154 cx18_av_write4(cx, CXADEC_AFE_CTRL, v);
155
156/* if(dwEnable && dw3DCombAvailable) { */
157/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x7728021F); */
158/* } else { */
159/* CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */
160/* } */
161 cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F);
162}
163
164/* ----------------------------------------------------------------------- */
165
166static void input_change(struct cx18 *cx)
167{
168 struct cx18_av_state *state = &cx->av_state;
169 v4l2_std_id std = state->std;
170
171 /* Follow step 8c and 8d of section 3.16 in the cx18_av datasheet */
172 if (std & V4L2_STD_SECAM)
173 cx18_av_write(cx, 0x402, 0);
174 else {
175 cx18_av_write(cx, 0x402, 0x04);
176 cx18_av_write(cx, 0x49f, (std & V4L2_STD_NTSC) ? 0x14 : 0x11);
177 }
178 cx18_av_and_or(cx, 0x401, ~0x60, 0);
179 cx18_av_and_or(cx, 0x401, ~0x60, 0x60);
180
181 if (std & V4L2_STD_525_60) {
182 if (std == V4L2_STD_NTSC_M_JP) {
183 /* Japan uses EIAJ audio standard */
184 cx18_av_write(cx, 0x808, 0xf7);
185 } else if (std == V4L2_STD_NTSC_M_KR) {
186 /* South Korea uses A2 audio standard */
187 cx18_av_write(cx, 0x808, 0xf8);
188 } else {
189 /* Others use the BTSC audio standard */
190 cx18_av_write(cx, 0x808, 0xf6);
191 }
192 cx18_av_write(cx, 0x80b, 0x00);
193 } else if (std & V4L2_STD_PAL) {
194 /* Follow tuner change procedure for PAL */
195 cx18_av_write(cx, 0x808, 0xff);
196 cx18_av_write(cx, 0x80b, 0x03);
197 } else if (std & V4L2_STD_SECAM) {
198 /* Select autodetect for SECAM */
199 cx18_av_write(cx, 0x808, 0xff);
200 cx18_av_write(cx, 0x80b, 0x03);
201 }
202
203 if (cx18_av_read(cx, 0x803) & 0x10) {
204 /* restart audio decoder microcontroller */
205 cx18_av_and_or(cx, 0x803, ~0x10, 0x00);
206 cx18_av_and_or(cx, 0x803, ~0x10, 0x10);
207 }
208}
209
210static int set_input(struct cx18 *cx, enum cx18_av_video_input vid_input,
211 enum cx18_av_audio_input aud_input)
212{
213 struct cx18_av_state *state = &cx->av_state;
214 u8 is_composite = (vid_input >= CX18_AV_COMPOSITE1 &&
215 vid_input <= CX18_AV_COMPOSITE8);
216 u8 reg;
217
218 CX18_DEBUG_INFO("decoder set video input %d, audio input %d\n",
219 vid_input, aud_input);
220
221 if (is_composite) {
222 reg = 0xf0 + (vid_input - CX18_AV_COMPOSITE1);
223 } else {
224 int luma = vid_input & 0xf0;
225 int chroma = vid_input & 0xf00;
226
227 if ((vid_input & ~0xff0) ||
228 luma < CX18_AV_SVIDEO_LUMA1 ||
229 luma > CX18_AV_SVIDEO_LUMA4 ||
230 chroma < CX18_AV_SVIDEO_CHROMA4 ||
231 chroma > CX18_AV_SVIDEO_CHROMA8) {
232 CX18_ERR("0x%04x is not a valid video input!\n",
233 vid_input);
234 return -EINVAL;
235 }
236 reg = 0xf0 + ((luma - CX18_AV_SVIDEO_LUMA1) >> 4);
237 if (chroma >= CX18_AV_SVIDEO_CHROMA7) {
238 reg &= 0x3f;
239 reg |= (chroma - CX18_AV_SVIDEO_CHROMA7) >> 2;
240 } else {
241 reg &= 0xcf;
242 reg |= (chroma - CX18_AV_SVIDEO_CHROMA4) >> 4;
243 }
244 }
245
246 switch (aud_input) {
247 case CX18_AV_AUDIO_SERIAL:
248 /* do nothing, use serial audio input */
249 break;
250 case CX18_AV_AUDIO4: reg &= ~0x30; break;
251 case CX18_AV_AUDIO5: reg &= ~0x30; reg |= 0x10; break;
252 case CX18_AV_AUDIO6: reg &= ~0x30; reg |= 0x20; break;
253 case CX18_AV_AUDIO7: reg &= ~0xc0; break;
254 case CX18_AV_AUDIO8: reg &= ~0xc0; reg |= 0x40; break;
255
256 default:
257 CX18_ERR("0x%04x is not a valid audio input!\n", aud_input);
258 return -EINVAL;
259 }
260
261 cx18_av_write(cx, 0x103, reg);
262 /* Set INPUT_MODE to Composite (0) or S-Video (1) */
263 cx18_av_and_or(cx, 0x401, ~0x6, is_composite ? 0 : 0x02);
264 /* Set CH_SEL_ADC2 to 1 if input comes from CH3 */
265 cx18_av_and_or(cx, 0x102, ~0x2, (reg & 0x80) == 0 ? 2 : 0);
266 /* Set DUAL_MODE_ADC2 to 1 if input comes from both CH2 and CH3 */
267 if ((reg & 0xc0) != 0xc0 && (reg & 0x30) != 0x30)
268 cx18_av_and_or(cx, 0x102, ~0x4, 4);
269 else
270 cx18_av_and_or(cx, 0x102, ~0x4, 0);
271 /*cx18_av_and_or4(cx, 0x104, ~0x001b4180, 0x00004180);*/
272
273 state->vid_input = vid_input;
274 state->aud_input = aud_input;
275 cx18_av_audio_set_path(cx);
276 input_change(cx);
277 return 0;
278}
279
280/* ----------------------------------------------------------------------- */
281
282static int set_v4lstd(struct cx18 *cx)
283{
284 struct cx18_av_state *state = &cx->av_state;
285 u8 fmt = 0; /* zero is autodetect */
286 u8 pal_m = 0;
287
288 /* First tests should be against specific std */
289 if (state->std == V4L2_STD_NTSC_M_JP) {
290 fmt = 0x2;
291 } else if (state->std == V4L2_STD_NTSC_443) {
292 fmt = 0x3;
293 } else if (state->std == V4L2_STD_PAL_M) {
294 pal_m = 1;
295 fmt = 0x5;
296 } else if (state->std == V4L2_STD_PAL_N) {
297 fmt = 0x6;
298 } else if (state->std == V4L2_STD_PAL_Nc) {
299 fmt = 0x7;
300 } else if (state->std == V4L2_STD_PAL_60) {
301 fmt = 0x8;
302 } else {
303 /* Then, test against generic ones */
304 if (state->std & V4L2_STD_NTSC)
305 fmt = 0x1;
306 else if (state->std & V4L2_STD_PAL)
307 fmt = 0x4;
308 else if (state->std & V4L2_STD_SECAM)
309 fmt = 0xc;
310 }
311
312 CX18_DEBUG_INFO("changing video std to fmt %i\n", fmt);
313
314 /* Follow step 9 of section 3.16 in the cx18_av datasheet.
315 Without this PAL may display a vertical ghosting effect.
316 This happens for example with the Yuan MPC622. */
317 if (fmt >= 4 && fmt < 8) {
318 /* Set format to NTSC-M */
319 cx18_av_and_or(cx, 0x400, ~0xf, 1);
320 /* Turn off LCOMB */
321 cx18_av_and_or(cx, 0x47b, ~6, 0);
322 }
323 cx18_av_and_or(cx, 0x400, ~0xf, fmt);
324 cx18_av_and_or(cx, 0x403, ~0x3, pal_m);
325 cx18_av_vbi_setup(cx);
326 input_change(cx);
327 return 0;
328}
329
330/* ----------------------------------------------------------------------- */
331
332static int set_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
333{
334 switch (ctrl->id) {
335 case V4L2_CID_BRIGHTNESS:
336 if (ctrl->value < 0 || ctrl->value > 255) {
337 CX18_ERR("invalid brightness setting %d\n",
338 ctrl->value);
339 return -ERANGE;
340 }
341
342 cx18_av_write(cx, 0x414, ctrl->value - 128);
343 break;
344
345 case V4L2_CID_CONTRAST:
346 if (ctrl->value < 0 || ctrl->value > 127) {
347 CX18_ERR("invalid contrast setting %d\n",
348 ctrl->value);
349 return -ERANGE;
350 }
351
352 cx18_av_write(cx, 0x415, ctrl->value << 1);
353 break;
354
355 case V4L2_CID_SATURATION:
356 if (ctrl->value < 0 || ctrl->value > 127) {
357 CX18_ERR("invalid saturation setting %d\n",
358 ctrl->value);
359 return -ERANGE;
360 }
361
362 cx18_av_write(cx, 0x420, ctrl->value << 1);
363 cx18_av_write(cx, 0x421, ctrl->value << 1);
364 break;
365
366 case V4L2_CID_HUE:
367 if (ctrl->value < -127 || ctrl->value > 127) {
368 CX18_ERR("invalid hue setting %d\n", ctrl->value);
369 return -ERANGE;
370 }
371
372 cx18_av_write(cx, 0x422, ctrl->value);
373 break;
374
375 case V4L2_CID_AUDIO_VOLUME:
376 case V4L2_CID_AUDIO_BASS:
377 case V4L2_CID_AUDIO_TREBLE:
378 case V4L2_CID_AUDIO_BALANCE:
379 case V4L2_CID_AUDIO_MUTE:
380 return cx18_av_audio(cx, VIDIOC_S_CTRL, ctrl);
381
382 default:
383 return -EINVAL;
384 }
385
386 return 0;
387}
388
389static int get_v4lctrl(struct cx18 *cx, struct v4l2_control *ctrl)
390{
391 switch (ctrl->id) {
392 case V4L2_CID_BRIGHTNESS:
393 ctrl->value = (s8)cx18_av_read(cx, 0x414) + 128;
394 break;
395 case V4L2_CID_CONTRAST:
396 ctrl->value = cx18_av_read(cx, 0x415) >> 1;
397 break;
398 case V4L2_CID_SATURATION:
399 ctrl->value = cx18_av_read(cx, 0x420) >> 1;
400 break;
401 case V4L2_CID_HUE:
402 ctrl->value = (s8)cx18_av_read(cx, 0x422);
403 break;
404 case V4L2_CID_AUDIO_VOLUME:
405 case V4L2_CID_AUDIO_BASS:
406 case V4L2_CID_AUDIO_TREBLE:
407 case V4L2_CID_AUDIO_BALANCE:
408 case V4L2_CID_AUDIO_MUTE:
409 return cx18_av_audio(cx, VIDIOC_G_CTRL, ctrl);
410 default:
411 return -EINVAL;
412 }
413
414 return 0;
415}
416
417/* ----------------------------------------------------------------------- */
418
419static int get_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt)
420{
421 switch (fmt->type) {
422 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
423 return cx18_av_vbi(cx, VIDIOC_G_FMT, fmt);
424 default:
425 return -EINVAL;
426 }
427
428 return 0;
429}
430
431static int set_v4lfmt(struct cx18 *cx, struct v4l2_format *fmt)
432{
433 struct cx18_av_state *state = &cx->av_state;
434 struct v4l2_pix_format *pix;
435 int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
436 int is_50Hz = !(state->std & V4L2_STD_525_60);
437
438 switch (fmt->type) {
439 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
440 pix = &(fmt->fmt.pix);
441
442 Vsrc = (cx18_av_read(cx, 0x476) & 0x3f) << 4;
443 Vsrc |= (cx18_av_read(cx, 0x475) & 0xf0) >> 4;
444
445 Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4;
446 Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4;
447
448 Vlines = pix->height + (is_50Hz ? 4 : 7);
449
450 if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) ||
451 (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
452 CX18_ERR("%dx%d is not a valid size!\n",
453 pix->width, pix->height);
454 return -ERANGE;
455 }
456
457 HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20);
458 VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9));
459 VSC &= 0x1fff;
460
461 if (pix->width >= 385)
462 filter = 0;
463 else if (pix->width > 192)
464 filter = 1;
465 else if (pix->width > 96)
466 filter = 2;
467 else
468 filter = 3;
469
470 CX18_DEBUG_INFO("decoder set size %dx%d -> scale %ux%u\n",
471 pix->width, pix->height, HSC, VSC);
472
473 /* HSCALE=HSC */
474 cx18_av_write(cx, 0x418, HSC & 0xff);
475 cx18_av_write(cx, 0x419, (HSC >> 8) & 0xff);
476 cx18_av_write(cx, 0x41a, HSC >> 16);
477 /* VSCALE=VSC */
478 cx18_av_write(cx, 0x41c, VSC & 0xff);
479 cx18_av_write(cx, 0x41d, VSC >> 8);
480 /* VS_INTRLACE=1 VFILT=filter */
481 cx18_av_write(cx, 0x41e, 0x8 | filter);
482 break;
483
484 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
485 return cx18_av_vbi(cx, VIDIOC_S_FMT, fmt);
486
487 case V4L2_BUF_TYPE_VBI_CAPTURE:
488 return cx18_av_vbi(cx, VIDIOC_S_FMT, fmt);
489
490 default:
491 return -EINVAL;
492 }
493
494 return 0;
495}
496
497/* ----------------------------------------------------------------------- */
498
499int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg)
500{
501 struct cx18_av_state *state = &cx->av_state;
502 struct v4l2_tuner *vt = arg;
503 struct v4l2_routing *route = arg;
504
505 /* ignore these commands */
506 switch (cmd) {
507 case TUNER_SET_TYPE_ADDR:
508 return 0;
509 }
510
511 if (!state->is_initialized) {
512 CX18_DEBUG_INFO("cmd %08x triggered fw load\n", cmd);
513 /* initialize on first use */
514 state->is_initialized = 1;
515 cx18_av_initialize(cx);
516 }
517
518 switch (cmd) {
519 case VIDIOC_INT_DECODE_VBI_LINE:
520 return cx18_av_vbi(cx, cmd, arg);
521
522 case VIDIOC_INT_AUDIO_CLOCK_FREQ:
523 return cx18_av_audio(cx, cmd, arg);
524
525 case VIDIOC_STREAMON:
526 CX18_DEBUG_INFO("enable output\n");
527 cx18_av_write(cx, 0x115, 0x8c);
528 cx18_av_write(cx, 0x116, 0x07);
529 break;
530
531 case VIDIOC_STREAMOFF:
532 CX18_DEBUG_INFO("disable output\n");
533 cx18_av_write(cx, 0x115, 0x00);
534 cx18_av_write(cx, 0x116, 0x00);
535 break;
536
537 case VIDIOC_LOG_STATUS:
538 log_video_status(cx);
539 log_audio_status(cx);
540 break;
541
542 case VIDIOC_G_CTRL:
543 return get_v4lctrl(cx, (struct v4l2_control *)arg);
544
545 case VIDIOC_S_CTRL:
546 return set_v4lctrl(cx, (struct v4l2_control *)arg);
547
548 case VIDIOC_QUERYCTRL:
549 {
550 struct v4l2_queryctrl *qc = arg;
551
552 switch (qc->id) {
553 case V4L2_CID_BRIGHTNESS:
554 case V4L2_CID_CONTRAST:
555 case V4L2_CID_SATURATION:
556 case V4L2_CID_HUE:
557 return v4l2_ctrl_query_fill_std(qc);
558 default:
559 break;
560 }
561
562 switch (qc->id) {
563 case V4L2_CID_AUDIO_VOLUME:
564 case V4L2_CID_AUDIO_MUTE:
565 case V4L2_CID_AUDIO_BALANCE:
566 case V4L2_CID_AUDIO_BASS:
567 case V4L2_CID_AUDIO_TREBLE:
568 return v4l2_ctrl_query_fill_std(qc);
569 default:
570 return -EINVAL;
571 }
572 return -EINVAL;
573 }
574
575 case VIDIOC_G_STD:
576 *(v4l2_std_id *)arg = state->std;
577 break;
578
579 case VIDIOC_S_STD:
580 if (state->radio == 0 && state->std == *(v4l2_std_id *)arg)
581 return 0;
582 state->radio = 0;
583 state->std = *(v4l2_std_id *)arg;
584 return set_v4lstd(cx);
585
586 case AUDC_SET_RADIO:
587 state->radio = 1;
588 break;
589
590 case VIDIOC_INT_G_VIDEO_ROUTING:
591 route->input = state->vid_input;
592 route->output = 0;
593 break;
594
595 case VIDIOC_INT_S_VIDEO_ROUTING:
596 return set_input(cx, route->input, state->aud_input);
597
598 case VIDIOC_INT_G_AUDIO_ROUTING:
599 route->input = state->aud_input;
600 route->output = 0;
601 break;
602
603 case VIDIOC_INT_S_AUDIO_ROUTING:
604 return set_input(cx, state->vid_input, route->input);
605
606 case VIDIOC_S_FREQUENCY:
607 input_change(cx);
608 break;
609
610 case VIDIOC_G_TUNER:
611 {
612 u8 vpres = cx18_av_read(cx, 0x40e) & 0x20;
613 u8 mode;
614 int val = 0;
615
616 if (state->radio)
617 break;
618
619 vt->signal = vpres ? 0xffff : 0x0;
620
621 vt->capability |=
622 V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LANG1 |
623 V4L2_TUNER_CAP_LANG2 | V4L2_TUNER_CAP_SAP;
624
625 mode = cx18_av_read(cx, 0x804);
626
627 /* get rxsubchans and audmode */
628 if ((mode & 0xf) == 1)
629 val |= V4L2_TUNER_SUB_STEREO;
630 else
631 val |= V4L2_TUNER_SUB_MONO;
632
633 if (mode == 2 || mode == 4)
634 val = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
635
636 if (mode & 0x10)
637 val |= V4L2_TUNER_SUB_SAP;
638
639 vt->rxsubchans = val;
640 vt->audmode = state->audmode;
641 break;
642 }
643
644 case VIDIOC_S_TUNER:
645 if (state->radio)
646 break;
647
648 switch (vt->audmode) {
649 case V4L2_TUNER_MODE_MONO:
650 /* mono -> mono
651 stereo -> mono
652 bilingual -> lang1 */
653 cx18_av_and_or(cx, 0x809, ~0xf, 0x00);
654 break;
655 case V4L2_TUNER_MODE_STEREO:
656 case V4L2_TUNER_MODE_LANG1:
657 /* mono -> mono
658 stereo -> stereo
659 bilingual -> lang1 */
660 cx18_av_and_or(cx, 0x809, ~0xf, 0x04);
661 break;
662 case V4L2_TUNER_MODE_LANG1_LANG2:
663 /* mono -> mono
664 stereo -> stereo
665 bilingual -> lang1/lang2 */
666 cx18_av_and_or(cx, 0x809, ~0xf, 0x07);
667 break;
668 case V4L2_TUNER_MODE_LANG2:
669 /* mono -> mono
670 stereo -> stereo
671 bilingual -> lang2 */
672 cx18_av_and_or(cx, 0x809, ~0xf, 0x01);
673 break;
674 default:
675 return -EINVAL;
676 }
677 state->audmode = vt->audmode;
678 break;
679
680 case VIDIOC_G_FMT:
681 return get_v4lfmt(cx, (struct v4l2_format *)arg);
682
683 case VIDIOC_S_FMT:
684 return set_v4lfmt(cx, (struct v4l2_format *)arg);
685
686 case VIDIOC_INT_RESET:
687 cx18_av_initialize(cx);
688 break;
689
690 default:
691 return -EINVAL;
692 }
693
694 return 0;
695}
696
697/* ----------------------------------------------------------------------- */
698
699/* ----------------------------------------------------------------------- */
700
701static void log_video_status(struct cx18 *cx)
702{
703 static const char *const fmt_strs[] = {
704 "0x0",
705 "NTSC-M", "NTSC-J", "NTSC-4.43",
706 "PAL-BDGHI", "PAL-M", "PAL-N", "PAL-Nc", "PAL-60",
707 "0x9", "0xA", "0xB",
708 "SECAM",
709 "0xD", "0xE", "0xF"
710 };
711
712 struct cx18_av_state *state = &cx->av_state;
713 u8 vidfmt_sel = cx18_av_read(cx, 0x400) & 0xf;
714 u8 gen_stat1 = cx18_av_read(cx, 0x40d);
715 u8 gen_stat2 = cx18_av_read(cx, 0x40e);
716 int vid_input = state->vid_input;
717
718 CX18_INFO("Video signal: %spresent\n",
719 (gen_stat2 & 0x20) ? "" : "not ");
720 CX18_INFO("Detected format: %s\n",
721 fmt_strs[gen_stat1 & 0xf]);
722
723 CX18_INFO("Specified standard: %s\n",
724 vidfmt_sel ? fmt_strs[vidfmt_sel] : "automatic detection");
725
726 if (vid_input >= CX18_AV_COMPOSITE1 &&
727 vid_input <= CX18_AV_COMPOSITE8) {
728 CX18_INFO("Specified video input: Composite %d\n",
729 vid_input - CX18_AV_COMPOSITE1 + 1);
730 } else {
731 CX18_INFO("Specified video input: S-Video (Luma In%d, Chroma In%d)\n",
732 (vid_input & 0xf0) >> 4, (vid_input & 0xf00) >> 8);
733 }
734
735 CX18_INFO("Specified audioclock freq: %d Hz\n", state->audclk_freq);
736}
737
738/* ----------------------------------------------------------------------- */
739
740static void log_audio_status(struct cx18 *cx)
741{
742 struct cx18_av_state *state = &cx->av_state;
743 u8 download_ctl = cx18_av_read(cx, 0x803);
744 u8 mod_det_stat0 = cx18_av_read(cx, 0x805);
745 u8 mod_det_stat1 = cx18_av_read(cx, 0x804);
746 u8 audio_config = cx18_av_read(cx, 0x808);
747 u8 pref_mode = cx18_av_read(cx, 0x809);
748 u8 afc0 = cx18_av_read(cx, 0x80b);
749 u8 mute_ctl = cx18_av_read(cx, 0x8d3);
750 int aud_input = state->aud_input;
751 char *p;
752
753 switch (mod_det_stat0) {
754 case 0x00: p = "mono"; break;
755 case 0x01: p = "stereo"; break;
756 case 0x02: p = "dual"; break;
757 case 0x04: p = "tri"; break;
758 case 0x10: p = "mono with SAP"; break;
759 case 0x11: p = "stereo with SAP"; break;
760 case 0x12: p = "dual with SAP"; break;
761 case 0x14: p = "tri with SAP"; break;
762 case 0xfe: p = "forced mode"; break;
763 default: p = "not defined";
764 }
765 CX18_INFO("Detected audio mode: %s\n", p);
766
767 switch (mod_det_stat1) {
768 case 0x00: p = "BTSC"; break;
769 case 0x01: p = "EIAJ"; break;
770 case 0x02: p = "A2-M"; break;
771 case 0x03: p = "A2-BG"; break;
772 case 0x04: p = "A2-DK1"; break;
773 case 0x05: p = "A2-DK2"; break;
774 case 0x06: p = "A2-DK3"; break;
775 case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
776 case 0x08: p = "AM-L"; break;
777 case 0x09: p = "NICAM-BG"; break;
778 case 0x0a: p = "NICAM-DK"; break;
779 case 0x0b: p = "NICAM-I"; break;
780 case 0x0c: p = "NICAM-L"; break;
781 case 0x0d: p = "BTSC/EIAJ/A2-M Mono (4.5 MHz FMMono)"; break;
782 case 0xff: p = "no detected audio standard"; break;
783 default: p = "not defined";
784 }
785 CX18_INFO("Detected audio standard: %s\n", p);
786 CX18_INFO("Audio muted: %s\n",
787 (mute_ctl & 0x2) ? "yes" : "no");
788 CX18_INFO("Audio microcontroller: %s\n",
789 (download_ctl & 0x10) ? "running" : "stopped");
790
791 switch (audio_config >> 4) {
792 case 0x00: p = "BTSC"; break;
793 case 0x01: p = "EIAJ"; break;
794 case 0x02: p = "A2-M"; break;
795 case 0x03: p = "A2-BG"; break;
796 case 0x04: p = "A2-DK1"; break;
797 case 0x05: p = "A2-DK2"; break;
798 case 0x06: p = "A2-DK3"; break;
799 case 0x07: p = "A1 (6.0 MHz FM Mono)"; break;
800 case 0x08: p = "AM-L"; break;
801 case 0x09: p = "NICAM-BG"; break;
802 case 0x0a: p = "NICAM-DK"; break;
803 case 0x0b: p = "NICAM-I"; break;
804 case 0x0c: p = "NICAM-L"; break;
805 case 0x0d: p = "FM radio"; break;
806 case 0x0f: p = "automatic detection"; break;
807 default: p = "undefined";
808 }
809 CX18_INFO("Configured audio standard: %s\n", p);
810
811 if ((audio_config >> 4) < 0xF) {
812 switch (audio_config & 0xF) {
813 case 0x00: p = "MONO1 (LANGUAGE A/Mono L+R channel for BTSC, EIAJ, A2)"; break;
814 case 0x01: p = "MONO2 (LANGUAGE B)"; break;
815 case 0x02: p = "MONO3 (STEREO forced MONO)"; break;
816 case 0x03: p = "MONO4 (NICAM ANALOG-Language C/Analog Fallback)"; break;
817 case 0x04: p = "STEREO"; break;
818 case 0x05: p = "DUAL1 (AB)"; break;
819 case 0x06: p = "DUAL2 (AC) (FM)"; break;
820 case 0x07: p = "DUAL3 (BC) (FM)"; break;
821 case 0x08: p = "DUAL4 (AC) (AM)"; break;
822 case 0x09: p = "DUAL5 (BC) (AM)"; break;
823 case 0x0a: p = "SAP"; break;
824 default: p = "undefined";
825 }
826 CX18_INFO("Configured audio mode: %s\n", p);
827 } else {
828 switch (audio_config & 0xF) {
829 case 0x00: p = "BG"; break;
830 case 0x01: p = "DK1"; break;
831 case 0x02: p = "DK2"; break;
832 case 0x03: p = "DK3"; break;
833 case 0x04: p = "I"; break;
834 case 0x05: p = "L"; break;
835 case 0x06: p = "BTSC"; break;
836 case 0x07: p = "EIAJ"; break;
837 case 0x08: p = "A2-M"; break;
838 case 0x09: p = "FM Radio"; break;
839 case 0x0f: p = "automatic standard and mode detection"; break;
840 default: p = "undefined";
841 }
842 CX18_INFO("Configured audio system: %s\n", p);
843 }
844
845 if (aud_input)
846 CX18_INFO("Specified audio input: Tuner (In%d)\n",
847 aud_input);
848 else
849 CX18_INFO("Specified audio input: External\n");
850
851 switch (pref_mode & 0xf) {
852 case 0: p = "mono/language A"; break;
853 case 1: p = "language B"; break;
854 case 2: p = "language C"; break;
855 case 3: p = "analog fallback"; break;
856 case 4: p = "stereo"; break;
857 case 5: p = "language AC"; break;
858 case 6: p = "language BC"; break;
859 case 7: p = "language AB"; break;
860 default: p = "undefined";
861 }
862 CX18_INFO("Preferred audio mode: %s\n", p);
863
864 if ((audio_config & 0xf) == 0xf) {
865 switch ((afc0 >> 2) & 0x1) {
866 case 0: p = "system DK"; break;
867 case 1: p = "system L"; break;
868 }
869 CX18_INFO("Selected 65 MHz format: %s\n", p);
870
871 switch (afc0 & 0x3) {
872 case 0: p = "BTSC"; break;
873 case 1: p = "EIAJ"; break;
874 case 2: p = "A2-M"; break;
875 default: p = "undefined";
876 }
877 CX18_INFO("Selected 45 MHz format: %s\n", p);
878 }
879}
diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h
new file mode 100644
index 000000000000..786901d72e9a
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-av-core.h
@@ -0,0 +1,318 @@
1/*
2 * cx18 ADEC header
3 *
4 * Derived from cx25840-core.h
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23
24#ifndef _CX18_AV_CORE_H_
25#define _CX18_AV_CORE_H_
26
27struct cx18;
28
29enum cx18_av_video_input {
30 /* Composite video inputs In1-In8 */
31 CX18_AV_COMPOSITE1 = 1,
32 CX18_AV_COMPOSITE2,
33 CX18_AV_COMPOSITE3,
34 CX18_AV_COMPOSITE4,
35 CX18_AV_COMPOSITE5,
36 CX18_AV_COMPOSITE6,
37 CX18_AV_COMPOSITE7,
38 CX18_AV_COMPOSITE8,
39
40 /* S-Video inputs consist of one luma input (In1-In4) ORed with one
41 chroma input (In5-In8) */
42 CX18_AV_SVIDEO_LUMA1 = 0x10,
43 CX18_AV_SVIDEO_LUMA2 = 0x20,
44 CX18_AV_SVIDEO_LUMA3 = 0x30,
45 CX18_AV_SVIDEO_LUMA4 = 0x40,
46 CX18_AV_SVIDEO_CHROMA4 = 0x400,
47 CX18_AV_SVIDEO_CHROMA5 = 0x500,
48 CX18_AV_SVIDEO_CHROMA6 = 0x600,
49 CX18_AV_SVIDEO_CHROMA7 = 0x700,
50 CX18_AV_SVIDEO_CHROMA8 = 0x800,
51
52 /* S-Video aliases for common luma/chroma combinations */
53 CX18_AV_SVIDEO1 = 0x510,
54 CX18_AV_SVIDEO2 = 0x620,
55 CX18_AV_SVIDEO3 = 0x730,
56 CX18_AV_SVIDEO4 = 0x840,
57};
58
59enum cx18_av_audio_input {
60 /* Audio inputs: serial or In4-In8 */
61 CX18_AV_AUDIO_SERIAL,
62 CX18_AV_AUDIO4 = 4,
63 CX18_AV_AUDIO5,
64 CX18_AV_AUDIO6,
65 CX18_AV_AUDIO7,
66 CX18_AV_AUDIO8,
67};
68
69struct cx18_av_state {
70 int radio;
71 v4l2_std_id std;
72 enum cx18_av_video_input vid_input;
73 enum cx18_av_audio_input aud_input;
74 u32 audclk_freq;
75 int audmode;
76 int vbi_line_offset;
77 u32 id;
78 u32 rev;
79 int is_initialized;
80};
81
82
83/* Registers */
84#define CXADEC_CHIP_TYPE_TIGER 0x837
85#define CXADEC_CHIP_TYPE_MAKO 0x843
86
87#define CXADEC_HOST_REG1 0x000
88#define CXADEC_HOST_REG2 0x001
89
90#define CXADEC_CHIP_CTRL 0x100
91#define CXADEC_AFE_CTRL 0x104
92#define CXADEC_PLL_CTRL1 0x108
93#define CXADEC_VID_PLL_FRAC 0x10C
94#define CXADEC_AUX_PLL_FRAC 0x110
95#define CXADEC_PIN_CTRL1 0x114
96#define CXADEC_PIN_CTRL2 0x118
97#define CXADEC_PIN_CFG1 0x11C
98#define CXADEC_PIN_CFG2 0x120
99
100#define CXADEC_PIN_CFG3 0x124
101#define CXADEC_I2S_MCLK 0x127
102
103#define CXADEC_AUD_LOCK1 0x128
104#define CXADEC_AUD_LOCK2 0x12C
105#define CXADEC_POWER_CTRL 0x130
106#define CXADEC_AFE_DIAG_CTRL1 0x134
107#define CXADEC_AFE_DIAG_CTRL2 0x138
108#define CXADEC_AFE_DIAG_CTRL3 0x13C
109#define CXADEC_PLL_DIAG_CTRL 0x140
110#define CXADEC_TEST_CTRL1 0x144
111#define CXADEC_TEST_CTRL2 0x148
112#define CXADEC_BIST_STAT 0x14C
113#define CXADEC_DLL1_DIAG_CTRL 0x158
114#define CXADEC_DLL2_DIAG_CTRL 0x15C
115
116/* IR registers */
117#define CXADEC_IR_CTRL_REG 0x200
118#define CXADEC_IR_TXCLK_REG 0x204
119#define CXADEC_IR_RXCLK_REG 0x208
120#define CXADEC_IR_CDUTY_REG 0x20C
121#define CXADEC_IR_STAT_REG 0x210
122#define CXADEC_IR_IRQEN_REG 0x214
123#define CXADEC_IR_FILTER_REG 0x218
124#define CXADEC_IR_FIFO_REG 0x21C
125
126/* Video Registers */
127#define CXADEC_MODE_CTRL 0x400
128#define CXADEC_OUT_CTRL1 0x404
129#define CXADEC_OUT_CTRL2 0x408
130#define CXADEC_GEN_STAT 0x40C
131#define CXADEC_INT_STAT_MASK 0x410
132#define CXADEC_LUMA_CTRL 0x414
133
134#define CXADEC_BRIGHTNESS_CTRL_BYTE 0x414
135#define CXADEC_CONTRAST_CTRL_BYTE 0x415
136#define CXADEC_LUMA_CTRL_BYTE_3 0x416
137
138#define CXADEC_HSCALE_CTRL 0x418
139#define CXADEC_VSCALE_CTRL 0x41C
140
141#define CXADEC_CHROMA_CTRL 0x420
142
143#define CXADEC_USAT_CTRL_BYTE 0x420
144#define CXADEC_VSAT_CTRL_BYTE 0x421
145#define CXADEC_HUE_CTRL_BYTE 0x422
146
147#define CXADEC_VBI_LINE_CTRL1 0x424
148#define CXADEC_VBI_LINE_CTRL2 0x428
149#define CXADEC_VBI_LINE_CTRL3 0x42C
150#define CXADEC_VBI_LINE_CTRL4 0x430
151#define CXADEC_VBI_LINE_CTRL5 0x434
152#define CXADEC_VBI_FC_CFG 0x438
153#define CXADEC_VBI_MISC_CFG1 0x43C
154#define CXADEC_VBI_MISC_CFG2 0x440
155#define CXADEC_VBI_PAY1 0x444
156#define CXADEC_VBI_PAY2 0x448
157#define CXADEC_VBI_CUST1_CFG1 0x44C
158#define CXADEC_VBI_CUST1_CFG2 0x450
159#define CXADEC_VBI_CUST1_CFG3 0x454
160#define CXADEC_VBI_CUST2_CFG1 0x458
161#define CXADEC_VBI_CUST2_CFG2 0x45C
162#define CXADEC_VBI_CUST2_CFG3 0x460
163#define CXADEC_VBI_CUST3_CFG1 0x464
164#define CXADEC_VBI_CUST3_CFG2 0x468
165#define CXADEC_VBI_CUST3_CFG3 0x46C
166#define CXADEC_HORIZ_TIM_CTRL 0x470
167#define CXADEC_VERT_TIM_CTRL 0x474
168#define CXADEC_SRC_COMB_CFG 0x478
169#define CXADEC_CHROMA_VBIOFF_CFG 0x47C
170#define CXADEC_FIELD_COUNT 0x480
171#define CXADEC_MISC_TIM_CTRL 0x484
172#define CXADEC_DFE_CTRL1 0x488
173#define CXADEC_DFE_CTRL2 0x48C
174#define CXADEC_DFE_CTRL3 0x490
175#define CXADEC_PLL_CTRL2 0x494
176#define CXADEC_HTL_CTRL 0x498
177#define CXADEC_COMB_CTRL 0x49C
178#define CXADEC_CRUSH_CTRL 0x4A0
179#define CXADEC_SOFT_RST_CTRL 0x4A4
180#define CXADEC_MV_DT_CTRL2 0x4A8
181#define CXADEC_MV_DT_CTRL3 0x4AC
182#define CXADEC_MISC_DIAG_CTRL 0x4B8
183
184#define CXADEC_DL_CTL 0x800
185#define CXADEC_DL_CTL_ADDRESS_LOW 0x800 /* Byte 1 in DL_CTL */
186#define CXADEC_DL_CTL_ADDRESS_HIGH 0x801 /* Byte 2 in DL_CTL */
187#define CXADEC_DL_CTL_DATA 0x802 /* Byte 3 in DL_CTL */
188#define CXADEC_DL_CTL_CONTROL 0x803 /* Byte 4 in DL_CTL */
189
190#define CXADEC_STD_DET_STATUS 0x804
191
192#define CXADEC_STD_DET_CTL 0x808
193#define CXADEC_STD_DET_CTL_AUD_CTL 0x808 /* Byte 1 in STD_DET_CTL */
194#define CXADEC_STD_DET_CTL_PREF_MODE 0x809 /* Byte 2 in STD_DET_CTL */
195
196#define CXADEC_DW8051_INT 0x80C
197#define CXADEC_GENERAL_CTL 0x810
198#define CXADEC_AAGC_CTL 0x814
199#define CXADEC_IF_SRC_CTL 0x818
200#define CXADEC_ANLOG_DEMOD_CTL 0x81C
201#define CXADEC_ROT_FREQ_CTL 0x820
202#define CXADEC_FM1_CTL 0x824
203#define CXADEC_PDF_CTL 0x828
204#define CXADEC_DFT1_CTL1 0x82C
205#define CXADEC_DFT1_CTL2 0x830
206#define CXADEC_DFT_STATUS 0x834
207#define CXADEC_DFT2_CTL1 0x838
208#define CXADEC_DFT2_CTL2 0x83C
209#define CXADEC_DFT2_STATUS 0x840
210#define CXADEC_DFT3_CTL1 0x844
211#define CXADEC_DFT3_CTL2 0x848
212#define CXADEC_DFT3_STATUS 0x84C
213#define CXADEC_DFT4_CTL1 0x850
214#define CXADEC_DFT4_CTL2 0x854
215#define CXADEC_DFT4_STATUS 0x858
216#define CXADEC_AM_MTS_DET 0x85C
217#define CXADEC_ANALOG_MUX_CTL 0x860
218#define CXADEC_DIG_PLL_CTL1 0x864
219#define CXADEC_DIG_PLL_CTL2 0x868
220#define CXADEC_DIG_PLL_CTL3 0x86C
221#define CXADEC_DIG_PLL_CTL4 0x870
222#define CXADEC_DIG_PLL_CTL5 0x874
223#define CXADEC_DEEMPH_GAIN_CTL 0x878
224#define CXADEC_DEEMPH_COEF1 0x87C
225#define CXADEC_DEEMPH_COEF2 0x880
226#define CXADEC_DBX1_CTL1 0x884
227#define CXADEC_DBX1_CTL2 0x888
228#define CXADEC_DBX1_STATUS 0x88C
229#define CXADEC_DBX2_CTL1 0x890
230#define CXADEC_DBX2_CTL2 0x894
231#define CXADEC_DBX2_STATUS 0x898
232#define CXADEC_AM_FM_DIFF 0x89C
233
234/* NICAM registers go here */
235#define CXADEC_NICAM_STATUS 0x8C8
236#define CXADEC_DEMATRIX_CTL 0x8CC
237
238#define CXADEC_PATH1_CTL1 0x8D0
239#define CXADEC_PATH1_VOL_CTL 0x8D4
240#define CXADEC_PATH1_EQ_CTL 0x8D8
241#define CXADEC_PATH1_SC_CTL 0x8DC
242
243#define CXADEC_PATH2_CTL1 0x8E0
244#define CXADEC_PATH2_VOL_CTL 0x8E4
245#define CXADEC_PATH2_EQ_CTL 0x8E8
246#define CXADEC_PATH2_SC_CTL 0x8EC
247
248#define CXADEC_SRC_CTL 0x8F0
249#define CXADEC_SRC_LF_COEF 0x8F4
250#define CXADEC_SRC1_CTL 0x8F8
251#define CXADEC_SRC2_CTL 0x8FC
252#define CXADEC_SRC3_CTL 0x900
253#define CXADEC_SRC4_CTL 0x904
254#define CXADEC_SRC5_CTL 0x908
255#define CXADEC_SRC6_CTL 0x90C
256
257#define CXADEC_BASEBAND_OUT_SEL 0x910
258#define CXADEC_I2S_IN_CTL 0x914
259#define CXADEC_I2S_OUT_CTL 0x918
260#define CXADEC_AC97_CTL 0x91C
261#define CXADEC_QAM_PDF 0x920
262#define CXADEC_QAM_CONST_DEC 0x924
263#define CXADEC_QAM_ROTATOR_FREQ 0x948
264
265/* Bit defintions / settings used in Mako Audio */
266#define CXADEC_PREF_MODE_MONO_LANGA 0
267#define CXADEC_PREF_MODE_MONO_LANGB 1
268#define CXADEC_PREF_MODE_MONO_LANGC 2
269#define CXADEC_PREF_MODE_FALLBACK 3
270#define CXADEC_PREF_MODE_STEREO 4
271#define CXADEC_PREF_MODE_DUAL_LANG_AC 5
272#define CXADEC_PREF_MODE_DUAL_LANG_BC 6
273#define CXADEC_PREF_MODE_DUAL_LANG_AB 7
274
275
276#define CXADEC_DETECT_STEREO 1
277#define CXADEC_DETECT_DUAL 2
278#define CXADEC_DETECT_TRI 4
279#define CXADEC_DETECT_SAP 0x10
280#define CXADEC_DETECT_NO_SIGNAL 0xFF
281
282#define CXADEC_SELECT_AUDIO_STANDARD_BG 0xF0 /* NICAM BG and A2 BG */
283#define CXADEC_SELECT_AUDIO_STANDARD_DK1 0xF1 /* NICAM DK and A2 DK */
284#define CXADEC_SELECT_AUDIO_STANDARD_DK2 0xF2
285#define CXADEC_SELECT_AUDIO_STANDARD_DK3 0xF3
286#define CXADEC_SELECT_AUDIO_STANDARD_I 0xF4 /* NICAM I and A1 */
287#define CXADEC_SELECT_AUDIO_STANDARD_L 0xF5 /* NICAM L and System L AM */
288#define CXADEC_SELECT_AUDIO_STANDARD_BTSC 0xF6
289#define CXADEC_SELECT_AUDIO_STANDARD_EIAJ 0xF7
290#define CXADEC_SELECT_AUDIO_STANDARD_A2_M 0xF8 /* A2 M */
291#define CXADEC_SELECT_AUDIO_STANDARD_FM 0xF9 /* FM radio */
292#define CXADEC_SELECT_AUDIO_STANDARD_AUTO 0xFF /* Auto detect */
293
294/* ----------------------------------------------------------------------- */
295/* cx18_av-core.c */
296int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
297int cx18_av_write4(struct cx18 *cx, u16 addr, u32 value);
298u8 cx18_av_read(struct cx18 *cx, u16 addr);
299u32 cx18_av_read4(struct cx18 *cx, u16 addr);
300int cx18_av_and_or(struct cx18 *cx, u16 addr, unsigned mask, u8 value);
301int cx18_av_and_or4(struct cx18 *cx, u16 addr, u32 mask, u32 value);
302int cx18_av_cmd(struct cx18 *cx, unsigned int cmd, void *arg);
303
304/* ----------------------------------------------------------------------- */
305/* cx18_av-firmware.c */
306int cx18_av_loadfw(struct cx18 *cx);
307
308/* ----------------------------------------------------------------------- */
309/* cx18_av-audio.c */
310int cx18_av_audio(struct cx18 *cx, unsigned int cmd, void *arg);
311void cx18_av_audio_set_path(struct cx18 *cx);
312
313/* ----------------------------------------------------------------------- */
314/* cx18_av-vbi.c */
315void cx18_av_vbi_setup(struct cx18 *cx);
316int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg);
317
318#endif
diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c
new file mode 100644
index 000000000000..526e142156cd
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-av-firmware.c
@@ -0,0 +1,120 @@
1/*
2 * cx18 ADEC firmware functions
3 *
4 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301, USA.
20 */
21
22#include "cx18-driver.h"
23#include <linux/firmware.h>
24
25#define FWFILE "v4l-cx23418-dig.fw"
26
27int cx18_av_loadfw(struct cx18 *cx)
28{
29 const struct firmware *fw = NULL;
30 u32 size;
31 u32 v;
32 u8 *ptr;
33 int i;
34
35 if (request_firmware(&fw, FWFILE, &cx->dev->dev) != 0) {
36 CX18_ERR("unable to open firmware %s\n", FWFILE);
37 return -EINVAL;
38 }
39
40 cx18_av_write4(cx, CXADEC_CHIP_CTRL, 0x00010000);
41 cx18_av_write(cx, CXADEC_STD_DET_CTL, 0xf6); /* Byte 0 */
42
43 /* Reset the Mako core (Register is undocumented.) */
44 cx18_av_write4(cx, 0x8100, 0x00010000);
45
46 /* Put the 8051 in reset and enable firmware upload */
47 cx18_av_write4(cx, CXADEC_DL_CTL, 0x0F000000);
48
49 ptr = fw->data;
50 size = fw->size;
51
52 for (i = 0; i < size; i++) {
53 u32 dl_control = 0x0F000000 | ((u32)ptr[i] << 16);
54 u32 value = 0;
55 int retries;
56
57 for (retries = 0; retries < 5; retries++) {
58 cx18_av_write4(cx, CXADEC_DL_CTL, dl_control);
59 value = cx18_av_read4(cx, CXADEC_DL_CTL);
60 if ((value & 0x3F00) == (dl_control & 0x3F00))
61 break;
62 }
63 if (retries >= 5) {
64 CX18_ERR("unable to load firmware %s\n", FWFILE);
65 release_firmware(fw);
66 return -EIO;
67 }
68 }
69
70 cx18_av_write4(cx, CXADEC_DL_CTL, 0x13000000 | fw->size);
71
72 /* Output to the 416 */
73 cx18_av_and_or4(cx, CXADEC_PIN_CTRL1, ~0, 0x78000);
74
75 /* Audio input control 1 set to Sony mode */
76 /* Audio output input 2 is 0 for slave operation input */
77 /* 0xC4000914[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */
78 /* 0xC4000914[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge
79 after WS transition for first bit of audio word. */
80 cx18_av_write4(cx, CXADEC_I2S_IN_CTL, 0x000000A0);
81
82 /* Audio output control 1 is set to Sony mode */
83 /* Audio output control 2 is set to 1 for master mode */
84 /* 0xC4000918[5]: 0 = left sample on WS=0, 1 = left sample on WS=1 */
85 /* 0xC4000918[7]: 0 = Philips mode, 1 = Sony mode (1st SCK rising edge
86 after WS transition for first bit of audio word. */
87 /* 0xC4000918[8]: 0 = slave operation, 1 = master (SCK_OUT and WS_OUT
88 are generated) */
89 cx18_av_write4(cx, CXADEC_I2S_OUT_CTL, 0x000001A0);
90
91 /* set alt I2s master clock to /16 and enable alt divider i2s
92 passthrough */
93 cx18_av_write4(cx, CXADEC_PIN_CFG3, 0x5000B687);
94
95 cx18_av_write4(cx, CXADEC_STD_DET_CTL, 0x000000F6);
96 /* CxDevWrReg(CXADEC_STD_DET_CTL, 0x000000FF); */
97
98 /* Set bit 0 in register 0x9CC to signify that this is MiniMe. */
99 /* Register 0x09CC is defined by the Merlin firmware, and doesn't
100 have a name in the spec. */
101 cx18_av_write4(cx, 0x09CC, 1);
102
103#define CX18_AUDIO_ENABLE 0xc72014
104 v = read_reg(CX18_AUDIO_ENABLE);
105 /* If bit 11 is 1 */
106 if (v & 0x800)
107 write_reg(v & 0xFFFFFBFF, CX18_AUDIO_ENABLE); /* Clear bit 10 */
108
109 /* Enable WW auto audio standard detection */
110 v = cx18_av_read4(cx, CXADEC_STD_DET_CTL);
111 v |= 0xFF; /* Auto by default */
112 v |= 0x400; /* Stereo by default */
113 v |= 0x14000000;
114 cx18_av_write4(cx, CXADEC_STD_DET_CTL, v);
115
116 release_firmware(fw);
117
118 CX18_INFO("loaded %s firmware (%d bytes)\n", FWFILE, size);
119 return 0;
120}
diff --git a/drivers/media/video/cx18/cx18-av-vbi.c b/drivers/media/video/cx18/cx18-av-vbi.c
new file mode 100644
index 000000000000..d09f1daf4ebf
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-av-vbi.c
@@ -0,0 +1,413 @@
1/*
2 * cx18 ADEC VBI functions
3 *
4 * Derived from cx25840-vbi.c
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 * 02110-1301, USA.
22 */
23
24
25#include "cx18-driver.h"
26
27static int odd_parity(u8 c)
28{
29 c ^= (c >> 4);
30 c ^= (c >> 2);
31 c ^= (c >> 1);
32
33 return c & 1;
34}
35
36static int decode_vps(u8 *dst, u8 *p)
37{
38 static const u8 biphase_tbl[] = {
39 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
40 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
41 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
42 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
43 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
44 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
45 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
46 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
47 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
48 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
49 0xc3, 0x4b, 0x43, 0xc3, 0x87, 0x0f, 0x07, 0x87,
50 0x83, 0x0b, 0x03, 0x83, 0xc3, 0x4b, 0x43, 0xc3,
51 0xc1, 0x49, 0x41, 0xc1, 0x85, 0x0d, 0x05, 0x85,
52 0x81, 0x09, 0x01, 0x81, 0xc1, 0x49, 0x41, 0xc1,
53 0xe1, 0x69, 0x61, 0xe1, 0xa5, 0x2d, 0x25, 0xa5,
54 0xa1, 0x29, 0x21, 0xa1, 0xe1, 0x69, 0x61, 0xe1,
55 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
56 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
57 0xc2, 0x4a, 0x42, 0xc2, 0x86, 0x0e, 0x06, 0x86,
58 0x82, 0x0a, 0x02, 0x82, 0xc2, 0x4a, 0x42, 0xc2,
59 0xc0, 0x48, 0x40, 0xc0, 0x84, 0x0c, 0x04, 0x84,
60 0x80, 0x08, 0x00, 0x80, 0xc0, 0x48, 0x40, 0xc0,
61 0xe0, 0x68, 0x60, 0xe0, 0xa4, 0x2c, 0x24, 0xa4,
62 0xa0, 0x28, 0x20, 0xa0, 0xe0, 0x68, 0x60, 0xe0,
63 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
64 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
65 0xd2, 0x5a, 0x52, 0xd2, 0x96, 0x1e, 0x16, 0x96,
66 0x92, 0x1a, 0x12, 0x92, 0xd2, 0x5a, 0x52, 0xd2,
67 0xd0, 0x58, 0x50, 0xd0, 0x94, 0x1c, 0x14, 0x94,
68 0x90, 0x18, 0x10, 0x90, 0xd0, 0x58, 0x50, 0xd0,
69 0xf0, 0x78, 0x70, 0xf0, 0xb4, 0x3c, 0x34, 0xb4,
70 0xb0, 0x38, 0x30, 0xb0, 0xf0, 0x78, 0x70, 0xf0,
71 };
72
73 u8 c, err = 0;
74 int i;
75
76 for (i = 0; i < 2 * 13; i += 2) {
77 err |= biphase_tbl[p[i]] | biphase_tbl[p[i + 1]];
78 c = (biphase_tbl[p[i + 1]] & 0xf) |
79 ((biphase_tbl[p[i]] & 0xf) << 4);
80 dst[i / 2] = c;
81 }
82
83 return err & 0xf0;
84}
85
86void cx18_av_vbi_setup(struct cx18 *cx)
87{
88 struct cx18_av_state *state = &cx->av_state;
89 v4l2_std_id std = state->std;
90 int hblank, hactive, burst, vblank, vactive, sc;
91 int vblank656, src_decimation;
92 int luma_lpf, uv_lpf, comb;
93 u32 pll_int, pll_frac, pll_post;
94
95 /* datasheet startup, step 8d */
96 if (std & ~V4L2_STD_NTSC)
97 cx18_av_write(cx, 0x49f, 0x11);
98 else
99 cx18_av_write(cx, 0x49f, 0x14);
100
101 if (std & V4L2_STD_625_50) {
102 hblank = 0x084;
103 hactive = 0x2d0;
104 burst = 0x5d;
105 vblank = 0x024;
106 vactive = 0x244;
107 vblank656 = 0x28;
108 src_decimation = 0x21f;
109
110 luma_lpf = 2;
111 if (std & V4L2_STD_SECAM) {
112 uv_lpf = 0;
113 comb = 0;
114 sc = 0x0a425f;
115 } else if (std == V4L2_STD_PAL_Nc) {
116 uv_lpf = 1;
117 comb = 0x20;
118 sc = 556453;
119 } else {
120 uv_lpf = 1;
121 comb = 0x20;
122 sc = 0x0a8263;
123 }
124 } else {
125 hactive = 720;
126 hblank = 122;
127 vactive = 487;
128 luma_lpf = 1;
129 uv_lpf = 1;
130
131 src_decimation = 0x21f;
132 if (std == V4L2_STD_PAL_60) {
133 vblank = 26;
134 vblank656 = 26;
135 burst = 0x5b;
136 luma_lpf = 2;
137 comb = 0x20;
138 sc = 0x0a8263;
139 } else if (std == V4L2_STD_PAL_M) {
140 vblank = 20;
141 vblank656 = 24;
142 burst = 0x61;
143 comb = 0x20;
144
145 sc = 555452;
146 } else {
147 vblank = 26;
148 vblank656 = 26;
149 burst = 0x5b;
150 comb = 0x66;
151 sc = 556063;
152 }
153 }
154
155 /* DEBUG: Displays configured PLL frequency */
156 pll_int = cx18_av_read(cx, 0x108);
157 pll_frac = cx18_av_read4(cx, 0x10c) & 0x1ffffff;
158 pll_post = cx18_av_read(cx, 0x109);
159 CX18_DEBUG_INFO("PLL regs = int: %u, frac: %u, post: %u\n",
160 pll_int, pll_frac, pll_post);
161
162 if (pll_post) {
163 int fin, fsc;
164 int pll = 28636363L * ((((u64)pll_int) << 25) + pll_frac);
165
166 pll >>= 25;
167 pll /= pll_post;
168 CX18_DEBUG_INFO("PLL = %d.%06d MHz\n",
169 pll / 1000000, pll % 1000000);
170 CX18_DEBUG_INFO("PLL/8 = %d.%06d MHz\n",
171 pll / 8000000, (pll / 8) % 1000000);
172
173 fin = ((u64)src_decimation * pll) >> 12;
174 CX18_DEBUG_INFO("ADC Sampling freq = %d.%06d MHz\n",
175 fin / 1000000, fin % 1000000);
176
177 fsc = (((u64)sc) * pll) >> 24L;
178 CX18_DEBUG_INFO("Chroma sub-carrier freq = %d.%06d MHz\n",
179 fsc / 1000000, fsc % 1000000);
180
181 CX18_DEBUG_INFO("hblank %i, hactive %i, "
182 "vblank %i , vactive %i, vblank656 %i, src_dec %i,"
183 "burst 0x%02x, luma_lpf %i, uv_lpf %i, comb 0x%02x,"
184 " sc 0x%06x\n",
185 hblank, hactive, vblank, vactive, vblank656,
186 src_decimation, burst, luma_lpf, uv_lpf, comb, sc);
187 }
188
189 /* Sets horizontal blanking delay and active lines */
190 cx18_av_write(cx, 0x470, hblank);
191 cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) |
192 (hactive << 4)));
193 cx18_av_write(cx, 0x472, hactive >> 4);
194
195 /* Sets burst gate delay */
196 cx18_av_write(cx, 0x473, burst);
197
198 /* Sets vertical blanking delay and active duration */
199 cx18_av_write(cx, 0x474, vblank);
200 cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) |
201 (vactive << 4)));
202 cx18_av_write(cx, 0x476, vactive >> 4);
203 cx18_av_write(cx, 0x477, vblank656);
204
205 /* Sets src decimation rate */
206 cx18_av_write(cx, 0x478, 0xff & src_decimation);
207 cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8));
208
209 /* Sets Luma and UV Low pass filters */
210 cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30));
211
212 /* Enables comb filters */
213 cx18_av_write(cx, 0x47b, comb);
214
215 /* Sets SC Step*/
216 cx18_av_write(cx, 0x47c, sc);
217 cx18_av_write(cx, 0x47d, 0xff & sc >> 8);
218 cx18_av_write(cx, 0x47e, 0xff & sc >> 16);
219
220 /* Sets VBI parameters */
221 if (std & V4L2_STD_625_50) {
222 cx18_av_write(cx, 0x47f, 0x01);
223 state->vbi_line_offset = 5;
224 } else {
225 cx18_av_write(cx, 0x47f, 0x00);
226 state->vbi_line_offset = 8;
227 }
228}
229
230int cx18_av_vbi(struct cx18 *cx, unsigned int cmd, void *arg)
231{
232 struct cx18_av_state *state = &cx->av_state;
233 struct v4l2_format *fmt;
234 struct v4l2_sliced_vbi_format *svbi;
235
236 switch (cmd) {
237 case VIDIOC_G_FMT:
238 {
239 static u16 lcr2vbi[] = {
240 0, V4L2_SLICED_TELETEXT_B, 0, /* 1 */
241 0, V4L2_SLICED_WSS_625, 0, /* 4 */
242 V4L2_SLICED_CAPTION_525, /* 6 */
243 0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */
244 0, 0, 0, 0
245 };
246 int is_pal = !(state->std & V4L2_STD_525_60);
247 int i;
248
249 fmt = arg;
250 if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
251 return -EINVAL;
252 svbi = &fmt->fmt.sliced;
253 memset(svbi, 0, sizeof(*svbi));
254 /* we're done if raw VBI is active */
255 if ((cx18_av_read(cx, 0x404) & 0x10) == 0)
256 break;
257
258 if (is_pal) {
259 for (i = 7; i <= 23; i++) {
260 u8 v = cx18_av_read(cx, 0x424 + i - 7);
261
262 svbi->service_lines[0][i] = lcr2vbi[v >> 4];
263 svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
264 svbi->service_set |= svbi->service_lines[0][i] |
265 svbi->service_lines[1][i];
266 }
267 } else {
268 for (i = 10; i <= 21; i++) {
269 u8 v = cx18_av_read(cx, 0x424 + i - 10);
270
271 svbi->service_lines[0][i] = lcr2vbi[v >> 4];
272 svbi->service_lines[1][i] = lcr2vbi[v & 0xf];
273 svbi->service_set |= svbi->service_lines[0][i] |
274 svbi->service_lines[1][i];
275 }
276 }
277 break;
278 }
279
280 case VIDIOC_S_FMT:
281 {
282 int is_pal = !(state->std & V4L2_STD_525_60);
283 int vbi_offset = is_pal ? 1 : 0;
284 int i, x;
285 u8 lcr[24];
286
287 fmt = arg;
288 if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
289 return -EINVAL;
290 svbi = &fmt->fmt.sliced;
291 if (svbi->service_set == 0) {
292 /* raw VBI */
293 memset(svbi, 0, sizeof(*svbi));
294
295 /* Setup VBI */
296 cx18_av_vbi_setup(cx);
297
298 /* VBI Offset */
299 cx18_av_write(cx, 0x47f, vbi_offset);
300 cx18_av_write(cx, 0x404, 0x2e);
301 break;
302 }
303
304 for (x = 0; x <= 23; x++)
305 lcr[x] = 0x00;
306
307 /* Setup VBI */
308 cx18_av_vbi_setup(cx);
309
310 /* Sliced VBI */
311 cx18_av_write(cx, 0x404, 0x32); /* Ancillary data */
312 cx18_av_write(cx, 0x406, 0x13);
313 cx18_av_write(cx, 0x47f, vbi_offset);
314
315 if (is_pal) {
316 for (i = 0; i <= 6; i++)
317 svbi->service_lines[0][i] =
318 svbi->service_lines[1][i] = 0;
319 } else {
320 for (i = 0; i <= 9; i++)
321 svbi->service_lines[0][i] =
322 svbi->service_lines[1][i] = 0;
323
324 for (i = 22; i <= 23; i++)
325 svbi->service_lines[0][i] =
326 svbi->service_lines[1][i] = 0;
327 }
328
329 for (i = 7; i <= 23; i++) {
330 for (x = 0; x <= 1; x++) {
331 switch (svbi->service_lines[1-x][i]) {
332 case V4L2_SLICED_TELETEXT_B:
333 lcr[i] |= 1 << (4 * x);
334 break;
335 case V4L2_SLICED_WSS_625:
336 lcr[i] |= 4 << (4 * x);
337 break;
338 case V4L2_SLICED_CAPTION_525:
339 lcr[i] |= 6 << (4 * x);
340 break;
341 case V4L2_SLICED_VPS:
342 lcr[i] |= 9 << (4 * x);
343 break;
344 }
345 }
346 }
347
348 if (is_pal) {
349 for (x = 1, i = 0x424; i <= 0x434; i++, x++)
350 cx18_av_write(cx, i, lcr[6 + x]);
351 } else {
352 for (x = 1, i = 0x424; i <= 0x430; i++, x++)
353 cx18_av_write(cx, i, lcr[9 + x]);
354 for (i = 0x431; i <= 0x434; i++)
355 cx18_av_write(cx, i, 0);
356 }
357
358 cx18_av_write(cx, 0x43c, 0x16);
359 cx18_av_write(cx, 0x474, is_pal ? 0x2a : 0x22);
360 break;
361 }
362
363 case VIDIOC_INT_DECODE_VBI_LINE:
364 {
365 struct v4l2_decode_vbi_line *vbi = arg;
366 u8 *p = vbi->p;
367 int id1, id2, l, err = 0;
368
369 if (p[0] || p[1] != 0xff || p[2] != 0xff ||
370 (p[3] != 0x55 && p[3] != 0x91)) {
371 vbi->line = vbi->type = 0;
372 break;
373 }
374
375 p += 4;
376 id1 = p[-1];
377 id2 = p[0] & 0xf;
378 l = p[2] & 0x3f;
379 l += state->vbi_line_offset;
380 p += 4;
381
382 switch (id2) {
383 case 1:
384 id2 = V4L2_SLICED_TELETEXT_B;
385 break;
386 case 4:
387 id2 = V4L2_SLICED_WSS_625;
388 break;
389 case 6:
390 id2 = V4L2_SLICED_CAPTION_525;
391 err = !odd_parity(p[0]) || !odd_parity(p[1]);
392 break;
393 case 9:
394 id2 = V4L2_SLICED_VPS;
395 if (decode_vps(p, p) != 0)
396 err = 1;
397 break;
398 default:
399 id2 = 0;
400 err = 1;
401 break;
402 }
403
404 vbi->type = err ? 0 : id2;
405 vbi->line = err ? 0 : l;
406 vbi->is_second_field = err ? 0 : (id1 == 0x55);
407 vbi->p = p;
408 break;
409 }
410 }
411
412 return 0;
413}
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
new file mode 100644
index 000000000000..f5e3ba1f5354
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -0,0 +1,277 @@
1/*
2 * cx18 functions to query card hardware
3 *
4 * Derived from ivtv-cards.c
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 */
23
24#include "cx18-driver.h"
25#include "cx18-cards.h"
26#include "cx18-i2c.h"
27#include <media/cs5345.h>
28
29/********************** card configuration *******************************/
30
31/* usual i2c tuner addresses to probe */
32static struct cx18_card_tuner_i2c cx18_i2c_std = {
33 .radio = { I2C_CLIENT_END },
34 .demod = { 0x43, I2C_CLIENT_END },
35 .tv = { 0x61, 0x60, I2C_CLIENT_END },
36};
37
38/* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii
39 This keeps the PCI ID database up to date. Note that the entries
40 must be added under vendor 0x4444 (Conexant) as subsystem IDs.
41 New vendor IDs should still be added to the vendor ID list. */
42
43/* Hauppauge HVR-1600 cards */
44
45/* Note: for Hauppauge cards the tveeprom information is used instead
46 of PCI IDs */
47static const struct cx18_card cx18_card_hvr1600_esmt = {
48 .type = CX18_CARD_HVR_1600_ESMT,
49 .name = "Hauppauge HVR-1600",
50 .comment = "DVB & VBI are not yet supported\n",
51 .v4l2_capabilities = CX18_CAP_ENCODER,
52 .hw_audio_ctrl = CX18_HW_CX23418,
53 .hw_muxer = CX18_HW_CS5345,
54 .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER | CX18_HW_CS5345,
55 .video_inputs = {
56 { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 },
57 { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 },
58 { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
59 { CX18_CARD_INPUT_SVIDEO2, 2, CX23418_SVIDEO2 },
60 { CX18_CARD_INPUT_COMPOSITE2, 2, CX23418_COMPOSITE4 },
61 },
62 .audio_inputs = {
63 { CX18_CARD_INPUT_AUD_TUNER,
64 CX23418_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
65 { CX18_CARD_INPUT_LINE_IN1,
66 CX23418_AUDIO_SERIAL, CS5345_IN_2 },
67 { CX18_CARD_INPUT_LINE_IN2,
68 CX23418_AUDIO_SERIAL, CS5345_IN_2 },
69 },
70 .radio_input = { CX18_CARD_INPUT_AUD_TUNER,
71 CX23418_AUDIO_SERIAL, 0 },
72 .ddr = {
73 /* ESMT M13S128324A-5B memory */
74 .chip_config = 0x003,
75 .refresh = 0x30c,
76 .timing1 = 0x44220e82,
77 .timing2 = 0x08,
78 .tune_lane = 0,
79 .initial_emrs = 0,
80 },
81 .gpio_init.initial_value = 0x3001,
82 .gpio_init.direction = 0x3001,
83 .i2c = &cx18_i2c_std,
84};
85
86static const struct cx18_card cx18_card_hvr1600_samsung = {
87 .type = CX18_CARD_HVR_1600_SAMSUNG,
88 .name = "Hauppauge HVR-1600 (Preproduction)",
89 .comment = "DVB & VBI are not yet supported\n",
90 .v4l2_capabilities = CX18_CAP_ENCODER,
91 .hw_audio_ctrl = CX18_HW_CX23418,
92 .hw_muxer = CX18_HW_CS5345,
93 .hw_all = CX18_HW_TVEEPROM | CX18_HW_TUNER | CX18_HW_CS5345,
94 .video_inputs = {
95 { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 },
96 { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 },
97 { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
98 { CX18_CARD_INPUT_SVIDEO2, 2, CX23418_SVIDEO2 },
99 { CX18_CARD_INPUT_COMPOSITE2, 2, CX23418_COMPOSITE4 },
100 },
101 .audio_inputs = {
102 { CX18_CARD_INPUT_AUD_TUNER,
103 CX23418_AUDIO8, CS5345_IN_1 | CS5345_MCLK_1_5 },
104 { CX18_CARD_INPUT_LINE_IN1,
105 CX23418_AUDIO_SERIAL, CS5345_IN_2 },
106 { CX18_CARD_INPUT_LINE_IN2,
107 CX23418_AUDIO_SERIAL, CS5345_IN_2 },
108 },
109 .radio_input = { CX18_CARD_INPUT_AUD_TUNER,
110 CX23418_AUDIO_SERIAL, 0 },
111 .ddr = {
112 /* Samsung K4D263238G-VC33 memory */
113 .chip_config = 0x003,
114 .refresh = 0x30c,
115 .timing1 = 0x23230b73,
116 .timing2 = 0x08,
117 .tune_lane = 0,
118 .initial_emrs = 2,
119 },
120 .gpio_init.initial_value = 0x3001,
121 .gpio_init.direction = 0x3001,
122 .i2c = &cx18_i2c_std,
123};
124
125/* ------------------------------------------------------------------------- */
126
127/* Compro VideoMate H900: not working at the moment! */
128
129static const struct cx18_card_pci_info cx18_pci_h900[] = {
130 { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_COMPRO, 0xe100 },
131 { 0, 0, 0 }
132};
133
134static const struct cx18_card cx18_card_h900 = {
135 .type = CX18_CARD_COMPRO_H900,
136 .name = "Compro VideoMate H900",
137 .comment = "Not yet supported!\n",
138 .v4l2_capabilities = 0,
139 .hw_audio_ctrl = CX18_HW_CX23418,
140 .hw_all = CX18_HW_TUNER,
141 .video_inputs = {
142 { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 },
143 { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 },
144 { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
145 },
146 .audio_inputs = {
147 { CX18_CARD_INPUT_AUD_TUNER,
148 CX23418_AUDIO8, 0 },
149 { CX18_CARD_INPUT_LINE_IN1,
150 CX23418_AUDIO_SERIAL, 0 },
151 },
152 .radio_input = { CX18_CARD_INPUT_AUD_TUNER,
153 CX23418_AUDIO_SERIAL, 0 },
154 .tuners = {
155 { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
156 },
157 .ddr = {
158 /* EtronTech EM6A9160TS-5G memory */
159 .chip_config = 0x50003,
160 .refresh = 0x753,
161 .timing1 = 0x24330e84,
162 .timing2 = 0x1f,
163 .tune_lane = 0,
164 .initial_emrs = 0,
165 },
166 .pci_list = cx18_pci_h900,
167 .i2c = &cx18_i2c_std,
168};
169
170/* ------------------------------------------------------------------------- */
171
172/* Yuan MPC718: not working at the moment! */
173
174static const struct cx18_card_pci_info cx18_pci_mpc718[] = {
175 { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_YUAN, 0x0718 },
176 { 0, 0, 0 }
177};
178
179static const struct cx18_card cx18_card_mpc718 = {
180 .type = CX18_CARD_YUAN_MPC718,
181 .name = "Yuan MPC718",
182 .comment = "Not yet supported!\n",
183 .v4l2_capabilities = 0,
184 .hw_audio_ctrl = CX18_HW_CX23418,
185 .hw_all = CX18_HW_TUNER,
186 .video_inputs = {
187 { CX18_CARD_INPUT_VID_TUNER, 0, CX23418_COMPOSITE7 },
188 { CX18_CARD_INPUT_SVIDEO1, 1, CX23418_SVIDEO1 },
189 { CX18_CARD_INPUT_COMPOSITE1, 1, CX23418_COMPOSITE3 },
190 },
191 .audio_inputs = {
192 { CX18_CARD_INPUT_AUD_TUNER,
193 CX23418_AUDIO8, 0 },
194 { CX18_CARD_INPUT_LINE_IN1,
195 CX23418_AUDIO_SERIAL, 0 },
196 },
197 .radio_input = { CX18_CARD_INPUT_AUD_TUNER,
198 CX23418_AUDIO_SERIAL, 0 },
199 .tuners = {
200 /* XC3028 tuner */
201 { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
202 },
203 /* tuner reset */
204 .gpio_init = { .direction = 0x1000, .initial_value = 0x1000 },
205 .ddr = {
206 /* Probably Samsung K4D263238G-VC33 memory */
207 .chip_config = 0x003,
208 .refresh = 0x30c,
209 .timing1 = 0x23230b73,
210 .timing2 = 0x08,
211 .tune_lane = 0,
212 .initial_emrs = 2,
213 },
214 .pci_list = cx18_pci_mpc718,
215 .i2c = &cx18_i2c_std,
216};
217
218static const struct cx18_card *cx18_card_list[] = {
219 &cx18_card_hvr1600_esmt,
220 &cx18_card_hvr1600_samsung,
221 &cx18_card_h900,
222 &cx18_card_mpc718,
223};
224
225const struct cx18_card *cx18_get_card(u16 index)
226{
227 if (index >= ARRAY_SIZE(cx18_card_list))
228 return NULL;
229 return cx18_card_list[index];
230}
231
232int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input)
233{
234 const struct cx18_card_video_input *card_input =
235 cx->card->video_inputs + index;
236 static const char * const input_strs[] = {
237 "Tuner 1",
238 "S-Video 1",
239 "S-Video 2",
240 "Composite 1",
241 "Composite 2",
242 "Composite 3"
243 };
244
245 memset(input, 0, sizeof(*input));
246 if (index >= cx->nof_inputs)
247 return -EINVAL;
248 input->index = index;
249 strlcpy(input->name, input_strs[card_input->video_type - 1],
250 sizeof(input->name));
251 input->type = (card_input->video_type == CX18_CARD_INPUT_VID_TUNER ?
252 V4L2_INPUT_TYPE_TUNER : V4L2_INPUT_TYPE_CAMERA);
253 input->audioset = (1 << cx->nof_audio_inputs) - 1;
254 input->std = (input->type == V4L2_INPUT_TYPE_TUNER) ?
255 cx->tuner_std : V4L2_STD_ALL;
256 return 0;
257}
258
259int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *audio)
260{
261 const struct cx18_card_audio_input *aud_input =
262 cx->card->audio_inputs + index;
263 static const char * const input_strs[] = {
264 "Tuner 1",
265 "Line In 1",
266 "Line In 2"
267 };
268
269 memset(audio, 0, sizeof(*audio));
270 if (index >= cx->nof_audio_inputs)
271 return -EINVAL;
272 strlcpy(audio->name, input_strs[aud_input->audio_type - 1],
273 sizeof(audio->name));
274 audio->index = index;
275 audio->capability = V4L2_AUDCAP_STEREO;
276 return 0;
277}
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h
new file mode 100644
index 000000000000..bca249bdd337
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-cards.h
@@ -0,0 +1,170 @@
1/*
2 * cx18 functions to query card hardware
3 *
4 * Derived from ivtv-cards.c
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23/* hardware flags */
24#define CX18_HW_TUNER (1 << 0)
25#define CX18_HW_TVEEPROM (1 << 1)
26#define CX18_HW_CS5345 (1 << 2)
27#define CX18_HW_GPIO (1 << 3)
28#define CX18_HW_CX23418 (1 << 4)
29#define CX18_HW_DVB (1 << 5)
30
31/* video inputs */
32#define CX18_CARD_INPUT_VID_TUNER 1
33#define CX18_CARD_INPUT_SVIDEO1 2
34#define CX18_CARD_INPUT_SVIDEO2 3
35#define CX18_CARD_INPUT_COMPOSITE1 4
36#define CX18_CARD_INPUT_COMPOSITE2 5
37#define CX18_CARD_INPUT_COMPOSITE3 6
38
39enum cx34180_video_input {
40 /* Composite video inputs In1-In8 */
41 CX23418_COMPOSITE1 = 1,
42 CX23418_COMPOSITE2,
43 CX23418_COMPOSITE3,
44 CX23418_COMPOSITE4,
45 CX23418_COMPOSITE5,
46 CX23418_COMPOSITE6,
47 CX23418_COMPOSITE7,
48 CX23418_COMPOSITE8,
49
50 /* S-Video inputs consist of one luma input (In1-In4) ORed with one
51 chroma input (In5-In8) */
52 CX23418_SVIDEO_LUMA1 = 0x10,
53 CX23418_SVIDEO_LUMA2 = 0x20,
54 CX23418_SVIDEO_LUMA3 = 0x30,
55 CX23418_SVIDEO_LUMA4 = 0x40,
56 CX23418_SVIDEO_CHROMA4 = 0x400,
57 CX23418_SVIDEO_CHROMA5 = 0x500,
58 CX23418_SVIDEO_CHROMA6 = 0x600,
59 CX23418_SVIDEO_CHROMA7 = 0x700,
60 CX23418_SVIDEO_CHROMA8 = 0x800,
61
62 /* S-Video aliases for common luma/chroma combinations */
63 CX23418_SVIDEO1 = 0x510,
64 CX23418_SVIDEO2 = 0x620,
65 CX23418_SVIDEO3 = 0x730,
66 CX23418_SVIDEO4 = 0x840,
67};
68
69/* audio inputs */
70#define CX18_CARD_INPUT_AUD_TUNER 1
71#define CX18_CARD_INPUT_LINE_IN1 2
72#define CX18_CARD_INPUT_LINE_IN2 3
73
74#define CX18_CARD_MAX_VIDEO_INPUTS 6
75#define CX18_CARD_MAX_AUDIO_INPUTS 3
76#define CX18_CARD_MAX_TUNERS 2
77
78enum cx23418_audio_input {
79 /* Audio inputs: serial or In4-In8 */
80 CX23418_AUDIO_SERIAL,
81 CX23418_AUDIO4 = 4,
82 CX23418_AUDIO5,
83 CX23418_AUDIO6,
84 CX23418_AUDIO7,
85 CX23418_AUDIO8,
86};
87
88/* V4L2 capability aliases */
89#define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
90 V4L2_CAP_AUDIO | V4L2_CAP_READWRITE)
91/* | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE) not yet */
92
93struct cx18_card_video_input {
94 u8 video_type; /* video input type */
95 u8 audio_index; /* index in cx18_card_audio_input array */
96 u16 video_input; /* hardware video input */
97};
98
99struct cx18_card_audio_input {
100 u8 audio_type; /* audio input type */
101 u32 audio_input; /* hardware audio input */
102 u16 muxer_input; /* hardware muxer input for boards with a
103 multiplexer chip */
104};
105
106struct cx18_card_pci_info {
107 u16 device;
108 u16 subsystem_vendor;
109 u16 subsystem_device;
110};
111
112/* GPIO definitions */
113
114/* The mask is the set of bits used by the operation */
115
116struct cx18_gpio_init { /* set initial GPIO DIR and OUT values */
117 u16 direction; /* DIR setting. Leave to 0 if no init is needed */
118 u16 initial_value;
119};
120
121struct cx18_card_tuner {
122 v4l2_std_id std; /* standard for which the tuner is suitable */
123 int tuner; /* tuner ID (from tuner.h) */
124};
125
126struct cx18_card_tuner_i2c {
127 unsigned short radio[2];/* radio tuner i2c address to probe */
128 unsigned short demod[2];/* demodulator i2c address to probe */
129 unsigned short tv[4]; /* tv tuner i2c addresses to probe */
130};
131
132struct cx18_ddr { /* DDR config data */
133 u32 chip_config;
134 u32 refresh;
135 u32 timing1;
136 u32 timing2;
137 u32 tune_lane;
138 u32 initial_emrs;
139};
140
141/* for card information/parameters */
142struct cx18_card {
143 int type;
144 char *name;
145 char *comment;
146 u32 v4l2_capabilities;
147 u32 hw_audio_ctrl; /* hardware used for the V4L2 controls (only
148 1 dev allowed) */
149 u32 hw_muxer; /* hardware used to multiplex audio input */
150 u32 hw_all; /* all hardware used by the board */
151 struct cx18_card_video_input video_inputs[CX18_CARD_MAX_VIDEO_INPUTS];
152 struct cx18_card_audio_input audio_inputs[CX18_CARD_MAX_AUDIO_INPUTS];
153 struct cx18_card_audio_input radio_input;
154
155 /* GPIO card-specific settings */
156 struct cx18_gpio_init gpio_init;
157
158 struct cx18_card_tuner tuners[CX18_CARD_MAX_TUNERS];
159 struct cx18_card_tuner_i2c *i2c;
160
161 struct cx18_ddr ddr;
162
163 /* list of device and subsystem vendor/devices that
164 correspond to this card type. */
165 const struct cx18_card_pci_info *pci_list;
166};
167
168int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input);
169int cx18_get_audio_input(struct cx18 *cx, u16 index, struct v4l2_audio *input);
170const struct cx18_card *cx18_get_card(u16 index);
diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c
new file mode 100644
index 000000000000..da299ae61cff
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-controls.c
@@ -0,0 +1,306 @@
1/*
2 * cx18 ioctl control functions
3 *
4 * Derived from ivtv-controls.c
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 */
23
24#include "cx18-driver.h"
25#include "cx18-av-core.h"
26#include "cx18-cards.h"
27#include "cx18-ioctl.h"
28#include "cx18-audio.h"
29#include "cx18-i2c.h"
30#include "cx18-mailbox.h"
31#include "cx18-controls.h"
32
33static const u32 user_ctrls[] = {
34 V4L2_CID_USER_CLASS,
35 V4L2_CID_BRIGHTNESS,
36 V4L2_CID_CONTRAST,
37 V4L2_CID_SATURATION,
38 V4L2_CID_HUE,
39 V4L2_CID_AUDIO_VOLUME,
40 V4L2_CID_AUDIO_BALANCE,
41 V4L2_CID_AUDIO_BASS,
42 V4L2_CID_AUDIO_TREBLE,
43 V4L2_CID_AUDIO_MUTE,
44 V4L2_CID_AUDIO_LOUDNESS,
45 0
46};
47
48static const u32 *ctrl_classes[] = {
49 user_ctrls,
50 cx2341x_mpeg_ctrls,
51 NULL
52};
53
54static int cx18_queryctrl(struct cx18 *cx, struct v4l2_queryctrl *qctrl)
55{
56 const char *name;
57
58 CX18_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id);
59
60 qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
61 if (qctrl->id == 0)
62 return -EINVAL;
63
64 switch (qctrl->id) {
65 /* Standard V4L2 controls */
66 case V4L2_CID_BRIGHTNESS:
67 case V4L2_CID_HUE:
68 case V4L2_CID_SATURATION:
69 case V4L2_CID_CONTRAST:
70 if (cx18_av_cmd(cx, VIDIOC_QUERYCTRL, qctrl))
71 qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
72 return 0;
73
74 case V4L2_CID_AUDIO_VOLUME:
75 case V4L2_CID_AUDIO_MUTE:
76 case V4L2_CID_AUDIO_BALANCE:
77 case V4L2_CID_AUDIO_BASS:
78 case V4L2_CID_AUDIO_TREBLE:
79 case V4L2_CID_AUDIO_LOUDNESS:
80 if (cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_QUERYCTRL, qctrl))
81 qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
82 return 0;
83
84 default:
85 if (cx2341x_ctrl_query(&cx->params, qctrl))
86 qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
87 return 0;
88 }
89 strncpy(qctrl->name, name, sizeof(qctrl->name) - 1);
90 qctrl->name[sizeof(qctrl->name) - 1] = 0;
91 return 0;
92}
93
94static int cx18_querymenu(struct cx18 *cx, struct v4l2_querymenu *qmenu)
95{
96 struct v4l2_queryctrl qctrl;
97
98 qctrl.id = qmenu->id;
99 cx18_queryctrl(cx, &qctrl);
100 return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
101}
102
103static int cx18_s_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
104{
105 s32 v = vctrl->value;
106
107 CX18_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v);
108
109 switch (vctrl->id) {
110 /* Standard V4L2 controls */
111 case V4L2_CID_BRIGHTNESS:
112 case V4L2_CID_HUE:
113 case V4L2_CID_SATURATION:
114 case V4L2_CID_CONTRAST:
115 return cx18_av_cmd(cx, VIDIOC_S_CTRL, vctrl);
116
117 case V4L2_CID_AUDIO_VOLUME:
118 case V4L2_CID_AUDIO_MUTE:
119 case V4L2_CID_AUDIO_BALANCE:
120 case V4L2_CID_AUDIO_BASS:
121 case V4L2_CID_AUDIO_TREBLE:
122 case V4L2_CID_AUDIO_LOUDNESS:
123 return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_S_CTRL, vctrl);
124
125 default:
126 CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
127 return -EINVAL;
128 }
129 return 0;
130}
131
132static int cx18_g_ctrl(struct cx18 *cx, struct v4l2_control *vctrl)
133{
134 CX18_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id);
135
136 switch (vctrl->id) {
137 /* Standard V4L2 controls */
138 case V4L2_CID_BRIGHTNESS:
139 case V4L2_CID_HUE:
140 case V4L2_CID_SATURATION:
141 case V4L2_CID_CONTRAST:
142 return cx18_av_cmd(cx, VIDIOC_G_CTRL, vctrl);
143
144 case V4L2_CID_AUDIO_VOLUME:
145 case V4L2_CID_AUDIO_MUTE:
146 case V4L2_CID_AUDIO_BALANCE:
147 case V4L2_CID_AUDIO_BASS:
148 case V4L2_CID_AUDIO_TREBLE:
149 case V4L2_CID_AUDIO_LOUDNESS:
150 return cx18_i2c_hw(cx, cx->card->hw_audio_ctrl, VIDIOC_G_CTRL, vctrl);
151 default:
152 CX18_DEBUG_IOCTL("invalid control %x\n", vctrl->id);
153 return -EINVAL;
154 }
155 return 0;
156}
157
158static int cx18_setup_vbi_fmt(struct cx18 *cx, enum v4l2_mpeg_stream_vbi_fmt fmt)
159{
160 if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE))
161 return -EINVAL;
162 if (atomic_read(&cx->capturing) > 0)
163 return -EBUSY;
164
165 /* First try to allocate sliced VBI buffers if needed. */
166 if (fmt && cx->vbi.sliced_mpeg_data[0] == NULL) {
167 int i;
168
169 for (i = 0; i < CX18_VBI_FRAMES; i++) {
170 /* Yuck, hardcoded. Needs to be a define */
171 cx->vbi.sliced_mpeg_data[i] = kmalloc(2049, GFP_KERNEL);
172 if (cx->vbi.sliced_mpeg_data[i] == NULL) {
173 while (--i >= 0) {
174 kfree(cx->vbi.sliced_mpeg_data[i]);
175 cx->vbi.sliced_mpeg_data[i] = NULL;
176 }
177 return -ENOMEM;
178 }
179 }
180 }
181
182 cx->vbi.insert_mpeg = fmt;
183
184 if (cx->vbi.insert_mpeg == 0)
185 return 0;
186 /* Need sliced data for mpeg insertion */
187 if (get_service_set(cx->vbi.sliced_in) == 0) {
188 if (cx->is_60hz)
189 cx->vbi.sliced_in->service_set = V4L2_SLICED_CAPTION_525;
190 else
191 cx->vbi.sliced_in->service_set = V4L2_SLICED_WSS_625;
192 expand_service_set(cx->vbi.sliced_in, cx->is_50hz);
193 }
194 return 0;
195}
196
197int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg)
198{
199 struct v4l2_control ctrl;
200
201 switch (cmd) {
202 case VIDIOC_QUERYMENU:
203 CX18_DEBUG_IOCTL("VIDIOC_QUERYMENU\n");
204 return cx18_querymenu(cx, arg);
205
206 case VIDIOC_QUERYCTRL:
207 return cx18_queryctrl(cx, arg);
208
209 case VIDIOC_S_CTRL:
210 return cx18_s_ctrl(cx, arg);
211
212 case VIDIOC_G_CTRL:
213 return cx18_g_ctrl(cx, arg);
214
215 case VIDIOC_S_EXT_CTRLS:
216 {
217 struct v4l2_ext_controls *c = arg;
218
219 if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
220 int i;
221 int err = 0;
222
223 for (i = 0; i < c->count; i++) {
224 ctrl.id = c->controls[i].id;
225 ctrl.value = c->controls[i].value;
226 err = cx18_s_ctrl(cx, &ctrl);
227 c->controls[i].value = ctrl.value;
228 if (err) {
229 c->error_idx = i;
230 break;
231 }
232 }
233 return err;
234 }
235 CX18_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
236 if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
237 struct cx2341x_mpeg_params p = cx->params;
238 int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->capturing), arg, cmd);
239
240 if (err)
241 return err;
242
243 if (p.video_encoding != cx->params.video_encoding) {
244 int is_mpeg1 = p.video_encoding ==
245 V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
246 struct v4l2_format fmt;
247
248 /* fix videodecoder resolution */
249 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
250 fmt.fmt.pix.width = cx->params.width / (is_mpeg1 ? 2 : 1);
251 fmt.fmt.pix.height = cx->params.height;
252 cx18_av_cmd(cx, VIDIOC_S_FMT, &fmt);
253 }
254 err = cx2341x_update(cx, cx18_api_func, &cx->params, &p);
255 if (!err && cx->params.stream_vbi_fmt != p.stream_vbi_fmt)
256 err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt);
257 cx->params = p;
258 cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
259 cx18_audio_set_audio_clock_freq(cx, p.audio_properties & 0x03);
260 return err;
261 }
262 return -EINVAL;
263 }
264
265 case VIDIOC_G_EXT_CTRLS:
266 {
267 struct v4l2_ext_controls *c = arg;
268
269 if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
270 int i;
271 int err = 0;
272
273 for (i = 0; i < c->count; i++) {
274 ctrl.id = c->controls[i].id;
275 ctrl.value = c->controls[i].value;
276 err = cx18_g_ctrl(cx, &ctrl);
277 c->controls[i].value = ctrl.value;
278 if (err) {
279 c->error_idx = i;
280 break;
281 }
282 }
283 return err;
284 }
285 CX18_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n");
286 if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
287 return cx2341x_ext_ctrls(&cx->params, 0, arg, cmd);
288 return -EINVAL;
289 }
290
291 case VIDIOC_TRY_EXT_CTRLS:
292 {
293 struct v4l2_ext_controls *c = arg;
294
295 CX18_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
296 if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
297 return cx2341x_ext_ctrls(&cx->params,
298 atomic_read(&cx->capturing), arg, cmd);
299 return -EINVAL;
300 }
301
302 default:
303 return -EINVAL;
304 }
305 return 0;
306}
diff --git a/drivers/media/video/cx18/cx18-controls.h b/drivers/media/video/cx18/cx18-controls.h
new file mode 100644
index 000000000000..6e985cf422a0
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-controls.h
@@ -0,0 +1,24 @@
1/*
2 * cx18 ioctl control functions
3 *
4 * Derived from ivtv-controls.h
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 */
23
24int cx18_control_ioctls(struct cx18 *cx, unsigned int cmd, void *arg);
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
new file mode 100644
index 000000000000..9f31befc3139
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -0,0 +1,971 @@
1/*
2 * cx18 driver initialization and card probing
3 *
4 * Derived from ivtv-driver.c
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 */
23
24#include "cx18-driver.h"
25#include "cx18-version.h"
26#include "cx18-cards.h"
27#include "cx18-i2c.h"
28#include "cx18-irq.h"
29#include "cx18-gpio.h"
30#include "cx18-firmware.h"
31#include "cx18-streams.h"
32#include "cx18-av-core.h"
33#include "cx18-scb.h"
34#include "cx18-mailbox.h"
35#include "cx18-ioctl.h"
36#include "tuner-xc2028.h"
37
38#include <media/tveeprom.h>
39
40
41/* var to keep track of the number of array elements in use */
42int cx18_cards_active;
43
44/* If you have already X v4l cards, then set this to X. This way
45 the device numbers stay matched. Example: you have a WinTV card
46 without radio and a Compro H900 with. Normally this would give a
47 video1 device together with a radio0 device for the Compro. By
48 setting this to 1 you ensure that radio0 is now also radio1. */
49int cx18_first_minor;
50
51/* Master variable for all cx18 info */
52struct cx18 *cx18_cards[CX18_MAX_CARDS];
53
54/* Protects cx18_cards_active */
55DEFINE_SPINLOCK(cx18_cards_lock);
56
57/* add your revision and whatnot here */
58static struct pci_device_id cx18_pci_tbl[] __devinitdata = {
59 {PCI_VENDOR_ID_CX, PCI_DEVICE_ID_CX23418,
60 PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
61 {0,}
62};
63
64MODULE_DEVICE_TABLE(pci, cx18_pci_tbl);
65
66/* Parameter declarations */
67static int cardtype[CX18_MAX_CARDS];
68static int tuner[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
69 -1, -1, -1, -1, -1, -1, -1, -1,
70 -1, -1, -1, -1, -1, -1, -1, -1,
71 -1, -1, -1, -1, -1, -1, -1, -1 };
72static int radio[CX18_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
73 -1, -1, -1, -1, -1, -1, -1, -1,
74 -1, -1, -1, -1, -1, -1, -1, -1,
75 -1, -1, -1, -1, -1, -1, -1, -1 };
76
77static int cardtype_c = 1;
78static int tuner_c = 1;
79static int radio_c = 1;
80static char pal[] = "--";
81static char secam[] = "--";
82static char ntsc[] = "-";
83
84/* Buffers */
85static int enc_mpg_buffers = CX18_DEFAULT_ENC_MPG_BUFFERS;
86static int enc_ts_buffers = CX18_DEFAULT_ENC_TS_BUFFERS;
87static int enc_yuv_buffers = CX18_DEFAULT_ENC_YUV_BUFFERS;
88static int enc_vbi_buffers = CX18_DEFAULT_ENC_VBI_BUFFERS;
89static int enc_pcm_buffers = CX18_DEFAULT_ENC_PCM_BUFFERS;
90
91static int cx18_pci_latency = 1;
92
93int cx18_debug;
94
95module_param_array(tuner, int, &tuner_c, 0644);
96module_param_array(radio, bool, &radio_c, 0644);
97module_param_array(cardtype, int, &cardtype_c, 0644);
98module_param_string(pal, pal, sizeof(pal), 0644);
99module_param_string(secam, secam, sizeof(secam), 0644);
100module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
101module_param_named(debug, cx18_debug, int, 0644);
102module_param(cx18_pci_latency, int, 0644);
103module_param(cx18_first_minor, int, 0644);
104
105module_param(enc_mpg_buffers, int, 0644);
106module_param(enc_ts_buffers, int, 0644);
107module_param(enc_yuv_buffers, int, 0644);
108module_param(enc_vbi_buffers, int, 0644);
109module_param(enc_pcm_buffers, int, 0644);
110
111MODULE_PARM_DESC(tuner, "Tuner type selection,\n"
112 "\t\t\tsee tuner.h for values");
113MODULE_PARM_DESC(radio,
114 "Enable or disable the radio. Use only if autodetection\n"
115 "\t\t\tfails. 0 = disable, 1 = enable");
116MODULE_PARM_DESC(cardtype,
117 "Only use this option if your card is not detected properly.\n"
118 "\t\tSpecify card type:\n"
119 "\t\t\t 1 = Hauppauge HVR 1600 (ESMT memory)\n"
120 "\t\t\t 2 = Hauppauge HVR 1600 (Samsung memory)\n"
121 "\t\t\t 3 = Compro VideoMate H900\n"
122 "\t\t\t 4 = Yuan MPC718\n"
123 "\t\t\t 0 = Autodetect (default)\n"
124 "\t\t\t-1 = Ignore this card\n\t\t");
125MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
126MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC");
127MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K");
128MODULE_PARM_DESC(debug,
129 "Debug level (bitmask). Default: 0\n"
130 "\t\t\t 1/0x0001: warning\n"
131 "\t\t\t 2/0x0002: info\n"
132 "\t\t\t 4/0x0004: mailbox\n"
133 "\t\t\t 8/0x0008: dma\n"
134 "\t\t\t 16/0x0010: ioctl\n"
135 "\t\t\t 32/0x0020: file\n"
136 "\t\t\t 64/0x0040: i2c\n"
137 "\t\t\t128/0x0080: irq\n"
138 "\t\t\t256/0x0100: high volume\n");
139MODULE_PARM_DESC(cx18_pci_latency,
140 "Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
141 "\t\t\tDefault: Yes");
142MODULE_PARM_DESC(enc_mpg_buffers,
143 "Encoder MPG Buffers (in MB)\n"
144 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_MPG_BUFFERS));
145MODULE_PARM_DESC(enc_ts_buffers,
146 "Encoder TS Buffers (in MB)\n"
147 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_TS_BUFFERS));
148MODULE_PARM_DESC(enc_yuv_buffers,
149 "Encoder YUV Buffers (in MB)\n"
150 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_YUV_BUFFERS));
151MODULE_PARM_DESC(enc_vbi_buffers,
152 "Encoder VBI Buffers (in MB)\n"
153 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_VBI_BUFFERS));
154MODULE_PARM_DESC(enc_pcm_buffers,
155 "Encoder PCM buffers (in MB)\n"
156 "\t\t\tDefault: " __stringify(CX18_DEFAULT_ENC_PCM_BUFFERS));
157
158MODULE_PARM_DESC(cx18_first_minor, "Set minor assigned to first card");
159
160MODULE_AUTHOR("Hans Verkuil");
161MODULE_DESCRIPTION("CX23418 driver");
162MODULE_SUPPORTED_DEVICE("CX23418 MPEG2 encoder");
163MODULE_LICENSE("GPL");
164
165MODULE_VERSION(CX18_VERSION);
166
167int cx18_waitq(wait_queue_head_t *waitq)
168{
169 DEFINE_WAIT(wait);
170
171 prepare_to_wait(waitq, &wait, TASK_INTERRUPTIBLE);
172 schedule();
173 finish_wait(waitq, &wait);
174 return signal_pending(current) ? -EINTR : 0;
175}
176
177/* Generic utility functions */
178int cx18_msleep_timeout(unsigned int msecs, int intr)
179{
180 int timeout = msecs_to_jiffies(msecs);
181 int sig;
182
183 do {
184 set_current_state(intr ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
185 timeout = schedule_timeout(timeout);
186 sig = intr ? signal_pending(current) : 0;
187 } while (!sig && timeout);
188 return sig;
189}
190
191/* Release ioremapped memory */
192static void cx18_iounmap(struct cx18 *cx)
193{
194 if (cx == NULL)
195 return;
196
197 /* Release io memory */
198 if (cx->enc_mem != NULL) {
199 CX18_DEBUG_INFO("releasing enc_mem\n");
200 iounmap(cx->enc_mem);
201 cx->enc_mem = NULL;
202 }
203}
204
205/* Hauppauge card? get values from tveeprom */
206void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
207{
208 u8 eedata[256];
209
210 cx->i2c_client[0].addr = 0xA0 >> 1;
211 tveeprom_read(&cx->i2c_client[0], eedata, sizeof(eedata));
212 tveeprom_hauppauge_analog(&cx->i2c_client[0], tv, eedata);
213}
214
215static void cx18_process_eeprom(struct cx18 *cx)
216{
217 struct tveeprom tv;
218
219 cx18_read_eeprom(cx, &tv);
220
221 /* Many thanks to Steven Toth from Hauppauge for providing the
222 model numbers */
223 switch (tv.model) {
224 case 74000 ... 74099:
225 cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
226 break;
227 case 74700 ... 74799:
228 cx->card = cx18_get_card(CX18_CARD_HVR_1600_SAMSUNG);
229 break;
230 case 0:
231 CX18_ERR("Invalid EEPROM\n");
232 return;
233 default:
234 CX18_ERR("Unknown model %d, defaulting to HVR-1600\n", tv.model);
235 cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
236 break;
237 }
238
239 cx->v4l2_cap = cx->card->v4l2_capabilities;
240 cx->card_name = cx->card->name;
241 cx->card_i2c = cx->card->i2c;
242
243 CX18_INFO("Autodetected %s\n", cx->card_name);
244
245 if (tv.tuner_type == TUNER_ABSENT)
246 CX18_ERR("tveeprom cannot autodetect tuner!");
247
248 if (cx->options.tuner == -1)
249 cx->options.tuner = tv.tuner_type;
250 if (cx->options.radio == -1)
251 cx->options.radio = (tv.has_radio != 0);
252
253 if (cx->std != 0)
254 /* user specified tuner standard */
255 return;
256
257 /* autodetect tuner standard */
258 if (tv.tuner_formats & V4L2_STD_PAL) {
259 CX18_DEBUG_INFO("PAL tuner detected\n");
260 cx->std |= V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
261 } else if (tv.tuner_formats & V4L2_STD_NTSC) {
262 CX18_DEBUG_INFO("NTSC tuner detected\n");
263 cx->std |= V4L2_STD_NTSC_M;
264 } else if (tv.tuner_formats & V4L2_STD_SECAM) {
265 CX18_DEBUG_INFO("SECAM tuner detected\n");
266 cx->std |= V4L2_STD_SECAM_L;
267 } else {
268 CX18_INFO("No tuner detected, default to NTSC-M\n");
269 cx->std |= V4L2_STD_NTSC_M;
270 }
271}
272
273static v4l2_std_id cx18_parse_std(struct cx18 *cx)
274{
275 switch (pal[0]) {
276 case '6':
277 return V4L2_STD_PAL_60;
278 case 'b':
279 case 'B':
280 case 'g':
281 case 'G':
282 return V4L2_STD_PAL_BG;
283 case 'h':
284 case 'H':
285 return V4L2_STD_PAL_H;
286 case 'n':
287 case 'N':
288 if (pal[1] == 'c' || pal[1] == 'C')
289 return V4L2_STD_PAL_Nc;
290 return V4L2_STD_PAL_N;
291 case 'i':
292 case 'I':
293 return V4L2_STD_PAL_I;
294 case 'd':
295 case 'D':
296 case 'k':
297 case 'K':
298 return V4L2_STD_PAL_DK;
299 case 'M':
300 case 'm':
301 return V4L2_STD_PAL_M;
302 case '-':
303 break;
304 default:
305 CX18_WARN("pal= argument not recognised\n");
306 return 0;
307 }
308
309 switch (secam[0]) {
310 case 'b':
311 case 'B':
312 case 'g':
313 case 'G':
314 case 'h':
315 case 'H':
316 return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
317 case 'd':
318 case 'D':
319 case 'k':
320 case 'K':
321 return V4L2_STD_SECAM_DK;
322 case 'l':
323 case 'L':
324 if (secam[1] == 'C' || secam[1] == 'c')
325 return V4L2_STD_SECAM_LC;
326 return V4L2_STD_SECAM_L;
327 case '-':
328 break;
329 default:
330 CX18_WARN("secam= argument not recognised\n");
331 return 0;
332 }
333
334 switch (ntsc[0]) {
335 case 'm':
336 case 'M':
337 return V4L2_STD_NTSC_M;
338 case 'j':
339 case 'J':
340 return V4L2_STD_NTSC_M_JP;
341 case 'k':
342 case 'K':
343 return V4L2_STD_NTSC_M_KR;
344 case '-':
345 break;
346 default:
347 CX18_WARN("ntsc= argument not recognised\n");
348 return 0;
349 }
350
351 /* no match found */
352 return 0;
353}
354
355static void cx18_process_options(struct cx18 *cx)
356{
357 int i, j;
358
359 cx->options.megabytes[CX18_ENC_STREAM_TYPE_MPG] = enc_mpg_buffers;
360 cx->options.megabytes[CX18_ENC_STREAM_TYPE_TS] = enc_ts_buffers;
361 cx->options.megabytes[CX18_ENC_STREAM_TYPE_YUV] = enc_yuv_buffers;
362 cx->options.megabytes[CX18_ENC_STREAM_TYPE_VBI] = enc_vbi_buffers;
363 cx->options.megabytes[CX18_ENC_STREAM_TYPE_PCM] = enc_pcm_buffers;
364 cx->options.cardtype = cardtype[cx->num];
365 cx->options.tuner = tuner[cx->num];
366 cx->options.radio = radio[cx->num];
367
368 cx->std = cx18_parse_std(cx);
369 if (cx->options.cardtype == -1) {
370 CX18_INFO("Ignore card\n");
371 return;
372 }
373 cx->card = cx18_get_card(cx->options.cardtype - 1);
374 if (cx->card)
375 CX18_INFO("User specified %s card\n", cx->card->name);
376 else if (cx->options.cardtype != 0)
377 CX18_ERR("Unknown user specified type, trying to autodetect card\n");
378 if (cx->card == NULL) {
379 if (cx->dev->subsystem_vendor == CX18_PCI_ID_HAUPPAUGE) {
380 cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
381 CX18_INFO("Autodetected Hauppauge card\n");
382 }
383 }
384 if (cx->card == NULL) {
385 for (i = 0; (cx->card = cx18_get_card(i)); i++) {
386 if (cx->card->pci_list == NULL)
387 continue;
388 for (j = 0; cx->card->pci_list[j].device; j++) {
389 if (cx->dev->device !=
390 cx->card->pci_list[j].device)
391 continue;
392 if (cx->dev->subsystem_vendor !=
393 cx->card->pci_list[j].subsystem_vendor)
394 continue;
395 if (cx->dev->subsystem_device !=
396 cx->card->pci_list[j].subsystem_device)
397 continue;
398 CX18_INFO("Autodetected %s card\n", cx->card->name);
399 goto done;
400 }
401 }
402 }
403done:
404
405 if (cx->card == NULL) {
406 cx->card = cx18_get_card(CX18_CARD_HVR_1600_ESMT);
407 CX18_ERR("Unknown card: vendor/device: %04x/%04x\n",
408 cx->dev->vendor, cx->dev->device);
409 CX18_ERR(" subsystem vendor/device: %04x/%04x\n",
410 cx->dev->subsystem_vendor, cx->dev->subsystem_device);
411 CX18_ERR("Defaulting to %s card\n", cx->card->name);
412 CX18_ERR("Please mail the vendor/device and subsystem vendor/device IDs and what kind of\n");
413 CX18_ERR("card you have to the ivtv-devel mailinglist (www.ivtvdriver.org)\n");
414 CX18_ERR("Prefix your subject line with [UNKNOWN CX18 CARD].\n");
415 }
416 cx->v4l2_cap = cx->card->v4l2_capabilities;
417 cx->card_name = cx->card->name;
418 cx->card_i2c = cx->card->i2c;
419}
420
421/* Precondition: the cx18 structure has been memset to 0. Only
422 the dev and num fields have been filled in.
423 No assumptions on the card type may be made here (see cx18_init_struct2
424 for that).
425 */
426static int __devinit cx18_init_struct1(struct cx18 *cx)
427{
428 cx->base_addr = pci_resource_start(cx->dev, 0);
429
430 mutex_init(&cx->serialize_lock);
431 mutex_init(&cx->i2c_bus_lock[0]);
432 mutex_init(&cx->i2c_bus_lock[1]);
433
434 spin_lock_init(&cx->lock);
435 spin_lock_init(&cx->dma_reg_lock);
436
437 /* start counting open_id at 1 */
438 cx->open_id = 1;
439
440 /* Initial settings */
441 cx2341x_fill_defaults(&cx->params);
442 cx->temporal_strength = cx->params.video_temporal_filter;
443 cx->spatial_strength = cx->params.video_spatial_filter;
444 cx->filter_mode = cx->params.video_spatial_filter_mode |
445 (cx->params.video_temporal_filter_mode << 1) |
446 (cx->params.video_median_filter_type << 2);
447 cx->params.port = CX2341X_PORT_MEMORY;
448 cx->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI;
449 init_waitqueue_head(&cx->cap_w);
450 init_waitqueue_head(&cx->mb_apu_waitq);
451 init_waitqueue_head(&cx->mb_cpu_waitq);
452 init_waitqueue_head(&cx->mb_epu_waitq);
453 init_waitqueue_head(&cx->mb_hpu_waitq);
454 init_waitqueue_head(&cx->dma_waitq);
455
456 /* VBI */
457 cx->vbi.in.type = V4L2_BUF_TYPE_SLICED_VBI_CAPTURE;
458 cx->vbi.sliced_in = &cx->vbi.in.fmt.sliced;
459 cx->vbi.raw_size = 1456;
460 cx->vbi.raw_decoder_line_size = 1456;
461 cx->vbi.raw_decoder_sav_odd_field = 0x20;
462 cx->vbi.raw_decoder_sav_even_field = 0x60;
463 cx->vbi.sliced_decoder_line_size = 272;
464 cx->vbi.sliced_decoder_sav_odd_field = 0xB0;
465 cx->vbi.sliced_decoder_sav_even_field = 0xF0;
466 return 0;
467}
468
469/* Second initialization part. Here the card type has been
470 autodetected. */
471static void __devinit cx18_init_struct2(struct cx18 *cx)
472{
473 int i;
474
475 for (i = 0; i < CX18_CARD_MAX_VIDEO_INPUTS; i++)
476 if (cx->card->video_inputs[i].video_type == 0)
477 break;
478 cx->nof_inputs = i;
479 for (i = 0; i < CX18_CARD_MAX_AUDIO_INPUTS; i++)
480 if (cx->card->audio_inputs[i].audio_type == 0)
481 break;
482 cx->nof_audio_inputs = i;
483
484 /* Find tuner input */
485 for (i = 0; i < cx->nof_inputs; i++) {
486 if (cx->card->video_inputs[i].video_type ==
487 CX18_CARD_INPUT_VID_TUNER)
488 break;
489 }
490 if (i == cx->nof_inputs)
491 i = 0;
492 cx->active_input = i;
493 cx->audio_input = cx->card->video_inputs[i].audio_index;
494 cx->av_state.vid_input = CX18_AV_COMPOSITE7;
495 cx->av_state.aud_input = CX18_AV_AUDIO8;
496 cx->av_state.audclk_freq = 48000;
497 cx->av_state.audmode = V4L2_TUNER_MODE_LANG1;
498 cx->av_state.vbi_line_offset = 8;
499}
500
501static int cx18_setup_pci(struct cx18 *cx, struct pci_dev *dev,
502 const struct pci_device_id *pci_id)
503{
504 u16 cmd;
505 unsigned char pci_latency;
506
507 CX18_DEBUG_INFO("Enabling pci device\n");
508
509 if (pci_enable_device(dev)) {
510 CX18_ERR("Can't enable device %d!\n", cx->num);
511 return -EIO;
512 }
513 if (pci_set_dma_mask(dev, 0xffffffff)) {
514 CX18_ERR("No suitable DMA available on card %d.\n", cx->num);
515 return -EIO;
516 }
517 if (!request_mem_region(cx->base_addr, CX18_MEM_SIZE, "cx18 encoder")) {
518 CX18_ERR("Cannot request encoder memory region on card %d.\n", cx->num);
519 return -EIO;
520 }
521
522 /* Check for bus mastering */
523 pci_read_config_word(dev, PCI_COMMAND, &cmd);
524 cmd |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER;
525 pci_write_config_word(dev, PCI_COMMAND, cmd);
526
527 pci_read_config_byte(dev, PCI_CLASS_REVISION, &cx->card_rev);
528 pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
529
530 if (pci_latency < 64 && cx18_pci_latency) {
531 CX18_INFO("Unreasonably low latency timer, "
532 "setting to 64 (was %d)\n", pci_latency);
533 pci_write_config_byte(dev, PCI_LATENCY_TIMER, 64);
534 pci_read_config_byte(dev, PCI_LATENCY_TIMER, &pci_latency);
535 }
536 /* This config space value relates to DMA latencies. The
537 default value 0x8080 is too low however and will lead
538 to DMA errors. 0xffff is the max value which solves
539 these problems. */
540 pci_write_config_dword(dev, 0x40, 0xffff);
541
542 CX18_DEBUG_INFO("cx%d (rev %d) at %02x:%02x.%x, "
543 "irq: %d, latency: %d, memory: 0x%lx\n",
544 cx->dev->device, cx->card_rev, dev->bus->number,
545 PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn),
546 cx->dev->irq, pci_latency, (unsigned long)cx->base_addr);
547
548 return 0;
549}
550
551static u32 cx18_request_module(struct cx18 *cx, u32 hw,
552 const char *name, u32 id)
553{
554 if ((hw & id) == 0)
555 return hw;
556 if (request_module(name) != 0) {
557 CX18_ERR("Failed to load module %s\n", name);
558 return hw & ~id;
559 }
560 CX18_DEBUG_INFO("Loaded module %s\n", name);
561 return hw;
562}
563
564static void cx18_load_and_init_modules(struct cx18 *cx)
565{
566 u32 hw = cx->card->hw_all;
567 int i;
568
569 /* load modules */
570#ifndef CONFIG_VIDEO_TUNER
571 hw = cx18_request_module(cx, hw, "tuner", CX18_HW_TUNER);
572#endif
573#ifndef CONFIG_VIDEO_CS5345
574 hw = cx18_request_module(cx, hw, "cs5345", CX18_HW_CS5345);
575#endif
576
577 /* check which i2c devices are actually found */
578 for (i = 0; i < 32; i++) {
579 u32 device = 1 << i;
580
581 if (!(device & hw))
582 continue;
583 if (device == CX18_HW_GPIO || device == CX18_HW_TVEEPROM ||
584 device == CX18_HW_CX23418 || device == CX18_HW_DVB) {
585 /* These 'devices' do not use i2c probing */
586 cx->hw_flags |= device;
587 continue;
588 }
589 cx18_i2c_register(cx, i);
590 if (cx18_i2c_hw_addr(cx, device) > 0)
591 cx->hw_flags |= device;
592 }
593
594 hw = cx->hw_flags;
595}
596
597static int __devinit cx18_probe(struct pci_dev *dev,
598 const struct pci_device_id *pci_id)
599{
600 int retval = 0;
601 int vbi_buf_size;
602 u32 devtype;
603 struct cx18 *cx;
604
605 spin_lock(&cx18_cards_lock);
606
607 /* Make sure we've got a place for this card */
608 if (cx18_cards_active == CX18_MAX_CARDS) {
609 printk(KERN_ERR "cx18: Maximum number of cards detected (%d).\n",
610 cx18_cards_active);
611 spin_unlock(&cx18_cards_lock);
612 return -ENOMEM;
613 }
614
615 cx = kzalloc(sizeof(struct cx18), GFP_ATOMIC);
616 if (cx == 0) {
617 spin_unlock(&cx18_cards_lock);
618 return -ENOMEM;
619 }
620 cx18_cards[cx18_cards_active] = cx;
621 cx->dev = dev;
622 cx->num = cx18_cards_active++;
623 snprintf(cx->name, sizeof(cx->name) - 1, "cx18-%d", cx->num);
624 CX18_INFO("Initializing card #%d\n", cx->num);
625
626 spin_unlock(&cx18_cards_lock);
627
628 cx18_process_options(cx);
629 if (cx->options.cardtype == -1) {
630 retval = -ENODEV;
631 goto err;
632 }
633 if (cx18_init_struct1(cx)) {
634 retval = -ENOMEM;
635 goto err;
636 }
637
638 CX18_DEBUG_INFO("base addr: 0x%08x\n", cx->base_addr);
639
640 /* PCI Device Setup */
641 retval = cx18_setup_pci(cx, dev, pci_id);
642 if (retval != 0) {
643 if (retval == -EIO)
644 goto free_workqueue;
645 else if (retval == -ENXIO)
646 goto free_mem;
647 }
648 /* save cx in the pci struct for later use */
649 pci_set_drvdata(dev, cx);
650
651 /* map io memory */
652 CX18_DEBUG_INFO("attempting ioremap at 0x%08x len 0x%08x\n",
653 cx->base_addr + CX18_MEM_OFFSET, CX18_MEM_SIZE);
654 cx->enc_mem = ioremap_nocache(cx->base_addr + CX18_MEM_OFFSET,
655 CX18_MEM_SIZE);
656 if (!cx->enc_mem) {
657 CX18_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
658 CX18_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
659 retval = -ENOMEM;
660 goto free_mem;
661 }
662 cx->reg_mem = cx->enc_mem + CX18_REG_OFFSET;
663 devtype = read_reg(0xC72028);
664 switch (devtype & 0xff000000) {
665 case 0xff000000:
666 CX18_INFO("cx23418 revision %08x (A)\n", devtype);
667 break;
668 case 0x01000000:
669 CX18_INFO("cx23418 revision %08x (B)\n", devtype);
670 break;
671 default:
672 CX18_INFO("cx23418 revision %08x (Unknown)\n", devtype);
673 break;
674 }
675
676 cx18_init_power(cx, 1);
677 cx18_init_memory(cx);
678
679 cx->scb = (struct cx18_scb *)(cx->enc_mem + SCB_OFFSET);
680 cx18_init_scb(cx);
681
682 cx18_gpio_init(cx);
683
684 /* active i2c */
685 CX18_DEBUG_INFO("activating i2c...\n");
686 if (init_cx18_i2c(cx)) {
687 CX18_ERR("Could not initialize i2c\n");
688 goto free_map;
689 }
690
691 CX18_DEBUG_INFO("Active card count: %d.\n", cx18_cards_active);
692
693 if (cx->card->hw_all & CX18_HW_TVEEPROM) {
694 /* Based on the model number the cardtype may be changed.
695 The PCI IDs are not always reliable. */
696 cx18_process_eeprom(cx);
697 }
698 if (cx->card->comment)
699 CX18_INFO("%s", cx->card->comment);
700 if (cx->card->v4l2_capabilities == 0) {
701 retval = -ENODEV;
702 goto free_i2c;
703 }
704 cx18_init_memory(cx);
705
706 /* Register IRQ */
707 retval = request_irq(cx->dev->irq, cx18_irq_handler,
708 IRQF_SHARED | IRQF_DISABLED, cx->name, (void *)cx);
709 if (retval) {
710 CX18_ERR("Failed to register irq %d\n", retval);
711 goto free_i2c;
712 }
713
714 if (cx->std == 0)
715 cx->std = V4L2_STD_NTSC_M;
716
717 if (cx->options.tuner == -1) {
718 int i;
719
720 for (i = 0; i < CX18_CARD_MAX_TUNERS; i++) {
721 if ((cx->std & cx->card->tuners[i].std) == 0)
722 continue;
723 cx->options.tuner = cx->card->tuners[i].tuner;
724 break;
725 }
726 }
727 /* if no tuner was found, then pick the first tuner in the card list */
728 if (cx->options.tuner == -1 && cx->card->tuners[0].std) {
729 cx->std = cx->card->tuners[0].std;
730 cx->options.tuner = cx->card->tuners[0].tuner;
731 }
732 if (cx->options.radio == -1)
733 cx->options.radio = (cx->card->radio_input.audio_type != 0);
734
735 /* The card is now fully identified, continue with card-specific
736 initialization. */
737 cx18_init_struct2(cx);
738
739 cx18_load_and_init_modules(cx);
740
741 if (cx->std & V4L2_STD_525_60) {
742 cx->is_60hz = 1;
743 cx->is_out_60hz = 1;
744 } else {
745 cx->is_50hz = 1;
746 cx->is_out_50hz = 1;
747 }
748 cx->params.video_gop_size = cx->is_60hz ? 15 : 12;
749
750 cx->stream_buf_size[CX18_ENC_STREAM_TYPE_MPG] = 0x08000;
751 cx->stream_buf_size[CX18_ENC_STREAM_TYPE_TS] = 0x08000;
752 cx->stream_buf_size[CX18_ENC_STREAM_TYPE_PCM] = 0x01200;
753 cx->stream_buf_size[CX18_ENC_STREAM_TYPE_YUV] = 0x20000;
754 vbi_buf_size = cx->vbi.raw_size * (cx->is_60hz ? 24 : 36) / 2;
755 cx->stream_buf_size[CX18_ENC_STREAM_TYPE_VBI] = vbi_buf_size;
756
757 if (cx->options.radio > 0)
758 cx->v4l2_cap |= V4L2_CAP_RADIO;
759
760 retval = cx18_streams_setup(cx);
761 if (retval) {
762 CX18_ERR("Error %d setting up streams\n", retval);
763 goto free_irq;
764 }
765 retval = cx18_streams_register(cx);
766 if (retval) {
767 CX18_ERR("Error %d registering devices\n", retval);
768 goto free_streams;
769 }
770
771 if (cx->options.tuner > -1) {
772 struct tuner_setup setup;
773
774 setup.addr = ADDR_UNSET;
775 setup.type = cx->options.tuner;
776 setup.mode_mask = T_ANALOG_TV; /* matches TV tuners */
777 setup.tuner_callback = (setup.type == TUNER_XC2028) ?
778 cx18_reset_tuner_gpio : NULL;
779 cx18_call_i2c_clients(cx, TUNER_SET_TYPE_ADDR, &setup);
780 if (setup.type == TUNER_XC2028) {
781 static struct xc2028_ctrl ctrl = {
782 .fname = XC2028_DEFAULT_FIRMWARE,
783 .max_len = 64,
784 };
785 struct v4l2_priv_tun_config cfg = {
786 .tuner = cx->options.tuner,
787 .priv = &ctrl,
788 };
789 cx18_call_i2c_clients(cx, TUNER_SET_CONFIG, &cfg);
790 }
791 }
792
793 /* The tuner is fixed to the standard. The other inputs (e.g. S-Video)
794 are not. */
795 cx->tuner_std = cx->std;
796
797 cx18_init_on_first_open(cx);
798
799 CX18_INFO("Initialized card #%d: %s\n", cx->num, cx->card_name);
800
801 return 0;
802
803free_streams:
804 cx18_streams_cleanup(cx);
805free_irq:
806 free_irq(cx->dev->irq, (void *)cx);
807free_i2c:
808 exit_cx18_i2c(cx);
809free_map:
810 cx18_iounmap(cx);
811free_mem:
812 release_mem_region(cx->base_addr, CX18_MEM_SIZE);
813free_workqueue:
814err:
815 if (retval == 0)
816 retval = -ENODEV;
817 CX18_ERR("Error %d on initialization\n", retval);
818
819 kfree(cx18_cards[cx18_cards_active]);
820 cx18_cards[cx18_cards_active] = NULL;
821 return retval;
822}
823
824int cx18_init_on_first_open(struct cx18 *cx)
825{
826 int video_input;
827 int fw_retry_count = 3;
828 struct v4l2_frequency vf;
829
830 if (test_bit(CX18_F_I_FAILED, &cx->i_flags))
831 return -ENXIO;
832
833 if (test_and_set_bit(CX18_F_I_INITED, &cx->i_flags))
834 return 0;
835
836 while (--fw_retry_count > 0) {
837 /* load firmware */
838 if (cx18_firmware_init(cx) == 0)
839 break;
840 if (fw_retry_count > 1)
841 CX18_WARN("Retry loading firmware\n");
842 }
843
844 if (fw_retry_count == 0) {
845 set_bit(CX18_F_I_FAILED, &cx->i_flags);
846 return -ENXIO;
847 }
848 set_bit(CX18_F_I_LOADED_FW, &cx->i_flags);
849
850 /* Init the firmware twice to work around a silicon bug
851 * transport related. */
852
853 fw_retry_count = 3;
854 while (--fw_retry_count > 0) {
855 /* load firmware */
856 if (cx18_firmware_init(cx) == 0)
857 break;
858 if (fw_retry_count > 1)
859 CX18_WARN("Retry loading firmware\n");
860 }
861
862 if (fw_retry_count == 0) {
863 set_bit(CX18_F_I_FAILED, &cx->i_flags);
864 return -ENXIO;
865 }
866
867 vf.tuner = 0;
868 vf.type = V4L2_TUNER_ANALOG_TV;
869 vf.frequency = 6400; /* the tuner 'baseline' frequency */
870
871 /* Set initial frequency. For PAL/SECAM broadcasts no
872 'default' channel exists AFAIK. */
873 if (cx->std == V4L2_STD_NTSC_M_JP)
874 vf.frequency = 1460; /* ch. 1 91250*16/1000 */
875 else if (cx->std & V4L2_STD_NTSC_M)
876 vf.frequency = 1076; /* ch. 4 67250*16/1000 */
877
878 video_input = cx->active_input;
879 cx->active_input++; /* Force update of input */
880 cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_INPUT, &video_input);
881
882 /* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
883 in one place. */
884 cx->std++; /* Force full standard initialization */
885 cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_STD, &cx->tuner_std);
886 cx18_v4l2_ioctls(cx, NULL, VIDIOC_S_FREQUENCY, &vf);
887 return 0;
888}
889
890static void cx18_remove(struct pci_dev *pci_dev)
891{
892 struct cx18 *cx = pci_get_drvdata(pci_dev);
893
894 CX18_DEBUG_INFO("Removing Card #%d\n", cx->num);
895
896 /* Stop all captures */
897 CX18_DEBUG_INFO("Stopping all streams\n");
898 if (atomic_read(&cx->capturing) > 0)
899 cx18_stop_all_captures(cx);
900
901 /* Interrupts */
902 sw1_irq_disable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
903 sw2_irq_disable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
904
905 cx18_halt_firmware(cx);
906
907 cx18_streams_cleanup(cx);
908
909 exit_cx18_i2c(cx);
910
911 free_irq(cx->dev->irq, (void *)cx);
912
913 if (cx->dev)
914 cx18_iounmap(cx);
915
916 release_mem_region(cx->base_addr, CX18_MEM_SIZE);
917
918 pci_disable_device(cx->dev);
919
920 CX18_INFO("Removed %s, card #%d\n", cx->card_name, cx->num);
921}
922
923/* define a pci_driver for card detection */
924static struct pci_driver cx18_pci_driver = {
925 .name = "cx18",
926 .id_table = cx18_pci_tbl,
927 .probe = cx18_probe,
928 .remove = cx18_remove,
929};
930
931static int module_start(void)
932{
933 printk(KERN_INFO "cx18: Start initialization, version %s\n", CX18_VERSION);
934
935 memset(cx18_cards, 0, sizeof(cx18_cards));
936
937 /* Validate parameters */
938 if (cx18_first_minor < 0 || cx18_first_minor >= CX18_MAX_CARDS) {
939 printk(KERN_ERR "cx18: Exiting, ivtv_first_minor must be between 0 and %d\n",
940 CX18_MAX_CARDS - 1);
941 return -1;
942 }
943
944 if (cx18_debug < 0 || cx18_debug > 511) {
945 cx18_debug = 0;
946 printk(KERN_INFO "cx18: Debug value must be >= 0 and <= 511!\n");
947 }
948
949 if (pci_register_driver(&cx18_pci_driver)) {
950 printk(KERN_ERR "cx18: Error detecting PCI card\n");
951 return -ENODEV;
952 }
953 printk(KERN_INFO "cx18: End initialization\n");
954 return 0;
955}
956
957static void module_cleanup(void)
958{
959 int i;
960
961 pci_unregister_driver(&cx18_pci_driver);
962
963 for (i = 0; i < cx18_cards_active; i++) {
964 if (cx18_cards[i] == NULL)
965 continue;
966 kfree(cx18_cards[i]);
967 }
968}
969
970module_init(module_start);
971module_exit(module_cleanup);
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
new file mode 100644
index 000000000000..2ee939193bb7
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -0,0 +1,500 @@
1/*
2 * cx18 driver internal defines and structures
3 *
4 * Derived from ivtv-driver.h
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 */
23
24#ifndef CX18_DRIVER_H
25#define CX18_DRIVER_H
26
27#include <linux/version.h>
28#include <linux/module.h>
29#include <linux/moduleparam.h>
30#include <linux/init.h>
31#include <linux/delay.h>
32#include <linux/sched.h>
33#include <linux/fs.h>
34#include <linux/pci.h>
35#include <linux/interrupt.h>
36#include <linux/spinlock.h>
37#include <linux/i2c.h>
38#include <linux/i2c-algo-bit.h>
39#include <linux/list.h>
40#include <linux/unistd.h>
41#include <linux/byteorder/swab.h>
42#include <linux/pagemap.h>
43#include <linux/workqueue.h>
44#include <linux/mutex.h>
45
46#include <linux/dvb/video.h>
47#include <linux/dvb/audio.h>
48#include <media/v4l2-common.h>
49#include <media/tuner.h>
50#include "cx18-mailbox.h"
51#include "cx18-av-core.h"
52#include "cx23418.h"
53
54/* DVB */
55#include "demux.h"
56#include "dmxdev.h"
57#include "dvb_demux.h"
58#include "dvb_frontend.h"
59#include "dvb_net.h"
60#include "dvbdev.h"
61
62#ifndef CONFIG_PCI
63# error "This driver requires kernel PCI support."
64#endif
65
66#define CX18_MEM_OFFSET 0x00000000
67#define CX18_MEM_SIZE 0x04000000
68#define CX18_REG_OFFSET 0x02000000
69
70/* Maximum cx18 driver instances. */
71#define CX18_MAX_CARDS 32
72
73/* Supported cards */
74#define CX18_CARD_HVR_1600_ESMT 0 /* Hauppauge HVR 1600 (ESMT memory) */
75#define CX18_CARD_HVR_1600_SAMSUNG 1 /* Hauppauge HVR 1600 (Samsung memory) */
76#define CX18_CARD_COMPRO_H900 2 /* Compro VideoMate H900 */
77#define CX18_CARD_YUAN_MPC718 3 /* Yuan MPC718 */
78#define CX18_CARD_LAST 3
79
80#define CX18_ENC_STREAM_TYPE_MPG 0
81#define CX18_ENC_STREAM_TYPE_TS 1
82#define CX18_ENC_STREAM_TYPE_YUV 2
83#define CX18_ENC_STREAM_TYPE_VBI 3
84#define CX18_ENC_STREAM_TYPE_PCM 4
85#define CX18_ENC_STREAM_TYPE_IDX 5
86#define CX18_ENC_STREAM_TYPE_RAD 6
87#define CX18_MAX_STREAMS 7
88
89/* system vendor and device IDs */
90#define PCI_VENDOR_ID_CX 0x14f1
91#define PCI_DEVICE_ID_CX23418 0x5b7a
92
93/* subsystem vendor ID */
94#define CX18_PCI_ID_HAUPPAUGE 0x0070
95#define CX18_PCI_ID_COMPRO 0x185b
96#define CX18_PCI_ID_YUAN 0x12ab
97
98/* ======================================================================== */
99/* ========================== START USER SETTABLE DMA VARIABLES =========== */
100/* ======================================================================== */
101
102/* DMA Buffers, Default size in MB allocated */
103#define CX18_DEFAULT_ENC_TS_BUFFERS 1
104#define CX18_DEFAULT_ENC_MPG_BUFFERS 2
105#define CX18_DEFAULT_ENC_IDX_BUFFERS 1
106#define CX18_DEFAULT_ENC_YUV_BUFFERS 2
107#define CX18_DEFAULT_ENC_VBI_BUFFERS 1
108#define CX18_DEFAULT_ENC_PCM_BUFFERS 1
109
110/* i2c stuff */
111#define I2C_CLIENTS_MAX 16
112
113/* debugging */
114
115/* Flag to turn on high volume debugging */
116#define CX18_DBGFLG_WARN (1 << 0)
117#define CX18_DBGFLG_INFO (1 << 1)
118#define CX18_DBGFLG_API (1 << 2)
119#define CX18_DBGFLG_DMA (1 << 3)
120#define CX18_DBGFLG_IOCTL (1 << 4)
121#define CX18_DBGFLG_FILE (1 << 5)
122#define CX18_DBGFLG_I2C (1 << 6)
123#define CX18_DBGFLG_IRQ (1 << 7)
124/* Flag to turn on high volume debugging */
125#define CX18_DBGFLG_HIGHVOL (1 << 8)
126
127/* NOTE: extra space before comma in 'cx->num , ## args' is required for
128 gcc-2.95, otherwise it won't compile. */
129#define CX18_DEBUG(x, type, fmt, args...) \
130 do { \
131 if ((x) & cx18_debug) \
132 printk(KERN_INFO "cx18-%d " type ": " fmt, cx->num , ## args); \
133 } while (0)
134#define CX18_DEBUG_WARN(fmt, args...) CX18_DEBUG(CX18_DBGFLG_WARN, "warning", fmt , ## args)
135#define CX18_DEBUG_INFO(fmt, args...) CX18_DEBUG(CX18_DBGFLG_INFO, "info", fmt , ## args)
136#define CX18_DEBUG_API(fmt, args...) CX18_DEBUG(CX18_DBGFLG_API, "api", fmt , ## args)
137#define CX18_DEBUG_DMA(fmt, args...) CX18_DEBUG(CX18_DBGFLG_DMA, "dma", fmt , ## args)
138#define CX18_DEBUG_IOCTL(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args)
139#define CX18_DEBUG_FILE(fmt, args...) CX18_DEBUG(CX18_DBGFLG_FILE, "file", fmt , ## args)
140#define CX18_DEBUG_I2C(fmt, args...) CX18_DEBUG(CX18_DBGFLG_I2C, "i2c", fmt , ## args)
141#define CX18_DEBUG_IRQ(fmt, args...) CX18_DEBUG(CX18_DBGFLG_IRQ, "irq", fmt , ## args)
142
143#define CX18_DEBUG_HIGH_VOL(x, type, fmt, args...) \
144 do { \
145 if (((x) & cx18_debug) && (cx18_debug & CX18_DBGFLG_HIGHVOL)) \
146 printk(KERN_INFO "cx18%d " type ": " fmt, cx->num , ## args); \
147 } while (0)
148#define CX18_DEBUG_HI_WARN(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_WARN, "warning", fmt , ## args)
149#define CX18_DEBUG_HI_INFO(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_INFO, "info", fmt , ## args)
150#define CX18_DEBUG_HI_API(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_API, "api", fmt , ## args)
151#define CX18_DEBUG_HI_DMA(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_DMA, "dma", fmt , ## args)
152#define CX18_DEBUG_HI_IOCTL(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IOCTL, "ioctl", fmt , ## args)
153#define CX18_DEBUG_HI_FILE(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_FILE, "file", fmt , ## args)
154#define CX18_DEBUG_HI_I2C(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_I2C, "i2c", fmt , ## args)
155#define CX18_DEBUG_HI_IRQ(fmt, args...) CX18_DEBUG_HIGH_VOL(CX18_DBGFLG_IRQ, "irq", fmt , ## args)
156
157/* Standard kernel messages */
158#define CX18_ERR(fmt, args...) printk(KERN_ERR "cx18-%d: " fmt, cx->num , ## args)
159#define CX18_WARN(fmt, args...) printk(KERN_WARNING "cx18-%d: " fmt, cx->num , ## args)
160#define CX18_INFO(fmt, args...) printk(KERN_INFO "cx18-%d: " fmt, cx->num , ## args)
161
162/* Values for CX18_API_DEC_PLAYBACK_SPEED mpeg_frame_type_mask parameter: */
163#define MPEG_FRAME_TYPE_IFRAME 1
164#define MPEG_FRAME_TYPE_IFRAME_PFRAME 3
165#define MPEG_FRAME_TYPE_ALL 7
166
167#define CX18_MAX_PGM_INDEX (400)
168
169extern int cx18_debug;
170
171
172struct cx18_options {
173 int megabytes[CX18_MAX_STREAMS]; /* Size in megabytes of each stream */
174 int cardtype; /* force card type on load */
175 int tuner; /* set tuner on load */
176 int radio; /* enable/disable radio */
177};
178
179/* per-buffer bit flags */
180#define CX18_F_B_NEED_BUF_SWAP 0 /* this buffer should be byte swapped */
181
182/* per-stream, s_flags */
183#define CX18_F_S_CLAIMED 3 /* this stream is claimed */
184#define CX18_F_S_STREAMING 4 /* the fw is decoding/encoding this stream */
185#define CX18_F_S_INTERNAL_USE 5 /* this stream is used internally (sliced VBI processing) */
186#define CX18_F_S_STREAMOFF 7 /* signal end of stream EOS */
187#define CX18_F_S_APPL_IO 8 /* this stream is used read/written by an application */
188
189/* per-cx18, i_flags */
190#define CX18_F_I_LOADED_FW 0 /* Loaded the firmware the first time */
191#define CX18_F_I_EOS 4 /* End of encoder stream reached */
192#define CX18_F_I_RADIO_USER 5 /* The radio tuner is selected */
193#define CX18_F_I_ENC_PAUSED 13 /* the encoder is paused */
194#define CX18_F_I_INITED 21 /* set after first open */
195#define CX18_F_I_FAILED 22 /* set if first open failed */
196
197/* These are the VBI types as they appear in the embedded VBI private packets. */
198#define CX18_SLICED_TYPE_TELETEXT_B (1)
199#define CX18_SLICED_TYPE_CAPTION_525 (4)
200#define CX18_SLICED_TYPE_WSS_625 (5)
201#define CX18_SLICED_TYPE_VPS (7)
202
203struct cx18_buffer {
204 struct list_head list;
205 dma_addr_t dma_handle;
206 u32 id;
207 unsigned long b_flags;
208 char *buf;
209
210 u32 bytesused;
211 u32 readpos;
212};
213
214struct cx18_queue {
215 struct list_head list;
216 u32 buffers;
217 u32 length;
218 u32 bytesused;
219};
220
221struct cx18_dvb {
222 struct dmx_frontend hw_frontend;
223 struct dmx_frontend mem_frontend;
224 struct dmxdev dmxdev;
225 struct dvb_adapter dvb_adapter;
226 struct dvb_demux demux;
227 struct dvb_frontend *fe;
228 struct dvb_net dvbnet;
229 int enabled;
230 int feeding;
231
232 struct mutex feedlock;
233
234};
235
236struct cx18; /* forward reference */
237struct cx18_scb; /* forward reference */
238
239struct cx18_stream {
240 /* These first four fields are always set, even if the stream
241 is not actually created. */
242 struct video_device *v4l2dev; /* NULL when stream not created */
243 struct cx18 *cx; /* for ease of use */
244 const char *name; /* name of the stream */
245 int type; /* stream type */
246 u32 handle; /* task handle */
247 unsigned mdl_offset;
248
249 u32 id;
250 spinlock_t qlock; /* locks access to the queues */
251 unsigned long s_flags; /* status flags, see above */
252 int dma; /* can be PCI_DMA_TODEVICE,
253 PCI_DMA_FROMDEVICE or
254 PCI_DMA_NONE */
255 u64 dma_pts;
256 wait_queue_head_t waitq;
257
258 /* Buffer Stats */
259 u32 buffers;
260 u32 buf_size;
261 u32 buffers_stolen;
262
263 /* Buffer Queues */
264 struct cx18_queue q_free; /* free buffers */
265 struct cx18_queue q_full; /* full buffers */
266 struct cx18_queue q_io; /* waiting for I/O */
267
268 /* DVB / Digital Transport */
269 struct cx18_dvb dvb;
270};
271
272struct cx18_open_id {
273 u32 open_id;
274 int type;
275 enum v4l2_priority prio;
276 struct cx18 *cx;
277};
278
279/* forward declaration of struct defined in cx18-cards.h */
280struct cx18_card;
281
282
283#define CX18_VBI_FRAMES 32
284
285/* VBI data */
286struct vbi_info {
287 u32 enc_size;
288 u32 frame;
289 u8 cc_data_odd[256];
290 u8 cc_data_even[256];
291 int cc_pos;
292 u8 cc_no_update;
293 u8 vps[5];
294 u8 vps_found;
295 int wss;
296 u8 wss_found;
297 u8 wss_no_update;
298 u32 raw_decoder_line_size;
299 u8 raw_decoder_sav_odd_field;
300 u8 raw_decoder_sav_even_field;
301 u32 sliced_decoder_line_size;
302 u8 sliced_decoder_sav_odd_field;
303 u8 sliced_decoder_sav_even_field;
304 struct v4l2_format in;
305 /* convenience pointer to sliced struct in vbi_in union */
306 struct v4l2_sliced_vbi_format *sliced_in;
307 u32 service_set_in;
308 int insert_mpeg;
309
310 /* Buffer for the maximum of 2 * 18 * packet_size sliced VBI lines.
311 One for /dev/vbi0 and one for /dev/vbi8 */
312 struct v4l2_sliced_vbi_data sliced_data[36];
313
314 /* Buffer for VBI data inserted into MPEG stream.
315 The first byte is a dummy byte that's never used.
316 The next 16 bytes contain the MPEG header for the VBI data,
317 the remainder is the actual VBI data.
318 The max size accepted by the MPEG VBI reinsertion turns out
319 to be 1552 bytes, which happens to be 4 + (1 + 42) * (2 * 18) bytes,
320 where 4 is a four byte header, 42 is the max sliced VBI payload, 1 is
321 a single line header byte and 2 * 18 is the number of VBI lines per frame.
322
323 However, it seems that the data must be 1K aligned, so we have to
324 pad the data until the 1 or 2 K boundary.
325
326 This pointer array will allocate 2049 bytes to store each VBI frame. */
327 u8 *sliced_mpeg_data[CX18_VBI_FRAMES];
328 u32 sliced_mpeg_size[CX18_VBI_FRAMES];
329 struct cx18_buffer sliced_mpeg_buf;
330 u32 inserted_frame;
331
332 u32 start[2], count;
333 u32 raw_size;
334 u32 sliced_size;
335};
336
337/* Per cx23418, per I2C bus private algo callback data */
338struct cx18_i2c_algo_callback_data {
339 struct cx18 *cx;
340 int bus_index; /* 0 or 1 for the cx23418's 1st or 2nd I2C bus */
341};
342
343/* Struct to hold info about cx18 cards */
344struct cx18 {
345 int num; /* board number, -1 during init! */
346 char name[8]; /* board name for printk and interrupts (e.g. 'cx180') */
347 struct pci_dev *dev; /* PCI device */
348 const struct cx18_card *card; /* card information */
349 const char *card_name; /* full name of the card */
350 const struct cx18_card_tuner_i2c *card_i2c; /* i2c addresses to probe for tuner */
351 u8 is_50hz;
352 u8 is_60hz;
353 u8 is_out_50hz;
354 u8 is_out_60hz;
355 u8 nof_inputs; /* number of video inputs */
356 u8 nof_audio_inputs; /* number of audio inputs */
357 u16 buffer_id; /* buffer ID counter */
358 u32 v4l2_cap; /* V4L2 capabilities of card */
359 u32 hw_flags; /* Hardware description of the board */
360 unsigned mdl_offset;
361 struct cx18_scb *scb; /* pointer to SCB */
362
363 struct cx18_av_state av_state;
364
365 /* codec settings */
366 struct cx2341x_mpeg_params params;
367 u32 filter_mode;
368 u32 temporal_strength;
369 u32 spatial_strength;
370
371 /* dualwatch */
372 unsigned long dualwatch_jiffies;
373 u16 dualwatch_stereo_mode;
374
375 /* Digitizer type */
376 int digitizer; /* 0x00EF = saa7114 0x00FO = saa7115 0x0106 = mic */
377
378 struct mutex serialize_lock; /* mutex used to serialize open/close/start/stop/ioctl operations */
379 struct cx18_options options; /* User options */
380 int stream_buf_size[CX18_MAX_STREAMS]; /* Stream buffer size */
381 struct cx18_stream streams[CX18_MAX_STREAMS]; /* Stream data */
382 unsigned long i_flags; /* global cx18 flags */
383 atomic_t capturing; /* count number of active capture streams */
384 spinlock_t lock; /* lock access to this struct */
385 int search_pack_header;
386
387 spinlock_t dma_reg_lock; /* lock access to DMA engine registers */
388
389 int open_id; /* incremented each time an open occurs, used as
390 unique ID. Starts at 1, so 0 can be used as
391 uninitialized value in the stream->id. */
392
393 u32 base_addr;
394 struct v4l2_prio_state prio;
395
396 u8 card_rev;
397 void __iomem *enc_mem, *reg_mem;
398
399 struct vbi_info vbi;
400
401 u32 pgm_info_offset;
402 u32 pgm_info_num;
403 u32 pgm_info_write_idx;
404 u32 pgm_info_read_idx;
405 struct v4l2_enc_idx_entry pgm_info[CX18_MAX_PGM_INDEX];
406
407 u64 mpg_data_received;
408 u64 vbi_data_inserted;
409
410 wait_queue_head_t mb_apu_waitq;
411 wait_queue_head_t mb_cpu_waitq;
412 wait_queue_head_t mb_epu_waitq;
413 wait_queue_head_t mb_hpu_waitq;
414 wait_queue_head_t cap_w;
415 /* when the current DMA is finished this queue is woken up */
416 wait_queue_head_t dma_waitq;
417
418 /* i2c */
419 struct i2c_adapter i2c_adap[2];
420 struct i2c_algo_bit_data i2c_algo[2];
421 struct cx18_i2c_algo_callback_data i2c_algo_cb_data[2];
422 struct i2c_client i2c_client[2];
423 struct mutex i2c_bus_lock[2];
424 struct i2c_client *i2c_clients[I2C_CLIENTS_MAX];
425
426 /* v4l2 and User settings */
427
428 /* codec settings */
429 u32 audio_input;
430 u32 active_input;
431 u32 active_output;
432 v4l2_std_id std;
433 v4l2_std_id tuner_std; /* The norm of the tuner (fixed) */
434};
435
436/* Globals */
437extern struct cx18 *cx18_cards[];
438extern int cx18_cards_active;
439extern int cx18_first_minor;
440extern spinlock_t cx18_cards_lock;
441
442/*==============Prototypes==================*/
443
444/* Return non-zero if a signal is pending */
445int cx18_msleep_timeout(unsigned int msecs, int intr);
446
447/* Wait on queue, returns -EINTR if interrupted */
448int cx18_waitq(wait_queue_head_t *waitq);
449
450/* Read Hauppauge eeprom */
451struct tveeprom; /* forward reference */
452void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv);
453
454/* First-open initialization: load firmware, etc. */
455int cx18_init_on_first_open(struct cx18 *cx);
456
457/* This is a PCI post thing, where if the pci register is not read, then
458 the write doesn't always take effect right away. By reading back the
459 register any pending PCI writes will be performed (in order), and so
460 you can be sure that the writes are guaranteed to be done.
461
462 Rarely needed, only in some timing sensitive cases.
463 Apparently if this is not done some motherboards seem
464 to kill the firmware and get into the broken state until computer is
465 rebooted. */
466#define write_sync(val, reg) \
467 do { writel(val, reg); readl(reg); } while (0)
468
469#define read_reg(reg) readl(cx->reg_mem + (reg))
470#define write_reg(val, reg) writel(val, cx->reg_mem + (reg))
471#define write_reg_sync(val, reg) \
472 do { write_reg(val, reg); read_reg(reg); } while (0)
473
474#define read_enc(addr) readl(cx->enc_mem + (u32)(addr))
475#define write_enc(val, addr) writel(val, cx->enc_mem + (u32)(addr))
476#define write_enc_sync(val, addr) \
477 do { write_enc(val, addr); read_enc(addr); } while (0)
478
479#define sw1_irq_enable(val) do { \
480 write_reg(val, SW1_INT_STATUS); \
481 write_reg(read_reg(SW1_INT_ENABLE_PCI) | (val), SW1_INT_ENABLE_PCI); \
482} while (0)
483
484#define sw1_irq_disable(val) \
485 write_reg(read_reg(SW1_INT_ENABLE_PCI) & ~(val), SW1_INT_ENABLE_PCI);
486
487#define sw2_irq_enable(val) do { \
488 write_reg(val, SW2_INT_STATUS); \
489 write_reg(read_reg(SW2_INT_ENABLE_PCI) | (val), SW2_INT_ENABLE_PCI); \
490} while (0)
491
492#define sw2_irq_disable(val) \
493 write_reg(read_reg(SW2_INT_ENABLE_PCI) & ~(val), SW2_INT_ENABLE_PCI);
494
495#define setup_page(addr) do { \
496 u32 val = read_reg(0xD000F8) & ~0x1f00; \
497 write_reg(val | (((addr) >> 17) & 0x1f00), 0xD000F8); \
498} while (0)
499
500#endif /* CX18_DRIVER_H */
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c
new file mode 100644
index 000000000000..65efe69d939a
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-dvb.c
@@ -0,0 +1,288 @@
1/*
2 * cx18 functions for DVB support
3 *
4 * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 *
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 "cx18-version.h"
23#include "cx18-dvb.h"
24#include "cx18-streams.h"
25#include "cx18-cards.h"
26#include "s5h1409.h"
27
28/* Wait until the MXL500X driver is merged */
29#ifdef HAVE_MXL500X
30#include "mxl500x.h"
31#endif
32
33DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
34
35#define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000
36
37#ifdef HAVE_MXL500X
38static struct mxl500x_config hauppauge_hvr1600_tuner = {
39 .delsys = MXL500x_MODE_ATSC,
40 .octf = MXL500x_OCTF_CH,
41 .xtal_freq = 16000000,
42 .iflo_freq = 5380000,
43 .ref_freq = 322800000,
44 .rssi_ena = MXL_RSSI_ENABLE,
45 .addr = 0xC6 >> 1,
46};
47
48static struct s5h1409_config hauppauge_hvr1600_config = {
49 .demod_address = 0x32 >> 1,
50 .output_mode = S5H1409_SERIAL_OUTPUT,
51 .gpio = S5H1409_GPIO_ON,
52 .qam_if = 44000,
53 .inversion = S5H1409_INVERSION_OFF,
54 .status_mode = S5H1409_DEMODLOCKING,
55 .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
56
57};
58#endif
59
60static int dvb_register(struct cx18_stream *stream);
61
62/* Kernel DVB framework calls this when the feed needs to start.
63 * The CX18 framework should enable the transport DMA handling
64 * and queue processing.
65 */
66static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
67{
68 struct dvb_demux *demux = feed->demux;
69 struct cx18_stream *stream = (struct cx18_stream *) demux->priv;
70 struct cx18 *cx = stream->cx;
71 int ret = -EINVAL;
72 u32 v;
73
74 CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n",
75 feed->pid, feed->index);
76 switch (cx->card->type) {
77 case CX18_CARD_HVR_1600_ESMT:
78 case CX18_CARD_HVR_1600_SAMSUNG:
79 v = read_reg(CX18_REG_DMUX_NUM_PORT_0_CONTROL);
80 v |= 0x00400000; /* Serial Mode */
81 v |= 0x00002000; /* Data Length - Byte */
82 v |= 0x00010000; /* Error - Polarity */
83 v |= 0x00020000; /* Error - Passthru */
84 v |= 0x000c0000; /* Error - Ignore */
85 write_reg(v, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
86 break;
87
88 default:
89 /* Assumption - Parallel transport - Signalling
90 * undefined or default.
91 */
92 break;
93 }
94
95 if (!demux->dmx.frontend)
96 return -EINVAL;
97
98 if (stream) {
99 mutex_lock(&stream->dvb.feedlock);
100 if (stream->dvb.feeding++ == 0) {
101 CX18_DEBUG_INFO("Starting Transport DMA\n");
102 ret = cx18_start_v4l2_encode_stream(stream);
103 } else
104 ret = 0;
105 mutex_unlock(&stream->dvb.feedlock);
106 }
107
108 return ret;
109}
110
111/* Kernel DVB framework calls this when the feed needs to stop. */
112static int cx18_dvb_stop_feed(struct dvb_demux_feed *feed)
113{
114 struct dvb_demux *demux = feed->demux;
115 struct cx18_stream *stream = (struct cx18_stream *)demux->priv;
116 struct cx18 *cx = stream->cx;
117 int ret = -EINVAL;
118
119 CX18_DEBUG_INFO("Stop feed: pid = 0x%x index = %d\n",
120 feed->pid, feed->index);
121
122 if (stream) {
123 mutex_lock(&stream->dvb.feedlock);
124 if (--stream->dvb.feeding == 0) {
125 CX18_DEBUG_INFO("Stopping Transport DMA\n");
126 ret = cx18_stop_v4l2_encode_stream(stream, 0);
127 } else
128 ret = 0;
129 mutex_unlock(&stream->dvb.feedlock);
130 }
131
132 return ret;
133}
134
135int cx18_dvb_register(struct cx18_stream *stream)
136{
137 struct cx18 *cx = stream->cx;
138 struct cx18_dvb *dvb = &stream->dvb;
139 struct dvb_adapter *dvb_adapter;
140 struct dvb_demux *dvbdemux;
141 struct dmx_demux *dmx;
142 int ret;
143
144 if (!dvb)
145 return -EINVAL;
146
147 ret = dvb_register_adapter(&dvb->dvb_adapter,
148 CX18_DRIVER_NAME,
149 THIS_MODULE, &cx->dev->dev, adapter_nr);
150 if (ret < 0)
151 goto err_out;
152
153 dvb_adapter = &dvb->dvb_adapter;
154
155 dvbdemux = &dvb->demux;
156
157 dvbdemux->priv = (void *)stream;
158
159 dvbdemux->filternum = 256;
160 dvbdemux->feednum = 256;
161 dvbdemux->start_feed = cx18_dvb_start_feed;
162 dvbdemux->stop_feed = cx18_dvb_stop_feed;
163 dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
164 DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
165 ret = dvb_dmx_init(dvbdemux);
166 if (ret < 0)
167 goto err_dvb_unregister_adapter;
168
169 dmx = &dvbdemux->dmx;
170
171 dvb->hw_frontend.source = DMX_FRONTEND_0;
172 dvb->mem_frontend.source = DMX_MEMORY_FE;
173 dvb->dmxdev.filternum = 256;
174 dvb->dmxdev.demux = dmx;
175
176 ret = dvb_dmxdev_init(&dvb->dmxdev, dvb_adapter);
177 if (ret < 0)
178 goto err_dvb_dmx_release;
179
180 ret = dmx->add_frontend(dmx, &dvb->hw_frontend);
181 if (ret < 0)
182 goto err_dvb_dmxdev_release;
183
184 ret = dmx->add_frontend(dmx, &dvb->mem_frontend);
185 if (ret < 0)
186 goto err_remove_hw_frontend;
187
188 ret = dmx->connect_frontend(dmx, &dvb->hw_frontend);
189 if (ret < 0)
190 goto err_remove_mem_frontend;
191
192 ret = dvb_register(stream);
193 if (ret < 0)
194 goto err_disconnect_frontend;
195
196 dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx);
197
198 CX18_INFO("DVB Frontend registered\n");
199 mutex_init(&dvb->feedlock);
200 dvb->enabled = 1;
201 return ret;
202
203err_disconnect_frontend:
204 dmx->disconnect_frontend(dmx);
205err_remove_mem_frontend:
206 dmx->remove_frontend(dmx, &dvb->mem_frontend);
207err_remove_hw_frontend:
208 dmx->remove_frontend(dmx, &dvb->hw_frontend);
209err_dvb_dmxdev_release:
210 dvb_dmxdev_release(&dvb->dmxdev);
211err_dvb_dmx_release:
212 dvb_dmx_release(dvbdemux);
213err_dvb_unregister_adapter:
214 dvb_unregister_adapter(dvb_adapter);
215err_out:
216 return ret;
217}
218
219void cx18_dvb_unregister(struct cx18_stream *stream)
220{
221 struct cx18 *cx = stream->cx;
222 struct cx18_dvb *dvb = &stream->dvb;
223 struct dvb_adapter *dvb_adapter;
224 struct dvb_demux *dvbdemux;
225 struct dmx_demux *dmx;
226
227 CX18_INFO("unregister DVB\n");
228
229 dvb_adapter = &dvb->dvb_adapter;
230 dvbdemux = &dvb->demux;
231 dmx = &dvbdemux->dmx;
232
233 dmx->close(dmx);
234 dvb_net_release(&dvb->dvbnet);
235 dmx->remove_frontend(dmx, &dvb->mem_frontend);
236 dmx->remove_frontend(dmx, &dvb->hw_frontend);
237 dvb_dmxdev_release(&dvb->dmxdev);
238 dvb_dmx_release(dvbdemux);
239 dvb_unregister_frontend(dvb->fe);
240 dvb_frontend_detach(dvb->fe);
241 dvb_unregister_adapter(dvb_adapter);
242}
243
244/* All the DVB attach calls go here, this function get's modified
245 * for each new card. No other function in this file needs
246 * to change.
247 */
248static int dvb_register(struct cx18_stream *stream)
249{
250 struct cx18_dvb *dvb = &stream->dvb;
251 struct cx18 *cx = stream->cx;
252 int ret = 0;
253
254 switch (cx->card->type) {
255/* Wait until the MXL500X driver is merged */
256#ifdef HAVE_MXL500X
257 case CX18_CARD_HVR_1600_ESMT:
258 case CX18_CARD_HVR_1600_SAMSUNG:
259 dvb->fe = dvb_attach(s5h1409_attach,
260 &hauppauge_hvr1600_config,
261 &cx->i2c_adap[0]);
262 if (dvb->fe != NULL) {
263 dvb_attach(mxl500x_attach, dvb->fe,
264 &hauppauge_hvr1600_tuner,
265 &cx->i2c_adap[0]);
266 ret = 0;
267 }
268 break;
269#endif
270 default:
271 /* No Digital Tv Support */
272 break;
273 }
274
275 if (dvb->fe == NULL) {
276 CX18_ERR("frontend initialization failed\n");
277 return -1;
278 }
279
280 ret = dvb_register_frontend(&dvb->dvb_adapter, dvb->fe);
281 if (ret < 0) {
282 if (dvb->fe->ops.release)
283 dvb->fe->ops.release(dvb->fe);
284 return ret;
285 }
286
287 return ret;
288}
diff --git a/drivers/media/video/cx18/cx18-dvb.h b/drivers/media/video/cx18/cx18-dvb.h
new file mode 100644
index 000000000000..d6a6ccda79a9
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-dvb.h
@@ -0,0 +1,25 @@
1/*
2 * cx18 functions for DVB support
3 *
4 * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 *
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 "cx18-driver.h"
23
24int cx18_dvb_register(struct cx18_stream *stream);
25void cx18_dvb_unregister(struct cx18_stream *stream);
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
new file mode 100644
index 000000000000..69303065a294
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-fileops.c
@@ -0,0 +1,711 @@
1/*
2 * cx18 file operation functions
3 *
4 * Derived from ivtv-fileops.c
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 */
23
24#include "cx18-driver.h"
25#include "cx18-fileops.h"
26#include "cx18-i2c.h"
27#include "cx18-queue.h"
28#include "cx18-vbi.h"
29#include "cx18-audio.h"
30#include "cx18-mailbox.h"
31#include "cx18-scb.h"
32#include "cx18-streams.h"
33#include "cx18-controls.h"
34#include "cx18-ioctl.h"
35#include "cx18-cards.h"
36
37/* This function tries to claim the stream for a specific file descriptor.
38 If no one else is using this stream then the stream is claimed and
39 associated VBI streams are also automatically claimed.
40 Possible error returns: -EBUSY if someone else has claimed
41 the stream or 0 on success. */
42int cx18_claim_stream(struct cx18_open_id *id, int type)
43{
44 struct cx18 *cx = id->cx;
45 struct cx18_stream *s = &cx->streams[type];
46 struct cx18_stream *s_vbi;
47 int vbi_type;
48
49 if (test_and_set_bit(CX18_F_S_CLAIMED, &s->s_flags)) {
50 /* someone already claimed this stream */
51 if (s->id == id->open_id) {
52 /* yes, this file descriptor did. So that's OK. */
53 return 0;
54 }
55 if (s->id == -1 && type == CX18_ENC_STREAM_TYPE_VBI) {
56 /* VBI is handled already internally, now also assign
57 the file descriptor to this stream for external
58 reading of the stream. */
59 s->id = id->open_id;
60 CX18_DEBUG_INFO("Start Read VBI\n");
61 return 0;
62 }
63 /* someone else is using this stream already */
64 CX18_DEBUG_INFO("Stream %d is busy\n", type);
65 return -EBUSY;
66 }
67 s->id = id->open_id;
68
69 /* CX18_DEC_STREAM_TYPE_MPG needs to claim CX18_DEC_STREAM_TYPE_VBI,
70 CX18_ENC_STREAM_TYPE_MPG needs to claim CX18_ENC_STREAM_TYPE_VBI
71 (provided VBI insertion is on and sliced VBI is selected), for all
72 other streams we're done */
73 if (type == CX18_ENC_STREAM_TYPE_MPG &&
74 cx->vbi.insert_mpeg && cx->vbi.sliced_in->service_set) {
75 vbi_type = CX18_ENC_STREAM_TYPE_VBI;
76 } else {
77 return 0;
78 }
79 s_vbi = &cx->streams[vbi_type];
80
81 set_bit(CX18_F_S_CLAIMED, &s_vbi->s_flags);
82
83 /* mark that it is used internally */
84 set_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags);
85 return 0;
86}
87
88/* This function releases a previously claimed stream. It will take into
89 account associated VBI streams. */
90void cx18_release_stream(struct cx18_stream *s)
91{
92 struct cx18 *cx = s->cx;
93 struct cx18_stream *s_vbi;
94
95 s->id = -1;
96 if (s->type == CX18_ENC_STREAM_TYPE_VBI &&
97 test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags)) {
98 /* this stream is still in use internally */
99 return;
100 }
101 if (!test_and_clear_bit(CX18_F_S_CLAIMED, &s->s_flags)) {
102 CX18_DEBUG_WARN("Release stream %s not in use!\n", s->name);
103 return;
104 }
105
106 cx18_flush_queues(s);
107
108 /* CX18_ENC_STREAM_TYPE_MPG needs to release CX18_ENC_STREAM_TYPE_VBI,
109 for all other streams we're done */
110 if (s->type == CX18_ENC_STREAM_TYPE_MPG)
111 s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
112 else
113 return;
114
115 /* clear internal use flag */
116 if (!test_and_clear_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags)) {
117 /* was already cleared */
118 return;
119 }
120 if (s_vbi->id != -1) {
121 /* VBI stream still claimed by a file descriptor */
122 return;
123 }
124 clear_bit(CX18_F_S_CLAIMED, &s_vbi->s_flags);
125 cx18_flush_queues(s_vbi);
126}
127
128static void cx18_dualwatch(struct cx18 *cx)
129{
130 struct v4l2_tuner vt;
131 u16 new_bitmap;
132 u16 new_stereo_mode;
133 const u16 stereo_mask = 0x0300;
134 const u16 dual = 0x0200;
135
136 new_stereo_mode = cx->params.audio_properties & stereo_mask;
137 memset(&vt, 0, sizeof(vt));
138 cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, &vt);
139 if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 &&
140 (vt.rxsubchans & V4L2_TUNER_SUB_LANG2))
141 new_stereo_mode = dual;
142
143 if (new_stereo_mode == cx->dualwatch_stereo_mode)
144 return;
145
146 new_bitmap = new_stereo_mode | (cx->params.audio_properties & ~stereo_mask);
147
148 CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. new audio_bitmask=0x%ux\n",
149 cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap);
150
151 if (cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2,
152 cx18_find_handle(cx), new_bitmap) == 0) {
153 cx->dualwatch_stereo_mode = new_stereo_mode;
154 return;
155 }
156 CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
157}
158
159
160static struct cx18_buffer *cx18_get_buffer(struct cx18_stream *s, int non_block, int *err)
161{
162 struct cx18 *cx = s->cx;
163 struct cx18_stream *s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
164 struct cx18_buffer *buf;
165 DEFINE_WAIT(wait);
166
167 *err = 0;
168 while (1) {
169 if (s->type == CX18_ENC_STREAM_TYPE_MPG) {
170
171 if (time_after(jiffies, cx->dualwatch_jiffies + msecs_to_jiffies(1000))) {
172 cx->dualwatch_jiffies = jiffies;
173 cx18_dualwatch(cx);
174 }
175 if (test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
176 !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
177 while ((buf = cx18_dequeue(s_vbi, &s_vbi->q_full))) {
178 /* byteswap and process VBI data */
179/* cx18_process_vbi_data(cx, buf, s_vbi->dma_pts, s_vbi->type); */
180 cx18_enqueue(s_vbi, buf, &s_vbi->q_free);
181 }
182 }
183 buf = &cx->vbi.sliced_mpeg_buf;
184 if (buf->readpos != buf->bytesused)
185 return buf;
186 }
187
188 /* do we have leftover data? */
189 buf = cx18_dequeue(s, &s->q_io);
190 if (buf)
191 return buf;
192
193 /* do we have new data? */
194 buf = cx18_dequeue(s, &s->q_full);
195 if (buf) {
196 if (!test_and_clear_bit(CX18_F_B_NEED_BUF_SWAP,
197 &buf->b_flags))
198 return buf;
199 if (s->type == CX18_ENC_STREAM_TYPE_MPG)
200 /* byteswap MPG data */
201 cx18_buf_swap(buf);
202 else {
203 /* byteswap and process VBI data */
204 cx18_process_vbi_data(cx, buf,
205 s->dma_pts, s->type);
206 }
207 return buf;
208 }
209
210 /* return if end of stream */
211 if (!test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
212 CX18_DEBUG_INFO("EOS %s\n", s->name);
213 return NULL;
214 }
215
216 /* return if file was opened with O_NONBLOCK */
217 if (non_block) {
218 *err = -EAGAIN;
219 return NULL;
220 }
221
222 /* wait for more data to arrive */
223 prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
224 /* New buffers might have become available before we were added
225 to the waitqueue */
226 if (!s->q_full.buffers)
227 schedule();
228 finish_wait(&s->waitq, &wait);
229 if (signal_pending(current)) {
230 /* return if a signal was received */
231 CX18_DEBUG_INFO("User stopped %s\n", s->name);
232 *err = -EINTR;
233 return NULL;
234 }
235 }
236}
237
238static void cx18_setup_sliced_vbi_buf(struct cx18 *cx)
239{
240 int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES;
241
242 cx->vbi.sliced_mpeg_buf.buf = cx->vbi.sliced_mpeg_data[idx];
243 cx->vbi.sliced_mpeg_buf.bytesused = cx->vbi.sliced_mpeg_size[idx];
244 cx->vbi.sliced_mpeg_buf.readpos = 0;
245}
246
247static size_t cx18_copy_buf_to_user(struct cx18_stream *s,
248 struct cx18_buffer *buf, char __user *ubuf, size_t ucount)
249{
250 struct cx18 *cx = s->cx;
251 size_t len = buf->bytesused - buf->readpos;
252
253 if (len > ucount)
254 len = ucount;
255 if (cx->vbi.insert_mpeg && s->type == CX18_ENC_STREAM_TYPE_MPG &&
256 cx->vbi.sliced_in->service_set && buf != &cx->vbi.sliced_mpeg_buf) {
257 const char *start = buf->buf + buf->readpos;
258 const char *p = start + 1;
259 const u8 *q;
260 u8 ch = cx->search_pack_header ? 0xba : 0xe0;
261 int stuffing, i;
262
263 while (start + len > p) {
264 q = memchr(p, 0, start + len - p);
265 if (q == NULL)
266 break;
267 p = q + 1;
268 if ((char *)q + 15 >= buf->buf + buf->bytesused ||
269 q[1] != 0 || q[2] != 1 || q[3] != ch)
270 continue;
271 if (!cx->search_pack_header) {
272 if ((q[6] & 0xc0) != 0x80)
273 continue;
274 if (((q[7] & 0xc0) == 0x80 &&
275 (q[9] & 0xf0) == 0x20) ||
276 ((q[7] & 0xc0) == 0xc0 &&
277 (q[9] & 0xf0) == 0x30)) {
278 ch = 0xba;
279 cx->search_pack_header = 1;
280 p = q + 9;
281 }
282 continue;
283 }
284 stuffing = q[13] & 7;
285 /* all stuffing bytes must be 0xff */
286 for (i = 0; i < stuffing; i++)
287 if (q[14 + i] != 0xff)
288 break;
289 if (i == stuffing &&
290 (q[4] & 0xc4) == 0x44 &&
291 (q[12] & 3) == 3 &&
292 q[14 + stuffing] == 0 &&
293 q[15 + stuffing] == 0 &&
294 q[16 + stuffing] == 1) {
295 cx->search_pack_header = 0;
296 len = (char *)q - start;
297 cx18_setup_sliced_vbi_buf(cx);
298 break;
299 }
300 }
301 }
302 if (copy_to_user(ubuf, (u8 *)buf->buf + buf->readpos, len)) {
303 CX18_DEBUG_WARN("copy %zd bytes to user failed for %s\n",
304 len, s->name);
305 return -EFAULT;
306 }
307 buf->readpos += len;
308 if (s->type == CX18_ENC_STREAM_TYPE_MPG &&
309 buf != &cx->vbi.sliced_mpeg_buf)
310 cx->mpg_data_received += len;
311 return len;
312}
313
314static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf,
315 size_t tot_count, int non_block)
316{
317 struct cx18 *cx = s->cx;
318 size_t tot_written = 0;
319 int single_frame = 0;
320
321 if (atomic_read(&cx->capturing) == 0 && s->id == -1) {
322 /* shouldn't happen */
323 CX18_DEBUG_WARN("Stream %s not initialized before read\n",
324 s->name);
325 return -EIO;
326 }
327
328 /* Each VBI buffer is one frame, the v4l2 API says that for VBI the
329 frames should arrive one-by-one, so make sure we never output more
330 than one VBI frame at a time */
331 if (s->type == CX18_ENC_STREAM_TYPE_VBI &&
332 cx->vbi.sliced_in->service_set)
333 single_frame = 1;
334
335 for (;;) {
336 struct cx18_buffer *buf;
337 int rc;
338
339 buf = cx18_get_buffer(s, non_block, &rc);
340 /* if there is no data available... */
341 if (buf == NULL) {
342 /* if we got data, then return that regardless */
343 if (tot_written)
344 break;
345 /* EOS condition */
346 if (rc == 0) {
347 clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
348 clear_bit(CX18_F_S_APPL_IO, &s->s_flags);
349 cx18_release_stream(s);
350 }
351 /* set errno */
352 return rc;
353 }
354
355 rc = cx18_copy_buf_to_user(s, buf, ubuf + tot_written,
356 tot_count - tot_written);
357
358 if (buf != &cx->vbi.sliced_mpeg_buf) {
359 if (buf->readpos == buf->bytesused) {
360 cx18_buf_sync_for_device(s, buf);
361 cx18_enqueue(s, buf, &s->q_free);
362 cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5,
363 s->handle,
364 (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
365 1, buf->id, s->buf_size);
366 } else
367 cx18_enqueue(s, buf, &s->q_io);
368 } else if (buf->readpos == buf->bytesused) {
369 int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES;
370
371 cx->vbi.sliced_mpeg_size[idx] = 0;
372 cx->vbi.inserted_frame++;
373 cx->vbi_data_inserted += buf->bytesused;
374 }
375 if (rc < 0)
376 return rc;
377 tot_written += rc;
378
379 if (tot_written == tot_count || single_frame)
380 break;
381 }
382 return tot_written;
383}
384
385static ssize_t cx18_read_pos(struct cx18_stream *s, char __user *ubuf,
386 size_t count, loff_t *pos, int non_block)
387{
388 ssize_t rc = count ? cx18_read(s, ubuf, count, non_block) : 0;
389 struct cx18 *cx = s->cx;
390
391 CX18_DEBUG_HI_FILE("read %zd from %s, got %zd\n", count, s->name, rc);
392 if (rc > 0)
393 pos += rc;
394 return rc;
395}
396
397int cx18_start_capture(struct cx18_open_id *id)
398{
399 struct cx18 *cx = id->cx;
400 struct cx18_stream *s = &cx->streams[id->type];
401 struct cx18_stream *s_vbi;
402
403 if (s->type == CX18_ENC_STREAM_TYPE_RAD) {
404 /* you cannot read from these stream types. */
405 return -EPERM;
406 }
407
408 /* Try to claim this stream. */
409 if (cx18_claim_stream(id, s->type))
410 return -EBUSY;
411
412 /* If capture is already in progress, then we also have to
413 do nothing extra. */
414 if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) ||
415 test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) {
416 set_bit(CX18_F_S_APPL_IO, &s->s_flags);
417 return 0;
418 }
419
420 /* Start VBI capture if required */
421 s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
422 if (s->type == CX18_ENC_STREAM_TYPE_MPG &&
423 test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
424 !test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) {
425 /* Note: the CX18_ENC_STREAM_TYPE_VBI is claimed
426 automatically when the MPG stream is claimed.
427 We only need to start the VBI capturing. */
428 if (cx18_start_v4l2_encode_stream(s_vbi)) {
429 CX18_DEBUG_WARN("VBI capture start failed\n");
430
431 /* Failure, clean up and return an error */
432 clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);
433 clear_bit(CX18_F_S_STREAMING, &s->s_flags);
434 /* also releases the associated VBI stream */
435 cx18_release_stream(s);
436 return -EIO;
437 }
438 CX18_DEBUG_INFO("VBI insertion started\n");
439 }
440
441 /* Tell the card to start capturing */
442 if (!cx18_start_v4l2_encode_stream(s)) {
443 /* We're done */
444 set_bit(CX18_F_S_APPL_IO, &s->s_flags);
445 /* Resume a possibly paused encoder */
446 if (test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
447 cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, s->handle);
448 return 0;
449 }
450
451 /* failure, clean up */
452 CX18_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name);
453
454 /* Note: the CX18_ENC_STREAM_TYPE_VBI is released
455 automatically when the MPG stream is released.
456 We only need to stop the VBI capturing. */
457 if (s->type == CX18_ENC_STREAM_TYPE_MPG &&
458 test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) {
459 cx18_stop_v4l2_encode_stream(s_vbi, 0);
460 clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);
461 }
462 clear_bit(CX18_F_S_STREAMING, &s->s_flags);
463 cx18_release_stream(s);
464 return -EIO;
465}
466
467ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
468 loff_t *pos)
469{
470 struct cx18_open_id *id = filp->private_data;
471 struct cx18 *cx = id->cx;
472 struct cx18_stream *s = &cx->streams[id->type];
473 int rc;
474
475 CX18_DEBUG_HI_FILE("read %zd bytes from %s\n", count, s->name);
476
477 mutex_lock(&cx->serialize_lock);
478 rc = cx18_start_capture(id);
479 mutex_unlock(&cx->serialize_lock);
480 if (rc)
481 return rc;
482 return cx18_read_pos(s, buf, count, pos, filp->f_flags & O_NONBLOCK);
483}
484
485unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait)
486{
487 struct cx18_open_id *id = filp->private_data;
488 struct cx18 *cx = id->cx;
489 struct cx18_stream *s = &cx->streams[id->type];
490 int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags);
491
492 /* Start a capture if there is none */
493 if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
494 int rc;
495
496 mutex_lock(&cx->serialize_lock);
497 rc = cx18_start_capture(id);
498 mutex_unlock(&cx->serialize_lock);
499 if (rc) {
500 CX18_DEBUG_INFO("Could not start capture for %s (%d)\n",
501 s->name, rc);
502 return POLLERR;
503 }
504 CX18_DEBUG_FILE("Encoder poll started capture\n");
505 }
506
507 /* add stream's waitq to the poll list */
508 CX18_DEBUG_HI_FILE("Encoder poll\n");
509 poll_wait(filp, &s->waitq, wait);
510
511 if (s->q_full.length || s->q_io.length)
512 return POLLIN | POLLRDNORM;
513 if (eof)
514 return POLLHUP;
515 return 0;
516}
517
518void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
519{
520 struct cx18 *cx = id->cx;
521 struct cx18_stream *s = &cx->streams[id->type];
522
523 CX18_DEBUG_IOCTL("close() of %s\n", s->name);
524
525 /* 'Unclaim' this stream */
526
527 /* Stop capturing */
528 if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
529 struct cx18_stream *s_vbi =
530 &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
531
532 CX18_DEBUG_INFO("close stopping capture\n");
533 /* Special case: a running VBI capture for VBI insertion
534 in the mpeg stream. Need to stop that too. */
535 if (id->type == CX18_ENC_STREAM_TYPE_MPG &&
536 test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) &&
537 !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
538 CX18_DEBUG_INFO("close stopping embedded VBI capture\n");
539 cx18_stop_v4l2_encode_stream(s_vbi, 0);
540 }
541 if (id->type == CX18_ENC_STREAM_TYPE_VBI &&
542 test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags))
543 /* Also used internally, don't stop capturing */
544 s->id = -1;
545 else
546 cx18_stop_v4l2_encode_stream(s, gop_end);
547 }
548 if (!gop_end) {
549 clear_bit(CX18_F_S_APPL_IO, &s->s_flags);
550 clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
551 cx18_release_stream(s);
552 }
553}
554
555int cx18_v4l2_close(struct inode *inode, struct file *filp)
556{
557 struct cx18_open_id *id = filp->private_data;
558 struct cx18 *cx = id->cx;
559 struct cx18_stream *s = &cx->streams[id->type];
560
561 CX18_DEBUG_IOCTL("close() of %s\n", s->name);
562
563 v4l2_prio_close(&cx->prio, &id->prio);
564
565 /* Easy case first: this stream was never claimed by us */
566 if (s->id != id->open_id) {
567 kfree(id);
568 return 0;
569 }
570
571 /* 'Unclaim' this stream */
572
573 /* Stop radio */
574 mutex_lock(&cx->serialize_lock);
575 if (id->type == CX18_ENC_STREAM_TYPE_RAD) {
576 /* Closing radio device, return to TV mode */
577 cx18_mute(cx);
578 /* Mark that the radio is no longer in use */
579 clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags);
580 /* Switch tuner to TV */
581 cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
582 /* Select correct audio input (i.e. TV tuner or Line in) */
583 cx18_audio_set_io(cx);
584 if (atomic_read(&cx->capturing) > 0) {
585 /* Undo video mute */
586 cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
587 cx->params.video_mute |
588 (cx->params.video_mute_yuv << 8));
589 }
590 /* Done! Unmute and continue. */
591 cx18_unmute(cx);
592 cx18_release_stream(s);
593 } else {
594 cx18_stop_capture(id, 0);
595 }
596 kfree(id);
597 mutex_unlock(&cx->serialize_lock);
598 return 0;
599}
600
601static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
602{
603 struct cx18 *cx = s->cx;
604 struct cx18_open_id *item;
605
606 CX18_DEBUG_FILE("open %s\n", s->name);
607
608 /* Allocate memory */
609 item = kmalloc(sizeof(struct cx18_open_id), GFP_KERNEL);
610 if (NULL == item) {
611 CX18_DEBUG_WARN("nomem on v4l2 open\n");
612 return -ENOMEM;
613 }
614 item->cx = cx;
615 item->type = s->type;
616 v4l2_prio_open(&cx->prio, &item->prio);
617
618 item->open_id = cx->open_id++;
619 filp->private_data = item;
620
621 if (item->type == CX18_ENC_STREAM_TYPE_RAD) {
622 /* Try to claim this stream */
623 if (cx18_claim_stream(item, item->type)) {
624 /* No, it's already in use */
625 kfree(item);
626 return -EBUSY;
627 }
628
629 if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
630 if (atomic_read(&cx->capturing) > 0) {
631 /* switching to radio while capture is
632 in progress is not polite */
633 cx18_release_stream(s);
634 kfree(item);
635 return -EBUSY;
636 }
637 }
638
639 /* Mark that the radio is being used. */
640 set_bit(CX18_F_I_RADIO_USER, &cx->i_flags);
641 /* We have the radio */
642 cx18_mute(cx);
643 /* Switch tuner to radio */
644 cx18_call_i2c_clients(cx, AUDC_SET_RADIO, NULL);
645 /* Select the correct audio input (i.e. radio tuner) */
646 cx18_audio_set_io(cx);
647 /* Done! Unmute and continue. */
648 cx18_unmute(cx);
649 }
650 return 0;
651}
652
653int cx18_v4l2_open(struct inode *inode, struct file *filp)
654{
655 int res, x, y = 0;
656 struct cx18 *cx = NULL;
657 struct cx18_stream *s = NULL;
658 int minor = iminor(inode);
659
660 /* Find which card this open was on */
661 spin_lock(&cx18_cards_lock);
662 for (x = 0; cx == NULL && x < cx18_cards_active; x++) {
663 /* find out which stream this open was on */
664 for (y = 0; y < CX18_MAX_STREAMS; y++) {
665 s = &cx18_cards[x]->streams[y];
666 if (s->v4l2dev && s->v4l2dev->minor == minor) {
667 cx = cx18_cards[x];
668 break;
669 }
670 }
671 }
672 spin_unlock(&cx18_cards_lock);
673
674 if (cx == NULL) {
675 /* Couldn't find a device registered
676 on that minor, shouldn't happen! */
677 printk(KERN_WARNING "No cx18 device found on minor %d\n",
678 minor);
679 return -ENXIO;
680 }
681
682 mutex_lock(&cx->serialize_lock);
683 if (cx18_init_on_first_open(cx)) {
684 CX18_ERR("Failed to initialize on minor %d\n", minor);
685 mutex_unlock(&cx->serialize_lock);
686 return -ENXIO;
687 }
688 res = cx18_serialized_open(s, filp);
689 mutex_unlock(&cx->serialize_lock);
690 return res;
691}
692
693void cx18_mute(struct cx18 *cx)
694{
695 if (atomic_read(&cx->capturing))
696 cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
697 cx18_find_handle(cx), 1);
698 CX18_DEBUG_INFO("Mute\n");
699}
700
701void cx18_unmute(struct cx18 *cx)
702{
703 if (atomic_read(&cx->capturing)) {
704 cx18_msleep_timeout(100, 0);
705 cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2,
706 cx18_find_handle(cx), 12);
707 cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
708 cx18_find_handle(cx), 0);
709 }
710 CX18_DEBUG_INFO("Unmute\n");
711}
diff --git a/drivers/media/video/cx18/cx18-fileops.h b/drivers/media/video/cx18/cx18-fileops.h
new file mode 100644
index 000000000000..16cdafbd24c5
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-fileops.h
@@ -0,0 +1,45 @@
1/*
2 * cx18 file operation functions
3 *
4 * Derived from ivtv-fileops.h
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 */
23
24/* Testing/Debugging */
25int cx18_v4l2_open(struct inode *inode, struct file *filp);
26ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count,
27 loff_t *pos);
28ssize_t cx18_v4l2_write(struct file *filp, const char __user *buf, size_t count,
29 loff_t *pos);
30int cx18_v4l2_close(struct inode *inode, struct file *filp);
31unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait);
32int cx18_start_capture(struct cx18_open_id *id);
33void cx18_stop_capture(struct cx18_open_id *id, int gop_end);
34void cx18_mute(struct cx18 *cx);
35void cx18_unmute(struct cx18 *cx);
36
37/* Utilities */
38
39/* Try to claim a stream for the filehandle. Return 0 on success,
40 -EBUSY if stream already claimed. Once a stream is claimed, it
41 remains claimed until the associated filehandle is closed. */
42int cx18_claim_stream(struct cx18_open_id *id, int type);
43
44/* Release a previously claimed stream. */
45void cx18_release_stream(struct cx18_stream *s);
diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c
new file mode 100644
index 000000000000..2694ce350631
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-firmware.c
@@ -0,0 +1,373 @@
1/*
2 * cx18 firmware functions
3 *
4 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 * 02111-1307 USA
20 */
21
22#include "cx18-driver.h"
23#include "cx18-scb.h"
24#include "cx18-irq.h"
25#include "cx18-firmware.h"
26#include "cx18-cards.h"
27#include <linux/firmware.h>
28
29#define CX18_PROC_SOFT_RESET 0xc70010
30#define CX18_DDR_SOFT_RESET 0xc70014
31#define CX18_CLOCK_SELECT1 0xc71000
32#define CX18_CLOCK_SELECT2 0xc71004
33#define CX18_HALF_CLOCK_SELECT1 0xc71008
34#define CX18_HALF_CLOCK_SELECT2 0xc7100C
35#define CX18_CLOCK_POLARITY1 0xc71010
36#define CX18_CLOCK_POLARITY2 0xc71014
37#define CX18_ADD_DELAY_ENABLE1 0xc71018
38#define CX18_ADD_DELAY_ENABLE2 0xc7101C
39#define CX18_CLOCK_ENABLE1 0xc71020
40#define CX18_CLOCK_ENABLE2 0xc71024
41
42#define CX18_REG_BUS_TIMEOUT_EN 0xc72024
43
44#define CX18_AUDIO_ENABLE 0xc72014
45#define CX18_REG_BUS_TIMEOUT_EN 0xc72024
46
47#define CX18_FAST_CLOCK_PLL_INT 0xc78000
48#define CX18_FAST_CLOCK_PLL_FRAC 0xc78004
49#define CX18_FAST_CLOCK_PLL_POST 0xc78008
50#define CX18_FAST_CLOCK_PLL_PRESCALE 0xc7800C
51#define CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH 0xc78010
52
53#define CX18_SLOW_CLOCK_PLL_INT 0xc78014
54#define CX18_SLOW_CLOCK_PLL_FRAC 0xc78018
55#define CX18_SLOW_CLOCK_PLL_POST 0xc7801C
56#define CX18_MPEG_CLOCK_PLL_INT 0xc78040
57#define CX18_MPEG_CLOCK_PLL_FRAC 0xc78044
58#define CX18_MPEG_CLOCK_PLL_POST 0xc78048
59#define CX18_PLL_POWER_DOWN 0xc78088
60#define CX18_SW1_INT_STATUS 0xc73104
61#define CX18_SW1_INT_ENABLE_PCI 0xc7311C
62#define CX18_SW2_INT_SET 0xc73140
63#define CX18_SW2_INT_STATUS 0xc73144
64#define CX18_ADEC_CONTROL 0xc78120
65
66#define CX18_DDR_REQUEST_ENABLE 0xc80000
67#define CX18_DDR_CHIP_CONFIG 0xc80004
68#define CX18_DDR_REFRESH 0xc80008
69#define CX18_DDR_TIMING1 0xc8000C
70#define CX18_DDR_TIMING2 0xc80010
71#define CX18_DDR_POWER_REG 0xc8001C
72
73#define CX18_DDR_TUNE_LANE 0xc80048
74#define CX18_DDR_INITIAL_EMRS 0xc80054
75#define CX18_DDR_MB_PER_ROW_7 0xc8009C
76#define CX18_DDR_BASE_63_ADDR 0xc804FC
77
78#define CX18_WMB_CLIENT02 0xc90108
79#define CX18_WMB_CLIENT05 0xc90114
80#define CX18_WMB_CLIENT06 0xc90118
81#define CX18_WMB_CLIENT07 0xc9011C
82#define CX18_WMB_CLIENT08 0xc90120
83#define CX18_WMB_CLIENT09 0xc90124
84#define CX18_WMB_CLIENT10 0xc90128
85#define CX18_WMB_CLIENT11 0xc9012C
86#define CX18_WMB_CLIENT12 0xc90130
87#define CX18_WMB_CLIENT13 0xc90134
88#define CX18_WMB_CLIENT14 0xc90138
89
90#define CX18_DSP0_INTERRUPT_MASK 0xd0004C
91
92/* Encoder/decoder firmware sizes */
93#define CX18_FW_CPU_SIZE (174716)
94#define CX18_FW_APU_SIZE (141200)
95
96#define APU_ROM_SYNC1 0x6D676553 /* "mgeS" */
97#define APU_ROM_SYNC2 0x72646548 /* "rdeH" */
98
99struct cx18_apu_rom_seghdr {
100 u32 sync1;
101 u32 sync2;
102 u32 addr;
103 u32 size;
104};
105
106static int load_cpu_fw_direct(const char *fn, u8 __iomem *mem, struct cx18 *cx, long size)
107{
108 const struct firmware *fw = NULL;
109 int retries = 3;
110 int i, j;
111 u32 __iomem *dst = (u32 __iomem *)mem;
112 const u32 *src;
113
114retry:
115 if (!retries || request_firmware(&fw, fn, &cx->dev->dev)) {
116 CX18_ERR("Unable to open firmware %s (must be %ld bytes)\n",
117 fn, size);
118 CX18_ERR("Did you put the firmware in the hotplug firmware directory?\n");
119 return -ENOMEM;
120 }
121
122 src = (const u32 *)fw->data;
123
124 if (fw->size != size) {
125 /* Due to race conditions in firmware loading (esp. with
126 udev <0.95) the wrong file was sometimes loaded. So we check
127 filesizes to see if at least the right-sized file was
128 loaded. If not, then we retry. */
129 CX18_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n",
130 fn, size, fw->size);
131 release_firmware(fw);
132 retries--;
133 goto retry;
134 }
135 for (i = 0; i < fw->size; i += 4096) {
136 setup_page(i);
137 for (j = i; j < fw->size && j < i + 4096; j += 4) {
138 /* no need for endianness conversion on the ppc */
139 __raw_writel(*src, dst);
140 if (__raw_readl(dst) != *src) {
141 CX18_ERR("Mismatch at offset %x\n", i);
142 release_firmware(fw);
143 return -EIO;
144 }
145 dst++;
146 src++;
147 }
148 }
149 if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
150 CX18_INFO("loaded %s firmware (%zd bytes)\n", fn, fw->size);
151 release_firmware(fw);
152 return size;
153}
154
155static int load_apu_fw_direct(const char *fn, u8 __iomem *dst, struct cx18 *cx, long size)
156{
157 const struct firmware *fw = NULL;
158 int retries = 3;
159 int i, j;
160 const u32 *src;
161 struct cx18_apu_rom_seghdr seghdr;
162 const u8 *vers;
163 u32 offset = 0;
164 u32 apu_version = 0;
165 int sz;
166
167retry:
168 if (!retries || request_firmware(&fw, fn, &cx->dev->dev)) {
169 CX18_ERR("unable to open firmware %s (must be %ld bytes)\n",
170 fn, size);
171 CX18_ERR("did you put the firmware in the hotplug firmware directory?\n");
172 return -ENOMEM;
173 }
174
175 src = (const u32 *)fw->data;
176 vers = fw->data + sizeof(seghdr);
177 sz = fw->size;
178
179 if (fw->size != size) {
180 /* Due to race conditions in firmware loading (esp. with
181 udev <0.95) the wrong file was sometimes loaded. So we check
182 filesizes to see if at least the right-sized file was
183 loaded. If not, then we retry. */
184 CX18_INFO("retry: file loaded was not %s (expected size %ld, got %zd)\n",
185 fn, size, fw->size);
186 release_firmware(fw);
187 retries--;
188 goto retry;
189 }
190 apu_version = (vers[0] << 24) | (vers[4] << 16) | vers[32];
191 while (offset + sizeof(seghdr) < size) {
192 /* TODO: byteswapping */
193 memcpy(&seghdr, src + offset / 4, sizeof(seghdr));
194 offset += sizeof(seghdr);
195 if (seghdr.sync1 != APU_ROM_SYNC1 ||
196 seghdr.sync2 != APU_ROM_SYNC2) {
197 offset += seghdr.size;
198 continue;
199 }
200 CX18_DEBUG_INFO("load segment %x-%x\n", seghdr.addr,
201 seghdr.addr + seghdr.size - 1);
202 if (offset + seghdr.size > sz)
203 break;
204 for (i = 0; i < seghdr.size; i += 4096) {
205 setup_page(offset + i);
206 for (j = i; j < seghdr.size && j < i + 4096; j += 4) {
207 /* no need for endianness conversion on the ppc */
208 __raw_writel(src[(offset + j) / 4], dst + seghdr.addr + j);
209 if (__raw_readl(dst + seghdr.addr + j) != src[(offset + j) / 4]) {
210 CX18_ERR("Mismatch at offset %x\n", offset + j);
211 release_firmware(fw);
212 return -EIO;
213 }
214 }
215 }
216 offset += seghdr.size;
217 }
218 if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags))
219 CX18_INFO("loaded %s firmware V%08x (%zd bytes)\n",
220 fn, apu_version, fw->size);
221 release_firmware(fw);
222 /* Clear bit0 for APU to start from 0 */
223 write_reg(read_reg(0xc72030) & ~1, 0xc72030);
224 return size;
225}
226
227void cx18_halt_firmware(struct cx18 *cx)
228{
229 CX18_DEBUG_INFO("Preparing for firmware halt.\n");
230 write_reg(0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */
231 write_reg(0x00020002, CX18_ADEC_CONTROL);
232}
233
234void cx18_init_power(struct cx18 *cx, int lowpwr)
235{
236 /* power-down Spare and AOM PLLs */
237 /* power-up fast, slow and mpeg PLLs */
238 write_reg(0x00000008, CX18_PLL_POWER_DOWN);
239
240 /* ADEC out of sleep */
241 write_reg(0x00020000, CX18_ADEC_CONTROL);
242
243 /* The fast clock is at 200/245 MHz */
244 write_reg(lowpwr ? 0xD : 0x11, CX18_FAST_CLOCK_PLL_INT);
245 write_reg(lowpwr ? 0x1EFBF37 : 0x038E3D7, CX18_FAST_CLOCK_PLL_FRAC);
246
247 write_reg(2, CX18_FAST_CLOCK_PLL_POST);
248 write_reg(1, CX18_FAST_CLOCK_PLL_PRESCALE);
249 write_reg(4, CX18_FAST_CLOCK_PLL_ADJUST_BANDWIDTH);
250
251 /* set slow clock to 125/120 MHz */
252 write_reg(lowpwr ? 0x11 : 0x10, CX18_SLOW_CLOCK_PLL_INT);
253 write_reg(lowpwr ? 0xEBAF05 : 0x18618A8, CX18_SLOW_CLOCK_PLL_FRAC);
254 write_reg(4, CX18_SLOW_CLOCK_PLL_POST);
255
256 /* mpeg clock pll 54MHz */
257 write_reg(0xF, CX18_MPEG_CLOCK_PLL_INT);
258 write_reg(0x2BCFEF, CX18_MPEG_CLOCK_PLL_FRAC);
259 write_reg(8, CX18_MPEG_CLOCK_PLL_POST);
260
261 /* Defaults */
262 /* APU = SC or SC/2 = 125/62.5 */
263 /* EPU = SC = 125 */
264 /* DDR = FC = 180 */
265 /* ENC = SC = 125 */
266 /* AI1 = SC = 125 */
267 /* VIM2 = disabled */
268 /* PCI = FC/2 = 90 */
269 /* AI2 = disabled */
270 /* DEMUX = disabled */
271 /* AO = SC/2 = 62.5 */
272 /* SER = 54MHz */
273 /* VFC = disabled */
274 /* USB = disabled */
275
276 write_reg(lowpwr ? 0xFFFF0020 : 0x00060004, CX18_CLOCK_SELECT1);
277 write_reg(lowpwr ? 0xFFFF0004 : 0x00060006, CX18_CLOCK_SELECT2);
278
279 write_reg(0xFFFF0002, CX18_HALF_CLOCK_SELECT1);
280 write_reg(0xFFFF0104, CX18_HALF_CLOCK_SELECT2);
281
282 write_reg(0xFFFF9026, CX18_CLOCK_ENABLE1);
283 write_reg(0xFFFF3105, CX18_CLOCK_ENABLE2);
284}
285
286void cx18_init_memory(struct cx18 *cx)
287{
288 cx18_msleep_timeout(10, 0);
289 write_reg(0x10000, CX18_DDR_SOFT_RESET);
290 cx18_msleep_timeout(10, 0);
291
292 write_reg(cx->card->ddr.chip_config, CX18_DDR_CHIP_CONFIG);
293
294 cx18_msleep_timeout(10, 0);
295
296 write_reg(cx->card->ddr.refresh, CX18_DDR_REFRESH);
297 write_reg(cx->card->ddr.timing1, CX18_DDR_TIMING1);
298 write_reg(cx->card->ddr.timing2, CX18_DDR_TIMING2);
299
300 cx18_msleep_timeout(10, 0);
301
302 /* Initialize DQS pad time */
303 write_reg(cx->card->ddr.tune_lane, CX18_DDR_TUNE_LANE);
304 write_reg(cx->card->ddr.initial_emrs, CX18_DDR_INITIAL_EMRS);
305
306 cx18_msleep_timeout(10, 0);
307
308 write_reg(0x20000, CX18_DDR_SOFT_RESET);
309 cx18_msleep_timeout(10, 0);
310
311 /* use power-down mode when idle */
312 write_reg(0x00000010, CX18_DDR_POWER_REG);
313
314 write_reg(0x10001, CX18_REG_BUS_TIMEOUT_EN);
315
316 write_reg(0x48, CX18_DDR_MB_PER_ROW_7);
317 write_reg(0xE0000, CX18_DDR_BASE_63_ADDR);
318
319 write_reg(0x00000101, CX18_WMB_CLIENT02); /* AO */
320 write_reg(0x00000101, CX18_WMB_CLIENT09); /* AI2 */
321 write_reg(0x00000101, CX18_WMB_CLIENT05); /* VIM1 */
322 write_reg(0x00000101, CX18_WMB_CLIENT06); /* AI1 */
323 write_reg(0x00000101, CX18_WMB_CLIENT07); /* 3D comb */
324 write_reg(0x00000101, CX18_WMB_CLIENT10); /* ME */
325 write_reg(0x00000101, CX18_WMB_CLIENT12); /* ENC */
326 write_reg(0x00000101, CX18_WMB_CLIENT13); /* PK */
327 write_reg(0x00000101, CX18_WMB_CLIENT11); /* RC */
328 write_reg(0x00000101, CX18_WMB_CLIENT14); /* AVO */
329}
330
331int cx18_firmware_init(struct cx18 *cx)
332{
333 /* Allow chip to control CLKRUN */
334 write_reg(0x5, CX18_DSP0_INTERRUPT_MASK);
335
336 write_reg(0x000F000F, CX18_PROC_SOFT_RESET); /* stop the fw */
337
338 cx18_msleep_timeout(1, 0);
339
340 sw1_irq_enable(IRQ_CPU_TO_EPU | IRQ_APU_TO_EPU);
341 sw2_irq_enable(IRQ_CPU_TO_EPU_ACK | IRQ_APU_TO_EPU_ACK);
342
343 /* Only if the processor is not running */
344 if (read_reg(CX18_PROC_SOFT_RESET) & 8) {
345 int sz = load_apu_fw_direct("v4l-cx23418-apu.fw",
346 cx->enc_mem, cx, CX18_FW_APU_SIZE);
347
348 sz = sz <= 0 ? sz : load_cpu_fw_direct("v4l-cx23418-cpu.fw",
349 cx->enc_mem, cx, CX18_FW_CPU_SIZE);
350
351 if (sz > 0) {
352 int retries = 0;
353
354 /* start the CPU */
355 write_reg(0x00080000, CX18_PROC_SOFT_RESET);
356 while (retries++ < 50) { /* Loop for max 500mS */
357 if ((read_reg(CX18_PROC_SOFT_RESET) & 1) == 0)
358 break;
359 cx18_msleep_timeout(10, 0);
360 }
361 cx18_msleep_timeout(200, 0);
362 if (retries == 51) {
363 CX18_ERR("Could not start the CPU\n");
364 return -EIO;
365 }
366 }
367 if (sz <= 0)
368 return -EIO;
369 }
370 /* initialize GPIO */
371 write_reg(0x14001400, 0xC78110);
372 return 0;
373}
diff --git a/drivers/media/video/cx18/cx18-firmware.h b/drivers/media/video/cx18/cx18-firmware.h
new file mode 100644
index 000000000000..38d4c05e8499
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-firmware.h
@@ -0,0 +1,25 @@
1/*
2 * cx18 firmware functions
3 *
4 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 * 02111-1307 USA
20 */
21
22int cx18_firmware_init(struct cx18 *cx);
23void cx18_halt_firmware(struct cx18 *cx);
24void cx18_init_memory(struct cx18 *cx);
25void cx18_init_power(struct cx18 *cx, int lowpwr);
diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c
new file mode 100644
index 000000000000..19253e6b8673
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-gpio.c
@@ -0,0 +1,74 @@
1/*
2 * cx18 gpio functions
3 *
4 * Derived from ivtv-gpio.c
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 */
23
24#include "cx18-driver.h"
25#include "cx18-cards.h"
26#include "cx18-gpio.h"
27#include "tuner-xc2028.h"
28
29/********************* GPIO stuffs *********************/
30
31/* GPIO registers */
32#define CX18_REG_GPIO_IN 0xc72010
33#define CX18_REG_GPIO_OUT1 0xc78100
34#define CX18_REG_GPIO_DIR1 0xc78108
35#define CX18_REG_GPIO_OUT2 0xc78104
36#define CX18_REG_GPIO_DIR2 0xc7810c
37
38/*
39 * HVR-1600 GPIO pins, courtesy of Hauppauge:
40 *
41 * gpio0: zilog ir process reset pin
42 * gpio1: zilog programming pin (you should never use this)
43 * gpio12: cx24227 reset pin
44 * gpio13: cs5345 reset pin
45*/
46
47void cx18_gpio_init(struct cx18 *cx)
48{
49 if (cx->card->gpio_init.direction == 0)
50 return;
51
52 CX18_DEBUG_INFO("GPIO initial dir: %08x out: %08x\n",
53 read_reg(CX18_REG_GPIO_DIR1), read_reg(CX18_REG_GPIO_OUT1));
54
55 /* init output data then direction */
56 write_reg(cx->card->gpio_init.direction << 16, CX18_REG_GPIO_DIR1);
57 write_reg(0, CX18_REG_GPIO_DIR2);
58 write_reg((cx->card->gpio_init.direction << 16) |
59 cx->card->gpio_init.initial_value, CX18_REG_GPIO_OUT1);
60 write_reg(0, CX18_REG_GPIO_OUT2);
61}
62
63/* Xceive tuner reset function */
64int cx18_reset_tuner_gpio(void *dev, int cmd, int value)
65{
66 struct i2c_algo_bit_data *algo = dev;
67 struct cx18 *cx = algo->data;
68/* int curdir, curout;*/
69
70 if (cmd != XC2028_TUNER_RESET)
71 return 0;
72 CX18_DEBUG_INFO("Resetting tuner\n");
73 return 0;
74}
diff --git a/drivers/media/video/cx18/cx18-gpio.h b/drivers/media/video/cx18/cx18-gpio.h
new file mode 100644
index 000000000000..41bac8856b50
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-gpio.h
@@ -0,0 +1,24 @@
1/*
2 * cx18 gpio functions
3 *
4 * Derived from ivtv-gpio.h
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23void cx18_gpio_init(struct cx18 *cx);
24int cx18_reset_tuner_gpio(void *dev, int cmd, int value);
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
new file mode 100644
index 000000000000..18c88d1e4833
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -0,0 +1,431 @@
1/*
2 * cx18 I2C functions
3 *
4 * Derived from ivtv-i2c.c
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 */
23
24#include "cx18-driver.h"
25#include "cx18-cards.h"
26#include "cx18-gpio.h"
27#include "cx18-av-core.h"
28
29#include <media/ir-kbd-i2c.h>
30
31#define CX18_REG_I2C_1_WR 0xf15000
32#define CX18_REG_I2C_1_RD 0xf15008
33#define CX18_REG_I2C_2_WR 0xf25100
34#define CX18_REG_I2C_2_RD 0xf25108
35
36#define SETSCL_BIT 0x0001
37#define SETSDL_BIT 0x0002
38#define GETSCL_BIT 0x0004
39#define GETSDL_BIT 0x0008
40
41#ifndef I2C_ADAP_CLASS_TV_ANALOG
42#define I2C_ADAP_CLASS_TV_ANALOG I2C_CLASS_TV_ANALOG
43#endif
44
45#define CX18_CS5345_I2C_ADDR 0x4c
46
47/* This array should match the CX18_HW_ defines */
48static const u8 hw_driverids[] = {
49 I2C_DRIVERID_TUNER,
50 I2C_DRIVERID_TVEEPROM,
51 I2C_DRIVERID_CS5345,
52 0, /* CX18_HW_GPIO dummy driver ID */
53 0 /* CX18_HW_CX23418 dummy driver ID */
54};
55
56/* This array should match the CX18_HW_ defines */
57static const u8 hw_addrs[] = {
58 0,
59 0,
60 CX18_CS5345_I2C_ADDR,
61 0, /* CX18_HW_GPIO dummy driver ID */
62 0, /* CX18_HW_CX23418 dummy driver ID */
63};
64
65/* This array should match the CX18_HW_ defines */
66/* This might well become a card-specific array */
67static const u8 hw_bus[] = {
68 0,
69 0,
70 0,
71 0, /* CX18_HW_GPIO dummy driver ID */
72 0, /* CX18_HW_CX23418 dummy driver ID */
73};
74
75/* This array should match the CX18_HW_ defines */
76static const char * const hw_drivernames[] = {
77 "tuner",
78 "tveeprom",
79 "cs5345",
80 "gpio",
81 "cx23418",
82};
83
84int cx18_i2c_register(struct cx18 *cx, unsigned idx)
85{
86 struct i2c_board_info info;
87 struct i2c_client *c;
88 u8 id, bus;
89 int i;
90
91 CX18_DEBUG_I2C("i2c client register\n");
92 if (idx >= ARRAY_SIZE(hw_driverids) || hw_driverids[idx] == 0)
93 return -1;
94 id = hw_driverids[idx];
95 bus = hw_bus[idx];
96 memset(&info, 0, sizeof(info));
97 strlcpy(info.driver_name, hw_drivernames[idx],
98 sizeof(info.driver_name));
99 info.addr = hw_addrs[idx];
100 for (i = 0; i < I2C_CLIENTS_MAX; i++)
101 if (cx->i2c_clients[i] == NULL)
102 break;
103
104 if (i == I2C_CLIENTS_MAX) {
105 CX18_ERR("insufficient room for new I2C client!\n");
106 return -ENOMEM;
107 }
108
109 if (id != I2C_DRIVERID_TUNER) {
110 c = i2c_new_device(&cx->i2c_adap[bus], &info);
111 if (c->driver == NULL)
112 i2c_unregister_device(c);
113 else
114 cx->i2c_clients[i] = c;
115 return cx->i2c_clients[i] ? 0 : -ENODEV;
116 }
117
118 /* special tuner handling */
119 c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->radio);
120 if (c && c->driver == NULL)
121 i2c_unregister_device(c);
122 else if (c)
123 cx->i2c_clients[i++] = c;
124 c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->demod);
125 if (c && c->driver == NULL)
126 i2c_unregister_device(c);
127 else if (c)
128 cx->i2c_clients[i++] = c;
129 c = i2c_new_probed_device(&cx->i2c_adap[1], &info, cx->card_i2c->tv);
130 if (c && c->driver == NULL)
131 i2c_unregister_device(c);
132 else if (c)
133 cx->i2c_clients[i++] = c;
134 return 0;
135}
136
137static int attach_inform(struct i2c_client *client)
138{
139 return 0;
140}
141
142static int detach_inform(struct i2c_client *client)
143{
144 int i;
145 struct cx18 *cx = (struct cx18 *)i2c_get_adapdata(client->adapter);
146
147 CX18_DEBUG_I2C("i2c client detach\n");
148 for (i = 0; i < I2C_CLIENTS_MAX; i++) {
149 if (cx->i2c_clients[i] == client) {
150 cx->i2c_clients[i] = NULL;
151 break;
152 }
153 }
154 CX18_DEBUG_I2C("i2c detach [client=%s,%s]\n",
155 client->name, (i < I2C_CLIENTS_MAX) ? "ok" : "failed");
156
157 return 0;
158}
159
160static void cx18_setscl(void *data, int state)
161{
162 struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
163 int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
164 u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
165 u32 r = read_reg(addr);
166
167 if (state)
168 write_reg_sync(r | SETSCL_BIT, addr);
169 else
170 write_reg_sync(r & ~SETSCL_BIT, addr);
171}
172
173static void cx18_setsda(void *data, int state)
174{
175 struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
176 int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
177 u32 addr = bus_index ? CX18_REG_I2C_2_WR : CX18_REG_I2C_1_WR;
178 u32 r = read_reg(addr);
179
180 if (state)
181 write_reg_sync(r | SETSDL_BIT, addr);
182 else
183 write_reg_sync(r & ~SETSDL_BIT, addr);
184}
185
186static int cx18_getscl(void *data)
187{
188 struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
189 int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
190 u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD;
191
192 return read_reg(addr) & GETSCL_BIT;
193}
194
195static int cx18_getsda(void *data)
196{
197 struct cx18 *cx = ((struct cx18_i2c_algo_callback_data *)data)->cx;
198 int bus_index = ((struct cx18_i2c_algo_callback_data *)data)->bus_index;
199 u32 addr = bus_index ? CX18_REG_I2C_2_RD : CX18_REG_I2C_1_RD;
200
201 return read_reg(addr) & GETSDL_BIT;
202}
203
204/* template for i2c-bit-algo */
205static struct i2c_adapter cx18_i2c_adap_template = {
206 .name = "cx18 i2c driver",
207 .id = I2C_HW_B_CX2341X,
208 .algo = NULL, /* set by i2c-algo-bit */
209 .algo_data = NULL, /* filled from template */
210 .client_register = attach_inform,
211 .client_unregister = detach_inform,
212 .owner = THIS_MODULE,
213};
214
215#define CX18_SCL_PERIOD (10) /* usecs. 10 usec is period for a 100 KHz clock */
216#define CX18_ALGO_BIT_TIMEOUT (2) /* seconds */
217
218static struct i2c_algo_bit_data cx18_i2c_algo_template = {
219 .setsda = cx18_setsda,
220 .setscl = cx18_setscl,
221 .getsda = cx18_getsda,
222 .getscl = cx18_getscl,
223 .udelay = CX18_SCL_PERIOD/2, /* 1/2 clock period in usec*/
224 .timeout = CX18_ALGO_BIT_TIMEOUT*HZ /* jiffies */
225};
226
227static struct i2c_client cx18_i2c_client_template = {
228 .name = "cx18 internal",
229};
230
231int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg)
232{
233 struct i2c_client *client;
234 int retval;
235 int i;
236
237 CX18_DEBUG_I2C("call_i2c_client addr=%02x\n", addr);
238 for (i = 0; i < I2C_CLIENTS_MAX; i++) {
239 client = cx->i2c_clients[i];
240 if (client == NULL || client->driver == NULL ||
241 client->driver->command == NULL)
242 continue;
243 if (addr == client->addr) {
244 retval = client->driver->command(client, cmd, arg);
245 return retval;
246 }
247 }
248 if (cmd != VIDIOC_G_CHIP_IDENT)
249 CX18_ERR("i2c addr 0x%02x not found for cmd 0x%x!\n",
250 addr, cmd);
251 return -ENODEV;
252}
253
254/* Find the i2c device based on the driver ID and return
255 its i2c address or -ENODEV if no matching device was found. */
256static int cx18_i2c_id_addr(struct cx18 *cx, u32 id)
257{
258 struct i2c_client *client;
259 int retval = -ENODEV;
260 int i;
261
262 for (i = 0; i < I2C_CLIENTS_MAX; i++) {
263 client = cx->i2c_clients[i];
264 if (client == NULL || client->driver == NULL)
265 continue;
266 if (id == client->driver->id) {
267 retval = client->addr;
268 break;
269 }
270 }
271 return retval;
272}
273
274/* Find the i2c device name matching the DRIVERID */
275static const char *cx18_i2c_id_name(u32 id)
276{
277 int i;
278
279 for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
280 if (hw_driverids[i] == id)
281 return hw_drivernames[i];
282 return "unknown device";
283}
284
285/* Find the i2c device name matching the CX18_HW_ flag */
286static const char *cx18_i2c_hw_name(u32 hw)
287{
288 int i;
289
290 for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
291 if (1 << i == hw)
292 return hw_drivernames[i];
293 return "unknown device";
294}
295
296/* Find the i2c device matching the CX18_HW_ flag and return
297 its i2c address or -ENODEV if no matching device was found. */
298int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw)
299{
300 int i;
301
302 for (i = 0; i < ARRAY_SIZE(hw_driverids); i++)
303 if (1 << i == hw)
304 return cx18_i2c_id_addr(cx, hw_driverids[i]);
305 return -ENODEV;
306}
307
308/* Calls i2c device based on CX18_HW_ flag. If hw == 0, then do nothing.
309 If hw == CX18_HW_GPIO then call the gpio handler. */
310int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg)
311{
312 int addr;
313
314 if (hw == CX18_HW_GPIO || hw == 0)
315 return 0;
316 if (hw == CX18_HW_CX23418)
317 return cx18_av_cmd(cx, cmd, arg);
318
319 addr = cx18_i2c_hw_addr(cx, hw);
320 if (addr < 0) {
321 CX18_ERR("i2c hardware 0x%08x (%s) not found for cmd 0x%x!\n",
322 hw, cx18_i2c_hw_name(hw), cmd);
323 return addr;
324 }
325 return cx18_call_i2c_client(cx, addr, cmd, arg);
326}
327
328/* Calls i2c device based on I2C driver ID. */
329int cx18_i2c_id(struct cx18 *cx, u32 id, unsigned int cmd, void *arg)
330{
331 int addr;
332
333 addr = cx18_i2c_id_addr(cx, id);
334 if (addr < 0) {
335 if (cmd != VIDIOC_G_CHIP_IDENT)
336 CX18_ERR("i2c ID 0x%08x (%s) not found for cmd 0x%x!\n",
337 id, cx18_i2c_id_name(id), cmd);
338 return addr;
339 }
340 return cx18_call_i2c_client(cx, addr, cmd, arg);
341}
342
343/* broadcast cmd for all I2C clients and for the gpio subsystem */
344void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg)
345{
346 if (cx->i2c_adap[0].algo == NULL || cx->i2c_adap[1].algo == NULL) {
347 CX18_ERR("adapter is not set\n");
348 return;
349 }
350 cx18_av_cmd(cx, cmd, arg);
351 i2c_clients_command(&cx->i2c_adap[0], cmd, arg);
352 i2c_clients_command(&cx->i2c_adap[1], cmd, arg);
353}
354
355/* init + register i2c algo-bit adapter */
356int init_cx18_i2c(struct cx18 *cx)
357{
358 int i;
359 CX18_DEBUG_I2C("i2c init\n");
360
361 for (i = 0; i < 2; i++) {
362 memcpy(&cx->i2c_adap[i], &cx18_i2c_adap_template,
363 sizeof(struct i2c_adapter));
364 memcpy(&cx->i2c_algo[i], &cx18_i2c_algo_template,
365 sizeof(struct i2c_algo_bit_data));
366 cx->i2c_algo_cb_data[i].cx = cx;
367 cx->i2c_algo_cb_data[i].bus_index = i;
368 cx->i2c_algo[i].data = &cx->i2c_algo_cb_data[i];
369 cx->i2c_adap[i].algo_data = &cx->i2c_algo[i];
370
371 sprintf(cx->i2c_adap[i].name + strlen(cx->i2c_adap[i].name),
372 " #%d-%d", cx->num, i);
373 i2c_set_adapdata(&cx->i2c_adap[i], cx);
374
375 memcpy(&cx->i2c_client[i], &cx18_i2c_client_template,
376 sizeof(struct i2c_client));
377 sprintf(cx->i2c_client[i].name +
378 strlen(cx->i2c_client[i].name), "%d", i);
379 cx->i2c_client[i].adapter = &cx->i2c_adap[i];
380 cx->i2c_adap[i].dev.parent = &cx->dev->dev;
381 }
382
383 if (read_reg(CX18_REG_I2C_2_WR) != 0x0003c02f) {
384 /* Reset/Unreset I2C hardware block */
385 write_reg(0x10000000, 0xc71004); /* Clock select 220MHz */
386 write_reg_sync(0x10001000, 0xc71024); /* Clock Enable */
387 }
388 /* courtesy of Steven Toth <stoth@hauppauge.com> */
389 write_reg_sync(0x00c00000, 0xc7001c);
390 mdelay(10);
391 write_reg_sync(0x00c000c0, 0xc7001c);
392 mdelay(10);
393 write_reg_sync(0x00c00000, 0xc7001c);
394
395 write_reg_sync(0x00c00000, 0xc730c8); /* Set to edge-triggered intrs. */
396 write_reg_sync(0x00c00000, 0xc730c4); /* Clear any stale intrs */
397
398 /* Hw I2C1 Clock Freq ~100kHz */
399 write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_1_WR);
400 cx18_setscl(&cx->i2c_algo_cb_data[0], 1);
401 cx18_setsda(&cx->i2c_algo_cb_data[0], 1);
402
403 /* Hw I2C2 Clock Freq ~100kHz */
404 write_reg_sync(0x00021c0f & ~4, CX18_REG_I2C_2_WR);
405 cx18_setscl(&cx->i2c_algo_cb_data[1], 1);
406 cx18_setsda(&cx->i2c_algo_cb_data[1], 1);
407
408 return i2c_bit_add_bus(&cx->i2c_adap[0]) ||
409 i2c_bit_add_bus(&cx->i2c_adap[1]);
410}
411
412void exit_cx18_i2c(struct cx18 *cx)
413{
414 int i;
415 CX18_DEBUG_I2C("i2c exit\n");
416 write_reg(read_reg(CX18_REG_I2C_1_WR) | 4, CX18_REG_I2C_1_WR);
417 write_reg(read_reg(CX18_REG_I2C_2_WR) | 4, CX18_REG_I2C_2_WR);
418
419 for (i = 0; i < 2; i++) {
420 i2c_del_adapter(&cx->i2c_adap[i]);
421 }
422}
423
424/*
425 Hauppauge HVR1600 should have:
426 32 cx24227
427 98 unknown
428 a0 eeprom
429 c2 tuner
430 e? zilog ir
431 */
diff --git a/drivers/media/video/cx18/cx18-i2c.h b/drivers/media/video/cx18/cx18-i2c.h
new file mode 100644
index 000000000000..113c3f9a2cc0
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-i2c.h
@@ -0,0 +1,33 @@
1/*
2 * cx18 I2C functions
3 *
4 * Derived from ivtv-i2c.h
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 */
23
24int cx18_i2c_hw_addr(struct cx18 *cx, u32 hw);
25int cx18_i2c_hw(struct cx18 *cx, u32 hw, unsigned int cmd, void *arg);
26int cx18_i2c_id(struct cx18 *cx, u32 id, unsigned int cmd, void *arg);
27int cx18_call_i2c_client(struct cx18 *cx, int addr, unsigned cmd, void *arg);
28void cx18_call_i2c_clients(struct cx18 *cx, unsigned int cmd, void *arg);
29int cx18_i2c_register(struct cx18 *cx, unsigned idx);
30
31/* init + register i2c algo-bit adapter */
32int init_cx18_i2c(struct cx18 *cx);
33void exit_cx18_i2c(struct cx18 *cx);
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
new file mode 100644
index 000000000000..4a93af2e4bb6
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -0,0 +1,851 @@
1/*
2 * cx18 ioctl system call
3 *
4 * Derived from ivtv-ioctl.c
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 */
23
24#include "cx18-driver.h"
25#include "cx18-version.h"
26#include "cx18-mailbox.h"
27#include "cx18-i2c.h"
28#include "cx18-queue.h"
29#include "cx18-fileops.h"
30#include "cx18-vbi.h"
31#include "cx18-audio.h"
32#include "cx18-video.h"
33#include "cx18-streams.h"
34#include "cx18-ioctl.h"
35#include "cx18-gpio.h"
36#include "cx18-controls.h"
37#include "cx18-cards.h"
38#include "cx18-av-core.h"
39#include <media/tveeprom.h>
40#include <media/v4l2-chip-ident.h>
41#include <linux/i2c-id.h>
42
43u16 service2vbi(int type)
44{
45 switch (type) {
46 case V4L2_SLICED_TELETEXT_B:
47 return CX18_SLICED_TYPE_TELETEXT_B;
48 case V4L2_SLICED_CAPTION_525:
49 return CX18_SLICED_TYPE_CAPTION_525;
50 case V4L2_SLICED_WSS_625:
51 return CX18_SLICED_TYPE_WSS_625;
52 case V4L2_SLICED_VPS:
53 return CX18_SLICED_TYPE_VPS;
54 default:
55 return 0;
56 }
57}
58
59static int valid_service_line(int field, int line, int is_pal)
60{
61 return (is_pal && line >= 6 && (line != 23 || field == 0)) ||
62 (!is_pal && line >= 10 && line < 22);
63}
64
65static u16 select_service_from_set(int field, int line, u16 set, int is_pal)
66{
67 u16 valid_set = (is_pal ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525);
68 int i;
69
70 set = set & valid_set;
71 if (set == 0 || !valid_service_line(field, line, is_pal))
72 return 0;
73 if (!is_pal) {
74 if (line == 21 && (set & V4L2_SLICED_CAPTION_525))
75 return V4L2_SLICED_CAPTION_525;
76 } else {
77 if (line == 16 && field == 0 && (set & V4L2_SLICED_VPS))
78 return V4L2_SLICED_VPS;
79 if (line == 23 && field == 0 && (set & V4L2_SLICED_WSS_625))
80 return V4L2_SLICED_WSS_625;
81 if (line == 23)
82 return 0;
83 }
84 for (i = 0; i < 32; i++) {
85 if ((1 << i) & set)
86 return 1 << i;
87 }
88 return 0;
89}
90
91void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
92{
93 u16 set = fmt->service_set;
94 int f, l;
95
96 fmt->service_set = 0;
97 for (f = 0; f < 2; f++) {
98 for (l = 0; l < 24; l++)
99 fmt->service_lines[f][l] = select_service_from_set(f, l, set, is_pal);
100 }
101}
102
103static int check_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal)
104{
105 int f, l;
106 u16 set = 0;
107
108 for (f = 0; f < 2; f++) {
109 for (l = 0; l < 24; l++) {
110 fmt->service_lines[f][l] = select_service_from_set(f, l, fmt->service_lines[f][l], is_pal);
111 set |= fmt->service_lines[f][l];
112 }
113 }
114 return set != 0;
115}
116
117u16 get_service_set(struct v4l2_sliced_vbi_format *fmt)
118{
119 int f, l;
120 u16 set = 0;
121
122 for (f = 0; f < 2; f++) {
123 for (l = 0; l < 24; l++)
124 set |= fmt->service_lines[f][l];
125 }
126 return set;
127}
128
129static const struct {
130 v4l2_std_id std;
131 char *name;
132} enum_stds[] = {
133 { V4L2_STD_PAL_BG | V4L2_STD_PAL_H, "PAL-BGH" },
134 { V4L2_STD_PAL_DK, "PAL-DK" },
135 { V4L2_STD_PAL_I, "PAL-I" },
136 { V4L2_STD_PAL_M, "PAL-M" },
137 { V4L2_STD_PAL_N, "PAL-N" },
138 { V4L2_STD_PAL_Nc, "PAL-Nc" },
139 { V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H, "SECAM-BGH" },
140 { V4L2_STD_SECAM_DK, "SECAM-DK" },
141 { V4L2_STD_SECAM_L, "SECAM-L" },
142 { V4L2_STD_SECAM_LC, "SECAM-L'" },
143 { V4L2_STD_NTSC_M, "NTSC-M" },
144 { V4L2_STD_NTSC_M_JP, "NTSC-J" },
145 { V4L2_STD_NTSC_M_KR, "NTSC-K" },
146};
147
148static const struct v4l2_standard cx18_std_60hz = {
149 .frameperiod = {.numerator = 1001, .denominator = 30000},
150 .framelines = 525,
151};
152
153static const struct v4l2_standard cx18_std_50hz = {
154 .frameperiod = { .numerator = 1, .denominator = 25 },
155 .framelines = 625,
156};
157
158static int cx18_cxc(struct cx18 *cx, unsigned int cmd, void *arg)
159{
160 struct v4l2_register *regs = arg;
161 unsigned long flags;
162
163 if (!capable(CAP_SYS_ADMIN))
164 return -EPERM;
165 if (regs->reg >= CX18_MEM_OFFSET + CX18_MEM_SIZE)
166 return -EINVAL;
167
168 spin_lock_irqsave(&cx18_cards_lock, flags);
169 if (cmd == VIDIOC_DBG_G_REGISTER)
170 regs->val = read_enc(regs->reg);
171 else
172 write_enc(regs->val, regs->reg);
173 spin_unlock_irqrestore(&cx18_cards_lock, flags);
174 return 0;
175}
176
177static int cx18_get_fmt(struct cx18 *cx, int streamtype, struct v4l2_format *fmt)
178{
179 switch (fmt->type) {
180 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
181 fmt->fmt.pix.width = cx->params.width;
182 fmt->fmt.pix.height = cx->params.height;
183 fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
184 fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
185 if (streamtype == CX18_ENC_STREAM_TYPE_YUV) {
186 fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
187 /* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
188 fmt->fmt.pix.sizeimage =
189 fmt->fmt.pix.height * fmt->fmt.pix.width +
190 fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
191 } else {
192 fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
193 fmt->fmt.pix.sizeimage = 128 * 1024;
194 }
195 break;
196
197 case V4L2_BUF_TYPE_VBI_CAPTURE:
198 fmt->fmt.vbi.sampling_rate = 27000000;
199 fmt->fmt.vbi.offset = 248;
200 fmt->fmt.vbi.samples_per_line = cx->vbi.raw_decoder_line_size - 4;
201 fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
202 fmt->fmt.vbi.start[0] = cx->vbi.start[0];
203 fmt->fmt.vbi.start[1] = cx->vbi.start[1];
204 fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = cx->vbi.count;
205 break;
206
207 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
208 {
209 struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
210
211 vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
212 memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
213 memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
214
215 cx18_av_cmd(cx, VIDIOC_G_FMT, fmt);
216 vbifmt->service_set = get_service_set(vbifmt);
217 break;
218 }
219 default:
220 return -EINVAL;
221 }
222 return 0;
223}
224
225static int cx18_try_or_set_fmt(struct cx18 *cx, int streamtype,
226 struct v4l2_format *fmt, int set_fmt)
227{
228 struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
229 u16 set;
230
231 /* set window size */
232 if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
233 int w = fmt->fmt.pix.width;
234 int h = fmt->fmt.pix.height;
235
236 if (w > 720)
237 w = 720;
238 else if (w < 1)
239 w = 1;
240 if (h > (cx->is_50hz ? 576 : 480))
241 h = (cx->is_50hz ? 576 : 480);
242 else if (h < 2)
243 h = 2;
244 cx18_get_fmt(cx, streamtype, fmt);
245 fmt->fmt.pix.width = w;
246 fmt->fmt.pix.height = h;
247
248 if (!set_fmt || (cx->params.width == w && cx->params.height == h))
249 return 0;
250 if (atomic_read(&cx->capturing) > 0)
251 return -EBUSY;
252
253 cx->params.width = w;
254 cx->params.height = h;
255 if (w != 720 || h != (cx->is_50hz ? 576 : 480))
256 cx->params.video_temporal_filter = 0;
257 else
258 cx->params.video_temporal_filter = 8;
259 cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
260 return cx18_get_fmt(cx, streamtype, fmt);
261 }
262
263 /* set raw VBI format */
264 if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
265 if (set_fmt && streamtype == CX18_ENC_STREAM_TYPE_VBI &&
266 cx->vbi.sliced_in->service_set &&
267 atomic_read(&cx->capturing) > 0)
268 return -EBUSY;
269 if (set_fmt) {
270 cx->vbi.sliced_in->service_set = 0;
271 cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
272 }
273 return cx18_get_fmt(cx, streamtype, fmt);
274 }
275
276 /* any else but sliced VBI capture is an error */
277 if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
278 return -EINVAL;
279
280 /* TODO: implement sliced VBI, for now silently return 0 */
281 return 0;
282
283 /* set sliced VBI capture format */
284 vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
285 memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
286
287 if (vbifmt->service_set)
288 expand_service_set(vbifmt, cx->is_50hz);
289 set = check_service_set(vbifmt, cx->is_50hz);
290 vbifmt->service_set = get_service_set(vbifmt);
291
292 if (!set_fmt)
293 return 0;
294 if (set == 0)
295 return -EINVAL;
296 if (atomic_read(&cx->capturing) > 0 && cx->vbi.sliced_in->service_set == 0)
297 return -EBUSY;
298 cx18_av_cmd(cx, VIDIOC_S_FMT, fmt);
299 memcpy(cx->vbi.sliced_in, vbifmt, sizeof(*cx->vbi.sliced_in));
300 return 0;
301}
302
303static int cx18_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
304{
305 struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
306 struct cx18 *cx = id->cx;
307 struct v4l2_register *reg = arg;
308
309 switch (cmd) {
310 /* ioctls to allow direct access to the encoder registers for testing */
311 case VIDIOC_DBG_G_REGISTER:
312 if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
313 return cx18_cxc(cx, cmd, arg);
314 if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
315 return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
316 return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
317
318 case VIDIOC_DBG_S_REGISTER:
319 if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
320 return cx18_cxc(cx, cmd, arg);
321 if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
322 return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
323 return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
324
325 case VIDIOC_G_CHIP_IDENT: {
326 struct v4l2_chip_ident *chip = arg;
327
328 chip->ident = V4L2_IDENT_NONE;
329 chip->revision = 0;
330 if (reg->match_type == V4L2_CHIP_MATCH_HOST) {
331 if (v4l2_chip_match_host(reg->match_type, reg->match_chip)) {
332 struct v4l2_chip_ident *chip = arg;
333
334 chip->ident = V4L2_IDENT_CX23418;
335 }
336 return 0;
337 }
338 if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
339 return cx18_i2c_id(cx, reg->match_chip, cmd, arg);
340 if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
341 return cx18_call_i2c_client(cx, reg->match_chip, cmd, arg);
342 return -EINVAL;
343 }
344
345 case VIDIOC_INT_S_AUDIO_ROUTING: {
346 struct v4l2_routing *route = arg;
347
348 cx18_audio_set_route(cx, route);
349 break;
350 }
351
352 default:
353 return -EINVAL;
354 }
355 return 0;
356}
357
358int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd, void *arg)
359{
360 struct cx18_open_id *id = NULL;
361
362 if (filp)
363 id = (struct cx18_open_id *)filp->private_data;
364
365 switch (cmd) {
366 case VIDIOC_G_PRIORITY:
367 {
368 enum v4l2_priority *p = arg;
369
370 *p = v4l2_prio_max(&cx->prio);
371 break;
372 }
373
374 case VIDIOC_S_PRIORITY:
375 {
376 enum v4l2_priority *prio = arg;
377
378 return v4l2_prio_change(&cx->prio, &id->prio, *prio);
379 }
380
381 case VIDIOC_QUERYCAP:{
382 struct v4l2_capability *vcap = arg;
383
384 memset(vcap, 0, sizeof(*vcap));
385 strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
386 strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
387 strlcpy(vcap->bus_info, pci_name(cx->dev), sizeof(vcap->bus_info));
388 vcap->version = CX18_DRIVER_VERSION; /* version */
389 vcap->capabilities = cx->v4l2_cap; /* capabilities */
390
391 /* reserved.. must set to 0! */
392 vcap->reserved[0] = vcap->reserved[1] =
393 vcap->reserved[2] = vcap->reserved[3] = 0;
394 break;
395 }
396
397 case VIDIOC_ENUMAUDIO:{
398 struct v4l2_audio *vin = arg;
399
400 return cx18_get_audio_input(cx, vin->index, vin);
401 }
402
403 case VIDIOC_G_AUDIO:{
404 struct v4l2_audio *vin = arg;
405
406 vin->index = cx->audio_input;
407 return cx18_get_audio_input(cx, vin->index, vin);
408 }
409
410 case VIDIOC_S_AUDIO:{
411 struct v4l2_audio *vout = arg;
412
413 if (vout->index >= cx->nof_audio_inputs)
414 return -EINVAL;
415 cx->audio_input = vout->index;
416 cx18_audio_set_io(cx);
417 break;
418 }
419
420 case VIDIOC_ENUMINPUT:{
421 struct v4l2_input *vin = arg;
422
423 /* set it to defaults from our table */
424 return cx18_get_input(cx, vin->index, vin);
425 }
426
427 case VIDIOC_TRY_FMT:
428 case VIDIOC_S_FMT: {
429 struct v4l2_format *fmt = arg;
430
431 return cx18_try_or_set_fmt(cx, id->type, fmt, cmd == VIDIOC_S_FMT);
432 }
433
434 case VIDIOC_G_FMT: {
435 struct v4l2_format *fmt = arg;
436 int type = fmt->type;
437
438 memset(fmt, 0, sizeof(*fmt));
439 fmt->type = type;
440 return cx18_get_fmt(cx, id->type, fmt);
441 }
442
443 case VIDIOC_CROPCAP: {
444 struct v4l2_cropcap *cropcap = arg;
445
446 if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
447 return -EINVAL;
448 cropcap->bounds.top = cropcap->bounds.left = 0;
449 cropcap->bounds.width = 720;
450 cropcap->bounds.height = cx->is_50hz ? 576 : 480;
451 cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10;
452 cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11;
453 cropcap->defrect = cropcap->bounds;
454 return 0;
455 }
456
457 case VIDIOC_S_CROP: {
458 struct v4l2_crop *crop = arg;
459
460 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
461 return -EINVAL;
462 return cx18_av_cmd(cx, VIDIOC_S_CROP, arg);
463 }
464
465 case VIDIOC_G_CROP: {
466 struct v4l2_crop *crop = arg;
467
468 if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
469 return -EINVAL;
470 return cx18_av_cmd(cx, VIDIOC_G_CROP, arg);
471 }
472
473 case VIDIOC_ENUM_FMT: {
474 static struct v4l2_fmtdesc formats[] = {
475 { 0, 0, 0,
476 "HM12 (YUV 4:1:1)", V4L2_PIX_FMT_HM12,
477 { 0, 0, 0, 0 }
478 },
479 { 1, 0, V4L2_FMT_FLAG_COMPRESSED,
480 "MPEG", V4L2_PIX_FMT_MPEG,
481 { 0, 0, 0, 0 }
482 }
483 };
484 struct v4l2_fmtdesc *fmt = arg;
485 enum v4l2_buf_type type = fmt->type;
486
487 switch (type) {
488 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
489 break;
490 default:
491 return -EINVAL;
492 }
493 if (fmt->index > 1)
494 return -EINVAL;
495 *fmt = formats[fmt->index];
496 fmt->type = type;
497 return 0;
498 }
499
500 case VIDIOC_G_INPUT:{
501 *(int *)arg = cx->active_input;
502 break;
503 }
504
505 case VIDIOC_S_INPUT:{
506 int inp = *(int *)arg;
507
508 if (inp < 0 || inp >= cx->nof_inputs)
509 return -EINVAL;
510
511 if (inp == cx->active_input) {
512 CX18_DEBUG_INFO("Input unchanged\n");
513 break;
514 }
515 CX18_DEBUG_INFO("Changing input from %d to %d\n",
516 cx->active_input, inp);
517
518 cx->active_input = inp;
519 /* Set the audio input to whatever is appropriate for the
520 input type. */
521 cx->audio_input = cx->card->video_inputs[inp].audio_index;
522
523 /* prevent others from messing with the streams until
524 we're finished changing inputs. */
525 cx18_mute(cx);
526 cx18_video_set_io(cx);
527 cx18_audio_set_io(cx);
528 cx18_unmute(cx);
529 break;
530 }
531
532 case VIDIOC_G_FREQUENCY:{
533 struct v4l2_frequency *vf = arg;
534
535 if (vf->tuner != 0)
536 return -EINVAL;
537 cx18_call_i2c_clients(cx, cmd, arg);
538 break;
539 }
540
541 case VIDIOC_S_FREQUENCY:{
542 struct v4l2_frequency vf = *(struct v4l2_frequency *)arg;
543
544 if (vf.tuner != 0)
545 return -EINVAL;
546
547 cx18_mute(cx);
548 CX18_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency);
549 cx18_call_i2c_clients(cx, cmd, &vf);
550 cx18_unmute(cx);
551 break;
552 }
553
554 case VIDIOC_ENUMSTD:{
555 struct v4l2_standard *vs = arg;
556 int idx = vs->index;
557
558 if (idx < 0 || idx >= ARRAY_SIZE(enum_stds))
559 return -EINVAL;
560
561 *vs = (enum_stds[idx].std & V4L2_STD_525_60) ?
562 cx18_std_60hz : cx18_std_50hz;
563 vs->index = idx;
564 vs->id = enum_stds[idx].std;
565 strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name));
566 break;
567 }
568
569 case VIDIOC_G_STD:{
570 *(v4l2_std_id *) arg = cx->std;
571 break;
572 }
573
574 case VIDIOC_S_STD: {
575 v4l2_std_id std = *(v4l2_std_id *) arg;
576
577 if ((std & V4L2_STD_ALL) == 0)
578 return -EINVAL;
579
580 if (std == cx->std)
581 break;
582
583 if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ||
584 atomic_read(&cx->capturing) > 0) {
585 /* Switching standard would turn off the radio or mess
586 with already running streams, prevent that by
587 returning EBUSY. */
588 return -EBUSY;
589 }
590
591 cx->std = std;
592 cx->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0;
593 cx->params.is_50hz = cx->is_50hz = !cx->is_60hz;
594 cx->params.width = 720;
595 cx->params.height = cx->is_50hz ? 576 : 480;
596 cx->vbi.count = cx->is_50hz ? 18 : 12;
597 cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
598 cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
599 cx->vbi.sliced_decoder_line_size = cx->is_60hz ? 272 : 284;
600 CX18_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)cx->std);
601
602 /* Tuner */
603 cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
604 break;
605 }
606
607 case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */
608 struct v4l2_tuner *vt = arg;
609
610 if (vt->index != 0)
611 return -EINVAL;
612
613 cx18_call_i2c_clients(cx, VIDIOC_S_TUNER, vt);
614 break;
615 }
616
617 case VIDIOC_G_TUNER: {
618 struct v4l2_tuner *vt = arg;
619
620 if (vt->index != 0)
621 return -EINVAL;
622
623 memset(vt, 0, sizeof(*vt));
624 cx18_call_i2c_clients(cx, VIDIOC_G_TUNER, vt);
625
626 if (test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
627 strlcpy(vt->name, "cx18 Radio Tuner", sizeof(vt->name));
628 vt->type = V4L2_TUNER_RADIO;
629 } else {
630 strlcpy(vt->name, "cx18 TV Tuner", sizeof(vt->name));
631 vt->type = V4L2_TUNER_ANALOG_TV;
632 }
633 break;
634 }
635
636 case VIDIOC_G_SLICED_VBI_CAP: {
637 struct v4l2_sliced_vbi_cap *cap = arg;
638 int set = cx->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
639 int f, l;
640 enum v4l2_buf_type type = cap->type;
641
642 memset(cap, 0, sizeof(*cap));
643 cap->type = type;
644 if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
645 for (f = 0; f < 2; f++) {
646 for (l = 0; l < 24; l++) {
647 if (valid_service_line(f, l, cx->is_50hz))
648 cap->service_lines[f][l] = set;
649 }
650 }
651 return 0;
652 }
653 return -EINVAL;
654 }
655
656 case VIDIOC_ENCODER_CMD:
657 case VIDIOC_TRY_ENCODER_CMD: {
658 struct v4l2_encoder_cmd *enc = arg;
659 int try = cmd == VIDIOC_TRY_ENCODER_CMD;
660
661 memset(&enc->raw, 0, sizeof(enc->raw));
662 switch (enc->cmd) {
663 case V4L2_ENC_CMD_START:
664 enc->flags = 0;
665 if (try)
666 return 0;
667 return cx18_start_capture(id);
668
669 case V4L2_ENC_CMD_STOP:
670 enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
671 if (try)
672 return 0;
673 cx18_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
674 return 0;
675
676 case V4L2_ENC_CMD_PAUSE:
677 enc->flags = 0;
678 if (try)
679 return 0;
680 if (!atomic_read(&cx->capturing))
681 return -EPERM;
682 if (test_and_set_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
683 return 0;
684 cx18_mute(cx);
685 cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, cx18_find_handle(cx));
686 break;
687
688 case V4L2_ENC_CMD_RESUME:
689 enc->flags = 0;
690 if (try)
691 return 0;
692 if (!atomic_read(&cx->capturing))
693 return -EPERM;
694 if (!test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
695 return 0;
696 cx18_vapi(cx, CX18_CPU_CAPTURE_RESUME, 1, cx18_find_handle(cx));
697 cx18_unmute(cx);
698 break;
699 default:
700 return -EINVAL;
701 }
702 break;
703 }
704
705 case VIDIOC_LOG_STATUS:
706 {
707 struct v4l2_input vidin;
708 struct v4l2_audio audin;
709 int i;
710
711 CX18_INFO("================= START STATUS CARD #%d =================\n", cx->num);
712 if (cx->hw_flags & CX18_HW_TVEEPROM) {
713 struct tveeprom tv;
714
715 cx18_read_eeprom(cx, &tv);
716 }
717 cx18_call_i2c_clients(cx, VIDIOC_LOG_STATUS, NULL);
718 cx18_get_input(cx, cx->active_input, &vidin);
719 cx18_get_audio_input(cx, cx->audio_input, &audin);
720 CX18_INFO("Video Input: %s\n", vidin.name);
721 CX18_INFO("Audio Input: %s\n", audin.name);
722 CX18_INFO("Tuner: %s\n",
723 test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ?
724 "Radio" : "TV");
725 cx2341x_log_status(&cx->params, cx->name);
726 CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
727 for (i = 0; i < CX18_MAX_STREAMS; i++) {
728 struct cx18_stream *s = &cx->streams[i];
729
730 if (s->v4l2dev == NULL || s->buffers == 0)
731 continue;
732 CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n",
733 s->name, s->s_flags,
734 (s->buffers - s->q_free.buffers) * 100 / s->buffers,
735 (s->buffers * s->buf_size) / 1024, s->buffers);
736 }
737 CX18_INFO("Read MPEG/VBI: %lld/%lld bytes\n",
738 (long long)cx->mpg_data_received,
739 (long long)cx->vbi_data_inserted);
740 CX18_INFO("================== END STATUS CARD #%d ==================\n", cx->num);
741 break;
742 }
743
744 default:
745 return -EINVAL;
746 }
747 return 0;
748}
749
750static int cx18_v4l2_do_ioctl(struct inode *inode, struct file *filp,
751 unsigned int cmd, void *arg)
752{
753 struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
754 struct cx18 *cx = id->cx;
755 int ret;
756
757 /* check priority */
758 switch (cmd) {
759 case VIDIOC_S_CTRL:
760 case VIDIOC_S_STD:
761 case VIDIOC_S_INPUT:
762 case VIDIOC_S_TUNER:
763 case VIDIOC_S_FREQUENCY:
764 case VIDIOC_S_FMT:
765 case VIDIOC_S_CROP:
766 case VIDIOC_S_EXT_CTRLS:
767 ret = v4l2_prio_check(&cx->prio, &id->prio);
768 if (ret)
769 return ret;
770 }
771
772 switch (cmd) {
773 case VIDIOC_DBG_G_REGISTER:
774 case VIDIOC_DBG_S_REGISTER:
775 case VIDIOC_G_CHIP_IDENT:
776 case VIDIOC_INT_S_AUDIO_ROUTING:
777 case VIDIOC_INT_RESET:
778 if (cx18_debug & CX18_DBGFLG_IOCTL) {
779 printk(KERN_INFO "cx18%d ioctl: ", cx->num);
780 v4l_printk_ioctl(cmd);
781 }
782 return cx18_debug_ioctls(filp, cmd, arg);
783
784 case VIDIOC_G_PRIORITY:
785 case VIDIOC_S_PRIORITY:
786 case VIDIOC_QUERYCAP:
787 case VIDIOC_ENUMINPUT:
788 case VIDIOC_G_INPUT:
789 case VIDIOC_S_INPUT:
790 case VIDIOC_G_FMT:
791 case VIDIOC_S_FMT:
792 case VIDIOC_TRY_FMT:
793 case VIDIOC_ENUM_FMT:
794 case VIDIOC_CROPCAP:
795 case VIDIOC_G_CROP:
796 case VIDIOC_S_CROP:
797 case VIDIOC_G_FREQUENCY:
798 case VIDIOC_S_FREQUENCY:
799 case VIDIOC_ENUMSTD:
800 case VIDIOC_G_STD:
801 case VIDIOC_S_STD:
802 case VIDIOC_S_TUNER:
803 case VIDIOC_G_TUNER:
804 case VIDIOC_ENUMAUDIO:
805 case VIDIOC_S_AUDIO:
806 case VIDIOC_G_AUDIO:
807 case VIDIOC_G_SLICED_VBI_CAP:
808 case VIDIOC_LOG_STATUS:
809 case VIDIOC_G_ENC_INDEX:
810 case VIDIOC_ENCODER_CMD:
811 case VIDIOC_TRY_ENCODER_CMD:
812 if (cx18_debug & CX18_DBGFLG_IOCTL) {
813 printk(KERN_INFO "cx18%d ioctl: ", cx->num);
814 v4l_printk_ioctl(cmd);
815 }
816 return cx18_v4l2_ioctls(cx, filp, cmd, arg);
817
818 case VIDIOC_QUERYMENU:
819 case VIDIOC_QUERYCTRL:
820 case VIDIOC_S_CTRL:
821 case VIDIOC_G_CTRL:
822 case VIDIOC_S_EXT_CTRLS:
823 case VIDIOC_G_EXT_CTRLS:
824 case VIDIOC_TRY_EXT_CTRLS:
825 if (cx18_debug & CX18_DBGFLG_IOCTL) {
826 printk(KERN_INFO "cx18%d ioctl: ", cx->num);
827 v4l_printk_ioctl(cmd);
828 }
829 return cx18_control_ioctls(cx, cmd, arg);
830
831 case 0x00005401: /* Handle isatty() calls */
832 return -EINVAL;
833 default:
834 return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
835 cx18_v4l2_do_ioctl);
836 }
837 return 0;
838}
839
840int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
841 unsigned long arg)
842{
843 struct cx18_open_id *id = (struct cx18_open_id *)filp->private_data;
844 struct cx18 *cx = id->cx;
845 int res;
846
847 mutex_lock(&cx->serialize_lock);
848 res = video_usercopy(inode, filp, cmd, arg, cx18_v4l2_do_ioctl);
849 mutex_unlock(&cx->serialize_lock);
850 return res;
851}
diff --git a/drivers/media/video/cx18/cx18-ioctl.h b/drivers/media/video/cx18/cx18-ioctl.h
new file mode 100644
index 000000000000..0ee152d837d6
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-ioctl.h
@@ -0,0 +1,30 @@
1/*
2 * cx18 ioctl system call
3 *
4 * Derived from ivtv-ioctl.h
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 */
23
24u16 service2vbi(int type);
25void expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
26u16 get_service_set(struct v4l2_sliced_vbi_format *fmt);
27int cx18_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
28 unsigned long arg);
29int cx18_v4l2_ioctls(struct cx18 *cx, struct file *filp, unsigned cmd,
30 void *arg);
diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c
new file mode 100644
index 000000000000..6e14f8bda559
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-irq.c
@@ -0,0 +1,179 @@
1/*
2 * cx18 interrupt handling
3 *
4 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 * 02111-1307 USA
20 */
21
22#include "cx18-driver.h"
23#include "cx18-firmware.h"
24#include "cx18-fileops.h"
25#include "cx18-queue.h"
26#include "cx18-irq.h"
27#include "cx18-ioctl.h"
28#include "cx18-mailbox.h"
29#include "cx18-vbi.h"
30#include "cx18-scb.h"
31
32#define DMA_MAGIC_COOKIE 0x000001fe
33
34static void epu_dma_done(struct cx18 *cx, struct cx18_mailbox *mb)
35{
36 u32 handle = mb->args[0];
37 struct cx18_stream *s = NULL;
38 struct cx18_buffer *buf;
39 u32 off;
40 int i;
41 int id;
42
43 for (i = 0; i < CX18_MAX_STREAMS; i++) {
44 s = &cx->streams[i];
45 if ((handle == s->handle) && (s->dvb.enabled))
46 break;
47 if (s->v4l2dev && handle == s->handle)
48 break;
49 }
50 if (i == CX18_MAX_STREAMS) {
51 CX18_WARN("DMA done for unknown handle %d for stream %s\n",
52 handle, s->name);
53 mb->error = CXERR_NOT_OPEN;
54 mb->cmd = 0;
55 cx18_mb_ack(cx, mb);
56 return;
57 }
58
59 off = mb->args[1];
60 if (mb->args[2] != 1)
61 CX18_WARN("Ack struct = %d for %s\n",
62 mb->args[2], s->name);
63 id = read_enc(off);
64 buf = cx18_queue_find_buf(s, id, read_enc(off + 4));
65 CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id);
66 if (buf) {
67 cx18_buf_sync_for_cpu(s, buf);
68 if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) {
69 /* process the buffer here */
70 CX18_DEBUG_HI_DMA("TS recv and sent bytesused=%d\n",
71 buf->bytesused);
72
73 dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
74 buf->bytesused);
75
76 cx18_buf_sync_for_device(s, buf);
77 cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
78 (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
79 1, buf->id, s->buf_size);
80 } else
81 set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
82 } else {
83 CX18_WARN("Could not find buf %d for stream %s\n",
84 read_enc(off), s->name);
85 }
86 mb->error = 0;
87 mb->cmd = 0;
88 cx18_mb_ack(cx, mb);
89 wake_up(&cx->dma_waitq);
90 if (s->id != -1)
91 wake_up(&s->waitq);
92}
93
94static void epu_debug(struct cx18 *cx, struct cx18_mailbox *mb)
95{
96 char str[256] = { 0 };
97 char *p;
98
99 if (mb->args[1]) {
100 setup_page(mb->args[1]);
101 memcpy_fromio(str, cx->enc_mem + mb->args[1], 252);
102 str[252] = 0;
103 }
104 cx18_mb_ack(cx, mb);
105 CX18_DEBUG_INFO("%x %s\n", mb->args[0], str);
106 p = strchr(str, '.');
107 if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str)
108 CX18_INFO("FW version: %s\n", p - 1);
109}
110
111static void hpu_cmd(struct cx18 *cx, u32 sw1)
112{
113 struct cx18_mailbox mb;
114
115 if (sw1 & IRQ_CPU_TO_EPU) {
116 memcpy_fromio(&mb, &cx->scb->cpu2epu_mb, sizeof(mb));
117 mb.error = 0;
118
119 switch (mb.cmd) {
120 case CX18_EPU_DMA_DONE:
121 epu_dma_done(cx, &mb);
122 break;
123 case CX18_EPU_DEBUG:
124 epu_debug(cx, &mb);
125 break;
126 default:
127 CX18_WARN("Unexpected mailbox command %08x\n", mb.cmd);
128 break;
129 }
130 }
131 if (sw1 & (IRQ_APU_TO_EPU | IRQ_HPU_TO_EPU))
132 CX18_WARN("Unexpected interrupt %08x\n", sw1);
133}
134
135irqreturn_t cx18_irq_handler(int irq, void *dev_id)
136{
137 struct cx18 *cx = (struct cx18 *)dev_id;
138 u32 sw1, sw1_mask;
139 u32 sw2, sw2_mask;
140 u32 hw2, hw2_mask;
141
142 spin_lock(&cx->dma_reg_lock);
143
144 hw2_mask = read_reg(HW2_INT_MASK5_PCI);
145 hw2 = read_reg(HW2_INT_CLR_STATUS) & hw2_mask;
146 sw2_mask = read_reg(SW2_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU_ACK;
147 sw2 = read_reg(SW2_INT_STATUS) & sw2_mask;
148 sw1_mask = read_reg(SW1_INT_ENABLE_PCI) | IRQ_EPU_TO_HPU;
149 sw1 = read_reg(SW1_INT_STATUS) & sw1_mask;
150
151 write_reg(sw2&sw2_mask, SW2_INT_STATUS);
152 write_reg(sw1&sw1_mask, SW1_INT_STATUS);
153 write_reg(hw2&hw2_mask, HW2_INT_CLR_STATUS);
154
155 if (sw1 || sw2 || hw2)
156 CX18_DEBUG_HI_IRQ("SW1: %x SW2: %x HW2: %x\n", sw1, sw2, hw2);
157
158 /* To do: interrupt-based I2C handling
159 if (hw2 & 0x00c00000) {
160 }
161 */
162
163 if (sw2) {
164 if (sw2 & (cx->scb->cpu2hpu_irq_ack | cx->scb->cpu2epu_irq_ack))
165 wake_up(&cx->mb_cpu_waitq);
166 if (sw2 & (cx->scb->apu2hpu_irq_ack | cx->scb->apu2epu_irq_ack))
167 wake_up(&cx->mb_apu_waitq);
168 if (sw2 & cx->scb->epu2hpu_irq_ack)
169 wake_up(&cx->mb_epu_waitq);
170 if (sw2 & cx->scb->hpu2epu_irq_ack)
171 wake_up(&cx->mb_hpu_waitq);
172 }
173
174 if (sw1)
175 hpu_cmd(cx, sw1);
176 spin_unlock(&cx->dma_reg_lock);
177
178 return (hw2 | sw1 | sw2) ? IRQ_HANDLED : IRQ_NONE;
179}
diff --git a/drivers/media/video/cx18/cx18-irq.h b/drivers/media/video/cx18/cx18-irq.h
new file mode 100644
index 000000000000..379f704f5cba
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-irq.h
@@ -0,0 +1,37 @@
1/*
2 * cx18 interrupt handling
3 *
4 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 * 02111-1307 USA
20 */
21
22#define HW2_I2C1_INT (1 << 22)
23#define HW2_I2C2_INT (1 << 23)
24#define HW2_INT_CLR_STATUS 0xc730c4
25#define HW2_INT_MASK5_PCI 0xc730e4
26#define SW1_INT_SET 0xc73100
27#define SW1_INT_STATUS 0xc73104
28#define SW1_INT_ENABLE_PCI 0xc7311c
29#define SW2_INT_SET 0xc73140
30#define SW2_INT_STATUS 0xc73144
31#define SW2_INT_ENABLE_PCI 0xc7315c
32
33irqreturn_t cx18_irq_handler(int irq, void *dev_id);
34
35void cx18_irq_work_handler(struct work_struct *work);
36void cx18_dma_stream_dec_prepare(struct cx18_stream *s, u32 offset, int lock);
37void cx18_unfinished_dma(unsigned long arg);
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
new file mode 100644
index 000000000000..0c5f328bca54
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -0,0 +1,372 @@
1/*
2 * cx18 mailbox functions
3 *
4 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 * 02111-1307 USA
20 */
21
22#include <stdarg.h>
23
24#include "cx18-driver.h"
25#include "cx18-scb.h"
26#include "cx18-irq.h"
27#include "cx18-mailbox.h"
28
29#define API_FAST (1 << 2) /* Short timeout */
30#define API_SLOW (1 << 3) /* Additional 300ms timeout */
31
32#define APU 0
33#define CPU 1
34#define EPU 2
35#define HPU 3
36
37struct cx18_api_info {
38 u32 cmd;
39 u8 flags; /* Flags, see above */
40 u8 rpu; /* Processing unit */
41 const char *name; /* The name of the command */
42};
43
44#define API_ENTRY(rpu, x, f) { (x), (f), (rpu), #x }
45
46static const struct cx18_api_info api_info[] = {
47 /* MPEG encoder API */
48 API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0),
49 API_ENTRY(CPU, CX18_EPU_DEBUG, 0),
50 API_ENTRY(CPU, CX18_CREATE_TASK, 0),
51 API_ENTRY(CPU, CX18_DESTROY_TASK, 0),
52 API_ENTRY(CPU, CX18_CPU_CAPTURE_START, API_SLOW),
53 API_ENTRY(CPU, CX18_CPU_CAPTURE_STOP, API_SLOW),
54 API_ENTRY(CPU, CX18_CPU_CAPTURE_PAUSE, 0),
55 API_ENTRY(CPU, CX18_CPU_CAPTURE_RESUME, 0),
56 API_ENTRY(CPU, CX18_CPU_SET_CHANNEL_TYPE, 0),
57 API_ENTRY(CPU, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 0),
58 API_ENTRY(CPU, CX18_CPU_SET_VIDEO_IN, 0),
59 API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RATE, 0),
60 API_ENTRY(CPU, CX18_CPU_SET_VIDEO_RESOLUTION, 0),
61 API_ENTRY(CPU, CX18_CPU_SET_FILTER_PARAM, 0),
62 API_ENTRY(CPU, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 0),
63 API_ENTRY(CPU, CX18_CPU_SET_MEDIAN_CORING, 0),
64 API_ENTRY(CPU, CX18_CPU_SET_INDEXTABLE, 0),
65 API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PARAMETERS, 0),
66 API_ENTRY(CPU, CX18_CPU_SET_VIDEO_MUTE, 0),
67 API_ENTRY(CPU, CX18_CPU_SET_AUDIO_MUTE, 0),
68 API_ENTRY(CPU, CX18_CPU_SET_MISC_PARAMETERS, 0),
69 API_ENTRY(CPU, CX18_CPU_SET_RAW_VBI_PARAM, API_SLOW),
70 API_ENTRY(CPU, CX18_CPU_SET_CAPTURE_LINE_NO, 0),
71 API_ENTRY(CPU, CX18_CPU_SET_COPYRIGHT, 0),
72 API_ENTRY(CPU, CX18_CPU_SET_AUDIO_PID, 0),
73 API_ENTRY(CPU, CX18_CPU_SET_VIDEO_PID, 0),
74 API_ENTRY(CPU, CX18_CPU_SET_VER_CROP_LINE, 0),
75 API_ENTRY(CPU, CX18_CPU_SET_GOP_STRUCTURE, 0),
76 API_ENTRY(CPU, CX18_CPU_SET_SCENE_CHANGE_DETECTION, 0),
77 API_ENTRY(CPU, CX18_CPU_SET_ASPECT_RATIO, 0),
78 API_ENTRY(CPU, CX18_CPU_SET_SKIP_INPUT_FRAME, 0),
79 API_ENTRY(CPU, CX18_CPU_SET_SLICED_VBI_PARAM, 0),
80 API_ENTRY(CPU, CX18_CPU_SET_USERDATA_PLACE_HOLDER, 0),
81 API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0),
82 API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0),
83 API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST),
84 API_ENTRY(0, 0, 0),
85};
86
87static const struct cx18_api_info *find_api_info(u32 cmd)
88{
89 int i;
90
91 for (i = 0; api_info[i].cmd; i++)
92 if (api_info[i].cmd == cmd)
93 return &api_info[i];
94 return NULL;
95}
96
97static struct cx18_mailbox *cx18_mb_is_complete(struct cx18 *cx, int rpu,
98 u32 *state, u32 *irq, u32 *req)
99{
100 struct cx18_mailbox *mb = NULL;
101 int wait_count = 0;
102 u32 ack;
103
104 switch (rpu) {
105 case APU:
106 mb = &cx->scb->epu2apu_mb;
107 *state = readl(&cx->scb->apu_state);
108 *irq = readl(&cx->scb->epu2apu_irq);
109 break;
110
111 case CPU:
112 mb = &cx->scb->epu2cpu_mb;
113 *state = readl(&cx->scb->cpu_state);
114 *irq = readl(&cx->scb->epu2cpu_irq);
115 break;
116
117 case HPU:
118 mb = &cx->scb->epu2hpu_mb;
119 *state = readl(&cx->scb->hpu_state);
120 *irq = readl(&cx->scb->epu2hpu_irq);
121 break;
122 }
123
124 if (mb == NULL)
125 return mb;
126
127 do {
128 *req = readl(&mb->request);
129 ack = readl(&mb->ack);
130 wait_count++;
131 } while (*req != ack && wait_count < 600);
132
133 if (*req == ack) {
134 (*req)++;
135 if (*req == 0 || *req == 0xffffffff)
136 *req = 1;
137 return mb;
138 }
139 return NULL;
140}
141
142long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb)
143{
144 const struct cx18_api_info *info = find_api_info(mb->cmd);
145 struct cx18_mailbox *ack_mb;
146 u32 ack_irq;
147 u8 rpu = CPU;
148
149 if (info == NULL && mb->cmd) {
150 CX18_WARN("Cannot ack unknown command %x\n", mb->cmd);
151 return -EINVAL;
152 }
153 if (info)
154 rpu = info->rpu;
155
156 switch (rpu) {
157 case HPU:
158 ack_irq = IRQ_EPU_TO_HPU_ACK;
159 ack_mb = &cx->scb->hpu2epu_mb;
160 break;
161 case APU:
162 ack_irq = IRQ_EPU_TO_APU_ACK;
163 ack_mb = &cx->scb->apu2epu_mb;
164 break;
165 case CPU:
166 ack_irq = IRQ_EPU_TO_CPU_ACK;
167 ack_mb = &cx->scb->cpu2epu_mb;
168 break;
169 default:
170 CX18_WARN("Unknown RPU for command %x\n", mb->cmd);
171 return -EINVAL;
172 }
173
174 setup_page(SCB_OFFSET);
175 write_sync(mb->request, &ack_mb->ack);
176 write_reg(ack_irq, SW2_INT_SET);
177 return 0;
178}
179
180
181static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
182{
183 const struct cx18_api_info *info = find_api_info(cmd);
184 u32 state = 0, irq = 0, req, oldreq, err;
185 struct cx18_mailbox *mb;
186 wait_queue_head_t *waitq;
187 int timeout = 100;
188 int cnt = 0;
189 int sig = 0;
190 int i;
191
192 if (info == NULL) {
193 CX18_WARN("unknown cmd %x\n", cmd);
194 return -EINVAL;
195 }
196
197 if (cmd == CX18_CPU_DE_SET_MDL)
198 CX18_DEBUG_HI_API("%s\n", info->name);
199 else
200 CX18_DEBUG_API("%s\n", info->name);
201 setup_page(SCB_OFFSET);
202 mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req);
203
204 if (mb == NULL) {
205 CX18_ERR("mb %s busy\n", info->name);
206 return -EBUSY;
207 }
208
209 oldreq = req - 1;
210 writel(cmd, &mb->cmd);
211 for (i = 0; i < args; i++)
212 writel(data[i], &mb->args[i]);
213 writel(0, &mb->error);
214 writel(req, &mb->request);
215
216 switch (info->rpu) {
217 case APU: waitq = &cx->mb_apu_waitq; break;
218 case CPU: waitq = &cx->mb_cpu_waitq; break;
219 case EPU: waitq = &cx->mb_epu_waitq; break;
220 case HPU: waitq = &cx->mb_hpu_waitq; break;
221 default: return -EINVAL;
222 }
223 if (info->flags & API_FAST)
224 timeout /= 2;
225 write_reg(irq, SW1_INT_SET);
226
227 while (!sig && readl(&mb->ack) != readl(&mb->request) && cnt < 660) {
228 if (cnt > 200 && !in_atomic())
229 sig = cx18_msleep_timeout(10, 1);
230 cnt++;
231 }
232 if (sig)
233 return -EINTR;
234 if (cnt == 660) {
235 writel(oldreq, &mb->request);
236 CX18_ERR("mb %s failed\n", info->name);
237 return -EINVAL;
238 }
239 for (i = 0; i < MAX_MB_ARGUMENTS; i++)
240 data[i] = readl(&mb->args[i]);
241 err = readl(&mb->error);
242 if (!in_atomic() && (info->flags & API_SLOW))
243 cx18_msleep_timeout(300, 0);
244 if (err)
245 CX18_DEBUG_API("mailbox error %08x for command %s\n", err,
246 info->name);
247 return err ? -EIO : 0;
248}
249
250int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[])
251{
252 int res = cx18_api_call(cx, cmd, args, data);
253
254 /* Allow a single retry, probably already too late though.
255 If there is no free mailbox then that is usually an indication
256 of a more serious problem. */
257 return (res == -EBUSY) ? cx18_api_call(cx, cmd, args, data) : res;
258}
259
260static int cx18_set_filter_param(struct cx18_stream *s)
261{
262 struct cx18 *cx = s->cx;
263 u32 mode;
264 int ret;
265
266 mode = (cx->filter_mode & 1) ? 2 : (cx->spatial_strength ? 1 : 0);
267 ret = cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
268 s->handle, 1, mode, cx->spatial_strength);
269 mode = (cx->filter_mode & 2) ? 2 : (cx->temporal_strength ? 1 : 0);
270 ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
271 s->handle, 0, mode, cx->temporal_strength);
272 ret = ret ? ret : cx18_vapi(cx, CX18_CPU_SET_FILTER_PARAM, 4,
273 s->handle, 2, cx->filter_mode >> 2, 0);
274 return ret;
275}
276
277int cx18_api_func(void *priv, u32 cmd, int in, int out,
278 u32 data[CX2341X_MBOX_MAX_DATA])
279{
280 struct cx18 *cx = priv;
281 struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
282
283 switch (cmd) {
284 case CX2341X_ENC_SET_OUTPUT_PORT:
285 return 0;
286 case CX2341X_ENC_SET_FRAME_RATE:
287 return cx18_vapi(cx, CX18_CPU_SET_VIDEO_IN, 6,
288 s->handle, 0, 0, 0, 0, data[0]);
289 case CX2341X_ENC_SET_FRAME_SIZE:
290 return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RESOLUTION, 3,
291 s->handle, data[1], data[0]);
292 case CX2341X_ENC_SET_STREAM_TYPE:
293 return cx18_vapi(cx, CX18_CPU_SET_STREAM_OUTPUT_TYPE, 2,
294 s->handle, data[0]);
295 case CX2341X_ENC_SET_ASPECT_RATIO:
296 return cx18_vapi(cx, CX18_CPU_SET_ASPECT_RATIO, 2,
297 s->handle, data[0]);
298
299 case CX2341X_ENC_SET_GOP_PROPERTIES:
300 return cx18_vapi(cx, CX18_CPU_SET_GOP_STRUCTURE, 3,
301 s->handle, data[0], data[1]);
302 case CX2341X_ENC_SET_GOP_CLOSURE:
303 return 0;
304 case CX2341X_ENC_SET_AUDIO_PROPERTIES:
305 return cx18_vapi(cx, CX18_CPU_SET_AUDIO_PARAMETERS, 2,
306 s->handle, data[0]);
307 case CX2341X_ENC_MUTE_AUDIO:
308 return cx18_vapi(cx, CX18_CPU_SET_AUDIO_MUTE, 2,
309 s->handle, data[0]);
310 case CX2341X_ENC_SET_BIT_RATE:
311 return cx18_vapi(cx, CX18_CPU_SET_VIDEO_RATE, 5,
312 s->handle, data[0], data[1], data[2], data[3]);
313 case CX2341X_ENC_MUTE_VIDEO:
314 return cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2,
315 s->handle, data[0]);
316 case CX2341X_ENC_SET_FRAME_DROP_RATE:
317 return cx18_vapi(cx, CX18_CPU_SET_SKIP_INPUT_FRAME, 2,
318 s->handle, data[0]);
319 case CX2341X_ENC_MISC:
320 return cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 4,
321 s->handle, data[0], data[1], data[2]);
322 case CX2341X_ENC_SET_DNR_FILTER_MODE:
323 cx->filter_mode = (data[0] & 3) | (data[1] << 2);
324 return cx18_set_filter_param(s);
325 case CX2341X_ENC_SET_DNR_FILTER_PROPS:
326 cx->spatial_strength = data[0];
327 cx->temporal_strength = data[1];
328 return cx18_set_filter_param(s);
329 case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
330 return cx18_vapi(cx, CX18_CPU_SET_SPATIAL_FILTER_TYPE, 3,
331 s->handle, data[0], data[1]);
332 case CX2341X_ENC_SET_CORING_LEVELS:
333 return cx18_vapi(cx, CX18_CPU_SET_MEDIAN_CORING, 5,
334 s->handle, data[0], data[1], data[2], data[3]);
335 }
336 CX18_WARN("Unknown cmd %x\n", cmd);
337 return 0;
338}
339
340int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS],
341 u32 cmd, int args, ...)
342{
343 va_list ap;
344 int i;
345
346 va_start(ap, args);
347 for (i = 0; i < args; i++)
348 data[i] = va_arg(ap, u32);
349 va_end(ap);
350 return cx18_api(cx, cmd, args, data);
351}
352
353int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...)
354{
355 u32 data[MAX_MB_ARGUMENTS];
356 va_list ap;
357 int i;
358
359 if (cx == NULL) {
360 CX18_ERR("cx == NULL (cmd=%x)\n", cmd);
361 return 0;
362 }
363 if (args > MAX_MB_ARGUMENTS) {
364 CX18_ERR("args too big (cmd=%x)\n", cmd);
365 args = MAX_MB_ARGUMENTS;
366 }
367 va_start(ap, args);
368 for (i = 0; i < args; i++)
369 data[i] = va_arg(ap, u32);
370 va_end(ap);
371 return cx18_api(cx, cmd, args, data);
372}
diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h
new file mode 100644
index 000000000000..d995641536b3
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-mailbox.h
@@ -0,0 +1,73 @@
1/*
2 * cx18 mailbox functions
3 *
4 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 * 02111-1307 USA
20 */
21
22#ifndef _CX18_MAILBOX_H_
23#define _CX18_MAILBOX_H_
24
25/* mailbox max args */
26#define MAX_MB_ARGUMENTS 6
27/* compatibility, should be same as the define in cx2341x.h */
28#define CX2341X_MBOX_MAX_DATA 16
29
30#define MB_RESERVED_HANDLE_0 0
31#define MB_RESERVED_HANDLE_1 0xFFFFFFFF
32
33struct cx18;
34
35/* The cx18_mailbox struct is the mailbox structure which is used for passing
36 messages between processors */
37struct cx18_mailbox {
38 /* The sender sets a handle in 'request' after he fills the command. The
39 'request' should be different than 'ack'. The sender, also, generates
40 an interrupt on XPU2YPU_irq where XPU is the sender and YPU is the
41 receiver. */
42 u32 request;
43 /* The receiver detects a new command when 'req' is different than 'ack'.
44 He sets 'ack' to the same value as 'req' to clear the command. He, also,
45 generates an interrupt on YPU2XPU_irq where XPU is the sender and YPU
46 is the receiver. */
47 u32 ack;
48 u32 reserved[6];
49 /* 'cmd' identifies the command. The list of these commands are in
50 cx23418.h */
51 u32 cmd;
52 /* Each command can have up to 6 arguments */
53 u32 args[MAX_MB_ARGUMENTS];
54 /* The return code can be one of the codes in the file cx23418.h. If the
55 command is completed successfuly, the error will be ERR_SYS_SUCCESS.
56 If it is pending, the code is ERR_SYS_PENDING. If it failed, the error
57 code would indicate the task from which the error originated and will
58 be one of the errors in cx23418.h. In that case, the following
59 applies ((error & 0xff) != 0).
60 If the command is pending, the return will be passed in a MB from the
61 receiver to the sender. 'req' will be returned in args[0] */
62 u32 error;
63};
64
65int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]);
66int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd,
67 int args, ...);
68int cx18_vapi(struct cx18 *cx, u32 cmd, int args, ...);
69int cx18_api_func(void *priv, u32 cmd, int in, int out,
70 u32 data[CX2341X_MBOX_MAX_DATA]);
71long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb);
72
73#endif
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c
new file mode 100644
index 000000000000..65af1bb507ca
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-queue.c
@@ -0,0 +1,282 @@
1/*
2 * cx18 buffer queues
3 *
4 * Derived from ivtv-queue.c
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 */
23
24#include "cx18-driver.h"
25#include "cx18-streams.h"
26#include "cx18-queue.h"
27#include "cx18-scb.h"
28
29int cx18_buf_copy_from_user(struct cx18_stream *s, struct cx18_buffer *buf,
30 const char __user *src, int copybytes)
31{
32 if (s->buf_size - buf->bytesused < copybytes)
33 copybytes = s->buf_size - buf->bytesused;
34 if (copy_from_user(buf->buf + buf->bytesused, src, copybytes))
35 return -EFAULT;
36 buf->bytesused += copybytes;
37 return copybytes;
38}
39
40void cx18_buf_swap(struct cx18_buffer *buf)
41{
42 int i;
43
44 for (i = 0; i < buf->bytesused; i += 4)
45 swab32s((u32 *)(buf->buf + i));
46}
47
48void cx18_queue_init(struct cx18_queue *q)
49{
50 INIT_LIST_HEAD(&q->list);
51 q->buffers = 0;
52 q->length = 0;
53 q->bytesused = 0;
54}
55
56void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
57 struct cx18_queue *q)
58{
59 unsigned long flags = 0;
60
61 /* clear the buffer if it is going to be enqueued to the free queue */
62 if (q == &s->q_free) {
63 buf->bytesused = 0;
64 buf->readpos = 0;
65 buf->b_flags = 0;
66 }
67 spin_lock_irqsave(&s->qlock, flags);
68 list_add_tail(&buf->list, &q->list);
69 q->buffers++;
70 q->length += s->buf_size;
71 q->bytesused += buf->bytesused - buf->readpos;
72 spin_unlock_irqrestore(&s->qlock, flags);
73}
74
75struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q)
76{
77 struct cx18_buffer *buf = NULL;
78 unsigned long flags = 0;
79
80 spin_lock_irqsave(&s->qlock, flags);
81 if (!list_empty(&q->list)) {
82 buf = list_entry(q->list.next, struct cx18_buffer, list);
83 list_del_init(q->list.next);
84 q->buffers--;
85 q->length -= s->buf_size;
86 q->bytesused -= buf->bytesused - buf->readpos;
87 }
88 spin_unlock_irqrestore(&s->qlock, flags);
89 return buf;
90}
91
92struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id,
93 u32 bytesused)
94{
95 struct cx18 *cx = s->cx;
96 struct list_head *p;
97
98 list_for_each(p, &s->q_free.list) {
99 struct cx18_buffer *buf =
100 list_entry(p, struct cx18_buffer, list);
101
102 if (buf->id != id)
103 continue;
104 buf->bytesused = bytesused;
105 /* the transport buffers are handled differently,
106 so there is no need to move them to the full queue */
107 if (s->type == CX18_ENC_STREAM_TYPE_TS)
108 return buf;
109 s->q_free.buffers--;
110 s->q_free.length -= s->buf_size;
111 s->q_full.buffers++;
112 s->q_full.length += s->buf_size;
113 s->q_full.bytesused += buf->bytesused;
114 list_move_tail(&buf->list, &s->q_full.list);
115 return buf;
116 }
117 CX18_ERR("Cannot find buffer %d for stream %s\n", id, s->name);
118 return NULL;
119}
120
121static void cx18_queue_move_buf(struct cx18_stream *s, struct cx18_queue *from,
122 struct cx18_queue *to, int clear, int full)
123{
124 struct cx18_buffer *buf =
125 list_entry(from->list.next, struct cx18_buffer, list);
126
127 list_move_tail(from->list.next, &to->list);
128 from->buffers--;
129 from->length -= s->buf_size;
130 from->bytesused -= buf->bytesused - buf->readpos;
131 /* special handling for q_free */
132 if (clear)
133 buf->bytesused = buf->readpos = buf->b_flags = 0;
134 else if (full) {
135 /* special handling for stolen buffers, assume
136 all bytes are used. */
137 buf->bytesused = s->buf_size;
138 buf->readpos = buf->b_flags = 0;
139 }
140 to->buffers++;
141 to->length += s->buf_size;
142 to->bytesused += buf->bytesused - buf->readpos;
143}
144
145/* Move 'needed_bytes' worth of buffers from queue 'from' into queue 'to'.
146 If 'needed_bytes' == 0, then move all buffers from 'from' into 'to'.
147 If 'steal' != NULL, then buffers may also taken from that queue if
148 needed.
149
150 The buffer is automatically cleared if it goes to the free queue. It is
151 also cleared if buffers need to be taken from the 'steal' queue and
152 the 'from' queue is the free queue.
153
154 When 'from' is q_free, then needed_bytes is compared to the total
155 available buffer length, otherwise needed_bytes is compared to the
156 bytesused value. For the 'steal' queue the total available buffer
157 length is always used.
158
159 -ENOMEM is returned if the buffers could not be obtained, 0 if all
160 buffers where obtained from the 'from' list and if non-zero then
161 the number of stolen buffers is returned. */
162int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from,
163 struct cx18_queue *steal, struct cx18_queue *to, int needed_bytes)
164{
165 unsigned long flags;
166 int rc = 0;
167 int from_free = from == &s->q_free;
168 int to_free = to == &s->q_free;
169 int bytes_available;
170
171 spin_lock_irqsave(&s->qlock, flags);
172 if (needed_bytes == 0) {
173 from_free = 1;
174 needed_bytes = from->length;
175 }
176
177 bytes_available = from_free ? from->length : from->bytesused;
178 bytes_available += steal ? steal->length : 0;
179
180 if (bytes_available < needed_bytes) {
181 spin_unlock_irqrestore(&s->qlock, flags);
182 return -ENOMEM;
183 }
184 if (from_free) {
185 u32 old_length = to->length;
186
187 while (to->length - old_length < needed_bytes) {
188 if (list_empty(&from->list))
189 from = steal;
190 if (from == steal)
191 rc++; /* keep track of 'stolen' buffers */
192 cx18_queue_move_buf(s, from, to, 1, 0);
193 }
194 } else {
195 u32 old_bytesused = to->bytesused;
196
197 while (to->bytesused - old_bytesused < needed_bytes) {
198 if (list_empty(&from->list))
199 from = steal;
200 if (from == steal)
201 rc++; /* keep track of 'stolen' buffers */
202 cx18_queue_move_buf(s, from, to, to_free, rc);
203 }
204 }
205 spin_unlock_irqrestore(&s->qlock, flags);
206 return rc;
207}
208
209void cx18_flush_queues(struct cx18_stream *s)
210{
211 cx18_queue_move(s, &s->q_io, NULL, &s->q_free, 0);
212 cx18_queue_move(s, &s->q_full, NULL, &s->q_free, 0);
213}
214
215int cx18_stream_alloc(struct cx18_stream *s)
216{
217 struct cx18 *cx = s->cx;
218 int i;
219
220 if (s->buffers == 0)
221 return 0;
222
223 CX18_DEBUG_INFO("Allocate %s stream: %d x %d buffers (%dkB total)\n",
224 s->name, s->buffers, s->buf_size,
225 s->buffers * s->buf_size / 1024);
226
227 if (((char *)&cx->scb->cpu_mdl[cx->mdl_offset + s->buffers] -
228 (char *)cx->scb) > SCB_RESERVED_SIZE) {
229 unsigned bufsz = (((char *)cx->scb) + SCB_RESERVED_SIZE -
230 ((char *)cx->scb->cpu_mdl));
231
232 CX18_ERR("Too many buffers, cannot fit in SCB area\n");
233 CX18_ERR("Max buffers = %zd\n",
234 bufsz / sizeof(struct cx18_mdl));
235 return -ENOMEM;
236 }
237
238 s->mdl_offset = cx->mdl_offset;
239
240 /* allocate stream buffers. Initially all buffers are in q_free. */
241 for (i = 0; i < s->buffers; i++) {
242 struct cx18_buffer *buf =
243 kzalloc(sizeof(struct cx18_buffer), GFP_KERNEL);
244
245 if (buf == NULL)
246 break;
247 buf->buf = kmalloc(s->buf_size, GFP_KERNEL);
248 if (buf->buf == NULL) {
249 kfree(buf);
250 break;
251 }
252 buf->id = cx->buffer_id++;
253 INIT_LIST_HEAD(&buf->list);
254 buf->dma_handle = pci_map_single(s->cx->dev,
255 buf->buf, s->buf_size, s->dma);
256 cx18_buf_sync_for_cpu(s, buf);
257 cx18_enqueue(s, buf, &s->q_free);
258 }
259 if (i == s->buffers) {
260 cx->mdl_offset += s->buffers;
261 return 0;
262 }
263 CX18_ERR("Couldn't allocate buffers for %s stream\n", s->name);
264 cx18_stream_free(s);
265 return -ENOMEM;
266}
267
268void cx18_stream_free(struct cx18_stream *s)
269{
270 struct cx18_buffer *buf;
271
272 /* move all buffers to q_free */
273 cx18_flush_queues(s);
274
275 /* empty q_free */
276 while ((buf = cx18_dequeue(s, &s->q_free))) {
277 pci_unmap_single(s->cx->dev, buf->dma_handle,
278 s->buf_size, s->dma);
279 kfree(buf->buf);
280 kfree(buf);
281 }
282}
diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h
new file mode 100644
index 000000000000..f86c8a6fa6e7
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-queue.h
@@ -0,0 +1,59 @@
1/*
2 * cx18 buffer queues
3 *
4 * Derived from ivtv-queue.h
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 */
23
24#define CX18_DMA_UNMAPPED ((u32) -1)
25
26/* cx18_buffer utility functions */
27
28static inline void cx18_buf_sync_for_cpu(struct cx18_stream *s,
29 struct cx18_buffer *buf)
30{
31 pci_dma_sync_single_for_cpu(s->cx->dev, buf->dma_handle,
32 s->buf_size, s->dma);
33}
34
35static inline void cx18_buf_sync_for_device(struct cx18_stream *s,
36 struct cx18_buffer *buf)
37{
38 pci_dma_sync_single_for_device(s->cx->dev, buf->dma_handle,
39 s->buf_size, s->dma);
40}
41
42int cx18_buf_copy_from_user(struct cx18_stream *s, struct cx18_buffer *buf,
43 const char __user *src, int copybytes);
44void cx18_buf_swap(struct cx18_buffer *buf);
45
46/* cx18_queue utility functions */
47void cx18_queue_init(struct cx18_queue *q);
48void cx18_enqueue(struct cx18_stream *s, struct cx18_buffer *buf,
49 struct cx18_queue *q);
50struct cx18_buffer *cx18_dequeue(struct cx18_stream *s, struct cx18_queue *q);
51int cx18_queue_move(struct cx18_stream *s, struct cx18_queue *from,
52 struct cx18_queue *steal, struct cx18_queue *to, int needed_bytes);
53struct cx18_buffer *cx18_queue_find_buf(struct cx18_stream *s, u32 id,
54 u32 bytesused);
55void cx18_flush_queues(struct cx18_stream *s);
56
57/* cx18_stream utility functions */
58int cx18_stream_alloc(struct cx18_stream *s);
59void cx18_stream_free(struct cx18_stream *s);
diff --git a/drivers/media/video/cx18/cx18-scb.c b/drivers/media/video/cx18/cx18-scb.c
new file mode 100644
index 000000000000..30bc803e30da
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-scb.c
@@ -0,0 +1,121 @@
1/*
2 * cx18 System Control Block initialization
3 *
4 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 * 02111-1307 USA
20 */
21
22#include "cx18-driver.h"
23#include "cx18-scb.h"
24
25void cx18_init_scb(struct cx18 *cx)
26{
27 setup_page(SCB_OFFSET);
28 memset_io(cx->scb, 0, 0x10000);
29
30 writel(IRQ_APU_TO_CPU, &cx->scb->apu2cpu_irq);
31 writel(IRQ_CPU_TO_APU_ACK, &cx->scb->cpu2apu_irq_ack);
32 writel(IRQ_HPU_TO_CPU, &cx->scb->hpu2cpu_irq);
33 writel(IRQ_CPU_TO_HPU_ACK, &cx->scb->cpu2hpu_irq_ack);
34 writel(IRQ_PPU_TO_CPU, &cx->scb->ppu2cpu_irq);
35 writel(IRQ_CPU_TO_PPU_ACK, &cx->scb->cpu2ppu_irq_ack);
36 writel(IRQ_EPU_TO_CPU, &cx->scb->epu2cpu_irq);
37 writel(IRQ_CPU_TO_EPU_ACK, &cx->scb->cpu2epu_irq_ack);
38
39 writel(IRQ_CPU_TO_APU, &cx->scb->cpu2apu_irq);
40 writel(IRQ_APU_TO_CPU_ACK, &cx->scb->apu2cpu_irq_ack);
41 writel(IRQ_HPU_TO_APU, &cx->scb->hpu2apu_irq);
42 writel(IRQ_APU_TO_HPU_ACK, &cx->scb->apu2hpu_irq_ack);
43 writel(IRQ_PPU_TO_APU, &cx->scb->ppu2apu_irq);
44 writel(IRQ_APU_TO_PPU_ACK, &cx->scb->apu2ppu_irq_ack);
45 writel(IRQ_EPU_TO_APU, &cx->scb->epu2apu_irq);
46 writel(IRQ_APU_TO_EPU_ACK, &cx->scb->apu2epu_irq_ack);
47
48 writel(IRQ_CPU_TO_HPU, &cx->scb->cpu2hpu_irq);
49 writel(IRQ_HPU_TO_CPU_ACK, &cx->scb->hpu2cpu_irq_ack);
50 writel(IRQ_APU_TO_HPU, &cx->scb->apu2hpu_irq);
51 writel(IRQ_HPU_TO_APU_ACK, &cx->scb->hpu2apu_irq_ack);
52 writel(IRQ_PPU_TO_HPU, &cx->scb->ppu2hpu_irq);
53 writel(IRQ_HPU_TO_PPU_ACK, &cx->scb->hpu2ppu_irq_ack);
54 writel(IRQ_EPU_TO_HPU, &cx->scb->epu2hpu_irq);
55 writel(IRQ_HPU_TO_EPU_ACK, &cx->scb->hpu2epu_irq_ack);
56
57 writel(IRQ_CPU_TO_PPU, &cx->scb->cpu2ppu_irq);
58 writel(IRQ_PPU_TO_CPU_ACK, &cx->scb->ppu2cpu_irq_ack);
59 writel(IRQ_APU_TO_PPU, &cx->scb->apu2ppu_irq);
60 writel(IRQ_PPU_TO_APU_ACK, &cx->scb->ppu2apu_irq_ack);
61 writel(IRQ_HPU_TO_PPU, &cx->scb->hpu2ppu_irq);
62 writel(IRQ_PPU_TO_HPU_ACK, &cx->scb->ppu2hpu_irq_ack);
63 writel(IRQ_EPU_TO_PPU, &cx->scb->epu2ppu_irq);
64 writel(IRQ_PPU_TO_EPU_ACK, &cx->scb->ppu2epu_irq_ack);
65
66 writel(IRQ_CPU_TO_EPU, &cx->scb->cpu2epu_irq);
67 writel(IRQ_EPU_TO_CPU_ACK, &cx->scb->epu2cpu_irq_ack);
68 writel(IRQ_APU_TO_EPU, &cx->scb->apu2epu_irq);
69 writel(IRQ_EPU_TO_APU_ACK, &cx->scb->epu2apu_irq_ack);
70 writel(IRQ_HPU_TO_EPU, &cx->scb->hpu2epu_irq);
71 writel(IRQ_EPU_TO_HPU_ACK, &cx->scb->epu2hpu_irq_ack);
72 writel(IRQ_PPU_TO_EPU, &cx->scb->ppu2epu_irq);
73 writel(IRQ_EPU_TO_PPU_ACK, &cx->scb->epu2ppu_irq_ack);
74
75 writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2cpu_mb),
76 &cx->scb->apu2cpu_mb_offset);
77 writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2cpu_mb),
78 &cx->scb->hpu2cpu_mb_offset);
79 writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2cpu_mb),
80 &cx->scb->ppu2cpu_mb_offset);
81 writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2cpu_mb),
82 &cx->scb->epu2cpu_mb_offset);
83 writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2apu_mb),
84 &cx->scb->cpu2apu_mb_offset);
85 writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2apu_mb),
86 &cx->scb->hpu2apu_mb_offset);
87 writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2apu_mb),
88 &cx->scb->ppu2apu_mb_offset);
89 writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2apu_mb),
90 &cx->scb->epu2apu_mb_offset);
91 writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2hpu_mb),
92 &cx->scb->cpu2hpu_mb_offset);
93 writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2hpu_mb),
94 &cx->scb->apu2hpu_mb_offset);
95 writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2hpu_mb),
96 &cx->scb->ppu2hpu_mb_offset);
97 writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2hpu_mb),
98 &cx->scb->epu2hpu_mb_offset);
99 writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2ppu_mb),
100 &cx->scb->cpu2ppu_mb_offset);
101 writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2ppu_mb),
102 &cx->scb->apu2ppu_mb_offset);
103 writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2ppu_mb),
104 &cx->scb->hpu2ppu_mb_offset);
105 writel(SCB_OFFSET + offsetof(struct cx18_scb, epu2ppu_mb),
106 &cx->scb->epu2ppu_mb_offset);
107 writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu2epu_mb),
108 &cx->scb->cpu2epu_mb_offset);
109 writel(SCB_OFFSET + offsetof(struct cx18_scb, apu2epu_mb),
110 &cx->scb->apu2epu_mb_offset);
111 writel(SCB_OFFSET + offsetof(struct cx18_scb, hpu2epu_mb),
112 &cx->scb->hpu2epu_mb_offset);
113 writel(SCB_OFFSET + offsetof(struct cx18_scb, ppu2epu_mb),
114 &cx->scb->ppu2epu_mb_offset);
115
116 writel(SCB_OFFSET + offsetof(struct cx18_scb, cpu_state),
117 &cx->scb->ipc_offset);
118
119 writel(1, &cx->scb->hpu_state);
120 writel(1, &cx->scb->epu_state);
121}
diff --git a/drivers/media/video/cx18/cx18-scb.h b/drivers/media/video/cx18/cx18-scb.h
new file mode 100644
index 000000000000..86b4cb15d163
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-scb.h
@@ -0,0 +1,285 @@
1/*
2 * cx18 System Control Block initialization
3 *
4 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 * 02111-1307 USA
20 */
21
22#ifndef CX18_SCB_H
23#define CX18_SCB_H
24
25#include "cx18-mailbox.h"
26
27/* NOTE: All ACK interrupts are in the SW2 register. All non-ACK interrupts
28 are in the SW1 register. */
29
30#define IRQ_APU_TO_CPU 0x00000001
31#define IRQ_CPU_TO_APU_ACK 0x00000001
32#define IRQ_HPU_TO_CPU 0x00000002
33#define IRQ_CPU_TO_HPU_ACK 0x00000002
34#define IRQ_PPU_TO_CPU 0x00000004
35#define IRQ_CPU_TO_PPU_ACK 0x00000004
36#define IRQ_EPU_TO_CPU 0x00000008
37#define IRQ_CPU_TO_EPU_ACK 0x00000008
38
39#define IRQ_CPU_TO_APU 0x00000010
40#define IRQ_APU_TO_CPU_ACK 0x00000010
41#define IRQ_HPU_TO_APU 0x00000020
42#define IRQ_APU_TO_HPU_ACK 0x00000020
43#define IRQ_PPU_TO_APU 0x00000040
44#define IRQ_APU_TO_PPU_ACK 0x00000040
45#define IRQ_EPU_TO_APU 0x00000080
46#define IRQ_APU_TO_EPU_ACK 0x00000080
47
48#define IRQ_CPU_TO_HPU 0x00000100
49#define IRQ_HPU_TO_CPU_ACK 0x00000100
50#define IRQ_APU_TO_HPU 0x00000200
51#define IRQ_HPU_TO_APU_ACK 0x00000200
52#define IRQ_PPU_TO_HPU 0x00000400
53#define IRQ_HPU_TO_PPU_ACK 0x00000400
54#define IRQ_EPU_TO_HPU 0x00000800
55#define IRQ_HPU_TO_EPU_ACK 0x00000800
56
57#define IRQ_CPU_TO_PPU 0x00001000
58#define IRQ_PPU_TO_CPU_ACK 0x00001000
59#define IRQ_APU_TO_PPU 0x00002000
60#define IRQ_PPU_TO_APU_ACK 0x00002000
61#define IRQ_HPU_TO_PPU 0x00004000
62#define IRQ_PPU_TO_HPU_ACK 0x00004000
63#define IRQ_EPU_TO_PPU 0x00008000
64#define IRQ_PPU_TO_EPU_ACK 0x00008000
65
66#define IRQ_CPU_TO_EPU 0x00010000
67#define IRQ_EPU_TO_CPU_ACK 0x00010000
68#define IRQ_APU_TO_EPU 0x00020000
69#define IRQ_EPU_TO_APU_ACK 0x00020000
70#define IRQ_HPU_TO_EPU 0x00040000
71#define IRQ_EPU_TO_HPU_ACK 0x00040000
72#define IRQ_PPU_TO_EPU 0x00080000
73#define IRQ_EPU_TO_PPU_ACK 0x00080000
74
75#define SCB_OFFSET 0xDC0000
76
77/* If Firmware uses fixed memory map, it shall not allocate the area
78 between SCB_OFFSET and SCB_OFFSET+SCB_RESERVED_SIZE-1 inclusive */
79#define SCB_RESERVED_SIZE 0x10000
80
81
82/* This structure is used by EPU to provide memory descriptors in its memory */
83struct cx18_mdl {
84 u32 paddr; /* Physical address of a buffer segment */
85 u32 length; /* Length of the buffer segment */
86};
87
88/* This structure is used by CPU to provide completed buffers information */
89struct cx18_mdl_ack {
90 u32 id; /* ID of a completed MDL */
91 u32 data_used; /* Total data filled in the MDL for buffer 'id' */
92};
93
94struct cx18_scb {
95 /* These fields form the System Control Block which is used at boot time
96 for localizing the IPC data as well as the code positions for all
97 processors. The offsets are from the start of this struct. */
98
99 /* Offset where to find the Inter-Processor Communication data */
100 u32 ipc_offset;
101 u32 reserved01[7];
102 /* Offset where to find the start of the CPU code */
103 u32 cpu_code_offset;
104 u32 reserved02[3];
105 /* Offset where to find the start of the APU code */
106 u32 apu_code_offset;
107 u32 reserved03[3];
108 /* Offset where to find the start of the HPU code */
109 u32 hpu_code_offset;
110 u32 reserved04[3];
111 /* Offset where to find the start of the PPU code */
112 u32 ppu_code_offset;
113 u32 reserved05[3];
114
115 /* These fields form Inter-Processor Communication data which is used
116 by all processors to locate the information needed for communicating
117 with other processors */
118
119 /* Fields for CPU: */
120
121 /* bit 0: 1/0 processor ready/not ready. Set other bits to 0. */
122 u32 cpu_state;
123 u32 reserved1[7];
124 /* Offset to the mailbox used for sending commands from APU to CPU */
125 u32 apu2cpu_mb_offset;
126 /* Value to write to register SW1 register set (0xC7003100) after the
127 command is ready */
128 u32 apu2cpu_irq;
129 /* Value to write to register SW2 register set (0xC7003140) after the
130 command is cleared */
131 u32 apu2cpu_irq_ack;
132 u32 reserved2[13];
133
134 u32 hpu2cpu_mb_offset;
135 u32 hpu2cpu_irq;
136 u32 hpu2cpu_irq_ack;
137 u32 reserved3[13];
138
139 u32 ppu2cpu_mb_offset;
140 u32 ppu2cpu_irq;
141 u32 ppu2cpu_irq_ack;
142 u32 reserved4[13];
143
144 u32 epu2cpu_mb_offset;
145 u32 epu2cpu_irq;
146 u32 epu2cpu_irq_ack;
147 u32 reserved5[13];
148 u32 reserved6[8];
149
150 /* Fields for APU: */
151
152 u32 apu_state;
153 u32 reserved11[7];
154 u32 cpu2apu_mb_offset;
155 u32 cpu2apu_irq;
156 u32 cpu2apu_irq_ack;
157 u32 reserved12[13];
158
159 u32 hpu2apu_mb_offset;
160 u32 hpu2apu_irq;
161 u32 hpu2apu_irq_ack;
162 u32 reserved13[13];
163
164 u32 ppu2apu_mb_offset;
165 u32 ppu2apu_irq;
166 u32 ppu2apu_irq_ack;
167 u32 reserved14[13];
168
169 u32 epu2apu_mb_offset;
170 u32 epu2apu_irq;
171 u32 epu2apu_irq_ack;
172 u32 reserved15[13];
173 u32 reserved16[8];
174
175 /* Fields for HPU: */
176
177 u32 hpu_state;
178 u32 reserved21[7];
179 u32 cpu2hpu_mb_offset;
180 u32 cpu2hpu_irq;
181 u32 cpu2hpu_irq_ack;
182 u32 reserved22[13];
183
184 u32 apu2hpu_mb_offset;
185 u32 apu2hpu_irq;
186 u32 apu2hpu_irq_ack;
187 u32 reserved23[13];
188
189 u32 ppu2hpu_mb_offset;
190 u32 ppu2hpu_irq;
191 u32 ppu2hpu_irq_ack;
192 u32 reserved24[13];
193
194 u32 epu2hpu_mb_offset;
195 u32 epu2hpu_irq;
196 u32 epu2hpu_irq_ack;
197 u32 reserved25[13];
198 u32 reserved26[8];
199
200 /* Fields for PPU: */
201
202 u32 ppu_state;
203 u32 reserved31[7];
204 u32 cpu2ppu_mb_offset;
205 u32 cpu2ppu_irq;
206 u32 cpu2ppu_irq_ack;
207 u32 reserved32[13];
208
209 u32 apu2ppu_mb_offset;
210 u32 apu2ppu_irq;
211 u32 apu2ppu_irq_ack;
212 u32 reserved33[13];
213
214 u32 hpu2ppu_mb_offset;
215 u32 hpu2ppu_irq;
216 u32 hpu2ppu_irq_ack;
217 u32 reserved34[13];
218
219 u32 epu2ppu_mb_offset;
220 u32 epu2ppu_irq;
221 u32 epu2ppu_irq_ack;
222 u32 reserved35[13];
223 u32 reserved36[8];
224
225 /* Fields for EPU: */
226
227 u32 epu_state;
228 u32 reserved41[7];
229 u32 cpu2epu_mb_offset;
230 u32 cpu2epu_irq;
231 u32 cpu2epu_irq_ack;
232 u32 reserved42[13];
233
234 u32 apu2epu_mb_offset;
235 u32 apu2epu_irq;
236 u32 apu2epu_irq_ack;
237 u32 reserved43[13];
238
239 u32 hpu2epu_mb_offset;
240 u32 hpu2epu_irq;
241 u32 hpu2epu_irq_ack;
242 u32 reserved44[13];
243
244 u32 ppu2epu_mb_offset;
245 u32 ppu2epu_irq;
246 u32 ppu2epu_irq_ack;
247 u32 reserved45[13];
248 u32 reserved46[8];
249
250 u32 semaphores[8]; /* Semaphores */
251
252 u32 reserved50[32]; /* Reserved for future use */
253
254 struct cx18_mailbox apu2cpu_mb;
255 struct cx18_mailbox hpu2cpu_mb;
256 struct cx18_mailbox ppu2cpu_mb;
257 struct cx18_mailbox epu2cpu_mb;
258
259 struct cx18_mailbox cpu2apu_mb;
260 struct cx18_mailbox hpu2apu_mb;
261 struct cx18_mailbox ppu2apu_mb;
262 struct cx18_mailbox epu2apu_mb;
263
264 struct cx18_mailbox cpu2hpu_mb;
265 struct cx18_mailbox apu2hpu_mb;
266 struct cx18_mailbox ppu2hpu_mb;
267 struct cx18_mailbox epu2hpu_mb;
268
269 struct cx18_mailbox cpu2ppu_mb;
270 struct cx18_mailbox apu2ppu_mb;
271 struct cx18_mailbox hpu2ppu_mb;
272 struct cx18_mailbox epu2ppu_mb;
273
274 struct cx18_mailbox cpu2epu_mb;
275 struct cx18_mailbox apu2epu_mb;
276 struct cx18_mailbox hpu2epu_mb;
277 struct cx18_mailbox ppu2epu_mb;
278
279 struct cx18_mdl_ack cpu_mdl_ack[CX18_MAX_STREAMS][2];
280 struct cx18_mdl cpu_mdl[1];
281};
282
283void cx18_init_scb(struct cx18 *cx);
284
285#endif
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
new file mode 100644
index 000000000000..afb141b2027a
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -0,0 +1,566 @@
1/*
2 * cx18 init/start/stop/exit stream functions
3 *
4 * Derived from ivtv-streams.c
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 */
23
24#include "cx18-driver.h"
25#include "cx18-fileops.h"
26#include "cx18-mailbox.h"
27#include "cx18-i2c.h"
28#include "cx18-queue.h"
29#include "cx18-ioctl.h"
30#include "cx18-streams.h"
31#include "cx18-cards.h"
32#include "cx18-scb.h"
33#include "cx18-av-core.h"
34#include "cx18-dvb.h"
35
36#define CX18_DSP0_INTERRUPT_MASK 0xd0004C
37
38static struct file_operations cx18_v4l2_enc_fops = {
39 .owner = THIS_MODULE,
40 .read = cx18_v4l2_read,
41 .open = cx18_v4l2_open,
42 .ioctl = cx18_v4l2_ioctl,
43 .release = cx18_v4l2_close,
44 .poll = cx18_v4l2_enc_poll,
45};
46
47/* offset from 0 to register ts v4l2 minors on */
48#define CX18_V4L2_ENC_TS_OFFSET 16
49/* offset from 0 to register pcm v4l2 minors on */
50#define CX18_V4L2_ENC_PCM_OFFSET 24
51/* offset from 0 to register yuv v4l2 minors on */
52#define CX18_V4L2_ENC_YUV_OFFSET 32
53
54static struct {
55 const char *name;
56 int vfl_type;
57 int minor_offset;
58 int dma;
59 enum v4l2_buf_type buf_type;
60 struct file_operations *fops;
61} cx18_stream_info[] = {
62 { /* CX18_ENC_STREAM_TYPE_MPG */
63 "encoder MPEG",
64 VFL_TYPE_GRABBER, 0,
65 PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
66 &cx18_v4l2_enc_fops
67 },
68 { /* CX18_ENC_STREAM_TYPE_TS */
69 "TS",
70 VFL_TYPE_GRABBER, -1,
71 PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
72 &cx18_v4l2_enc_fops
73 },
74 { /* CX18_ENC_STREAM_TYPE_YUV */
75 "encoder YUV",
76 VFL_TYPE_GRABBER, CX18_V4L2_ENC_YUV_OFFSET,
77 PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
78 &cx18_v4l2_enc_fops
79 },
80 { /* CX18_ENC_STREAM_TYPE_VBI */
81 "encoder VBI",
82 VFL_TYPE_VBI, 0,
83 PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VBI_CAPTURE,
84 &cx18_v4l2_enc_fops
85 },
86 { /* CX18_ENC_STREAM_TYPE_PCM */
87 "encoder PCM audio",
88 VFL_TYPE_GRABBER, CX18_V4L2_ENC_PCM_OFFSET,
89 PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_PRIVATE,
90 &cx18_v4l2_enc_fops
91 },
92 { /* CX18_ENC_STREAM_TYPE_IDX */
93 "encoder IDX",
94 VFL_TYPE_GRABBER, -1,
95 PCI_DMA_FROMDEVICE, V4L2_BUF_TYPE_VIDEO_CAPTURE,
96 &cx18_v4l2_enc_fops
97 },
98 { /* CX18_ENC_STREAM_TYPE_RAD */
99 "encoder radio",
100 VFL_TYPE_RADIO, 0,
101 PCI_DMA_NONE, V4L2_BUF_TYPE_PRIVATE,
102 &cx18_v4l2_enc_fops
103 },
104};
105
106static void cx18_stream_init(struct cx18 *cx, int type)
107{
108 struct cx18_stream *s = &cx->streams[type];
109 struct video_device *dev = s->v4l2dev;
110 u32 max_size = cx->options.megabytes[type] * 1024 * 1024;
111
112 /* we need to keep v4l2dev, so restore it afterwards */
113 memset(s, 0, sizeof(*s));
114 s->v4l2dev = dev;
115
116 /* initialize cx18_stream fields */
117 s->cx = cx;
118 s->type = type;
119 s->name = cx18_stream_info[type].name;
120 s->handle = 0xffffffff;
121
122 s->dma = cx18_stream_info[type].dma;
123 s->buf_size = cx->stream_buf_size[type];
124 if (s->buf_size)
125 s->buffers = max_size / s->buf_size;
126 if (s->buffers > 63) {
127 /* Each stream has a maximum of 63 buffers,
128 ensure we do not exceed that. */
129 s->buffers = 63;
130 s->buf_size = (max_size / s->buffers) & ~0xfff;
131 }
132 spin_lock_init(&s->qlock);
133 init_waitqueue_head(&s->waitq);
134 s->id = -1;
135 cx18_queue_init(&s->q_free);
136 cx18_queue_init(&s->q_full);
137 cx18_queue_init(&s->q_io);
138}
139
140static int cx18_prep_dev(struct cx18 *cx, int type)
141{
142 struct cx18_stream *s = &cx->streams[type];
143 u32 cap = cx->v4l2_cap;
144 int minor_offset = cx18_stream_info[type].minor_offset;
145 int minor;
146
147 /* These four fields are always initialized. If v4l2dev == NULL, then
148 this stream is not in use. In that case no other fields but these
149 four can be used. */
150 s->v4l2dev = NULL;
151 s->cx = cx;
152 s->type = type;
153 s->name = cx18_stream_info[type].name;
154
155 /* Check whether the radio is supported */
156 if (type == CX18_ENC_STREAM_TYPE_RAD && !(cap & V4L2_CAP_RADIO))
157 return 0;
158
159 /* Check whether VBI is supported */
160 if (type == CX18_ENC_STREAM_TYPE_VBI &&
161 !(cap & (V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE)))
162 return 0;
163
164 /* card number + user defined offset + device offset */
165 minor = cx->num + cx18_first_minor + minor_offset;
166
167 /* User explicitly selected 0 buffers for these streams, so don't
168 create them. */
169 if (cx18_stream_info[type].dma != PCI_DMA_NONE &&
170 cx->options.megabytes[type] == 0) {
171 CX18_INFO("Disabled %s device\n", cx18_stream_info[type].name);
172 return 0;
173 }
174
175 cx18_stream_init(cx, type);
176
177 if (minor_offset == -1)
178 return 0;
179
180 /* allocate and initialize the v4l2 video device structure */
181 s->v4l2dev = video_device_alloc();
182 if (s->v4l2dev == NULL) {
183 CX18_ERR("Couldn't allocate v4l2 video_device for %s\n",
184 s->name);
185 return -ENOMEM;
186 }
187
188 s->v4l2dev->type =
189 VID_TYPE_CAPTURE | VID_TYPE_TUNER | VID_TYPE_TELETEXT |
190 VID_TYPE_CLIPPING | VID_TYPE_SCALES | VID_TYPE_MPEG_ENCODER;
191 snprintf(s->v4l2dev->name, sizeof(s->v4l2dev->name), "cx18%d %s",
192 cx->num, s->name);
193
194 s->v4l2dev->minor = minor;
195 s->v4l2dev->dev = &cx->dev->dev;
196 s->v4l2dev->fops = cx18_stream_info[type].fops;
197 s->v4l2dev->release = video_device_release;
198
199 return 0;
200}
201
202/* Initialize v4l2 variables and register v4l2 devices */
203int cx18_streams_setup(struct cx18 *cx)
204{
205 int type;
206
207 /* Setup V4L2 Devices */
208 for (type = 0; type < CX18_MAX_STREAMS; type++) {
209 /* Prepare device */
210 if (cx18_prep_dev(cx, type))
211 break;
212
213 /* Allocate Stream */
214 if (cx18_stream_alloc(&cx->streams[type]))
215 break;
216 }
217 if (type == CX18_MAX_STREAMS)
218 return 0;
219
220 /* One or more streams could not be initialized. Clean 'em all up. */
221 cx18_streams_cleanup(cx);
222 return -ENOMEM;
223}
224
225static int cx18_reg_dev(struct cx18 *cx, int type)
226{
227 struct cx18_stream *s = &cx->streams[type];
228 int vfl_type = cx18_stream_info[type].vfl_type;
229 int minor;
230
231 /* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something?
232 * We need a VFL_TYPE_TS defined.
233 */
234 if (strcmp("TS", s->name) == 0) {
235 /* just return if no DVB is supported */
236 if ((cx->card->hw_all & CX18_HW_DVB) == 0)
237 return 0;
238 if (cx18_dvb_register(s) < 0) {
239 CX18_ERR("DVB failed to register\n");
240 return -EINVAL;
241 }
242 }
243
244 if (s->v4l2dev == NULL)
245 return 0;
246
247 minor = s->v4l2dev->minor;
248
249 /* Register device. First try the desired minor, then any free one. */
250 if (video_register_device(s->v4l2dev, vfl_type, minor) &&
251 video_register_device(s->v4l2dev, vfl_type, -1)) {
252 CX18_ERR("Couldn't register v4l2 device for %s minor %d\n",
253 s->name, minor);
254 video_device_release(s->v4l2dev);
255 s->v4l2dev = NULL;
256 return -ENOMEM;
257 }
258 minor = s->v4l2dev->minor;
259
260 switch (vfl_type) {
261 case VFL_TYPE_GRABBER:
262 CX18_INFO("Registered device video%d for %s (%d MB)\n",
263 minor, s->name, cx->options.megabytes[type]);
264 break;
265
266 case VFL_TYPE_RADIO:
267 CX18_INFO("Registered device radio%d for %s\n",
268 minor - MINOR_VFL_TYPE_RADIO_MIN, s->name);
269 break;
270
271 case VFL_TYPE_VBI:
272 if (cx->options.megabytes[type])
273 CX18_INFO("Registered device vbi%d for %s (%d MB)\n",
274 minor - MINOR_VFL_TYPE_VBI_MIN,
275 s->name, cx->options.megabytes[type]);
276 else
277 CX18_INFO("Registered device vbi%d for %s\n",
278 minor - MINOR_VFL_TYPE_VBI_MIN, s->name);
279 break;
280 }
281
282 return 0;
283}
284
285/* Register v4l2 devices */
286int cx18_streams_register(struct cx18 *cx)
287{
288 int type;
289 int err = 0;
290
291 /* Register V4L2 devices */
292 for (type = 0; type < CX18_MAX_STREAMS; type++)
293 err |= cx18_reg_dev(cx, type);
294
295 if (err == 0)
296 return 0;
297
298 /* One or more streams could not be initialized. Clean 'em all up. */
299 cx18_streams_cleanup(cx);
300 return -ENOMEM;
301}
302
303/* Unregister v4l2 devices */
304void cx18_streams_cleanup(struct cx18 *cx)
305{
306 struct video_device *vdev;
307 int type;
308
309 /* Teardown all streams */
310 for (type = 0; type < CX18_MAX_STREAMS; type++) {
311 if (cx->streams[type].dvb.enabled)
312 cx18_dvb_unregister(&cx->streams[type]);
313
314 vdev = cx->streams[type].v4l2dev;
315
316 cx->streams[type].v4l2dev = NULL;
317 if (vdev == NULL)
318 continue;
319
320 cx18_stream_free(&cx->streams[type]);
321
322 /* Unregister device */
323 video_unregister_device(vdev);
324 }
325}
326
327static void cx18_vbi_setup(struct cx18_stream *s)
328{
329 struct cx18 *cx = s->cx;
330 int raw = cx->vbi.sliced_in->service_set == 0;
331 u32 data[CX2341X_MBOX_MAX_DATA];
332 int lines;
333
334 if (cx->is_60hz) {
335 cx->vbi.count = 12;
336 cx->vbi.start[0] = 10;
337 cx->vbi.start[1] = 273;
338 } else { /* PAL/SECAM */
339 cx->vbi.count = 18;
340 cx->vbi.start[0] = 6;
341 cx->vbi.start[1] = 318;
342 }
343
344 /* setup VBI registers */
345 cx18_av_cmd(cx, VIDIOC_S_FMT, &cx->vbi.in);
346
347 /* determine number of lines and total number of VBI bytes.
348 A raw line takes 1443 bytes: 2 * 720 + 4 byte frame header - 1
349 The '- 1' byte is probably an unused U or V byte. Or something...
350 A sliced line takes 51 bytes: 4 byte frame header, 4 byte internal
351 header, 42 data bytes + checksum (to be confirmed) */
352 if (raw) {
353 lines = cx->vbi.count * 2;
354 } else {
355 lines = cx->is_60hz ? 24 : 38;
356 if (cx->is_60hz)
357 lines += 2;
358 }
359
360 cx->vbi.enc_size = lines *
361 (raw ? cx->vbi.raw_size : cx->vbi.sliced_size);
362
363 data[0] = s->handle;
364 /* Lines per field */
365 data[1] = (lines / 2) | ((lines / 2) << 16);
366 /* bytes per line */
367 data[2] = (raw ? cx->vbi.raw_size : cx->vbi.sliced_size);
368 /* Every X number of frames a VBI interrupt arrives
369 (frames as in 25 or 30 fps) */
370 data[3] = 1;
371 /* Setup VBI for the cx25840 digitizer */
372 if (raw) {
373 data[4] = 0x20602060;
374 data[5] = 0x30703070;
375 } else {
376 data[4] = 0xB0F0B0F0;
377 data[5] = 0xA0E0A0E0;
378 }
379
380 CX18_DEBUG_INFO("Setup VBI h: %d lines %x bpl %d fr %d %x %x\n",
381 data[0], data[1], data[2], data[3], data[4], data[5]);
382
383 if (s->type == CX18_ENC_STREAM_TYPE_VBI)
384 cx18_api(cx, CX18_CPU_SET_RAW_VBI_PARAM, 6, data);
385}
386
387int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
388{
389 u32 data[MAX_MB_ARGUMENTS];
390 struct cx18 *cx = s->cx;
391 struct list_head *p;
392 int ts = 0;
393 int captype = 0;
394
395 if (s->v4l2dev == NULL && s->dvb.enabled == 0)
396 return -EINVAL;
397
398 CX18_DEBUG_INFO("Start encoder stream %s\n", s->name);
399
400 switch (s->type) {
401 case CX18_ENC_STREAM_TYPE_MPG:
402 captype = CAPTURE_CHANNEL_TYPE_MPEG;
403 cx->mpg_data_received = cx->vbi_data_inserted = 0;
404 cx->dualwatch_jiffies = jiffies;
405 cx->dualwatch_stereo_mode = cx->params.audio_properties & 0x300;
406 cx->search_pack_header = 0;
407 break;
408
409 case CX18_ENC_STREAM_TYPE_TS:
410 captype = CAPTURE_CHANNEL_TYPE_TS;
411 ts = 1;
412 break;
413 case CX18_ENC_STREAM_TYPE_YUV:
414 captype = CAPTURE_CHANNEL_TYPE_YUV;
415 break;
416 case CX18_ENC_STREAM_TYPE_PCM:
417 captype = CAPTURE_CHANNEL_TYPE_PCM;
418 break;
419 case CX18_ENC_STREAM_TYPE_VBI:
420 captype = cx->vbi.sliced_in->service_set ?
421 CAPTURE_CHANNEL_TYPE_SLICED_VBI : CAPTURE_CHANNEL_TYPE_VBI;
422 cx->vbi.frame = 0;
423 cx->vbi.inserted_frame = 0;
424 memset(cx->vbi.sliced_mpeg_size,
425 0, sizeof(cx->vbi.sliced_mpeg_size));
426 break;
427 default:
428 return -EINVAL;
429 }
430 s->buffers_stolen = 0;
431
432 /* mute/unmute video */
433 cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2,
434 s->handle, !!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags));
435
436 /* Clear Streamoff flags in case left from last capture */
437 clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
438
439 cx18_vapi_result(cx, data, CX18_CREATE_TASK, 1, CPU_CMD_MASK_CAPTURE);
440 s->handle = data[0];
441 cx18_vapi(cx, CX18_CPU_SET_CHANNEL_TYPE, 2, s->handle, captype);
442
443 if (atomic_read(&cx->capturing) == 0 && !ts) {
444 /* Stuff from Windows, we don't know what it is */
445 cx18_vapi(cx, CX18_CPU_SET_VER_CROP_LINE, 2, s->handle, 0);
446 cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 3, 1);
447 cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 8, 0);
448 cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 3, s->handle, 4, 1);
449 cx18_vapi(cx, CX18_CPU_SET_MISC_PARAMETERS, 2, s->handle, 12);
450
451 cx18_vapi(cx, CX18_CPU_SET_CAPTURE_LINE_NO, 3,
452 s->handle, cx->digitizer, cx->digitizer);
453
454 /* Setup VBI */
455 if (cx->v4l2_cap & V4L2_CAP_VBI_CAPTURE)
456 cx18_vbi_setup(s);
457
458 /* assign program index info.
459 Mask 7: select I/P/B, Num_req: 400 max */
460 cx18_vapi_result(cx, data, CX18_CPU_SET_INDEXTABLE, 1, 0);
461
462 /* Setup API for Stream */
463 cx2341x_update(cx, cx18_api_func, NULL, &cx->params);
464 }
465
466 if (atomic_read(&cx->capturing) == 0) {
467 clear_bit(CX18_F_I_EOS, &cx->i_flags);
468 write_reg(7, CX18_DSP0_INTERRUPT_MASK);
469 }
470
471 cx18_vapi(cx, CX18_CPU_DE_SET_MDL_ACK, 3, s->handle,
472 (void *)&cx->scb->cpu_mdl_ack[s->type][0] - cx->enc_mem,
473 (void *)&cx->scb->cpu_mdl_ack[s->type][1] - cx->enc_mem);
474
475 list_for_each(p, &s->q_free.list) {
476 struct cx18_buffer *buf = list_entry(p, struct cx18_buffer, list);
477
478 writel(buf->dma_handle, &cx->scb->cpu_mdl[buf->id].paddr);
479 writel(s->buf_size, &cx->scb->cpu_mdl[buf->id].length);
480 cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5, s->handle,
481 (void *)&cx->scb->cpu_mdl[buf->id] - cx->enc_mem, 1,
482 buf->id, s->buf_size);
483 }
484 /* begin_capture */
485 if (cx18_vapi(cx, CX18_CPU_CAPTURE_START, 1, s->handle)) {
486 CX18_DEBUG_WARN("Error starting capture!\n");
487 cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
488 return -EINVAL;
489 }
490
491 /* you're live! sit back and await interrupts :) */
492 atomic_inc(&cx->capturing);
493 return 0;
494}
495
496void cx18_stop_all_captures(struct cx18 *cx)
497{
498 int i;
499
500 for (i = CX18_MAX_STREAMS - 1; i >= 0; i--) {
501 struct cx18_stream *s = &cx->streams[i];
502
503 if (s->v4l2dev == NULL && s->dvb.enabled == 0)
504 continue;
505 if (test_bit(CX18_F_S_STREAMING, &s->s_flags))
506 cx18_stop_v4l2_encode_stream(s, 0);
507 }
508}
509
510int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
511{
512 struct cx18 *cx = s->cx;
513 unsigned long then;
514
515 if (s->v4l2dev == NULL && s->dvb.enabled == 0)
516 return -EINVAL;
517
518 /* This function assumes that you are allowed to stop the capture
519 and that we are actually capturing */
520
521 CX18_DEBUG_INFO("Stop Capture\n");
522
523 if (atomic_read(&cx->capturing) == 0)
524 return 0;
525
526 if (s->type == CX18_ENC_STREAM_TYPE_MPG)
527 cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 2, s->handle, !gop_end);
528 else
529 cx18_vapi(cx, CX18_CPU_CAPTURE_STOP, 1, s->handle);
530
531 then = jiffies;
532
533 if (s->type == CX18_ENC_STREAM_TYPE_MPG && gop_end) {
534 CX18_INFO("ignoring gop_end: not (yet?) supported by the firmware\n");
535 }
536
537 atomic_dec(&cx->capturing);
538
539 /* Clear capture and no-read bits */
540 clear_bit(CX18_F_S_STREAMING, &s->s_flags);
541
542 cx18_vapi(cx, CX18_DESTROY_TASK, 1, s->handle);
543 s->handle = 0xffffffff;
544
545 if (atomic_read(&cx->capturing) > 0)
546 return 0;
547
548 write_reg(5, CX18_DSP0_INTERRUPT_MASK);
549 wake_up(&s->waitq);
550
551 return 0;
552}
553
554u32 cx18_find_handle(struct cx18 *cx)
555{
556 int i;
557
558 /* find first available handle to be used for global settings */
559 for (i = 0; i < CX18_MAX_STREAMS; i++) {
560 struct cx18_stream *s = &cx->streams[i];
561
562 if (s->v4l2dev && s->handle)
563 return s->handle;
564 }
565 return 0;
566}
diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h
new file mode 100644
index 000000000000..8c7ba7d2fa79
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-streams.h
@@ -0,0 +1,33 @@
1/*
2 * cx18 init/start/stop/exit stream functions
3 *
4 * Derived from ivtv-streams.h
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 */
23
24u32 cx18_find_handle(struct cx18 *cx);
25int cx18_streams_setup(struct cx18 *cx);
26int cx18_streams_register(struct cx18 *cx);
27void cx18_streams_cleanup(struct cx18 *cx);
28
29/* Capture related */
30int cx18_start_v4l2_encode_stream(struct cx18_stream *s);
31int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end);
32
33void cx18_stop_all_captures(struct cx18 *cx);
diff --git a/drivers/media/video/cx18/cx18-vbi.c b/drivers/media/video/cx18/cx18-vbi.c
new file mode 100644
index 000000000000..4bece9c02f7d
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-vbi.c
@@ -0,0 +1,208 @@
1/*
2 * cx18 Vertical Blank Interval support functions
3 *
4 * Derived from ivtv-vbi.c
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 */
23
24#include "cx18-driver.h"
25#include "cx18-vbi.h"
26#include "cx18-ioctl.h"
27#include "cx18-queue.h"
28#include "cx18-av-core.h"
29
30static void copy_vbi_data(struct cx18 *cx, int lines, u32 pts_stamp)
31{
32 int line = 0;
33 int i;
34 u32 linemask[2] = { 0, 0 };
35 unsigned short size;
36 static const u8 mpeg_hdr_data[] = {
37 0x00, 0x00, 0x01, 0xba, 0x44, 0x00, 0x0c, 0x66,
38 0x24, 0x01, 0x01, 0xd1, 0xd3, 0xfa, 0xff, 0xff,
39 0x00, 0x00, 0x01, 0xbd, 0x00, 0x1a, 0x84, 0x80,
40 0x07, 0x21, 0x00, 0x5d, 0x63, 0xa7, 0xff, 0xff
41 };
42 const int sd = sizeof(mpeg_hdr_data); /* start of vbi data */
43 int idx = cx->vbi.frame % CX18_VBI_FRAMES;
44 u8 *dst = &cx->vbi.sliced_mpeg_data[idx][0];
45
46 for (i = 0; i < lines; i++) {
47 struct v4l2_sliced_vbi_data *sdata = cx->vbi.sliced_data + i;
48 int f, l;
49
50 if (sdata->id == 0)
51 continue;
52
53 l = sdata->line - 6;
54 f = sdata->field;
55 if (f)
56 l += 18;
57 if (l < 32)
58 linemask[0] |= (1 << l);
59 else
60 linemask[1] |= (1 << (l - 32));
61 dst[sd + 12 + line * 43] = service2vbi(sdata->id);
62 memcpy(dst + sd + 12 + line * 43 + 1, sdata->data, 42);
63 line++;
64 }
65 memcpy(dst, mpeg_hdr_data, sizeof(mpeg_hdr_data));
66 if (line == 36) {
67 /* All lines are used, so there is no space for the linemask
68 (the max size of the VBI data is 36 * 43 + 4 bytes).
69 So in this case we use the magic number 'ITV0'. */
70 memcpy(dst + sd, "ITV0", 4);
71 memcpy(dst + sd + 4, dst + sd + 12, line * 43);
72 size = 4 + ((43 * line + 3) & ~3);
73 } else {
74 memcpy(dst + sd, "cx0", 4);
75 memcpy(dst + sd + 4, &linemask[0], 8);
76 size = 12 + ((43 * line + 3) & ~3);
77 }
78 dst[4+16] = (size + 10) >> 8;
79 dst[5+16] = (size + 10) & 0xff;
80 dst[9+16] = 0x21 | ((pts_stamp >> 29) & 0x6);
81 dst[10+16] = (pts_stamp >> 22) & 0xff;
82 dst[11+16] = 1 | ((pts_stamp >> 14) & 0xff);
83 dst[12+16] = (pts_stamp >> 7) & 0xff;
84 dst[13+16] = 1 | ((pts_stamp & 0x7f) << 1);
85 cx->vbi.sliced_mpeg_size[idx] = sd + size;
86}
87
88/* Compress raw VBI format, removes leading SAV codes and surplus space
89 after the field.
90 Returns new compressed size. */
91static u32 compress_raw_buf(struct cx18 *cx, u8 *buf, u32 size)
92{
93 u32 line_size = cx->vbi.raw_decoder_line_size;
94 u32 lines = cx->vbi.count;
95 u8 sav1 = cx->vbi.raw_decoder_sav_odd_field;
96 u8 sav2 = cx->vbi.raw_decoder_sav_even_field;
97 u8 *q = buf;
98 u8 *p;
99 int i;
100
101 for (i = 0; i < lines; i++) {
102 p = buf + i * line_size;
103
104 /* Look for SAV code */
105 if (p[0] != 0xff || p[1] || p[2] ||
106 (p[3] != sav1 && p[3] != sav2))
107 break;
108 memcpy(q, p + 4, line_size - 4);
109 q += line_size - 4;
110 }
111 return lines * (line_size - 4);
112}
113
114
115/* Compressed VBI format, all found sliced blocks put next to one another
116 Returns new compressed size */
117static u32 compress_sliced_buf(struct cx18 *cx, u32 line, u8 *buf,
118 u32 size, u8 sav)
119{
120 u32 line_size = cx->vbi.sliced_decoder_line_size;
121 struct v4l2_decode_vbi_line vbi;
122 int i;
123
124 /* find the first valid line */
125 for (i = 0; i < size; i++, buf++) {
126 if (buf[0] == 0xff && !buf[1] && !buf[2] && buf[3] == sav)
127 break;
128 }
129
130 size -= i;
131 if (size < line_size)
132 return line;
133 for (i = 0; i < size / line_size; i++) {
134 u8 *p = buf + i * line_size;
135
136 /* Look for SAV code */
137 if (p[0] != 0xff || p[1] || p[2] || p[3] != sav)
138 continue;
139 vbi.p = p + 4;
140 cx18_av_cmd(cx, VIDIOC_INT_DECODE_VBI_LINE, &vbi);
141 if (vbi.type) {
142 cx->vbi.sliced_data[line].id = vbi.type;
143 cx->vbi.sliced_data[line].field = vbi.is_second_field;
144 cx->vbi.sliced_data[line].line = vbi.line;
145 memcpy(cx->vbi.sliced_data[line].data, vbi.p, 42);
146 line++;
147 }
148 }
149 return line;
150}
151
152void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
153 u64 pts_stamp, int streamtype)
154{
155 u8 *p = (u8 *) buf->buf;
156 u32 size = buf->bytesused;
157 int lines;
158
159 if (streamtype != CX18_ENC_STREAM_TYPE_VBI)
160 return;
161
162 /* Raw VBI data */
163 if (cx->vbi.sliced_in->service_set == 0) {
164 u8 type;
165
166 cx18_buf_swap(buf);
167
168 type = p[3];
169
170 size = buf->bytesused = compress_raw_buf(cx, p, size);
171
172 /* second field of the frame? */
173 if (type == cx->vbi.raw_decoder_sav_even_field) {
174 /* Dirty hack needed for backwards
175 compatibility of old VBI software. */
176 p += size - 4;
177 memcpy(p, &cx->vbi.frame, 4);
178 cx->vbi.frame++;
179 }
180 return;
181 }
182
183 /* Sliced VBI data with data insertion */
184 cx18_buf_swap(buf);
185
186 /* first field */
187 lines = compress_sliced_buf(cx, 0, p, size / 2,
188 cx->vbi.sliced_decoder_sav_odd_field);
189 /* second field */
190 /* experimentation shows that the second half does not always
191 begin at the exact address. So start a bit earlier
192 (hence 32). */
193 lines = compress_sliced_buf(cx, lines, p + size / 2 - 32,
194 size / 2 + 32, cx->vbi.sliced_decoder_sav_even_field);
195 /* always return at least one empty line */
196 if (lines == 0) {
197 cx->vbi.sliced_data[0].id = 0;
198 cx->vbi.sliced_data[0].line = 0;
199 cx->vbi.sliced_data[0].field = 0;
200 lines = 1;
201 }
202 buf->bytesused = size = lines * sizeof(cx->vbi.sliced_data[0]);
203 memcpy(p, &cx->vbi.sliced_data[0], size);
204
205 if (cx->vbi.insert_mpeg)
206 copy_vbi_data(cx, lines, pts_stamp);
207 cx->vbi.frame++;
208}
diff --git a/drivers/media/video/cx18/cx18-vbi.h b/drivers/media/video/cx18/cx18-vbi.h
new file mode 100644
index 000000000000..c56ff7d28f20
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-vbi.h
@@ -0,0 +1,26 @@
1/*
2 * cx18 Vertical Blank Interval support functions
3 *
4 * Derived from ivtv-vbi.h
5 *
6 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
21 * 02111-1307 USA
22 */
23
24void cx18_process_vbi_data(struct cx18 *cx, struct cx18_buffer *buf,
25 u64 pts_stamp, int streamtype);
26int cx18_used_line(struct cx18 *cx, int line, int field);
diff --git a/drivers/media/video/cx18/cx18-version.h b/drivers/media/video/cx18/cx18-version.h
new file mode 100644
index 000000000000..d5c7a6f968dd
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-version.h
@@ -0,0 +1,34 @@
1/*
2 * cx18 driver version information
3 *
4 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 * 02111-1307 USA
20 */
21
22#ifndef CX18_VERSION_H
23#define CX18_VERSION_H
24
25#define CX18_DRIVER_NAME "cx18"
26#define CX18_DRIVER_VERSION_MAJOR 1
27#define CX18_DRIVER_VERSION_MINOR 0
28#define CX18_DRIVER_VERSION_PATCHLEVEL 0
29
30#define CX18_VERSION __stringify(CX18_DRIVER_VERSION_MAJOR) "." __stringify(CX18_DRIVER_VERSION_MINOR) "." __stringify(CX18_DRIVER_VERSION_PATCHLEVEL)
31#define CX18_DRIVER_VERSION KERNEL_VERSION(CX18_DRIVER_VERSION_MAJOR, \
32 CX18_DRIVER_VERSION_MINOR, CX18_DRIVER_VERSION_PATCHLEVEL)
33
34#endif
diff --git a/drivers/media/video/cx18/cx18-video.c b/drivers/media/video/cx18/cx18-video.c
new file mode 100644
index 000000000000..2e5c41939330
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-video.c
@@ -0,0 +1,45 @@
1/*
2 * cx18 video interface functions
3 *
4 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 * 02111-1307 USA
20 */
21
22#include "cx18-driver.h"
23#include "cx18-video.h"
24#include "cx18-av-core.h"
25#include "cx18-cards.h"
26
27void cx18_video_set_io(struct cx18 *cx)
28{
29 struct v4l2_routing route;
30 int inp = cx->active_input;
31 u32 type;
32
33 route.input = cx->card->video_inputs[inp].video_input;
34 route.output = 0;
35 cx18_av_cmd(cx, VIDIOC_INT_S_VIDEO_ROUTING, &route);
36
37 type = cx->card->video_inputs[inp].video_type;
38
39 if (type == CX18_CARD_INPUT_VID_TUNER)
40 route.input = 0; /* Tuner */
41 else if (type < CX18_CARD_INPUT_COMPOSITE1)
42 route.input = 2; /* S-Video */
43 else
44 route.input = 1; /* Composite */
45}
diff --git a/drivers/media/video/cx18/cx18-video.h b/drivers/media/video/cx18/cx18-video.h
new file mode 100644
index 000000000000..529006a06e5c
--- /dev/null
+++ b/drivers/media/video/cx18/cx18-video.h
@@ -0,0 +1,22 @@
1/*
2 * cx18 video interface functions
3 *
4 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 * 02111-1307 USA
20 */
21
22void cx18_video_set_io(struct cx18 *cx);
diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h
new file mode 100644
index 000000000000..33f78da9dba8
--- /dev/null
+++ b/drivers/media/video/cx18/cx23418.h
@@ -0,0 +1,458 @@
1/*
2 * cx18 header containing common defines.
3 *
4 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 * 02111-1307 USA
20 */
21
22#ifndef CX23418_H
23#define CX23418_H
24
25#include <media/cx2341x.h>
26
27#define MGR_CMD_MASK 0x40000000
28/* The MSB of the command code indicates that this is the completion of a
29 command */
30#define MGR_CMD_MASK_ACK (MGR_CMD_MASK | 0x80000000)
31
32/* Description: This command creates a new instance of a certain task
33 IN[0] - Task ID. This is one of the XPU_CMD_MASK_YYY where XPU is
34 the processor on which the task YYY will be created
35 OUT[0] - Task handle. This handle is passed along with commands to
36 dispatch to the right instance of the task
37 ReturnCode - One of the ERR_SYS_... */
38#define CX18_CREATE_TASK (MGR_CMD_MASK | 0x0001)
39
40/* Description: This command destroys an instance of a task
41 IN[0] - Task handle. Hanlde of the task to destroy
42 ReturnCode - One of the ERR_SYS_... */
43#define CX18_DESTROY_TASK (MGR_CMD_MASK | 0x0002)
44
45/* All commands for CPU have the following mask set */
46#define CPU_CMD_MASK 0x20000000
47#define CPU_CMD_MASK_ACK (CPU_CMD_MASK | 0x80000000)
48#define CPU_CMD_MASK_CAPTURE (CPU_CMD_MASK | 0x00020000)
49#define CPU_CMD_MASK_TS (CPU_CMD_MASK | 0x00040000)
50
51#define EPU_CMD_MASK 0x02000000
52#define EPU_CMD_MASK_DEBUG (EPU_CMD_MASK | 0x000000)
53#define EPU_CMD_MASK_DE (EPU_CMD_MASK | 0x040000)
54
55/* Description: This command indicates that a Memory Descriptor List has been
56 filled with the requested channel type
57 IN[0] - Task handle. Handle of the task
58 IN[1] - Offset of the MDL_ACK from the beginning of the local DDR.
59 IN[2] - Number of CNXT_MDL_ACK structures in the array pointed to by IN[1]
60 ReturnCode - One of the ERR_DE_... */
61#define CX18_EPU_DMA_DONE (EPU_CMD_MASK_DE | 0x0001)
62
63/* Something interesting happened
64 IN[0] - A value to log
65 IN[1] - An offset of a string in the MiniMe memory;
66 0/zero/NULL means "I have nothing to say" */
67#define CX18_EPU_DEBUG (EPU_CMD_MASK_DEBUG | 0x0003)
68
69/* Description: This command starts streaming with the set channel type
70 IN[0] - Task handle. Handle of the task to start
71 ReturnCode - One of the ERR_CAPTURE_... */
72#define CX18_CPU_CAPTURE_START (CPU_CMD_MASK_CAPTURE | 0x0002)
73
74/* Description: This command stops streaming with the set channel type
75 IN[0] - Task handle. Handle of the task to stop
76 IN[1] - 0 = stop at end of GOP, 1 = stop at end of frame (MPEG only)
77 ReturnCode - One of the ERR_CAPTURE_... */
78#define CX18_CPU_CAPTURE_STOP (CPU_CMD_MASK_CAPTURE | 0x0003)
79
80/* Description: This command pauses streaming with the set channel type
81 IN[0] - Task handle. Handle of the task to pause
82 ReturnCode - One of the ERR_CAPTURE_... */
83#define CX18_CPU_CAPTURE_PAUSE (CPU_CMD_MASK_CAPTURE | 0x0007)
84
85/* Description: This command resumes streaming with the set channel type
86 IN[0] - Task handle. Handle of the task to resume
87 ReturnCode - One of the ERR_CAPTURE_... */
88#define CX18_CPU_CAPTURE_RESUME (CPU_CMD_MASK_CAPTURE | 0x0008)
89
90#define CAPTURE_CHANNEL_TYPE_NONE 0
91#define CAPTURE_CHANNEL_TYPE_MPEG 1
92#define CAPTURE_CHANNEL_TYPE_INDEX 2
93#define CAPTURE_CHANNEL_TYPE_YUV 3
94#define CAPTURE_CHANNEL_TYPE_PCM 4
95#define CAPTURE_CHANNEL_TYPE_VBI 5
96#define CAPTURE_CHANNEL_TYPE_SLICED_VBI 6
97#define CAPTURE_CHANNEL_TYPE_TS 7
98#define CAPTURE_CHANNEL_TYPE_MAX 15
99
100/* Description: This command sets the channel type. This can only be done
101 when stopped.
102 IN[0] - Task handle. Handle of the task to start
103 IN[1] - Channel Type. See Below.
104 ReturnCode - One of the ERR_CAPTURE_... */
105#define CX18_CPU_SET_CHANNEL_TYPE (CPU_CMD_MASK_CAPTURE + 1)
106
107/* Description: Set stream output type
108 IN[0] - task handle. Handle of the task to start
109 IN[1] - type
110 ReturnCode - One of the ERR_CAPTURE_... */
111#define CX18_CPU_SET_STREAM_OUTPUT_TYPE (CPU_CMD_MASK_CAPTURE | 0x0012)
112
113/* Description: Set video input resolution and frame rate
114 IN[0] - task handle
115 IN[1] - reserved
116 IN[2] - reserved
117 IN[3] - reserved
118 IN[4] - reserved
119 IN[5] - frame rate, 0 - 29.97f/s, 1 - 25f/s
120 ReturnCode - One of the ERR_CAPTURE_... */
121#define CX18_CPU_SET_VIDEO_IN (CPU_CMD_MASK_CAPTURE | 0x0004)
122
123/* Description: Set video frame rate
124 IN[0] - task handle. Handle of the task to start
125 IN[1] - video bit rate mode
126 IN[2] - video average rate
127 IN[3] - video peak rate
128 IN[4] - system mux rate
129 ReturnCode - One of the ERR_CAPTURE_... */
130#define CX18_CPU_SET_VIDEO_RATE (CPU_CMD_MASK_CAPTURE | 0x0005)
131
132/* Description: Set video output resolution
133 IN[0] - task handle
134 IN[1] - horizontal size
135 IN[2] - vertical size
136 ReturnCode - One of the ERR_CAPTURE_... */
137#define CX18_CPU_SET_VIDEO_RESOLUTION (CPU_CMD_MASK_CAPTURE | 0x0006)
138
139/* Description: This command set filter parameters
140 IN[0] - Task handle. Handle of the task
141 IN[1] - type, 0 - temporal, 1 - spatial, 2 - median
142 IN[2] - mode, temporal/spatial: 0 - disable, 1 - static, 2 - dynamic
143 median: 0 = disable, 1 = horizontal, 2 = vertical,
144 3 = horizontal/vertical, 4 = diagonal
145 IN[3] - strength, temporal 0 - 31, spatial 0 - 15
146 ReturnCode - One of the ERR_CAPTURE_... */
147#define CX18_CPU_SET_FILTER_PARAM (CPU_CMD_MASK_CAPTURE | 0x0009)
148
149/* Description: This command set spatial filter type
150 IN[0] - Task handle.
151 IN[1] - luma type: 0 = disable, 1 = 1D horizontal only, 2 = 1D vertical only,
152 3 = 2D H/V separable, 4 = 2D symmetric non-separable
153 IN[2] - chroma type: 0 - diable, 1 = 1D horizontal
154 ReturnCode - One of the ERR_CAPTURE_... */
155#define CX18_CPU_SET_SPATIAL_FILTER_TYPE (CPU_CMD_MASK_CAPTURE | 0x000C)
156
157/* Description: This command set coring levels for median filter
158 IN[0] - Task handle.
159 IN[1] - luma_high
160 IN[2] - luma_low
161 IN[3] - chroma_high
162 IN[4] - chroma_low
163 ReturnCode - One of the ERR_CAPTURE_... */
164#define CX18_CPU_SET_MEDIAN_CORING (CPU_CMD_MASK_CAPTURE | 0x000E)
165
166/* Description: This command set the picture type mask for index file
167 IN[0] - 0 = disable index file output
168 1 = output I picture
169 2 = P picture
170 4 = B picture
171 other = illegal */
172#define CX18_CPU_SET_INDEXTABLE (CPU_CMD_MASK_CAPTURE | 0x0010)
173
174/* Description: Set audio parameters
175 IN[0] - task handle. Handle of the task to start
176 IN[1] - audio parameter
177 ReturnCode - One of the ERR_CAPTURE_... */
178#define CX18_CPU_SET_AUDIO_PARAMETERS (CPU_CMD_MASK_CAPTURE | 0x0011)
179
180/* Description: Set video mute
181 IN[0] - task handle. Handle of the task to start
182 IN[1] - bit31-24: muteYvalue
183 bit23-16: muteUvalue
184 bit15-8: muteVvalue
185 bit0: 1:mute, 0: unmute
186 ReturnCode - One of the ERR_CAPTURE_... */
187#define CX18_CPU_SET_VIDEO_MUTE (CPU_CMD_MASK_CAPTURE | 0x0013)
188
189/* Description: Set audio mute
190 IN[0] - task handle. Handle of the task to start
191 IN[1] - mute/unmute
192 ReturnCode - One of the ERR_CAPTURE_... */
193#define CX18_CPU_SET_AUDIO_MUTE (CPU_CMD_MASK_CAPTURE | 0x0014)
194
195/* Description: Set stream output type
196 IN[0] - task handle. Handle of the task to start
197 IN[1] - subType
198 SET_INITIAL_SCR 1
199 SET_QUALITY_MODE 2
200 SET_VIM_PROTECT_MODE 3
201 SET_PTS_CORRECTION 4
202 SET_USB_FLUSH_MODE 5
203 SET_MERAQPAR_ENABLE 6
204 SET_NAV_PACK_INSERTION 7
205 SET_SCENE_CHANGE_ENABLE 8
206 IN[2] - parameter 1
207 IN[3] - parameter 2
208 ReturnCode - One of the ERR_CAPTURE_... */
209#define CX18_CPU_SET_MISC_PARAMETERS (CPU_CMD_MASK_CAPTURE | 0x0015)
210
211/* Description: Set raw VBI parameters
212 IN[0] - Task handle
213 IN[1] - No. of input lines per field:
214 bit[15:0]: field 1,
215 bit[31:16]: field 2
216 IN[2] - No. of input bytes per line
217 IN[3] - No. of output frames per transfer
218 IN[4] - start code
219 IN[5] - stop code
220 ReturnCode */
221#define CX18_CPU_SET_RAW_VBI_PARAM (CPU_CMD_MASK_CAPTURE | 0x0016)
222
223/* Description: Set capture line No.
224 IN[0] - task handle. Handle of the task to start
225 IN[1] - height1
226 IN[2] - height2
227 ReturnCode - One of the ERR_CAPTURE_... */
228#define CX18_CPU_SET_CAPTURE_LINE_NO (CPU_CMD_MASK_CAPTURE | 0x0017)
229
230/* Description: Set copyright
231 IN[0] - task handle. Handle of the task to start
232 IN[1] - copyright
233 ReturnCode - One of the ERR_CAPTURE_... */
234#define CX18_CPU_SET_COPYRIGHT (CPU_CMD_MASK_CAPTURE | 0x0018)
235
236/* Description: Set audio PID
237 IN[0] - task handle. Handle of the task to start
238 IN[1] - PID
239 ReturnCode - One of the ERR_CAPTURE_... */
240#define CX18_CPU_SET_AUDIO_PID (CPU_CMD_MASK_CAPTURE | 0x0019)
241
242/* Description: Set video PID
243 IN[0] - task handle. Handle of the task to start
244 IN[1] - PID
245 ReturnCode - One of the ERR_CAPTURE_... */
246#define CX18_CPU_SET_VIDEO_PID (CPU_CMD_MASK_CAPTURE | 0x001A)
247
248/* Description: Set Vertical Crop Line
249 IN[0] - task handle. Handle of the task to start
250 IN[1] - Line
251 ReturnCode - One of the ERR_CAPTURE_... */
252#define CX18_CPU_SET_VER_CROP_LINE (CPU_CMD_MASK_CAPTURE | 0x001B)
253
254/* Description: Set COP structure
255 IN[0] - task handle. Handle of the task to start
256 IN[1] - M
257 IN[2] - N
258 ReturnCode - One of the ERR_CAPTURE_... */
259#define CX18_CPU_SET_GOP_STRUCTURE (CPU_CMD_MASK_CAPTURE | 0x001C)
260
261/* Description: Set Scene Change Detection
262 IN[0] - task handle. Handle of the task to start
263 IN[1] - scene change
264 ReturnCode - One of the ERR_CAPTURE_... */
265#define CX18_CPU_SET_SCENE_CHANGE_DETECTION (CPU_CMD_MASK_CAPTURE | 0x001D)
266
267/* Description: Set Aspect Ratio
268 IN[0] - task handle. Handle of the task to start
269 IN[1] - AspectRatio
270 ReturnCode - One of the ERR_CAPTURE_... */
271#define CX18_CPU_SET_ASPECT_RATIO (CPU_CMD_MASK_CAPTURE | 0x001E)
272
273/* Description: Set Skip Input Frame
274 IN[0] - task handle. Handle of the task to start
275 IN[1] - skip input frames
276 ReturnCode - One of the ERR_CAPTURE_... */
277#define CX18_CPU_SET_SKIP_INPUT_FRAME (CPU_CMD_MASK_CAPTURE | 0x001F)
278
279/* Description: Set sliced VBI parameters -
280 Note This API will only apply to MPEG and Sliced VBI Channels
281 IN[0] - Task handle
282 IN[1] - output type, 0 - CC, 1 - Moji, 2 - Teletext
283 IN[2] - start / stop line
284 bit[15:0] start line number
285 bit[31:16] stop line number
286 IN[3] - number of output frames per interrupt
287 IN[4] - VBI insertion mode
288 bit 0: output user data, 1 - enable
289 bit 1: output private stream, 1 - enable
290 bit 2: mux option, 0 - in GOP, 1 - in picture
291 bit[7:0] private stream ID
292 IN[5] - insertion period while mux option is in picture
293 ReturnCode - VBI data offset */
294#define CX18_CPU_SET_SLICED_VBI_PARAM (CPU_CMD_MASK_CAPTURE | 0x0020)
295
296/* Description: Set the user data place holder
297 IN[0] - type of data (0 for user)
298 IN[1] - Stuffing period
299 IN[2] - ID data size in word (less than 10)
300 IN[3] - Pointer to ID buffer */
301#define CX18_CPU_SET_USERDATA_PLACE_HOLDER (CPU_CMD_MASK_CAPTURE | 0x0021)
302
303
304/* Description:
305 In[0] Task Handle
306 return parameter:
307 Out[0] Reserved
308 Out[1] Video PTS bit[32:2] of last output video frame.
309 Out[2] Video PTS bit[ 1:0] of last output video frame.
310 Out[3] Hardware Video PTS counter bit[31:0],
311 these bits get incremented on every 90kHz clock tick.
312 Out[4] Hardware Video PTS counter bit32,
313 these bits get incremented on every 90kHz clock tick.
314 ReturnCode */
315#define CX18_CPU_GET_ENC_PTS (CPU_CMD_MASK_CAPTURE | 0x0022)
316
317/* Below is the list of commands related to the data exchange */
318#define CPU_CMD_MASK_DE (CPU_CMD_MASK | 0x040000)
319
320/* Description: This command provides the physical base address of the local
321 DDR as viewed by EPU
322 IN[0] - Physical offset where EPU has the local DDR mapped
323 ReturnCode - One of the ERR_DE_... */
324#define CPU_CMD_DE_SetBase (CPU_CMD_MASK_DE | 0x0001)
325
326/* Description: This command provides the offsets in the device memory where
327 the 2 cx18_mdl_ack blocks reside
328 IN[0] - Task handle. Handle of the task to start
329 IN[1] - Offset of the first cx18_mdl_ack from the beginning of the
330 local DDR.
331 IN[2] - Offset of the second cx18_mdl_ack from the beginning of the
332 local DDR.
333 ReturnCode - One of the ERR_DE_... */
334#define CX18_CPU_DE_SET_MDL_ACK (CPU_CMD_MASK_DE | 0x0002)
335
336/* Description: This command provides the offset to a Memory Descriptor List
337 IN[0] - Task handle. Handle of the task to start
338 IN[1] - Offset of the MDL from the beginning of the local DDR.
339 IN[2] - Number of cx18_mdl structures in the array pointed to by IN[1]
340 IN[3] - Buffer ID
341 IN[4] - Total buffer length
342 ReturnCode - One of the ERR_DE_... */
343#define CX18_CPU_DE_SET_MDL (CPU_CMD_MASK_DE | 0x0005)
344
345/* Description: This command requests return of all current Memory
346 Descriptor Lists to the driver
347 IN[0] - Task handle. Handle of the task to start
348 ReturnCode - One of the ERR_DE_... */
349/* #define CX18_CPU_DE_ReleaseMDL (CPU_CMD_MASK_DE | 0x0006) */
350
351/* Description: This command signals the cpu that the dat buffer has been
352 consumed and ready for re-use.
353 IN[0] - Task handle. Handle of the task
354 IN[1] - Offset of the data block from the beginning of the local DDR.
355 IN[2] - Number of bytes in the data block
356 ReturnCode - One of the ERR_DE_... */
357/* #define CX18_CPU_DE_RELEASE_BUFFER (CPU_CMD_MASK_DE | 0x0007) */
358
359/* No Error / Success */
360#define CNXT_OK 0x000000
361
362/* Received unknown command */
363#define CXERR_UNK_CMD 0x000001
364
365/* First parameter in the command is invalid */
366#define CXERR_INVALID_PARAM1 0x000002
367
368/* Second parameter in the command is invalid */
369#define CXERR_INVALID_PARAM2 0x000003
370
371/* Device interface is not open/found */
372#define CXERR_DEV_NOT_FOUND 0x000004
373
374/* Requested function is not implemented/available */
375#define CXERR_NOTSUPPORTED 0x000005
376
377/* Invalid pointer is provided */
378#define CXERR_BADPTR 0x000006
379
380/* Unable to allocate memory */
381#define CXERR_NOMEM 0x000007
382
383/* Object/Link not found */
384#define CXERR_LINK 0x000008
385
386/* Device busy, command cannot be executed */
387#define CXERR_BUSY 0x000009
388
389/* File/device/handle is not open. */
390#define CXERR_NOT_OPEN 0x00000A
391
392/* Value is out of range */
393#define CXERR_OUTOFRANGE 0x00000B
394
395/* Buffer overflow */
396#define CXERR_OVERFLOW 0x00000C
397
398/* Version mismatch */
399#define CXERR_BADVER 0x00000D
400
401/* Operation timed out */
402#define CXERR_TIMEOUT 0x00000E
403
404/* Operation aborted */
405#define CXERR_ABORT 0x00000F
406
407/* Specified I2C device not found for read/write */
408#define CXERR_I2CDEV_NOTFOUND 0x000010
409
410/* Error in I2C data xfer (but I2C device is present) */
411#define CXERR_I2CDEV_XFERERR 0x000011
412
413/* Chanel changing component not ready */
414#define CXERR_CHANNELNOTREADY 0x000012
415
416/* PPU (Presensation/Decoder) mail box is corrupted */
417#define CXERR_PPU_MB_CORRUPT 0x000013
418
419/* CPU (Capture/Encoder) mail box is corrupted */
420#define CXERR_CPU_MB_CORRUPT 0x000014
421
422/* APU (Audio) mail box is corrupted */
423#define CXERR_APU_MB_CORRUPT 0x000015
424
425/* Unable to open file for reading */
426#define CXERR_FILE_OPEN_READ 0x000016
427
428/* Unable to open file for writing */
429#define CXERR_FILE_OPEN_WRITE 0x000017
430
431/* Unable to find the I2C section specified */
432#define CXERR_I2C_BADSECTION 0x000018
433
434/* Error in I2C data xfer (but I2C device is present) */
435#define CXERR_I2CDEV_DATALOW 0x000019
436
437/* Error in I2C data xfer (but I2C device is present) */
438#define CXERR_I2CDEV_CLOCKLOW 0x00001A
439
440/* No Interrupt received from HW (for I2C access) */
441#define CXERR_NO_HW_I2C_INTR 0x00001B
442
443/* RPU is not ready to accept commands! */
444#define CXERR_RPU_NOT_READY 0x00001C
445
446/* RPU is not ready to accept commands! */
447#define CXERR_RPU_NO_ACK 0x00001D
448
449/* The are no buffers ready. Try again soon! */
450#define CXERR_NODATA_AGAIN 0x00001E
451
452/* The stream is stopping. Function not alllowed now! */
453#define CXERR_STOPPING_STATUS 0x00001F
454
455/* Trying to access hardware when the power is turned OFF */
456#define CXERR_DEVPOWER_OFF 0x000020
457
458#endif /* CX23418_H */