kaffeine/support_for_sundtek_tv_tuners.patch
Hrvoje Senjan c8188cb8b1 Accepting request 314531 from home:wolfi323:branches:KDE:Extra
- 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
2015-06-30 18:08:38 +00:00

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 */