* [PATCH 1/6] rtl2832_sdr: convert to SDR API
2013-12-29 4:51 [PATCH 0/6] convert drivers to SDR API Antti Palosaari
@ 2013-12-29 4:51 ` Antti Palosaari
2013-12-29 4:51 ` [PATCH 2/6] msi3101: " Antti Palosaari
` (4 subsequent siblings)
5 siblings, 0 replies; 11+ messages in thread
From: Antti Palosaari @ 2013-12-29 4:51 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Antti Palosaari
It was abusing video device API. Use SDR API instead.
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c | 387 +++++++++++++----------
1 file changed, 223 insertions(+), 164 deletions(-)
diff --git a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
index 4b8c016..a26125c 100644
--- a/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
+++ b/drivers/staging/media/rtl2832u_sdr/rtl2832_sdr.c
@@ -20,12 +20,6 @@
* GNU Radio plugin "gr-kernel" for device usage will be on:
* http://git.linuxtv.org/anttip/gr-kernel.git
*
- * TODO:
- * Help is very highly welcome for these + all the others you could imagine:
- * - move controls to V4L2 API
- * - use libv4l2 for stream format conversions
- * - gr-kernel: switch to v4l2_mmap (current read eats a lot of cpu)
- * - SDRSharp support
*/
#include "dvb_frontend.h"
@@ -38,22 +32,75 @@
#include <media/v4l2-event.h>
#include <media/videobuf2-vmalloc.h>
+#include <linux/jiffies.h>
#include <linux/math64.h>
/* TODO: These should be moved to V4L2 API */
-#define RTL2832_SDR_CID_SAMPLING_MODE ((V4L2_CID_USER_BASE | 0xf000) + 0)
-#define RTL2832_SDR_CID_SAMPLING_RATE ((V4L2_CID_USER_BASE | 0xf000) + 1)
-#define RTL2832_SDR_CID_SAMPLING_RESOLUTION ((V4L2_CID_USER_BASE | 0xf000) + 2)
-#define RTL2832_SDR_CID_TUNER_RF ((V4L2_CID_USER_BASE | 0xf000) + 10)
#define RTL2832_SDR_CID_TUNER_BW ((V4L2_CID_USER_BASE | 0xf000) + 11)
-#define RTL2832_SDR_CID_TUNER_IF ((V4L2_CID_USER_BASE | 0xf000) + 12)
#define RTL2832_SDR_CID_TUNER_GAIN ((V4L2_CID_USER_BASE | 0xf000) + 13)
-#define V4L2_PIX_FMT_SDR_U8 v4l2_fourcc('D', 'U', '0', '8') /* unsigned 8-bit */
+#define V4L2_PIX_FMT_SDR_U8 v4l2_fourcc('D', 'U', '0', '8')
+#define V4L2_PIX_FMT_SDR_U16LE v4l2_fourcc('D', 'U', '1', '6')
#define MAX_BULK_BUFS (10)
#define BULK_BUFFER_SIZE (128 * 512)
+static const struct v4l2_frequency_band bands_adc[] = {
+ {
+ .tuner = 0,
+ .type = V4L2_TUNER_ADC,
+ .index = 0,
+ .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 300000,
+ .rangehigh = 300000,
+ },
+ {
+ .tuner = 0,
+ .type = V4L2_TUNER_ADC,
+ .index = 1,
+ .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 900001,
+ .rangehigh = 2800000,
+ },
+ {
+ .tuner = 0,
+ .type = V4L2_TUNER_ADC,
+ .index = 2,
+ .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 3200000,
+ .rangehigh = 3200000,
+ },
+};
+
+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,
+ },
+};
+
+/* stream formats */
+struct rtl2832_sdr_format {
+ char *name;
+ u32 pixelformat;
+};
+
+static struct rtl2832_sdr_format formats[] = {
+ {
+ .name = "8-bit unsigned",
+ .pixelformat = V4L2_PIX_FMT_SDR_U8,
+ }, {
+ .name = "16-bit unsigned little endian",
+ .pixelformat = V4L2_PIX_FMT_SDR_U16LE,
+ },
+};
+
+static const unsigned int NUM_FORMATS = ARRAY_SIZE(formats);
+
/* intermediate buffers with raw data from the USB device */
struct rtl2832_sdr_frame_buf {
struct vb2_buffer vb; /* common v4l buffer stuff -- must be first */
@@ -96,18 +143,18 @@ struct rtl2832_sdr_state {
int urbs_initialized;
int urbs_submitted;
+ unsigned int f_adc, f_tuner;
+ u32 pixelformat;
+
/* Controls */
struct v4l2_ctrl_handler ctrl_handler;
- struct v4l2_ctrl *ctrl_sampling_rate;
- struct v4l2_ctrl *ctrl_tuner_rf;
struct v4l2_ctrl *ctrl_tuner_bw;
- struct v4l2_ctrl *ctrl_tuner_if;
struct v4l2_ctrl *ctrl_tuner_gain;
/* for sample rate calc */
unsigned int sample;
unsigned int sample_measured;
- unsigned long jiffies;
+ unsigned long jiffies_next;
};
/* write multiple hardware registers */
@@ -292,27 +339,41 @@ leave:
}
static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_state *s,
- u8 *dst, const u8 *src, unsigned int src_len)
+ void *dst, const u8 *src, unsigned int src_len)
{
- memcpy(dst, src, src_len);
+ unsigned int dst_len;
+
+ if (s->pixelformat == V4L2_PIX_FMT_SDR_U8) {
+ /* native stream, no need to convert */
+ memcpy(dst, src, src_len);
+ dst_len = src_len;
+ } else if (s->pixelformat == V4L2_PIX_FMT_SDR_U16LE) {
+ /* convert u8 to u16 */
+ unsigned int i;
+ u16 *u16dst = dst;
+ for (i = 0; i < src_len; i++)
+ *u16dst++ = (src[i] << 8) | (src[i] >> 0);
+ dst_len = 2 * src_len;
+ } else {
+ dst_len = 0;
+ }
/* calculate samping rate and output it in 10 seconds intervals */
- if ((s->jiffies + msecs_to_jiffies(10000)) <= jiffies) {
- unsigned long jiffies_now = jiffies;
- unsigned long msecs = jiffies_to_msecs(jiffies_now) - jiffies_to_msecs(s->jiffies);
+ if (unlikely(time_is_before_jiffies(s->jiffies_next))) {
+#define MSECS 10000UL
unsigned int samples = s->sample - s->sample_measured;
- s->jiffies = jiffies_now;
+ s->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
s->sample_measured = s->sample;
dev_dbg(&s->udev->dev,
"slen=%d samples=%u msecs=%lu sampling rate=%lu\n",
- src_len, samples, msecs,
- samples * 1000UL / msecs);
+ src_len, samples, MSECS,
+ samples * 1000UL / MSECS);
}
/* total number of I+Q pairs */
s->sample += src_len / 2;
- return src_len;
+ return dst_len;
}
/*
@@ -343,12 +404,12 @@ static void rtl2832_sdr_urb_complete(struct urb *urb)
break;
}
- if (urb->actual_length > 0) {
+ if (likely(urb->actual_length > 0)) {
void *ptr;
unsigned int len;
/* get free framebuffer */
fbuf = rtl2832_sdr_get_next_fill_buf(s);
- if (fbuf == NULL) {
+ if (unlikely(fbuf == NULL)) {
s->vb_full++;
dev_notice_ratelimited(&s->udev->dev,
"videobuf is full, %d packets dropped\n",
@@ -544,7 +605,7 @@ static int rtl2832_sdr_querycap(struct file *file, void *fh,
strlcpy(cap->card, s->vdev.name, sizeof(cap->card));
usb_make_path(s->udev, cap->bus_info, sizeof(cap->bus_info));
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE;
+ V4L2_CAP_READWRITE | V4L2_CAP_TUNER;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -560,7 +621,8 @@ static int rtl2832_sdr_queue_setup(struct vb2_queue *vq,
/* Absolute min and max number of buffers available for mmap() */
*nbuffers = 32;
*nplanes = 1;
- sizes[0] = PAGE_ALIGN(BULK_BUFFER_SIZE * 4); /* 8 * 512 * 4 = 16384 */
+ /* 2 = max 16-bit sample returned */
+ sizes[0] = PAGE_ALIGN(BULK_BUFFER_SIZE * 2);
dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n",
__func__, *nbuffers, sizes[0]);
return 0;
@@ -609,7 +671,10 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s)
if (!test_bit(POWER_ON, &s->flags))
return 0;
- f_sr = s->ctrl_sampling_rate->val64;
+ if (s->f_adc == 0)
+ return 0;
+
+ f_sr = s->f_adc;
ret = rtl2832_sdr_wr_regs(s, 0x13e, "\x00\x00", 2);
ret = rtl2832_sdr_wr_regs(s, 0x115, "\x00", 1);
@@ -788,17 +853,15 @@ static int rtl2832_sdr_set_tuner(struct rtl2832_sdr_state *s)
struct dvb_frontend *fe = s->fe;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- unsigned int f_rf = s->ctrl_tuner_rf->val64;
-
/*
- * bandwidth (Hz)
+ * tuner RF (Hz)
*/
- unsigned int bandwidth = s->ctrl_tuner_bw->val;
+ unsigned int f_rf = s->f_tuner;
/*
- * intermediate frequency (Hz)
+ * bandwidth (Hz)
*/
- unsigned int f_if = s->ctrl_tuner_if->val;
+ unsigned int bandwidth = s->ctrl_tuner_bw->val;
/*
* gain (dB)
@@ -806,8 +869,11 @@ static int rtl2832_sdr_set_tuner(struct rtl2832_sdr_state *s)
int gain = s->ctrl_tuner_gain->val;
dev_dbg(&s->udev->dev,
- "%s: f_rf=%u bandwidth=%d f_if=%u gain=%d\n",
- __func__, f_rf, bandwidth, f_if, gain);
+ "%s: f_rf=%u bandwidth=%d gain=%d\n",
+ __func__, f_rf, bandwidth, gain);
+
+ if (f_rf == 0)
+ return 0;
if (!test_bit(POWER_ON, &s->flags))
return 0;
@@ -913,123 +979,182 @@ static struct vb2_ops rtl2832_sdr_vb2_ops = {
.wait_finish = vb2_ops_wait_finish,
};
-static int rtl2832_sdr_enum_input(struct file *file, void *fh, struct v4l2_input *i)
+static int rtl2832_sdr_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
{
- if (i->index != 0)
+ struct rtl2832_sdr_state *s = video_drvdata(file);
+ dev_dbg(&s->udev->dev, "%s: index=%d type=%d\n",
+ __func__, v->index, v->type);
+
+ if (v->index == 0) {
+ strlcpy(v->name, "ADC: Realtek RTL2832", sizeof(v->name));
+ v->type = V4L2_TUNER_ADC;
+ v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+ v->rangelow = 300000;
+ v->rangehigh = 3200000;
+ } else if (v->index == 1) {
+ strlcpy(v->name, "RF: <unknown>", sizeof(v->name));
+ v->type = V4L2_TUNER_RF;
+ v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+ v->rangelow = 50000000;
+ v->rangehigh = 2000000000;
+ } else {
return -EINVAL;
-
- strlcpy(i->name, "SDR data", sizeof(i->name));
- i->type = V4L2_INPUT_TYPE_CAMERA;
+ }
return 0;
}
-static int rtl2832_sdr_g_input(struct file *file, void *fh, unsigned int *i)
+static int rtl2832_sdr_s_tuner(struct file *file, void *priv,
+ const struct v4l2_tuner *v)
{
- *i = 0;
+ struct rtl2832_sdr_state *s = video_drvdata(file);
+ dev_dbg(&s->udev->dev, "%s:\n", __func__);
return 0;
}
-static int rtl2832_sdr_s_input(struct file *file, void *fh, unsigned int i)
-{
- return i ? -EINVAL : 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
- const struct v4l2_tuner *v)
+static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv,
+ struct v4l2_frequency_band *band)
{
struct rtl2832_sdr_state *s = video_drvdata(file);
- dev_dbg(&s->udev->dev, "%s:\n", __func__);
+ dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n",
+ __func__, band->tuner, band->type, band->index);
+
+ if (band->tuner == 0) {
+ if (band->index >= ARRAY_SIZE(bands_adc))
+ return -EINVAL;
+
+ *band = bands_adc[band->index];
+ } else if (band->tuner == 1) {
+ if (band->index >= ARRAY_SIZE(bands_fm))
+ return -EINVAL;
+
+ *band = bands_fm[band->index];
+ } else {
+ return -EINVAL;
+ }
return 0;
}
-static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
+static int rtl2832_sdr_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
{
struct rtl2832_sdr_state *s = video_drvdata(file);
- dev_dbg(&s->udev->dev, "%s:\n", __func__);
-
- strcpy(v->name, "SDR RX");
- v->capability = V4L2_TUNER_CAP_LOW;
+ int ret = 0;
+ dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n",
+ __func__, f->tuner, f->type);
+
+ if (f->tuner == 0)
+ f->frequency = s->f_adc;
+ else if (f->tuner == 1)
+ f->frequency = s->f_tuner;
+ else
+ return -EINVAL;
- return 0;
+ return ret;
}
-static int vidioc_s_frequency(struct file *file, void *priv,
+static int rtl2832_sdr_s_frequency(struct file *file, void *priv,
const struct v4l2_frequency *f)
{
struct rtl2832_sdr_state *s = video_drvdata(file);
- dev_dbg(&s->udev->dev, "%s: frequency=%lu Hz (%u)\n",
- __func__, f->frequency * 625UL / 10UL, f->frequency);
+ int ret;
+ dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n",
+ __func__, f->tuner, f->type, f->frequency);
- return v4l2_ctrl_s_ctrl_int64(s->ctrl_tuner_rf,
- f->frequency * 625UL / 10UL);
+ if (f->tuner == 0) {
+ s->f_adc = f->frequency;
+ dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n",
+ __func__, s->f_adc);
+ ret = rtl2832_sdr_set_adc(s);
+ } else if (f->tuner == 1) {
+ s->f_tuner = f->frequency;
+ dev_dbg(&s->udev->dev, "%s: RF frequency=%u Hz\n",
+ __func__, f->frequency);
+ ret = rtl2832_sdr_set_tuner(s);
+ } else {
+ return -EINVAL;
+ }
+
+ return ret;
}
-static int rtl2832_sdr_enum_fmt_vid_cap(struct file *file, void *priv,
+static int rtl2832_sdr_enum_fmt_sdr_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
struct rtl2832_sdr_state *s = video_drvdata(file);
dev_dbg(&s->udev->dev, "%s:\n", __func__);
- if (f->index > 0)
+ if (f->index >= NUM_FORMATS)
return -EINVAL;
- f->flags = 0;
- strcpy(f->description, "I/Q 8-bit unsigned");
- f->pixelformat = V4L2_PIX_FMT_SDR_U8;
+ strlcpy(f->description, formats[f->index].name, sizeof(f->description));
+ f->pixelformat = formats[f->index].pixelformat;
return 0;
}
-static int rtl2832_sdr_g_fmt_vid_cap(struct file *file, void *priv,
+static int rtl2832_sdr_g_fmt_sdr_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct rtl2832_sdr_state *s = video_drvdata(file);
dev_dbg(&s->udev->dev, "%s:\n", __func__);
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (f->type != V4L2_BUF_TYPE_SDR_CAPTURE)
return -EINVAL;
- memset(&f->fmt.pix, 0, sizeof(f->fmt.pix));
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_SDR_U8;
+ f->fmt.sdr.pixelformat = s->pixelformat;
return 0;
}
-static int rtl2832_sdr_s_fmt_vid_cap(struct file *file, void *priv,
+static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct rtl2832_sdr_state *s = video_drvdata(file);
struct vb2_queue *q = &s->vb_queue;
+ int i;
dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
- (char *)&f->fmt.pix.pixelformat);
+ (char *)&f->fmt.sdr.pixelformat);
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (f->type != V4L2_BUF_TYPE_SDR_CAPTURE)
return -EINVAL;
if (vb2_is_busy(q))
return -EBUSY;
- memset(&f->fmt.pix, 0, sizeof(f->fmt.pix));
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_SDR_U8;
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
+ s->pixelformat = f->fmt.sdr.pixelformat;
+ return 0;
+ }
+ }
+
+ f->fmt.sdr.pixelformat = formats[0].pixelformat;
+ s->pixelformat = formats[0].pixelformat;
return 0;
}
-static int rtl2832_sdr_try_fmt_vid_cap(struct file *file, void *priv,
+static int rtl2832_sdr_try_fmt_sdr_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct rtl2832_sdr_state *s = video_drvdata(file);
+ int i;
dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
- (char *)&f->fmt.pix.pixelformat);
+ (char *)&f->fmt.sdr.pixelformat);
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (f->type != V4L2_BUF_TYPE_SDR_CAPTURE)
return -EINVAL;
- memset(&f->fmt.pix, 0, sizeof(f->fmt.pix));
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_SDR_U8;
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (formats[i].pixelformat == f->fmt.sdr.pixelformat)
+ return 0;
+ }
+
+ f->fmt.sdr.pixelformat = formats[0].pixelformat;
return 0;
}
@@ -1037,14 +1162,10 @@ static int rtl2832_sdr_try_fmt_vid_cap(struct file *file, void *priv,
static const struct v4l2_ioctl_ops rtl2832_sdr_ioctl_ops = {
.vidioc_querycap = rtl2832_sdr_querycap,
- .vidioc_enum_fmt_vid_cap = rtl2832_sdr_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = rtl2832_sdr_g_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = rtl2832_sdr_s_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = rtl2832_sdr_try_fmt_vid_cap,
-
- .vidioc_enum_input = rtl2832_sdr_enum_input,
- .vidioc_g_input = rtl2832_sdr_g_input,
- .vidioc_s_input = rtl2832_sdr_s_input,
+ .vidioc_enum_fmt_sdr_cap = rtl2832_sdr_enum_fmt_sdr_cap,
+ .vidioc_g_fmt_sdr_cap = rtl2832_sdr_g_fmt_sdr_cap,
+ .vidioc_s_fmt_sdr_cap = rtl2832_sdr_s_fmt_sdr_cap,
+ .vidioc_try_fmt_sdr_cap = rtl2832_sdr_try_fmt_sdr_cap,
.vidioc_reqbufs = vb2_ioctl_reqbufs,
.vidioc_create_bufs = vb2_ioctl_create_bufs,
@@ -1056,9 +1177,12 @@ static const struct v4l2_ioctl_ops rtl2832_sdr_ioctl_ops = {
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_g_tuner = rtl2832_sdr_g_tuner,
+ .vidioc_s_tuner = rtl2832_sdr_s_tuner,
+
+ .vidioc_enum_freq_bands = rtl2832_sdr_enum_freq_bands,
+ .vidioc_g_frequency = rtl2832_sdr_g_frequency,
+ .vidioc_s_frequency = rtl2832_sdr_s_frequency,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
@@ -1076,7 +1200,7 @@ static const struct v4l2_file_operations rtl2832_sdr_fops = {
};
static struct video_device rtl2832_sdr_template = {
- .name = "Realtek RTL2832U SDR",
+ .name = "Realtek RTL2832 SDR",
.release = video_device_release_empty,
.fops = &rtl2832_sdr_fops,
.ioctl_ops = &rtl2832_sdr_ioctl_ops,
@@ -1094,14 +1218,7 @@ static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl)
ctrl->minimum, ctrl->maximum, ctrl->step);
switch (ctrl->id) {
- case RTL2832_SDR_CID_SAMPLING_MODE:
- case RTL2832_SDR_CID_SAMPLING_RATE:
- case RTL2832_SDR_CID_SAMPLING_RESOLUTION:
- ret = rtl2832_sdr_set_adc(s);
- break;
- case RTL2832_SDR_CID_TUNER_RF:
case RTL2832_SDR_CID_TUNER_BW:
- case RTL2832_SDR_CID_TUNER_IF:
case RTL2832_SDR_CID_TUNER_GAIN:
ret = rtl2832_sdr_set_tuner(s);
break;
@@ -1132,49 +1249,6 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
int ret;
struct rtl2832_sdr_state *s;
struct dvb_usb_device *d = i2c_get_adapdata(i2c);
- static const char * const ctrl_sampling_mode_qmenu_strings[] = {
- "Quadrature Sampling",
- NULL,
- };
- static const struct v4l2_ctrl_config ctrl_sampling_mode = {
- .ops = &rtl2832_sdr_ctrl_ops,
- .id = RTL2832_SDR_CID_SAMPLING_MODE,
- .type = V4L2_CTRL_TYPE_MENU,
- .flags = V4L2_CTRL_FLAG_INACTIVE,
- .name = "Sampling Mode",
- .qmenu = ctrl_sampling_mode_qmenu_strings,
- };
- static const struct v4l2_ctrl_config ctrl_sampling_rate = {
- .ops = &rtl2832_sdr_ctrl_ops,
- .id = RTL2832_SDR_CID_SAMPLING_RATE,
- .type = V4L2_CTRL_TYPE_INTEGER64,
- .name = "Sampling Rate",
- .min = 900001,
- .max = 2800000,
- .def = 2048000,
- .step = 1,
- };
- static const struct v4l2_ctrl_config ctrl_sampling_resolution = {
- .ops = &rtl2832_sdr_ctrl_ops,
- .id = RTL2832_SDR_CID_SAMPLING_RESOLUTION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .flags = V4L2_CTRL_FLAG_INACTIVE,
- .name = "Sampling Resolution",
- .min = 8,
- .max = 8,
- .def = 8,
- .step = 1,
- };
- static const struct v4l2_ctrl_config ctrl_tuner_rf = {
- .ops = &rtl2832_sdr_ctrl_ops,
- .id = RTL2832_SDR_CID_TUNER_RF,
- .type = V4L2_CTRL_TYPE_INTEGER64,
- .name = "Tuner RF",
- .min = 40000000,
- .max = 2000000000,
- .def = 100000000,
- .step = 1,
- };
static const struct v4l2_ctrl_config ctrl_tuner_bw = {
.ops = &rtl2832_sdr_ctrl_ops,
.id = RTL2832_SDR_CID_TUNER_BW,
@@ -1185,17 +1259,6 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
.def = 600000,
.step = 1,
};
- static const struct v4l2_ctrl_config ctrl_tuner_if = {
- .ops = &rtl2832_sdr_ctrl_ops,
- .id = RTL2832_SDR_CID_TUNER_IF,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .flags = V4L2_CTRL_FLAG_INACTIVE,
- .name = "Tuner IF",
- .min = 0,
- .max = 10,
- .def = 0,
- .step = 1,
- };
static const struct v4l2_ctrl_config ctrl_tuner_gain = {
.ops = &rtl2832_sdr_ctrl_ops,
.id = RTL2832_SDR_CID_TUNER_GAIN,
@@ -1227,7 +1290,7 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
INIT_LIST_HEAD(&s->queued_bufs);
/* Init videobuf2 queue structure */
- s->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ s->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
s->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
s->vb_queue.drv_priv = s;
s->vb_queue.buf_struct_size = sizeof(struct rtl2832_sdr_frame_buf);
@@ -1248,13 +1311,8 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
video_set_drvdata(&s->vdev, s);
/* Register controls */
- v4l2_ctrl_handler_init(&s->ctrl_handler, 7);
- v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_sampling_mode, NULL);
- s->ctrl_sampling_rate = v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_sampling_rate, NULL);
- v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_sampling_resolution, NULL);
- s->ctrl_tuner_rf = v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_tuner_rf, NULL);
+ v4l2_ctrl_handler_init(&s->ctrl_handler, 2);
s->ctrl_tuner_bw = v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_tuner_bw, NULL);
- s->ctrl_tuner_if = v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_tuner_if, NULL);
s->ctrl_tuner_gain = v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_tuner_gain, NULL);
if (s->ctrl_handler.error) {
ret = s->ctrl_handler.error;
@@ -1274,8 +1332,9 @@ struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
s->v4l2_dev.ctrl_handler = &s->ctrl_handler;
s->vdev.v4l2_dev = &s->v4l2_dev;
s->vdev.lock = &s->v4l2_lock;
+ s->vdev.vfl_dir = VFL_DIR_RX;
- ret = video_register_device(&s->vdev, VFL_TYPE_GRABBER, -1);
+ ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1);
if (ret < 0) {
dev_err(&s->udev->dev,
"Failed to register as video device (%d)\n",
--
1.8.4.2
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 2/6] msi3101: convert to SDR API
2013-12-29 4:51 [PATCH 0/6] convert drivers to SDR API Antti Palosaari
2013-12-29 4:51 ` [PATCH 1/6] rtl2832_sdr: convert " Antti Palosaari
@ 2013-12-29 4:51 ` Antti Palosaari
2013-12-29 4:51 ` [PATCH 3/6] msi3101: add u8 sample format Antti Palosaari
` (3 subsequent siblings)
5 siblings, 0 replies; 11+ messages in thread
From: Antti Palosaari @ 2013-12-29 4:51 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Antti Palosaari
Convert to SDR API.
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/staging/media/msi3101/sdr-msi3101.c | 204 ++++++++++++++++++++--------
1 file changed, 148 insertions(+), 56 deletions(-)
diff --git a/drivers/staging/media/msi3101/sdr-msi3101.c b/drivers/staging/media/msi3101/sdr-msi3101.c
index 16ce417..9c54c63 100644
--- a/drivers/staging/media/msi3101/sdr-msi3101.c
+++ b/drivers/staging/media/msi3101/sdr-msi3101.c
@@ -386,10 +386,39 @@ static const struct msi3101_gain msi3101_gain_lut_1000[] = {
#define MSI3101_CID_TUNER_GAIN ((V4L2_CID_USER_BASE | 0xf000) + 13)
#define V4L2_PIX_FMT_SDR_S8 v4l2_fourcc('D', 'S', '0', '8') /* signed 8-bit */
-#define V4L2_PIX_FMT_SDR_S12 v4l2_fourcc('D', 'S', '1', '2') /* signed 12-bit */
-#define V4L2_PIX_FMT_SDR_S14 v4l2_fourcc('D', 'S', '1', '4') /* signed 14-bit */
+#define V4L2_PIX_FMT_SDR_S12 v4l2_fourcc('D', 'S', '1', '2') /* signed 12-bit */
+#define V4L2_PIX_FMT_SDR_S14 v4l2_fourcc('D', 'S', '1', '4') /* signed 14-bit */
#define V4L2_PIX_FMT_SDR_MSI2500_384 v4l2_fourcc('M', '3', '8', '4') /* Mirics MSi2500 format 384 */
+static const struct v4l2_frequency_band bands_adc[] = {
+ {
+ .tuner = 0,
+ .type = V4L2_TUNER_ADC,
+ .index = 0,
+ .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 1200000,
+ .rangehigh = 15000000,
+ },
+};
+
+static const struct v4l2_frequency_band bands_rf[] = {
+ {
+ .tuner = 1,
+ .type = V4L2_TUNER_RF,
+ .index = 0,
+ .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 49000000 / 62.5,
+ .rangehigh = 263000000 / 62.5,
+ }, {
+ .tuner = 1,
+ .type = V4L2_TUNER_RF,
+ .index = 1,
+ .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 390000000 / 62.5,
+ .rangehigh = 960000000 / 62.5,
+ },
+};
+
/* stream formats */
struct msi3101_format {
char *name;
@@ -437,6 +466,7 @@ struct msi3101_state {
/* Pointer to our usb_device, will be NULL after unplug */
struct usb_device *udev; /* Both mutexes most be hold when setting! */
+ unsigned int f_adc, f_tuner;
u32 pixelformat;
unsigned int isoc_errors; /* number of contiguous ISOC errors */
@@ -479,16 +509,6 @@ leave:
}
/*
- * Integer to 32-bit IEEE floating point representation routine is taken
- * from Radeon R600 driver (drivers/gpu/drm/radeon/r600_blit_kms.c).
- *
- * TODO: Currently we do conversion here in Kernel, but in future that will
- * be moved to the libv4l2 library as video format conversions are.
- */
-#define I2F_FRAC_BITS 23
-#define I2F_MASK ((1 << I2F_FRAC_BITS) - 1)
-
-/*
* +===========================================================================
* | 00-1023 | USB packet type '504'
* +===========================================================================
@@ -1016,12 +1036,11 @@ static int msi3101_querycap(struct file *file, void *fh,
strlcpy(cap->card, s->vdev.name, sizeof(cap->card));
usb_make_path(s->udev, cap->bus_info, sizeof(cap->bus_info));
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE;
+ V4L2_CAP_READWRITE | V4L2_CAP_TUNER;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
-
/* Videobuf2 operations */
static int msi3101_queue_setup(struct vb2_queue *vq,
const struct v4l2_format *fmt, unsigned int *nbuffers,
@@ -1037,9 +1056,9 @@ static int msi3101_queue_setup(struct vb2_queue *vq,
* 3, wMaxPacketSize 3x 1024 bytes
* 504, max IQ sample pairs per 1024 frame
* 2, two samples, I and Q
- * 4, 32-bit float
+ * 2, 16-bit is enough for single sample
*/
- sizes[0] = PAGE_ALIGN(3 * 504 * 2 * 4); /* = 12096 */
+ sizes[0] = PAGE_ALIGN(3 * 504 * 2 * 2);
dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n",
__func__, *nbuffers, sizes[0]);
return 0;
@@ -1527,28 +1546,27 @@ static struct vb2_ops msi3101_vb2_ops = {
static int msi3101_enum_input(struct file *file, void *fh, struct v4l2_input *i)
{
- if (i->index != 0)
+ if (i->index > 0)
return -EINVAL;
-
- strlcpy(i->name, "SDR data", sizeof(i->name));
- i->type = V4L2_INPUT_TYPE_CAMERA;
-
+ strlcpy(i->name, "Antenna #0", sizeof(i->name));
+ i->type = V4L2_INPUT_TYPE_TUNER;
return 0;
}
static int msi3101_g_input(struct file *file, void *fh, unsigned int *i)
{
*i = 0;
-
return 0;
}
static int msi3101_s_input(struct file *file, void *fh, unsigned int i)
{
- return i ? -EINVAL : 0;
+ if (i > 0)
+ return -EINVAL;
+ return 0;
}
-static int msi3101_enum_fmt_vid_cap(struct file *file, void *priv,
+static int msi3101_enum_fmt_sdr_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
struct msi3101_state *s = video_drvdata(file);
@@ -1563,70 +1581,70 @@ static int msi3101_enum_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-static int msi3101_g_fmt_vid_cap(struct file *file, void *priv,
+static int msi3101_g_fmt_sdr_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct msi3101_state *s = video_drvdata(file);
dev_dbg(&s->udev->dev, "%s:\n", __func__);
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (f->type != V4L2_BUF_TYPE_SDR_CAPTURE)
return -EINVAL;
- f->fmt.pix.pixelformat = s->pixelformat;
+ f->fmt.sdr.pixelformat = s->pixelformat;
return 0;
}
-static int msi3101_s_fmt_vid_cap(struct file *file, void *priv,
+static int msi3101_s_fmt_sdr_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct msi3101_state *s = video_drvdata(file);
struct vb2_queue *q = &s->vb_queue;
int i;
dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
- (char *)&f->fmt.pix.pixelformat);
+ (char *)&f->fmt.sdr.pixelformat);
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (f->type != V4L2_BUF_TYPE_SDR_CAPTURE)
return -EINVAL;
if (vb2_is_busy(q))
return -EBUSY;
for (i = 0; i < NUM_FORMATS; i++) {
- if (formats[i].pixelformat == f->fmt.pix.pixelformat) {
- s->pixelformat = f->fmt.pix.pixelformat;
+ if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
+ s->pixelformat = f->fmt.sdr.pixelformat;
return 0;
}
}
- f->fmt.pix.pixelformat = formats[0].pixelformat;
+ f->fmt.sdr.pixelformat = formats[0].pixelformat;
s->pixelformat = formats[0].pixelformat;
return 0;
}
-static int msi3101_try_fmt_vid_cap(struct file *file, void *priv,
+static int msi3101_try_fmt_sdr_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct msi3101_state *s = video_drvdata(file);
int i;
dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__,
- (char *)&f->fmt.pix.pixelformat);
+ (char *)&f->fmt.sdr.pixelformat);
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (f->type != V4L2_BUF_TYPE_SDR_CAPTURE)
return -EINVAL;
for (i = 0; i < NUM_FORMATS; i++) {
- if (formats[i].pixelformat == f->fmt.pix.pixelformat)
+ if (formats[i].pixelformat == f->fmt.sdr.pixelformat)
return 0;
}
- f->fmt.pix.pixelformat = formats[0].pixelformat;
+ f->fmt.sdr.pixelformat = formats[0].pixelformat;
return 0;
}
-static int vidioc_s_tuner(struct file *file, void *priv,
+static int msi3101_s_tuner(struct file *file, void *priv,
const struct v4l2_tuner *v)
{
struct msi3101_state *s = video_drvdata(file);
@@ -1635,35 +1653,106 @@ static int vidioc_s_tuner(struct file *file, void *priv,
return 0;
}
-static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
+static int msi3101_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
{
struct msi3101_state *s = video_drvdata(file);
dev_dbg(&s->udev->dev, "%s:\n", __func__);
- strcpy(v->name, "SDR RX");
- v->capability = V4L2_TUNER_CAP_LOW;
+ if (v->index == 0) {
+ strlcpy(v->name, "ADC: Mirics MSi2500", sizeof(v->name));
+ v->type = V4L2_TUNER_ADC;
+ v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+ v->rangelow = 1200000;
+ v->rangehigh = 15000000;
+ } else if (v->index == 1) {
+ strlcpy(v->name, "RF: Mirics MSi001", sizeof(v->name));
+ v->type = V4L2_TUNER_RF;
+ v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS;
+ v->rangelow = 49000000 / 62.5;
+ v->rangehigh = 960000000 / 62.5;
+ } else {
+ return -EINVAL;
+ }
return 0;
}
-static int vidioc_s_frequency(struct file *file, void *priv,
+static int msi3101_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct msi3101_state *s = video_drvdata(file);
+ int ret = 0;
+ dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d\n",
+ __func__, f->tuner, f->type);
+
+ if (f->tuner == 0)
+ f->frequency = s->f_adc;
+ else if (f->tuner == 1)
+ f->frequency = s->f_tuner;
+ else
+ return -EINVAL;
+
+ return ret;
+}
+
+static int msi3101_s_frequency(struct file *file, void *priv,
const struct v4l2_frequency *f)
{
struct msi3101_state *s = video_drvdata(file);
- dev_dbg(&s->udev->dev, "%s: frequency=%lu Hz (%u)\n",
- __func__, f->frequency * 625UL / 10UL, f->frequency);
+ int ret;
+ dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n",
+ __func__, f->tuner, f->type, f->frequency);
+
+ if (f->tuner == 0) {
+ dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n",
+ __func__, f->frequency);
+ s->f_adc = f->frequency;
+ ret = v4l2_ctrl_s_ctrl_int64(s->ctrl_sampling_rate,
+ f->frequency);
+ } else if (f->tuner == 1) {
+ dev_dbg(&s->udev->dev, "%s: RF frequency=%lu Hz\n",
+ __func__, f->frequency * 625UL / 10UL);
+ s->f_tuner = f->frequency;
+ ret = v4l2_ctrl_s_ctrl_int64(s->ctrl_tuner_rf,
+ f->frequency * 625UL / 10UL);
+ } else {
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int msi3101_enum_freq_bands(struct file *file, void *priv,
+ struct v4l2_frequency_band *band)
+{
+ struct msi3101_state *s = video_drvdata(file);
+ dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d index=%d\n",
+ __func__, band->tuner, band->type, band->index);
+
+ if (band->tuner == 0) {
+ if (band->index >= ARRAY_SIZE(bands_adc))
+ return -EINVAL;
+
+ *band = bands_adc[band->index];
+ } else if (band->tuner == 1) {
+ if (band->index >= ARRAY_SIZE(bands_rf))
+ return -EINVAL;
- return v4l2_ctrl_s_ctrl_int64(s->ctrl_tuner_rf,
- f->frequency * 625UL / 10UL);
+ *band = bands_rf[band->index];
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
}
static const struct v4l2_ioctl_ops msi3101_ioctl_ops = {
.vidioc_querycap = msi3101_querycap,
- .vidioc_enum_fmt_vid_cap = msi3101_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = msi3101_g_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = msi3101_s_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = msi3101_try_fmt_vid_cap,
+ .vidioc_enum_fmt_sdr_cap = msi3101_enum_fmt_sdr_cap,
+ .vidioc_g_fmt_sdr_cap = msi3101_g_fmt_sdr_cap,
+ .vidioc_s_fmt_sdr_cap = msi3101_s_fmt_sdr_cap,
+ .vidioc_try_fmt_sdr_cap = msi3101_try_fmt_sdr_cap,
.vidioc_enum_input = msi3101_enum_input,
.vidioc_g_input = msi3101_g_input,
@@ -1679,9 +1768,12 @@ static const struct v4l2_ioctl_ops msi3101_ioctl_ops = {
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_g_tuner = msi3101_g_tuner,
+ .vidioc_s_tuner = msi3101_s_tuner,
+
+ .vidioc_g_frequency = msi3101_g_frequency,
+ .vidioc_s_frequency = msi3101_s_frequency,
+ .vidioc_enum_freq_bands = msi3101_enum_freq_bands,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
@@ -1844,7 +1936,7 @@ static int msi3101_probe(struct usb_interface *intf,
s->udev = udev;
/* Init videobuf2 queue structure */
- s->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ s->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
s->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
s->vb_queue.drv_priv = s;
s->vb_queue.buf_struct_size = sizeof(struct msi3101_frame_buf);
@@ -1892,7 +1984,7 @@ static int msi3101_probe(struct usb_interface *intf,
s->vdev.v4l2_dev = &s->v4l2_dev;
s->vdev.lock = &s->v4l2_lock;
- ret = video_register_device(&s->vdev, VFL_TYPE_GRABBER, -1);
+ ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1);
if (ret < 0) {
dev_err(&s->udev->dev,
"Failed to register as video device (%d)\n",
--
1.8.4.2
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 3/6] msi3101: add u8 sample format
2013-12-29 4:51 [PATCH 0/6] convert drivers to SDR API Antti Palosaari
2013-12-29 4:51 ` [PATCH 1/6] rtl2832_sdr: convert " Antti Palosaari
2013-12-29 4:51 ` [PATCH 2/6] msi3101: " Antti Palosaari
@ 2013-12-29 4:51 ` Antti Palosaari
2014-01-05 12:14 ` Hans Verkuil
2013-12-29 4:51 ` [PATCH 4/6] msi3101: add u16 LE " Antti Palosaari
` (2 subsequent siblings)
5 siblings, 1 reply; 11+ messages in thread
From: Antti Palosaari @ 2013-12-29 4:51 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Antti Palosaari
Add unsigned 8-bit sample format. Format is got directly from
hardware, but it is converted from signed to unsigned. It is worst
known sampling resolution hardware offer.
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/staging/media/msi3101/sdr-msi3101.c | 67 ++++++++++++++++++++++++++++-
1 file changed, 66 insertions(+), 1 deletion(-)
diff --git a/drivers/staging/media/msi3101/sdr-msi3101.c b/drivers/staging/media/msi3101/sdr-msi3101.c
index 9c54c63..2110488 100644
--- a/drivers/staging/media/msi3101/sdr-msi3101.c
+++ b/drivers/staging/media/msi3101/sdr-msi3101.c
@@ -385,6 +385,7 @@ static const struct msi3101_gain msi3101_gain_lut_1000[] = {
#define MSI3101_CID_TUNER_IF ((V4L2_CID_USER_BASE | 0xf000) + 12)
#define MSI3101_CID_TUNER_GAIN ((V4L2_CID_USER_BASE | 0xf000) + 13)
+#define V4L2_PIX_FMT_SDR_U8 v4l2_fourcc('D', 'U', '0', '8') /* unsigned 8-bit */
#define V4L2_PIX_FMT_SDR_S8 v4l2_fourcc('D', 'S', '0', '8') /* signed 8-bit */
#define V4L2_PIX_FMT_SDR_S12 v4l2_fourcc('D', 'S', '1', '2') /* signed 12-bit */
#define V4L2_PIX_FMT_SDR_S14 v4l2_fourcc('D', 'S', '1', '4') /* signed 14-bit */
@@ -428,6 +429,9 @@ struct msi3101_format {
/* format descriptions for capture and preview */
static struct msi3101_format formats[] = {
{
+ .name = "I/Q 8-bit unsigned",
+ .pixelformat = V4L2_PIX_FMT_SDR_U8,
+ }, {
.name = "I/Q 8-bit signed",
.pixelformat = V4L2_PIX_FMT_SDR_S8,
}, {
@@ -487,6 +491,7 @@ struct msi3101_state {
u32 next_sample; /* for track lost packets */
u32 sample; /* for sample rate calc */
unsigned long jiffies;
+ unsigned long jiffies_next;
unsigned int sample_ctrl_bit[4];
};
@@ -572,6 +577,63 @@ static int msi3101_convert_stream_504(struct msi3101_state *s, u8 *dst,
return dst_len;
}
+static int msi3101_convert_stream_504_u8(struct msi3101_state *s, u8 *dst,
+ u8 *src, unsigned int src_len)
+{
+ int i, j, i_max, dst_len = 0;
+ u32 sample_num[3];
+ s8 *s8src;
+ u8 *u8dst;
+
+ /* There could be 1-3 1024 bytes URB frames */
+ i_max = src_len / 1024;
+ u8dst = (u8 *) dst;
+
+ for (i = 0; i < i_max; i++) {
+ sample_num[i] = src[3] << 24 | src[2] << 16 | src[1] << 8 | src[0] << 0;
+ if (i == 0 && s->next_sample != sample_num[0]) {
+ dev_dbg_ratelimited(&s->udev->dev,
+ "%d samples lost, %d %08x:%08x\n",
+ sample_num[0] - s->next_sample,
+ src_len, s->next_sample, sample_num[0]);
+ }
+
+ /*
+ * Dump all unknown 'garbage' data - maybe we will discover
+ * someday if there is something rational...
+ */
+ dev_dbg_ratelimited(&s->udev->dev, "%*ph\n", 12, &src[4]);
+
+ /* 504 x I+Q samples */
+ src += 16;
+
+ s8src = (s8 *) src;
+ for (j = 0; j < 1008; j++)
+ *u8dst++ = *s8src++ + 128;
+
+ src += 1008;
+ dst += 1008;
+ dst_len += 1008;
+ }
+
+ /* calculate samping rate and output it in 10 seconds intervals */
+ if (unlikely(time_is_before_jiffies(s->jiffies_next))) {
+#define MSECS 10000UL
+ unsigned int samples = sample_num[i_max - 1] - s->sample;
+ s->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
+ s->sample = sample_num[i_max - 1];
+ dev_dbg(&s->udev->dev,
+ "slen=%d samples=%u msecs=%lu sampling rate=%lu\n",
+ src_len, samples, MSECS,
+ samples * 1000UL / MSECS);
+ }
+
+ /* next sample (sample = sample + i * 504) */
+ s->next_sample = sample_num[i_max - 1] + 504;
+
+ return dst_len;
+}
+
/*
* +===========================================================================
* | 00-1023 | USB packet type '384'
@@ -1159,7 +1221,10 @@ static int msi3101_set_usb_adc(struct msi3101_state *s)
reg7 = 0x000c9407;
}
- if (s->pixelformat == V4L2_PIX_FMT_SDR_S8) {
+ if (s->pixelformat == V4L2_PIX_FMT_SDR_U8) {
+ s->convert_stream = msi3101_convert_stream_504_u8;
+ reg7 = 0x000c9407;
+ } else if (s->pixelformat == V4L2_PIX_FMT_SDR_S8) {
s->convert_stream = msi3101_convert_stream_504;
reg7 = 0x000c9407;
} else if (s->pixelformat == V4L2_PIX_FMT_SDR_MSI2500_384) {
--
1.8.4.2
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH 3/6] msi3101: add u8 sample format
2013-12-29 4:51 ` [PATCH 3/6] msi3101: add u8 sample format Antti Palosaari
@ 2014-01-05 12:14 ` Hans Verkuil
2014-01-14 1:46 ` Antti Palosaari
0 siblings, 1 reply; 11+ messages in thread
From: Hans Verkuil @ 2014-01-05 12:14 UTC (permalink / raw)
To: Antti Palosaari; +Cc: linux-media
On 12/29/2013 05:51 AM, Antti Palosaari wrote:
> Add unsigned 8-bit sample format. Format is got directly from
> hardware, but it is converted from signed to unsigned. It is worst
> known sampling resolution hardware offer.
>
> Signed-off-by: Antti Palosaari <crope@iki.fi>
> ---
> drivers/staging/media/msi3101/sdr-msi3101.c | 67 ++++++++++++++++++++++++++++-
> 1 file changed, 66 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/staging/media/msi3101/sdr-msi3101.c b/drivers/staging/media/msi3101/sdr-msi3101.c
> index 9c54c63..2110488 100644
> --- a/drivers/staging/media/msi3101/sdr-msi3101.c
> +++ b/drivers/staging/media/msi3101/sdr-msi3101.c
> @@ -385,6 +385,7 @@ static const struct msi3101_gain msi3101_gain_lut_1000[] = {
> #define MSI3101_CID_TUNER_IF ((V4L2_CID_USER_BASE | 0xf000) + 12)
> #define MSI3101_CID_TUNER_GAIN ((V4L2_CID_USER_BASE | 0xf000) + 13)
>
> +#define V4L2_PIX_FMT_SDR_U8 v4l2_fourcc('D', 'U', '0', '8') /* unsigned 8-bit */
> #define V4L2_PIX_FMT_SDR_S8 v4l2_fourcc('D', 'S', '0', '8') /* signed 8-bit */
> #define V4L2_PIX_FMT_SDR_S12 v4l2_fourcc('D', 'S', '1', '2') /* signed 12-bit */
> #define V4L2_PIX_FMT_SDR_S14 v4l2_fourcc('D', 'S', '1', '4') /* signed 14-bit */
These defines should be moved to videodev2.h and documented in DocBook.
Regards,
Hans
> @@ -428,6 +429,9 @@ struct msi3101_format {
> /* format descriptions for capture and preview */
> static struct msi3101_format formats[] = {
> {
> + .name = "I/Q 8-bit unsigned",
> + .pixelformat = V4L2_PIX_FMT_SDR_U8,
> + }, {
> .name = "I/Q 8-bit signed",
> .pixelformat = V4L2_PIX_FMT_SDR_S8,
> }, {
> @@ -487,6 +491,7 @@ struct msi3101_state {
> u32 next_sample; /* for track lost packets */
> u32 sample; /* for sample rate calc */
> unsigned long jiffies;
> + unsigned long jiffies_next;
> unsigned int sample_ctrl_bit[4];
> };
>
> @@ -572,6 +577,63 @@ static int msi3101_convert_stream_504(struct msi3101_state *s, u8 *dst,
> return dst_len;
> }
>
> +static int msi3101_convert_stream_504_u8(struct msi3101_state *s, u8 *dst,
> + u8 *src, unsigned int src_len)
> +{
> + int i, j, i_max, dst_len = 0;
> + u32 sample_num[3];
> + s8 *s8src;
> + u8 *u8dst;
> +
> + /* There could be 1-3 1024 bytes URB frames */
> + i_max = src_len / 1024;
> + u8dst = (u8 *) dst;
> +
> + for (i = 0; i < i_max; i++) {
> + sample_num[i] = src[3] << 24 | src[2] << 16 | src[1] << 8 | src[0] << 0;
> + if (i == 0 && s->next_sample != sample_num[0]) {
> + dev_dbg_ratelimited(&s->udev->dev,
> + "%d samples lost, %d %08x:%08x\n",
> + sample_num[0] - s->next_sample,
> + src_len, s->next_sample, sample_num[0]);
> + }
> +
> + /*
> + * Dump all unknown 'garbage' data - maybe we will discover
> + * someday if there is something rational...
> + */
> + dev_dbg_ratelimited(&s->udev->dev, "%*ph\n", 12, &src[4]);
> +
> + /* 504 x I+Q samples */
> + src += 16;
> +
> + s8src = (s8 *) src;
> + for (j = 0; j < 1008; j++)
> + *u8dst++ = *s8src++ + 128;
> +
> + src += 1008;
> + dst += 1008;
> + dst_len += 1008;
> + }
> +
> + /* calculate samping rate and output it in 10 seconds intervals */
> + if (unlikely(time_is_before_jiffies(s->jiffies_next))) {
> +#define MSECS 10000UL
> + unsigned int samples = sample_num[i_max - 1] - s->sample;
> + s->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
> + s->sample = sample_num[i_max - 1];
> + dev_dbg(&s->udev->dev,
> + "slen=%d samples=%u msecs=%lu sampling rate=%lu\n",
> + src_len, samples, MSECS,
> + samples * 1000UL / MSECS);
> + }
> +
> + /* next sample (sample = sample + i * 504) */
> + s->next_sample = sample_num[i_max - 1] + 504;
> +
> + return dst_len;
> +}
> +
> /*
> * +===========================================================================
> * | 00-1023 | USB packet type '384'
> @@ -1159,7 +1221,10 @@ static int msi3101_set_usb_adc(struct msi3101_state *s)
> reg7 = 0x000c9407;
> }
>
> - if (s->pixelformat == V4L2_PIX_FMT_SDR_S8) {
> + if (s->pixelformat == V4L2_PIX_FMT_SDR_U8) {
> + s->convert_stream = msi3101_convert_stream_504_u8;
> + reg7 = 0x000c9407;
> + } else if (s->pixelformat == V4L2_PIX_FMT_SDR_S8) {
> s->convert_stream = msi3101_convert_stream_504;
> reg7 = 0x000c9407;
> } else if (s->pixelformat == V4L2_PIX_FMT_SDR_MSI2500_384) {
>
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH 3/6] msi3101: add u8 sample format
2014-01-05 12:14 ` Hans Verkuil
@ 2014-01-14 1:46 ` Antti Palosaari
0 siblings, 0 replies; 11+ messages in thread
From: Antti Palosaari @ 2014-01-14 1:46 UTC (permalink / raw)
To: Hans Verkuil; +Cc: linux-media
On 05.01.2014 14:14, Hans Verkuil wrote:
> On 12/29/2013 05:51 AM, Antti Palosaari wrote:
>> Add unsigned 8-bit sample format. Format is got directly from
>> hardware, but it is converted from signed to unsigned. It is worst
>> known sampling resolution hardware offer.
>>
>> Signed-off-by: Antti Palosaari <crope@iki.fi>
>> ---
>> drivers/staging/media/msi3101/sdr-msi3101.c | 67 ++++++++++++++++++++++++++++-
>> 1 file changed, 66 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/staging/media/msi3101/sdr-msi3101.c b/drivers/staging/media/msi3101/sdr-msi3101.c
>> index 9c54c63..2110488 100644
>> --- a/drivers/staging/media/msi3101/sdr-msi3101.c
>> +++ b/drivers/staging/media/msi3101/sdr-msi3101.c
>> @@ -385,6 +385,7 @@ static const struct msi3101_gain msi3101_gain_lut_1000[] = {
>> #define MSI3101_CID_TUNER_IF ((V4L2_CID_USER_BASE | 0xf000) + 12)
>> #define MSI3101_CID_TUNER_GAIN ((V4L2_CID_USER_BASE | 0xf000) + 13)
>>
>> +#define V4L2_PIX_FMT_SDR_U8 v4l2_fourcc('D', 'U', '0', '8') /* unsigned 8-bit */
>> #define V4L2_PIX_FMT_SDR_S8 v4l2_fourcc('D', 'S', '0', '8') /* signed 8-bit */
>> #define V4L2_PIX_FMT_SDR_S12 v4l2_fourcc('D', 'S', '1', '2') /* signed 12-bit */
>> #define V4L2_PIX_FMT_SDR_S14 v4l2_fourcc('D', 'S', '1', '4') /* signed 14-bit */
>
> These defines should be moved to videodev2.h and documented in DocBook.
Indeed, but that driver is still on staging. I will move those later...
regards
Antti
--
http://palosaari.fi/
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH 4/6] msi3101: add u16 LE sample format
2013-12-29 4:51 [PATCH 0/6] convert drivers to SDR API Antti Palosaari
` (2 preceding siblings ...)
2013-12-29 4:51 ` [PATCH 3/6] msi3101: add u8 sample format Antti Palosaari
@ 2013-12-29 4:51 ` Antti Palosaari
2013-12-29 4:51 ` [PATCH 5/6] msi3101: tons of small changes Antti Palosaari
2013-12-29 4:51 ` [PATCH 6/6] v4l: disable lockdep on vb2_fop_mmap() Antti Palosaari
5 siblings, 0 replies; 11+ messages in thread
From: Antti Palosaari @ 2013-12-29 4:51 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Antti Palosaari
Add unsigned 16-bit little endian sample format. That stream
format is scaled from hardware 14-bit signed value. That is best
known sampling resolution that MSi2500 ADC provides.
It is not guaranteed to be little endian, but host endian which is
usually little endian - room for improvement.
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/staging/media/msi3101/sdr-msi3101.c | 79 +++++++++++++++++++++++++++++
1 file changed, 79 insertions(+)
diff --git a/drivers/staging/media/msi3101/sdr-msi3101.c b/drivers/staging/media/msi3101/sdr-msi3101.c
index 2110488..41894c1 100644
--- a/drivers/staging/media/msi3101/sdr-msi3101.c
+++ b/drivers/staging/media/msi3101/sdr-msi3101.c
@@ -386,6 +386,7 @@ static const struct msi3101_gain msi3101_gain_lut_1000[] = {
#define MSI3101_CID_TUNER_GAIN ((V4L2_CID_USER_BASE | 0xf000) + 13)
#define V4L2_PIX_FMT_SDR_U8 v4l2_fourcc('D', 'U', '0', '8') /* unsigned 8-bit */
+#define V4L2_PIX_FMT_SDR_U16LE v4l2_fourcc('D', 'U', '1', '6') /* unsigned 16-bit LE */
#define V4L2_PIX_FMT_SDR_S8 v4l2_fourcc('D', 'S', '0', '8') /* signed 8-bit */
#define V4L2_PIX_FMT_SDR_S12 v4l2_fourcc('D', 'S', '1', '2') /* signed 12-bit */
#define V4L2_PIX_FMT_SDR_S14 v4l2_fourcc('D', 'S', '1', '4') /* signed 14-bit */
@@ -432,6 +433,9 @@ static struct msi3101_format formats[] = {
.name = "I/Q 8-bit unsigned",
.pixelformat = V4L2_PIX_FMT_SDR_U8,
}, {
+ .name = "I/Q 16-bit unsigned little endian",
+ .pixelformat = V4L2_PIX_FMT_SDR_U16LE,
+ }, {
.name = "I/Q 8-bit signed",
.pixelformat = V4L2_PIX_FMT_SDR_S8,
}, {
@@ -857,6 +861,78 @@ static int msi3101_convert_stream_252(struct msi3101_state *s, u8 *dst,
return dst_len;
}
+static int msi3101_convert_stream_252_u16(struct msi3101_state *s, u8 *dst,
+ u8 *src, unsigned int src_len)
+{
+ int i, j, i_max, dst_len = 0;
+ u32 sample_num[3];
+ u16 *u16dst = (u16 *) dst;
+ struct {signed int x:14;} se;
+
+ /* There could be 1-3 1024 bytes URB frames */
+ i_max = src_len / 1024;
+
+ for (i = 0; i < i_max; i++) {
+ sample_num[i] = src[3] << 24 | src[2] << 16 | src[1] << 8 | src[0] << 0;
+ if (i == 0 && s->next_sample != sample_num[0]) {
+ dev_dbg_ratelimited(&s->udev->dev,
+ "%d samples lost, %d %08x:%08x\n",
+ sample_num[0] - s->next_sample,
+ src_len, s->next_sample, sample_num[0]);
+ }
+
+ /*
+ * Dump all unknown 'garbage' data - maybe we will discover
+ * someday if there is something rational...
+ */
+ dev_dbg_ratelimited(&s->udev->dev, "%*ph\n", 12, &src[4]);
+
+ /* 252 x I+Q samples */
+ src += 16;
+
+ for (j = 0; j < 1008; j += 4) {
+ unsigned int usample[2];
+ int ssample[2];
+
+ usample[0] = src[j + 0] >> 0 | src[j + 1] << 8;
+ usample[1] = src[j + 2] >> 0 | src[j + 3] << 8;
+
+ /* sign extension from 14-bit to signed int */
+ ssample[0] = se.x = usample[0];
+ ssample[1] = se.x = usample[1];
+
+ /* from signed to unsigned */
+ usample[0] = ssample[0] + 8192;
+ usample[1] = ssample[1] + 8192;
+
+ /* from 14-bit to 16-bit */
+ *u16dst++ = (usample[0] << 2) | (usample[0] >> 12);
+ *u16dst++ = (usample[1] << 2) | (usample[1] >> 12);
+ }
+
+ src += 1008;
+ dst += 1008;
+ dst_len += 1008;
+ }
+
+ /* calculate samping rate and output it in 10 seconds intervals */
+ if (unlikely(time_is_before_jiffies(s->jiffies_next))) {
+#define MSECS 10000UL
+ unsigned int samples = sample_num[i_max - 1] - s->sample;
+ s->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
+ s->sample = sample_num[i_max - 1];
+ dev_dbg(&s->udev->dev,
+ "slen=%d samples=%u msecs=%lu sampling rate=%lu\n",
+ src_len, samples, MSECS,
+ samples * 1000UL / MSECS);
+ }
+
+ /* next sample (sample = sample + i * 252) */
+ s->next_sample = sample_num[i_max - 1] + 252;
+
+ return dst_len;
+}
+
/*
* This gets called for the Isochronous pipe (stream). This is done in interrupt
* time, so it has to be fast, not crash, and not stall. Neat.
@@ -1224,6 +1300,9 @@ static int msi3101_set_usb_adc(struct msi3101_state *s)
if (s->pixelformat == V4L2_PIX_FMT_SDR_U8) {
s->convert_stream = msi3101_convert_stream_504_u8;
reg7 = 0x000c9407;
+ } else if (s->pixelformat == V4L2_PIX_FMT_SDR_U16LE) {
+ s->convert_stream = msi3101_convert_stream_252_u16;
+ reg7 = 0x00009407;
} else if (s->pixelformat == V4L2_PIX_FMT_SDR_S8) {
s->convert_stream = msi3101_convert_stream_504;
reg7 = 0x000c9407;
--
1.8.4.2
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 5/6] msi3101: tons of small changes
2013-12-29 4:51 [PATCH 0/6] convert drivers to SDR API Antti Palosaari
` (3 preceding siblings ...)
2013-12-29 4:51 ` [PATCH 4/6] msi3101: add u16 LE " Antti Palosaari
@ 2013-12-29 4:51 ` Antti Palosaari
2013-12-29 4:51 ` [PATCH 6/6] v4l: disable lockdep on vb2_fop_mmap() Antti Palosaari
5 siblings, 0 replies; 11+ messages in thread
From: Antti Palosaari @ 2013-12-29 4:51 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Antti Palosaari
* remove unneeded controls
* rename things
* remove unneeded callbacks
* use likely/unlikely on hot paths
* use 1Hz resolution for tuner RF frequency
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/staging/media/msi3101/sdr-msi3101.c | 214 +++++++---------------------
1 file changed, 55 insertions(+), 159 deletions(-)
diff --git a/drivers/staging/media/msi3101/sdr-msi3101.c b/drivers/staging/media/msi3101/sdr-msi3101.c
index 41894c1..24dfd79 100644
--- a/drivers/staging/media/msi3101/sdr-msi3101.c
+++ b/drivers/staging/media/msi3101/sdr-msi3101.c
@@ -21,20 +21,6 @@
* (C) 1999-2004 Nemosoft Unv.
* (C) 2004-2006 Luc Saillard (luc@saillard.org)
* (C) 2011 Hans de Goede <hdegoede@redhat.com>
- *
- * Development tree of that driver will be on:
- * http://git.linuxtv.org/anttip/media_tree.git/shortlog/refs/heads/mirics
- *
- * GNU Radio plugin "gr-kernel" for device usage will be on:
- * http://git.linuxtv.org/anttip/gr-kernel.git
- *
- * TODO:
- * Help is very highly welcome for these + all the others you could imagine:
- * - split USB ADC interface and RF tuner to own drivers (msi2500 and msi001)
- * - move controls to V4L2 API
- * - use libv4l2 for stream format conversions
- * - gr-kernel: switch to v4l2_mmap (current read eats a lot of cpu)
- * - SDRSharp support
*/
#include <linux/module.h>
@@ -377,12 +363,7 @@ static const struct msi3101_gain msi3101_gain_lut_1000[] = {
#define MAX_ISOC_ERRORS 20
/* TODO: These should be moved to V4L2 API */
-#define MSI3101_CID_SAMPLING_MODE ((V4L2_CID_USER_BASE | 0xf000) + 0)
-#define MSI3101_CID_SAMPLING_RATE ((V4L2_CID_USER_BASE | 0xf000) + 1)
-#define MSI3101_CID_SAMPLING_RESOLUTION ((V4L2_CID_USER_BASE | 0xf000) + 2)
-#define MSI3101_CID_TUNER_RF ((V4L2_CID_USER_BASE | 0xf000) + 10)
#define MSI3101_CID_TUNER_BW ((V4L2_CID_USER_BASE | 0xf000) + 11)
-#define MSI3101_CID_TUNER_IF ((V4L2_CID_USER_BASE | 0xf000) + 12)
#define MSI3101_CID_TUNER_GAIN ((V4L2_CID_USER_BASE | 0xf000) + 13)
#define V4L2_PIX_FMT_SDR_U8 v4l2_fourcc('D', 'U', '0', '8') /* unsigned 8-bit */
@@ -408,16 +389,16 @@ static const struct v4l2_frequency_band bands_rf[] = {
.tuner = 1,
.type = V4L2_TUNER_RF,
.index = 0,
- .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
- .rangelow = 49000000 / 62.5,
- .rangehigh = 263000000 / 62.5,
+ .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 49000000,
+ .rangehigh = 263000000,
}, {
.tuner = 1,
.type = V4L2_TUNER_RF,
.index = 1,
- .capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
- .rangelow = 390000000 / 62.5,
- .rangehigh = 960000000 / 62.5,
+ .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS,
+ .rangelow = 390000000,
+ .rangehigh = 960000000,
},
};
@@ -430,27 +411,27 @@ struct msi3101_format {
/* format descriptions for capture and preview */
static struct msi3101_format formats[] = {
{
- .name = "I/Q 8-bit unsigned",
+ .name = "8-bit unsigned",
.pixelformat = V4L2_PIX_FMT_SDR_U8,
}, {
- .name = "I/Q 16-bit unsigned little endian",
+ .name = "16-bit unsigned little endian",
.pixelformat = V4L2_PIX_FMT_SDR_U16LE,
}, {
- .name = "I/Q 8-bit signed",
+ .name = "8-bit signed",
.pixelformat = V4L2_PIX_FMT_SDR_S8,
}, {
- .name = "I/Q 10+2-bit signed",
+ .name = "10+2-bit signed",
.pixelformat = V4L2_PIX_FMT_SDR_MSI2500_384,
}, {
- .name = "I/Q 12-bit signed",
+ .name = "12-bit signed",
.pixelformat = V4L2_PIX_FMT_SDR_S12,
}, {
- .name = "I/Q 14-bit signed",
+ .name = "14-bit signed",
.pixelformat = V4L2_PIX_FMT_SDR_S14,
},
};
-static const int NUM_FORMATS = sizeof(formats) / sizeof(struct msi3101_format);
+static const unsigned int NUM_FORMATS = ARRAY_SIZE(formats);
/* intermediate buffers with raw data from the USB device */
struct msi3101_frame_buf {
@@ -486,15 +467,11 @@ struct msi3101_state {
/* Controls */
struct v4l2_ctrl_handler ctrl_handler;
- struct v4l2_ctrl *ctrl_sampling_rate;
- struct v4l2_ctrl *ctrl_tuner_rf;
struct v4l2_ctrl *ctrl_tuner_bw;
- struct v4l2_ctrl *ctrl_tuner_if;
struct v4l2_ctrl *ctrl_tuner_gain;
u32 next_sample; /* for track lost packets */
u32 sample; /* for sample rate calc */
- unsigned long jiffies;
unsigned long jiffies_next;
unsigned int sample_ctrl_bit[4];
};
@@ -563,11 +540,11 @@ static int msi3101_convert_stream_504(struct msi3101_state *s, u8 *dst,
}
/* calculate samping rate and output it in 10 seconds intervals */
- if ((s->jiffies + msecs_to_jiffies(10000)) <= jiffies) {
+ if ((s->jiffies_next + msecs_to_jiffies(10000)) <= jiffies) {
unsigned long jiffies_now = jiffies;
- unsigned long msecs = jiffies_to_msecs(jiffies_now) - jiffies_to_msecs(s->jiffies);
+ unsigned long msecs = jiffies_to_msecs(jiffies_now) - jiffies_to_msecs(s->jiffies_next);
unsigned int samples = sample_num[i_max - 1] - s->sample;
- s->jiffies = jiffies_now;
+ s->jiffies_next = jiffies_now;
s->sample = sample_num[i_max - 1];
dev_dbg(&s->udev->dev,
"slen=%d samples=%u msecs=%lu sampling rate=%lu\n",
@@ -715,11 +692,11 @@ static int msi3101_convert_stream_384(struct msi3101_state *s, u8 *dst,
}
/* calculate samping rate and output it in 10 seconds intervals */
- if ((s->jiffies + msecs_to_jiffies(10000)) <= jiffies) {
+ if ((s->jiffies_next + msecs_to_jiffies(10000)) <= jiffies) {
unsigned long jiffies_now = jiffies;
- unsigned long msecs = jiffies_to_msecs(jiffies_now) - jiffies_to_msecs(s->jiffies);
+ unsigned long msecs = jiffies_to_msecs(jiffies_now) - jiffies_to_msecs(s->jiffies_next);
unsigned int samples = sample_num[i_max - 1] - s->sample;
- s->jiffies = jiffies_now;
+ s->jiffies_next = jiffies_now;
s->sample = sample_num[i_max - 1];
dev_dbg(&s->udev->dev,
"slen=%d samples=%u msecs=%lu sampling rate=%lu bits=%d.%d.%d.%d\n",
@@ -780,11 +757,11 @@ static int msi3101_convert_stream_336(struct msi3101_state *s, u8 *dst,
}
/* calculate samping rate and output it in 10 seconds intervals */
- if ((s->jiffies + msecs_to_jiffies(10000)) <= jiffies) {
+ if ((s->jiffies_next + msecs_to_jiffies(10000)) <= jiffies) {
unsigned long jiffies_now = jiffies;
- unsigned long msecs = jiffies_to_msecs(jiffies_now) - jiffies_to_msecs(s->jiffies);
+ unsigned long msecs = jiffies_to_msecs(jiffies_now) - jiffies_to_msecs(s->jiffies_next);
unsigned int samples = sample_num[i_max - 1] - s->sample;
- s->jiffies = jiffies_now;
+ s->jiffies_next = jiffies_now;
s->sample = sample_num[i_max - 1];
dev_dbg(&s->udev->dev,
"slen=%d samples=%u msecs=%lu sampling rate=%lu\n",
@@ -843,11 +820,11 @@ static int msi3101_convert_stream_252(struct msi3101_state *s, u8 *dst,
}
/* calculate samping rate and output it in 10 seconds intervals */
- if ((s->jiffies + msecs_to_jiffies(10000)) <= jiffies) {
+ if ((s->jiffies_next + msecs_to_jiffies(10000)) <= jiffies) {
unsigned long jiffies_now = jiffies;
- unsigned long msecs = jiffies_to_msecs(jiffies_now) - jiffies_to_msecs(s->jiffies);
+ unsigned long msecs = jiffies_to_msecs(jiffies_now) - jiffies_to_msecs(s->jiffies_next);
unsigned int samples = sample_num[i_max - 1] - s->sample;
- s->jiffies = jiffies_now;
+ s->jiffies_next = jiffies_now;
s->sample = sample_num[i_max - 1];
dev_dbg(&s->udev->dev,
"slen=%d samples=%u msecs=%lu sampling rate=%lu\n",
@@ -944,14 +921,14 @@ static void msi3101_isoc_handler(struct urb *urb)
unsigned char *iso_buf = NULL;
struct msi3101_frame_buf *fbuf;
- if (urb->status == -ENOENT || urb->status == -ECONNRESET ||
- urb->status == -ESHUTDOWN) {
+ if (unlikely(urb->status == -ENOENT || urb->status == -ECONNRESET ||
+ urb->status == -ESHUTDOWN)) {
dev_dbg(&s->udev->dev, "URB (%p) unlinked %ssynchronuously\n",
urb, urb->status == -ENOENT ? "" : "a");
return;
}
- if (urb->status != 0) {
+ if (unlikely(urb->status != 0)) {
dev_dbg(&s->udev->dev,
"msi3101_isoc_handler() called with status %d\n",
urb->status);
@@ -971,28 +948,28 @@ static void msi3101_isoc_handler(struct urb *urb)
/* Check frame error */
fstatus = urb->iso_frame_desc[i].status;
- if (fstatus) {
+ if (unlikely(fstatus)) {
dev_dbg_ratelimited(&s->udev->dev,
"frame=%d/%d has error %d skipping\n",
i, urb->number_of_packets, fstatus);
- goto skip;
+ continue;
}
/* Check if that frame contains data */
flen = urb->iso_frame_desc[i].actual_length;
- if (flen == 0)
- goto skip;
+ if (unlikely(flen == 0))
+ continue;
iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
/* Get free framebuffer */
fbuf = msi3101_get_next_fill_buf(s);
- if (fbuf == NULL) {
+ if (unlikely(fbuf == NULL)) {
s->vb_full++;
dev_dbg_ratelimited(&s->udev->dev,
"videobuf is full, %d packets dropped\n",
s->vb_full);
- goto skip;
+ continue;
}
/* fill framebuffer */
@@ -1000,13 +977,11 @@ static void msi3101_isoc_handler(struct urb *urb)
flen = s->convert_stream(s, ptr, iso_buf, flen);
vb2_set_plane_payload(&fbuf->vb, 0, flen);
vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE);
-skip:
- ;
}
handler_end:
i = usb_submit_urb(urb, GFP_ATOMIC);
- if (i != 0)
+ if (unlikely(i != 0))
dev_dbg(&s->udev->dev,
"Error (%d) re-submitting urb in msi3101_isoc_handler\n",
i);
@@ -1069,7 +1044,7 @@ static int msi3101_isoc_init(struct msi3101_state *s)
udev = s->udev;
ret = usb_set_interface(s->udev, 0, 1);
- if (ret < 0)
+ if (ret)
return ret;
/* Allocate and init Isochronuous urbs */
@@ -1202,17 +1177,6 @@ static int msi3101_queue_setup(struct vb2_queue *vq,
return 0;
}
-static int msi3101_buf_prepare(struct vb2_buffer *vb)
-{
- struct msi3101_state *s = vb2_get_drv_priv(vb->vb2_queue);
-
- /* Don't allow queing new buffers after device disconnection */
- if (!s->udev)
- return -ENODEV;
-
- return 0;
-}
-
static void msi3101_buf_queue(struct vb2_buffer *vb)
{
struct msi3101_state *s = vb2_get_drv_priv(vb->vb2_queue);
@@ -1221,7 +1185,7 @@ static void msi3101_buf_queue(struct vb2_buffer *vb)
unsigned long flags = 0;
/* Check the device has not disconnected between prep and queuing */
- if (!s->udev) {
+ if (unlikely(!s->udev)) {
vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
return;
}
@@ -1280,7 +1244,7 @@ static int msi3101_set_usb_adc(struct msi3101_state *s)
int ret, div_n, div_m, div_r_out, f_sr, f_vco, fract;
u32 reg3, reg4, reg7;
- f_sr = s->ctrl_sampling_rate->val64;
+ f_sr = s->f_adc;
/* select stream format */
if (f_sr < 6000000) {
@@ -1455,7 +1419,7 @@ static int msi3101_set_tuner(struct msi3101_state *s)
{8000000, 0x07}, /* 8 MHz */
};
- unsigned int f_rf = s->ctrl_tuner_rf->val64;
+ unsigned int f_rf = s->f_tuner;
/*
* bandwidth (Hz)
@@ -1467,7 +1431,7 @@ static int msi3101_set_tuner(struct msi3101_state *s)
* intermediate frequency (Hz)
* 0, 450000, 1620000, 2048000
*/
- unsigned int f_if = s->ctrl_tuner_if->val;
+ unsigned int f_if = 0;
/*
* gain reduction (dB)
@@ -1680,7 +1644,6 @@ static int msi3101_stop_streaming(struct vb2_queue *vq)
static struct vb2_ops msi3101_vb2_ops = {
.queue_setup = msi3101_queue_setup,
- .buf_prepare = msi3101_buf_prepare,
.buf_queue = msi3101_buf_queue,
.start_streaming = msi3101_start_streaming,
.stop_streaming = msi3101_stop_streaming,
@@ -1811,9 +1774,9 @@ static int msi3101_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v)
} else if (v->index == 1) {
strlcpy(v->name, "RF: Mirics MSi001", sizeof(v->name));
v->type = V4L2_TUNER_RF;
- v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS;
- v->rangelow = 49000000 / 62.5;
- v->rangehigh = 960000000 / 62.5;
+ v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS;
+ v->rangelow = 49000000;
+ v->rangehigh = 960000000;
} else {
return -EINVAL;
}
@@ -1848,17 +1811,15 @@ static int msi3101_s_frequency(struct file *file, void *priv,
__func__, f->tuner, f->type, f->frequency);
if (f->tuner == 0) {
- dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n",
- __func__, f->frequency);
s->f_adc = f->frequency;
- ret = v4l2_ctrl_s_ctrl_int64(s->ctrl_sampling_rate,
- f->frequency);
+ dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n",
+ __func__, s->f_adc);
+ ret = msi3101_set_usb_adc(s);
} else if (f->tuner == 1) {
- dev_dbg(&s->udev->dev, "%s: RF frequency=%lu Hz\n",
- __func__, f->frequency * 625UL / 10UL);
s->f_tuner = f->frequency;
- ret = v4l2_ctrl_s_ctrl_int64(s->ctrl_tuner_rf,
- f->frequency * 625UL / 10UL);
+ dev_dbg(&s->udev->dev, "%s: RF frequency=%u Hz\n",
+ __func__, f->frequency);
+ ret = msi3101_set_tuner(s);
} else {
return -EINVAL;
}
@@ -1939,6 +1900,7 @@ static struct video_device msi3101_template = {
.release = video_device_release_empty,
.fops = &msi3101_fops,
.ioctl_ops = &msi3101_ioctl_ops,
+ .debug = 0,
};
static int msi3101_s_ctrl(struct v4l2_ctrl *ctrl)
@@ -1953,14 +1915,7 @@ static int msi3101_s_ctrl(struct v4l2_ctrl *ctrl)
ctrl->minimum, ctrl->maximum, ctrl->step);
switch (ctrl->id) {
- case MSI3101_CID_SAMPLING_MODE:
- case MSI3101_CID_SAMPLING_RATE:
- case MSI3101_CID_SAMPLING_RESOLUTION:
- ret = 0;
- break;
- case MSI3101_CID_TUNER_RF:
case MSI3101_CID_TUNER_BW:
- case MSI3101_CID_TUNER_IF:
case MSI3101_CID_TUNER_GAIN:
ret = msi3101_set_tuner(s);
break;
@@ -1991,70 +1946,16 @@ static int msi3101_probe(struct usb_interface *intf,
struct usb_device *udev = interface_to_usbdev(intf);
struct msi3101_state *s = NULL;
int ret;
- static const char * const ctrl_sampling_mode_qmenu_strings[] = {
- "Quadrature Sampling",
- NULL,
- };
- static const struct v4l2_ctrl_config ctrl_sampling_mode = {
- .ops = &msi3101_ctrl_ops,
- .id = MSI3101_CID_SAMPLING_MODE,
- .type = V4L2_CTRL_TYPE_MENU,
- .flags = V4L2_CTRL_FLAG_INACTIVE,
- .name = "Sampling Mode",
- .qmenu = ctrl_sampling_mode_qmenu_strings,
- };
- static const struct v4l2_ctrl_config ctrl_sampling_rate = {
- .ops = &msi3101_ctrl_ops,
- .id = MSI3101_CID_SAMPLING_RATE,
- .type = V4L2_CTRL_TYPE_INTEGER64,
- .name = "Sampling Rate",
- .min = 500000,
- .max = 12000000,
- .def = 2048000,
- .step = 1,
- };
- static const struct v4l2_ctrl_config ctrl_sampling_resolution = {
- .ops = &msi3101_ctrl_ops,
- .id = MSI3101_CID_SAMPLING_RESOLUTION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .flags = V4L2_CTRL_FLAG_INACTIVE,
- .name = "Sampling Resolution",
- .min = 10,
- .max = 10,
- .def = 10,
- .step = 1,
- };
- static const struct v4l2_ctrl_config ctrl_tuner_rf = {
- .ops = &msi3101_ctrl_ops,
- .id = MSI3101_CID_TUNER_RF,
- .type = V4L2_CTRL_TYPE_INTEGER64,
- .name = "Tuner RF",
- .min = 40000000,
- .max = 2000000000,
- .def = 100000000,
- .step = 1,
- };
static const struct v4l2_ctrl_config ctrl_tuner_bw = {
.ops = &msi3101_ctrl_ops,
.id = MSI3101_CID_TUNER_BW,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Tuner BW",
+ .name = "Tuner Bandwidth",
.min = 200000,
.max = 8000000,
.def = 600000,
.step = 1,
};
- static const struct v4l2_ctrl_config ctrl_tuner_if = {
- .ops = &msi3101_ctrl_ops,
- .id = MSI3101_CID_TUNER_IF,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .flags = V4L2_CTRL_FLAG_INACTIVE,
- .name = "Tuner IF",
- .min = 0,
- .max = 2048000,
- .def = 0,
- .step = 1,
- };
static const struct v4l2_ctrl_config ctrl_tuner_gain = {
.ops = &msi3101_ctrl_ops,
.id = MSI3101_CID_TUNER_GAIN,
@@ -2062,7 +1963,7 @@ static int msi3101_probe(struct usb_interface *intf,
.name = "Tuner Gain",
.min = 0,
.max = 102,
- .def = 0,
+ .def = 50,
.step = 1,
};
@@ -2088,7 +1989,7 @@ static int msi3101_probe(struct usb_interface *intf,
s->vb_queue.mem_ops = &vb2_vmalloc_memops;
s->vb_queue.timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
ret = vb2_queue_init(&s->vb_queue);
- if (ret < 0) {
+ if (ret) {
dev_err(&s->udev->dev, "Could not initialize vb2 queue\n");
goto err_free_mem;
}
@@ -2101,13 +2002,8 @@ static int msi3101_probe(struct usb_interface *intf,
video_set_drvdata(&s->vdev, s);
/* Register controls */
- v4l2_ctrl_handler_init(&s->ctrl_handler, 7);
- v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_sampling_mode, NULL);
- s->ctrl_sampling_rate = v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_sampling_rate, NULL);
- v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_sampling_resolution, NULL);
- s->ctrl_tuner_rf = v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_tuner_rf, NULL);
+ v4l2_ctrl_handler_init(&s->ctrl_handler, 2);
s->ctrl_tuner_bw = v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_tuner_bw, NULL);
- s->ctrl_tuner_if = v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_tuner_if, NULL);
s->ctrl_tuner_gain = v4l2_ctrl_new_custom(&s->ctrl_handler, &ctrl_tuner_gain, NULL);
if (s->ctrl_handler.error) {
ret = s->ctrl_handler.error;
@@ -2129,7 +2025,7 @@ static int msi3101_probe(struct usb_interface *intf,
s->vdev.lock = &s->v4l2_lock;
ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1);
- if (ret < 0) {
+ if (ret) {
dev_err(&s->udev->dev,
"Failed to register as video device (%d)\n",
ret);
--
1.8.4.2
^ permalink raw reply related [flat|nested] 11+ messages in thread* [PATCH 6/6] v4l: disable lockdep on vb2_fop_mmap()
2013-12-29 4:51 [PATCH 0/6] convert drivers to SDR API Antti Palosaari
` (4 preceding siblings ...)
2013-12-29 4:51 ` [PATCH 5/6] msi3101: tons of small changes Antti Palosaari
@ 2013-12-29 4:51 ` Antti Palosaari
2014-01-17 10:04 ` Hans Verkuil
5 siblings, 1 reply; 11+ messages in thread
From: Antti Palosaari @ 2013-12-29 4:51 UTC (permalink / raw)
To: linux-media; +Cc: Hans Verkuil, Antti Palosaari
Avoid that lockdep warning:
[ INFO: possible circular locking dependency detected ]
3.13.0-rc1+ #77 Tainted: G C O
-------------------------------------------------------
video_source:sr/32072 is trying to acquire lock:
(&dev->mutex#2){+.+.+.}, at: [<ffffffffa073fde3>] vb2_fop_mmap+0x33/0x90 [videobuf2_core]
but task is already holding lock:
(&mm->mmap_sem){++++++}, at: [<ffffffff8117825f>] vm_mmap_pgoff+0x6f/0xc0
Possible unsafe locking scenario:
CPU0 CPU1
---- ----
lock(&mm->mmap_sem);
lock(&dev->mutex#2);
lock(&mm->mmap_sem);
lock(&dev->mutex#2);
*** DEADLOCK ***
Signed-off-by: Antti Palosaari <crope@iki.fi>
---
drivers/media/v4l2-core/videobuf2-core.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index 12df9fd..2a74295 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -2641,12 +2641,24 @@ int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma)
struct video_device *vdev = video_devdata(file);
struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
int err;
+ /*
+ * FIXME: Ugly hack. Disable possible lockdep as it detects possible
+ * deadlock. "INFO: possible circular locking dependency detected"
+ */
+ lockdep_off();
- if (lock && mutex_lock_interruptible(lock))
+ if (lock && mutex_lock_interruptible(lock)) {
+ lockdep_on();
return -ERESTARTSYS;
+ }
+
err = vb2_mmap(vdev->queue, vma);
+
if (lock)
mutex_unlock(lock);
+
+ lockdep_on();
+
return err;
}
EXPORT_SYMBOL_GPL(vb2_fop_mmap);
--
1.8.4.2
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [PATCH 6/6] v4l: disable lockdep on vb2_fop_mmap()
2013-12-29 4:51 ` [PATCH 6/6] v4l: disable lockdep on vb2_fop_mmap() Antti Palosaari
@ 2014-01-17 10:04 ` Hans Verkuil
2014-01-17 15:14 ` Antti Palosaari
0 siblings, 1 reply; 11+ messages in thread
From: Hans Verkuil @ 2014-01-17 10:04 UTC (permalink / raw)
To: Antti Palosaari; +Cc: linux-media
Hi Antti,
Is this still needed after this commit was merged?
http://git.linuxtv.org/media_tree.git/commit/b18a8ff29d80b132018d33479e86ab8ecaee6b46
Regards,
Hans
On 12/29/2013 05:51 AM, Antti Palosaari wrote:
> Avoid that lockdep warning:
>
> [ INFO: possible circular locking dependency detected ]
> 3.13.0-rc1+ #77 Tainted: G C O
> -------------------------------------------------------
> video_source:sr/32072 is trying to acquire lock:
> (&dev->mutex#2){+.+.+.}, at: [<ffffffffa073fde3>] vb2_fop_mmap+0x33/0x90 [videobuf2_core]
>
> but task is already holding lock:
> (&mm->mmap_sem){++++++}, at: [<ffffffff8117825f>] vm_mmap_pgoff+0x6f/0xc0
>
> Possible unsafe locking scenario:
> CPU0 CPU1
> ---- ----
> lock(&mm->mmap_sem);
> lock(&dev->mutex#2);
> lock(&mm->mmap_sem);
> lock(&dev->mutex#2);
> *** DEADLOCK ***
>
> Signed-off-by: Antti Palosaari <crope@iki.fi>
> ---
> drivers/media/v4l2-core/videobuf2-core.c | 14 +++++++++++++-
> 1 file changed, 13 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
> index 12df9fd..2a74295 100644
> --- a/drivers/media/v4l2-core/videobuf2-core.c
> +++ b/drivers/media/v4l2-core/videobuf2-core.c
> @@ -2641,12 +2641,24 @@ int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma)
> struct video_device *vdev = video_devdata(file);
> struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
> int err;
> + /*
> + * FIXME: Ugly hack. Disable possible lockdep as it detects possible
> + * deadlock. "INFO: possible circular locking dependency detected"
> + */
> + lockdep_off();
>
> - if (lock && mutex_lock_interruptible(lock))
> + if (lock && mutex_lock_interruptible(lock)) {
> + lockdep_on();
> return -ERESTARTSYS;
> + }
> +
> err = vb2_mmap(vdev->queue, vma);
> +
> if (lock)
> mutex_unlock(lock);
> +
> + lockdep_on();
> +
> return err;
> }
> EXPORT_SYMBOL_GPL(vb2_fop_mmap);
>
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [PATCH 6/6] v4l: disable lockdep on vb2_fop_mmap()
2014-01-17 10:04 ` Hans Verkuil
@ 2014-01-17 15:14 ` Antti Palosaari
0 siblings, 0 replies; 11+ messages in thread
From: Antti Palosaari @ 2014-01-17 15:14 UTC (permalink / raw)
To: Hans Verkuil; +Cc: linux-media
Hi Hans
On 17.01.2014 12:04, Hans Verkuil wrote:
> Hi Antti,
>
> Is this still needed after this commit was merged?
>
> http://git.linuxtv.org/media_tree.git/commit/b18a8ff29d80b132018d33479e86ab8ecaee6b46
It didn't fix the problem.
I could reproduce that issue easily using vivi and Cheese (webcam app).
1) Compile Kernel with lockdep debug. For me these seems to be enabled:
CONFIG_LOCKDEP_SUPPORT=y
CONFIG_LOCKDEP=y
CONFIG_DEBUG_LOCKDEP=y
2) Load virtual video driver (vivi)
# modprobe vivi
3) Start Cheese
$ cheese
Lockdep error appears to system log just after Cheese is started. I
think it is related to mmap.
regards
Antti
tammi 17 17:07:38 localhost.localdomain kernel: media: Linux media
interface: v0.10
tammi 17 17:07:38 localhost.localdomain kernel: Linux video capture
interface: v2.00
tammi 17 17:07:38 localhost.localdomain kernel: vivi-000: V4L2 device
registered as video0
tammi 17 17:07:38 localhost.localdomain kernel: Video Technology
Magazine Virtual Video Capture Board ver 0.8.1 successfully loaded.
tammi 17 17:07:50 localhost.localdomain /etc/gdm/Xsession[1521]: Window
manager warning: Buggy client sent a _NET_ACTIVE_WINDOW message with a
timestamp of 0 for 0x3200024 (Cheese)
tammi 17 17:07:50 localhost.localdomain /etc/gdm/Xsession[1521]: Window
manager warning: meta_window_activate called by a pager with a 0
timestamp; the pager needs to be fixed.
tammi 17 17:07:50 localhost.localdomain kernel: tammi 17 17:07:50
localhost.localdomain kernel:
======================================================
tammi 17 17:07:50 localhost.localdomain kernel: [ INFO: possible
circular locking dependency detected ]
tammi 17 17:07:50 localhost.localdomain kernel: 3.13.0-rc1+ #79 Tainted:
G C O
tammi 17 17:07:50 localhost.localdomain kernel:
-------------------------------------------------------
tammi 17 17:07:50 localhost.localdomain kernel: video_source:sr/8871 is
trying to acquire lock:
tammi 17 17:07:50 localhost.localdomain kernel:
(&dev->mutex#2){+.+.+.}, at: [<ffffffffa06a8df3>] vb2_fop_mmap+0x33/0x90
[videobuf2_core]
tammi 17 17:07:50 localhost.localdomain kernel:
but task is already
holding lock:
tammi 17 17:07:50 localhost.localdomain kernel:
(&mm->mmap_sem){++++++}, at: [<ffffffff8117825f>] vm_mmap_pgoff+0x6f/0xc0
tammi 17 17:07:50 localhost.localdomain kernel:
which lock already
depends on the new lock.
tammi 17 17:07:50 localhost.localdomain kernel:
the existing dependency
chain (in reverse order) is:
tammi 17 17:07:50 localhost.localdomain kernel:
-> #1
(&mm->mmap_sem){++++++}:
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffff810bb386>] __lock_acquire+0x3d6/0xc40
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffff810bbca0>] lock_acquire+0xb0/0x150
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffff81181f3c>] might_fault+0x8c/0xb0
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffffa067dc15>] video_usercopy+0x375/0x5e0 [videodev]
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffffa067de95>] video_ioctl2+0x15/0x20 [videodev]
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffffa0677703>] v4l2_ioctl+0x123/0x160 [videodev]
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffff811e0590>] do_vfs_ioctl+0x300/0x520
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffff811e0831>] SyS_ioctl+0x81/0xa0
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffff816ca729>] system_call_fastpath+0x16/0x1b
tammi 17 17:07:50 localhost.localdomain kernel:
-> #0
(&dev->mutex#2){+.+.+.}:
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffff810b96b7>] validate_chain.isra.36+0x10d7/0x1130
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffff810bb386>] __lock_acquire+0x3d6/0xc40
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffff810bbca0>] lock_acquire+0xb0/0x150
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffff816bf1c7>] mutex_lock_interruptible_nested+0x77/0x460
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffffa06a8df3>] vb2_fop_mmap+0x33/0x90 [videobuf2_core]
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffffa067711a>] v4l2_mmap+0x5a/0xa0 [videodev]
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffff8118da7d>] mmap_region+0x3cd/0x5a0
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffff8118dfa7>] do_mmap_pgoff+0x357/0x3e0
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffff81178280>] vm_mmap_pgoff+0x90/0xc0
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffff8118c553>] SyS_mmap_pgoff+0x1d3/0x270
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffff810191a2>] SyS_mmap+0x22/0x30
tammi 17 17:07:50 localhost.localdomain kernel:
[<ffffffff816ca729>] system_call_fastpath+0x16/0x1b
tammi 17 17:07:50 localhost.localdomain kernel:
other info that might
help us debug this:
tammi 17 17:07:50 localhost.localdomain kernel: Possible unsafe locking
scenario:
tammi 17 17:07:50 localhost.localdomain kernel: CPU0
CPU1
tammi 17 17:07:50 localhost.localdomain kernel: ----
----
tammi 17 17:07:50 localhost.localdomain kernel: lock(&mm->mmap_sem);
tammi 17 17:07:50 localhost.localdomain kernel:
lock(&dev->mutex#2);
tammi 17 17:07:50 localhost.localdomain kernel:
lock(&mm->mmap_sem);
tammi 17 17:07:50 localhost.localdomain kernel: lock(&dev->mutex#2);
tammi 17 17:07:50 localhost.localdomain kernel:
*** DEADLOCK ***
tammi 17 17:07:50 localhost.localdomain kernel: 1 lock held by
video_source:sr/8871:
tammi 17 17:07:50 localhost.localdomain kernel: #0:
(&mm->mmap_sem){++++++}, at: [<ffffffff8117825f>] vm_mmap_pgoff+0x6f/0xc0
tammi 17 17:07:50 localhost.localdomain kernel:
stack backtrace:
tammi 17 17:07:50 localhost.localdomain kernel: CPU: 3 PID: 8871 Comm:
video_source:sr Tainted: G C O 3.13.0-rc1+ #79
tammi 17 17:07:50 localhost.localdomain kernel: Hardware name: System
manufacturer System Product Name/M5A78L-M/USB3, BIOS 1801 11/12/2013
tammi 17 17:07:50 localhost.localdomain kernel: ffffffff824f9bd0
ffff880083075b68 ffffffff816b8da9 ffffffff824f9bd0
tammi 17 17:07:50 localhost.localdomain kernel: ffff880083075ba8
ffffffff816b2c9b ffff880083075be0 0000000000000000
tammi 17 17:07:50 localhost.localdomain kernel: ffff8801ee6fc378
0000000000000001 ffff8801ee6fbcf0 ffff8801ee6fc378
tammi 17 17:07:50 localhost.localdomain kernel: Call Trace:
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffff816b8da9>]
dump_stack+0x4d/0x66
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffff816b2c9b>]
print_circular_bug+0x200/0x20e
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffff810b96b7>]
validate_chain.isra.36+0x10d7/0x1130
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffff810bb3a7>] ?
__lock_acquire+0x3f7/0xc40
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffff8101c413>] ?
native_sched_clock+0x13/0x80
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffff810bb386>]
__lock_acquire+0x3d6/0xc40
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffff8101c413>] ?
native_sched_clock+0x13/0x80
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffff8101c489>] ?
sched_clock+0x9/0x10
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffff810bbca0>]
lock_acquire+0xb0/0x150
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffffa06a8df3>] ?
vb2_fop_mmap+0x33/0x90 [videobuf2_core]
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffff816bf1c7>]
mutex_lock_interruptible_nested+0x77/0x460
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffffa06a8df3>] ?
vb2_fop_mmap+0x33/0x90 [videobuf2_core]
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffffa06a8df3>] ?
vb2_fop_mmap+0x33/0x90 [videobuf2_core]
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffffa06a8df3>]
vb2_fop_mmap+0x33/0x90 [videobuf2_core]
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffffa067711a>]
v4l2_mmap+0x5a/0xa0 [videodev]
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffff8118da7d>]
mmap_region+0x3cd/0x5a0
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffff8118dfa7>]
do_mmap_pgoff+0x357/0x3e0
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffff81178280>]
vm_mmap_pgoff+0x90/0xc0
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffff8118c553>]
SyS_mmap_pgoff+0x1d3/0x270
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffff810191a2>]
SyS_mmap+0x22/0x30
tammi 17 17:07:50 localhost.localdomain kernel: [<ffffffff816ca729>]
system_call_fastpath+0x16/0x1b
>
> Regards,
>
> Hans
>
> On 12/29/2013 05:51 AM, Antti Palosaari wrote:
>> Avoid that lockdep warning:
>>
>> [ INFO: possible circular locking dependency detected ]
>> 3.13.0-rc1+ #77 Tainted: G C O
>> -------------------------------------------------------
>> video_source:sr/32072 is trying to acquire lock:
>> (&dev->mutex#2){+.+.+.}, at: [<ffffffffa073fde3>] vb2_fop_mmap+0x33/0x90 [videobuf2_core]
>>
>> but task is already holding lock:
>> (&mm->mmap_sem){++++++}, at: [<ffffffff8117825f>] vm_mmap_pgoff+0x6f/0xc0
>>
>> Possible unsafe locking scenario:
>> CPU0 CPU1
>> ---- ----
>> lock(&mm->mmap_sem);
>> lock(&dev->mutex#2);
>> lock(&mm->mmap_sem);
>> lock(&dev->mutex#2);
>> *** DEADLOCK ***
>>
>> Signed-off-by: Antti Palosaari <crope@iki.fi>
>> ---
>> drivers/media/v4l2-core/videobuf2-core.c | 14 +++++++++++++-
>> 1 file changed, 13 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
>> index 12df9fd..2a74295 100644
>> --- a/drivers/media/v4l2-core/videobuf2-core.c
>> +++ b/drivers/media/v4l2-core/videobuf2-core.c
>> @@ -2641,12 +2641,24 @@ int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma)
>> struct video_device *vdev = video_devdata(file);
>> struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
>> int err;
>> + /*
>> + * FIXME: Ugly hack. Disable possible lockdep as it detects possible
>> + * deadlock. "INFO: possible circular locking dependency detected"
>> + */
>> + lockdep_off();
>>
>> - if (lock && mutex_lock_interruptible(lock))
>> + if (lock && mutex_lock_interruptible(lock)) {
>> + lockdep_on();
>> return -ERESTARTSYS;
>> + }
>> +
>> err = vb2_mmap(vdev->queue, vma);
>> +
>> if (lock)
>> mutex_unlock(lock);
>> +
>> + lockdep_on();
>> +
>> return err;
>> }
>> EXPORT_SYMBOL_GPL(vb2_fop_mmap);
>>
>
--
http://palosaari.fi/
^ permalink raw reply [flat|nested] 11+ messages in thread