9e87402289a6465e53668133a4ea4a3ace970995
[linux-2.6-block.git] / drivers / media / dvb / firesat / firesat_dvb.c
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
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>
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
40         //printk(KERN_INFO "%s\n", __func__);
41
42         if (down_interruptible(&firesat->demux_sem))
43                 return NULL;
44
45         for (k = 0; k < 16; k++) {
46                 //printk(KERN_INFO "%s: channel %d: active = %d, pid = 0x%x\n",__func__,k,firesat->channel[k].active,firesat->channel[k].pid);
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
96 //      printk(KERN_INFO "%s (pid %u)\n", __func__, dvbdmxfeed->pid);
97
98         switch (dvbdmxfeed->type) {
99         case DMX_TYPE_TS:
100         case DMX_TYPE_SEC:
101                 break;
102         default:
103                 printk(KERN_ERR "%s: invalid type %u\n",
104                        __func__, dvbdmxfeed->type);
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:
125                         printk(KERN_ERR "%s: invalid pes type %u\n",
126                                __func__, dvbdmxfeed->pes_type);
127                         return -EINVAL;
128                 }
129         } else {
130                 channel = firesat_channel_allocate(firesat);
131         }
132
133         if (!channel) {
134                 printk(KERN_ERR "%s: busy!\n", __func__);
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);
147                 printk(KERN_ERR "%s: could not collect pids!\n", __func__);
148                 return -EINTR;
149         }
150
151         if(dvbdmxfeed->pid == 8192) {
152                 if((k = AVCTuner_GetTS(firesat))) {
153                         firesat_channel_release(firesat, channel);
154                         printk("%s: AVCTuner_GetTS failed with error %d\n",
155                                __func__, k);
156                         return k;
157                 }
158         }
159         else {
160                 if((k = AVCTuner_SetPIDs(firesat, pidc, pids))) {
161                         firesat_channel_release(firesat, channel);
162                         printk("%s: AVCTuner_SetPIDs failed with error %d\n",
163                                __func__, k);
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
178         //printk(KERN_INFO "%s (pid %u)\n", __func__, dvbdmxfeed->pid);
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++)
206                 if (firesat->channel[k].active == 1) {
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;
212                 }
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
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
270                 if ((result = DVB_REGISTER_ADAPTER(firesat->adapter,
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
287                 memset(&firesat->demux, 0, sizeof(struct dvb_demux));
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
360                         firesat_ca_init(firesat);
361
362                 return 0;
363 }
364
365