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