File indexing completed on 2025-01-19 04:27:59

0001 /*
0002  * dvbdevice_linux.cpp
0003  *
0004  * Copyright (C) 2007-2011 Christoph Pfister <christophpfister@gmail.com>
0005  * Copyright (c) 2014 Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
0006  *
0007  * This program is free software; you can redistribute it and/or modify
0008  * it under the terms of the GNU General Public License as published by
0009  * the Free Software Foundation; either version 2 of the License, or
0010  * (at your option) any later version.
0011  *
0012  * This program is distributed in the hope that it will be useful,
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0015  * GNU General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU General Public License along
0018  * with this program; if not, write to the Free Software Foundation, Inc.,
0019  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
0020  */
0021 
0022 #include "../log.h"
0023 
0024 extern "C" {
0025   #include <dmx.h>
0026   #include <errno.h>
0027   #include <fcntl.h>
0028   #include <frontend.h>
0029   #include <poll.h>
0030 }
0031 
0032 #include <QFile>
0033 #include <QCheckBox>
0034 #include <QMessageLogger>
0035 #include <QRegularExpressionMatch>
0036 #include <Solid/Device>
0037 #include <Solid/DeviceNotifier>
0038 
0039 #include "dvbdevice_linux.h"
0040 #include "dvbtransponder.h"
0041 
0042 #if EAGAIN == EWOULDBLOCK
0043   #define IS_EAGAIN(e) (e == EAGAIN)
0044 #else
0045   #define IS_EAGAIN(e) (e == EAGAIN || e == EWOULDBLOCK)
0046 #endif
0047 
0048 // krazy:excludeall=syscalls
0049 
0050 DvbLinuxDevice::DvbLinuxDevice(QObject *parent) : QThread(parent), ready(false), frontend(NULL),
0051     enabled(false), dvrFd(-1), dvrBuffer(NULL, 0), cam(parent)
0052 {
0053     verbose = 1;
0054     numDemux = 0;
0055     dvrPipe[0] = -1;
0056     dvrPipe[1] = -1;
0057 }
0058 
0059 DvbLinuxDevice::~DvbLinuxDevice()
0060 {
0061     stopDevice();
0062 }
0063 
0064 static void dvbv5_log(int level, const char *fmt, ...)
0065 {
0066     va_list ap;
0067     char log[1024];
0068 
0069     va_start(ap, fmt);
0070     vsnprintf(log, sizeof(log), fmt, ap);
0071     va_end(ap);
0072 
0073     switch(LOG_PRI(level)) {
0074     case LOG_DEBUG:
0075     case LOG_INFO:
0076         qCDebug(logDev, "%s", log);
0077         break;
0078     case LOG_NOTICE:
0079         qCInfo(logDev, "%s", log);
0080         break;
0081     case LOG_WARNING:
0082         qCWarning(logDev, "%s", log);
0083         break;
0084     case LOG_ERR:
0085     case LOG_CRIT:
0086     case LOG_ALERT:
0087     case LOG_EMERG:
0088         qCCritical(logDev, "%s", log);
0089         break;
0090     }
0091 }
0092 
0093 bool DvbLinuxDevice::isReady() const
0094 {
0095     return ready;
0096 }
0097 
0098 void DvbLinuxDevice::startDevice(const QString &deviceId_)
0099 {
0100     Q_ASSERT(!ready);
0101     struct dvb_v5_fe_parms *parms = dvb_fe_open2(adapter, index, verbose, 0, dvbv5_log);
0102 
0103     if (!parms) {
0104         qCWarning(logDev, "Cannot open frontend %s", qPrintable(frontendPath));
0105         return;
0106     }
0107 
0108     transmissionTypes = Nothing;
0109     for (int i = 0; i < parms->num_systems; i++) {
0110         switch (parms->systems[i]) {
0111         case SYS_DVBS:
0112             transmissionTypes |= DvbS;
0113             break;
0114         case SYS_DVBS2:
0115             transmissionTypes |= DvbS2;
0116             break;
0117         case SYS_DVBT:
0118             transmissionTypes |= DvbT;
0119             break;
0120         case SYS_DVBT2:
0121             transmissionTypes |= DvbT2;
0122             break;
0123         case SYS_DVBC_ANNEX_A:
0124         case SYS_DVBC_ANNEX_C:
0125             transmissionTypes |= DvbC;
0126             break;
0127         case SYS_ATSC:
0128         case SYS_DVBC_ANNEX_B:
0129             transmissionTypes |= Atsc;
0130             break;
0131         case SYS_ISDBT:
0132             transmissionTypes |= IsdbT;
0133             break;
0134         default: /* not supported yet */
0135             qCWarning(logDev, "Unsupported transmission type: %d", parms->systems[i]);
0136             break;
0137         }
0138     }
0139 
0140     deviceId = deviceId_;
0141     frontendName = QString::fromUtf8(parms->info.name);
0142 
0143     capabilities = None;
0144 
0145     if ((parms->info.caps & FE_CAN_QAM_AUTO) != 0) {
0146         capabilities |= DvbTModulationAuto;
0147     }
0148 
0149     if ((parms->info.caps & FE_CAN_FEC_AUTO) != 0) {
0150         capabilities |= DvbTFecAuto;
0151     }
0152 
0153     if ((parms->info.caps & FE_CAN_TRANSMISSION_MODE_AUTO) != 0) {
0154         capabilities |= DvbTTransmissionModeAuto;
0155     }
0156 
0157     if ((parms->info.caps & FE_CAN_GUARD_INTERVAL_AUTO) != 0) {
0158         capabilities |= DvbTGuardIntervalAuto;
0159     }
0160 
0161     // Get the supported LNBf types if the device supports satellite
0162     if (transmissionTypes & (DvbS | DvbS2)) {
0163         for (int i = 0;; i++) {
0164             const struct dvb_sat_lnb *lnb = dvb_sat_get_lnb(i);
0165 
0166             if (!lnb)
0167                 break;
0168 
0169             struct lnbSat lnbSat;
0170 
0171             // FIXME: on newer libdvbv5, use dvb_sat_get_lnb_name() in
0172             // order to get the name i18n translated
0173             lnbSat.name = QString::fromUtf8(lnb->name);
0174             lnbSat.alias = QString::fromUtf8(lnb->alias);
0175             lnbSat.lowFreq = lnb->lowfreq;
0176             lnbSat.highFreq = lnb->highfreq;
0177             lnbSat.rangeSwitch = lnb->rangeswitch;
0178             lnbSat.freqRange[0].low = lnb->freqrange[0].low;
0179             lnbSat.freqRange[0].high = lnb->freqrange[0].high;
0180             lnbSat.freqRange[1].low = lnb->freqrange[1].low;
0181             lnbSat.freqRange[1].high = lnb->freqrange[1].high;
0182 
0183             qCDebug(logDev, "supports lnb %s", lnb->alias);
0184 
0185             lnbSatModels.append(lnbSat);
0186         }
0187     }
0188 
0189     dvb_fe_close(parms);
0190 
0191     ready = true;
0192 
0193     qCInfo(logDev, "Found dvb device %s: %s", qPrintable(deviceId), qPrintable(frontendName));
0194 }
0195 
0196 void DvbLinuxDevice::startCa()
0197 {
0198     Q_ASSERT(ready && !caPath.isEmpty());
0199 
0200     if (enabled) {
0201         cam.startCa(caPath);
0202     }
0203 }
0204 
0205 void DvbLinuxDevice::stopCa()
0206 {
0207     Q_ASSERT(ready && caPath.isEmpty());
0208 
0209     if (enabled) {
0210         cam.stopCa();
0211     }
0212 }
0213 
0214 void DvbLinuxDevice::stopDevice()
0215 {
0216     setDeviceEnabled(false);
0217     ready = false;
0218 }
0219 
0220 QString DvbLinuxDevice::getDeviceId()
0221 {
0222     Q_ASSERT(ready);
0223     return deviceId;
0224 }
0225 
0226 QString DvbLinuxDevice::getFrontendName()
0227 {
0228     Q_ASSERT(ready);
0229     return frontendName;
0230 }
0231 
0232 DvbLinuxDevice::TransmissionTypes DvbLinuxDevice::getTransmissionTypes()
0233 {
0234     Q_ASSERT(ready);
0235     return transmissionTypes;
0236 }
0237 
0238 DvbLinuxDevice::Capabilities DvbLinuxDevice::getCapabilities()
0239 {
0240     Q_ASSERT(ready);
0241     return capabilities;
0242 }
0243 
0244 void DvbLinuxDevice::setFrontendDevice(DvbFrontendDevice *frontend_)
0245 {
0246     frontend = frontend_;
0247 }
0248 
0249 void DvbLinuxDevice::setDeviceEnabled(bool enabled_)
0250 {
0251     Q_ASSERT(ready);
0252 
0253     if (enabled != enabled_) {
0254         enabled = enabled_;
0255 
0256         if (enabled) {
0257             if (!caPath.isEmpty()) {
0258                 cam.startCa(caPath);
0259             }
0260         } else {
0261             release();
0262             cam.stopCa();
0263         }
0264     }
0265 }
0266 
0267 bool DvbLinuxDevice::acquire()
0268 {
0269     Q_ASSERT(enabled && (!dvbv5_parms) && (dvrFd < 0));
0270     dvbv5_parms = dvb_fe_open2(adapter, index, verbose, 0, dvbv5_log);
0271 
0272     if (!dvbv5_parms) {
0273         qCWarning(logDev, "Cannot open frontend %s", qPrintable(frontendPath));
0274         return false;
0275     }
0276 
0277     dvrFd = open(QFile::encodeName(dvrPath).constData(), O_RDONLY | O_NONBLOCK | O_CLOEXEC);
0278 
0279     if (dvrFd < 0) {
0280         qCWarning(logDev, "Cannot open dvr %s", qPrintable(dvrPath));
0281         dvb_fe_close(dvbv5_parms);
0282         dvbv5_parms = NULL;
0283         return false;
0284     }
0285 
0286     return true;
0287 }
0288 
0289 bool DvbLinuxDevice::setHighVoltage(int higherVoltage)
0290 {
0291     Q_ASSERT(dvbv5_parms);
0292 
0293     if ((Qt::CheckState)higherVoltage == Qt::PartiallyChecked)
0294         return true;
0295 
0296     if (dvb_fe_lnb_high_voltage(dvbv5_parms, higherVoltage ? 1 : 0))
0297         return false;
0298 
0299     return true;
0300 }
0301 
0302 bool DvbLinuxDevice::sendMessage(const char *message, int length)
0303 {
0304     Q_ASSERT(dvbv5_parms && (length >= 0) && (length <= 6));
0305 
0306     if (dvb_fe_diseqc_cmd(dvbv5_parms, length, (const unsigned char *)message) != 0) {
0307         qCWarning(logDev, "ioctl FE_DISEQC_SEND_MASTER_CMD failed for frontend %s", qPrintable(frontendPath));
0308         return false;
0309     }
0310 
0311     return true;
0312 }
0313 
0314 bool DvbLinuxDevice::sendBurst(SecBurst burst)
0315 {
0316     Q_ASSERT(dvbv5_parms);
0317 
0318     if (dvb_fe_diseqc_burst(dvbv5_parms, burst == BurstMiniB) != 0) {
0319         qCWarning(logDev, "ioctl FE_DISEQC_SEND_BURST failed for frontend %s", qPrintable(frontendPath));
0320         return false;
0321     }
0322 
0323     return true;
0324 }
0325 
0326 static fe_modulation_t toDvbModulation(DvbCTransponder::Modulation modulation)
0327 {
0328     switch (modulation) {
0329     case DvbCTransponder::Qam16: return QAM_16;
0330     case DvbCTransponder::Qam32: return QAM_32;
0331     case DvbCTransponder::Qam64: return QAM_64;
0332     case DvbCTransponder::Qam128: return QAM_128;
0333     case DvbCTransponder::Qam256: return QAM_256;
0334     case DvbCTransponder::ModulationAuto: return QAM_AUTO;
0335     }
0336 
0337     return QAM_AUTO;
0338 }
0339 
0340 static fe_modulation_t toDvbModulation(DvbS2Transponder::Modulation modulation)
0341 {
0342     switch (modulation) {
0343     case DvbS2Transponder::Qpsk: return QPSK;
0344     case DvbS2Transponder::Psk8: return PSK_8;
0345     case DvbS2Transponder::Apsk16: return APSK_16;
0346     case DvbS2Transponder::Apsk32: return APSK_32;
0347     case DvbS2Transponder::ModulationAuto: return QAM_AUTO;
0348     }
0349 
0350     return QAM_AUTO;
0351 }
0352 
0353 static fe_rolloff toDvbRollOff(DvbS2Transponder::RollOff rollOff)
0354 {
0355     switch (rollOff) {
0356     case DvbS2Transponder::RollOff20: return ROLLOFF_20;
0357     case DvbS2Transponder::RollOff25: return ROLLOFF_25;
0358     case DvbS2Transponder::RollOff35: return ROLLOFF_35;
0359     case DvbS2Transponder::RollOffAuto: return ROLLOFF_AUTO;
0360     }
0361 
0362     return ROLLOFF_AUTO;
0363 }
0364 
0365 static fe_modulation_t toDvbModulation(DvbTTransponder::Modulation modulation)
0366 {
0367     switch (modulation) {
0368     case DvbTTransponder::Qpsk: return QPSK;
0369     case DvbTTransponder::Qam16: return QAM_16;
0370     case DvbTTransponder::Qam64: return QAM_64;
0371     case DvbTTransponder::ModulationAuto: return QAM_AUTO;
0372     }
0373 
0374     return QAM_AUTO;
0375 }
0376 
0377 static fe_modulation_t toDvbModulation(DvbT2Transponder::Modulation modulation)
0378 {
0379     switch (modulation) {
0380     case DvbT2Transponder::Qpsk: return QPSK;
0381     case DvbT2Transponder::Qam16: return QAM_16;
0382     case DvbT2Transponder::Qam64: return QAM_64;
0383     case DvbT2Transponder::Qam256: return QAM_256;
0384     case DvbT2Transponder::ModulationAuto: return QAM_AUTO;
0385     }
0386 
0387     return QAM_AUTO;
0388 }
0389 
0390 static fe_modulation_t toDvbModulation(IsdbTTransponder::Modulation modulation)
0391 {
0392     switch (modulation) {
0393     case IsdbTTransponder::Qpsk: return QPSK;
0394     case IsdbTTransponder::Dqpsk: return DQPSK;
0395     case IsdbTTransponder::Qam16: return QAM_16;
0396     case IsdbTTransponder::Qam64: return QAM_64;
0397     case IsdbTTransponder::ModulationAuto: return QAM_AUTO;
0398     }
0399 
0400     return QAM_AUTO;
0401 }
0402 
0403 static fe_modulation_t toDvbModulation(AtscTransponder::Modulation modulation)
0404 {
0405     switch (modulation) {
0406     case AtscTransponder::Qam64: return QAM_64;
0407     case AtscTransponder::Qam256: return QAM_256;
0408     case AtscTransponder::Vsb8: return VSB_8;
0409     case AtscTransponder::Vsb16: return VSB_16;
0410     case AtscTransponder::ModulationAuto: return QAM_AUTO;
0411     }
0412 
0413     return QAM_AUTO;
0414 }
0415 
0416 static fe_code_rate toDvbFecRate(DvbTransponderBase::FecRate fecRate)
0417 {
0418     switch (fecRate) {
0419     case DvbTransponderBase::FecNone: return FEC_NONE;
0420     case DvbTransponderBase::Fec1_2: return FEC_1_2;
0421     case DvbTransponderBase::Fec1_3: return FEC_AUTO; // FIXME
0422     case DvbTransponderBase::Fec1_4: return FEC_AUTO; // FIXME
0423     case DvbTransponderBase::Fec2_3: return FEC_2_3;
0424     case DvbTransponderBase::Fec2_5: return FEC_2_5;
0425     case DvbTransponderBase::Fec3_4: return FEC_3_4;
0426     case DvbTransponderBase::Fec3_5: return FEC_3_5;
0427     case DvbTransponderBase::Fec4_5: return FEC_4_5;
0428     case DvbTransponderBase::Fec5_6: return FEC_5_6;
0429     case DvbTransponderBase::Fec6_7: return FEC_6_7;
0430     case DvbTransponderBase::Fec7_8: return FEC_7_8;
0431     case DvbTransponderBase::Fec8_9: return FEC_8_9;
0432     case DvbTransponderBase::Fec9_10: return FEC_9_10;
0433     case DvbTransponderBase::FecAuto: return FEC_AUTO;
0434     }
0435 
0436     return FEC_AUTO;
0437 }
0438 
0439 static uint32_t toDvbBandwidth(DvbTTransponder::Bandwidth bandwidth)
0440 {
0441     switch (bandwidth) {
0442     case DvbTTransponder::Bandwidth5MHz: return 5000000;
0443     case DvbTTransponder::Bandwidth6MHz: return 6000000;
0444     case DvbTTransponder::Bandwidth7MHz: return 7000000;
0445     case DvbTTransponder::Bandwidth8MHz: return 8000000;
0446     case DvbTTransponder::BandwidthAuto: return 0;
0447     }
0448 
0449     return BANDWIDTH_AUTO;
0450 }
0451 
0452 static uint32_t toDvbBandwidth(DvbT2Transponder::Bandwidth bandwidth)
0453 {
0454     switch (bandwidth) {
0455     case DvbT2Transponder::Bandwidth1_7MHz: return 1700000;
0456     case DvbT2Transponder::Bandwidth5MHz:   return 5000000;
0457     case DvbT2Transponder::Bandwidth6MHz:   return 6000000;
0458     case DvbT2Transponder::Bandwidth7MHz:   return 7000000;
0459     case DvbT2Transponder::Bandwidth8MHz:   return 8000000;
0460     case DvbT2Transponder::Bandwidth10MHz:  return 10000000;
0461     case DvbT2Transponder::BandwidthAuto:   return 0;
0462     }
0463 
0464     return BANDWIDTH_AUTO;
0465 }
0466 
0467 static uint32_t toDvbBandwidth(IsdbTTransponder::Bandwidth bandwidth)
0468 {
0469     switch (bandwidth) {
0470     case IsdbTTransponder::Bandwidth6MHz: return 6000000;
0471     case IsdbTTransponder::Bandwidth7MHz: return 7000000;
0472     case IsdbTTransponder::Bandwidth8MHz: return 8000000;
0473     }
0474 
0475     return BANDWIDTH_AUTO;
0476 }
0477 
0478 static fe_transmit_mode toDvbTransmissionMode(DvbTTransponder::TransmissionMode mode)
0479 {
0480     switch (mode) {
0481     case DvbTTransponder::TransmissionMode2k: return TRANSMISSION_MODE_2K;
0482     case DvbTTransponder::TransmissionMode4k: return TRANSMISSION_MODE_4K;
0483     case DvbTTransponder::TransmissionMode8k: return TRANSMISSION_MODE_8K;
0484     case DvbTTransponder::TransmissionModeAuto: return TRANSMISSION_MODE_AUTO;
0485     }
0486 
0487     return TRANSMISSION_MODE_AUTO;
0488 }
0489 
0490 static fe_transmit_mode toDvbTransmissionMode(DvbT2Transponder::TransmissionMode mode)
0491 {
0492     switch (mode) {
0493     case DvbT2Transponder::TransmissionMode1k:  return TRANSMISSION_MODE_1K;
0494     case DvbT2Transponder::TransmissionMode2k:  return TRANSMISSION_MODE_2K;
0495     case DvbT2Transponder::TransmissionMode4k:  return TRANSMISSION_MODE_4K;
0496     case DvbT2Transponder::TransmissionMode8k:  return TRANSMISSION_MODE_8K;
0497     case DvbT2Transponder::TransmissionMode16k: return TRANSMISSION_MODE_16K;
0498     case DvbT2Transponder::TransmissionMode32k: return TRANSMISSION_MODE_32K;
0499     case DvbT2Transponder::TransmissionModeAuto: return TRANSMISSION_MODE_AUTO;
0500     }
0501 
0502     return TRANSMISSION_MODE_AUTO;
0503 }
0504 
0505 static fe_transmit_mode toDvbTransmissionMode(IsdbTTransponder::TransmissionMode mode)
0506 {
0507     switch (mode) {
0508     case IsdbTTransponder::TransmissionMode2k: return TRANSMISSION_MODE_2K;
0509     case IsdbTTransponder::TransmissionMode4k: return TRANSMISSION_MODE_4K;
0510     case IsdbTTransponder::TransmissionMode8k: return TRANSMISSION_MODE_8K;
0511     case IsdbTTransponder::TransmissionModeAuto: return TRANSMISSION_MODE_AUTO;
0512     }
0513 
0514     return TRANSMISSION_MODE_AUTO;
0515 }
0516 
0517 static fe_guard_interval toDvbGuardInterval(DvbTTransponder::GuardInterval guardInterval)
0518 {
0519     switch (guardInterval) {
0520     case DvbTTransponder::GuardInterval1_4: return GUARD_INTERVAL_1_4;
0521     case DvbTTransponder::GuardInterval1_8: return GUARD_INTERVAL_1_8;
0522     case DvbTTransponder::GuardInterval1_16: return GUARD_INTERVAL_1_16;
0523     case DvbTTransponder::GuardInterval1_32: return GUARD_INTERVAL_1_32;
0524     case DvbTTransponder::GuardIntervalAuto: return GUARD_INTERVAL_AUTO;
0525     }
0526 
0527     return GUARD_INTERVAL_AUTO;
0528 }
0529 
0530 static fe_guard_interval toDvbGuardInterval(DvbT2Transponder::GuardInterval guardInterval)
0531 {
0532     switch (guardInterval) {
0533     case DvbT2Transponder::GuardInterval1_4:    return GUARD_INTERVAL_1_4;
0534     case DvbT2Transponder::GuardInterval19_128: return GUARD_INTERVAL_19_128;
0535     case DvbT2Transponder::GuardInterval1_8:    return GUARD_INTERVAL_1_8;
0536     case DvbT2Transponder::GuardInterval19_256: return GUARD_INTERVAL_19_256;
0537     case DvbT2Transponder::GuardInterval1_16:   return GUARD_INTERVAL_1_16;
0538     case DvbT2Transponder::GuardInterval1_32:   return GUARD_INTERVAL_1_32;
0539     case DvbT2Transponder::GuardInterval1_128:  return GUARD_INTERVAL_1_128;
0540     case DvbT2Transponder::GuardIntervalAuto:   return GUARD_INTERVAL_AUTO;
0541     }
0542 
0543     return GUARD_INTERVAL_AUTO;
0544 }
0545 
0546 static fe_guard_interval toDvbGuardInterval(IsdbTTransponder::GuardInterval guardInterval)
0547 {
0548     switch (guardInterval) {
0549     case IsdbTTransponder::GuardInterval1_4: return GUARD_INTERVAL_1_4;
0550     case IsdbTTransponder::GuardInterval1_8: return GUARD_INTERVAL_1_8;
0551     case IsdbTTransponder::GuardInterval1_16: return GUARD_INTERVAL_1_16;
0552     case IsdbTTransponder::GuardInterval1_32: return GUARD_INTERVAL_1_32;
0553     case IsdbTTransponder::GuardIntervalAuto: return GUARD_INTERVAL_AUTO;
0554     }
0555 
0556     return GUARD_INTERVAL_AUTO;
0557 }
0558 
0559 static uint32_t toDvbPartialReception(IsdbTTransponder::PartialReception partialReception)
0560 {
0561     switch (partialReception) {
0562     case IsdbTTransponder::PR_disabled: return 0;
0563     case IsdbTTransponder::PR_enabled: return 1;
0564     case IsdbTTransponder::PR_AUTO: return (uint32_t)-1;
0565     }
0566 
0567     return (uint32_t)-1;
0568 }
0569 
0570 static uint32_t toDvbSoundBroadcasting(IsdbTTransponder::SoundBroadcasting partialReception)
0571 {
0572     switch (partialReception) {
0573     case IsdbTTransponder::SB_disabled: return 0;
0574     case IsdbTTransponder::SB_enabled: return 1;
0575     case IsdbTTransponder::SB_AUTO: return (uint32_t)-1;
0576     }
0577 
0578     return (uint32_t)-1;
0579 }
0580 
0581 static uint32_t toDvbInterleaving(IsdbTTransponder::Interleaving interleaving)
0582 {
0583     switch (interleaving) {
0584     case IsdbTTransponder::I_0: return 0;
0585     case IsdbTTransponder::I_1: return 1;
0586     case IsdbTTransponder::I_2: return 2;
0587     case IsdbTTransponder::I_4: return 4;
0588     case IsdbTTransponder::I_8: return 8;
0589     case IsdbTTransponder::I_16: return 16;
0590     case IsdbTTransponder::I_AUTO: return (uint32_t)-1;
0591     }
0592 
0593     return (uint32_t)-1;
0594 }
0595 
0596 static uint32_t toDvbPolarization(DvbSTransponder::Polarization polarization)
0597 {
0598     switch (polarization) {
0599     case DvbSTransponder::Off:      return POLARIZATION_OFF;
0600     case DvbSTransponder::Horizontal:   return POLARIZATION_H;
0601     case DvbSTransponder::Vertical:     return POLARIZATION_V;
0602     case DvbSTransponder::CircularLeft: return POLARIZATION_L;
0603     case DvbSTransponder::CircularRight:    return POLARIZATION_R;
0604     }
0605 
0606     return (uint32_t)-1;
0607 }
0608 
0609 static fe_hierarchy toDvbHierarchy(DvbTTransponder::Hierarchy hierarchy)
0610 {
0611     switch (hierarchy) {
0612     case DvbTTransponder::HierarchyNone: return HIERARCHY_NONE;
0613     case DvbTTransponder::Hierarchy1: return HIERARCHY_1;
0614     case DvbTTransponder::Hierarchy2: return HIERARCHY_2;
0615     case DvbTTransponder::Hierarchy4: return HIERARCHY_4;
0616     case DvbTTransponder::HierarchyAuto: return HIERARCHY_AUTO;
0617     }
0618 
0619     return HIERARCHY_AUTO;
0620 }
0621 
0622 static fe_hierarchy toDvbHierarchy(DvbT2Transponder::Hierarchy hierarchy)
0623 {
0624     switch (hierarchy) {
0625     case DvbT2Transponder::HierarchyNone: return HIERARCHY_NONE;
0626     case DvbT2Transponder::Hierarchy1: return HIERARCHY_1;
0627     case DvbT2Transponder::Hierarchy2: return HIERARCHY_2;
0628     case DvbT2Transponder::Hierarchy4: return HIERARCHY_4;
0629     case DvbT2Transponder::HierarchyAuto: return HIERARCHY_AUTO;
0630     }
0631 
0632     return HIERARCHY_AUTO;
0633 }
0634 
0635 static DvbCTransponder::Modulation DvbCtoModulation(uint32_t modulation)
0636 {
0637     switch (modulation) {
0638     case QAM_16:   return DvbCTransponder::Qam16;
0639     case QAM_32:   return DvbCTransponder::Qam32;
0640     case QAM_64:   return DvbCTransponder::Qam64;
0641     case QAM_128:  return DvbCTransponder::Qam128;
0642     case QAM_256:  return DvbCTransponder::Qam256;
0643     default:       return DvbCTransponder::ModulationAuto;
0644     }
0645 }
0646 
0647 static DvbS2Transponder::Modulation DvbS2toModulation(uint32_t modulation)
0648 {
0649     switch (modulation) {
0650     case QPSK:     return DvbS2Transponder::Qpsk;
0651     case PSK_8:    return DvbS2Transponder::Psk8;
0652     case APSK_16:  return DvbS2Transponder::Apsk16;
0653     case APSK_32:  return DvbS2Transponder::Apsk32;
0654     default:       return DvbS2Transponder::ModulationAuto;
0655     }
0656 }
0657 
0658 static DvbS2Transponder::RollOff DvbS2toRollOff(uint32_t rollOff)
0659 {
0660     switch (rollOff) {
0661     case ROLLOFF_20:   return DvbS2Transponder::RollOff20;
0662     case ROLLOFF_25:   return DvbS2Transponder::RollOff25;
0663     case ROLLOFF_35:   return DvbS2Transponder::RollOff35;
0664     default: return DvbS2Transponder::RollOffAuto;
0665     }
0666 }
0667 
0668 static DvbTTransponder::Modulation DvbTtoModulation(uint32_t modulation)
0669 {
0670     switch (modulation) {
0671     case QPSK:     return DvbTTransponder::Qpsk;
0672     case QAM_16:   return DvbTTransponder::Qam16;
0673     case QAM_64:   return DvbTTransponder::Qam64;
0674     default:       return DvbTTransponder::ModulationAuto;
0675     }
0676 }
0677 
0678 static DvbT2Transponder::Modulation DvbT2toModulation(uint32_t modulation)
0679 {
0680     switch (modulation) {
0681     case QPSK:     return DvbT2Transponder::Qpsk;
0682     case QAM_16:   return DvbT2Transponder::Qam16;
0683     case QAM_64:   return DvbT2Transponder::Qam64;
0684     case QAM_256:  return DvbT2Transponder::Qam256;
0685     default:       return DvbT2Transponder::ModulationAuto;
0686     }
0687 }
0688 
0689 static IsdbTTransponder::Modulation IsdbTtoModulation(uint32_t modulation)
0690 {
0691     switch (modulation) {
0692     case QPSK:     return IsdbTTransponder::Qpsk;
0693     case DQPSK:    return IsdbTTransponder::Dqpsk;
0694     case QAM_16:   return IsdbTTransponder::Qam16;
0695     case QAM_64:   return IsdbTTransponder::Qam64;
0696     default:       return IsdbTTransponder::ModulationAuto;
0697     }
0698 }
0699 
0700 static AtscTransponder::Modulation AtsctoModulation(uint32_t modulation)
0701 {
0702     switch (modulation) {
0703     case QAM_64:   return AtscTransponder::Qam64;
0704     case QAM_256:  return AtscTransponder::Qam256;
0705     case VSB_8:    return AtscTransponder::Vsb8;
0706     case VSB_16:   return AtscTransponder::Vsb16;
0707     default:       return AtscTransponder::ModulationAuto;
0708     }
0709 }
0710 
0711 static DvbTransponderBase::FecRate DvbtoFecRate(uint32_t fecRate)
0712 {
0713     switch (fecRate) {
0714     case FEC_NONE: return DvbTransponderBase::FecNone;
0715     case FEC_1_2:  return DvbTransponderBase::Fec1_2;
0716 //  case FEC_AUTO: return DvbTransponderBase::Fec1_3; // FIXME
0717 //  case FEC_AUTO: return DvbTransponderBase::Fec1_4; // FIXME
0718     case FEC_2_3:  return DvbTransponderBase::Fec2_3;
0719     case FEC_2_5:  return DvbTransponderBase::Fec2_5;
0720     case FEC_3_4:  return DvbTransponderBase::Fec3_4;
0721     case FEC_3_5:  return DvbTransponderBase::Fec3_5;
0722     case FEC_4_5:  return DvbTransponderBase::Fec4_5;
0723     case FEC_5_6:  return DvbTransponderBase::Fec5_6;
0724     case FEC_6_7:  return DvbTransponderBase::Fec6_7;
0725     case FEC_7_8:  return DvbTransponderBase::Fec7_8;
0726     case FEC_8_9:  return DvbTransponderBase::Fec8_9;
0727     case FEC_9_10: return DvbTransponderBase::Fec9_10;
0728     default:       return DvbTransponderBase::FecAuto;
0729     }
0730 }
0731 
0732 static DvbTTransponder::Bandwidth DvbTtoBandwidth(uint32_t bandwidth)
0733 {
0734     switch (bandwidth) {
0735     case 5000000: return DvbTTransponder::Bandwidth5MHz;
0736     case 6000000: return DvbTTransponder::Bandwidth6MHz;
0737     case 7000000: return DvbTTransponder::Bandwidth7MHz;
0738     case 8000000: return DvbTTransponder::Bandwidth8MHz;
0739     default:      return DvbTTransponder::BandwidthAuto;
0740     }
0741 }
0742 
0743 static DvbT2Transponder::Bandwidth DvbT2toBandwidth(uint32_t bandwidth)
0744 {
0745     switch (bandwidth) {
0746     case 1700000:  return DvbT2Transponder::Bandwidth1_7MHz;
0747     case 5000000:  return DvbT2Transponder::Bandwidth5MHz;
0748     case 6000000:  return DvbT2Transponder::Bandwidth6MHz;
0749     case 7000000:  return DvbT2Transponder::Bandwidth7MHz;
0750     case 8000000:  return DvbT2Transponder::Bandwidth8MHz;
0751     case 10000000: return DvbT2Transponder::Bandwidth10MHz;
0752     default:       return DvbT2Transponder::BandwidthAuto;
0753     }
0754 }
0755 
0756 static IsdbTTransponder::Bandwidth IsdbTtoBandwidth(uint32_t bandwidth)
0757 {
0758     switch (bandwidth) {
0759     default:      return IsdbTTransponder::Bandwidth6MHz;
0760     case 7000000: return IsdbTTransponder::Bandwidth7MHz;
0761     case 8000000: return IsdbTTransponder::Bandwidth8MHz;
0762     }
0763 }
0764 
0765 static DvbTTransponder::TransmissionMode DvbTtoTransmissionMode(uint32_t mode)
0766 {
0767     switch (mode) {
0768     case TRANSMISSION_MODE_2K: return DvbTTransponder::TransmissionMode2k;
0769     case TRANSMISSION_MODE_4K: return DvbTTransponder::TransmissionMode4k;
0770     case TRANSMISSION_MODE_8K: return DvbTTransponder::TransmissionMode8k;
0771     default:                   return DvbTTransponder::TransmissionModeAuto;
0772     }
0773 }
0774 
0775 static DvbT2Transponder::TransmissionMode DvbT2toTransmissionMode(uint32_t mode)
0776 {
0777     switch (mode) {
0778     case TRANSMISSION_MODE_1K: return DvbT2Transponder::TransmissionMode1k;
0779     case TRANSMISSION_MODE_2K: return DvbT2Transponder::TransmissionMode2k;
0780     case TRANSMISSION_MODE_4K: return DvbT2Transponder::TransmissionMode4k;
0781     case TRANSMISSION_MODE_8K: return DvbT2Transponder::TransmissionMode8k;
0782     case TRANSMISSION_MODE_16K: return DvbT2Transponder::TransmissionMode16k;
0783     case TRANSMISSION_MODE_32K: return DvbT2Transponder::TransmissionMode32k;
0784     default:                   return DvbT2Transponder::TransmissionModeAuto;
0785     }
0786 }
0787 
0788 static IsdbTTransponder::TransmissionMode IsdbTtoTransmissionMode(uint32_t mode)
0789 {
0790     switch (mode) {
0791     case TRANSMISSION_MODE_2K: return IsdbTTransponder::TransmissionMode2k;
0792     case TRANSMISSION_MODE_4K: return IsdbTTransponder::TransmissionMode4k;
0793     case TRANSMISSION_MODE_8K: return IsdbTTransponder::TransmissionMode8k;
0794     default:                   return IsdbTTransponder::TransmissionModeAuto;
0795     }
0796 }
0797 
0798 static DvbTTransponder::GuardInterval DvbTtoGuardInterval(uint32_t guardInterval)
0799 {
0800     switch (guardInterval) {
0801     case GUARD_INTERVAL_1_4:  return DvbTTransponder::GuardInterval1_4;
0802     case GUARD_INTERVAL_1_8:  return DvbTTransponder::GuardInterval1_8;
0803     case GUARD_INTERVAL_1_16: return DvbTTransponder::GuardInterval1_16;
0804     case GUARD_INTERVAL_1_32: return DvbTTransponder::GuardInterval1_32;
0805     default:                  return DvbTTransponder::GuardIntervalAuto;
0806     }
0807 }
0808 
0809 static DvbT2Transponder::GuardInterval DvbT2toGuardInterval(uint32_t guardInterval)
0810 {
0811     switch (guardInterval) {
0812     case GUARD_INTERVAL_1_4:    return DvbT2Transponder::GuardInterval1_4;
0813     case GUARD_INTERVAL_19_128: return DvbT2Transponder::GuardInterval19_128;
0814     case GUARD_INTERVAL_1_8:    return DvbT2Transponder::GuardInterval1_8;
0815     case GUARD_INTERVAL_19_256: return DvbT2Transponder::GuardInterval19_256;
0816     case GUARD_INTERVAL_1_16:   return DvbT2Transponder::GuardInterval1_16;
0817     case GUARD_INTERVAL_1_32:   return DvbT2Transponder::GuardInterval1_32;
0818     case GUARD_INTERVAL_1_128:  return DvbT2Transponder::GuardInterval1_128;
0819     default:            return DvbT2Transponder::GuardIntervalAuto;
0820     }
0821 }
0822 
0823 static IsdbTTransponder::GuardInterval IsdbTtoGuardInterval(uint32_t guardInterval)
0824 {
0825     switch (guardInterval) {
0826     case GUARD_INTERVAL_1_4:  return IsdbTTransponder::GuardInterval1_4;
0827     case GUARD_INTERVAL_1_8:  return IsdbTTransponder::GuardInterval1_8;
0828     case GUARD_INTERVAL_1_16: return IsdbTTransponder::GuardInterval1_16;
0829     case GUARD_INTERVAL_1_32: return IsdbTTransponder::GuardInterval1_32;
0830     default:                  return IsdbTTransponder::GuardIntervalAuto;
0831     }
0832 }
0833 
0834 static IsdbTTransponder::PartialReception IsdbTtoPartialReception(uint32_t partialReception)
0835 {
0836     switch (partialReception) {
0837     case 0:  return IsdbTTransponder::PR_disabled;
0838     case 1:  return IsdbTTransponder::PR_enabled;
0839     default: return IsdbTTransponder::PR_AUTO;
0840     }
0841 }
0842 
0843 static IsdbTTransponder::SoundBroadcasting IsdbTtoSoundBroadcasting(uint32_t partialReception)
0844 {
0845     switch (partialReception) {
0846     case 0:  return IsdbTTransponder::SB_disabled;
0847     case 1:  return IsdbTTransponder::SB_enabled;
0848     default: return IsdbTTransponder::SB_AUTO;
0849     }
0850 }
0851 
0852 static IsdbTTransponder::Interleaving IsdbTtoInterleaving(uint32_t interleaving)
0853 {
0854     switch (interleaving) {
0855     case 0:  return IsdbTTransponder::I_0;
0856     case 1:  return IsdbTTransponder::I_1;
0857     case 2:  return IsdbTTransponder::I_2;
0858     case 4:  return IsdbTTransponder::I_4;
0859     case 8:  return IsdbTTransponder::I_8;
0860     case 16: return IsdbTTransponder::I_16;
0861     default: return IsdbTTransponder::I_AUTO;
0862     }
0863 }
0864 
0865 static DvbTTransponder::Hierarchy DvbTtoHierarchy(uint32_t hierarchy)
0866 {
0867     switch (hierarchy) {
0868     case HIERARCHY_NONE: return DvbTTransponder::HierarchyNone;
0869     case HIERARCHY_1:    return DvbTTransponder::Hierarchy1;
0870     case HIERARCHY_2:    return DvbTTransponder::Hierarchy2;
0871     case HIERARCHY_4:    return DvbTTransponder::Hierarchy4;
0872     default:             return DvbTTransponder::HierarchyAuto;
0873     }
0874 }
0875 
0876 static DvbT2Transponder::Hierarchy DvbT2toHierarchy(uint32_t hierarchy)
0877 {
0878     switch (hierarchy) {
0879     case HIERARCHY_NONE: return DvbT2Transponder::HierarchyNone;
0880     case HIERARCHY_1:    return DvbT2Transponder::Hierarchy1;
0881     case HIERARCHY_2:    return DvbT2Transponder::Hierarchy2;
0882     case HIERARCHY_4:    return DvbT2Transponder::Hierarchy4;
0883     default:             return DvbT2Transponder::HierarchyAuto;
0884     }
0885 }
0886 
0887 bool DvbLinuxDevice::satSetup(QString lnbModel, int satNumber, int bpf)
0888 {
0889     Q_ASSERT(dvbv5_parms);
0890 
0891     int lnb = dvb_sat_search_lnb(lnbModel.toUtf8());
0892     dvbv5_parms->lnb = dvb_sat_get_lnb(lnb);
0893     if (!dvbv5_parms->lnb) {
0894         qCCritical(logDev, "Cannot set LNBf type to %s", qPrintable(lnbModel));
0895         return false;
0896     }
0897 
0898     qCDebug(logDev, "Using LNBf type %s", qPrintable(lnbModel));
0899 
0900     dvbv5_parms->sat_number = satNumber;
0901     dvbv5_parms->freq_bpf = bpf;
0902 
0903     return true;
0904 }
0905 
0906 bool DvbLinuxDevice::tune(const DvbTransponder &transponder)
0907 {
0908     Q_ASSERT(dvbv5_parms);
0909     stopDvr();
0910     fe_delivery_system_t delsys;
0911 
0912     qCDebug(logDev, "tune to: %s", qPrintable(transponder.toString()));
0913 
0914     // FIXME: add support for LNA on/off
0915 
0916     switch (transponder.getTransmissionType()) {
0917     case DvbTransponderBase::DvbS: {
0918         const DvbSTransponder *dvbSTransponder = transponder.as<DvbSTransponder>();
0919 
0920         delsys = SYS_DVBS;
0921         dvb_set_sys(dvbv5_parms, delsys);
0922 
0923         dvb_fe_store_parm(dvbv5_parms, DTV_POLARIZATION, toDvbPolarization(dvbSTransponder->polarization));
0924         dvb_fe_store_parm(dvbv5_parms, DTV_FREQUENCY, dvbSTransponder->frequency);
0925         dvb_fe_store_parm(dvbv5_parms, DTV_INVERSION, INVERSION_AUTO);
0926         dvb_fe_store_parm(dvbv5_parms, DTV_SYMBOL_RATE, dvbSTransponder->symbolRate);
0927         dvb_fe_store_parm(dvbv5_parms, DTV_INNER_FEC, toDvbFecRate(dvbSTransponder->fecRate));
0928         freqMHz = dvbSTransponder->frequency / 1000.;
0929 
0930         /// FIXME
0931 
0932         break;
0933         }
0934     case DvbTransponderBase::DvbS2: {
0935         const DvbS2Transponder *dvbS2Transponder = transponder.as<DvbS2Transponder>();
0936 
0937         delsys = SYS_DVBS2;
0938         dvb_set_sys(dvbv5_parms, delsys);
0939 
0940         dvb_fe_store_parm(dvbv5_parms, DTV_POLARIZATION, toDvbPolarization(dvbS2Transponder->polarization));
0941         dvb_fe_store_parm(dvbv5_parms, DTV_FREQUENCY, dvbS2Transponder->frequency);
0942         dvb_fe_store_parm(dvbv5_parms, DTV_INVERSION, INVERSION_AUTO);
0943         dvb_fe_store_parm(dvbv5_parms, DTV_SYMBOL_RATE, dvbS2Transponder->symbolRate);
0944         dvb_fe_store_parm(dvbv5_parms, DTV_INNER_FEC, toDvbFecRate(dvbS2Transponder->fecRate));
0945         dvb_fe_store_parm(dvbv5_parms, DTV_MODULATION, toDvbModulation(dvbS2Transponder->modulation));
0946         dvb_fe_store_parm(dvbv5_parms, DTV_PILOT, PILOT_AUTO);
0947         dvb_fe_store_parm(dvbv5_parms, DTV_ROLLOFF, toDvbRollOff(dvbS2Transponder->rollOff));
0948         freqMHz = dvbS2Transponder->frequency / 1000.;
0949         break;
0950         }
0951     case DvbTransponderBase::DvbC: {
0952         const DvbCTransponder *dvbCTransponder = transponder.as<DvbCTransponder>();
0953 
0954         delsys = SYS_DVBC_ANNEX_A;
0955         dvb_set_sys(dvbv5_parms, delsys);
0956 
0957         dvb_fe_store_parm(dvbv5_parms, DTV_FREQUENCY, dvbCTransponder->frequency);
0958         dvb_fe_store_parm(dvbv5_parms, DTV_MODULATION, toDvbModulation(dvbCTransponder->modulation));
0959         dvb_fe_store_parm(dvbv5_parms, DTV_INVERSION, INVERSION_AUTO);
0960         dvb_fe_store_parm(dvbv5_parms, DTV_SYMBOL_RATE, dvbCTransponder->symbolRate);
0961         dvb_fe_store_parm(dvbv5_parms, DTV_INNER_FEC, toDvbFecRate(dvbCTransponder->fecRate));
0962         freqMHz = dvbCTransponder->frequency / 1000000.;
0963 
0964         break;
0965         }
0966     case DvbTransponderBase::DvbT: {
0967         const DvbTTransponder *dvbTTransponder = transponder.as<DvbTTransponder>();
0968 
0969         delsys = SYS_DVBT;
0970         dvb_set_sys(dvbv5_parms, delsys);
0971 
0972         dvb_fe_store_parm(dvbv5_parms, DTV_FREQUENCY, dvbTTransponder->frequency);
0973         dvb_fe_store_parm(dvbv5_parms, DTV_MODULATION, toDvbModulation(dvbTTransponder->modulation));
0974         dvb_fe_store_parm(dvbv5_parms, DTV_BANDWIDTH_HZ, toDvbBandwidth(dvbTTransponder->bandwidth));
0975         dvb_fe_store_parm(dvbv5_parms, DTV_INVERSION, INVERSION_AUTO);
0976         dvb_fe_store_parm(dvbv5_parms, DTV_CODE_RATE_HP, toDvbFecRate(dvbTTransponder->fecRateHigh));
0977         dvb_fe_store_parm(dvbv5_parms, DTV_CODE_RATE_LP, toDvbFecRate(dvbTTransponder->fecRateLow));
0978         dvb_fe_store_parm(dvbv5_parms, DTV_GUARD_INTERVAL, toDvbGuardInterval(dvbTTransponder->guardInterval));
0979         dvb_fe_store_parm(dvbv5_parms, DTV_TRANSMISSION_MODE, toDvbTransmissionMode(dvbTTransponder->transmissionMode));
0980         dvb_fe_store_parm(dvbv5_parms, DTV_HIERARCHY, toDvbHierarchy(dvbTTransponder->hierarchy));
0981         freqMHz = dvbTTransponder->frequency / 1000000.;
0982         break;
0983         }
0984     case DvbTransponderBase::DvbT2: {
0985         const DvbT2Transponder *dvbT2Transponder = transponder.as<DvbT2Transponder>();
0986 
0987         delsys = SYS_DVBT2;
0988         dvb_set_sys(dvbv5_parms, delsys);
0989 
0990         dvb_fe_store_parm(dvbv5_parms, DTV_FREQUENCY, dvbT2Transponder->frequency);
0991         dvb_fe_store_parm(dvbv5_parms, DTV_MODULATION, toDvbModulation(dvbT2Transponder->modulation));
0992         dvb_fe_store_parm(dvbv5_parms, DTV_BANDWIDTH_HZ, toDvbBandwidth(dvbT2Transponder->bandwidth));
0993         dvb_fe_store_parm(dvbv5_parms, DTV_INVERSION, INVERSION_AUTO);
0994         dvb_fe_store_parm(dvbv5_parms, DTV_CODE_RATE_HP, toDvbFecRate(dvbT2Transponder->fecRateHigh));
0995         dvb_fe_store_parm(dvbv5_parms, DTV_CODE_RATE_LP, toDvbFecRate(dvbT2Transponder->fecRateLow));
0996         dvb_fe_store_parm(dvbv5_parms, DTV_GUARD_INTERVAL, toDvbGuardInterval(dvbT2Transponder->guardInterval));
0997         dvb_fe_store_parm(dvbv5_parms, DTV_TRANSMISSION_MODE, toDvbTransmissionMode(dvbT2Transponder->transmissionMode));
0998         dvb_fe_store_parm(dvbv5_parms, DTV_HIERARCHY, toDvbHierarchy(dvbT2Transponder->hierarchy));
0999         dvb_fe_store_parm(dvbv5_parms, DTV_STREAM_ID, dvbT2Transponder->streamId);
1000         freqMHz = dvbT2Transponder->frequency / 1000000.;
1001         break;
1002         }
1003     case DvbTransponderBase::Atsc: {
1004         const AtscTransponder *atscTransponder = transponder.as<AtscTransponder>();
1005 
1006         switch (atscTransponder->modulation) {
1007         case AtscTransponder::Vsb8:
1008         case AtscTransponder::Vsb16:
1009             delsys = SYS_ATSC;
1010             break;
1011         default:
1012             delsys = SYS_DVBC_ANNEX_B;
1013         }
1014         dvb_set_sys(dvbv5_parms, delsys);
1015 
1016         dvb_fe_store_parm(dvbv5_parms, DTV_FREQUENCY, atscTransponder->frequency);
1017         dvb_fe_store_parm(dvbv5_parms, DTV_MODULATION, toDvbModulation(atscTransponder->modulation));
1018 /*      dvb_fe_store_parm(dvbv5_parms, DTV_INVERSION, INVERSION_AUTO); */
1019         freqMHz = atscTransponder->frequency / 1000000.;
1020         break;
1021         }
1022     case DvbTransponderBase::IsdbT: {
1023         const IsdbTTransponder *isdbTTransponder = transponder.as<IsdbTTransponder>();
1024         int i;
1025         uint32_t layers = 0;
1026 
1027         delsys = SYS_ISDBT;
1028         dvb_set_sys(dvbv5_parms, delsys);
1029 
1030         dvb_fe_store_parm(dvbv5_parms, DTV_FREQUENCY, isdbTTransponder->frequency);
1031         dvb_fe_store_parm(dvbv5_parms, DTV_BANDWIDTH_HZ, toDvbBandwidth(isdbTTransponder->bandwidth));
1032         dvb_fe_store_parm(dvbv5_parms, DTV_INVERSION, INVERSION_AUTO);
1033         dvb_fe_store_parm(dvbv5_parms, DTV_GUARD_INTERVAL, toDvbGuardInterval(isdbTTransponder->guardInterval));
1034         dvb_fe_store_parm(dvbv5_parms, DTV_TRANSMISSION_MODE, toDvbTransmissionMode(isdbTTransponder->transmissionMode));
1035 
1036         dvb_fe_store_parm(dvbv5_parms, DTV_ISDBT_PARTIAL_RECEPTION, toDvbPartialReception(isdbTTransponder->partialReception));
1037         dvb_fe_store_parm(dvbv5_parms, DTV_ISDBT_SOUND_BROADCASTING, toDvbSoundBroadcasting(isdbTTransponder->soundBroadcasting));
1038         dvb_fe_store_parm(dvbv5_parms, DTV_ISDBT_SB_SUBCHANNEL_ID, isdbTTransponder->subChannelId);
1039         dvb_fe_store_parm(dvbv5_parms, DTV_ISDBT_SB_SEGMENT_IDX, isdbTTransponder->sbSegmentIdx);
1040         dvb_fe_store_parm(dvbv5_parms, DTV_ISDBT_SB_SEGMENT_COUNT, isdbTTransponder->sbSegmentCount);
1041 
1042         for (i = 0; i < 3; ++i) {
1043             if (isdbTTransponder->layerEnabled[i])
1044                 layers |= 1 << i;
1045         }
1046         dvb_fe_store_parm(dvbv5_parms, DTV_ISDBT_LAYER_ENABLED, layers);
1047 
1048         dvb_fe_store_parm(dvbv5_parms, DTV_ISDBT_LAYERA_FEC, toDvbFecRate(isdbTTransponder->fecRate[0]));
1049         dvb_fe_store_parm(dvbv5_parms, DTV_ISDBT_LAYERA_MODULATION, toDvbModulation(isdbTTransponder->modulation[0]));
1050         dvb_fe_store_parm(dvbv5_parms, DTV_ISDBT_LAYERA_SEGMENT_COUNT, isdbTTransponder->segmentCount[0]);
1051         dvb_fe_store_parm(dvbv5_parms, DTV_ISDBT_LAYERA_TIME_INTERLEAVING, toDvbInterleaving(isdbTTransponder->interleaving[0]));
1052 
1053         dvb_fe_store_parm(dvbv5_parms, DTV_ISDBT_LAYERB_FEC, toDvbFecRate(isdbTTransponder->fecRate[1]));
1054         dvb_fe_store_parm(dvbv5_parms, DTV_ISDBT_LAYERB_MODULATION, toDvbModulation(isdbTTransponder->modulation[1]));
1055         dvb_fe_store_parm(dvbv5_parms, DTV_ISDBT_LAYERB_SEGMENT_COUNT, isdbTTransponder->segmentCount[1]);
1056         dvb_fe_store_parm(dvbv5_parms, DTV_ISDBT_LAYERA_TIME_INTERLEAVING, toDvbInterleaving(isdbTTransponder->interleaving[1]));
1057 
1058         dvb_fe_store_parm(dvbv5_parms, DTV_ISDBT_LAYERC_FEC, toDvbFecRate(isdbTTransponder->fecRate[2]));
1059         dvb_fe_store_parm(dvbv5_parms, DTV_ISDBT_LAYERC_MODULATION, toDvbModulation(isdbTTransponder->modulation[2]));
1060         dvb_fe_store_parm(dvbv5_parms, DTV_ISDBT_LAYERC_SEGMENT_COUNT, isdbTTransponder->segmentCount[2]);
1061         dvb_fe_store_parm(dvbv5_parms, DTV_ISDBT_LAYERA_TIME_INTERLEAVING, toDvbInterleaving(isdbTTransponder->interleaving[2]));
1062 
1063         freqMHz = isdbTTransponder->frequency / 1000000.;
1064 
1065         break;
1066         }
1067     case DvbTransponderBase::Invalid:
1068         qCWarning(logDev, "Invalid transmission type when tuning to %s",
1069               qPrintable(transponder.toString()));
1070         return false;
1071     default:
1072         qCWarning(logDev, "Unknown transmission type %d when tuning to %s",
1073               transponder.getTransmissionType(),
1074               qPrintable(transponder.toString()));
1075         return false;
1076     }
1077 
1078     if (dvb_fe_set_parms(dvbv5_parms) != 0) {
1079         qCWarning(logDev, "ioctl FE_SET_PROPERTY failed for frontend %s", qPrintable(frontendPath));
1080         return false;
1081     }
1082 
1083     startDvr();
1084     return true;
1085 }
1086 
1087 bool DvbLinuxDevice::getProps(DvbTransponder &transponder)
1088 {
1089     Q_ASSERT(dvbv5_parms);
1090     uint32_t value;
1091 
1092     /* Update properties with the detected stuff */
1093     if (!isTuned())
1094         return false;
1095 
1096     dvb_fe_get_parms(dvbv5_parms);
1097 
1098     switch (transponder.getTransmissionType()) {
1099     case DvbTransponderBase::DvbS: {
1100         DvbSTransponder *dvbSTransponder = transponder.as<DvbSTransponder>();
1101 
1102         dvb_fe_retrieve_parm(dvbv5_parms, DTV_FREQUENCY, &value);
1103         dvbSTransponder->frequency = (int)value;
1104         dvb_fe_retrieve_parm(dvbv5_parms, DTV_SYMBOL_RATE, &value);
1105         dvbSTransponder->symbolRate  = (int)value;
1106         dvb_fe_retrieve_parm(dvbv5_parms, DTV_INNER_FEC, &value);
1107         dvbSTransponder->fecRate = DvbtoFecRate(value);
1108         break;
1109         }
1110     case DvbTransponderBase::DvbS2: {
1111         DvbS2Transponder *dvbS2Transponder = transponder.as<DvbS2Transponder>();
1112 
1113         dvb_fe_retrieve_parm(dvbv5_parms, DTV_FREQUENCY, &value);
1114         dvbS2Transponder->frequency = (int)value;
1115         dvb_fe_retrieve_parm(dvbv5_parms, DTV_SYMBOL_RATE, &value);
1116         dvbS2Transponder->symbolRate = (int)value;
1117         dvb_fe_retrieve_parm(dvbv5_parms, DTV_INNER_FEC, &value);
1118         dvbS2Transponder->fecRate = DvbtoFecRate(value);
1119         dvb_fe_retrieve_parm(dvbv5_parms, DTV_MODULATION, &value);
1120         dvbS2Transponder->modulation = DvbS2toModulation(value);
1121         dvb_fe_retrieve_parm(dvbv5_parms, DTV_ROLLOFF, &value);
1122         dvbS2Transponder->rollOff = DvbS2toRollOff(value);
1123         break;
1124         }
1125     case DvbTransponderBase::DvbC: {
1126         DvbCTransponder *dvbCTransponder = transponder.as<DvbCTransponder>();
1127 
1128         dvb_fe_retrieve_parm(dvbv5_parms, DTV_FREQUENCY, &value);
1129         dvbCTransponder->frequency = (int)value;
1130         dvb_fe_retrieve_parm(dvbv5_parms, DTV_MODULATION, &value);
1131         dvbCTransponder->modulation = DvbCtoModulation(value);
1132         dvb_fe_retrieve_parm(dvbv5_parms, DTV_SYMBOL_RATE, &value);
1133         dvbCTransponder->symbolRate = (int)value;
1134         dvb_fe_retrieve_parm(dvbv5_parms, DTV_INNER_FEC, &value);
1135         dvbCTransponder->fecRate = DvbtoFecRate(value);
1136 
1137         break;
1138         }
1139     case DvbTransponderBase::DvbT: {
1140         DvbTTransponder *dvbTTransponder = transponder.as<DvbTTransponder>();
1141 
1142         dvb_fe_retrieve_parm(dvbv5_parms, DTV_FREQUENCY, &value);
1143         dvbTTransponder->frequency = (int)value;
1144         dvb_fe_retrieve_parm(dvbv5_parms, DTV_MODULATION, &value);
1145         dvbTTransponder->modulation = DvbTtoModulation(value);
1146         dvb_fe_retrieve_parm(dvbv5_parms, DTV_BANDWIDTH_HZ, &value);
1147         dvbTTransponder->bandwidth = DvbTtoBandwidth(value);
1148         dvb_fe_retrieve_parm(dvbv5_parms, DTV_CODE_RATE_HP, &value);
1149         dvbTTransponder->fecRateHigh = DvbtoFecRate(value);
1150         dvb_fe_retrieve_parm(dvbv5_parms, DTV_CODE_RATE_LP, &value);
1151         dvbTTransponder->fecRateLow = DvbtoFecRate(value);
1152         dvb_fe_retrieve_parm(dvbv5_parms, DTV_GUARD_INTERVAL, &value);
1153         dvbTTransponder->guardInterval = DvbTtoGuardInterval(value);
1154         dvb_fe_retrieve_parm(dvbv5_parms, DTV_TRANSMISSION_MODE, &value);
1155         dvbTTransponder->transmissionMode = DvbTtoTransmissionMode(value);
1156         dvb_fe_retrieve_parm(dvbv5_parms, DTV_HIERARCHY, &value);
1157         dvbTTransponder->hierarchy = DvbTtoHierarchy(value);
1158         break;
1159         }
1160     case DvbTransponderBase::DvbT2: {
1161         DvbT2Transponder *dvbT2Transponder = transponder.as<DvbT2Transponder>();
1162 
1163         dvb_fe_retrieve_parm(dvbv5_parms, DTV_FREQUENCY, &value);
1164         dvbT2Transponder->frequency = (int)value;
1165         dvb_fe_retrieve_parm(dvbv5_parms, DTV_MODULATION, &value);
1166         dvbT2Transponder->modulation = DvbT2toModulation(value);
1167         dvb_fe_retrieve_parm(dvbv5_parms, DTV_BANDWIDTH_HZ, &value);
1168         dvbT2Transponder->bandwidth = DvbT2toBandwidth(value);
1169         dvb_fe_retrieve_parm(dvbv5_parms, DTV_CODE_RATE_HP, &value);
1170         dvbT2Transponder->fecRateHigh = DvbtoFecRate(value);
1171         dvb_fe_retrieve_parm(dvbv5_parms, DTV_CODE_RATE_LP, &value);
1172         dvbT2Transponder->fecRateLow = DvbtoFecRate(value);
1173         dvb_fe_retrieve_parm(dvbv5_parms, DTV_GUARD_INTERVAL, &value);
1174         dvbT2Transponder->guardInterval = DvbT2toGuardInterval(value);
1175         dvb_fe_retrieve_parm(dvbv5_parms, DTV_TRANSMISSION_MODE, &value);
1176         dvbT2Transponder->transmissionMode = DvbT2toTransmissionMode(value);
1177         dvb_fe_retrieve_parm(dvbv5_parms, DTV_HIERARCHY, &value);
1178         dvbT2Transponder->hierarchy = DvbT2toHierarchy(value);
1179         dvb_fe_retrieve_parm(dvbv5_parms, DTV_STREAM_ID, &value);
1180         dvbT2Transponder->streamId = (int)value;
1181         break;
1182         }
1183     case DvbTransponderBase::Atsc: {
1184         AtscTransponder *atscTransponder = transponder.as<AtscTransponder>();
1185 
1186         dvb_fe_retrieve_parm(dvbv5_parms, DTV_FREQUENCY, &value);
1187         atscTransponder->frequency = (int)value;
1188         dvb_fe_retrieve_parm(dvbv5_parms, DTV_MODULATION, &value);
1189         atscTransponder->modulation = AtsctoModulation(value);
1190         break;
1191         }
1192     case DvbTransponderBase::IsdbT: {
1193         IsdbTTransponder *isdbTTransponder = transponder.as<IsdbTTransponder>();
1194         int i;
1195         uint32_t layers = 0;
1196 
1197         dvb_fe_retrieve_parm(dvbv5_parms, DTV_FREQUENCY, &value);
1198         isdbTTransponder->frequency = (int)value;
1199         dvb_fe_retrieve_parm(dvbv5_parms, DTV_BANDWIDTH_HZ, &value);
1200         isdbTTransponder->bandwidth = IsdbTtoBandwidth(value);
1201         dvb_fe_retrieve_parm(dvbv5_parms, DTV_GUARD_INTERVAL, &value);
1202         isdbTTransponder->guardInterval = IsdbTtoGuardInterval(value);
1203         dvb_fe_retrieve_parm(dvbv5_parms, DTV_TRANSMISSION_MODE, &value);
1204         isdbTTransponder->transmissionMode = IsdbTtoTransmissionMode(value);
1205 
1206         dvb_fe_retrieve_parm(dvbv5_parms, DTV_ISDBT_PARTIAL_RECEPTION, &value);
1207         isdbTTransponder->partialReception = IsdbTtoPartialReception(value);
1208         dvb_fe_retrieve_parm(dvbv5_parms, DTV_ISDBT_SOUND_BROADCASTING, &value);
1209         isdbTTransponder->soundBroadcasting = IsdbTtoSoundBroadcasting(value);
1210         dvb_fe_retrieve_parm(dvbv5_parms, DTV_ISDBT_SB_SUBCHANNEL_ID, &value);
1211         isdbTTransponder->subChannelId = (int)value;
1212         dvb_fe_retrieve_parm(dvbv5_parms, DTV_ISDBT_SB_SEGMENT_IDX, &value);
1213         isdbTTransponder->sbSegmentIdx = (int)value;
1214         dvb_fe_retrieve_parm(dvbv5_parms, DTV_ISDBT_SB_SEGMENT_COUNT, &value);
1215         isdbTTransponder->sbSegmentCount = (int)value;
1216 
1217         dvb_fe_retrieve_parm(dvbv5_parms, DTV_ISDBT_LAYER_ENABLED, &value);
1218         layers = (int)value;
1219         for (i = 0; i < 3; ++i) {
1220             if (isdbTTransponder->layerEnabled[i])
1221                 layers |= 1 << i;
1222         }
1223 
1224         dvb_fe_retrieve_parm(dvbv5_parms, DTV_ISDBT_LAYERA_FEC, &value);
1225         isdbTTransponder->fecRate[0] = DvbtoFecRate(value);
1226         dvb_fe_retrieve_parm(dvbv5_parms, DTV_ISDBT_LAYERA_MODULATION, &value);
1227         isdbTTransponder->modulation[0] = IsdbTtoModulation(value);
1228         dvb_fe_retrieve_parm(dvbv5_parms, DTV_ISDBT_LAYERA_SEGMENT_COUNT, &value);
1229         isdbTTransponder->segmentCount[0] = (int)value;
1230         dvb_fe_retrieve_parm(dvbv5_parms, DTV_ISDBT_LAYERA_TIME_INTERLEAVING, &value);
1231         isdbTTransponder->interleaving[0] = IsdbTtoInterleaving(value);
1232 
1233         dvb_fe_retrieve_parm(dvbv5_parms, DTV_ISDBT_LAYERB_FEC, &value);
1234         isdbTTransponder->fecRate[1] = DvbtoFecRate(value);
1235         dvb_fe_retrieve_parm(dvbv5_parms, DTV_ISDBT_LAYERB_MODULATION, &value);
1236         isdbTTransponder->modulation[1] = IsdbTtoModulation(value);
1237         dvb_fe_retrieve_parm(dvbv5_parms, DTV_ISDBT_LAYERB_SEGMENT_COUNT, &value);
1238         isdbTTransponder->segmentCount[1] = (int)value;
1239         dvb_fe_retrieve_parm(dvbv5_parms, DTV_ISDBT_LAYERB_TIME_INTERLEAVING, &value);
1240         isdbTTransponder->interleaving[1] = IsdbTtoInterleaving(value);
1241 
1242         dvb_fe_retrieve_parm(dvbv5_parms, DTV_ISDBT_LAYERC_FEC, &value);
1243         isdbTTransponder->fecRate[2] = DvbtoFecRate(value);
1244         dvb_fe_retrieve_parm(dvbv5_parms, DTV_ISDBT_LAYERC_MODULATION, &value);
1245         isdbTTransponder->modulation[2] = IsdbTtoModulation(value);
1246         dvb_fe_retrieve_parm(dvbv5_parms, DTV_ISDBT_LAYERC_SEGMENT_COUNT, &value);
1247         isdbTTransponder->segmentCount[2] = (int)value;
1248         dvb_fe_retrieve_parm(dvbv5_parms, DTV_ISDBT_LAYERC_TIME_INTERLEAVING, &value);
1249         isdbTTransponder->interleaving[2] = IsdbTtoInterleaving(value);
1250 
1251         break;
1252         }
1253     case DvbTransponderBase::Invalid:
1254         dvb_fe_retrieve_parm(dvbv5_parms, DTV_FREQUENCY, &value);
1255         qCWarning(logDev, "Invalid transmission type when get props from %.2f MHz",
1256               value / 1000000.);
1257         return false;
1258     default:
1259         dvb_fe_retrieve_parm(dvbv5_parms, DTV_FREQUENCY, &value);
1260         qCWarning(logDev, "Unknown transmission type %d when get props from %.2f MHz",
1261               transponder.getTransmissionType(),
1262               value / 1000000.);
1263         return false;
1264     }
1265     return true;
1266 }
1267 
1268 float DvbLinuxDevice::getFrqMHz()
1269 {
1270     return freqMHz;
1271 }
1272 
1273 void DvbLinuxDevice::enableDvbDump()
1274 {
1275     verbose = 1;
1276 
1277     if (dvbv5_parms)
1278         dvbv5_parms->verbose = 1;
1279 }
1280 
1281 bool DvbLinuxDevice::isTuned()
1282 {
1283     Q_ASSERT(dvbv5_parms);
1284     uint32_t status = 0;
1285 
1286     if (dvb_fe_get_stats(dvbv5_parms) != 0) {
1287         qCWarning(logDev, "ioctl FE_READ_STATUS failed for frontend %s", qPrintable(frontendPath));
1288         return false;
1289     }
1290 
1291     if (dvb_fe_retrieve_stats(dvbv5_parms, DTV_STATUS, &status) != 0) {
1292         qCWarning(logDev, "ioctl FE_READ_STATUS failed for frontend %s", qPrintable(frontendPath));
1293         return false;
1294     }
1295 
1296     return ((status & FE_HAS_LOCK) != 0);
1297 }
1298 
1299 float DvbLinuxDevice::getSignal(Scale &scale)
1300 {
1301     Q_ASSERT(dvbv5_parms);
1302     struct dtv_stats *stat;
1303     float signal;
1304 
1305     scale = DvbBackendDevice::NotSupported;
1306 
1307     if (dvb_fe_get_stats(dvbv5_parms) != 0) {
1308         qCWarning(logDev, "ioctl FE_READ_STATUS failed for frontend %s", qPrintable(frontendPath));
1309         return false;
1310     }
1311 
1312     stat = dvb_fe_retrieve_stats_layer(dvbv5_parms, DTV_STAT_SIGNAL_STRENGTH, 0);
1313     if (!stat)
1314         return -1;
1315 
1316     switch (stat->scale) {
1317     case FE_SCALE_RELATIVE:
1318         signal = (100. * stat->uvalue) / 65535;
1319 
1320         scale = DvbBackendDevice::Percentage;
1321 
1322         // Assert that signal will be within the expected range
1323         if (signal > 100.)
1324             signal = 100.;
1325         else if (signal < 0)
1326             signal = 0;
1327 
1328         break;
1329     case FE_SCALE_DECIBEL:
1330         // Convert to dBuV @ 75 ohms, to be positive and typically smaller than 100
1331         signal = (108800. + stat->svalue) / 1000;
1332 
1333         scale = DvbBackendDevice::dBuV;
1334 
1335         break;
1336     default:
1337         return -1;
1338     }
1339 
1340     return signal;
1341 }
1342 
1343 float DvbLinuxDevice::getSnr(Scale &scale)
1344 {
1345     Q_ASSERT(dvbv5_parms);
1346     struct dtv_stats *stat;
1347     float cnr;
1348 
1349     scale = DvbBackendDevice::NotSupported;
1350     if (dvb_fe_get_stats(dvbv5_parms) != 0) {
1351         qCWarning(logDev, "ioctl FE_READ_STATUS failed for frontend %s", qPrintable(frontendPath));
1352         return false;
1353     }
1354 
1355     stat = dvb_fe_retrieve_stats_layer(dvbv5_parms, DTV_STAT_CNR, 0);
1356     if (!stat)
1357         return -1;
1358 
1359     switch (stat->scale) {
1360     case FE_SCALE_RELATIVE:
1361         cnr = (100. * stat->uvalue) / 65535;
1362 
1363         // Assert that CNR will be within the expected range
1364         if (cnr > 100.)
1365             cnr = 100.;
1366         else if (cnr < 0.)
1367             cnr = 0.;
1368 
1369         scale = DvbBackendDevice::Percentage;
1370 
1371         break;
1372     case FE_SCALE_DECIBEL:
1373         cnr = (stat->svalue / 1000.);
1374 
1375         scale = DvbBackendDevice::Decibel;
1376 
1377         break;
1378     default:
1379         return -1;
1380     }
1381 
1382     return cnr;
1383 }
1384 
1385 bool DvbLinuxDevice::addPidFilter(int pid)
1386 {
1387     if (dmxFds.contains(pid)) {
1388         qCWarning(logDev, "PID filter already set up for pid %d", pid);
1389         return false;
1390     }
1391 
1392     int dmxFd = open(QFile::encodeName(demuxPath).constData(), O_RDONLY | O_NONBLOCK | O_CLOEXEC);
1393 
1394     if (dmxFd < 0) {
1395         qCWarning(logDev, "Cannot open demux %s", qPrintable(demuxPath));
1396         return false;
1397     }
1398 
1399     dmx_pes_filter_params pes_filter;
1400     memset(&pes_filter, 0, sizeof(pes_filter));
1401     pes_filter.pid = ushort(pid);
1402     pes_filter.input = DMX_IN_FRONTEND;
1403     pes_filter.output = DMX_OUT_TS_TAP;
1404     pes_filter.pes_type = DMX_PES_OTHER;
1405     pes_filter.flags = DMX_IMMEDIATE_START;
1406 
1407     if (ioctl(dmxFd, DMX_SET_PES_FILTER, &pes_filter) != 0) {
1408         qCWarning(logDev, "Cannot set up PID filter for demux %s", qPrintable(demuxPath));
1409         close(dmxFd);
1410         return false;
1411     }
1412 
1413     dmxFds.insert(pid, dmxFd);
1414     return true;
1415 }
1416 
1417 void DvbLinuxDevice::removePidFilter(int pid)
1418 {
1419     if (!dmxFds.contains(pid)) {
1420         qCWarning(logDev, "No PID filter set up for PID %i", pid);
1421         return;
1422     }
1423 
1424     close(dmxFds.take(pid));
1425 }
1426 
1427 void DvbLinuxDevice::startDescrambling(const QByteArray &pmtSectionData)
1428 {
1429     cam.startDescrambling(pmtSectionData);
1430 }
1431 
1432 void DvbLinuxDevice::stopDescrambling(int serviceId)
1433 {
1434     cam.stopDescrambling(serviceId);
1435 }
1436 
1437 void DvbLinuxDevice::release()
1438 {
1439     stopDvr();
1440 
1441     if (dvrBuffer.data != NULL) {
1442         dvrBuffer.dataSize = 0;
1443         frontend->writeBuffer(dvrBuffer);
1444         dvrBuffer.data = NULL;
1445     }
1446 
1447     if (dvrPipe[0] >= 0) {
1448         close(dvrPipe[0]);
1449         dvrPipe[0] = -1;
1450     }
1451 
1452     if (dvrPipe[1] >= 0) {
1453         close(dvrPipe[1]);
1454         dvrPipe[1] = -1;
1455     }
1456 
1457     if (dvrFd >= 0) {
1458         close(dvrFd);
1459         dvrFd = -1;
1460     }
1461 
1462     foreach (int dmxFd, dmxFds) {
1463         close(dmxFd);
1464     }
1465 
1466     dmxFds.clear();
1467 
1468     if (dvbv5_parms) {
1469         dvb_fe_close(dvbv5_parms);
1470         dvbv5_parms = NULL;
1471     }
1472 }
1473 
1474 void DvbLinuxDevice::startDvr()
1475 {
1476     Q_ASSERT((dvrFd >= 0) && !isRunning());
1477 
1478     if ((dvrPipe[0] < 0) || (dvrPipe[1] < 0)) {
1479         if (pipe(dvrPipe) != 0) {
1480             dvrPipe[0] = -1;
1481             dvrPipe[1] = -1;
1482         }
1483 
1484         if ((dvrPipe[0] < 0) || (dvrPipe[1] < 0)) {
1485             qCCritical(logDev, "Cannot create pipe");
1486             return;
1487         }
1488     }
1489 
1490     if (dvrBuffer.data == NULL) {
1491         dvrBuffer = frontend->getBuffer();
1492     }
1493 
1494     while (true) {
1495         int bufferSize = dvrBuffer.bufferSize;
1496         int dataSize = int(read(dvrFd, dvrBuffer.data, bufferSize));
1497 
1498         if (dataSize < 0) {
1499             if (IS_EAGAIN(errno)) {
1500                 break;
1501             }
1502 
1503             if (errno == EINTR) {
1504                 continue;
1505             }
1506 
1507             dataSize = int(read(dvrFd, dvrBuffer.data, bufferSize));
1508 
1509             if (dataSize < 0) {
1510                 if (IS_EAGAIN(errno)) {
1511                     break;
1512                 }
1513 
1514                 if (errno == EINTR) {
1515                     continue;
1516                 }
1517 
1518                 qCWarning(logDev, "Cannot read from dvr %s: error: %d", qPrintable(dvrPath), errno);
1519                 return;
1520             }
1521         }
1522 
1523         if (dataSize != bufferSize) {
1524             break;
1525         }
1526     }
1527 
1528     start();
1529 }
1530 
1531 void DvbLinuxDevice::stopDvr()
1532 {
1533     if (isRunning()) {
1534         Q_ASSERT((dvrPipe[0] >= 0) && (dvrPipe[1] >= 0));
1535 
1536         if (write(dvrPipe[1], " ", 1) != 1) {
1537             qCWarning(logDev, "Cannot write to pipe");
1538         }
1539 
1540         wait();
1541         char data;
1542 
1543         if (read(dvrPipe[0], &data, 1) != 1) {
1544             qCWarning(logDev, "Cannot read from pipe");
1545         }
1546     }
1547 }
1548 
1549 void DvbLinuxDevice::run()
1550 {
1551     Q_ASSERT((dvrFd >= 0) && (dvrPipe[0] >= 0) && (dvrBuffer.data != NULL));
1552     pollfd pollFds[2];
1553     memset(&pollFds, 0, sizeof(pollFds));
1554     pollFds[0].fd = dvrPipe[0];
1555     pollFds[0].events = POLLIN;
1556     pollFds[1].fd = dvrFd;
1557     pollFds[1].events = POLLIN;
1558 
1559     while (true) {
1560         if (poll(pollFds, 2, -1) < 0) {
1561             if (errno == EINTR) {
1562                 continue;
1563             }
1564 
1565             qCWarning(logDev, "Poll failed with error: %d", errno);
1566             return;
1567         }
1568 
1569         if ((pollFds[0].revents & POLLIN) != 0) {
1570             return;
1571         }
1572 
1573         while (true) {
1574             int bufferSize = dvrBuffer.bufferSize;
1575             int dataSize = int(read(dvrFd, dvrBuffer.data, bufferSize));
1576 
1577             if (dataSize < 0) {
1578                 if (IS_EAGAIN(errno)) {
1579                     break;
1580                 }
1581 
1582                 if (errno == EINTR) {
1583                     continue;
1584                 }
1585 
1586                 qCWarning(logDev, "Cannot read from dvr %s: error %d", qPrintable(dvrPath), errno);
1587                 dataSize = int(read(dvrFd, dvrBuffer.data, bufferSize));
1588 
1589                 if (dataSize < 0) {
1590                     if (IS_EAGAIN(errno)) {
1591                         break;
1592                     }
1593 
1594                     if (errno == EINTR) {
1595                         continue;
1596                     }
1597 
1598                     qCWarning(logDev, "Cannot read from dvr %s: error %d", qPrintable(dvrPath), errno);
1599                     return;
1600                 }
1601             }
1602 
1603             if (dataSize > 0) {
1604                 dvrBuffer.dataSize = dataSize;
1605                 frontend->writeBuffer(dvrBuffer);
1606                 dvrBuffer = frontend->getBuffer();
1607             }
1608 
1609             if (dataSize != bufferSize) {
1610                 break;
1611             }
1612         }
1613 
1614         msleep(10);
1615     }
1616 }
1617 
1618 DvbLinuxDeviceManager::DvbLinuxDeviceManager(QObject *parent) : QObject(parent)
1619 {
1620     QObject *notifier = Solid::DeviceNotifier::instance();
1621     connect(notifier, SIGNAL(deviceAdded(QString)), this, SLOT(componentAdded(QString)));
1622     connect(notifier, SIGNAL(deviceRemoved(QString)), this, SLOT(componentRemoved(QString)));
1623 }
1624 
1625 DvbLinuxDeviceManager::~DvbLinuxDeviceManager()
1626 {
1627 }
1628 
1629 void DvbLinuxDeviceManager::doColdPlug()
1630 {
1631     foreach (const Solid::Device &device, Solid::Device::allDevices()) {
1632         componentAdded(device.udi());
1633     }
1634 }
1635 
1636 void DvbLinuxDeviceManager::componentAdded(const QString &udi)
1637 {
1638     QRegularExpressionMatch match;
1639     bool ok;
1640 
1641     QRegularExpression rejex = QRegularExpression("/dvb/dvb(\\d+).(\\w+)(\\d+)");
1642     if (!udi.contains(rejex, &match))
1643         return;
1644 
1645     int adapter = match.captured(1).toShort(&ok, 10);
1646     if (!ok)
1647         return;
1648     QString type = match.captured(2);
1649     int index = match.captured(3).toShort(&ok, 10);
1650     if (!ok)
1651         return;
1652 
1653     QString devicePath = QString(QLatin1String("/dev/dvb/adapter%1/%2%3")).arg(adapter).arg(type).arg(index);
1654 
1655     if ((adapter < 0) || (adapter > 0x7fff) || (index < 0) || (index > 0x7fff)) {
1656         qCWarning(logDev, "Cannot determine adapter or index for device %s", qPrintable(udi));
1657         return;
1658     }
1659 
1660     if (devicePath.isEmpty()) {
1661         qCWarning(logDev, "Cannot determine path for device %s", qPrintable(udi));
1662         return;
1663     }
1664 
1665     qCDebug(logDev, "New device detected: %s", qPrintable(udi));
1666 
1667     int deviceIndex = ((adapter << 16) | index);
1668     DvbLinuxDevice *device = devices.value(deviceIndex);
1669 
1670     if (device == NULL) {
1671         device = new DvbLinuxDevice(this);
1672         devices.insert(deviceIndex, device);
1673     }
1674 
1675     bool addDevice = false;
1676 
1677     if (!type.compare("ca")) {
1678         if (device->caPath.isEmpty()) {
1679             device->caPath = devicePath;
1680             device->caUdi = udi;
1681             udis.insert(udi, device);
1682 
1683             if (device->isReady())
1684                 device->startCa();
1685         }
1686     } else if (!type.compare("demux")) {
1687         device->numDemux++;
1688         if (device->demuxPath.isEmpty()) {
1689             device->demuxPath = devicePath;
1690             device->demuxUdi = udi;
1691             udis.insert(udi, device);
1692             addDevice = true;
1693         }
1694     } else if (!type.compare("dvr")) {
1695         if (device->dvrPath.isEmpty()) {
1696             device->dvrPath = devicePath;
1697             device->dvrUdi = udi;
1698             udis.insert(udi, device);
1699             addDevice = true;
1700         }
1701     } else if (!type.compare("frontend")) {
1702         if (device->frontendPath.isEmpty()) {
1703             device->frontendPath = devicePath;
1704             device->frontendUdi = udi;
1705             udis.insert(udi, device);
1706             addDevice = true;
1707         }
1708     }
1709 
1710     // Special case: one demux, multiple frontends
1711     if (index && device->numDemux < 2) {
1712         int parentDeviceIndex = (adapter << 16);
1713         DvbLinuxDevice *parentDevice = devices.value(parentDeviceIndex);
1714 
1715         if (device->demuxPath.isEmpty() && !parentDevice->demuxPath.isEmpty())
1716             device->demuxPath = parentDevice->demuxPath;
1717         if (device->dvrPath.isEmpty() && !parentDevice->dvrPath.isEmpty())
1718             device->dvrPath = parentDevice->dvrPath;
1719         if (device->caPath.isEmpty() && !parentDevice->caPath.isEmpty())
1720             device->caPath = parentDevice->caPath;
1721     }
1722 
1723     if (addDevice && !device->demuxPath.isEmpty() && !device->dvrPath.isEmpty() &&
1724         !device->frontendPath.isEmpty()) {
1725         QString path = QString(QLatin1String("/sys/class/dvb/dvb%1.frontend%2/")).arg(adapter).arg(index);
1726         QString deviceId;
1727         device->adapter = adapter;
1728         device->index = index;
1729         device->dvbv5_parms = NULL;
1730         if (QFile::exists(path + QLatin1String("device/vendor"))) {
1731             // PCI device
1732             int vendor = readSysAttr(path + QLatin1String("device/vendor"));
1733             int pciDevice = readSysAttr(path + QLatin1String("device/device"));
1734             int subsystemVendor = readSysAttr(path + QLatin1String("device/subsystem_vendor"));
1735             int subsystemDevice = readSysAttr(path + QLatin1String("device/subsystem_device"));
1736 
1737             if ((vendor >= 0) && (pciDevice >= 0) && (subsystemVendor >= 0) && (subsystemDevice >= 0)) {
1738                 deviceId = QLatin1Char('P');
1739                 deviceId += QString(QLatin1String("%1")).arg(vendor, 4, 16, QLatin1Char('0'));
1740                 deviceId += QString(QLatin1String("%1")).arg(pciDevice, 4, 16, QLatin1Char('0'));
1741                 deviceId += QString(QLatin1String("%1")).arg(subsystemVendor, 4, 16, QLatin1Char('0'));
1742                 deviceId += QString(QLatin1String("%1")).arg(subsystemDevice, 4, 16, QLatin1Char('0'));
1743             }
1744         } else if (QFile::exists(path + QLatin1String("device/idVendor"))) {
1745             // USB device
1746             int vendor = readSysAttr(path + QLatin1String("device/idVendor"));
1747             int product = readSysAttr(path + QLatin1String("device/idProduct"));
1748 
1749             if ((vendor >= 0) && (product >= 0)) {
1750                 deviceId = QLatin1Char('U');
1751                 deviceId += QString(QLatin1String("%1")).arg(vendor, 4, 16, QLatin1Char('0'));
1752                 deviceId += QString(QLatin1String("%1")).arg(product, 4, 16, QLatin1Char('0'));
1753             }
1754         }
1755 
1756         device->startDevice(deviceId);
1757 
1758         if (device->isReady()) {
1759             emit deviceAdded(device);
1760         }
1761     }
1762 }
1763 
1764 void DvbLinuxDeviceManager::componentRemoved(QString node, int adapter, int index) {
1765     int deviceIndex = (adapter << 16) | index;
1766     char adapterstring[10];
1767     DvbLinuxDevice *device = devices.value(deviceIndex, NULL);
1768     if (device == NULL) {
1769         return;
1770     }
1771     sprintf(adapterstring, "adapter%d", adapter);
1772 
1773     QRegularExpressionMatch match;
1774     QRegularExpression rejex = QRegularExpression("(frontend|dvr|demux|ca)\\d+");
1775     if (node.contains(rejex))
1776         return;
1777     QString type = match.captured(1);
1778 
1779     if (type == "frontend") {
1780         device->frontendPath.clear();
1781     } else if (type == "dvr") {
1782         device->dvrPath.clear();
1783     } else if (type == "demux") {
1784         device->demuxPath.clear();
1785     } else if (type == "ca") {
1786         device->caPath.clear();
1787     } else {
1788         return;
1789     }
1790 
1791     if (device->frontendPath.isEmpty() && device->dvrPath.isEmpty() &&
1792             device->demuxPath.isEmpty() && device->isReady()) {
1793         emit deviceRemoved(device);
1794         device->stopDevice();
1795     }
1796 }
1797 
1798 void DvbLinuxDeviceManager::componentRemoved(const QString &udi)
1799 {
1800     QRegularExpression rejex = QRegularExpression("/dvb/dvb(\\d+).(\\w+)(\\d+)");
1801     if (!udi.contains(rejex))
1802         return;
1803 
1804     DvbLinuxDevice *device = udis.take(udi);
1805 
1806     // The device is not mapped. Just return
1807     if (!device)
1808         return;
1809 
1810     bool removeDevice = false;
1811 
1812     if (device->isReady())
1813         qCInfo(logDev, "Digital TV device removed %s: %s", qPrintable(device->getDeviceId()), qPrintable(device->getFrontendName()));
1814 
1815     if (udi == device->caUdi) {
1816         device->caPath.clear();
1817         device->caUdi.clear();
1818 
1819         if (device->isReady()) {
1820             device->stopCa();
1821         }
1822     } else if (udi == device->demuxUdi) {
1823         device->demuxPath.clear();
1824         device->demuxUdi.clear();
1825         removeDevice = true;
1826     } else if (udi == device->dvrUdi) {
1827         device->dvrPath.clear();
1828         device->dvrUdi.clear();
1829         removeDevice = true;
1830     } else if (udi == device->frontendUdi) {
1831         device->frontendPath.clear();
1832         device->frontendUdi.clear();
1833         removeDevice = true;
1834     }
1835 
1836     if (removeDevice && device->isReady()) {
1837         emit deviceRemoved(device);
1838         device->stopDevice();
1839     }
1840 }
1841 
1842 int DvbLinuxDeviceManager::readSysAttr(const QString &path)
1843 {
1844     QFile file(path);
1845 
1846     if (!file.open(QIODevice::ReadOnly)) {
1847         return -1;
1848     }
1849 
1850     QByteArray data = file.read(8);
1851 
1852     if ((data.size() == 0) || (data.size() == 8)) {
1853         return -1;
1854     }
1855 
1856     bool ok = false;
1857     int value = data.simplified().toInt(&ok, 0);
1858 
1859     if (!ok || (value < 0) || (value > 0xffff)) {
1860         return -1;
1861     }
1862 
1863     return value;
1864 }
1865 
1866 #include "moc_dvbdevice_linux.cpp"