Commit | Line | Data |
---|---|---|
c81c8b68 GKH |
1 | #include <linux/init.h> |
2 | #include <linux/slab.h> | |
3 | #include <linux/wait.h> | |
4 | #include <linux/module.h> | |
5 | #include <linux/delay.h> | |
6 | #include <linux/time.h> | |
7 | #include <linux/errno.h> | |
8 | #include <linux/interrupt.h> | |
9 | #include <linux/semaphore.h> | |
10 | #include <ieee1394_hotplug.h> | |
11 | #include <nodemgr.h> | |
12 | #include <highlevel.h> | |
13 | #include <ohci1394.h> | |
14 | #include <hosts.h> | |
15 | #include <dvbdev.h> | |
16 | ||
17 | #include "firesat.h" | |
18 | #include "avc_api.h" | |
19 | #include "cmp.h" | |
20 | #include "firesat-rc.h" | |
21 | #include "firesat-ci.h" | |
22 | ||
23 | DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); | |
24 | ||
25 | static struct firesat_channel *firesat_channel_allocate(struct firesat *firesat) | |
26 | { | |
27 | int k; | |
28 | ||
29 | printk(KERN_INFO "%s\n", __func__); | |
30 | ||
31 | if (down_interruptible(&firesat->demux_sem)) | |
32 | return NULL; | |
33 | ||
34 | for (k = 0; k < 16; k++) { | |
35 | printk(KERN_INFO "%s: channel %d: active = %d, pid = 0x%x\n",__func__,k,firesat->channel[k].active,firesat->channel[k].pid); | |
36 | ||
37 | if (firesat->channel[k].active == 0) { | |
38 | firesat->channel[k].active = 1; | |
39 | up(&firesat->demux_sem); | |
40 | return &firesat->channel[k]; | |
41 | } | |
42 | } | |
43 | ||
44 | up(&firesat->demux_sem); | |
45 | return NULL; // no more channels available | |
46 | } | |
47 | ||
48 | static int firesat_channel_collect(struct firesat *firesat, int *pidc, u16 pid[]) | |
49 | { | |
50 | int k, l = 0; | |
51 | ||
52 | if (down_interruptible(&firesat->demux_sem)) | |
53 | return -EINTR; | |
54 | ||
55 | for (k = 0; k < 16; k++) | |
56 | if (firesat->channel[k].active == 1) | |
57 | pid[l++] = firesat->channel[k].pid; | |
58 | ||
59 | up(&firesat->demux_sem); | |
60 | ||
61 | *pidc = l; | |
62 | ||
63 | return 0; | |
64 | } | |
65 | ||
66 | static int firesat_channel_release(struct firesat *firesat, | |
67 | struct firesat_channel *channel) | |
68 | { | |
69 | if (down_interruptible(&firesat->demux_sem)) | |
70 | return -EINTR; | |
71 | ||
72 | channel->active = 0; | |
73 | ||
74 | up(&firesat->demux_sem); | |
75 | return 0; | |
76 | } | |
77 | ||
78 | int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed) | |
79 | { | |
80 | struct firesat *firesat = (struct firesat*)dvbdmxfeed->demux->priv; | |
81 | struct firesat_channel *channel; | |
82 | int pidc,k; | |
83 | u16 pids[16]; | |
84 | ||
85 | printk(KERN_INFO "%s (pid %u)\n",__func__,dvbdmxfeed->pid); | |
86 | ||
87 | switch (dvbdmxfeed->type) { | |
88 | case DMX_TYPE_TS: | |
89 | case DMX_TYPE_SEC: | |
90 | break; | |
91 | default: | |
92 | printk("%s: invalid type %u\n",__func__,dvbdmxfeed->type); | |
93 | return -EINVAL; | |
94 | } | |
95 | ||
96 | if (dvbdmxfeed->type == DMX_TYPE_TS) { | |
97 | switch (dvbdmxfeed->pes_type) { | |
98 | case DMX_TS_PES_VIDEO: | |
99 | case DMX_TS_PES_AUDIO: | |
100 | case DMX_TS_PES_TELETEXT: | |
101 | case DMX_TS_PES_PCR: | |
102 | case DMX_TS_PES_OTHER: | |
103 | //Dirty fix to keep firesat->channel pid-list up to date | |
104 | for(k=0;k<16;k++){ | |
105 | if(firesat->channel[k].active == 0) | |
106 | firesat->channel[k].pid = | |
107 | dvbdmxfeed->pid; | |
108 | break; | |
109 | } | |
110 | channel = firesat_channel_allocate(firesat); | |
111 | break; | |
112 | default: | |
113 | printk("%s: invalid pes type %u\n",__func__, dvbdmxfeed->pes_type); | |
114 | return -EINVAL; | |
115 | } | |
116 | } else { | |
117 | channel = firesat_channel_allocate(firesat); | |
118 | } | |
119 | ||
120 | if (!channel) { | |
121 | printk("%s: busy!\n", __func__); | |
122 | return -EBUSY; | |
123 | } | |
124 | ||
125 | dvbdmxfeed->priv = channel; | |
126 | ||
127 | channel->dvbdmxfeed = dvbdmxfeed; | |
128 | channel->pid = dvbdmxfeed->pid; | |
129 | channel->type = dvbdmxfeed->type; | |
130 | channel->firesat = firesat; | |
131 | ||
132 | if (firesat_channel_collect(firesat, &pidc, pids)) { | |
133 | firesat_channel_release(firesat, channel); | |
134 | return -EINTR; | |
135 | } | |
136 | ||
137 | if(dvbdmxfeed->pid == 8192) { | |
138 | if((k=AVCTuner_GetTS(firesat))) { | |
139 | firesat_channel_release(firesat, channel); | |
140 | printk("%s: AVCTuner_GetTS failed with error %d\n", | |
141 | __func__,k); | |
142 | return k; | |
143 | } | |
144 | } | |
145 | else { | |
146 | if((k=AVCTuner_SetPIDs(firesat, pidc, pids))) { | |
147 | firesat_channel_release(firesat, channel); | |
148 | printk("%s: AVCTuner_SetPIDs failed with error %d\n", | |
149 | __func__,k); | |
150 | return k; | |
151 | } | |
152 | } | |
153 | ||
154 | return 0; | |
155 | } | |
156 | ||
157 | int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed) | |
158 | { | |
159 | struct dvb_demux *demux = dvbdmxfeed->demux; | |
160 | struct firesat *firesat = (struct firesat*)demux->priv; | |
161 | int k, l = 0; | |
162 | u16 pids[16]; | |
163 | ||
164 | printk(KERN_INFO "%s (pid %u)\n", __func__, dvbdmxfeed->pid); | |
165 | ||
166 | if (dvbdmxfeed->type == DMX_TYPE_TS && !((dvbdmxfeed->ts_type & TS_PACKET) && | |
167 | (demux->dmx.frontend->source != DMX_MEMORY_FE))) { | |
168 | ||
169 | if (dvbdmxfeed->ts_type & TS_DECODER) { | |
170 | ||
171 | if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER || | |
172 | !demux->pesfilter[dvbdmxfeed->pes_type]) | |
173 | ||
174 | return -EINVAL; | |
175 | ||
176 | demux->pids[dvbdmxfeed->pes_type] |= 0x8000; | |
177 | demux->pesfilter[dvbdmxfeed->pes_type] = 0; | |
178 | } | |
179 | ||
180 | if (!(dvbdmxfeed->ts_type & TS_DECODER && | |
181 | dvbdmxfeed->pes_type < DMX_TS_PES_OTHER)) | |
182 | ||
183 | return 0; | |
184 | } | |
185 | ||
186 | if (down_interruptible(&firesat->demux_sem)) | |
187 | return -EINTR; | |
188 | ||
189 | ||
190 | // list except channel to be removed | |
191 | for (k = 0; k < 16; k++) | |
192 | if (firesat->channel[k].active == 1) | |
193 | if (&firesat->channel[k] != | |
194 | (struct firesat_channel *)dvbdmxfeed->priv) | |
195 | pids[l++] = firesat->channel[k].pid; | |
196 | else | |
197 | firesat->channel[k].active = 0; | |
198 | ||
199 | if ((k = AVCTuner_SetPIDs(firesat, l, pids))) { | |
200 | up(&firesat->demux_sem); | |
201 | return k; | |
202 | } | |
203 | ||
204 | ((struct firesat_channel *)dvbdmxfeed->priv)->active = 0; | |
205 | ||
206 | up(&firesat->demux_sem); | |
207 | ||
208 | return 0; | |
209 | } | |
210 | ||
211 | int firesat_dvbdev_init(struct firesat *firesat, | |
212 | struct device *dev, | |
213 | struct dvb_frontend *fe) | |
214 | { | |
215 | int result; | |
216 | ||
217 | firesat->has_ci = 1; // TEMP workaround | |
218 | ||
219 | #if 0 | |
220 | switch (firesat->type) { | |
221 | case FireSAT_DVB_S: | |
222 | firesat->model_name = "FireSAT DVB-S"; | |
223 | firesat->frontend_info = &firesat_S_frontend_info; | |
224 | break; | |
225 | case FireSAT_DVB_C: | |
226 | firesat->model_name = "FireSAT DVB-C"; | |
227 | firesat->frontend_info = &firesat_C_frontend_info; | |
228 | break; | |
229 | case FireSAT_DVB_T: | |
230 | firesat->model_name = "FireSAT DVB-T"; | |
231 | firesat->frontend_info = &firesat_T_frontend_info; | |
232 | break; | |
233 | default: | |
234 | printk("%s: unknown model type 0x%x on subunit %d!\n", | |
235 | __func__, firesat->type,subunit); | |
236 | firesat->model_name = "Unknown"; | |
237 | firesat->frontend_info = NULL; | |
238 | } | |
239 | #endif | |
240 | /* // ------- CRAP ----------- | |
241 | if (!firesat->frontend_info) { | |
242 | spin_lock_irqsave(&firesat_list_lock, flags); | |
243 | list_del(&firesat->list); | |
244 | spin_unlock_irqrestore(&firesat_list_lock, flags); | |
245 | kfree(firesat); | |
246 | continue; | |
247 | } | |
248 | */ | |
249 | //initialising firesat->adapter before calling dvb_register_adapter | |
250 | if (!(firesat->adapter = kmalloc(sizeof (struct dvb_adapter), GFP_KERNEL))) { | |
251 | printk("%s: couldn't allocate memory.\n", __func__); | |
252 | kfree(firesat->adapter); | |
253 | kfree(firesat); | |
254 | return -ENOMEM; | |
255 | } | |
256 | ||
257 | if ((result = dvb_register_adapter(firesat->adapter, | |
258 | firesat->model_name, | |
259 | THIS_MODULE, | |
260 | dev, adapter_nr)) < 0) { | |
261 | ||
262 | printk("%s: dvb_register_adapter failed: error %d\n", __func__, result); | |
263 | #if 0 | |
264 | /* ### cleanup */ | |
265 | spin_lock_irqsave(&firesat_list_lock, flags); | |
266 | list_del(&firesat->list); | |
267 | spin_unlock_irqrestore(&firesat_list_lock, flags); | |
268 | #endif | |
269 | kfree(firesat); | |
270 | ||
271 | return result; | |
272 | } | |
273 | ||
274 | firesat->demux.dmx.capabilities = 0/*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/; | |
275 | ||
276 | firesat->demux.priv = (void *)firesat; | |
277 | firesat->demux.filternum = 16; | |
278 | firesat->demux.feednum = 16; | |
279 | firesat->demux.start_feed = firesat_start_feed; | |
280 | firesat->demux.stop_feed = firesat_stop_feed; | |
281 | firesat->demux.write_to_decoder = NULL; | |
282 | ||
283 | if ((result = dvb_dmx_init(&firesat->demux)) < 0) { | |
284 | printk("%s: dvb_dmx_init failed: error %d\n", __func__, | |
285 | result); | |
286 | ||
287 | dvb_unregister_adapter(firesat->adapter); | |
288 | ||
289 | return result; | |
290 | } | |
291 | ||
292 | firesat->dmxdev.filternum = 16; | |
293 | firesat->dmxdev.demux = &firesat->demux.dmx; | |
294 | firesat->dmxdev.capabilities = 0; | |
295 | ||
296 | if ((result = dvb_dmxdev_init(&firesat->dmxdev, firesat->adapter)) < 0) { | |
297 | printk("%s: dvb_dmxdev_init failed: error %d\n", | |
298 | __func__, result); | |
299 | ||
300 | dvb_dmx_release(&firesat->demux); | |
301 | dvb_unregister_adapter(firesat->adapter); | |
302 | ||
303 | return result; | |
304 | } | |
305 | ||
306 | firesat->frontend.source = DMX_FRONTEND_0; | |
307 | ||
308 | if ((result = firesat->demux.dmx.add_frontend(&firesat->demux.dmx, | |
309 | &firesat->frontend)) < 0) { | |
310 | printk("%s: dvb_dmx_init failed: error %d\n", __func__, | |
311 | result); | |
312 | ||
313 | dvb_dmxdev_release(&firesat->dmxdev); | |
314 | dvb_dmx_release(&firesat->demux); | |
315 | dvb_unregister_adapter(firesat->adapter); | |
316 | ||
317 | return result; | |
318 | } | |
319 | ||
320 | if ((result = firesat->demux.dmx.connect_frontend(&firesat->demux.dmx, | |
321 | &firesat->frontend)) < 0) { | |
322 | printk("%s: dvb_dmx_init failed: error %d\n", __func__, | |
323 | result); | |
324 | ||
325 | firesat->demux.dmx.remove_frontend(&firesat->demux.dmx, &firesat->frontend); | |
326 | dvb_dmxdev_release(&firesat->dmxdev); | |
327 | dvb_dmx_release(&firesat->demux); | |
328 | dvb_unregister_adapter(firesat->adapter); | |
329 | ||
330 | return result; | |
331 | } | |
332 | ||
333 | dvb_net_init(firesat->adapter, &firesat->dvbnet, &firesat->demux.dmx); | |
334 | ||
335 | // fe->ops = firesat_ops; | |
336 | // fe->dvb = firesat->adapter; | |
337 | firesat_frontend_attach(firesat, fe); | |
338 | ||
339 | fe->sec_priv = firesat; //IMPORTANT, functions depend on this!!! | |
340 | if ((result= dvb_register_frontend(firesat->adapter, fe)) < 0) { | |
341 | printk("%s: dvb_register_frontend_new failed: error %d\n", __func__, result); | |
342 | /* ### cleanup */ | |
343 | return result; | |
344 | } | |
345 | ||
346 | if (firesat->has_ci) | |
347 | firesat_ca_init(firesat); | |
348 | ||
349 | return 0; | |
350 | } |