@@ -387,6 +387,22 @@ static const struct msi3101_gain msi3101_gain_lut_1000[] = {
#define V4L2_PIX_FMT_SDR_S8 v4l2_fourcc('D', 'S', '0', '8') /* signed 8-bit */
+/* stream formats */
+struct msi3101_format {
+ char *name;
+ u32 pixelformat;
+};
+
+/* format descriptions for capture and preview */
+static struct msi3101_format formats[] = {
+ {
+ .name = "I/Q 8-bit signed",
+ .pixelformat = V4L2_PIX_FMT_SDR_S8,
+ },
+};
+
+static const int NUM_FORMATS = sizeof(formats) / sizeof(struct msi3101_format);
+
/* intermediate buffers with raw data from the USB device */
struct msi3101_frame_buf {
struct vb2_buffer vb; /* common v4l buffer stuff -- must be first */
@@ -409,6 +425,8 @@ struct msi3101_state {
/* Pointer to our usb_device, will be NULL after unplug */
struct usb_device *udev; /* Both mutexes most be hold when setting! */
+ u32 pixelformat;
+
unsigned int isoc_errors; /* number of contiguous ISOC errors */
unsigned int vb_full; /* vb is full and packets dropped */
@@ -447,7 +465,6 @@ leave:
spin_unlock_irqrestore(&s->queued_bufs_lock, flags);
return buf;
}
-
/*
* +===========================================================================
* | 00-1023 | USB packet type '384'
@@ -504,40 +521,22 @@ leave:
#define I2F_MASK ((1 << I2F_FRAC_BITS) - 1)
/*
- * Converts signed 8-bit integer into 32-bit IEEE floating point
- * representation.
+ * +===========================================================================
+ * | 00-1023 | USB packet type '504'
+ * +===========================================================================
+ * | 00- 03 | sequence number of first sample in that USB packet
+ * +---------------------------------------------------------------------------
+ * | 04- 15 | garbage
+ * +---------------------------------------------------------------------------
+ * | 16-1023 | samples
+ * +---------------------------------------------------------------------------
+ * signed 8-bit sample
+ * 504 * 2 = 1008 samples
*/
-static u32 msi3101_convert_sample_504(struct msi3101_state *s, u16 x)
-{
- u32 msb, exponent, fraction, sign;
-
- /* Zero is special */
- if (!x)
- return 0;
-
- /* Negative / positive value */
- if (x & (1 << 7)) {
- x = -x;
- x &= 0x7f; /* result is 7 bit ... + sign */
- sign = 1 << 31;
- } else {
- sign = 0 << 31;
- }
-
- /* Get location of the most significant bit */
- msb = __fls(x);
-
- fraction = ror32(x, (msb - I2F_FRAC_BITS) & 0x1f) & I2F_MASK;
- exponent = (127 + msb) << I2F_FRAC_BITS;
-
- return (fraction + exponent) | sign;
-}
-
-static int msi3101_convert_stream_504(struct msi3101_state *s, u32 *dst,
+static int msi3101_convert_stream_504(struct msi3101_state *s, u8 *dst,
u8 *src, unsigned int src_len)
{
- int i, j, i_max, dst_len = 0;
- u16 sample[2];
+ int i, i_max, dst_len = 0;
u32 sample_num[3];
/* There could be 1-3 1024 bytes URB frames */
@@ -558,17 +557,12 @@ static int msi3101_convert_stream_504(struct msi3101_state *s, u32 *dst,
*/
dev_dbg_ratelimited(&s->udev->dev, "%*ph\n", 12, &src[4]);
+ /* 504 x I+Q samples */
src += 16;
- for (j = 0; j < 1008; j += 2) {
- sample[0] = src[j + 0];
- sample[1] = src[j + 1];
-
- *dst++ = msi3101_convert_sample_504(s, sample[0]);
- *dst++ = msi3101_convert_sample_504(s, sample[1]);
- }
- /* 504 x I+Q 32bit float samples */
- dst_len += 504 * 2 * 4;
+ memcpy(dst, src, 1008);
src += 1008;
+ dst += 1008;
+ dst_len += 1008;
}
/* calculate samping rate and output it in 10 seconds intervals */
@@ -1116,7 +1110,6 @@ static int msi3101_querycap(struct file *file, void *fh,
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;
- cap->device_caps = V4L2_CAP_TUNER;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1240,6 +1233,11 @@ static int msi3101_set_usb_adc(struct msi3101_state *s)
reg7 = 0x000c9407;
}
+ if (s->pixelformat == V4L2_PIX_FMT_SDR_S8) {
+ s->convert_stream = msi3101_convert_stream_504;
+ reg7 = 0x000c9407;
+ }
+
/*
* Synthesizer config is just a educated guess...
*
@@ -1634,6 +1632,84 @@ static int msi3101_s_input(struct file *file, void *fh, unsigned int i)
return i ? -EINVAL : 0;
}
+static int msi3101_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct msi3101_state *s = video_drvdata(file);
+ dev_dbg(&s->udev->dev, "%s:\n", __func__);
+
+ if (f->index >= NUM_FORMATS)
+ return -EINVAL;
+
+ strlcpy(f->description, formats[f->index].name, sizeof(f->description));
+ f->pixelformat = formats[f->index].pixelformat;
+
+ return 0;
+}
+
+static int msi3101_g_fmt_vid_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)
+ return -EINVAL;
+
+ f->fmt.pix.pixelformat = s->pixelformat;
+
+ return 0;
+}
+
+static int msi3101_s_fmt_vid_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);
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_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;
+ return 0;
+ }
+ }
+
+ f->fmt.pix.pixelformat = formats[0].pixelformat;
+ s->pixelformat = formats[0].pixelformat;
+
+ return 0;
+}
+
+static int msi3101_try_fmt_vid_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);
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (formats[i].pixelformat == f->fmt.pix.pixelformat)
+ return 0;
+ }
+
+ f->fmt.pix.pixelformat = formats[0].pixelformat;
+
+ return 0;
+}
+
static int vidioc_s_tuner(struct file *file, void *priv,
const struct v4l2_tuner *v)
{
@@ -1668,6 +1744,11 @@ static int vidioc_s_frequency(struct file *file, void *priv,
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_input = msi3101_enum_input,
.vidioc_g_input = msi3101_g_input,
.vidioc_s_input = msi3101_s_input,
VIDIOC_ENUM_FMT, VIDIOC_G_FMT, VIDIOC_S_FMT and VIDIOC_TRY_FMT. Implement 8-bit signed stream (type '504' samples per USB packet) using FMT. Signed-off-by: Antti Palosaari <crope@iki.fi> --- drivers/staging/media/msi3101/sdr-msi3101.c | 165 +++++++++++++++++++++------- 1 file changed, 123 insertions(+), 42 deletions(-)