Exemplo n.º 1
0
void dvb_desc_service_location_init(struct dvb_v5_fe_parms *parms, const uint8_t *buf, struct dvb_desc *desc)
{
	struct dvb_desc_service_location *service_location = (struct dvb_desc_service_location *) desc;
	uint8_t *endbuf = buf + desc->length;
	ssize_t size = sizeof(struct dvb_desc_service_location) - sizeof(struct dvb_desc);
	struct dvb_desc_service_location_element *element;
	int i;

	if (buf + size > endbuf) {
		dvb_logerr("%s: short read %d/%zd bytes", __FUNCTION__, endbuf - buf, size);
		return;
	}

	memcpy(desc->data, buf, size);
	bswap16(service_location->bitfield);
	buf += size;

	if (service_location->elements == 0)
		return;

	size = service_location->elements * sizeof(struct dvb_desc_service_location_element);
	if (buf + size > endbuf) {
		dvb_logerr("%s: short read %d/%zd bytes", __FUNCTION__, endbuf - buf, size);
		return;
	}
	service_location->element = malloc(size);
	element = service_location->element;
	for (i = 0; i < service_location->elements; i++) {
		memcpy(element, buf, sizeof(struct dvb_desc_service_location_element) - 1); /* no \0 in lang */
		buf += sizeof(struct dvb_desc_service_location_element) - 1;
		element->language[3] = '\0';
		bswap16(element->bitfield);
		element++;
	}
}
Exemplo n.º 2
0
void dvb_table_sdt_init(struct dvb_v5_fe_parms *parms, const uint8_t *buf,
			ssize_t buflen, uint8_t *table, ssize_t *table_length)
{
	const uint8_t *p = buf, *endbuf = buf + buflen - 4;
	struct dvb_table_sdt *sdt = (void *)table;
	struct dvb_table_sdt_service **head = &sdt->service;
	size_t size = offsetof(struct dvb_table_sdt, service);

	if (*table_length > 0) {
		/* find end of curent list */
		while (*head != NULL)
			head = &(*head)->next;
	} else {
		if (p + size > endbuf) {
			dvb_logerr("SDT table was truncated. Need %zu bytes, but has only %zu.",
					size, buflen);
			return;
		}
		memcpy(sdt, p, size);
		*table_length = sizeof(struct dvb_table_sdt);

		bswap16(sdt->network_id);

		sdt->service = NULL;
	}
	p += size;

	size = offsetof(struct dvb_table_sdt_service, descriptor);
	while (p + size <= endbuf) {
		struct dvb_table_sdt_service *service;

		service = malloc(sizeof(struct dvb_table_sdt_service));

		memcpy(service, p, size);
		p += size;

		bswap16(service->service_id);
		bswap16(service->bitfield);
		service->descriptor = NULL;
		service->next = NULL;

		*head = service;
		head = &(*head)->next;

		/* get the descriptors for each program */
		dvb_parse_descriptors(parms, p, service->section_length,
				      &service->descriptor);

		p += service->section_length;
	}
	if (endbuf - p)
		dvb_logerr("PAT table has %zu spurious bytes at the end.",
			   endbuf - p);
}
Exemplo n.º 3
0
ssize_t dvb_mpeg_ts_init(struct dvb_v5_fe_parms *parms, const uint8_t *buf, ssize_t buflen, uint8_t *table, ssize_t *table_length)
{
	struct dvb_mpeg_ts *ts = (struct dvb_mpeg_ts *) table;
	const uint8_t *p = buf;

	if (buf[0] != DVB_MPEG_TS) {
		dvb_logerr("mpeg ts invalid marker 0x%02x, sould be 0x%02x", buf[0], DVB_MPEG_TS);
		*table_length = 0;
		return -1;
	}

	memcpy(table, p, sizeof(struct dvb_mpeg_ts));
	p += sizeof(struct dvb_mpeg_ts);

	bswap16(ts->bitfield);

	if (ts->adaptation_field) {
		memcpy(ts->adaption, p, sizeof(struct dvb_mpeg_ts_adaption));
		p += ts->adaption->length + 1;
		/* FIXME: copy adaption->lenght bytes */
	}

	*table_length = p - buf;
	return p - buf;
}
Exemplo n.º 4
0
void dvb_parse_descriptors(struct dvb_v5_fe_parms *parms, const uint8_t *buf, uint16_t section_length, struct dvb_desc **head_desc)
{
	const uint8_t *ptr = buf;
	struct dvb_desc *current = NULL;
	struct dvb_desc *last = NULL;
	while (ptr < buf + section_length) {
		int desc_type = ptr[0];
		int desc_len  = ptr[1];
		size_t size;
		dvb_desc_init_func init = dvb_descriptors[desc_type].init;
		if (!init) {
			init = dvb_desc_default_init;
			size = sizeof(struct dvb_desc) + desc_len;
		} else {
			size = dvb_descriptors[desc_type].size;
		}
		if (!size) {
			dvb_logerr("descriptor type %d has no size defined", current->type);
			size = 4096;
		}
		current = (struct dvb_desc *) malloc(size);
		ptr += dvb_desc_init(ptr, current); /* the standard header was read */
		init(parms, ptr, current);
		if(!*head_desc)
			*head_desc = current;
		if (last)
			last->next = current;
		last = current;
		ptr += current->length;     /* standard descriptor header plus descriptor length */
	}
}
Exemplo n.º 5
0
int dvb_fe_store_parm(struct dvb_v5_fe_parms *p,
			     unsigned cmd, uint32_t value)
{
	struct dvb_v5_fe_parms_priv *parms = (void *)p;
	int i;
	for (i = 0; i < parms->n_props; i++) {
		if (parms->dvb_prop[i].cmd != cmd)
			continue;
		parms->dvb_prop[i].u.data = value;
		return 0;
	}
	dvb_logerr(_("command %s (%d) not found during store"),
		dvb_cmd_name(cmd), cmd);

	return EINVAL;
}
Exemplo n.º 6
0
struct dtv_stats *dvb_fe_retrieve_stats_layer(struct dvb_v5_fe_parms *p,
					      unsigned cmd, unsigned layer)
{
	struct dvb_v5_fe_parms_priv *parms = (void *)p;
	int i;

	if (cmd == DTV_BER && parms->p.has_v5_stats)
		return dvb_fe_retrieve_v5_BER(parms, layer);

	for (i = 0; i < DTV_NUM_STATS_PROPS; i++) {
		if (parms->stats.prop[i].cmd != cmd)
			continue;
		if (layer >= parms->stats.prop[i].u.st.len)
			return NULL;
		return &parms->stats.prop[i].u.st.stat[layer];
	}
	dvb_logerr(_("%s not found on retrieve"), dvb_cmd_name(cmd));

	return NULL;
}
Exemplo n.º 7
0
static struct dtv_stats *dvb_fe_store_stats(struct dvb_v5_fe_parms_priv *parms,
			      unsigned cmd,
			      enum fecap_scale_params scale,
			      unsigned layer,
			      uint32_t value)
{
	int i;

	for (i = 0; i < DTV_NUM_STATS_PROPS; i++) {
		if (parms->stats.prop[i].cmd != cmd)
			continue;
		parms->stats.prop[i].u.st.stat[layer].scale = scale;
		parms->stats.prop[i].u.st.stat[layer].uvalue = value;
		if (parms->stats.prop[i].u.st.len < layer + 1)
			parms->stats.prop[i].u.st.len = layer + 1;
		return &parms->stats.prop[i].u.st.stat[layer];
	}
	dvb_logerr(_("%s not found on store"), dvb_cmd_name(cmd));

	return NULL;
}
Exemplo n.º 8
0
int isdb_desc_partial_reception_init(struct dvb_v5_fe_parms *parms,
                                     const uint8_t *buf, struct dvb_desc *desc)
{
    struct isdb_desc_partial_reception *d = (void *)desc;
    unsigned char *p = (unsigned char *)buf;
    size_t len;
    int i;

    d->partial_reception = malloc(d->length);
    if (!d->partial_reception) {
        dvb_logerr("%s: out of memory", __func__);
        return -1;
    }

    memcpy(d->partial_reception, p, d->length);

    len = d->length / sizeof(*d->partial_reception);

    for (i = 0; i < len; i++)
        bswap16(d->partial_reception[i].service_id);
    return 0;
}
Exemplo n.º 9
0
int dvb_desc_logical_channel_init(struct dvb_v5_fe_parms *parms,
			      const uint8_t *buf, struct dvb_desc *desc)
{
	struct dvb_desc_logical_channel *d = (void *)desc;
	unsigned char *p = (unsigned char *)buf;
	size_t len;
	int i;

	d->lcn = malloc(d->length);
	if (!d->lcn) {
		dvb_logerr("%s: out of memory", __func__);
		return -1;
	}

	memcpy(d->lcn, p, d->length);

	len = d->length / sizeof(d->lcn);

	for (i = 0; i < len; i++) {
		bswap16(d->lcn[i].service_id);
		bswap16(d->lcn[i].bitfield);
	}
	return 0;
}
Exemplo n.º 10
0
ssize_t atsc_table_eit_init(struct dvb_v5_fe_parms *parms, const uint8_t *buf,
		ssize_t buflen, struct atsc_table_eit **table)
{
	const uint8_t *p = buf, *endbuf = buf + buflen;
	struct atsc_table_eit *eit;
	struct atsc_table_eit_event **head;
	size_t size;
	int i = 0;

	size = offsetof(struct atsc_table_eit, event);
	if (p + size > endbuf) {
		dvb_logerr("%s: short read %zd/%zd bytes", __func__,
			   endbuf - p, size);
		return -1;
	}

	if (buf[0] != ATSC_TABLE_EIT) {
		dvb_logerr("%s: invalid marker 0x%02x, sould be 0x%02x",
				__func__, buf[0], ATSC_TABLE_EIT);
		return -2;
	}

	if (!*table) {
		*table = calloc(sizeof(struct atsc_table_eit), 1);
		if (!*table) {
			dvb_logerr("%s: out of memory", __func__);
			return -3;
		}
	}
	eit = *table;
	memcpy(eit, p, size);
	p += size;
	dvb_table_header_init(&eit->header);

	/* find end of curent list */
	head = &eit->event;
	while (*head != NULL)
		head = &(*head)->next;

	while (i++ < eit->events && p < endbuf) {
		struct atsc_table_eit_event *event;
                union atsc_table_eit_desc_length dl;

		size = offsetof(struct atsc_table_eit_event, descriptor);
		if (p + size > endbuf) {
			dvb_logerr("%s: short read %zd/%zd bytes", __func__,
				   endbuf - p, size);
			return -4;
		}
		event = (struct atsc_table_eit_event *) malloc(sizeof(struct atsc_table_eit_event));
		if (!event) {
			dvb_logerr("%s: out of memory", __func__);
			return -5;
		}
		memcpy(event, p, size);
		p += size;

		bswap16(event->bitfield);
		bswap32(event->start_time);
		bswap32(event->bitfield2);
		event->descriptor = NULL;
		event->next = NULL;
                atsc_time(event->start_time, &event->start);
		event->source_id = eit->header.id;

		*head = event;
		head = &(*head)->next;

		size = event->title_length - 1;
		if (p + size > endbuf) {
			dvb_logerr("%s: short read %zd/%zd bytes", __func__,
				   endbuf - p, size);
			return -6;
		}
                /* TODO: parse title */
                p += size;

		/* get the descriptors for each program */
		size = sizeof(union atsc_table_eit_desc_length);
		if (p + size > endbuf) {
			dvb_logerr("%s: short read %zd/%zd bytes", __func__,
				   endbuf - p, size);
			return -7;
		}
		memcpy(&dl, p, size);
                p += size;
                bswap16(dl.bitfield);

		size = dl.desc_length;
		if (p + size > endbuf) {
			dvb_logerr("%s: short read %zd/%zd bytes", __func__,
				   endbuf - p, size);
			return -8;
		}
		if (dvb_desc_parse(parms, p, size,
					&event->descriptor) != 0 ) {
			return -9;
		}

		p += size;
	}

	return p - buf;
}
Exemplo n.º 11
0
void atsc_table_vct_init(struct dvb_v5_fe_parms *parms, const uint8_t *buf,
			ssize_t buflen, uint8_t *table, ssize_t *table_length)
{
	const uint8_t *p = buf, *endbuf = buf + buflen - 4;
	struct atsc_table_vct *vct = (void *)table;
	struct atsc_table_vct_channel **head = &vct->channel;
	int i, n;
	size_t size = offsetof(struct atsc_table_vct, channel);

	if (p + size > endbuf) {
		dvb_logerr("VCT table was truncated. Need %zu bytes, but has only %zu.",
			   size, buflen);
		return;
	}

	if (*table_length > 0) {
		/* find end of curent list */
		while (*head != NULL)
			head = &(*head)->next;
	} else {
		memcpy(vct, p, size);

		*table_length = sizeof(struct atsc_table_vct);

		vct->channel = NULL;
		vct->descriptor = NULL;
	}
	p += size;

	size = offsetof(struct atsc_table_vct_channel, descriptor);
	for (n = 0; n < vct->num_channels_in_section; n++) {
		struct atsc_table_vct_channel *channel;

		if (p + size > endbuf) {
			dvb_logerr("VCT channel table is missing %d elements",
				   vct->num_channels_in_section - n + 1);
			vct->num_channels_in_section = n;
			break;
		}

		channel = malloc(sizeof(struct atsc_table_vct_channel));

		memcpy(channel, p, size);
		p += size;

		/* Fix endiannes of the copied fields */
		for (i = 0; i < ARRAY_SIZE(channel->__short_name); i++)
			bswap16(channel->__short_name[i]);

		bswap32(channel->carrier_frequency);
		bswap16(channel->channel_tsid);
		bswap16(channel->program_number);
		bswap32(channel->bitfield1);
		bswap16(channel->bitfield2);
		bswap16(channel->source_id);
		bswap16(channel->bitfield3);

		/* Short name is always UTF-16 */
		iconv_to_charset(parms, channel->short_name,
				 sizeof(channel->short_name),
				 (const unsigned char *)channel->__short_name,
				 sizeof(channel->__short_name),
				 "UTF-16",
				 output_charset);

		/* Fill descriptors */

		channel->descriptor = NULL;
		channel->next = NULL;

		*head = channel;
		head = &(*head)->next;

		/* get the descriptors for each program */
		dvb_parse_descriptors(parms, p, channel->descriptors_length,
				      &channel->descriptor);

		p += channel->descriptors_length;
	}

	/* Get extra descriptors */
	size = sizeof(union atsc_table_vct_descriptor_length);
	while (p + size <= endbuf) {
		union atsc_table_vct_descriptor_length *d = (void *)p;
		bswap16(d->descriptor_length);
		p += size;
		dvb_parse_descriptors(parms, p, d->descriptor_length,
				      &vct->descriptor);
	}
	if (endbuf - p)
		dvb_logerr("VCT table has %zu spurious bytes at the end.",
			   endbuf - p);
}
Exemplo n.º 12
0
static int dev_set_parms(uint32_t seq, char *cmd, int fd,
			 char *buf, ssize_t size)
{
	struct dvb_v5_fe_parms_priv *parms = (void *)dvb->fe_parms;
	struct dvb_v5_fe_parms *par = (void *)parms;
	int ret, i;
	char *p = buf;
	const char *old_lnb = "";
	char new_lnb[256];

	if (verbose)
		dbg("dev_set_parms called");

	/* first the public params that aren't read only */

	/* Get current LNB name */
	if (par->lnb)
		old_lnb = par->lnb->name;

	ret = scan_data(p, size, "%i%i%s%i%i%i%i%s%s",
			&par->abort, &par->lna, new_lnb,
			&par->sat_number, &par->freq_bpf, &par->diseqc_wait,
			&par->verbose, default_charset, output_charset);

	if (ret < 0)
		goto error;

	p += ret;
	size -= ret;

	/* Now, the private ones */

	ret = scan_data(p, size, "%i", &i);
	if (ret < 0)
		goto error;
	parms->country = i;

	p += ret;
	size -= ret;

	for (i = 0; i < parms->n_props; i++) {
		ret = scan_data(p, size, "%i%i",
				&parms->dvb_prop[i].cmd,
				&parms->dvb_prop[i].u.data);
		if (ret < 0)
			goto error;

		p += ret;
		size -= ret;
	}

	if (!*new_lnb) {
		par->lnb = NULL;
	} else if (strcmp(old_lnb, new_lnb)) {
		int lnb = dvb_sat_search_lnb(new_lnb);

		if (lnb < 0) {
			dvb_logerr("Invalid lnb: %s", new_lnb);
			ret = -1;
			goto error;
		}

		par->lnb = dvb_sat_get_lnb(lnb);
	}

	par->output_charset = output_charset;
	par->default_charset = default_charset;

	ret = __dvb_fe_set_parms(par);

error:
	return send_data(fd, "%i%s%i", seq, cmd, ret);
}
Exemplo n.º 13
0
int dvb_fe_snprintf_stat(struct dvb_v5_fe_parms *p, uint32_t cmd,
			  char *display_name, int layer,
		          char **buf, int *len, int *show_layer_name)
{
	struct dvb_v5_fe_parms_priv *parms = (void *)p;
	struct dtv_stats *stat = NULL;
	enum dvb_quality qual = DVB_QUAL_UNKNOWN;
	enum fecap_scale_params scale;
	float val = -1;
	int initial_len = *len;
	int size, i;

	/* Print status, if layer == 0, as there is only global status */
	if (cmd == DTV_STATUS) {
		fe_status_t status;

		if (layer)
			return 0;

		if (dvb_fe_retrieve_stats(&parms->p, DTV_STATUS, &status)) {
			dvb_logerr (_("Error: no adapter status"));
			return -1;
		}
		if (display_name) {
			size = snprintf(*buf, *len, " %s=", display_name);
			*buf += size;
			*len -= size;
		}

		/* Get the name of the highest status bit */
		for (i = ARRAY_SIZE(sig_bits) - 1; i >= 0 ; i--) {
			if ((1 << i) & status) {
				size = snprintf(*buf, *len, _("%-7s"), _(sig_bits[i]));
				*buf += size;
				*len -= size;
				break;
			}
		}
		if (i < 0) {
			size = snprintf(*buf, *len, _("%7s"), "");
			*buf += size;
			*len -= size;
		}

		/* Add the status bits */
		size = snprintf(*buf, *len, "(0x%02x)", status);
		*buf += size;
		*len -= size;

		return initial_len - *len;
	}

	/* Retrieve the statistics */
	switch (cmd) {
	case DTV_PRE_BER:
		val = calculate_preBER(parms, layer);
		if (val < 0)
			return 0;
		scale = FE_SCALE_COUNTER;
		break;
	case DTV_BER:
		val = dvb_fe_retrieve_ber(&parms->p, layer, &scale);
		if (scale == FE_SCALE_NOT_AVAILABLE)
			return 0;
		break;
	case DTV_PER:
		val = dvb_fe_retrieve_per(&parms->p, layer);
		if (val < 0)
			return 0;
		scale = FE_SCALE_COUNTER;
		break;
	case DTV_QUALITY:
		qual = dvb_fe_retrieve_quality(&parms->p, layer);
		if (qual == DVB_QUAL_UNKNOWN)
			return 0;
		break;
	default:
		stat = dvb_fe_retrieve_stats_layer(&parms->p, cmd, layer);
		if (!stat || stat->scale == FE_SCALE_NOT_AVAILABLE)
			return 0;
	}

	/* If requested, prints the layer name */
	if (*show_layer_name && layer) {
		size = snprintf(*buf, *len, _("  Layer %c:"), 'A' + layer - 1);
		*buf += size;
		*len -= size;
		*show_layer_name = 0;
	}
	if (display_name) {
		size = snprintf(*buf, *len, " %s=", display_name);
		*buf += size;
		*len -= size;
	}

	/* Quality measure */
	if (qual != DVB_QUAL_UNKNOWN) {
		size = snprintf(*buf, *len, " %-4s", _(qual_name[qual]));
		*buf += size;
		*len -= size;
		return initial_len - *len;
	}


	/* Special case: float point measures like BER/PER */
	if (!stat) {
		switch (scale) {
		case FE_SCALE_RELATIVE:
			size = snprintf(*buf, *len, " %u", (unsigned int)val);
			break;
		case FE_SCALE_COUNTER:
			size = dvb_fe_snprintf_eng(*buf, *len, val);
			break;
		default:
			size = 0;
		}
		*buf += size;
		*len -= size;
		return initial_len - *len;
	}

	/* Prints the scale */
	switch (stat->scale) {
	case FE_SCALE_DECIBEL:
		if (cmd == DTV_STAT_SIGNAL_STRENGTH)
			size = snprintf(*buf, *len, " %.2fdBm", stat->svalue / 1000.);
		else
			size = snprintf(*buf, *len, " %.2fdB", stat->svalue / 1000.);
		break;
	case FE_SCALE_RELATIVE:
		size = snprintf(*buf, *len, " %3.2f%%", (100 * stat->uvalue) / 65535.);
		break;
	case FE_SCALE_COUNTER:
		size = snprintf(*buf, *len, " %" PRIu64, (uint64_t)stat->uvalue);
		break;
	default:
		size = 0;
	}
	*buf += size;
	*len -= size;

	return initial_len - *len;
}
Exemplo n.º 14
0
struct dvb_v5_fe_parms *dvb_fe_open_flags(int adapter, int frontend,
					  unsigned verbose,
					  unsigned use_legacy_call,
					  dvb_logfunc logfunc,
					  int flags)
{
	int fd, i, r;
	char *fname;
	struct dtv_properties dtv_prop;
	struct dvb_v5_fe_parms_priv *parms = NULL;

	libdvbv5_initialize();

	if (logfunc == NULL)
		logfunc = dvb_default_log;

	r = asprintf(&fname, "/dev/dvb/adapter%i/frontend%i", adapter, frontend);
	if (r < 0) {
		logfunc(LOG_ERR, _("asprintf error"));
		return NULL;
	}
	if (!fname) {
		logfunc(LOG_ERR, _("fname calloc: %s"), strerror(errno));
		return NULL;
	}

	fd = open(fname, flags, 0);
	if (fd == -1) {
		logfunc(LOG_ERR, _("%s while opening %s"), strerror(errno), fname);
		free(fname);
		return NULL;
	}
	parms = calloc(sizeof(*parms), 1);
	if (!parms) {
		logfunc(LOG_ERR, _("parms calloc: %s"), strerror(errno));
		close(fd);
		free(fname);
		return NULL;
	}
	parms->fname = fname;
	parms->fd = fd;
	parms->fe_flags = flags;
	parms->p.verbose = verbose;
	parms->p.default_charset = "iso-8859-1";
	parms->p.output_charset = "utf-8";
	parms->p.logfunc = logfunc;
	parms->p.lna = LNA_AUTO;
	parms->p.sat_number = -1;
	parms->p.abort = 0;
	parms->country = COUNTRY_UNKNOWN;

	if (xioctl(fd, FE_GET_INFO, &parms->p.info) == -1) {
		dvb_perror("FE_GET_INFO");
		dvb_v5_free(parms);
		close(fd);
		free(fname);
		return NULL;
	}

	if (verbose) {
		fe_caps_t caps = parms->p.info.caps;

		dvb_log(_("Device %s (%s) capabilities:"),
			parms->p.info.name, fname);
		for (i = 0; i < ARRAY_SIZE(fe_caps_name); i++) {
			if (caps & fe_caps_name[i].idx)
				dvb_log ("     %s", fe_caps_name[i].name);
		}
	}

	parms->dvb_prop[0].cmd = DTV_API_VERSION;
	parms->dvb_prop[1].cmd = DTV_DELIVERY_SYSTEM;

	dtv_prop.num = 2;
	dtv_prop.props = parms->dvb_prop;

	/* Detect a DVBv3 device */
	if (xioctl(fd, FE_GET_PROPERTY, &dtv_prop) == -1) {
		parms->dvb_prop[0].u.data = 0x300;
		parms->dvb_prop[1].u.data = SYS_UNDEFINED;
	}

	parms->p.version = parms->dvb_prop[0].u.data;
	parms->p.current_sys = parms->dvb_prop[1].u.data;
	if (verbose)
		dvb_log (_("DVB API Version %d.%d%s, Current v5 delivery system: %s"),
			parms->p.version / 256,
			parms->p.version % 256,
			use_legacy_call ? _(" (forcing DVBv3 calls)") : "",
			delivery_system_name[parms->p.current_sys]);

	if (parms->p.version < 0x500)
		use_legacy_call = 1;

	if (parms->p.version >= 0x50a)
		parms->p.has_v5_stats = 1;
	else
		parms->p.has_v5_stats = 0;

	if (use_legacy_call || parms->p.version < 0x505) {
		parms->p.legacy_fe = 1;
		switch(parms->p.info.type) {
		case FE_QPSK:
			parms->p.current_sys = SYS_DVBS;
			parms->p.systems[parms->p.num_systems++] = parms->p.current_sys;
			if (parms->p.version < 0x0500)
				break;
			if (parms->p.info.caps & FE_CAN_2G_MODULATION)
				parms->p.systems[parms->p.num_systems++] = SYS_DVBS2;
			if (parms->p.info.caps & FE_CAN_TURBO_FEC)
				parms->p.systems[parms->p.num_systems++] = SYS_TURBO;
			break;
		case FE_QAM:
			parms->p.current_sys = SYS_DVBC_ANNEX_A;
			parms->p.systems[parms->p.num_systems++] = parms->p.current_sys;
			break;
		case FE_OFDM:
			parms->p.current_sys = SYS_DVBT;
			parms->p.systems[parms->p.num_systems++] = parms->p.current_sys;
			if (parms->p.version < 0x0500)
				break;
			if (parms->p.info.caps & FE_CAN_2G_MODULATION)
				parms->p.systems[parms->p.num_systems++] = SYS_DVBT2;
			break;
		case FE_ATSC:
			if (parms->p.info.caps & (FE_CAN_8VSB | FE_CAN_16VSB))
				parms->p.systems[parms->p.num_systems++] = SYS_ATSC;
			if (parms->p.info.caps & (FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_QAM_AUTO))
				parms->p.systems[parms->p.num_systems++] = SYS_DVBC_ANNEX_B;
			parms->p.current_sys = parms->p.systems[0];
			break;
		}
		if (!parms->p.num_systems) {
			dvb_logerr(_("delivery system not detected"));
			dvb_v5_free(parms);
			close(fd);
			return NULL;
		}
	} else {
		parms->dvb_prop[0].cmd = DTV_ENUM_DELSYS;
		parms->n_props = 1;
		dtv_prop.num = 1;
		dtv_prop.props = parms->dvb_prop;
		if (xioctl(fd, FE_GET_PROPERTY, &dtv_prop) == -1) {
			dvb_perror("FE_GET_PROPERTY");
			dvb_v5_free(parms);
			close(fd);
			return NULL;
		}
		parms->p.num_systems = parms->dvb_prop[0].u.buffer.len;
		for (i = 0; i < parms->p.num_systems; i++)
			parms->p.systems[i] = parms->dvb_prop[0].u.buffer.data[i];

		if (parms->p.num_systems == 0) {
			dvb_logerr(_("driver returned 0 supported delivery systems!"));
			dvb_v5_free(parms);
			close(fd);
			return NULL;
		}
	}

	if (verbose) {
		dvb_log(_("Supported delivery system%s: "),
		       (parms->p.num_systems > 1) ? "s" : "");
		for (i = 0; i < parms->p.num_systems; i++) {
			if (parms->p.systems[i] == parms->p.current_sys)
				dvb_log ("    [%s]",
					delivery_system_name[parms->p.systems[i]]);
			else
				dvb_log ("     %s",
					delivery_system_name[parms->p.systems[i]]);
		}
		if (use_legacy_call || parms->p.version < 0x505)
			dvb_log(_("Warning: new delivery systems like ISDB-T, ISDB-S, DMB-TH, DSS, ATSC-MH will be miss-detected by a DVBv5.4 or earlier API call"));
	}

	/*
	 * Fix a bug at some DVB drivers
	 */
	if (parms->p.current_sys == SYS_UNDEFINED)
		parms->p.current_sys = parms->p.systems[0];

	/* Prepare to use the delivery system */
	parms->n_props = dvb_add_parms_for_sys(&parms->p, parms->p.current_sys);

	if ((flags & O_ACCMODE) == O_RDWR)
		dvb_set_sys(&parms->p, parms->p.current_sys);

	/*
	 * Prepare the status struct - DVBv5.10 parameters should
	 * come first, as they'll be read together.
	 */
	parms->stats.prop[0].cmd = DTV_STAT_SIGNAL_STRENGTH;
	parms->stats.prop[1].cmd = DTV_STAT_CNR;
	parms->stats.prop[2].cmd = DTV_STAT_PRE_ERROR_BIT_COUNT;
	parms->stats.prop[3].cmd = DTV_STAT_PRE_TOTAL_BIT_COUNT;
	parms->stats.prop[4].cmd = DTV_STAT_POST_ERROR_BIT_COUNT;
	parms->stats.prop[5].cmd = DTV_STAT_POST_TOTAL_BIT_COUNT;
	parms->stats.prop[6].cmd = DTV_STAT_ERROR_BLOCK_COUNT;
	parms->stats.prop[7].cmd = DTV_STAT_TOTAL_BLOCK_COUNT;

	/* Now, status and the calculated stats */
	parms->stats.prop[8].cmd = DTV_STATUS;
	parms->stats.prop[9].cmd = DTV_BER;
	parms->stats.prop[10].cmd = DTV_PER;
	parms->stats.prop[11].cmd = DTV_QUALITY;
	parms->stats.prop[12].cmd = DTV_PRE_BER;

	return &parms->p;
}