diff options
Diffstat (limited to 'drivers/media/video/cx18/cx18-dvb.c')
-rw-r--r-- | drivers/media/video/cx18/cx18-dvb.c | 288 |
1 files changed, 288 insertions, 0 deletions
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 | |||
33 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | ||
34 | |||
35 | #define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000 | ||
36 | |||
37 | #ifdef HAVE_MXL500X | ||
38 | static 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 | |||
48 | static 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 | |||
60 | static 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 | */ | ||
66 | static 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. */ | ||
112 | static 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 | |||
135 | int 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 | |||
203 | err_disconnect_frontend: | ||
204 | dmx->disconnect_frontend(dmx); | ||
205 | err_remove_mem_frontend: | ||
206 | dmx->remove_frontend(dmx, &dvb->mem_frontend); | ||
207 | err_remove_hw_frontend: | ||
208 | dmx->remove_frontend(dmx, &dvb->hw_frontend); | ||
209 | err_dvb_dmxdev_release: | ||
210 | dvb_dmxdev_release(&dvb->dmxdev); | ||
211 | err_dvb_dmx_release: | ||
212 | dvb_dmx_release(dvbdemux); | ||
213 | err_dvb_unregister_adapter: | ||
214 | dvb_unregister_adapter(dvb_adapter); | ||
215 | err_out: | ||
216 | return ret; | ||
217 | } | ||
218 | |||
219 | void 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 | */ | ||
248 | static 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 | } | ||