linux-media.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCHv3 00/13] SDR transmitter API
@ 2015-07-31  2:10 Antti Palosaari
  2015-07-31  2:10 ` [PATCHv3 01/13] v4l2: rename V4L2_TUNER_ADC to V4L2_TUNER_SDR Antti Palosaari
                   ` (12 more replies)
  0 siblings, 13 replies; 24+ messages in thread
From: Antti Palosaari @ 2015-07-31  2:10 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Antti Palosaari

v3:
* some documentation addons

* added type field to v4l2 modulator struct

* hackrf: fix querycap capabilities

* hackrf: remove another v4l2_device struct

* hackrf: fix / moved RX/TX busy check to start streaming

* hackrf: some other minor changes

Those fixes were the ones Hans pointed out, thanks. Some documentation is still TODO.

Passes v4l2-compliance otherwise than new modulator type field.

Output ioctls:
fail: v4l2-test-input-output.cpp(576): non-zero reserved fields
fail: v4l2-test-input-output.cpp(640): invalid modulator 0
test VIDIOC_G/S_MODULATOR: FAIL
fail: v4l2-test-input-output.cpp(729): could get frequency for invalid modulator 0
test VIDIOC_G/S_FREQUENCY: FAIL


v2:
* Allow device open even another device node is active. This means you
could use transmitter device even receiver is active and other way
around, just streaming is blocked to single node.

* Removed V4L2_CID_RF_TUNER_RF_GAIN_AUTO control as it was not used.

* Changed RF gain documentation.


Antti Palosaari (13):
  v4l2: rename V4L2_TUNER_ADC to V4L2_TUNER_SDR
  v4l2: add RF gain control
  DocBook: document tuner RF gain control
  v4l2: add support for SDR transmitter
  DocBook: document SDR transmitter
  v4l: add type field to v4l2_modulator struct
  DocBook: add modulator type field
  hackrf: add control for RF amplifier
  hackrf: switch to single function which configures everything
  hackrf: add support for transmitter
  hackrf: do not set human readable name for formats
  DocBook: fix S_FREQUENCY => G_FREQUENCY
  DocBook: add tuner types SDR and RF for G_TUNER / S_TUNER

 Documentation/DocBook/media/v4l/common.xml         |    2 +-
 Documentation/DocBook/media/v4l/compat.xml         |   20 +
 Documentation/DocBook/media/v4l/controls.xml       |   14 +
 Documentation/DocBook/media/v4l/dev-sdr.xml        |   32 +-
 Documentation/DocBook/media/v4l/io.xml             |   10 +-
 Documentation/DocBook/media/v4l/pixfmt.xml         |    2 +-
 Documentation/DocBook/media/v4l/v4l2.xml           |    9 +
 Documentation/DocBook/media/v4l/vidioc-g-fmt.xml   |    2 +-
 .../DocBook/media/v4l/vidioc-g-modulator.xml       |    8 +-
 Documentation/DocBook/media/v4l/vidioc-g-tuner.xml |   10 +
 .../DocBook/media/v4l/vidioc-querycap.xml          |    6 +
 drivers/media/usb/hackrf/hackrf.c                  | 1062 ++++++++++++++------
 drivers/media/v4l2-core/v4l2-ctrls.c               |    2 +
 drivers/media/v4l2-core/v4l2-dev.c                 |   14 +-
 drivers/media/v4l2-core/v4l2-ioctl.c               |   49 +-
 drivers/media/v4l2-core/videobuf-core.c            |    4 +-
 include/media/v4l2-ioctl.h                         |    8 +
 include/trace/events/v4l2.h                        |    1 +
 include/uapi/linux/v4l2-controls.h                 |    1 +
 include/uapi/linux/videodev2.h                     |   13 +-
 20 files changed, 916 insertions(+), 353 deletions(-)

-- 
http://palosaari.fi/


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

* [PATCHv3 01/13] v4l2: rename V4L2_TUNER_ADC to V4L2_TUNER_SDR
  2015-07-31  2:10 [PATCHv3 00/13] SDR transmitter API Antti Palosaari
@ 2015-07-31  2:10 ` Antti Palosaari
  2015-07-31  2:10 ` [PATCHv3 02/13] v4l2: add RF gain control Antti Palosaari
                   ` (11 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Antti Palosaari @ 2015-07-31  2:10 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Antti Palosaari

SDR receiver has ADC (Analog-to-Digital Converter) and SDR transmitter
has DAC (Digital-to-Analog Converter). Originally I though it could
be good idea to have own type for receiver and transmitter, but now I
feel one common type for SDR is enough. So lets rename it.

Cc: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
 Documentation/DocBook/media/v4l/compat.xml  | 12 ++++++++++++
 Documentation/DocBook/media/v4l/dev-sdr.xml |  6 +++---
 Documentation/DocBook/media/v4l/v4l2.xml    |  7 +++++++
 drivers/media/v4l2-core/v4l2-ioctl.c        |  6 +++---
 include/uapi/linux/videodev2.h              |  5 ++++-
 5 files changed, 29 insertions(+), 7 deletions(-)

diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml
index a0aef85..f56faf5 100644
--- a/Documentation/DocBook/media/v4l/compat.xml
+++ b/Documentation/DocBook/media/v4l/compat.xml
@@ -2591,6 +2591,18 @@ and &v4l2-mbus-framefmt;.
       </orderedlist>
     </section>
 
+    <section>
+      <title>V4L2 in Linux 4.2</title>
+      <orderedlist>
+	<listitem>
+	  <para>Renamed <constant>V4L2_TUNER_ADC</constant> to
+<constant>V4L2_TUNER_SDR</constant>. The use of
+<constant>V4L2_TUNER_ADC</constant> is deprecated now.
+	  </para>
+	</listitem>
+      </orderedlist>
+    </section>
+
     <section id="other">
       <title>Relation of V4L2 to other Linux multimedia APIs</title>
 
diff --git a/Documentation/DocBook/media/v4l/dev-sdr.xml b/Documentation/DocBook/media/v4l/dev-sdr.xml
index f890356..3344921 100644
--- a/Documentation/DocBook/media/v4l/dev-sdr.xml
+++ b/Documentation/DocBook/media/v4l/dev-sdr.xml
@@ -44,10 +44,10 @@ frequency.
     </para>
 
     <para>
-The <constant>V4L2_TUNER_ADC</constant> tuner type is used for ADC tuners, and
+The <constant>V4L2_TUNER_SDR</constant> tuner type is used for SDR tuners, and
 the <constant>V4L2_TUNER_RF</constant> tuner type is used for RF tuners. The
-tuner index of the RF tuner (if any) must always follow the ADC tuner index.
-Normally the ADC tuner is #0 and the RF tuner is #1.
+tuner index of the RF tuner (if any) must always follow the SDR tuner index.
+Normally the SDR tuner is #0 and the RF tuner is #1.
     </para>
 
     <para>
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
index e98caa1..c9eedc1 100644
--- a/Documentation/DocBook/media/v4l/v4l2.xml
+++ b/Documentation/DocBook/media/v4l/v4l2.xml
@@ -151,6 +151,13 @@ Rubli, Andy Walls, Muralidharan Karicheri, Mauro Carvalho Chehab,
 structs, ioctls) must be noted in more detail in the history chapter
 (compat.xml), along with the possible impact on existing drivers and
 applications. -->
+      <revision>
+	<revnumber>4.2</revnumber>
+	<date>2015-05-26</date>
+	<authorinitials>ap</authorinitials>
+	<revremark>Renamed V4L2_TUNER_ADC to V4L2_TUNER_SDR.
+	</revremark>
+      </revision>
 
       <revision>
 	<revnumber>3.21</revnumber>
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 85de455..ef42474 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1637,7 +1637,7 @@ static int v4l_g_frequency(const struct v4l2_ioctl_ops *ops,
 	struct v4l2_frequency *p = arg;
 
 	if (vfd->vfl_type == VFL_TYPE_SDR)
-		p->type = V4L2_TUNER_ADC;
+		p->type = V4L2_TUNER_SDR;
 	else
 		p->type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
 				V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
@@ -1652,7 +1652,7 @@ static int v4l_s_frequency(const struct v4l2_ioctl_ops *ops,
 	enum v4l2_tuner_type type;
 
 	if (vfd->vfl_type == VFL_TYPE_SDR) {
-		if (p->type != V4L2_TUNER_ADC && p->type != V4L2_TUNER_RF)
+		if (p->type != V4L2_TUNER_SDR && p->type != V4L2_TUNER_RF)
 			return -EINVAL;
 	} else {
 		type = (vfd->vfl_type == VFL_TYPE_RADIO) ?
@@ -2277,7 +2277,7 @@ static int v4l_enum_freq_bands(const struct v4l2_ioctl_ops *ops,
 	int err;
 
 	if (vfd->vfl_type == VFL_TYPE_SDR) {
-		if (p->type != V4L2_TUNER_ADC && p->type != V4L2_TUNER_RF)
+		if (p->type != V4L2_TUNER_SDR && p->type != V4L2_TUNER_RF)
 			return -EINVAL;
 		type = p->type;
 	} else {
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 3228fbe..467816cb 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -165,10 +165,13 @@ enum v4l2_tuner_type {
 	V4L2_TUNER_RADIO	     = 1,
 	V4L2_TUNER_ANALOG_TV	     = 2,
 	V4L2_TUNER_DIGITAL_TV	     = 3,
-	V4L2_TUNER_ADC               = 4,
+	V4L2_TUNER_SDR               = 4,
 	V4L2_TUNER_RF                = 5,
 };
 
+/* Deprecated, do not use */
+#define V4L2_TUNER_ADC  V4L2_TUNER_SDR
+
 enum v4l2_memory {
 	V4L2_MEMORY_MMAP             = 1,
 	V4L2_MEMORY_USERPTR          = 2,
-- 
http://palosaari.fi/


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

* [PATCHv3 02/13] v4l2: add RF gain control
  2015-07-31  2:10 [PATCHv3 00/13] SDR transmitter API Antti Palosaari
  2015-07-31  2:10 ` [PATCHv3 01/13] v4l2: rename V4L2_TUNER_ADC to V4L2_TUNER_SDR Antti Palosaari
@ 2015-07-31  2:10 ` Antti Palosaari
  2015-08-10  8:56   ` Hans Verkuil
  2015-07-31  2:10 ` [PATCHv3 03/13] DocBook: document tuner " Antti Palosaari
                   ` (10 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Antti Palosaari @ 2015-07-31  2:10 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Antti Palosaari

Add new RF tuner gain control named RF Gain. That is aimed for first
amplifier chip right after antenna connector.
There is existing LNA Gain control, which is quite same, but it is
aimed for cases amplifier is integrated to tuner chip. Some designs
have both, as almost all recent tuner silicons has integrated LNA/RF
amplifier in any case.

Cc: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
 drivers/media/v4l2-core/v4l2-ctrls.c | 2 ++
 include/uapi/linux/v4l2-controls.h   | 1 +
 2 files changed, 3 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index b6b7dcc..d18462c 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -888,6 +888,7 @@ const char *v4l2_ctrl_get_name(u32 id)
 	case V4L2_CID_TUNE_DEEMPHASIS:		return "De-Emphasis";
 	case V4L2_CID_RDS_RECEPTION:		return "RDS Reception";
 	case V4L2_CID_RF_TUNER_CLASS:		return "RF Tuner Controls";
+	case V4L2_CID_RF_TUNER_RF_GAIN:		return "RF Gain";
 	case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO:	return "LNA Gain, Auto";
 	case V4L2_CID_RF_TUNER_LNA_GAIN:	return "LNA Gain";
 	case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO:	return "Mixer Gain, Auto";
@@ -1161,6 +1162,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
 	case V4L2_CID_PILOT_TONE_FREQUENCY:
 	case V4L2_CID_TUNE_POWER_LEVEL:
 	case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
+	case V4L2_CID_RF_TUNER_RF_GAIN:
 	case V4L2_CID_RF_TUNER_LNA_GAIN:
 	case V4L2_CID_RF_TUNER_MIXER_GAIN:
 	case V4L2_CID_RF_TUNER_IF_GAIN:
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index d448c53..1bdce50 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -936,6 +936,7 @@ enum v4l2_deemphasis {
 
 #define V4L2_CID_RF_TUNER_BANDWIDTH_AUTO	(V4L2_CID_RF_TUNER_CLASS_BASE + 11)
 #define V4L2_CID_RF_TUNER_BANDWIDTH		(V4L2_CID_RF_TUNER_CLASS_BASE + 12)
+#define V4L2_CID_RF_TUNER_RF_GAIN		(V4L2_CID_RF_TUNER_CLASS_BASE + 32)
 #define V4L2_CID_RF_TUNER_LNA_GAIN_AUTO		(V4L2_CID_RF_TUNER_CLASS_BASE + 41)
 #define V4L2_CID_RF_TUNER_LNA_GAIN		(V4L2_CID_RF_TUNER_CLASS_BASE + 42)
 #define V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO	(V4L2_CID_RF_TUNER_CLASS_BASE + 51)
-- 
http://palosaari.fi/


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

* [PATCHv3 03/13] DocBook: document tuner RF gain control
  2015-07-31  2:10 [PATCHv3 00/13] SDR transmitter API Antti Palosaari
  2015-07-31  2:10 ` [PATCHv3 01/13] v4l2: rename V4L2_TUNER_ADC to V4L2_TUNER_SDR Antti Palosaari
  2015-07-31  2:10 ` [PATCHv3 02/13] v4l2: add RF gain control Antti Palosaari
@ 2015-07-31  2:10 ` Antti Palosaari
  2015-08-10  8:57   ` Hans Verkuil
  2015-07-31  2:10 ` [PATCHv3 04/13] v4l2: add support for SDR transmitter Antti Palosaari
                   ` (9 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Antti Palosaari @ 2015-07-31  2:10 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Antti Palosaari

Add brief description for tuner RF gain control.

Cc: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
 Documentation/DocBook/media/v4l/compat.xml   |  4 ++++
 Documentation/DocBook/media/v4l/controls.xml | 14 ++++++++++++++
 Documentation/DocBook/media/v4l/v4l2.xml     |  1 +
 3 files changed, 19 insertions(+)

diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml
index f56faf5..eb091c7 100644
--- a/Documentation/DocBook/media/v4l/compat.xml
+++ b/Documentation/DocBook/media/v4l/compat.xml
@@ -2600,6 +2600,10 @@ and &v4l2-mbus-framefmt;.
 <constant>V4L2_TUNER_ADC</constant> is deprecated now.
 	  </para>
 	</listitem>
+	<listitem>
+	  <para>Added <constant>V4L2_CID_RF_TUNER_RF_GAIN</constant>
+RF Tuner control.</para>
+	</listitem>
       </orderedlist>
     </section>
 
diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
index 6e1667b..7cae933 100644
--- a/Documentation/DocBook/media/v4l/controls.xml
+++ b/Documentation/DocBook/media/v4l/controls.xml
@@ -5418,6 +5418,18 @@ set. Unit is in Hz. The range and step are driver-specific.</entry>
               <entry spanname="descr">Enables/disables IF automatic gain control (AGC)</entry>
             </row>
             <row>
+              <entry spanname="id"><constant>V4L2_CID_RF_TUNER_RF_GAIN</constant>&nbsp;</entry>
+              <entry>integer</entry>
+            </row>
+            <row>
+              <entry spanname="descr">The RF amplifier is the very first
+amplifier on the receiver signal path, just right after the antenna input.
+The difference between the LNA gain and the RF gain in this document is that
+the LNA gain is integrated in the tuner chip while the RF gain is a separate
+chip. There may be both RF and LNA gain controls in the same device.
+The range and step are driver-specific.</entry>
+            </row>
+            <row>
               <entry spanname="id"><constant>V4L2_CID_RF_TUNER_LNA_GAIN</constant>&nbsp;</entry>
               <entry>integer</entry>
             </row>
@@ -5425,6 +5437,8 @@ set. Unit is in Hz. The range and step are driver-specific.</entry>
               <entry spanname="descr">LNA (low noise amplifier) gain is first
 gain stage on the RF tuner signal path. It is located very close to tuner
 antenna input. Used when <constant>V4L2_CID_RF_TUNER_LNA_GAIN_AUTO</constant> is not set.
+See <constant>V4L2_CID_RF_TUNER_RF_GAIN</constant> to understand how RF gain
+and LNA gain differs from the each others.
 The range and step are driver-specific.</entry>
             </row>
             <row>
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
index c9eedc1..ab9fca4 100644
--- a/Documentation/DocBook/media/v4l/v4l2.xml
+++ b/Documentation/DocBook/media/v4l/v4l2.xml
@@ -156,6 +156,7 @@ applications. -->
 	<date>2015-05-26</date>
 	<authorinitials>ap</authorinitials>
 	<revremark>Renamed V4L2_TUNER_ADC to V4L2_TUNER_SDR.
+Added V4L2_CID_RF_TUNER_RF_GAIN control.
 	</revremark>
       </revision>
 
-- 
http://palosaari.fi/


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

* [PATCHv3 04/13] v4l2: add support for SDR transmitter
  2015-07-31  2:10 [PATCHv3 00/13] SDR transmitter API Antti Palosaari
                   ` (2 preceding siblings ...)
  2015-07-31  2:10 ` [PATCHv3 03/13] DocBook: document tuner " Antti Palosaari
@ 2015-07-31  2:10 ` Antti Palosaari
  2015-07-31  2:10 ` [PATCHv3 05/13] DocBook: document " Antti Palosaari
                   ` (8 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Antti Palosaari @ 2015-07-31  2:10 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Antti Palosaari

New IOCTL ops:
vidioc_enum_fmt_sdr_out
vidioc_g_fmt_sdr_out
vidioc_s_fmt_sdr_out
vidioc_try_fmt_sdr_out

New vb2 buffertype:
V4L2_BUF_TYPE_SDR_OUTPUT

New v4l2 capability:
V4L2_CAP_SDR_OUTPUT

Signed-off-by: Antti Palosaari <crope@iki.fi>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-dev.c      | 14 ++++++++++++--
 drivers/media/v4l2-core/v4l2-ioctl.c    | 25 +++++++++++++++++++++++++
 drivers/media/v4l2-core/videobuf-core.c |  4 +++-
 include/media/v4l2-ioctl.h              |  8 ++++++++
 include/trace/events/v4l2.h             |  1 +
 include/uapi/linux/videodev2.h          |  5 ++++-
 6 files changed, 53 insertions(+), 4 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index 71a1b93..6b1eaed 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -637,8 +637,8 @@ static void determine_valid_ioctls(struct video_device *vdev)
 			       ops->vidioc_try_fmt_sliced_vbi_out)))
 			set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls);
 		SET_VALID_IOCTL(ops, VIDIOC_G_SLICED_VBI_CAP, vidioc_g_sliced_vbi_cap);
-	} else if (is_sdr) {
-		/* SDR specific ioctls */
+	} else if (is_sdr && is_rx) {
+		/* SDR receiver specific ioctls */
 		if (ops->vidioc_enum_fmt_sdr_cap)
 			set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls);
 		if (ops->vidioc_g_fmt_sdr_cap)
@@ -647,6 +647,16 @@ static void determine_valid_ioctls(struct video_device *vdev)
 			set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls);
 		if (ops->vidioc_try_fmt_sdr_cap)
 			set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls);
+	} else if (is_sdr && is_tx) {
+		/* SDR transmitter specific ioctls */
+		if (ops->vidioc_enum_fmt_sdr_out)
+			set_bit(_IOC_NR(VIDIOC_ENUM_FMT), valid_ioctls);
+		if (ops->vidioc_g_fmt_sdr_out)
+			set_bit(_IOC_NR(VIDIOC_G_FMT), valid_ioctls);
+		if (ops->vidioc_s_fmt_sdr_out)
+			set_bit(_IOC_NR(VIDIOC_S_FMT), valid_ioctls);
+		if (ops->vidioc_try_fmt_sdr_out)
+			set_bit(_IOC_NR(VIDIOC_TRY_FMT), valid_ioctls);
 	}
 
 	if (is_vid || is_vbi || is_sdr) {
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index ef42474..21e9598 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -154,6 +154,7 @@ const char *v4l2_type_names[] = {
 	[V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE] = "vid-cap-mplane",
 	[V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE] = "vid-out-mplane",
 	[V4L2_BUF_TYPE_SDR_CAPTURE]        = "sdr-cap",
+	[V4L2_BUF_TYPE_SDR_OUTPUT]         = "sdr-out",
 };
 EXPORT_SYMBOL(v4l2_type_names);
 
@@ -327,6 +328,7 @@ static void v4l_print_format(const void *arg, bool write_only)
 				sliced->service_lines[1][i]);
 		break;
 	case V4L2_BUF_TYPE_SDR_CAPTURE:
+	case V4L2_BUF_TYPE_SDR_OUTPUT:
 		sdr = &p->fmt.sdr;
 		pr_cont(", pixelformat=%c%c%c%c\n",
 			(sdr->pixelformat >>  0) & 0xff,
@@ -975,6 +977,10 @@ static int check_fmt(struct file *file, enum v4l2_buf_type type)
 		if (is_sdr && is_rx && ops->vidioc_g_fmt_sdr_cap)
 			return 0;
 		break;
+	case V4L2_BUF_TYPE_SDR_OUTPUT:
+		if (is_sdr && is_tx && ops->vidioc_g_fmt_sdr_out)
+			return 0;
+		break;
 	default:
 		break;
 	}
@@ -1324,6 +1330,11 @@ static int v4l_enum_fmt(const struct v4l2_ioctl_ops *ops,
 			break;
 		ret = ops->vidioc_enum_fmt_sdr_cap(file, fh, arg);
 		break;
+	case V4L2_BUF_TYPE_SDR_OUTPUT:
+		if (unlikely(!is_tx || !is_sdr || !ops->vidioc_enum_fmt_sdr_out))
+			break;
+		ret = ops->vidioc_enum_fmt_sdr_out(file, fh, arg);
+		break;
 	}
 	if (ret == 0)
 		v4l_fill_fmtdesc(p);
@@ -1418,6 +1429,10 @@ static int v4l_g_fmt(const struct v4l2_ioctl_ops *ops,
 		if (unlikely(!is_rx || !is_sdr || !ops->vidioc_g_fmt_sdr_cap))
 			break;
 		return ops->vidioc_g_fmt_sdr_cap(file, fh, arg);
+	case V4L2_BUF_TYPE_SDR_OUTPUT:
+		if (unlikely(!is_tx || !is_sdr || !ops->vidioc_g_fmt_sdr_out))
+			break;
+		return ops->vidioc_g_fmt_sdr_out(file, fh, arg);
 	}
 	return -EINVAL;
 }
@@ -1497,6 +1512,11 @@ static int v4l_s_fmt(const struct v4l2_ioctl_ops *ops,
 			break;
 		CLEAR_AFTER_FIELD(p, fmt.sdr);
 		return ops->vidioc_s_fmt_sdr_cap(file, fh, arg);
+	case V4L2_BUF_TYPE_SDR_OUTPUT:
+		if (unlikely(!is_tx || !is_sdr || !ops->vidioc_s_fmt_sdr_out))
+			break;
+		CLEAR_AFTER_FIELD(p, fmt.sdr);
+		return ops->vidioc_s_fmt_sdr_out(file, fh, arg);
 	}
 	return -EINVAL;
 }
@@ -1576,6 +1596,11 @@ static int v4l_try_fmt(const struct v4l2_ioctl_ops *ops,
 			break;
 		CLEAR_AFTER_FIELD(p, fmt.sdr);
 		return ops->vidioc_try_fmt_sdr_cap(file, fh, arg);
+	case V4L2_BUF_TYPE_SDR_OUTPUT:
+		if (unlikely(!is_tx || !is_sdr || !ops->vidioc_try_fmt_sdr_out))
+			break;
+		CLEAR_AFTER_FIELD(p, fmt.sdr);
+		return ops->vidioc_try_fmt_sdr_out(file, fh, arg);
 	}
 	return -EINVAL;
 }
diff --git a/drivers/media/v4l2-core/videobuf-core.c b/drivers/media/v4l2-core/videobuf-core.c
index 926836d..6c02989 100644
--- a/drivers/media/v4l2-core/videobuf-core.c
+++ b/drivers/media/v4l2-core/videobuf-core.c
@@ -576,7 +576,8 @@ int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b)
 		}
 		if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT
 		    || q->type == V4L2_BUF_TYPE_VBI_OUTPUT
-		    || q->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {
+		    || q->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT
+		    || q->type == V4L2_BUF_TYPE_SDR_OUTPUT) {
 			buf->size = b->bytesused;
 			buf->field = b->field;
 			buf->ts = b->timestamp;
@@ -1154,6 +1155,7 @@ unsigned int videobuf_poll_stream(struct file *file,
 			case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 			case V4L2_BUF_TYPE_VBI_OUTPUT:
 			case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+			case V4L2_BUF_TYPE_SDR_OUTPUT:
 				rc = POLLOUT | POLLWRNORM;
 				break;
 			default:
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index 8fbbd76..017ffb2 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -36,6 +36,8 @@ struct v4l2_ioctl_ops {
 					      struct v4l2_fmtdesc *f);
 	int (*vidioc_enum_fmt_sdr_cap)     (struct file *file, void *fh,
 					    struct v4l2_fmtdesc *f);
+	int (*vidioc_enum_fmt_sdr_out)     (struct file *file, void *fh,
+					    struct v4l2_fmtdesc *f);
 
 	/* VIDIOC_G_FMT handlers */
 	int (*vidioc_g_fmt_vid_cap)    (struct file *file, void *fh,
@@ -60,6 +62,8 @@ struct v4l2_ioctl_ops {
 					   struct v4l2_format *f);
 	int (*vidioc_g_fmt_sdr_cap)    (struct file *file, void *fh,
 					struct v4l2_format *f);
+	int (*vidioc_g_fmt_sdr_out)    (struct file *file, void *fh,
+					struct v4l2_format *f);
 
 	/* VIDIOC_S_FMT handlers */
 	int (*vidioc_s_fmt_vid_cap)    (struct file *file, void *fh,
@@ -84,6 +88,8 @@ struct v4l2_ioctl_ops {
 					   struct v4l2_format *f);
 	int (*vidioc_s_fmt_sdr_cap)    (struct file *file, void *fh,
 					struct v4l2_format *f);
+	int (*vidioc_s_fmt_sdr_out)    (struct file *file, void *fh,
+					struct v4l2_format *f);
 
 	/* VIDIOC_TRY_FMT handlers */
 	int (*vidioc_try_fmt_vid_cap)    (struct file *file, void *fh,
@@ -108,6 +114,8 @@ struct v4l2_ioctl_ops {
 					     struct v4l2_format *f);
 	int (*vidioc_try_fmt_sdr_cap)    (struct file *file, void *fh,
 					  struct v4l2_format *f);
+	int (*vidioc_try_fmt_sdr_out)    (struct file *file, void *fh,
+					  struct v4l2_format *f);
 
 	/* Buffer handlers */
 	int (*vidioc_reqbufs) (struct file *file, void *fh, struct v4l2_requestbuffers *b);
diff --git a/include/trace/events/v4l2.h b/include/trace/events/v4l2.h
index 4c88a32..38ec1d4 100644
--- a/include/trace/events/v4l2.h
+++ b/include/trace/events/v4l2.h
@@ -27,6 +27,7 @@
 	EM( V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, "VIDEO_CAPTURE_MPLANE" ) \
 	EM( V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,  "VIDEO_OUTPUT_MPLANE" )	\
 	EM( V4L2_BUF_TYPE_SDR_CAPTURE,          "SDR_CAPTURE" )		\
+	EM( V4L2_BUF_TYPE_SDR_OUTPUT,           "SDR_OUTPUT" )		\
 	EMe(V4L2_BUF_TYPE_PRIVATE,		"PRIVATE" )
 
 SHOW_TYPE
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 467816cb..70f06c9 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -145,6 +145,7 @@ enum v4l2_buf_type {
 	V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE = 9,
 	V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE  = 10,
 	V4L2_BUF_TYPE_SDR_CAPTURE          = 11,
+	V4L2_BUF_TYPE_SDR_OUTPUT           = 12,
 	/* Deprecated, do not use */
 	V4L2_BUF_TYPE_PRIVATE              = 0x80,
 };
@@ -159,7 +160,8 @@ enum v4l2_buf_type {
 	 || (type) == V4L2_BUF_TYPE_VIDEO_OVERLAY		\
 	 || (type) == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY	\
 	 || (type) == V4L2_BUF_TYPE_VBI_OUTPUT			\
-	 || (type) == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
+	 || (type) == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT		\
+	 || (type) == V4L2_BUF_TYPE_SDR_OUTPUT)
 
 enum v4l2_tuner_type {
 	V4L2_TUNER_RADIO	     = 1,
@@ -426,6 +428,7 @@ struct v4l2_capability {
 
 #define V4L2_CAP_SDR_CAPTURE		0x00100000  /* Is a SDR capture device */
 #define V4L2_CAP_EXT_PIX_FORMAT		0x00200000  /* Supports the extended pixel format */
+#define V4L2_CAP_SDR_OUTPUT		0x00400000  /* Is a SDR output device */
 
 #define V4L2_CAP_READWRITE              0x01000000  /* read/write systemcalls */
 #define V4L2_CAP_ASYNCIO                0x02000000  /* async I/O */
-- 
http://palosaari.fi/


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

* [PATCHv3 05/13] DocBook: document SDR transmitter
  2015-07-31  2:10 [PATCHv3 00/13] SDR transmitter API Antti Palosaari
                   ` (3 preceding siblings ...)
  2015-07-31  2:10 ` [PATCHv3 04/13] v4l2: add support for SDR transmitter Antti Palosaari
@ 2015-07-31  2:10 ` Antti Palosaari
  2015-07-31  2:10 ` [PATCHv3 06/13] v4l: add type field to v4l2_modulator struct Antti Palosaari
                   ` (7 subsequent siblings)
  12 siblings, 0 replies; 24+ messages in thread
From: Antti Palosaari @ 2015-07-31  2:10 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Antti Palosaari

Add documentation for V4L SDR transmitter (output) devices.

Signed-off-by: Antti Palosaari <crope@iki.fi>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 Documentation/DocBook/media/v4l/compat.xml         |  4 +++
 Documentation/DocBook/media/v4l/dev-sdr.xml        | 30 +++++++++++++++-------
 Documentation/DocBook/media/v4l/io.xml             | 10 ++++++--
 Documentation/DocBook/media/v4l/pixfmt.xml         |  2 +-
 Documentation/DocBook/media/v4l/v4l2.xml           |  1 +
 Documentation/DocBook/media/v4l/vidioc-g-fmt.xml   |  2 +-
 .../DocBook/media/v4l/vidioc-querycap.xml          |  6 +++++
 7 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml
index eb091c7..f534fc5 100644
--- a/Documentation/DocBook/media/v4l/compat.xml
+++ b/Documentation/DocBook/media/v4l/compat.xml
@@ -2604,6 +2604,10 @@ and &v4l2-mbus-framefmt;.
 	  <para>Added <constant>V4L2_CID_RF_TUNER_RF_GAIN</constant>
 RF Tuner control.</para>
 	</listitem>
+	<listitem>
+	  <para>Added transmitter support for Software Defined Radio (SDR)
+Interface.</para>
+	</listitem>
       </orderedlist>
     </section>
 
diff --git a/Documentation/DocBook/media/v4l/dev-sdr.xml b/Documentation/DocBook/media/v4l/dev-sdr.xml
index 3344921..a659771 100644
--- a/Documentation/DocBook/media/v4l/dev-sdr.xml
+++ b/Documentation/DocBook/media/v4l/dev-sdr.xml
@@ -28,6 +28,16 @@ Devices supporting the SDR receiver interface set the
 <structfield>capabilities</structfield> field of &v4l2-capability;
 returned by the &VIDIOC-QUERYCAP; ioctl. That flag means the device has an
 Analog to Digital Converter (ADC), which is a mandatory element for the SDR receiver.
+    </para>
+    <para>
+Devices supporting the SDR transmitter interface set the
+<constant>V4L2_CAP_SDR_OUTPUT</constant> and
+<constant>V4L2_CAP_MODULATOR</constant> flag in the
+<structfield>capabilities</structfield> field of &v4l2-capability;
+returned by the &VIDIOC-QUERYCAP; ioctl. That flag means the device has an
+Digital to Analog Converter (DAC), which is a mandatory element for the SDR transmitter.
+    </para>
+    <para>
 At least one of the read/write, streaming or asynchronous I/O methods must
 be supported.
     </para>
@@ -39,14 +49,15 @@ be supported.
     <para>
 SDR devices can support <link linkend="control">controls</link>, and must
 support the <link linkend="tuner">tuner</link> ioctls. Tuner ioctls are used
-for setting the ADC sampling rate (sampling frequency) and the possible RF tuner
-frequency.
+for setting the ADC/DAC sampling rate (sampling frequency) and the possible
+radio frequency (RF).
     </para>
 
     <para>
-The <constant>V4L2_TUNER_SDR</constant> tuner type is used for SDR tuners, and
-the <constant>V4L2_TUNER_RF</constant> tuner type is used for RF tuners. The
-tuner index of the RF tuner (if any) must always follow the SDR tuner index.
+The <constant>V4L2_TUNER_SDR</constant> tuner type is used for setting SDR
+device ADC/DAC frequency, and the <constant>V4L2_TUNER_RF</constant>
+tuner type is used for setting radio frequency.
+The tuner index of the RF tuner (if any) must always follow the SDR tuner index.
 Normally the SDR tuner is #0 and the RF tuner is #1.
     </para>
 
@@ -59,9 +70,9 @@ The &VIDIOC-S-HW-FREQ-SEEK; ioctl is not supported.
     <title>Data Format Negotiation</title>
 
     <para>
-The SDR capture device uses the <link linkend="format">format</link> ioctls to
-select the capture format. Both the sampling resolution and the data streaming
-format are bound to that selectable format. In addition to the basic
+The SDR device uses the <link linkend="format">format</link> ioctls to
+select the capture and output format. Both the sampling resolution and the data
+streaming format are bound to that selectable format. In addition to the basic
 <link linkend="format">format</link> ioctls, the &VIDIOC-ENUM-FMT; ioctl
 must be supported as well.
     </para>
@@ -69,7 +80,8 @@ must be supported as well.
     <para>
 To use the <link linkend="format">format</link> ioctls applications set the
 <structfield>type</structfield> field of a &v4l2-format; to
-<constant>V4L2_BUF_TYPE_SDR_CAPTURE</constant> and use the &v4l2-sdr-format;
+<constant>V4L2_BUF_TYPE_SDR_CAPTURE</constant> or
+<constant>V4L2_BUF_TYPE_SDR_OUTPUT</constant> and use the &v4l2-sdr-format;
 <structfield>sdr</structfield> member of the <structfield>fmt</structfield>
 union as needed per the desired operation.
 Currently there is two fields, <structfield>pixelformat</structfield> and
diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
index 7bbc2a4..da65403 100644
--- a/Documentation/DocBook/media/v4l/io.xml
+++ b/Documentation/DocBook/media/v4l/io.xml
@@ -1006,8 +1006,14 @@ must set this to 0.</entry>
 	  <row>
 	    <entry><constant>V4L2_BUF_TYPE_SDR_CAPTURE</constant></entry>
 	    <entry>11</entry>
-	    <entry>Buffer for Software Defined Radio (SDR), see <xref
-		linkend="sdr" />.</entry>
+	    <entry>Buffer for Software Defined Radio (SDR) capture stream, see
+		<xref linkend="sdr" />.</entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_BUF_TYPE_SDR_OUTPUT</constant></entry>
+	    <entry>12</entry>
+	    <entry>Buffer for Software Defined Radio (SDR) output stream, see
+		<xref linkend="sdr" />.</entry>
 	  </row>
 	</tbody>
       </tgroup>
diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml
index 965ea91..02aac95 100644
--- a/Documentation/DocBook/media/v4l/pixfmt.xml
+++ b/Documentation/DocBook/media/v4l/pixfmt.xml
@@ -1623,7 +1623,7 @@ extended control <constant>V4L2_CID_MPEG_STREAM_TYPE</constant>, see
   <section id="sdr-formats">
     <title>SDR Formats</title>
 
-    <para>These formats are used for <link linkend="sdr">SDR Capture</link>
+    <para>These formats are used for <link linkend="sdr">SDR</link>
 interface only.</para>
 
     &sub-sdr-cu08;
diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
index ab9fca4..ed870fb 100644
--- a/Documentation/DocBook/media/v4l/v4l2.xml
+++ b/Documentation/DocBook/media/v4l/v4l2.xml
@@ -157,6 +157,7 @@ applications. -->
 	<authorinitials>ap</authorinitials>
 	<revremark>Renamed V4L2_TUNER_ADC to V4L2_TUNER_SDR.
 Added V4L2_CID_RF_TUNER_RF_GAIN control.
+Added transmitter support for Software Defined Radio (SDR) Interface.
 	</revremark>
       </revision>
 
diff --git a/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml b/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml
index 4fe19a7a..ffcb448 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-fmt.xml
@@ -175,7 +175,7 @@ capture and output devices.</entry>
 	    <entry>&v4l2-sdr-format;</entry>
 	    <entry><structfield>sdr</structfield></entry>
 	    <entry>Definition of a data format, see
-<xref linkend="pixfmt" />, used by SDR capture devices.</entry>
+<xref linkend="pixfmt" />, used by SDR capture and output devices.</entry>
 	  </row>
 	  <row>
 	    <entry></entry>
diff --git a/Documentation/DocBook/media/v4l/vidioc-querycap.xml b/Documentation/DocBook/media/v4l/vidioc-querycap.xml
index 20fda75..cd82148 100644
--- a/Documentation/DocBook/media/v4l/vidioc-querycap.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-querycap.xml
@@ -308,6 +308,12 @@ modulator programming see
 fields.</entry>
 	  </row>
 	  <row>
+	    <entry><constant>V4L2_CAP_SDR_OUTPUT</constant></entry>
+	    <entry>0x00400000</entry>
+	    <entry>The device supports the
+<link linkend="sdr">SDR Output</link> interface.</entry>
+	  </row>
+	  <row>
 	    <entry><constant>V4L2_CAP_READWRITE</constant></entry>
 	    <entry>0x01000000</entry>
 	    <entry>The device supports the <link
-- 
http://palosaari.fi/


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

* [PATCHv3 06/13] v4l: add type field to v4l2_modulator struct
  2015-07-31  2:10 [PATCHv3 00/13] SDR transmitter API Antti Palosaari
                   ` (4 preceding siblings ...)
  2015-07-31  2:10 ` [PATCHv3 05/13] DocBook: document " Antti Palosaari
@ 2015-07-31  2:10 ` Antti Palosaari
  2015-08-10  9:01   ` Hans Verkuil
  2015-07-31  2:10 ` [PATCHv3 07/13] DocBook: add modulator type field Antti Palosaari
                   ` (6 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Antti Palosaari @ 2015-07-31  2:10 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Antti Palosaari

Add type field to that struct like it counterpart v4l2_tuner
already has. We need type field to distinguish different tuner
types from each others for transmitter too.

Cc: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
 drivers/media/v4l2-core/v4l2-ioctl.c | 18 +++++++++++++++++-
 include/uapi/linux/videodev2.h       |  3 ++-
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 21e9598..85f80cb 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1646,15 +1646,31 @@ static int v4l_s_tuner(const struct v4l2_ioctl_ops *ops,
 static int v4l_g_modulator(const struct v4l2_ioctl_ops *ops,
 				struct file *file, void *fh, void *arg)
 {
+	struct video_device *vfd = video_devdata(file);
 	struct v4l2_modulator *p = arg;
 	int err;
 
+	if (vfd->vfl_type == VFL_TYPE_RADIO)
+		p->type = V4L2_TUNER_RADIO;
+
 	err = ops->vidioc_g_modulator(file, fh, p);
 	if (!err)
 		p->capability |= V4L2_TUNER_CAP_FREQ_BANDS;
 	return err;
 }
 
+static int v4l_s_modulator(const struct v4l2_ioctl_ops *ops,
+				struct file *file, void *fh, void *arg)
+{
+	struct video_device *vfd = video_devdata(file);
+	struct v4l2_modulator *p = arg;
+
+	if (vfd->vfl_type == VFL_TYPE_RADIO)
+		p->type = V4L2_TUNER_RADIO;
+
+	return ops->vidioc_s_modulator(file, fh, p);
+}
+
 static int v4l_g_frequency(const struct v4l2_ioctl_ops *ops,
 				struct file *file, void *fh, void *arg)
 {
@@ -2441,7 +2457,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {
 	IOCTL_INFO_STD(VIDIOC_G_AUDOUT, vidioc_g_audout, v4l_print_audioout, 0),
 	IOCTL_INFO_STD(VIDIOC_S_AUDOUT, vidioc_s_audout, v4l_print_audioout, INFO_FL_PRIO),
 	IOCTL_INFO_FNC(VIDIOC_G_MODULATOR, v4l_g_modulator, v4l_print_modulator, INFO_FL_CLEAR(v4l2_modulator, index)),
-	IOCTL_INFO_STD(VIDIOC_S_MODULATOR, vidioc_s_modulator, v4l_print_modulator, INFO_FL_PRIO),
+	IOCTL_INFO_FNC(VIDIOC_S_MODULATOR, v4l_s_modulator, v4l_print_modulator, INFO_FL_PRIO),
 	IOCTL_INFO_FNC(VIDIOC_G_FREQUENCY, v4l_g_frequency, v4l_print_frequency, INFO_FL_CLEAR(v4l2_frequency, tuner)),
 	IOCTL_INFO_FNC(VIDIOC_S_FREQUENCY, v4l_s_frequency, v4l_print_frequency, INFO_FL_PRIO),
 	IOCTL_INFO_FNC(VIDIOC_CROPCAP, v4l_cropcap, v4l_print_cropcap, INFO_FL_CLEAR(v4l2_cropcap, type)),
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 70f06c9..3a8eb8e 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -1584,7 +1584,8 @@ struct v4l2_modulator {
 	__u32			rangelow;
 	__u32			rangehigh;
 	__u32			txsubchans;
-	__u32			reserved[4];
+	__u32			type;	/* enum v4l2_tuner_type */
+	__u32			reserved[3];
 };
 
 /*  Flags for the 'capability' field */
-- 
http://palosaari.fi/


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

* [PATCHv3 07/13] DocBook: add modulator type field
  2015-07-31  2:10 [PATCHv3 00/13] SDR transmitter API Antti Palosaari
                   ` (5 preceding siblings ...)
  2015-07-31  2:10 ` [PATCHv3 06/13] v4l: add type field to v4l2_modulator struct Antti Palosaari
@ 2015-07-31  2:10 ` Antti Palosaari
  2015-08-10  9:02   ` Hans Verkuil
  2015-07-31  2:10 ` [PATCHv3 08/13] hackrf: add control for RF amplifier Antti Palosaari
                   ` (5 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Antti Palosaari @ 2015-07-31  2:10 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Antti Palosaari

Add new modulator type field to documentation.

Cc: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
 Documentation/DocBook/media/v4l/vidioc-g-modulator.xml | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml b/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml
index 7068b59..fe4230c 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml
@@ -140,7 +140,13 @@ indicator, for example a stereo pilot tone.</entry>
 	  </row>
 	  <row>
 	    <entry>__u32</entry>
-	    <entry><structfield>reserved</structfield>[4]</entry>
+	    <entry><structfield>type</structfield></entry>
+	    <entry spanname="hspan">Type of the tuner, see <xref
+		linkend="v4l2-tuner-type" />.</entry>
+	  </row>
+	  <row>
+	    <entry>__u32</entry>
+	    <entry><structfield>reserved</structfield>[3]</entry>
 	    <entry>Reserved for future extensions. Drivers and
 applications must set the array to zero.</entry>
 	  </row>
-- 
http://palosaari.fi/


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

* [PATCHv3 08/13] hackrf: add control for RF amplifier
  2015-07-31  2:10 [PATCHv3 00/13] SDR transmitter API Antti Palosaari
                   ` (6 preceding siblings ...)
  2015-07-31  2:10 ` [PATCHv3 07/13] DocBook: add modulator type field Antti Palosaari
@ 2015-07-31  2:10 ` Antti Palosaari
  2015-08-10  9:03   ` Hans Verkuil
  2015-07-31  2:10 ` [PATCHv3 09/13] hackrf: switch to single function which configures everything Antti Palosaari
                   ` (4 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Antti Palosaari @ 2015-07-31  2:10 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Antti Palosaari

There is Avago MGA-81563 amplifier just right after antenna connector.
It could be turned on/off and its gain is around 12dB.

Signed-off-by: Antti Palosaari <crope@iki.fi>
---
 drivers/media/usb/hackrf/hackrf.c | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c
index fd1fa41..136de9a 100644
--- a/drivers/media/usb/hackrf/hackrf.c
+++ b/drivers/media/usb/hackrf/hackrf.c
@@ -31,6 +31,7 @@ enum {
 	CMD_BOARD_ID_READ                  = 0x0e,
 	CMD_VERSION_STRING_READ            = 0x0f,
 	CMD_SET_FREQ                       = 0x10,
+	CMD_AMP_ENABLE                     = 0x11,
 	CMD_SET_LNA_GAIN                   = 0x13,
 	CMD_SET_VGA_GAIN                   = 0x14,
 };
@@ -133,6 +134,7 @@ struct hackrf_dev {
 	struct v4l2_ctrl_handler hdl;
 	struct v4l2_ctrl *bandwidth_auto;
 	struct v4l2_ctrl *bandwidth;
+	struct v4l2_ctrl *rf_gain;
 	struct v4l2_ctrl *lna_gain;
 	struct v4l2_ctrl *if_gain;
 
@@ -164,6 +166,7 @@ static int hackrf_ctrl_msg(struct hackrf_dev *dev, u8 request, u16 value,
 	switch (request) {
 	case CMD_SET_TRANSCEIVER_MODE:
 	case CMD_SET_FREQ:
+	case CMD_AMP_ENABLE:
 	case CMD_SAMPLE_RATE_SET:
 	case CMD_BASEBAND_FILTER_BANDWIDTH_SET:
 		pipe = usb_sndctrlpipe(dev->udev, 0);
@@ -949,6 +952,22 @@ static int hackrf_set_bandwidth(struct hackrf_dev *dev)
 	return ret;
 }
 
+static int hackrf_set_rf_gain(struct hackrf_dev *dev)
+{
+	int ret;
+	u8 u8tmp;
+
+	dev_dbg(dev->dev, "rf val=%d->%d\n",
+		dev->rf_gain->cur.val, dev->rf_gain->val);
+
+	u8tmp = (dev->rf_gain->val) ? 1 : 0;
+	ret = hackrf_ctrl_msg(dev, CMD_AMP_ENABLE, u8tmp, 0, NULL, 0);
+	if (ret)
+		dev_dbg(dev->dev, "failed=%d\n", ret);
+
+	return ret;
+}
+
 static int hackrf_set_lna_gain(struct hackrf_dev *dev)
 {
 	int ret;
@@ -992,6 +1011,9 @@ static int hackrf_s_ctrl(struct v4l2_ctrl *ctrl)
 	case V4L2_CID_RF_TUNER_BANDWIDTH:
 		ret = hackrf_set_bandwidth(dev);
 		break;
+	case  V4L2_CID_RF_TUNER_RF_GAIN:
+		ret = hackrf_set_rf_gain(dev);
+		break;
 	case  V4L2_CID_RF_TUNER_LNA_GAIN:
 		ret = hackrf_set_lna_gain(dev);
 		break;
@@ -1077,13 +1099,15 @@ static int hackrf_probe(struct usb_interface *intf,
 	}
 
 	/* Register controls */
-	v4l2_ctrl_handler_init(&dev->hdl, 4);
+	v4l2_ctrl_handler_init(&dev->hdl, 5);
 	dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
 			V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
 	dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
 			V4L2_CID_RF_TUNER_BANDWIDTH,
 			1750000, 28000000, 50000, 1750000);
 	v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false);
+	dev->rf_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
+			V4L2_CID_RF_TUNER_RF_GAIN, 0, 12, 12, 0);
 	dev->lna_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
 			V4L2_CID_RF_TUNER_LNA_GAIN, 0, 40, 8, 0);
 	dev->if_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
-- 
http://palosaari.fi/


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

* [PATCHv3 09/13] hackrf: switch to single function which configures everything
  2015-07-31  2:10 [PATCHv3 00/13] SDR transmitter API Antti Palosaari
                   ` (7 preceding siblings ...)
  2015-07-31  2:10 ` [PATCHv3 08/13] hackrf: add control for RF amplifier Antti Palosaari
@ 2015-07-31  2:10 ` Antti Palosaari
  2015-08-10  9:04   ` Hans Verkuil
  2015-07-31  2:10 ` [PATCHv3 10/13] hackrf: add support for transmitter Antti Palosaari
                   ` (3 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Antti Palosaari @ 2015-07-31  2:10 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Antti Palosaari

Implement single funtion, hackrf_set_params(), which handles all
needed settings. Controls and other IOCTLs are just wrappers to that
function. That way we can get easily better control what we could do
on different device states - sleeping, receiving, transmitting.

Signed-off-by: Antti Palosaari <crope@iki.fi>
---
 drivers/media/usb/hackrf/hackrf.c | 323 +++++++++++++++++++++-----------------
 1 file changed, 175 insertions(+), 148 deletions(-)

diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c
index 136de9a..5bd291b 100644
--- a/drivers/media/usb/hackrf/hackrf.c
+++ b/drivers/media/usb/hackrf/hackrf.c
@@ -91,11 +91,17 @@ struct hackrf_frame_buf {
 };
 
 struct hackrf_dev {
-#define POWER_ON           (1 << 1)
-#define URB_BUF            (1 << 2)
-#define USB_STATE_URB_BUF  (1 << 3)
+#define POWER_ON                         1
+#define USB_STATE_URB_BUF                2 /* XXX: set manually */
+#define SAMPLE_RATE_SET                 10
+#define RX_BANDWIDTH                    11
+#define RX_RF_FREQUENCY                 12
+#define RX_RF_GAIN                      13
+#define RX_LNA_GAIN                     14
+#define RX_IF_GAIN                      15
 	unsigned long flags;
 
+	struct usb_interface *intf;
 	struct device *dev;
 	struct usb_device *udev;
 	struct video_device vdev;
@@ -208,6 +214,140 @@ err:
 	return ret;
 }
 
+static int hackrf_set_params(struct hackrf_dev *dev)
+{
+	struct usb_interface *intf = dev->intf;
+	int ret, i;
+	u8 buf[8], u8tmp;
+	unsigned int uitmp, uitmp1, uitmp2;
+
+	if (!test_bit(POWER_ON, &dev->flags)) {
+		dev_dbg(&intf->dev, "device is sleeping\n");
+		return 0;
+	}
+
+	if (test_and_clear_bit(SAMPLE_RATE_SET, &dev->flags)) {
+		dev_dbg(&intf->dev, "ADC frequency=%u Hz\n", dev->f_adc);
+		uitmp1 = dev->f_adc;
+		uitmp2 = 1;
+		buf[0] = (uitmp1 >>  0) & 0xff;
+		buf[1] = (uitmp1 >>  8) & 0xff;
+		buf[2] = (uitmp1 >> 16) & 0xff;
+		buf[3] = (uitmp1 >> 24) & 0xff;
+		buf[4] = (uitmp2 >>  0) & 0xff;
+		buf[5] = (uitmp2 >>  8) & 0xff;
+		buf[6] = (uitmp2 >> 16) & 0xff;
+		buf[7] = (uitmp2 >> 24) & 0xff;
+		ret = hackrf_ctrl_msg(dev, CMD_SAMPLE_RATE_SET, 0, 0, buf, 8);
+		if (ret)
+			goto err;
+	}
+
+	if (test_and_clear_bit(RX_BANDWIDTH, &dev->flags)) {
+		static const struct {
+			u32 freq;
+		} bandwidth_lut[] = {
+			{ 1750000}, /*  1.75 MHz */
+			{ 2500000}, /*  2.5  MHz */
+			{ 3500000}, /*  3.5  MHz */
+			{ 5000000}, /*  5    MHz */
+			{ 5500000}, /*  5.5  MHz */
+			{ 6000000}, /*  6    MHz */
+			{ 7000000}, /*  7    MHz */
+			{ 8000000}, /*  8    MHz */
+			{ 9000000}, /*  9    MHz */
+			{10000000}, /* 10    MHz */
+			{12000000}, /* 12    MHz */
+			{14000000}, /* 14    MHz */
+			{15000000}, /* 15    MHz */
+			{20000000}, /* 20    MHz */
+			{24000000}, /* 24    MHz */
+			{28000000}, /* 28    MHz */
+		};
+
+		if (dev->bandwidth_auto->val == true)
+			uitmp = dev->f_adc;
+		else
+			uitmp = dev->bandwidth->val;
+
+		for (i = 0; i < ARRAY_SIZE(bandwidth_lut); i++) {
+			if (uitmp <= bandwidth_lut[i].freq) {
+				uitmp = bandwidth_lut[i].freq;
+				break;
+			}
+		}
+
+		dev->bandwidth->val = uitmp;
+		dev->bandwidth->cur.val = uitmp;
+
+		dev_dbg(&intf->dev, "bandwidth selected=%u\n", uitmp);
+
+		uitmp1 = 0;
+		uitmp1 |= ((uitmp >> 0) & 0xff) << 0;
+		uitmp1 |= ((uitmp >> 8) & 0xff) << 8;
+		uitmp2 = 0;
+		uitmp2 |= ((uitmp >> 16) & 0xff) << 0;
+		uitmp2 |= ((uitmp >> 24) & 0xff) << 8;
+
+		ret = hackrf_ctrl_msg(dev, CMD_BASEBAND_FILTER_BANDWIDTH_SET,
+				      uitmp1, uitmp2, NULL, 0);
+		if (ret)
+			goto err;
+	}
+
+	if (test_and_clear_bit(RX_RF_FREQUENCY, &dev->flags)) {
+		dev_dbg(&intf->dev, "RF frequency=%u Hz\n", dev->f_rf);
+		uitmp1 = dev->f_rf / 1000000;
+		uitmp2 = dev->f_rf % 1000000;
+		buf[0] = (uitmp1 >>  0) & 0xff;
+		buf[1] = (uitmp1 >>  8) & 0xff;
+		buf[2] = (uitmp1 >> 16) & 0xff;
+		buf[3] = (uitmp1 >> 24) & 0xff;
+		buf[4] = (uitmp2 >>  0) & 0xff;
+		buf[5] = (uitmp2 >>  8) & 0xff;
+		buf[6] = (uitmp2 >> 16) & 0xff;
+		buf[7] = (uitmp2 >> 24) & 0xff;
+		ret = hackrf_ctrl_msg(dev, CMD_SET_FREQ, 0, 0, buf, 8);
+		if (ret)
+			goto err;
+	}
+
+	if (test_and_clear_bit(RX_RF_GAIN, &dev->flags)) {
+		dev_dbg(&intf->dev, "RF gain val=%d->%d\n",
+			dev->rf_gain->cur.val, dev->rf_gain->val);
+
+		u8tmp = (dev->rf_gain->val) ? 1 : 0;
+		ret = hackrf_ctrl_msg(dev, CMD_AMP_ENABLE, u8tmp, 0, NULL, 0);
+		if (ret)
+			goto err;
+	}
+
+	if (test_and_clear_bit(RX_LNA_GAIN, &dev->flags)) {
+		dev_dbg(dev->dev, "LNA gain val=%d->%d\n",
+			dev->lna_gain->cur.val, dev->lna_gain->val);
+
+		ret = hackrf_ctrl_msg(dev, CMD_SET_LNA_GAIN, 0,
+				      dev->lna_gain->val, &u8tmp, 1);
+		if (ret)
+			goto err;
+	}
+
+	if (test_and_clear_bit(RX_IF_GAIN, &dev->flags)) {
+		dev_dbg(&intf->dev, "IF gain val=%d->%d\n",
+			dev->if_gain->cur.val, dev->if_gain->val);
+
+		ret = hackrf_ctrl_msg(dev, CMD_SET_VGA_GAIN, 0,
+				      dev->if_gain->val, &u8tmp, 1);
+		if (ret)
+			goto err;
+	}
+
+	return 0;
+err:
+	dev_dbg(&intf->dev, "failed=%d\n", ret);
+	return ret;
+}
+
 /* Private functions */
 static struct hackrf_frame_buf *hackrf_get_next_fill_buf(struct hackrf_dev *dev)
 {
@@ -524,6 +664,10 @@ static int hackrf_start_streaming(struct vb2_queue *vq, unsigned int count)
 	if (ret)
 		goto err;
 
+	ret = hackrf_set_params(dev);
+	if (ret)
+		goto err;
+
 	/* start hardware streaming */
 	ret = hackrf_ctrl_msg(dev, CMD_SET_TRANSCEIVER_MODE, 1, 0, NULL, 0);
 	if (ret)
@@ -735,47 +879,32 @@ static int hackrf_s_frequency(struct file *file, void *priv,
 		const struct v4l2_frequency *f)
 {
 	struct hackrf_dev *dev = video_drvdata(file);
+	struct usb_interface *intf = dev->intf;
 	int ret;
-	unsigned int upper, lower;
-	u8 buf[8];
 
-	dev_dbg(dev->dev, "tuner=%d type=%d frequency=%u\n",
+	dev_dbg(&intf->dev, "tuner=%d type=%d frequency=%u\n",
 			f->tuner, f->type, f->frequency);
 
 	if (f->tuner == 0) {
 		dev->f_adc = clamp_t(unsigned int, f->frequency,
 				bands_adc[0].rangelow, bands_adc[0].rangehigh);
-		dev_dbg(dev->dev, "ADC frequency=%u Hz\n", dev->f_adc);
-		upper = dev->f_adc;
-		lower = 1;
-		buf[0] = (upper >>  0) & 0xff;
-		buf[1] = (upper >>  8) & 0xff;
-		buf[2] = (upper >> 16) & 0xff;
-		buf[3] = (upper >> 24) & 0xff;
-		buf[4] = (lower >>  0) & 0xff;
-		buf[5] = (lower >>  8) & 0xff;
-		buf[6] = (lower >> 16) & 0xff;
-		buf[7] = (lower >> 24) & 0xff;
-		ret = hackrf_ctrl_msg(dev, CMD_SAMPLE_RATE_SET, 0, 0, buf, 8);
+		set_bit(SAMPLE_RATE_SET, &dev->flags);
 	} else if (f->tuner == 1) {
 		dev->f_rf = clamp_t(unsigned int, f->frequency,
 				bands_rf[0].rangelow, bands_rf[0].rangehigh);
-		dev_dbg(dev->dev, "RF frequency=%u Hz\n", dev->f_rf);
-		upper = dev->f_rf / 1000000;
-		lower = dev->f_rf % 1000000;
-		buf[0] = (upper >>  0) & 0xff;
-		buf[1] = (upper >>  8) & 0xff;
-		buf[2] = (upper >> 16) & 0xff;
-		buf[3] = (upper >> 24) & 0xff;
-		buf[4] = (lower >>  0) & 0xff;
-		buf[5] = (lower >>  8) & 0xff;
-		buf[6] = (lower >> 16) & 0xff;
-		buf[7] = (lower >> 24) & 0xff;
-		ret = hackrf_ctrl_msg(dev, CMD_SET_FREQ, 0, 0, buf, 8);
+		set_bit(RX_RF_FREQUENCY, &dev->flags);
 	} else {
 		ret = -EINVAL;
+		goto err;
 	}
 
+	ret = hackrf_set_params(dev);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	dev_dbg(&intf->dev, "failed=%d\n", ret);
 	return ret;
 }
 
@@ -888,144 +1017,41 @@ static void hackrf_video_release(struct v4l2_device *v)
 	kfree(dev);
 }
 
-static int hackrf_set_bandwidth(struct hackrf_dev *dev)
-{
-	int ret, i;
-	u16 u16tmp, u16tmp2;
-	unsigned int bandwidth;
-
-	static const struct {
-		u32 freq;
-	} bandwidth_lut[] = {
-		{ 1750000}, /*  1.75 MHz */
-		{ 2500000}, /*  2.5  MHz */
-		{ 3500000}, /*  3.5  MHz */
-		{ 5000000}, /*  5    MHz */
-		{ 5500000}, /*  5.5  MHz */
-		{ 6000000}, /*  6    MHz */
-		{ 7000000}, /*  7    MHz */
-		{ 8000000}, /*  8    MHz */
-		{ 9000000}, /*  9    MHz */
-		{10000000}, /* 10    MHz */
-		{12000000}, /* 12    MHz */
-		{14000000}, /* 14    MHz */
-		{15000000}, /* 15    MHz */
-		{20000000}, /* 20    MHz */
-		{24000000}, /* 24    MHz */
-		{28000000}, /* 28    MHz */
-	};
-
-	dev_dbg(dev->dev, "bandwidth auto=%d->%d val=%d->%d f_adc=%u\n",
-			dev->bandwidth_auto->cur.val,
-			dev->bandwidth_auto->val, dev->bandwidth->cur.val,
-			dev->bandwidth->val, dev->f_adc);
-
-	if (dev->bandwidth_auto->val == true)
-		bandwidth = dev->f_adc;
-	else
-		bandwidth = dev->bandwidth->val;
-
-	for (i = 0; i < ARRAY_SIZE(bandwidth_lut); i++) {
-		if (bandwidth <= bandwidth_lut[i].freq) {
-			bandwidth = bandwidth_lut[i].freq;
-			break;
-		}
-	}
-
-	dev->bandwidth->val = bandwidth;
-	dev->bandwidth->cur.val = bandwidth;
-
-	dev_dbg(dev->dev, "bandwidth selected=%d\n", bandwidth);
-
-	u16tmp = 0;
-	u16tmp |= ((bandwidth >> 0) & 0xff) << 0;
-	u16tmp |= ((bandwidth >> 8) & 0xff) << 8;
-	u16tmp2 = 0;
-	u16tmp2 |= ((bandwidth >> 16) & 0xff) << 0;
-	u16tmp2 |= ((bandwidth >> 24) & 0xff) << 8;
-
-	ret = hackrf_ctrl_msg(dev, CMD_BASEBAND_FILTER_BANDWIDTH_SET,
-				u16tmp, u16tmp2, NULL, 0);
-	if (ret)
-		dev_dbg(dev->dev, "failed=%d\n", ret);
-
-	return ret;
-}
-
-static int hackrf_set_rf_gain(struct hackrf_dev *dev)
-{
-	int ret;
-	u8 u8tmp;
-
-	dev_dbg(dev->dev, "rf val=%d->%d\n",
-		dev->rf_gain->cur.val, dev->rf_gain->val);
-
-	u8tmp = (dev->rf_gain->val) ? 1 : 0;
-	ret = hackrf_ctrl_msg(dev, CMD_AMP_ENABLE, u8tmp, 0, NULL, 0);
-	if (ret)
-		dev_dbg(dev->dev, "failed=%d\n", ret);
-
-	return ret;
-}
-
-static int hackrf_set_lna_gain(struct hackrf_dev *dev)
-{
-	int ret;
-	u8 u8tmp;
-
-	dev_dbg(dev->dev, "lna val=%d->%d\n",
-			dev->lna_gain->cur.val, dev->lna_gain->val);
-
-	ret = hackrf_ctrl_msg(dev, CMD_SET_LNA_GAIN, 0, dev->lna_gain->val,
-			&u8tmp, 1);
-	if (ret)
-		dev_dbg(dev->dev, "failed=%d\n", ret);
-
-	return ret;
-}
-
-static int hackrf_set_if_gain(struct hackrf_dev *dev)
-{
-	int ret;
-	u8 u8tmp;
-
-	dev_dbg(dev->dev, "val=%d->%d\n",
-			dev->if_gain->cur.val, dev->if_gain->val);
-
-	ret = hackrf_ctrl_msg(dev, CMD_SET_VGA_GAIN, 0, dev->if_gain->val,
-			&u8tmp, 1);
-	if (ret)
-		dev_dbg(dev->dev, "failed=%d\n", ret);
-
-	return ret;
-}
-
 static int hackrf_s_ctrl(struct v4l2_ctrl *ctrl)
 {
 	struct hackrf_dev *dev = container_of(ctrl->handler,
 			struct hackrf_dev, hdl);
+	struct usb_interface *intf = dev->intf;
 	int ret;
 
 	switch (ctrl->id) {
 	case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:
 	case V4L2_CID_RF_TUNER_BANDWIDTH:
-		ret = hackrf_set_bandwidth(dev);
+		set_bit(RX_BANDWIDTH, &dev->flags);
 		break;
 	case  V4L2_CID_RF_TUNER_RF_GAIN:
-		ret = hackrf_set_rf_gain(dev);
+		set_bit(RX_RF_GAIN, &dev->flags);
 		break;
 	case  V4L2_CID_RF_TUNER_LNA_GAIN:
-		ret = hackrf_set_lna_gain(dev);
+		set_bit(RX_LNA_GAIN, &dev->flags);
 		break;
 	case  V4L2_CID_RF_TUNER_IF_GAIN:
-		ret = hackrf_set_if_gain(dev);
+		set_bit(RX_IF_GAIN, &dev->flags);
 		break;
 	default:
-		dev_dbg(dev->dev, "unknown ctrl: id=%d name=%s\n",
-				ctrl->id, ctrl->name);
+		dev_dbg(&intf->dev, "unknown ctrl: id=%d name=%s\n",
+			ctrl->id, ctrl->name);
 		ret = -EINVAL;
+		goto err;
 	}
 
+	ret = hackrf_set_params(dev);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	dev_dbg(&intf->dev, "failed=%d\n", ret);
 	return ret;
 }
 
@@ -1048,6 +1074,7 @@ static int hackrf_probe(struct usb_interface *intf,
 	mutex_init(&dev->vb_queue_lock);
 	spin_lock_init(&dev->queued_bufs_lock);
 	INIT_LIST_HEAD(&dev->queued_bufs);
+	dev->intf = intf;
 	dev->dev = &intf->dev;
 	dev->udev = interface_to_usbdev(intf);
 	dev->f_adc = bands_adc[0].rangelow;
-- 
http://palosaari.fi/


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

* [PATCHv3 10/13] hackrf: add support for transmitter
  2015-07-31  2:10 [PATCHv3 00/13] SDR transmitter API Antti Palosaari
                   ` (8 preceding siblings ...)
  2015-07-31  2:10 ` [PATCHv3 09/13] hackrf: switch to single function which configures everything Antti Palosaari
@ 2015-07-31  2:10 ` Antti Palosaari
  2015-08-10  9:34   ` Hans Verkuil
  2015-07-31  2:10 ` [PATCHv3 11/13] hackrf: do not set human readable name for formats Antti Palosaari
                   ` (2 subsequent siblings)
  12 siblings, 1 reply; 24+ messages in thread
From: Antti Palosaari @ 2015-07-31  2:10 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Antti Palosaari

HackRF SDR device has both receiver and transmitter. There is limitation
that receiver and transmitter cannot be used at the same time
(half-duplex operation). That patch implements transmitter support to
existing receiver only driver.

Cc: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
 drivers/media/usb/hackrf/hackrf.c | 894 ++++++++++++++++++++++++++------------
 1 file changed, 627 insertions(+), 267 deletions(-)

diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c
index 5bd291b..f4b5606 100644
--- a/drivers/media/usb/hackrf/hackrf.c
+++ b/drivers/media/usb/hackrf/hackrf.c
@@ -34,6 +34,7 @@ enum {
 	CMD_AMP_ENABLE                     = 0x11,
 	CMD_SET_LNA_GAIN                   = 0x13,
 	CMD_SET_VGA_GAIN                   = 0x14,
+	CMD_SET_TXVGA_GAIN                 = 0x15,
 };
 
 /*
@@ -44,10 +45,10 @@ enum {
 #define MAX_BULK_BUFS            (6)
 #define BULK_BUFFER_SIZE         (128 * 512)
 
-static const struct v4l2_frequency_band bands_adc[] = {
+static const struct v4l2_frequency_band bands_adc_dac[] = {
 	{
 		.tuner = 0,
-		.type = V4L2_TUNER_ADC,
+		.type = V4L2_TUNER_SDR,
 		.index = 0,
 		.capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
 		.rangelow   =   200000,
@@ -55,7 +56,7 @@ static const struct v4l2_frequency_band bands_adc[] = {
 	},
 };
 
-static const struct v4l2_frequency_band bands_rf[] = {
+static const struct v4l2_frequency_band bands_rx_tx[] = {
 	{
 		.tuner = 1,
 		.type = V4L2_TUNER_RF,
@@ -85,34 +86,44 @@ static struct hackrf_format formats[] = {
 static const unsigned int NUM_FORMATS = ARRAY_SIZE(formats);
 
 /* intermediate buffers with raw data from the USB device */
-struct hackrf_frame_buf {
-	struct vb2_buffer vb;   /* common v4l buffer stuff -- must be first */
+struct hackrf_buffer {
+	struct vb2_buffer vb;
 	struct list_head list;
 };
 
 struct hackrf_dev {
-#define POWER_ON                         1
-#define USB_STATE_URB_BUF                2 /* XXX: set manually */
-#define SAMPLE_RATE_SET                 10
-#define RX_BANDWIDTH                    11
-#define RX_RF_FREQUENCY                 12
-#define RX_RF_GAIN                      13
-#define RX_LNA_GAIN                     14
-#define RX_IF_GAIN                      15
+#define USB_STATE_URB_BUF                1 /* XXX: set manually */
+#define RX_ON                            4
+#define TX_ON                            5
+#define RX_ADC_FREQUENCY                11
+#define TX_DAC_FREQUENCY                12
+#define RX_BANDWIDTH                    13
+#define TX_BANDWIDTH                    14
+#define RX_RF_FREQUENCY                 15
+#define TX_RF_FREQUENCY                 16
+#define RX_RF_GAIN                      17
+#define TX_RF_GAIN                      18
+#define RX_IF_GAIN                      19
+#define RX_LNA_GAIN                     20
+#define TX_LNA_GAIN                     21
 	unsigned long flags;
 
 	struct usb_interface *intf;
 	struct device *dev;
 	struct usb_device *udev;
-	struct video_device vdev;
+	struct video_device rx_vdev;
+	struct video_device tx_vdev;
 	struct v4l2_device v4l2_dev;
 
 	/* videobuf2 queue and queued buffers list */
-	struct vb2_queue vb_queue;
-	struct list_head queued_bufs;
-	spinlock_t queued_bufs_lock; /* Protects queued_bufs */
+	struct vb2_queue rx_vb2_queue;
+	struct vb2_queue tx_vb2_queue;
+	struct list_head rx_buffer_list;
+	struct list_head tx_buffer_list;
+	spinlock_t buffer_list_lock; /* Protects buffer_list */
 	unsigned sequence;	     /* Buffer sequence counter */
 	unsigned int vb_full;        /* vb is full and packets dropped */
+	unsigned int vb_empty;       /* vb is empty and packets dropped */
 
 	/* Note if taking both locks v4l2_lock must always be locked first! */
 	struct mutex v4l2_lock;      /* Protects everything else */
@@ -132,17 +143,24 @@ struct hackrf_dev {
 
 	/* Current configuration */
 	unsigned int f_adc;
-	unsigned int f_rf;
+	unsigned int f_dac;
+	unsigned int f_rx;
+	unsigned int f_tx;
 	u32 pixelformat;
 	u32 buffersize;
 
 	/* Controls */
-	struct v4l2_ctrl_handler hdl;
-	struct v4l2_ctrl *bandwidth_auto;
-	struct v4l2_ctrl *bandwidth;
-	struct v4l2_ctrl *rf_gain;
-	struct v4l2_ctrl *lna_gain;
-	struct v4l2_ctrl *if_gain;
+	struct v4l2_ctrl_handler rx_ctrl_handler;
+	struct v4l2_ctrl *rx_bandwidth_auto;
+	struct v4l2_ctrl *rx_bandwidth;
+	struct v4l2_ctrl *rx_rf_gain;
+	struct v4l2_ctrl *rx_lna_gain;
+	struct v4l2_ctrl *rx_if_gain;
+	struct v4l2_ctrl_handler tx_ctrl_handler;
+	struct v4l2_ctrl *tx_bandwidth_auto;
+	struct v4l2_ctrl *tx_bandwidth;
+	struct v4l2_ctrl *tx_rf_gain;
+	struct v4l2_ctrl *tx_lna_gain;
 
 	/* Sample rate calc */
 	unsigned long jiffies_next;
@@ -182,6 +200,7 @@ static int hackrf_ctrl_msg(struct hackrf_dev *dev, u8 request, u16 value,
 	case CMD_VERSION_STRING_READ:
 	case CMD_SET_LNA_GAIN:
 	case CMD_SET_VGA_GAIN:
+	case CMD_SET_TXVGA_GAIN:
 		pipe = usb_rcvctrlpipe(dev->udev, 0);
 		requesttype = (USB_TYPE_VENDOR | USB_DIR_IN);
 		break;
@@ -220,16 +239,49 @@ static int hackrf_set_params(struct hackrf_dev *dev)
 	int ret, i;
 	u8 buf[8], u8tmp;
 	unsigned int uitmp, uitmp1, uitmp2;
-
-	if (!test_bit(POWER_ON, &dev->flags)) {
+	const bool rx = test_bit(RX_ON, &dev->flags);
+	const bool tx = test_bit(TX_ON, &dev->flags);
+	static const struct {
+		u32 freq;
+	} bandwidth_lut[] = {
+		{ 1750000}, /*  1.75 MHz */
+		{ 2500000}, /*  2.5  MHz */
+		{ 3500000}, /*  3.5  MHz */
+		{ 5000000}, /*  5    MHz */
+		{ 5500000}, /*  5.5  MHz */
+		{ 6000000}, /*  6    MHz */
+		{ 7000000}, /*  7    MHz */
+		{ 8000000}, /*  8    MHz */
+		{ 9000000}, /*  9    MHz */
+		{10000000}, /* 10    MHz */
+		{12000000}, /* 12    MHz */
+		{14000000}, /* 14    MHz */
+		{15000000}, /* 15    MHz */
+		{20000000}, /* 20    MHz */
+		{24000000}, /* 24    MHz */
+		{28000000}, /* 28    MHz */
+	};
+
+	if (!rx && !tx) {
 		dev_dbg(&intf->dev, "device is sleeping\n");
 		return 0;
 	}
 
-	if (test_and_clear_bit(SAMPLE_RATE_SET, &dev->flags)) {
-		dev_dbg(&intf->dev, "ADC frequency=%u Hz\n", dev->f_adc);
+	/* ADC / DAC frequency */
+	if (rx && test_and_clear_bit(RX_ADC_FREQUENCY, &dev->flags)) {
+		dev_dbg(&intf->dev, "RX ADC frequency=%u Hz\n", dev->f_adc);
 		uitmp1 = dev->f_adc;
 		uitmp2 = 1;
+		set_bit(TX_DAC_FREQUENCY, &dev->flags);
+	} else if (tx && test_and_clear_bit(TX_DAC_FREQUENCY, &dev->flags)) {
+		dev_dbg(&intf->dev, "TX DAC frequency=%u Hz\n", dev->f_dac);
+		uitmp1 = dev->f_dac;
+		uitmp2 = 1;
+		set_bit(RX_ADC_FREQUENCY, &dev->flags);
+	} else {
+		uitmp1 = uitmp2 = 0;
+	}
+	if (uitmp1 || uitmp2) {
 		buf[0] = (uitmp1 >>  0) & 0xff;
 		buf[1] = (uitmp1 >>  8) & 0xff;
 		buf[2] = (uitmp1 >> 16) & 0xff;
@@ -243,32 +295,12 @@ static int hackrf_set_params(struct hackrf_dev *dev)
 			goto err;
 	}
 
-	if (test_and_clear_bit(RX_BANDWIDTH, &dev->flags)) {
-		static const struct {
-			u32 freq;
-		} bandwidth_lut[] = {
-			{ 1750000}, /*  1.75 MHz */
-			{ 2500000}, /*  2.5  MHz */
-			{ 3500000}, /*  3.5  MHz */
-			{ 5000000}, /*  5    MHz */
-			{ 5500000}, /*  5.5  MHz */
-			{ 6000000}, /*  6    MHz */
-			{ 7000000}, /*  7    MHz */
-			{ 8000000}, /*  8    MHz */
-			{ 9000000}, /*  9    MHz */
-			{10000000}, /* 10    MHz */
-			{12000000}, /* 12    MHz */
-			{14000000}, /* 14    MHz */
-			{15000000}, /* 15    MHz */
-			{20000000}, /* 20    MHz */
-			{24000000}, /* 24    MHz */
-			{28000000}, /* 28    MHz */
-		};
-
-		if (dev->bandwidth_auto->val == true)
+	/* bandwidth */
+	if (rx && test_and_clear_bit(RX_BANDWIDTH, &dev->flags)) {
+		if (dev->rx_bandwidth_auto->val == true)
 			uitmp = dev->f_adc;
 		else
-			uitmp = dev->bandwidth->val;
+			uitmp = dev->rx_bandwidth->val;
 
 		for (i = 0; i < ARRAY_SIZE(bandwidth_lut); i++) {
 			if (uitmp <= bandwidth_lut[i].freq) {
@@ -276,29 +308,56 @@ static int hackrf_set_params(struct hackrf_dev *dev)
 				break;
 			}
 		}
+		dev->rx_bandwidth->val = uitmp;
+		dev->rx_bandwidth->cur.val = uitmp;
+		dev_dbg(&intf->dev, "RX bandwidth selected=%u\n", uitmp);
+		set_bit(TX_BANDWIDTH, &dev->flags);
+	} else if (tx && test_and_clear_bit(TX_BANDWIDTH, &dev->flags)) {
+		if (dev->tx_bandwidth_auto->val == true)
+			uitmp = dev->f_dac;
+		else
+			uitmp = dev->tx_bandwidth->val;
 
-		dev->bandwidth->val = uitmp;
-		dev->bandwidth->cur.val = uitmp;
-
-		dev_dbg(&intf->dev, "bandwidth selected=%u\n", uitmp);
-
-		uitmp1 = 0;
-		uitmp1 |= ((uitmp >> 0) & 0xff) << 0;
-		uitmp1 |= ((uitmp >> 8) & 0xff) << 8;
-		uitmp2 = 0;
+		for (i = 0; i < ARRAY_SIZE(bandwidth_lut); i++) {
+			if (uitmp <= bandwidth_lut[i].freq) {
+				uitmp = bandwidth_lut[i].freq;
+				break;
+			}
+		}
+		dev->tx_bandwidth->val = uitmp;
+		dev->tx_bandwidth->cur.val = uitmp;
+		dev_dbg(&intf->dev, "TX bandwidth selected=%u\n", uitmp);
+		set_bit(RX_BANDWIDTH, &dev->flags);
+	} else {
+		uitmp = 0;
+	}
+	if (uitmp) {
+		uitmp1 = uitmp2 = 0;
+		uitmp1 |= ((uitmp >>  0) & 0xff) << 0;
+		uitmp1 |= ((uitmp >>  8) & 0xff) << 8;
 		uitmp2 |= ((uitmp >> 16) & 0xff) << 0;
 		uitmp2 |= ((uitmp >> 24) & 0xff) << 8;
-
 		ret = hackrf_ctrl_msg(dev, CMD_BASEBAND_FILTER_BANDWIDTH_SET,
 				      uitmp1, uitmp2, NULL, 0);
 		if (ret)
 			goto err;
 	}
 
-	if (test_and_clear_bit(RX_RF_FREQUENCY, &dev->flags)) {
-		dev_dbg(&intf->dev, "RF frequency=%u Hz\n", dev->f_rf);
-		uitmp1 = dev->f_rf / 1000000;
-		uitmp2 = dev->f_rf % 1000000;
+	/* RX / TX RF frequency */
+	if (rx && test_and_clear_bit(RX_RF_FREQUENCY, &dev->flags)) {
+		dev_dbg(&intf->dev, "RX RF frequency=%u Hz\n", dev->f_rx);
+		uitmp1 = dev->f_rx / 1000000;
+		uitmp2 = dev->f_rx % 1000000;
+		set_bit(TX_RF_FREQUENCY, &dev->flags);
+	} else if (tx && test_and_clear_bit(TX_RF_FREQUENCY, &dev->flags)) {
+		dev_dbg(&intf->dev, "TX RF frequency=%u Hz\n", dev->f_tx);
+		uitmp1 = dev->f_tx / 1000000;
+		uitmp2 = dev->f_tx % 1000000;
+		set_bit(RX_RF_FREQUENCY, &dev->flags);
+	} else {
+		uitmp1 = uitmp2 = 0;
+	}
+	if (uitmp1 || uitmp2) {
 		buf[0] = (uitmp1 >>  0) & 0xff;
 		buf[1] = (uitmp1 >>  8) & 0xff;
 		buf[2] = (uitmp1 >> 16) & 0xff;
@@ -312,32 +371,59 @@ static int hackrf_set_params(struct hackrf_dev *dev)
 			goto err;
 	}
 
-	if (test_and_clear_bit(RX_RF_GAIN, &dev->flags)) {
-		dev_dbg(&intf->dev, "RF gain val=%d->%d\n",
-			dev->rf_gain->cur.val, dev->rf_gain->val);
+	/* RX RF gain */
+	if (rx && test_and_clear_bit(RX_RF_GAIN, &dev->flags)) {
+		dev_dbg(&intf->dev, "RX RF gain val=%d->%d\n",
+			dev->rx_rf_gain->cur.val, dev->rx_rf_gain->val);
 
-		u8tmp = (dev->rf_gain->val) ? 1 : 0;
+		u8tmp = (dev->rx_rf_gain->val) ? 1 : 0;
 		ret = hackrf_ctrl_msg(dev, CMD_AMP_ENABLE, u8tmp, 0, NULL, 0);
 		if (ret)
 			goto err;
+		set_bit(TX_RF_GAIN, &dev->flags);
+	}
+
+	/* TX RF gain */
+	if (tx && test_and_clear_bit(TX_RF_GAIN, &dev->flags)) {
+		dev_dbg(&intf->dev, "TX RF gain val=%d->%d\n",
+			dev->tx_rf_gain->cur.val, dev->tx_rf_gain->val);
+
+		u8tmp = (dev->tx_rf_gain->val) ? 1 : 0;
+		ret = hackrf_ctrl_msg(dev, CMD_AMP_ENABLE, u8tmp, 0, NULL, 0);
+		if (ret)
+			goto err;
+		set_bit(RX_RF_GAIN, &dev->flags);
 	}
 
-	if (test_and_clear_bit(RX_LNA_GAIN, &dev->flags)) {
-		dev_dbg(dev->dev, "LNA gain val=%d->%d\n",
-			dev->lna_gain->cur.val, dev->lna_gain->val);
+	/* RX LNA gain */
+	if (rx && test_and_clear_bit(RX_LNA_GAIN, &dev->flags)) {
+		dev_dbg(dev->dev, "RX LNA gain val=%d->%d\n",
+			dev->rx_lna_gain->cur.val, dev->rx_lna_gain->val);
 
 		ret = hackrf_ctrl_msg(dev, CMD_SET_LNA_GAIN, 0,
-				      dev->lna_gain->val, &u8tmp, 1);
+				      dev->rx_lna_gain->val, &u8tmp, 1);
 		if (ret)
 			goto err;
 	}
 
-	if (test_and_clear_bit(RX_IF_GAIN, &dev->flags)) {
+	/* RX IF gain */
+	if (rx && test_and_clear_bit(RX_IF_GAIN, &dev->flags)) {
 		dev_dbg(&intf->dev, "IF gain val=%d->%d\n",
-			dev->if_gain->cur.val, dev->if_gain->val);
+			dev->rx_if_gain->cur.val, dev->rx_if_gain->val);
 
 		ret = hackrf_ctrl_msg(dev, CMD_SET_VGA_GAIN, 0,
-				      dev->if_gain->val, &u8tmp, 1);
+				      dev->rx_if_gain->val, &u8tmp, 1);
+		if (ret)
+			goto err;
+	}
+
+	/* TX LNA gain */
+	if (tx && test_and_clear_bit(TX_LNA_GAIN, &dev->flags)) {
+		dev_dbg(&intf->dev, "TX LNA gain val=%d->%d\n",
+			dev->tx_lna_gain->cur.val, dev->tx_lna_gain->val);
+
+		ret = hackrf_ctrl_msg(dev, CMD_SET_TXVGA_GAIN, 0,
+				      dev->tx_lna_gain->val, &u8tmp, 1);
 		if (ret)
 			goto err;
 	}
@@ -349,24 +435,25 @@ err:
 }
 
 /* Private functions */
-static struct hackrf_frame_buf *hackrf_get_next_fill_buf(struct hackrf_dev *dev)
+static struct hackrf_buffer *hackrf_get_next_buffer(struct hackrf_dev *dev,
+						    struct list_head *buffer_list)
 {
 	unsigned long flags;
-	struct hackrf_frame_buf *buf = NULL;
+	struct hackrf_buffer *buffer = NULL;
 
-	spin_lock_irqsave(&dev->queued_bufs_lock, flags);
-	if (list_empty(&dev->queued_bufs))
+	spin_lock_irqsave(&dev->buffer_list_lock, flags);
+	if (list_empty(buffer_list))
 		goto leave;
 
-	buf = list_entry(dev->queued_bufs.next, struct hackrf_frame_buf, list);
-	list_del(&buf->list);
+	buffer = list_entry(buffer_list->next, struct hackrf_buffer, list);
+	list_del(&buffer->list);
 leave:
-	spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
-	return buf;
+	spin_unlock_irqrestore(&dev->buffer_list_lock, flags);
+	return buffer;
 }
 
-static unsigned int hackrf_convert_stream(struct hackrf_dev *dev,
-		void *dst, void *src, unsigned int src_len)
+void hackrf_copy_stream(struct hackrf_dev *dev, void *dst,
+			void *src, unsigned int src_len)
 {
 	memcpy(dst, src, src_len);
 
@@ -386,22 +473,21 @@ static unsigned int hackrf_convert_stream(struct hackrf_dev *dev,
 
 	/* total number of samples */
 	dev->sample += src_len / 2;
-
-	return src_len;
 }
 
 /*
  * This gets called for the bulk stream pipe. This is done in interrupt
  * time, so it has to be fast, not crash, and not stall. Neat.
  */
-static void hackrf_urb_complete(struct urb *urb)
+static void hackrf_urb_complete_in(struct urb *urb)
 {
 	struct hackrf_dev *dev = urb->context;
-	struct hackrf_frame_buf *fbuf;
+	struct usb_interface *intf = dev->intf;
+	struct hackrf_buffer *buffer;
+	unsigned int len;
 
-	dev_dbg_ratelimited(dev->dev, "status=%d length=%d/%d errors=%d\n",
-			urb->status, urb->actual_length,
-			urb->transfer_buffer_length, urb->error_count);
+	dev_dbg_ratelimited(&intf->dev, "status=%d length=%u/%u\n", urb->status,
+			    urb->actual_length, urb->transfer_buffer_length);
 
 	switch (urb->status) {
 	case 0:             /* success */
@@ -412,33 +498,74 @@ static void hackrf_urb_complete(struct urb *urb)
 	case -ESHUTDOWN:
 		return;
 	default:            /* error */
-		dev_err_ratelimited(dev->dev, "URB failed %d\n", urb->status);
-		break;
+		dev_err_ratelimited(&intf->dev, "URB failed %d\n", urb->status);
+		goto exit_usb_submit_urb;
 	}
 
-	if (likely(urb->actual_length > 0)) {
-		void *ptr;
-		unsigned int len;
-		/* get free framebuffer */
-		fbuf = hackrf_get_next_fill_buf(dev);
-		if (unlikely(fbuf == NULL)) {
-			dev->vb_full++;
-			dev_notice_ratelimited(dev->dev,
-					"videobuf is full, %d packets dropped\n",
-					dev->vb_full);
-			goto skip;
-		}
+	/* get buffer to write */
+	buffer = hackrf_get_next_buffer(dev, &dev->rx_buffer_list);
+	if (unlikely(buffer == NULL)) {
+		dev->vb_full++;
+		dev_notice_ratelimited(&intf->dev,
+				       "buffer is full - %u packets dropped\n",
+				       dev->vb_full);
+		goto exit_usb_submit_urb;
+	}
 
-		/* fill framebuffer */
-		ptr = vb2_plane_vaddr(&fbuf->vb, 0);
-		len = hackrf_convert_stream(dev, ptr, urb->transfer_buffer,
-				urb->actual_length);
-		vb2_set_plane_payload(&fbuf->vb, 0, len);
-		v4l2_get_timestamp(&fbuf->vb.v4l2_buf.timestamp);
-		fbuf->vb.v4l2_buf.sequence = dev->sequence++;
-		vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE);
+	len = min_t(unsigned long, vb2_plane_size(&buffer->vb, 0),
+		    urb->actual_length);
+	hackrf_copy_stream(dev, vb2_plane_vaddr(&buffer->vb, 0),
+		    urb->transfer_buffer, len);
+	vb2_set_plane_payload(&buffer->vb, 0, len);
+	buffer->vb.v4l2_buf.sequence = dev->sequence++;
+	v4l2_get_timestamp(&buffer->vb.v4l2_buf.timestamp);
+	vb2_buffer_done(&buffer->vb, VB2_BUF_STATE_DONE);
+exit_usb_submit_urb:
+	usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static void hackrf_urb_complete_out(struct urb *urb)
+{
+	struct hackrf_dev *dev = urb->context;
+	struct usb_interface *intf = dev->intf;
+	struct hackrf_buffer *buffer;
+	unsigned int len;
+
+	dev_dbg_ratelimited(&intf->dev, "status=%d length=%u/%u\n", urb->status,
+			    urb->actual_length, urb->transfer_buffer_length);
+
+	switch (urb->status) {
+	case 0:             /* success */
+	case -ETIMEDOUT:    /* NAK */
+		break;
+	case -ECONNRESET:   /* kill */
+	case -ENOENT:
+	case -ESHUTDOWN:
+		return;
+	default:            /* error */
+		dev_err_ratelimited(&intf->dev, "URB failed %d\n", urb->status);
 	}
-skip:
+
+	/* get buffer to read */
+	buffer = hackrf_get_next_buffer(dev, &dev->tx_buffer_list);
+	if (unlikely(buffer == NULL)) {
+		dev->vb_empty++;
+		dev_notice_ratelimited(&intf->dev,
+				       "buffer is empty - %u packets dropped\n",
+				       dev->vb_empty);
+		urb->actual_length = 0;
+		goto exit_usb_submit_urb;
+	}
+
+	len = min_t(unsigned long, urb->transfer_buffer_length,
+		    vb2_get_plane_payload(&buffer->vb, 0));
+	hackrf_copy_stream(dev, urb->transfer_buffer,
+			   vb2_plane_vaddr(&buffer->vb, 0), len);
+	urb->actual_length = len;
+	buffer->vb.v4l2_buf.sequence = dev->sequence++;
+	v4l2_get_timestamp(&buffer->vb.v4l2_buf.timestamp);
+	vb2_buffer_done(&buffer->vb, VB2_BUF_STATE_DONE);
+exit_usb_submit_urb:
 	usb_submit_urb(urb, GFP_ATOMIC);
 }
 
@@ -537,9 +664,19 @@ static int hackrf_free_urbs(struct hackrf_dev *dev)
 	return 0;
 }
 
-static int hackrf_alloc_urbs(struct hackrf_dev *dev)
+static int hackrf_alloc_urbs(struct hackrf_dev *dev, bool rcv)
 {
 	int i, j;
+	unsigned int pipe;
+	usb_complete_t complete;
+
+	if (rcv) {
+		pipe = usb_rcvbulkpipe(dev->udev, 0x81);
+		complete = &hackrf_urb_complete_in;
+	} else {
+		pipe = usb_sndbulkpipe(dev->udev, 0x02);
+		complete = &hackrf_urb_complete_out;
+	}
 
 	/* allocate the URBs */
 	for (i = 0; i < MAX_BULK_BUFS; i++) {
@@ -553,10 +690,10 @@ static int hackrf_alloc_urbs(struct hackrf_dev *dev)
 		}
 		usb_fill_bulk_urb(dev->urb_list[i],
 				dev->udev,
-				usb_rcvbulkpipe(dev->udev, 0x81),
+				pipe,
 				dev->buf_list[i],
 				BULK_BUFFER_SIZE,
-				hackrf_urb_complete, dev);
+				complete, dev);
 
 		dev->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
 		dev->urb_list[i]->transfer_dma = dev->dma_addr[i];
@@ -566,25 +703,6 @@ static int hackrf_alloc_urbs(struct hackrf_dev *dev)
 	return 0;
 }
 
-/* Must be called with vb_queue_lock hold */
-static void hackrf_cleanup_queued_bufs(struct hackrf_dev *dev)
-{
-	unsigned long flags;
-
-	dev_dbg(dev->dev, "\n");
-
-	spin_lock_irqsave(&dev->queued_bufs_lock, flags);
-	while (!list_empty(&dev->queued_bufs)) {
-		struct hackrf_frame_buf *buf;
-
-		buf = list_entry(dev->queued_bufs.next,
-				struct hackrf_frame_buf, list);
-		list_del(&buf->list);
-		vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
-	}
-	spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
-}
-
 /* The user yanked out the cable... */
 static void hackrf_disconnect(struct usb_interface *intf)
 {
@@ -598,7 +716,8 @@ static void hackrf_disconnect(struct usb_interface *intf)
 	/* No need to keep the urbs around after disconnection */
 	dev->udev = NULL;
 	v4l2_device_disconnect(&dev->v4l2_dev);
-	video_unregister_device(&dev->vdev);
+	video_unregister_device(&dev->tx_vdev);
+	video_unregister_device(&dev->rx_vdev);
 	mutex_unlock(&dev->v4l2_lock);
 	mutex_unlock(&dev->vb_queue_lock);
 
@@ -606,6 +725,31 @@ static void hackrf_disconnect(struct usb_interface *intf)
 }
 
 /* Videobuf2 operations */
+static void hackrf_return_all_buffers(struct vb2_queue *vq,
+				      enum vb2_buffer_state state)
+{
+	struct hackrf_dev *dev = vb2_get_drv_priv(vq);
+	struct usb_interface *intf = dev->intf;
+	struct hackrf_buffer *buffer, *node;
+	struct list_head *buffer_list;
+	unsigned long flags;
+
+	dev_dbg(&intf->dev, "\n");
+
+	if (vq->type == V4L2_BUF_TYPE_SDR_CAPTURE)
+		buffer_list = &dev->rx_buffer_list;
+	else
+		buffer_list = &dev->tx_buffer_list;
+
+	spin_lock_irqsave(&dev->buffer_list_lock, flags);
+	list_for_each_entry_safe(buffer, node, buffer_list, list) {
+		dev_dbg(&intf->dev, "list_for_each_entry_safe\n");
+		vb2_buffer_done(&buffer->vb, state);
+		list_del(&buffer->list);
+	}
+	spin_unlock_irqrestore(&dev->buffer_list_lock, flags);
+}
+
 static int hackrf_queue_setup(struct vb2_queue *vq,
 		const struct v4l2_format *fmt, unsigned int *nbuffers,
 		unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
@@ -626,37 +770,62 @@ static int hackrf_queue_setup(struct vb2_queue *vq,
 
 static void hackrf_buf_queue(struct vb2_buffer *vb)
 {
-	struct hackrf_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
-	struct hackrf_frame_buf *buf =
-			container_of(vb, struct hackrf_frame_buf, vb);
+	struct vb2_queue *vq = vb->vb2_queue;
+	struct hackrf_dev *dev = vb2_get_drv_priv(vq);
+	struct usb_interface *intf = dev->intf;
+	struct hackrf_buffer *buffer = container_of(vb, struct hackrf_buffer, vb);
+	struct list_head *buffer_list;
 	unsigned long flags;
 
-	spin_lock_irqsave(&dev->queued_bufs_lock, flags);
-	list_add_tail(&buf->list, &dev->queued_bufs);
-	spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
+	dev_dbg_ratelimited(&intf->dev, "\n");
+
+	if (vq->type == V4L2_BUF_TYPE_SDR_CAPTURE)
+		buffer_list = &dev->rx_buffer_list;
+	else
+		buffer_list = &dev->tx_buffer_list;
+
+	spin_lock_irqsave(&dev->buffer_list_lock, flags);
+	list_add_tail(&buffer->list, buffer_list);
+	spin_unlock_irqrestore(&dev->buffer_list_lock, flags);
 }
 
 static int hackrf_start_streaming(struct vb2_queue *vq, unsigned int count)
 {
 	struct hackrf_dev *dev = vb2_get_drv_priv(vq);
+	struct usb_interface *intf = dev->intf;
 	int ret;
+	unsigned int mode;
 
-	dev_dbg(dev->dev, "\n");
-
-	if (!dev->udev)
-		return -ENODEV;
+	dev_dbg(&intf->dev, "count=%i\n", count);
 
 	mutex_lock(&dev->v4l2_lock);
 
-	dev->sequence = 0;
+	/* Allow only RX or TX, not both same time */
+	if (vq->type == V4L2_BUF_TYPE_SDR_CAPTURE) {
+		if (test_bit(TX_ON, &dev->flags)) {
+			ret = -EBUSY;
+			goto err_hackrf_return_all_buffers;
+		}
+
+		mode = 1;
+		set_bit(RX_ON, &dev->flags);
+	} else {
+		if (test_bit(RX_ON, &dev->flags)) {
+			ret = -EBUSY;
+			goto err_hackrf_return_all_buffers;
+		}
 
-	set_bit(POWER_ON, &dev->flags);
+		mode = 2;
+		set_bit(TX_ON, &dev->flags);
+	}
+
+	dev->sequence = 0;
 
 	ret = hackrf_alloc_stream_bufs(dev);
 	if (ret)
 		goto err;
 
-	ret = hackrf_alloc_urbs(dev);
+	ret = hackrf_alloc_urbs(dev, (mode == 1));
 	if (ret)
 		goto err;
 
@@ -669,38 +838,32 @@ static int hackrf_start_streaming(struct vb2_queue *vq, unsigned int count)
 		goto err;
 
 	/* start hardware streaming */
-	ret = hackrf_ctrl_msg(dev, CMD_SET_TRANSCEIVER_MODE, 1, 0, NULL, 0);
+	ret = hackrf_ctrl_msg(dev, CMD_SET_TRANSCEIVER_MODE, mode, 0, NULL, 0);
 	if (ret)
 		goto err;
 
-	goto exit_mutex_unlock;
+	mutex_unlock(&dev->v4l2_lock);
+
+	return 0;
 err:
 	hackrf_kill_urbs(dev);
 	hackrf_free_urbs(dev);
 	hackrf_free_stream_bufs(dev);
-	clear_bit(POWER_ON, &dev->flags);
-
-	/* return all queued buffers to vb2 */
-	{
-		struct hackrf_frame_buf *buf, *tmp;
-
-		list_for_each_entry_safe(buf, tmp, &dev->queued_bufs, list) {
-			list_del(&buf->list);
-			vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
-		}
-	}
-
-exit_mutex_unlock:
+	clear_bit(RX_ON, &dev->flags);
+	clear_bit(TX_ON, &dev->flags);
+err_hackrf_return_all_buffers:
+	hackrf_return_all_buffers(vq, VB2_BUF_STATE_QUEUED);
 	mutex_unlock(&dev->v4l2_lock);
-
+	dev_dbg(&intf->dev, "failed=%d\n", ret);
 	return ret;
 }
 
 static void hackrf_stop_streaming(struct vb2_queue *vq)
 {
 	struct hackrf_dev *dev = vb2_get_drv_priv(vq);
+	struct usb_interface *intf = dev->intf;
 
-	dev_dbg(dev->dev, "\n");
+	dev_dbg(&intf->dev, "\n");
 
 	mutex_lock(&dev->v4l2_lock);
 
@@ -711,9 +874,12 @@ static void hackrf_stop_streaming(struct vb2_queue *vq)
 	hackrf_free_urbs(dev);
 	hackrf_free_stream_bufs(dev);
 
-	hackrf_cleanup_queued_bufs(dev);
+	hackrf_return_all_buffers(vq, VB2_BUF_STATE_ERROR);
 
-	clear_bit(POWER_ON, &dev->flags);
+	if (vq->type == V4L2_BUF_TYPE_SDR_CAPTURE)
+		clear_bit(RX_ON, &dev->flags);
+	else
+		clear_bit(TX_ON, &dev->flags);
 
 	mutex_unlock(&dev->v4l2_lock);
 }
@@ -731,15 +897,26 @@ static int hackrf_querycap(struct file *file, void *fh,
 		struct v4l2_capability *cap)
 {
 	struct hackrf_dev *dev = video_drvdata(file);
+	struct usb_interface *intf = dev->intf;
+	struct video_device *vdev = video_devdata(file);
 
-	dev_dbg(dev->dev, "\n");
+	dev_dbg(&intf->dev, "\n");
+
+	if (vdev->vfl_dir == VFL_DIR_RX)
+		cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER |
+				   V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
 
+	else
+		cap->device_caps = V4L2_CAP_SDR_OUTPUT | V4L2_CAP_MODULATOR |
+				   V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+
+	cap->capabilities = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER |
+			    V4L2_CAP_SDR_OUTPUT | V4L2_CAP_MODULATOR |
+			    V4L2_CAP_STREAMING | V4L2_CAP_READWRITE |
+			    V4L2_CAP_DEVICE_CAPS;
 	strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
-	strlcpy(cap->card, dev->vdev.name, sizeof(cap->card));
+	strlcpy(cap->card, dev->rx_vdev.name, sizeof(cap->card));
 	usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
-	cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING |
-			V4L2_CAP_READWRITE | V4L2_CAP_TUNER;
-	cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
 
 	return 0;
 }
@@ -748,15 +925,11 @@ static int hackrf_s_fmt_sdr_cap(struct file *file, void *priv,
 		struct v4l2_format *f)
 {
 	struct hackrf_dev *dev = video_drvdata(file);
-	struct vb2_queue *q = &dev->vb_queue;
 	int i;
 
 	dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n",
 			(char *)&f->fmt.sdr.pixelformat);
 
-	if (vb2_is_busy(q))
-		return -EBUSY;
-
 	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
 	for (i = 0; i < NUM_FORMATS; i++) {
 		if (f->fmt.sdr.pixelformat == formats[i].pixelformat) {
@@ -856,17 +1029,64 @@ static int hackrf_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
 
 	if (v->index == 0) {
 		strlcpy(v->name, "HackRF ADC", sizeof(v->name));
-		v->type = V4L2_TUNER_ADC;
+		v->type = V4L2_TUNER_SDR;
 		v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
-		v->rangelow  = bands_adc[0].rangelow;
-		v->rangehigh = bands_adc[0].rangehigh;
+		v->rangelow  = bands_adc_dac[0].rangelow;
+		v->rangehigh = bands_adc_dac[0].rangehigh;
 		ret = 0;
 	} else if (v->index == 1) {
-		strlcpy(v->name, "HackRF RF", sizeof(v->name));
+		strlcpy(v->name, "HackRF RF RX", sizeof(v->name));
 		v->type = V4L2_TUNER_RF;
 		v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
-		v->rangelow  = bands_rf[0].rangelow;
-		v->rangehigh = bands_rf[0].rangehigh;
+		v->rangelow  = bands_rx_tx[0].rangelow;
+		v->rangehigh = bands_rx_tx[0].rangehigh;
+		ret = 0;
+	} else {
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
+static int hackrf_s_modulator(struct file *file, void *fh,
+		       const struct v4l2_modulator *a)
+{
+	struct hackrf_dev *dev = video_drvdata(file);
+	int ret;
+
+	dev_dbg(dev->dev, "index=%d\n", a->index);
+
+	if (a->index == 0)
+		ret = 0;
+	else if (a->index == 1)
+		ret = 0;
+	else
+		ret = -EINVAL;
+
+	return ret;
+}
+
+static int hackrf_g_modulator(struct file *file, void *fh,
+			      struct v4l2_modulator *a)
+{
+	struct hackrf_dev *dev = video_drvdata(file);
+	int ret;
+
+	dev_dbg(dev->dev, "index=%d\n", a->index);
+
+	if (a->index == 0) {
+		strlcpy(a->name, "HackRF DAC", sizeof(a->name));
+		a->type = V4L2_TUNER_SDR;
+		a->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+		a->rangelow  = bands_adc_dac[0].rangelow;
+		a->rangehigh = bands_adc_dac[0].rangehigh;
+		ret = 0;
+	} else if (a->index == 1) {
+		strlcpy(a->name, "HackRF RF TX", sizeof(a->name));
+		a->type = V4L2_TUNER_RF;
+		a->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+		a->rangelow  = bands_rx_tx[0].rangelow;
+		a->rangehigh = bands_rx_tx[0].rangehigh;
 		ret = 0;
 	} else {
 		ret = -EINVAL;
@@ -880,19 +1100,33 @@ static int hackrf_s_frequency(struct file *file, void *priv,
 {
 	struct hackrf_dev *dev = video_drvdata(file);
 	struct usb_interface *intf = dev->intf;
+	struct video_device *vdev = video_devdata(file);
 	int ret;
+	unsigned int uitmp;
 
 	dev_dbg(&intf->dev, "tuner=%d type=%d frequency=%u\n",
 			f->tuner, f->type, f->frequency);
 
 	if (f->tuner == 0) {
-		dev->f_adc = clamp_t(unsigned int, f->frequency,
-				bands_adc[0].rangelow, bands_adc[0].rangehigh);
-		set_bit(SAMPLE_RATE_SET, &dev->flags);
+		uitmp = clamp(f->frequency, bands_adc_dac[0].rangelow,
+			      bands_adc_dac[0].rangehigh);
+		if (vdev->vfl_dir == VFL_DIR_RX) {
+			dev->f_adc = uitmp;
+			set_bit(RX_ADC_FREQUENCY, &dev->flags);
+		} else {
+			dev->f_dac = uitmp;
+			set_bit(TX_DAC_FREQUENCY, &dev->flags);
+		}
 	} else if (f->tuner == 1) {
-		dev->f_rf = clamp_t(unsigned int, f->frequency,
-				bands_rf[0].rangelow, bands_rf[0].rangehigh);
-		set_bit(RX_RF_FREQUENCY, &dev->flags);
+		uitmp = clamp(f->frequency, bands_rx_tx[0].rangelow,
+			      bands_rx_tx[0].rangehigh);
+		if (vdev->vfl_dir == VFL_DIR_RX) {
+			dev->f_rx = uitmp;
+			set_bit(RX_RF_FREQUENCY, &dev->flags);
+		} else {
+			dev->f_tx = uitmp;
+			set_bit(TX_RF_FREQUENCY, &dev->flags);
+		}
 	} else {
 		ret = -EINVAL;
 		goto err;
@@ -912,22 +1146,32 @@ static int hackrf_g_frequency(struct file *file, void *priv,
 		struct v4l2_frequency *f)
 {
 	struct hackrf_dev *dev = video_drvdata(file);
+	struct usb_interface *intf = dev->intf;
+	struct video_device *vdev = video_devdata(file);
 	int ret;
 
 	dev_dbg(dev->dev, "tuner=%d type=%d\n", f->tuner, f->type);
 
 	if (f->tuner == 0) {
-		f->type = V4L2_TUNER_ADC;
-		f->frequency = dev->f_adc;
-		ret = 0;
+		f->type = V4L2_TUNER_SDR;
+		if (vdev->vfl_dir == VFL_DIR_RX)
+			f->frequency = dev->f_adc;
+		else
+			f->frequency = dev->f_dac;
 	} else if (f->tuner == 1) {
 		f->type = V4L2_TUNER_RF;
-		f->frequency = dev->f_rf;
-		ret = 0;
+		if (vdev->vfl_dir == VFL_DIR_RX)
+			f->frequency = dev->f_rx;
+		else
+			f->frequency = dev->f_tx;
 	} else {
 		ret = -EINVAL;
+		goto err;
 	}
 
+	return 0;
+err:
+	dev_dbg(&intf->dev, "failed=%d\n", ret);
 	return ret;
 }
 
@@ -941,17 +1185,17 @@ static int hackrf_enum_freq_bands(struct file *file, void *priv,
 			band->tuner, band->type, band->index);
 
 	if (band->tuner == 0) {
-		if (band->index >= ARRAY_SIZE(bands_adc)) {
+		if (band->index >= ARRAY_SIZE(bands_adc_dac)) {
 			ret = -EINVAL;
 		} else {
-			*band = bands_adc[band->index];
+			*band = bands_adc_dac[band->index];
 			ret = 0;
 		}
 	} else if (band->tuner == 1) {
-		if (band->index >= ARRAY_SIZE(bands_rf)) {
+		if (band->index >= ARRAY_SIZE(bands_rx_tx)) {
 			ret = -EINVAL;
 		} else {
-			*band = bands_rf[band->index];
+			*band = bands_rx_tx[band->index];
 			ret = 0;
 		}
 	} else {
@@ -969,6 +1213,11 @@ static const struct v4l2_ioctl_ops hackrf_ioctl_ops = {
 	.vidioc_enum_fmt_sdr_cap  = hackrf_enum_fmt_sdr_cap,
 	.vidioc_try_fmt_sdr_cap   = hackrf_try_fmt_sdr_cap,
 
+	.vidioc_s_fmt_sdr_out     = hackrf_s_fmt_sdr_cap,
+	.vidioc_g_fmt_sdr_out     = hackrf_g_fmt_sdr_cap,
+	.vidioc_enum_fmt_sdr_out  = hackrf_enum_fmt_sdr_cap,
+	.vidioc_try_fmt_sdr_out   = hackrf_try_fmt_sdr_cap,
+
 	.vidioc_reqbufs           = vb2_ioctl_reqbufs,
 	.vidioc_create_bufs       = vb2_ioctl_create_bufs,
 	.vidioc_prepare_buf       = vb2_ioctl_prepare_buf,
@@ -982,6 +1231,9 @@ static const struct v4l2_ioctl_ops hackrf_ioctl_ops = {
 	.vidioc_s_tuner           = hackrf_s_tuner,
 	.vidioc_g_tuner           = hackrf_g_tuner,
 
+	.vidioc_s_modulator       = hackrf_s_modulator,
+	.vidioc_g_modulator       = hackrf_g_modulator,
+
 	.vidioc_s_frequency       = hackrf_s_frequency,
 	.vidioc_g_frequency       = hackrf_g_frequency,
 	.vidioc_enum_freq_bands   = hackrf_enum_freq_bands,
@@ -996,6 +1248,7 @@ static const struct v4l2_file_operations hackrf_fops = {
 	.open                     = v4l2_fh_open,
 	.release                  = vb2_fop_release,
 	.read                     = vb2_fop_read,
+	.write                    = vb2_fop_write,
 	.poll                     = vb2_fop_poll,
 	.mmap                     = vb2_fop_mmap,
 	.unlocked_ioctl           = video_ioctl2,
@@ -1012,15 +1265,18 @@ static void hackrf_video_release(struct v4l2_device *v)
 {
 	struct hackrf_dev *dev = container_of(v, struct hackrf_dev, v4l2_dev);
 
-	v4l2_ctrl_handler_free(&dev->hdl);
+	dev_dbg(dev->dev, "\n");
+
+	v4l2_ctrl_handler_free(&dev->rx_ctrl_handler);
+	v4l2_ctrl_handler_free(&dev->tx_ctrl_handler);
 	v4l2_device_unregister(&dev->v4l2_dev);
 	kfree(dev);
 }
 
-static int hackrf_s_ctrl(struct v4l2_ctrl *ctrl)
+static int hackrf_s_ctrl_rx(struct v4l2_ctrl *ctrl)
 {
 	struct hackrf_dev *dev = container_of(ctrl->handler,
-			struct hackrf_dev, hdl);
+			struct hackrf_dev, rx_ctrl_handler);
 	struct usb_interface *intf = dev->intf;
 	int ret;
 
@@ -1055,8 +1311,47 @@ err:
 	return ret;
 }
 
-static const struct v4l2_ctrl_ops hackrf_ctrl_ops = {
-	.s_ctrl = hackrf_s_ctrl,
+static int hackrf_s_ctrl_tx(struct v4l2_ctrl *ctrl)
+{
+	struct hackrf_dev *dev = container_of(ctrl->handler,
+			struct hackrf_dev, tx_ctrl_handler);
+	struct usb_interface *intf = dev->intf;
+	int ret;
+
+	switch (ctrl->id) {
+	case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:
+	case V4L2_CID_RF_TUNER_BANDWIDTH:
+		set_bit(TX_BANDWIDTH, &dev->flags);
+		break;
+	case  V4L2_CID_RF_TUNER_LNA_GAIN:
+		set_bit(TX_LNA_GAIN, &dev->flags);
+		break;
+	case  V4L2_CID_RF_TUNER_RF_GAIN:
+		set_bit(TX_RF_GAIN, &dev->flags);
+		break;
+	default:
+		dev_dbg(&intf->dev, "unknown ctrl: id=%d name=%s\n",
+			ctrl->id, ctrl->name);
+		ret = -EINVAL;
+		goto err;
+	}
+
+	ret = hackrf_set_params(dev);
+	if (ret)
+		goto err;
+
+	return 0;
+err:
+	dev_dbg(&intf->dev, "failed=%d\n", ret);
+	return ret;
+}
+
+static const struct v4l2_ctrl_ops hackrf_ctrl_ops_rx = {
+	.s_ctrl = hackrf_s_ctrl_rx,
+};
+
+static const struct v4l2_ctrl_ops hackrf_ctrl_ops_tx = {
+	.s_ctrl = hackrf_s_ctrl_tx,
 };
 
 static int hackrf_probe(struct usb_interface *intf,
@@ -1067,20 +1362,29 @@ static int hackrf_probe(struct usb_interface *intf,
 	u8 u8tmp, buf[BUF_SIZE];
 
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-	if (dev == NULL)
-		return -ENOMEM;
+	if (!dev) {
+		ret = -ENOMEM;
+		goto err;
+	}
 
 	mutex_init(&dev->v4l2_lock);
 	mutex_init(&dev->vb_queue_lock);
-	spin_lock_init(&dev->queued_bufs_lock);
-	INIT_LIST_HEAD(&dev->queued_bufs);
+	spin_lock_init(&dev->buffer_list_lock);
+	INIT_LIST_HEAD(&dev->rx_buffer_list);
+	INIT_LIST_HEAD(&dev->tx_buffer_list);
 	dev->intf = intf;
 	dev->dev = &intf->dev;
 	dev->udev = interface_to_usbdev(intf);
-	dev->f_adc = bands_adc[0].rangelow;
-	dev->f_rf = bands_rf[0].rangelow;
 	dev->pixelformat = formats[0].pixelformat;
 	dev->buffersize = formats[0].buffersize;
+	dev->f_adc = bands_adc_dac[0].rangelow;
+	dev->f_dac = bands_adc_dac[0].rangelow;
+	dev->f_rx = bands_rx_tx[0].rangelow;
+	dev->f_tx = bands_rx_tx[0].rangelow;
+	set_bit(RX_ADC_FREQUENCY, &dev->flags);
+	set_bit(TX_DAC_FREQUENCY, &dev->flags);
+	set_bit(RX_RF_FREQUENCY, &dev->flags);
+	set_bit(TX_RF_FREQUENCY, &dev->flags);
 
 	/* Detect device */
 	ret = hackrf_ctrl_msg(dev, CMD_BOARD_ID_READ, 0, 0, &u8tmp, 1);
@@ -1089,85 +1393,141 @@ static int hackrf_probe(struct usb_interface *intf,
 				buf, BUF_SIZE);
 	if (ret) {
 		dev_err(dev->dev, "Could not detect board\n");
-		goto err_free_mem;
+		goto err_kfree;
 	}
 
 	buf[BUF_SIZE - 1] = '\0';
-
 	dev_info(dev->dev, "Board ID: %02x\n", u8tmp);
 	dev_info(dev->dev, "Firmware version: %s\n", buf);
 
-	/* Init videobuf2 queue structure */
-	dev->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
-	dev->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
-	dev->vb_queue.drv_priv = dev;
-	dev->vb_queue.buf_struct_size = sizeof(struct hackrf_frame_buf);
-	dev->vb_queue.ops = &hackrf_vb2_ops;
-	dev->vb_queue.mem_ops = &vb2_vmalloc_memops;
-	dev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
-	ret = vb2_queue_init(&dev->vb_queue);
+	/* Init vb2 queue structure for receiver */
+	dev->rx_vb2_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
+	dev->rx_vb2_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+	dev->rx_vb2_queue.ops = &hackrf_vb2_ops;
+	dev->rx_vb2_queue.mem_ops = &vb2_vmalloc_memops;
+	dev->rx_vb2_queue.drv_priv = dev;
+	dev->rx_vb2_queue.buf_struct_size = sizeof(struct hackrf_buffer);
+	dev->rx_vb2_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+	ret = vb2_queue_init(&dev->rx_vb2_queue);
+	if (ret) {
+		dev_err(dev->dev, "Could not initialize rx vb2 queue\n");
+		goto err_kfree;
+	}
+
+	/* Init vb2 queue structure for transmitter */
+	dev->tx_vb2_queue.type = V4L2_BUF_TYPE_SDR_OUTPUT;
+	dev->tx_vb2_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_WRITE;
+	dev->tx_vb2_queue.ops = &hackrf_vb2_ops;
+	dev->tx_vb2_queue.mem_ops = &vb2_vmalloc_memops;
+	dev->tx_vb2_queue.drv_priv = dev;
+	dev->tx_vb2_queue.buf_struct_size = sizeof(struct hackrf_buffer);
+	dev->tx_vb2_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+	ret = vb2_queue_init(&dev->tx_vb2_queue);
 	if (ret) {
-		dev_err(dev->dev, "Could not initialize vb2 queue\n");
-		goto err_free_mem;
+		dev_err(dev->dev, "Could not initialize tx vb2 queue\n");
+		goto err_kfree;
 	}
 
-	/* Init video_device structure */
-	dev->vdev = hackrf_template;
-	dev->vdev.queue = &dev->vb_queue;
-	dev->vdev.queue->lock = &dev->vb_queue_lock;
-	video_set_drvdata(&dev->vdev, dev);
+	/* Register controls for receiver */
+	v4l2_ctrl_handler_init(&dev->rx_ctrl_handler, 5);
+	dev->rx_bandwidth_auto = v4l2_ctrl_new_std(&dev->rx_ctrl_handler,
+		&hackrf_ctrl_ops_rx, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
+		0, 1, 0, 1);
+	dev->rx_bandwidth = v4l2_ctrl_new_std(&dev->rx_ctrl_handler,
+		&hackrf_ctrl_ops_rx, V4L2_CID_RF_TUNER_BANDWIDTH,
+		1750000, 28000000, 50000, 1750000);
+	v4l2_ctrl_auto_cluster(2, &dev->rx_bandwidth_auto, 0, false);
+	dev->rx_rf_gain = v4l2_ctrl_new_std(&dev->rx_ctrl_handler,
+		&hackrf_ctrl_ops_rx, V4L2_CID_RF_TUNER_RF_GAIN, 0, 12, 12, 0);
+	dev->rx_lna_gain = v4l2_ctrl_new_std(&dev->rx_ctrl_handler,
+		&hackrf_ctrl_ops_rx, V4L2_CID_RF_TUNER_LNA_GAIN, 0, 40, 8, 0);
+	dev->rx_if_gain = v4l2_ctrl_new_std(&dev->rx_ctrl_handler,
+		&hackrf_ctrl_ops_rx, V4L2_CID_RF_TUNER_IF_GAIN, 0, 62, 2, 0);
+	if (dev->rx_ctrl_handler.error) {
+		ret = dev->rx_ctrl_handler.error;
+		dev_err(dev->dev, "Could not initialize controls\n");
+		goto err_v4l2_ctrl_handler_free_rx;
+	}
+	v4l2_ctrl_handler_setup(&dev->rx_ctrl_handler);
+
+	/* Register controls for transmitter */
+	v4l2_ctrl_handler_init(&dev->tx_ctrl_handler, 4);
+	dev->tx_bandwidth_auto = v4l2_ctrl_new_std(&dev->tx_ctrl_handler,
+		&hackrf_ctrl_ops_tx, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
+		0, 1, 0, 1);
+	dev->tx_bandwidth = v4l2_ctrl_new_std(&dev->tx_ctrl_handler,
+		&hackrf_ctrl_ops_tx, V4L2_CID_RF_TUNER_BANDWIDTH,
+		1750000, 28000000, 50000, 1750000);
+	v4l2_ctrl_auto_cluster(2, &dev->tx_bandwidth_auto, 0, false);
+	dev->tx_lna_gain = v4l2_ctrl_new_std(&dev->tx_ctrl_handler,
+		&hackrf_ctrl_ops_tx, V4L2_CID_RF_TUNER_LNA_GAIN, 0, 47, 1, 0);
+	dev->tx_rf_gain = v4l2_ctrl_new_std(&dev->tx_ctrl_handler,
+		&hackrf_ctrl_ops_tx, V4L2_CID_RF_TUNER_RF_GAIN, 0, 15, 15, 0);
+	if (dev->tx_ctrl_handler.error) {
+		ret = dev->tx_ctrl_handler.error;
+		dev_err(dev->dev, "Could not initialize controls\n");
+		goto err_v4l2_ctrl_handler_free_tx;
+	}
+	v4l2_ctrl_handler_setup(&dev->tx_ctrl_handler);
 
 	/* Register the v4l2_device structure */
 	dev->v4l2_dev.release = hackrf_video_release;
 	ret = v4l2_device_register(&intf->dev, &dev->v4l2_dev);
 	if (ret) {
 		dev_err(dev->dev, "Failed to register v4l2-device (%d)\n", ret);
-		goto err_free_mem;
+		goto err_v4l2_ctrl_handler_free_tx;
 	}
 
-	/* Register controls */
-	v4l2_ctrl_handler_init(&dev->hdl, 5);
-	dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
-			V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
-	dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
-			V4L2_CID_RF_TUNER_BANDWIDTH,
-			1750000, 28000000, 50000, 1750000);
-	v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false);
-	dev->rf_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
-			V4L2_CID_RF_TUNER_RF_GAIN, 0, 12, 12, 0);
-	dev->lna_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
-			V4L2_CID_RF_TUNER_LNA_GAIN, 0, 40, 8, 0);
-	dev->if_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
-			V4L2_CID_RF_TUNER_IF_GAIN, 0, 62, 2, 0);
-	if (dev->hdl.error) {
-		ret = dev->hdl.error;
-		dev_err(dev->dev, "Could not initialize controls\n");
-		goto err_free_controls;
+	/* Init video_device structure for receiver */
+	dev->rx_vdev = hackrf_template;
+	dev->rx_vdev.queue = &dev->rx_vb2_queue;
+	dev->rx_vdev.queue->lock = &dev->vb_queue_lock;
+	dev->rx_vdev.v4l2_dev = &dev->v4l2_dev;
+	dev->rx_vdev.ctrl_handler = &dev->rx_ctrl_handler;
+	dev->rx_vdev.lock = &dev->v4l2_lock;
+	dev->rx_vdev.vfl_dir = VFL_DIR_RX;
+	video_set_drvdata(&dev->rx_vdev, dev);
+	ret = video_register_device(&dev->rx_vdev, VFL_TYPE_SDR, -1);
+	if (ret) {
+		dev_err(dev->dev,
+			"Failed to register as video device (%d)\n", ret);
+		goto err_v4l2_device_unregister;
 	}
-
-	v4l2_ctrl_handler_setup(&dev->hdl);
-
-	dev->v4l2_dev.ctrl_handler = &dev->hdl;
-	dev->vdev.v4l2_dev = &dev->v4l2_dev;
-	dev->vdev.lock = &dev->v4l2_lock;
-
-	ret = video_register_device(&dev->vdev, VFL_TYPE_SDR, -1);
+	dev_info(dev->dev, "Registered as %s\n",
+		 video_device_node_name(&dev->rx_vdev));
+
+	/* Init video_device structure for transmitter */
+	dev->tx_vdev = hackrf_template;
+	dev->tx_vdev.queue = &dev->tx_vb2_queue;
+	dev->tx_vdev.queue->lock = &dev->vb_queue_lock;
+	dev->tx_vdev.v4l2_dev = &dev->v4l2_dev;
+	dev->tx_vdev.ctrl_handler = &dev->tx_ctrl_handler;
+	dev->tx_vdev.lock = &dev->v4l2_lock;
+	dev->tx_vdev.vfl_dir = VFL_DIR_TX;
+	video_set_drvdata(&dev->tx_vdev, dev);
+	ret = video_register_device(&dev->tx_vdev, VFL_TYPE_SDR, -1);
 	if (ret) {
-		dev_err(dev->dev, "Failed to register as video device (%d)\n",
-				ret);
-		goto err_unregister_v4l2_dev;
+		dev_err(dev->dev,
+			"Failed to register as video device (%d)\n", ret);
+		goto err_video_unregister_device_rx;
 	}
 	dev_info(dev->dev, "Registered as %s\n",
-			video_device_node_name(&dev->vdev));
+		 video_device_node_name(&dev->tx_vdev));
+
 	dev_notice(dev->dev, "SDR API is still slightly experimental and functionality changes may follow\n");
 	return 0;
-
-err_free_controls:
-	v4l2_ctrl_handler_free(&dev->hdl);
-err_unregister_v4l2_dev:
+err_video_unregister_device_rx:
+	video_unregister_device(&dev->rx_vdev);
+err_v4l2_device_unregister:
 	v4l2_device_unregister(&dev->v4l2_dev);
-err_free_mem:
+err_v4l2_ctrl_handler_free_tx:
+	v4l2_ctrl_handler_free(&dev->tx_ctrl_handler);
+err_v4l2_ctrl_handler_free_rx:
+	v4l2_ctrl_handler_free(&dev->rx_ctrl_handler);
+err_kfree:
 	kfree(dev);
+err:
+	dev_dbg(dev->dev, "failed=%d\n", ret);
 	return ret;
 }
 
-- 
http://palosaari.fi/


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

* [PATCHv3 11/13] hackrf: do not set human readable name for formats
  2015-07-31  2:10 [PATCHv3 00/13] SDR transmitter API Antti Palosaari
                   ` (9 preceding siblings ...)
  2015-07-31  2:10 ` [PATCHv3 10/13] hackrf: add support for transmitter Antti Palosaari
@ 2015-07-31  2:10 ` Antti Palosaari
  2015-07-31  2:10 ` [PATCHv3 12/13] DocBook: fix S_FREQUENCY => G_FREQUENCY Antti Palosaari
  2015-07-31  2:10 ` [PATCHv3 13/13] DocBook: add tuner types SDR and RF for G_TUNER / S_TUNER Antti Palosaari
  12 siblings, 0 replies; 24+ messages in thread
From: Antti Palosaari @ 2015-07-31  2:10 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Antti Palosaari

Format names are set by core nowadays. Remove name from driver.

Signed-off-by: Antti Palosaari <crope@iki.fi>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/usb/hackrf/hackrf.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c
index f4b5606..475eb22 100644
--- a/drivers/media/usb/hackrf/hackrf.c
+++ b/drivers/media/usb/hackrf/hackrf.c
@@ -69,7 +69,6 @@ static const struct v4l2_frequency_band bands_rx_tx[] = {
 
 /* stream formats */
 struct hackrf_format {
-	char	*name;
 	u32	pixelformat;
 	u32	buffersize;
 };
@@ -77,7 +76,6 @@ struct hackrf_format {
 /* format descriptions for capture and preview */
 static struct hackrf_format formats[] = {
 	{
-		.name		= "Complex S8",
 		.pixelformat	= V4L2_SDR_FMT_CS8,
 		.buffersize	= BULK_BUFFER_SIZE,
 	},
@@ -996,7 +994,6 @@ static int hackrf_enum_fmt_sdr_cap(struct file *file, void *priv,
 	if (f->index >= NUM_FORMATS)
 		return -EINVAL;
 
-	strlcpy(f->description, formats[f->index].name, sizeof(f->description));
 	f->pixelformat = formats[f->index].pixelformat;
 
 	return 0;
-- 
http://palosaari.fi/


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

* [PATCHv3 12/13] DocBook: fix S_FREQUENCY => G_FREQUENCY
  2015-07-31  2:10 [PATCHv3 00/13] SDR transmitter API Antti Palosaari
                   ` (10 preceding siblings ...)
  2015-07-31  2:10 ` [PATCHv3 11/13] hackrf: do not set human readable name for formats Antti Palosaari
@ 2015-07-31  2:10 ` Antti Palosaari
  2015-08-10  9:41   ` Hans Verkuil
  2015-07-31  2:10 ` [PATCHv3 13/13] DocBook: add tuner types SDR and RF for G_TUNER / S_TUNER Antti Palosaari
  12 siblings, 1 reply; 24+ messages in thread
From: Antti Palosaari @ 2015-07-31  2:10 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Antti Palosaari

It is VIDIOC_G_FREQUENCY which does not use type to identify tuner,
not VIDIOC_S_FREQUENCY. VIDIOC_S_FREQUENCY uses both tuner and type
fields. One of these V4L API weirdness...

Cc: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
 Documentation/DocBook/media/v4l/common.xml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/DocBook/media/v4l/common.xml b/Documentation/DocBook/media/v4l/common.xml
index 8b5e014..f7008ea 100644
--- a/Documentation/DocBook/media/v4l/common.xml
+++ b/Documentation/DocBook/media/v4l/common.xml
@@ -428,7 +428,7 @@ zero, no video outputs.</para>
 modulator. Two separate device nodes will have to be used for such
 hardware, one that supports the tuner functionality and one that supports
 the modulator functionality. The reason is a limitation with the
-&VIDIOC-S-FREQUENCY; ioctl where you cannot specify whether the frequency
+&VIDIOC-G-FREQUENCY; ioctl where you cannot specify whether the frequency
 is for a tuner or a modulator.</para>
 
       <para>To query and change modulator properties applications use
-- 
http://palosaari.fi/


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

* [PATCHv3 13/13] DocBook: add tuner types SDR and RF for G_TUNER / S_TUNER
  2015-07-31  2:10 [PATCHv3 00/13] SDR transmitter API Antti Palosaari
                   ` (11 preceding siblings ...)
  2015-07-31  2:10 ` [PATCHv3 12/13] DocBook: fix S_FREQUENCY => G_FREQUENCY Antti Palosaari
@ 2015-07-31  2:10 ` Antti Palosaari
  2015-08-10  9:43   ` Hans Verkuil
  12 siblings, 1 reply; 24+ messages in thread
From: Antti Palosaari @ 2015-07-31  2:10 UTC (permalink / raw)
  To: linux-media; +Cc: Hans Verkuil, Antti Palosaari

Add V4L2_TUNER_SDR and V4L2_TUNER_RF to supported tuner types to
table.

Cc: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
 Documentation/DocBook/media/v4l/vidioc-g-tuner.xml | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
index b0d8659..10737a1 100644
--- a/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
@@ -261,6 +261,16 @@ applications must set the array to zero.</entry>
 	    <entry>2</entry>
 	    <entry></entry>
 	  </row>
+	  <row>
+	    <entry><constant>V4L2_TUNER_SDR</constant></entry>
+	    <entry>4</entry>
+	    <entry></entry>
+	  </row>
+	  <row>
+	    <entry><constant>V4L2_TUNER_RF</constant></entry>
+	    <entry>5</entry>
+	    <entry></entry>
+	  </row>
 	</tbody>
       </tgroup>
     </table>
-- 
http://palosaari.fi/


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

* Re: [PATCHv3 02/13] v4l2: add RF gain control
  2015-07-31  2:10 ` [PATCHv3 02/13] v4l2: add RF gain control Antti Palosaari
@ 2015-08-10  8:56   ` Hans Verkuil
  0 siblings, 0 replies; 24+ messages in thread
From: Hans Verkuil @ 2015-08-10  8:56 UTC (permalink / raw)
  To: Antti Palosaari, linux-media

On 07/31/2015 04:10 AM, Antti Palosaari wrote:
> Add new RF tuner gain control named RF Gain. That is aimed for first
> amplifier chip right after antenna connector.
> There is existing LNA Gain control, which is quite same, but it is
> aimed for cases amplifier is integrated to tuner chip. Some designs
> have both, as almost all recent tuner silicons has integrated LNA/RF
> amplifier in any case.
> 
> Cc: Hans Verkuil <hverkuil@xs4all.nl>

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

> Signed-off-by: Antti Palosaari <crope@iki.fi>
> ---
>  drivers/media/v4l2-core/v4l2-ctrls.c | 2 ++
>  include/uapi/linux/v4l2-controls.h   | 1 +
>  2 files changed, 3 insertions(+)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
> index b6b7dcc..d18462c 100644
> --- a/drivers/media/v4l2-core/v4l2-ctrls.c
> +++ b/drivers/media/v4l2-core/v4l2-ctrls.c
> @@ -888,6 +888,7 @@ const char *v4l2_ctrl_get_name(u32 id)
>  	case V4L2_CID_TUNE_DEEMPHASIS:		return "De-Emphasis";
>  	case V4L2_CID_RDS_RECEPTION:		return "RDS Reception";
>  	case V4L2_CID_RF_TUNER_CLASS:		return "RF Tuner Controls";
> +	case V4L2_CID_RF_TUNER_RF_GAIN:		return "RF Gain";
>  	case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO:	return "LNA Gain, Auto";
>  	case V4L2_CID_RF_TUNER_LNA_GAIN:	return "LNA Gain";
>  	case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO:	return "Mixer Gain, Auto";
> @@ -1161,6 +1162,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
>  	case V4L2_CID_PILOT_TONE_FREQUENCY:
>  	case V4L2_CID_TUNE_POWER_LEVEL:
>  	case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
> +	case V4L2_CID_RF_TUNER_RF_GAIN:
>  	case V4L2_CID_RF_TUNER_LNA_GAIN:
>  	case V4L2_CID_RF_TUNER_MIXER_GAIN:
>  	case V4L2_CID_RF_TUNER_IF_GAIN:
> diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
> index d448c53..1bdce50 100644
> --- a/include/uapi/linux/v4l2-controls.h
> +++ b/include/uapi/linux/v4l2-controls.h
> @@ -936,6 +936,7 @@ enum v4l2_deemphasis {
>  
>  #define V4L2_CID_RF_TUNER_BANDWIDTH_AUTO	(V4L2_CID_RF_TUNER_CLASS_BASE + 11)
>  #define V4L2_CID_RF_TUNER_BANDWIDTH		(V4L2_CID_RF_TUNER_CLASS_BASE + 12)
> +#define V4L2_CID_RF_TUNER_RF_GAIN		(V4L2_CID_RF_TUNER_CLASS_BASE + 32)
>  #define V4L2_CID_RF_TUNER_LNA_GAIN_AUTO		(V4L2_CID_RF_TUNER_CLASS_BASE + 41)
>  #define V4L2_CID_RF_TUNER_LNA_GAIN		(V4L2_CID_RF_TUNER_CLASS_BASE + 42)
>  #define V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO	(V4L2_CID_RF_TUNER_CLASS_BASE + 51)
> 


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

* Re: [PATCHv3 03/13] DocBook: document tuner RF gain control
  2015-07-31  2:10 ` [PATCHv3 03/13] DocBook: document tuner " Antti Palosaari
@ 2015-08-10  8:57   ` Hans Verkuil
  0 siblings, 0 replies; 24+ messages in thread
From: Hans Verkuil @ 2015-08-10  8:57 UTC (permalink / raw)
  To: Antti Palosaari, linux-media

On 07/31/2015 04:10 AM, Antti Palosaari wrote:
> Add brief description for tuner RF gain control.
> 
> Cc: Hans Verkuil <hverkuil@xs4all.nl>

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

> Signed-off-by: Antti Palosaari <crope@iki.fi>
> ---
>  Documentation/DocBook/media/v4l/compat.xml   |  4 ++++
>  Documentation/DocBook/media/v4l/controls.xml | 14 ++++++++++++++
>  Documentation/DocBook/media/v4l/v4l2.xml     |  1 +
>  3 files changed, 19 insertions(+)
> 
> diff --git a/Documentation/DocBook/media/v4l/compat.xml b/Documentation/DocBook/media/v4l/compat.xml
> index f56faf5..eb091c7 100644
> --- a/Documentation/DocBook/media/v4l/compat.xml
> +++ b/Documentation/DocBook/media/v4l/compat.xml
> @@ -2600,6 +2600,10 @@ and &v4l2-mbus-framefmt;.
>  <constant>V4L2_TUNER_ADC</constant> is deprecated now.
>  	  </para>
>  	</listitem>
> +	<listitem>
> +	  <para>Added <constant>V4L2_CID_RF_TUNER_RF_GAIN</constant>
> +RF Tuner control.</para>
> +	</listitem>
>        </orderedlist>
>      </section>
>  
> diff --git a/Documentation/DocBook/media/v4l/controls.xml b/Documentation/DocBook/media/v4l/controls.xml
> index 6e1667b..7cae933 100644
> --- a/Documentation/DocBook/media/v4l/controls.xml
> +++ b/Documentation/DocBook/media/v4l/controls.xml
> @@ -5418,6 +5418,18 @@ set. Unit is in Hz. The range and step are driver-specific.</entry>
>                <entry spanname="descr">Enables/disables IF automatic gain control (AGC)</entry>
>              </row>
>              <row>
> +              <entry spanname="id"><constant>V4L2_CID_RF_TUNER_RF_GAIN</constant>&nbsp;</entry>
> +              <entry>integer</entry>
> +            </row>
> +            <row>
> +              <entry spanname="descr">The RF amplifier is the very first
> +amplifier on the receiver signal path, just right after the antenna input.
> +The difference between the LNA gain and the RF gain in this document is that
> +the LNA gain is integrated in the tuner chip while the RF gain is a separate
> +chip. There may be both RF and LNA gain controls in the same device.
> +The range and step are driver-specific.</entry>
> +            </row>
> +            <row>
>                <entry spanname="id"><constant>V4L2_CID_RF_TUNER_LNA_GAIN</constant>&nbsp;</entry>
>                <entry>integer</entry>
>              </row>
> @@ -5425,6 +5437,8 @@ set. Unit is in Hz. The range and step are driver-specific.</entry>
>                <entry spanname="descr">LNA (low noise amplifier) gain is first
>  gain stage on the RF tuner signal path. It is located very close to tuner
>  antenna input. Used when <constant>V4L2_CID_RF_TUNER_LNA_GAIN_AUTO</constant> is not set.
> +See <constant>V4L2_CID_RF_TUNER_RF_GAIN</constant> to understand how RF gain
> +and LNA gain differs from the each others.
>  The range and step are driver-specific.</entry>
>              </row>
>              <row>
> diff --git a/Documentation/DocBook/media/v4l/v4l2.xml b/Documentation/DocBook/media/v4l/v4l2.xml
> index c9eedc1..ab9fca4 100644
> --- a/Documentation/DocBook/media/v4l/v4l2.xml
> +++ b/Documentation/DocBook/media/v4l/v4l2.xml
> @@ -156,6 +156,7 @@ applications. -->
>  	<date>2015-05-26</date>
>  	<authorinitials>ap</authorinitials>
>  	<revremark>Renamed V4L2_TUNER_ADC to V4L2_TUNER_SDR.
> +Added V4L2_CID_RF_TUNER_RF_GAIN control.
>  	</revremark>
>        </revision>
>  
> 


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

* Re: [PATCHv3 06/13] v4l: add type field to v4l2_modulator struct
  2015-07-31  2:10 ` [PATCHv3 06/13] v4l: add type field to v4l2_modulator struct Antti Palosaari
@ 2015-08-10  9:01   ` Hans Verkuil
  0 siblings, 0 replies; 24+ messages in thread
From: Hans Verkuil @ 2015-08-10  9:01 UTC (permalink / raw)
  To: Antti Palosaari, linux-media

On 07/31/2015 04:10 AM, Antti Palosaari wrote:
> Add type field to that struct like it counterpart v4l2_tuner
> already has. We need type field to distinguish different tuner
> types from each others for transmitter too.
> 
> Cc: Hans Verkuil <hverkuil@xs4all.nl>
> Signed-off-by: Antti Palosaari <crope@iki.fi>

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

> ---
>  drivers/media/v4l2-core/v4l2-ioctl.c | 18 +++++++++++++++++-
>  include/uapi/linux/videodev2.h       |  3 ++-
>  2 files changed, 19 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
> index 21e9598..85f80cb 100644
> --- a/drivers/media/v4l2-core/v4l2-ioctl.c
> +++ b/drivers/media/v4l2-core/v4l2-ioctl.c
> @@ -1646,15 +1646,31 @@ static int v4l_s_tuner(const struct v4l2_ioctl_ops *ops,
>  static int v4l_g_modulator(const struct v4l2_ioctl_ops *ops,
>  				struct file *file, void *fh, void *arg)
>  {
> +	struct video_device *vfd = video_devdata(file);
>  	struct v4l2_modulator *p = arg;
>  	int err;
>  
> +	if (vfd->vfl_type == VFL_TYPE_RADIO)
> +		p->type = V4L2_TUNER_RADIO;
> +
>  	err = ops->vidioc_g_modulator(file, fh, p);
>  	if (!err)
>  		p->capability |= V4L2_TUNER_CAP_FREQ_BANDS;
>  	return err;
>  }
>  
> +static int v4l_s_modulator(const struct v4l2_ioctl_ops *ops,
> +				struct file *file, void *fh, void *arg)
> +{
> +	struct video_device *vfd = video_devdata(file);
> +	struct v4l2_modulator *p = arg;
> +
> +	if (vfd->vfl_type == VFL_TYPE_RADIO)
> +		p->type = V4L2_TUNER_RADIO;
> +
> +	return ops->vidioc_s_modulator(file, fh, p);
> +}
> +
>  static int v4l_g_frequency(const struct v4l2_ioctl_ops *ops,
>  				struct file *file, void *fh, void *arg)
>  {
> @@ -2441,7 +2457,7 @@ static struct v4l2_ioctl_info v4l2_ioctls[] = {
>  	IOCTL_INFO_STD(VIDIOC_G_AUDOUT, vidioc_g_audout, v4l_print_audioout, 0),
>  	IOCTL_INFO_STD(VIDIOC_S_AUDOUT, vidioc_s_audout, v4l_print_audioout, INFO_FL_PRIO),
>  	IOCTL_INFO_FNC(VIDIOC_G_MODULATOR, v4l_g_modulator, v4l_print_modulator, INFO_FL_CLEAR(v4l2_modulator, index)),
> -	IOCTL_INFO_STD(VIDIOC_S_MODULATOR, vidioc_s_modulator, v4l_print_modulator, INFO_FL_PRIO),
> +	IOCTL_INFO_FNC(VIDIOC_S_MODULATOR, v4l_s_modulator, v4l_print_modulator, INFO_FL_PRIO),
>  	IOCTL_INFO_FNC(VIDIOC_G_FREQUENCY, v4l_g_frequency, v4l_print_frequency, INFO_FL_CLEAR(v4l2_frequency, tuner)),
>  	IOCTL_INFO_FNC(VIDIOC_S_FREQUENCY, v4l_s_frequency, v4l_print_frequency, INFO_FL_PRIO),
>  	IOCTL_INFO_FNC(VIDIOC_CROPCAP, v4l_cropcap, v4l_print_cropcap, INFO_FL_CLEAR(v4l2_cropcap, type)),
> diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
> index 70f06c9..3a8eb8e 100644
> --- a/include/uapi/linux/videodev2.h
> +++ b/include/uapi/linux/videodev2.h
> @@ -1584,7 +1584,8 @@ struct v4l2_modulator {
>  	__u32			rangelow;
>  	__u32			rangehigh;
>  	__u32			txsubchans;
> -	__u32			reserved[4];
> +	__u32			type;	/* enum v4l2_tuner_type */
> +	__u32			reserved[3];
>  };
>  
>  /*  Flags for the 'capability' field */
> 


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

* Re: [PATCHv3 07/13] DocBook: add modulator type field
  2015-07-31  2:10 ` [PATCHv3 07/13] DocBook: add modulator type field Antti Palosaari
@ 2015-08-10  9:02   ` Hans Verkuil
  0 siblings, 0 replies; 24+ messages in thread
From: Hans Verkuil @ 2015-08-10  9:02 UTC (permalink / raw)
  To: Antti Palosaari, linux-media

On 07/31/2015 04:10 AM, Antti Palosaari wrote:
> Add new modulator type field to documentation.
> 
> Cc: Hans Verkuil <hverkuil@xs4all.nl>
> Signed-off-by: Antti Palosaari <crope@iki.fi>
> ---
>  Documentation/DocBook/media/v4l/vidioc-g-modulator.xml | 8 +++++++-
>  1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml b/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml
> index 7068b59..fe4230c 100644
> --- a/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml
> +++ b/Documentation/DocBook/media/v4l/vidioc-g-modulator.xml
> @@ -140,7 +140,13 @@ indicator, for example a stereo pilot tone.</entry>
>  	  </row>
>  	  <row>
>  	    <entry>__u32</entry>
> -	    <entry><structfield>reserved</structfield>[4]</entry>
> +	    <entry><structfield>type</structfield></entry>
> +	    <entry spanname="hspan">Type of the tuner, see <xref

s/tuner/modulator/

Regards,

	Hans

> +		linkend="v4l2-tuner-type" />.</entry>
> +	  </row>
> +	  <row>
> +	    <entry>__u32</entry>
> +	    <entry><structfield>reserved</structfield>[3]</entry>
>  	    <entry>Reserved for future extensions. Drivers and
>  applications must set the array to zero.</entry>
>  	  </row>
> 


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

* Re: [PATCHv3 08/13] hackrf: add control for RF amplifier
  2015-07-31  2:10 ` [PATCHv3 08/13] hackrf: add control for RF amplifier Antti Palosaari
@ 2015-08-10  9:03   ` Hans Verkuil
  0 siblings, 0 replies; 24+ messages in thread
From: Hans Verkuil @ 2015-08-10  9:03 UTC (permalink / raw)
  To: Antti Palosaari, linux-media

On 07/31/2015 04:10 AM, Antti Palosaari wrote:
> There is Avago MGA-81563 amplifier just right after antenna connector.
> It could be turned on/off and its gain is around 12dB.
> 
> Signed-off-by: Antti Palosaari <crope@iki.fi>

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

> ---
>  drivers/media/usb/hackrf/hackrf.c | 26 +++++++++++++++++++++++++-
>  1 file changed, 25 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c
> index fd1fa41..136de9a 100644
> --- a/drivers/media/usb/hackrf/hackrf.c
> +++ b/drivers/media/usb/hackrf/hackrf.c
> @@ -31,6 +31,7 @@ enum {
>  	CMD_BOARD_ID_READ                  = 0x0e,
>  	CMD_VERSION_STRING_READ            = 0x0f,
>  	CMD_SET_FREQ                       = 0x10,
> +	CMD_AMP_ENABLE                     = 0x11,
>  	CMD_SET_LNA_GAIN                   = 0x13,
>  	CMD_SET_VGA_GAIN                   = 0x14,
>  };
> @@ -133,6 +134,7 @@ struct hackrf_dev {
>  	struct v4l2_ctrl_handler hdl;
>  	struct v4l2_ctrl *bandwidth_auto;
>  	struct v4l2_ctrl *bandwidth;
> +	struct v4l2_ctrl *rf_gain;
>  	struct v4l2_ctrl *lna_gain;
>  	struct v4l2_ctrl *if_gain;
>  
> @@ -164,6 +166,7 @@ static int hackrf_ctrl_msg(struct hackrf_dev *dev, u8 request, u16 value,
>  	switch (request) {
>  	case CMD_SET_TRANSCEIVER_MODE:
>  	case CMD_SET_FREQ:
> +	case CMD_AMP_ENABLE:
>  	case CMD_SAMPLE_RATE_SET:
>  	case CMD_BASEBAND_FILTER_BANDWIDTH_SET:
>  		pipe = usb_sndctrlpipe(dev->udev, 0);
> @@ -949,6 +952,22 @@ static int hackrf_set_bandwidth(struct hackrf_dev *dev)
>  	return ret;
>  }
>  
> +static int hackrf_set_rf_gain(struct hackrf_dev *dev)
> +{
> +	int ret;
> +	u8 u8tmp;
> +
> +	dev_dbg(dev->dev, "rf val=%d->%d\n",
> +		dev->rf_gain->cur.val, dev->rf_gain->val);
> +
> +	u8tmp = (dev->rf_gain->val) ? 1 : 0;
> +	ret = hackrf_ctrl_msg(dev, CMD_AMP_ENABLE, u8tmp, 0, NULL, 0);
> +	if (ret)
> +		dev_dbg(dev->dev, "failed=%d\n", ret);
> +
> +	return ret;
> +}
> +
>  static int hackrf_set_lna_gain(struct hackrf_dev *dev)
>  {
>  	int ret;
> @@ -992,6 +1011,9 @@ static int hackrf_s_ctrl(struct v4l2_ctrl *ctrl)
>  	case V4L2_CID_RF_TUNER_BANDWIDTH:
>  		ret = hackrf_set_bandwidth(dev);
>  		break;
> +	case  V4L2_CID_RF_TUNER_RF_GAIN:
> +		ret = hackrf_set_rf_gain(dev);
> +		break;
>  	case  V4L2_CID_RF_TUNER_LNA_GAIN:
>  		ret = hackrf_set_lna_gain(dev);
>  		break;
> @@ -1077,13 +1099,15 @@ static int hackrf_probe(struct usb_interface *intf,
>  	}
>  
>  	/* Register controls */
> -	v4l2_ctrl_handler_init(&dev->hdl, 4);
> +	v4l2_ctrl_handler_init(&dev->hdl, 5);
>  	dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
>  			V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
>  	dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
>  			V4L2_CID_RF_TUNER_BANDWIDTH,
>  			1750000, 28000000, 50000, 1750000);
>  	v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false);
> +	dev->rf_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
> +			V4L2_CID_RF_TUNER_RF_GAIN, 0, 12, 12, 0);
>  	dev->lna_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
>  			V4L2_CID_RF_TUNER_LNA_GAIN, 0, 40, 8, 0);
>  	dev->if_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
> 


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

* Re: [PATCHv3 09/13] hackrf: switch to single function which configures everything
  2015-07-31  2:10 ` [PATCHv3 09/13] hackrf: switch to single function which configures everything Antti Palosaari
@ 2015-08-10  9:04   ` Hans Verkuil
  0 siblings, 0 replies; 24+ messages in thread
From: Hans Verkuil @ 2015-08-10  9:04 UTC (permalink / raw)
  To: Antti Palosaari, linux-media

On 07/31/2015 04:10 AM, Antti Palosaari wrote:
> Implement single funtion, hackrf_set_params(), which handles all
> needed settings. Controls and other IOCTLs are just wrappers to that
> function. That way we can get easily better control what we could do
> on different device states - sleeping, receiving, transmitting.
> 
> Signed-off-by: Antti Palosaari <crope@iki.fi>

Acked-by: Hans Verkuil <hans.verkuil@cisco.com>


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

* Re: [PATCHv3 10/13] hackrf: add support for transmitter
  2015-07-31  2:10 ` [PATCHv3 10/13] hackrf: add support for transmitter Antti Palosaari
@ 2015-08-10  9:34   ` Hans Verkuil
  0 siblings, 0 replies; 24+ messages in thread
From: Hans Verkuil @ 2015-08-10  9:34 UTC (permalink / raw)
  To: Antti Palosaari, linux-media

Some comments below:

On 07/31/2015 04:10 AM, Antti Palosaari wrote:
> HackRF SDR device has both receiver and transmitter. There is limitation
> that receiver and transmitter cannot be used at the same time
> (half-duplex operation). That patch implements transmitter support to
> existing receiver only driver.
> 
> Cc: Hans Verkuil <hverkuil@xs4all.nl>
> Signed-off-by: Antti Palosaari <crope@iki.fi>
> ---
>  drivers/media/usb/hackrf/hackrf.c | 894 ++++++++++++++++++++++++++------------
>  1 file changed, 627 insertions(+), 267 deletions(-)
> 
> diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c
> index 5bd291b..f4b5606 100644
> --- a/drivers/media/usb/hackrf/hackrf.c
> +++ b/drivers/media/usb/hackrf/hackrf.c

<snip>

> @@ -748,15 +925,11 @@ static int hackrf_s_fmt_sdr_cap(struct file *file, void *priv,
>  		struct v4l2_format *f)
>  {
>  	struct hackrf_dev *dev = video_drvdata(file);
> -	struct vb2_queue *q = &dev->vb_queue;
>  	int i;
>  
>  	dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n",
>  			(char *)&f->fmt.sdr.pixelformat);
>  
> -	if (vb2_is_busy(q))
> -		return -EBUSY;
> -

Why is this removed?

>  	memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
>  	for (i = 0; i < NUM_FORMATS; i++) {
>  		if (f->fmt.sdr.pixelformat == formats[i].pixelformat) {
> @@ -856,17 +1029,64 @@ static int hackrf_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
>  
>  	if (v->index == 0) {
>  		strlcpy(v->name, "HackRF ADC", sizeof(v->name));
> -		v->type = V4L2_TUNER_ADC;
> +		v->type = V4L2_TUNER_SDR;
>  		v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
> -		v->rangelow  = bands_adc[0].rangelow;
> -		v->rangehigh = bands_adc[0].rangehigh;
> +		v->rangelow  = bands_adc_dac[0].rangelow;
> +		v->rangehigh = bands_adc_dac[0].rangehigh;
>  		ret = 0;
>  	} else if (v->index == 1) {
> -		strlcpy(v->name, "HackRF RF", sizeof(v->name));
> +		strlcpy(v->name, "HackRF RF RX", sizeof(v->name));

This seems unnecessary. You're calling g_tuner, so it is obvious that it is RX.
I'd keep the name as "HackRF RF".

>  		v->type = V4L2_TUNER_RF;
>  		v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
> -		v->rangelow  = bands_rf[0].rangelow;
> -		v->rangehigh = bands_rf[0].rangehigh;
> +		v->rangelow  = bands_rx_tx[0].rangelow;
> +		v->rangehigh = bands_rx_tx[0].rangehigh;
> +		ret = 0;
> +	} else {
> +		ret = -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
> +static int hackrf_s_modulator(struct file *file, void *fh,
> +		       const struct v4l2_modulator *a)
> +{
> +	struct hackrf_dev *dev = video_drvdata(file);
> +	int ret;
> +
> +	dev_dbg(dev->dev, "index=%d\n", a->index);
> +
> +	if (a->index == 0)
> +		ret = 0;
> +	else if (a->index == 1)
> +		ret = 0;
> +	else
> +		ret = -EINVAL;
> +
> +	return ret;

I'd just write:

	return a->index > 1 ? -EINVAL : 0;

More to the point, why implement this at all? At the moment s_modulator is meaningless
since there is nothing to set.

> +}
> +
> +static int hackrf_g_modulator(struct file *file, void *fh,
> +			      struct v4l2_modulator *a)
> +{
> +	struct hackrf_dev *dev = video_drvdata(file);
> +	int ret;
> +
> +	dev_dbg(dev->dev, "index=%d\n", a->index);
> +
> +	if (a->index == 0) {
> +		strlcpy(a->name, "HackRF DAC", sizeof(a->name));
> +		a->type = V4L2_TUNER_SDR;
> +		a->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
> +		a->rangelow  = bands_adc_dac[0].rangelow;
> +		a->rangehigh = bands_adc_dac[0].rangehigh;
> +		ret = 0;
> +	} else if (a->index == 1) {
> +		strlcpy(a->name, "HackRF RF TX", sizeof(a->name));

Same as with g_tuner: I'd drop the "TX" part in the name.

> +		a->type = V4L2_TUNER_RF;
> +		a->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
> +		a->rangelow  = bands_rx_tx[0].rangelow;
> +		a->rangehigh = bands_rx_tx[0].rangehigh;
>  		ret = 0;
>  	} else {
>  		ret = -EINVAL;

<snip>

> @@ -969,6 +1213,11 @@ static const struct v4l2_ioctl_ops hackrf_ioctl_ops = {
>  	.vidioc_enum_fmt_sdr_cap  = hackrf_enum_fmt_sdr_cap,
>  	.vidioc_try_fmt_sdr_cap   = hackrf_try_fmt_sdr_cap,
>  
> +	.vidioc_s_fmt_sdr_out     = hackrf_s_fmt_sdr_cap,
> +	.vidioc_g_fmt_sdr_out     = hackrf_g_fmt_sdr_cap,
> +	.vidioc_enum_fmt_sdr_out  = hackrf_enum_fmt_sdr_cap,
> +	.vidioc_try_fmt_sdr_out   = hackrf_try_fmt_sdr_cap,
> +

Since hackrf_*_fmt_sdr_cap is used for both capture and output I suggest that
those functions are renamed to hackrf_*_fmt_sdr(), dropping the "_cap" part.

>  	.vidioc_reqbufs           = vb2_ioctl_reqbufs,
>  	.vidioc_create_bufs       = vb2_ioctl_create_bufs,
>  	.vidioc_prepare_buf       = vb2_ioctl_prepare_buf,
> @@ -982,6 +1231,9 @@ static const struct v4l2_ioctl_ops hackrf_ioctl_ops = {
>  	.vidioc_s_tuner           = hackrf_s_tuner,
>  	.vidioc_g_tuner           = hackrf_g_tuner,
>  
> +	.vidioc_s_modulator       = hackrf_s_modulator,
> +	.vidioc_g_modulator       = hackrf_g_modulator,
> +
>  	.vidioc_s_frequency       = hackrf_s_frequency,
>  	.vidioc_g_frequency       = hackrf_g_frequency,
>  	.vidioc_enum_freq_bands   = hackrf_enum_freq_bands,
> @@ -996,6 +1248,7 @@ static const struct v4l2_file_operations hackrf_fops = {
>  	.open                     = v4l2_fh_open,
>  	.release                  = vb2_fop_release,
>  	.read                     = vb2_fop_read,
> +	.write                    = vb2_fop_write,
>  	.poll                     = vb2_fop_poll,
>  	.mmap                     = vb2_fop_mmap,
>  	.unlocked_ioctl           = video_ioctl2,

<snip>

> @@ -1089,85 +1393,141 @@ static int hackrf_probe(struct usb_interface *intf,
>  				buf, BUF_SIZE);
>  	if (ret) {
>  		dev_err(dev->dev, "Could not detect board\n");
> -		goto err_free_mem;
> +		goto err_kfree;
>  	}
>  
>  	buf[BUF_SIZE - 1] = '\0';
> -
>  	dev_info(dev->dev, "Board ID: %02x\n", u8tmp);
>  	dev_info(dev->dev, "Firmware version: %s\n", buf);
>  
> -	/* Init videobuf2 queue structure */
> -	dev->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
> -	dev->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
> -	dev->vb_queue.drv_priv = dev;
> -	dev->vb_queue.buf_struct_size = sizeof(struct hackrf_frame_buf);
> -	dev->vb_queue.ops = &hackrf_vb2_ops;
> -	dev->vb_queue.mem_ops = &vb2_vmalloc_memops;
> -	dev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
> -	ret = vb2_queue_init(&dev->vb_queue);
> +	/* Init vb2 queue structure for receiver */
> +	dev->rx_vb2_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
> +	dev->rx_vb2_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;

I suggest that you add VB2_DMABUF here and for tx_vb2_queue.io_modes.

I see no reason to leave that out.

Also add .vidioc_expbuf = vb2_ioctl_expbuf to the ioctl ops.

> +	dev->rx_vb2_queue.ops = &hackrf_vb2_ops;
> +	dev->rx_vb2_queue.mem_ops = &vb2_vmalloc_memops;
> +	dev->rx_vb2_queue.drv_priv = dev;
> +	dev->rx_vb2_queue.buf_struct_size = sizeof(struct hackrf_buffer);
> +	dev->rx_vb2_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
> +	ret = vb2_queue_init(&dev->rx_vb2_queue);
> +	if (ret) {
> +		dev_err(dev->dev, "Could not initialize rx vb2 queue\n");
> +		goto err_kfree;
> +	}
> +
> +	/* Init vb2 queue structure for transmitter */
> +	dev->tx_vb2_queue.type = V4L2_BUF_TYPE_SDR_OUTPUT;
> +	dev->tx_vb2_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_WRITE;
> +	dev->tx_vb2_queue.ops = &hackrf_vb2_ops;
> +	dev->tx_vb2_queue.mem_ops = &vb2_vmalloc_memops;
> +	dev->tx_vb2_queue.drv_priv = dev;
> +	dev->tx_vb2_queue.buf_struct_size = sizeof(struct hackrf_buffer);
> +	dev->tx_vb2_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
> +	ret = vb2_queue_init(&dev->tx_vb2_queue);
>  	if (ret) {
> -		dev_err(dev->dev, "Could not initialize vb2 queue\n");
> -		goto err_free_mem;
> +		dev_err(dev->dev, "Could not initialize tx vb2 queue\n");
> +		goto err_kfree;
>  	}
>  
> -	/* Init video_device structure */
> -	dev->vdev = hackrf_template;
> -	dev->vdev.queue = &dev->vb_queue;
> -	dev->vdev.queue->lock = &dev->vb_queue_lock;
> -	video_set_drvdata(&dev->vdev, dev);
> +	/* Register controls for receiver */
> +	v4l2_ctrl_handler_init(&dev->rx_ctrl_handler, 5);
> +	dev->rx_bandwidth_auto = v4l2_ctrl_new_std(&dev->rx_ctrl_handler,
> +		&hackrf_ctrl_ops_rx, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
> +		0, 1, 0, 1);
> +	dev->rx_bandwidth = v4l2_ctrl_new_std(&dev->rx_ctrl_handler,
> +		&hackrf_ctrl_ops_rx, V4L2_CID_RF_TUNER_BANDWIDTH,
> +		1750000, 28000000, 50000, 1750000);
> +	v4l2_ctrl_auto_cluster(2, &dev->rx_bandwidth_auto, 0, false);
> +	dev->rx_rf_gain = v4l2_ctrl_new_std(&dev->rx_ctrl_handler,
> +		&hackrf_ctrl_ops_rx, V4L2_CID_RF_TUNER_RF_GAIN, 0, 12, 12, 0);
> +	dev->rx_lna_gain = v4l2_ctrl_new_std(&dev->rx_ctrl_handler,
> +		&hackrf_ctrl_ops_rx, V4L2_CID_RF_TUNER_LNA_GAIN, 0, 40, 8, 0);
> +	dev->rx_if_gain = v4l2_ctrl_new_std(&dev->rx_ctrl_handler,
> +		&hackrf_ctrl_ops_rx, V4L2_CID_RF_TUNER_IF_GAIN, 0, 62, 2, 0);
> +	if (dev->rx_ctrl_handler.error) {
> +		ret = dev->rx_ctrl_handler.error;
> +		dev_err(dev->dev, "Could not initialize controls\n");
> +		goto err_v4l2_ctrl_handler_free_rx;
> +	}
> +	v4l2_ctrl_handler_setup(&dev->rx_ctrl_handler);
> +
> +	/* Register controls for transmitter */
> +	v4l2_ctrl_handler_init(&dev->tx_ctrl_handler, 4);
> +	dev->tx_bandwidth_auto = v4l2_ctrl_new_std(&dev->tx_ctrl_handler,
> +		&hackrf_ctrl_ops_tx, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
> +		0, 1, 0, 1);
> +	dev->tx_bandwidth = v4l2_ctrl_new_std(&dev->tx_ctrl_handler,
> +		&hackrf_ctrl_ops_tx, V4L2_CID_RF_TUNER_BANDWIDTH,
> +		1750000, 28000000, 50000, 1750000);
> +	v4l2_ctrl_auto_cluster(2, &dev->tx_bandwidth_auto, 0, false);
> +	dev->tx_lna_gain = v4l2_ctrl_new_std(&dev->tx_ctrl_handler,
> +		&hackrf_ctrl_ops_tx, V4L2_CID_RF_TUNER_LNA_GAIN, 0, 47, 1, 0);
> +	dev->tx_rf_gain = v4l2_ctrl_new_std(&dev->tx_ctrl_handler,
> +		&hackrf_ctrl_ops_tx, V4L2_CID_RF_TUNER_RF_GAIN, 0, 15, 15, 0);
> +	if (dev->tx_ctrl_handler.error) {
> +		ret = dev->tx_ctrl_handler.error;
> +		dev_err(dev->dev, "Could not initialize controls\n");
> +		goto err_v4l2_ctrl_handler_free_tx;
> +	}
> +	v4l2_ctrl_handler_setup(&dev->tx_ctrl_handler);
>  
>  	/* Register the v4l2_device structure */
>  	dev->v4l2_dev.release = hackrf_video_release;
>  	ret = v4l2_device_register(&intf->dev, &dev->v4l2_dev);
>  	if (ret) {
>  		dev_err(dev->dev, "Failed to register v4l2-device (%d)\n", ret);
> -		goto err_free_mem;
> +		goto err_v4l2_ctrl_handler_free_tx;
>  	}
>  
> -	/* Register controls */
> -	v4l2_ctrl_handler_init(&dev->hdl, 5);
> -	dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
> -			V4L2_CID_RF_TUNER_BANDWIDTH_AUTO, 0, 1, 1, 1);
> -	dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
> -			V4L2_CID_RF_TUNER_BANDWIDTH,
> -			1750000, 28000000, 50000, 1750000);
> -	v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false);
> -	dev->rf_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
> -			V4L2_CID_RF_TUNER_RF_GAIN, 0, 12, 12, 0);
> -	dev->lna_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
> -			V4L2_CID_RF_TUNER_LNA_GAIN, 0, 40, 8, 0);
> -	dev->if_gain = v4l2_ctrl_new_std(&dev->hdl, &hackrf_ctrl_ops,
> -			V4L2_CID_RF_TUNER_IF_GAIN, 0, 62, 2, 0);
> -	if (dev->hdl.error) {
> -		ret = dev->hdl.error;
> -		dev_err(dev->dev, "Could not initialize controls\n");
> -		goto err_free_controls;
> +	/* Init video_device structure for receiver */
> +	dev->rx_vdev = hackrf_template;
> +	dev->rx_vdev.queue = &dev->rx_vb2_queue;
> +	dev->rx_vdev.queue->lock = &dev->vb_queue_lock;
> +	dev->rx_vdev.v4l2_dev = &dev->v4l2_dev;
> +	dev->rx_vdev.ctrl_handler = &dev->rx_ctrl_handler;
> +	dev->rx_vdev.lock = &dev->v4l2_lock;
> +	dev->rx_vdev.vfl_dir = VFL_DIR_RX;
> +	video_set_drvdata(&dev->rx_vdev, dev);
> +	ret = video_register_device(&dev->rx_vdev, VFL_TYPE_SDR, -1);
> +	if (ret) {
> +		dev_err(dev->dev,
> +			"Failed to register as video device (%d)\n", ret);
> +		goto err_v4l2_device_unregister;
>  	}
> -
> -	v4l2_ctrl_handler_setup(&dev->hdl);
> -
> -	dev->v4l2_dev.ctrl_handler = &dev->hdl;
> -	dev->vdev.v4l2_dev = &dev->v4l2_dev;
> -	dev->vdev.lock = &dev->v4l2_lock;
> -
> -	ret = video_register_device(&dev->vdev, VFL_TYPE_SDR, -1);
> +	dev_info(dev->dev, "Registered as %s\n",
> +		 video_device_node_name(&dev->rx_vdev));
> +
> +	/* Init video_device structure for transmitter */
> +	dev->tx_vdev = hackrf_template;
> +	dev->tx_vdev.queue = &dev->tx_vb2_queue;
> +	dev->tx_vdev.queue->lock = &dev->vb_queue_lock;
> +	dev->tx_vdev.v4l2_dev = &dev->v4l2_dev;
> +	dev->tx_vdev.ctrl_handler = &dev->tx_ctrl_handler;
> +	dev->tx_vdev.lock = &dev->v4l2_lock;
> +	dev->tx_vdev.vfl_dir = VFL_DIR_TX;
> +	video_set_drvdata(&dev->tx_vdev, dev);
> +	ret = video_register_device(&dev->tx_vdev, VFL_TYPE_SDR, -1);
>  	if (ret) {
> -		dev_err(dev->dev, "Failed to register as video device (%d)\n",
> -				ret);
> -		goto err_unregister_v4l2_dev;
> +		dev_err(dev->dev,
> +			"Failed to register as video device (%d)\n", ret);
> +		goto err_video_unregister_device_rx;
>  	}
>  	dev_info(dev->dev, "Registered as %s\n",
> -			video_device_node_name(&dev->vdev));
> +		 video_device_node_name(&dev->tx_vdev));
> +
>  	dev_notice(dev->dev, "SDR API is still slightly experimental and functionality changes may follow\n");
>  	return 0;
> -
> -err_free_controls:
> -	v4l2_ctrl_handler_free(&dev->hdl);
> -err_unregister_v4l2_dev:
> +err_video_unregister_device_rx:
> +	video_unregister_device(&dev->rx_vdev);
> +err_v4l2_device_unregister:
>  	v4l2_device_unregister(&dev->v4l2_dev);
> -err_free_mem:
> +err_v4l2_ctrl_handler_free_tx:
> +	v4l2_ctrl_handler_free(&dev->tx_ctrl_handler);
> +err_v4l2_ctrl_handler_free_rx:
> +	v4l2_ctrl_handler_free(&dev->rx_ctrl_handler);
> +err_kfree:
>  	kfree(dev);
> +err:
> +	dev_dbg(dev->dev, "failed=%d\n", ret);
>  	return ret;
>  }
>  
> 

Regards,

	Hans

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

* Re: [PATCHv3 12/13] DocBook: fix S_FREQUENCY => G_FREQUENCY
  2015-07-31  2:10 ` [PATCHv3 12/13] DocBook: fix S_FREQUENCY => G_FREQUENCY Antti Palosaari
@ 2015-08-10  9:41   ` Hans Verkuil
  2015-08-11  2:55     ` Antti Palosaari
  0 siblings, 1 reply; 24+ messages in thread
From: Hans Verkuil @ 2015-08-10  9:41 UTC (permalink / raw)
  To: Antti Palosaari, linux-media

On 07/31/2015 04:10 AM, Antti Palosaari wrote:
> It is VIDIOC_G_FREQUENCY which does not use type to identify tuner,
> not VIDIOC_S_FREQUENCY. VIDIOC_S_FREQUENCY uses both tuner and type
> fields. One of these V4L API weirdness...

Actually, that's not what this is about. It's about whether g/s_frequency gets/sets
the frequency for the tuner or the modulator. That has nothing to do with the tuner
and type fields. The problem described here in the spec is a problem for both G and
S_FREQUENCY.

Regards,

	Hans

> 
> Cc: Hans Verkuil <hverkuil@xs4all.nl>
> Signed-off-by: Antti Palosaari <crope@iki.fi>
> ---
>  Documentation/DocBook/media/v4l/common.xml | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/Documentation/DocBook/media/v4l/common.xml b/Documentation/DocBook/media/v4l/common.xml
> index 8b5e014..f7008ea 100644
> --- a/Documentation/DocBook/media/v4l/common.xml
> +++ b/Documentation/DocBook/media/v4l/common.xml
> @@ -428,7 +428,7 @@ zero, no video outputs.</para>
>  modulator. Two separate device nodes will have to be used for such
>  hardware, one that supports the tuner functionality and one that supports
>  the modulator functionality. The reason is a limitation with the
> -&VIDIOC-S-FREQUENCY; ioctl where you cannot specify whether the frequency
> +&VIDIOC-G-FREQUENCY; ioctl where you cannot specify whether the frequency
>  is for a tuner or a modulator.</para>
>  
>        <para>To query and change modulator properties applications use
> 


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

* Re: [PATCHv3 13/13] DocBook: add tuner types SDR and RF for G_TUNER / S_TUNER
  2015-07-31  2:10 ` [PATCHv3 13/13] DocBook: add tuner types SDR and RF for G_TUNER / S_TUNER Antti Palosaari
@ 2015-08-10  9:43   ` Hans Verkuil
  0 siblings, 0 replies; 24+ messages in thread
From: Hans Verkuil @ 2015-08-10  9:43 UTC (permalink / raw)
  To: Antti Palosaari, linux-media

On 07/31/2015 04:10 AM, Antti Palosaari wrote:
> Add V4L2_TUNER_SDR and V4L2_TUNER_RF to supported tuner types to
> table.
> 
> Cc: Hans Verkuil <hverkuil@xs4all.nl>
> Signed-off-by: Antti Palosaari <crope@iki.fi>
> ---
>  Documentation/DocBook/media/v4l/vidioc-g-tuner.xml | 10 ++++++++++
>  1 file changed, 10 insertions(+)
> 
> diff --git a/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
> index b0d8659..10737a1 100644
> --- a/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
> +++ b/Documentation/DocBook/media/v4l/vidioc-g-tuner.xml
> @@ -261,6 +261,16 @@ applications must set the array to zero.</entry>
>  	    <entry>2</entry>
>  	    <entry></entry>
>  	  </row>
> +	  <row>
> +	    <entry><constant>V4L2_TUNER_SDR</constant></entry>
> +	    <entry>4</entry>
> +	    <entry></entry>
> +	  </row>
> +	  <row>
> +	    <entry><constant>V4L2_TUNER_RF</constant></entry>
> +	    <entry>5</entry>
> +	    <entry></entry>
> +	  </row>
>  	</tbody>
>        </tgroup>
>      </table>
> 

The description should also be filled in here. It was never filled in for the
RADIO and ANALOG_TV since that was obvious, but for these two new types it
should be set. For consistency just set the description of the RADIO type to
"Radio" and for ANALOG_TV to "Analog TV".

Regards,

	Hans

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

* Re: [PATCHv3 12/13] DocBook: fix S_FREQUENCY => G_FREQUENCY
  2015-08-10  9:41   ` Hans Verkuil
@ 2015-08-11  2:55     ` Antti Palosaari
  0 siblings, 0 replies; 24+ messages in thread
From: Antti Palosaari @ 2015-08-11  2:55 UTC (permalink / raw)
  To: Hans Verkuil, linux-media

On 08/10/2015 12:41 PM, Hans Verkuil wrote:
> On 07/31/2015 04:10 AM, Antti Palosaari wrote:
>> It is VIDIOC_G_FREQUENCY which does not use type to identify tuner,
>> not VIDIOC_S_FREQUENCY. VIDIOC_S_FREQUENCY uses both tuner and type
>> fields. One of these V4L API weirdness...
>
> Actually, that's not what this is about. It's about whether g/s_frequency gets/sets
> the frequency for the tuner or the modulator. That has nothing to do with the tuner
> and type fields. The problem described here in the spec is a problem for both G and
> S_FREQUENCY.

ah, now I think I see it. There is no tuner type for FM radio modulator 
- but instead it is capability of tuner type V4L2_TUNER_RADIO. As both 
radio receiver and transmitter has same tuner type it is not possible to 
identify it using tuner type...

regards
Antti

-- 
http://palosaari.fi/

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

end of thread, other threads:[~2015-08-11  2:55 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-31  2:10 [PATCHv3 00/13] SDR transmitter API Antti Palosaari
2015-07-31  2:10 ` [PATCHv3 01/13] v4l2: rename V4L2_TUNER_ADC to V4L2_TUNER_SDR Antti Palosaari
2015-07-31  2:10 ` [PATCHv3 02/13] v4l2: add RF gain control Antti Palosaari
2015-08-10  8:56   ` Hans Verkuil
2015-07-31  2:10 ` [PATCHv3 03/13] DocBook: document tuner " Antti Palosaari
2015-08-10  8:57   ` Hans Verkuil
2015-07-31  2:10 ` [PATCHv3 04/13] v4l2: add support for SDR transmitter Antti Palosaari
2015-07-31  2:10 ` [PATCHv3 05/13] DocBook: document " Antti Palosaari
2015-07-31  2:10 ` [PATCHv3 06/13] v4l: add type field to v4l2_modulator struct Antti Palosaari
2015-08-10  9:01   ` Hans Verkuil
2015-07-31  2:10 ` [PATCHv3 07/13] DocBook: add modulator type field Antti Palosaari
2015-08-10  9:02   ` Hans Verkuil
2015-07-31  2:10 ` [PATCHv3 08/13] hackrf: add control for RF amplifier Antti Palosaari
2015-08-10  9:03   ` Hans Verkuil
2015-07-31  2:10 ` [PATCHv3 09/13] hackrf: switch to single function which configures everything Antti Palosaari
2015-08-10  9:04   ` Hans Verkuil
2015-07-31  2:10 ` [PATCHv3 10/13] hackrf: add support for transmitter Antti Palosaari
2015-08-10  9:34   ` Hans Verkuil
2015-07-31  2:10 ` [PATCHv3 11/13] hackrf: do not set human readable name for formats Antti Palosaari
2015-07-31  2:10 ` [PATCHv3 12/13] DocBook: fix S_FREQUENCY => G_FREQUENCY Antti Palosaari
2015-08-10  9:41   ` Hans Verkuil
2015-08-11  2:55     ` Antti Palosaari
2015-07-31  2:10 ` [PATCHv3 13/13] DocBook: add tuner types SDR and RF for G_TUNER / S_TUNER Antti Palosaari
2015-08-10  9:43   ` Hans Verkuil

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).