diff options
Diffstat (limited to 'drivers/media/usb')
45 files changed, 3490 insertions, 360 deletions
diff --git a/drivers/media/usb/Kconfig b/drivers/media/usb/Kconfig index 39d824e2bb69..fa67519abda2 100644 --- a/drivers/media/usb/Kconfig +++ b/drivers/media/usb/Kconfig @@ -52,5 +52,11 @@ if (MEDIA_CAMERA_SUPPORT || MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT) source "drivers/media/usb/em28xx/Kconfig" endif +if MEDIA_SDR_SUPPORT + comment "Software defined radio USB devices" +source "drivers/media/usb/msi2500/Kconfig" +source "drivers/media/usb/airspy/Kconfig" +endif + endif #MEDIA_USB_SUPPORT endif #USB diff --git a/drivers/media/usb/Makefile b/drivers/media/usb/Makefile index 7ac4b143dce8..712a6b1e8882 100644 --- a/drivers/media/usb/Makefile +++ b/drivers/media/usb/Makefile @@ -9,6 +9,8 @@ obj-y += zr364xx/ stkwebcam/ s2255/ obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/ obj-$(CONFIG_USB_GSPCA) += gspca/ obj-$(CONFIG_USB_PWC) += pwc/ +obj-$(CONFIG_USB_MSI2500) += msi2500/ +obj-$(CONFIG_USB_AIRSPY) += airspy/ obj-$(CONFIG_VIDEO_CPIA2) += cpia2/ obj-$(CONFIG_VIDEO_AU0828) += au0828/ obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/ diff --git a/drivers/media/usb/airspy/Kconfig b/drivers/media/usb/airspy/Kconfig new file mode 100644 index 000000000000..10b204cf4dbc --- /dev/null +++ b/drivers/media/usb/airspy/Kconfig @@ -0,0 +1,10 @@ +config USB_AIRSPY + tristate "AirSpy" + depends on VIDEO_V4L2 + select VIDEOBUF2_VMALLOC + ---help--- + This is a video4linux2 driver for AirSpy SDR device. + + To compile this driver as a module, choose M here: the + module will be called airspy + diff --git a/drivers/media/usb/airspy/Makefile b/drivers/media/usb/airspy/Makefile new file mode 100644 index 000000000000..8d8e61c1a349 --- /dev/null +++ b/drivers/media/usb/airspy/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_USB_AIRSPY) += airspy.o diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c new file mode 100644 index 000000000000..cb0e515d80ae --- /dev/null +++ b/drivers/media/usb/airspy/airspy.c @@ -0,0 +1,1132 @@ +/* + * AirSpy SDR driver + * + * Copyright (C) 2014 Antti Palosaari <crope@iki.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/usb.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> +#include <media/v4l2-ctrls.h> +#include <media/v4l2-event.h> +#include <media/videobuf2-vmalloc.h> + +/* AirSpy USB API commands (from AirSpy Library) */ +enum { + CMD_INVALID = 0x00, + CMD_RECEIVER_MODE = 0x01, + CMD_SI5351C_WRITE = 0x02, + CMD_SI5351C_READ = 0x03, + CMD_R820T_WRITE = 0x04, + CMD_R820T_READ = 0x05, + CMD_SPIFLASH_ERASE = 0x06, + CMD_SPIFLASH_WRITE = 0x07, + CMD_SPIFLASH_READ = 0x08, + CMD_BOARD_ID_READ = 0x09, + CMD_VERSION_STRING_READ = 0x0a, + CMD_BOARD_PARTID_SERIALNO_READ = 0x0b, + CMD_SET_SAMPLE_RATE = 0x0c, + CMD_SET_FREQ = 0x0d, + CMD_SET_LNA_GAIN = 0x0e, + CMD_SET_MIXER_GAIN = 0x0f, + CMD_SET_VGA_GAIN = 0x10, + CMD_SET_LNA_AGC = 0x11, + CMD_SET_MIXER_AGC = 0x12, + CMD_SET_PACKING = 0x13, +}; + +/* + * bEndpointAddress 0x81 EP 1 IN + * Transfer Type Bulk + * wMaxPacketSize 0x0200 1x 512 bytes + */ +#define MAX_BULK_BUFS (6) +#define BULK_BUFFER_SIZE (128 * 512) + +static const struct v4l2_frequency_band bands[] = { + { + .tuner = 0, + .type = V4L2_TUNER_ADC, + .index = 0, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 20000000, + .rangehigh = 20000000, + }, +}; + +static const struct v4l2_frequency_band bands_rf[] = { + { + .tuner = 1, + .type = V4L2_TUNER_RF, + .index = 0, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 24000000, + .rangehigh = 1750000000, + }, +}; + +/* stream formats */ +struct airspy_format { + char *name; + u32 pixelformat; + u32 buffersize; +}; + +/* format descriptions for capture and preview */ +static struct airspy_format formats[] = { + { + .name = "Real U12LE", + .pixelformat = V4L2_SDR_FMT_RU12LE, + .buffersize = BULK_BUFFER_SIZE, + }, +}; + +static const unsigned int NUM_FORMATS = ARRAY_SIZE(formats); + +/* intermediate buffers with raw data from the USB device */ +struct airspy_frame_buf { + struct vb2_buffer vb; /* common v4l buffer stuff -- must be first */ + struct list_head list; +}; + +struct airspy { +#define POWER_ON (1 << 1) +#define URB_BUF (1 << 2) +#define USB_STATE_URB_BUF (1 << 3) + unsigned long flags; + + struct usb_device *udev; + struct video_device vdev; + struct v4l2_device v4l2_dev; + + /* videobuf2 queue and queued buffers list */ + struct vb2_queue vb_queue; + struct list_head queued_bufs; + spinlock_t queued_bufs_lock; /* Protects queued_bufs */ + unsigned sequence; /* Buffer sequence counter */ + unsigned int vb_full; /* vb is full and packets dropped */ + + /* Note if taking both locks v4l2_lock must always be locked first! */ + struct mutex v4l2_lock; /* Protects everything else */ + struct mutex vb_queue_lock; /* Protects vb_queue and capt_file */ + + struct urb *urb_list[MAX_BULK_BUFS]; + int buf_num; + unsigned long buf_size; + u8 *buf_list[MAX_BULK_BUFS]; + dma_addr_t dma_addr[MAX_BULK_BUFS]; + int urbs_initialized; + int urbs_submitted; + + /* USB control message buffer */ + #define BUF_SIZE 24 + u8 buf[BUF_SIZE]; + + /* Current configuration */ + unsigned int f_adc; + unsigned int f_rf; + u32 pixelformat; + u32 buffersize; + + /* Controls */ + struct v4l2_ctrl_handler hdl; + struct v4l2_ctrl *lna_gain_auto; + struct v4l2_ctrl *lna_gain; + struct v4l2_ctrl *mixer_gain_auto; + struct v4l2_ctrl *mixer_gain; + struct v4l2_ctrl *if_gain; + + /* Sample rate calc */ + unsigned long jiffies_next; + unsigned int sample; + unsigned int sample_measured; +}; + +#define airspy_dbg_usb_control_msg(_udev, _r, _t, _v, _i, _b, _l) { \ + char *_direction; \ + if (_t & USB_DIR_IN) \ + _direction = "<<<"; \ + else \ + _direction = ">>>"; \ + dev_dbg(&_udev->dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x " \ + "%s %*ph\n", __func__, _t, _r, _v & 0xff, _v >> 8, \ + _i & 0xff, _i >> 8, _l & 0xff, _l >> 8, _direction, \ + _l, _b); \ +} + +/* execute firmware command */ +static int airspy_ctrl_msg(struct airspy *s, u8 request, u16 value, u16 index, + u8 *data, u16 size) +{ + int ret; + unsigned int pipe; + u8 requesttype; + + switch (request) { + case CMD_RECEIVER_MODE: + case CMD_SET_FREQ: + pipe = usb_sndctrlpipe(s->udev, 0); + requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT); + break; + case CMD_BOARD_ID_READ: + case CMD_VERSION_STRING_READ: + case CMD_BOARD_PARTID_SERIALNO_READ: + case CMD_SET_LNA_GAIN: + case CMD_SET_MIXER_GAIN: + case CMD_SET_VGA_GAIN: + case CMD_SET_LNA_AGC: + case CMD_SET_MIXER_AGC: + pipe = usb_rcvctrlpipe(s->udev, 0); + requesttype = (USB_TYPE_VENDOR | USB_DIR_IN); + break; + default: + dev_err(&s->udev->dev, "Unknown command %02x\n", request); + ret = -EINVAL; + goto err; + } + + /* write request */ + if (!(requesttype & USB_DIR_IN)) + memcpy(s->buf, data, size); + + ret = usb_control_msg(s->udev, pipe, request, requesttype, value, + index, s->buf, size, 1000); + airspy_dbg_usb_control_msg(s->udev, request, requesttype, value, + index, s->buf, size); + if (ret < 0) { + dev_err(&s->udev->dev, + "usb_control_msg() failed %d request %02x\n", + ret, request); + goto err; + } + + /* read request */ + if (requesttype & USB_DIR_IN) + memcpy(data, s->buf, size); + + return 0; +err: + return ret; +} + +/* Private functions */ +static struct airspy_frame_buf *airspy_get_next_fill_buf(struct airspy *s) +{ + unsigned long flags = 0; + struct airspy_frame_buf *buf = NULL; + + spin_lock_irqsave(&s->queued_bufs_lock, flags); + if (list_empty(&s->queued_bufs)) + goto leave; + + buf = list_entry(s->queued_bufs.next, + struct airspy_frame_buf, list); + list_del(&buf->list); +leave: + spin_unlock_irqrestore(&s->queued_bufs_lock, flags); + return buf; +} + +static unsigned int airspy_convert_stream(struct airspy *s, + void *dst, void *src, unsigned int src_len) +{ + unsigned int dst_len; + + if (s->pixelformat == V4L2_SDR_FMT_RU12LE) { + memcpy(dst, src, src_len); + dst_len = src_len; + } else { + dst_len = 0; + } + + /* 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 = s->sample - s->sample_measured; + s->jiffies_next = jiffies + msecs_to_jiffies(MSECS); + s->sample_measured = s->sample; + dev_dbg(&s->udev->dev, + "slen=%d samples=%u msecs=%lu sample rate=%lu\n", + src_len, samples, MSECS, + samples * 1000UL / MSECS); + } + + /* total number of samples */ + s->sample += src_len / 2; + + return dst_len; +} + +/* + * This gets called for the bulk stream pipe. This is done in interrupt + * time, so it has to be fast, not crash, and not stall. Neat. + */ +static void airspy_urb_complete(struct urb *urb) +{ + struct airspy *s = urb->context; + struct airspy_frame_buf *fbuf; + + dev_dbg_ratelimited(&s->udev->dev, + "%s: status=%d length=%d/%d errors=%d\n", + __func__, urb->status, urb->actual_length, + urb->transfer_buffer_length, urb->error_count); + + switch (urb->status) { + case 0: /* success */ + case -ETIMEDOUT: /* NAK */ + break; + case -ECONNRESET: /* kill */ + case -ENOENT: + case -ESHUTDOWN: + return; + default: /* error */ + dev_err_ratelimited(&s->udev->dev, "URB failed %d\n", + urb->status); + break; + } + + if (likely(urb->actual_length > 0)) { + void *ptr; + unsigned int len; + /* get free framebuffer */ + fbuf = airspy_get_next_fill_buf(s); + if (unlikely(fbuf == NULL)) { + s->vb_full++; + dev_notice_ratelimited(&s->udev->dev, + "videobuf is full, %d packets dropped\n", + s->vb_full); + goto skip; + } + + /* fill framebuffer */ + ptr = vb2_plane_vaddr(&fbuf->vb, 0); + len = airspy_convert_stream(s, ptr, urb->transfer_buffer, + urb->actual_length); + vb2_set_plane_payload(&fbuf->vb, 0, len); + v4l2_get_timestamp(&fbuf->vb.v4l2_buf.timestamp); + fbuf->vb.v4l2_buf.sequence = s->sequence++; + vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE); + } +skip: + usb_submit_urb(urb, GFP_ATOMIC); +} + +static int airspy_kill_urbs(struct airspy *s) +{ + int i; + + for (i = s->urbs_submitted - 1; i >= 0; i--) { + dev_dbg(&s->udev->dev, "%s: kill urb=%d\n", __func__, i); + /* stop the URB */ + usb_kill_urb(s->urb_list[i]); + } + s->urbs_submitted = 0; + + return 0; +} + +static int airspy_submit_urbs(struct airspy *s) +{ + int i, ret; + + for (i = 0; i < s->urbs_initialized; i++) { + dev_dbg(&s->udev->dev, "%s: submit urb=%d\n", __func__, i); + ret = usb_submit_urb(s->urb_list[i], GFP_ATOMIC); + if (ret) { + dev_err(&s->udev->dev, + "Could not submit URB no. %d - get them all back\n", + i); + airspy_kill_urbs(s); + return ret; + } + s->urbs_submitted++; + } + + return 0; +} + +static int airspy_free_stream_bufs(struct airspy *s) +{ + if (s->flags & USB_STATE_URB_BUF) { + while (s->buf_num) { + s->buf_num--; + dev_dbg(&s->udev->dev, "%s: free buf=%d\n", + __func__, s->buf_num); + usb_free_coherent(s->udev, s->buf_size, + s->buf_list[s->buf_num], + s->dma_addr[s->buf_num]); + } + } + s->flags &= ~USB_STATE_URB_BUF; + + return 0; +} + +static int airspy_alloc_stream_bufs(struct airspy *s) +{ + s->buf_num = 0; + s->buf_size = BULK_BUFFER_SIZE; + + dev_dbg(&s->udev->dev, + "%s: all in all I will use %u bytes for streaming\n", + __func__, MAX_BULK_BUFS * BULK_BUFFER_SIZE); + + for (s->buf_num = 0; s->buf_num < MAX_BULK_BUFS; s->buf_num++) { + s->buf_list[s->buf_num] = usb_alloc_coherent(s->udev, + BULK_BUFFER_SIZE, GFP_ATOMIC, + &s->dma_addr[s->buf_num]); + if (!s->buf_list[s->buf_num]) { + dev_dbg(&s->udev->dev, "%s: alloc buf=%d failed\n", + __func__, s->buf_num); + airspy_free_stream_bufs(s); + return -ENOMEM; + } + + dev_dbg(&s->udev->dev, "%s: alloc buf=%d %p (dma %llu)\n", + __func__, s->buf_num, + s->buf_list[s->buf_num], + (long long)s->dma_addr[s->buf_num]); + s->flags |= USB_STATE_URB_BUF; + } + + return 0; +} + +static int airspy_free_urbs(struct airspy *s) +{ + int i; + + airspy_kill_urbs(s); + + for (i = s->urbs_initialized - 1; i >= 0; i--) { + if (s->urb_list[i]) { + dev_dbg(&s->udev->dev, "%s: free urb=%d\n", + __func__, i); + /* free the URBs */ + usb_free_urb(s->urb_list[i]); + } + } + s->urbs_initialized = 0; + + return 0; +} + +static int airspy_alloc_urbs(struct airspy *s) +{ + int i, j; + + /* allocate the URBs */ + for (i = 0; i < MAX_BULK_BUFS; i++) { + dev_dbg(&s->udev->dev, "%s: alloc urb=%d\n", __func__, i); + s->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC); + if (!s->urb_list[i]) { + dev_dbg(&s->udev->dev, "%s: failed\n", __func__); + for (j = 0; j < i; j++) + usb_free_urb(s->urb_list[j]); + return -ENOMEM; + } + usb_fill_bulk_urb(s->urb_list[i], + s->udev, + usb_rcvbulkpipe(s->udev, 0x81), + s->buf_list[i], + BULK_BUFFER_SIZE, + airspy_urb_complete, s); + + s->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; + s->urb_list[i]->transfer_dma = s->dma_addr[i]; + s->urbs_initialized++; + } + + return 0; +} + +/* Must be called with vb_queue_lock hold */ +static void airspy_cleanup_queued_bufs(struct airspy *s) +{ + unsigned long flags = 0; + + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + spin_lock_irqsave(&s->queued_bufs_lock, flags); + while (!list_empty(&s->queued_bufs)) { + struct airspy_frame_buf *buf; + buf = list_entry(s->queued_bufs.next, + struct airspy_frame_buf, list); + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + spin_unlock_irqrestore(&s->queued_bufs_lock, flags); +} + +/* The user yanked out the cable... */ +static void airspy_disconnect(struct usb_interface *intf) +{ + struct v4l2_device *v = usb_get_intfdata(intf); + struct airspy *s = container_of(v, struct airspy, v4l2_dev); + + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + mutex_lock(&s->vb_queue_lock); + mutex_lock(&s->v4l2_lock); + /* No need to keep the urbs around after disconnection */ + s->udev = NULL; + v4l2_device_disconnect(&s->v4l2_dev); + video_unregister_device(&s->vdev); + mutex_unlock(&s->v4l2_lock); + mutex_unlock(&s->vb_queue_lock); + + v4l2_device_put(&s->v4l2_dev); +} + +/* Videobuf2 operations */ +static int airspy_queue_setup(struct vb2_queue *vq, + const struct v4l2_format *fmt, unsigned int *nbuffers, + unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) +{ + struct airspy *s = vb2_get_drv_priv(vq); + + dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers); + + /* Need at least 8 buffers */ + if (vq->num_buffers + *nbuffers < 8) + *nbuffers = 8 - vq->num_buffers; + *nplanes = 1; + sizes[0] = PAGE_ALIGN(s->buffersize); + + dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n", + __func__, *nbuffers, sizes[0]); + return 0; +} + +static void airspy_buf_queue(struct vb2_buffer *vb) +{ + struct airspy *s = vb2_get_drv_priv(vb->vb2_queue); + struct airspy_frame_buf *buf = + container_of(vb, struct airspy_frame_buf, vb); + unsigned long flags = 0; + + /* Check the device has not disconnected between prep and queuing */ + if (unlikely(!s->udev)) { + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + return; + } + + spin_lock_irqsave(&s->queued_bufs_lock, flags); + list_add_tail(&buf->list, &s->queued_bufs); + spin_unlock_irqrestore(&s->queued_bufs_lock, flags); +} + +static int airspy_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct airspy *s = vb2_get_drv_priv(vq); + int ret; + + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + if (!s->udev) + return -ENODEV; + + mutex_lock(&s->v4l2_lock); + + set_bit(POWER_ON, &s->flags); + + s->sequence = 0; + + ret = airspy_alloc_stream_bufs(s); + if (ret) + goto err; + + ret = airspy_alloc_urbs(s); + if (ret) + goto err; + + ret = airspy_submit_urbs(s); + if (ret) + goto err; + + /* start hardware streaming */ + ret = airspy_ctrl_msg(s, CMD_RECEIVER_MODE, 1, 0, NULL, 0); + if (ret) + goto err; +err: + mutex_unlock(&s->v4l2_lock); + + return ret; +} + +static void airspy_stop_streaming(struct vb2_queue *vq) +{ + struct airspy *s = vb2_get_drv_priv(vq); + + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + mutex_lock(&s->v4l2_lock); + + /* stop hardware streaming */ + airspy_ctrl_msg(s, CMD_RECEIVER_MODE, 0, 0, NULL, 0); + + airspy_kill_urbs(s); + airspy_free_urbs(s); + airspy_free_stream_bufs(s); + + airspy_cleanup_queued_bufs(s); + + clear_bit(POWER_ON, &s->flags); + + mutex_unlock(&s->v4l2_lock); +} + +static struct vb2_ops airspy_vb2_ops = { + .queue_setup = airspy_queue_setup, + .buf_queue = airspy_buf_queue, + .start_streaming = airspy_start_streaming, + .stop_streaming = airspy_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static int airspy_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + struct airspy *s = video_drvdata(file); + + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); + 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_SDR_CAPTURE | V4L2_CAP_STREAMING | + V4L2_CAP_READWRITE | V4L2_CAP_TUNER; + cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS; + + return 0; +} + +static int airspy_enum_fmt_sdr_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct airspy *s = video_drvdata(file); + + dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, f->index); + + 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 airspy_g_fmt_sdr_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct airspy *s = video_drvdata(file); + + dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, + (char *)&s->pixelformat); + + f->fmt.sdr.pixelformat = s->pixelformat; + f->fmt.sdr.buffersize = s->buffersize; + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); + + return 0; +} + +static int airspy_s_fmt_sdr_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct airspy *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.sdr.pixelformat); + + if (vb2_is_busy(q)) + return -EBUSY; + + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); + for (i = 0; i < NUM_FORMATS; i++) { + if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { + s->pixelformat = formats[i].pixelformat; + s->buffersize = formats[i].buffersize; + f->fmt.sdr.buffersize = formats[i].buffersize; + return 0; + } + } + + s->pixelformat = formats[0].pixelformat; + s->buffersize = formats[0].buffersize; + f->fmt.sdr.pixelformat = formats[0].pixelformat; + f->fmt.sdr.buffersize = formats[0].buffersize; + + return 0; +} + +static int airspy_try_fmt_sdr_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct airspy *s = video_drvdata(file); + int i; + + dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, + (char *)&f->fmt.sdr.pixelformat); + + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); + for (i = 0; i < NUM_FORMATS; i++) { + if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { + f->fmt.sdr.buffersize = formats[i].buffersize; + return 0; + } + } + + f->fmt.sdr.pixelformat = formats[0].pixelformat; + f->fmt.sdr.buffersize = formats[0].buffersize; + + return 0; +} + +static int airspy_s_tuner(struct file *file, void *priv, + const struct v4l2_tuner *v) +{ + struct airspy *s = video_drvdata(file); + int ret; + + dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index); + + if (v->index == 0) + ret = 0; + else if (v->index == 1) + ret = 0; + else + ret = -EINVAL; + + return ret; +} + +static int airspy_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) +{ + struct airspy *s = video_drvdata(file); + int ret; + + dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index); + + if (v->index == 0) { + strlcpy(v->name, "AirSpy ADC", sizeof(v->name)); + v->type = V4L2_TUNER_ADC; + v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; + v->rangelow = bands[0].rangelow; + v->rangehigh = bands[0].rangehigh; + ret = 0; + } else if (v->index == 1) { + strlcpy(v->name, "AirSpy RF", sizeof(v->name)); + v->type = V4L2_TUNER_RF; + v->capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS; + v->rangelow = bands_rf[0].rangelow; + v->rangehigh = bands_rf[0].rangehigh; + ret = 0; + } else { + ret = -EINVAL; + } + + return ret; +} + +static int airspy_g_frequency(struct file *file, void *priv, + struct v4l2_frequency *f) +{ + struct airspy *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->type = V4L2_TUNER_ADC; + f->frequency = s->f_adc; + ret = 0; + } else if (f->tuner == 1) { + f->type = V4L2_TUNER_RF; + f->frequency = s->f_rf; + } else { + ret = -EINVAL; + } + + return ret; +} + +static int airspy_s_frequency(struct file *file, void *priv, + const struct v4l2_frequency *f) +{ + struct airspy *s = video_drvdata(file); + int ret; + u8 buf[4]; + + dev_dbg(&s->udev->dev, "%s: tuner=%d type=%d frequency=%u\n", + __func__, f->tuner, f->type, f->frequency); + + if (f->tuner == 0) { + s->f_adc = clamp_t(unsigned int, f->frequency, + bands[0].rangelow, + bands[0].rangehigh); + dev_dbg(&s->udev->dev, "%s: ADC frequency=%u Hz\n", + __func__, s->f_adc); + ret = 0; + } else if (f->tuner == 1) { + s->f_rf = clamp_t(unsigned int, f->frequency, + bands_rf[0].rangelow, + bands_rf[0].rangehigh); + dev_dbg(&s->udev->dev, "%s: RF frequency=%u Hz\n", + __func__, s->f_rf); + buf[0] = (s->f_rf >> 0) & 0xff; + buf[1] = (s->f_rf >> 8) & 0xff; + buf[2] = (s->f_rf >> 16) & 0xff; + buf[3] = (s->f_rf >> 24) & 0xff; + ret = airspy_ctrl_msg(s, CMD_SET_FREQ, 0, 0, buf, 4); + } else { + ret = -EINVAL; + } + + return ret; +} + +static int airspy_enum_freq_bands(struct file *file, void *priv, + struct v4l2_frequency_band *band) +{ + struct airspy *s = video_drvdata(file); + int ret; + 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)) { + ret = -EINVAL; + } else { + *band = bands[band->index]; + ret = 0; + } + } else if (band->tuner == 1) { + if (band->index >= ARRAY_SIZE(bands_rf)) { + ret = -EINVAL; + } else { + *band = bands_rf[band->index]; + ret = 0; + } + } else { + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ioctl_ops airspy_ioctl_ops = { + .vidioc_querycap = airspy_querycap, + + .vidioc_enum_fmt_sdr_cap = airspy_enum_fmt_sdr_cap, + .vidioc_g_fmt_sdr_cap = airspy_g_fmt_sdr_cap, + .vidioc_s_fmt_sdr_cap = airspy_s_fmt_sdr_cap, + .vidioc_try_fmt_sdr_cap = airspy_try_fmt_sdr_cap, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + + .vidioc_g_tuner = airspy_g_tuner, + .vidioc_s_tuner = airspy_s_tuner, + + .vidioc_g_frequency = airspy_g_frequency, + .vidioc_s_frequency = airspy_s_frequency, + .vidioc_enum_freq_bands = airspy_enum_freq_bands, + + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, + .vidioc_log_status = v4l2_ctrl_log_status, +}; + +static const struct v4l2_file_operations airspy_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .unlocked_ioctl = video_ioctl2, +}; + +static struct video_device airspy_template = { + .name = "AirSpy SDR", + .release = video_device_release_empty, + .fops = &airspy_fops, + .ioctl_ops = &airspy_ioctl_ops, +}; + +static void airspy_video_release(struct v4l2_device *v) +{ + struct airspy *s = container_of(v, struct airspy, v4l2_dev); + + v4l2_ctrl_handler_free(&s->hdl); + v4l2_device_unregister(&s->v4l2_dev); + kfree(s); +} + +static int airspy_set_lna_gain(struct airspy *s) +{ + int ret; + u8 u8tmp; + + dev_dbg(&s->udev->dev, "%s: lna auto=%d->%d val=%d->%d\n", + __func__, s->lna_gain_auto->cur.val, + s->lna_gain_auto->val, s->lna_gain->cur.val, + s->lna_gain->val); + + ret = airspy_ctrl_msg(s, CMD_SET_LNA_AGC, 0, s->lna_gain_auto->val, + &u8tmp, 1); + if (ret) + goto err; + + if (s->lna_gain_auto->val == false) { + ret = airspy_ctrl_msg(s, CMD_SET_LNA_GAIN, 0, s->lna_gain->val, + &u8tmp, 1); + if (ret) + goto err; + } +err: + if (ret) + dev_dbg(&s->udev->dev, "%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int airspy_set_mixer_gain(struct airspy *s) +{ + int ret; + u8 u8tmp; + + dev_dbg(&s->udev->dev, "%s: mixer auto=%d->%d val=%d->%d\n", + __func__, s->mixer_gain_auto->cur.val, + s->mixer_gain_auto->val, s->mixer_gain->cur.val, + s->mixer_gain->val); + + ret = airspy_ctrl_msg(s, CMD_SET_MIXER_AGC, 0, s->mixer_gain_auto->val, + &u8tmp, 1); + if (ret) + goto err; + + if (s->mixer_gain_auto->val == false) { + ret = airspy_ctrl_msg(s, CMD_SET_MIXER_GAIN, 0, + s->mixer_gain->val, &u8tmp, 1); + if (ret) + goto err; + } +err: + if (ret) + dev_dbg(&s->udev->dev, "%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int airspy_set_if_gain(struct airspy *s) +{ + int ret; + u8 u8tmp; + + dev_dbg(&s->udev->dev, "%s: val=%d->%d\n", + __func__, s->if_gain->cur.val, s->if_gain->val); + + ret = airspy_ctrl_msg(s, CMD_SET_VGA_GAIN, 0, s->if_gain->val, + &u8tmp, 1); + if (ret) + goto err; +err: + if (ret) + dev_dbg(&s->udev->dev, "%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int airspy_s_ctrl(struct v4l2_ctrl *ctrl) +{ + struct airspy *s = container_of(ctrl->handler, struct airspy, hdl); + int ret; + + switch (ctrl->id) { + case V4L2_CID_RF_TUNER_LNA_GAIN_AUTO: + case V4L2_CID_RF_TUNER_LNA_GAIN: + ret = airspy_set_lna_gain(s); + break; + case V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO: + case V4L2_CID_RF_TUNER_MIXER_GAIN: + ret = airspy_set_mixer_gain(s); + break; + case V4L2_CID_RF_TUNER_IF_GAIN: + ret = airspy_set_if_gain(s); + break; + default: + dev_dbg(&s->udev->dev, "%s: unknown ctrl: id=%d name=%s\n", + __func__, ctrl->id, ctrl->name); + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops airspy_ctrl_ops = { + .s_ctrl = airspy_s_ctrl, +}; + +static int airspy_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct airspy *s = NULL; + int ret; + u8 u8tmp, buf[BUF_SIZE]; + + s = kzalloc(sizeof(struct airspy), GFP_KERNEL); + if (s == NULL) { + dev_err(&udev->dev, + "Could not allocate memory for airspy state\n"); + return -ENOMEM; + } + + mutex_init(&s->v4l2_lock); + mutex_init(&s->vb_queue_lock); + spin_lock_init(&s->queued_bufs_lock); + INIT_LIST_HEAD(&s->queued_bufs); + s->udev = udev; + s->f_adc = bands[0].rangelow; + s->f_rf = bands_rf[0].rangelow; + s->pixelformat = formats[0].pixelformat; + s->buffersize = formats[0].buffersize; + + /* Detect device */ + ret = airspy_ctrl_msg(s, CMD_BOARD_ID_READ, 0, 0, &u8tmp, 1); + if (ret == 0) + ret = airspy_ctrl_msg(s, CMD_VERSION_STRING_READ, 0, 0, + buf, BUF_SIZE); + if (ret) { + dev_err(&s->udev->dev, "Could not detect board\n"); + goto err_free_mem; + } + + buf[BUF_SIZE - 1] = '\0'; + + dev_info(&s->udev->dev, "Board ID: %02x\n", u8tmp); + dev_info(&s->udev->dev, "Firmware version: %s\n", buf); + + /* Init videobuf2 queue structure */ + 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 airspy_frame_buf); + s->vb_queue.ops = &airspy_vb2_ops; + s->vb_queue.mem_ops = &vb2_vmalloc_memops; + s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + ret = vb2_queue_init(&s->vb_queue); + if (ret) { + dev_err(&s->udev->dev, "Could not initialize vb2 queue\n"); + goto err_free_mem; + } + + /* Init video_device structure */ + s->vdev = airspy_template; + s->vdev.queue = &s->vb_queue; + s->vdev.queue->lock = &s->vb_queue_lock; + video_set_drvdata(&s->vdev, s); + + /* Register the v4l2_device structure */ + s->v4l2_dev.release = airspy_video_release; + ret = v4l2_device_register(&intf->dev, &s->v4l2_dev); + if (ret) { + dev_err(&s->udev->dev, + "Failed to register v4l2-device (%d)\n", ret); + goto err_free_mem; + } + + /* Register controls */ + v4l2_ctrl_handler_init(&s->hdl, 5); + s->lna_gain_auto = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops, + V4L2_CID_RF_TUNER_LNA_GAIN_AUTO, 0, 1, 1, 0); + s->lna_gain = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops, + V4L2_CID_RF_TUNER_LNA_GAIN, 0, 14, 1, 8); + v4l2_ctrl_auto_cluster(2, &s->lna_gain_auto, 0, false); + s->mixer_gain_auto = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops, + V4L2_CID_RF_TUNER_MIXER_GAIN_AUTO, 0, 1, 1, 0); + s->mixer_gain = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops, + V4L2_CID_RF_TUNER_MIXER_GAIN, 0, 15, 1, 8); + v4l2_ctrl_auto_cluster(2, &s->mixer_gain_auto, 0, false); + s->if_gain = v4l2_ctrl_new_std(&s->hdl, &airspy_ctrl_ops, + V4L2_CID_RF_TUNER_IF_GAIN, 0, 15, 1, 0); + if (s->hdl.error) { + ret = s->hdl.error; + dev_err(&s->udev->dev, "Could not initialize controls\n"); + goto err_free_controls; + } + + v4l2_ctrl_handler_setup(&s->hdl); + + s->v4l2_dev.ctrl_handler = &s->hdl; + s->vdev.v4l2_dev = &s->v4l2_dev; + s->vdev.lock = &s->v4l2_lock; + + ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1); + if (ret) { + dev_err(&s->udev->dev, + "Failed to register as video device (%d)\n", + ret); + goto err_unregister_v4l2_dev; + } + dev_info(&s->udev->dev, "Registered as %s\n", + video_device_node_name(&s->vdev)); + dev_notice(&s->udev->dev, + "%s: SDR API is still slightly experimental and functionality changes may follow\n", + KBUILD_MODNAME); + return 0; + +err_free_controls: + v4l2_ctrl_handler_free(&s->hdl); +err_unregister_v4l2_dev: + v4l2_device_unregister(&s->v4l2_dev); +err_free_mem: + kfree(s); + return ret; +} + +/* USB device ID list */ +static struct usb_device_id airspy_id_table[] = { + { USB_DEVICE(0x1d50, 0x60a1) }, /* AirSpy */ + { } +}; +MODULE_DEVICE_TABLE(usb, airspy_id_table); + +/* USB subsystem interface */ +static struct usb_driver airspy_driver = { + .name = KBUILD_MODNAME, + .probe = airspy_probe, + .disconnect = airspy_disconnect, + .id_table = airspy_id_table, +}; + +module_usb_driver(airspy_driver); + +MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("AirSpy SDR"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/au0828/Kconfig b/drivers/media/usb/au0828/Kconfig index 953a37c613b1..fe48403eadd0 100644 --- a/drivers/media/usb/au0828/Kconfig +++ b/drivers/media/usb/au0828/Kconfig @@ -20,6 +20,7 @@ config VIDEO_AU0828_V4L2 bool "Auvitek AU0828 v4l2 analog video support" depends on VIDEO_AU0828 && VIDEO_V4L2 select DVB_AU8522_V4L if MEDIA_SUBDRV_AUTOSELECT + select VIDEO_TUNER default y ---help--- This is a video4linux driver for Auvitek's USB device. diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c index 9038194513c5..98f7ea1d6d63 100644 --- a/drivers/media/usb/au0828/au0828-video.c +++ b/drivers/media/usb/au0828/au0828-video.c @@ -787,23 +787,40 @@ static int au0828_i2s_init(struct au0828_dev *dev) /* * Auvitek au0828 analog stream enable - * Please set interface0 to AS5 before enable the stream */ static int au0828_analog_stream_enable(struct au0828_dev *d) { + struct usb_interface *iface; + int ret, h, w; + dprintk(1, "au0828_analog_stream_enable called\n"); + + iface = usb_ifnum_to_if(d->usbdev, 0); + if (iface && iface->cur_altsetting->desc.bAlternateSetting != 5) { + dprintk(1, "Changing intf#0 to alt 5\n"); + /* set au0828 interface0 to AS5 here again */ + ret = usb_set_interface(d->usbdev, 0, 5); + if (ret < 0) { + printk(KERN_INFO "Au0828 can't set alt setting to 5!\n"); + return -EBUSY; + } + } + + h = d->height / 2 + 2; + w = d->width * 2; + au0828_writereg(d, AU0828_SENSORCTRL_VBI_103, 0x00); au0828_writereg(d, 0x106, 0x00); /* set x position */ au0828_writereg(d, 0x110, 0x00); au0828_writereg(d, 0x111, 0x00); - au0828_writereg(d, 0x114, 0xa0); - au0828_writereg(d, 0x115, 0x05); + au0828_writereg(d, 0x114, w & 0xff); + au0828_writereg(d, 0x115, w >> 8); /* set y position */ au0828_writereg(d, 0x112, 0x00); au0828_writereg(d, 0x113, 0x00); - au0828_writereg(d, 0x116, 0xf2); - au0828_writereg(d, 0x117, 0x00); + au0828_writereg(d, 0x116, h & 0xff); + au0828_writereg(d, 0x117, h >> 8); au0828_writereg(d, AU0828_SENSORCTRL_100, 0xb3); return 0; @@ -1002,15 +1019,6 @@ static int au0828_v4l2_open(struct file *filp) return -ERESTARTSYS; } if (dev->users == 0) { - /* set au0828 interface0 to AS5 here again */ - ret = usb_set_interface(dev->usbdev, 0, 5); - if (ret < 0) { - mutex_unlock(&dev->lock); - printk(KERN_INFO "Au0828 can't set alternate to 5!\n"); - kfree(fh); - return -EBUSY; - } - au0828_analog_stream_enable(dev); au0828_analog_stream_reset(dev); @@ -1252,13 +1260,6 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd, } } - /* set au0828 interface0 to AS5 here again */ - ret = usb_set_interface(dev->usbdev, 0, 5); - if (ret < 0) { - printk(KERN_INFO "Au0828 can't set alt setting to 5!\n"); - return -EBUSY; - } - au0828_analog_stream_enable(dev); return 0; @@ -1364,9 +1365,11 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm) i2c_gate_ctrl(dev, 1); - /* FIXME: when we support something other than NTSC, we are going to - have to make the au0828 bridge adjust the size of its capture - buffer, which is currently hardcoded at 720x480 */ + /* + * FIXME: when we support something other than 60Hz standards, + * we are going to have to make the au0828 bridge adjust the size + * of its capture buffer, which is currently hardcoded at 720x480 + */ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_std, norm); @@ -1723,6 +1726,7 @@ static int vidioc_streamoff(struct file *file, void *priv, dev->vid_timeout_running = 0; del_timer_sync(&dev->vid_timeout); + au0828_analog_stream_disable(dev); v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0); rc = au0828_stream_interrupt(dev); if (rc != 0) @@ -1915,7 +1919,7 @@ static const struct video_device au0828_video_template = { .fops = &au0828_v4l_fops, .release = video_device_release, .ioctl_ops = &video_ioctl_ops, - .tvnorms = V4L2_STD_NTSC_M, + .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_M, }; /**************************************************************************/ @@ -1928,7 +1932,8 @@ int au0828_analog_register(struct au0828_dev *dev, struct usb_endpoint_descriptor *endpoint; int i, ret; - dprintk(1, "au0828_analog_register called!\n"); + dprintk(1, "au0828_analog_register called for intf#%d!\n", + interface->cur_altsetting->desc.bInterfaceNumber); /* set au0828 usb interface0 to as5 */ retval = usb_set_interface(dev->usbdev, @@ -1952,6 +1957,9 @@ int au0828_analog_register(struct au0828_dev *dev, dev->max_pkt_size = (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1); dev->isoc_in_endpointaddr = endpoint->bEndpointAddress; + dprintk(1, + "Found isoc endpoint 0x%02x, max size = %d\n", + dev->isoc_in_endpointaddr, dev->max_pkt_size); } } if (!(dev->isoc_in_endpointaddr)) { @@ -2008,14 +2016,12 @@ int au0828_analog_register(struct au0828_dev *dev, *dev->vdev = au0828_video_template; dev->vdev->v4l2_dev = &dev->v4l2_dev; dev->vdev->lock = &dev->lock; - set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev->flags); strcpy(dev->vdev->name, "au0828a video"); /* Setup the VBI device */ *dev->vbi_dev = au0828_video_template; dev->vbi_dev->v4l2_dev = &dev->v4l2_dev; dev->vbi_dev->lock = &dev->lock; - set_bit(V4L2_FL_USE_FH_PRIO, &dev->vbi_dev->flags); strcpy(dev->vbi_dev->name, "au0828a vbi"); /* Register the v4l2 device */ diff --git a/drivers/media/usb/cpia2/cpia2_v4l.c b/drivers/media/usb/cpia2/cpia2_v4l.c index d5d42b6e94be..9caea8344547 100644 --- a/drivers/media/usb/cpia2/cpia2_v4l.c +++ b/drivers/media/usb/cpia2/cpia2_v4l.c @@ -1169,7 +1169,6 @@ int cpia2_register_camera(struct camera_data *cam) cam->vdev.lock = &cam->v4l2_lock; cam->vdev.ctrl_handler = hdl; cam->vdev.v4l2_dev = &cam->v4l2_dev; - set_bit(V4L2_FL_USE_FH_PRIO, &cam->vdev.flags); reset_camera_struct_v4l(cam); diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c index 30a0c69fb42f..459bb0e98971 100644 --- a/drivers/media/usb/cx231xx/cx231xx-417.c +++ b/drivers/media/usb/cx231xx/cx231xx-417.c @@ -1563,7 +1563,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.width = dev->ts1.width; f->fmt.pix.height = dev->ts1.height; f->fmt.pix.field = V4L2_FIELD_INTERLACED; - f->fmt.pix.priv = 0; dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d\n", dev->ts1.width, dev->ts1.height); dprintk(3, "exit vidioc_g_fmt_vid_cap()\n"); @@ -1582,7 +1581,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.sizeimage = mpeglines * mpeglinesize; f->fmt.pix.field = V4L2_FIELD_INTERLACED; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; - f->fmt.pix.priv = 0; dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d\n", dev->ts1.width, dev->ts1.height); dprintk(3, "exit vidioc_try_fmt_vid_cap()\n"); @@ -1923,7 +1921,6 @@ static struct video_device *cx231xx_video_dev_alloc( vfd->v4l2_dev = &dev->v4l2_dev; vfd->lock = &dev->lock; vfd->release = video_device_release; - set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); vfd->ctrl_handler = &dev->mpeg_ctrl_handler.hdl; video_set_drvdata(vfd, dev); if (dev->tuner_type == TUNER_ABSENT) { diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c index 1f8751379e24..3b3ada6562ca 100644 --- a/drivers/media/usb/cx231xx/cx231xx-video.c +++ b/drivers/media/usb/cx231xx/cx231xx-video.c @@ -208,7 +208,7 @@ static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q, static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb) { struct cx231xx_dmaqueue *dma_q = urb->context; - int i, rc = 1; + int i; unsigned char *p_buffer; u32 bytes_parsed = 0, buffer_size = 0; u8 sav_eav = 0; @@ -299,13 +299,12 @@ static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb) bytes_parsed = 0; } - return rc; + return 1; } static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb) { struct cx231xx_dmaqueue *dma_q = urb->context; - int rc = 1; unsigned char *p_buffer; u32 bytes_parsed = 0, buffer_size = 0; u8 sav_eav = 0; @@ -379,7 +378,7 @@ static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb) bytes_parsed = 0; } - return rc; + return 1; } @@ -886,7 +885,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.field = V4L2_FIELD_INTERLACED; - f->fmt.pix.priv = 0; return 0; } @@ -931,7 +929,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.field = V4L2_FIELD_INTERLACED; - f->fmt.pix.priv = 0; return 0; } @@ -1620,7 +1617,7 @@ static int radio_s_tuner(struct file *file, void *priv, const struct v4l2_tuner */ static int cx231xx_v4l2_open(struct file *filp) { - int errCode = 0, radio = 0; + int radio = 0; struct video_device *vdev = video_devdata(filp); struct cx231xx *dev = video_drvdata(filp); struct cx231xx_fh *fh; @@ -1718,7 +1715,7 @@ static int cx231xx_v4l2_open(struct file *filp) mutex_unlock(&dev->lock); v4l2_fh_add(&fh->fh); - return errCode; + return 0; } /* @@ -2066,7 +2063,6 @@ static struct video_device *cx231xx_vdev_init(struct cx231xx *dev, vfd->release = video_device_release; vfd->debug = video_debug; vfd->lock = &dev->lock; - set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig index 037e519bbaa2..66645b02c854 100644 --- a/drivers/media/usb/dvb-usb-v2/Kconfig +++ b/drivers/media/usb/dvb-usb-v2/Kconfig @@ -129,6 +129,7 @@ config DVB_USB_RTL28XXU depends on DVB_USB_V2 && I2C_MUX select DVB_RTL2830 select DVB_RTL2832 + select DVB_RTL2832_SDR if (MEDIA_SUBDRV_AUTOSELECT && MEDIA_SDR_SUPPORT) select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MT2060 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index f674dc024d06..7d685bc8c2c0 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -125,14 +125,13 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); #define TUNER_RS2000 0x4 struct lme2510_state { + unsigned long int_urb_due; u8 id; u8 tuner_config; u8 signal_lock; u8 signal_level; u8 signal_sn; u8 time_key; - u8 last_key; - u8 key_timeout; u8 i2c_talk_onoff; u8 i2c_gate; u8 i2c_tuner_gate_w; @@ -323,7 +322,7 @@ static void lme2510_int_response(struct urb *lme_urb) } break; case TUNER_RS2000: - if (ibuf[1] == 0x3 && ibuf[6] == 0xff) + if (ibuf[2] & 0x1) st->signal_lock = 0xff; else st->signal_lock = 0x00; @@ -343,7 +342,12 @@ static void lme2510_int_response(struct urb *lme_urb) break; } } + usb_submit_urb(lme_urb, GFP_ATOMIC); + + /* interrupt urb is due every 48 msecs while streaming + * add 12msecs for system lag */ + st->int_urb_due = jiffies + msecs_to_jiffies(60); } static int lme2510_int_read(struct dvb_usb_adapter *adap) @@ -584,14 +588,13 @@ static int lme2510_msg(struct dvb_usb_device *d, switch (wbuf[3]) { case 0x8c: rbuf[0] = 0x55; - rbuf[1] = 0xff; - if (st->last_key == st->time_key) { - st->key_timeout++; - if (st->key_timeout > 5) - rbuf[1] = 0; - } else - st->key_timeout = 0; - st->last_key = st->time_key; + rbuf[1] = st->signal_lock; + + /* If int_urb_due overdue + * set rbuf[1] to 0 to clear lock */ + if (time_after(jiffies, st->int_urb_due)) + rbuf[1] = 0; + break; default: lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen); diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c index c7304fa8ab73..b8a707e57b99 100644 --- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c +++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c @@ -129,7 +129,7 @@ int mxl111sf_write_reg_mask(struct mxl111sf_state *state, u8 addr, u8 mask, u8 data) { int ret; - u8 val; + u8 val = 0; if (mask != 0xff) { ret = mxl111sf_read_reg(state, addr, &val); diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig index c5d95662e2e1..10aef2188fbe 100644 --- a/drivers/media/usb/dvb-usb/Kconfig +++ b/drivers/media/usb/dvb-usb/Kconfig @@ -117,10 +117,12 @@ config DVB_USB_CXUSB select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT select DVB_ATBM8830 if MEDIA_SUBDRV_AUTOSELECT select DVB_LGS8GXX if MEDIA_SUBDRV_AUTOSELECT + select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_XC2028 if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MXL5005S if MEDIA_SUBDRV_AUTOSELECT select MEDIA_TUNER_MAX2165 if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT help Say Y here to support the Conexant USB2.0 hybrid reference design. Currently, only DVB and ATSC modes are supported, analog mode @@ -128,6 +130,7 @@ config DVB_USB_CXUSB Medion MD95700 hybrid USB2.0 device. DViCO FusionHDTV (Bluebird) USB2.0 devices + TechnoTrend TVStick CT2-4400 config DVB_USB_M920X tristate "Uli m920x DVB-T USB2.0 support" diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c index a1c641e18362..b7461ac1ce74 100644 --- a/drivers/media/usb/dvb-usb/cxusb.c +++ b/drivers/media/usb/dvb-usb/cxusb.c @@ -42,6 +42,8 @@ #include "dib0070.h" #include "lgs8gxx.h" #include "atbm8830.h" +#include "si2168.h" +#include "si2157.h" /* Max transfer size done by I2C transfer functions */ #define MAX_XFER_SIZE 64 @@ -144,6 +146,22 @@ static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d, } } +static int cxusb_tt_ct2_4400_gpio_tuner(struct dvb_usb_device *d, int onoff) +{ + u8 o[2], i; + int rc; + + o[0] = 0x83; + o[1] = onoff; + rc = cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1); + + if (rc) { + deb_info("gpio_write failed.\n"); + return -EIO; + } + return 0; +} + /* I2C */ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num) @@ -505,6 +523,30 @@ static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event, return 0; } +static int cxusb_tt_ct2_4400_rc_query(struct dvb_usb_device *d) +{ + u8 i[2]; + int ret; + u32 cmd, keycode; + u8 rc5_cmd, rc5_addr, rc5_toggle; + + ret = cxusb_ctrl_msg(d, 0x10, NULL, 0, i, 2); + if (ret) + return ret; + + cmd = (i[0] << 8) | i[1]; + + if (cmd != 0xffff) { + rc5_cmd = cmd & 0x3F; /* bits 1-6 for command */ + rc5_addr = (cmd & 0x07C0) >> 6; /* bits 7-11 for address */ + rc5_toggle = (cmd & 0x0800) >> 11; /* bit 12 for toggle */ + keycode = (rc5_addr << 8) | rc5_cmd; + rc_keydown(d->rc_dev, keycode, rc5_toggle); + } + + return 0; +} + static struct rc_map_table rc_map_dvico_mce_table[] = { { 0xfe02, KEY_TV }, { 0xfe0e, KEY_MP3 }, @@ -1070,8 +1112,15 @@ static struct dib7000p_config cxusb_dualdig4_rev2_config = { .hostbus_diversity = 1, }; +struct dib0700_adapter_state { + int (*set_param_save)(struct dvb_frontend *); + struct dib7000p_ops dib7000p_ops; +}; + static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap) { + struct dib0700_adapter_state *state = adap->priv; + if (usb_set_interface(adap->dev->udev, 0, 1) < 0) err("set interface failed"); @@ -1079,14 +1128,17 @@ static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap) cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1); - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, - &cxusb_dualdig4_rev2_config) < 0) { + if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops)) + return -ENODEV; + + if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + &cxusb_dualdig4_rev2_config) < 0) { printk(KERN_WARNING "Unable to enumerate dib7000p\n"); return -ENODEV; } - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, - &cxusb_dualdig4_rev2_config); + adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80, + &cxusb_dualdig4_rev2_config); if (adap->fe_adap[0].fe == NULL) return -EIO; @@ -1095,7 +1147,10 @@ static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap) static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) { - return dib7000p_set_gpio(fe, 8, 0, !onoff); + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + + return state->dib7000p_ops.set_gpio(fe, 8, 0, !onoff); } static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff) @@ -1110,10 +1165,6 @@ static struct dib0070_config dib7070p_dib0070_config = { .clock_khz = 12000, }; -struct dib0700_adapter_state { - int (*set_param_save) (struct dvb_frontend *); -}; - static int dib7070_set_param_override(struct dvb_frontend *fe) { struct dtv_frontend_properties *p = &fe->dtv_property_cache; @@ -1128,7 +1179,7 @@ static int dib7070_set_param_override(struct dvb_frontend *fe) case BAND_UHF: offset = 550; break; } - dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); + state->dib7000p_ops.set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); return state->set_param_save(fe); } @@ -1136,8 +1187,14 @@ static int dib7070_set_param_override(struct dvb_frontend *fe) static int cxusb_dualdig4_rev2_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = - dib7000p_get_i2c_master(adap->fe_adap[0].fe, + struct i2c_adapter *tun_i2c; + + /* + * No need to call dvb7000p_attach here, as it was called + * already, as frontend_attach method is called first, and + * tuner_attach is only called on sucess. + */ + tun_i2c = st->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, @@ -1286,6 +1343,74 @@ static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap) return 0; } +static int cxusb_tt_ct2_4400_attach(struct dvb_usb_adapter *adap) +{ + struct dvb_usb_device *d = adap->dev; + struct cxusb_state *st = d->priv; + struct i2c_adapter *adapter; + struct i2c_client *client_demod; + struct i2c_client *client_tuner; + struct i2c_board_info info; + struct si2168_config si2168_config; + struct si2157_config si2157_config; + + /* reset the tuner */ + if (cxusb_tt_ct2_4400_gpio_tuner(d, 0) < 0) { + err("clear tuner gpio failed"); + return -EIO; + } + msleep(100); + if (cxusb_tt_ct2_4400_gpio_tuner(d, 1) < 0) { + err("set tuner gpio failed"); + return -EIO; + } + msleep(100); + + /* attach frontend */ + si2168_config.i2c_adapter = &adapter; + si2168_config.fe = &adap->fe_adap[0].fe; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2168", I2C_NAME_SIZE); + info.addr = 0x64; + info.platform_data = &si2168_config; + request_module(info.type); + client_demod = i2c_new_device(&d->i2c_adap, &info); + if (client_demod == NULL || client_demod->dev.driver == NULL) + return -ENODEV; + + if (!try_module_get(client_demod->dev.driver->owner)) { + i2c_unregister_device(client_demod); + return -ENODEV; + } + + st->i2c_client_demod = client_demod; + + /* attach tuner */ + memset(&si2157_config, 0, sizeof(si2157_config)); + si2157_config.fe = adap->fe_adap[0].fe; + memset(&info, 0, sizeof(struct i2c_board_info)); + strlcpy(info.type, "si2157", I2C_NAME_SIZE); + info.addr = 0x60; + info.platform_data = &si2157_config; + request_module(info.type); + client_tuner = i2c_new_device(adapter, &info); + if (client_tuner == NULL || client_tuner->dev.driver == NULL) { + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + return -ENODEV; + } + if (!try_module_get(client_tuner->dev.driver->owner)) { + i2c_unregister_device(client_tuner); + module_put(client_demod->dev.driver->owner); + i2c_unregister_device(client_demod); + return -ENODEV; + } + + st->i2c_client_tuner = client_tuner; + + return 0; +} + /* * DViCO has shipped two devices with the same USB ID, but only one of them * needs a firmware download. Check the device class details to see if they @@ -1367,6 +1492,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope static struct dvb_usb_device_properties cxusb_aver_a868r_properties; static struct dvb_usb_device_properties cxusb_d680_dmb_properties; static struct dvb_usb_device_properties cxusb_mygica_d689_properties; +static struct dvb_usb_device_properties cxusb_tt_ct2_4400_properties; static int cxusb_probe(struct usb_interface *intf, const struct usb_device_id *id) @@ -1397,12 +1523,37 @@ static int cxusb_probe(struct usb_interface *intf, THIS_MODULE, NULL, adapter_nr) || 0 == dvb_usb_device_init(intf, &cxusb_mygica_d689_properties, THIS_MODULE, NULL, adapter_nr) || + 0 == dvb_usb_device_init(intf, &cxusb_tt_ct2_4400_properties, + THIS_MODULE, NULL, adapter_nr) || 0) return 0; return -EINVAL; } +static void cxusb_disconnect(struct usb_interface *intf) +{ + struct dvb_usb_device *d = usb_get_intfdata(intf); + struct cxusb_state *st = d->priv; + struct i2c_client *client; + + /* remove I2C client for tuner */ + client = st->i2c_client_tuner; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + /* remove I2C client for demodulator */ + client = st->i2c_client_demod; + if (client) { + module_put(client->dev.driver->owner); + i2c_unregister_device(client); + } + + dvb_usb_device_exit(intf); +} + static struct usb_device_id cxusb_table [] = { { USB_DEVICE(USB_VID_MEDION, USB_PID_MEDION_MD95700) }, { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_LG064F_COLD) }, @@ -1424,6 +1575,7 @@ static struct usb_device_id cxusb_table [] = { { USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) }, { USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) }, { USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) }, + { USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_TVSTICK_CT2_4400) }, {} /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, cxusb_table); @@ -2070,10 +2222,63 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = { } }; +static struct dvb_usb_device_properties cxusb_tt_ct2_4400_properties = { + .caps = DVB_USB_IS_AN_I2C_ADAPTER, + + .usb_ctrl = CYPRESS_FX2, + + .size_of_priv = sizeof(struct cxusb_state), + + .num_adapters = 1, + .adapter = { + { + .num_frontends = 1, + .fe = {{ + .streaming_ctrl = cxusb_streaming_ctrl, + /* both frontend and tuner attached in the + same function */ + .frontend_attach = cxusb_tt_ct2_4400_attach, + + /* parameter for the MPEG2-data transfer */ + .stream = { + .type = USB_BULK, + .count = 8, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 4096, + } + } + }, + } }, + }, + }, + + .i2c_algo = &cxusb_i2c_algo, + .generic_bulk_ctrl_endpoint = 0x01, + .generic_bulk_ctrl_endpoint_response = 0x81, + + .rc.core = { + .rc_codes = RC_MAP_TT_1500, + .allowed_protos = RC_BIT_RC5, + .rc_query = cxusb_tt_ct2_4400_rc_query, + .rc_interval = 150, + }, + + .num_device_descs = 1, + .devices = { + { + "TechnoTrend TVStick CT2-4400", + { NULL }, + { &cxusb_table[20], NULL }, + }, + } +}; + static struct usb_driver cxusb_driver = { .name = "dvb_usb_cxusb", .probe = cxusb_probe, - .disconnect = dvb_usb_device_exit, + .disconnect = cxusb_disconnect, .id_table = cxusb_table, }; diff --git a/drivers/media/usb/dvb-usb/cxusb.h b/drivers/media/usb/dvb-usb/cxusb.h index 1a51eafd31b9..527ff7905e15 100644 --- a/drivers/media/usb/dvb-usb/cxusb.h +++ b/drivers/media/usb/dvb-usb/cxusb.h @@ -30,6 +30,8 @@ struct cxusb_state { u8 gpio_write_state[3]; + struct i2c_client *i2c_client_demod; + struct i2c_client *i2c_client_tuner; }; #endif diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c index 10e0db8d1850..501947eaacfe 100644 --- a/drivers/media/usb/dvb-usb/dib0700_devices.c +++ b/drivers/media/usb/dvb-usb/dib0700_devices.c @@ -32,6 +32,8 @@ MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplif struct dib0700_adapter_state { int (*set_param_save) (struct dvb_frontend *); const struct firmware *frontend_firmware; + struct dib7000p_ops dib7000p_ops; + struct dib8000_ops dib8000_ops; }; /* Hauppauge Nova-T 500 (aka Bristol) @@ -262,6 +264,11 @@ static struct mt2266_config stk7700d_mt2266_config[2] = { static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap) { + struct dib0700_adapter_state *state = adap->priv; + + if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops)) + return -ENODEV; + if (adap->id == 0) { dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10); @@ -272,16 +279,16 @@ static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap) msleep(10); dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(10); - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18, stk7700d_dib7000p_mt2266_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); + dvb_detach(&state->dib7000p_ops); return -ENODEV; } } - adap->fe_adap[0].fe = - dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, + adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80 + (adap->id << 1), &stk7700d_dib7000p_mt2266_config[adap->id]); @@ -290,6 +297,11 @@ static int stk7700P2_frontend_attach(struct dvb_usb_adapter *adap) static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) { + struct dib0700_adapter_state *state = adap->priv; + + if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops)) + return -ENODEV; + if (adap->id == 0) { dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10); @@ -301,16 +313,16 @@ static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1); msleep(10); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, + if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 2, 18, stk7700d_dib7000p_mt2266_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); + dvb_detach(&state->dib7000p_ops); return -ENODEV; } } - adap->fe_adap[0].fe = - dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, + adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80 + (adap->id << 1), &stk7700d_dib7000p_mt2266_config[adap->id]); @@ -320,7 +332,10 @@ static int stk7700d_frontend_attach(struct dvb_usb_adapter *adap) static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap) { struct i2c_adapter *tun_i2c; - tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); + struct dib0700_adapter_state *state = adap->priv; + + tun_i2c = state->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe, + DIBX000_I2C_INTERFACE_TUNER, 1); return dvb_attach(mt2266_attach, adap->fe_adap[0].fe, tun_i2c, &stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0; } @@ -397,12 +412,14 @@ static int stk7700ph_xc3028_callback(void *ptr, int component, int command, int arg) { struct dvb_usb_adapter *adap = ptr; + struct dib0700_adapter_state *state = adap->priv; switch (command) { case XC2028_TUNER_RESET: /* Send the tuner in then out of reset */ - dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 0); msleep(10); - dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 0); + msleep(10); + state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1); break; case XC2028_RESET_CLK: break; @@ -428,12 +445,16 @@ static struct xc2028_config stk7700ph_xc3028_config = { static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap) { struct usb_device_descriptor *desc = &adap->dev->udev->descriptor; + struct dib0700_adapter_state *state = adap->priv; + + if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops)) + return -ENODEV; if (desc->idVendor == cpu_to_le16(USB_VID_PINNACLE) && desc->idProduct == cpu_to_le16(USB_PID_PINNACLE_EXPRESSCARD_320CX)) - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); else - dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(20); dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1); @@ -445,14 +466,15 @@ static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap) dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); msleep(10); - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18, &stk7700ph_dib7700_xc3028_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); + dvb_detach(&state->dib7000p_ops); return -ENODEV; } - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80, &stk7700ph_dib7700_xc3028_config); return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; @@ -461,8 +483,9 @@ static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap) static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap) { struct i2c_adapter *tun_i2c; + struct dib0700_adapter_state *state = adap->priv; - tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, + tun_i2c = state->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); stk7700ph_xc3028_config.i2c_adap = tun_i2c; @@ -673,6 +696,11 @@ static struct dib7000p_config stk7700p_dib7000p_config = { static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap) { struct dib0700_state *st = adap->dev->priv; + struct dib0700_adapter_state *state = adap->priv; + + if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops)) + return -ENODEV; + /* unless there is no real power management in DVB - we leave the device on GPIO6 */ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0); @@ -689,11 +717,14 @@ static int stk7700p_frontend_attach(struct dvb_usb_adapter *adap) st->mt2060_if1[0] = 1220; - if (dib7000pc_detection(&adap->dev->i2c_adap)) { - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config); + if (state->dib7000p_ops.dib7000pc_detection(&adap->dev->i2c_adap)) { + adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 18, &stk7700p_dib7000p_config); st->is_dib7000pc = 1; - } else + } else { + dvb_detach(&state->dib7000p_ops); + memset(&state->dib7000p_ops, 0, sizeof(state->dib7000p_ops)); adap->fe_adap[0].fe = dvb_attach(dib7000m_attach, &adap->dev->i2c_adap, 18, &stk7700p_dib7000m_config); + } return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } @@ -707,14 +738,16 @@ static int stk7700p_tuner_attach(struct dvb_usb_adapter *adap) struct i2c_adapter *prim_i2c = &adap->dev->i2c_adap; struct dib0700_state *st = adap->dev->priv; struct i2c_adapter *tun_i2c; + struct dib0700_adapter_state *state = adap->priv; s8 a; int if1=1220; + if (adap->dev->udev->descriptor.idVendor == cpu_to_le16(USB_VID_HAUPPAUGE) && adap->dev->udev->descriptor.idProduct == cpu_to_le16(USB_PID_HAUPPAUGE_NOVA_T_STICK)) { if (!eeprom_read(prim_i2c,0x58,&a)) if1=1220+a; } if (st->is_dib7000pc) - tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); + tun_i2c = state->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); else tun_i2c = dib7000m_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); @@ -767,14 +800,20 @@ static struct dibx000_agc_config dib7070_agc_config = { static int dib7070_tuner_reset(struct dvb_frontend *fe, int onoff) { + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + deb_info("reset: %d", onoff); - return dib7000p_set_gpio(fe, 8, 0, !onoff); + return state->dib7000p_ops.set_gpio(fe, 8, 0, !onoff); } static int dib7070_tuner_sleep(struct dvb_frontend *fe, int onoff) { + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + deb_info("sleep: %d", onoff); - return dib7000p_set_gpio(fe, 9, 0, onoff); + return state->dib7000p_ops.set_gpio(fe, 9, 0, onoff); } static struct dib0070_config dib7070p_dib0070_config[2] = { @@ -818,7 +857,7 @@ static int dib7070_set_param_override(struct dvb_frontend *fe) default: offset = 550; break; } deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); - dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); + state->dib7000p_ops.set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); return state->set_param_save(fe); } @@ -832,39 +871,39 @@ static int dib7770_set_param_override(struct dvb_frontend *fe) u8 band = BAND_OF_FREQUENCY(p->frequency/1000); switch (band) { case BAND_VHF: - dib7000p_set_gpio(fe, 0, 0, 1); + state->dib7000p_ops.set_gpio(fe, 0, 0, 1); offset = 850; break; case BAND_UHF: default: - dib7000p_set_gpio(fe, 0, 0, 0); + state->dib7000p_ops.set_gpio(fe, 0, 0, 0); offset = 250; break; } deb_info("WBD for DiB7000P: %d\n", offset + dib0070_wbd_offset(fe)); - dib7000p_set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); + state->dib7000p_ops.set_wbd_ref(fe, offset + dib0070_wbd_offset(fe)); return state->set_param_save(fe); } static int dib7770p_tuner_attach(struct dvb_usb_adapter *adap) { - struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, + struct dib0700_adapter_state *st = adap->priv; + struct i2c_adapter *tun_i2c = st->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); - if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, - &dib7770p_dib0070_config) == NULL) - return -ENODEV; + if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, + &dib7770p_dib0070_config) == NULL) + return -ENODEV; - st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; - adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7770_set_param_override; - return 0; + st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; + adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7770_set_param_override; + return 0; } static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); + struct i2c_adapter *tun_i2c = st->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); if (adap->id == 0) { if (dvb_attach(dib0070_attach, adap->fe_adap[0].fe, tun_i2c, &dib7070p_dib0070_config[0]) == NULL) @@ -882,28 +921,33 @@ static int dib7070p_tuner_attach(struct dvb_usb_adapter *adap) static int stk7700p_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) { + struct dib0700_adapter_state *state = adapter->priv; struct dib0700_state *st = adapter->dev->priv; + if (st->is_dib7000pc) - return dib7000p_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); + return state->dib7000p_ops.pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); return dib7000m_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); } static int stk7700p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) { struct dib0700_state *st = adapter->dev->priv; + struct dib0700_adapter_state *state = adapter->priv; if (st->is_dib7000pc) - return dib7000p_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); + return state->dib7000p_ops.pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); return dib7000m_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); } static int stk70x0p_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) { - return dib7000p_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); + struct dib0700_adapter_state *state = adapter->priv; + return state->dib7000p_ops.pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); } static int stk70x0p_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) { - return dib7000p_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); + struct dib0700_adapter_state *state = adapter->priv; + return state->dib7000p_ops.pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); } static struct dibx000_bandwidth_config dib7070_bw_config_12_mhz = { @@ -936,6 +980,11 @@ static struct dib7000p_config dib7070p_dib7000p_config = { static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap) { struct usb_device_descriptor *p = &adap->dev->udev->descriptor; + struct dib0700_adapter_state *state = adap->priv; + + if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops)) + return -ENODEV; + if (p->idVendor == cpu_to_le16(USB_VID_PINNACLE) && p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E)) dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); @@ -954,14 +1003,15 @@ static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap) msleep(10); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18, &dib7070p_dib7000p_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); + dvb_detach(&state->dib7000p_ops); return -ENODEV; } - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80, &dib7070p_dib7000p_config); return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } @@ -988,6 +1038,11 @@ static struct dib7000p_config dib7770p_dib7000p_config = { static int stk7770p_frontend_attach(struct dvb_usb_adapter *adap) { struct usb_device_descriptor *p = &adap->dev->udev->descriptor; + struct dib0700_adapter_state *state = adap->priv; + + if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops)) + return -ENODEV; + if (p->idVendor == cpu_to_le16(USB_VID_PINNACLE) && p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E)) dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); @@ -1006,14 +1061,15 @@ static int stk7770p_frontend_attach(struct dvb_usb_adapter *adap) msleep(10); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18, &dib7770p_dib7000p_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); + dvb_detach(&state->dib7000p_ops); return -ENODEV; } - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, + adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80, &dib7770p_dib7000p_config); return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } @@ -1161,12 +1217,18 @@ static struct dib8000_config dib807x_dib8000_config[2] = { static int dib80xx_tuner_reset(struct dvb_frontend *fe, int onoff) { - return dib8000_set_gpio(fe, 5, 0, !onoff); + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + + return state->dib8000_ops.set_gpio(fe, 5, 0, !onoff); } static int dib80xx_tuner_sleep(struct dvb_frontend *fe, int onoff) { - return dib8000_set_gpio(fe, 0, 0, onoff); + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + + return state->dib8000_ops.set_gpio(fe, 0, 0, onoff); } static const struct dib0070_wbd_gain_cfg dib8070_wbd_gain_cfg[] = { @@ -1223,7 +1285,7 @@ static int dib807x_set_param_override(struct dvb_frontend *fe) offset += 250; break; } deb_info("WBD for DiB8000: %d\n", offset); - dib8000_set_wbd_ref(fe, offset); + state->dib8000_ops.set_wbd_ref(fe, offset); return state->set_param_save(fe); } @@ -1231,7 +1293,7 @@ static int dib807x_set_param_override(struct dvb_frontend *fe) static int dib807x_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe, + struct i2c_adapter *tun_i2c = st->dib8000_ops.get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); if (adap->id == 0) { @@ -1252,18 +1314,27 @@ static int dib807x_tuner_attach(struct dvb_usb_adapter *adap) static int stk80xx_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff) { - return dib8000_pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); + struct dib0700_adapter_state *state = adapter->priv; + + return state->dib8000_ops.pid_filter(adapter->fe_adap[0].fe, index, pid, onoff); } static int stk80xx_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff) { - return dib8000_pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); + struct dib0700_adapter_state *state = adapter->priv; + + return state->dib8000_ops.pid_filter_ctrl(adapter->fe_adap[0].fe, onoff); } /* STK807x */ static int stk807x_frontend_attach(struct dvb_usb_adapter *adap) { + struct dib0700_adapter_state *state = adap->priv; + + if (!dvb_attach(dib8000_attach, &state->dib8000_ops)) + return -ENODEV; + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10); dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); @@ -1279,10 +1350,10 @@ static int stk807x_frontend_attach(struct dvb_usb_adapter *adap) msleep(10); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, + state->dib8000_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80, 0); - adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, + adap->fe_adap[0].fe = state->dib8000_ops.init(&adap->dev->i2c_adap, 0x80, &dib807x_dib8000_config[0]); return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; @@ -1291,6 +1362,11 @@ static int stk807x_frontend_attach(struct dvb_usb_adapter *adap) /* STK807xPVR */ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) { + struct dib0700_adapter_state *state = adap->priv; + + if (!dvb_attach(dib8000_attach, &state->dib8000_ops)) + return -ENODEV; + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(30); dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); @@ -1309,9 +1385,9 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); /* initialize IC 0 */ - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80, 0); + state->dib8000_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x22, 0x80, 0); - adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, + adap->fe_adap[0].fe = state->dib8000_ops.init(&adap->dev->i2c_adap, 0x80, &dib807x_dib8000_config[0]); return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; @@ -1319,10 +1395,15 @@ static int stk807xpvr_frontend_attach0(struct dvb_usb_adapter *adap) static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) { + struct dib0700_adapter_state *state = adap->priv; + + if (!dvb_attach(dib8000_attach, &state->dib8000_ops)) + return -ENODEV; + /* initialize IC 1 */ - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82, 0); + state->dib8000_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x12, 0x82, 0); - adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, + adap->fe_adap[0].fe = state->dib8000_ops.init(&adap->dev->i2c_adap, 0x82, &dib807x_dib8000_config[1]); return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; @@ -1331,104 +1412,121 @@ static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap) /* STK8096GP */ static struct dibx000_agc_config dib8090_agc_config[2] = { { - BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, + .band_caps = BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), - 787, - 10, - - 0, - 118, - - 0, - 3530, - 1, - 5, + .inv_gain = 787, + .time_stabiliz = 10, - 65535, - 0, + .alpha_level = 0, + .thlock = 118, - 65535, - 0, + .wbd_inv = 0, + .wbd_ref = 3530, + .wbd_sel = 1, + .wbd_alpha = 5, - 0, - 32, - 114, - 143, - 144, - 114, - 227, - 116, - 117, + .agc1_max = 65535, + .agc1_min = 0, - 28, - 26, - 31, - 51, + .agc2_max = 65535, + .agc2_min = 0, - 0, + .agc1_pt1 = 0, + .agc1_pt2 = 32, + .agc1_pt3 = 114, + .agc1_slope1 = 143, + .agc1_slope2 = 144, + .agc2_pt1 = 114, + .agc2_pt2 = 227, + .agc2_slope1 = 116, + .agc2_slope2 = 117, + + .alpha_mant = 28, + .alpha_exp = 26, + .beta_mant = 31, + .beta_exp = 51, + + .perform_agc_softsplit = 0, }, { - BAND_CBAND, + .band_caps = BAND_CBAND, /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0, * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */ - (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) + .setup = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), - 787, - 10, - - 0, - 118, + .inv_gain = 787, + .time_stabiliz = 10, - 0, - 3530, - 1, - 5, - - 0, - 0, + .alpha_level = 0, + .thlock = 118, - 65535, - 0, + .wbd_inv = 0, + .wbd_ref = 3530, + .wbd_sel = 1, + .wbd_alpha = 5, - 0, - 32, - 114, - 143, - 144, - 114, - 227, - 116, - 117, + .agc1_max = 0, + .agc1_min = 0, - 28, - 26, - 31, - 51, + .agc2_max = 65535, + .agc2_min = 0, - 0, + .agc1_pt1 = 0, + .agc1_pt2 = 32, + .agc1_pt3 = 114, + .agc1_slope1 = 143, + .agc1_slope2 = 144, + .agc2_pt1 = 114, + .agc2_pt2 = 227, + .agc2_slope1 = 116, + .agc2_slope2 = 117, + + .alpha_mant = 28, + .alpha_exp = 26, + .beta_mant = 31, + .beta_exp = 51, + + .perform_agc_softsplit = 0, } }; static struct dibx000_bandwidth_config dib8090_pll_config_12mhz = { - 54000, 13500, - 1, 18, 3, 1, 0, - 0, 0, 1, 1, 2, - (3 << 14) | (1 << 12) | (599 << 0), - (0 << 25) | 0, - 20199727, - 12000000, + .internal = 54000, + .sampling = 13500, + + .pll_prediv = 1, + .pll_ratio = 18, + .pll_range = 3, + .pll_reset = 1, + .pll_bypass = 0, + + .enable_refdiv = 0, + .bypclk_div = 0, + .IO_CLK_en_core = 1, + .ADClkSrc = 1, + .modulo = 2, + + .sad_cfg = (3 << 14) | (1 << 12) | (599 << 0), + + .ifreq = (0 << 25) | 0, + .timf = 20199727, + + .xtal_hz = 12000000, }; static int dib8090_get_adc_power(struct dvb_frontend *fe) { - return dib8000_get_adc_power(fe, 1); + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + + return state->dib8000_ops.get_adc_power(fe, 1); } static void dib8090_agc_control(struct dvb_frontend *fe, u8 restart) @@ -1551,10 +1649,10 @@ static int dib8096_set_param_override(struct dvb_frontend *fe) default: deb_info("Warning : Rf frequency (%iHz) is not in the supported range, using VHF switch ", fe->dtv_property_cache.frequency); case BAND_VHF: - dib8000_set_gpio(fe, 3, 0, 1); + state->dib8000_ops.set_gpio(fe, 3, 0, 1); break; case BAND_UHF: - dib8000_set_gpio(fe, 3, 0, 0); + state->dib8000_ops.set_gpio(fe, 3, 0, 0); break; } @@ -1568,7 +1666,7 @@ static int dib8096_set_param_override(struct dvb_frontend *fe) } /** Update PLL if needed ratio **/ - dib8000_update_pll(fe, &dib8090_pll_config_12mhz, fe->dtv_property_cache.bandwidth_hz / 1000, 0); + state->dib8000_ops.update_pll(fe, &dib8090_pll_config_12mhz, fe->dtv_property_cache.bandwidth_hz / 1000, 0); /** Get optimize PLL ratio to remove spurious **/ pll_ratio = dib8090_compute_pll_parameters(fe); @@ -1582,14 +1680,14 @@ static int dib8096_set_param_override(struct dvb_frontend *fe) timf = 18179756; /** Update ratio **/ - dib8000_update_pll(fe, &dib8090_pll_config_12mhz, fe->dtv_property_cache.bandwidth_hz / 1000, pll_ratio); + state->dib8000_ops.update_pll(fe, &dib8090_pll_config_12mhz, fe->dtv_property_cache.bandwidth_hz / 1000, pll_ratio); - dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, timf); + state->dib8000_ops.ctrl_timf(fe, DEMOD_TIMF_SET, timf); if (band != BAND_CBAND) { /* dib0090_get_wbd_target is returning any possible temperature compensated wbd-target */ target = (dib0090_get_wbd_target(fe) * 8 * 18 / 33 + 1) / 2; - dib8000_set_wbd_ref(fe, target); + state->dib8000_ops.set_wbd_ref(fe, target); } if (band == BAND_CBAND) { @@ -1601,18 +1699,18 @@ static int dib8096_set_param_override(struct dvb_frontend *fe) msleep(ret); tune_state = dib0090_get_tune_state(fe); if (tune_state == CT_AGC_STEP_0) - dib8000_set_gpio(fe, 6, 0, 1); + state->dib8000_ops.set_gpio(fe, 6, 0, 1); else if (tune_state == CT_AGC_STEP_1) { dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, <gain); if (rf_gain_limit < 2000) /* activate the external attenuator in case of very high input power */ - dib8000_set_gpio(fe, 6, 0, 0); + state->dib8000_ops.set_gpio(fe, 6, 0, 0); } } while (tune_state < CT_AGC_STOP); deb_info("switching to PWM AGC\n"); dib0090_pwm_gain_reset(fe); - dib8000_pwm_agc_reset(fe); - dib8000_set_tune_state(fe, CT_DEMOD_START); + state->dib8000_ops.pwm_agc_reset(fe); + state->dib8000_ops.set_tune_state(fe, CT_DEMOD_START); } else { /* for everything else than CBAND we are using standard AGC */ deb_info("not tuning in CBAND - standard AGC startup\n"); @@ -1625,7 +1723,7 @@ static int dib8096_set_param_override(struct dvb_frontend *fe) static int dib809x_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); + struct i2c_adapter *tun_i2c = st->dib8000_ops.get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL) return -ENODEV; @@ -1637,6 +1735,11 @@ static int dib809x_tuner_attach(struct dvb_usb_adapter *adap) static int stk809x_frontend_attach(struct dvb_usb_adapter *adap) { + struct dib0700_adapter_state *state = adap->priv; + + if (!dvb_attach(dib8000_attach, &state->dib8000_ops)) + return -ENODEV; + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(10); dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); @@ -1652,9 +1755,9 @@ static int stk809x_frontend_attach(struct dvb_usb_adapter *adap) msleep(10); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80, 0); + state->dib8000_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80, 0); - adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); + adap->fe_adap[0].fe = state->dib8000_ops.init(&adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } @@ -1663,16 +1766,16 @@ static int nim8096md_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; struct i2c_adapter *tun_i2c; - struct dvb_frontend *fe_slave = dib8000_get_slave_frontend(adap->fe_adap[0].fe, 1); + struct dvb_frontend *fe_slave = st->dib8000_ops.get_slave_frontend(adap->fe_adap[0].fe, 1); if (fe_slave) { - tun_i2c = dib8000_get_i2c_master(fe_slave, DIBX000_I2C_INTERFACE_TUNER, 1); + tun_i2c = st->dib8000_ops.get_i2c_master(fe_slave, DIBX000_I2C_INTERFACE_TUNER, 1); if (dvb_attach(dib0090_register, fe_slave, tun_i2c, &dib809x_dib0090_config) == NULL) return -ENODEV; fe_slave->dvb = adap->fe_adap[0].fe->dvb; fe_slave->ops.tuner_ops.set_params = dib8096_set_param_override; } - tun_i2c = dib8000_get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); + tun_i2c = st->dib8000_ops.get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL) return -ENODEV; @@ -1685,6 +1788,10 @@ static int nim8096md_tuner_attach(struct dvb_usb_adapter *adap) static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap) { struct dvb_frontend *fe_slave; + struct dib0700_adapter_state *state = adap->priv; + + if (!dvb_attach(dib8000_attach, &state->dib8000_ops)) + return -ENODEV; dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); msleep(20); @@ -1703,14 +1810,18 @@ static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap) msleep(20); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80, 0); + state->dib8000_ops.i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80, 0); - adap->fe_adap[0].fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); + adap->fe_adap[0].fe = state->dib8000_ops.init(&adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]); if (adap->fe_adap[0].fe == NULL) return -ENODEV; - fe_slave = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib809x_dib8000_config[1]); - dib8000_set_slave_frontend(adap->fe_adap[0].fe, fe_slave); + /* Needed to increment refcount */ + if (!dvb_attach(dib8000_attach, &state->dib8000_ops)) + return -ENODEV; + + fe_slave = state->dib8000_ops.init(&adap->dev->i2c_adap, 0x82, &dib809x_dib8000_config[1]); + state->dib8000_ops.set_slave_frontend(adap->fe_adap[0].fe, fe_slave); return fe_slave == NULL ? -ENODEV : 0; } @@ -1845,7 +1956,7 @@ static struct dib0090_wbd_slope dib8096p_wbd_table[] = { { 0xFFFF, 0, 0, 0, 0, 0}, }; -static const struct dib0090_config tfe8096p_dib0090_config = { +static struct dib0090_config tfe8096p_dib0090_config = { .io.clock_khz = 12000, .io.pll_bypass = 0, .io.pll_range = 0, @@ -1853,8 +1964,6 @@ static const struct dib0090_config tfe8096p_dib0090_config = { .io.pll_loopdiv = 6, .io.adc_clock_ratio = 0, .io.pll_int_loop_filt = 0, - .reset = dib8096p_tuner_sleep, - .sleep = dib8096p_tuner_sleep, .freq_offset_khz_uhf = -143, .freq_offset_khz_vhf = -143, @@ -1871,8 +1980,6 @@ static const struct dib0090_config tfe8096p_dib0090_config = { .fref_clock_ratio = 1, - .wbd = dib8096p_wbd_table, - .ls_cfg_pad_drv = 0, .data_tx_drv = 0, .low_if = NULL, @@ -1983,15 +2090,15 @@ static int dib8096p_agc_startup(struct dvb_frontend *fe) /* dib0090_get_wbd_target is returning any possible temperature compensated wbd-target */ target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2; - dib8000_set_wbd_ref(fe, target); + state->dib8000_ops.set_wbd_ref(fe, target); if (dib8096p_get_best_sampling(fe, &adc) == 0) { pll.pll_ratio = adc.pll_loopdiv; pll.pll_prediv = adc.pll_prediv; dib0700_set_i2c_speed(adap->dev, 200); - dib8000_update_pll(fe, &pll, fe->dtv_property_cache.bandwidth_hz / 1000, 0); - dib8000_ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf); + state->dib8000_ops.update_pll(fe, &pll, fe->dtv_property_cache.bandwidth_hz / 1000, 0); + state->dib8000_ops.ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf); dib0700_set_i2c_speed(adap->dev, 1000); } return 0; @@ -2001,6 +2108,10 @@ static int tfe8096p_frontend_attach(struct dvb_usb_adapter *adap) { struct dib0700_state *st = adap->dev->priv; u32 fw_version; + struct dib0700_adapter_state *state = adap->priv; + + if (!dvb_attach(dib8000_attach, &state->dib8000_ops)) + return -ENODEV; dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL); if (fw_version >= 0x10200) @@ -2021,10 +2132,10 @@ static int tfe8096p_frontend_attach(struct dvb_usb_adapter *adap) msleep(20); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80, 1); + state->dib8000_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80, 1); - adap->fe_adap[0].fe = dvb_attach(dib8000_attach, - &adap->dev->i2c_adap, 0x80, &tfe8096p_dib8000_config); + adap->fe_adap[0].fe = state->dib8000_ops.init(&adap->dev->i2c_adap, + 0x80, &tfe8096p_dib8000_config); return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } @@ -2032,13 +2143,17 @@ static int tfe8096p_frontend_attach(struct dvb_usb_adapter *adap) static int tfe8096p_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib8096p_get_i2c_tuner(adap->fe_adap[0].fe); + struct i2c_adapter *tun_i2c = st->dib8000_ops.get_i2c_tuner(adap->fe_adap[0].fe); + + tfe8096p_dib0090_config.reset = st->dib8000_ops.tuner_sleep; + tfe8096p_dib0090_config.sleep = st->dib8000_ops.tuner_sleep; + tfe8096p_dib0090_config.wbd = dib8096p_wbd_table; if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &tfe8096p_dib0090_config) == NULL) return -ENODEV; - dib8000_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + st->dib8000_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1); st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096p_agc_startup; @@ -2479,14 +2594,14 @@ static int dib7090_agc_startup(struct dvb_frontend *fe) memset(&pll, 0, sizeof(struct dibx000_bandwidth_config)); dib0090_pwm_gain_reset(fe); target = (dib0090_get_wbd_target(fe) * 8 + 1) / 2; - dib7000p_set_wbd_ref(fe, target); + state->dib7000p_ops.set_wbd_ref(fe, target); if (dib7090p_get_best_sampling(fe, &adc) == 0) { pll.pll_ratio = adc.pll_loopdiv; pll.pll_prediv = adc.pll_prediv; - dib7000p_update_pll(fe, &pll); - dib7000p_ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf); + state->dib7000p_ops.update_pll(fe, &pll); + state->dib7000p_ops.ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf); } return 0; } @@ -2501,14 +2616,17 @@ static int dib7090_agc_restart(struct dvb_frontend *fe, u8 restart) static int tfe7790p_update_lna(struct dvb_frontend *fe, u16 agc_global) { + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + deb_info("update LNA: agc global=%i", agc_global); if (agc_global < 25000) { - dib7000p_set_gpio(fe, 8, 0, 0); - dib7000p_set_agc1_min(fe, 0); + state->dib7000p_ops.set_gpio(fe, 8, 0, 0); + state->dib7000p_ops.set_agc1_min(fe, 0); } else { - dib7000p_set_gpio(fe, 8, 0, 1); - dib7000p_set_agc1_min(fe, 32768); + state->dib7000p_ops.set_gpio(fe, 8, 0, 1); + state->dib7000p_ops.set_agc1_min(fe, 32768); } return 0; @@ -2644,13 +2762,16 @@ static struct dib7000p_config nim7090_dib7000p_config = { static int tfe7090p_pvr_update_lna(struct dvb_frontend *fe, u16 agc_global) { + struct dvb_usb_adapter *adap = fe->dvb->priv; + struct dib0700_adapter_state *state = adap->priv; + deb_info("TFE7090P-PVR update LNA: agc global=%i", agc_global); if (agc_global < 25000) { - dib7000p_set_gpio(fe, 5, 0, 0); - dib7000p_set_agc1_min(fe, 0); + state->dib7000p_ops.set_gpio(fe, 5, 0, 0); + state->dib7000p_ops.set_agc1_min(fe, 0); } else { - dib7000p_set_gpio(fe, 5, 0, 1); - dib7000p_set_agc1_min(fe, 32768); + state->dib7000p_ops.set_gpio(fe, 5, 0, 1); + state->dib7000p_ops.set_agc1_min(fe, 32768); } return 0; @@ -2714,7 +2835,7 @@ static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = { } }; -static const struct dib0090_config nim7090_dib0090_config = { +static struct dib0090_config nim7090_dib0090_config = { .io.clock_khz = 12000, .io.pll_bypass = 0, .io.pll_range = 0, @@ -2722,14 +2843,10 @@ static const struct dib0090_config nim7090_dib0090_config = { .io.pll_loopdiv = 6, .io.adc_clock_ratio = 0, .io.pll_int_loop_filt = 0, - .reset = dib7090_tuner_sleep, - .sleep = dib7090_tuner_sleep, .freq_offset_khz_uhf = 0, .freq_offset_khz_vhf = 0, - .get_adc_power = dib7090_get_adc_power, - .clkouttobamse = 1, .analog_output = 0, @@ -2776,7 +2893,7 @@ static struct dib7000p_config tfe7790p_dib7000p_config = { .enMpegOutput = 1, }; -static const struct dib0090_config tfe7790p_dib0090_config = { +static struct dib0090_config tfe7790p_dib0090_config = { .io.clock_khz = 12000, .io.pll_bypass = 0, .io.pll_range = 0, @@ -2784,14 +2901,10 @@ static const struct dib0090_config tfe7790p_dib0090_config = { .io.pll_loopdiv = 6, .io.adc_clock_ratio = 0, .io.pll_int_loop_filt = 0, - .reset = dib7090_tuner_sleep, - .sleep = dib7090_tuner_sleep, .freq_offset_khz_uhf = 0, .freq_offset_khz_vhf = 0, - .get_adc_power = dib7090_get_adc_power, - .clkouttobamse = 1, .analog_output = 0, @@ -2813,7 +2926,7 @@ static const struct dib0090_config tfe7790p_dib0090_config = { .force_crystal_mode = 1, }; -static const struct dib0090_config tfe7090pvr_dib0090_config[2] = { +static struct dib0090_config tfe7090pvr_dib0090_config[2] = { { .io.clock_khz = 12000, .io.pll_bypass = 0, @@ -2822,14 +2935,10 @@ static const struct dib0090_config tfe7090pvr_dib0090_config[2] = { .io.pll_loopdiv = 6, .io.adc_clock_ratio = 0, .io.pll_int_loop_filt = 0, - .reset = dib7090_tuner_sleep, - .sleep = dib7090_tuner_sleep, .freq_offset_khz_uhf = 50, .freq_offset_khz_vhf = 70, - .get_adc_power = dib7090_get_adc_power, - .clkouttobamse = 1, .analog_output = 0, @@ -2854,14 +2963,10 @@ static const struct dib0090_config tfe7090pvr_dib0090_config[2] = { .io.pll_loopdiv = 6, .io.adc_clock_ratio = 0, .io.pll_int_loop_filt = 0, - .reset = dib7090_tuner_sleep, - .sleep = dib7090_tuner_sleep, .freq_offset_khz_uhf = -50, .freq_offset_khz_vhf = -70, - .get_adc_power = dib7090_get_adc_power, - .clkouttobamse = 1, .analog_output = 0, @@ -2883,6 +2988,11 @@ static const struct dib0090_config tfe7090pvr_dib0090_config[2] = { static int nim7090_frontend_attach(struct dvb_usb_adapter *adap) { + struct dib0700_adapter_state *state = adap->priv; + + if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops)) + return -ENODEV; + dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1); msleep(20); dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1); @@ -2895,11 +3005,12 @@ static int nim7090_frontend_attach(struct dvb_usb_adapter *adap) msleep(20); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &nim7090_dib7000p_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); + if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &nim7090_dib7000p_config) != 0) { + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); + dvb_detach(&state->dib7000p_ops); return -ENODEV; } - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config); + adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config); return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } @@ -2907,12 +3018,16 @@ static int nim7090_frontend_attach(struct dvb_usb_adapter *adap) static int nim7090_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe); + struct i2c_adapter *tun_i2c = st->dib7000p_ops.get_i2c_tuner(adap->fe_adap[0].fe); + + nim7090_dib0090_config.reset = st->dib7000p_ops.tuner_sleep, + nim7090_dib0090_config.sleep = st->dib7000p_ops.tuner_sleep, + nim7090_dib0090_config.get_adc_power = st->dib7000p_ops.get_adc_power; if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &nim7090_dib0090_config) == NULL) return -ENODEV; - dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + st->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1); st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; @@ -2922,6 +3037,10 @@ static int nim7090_tuner_attach(struct dvb_usb_adapter *adap) static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap) { struct dib0700_state *st = adap->dev->priv; + struct dib0700_adapter_state *state = adap->priv; + + if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops)) + return -ENODEV; /* The TFE7090 requires the dib0700 to not be in master mode */ st->disable_streaming_master_mode = 1; @@ -2939,17 +3058,18 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap) dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); /* initialize IC 0 */ - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, &tfe7090pvr_dib7000p_config[0]) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); + if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, &tfe7090pvr_dib7000p_config[0]) != 0) { + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); + dvb_detach(&state->dib7000p_ops); return -ENODEV; } dib0700_set_i2c_speed(adap->dev, 340); - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]); + adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]); if (adap->fe_adap[0].fe == NULL) return -ENODEV; - dib7090_slave_reset(adap->fe_adap[0].fe); + state->dib7000p_ops.slave_reset(adap->fe_adap[0].fe); return 0; } @@ -2957,19 +3077,24 @@ static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap) static int tfe7090pvr_frontend1_attach(struct dvb_usb_adapter *adap) { struct i2c_adapter *i2c; + struct dib0700_adapter_state *state = adap->priv; if (adap->dev->adapter[0].fe_adap[0].fe == NULL) { err("the master dib7090 has to be initialized first"); return -ENODEV; /* the master device has not been initialized */ } - i2c = dib7000p_get_i2c_master(adap->dev->adapter[0].fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1); - if (dib7000p_i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", __func__); + if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops)) + return -ENODEV; + + i2c = state->dib7000p_ops.get_i2c_master(adap->dev->adapter[0].fe_adap[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1); + if (state->dib7000p_ops.i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) { + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); + dvb_detach(&state->dib7000p_ops); return -ENODEV; } - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, i2c, 0x92, &tfe7090pvr_dib7000p_config[1]); + adap->fe_adap[0].fe = state->dib7000p_ops.init(i2c, 0x92, &tfe7090pvr_dib7000p_config[1]); dib0700_set_i2c_speed(adap->dev, 200); return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; @@ -2978,12 +3103,16 @@ static int tfe7090pvr_frontend1_attach(struct dvb_usb_adapter *adap) static int tfe7090pvr_tuner0_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe); + struct i2c_adapter *tun_i2c = st->dib7000p_ops.get_i2c_tuner(adap->fe_adap[0].fe); + + tfe7090pvr_dib0090_config[0].reset = st->dib7000p_ops.tuner_sleep; + tfe7090pvr_dib0090_config[0].sleep = st->dib7000p_ops.tuner_sleep; + tfe7090pvr_dib0090_config[0].get_adc_power = st->dib7000p_ops.get_adc_power; if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &tfe7090pvr_dib0090_config[0]) == NULL) return -ENODEV; - dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + st->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1); st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; @@ -2993,12 +3122,16 @@ static int tfe7090pvr_tuner0_attach(struct dvb_usb_adapter *adap) static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; - struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe_adap[0].fe); + struct i2c_adapter *tun_i2c = st->dib7000p_ops.get_i2c_tuner(adap->fe_adap[0].fe); + + tfe7090pvr_dib0090_config[1].reset = st->dib7000p_ops.tuner_sleep; + tfe7090pvr_dib0090_config[1].sleep = st->dib7000p_ops.tuner_sleep; + tfe7090pvr_dib0090_config[1].get_adc_power = st->dib7000p_ops.get_adc_power; if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &tfe7090pvr_dib0090_config[1]) == NULL) return -ENODEV; - dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + st->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1); st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; @@ -3008,6 +3141,10 @@ static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap) static int tfe7790p_frontend_attach(struct dvb_usb_adapter *adap) { struct dib0700_state *st = adap->dev->priv; + struct dib0700_adapter_state *state = adap->priv; + + if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops)) + return -ENODEV; /* The TFE7790P requires the dib0700 to not be in master mode */ st->disable_streaming_master_mode = 1; @@ -3024,13 +3161,14 @@ static int tfe7790p_frontend_attach(struct dvb_usb_adapter *adap) msleep(20); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, + if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &tfe7790p_dib7000p_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); + dvb_detach(&state->dib7000p_ops); return -ENODEV; } - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, + adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80, &tfe7790p_dib7000p_config); return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; @@ -3040,13 +3178,18 @@ static int tfe7790p_tuner_attach(struct dvb_usb_adapter *adap) { struct dib0700_adapter_state *st = adap->priv; struct i2c_adapter *tun_i2c = - dib7090_get_i2c_tuner(adap->fe_adap[0].fe); + st->dib7000p_ops.get_i2c_tuner(adap->fe_adap[0].fe); + + + tfe7790p_dib0090_config.reset = st->dib7000p_ops.tuner_sleep; + tfe7790p_dib0090_config.sleep = st->dib7000p_ops.tuner_sleep; + tfe7790p_dib0090_config.get_adc_power = st->dib7000p_ops.get_adc_power; if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &tfe7790p_dib0090_config) == NULL) return -ENODEV; - dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + st->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1); st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params; adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib7090_agc_startup; @@ -3103,25 +3246,36 @@ static void stk7070pd_init(struct dvb_usb_device *dev) static int stk7070pd_frontend_attach0(struct dvb_usb_adapter *adap) { + struct dib0700_adapter_state *state = adap->priv; + + if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops)) + return -ENODEV; + stk7070pd_init(adap->dev); msleep(10); dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1); - if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, + if (state->dib7000p_ops.i2c_enumeration(&adap->dev->i2c_adap, 2, 18, stk7070pd_dib7000p_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); + dvb_detach(&state->dib7000p_ops); return -ENODEV; } - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]); + adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x80, &stk7070pd_dib7000p_config[0]); return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap) { - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]); + struct dib0700_adapter_state *state = adap->priv; + + if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops)) + return -ENODEV; + + adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x82, &stk7070pd_dib7000p_config[1]); return adap->fe_adap[0].fe == NULL ? -ENODEV : 0; } @@ -3164,6 +3318,10 @@ static int novatd_frontend_attach(struct dvb_usb_adapter *adap) { struct dvb_usb_device *dev = adap->dev; struct dib0700_state *st = dev->priv; + struct dib0700_adapter_state *state = adap->priv; + + if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops)) + return -ENODEV; if (adap->id == 0) { stk7070pd_init(dev); @@ -3173,15 +3331,16 @@ static int novatd_frontend_attach(struct dvb_usb_adapter *adap) dib0700_set_gpio(dev, GPIO1, GPIO_OUT, 0); dib0700_set_gpio(dev, GPIO2, GPIO_OUT, 1); - if (dib7000p_i2c_enumeration(&dev->i2c_adap, 2, 18, + if (state->dib7000p_ops.i2c_enumeration(&dev->i2c_adap, 2, 18, stk7070pd_dib7000p_config) != 0) { - err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n", + err("%s: state->dib7000p_ops.i2c_enumeration failed. Cannot continue\n", __func__); + dvb_detach(&state->dib7000p_ops); return -ENODEV; } } - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &dev->i2c_adap, + adap->fe_adap[0].fe = state->dib7000p_ops.init(&dev->i2c_adap, adap->id == 0 ? 0x80 : 0x82, &stk7070pd_dib7000p_config[adap->id]); @@ -3291,12 +3450,13 @@ static int dib0700_xc4000_tuner_callback(void *priv, int component, int command, int arg) { struct dvb_usb_adapter *adap = priv; + struct dib0700_adapter_state *state = adap->priv; if (command == XC4000_TUNER_RESET) { /* Reset the tuner */ - dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 0); + state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 0); msleep(10); - dib7000p_set_gpio(adap->fe_adap[0].fe, 8, 0, 1); + state->dib7000p_ops.set_gpio(adap->fe_adap[0].fe, 8, 0, 1); } else { err("xc4000: unknown tuner callback command: %d\n", command); return -EINVAL; @@ -3374,6 +3534,10 @@ static struct dib7000p_config pctv_340e_config = { static int pctv340e_frontend_attach(struct dvb_usb_adapter *adap) { struct dib0700_state *st = adap->dev->priv; + struct dib0700_adapter_state *state = adap->priv; + + if (!dvb_attach(dib7000p_attach, &state->dib7000p_ops)) + return -ENODEV; /* Power Supply on */ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0); @@ -3397,12 +3561,13 @@ static int pctv340e_frontend_attach(struct dvb_usb_adapter *adap) msleep(500); - if (dib7000pc_detection(&adap->dev->i2c_adap) == 0) { + if (state->dib7000p_ops.dib7000pc_detection(&adap->dev->i2c_adap) == 0) { /* Demodulator not found for some reason? */ + dvb_detach(&state->dib7000p_ops); return -ENODEV; } - adap->fe_adap[0].fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x12, + adap->fe_adap[0].fe = state->dib7000p_ops.init(&adap->dev->i2c_adap, 0x12, &pctv_340e_config); st->is_dib7000pc = 1; @@ -3420,9 +3585,10 @@ static struct xc4000_config dib7000p_xc4000_tunerconfig = { static int xc4000_tuner_attach(struct dvb_usb_adapter *adap) { struct i2c_adapter *tun_i2c; + struct dib0700_adapter_state *state = adap->priv; /* The xc4000 is not on the main i2c bus */ - tun_i2c = dib7000p_get_i2c_master(adap->fe_adap[0].fe, + tun_i2c = state->dib7000p_ops.get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1); if (tun_i2c == NULL) { printk(KERN_ERR "Could not reach tuner i2c bus\n"); diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c index d947e0379008..6b0b8b6b9e2a 100644 --- a/drivers/media/usb/dvb-usb/technisat-usb2.c +++ b/drivers/media/usb/dvb-usb/technisat-usb2.c @@ -710,7 +710,7 @@ static struct dvb_usb_device_properties technisat_usb2_devices = { .isoc = { .framesperurb = 32, .framesize = 2048, - .interval = 3, + .interval = 1, } } }, diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c index 15ad47045553..9da812b8a786 100644 --- a/drivers/media/usb/em28xx/em28xx-cards.c +++ b/drivers/media/usb/em28xx/em28xx-cards.c @@ -2280,6 +2280,8 @@ struct usb_device_id em28xx_id_table[] = { .driver_info = EM2820_BOARD_UNKNOWN }, { USB_DEVICE(0xeb1a, 0x2875), .driver_info = EM2820_BOARD_UNKNOWN }, + { USB_DEVICE(0xeb1a, 0x2885), /* MSI Digivox Trio */ + .driver_info = EM2884_BOARD_TERRATEC_H5 }, { USB_DEVICE(0xeb1a, 0xe300), .driver_info = EM2861_BOARD_KWORLD_PVRTV_300U }, { USB_DEVICE(0xeb1a, 0xe303), diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c index a121ed9561fd..96a0bdbecfad 100644 --- a/drivers/media/usb/em28xx/em28xx-dvb.c +++ b/drivers/media/usb/em28xx/em28xx-dvb.c @@ -1545,6 +1545,7 @@ static int em28xx_dvb_init(struct em28xx *dev) dvb->i2c_client_demod = client; /* attach tuner */ + memset(&si2157_config, 0, sizeof(si2157_config)); si2157_config.fe = dvb->fe[0]; memset(&info, 0, sizeof(struct i2c_board_info)); strlcpy(info.type, "si2157", I2C_NAME_SIZE); diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c index f6b49c98e2c9..3f8b5aa7669a 100644 --- a/drivers/media/usb/em28xx/em28xx-video.c +++ b/drivers/media/usb/em28xx/em28xx-video.c @@ -2208,7 +2208,6 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev, vfd->v4l2_dev = &dev->v4l2->v4l2_dev; vfd->debug = video_debug; vfd->lock = &dev->lock; - set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); if (dev->board.is_webcam) vfd->tvnorms = 0; diff --git a/drivers/media/usb/gspca/autogain_functions.c b/drivers/media/usb/gspca/autogain_functions.c index 67db674bb044..0e9ee8b50bb7 100644 --- a/drivers/media/usb/gspca/autogain_functions.c +++ b/drivers/media/usb/gspca/autogain_functions.c @@ -121,9 +121,9 @@ int gspca_coarse_grained_expo_autogain( orig_gain = gain = v4l2_ctrl_g_ctrl(gspca_dev->gain); orig_exposure = exposure = v4l2_ctrl_g_ctrl(gspca_dev->exposure); - gain_low = (gspca_dev->gain->maximum - gspca_dev->gain->minimum) / + gain_low = (s32)(gspca_dev->gain->maximum - gspca_dev->gain->minimum) / 5 * 2 + gspca_dev->gain->minimum; - gain_high = (gspca_dev->gain->maximum - gspca_dev->gain->minimum) / + gain_high = (s32)(gspca_dev->gain->maximum - gspca_dev->gain->minimum) / 5 * 4 + gspca_dev->gain->minimum; /* If we are of a multiple of deadzone, do multiple steps to reach the diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c index f3a7ace0fac9..e8cf23c91cef 100644 --- a/drivers/media/usb/gspca/gspca.c +++ b/drivers/media/usb/gspca/gspca.c @@ -603,10 +603,13 @@ static void gspca_stream_off(struct gspca_dev *gspca_dev) } /* - * look for an input transfer endpoint in an alternate setting + * look for an input transfer endpoint in an alternate setting. + * + * If xfer_ep is invalid, return the first valid ep found, otherwise + * look for exactly the ep with address equal to xfer_ep. */ static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt, - int xfer) + int xfer, int xfer_ep) { struct usb_host_endpoint *ep; int i, attr; @@ -616,7 +619,8 @@ static struct usb_host_endpoint *alt_xfer(struct usb_host_interface *alt, attr = ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK; if (attr == xfer && ep->desc.wMaxPacketSize != 0 - && usb_endpoint_dir_in(&ep->desc)) + && usb_endpoint_dir_in(&ep->desc) + && (xfer_ep < 0 || ep->desc.bEndpointAddress == xfer_ep)) return ep; } return NULL; @@ -689,7 +693,8 @@ static int build_isoc_ep_tb(struct gspca_dev *gspca_dev, found = 0; for (j = 0; j < nbalt; j++) { ep = alt_xfer(&intf->altsetting[j], - USB_ENDPOINT_XFER_ISOC); + USB_ENDPOINT_XFER_ISOC, + gspca_dev->xfer_ep); if (ep == NULL) continue; if (ep->desc.bInterval == 0) { @@ -862,7 +867,8 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) /* if bulk or the subdriver forced an altsetting, get the endpoint */ if (gspca_dev->alt != 0) { gspca_dev->alt--; /* (previous version compatibility) */ - ep = alt_xfer(&intf->altsetting[gspca_dev->alt], xfer); + ep = alt_xfer(&intf->altsetting[gspca_dev->alt], xfer, + gspca_dev->xfer_ep); if (ep == NULL) { pr_err("bad altsetting %d\n", gspca_dev->alt); return -EIO; @@ -904,7 +910,8 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev) if (!gspca_dev->cam.no_urb_create) { PDEBUG(D_STREAM, "init transfer alt %d", alt); ret = create_urbs(gspca_dev, - alt_xfer(&intf->altsetting[alt], xfer)); + alt_xfer(&intf->altsetting[alt], xfer, + gspca_dev->xfer_ep)); if (ret < 0) { destroy_urbs(gspca_dev); goto out; @@ -1102,8 +1109,8 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, struct gspca_dev *gspca_dev = video_drvdata(file); fmt->fmt.pix = gspca_dev->pixfmt; - /* some drivers use priv internally, zero it before giving it to - userspace */ + /* some drivers use priv internally, zero it before giving it back to + the core */ fmt->fmt.pix.priv = 0; return 0; } @@ -1139,8 +1146,8 @@ static int try_fmt_vid_cap(struct gspca_dev *gspca_dev, fmt->fmt.pix.height = h; gspca_dev->sd_desc->try_fmt(gspca_dev, fmt); } - /* some drivers use priv internally, zero it before giving it to - userspace */ + /* some drivers use priv internally, zero it before giving it back to + the core */ fmt->fmt.pix.priv = 0; return mode; /* used when s_fmt */ } @@ -2030,6 +2037,7 @@ int gspca_dev_probe2(struct usb_interface *intf, } gspca_dev->dev = dev; gspca_dev->iface = intf->cur_altsetting->desc.bInterfaceNumber; + gspca_dev->xfer_ep = -1; /* check if any audio device */ if (dev->actconfig->desc.bNumInterfaces != 1) { @@ -2058,7 +2066,6 @@ int gspca_dev_probe2(struct usb_interface *intf, gspca_dev->vdev = gspca_template; gspca_dev->vdev.v4l2_dev = &gspca_dev->v4l2_dev; video_set_drvdata(&gspca_dev->vdev, gspca_dev); - set_bit(V4L2_FL_USE_FH_PRIO, &gspca_dev->vdev.flags); gspca_dev->module = module; gspca_dev->present = 1; diff --git a/drivers/media/usb/gspca/gspca.h b/drivers/media/usb/gspca/gspca.h index 300642dc1a17..f06253cd7469 100644 --- a/drivers/media/usb/gspca/gspca.h +++ b/drivers/media/usb/gspca/gspca.h @@ -205,6 +205,7 @@ struct gspca_dev { char memory; /* memory type (V4L2_MEMORY_xxx) */ __u8 iface; /* USB interface number */ __u8 alt; /* USB alternate setting */ + int xfer_ep; /* USB transfer endpoint address */ u8 audio; /* presence of audio device */ /* (*) These variables are proteced by both usb_lock and queue_lock, diff --git a/drivers/media/usb/gspca/kinect.c b/drivers/media/usb/gspca/kinect.c index 081f05162809..45bc1f51c5d8 100644 --- a/drivers/media/usb/gspca/kinect.c +++ b/drivers/media/usb/gspca/kinect.c @@ -36,6 +36,8 @@ MODULE_AUTHOR("Antonio Ospite <ospite@studenti.unina.it>"); MODULE_DESCRIPTION("GSPCA/Kinect Sensor Device USB Camera Driver"); MODULE_LICENSE("GPL"); +static bool depth_mode; + struct pkt_hdr { uint8_t magic[2]; uint8_t pad; @@ -73,6 +75,14 @@ struct sd { #define FPS_HIGH 0x0100 +static const struct v4l2_pix_format depth_camera_mode[] = { + {640, 480, V4L2_PIX_FMT_Y10BPACK, V4L2_FIELD_NONE, + .bytesperline = 640 * 10 / 8, + .sizeimage = 640 * 480 * 10 / 8, + .colorspace = V4L2_COLORSPACE_SRGB, + .priv = MODE_640x488 | FORMAT_Y10B}, +}; + static const struct v4l2_pix_format video_camera_mode[] = { {640, 480, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE, .bytesperline = 640, @@ -219,7 +229,7 @@ static int write_register(struct gspca_dev *gspca_dev, uint16_t reg, } /* this function is called at probe time */ -static int sd_config(struct gspca_dev *gspca_dev, +static int sd_config_video(struct gspca_dev *gspca_dev, const struct usb_device_id *id) { struct sd *sd = (struct sd *) gspca_dev; @@ -227,8 +237,6 @@ static int sd_config(struct gspca_dev *gspca_dev, sd->cam_tag = 0; - /* Only video stream is supported for now, - * which has stream flag = 0x80 */ sd->stream_flag = 0x80; cam = &gspca_dev->cam; @@ -236,6 +244,8 @@ static int sd_config(struct gspca_dev *gspca_dev, cam->cam_mode = video_camera_mode; cam->nmodes = ARRAY_SIZE(video_camera_mode); + gspca_dev->xfer_ep = 0x81; + #if 0 /* Setting those values is not needed for video stream */ cam->npkt = 15; @@ -245,6 +255,26 @@ static int sd_config(struct gspca_dev *gspca_dev, return 0; } +static int sd_config_depth(struct gspca_dev *gspca_dev, + const struct usb_device_id *id) +{ + struct sd *sd = (struct sd *) gspca_dev; + struct cam *cam; + + sd->cam_tag = 0; + + sd->stream_flag = 0x70; + + cam = &gspca_dev->cam; + + cam->cam_mode = depth_camera_mode; + cam->nmodes = ARRAY_SIZE(depth_camera_mode); + + gspca_dev->xfer_ep = 0x82; + + return 0; +} + /* this function is called at probe and resume time */ static int sd_init(struct gspca_dev *gspca_dev) { @@ -253,7 +283,7 @@ static int sd_init(struct gspca_dev *gspca_dev) return 0; } -static int sd_start(struct gspca_dev *gspca_dev) +static int sd_start_video(struct gspca_dev *gspca_dev) { int mode; uint8_t fmt_reg, fmt_val; @@ -325,12 +355,39 @@ static int sd_start(struct gspca_dev *gspca_dev) return 0; } -static void sd_stopN(struct gspca_dev *gspca_dev) +static int sd_start_depth(struct gspca_dev *gspca_dev) +{ + /* turn off IR-reset function */ + write_register(gspca_dev, 0x105, 0x00); + + /* reset depth stream */ + write_register(gspca_dev, 0x06, 0x00); + /* Depth Stream Format 0x03: 11 bit stream | 0x02: 10 bit */ + write_register(gspca_dev, 0x12, 0x02); + /* Depth Stream Resolution 1: standard (640x480) */ + write_register(gspca_dev, 0x13, 0x01); + /* Depth Framerate / 0x1e (30): 30 fps */ + write_register(gspca_dev, 0x14, 0x1e); + /* Depth Stream Control / 2: Open Depth Stream */ + write_register(gspca_dev, 0x06, 0x02); + /* disable depth hflip / LSB = 0: Smoothing Disabled */ + write_register(gspca_dev, 0x17, 0x00); + + return 0; +} + +static void sd_stopN_video(struct gspca_dev *gspca_dev) { /* reset video stream */ write_register(gspca_dev, 0x05, 0x00); } +static void sd_stopN_depth(struct gspca_dev *gspca_dev) +{ + /* reset depth stream */ + write_register(gspca_dev, 0x06, 0x00); +} + static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *__data, int len) { struct sd *sd = (struct sd *) gspca_dev; @@ -366,12 +423,24 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, u8 *__data, int len) } /* sub-driver description */ -static const struct sd_desc sd_desc = { +static const struct sd_desc sd_desc_video = { .name = MODULE_NAME, - .config = sd_config, + .config = sd_config_video, .init = sd_init, - .start = sd_start, - .stopN = sd_stopN, + .start = sd_start_video, + .stopN = sd_stopN_video, + .pkt_scan = sd_pkt_scan, + /* + .get_streamparm = sd_get_streamparm, + .set_streamparm = sd_set_streamparm, + */ +}; +static const struct sd_desc sd_desc_depth = { + .name = MODULE_NAME, + .config = sd_config_depth, + .init = sd_init, + .start = sd_start_depth, + .stopN = sd_stopN_depth, .pkt_scan = sd_pkt_scan, /* .get_streamparm = sd_get_streamparm, @@ -391,8 +460,12 @@ MODULE_DEVICE_TABLE(usb, device_table); /* -- device connect -- */ static int sd_probe(struct usb_interface *intf, const struct usb_device_id *id) { - return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd), - THIS_MODULE); + if (depth_mode) + return gspca_dev_probe(intf, id, &sd_desc_depth, + sizeof(struct sd), THIS_MODULE); + else + return gspca_dev_probe(intf, id, &sd_desc_video, + sizeof(struct sd), THIS_MODULE); } static struct usb_driver sd_driver = { @@ -408,3 +481,6 @@ static struct usb_driver sd_driver = { }; module_usb_driver(sd_driver); + +module_param(depth_mode, bool, 0644); +MODULE_PARM_DESC(depth_mode, "0=video 1=depth"); diff --git a/drivers/media/usb/gspca/pac7302.c b/drivers/media/usb/gspca/pac7302.c index 339adce7c7a5..8b08bd0172f4 100644 --- a/drivers/media/usb/gspca/pac7302.c +++ b/drivers/media/usb/gspca/pac7302.c @@ -394,9 +394,9 @@ static void setbrightcont(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ for (i = 0; i < 10; i++) { v = max[i]; - v += (sd->brightness->val - sd->brightness->maximum) - * 150 / sd->brightness->maximum; /* 200 ? */ - v -= delta[i] * sd->contrast->val / sd->contrast->maximum; + v += (sd->brightness->val - (s32)sd->brightness->maximum) + * 150 / (s32)sd->brightness->maximum; /* 200 ? */ + v -= delta[i] * sd->contrast->val / (s32)sd->contrast->maximum; if (v < 0) v = 0; else if (v > 0xff) @@ -419,7 +419,7 @@ static void setcolors(struct gspca_dev *gspca_dev) reg_w(gspca_dev, 0x11, 0x01); reg_w(gspca_dev, 0xff, 0x00); /* page 0 */ for (i = 0; i < 9; i++) { - v = a[i] * sd->saturation->val / sd->saturation->maximum; + v = a[i] * sd->saturation->val / (s32)sd->saturation->maximum; v += b[i]; reg_w(gspca_dev, 0x0f + 2 * i, (v >> 8) & 0x07); reg_w(gspca_dev, 0x0f + 2 * i + 1, v); diff --git a/drivers/media/usb/gspca/sonixb.c b/drivers/media/usb/gspca/sonixb.c index ecbcb39feb71..6696b2ec34e9 100644 --- a/drivers/media/usb/gspca/sonixb.c +++ b/drivers/media/usb/gspca/sonixb.c @@ -913,7 +913,7 @@ static void do_autogain(struct gspca_dev *gspca_dev) desired_avg_lum, deadzone)) sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES; } else { - int gain_knee = gspca_dev->gain->maximum * 9 / 10; + int gain_knee = (s32)gspca_dev->gain->maximum * 9 / 10; if (gspca_expo_autogain(gspca_dev, avg_lum, desired_avg_lum, deadzone, gain_knee, sd->exposure_knee)) sd->autogain_ignore_frames = AUTOGAIN_IGNORE_FRAMES; diff --git a/drivers/media/usb/hdpvr/hdpvr-video.c b/drivers/media/usb/hdpvr/hdpvr-video.c index 6bce01a674f9..59d15fd242ba 100644 --- a/drivers/media/usb/hdpvr/hdpvr-video.c +++ b/drivers/media/usb/hdpvr/hdpvr-video.c @@ -1022,14 +1022,13 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *_fh, f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG; f->fmt.pix.sizeimage = dev->bulk_in_size; f->fmt.pix.bytesperline = 0; - f->fmt.pix.priv = 0; if (f->fmt.pix.width == 720) { /* SDTV formats */ f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.field = V4L2_FIELD_INTERLACED; } else { /* HDTV formats */ - f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE240M; + f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709; f->fmt.pix.field = V4L2_FIELD_NONE; } return 0; @@ -1240,7 +1239,6 @@ int hdpvr_register_videodev(struct hdpvr_device *dev, struct device *parent, strcpy(dev->video_dev->name, "Hauppauge HD PVR"); dev->video_dev->v4l2_dev = &dev->v4l2_dev; video_set_drvdata(dev->video_dev, dev); - set_bit(V4L2_FL_USE_FH_PRIO, &dev->video_dev->flags); res = video_register_device(dev->video_dev, VFL_TYPE_GRABBER, devnum); if (res < 0) { diff --git a/drivers/media/usb/msi2500/Kconfig b/drivers/media/usb/msi2500/Kconfig new file mode 100644 index 000000000000..9eff8a76ff0e --- /dev/null +++ b/drivers/media/usb/msi2500/Kconfig @@ -0,0 +1,5 @@ +config USB_MSI2500 + tristate "Mirics MSi2500" + depends on VIDEO_V4L2 && SPI + select VIDEOBUF2_VMALLOC + select MEDIA_TUNER_MSI001 diff --git a/drivers/media/usb/msi2500/Makefile b/drivers/media/usb/msi2500/Makefile new file mode 100644 index 000000000000..b3bc2e53707f --- /dev/null +++ b/drivers/media/usb/msi2500/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_USB_MSI2500) += msi2500.o diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c new file mode 100644 index 000000000000..483dc6e6642d --- /dev/null +++ b/drivers/media/usb/msi2500/msi2500.c @@ -0,0 +1,1535 @@ +/* + * Mirics MSi3101 SDR Dongle driver + * + * Copyright (C) 2013 Antti Palosaari <crope@iki.fi> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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> + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <asm/div64.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 <media/videobuf2-vmalloc.h> +#include <linux/spi/spi.h> + +static bool msi3101_emulated_fmt; +module_param_named(emulated_formats, msi3101_emulated_fmt, bool, 0644); +MODULE_PARM_DESC(emulated_formats, "enable emulated formats (disappears in future)"); + +/* + * iConfiguration 0 + * bInterfaceNumber 0 + * bAlternateSetting 1 + * bNumEndpoints 1 + * bEndpointAddress 0x81 EP 1 IN + * bmAttributes 1 + * Transfer Type Isochronous + * wMaxPacketSize 0x1400 3x 1024 bytes + * bInterval 1 + */ +#define MAX_ISO_BUFS (8) +#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 V4L2_PIX_FMT_SDR_S12 v4l2_fourcc('D', 'S', '1', '2') /* signed 12-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[] = { + { + .tuner = 0, + .type = V4L2_TUNER_ADC, + .index = 0, + .capability = V4L2_TUNER_CAP_1HZ | V4L2_TUNER_CAP_FREQ_BANDS, + .rangelow = 1200000, + .rangehigh = 15000000, + }, +}; + +/* stream formats */ +struct msi3101_format { + char *name; + u32 pixelformat; + u32 buffersize; +}; + +/* format descriptions for capture and preview */ +static struct msi3101_format formats[] = { + { + .name = "Complex S8", + .pixelformat = V4L2_SDR_FMT_CS8, + .buffersize = 3 * 1008, +#if 0 + }, { + .name = "10+2-bit signed", + .pixelformat = V4L2_PIX_FMT_SDR_MSI2500_384, + }, { + .name = "12-bit signed", + .pixelformat = V4L2_PIX_FMT_SDR_S12, +#endif + }, { + .name = "Complex S14LE", + .pixelformat = V4L2_SDR_FMT_CS14LE, + .buffersize = 3 * 1008, + }, { + .name = "Complex U8 (emulated)", + .pixelformat = V4L2_SDR_FMT_CU8, + .buffersize = 3 * 1008, + }, { + .name = "Complex U16LE (emulated)", + .pixelformat = V4L2_SDR_FMT_CU16LE, + .buffersize = 3 * 1008, + }, +}; + +static const unsigned int NUM_FORMATS = ARRAY_SIZE(formats); + +/* intermediate buffers with raw data from the USB device */ +struct msi3101_frame_buf { + struct vb2_buffer vb; /* common v4l buffer stuff -- must be first */ + struct list_head list; +}; + +struct msi3101_state { + struct video_device vdev; + struct v4l2_device v4l2_dev; + struct v4l2_subdev *v4l2_subdev; + struct spi_master *master; + + /* videobuf2 queue and queued buffers list */ + struct vb2_queue vb_queue; + struct list_head queued_bufs; + spinlock_t queued_bufs_lock; /* Protects queued_bufs */ + + /* Note if taking both locks v4l2_lock must always be locked first! */ + struct mutex v4l2_lock; /* Protects everything else */ + struct mutex vb_queue_lock; /* Protects vb_queue and capt_file */ + + /* 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; + u32 pixelformat; + u32 buffersize; + unsigned int num_formats; + + unsigned int isoc_errors; /* number of contiguous ISOC errors */ + unsigned int vb_full; /* vb is full and packets dropped */ + + struct urb *urbs[MAX_ISO_BUFS]; + int (*convert_stream)(struct msi3101_state *s, u8 *dst, u8 *src, + unsigned int src_len); + + /* Controls */ + struct v4l2_ctrl_handler hdl; + + u32 next_sample; /* for track lost packets */ + u32 sample; /* for sample rate calc */ + unsigned long jiffies_next; + unsigned int sample_ctrl_bit[4]; +}; + +/* Private functions */ +static struct msi3101_frame_buf *msi3101_get_next_fill_buf( + struct msi3101_state *s) +{ + unsigned long flags = 0; + struct msi3101_frame_buf *buf = NULL; + + spin_lock_irqsave(&s->queued_bufs_lock, flags); + if (list_empty(&s->queued_bufs)) + goto leave; + + buf = list_entry(s->queued_bufs.next, struct msi3101_frame_buf, list); + list_del(&buf->list); +leave: + spin_unlock_irqrestore(&s->queued_bufs_lock, flags); + return buf; +} + +/* + * +=========================================================================== + * | 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 int msi3101_convert_stream_504(struct msi3101_state *s, u8 *dst, + u8 *src, unsigned int src_len) +{ + int i, i_max, dst_len = 0; + u32 sample_num[3]; + + /* 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]); + + /* 504 x I+Q samples */ + src += 16; + memcpy(dst, src, 1008); + src += 1008; + dst += 1008; + dst_len += 1008; + } + + /* calculate samping rate and output it in 10 seconds intervals */ + 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_next); + unsigned int samples = sample_num[i_max - 1] - s->sample; + 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", + 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; +} + +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' + * +=========================================================================== + * | 00- 03 | sequence number of first sample in that USB packet + * +--------------------------------------------------------------------------- + * | 04- 15 | garbage + * +--------------------------------------------------------------------------- + * | 16- 175 | samples + * +--------------------------------------------------------------------------- + * | 176- 179 | control bits for previous samples + * +--------------------------------------------------------------------------- + * | 180- 339 | samples + * +--------------------------------------------------------------------------- + * | 340- 343 | control bits for previous samples + * +--------------------------------------------------------------------------- + * | 344- 503 | samples + * +--------------------------------------------------------------------------- + * | 504- 507 | control bits for previous samples + * +--------------------------------------------------------------------------- + * | 508- 667 | samples + * +--------------------------------------------------------------------------- + * | 668- 671 | control bits for previous samples + * +--------------------------------------------------------------------------- + * | 672- 831 | samples + * +--------------------------------------------------------------------------- + * | 832- 835 | control bits for previous samples + * +--------------------------------------------------------------------------- + * | 836- 995 | samples + * +--------------------------------------------------------------------------- + * | 996- 999 | control bits for previous samples + * +--------------------------------------------------------------------------- + * | 1000-1023 | garbage + * +--------------------------------------------------------------------------- + * + * Bytes 4 - 7 could have some meaning? + * + * Control bits for previous samples is 32-bit field, containing 16 x 2-bit + * numbers. This results one 2-bit number for 8 samples. It is likely used for + * for bit shifting sample by given bits, increasing actual sampling resolution. + * Number 2 (0b10) was never seen. + * + * 6 * 16 * 2 * 4 = 768 samples. 768 * 4 = 3072 bytes + */ +static int msi3101_convert_stream_384(struct msi3101_state *s, u8 *dst, + u8 *src, unsigned int src_len) +{ + int i, i_max, dst_len = 0; + u32 sample_num[3]; + + /* 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 %*ph\n", 12, &src[4], 24, &src[1000]); + + /* 384 x I+Q samples */ + src += 16; + memcpy(dst, src, 984); + src += 984 + 24; + dst += 984; + dst_len += 984; + } + + /* calculate samping rate and output it in 10 seconds intervals */ + 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_next); + unsigned int samples = sample_num[i_max - 1] - s->sample; + 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", + src_len, samples, msecs, + samples * 1000UL / msecs, + s->sample_ctrl_bit[0], s->sample_ctrl_bit[1], + s->sample_ctrl_bit[2], s->sample_ctrl_bit[3]); + } + + /* next sample (sample = sample + i * 384) */ + s->next_sample = sample_num[i_max - 1] + 384; + + return dst_len; +} + +/* + * +=========================================================================== + * | 00-1023 | USB packet type '336' + * +=========================================================================== + * | 00- 03 | sequence number of first sample in that USB packet + * +--------------------------------------------------------------------------- + * | 04- 15 | garbage + * +--------------------------------------------------------------------------- + * | 16-1023 | samples + * +--------------------------------------------------------------------------- + * signed 12-bit sample + */ +static int msi3101_convert_stream_336(struct msi3101_state *s, u8 *dst, + u8 *src, unsigned int src_len) +{ + int i, i_max, dst_len = 0; + u32 sample_num[3]; + + /* 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]); + + /* 336 x I+Q samples */ + src += 16; + memcpy(dst, src, 1008); + src += 1008; + dst += 1008; + dst_len += 1008; + } + + /* calculate samping rate and output it in 10 seconds intervals */ + 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_next); + unsigned int samples = sample_num[i_max - 1] - s->sample; + 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", + src_len, samples, msecs, + samples * 1000UL / msecs); + } + + /* next sample (sample = sample + i * 336) */ + s->next_sample = sample_num[i_max - 1] + 336; + + return dst_len; +} + +/* + * +=========================================================================== + * | 00-1023 | USB packet type '252' + * +=========================================================================== + * | 00- 03 | sequence number of first sample in that USB packet + * +--------------------------------------------------------------------------- + * | 04- 15 | garbage + * +--------------------------------------------------------------------------- + * | 16-1023 | samples + * +--------------------------------------------------------------------------- + * signed 14-bit sample + */ +static int msi3101_convert_stream_252(struct msi3101_state *s, u8 *dst, + u8 *src, unsigned int src_len) +{ + int i, i_max, dst_len = 0; + u32 sample_num[3]; + + /* 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; + memcpy(dst, src, 1008); + src += 1008; + dst += 1008; + dst_len += 1008; + } + + /* calculate samping rate and output it in 10 seconds intervals */ + 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_next); + unsigned int samples = sample_num[i_max - 1] - s->sample; + 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", + 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; +} + +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. + */ +static void msi3101_isoc_handler(struct urb *urb) +{ + struct msi3101_state *s = (struct msi3101_state *)urb->context; + int i, flen, fstatus; + unsigned char *iso_buf = NULL; + struct msi3101_frame_buf *fbuf; + + 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 (unlikely(urb->status != 0)) { + dev_dbg(&s->udev->dev, + "msi3101_isoc_handler() called with status %d\n", + urb->status); + /* Give up after a number of contiguous errors */ + if (++s->isoc_errors > MAX_ISOC_ERRORS) + dev_dbg(&s->udev->dev, + "Too many ISOC errors, bailing out\n"); + goto handler_end; + } else { + /* Reset ISOC error counter. We did get here, after all. */ + s->isoc_errors = 0; + } + + /* Compact data */ + for (i = 0; i < urb->number_of_packets; i++) { + void *ptr; + + /* Check frame error */ + fstatus = urb->iso_frame_desc[i].status; + if (unlikely(fstatus)) { + dev_dbg_ratelimited(&s->udev->dev, + "frame=%d/%d has error %d skipping\n", + i, urb->number_of_packets, fstatus); + continue; + } + + /* Check if that frame contains data */ + flen = urb->iso_frame_desc[i].actual_length; + 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 (unlikely(fbuf == NULL)) { + s->vb_full++; + dev_dbg_ratelimited(&s->udev->dev, + "videobuf is full, %d packets dropped\n", + s->vb_full); + continue; + } + + /* fill framebuffer */ + ptr = vb2_plane_vaddr(&fbuf->vb, 0); + 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); + } + +handler_end: + i = usb_submit_urb(urb, GFP_ATOMIC); + if (unlikely(i != 0)) + dev_dbg(&s->udev->dev, + "Error (%d) re-submitting urb in msi3101_isoc_handler\n", + i); +} + +static void msi3101_iso_stop(struct msi3101_state *s) +{ + int i; + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + /* Unlinking ISOC buffers one by one */ + for (i = 0; i < MAX_ISO_BUFS; i++) { + if (s->urbs[i]) { + dev_dbg(&s->udev->dev, "Unlinking URB %p\n", + s->urbs[i]); + usb_kill_urb(s->urbs[i]); + } + } +} + +static void msi3101_iso_free(struct msi3101_state *s) +{ + int i; + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + /* Freeing ISOC buffers one by one */ + for (i = 0; i < MAX_ISO_BUFS; i++) { + if (s->urbs[i]) { + dev_dbg(&s->udev->dev, "Freeing URB\n"); + if (s->urbs[i]->transfer_buffer) { + usb_free_coherent(s->udev, + s->urbs[i]->transfer_buffer_length, + s->urbs[i]->transfer_buffer, + s->urbs[i]->transfer_dma); + } + usb_free_urb(s->urbs[i]); + s->urbs[i] = NULL; + } + } +} + +/* Both v4l2_lock and vb_queue_lock should be locked when calling this */ +static void msi3101_isoc_cleanup(struct msi3101_state *s) +{ + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + msi3101_iso_stop(s); + msi3101_iso_free(s); +} + +/* Both v4l2_lock and vb_queue_lock should be locked when calling this */ +static int msi3101_isoc_init(struct msi3101_state *s) +{ + struct usb_device *udev; + struct urb *urb; + int i, j, ret; + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + s->isoc_errors = 0; + udev = s->udev; + + ret = usb_set_interface(s->udev, 0, 1); + if (ret) + return ret; + + /* Allocate and init Isochronuous urbs */ + for (i = 0; i < MAX_ISO_BUFS; i++) { + urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); + if (urb == NULL) { + dev_err(&s->udev->dev, + "Failed to allocate urb %d\n", i); + msi3101_isoc_cleanup(s); + return -ENOMEM; + } + s->urbs[i] = urb; + dev_dbg(&s->udev->dev, "Allocated URB at 0x%p\n", urb); + + urb->interval = 1; + urb->dev = udev; + urb->pipe = usb_rcvisocpipe(udev, 0x81); + urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; + urb->transfer_buffer = usb_alloc_coherent(udev, ISO_BUFFER_SIZE, + GFP_KERNEL, &urb->transfer_dma); + if (urb->transfer_buffer == NULL) { + dev_err(&s->udev->dev, + "Failed to allocate urb buffer %d\n", + i); + msi3101_isoc_cleanup(s); + return -ENOMEM; + } + urb->transfer_buffer_length = ISO_BUFFER_SIZE; + urb->complete = msi3101_isoc_handler; + urb->context = s; + urb->start_frame = 0; + urb->number_of_packets = ISO_FRAMES_PER_DESC; + for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { + urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; + urb->iso_frame_desc[j].length = ISO_MAX_FRAME_SIZE; + } + } + + /* link */ + for (i = 0; i < MAX_ISO_BUFS; i++) { + ret = usb_submit_urb(s->urbs[i], GFP_KERNEL); + if (ret) { + dev_err(&s->udev->dev, + "isoc_init() submit_urb %d failed with error %d\n", + i, ret); + msi3101_isoc_cleanup(s); + return ret; + } + dev_dbg(&s->udev->dev, "URB 0x%p submitted.\n", s->urbs[i]); + } + + /* All is done... */ + return 0; +} + +/* Must be called with vb_queue_lock hold */ +static void msi3101_cleanup_queued_bufs(struct msi3101_state *s) +{ + unsigned long flags = 0; + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + spin_lock_irqsave(&s->queued_bufs_lock, flags); + while (!list_empty(&s->queued_bufs)) { + struct msi3101_frame_buf *buf; + + buf = list_entry(s->queued_bufs.next, struct msi3101_frame_buf, + list); + list_del(&buf->list); + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + } + spin_unlock_irqrestore(&s->queued_bufs_lock, flags); +} + +/* The user yanked out the cable... */ +static void msi3101_disconnect(struct usb_interface *intf) +{ + struct v4l2_device *v = usb_get_intfdata(intf); + struct msi3101_state *s = + container_of(v, struct msi3101_state, v4l2_dev); + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + mutex_lock(&s->vb_queue_lock); + mutex_lock(&s->v4l2_lock); + /* No need to keep the urbs around after disconnection */ + s->udev = NULL; + v4l2_device_disconnect(&s->v4l2_dev); + video_unregister_device(&s->vdev); + spi_unregister_master(s->master); + mutex_unlock(&s->v4l2_lock); + mutex_unlock(&s->vb_queue_lock); + + v4l2_device_put(&s->v4l2_dev); +} + +static int msi3101_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + struct msi3101_state *s = video_drvdata(file); + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver)); + 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_SDR_CAPTURE | V4L2_CAP_STREAMING | + 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, + unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[]) +{ + struct msi3101_state *s = vb2_get_drv_priv(vq); + dev_dbg(&s->udev->dev, "%s: *nbuffers=%d\n", __func__, *nbuffers); + + /* Absolute min and max number of buffers available for mmap() */ + *nbuffers = clamp_t(unsigned int, *nbuffers, 8, 32); + *nplanes = 1; + sizes[0] = PAGE_ALIGN(s->buffersize); + dev_dbg(&s->udev->dev, "%s: nbuffers=%d sizes[0]=%d\n", + __func__, *nbuffers, sizes[0]); + return 0; +} + +static void msi3101_buf_queue(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); + unsigned long flags = 0; + + /* Check the device has not disconnected between prep and queuing */ + if (unlikely(!s->udev)) { + vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR); + return; + } + + spin_lock_irqsave(&s->queued_bufs_lock, flags); + list_add_tail(&buf->list, &s->queued_bufs); + spin_unlock_irqrestore(&s->queued_bufs_lock, flags); +} + +#define CMD_WREG 0x41 +#define CMD_START_STREAMING 0x43 +#define CMD_STOP_STREAMING 0x45 +#define CMD_READ_UNKNOW 0x48 + +#define msi3101_dbg_usb_control_msg(udev, r, t, v, _i, b, l) { \ + char *direction; \ + if (t == (USB_TYPE_VENDOR | USB_DIR_OUT)) \ + direction = ">>>"; \ + else \ + direction = "<<<"; \ + dev_dbg(&udev->dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x " \ + "%s %*ph\n", __func__, t, r, v & 0xff, v >> 8, \ + _i & 0xff, _i >> 8, l & 0xff, l >> 8, direction, l, b); \ +} + +static int msi3101_ctrl_msg(struct msi3101_state *s, u8 cmd, u32 data) +{ + int ret; + u8 request = cmd; + u8 requesttype = USB_DIR_OUT | USB_TYPE_VENDOR; + u16 value = (data >> 0) & 0xffff; + u16 index = (data >> 16) & 0xffff; + + msi3101_dbg_usb_control_msg(s->udev, + request, requesttype, value, index, NULL, 0); + + ret = usb_control_msg(s->udev, usb_sndctrlpipe(s->udev, 0), + request, requesttype, value, index, NULL, 0, 2000); + + if (ret) + dev_err(&s->udev->dev, "%s: failed %d, cmd %02x, data %04x\n", + __func__, ret, cmd, data); + + return ret; +}; + +#define F_REF 24000000 +#define DIV_R_IN 2 +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; + struct v4l2_ctrl *bandwidth_auto; + struct v4l2_ctrl *bandwidth; + + f_sr = s->f_adc; + + /* set tuner, subdev, filters according to sampling rate */ + bandwidth_auto = v4l2_ctrl_find(&s->hdl, V4L2_CID_RF_TUNER_BANDWIDTH_AUTO); + if (v4l2_ctrl_g_ctrl(bandwidth_auto)) { + bandwidth = v4l2_ctrl_find(&s->hdl, V4L2_CID_RF_TUNER_BANDWIDTH); + v4l2_ctrl_s_ctrl(bandwidth, s->f_adc); + } + + /* select stream format */ + switch (s->pixelformat) { + case V4L2_SDR_FMT_CU8: + s->convert_stream = msi3101_convert_stream_504_u8; + reg7 = 0x000c9407; + break; + case V4L2_SDR_FMT_CU16LE: + s->convert_stream = msi3101_convert_stream_252_u16; + reg7 = 0x00009407; + break; + case V4L2_SDR_FMT_CS8: + s->convert_stream = msi3101_convert_stream_504; + reg7 = 0x000c9407; + break; + case V4L2_PIX_FMT_SDR_MSI2500_384: + s->convert_stream = msi3101_convert_stream_384; + reg7 = 0x0000a507; + break; + case V4L2_PIX_FMT_SDR_S12: + s->convert_stream = msi3101_convert_stream_336; + reg7 = 0x00008507; + break; + case V4L2_SDR_FMT_CS14LE: + s->convert_stream = msi3101_convert_stream_252; + reg7 = 0x00009407; + break; + default: + s->convert_stream = msi3101_convert_stream_504_u8; + reg7 = 0x000c9407; + break; + } + + /* + * Synthesizer config is just a educated guess... + * + * [7:0] 0x03, register address + * [8] 1, power control + * [9] ?, power control + * [12:10] output divider + * [13] 0 ? + * [14] 0 ? + * [15] fractional MSB, bit 20 + * [16:19] N + * [23:20] ? + * [24:31] 0x01 + * + * output divider + * val div + * 0 - (invalid) + * 1 4 + * 2 6 + * 3 8 + * 4 10 + * 5 12 + * 6 14 + * 7 16 + * + * VCO 202000000 - 720000000++ + */ + reg3 = 0x01000303; + reg4 = 0x00000004; + + /* XXX: Filters? AGC? */ + if (f_sr < 6000000) + reg3 |= 0x1 << 20; + else if (f_sr < 7000000) + reg3 |= 0x5 << 20; + else if (f_sr < 8500000) + reg3 |= 0x9 << 20; + else + reg3 |= 0xd << 20; + + for (div_r_out = 4; div_r_out < 16; div_r_out += 2) { + f_vco = f_sr * div_r_out * 12; + dev_dbg(&s->udev->dev, "%s: div_r_out=%d f_vco=%d\n", + __func__, div_r_out, f_vco); + if (f_vco >= 202000000) + break; + } + + div_n = f_vco / (F_REF * DIV_R_IN); + div_m = f_vco % (F_REF * DIV_R_IN); + fract = 0x200000ul * div_m / (F_REF * DIV_R_IN); + + reg3 |= div_n << 16; + reg3 |= (div_r_out / 2 - 1) << 10; + reg3 |= ((fract >> 20) & 0x000001) << 15; /* [20] */ + reg4 |= ((fract >> 0) & 0x0fffff) << 8; /* [19:0] */ + + dev_dbg(&s->udev->dev, + "%s: f_sr=%d f_vco=%d div_n=%d div_m=%d div_r_out=%d reg3=%08x reg4=%08x\n", + __func__, f_sr, f_vco, div_n, div_m, div_r_out, reg3, reg4); + + ret = msi3101_ctrl_msg(s, CMD_WREG, 0x00608008); + if (ret) + goto err; + + ret = msi3101_ctrl_msg(s, CMD_WREG, 0x00000c05); + if (ret) + goto err; + + ret = msi3101_ctrl_msg(s, CMD_WREG, 0x00020000); + if (ret) + goto err; + + ret = msi3101_ctrl_msg(s, CMD_WREG, 0x00480102); + if (ret) + goto err; + + ret = msi3101_ctrl_msg(s, CMD_WREG, 0x00f38008); + if (ret) + goto err; + + ret = msi3101_ctrl_msg(s, CMD_WREG, reg7); + if (ret) + goto err; + + ret = msi3101_ctrl_msg(s, CMD_WREG, reg4); + if (ret) + goto err; + + ret = msi3101_ctrl_msg(s, CMD_WREG, reg3); + if (ret) + goto err; +err: + return ret; +}; + +static int msi3101_start_streaming(struct vb2_queue *vq, unsigned int count) +{ + struct msi3101_state *s = vb2_get_drv_priv(vq); + int ret; + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + if (!s->udev) + return -ENODEV; + + if (mutex_lock_interruptible(&s->v4l2_lock)) + return -ERESTARTSYS; + + /* wake-up tuner */ + v4l2_subdev_call(s->v4l2_subdev, core, s_power, 1); + + ret = msi3101_set_usb_adc(s); + + ret = msi3101_isoc_init(s); + if (ret) + msi3101_cleanup_queued_bufs(s); + + ret = msi3101_ctrl_msg(s, CMD_START_STREAMING, 0); + + mutex_unlock(&s->v4l2_lock); + + return ret; +} + +static void msi3101_stop_streaming(struct vb2_queue *vq) +{ + struct msi3101_state *s = vb2_get_drv_priv(vq); + + dev_dbg(&s->udev->dev, "%s:\n", __func__); + + mutex_lock(&s->v4l2_lock); + + if (s->udev) + msi3101_isoc_cleanup(s); + + msi3101_cleanup_queued_bufs(s); + + /* according to tests, at least 700us delay is required */ + msleep(20); + if (!msi3101_ctrl_msg(s, CMD_STOP_STREAMING, 0)) { + /* sleep USB IF / ADC */ + msi3101_ctrl_msg(s, CMD_WREG, 0x01000003); + } + + /* sleep tuner */ + v4l2_subdev_call(s->v4l2_subdev, core, s_power, 0); + + mutex_unlock(&s->v4l2_lock); +} + +static struct vb2_ops msi3101_vb2_ops = { + .queue_setup = msi3101_queue_setup, + .buf_queue = msi3101_buf_queue, + .start_streaming = msi3101_start_streaming, + .stop_streaming = msi3101_stop_streaming, + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, +}; + +static int msi3101_enum_fmt_sdr_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + struct msi3101_state *s = video_drvdata(file); + dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, f->index); + + if (f->index >= s->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_sdr_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct msi3101_state *s = video_drvdata(file); + dev_dbg(&s->udev->dev, "%s: pixelformat fourcc %4.4s\n", __func__, + (char *)&s->pixelformat); + + f->fmt.sdr.pixelformat = s->pixelformat; + f->fmt.sdr.buffersize = s->buffersize; + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); + + return 0; +} + +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.sdr.pixelformat); + + if (vb2_is_busy(q)) + return -EBUSY; + + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); + for (i = 0; i < s->num_formats; i++) { + if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { + s->pixelformat = formats[i].pixelformat; + s->buffersize = formats[i].buffersize; + f->fmt.sdr.buffersize = formats[i].buffersize; + return 0; + } + } + + s->pixelformat = formats[0].pixelformat; + s->buffersize = formats[0].buffersize; + f->fmt.sdr.pixelformat = formats[0].pixelformat; + f->fmt.sdr.buffersize = formats[0].buffersize; + + return 0; +} + +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.sdr.pixelformat); + + memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved)); + for (i = 0; i < s->num_formats; i++) { + if (formats[i].pixelformat == f->fmt.sdr.pixelformat) { + f->fmt.sdr.buffersize = formats[i].buffersize; + return 0; + } + } + + f->fmt.sdr.pixelformat = formats[0].pixelformat; + f->fmt.sdr.buffersize = formats[0].buffersize; + + return 0; +} + +static int msi3101_s_tuner(struct file *file, void *priv, + const struct v4l2_tuner *v) +{ + struct msi3101_state *s = video_drvdata(file); + int ret; + dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index); + + if (v->index == 0) + ret = 0; + else if (v->index == 1) + ret = v4l2_subdev_call(s->v4l2_subdev, tuner, s_tuner, v); + else + ret = -EINVAL; + + return ret; +} + +static int msi3101_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) +{ + struct msi3101_state *s = video_drvdata(file); + int ret; + dev_dbg(&s->udev->dev, "%s: index=%d\n", __func__, v->index); + + if (v->index == 0) { + strlcpy(v->name, "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; + ret = 0; + } else if (v->index == 1) { + ret = v4l2_subdev_call(s->v4l2_subdev, tuner, g_tuner, v); + } else { + ret = -EINVAL; + } + + return ret; +} + +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; + ret = 0; + } else if (f->tuner == 1) { + f->type = V4L2_TUNER_RF; + ret = v4l2_subdev_call(s->v4l2_subdev, tuner, g_frequency, f); + } else { + ret = -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); + 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) { + s->f_adc = clamp_t(unsigned int, f->frequency, + bands[0].rangelow, + bands[0].rangehigh); + 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) { + ret = v4l2_subdev_call(s->v4l2_subdev, tuner, s_frequency, f); + } else { + ret = -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); + int ret; + 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)) { + ret = -EINVAL; + } else { + *band = bands[band->index]; + ret = 0; + } + } else if (band->tuner == 1) { + ret = v4l2_subdev_call(s->v4l2_subdev, tuner, + enum_freq_bands, band); + } else { + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ioctl_ops msi3101_ioctl_ops = { + .vidioc_querycap = msi3101_querycap, + + .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_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + + .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, + .vidioc_log_status = v4l2_ctrl_log_status, +}; + +static const struct v4l2_file_operations msi3101_fops = { + .owner = THIS_MODULE, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .read = vb2_fop_read, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, + .unlocked_ioctl = video_ioctl2, +}; + +static struct video_device msi3101_template = { + .name = "Mirics MSi3101 SDR Dongle", + .release = video_device_release_empty, + .fops = &msi3101_fops, + .ioctl_ops = &msi3101_ioctl_ops, +}; + +static void msi3101_video_release(struct v4l2_device *v) +{ + struct msi3101_state *s = + container_of(v, struct msi3101_state, v4l2_dev); + + v4l2_ctrl_handler_free(&s->hdl); + v4l2_device_unregister(&s->v4l2_dev); + kfree(s); +} + +static int msi3101_transfer_one_message(struct spi_master *master, + struct spi_message *m) +{ + struct msi3101_state *s = spi_master_get_devdata(master); + struct spi_transfer *t; + int ret = 0; + u32 data; + + list_for_each_entry(t, &m->transfers, transfer_list) { + dev_dbg(&s->udev->dev, "%s: msg=%*ph\n", + __func__, t->len, t->tx_buf); + data = 0x09; /* reg 9 is SPI adapter */ + data |= ((u8 *)t->tx_buf)[0] << 8; + data |= ((u8 *)t->tx_buf)[1] << 16; + data |= ((u8 *)t->tx_buf)[2] << 24; + ret = msi3101_ctrl_msg(s, CMD_WREG, data); + } + + m->status = ret; + spi_finalize_current_message(master); + return ret; +} + +static int msi3101_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct msi3101_state *s = NULL; + struct v4l2_subdev *sd; + struct spi_master *master; + int ret; + static struct spi_board_info board_info = { + .modalias = "msi001", + .bus_num = 0, + .chip_select = 0, + .max_speed_hz = 12000000, + }; + + s = kzalloc(sizeof(struct msi3101_state), GFP_KERNEL); + if (s == NULL) { + pr_err("Could not allocate memory for msi3101_state\n"); + return -ENOMEM; + } + + mutex_init(&s->v4l2_lock); + mutex_init(&s->vb_queue_lock); + spin_lock_init(&s->queued_bufs_lock); + INIT_LIST_HEAD(&s->queued_bufs); + s->udev = udev; + s->f_adc = bands[0].rangelow; + s->pixelformat = formats[0].pixelformat; + s->buffersize = formats[0].buffersize; + s->num_formats = NUM_FORMATS; + if (msi3101_emulated_fmt == false) + s->num_formats -= 2; + + /* Init videobuf2 queue structure */ + 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); + s->vb_queue.ops = &msi3101_vb2_ops; + s->vb_queue.mem_ops = &vb2_vmalloc_memops; + s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + ret = vb2_queue_init(&s->vb_queue); + if (ret) { + dev_err(&s->udev->dev, "Could not initialize vb2 queue\n"); + goto err_free_mem; + } + + /* Init video_device structure */ + s->vdev = msi3101_template; + s->vdev.queue = &s->vb_queue; + s->vdev.queue->lock = &s->vb_queue_lock; + video_set_drvdata(&s->vdev, s); + + /* Register the v4l2_device structure */ + s->v4l2_dev.release = msi3101_video_release; + ret = v4l2_device_register(&intf->dev, &s->v4l2_dev); + if (ret) { + dev_err(&s->udev->dev, + "Failed to register v4l2-device (%d)\n", ret); + goto err_free_mem; + } + + /* SPI master adapter */ + master = spi_alloc_master(&s->udev->dev, 0); + if (master == NULL) { + ret = -ENOMEM; + goto err_unregister_v4l2_dev; + } + + s->master = master; + master->bus_num = 0; + master->num_chipselect = 1; + master->transfer_one_message = msi3101_transfer_one_message; + spi_master_set_devdata(master, s); + ret = spi_register_master(master); + if (ret) { + spi_master_put(master); + goto err_unregister_v4l2_dev; + } + + /* load v4l2 subdevice */ + sd = v4l2_spi_new_subdev(&s->v4l2_dev, master, &board_info); + s->v4l2_subdev = sd; + if (sd == NULL) { + dev_err(&s->udev->dev, "cannot get v4l2 subdevice\n"); + ret = -ENODEV; + goto err_unregister_master; + } + + /* Register controls */ + v4l2_ctrl_handler_init(&s->hdl, 0); + if (s->hdl.error) { + ret = s->hdl.error; + dev_err(&s->udev->dev, "Could not initialize controls\n"); + goto err_free_controls; + } + + /* currently all controls are from subdev */ + v4l2_ctrl_add_handler(&s->hdl, sd->ctrl_handler, NULL); + + s->v4l2_dev.ctrl_handler = &s->hdl; + s->vdev.v4l2_dev = &s->v4l2_dev; + s->vdev.lock = &s->v4l2_lock; + + ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1); + if (ret) { + dev_err(&s->udev->dev, + "Failed to register as video device (%d)\n", + ret); + goto err_unregister_v4l2_dev; + } + dev_info(&s->udev->dev, "Registered as %s\n", + video_device_node_name(&s->vdev)); + dev_notice(&s->udev->dev, + "%s: SDR API is still slightly experimental and functionality changes may follow\n", + KBUILD_MODNAME); + + return 0; + +err_free_controls: + v4l2_ctrl_handler_free(&s->hdl); +err_unregister_master: + spi_unregister_master(s->master); +err_unregister_v4l2_dev: + v4l2_device_unregister(&s->v4l2_dev); +err_free_mem: + kfree(s); + return ret; +} + +/* USB device ID list */ +static struct usb_device_id msi3101_id_table[] = { + { USB_DEVICE(0x1df7, 0x2500) }, /* Mirics MSi3101 SDR Dongle */ + { USB_DEVICE(0x2040, 0xd300) }, /* Hauppauge WinTV 133559 LF */ + { } +}; +MODULE_DEVICE_TABLE(usb, msi3101_id_table); + +/* USB subsystem interface */ +static struct usb_driver msi3101_driver = { + .name = KBUILD_MODNAME, + .probe = msi3101_probe, + .disconnect = msi3101_disconnect, + .id_table = msi3101_id_table, +}; + +module_usb_driver(msi3101_driver); + +MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>"); +MODULE_DESCRIPTION("Mirics MSi3101 SDR Dongle"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c index 7c280f35eea9..1b158f1167ed 100644 --- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c +++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c @@ -951,15 +951,9 @@ static long pvr2_v4l2_ioctl(struct file *file, if (ret < 0) { if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) { pvr2_trace(PVR2_TRACE_V4LIOCTL, - "pvr2_v4l2_do_ioctl failure, ret=%ld", ret); - } else { - if (pvrusb2_debug & PVR2_TRACE_V4LIOCTL) { - pvr2_trace(PVR2_TRACE_V4LIOCTL, - "pvr2_v4l2_do_ioctl failure, ret=%ld" - " command was:", ret); - v4l_printk_ioctl(pvr2_hdw_get_driver_name(hdw), - cmd); - } + "pvr2_v4l2_do_ioctl failure, ret=%ld" + " command was:", ret); + v4l_printk_ioctl(pvr2_hdw_get_driver_name(hdw), cmd); } } else { pvr2_trace(PVR2_TRACE_V4LIOCTL, diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c index a73b0bced96f..15b754da4a2c 100644 --- a/drivers/media/usb/pwc/pwc-if.c +++ b/drivers/media/usb/pwc/pwc-if.c @@ -1013,7 +1013,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id strcpy(pdev->vdev.name, name); pdev->vdev.queue = &pdev->vb_queue; pdev->vdev.queue->lock = &pdev->vb_queue_lock; - set_bit(V4L2_FL_USE_FH_PRIO, &pdev->vdev.flags); video_set_drvdata(&pdev->vdev, pdev); pdev->release = le16_to_cpu(udev->descriptor.bcdDevice); diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c index a44466bc7b86..2c901861034a 100644 --- a/drivers/media/usb/s2255/s2255drv.c +++ b/drivers/media/usb/s2255/s2255drv.c @@ -1676,7 +1676,6 @@ static int s2255_probe_v4l(struct s2255_dev *dev) vc->vdev.ctrl_handler = &vc->hdl; vc->vdev.lock = &dev->lock; vc->vdev.v4l2_dev = &dev->v4l2_dev; - set_bit(V4L2_FL_USE_FH_PRIO, &vc->vdev.flags); video_set_drvdata(&vc->vdev, vc); if (video_nr == -1) ret = video_register_device(&vc->vdev, diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c index 5461341a31cb..233054311a62 100644 --- a/drivers/media/usb/stk1160/stk1160-v4l.c +++ b/drivers/media/usb/stk1160/stk1160-v4l.c @@ -671,7 +671,6 @@ int stk1160_video_register(struct stk1160 *dev) /* This will be used to set video_device parent */ dev->vdev.v4l2_dev = &dev->v4l2_dev; - set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags); /* NTSC is default */ dev->norm = V4L2_STD_NTSC_M; diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c index be77482c3070..3588dc38db87 100644 --- a/drivers/media/usb/stkwebcam/stk-webcam.c +++ b/drivers/media/usb/stkwebcam/stk-webcam.c @@ -923,7 +923,6 @@ static int stk_vidioc_g_fmt_vid_cap(struct file *filp, pix_format->bytesperline = 2 * pix_format->width; pix_format->sizeimage = pix_format->bytesperline * pix_format->height; - pix_format->priv = 0; return 0; } @@ -967,7 +966,6 @@ static int stk_try_fmt_vid_cap(struct file *filp, fmtd->fmt.pix.bytesperline = 2 * fmtd->fmt.pix.width; fmtd->fmt.pix.sizeimage = fmtd->fmt.pix.bytesperline * fmtd->fmt.pix.height; - fmtd->fmt.pix.priv = 0; return 0; } @@ -1266,7 +1264,6 @@ static int stk_register_video_device(struct stk_camera *dev) dev->vdev.lock = &dev->lock; dev->vdev.debug = debug; dev->vdev.v4l2_dev = &dev->v4l2_dev; - set_bit(V4L2_FL_USE_FH_PRIO, &dev->vdev.flags); video_set_drvdata(&dev->vdev, dev); err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1); if (err) diff --git a/drivers/media/usb/tlg2300/pd-main.c b/drivers/media/usb/tlg2300/pd-main.c index 3316caa4733b..b31f4791b8ff 100644 --- a/drivers/media/usb/tlg2300/pd-main.c +++ b/drivers/media/usb/tlg2300/pd-main.c @@ -476,6 +476,8 @@ err_audio: err_video: v4l2_device_unregister(&pd->v4l2_dev); err_v4l2: + usb_put_intf(pd->interface); + usb_put_dev(pd->udev); kfree(pd); return ret; } diff --git a/drivers/media/usb/tlg2300/pd-radio.c b/drivers/media/usb/tlg2300/pd-radio.c index ea6070ba835e..b391194a840c 100644 --- a/drivers/media/usb/tlg2300/pd-radio.c +++ b/drivers/media/usb/tlg2300/pd-radio.c @@ -327,7 +327,6 @@ int poseidon_fm_init(struct poseidon *p) } vfd->v4l2_dev = &p->v4l2_dev; vfd->ctrl_handler = hdl; - set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); video_set_drvdata(vfd, p); return video_register_device(vfd, VFL_TYPE_RADIO, -1); } diff --git a/drivers/media/usb/tlg2300/pd-video.c b/drivers/media/usb/tlg2300/pd-video.c index 8df668d06552..8cd7f02fcf9f 100644 --- a/drivers/media/usb/tlg2300/pd-video.c +++ b/drivers/media/usb/tlg2300/pd-video.c @@ -1321,7 +1321,6 @@ static void init_video_context(struct running_context *context) .bytesperline = 720 * 2, .sizeimage = 720 * 576 * 2, .colorspace = V4L2_COLORSPACE_SMPTE170M, - .priv = 0 }; } diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c index e6b3d5d83d43..793577fc4633 100644 --- a/drivers/media/usb/tm6000/tm6000-video.c +++ b/drivers/media/usb/tm6000/tm6000-video.c @@ -918,7 +918,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, (f->fmt.pix.width * fh->fmt->depth) >> 3; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; - f->fmt.pix.priv = 0; return 0; } @@ -959,7 +958,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.width &= ~0x01; f->fmt.pix.field = field; - f->fmt.pix.priv = 0; f->fmt.pix.bytesperline = (f->fmt.pix.width * fmt->depth) >> 3; @@ -1626,7 +1624,6 @@ static struct video_device *vdev_init(struct tm6000_core *dev, vfd->release = video_device_release; vfd->debug = tm6000_debug; vfd->lock = &dev->lock; - set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags); snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name); diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c index 2f87ddfa469f..473fab81b602 100644 --- a/drivers/media/usb/usbtv/usbtv-core.c +++ b/drivers/media/usb/usbtv/usbtv-core.c @@ -91,6 +91,8 @@ static int usbtv_probe(struct usb_interface *intf, return 0; usbtv_video_fail: + usb_set_intfdata(intf, NULL); + usb_put_dev(usbtv->udev); kfree(usbtv); return ret; diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c index 2967e808408b..030c5854b4b3 100644 --- a/drivers/media/usb/usbtv/usbtv-video.c +++ b/drivers/media/usb/usbtv/usbtv-video.c @@ -701,7 +701,6 @@ int usbtv_video_init(struct usbtv *usbtv) usbtv->vdev.tvnorms = USBTV_TV_STD; usbtv->vdev.queue = &usbtv->vb2q; usbtv->vdev.lock = &usbtv->v4l2_lock; - set_bit(V4L2_FL_USE_FH_PRIO, &usbtv->vdev.flags); video_set_drvdata(&usbtv->vdev, usbtv); ret = video_register_device(&usbtv->vdev, VFL_TYPE_GRABBER, -1); if (ret < 0) { diff --git a/drivers/media/usb/usbvision/usbvision-core.c b/drivers/media/usb/usbvision/usbvision-core.c index 816b1cffab7d..302aa07c458f 100644 --- a/drivers/media/usb/usbvision/usbvision-core.c +++ b/drivers/media/usb/usbvision/usbvision-core.c @@ -1463,8 +1463,6 @@ static int usbvision_write_reg_irq(struct usb_usbvision *usbvision, int address, static int usbvision_init_compression(struct usb_usbvision *usbvision) { - int err_code = 0; - usbvision->last_isoc_frame_num = -1; usbvision->isoc_data_count = 0; usbvision->isoc_packet_count = 0; @@ -1475,7 +1473,7 @@ static int usbvision_init_compression(struct usb_usbvision *usbvision) usbvision->request_intra = 1; usbvision->isoc_measure_bandwidth_count = 0; - return err_code; + return 0; } /* this function measures the used bandwidth since last call @@ -1484,11 +1482,9 @@ static int usbvision_init_compression(struct usb_usbvision *usbvision) */ static int usbvision_measure_bandwidth(struct usb_usbvision *usbvision) { - int err_code = 0; - if (usbvision->isoc_measure_bandwidth_count < 2) { /* this gives an average bandwidth of 3 frames */ usbvision->isoc_measure_bandwidth_count++; - return err_code; + return 0; } if ((usbvision->isoc_packet_size > 0) && (usbvision->isoc_packet_count > 0)) { usbvision->used_bandwidth = usbvision->isoc_data_count / @@ -1499,7 +1495,7 @@ static int usbvision_measure_bandwidth(struct usb_usbvision *usbvision) usbvision->isoc_data_count = 0; usbvision->isoc_packet_count = 0; usbvision->isoc_skip_count = 0; - return err_code; + return 0; } static int usbvision_adjust_compression(struct usb_usbvision *usbvision) @@ -1546,26 +1542,24 @@ static int usbvision_adjust_compression(struct usb_usbvision *usbvision) static int usbvision_request_intra(struct usb_usbvision *usbvision) { - int err_code = 0; unsigned char buffer[1]; PDEBUG(DBG_IRQ, ""); usbvision->request_intra = 1; buffer[0] = 1; usbvision_write_reg_irq(usbvision, USBVISION_FORCE_INTRA, buffer, 1); - return err_code; + return 0; } static int usbvision_unrequest_intra(struct usb_usbvision *usbvision) { - int err_code = 0; unsigned char buffer[1]; PDEBUG(DBG_IRQ, ""); usbvision->request_intra = 0; buffer[0] = 0; usbvision_write_reg_irq(usbvision, USBVISION_FORCE_INTRA, buffer, 1); - return err_code; + return 0; } /******************************* diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index ad47c5cb539a..f8135f4e3b52 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -1746,7 +1746,6 @@ static int uvc_register_video(struct uvc_device *dev, vdev->fops = &uvc_fops; vdev->release = uvc_release; vdev->prio = &stream->chain->prio; - set_bit(V4L2_FL_USE_FH_PRIO, &vdev->flags); if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) vdev->vfl_dir = VFL_DIR_TX; strlcpy(vdev->name, dev->name, sizeof vdev->name); diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c index 74d56df3347f..5c006277b8b1 100644 --- a/drivers/media/usb/zr364xx/zr364xx.c +++ b/drivers/media/usb/zr364xx/zr364xx.c @@ -806,7 +806,6 @@ static int zr364xx_vidioc_try_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.bytesperline = f->fmt.pix.width * 2; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; - f->fmt.pix.priv = 0; DBG("%s: V4L2_PIX_FMT_%s (%d) ok!\n", __func__, decode_fourcc(f->fmt.pix.pixelformat, pixelformat_name), f->fmt.pix.field); @@ -829,7 +828,6 @@ static int zr364xx_vidioc_g_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.bytesperline = f->fmt.pix.width * 2; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; - f->fmt.pix.priv = 0; return 0; } @@ -866,7 +864,6 @@ static int zr364xx_vidioc_s_fmt_vid_cap(struct file *file, void *priv, f->fmt.pix.bytesperline = f->fmt.pix.width * 2; f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG; - f->fmt.pix.priv = 0; cam->vb_vidq.field = f->fmt.pix.field; if (f->fmt.pix.width == 160 && f->fmt.pix.height == 120) @@ -1456,7 +1453,6 @@ static int zr364xx_probe(struct usb_interface *intf, cam->vdev.lock = &cam->lock; cam->vdev.v4l2_dev = &cam->v4l2_dev; cam->vdev.ctrl_handler = &cam->ctrl_handler; - set_bit(V4L2_FL_USE_FH_PRIO, &cam->vdev.flags); video_set_drvdata(&cam->vdev, cam); if (debug) cam->vdev.debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG; |