diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-06 11:27:48 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-02-06 11:27:48 -0800 |
commit | 68c5735eaa5e680e701c9a2d1e3c7880bdf5ab66 (patch) | |
tree | 4f584693638bf257b66a1646cc30d823cacc0a58 /drivers/media/dvb-core/dmxdev.c | |
parent | 2246edfaf88dc368e8671b04afd54412625df60a (diff) | |
parent | 273caa260035c03d89ad63d72d8cd3d9e5c5e3f1 (diff) |
Merge tag 'media/v4.16-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media
Pull media updates from Mauro Carvalho Chehab:
- videobuf2 was moved to a media/common dir, as it is now used by the
DVB subsystem too
- Digital TV core memory mapped support interface
- new sensor driver: ov7740
- several improvements at ddbridge driver
- new V4L2 driver: IPU3 CIO2 CSI-2 receiver unit, found on some Intel
SoCs
- new tuner driver: tda18250
- finally got rid of all LIRC staging drivers
- as we don't have old lirc drivers anymore, restruct the lirc device
code
- add support for UVC metadata
- add a new staging driver for NVIDIA Tegra Video Decoder Engine
- DVB kAPI headers moved to include/media
- synchronize the kAPI and uAPI for the DVB subsystem, removing the gap
for non-legacy APIs
- reduce the kAPI gap for V4L2
- lots of other driver enhancements, cleanups, etc.
* tag 'media/v4.16-2' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (407 commits)
media: v4l2-compat-ioctl32.c: make ctrl_is_pointer work for subdevs
media: v4l2-compat-ioctl32.c: refactor compat ioctl32 logic
media: v4l2-compat-ioctl32.c: don't copy back the result for certain errors
media: v4l2-compat-ioctl32.c: drop pr_info for unknown buffer type
media: v4l2-compat-ioctl32.c: copy clip list in put_v4l2_window32
media: v4l2-compat-ioctl32.c: fix ctrl_is_pointer
media: v4l2-compat-ioctl32.c: copy m.userptr in put_v4l2_plane32
media: v4l2-compat-ioctl32.c: avoid sizeof(type)
media: v4l2-compat-ioctl32.c: move 'helper' functions to __get/put_v4l2_format32
media: v4l2-compat-ioctl32.c: fix the indentation
media: v4l2-compat-ioctl32.c: add missing VIDIOC_PREPARE_BUF
media: v4l2-ioctl.c: don't copy back the result for -ENOTTY
media: v4l2-ioctl.c: use check_fmt for enum/g/s/try_fmt
media: vivid: fix module load error when enabling fb and no_error_inj=1
media: dvb_demux: improve debug messages
media: dvb_demux: Better handle discontinuity errors
media: cxusb, dib0700: ignore XC2028_I2C_FLUSH
media: ts2020: avoid integer overflows on 32 bit machines
media: i2c: ov7740: use gpio/consumer.h instead of gpio.h
media: entity: Add a nop variant of media_entity_cleanup
...
Diffstat (limited to 'drivers/media/dvb-core/dmxdev.c')
-rw-r--r-- | drivers/media/dvb-core/dmxdev.c | 232 |
1 files changed, 211 insertions, 21 deletions
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c index 3fe0eb740a6d..bc198f84b9cd 100644 --- a/drivers/media/dvb-core/dmxdev.c +++ b/drivers/media/dvb-core/dmxdev.c @@ -27,7 +27,8 @@ #include <linux/ioctl.h> #include <linux/wait.h> #include <linux/uaccess.h> -#include "dmxdev.h" +#include <media/dmxdev.h> +#include <media/dvb_vb2.h> static int debug; @@ -127,6 +128,11 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv; struct dmx_frontend *front; +#ifndef DVB_MMAP + bool need_ringbuffer = false; +#else + const bool need_ringbuffer = true; +#endif dprintk("%s\n", __func__); @@ -138,14 +144,19 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) return -ENODEV; } +#ifndef DVB_MMAP + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + need_ringbuffer = true; +#else if ((file->f_flags & O_ACCMODE) == O_RDWR) { if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) { mutex_unlock(&dmxdev->mutex); return -EOPNOTSUPP; } } +#endif - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + if (need_ringbuffer) { void *mem; if (!dvbdev->readers) { @@ -158,6 +169,8 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) return -ENOMEM; } dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE); + dvb_vb2_init(&dmxdev->dvr_vb2_ctx, "dvr", + file->f_flags & O_NONBLOCK); dvbdev->readers--; } @@ -187,6 +200,11 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) { struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv; +#ifndef DVB_MMAP + bool need_ringbuffer = false; +#else + const bool need_ringbuffer = true; +#endif mutex_lock(&dmxdev->mutex); @@ -195,7 +213,15 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) dmxdev->demux->connect_frontend(dmxdev->demux, dmxdev->dvr_orig_fe); } - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { +#ifndef DVB_MMAP + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + need_ringbuffer = true; +#endif + + if (need_ringbuffer) { + if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx)) + dvb_vb2_stream_off(&dmxdev->dvr_vb2_ctx); + dvb_vb2_release(&dmxdev->dvr_vb2_ctx); dvbdev->readers++; if (dmxdev->dvr_buffer.data) { void *mem = dmxdev->dvr_buffer.data; @@ -359,7 +385,8 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, struct dmxdev_filter *dmxdevfilter = filter->priv; int ret; - if (dmxdevfilter->buffer.error) { + if (!dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx) && + dmxdevfilter->buffer.error) { wake_up(&dmxdevfilter->buffer.queue); return 0; } @@ -370,11 +397,19 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, } del_timer(&dmxdevfilter->timer); dprintk("section callback %*ph\n", 6, buffer1); - ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, - buffer1_len); - if (ret == buffer1_len) { - ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, - buffer2_len); + if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) { + ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx, + buffer1, buffer1_len); + if (ret == buffer1_len) + ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx, + buffer2, buffer2_len); + } else { + ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, + buffer1, buffer1_len); + if (ret == buffer1_len) { + ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, + buffer2, buffer2_len); + } } if (ret < 0) dmxdevfilter->buffer.error = ret; @@ -391,6 +426,9 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, { struct dmxdev_filter *dmxdevfilter = feed->priv; struct dvb_ringbuffer *buffer; +#ifdef DVB_MMAP + struct dvb_vb2_ctx *ctx; +#endif int ret; spin_lock(&dmxdevfilter->dev->lock); @@ -399,19 +437,34 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, return 0; } - if (dmxdevfilter->params.pes.output == DMX_OUT_TAP - || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) + if (dmxdevfilter->params.pes.output == DMX_OUT_TAP || + dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) { buffer = &dmxdevfilter->buffer; - else +#ifdef DVB_MMAP + ctx = &dmxdevfilter->vb2_ctx; +#endif + } else { buffer = &dmxdevfilter->dev->dvr_buffer; - if (buffer->error) { - spin_unlock(&dmxdevfilter->dev->lock); - wake_up(&buffer->queue); - return 0; +#ifdef DVB_MMAP + ctx = &dmxdevfilter->dev->dvr_vb2_ctx; +#endif + } + + if (dvb_vb2_is_streaming(ctx)) { + ret = dvb_vb2_fill_buffer(ctx, buffer1, buffer1_len); + if (ret == buffer1_len) + ret = dvb_vb2_fill_buffer(ctx, buffer2, buffer2_len); + } else { + if (buffer->error) { + spin_unlock(&dmxdevfilter->dev->lock); + wake_up(&buffer->queue); + return 0; + } + ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len); + if (ret == buffer1_len) + ret = dvb_dmxdev_buffer_write(buffer, + buffer2, buffer2_len); } - ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len); - if (ret == buffer1_len) - ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len); if (ret < 0) buffer->error = ret; spin_unlock(&dmxdevfilter->dev->lock); @@ -750,6 +803,8 @@ static int dvb_demux_open(struct inode *inode, struct file *file) file->private_data = dmxdevfilter; dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192); + dvb_vb2_init(&dmxdevfilter->vb2_ctx, "demux_filter", + file->f_flags & O_NONBLOCK); dmxdevfilter->type = DMXDEV_TYPE_NONE; dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); timer_setup(&dmxdevfilter->timer, dvb_dmxdev_filter_timeout, 0); @@ -765,6 +820,10 @@ static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, { mutex_lock(&dmxdev->mutex); mutex_lock(&dmxdevfilter->mutex); + if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) + dvb_vb2_stream_off(&dmxdevfilter->vb2_ctx); + dvb_vb2_release(&dmxdevfilter->vb2_ctx); + dvb_dmxdev_filter_stop(dmxdevfilter); dvb_dmxdev_filter_reset(dmxdevfilter); @@ -1052,6 +1111,54 @@ static int dvb_demux_do_ioctl(struct file *file, mutex_unlock(&dmxdevfilter->mutex); break; +#ifdef DVB_MMAP + case DMX_REQBUFS: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_vb2_reqbufs(&dmxdevfilter->vb2_ctx, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_QUERYBUF: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_vb2_querybuf(&dmxdevfilter->vb2_ctx, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_EXPBUF: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_vb2_expbuf(&dmxdevfilter->vb2_ctx, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_QBUF: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_vb2_qbuf(&dmxdevfilter->vb2_ctx, parg); + if (ret == 0 && !dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) + ret = dvb_vb2_stream_on(&dmxdevfilter->vb2_ctx); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_DQBUF: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_vb2_dqbuf(&dmxdevfilter->vb2_ctx, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; +#endif default: ret = -EINVAL; break; @@ -1073,6 +1180,8 @@ static __poll_t dvb_demux_poll(struct file *file, poll_table *wait) if ((!dmxdevfilter) || dmxdevfilter->dev->exit) return POLLERR; + if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) + return dvb_vb2_poll(&dmxdevfilter->vb2_ctx, file, wait); poll_wait(file, &dmxdevfilter->buffer.queue, wait); @@ -1090,11 +1199,33 @@ static __poll_t dvb_demux_poll(struct file *file, poll_table *wait) return mask; } -static int dvb_demux_release(struct inode *inode, struct file *file) +#ifdef DVB_MMAP +static int dvb_demux_mmap(struct file *file, struct vm_area_struct *vma) { struct dmxdev_filter *dmxdevfilter = file->private_data; struct dmxdev *dmxdev = dmxdevfilter->dev; + int ret; + + if (mutex_lock_interruptible(&dmxdev->mutex)) + return -ERESTARTSYS; + + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_vb2_mmap(&dmxdevfilter->vb2_ctx, vma); + + mutex_unlock(&dmxdevfilter->mutex); + mutex_unlock(&dmxdev->mutex); + return ret; +} +#endif + +static int dvb_demux_release(struct inode *inode, struct file *file) +{ + struct dmxdev_filter *dmxdevfilter = file->private_data; + struct dmxdev *dmxdev = dmxdevfilter->dev; int ret; ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter); @@ -1118,6 +1249,9 @@ static const struct file_operations dvb_demux_fops = { .release = dvb_demux_release, .poll = dvb_demux_poll, .llseek = default_llseek, +#ifdef DVB_MMAP + .mmap = dvb_demux_mmap, +#endif }; static const struct dvb_device dvbdev_demux = { @@ -1146,6 +1280,29 @@ static int dvb_dvr_do_ioctl(struct file *file, ret = dvb_dvr_set_buffer_size(dmxdev, arg); break; +#ifdef DVB_MMAP + case DMX_REQBUFS: + ret = dvb_vb2_reqbufs(&dmxdev->dvr_vb2_ctx, parg); + break; + + case DMX_QUERYBUF: + ret = dvb_vb2_querybuf(&dmxdev->dvr_vb2_ctx, parg); + break; + + case DMX_EXPBUF: + ret = dvb_vb2_expbuf(&dmxdev->dvr_vb2_ctx, parg); + break; + + case DMX_QBUF: + ret = dvb_vb2_qbuf(&dmxdev->dvr_vb2_ctx, parg); + if (ret == 0 && !dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx)) + ret = dvb_vb2_stream_on(&dmxdev->dvr_vb2_ctx); + break; + + case DMX_DQBUF: + ret = dvb_vb2_dqbuf(&dmxdev->dvr_vb2_ctx, parg); + break; +#endif default: ret = -EINVAL; break; @@ -1165,15 +1322,26 @@ static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait) struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv; __poll_t mask = 0; +#ifndef DVB_MMAP + bool need_ringbuffer = false; +#else + const bool need_ringbuffer = true; +#endif dprintk("%s\n", __func__); if (dmxdev->exit) return POLLERR; + if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx)) + return dvb_vb2_poll(&dmxdev->dvr_vb2_ctx, file, wait); poll_wait(file, &dmxdev->dvr_buffer.queue, wait); - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { +#ifndef DVB_MMAP + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + need_ringbuffer = true; +#endif + if (need_ringbuffer) { if (dmxdev->dvr_buffer.error) mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); @@ -1185,6 +1353,25 @@ static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait) return mask; } +#ifdef DVB_MMAP +static int dvb_dvr_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; + int ret; + + if (dmxdev->exit) + return -ENODEV; + + if (mutex_lock_interruptible(&dmxdev->mutex)) + return -ERESTARTSYS; + + ret = dvb_vb2_mmap(&dmxdev->dvr_vb2_ctx, vma); + mutex_unlock(&dmxdev->mutex); + return ret; +} +#endif + static const struct file_operations dvb_dvr_fops = { .owner = THIS_MODULE, .read = dvb_dvr_read, @@ -1194,6 +1381,9 @@ static const struct file_operations dvb_dvr_fops = { .release = dvb_dvr_release, .poll = dvb_dvr_poll, .llseek = default_llseek, +#ifdef DVB_MMAP + .mmap = dvb_dvr_mmap, +#endif }; static const struct dvb_device dvbdev_dvr = { |