update dvbapp.
[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 FE_SLOT_ID(fe) fe->m_frontend->getSlotID()
11
12 //#define FBC_DEBUG
13
14 #ifdef FBC_DEBUG
15 #define eFecDebug(arg...) eDebug(arg)
16 #else
17 #define eFecDebug(arg...)
18 #endif
19
20
21 DEFINE_REF(eFBCTunerManager);
22
23 bool eFBCTunerManager::isDestroyed = false;
24
25 eFBCTunerManager::eFBCTunerManager()
26 {
27         ePtr<eDVBResourceManager> res_mgr;
28         eDVBResourceManager::getInstance(res_mgr);
29         m_res_mgr = res_mgr;
30
31         /* num of fbc tuner in one set */
32         m_fbc_tuner_num = getFBCTunerNum();
33         procInit();
34 }
35
36 eFBCTunerManager::~eFBCTunerManager()
37 {
38         isDestroyed = true;
39 }
40
41 void eFBCTunerManager::procInit()
42 {
43         eSmartPtrList<eDVBRegisteredFrontend> &frontends = m_res_mgr->m_frontend;
44
45         /* 1 FBC set has 8 tuners. */
46         /* 1st set : 0, 1, 2, 3, 4, 5, 6, 7 */
47         /* 2nd set : 8, 9, 10, 11, 12, 13, 14, 15 */
48         /* 1st, 2nd frontend is top on a set */
49
50         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
51         {
52                 if (!it->m_frontend->is_FBCTuner())
53                         continue;
54
55                 if (isRootFe(*it))
56                 {
57                         setProcFBCID(FE_SLOT_ID(it), getFBCID(FE_SLOT_ID(it)));
58                 }
59         }
60 }
61
62 int eFBCTunerManager::getFBCTunerNum()
63 {
64         char tmp[255];
65         int fbc_tuner_num = 2;
66         int fd = open("/proc/stb/info/chipset", O_RDONLY);
67         if(fd < 0) {
68                 eDebug("open failed, /proc/stb/info/chipset!");
69                 fbc_tuner_num = 2;
70         }
71         else
72         {
73                 read(fd, tmp, 255);
74                 close(fd);
75
76                 if (!!strstr(tmp, "7376"))
77                         fbc_tuner_num = 2;
78         }
79         return fbc_tuner_num;
80 }
81
82 int eFBCTunerManager::setProcFBCID(int fe_id, int fbc_id)
83 {
84         eFecDebug("[*][eFBCTunerManager::setProcFBCID] %d -> %d %s", fe_id, fbc_id, !isRootFeSlot(fe_id)?"(linked)":"");
85         char filename[128];
86         char data[4];
87         sprintf(filename, "/proc/stb/frontend/%d/fbc_id", fe_id);
88         int fd = open(filename, O_RDWR);
89         if(fd < 0) {
90                 eDebug("[*][eFBCTunerManager::setProcFBCID] open failed, %s: %m", filename);
91                 return -1;
92         }
93         else
94         {
95                 if(isLinkedByIndex(fe_id))
96                         fbc_id += 0x10; // 0x10 : isLinked, 0x01 : fbc_id
97
98                 sprintf(data, "%x", fbc_id);
99                 write(fd, data, strlen(data));
100                 close(fd);
101         }
102         return 0;
103 }
104
105 bool eFBCTunerManager::isRootFeSlot(int fe_slot_id)
106 {
107         return (fe_slot_id%8 < m_fbc_tuner_num) ? true : false;
108 }
109
110
111 bool eFBCTunerManager::isRootFe(eDVBRegisteredFrontend *fe)
112 {
113         return isRootFeSlot(FE_SLOT_ID(fe));
114 }
115
116 bool eFBCTunerManager::isSameFbcSet(int a, int b)
117 {
118         return (a/8) == (b/8) ? true : false;
119 }
120
121 bool eFBCTunerManager::isSupportDVBS(eDVBRegisteredFrontend *fe)
122 {
123         return (fe->m_frontend->supportsDeliverySystem(SYS_DVBS, true) || fe->m_frontend->supportsDeliverySystem(SYS_DVBS2, true)) ? true : false;
124 }
125
126 int eFBCTunerManager::getFBCID(int top_fe_id)
127 {
128         return 2*top_fe_id/8 + top_fe_id%8; /* (0,1,8,9,16,17...) -> (0,1,2,3,4,5...)*/
129 }
130
131 int eFBCTunerManager::setDefaultFBCID(eDVBRegisteredFrontend *fe)
132 {
133         if (!isRootFe(fe))
134                 return -1;
135
136         return setProcFBCID(FE_SLOT_ID(fe), getFBCID(FE_SLOT_ID(fe)));
137 }
138
139 void eFBCTunerManager::updateFBCID(eDVBRegisteredFrontend *next_fe, eDVBRegisteredFrontend *prev_fe)
140 {
141         eDVBRegisteredFrontend *top_fe = getTop(prev_fe);
142         setProcFBCID(FE_SLOT_ID(next_fe), getFBCID(FE_SLOT_ID(top_fe)));
143 }
144
145 eDVBRegisteredFrontend *eFBCTunerManager::getPrev(eDVBRegisteredFrontend *fe)
146 {
147         eDVBRegisteredFrontend *prev_fe = NULL;
148         long linked_prev_ptr = -1;
149         fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, linked_prev_ptr);
150         if (linked_prev_ptr != -1)
151                 prev_fe = (eDVBRegisteredFrontend *)linked_prev_ptr;
152         return prev_fe;
153 }
154
155 eDVBRegisteredFrontend *eFBCTunerManager::getNext(eDVBRegisteredFrontend *fe)
156 {
157         eDVBRegisteredFrontend *next_fe = NULL;
158         long linked_next_ptr = -1;
159         fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr);
160         if (linked_next_ptr != -1)
161                 next_fe = (eDVBRegisteredFrontend *)linked_next_ptr;
162         return next_fe;
163 }
164
165 eDVBRegisteredFrontend *eFBCTunerManager::getTop(eDVBRegisteredFrontend *fe)
166 {
167         eDVBRegisteredFrontend *prev_fe = fe;
168         long linked_prev_ptr = -1;
169         fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, linked_prev_ptr);
170         while(linked_prev_ptr != -1)
171         {
172                 prev_fe = (eDVBRegisteredFrontend *)linked_prev_ptr;
173                 prev_fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, linked_prev_ptr);
174         }
175         return prev_fe;
176 }
177
178 eDVBRegisteredFrontend *eFBCTunerManager::getLast(eDVBRegisteredFrontend *fe)
179 {
180         eDVBRegisteredFrontend *next_fe = fe;
181         long linked_next_ptr = -1;
182         fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr);
183         while(linked_next_ptr != -1)
184         {
185                 next_fe = (eDVBRegisteredFrontend *)linked_next_ptr;
186                 next_fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr);
187         }
188         return next_fe;
189 }
190
191 bool eFBCTunerManager::isLinked(eDVBRegisteredFrontend *fe)
192 {
193         return getPrev(fe) ? true:false;
194 }
195
196 bool eFBCTunerManager::isLinkedByIndex(int fe_idx)
197 {
198         bool linked = false;
199         eSmartPtrList<eDVBRegisteredFrontend> &frontends = m_res_mgr->m_frontend;
200
201         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
202         {
203                 if (FE_SLOT_ID(it) == fe_idx)
204                 {
205                         linked = isLinked(*it);
206                         break;
207                 }
208         }
209         return linked;
210 }
211
212 bool eFBCTunerManager::checkTop(eDVBRegisteredFrontend *fe)
213 {
214         return getPrev(fe) ? false:true;
215 }
216
217 int eFBCTunerManager::connectLinkByIndex(int link_fe_index, int prev_fe_index, int next_fe_index, bool simulate)
218 {
219         eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_res_mgr->m_simulate_frontend : m_res_mgr->m_frontend;
220
221         eFecDebug("     [*][eFBCTunerManager::connectLinkByIndex] try to link %d->%d->%d %s", prev_fe_index, link_fe_index, next_fe_index, simulate?"(simulate)":"");
222
223         eDVBRegisteredFrontend *link_fe=NULL;
224         eDVBRegisteredFrontend *prev_fe=NULL;
225         eDVBRegisteredFrontend *next_fe=NULL;
226
227         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
228         {
229                 if (FE_SLOT_ID(it) == prev_fe_index)
230                 {
231                         prev_fe = *it;
232                 }
233                 else if (FE_SLOT_ID(it) == next_fe_index)
234                 {
235                         next_fe = *it;
236                 }
237                 else if (FE_SLOT_ID(it) == link_fe_index)
238                 {
239                         link_fe = *it;
240                 }
241         }
242
243         if (prev_fe && next_fe && link_fe)
244         {
245                 /* enable linked fe */
246                 link_fe->m_frontend->setEnabled(true);
247
248                 /* connect */
249                 prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)link_fe);
250                 link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)prev_fe);
251
252                 link_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)next_fe);
253                 next_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)link_fe);
254         }
255         else
256         {
257                 eDebug("        [*][eFBCTunerManager::connectLinkByIndex] connect failed! (prev_fe : %p, next_fe : %p, link_fe : %p, %s)", prev_fe, next_fe, link_fe, simulate?"simulate":"");
258                 return -1;
259         }
260
261         return 0;
262 }
263
264 int eFBCTunerManager::connectLinkByIndex(int link_fe_index, int prev_fe_index, bool simulate)
265 {
266         eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_res_mgr->m_simulate_frontend : m_res_mgr->m_frontend;
267
268         eFecDebug("     [*][eFBCTunerManager::connectLinkByIndex] try to link %d->%d %s", prev_fe_index, link_fe_index, simulate?"(simulate)":"");
269
270         eDVBRegisteredFrontend *link_fe=NULL;
271         eDVBRegisteredFrontend *prev_fe=NULL;
272
273         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
274         {
275                 if (FE_SLOT_ID(it) == prev_fe_index)
276                 {
277                         prev_fe = *it;
278                 }
279                 else if (FE_SLOT_ID(it) == link_fe_index)
280                 {
281                         link_fe = *it;
282                 }
283         }
284
285         if (prev_fe && link_fe)
286         {
287                 /* enable linked fe */
288                 link_fe->m_frontend->setEnabled(true);
289
290                 /* connect */
291                 prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)link_fe);
292                 link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)prev_fe);
293         }
294         else
295         {
296                 eDebug("        [*][eFBCTunerManager::connectLinkByIndex] connect failed! (prev_fe : %p, link_fe : %p, %s)", prev_fe, link_fe, simulate?"simulate":"");
297                 return -1;
298         }
299
300         return 0;
301 }
302
303 int eFBCTunerManager::disconnectLinkByIndex(int link_fe_index, int prev_fe_index, int next_fe_index, bool simulate)
304 {
305         eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_res_mgr->m_simulate_frontend : m_res_mgr->m_frontend;
306
307         eFecDebug("     [*][eFBCTunerManager::connectLinkByIndex] try to unlink %d->%d->%d %s", prev_fe_index, link_fe_index, next_fe_index, simulate?"(simulate)":"");
308
309         eDVBRegisteredFrontend *link_fe=NULL;
310         eDVBRegisteredFrontend *prev_fe=NULL;
311         eDVBRegisteredFrontend *next_fe=NULL;
312
313         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
314         {
315                 if (FE_SLOT_ID(it) == prev_fe_index)
316                 {
317                         prev_fe = *it;
318                 }
319                 else if (FE_SLOT_ID(it) == next_fe_index)
320                 {
321                         next_fe = *it;
322                 }
323                 else if (FE_SLOT_ID(it) == link_fe_index)
324                 {
325                         link_fe = *it;
326                 }
327         }
328
329         if (prev_fe && next_fe && link_fe)
330         {
331                 /* disconnect */
332                 prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)next_fe);
333                 next_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)prev_fe);
334
335                 link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)-1);
336                 link_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)-1);
337
338                 /* enable linked fe */
339                 link_fe->m_frontend->setEnabled(false);
340         }
341         else
342         {
343                 eDebug("        [*][eFBCTunerManager::disconnectLinkByIndex] disconnect failed! (prev_fe : %p, next_fe : %p, link_fe : %p, %s)", prev_fe, next_fe, link_fe, simulate?"simulate":"");
344                 return -1;
345         }
346
347         return 0;
348 }
349 int eFBCTunerManager::disconnectLinkByIndex(int link_fe_index, int prev_fe_index, bool simulate)
350 {
351         eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_res_mgr->m_simulate_frontend : m_res_mgr->m_frontend;
352
353         eFecDebug("     [*][eFBCTunerManager::connectLinkByIndex] try to unlink %d->%d %s", prev_fe_index, link_fe_index, simulate?"(simulate)":"");
354
355         eDVBRegisteredFrontend *link_fe=NULL;
356         eDVBRegisteredFrontend *prev_fe=NULL;
357
358         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
359         {
360                 if (FE_SLOT_ID(it) == prev_fe_index)
361                 {
362                         prev_fe = *it;
363                 }
364                 else if (FE_SLOT_ID(it) == link_fe_index)
365                 {
366                         link_fe = *it;
367                 }
368         }
369
370         if (prev_fe && link_fe)
371         {
372                 /* disconnect */
373                 prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)-1);
374                 link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)-1);
375
376                 /* enable linked fe */
377                 link_fe->m_frontend->setEnabled(false);
378         }
379         else
380         {
381                 eDebug("        [*][eFBCTunerManager::disconnectLinkByIndex] disconnect failed! (prev_fe : %p, link_fe : %p, %s)", prev_fe, link_fe, simulate?"simulate":"");
382                 return -1;
383         }
384
385         return 0;
386 }
387
388 int eFBCTunerManager::connectLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *prev_fe, eDVBRegisteredFrontend *next_fe, bool simulate)
389 {
390         eFecDebug("     [*][eFBCTunerManager::connectLink] try to link %d->%d->%d %s", FE_SLOT_ID(prev_fe), FE_SLOT_ID(link_fe), FE_SLOT_ID(next_fe), simulate?"(simulate)":"");
391         int ret = connectLinkByIndex(FE_SLOT_ID(link_fe), FE_SLOT_ID(prev_fe), FE_SLOT_ID(next_fe), !simulate);
392         if(!ret)
393         {
394                 prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)link_fe);
395                 link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)prev_fe);
396
397                 link_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)next_fe);
398                 next_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)link_fe);
399
400                 /* enable linked fe */
401                 link_fe->m_frontend->setEnabled(true);  
402         }
403
404         return ret;
405 }
406
407 int eFBCTunerManager::connectLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *prev_fe, bool simulate)
408 {
409         eFecDebug("     [*][eFBCTunerManager::connectLink] try to link %d->%d %s", FE_SLOT_ID(prev_fe), FE_SLOT_ID(link_fe), simulate?"(simulate)":"");
410         int ret = connectLinkByIndex(FE_SLOT_ID(link_fe), FE_SLOT_ID(prev_fe), !simulate);
411         if(!ret)
412         {
413                 prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)link_fe);
414                 link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)prev_fe);
415
416                 /* enable linked fe */
417                 link_fe->m_frontend->setEnabled(true);
418         }
419
420         return ret;
421 }
422
423 int eFBCTunerManager::disconnectLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *prev_fe, eDVBRegisteredFrontend *next_fe, bool simulate)
424 {
425         eFecDebug("     [*][eFBCTunerManager::disconnectLink] disconnect %d->%d->%d %s", FE_SLOT_ID(prev_fe), FE_SLOT_ID(link_fe), FE_SLOT_ID(next_fe), simulate?"(simulate)":"");
426         int ret = disconnectLinkByIndex(FE_SLOT_ID(link_fe), FE_SLOT_ID(prev_fe), FE_SLOT_ID(next_fe), !simulate);
427         if(!ret)
428         {
429                 prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)next_fe);
430                 next_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)prev_fe);
431
432                 link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)-1);
433                 link_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)-1);
434
435                 link_fe->m_frontend->setEnabled(false);
436         }
437
438         return ret;
439 }
440
441 int eFBCTunerManager::disconnectLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *prev_fe, bool simulate)
442 {
443         eFecDebug("     [*][eFBCTunerManager::disconnectLink] disconnect %d->%d %s", FE_SLOT_ID(prev_fe), FE_SLOT_ID(link_fe), simulate?"(simulate)":"");
444         int ret = disconnectLinkByIndex(FE_SLOT_ID(link_fe), FE_SLOT_ID(prev_fe), !simulate);
445         if(!ret)
446         {
447                 prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)-1);
448                 link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)-1);
449
450                 link_fe->m_frontend->setEnabled(false);
451         }
452
453         return ret;
454 }
455
456 /* no set pair simulate fe */
457 /* no set proc fbc_id */
458 void eFBCTunerManager::connectLinkNoSimulate(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *top_fe)
459 {
460         eDVBRegisteredFrontend *last_fe = getLast(top_fe);
461
462         last_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)link_fe);
463         link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)last_fe);
464
465         /* enable linked fe */
466         link_fe->m_frontend->setEnabled(true);
467
468         /* add slot mask*/
469         updateLNBSlotMask(FE_SLOT_ID(link_fe), FE_SLOT_ID(top_fe), false);
470 }
471
472 /* no set pair simulate fe */
473 /* no set proc fbc_id */
474 void eFBCTunerManager::disconnectLinkNoSimulate(eDVBRegisteredFrontend *link_fe)
475 {
476         if(getNext(link_fe))
477         {
478                 eFecDebug("[*][eFBCTunerManager::disconnectLinkNoSimulate] link fe is no last.");
479                 return;
480         }
481
482         eDVBRegisteredFrontend *prev_fe = getPrev(link_fe);
483
484         if(!prev_fe)
485         {
486                 eFecDebug("[*][eFBCTunerManager::disconnectLinkNoSimulate] can not found prev fe.");
487                 return;
488         }
489
490         prev_fe->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)-1);
491         link_fe->m_frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)-1);
492                 
493         /* enable linked fe */
494         link_fe->m_frontend->setEnabled(false);
495
496         /* add slot mask*/
497         updateLNBSlotMask(FE_SLOT_ID(link_fe), FE_SLOT_ID(prev_fe), true);
498 }
499
500 bool eFBCTunerManager::checkUsed(eDVBRegisteredFrontend *fe, bool a_simulate)
501 {
502         if (fe->m_inuse > 0)
503                 return true;
504
505         bool simulate = !a_simulate;
506
507         eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_res_mgr->m_simulate_frontend : m_res_mgr->m_frontend;
508         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
509         {
510                 if (FE_SLOT_ID(it) == FE_SLOT_ID(fe))
511                 {
512                         return (it->m_inuse >0)?true:false;
513                 }
514         }
515
516         eDebug("[*][eFBCTunerManager::checkUsed] ERROR! can not found fe ptr (feid : %d, simulate : %d)", FE_SLOT_ID(fe), simulate);
517         return false;
518 }
519
520 bool eFBCTunerManager::canLink(eDVBRegisteredFrontend *fe)
521 {
522         if(isRootFe(fe))
523                 return false;
524
525         if(getPrev(fe) || getNext(fe))
526                 return false;
527
528         if(isUnicable(fe))
529                 return false;
530
531         return true;
532 }
533
534 bool eFBCTunerManager::isUnicable(eDVBRegisteredFrontend *fe)
535 {
536         int slot_idx = FE_SLOT_ID(fe);
537         bool is_unicable = false;
538
539         ePtr<eDVBSatelliteEquipmentControl> sec = eDVBSatelliteEquipmentControl::getInstance();
540         for (int idx=0; idx <= sec->m_lnbidx; ++idx )
541         {
542                 eDVBSatelliteLNBParameters &lnb_param = sec->m_lnbs[idx];
543                 if ( lnb_param.m_slot_mask & (1 << slot_idx) )
544                 {
545                         is_unicable = lnb_param.SatCR_idx != -1;
546                         break;
547                 }
548         }
549         return is_unicable;
550 }
551
552 int eFBCTunerManager::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm, eDVBRegisteredFrontend *link_fe, bool simulate)
553 {
554         eDVBRegisteredFrontend *best_fbc_fe;
555         return isCompatibleWith(feparm, link_fe, best_fbc_fe, simulate);
556 }
557
558 int eFBCTunerManager::isCompatibleWith(ePtr<iDVBFrontendParameters> &feparm, eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *&fbc_fe, bool simulate)
559 {
560         int best_score = 0;
561
562         eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_res_mgr->m_simulate_frontend : m_res_mgr->m_frontend;
563         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
564         {
565                 if (!it->m_frontend->is_FBCTuner())
566                         continue;
567
568                 if (!isRootFe(*it))
569                         continue;
570
571                 if(!it->m_frontend->getEnabled())
572                         continue;
573
574                 if(!isSameFbcSet(FE_SLOT_ID(link_fe), FE_SLOT_ID(it)))
575                         continue;
576
577                 if(it->m_inuse == 0) // No link to a fe not in use.
578                         continue;
579
580                 if(isLinked(*it)) // No link to a fe linked to another.
581                         continue;
582
583                 if(isUnicable(*it))
584                         continue;
585
586                 /* connect link */
587                 connectLinkNoSimulate(link_fe, *it);
588
589                 /* get score */
590                 int c = link_fe->m_frontend->isCompatibleWith(feparm);
591                 eFecDebug("[*][eFBCTunerManager::isCompatibleWith] score : %d (%d->%d)", c, FE_SLOT_ID(it), FE_SLOT_ID(link_fe));
592                 if (c > best_score)
593                 {
594                         best_score = c;
595                         fbc_fe = (eDVBRegisteredFrontend *)*it;
596                 }
597
598                 /* disconnect link */
599                 disconnectLinkNoSimulate(link_fe);
600         }
601
602         eFecDebug("[*][eFBCTunerManager::isCompatibleWith] fe : %p(%d), score : %d %s", link_fe, FE_SLOT_ID(link_fe), best_score, simulate?"(simulate)":"");
603
604         return best_score;
605 }
606
607 void eFBCTunerManager::connectSortedLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *top_fe, bool simulate)
608 {
609         int link_fe_id = FE_SLOT_ID(link_fe);
610         int top_fe_id = FE_SLOT_ID(top_fe);
611         int prev_fe_id = link_fe_id - 1;
612
613         eFecDebug("     [*][eFBCTunerManager::connectSortedLink] link_id : %d, top_id : %d %s", link_fe_id, top_fe_id, simulate?"(simulate)":"");
614
615         if (prev_fe_id < 0)
616         {
617                 eFecDebug("     [*][eFBCTunerManager::connectSortedLink] link failed! link_id : %d, top_id : %d %s", link_fe_id, top_fe_id, simulate?"(simulate)":"");
618                 return;
619         }
620
621         /* serach prev fe */
622         eDVBRegisteredFrontend *next_fe = top_fe;
623         long linked_next_ptr = -1;
624         top_fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr);
625         while(linked_next_ptr != -1)
626         {
627                 next_fe = (eDVBRegisteredFrontend *)linked_next_ptr;
628                 next_fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr);
629                 if (FE_SLOT_ID(next_fe) == prev_fe_id)
630                         break;
631         }
632
633         eDVBRegisteredFrontend *prev_fe = next_fe;
634
635         /* get next fe */
636         next_fe = getNext(prev_fe);     
637
638         /* connect */
639         if (next_fe)
640         {
641                 int res = connectLink(link_fe, prev_fe, next_fe, simulate);
642                 if (res)
643                 {
644                         eDebug("[*][eFBCTunerManager::connectSortedLink] ERROR! connect link failed! (%d->%d->%d)", FE_SLOT_ID(prev_fe), FE_SLOT_ID(link_fe), FE_SLOT_ID(next_fe));
645                         return;
646                 }
647         }
648         else
649         {
650                 int res = connectLink(link_fe, prev_fe, simulate);
651                 if (res)
652                 {
653                         eDebug("[*][eFBCTunerManager::connectSortedLink] ERROR! connect link failed! (%d->%d)", FE_SLOT_ID(prev_fe), FE_SLOT_ID(link_fe));
654                         return;
655                 }
656         }
657
658         /* set proc fbc_id */
659         setProcFBCID(link_fe_id, getFBCID(top_fe_id));
660
661         /* add slot mask*/
662         updateLNBSlotMask(link_fe_id, top_fe_id, false);
663 }
664
665 /* attach link_fe to tail of fe linked list */
666 void eFBCTunerManager::addLink(eDVBRegisteredFrontend *link_fe, eDVBRegisteredFrontend *top_fe, bool simulate)
667 {
668         eFecDebug("     [*][eFBCTunerManager::addLink] addLink : %p(%d)->%p(%d) %s", top_fe, FE_SLOT_ID(top_fe), link_fe, FE_SLOT_ID(link_fe), simulate?"(simulate)":"");
669
670         if (!isRootFe(top_fe))
671                 return;
672
673 //      eDVBRegisteredFrontend *top_fe = a_top_fe;
674 //      if (!checkTop(top_fe))
675 //              top_fe = getTop(top_fe);
676
677 //      printLinks(top_fe);
678         connectSortedLink(link_fe, top_fe, simulate);
679 //      printLinks(top_fe);
680 }
681
682 /* if fe, fe_simulated is unused, unlink current frontend from linked things. */
683 /* all unused linked fbc fe must be unlinked! */
684 void eFBCTunerManager::unset(eDVBRegisteredFrontend *fe)
685 {
686         bool simulate = fe->m_frontend->is_simulate();
687
688         if (isRootFe(fe))
689                 return;
690
691         if(checkUsed(fe, simulate))
692                 return;
693
694         if(isUnicable(fe))
695                 return;
696
697         eFecDebug("     [*][eFBCTunerManager::unset] fe id : %p(%d) %s", fe, FE_SLOT_ID(fe), simulate?"(simulate)":"");
698
699         
700 //      printLinks(fe);
701
702         eDVBRegisteredFrontend *linked_prev_fe = getPrev(fe);
703         eDVBRegisteredFrontend *linked_next_fe = getNext(fe);
704
705         if (!linked_prev_fe)
706         {
707                 eDebug("[*][eFBCTunerManager::unset] ERROR! can not found prev linked frontend (fe_id : %d)", FE_SLOT_ID(fe));
708                 return;
709         }
710
711         if (linked_next_fe)
712         {
713                 int res = disconnectLink(fe, linked_prev_fe, linked_next_fe, simulate);
714                 if (res)
715                 {
716                         eDebug("[*][eFBCTunerManager::unset] ERROR! disconnect link failed! (%d->%d->%d)", FE_SLOT_ID(linked_prev_fe), FE_SLOT_ID(fe), FE_SLOT_ID(linked_next_fe));
717                         return;
718                 }
719         }
720         else
721         {
722                 int res = disconnectLink(fe, linked_prev_fe, simulate);
723                 if (res)
724                 {
725                         eDebug("[*][eFBCTunerManager::unset] ERROR! disconnect link failed! (%d->%d)", FE_SLOT_ID(linked_prev_fe), FE_SLOT_ID(fe));
726                         return;
727                 }
728         }
729
730         /* set proc fbc_id (skip) */
731
732         /* remove slot mask*/
733         updateLNBSlotMask(FE_SLOT_ID(fe), FE_SLOT_ID(linked_prev_fe), true);
734
735 //      printLinks(fe);
736 }
737
738 bool eFBCTunerManager::canAllocateLink(eDVBRegisteredFrontend *fe, bool simulate)
739 {
740         if (!isRootFe(fe))
741                 return false;
742
743         if (isLinked(fe))
744                 return false;
745
746         eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_res_mgr->m_simulate_frontend : m_res_mgr->m_frontend;
747         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
748         {
749                 if (it->m_frontend->is_FBCTuner() && !isRootFe(*it) && isSameFbcSet(FE_SLOT_ID(fe), FE_SLOT_ID(it)) && !it->m_frontend->getEnabled() && !isLinked(*it))
750                         return true;
751         }
752
753         return false;
754 }
755
756 int eFBCTunerManager::updateLNBSlotMask(int dest_slot, int src_slot, bool remove)
757 {
758         ePtr<eDVBSatelliteEquipmentControl> sec = eDVBSatelliteEquipmentControl::getInstance();
759
760         int sec_lnbidx = sec->m_lnbidx;
761
762         int found = 0;
763         for (int idx=0; idx <= sec_lnbidx; ++idx )
764         {
765                 eDVBSatelliteLNBParameters &lnb_param = sec->m_lnbs[idx];
766                 if ( lnb_param.m_slot_mask & (1 << src_slot) )
767                 {
768                         eFecDebug("[*][eFBCTunerManager::updateLNBSlotMask] m_slot_mask : %d", lnb_param.m_slot_mask);
769
770                         if (!remove)
771                                 lnb_param.m_slot_mask |= (1 << dest_slot);
772                         else
773                                 lnb_param.m_slot_mask &= ~(1 << dest_slot);
774
775                         eFecDebug("[*][eFBCTunerManager::updateLNBSlotMask] changed m_slot_mask : %d", lnb_param.m_slot_mask);
776                         found = 1;
777                 }
778         }
779
780         if (!found)
781                 eFecDebug("[*][eFBCTunerManager::updateLNBSlotMask] src %d not found", src_slot);
782
783         return 0;
784 }
785
786 int eFBCTunerManager::getLinkedSlotID(int fe_id)
787 {
788         int link = -1;
789         eSmartPtrList<eDVBRegisteredFrontend> &frontends = m_res_mgr->m_frontend;
790         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
791         {
792                 if(it->m_frontend->getSlotID() == fe_id)
793                 {
794                         long prev_ptr = -1;
795                         it->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, prev_ptr);
796                         if (prev_ptr != -1)
797                         {
798                                 eDVBRegisteredFrontend *prev_fe = (eDVBRegisteredFrontend *)prev_ptr;
799                                 link = FE_SLOT_ID(prev_fe);
800                         }
801                         break;
802                 }
803         }
804
805         eFecDebug(" [*][eFBCTunerManager::getLinkedSlotID] fe_id : %d, link : %d", fe_id, link);
806
807         return link;
808 }
809
810 void eFBCTunerManager::printLinks(eDVBRegisteredFrontend *fe)
811 {
812         long linked_prev_ptr = -1;
813         eDVBRegisteredFrontend *linked_prev_fe = fe;
814         fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, linked_prev_ptr);
815         while (linked_prev_ptr != -1)
816         {
817                 linked_prev_fe = (eDVBRegisteredFrontend*) linked_prev_ptr;
818                 linked_prev_fe->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, (long&)linked_prev_ptr);
819         }
820
821         long linked_next_ptr = -1;
822         eDVBRegisteredFrontend *linked_next_fe = linked_prev_fe;
823         eFecDebug("     [*][eFBCTunerManager::printLinks] fe id : %d (%p), inuse : %d, enabled : %d, fbc : %d", FE_SLOT_ID(linked_next_fe), linked_next_fe, linked_next_fe->m_inuse, linked_next_fe->m_frontend->getEnabled(), linked_next_fe->m_frontend->is_FBCTuner());
824         linked_prev_fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, linked_next_ptr);
825         while (linked_next_ptr != -1)
826         {
827                 linked_next_fe = (eDVBRegisteredFrontend*) linked_next_ptr;
828                 eFecDebug("     [*][eFBCTunerManager::printLinks] fe id : %d (%p), inuse : %d, enabled : %d, fbc : %d", FE_SLOT_ID(linked_next_fe), linked_next_fe, linked_next_fe->m_inuse, linked_next_fe->m_frontend->getEnabled(), linked_next_fe->m_frontend->is_FBCTuner());
829                 linked_next_fe->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, (long&)linked_next_ptr);
830         }
831
832         eSmartPtrList<eDVBRegisteredFrontend> &frontends = m_res_mgr->m_frontend;
833         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(frontends.begin()); it != frontends.end(); ++it)
834         {
835                 int prev = -1;
836                 int next = -1;
837                 long prev_ptr = -1;
838                 long next_ptr = -1;
839                 it->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, prev_ptr);
840                 it->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, next_ptr);
841                 if (prev_ptr != -1)
842                 {
843                         eDVBRegisteredFrontend *prev_fe = (eDVBRegisteredFrontend *)prev_ptr;
844                         prev = FE_SLOT_ID(prev_fe);
845                 }
846
847                 if (next_ptr != -1)
848                 {
849                         eDVBRegisteredFrontend *next_fe = (eDVBRegisteredFrontend *)next_ptr;
850                         next = FE_SLOT_ID(next_fe);
851                 }
852                 
853                 eFecDebug("     [*][eFBCTunerManager::printLinks] fe_id : %d, inuse : %d, enabled : %d, fbc : %d, prev : %d, next : %d", FE_SLOT_ID(it), it->m_inuse, it->m_frontend->getEnabled(), it->m_frontend->is_FBCTuner(), prev, next);
854         }
855
856         eSmartPtrList<eDVBRegisteredFrontend> &simulate_frontends = m_res_mgr->m_simulate_frontend;
857         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator it(simulate_frontends.begin()); it != simulate_frontends.end(); ++it)
858         {
859                 int prev = -1;
860                 int next = -1;
861                 long prev_ptr = -1;
862                 long next_ptr = -1;
863                 it->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, prev_ptr);
864                 it->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, next_ptr);
865                 if (prev_ptr != -1)
866                 {
867                         eDVBRegisteredFrontend *prev_fe = (eDVBRegisteredFrontend *)prev_ptr;
868                         prev = FE_SLOT_ID(prev_fe);
869                 }
870
871                 if (next_ptr != -1)
872                 {
873                         eDVBRegisteredFrontend *next_fe = (eDVBRegisteredFrontend *)next_ptr;
874                         next = FE_SLOT_ID(next_fe);
875                 }
876                 
877                 eFecDebug("     [*][eFBCTunerManager::printLinks] fe_id : %2d, inuse : %d, enabled : %d, fbc : %d, prev : %2d, cur : %2d, next : %2d (simulate)", FE_SLOT_ID(it), it->m_inuse, it->m_frontend->getEnabled(), it->m_frontend->is_FBCTuner(), prev, FE_SLOT_ID(it), next);
878         }
879 }
880