aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform')
-rw-r--r--drivers/media/platform/vivid/Makefile4
-rw-r--r--drivers/media/platform/vivid/vivid-core.c123
-rw-r--r--drivers/media/platform/vivid/vivid-core.h42
-rw-r--r--drivers/media/platform/vivid/vivid-radio-tx.c4
-rw-r--r--drivers/media/platform/vivid/vivid-radio-tx.h4
-rw-r--r--drivers/media/platform/vivid/vivid-sdr-cap.c135
-rw-r--r--drivers/media/platform/vivid/vivid-sdr-cap.h7
-rw-r--r--drivers/media/platform/vivid/vivid-sdr-common.c146
-rw-r--r--drivers/media/platform/vivid/vivid-sdr-common.h35
-rw-r--r--drivers/media/platform/vivid/vivid-sdr-out.c499
-rw-r--r--drivers/media/platform/vivid/vivid-sdr-out.h33
11 files changed, 894 insertions, 138 deletions
diff --git a/drivers/media/platform/vivid/Makefile b/drivers/media/platform/vivid/Makefile
index 756fc12851df..597b1f8dd379 100644
--- a/drivers/media/platform/vivid/Makefile
+++ b/drivers/media/platform/vivid/Makefile
@@ -1,6 +1,6 @@
vivid-objs := vivid-core.o vivid-ctrls.o vivid-vid-common.o vivid-vbi-gen.o \
vivid-vid-cap.o vivid-vid-out.o vivid-kthread-cap.o vivid-kthread-out.o \
vivid-radio-rx.o vivid-radio-tx.o vivid-radio-common.o \
- vivid-rds-gen.o vivid-sdr-cap.o vivid-vbi-cap.o vivid-vbi-out.o \
- vivid-osd.o vivid-tpg.o vivid-tpg-colors.o
+ vivid-rds-gen.o vivid-sdr-common.o vivid-sdr-cap.o vivid-sdr-out.o \
+ vivid-vbi-cap.o vivid-vbi-out.o vivid-osd.o vivid-tpg.o vivid-tpg-colors.o
obj-$(CONFIG_VIDEO_VIVID) += vivid.o
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c
index ec125becb7af..5bd97d62c25c 100644
--- a/drivers/media/platform/vivid/vivid-core.c
+++ b/drivers/media/platform/vivid/vivid-core.c
@@ -42,7 +42,9 @@
#include "vivid-radio-common.h"
#include "vivid-radio-rx.h"
#include "vivid-radio-tx.h"
+#include "vivid-sdr-common.h"
#include "vivid-sdr-cap.h"
+#include "vivid-sdr-out.h"
#include "vivid-vbi-cap.h"
#include "vivid-vbi-out.h"
#include "vivid-osd.h"
@@ -81,6 +83,10 @@ static int sdr_cap_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
module_param_array(sdr_cap_nr, int, NULL, 0444);
MODULE_PARM_DESC(sdr_cap_nr, " swradioX start number, -1 is autodetect");
+static int sdr_out_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
+module_param_array(sdr_out_nr, int, NULL, 0444);
+MODULE_PARM_DESC(sdr_out_nr, " swradioX start number, -1 is autodetect");
+
static int radio_rx_nr[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = -1 };
module_param_array(radio_rx_nr, int, NULL, 0444);
MODULE_PARM_DESC(radio_rx_nr, " radioX start number, -1 is autodetect");
@@ -105,8 +111,8 @@ static unsigned multiplanar[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 1
module_param_array(multiplanar, uint, NULL, 0444);
MODULE_PARM_DESC(multiplanar, " 1 (default) creates a single planar device, 2 creates a multiplanar device.");
-/* Default: video + vbi-cap (raw and sliced) + radio rx + radio tx + sdr + vbi-out + vid-out */
-static unsigned node_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0x1d3d };
+/* Default: video + vbi-cap (raw and sliced) + radio rx + radio tx + sdr-cap + sdr-out + vbi-out + vid-out */
+static unsigned node_types[VIVID_MAX_DEVS] = { [0 ... (VIVID_MAX_DEVS - 1)] = 0x3d3d };
module_param_array(node_types, uint, NULL, 0444);
MODULE_PARM_DESC(node_types, " node types, default is 0x1d3d. Bitmask with the following meaning:\n"
"\t\t bit 0: Video Capture node\n"
@@ -116,6 +122,7 @@ MODULE_PARM_DESC(node_types, " node types, default is 0x1d3d. Bitmask with the f
"\t\t bit 8: Video Output node\n"
"\t\t bit 10-11: VBI Output node: 0 = none, 1 = raw vbi, 2 = sliced vbi, 3 = both\n"
"\t\t bit 12: Radio Transmitter node\n"
+ "\t\t bit 13: Software Defined Radio Receiver node\n"
"\t\t bit 16: Framebuffer for testing overlays");
/* Default: 4 inputs */
@@ -215,8 +222,10 @@ static int vidioc_querycap(struct file *file, void *priv,
cap->device_caps = dev->vbi_cap_caps;
else if (vdev->vfl_type == VFL_TYPE_VBI && vdev->vfl_dir == VFL_DIR_TX)
cap->device_caps = dev->vbi_out_caps;
- else if (vdev->vfl_type == VFL_TYPE_SDR)
+ else if (vdev->vfl_type == VFL_TYPE_SDR && vdev->vfl_dir == VFL_DIR_RX)
cap->device_caps = dev->sdr_cap_caps;
+ else if (vdev->vfl_type == VFL_TYPE_SDR && vdev->vfl_dir == VFL_DIR_TX)
+ cap->device_caps = dev->sdr_out_caps;
else if (vdev->vfl_type == VFL_TYPE_RADIO && vdev->vfl_dir == VFL_DIR_RX)
cap->device_caps = dev->radio_rx_caps;
else if (vdev->vfl_type == VFL_TYPE_RADIO && vdev->vfl_dir == VFL_DIR_TX)
@@ -224,7 +233,7 @@ static int vidioc_querycap(struct file *file, void *priv,
cap->capabilities = dev->vid_cap_caps | dev->vid_out_caps |
dev->vbi_cap_caps | dev->vbi_out_caps |
dev->radio_rx_caps | dev->radio_tx_caps |
- dev->sdr_cap_caps | V4L2_CAP_DEVICE_CAPS;
+ dev->sdr_cap_caps | dev->sdr_out_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -270,6 +279,28 @@ static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *
return vivid_video_s_tuner(file, fh, vt);
}
+static int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *mt)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_RADIO)
+ return vivid_radio_g_modulator(file, fh, mt);
+ if (vdev->vfl_type == VFL_TYPE_SDR)
+ return vivid_sdr_g_modulator(file, fh, mt);
+ return -ENOTTY;
+}
+
+static int vidioc_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *mt)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ if (vdev->vfl_type == VFL_TYPE_RADIO)
+ return vivid_radio_s_modulator(file, fh, mt);
+ if (vdev->vfl_type == VFL_TYPE_SDR)
+ return vivid_sdr_s_modulator(file, fh, mt);
+ return -ENOTTY;
+}
+
static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
{
struct vivid_dev *dev = video_drvdata(file);
@@ -280,7 +311,9 @@ static int vidioc_g_frequency(struct file *file, void *fh, struct v4l2_frequency
vdev->vfl_dir == VFL_DIR_RX ?
&dev->radio_rx_freq : &dev->radio_tx_freq, vf);
if (vdev->vfl_type == VFL_TYPE_SDR)
- return vivid_sdr_g_frequency(file, fh, vf);
+ return vdev->vfl_dir == VFL_DIR_RX ?
+ vivid_sdr_cap_g_frequency(file, fh, vf) :
+ vivid_sdr_out_g_frequency(file, fh, vf);
return vivid_video_g_frequency(file, fh, vf);
}
@@ -294,7 +327,9 @@ static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_fre
vdev->vfl_dir == VFL_DIR_RX ?
&dev->radio_rx_freq : &dev->radio_tx_freq, vf);
if (vdev->vfl_type == VFL_TYPE_SDR)
- return vivid_sdr_s_frequency(file, fh, vf);
+ return vdev->vfl_dir == VFL_DIR_RX ?
+ vivid_sdr_cap_s_frequency(file, fh, vf) :
+ vivid_sdr_out_s_frequency(file, fh, vf);
return vivid_video_s_frequency(file, fh, vf);
}
@@ -450,6 +485,7 @@ static bool vivid_is_last_user(struct vivid_dev *dev)
vivid_is_in_use(&dev->vbi_cap_dev) +
vivid_is_in_use(&dev->vbi_out_dev) +
vivid_is_in_use(&dev->sdr_cap_dev) +
+ vivid_is_in_use(&dev->sdr_out_dev) +
vivid_is_in_use(&dev->radio_rx_dev) +
vivid_is_in_use(&dev->radio_tx_dev);
@@ -475,6 +511,7 @@ static int vivid_fop_release(struct file *file)
set_bit(V4L2_FL_REGISTERED, &dev->vbi_cap_dev.flags);
set_bit(V4L2_FL_REGISTERED, &dev->vbi_out_dev.flags);
set_bit(V4L2_FL_REGISTERED, &dev->sdr_cap_dev.flags);
+ set_bit(V4L2_FL_REGISTERED, &dev->sdr_out_dev.flags);
set_bit(V4L2_FL_REGISTERED, &dev->radio_rx_dev.flags);
set_bit(V4L2_FL_REGISTERED, &dev->radio_tx_dev.flags);
}
@@ -557,11 +594,16 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
.vidioc_try_fmt_sliced_vbi_out = vidioc_try_fmt_sliced_vbi_out,
.vidioc_s_fmt_sliced_vbi_out = vidioc_s_fmt_sliced_vbi_out,
- .vidioc_enum_fmt_sdr_cap = vidioc_enum_fmt_sdr_cap,
+ .vidioc_enum_fmt_sdr_cap = vivid_enum_fmt_sdr,
.vidioc_g_fmt_sdr_cap = vidioc_g_fmt_sdr_cap,
- .vidioc_try_fmt_sdr_cap = vidioc_try_fmt_sdr_cap,
+ .vidioc_try_fmt_sdr_cap = vivid_try_fmt_sdr,
.vidioc_s_fmt_sdr_cap = vidioc_s_fmt_sdr_cap,
+ .vidioc_enum_fmt_sdr_out = vivid_enum_fmt_sdr,
+ .vidioc_g_fmt_sdr_out = vidioc_g_fmt_sdr_out,
+ .vidioc_try_fmt_sdr_out = vivid_try_fmt_sdr,
+ .vidioc_s_fmt_sdr_out = vidioc_s_fmt_sdr_out,
+
.vidioc_overlay = vidioc_overlay,
.vidioc_enum_framesizes = vidioc_enum_framesizes,
.vidioc_enum_frameintervals = vidioc_enum_frameintervals,
@@ -741,12 +783,15 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
/* do we create a software defined radio capture device? */
dev->has_sdr_cap = node_type & 0x0020;
+ /* do we create a software defined radio output device? */
+ dev->has_sdr_out = node_type & 0x2000;
+
/* do we have a tuner? */
has_tuner = ((dev->has_vid_cap || dev->has_vbi_cap) && in_type_counter[TV]) ||
dev->has_radio_rx || dev->has_sdr_cap;
/* do we have a modulator? */
- has_modulator = dev->has_radio_tx;
+ has_modulator = dev->has_radio_tx || dev->has_sdr_out;
if (dev->has_vid_cap)
/* do we have a framebuffer for overlay testing? */
@@ -829,6 +874,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->sdr_cap_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER;
dev->sdr_cap_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
}
+ if (dev->has_sdr_out) {
+ /* set up the capabilities of the sdr output device */
+ dev->sdr_out_caps = V4L2_CAP_SDR_OUTPUT | V4L2_CAP_MODULATOR;
+ dev->sdr_out_caps |= V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
+ }
/* set up the capabilities of the radio receiver device */
if (dev->has_radio_rx)
dev->radio_rx_caps = V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE |
@@ -975,10 +1025,12 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->radio_rds_loop = false;
}
dev->radio_tx_subchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_RDS;
- dev->sdr_adc_freq = 300000;
- dev->sdr_fm_freq = 50000000;
- dev->sdr_pixelformat = V4L2_SDR_FMT_CU8;
- dev->sdr_buffersize = SDR_CAP_SAMPLES_PER_BUF * 2;
+ dev->sdr_cap_adc_freq = 300000;
+ dev->sdr_cap_fm_freq = 50000000;
+ dev->sdr_cap_pixelformat = V4L2_SDR_FMT_CU8;
+ dev->sdr_out_dac_freq = 300000;
+ dev->sdr_out_fm_freq = 50000000;
+ dev->sdr_out_pixelformat = V4L2_SDR_FMT_CU8;
dev->edid_max_blocks = dev->edid_blocks = 2;
memcpy(dev->edid, vivid_hdmi_edid, sizeof(vivid_hdmi_edid));
@@ -1006,6 +1058,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx);
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx);
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_out);
/* initialize overlay */
dev->fb_cap.fmt.width = dev->src_rect.width;
@@ -1024,6 +1077,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
INIT_LIST_HEAD(&dev->vbi_cap_active);
INIT_LIST_HEAD(&dev->vbi_out_active);
INIT_LIST_HEAD(&dev->sdr_cap_active);
+ INIT_LIST_HEAD(&dev->sdr_out_active);
/* start creating the vb2 queues */
if (dev->has_vid_cap) {
@@ -1120,6 +1174,24 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
goto unreg_dev;
}
+ if (dev->has_sdr_out) {
+ /* initialize sdr_out queue */
+ q = &dev->vb_sdr_out_q;
+ q->type = V4L2_BUF_TYPE_SDR_OUTPUT;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_WRITE;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct vivid_buffer);
+ q->ops = &vivid_sdr_out_qops;
+ q->mem_ops = &vb2_vmalloc_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->min_buffers_needed = 8;
+ q->lock = &dev->mutex;
+
+ ret = vb2_queue_init(q);
+ if (ret)
+ goto unreg_dev;
+ }
+
if (dev->has_fb) {
/* Create framebuffer for testing capture/output overlay */
ret = vivid_fb_init(dev);
@@ -1242,6 +1314,25 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
video_device_node_name(vfd));
}
+ if (dev->has_sdr_out) {
+ vfd = &dev->sdr_out_dev;
+ strlcpy(vfd->name, "vivid-sdr-out", sizeof(vfd->name));
+ vfd->vfl_dir = VFL_DIR_TX;
+ vfd->fops = &vivid_fops;
+ vfd->ioctl_ops = &vivid_ioctl_ops;
+ vfd->release = video_device_release_empty;
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->queue = &dev->vb_sdr_out_q;
+ vfd->lock = &dev->mutex;
+ video_set_drvdata(vfd, dev);
+
+ ret = video_register_device(vfd, VFL_TYPE_SDR, sdr_out_nr[inst]);
+ if (ret < 0)
+ goto unreg_dev;
+ v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n",
+ video_device_node_name(vfd));
+ }
+
if (dev->has_radio_rx) {
vfd = &dev->radio_rx_dev;
strlcpy(vfd->name, "vivid-rad-rx", sizeof(vfd->name));
@@ -1286,6 +1377,7 @@ unreg_dev:
video_unregister_device(&dev->radio_tx_dev);
video_unregister_device(&dev->radio_rx_dev);
video_unregister_device(&dev->sdr_cap_dev);
+ video_unregister_device(&dev->sdr_out_dev);
video_unregister_device(&dev->vbi_out_dev);
video_unregister_device(&dev->vbi_cap_dev);
video_unregister_device(&dev->vid_out_dev);
@@ -1372,6 +1464,11 @@ static int vivid_remove(struct platform_device *pdev)
video_device_node_name(&dev->sdr_cap_dev));
video_unregister_device(&dev->sdr_cap_dev);
}
+ if (dev->has_sdr_out) {
+ v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
+ video_device_node_name(&dev->sdr_out_dev));
+ video_unregister_device(&dev->sdr_out_dev);
+ }
if (dev->has_radio_rx) {
v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
video_device_node_name(&dev->radio_rx_dev));
diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h
index 8c7a5ba87c90..79cb7db1da48 100644
--- a/drivers/media/platform/vivid/vivid-core.h
+++ b/drivers/media/platform/vivid/vivid-core.h
@@ -66,7 +66,7 @@
#define MAX_TV_FREQ (958U * 16U)
/* The number of samples returned in every SDR buffer */
-#define SDR_CAP_SAMPLES_PER_BUF 0x4000
+#define SDR_SAMPLES_PER_BUF 0x4000
/* used by the threads to know when to resync internal counters */
#define JIFFIES_PER_DAY (3600U * 24U * HZ)
@@ -155,6 +155,8 @@ struct vivid_dev {
struct v4l2_ctrl_handler ctrl_hdl_radio_tx;
struct video_device sdr_cap_dev;
struct v4l2_ctrl_handler ctrl_hdl_sdr_cap;
+ struct video_device sdr_out_dev;
+ struct v4l2_ctrl_handler ctrl_hdl_sdr_out;
spinlock_t slock;
struct mutex mutex;
@@ -164,6 +166,7 @@ struct vivid_dev {
u32 vbi_cap_caps;
u32 vbi_out_caps;
u32 sdr_cap_caps;
+ u32 sdr_out_caps;
u32 radio_rx_caps;
u32 radio_tx_caps;
@@ -188,6 +191,7 @@ struct vivid_dev {
bool has_radio_rx;
bool has_radio_tx;
bool has_sdr_cap;
+ bool has_sdr_out;
bool has_fb;
bool can_loop_video;
@@ -449,14 +453,35 @@ struct vivid_dev {
/* SDR capture */
struct vb2_queue vb_sdr_cap_q;
struct list_head sdr_cap_active;
- u32 sdr_pixelformat; /* v4l2 format id */
- unsigned sdr_buffersize;
- unsigned sdr_adc_freq;
- unsigned sdr_fm_freq;
+ u32 sdr_cap_pixelformat; /* v4l2 format id */
+ unsigned sdr_cap_adc_freq;
+ unsigned sdr_cap_fm_freq;
unsigned sdr_fm_deviation;
int sdr_fixp_src_phase;
int sdr_fixp_mod_phase;
+ /* thread for generating SDR stream */
+ struct task_struct *kthread_sdr_cap;
+ unsigned long jiffies_sdr_cap;
+ u32 sdr_cap_seq_offset;
+ u32 sdr_cap_seq_count;
+ bool sdr_cap_seq_resync;
+
+ /* SDR output */
+ struct vb2_queue vb_sdr_out_q;
+ struct list_head sdr_out_active;
+ u32 sdr_out_pixelformat; /* v4l2 format id */
+ unsigned sdr_buffersize;
+ unsigned sdr_out_dac_freq;
+ unsigned sdr_out_fm_freq;
+
+ /* thread for SDR output stream */
+ struct task_struct *kthread_sdr_out;
+ unsigned long jiffies_sdr_out;
+ u32 sdr_out_seq_offset;
+ u32 sdr_out_seq_count;
+ bool sdr_out_seq_resync;
+
bool tstamp_src_is_soe;
bool has_crop_cap;
bool has_compose_cap;
@@ -465,13 +490,6 @@ struct vivid_dev {
bool has_compose_out;
bool has_scaler_out;
- /* thread for generating SDR stream */
- struct task_struct *kthread_sdr_cap;
- unsigned long jiffies_sdr_cap;
- u32 sdr_cap_seq_offset;
- u32 sdr_cap_seq_count;
- bool sdr_cap_seq_resync;
-
/* RDS generator */
struct vivid_rds_gen rds_gen;
diff --git a/drivers/media/platform/vivid/vivid-radio-tx.c b/drivers/media/platform/vivid/vivid-radio-tx.c
index 8c59d4f53200..2cf423968ca8 100644
--- a/drivers/media/platform/vivid/vivid-radio-tx.c
+++ b/drivers/media/platform/vivid/vivid-radio-tx.c
@@ -109,7 +109,7 @@ unsigned int vivid_radio_tx_poll(struct file *file, struct poll_table_struct *wa
return POLLOUT | POLLWRNORM | v4l2_ctrl_poll(file, wait);
}
-int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a)
+int vivid_radio_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a)
{
struct vivid_dev *dev = video_drvdata(file);
@@ -128,7 +128,7 @@ int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a)
return 0;
}
-int vidioc_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *a)
+int vivid_radio_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *a)
{
struct vivid_dev *dev = video_drvdata(file);
diff --git a/drivers/media/platform/vivid/vivid-radio-tx.h b/drivers/media/platform/vivid/vivid-radio-tx.h
index 7f8ff7547119..001b927e77d1 100644
--- a/drivers/media/platform/vivid/vivid-radio-tx.h
+++ b/drivers/media/platform/vivid/vivid-radio-tx.h
@@ -23,7 +23,7 @@
ssize_t vivid_radio_tx_write(struct file *, const char __user *, size_t, loff_t *);
unsigned int vivid_radio_tx_poll(struct file *file, struct poll_table_struct *wait);
-int vidioc_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a);
-int vidioc_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *a);
+int vivid_radio_g_modulator(struct file *file, void *fh, struct v4l2_modulator *a);
+int vivid_radio_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *a);
#endif
diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c
index 082c401764ce..b6dedd257c2b 100644
--- a/drivers/media/platform/vivid/vivid-sdr-cap.c
+++ b/drivers/media/platform/vivid/vivid-sdr-cap.c
@@ -33,30 +33,12 @@
#include "vivid-core.h"
#include "vivid-ctrls.h"
#include "vivid-sdr-cap.h"
-
-/* stream formats */
-struct vivid_format {
- u32 pixelformat;
- u32 buffersize;
-};
-
-/* format descriptions for capture and preview */
-static const struct vivid_format formats[] = {
- {
- .pixelformat = V4L2_SDR_FMT_CU8,
- .buffersize = SDR_CAP_SAMPLES_PER_BUF * 2,
- }, {
- .pixelformat = V4L2_SDR_FMT_CS8,
- .buffersize = SDR_CAP_SAMPLES_PER_BUF * 2,
- },
-};
-
-static const unsigned int NUM_FORMATS = ARRAY_SIZE(formats);
+#include "vivid-sdr-common.h"
static const struct v4l2_frequency_band bands_adc[] = {
{
.tuner = 0,
- .type = V4L2_TUNER_ADC,
+ .type = V4L2_TUNER_SDR,
.index = 0,
.capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
.rangelow = 300000,
@@ -64,7 +46,7 @@ static const struct v4l2_frequency_band bands_adc[] = {
},
{
.tuner = 0,
- .type = V4L2_TUNER_ADC,
+ .type = V4L2_TUNER_SDR,
.index = 1,
.capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
.rangelow = 900001,
@@ -72,7 +54,7 @@ static const struct v4l2_frequency_band bands_adc[] = {
},
{
.tuner = 0,
- .type = V4L2_TUNER_ADC,
+ .type = V4L2_TUNER_SDR,
.index = 2,
.capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
.rangelow = 3200000,
@@ -163,9 +145,9 @@ static int vivid_thread_sdr_cap(void *data)
jiffies_since_start = cur_jiffies - dev->jiffies_sdr_cap;
/* Get the number of buffers streamed since the start */
buffers_since_start =
- (u64)jiffies_since_start * dev->sdr_adc_freq +
- (HZ * SDR_CAP_SAMPLES_PER_BUF) / 2;
- do_div(buffers_since_start, HZ * SDR_CAP_SAMPLES_PER_BUF);
+ (u64)jiffies_since_start * dev->sdr_cap_adc_freq +
+ (HZ * SDR_SAMPLES_PER_BUF) / 2;
+ do_div(buffers_since_start, HZ * SDR_SAMPLES_PER_BUF);
/*
* After more than 0xf0000000 (rounded down to a multiple of
@@ -188,20 +170,20 @@ static int vivid_thread_sdr_cap(void *data)
* Calculate the number of samples streamed since we started,
* not including the current buffer.
*/
- samples_since_start = buffers_since_start * SDR_CAP_SAMPLES_PER_BUF;
+ samples_since_start = buffers_since_start * SDR_SAMPLES_PER_BUF;
/* And the number of jiffies since we started */
jiffies_since_start = jiffies - dev->jiffies_sdr_cap;
/* Increase by the number of samples in one buffer */
- samples_since_start += SDR_CAP_SAMPLES_PER_BUF;
+ samples_since_start += SDR_SAMPLES_PER_BUF;
/*
* Calculate when that next buffer is supposed to start
* in jiffies since we started streaming.
*/
next_jiffies_since_start = samples_since_start * HZ +
- dev->sdr_adc_freq / 2;
- do_div(next_jiffies_since_start, dev->sdr_adc_freq);
+ dev->sdr_cap_adc_freq / 2;
+ do_div(next_jiffies_since_start, dev->sdr_cap_adc_freq);
/* If it is in the past, then just schedule asap */
if (next_jiffies_since_start < jiffies_since_start)
next_jiffies_since_start = jiffies_since_start;
@@ -218,7 +200,7 @@ static int sdr_cap_queue_setup(struct vb2_queue *vq, const void *parg,
unsigned sizes[], void *alloc_ctxs[])
{
/* 2 = max 16-bit sample returned */
- sizes[0] = SDR_CAP_SAMPLES_PER_BUF * 2;
+ sizes[0] = SDR_SAMPLES_PER_BUF * 2;
*nplanes = 1;
return 0;
}
@@ -226,7 +208,7 @@ static int sdr_cap_queue_setup(struct vb2_queue *vq, const void *parg,
static int sdr_cap_buf_prepare(struct vb2_buffer *vb)
{
struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
- unsigned size = SDR_CAP_SAMPLES_PER_BUF * 2;
+ unsigned size = SDR_SAMPLES_PER_BUF * 2;
dprintk(dev, 1, "%s\n", __func__);
@@ -327,37 +309,18 @@ const struct vb2_ops vivid_sdr_cap_qops = {
.wait_finish = vb2_ops_wait_finish,
};
-int vivid_sdr_enum_freq_bands(struct file *file, void *fh,
- struct v4l2_frequency_band *band)
-{
- switch (band->tuner) {
- case 0:
- if (band->index >= ARRAY_SIZE(bands_adc))
- return -EINVAL;
- *band = bands_adc[band->index];
- return 0;
- case 1:
- if (band->index >= ARRAY_SIZE(bands_fm))
- return -EINVAL;
- *band = bands_fm[band->index];
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-int vivid_sdr_g_frequency(struct file *file, void *fh,
+int vivid_sdr_cap_g_frequency(struct file *file, void *fh,
struct v4l2_frequency *vf)
{
struct vivid_dev *dev = video_drvdata(file);
switch (vf->tuner) {
case 0:
- vf->frequency = dev->sdr_adc_freq;
- vf->type = V4L2_TUNER_ADC;
+ vf->frequency = dev->sdr_cap_adc_freq;
+ vf->type = V4L2_TUNER_SDR;
return 0;
case 1:
- vf->frequency = dev->sdr_fm_freq;
+ vf->frequency = dev->sdr_cap_fm_freq;
vf->type = V4L2_TUNER_RF;
return 0;
default:
@@ -365,7 +328,7 @@ int vivid_sdr_g_frequency(struct file *file, void *fh,
}
}
-int vivid_sdr_s_frequency(struct file *file, void *fh,
+int vivid_sdr_cap_s_frequency(struct file *file, void *fh,
const struct v4l2_frequency *vf)
{
struct vivid_dev *dev = video_drvdata(file);
@@ -374,7 +337,7 @@ int vivid_sdr_s_frequency(struct file *file, void *fh,
switch (vf->tuner) {
case 0:
- if (vf->type != V4L2_TUNER_ADC)
+ if (vf->type != V4L2_TUNER_SDR)
return -EINVAL;
if (freq < BAND_ADC_0)
band = 0;
@@ -388,16 +351,16 @@ int vivid_sdr_s_frequency(struct file *file, void *fh,
bands_adc[band].rangehigh);
if (vb2_is_streaming(&dev->vb_sdr_cap_q) &&
- freq != dev->sdr_adc_freq) {
+ freq != dev->sdr_cap_adc_freq) {
/* resync the thread's timings */
dev->sdr_cap_seq_resync = true;
}
- dev->sdr_adc_freq = freq;
+ dev->sdr_cap_adc_freq = freq;
return 0;
case 1:
if (vf->type != V4L2_TUNER_RF)
return -EINVAL;
- dev->sdr_fm_freq = clamp_t(unsigned, freq,
+ dev->sdr_cap_fm_freq = clamp_t(unsigned, freq,
bands_fm[0].rangelow,
bands_fm[0].rangehigh);
return 0;
@@ -411,7 +374,7 @@ int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
switch (vt->index) {
case 0:
strlcpy(vt->name, "ADC", sizeof(vt->name));
- vt->type = V4L2_TUNER_ADC;
+ vt->type = V4L2_TUNER_SDR;
vt->capability =
V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
vt->rangelow = bands_adc[0].rangelow;
@@ -437,20 +400,14 @@ int vivid_sdr_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt)
return 0;
}
-int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
-{
- if (f->index >= ARRAY_SIZE(formats))
- return -EINVAL;
- f->pixelformat = formats[f->index].pixelformat;
- return 0;
-}
-
int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f)
{
struct vivid_dev *dev = video_drvdata(file);
+ const struct vivid_sdr_fmt *fmt;
- f->fmt.sdr.pixelformat = dev->sdr_pixelformat;
- f->fmt.sdr.buffersize = dev->sdr_buffersize;
+ fmt = vivid_sdr_get_format(dev, dev->sdr_cap_pixelformat);
+ f->fmt.sdr.pixelformat = fmt->pixelformat;
+ f->fmt.sdr.buffersize = fmt->buffersize;
memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
return 0;
}
@@ -459,40 +416,14 @@ int vidioc_s_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f)
{
struct vivid_dev *dev = video_drvdata(file);
struct vb2_queue *q = &dev->vb_sdr_cap_q;
- int i;
+ const struct vivid_sdr_fmt *fmt;
if (vb2_is_busy(q))
return -EBUSY;
- memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
- for (i = 0; i < ARRAY_SIZE(formats); i++) {
- if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
- dev->sdr_pixelformat = formats[i].pixelformat;
- dev->sdr_buffersize = formats[i].buffersize;
- f->fmt.sdr.buffersize = formats[i].buffersize;
- return 0;
- }
- }
- dev->sdr_pixelformat = formats[0].pixelformat;
- dev->sdr_buffersize = formats[0].buffersize;
- f->fmt.sdr.pixelformat = formats[0].pixelformat;
- f->fmt.sdr.buffersize = formats[0].buffersize;
- return 0;
-}
-
-int vidioc_try_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f)
-{
- int i;
-
- memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
- for (i = 0; i < ARRAY_SIZE(formats); i++) {
- if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
- f->fmt.sdr.buffersize = formats[i].buffersize;
- return 0;
- }
- }
- f->fmt.sdr.pixelformat = formats[0].pixelformat;
- f->fmt.sdr.buffersize = formats[0].buffersize;
+ vivid_try_fmt_sdr(file, fh, f);
+ fmt = vivid_sdr_get_format(dev, dev->sdr_cap_pixelformat);
+ dev->sdr_cap_pixelformat = f->fmt.sdr.pixelformat;
return 0;
}
@@ -515,7 +446,7 @@ void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf)
/* calculate phase step */
#define BEEP_FREQ 1000 /* 1kHz beep */
src_phase_step = DIV_ROUND_CLOSEST(FIXP_2PI * BEEP_FREQ,
- dev->sdr_adc_freq);
+ dev->sdr_cap_adc_freq);
for (i = 0; i < plane_size; i += 2) {
mod_phase_step = fixp_cos32_rad(dev->sdr_fixp_src_phase,
@@ -544,7 +475,7 @@ void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf)
fixp_i >>= (31 - FIXP_N);
fixp_q >>= (31 - FIXP_N);
- switch (dev->sdr_pixelformat) {
+ switch (dev->sdr_cap_pixelformat) {
case V4L2_SDR_FMT_CU8:
/* convert 'fixp float' to u8 [0, +255] */
/* u8 = X * 127.5 + 127.5; X is float [-1.0, +1.0] */
diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.h b/drivers/media/platform/vivid/vivid-sdr-cap.h
index 43014b2733db..ef0bc8f8101f 100644
--- a/drivers/media/platform/vivid/vivid-sdr-cap.h
+++ b/drivers/media/platform/vivid/vivid-sdr-cap.h
@@ -20,15 +20,12 @@
#ifndef _VIVID_SDR_CAP_H_
#define _VIVID_SDR_CAP_H_
-int vivid_sdr_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band);
-int vivid_sdr_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
-int vivid_sdr_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf);
+int vivid_sdr_cap_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
+int vivid_sdr_cap_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf);
int vivid_sdr_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt);
int vivid_sdr_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *vt);
-int vidioc_enum_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f);
int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f);
int vidioc_s_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f);
-int vidioc_try_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f);
void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf);
extern const struct vb2_ops vivid_sdr_cap_qops;
diff --git a/drivers/media/platform/vivid/vivid-sdr-common.c b/drivers/media/platform/vivid/vivid-sdr-common.c
new file mode 100644
index 000000000000..7fbffa55d216
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-sdr-common.c
@@ -0,0 +1,146 @@
+/*
+ * vivid-sdr-common.c - software defined radio support functions.
+ *
+ * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/math64.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-dv-timings.h>
+#include <linux/fixp-arith.h>
+
+#include "vivid-core.h"
+#include "vivid-ctrls.h"
+#include "vivid-sdr-common.h"
+
+/* format descriptions for capture and preview */
+static const struct vivid_sdr_fmt formats[] = {
+ {
+ .pixelformat = V4L2_SDR_FMT_CU8,
+ .buffersize = SDR_SAMPLES_PER_BUF * 2,
+ }, {
+ .pixelformat = V4L2_SDR_FMT_CS8,
+ .buffersize = SDR_SAMPLES_PER_BUF * 2,
+ },
+};
+
+static const unsigned int NUM_FORMATS = ARRAY_SIZE(formats);
+
+static const struct v4l2_frequency_band bands_adc[] = {
+ {
+ .tuner = 0,
+ .type = V4L2_TUNER_SDR,
+ .index = 0,
+ .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 300000,
+ .rangehigh = 300000,
+ },
+ {
+ .tuner = 0,
+ .type = V4L2_TUNER_SDR,
+ .index = 1,
+ .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 900001,
+ .rangehigh = 2800000,
+ },
+ {
+ .tuner = 0,
+ .type = V4L2_TUNER_SDR,
+ .index = 2,
+ .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 3200000,
+ .rangehigh = 3200000,
+ },
+};
+
+/* ADC band midpoints */
+#define BAND_ADC_0 ((bands_adc[0].rangehigh + bands_adc[1].rangelow) / 2)
+#define BAND_ADC_1 ((bands_adc[1].rangehigh + bands_adc[2].rangelow) / 2)
+
+static const struct v4l2_frequency_band bands_fm[] = {
+ {
+ .tuner = 1,
+ .type = V4L2_TUNER_RF,
+ .index = 0,
+ .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 50000000,
+ .rangehigh = 2000000000,
+ },
+};
+
+const struct vivid_sdr_fmt *vivid_sdr_get_format(struct vivid_dev *dev, u32 pixelformat)
+{
+ const struct vivid_sdr_fmt *fmt;
+ unsigned k;
+
+ for (k = 0; k < ARRAY_SIZE(formats); k++) {
+ fmt = &formats[k];
+ if (fmt->pixelformat == pixelformat)
+ return fmt;
+ }
+
+ return NULL;
+}
+
+int vivid_sdr_enum_freq_bands(struct file *file, void *fh,
+ struct v4l2_frequency_band *band)
+{
+ switch (band->tuner) {
+ case 0:
+ if (band->index >= ARRAY_SIZE(bands_adc))
+ return -EINVAL;
+ *band = bands_adc[band->index];
+ return 0;
+ case 1:
+ if (band->index >= ARRAY_SIZE(bands_fm))
+ return -EINVAL;
+ *band = bands_fm[band->index];
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+int vivid_enum_fmt_sdr(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+ if (f->index >= ARRAY_SIZE(formats))
+ return -EINVAL;
+ f->pixelformat = formats[f->index].pixelformat;
+ return 0;
+}
+
+int vivid_try_fmt_sdr(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+ const struct vivid_sdr_fmt *fmt;
+ int i;
+
+ memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
+ fmt = vivid_sdr_get_format(dev, f->fmt.sdr.pixelformat);
+ if (fmt == NULL)
+ fmt = &formats[0];
+ f->fmt.sdr.pixelformat = fmt->pixelformat;
+ f->fmt.sdr.buffersize = fmt->buffersize;
+ return 0;
+}
diff --git a/drivers/media/platform/vivid/vivid-sdr-common.h b/drivers/media/platform/vivid/vivid-sdr-common.h
new file mode 100644
index 000000000000..b9b27fafa53f
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-sdr-common.h
@@ -0,0 +1,35 @@
+/*
+ * vivid-sdr-common.h - software defined radio support functions.
+ *
+ * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_SDR_COMMON_H_
+#define _VIVID_SDR_COMMON_H_
+
+/* SDR stream formats */
+struct vivid_sdr_fmt {
+ u32 pixelformat;
+ u32 buffersize;
+};
+
+const struct vivid_sdr_fmt *vivid_sdr_get_format(struct vivid_dev *dev, u32 pixelformat);
+
+int vivid_sdr_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band);
+int vivid_enum_fmt_sdr(struct file *file, void *fh, struct v4l2_fmtdesc *f);
+int vivid_try_fmt_sdr(struct file *file, void *fh, struct v4l2_format *f);
+
+#endif
diff --git a/drivers/media/platform/vivid/vivid-sdr-out.c b/drivers/media/platform/vivid/vivid-sdr-out.c
new file mode 100644
index 000000000000..2090b5eeb29f
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-sdr-out.c
@@ -0,0 +1,499 @@
+/*
+ * vivid-sdr-out.c - software defined radio support functions.
+ *
+ * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include <linux/math64.h>
+#include <linux/videodev2.h>
+#include <linux/v4l2-dv-timings.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-dv-timings.h>
+#include <linux/fixp-arith.h>
+
+#include "vivid-core.h"
+#include "vivid-ctrls.h"
+#include "vivid-sdr-out.h"
+#include "vivid-sdr-common.h"
+
+static const struct v4l2_frequency_band bands_dac[] = {
+ {
+ .tuner = 0,
+ .type = V4L2_TUNER_SDR,
+ .index = 0,
+ .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 300000,
+ .rangehigh = 300000,
+ },
+ {
+ .tuner = 0,
+ .type = V4L2_TUNER_SDR,
+ .index = 1,
+ .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 900001,
+ .rangehigh = 2800000,
+ },
+ {
+ .tuner = 0,
+ .type = V4L2_TUNER_SDR,
+ .index = 2,
+ .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 3200000,
+ .rangehigh = 3200000,
+ },
+};
+
+/* DAC band midpoints */
+#define BAND_DAC_0 ((bands_dac[0].rangehigh + bands_dac[1].rangelow) / 2)
+#define BAND_DAC_1 ((bands_dac[1].rangehigh + bands_dac[2].rangelow) / 2)
+
+static const struct v4l2_frequency_band bands_fm[] = {
+ {
+ .tuner = 1,
+ .type = V4L2_TUNER_RF,
+ .index = 0,
+ .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 50000000,
+ .rangehigh = 2000000000,
+ },
+};
+
+static void vivid_thread_sdr_out_tick(struct vivid_dev *dev)
+{
+ struct vivid_buffer *sdr_out_buf = NULL;
+
+ dprintk(dev, 1, "SDR Capture Thread Tick\n");
+
+ /* Drop a certain percentage of buffers. */
+ if (dev->perc_dropped_buffers &&
+ prandom_u32_max(100) < dev->perc_dropped_buffers)
+ return;
+
+ spin_lock(&dev->slock);
+ if (!list_empty(&dev->sdr_out_active)) {
+ sdr_out_buf = list_entry(dev->sdr_out_active.next,
+ struct vivid_buffer, list);
+ list_del(&sdr_out_buf->list);
+ }
+ spin_unlock(&dev->slock);
+
+ if (sdr_out_buf) {
+ sdr_out_buf->vb.sequence = dev->sdr_out_seq_count;
+ vivid_sdr_out_process(dev, sdr_out_buf);
+ v4l2_get_timestamp(&sdr_out_buf->vb.timestamp);
+ sdr_out_buf->vb.timestamp.tv_sec += dev->time_wrap_offset;
+ vb2_buffer_done(&sdr_out_buf->vb.vb2_buf, dev->dqbuf_error ?
+ VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+ dev->dqbuf_error = false;
+ }
+}
+
+static int vivid_thread_sdr_out(void *data)
+{
+ struct vivid_dev *dev = data;
+ u64 samples_since_start;
+ u64 buffers_since_start;
+ u64 next_jiffies_since_start;
+ unsigned long jiffies_since_start;
+ unsigned long cur_jiffies;
+ unsigned wait_jiffies;
+
+ dprintk(dev, 1, "SDR Capture Thread Start\n");
+
+ set_freezable();
+
+ /* Resets frame counters */
+ dev->sdr_out_seq_offset = 0;
+ if (dev->seq_wrap)
+ dev->sdr_out_seq_offset = 0xffffff80U;
+ dev->jiffies_sdr_out = jiffies;
+ dev->sdr_out_seq_resync = false;
+
+ for (;;) {
+ try_to_freeze();
+ if (kthread_should_stop())
+ break;
+
+ mutex_lock(&dev->mutex);
+ cur_jiffies = jiffies;
+ if (dev->sdr_out_seq_resync) {
+ dev->jiffies_sdr_out = cur_jiffies;
+ dev->sdr_out_seq_offset = dev->sdr_out_seq_count + 1;
+ dev->sdr_out_seq_count = 0;
+ dev->sdr_out_seq_resync = false;
+ }
+ /* Calculate the number of jiffies since we started streaming */
+ jiffies_since_start = cur_jiffies - dev->jiffies_sdr_out;
+ /* Get the number of buffers streamed since the start */
+ buffers_since_start =
+ (u64)jiffies_since_start * dev->sdr_out_dac_freq +
+ (HZ * SDR_SAMPLES_PER_BUF) / 2;
+ do_div(buffers_since_start, HZ * SDR_SAMPLES_PER_BUF);
+
+ /*
+ * After more than 0xf0000000 (rounded down to a multiple of
+ * 'jiffies-per-day' to ease jiffies_to_msecs calculation)
+ * jiffies have passed since we started streaming reset the
+ * counters and keep track of the sequence offset.
+ */
+ if (jiffies_since_start > JIFFIES_RESYNC) {
+ dev->jiffies_sdr_out = cur_jiffies;
+ dev->sdr_out_seq_offset = buffers_since_start;
+ buffers_since_start = 0;
+ }
+ dev->sdr_out_seq_count =
+ buffers_since_start + dev->sdr_out_seq_offset;
+
+ vivid_thread_sdr_out_tick(dev);
+ mutex_unlock(&dev->mutex);
+
+ /*
+ * Calculate the number of samples streamed since we started,
+ * not including the current buffer.
+ */
+ samples_since_start = buffers_since_start * SDR_SAMPLES_PER_BUF;
+
+ /* And the number of jiffies since we started */
+ jiffies_since_start = jiffies - dev->jiffies_sdr_out;
+
+ /* Increase by the number of samples in one buffer */
+ samples_since_start += SDR_SAMPLES_PER_BUF;
+ /*
+ * Calculate when that next buffer is supposed to start
+ * in jiffies since we started streaming.
+ */
+ next_jiffies_since_start = samples_since_start * HZ +
+ dev->sdr_out_dac_freq / 2;
+ do_div(next_jiffies_since_start, dev->sdr_out_dac_freq);
+ /* If it is in the past, then just schedule asap */
+ if (next_jiffies_since_start < jiffies_since_start)
+ next_jiffies_since_start = jiffies_since_start;
+
+ wait_jiffies = next_jiffies_since_start - jiffies_since_start;
+ schedule_timeout_interruptible(wait_jiffies ? wait_jiffies : 1);
+ }
+ dprintk(dev, 1, "SDR Capture Thread End\n");
+ return 0;
+}
+
+static int sdr_out_queue_setup(struct vb2_queue *vq, const void *parg,
+ unsigned *nbuffers, unsigned *nplanes,
+ unsigned sizes[], void *alloc_ctxs[])
+{
+ /* 2 = max 16-bit sample returned */
+ sizes[0] = SDR_SAMPLES_PER_BUF * 2;
+ *nplanes = 1;
+ return 0;
+}
+
+static int sdr_out_buf_prepare(struct vb2_buffer *vb)
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+ unsigned size = SDR_SAMPLES_PER_BUF * 2;
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ if (dev->buf_prepare_error) {
+ /*
+ * Error injection: test what happens if buf_prepare() returns
+ * an error.
+ */
+ dev->buf_prepare_error = false;
+ return -EINVAL;
+ }
+ if (vb2_plane_size(vb, 0) < size) {
+ dprintk(dev, 1, "%s data will not fit into plane (%lu < %u)\n",
+ __func__, vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
+ vb2_set_plane_payload(vb, 0, size);
+
+ return 0;
+}
+
+static void sdr_out_buf_queue(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct vivid_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
+ struct vivid_buffer *buf = container_of(vbuf, struct vivid_buffer, vb);
+
+ dprintk(dev, 1, "%s\n", __func__);
+
+ spin_lock(&dev->slock);
+ list_add_tail(&buf->list, &dev->sdr_out_active);
+ spin_unlock(&dev->slock);
+}
+
+static int sdr_out_start_streaming(struct vb2_queue *vq, unsigned count)
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vq);
+ int err = 0;
+
+ dprintk(dev, 1, "%s\n", __func__);
+ dev->sdr_out_seq_count = 0;
+ if (dev->start_streaming_error) {
+ dev->start_streaming_error = false;
+ err = -EINVAL;
+ } else if (dev->kthread_sdr_out == NULL) {
+ dev->kthread_sdr_out = kthread_run(vivid_thread_sdr_out, dev,
+ "%s-sdr-out", dev->v4l2_dev.name);
+
+ if (IS_ERR(dev->kthread_sdr_out)) {
+ v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
+ err = PTR_ERR(dev->kthread_sdr_out);
+ dev->kthread_sdr_out = NULL;
+ }
+ }
+ if (err) {
+ struct vivid_buffer *buf, *tmp;
+
+ list_for_each_entry_safe(buf, tmp, &dev->sdr_out_active, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb.vb2_buf,
+ VB2_BUF_STATE_QUEUED);
+ }
+ }
+ return err;
+}
+
+/* abort streaming and wait for last buffer */
+static void sdr_out_stop_streaming(struct vb2_queue *vq)
+{
+ struct vivid_dev *dev = vb2_get_drv_priv(vq);
+
+ if (dev->kthread_sdr_out == NULL)
+ return;
+
+ while (!list_empty(&dev->sdr_out_active)) {
+ struct vivid_buffer *buf;
+
+ buf = list_entry(dev->sdr_out_active.next,
+ struct vivid_buffer, list);
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
+
+ /* shutdown control thread */
+ mutex_unlock(&dev->mutex);
+ kthread_stop(dev->kthread_sdr_out);
+ dev->kthread_sdr_out = NULL;
+ mutex_lock(&dev->mutex);
+}
+
+const struct vb2_ops vivid_sdr_out_qops = {
+ .queue_setup = sdr_out_queue_setup,
+ .buf_prepare = sdr_out_buf_prepare,
+ .buf_queue = sdr_out_buf_queue,
+ .start_streaming = sdr_out_start_streaming,
+ .stop_streaming = sdr_out_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+int vivid_sdr_out_g_frequency(struct file *file, void *fh,
+ struct v4l2_frequency *vf)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+
+ switch (vf->tuner) {
+ case 0:
+ vf->frequency = dev->sdr_out_dac_freq;
+ vf->type = V4L2_TUNER_SDR;
+ return 0;
+ case 1:
+ vf->frequency = dev->sdr_out_fm_freq;
+ vf->type = V4L2_TUNER_RF;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+int vivid_sdr_out_s_frequency(struct file *file, void *fh,
+ const struct v4l2_frequency *vf)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+ unsigned freq = vf->frequency;
+ unsigned band;
+
+ switch (vf->tuner) {
+ case 0:
+ if (vf->type != V4L2_TUNER_SDR)
+ return -EINVAL;
+ if (freq < BAND_DAC_0)
+ band = 0;
+ else if (freq < BAND_DAC_1)
+ band = 1;
+ else
+ band = 2;
+
+ freq = clamp_t(unsigned, freq,
+ bands_dac[band].rangelow,
+ bands_dac[band].rangehigh);
+
+ if (vb2_is_streaming(&dev->vb_sdr_out_q) &&
+ freq != dev->sdr_out_dac_freq) {
+ /* resync the thread's timings */
+ dev->sdr_out_seq_resync = true;
+ }
+ dev->sdr_out_dac_freq = freq;
+ return 0;
+ case 1:
+ if (vf->type != V4L2_TUNER_RF)
+ return -EINVAL;
+ dev->sdr_out_fm_freq = clamp_t(unsigned, freq,
+ bands_fm[0].rangelow,
+ bands_fm[0].rangehigh);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+int vivid_sdr_g_modulator(struct file *file, void *fh, struct v4l2_modulator *mt)
+{
+ switch (mt->index) {
+ case 0:
+ strlcpy(mt->name, "DAC", sizeof(mt->name));
+ mt->type = V4L2_TUNER_SDR;
+ mt->capability =
+ V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+ mt->rangelow = bands_dac[0].rangelow;
+ mt->rangehigh = bands_dac[2].rangehigh;
+ return 0;
+ case 1:
+ strlcpy(mt->name, "RF", sizeof(mt->name));
+ mt->type = V4L2_TUNER_RF;
+ mt->capability =
+ V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+ mt->rangelow = bands_fm[0].rangelow;
+ mt->rangehigh = bands_fm[0].rangehigh;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+int vivid_sdr_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *mt)
+{
+ if (mt->index > 1)
+ return -EINVAL;
+ return 0;
+}
+
+int vidioc_g_fmt_sdr_out(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+ const struct vivid_sdr_fmt *fmt;
+
+ fmt = vivid_sdr_get_format(dev, dev->sdr_out_pixelformat);
+ f->fmt.sdr.pixelformat = fmt->pixelformat;
+ f->fmt.sdr.buffersize = fmt->buffersize;
+ memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
+ return 0;
+}
+
+int vidioc_s_fmt_sdr_out(struct file *file, void *fh, struct v4l2_format *f)
+{
+ struct vivid_dev *dev = video_drvdata(file);
+ struct vb2_queue *q = &dev->vb_sdr_out_q;
+ const struct vivid_sdr_fmt *fmt;
+
+ if (vb2_is_busy(q))
+ return -EBUSY;
+
+ vivid_try_fmt_sdr(file, fh, f);
+ fmt = vivid_sdr_get_format(dev, dev->sdr_cap_pixelformat);
+ dev->sdr_out_pixelformat = fmt->pixelformat;
+ return 0;
+}
+
+#define FIXP_N (15)
+#define FIXP_FRAC (1 << FIXP_N)
+#define FIXP_2PI ((int)(2 * 3.141592653589 * FIXP_FRAC))
+#define M_100000PI (3.14159 * 100000)
+
+void vivid_sdr_out_process(struct vivid_dev *dev, struct vivid_buffer *buf)
+{
+ u8 *vbuf = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
+ unsigned long i;
+ unsigned long plane_size = vb2_plane_size(&buf->vb.vb2_buf, 0);
+ s64 s64tmp;
+ s32 src_phase_step;
+ s32 mod_phase_step;
+ s32 fixp_i;
+ s32 fixp_q;
+
+ /* calculate phase step */
+ #define BEEP_FREQ 1000 /* 1kHz beep */
+ src_phase_step = DIV_ROUND_CLOSEST(FIXP_2PI * BEEP_FREQ,
+ dev->sdr_out_dac_freq);
+
+ for (i = 0; i < plane_size; i += 2) {
+ mod_phase_step = fixp_cos32_rad(dev->sdr_fixp_src_phase,
+ FIXP_2PI) >> (31 - FIXP_N);
+
+ dev->sdr_fixp_src_phase += src_phase_step;
+ s64tmp = (s64) mod_phase_step * dev->sdr_fm_deviation;
+ dev->sdr_fixp_mod_phase += div_s64(s64tmp, M_100000PI);
+
+ /*
+ * Transfer phase angle to [0, 2xPI] in order to avoid variable
+ * overflow and make it suitable for cosine implementation
+ * used, which does not support negative angles.
+ */
+ dev->sdr_fixp_src_phase %= FIXP_2PI;
+ dev->sdr_fixp_mod_phase %= FIXP_2PI;
+
+ if (dev->sdr_fixp_mod_phase < 0)
+ dev->sdr_fixp_mod_phase += FIXP_2PI;
+
+ fixp_i = fixp_cos32_rad(dev->sdr_fixp_mod_phase, FIXP_2PI);
+ fixp_q = fixp_sin32_rad(dev->sdr_fixp_mod_phase, FIXP_2PI);
+
+ /* Normalize fraction values represented with 32 bit precision
+ * to fixed point representation with FIXP_N bits */
+ fixp_i >>= (31 - FIXP_N);
+ fixp_q >>= (31 - FIXP_N);
+
+ switch (dev->sdr_out_pixelformat) {
+ case V4L2_SDR_FMT_CU8:
+ /* convert 'fixp float' to u8 [0, +255] */
+ /* u8 = X * 127.5 + 127.5; X is float [-1.0, +1.0] */
+ fixp_i = fixp_i * 1275 + FIXP_FRAC * 1275;
+ fixp_q = fixp_q * 1275 + FIXP_FRAC * 1275;
+ *vbuf++ = DIV_ROUND_CLOSEST(fixp_i, FIXP_FRAC * 10);
+ *vbuf++ = DIV_ROUND_CLOSEST(fixp_q, FIXP_FRAC * 10);
+ break;
+ case V4L2_SDR_FMT_CS8:
+ /* convert 'fixp float' to s8 [-128, +127] */
+ /* s8 = X * 127.5 - 0.5; X is float [-1.0, +1.0] */
+ fixp_i = fixp_i * 1275 - FIXP_FRAC * 5;
+ fixp_q = fixp_q * 1275 - FIXP_FRAC * 5;
+ *vbuf++ = DIV_ROUND_CLOSEST(fixp_i, FIXP_FRAC * 10);
+ *vbuf++ = DIV_ROUND_CLOSEST(fixp_q, FIXP_FRAC * 10);
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/drivers/media/platform/vivid/vivid-sdr-out.h b/drivers/media/platform/vivid/vivid-sdr-out.h
new file mode 100644
index 000000000000..ae973d86cd70
--- /dev/null
+++ b/drivers/media/platform/vivid/vivid-sdr-out.h
@@ -0,0 +1,33 @@
+/*
+ * vivid-sdr-out.h - software defined radio support functions.
+ *
+ * Copyright 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *
+ * This program is free software; you may redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VIVID_SDR_OUT_H_
+#define _VIVID_SDR_OUT_H_
+
+int vivid_sdr_out_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
+int vivid_sdr_out_s_frequency(struct file *file, void *fh, const struct v4l2_frequency *vf);
+int vivid_sdr_g_modulator(struct file *file, void *fh, struct v4l2_modulator *mt);
+int vivid_sdr_s_modulator(struct file *file, void *fh, const struct v4l2_modulator *mt);
+int vidioc_g_fmt_sdr_out(struct file *file, void *fh, struct v4l2_format *f);
+int vidioc_s_fmt_sdr_out(struct file *file, void *fh, struct v4l2_format *f);
+void vivid_sdr_out_process(struct vivid_dev *dev, struct vivid_buffer *buf);
+
+extern const struct vb2_ops vivid_sdr_out_qops;
+
+#endif

Privacy Policy