MythTV  0.28pre
cardutil.cpp
Go to the documentation of this file.
1 // Standard UNIX C headers
2 #include <fcntl.h>
3 #include <unistd.h>
4 
5 #include <algorithm>
6 
7 #if defined(USING_V4L2) || defined(USING_DVB)
8 #include <sys/ioctl.h>
9 #endif
10 
11 // Qt headers
12 #include <QMap>
13 #include <QDir>
14 
15 // MythTV headers
16 #include "mythconfig.h"
17 #include "cardutil.h"
18 #include "videosource.h"
19 #include "dvbchannel.h"
20 #include "diseqcsettings.h"
21 #include "sourceutil.h"
22 #include "mythdb.h"
23 #include "mythlogging.h"
24 #include "inputinfo.h"
25 
26 #ifdef USING_DVB
27 #include "dvbtypes.h"
28 #endif
29 
30 #ifdef USING_V4L1
31 #include <linux/videodev.h>
32 #endif
33 
34 #ifdef USING_V4L2
35 #include "v4l2util.h"
36 #endif
37 
38 #ifdef USING_HDHOMERUN
39 #include "hdhomerun.h"
40 #endif
41 
42 #ifdef USING_VBOX
43 #include "vboxutils.h"
44 #endif
45 
46 #ifdef USING_ASI
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <dveo/asi.h>
50 #include <dveo/master.h>
51 #endif
52 
53 #define LOC QString("CardUtil: ")
54 
56 {
57  QString inputTypes = "";
58 
59 #ifdef USING_DVB
60  inputTypes += "'DVB'";
61 #endif // USING_DVB
62 
63 #ifdef USING_V4L2
64  if (!inputTypes.isEmpty())
65  inputTypes += ",";
66  inputTypes += "'V4L'";
67 # ifdef USING_IVTV
68  inputTypes += ",'MPEG'";
69 # endif // USING_IVTV
70 #endif // USING_V4L2
71 
72 #ifdef USING_IPTV
73  if (!inputTypes.isEmpty())
74  inputTypes += ",";
75  inputTypes += "'FREEBOX'";
76 #endif // USING_IPTV
77 
78 #ifdef USING_VBOX
79  if (!inputTypes.isEmpty())
80  inputTypes += ",";
81  inputTypes += "'VBOX'";
82 #endif // USING_VBOX
83 
84 #ifdef USING_HDHOMERUN
85  if (!inputTypes.isEmpty())
86  inputTypes += ",";
87  inputTypes += "'HDHOMERUN'";
88 #endif // USING_HDHOMERUN
89 
90 #ifdef USING_ASI
91  if (!inputTypes.isEmpty())
92  inputTypes += ",";
93  inputTypes += "'ASI'";
94 #endif
95 
96 #ifdef USING_CETON
97  if (!inputTypes.isEmpty())
98  inputTypes += ",";
99  inputTypes += "'CETON'";
100 #endif // USING_CETON
101 
102 #if !defined( USING_MINGW ) && !defined( _MSC_VER )
103  if (!inputTypes.isEmpty())
104  inputTypes += ",";
105  inputTypes += "'EXTERNAL'";
106 #endif
107 
108  if (inputTypes.isEmpty())
109  inputTypes = "'DUMMY'";
110 
111  return QString("(%1)").arg(inputTypes);
112 }
113 
115  const QString &inputType)
116 {
117  if (inputType == "HDHOMERUN")
118  {
119 #ifdef USING_HDHOMERUN
120  hdhomerun_device_t *hdhr;
121  hdhomerun_tuner_status_t status;
122  QString device = GetVideoDevice(inputid);
123  hdhr = hdhomerun_device_create_from_str(device.toLatin1(), NULL);
124  if (!hdhr)
125  return false;
126 
127  int oob = -1;
128  oob = hdhomerun_device_get_oob_status(hdhr, NULL, &status);
129 
130  // if no OOB tuner, oob will be < 1. If no CC present, OOB
131  // status will be "none."
132  if (oob > 0 && (strncmp(status.channel, "none", 4) != 0))
133  {
134  LOG(VB_GENERAL, LOG_INFO, "Cardutil: HDHomeRun Cablecard Present.");
135  hdhomerun_device_destroy(hdhr);
136  return true;
137  }
138 
139  hdhomerun_device_destroy(hdhr);
140 
141 #endif
142  return false;
143  }
144  else if (inputType == "CETON")
145  {
146 #ifdef USING_CETON
147  // TODO FIXME implement detection of Cablecard presence
148  LOG(VB_GENERAL, LOG_INFO, "Cardutil: TODO Ceton Is Cablecard Present?");
149  return true;
150 #else
151  return false;
152 #endif
153  }
154  else
155  return false;
156 }
157 
158 bool CardUtil::HasTuner(const QString &rawtype, const QString & device)
159 {
160  if (rawtype == "DVB" || rawtype == "HDHOMERUN" ||
161  rawtype == "FREEBOX" || rawtype == "CETON")
162  return true;
163 
164 #ifdef USING_V4L2
165  if (rawtype == "V4L2ENC")
166  {
167  V4L2util v4l2(device);
168  return !v4l2 ? false : v4l2.HasTuner();
169  }
170 #endif
171 
172  if (rawtype == "EXTERNAL")
173  {
174  // TODO: query EXTERNAL for capability
175  return true;
176  }
177 
178  return false;
179 }
180 
181 bool CardUtil::IsTunerShared(uint inputidA, uint inputidB)
182 {
183  LOG(VB_GENERAL, LOG_DEBUG, QString("IsTunerShared(%1,%2)")
184  .arg(inputidA).arg(inputidB));
185 
186  MSqlQuery query(MSqlQuery::InitCon());
187  query.prepare("SELECT videodevice, hostname, cardtype "
188  "FROM capturecard "
189  "WHERE ( (cardid = :INPUTID_A) OR "
190  " (cardid = :INPUTID_B) )");
191  query.bindValue(":INPUTID_A", inputidA);
192  query.bindValue(":INPUTID_B", inputidB);
193 
194  if (!query.exec())
195  {
196  MythDB::DBError("CardUtil::is_tuner_shared", query);
197  return false;
198  }
199 
200  if (!query.next())
201  return false;
202 
203  const QString vdevice = query.value(0).toString();
204  const QString hostname = query.value(1).toString();
205  const QString inputtype = query.value(2).toString();
206 
207  if (!IsTunerSharingCapable(inputtype.toUpper()))
208  return false;
209 
210  if (!query.next())
211  return false;
212 
213  bool ret = ((vdevice == query.value(0).toString()) &&
214  (hostname == query.value(1).toString()) &&
215  (inputtype == query.value(2).toString()));
216 
217  LOG(VB_RECORD, LOG_DEBUG, QString("IsTunerShared(%1,%2) -> %3")
218  .arg(inputidA).arg(inputidB).arg(ret));
219 
220  return ret;
221 }
222 
228 bool CardUtil::IsInputTypePresent(const QString &rawtype, QString hostname)
229 {
230  if (hostname.isEmpty())
231  hostname = gCoreContext->GetHostName();
232 
233  MSqlQuery query(MSqlQuery::InitCon());
234  QString qstr =
235  "SELECT count(cardtype) "
236  "FROM capturecard "
237  "WHERE capturecard.hostname = :HOSTNAME ";
238 
239  if (!rawtype.isEmpty())
240  qstr += " AND capturecard.cardtype = :INPUTTYPE";
241 
242  query.prepare(qstr);
243 
244  if (!rawtype.isEmpty())
245  query.bindValue(":INPUTTYPE", rawtype.toUpper());
246 
247  query.bindValue(":HOSTNAME", hostname);
248 
249  if (!query.exec())
250  {
251  MythDB::DBError("CardUtil::IsInputTypePresent", query);
252  return false;
253  }
254 
255  uint count = 0;
256  if (query.next())
257  count = query.value(0).toUInt();
258 
259  return count > 0;
260 }
261 
263 {
264  InputTypes inputtypes;
265 
266  MSqlQuery query(MSqlQuery::InitCon());
267  query.prepare("SELECT DISTINCT cardtype, videodevice "
268  "FROM capturecard");
269 
270  if (!query.exec())
271  {
272  MythDB::DBError("CardUtil::GetInputTypes()", query);
273  }
274  else
275  {
276  QString cardtype;
277 
278  while (query.next())
279  {
280  cardtype = query.value(0).toString();
281  if (cardtype != "V4L2ENC")
282  inputtypes[cardtype] = "";
283 #ifdef USING_V4L2
284  else
285  {
286  V4L2util v4l2(query.value(1).toString());
287  if (v4l2.IsOpen())
288  {
289  QString driver_name = "V4L2:" + v4l2.DriverName();
290  inputtypes[driver_name] = v4l2.CardName();
291  }
292  }
293 #endif
294  }
295  }
296 
297  return inputtypes;
298 }
299 
305 QStringList CardUtil::GetVideoDevices(const QString &rawtype, QString hostname)
306 {
307  QStringList list;
308 
309  if (hostname.isEmpty())
310  hostname = gCoreContext->GetHostName();
311 
312  MSqlQuery query(MSqlQuery::InitCon());
313  QString qstr =
314  "SELECT videodevice "
315  "FROM capturecard "
316  "WHERE hostname = :HOSTNAME";
317 
318  if (!rawtype.isEmpty())
319  qstr += " AND cardtype = :INPUTTYPE";
320 
321  query.prepare(qstr);
322 
323  if (!rawtype.isEmpty())
324  query.bindValue(":INPUTTYPE", rawtype.toUpper());
325 
326  query.bindValue(":HOSTNAME", hostname);
327 
328  if (!query.exec())
329  {
330  MythDB::DBError("CardUtil::GetVideoDevices", query);
331  return list;
332  }
333 
334  QMap<QString,bool> dup;
335  while (query.next())
336  {
337  QString videodevice = query.value(0).toString();
338  if (dup[videodevice])
339  continue;
340 
341  list.push_back(videodevice);
342  dup[videodevice] = true;
343  }
344 
345  return list;
346 }
347 
348 QStringList CardUtil::ProbeVideoDevices(const QString &rawtype)
349 {
350  QStringList devs;
351 
352  if (rawtype.toUpper() == "DVB")
353  {
354  QDir dir("/dev/dvb", "adapter*", QDir::Name, QDir::Dirs);
355  const QFileInfoList il = dir.entryInfoList();
356  if (il.isEmpty())
357  return devs;
358 
359  QFileInfoList::const_iterator it = il.begin();
360 
361  for (; it != il.end(); ++it)
362  {
363  QDir subdir(it->filePath(), "frontend*", QDir::Name, QDir::Files | QDir::System);
364  const QFileInfoList subil = subdir.entryInfoList();
365  if (subil.isEmpty())
366  continue;
367 
368  QFileInfoList::const_iterator subit = subil.begin();
369  for (; subit != subil.end(); ++subit)
370  devs.push_back(subit->filePath());
371  }
372  }
373  else if (rawtype.toUpper() == "ASI")
374  {
375  QDir dir("/dev/", "asirx*", QDir::Name, QDir::System);
376  const QFileInfoList il = dir.entryInfoList();
377  if (il.isEmpty())
378  return devs;
379 
380  QFileInfoList::const_iterator it = il.begin();
381  for (; it != il.end(); ++it)
382  {
383  if (GetASIDeviceNumber(it->filePath()) >= 0)
384  {
385  devs.push_back(it->filePath());
386  continue;
387  }
388  break;
389  }
390  }
391 #ifdef USING_HDHOMERUN
392  else if (rawtype.toUpper() == "HDHOMERUN")
393  {
394  uint32_t target_ip = 0;
395  uint32_t device_type = HDHOMERUN_DEVICE_TYPE_TUNER;
396  uint32_t device_id = HDHOMERUN_DEVICE_ID_WILDCARD;
397  const int max_count = 50;
398  hdhomerun_discover_device_t result_list[max_count];
399 
400  int result = hdhomerun_discover_find_devices_custom(
401  target_ip, device_type, device_id, result_list, max_count);
402 
403  if (result == -1)
404  {
405  LOG(VB_GENERAL, LOG_ERR, "Error finding HDHomerun devices");
406  return devs;
407  }
408 
409  if (result >= max_count)
410  {
411  LOG(VB_GENERAL, LOG_WARNING,
412  "Warning: may be > 50 HDHomerun devices");
413  }
414 
415  // Return "deviceid ipaddress" pairs
416  for (int i = 0; i < result; i++)
417  {
418  QString id = QString("%1").arg(result_list[i].device_id, 0, 16);
419  QString ip = QString("%1.%2.%3.%4")
420  .arg((result_list[i].ip_addr>>24) & 0xFF)
421  .arg((result_list[i].ip_addr>>16) & 0xFF)
422  .arg((result_list[i].ip_addr>> 8) & 0xFF)
423  .arg((result_list[i].ip_addr>> 0) & 0xFF);
424 
425  for (int tuner = 0; tuner < result_list[i].tuner_count; tuner++)
426  {
427  QString hdhrdev = id.toUpper() + " " + ip + " " +
428  QString("%1").arg(tuner);
429  devs.push_back(hdhrdev);
430  }
431  }
432  }
433 #endif // USING_HDHOMERUN
434 #ifdef USING_VBOX
435  else if (rawtype.toUpper() == "VBOX")
436  {
437  devs = VBox::probeDevices();
438  }
439 #endif // USING_VBOX
440 #ifdef USING_CETON
441  else if (rawtype.toUpper() == "CETON")
442  {
443  // TODO implement CETON probing.
444  LOG(VB_GENERAL, LOG_INFO, "CardUtil::ProbeVideoDevices: "
445  "TODO Probe Ceton devices");
446  }
447 #endif // USING_CETON
448  else
449  {
450  LOG(VB_GENERAL, LOG_ERR, QString("Raw Type: '%1' is not supported")
451  .arg(rawtype));
452  }
453 
454  return devs;
455 }
456 
457 QString CardUtil::ProbeDVBType(const QString &device)
458 {
459  QString ret = "ERROR_UNKNOWN";
460 
461  if (device.isEmpty())
462  return ret;
463 
464 #ifdef USING_DVB
465  QString dvbdev = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device);
466  QByteArray dev = dvbdev.toLatin1();
467 
468  int fd_frontend = open(dev.constData(), O_RDWR | O_NONBLOCK);
469  if (fd_frontend < 0)
470  {
471  LOG(VB_GENERAL, LOG_ERR, QString("Can't open DVB frontend (%1) for %2.")
472  .arg(dvbdev).arg(device));
473  return ret;
474  }
475 
476  struct dvb_frontend_info info;
477  memset(&info, 0, sizeof(info));
478  int err = ioctl(fd_frontend, FE_GET_INFO, &info);
479  if (err < 0)
480  {
481  close(fd_frontend);
482  LOG(VB_GENERAL, LOG_ERR, QString("FE_GET_INFO ioctl failed (%1)")
483  .arg(dvbdev) + ENO);
484  return ret;
485  }
486  close(fd_frontend);
487 
488  DTVTunerType type(info.type);
489 #if HAVE_FE_CAN_2G_MODULATION
490  if (info.caps & FE_CAN_2G_MODULATION)
491  {
492  if (type == DTVTunerType::kTunerTypeDVBS1)
494  else if (type == DTVTunerType::kTunerTypeDVBT)
496  }
497 #endif // HAVE_FE_CAN_2G_MODULATION
498  ret = (type.toString() != "UNKNOWN") ? type.toString().toUpper() : ret;
499 #endif // USING_DVB
500 
501  return ret;
502 }
503 
507 QString CardUtil::ProbeDVBFrontendName(const QString &device)
508 {
509  QString ret = "ERROR_UNKNOWN";
510  (void) device;
511 
512 #ifdef USING_DVB
513  QString dvbdev = CardUtil::GetDeviceName(DVB_DEV_FRONTEND, device);
514  QByteArray dev = dvbdev.toLatin1();
515  int fd_frontend = open(dev.constData(), O_RDWR | O_NONBLOCK);
516  if (fd_frontend < 0)
517  return "ERROR_OPEN";
518 
519  struct dvb_frontend_info info;
520  memset(&info, 0, sizeof(info));
521  int err = ioctl(fd_frontend, FE_GET_INFO, &info);
522  if (err < 0)
523  {
524  close(fd_frontend);
525  return "ERROR_PROBE";
526  }
527 
528  ret = info.name;
529 
530  close(fd_frontend);
531 #endif // USING_DVB
532 
533  return ret;
534 }
535 
553 bool CardUtil::HasDVBCRCBug(const QString &device)
554 {
555  QString name = ProbeDVBFrontendName(device);
556  return ((name == "VLSI VES1x93 DVB-S") || // munges PMT
557  (name == "ST STV0299 DVB-S")); // munges PAT
558 }
559 
561 {
562  QString name = ProbeDVBFrontendName(device);
563  if (name.indexOf("DVB-S") >= 0)
564  return 300;
565  if (name == "DiBcom 3000P/M-C DVB-T")
566  return 100;
567  return 25;
568 }
569 
571 {
572  QString type = GetRawInputType(inputid);
573  if ("DVB" != type)
574  return type;
575 
576  QString device = GetVideoDevice(inputid);
577 
578  if (device.isEmpty())
579  return "ERROR_OPEN";
580 
581  return ProbeDVBType(device);
582 }
583 
585 bool CardUtil::IsDVBInputType(const QString &inputType)
586 {
587  QString t = inputType.toUpper();
588  return (t == "DVB") || (t == "QAM") || (t == "QPSK") ||
589  (t == "OFDM") || (t == "ATSC") || (t == "DVB_S2");
590 }
591 
592 QString get_on_input(const QString &to_get, uint inputid)
593 {
594  MSqlQuery query(MSqlQuery::InitCon());
595  query.prepare(
596  QString("SELECT %1 ").arg(to_get) +
597  "FROM capturecard "
598  "WHERE capturecard.cardid = :INPUTID");
599  query.bindValue(":INPUTID", inputid);
600 
601  if (!query.exec())
602  MythDB::DBError("CardUtil::get_on_source", query);
603  else if (query.next())
604  return query.value(0).toString();
605 
606  return QString::null;
607 }
608 
609 bool set_on_input(const QString &to_set, uint inputid, const QString &value)
610 {
611  QString tmp = get_on_input("capturecard.cardid", inputid);
612  if (tmp.isEmpty())
613  return false;
614 
615  MSqlQuery query(MSqlQuery::InitCon());
616  query.prepare(
617  QString("UPDATE capturecard SET %1 = :VALUE ").arg(to_set) +
618  "WHERE cardid = :INPUTID");
619  query.bindValue(":INPUTID", inputid);
620  query.bindValue(":VALUE", value);
621 
622  if (query.exec())
623  return true;
624 
625  MythDB::DBError("CardUtil::set_on_input", query);
626  return false;
627 }
628 
638 vector<uint> CardUtil::GetInputIDs(QString videodevice,
639  QString rawtype,
640  QString inputname,
641  QString hostname)
642 {
643  vector<uint> list;
644 
645  if (hostname.isEmpty())
646  hostname = gCoreContext->GetHostName();
647 
648  MSqlQuery query(MSqlQuery::InitCon());
649  QString qstr =
650  "SELECT cardid "
651  "FROM capturecard "
652  "WHERE hostname = :HOSTNAME ";
653  if (!videodevice.isEmpty())
654  qstr += "AND videodevice = :DEVICE ";
655  if (!inputname.isEmpty())
656  qstr += "AND inputname = :INPUTNAME ";
657  if (!rawtype.isEmpty())
658  qstr += "AND cardtype = :INPUTTYPE ";
659  qstr += "ORDER BY cardid";
660 
661  query.prepare(qstr);
662 
663  query.bindValue(":HOSTNAME", hostname);
664  if (!videodevice.isEmpty())
665  query.bindValue(":DEVICE", videodevice);
666  if (!inputname.isEmpty())
667  query.bindValue(":INPUTNAME", inputname);
668  if (!rawtype.isEmpty())
669  query.bindValue(":INPUTTYPE", rawtype.toUpper());
670 
671  if (!query.exec())
672  MythDB::DBError("CardUtil::GetInputIDs(videodevice...)", query);
673  else
674  {
675  while (query.next())
676  list.push_back(query.value(0).toUInt());
677  }
678 
679  return list;
680 }
681 
683 {
684  if (!inputid)
685  return 0;
686 
687  MSqlQuery query(MSqlQuery::InitCon());
688  QString qstr =
689  "SELECT COUNT(*) "
690  "FROM capturecard "
691  "WHERE parentid = :INPUTID";
692 
693  query.prepare(qstr);
694  query.bindValue(":INPUTID", inputid);
695 
696  uint count = 0;
697 
698  if (!query.exec())
699  MythDB::DBError("CardUtil::GetChildInputCount()", query);
700  else if (query.next())
701  count = query.value(0).toUInt();
702 
703  return count;
704 }
705 
706 vector<uint> CardUtil::GetChildInputIDs(uint inputid)
707 {
708  vector<uint> list;
709 
710  if (!inputid)
711  return list;
712 
713  MSqlQuery query(MSqlQuery::InitCon());
714  QString qstr =
715  "SELECT cardid "
716  "FROM capturecard "
717  "WHERE parentid = :INPUTID "
718  "ORDER BY cardid";
719 
720  query.prepare(qstr);
721  query.bindValue(":INPUTID", inputid);
722 
723  if (!query.exec())
724  MythDB::DBError("CardUtil::GetChildInputIDs()", query);
725  else
726  {
727  while (query.next())
728  list.push_back(query.value(0).toUInt());
729  }
730 
731  return list;
732 }
733 
734 static uint clone_capturecard(uint src_inputid, uint orig_dst_inputid)
735 {
736  uint dst_inputid = orig_dst_inputid;
737 
738  MSqlQuery query(MSqlQuery::InitCon());
739  if (!dst_inputid)
740  {
741  query.prepare(
742  "DELETE FROM capturecard "
743  "WHERE videodevice = 'temp_dummy'");
744 
745  if (!query.exec())
746  {
747  MythDB::DBError("clone_capturecard -- delete temp", query);
748  return 0;
749  }
750 
751  query.prepare(
752  "INSERT INTO capturecard "
753  "SET videodevice = 'temp_dummy'");
754 
755  if (!query.exec())
756  {
757  MythDB::DBError("clone_capturecard -- insert temp", query);
758  return 0;
759  }
760 
761  query.prepare(
762  "SELECT cardid "
763  "FROM capturecard "
764  "WHERE videodevice = 'temp_dummy'");
765 
766  if (!query.exec())
767  {
768  MythDB::DBError("clone_capturecard -- get temp id", query);
769  return 0;
770  }
771 
772  if (!query.next())
773  {
774  LOG(VB_GENERAL, LOG_ERR, "clone_capturecard -- get temp id");
775  return 0;
776  }
777 
778  dst_inputid = query.value(0).toUInt();
779  }
780 
781  query.prepare(
782  "SELECT videodevice, audiodevice, vbidevice, "
783  " cardtype, hostname, signal_timeout, "
784  " channel_timeout, dvb_wait_for_seqstart, dvb_on_demand, "
785  " dvb_tuning_delay, dvb_diseqc_type, diseqcid, "
786  " dvb_eitscan, inputname, sourceid, "
787  " externalcommand, changer_device, changer_model, "
788  " tunechan, startchan, displayname, "
789  " dishnet_eit, recpriority, quicktune, "
790  " livetvorder, reclimit, "
791  // See below for special handling of the following.
792  " schedgroup, schedorder "
793  "FROM capturecard "
794  "WHERE cardid = :INPUTID");
795  query.bindValue(":INPUTID", src_inputid);
796 
797  if (!query.exec())
798  {
799  MythDB::DBError("clone_capturecard -- get data", query);
800  return 0;
801  }
802  if (!query.next())
803  {
804  LOG(VB_GENERAL, LOG_ERR, "clone_cardinput -- get data 2");
805  return 0;
806  }
807 
808  // Hangel schedgroup and schedorder specially. If schedgroup is
809  // set, schedgroup and schedorder should be false and 0,
810  // respectively, for all children.
811  bool schedgroup = query.value(26).toBool();
812  uint schedorder = query.value(27).toUInt();
813  if (schedgroup)
814  {
815  schedgroup = false;
816  schedorder = 0;
817  }
818 
819  MSqlQuery query2(MSqlQuery::InitCon());
820  query2.prepare(
821  "UPDATE capturecard "
822  "SET videodevice = :V0, "
823  " audiodevice = :V1, "
824  " vbidevice = :V2, "
825  " cardtype = :V3, "
826  " hostname = :V4, "
827  " signal_timeout = :V5, "
828  " channel_timeout = :V6, "
829  " dvb_wait_for_seqstart = :V7, "
830  " dvb_on_demand = :V8, "
831  " dvb_tuning_delay = :V9, "
832  " dvb_diseqc_type = :V10, "
833  " diseqcid = :V11,"
834  " dvb_eitscan = :V12, "
835  " inputname = :V13, "
836  " sourceid = :V14, "
837  " externalcommand = :V15, "
838  " changer_device = :V16, "
839  " changer_model = :V17, "
840  " tunechan = :V18, "
841  " startchan = :V19, "
842  " displayname = :V20, "
843  " dishnet_eit = :V21, "
844  " recpriority = :V22, "
845  " quicktune = :V23, "
846  " livetvorder = :V24, "
847  " reclimit = :V25, "
848  " schedgroup = :SCHEDGROUP, "
849  " schedorder = :SCHEDORDER, "
850  " parentid = :PARENTID "
851  "WHERE cardid = :INPUTID");
852  for (uint i = 0; i < 26; ++i)
853  query2.bindValue(QString(":V%1").arg(i), query.value(i).toString());
854  query2.bindValue(":INPUTID", dst_inputid);
855  query2.bindValue(":PARENTID", src_inputid);
856  query2.bindValue(":SCHEDGROUP", schedgroup);
857  query2.bindValue(":SCHEDORDER", schedorder);
858 
859  if (!query2.exec())
860  {
861  MythDB::DBError("clone_capturecard -- save data", query2);
862  if (!orig_dst_inputid)
863  CardUtil::DeleteCard(dst_inputid);
864  return 0;
865  }
866 
867  // copy input group linkages
868  vector<uint> src_grps = CardUtil::GetInputGroups(src_inputid);
869  vector<uint> dst_grps = CardUtil::GetInputGroups(dst_inputid);
870  for (uint j = 0; j < dst_grps.size(); j++)
871  CardUtil::UnlinkInputGroup(dst_inputid, dst_grps[j]);
872  for (uint j = 0; j < src_grps.size(); j++)
873  CardUtil::LinkInputGroup(dst_inputid, src_grps[j]);
874 
875  // clone diseqc_config (just points to the same diseqc_tree row)
876  DiSEqCDevSettings diseqc;
877  if (diseqc.Load(src_inputid))
878  diseqc.Store(dst_inputid);
879 
880  return dst_inputid;
881 }
882 
883 bool CardUtil::CloneCard(uint src_inputid, uint orig_dst_inputid)
884 {
885  QString type = CardUtil::GetRawInputType(src_inputid);
886  if (!IsTunerSharingCapable(type))
887  return false;
888 
889  uint dst_inputid = clone_capturecard(src_inputid, orig_dst_inputid);
890  if (!dst_inputid)
891  return false;
892 
893  return true;
894 }
895 
897 {
898  QString fwnode;
899 
900  MSqlQuery query(MSqlQuery::InitCon());
901  query.prepare("SELECT changer_device "
902  "FROM capturecard WHERE cardid = :INPUTID ");
903  query.bindValue(":INPUTID", inputid);
904 
905  if (query.exec() && query.next())
906  {
907  fwnode = query.value(0).toString();
908  }
909 
910  return fwnode;
911 }
912 
914 {
915  QString fwnode;
916 
917  MSqlQuery query(MSqlQuery::InitCon());
918  query.prepare("SELECT changer_model "
919  "FROM capturecard WHERE cardid = :INPUTID ");
920  query.bindValue(":INPUTID", inputid);
921 
922  if (query.exec() && query.next())
923  {
924  fwnode = query.value(0).toString();
925  }
926 
927  return fwnode;
928 }
929 
930 vector<uint> CardUtil::GetInputIDs(uint sourceid)
931 {
932  MSqlQuery query(MSqlQuery::InitCon());
933 
934  query.prepare(
935  "SELECT DISTINCT cardid "
936  "FROM capturecard "
937  "WHERE sourceid = :SOURCEID");
938  query.bindValue(":SOURCEID", sourceid);
939 
940  vector<uint> list;
941 
942  if (!query.exec())
943  {
944  MythDB::DBError("CardUtil::GetInputIDs()", query);
945  return list;
946  }
947 
948  while (query.next())
949  list.push_back(query.value(0).toUInt());
950 
951  return list;
952 }
953 
954 bool CardUtil::SetStartChannel(uint inputid, const QString &channum)
955 {
956  MSqlQuery query(MSqlQuery::InitCon());
957  query.prepare("UPDATE capturecard "
958  "SET startchan = :CHANNUM "
959  "WHERE cardid = :INPUTID");
960  query.bindValue(":CHANNUM", channum);
961  query.bindValue(":INPUTID", inputid);
962 
963  if (!query.exec())
964  {
965  MythDB::DBError("set_startchan", query);
966  return false;
967  }
968 
969  return true;
970 }
971 
972 bool CardUtil::GetInputInfo(InputInfo &input, vector<uint> *groupids)
973 {
974  if (!input.inputid)
975  return false;
976 
977  MSqlQuery query(MSqlQuery::InitCon());
978  query.prepare("SELECT "
979  "inputname, sourceid, livetvorder, "
980  "schedorder, displayname, recpriority, quicktune "
981  "FROM capturecard "
982  "WHERE cardid = :INPUTID");
983  query.bindValue(":INPUTID", input.inputid);
984 
985  if (!query.exec())
986  {
987  MythDB::DBError("CardUtil::GetInputInfo()", query);
988  return false;
989  }
990 
991  if (!query.next())
992  return false;
993 
994  input.name = query.value(0).toString();
995  input.sourceid = query.value(1).toUInt();
996  input.livetvorder = query.value(2).toUInt();
997  input.scheduleOrder = query.value(3).toUInt();
998  input.displayName = query.value(4).toString();
999  input.recPriority = query.value(5).toInt();
1000  input.quickTune = query.value(6).toBool();
1001 
1002  if (input.displayName.isEmpty())
1003  input.displayName = QObject::tr("Input %1:%2")
1004  .arg(input.inputid).arg(input.name);
1005 
1006  if (groupids)
1007  *groupids = GetInputGroups(input.inputid);
1008 
1009  return true;
1010 }
1011 
1012 QList<InputInfo> CardUtil::GetAllInputInfo()
1013 {
1014  QList<InputInfo> infoInputList;
1015 
1016  MSqlQuery query(MSqlQuery::InitCon());
1017  query.prepare("SELECT cardid, "
1018  "inputname, sourceid, livetvorder, "
1019  "schedorder, displayname, recpriority, quicktune "
1020  "FROM capturecard");
1021 
1022  if (!query.exec())
1023  {
1024  MythDB::DBError("CardUtil::GetAllInputInfo()", query);
1025  return infoInputList;
1026  }
1027 
1028  while (query.next())
1029  {
1030  InputInfo input;
1031  input.inputid = query.value(0).toUInt();
1032  input.name = query.value(1).toString();
1033  input.sourceid = query.value(2).toUInt();
1034  input.livetvorder = query.value(3).toUInt();
1035  input.scheduleOrder = query.value(4).toUInt();
1036  input.displayName = query.value(5).toString();
1037  input.recPriority = query.value(6).toInt();
1038  input.quickTune = query.value(7).toBool();
1039 
1040  infoInputList.push_back(input);
1041  }
1042 
1043  return infoInputList;
1044 }
1045 
1047 {
1048  InputInfo info("None", 0, inputid, 0, 0, 0);
1049  GetInputInfo(info);
1050  return info.name;
1051 }
1052 
1054 {
1055  MSqlQuery query(MSqlQuery::InitCon());
1056  query.prepare("SELECT startchan "
1057  "FROM capturecard "
1058  "WHERE cardid = :INPUTID");
1059  query.bindValue(":INPUTID", inputid);
1060 
1061  if (!query.exec())
1062  MythDB::DBError("CardUtil::GetStartingChannel(uint)", query);
1063  else if (query.next())
1064  return query.value(0).toString();
1065 
1066  return QString::null;
1067 }
1068 
1070 {
1071  if (!inputid)
1072  return QString::null;
1073 
1074  MSqlQuery query(MSqlQuery::InitCon());
1075  query.prepare("SELECT displayname, cardid, cardtype, inputname "
1076  "FROM capturecard "
1077  "WHERE cardid = :INPUTID");
1078  query.bindValue(":INPUTID", inputid);
1079 
1080  if (!query.exec())
1081  MythDB::DBError("CardUtil::GetDisplayName(uint)", query);
1082  else if (query.next())
1083  {
1084  QString result = query.value(0).toString();
1085  if (result.isEmpty())
1086  result = QString("%1: %2/%3").arg(query.value(1).toInt())
1087  .arg(query.value(2).toString()).arg(query.value(3).toString());
1088  return result;
1089  }
1090 
1091  return QString::null;
1092 }
1093 
1095 {
1096  MSqlQuery query(MSqlQuery::InitCon());
1097  query.prepare(
1098  "SELECT sourceid "
1099  "FROM capturecard "
1100  "WHERE cardid = :INPUTID");
1101  query.bindValue(":INPUTID", inputid);
1102  if (!query.exec() || !query.isActive())
1103  MythDB::DBError("CardUtil::GetSourceID()", query);
1104  else if (query.next())
1105  return query.value(0).toUInt();
1106 
1107  return 0;
1108 }
1109 
1111  const uint sourceid,
1112  const QString &inputname,
1113  const QString &externalcommand,
1114  const QString &changer_device,
1115  const QString &changer_model,
1116  const QString &hostname,
1117  const QString &tunechan,
1118  const QString &startchan,
1119  const QString &displayname,
1120  bool dishnet_eit,
1121  const uint recpriority,
1122  const uint quicktune,
1123  const uint schedorder,
1124  const uint livetvorder)
1125 {
1126  MSqlQuery query(MSqlQuery::InitCon());
1127 
1128  query.prepare(
1129  "UPDATE capturecard "
1130  "SET sourceid = :SOURCEID, "
1131  " inputname = :INPUTNAME, "
1132  " externalcommand = :EXTERNALCOMMAND, "
1133  " changer_device = :CHANGERDEVICE, "
1134  " changer_model = :CHANGERMODEL, "
1135  " tunechan = :TUNECHAN, "
1136  " startchan = :STARTCHAN, "
1137  " displayname = :DISPLAYNAME, "
1138  " dishnet_eit = :DISHNETEIT, "
1139  " recpriority = :RECPRIORITY, "
1140  " quicktune = :QUICKTUNE, "
1141  " schedorder = :SCHEDORDER, "
1142  " livetvorder = :LIVETVORDER "
1143  "WHERE cardid = :INPUTID AND "
1144  " inputname = 'None'");
1145 
1146  query.bindValue(":INPUTID", inputid);
1147  query.bindValue(":SOURCEID", sourceid);
1148  query.bindValue(":INPUTNAME", inputname);
1149  query.bindValue(":EXTERNALCOMMAND", externalcommand);
1150  query.bindValue(":CHANGERDEVICE", changer_device);
1151  query.bindValue(":CHANGERMODEL", changer_model);
1152  query.bindValue(":TUNECHAN", tunechan);
1153  query.bindValue(":STARTCHAN", startchan);
1154  query.bindValue(":DISPLAYNAME", displayname.isNull() ? "" : displayname);
1155  query.bindValue(":DISHNETEIT", dishnet_eit);
1156  query.bindValue(":RECPRIORITY", recpriority);
1157  query.bindValue(":QUICKTUNE", quicktune);
1158  query.bindValue(":SCHEDORDER", schedorder);
1159  query.bindValue(":LIVETVORDER", livetvorder);
1160 
1161  if (!query.exec())
1162  {
1163  MythDB::DBError("CreateCardInput", query);
1164  return -1;
1165  }
1166 
1167  return inputid;
1168 }
1169 
1171 {
1172  MSqlQuery query(MSqlQuery::InitCon());
1173  query.prepare(
1174  "UPDATE capturecard "
1175  "SET sourceid = 0, "
1176  " inputname = 'None', "
1177  " externalcommand = '', "
1178  " changer_device = '', "
1179  " changer_model = '', "
1180  " tunechan = '', "
1181  " startchan = '', "
1182  " displayname = '', "
1183  " dishnet_eit = 0, "
1184  " recpriority = 0, "
1185  " quicktune = 0, "
1186  " schedorder = 1, "
1187  " livetvorder = 1 "
1188  "WHERE cardid = :INPUTID");
1189  query.bindValue(":INPUTID", inputid);
1190 
1191  if (!query.exec())
1192  {
1193  MythDB::DBError("DeleteInput", query);
1194  return false;
1195  }
1196 
1197  query.prepare("DELETE FROM inputgroup "
1198  "WHERE cardinputid = :INPUTID AND "
1199  " inputgroupname LIKE 'user:%'");
1200  query.bindValue(":INPUTID", inputid);
1201 
1202  if (!query.exec())
1203  {
1204  MythDB::DBError("DeleteInput2", query);
1205  return false;
1206  }
1207 
1208  return true;
1209 }
1210 
1212 {
1213  MSqlQuery query(MSqlQuery::InitCon());
1214 
1215  query.prepare("SELECT inputgroupid FROM inputgroup "
1216  "WHERE inputgroupname = :GROUPNAME "
1217  "LIMIT 1");
1218  query.bindValue(":GROUPNAME", name);
1219  if (!query.exec())
1220  {
1221  MythDB::DBError("CreateNewInputGroup 0", query);
1222  return 0;
1223  }
1224 
1225  if (query.next())
1226  return query.value(0).toUInt();
1227 
1228  query.prepare("SELECT MAX(inputgroupid) FROM inputgroup");
1229  if (!query.exec())
1230  {
1231  MythDB::DBError("CreateNewInputGroup 1", query);
1232  return 0;
1233  }
1234 
1235  uint inputgroupid = (query.next()) ? query.value(0).toUInt() + 1 : 1;
1236 
1237  query.prepare(
1238  "INSERT INTO inputgroup "
1239  " (cardinputid, inputgroupid, inputgroupname) "
1240  "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
1241  query.bindValue(":INPUTID", 0);
1242  query.bindValue(":GROUPID", inputgroupid);
1243  query.bindValue(":GROUPNAME", name);
1244  if (!query.exec())
1245  {
1246  MythDB::DBError("CreateNewInputGroup 2", query);
1247  return 0;
1248  }
1249 
1250  return inputgroupid;
1251 }
1252 
1254  const QString &type,
1255  const QString &host,
1256  const QString &device)
1257 {
1258  QString name = host + '|' + device;
1259  if (type == "FREEBOX" || type == "IMPORT" ||
1260  type == "DEMO" || type == "EXTERNAL")
1261  name += QString("|%1").arg(inputid);
1262  return CreateInputGroup(name);
1263 }
1264 
1266 {
1267  MSqlQuery query(MSqlQuery::InitCon());
1268  query.prepare(
1269  "SELECT inputgroupid "
1270  "FROM inputgroup "
1271  "WHERE cardinputid = :INPUTID "
1272  " AND inputgroupname REGEXP '^[a-z_-]*\\\\|'");
1273  query.bindValue(":INPUTID", inputid);
1274 
1275  if (!query.exec())
1276  {
1277  MythDB::DBError("CardUtil::GetDeviceInputGroup()", query);
1278  return false;
1279  }
1280 
1281  if (query.next())
1282  {
1283  return query.value(0).toUInt();
1284  }
1285 
1286  return 0;
1287 }
1288 
1289 bool CardUtil::LinkInputGroup(uint inputid, uint inputgroupid)
1290 {
1291  MSqlQuery query(MSqlQuery::InitCon());
1292 
1293  query.prepare(
1294  "SELECT cardinputid, inputgroupid, inputgroupname "
1295  "FROM inputgroup "
1296  "WHERE inputgroupid = :GROUPID "
1297  "ORDER BY inputgroupid, cardinputid, inputgroupname");
1298  query.bindValue(":GROUPID", inputgroupid);
1299 
1300  if (!query.exec())
1301  {
1302  MythDB::DBError("CardUtil::CreateInputGroup() 1", query);
1303  return false;
1304  }
1305 
1306  if (!query.next())
1307  return false;
1308 
1309  const QString name = query.value(2).toString();
1310 
1311  query.prepare(
1312  "INSERT INTO inputgroup "
1313  " (cardinputid, inputgroupid, inputgroupname) "
1314  "VALUES (:INPUTID, :GROUPID, :GROUPNAME ) ");
1315 
1316  query.bindValue(":INPUTID", inputid);
1317  query.bindValue(":GROUPID", inputgroupid);
1318  query.bindValue(":GROUPNAME", name);
1319 
1320  if (!query.exec())
1321  {
1322  MythDB::DBError("CardUtil::CreateInputGroup() 2", query);
1323  return false;
1324  }
1325 
1326  return true;
1327 }
1328 
1329 bool CardUtil::UnlinkInputGroup(uint inputid, uint inputgroupid)
1330 {
1331  MSqlQuery query(MSqlQuery::InitCon());
1332 
1333  if (!inputid && !inputgroupid)
1334  {
1335  query.prepare(
1336  "DELETE FROM inputgroup "
1337  "WHERE cardinputid NOT IN "
1338  "( SELECT cardid FROM capturecard )");
1339  }
1340  else
1341  {
1342  query.prepare(
1343  "DELETE FROM inputgroup "
1344  "WHERE cardinputid = :INPUTID AND "
1345  " inputgroupid = :GROUPID ");
1346 
1347  query.bindValue(":INPUTID", inputid);
1348  query.bindValue(":GROUPID", inputgroupid);
1349  }
1350 
1351  if (!query.exec())
1352  {
1353  MythDB::DBError("CardUtil::DeleteInputGroup()", query);
1354  return false;
1355  }
1356 
1357  return true;
1358 }
1359 
1360 vector<uint> CardUtil::GetInputGroups(uint inputid)
1361 {
1362  vector<uint> list;
1363 
1364  MSqlQuery query(MSqlQuery::InitCon());
1365 
1366  query.prepare(
1367  "SELECT inputgroupid "
1368  "FROM inputgroup "
1369  "WHERE cardinputid = :INPUTID "
1370  "ORDER BY inputgroupid, cardinputid, inputgroupname");
1371 
1372  query.bindValue(":INPUTID", inputid);
1373 
1374  if (!query.exec())
1375  {
1376  MythDB::DBError("CardUtil::GetInputGroups()", query);
1377  return list;
1378  }
1379 
1380  while (query.next())
1381  list.push_back(query.value(0).toUInt());
1382 
1383  return list;
1384 }
1385 
1386 vector<uint> CardUtil::GetGroupInputIDs(uint inputgroupid)
1387 {
1388  vector<uint> list;
1389 
1390  MSqlQuery query(MSqlQuery::InitCon());
1391 
1392  query.prepare(
1393  "SELECT DISTINCT cardid "
1394  "FROM capturecard, inputgroup "
1395  "WHERE inputgroupid = :GROUPID AND "
1396  " capturecard.cardid = inputgroup.cardinputid "
1397  "ORDER BY cardid");
1398 
1399  query.bindValue(":GROUPID", inputgroupid);
1400 
1401  if (!query.exec())
1402  {
1403  MythDB::DBError("CardUtil::GetGroupInputIDs()", query);
1404  return list;
1405  }
1406 
1407  while (query.next())
1408  list.push_back(query.value(0).toUInt());
1409 
1410  return list;
1411 }
1412 
1414 {
1415  LOG(VB_RECORD, LOG_INFO,
1416  LOC + QString("GetConflictingInputs() input %1").arg(inputid));
1417 
1418  vector<uint> inputids;
1419 
1420  MSqlQuery query(MSqlQuery::InitCon());
1421 
1422  query.prepare(
1423  "SELECT DISTINCT c.cardid "
1424  "FROM ( "
1425  " SELECT inputgroupid "
1426  " FROM inputgroup "
1427  " WHERE cardinputid = :INPUTID1 "
1428  ") g "
1429  "JOIN inputgroup ig ON ig.inputgroupid = g.inputgroupid "
1430  "JOIN capturecard c ON c.cardid = ig.cardinputid "
1431  " AND c.cardid <> :INPUTID2 "
1432  "ORDER BY c.cardid");
1433 
1434  query.bindValue(":INPUTID1", inputid);
1435  query.bindValue(":INPUTID2", inputid);
1436 
1437  if (!query.exec())
1438  {
1439  MythDB::DBError("CardUtil::GetConflictingInputs()", query);
1440  return inputids;
1441  }
1442 
1443  while (query.next())
1444  {
1445  inputids.push_back(query.value(0).toUInt());
1446  LOG(VB_RECORD, LOG_INFO,
1447  LOC + QString("GetConflictingInputs() got input %1").arg(inputids.back()));
1448  }
1449 
1450  return inputids;
1451 }
1452 
1454  uint &signal_timeout, uint &channel_timeout)
1455 {
1456  MSqlQuery query(MSqlQuery::InitCon());
1457  query.prepare(
1458  "SELECT signal_timeout, channel_timeout "
1459  "FROM capturecard "
1460  "WHERE cardid = :INPUTID");
1461  query.bindValue(":INPUTID", inputid);
1462 
1463  if (!query.exec() || !query.isActive())
1464  MythDB::DBError("CardUtil::GetTimeouts()", query);
1465  else if (query.next())
1466  {
1467  signal_timeout = (uint) max(query.value(0).toInt(), 250);
1468  channel_timeout = (uint) max(query.value(1).toInt(), 500);
1469  return true;
1470  }
1471 
1472  return false;
1473 }
1474 
1476 {
1477  DiSEqCDev dev;
1478  DiSEqCDevTree *diseqc_tree = dev.FindTree(inputid);
1479 
1480  bool needsConf = false;
1481  if (diseqc_tree)
1482  needsConf = diseqc_tree->IsInNeedOfConf();
1483 
1484  return needsConf;
1485 }
1486 
1487 uint CardUtil::GetQuickTuning(uint inputid, const QString &input_name)
1488 {
1489  uint quicktune = 0;
1490 
1491  MSqlQuery query(MSqlQuery::InitCon());
1492  query.prepare(
1493  "SELECT quicktune "
1494  "FROM capturecard "
1495  "WHERE cardid = :INPUTID AND "
1496  " inputname = :INPUTNAME");
1497  query.bindValue(":INPUTID", inputid);
1498  query.bindValue(":INPUTNAME", input_name);
1499 
1500  if (!query.exec() || !query.isActive())
1501  MythDB::DBError("CardUtil::GetQuickTuning()", query);
1502  else if (query.next())
1503  quicktune = query.value(0).toUInt();
1504 
1505  return quicktune;
1506 }
1507 
1508 bool CardUtil::hasV4L2(int videofd)
1509 {
1510  (void) videofd;
1511 #ifdef USING_V4L2
1512  struct v4l2_capability vcap;
1513  memset(&vcap, 0, sizeof(vcap));
1514 
1515  return ((ioctl(videofd, VIDIOC_QUERYCAP, &vcap) >= 0) &&
1516  (vcap.capabilities & V4L2_CAP_VIDEO_CAPTURE));
1517 #else // if !USING_V4L2
1518  return false;
1519 #endif // !USING_V4L2
1520 }
1521 
1523  int videofd, QString &input, QString &driver, uint32_t &version,
1524  uint32_t &capabilities)
1525 {
1526  input = driver = QString::null;
1527  version = 0;
1528  capabilities = 0;
1529 
1530  if (videofd < 0)
1531  return false;
1532 
1533 #ifdef USING_V4L2
1534  // First try V4L2 query
1535  struct v4l2_capability capability;
1536  memset(&capability, 0, sizeof(struct v4l2_capability));
1537  if (ioctl(videofd, VIDIOC_QUERYCAP, &capability) >= 0)
1538  {
1539  input = QString::fromLatin1((const char*)capability.card);
1540  driver = QString::fromLatin1((const char*)capability.driver);
1541  version = capability.version;
1542  capabilities = capability.capabilities;
1543  }
1544 #ifdef USING_V4L1
1545  else // Fallback to V4L1 query
1546  {
1547  struct video_capability capability;
1548  if (ioctl(videofd, VIDIOCGCAP, &capability) >= 0)
1549  input = QString::fromLatin1((const char*)capability.name);
1550  }
1551 #endif // USING_V4L1
1552 #endif // USING_V4L2
1553 
1554  if (!driver.isEmpty())
1555  driver.remove( QRegExp("\\[[0-9]\\]$") );
1556 
1557  return !input.isEmpty();
1558 }
1559 
1561 {
1562  (void) videofd;
1563 
1564  InputNames list;
1565  ok = false;
1566 
1567 #ifdef USING_V4L2
1568  bool usingv4l2 = hasV4L2(videofd);
1569 
1570  // V4L v2 query
1571  struct v4l2_input vin;
1572  memset(&vin, 0, sizeof(vin));
1573  while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMINPUT, &vin) >= 0))
1574  {
1575  QString input((char *)vin.name);
1576  list[vin.index] = input;
1577  vin.index++;
1578  }
1579  if (vin.index)
1580  {
1581  ok = true;
1582  return list;
1583  }
1584 
1585 #ifdef USING_V4L1
1586  // V4L v1 query
1587  struct video_capability vidcap;
1588  memset(&vidcap, 0, sizeof(vidcap));
1589  if (ioctl(videofd, VIDIOCGCAP, &vidcap) != 0)
1590  {
1591  QString msg = QObject::tr("Could not query inputs.");
1592  LOG(VB_GENERAL, LOG_ERR, "ProbeV4LVideoInputs(): Error, " + msg + ENO);
1593  list[-1] = msg;
1594  vidcap.channels = 0;
1595  }
1596 
1597  for (int i = 0; i < vidcap.channels; i++)
1598  {
1599  struct video_channel test;
1600  memset(&test, 0, sizeof(test));
1601  test.channel = i;
1602 
1603  if (ioctl(videofd, VIDIOCGCHAN, &test) != 0)
1604  {
1605  LOG(VB_GENERAL, LOG_ERR, "ProbeV4LVideoInputs(): Error, " +
1606  QString("Could determine name of input #%1"
1607  "\n\t\t\tNot adding it to the list.")
1608  .arg(test.channel) + ENO);
1609  continue;
1610  }
1611 
1612  list[i] = test.name;
1613  }
1614 #endif // USING_V4L1
1615 
1616  // Create an input when none are advertised
1617  if (list.isEmpty())
1618  list[0] = "Television";
1619 
1620  ok = true;
1621 #else // if !USING_V4L2
1622  list[-1] += QObject::tr("ERROR, Compile with V4L support to query inputs");
1623 #endif // !USING_V4L2
1624  return list;
1625 }
1626 
1628 {
1629  (void) videofd;
1630 
1631  InputNames list;
1632  ok = false;
1633 
1634 #ifdef USING_V4L2
1635  bool usingv4l2 = hasV4L2(videofd);
1636 
1637  // V4L v2 query
1638  struct v4l2_audio ain;
1639  memset(&ain, 0, sizeof(ain));
1640  while (usingv4l2 && (ioctl(videofd, VIDIOC_ENUMAUDIO, &ain) >= 0))
1641  {
1642  QString input((char *)ain.name);
1643  list[ain.index] = input;
1644  ain.index++;
1645  }
1646  if (ain.index)
1647  {
1648  ok = true;
1649  return list;
1650  }
1651 
1652  ok = true;
1653 #else // if !USING_V4L2
1654  list[-1] += QObject::tr(
1655  "ERROR, Compile with V4L support to query audio inputs");
1656 #endif // !USING_V4L2
1657  return list;
1658 }
1659 
1661 {
1662  InputNames list;
1663  MSqlQuery query(MSqlQuery::InitCon());
1664  query.prepare(
1665  "SELECT cardid, inputname "
1666  "FROM capturecard "
1667  "WHERE hostname = :HOSTNAME "
1668  " AND videodevice = :DEVICE "
1669  " AND parentid = 0 "
1670  " AND inputname <> 'None'");
1671  query.bindValue(":HOSTNAME", gCoreContext->GetHostName());
1672  query.bindValue(":DEVICE", device);
1673 
1674  if (!query.exec() || !query.isActive())
1675  MythDB::DBError("CardUtil::GetConfiguredDVBInputs", query);
1676  else
1677  {
1678  while (query.next())
1679  list[query.value(0).toUInt()] = query.value(1).toString();
1680  }
1681  return list;
1682 }
1683 
1684 QStringList CardUtil::ProbeVideoInputs(QString device, QString inputtype)
1685 {
1686  QStringList ret;
1687 
1688  if (IsSingleInputType(inputtype))
1689  ret += "MPEG2TS";
1690  else if ("DVB" == inputtype)
1691  ret += ProbeDVBInputs(device);
1692  else
1693  ret += ProbeV4LVideoInputs(device);
1694 
1695  return ret;
1696 }
1697 
1698 QStringList CardUtil::ProbeAudioInputs(QString device, QString inputtype)
1699 {
1700  LOG(VB_GENERAL, LOG_DEBUG, QString("ProbeAudioInputs(%1,%2)")
1701  .arg(device).arg(inputtype));
1702  QStringList ret;
1703 
1704  if ("HDPVR" == inputtype ||
1705  "V4L2" == inputtype)
1706  ret += ProbeV4LAudioInputs(device);
1707 
1708  return ret;
1709 }
1710 
1711 QStringList CardUtil::ProbeV4LVideoInputs(QString device)
1712 {
1713  bool ok;
1714  QStringList ret;
1715  QByteArray dev = device.toLatin1();
1716  int videofd = open(dev.constData(), O_RDWR);
1717  if (videofd < 0)
1718  {
1719  ret += QObject::tr("Could not open '%1' "
1720  "to probe its inputs.").arg(device);
1721  return ret;
1722  }
1723  InputNames list = CardUtil::ProbeV4LVideoInputs(videofd, ok);
1724  close(videofd);
1725 
1726  if (!ok)
1727  {
1728  ret += list[-1];
1729  return ret;
1730  }
1731 
1732  InputNames::iterator it;
1733  for (it = list.begin(); it != list.end(); ++it)
1734  {
1735  if (it.key() >= 0)
1736  ret += *it;
1737  }
1738 
1739  return ret;
1740 }
1741 
1742 QStringList CardUtil::ProbeV4LAudioInputs(QString device)
1743 {
1744  LOG(VB_GENERAL, LOG_DEBUG, QString("ProbeV4LAudioInputs(%1)").arg(device));
1745 
1746  bool ok;
1747  QStringList ret;
1748  int videofd = open(device.toLatin1().constData(), O_RDWR);
1749  if (videofd < 0)
1750  {
1751  LOG(VB_GENERAL, LOG_ERR, "ProbeAudioInputs() -> couldn't open device");
1752  ret += QObject::tr("Could not open '%1' to probe its inputs.")
1753  .arg(device);
1754  return ret;
1755  }
1756  InputNames list = CardUtil::ProbeV4LAudioInputs(videofd, ok);
1757  close(videofd);
1758 
1759  if (!ok)
1760  {
1761  ret += list[-1];
1762  return ret;
1763  }
1764 
1765  InputNames::iterator it;
1766  for (it = list.begin(); it != list.end(); ++it)
1767  {
1768  if (it.key() >= 0)
1769  ret += *it;
1770  }
1771 
1772  return ret;
1773 }
1774 
1775 QStringList CardUtil::ProbeDVBInputs(QString device)
1776 {
1777  QStringList ret;
1778 
1779 #ifdef USING_DVB
1780  InputNames list = GetConfiguredDVBInputs(device);
1781  InputNames::iterator it;
1782  for (it = list.begin(); it != list.end(); ++it)
1783  {
1784  if (it.key())
1785  ret += *it;
1786  }
1787 #else
1788  (void) device;
1789  ret += QObject::tr("ERROR, Compile with DVB support to query inputs");
1790 #endif
1791 
1792  return ret;
1793 }
1794 
1795 QString CardUtil::GetDeviceLabel(const QString &inputtype,
1796  const QString &videodevice)
1797 {
1798  return QString("[ %1 : %2 ]").arg(inputtype).arg(videodevice);
1799 }
1800 
1802 {
1803  QString devlabel;
1804  MSqlQuery query(MSqlQuery::InitCon());
1805  query.prepare("SELECT cardtype, videodevice "
1806  "FROM capturecard WHERE cardid = :INPUTID ");
1807  query.bindValue(":INPUTID", inputid);
1808 
1809  if (query.exec() && query.next())
1810  {
1811  return GetDeviceLabel(query.value(0).toString(),
1812  query.value(1).toString());
1813  }
1814 
1815  return "[ UNKNOWN ]";
1816 }
1817 
1819  uint inputid,
1820  const QString &device,
1821  const QString &inputtype,
1822  QStringList &inputs)
1823 {
1824  inputs.clear();
1825  if (IsSingleInputType(inputtype))
1826  inputs += "MPEG2TS";
1827  else if (inputtype == "DVB")
1828  inputs += "DVBInput";
1829  else
1830  inputs += ProbeV4LVideoInputs(device);
1831 }
1832 
1833 int CardUtil::CreateCaptureCard(const QString &videodevice,
1834  const QString &audiodevice,
1835  const QString &vbidevice,
1836  const QString &inputtype,
1837  const uint audioratelimit,
1838  const QString &hostname,
1839  const uint dvb_swfilter,
1840  const uint dvb_sat_type,
1841  bool dvb_wait_for_seqstart,
1842  bool skipbtaudio,
1843  bool dvb_on_demand,
1844  const uint dvb_diseqc_type,
1845  const uint firewire_speed,
1846  const QString &firewire_model,
1847  const uint firewire_connection,
1848  const uint signal_timeout,
1849  const uint channel_timeout,
1850  const uint dvb_tuning_delay,
1851  const uint contrast,
1852  const uint brightness,
1853  const uint colour,
1854  const uint hue,
1855  const uint diseqcid,
1856  bool dvb_eitscan)
1857 {
1858  MSqlQuery query(MSqlQuery::InitCon());
1859 
1860  query.prepare(
1861  "INSERT INTO capturecard "
1862  "(videodevice, audiodevice, vbidevice, cardtype, "
1863  "audioratelimit, hostname, dvb_swfilter, dvb_sat_type, "
1864  "dvb_wait_for_seqstart, skipbtaudio, dvb_on_demand, dvb_diseqc_type, "
1865  "firewire_speed, firewire_model, firewire_connection, signal_timeout, "
1866  "channel_timeout, dvb_tuning_delay, contrast, brightness, colour, "
1867  "hue, diseqcid, dvb_eitscan) "
1868  "VALUES (:VIDEODEVICE, :AUDIODEVICE, :VBIDEVICE, :INPUTTYPE, "
1869  ":AUDIORATELIMIT, :HOSTNAME, :DVBSWFILTER, :DVBSATTYPE, "
1870  ":DVBWAITFORSEQSTART, :SKIPBTAUDIO, :DVBONDEMAND, :DVBDISEQCTYPE, "
1871  ":FIREWIRESPEED, :FIREWIREMODEL, :FIREWIRECONNECTION, :SIGNALTIMEOUT, "
1872  ":CHANNELTIMEOUT, :DVBTUNINGDELAY, :CONTRAST, :BRIGHTNESS, :COLOUR, "
1873  ":HUE, :DISEQCID, :DVBEITSCAN ) ");
1874 
1875  query.bindValue(":VIDEODEVICE", videodevice);
1876  query.bindValue(":AUDIODEVICE", audiodevice);
1877  query.bindValue(":VBIDEVICE", vbidevice);
1878  query.bindValue(":INPUTTYPE", inputtype);
1879  query.bindValue(":AUDIORATELIMIT", audioratelimit);
1880  query.bindValue(":HOSTNAME", hostname);
1881  query.bindValue(":DVBSWFILTER", dvb_swfilter);
1882  query.bindValue(":DVBSATTYPE", dvb_sat_type);
1883  query.bindValue(":DVBWAITFORSEQSTART", dvb_wait_for_seqstart);
1884  query.bindValue(":SKIPBTAUDIO", skipbtaudio);
1885  query.bindValue(":DVBONDEMAND", dvb_on_demand);
1886  query.bindValue(":DVBDISEQCTYPE", dvb_diseqc_type);
1887  query.bindValue(":FIREWIRESPEED", firewire_speed);
1888  query.bindValue(":FIREWIREMODEL", firewire_model);
1889  query.bindValue(":FIREWIRECONNECTION", firewire_connection);
1890  query.bindValue(":SIGNALTIMEOUT", signal_timeout);
1891  query.bindValue(":CHANNELTIMEOUT", channel_timeout);
1892  query.bindValue(":DVBTUNINGDELAY", dvb_tuning_delay);
1893  query.bindValue(":CONTRAST", contrast);
1894  query.bindValue(":BRIGHTNESS", brightness);
1895  query.bindValue(":COLOUR", colour);
1896  query.bindValue(":HUE", hue);
1897  query.bindValue(":DISEQCID", diseqcid);
1898  query.bindValue(":DVBEITSCAN", dvb_eitscan);
1899 
1900  if (!query.exec())
1901  {
1902  MythDB::DBError("CreateCaptureCard", query);
1903  return -1;
1904  }
1905 
1906  query.prepare("SELECT MAX(cardid) FROM capturecard");
1907 
1908  if (!query.exec())
1909  {
1910  MythDB::DBError("CreateCaptureCard maxinput", query);
1911  return -1;
1912  }
1913 
1914  int inputid = -1; /* must be int not uint because of return type. */
1915 
1916  if (query.next())
1917  {
1918  inputid = query.value(0).toInt();
1919  uint groupid = CardUtil::CreateDeviceInputGroup(inputid, inputtype,
1920  hostname, videodevice);
1921  CardUtil::LinkInputGroup(inputid, groupid);
1922  }
1923 
1924  return inputid;
1925 }
1926 
1928 {
1929  MSqlQuery query(MSqlQuery::InitCon());
1930  bool ok = true;
1931 
1932  if (!inputid)
1933  return true;
1934 
1935  DiSEqCDevTree tree;
1936  tree.Load(inputid);
1937 
1938  // delete any clones
1939  QString rawtype = GetRawInputType(inputid);
1940  QString videodevice = GetVideoDevice(inputid);
1941  if (IsTunerSharingCapable(rawtype) && !videodevice.isEmpty())
1942  {
1943  query.prepare(
1944  "SELECT cardid "
1945  "FROM capturecard "
1946  "WHERE parentid = :INPUTID");
1947  query.bindValue(":INPUTID", inputid);
1948 
1949  if (!query.exec())
1950  {
1951  MythDB::DBError("DeleteCard -- find clone inputs", query);
1952  return false;
1953  }
1954 
1955  while (query.next())
1956  ok &= DeleteCard(query.value(0).toUInt());
1957 
1958  if (!ok)
1959  return false;
1960  }
1961 
1962  ok &= CardUtil::DeleteInput(inputid);
1963 
1964  if (!ok)
1965  return false;
1966 
1967  // actually delete the capturecard row for this input
1968  query.prepare("DELETE FROM capturecard WHERE cardid = :INPUTID");
1969  query.bindValue(":INPUTID", inputid);
1970 
1971  if (!query.exec())
1972  {
1973  MythDB::DBError("DeleteCard -- delete row", query);
1974  ok = false;
1975  }
1976 
1977  if (ok)
1978  {
1979  // Delete the diseqc tree if no more inputs reference it.
1980  if (tree.Root())
1981  {
1982  query.prepare("SELECT cardid FROM capturecard "
1983  "WHERE diseqcid = :DISEQCID LIMIT 1");
1984  query.bindValue(":DISEQCID", tree.Root()->GetDeviceID());
1985  if (!query.exec())
1986  {
1987  MythDB::DBError("DeleteCard -- find diseqc tree", query);
1988  }
1989  else if (!query.next())
1990  {
1991  tree.SetRoot(NULL);
1992  tree.Store(inputid);
1993  }
1994  }
1995 
1996  // delete any unused input groups
1997  UnlinkInputGroup(0,0);
1998  }
1999 
2000  return ok;
2001 }
2002 
2004 {
2005  MSqlQuery query(MSqlQuery::InitCon());
2006  return (query.exec("TRUNCATE TABLE inputgroup") &&
2007  query.exec("TRUNCATE TABLE diseqc_config") &&
2008  query.exec("TRUNCATE TABLE diseqc_tree") &&
2009  query.exec("TRUNCATE TABLE capturecard"));
2010 }
2011 
2012 vector<uint> CardUtil::GetInputList(void)
2013 {
2014  vector<uint> list;
2015 
2016  MSqlQuery query(MSqlQuery::InitCon());
2017  query.prepare(
2018  "SELECT cardid "
2019  "FROM capturecard "
2020  "ORDER BY cardid");
2021 
2022  if (!query.exec())
2023  MythDB::DBError("CardUtil::GetInputList()", query);
2024  else
2025  {
2026  while (query.next())
2027  list.push_back(query.value(0).toUInt());
2028  }
2029 
2030  return list;
2031 }
2032 
2034 {
2035  vector<uint> list;
2036 
2037  MSqlQuery query(MSqlQuery::InitCon());
2038  query.prepare(
2039  "SELECT DISTINCT cardid "
2040  "FROM capturecard "
2041  "WHERE schedorder <> 0 "
2042  "ORDER BY schedorder, cardid");
2043 
2044  if (!query.exec())
2045  MythDB::DBError("CardUtil::GetSchedInputList()", query);
2046  else
2047  {
2048  while (query.next())
2049  list.push_back(query.value(0).toUInt());
2050  }
2051 
2052  return list;
2053 }
2054 
2056 {
2057  vector<uint> list;
2058 
2059  MSqlQuery query(MSqlQuery::InitCon());
2060  query.prepare(
2061  "SELECT DISTINCT cardid "
2062  "FROM capturecard "
2063  "WHERE livetvorder <> 0 "
2064  "ORDER BY livetvorder, cardid");
2065 
2066  if (!query.exec())
2067  MythDB::DBError("CardUtil::GetLiveTVInputList()", query);
2068  else
2069  {
2070  while (query.next())
2071  list.push_back(query.value(0).toUInt());
2072  }
2073 
2074  return list;
2075 }
2076 
2077 QString CardUtil::GetDeviceName(dvb_dev_type_t type, const QString &device)
2078 {
2079  QString devname = QString(device);
2080 
2081  if (DVB_DEV_FRONTEND == type)
2082  return devname;
2083  else if (DVB_DEV_DVR == type)
2084  return devname.replace(devname.indexOf("frontend"), 8, "dvr");
2085  else if (DVB_DEV_DEMUX == type)
2086  return devname.replace(devname.indexOf("frontend"), 8, "demux");
2087  else if (DVB_DEV_CA == type)
2088  return devname.replace(devname.indexOf("frontend"), 8, "ca");
2089  else if (DVB_DEV_AUDIO == type)
2090  return devname.replace(devname.indexOf("frontend"), 8, "audio");
2091  else if (DVB_DEV_VIDEO == type)
2092  return devname.replace(devname.indexOf("frontend"), 8, "video");
2093 
2094  return "";
2095 }
2096 
2106 bool CardUtil::HDHRdoesDVB(const QString &device)
2107 {
2108  (void) device;
2109 
2110 #ifdef USING_HDHOMERUN
2111  hdhomerun_device_t *hdhr;
2112  hdhr = hdhomerun_device_create_from_str(device.toLatin1(), NULL);
2113  if (!hdhr)
2114  return false;
2115 
2116  const char *model = hdhomerun_device_get_model_str(hdhr);
2117  if (model && strstr(model, "dvb"))
2118  {
2119  hdhomerun_device_destroy(hdhr);
2120  return true;
2121  }
2122 
2123  hdhomerun_device_destroy(hdhr);
2124 
2125 #endif
2126 
2127  return false;
2128 }
2129 
2134 QString CardUtil::GetHDHRdesc(const QString &device)
2135 {
2136  QString connectErr = QObject::tr("Unable to connect to device.");
2137 
2138 #ifdef USING_HDHOMERUN
2139  bool deviceIsIP = false;
2140  uint32_t dev;
2141 
2142  if (device.contains('.')) // Simplistic check, but also allows DNS names
2143  deviceIsIP = true;
2144  else
2145  {
2146  bool validID;
2147 
2148  dev = device.toUInt(&validID, 16);
2149  if (!validID || !hdhomerun_discover_validate_device_id(dev))
2150  return QObject::tr("Invalid Device ID");
2151  }
2152  (void) deviceIsIP;
2153 
2154  LOG(VB_GENERAL, LOG_INFO, "CardUtil::GetHDHRdescription(" + device +
2155  ") - trying to locate device");
2156 
2157  hdhomerun_device_t *hdhr;
2158  hdhr = hdhomerun_device_create_from_str(device.toLatin1(), NULL);
2159  if (!hdhr)
2160  return QObject::tr("Invalid Device ID or address.");
2161 
2162  const char *model = hdhomerun_device_get_model_str(hdhr);
2163  if (!model)
2164  {
2165  hdhomerun_device_destroy(hdhr);
2166  return connectErr;
2167  }
2168 
2169 
2170  QString description = model;
2171  char *sVersion;
2172  uint32_t iVersion;
2173 
2174  if (hdhomerun_device_get_version(hdhr, &sVersion, &iVersion))
2175  description += QObject::tr(", firmware: %2").arg(sVersion);
2176 
2177  hdhomerun_device_destroy(hdhr);
2178 
2179  return description;
2180 #else
2181 
2182  (void) device;
2183  return connectErr;
2184 #endif
2185 }
2186 
2191 QString CardUtil::GetVBoxdesc(const QString &id, const QString &ip,
2192  const QString &tunerNo, const QString &tunerType)
2193 {
2194  QString connectErr = QObject::tr("Unable to connect to device.");
2195 
2196 #ifdef USING_VBOX
2197  VBox *vbox = new VBox(ip);
2198 
2199  if (!vbox->checkConnection())
2200  {
2201  delete vbox;
2202  return connectErr;
2203  }
2204 
2205  QString version;
2206 
2207  if (!vbox->checkVersion(version))
2208  {
2209  QString apiVersionErr = QObject::tr("The VBox software version is too old (%1), we require %2")
2210  .arg(version).arg(VBOX_MIN_API_VERSION);
2211  delete vbox;
2212  return apiVersionErr;
2213 
2214  }
2215 
2216  delete vbox;
2217 
2218  return QString("V@Box TV Gateway - ID: %1, IP: %2, Tuner: %3-%4").arg(id)
2219  .arg(ip).arg(tunerNo).arg(tunerType);
2220 
2221 #else
2222  (void) id;
2223  (void) ip;
2224  (void) tunerNo;
2225  (void) tunerType;
2226 
2227  return connectErr;
2228 #endif
2229 }
2230 
2231 #ifdef USING_ASI
2232 static QString sys_dev(uint device_num, QString dev)
2233 {
2234  return QString("/sys/class/asi/asirx%1/%2").arg(device_num).arg(dev);
2235 }
2236 
2237 static QString read_sys(QString sys_dev)
2238 {
2239  QFile f(sys_dev);
2240  f.open(QIODevice::ReadOnly);
2241  QByteArray sdba = f.readAll();
2242  f.close();
2243  return sdba;
2244 }
2245 
2246 static bool write_sys(QString sys_dev, QString str)
2247 {
2248  QFile f(sys_dev);
2249  f.open(QIODevice::WriteOnly);
2250  QByteArray ba = str.toLocal8Bit();
2251  qint64 offset = 0;
2252  for (uint tries = 0; (offset < ba.size()) && tries < 5; tries++)
2253  {
2254  qint64 written = f.write(ba.data()+offset, ba.size()-offset);
2255  if (written < 0)
2256  return false;
2257  offset += written;
2258  }
2259  return true;
2260 }
2261 #endif
2262 
2263 int CardUtil::GetASIDeviceNumber(const QString &device, QString *error)
2264 {
2265 #ifdef USING_ASI
2266  // basic confirmation
2267  struct stat statbuf;
2268  memset(&statbuf, 0, sizeof(statbuf));
2269  if (stat(device.toLocal8Bit().constData(), &statbuf) < 0)
2270  {
2271  if (error)
2272  *error = QString("Unable to stat '%1'").arg(device) + ENO;
2273  return -1;
2274  }
2275 
2276  if (!S_ISCHR(statbuf.st_mode))
2277  {
2278  if (error)
2279  *error = QString("'%1' is not a character device").arg(device);
2280  return -1;
2281  }
2282 
2283  if (!(statbuf.st_rdev & 0x0080))
2284  {
2285  if (error)
2286  *error = QString("'%1' not a DVEO ASI receiver").arg(device);
2287  return -1;
2288  }
2289 
2290  int device_num = statbuf.st_rdev & 0x007f;
2291 
2292  // extra confirmation
2293  QString sys_dev_contents = read_sys(sys_dev(device_num, "dev"));
2294  QStringList sys_dev_clist = sys_dev_contents.split(":");
2295  if (2 != sys_dev_clist.size())
2296  {
2297  if (error)
2298  {
2299  *error = QString("Unable to read '%1'")
2300  .arg(sys_dev(device_num, "dev"));
2301  }
2302  return -1;
2303  }
2304  if (sys_dev_clist[0].toUInt() != (statbuf.st_rdev>>8))
2305  {
2306  if (error)
2307  *error = QString("'%1' not a DVEO ASI device").arg(device);
2308  return -1;
2309  }
2310 
2311  return device_num;
2312 #else
2313  (void) device;
2314  if (error)
2315  *error = "Not compiled with ASI support.";
2316  return -1;
2317 #endif
2318 }
2319 
2321 {
2322 #ifdef USING_ASI
2323  // get the buffer size
2324  QString sys_bufsize_contents = read_sys(sys_dev(device_num, "bufsize"));
2325  bool ok;
2326  uint buf_size = sys_bufsize_contents.toUInt(&ok);
2327  if (!ok)
2328  {
2329  if (error)
2330  {
2331  *error = QString("Failed to read buffer size from '%1'")
2332  .arg(sys_dev(device_num, "bufsize"));
2333  }
2334  return 0;
2335  }
2336  return buf_size;
2337 #else
2338  (void) device_num;
2339  if (error)
2340  *error = "Not compiled with ASI support.";
2341  return 0;
2342 #endif
2343 }
2344 
2346 {
2347 #ifdef USING_ASI
2348  // get the buffer size
2349  QString sys_numbuffers_contents = read_sys(sys_dev(device_num, "buffers"));
2350  bool ok;
2351  uint num_buffers = sys_numbuffers_contents.toUInt(&ok);
2352  if (!ok)
2353  {
2354  if (error)
2355  {
2356  *error = QString("Failed to read num buffers from '%1'")
2357  .arg(sys_dev(device_num, "buffers"));
2358  }
2359  return 0;
2360  }
2361  return num_buffers;
2362 #else
2363  (void) device_num;
2364  if (error)
2365  *error = "Not compiled with ASI support.";
2366  return 0;
2367 #endif
2368 }
2369 
2370 int CardUtil::GetASIMode(uint device_num, QString *error)
2371 {
2372 #ifdef USING_ASI
2373  QString sys_bufsize_contents = read_sys(sys_dev(device_num, "mode"));
2374  bool ok;
2375  uint mode = sys_bufsize_contents.toUInt(&ok);
2376  if (!ok)
2377  {
2378  if (error)
2379  {
2380  *error = QString("Failed to read mode from '%1'")
2381  .arg(sys_dev(device_num, "mode"));
2382  }
2383  return -1;
2384  }
2385  return mode;
2386 #else
2387  (void) device_num;
2388  if (error)
2389  *error = "Not compiled with ASI support.";
2390  return -1;
2391 #endif
2392 }
2393 
2394 bool CardUtil::SetASIMode(uint device_num, uint mode, QString *error)
2395 {
2396 #ifdef USING_ASI
2397  QString sys_bufsize_contents = read_sys(sys_dev(device_num, "mode"));
2398  bool ok;
2399  uint old_mode = sys_bufsize_contents.toUInt(&ok);
2400  if (ok && old_mode == mode)
2401  return true;
2402  ok = write_sys(sys_dev(device_num, "mode"), QString("%1\n").arg(mode));
2403  if (!ok && error)
2404  {
2405  *error = QString("Failed to set mode to %1 using '%2'")
2406  .arg(mode).arg(sys_dev(device_num, "mode"));
2407  }
2408  return ok;
2409 #else
2410  (void) device_num;
2411  if (error)
2412  *error = "Not compiled with ASI support.";
2413  return false;
2414 #endif
2415 }
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:785
uint scheduleOrder
Definition: inputinfo.h:77
dvb_dev_type_t
Definition: cardutil.h:29
static bool IsTunerSharingCapable(const QString &rawtype)
Definition: cardutil.h:163
static bool HasDVBCRCBug(const QString &device)
Returns true if and only if the device munges PAT/PMT tables, and then doesn&#39;t fix the CRC...
Definition: cardutil.cpp:553
int recPriority
Definition: inputinfo.h:76
static QStringList ProbeVideoDevices(const QString &rawtype)
Definition: cardutil.cpp:348
void bindValue(const QString &placeholder, const QVariant &val)
Definition: mythdbcon.cpp:884
DVB-S device settings class.
Definition: diseqc.h:37
__u8 driver[16]
Definition: videodev2.h:386
static QString GetInputName(uint inputid)
Definition: cardutil.cpp:1046
DiSEqCDevDevice * Root(void)
Retrieves the root node in the tree.
Definition: diseqc.h:94
static uint GetASINumBuffers(uint device_num, QString *error=NULL)
Definition: cardutil.cpp:2345
static bool IsTunerShared(uint inputidA, uint inputidB)
Definition: cardutil.cpp:181
DiSEqCDevTree * FindTree(uint cardid)
Retrieve device tree.
Definition: diseqc.cpp:248
__u32 index
Definition: videodev2.h:1369
static const int kTunerTypeDVBT
static bool SetStartChannel(uint inputid, const QString &channum)
Definition: cardutil.cpp:954
static QStringList GetVideoDevices(const QString &rawtype, QString hostname=QString::null)
Returns the videodevices of the matching inputs, duplicates removed.
Definition: cardutil.cpp:305
uint GetDeviceID(void) const
Definition: diseqc.h:164
static uint CreateInputGroup(const QString &name)
Definition: cardutil.cpp:1211
static QString ProbeDVBType(const QString &device)
Definition: cardutil.cpp:457
static vector< uint > GetInputIDs(QString videodevice=QString::null, QString rawtype=QString::null, QString inputname=QString::null, QString hostname=QString::null)
Returns all inputids of inputs that uses the specified videodevice if specified, and optionally rawty...
Definition: cardutil.cpp:638
static vector< uint > GetConflictingInputs(uint inputid)
Definition: cardutil.cpp:1413
static QString GetDeviceLabel(const QString &inputtype, const QString &videodevice)
Definition: cardutil.cpp:1795
static QString ProbeSubTypeName(uint inputid)
Definition: cardutil.cpp:570
static void error(const char *str,...)
Definition: vbi.c:41
static int CreateCaptureCard(const QString &videodevice, const QString &audiodevice, const QString &vbidevice, const QString &inputtype, const uint audioratelimit, const QString &hostname, const uint dvb_swfilter, const uint dvb_sat_type, bool dvb_wait_for_seqstart, bool skipbtaudio, bool dvb_on_demand, const uint dvb_diseqc_type, const uint firewire_speed, const QString &firewire_model, const uint firewire_connection, const uint signal_timeout, const uint channel_timeout, const uint dvb_tuning_delay, const uint contrast, const uint brightness, const uint colour, const uint hue, const uint diseqcid, bool dvb_eitscan)
Definition: cardutil.cpp:1833
uint sourceid
associated channel listings source
Definition: inputinfo.h:71
bool IsInNeedOfConf(void) const
Definition: diseqc.cpp:846
bool checkVersion(QString &version)
Definition: vboxutils.cpp:220
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
Definition: vboxutils.h:13
static QString ProbeDVBFrontendName(const QString &device)
Returns the input type from the video device.
Definition: cardutil.cpp:507
static QStringList ProbeDVBInputs(QString device)
Definition: cardutil.cpp:1775
static bool IsInNeedOfExternalInputConf(uint inputid)
Definition: cardutil.cpp:1475
static bool write_sys(QString sys_dev, QString str)
Definition: cardutil.cpp:2246
__u8 name[32]
Definition: videodev2.h:1673
QMap< QString, QString > InputTypes
Definition: cardutil.h:45
unsigned int uint
Definition: compat.h:136
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
static bool GetInputInfo(InputInfo &info, vector< uint > *groupids=NULL)
Definition: cardutil.cpp:972
static vector< uint > GetSchedInputList(void)
Definition: cardutil.cpp:2033
bool set_on_input(const QString &to_set, uint inputid, const QString &value)
Definition: cardutil.cpp:609
static bool DeleteInput(uint inputid)
Definition: cardutil.cpp:1170
static const int kTunerTypeDVBS1
static bool HasTuner(const QString &rawtype, const QString &device)
Definition: cardutil.cpp:158
bool Load(uint card_input_id)
Loads configuration chain from DB for specified card input id.
Definition: diseqc.cpp:137
bool Store(uint cardid, const QString &device="")
Stores the device tree to the database.
Definition: diseqc.cpp:434
__u32 type
Definition: videodev2.h:1038
static QString sys_dev(uint device_num, QString dev)
Definition: cardutil.cpp:2232
static bool GetV4LInfo(int videofd, QString &input, QString &driver, uint32_t &version, uint32_t &capabilities)
Definition: cardutil.cpp:1522
static vector< uint > GetLiveTVInputList(void)
Definition: cardutil.cpp:2055
static bool GetTimeouts(uint inputid, uint &signal_timeout, uint &channel_timeout)
Definition: cardutil.cpp:1453
QVariant value(int i) const
Definition: mythdbcon.h:182
static QString GetVBoxdesc(const QString &id, const QString &ip, const QString &tunerNo, const QString &tunerType)
Get a nicely formatted string describing the device.
Definition: cardutil.cpp:2191
QString displayName
Definition: inputinfo.h:75
voidpf uLong offset
Definition: ioapi.h:142
static const int kTunerTypeDVBS2
static QStringList ProbeAudioInputs(QString device, QString inputtype=QString::null)
Definition: cardutil.cpp:1698
const char * name
Definition: ParseText.cpp:338
static const int kTunerTypeDVBT2
struct v4l2_capability - Describes V4L2 device caps returned by VIDIOC_QUERYCAP
Definition: videodev2.h:385
static InputNames ProbeV4LAudioInputs(int videofd, bool &ok)
Definition: cardutil.cpp:1627
void SetRoot(DiSEqCDevDevice *root)
Changes the root node of the tree.
Definition: diseqc.cpp:647
static bool IsDVBInputType(const QString &input_type)
Returns true iff the input_type is one of the DVB types.
Definition: cardutil.cpp:585
uint livetvorder
order for live TV use
Definition: inputinfo.h:78
static bool IsSingleInputType(const QString &rawtype)
Definition: cardutil.h:197
unsigned char t
Definition: ParseText.cpp:339
__u8 card[32]
Definition: videodev2.h:387
static QString GetDeviceName(dvb_dev_type_t, const QString &device)
Definition: cardutil.cpp:2077
static bool IsCableCardPresent(uint inputid, const QString &inputType)
Definition: cardutil.cpp:114
static uint GetDeviceInputGroup(uint inputid)
Definition: cardutil.cpp:1265
bool isActive(void) const
Definition: mythdbcon.h:188
bool Store(uint card_input_id) const
Stores configuration chain to DB for specified card input id.
Definition: diseqc.cpp:171
static QString GetFirewireChangerModel(uint inputid)
Definition: cardutil.cpp:913
string hostname
Definition: caa.py:17
static vector< uint > GetGroupInputIDs(uint inputgroupid)
Definition: cardutil.cpp:1386
static vector< uint > GetChildInputIDs(uint inputid)
Definition: cardutil.cpp:706
static bool UnlinkInputGroup(uint inputid, uint inputgroupid)
Definition: cardutil.cpp:1329
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:542
static QList< InputInfo > GetAllInputInfo()
Definition: cardutil.cpp:1012
static InputNames GetConfiguredDVBInputs(const QString &device)
Definition: cardutil.cpp:1660
static uint GetQuickTuning(uint inputid, const QString &inputname)
Definition: cardutil.cpp:1487
static bool HDHRdoesDVB(const QString &device)
If the device is valid, check if the model does DVB.
Definition: cardutil.cpp:2106
__u32 index
Definition: videodev2.h:1672
static uint GetASIBufferSize(uint device_num, QString *error=NULL)
Definition: cardutil.cpp:2320
uint inputid
unique key in DB for this input
Definition: inputinfo.h:72
static int GetASIDeviceNumber(const QString &device, QString *error=NULL)
Definition: cardutil.cpp:2263
static QStringList ProbeVideoInputs(QString device, QString inputtype=QString::null)
Definition: cardutil.cpp:1684
static bool SetASIMode(uint device_num, uint mode, QString *error=NULL)
Definition: cardutil.cpp:2394
static bool CloneCard(uint src_inputid, uint dst_inputid)
Definition: cardutil.cpp:883
static vector< uint > GetInputList(void)
Definition: cardutil.cpp:2012
bool Load(const QString &device)
Definition: diseqc.cpp:331
static QString GetFirewireChangerNode(uint inputid)
Definition: cardutil.cpp:896
static QString GetVideoDevice(uint inputid)
Definition: cardutil.h:273
static QStringList probeDevices(void)
Definition: vboxutils.cpp:36
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:810
bool quickTune
Definition: inputinfo.h:79
static uint GetChildInputCount(uint inputid)
Definition: cardutil.cpp:682
__u32 capabilities
Definition: videodev2.h:1045
bool HasTuner(void) const
Definition: v4l2util.cpp:698
QString name
input name
Definition: inputinfo.h:70
__u8 name[32]
Definition: videodev2.h:1370
static uint clone_capturecard(uint src_inputid, uint orig_dst_inputid)
Definition: cardutil.cpp:734
static int CreateCardInput(const uint inputid, const uint sourceid, const QString &inputname, const QString &externalcommand, const QString &changer_device, const QString &changer_model, const QString &hostname, const QString &tunechan, const QString &startchan, const QString &displayname, bool dishnet_eit, const uint recpriority, const uint quicktune, const uint schedorder, const uint livetvorder)
Definition: cardutil.cpp:1110
QString get_on_input(const QString &to_get, uint inputid)
Definition: cardutil.cpp:592
static bool DeleteCard(uint inputid)
Definition: cardutil.cpp:1927
QMap< int, QString > InputNames
Definition: cardutil.h:22
static const QString LOC
static uint GetSourceID(uint inputid)
Definition: cardutil.cpp:1094
static bool hasV4L2(int videofd)
Definition: cardutil.cpp:1508
const char int mode
Definition: ioapi.h:135
static QString GetRawInputType(uint inputid)
Definition: cardutil.h:271
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:610
bool checkConnection(void)
Definition: vboxutils.cpp:214
static bool LinkInputGroup(uint inputid, uint inputgroupid)
Definition: cardutil.cpp:1289
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:181
static bool DeleteAllCards(void)
Definition: cardutil.cpp:2003
QString GetHostName(void)
static InputTypes GetInputTypes(void)
Definition: cardutil.cpp:262
DVB-S device tree class.
Definition: diseqc.h:75
QString DriverName(void) const
Definition: v4l2util.h:45
static InputNames ProbeV4LVideoInputs(int videofd, bool &ok)
Definition: cardutil.cpp:1560
__u32 capabilities
Definition: videodev2.h:390
static int GetASIMode(uint device_num, QString *error=NULL)
Definition: cardutil.cpp:2370
static bool IsInputTypePresent(const QString &rawtype, QString hostname=QString::null)
Returns true if the input type is present and connected to an input.
Definition: cardutil.cpp:228
__s32 value
Definition: videodev2.h:1042
static QString GetHDHRdesc(const QString &device)
Get a nicely formatted string describing the device.
Definition: cardutil.cpp:2134
static QString GetScanableInputTypes(void)
Definition: cardutil.cpp:55
static vector< uint > GetInputGroups(uint inputid)
Definition: cardutil.cpp:1360
QString toString() const
static uint GetMinSignalMonitoringDelay(const QString &device)
Definition: cardutil.cpp:560
static uint CreateDeviceInputGroup(uint inputid, const QString &type, const QString &host, const QString &device)
Definition: cardutil.cpp:1253
static QString GetStartingChannel(uint inputid)
Definition: cardutil.cpp:1053
Main DVB-S device interface.
Definition: diseqc.h:52
static void GetDeviceInputNames(uint inputid, const QString &device, const QString &inputtype, QStringList &inputs)
Definition: cardutil.cpp:1818
static QString read_sys(QString sys_dev)
Definition: cardutil.cpp:2237
static QString GetDisplayName(uint inputid)
Definition: cardutil.cpp:1069