firedtv-dvb.c revision a70f81c1c0dac113ac4705e7701e2676e67905cd
1/*
2 * FireDTV driver (formerly known as FireSAT)
3 *
4 * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
5 * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
6 *
7 *	This program is free software; you can redistribute it and/or
8 *	modify it under the terms of the GNU General Public License as
9 *	published by the Free Software Foundation; either version 2 of
10 *	the License, or (at your option) any later version.
11 */
12
13#include <linux/errno.h>
14#include <linux/kernel.h>
15#include <linux/mutex.h>
16#include <linux/types.h>
17
18#include <dvb_demux.h>
19#include <dvb_frontend.h>
20#include <dvbdev.h>
21
22#include "avc.h"
23#include "firedtv.h"
24#include "firedtv-ci.h"
25
26DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
27
28static struct firedtv_channel *fdtv_channel_allocate(struct firedtv *fdtv)
29{
30	struct firedtv_channel *c = NULL;
31	int k;
32
33	if (mutex_lock_interruptible(&fdtv->demux_mutex))
34		return NULL;
35
36	for (k = 0; k < 16; k++)
37		if (!fdtv->channel[k].active) {
38			fdtv->channel[k].active = true;
39			c = &fdtv->channel[k];
40			break;
41		}
42
43	mutex_unlock(&fdtv->demux_mutex);
44	return c;
45}
46
47static int fdtv_channel_collect(struct firedtv *fdtv, int *pidc, u16 pid[])
48{
49	int k, l = 0;
50
51	if (mutex_lock_interruptible(&fdtv->demux_mutex))
52		return -EINTR;
53
54	for (k = 0; k < 16; k++)
55		if (fdtv->channel[k].active)
56			pid[l++] = fdtv->channel[k].pid;
57
58	mutex_unlock(&fdtv->demux_mutex);
59
60	*pidc = l;
61
62	return 0;
63}
64
65static int fdtv_channel_release(struct firedtv *fdtv,
66				   struct firedtv_channel *channel)
67{
68	if (mutex_lock_interruptible(&fdtv->demux_mutex))
69		return -EINTR;
70
71	channel->active = false;
72
73	mutex_unlock(&fdtv->demux_mutex);
74	return 0;
75}
76
77int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed)
78{
79	struct firedtv *fdtv = (struct firedtv*)dvbdmxfeed->demux->priv;
80	struct firedtv_channel *channel;
81	int pidc,k;
82	u16 pids[16];
83
84	switch (dvbdmxfeed->type) {
85	case DMX_TYPE_TS:
86	case DMX_TYPE_SEC:
87		break;
88	default:
89		printk(KERN_ERR "%s: invalid type %u\n",
90		       __func__, dvbdmxfeed->type);
91		return -EINVAL;
92	}
93
94	if (dvbdmxfeed->type == DMX_TYPE_TS) {
95		switch (dvbdmxfeed->pes_type) {
96		case DMX_TS_PES_VIDEO:
97		case DMX_TS_PES_AUDIO:
98		case DMX_TS_PES_TELETEXT:
99		case DMX_TS_PES_PCR:
100		case DMX_TS_PES_OTHER:
101			//Dirty fix to keep fdtv->channel pid-list up to date
102			for(k=0;k<16;k++){
103				if (!fdtv->channel[k].active)
104					fdtv->channel[k].pid =
105						dvbdmxfeed->pid;
106					break;
107			}
108			channel = fdtv_channel_allocate(fdtv);
109			break;
110		default:
111			printk(KERN_ERR "%s: invalid pes type %u\n",
112			       __func__, dvbdmxfeed->pes_type);
113			return -EINVAL;
114		}
115	} else {
116		channel = fdtv_channel_allocate(fdtv);
117	}
118
119	if (!channel) {
120		printk(KERN_ERR "%s: busy!\n", __func__);
121		return -EBUSY;
122	}
123
124	dvbdmxfeed->priv = channel;
125	channel->pid = dvbdmxfeed->pid;
126
127	if (fdtv_channel_collect(fdtv, &pidc, pids)) {
128		fdtv_channel_release(fdtv, channel);
129		printk(KERN_ERR "%s: could not collect pids!\n", __func__);
130		return -EINTR;
131	}
132
133	if (dvbdmxfeed->pid == 8192) {
134		k = avc_tuner_get_ts(fdtv);
135		if (k) {
136			fdtv_channel_release(fdtv, channel);
137			printk("%s: AVCTuner_GetTS failed with error %d\n",
138			       __func__, k);
139			return k;
140		}
141	} else {
142		k = avc_tuner_set_pids(fdtv, pidc, pids);
143		if (k) {
144			fdtv_channel_release(fdtv, channel);
145			printk("%s: AVCTuner_SetPIDs failed with error %d\n",
146			       __func__, k);
147			return k;
148		}
149	}
150
151	return 0;
152}
153
154int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
155{
156	struct dvb_demux *demux = dvbdmxfeed->demux;
157	struct firedtv *fdtv = (struct firedtv*)demux->priv;
158	struct firedtv_channel *c = dvbdmxfeed->priv;
159	int k, l;
160	u16 pids[16];
161
162	if (dvbdmxfeed->type == DMX_TYPE_TS && !((dvbdmxfeed->ts_type & TS_PACKET) &&
163				(demux->dmx.frontend->source != DMX_MEMORY_FE))) {
164
165		if (dvbdmxfeed->ts_type & TS_DECODER) {
166
167			if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER ||
168				!demux->pesfilter[dvbdmxfeed->pes_type])
169
170				return -EINVAL;
171
172			demux->pids[dvbdmxfeed->pes_type] |= 0x8000;
173			demux->pesfilter[dvbdmxfeed->pes_type] = NULL;
174		}
175
176		if (!(dvbdmxfeed->ts_type & TS_DECODER &&
177			dvbdmxfeed->pes_type < DMX_TS_PES_OTHER))
178
179			return 0;
180	}
181
182	if (mutex_lock_interruptible(&fdtv->demux_mutex))
183		return -EINTR;
184
185	/* list except channel to be removed */
186	for (k = 0, l = 0; k < 16; k++)
187		if (fdtv->channel[k].active) {
188			if (&fdtv->channel[k] != c)
189				pids[l++] = fdtv->channel[k].pid;
190			else
191				fdtv->channel[k].active = false;
192		}
193
194	k = avc_tuner_set_pids(fdtv, l, pids);
195	if (!k)
196		c->active = false;
197
198	mutex_unlock(&fdtv->demux_mutex);
199	return k;
200}
201
202int fdtv_dvbdev_init(struct firedtv *fdtv, struct device *dev)
203{
204	int err;
205
206	err = DVB_REGISTER_ADAPTER(&fdtv->adapter,
207				   fdtv_model_names[fdtv->type],
208				   THIS_MODULE, dev, adapter_nr);
209	if (err < 0)
210		goto fail_log;
211
212	/*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/
213	fdtv->demux.dmx.capabilities = 0;
214
215	fdtv->demux.priv	= fdtv;
216	fdtv->demux.filternum	= 16;
217	fdtv->demux.feednum	= 16;
218	fdtv->demux.start_feed	= fdtv_start_feed;
219	fdtv->demux.stop_feed	= fdtv_stop_feed;
220	fdtv->demux.write_to_decoder = NULL;
221
222	err = dvb_dmx_init(&fdtv->demux);
223	if (err)
224		goto fail_unreg_adapter;
225
226	fdtv->dmxdev.filternum	= 16;
227	fdtv->dmxdev.demux		= &fdtv->demux.dmx;
228	fdtv->dmxdev.capabilities	= 0;
229
230	err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter);
231	if (err)
232		goto fail_dmx_release;
233
234	fdtv->frontend.source = DMX_FRONTEND_0;
235
236	err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx,
237					      &fdtv->frontend);
238	if (err)
239		goto fail_dmxdev_release;
240
241	err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx,
242						  &fdtv->frontend);
243	if (err)
244		goto fail_rem_frontend;
245
246	dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx);
247
248	fdtv_frontend_init(fdtv);
249	err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe);
250	if (err)
251		goto fail_net_release;
252
253	err = fdtv_ca_register(fdtv);
254	if (err)
255		dev_info(dev, "Conditional Access Module not enabled\n");
256
257	return 0;
258
259fail_net_release:
260	dvb_net_release(&fdtv->dvbnet);
261	fdtv->demux.dmx.close(&fdtv->demux.dmx);
262fail_rem_frontend:
263	fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx,
264					   &fdtv->frontend);
265fail_dmxdev_release:
266	dvb_dmxdev_release(&fdtv->dmxdev);
267fail_dmx_release:
268	dvb_dmx_release(&fdtv->demux);
269fail_unreg_adapter:
270	dvb_unregister_adapter(&fdtv->adapter);
271fail_log:
272	dev_err(dev, "DVB initialization failed\n");
273	return err;
274}
275
276
277