c8188cb8b1
- Add support_for_sundtek_tv_tuners.patch: add support for Sundtek (local and networkbased) TV devices (boo#827097) OBS-URL: https://build.opensuse.org/request/show/314531 OBS-URL: https://build.opensuse.org/package/show/KDE:Extra/kaffeine?expand=0&rev=4
316 lines
12 KiB
Diff
316 lines
12 KiB
Diff
From: Jonathan Riddell <jr@jriddell.org>
|
|
Date: Wed, 03 Dec 2014 14:23:17 +0000
|
|
Subject: Support for Sundtek TV Tuners (Networkbased and local devices)
|
|
X-Git-Url: http://quickgit.kde.org/?p=kaffeine.git&a=commitdiff&h=333ba6c927df747b61d8ba25b097741ac353dfc2
|
|
---
|
|
Support for Sundtek TV Tuners (Networkbased and local devices)
|
|
|
|
The attached patch only adds support for our new tuners which can be
|
|
network based or locally. Due the different architecture there is no
|
|
need for additional kernel drivers.
|
|
|
|
The change does not affect legacy devices.
|
|
|
|
by Markus Rechberger kontakt@sundtek.de
|
|
|
|
REVIEW:120583
|
|
---
|
|
|
|
|
|
--- a/src/dvb/dvbdevice_linux.cpp
|
|
+++ b/src/dvb/dvbdevice_linux.cpp
|
|
@@ -29,7 +29,15 @@
|
|
#include <fcntl.h>
|
|
#include <frontend.h>
|
|
#include <poll.h>
|
|
+#include <sys/socket.h>
|
|
+#include <sys/un.h>
|
|
+#include <sys/types.h>
|
|
#include <sys/ioctl.h>
|
|
+#include <sys/stat.h>
|
|
+#include <dirent.h>
|
|
+#include <sys/inotify.h>
|
|
+#include <vector>
|
|
+#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include "dvbtransponder.h"
|
|
|
|
@@ -808,15 +816,179 @@
|
|
}
|
|
}
|
|
|
|
+struct dvbdev {
|
|
+ time_t stctime;
|
|
+ char checked;
|
|
+ char adapter_name[50];
|
|
+ char node_name[75];
|
|
+ int adapternum;
|
|
+ char lnode[20];
|
|
+};
|
|
+
|
|
+class DvbDeviceMonitor : public QThread
|
|
+{
|
|
+public:
|
|
+ DvbDeviceMonitor(DvbLinuxDeviceManager *ddm)
|
|
+ {
|
|
+ this->ddm = ddm;
|
|
+ }
|
|
+ ~DvbDeviceMonitor()
|
|
+ {
|
|
+ }
|
|
+ void run() {
|
|
+ DIR *dvbdir, *adapterdirp;
|
|
+ struct dirent *dp, *dp2;
|
|
+ struct stat stbuf;
|
|
+ int adapter;
|
|
+ int rescan=0;
|
|
+ int rv;
|
|
+ int ifd;
|
|
+ int found=0;
|
|
+ char adapterdir[50];
|
|
+ char nodename[75];
|
|
+ char buffer[1024];
|
|
+ struct pollfd pfd;
|
|
+ char firstrun_complete=0;
|
|
+ std::vector<struct dvbdev*>adapterlist;
|
|
+ std::vector<struct dvbdev*>::iterator iter;
|
|
+
|
|
+ runstate = 1;
|
|
+
|
|
+ ifd = inotify_init();
|
|
+ inotify_add_watch(ifd, "/dev/dvb", IN_CREATE|IN_DELETE);
|
|
+ fcntl(ifd, F_SETFL, O_NONBLOCK);
|
|
+ pfd.fd = ifd;
|
|
+ pfd.events = POLLIN;
|
|
+
|
|
+ while(runstate) {
|
|
+ if (firstrun_complete) {
|
|
+ rv = poll(&pfd, 1, 100);
|
|
+ switch (rv) {
|
|
+ case -1:
|
|
+ break;
|
|
+ case 0:
|
|
+ continue;
|
|
+ default:
|
|
+ usleep(100000); /* give it some time to settle down */
|
|
+ while(read(ifd, buffer, 1024)>0);
|
|
+ break;
|
|
+ }
|
|
+ } else {
|
|
+ firstrun_complete=1;
|
|
+ }
|
|
+
|
|
+ dvbdir = opendir("/dev/dvb");
|
|
+ for (iter=adapterlist.begin();iter!=adapterlist.end();iter++) {
|
|
+ (*iter)->checked=0;
|
|
+ }
|
|
+ if (dvbdir) {
|
|
+ while((dp=readdir(dvbdir))!= 0) {
|
|
+ if (strcmp(dp->d_name, ".") == 0 ||
|
|
+ strcmp(dp->d_name, "..") == 0)
|
|
+ continue;
|
|
+ adapter = strtol(&dp->d_name[7], NULL, 10);
|
|
+ sprintf(adapterdir, "/dev/dvb/%s", dp->d_name);
|
|
+ adapterdirp = opendir(adapterdir);
|
|
+ if (adapterdirp) {
|
|
+ while((dp2=readdir(adapterdirp))!=0) {
|
|
+ found=0;
|
|
+ if (strcmp(dp2->d_name, ".")==0 ||
|
|
+ strcmp(dp2->d_name, "..")==0)
|
|
+ continue;
|
|
+ sprintf(nodename, "/dev/dvb/%s/%s", dp->d_name, dp2->d_name);
|
|
+ rv = stat(nodename, &stbuf);
|
|
+ for (iter=adapterlist.begin();iter!=adapterlist.end();iter++) {
|
|
+ if (strcmp((*iter)->node_name, nodename)==0 && (*iter)->stctime == stbuf.st_ctime) {
|
|
+ (*iter)->checked=1;
|
|
+ found=1;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ if (found == 0) {
|
|
+ struct dvbdev *dvbdev = (struct dvbdev*)calloc(1, sizeof(struct dvbdev));
|
|
+ dvbdev->checked=1;
|
|
+ dvbdev->stctime = stbuf.st_ctime;
|
|
+ strcpy(dvbdev->adapter_name, dp->d_name);
|
|
+ strcpy(dvbdev->node_name, nodename);
|
|
+ dvbdev->adapternum = adapter;
|
|
+ strcpy(dvbdev->lnode, dp2->d_name);
|
|
+ adapterlist.push_back(dvbdev);
|
|
+ ddm->componentAdded(dp2->d_name, adapter, 0);
|
|
+ }
|
|
+
|
|
+ }
|
|
+ closedir(adapterdirp);
|
|
+ }
|
|
+ }
|
|
+ closedir(dvbdir);
|
|
+ }
|
|
+ do {
|
|
+ rescan=0;
|
|
+ for (iter=adapterlist.begin();iter!=adapterlist.end();iter++) {
|
|
+ if ((*iter)->checked==0) {
|
|
+ ddm->componentRemoved((*iter)->lnode, (*iter)->adapternum, 0);
|
|
+ free(*iter);
|
|
+ adapterlist.erase(iter);
|
|
+ rescan=1;
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+ } while (rescan!=0);
|
|
+ }
|
|
+ }
|
|
+ void stop() {
|
|
+ runstate = 0;
|
|
+ wait();
|
|
+ }
|
|
+private:
|
|
+ int runstate;
|
|
+ DvbLinuxDeviceManager *ddm;
|
|
+};
|
|
+
|
|
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__sun)
|
|
+#define MACHADDRESS "/tmp/.mediasocket"
|
|
+#else
|
|
+#define ADDRESS "/de/sundtek/mediasocket" /* addr to connect */
|
|
+#endif
|
|
+
|
|
DvbLinuxDeviceManager::DvbLinuxDeviceManager(QObject *parent) : QObject(parent)
|
|
{
|
|
+ int fd;
|
|
+ int len;
|
|
+ int ret;
|
|
+ struct sockaddr_un saun;
|
|
QObject *notifier = Solid::DeviceNotifier::instance();
|
|
connect(notifier, SIGNAL(deviceAdded(QString)), this, SLOT(componentAdded(QString)));
|
|
connect(notifier, SIGNAL(deviceRemoved(QString)), this, SLOT(componentRemoved(QString)));
|
|
+
|
|
+ memset(&saun, 0x0, sizeof(struct sockaddr_un));
|
|
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
+ if (fd==-1) {
|
|
+ monitor = NULL;
|
|
+ return;
|
|
+ }
|
|
+ saun.sun_family = AF_UNIX;
|
|
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__sun)
|
|
+ strcpy(saun.sun_path, MACHADDRESS);
|
|
+ len = sizeof(saun.sun_family) + strlen(saun.sun_path)+1;
|
|
+#else
|
|
+ strcpy(&saun.sun_path[1], ADDRESS);
|
|
+ len = sizeof(saun.sun_family) + strlen(&saun.sun_path[1])+1;
|
|
+#endif
|
|
+ if ((ret=::connect(fd, (struct sockaddr*)&saun, len)) < 0) {
|
|
+ close(fd);
|
|
+ monitor = NULL;
|
|
+ return;
|
|
+ }
|
|
+ close(fd);
|
|
+ monitor = new DvbDeviceMonitor(this);
|
|
+ monitor->start();
|
|
}
|
|
|
|
DvbLinuxDeviceManager::~DvbLinuxDeviceManager()
|
|
{
|
|
+ if (monitor)
|
|
+ monitor->stop();
|
|
}
|
|
|
|
void DvbLinuxDeviceManager::doColdPlug()
|
|
@@ -824,6 +996,36 @@
|
|
foreach (const Solid::Device &device,
|
|
Solid::Device::listFromType(Solid::DeviceInterface::DvbInterface)) {
|
|
componentAdded(device.udi());
|
|
+ }
|
|
+}
|
|
+
|
|
+void DvbLinuxDeviceManager::componentAdded(QString node, int adapter, int index) {
|
|
+ int deviceIndex = (adapter << 16) | index;
|
|
+ char adapterstring[10];
|
|
+ DvbLinuxDevice *device = devices.value(deviceIndex, NULL);
|
|
+ if (device == NULL) {
|
|
+ device = new DvbLinuxDevice(this);
|
|
+ devices.insert(deviceIndex, device);
|
|
+ }
|
|
+ sprintf(adapterstring, "adapter%d", adapter);
|
|
+
|
|
+ if (node == "frontend0") {
|
|
+ device->frontendPath.sprintf("/dev/dvb/%s/%s", adapterstring, node.toAscii().data());
|
|
+ } else if (node == "dvr0") {
|
|
+ device->dvrPath.sprintf("/dev/dvb/%s/%s", adapterstring, node.toAscii().data());
|
|
+ } else if (node == "demux0") {
|
|
+ device->demuxPath.sprintf("/dev/dvb/%s/%s", adapterstring, node.toAscii().data());
|
|
+ } else {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (!device->demuxPath.isEmpty() && !device->dvrPath.isEmpty() &&
|
|
+ !device->frontendPath.isEmpty()) {
|
|
+ device->startDevice("");
|
|
+
|
|
+ if (device->isReady()) {
|
|
+ emit deviceAdded(device);
|
|
+ }
|
|
}
|
|
}
|
|
|
|
@@ -941,6 +1143,31 @@
|
|
if (device->isReady()) {
|
|
emit deviceAdded(device);
|
|
}
|
|
+ }
|
|
+}
|
|
+
|
|
+void DvbLinuxDeviceManager::componentRemoved(QString node, int adapter, int index) {
|
|
+ int deviceIndex = (adapter << 16) | index;
|
|
+ char adapterstring[10];
|
|
+ DvbLinuxDevice *device = devices.value(deviceIndex, NULL);
|
|
+ if (device == NULL) {
|
|
+ return;
|
|
+ }
|
|
+ sprintf(adapterstring, "adapter%d", adapter);
|
|
+ if (node == "frontend0") {
|
|
+ device->frontendPath.clear();
|
|
+ } else if (node == "dvr0") {
|
|
+ device->dvrPath.clear();
|
|
+ } else if (node == "demux0") {
|
|
+ device->demuxPath.clear();
|
|
+ } else {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ if (device->frontendPath.isEmpty() && device->dvrPath.isEmpty() &&
|
|
+ device->demuxPath.isEmpty() && device->isReady()) {
|
|
+ emit deviceRemoved(device);
|
|
+ device->stopDevice();
|
|
}
|
|
}
|
|
|
|
|
|
--- a/src/dvb/dvbdevice_linux.h
|
|
+++ b/src/dvb/dvbdevice_linux.h
|
|
@@ -90,6 +90,7 @@
|
|
DvbLinuxCam cam;
|
|
};
|
|
|
|
+class DvbDeviceMonitor;
|
|
class DvbLinuxDeviceManager : public QObject
|
|
{
|
|
Q_OBJECT
|
|
@@ -97,6 +98,8 @@
|
|
explicit DvbLinuxDeviceManager(QObject *parent);
|
|
~DvbLinuxDeviceManager();
|
|
|
|
+ void componentAdded(QString node, int adapter, int index);
|
|
+ void componentRemoved(QString node, int adapter, int index);
|
|
public slots:
|
|
void doColdPlug();
|
|
|
|
@@ -114,6 +117,7 @@
|
|
|
|
QMap<int, DvbLinuxDevice *> devices;
|
|
QMap<QString, DvbLinuxDevice *> udis;
|
|
+ class DvbDeviceMonitor *monitor;
|
|
};
|
|
|
|
#endif /* DVBDEVICE_LINUX_H */
|
|
|