the epgcache can now handle more then one channel(transponder),
[enigma2.git] / lib / dvb / dvb.cpp
1 #include <lib/dvb/idvb.h>
2 #include <lib/base/eerror.h>
3 #include <lib/dvb/dvb.h>
4 #include <lib/dvb/sec.h>
5 #include <errno.h>
6
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <unistd.h>
10
11 DEFINE_REF(eDVBRegisteredFrontend);
12 DEFINE_REF(eDVBRegisteredDemux);
13
14 DEFINE_REF(eDVBAllocatedFrontend);
15
16 eDVBAllocatedFrontend::eDVBAllocatedFrontend(eDVBRegisteredFrontend *fe): m_fe(fe)
17 {
18         m_fe->m_inuse++;
19 }
20
21 eDVBAllocatedFrontend::~eDVBAllocatedFrontend()
22 {
23         --m_fe->m_inuse;
24 }
25
26 DEFINE_REF(eDVBAllocatedDemux);
27
28 eDVBAllocatedDemux::eDVBAllocatedDemux(eDVBRegisteredDemux *demux): m_demux(demux)
29 {
30         m_demux->m_inuse++;
31 }
32
33 eDVBAllocatedDemux::~eDVBAllocatedDemux()
34 {
35         --m_demux->m_inuse;
36 }
37
38 DEFINE_REF(eDVBResourceManager);
39
40 eDVBResourceManager *eDVBResourceManager::instance;
41
42 eDVBResourceManager::eDVBResourceManager()
43 {
44         avail = 1;
45         busy = 0;
46         m_sec = new eDVBSatelliteEquipmentControl;
47         if (!instance)
48                 instance = this;
49                 
50                 /* search available adapters... */
51
52                 // add linux devices
53         
54         int num_adapter = 0;
55         while (eDVBAdapterLinux::exist(num_adapter))
56         {
57                 addAdapter(new eDVBAdapterLinux(num_adapter));
58                 num_adapter++;
59         }
60         
61         eDebug("found %d adapter, %d frontends and %d demux", 
62                 m_adapter.size(), m_frontend.size(), m_demux.size());
63 }
64
65
66 DEFINE_REF(eDVBAdapterLinux);
67 eDVBAdapterLinux::eDVBAdapterLinux(int nr): m_nr(nr)
68 {
69                 // scan frontends
70         int num_fe = 0;
71         
72         eDebug("scanning for frontends..");
73         while (1)
74         {
75                 struct stat s;
76                 char filename[128];
77 #if HAVE_DVB_API_VERSION < 3
78                 sprintf(filename, "/dev/dvb/card%d/frontend%d", m_nr, num_fe);
79 #else
80                 sprintf(filename, "/dev/dvb/adapter%d/frontend%d", m_nr, num_fe);
81 #endif
82                 if (stat(filename, &s))
83                         break;
84                 ePtr<eDVBFrontend> fe;
85
86                 int ok = 0;
87                 fe = new eDVBFrontend(m_nr, num_fe, ok);
88                 if (ok)
89                         m_frontend.push_back(fe);
90                 ++num_fe;
91         }
92         
93                 // scan demux
94         int num_demux = 0;
95         while (1)
96         {
97                 struct stat s;
98                 char filename[128];
99 #if HAVE_DVB_API_VERSION < 3
100                 sprintf(filename, "/dev/dvb/card%d/demux%d", m_nr, num_demux);
101 #else
102                 sprintf(filename, "/dev/dvb/adapter%d/demux%d", m_nr, num_demux);
103 #endif
104                 if (stat(filename, &s))
105                         break;
106                 ePtr<eDVBDemux> demux;
107                 
108                 demux = new eDVBDemux(m_nr, num_demux);
109                 m_demux.push_back(demux);
110                         
111                 ++num_demux;
112         }
113 }
114
115 int eDVBAdapterLinux::getNumDemux()
116 {
117         return m_demux.size();
118 }
119
120 RESULT eDVBAdapterLinux::getDemux(ePtr<eDVBDemux> &demux, int nr)
121 {
122         eSmartPtrList<eDVBDemux>::iterator i(m_demux.begin());
123         while (nr && (i != m_demux.end()))
124         {
125                 --nr;
126                 ++i;
127         }
128         
129         if (i != m_demux.end())
130                 demux = *i;
131         else
132                 return -1;
133                 
134         return 0;
135 }
136
137 int eDVBAdapterLinux::getNumFrontends()
138 {
139         return m_frontend.size();
140 }
141
142 RESULT eDVBAdapterLinux::getFrontend(ePtr<eDVBFrontend> &fe, int nr)
143 {
144         eSmartPtrList<eDVBFrontend>::iterator i(m_frontend.begin());
145         while (nr && (i != m_frontend.end()))
146         {
147                 --nr;
148                 ++i;
149         }
150         
151         if (i != m_frontend.end())
152                 fe = *i;
153         else
154                 return -1;
155                 
156         return 0;
157 }
158
159 int eDVBAdapterLinux::exist(int nr)
160 {
161         struct stat s;
162         char filename[128];
163 #if HAVE_DVB_API_VERSION < 3
164         sprintf(filename, "/dev/dvb/card%d", nr);
165 #else
166         sprintf(filename, "/dev/dvb/adapter%d", nr);
167 #endif
168         if (!stat(filename, &s))
169                 return 1;
170         return 0;
171 }
172
173 eDVBResourceManager::~eDVBResourceManager()
174 {
175         if (instance == this)
176                 instance = 0;
177
178 }
179
180 void eDVBResourceManager::addAdapter(iDVBAdapter *adapter)
181 {
182         int num_fe = adapter->getNumFrontends();
183         int num_demux = adapter->getNumDemux();
184         
185         m_adapter.push_back(adapter);
186         
187         int i;
188         for (i=0; i<num_demux; ++i)
189         {
190                 ePtr<eDVBDemux> demux;
191                 if (!adapter->getDemux(demux, i))
192                         m_demux.push_back(new eDVBRegisteredDemux(demux, adapter));
193         }
194
195         for (i=0; i<num_fe; ++i)
196         {
197                 ePtr<eDVBFrontend> frontend;
198                 if (!adapter->getFrontend(frontend, i))
199                         m_frontend.push_back(new eDVBRegisteredFrontend(frontend, adapter));
200         }
201 }
202
203 RESULT eDVBResourceManager::allocateFrontend(const eDVBChannelID &chid, ePtr<eDVBAllocatedFrontend> &fe)
204 {
205                 /* find first unused frontend. we ignore compatibility for now. */
206         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
207                 if (!i->m_inuse)
208                 {
209                         fe = new eDVBAllocatedFrontend(i);
210                         return 0;
211                 }
212         return -1;
213 }
214
215 RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBAllocatedDemux> &demux)
216 {
217                 /* find first unused demux which is on same adapter as frontend */
218         for (eSmartPtrList<eDVBRegisteredDemux>::iterator i(m_demux.begin()); i != m_demux.end(); ++i)
219                 if ((!i->m_inuse) && (i->m_adapter == fe->m_adapter))
220                 {
221                         demux = new eDVBAllocatedDemux(i);
222                         return 0;
223                 }
224         return -1;
225 }
226
227 RESULT eDVBResourceManager::setChannelList(iDVBChannelList *list)
228 {
229         m_list = list;
230         return 0;
231 }
232
233 RESULT eDVBResourceManager::getChannelList(ePtr<iDVBChannelList> &list)
234 {
235         list = m_list;
236         if (list)
237                 return 0;
238         else
239                 return -ENOENT;
240 }
241
242
243 RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUsePtr<iDVBChannel> &channel)
244 {
245                 /* first, check if a channel is already existing. */
246         
247 //      eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
248         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
249         {
250 //              eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
251                 if (i->m_channel_id == channelid)
252                 {
253 //                      eDebug("found shared channel..");
254                         channel = i->m_channel;
255                         return 0;
256                 }
257         }
258         
259                 /* no currently available channel is tuned to this channelid. create a new one, if possible. */
260                 
261                 /* allocate a frontend. */
262         
263         ePtr<eDVBAllocatedFrontend> fe;
264         
265         if (allocateFrontend(channelid, fe))
266                 return errNoFrontend;
267         
268         ePtr<eDVBAllocatedDemux> demux;
269         
270         if (allocateDemux(*fe, demux))
271                 return errNoDemux;
272         
273         RESULT res;
274         eDVBChannel *ch;
275         ch = new eDVBChannel(this, fe, demux);
276
277         ePtr<iDVBFrontend> myfe;
278         if (!ch->getFrontend(myfe))
279                 myfe->setSEC(m_sec);
280
281         res = ch->setChannel(channelid);
282         if (res)
283         {
284                 channel = 0;
285                 return errChidNotFound;
286         }
287         
288         channel = ch;
289         return 0;
290 }
291
292 RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel)
293 {
294         ePtr<eDVBAllocatedFrontend> fe;
295         
296         if (allocateFrontend(eDVBChannelID(), fe))
297                 return errNoFrontend;
298         
299         ePtr<eDVBAllocatedDemux> demux;
300         
301         if (allocateDemux(*fe, demux))
302                 return errNoDemux;
303         
304         eDVBChannel *ch;
305         ch = new eDVBChannel(this, fe, demux);
306
307         ePtr<iDVBFrontend> myfe;
308         if (!ch->getFrontend(myfe))
309                 myfe->setSEC(m_sec);
310
311         channel = ch;
312         return 0;
313 }
314
315 RESULT eDVBResourceManager::allocatePVRChannel(int caps)
316 {
317         return -1; // will nicht, mag nicht, und das interface ist auch kaputt
318 }
319
320 RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *ch)
321 {
322         eDebug("add channel %p", ch);
323         m_active_channels.push_back(active_channel(chid, ch));
324         /* emit */ m_channelAdded(ch);
325         return 0;
326 }
327
328 RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch)
329 {
330         int cnt = 0;
331         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end();)
332         {
333                 if (i->m_channel == ch)
334                 {
335                         i = m_active_channels.erase(i);
336                         ++cnt;
337                 } else
338                         ++i;
339         }
340         ASSERT(cnt == 1);
341         if (cnt == 1)
342                 return 0;
343         return -ENOENT;
344 }
345
346 RESULT eDVBResourceManager::connectChannelAdded(const Slot1<void,eDVBChannel*> &channelAdded, ePtr<eConnection> &connection)
347 {
348         connection = new eConnection((eDVBResourceManager*)this, m_channelAdded.connect(channelAdded));
349         return 0;
350 }
351
352 DEFINE_REF(eDVBChannel);
353
354 eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend, eDVBAllocatedDemux *demux): m_state(state_idle), m_mgr(mgr)
355 {
356         m_frontend = frontend;
357         m_demux = demux;
358         
359         if (m_frontend)
360                 m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
361 }
362
363 eDVBChannel::~eDVBChannel()
364 {
365         if (m_channel_id)
366                 m_mgr->removeChannel(this);
367 }
368
369 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
370 {
371         eDebug("fe state changed!");
372         int state, ourstate = 0;
373         
374                 /* if we are already in shutdown, don't change state. */
375         if (m_state == state_release)
376                 return;
377         
378         if (fe->getState(state))
379                 return;
380         
381         if (state == iDVBFrontend::stateLock)
382         {
383                 eDebug("OURSTATE: ok");
384                 ourstate = state_ok;
385         } else if (state == iDVBFrontend::stateTuning)
386         {
387                 eDebug("OURSTATE: tuning");
388                 ourstate = state_tuning;
389         } else if (state == iDVBFrontend::stateFailed)
390         {
391                 eDebug("OURSTATE: failed/unavailable");
392                 ourstate = state_unavailable;
393         } else
394                 eFatal("state unknown");
395         
396         if (ourstate != m_state)
397         {
398                 m_state = ourstate;
399                 m_stateChanged(this);
400         }
401 }
402
403 void eDVBChannel::AddUse()
404 {
405         ++m_use_count;
406 }
407
408 void eDVBChannel::ReleaseUse()
409 {
410         if (!--m_use_count)
411         {
412                 m_state = state_release;
413                 m_stateChanged(this);
414         }
415 }
416
417 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid)
418 {
419         if (m_channel_id)
420                 m_mgr->removeChannel(this);
421                 
422         if (!channelid)
423                 return 0;
424
425         ePtr<iDVBChannelList> list;
426         
427         if (m_mgr->getChannelList(list))
428         {
429                 eDebug("no channel list set!");
430                 return -ENOENT;
431         }
432         
433         eDebug("tuning to chid: ns: %08x tsid %04x onid %04x",
434                 channelid.dvbnamespace.get(), channelid.transport_stream_id.get(), channelid.original_network_id.get());
435
436         ePtr<iDVBFrontendParameters> feparm;
437         if (list->getChannelFrontendData(channelid, feparm))
438         {
439                 eDebug("channel not found!");
440                 return -ENOENT;
441         }
442         eDebug("allocateChannel: channel found..");
443         
444         if (!m_frontend)
445         {
446                 eDebug("no frontend to tune!");
447                 return -ENODEV;
448         }
449         
450         m_channel_id = channelid;
451         m_mgr->addChannel(channelid, this);
452         m_state = state_tuning;
453         return m_frontend->get().tune(*feparm);
454 }
455
456 RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
457 {
458         connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange));
459         return 0;
460 }
461
462 RESULT eDVBChannel::getState(int &state)
463 {
464         state = m_state;
465         return 0;
466 }
467
468 RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
469 {
470         return -1;
471 }
472
473 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux)
474 {
475         demux = &m_demux->get();
476         return 0;
477 }
478
479 RESULT eDVBChannel::getFrontend(ePtr<iDVBFrontend> &frontend)
480 {
481         frontend = &m_frontend->get();
482         if (frontend)
483                 return 0;
484         else
485                 return -ENODEV;
486 }