public inbox for linux-media@vger.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 0/7] si4713 enhancements, add miro RDS support
@ 2014-02-07 12:19 Hans Verkuil
  2014-02-07 12:19 ` [RFC PATCH 1/7] v4l2-ctrls: add new RDS TX controls Hans Verkuil
                   ` (6 more replies)
  0 siblings, 7 replies; 9+ messages in thread
From: Hans Verkuil @ 2014-02-07 12:19 UTC (permalink / raw)
  To: linux-media; +Cc: edubezval

This patch series adds some missing RDS functionality to the si4713
driver. In addition it adds back support for RDS to the radio-miropcm20
driver that was dropped somewhere around the 2.6.2x timeframe.

It's been tested with a miropcm20 board, an si4713 board and a si470x
based usb stick.

Regards,

	Hans


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [RFC PATCH 1/7] v4l2-ctrls: add new RDS TX controls
  2014-02-07 12:19 [RFC PATCH 0/7] si4713 enhancements, add miro RDS support Hans Verkuil
@ 2014-02-07 12:19 ` Hans Verkuil
  2014-02-10  9:52   ` Hans Verkuil
  2014-02-07 12:19 ` [RFC PATCH 2/7] DocBook/media: document the " Hans Verkuil
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 9+ messages in thread
From: Hans Verkuil @ 2014-02-07 12:19 UTC (permalink / raw)
  To: linux-media; +Cc: edubezval, Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

The si4713 supports several RDS features not yet implemented in the driver.

This patch adds the missing RDS functionality to the list of RDS controls.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Eduardo Valentin <edubezval@gmail.com>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 17 +++++++++++++++++
 include/uapi/linux/v4l2-controls.h   |  9 +++++++++
 2 files changed, 26 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 6ff002b..66a2d0b 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -794,6 +794,15 @@ const char *v4l2_ctrl_get_name(u32 id)
 	case V4L2_CID_RDS_TX_PTY:		return "RDS Program Type";
 	case V4L2_CID_RDS_TX_PS_NAME:		return "RDS PS Name";
 	case V4L2_CID_RDS_TX_RADIO_TEXT:	return "RDS Radio Text";
+	case V4L2_CID_RDS_TX_MONO_STEREO:	return "RDS Stereo";
+	case V4L2_CID_RDS_TX_ARTIFICIAL_HEAD:	return "RDS Artificial Head";
+	case V4L2_CID_RDS_TX_COMPRESSED:	return "RDS Compressed";
+	case V4L2_CID_RDS_TX_DYNAMIC_PTY:	return "RDS Dynamic PTY";
+	case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT: return "RDS Traffic Announcement";
+	case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM:	return "RDS Traffic Program";
+	case V4L2_CID_RDS_TX_MUSIC_SPEECH:	return "RDS Music";
+	case V4L2_CID_RDS_TX_ALT_FREQ_ENABLE:	return "RDS Enable Alternate Frequency";
+	case V4L2_CID_RDS_TX_ALT_FREQ:		return "RDS Alternate Frequency";
 	case V4L2_CID_AUDIO_LIMITER_ENABLED:	return "Audio Limiter Feature Enabled";
 	case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: return "Audio Limiter Release Time";
 	case V4L2_CID_AUDIO_LIMITER_DEVIATION:	return "Audio Limiter Deviation";
@@ -906,6 +915,14 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
 	case V4L2_CID_WIDE_DYNAMIC_RANGE:
 	case V4L2_CID_IMAGE_STABILIZATION:
 	case V4L2_CID_RDS_RECEPTION:
+	case V4L2_CID_RDS_TX_MONO_STEREO:
+	case V4L2_CID_RDS_TX_ARTIFICIAL_HEAD:
+	case V4L2_CID_RDS_TX_COMPRESSED:
+	case V4L2_CID_RDS_TX_DYNAMIC_PTY:
+	case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT:
+	case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM:
+	case V4L2_CID_RDS_TX_MUSIC_SPEECH:
+	case V4L2_CID_RDS_TX_ALT_FREQ_ENABLE:
 		*type = V4L2_CTRL_TYPE_BOOLEAN;
 		*min = 0;
 		*max = *step = 1;
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 2cbe605..21abf77 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -753,6 +753,15 @@ enum v4l2_auto_focus_range {
 #define V4L2_CID_RDS_TX_PTY			(V4L2_CID_FM_TX_CLASS_BASE + 3)
 #define V4L2_CID_RDS_TX_PS_NAME			(V4L2_CID_FM_TX_CLASS_BASE + 5)
 #define V4L2_CID_RDS_TX_RADIO_TEXT		(V4L2_CID_FM_TX_CLASS_BASE + 6)
+#define V4L2_CID_RDS_TX_MONO_STEREO		(V4L2_CID_FM_TX_CLASS_BASE + 7)
+#define V4L2_CID_RDS_TX_ARTIFICIAL_HEAD		(V4L2_CID_FM_TX_CLASS_BASE + 8)
+#define V4L2_CID_RDS_TX_COMPRESSED		(V4L2_CID_FM_TX_CLASS_BASE + 9)
+#define V4L2_CID_RDS_TX_DYNAMIC_PTY		(V4L2_CID_FM_TX_CLASS_BASE + 10)
+#define V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT	(V4L2_CID_FM_TX_CLASS_BASE + 11)
+#define V4L2_CID_RDS_TX_TRAFFIC_PROGRAM		(V4L2_CID_FM_TX_CLASS_BASE + 12)
+#define V4L2_CID_RDS_TX_MUSIC_SPEECH		(V4L2_CID_FM_TX_CLASS_BASE + 13)
+#define V4L2_CID_RDS_TX_ALT_FREQ_ENABLE		(V4L2_CID_FM_TX_CLASS_BASE + 14)
+#define V4L2_CID_RDS_TX_ALT_FREQ		(V4L2_CID_FM_TX_CLASS_BASE + 15)
 
 #define V4L2_CID_AUDIO_LIMITER_ENABLED		(V4L2_CID_FM_TX_CLASS_BASE + 64)
 #define V4L2_CID_AUDIO_LIMITER_RELEASE_TIME	(V4L2_CID_FM_TX_CLASS_BASE + 65)
-- 
1.8.5.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 2/7] DocBook/media: document the new RDS TX controls
  2014-02-07 12:19 [RFC PATCH 0/7] si4713 enhancements, add miro RDS support Hans Verkuil
  2014-02-07 12:19 ` [RFC PATCH 1/7] v4l2-ctrls: add new RDS TX controls Hans Verkuil
@ 2014-02-07 12:19 ` Hans Verkuil
  2014-02-07 12:19 ` [RFC PATCH 3/7] si4713: add the missing RDS functionality Hans Verkuil
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Hans Verkuil @ 2014-02-07 12:19 UTC (permalink / raw)
  To: linux-media; +Cc: edubezval, Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

Document the new RDS features that will be supported by the si4713 driver.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Eduardo Valentin <edubezval@gmail.com>
---
 Documentation/DocBook/media/v4l/controls.xml | 60 ++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index a5a3188..58fd169 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -3980,6 +3980,66 @@ to find receivers which can scroll strings sized as 32 x N or 64 x N characters.
 with steps of 32 or 64 characters. The result is it must always contain a string with size multiple of 32 or 64. </entry>
 	  </row>
 	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_MONO_STEREO</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the Mono/Stereo bit of the Decoder Identification code. If set,
+then the audio was recorded as stereo.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_ARTIFICIAL_HEAD</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the
+<ulink url="http://en.wikipedia.org/wiki/Artificial_head">Artificial Head</ulink> bit of the Decoder
+Identification code. If set, then the audio was recorded using an artificial head.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_COMPRESSED</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the Compressed bit of the Decoder Identification code. If set,
+then the audio is compressed.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_DYNAMIC_PTY</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">Sets the Dynamic PTY bit of the Decoder Identification code. If set,
+then the PTY code is dynamically switched.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">If set, then a traffic announcement is in progress.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_TRAFFIC_PROGRAM</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">If set, then the tuned programme carries traffic announcements.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_MUSIC_SPEECH</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">If set, then this channel broadcasts music. If cleared, then it
+broadcasts speech. If the transmitter doesn't make this distinction, then it should be set.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_ALT_FREQ_ENABLE</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">If set, then transmit alternate frequencies.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_TX_FREQ</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row><entry spanname="descr">The alternate frequency (in Hz).</entry>
+	  </row>
+	  <row>
 	    <entry spanname="id"><constant>V4L2_CID_AUDIO_LIMITER_ENABLED</constant>&nbsp;</entry>
 	    <entry>boolean</entry>
 	  </row>
-- 
1.8.5.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 3/7] si4713: add the missing RDS functionality.
  2014-02-07 12:19 [RFC PATCH 0/7] si4713 enhancements, add miro RDS support Hans Verkuil
  2014-02-07 12:19 ` [RFC PATCH 1/7] v4l2-ctrls: add new RDS TX controls Hans Verkuil
  2014-02-07 12:19 ` [RFC PATCH 2/7] DocBook/media: document the " Hans Verkuil
@ 2014-02-07 12:19 ` Hans Verkuil
  2014-02-07 12:19 ` [RFC PATCH 4/7] v4l2-ctrls: add RX RDS controls Hans Verkuil
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Hans Verkuil @ 2014-02-07 12:19 UTC (permalink / raw)
  To: linux-media; +Cc: edubezval, Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

Not all the RDS features of the si4713 were supported. Add
the missing bits to fully support the hardware capabilities.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Cc: Eduardo Valentin <edubezval@gmail.com>
---
 drivers/media/radio/si4713/si4713.c | 64 ++++++++++++++++++++++++++++++++++++-
 drivers/media/radio/si4713/si4713.h |  9 ++++++
 2 files changed, 72 insertions(+), 1 deletion(-)

diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c
index 07d5153..741db93 100644
--- a/drivers/media/radio/si4713/si4713.c
+++ b/drivers/media/radio/si4713/si4713.c
@@ -957,6 +957,41 @@ static int si4713_choose_econtrol_action(struct si4713_device *sdev, u32 id,
 		*bit = 5;
 		*mask = 0x1F << 5;
 		break;
+	case V4L2_CID_RDS_TX_DYNAMIC_PTY:
+		*property = SI4713_TX_RDS_PS_MISC;
+		*bit = 15;
+		*mask = 1 << 15;
+		break;
+	case V4L2_CID_RDS_TX_COMPRESSED:
+		*property = SI4713_TX_RDS_PS_MISC;
+		*bit = 14;
+		*mask = 1 << 14;
+		break;
+	case V4L2_CID_RDS_TX_ARTIFICIAL_HEAD:
+		*property = SI4713_TX_RDS_PS_MISC;
+		*bit = 13;
+		*mask = 1 << 13;
+		break;
+	case V4L2_CID_RDS_TX_MONO_STEREO:
+		*property = SI4713_TX_RDS_PS_MISC;
+		*bit = 12;
+		*mask = 1 << 12;
+		break;
+	case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM:
+		*property = SI4713_TX_RDS_PS_MISC;
+		*bit = 10;
+		*mask = 1 << 10;
+		break;
+	case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT:
+		*property = SI4713_TX_RDS_PS_MISC;
+		*bit = 4;
+		*mask = 1 << 4;
+		break;
+	case V4L2_CID_RDS_TX_MUSIC_SPEECH:
+		*property = SI4713_TX_RDS_PS_MISC;
+		*bit = 3;
+		*mask = 1 << 3;
+		break;
 	case V4L2_CID_AUDIO_LIMITER_ENABLED:
 		*property = SI4713_TX_ACOMP_ENABLE;
 		*bit = 1;
@@ -1122,6 +1157,15 @@ static int si4713_s_ctrl(struct v4l2_ctrl *ctrl)
 			}
 			break;
 
+		case V4L2_CID_RDS_TX_ALT_FREQ_ENABLE:
+		case V4L2_CID_RDS_TX_ALT_FREQ:
+			if (sdev->rds_alt_freq_enable->val)
+				val = sdev->rds_alt_freq->val / 100 - 876 + 0xe101;
+			else
+				val = 0xe0e0;
+			ret = si4713_write_property(sdev, SI4713_TX_RDS_PS_AF, val);
+			break;
+
 		default:
 			ret = si4713_choose_econtrol_action(sdev, ctrl->id, &bit,
 					&mask, &property, &mul, &table, &size);
@@ -1410,6 +1454,24 @@ static int si4713_probe(struct i2c_client *client,
 			V4L2_CID_RDS_TX_PI, 0, 0xffff, 1, DEFAULT_RDS_PI);
 	sdev->rds_pty = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
 			V4L2_CID_RDS_TX_PTY, 0, 31, 1, DEFAULT_RDS_PTY);
+	sdev->rds_compressed = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+			V4L2_CID_RDS_TX_COMPRESSED, 0, 1, 1, 0);
+	sdev->rds_art_head = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+			V4L2_CID_RDS_TX_ARTIFICIAL_HEAD, 0, 1, 1, 0);
+	sdev->rds_stereo = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+			V4L2_CID_RDS_TX_MONO_STEREO, 0, 1, 1, 1);
+	sdev->rds_tp = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+			V4L2_CID_RDS_TX_TRAFFIC_PROGRAM, 0, 1, 1, 0);
+	sdev->rds_ta = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+			V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT, 0, 1, 1, 0);
+	sdev->rds_ms = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+			V4L2_CID_RDS_TX_MUSIC_SPEECH, 0, 1, 1, 1);
+	sdev->rds_dyn_pty = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+			V4L2_CID_RDS_TX_DYNAMIC_PTY, 0, 1, 1, 0);
+	sdev->rds_alt_freq_enable = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+			V4L2_CID_RDS_TX_ALT_FREQ_ENABLE, 0, 1, 1, 0);
+	sdev->rds_alt_freq = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
+			V4L2_CID_RDS_TX_ALT_FREQ, 87600, 107900, 100, 87600);
 	sdev->rds_deviation = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
 			V4L2_CID_RDS_TX_DEVIATION, 0, MAX_RDS_DEVIATION,
 			10, DEFAULT_RDS_DEVIATION);
@@ -1476,7 +1538,7 @@ static int si4713_probe(struct i2c_client *client,
 		rval = hdl->error;
 		goto free_ctrls;
 	}
-	v4l2_ctrl_cluster(20, &sdev->mute);
+	v4l2_ctrl_cluster(29, &sdev->mute);
 	sdev->sd.ctrl_handler = hdl;
 
 	if (client->irq) {
diff --git a/drivers/media/radio/si4713/si4713.h b/drivers/media/radio/si4713/si4713.h
index 4837cf6..3bee6a5 100644
--- a/drivers/media/radio/si4713/si4713.h
+++ b/drivers/media/radio/si4713/si4713.h
@@ -211,6 +211,15 @@ struct si4713_device {
 		struct v4l2_ctrl *rds_pi;
 		struct v4l2_ctrl *rds_deviation;
 		struct v4l2_ctrl *rds_pty;
+		struct v4l2_ctrl *rds_compressed;
+		struct v4l2_ctrl *rds_art_head;
+		struct v4l2_ctrl *rds_stereo;
+		struct v4l2_ctrl *rds_ta;
+		struct v4l2_ctrl *rds_tp;
+		struct v4l2_ctrl *rds_ms;
+		struct v4l2_ctrl *rds_dyn_pty;
+		struct v4l2_ctrl *rds_alt_freq_enable;
+		struct v4l2_ctrl *rds_alt_freq;
 		struct v4l2_ctrl *compression_enabled;
 		struct v4l2_ctrl *compression_threshold;
 		struct v4l2_ctrl *compression_gain;
-- 
1.8.5.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 4/7] v4l2-ctrls: add RX RDS controls.
  2014-02-07 12:19 [RFC PATCH 0/7] si4713 enhancements, add miro RDS support Hans Verkuil
                   ` (2 preceding siblings ...)
  2014-02-07 12:19 ` [RFC PATCH 3/7] si4713: add the missing RDS functionality Hans Verkuil
@ 2014-02-07 12:19 ` Hans Verkuil
  2014-02-07 12:19 ` [RFC PATCH 5/7] DocBook/media: document the new RDS RX controls Hans Verkuil
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 9+ messages in thread
From: Hans Verkuil @ 2014-02-07 12:19 UTC (permalink / raw)
  To: linux-media; +Cc: edubezval, Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

The radio-miropcm20 driver has firmware that decodes the RDS signals. So in that
case the RDS data becomes available in the form of controls.

Add support for these controls to the control framework, allowing the miro driver
to use them.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 17 +++++++++++++++++
 include/uapi/linux/v4l2-controls.h   |  6 ++++++
 2 files changed, 23 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 66a2d0b..7c138b5 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -866,6 +866,12 @@ const char *v4l2_ctrl_get_name(u32 id)
 	case V4L2_CID_FM_RX_CLASS:		return "FM Radio Receiver Controls";
 	case V4L2_CID_TUNE_DEEMPHASIS:		return "De-Emphasis";
 	case V4L2_CID_RDS_RECEPTION:		return "RDS Reception";
+	case V4L2_CID_RDS_RX_PTY:		return "RDS Program Type";
+	case V4L2_CID_RDS_RX_PS_NAME:		return "RDS PS Name";
+	case V4L2_CID_RDS_RX_RADIO_TEXT:	return "RDS Radio Text";
+	case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT: return "RDS Traffic Announcement";
+	case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM:	return "RDS Traffic Program";
+	case V4L2_CID_RDS_RX_MUSIC_SPEECH:	return "RDS Music";
 	default:
 		return NULL;
 	}
@@ -923,6 +929,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
 	case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM:
 	case V4L2_CID_RDS_TX_MUSIC_SPEECH:
 	case V4L2_CID_RDS_TX_ALT_FREQ_ENABLE:
+	case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT:
+	case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM:
+	case V4L2_CID_RDS_RX_MUSIC_SPEECH:
 		*type = V4L2_CTRL_TYPE_BOOLEAN;
 		*min = 0;
 		*max = *step = 1;
@@ -990,6 +999,8 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
 		break;
 	case V4L2_CID_RDS_TX_PS_NAME:
 	case V4L2_CID_RDS_TX_RADIO_TEXT:
+	case V4L2_CID_RDS_RX_PS_NAME:
+	case V4L2_CID_RDS_RX_RADIO_TEXT:
 		*type = V4L2_CTRL_TYPE_STRING;
 		break;
 	case V4L2_CID_ISO_SENSITIVITY:
@@ -1096,6 +1107,12 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
 	case V4L2_CID_DV_TX_RXSENSE:
 	case V4L2_CID_DV_TX_EDID_PRESENT:
 	case V4L2_CID_DV_RX_POWER_PRESENT:
+	case V4L2_CID_RDS_RX_PTY:
+	case V4L2_CID_RDS_RX_PS_NAME:
+	case V4L2_CID_RDS_RX_RADIO_TEXT:
+	case V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT:
+	case V4L2_CID_RDS_RX_TRAFFIC_PROGRAM:
+	case V4L2_CID_RDS_RX_MUSIC_SPEECH:
 		*flags |= V4L2_CTRL_FLAG_READ_ONLY;
 		break;
 	}
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 21abf77..52c9679 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -903,5 +903,11 @@ enum v4l2_deemphasis {
 };
 
 #define V4L2_CID_RDS_RECEPTION			(V4L2_CID_FM_RX_CLASS_BASE + 2)
+#define V4L2_CID_RDS_RX_PTY			(V4L2_CID_FM_RX_CLASS_BASE + 3)
+#define V4L2_CID_RDS_RX_PS_NAME			(V4L2_CID_FM_RX_CLASS_BASE + 4)
+#define V4L2_CID_RDS_RX_RADIO_TEXT		(V4L2_CID_FM_RX_CLASS_BASE + 5)
+#define V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT	(V4L2_CID_FM_RX_CLASS_BASE + 6)
+#define V4L2_CID_RDS_RX_TRAFFIC_PROGRAM		(V4L2_CID_FM_RX_CLASS_BASE + 7)
+#define V4L2_CID_RDS_RX_MUSIC_SPEECH		(V4L2_CID_FM_RX_CLASS_BASE + 8)
 
 #endif
-- 
1.8.5.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 5/7] DocBook/media: document the new RDS RX controls
  2014-02-07 12:19 [RFC PATCH 0/7] si4713 enhancements, add miro RDS support Hans Verkuil
                   ` (3 preceding siblings ...)
  2014-02-07 12:19 ` [RFC PATCH 4/7] v4l2-ctrls: add RX RDS controls Hans Verkuil
@ 2014-02-07 12:19 ` Hans Verkuil
  2014-02-07 12:19 ` [RFC PATCH 6/7] v4l2-ctrls: add support for setting string controls Hans Verkuil
  2014-02-07 12:19 ` [RFC PATCH 7/7] radio-miropcm20: add RDS support Hans Verkuil
  6 siblings, 0 replies; 9+ messages in thread
From: Hans Verkuil @ 2014-02-07 12:19 UTC (permalink / raw)
  To: linux-media; +Cc: edubezval, Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

Document the new RDS receiver controls. This will be used by the radio-miropcm20
driver.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 Documentation/DocBook/media/v4l/controls.xml | 51 ++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index 58fd169..29f7ffc 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -4998,6 +4998,57 @@ description of this control class.</entry>
           </row><row><entry spanname="descr">Enables/disables RDS
 	  reception by the radio tuner</entry>
           </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_RX_PTY</constant>&nbsp;</entry>
+	    <entry>integer</entry>
+	  </row>
+	  <row><entry spanname="descr">Gets RDS Programme Type field.
+This encodes up to 31 pre-defined programme types.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_RX_PS_NAME</constant>&nbsp;</entry>
+	    <entry>string</entry>
+	  </row>
+	  <row><entry spanname="descr">Gets the Programme Service name (PS_NAME).
+It is intended for static display on a receiver. It is the primary aid to listeners in programme service
+identification and selection.  In Annex E of <xref linkend="iec62106" />, the RDS specification,
+there is a full description of the correct character encoding for Programme Service name strings.
+Also from RDS specification, PS is usually a single eight character text. However, it is also possible
+to find receivers which can scroll strings sized as 8 x N characters. So, this control must be configured
+with steps of 8 characters. The result is it must always contain a string with size multiple of 8.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_RX_RADIO_TEXT</constant>&nbsp;</entry>
+	    <entry>string</entry>
+	  </row>
+	  <row><entry spanname="descr">Gets the Radio Text info. It is a textual description of
+what is being broadcasted. RDS Radio Text can be applied when broadcaster wishes to transmit longer PS names,
+programme-related information or any other text. In these cases, RadioText can be used in addition to
+<constant>V4L2_CID_RDS_RX_PS_NAME</constant>. The encoding for Radio Text strings is also fully described
+in Annex E of <xref linkend="iec62106" />. The length of Radio Text strings depends on which RDS Block is being
+used to transmit it, either 32 (2A block) or 64 (2B block).  However, it is also possible
+to find receivers which can scroll strings sized as 32 x N or 64 x N characters. So, this control must be configured
+with steps of 32 or 64 characters. The result is it must always contain a string with size multiple of 32 or 64. </entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">If set, then a traffic announcement is in progress.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_RX_TRAFFIC_PROGRAM</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">If set, then the tuned programme carries traffic announcements.</entry>
+	  </row>
+	  <row>
+	    <entry spanname="id"><constant>V4L2_CID_RDS_RX_MUSIC_SPEECH</constant>&nbsp;</entry>
+	    <entry>boolean</entry>
+	  </row>
+	  <row><entry spanname="descr">If set, then this channel broadcasts music. If cleared, then it
+broadcasts speech. If the transmitter doesn't make this distinction, then it will be set.</entry>
+	  </row>
           <row>
 	    <entry spanname="id"><constant>V4L2_CID_TUNE_DEEMPHASIS</constant>&nbsp;</entry>
 	    <entry>enum v4l2_deemphasis</entry>
-- 
1.8.5.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 6/7] v4l2-ctrls: add support for setting string controls
  2014-02-07 12:19 [RFC PATCH 0/7] si4713 enhancements, add miro RDS support Hans Verkuil
                   ` (4 preceding siblings ...)
  2014-02-07 12:19 ` [RFC PATCH 5/7] DocBook/media: document the new RDS RX controls Hans Verkuil
@ 2014-02-07 12:19 ` Hans Verkuil
  2014-02-07 12:19 ` [RFC PATCH 7/7] radio-miropcm20: add RDS support Hans Verkuil
  6 siblings, 0 replies; 9+ messages in thread
From: Hans Verkuil @ 2014-02-07 12:19 UTC (permalink / raw)
  To: linux-media; +Cc: edubezval, Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

Rather than always having to use a v4l2_ext_control struct to set
a control value from within a driver, switch to just setting the
new value. This is faster and it makes it possible to set more
complex types such as a string control.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 46 ++++++++++++++++++++++++------------
 include/media/v4l2-ctrls.h           | 12 ++++++++++
 2 files changed, 43 insertions(+), 15 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 7c138b5..2aad5c6 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -2786,26 +2786,22 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
 	struct v4l2_ctrl *master = ctrl->cluster[0];
 	int i;
 
-	/* String controls are not supported. The user_to_new() and
-	 * cur_to_user() calls below would need to be modified not to access
-	 * userspace memory when called from set_ctrl().
-	 */
-	if (ctrl->type == V4L2_CTRL_TYPE_STRING)
-		return -EINVAL;
-
 	/* Reset the 'is_new' flags of the cluster */
 	for (i = 0; i < master->ncontrols; i++)
 		if (master->cluster[i])
 			master->cluster[i]->is_new = 0;
 
+	if (c)
+		user_to_new(c, ctrl);
+
 	/* For autoclusters with volatiles that are switched from auto to
 	   manual mode we have to update the current volatile values since
 	   those will become the initial manual values after such a switch. */
 	if (master->is_auto && master->has_volatiles && ctrl == master &&
-	    !is_cur_manual(master) && c->value == master->manual_mode_value)
+	    !is_cur_manual(master) && ctrl->val == master->manual_mode_value)
 		update_from_auto_cluster(master);
 
-	user_to_new(c, ctrl);
+	ctrl->is_new = 1;
 	return try_or_set_cluster(fh, master, true, ch_flags);
 }
 
@@ -2853,26 +2849,46 @@ EXPORT_SYMBOL(v4l2_subdev_s_ctrl);
 
 int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
 {
-	struct v4l2_ext_control c;
+	int ret;
 
 	/* It's a driver bug if this happens. */
 	WARN_ON(!type_is_int(ctrl));
-	c.value = val;
-	return set_ctrl_lock(NULL, ctrl, &c);
+	v4l2_ctrl_lock(ctrl);
+	ctrl->val = val;
+	ret = set_ctrl(NULL, ctrl, NULL, 0);
+	v4l2_ctrl_unlock(ctrl);
+	return ret;
 }
 EXPORT_SYMBOL(v4l2_ctrl_s_ctrl);
 
 int v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val)
 {
-	struct v4l2_ext_control c;
+	int ret;
 
 	/* It's a driver bug if this happens. */
 	WARN_ON(ctrl->type != V4L2_CTRL_TYPE_INTEGER64);
-	c.value64 = val;
-	return set_ctrl_lock(NULL, ctrl, &c);
+	v4l2_ctrl_lock(ctrl);
+	ctrl->val64 = val;
+	ret = set_ctrl(NULL, ctrl, NULL, 0);
+	v4l2_ctrl_unlock(ctrl);
+	return ret;
 }
 EXPORT_SYMBOL(v4l2_ctrl_s_ctrl_int64);
 
+int v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s)
+{
+	int ret;
+
+	/* It's a driver bug if this happens. */
+	WARN_ON(ctrl->type != V4L2_CTRL_TYPE_STRING);
+	v4l2_ctrl_lock(ctrl);
+	strlcpy(ctrl->string, s, ctrl->maximum + 1);
+	ret = set_ctrl(NULL, ctrl, NULL, 0);
+	v4l2_ctrl_unlock(ctrl);
+	return ret;
+}
+EXPORT_SYMBOL(v4l2_ctrl_s_ctrl_string);
+
 void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify, void *priv)
 {
 	if (ctrl == NULL)
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index 16f7f26..ee00f11 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -640,6 +640,18 @@ s64 v4l2_ctrl_g_ctrl_int64(struct v4l2_ctrl *ctrl);
   */
 int v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val);
 
+/** v4l2_ctrl_s_ctrl_string() - Helper function to set a control's string value from within a driver.
+  * @ctrl:	The control.
+  * @s:		The new string.
+  *
+  * This set the control's new string safely by going through the control
+  * framework. This function will lock the control's handler, so it cannot be
+  * used from within the &v4l2_ctrl_ops functions.
+  *
+  * This function is for string type controls only.
+  */
+int v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s);
+
 /* Internal helper functions that deal with control events. */
 extern const struct v4l2_subscribed_event_ops v4l2_ctrl_sub_ev_ops;
 void v4l2_ctrl_replace(struct v4l2_event *old, const struct v4l2_event *new);
-- 
1.8.5.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [RFC PATCH 7/7] radio-miropcm20: add RDS support.
  2014-02-07 12:19 [RFC PATCH 0/7] si4713 enhancements, add miro RDS support Hans Verkuil
                   ` (5 preceding siblings ...)
  2014-02-07 12:19 ` [RFC PATCH 6/7] v4l2-ctrls: add support for setting string controls Hans Verkuil
@ 2014-02-07 12:19 ` Hans Verkuil
  6 siblings, 0 replies; 9+ messages in thread
From: Hans Verkuil @ 2014-02-07 12:19 UTC (permalink / raw)
  To: linux-media; +Cc: edubezval, Hans Verkuil

From: Hans Verkuil <hans.verkuil@cisco.com>

Once upon a time the radio-miropcm20 driver had RDS support. However, after
some internal kernel changes that support was removed. Now that we have a
nice RDS API I have been working on adding back this support. It has been
tested with the si4713 RDS transmitter and it is working quite nicely.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/radio/radio-miropcm20.c | 303 ++++++++++++++++++++++++++++++++--
 1 file changed, 286 insertions(+), 17 deletions(-)

diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c
index a7e93d7..62cda88 100644
--- a/drivers/media/radio/radio-miropcm20.c
+++ b/drivers/media/radio/radio-miropcm20.c
@@ -1,20 +1,35 @@
-/* Miro PCM20 radio driver for Linux radio support
+/*
+ * Miro PCM20 radio driver for Linux radio support
  * (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
  * Thanks to Norberto Pellici for the ACI device interface specification
  * The API part is based on the radiotrack driver by M. Kirkwood
  * This driver relies on the aci mixer provided by the snd-miro
  * ALSA driver.
  * Look there for further info...
- */
-
-/* What ever you think about the ACI, version 0x07 is not very well!
- * I can't get frequency, 'tuner status', 'tuner flags' or mute/mono
- * conditions...                Robert
+ *
+ * From the original miro RDS sources:
+ *
+ *  (c) 2001 Robert Siemer <Robert.Siemer@gmx.de>
+ *
+ *  Many thanks to Fred Seidel <seidel@metabox.de>, the
+ *  designer of the RDS decoder hardware. With his help
+ *  I was able to code this driver.
+ *  Thanks also to Norberto Pellicci, Dominic Mounteney
+ *  <DMounteney@pinnaclesys.com> and www.teleauskunft.de
+ *  for good hints on finding Fred. It was somewhat hard
+ *  to locate him here in Germany... [:
+ *
+ * This code has been reintroduced and converted to use
+ * the new V4L2 RDS API by:
+ *
+ * Hans Verkuil <hans.verkuil@cisco.com>
  */
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/delay.h>
 #include <linux/videodev2.h>
+#include <linux/kthread.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-ctrls.h>
@@ -22,6 +37,22 @@
 #include <media/v4l2-event.h>
 #include <sound/aci.h>
 
+#define RDS_DATASHIFT          2   /* Bit 2 */
+#define RDS_DATAMASK        (1 << RDS_DATASHIFT)
+#define RDS_BUSYMASK        0x10   /* Bit 4 */
+#define RDS_CLOCKMASK       0x08   /* Bit 3 */
+#define RDS_DATA(x)         (((x) >> RDS_DATASHIFT) & 1)
+
+#define RDS_STATUS      0x01
+#define RDS_STATIONNAME 0x02
+#define RDS_TEXT        0x03
+#define RDS_ALTFREQ     0x04
+#define RDS_TIMEDATE    0x05
+#define RDS_PI_CODE     0x06
+#define RDS_PTYTATP     0x07
+#define RDS_RESET       0x08
+#define RDS_RXVALUE     0x09
+
 static int radio_nr = -1;
 module_param(radio_nr, int, 0);
 MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX).  Default: -1 (autodetect)");
@@ -30,6 +61,14 @@ struct pcm20 {
 	struct v4l2_device v4l2_dev;
 	struct video_device vdev;
 	struct v4l2_ctrl_handler ctrl_handler;
+	struct v4l2_ctrl *rds_pty;
+	struct v4l2_ctrl *rds_ps_name;
+	struct v4l2_ctrl *rds_radio_test;
+	struct v4l2_ctrl *rds_ta;
+	struct v4l2_ctrl *rds_tp;
+	struct v4l2_ctrl *rds_ms;
+	/* thread for periodic RDS status checking */
+	struct task_struct *kthread;
 	unsigned long freq;
 	u32 audmode;
 	struct snd_miro_aci *aci;
@@ -41,6 +80,103 @@ static struct pcm20 pcm20_card = {
 	.audmode = V4L2_TUNER_MODE_STEREO,
 };
 
+
+static int rds_waitread(struct snd_miro_aci *aci)
+{
+	u8 byte;
+	int i = 2000;
+
+	do {
+		byte = inb(aci->aci_port + ACI_REG_RDS);
+		i--;
+	} while ((byte & RDS_BUSYMASK) && i);
+
+	/*
+	 * It's magic, but without this the data that you read later on
+	 * is unreliable and full of bit errors. With this 1 usec delay
+	 * everything is fine.
+	 */
+	udelay(1);
+	return i ? byte : -1;
+}
+
+static int rds_rawwrite(struct snd_miro_aci *aci, u8 byte)
+{
+	if (rds_waitread(aci) >= 0) {
+		outb(byte, aci->aci_port + ACI_REG_RDS);
+		return 0;
+	}
+	return -1;
+}
+
+static int rds_write(struct snd_miro_aci *aci, u8 byte)
+{
+	u8 sendbuffer[8];
+	int i;
+
+	for (i = 7; i >= 0; i--)
+		sendbuffer[7 - i] = (byte & (1 << i)) ? RDS_DATAMASK : 0;
+	sendbuffer[0] |= RDS_CLOCKMASK;
+
+	for (i = 0; i < 8; i++)
+		rds_rawwrite(aci, sendbuffer[i]);
+	return 0;
+}
+
+static int rds_readcycle_nowait(struct snd_miro_aci *aci)
+{
+	outb(0, aci->aci_port + ACI_REG_RDS);
+	return rds_waitread(aci);
+}
+
+static int rds_readcycle(struct snd_miro_aci *aci)
+{
+	if (rds_rawwrite(aci, 0) < 0)
+		return -1;
+	return rds_waitread(aci);
+}
+
+static int rds_ack(struct snd_miro_aci *aci)
+{
+	int i = rds_readcycle(aci);
+
+	if (i < 0)
+		return -1;
+	if (i & RDS_DATAMASK)
+		return 0;  /* ACK  */
+	return 1;  /* NACK */
+}
+
+static int rds_cmd(struct snd_miro_aci *aci, u8 cmd, u8 databuffer[], u8 datasize)
+{
+	int i, j;
+
+	rds_write(aci, cmd);
+
+	/* RDS_RESET doesn't need further processing */
+	if (cmd == RDS_RESET)
+		return 0;
+	if (rds_ack(aci))
+		return -EIO;
+	if (datasize == 0)
+		return 0;
+
+	/* to be able to use rds_readcycle_nowait()
+	   I have to waitread() here */
+	if (rds_waitread(aci) < 0)
+		return -1;
+
+	memset(databuffer, 0, datasize);
+
+	for (i = 0; i < 8 * datasize; i++) {
+		j = rds_readcycle_nowait(aci);
+		if (j < 0)
+			return -EIO;
+		databuffer[i / 8] |= RDS_DATA(j) << (7 - (i % 8));
+	}
+	return 0;
+}
+
 static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq)
 {
 	unsigned char freql;
@@ -54,17 +190,10 @@ static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq)
 	freql = freq & 0xff;
 	freqh = freq >> 8;
 
+	rds_cmd(aci, RDS_RESET, 0, 0);
 	return snd_aci_cmd(aci, ACI_WRITE_TUNE, freql, freqh);
 }
 
-static const struct v4l2_file_operations pcm20_fops = {
-	.owner		= THIS_MODULE,
-	.open		= v4l2_fh_open,
-	.poll		= v4l2_ctrl_poll,
-	.release	= v4l2_fh_release,
-	.unlocked_ioctl	= video_ioctl2,
-};
-
 static int vidioc_querycap(struct file *file, void *priv,
 				struct v4l2_capability *v)
 {
@@ -73,16 +202,31 @@ static int vidioc_querycap(struct file *file, void *priv,
 	strlcpy(v->driver, "Miro PCM20", sizeof(v->driver));
 	strlcpy(v->card, "Miro PCM20", sizeof(v->card));
 	snprintf(v->bus_info, sizeof(v->bus_info), "ISA:%s", dev->v4l2_dev.name);
-	v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+	v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
 	v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
 	return 0;
 }
 
+static bool sanitize(char *p, int size)
+{
+	int i;
+	bool ret = true;
+
+	for (i = 0; i < size; i++) {
+		if (p[i] < 32 || p[i] >= 128) {
+			p[i] = ' ';
+			ret = false;
+		}
+	}
+	return ret;
+}
+
 static int vidioc_g_tuner(struct file *file, void *priv,
 				struct v4l2_tuner *v)
 {
 	struct pcm20 *dev = video_drvdata(file);
 	int res;
+	u8 buf;
 
 	if (v->index)
 		return -EINVAL;
@@ -97,8 +241,12 @@ static int vidioc_g_tuner(struct file *file, void *priv,
 	res = snd_aci_cmd(dev->aci, ACI_READ_TUNERSTEREO, -1, -1);
 	v->rxsubchans = (res & 0x40) ? V4L2_TUNER_SUB_MONO :
 					V4L2_TUNER_SUB_STEREO;
-	v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+	v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
+			V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_CONTROLS;
 	v->audmode = dev->audmode;
+	res = rds_cmd(dev->aci, RDS_RXVALUE, &buf, 1);
+	if (res >= 0 && buf)
+		v->rxsubchans |= V4L2_TUNER_SUB_RDS;
 	return 0;
 }
 
@@ -157,6 +305,115 @@ static int pcm20_s_ctrl(struct v4l2_ctrl *ctrl)
 	return -EINVAL;
 }
 
+static int pcm20_thread(void *data)
+{
+	struct pcm20 *dev = data;
+	const unsigned no_rds_start_counter = 5;
+	const unsigned sleep_msecs = 2000;
+	unsigned no_rds_counter = no_rds_start_counter;
+
+	for (;;) {
+		char text_buffer[66];
+		u8 buf;
+		int res;
+
+		msleep_interruptible(sleep_msecs);
+
+		if (kthread_should_stop())
+			break;
+
+		res = rds_cmd(dev->aci, RDS_RXVALUE, &buf, 1);
+		if (res)
+			continue;
+		if (buf == 0) {
+			if (no_rds_counter == 0)
+				continue;
+			no_rds_counter--;
+			if (no_rds_counter)
+				continue;
+
+			/*
+			 * No RDS seen for no_rds_start_counter * sleep_msecs
+			 * milliseconds, clear all RDS controls to their
+			 * default values.
+			 */
+			v4l2_ctrl_s_ctrl_string(dev->rds_ps_name, "");
+			v4l2_ctrl_s_ctrl(dev->rds_ms, 1);
+			v4l2_ctrl_s_ctrl(dev->rds_ta, 0);
+			v4l2_ctrl_s_ctrl(dev->rds_tp, 0);
+			v4l2_ctrl_s_ctrl(dev->rds_pty, 0);
+			v4l2_ctrl_s_ctrl_string(dev->rds_radio_test, "");
+			continue;
+		}
+		no_rds_counter = no_rds_start_counter;
+
+		res = rds_cmd(dev->aci, RDS_STATUS, &buf, 1);
+		if (res)
+			continue;
+		if ((buf >> 3) & 1) {
+			res = rds_cmd(dev->aci, RDS_STATIONNAME, text_buffer, 8);
+			text_buffer[8] = 0;
+			if (!res && sanitize(text_buffer, 8))
+				v4l2_ctrl_s_ctrl_string(dev->rds_ps_name, text_buffer);
+		}
+		if ((buf >> 6) & 1) {
+			u8 pty;
+
+			res = rds_cmd(dev->aci, RDS_PTYTATP, &pty, 1);
+			if (!res) {
+				v4l2_ctrl_s_ctrl(dev->rds_ms, !!(pty & 0x01));
+				v4l2_ctrl_s_ctrl(dev->rds_ta, !!(pty & 0x02));
+				v4l2_ctrl_s_ctrl(dev->rds_tp, !!(pty & 0x80));
+				v4l2_ctrl_s_ctrl(dev->rds_pty, (pty >> 2) & 0x1f);
+			}
+		}
+		if ((buf >> 4) & 1) {
+			res = rds_cmd(dev->aci, RDS_TEXT, text_buffer, 65);
+			text_buffer[65] = 0;
+			if (!res && sanitize(text_buffer + 1, 64))
+				v4l2_ctrl_s_ctrl_string(dev->rds_radio_test, text_buffer + 1);
+		}
+	}
+	return 0;
+}
+
+static int pcm20_open(struct file *file)
+{
+	struct pcm20 *dev = video_drvdata(file);
+	int res = v4l2_fh_open(file);
+
+	if (!res && v4l2_fh_is_singular_file(file) &&
+	    IS_ERR_OR_NULL(dev->kthread)) {
+		dev->kthread = kthread_run(pcm20_thread, dev, "%s",
+					   dev->v4l2_dev.name);
+		if (IS_ERR(dev->kthread)) {
+			v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
+			v4l2_fh_release(file);
+			return PTR_ERR(dev->kthread);
+		}
+	}
+	return res;
+}
+
+static int pcm20_release(struct file *file)
+{
+	struct pcm20 *dev = video_drvdata(file);
+
+	if (v4l2_fh_is_singular_file(file) && !IS_ERR_OR_NULL(dev->kthread)) {
+		kthread_stop(dev->kthread);
+		dev->kthread = NULL;
+	}
+	return v4l2_fh_release(file);
+}
+
+static const struct v4l2_file_operations pcm20_fops = {
+	.owner		= THIS_MODULE,
+	.open		= pcm20_open,
+	.poll		= v4l2_ctrl_poll,
+	.release	= pcm20_release,
+	.unlocked_ioctl	= video_ioctl2,
+};
+
 static const struct v4l2_ioctl_ops pcm20_ioctl_ops = {
 	.vidioc_querycap    = vidioc_querycap,
 	.vidioc_g_tuner     = vidioc_g_tuner,
@@ -195,9 +452,21 @@ static int __init pcm20_init(void)
 	}
 
 	hdl = &dev->ctrl_handler;
-	v4l2_ctrl_handler_init(hdl, 1);
+	v4l2_ctrl_handler_init(hdl, 7);
 	v4l2_ctrl_new_std(hdl, &pcm20_ctrl_ops,
 			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+	dev->rds_pty = v4l2_ctrl_new_std(hdl, NULL,
+			V4L2_CID_RDS_RX_PTY, 0, 0x1f, 1, 0);
+	dev->rds_ps_name = v4l2_ctrl_new_std(hdl, NULL,
+			V4L2_CID_RDS_RX_PS_NAME, 0, 8, 8, 0);
+	dev->rds_radio_test = v4l2_ctrl_new_std(hdl, NULL,
+			V4L2_CID_RDS_RX_RADIO_TEXT, 0, 64, 64, 0);
+	dev->rds_ta = v4l2_ctrl_new_std(hdl, NULL,
+			V4L2_CID_RDS_RX_TRAFFIC_ANNOUNCEMENT, 0, 1, 1, 0);
+	dev->rds_tp = v4l2_ctrl_new_std(hdl, NULL,
+			V4L2_CID_RDS_RX_TRAFFIC_PROGRAM, 0, 1, 1, 0);
+	dev->rds_ms = v4l2_ctrl_new_std(hdl, NULL,
+			V4L2_CID_RDS_RX_MUSIC_SPEECH, 0, 1, 1, 1);
 	v4l2_dev->ctrl_handler = hdl;
 	if (hdl->error) {
 		res = hdl->error;
-- 
1.8.5.2


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [RFC PATCH 1/7] v4l2-ctrls: add new RDS TX controls
  2014-02-07 12:19 ` [RFC PATCH 1/7] v4l2-ctrls: add new RDS TX controls Hans Verkuil
@ 2014-02-10  9:52   ` Hans Verkuil
  0 siblings, 0 replies; 9+ messages in thread
From: Hans Verkuil @ 2014-02-10  9:52 UTC (permalink / raw)
  To: linux-media; +Cc: edubezval, Hans Verkuil

On 02/07/2014 01:19 PM, Hans Verkuil wrote:
> From: Hans Verkuil <hans.verkuil@cisco.com>
> 
> The si4713 supports several RDS features not yet implemented in the driver.
> 
> This patch adds the missing RDS functionality to the list of RDS controls.

I'm going to postpone this until the patch series adding support for complex control
types is merged. The ALT_FREQ control should really be an array control since you
can set up to 25 (if memory serves) alternate frequencies. Note though that this
particular device can handle only one alternate frequency.

Regards,

	Hans

> 
> Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
> Cc: Eduardo Valentin <edubezval@gmail.com>
> ---
>  drivers/media/v4l2-core/v4l2-ctrls.c | 17 +++++++++++++++++
>  include/uapi/linux/v4l2-controls.h   |  9 +++++++++
>  2 files changed, 26 insertions(+)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
> index 6ff002b..66a2d0b 100644
> --- a/drivers/media/v4l2-core/v4l2-ctrls.c
> +++ b/drivers/media/v4l2-core/v4l2-ctrls.c
> @@ -794,6 +794,15 @@ const char *v4l2_ctrl_get_name(u32 id)
>  	case V4L2_CID_RDS_TX_PTY:		return "RDS Program Type";
>  	case V4L2_CID_RDS_TX_PS_NAME:		return "RDS PS Name";
>  	case V4L2_CID_RDS_TX_RADIO_TEXT:	return "RDS Radio Text";
> +	case V4L2_CID_RDS_TX_MONO_STEREO:	return "RDS Stereo";
> +	case V4L2_CID_RDS_TX_ARTIFICIAL_HEAD:	return "RDS Artificial Head";
> +	case V4L2_CID_RDS_TX_COMPRESSED:	return "RDS Compressed";
> +	case V4L2_CID_RDS_TX_DYNAMIC_PTY:	return "RDS Dynamic PTY";
> +	case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT: return "RDS Traffic Announcement";
> +	case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM:	return "RDS Traffic Program";
> +	case V4L2_CID_RDS_TX_MUSIC_SPEECH:	return "RDS Music";
> +	case V4L2_CID_RDS_TX_ALT_FREQ_ENABLE:	return "RDS Enable Alternate Frequency";
> +	case V4L2_CID_RDS_TX_ALT_FREQ:		return "RDS Alternate Frequency";
>  	case V4L2_CID_AUDIO_LIMITER_ENABLED:	return "Audio Limiter Feature Enabled";
>  	case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: return "Audio Limiter Release Time";
>  	case V4L2_CID_AUDIO_LIMITER_DEVIATION:	return "Audio Limiter Deviation";
> @@ -906,6 +915,14 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
>  	case V4L2_CID_WIDE_DYNAMIC_RANGE:
>  	case V4L2_CID_IMAGE_STABILIZATION:
>  	case V4L2_CID_RDS_RECEPTION:
> +	case V4L2_CID_RDS_TX_MONO_STEREO:
> +	case V4L2_CID_RDS_TX_ARTIFICIAL_HEAD:
> +	case V4L2_CID_RDS_TX_COMPRESSED:
> +	case V4L2_CID_RDS_TX_DYNAMIC_PTY:
> +	case V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT:
> +	case V4L2_CID_RDS_TX_TRAFFIC_PROGRAM:
> +	case V4L2_CID_RDS_TX_MUSIC_SPEECH:
> +	case V4L2_CID_RDS_TX_ALT_FREQ_ENABLE:
>  		*type = V4L2_CTRL_TYPE_BOOLEAN;
>  		*min = 0;
>  		*max = *step = 1;
> diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
> index 2cbe605..21abf77 100644
> --- a/include/uapi/linux/v4l2-controls.h
> +++ b/include/uapi/linux/v4l2-controls.h
> @@ -753,6 +753,15 @@ enum v4l2_auto_focus_range {
>  #define V4L2_CID_RDS_TX_PTY			(V4L2_CID_FM_TX_CLASS_BASE + 3)
>  #define V4L2_CID_RDS_TX_PS_NAME			(V4L2_CID_FM_TX_CLASS_BASE + 5)
>  #define V4L2_CID_RDS_TX_RADIO_TEXT		(V4L2_CID_FM_TX_CLASS_BASE + 6)
> +#define V4L2_CID_RDS_TX_MONO_STEREO		(V4L2_CID_FM_TX_CLASS_BASE + 7)
> +#define V4L2_CID_RDS_TX_ARTIFICIAL_HEAD		(V4L2_CID_FM_TX_CLASS_BASE + 8)
> +#define V4L2_CID_RDS_TX_COMPRESSED		(V4L2_CID_FM_TX_CLASS_BASE + 9)
> +#define V4L2_CID_RDS_TX_DYNAMIC_PTY		(V4L2_CID_FM_TX_CLASS_BASE + 10)
> +#define V4L2_CID_RDS_TX_TRAFFIC_ANNOUNCEMENT	(V4L2_CID_FM_TX_CLASS_BASE + 11)
> +#define V4L2_CID_RDS_TX_TRAFFIC_PROGRAM		(V4L2_CID_FM_TX_CLASS_BASE + 12)
> +#define V4L2_CID_RDS_TX_MUSIC_SPEECH		(V4L2_CID_FM_TX_CLASS_BASE + 13)
> +#define V4L2_CID_RDS_TX_ALT_FREQ_ENABLE		(V4L2_CID_FM_TX_CLASS_BASE + 14)
> +#define V4L2_CID_RDS_TX_ALT_FREQ		(V4L2_CID_FM_TX_CLASS_BASE + 15)
>  
>  #define V4L2_CID_AUDIO_LIMITER_ENABLED		(V4L2_CID_FM_TX_CLASS_BASE + 64)
>  #define V4L2_CID_AUDIO_LIMITER_RELEASE_TIME	(V4L2_CID_FM_TX_CLASS_BASE + 65)
> 


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2014-02-10  9:53 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-02-07 12:19 [RFC PATCH 0/7] si4713 enhancements, add miro RDS support Hans Verkuil
2014-02-07 12:19 ` [RFC PATCH 1/7] v4l2-ctrls: add new RDS TX controls Hans Verkuil
2014-02-10  9:52   ` Hans Verkuil
2014-02-07 12:19 ` [RFC PATCH 2/7] DocBook/media: document the " Hans Verkuil
2014-02-07 12:19 ` [RFC PATCH 3/7] si4713: add the missing RDS functionality Hans Verkuil
2014-02-07 12:19 ` [RFC PATCH 4/7] v4l2-ctrls: add RX RDS controls Hans Verkuil
2014-02-07 12:19 ` [RFC PATCH 5/7] DocBook/media: document the new RDS RX controls Hans Verkuil
2014-02-07 12:19 ` [RFC PATCH 6/7] v4l2-ctrls: add support for setting string controls Hans Verkuil
2014-02-07 12:19 ` [RFC PATCH 7/7] radio-miropcm20: add RDS support Hans Verkuil

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox