|
@@ -16,20 +16,36 @@
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
+ *
|
|
|
+ * That driver is somehow based of pwc driver:
|
|
|
+ * (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:
|
|
|
+ * I will look these:
|
|
|
+ * - split RF tuner and USB ADC interface to own drivers (msi2500 and msi001)
|
|
|
+ * - move controls to V4L2 API
|
|
|
+ *
|
|
|
+ * Help is very highly welcome for these + all the others you could imagine:
|
|
|
+ * - use libv4l2 for stream format conversions
|
|
|
+ * - gr-kernel: switch to v4l2_mmap (current read eats a lot of cpu)
|
|
|
+ * - SDRSharp support
|
|
|
*/
|
|
|
|
|
|
-#include <linux/kernel.h>
|
|
|
#include <linux/module.h>
|
|
|
-#include <linux/init.h>
|
|
|
#include <linux/slab.h>
|
|
|
-#include <linux/input.h>
|
|
|
-#include <linux/videodev2.h>
|
|
|
#include <media/v4l2-device.h>
|
|
|
#include <media/v4l2-ioctl.h>
|
|
|
#include <media/v4l2-ctrls.h>
|
|
|
#include <media/v4l2-event.h>
|
|
|
#include <linux/usb.h>
|
|
|
-#include <linux/mutex.h>
|
|
|
#include <media/videobuf2-vmalloc.h>
|
|
|
|
|
|
struct msi3101_gain {
|
|
@@ -358,9 +374,9 @@ static const struct msi3101_gain msi3101_gain_lut_1000[] = {
|
|
|
#define ISO_FRAMES_PER_DESC (8)
|
|
|
#define ISO_MAX_FRAME_SIZE (3 * 1024)
|
|
|
#define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE)
|
|
|
-
|
|
|
#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)
|
|
@@ -373,8 +389,6 @@ static const struct msi3101_gain msi3101_gain_lut_1000[] = {
|
|
|
struct msi3101_frame_buf {
|
|
|
struct vb2_buffer vb; /* common v4l buffer stuff -- must be first */
|
|
|
struct list_head list;
|
|
|
- void *data; /* raw data from USB device */
|
|
|
- int filled; /* number of bytes filled to *data */
|
|
|
};
|
|
|
|
|
|
struct msi3101_state {
|
|
@@ -478,14 +492,19 @@ leave:
|
|
|
*/
|
|
|
|
|
|
/*
|
|
|
- * Converts signed 10-bit integer into 32-bit IEEE floating point
|
|
|
- * representation.
|
|
|
- * Will be exact from 0 to 2^24. Above that, we round towards zero
|
|
|
- * as the fractional bits will not fit in a float. (It would be better to
|
|
|
- * round towards even as the fpu does, but that is slower.)
|
|
|
+ * 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)
|
|
|
+
|
|
|
+/*
|
|
|
+ * Converts signed ~10+3-bit integer into 32-bit IEEE floating point
|
|
|
+ * representation.
|
|
|
+ */
|
|
|
static u32 msi3101_convert_sample_384(struct msi3101_state *s, u16 x, int shift)
|
|
|
{
|
|
|
u32 msb, exponent, fraction, sign;
|
|
@@ -510,35 +529,26 @@ static u32 msi3101_convert_sample_384(struct msi3101_state *s, u16 x, int shift)
|
|
|
/* Get location of the most significant bit */
|
|
|
msb = __fls(x);
|
|
|
|
|
|
- /*
|
|
|
- * Use a rotate instead of a shift because that works both leftwards
|
|
|
- * and rightwards due to the mod(32) behaviour. This means we don't
|
|
|
- * need to check to see if we are above 2^24 or not.
|
|
|
- */
|
|
|
fraction = ror32(x, (msb - I2F_FRAC_BITS) & 0x1f) & I2F_MASK;
|
|
|
exponent = (127 + msb) << I2F_FRAC_BITS;
|
|
|
|
|
|
return (fraction + exponent) | sign;
|
|
|
}
|
|
|
|
|
|
-#define MSI3101_CONVERT_IN_URB_HANDLER
|
|
|
-#define MSI3101_EXTENSIVE_DEBUG
|
|
|
static int msi3101_convert_stream_384(struct msi3101_state *s, u32 *dst,
|
|
|
u8 *src, unsigned int src_len)
|
|
|
{
|
|
|
int i, j, k, l, i_max, dst_len = 0;
|
|
|
u16 sample[4];
|
|
|
u32 bits;
|
|
|
-#ifdef MSI3101_EXTENSIVE_DEBUG
|
|
|
u32 sample_num[3];
|
|
|
-#endif
|
|
|
+
|
|
|
/* There could be 1-3 1024 bytes URB frames */
|
|
|
i_max = src_len / 1024;
|
|
|
for (i = 0; i < i_max; i++) {
|
|
|
-#ifdef MSI3101_EXTENSIVE_DEBUG
|
|
|
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(&s->udev->dev,
|
|
|
+ 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]);
|
|
@@ -550,9 +560,7 @@ static int msi3101_convert_stream_384(struct msi3101_state *s, u32 *dst,
|
|
|
*/
|
|
|
dev_dbg_ratelimited(&s->udev->dev,
|
|
|
"%*ph %*ph\n", 12, &src[4], 24, &src[1000]);
|
|
|
- memset(&src[4], 0, 12);
|
|
|
- memset(&src[1000], 0, 24);
|
|
|
-#endif
|
|
|
+
|
|
|
src += 16;
|
|
|
for (j = 0; j < 6; j++) {
|
|
|
bits = src[160 + 3] << 24 | src[160 + 2] << 16 | src[160 + 1] << 8 | src[160 + 0] << 0;
|
|
@@ -567,22 +575,18 @@ static int msi3101_convert_stream_384(struct msi3101_state *s, u32 *dst,
|
|
|
*dst++ = msi3101_convert_sample_384(s, sample[1], (bits >> (2 * k)) & 0x3);
|
|
|
*dst++ = msi3101_convert_sample_384(s, sample[2], (bits >> (2 * k)) & 0x3);
|
|
|
*dst++ = msi3101_convert_sample_384(s, sample[3], (bits >> (2 * k)) & 0x3);
|
|
|
-
|
|
|
- /* 4 x 32bit float samples */
|
|
|
- dst_len += 4 * 4;
|
|
|
}
|
|
|
src += 10;
|
|
|
}
|
|
|
-#ifdef MSI3101_EXTENSIVE_DEBUG
|
|
|
dev_dbg_ratelimited(&s->udev->dev,
|
|
|
"sample control bits %08x\n", bits);
|
|
|
-#endif
|
|
|
src += 4;
|
|
|
}
|
|
|
+ /* 384 x I+Q 32bit float samples */
|
|
|
+ dst_len += 384 * 2 * 4;
|
|
|
src += 24;
|
|
|
}
|
|
|
|
|
|
-#ifdef MSI3101_EXTENSIVE_DEBUG
|
|
|
/* calculate samping rate and output it in 10 seconds intervals */
|
|
|
if ((s->jiffies + msecs_to_jiffies(10000)) <= jiffies) {
|
|
|
unsigned long jiffies_now = jiffies;
|
|
@@ -600,7 +604,7 @@ static int msi3101_convert_stream_384(struct msi3101_state *s, u32 *dst,
|
|
|
|
|
|
/* next sample (sample = sample + i * 384) */
|
|
|
s->next_sample = sample_num[i_max - 1] + 384;
|
|
|
-#endif
|
|
|
+
|
|
|
return dst_len;
|
|
|
}
|
|
|
|
|
@@ -628,11 +632,6 @@ static u32 msi3101_convert_sample_336(struct msi3101_state *s, u16 x)
|
|
|
/* Get location of the most significant bit */
|
|
|
msb = __fls(x);
|
|
|
|
|
|
- /*
|
|
|
- * Use a rotate instead of a shift because that works both leftwards
|
|
|
- * and rightwards due to the mod(32) behaviour. This means we don't
|
|
|
- * need to check to see if we are above 2^24 or not.
|
|
|
- */
|
|
|
fraction = ror32(x, (msb - I2F_FRAC_BITS) & 0x1f) & I2F_MASK;
|
|
|
exponent = (127 + msb) << I2F_FRAC_BITS;
|
|
|
|
|
@@ -699,12 +698,7 @@ static int msi3101_convert_stream_336(struct msi3101_state *s, u32 *dst,
|
|
|
/*
|
|
|
* Converts signed 14-bit integer into 32-bit IEEE floating point
|
|
|
* representation.
|
|
|
- * Will be exact from 0 to 2^24. Above that, we round towards zero
|
|
|
- * as the fractional bits will not fit in a float. (It would be better to
|
|
|
- * round towards even as the fpu does, but that is slower.)
|
|
|
*/
|
|
|
-#define I2F_FRAC_BITS 23
|
|
|
-#define I2F_MASK ((1 << I2F_FRAC_BITS) - 1)
|
|
|
static u32 msi3101_convert_sample_252(struct msi3101_state *s, u16 x)
|
|
|
{
|
|
|
u32 msb, exponent, fraction, sign;
|
|
@@ -725,11 +719,6 @@ static u32 msi3101_convert_sample_252(struct msi3101_state *s, u16 x)
|
|
|
/* Get location of the most significant bit */
|
|
|
msb = __fls(x);
|
|
|
|
|
|
- /*
|
|
|
- * Use a rotate instead of a shift because that works both leftwards
|
|
|
- * and rightwards due to the mod(32) behaviour. This means we don't
|
|
|
- * need to check to see if we are above 2^24 or not.
|
|
|
- */
|
|
|
fraction = ror32(x, (msb - I2F_FRAC_BITS) & 0x1f) & I2F_MASK;
|
|
|
exponent = (127 + msb) << I2F_FRAC_BITS;
|
|
|
|
|
@@ -832,7 +821,7 @@ static void msi3101_isoc_handler(struct urb *urb)
|
|
|
/* Check frame error */
|
|
|
fstatus = urb->iso_frame_desc[i].status;
|
|
|
if (fstatus) {
|
|
|
- dev_dbg(&s->udev->dev,
|
|
|
+ dev_dbg_ratelimited(&s->udev->dev,
|
|
|
"frame=%d/%d has error %d skipping\n",
|
|
|
i, urb->number_of_packets, fstatus);
|
|
|
goto skip;
|
|
@@ -856,14 +845,9 @@ static void msi3101_isoc_handler(struct urb *urb)
|
|
|
}
|
|
|
|
|
|
/* fill framebuffer */
|
|
|
-#ifdef MSI3101_CONVERT_IN_URB_HANDLER
|
|
|
ptr = vb2_plane_vaddr(&fbuf->vb, 0);
|
|
|
flen = s->convert_stream(s, ptr, iso_buf, flen);
|
|
|
vb2_set_plane_payload(&fbuf->vb, 0, flen);
|
|
|
-#else
|
|
|
- memcpy(fbuf->data, iso_buf, flen);
|
|
|
- fbuf->filled = flen;
|
|
|
-#endif
|
|
|
vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE);
|
|
|
skip:
|
|
|
;
|
|
@@ -1063,20 +1047,6 @@ static int msi3101_queue_setup(struct vb2_queue *vq,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int msi3101_buf_init(struct vb2_buffer *vb)
|
|
|
-{
|
|
|
- struct msi3101_state *s = vb2_get_drv_priv(vb->vb2_queue);
|
|
|
- struct msi3101_frame_buf *fbuf =
|
|
|
- container_of(vb, struct msi3101_frame_buf, vb);
|
|
|
- dev_dbg(&s->udev->dev, "%s:\n", __func__);
|
|
|
-
|
|
|
- fbuf->data = vzalloc(ISO_MAX_FRAME_SIZE);
|
|
|
- if (fbuf->data == NULL)
|
|
|
- return -ENOMEM;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
static int msi3101_buf_prepare(struct vb2_buffer *vb)
|
|
|
{
|
|
|
struct msi3101_state *s = vb2_get_drv_priv(vb->vb2_queue);
|
|
@@ -1088,34 +1058,6 @@ static int msi3101_buf_prepare(struct vb2_buffer *vb)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-#ifdef MSI3101_CONVERT_IN_URB_HANDLER
|
|
|
-static int msi3101_buf_finish(struct vb2_buffer *vb)
|
|
|
-{
|
|
|
- return 0;
|
|
|
-}
|
|
|
-#else
|
|
|
-static int msi3101_buf_finish(struct vb2_buffer *vb)
|
|
|
-{
|
|
|
- struct msi3101_state *s = vb2_get_drv_priv(vb->vb2_queue);
|
|
|
- struct msi3101_frame_buf *fbuf =
|
|
|
- container_of(vb, struct msi3101_frame_buf, vb);
|
|
|
- int ret;
|
|
|
- u32 *dst = vb2_plane_vaddr(&fbuf->vb, 0);
|
|
|
- ret = msi3101_convert_stream_384(s, dst, fbuf->data, fbuf->filled);
|
|
|
- vb2_set_plane_payload(&fbuf->vb, 0, ret);
|
|
|
- return 0;
|
|
|
-}
|
|
|
-#endif
|
|
|
-
|
|
|
-static void msi3101_buf_cleanup(struct vb2_buffer *vb)
|
|
|
-{
|
|
|
- struct msi3101_state *s = vb2_get_drv_priv(vb->vb2_queue);
|
|
|
- struct msi3101_frame_buf *buf =
|
|
|
- container_of(vb, struct msi3101_frame_buf, vb);
|
|
|
- dev_dbg(&s->udev->dev, "%s:\n", __func__);
|
|
|
-
|
|
|
- vfree(buf->data);
|
|
|
-}
|
|
|
static void msi3101_buf_queue(struct vb2_buffer *vb)
|
|
|
{
|
|
|
struct msi3101_state *s = vb2_get_drv_priv(vb->vb2_queue);
|
|
@@ -1544,10 +1486,7 @@ static int msi3101_stop_streaming(struct vb2_queue *vq)
|
|
|
|
|
|
static struct vb2_ops msi3101_vb2_ops = {
|
|
|
.queue_setup = msi3101_queue_setup,
|
|
|
- .buf_init = msi3101_buf_init,
|
|
|
.buf_prepare = msi3101_buf_prepare,
|
|
|
- .buf_finish = msi3101_buf_finish,
|
|
|
- .buf_cleanup = msi3101_buf_cleanup,
|
|
|
.buf_queue = msi3101_buf_queue,
|
|
|
.start_streaming = msi3101_start_streaming,
|
|
|
.stop_streaming = msi3101_stop_streaming,
|
|
@@ -1862,7 +1801,7 @@ err_free_mem:
|
|
|
|
|
|
/* USB device ID list */
|
|
|
static struct usb_device_id msi3101_id_table[] = {
|
|
|
- { USB_DEVICE(0x1df7, 0x2500) },
|
|
|
+ { USB_DEVICE(0x1df7, 0x2500) }, /* Mirics MSi3101 SDR Dongle */
|
|
|
{ USB_DEVICE(0x2040, 0xd300) }, /* Hauppauge WinTV 133559 LF */
|
|
|
{ }
|
|
|
};
|