• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  cx18 functions for DVB support
3  *
4  *  Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
5  *  Copyright (C) 2008  Andy Walls <awalls@radix.net>
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *
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., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22 
23 #include "cx18-version.h"
24 #include "cx18-dvb.h"
25 #include "cx18-io.h"
26 #include "cx18-streams.h"
27 #include "cx18-cards.h"
28 #include "s5h1409.h"
29 #include "mxl5005s.h"
30 
31 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
32 
33 #define CX18_REG_DMUX_NUM_PORT_0_CONTROL 0xd5a000
34 
35 static struct mxl5005s_config hauppauge_hvr1600_tuner = {
36 	.i2c_address     = 0xC6 >> 1,
37 	.if_freq         = IF_FREQ_5380000HZ,
38 	.xtal_freq       = CRYSTAL_FREQ_16000000HZ,
39 	.agc_mode        = MXL_SINGLE_AGC,
40 	.tracking_filter = MXL_TF_C_H,
41 	.rssi_enable     = MXL_RSSI_ENABLE,
42 	.cap_select      = MXL_CAP_SEL_ENABLE,
43 	.div_out         = MXL_DIV_OUT_4,
44 	.clock_out       = MXL_CLOCK_OUT_DISABLE,
45 	.output_load     = MXL5005S_IF_OUTPUT_LOAD_200_OHM,
46 	.top		 = MXL5005S_TOP_25P2,
47 	.mod_mode        = MXL_DIGITAL_MODE,
48 	.if_mode         = MXL_ZERO_IF,
49 	.AgcMasterByte   = 0x00,
50 };
51 
52 static struct s5h1409_config hauppauge_hvr1600_config = {
53 	.demod_address = 0x32 >> 1,
54 	.output_mode   = S5H1409_SERIAL_OUTPUT,
55 	.gpio          = S5H1409_GPIO_ON,
56 	.qam_if        = 44000,
57 	.inversion     = S5H1409_INVERSION_OFF,
58 	.status_mode   = S5H1409_DEMODLOCKING,
59 	.mpeg_timing   = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
60 
61 };
62 
63 static int dvb_register(struct cx18_stream *stream);
64 
65 /* Kernel DVB framework calls this when the feed needs to start.
66  * The CX18 framework should enable the transport DMA handling
67  * and queue processing.
68  */
cx18_dvb_start_feed(struct dvb_demux_feed * feed)69 static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
70 {
71 	struct dvb_demux *demux = feed->demux;
72 	struct cx18_stream *stream = (struct cx18_stream *) demux->priv;
73 	struct cx18 *cx = stream->cx;
74 	int ret;
75 	u32 v;
76 
77 	CX18_DEBUG_INFO("Start feed: pid = 0x%x index = %d\n",
78 			feed->pid, feed->index);
79 
80 	mutex_lock(&cx->serialize_lock);
81 	ret = cx18_init_on_first_open(cx);
82 	mutex_unlock(&cx->serialize_lock);
83 	if (ret) {
84 		CX18_ERR("Failed to initialize firmware starting DVB feed\n");
85 		return ret;
86 	}
87 	ret = -EINVAL;
88 
89 	switch (cx->card->type) {
90 	case CX18_CARD_HVR_1600_ESMT:
91 	case CX18_CARD_HVR_1600_SAMSUNG:
92 		v = cx18_read_reg(cx, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
93 		v |= 0x00400000; /* Serial Mode */
94 		v |= 0x00002000; /* Data Length - Byte */
95 		v |= 0x00010000; /* Error - Polarity */
96 		v |= 0x00020000; /* Error - Passthru */
97 		v |= 0x000c0000; /* Error - Ignore */
98 		cx18_write_reg(cx, v, CX18_REG_DMUX_NUM_PORT_0_CONTROL);
99 		break;
100 
101 	default:
102 		/* Assumption - Parallel transport - Signalling
103 		 * undefined or default.
104 		 */
105 		break;
106 	}
107 
108 	if (!demux->dmx.frontend)
109 		return -EINVAL;
110 
111 	if (!stream)
112 		return -EINVAL;
113 
114 	mutex_lock(&stream->dvb.feedlock);
115 	if (stream->dvb.feeding++ == 0) {
116 		CX18_DEBUG_INFO("Starting Transport DMA\n");
117 		set_bit(CX18_F_S_STREAMING, &stream->s_flags);
118 		ret = cx18_start_v4l2_encode_stream(stream);
119 		if (ret < 0) {
120 			CX18_DEBUG_INFO("Failed to start Transport DMA\n");
121 			stream->dvb.feeding--;
122 			if (stream->dvb.feeding == 0)
123 				clear_bit(CX18_F_S_STREAMING, &stream->s_flags);
124 		}
125 	} else
126 		ret = 0;
127 	mutex_unlock(&stream->dvb.feedlock);
128 
129 	return ret;
130 }
131 
132 /* Kernel DVB framework calls this when the feed needs to stop. */
cx18_dvb_stop_feed(struct dvb_demux_feed * feed)133 static int cx18_dvb_stop_feed(struct dvb_demux_feed *feed)
134 {
135 	struct dvb_demux *demux = feed->demux;
136 	struct cx18_stream *stream = (struct cx18_stream *)demux->priv;
137 	struct cx18 *cx = stream->cx;
138 	int ret = -EINVAL;
139 
140 	CX18_DEBUG_INFO("Stop feed: pid = 0x%x index = %d\n",
141 			feed->pid, feed->index);
142 
143 	if (stream) {
144 		mutex_lock(&stream->dvb.feedlock);
145 		if (--stream->dvb.feeding == 0) {
146 			CX18_DEBUG_INFO("Stopping Transport DMA\n");
147 			ret = cx18_stop_v4l2_encode_stream(stream, 0);
148 		} else
149 			ret = 0;
150 		mutex_unlock(&stream->dvb.feedlock);
151 	}
152 
153 	return ret;
154 }
155 
cx18_dvb_register(struct cx18_stream * stream)156 int cx18_dvb_register(struct cx18_stream *stream)
157 {
158 	struct cx18 *cx = stream->cx;
159 	struct cx18_dvb *dvb = &stream->dvb;
160 	struct dvb_adapter *dvb_adapter;
161 	struct dvb_demux *dvbdemux;
162 	struct dmx_demux *dmx;
163 	int ret;
164 
165 	if (!dvb)
166 		return -EINVAL;
167 
168 	ret = dvb_register_adapter(&dvb->dvb_adapter,
169 			CX18_DRIVER_NAME,
170 			THIS_MODULE, &cx->dev->dev, adapter_nr);
171 	if (ret < 0)
172 		goto err_out;
173 
174 	dvb_adapter = &dvb->dvb_adapter;
175 
176 	dvbdemux = &dvb->demux;
177 
178 	dvbdemux->priv = (void *)stream;
179 
180 	dvbdemux->filternum = 256;
181 	dvbdemux->feednum = 256;
182 	dvbdemux->start_feed = cx18_dvb_start_feed;
183 	dvbdemux->stop_feed = cx18_dvb_stop_feed;
184 	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
185 		DMX_SECTION_FILTERING | DMX_MEMORY_BASED_FILTERING);
186 	ret = dvb_dmx_init(dvbdemux);
187 	if (ret < 0)
188 		goto err_dvb_unregister_adapter;
189 
190 	dmx = &dvbdemux->dmx;
191 
192 	dvb->hw_frontend.source = DMX_FRONTEND_0;
193 	dvb->mem_frontend.source = DMX_MEMORY_FE;
194 	dvb->dmxdev.filternum = 256;
195 	dvb->dmxdev.demux = dmx;
196 
197 	ret = dvb_dmxdev_init(&dvb->dmxdev, dvb_adapter);
198 	if (ret < 0)
199 		goto err_dvb_dmx_release;
200 
201 	ret = dmx->add_frontend(dmx, &dvb->hw_frontend);
202 	if (ret < 0)
203 		goto err_dvb_dmxdev_release;
204 
205 	ret = dmx->add_frontend(dmx, &dvb->mem_frontend);
206 	if (ret < 0)
207 		goto err_remove_hw_frontend;
208 
209 	ret = dmx->connect_frontend(dmx, &dvb->hw_frontend);
210 	if (ret < 0)
211 		goto err_remove_mem_frontend;
212 
213 	ret = dvb_register(stream);
214 	if (ret < 0)
215 		goto err_disconnect_frontend;
216 
217 	dvb_net_init(dvb_adapter, &dvb->dvbnet, dmx);
218 
219 	CX18_INFO("DVB Frontend registered\n");
220 	CX18_INFO("Registered DVB adapter%d for %s (%d x %d kB)\n",
221 		  stream->dvb.dvb_adapter.num, stream->name,
222 		  stream->buffers, stream->buf_size/1024);
223 
224 	mutex_init(&dvb->feedlock);
225 	dvb->enabled = 1;
226 	return ret;
227 
228 err_disconnect_frontend:
229 	dmx->disconnect_frontend(dmx);
230 err_remove_mem_frontend:
231 	dmx->remove_frontend(dmx, &dvb->mem_frontend);
232 err_remove_hw_frontend:
233 	dmx->remove_frontend(dmx, &dvb->hw_frontend);
234 err_dvb_dmxdev_release:
235 	dvb_dmxdev_release(&dvb->dmxdev);
236 err_dvb_dmx_release:
237 	dvb_dmx_release(dvbdemux);
238 err_dvb_unregister_adapter:
239 	dvb_unregister_adapter(dvb_adapter);
240 err_out:
241 	return ret;
242 }
243 
cx18_dvb_unregister(struct cx18_stream * stream)244 void cx18_dvb_unregister(struct cx18_stream *stream)
245 {
246 	struct cx18 *cx = stream->cx;
247 	struct cx18_dvb *dvb = &stream->dvb;
248 	struct dvb_adapter *dvb_adapter;
249 	struct dvb_demux *dvbdemux;
250 	struct dmx_demux *dmx;
251 
252 	CX18_INFO("unregister DVB\n");
253 
254 	dvb_adapter = &dvb->dvb_adapter;
255 	dvbdemux = &dvb->demux;
256 	dmx = &dvbdemux->dmx;
257 
258 	dmx->close(dmx);
259 	dvb_net_release(&dvb->dvbnet);
260 	dmx->remove_frontend(dmx, &dvb->mem_frontend);
261 	dmx->remove_frontend(dmx, &dvb->hw_frontend);
262 	dvb_dmxdev_release(&dvb->dmxdev);
263 	dvb_dmx_release(dvbdemux);
264 	dvb_unregister_frontend(dvb->fe);
265 	dvb_frontend_detach(dvb->fe);
266 	dvb_unregister_adapter(dvb_adapter);
267 }
268 
269 /* All the DVB attach calls go here, this function get's modified
270  * for each new card. No other function in this file needs
271  * to change.
272  */
dvb_register(struct cx18_stream * stream)273 static int dvb_register(struct cx18_stream *stream)
274 {
275 	struct cx18_dvb *dvb = &stream->dvb;
276 	struct cx18 *cx = stream->cx;
277 	int ret = 0;
278 
279 	switch (cx->card->type) {
280 	case CX18_CARD_HVR_1600_ESMT:
281 	case CX18_CARD_HVR_1600_SAMSUNG:
282 		dvb->fe = dvb_attach(s5h1409_attach,
283 			&hauppauge_hvr1600_config,
284 			&cx->i2c_adap[0]);
285 		if (dvb->fe != NULL) {
286 			dvb_attach(mxl5005s_attach, dvb->fe,
287 				&cx->i2c_adap[0],
288 				&hauppauge_hvr1600_tuner);
289 			ret = 0;
290 		}
291 		break;
292 	default:
293 		/* No Digital Tv Support */
294 		break;
295 	}
296 
297 	if (dvb->fe == NULL) {
298 		CX18_ERR("frontend initialization failed\n");
299 		return -1;
300 	}
301 
302 	ret = dvb_register_frontend(&dvb->dvb_adapter, dvb->fe);
303 	if (ret < 0) {
304 		if (dvb->fe->ops.release)
305 			dvb->fe->ops.release(dvb->fe);
306 		return ret;
307 	}
308 
309 	return ret;
310 }
311