DVB: add firesat driver
[linux-2.6-block.git] / drivers / media / dvb / firesat / firesat_dvb.c
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 }