Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
linuxdvb: add master tuner support, fixes #2952
  • Loading branch information
perexg committed Oct 6, 2015
1 parent b35cf23 commit ac47b98
Show file tree
Hide file tree
Showing 6 changed files with 304 additions and 41 deletions.
4 changes: 2 additions & 2 deletions src/descrambler/dvbcam.c
Expand Up @@ -218,10 +218,10 @@ dvbcam_service_start(service_t *t)
void
dvbcam_service_stop(service_t *t)
{
dvbcam_active_service_t *as, *as_tmp;
dvbcam_active_service_t *as, *as_tmp;
linuxdvb_ca_t *ca = NULL;
dvbcam_active_cam_t *ac2;
uint8_t slot;
uint8_t slot = -1;

tvhtrace("dvbcam", "stop service %p", t);

Expand Down
8 changes: 8 additions & 0 deletions src/input/mpegts/linuxdvb/linuxdvb_en50494.c
Expand Up @@ -184,6 +184,13 @@ linuxdvb_en50494_freq
return rfreq;
}

static int
linuxdvb_en50494_match
( linuxdvb_diseqc_t *ld, dvb_mux_t *lm1, dvb_mux_t *lm2 )
{
return lm1 == lm2;
}

static int
linuxdvb_en50494_tune
( linuxdvb_diseqc_t *ld, dvb_mux_t *lm,
Expand Down Expand Up @@ -321,6 +328,7 @@ linuxdvb_en50494_create0
le->le_frequency = 0;
le->le_pin = LINUXDVB_EN50494_NOPIN;
le->ld_freq = linuxdvb_en50494_freq;
le->ld_match = linuxdvb_en50494_match;

ld = linuxdvb_diseqc_create0((linuxdvb_diseqc_t *)le,
NULL, &linuxdvb_en50494_class, conf,
Expand Down
187 changes: 170 additions & 17 deletions src/input/mpegts/linuxdvb/linuxdvb_frontend.c
Expand Up @@ -189,6 +189,32 @@ linuxdvb_frontend_dvbs_class_satconf_get ( void *self )
return &s;
}

static htsmsg_t *
linuxdvb_frontend_dvbs_class_master_enum( void * self, const char *lang )
{
linuxdvb_frontend_t *lfe = self, *lfe2;
linuxdvb_adapter_t *la;
tvh_hardware_t *th;
htsmsg_t *m = htsmsg_create_list();
htsmsg_t *e = htsmsg_create_map();
htsmsg_add_str(e, "key", "");
htsmsg_add_str(e, "val", N_("This Tuner"));
htsmsg_add_msg(m, NULL, e);
LIST_FOREACH(th, &tvh_hardware, th_link) {
if (!idnode_is_instance(&th->th_id, &linuxdvb_adapter_class)) continue;
la = (linuxdvb_adapter_t*)th;
LIST_FOREACH(lfe2, &la->la_frontends, lfe_link) {
if (lfe2 != lfe && lfe2->lfe_type == lfe->lfe_type) {
e = htsmsg_create_map();
htsmsg_add_str(e, "key", idnode_uuid_as_sstr(&lfe2->ti_id));
htsmsg_add_str(e, "val", lfe2->mi_name);
htsmsg_add_msg(m, NULL, e);
}
}
}
return m;
}

const idclass_t linuxdvb_frontend_dvbs_class =
{
.ic_super = &linuxdvb_frontend_class,
Expand All @@ -206,6 +232,34 @@ const idclass_t linuxdvb_frontend_dvbs_class =
.list = linuxdvb_satconf_type_list,
.def.s = "simple"
},
{
.type = PT_STR,
.id = "fe_master",
.name = N_("Master Tuner"),
.list = linuxdvb_frontend_dvbs_class_master_enum,
.off = offsetof(linuxdvb_frontend_t, lfe_master),
},
{
.id = "networks",
.type = PT_NONE,
},
{}
}
};

const idclass_t linuxdvb_frontend_dvbs_slave_class =
{
.ic_super = &linuxdvb_frontend_class,
.ic_class = "linuxdvb_frontend_dvbs",
.ic_caption = N_("Linux DVB-S Slave Frontend"),
.ic_properties = (const property_t[]){
{
.type = PT_STR,
.id = "fe_master",
.name = N_("Master Tuner"),
.list = linuxdvb_frontend_dvbs_class_master_enum,
.off = offsetof(linuxdvb_frontend_t, lfe_master),
},
{
.id = "networks",
.type = PT_NONE,
Expand Down Expand Up @@ -303,11 +357,37 @@ linuxdvb_frontend_get_grace ( mpegts_input_t *mi, mpegts_mux_t *mm )
static int
linuxdvb_frontend_is_enabled ( mpegts_input_t *mi, mpegts_mux_t *mm, int flags )
{
linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi;
linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi, *lfe2;
linuxdvb_adapter_t *la;
tvh_hardware_t *th;

if (lfe->lfe_fe_path == NULL) return 0;
if (!mpegts_input_is_enabled(mi, mm, flags)) return 0;
if (access(lfe->lfe_fe_path, R_OK | W_OK)) return 0;
if (lfe->lfe_in_setup) return 0;
if (lfe->lfe_type != DVB_TYPE_S) return 0;

/* check if any "blocking" tuner is running */
LIST_FOREACH(th, &tvh_hardware, th_link) {
if (!idnode_is_instance(&th->th_id, &linuxdvb_adapter_class)) continue;
la = (linuxdvb_adapter_t*)th;
LIST_FOREACH(lfe2, &la->la_frontends, lfe_link) {
if (lfe2 == lfe) continue;
if (lfe2->lfe_type != DVB_TYPE_S) continue;
if (lfe->lfe_master && !strcmp(lfe->lfe_master, idnode_uuid_as_sstr(&lfe2->ti_id))) {
if (lfe2->lfe_satconf == NULL)
return 0; /* invalid master */
return linuxdvb_satconf_match_mux(lfe2->lfe_satconf, mm);
}
if (lfe2->lfe_master &&
!strcmp(lfe2->lfe_master, idnode_uuid_as_sstr(&lfe->ti_id)) &&
lfe2->lfe_refcount > 0) {
if (lfe->lfe_satconf == NULL)
return 0;
return linuxdvb_satconf_match_mux(lfe->lfe_satconf, mm);
}
}
}
return 1;
}

Expand All @@ -316,8 +396,11 @@ linuxdvb_frontend_stop_mux
( mpegts_input_t *mi, mpegts_mux_instance_t *mmi )
{
char buf1[256], buf2[256];

linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi;
linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi, *lfe2;

if (lfe->lfe_master)
assert(lfe->lfe_type == DVB_TYPE_S);

mi->mi_display_name(mi, buf1, sizeof(buf1));
mpegts_mux_nice_name(mmi->mmi_mux, buf2, sizeof(buf2));
tvhdebug("linuxdvb", "%s - stopping %s", buf1, buf2);
Expand All @@ -340,9 +423,31 @@ linuxdvb_frontend_stop_mux
/* Ensure it won't happen immediately */
gtimer_arm(&lfe->lfe_monitor_timer, linuxdvb_frontend_monitor, lfe, 2);

if (lfe->lfe_satconf)
if (lfe->lfe_satconf && lfe->lfe_refcount == 1)
linuxdvb_satconf_post_stop_mux(lfe->lfe_satconf);

if (lfe->lfe_master) {
lfe2 = (linuxdvb_frontend_t *)idnode_find(lfe->lfe_master, &linuxdvb_frontend_class, NULL);
if (lfe2->lfe_type != lfe->lfe_type)
lfe2 = NULL;
if (lfe2) { /* master tuner shutdown procedure */
assert(lfe2->lfe_refcount >= 0);
if (--lfe2->lfe_refcount == 0) {
lfe2->lfe_ready = 0;
lfe2->lfe_locked = 0;
lfe2->lfe_status = 0;
lfe2->lfe_status2 = 0;
/* Ensure it won't happen immediately */
gtimer_arm(&lfe2->lfe_monitor_timer, linuxdvb_frontend_monitor, lfe, 2);
if (lfe2->lfe_satconf)
linuxdvb_satconf_post_stop_mux(lfe2->lfe_satconf);
lfe2->lfe_in_setup = 0;
lfe2->lfe_freq = 0;
}
}
}

lfe->lfe_refcount--;
lfe->lfe_in_setup = 0;
lfe->lfe_freq = 0;
mpegts_pid_done(&lfe->lfe_pids);
Expand All @@ -352,17 +457,47 @@ static int
linuxdvb_frontend_start_mux
( mpegts_input_t *mi, mpegts_mux_instance_t *mmi )
{
linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi;
int res;
linuxdvb_frontend_t *lfe = (linuxdvb_frontend_t*)mi, *lfe2;
int res, f;

assert(lfe->lfe_in_setup == 0);

lfe->lfe_refcount++;
lfe->lfe_in_setup = 1;
lfe->lfe_ioctls = 0;

if (lfe->lfe_master) {
assert(lfe->lfe_type == DVB_TYPE_S);
lfe2 = (linuxdvb_frontend_t *)idnode_find(lfe->lfe_master, &linuxdvb_frontend_class, NULL);
if (lfe2->lfe_type != lfe->lfe_type)
lfe2 = NULL;
res = SM_CODE_TUNING_FAILED;
if (lfe2) {
f = linuxdvb_satconf_lnb_freq(lfe2->lfe_satconf, mmi);
if (f <= 0)
goto end;
if (lfe2->lfe_refcount++ == 0) {
lfe2->lfe_in_setup = 1;
lfe2->lfe_ioctls = 0;
res = linuxdvb_satconf_start_mux(lfe2->lfe_satconf, mmi, 0);
if (res)
goto end;
}
res = linuxdvb_frontend_tune1((linuxdvb_frontend_t*)mi, mmi, f);
}
goto end;
}

if (lfe->lfe_satconf)
res = linuxdvb_satconf_start_mux(lfe->lfe_satconf, mmi);
res = linuxdvb_satconf_start_mux(lfe->lfe_satconf, mmi, lfe->lfe_refcount > 1);
else
res = linuxdvb_frontend_tune1((linuxdvb_frontend_t*)mi, mmi, -1);
if (res)

end:
if (res) {
lfe->lfe_in_setup = 0;
lfe->lfe_refcount--;
}
return res;
}

Expand Down Expand Up @@ -459,7 +594,7 @@ linuxdvb_frontend_monitor ( void *aux )
mmi->mmi_mux->mm_stop(mmi->mmi_mux, 1, SM_CODE_ABORTED);

/* Close FE */
if (lfe->lfe_fe_fd > 0 && !mmi && lfe->lfe_powersave) {
if (lfe->lfe_fe_fd > 0 && !lfe->lfe_refcount && lfe->lfe_powersave) {
tvhtrace("linuxdvb", "%s - closing frontend", buf);
close(lfe->lfe_fe_fd);
lfe->lfe_fe_fd = -1;
Expand Down Expand Up @@ -1116,6 +1251,7 @@ linuxdvb_frontend_clear

/* Open FE */
lfe->mi_display_name((mpegts_input_t*)lfe, buf1, sizeof(buf1));
tvhtrace("linuxdvb", "%s - frontend clear", buf1);

if (lfe->lfe_fe_fd <= 0) {
lfe->lfe_fe_fd = tvh_open(lfe->lfe_fe_path, O_RDWR | O_NONBLOCK, 0);
Expand Down Expand Up @@ -1513,11 +1649,19 @@ linuxdvb_frontend_create
dvb_fe_type_t type, const char *name )
{
const idclass_t *idc;
const char *str, *uuid = NULL, *scuuid = NULL, *sctype = NULL;
char id[12], lname[256];
const char *str, *uuid = NULL, *muuid = NULL, *scuuid = NULL, *sctype = NULL;
char id[16], lname[256];
linuxdvb_frontend_t *lfe;
htsmsg_t *scconf = NULL;

/* Tuner slave */
snprintf(id, sizeof(id), "master for #%d", number);
if (conf && type == DVB_TYPE_S) {
muuid = htsmsg_get_str(conf, id);
if (muuid && uuid && !strcmp(muuid, uuid))
muuid = NULL;
}

/* Internal config ID */
snprintf(id, sizeof(id), "%s #%d", dvb_type2str(type), number);
if (conf)
Expand All @@ -1537,7 +1681,8 @@ linuxdvb_frontend_create

/* Class */
if (type == DVB_TYPE_S)
idc = &linuxdvb_frontend_dvbs_class;
idc = muuid ? &linuxdvb_frontend_dvbs_slave_class :
&linuxdvb_frontend_dvbs_class;
else if (type == DVB_TYPE_C)
idc = &linuxdvb_frontend_dvbc_class;
else if (type == DVB_TYPE_T)
Expand All @@ -1555,7 +1700,8 @@ linuxdvb_frontend_create
// in mpegts_input_create()). So we must set early.
lfe = calloc(1, sizeof(linuxdvb_frontend_t));
lfe->lfe_number = number;
lfe->lfe_type = type;
lfe->lfe_type = type;
lfe->lfe_master = muuid ? strdup(muuid) : NULL;
strncpy(lfe->lfe_name, name, sizeof(lfe->lfe_name));
lfe->lfe_name[sizeof(lfe->lfe_name)-1] = '\0';
lfe->lfe_ibuf_size = 18800;
Expand Down Expand Up @@ -1598,15 +1744,15 @@ linuxdvb_frontend_create
mpegts_pid_init(&lfe->lfe_pids);

/* Satconf */
if (conf) {
if (conf && !muuid) {
if ((scconf = htsmsg_get_map(conf, "satconf"))) {
sctype = htsmsg_get_str(scconf, "type");
scuuid = htsmsg_get_str(scconf, "uuid");
}
}

/* Create satconf */
if (lfe->lfe_type == DVB_TYPE_S && !lfe->lfe_satconf)
if (lfe->lfe_type == DVB_TYPE_S && !lfe->lfe_satconf && !muuid)
lfe->lfe_satconf = linuxdvb_satconf_create(lfe, sctype, scuuid, scconf);

/* Double check enabled */
Expand All @@ -1618,23 +1764,29 @@ linuxdvb_frontend_create
void
linuxdvb_frontend_save ( linuxdvb_frontend_t *lfe, htsmsg_t *fe )
{
char id[12];
char id[16];
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_type));
htsmsg_add_str(m, "uuid", idnode_uuid_as_sstr(&lfe->ti_id));
if (lfe->lfe_satconf) {
if (lfe->lfe_satconf && !lfe->lfe_master) {
htsmsg_t *s = htsmsg_create_map();
linuxdvb_satconf_save(lfe->lfe_satconf, s);
htsmsg_add_str(s, "uuid", idnode_uuid_as_sstr(&lfe->lfe_satconf->ls_id));
htsmsg_add_msg(m, "satconf", s);
}
htsmsg_delete_field(m, "fe_master");

/* Add to list */
snprintf(id, sizeof(id), "%s #%d", dvb_type2str(lfe->lfe_type), lfe->lfe_number);
htsmsg_add_msg(fe, id, m);

if (lfe->lfe_master) {
snprintf(id, sizeof(id), "master for #%d", lfe->lfe_number);
htsmsg_add_str(fe, id, lfe->lfe_master);
}
}

void
Expand All @@ -1659,6 +1811,7 @@ linuxdvb_frontend_delete ( linuxdvb_frontend_t *lfe )
free(lfe->lfe_fe_path);
free(lfe->lfe_dmx_path);
free(lfe->lfe_dvr_path);
free(lfe->lfe_master);

/* Delete satconf */
if (lfe->lfe_satconf)
Expand Down

0 comments on commit ac47b98

Please sign in to comment.