[v4l-utils] Add a few libv4l2rds patches from upstream, which bring libv4l2rds to its

Hans de Goede jwrdegoede at fedoraproject.org
Fri Jun 14 11:12:36 UTC 2013


commit fedd942e6b00628af618a21b3c4d09022450492c
Author: Hans de Goede <hdegoede at redhat.com>
Date:   Fri Jun 14 13:12:20 2013 +0200

    Add a few libv4l2rds patches from upstream, which bring libv4l2rds to its
    
      final API / ABI, so that apps build against it won't need a rebuild in the
      future

 0001-rds-ctl-fix-percentage-handling.patch         |   49 ++
 ...l2rds-support-RDS-EON-and-TMC-tuning-info.patch |  614 ++++++++++++++++++++
 ...s-ctl-support-RDS-EON-and-TMC-tuning-info.patch |  124 ++++
 ...c-moving-functions-to-get-rid-of-declarat.patch |  297 ++++++++++
 0005-rds-ctl-support-d10-to-refer-to-radio10.patch |   43 ++
 ...-logging-of-dqbuf-timestamps-to-debug-log.patch |   31 +
 v4l-utils.spec                                     |   19 +-
 7 files changed, 1176 insertions(+), 1 deletions(-)
---
diff --git a/0001-rds-ctl-fix-percentage-handling.patch b/0001-rds-ctl-fix-percentage-handling.patch
new file mode 100644
index 0000000..ad0b634
--- /dev/null
+++ b/0001-rds-ctl-fix-percentage-handling.patch
@@ -0,0 +1,49 @@
+From 3941ad41dc97bea2a87c3a9e165a251eb551c54f Mon Sep 17 00:00:00 2001
+From: Hans Verkuil <hans.verkuil at cisco.com>
+Date: Sun, 2 Jun 2013 13:32:01 +0200
+Subject: [PATCH 1/6] rds-ctl: fix percentage handling.
+
+The block_cnt can be 0, and in that case the percentage becomes -nan.
+Fix this.
+
+Signed-off-by: Hans Verkuil <hans.verkuil at cisco.com>
+---
+ utils/rds-ctl/rds-ctl.cpp | 17 ++++++++++++-----
+ 1 file changed, 12 insertions(+), 5 deletions(-)
+
+diff --git a/utils/rds-ctl/rds-ctl.cpp b/utils/rds-ctl/rds-ctl.cpp
+index de76d9f..191cfee 100644
+--- a/utils/rds-ctl/rds-ctl.cpp
++++ b/utils/rds-ctl/rds-ctl.cpp
+@@ -523,16 +523,23 @@ static void print_rds_statistics(const struct v4l2_rds_statistics *statistics)
+ 	printf("received blocks / received groups: %u / %u\n",
+ 		statistics->block_cnt, statistics->group_cnt);
+ 
+-	float block_error_percentage =
+-	((float)statistics->block_error_cnt / statistics->block_cnt) * 100.0;
++	float block_error_percentage = 0;
++
++	if (statistics->block_cnt)
++		block_error_percentage =
++			((float)statistics->block_error_cnt / statistics->block_cnt) * 100.0;
+ 	printf("block errors / group errors: %u (%3.2f%%) / %u \n",
+ 		statistics->block_error_cnt,
+ 		block_error_percentage, statistics->group_error_cnt);
+-	float block_corrected_percentage =
+-	((float)statistics->block_corrected_cnt / statistics->block_cnt) * 100.0;
++
++	float block_corrected_percentage = 0;
++
++	if (statistics->block_cnt)
++		block_corrected_percentage = (
++			(float)statistics->block_corrected_cnt / statistics->block_cnt) * 100.0;
+ 	printf("corrected blocks: %u (%3.2f%%)\n",
+ 		statistics->block_corrected_cnt, block_corrected_percentage);
+-	for(int i=0; i<16; i++)
++	for (int i = 0; i < 16; i++)
+ 		printf("Group %02d: %u\n", i, statistics->group_type_cnt[i]);
+ }
+ 
+-- 
+1.8.2.1
+
diff --git a/0002-libv4l2rds-support-RDS-EON-and-TMC-tuning-info.patch b/0002-libv4l2rds-support-RDS-EON-and-TMC-tuning-info.patch
new file mode 100644
index 0000000..3a5412a
--- /dev/null
+++ b/0002-libv4l2rds-support-RDS-EON-and-TMC-tuning-info.patch
@@ -0,0 +1,614 @@
+From 5d64d74fe49d0af01eea2a85db69669f45043090 Mon Sep 17 00:00:00 2001
+From: Konke Radlow <koradlow at gmail.com>
+Date: Tue, 4 Jun 2013 18:15:01 +0000
+Subject: [PATCH 2/6] libv4l2rds: support RDS-EON and TMC-tuning info
+
+- added support to decode RDS-EON information
+- added support to decode RDS-TMC tuning information
+- fixing compiler warnings due to missing pointer dereferencing
+
+Signed-off-by: Konke Radlow <koradlow at gmail.com>
+Signed-off-by: Hans Verkuil <hans.verkuil at cisco.com>
+---
+ lib/include/libv4l2rds.h    |  79 +++++++++-
+ lib/libv4l2rds/libv4l2rds.c | 363 +++++++++++++++++++++++++++++++++++++++++---
+ 2 files changed, 417 insertions(+), 25 deletions(-)
+
+diff --git a/lib/include/libv4l2rds.h b/lib/include/libv4l2rds.h
+index 6a6c7f3..e1078de 100644
+--- a/lib/include/libv4l2rds.h
++++ b/lib/include/libv4l2rds.h
+@@ -37,7 +37,7 @@ extern "C" {
+ #endif
+ 
+ /* used to define the current version (version field) of the v4l2_rds struct */
+-#define V4L2_RDS_VERSION (1)
++#define V4L2_RDS_VERSION (2)
+ 
+ /* Constants used to define the size of arrays used to store RDS information */
+ #define MAX_ODA_CNT 18 	/* there are 16 groups each with type a or b. Of these
+@@ -50,6 +50,16 @@ extern "C" {
+ 			* Additional data is limited to 112 bit, and the smallest
+ 			* optional tuple has a size of 4 bit (4 bit identifier +
+ 			* 0 bits of data) */
++#define MAX_TMC_ALT_STATIONS 32 /* defined by ISO 14819-1:2003, 7.5.3.3  */
++#define MAX_TMC_AF_CNT 4	/* limit for the numbers of AFs stored per alternative TMC
++			* station. This value is not defined by the standard, but based on observation
++			* of real-world RDS-TMC streams. The maximum encountered number of AFs per
++			* station during testing was 2 */
++#define MAX_EON_CNT 20	/* Maximal number of entries in the EON table (for storing
++			* information about other radio stations, broadcasted by the current station). 
++			* This value is not defined by the standard, but based on observation
++			* of real-world RDS-TMC streams. EON doesn't seem to be a widely used feature
++			* and the maximum number of EON encountered during testing was 8 */
+ 
+ /* Define Constants for the possible types of RDS information
+  * used to address the relevant bit in the valid_fields bitmask */
+@@ -69,7 +79,10 @@ extern "C" {
+ #define V4L2_RDS_LC		0x2000	/* Language Code */
+ #define V4L2_RDS_TMC_SG		0x4000	/* RDS-TMC single group */
+ #define V4L2_RDS_TMC_MG		0x8000	/* RDS-TMC multi group */
+-#define V4L2_RDS_TMC_SYS	0x10000 /* RDS-TMC system information */
++#define V4L2_RDS_TMC_SYS	0x10000	/* RDS-TMC system information */
++#define V4L2_RDS_EON		0x20000	/* Enhanced Other Network Info */
++#define V4L2_RDS_LSF		0x40000	/* Linkage information */
++#define V4L2_RDS_TMC_TUNING	0x80000	/* RDS-TMC tuning information */
+ 
+ /* Define Constants for the state of the RDS decoding process
+  * used to address the relevant bit in the decode_information bitmask */
+@@ -84,9 +97,10 @@ extern "C" {
+ #define V4L2_RDS_FLAG_STATIC_PTY	0x08
+ 
+ /* TMC related codes
+- * used to extract TMC fields from RDS groups */
+-#define V4L2_TMC_TUNING_INFO	0x08
+-#define V4L2_TMC_SINGLE_GROUP	0x04
++ * used to extract TMC fields from RDS-TMC groups
++ * see ISO 14819-1:2003, Figure 2 - RDS-TMC single-grp full message structure */
++#define V4L2_TMC_TUNING_INFO	0x10	/* Bit 4 indicates Tuning Info / User msg */
++#define V4L2_TMC_SINGLE_GROUP	0x08	/* Bit 3 indicates Single / Multi-group msg */
+ 
+ /* struct to encapsulate one complete RDS group */
+ /* This structure is used internally to store data until a complete RDS
+@@ -149,6 +163,57 @@ struct v4l2_rds_af_set {
+ 	uint32_t af[MAX_AF_CNT];	/* AFs defined in Hz */
+ };
+ 
++/* struct to encapsulate one entry in the EON table (Enhanced Other Network) */
++struct v4l2_rds_eon {
++	uint32_t valid_fields;
++	uint16_t pi;
++	uint8_t ps[9];
++	uint8_t pty;
++	bool ta;
++	bool tp;
++	uint16_t lsf;		/* Linkage Set Number */
++	struct v4l2_rds_af_set af;
++};
++
++/* struct to encapsulate a table of EON information */
++struct v4l2_rds_eon_set {
++	uint8_t size;		/* size of the table */
++	uint8_t index;		/* current position in the table */
++	struct v4l2_rds_eon eon[MAX_EON_CNT];	/* Information about other
++						 * radio channels */
++};
++
++/* struct to encapsulate alternative frequencies (AFs) for RDS-TMC stations.
++ * AFs listed in af[] can be used unconditionally. 
++ * AFs listed in mapped_af[n] should only be used if the current 
++ * tuner frequency matches the value in mapped_af_tuning[n] */
++struct v4l2_tmc_alt_freq {
++	uint8_t af_size;		/* number of known AFs */
++	uint8_t af_index;
++	uint8_t mapped_af_size;		/* number of mapped AFs */
++	uint8_t mapped_af_index;
++	uint32_t af[MAX_TMC_AF_CNT];		/* AFs defined in Hz */
++	uint32_t mapped_af[MAX_TMC_AF_CNT];		/* mapped AFs defined in Hz */
++	uint32_t mapped_af_tuning[MAX_TMC_AF_CNT];	/* mapped AFs defined in Hz */
++};
++
++/* struct to encapsulate information about stations carrying RDS-TMC services */
++struct v4l2_tmc_station {
++	uint16_t pi;
++	uint8_t ltn;	/* database-ID of ON */
++	uint8_t msg;	/* msg parameters of ON */
++	uint8_t sid;	/* service-ID of ON */
++	struct v4l2_tmc_alt_freq afi;
++};
++
++/* struct to encapsulate tuning information for TMC */
++struct v4l2_tmc_tuning {
++	uint8_t station_cnt;	/* number of announced alternative stations */
++	uint8_t index;
++	struct v4l2_tmc_station station[MAX_TMC_ALT_STATIONS];	/* information
++							* about other stations carrying the same RDS-TMC service */
++};
++
+ /* struct to encapsulate an additional data field in a TMC message */
+ struct v4l2_tmc_additional {
+ 	uint8_t label;
+@@ -199,6 +264,9 @@ struct v4l2_rds_tmc {
+ 	uint8_t t_d;		/* delay time (only if mode = enhanced */
+ 	uint8_t spn[9];		/* service provider name */
+ 	struct v4l2_rds_tmc_msg tmc_msg;
++
++	/* tuning information for alternative service providers */
++	struct v4l2_tmc_tuning tuning;
+ };
+ 
+ /* struct to encapsulate state and RDS information for current decoding process */
+@@ -236,6 +304,7 @@ struct v4l2_rds {
+ 	struct v4l2_rds_statistics rds_statistics;
+ 	struct v4l2_rds_oda_set rds_oda;	/* Open Data Services */
+ 	struct v4l2_rds_af_set rds_af; 		/* Alternative Frequencies */
++	struct v4l2_rds_eon_set rds_eon;	/* EON information */
+ 	struct v4l2_rds_tmc tmc;		/* TMC information */
+ };
+ 
+diff --git a/lib/libv4l2rds/libv4l2rds.c b/lib/libv4l2rds/libv4l2rds.c
+index 2918061..28b78ce 100644
+--- a/lib/libv4l2rds/libv4l2rds.c
++++ b/lib/libv4l2rds/libv4l2rds.c
+@@ -92,6 +92,11 @@ enum rds_state {
+ 	RDS_C_RECEIVED,
+ };
+ 
++/* function declarations to prevent the need to move large code blocks */
++static int rds_add_tmc_station(struct rds_private_state *priv_state, uint16_t pi);
++static uint32_t rds_decode_af(uint8_t af, bool is_vhf);
++static bool rds_add_tmc_af(struct rds_private_state *priv_state);
++
+ static inline uint8_t set_bit(uint8_t input, uint8_t bitmask, bool bitvalue)
+ {
+ 	return bitvalue ? input | bitmask : input & ~bitmask;
+@@ -368,7 +373,7 @@ static uint32_t rds_decode_tmc_multi_group(struct rds_private_state *priv_state)
+ 	/* bit 15 of block 3 is the first group indicator */
+ 	if (grp->data_c_msb & 0x80) {
+ 		/* begine decoding of new message */
+-		memset(msg, 0, sizeof(msg));
++		memset(msg, 0, sizeof(*msg));
+ 		memset(priv_state->optional_tmc, 0, 112*sizeof(bool)); 
+ 		/* bits 0-3 of block 2 contain continuity index */
+ 		priv_state->continuity_id = grp->data_b_lsb & 0x07;
+@@ -434,6 +439,60 @@ static uint32_t rds_decode_tmc_multi_group(struct rds_private_state *priv_state)
+ 	return V4L2_RDS_TMC_MG;
+ }
+ 
++/* decode the RDS-TMC tuning information that is contained in type 8A groups
++ * (variants 4 to 9) that announce the presence alternative transmitters 
++ * providing the same RDS-TMC service */
++static uint32_t rds_decode_tmc_tuning(struct rds_private_state *priv_state)
++{
++	struct v4l2_rds_group *group = &priv_state->rds_group;
++	struct v4l2_rds_tmc *tmc = &priv_state->handle.tmc;
++	uint8_t variant_code = group->data_b_lsb & 0x0f;
++	uint16_t pi_on = (group->data_d_msb << 8) | group->data_d_lsb;
++	uint8_t index;
++
++	/* variants 4 and 5 carry the service provider name */
++	if (variant_code >= 4 && variant_code <= 5) {
++		int offset = 4 * (variant_code - 4);
++		tmc->spn[0 + offset] = group->data_c_msb;
++		tmc->spn[1 + offset] = group->data_c_lsb;
++		tmc->spn[2 + offset] = group->data_d_msb;
++		tmc->spn[3 + offset] = group->data_d_lsb;
++
++	/* variant 6 provides specific frequencies for the same RDS-TMC service
++	 * on a network with a different PI code */
++	/* variant 7 provides mapped frequency pair information which should only
++	 * be used if the terminal is tuned to the tuning frequency */
++	} else if (variant_code == 6 || variant_code == 7) {
++		rds_add_tmc_af(priv_state);
++
++	/* variant 8 indicates up to 2 PI codes of adjacent networks carrying 
++	 * the same RDS-TMC service on all transmitters of the network */ 
++	} else if (variant_code == 8) {
++		uint16_t pi_on_2 = (group->data_c_msb << 8) | group->data_c_lsb;
++
++		/* try to add both transmitted PI codes to the table */
++		rds_add_tmc_station(priv_state, pi_on);
++		/* PI = 0 is used as a filler code */
++		if (pi_on_2 != 0)
++			rds_add_tmc_station(priv_state, pi_on_2);
++
++	/* variant 9 provides PI codes of other networks with different system 
++	 * parameters */
++	} else if (variant_code == 9) {
++		index = rds_add_tmc_station(priv_state, pi_on);
++
++		/* bits 0 - 5 contain the service-ID of the ON */
++		tmc->tuning.station[index].sid = group->data_c_lsb & 0x3F;
++		/* bits 6-10 contain the msg parameters of the ON */
++		tmc->tuning.station[index].msg = (group->data_c_msb & 0x03) << 2;
++		tmc->tuning.station[index].msg |= (group->data_c_lsb >> 6) & 0x03;
++		/* bits 11-15 contain the database-ID of the ON */
++		tmc->tuning.station[index].ltn = group->data_c_msb >> 2;
++	}
++
++	return V4L2_RDS_TMC_TUNING;
++}
++
+ static bool rds_add_oda(struct rds_private_state *priv_state, struct v4l2_rds_oda oda)
+ {
+ 	struct v4l2_rds *handle = &priv_state->handle;
+@@ -455,20 +514,11 @@ static bool rds_add_oda(struct rds_private_state *priv_state, struct v4l2_rds_od
+ /* add a new AF to the list, if it doesn't exist yet */
+ static bool rds_add_af_to_list(struct v4l2_rds_af_set *af_set, uint8_t af, bool is_vhf)
+ {
+-	uint32_t freq = 0;
+-
+-	/* AF0 -> "Not to be used" */
+-	if (af == 0)
++	/* convert the frequency to Hz, skip on errors */
++	uint32_t freq = rds_decode_af(af, is_vhf);
++	if (freq == 0) 
+ 		return false;
+ 
+-	/* calculate the AF values in HZ */
+-	if (is_vhf)
+-		freq = 87500000 + af * 100000;
+-	else if (freq <= 15)
+-		freq = 152000 + af * 9000;
+-	else
+-		freq = 531000 + af * 9000;
+-
+ 	/* prevent buffer overflows */
+ 	if (af_set->size >= MAX_AF_CNT || af_set->size >= af_set->announced_af)
+ 		return false;
+@@ -505,7 +555,7 @@ static bool rds_add_af(struct rds_private_state *priv_state)
+ 			updated_af = true;
+ 		c_lsb = 0; /* invalidate */
+ 	}
+-	/* 224..249: announcement of AF count (224=0, 249=25)*/
++	/* 224..249: announcement of AF count (224=0, 249=25) */
+ 	if (c_msb >= 224 && c_msb <= 249)
+ 		af_set->announced_af = c_msb - 224;
+ 	/* check if the data represents an AF (for 1 =< val <= 204 the
+@@ -522,6 +572,103 @@ static bool rds_add_af(struct rds_private_state *priv_state)
+ 	return updated_af;
+ }
+ 
++/* checks if an entry for the given PI already exists and returns the index
++ * of that entry if so. Else it adds a new entry to the TMC-Tuning table and returns
++ * the index of the new field */
++static int rds_add_tmc_station(struct rds_private_state *priv_state, uint16_t pi)
++{
++	struct v4l2_tmc_tuning *tuning = &priv_state->handle.tmc.tuning;
++	uint8_t index = tuning->index;
++	uint8_t size = tuning->station_cnt;
++	
++	/* check if there's an entry for the given PI key */
++	for (int i = 0; i < tuning->station_cnt; i++) {
++		if (tuning->station[i].pi == pi) {
++			return i;
++		}
++	}
++	/* if the the maximum table size is reached, overwrite old
++	 * entries, starting at the oldest one = 0 */
++	tuning->station[index].pi = pi;
++	tuning->index = (index+1 < MAX_TMC_ALT_STATIONS) ? (index+1) : 0;
++	tuning->station_cnt = (size+1 <= MAX_TMC_ALT_STATIONS) ? (size+1) : MAX_TMC_ALT_STATIONS;
++	return index;
++}
++
++/* tries to add new AFs to the relevant entry in the list of RDS-TMC providers */
++static bool rds_add_tmc_af(struct rds_private_state *priv_state)
++{
++	struct v4l2_rds_group *grp = &priv_state->rds_group;
++	struct v4l2_tmc_alt_freq *afi;
++	uint16_t pi_on = grp->data_d_msb << 8 | grp->data_d_lsb;
++	uint8_t variant = grp->data_b_lsb & 0x0f;
++	uint8_t station_index = rds_add_tmc_station(priv_state, pi_on);
++	uint8_t af_index;
++	uint8_t mapped_af_index;
++	uint32_t freq_a = rds_decode_af(grp->data_c_msb, true);
++	uint32_t freq_b = rds_decode_af(grp->data_c_lsb, true);
++	
++	afi = &priv_state->handle.tmc.tuning.station[station_index].afi;
++	af_index = afi->af_index;
++	mapped_af_index = afi->mapped_af_index;
++
++	/* specific frequencies */
++	if (variant == 6) {
++		/* compare the new AFs to the stored ones, reset them to 0 if the AFs are
++		 * already known */
++		for (int i = 0; i < afi->af_size; i++) {
++			freq_a = (freq_a == afi->af[i]) ? 0 : freq_a;
++			freq_b = (freq_b == afi->af[i]) ? 0 : freq_b;
++		}
++		/* return early if there is nothing to do */
++		if (freq_a == 0 && freq_b == 0)
++			return false;
++
++		/* add the new AFs if they were previously unknown */
++		if (freq_a != 0) {
++			afi->af[af_index] = freq_a;
++			af_index = (af_index+1 < MAX_TMC_AF_CNT) ? af_index+1 : 0;
++			afi->af_size++; 
++		}
++		if (freq_b != 0) {
++			afi->af[af_index] = freq_b;
++			af_index = (af_index+1 < MAX_TMC_AF_CNT) ? af_index+1 : 0;
++			afi->af_size++; 
++		}
++		/* update the information in the handle */
++		afi->af_index = af_index;
++		if (afi->af_size >= MAX_TMC_AF_CNT) 
++			afi->af_size = MAX_TMC_AF_CNT;
++
++		return true;
++	}
++
++	/* mapped frequency pair */
++	else if (variant == 7) {
++		/* check the if there's already a frequency mapped to the new tuning
++		 * frequency, update the mapped frequency in this case */
++		for (int i = 0; i < afi->mapped_af_size; i++) {
++			if (freq_a == afi->mapped_af_tuning[i])
++				afi->mapped_af[i] = freq_b;
++				return true;
++		}
++		/* new pair is unknown, add it to the list */
++		if (freq_a != 0 && freq_b != 0) {
++			mapped_af_index = (mapped_af_index+1 >= MAX_TMC_AF_CNT) ? 0 : mapped_af_index + 1;
++			afi->mapped_af[mapped_af_index] = freq_b;
++			afi->mapped_af_tuning[mapped_af_index] = freq_a;
++			afi->mapped_af_size++; 
++		}
++		/* update the information in the handle */
++		afi->mapped_af_index = mapped_af_index;
++		if (afi->mapped_af_size >= MAX_TMC_AF_CNT) 
++			afi->mapped_af_size = MAX_TMC_AF_CNT;
++
++		return true;
++	}
++	return false;
++}
++
+ /* adds one char of the ps name to temporal storage, the value is validated
+  * if it is received twice in a row
+  * @pos:	position of the char within the PS name (0..7)
+@@ -543,6 +690,44 @@ static bool rds_add_ps(struct rds_private_state *priv_state, uint8_t pos, uint8_
+ 	return true;
+ }
+ 
++/* checks if an entry for the given PI already exists and returns the index
++ * of that entry if so. Else it adds a new entry to the EON table and returns
++ * the index of the new field */
++static uint8_t rds_add_eon_entry(struct rds_private_state *priv_state, uint16_t pi)
++{
++	struct v4l2_rds *handle = &priv_state->handle;
++	uint8_t index = handle->rds_eon.index;
++	uint8_t size = handle->rds_eon.size;
++
++	/* check if there's an entry for the given PI key */
++	for (int i = 0; i < handle->rds_eon.size; i++) {
++		if (handle->rds_eon.eon[i].pi == pi) {
++			return i;
++		}
++	}
++	/* if the the maximum table size is reached, overwrite old
++	 * entries, starting at the oldest one = 0 */
++	handle->rds_eon.eon[index].pi = pi;
++	handle->rds_eon.eon[index].valid_fields |= V4L2_RDS_PI;
++	handle->rds_eon.index = (index+1 < MAX_EON_CNT) ? (index+1) : 0;
++	handle->rds_eon.size = (size+1 <= MAX_EON_CNT) ? (size+1) : MAX_EON_CNT;
++	return index;
++}
++
++/* checks if an entry for the given PI already exists */
++static bool rds_check_eon_entry(struct rds_private_state *priv_state, uint16_t pi)
++{
++	struct v4l2_rds *handle = &priv_state->handle;
++
++	/* check if there's an entry for the given PI key */
++	for (int i = 0; i <= handle->rds_eon.size; i++) {
++		if (handle->rds_eon.eon[i].pi == pi) {
++			return true;
++		}
++	}
++	return false;
++}
++
+ /* group of functions to decode successfully received RDS groups into
+  * easily accessible data fields
+  *
+@@ -790,6 +975,29 @@ static uint32_t rds_decode_group3(struct rds_private_state *priv_state)
+ 	return updated_fields;
+ }
+ 
++/* decodes the RDS radio frequency representation into Hz
++ * @af: 8-bit AF value as transmitted in RDS groups
++ * @is_vhf: boolean value defining  which conversion table to use
++ * @return: frequency in Hz, 0 in case of wrong input values */
++static uint32_t rds_decode_af(uint8_t af, bool is_vhf) {
++	uint32_t freq = 0;
++
++	/* AF = 0 => "not to be used"
++	 * AF >= 205 => special meanings */
++	if (af == 0 || af >= 205)
++		return 0;
++
++	/* calculate the AF values in HZ */
++	if (is_vhf)
++		freq = 87500000 + af * 100000;
++	else if (freq <= 15)
++		freq = 152000 + af * 9000;
++	else
++		freq = 531000 + af * 9000;
++
++	return freq;
++}
++
+ /* decodes the RDS date/time representation into a standard c representation
+  * that can be used with c-library functions */
+ static time_t rds_decode_mjd(const struct rds_private_state *priv_state)
+@@ -880,7 +1088,6 @@ static uint32_t rds_decode_group4(struct rds_private_state *priv_state)
+ 	handle->time = rds_decode_mjd(priv_state);
+ 	updated_fields |= V4L2_RDS_TIME;
+ 	handle->valid_fields |= V4L2_RDS_TIME;
+-	printf("\nLIB: time_t: %ld", handle->time);
+ 	return updated_fields;
+ }
+ 
+@@ -916,13 +1123,13 @@ static uint32_t rds_decode_group8(struct rds_private_state *priv_state)
+ 		!(grp->data_b_lsb & V4L2_TMC_TUNING_INFO)) {
+ 		return rds_decode_tmc_multi_group(priv_state);
+ 	}
+-	/* -> tuning information message, defined for variants 4..9, submitted
+-	 * in bits 0-3 of block 2 */
++	/* -> tuning information message, defined for variants 4..9,
++	 * submitted in bits 0-3 of block 2 */
+ 	tuning_variant = grp->data_b_lsb & 0x0f;
+ 	if ((grp->data_b_lsb & V4L2_TMC_TUNING_INFO) && tuning_variant >= 4 &&
+ 		tuning_variant <= 9) {
+-		/* TODO: Implement tuning information decoding */
+-		return 0;
++		priv_state->handle.valid_fields |= V4L2_RDS_TMC_TUNING;
++		return rds_decode_tmc_tuning(priv_state);
+ 	}
+ 
+ 	return 0;
+@@ -981,6 +1188,121 @@ static uint32_t rds_decode_group10(struct rds_private_state *priv_state)
+ 	return updated_fields;
+ }
+ 
++/* group 14: EON (Enhanced Other Network) information */
++static uint32_t rds_decode_group14(struct rds_private_state* priv_state)
++{
++	struct v4l2_rds *handle = &priv_state->handle;
++	struct v4l2_rds_group *grp = &priv_state->rds_group;
++	struct v4l2_rds_eon *eon_entry;
++	uint32_t updated_fields = 0;
++	uint16_t pi_on;
++	uint16_t lsf_on;
++	uint8_t variant_code;
++	uint8_t eon_index;
++	uint8_t pty_on;
++	bool tp_on, ta_on;
++	bool new_a = false, new_b = false;
++
++	if (grp->group_version != 'A')
++		return 0;
++
++	/* bits 0-3 of group b contain the variant code */
++	variant_code = grp->data_b_lsb & 0x0f;
++
++	/* group d contains the PI code of the ON (Other Network) */
++	pi_on = (grp->data_d_msb << 8) | grp->data_d_lsb;
++
++	/* bit 4 of group b contains the TP status of the ON*/
++	tp_on = grp->data_b_lsb & 0x10;
++	if (rds_check_eon_entry(priv_state, pi_on)) {
++		/* if there's an entry for this PI(ON) update the TP field */
++		eon_index = rds_add_eon_entry(priv_state, pi_on);
++		eon_entry = &handle->rds_eon.eon[eon_index];
++		eon_entry->tp = tp_on;
++		eon_entry->valid_fields |= V4L2_RDS_TP;
++		updated_fields |= V4L2_RDS_EON;
++	}
++
++	/* perform group variant dependent decoding */
++	if ((variant_code >=5 && variant_code <= 11) || variant_code >= 14) {
++		/* 5-9 = mapped FM frequencies -> unsupported
++		 * 10-11 = unallocated
++		 * 14 = PIN(ON) -> unsupported (unused RDS feature)
++		 * 15 = reserved for broadcasters use */
++		return updated_fields;
++	}
++	
++	/* retrieve the EON entry corresponding to the PI(ON) code or add a new
++	 * entry to the table if no entry exists */
++	eon_index = rds_add_eon_entry(priv_state, pi_on);
++	eon_entry = &handle->rds_eon.eon[eon_index];
++
++	/* PS Name */
++	if (variant_code < 4) {
++		eon_entry->ps[variant_code*2] = grp->data_c_msb;
++		eon_entry->ps[variant_code*2+1] = grp->data_c_lsb;
++		eon_entry->valid_fields |= V4L2_RDS_PS;
++		updated_fields |= V4L2_RDS_EON;
++	}
++	/* Alternative frequencies */
++	else if (variant_code == 4) {
++		uint8_t c_msb = grp->data_c_msb;
++		uint8_t c_lsb = grp->data_c_lsb;
++
++		/* 224..249: announcement of AF count (224=0, 249=25) */
++		if (c_msb >= 224 && c_msb <= 249)
++			eon_entry->af.announced_af = c_msb - 224;
++		/* check if the data represents an AF (for 1 =< val <= 204 the
++		 * value represents an AF) */
++		if (c_msb < 205)
++			new_a = rds_add_af_to_list(&eon_entry->af,
++					grp->data_c_msb, true);
++		if (c_lsb < 205)
++			new_b = rds_add_af_to_list(&eon_entry->af,
++					grp->data_c_lsb, true);
++		/* check if one of the frequencies was previously unknown */
++		if (new_a || new_b) {
++			eon_entry->valid_fields |= V4L2_RDS_AF;
++			updated_fields |= V4L2_RDS_EON;
++		}
++	}
++	/* Linkage information */
++	else if (variant_code == 12) {
++		/* group c contains the lsf code */
++		lsf_on = (grp->data_c_msb << 8) | grp->data_c_lsb;
++		/* check if the lsf code is already known */
++		new_a = (eon_entry->lsf == lsf_on);
++		if (new_a) {
++			eon_entry->lsf = lsf_on;
++			eon_entry->valid_fields |= V4L2_RDS_LSF;
++			updated_fields |= V4L2_RDS_EON;
++		}
++	}
++	/* PTY(ON) and TA(ON) */
++	else if (variant_code == 13) {
++		/* bits 15-10 of group c contain the PTY(ON) */
++		pty_on = grp->data_c_msb >> 3;
++		/* bit 0 of group c contains the TA code */
++		ta_on = grp->data_c_lsb & 0x01;
++		/* check if the data is new */
++		new_a = (eon_entry->pty == pty_on);
++		if (new_a) {
++			eon_entry->pty = pty_on;
++			eon_entry->valid_fields |= V4L2_RDS_PTY;
++		}
++		new_b = (eon_entry->ta == ta_on);
++		eon_entry->ta = ta_on;
++		eon_entry->valid_fields |= V4L2_RDS_TA;
++		if (new_a || new_b)
++			updated_fields |= V4L2_RDS_EON;
++	}
++	/* set valid field for EON data, if EON table contains entries */
++	if (handle->rds_eon.size > 0)
++		handle->valid_fields |= V4L2_RDS_EON;
++
++	return updated_fields;
++}
++
+ typedef uint32_t (*decode_group_func)(struct rds_private_state *);
+ 
+ /* array of function pointers to contain all group specific decoding functions */
+@@ -992,6 +1314,7 @@ static const decode_group_func decode_group[16] = {
+ 	[4] = rds_decode_group4,
+ 	[8] = rds_decode_group8,
+ 	[10] = rds_decode_group10,
++	[14] = rds_decode_group14
+ };
+ 
+ static uint32_t rds_decode_group(struct rds_private_state *priv_state)
+@@ -1068,7 +1391,7 @@ uint32_t v4l2_rds_add(struct v4l2_rds *handle, struct v4l2_rds_data *rds_data)
+ 		if (block_id == 0) {
+ 			*decode_state = RDS_A_RECEIVED;
+ 			/* begin reception of a new data group, reset raw buffer to 0 */
+-			memset(rds_data_raw, 0, sizeof(rds_data_raw));
++			memset(rds_data_raw, 0, sizeof(*rds_data_raw));
+ 			rds_data_raw[0] = *rds_data;
+ 		} else {
+ 			/* ignore block if it is not the first block of a group */
+-- 
+1.8.2.1
+
diff --git a/0003-rds-ctl-support-RDS-EON-and-TMC-tuning-info.patch b/0003-rds-ctl-support-RDS-EON-and-TMC-tuning-info.patch
new file mode 100644
index 0000000..927dafa
--- /dev/null
+++ b/0003-rds-ctl-support-RDS-EON-and-TMC-tuning-info.patch
@@ -0,0 +1,124 @@
+From d588da4738609a921a77745ea4577f543444be48 Mon Sep 17 00:00:00 2001
+From: Konke Radlow <koradlow at gmail.com>
+Date: Tue, 4 Jun 2013 18:15:02 +0000
+Subject: [PATCH 3/6] rds-ctl: support RDS-EON and TMC-tuning info
+
+- added functionality to print RDS-EON information
+- added functionality to print RDS-TMC tuning information
+- clarify option description, change
+  trigger condition for printing TMC Tuning information
+
+Signed-off-by: Konke Radlow <koradlow at gmail.com>
+Signed-off-by: Hans Verkuil <hans.verkuil at cisco.com>
+---
+ utils/rds-ctl/rds-ctl.cpp | 59 +++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 57 insertions(+), 2 deletions(-)
+
+diff --git a/utils/rds-ctl/rds-ctl.cpp b/utils/rds-ctl/rds-ctl.cpp
+index 191cfee..d894ec1 100644
+--- a/utils/rds-ctl/rds-ctl.cpp
++++ b/utils/rds-ctl/rds-ctl.cpp
+@@ -130,7 +130,7 @@ static void usage_hint(void)
+ static void usage_common(void)
+ {
+ 	printf("\nGeneral/Common options:\n"
+-	       "  --all              display all information available\n"
++	       "  --all              display all device information available\n"
+ 	       "  -D, --info         show driver info [VIDIOC_QUERYCAP]\n"
+ 	       "  -d, --device=<dev> use device <dev>\n"
+ 	       "                     if <dev> is a single digit, then /dev/radio<dev> is used\n"
+@@ -172,7 +172,7 @@ static void usage_rds(void)
+ 	       "                     <default>: 5000 ms\n"
+ 	       "  --print-block      prints all valid RDS fields, whenever a value is updated\n"
+ 	       "                     instead of printing only updated values\n"
+-	       "  --tmc              enables decoding of TMC (Traffic Message Channel) data\n"
++	       "  --tmc              print information about TMC (Traffic Message Channel) messages\n"
+ 	       "  --silent           only set the result code, do not print any messages\n"
+ 	       "  --verbose          turn on verbose mode - every received RDS group\n"
+ 	       "                     will be printed\n"
+@@ -517,6 +517,30 @@ static void print_rds_tmc(const struct v4l2_rds *handle, uint32_t updated_fields
+ 	}
+ }
+ 
++static void print_rds_tmc_tuning(const struct v4l2_rds *handle, uint32_t updated_fields)
++{
++	const struct v4l2_tmc_tuning *tuning = &handle->tmc.tuning;
++	const struct v4l2_tmc_station *station;
++	
++	if (updated_fields & V4L2_RDS_TMC_TUNING) {
++		printf("\nTMC Service provider: %s, %u alternative stations\n", handle->tmc.spn, tuning->station_cnt);
++		for (int i = 0; i < tuning->station_cnt; i++) {
++			station = &tuning->station[i];
++			printf("PI(ON %02u) = %04x, AFs: %u, mapped AFs: %u \n", i, station->pi,
++					station->afi.af_size, station->afi.mapped_af_size);
++			for (int j = 0; j < station->afi.af_size; j++)
++				printf("        AF%02d: %.1fMHz\n", j, station->afi.af[j] / 1000000.0);
++			for (int k = 0; k < station->afi.mapped_af_size; k++)
++				printf("        m_AF%02d: %.1fMHz => %.1fMHz\n", k,
++						station->afi.mapped_af_tuning[k] / 1000000.0,
++						station->afi.mapped_af[k] / 1000000.0);
++			if (station->ltn != 0 || station->msg != 0 || station-> sid != 0)
++				printf("        ltn: %02x, msg: %02x, sid: %02x\n", station->ltn,
++						station->msg, station->sid);
++		}
++	}
++}
++
+ static void print_rds_statistics(const struct v4l2_rds_statistics *statistics)
+ {
+ 	printf("\n\nRDS Statistics: \n");
+@@ -557,6 +581,33 @@ static void print_rds_af(const struct v4l2_rds_af_set *af_set)
+ 	}
+ }
+ 
++static void print_rds_eon(const struct v4l2_rds_eon_set *eon_set)
++{
++	int counter = 0;
++
++	printf("\n\nEnhanced Other Network information: %u channels", eon_set->size);
++	for (int i = 0; i < eon_set->size; i++, counter++) {
++		if (eon_set->eon[i].valid_fields & V4L2_RDS_PI)
++			printf("\nPI(ON %02i) =  %04x", i, eon_set->eon[i].pi);
++		if (eon_set->eon[i].valid_fields & V4L2_RDS_PS)
++			printf("\nPS(ON %02i) =  %s", i, eon_set->eon[i].ps);
++		if (eon_set->eon[i].valid_fields & V4L2_RDS_PTY)
++			printf("\nPTY(ON %02i) =  %0u", i, eon_set->eon[i].pty);
++		if (eon_set->eon[i].valid_fields & V4L2_RDS_LSF)
++			printf("\nLSF(ON %02i) =  %0u", i, eon_set->eon[i].lsf);
++		if (eon_set->eon[i].valid_fields & V4L2_RDS_AF)
++			printf("\nPTY(ON %02i) =  %0u", i, eon_set->eon[i].pty);
++		if (eon_set->eon[i].valid_fields & V4L2_RDS_TP)
++			printf("\nTP(ON %02i): %s", i, eon_set->eon[i].tp? "yes":"no");
++		if (eon_set->eon[i].valid_fields & V4L2_RDS_TA)
++			printf("\nTA(ON %02i): %s", i, eon_set->eon[i].tp? "yes":"no");
++		if (eon_set->eon[i].valid_fields & V4L2_RDS_AF) {
++			printf("\nAF(ON %02i): size=%i", i, eon_set->eon[i].af.size);
++			print_rds_af(&(eon_set->eon[i].af));
++		}
++	}
++}
++
+ static void print_rds_pi(const struct v4l2_rds *handle)
+ {
+ 	printf("\nArea Coverage: %s", v4l2_rds_get_coverage_str(handle));
+@@ -614,6 +665,8 @@ static void print_rds_data(const struct v4l2_rds *handle, uint32_t updated_field
+ 	}
+ 	if (updated_fields & V4L2_RDS_AF && handle->valid_fields & V4L2_RDS_AF)
+ 		print_rds_af(&handle->rds_af);
++	if (updated_fields & V4L2_RDS_TMC_TUNING && handle->valid_fields & V4L2_RDS_TMC_TUNING);
++		print_rds_tmc_tuning(handle, updated_fields);
+ 	if (params.options[OptPrintBlock])
+ 		printf("\n");
+ 	if (params.options[OptTMC])
+@@ -669,6 +722,8 @@ static void read_rds_from_fd(const int fd)
+ 
+ 	/* try to receive and decode RDS data */
+ 	read_rds(rds_handle, fd, params.wait_limit);
++	if (rds_handle->valid_fields & V4L2_RDS_EON)
++		print_rds_eon(&rds_handle->rds_eon);
+ 	print_rds_statistics(&rds_handle->rds_statistics);
+ 
+ 	v4l2_rds_destroy(rds_handle);
+-- 
+1.8.2.1
+
diff --git a/0004-libv4l2rds.c-moving-functions-to-get-rid-of-declarat.patch b/0004-libv4l2rds.c-moving-functions-to-get-rid-of-declarat.patch
new file mode 100644
index 0000000..7f6d7b6
--- /dev/null
+++ b/0004-libv4l2rds.c-moving-functions-to-get-rid-of-declarat.patch
@@ -0,0 +1,297 @@
+From d5ec86b3ed8151e05c79e69bff6dde15d5f8487c Mon Sep 17 00:00:00 2001
+From: Konke Radlow <koradlow at gmail.com>
+Date: Tue, 4 Jun 2013 18:15:03 +0000
+Subject: [PATCH 4/6] libv4l2rds.c: moving functions to get rid of declarations
+
+Signed-off-by: Konke Radlow <koradlow at gmail.com>
+Signed-off-by: Hans Verkuil <hans.verkuil at cisco.com>
+---
+ lib/libv4l2rds/libv4l2rds.c | 243 ++++++++++++++++++++++----------------------
+ 1 file changed, 120 insertions(+), 123 deletions(-)
+
+diff --git a/lib/libv4l2rds/libv4l2rds.c b/lib/libv4l2rds/libv4l2rds.c
+index 28b78ce..333bf95 100644
+--- a/lib/libv4l2rds/libv4l2rds.c
++++ b/lib/libv4l2rds/libv4l2rds.c
+@@ -92,11 +92,6 @@ enum rds_state {
+ 	RDS_C_RECEIVED,
+ };
+ 
+-/* function declarations to prevent the need to move large code blocks */
+-static int rds_add_tmc_station(struct rds_private_state *priv_state, uint16_t pi);
+-static uint32_t rds_decode_af(uint8_t af, bool is_vhf);
+-static bool rds_add_tmc_af(struct rds_private_state *priv_state);
+-
+ static inline uint8_t set_bit(uint8_t input, uint8_t bitmask, bool bitvalue)
+ {
+ 	return bitvalue ? input | bitmask : input & ~bitmask;
+@@ -201,6 +196,29 @@ static void rds_decode_d(struct rds_private_state *priv_state, struct v4l2_rds_d
+ 	grp->data_d_lsb = rds_data->lsb;
+ }
+ 
++/* decodes the RDS radio frequency representation into Hz
++ * @af: 8-bit AF value as transmitted in RDS groups
++ * @is_vhf: boolean value defining  which conversion table to use
++ * @return: frequency in Hz, 0 in case of wrong input values */
++static uint32_t rds_decode_af(uint8_t af, bool is_vhf) {
++	uint32_t freq = 0;
++
++	/* AF = 0 => "not to be used"
++	 * AF >= 205 => special meanings */
++	if (af == 0 || af >= 205)
++		return 0;
++
++	/* calculate the AF values in HZ */
++	if (is_vhf)
++		freq = 87500000 + af * 100000;
++	else if (freq <= 15)
++		freq = 152000 + af * 9000;
++	else
++		freq = 531000 + af * 9000;
++
++	return freq;
++}
++
+ /* compare two rds-groups for equality */
+ /* used for decoding RDS-TMC, which has the requirement that the same group
+  * is at least received twice before it is accepted */
+@@ -224,6 +242,103 @@ static bool rds_compare_group(const struct v4l2_rds_group *a,
+ 	return true;
+ }
+ 
++/* checks if an entry for the given PI already exists and returns the index
++ * of that entry if so. Else it adds a new entry to the TMC-Tuning table and returns
++ * the index of the new field */
++static int rds_add_tmc_station(struct rds_private_state *priv_state, uint16_t pi)
++{
++	struct v4l2_tmc_tuning *tuning = &priv_state->handle.tmc.tuning;
++	uint8_t index = tuning->index;
++	uint8_t size = tuning->station_cnt;
++
++	/* check if there's an entry for the given PI key */
++	for (int i = 0; i < tuning->station_cnt; i++) {
++		if (tuning->station[i].pi == pi) {
++			return i;
++		}
++	}
++	/* if the the maximum table size is reached, overwrite old
++	 * entries, starting at the oldest one = 0 */
++	tuning->station[index].pi = pi;
++	tuning->index = (index+1 < MAX_TMC_ALT_STATIONS) ? (index+1) : 0;
++	tuning->station_cnt = (size+1 <= MAX_TMC_ALT_STATIONS) ? (size+1) : MAX_TMC_ALT_STATIONS;
++	return index;
++}
++
++/* tries to add new AFs to the relevant entry in the list of RDS-TMC providers */
++static bool rds_add_tmc_af(struct rds_private_state *priv_state)
++{
++	struct v4l2_rds_group *grp = &priv_state->rds_group;
++	struct v4l2_tmc_alt_freq *afi;
++	uint16_t pi_on = grp->data_d_msb << 8 | grp->data_d_lsb;
++	uint8_t variant = grp->data_b_lsb & 0x0f;
++	uint8_t station_index = rds_add_tmc_station(priv_state, pi_on);
++	uint8_t af_index;
++	uint8_t mapped_af_index;
++	uint32_t freq_a = rds_decode_af(grp->data_c_msb, true);
++	uint32_t freq_b = rds_decode_af(grp->data_c_lsb, true);
++
++	afi = &priv_state->handle.tmc.tuning.station[station_index].afi;
++	af_index = afi->af_index;
++	mapped_af_index = afi->mapped_af_index;
++
++	/* specific frequencies */
++	if (variant == 6) {
++		/* compare the new AFs to the stored ones, reset them to 0 if the AFs are
++		 * already known */
++		for (int i = 0; i < afi->af_size; i++) {
++			freq_a = (freq_a == afi->af[i]) ? 0 : freq_a;
++			freq_b = (freq_b == afi->af[i]) ? 0 : freq_b;
++		}
++		/* return early if there is nothing to do */
++		if (freq_a == 0 && freq_b == 0)
++			return false;
++
++		/* add the new AFs if they were previously unknown */
++		if (freq_a != 0) {
++			afi->af[af_index] = freq_a;
++			af_index = (af_index+1 < MAX_TMC_AF_CNT) ? af_index+1 : 0;
++			afi->af_size++;
++		}
++		if (freq_b != 0) {
++			afi->af[af_index] = freq_b;
++			af_index = (af_index+1 < MAX_TMC_AF_CNT) ? af_index+1 : 0;
++			afi->af_size++;
++		}
++		/* update the information in the handle */
++		afi->af_index = af_index;
++		if (afi->af_size >= MAX_TMC_AF_CNT)
++			afi->af_size = MAX_TMC_AF_CNT;
++
++		return true;
++	}
++
++	/* mapped frequency pair */
++	else if (variant == 7) {
++		/* check the if there's already a frequency mapped to the new tuning
++		 * frequency, update the mapped frequency in this case */
++		for (int i = 0; i < afi->mapped_af_size; i++) {
++			if (freq_a == afi->mapped_af_tuning[i])
++				afi->mapped_af[i] = freq_b;
++				return true;
++		}
++		/* new pair is unknown, add it to the list */
++		if (freq_a != 0 && freq_b != 0) {
++			mapped_af_index = (mapped_af_index+1 >= MAX_TMC_AF_CNT) ? 0 : mapped_af_index + 1;
++			afi->mapped_af[mapped_af_index] = freq_b;
++			afi->mapped_af_tuning[mapped_af_index] = freq_a;
++			afi->mapped_af_size++;
++		}
++		/* update the information in the handle */
++		afi->mapped_af_index = mapped_af_index;
++		if (afi->mapped_af_size >= MAX_TMC_AF_CNT)
++			afi->mapped_af_size = MAX_TMC_AF_CNT;
++
++		return true;
++	}
++	return false;
++}
++
+ /* decode additional information of a TMC message into handy representation */
+ /* the additional information of TMC messages is submitted in (up to) 4 blocks of
+  * 28 bits each, which are to be treated as a consecutive bit-array. This data
+@@ -572,102 +687,7 @@ static bool rds_add_af(struct rds_private_state *priv_state)
+ 	return updated_af;
+ }
+ 
+-/* checks if an entry for the given PI already exists and returns the index
+- * of that entry if so. Else it adds a new entry to the TMC-Tuning table and returns
+- * the index of the new field */
+-static int rds_add_tmc_station(struct rds_private_state *priv_state, uint16_t pi)
+-{
+-	struct v4l2_tmc_tuning *tuning = &priv_state->handle.tmc.tuning;
+-	uint8_t index = tuning->index;
+-	uint8_t size = tuning->station_cnt;
+-	
+-	/* check if there's an entry for the given PI key */
+-	for (int i = 0; i < tuning->station_cnt; i++) {
+-		if (tuning->station[i].pi == pi) {
+-			return i;
+-		}
+-	}
+-	/* if the the maximum table size is reached, overwrite old
+-	 * entries, starting at the oldest one = 0 */
+-	tuning->station[index].pi = pi;
+-	tuning->index = (index+1 < MAX_TMC_ALT_STATIONS) ? (index+1) : 0;
+-	tuning->station_cnt = (size+1 <= MAX_TMC_ALT_STATIONS) ? (size+1) : MAX_TMC_ALT_STATIONS;
+-	return index;
+-}
+-
+-/* tries to add new AFs to the relevant entry in the list of RDS-TMC providers */
+-static bool rds_add_tmc_af(struct rds_private_state *priv_state)
+-{
+-	struct v4l2_rds_group *grp = &priv_state->rds_group;
+-	struct v4l2_tmc_alt_freq *afi;
+-	uint16_t pi_on = grp->data_d_msb << 8 | grp->data_d_lsb;
+-	uint8_t variant = grp->data_b_lsb & 0x0f;
+-	uint8_t station_index = rds_add_tmc_station(priv_state, pi_on);
+-	uint8_t af_index;
+-	uint8_t mapped_af_index;
+-	uint32_t freq_a = rds_decode_af(grp->data_c_msb, true);
+-	uint32_t freq_b = rds_decode_af(grp->data_c_lsb, true);
+-	
+-	afi = &priv_state->handle.tmc.tuning.station[station_index].afi;
+-	af_index = afi->af_index;
+-	mapped_af_index = afi->mapped_af_index;
+-
+-	/* specific frequencies */
+-	if (variant == 6) {
+-		/* compare the new AFs to the stored ones, reset them to 0 if the AFs are
+-		 * already known */
+-		for (int i = 0; i < afi->af_size; i++) {
+-			freq_a = (freq_a == afi->af[i]) ? 0 : freq_a;
+-			freq_b = (freq_b == afi->af[i]) ? 0 : freq_b;
+-		}
+-		/* return early if there is nothing to do */
+-		if (freq_a == 0 && freq_b == 0)
+-			return false;
+-
+-		/* add the new AFs if they were previously unknown */
+-		if (freq_a != 0) {
+-			afi->af[af_index] = freq_a;
+-			af_index = (af_index+1 < MAX_TMC_AF_CNT) ? af_index+1 : 0;
+-			afi->af_size++; 
+-		}
+-		if (freq_b != 0) {
+-			afi->af[af_index] = freq_b;
+-			af_index = (af_index+1 < MAX_TMC_AF_CNT) ? af_index+1 : 0;
+-			afi->af_size++; 
+-		}
+-		/* update the information in the handle */
+-		afi->af_index = af_index;
+-		if (afi->af_size >= MAX_TMC_AF_CNT) 
+-			afi->af_size = MAX_TMC_AF_CNT;
+-
+-		return true;
+-	}
+ 
+-	/* mapped frequency pair */
+-	else if (variant == 7) {
+-		/* check the if there's already a frequency mapped to the new tuning
+-		 * frequency, update the mapped frequency in this case */
+-		for (int i = 0; i < afi->mapped_af_size; i++) {
+-			if (freq_a == afi->mapped_af_tuning[i])
+-				afi->mapped_af[i] = freq_b;
+-				return true;
+-		}
+-		/* new pair is unknown, add it to the list */
+-		if (freq_a != 0 && freq_b != 0) {
+-			mapped_af_index = (mapped_af_index+1 >= MAX_TMC_AF_CNT) ? 0 : mapped_af_index + 1;
+-			afi->mapped_af[mapped_af_index] = freq_b;
+-			afi->mapped_af_tuning[mapped_af_index] = freq_a;
+-			afi->mapped_af_size++; 
+-		}
+-		/* update the information in the handle */
+-		afi->mapped_af_index = mapped_af_index;
+-		if (afi->mapped_af_size >= MAX_TMC_AF_CNT) 
+-			afi->mapped_af_size = MAX_TMC_AF_CNT;
+-
+-		return true;
+-	}
+-	return false;
+-}
+ 
+ /* adds one char of the ps name to temporal storage, the value is validated
+  * if it is received twice in a row
+@@ -975,29 +995,6 @@ static uint32_t rds_decode_group3(struct rds_private_state *priv_state)
+ 	return updated_fields;
+ }
+ 
+-/* decodes the RDS radio frequency representation into Hz
+- * @af: 8-bit AF value as transmitted in RDS groups
+- * @is_vhf: boolean value defining  which conversion table to use
+- * @return: frequency in Hz, 0 in case of wrong input values */
+-static uint32_t rds_decode_af(uint8_t af, bool is_vhf) {
+-	uint32_t freq = 0;
+-
+-	/* AF = 0 => "not to be used"
+-	 * AF >= 205 => special meanings */
+-	if (af == 0 || af >= 205)
+-		return 0;
+-
+-	/* calculate the AF values in HZ */
+-	if (is_vhf)
+-		freq = 87500000 + af * 100000;
+-	else if (freq <= 15)
+-		freq = 152000 + af * 9000;
+-	else
+-		freq = 531000 + af * 9000;
+-
+-	return freq;
+-}
+-
+ /* decodes the RDS date/time representation into a standard c representation
+  * that can be used with c-library functions */
+ static time_t rds_decode_mjd(const struct rds_private_state *priv_state)
+-- 
+1.8.2.1
+
diff --git a/0005-rds-ctl-support-d10-to-refer-to-radio10.patch b/0005-rds-ctl-support-d10-to-refer-to-radio10.patch
new file mode 100644
index 0000000..af9fde6
--- /dev/null
+++ b/0005-rds-ctl-support-d10-to-refer-to-radio10.patch
@@ -0,0 +1,43 @@
+From c7bdfa014bac092cc4490820708ad65da07cf15c Mon Sep 17 00:00:00 2001
+From: Hans Verkuil <hans.verkuil at cisco.com>
+Date: Fri, 7 Jun 2013 10:22:51 +0200
+Subject: [PATCH 5/6] rds-ctl: support -d10 to refer to radio10.
+
+In order to be consistent with other v4l utilities support the '-d<num>' option
+for num >= 10.
+
+Signed-off-by: Hans Verkuil <hans.verkuil at cisco.com>
+---
+ utils/rds-ctl/rds-ctl.cpp | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/utils/rds-ctl/rds-ctl.cpp b/utils/rds-ctl/rds-ctl.cpp
+index d894ec1..a9fe2a8 100644
+--- a/utils/rds-ctl/rds-ctl.cpp
++++ b/utils/rds-ctl/rds-ctl.cpp
+@@ -133,7 +133,7 @@ static void usage_common(void)
+ 	       "  --all              display all device information available\n"
+ 	       "  -D, --info         show driver info [VIDIOC_QUERYCAP]\n"
+ 	       "  -d, --device=<dev> use device <dev>\n"
+-	       "                     if <dev> is a single digit, then /dev/radio<dev> is used\n"
++	       "                     If <dev> starts with a digit, then /dev/radio<dev> is used\n"
+ 	       "                     default: checks for RDS-capable devices,\n"
+ 	       "                     uses device with lowest ID\n"
+ 	       "  -h, --help         display this help message\n"
+@@ -763,9 +763,10 @@ static int parse_cl(int argc, char **argv)
+ 		switch (opt) {
+ 		case OptSetDevice:
+ 			strncpy(params.fd_name, optarg, 80);
+-			if (isdigit(optarg[0]) && optarg[1] == 0) {
+-				char newdev[20];
+-				sprintf(newdev, "/dev/radio%c", optarg[0]);
++			if (optarg[0] >= '0' && optarg[0] <= '9' && strlen(optarg) <= 3) {
++				static char newdev[20];
++
++				sprintf(newdev, "/dev/radio%s", optarg);
+ 				strncpy(params.fd_name, newdev, 20);
+ 			}
+ 			break;
+-- 
+1.8.2.1
+
diff --git a/0006-libv4l2-Add-logging-of-dqbuf-timestamps-to-debug-log.patch b/0006-libv4l2-Add-logging-of-dqbuf-timestamps-to-debug-log.patch
new file mode 100644
index 0000000..9126683
--- /dev/null
+++ b/0006-libv4l2-Add-logging-of-dqbuf-timestamps-to-debug-log.patch
@@ -0,0 +1,31 @@
+From 38d8bf17783cda83ec05920094896c9275835529 Mon Sep 17 00:00:00 2001
+From: Hans de Goede <hdegoede at redhat.com>
+Date: Sun, 9 Jun 2013 16:31:55 +0200
+Subject: [PATCH 6/6] libv4l2: Add logging of dqbuf timestamps to debug logging
+
+Signed-off-by: Hans de Goede <hdegoede at redhat.com>
+---
+ lib/libv4l2/log.c | 7 +++++++
+ 1 file changed, 7 insertions(+)
+
+diff --git a/lib/libv4l2/log.c b/lib/libv4l2/log.c
+index 45c0e6b..8aa5310 100644
+--- a/lib/libv4l2/log.c
++++ b/lib/libv4l2/log.c
+@@ -173,6 +173,13 @@ void v4l2_log_ioctl(unsigned long int request, void *arg, int result)
+ 				req->count, (int)req->type, (int)req->memory);
+ 		break;
+ 	}
++	case VIDIOC_DQBUF: {
++		struct v4l2_buffer *buf = arg;
++		fprintf(v4l2_log_file, "  timestamp %ld.%06ld\n",
++			(long)buf->timestamp.tv_sec,
++			(long)buf->timestamp.tv_usec);
++		break;
++	}
+ 	case VIDIOC_ENUM_FRAMESIZES: {
+ 		struct v4l2_frmsizeenum *frmsize = arg;
+ 		int pixfmt = frmsize->pixel_format;
+-- 
+1.8.2.1
+
diff --git a/v4l-utils.spec b/v4l-utils.spec
index 0d4c165..5c1cb88 100644
--- a/v4l-utils.spec
+++ b/v4l-utils.spec
@@ -1,12 +1,18 @@
 Name:           v4l-utils
 Version:        0.9.5
-Release:        1%{?dist}
+Release:        2%{?dist}
 Summary:        Utilities for video4linux and DVB devices
 Group:          Applications/System
 # ir-keytable and v4l2-sysfs-path are GPLv2 only
 License:        GPLv2+ and GPLv2
 URL:            http://www.linuxtv.org/downloads/v4l-utils/
 Source0:        http://linuxtv.org/downloads/v4l-utils/v4l-utils-%{version}.tar.bz2
+Patch1:         0001-rds-ctl-fix-percentage-handling.patch
+Patch2:         0002-libv4l2rds-support-RDS-EON-and-TMC-tuning-info.patch
+Patch3:         0003-rds-ctl-support-RDS-EON-and-TMC-tuning-info.patch
+Patch4:         0004-libv4l2rds.c-moving-functions-to-get-rid-of-declarat.patch
+Patch5:         0005-rds-ctl-support-d10-to-refer-to-radio10.patch
+Patch6:         0006-libv4l2-Add-logging-of-dqbuf-timestamps-to-debug-log.patch
 BuildRequires:  libjpeg-devel qt4-devel kernel-headers desktop-file-utils
 # For /lib/udev/rules.d ownership
 Requires:       udev
@@ -77,6 +83,12 @@ developing applications that use libv4l.
 
 %prep
 %setup -q
+%patch1 -p1
+%patch2 -p1
+%patch3 -p1
+%patch4 -p1
+%patch5 -p1
+%patch6 -p1
 
 
 %build
@@ -155,6 +167,11 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
 
 
 %changelog
+* Fri Jun 14 2013 Hans de Goede <hdegoede at redhat.com> - 0.9.5-2
+- Add a few libv4l2rds patches from upstream, which bring libv4l2rds to its
+  final API / ABI, so that apps build against it won't need a rebuild in the
+  future
+
 * Sun Jun  9 2013 Hans de Goede <hdegoede at redhat.com> - 0.9.5-1
 - New upstream release 0.9.5 (rhbz#970412)
 - Modernize specfile a bit


More information about the scm-commits mailing list