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++; } }
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); }
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; }
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 */ } }
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; }
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; }
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; }
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; }
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; }
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; }
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); }
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); }
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; }
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; }