Commit | Line | Data |
---|---|---|
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 | ||
26 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | |
27 | ||
28 | static 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 | ||
47 | static 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 | ||
65 | static 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 | ||
77 | int 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 | ||
154 | int 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 | 202 | int 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 |
259 | fail_net_release: |
260 | dvb_net_release(&firesat->dvbnet); | |
261 | firesat->demux.dmx.close(&firesat->demux.dmx); | |
262 | fail_rem_frontend: | |
263 | firesat->demux.dmx.remove_frontend(&firesat->demux.dmx, | |
264 | &firesat->frontend); | |
265 | fail_dmxdev_release: | |
266 | dvb_dmxdev_release(&firesat->dmxdev); | |
267 | fail_dmx_release: | |
268 | dvb_dmx_release(&firesat->demux); | |
269 | fail_unreg_adapter: | |
270 | dvb_unregister_adapter(&firesat->adapter); | |
271 | fail_log: | |
272 | dev_err(dev, "DVB initialization failed\n"); | |
273 | return err; | |
c81c8b68 | 274 | } |
df4846c3 HK |
275 | |
276 |