linuxdvb: added dynamic and combi DVB tuner support
I have also simplified the hardware tree. Though I still need to resolve some minor issues related to adapter ID'ing.
This commit is contained in:
parent
517af478ab
commit
96b4b22312
17 changed files with 483 additions and 649 deletions
1
Makefile
1
Makefile
|
@ -186,7 +186,6 @@ SRCS-$(CONFIG_MPEGTS) += \
|
|||
# DVB
|
||||
SRCS-${CONFIG_LINUXDVB} += \
|
||||
src/input/mpegts/linuxdvb/linuxdvb.c \
|
||||
src/input/mpegts/linuxdvb/linuxdvb_device.c \
|
||||
src/input/mpegts/linuxdvb/linuxdvb_adapter.c \
|
||||
src/input/mpegts/linuxdvb/linuxdvb_frontend.c \
|
||||
src/input/mpegts/linuxdvb/linuxdvb_network.c \
|
||||
|
|
|
@ -230,6 +230,12 @@ idnode_uuid_as_str(const idnode_t *in)
|
|||
p = (p + 1) % 16;
|
||||
return idnode_uuid_as_str0(in, b);
|
||||
}
|
||||
const char *
|
||||
idnode_uuid_as_str1 ( const uint8_t *bin, size_t len, char *b )
|
||||
{
|
||||
bin2hex(b, UUID_STR_LEN, bin, len);
|
||||
return b;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
|
|
|
@ -114,6 +114,7 @@ int idnode_insert(idnode_t *in, const char *uuid, const idclass_t *idc);
|
|||
void idnode_unlink(idnode_t *in);
|
||||
|
||||
uint32_t idnode_get_short_uuid (const idnode_t *in);
|
||||
const char *idnode_uuid_as_str1 (const uint8_t *bin, size_t len, char *b);
|
||||
const char *idnode_uuid_as_str0 (const idnode_t *in, char *b);
|
||||
const char *idnode_uuid_as_str (const idnode_t *in);
|
||||
idnode_set_t *idnode_get_childs (idnode_t *in);
|
||||
|
|
42
src/input.c
42
src/input.c
|
@ -17,10 +17,52 @@
|
|||
*/
|
||||
|
||||
#include "input.h"
|
||||
#include "notify.h"
|
||||
|
||||
tvh_input_list_t tvh_inputs;
|
||||
tvh_hardware_list_t tvh_hardware;
|
||||
|
||||
/*
|
||||
* Create entry
|
||||
*/
|
||||
void *
|
||||
tvh_hardware_create0
|
||||
( void *o, const idclass_t *idc, const char *uuid, htsmsg_t *conf )
|
||||
{
|
||||
tvh_hardware_t *th = o;
|
||||
|
||||
/* Create node */
|
||||
if (idnode_insert(&th->th_id, uuid, idc)) {
|
||||
free(o);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Update list */
|
||||
LIST_INSERT_HEAD(&tvh_hardware, th, th_link);
|
||||
|
||||
/* Load config */
|
||||
if (conf)
|
||||
idnode_load(&th->th_id, conf);
|
||||
|
||||
/* Update */
|
||||
notify_reload("hardware");
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
/*
|
||||
* Delete hardware entry
|
||||
*/
|
||||
|
||||
void
|
||||
tvh_hardware_delete ( tvh_hardware_t *th )
|
||||
{
|
||||
// TODO
|
||||
LIST_REMOVE(th, th_link);
|
||||
idnode_unlink(&th->th_id);
|
||||
notify_reload("hardware");
|
||||
}
|
||||
|
||||
/*
|
||||
* Input status handling
|
||||
*/
|
||||
|
|
|
@ -78,6 +78,9 @@ struct tvh_hardware {
|
|||
LIST_ENTRY(tvh_hardware) th_link;
|
||||
};
|
||||
|
||||
void *tvh_hardware_create0
|
||||
( void *o, const idclass_t *idc, const char *uuid, htsmsg_t *conf );
|
||||
void tvh_hardware_delete ( tvh_hardware_t *th );
|
||||
|
||||
/*
|
||||
* Class and Global list defs
|
||||
|
|
|
@ -222,7 +222,7 @@ typedef struct dvb_mux_conf
|
|||
polarisation_t dmc_fe_polarisation;
|
||||
int dmc_fe_orbital_pos;
|
||||
char dmc_fe_orbital_dir;
|
||||
#if DVB_API_VERSION >= 5
|
||||
#if DVB_VER_ATLEAST(5,0)
|
||||
fe_modulation_t dmc_fe_modulation;
|
||||
fe_delivery_system_t dmc_fe_delsys;
|
||||
fe_rolloff_t dmc_fe_rolloff;
|
||||
|
@ -270,6 +270,10 @@ int dvb_str2pilot ( const char *str );
|
|||
|
||||
int dvb_bandwidth ( enum fe_bandwidth bw );
|
||||
|
||||
#if DVB_VER_ATLEAST(5,10)
|
||||
int dvb_delsys2type ( enum fe_delivery_system ds );
|
||||
#endif
|
||||
|
||||
#endif /* ENABLE_DVBAPI */
|
||||
|
||||
#endif /* DVB_SUPPORT_H */
|
||||
|
|
|
@ -421,6 +421,33 @@ const static struct strtab delsystab[] = {
|
|||
};
|
||||
dvb_str2val(delsys);
|
||||
|
||||
#if DVB_VER_ATLEAST(5,10)
|
||||
int
|
||||
dvb_delsys2type ( fe_delivery_system_t delsys )
|
||||
{
|
||||
switch (delsys) {
|
||||
case SYS_DVBC_ANNEX_AC:
|
||||
case SYS_DVBC_ANNEX_B:
|
||||
case SYS_ISDBC:
|
||||
return FE_QAM;
|
||||
case SYS_DVBT:
|
||||
case SYS_DVBT2:
|
||||
case SYS_TURBO:
|
||||
case SYS_ISDBT:
|
||||
return FE_OFDM;
|
||||
case SYS_DVBS:
|
||||
case SYS_DVBS2:
|
||||
case SYS_ISDBS:
|
||||
return FE_QPSK;
|
||||
case SYS_ATSC:
|
||||
case SYS_ATSCMH:
|
||||
return FE_ATSC;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const static struct strtab fectab[] = {
|
||||
{ "NONE", FEC_NONE },
|
||||
{ "1/2", FEC_1_2 },
|
||||
|
|
|
@ -36,5 +36,5 @@ void linuxdvb_init ( int adapter_mask )
|
|||
linuxdvb_network_init();
|
||||
|
||||
/* Initialsie devices */
|
||||
linuxdvb_device_init(adapter_mask);
|
||||
linuxdvb_adapter_init();
|
||||
}
|
||||
|
|
|
@ -21,17 +21,21 @@
|
|||
#include "input.h"
|
||||
#include "linuxdvb_private.h"
|
||||
#include "queue.h"
|
||||
#include "fsmonitor.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <openssl/sha.h>
|
||||
|
||||
#define FE_PATH "/dev/dvb/adapter%d/frontend%d"
|
||||
#define DVR_PATH "/dev/dvb/adapter%d/dvr%d"
|
||||
#define DMX_PATH "/dev/dvb/adapter%d/demux%d"
|
||||
#define FE_PATH "%s/frontend%d"
|
||||
#define DVR_PATH "%s/dvr%d"
|
||||
#define DMX_PATH "%s/demux%d"
|
||||
|
||||
/* ***************************************************************************
|
||||
* DVB Adapter
|
||||
|
@ -41,7 +45,7 @@ static void
|
|||
linuxdvb_adapter_class_save ( idnode_t *in )
|
||||
{
|
||||
linuxdvb_adapter_t *la = (linuxdvb_adapter_t*)in;
|
||||
linuxdvb_device_save(la->la_device);
|
||||
linuxdvb_adapter_save(la);
|
||||
}
|
||||
|
||||
static idnode_set_t *
|
||||
|
@ -85,141 +89,114 @@ const idclass_t linuxdvb_adapter_class =
|
|||
* Save data
|
||||
*/
|
||||
void
|
||||
linuxdvb_adapter_save ( linuxdvb_adapter_t *la, htsmsg_t *m )
|
||||
linuxdvb_adapter_save ( linuxdvb_adapter_t *la )
|
||||
{
|
||||
htsmsg_t *l;
|
||||
htsmsg_t *m, *l;
|
||||
linuxdvb_frontend_t *lfe;
|
||||
|
||||
idnode_save(&la->la_id, m);
|
||||
htsmsg_add_u32(m, "number", la->la_number);
|
||||
m = htsmsg_create_map();
|
||||
idnode_save(&la->th_id, m);
|
||||
|
||||
/* Frontends */
|
||||
l = htsmsg_create_map();
|
||||
LIST_FOREACH(lfe, &la->la_frontends, lfe_link) {
|
||||
htsmsg_t *e = htsmsg_create_map();
|
||||
linuxdvb_frontend_save(lfe, e);
|
||||
htsmsg_add_msg(l, idnode_uuid_as_str(&lfe->ti_id), e);
|
||||
}
|
||||
LIST_FOREACH(lfe, &la->la_frontends, lfe_link)
|
||||
linuxdvb_frontend_save(lfe, l);
|
||||
htsmsg_add_msg(m, "frontends", l);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if enabled
|
||||
*/
|
||||
static int
|
||||
linuxdvb_adapter_is_enabled ( linuxdvb_adapter_t *la )
|
||||
{
|
||||
linuxdvb_frontend_t *lfe;
|
||||
LIST_FOREACH(lfe, &la->la_frontends, lfe_link) {
|
||||
if (lfe->mi_is_enabled((mpegts_input_t*)lfe))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
/* Save */
|
||||
hts_settings_save(m, "input/linuxdvb/adapters/%s",
|
||||
idnode_uuid_as_str(&la->th_id));
|
||||
htsmsg_destroy(m);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create
|
||||
*/
|
||||
linuxdvb_adapter_t *
|
||||
linuxdvb_adapter_create0
|
||||
( linuxdvb_device_t *ld, const char *uuid, htsmsg_t *conf )
|
||||
static linuxdvb_adapter_t *
|
||||
linuxdvb_adapter_create
|
||||
( const char *uuid, htsmsg_t *conf,
|
||||
const char *path, int number, struct dvb_frontend_info *dfi )
|
||||
{
|
||||
uint32_t u32;
|
||||
htsmsg_t *e;
|
||||
htsmsg_field_t *f;
|
||||
linuxdvb_adapter_t *la;
|
||||
char buf[1024];
|
||||
|
||||
/* Create */
|
||||
la = calloc(1, sizeof(linuxdvb_adapter_t));
|
||||
if (idnode_insert(&la->la_id, uuid, &linuxdvb_adapter_class)) {
|
||||
if (!tvh_hardware_create0((tvh_hardware_t*)la, &linuxdvb_adapter_class,
|
||||
uuid, conf)) {
|
||||
free(la);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LIST_INSERT_HEAD(&ld->ld_adapters, la, la_link);
|
||||
la->la_device = ld;
|
||||
la->la_dvb_number = -1;
|
||||
la->la_is_enabled = linuxdvb_adapter_is_enabled;
|
||||
|
||||
/* No conf */
|
||||
if (!conf)
|
||||
return la;
|
||||
|
||||
idnode_load(&la->la_id, conf);
|
||||
if (!htsmsg_get_u32(conf, "number", &u32))
|
||||
la->la_number = u32;
|
||||
|
||||
/* Frontends */
|
||||
if ((conf = htsmsg_get_map(conf, "frontends"))) {
|
||||
HTSMSG_FOREACH(f, conf) {
|
||||
if (!(e = htsmsg_get_map_by_field(f))) continue;
|
||||
(void)linuxdvb_frontend_create0(la, f->hmf_name, e, 0);
|
||||
}
|
||||
}
|
||||
/* Setup */
|
||||
sprintf(buf, "%s [%s]", path, dfi->name);
|
||||
la->la_rootpath = strdup(path);
|
||||
la->la_name = strdup(buf);
|
||||
la->la_dvb_number = number;
|
||||
|
||||
return la;
|
||||
}
|
||||
|
||||
/*
|
||||
* Find existing adapter/device entry
|
||||
* Add adapter by path
|
||||
*/
|
||||
static linuxdvb_adapter_t *
|
||||
linuxdvb_adapter_find_by_number ( int adapter )
|
||||
static void
|
||||
linuxdvb_adapter_add ( const char *path )
|
||||
{
|
||||
int a;
|
||||
char buf[1024];
|
||||
linuxdvb_device_t *ld;
|
||||
linuxdvb_adapter_t *la;
|
||||
|
||||
/* Find device */
|
||||
if (!(ld = linuxdvb_device_find_by_adapter(adapter)))
|
||||
return NULL;
|
||||
|
||||
/* Find existing adapter */
|
||||
a = adapter - ld->ld_devid.di_min_adapter;
|
||||
LIST_FOREACH(la, &ld->ld_adapters, la_link) {
|
||||
if (la->la_number == a)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Create */
|
||||
if (!la) {
|
||||
if (!(la = linuxdvb_adapter_create0(ld, NULL, NULL)))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Update */
|
||||
la->la_number = a;
|
||||
snprintf(buf, sizeof(buf), "/dev/dvb/adapter%d", adapter);
|
||||
tvh_str_update(&la->la_rootpath, buf);
|
||||
|
||||
return la;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load an adapter
|
||||
*/
|
||||
void
|
||||
linuxdvb_adapter_added ( int adapter )
|
||||
{
|
||||
int i, r, fd, save = 0;
|
||||
char fe_path[512], dmx_path[512], dvr_path[512];
|
||||
int a, i, j, r, fd;
|
||||
char fe_path[512], dmx_path[512], dvr_path[512], uuid[UUID_STR_LEN];
|
||||
linuxdvb_adapter_t *la = NULL;
|
||||
struct dvb_frontend_info dfi;
|
||||
SHA_CTX sha1;
|
||||
uint8_t uuidbin[20];
|
||||
htsmsg_t *conf = NULL, *feconf = NULL;
|
||||
#if DVB_VER_ATLEAST(5,10)
|
||||
int fetypes[4] = { 0 };
|
||||
struct dtv_property cmd = {
|
||||
.cmd = DTV_ENUM_DELSYS
|
||||
};
|
||||
struct dtv_properties cmdseq = {
|
||||
.num = 1,
|
||||
.props = &cmd
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Validate the path */
|
||||
if (sscanf(path, "/dev/dvb/adapter%d", &a) != 1)
|
||||
return;
|
||||
|
||||
/* Note: some of the below can take a while, so we relinquish the lock
|
||||
* to stop us blocking everyhing else
|
||||
*/
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
|
||||
/* Process each frontend */
|
||||
for (i = 0; i < 32; i++) {
|
||||
snprintf(fe_path, sizeof(fe_path), FE_PATH, adapter, i);
|
||||
snprintf(fe_path, sizeof(fe_path), FE_PATH, path, i);
|
||||
|
||||
/* No access */
|
||||
/* Wait for access (first FE can take a fe ms to be setup) */
|
||||
if (!i) {
|
||||
for (j = 0; j < 10; j++) {
|
||||
if (!access(fe_path, R_OK | W_OK)) break;
|
||||
usleep(100000);
|
||||
}
|
||||
}
|
||||
if (access(fe_path, R_OK | W_OK)) continue;
|
||||
|
||||
/* Get frontend info */
|
||||
fd = tvh_open(fe_path, O_RDONLY | O_NONBLOCK, 0);
|
||||
for (j = 0; j < 10; j++) {
|
||||
if ((fd = tvh_open(fe_path, O_RDONLY, 0)) > 0) break;
|
||||
usleep(100000);
|
||||
}
|
||||
if (fd == -1) {
|
||||
tvhlog(LOG_ERR, "linuxdvb", "unable to open %s", fe_path);
|
||||
continue;
|
||||
}
|
||||
r = ioctl(fd, FE_GET_INFO, &dfi);
|
||||
#if DVB_VER_ATLEAST(5,10)
|
||||
if (!r)
|
||||
r = ioctl(fd, FE_GET_PROPERTY, &cmdseq);
|
||||
#endif
|
||||
close(fd);
|
||||
if(r) {
|
||||
tvhlog(LOG_ERR, "linuxdvb", "unable to query %s", fe_path);
|
||||
|
@ -227,38 +204,188 @@ linuxdvb_adapter_added ( int adapter )
|
|||
}
|
||||
|
||||
/* DVR/DMX (bit of a guess) */
|
||||
snprintf(dmx_path, sizeof(dmx_path), DMX_PATH, adapter, i);
|
||||
snprintf(dmx_path, sizeof(dmx_path), DMX_PATH, path, i);
|
||||
if (access(dmx_path, R_OK | W_OK)) {
|
||||
snprintf(dmx_path, sizeof(dmx_path), DMX_PATH, adapter, 0);
|
||||
snprintf(dmx_path, sizeof(dmx_path), DMX_PATH, path, 0);
|
||||
if (access(dmx_path, R_OK | W_OK)) continue;
|
||||
}
|
||||
|
||||
snprintf(dvr_path, sizeof(dvr_path), DVR_PATH, adapter, i);
|
||||
snprintf(dvr_path, sizeof(dvr_path), DVR_PATH, path, i);
|
||||
if (access(dvr_path, R_OK | W_OK)) {
|
||||
snprintf(dvr_path, sizeof(dvr_path), DVR_PATH, adapter, 0);
|
||||
snprintf(dvr_path, sizeof(dvr_path), DVR_PATH, path, 0);
|
||||
if (access(dvr_path, R_OK | W_OK)) continue;
|
||||
}
|
||||
|
||||
/* Create/Find adapter */
|
||||
pthread_mutex_lock(&global_lock);
|
||||
if (!la) {
|
||||
if (!(la = linuxdvb_adapter_find_by_number(adapter))) {
|
||||
tvhlog(LOG_ERR, "linuxdvb", "failed to find/create adapter%d", adapter);
|
||||
return;
|
||||
}
|
||||
la->la_dvb_number = adapter;
|
||||
if (!la->la_name) {
|
||||
char buf[512];
|
||||
snprintf(buf, sizeof(buf), "%s #%d", dfi.name, la->la_number);
|
||||
la->la_name = strdup(buf);
|
||||
|
||||
/* Create hash for adapter */
|
||||
SHA1_Init(&sha1);
|
||||
SHA1_Update(&sha1, (void*)path, strlen(path));
|
||||
SHA1_Update(&sha1, (void*)dfi.name, strlen(dfi.name));
|
||||
// TODO: could include more form dfi, and maybe frontend enum
|
||||
SHA1_Final(uuidbin, &sha1);
|
||||
idnode_uuid_as_str1(uuidbin, sizeof(uuidbin), uuid);
|
||||
|
||||
/* Load config */
|
||||
conf = hts_settings_load("input/linuxdvb/adapters/%s", uuid);
|
||||
if (conf)
|
||||
feconf = htsmsg_get_map(conf, "frontends");
|
||||
|
||||
/* Create */
|
||||
if (!(la = linuxdvb_adapter_create(uuid, conf, path, a, &dfi))) {
|
||||
tvhlog(LOG_ERR, "linuxdvb", "failed to create %s", path);
|
||||
return; // Note: save to return here as global_lock is held
|
||||
}
|
||||
}
|
||||
|
||||
/* Create frontend */
|
||||
tvhlog(LOG_DEBUG, "linuxdvb", "fe_create(%p, %s, %s, %s)",
|
||||
la, fe_path, dmx_path, dvr_path);
|
||||
save |= linuxdvb_frontend_added(la, i, fe_path, dmx_path, dvr_path, &dfi);
|
||||
linuxdvb_frontend_create(feconf, la, i, fe_path, dmx_path, dvr_path, &dfi);
|
||||
#if DVB_VER_ATLEAST(5,10)
|
||||
fetypes[dfi.type] = 1;
|
||||
for (j = 0; j < cmd.u.buffer.len; j++) {
|
||||
|
||||
/* Invalid */
|
||||
if ((dfi.type = dvb_delsys2type(cmd.u.buffer.data[j])) == -1)
|
||||
continue;
|
||||
|
||||
/* Couldn't find */
|
||||
if (fetypes[dfi.type])
|
||||
continue;
|
||||
|
||||
/* Create */
|
||||
linuxdvb_frontend_create(feconf, la, i, fe_path, dmx_path, dvr_path, &dfi);
|
||||
fetypes[dfi.type] = 1;
|
||||
}
|
||||
#endif
|
||||
pthread_mutex_unlock(&global_lock);
|
||||
}
|
||||
|
||||
if (save)
|
||||
linuxdvb_device_save(la->la_device);
|
||||
/* Relock before exit */
|
||||
pthread_mutex_lock(&global_lock);
|
||||
|
||||
/* Save configuration */
|
||||
if (!conf && la)
|
||||
linuxdvb_adapter_save(la);
|
||||
}
|
||||
|
||||
static void
|
||||
linuxdvb_adapter_del ( const char *path )
|
||||
{
|
||||
int a;
|
||||
linuxdvb_frontend_t *lfe, *next;
|
||||
linuxdvb_adapter_t *la;
|
||||
tvh_hardware_t *th;
|
||||
|
||||
if (sscanf(path, "/dev/dvb/adapter%d", &a) == 1) {
|
||||
LIST_FOREACH(th, &tvh_hardware, th_link)
|
||||
if (idnode_is_instance(&th->th_id, &linuxdvb_adapter_class)) {
|
||||
la = (linuxdvb_adapter_t*)th;
|
||||
if (!strcmp(path, la->la_rootpath))
|
||||
break;
|
||||
}
|
||||
if (!th) return;
|
||||
|
||||
/* Delete the frontends */
|
||||
for (lfe = LIST_FIRST(&la->la_frontends); lfe != NULL; lfe = next) {
|
||||
next = LIST_NEXT(lfe, lfe_link);
|
||||
linuxdvb_frontend_delete(lfe);
|
||||
}
|
||||
|
||||
/* Free memory */
|
||||
free(la->la_rootpath);
|
||||
free(la->la_name);
|
||||
|
||||
/* Delete */
|
||||
tvh_hardware_delete((tvh_hardware_t*)la);
|
||||
}
|
||||
}
|
||||
|
||||
/* **************************************************************************
|
||||
* Adapter Management
|
||||
* *************************************************************************/
|
||||
|
||||
/*
|
||||
* Scan for adapters
|
||||
*/
|
||||
static void
|
||||
linuxdvb_adapter_scan ( void )
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent buf, *de;
|
||||
char path[1024];
|
||||
|
||||
if ((dir = opendir("/dev/dvb"))) {
|
||||
while (!readdir_r(dir, &buf, &de) && de) {
|
||||
if (de->d_name[0] == '.') continue;
|
||||
snprintf(path, sizeof(path), "/dev/dvb/%s", de->d_name);
|
||||
linuxdvb_adapter_add(path);
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* /dev/dvb monitor
|
||||
*/
|
||||
static void
|
||||
devdvb_create ( fsmonitor_t *fsm, const char *path )
|
||||
{
|
||||
linuxdvb_adapter_add(path);
|
||||
}
|
||||
|
||||
static void
|
||||
devdvb_delete ( fsmonitor_t *fsm, const char *path )
|
||||
{
|
||||
linuxdvb_adapter_del(path);
|
||||
}
|
||||
|
||||
static fsmonitor_t devdvbmon = {
|
||||
.fsm_create = devdvb_create,
|
||||
.fsm_delete = devdvb_delete
|
||||
};
|
||||
|
||||
/*
|
||||
* /dev monitor
|
||||
*/
|
||||
|
||||
static void
|
||||
dev_create ( fsmonitor_t *fsm, const char *path )
|
||||
{
|
||||
if (!strcmp(path, "/dev/dvb")) {
|
||||
fsmonitor_add("/dev/dvb", &devdvbmon);
|
||||
linuxdvb_adapter_scan();
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dev_delete ( fsmonitor_t *fsm, const char *path )
|
||||
{
|
||||
if (!strcmp(path, "/dev/dvb"))
|
||||
fsmonitor_del("/dev/dvb", &devdvbmon);
|
||||
}
|
||||
|
||||
static fsmonitor_t devmon = {
|
||||
.fsm_create = dev_create,
|
||||
.fsm_delete = dev_delete
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialise
|
||||
*/
|
||||
|
||||
void
|
||||
linuxdvb_adapter_init ( void )
|
||||
{
|
||||
/* Install monitor on /dev */
|
||||
(void)fsmonitor_add("/dev", &devmon);
|
||||
|
||||
/* Install monitor on /dev/dvb */
|
||||
if (!access("/dev/dvb", R_OK)) {
|
||||
(void)fsmonitor_add("/dev/dvb", &devdvbmon);
|
||||
|
||||
/* Scan for adapters */
|
||||
linuxdvb_adapter_scan();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,353 +0,0 @@
|
|||
/*
|
||||
* Tvheadend - Linux DVB device management
|
||||
*
|
||||
* Copyright (C) 2013 Adam Sutton
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "tvheadend.h"
|
||||
#include "input.h"
|
||||
#include "linuxdvb_private.h"
|
||||
#include "queue.h"
|
||||
#include "settings.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/* ***************************************************************************
|
||||
* Device/BUS Info
|
||||
* **************************************************************************/
|
||||
|
||||
/*
|
||||
* BUS str table
|
||||
*/
|
||||
static struct strtab bustab[] = {
|
||||
{ "NONE", BUS_NONE },
|
||||
{ "PCI", BUS_PCI },
|
||||
{ "USB1", BUS_USB1 },
|
||||
{ "USB2", BUS_USB2 },
|
||||
{ "USB3", BUS_USB3 }
|
||||
};
|
||||
#define devinfo_bus2str(p) val2str(p, bustab)
|
||||
#define devinfo_str2bus(p) str2val(p, bustab)
|
||||
|
||||
/*
|
||||
* Get bus information
|
||||
*/
|
||||
static void
|
||||
get_device_info ( device_info_t *di, int a )
|
||||
{
|
||||
FILE *fp;
|
||||
DIR *dp;
|
||||
struct dirent *de;
|
||||
uint16_t u16;
|
||||
int speed;
|
||||
char path[512], buf[512];
|
||||
ssize_t c;
|
||||
int mina = a;
|
||||
|
||||
/* Clear */
|
||||
memset(di, 0, sizeof(device_info_t));
|
||||
|
||||
/* Check for subsystem */
|
||||
#define DVB_DEV_PATH "/sys/class/dvb/dvb%d.frontend0/device"
|
||||
snprintf(path, sizeof(path), DVB_DEV_PATH "/subsystem", a);
|
||||
if ((c = readlink(path, buf, sizeof(buf))) != -1) {
|
||||
buf[c] = '\0';
|
||||
char *bus = basename(buf);
|
||||
if (!strcmp(bus, "pci")) {
|
||||
di->di_bus = BUS_PCI;
|
||||
snprintf(path, sizeof(path), DVB_DEV_PATH "/subsystem_vendor", a);
|
||||
if ((fp = fopen(path, "r"))) {
|
||||
if (fscanf(fp, "0x%hx", &u16) == 1)
|
||||
di->di_dev = u16;
|
||||
fclose(fp);
|
||||
}
|
||||
di->di_dev <<= 16;
|
||||
snprintf(path, sizeof(path), DVB_DEV_PATH "/subsystem_device", a);
|
||||
if ((fp = fopen(path, "r"))) {
|
||||
if (fscanf(fp, "0x%hx", &u16) == 1)
|
||||
di->di_dev |= u16;
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
} else if (!strcmp(bus, "usb")) {
|
||||
di->di_bus = BUS_USB1;
|
||||
snprintf(path, sizeof(path), DVB_DEV_PATH "/idVendor", a);
|
||||
if ((fp = fopen(path, "r"))) {
|
||||
if (fscanf(fp, "%hx", &u16) == 1)
|
||||
di->di_dev = u16;
|
||||
fclose(fp);
|
||||
}
|
||||
di->di_dev <<= 16;
|
||||
snprintf(path, sizeof(path), DVB_DEV_PATH "/idProduct", a);
|
||||
if ((fp = fopen(path, "r"))) {
|
||||
if (fscanf(fp, "%hx", &u16) == 1)
|
||||
di->di_dev |= u16;
|
||||
fclose(fp);
|
||||
}
|
||||
snprintf(path, sizeof(path), DVB_DEV_PATH "/speed", a);
|
||||
if ((fp = fopen(path, "r"))) {
|
||||
if (fscanf(fp, "%d", &speed) == 1) {
|
||||
if (speed > 480) {
|
||||
di->di_bus = BUS_USB3;
|
||||
} else if (speed == 480) {
|
||||
di->di_bus = BUS_USB2;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
} else {
|
||||
tvhlog(LOG_WARNING, "linuxdvb",
|
||||
"could not determine host connection for adapter%d", a);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get Path */
|
||||
snprintf(path, sizeof(path), DVB_DEV_PATH, a);
|
||||
if ((c = readlink(path, buf, sizeof(buf))) != -1) {
|
||||
buf[c] = '\0';
|
||||
strcpy(di->di_path, basename(buf));
|
||||
}
|
||||
|
||||
/* Find minimum adapter number */
|
||||
snprintf(path, sizeof(path), DVB_DEV_PATH "/dvb", a);
|
||||
if ((dp = opendir(path))) {
|
||||
while ((de = readdir(dp))) {
|
||||
int t;
|
||||
if ((sscanf(de->d_name, "dvb%d.frontend0", &t)))
|
||||
if (t < mina) mina = t;
|
||||
}
|
||||
closedir(dp);
|
||||
}
|
||||
di->di_min_adapter = mina;
|
||||
|
||||
/* Create ID */
|
||||
if (*di->di_path && di->di_dev && di->di_bus) {
|
||||
snprintf(buf, sizeof(buf), "%s/%s/%04x:%04x",
|
||||
devinfo_bus2str(di->di_bus), di->di_path,
|
||||
di->di_dev >> 16, di->di_dev & 0xFFFF);
|
||||
} else {
|
||||
snprintf(buf, sizeof(buf), "/dev/dvb/adapter%d", a);
|
||||
}
|
||||
di->di_id = strdup(buf);
|
||||
}
|
||||
static void
|
||||
get_min_dvb_adapter ( device_info_t *di )
|
||||
{
|
||||
int mina = -1;
|
||||
char path[512];
|
||||
DIR *dp;
|
||||
struct dirent *de;
|
||||
|
||||
snprintf(path, sizeof(path), "/sys/bus/%s/devices/%s/dvb",
|
||||
di->di_bus == BUS_PCI ? "pci" : "usb", di->di_path);
|
||||
|
||||
/* Find minimum adapter number */
|
||||
if ((dp = opendir(path))) {
|
||||
while ((de = readdir(dp))) {
|
||||
int t;
|
||||
if ((sscanf(de->d_name, "dvb%d.frontend0", &t)))
|
||||
if (mina == -1 || t < mina) mina = t;
|
||||
}
|
||||
closedir(dp);
|
||||
}
|
||||
di->di_min_adapter = mina;
|
||||
}
|
||||
|
||||
/* ***************************************************************************
|
||||
* Class
|
||||
* **************************************************************************/
|
||||
|
||||
static void
|
||||
linuxdvb_device_class_save ( idnode_t *in )
|
||||
{
|
||||
linuxdvb_device_save((linuxdvb_device_t*)in);
|
||||
}
|
||||
|
||||
static const char *
|
||||
linuxdvb_device_class_get_title ( idnode_t *in )
|
||||
{
|
||||
return ((linuxdvb_device_t*)in)->ld_devid.di_id;
|
||||
}
|
||||
|
||||
static idnode_set_t *
|
||||
linuxdvb_device_class_get_childs ( idnode_t *in )
|
||||
{
|
||||
linuxdvb_adapter_t *la;
|
||||
linuxdvb_device_t *ld = (linuxdvb_device_t*)in;
|
||||
idnode_set_t *is = idnode_set_create();
|
||||
LIST_FOREACH(la, &ld->ld_adapters, la_link)
|
||||
idnode_set_add(is, &la->la_id, NULL);
|
||||
return is;
|
||||
}
|
||||
|
||||
const idclass_t linuxdvb_device_class =
|
||||
{
|
||||
.ic_class = "linuxdvb_device",
|
||||
.ic_caption = "LinuxDVB Device",
|
||||
.ic_save = linuxdvb_device_class_save,
|
||||
.ic_get_childs = linuxdvb_device_class_get_childs,
|
||||
.ic_get_title = linuxdvb_device_class_get_title,
|
||||
.ic_properties = (const property_t[]){
|
||||
{
|
||||
.type = PT_STR,
|
||||
.id = "devid",
|
||||
.name = "Device ID",
|
||||
.opts = PO_RDONLY,
|
||||
.off = offsetof(linuxdvb_device_t, ld_devid.di_id)
|
||||
},
|
||||
{}
|
||||
}
|
||||
};
|
||||
|
||||
void linuxdvb_device_save ( linuxdvb_device_t *ld )
|
||||
{
|
||||
htsmsg_t *m, *e, *l;
|
||||
linuxdvb_adapter_t *la;
|
||||
|
||||
m = htsmsg_create_map();
|
||||
|
||||
idnode_save(&ld->th_id, m);
|
||||
|
||||
/* Adapters */
|
||||
l = htsmsg_create_map();
|
||||
LIST_FOREACH(la, &ld->ld_adapters, la_link) {
|
||||
e = htsmsg_create_map();
|
||||
linuxdvb_adapter_save(la, e);
|
||||
htsmsg_add_msg(l, idnode_uuid_as_str(&la->la_id), e);
|
||||
}
|
||||
htsmsg_add_msg(m, "adapters", l);
|
||||
|
||||
/* Save */
|
||||
hts_settings_save(m, "input/linuxdvb/devices/%s",
|
||||
idnode_uuid_as_str(&ld->th_id));
|
||||
htsmsg_destroy(m);
|
||||
}
|
||||
|
||||
|
||||
linuxdvb_device_t *
|
||||
linuxdvb_device_create0 ( const char *uuid, htsmsg_t *conf )
|
||||
{
|
||||
linuxdvb_device_t *ld;
|
||||
htsmsg_t *e;
|
||||
htsmsg_field_t *f;
|
||||
|
||||
/* Create */
|
||||
ld = calloc(1, sizeof(linuxdvb_device_t));
|
||||
if (idnode_insert(&ld->th_id, uuid, &linuxdvb_device_class)) {
|
||||
free(ld);
|
||||
return NULL;
|
||||
}
|
||||
LIST_INSERT_HEAD(&tvh_hardware, (tvh_hardware_t*)ld, th_link);
|
||||
|
||||
/* No config */
|
||||
if (!conf)
|
||||
return ld;
|
||||
|
||||
/* Load config */
|
||||
idnode_load(&ld->th_id, conf);
|
||||
get_min_dvb_adapter(&ld->ld_devid);
|
||||
|
||||
/* Adapters */
|
||||
if ((conf = htsmsg_get_map(conf, "adapters"))) {
|
||||
HTSMSG_FOREACH(f, conf) {
|
||||
if (!(e = htsmsg_get_map_by_field(f))) continue;
|
||||
(void)linuxdvb_adapter_create0(ld, f->hmf_name, e);
|
||||
}
|
||||
}
|
||||
|
||||
return ld;
|
||||
}
|
||||
|
||||
static linuxdvb_device_t *
|
||||
linuxdvb_device_find_by_hwid ( const char *hwid )
|
||||
{
|
||||
tvh_hardware_t *lh;
|
||||
LIST_FOREACH(lh, &tvh_hardware, th_link) {
|
||||
if (idnode_is_instance(&lh->th_id, &linuxdvb_device_class))
|
||||
if (!strcmp(hwid, ((linuxdvb_device_t*)lh)->ld_devid.di_id ?: ""))
|
||||
return (linuxdvb_device_t*)lh;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
linuxdvb_device_t *
|
||||
linuxdvb_device_find_by_adapter ( int a )
|
||||
{
|
||||
linuxdvb_device_t *ld;
|
||||
device_info_t dev;
|
||||
|
||||
/* Get device info */
|
||||
get_device_info(&dev, a);
|
||||
|
||||
/* Find existing */
|
||||
if ((ld = linuxdvb_device_find_by_hwid(dev.di_id))) {
|
||||
free(dev.di_id);
|
||||
if (ld->ld_devid.di_bus == BUS_NONE) {
|
||||
strcpy(ld->ld_devid.di_path, dev.di_path);
|
||||
ld->ld_devid.di_bus = dev.di_bus;
|
||||
ld->ld_devid.di_dev = dev.di_dev;
|
||||
ld->ld_devid.di_min_adapter = dev.di_min_adapter;
|
||||
}
|
||||
return ld;
|
||||
}
|
||||
|
||||
/* Create new */
|
||||
if (!(ld = linuxdvb_device_create0(NULL, NULL))) {
|
||||
free(dev.di_id);
|
||||
tvhlog(LOG_ERR, "linuxdvb", "failed to create device for adapter%d", a);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Copy device info */
|
||||
memcpy(&ld->ld_devid, &dev, sizeof(dev));
|
||||
ld->ld_devid.di_id = dev.di_id;
|
||||
return ld;
|
||||
}
|
||||
|
||||
void linuxdvb_device_init ( int adapter_mask )
|
||||
{
|
||||
int a;
|
||||
DIR *dp;
|
||||
htsmsg_t *s, *e;
|
||||
htsmsg_field_t *f;
|
||||
|
||||
/* Load configuration */
|
||||
if ((s = hts_settings_load_r(1, "input/linuxdvb/devices"))) {
|
||||
HTSMSG_FOREACH(f, s) {
|
||||
if (!(e = htsmsg_get_map_by_field(f))) continue;
|
||||
(void)linuxdvb_device_create0(f->hmf_name, e);
|
||||
}
|
||||
htsmsg_destroy(s);
|
||||
}
|
||||
|
||||
/* Scan for hardware */
|
||||
if ((dp = opendir("/dev/dvb"))) {
|
||||
struct dirent *de;
|
||||
while ((de = readdir(dp))) {
|
||||
if (sscanf(de->d_name, "adapter%d", &a) != 1) continue;
|
||||
if ((0x1 << a) & adapter_mask)
|
||||
linuxdvb_adapter_added(a);
|
||||
}
|
||||
closedir(dp);
|
||||
}
|
||||
|
||||
// TODO: add udev support for hotplug
|
||||
}
|
|
@ -43,9 +43,8 @@ linuxdvb_frontend_input_thread ( void *aux );
|
|||
static void
|
||||
linuxdvb_frontend_class_save ( idnode_t *in )
|
||||
{
|
||||
linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)in;
|
||||
if (lfe->lfe_adapter && lfe->lfe_adapter->la_device)
|
||||
linuxdvb_device_save(lfe->lfe_adapter->la_device);
|
||||
linuxdvb_adapter_t *la = ((linuxdvb_frontend_t*)in)->lfe_adapter;
|
||||
linuxdvb_adapter_save(la);
|
||||
}
|
||||
|
||||
static const void*
|
||||
|
@ -111,28 +110,28 @@ const idclass_t linuxdvb_frontend_class =
|
|||
.type = PT_STR,
|
||||
.id = "fe_path",
|
||||
.name = "Frontend Path",
|
||||
.opts = PO_RDONLY,
|
||||
.opts = PO_RDONLY | PO_NOSAVE,
|
||||
.off = offsetof(linuxdvb_frontend_t, lfe_fe_path),
|
||||
},
|
||||
{
|
||||
.type = PT_STR,
|
||||
.id = "dvr_path",
|
||||
.name = "Input Path",
|
||||
.opts = PO_RDONLY,
|
||||
.opts = PO_RDONLY | PO_NOSAVE,
|
||||
.off = offsetof(linuxdvb_frontend_t, lfe_dvr_path),
|
||||
},
|
||||
{
|
||||
.type = PT_STR,
|
||||
.id = "dmx_path",
|
||||
.name = "Demux Path",
|
||||
.opts = PO_RDONLY,
|
||||
.opts = PO_RDONLY | PO_NOSAVE,
|
||||
.off = offsetof(linuxdvb_frontend_t, lfe_dmx_path),
|
||||
},
|
||||
{
|
||||
.type = PT_INT,
|
||||
.id = "fe_number",
|
||||
.name = "Frontend Number",
|
||||
.opts = PO_RDONLY,
|
||||
.opts = PO_RDONLY | PO_NOSAVE,
|
||||
.off = offsetof(linuxdvb_frontend_t, lfe_number),
|
||||
},
|
||||
{
|
||||
|
@ -184,7 +183,7 @@ linuxdvb_frontend_dvbs_class_satconf_set ( void *self, const void *str )
|
|||
linuxdvb_frontend_t *lfe = self;
|
||||
if (lfe->lfe_satconf && !strcmp(str ?: "", lfe->lfe_satconf->ls_type))
|
||||
return 0;
|
||||
linuxdvb_satconf_destroy(lfe->lfe_satconf);
|
||||
linuxdvb_satconf_delete(lfe->lfe_satconf);
|
||||
lfe->lfe_satconf = linuxdvb_satconf_create(lfe, str, NULL, NULL);
|
||||
return 1;
|
||||
}
|
||||
|
@ -262,6 +261,28 @@ const idclass_t linuxdvb_frontend_atsc_class =
|
|||
* Class methods
|
||||
* *************************************************************************/
|
||||
|
||||
static int
|
||||
linuxdvb_frontend_is_free ( mpegts_input_t *mi )
|
||||
{
|
||||
linuxdvb_adapter_t *la = ((linuxdvb_frontend_t*)mi)->lfe_adapter;
|
||||
linuxdvb_frontend_t *lfe;
|
||||
LIST_FOREACH(lfe, &la->la_frontends, lfe_link)
|
||||
if (!mpegts_input_is_free((mpegts_input_t*)lfe))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
linuxdvb_frontend_get_weight ( mpegts_input_t *mi )
|
||||
{
|
||||
int weight = 0;
|
||||
linuxdvb_adapter_t *la = ((linuxdvb_frontend_t*)mi)->lfe_adapter;
|
||||
linuxdvb_frontend_t *lfe;
|
||||
LIST_FOREACH(lfe, &la->la_frontends, lfe_link)
|
||||
weight = MAX(weight, mpegts_input_get_weight((mpegts_input_t*)lfe));
|
||||
return weight;
|
||||
}
|
||||
|
||||
static int
|
||||
linuxdvb_frontend_is_enabled ( mpegts_input_t *mi )
|
||||
{
|
||||
|
@ -871,41 +892,65 @@ linuxdvb_frontend_tune1
|
|||
/* **************************************************************************
|
||||
* Creation/Config
|
||||
* *************************************************************************/
|
||||
|
||||
linuxdvb_frontend_t *
|
||||
linuxdvb_frontend_create0
|
||||
( linuxdvb_adapter_t *la, const char *uuid, htsmsg_t *conf, fe_type_t type )
|
||||
{
|
||||
const char *str;
|
||||
const idclass_t *idc;
|
||||
pthread_t tid;
|
||||
const char *scuuid = NULL, *sctype = NULL;
|
||||
htsmsg_t *scconf = NULL;
|
||||
|
||||
/* Get type */
|
||||
if (conf) {
|
||||
if (!(str = htsmsg_get_str(conf, "type")))
|
||||
return NULL;
|
||||
type = dvb_str2type(str);
|
||||
}
|
||||
linuxdvb_frontend_t *
|
||||
linuxdvb_frontend_create
|
||||
( htsmsg_t *conf, linuxdvb_adapter_t *la, int number,
|
||||
const char *fe_path, const char *dmx_path, const char *dvr_path,
|
||||
struct dvb_frontend_info *dfi )
|
||||
{
|
||||
const idclass_t *idc;
|
||||
const char *uuid = NULL, *scuuid = NULL, *sctype = NULL;
|
||||
char id[12], name[256];
|
||||
linuxdvb_frontend_t *lfe;
|
||||
htsmsg_t *scconf = NULL;
|
||||
pthread_t tid;
|
||||
|
||||
/* Internal config ID */
|
||||
snprintf(id, sizeof(id), "%s #%d", dvb_type2str(dfi->type), number);
|
||||
if (conf)
|
||||
conf = htsmsg_get_map(conf, id);
|
||||
if (conf)
|
||||
uuid = htsmsg_get_str(conf, "uuid");
|
||||
|
||||
/* Class */
|
||||
if (type == FE_QPSK)
|
||||
if (dfi->type == FE_QPSK)
|
||||
idc = &linuxdvb_frontend_dvbs_class;
|
||||
else if (type == FE_QAM)
|
||||
else if (dfi->type == FE_QAM)
|
||||
idc = &linuxdvb_frontend_dvbc_class;
|
||||
else if (type == FE_OFDM)
|
||||
else if (dfi->type == FE_OFDM)
|
||||
idc = &linuxdvb_frontend_dvbt_class;
|
||||
else if (type == FE_ATSC)
|
||||
else if (dfi->type == FE_ATSC)
|
||||
idc = &linuxdvb_frontend_atsc_class;
|
||||
else {
|
||||
tvherror("linuxdvb", "unknown FE type %d", type);
|
||||
tvherror("linuxdvb", "unknown FE type %d", dfi->type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
linuxdvb_frontend_t *lfe = calloc(1, sizeof(linuxdvb_frontend_t));
|
||||
lfe->lfe_info.type = type;
|
||||
/* Create */
|
||||
// Note: there is a bit of a chicken/egg issue below, without the
|
||||
// correct "fe_type" we cannot set the network (which is done
|
||||
// in mpegts_input_create()). So we must set early.
|
||||
lfe = calloc(1, sizeof(linuxdvb_frontend_t));
|
||||
lfe->lfe_number = number;
|
||||
memcpy(&lfe->lfe_info, dfi, sizeof(struct dvb_frontend_info));
|
||||
lfe = (linuxdvb_frontend_t*)mpegts_input_create0((mpegts_input_t*)lfe, idc, uuid, conf);
|
||||
if (!lfe) return NULL;
|
||||
|
||||
/* Callbacks */
|
||||
lfe->mi_is_free = linuxdvb_frontend_is_free;
|
||||
lfe->mi_get_weight = linuxdvb_frontend_get_weight;
|
||||
|
||||
/* Default name */
|
||||
if (!lfe->mi_name) {
|
||||
snprintf(name, sizeof(name), "%s : %s", dfi->name, id);
|
||||
lfe->mi_name = strdup(name);
|
||||
}
|
||||
|
||||
/* Set paths */
|
||||
lfe->lfe_fe_path = strdup(fe_path);
|
||||
lfe->lfe_dmx_path = strdup(dmx_path);
|
||||
lfe->lfe_dvr_path = strdup(dvr_path);
|
||||
|
||||
/* Input callbacks */
|
||||
lfe->mi_is_enabled = linuxdvb_frontend_is_enabled;
|
||||
|
@ -934,70 +979,19 @@ linuxdvb_frontend_create0
|
|||
}
|
||||
|
||||
/* Create satconf */
|
||||
if (type == FE_QPSK && !lfe->lfe_satconf)
|
||||
if (dfi->type == FE_QPSK && !lfe->lfe_satconf)
|
||||
lfe->lfe_satconf = linuxdvb_satconf_create(lfe, sctype, scuuid, scconf);
|
||||
|
||||
/* No conf */
|
||||
if (!conf)
|
||||
return lfe;
|
||||
|
||||
return lfe;
|
||||
}
|
||||
|
||||
int
|
||||
linuxdvb_frontend_added
|
||||
( linuxdvb_adapter_t *la, int fe_num,
|
||||
const char *fe_path,
|
||||
const char *dmx_path,
|
||||
const char *dvr_path,
|
||||
const struct dvb_frontend_info *fe_info )
|
||||
{
|
||||
int save = 0;
|
||||
linuxdvb_frontend_t *lfe = NULL;
|
||||
|
||||
/* Find existing */
|
||||
LIST_FOREACH(lfe, &la->la_frontends, lfe_link) {
|
||||
if (lfe->lfe_number == fe_num) {
|
||||
if (lfe->lfe_info.type != fe_info->type) {
|
||||
tvhlog(LOG_ERR, "linuxdvb", "detected incorrect fe_type %s != %s",
|
||||
dvb_type2str(lfe->lfe_info.type), dvb_type2str(fe_info->type));
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create new */
|
||||
if (!lfe) {
|
||||
if (!(lfe = linuxdvb_frontend_create0(la, NULL, NULL, fe_info->type))) {
|
||||
tvhlog(LOG_ERR, "linuxdvb", "failed to create frontend");
|
||||
return 0;
|
||||
}
|
||||
save = 1;
|
||||
}
|
||||
|
||||
/* Defaults */
|
||||
if (!lfe->mi_name)
|
||||
lfe->mi_name = strdup(fe_path);
|
||||
|
||||
/* Copy info */
|
||||
lfe->lfe_number = fe_num;
|
||||
memcpy(&lfe->lfe_info, fe_info, sizeof(struct dvb_frontend_info));
|
||||
|
||||
/* Set paths */
|
||||
free(lfe->lfe_fe_path);
|
||||
free(lfe->lfe_dvr_path);
|
||||
free(lfe->lfe_dmx_path);
|
||||
lfe->lfe_fe_path = strdup(fe_path);
|
||||
lfe->lfe_dmx_path = strdup(dmx_path);
|
||||
lfe->lfe_dvr_path = strdup(dvr_path);
|
||||
|
||||
return save;
|
||||
}
|
||||
|
||||
void
|
||||
linuxdvb_frontend_save ( linuxdvb_frontend_t *lfe, htsmsg_t *m )
|
||||
linuxdvb_frontend_save ( linuxdvb_frontend_t *lfe, htsmsg_t *fe )
|
||||
{
|
||||
char id[12];
|
||||
htsmsg_t *m = htsmsg_create_map();
|
||||
|
||||
/* Save frontend */
|
||||
mpegts_input_save((mpegts_input_t*)lfe, m);
|
||||
htsmsg_add_str(m, "type", dvb_type2str(lfe->lfe_info.type));
|
||||
if (lfe->lfe_satconf) {
|
||||
|
@ -1006,6 +1000,44 @@ linuxdvb_frontend_save ( linuxdvb_frontend_t *lfe, htsmsg_t *m )
|
|||
htsmsg_add_str(s, "uuid", idnode_uuid_as_str(&lfe->lfe_satconf->ls_id));
|
||||
htsmsg_add_msg(m, "satconf", s);
|
||||
}
|
||||
|
||||
/* Add to list */
|
||||
snprintf(id, sizeof(id), "%s #%d", dvb_type2str(lfe->lfe_info.type), lfe->lfe_number);
|
||||
htsmsg_add_msg(fe, id, m);
|
||||
}
|
||||
|
||||
void
|
||||
linuxdvb_frontend_delete ( linuxdvb_frontend_t *lfe )
|
||||
{
|
||||
mpegts_mux_instance_t *mmi;
|
||||
|
||||
lock_assert(&global_lock);
|
||||
|
||||
/* Ensure we're stopped */
|
||||
if ((mmi = LIST_FIRST(&lfe->mi_mux_active)))
|
||||
mmi->mmi_mux->mm_stop(mmi->mmi_mux, 1);
|
||||
|
||||
/* Stop monitor */
|
||||
gtimer_disarm(&lfe->lfe_monitor_timer);
|
||||
|
||||
/* Close FDs */
|
||||
if (lfe->lfe_fe_fd > 0)
|
||||
close(lfe->lfe_fe_fd);
|
||||
|
||||
/* Remove from adapter */
|
||||
LIST_REMOVE(lfe, lfe_link);
|
||||
|
||||
/* Free memory */
|
||||
free(lfe->lfe_fe_path);
|
||||
free(lfe->lfe_dmx_path);
|
||||
free(lfe->lfe_dvr_path);
|
||||
|
||||
/* Delete satconf */
|
||||
if (lfe->lfe_satconf)
|
||||
linuxdvb_satconf_delete(lfe->lfe_satconf);
|
||||
|
||||
/* Finish */
|
||||
mpegts_input_delete((mpegts_input_t*)lfe);
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
#define LINUXDVB_FREQ_TOL 2000
|
||||
|
||||
typedef struct linuxdvb_hardware linuxdvb_hardware_t;
|
||||
typedef struct linuxdvb_device linuxdvb_device_t;
|
||||
typedef struct linuxdvb_adapter linuxdvb_adapter_t;
|
||||
typedef struct linuxdvb_frontend linuxdvb_frontend_t;
|
||||
typedef struct linuxdvb_satconf linuxdvb_satconf_t;
|
||||
|
@ -39,56 +38,15 @@ typedef struct linuxdvb_mux linuxdvb_mux_t;
|
|||
typedef LIST_HEAD(,linuxdvb_hardware) linuxdvb_hardware_list_t;
|
||||
typedef TAILQ_HEAD(linuxdvb_satconf_ele_list,linuxdvb_satconf_ele) linuxdvb_satconf_ele_list_t;
|
||||
|
||||
/*
|
||||
* Hardware tree objects
|
||||
*/
|
||||
|
||||
typedef struct device_info
|
||||
{
|
||||
char *di_id;
|
||||
char di_path[128];
|
||||
enum {
|
||||
BUS_NONE = 0,
|
||||
BUS_PCI,
|
||||
BUS_USB1,
|
||||
BUS_USB2,
|
||||
BUS_USB3
|
||||
} di_bus;
|
||||
uint32_t di_dev;
|
||||
int di_min_adapter;
|
||||
} device_info_t;
|
||||
|
||||
struct linuxdvb_device
|
||||
{
|
||||
tvh_hardware_t;
|
||||
|
||||
/*
|
||||
* Device info
|
||||
*/
|
||||
device_info_t ld_devid;
|
||||
|
||||
/*
|
||||
* Adapters
|
||||
*/
|
||||
LIST_HEAD(,linuxdvb_adapter) ld_adapters;
|
||||
};
|
||||
|
||||
struct linuxdvb_adapter
|
||||
{
|
||||
idnode_t la_id;
|
||||
|
||||
/*
|
||||
* Link to device
|
||||
*/
|
||||
linuxdvb_device_t *la_device;
|
||||
LIST_ENTRY(linuxdvb_adapter) la_link;
|
||||
tvh_hardware_t;
|
||||
|
||||
/*
|
||||
* Adapter info
|
||||
*/
|
||||
char *la_name;
|
||||
char *la_rootpath;
|
||||
uint32_t la_number;
|
||||
int la_dvb_number;
|
||||
|
||||
/*
|
||||
|
@ -223,40 +181,26 @@ struct linuxdvb_lnb
|
|||
* Methods
|
||||
*/
|
||||
|
||||
void linuxdvb_device_init ( int adapter_mask );
|
||||
void linuxdvb_device_save ( linuxdvb_device_t *ld );
|
||||
|
||||
linuxdvb_device_t *linuxdvb_device_create0
|
||||
(const char *uuid, htsmsg_t *conf);
|
||||
|
||||
linuxdvb_device_t * linuxdvb_device_find_by_adapter ( int a );
|
||||
|
||||
#define LINUXDVB_SUBSYS_FE 0x01
|
||||
#define LINUXDVB_SUBSYS_DVR 0x02
|
||||
|
||||
void linuxdvb_adapter_save ( linuxdvb_adapter_t *la, htsmsg_t *m );
|
||||
void linuxdvb_adapter_init ( void );
|
||||
|
||||
linuxdvb_adapter_t *linuxdvb_adapter_create0
|
||||
( linuxdvb_device_t *ld, const char *uuid, htsmsg_t *conf );
|
||||
|
||||
void linuxdvb_adapter_added (int a);
|
||||
void linuxdvb_adapter_save ( linuxdvb_adapter_t *la );
|
||||
|
||||
int linuxdvb_adapter_is_free ( linuxdvb_adapter_t *la );
|
||||
int linuxdvb_adapter_current_weight ( linuxdvb_adapter_t *la );
|
||||
|
||||
linuxdvb_adapter_t *linuxdvb_adapter_find_by_hwid ( const char *hwid );
|
||||
linuxdvb_adapter_t *linuxdvb_adapter_find_by_path ( const char *path );
|
||||
|
||||
linuxdvb_frontend_t *
|
||||
linuxdvb_frontend_create0
|
||||
( linuxdvb_adapter_t *la, const char *uuid, htsmsg_t *conf, fe_type_t type );
|
||||
linuxdvb_frontend_create
|
||||
( htsmsg_t *conf, linuxdvb_adapter_t *la, int number,
|
||||
const char *fe_path, const char *dmx_path, const char *dvr_path,
|
||||
struct dvb_frontend_info *dfi );
|
||||
|
||||
void linuxdvb_frontend_save ( linuxdvb_frontend_t *lfe, htsmsg_t *m );
|
||||
|
||||
int linuxdvb_frontend_added
|
||||
( linuxdvb_adapter_t *la, int fe_num,
|
||||
const char *fe_path, const char *dmx_path, const char *dvr_path,
|
||||
const struct dvb_frontend_info *fe_info );
|
||||
void linuxdvb_frontend_delete ( linuxdvb_frontend_t *lfe );
|
||||
|
||||
void linuxdvb_frontend_add_network
|
||||
( linuxdvb_frontend_t *lfe, linuxdvb_network_t *net );
|
||||
|
||||
|
@ -360,6 +304,5 @@ linuxdvb_satconf_t *linuxdvb_satconf_create
|
|||
const char *type, const char *uuid, htsmsg_t *conf );
|
||||
|
||||
void linuxdvb_satconf_delete ( linuxdvb_satconf_t *ls );
|
||||
void linuxdvb_satconf_destroy ( linuxdvb_satconf_t *ls );
|
||||
|
||||
#endif /* __TVH_LINUXDVB_PRIVATE_H__ */
|
||||
|
|
|
@ -115,9 +115,11 @@ linuxdvb_satconf_class_get_title ( idnode_t *p )
|
|||
static void
|
||||
linuxdvb_satconf_class_save ( idnode_t *s )
|
||||
{
|
||||
#if 0
|
||||
linuxdvb_satconf_t *ls = (linuxdvb_satconf_t*)s;
|
||||
linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)ls->ls_frontend;
|
||||
linuxdvb_device_save(lfe->lfe_adapter->la_device);
|
||||
#endif
|
||||
}
|
||||
|
||||
static const void *
|
||||
|
@ -382,12 +384,6 @@ linuxdvb_satconf_type_list ( void *p )
|
|||
* Create/Delete satconf
|
||||
* *************************************************************************/
|
||||
|
||||
void
|
||||
linuxdvb_satconf_destroy ( linuxdvb_satconf_t *ls )
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
linuxdvb_satconf_t *
|
||||
linuxdvb_satconf_create
|
||||
( linuxdvb_frontend_t *lfe, const char *type, const char *uuid,
|
||||
|
|
|
@ -443,7 +443,6 @@ scanfile_find ( const char *id )
|
|||
/* Type */
|
||||
if (!(tok = strtok_r(tmp, "/", &s)))
|
||||
return NULL;
|
||||
printf("tok = %s\n", tok);
|
||||
if (!strcasecmp(tok, "dvbt"))
|
||||
l = &scanfile_regions_DVBT;
|
||||
else if (!strcasecmp(tok, "dvbc"))
|
||||
|
@ -458,7 +457,6 @@ scanfile_find ( const char *id )
|
|||
/* Region */
|
||||
if (!(tok = strtok_r(NULL, "/", &s)))
|
||||
return NULL;
|
||||
printf("tok = %s\n", tok);
|
||||
LIST_FOREACH(r, l, sfr_link)
|
||||
if (!strcmp(r->sfr_id, tok))
|
||||
break;
|
||||
|
@ -467,7 +465,6 @@ scanfile_find ( const char *id )
|
|||
/* Network */
|
||||
if (!(tok = strtok_r(NULL, "/", &s)))
|
||||
return NULL;
|
||||
printf("tok = %s\n", tok);
|
||||
LIST_FOREACH(n, &r->sfr_networks, sfn_link)
|
||||
if (!strcmp(n->sfn_id, tok))
|
||||
break;
|
||||
|
|
20
src/main.c
20
src/main.c
|
@ -59,6 +59,7 @@
|
|||
#include "idnode.h"
|
||||
#include "imagecache.h"
|
||||
#include "timeshift.h"
|
||||
#include "fsmonitor.h"
|
||||
#if ENABLE_LIBAV
|
||||
#include "libav.h"
|
||||
#include "plumbing/transcoding.h"
|
||||
|
@ -420,6 +421,14 @@ main(int argc, char **argv)
|
|||
const char *log_debug = NULL, *log_trace = NULL;
|
||||
char buf[512];
|
||||
|
||||
/* Setup global mutexes */
|
||||
pthread_mutex_init(&ffmpeg_lock, NULL);
|
||||
pthread_mutex_init(&fork_lock, NULL);
|
||||
pthread_mutex_init(&global_lock, NULL);
|
||||
pthread_mutex_init(&atomic_lock, NULL);
|
||||
pthread_mutex_lock(&global_lock);
|
||||
pthread_cond_init(>imer_cond, NULL);
|
||||
|
||||
/* Defaults */
|
||||
tvheadend_webui_port = 9981;
|
||||
tvheadend_webroot = NULL;
|
||||
|
@ -702,14 +711,7 @@ main(int argc, char **argv)
|
|||
idnode_init();
|
||||
hts_settings_init(opt_config);
|
||||
|
||||
/* Setup global mutexes */
|
||||
pthread_mutex_init(&ffmpeg_lock, NULL);
|
||||
pthread_mutex_init(&fork_lock, NULL);
|
||||
pthread_mutex_init(&global_lock, NULL);
|
||||
pthread_mutex_init(&atomic_lock, NULL);
|
||||
pthread_mutex_lock(&global_lock);
|
||||
pthread_cond_init(>imer_cond, NULL);
|
||||
|
||||
/* Initialise clock */
|
||||
time(&dispatch_clock);
|
||||
|
||||
/* Signal handling */
|
||||
|
@ -723,6 +725,8 @@ main(int argc, char **argv)
|
|||
|
||||
api_init();
|
||||
|
||||
fsmonitor_init();
|
||||
|
||||
#if ENABLE_LIBAV
|
||||
libav_init();
|
||||
transcoding_init();
|
||||
|
|
|
@ -611,12 +611,6 @@ tvheadend.idnode_grid = function(panel, conf)
|
|||
var delBtn = null;
|
||||
var editBtn = null;
|
||||
|
||||
/* Selection */
|
||||
var select = new Ext.grid.CheckboxSelectionModel({
|
||||
singleSelect : false
|
||||
});
|
||||
columns.splice(0, 0, select);
|
||||
|
||||
/* Model */
|
||||
var idnode = new tvheadend.IdNode(d);
|
||||
for (var i = 0; i < idnode.length(); i++) {
|
||||
|
@ -658,6 +652,11 @@ tvheadend.idnode_grid = function(panel, conf)
|
|||
columns : columns
|
||||
});
|
||||
|
||||
/* Selection */
|
||||
var select = new Ext.grid.RowSelectionModel({
|
||||
singleSelect : false
|
||||
});
|
||||
|
||||
/* Event handlers */
|
||||
store.on('update', function(s, r, o){
|
||||
var d = (s.getModifiedRecords().length == 0);
|
||||
|
@ -995,6 +994,13 @@ tvheadend.idnode_tree = function (conf)
|
|||
}
|
||||
});
|
||||
|
||||
if (conf.comet) {
|
||||
tvheadend.comet.on(conf.comet, function(o) {
|
||||
if (o.reload)
|
||||
tree.getRootNode().reload();
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: top-level reload
|
||||
tvheadend.comet.on('idnodeUpdated', function(o) {
|
||||
var n = tree.getNodeById(o.uuid);
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
tvheadend.tvadapters = function() {
|
||||
return tvheadend.idnode_tree({ url: 'api/hardware/tree', title: 'TV adapters'});
|
||||
return tvheadend.idnode_tree({ url: 'api/hardware/tree', title: 'TV adapters', comet: 'hardware'});
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue