* [ATTN 7/9] hackrf: switch to single function which configures everything
2015-05-26 17:08 [ATTN 0/9] SDR transmitter API Antti Palosaari
` (5 preceding siblings ...)
2015-05-26 17:08 ` [ATTN 6/9] hackrf: add control for RF amplifier Antti Palosaari
@ 2015-05-26 17:08 ` Antti Palosaari
2015-05-26 17:08 ` [ATTN 8/9] hackrf: add support for transmitter Antti Palosaari
` (2 subsequent siblings)
9 siblings, 0 replies; 13+ messages in thread
From: Antti Palosaari @ 2015-05-26 17:08 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] 13+ messages in thread* [ATTN 8/9] hackrf: add support for transmitter
2015-05-26 17:08 [ATTN 0/9] SDR transmitter API Antti Palosaari
` (6 preceding siblings ...)
2015-05-26 17:08 ` [ATTN 7/9] hackrf: switch to single function which configures everything Antti Palosaari
@ 2015-05-26 17:08 ` Antti Palosaari
2015-05-26 17:08 ` [ATTN 9/9] hackrf: do not set human readable name for formats Antti Palosaari
2015-06-05 9:50 ` [ATTN 0/9] SDR transmitter API Hans Verkuil
9 siblings, 0 replies; 13+ messages in thread
From: Antti Palosaari @ 2015-05-26 17:08 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 | 855 ++++++++++++++++++++++++++++----------
1 file changed, 640 insertions(+), 215 deletions(-)
diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c
index 5bd291b..6ad6937 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,7 +45,7 @@ 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,
@@ -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,
@@ -91,28 +92,44 @@ struct hackrf_frame_buf {
};
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 3
+#define TX_ON 4
+#define RX_V4L2_DEV_OPEN 5
+#define TX_V4L2_DEV_OPEN 6
+#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 v4l2_device v4l2_dev;
+ struct video_device rx_vdev;
+ struct video_device tx_vdev;
+ struct v4l2_device rx_v4l2_dev;
+ struct v4l2_device tx_v4l2_dev;
+
+ /* For RX / TX dev exclusive use */
+ int users;
+ struct mutex v4l2_open_release_mutex;
/* videobuf2 queue and queued buffers list */
- struct vb2_queue vb_queue;
+ struct vb2_queue rx_vb2_queue;
+ struct vb2_queue tx_vb2_queue;
struct list_head queued_bufs;
spinlock_t queued_bufs_lock; /* Protects queued_bufs */
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 +149,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 +206,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 +245,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 +301,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 +314,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 +377,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->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->rf_gain->val) ? 1 : 0;
+ 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;
}
@@ -365,8 +457,8 @@ leave:
return buf;
}
-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 +478,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_frame_buf *buf;
+ 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 +503,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 */
+ buf = hackrf_get_next_fill_buf(dev);
+ if (unlikely(buf == NULL)) {
+ dev->vb_full++;
+ dev_notice_ratelimited(&intf->dev,
+ "buffer is full - %u packets dropped\n",
+ dev->vb_full);
+ goto exit_usb_submit_urb;
+ }
+
+ len = min_t(unsigned long, vb2_plane_size(&buf->vb, 0),
+ urb->actual_length);
+ hackrf_copy_stream(dev, vb2_plane_vaddr(&buf->vb, 0),
+ urb->transfer_buffer, len);
+ vb2_set_plane_payload(&buf->vb, 0, len);
+ buf->vb.v4l2_buf.sequence = dev->sequence++;
+ v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+ vb2_buffer_done(&buf->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_frame_buf *buf;
+ 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);
+ }
- /* 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);
+ /* get buffer to read */
+ buf = hackrf_get_next_fill_buf(dev);
+ if (unlikely(buf == 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;
}
-skip:
+
+ len = min_t(unsigned long, urb->transfer_buffer_length,
+ vb2_get_plane_payload(&buf->vb, 0));
+ hackrf_copy_stream(dev, urb->transfer_buffer,
+ vb2_plane_vaddr(&buf->vb, 0), len);
+ urb->actual_length = len;
+ buf->vb.v4l2_buf.sequence = dev->sequence++;
+ v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+exit_usb_submit_urb:
usb_submit_urb(urb, GFP_ATOMIC);
}
@@ -537,9 +669,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 +695,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];
@@ -589,7 +731,8 @@ static void hackrf_cleanup_queued_bufs(struct hackrf_dev *dev)
static void hackrf_disconnect(struct usb_interface *intf)
{
struct v4l2_device *v = usb_get_intfdata(intf);
- struct hackrf_dev *dev = container_of(v, struct hackrf_dev, v4l2_dev);
+ struct hackrf_dev *dev = container_of(v, struct hackrf_dev,
+ rx_v4l2_dev);
dev_dbg(dev->dev, "\n");
@@ -597,12 +740,14 @@ static void hackrf_disconnect(struct usb_interface *intf)
mutex_lock(&dev->v4l2_lock);
/* No need to keep the urbs around after disconnection */
dev->udev = NULL;
- v4l2_device_disconnect(&dev->v4l2_dev);
- video_unregister_device(&dev->vdev);
+ v4l2_device_disconnect(&dev->tx_v4l2_dev);
+ v4l2_device_disconnect(&dev->rx_v4l2_dev);
+ video_unregister_device(&dev->tx_vdev);
+ video_unregister_device(&dev->rx_vdev);
mutex_unlock(&dev->v4l2_lock);
mutex_unlock(&dev->vb_queue_lock);
-
- v4l2_device_put(&dev->v4l2_dev);
+ v4l2_device_put(&dev->tx_v4l2_dev);
+ v4l2_device_put(&dev->rx_v4l2_dev);
}
/* Videobuf2 operations */
@@ -640,23 +785,26 @@ static int hackrf_start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct hackrf_dev *dev = vb2_get_drv_priv(vq);
int ret;
+ unsigned int mode;
dev_dbg(dev->dev, "\n");
- if (!dev->udev)
- return -ENODEV;
-
mutex_lock(&dev->v4l2_lock);
dev->sequence = 0;
-
- set_bit(POWER_ON, &dev->flags);
+ if (vq->type == V4L2_BUF_TYPE_SDR_CAPTURE) {
+ mode = 1;
+ set_bit(RX_ON, &dev->flags);
+ } else {
+ mode = 2;
+ set_bit(TX_ON, &dev->flags);
+ }
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,7 +817,7 @@ 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;
@@ -678,7 +826,8 @@ err:
hackrf_kill_urbs(dev);
hackrf_free_urbs(dev);
hackrf_free_stream_bufs(dev);
- clear_bit(POWER_ON, &dev->flags);
+ clear_bit(RX_ON, &dev->flags);
+ clear_bit(TX_ON, &dev->flags);
/* return all queued buffers to vb2 */
{
@@ -713,7 +862,8 @@ static void hackrf_stop_streaming(struct vb2_queue *vq)
hackrf_cleanup_queued_bufs(dev);
- clear_bit(POWER_ON, &dev->flags);
+ clear_bit(RX_ON, &dev->flags);
+ clear_bit(TX_ON, &dev->flags);
mutex_unlock(&dev->v4l2_lock);
}
@@ -731,15 +881,19 @@ static int hackrf_querycap(struct file *file, void *fh,
struct v4l2_capability *cap)
{
struct hackrf_dev *dev = video_drvdata(file);
+ struct video_device *vdev = video_devdata(file);
dev_dbg(dev->dev, "\n");
+ if (vdev->vfl_dir == VFL_DIR_RX)
+ cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER;
+ else
+ cap->device_caps = V4L2_CAP_SDR_OUTPUT | V4L2_CAP_MODULATOR;
+ cap->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+ cap->capabilities = cap->device_caps | 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,7 +902,7 @@ 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;
+ struct vb2_queue *q = &dev->rx_vb2_queue;
int i;
dev_dbg(dev->dev, "pixelformat fourcc %4.4s\n",
@@ -858,15 +1012,59 @@ static int hackrf_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
strlcpy(v->name, "HackRF ADC", sizeof(v->name));
v->type = V4L2_TUNER_ADC;
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;
+}
+
+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;
+}
+
+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->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->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 +1078,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 +1124,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;
+ 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 +1163,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 +1191,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 +1209,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,
@@ -991,11 +1221,87 @@ static const struct v4l2_ioctl_ops hackrf_ioctl_ops = {
.vidioc_log_status = v4l2_ctrl_log_status,
};
+/*
+ * TODO: That blocks whole transmitter device open when receiver is opened and
+ * the other way around, even only streaming is not allowed. Better solution
+ * needed...
+ */
+static int hackrf_v4l2_open(struct file *file)
+{
+ struct hackrf_dev *dev = video_drvdata(file);
+ struct video_device *vdev = video_devdata(file);
+ int ret;
+
+ dev_dbg(dev->dev, "\n");
+
+ if (mutex_lock_interruptible(&dev->v4l2_open_release_mutex))
+ return -ERESTARTSYS;
+
+ if (vdev->vfl_dir == VFL_DIR_RX) {
+ if (test_bit(TX_V4L2_DEV_OPEN, &dev->flags)) {
+ ret = -EBUSY;
+ goto err_mutex_unlock;
+ }
+ } else {
+ if (test_bit(RX_V4L2_DEV_OPEN, &dev->flags)) {
+ ret = -EBUSY;
+ goto err_mutex_unlock;
+ }
+ }
+
+ ret = v4l2_fh_open(file);
+ if (ret)
+ goto err_mutex_unlock;
+
+ dev->users++;
+
+ if (vdev->vfl_dir == VFL_DIR_RX)
+ set_bit(RX_V4L2_DEV_OPEN, &dev->flags);
+ else
+ set_bit(TX_V4L2_DEV_OPEN, &dev->flags);
+
+ mutex_unlock(&dev->v4l2_open_release_mutex);
+
+ return 0;
+err_mutex_unlock:
+ mutex_unlock(&dev->v4l2_open_release_mutex);
+ return ret;
+}
+
+static int hackrf_v4l2_release(struct file *file)
+{
+ struct hackrf_dev *dev = video_drvdata(file);
+ int ret;
+
+ dev_dbg(dev->dev, "\n");
+
+ mutex_lock(&dev->v4l2_open_release_mutex);
+
+ ret = vb2_fop_release(file);
+ if (ret)
+ goto err_mutex_unlock;
+
+ dev->users--;
+
+ if (!dev->users) {
+ clear_bit(RX_V4L2_DEV_OPEN, &dev->flags);
+ clear_bit(TX_V4L2_DEV_OPEN, &dev->flags);
+ }
+
+ mutex_unlock(&dev->v4l2_open_release_mutex);
+
+ return 0;
+err_mutex_unlock:
+ mutex_unlock(&dev->v4l2_open_release_mutex);
+ return ret;
+}
+
static const struct v4l2_file_operations hackrf_fops = {
.owner = THIS_MODULE,
- .open = v4l2_fh_open,
- .release = vb2_fop_release,
+ .open = hackrf_v4l2_open,
+ .release = hackrf_v4l2_release,
.read = vb2_fop_read,
+ .write = vb2_fop_write,
.poll = vb2_fop_poll,
.mmap = vb2_fop_mmap,
.unlocked_ioctl = video_ioctl2,
@@ -1010,17 +1316,22 @@ static struct video_device hackrf_template = {
static void hackrf_video_release(struct v4l2_device *v)
{
- struct hackrf_dev *dev = container_of(v, struct hackrf_dev, v4l2_dev);
+ struct hackrf_dev *dev = container_of(v, struct hackrf_dev,
+ rx_v4l2_dev);
+
+ dev_dbg(dev->dev, "\n");
- v4l2_ctrl_handler_free(&dev->hdl);
- v4l2_device_unregister(&dev->v4l2_dev);
+ v4l2_ctrl_handler_free(&dev->rx_ctrl_handler);
+ v4l2_ctrl_handler_free(&dev->tx_ctrl_handler);
+ v4l2_device_unregister(&dev->tx_v4l2_dev);
+ v4l2_device_unregister(&dev->rx_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 +1366,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,9 +1417,12 @@ 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_open_release_mutex);
mutex_init(&dev->v4l2_lock);
mutex_init(&dev->vb_queue_lock);
spin_lock_init(&dev->queued_bufs_lock);
@@ -1077,10 +1430,16 @@ static int hackrf_probe(struct usb_interface *intf,
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 +1448,151 @@ 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_frame_buf);
+ 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 vb2 queue\n");
- goto err_free_mem;
+ dev_err(dev->dev, "Could not initialize rx 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 the v4l2_device structure */
- dev->v4l2_dev.release = hackrf_video_release;
- ret = v4l2_device_register(&intf->dev, &dev->v4l2_dev);
+ /* 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_frame_buf);
+ 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, "Failed to register v4l2-device (%d)\n", ret);
- goto err_free_mem;
+ dev_err(dev->dev, "Could not initialize tx vb2 queue\n");
+ goto err_kfree;
}
- /* 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;
+ /* 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_free_controls;
+ goto err_v4l2_ctrl_handler_free_tx;
}
+ v4l2_ctrl_handler_setup(&dev->tx_ctrl_handler);
- v4l2_ctrl_handler_setup(&dev->hdl);
+ /* Register the v4l2_device structure for receiver */
+ dev->rx_v4l2_dev.release = hackrf_video_release;
+ dev->rx_v4l2_dev.ctrl_handler = &dev->rx_ctrl_handler;
+ ret = v4l2_device_register(&intf->dev, &dev->rx_v4l2_dev);
+ if (ret) {
+ dev_err(dev->dev, "Failed to register v4l2-device (%d)\n", ret);
+ goto err_v4l2_ctrl_handler_free_tx;
+ }
- dev->v4l2_dev.ctrl_handler = &dev->hdl;
- dev->vdev.v4l2_dev = &dev->v4l2_dev;
- dev->vdev.lock = &dev->v4l2_lock;
+ /* Register the v4l2_device structure for transmitter */
+ /* release called by receiver v4l2 dev */
+ dev->tx_v4l2_dev.ctrl_handler = &dev->tx_ctrl_handler;
+ ret = v4l2_device_register(&intf->dev, &dev->tx_v4l2_dev);
+ if (ret) {
+ dev_err(dev->dev, "Failed to register v4l2-device (%d)\n", ret);
+ goto err_v4l2_device_unregister_rx;
+ }
- ret = video_register_device(&dev->vdev, VFL_TYPE_SDR, -1);
+ /* 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->rx_v4l2_dev;
+ 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_unregister_v4l2_dev;
+ dev_err(dev->dev,
+ "Failed to register as video device (%d)\n", ret);
+ goto err_v4l2_device_unregister_tx;
}
dev_info(dev->dev, "Registered as %s\n",
- video_device_node_name(&dev->vdev));
+ 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->tx_v4l2_dev;
+ 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_video_unregister_device_rx;
+ }
+ dev_info(dev->dev, "Registered as %s\n",
+ 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:
- v4l2_device_unregister(&dev->v4l2_dev);
-err_free_mem:
+err_video_unregister_device_rx:
+ video_unregister_device(&dev->rx_vdev);
+err_v4l2_device_unregister_tx:
+ v4l2_device_unregister(&dev->tx_v4l2_dev);
+err_v4l2_device_unregister_rx:
+ v4l2_device_unregister(&dev->rx_v4l2_dev);
+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] 13+ messages in thread