V4L/DVB (7786): cx18: new driver for the Conexant CX23418 MPEG encoder chip
[safe/jmp/linux-2.6] / drivers / media / video / cx18 / cx18-dvb.c
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 }