firedtv: cleanups and minor fixes
[linux-2.6-block.git] / drivers / media / dvb / firesat / firesat_dvb.c
CommitLineData
df4846c3 1/*
612262a5 2 * FireDTV driver (formerly known as FireSAT)
df4846c3 3 *
612262a5
SR
4 * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
5 * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
df4846c3
HK
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
c81c8b68 13#include <linux/errno.h>
612262a5
SR
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>
c81c8b68
GKH
20#include <dvbdev.h>
21
c81c8b68 22#include "avc_api.h"
612262a5 23#include "firesat.h"
c81c8b68
GKH
24#include "firesat-ci.h"
25
26DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
27
28static struct firesat_channel *firesat_channel_allocate(struct firesat *firesat)
29{
612262a5 30 struct firesat_channel *c = NULL;
c81c8b68
GKH
31 int k;
32
612262a5 33 if (mutex_lock_interruptible(&firesat->demux_mutex))
c81c8b68
GKH
34 return NULL;
35
612262a5 36 for (k = 0; k < 16; k++)
8ae83cdf
SR
37 if (!firesat->channel[k].active) {
38 firesat->channel[k].active = true;
612262a5
SR
39 c = &firesat->channel[k];
40 break;
c81c8b68 41 }
c81c8b68 42
612262a5
SR
43 mutex_unlock(&firesat->demux_mutex);
44 return c;
c81c8b68
GKH
45}
46
47static int firesat_channel_collect(struct firesat *firesat, int *pidc, u16 pid[])
48{
49 int k, l = 0;
50
612262a5 51 if (mutex_lock_interruptible(&firesat->demux_mutex))
c81c8b68
GKH
52 return -EINTR;
53
54 for (k = 0; k < 16; k++)
8ae83cdf 55 if (firesat->channel[k].active)
c81c8b68
GKH
56 pid[l++] = firesat->channel[k].pid;
57
612262a5 58 mutex_unlock(&firesat->demux_mutex);
c81c8b68
GKH
59
60 *pidc = l;
61
62 return 0;
63}
64
65static int firesat_channel_release(struct firesat *firesat,
66 struct firesat_channel *channel)
67{
612262a5 68 if (mutex_lock_interruptible(&firesat->demux_mutex))
c81c8b68
GKH
69 return -EINTR;
70
8ae83cdf 71 channel->active = false;
c81c8b68 72
612262a5 73 mutex_unlock(&firesat->demux_mutex);
c81c8b68
GKH
74 return 0;
75}
76
77int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed)
78{
79 struct firesat *firesat = (struct firesat*)dvbdmxfeed->demux->priv;
80 struct firesat_channel *channel;
81 int pidc,k;
82 u16 pids[16];
83
c81c8b68
GKH
84 switch (dvbdmxfeed->type) {
85 case DMX_TYPE_TS:
86 case DMX_TYPE_SEC:
87 break;
88 default:
df4846c3
HK
89 printk(KERN_ERR "%s: invalid type %u\n",
90 __func__, dvbdmxfeed->type);
c81c8b68
GKH
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 firesat->channel pid-list up to date
102 for(k=0;k<16;k++){
8ae83cdf 103 if (!firesat->channel[k].active)
c81c8b68
GKH
104 firesat->channel[k].pid =
105 dvbdmxfeed->pid;
106 break;
107 }
108 channel = firesat_channel_allocate(firesat);
109 break;
110 default:
df4846c3
HK
111 printk(KERN_ERR "%s: invalid pes type %u\n",
112 __func__, dvbdmxfeed->pes_type);
c81c8b68
GKH
113 return -EINVAL;
114 }
115 } else {
116 channel = firesat_channel_allocate(firesat);
117 }
118
119 if (!channel) {
df4846c3 120 printk(KERN_ERR "%s: busy!\n", __func__);
c81c8b68
GKH
121 return -EBUSY;
122 }
123
124 dvbdmxfeed->priv = channel;
c81c8b68 125 channel->pid = dvbdmxfeed->pid;
c81c8b68
GKH
126
127 if (firesat_channel_collect(firesat, &pidc, pids)) {
128 firesat_channel_release(firesat, channel);
df4846c3 129 printk(KERN_ERR "%s: could not collect pids!\n", __func__);
c81c8b68
GKH
130 return -EINTR;
131 }
132
8ae83cdf
SR
133 if (dvbdmxfeed->pid == 8192) {
134 k = avc_tuner_get_ts(firesat);
135 if (k) {
c81c8b68
GKH
136 firesat_channel_release(firesat, channel);
137 printk("%s: AVCTuner_GetTS failed with error %d\n",
df4846c3 138 __func__, k);
c81c8b68
GKH
139 return k;
140 }
8ae83cdf
SR
141 } else {
142 k = avc_tuner_set_pids(firesat, pidc, pids);
143 if (k) {
c81c8b68
GKH
144 firesat_channel_release(firesat, channel);
145 printk("%s: AVCTuner_SetPIDs failed with error %d\n",
df4846c3 146 __func__, k);
c81c8b68
GKH
147 return k;
148 }
149 }
150
151 return 0;
152}
153
154int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
155{
156 struct dvb_demux *demux = dvbdmxfeed->demux;
157 struct firesat *firesat = (struct firesat*)demux->priv;
612262a5
SR
158 struct firesat_channel *c = dvbdmxfeed->priv;
159 int k, l;
c81c8b68
GKH
160 u16 pids[16];
161
c81c8b68
GKH
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;
8ae83cdf 173 demux->pesfilter[dvbdmxfeed->pes_type] = NULL;
c81c8b68
GKH
174 }
175
176 if (!(dvbdmxfeed->ts_type & TS_DECODER &&
177 dvbdmxfeed->pes_type < DMX_TS_PES_OTHER))
178
179 return 0;
180 }
181
612262a5 182 if (mutex_lock_interruptible(&firesat->demux_mutex))
c81c8b68
GKH
183 return -EINTR;
184
612262a5
SR
185 /* list except channel to be removed */
186 for (k = 0, l = 0; k < 16; k++)
8ae83cdf 187 if (firesat->channel[k].active) {
612262a5 188 if (&firesat->channel[k] != c)
c81c8b68
GKH
189 pids[l++] = firesat->channel[k].pid;
190 else
8ae83cdf 191 firesat->channel[k].active = false;
df4846c3 192 }
c81c8b68 193
8ae83cdf 194 k = avc_tuner_set_pids(firesat, l, pids);
612262a5 195 if (!k)
8ae83cdf 196 c->active = false;
c81c8b68 197
612262a5
SR
198 mutex_unlock(&firesat->demux_mutex);
199 return k;
c81c8b68
GKH
200}
201
8ae83cdf 202int firesat_dvbdev_init(struct firesat *firesat, struct device *dev)
c81c8b68 203{
8ae83cdf 204 int err;
c81c8b68 205
8ae83cdf
SR
206 err = DVB_REGISTER_ADAPTER(&firesat->adapter,
207 firedtv_model_names[firesat->type],
208 THIS_MODULE, dev, adapter_nr);
209 if (err)
210 goto fail_log;
c81c8b68 211
8ae83cdf
SR
212 /*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/
213 firesat->demux.dmx.capabilities = 0;
c81c8b68 214
8ae83cdf
SR
215 firesat->demux.priv = (void *)firesat;
216 firesat->demux.filternum = 16;
217 firesat->demux.feednum = 16;
218 firesat->demux.start_feed = firesat_start_feed;
219 firesat->demux.stop_feed = firesat_stop_feed;
220 firesat->demux.write_to_decoder = NULL;
c81c8b68 221
8ae83cdf
SR
222 err = dvb_dmx_init(&firesat->demux);
223 if (err)
224 goto fail_unreg_adapter;
c81c8b68 225
8ae83cdf
SR
226 firesat->dmxdev.filternum = 16;
227 firesat->dmxdev.demux = &firesat->demux.dmx;
228 firesat->dmxdev.capabilities = 0;
c81c8b68 229
8ae83cdf
SR
230 err = dvb_dmxdev_init(&firesat->dmxdev, &firesat->adapter);
231 if (err)
232 goto fail_dmx_release;
c81c8b68 233
8ae83cdf 234 firesat->frontend.source = DMX_FRONTEND_0;
c81c8b68 235
8ae83cdf
SR
236 err = firesat->demux.dmx.add_frontend(&firesat->demux.dmx,
237 &firesat->frontend);
238 if (err)
239 goto fail_dmxdev_release;
c81c8b68 240
8ae83cdf
SR
241 err = firesat->demux.dmx.connect_frontend(&firesat->demux.dmx,
242 &firesat->frontend);
243 if (err)
244 goto fail_rem_frontend;
c81c8b68 245
8ae83cdf 246 dvb_net_init(&firesat->adapter, &firesat->dvbnet, &firesat->demux.dmx);
c81c8b68 247
8ae83cdf
SR
248 firesat_frontend_init(firesat);
249 err = dvb_register_frontend(&firesat->adapter, &firesat->fe);
250 if (err)
251 goto fail_net_release;
c81c8b68 252
8ae83cdf
SR
253 err = firesat_ca_register(firesat);
254 if (err)
255 dev_info(dev, "Conditional Access Module not enabled\n");
c81c8b68 256
8ae83cdf 257 return 0;
c81c8b68 258
8ae83cdf
SR
259fail_net_release:
260 dvb_net_release(&firesat->dvbnet);
261 firesat->demux.dmx.close(&firesat->demux.dmx);
262fail_rem_frontend:
263 firesat->demux.dmx.remove_frontend(&firesat->demux.dmx,
264 &firesat->frontend);
265fail_dmxdev_release:
266 dvb_dmxdev_release(&firesat->dmxdev);
267fail_dmx_release:
268 dvb_dmx_release(&firesat->demux);
269fail_unreg_adapter:
270 dvb_unregister_adapter(&firesat->adapter);
271fail_log:
272 dev_err(dev, "DVB initialization failed\n");
273 return err;
c81c8b68 274}
df4846c3
HK
275
276