Support Uno4k/Ultimo4k
[vuplus_dvbapp] / lib / dvb / fbc.cpp
1 /* FBC Manager */
2 #include <lib/dvb/fbc.h>
3 #include <lib/dvb/dvb.h>
4 #include <lib/dvb/sec.h>
5 #include <lib/base/object.h>
6
7 #include <unistd.h>
8 #include <fcntl.h>
9
10 //#define FBC_DEBUG
11
12 #ifdef FBC_DEBUG
13 #define eFecDebug(arg...) eDebug(arg)
14 #else
15 #define eFecDebug(arg...)
16 #endif
17
18 static int getProcData(const char* filename)
19 {
20         int res = -1;
21         FILE *fp = fopen(filename,"r");
22         if(fp)
23         {
24                 fscanf(fp, "%d", &res);
25                 fclose(fp);
26         }
27         else
28         {
29                 eFecDebug("[*][eFBCTunerManager::getProcData] open failed, %s: %m", filename);
30         }
31         return res;
32 }
33
34 static void setProcData(const char* filename, int value)
35 {
36         eDebug("[*] setProcData %s -> %d", filename, value);
37         FILE *fp = fopen(filename, "w");
38         if(fp)
39         {
40                 fprintf(fp, "%d", value);
41                 fclose(fp);
42         }
43         else
44         {
45                 eFecDebug("[*][eFBCTunerManager::setProcData] open failed, %s: %m", filename);
46         }
47 }
48
49 static void loadConnectChoices(const char* filename, bool *connect_choices)
50 {
51         FILE *fp = fopen(filename,"r");
52         if(fp)
53         {
54                 int c;
55                 while(EOF != (c = fgetc(fp)))
56                 {
57                         if(isdigit(c))
58                                 connect_choices[c - '0'] = true;
59                 }
60                 fclose(fp);
61         }
62         else
63         {
64                 eFecDebug("[*][eFBCTunerManager::LoadFbcRootChoices] open failed, %s: %m", filename);
65         }
66 }
67
68
69 DEFINE_REF(eFBCTunerManager);
70
71 eFBCTunerManager* eFBCTunerManager::m_instance = (eFBCTunerManager*)0;
72
73 eFBCTunerManager* eFBCTunerManager::getInstance()
74 {
75         return m_instance;
76 }
77
78 eFBCTunerManager::eFBCTunerManager(ePtr<eDVBResourceManager> res_mgr)
79         :m_res_mgr(res_mgr)
80 {
81         if (!m_instance)
82                 m_instance = this;
83
84         eSmartPtrList<eDVBRegisteredFrontend> &frontends = m_res_mgr->m_frontend;
85
86         /* each FBC set has 8 tuners. */
87         /* first set : 0, 1, 2, 3, 4, 5, 6, 7 */
88         /* second set : 8, 9, 10, 11, 12, 13, 14, 15 */
89         /* first, second frontend is top on a set */
90
91         bool isRoot;
92         int fbcSetID = -1;
93         int fbcIndex = 0;
94         int initFbcId = -1;
95         int prevFbcSetID = -1;
96         char tmp[128];
97         std::string proc_fe;
98         bool connect_choices[32] = {false};
99
100         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
101         {
102                 // continue for DVB-C FBC Tuner
103                 if (!(it->m_frontend->supportsDeliverySystem(SYS_DVBS, false) || it->m_frontend->supportsDeliverySystem(SYS_DVBS2, false)))
104                         continue;
105
106                 int fe_id = feSlotID(it);
107                 snprintf(tmp, sizeof(tmp), "/proc/stb/frontend/%d", fe_id);
108                 proc_fe = tmp;
109                 fbcSetID = getProcData(std::string(proc_fe + "/fbc_set_id").c_str());
110                 if (fbcSetID != -1)
111                 {
112                         if (prevFbcSetID != fbcSetID)
113                         {
114                                 prevFbcSetID = fbcSetID;
115                                 memset(connect_choices, 0, sizeof(connect_choices));
116                                 loadConnectChoices(std::string(proc_fe + "/fbc_connect_choices").c_str(), connect_choices);
117                                 fbcIndex =0; // reset
118                         }
119
120                         isRoot = false;
121                         if (fbcIndex < sizeof(connect_choices)/sizeof(connect_choices[0]))
122                         {
123                                 isRoot = connect_choices[fbcIndex];
124                         }
125
126                         initFbcId = isRoot ? fbcIndex : 0;
127
128                         FBC_TUNER elem = {fbcSetID, fbcIndex, isRoot, initFbcId};
129                         m_fbc_tuners[fe_id] = elem;
130
131                         /* set default fbc ID */
132                         setProcFBCID(fe_id, initFbcId, false);
133
134                         /* enable fbc tuner */
135                         it->m_frontend->setFBCTuner(true);
136
137                         fbcIndex++;
138                 }
139         }
140 }
141
142 eFBCTunerManager::~eFBCTunerManager()
143 {
144         if (m_instance == this)
145                 m_instance = 0;
146 }
147
148 int eFBCTunerManager::setProcFBCID(int fe_id, int fbc_connect, bool is_linked)
149 {
150         eFecDebug("[*][eFBCTunerManager::setProcFBCID] %d -> %d", fe_id, fbc_connect);
151         char filename[128];
152
153         /* set root */
154         sprintf(filename, "/proc/stb/frontend/%d/fbc_connect", fe_id);
155         setProcData(filename, fbc_connect);
156
157         /* set linked */
158         sprintf(filename, "/proc/stb/frontend/%d/fbc_link", fe_id);
159         setProcData(filename, (int)is_linked);
160
161         return 0;
162 }
163
164
165 int eFBCTunerManager::feSlotID(const eDVBRegisteredFrontend *fe) const
166 {
167         return fe->m_frontend->getSlotID();
168 }
169
170 void eFBCTunerManager::setDefaultFBCID(eDVBRegisteredFrontend *fe)
171 {
172         int fe_id = feSlotID(fe);
173         setProcFBCID(fe_id, getDefaultFBCID(fe_id), isLinked(fe));
174 }
175
176 void eFBCTunerManager::updateFBCID(eDVBRegisteredFrontend *next_fe, eDVBRegisteredFrontend *prev_fe)
177 {
178         setProcFBCID(feSlotID(next_fe), getFBCID(feSlotID(getTop(prev_fe))), isLinked(next_fe));
179 }
180
181 bool eFBCTunerManager::isLinked(eDVBRegisteredFrontend *fe) const
182 {
183  
184         long linked_prev_ptr = -1;
185         fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, linked_prev_ptr);
186         return (linked_prev_ptr != -1);
187 }
188
189 bool eFBCTunerManager::isUnicable(eDVBRegisteredFrontend *fe) const
190 {
191         int slot_idx = feSlotID(fe);
192         bool is_unicable = false;
193
194         ePtr<eDVBSatelliteEquipmentControl> sec = eDVBSatelliteEquipmentControl::getInstance();
195         for (int idx=0; idx <= sec->m_lnbidx; ++idx )
196         {
197                 eDVBSatelliteLNBParameters &lnb_param = sec->m_lnbs[idx];
198                 if ( lnb_param.m_slot_mask & (1 << slot_idx) )
199                 {
200                         is_unicable = lnb_param.SatCR_idx != -1;
201                         break;
202                 }
203         }
204         return is_unicable;
205 }
206
207 bool eFBCTunerManager::isFeUsed(eDVBRegisteredFrontend *fe, bool a_simulate) const
208 {
209         if (fe->m_inuse > 0)
210                 return true;
211
212         bool simulate = !a_simulate;
213
214         eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_res_mgr->m_simulate_frontend : m_res_mgr->m_frontend;
215         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
216         {
217                 if (feSlotID(it) == feSlotID(fe))
218                 {
219                         return (it->m_inuse >0);
220                 }
221         }
222
223         eDebug("[*][eFBCTunerManager::isFeUsed] ERROR! can not found fe ptr (feid : %d, simulate : %d)", feSlotID(fe), simulate);
224         return false;
225 }
226
227 bool eFBCTunerManager::isSameFbcSet(int fe_a, int fe_b)
228 {
229         return m_fbc_tuners[fe_a].fbcSetID == m_fbc_tuners[fe_b].fbcSetID;
230 }
231
232 bool eFBCTunerManager::isRootFe(eDVBRegisteredFrontend *fe)
233 {
234         return m_fbc_tuners[feSlotID(fe)].isRoot;
235 }
236
237 int eFBCTunerManager::getFBCID(int fe_id)
238 {
239         return m_fbc_tuners[fe_id].fbcIndex;
240 }
241
242 int eFBCTunerManager::getDefaultFBCID(int fe_id)
243 {
244         return m_fbc_tuners[fe_id].initFbcId;
245 }
246
247 int eFBCTunerManager::getFBCSetID(int fe_id)
248 {
249         return m_fbc_tuners[fe_id].fbcSetID;
250 }
251
252 eDVBRegisteredFrontend *eFBCTunerManager::getPrev(eDVBRegisteredFrontend *fe) const
253 {
254         eDVBRegisteredFrontend *prev_fe = NULL;
255         long linked_prev_ptr = -1;
256         fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, linked_prev_ptr);
257         if (linked_prev_ptr != -1)
258                 prev_fe = (eDVBRegisteredFrontend *)linked_prev_ptr;
259         return prev_fe;
260 }
261
262 eDVBRegisteredFrontend *eFBCTunerManager::getNext(eDVBRegisteredFrontend *fe) const
263 {
264         eDVBRegisteredFrontend *next_fe = NULL;
265         long linked_next_ptr = -1;
266         fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr);
267         if (linked_next_ptr != -1)
268                 next_fe = (eDVBRegisteredFrontend *)linked_next_ptr;
269         return next_fe;
270 }
271
272 eDVBRegisteredFrontend *eFBCTunerManager::getTop(eDVBRegisteredFrontend *fe) const
273 {
274         eDVBRegisteredFrontend *prev_fe = fe;
275         long linked_prev_ptr = -1;
276         fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, linked_prev_ptr);
277         while(linked_prev_ptr != -1)
278         {
279                 prev_fe = (eDVBRegisteredFrontend *)linked_prev_ptr;
280                 prev_fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, linked_prev_ptr);
281         }
282         return prev_fe;
283 }
284
285 eDVBRegisteredFrontend *eFBCTunerManager::getLast(eDVBRegisteredFrontend *fe) const
286 {
287         eDVBRegisteredFrontend *next_fe = fe;
288         long linked_next_ptr = -1;
289         fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr);
290         while(linked_next_ptr != -1)
291         {
292                 next_fe = (eDVBRegisteredFrontend *)linked_next_ptr;
293                 next_fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr);
294         }
295         return next_fe;
296 }
297
298 eDVBRegisteredFrontend *eFBCTunerManager::getSimulFe(eDVBRegisteredFrontend *fe) const
299 {
300         eSmartPtrList<eDVBRegisteredFrontend> &frontends = m_res_mgr->m_simulate_frontend;
301
302         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); it++)
303                 if (feSlotID(*it) == feSlotID(fe))
304                         return(*it);
305
306         return((eDVBRegisteredFrontend *)0);
307 }
308
309 void eFBCTunerManager::connectLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *prev_fe, eDVBRegisteredFrontend *next_fe, bool simulate)
310 {
311         if (next_fe)
312                 eFecDebug("     [*][eFBCTunerManager::connectLink] connect %d->%d->%d %s", feSlotID(prev_fe), feSlotID(link_fe), feSlotID(next_fe), simulate?"(simulate)":"");
313         else
314                 eFecDebug("     [*][eFBCTunerManager::connectLink] connect %d->%d %s", feSlotID(prev_fe), feSlotID(link_fe), simulate?"(simulate)":"");
315
316         prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)link_fe);
317         link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)prev_fe);
318         if (next_fe)
319         {
320                 link_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)next_fe);
321                 next_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)link_fe);
322         }
323 }
324
325 void eFBCTunerManager::disconnectLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *prev_fe, eDVBRegisteredFrontend *next_fe, bool simulate)
326 {
327         if (next_fe)
328                 eFecDebug("     [*][eFBCTunerManager::disconnectLink] disconnect %d->%d->%d %s", feSlotID(prev_fe), feSlotID(link_fe), feSlotID(next_fe), simulate?"(simulate)":"");
329         else
330                 eFecDebug("     [*][eFBCTunerManager::disconnectLink] disconnect %d->%d %s", feSlotID(prev_fe), feSlotID(link_fe), simulate?"(simulate)":"");
331
332         if (next_fe)
333         {
334                 prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)next_fe);
335                 next_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)prev_fe);
336
337                 link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)-1);
338                 link_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)-1);
339         }
340         else
341         {
342                 prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)-1);
343                 link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)-1);
344         }
345 }
346
347 int eFBCTunerManager::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm, eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *&fbc_fe, bool simulate)
348 {
349         int best_score = 0;
350
351         eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_res_mgr->m_simulate_frontend : m_res_mgr->m_frontend;
352         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
353         {
354                 if (!it->m_frontend->is_FBCTuner())
355                         continue;
356
357                 if (!isRootFe(*it))
358                         continue;
359
360                 if(!it->m_frontend->getEnabled())
361                         continue;
362
363                 if(!isSameFbcSet(feSlotID(link_fe), feSlotID(it)))
364                         continue;
365
366                 if(it->m_inuse == 0) // No link to a fe not in use.
367                         continue;
368
369                 if(isLinked(*it)) // No link to a fe linked to another.
370                         continue;
371
372                 if(isUnicable(*it))
373                         continue;
374
375                 eDVBRegisteredFrontend *top_fe = *it;
376                 eDVBRegisteredFrontend *prev_fe = getLast(top_fe);
377
378                 /* connect link */
379                 connectLink(link_fe, prev_fe, NULL, simulate);
380
381                 /* enable linked fe */
382                 link_fe->m_frontend->setEnabled(true);
383
384                 /* add slot mask*/
385                 updateLNBSlotMask(feSlotID(link_fe), feSlotID(*it), false);
386
387                 /* get score */
388                 int c = link_fe->m_frontend->isCompatibleWith(feparm);
389                 if (c > best_score)
390                 {
391                         best_score = c;
392                         fbc_fe = (eDVBRegisteredFrontend *)*it;
393                 }
394
395                 eFecDebug("[*][eFBCTunerManager::isCompatibleWith] score : %d (%d->%d)", c, feSlotID(it), feSlotID(link_fe));
396
397                 ASSERT(!getNext(link_fe));
398                 ASSERT(getPrev(link_fe));
399                 ASSERT(getLast(top_fe) == link_fe);
400
401                 /* disconnect link */
402                 disconnectLink(link_fe, prev_fe, NULL, simulate);
403
404                 /* disable linked fe */
405                 link_fe->m_frontend->setEnabled(false);
406
407                 /* remove slot mask*/
408                 updateLNBSlotMask(feSlotID(link_fe), feSlotID(top_fe), true);
409         }
410
411         eFecDebug("[*][eFBCTunerManager::isCompatibleWith] fe : %p(%d), score : %d %s", link_fe, feSlotID(link_fe), best_score, simulate?"(simulate)":"");
412
413         return best_score;
414 }
415
416 /* attach link_fe to tail of fe linked list */
417 void eFBCTunerManager::addLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *top_fe, bool simulate)
418 {
419         //printLinks(link_fe);
420
421         eFecDebug("     [*][eFBCTunerManager::addLink] addLink : %p(%d)->%p(%d) %s", top_fe, feSlotID(top_fe), link_fe, feSlotID(link_fe), simulate?"(simulate)":"");
422
423         eDVBRegisteredFrontend *next_fe = NULL;
424         eDVBRegisteredFrontend *prev_fe = NULL;
425
426         if(isRootFe(link_fe) || !isRootFe(top_fe))
427                 return;
428
429         /* search prev/next fe */
430         next_fe = top_fe;
431         while(true)
432         {
433                 prev_fe = next_fe;
434                 next_fe = getNext(prev_fe);
435                 if ((next_fe == NULL) || (feSlotID(next_fe) > feSlotID(link_fe)))
436                         break;
437         }
438
439         /* connect */
440         connectLink(link_fe, prev_fe, next_fe, simulate);
441
442         /* enable linked fe */
443         link_fe->m_frontend->setEnabled(true);
444
445         /* simulate connect */
446         if (!simulate)
447         {
448                 eDVBRegisteredFrontend *simulate_prev_fe = NULL;
449                 eDVBRegisteredFrontend *simulate_link_fe = NULL;
450                 eDVBRegisteredFrontend *simulate_next_fe = NULL;
451
452                 simulate_prev_fe = getSimulFe(prev_fe);
453                 simulate_link_fe = getSimulFe(link_fe);
454
455                 if (next_fe) 
456                         simulate_next_fe = getSimulFe(next_fe);
457
458                 eFecDebug("     [*][eFBCTunerManager::addLink] simulate fe : %p -> %p -> %p", simulate_prev_fe, simulate_link_fe, simulate_next_fe);
459
460                 connectLink(simulate_link_fe, simulate_prev_fe, simulate_next_fe, !simulate);
461
462                 /* enable simulate linked fe */
463                 simulate_link_fe->m_frontend->setEnabled(true);
464         }
465
466         /* set proc fbc_id */
467         if (!simulate)
468                 setProcFBCID(feSlotID(link_fe), getFBCID(feSlotID(top_fe)), isLinked(link_fe));
469
470         /* add slot mask*/
471         updateLNBSlotMask(feSlotID(link_fe), feSlotID(top_fe), false);
472
473         //printLinks(link_fe);
474 }
475
476 /* if fe, fe_simulated is unused, unlink current frontend from linked things. */
477 /* all unused linked fbc fe must be unlinked! */
478 void eFBCTunerManager::unLink(eDVBRegisteredFrontend *link_fe)
479 {
480         bool simulate = link_fe->m_frontend->is_simulate();
481         eFecDebug("     [*][eFBCTunerManager::unLink] fe id : %p(%d) %s", link_fe, feSlotID(link_fe), simulate?"(simulate)":"");
482
483         if (isRootFe(link_fe) || isFeUsed(link_fe, simulate) || isUnicable(link_fe) || !isLinked(link_fe))
484         {
485                 eFecDebug("     [*][eFBCTunerManager::unLink] skip..");
486                 return;
487         }
488
489         //printLinks(link_fe);
490
491         eDVBRegisteredFrontend *prev_fe = getPrev(link_fe);
492         eDVBRegisteredFrontend *next_fe = getNext(link_fe);
493
494         ASSERT(prev_fe);
495
496         disconnectLink(link_fe, prev_fe, next_fe, simulate);
497
498         /* disable linked fe */
499         link_fe->m_frontend->setEnabled(false);
500
501         /* simulate disconnect */
502         if (!simulate)
503         {
504                 eDVBRegisteredFrontend *simulate_prev_fe = NULL;
505                 eDVBRegisteredFrontend *simulate_link_fe = NULL;
506                 eDVBRegisteredFrontend *simulate_next_fe = NULL;
507
508                 simulate_prev_fe = getSimulFe(prev_fe);
509                 simulate_link_fe = getSimulFe(link_fe);
510
511                 if (next_fe) 
512                         simulate_next_fe = getSimulFe(next_fe);
513
514                 disconnectLink(simulate_link_fe, simulate_prev_fe, simulate_next_fe, !simulate);
515
516                 /* enable simulate linked fe */
517                 simulate_link_fe->m_frontend->setEnabled(false);
518         }
519
520         /* set default proc fbc_id */
521         //setDefaultFBCID(link_fe);
522
523         /* remove slot mask*/
524         updateLNBSlotMask(feSlotID(link_fe), feSlotID(getTop(prev_fe)), true);
525
526         //printLinks(link_fe);
527 }
528
529 int eFBCTunerManager::updateLNBSlotMask(int dest_slot, int src_slot, bool remove)
530 {
531         ePtr<eDVBSatelliteEquipmentControl> sec = eDVBSatelliteEquipmentControl::getInstance();
532
533         int sec_lnbidx = sec->m_lnbidx;
534
535         int found = 0;
536         for (int idx=0; idx <= sec_lnbidx; ++idx )
537         {
538                 eDVBSatelliteLNBParameters &lnb_param = sec->m_lnbs[idx];
539                 if ( lnb_param.m_slot_mask & (1 << src_slot) )
540                 {
541                         eFecDebug("[*][eFBCTunerManager::updateLNBSlotMask] m_slot_mask : %d", lnb_param.m_slot_mask);
542
543                         if (!remove)
544                                 lnb_param.m_slot_mask |= (1 << dest_slot);
545                         else
546                                 lnb_param.m_slot_mask &= ~(1 << dest_slot);
547
548                         eFecDebug("[*][eFBCTunerManager::updateLNBSlotMask] changed m_slot_mask : %d", lnb_param.m_slot_mask);
549                         found = 1;
550                 }
551         }
552
553         if (!found)
554                 eFecDebug("[*][eFBCTunerManager::updateLNBSlotMask] src %d not found", src_slot);
555
556         return 0;
557 }
558
559 bool eFBCTunerManager::canLink(eDVBRegisteredFrontend *fe)
560 {
561         return !(isRootFe(fe) || getPrev(fe) || getNext(fe) || isUnicable(fe));
562 }
563
564 int eFBCTunerManager::getLinkedSlotID(int fe_id) const
565 {
566         int link = -1;
567         eSmartPtrList<eDVBRegisteredFrontend> &frontends = m_res_mgr->m_frontend;
568         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
569         {
570                 if(it->m_frontend->getSlotID() == fe_id)
571                 {
572                         long prev_ptr = -1;
573                         it->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, prev_ptr);
574                         if (prev_ptr != -1)
575                         {
576                                 eDVBRegisteredFrontend *prev_fe = (eDVBRegisteredFrontend *)prev_ptr;
577                                 link = feSlotID(prev_fe);
578                         }
579                         break;
580                 }
581         }
582
583         eFecDebug(" [*][eFBCTunerManager::getLinkedSlotID] fe_id : %d, link : %d", fe_id, link);
584
585         return link;
586 }
587
588 bool eFBCTunerManager::isFBCLink(int fe_id)
589 {
590         bool res = false;
591         std::map<int, FBC_TUNER>::iterator it = m_fbc_tuners.find(fe_id);
592         if (it != m_fbc_tuners.end())
593         {
594                 res = !it->second.isRoot;
595         }
596         return res;
597 }
598
599 void eFBCTunerManager::printLinks(eDVBRegisteredFrontend *fe) const
600 {
601         long linked_prev_ptr = -1;
602         eDVBRegisteredFrontend *linked_prev_fe = fe;
603         fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, linked_prev_ptr);
604         while (linked_prev_ptr != -1)
605         {
606                 linked_prev_fe = (eDVBRegisteredFrontend*) linked_prev_ptr;
607                 linked_prev_fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, (long&)linked_prev_ptr);
608         }
609
610         long linked_next_ptr = -1;
611         eDVBRegisteredFrontend *linked_next_fe = linked_prev_fe;
612         eFecDebug("     [*][eFBCTunerManager::printLinks] fe id : %d (%p), inuse : %d, enabled : %d, fbc : %d", feSlotID(linked_next_fe), linked_next_fe, linked_next_fe->m_inuse, linked_next_fe->m_frontend->getEnabled(), linked_next_fe->m_frontend->is_FBCTuner());
613         linked_prev_fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr);
614         while (linked_next_ptr != -1)
615         {
616                 linked_next_fe = (eDVBRegisteredFrontend*) linked_next_ptr;
617                 eFecDebug("     [*][eFBCTunerManager::printLinks] fe id : %d (%p), inuse : %d, enabled : %d, fbc : %d", feSlotID(linked_next_fe), linked_next_fe, linked_next_fe->m_inuse, linked_next_fe->m_frontend->getEnabled(), linked_next_fe->m_frontend->is_FBCTuner());
618                 linked_next_fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, (long&)linked_next_ptr);
619         }
620
621         eSmartPtrList<eDVBRegisteredFrontend> &frontends = m_res_mgr->m_frontend;
622         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
623         {
624                 int prev = -1;
625                 int next = -1;
626                 long prev_ptr = -1;
627                 long next_ptr = -1;
628                 it->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, prev_ptr);
629                 it->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, next_ptr);
630                 if (prev_ptr != -1)
631                 {
632                         eDVBRegisteredFrontend *prev_fe = (eDVBRegisteredFrontend *)prev_ptr;
633                         prev = feSlotID(prev_fe);
634                 }
635
636                 if (next_ptr != -1)
637                 {
638                         eDVBRegisteredFrontend *next_fe = (eDVBRegisteredFrontend *)next_ptr;
639                         next = feSlotID(next_fe);
640                 }
641                 
642                 eFecDebug("     [*][eFBCTunerManager::printLinks] fe_id : %2d, inuse : %d, enabled : %d, fbc : %d, prev : %2d, cur : %2d, next : %2d", feSlotID(it), it->m_inuse, it->m_frontend->getEnabled(), it->m_frontend->is_FBCTuner(), prev, feSlotID(it), next);
643         }
644
645         eSmartPtrList<eDVBRegisteredFrontend> &simulate_frontends = m_res_mgr->m_simulate_frontend;
646         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(simulate_frontends.begin()); it != simulate_frontends.end(); ++it)
647         {
648                 int prev = -1;
649                 int next = -1;
650                 long prev_ptr = -1;
651                 long next_ptr = -1;
652                 it->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, prev_ptr);
653                 it->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, next_ptr);
654                 if (prev_ptr != -1)
655                 {
656                         eDVBRegisteredFrontend *prev_fe = (eDVBRegisteredFrontend *)prev_ptr;
657                         prev = feSlotID(prev_fe);
658                 }
659
660                 if (next_ptr != -1)
661                 {
662                         eDVBRegisteredFrontend *next_fe = (eDVBRegisteredFrontend *)next_ptr;
663                         next = feSlotID(next_fe);
664                 }
665                 
666                 eFecDebug("     [*][eFBCTunerManager::printLinks] fe_id : %2d, inuse : %d, enabled : %d, fbc : %d, prev : %2d, cur : %2d, next : %2d (simulate)", feSlotID(it), it->m_inuse, it->m_frontend->getEnabled(), it->m_frontend->is_FBCTuner(), prev, feSlotID(it), next);
667         }
668 }
669