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