firesat: update isochronous interface, add CI support
[linux-2.6/mini2440.git] / drivers / media / dvb / firesat / firesat_dvb.c
blob9e87402289a6465e53668133a4ea4a3ace970995
1 /*
2 * FireSAT DVB driver
4 * Copyright (c) ?
5 * Copyright (c) 2008 Henrik Kurelid <henrik@kurelid.se>
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.
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>
28 #include "firesat.h"
29 #include "avc_api.h"
30 #include "cmp.h"
31 #include "firesat-rc.h"
32 #include "firesat-ci.h"
34 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
36 static struct firesat_channel *firesat_channel_allocate(struct firesat *firesat)
38 int k;
40 //printk(KERN_INFO "%s\n", __func__);
42 if (down_interruptible(&firesat->demux_sem))
43 return NULL;
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);
48 if (firesat->channel[k].active == 0) {
49 firesat->channel[k].active = 1;
50 up(&firesat->demux_sem);
51 return &firesat->channel[k];
55 up(&firesat->demux_sem);
56 return NULL; // no more channels available
59 static int firesat_channel_collect(struct firesat *firesat, int *pidc, u16 pid[])
61 int k, l = 0;
63 if (down_interruptible(&firesat->demux_sem))
64 return -EINTR;
66 for (k = 0; k < 16; k++)
67 if (firesat->channel[k].active == 1)
68 pid[l++] = firesat->channel[k].pid;
70 up(&firesat->demux_sem);
72 *pidc = l;
74 return 0;
77 static int firesat_channel_release(struct firesat *firesat,
78 struct firesat_channel *channel)
80 if (down_interruptible(&firesat->demux_sem))
81 return -EINTR;
83 channel->active = 0;
85 up(&firesat->demux_sem);
86 return 0;
89 int firesat_start_feed(struct dvb_demux_feed *dvbdmxfeed)
91 struct firesat *firesat = (struct firesat*)dvbdmxfeed->demux->priv;
92 struct firesat_channel *channel;
93 int pidc,k;
94 u16 pids[16];
96 // printk(KERN_INFO "%s (pid %u)\n", __func__, dvbdmxfeed->pid);
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;
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;
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;
129 } else {
130 channel = firesat_channel_allocate(firesat);
133 if (!channel) {
134 printk(KERN_ERR "%s: busy!\n", __func__);
135 return -EBUSY;
138 dvbdmxfeed->priv = channel;
140 channel->dvbdmxfeed = dvbdmxfeed;
141 channel->pid = dvbdmxfeed->pid;
142 channel->type = dvbdmxfeed->type;
143 channel->firesat = firesat;
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;
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;
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;
168 return 0;
171 int firesat_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
173 struct dvb_demux *demux = dvbdmxfeed->demux;
174 struct firesat *firesat = (struct firesat*)demux->priv;
175 int k, l = 0;
176 u16 pids[16];
178 //printk(KERN_INFO "%s (pid %u)\n", __func__, dvbdmxfeed->pid);
180 if (dvbdmxfeed->type == DMX_TYPE_TS && !((dvbdmxfeed->ts_type & TS_PACKET) &&
181 (demux->dmx.frontend->source != DMX_MEMORY_FE))) {
183 if (dvbdmxfeed->ts_type & TS_DECODER) {
185 if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER ||
186 !demux->pesfilter[dvbdmxfeed->pes_type])
188 return -EINVAL;
190 demux->pids[dvbdmxfeed->pes_type] |= 0x8000;
191 demux->pesfilter[dvbdmxfeed->pes_type] = 0;
194 if (!(dvbdmxfeed->ts_type & TS_DECODER &&
195 dvbdmxfeed->pes_type < DMX_TS_PES_OTHER))
197 return 0;
200 if (down_interruptible(&firesat->demux_sem))
201 return -EINTR;
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;
214 if ((k = AVCTuner_SetPIDs(firesat, l, pids))) {
215 up(&firesat->demux_sem);
216 return k;
219 ((struct firesat_channel *)dvbdmxfeed->priv)->active = 0;
221 up(&firesat->demux_sem);
223 return 0;
226 int firesat_dvbdev_init(struct firesat *firesat,
227 struct device *dev,
228 struct dvb_frontend *fe)
230 int result;
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;
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;
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;
270 if ((result = DVB_REGISTER_ADAPTER(firesat->adapter,
271 firesat->model_name,
272 THIS_MODULE,
273 dev, adapter_nr)) < 0) {
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);
284 return result;
287 memset(&firesat->demux, 0, sizeof(struct dvb_demux));
288 firesat->demux.dmx.capabilities = 0/*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/;
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;
297 if ((result = dvb_dmx_init(&firesat->demux)) < 0) {
298 printk("%s: dvb_dmx_init failed: error %d\n", __func__,
299 result);
301 dvb_unregister_adapter(firesat->adapter);
303 return result;
306 firesat->dmxdev.filternum = 16;
307 firesat->dmxdev.demux = &firesat->demux.dmx;
308 firesat->dmxdev.capabilities = 0;
310 if ((result = dvb_dmxdev_init(&firesat->dmxdev, firesat->adapter)) < 0) {
311 printk("%s: dvb_dmxdev_init failed: error %d\n",
312 __func__, result);
314 dvb_dmx_release(&firesat->demux);
315 dvb_unregister_adapter(firesat->adapter);
317 return result;
320 firesat->frontend.source = DMX_FRONTEND_0;
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);
327 dvb_dmxdev_release(&firesat->dmxdev);
328 dvb_dmx_release(&firesat->demux);
329 dvb_unregister_adapter(firesat->adapter);
331 return result;
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);
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);
344 return result;
347 dvb_net_init(firesat->adapter, &firesat->dvbnet, &firesat->demux.dmx);
349 // fe->ops = firesat_ops;
350 // fe->dvb = firesat->adapter;
351 firesat_frontend_attach(firesat, fe);
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;
360 firesat_ca_init(firesat);
362 return 0;