18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * dmxdev.c - DVB demultiplexer device 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2000 Ralph Metzler & Marcus Metzler 58c2ecf20Sopenharmony_ci * for convergence integrated media GmbH 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or 88c2ecf20Sopenharmony_ci * modify it under the terms of the GNU Lesser General Public License 98c2ecf20Sopenharmony_ci * as published by the Free Software Foundation; either version 2.1 108c2ecf20Sopenharmony_ci * of the License, or (at your option) any later version. 118c2ecf20Sopenharmony_ci * 128c2ecf20Sopenharmony_ci * This program is distributed in the hope that it will be useful, 138c2ecf20Sopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 148c2ecf20Sopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 158c2ecf20Sopenharmony_ci * GNU General Public License for more details. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define pr_fmt(fmt) "dmxdev: " fmt 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/sched.h> 228c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 238c2ecf20Sopenharmony_ci#include <linux/slab.h> 248c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 258c2ecf20Sopenharmony_ci#include <linux/module.h> 268c2ecf20Sopenharmony_ci#include <linux/poll.h> 278c2ecf20Sopenharmony_ci#include <linux/ioctl.h> 288c2ecf20Sopenharmony_ci#include <linux/wait.h> 298c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 308c2ecf20Sopenharmony_ci#include <media/dmxdev.h> 318c2ecf20Sopenharmony_ci#include <media/dvb_vb2.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic int debug; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 368c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_ci#define dprintk(fmt, arg...) do { \ 398c2ecf20Sopenharmony_ci if (debug) \ 408c2ecf20Sopenharmony_ci printk(KERN_DEBUG pr_fmt("%s: " fmt), \ 418c2ecf20Sopenharmony_ci __func__, ##arg); \ 428c2ecf20Sopenharmony_ci} while (0) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf, 458c2ecf20Sopenharmony_ci const u8 *src, size_t len) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci ssize_t free; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci if (!len) 508c2ecf20Sopenharmony_ci return 0; 518c2ecf20Sopenharmony_ci if (!buf->data) 528c2ecf20Sopenharmony_ci return 0; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci free = dvb_ringbuffer_free(buf); 558c2ecf20Sopenharmony_ci if (len > free) { 568c2ecf20Sopenharmony_ci dprintk("buffer overflow\n"); 578c2ecf20Sopenharmony_ci return -EOVERFLOW; 588c2ecf20Sopenharmony_ci } 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci return dvb_ringbuffer_write(buf, src, len); 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_cistatic ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src, 648c2ecf20Sopenharmony_ci int non_blocking, char __user *buf, 658c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci size_t todo; 688c2ecf20Sopenharmony_ci ssize_t avail; 698c2ecf20Sopenharmony_ci ssize_t ret = 0; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (!src->data) 728c2ecf20Sopenharmony_ci return 0; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci if (src->error) { 758c2ecf20Sopenharmony_ci ret = src->error; 768c2ecf20Sopenharmony_ci dvb_ringbuffer_flush(src); 778c2ecf20Sopenharmony_ci return ret; 788c2ecf20Sopenharmony_ci } 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci for (todo = count; todo > 0; todo -= ret) { 818c2ecf20Sopenharmony_ci if (non_blocking && dvb_ringbuffer_empty(src)) { 828c2ecf20Sopenharmony_ci ret = -EWOULDBLOCK; 838c2ecf20Sopenharmony_ci break; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci ret = wait_event_interruptible(src->queue, 878c2ecf20Sopenharmony_ci !dvb_ringbuffer_empty(src) || 888c2ecf20Sopenharmony_ci (src->error != 0)); 898c2ecf20Sopenharmony_ci if (ret < 0) 908c2ecf20Sopenharmony_ci break; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci if (src->error) { 938c2ecf20Sopenharmony_ci ret = src->error; 948c2ecf20Sopenharmony_ci dvb_ringbuffer_flush(src); 958c2ecf20Sopenharmony_ci break; 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci avail = dvb_ringbuffer_avail(src); 998c2ecf20Sopenharmony_ci if (avail > todo) 1008c2ecf20Sopenharmony_ci avail = todo; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci ret = dvb_ringbuffer_read_user(src, buf, avail); 1038c2ecf20Sopenharmony_ci if (ret < 0) 1048c2ecf20Sopenharmony_ci break; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci buf += ret; 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return (count - todo) ? (count - todo) : ret; 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic struct dmx_frontend *get_fe(struct dmx_demux *demux, int type) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct list_head *head, *pos; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci head = demux->get_frontends(demux); 1178c2ecf20Sopenharmony_ci if (!head) 1188c2ecf20Sopenharmony_ci return NULL; 1198c2ecf20Sopenharmony_ci list_for_each(pos, head) 1208c2ecf20Sopenharmony_ci if (DMX_FE_ENTRY(pos)->source == type) 1218c2ecf20Sopenharmony_ci return DMX_FE_ENTRY(pos); 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci return NULL; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_cistatic int dvb_dvr_open(struct inode *inode, struct file *file) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct dvb_device *dvbdev = file->private_data; 1298c2ecf20Sopenharmony_ci struct dmxdev *dmxdev = dvbdev->priv; 1308c2ecf20Sopenharmony_ci struct dmx_frontend *front; 1318c2ecf20Sopenharmony_ci bool need_ringbuffer = false; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdev->mutex)) 1368c2ecf20Sopenharmony_ci return -ERESTARTSYS; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (dmxdev->exit) { 1398c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 1408c2ecf20Sopenharmony_ci return -ENODEV; 1418c2ecf20Sopenharmony_ci } 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci dmxdev->may_do_mmap = 0; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci /* 1468c2ecf20Sopenharmony_ci * The logic here is a little tricky due to the ifdef. 1478c2ecf20Sopenharmony_ci * 1488c2ecf20Sopenharmony_ci * The ringbuffer is used for both read and mmap. 1498c2ecf20Sopenharmony_ci * 1508c2ecf20Sopenharmony_ci * It is not needed, however, on two situations: 1518c2ecf20Sopenharmony_ci * - Write devices (access with O_WRONLY); 1528c2ecf20Sopenharmony_ci * - For duplex device nodes, opened with O_RDWR. 1538c2ecf20Sopenharmony_ci */ 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci if ((file->f_flags & O_ACCMODE) == O_RDONLY) 1568c2ecf20Sopenharmony_ci need_ringbuffer = true; 1578c2ecf20Sopenharmony_ci else if ((file->f_flags & O_ACCMODE) == O_RDWR) { 1588c2ecf20Sopenharmony_ci if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) { 1598c2ecf20Sopenharmony_ci#ifdef CONFIG_DVB_MMAP 1608c2ecf20Sopenharmony_ci dmxdev->may_do_mmap = 1; 1618c2ecf20Sopenharmony_ci need_ringbuffer = true; 1628c2ecf20Sopenharmony_ci#else 1638c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 1648c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1658c2ecf20Sopenharmony_ci#endif 1668c2ecf20Sopenharmony_ci } 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (need_ringbuffer) { 1708c2ecf20Sopenharmony_ci void *mem; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (!dvbdev->readers) { 1738c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 1748c2ecf20Sopenharmony_ci return -EBUSY; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci mem = vmalloc(DVR_BUFFER_SIZE); 1778c2ecf20Sopenharmony_ci if (!mem) { 1788c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 1798c2ecf20Sopenharmony_ci return -ENOMEM; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE); 1828c2ecf20Sopenharmony_ci if (dmxdev->may_do_mmap) 1838c2ecf20Sopenharmony_ci dvb_vb2_init(&dmxdev->dvr_vb2_ctx, "dvr", 1848c2ecf20Sopenharmony_ci file->f_flags & O_NONBLOCK); 1858c2ecf20Sopenharmony_ci dvbdev->readers--; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci if ((file->f_flags & O_ACCMODE) == O_WRONLY) { 1898c2ecf20Sopenharmony_ci dmxdev->dvr_orig_fe = dmxdev->demux->frontend; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci if (!dmxdev->demux->write) { 1928c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 1938c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 1948c2ecf20Sopenharmony_ci } 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci front = get_fe(dmxdev->demux, DMX_MEMORY_FE); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (!front) { 1998c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 2008c2ecf20Sopenharmony_ci return -EINVAL; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci dmxdev->demux->disconnect_frontend(dmxdev->demux); 2038c2ecf20Sopenharmony_ci dmxdev->demux->connect_frontend(dmxdev->demux, front); 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci dvbdev->users++; 2068c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 2078c2ecf20Sopenharmony_ci return 0; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic int dvb_dvr_release(struct inode *inode, struct file *file) 2118c2ecf20Sopenharmony_ci{ 2128c2ecf20Sopenharmony_ci struct dvb_device *dvbdev = file->private_data; 2138c2ecf20Sopenharmony_ci struct dmxdev *dmxdev = dvbdev->priv; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci mutex_lock(&dmxdev->mutex); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if ((file->f_flags & O_ACCMODE) == O_WRONLY) { 2188c2ecf20Sopenharmony_ci dmxdev->demux->disconnect_frontend(dmxdev->demux); 2198c2ecf20Sopenharmony_ci dmxdev->demux->connect_frontend(dmxdev->demux, 2208c2ecf20Sopenharmony_ci dmxdev->dvr_orig_fe); 2218c2ecf20Sopenharmony_ci } 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci if (((file->f_flags & O_ACCMODE) == O_RDONLY) || 2248c2ecf20Sopenharmony_ci dmxdev->may_do_mmap) { 2258c2ecf20Sopenharmony_ci if (dmxdev->may_do_mmap) { 2268c2ecf20Sopenharmony_ci if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx)) 2278c2ecf20Sopenharmony_ci dvb_vb2_stream_off(&dmxdev->dvr_vb2_ctx); 2288c2ecf20Sopenharmony_ci dvb_vb2_release(&dmxdev->dvr_vb2_ctx); 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci dvbdev->readers++; 2318c2ecf20Sopenharmony_ci if (dmxdev->dvr_buffer.data) { 2328c2ecf20Sopenharmony_ci void *mem = dmxdev->dvr_buffer.data; 2338c2ecf20Sopenharmony_ci /*memory barrier*/ 2348c2ecf20Sopenharmony_ci mb(); 2358c2ecf20Sopenharmony_ci spin_lock_irq(&dmxdev->lock); 2368c2ecf20Sopenharmony_ci dmxdev->dvr_buffer.data = NULL; 2378c2ecf20Sopenharmony_ci spin_unlock_irq(&dmxdev->lock); 2388c2ecf20Sopenharmony_ci vfree(mem); 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci /* TODO */ 2428c2ecf20Sopenharmony_ci dvbdev->users--; 2438c2ecf20Sopenharmony_ci if (dvbdev->users == 1 && dmxdev->exit == 1) { 2448c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 2458c2ecf20Sopenharmony_ci wake_up(&dvbdev->wait_queue); 2468c2ecf20Sopenharmony_ci } else 2478c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci return 0; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic ssize_t dvb_dvr_write(struct file *file, const char __user *buf, 2538c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 2548c2ecf20Sopenharmony_ci{ 2558c2ecf20Sopenharmony_ci struct dvb_device *dvbdev = file->private_data; 2568c2ecf20Sopenharmony_ci struct dmxdev *dmxdev = dvbdev->priv; 2578c2ecf20Sopenharmony_ci int ret; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (!dmxdev->demux->write) 2608c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 2618c2ecf20Sopenharmony_ci if ((file->f_flags & O_ACCMODE) != O_WRONLY) 2628c2ecf20Sopenharmony_ci return -EINVAL; 2638c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdev->mutex)) 2648c2ecf20Sopenharmony_ci return -ERESTARTSYS; 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (dmxdev->exit) { 2678c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 2688c2ecf20Sopenharmony_ci return -ENODEV; 2698c2ecf20Sopenharmony_ci } 2708c2ecf20Sopenharmony_ci ret = dmxdev->demux->write(dmxdev->demux, buf, count); 2718c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 2728c2ecf20Sopenharmony_ci return ret; 2738c2ecf20Sopenharmony_ci} 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_cistatic ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count, 2768c2ecf20Sopenharmony_ci loff_t *ppos) 2778c2ecf20Sopenharmony_ci{ 2788c2ecf20Sopenharmony_ci struct dvb_device *dvbdev = file->private_data; 2798c2ecf20Sopenharmony_ci struct dmxdev *dmxdev = dvbdev->priv; 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (dmxdev->exit) 2828c2ecf20Sopenharmony_ci return -ENODEV; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, 2858c2ecf20Sopenharmony_ci file->f_flags & O_NONBLOCK, 2868c2ecf20Sopenharmony_ci buf, count, ppos); 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev, 2908c2ecf20Sopenharmony_ci unsigned long size) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci struct dvb_ringbuffer *buf = &dmxdev->dvr_buffer; 2938c2ecf20Sopenharmony_ci void *newmem; 2948c2ecf20Sopenharmony_ci void *oldmem; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (buf->size == size) 2998c2ecf20Sopenharmony_ci return 0; 3008c2ecf20Sopenharmony_ci if (!size) 3018c2ecf20Sopenharmony_ci return -EINVAL; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci newmem = vmalloc(size); 3048c2ecf20Sopenharmony_ci if (!newmem) 3058c2ecf20Sopenharmony_ci return -ENOMEM; 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_ci oldmem = buf->data; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci spin_lock_irq(&dmxdev->lock); 3108c2ecf20Sopenharmony_ci buf->data = newmem; 3118c2ecf20Sopenharmony_ci buf->size = size; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci /* reset and not flush in case the buffer shrinks */ 3148c2ecf20Sopenharmony_ci dvb_ringbuffer_reset(buf); 3158c2ecf20Sopenharmony_ci spin_unlock_irq(&dmxdev->lock); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci vfree(oldmem); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci return 0; 3208c2ecf20Sopenharmony_ci} 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_cistatic inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter 3238c2ecf20Sopenharmony_ci *dmxdevfilter, int state) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci spin_lock_irq(&dmxdevfilter->dev->lock); 3268c2ecf20Sopenharmony_ci dmxdevfilter->state = state; 3278c2ecf20Sopenharmony_ci spin_unlock_irq(&dmxdevfilter->dev->lock); 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, 3318c2ecf20Sopenharmony_ci unsigned long size) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci struct dvb_ringbuffer *buf = &dmxdevfilter->buffer; 3348c2ecf20Sopenharmony_ci void *newmem; 3358c2ecf20Sopenharmony_ci void *oldmem; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (buf->size == size) 3388c2ecf20Sopenharmony_ci return 0; 3398c2ecf20Sopenharmony_ci if (!size) 3408c2ecf20Sopenharmony_ci return -EINVAL; 3418c2ecf20Sopenharmony_ci if (dmxdevfilter->state >= DMXDEV_STATE_GO) 3428c2ecf20Sopenharmony_ci return -EBUSY; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci newmem = vmalloc(size); 3458c2ecf20Sopenharmony_ci if (!newmem) 3468c2ecf20Sopenharmony_ci return -ENOMEM; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci oldmem = buf->data; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci spin_lock_irq(&dmxdevfilter->dev->lock); 3518c2ecf20Sopenharmony_ci buf->data = newmem; 3528c2ecf20Sopenharmony_ci buf->size = size; 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci /* reset and not flush in case the buffer shrinks */ 3558c2ecf20Sopenharmony_ci dvb_ringbuffer_reset(buf); 3568c2ecf20Sopenharmony_ci spin_unlock_irq(&dmxdevfilter->dev->lock); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci vfree(oldmem); 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci return 0; 3618c2ecf20Sopenharmony_ci} 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_cistatic void dvb_dmxdev_filter_timeout(struct timer_list *t) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci struct dmxdev_filter *dmxdevfilter = from_timer(dmxdevfilter, t, timer); 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci dmxdevfilter->buffer.error = -ETIMEDOUT; 3688c2ecf20Sopenharmony_ci spin_lock_irq(&dmxdevfilter->dev->lock); 3698c2ecf20Sopenharmony_ci dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT; 3708c2ecf20Sopenharmony_ci spin_unlock_irq(&dmxdevfilter->dev->lock); 3718c2ecf20Sopenharmony_ci wake_up(&dmxdevfilter->buffer.queue); 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci del_timer(&dmxdevfilter->timer); 3798c2ecf20Sopenharmony_ci if (para->timeout) { 3808c2ecf20Sopenharmony_ci dmxdevfilter->timer.expires = 3818c2ecf20Sopenharmony_ci jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000; 3828c2ecf20Sopenharmony_ci add_timer(&dmxdevfilter->timer); 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci} 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_cistatic int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, 3878c2ecf20Sopenharmony_ci const u8 *buffer2, size_t buffer2_len, 3888c2ecf20Sopenharmony_ci struct dmx_section_filter *filter, 3898c2ecf20Sopenharmony_ci u32 *buffer_flags) 3908c2ecf20Sopenharmony_ci{ 3918c2ecf20Sopenharmony_ci struct dmxdev_filter *dmxdevfilter = filter->priv; 3928c2ecf20Sopenharmony_ci int ret; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (!dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx) && 3958c2ecf20Sopenharmony_ci dmxdevfilter->buffer.error) { 3968c2ecf20Sopenharmony_ci wake_up(&dmxdevfilter->buffer.queue); 3978c2ecf20Sopenharmony_ci return 0; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci spin_lock(&dmxdevfilter->dev->lock); 4008c2ecf20Sopenharmony_ci if (dmxdevfilter->state != DMXDEV_STATE_GO) { 4018c2ecf20Sopenharmony_ci spin_unlock(&dmxdevfilter->dev->lock); 4028c2ecf20Sopenharmony_ci return 0; 4038c2ecf20Sopenharmony_ci } 4048c2ecf20Sopenharmony_ci del_timer(&dmxdevfilter->timer); 4058c2ecf20Sopenharmony_ci dprintk("section callback %*ph\n", 6, buffer1); 4068c2ecf20Sopenharmony_ci if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) { 4078c2ecf20Sopenharmony_ci ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx, 4088c2ecf20Sopenharmony_ci buffer1, buffer1_len, 4098c2ecf20Sopenharmony_ci buffer_flags); 4108c2ecf20Sopenharmony_ci if (ret == buffer1_len) 4118c2ecf20Sopenharmony_ci ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx, 4128c2ecf20Sopenharmony_ci buffer2, buffer2_len, 4138c2ecf20Sopenharmony_ci buffer_flags); 4148c2ecf20Sopenharmony_ci } else { 4158c2ecf20Sopenharmony_ci ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, 4168c2ecf20Sopenharmony_ci buffer1, buffer1_len); 4178c2ecf20Sopenharmony_ci if (ret == buffer1_len) { 4188c2ecf20Sopenharmony_ci ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, 4198c2ecf20Sopenharmony_ci buffer2, buffer2_len); 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci } 4228c2ecf20Sopenharmony_ci if (ret < 0) 4238c2ecf20Sopenharmony_ci dmxdevfilter->buffer.error = ret; 4248c2ecf20Sopenharmony_ci if (dmxdevfilter->params.sec.flags & DMX_ONESHOT) 4258c2ecf20Sopenharmony_ci dmxdevfilter->state = DMXDEV_STATE_DONE; 4268c2ecf20Sopenharmony_ci spin_unlock(&dmxdevfilter->dev->lock); 4278c2ecf20Sopenharmony_ci wake_up(&dmxdevfilter->buffer.queue); 4288c2ecf20Sopenharmony_ci return 0; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, 4328c2ecf20Sopenharmony_ci const u8 *buffer2, size_t buffer2_len, 4338c2ecf20Sopenharmony_ci struct dmx_ts_feed *feed, 4348c2ecf20Sopenharmony_ci u32 *buffer_flags) 4358c2ecf20Sopenharmony_ci{ 4368c2ecf20Sopenharmony_ci struct dmxdev_filter *dmxdevfilter = feed->priv; 4378c2ecf20Sopenharmony_ci struct dvb_ringbuffer *buffer; 4388c2ecf20Sopenharmony_ci#ifdef CONFIG_DVB_MMAP 4398c2ecf20Sopenharmony_ci struct dvb_vb2_ctx *ctx; 4408c2ecf20Sopenharmony_ci#endif 4418c2ecf20Sopenharmony_ci int ret; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci spin_lock(&dmxdevfilter->dev->lock); 4448c2ecf20Sopenharmony_ci if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) { 4458c2ecf20Sopenharmony_ci spin_unlock(&dmxdevfilter->dev->lock); 4468c2ecf20Sopenharmony_ci return 0; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci if (dmxdevfilter->params.pes.output == DMX_OUT_TAP || 4508c2ecf20Sopenharmony_ci dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) { 4518c2ecf20Sopenharmony_ci buffer = &dmxdevfilter->buffer; 4528c2ecf20Sopenharmony_ci#ifdef CONFIG_DVB_MMAP 4538c2ecf20Sopenharmony_ci ctx = &dmxdevfilter->vb2_ctx; 4548c2ecf20Sopenharmony_ci#endif 4558c2ecf20Sopenharmony_ci } else { 4568c2ecf20Sopenharmony_ci buffer = &dmxdevfilter->dev->dvr_buffer; 4578c2ecf20Sopenharmony_ci#ifdef CONFIG_DVB_MMAP 4588c2ecf20Sopenharmony_ci ctx = &dmxdevfilter->dev->dvr_vb2_ctx; 4598c2ecf20Sopenharmony_ci#endif 4608c2ecf20Sopenharmony_ci } 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if (dvb_vb2_is_streaming(ctx)) { 4638c2ecf20Sopenharmony_ci ret = dvb_vb2_fill_buffer(ctx, buffer1, buffer1_len, 4648c2ecf20Sopenharmony_ci buffer_flags); 4658c2ecf20Sopenharmony_ci if (ret == buffer1_len) 4668c2ecf20Sopenharmony_ci ret = dvb_vb2_fill_buffer(ctx, buffer2, buffer2_len, 4678c2ecf20Sopenharmony_ci buffer_flags); 4688c2ecf20Sopenharmony_ci } else { 4698c2ecf20Sopenharmony_ci if (buffer->error) { 4708c2ecf20Sopenharmony_ci spin_unlock(&dmxdevfilter->dev->lock); 4718c2ecf20Sopenharmony_ci wake_up(&buffer->queue); 4728c2ecf20Sopenharmony_ci return 0; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len); 4758c2ecf20Sopenharmony_ci if (ret == buffer1_len) 4768c2ecf20Sopenharmony_ci ret = dvb_dmxdev_buffer_write(buffer, 4778c2ecf20Sopenharmony_ci buffer2, buffer2_len); 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci if (ret < 0) 4808c2ecf20Sopenharmony_ci buffer->error = ret; 4818c2ecf20Sopenharmony_ci spin_unlock(&dmxdevfilter->dev->lock); 4828c2ecf20Sopenharmony_ci wake_up(&buffer->queue); 4838c2ecf20Sopenharmony_ci return 0; 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci/* stop feed but only mark the specified filter as stopped (state set) */ 4878c2ecf20Sopenharmony_cistatic int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci struct dmxdev_feed *feed; 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ci dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci switch (dmxdevfilter->type) { 4948c2ecf20Sopenharmony_ci case DMXDEV_TYPE_SEC: 4958c2ecf20Sopenharmony_ci del_timer(&dmxdevfilter->timer); 4968c2ecf20Sopenharmony_ci dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec); 4978c2ecf20Sopenharmony_ci break; 4988c2ecf20Sopenharmony_ci case DMXDEV_TYPE_PES: 4998c2ecf20Sopenharmony_ci list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) 5008c2ecf20Sopenharmony_ci feed->ts->stop_filtering(feed->ts); 5018c2ecf20Sopenharmony_ci break; 5028c2ecf20Sopenharmony_ci default: 5038c2ecf20Sopenharmony_ci return -EINVAL; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci return 0; 5068c2ecf20Sopenharmony_ci} 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci/* start feed associated with the specified filter */ 5098c2ecf20Sopenharmony_cistatic int dvb_dmxdev_feed_start(struct dmxdev_filter *filter) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci struct dmxdev_feed *feed; 5128c2ecf20Sopenharmony_ci int ret; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci switch (filter->type) { 5178c2ecf20Sopenharmony_ci case DMXDEV_TYPE_SEC: 5188c2ecf20Sopenharmony_ci return filter->feed.sec->start_filtering(filter->feed.sec); 5198c2ecf20Sopenharmony_ci case DMXDEV_TYPE_PES: 5208c2ecf20Sopenharmony_ci list_for_each_entry(feed, &filter->feed.ts, next) { 5218c2ecf20Sopenharmony_ci ret = feed->ts->start_filtering(feed->ts); 5228c2ecf20Sopenharmony_ci if (ret < 0) { 5238c2ecf20Sopenharmony_ci dvb_dmxdev_feed_stop(filter); 5248c2ecf20Sopenharmony_ci return ret; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci } 5278c2ecf20Sopenharmony_ci break; 5288c2ecf20Sopenharmony_ci default: 5298c2ecf20Sopenharmony_ci return -EINVAL; 5308c2ecf20Sopenharmony_ci } 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci return 0; 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci/* restart section feed if it has filters left associated with it, 5368c2ecf20Sopenharmony_ci otherwise release the feed */ 5378c2ecf20Sopenharmony_cistatic int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter) 5388c2ecf20Sopenharmony_ci{ 5398c2ecf20Sopenharmony_ci int i; 5408c2ecf20Sopenharmony_ci struct dmxdev *dmxdev = filter->dev; 5418c2ecf20Sopenharmony_ci u16 pid = filter->params.sec.pid; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci for (i = 0; i < dmxdev->filternum; i++) 5448c2ecf20Sopenharmony_ci if (dmxdev->filter[i].state >= DMXDEV_STATE_GO && 5458c2ecf20Sopenharmony_ci dmxdev->filter[i].type == DMXDEV_TYPE_SEC && 5468c2ecf20Sopenharmony_ci dmxdev->filter[i].params.sec.pid == pid) { 5478c2ecf20Sopenharmony_ci dvb_dmxdev_feed_start(&dmxdev->filter[i]); 5488c2ecf20Sopenharmony_ci return 0; 5498c2ecf20Sopenharmony_ci } 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci filter->dev->demux->release_section_feed(dmxdev->demux, 5528c2ecf20Sopenharmony_ci filter->feed.sec); 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci return 0; 5558c2ecf20Sopenharmony_ci} 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_cistatic int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter) 5588c2ecf20Sopenharmony_ci{ 5598c2ecf20Sopenharmony_ci struct dmxdev_feed *feed; 5608c2ecf20Sopenharmony_ci struct dmx_demux *demux; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (dmxdevfilter->state < DMXDEV_STATE_GO) 5638c2ecf20Sopenharmony_ci return 0; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci switch (dmxdevfilter->type) { 5668c2ecf20Sopenharmony_ci case DMXDEV_TYPE_SEC: 5678c2ecf20Sopenharmony_ci if (!dmxdevfilter->feed.sec) 5688c2ecf20Sopenharmony_ci break; 5698c2ecf20Sopenharmony_ci dvb_dmxdev_feed_stop(dmxdevfilter); 5708c2ecf20Sopenharmony_ci if (dmxdevfilter->filter.sec) 5718c2ecf20Sopenharmony_ci dmxdevfilter->feed.sec-> 5728c2ecf20Sopenharmony_ci release_filter(dmxdevfilter->feed.sec, 5738c2ecf20Sopenharmony_ci dmxdevfilter->filter.sec); 5748c2ecf20Sopenharmony_ci dvb_dmxdev_feed_restart(dmxdevfilter); 5758c2ecf20Sopenharmony_ci dmxdevfilter->feed.sec = NULL; 5768c2ecf20Sopenharmony_ci break; 5778c2ecf20Sopenharmony_ci case DMXDEV_TYPE_PES: 5788c2ecf20Sopenharmony_ci dvb_dmxdev_feed_stop(dmxdevfilter); 5798c2ecf20Sopenharmony_ci demux = dmxdevfilter->dev->demux; 5808c2ecf20Sopenharmony_ci list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) { 5818c2ecf20Sopenharmony_ci demux->release_ts_feed(demux, feed->ts); 5828c2ecf20Sopenharmony_ci feed->ts = NULL; 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci break; 5858c2ecf20Sopenharmony_ci default: 5868c2ecf20Sopenharmony_ci if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED) 5878c2ecf20Sopenharmony_ci return 0; 5888c2ecf20Sopenharmony_ci return -EINVAL; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci dvb_ringbuffer_flush(&dmxdevfilter->buffer); 5928c2ecf20Sopenharmony_ci return 0; 5938c2ecf20Sopenharmony_ci} 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_cistatic void dvb_dmxdev_delete_pids(struct dmxdev_filter *dmxdevfilter) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci struct dmxdev_feed *feed, *tmp; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci /* delete all PIDs */ 6008c2ecf20Sopenharmony_ci list_for_each_entry_safe(feed, tmp, &dmxdevfilter->feed.ts, next) { 6018c2ecf20Sopenharmony_ci list_del(&feed->next); 6028c2ecf20Sopenharmony_ci kfree(feed); 6038c2ecf20Sopenharmony_ci } 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci BUG_ON(!list_empty(&dmxdevfilter->feed.ts)); 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_cistatic inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter) 6098c2ecf20Sopenharmony_ci{ 6108c2ecf20Sopenharmony_ci if (dmxdevfilter->state < DMXDEV_STATE_SET) 6118c2ecf20Sopenharmony_ci return 0; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci if (dmxdevfilter->type == DMXDEV_TYPE_PES) 6148c2ecf20Sopenharmony_ci dvb_dmxdev_delete_pids(dmxdevfilter); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci dmxdevfilter->type = DMXDEV_TYPE_NONE; 6178c2ecf20Sopenharmony_ci dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); 6188c2ecf20Sopenharmony_ci return 0; 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistatic int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, 6228c2ecf20Sopenharmony_ci struct dmxdev_filter *filter, 6238c2ecf20Sopenharmony_ci struct dmxdev_feed *feed) 6248c2ecf20Sopenharmony_ci{ 6258c2ecf20Sopenharmony_ci ktime_t timeout = ktime_set(0, 0); 6268c2ecf20Sopenharmony_ci struct dmx_pes_filter_params *para = &filter->params.pes; 6278c2ecf20Sopenharmony_ci enum dmx_output otype; 6288c2ecf20Sopenharmony_ci int ret; 6298c2ecf20Sopenharmony_ci int ts_type; 6308c2ecf20Sopenharmony_ci enum dmx_ts_pes ts_pes; 6318c2ecf20Sopenharmony_ci struct dmx_ts_feed *tsfeed; 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci feed->ts = NULL; 6348c2ecf20Sopenharmony_ci otype = para->output; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci ts_pes = para->pes_type; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci if (ts_pes < DMX_PES_OTHER) 6398c2ecf20Sopenharmony_ci ts_type = TS_DECODER; 6408c2ecf20Sopenharmony_ci else 6418c2ecf20Sopenharmony_ci ts_type = 0; 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci if (otype == DMX_OUT_TS_TAP) 6448c2ecf20Sopenharmony_ci ts_type |= TS_PACKET; 6458c2ecf20Sopenharmony_ci else if (otype == DMX_OUT_TSDEMUX_TAP) 6468c2ecf20Sopenharmony_ci ts_type |= TS_PACKET | TS_DEMUX; 6478c2ecf20Sopenharmony_ci else if (otype == DMX_OUT_TAP) 6488c2ecf20Sopenharmony_ci ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, &feed->ts, 6518c2ecf20Sopenharmony_ci dvb_dmxdev_ts_callback); 6528c2ecf20Sopenharmony_ci if (ret < 0) 6538c2ecf20Sopenharmony_ci return ret; 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_ci tsfeed = feed->ts; 6568c2ecf20Sopenharmony_ci tsfeed->priv = filter; 6578c2ecf20Sopenharmony_ci 6588c2ecf20Sopenharmony_ci ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, timeout); 6598c2ecf20Sopenharmony_ci if (ret < 0) { 6608c2ecf20Sopenharmony_ci dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); 6618c2ecf20Sopenharmony_ci return ret; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci ret = tsfeed->start_filtering(tsfeed); 6658c2ecf20Sopenharmony_ci if (ret < 0) { 6668c2ecf20Sopenharmony_ci dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); 6678c2ecf20Sopenharmony_ci return ret; 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci return 0; 6718c2ecf20Sopenharmony_ci} 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_cistatic int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci struct dmxdev *dmxdev = filter->dev; 6768c2ecf20Sopenharmony_ci struct dmxdev_feed *feed; 6778c2ecf20Sopenharmony_ci void *mem; 6788c2ecf20Sopenharmony_ci int ret, i; 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (filter->state < DMXDEV_STATE_SET) 6818c2ecf20Sopenharmony_ci return -EINVAL; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci if (filter->state >= DMXDEV_STATE_GO) 6848c2ecf20Sopenharmony_ci dvb_dmxdev_filter_stop(filter); 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci if (!filter->buffer.data) { 6878c2ecf20Sopenharmony_ci mem = vmalloc(filter->buffer.size); 6888c2ecf20Sopenharmony_ci if (!mem) 6898c2ecf20Sopenharmony_ci return -ENOMEM; 6908c2ecf20Sopenharmony_ci spin_lock_irq(&filter->dev->lock); 6918c2ecf20Sopenharmony_ci filter->buffer.data = mem; 6928c2ecf20Sopenharmony_ci spin_unlock_irq(&filter->dev->lock); 6938c2ecf20Sopenharmony_ci } 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci dvb_ringbuffer_flush(&filter->buffer); 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci switch (filter->type) { 6988c2ecf20Sopenharmony_ci case DMXDEV_TYPE_SEC: 6998c2ecf20Sopenharmony_ci { 7008c2ecf20Sopenharmony_ci struct dmx_sct_filter_params *para = &filter->params.sec; 7018c2ecf20Sopenharmony_ci struct dmx_section_filter **secfilter = &filter->filter.sec; 7028c2ecf20Sopenharmony_ci struct dmx_section_feed **secfeed = &filter->feed.sec; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci *secfilter = NULL; 7058c2ecf20Sopenharmony_ci *secfeed = NULL; 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* find active filter/feed with same PID */ 7098c2ecf20Sopenharmony_ci for (i = 0; i < dmxdev->filternum; i++) { 7108c2ecf20Sopenharmony_ci if (dmxdev->filter[i].state >= DMXDEV_STATE_GO && 7118c2ecf20Sopenharmony_ci dmxdev->filter[i].type == DMXDEV_TYPE_SEC && 7128c2ecf20Sopenharmony_ci dmxdev->filter[i].params.sec.pid == para->pid) { 7138c2ecf20Sopenharmony_ci *secfeed = dmxdev->filter[i].feed.sec; 7148c2ecf20Sopenharmony_ci break; 7158c2ecf20Sopenharmony_ci } 7168c2ecf20Sopenharmony_ci } 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci /* if no feed found, try to allocate new one */ 7198c2ecf20Sopenharmony_ci if (!*secfeed) { 7208c2ecf20Sopenharmony_ci ret = dmxdev->demux->allocate_section_feed(dmxdev->demux, 7218c2ecf20Sopenharmony_ci secfeed, 7228c2ecf20Sopenharmony_ci dvb_dmxdev_section_callback); 7238c2ecf20Sopenharmony_ci if (ret < 0) { 7248c2ecf20Sopenharmony_ci pr_err("DVB (%s): could not alloc feed\n", 7258c2ecf20Sopenharmony_ci __func__); 7268c2ecf20Sopenharmony_ci return ret; 7278c2ecf20Sopenharmony_ci } 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci ret = (*secfeed)->set(*secfeed, para->pid, 7308c2ecf20Sopenharmony_ci (para->flags & DMX_CHECK_CRC) ? 1 : 0); 7318c2ecf20Sopenharmony_ci if (ret < 0) { 7328c2ecf20Sopenharmony_ci pr_err("DVB (%s): could not set feed\n", 7338c2ecf20Sopenharmony_ci __func__); 7348c2ecf20Sopenharmony_ci dvb_dmxdev_feed_restart(filter); 7358c2ecf20Sopenharmony_ci return ret; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci } else { 7388c2ecf20Sopenharmony_ci dvb_dmxdev_feed_stop(filter); 7398c2ecf20Sopenharmony_ci } 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci ret = (*secfeed)->allocate_filter(*secfeed, secfilter); 7428c2ecf20Sopenharmony_ci if (ret < 0) { 7438c2ecf20Sopenharmony_ci dvb_dmxdev_feed_restart(filter); 7448c2ecf20Sopenharmony_ci filter->feed.sec->start_filtering(*secfeed); 7458c2ecf20Sopenharmony_ci dprintk("could not get filter\n"); 7468c2ecf20Sopenharmony_ci return ret; 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci (*secfilter)->priv = filter; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci memcpy(&((*secfilter)->filter_value[3]), 7528c2ecf20Sopenharmony_ci &(para->filter.filter[1]), DMX_FILTER_SIZE - 1); 7538c2ecf20Sopenharmony_ci memcpy(&(*secfilter)->filter_mask[3], 7548c2ecf20Sopenharmony_ci ¶->filter.mask[1], DMX_FILTER_SIZE - 1); 7558c2ecf20Sopenharmony_ci memcpy(&(*secfilter)->filter_mode[3], 7568c2ecf20Sopenharmony_ci ¶->filter.mode[1], DMX_FILTER_SIZE - 1); 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci (*secfilter)->filter_value[0] = para->filter.filter[0]; 7598c2ecf20Sopenharmony_ci (*secfilter)->filter_mask[0] = para->filter.mask[0]; 7608c2ecf20Sopenharmony_ci (*secfilter)->filter_mode[0] = para->filter.mode[0]; 7618c2ecf20Sopenharmony_ci (*secfilter)->filter_mask[1] = 0; 7628c2ecf20Sopenharmony_ci (*secfilter)->filter_mask[2] = 0; 7638c2ecf20Sopenharmony_ci 7648c2ecf20Sopenharmony_ci filter->todo = 0; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci ret = filter->feed.sec->start_filtering(filter->feed.sec); 7678c2ecf20Sopenharmony_ci if (ret < 0) 7688c2ecf20Sopenharmony_ci return ret; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci dvb_dmxdev_filter_timer(filter); 7718c2ecf20Sopenharmony_ci break; 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci case DMXDEV_TYPE_PES: 7748c2ecf20Sopenharmony_ci list_for_each_entry(feed, &filter->feed.ts, next) { 7758c2ecf20Sopenharmony_ci ret = dvb_dmxdev_start_feed(dmxdev, filter, feed); 7768c2ecf20Sopenharmony_ci if (ret < 0) { 7778c2ecf20Sopenharmony_ci dvb_dmxdev_filter_stop(filter); 7788c2ecf20Sopenharmony_ci return ret; 7798c2ecf20Sopenharmony_ci } 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci break; 7828c2ecf20Sopenharmony_ci default: 7838c2ecf20Sopenharmony_ci return -EINVAL; 7848c2ecf20Sopenharmony_ci } 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO); 7878c2ecf20Sopenharmony_ci return 0; 7888c2ecf20Sopenharmony_ci} 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_cistatic int dvb_demux_open(struct inode *inode, struct file *file) 7918c2ecf20Sopenharmony_ci{ 7928c2ecf20Sopenharmony_ci struct dvb_device *dvbdev = file->private_data; 7938c2ecf20Sopenharmony_ci struct dmxdev *dmxdev = dvbdev->priv; 7948c2ecf20Sopenharmony_ci int i; 7958c2ecf20Sopenharmony_ci struct dmxdev_filter *dmxdevfilter; 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_ci if (!dmxdev->filter) 7988c2ecf20Sopenharmony_ci return -EINVAL; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdev->mutex)) 8018c2ecf20Sopenharmony_ci return -ERESTARTSYS; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci if (dmxdev->exit) { 8048c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 8058c2ecf20Sopenharmony_ci return -ENODEV; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci for (i = 0; i < dmxdev->filternum; i++) 8098c2ecf20Sopenharmony_ci if (dmxdev->filter[i].state == DMXDEV_STATE_FREE) 8108c2ecf20Sopenharmony_ci break; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci if (i == dmxdev->filternum) { 8138c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 8148c2ecf20Sopenharmony_ci return -EMFILE; 8158c2ecf20Sopenharmony_ci } 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci dmxdevfilter = &dmxdev->filter[i]; 8188c2ecf20Sopenharmony_ci mutex_init(&dmxdevfilter->mutex); 8198c2ecf20Sopenharmony_ci file->private_data = dmxdevfilter; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci#ifdef CONFIG_DVB_MMAP 8228c2ecf20Sopenharmony_ci dmxdev->may_do_mmap = 1; 8238c2ecf20Sopenharmony_ci#else 8248c2ecf20Sopenharmony_ci dmxdev->may_do_mmap = 0; 8258c2ecf20Sopenharmony_ci#endif 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192); 8288c2ecf20Sopenharmony_ci dvb_vb2_init(&dmxdevfilter->vb2_ctx, "demux_filter", 8298c2ecf20Sopenharmony_ci file->f_flags & O_NONBLOCK); 8308c2ecf20Sopenharmony_ci dmxdevfilter->type = DMXDEV_TYPE_NONE; 8318c2ecf20Sopenharmony_ci dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); 8328c2ecf20Sopenharmony_ci timer_setup(&dmxdevfilter->timer, dvb_dmxdev_filter_timeout, 0); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci dvbdev->users++; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 8378c2ecf20Sopenharmony_ci return 0; 8388c2ecf20Sopenharmony_ci} 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_cistatic int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, 8418c2ecf20Sopenharmony_ci struct dmxdev_filter *dmxdevfilter) 8428c2ecf20Sopenharmony_ci{ 8438c2ecf20Sopenharmony_ci mutex_lock(&dmxdev->mutex); 8448c2ecf20Sopenharmony_ci mutex_lock(&dmxdevfilter->mutex); 8458c2ecf20Sopenharmony_ci if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) 8468c2ecf20Sopenharmony_ci dvb_vb2_stream_off(&dmxdevfilter->vb2_ctx); 8478c2ecf20Sopenharmony_ci dvb_vb2_release(&dmxdevfilter->vb2_ctx); 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci dvb_dmxdev_filter_stop(dmxdevfilter); 8518c2ecf20Sopenharmony_ci dvb_dmxdev_filter_reset(dmxdevfilter); 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci if (dmxdevfilter->buffer.data) { 8548c2ecf20Sopenharmony_ci void *mem = dmxdevfilter->buffer.data; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci spin_lock_irq(&dmxdev->lock); 8578c2ecf20Sopenharmony_ci dmxdevfilter->buffer.data = NULL; 8588c2ecf20Sopenharmony_ci spin_unlock_irq(&dmxdev->lock); 8598c2ecf20Sopenharmony_ci vfree(mem); 8608c2ecf20Sopenharmony_ci } 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE); 8638c2ecf20Sopenharmony_ci wake_up(&dmxdevfilter->buffer.queue); 8648c2ecf20Sopenharmony_ci mutex_unlock(&dmxdevfilter->mutex); 8658c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 8668c2ecf20Sopenharmony_ci return 0; 8678c2ecf20Sopenharmony_ci} 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_cistatic inline void invert_mode(struct dmx_filter *filter) 8708c2ecf20Sopenharmony_ci{ 8718c2ecf20Sopenharmony_ci int i; 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci for (i = 0; i < DMX_FILTER_SIZE; i++) 8748c2ecf20Sopenharmony_ci filter->mode[i] ^= 0xff; 8758c2ecf20Sopenharmony_ci} 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_cistatic int dvb_dmxdev_add_pid(struct dmxdev *dmxdev, 8788c2ecf20Sopenharmony_ci struct dmxdev_filter *filter, u16 pid) 8798c2ecf20Sopenharmony_ci{ 8808c2ecf20Sopenharmony_ci struct dmxdev_feed *feed; 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_ci if ((filter->type != DMXDEV_TYPE_PES) || 8838c2ecf20Sopenharmony_ci (filter->state < DMXDEV_STATE_SET)) 8848c2ecf20Sopenharmony_ci return -EINVAL; 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci /* only TS packet filters may have multiple PIDs */ 8878c2ecf20Sopenharmony_ci if ((filter->params.pes.output != DMX_OUT_TSDEMUX_TAP) && 8888c2ecf20Sopenharmony_ci (!list_empty(&filter->feed.ts))) 8898c2ecf20Sopenharmony_ci return -EINVAL; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci feed = kzalloc(sizeof(struct dmxdev_feed), GFP_KERNEL); 8928c2ecf20Sopenharmony_ci if (feed == NULL) 8938c2ecf20Sopenharmony_ci return -ENOMEM; 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci feed->pid = pid; 8968c2ecf20Sopenharmony_ci list_add(&feed->next, &filter->feed.ts); 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci if (filter->state >= DMXDEV_STATE_GO) 8998c2ecf20Sopenharmony_ci return dvb_dmxdev_start_feed(dmxdev, filter, feed); 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_ci return 0; 9028c2ecf20Sopenharmony_ci} 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_cistatic int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev, 9058c2ecf20Sopenharmony_ci struct dmxdev_filter *filter, u16 pid) 9068c2ecf20Sopenharmony_ci{ 9078c2ecf20Sopenharmony_ci struct dmxdev_feed *feed, *tmp; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci if ((filter->type != DMXDEV_TYPE_PES) || 9108c2ecf20Sopenharmony_ci (filter->state < DMXDEV_STATE_SET)) 9118c2ecf20Sopenharmony_ci return -EINVAL; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) { 9148c2ecf20Sopenharmony_ci if ((feed->pid == pid) && (feed->ts != NULL)) { 9158c2ecf20Sopenharmony_ci feed->ts->stop_filtering(feed->ts); 9168c2ecf20Sopenharmony_ci filter->dev->demux->release_ts_feed(filter->dev->demux, 9178c2ecf20Sopenharmony_ci feed->ts); 9188c2ecf20Sopenharmony_ci list_del(&feed->next); 9198c2ecf20Sopenharmony_ci kfree(feed); 9208c2ecf20Sopenharmony_ci } 9218c2ecf20Sopenharmony_ci } 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci return 0; 9248c2ecf20Sopenharmony_ci} 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_cistatic int dvb_dmxdev_filter_set(struct dmxdev *dmxdev, 9278c2ecf20Sopenharmony_ci struct dmxdev_filter *dmxdevfilter, 9288c2ecf20Sopenharmony_ci struct dmx_sct_filter_params *params) 9298c2ecf20Sopenharmony_ci{ 9308c2ecf20Sopenharmony_ci dprintk("%s: PID=0x%04x, flags=%02x, timeout=%d\n", 9318c2ecf20Sopenharmony_ci __func__, params->pid, params->flags, params->timeout); 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci dvb_dmxdev_filter_stop(dmxdevfilter); 9348c2ecf20Sopenharmony_ci 9358c2ecf20Sopenharmony_ci dmxdevfilter->type = DMXDEV_TYPE_SEC; 9368c2ecf20Sopenharmony_ci memcpy(&dmxdevfilter->params.sec, 9378c2ecf20Sopenharmony_ci params, sizeof(struct dmx_sct_filter_params)); 9388c2ecf20Sopenharmony_ci invert_mode(&dmxdevfilter->params.sec.filter); 9398c2ecf20Sopenharmony_ci dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci if (params->flags & DMX_IMMEDIATE_START) 9428c2ecf20Sopenharmony_ci return dvb_dmxdev_filter_start(dmxdevfilter); 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci return 0; 9458c2ecf20Sopenharmony_ci} 9468c2ecf20Sopenharmony_ci 9478c2ecf20Sopenharmony_cistatic int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev, 9488c2ecf20Sopenharmony_ci struct dmxdev_filter *dmxdevfilter, 9498c2ecf20Sopenharmony_ci struct dmx_pes_filter_params *params) 9508c2ecf20Sopenharmony_ci{ 9518c2ecf20Sopenharmony_ci int ret; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci dvb_dmxdev_filter_stop(dmxdevfilter); 9548c2ecf20Sopenharmony_ci dvb_dmxdev_filter_reset(dmxdevfilter); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci if ((unsigned int)params->pes_type > DMX_PES_OTHER) 9578c2ecf20Sopenharmony_ci return -EINVAL; 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci dmxdevfilter->type = DMXDEV_TYPE_PES; 9608c2ecf20Sopenharmony_ci memcpy(&dmxdevfilter->params, params, 9618c2ecf20Sopenharmony_ci sizeof(struct dmx_pes_filter_params)); 9628c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&dmxdevfilter->feed.ts); 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, 9678c2ecf20Sopenharmony_ci dmxdevfilter->params.pes.pid); 9688c2ecf20Sopenharmony_ci if (ret < 0) 9698c2ecf20Sopenharmony_ci return ret; 9708c2ecf20Sopenharmony_ci 9718c2ecf20Sopenharmony_ci if (params->flags & DMX_IMMEDIATE_START) 9728c2ecf20Sopenharmony_ci return dvb_dmxdev_filter_start(dmxdevfilter); 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci return 0; 9758c2ecf20Sopenharmony_ci} 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_cistatic ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil, 9788c2ecf20Sopenharmony_ci struct file *file, char __user *buf, 9798c2ecf20Sopenharmony_ci size_t count, loff_t *ppos) 9808c2ecf20Sopenharmony_ci{ 9818c2ecf20Sopenharmony_ci int result, hcount; 9828c2ecf20Sopenharmony_ci int done = 0; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci if (dfil->todo <= 0) { 9858c2ecf20Sopenharmony_ci hcount = 3 + dfil->todo; 9868c2ecf20Sopenharmony_ci if (hcount > count) 9878c2ecf20Sopenharmony_ci hcount = count; 9888c2ecf20Sopenharmony_ci result = dvb_dmxdev_buffer_read(&dfil->buffer, 9898c2ecf20Sopenharmony_ci file->f_flags & O_NONBLOCK, 9908c2ecf20Sopenharmony_ci buf, hcount, ppos); 9918c2ecf20Sopenharmony_ci if (result < 0) { 9928c2ecf20Sopenharmony_ci dfil->todo = 0; 9938c2ecf20Sopenharmony_ci return result; 9948c2ecf20Sopenharmony_ci } 9958c2ecf20Sopenharmony_ci if (copy_from_user(dfil->secheader - dfil->todo, buf, result)) 9968c2ecf20Sopenharmony_ci return -EFAULT; 9978c2ecf20Sopenharmony_ci buf += result; 9988c2ecf20Sopenharmony_ci done = result; 9998c2ecf20Sopenharmony_ci count -= result; 10008c2ecf20Sopenharmony_ci dfil->todo -= result; 10018c2ecf20Sopenharmony_ci if (dfil->todo > -3) 10028c2ecf20Sopenharmony_ci return done; 10038c2ecf20Sopenharmony_ci dfil->todo = ((dfil->secheader[1] << 8) | dfil->secheader[2]) & 0xfff; 10048c2ecf20Sopenharmony_ci if (!count) 10058c2ecf20Sopenharmony_ci return done; 10068c2ecf20Sopenharmony_ci } 10078c2ecf20Sopenharmony_ci if (count > dfil->todo) 10088c2ecf20Sopenharmony_ci count = dfil->todo; 10098c2ecf20Sopenharmony_ci result = dvb_dmxdev_buffer_read(&dfil->buffer, 10108c2ecf20Sopenharmony_ci file->f_flags & O_NONBLOCK, 10118c2ecf20Sopenharmony_ci buf, count, ppos); 10128c2ecf20Sopenharmony_ci if (result < 0) 10138c2ecf20Sopenharmony_ci return result; 10148c2ecf20Sopenharmony_ci dfil->todo -= result; 10158c2ecf20Sopenharmony_ci return (result + done); 10168c2ecf20Sopenharmony_ci} 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_cistatic ssize_t 10198c2ecf20Sopenharmony_cidvb_demux_read(struct file *file, char __user *buf, size_t count, 10208c2ecf20Sopenharmony_ci loff_t *ppos) 10218c2ecf20Sopenharmony_ci{ 10228c2ecf20Sopenharmony_ci struct dmxdev_filter *dmxdevfilter = file->private_data; 10238c2ecf20Sopenharmony_ci int ret; 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdevfilter->mutex)) 10268c2ecf20Sopenharmony_ci return -ERESTARTSYS; 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci if (dmxdevfilter->type == DMXDEV_TYPE_SEC) 10298c2ecf20Sopenharmony_ci ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos); 10308c2ecf20Sopenharmony_ci else 10318c2ecf20Sopenharmony_ci ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer, 10328c2ecf20Sopenharmony_ci file->f_flags & O_NONBLOCK, 10338c2ecf20Sopenharmony_ci buf, count, ppos); 10348c2ecf20Sopenharmony_ci 10358c2ecf20Sopenharmony_ci mutex_unlock(&dmxdevfilter->mutex); 10368c2ecf20Sopenharmony_ci return ret; 10378c2ecf20Sopenharmony_ci} 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_cistatic int dvb_demux_do_ioctl(struct file *file, 10408c2ecf20Sopenharmony_ci unsigned int cmd, void *parg) 10418c2ecf20Sopenharmony_ci{ 10428c2ecf20Sopenharmony_ci struct dmxdev_filter *dmxdevfilter = file->private_data; 10438c2ecf20Sopenharmony_ci struct dmxdev *dmxdev = dmxdevfilter->dev; 10448c2ecf20Sopenharmony_ci unsigned long arg = (unsigned long)parg; 10458c2ecf20Sopenharmony_ci int ret = 0; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdev->mutex)) 10488c2ecf20Sopenharmony_ci return -ERESTARTSYS; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci switch (cmd) { 10518c2ecf20Sopenharmony_ci case DMX_START: 10528c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { 10538c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 10548c2ecf20Sopenharmony_ci return -ERESTARTSYS; 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci if (dmxdevfilter->state < DMXDEV_STATE_SET) 10578c2ecf20Sopenharmony_ci ret = -EINVAL; 10588c2ecf20Sopenharmony_ci else 10598c2ecf20Sopenharmony_ci ret = dvb_dmxdev_filter_start(dmxdevfilter); 10608c2ecf20Sopenharmony_ci mutex_unlock(&dmxdevfilter->mutex); 10618c2ecf20Sopenharmony_ci break; 10628c2ecf20Sopenharmony_ci 10638c2ecf20Sopenharmony_ci case DMX_STOP: 10648c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { 10658c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 10668c2ecf20Sopenharmony_ci return -ERESTARTSYS; 10678c2ecf20Sopenharmony_ci } 10688c2ecf20Sopenharmony_ci ret = dvb_dmxdev_filter_stop(dmxdevfilter); 10698c2ecf20Sopenharmony_ci mutex_unlock(&dmxdevfilter->mutex); 10708c2ecf20Sopenharmony_ci break; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci case DMX_SET_FILTER: 10738c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { 10748c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 10758c2ecf20Sopenharmony_ci return -ERESTARTSYS; 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg); 10788c2ecf20Sopenharmony_ci mutex_unlock(&dmxdevfilter->mutex); 10798c2ecf20Sopenharmony_ci break; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci case DMX_SET_PES_FILTER: 10828c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { 10838c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 10848c2ecf20Sopenharmony_ci return -ERESTARTSYS; 10858c2ecf20Sopenharmony_ci } 10868c2ecf20Sopenharmony_ci ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg); 10878c2ecf20Sopenharmony_ci mutex_unlock(&dmxdevfilter->mutex); 10888c2ecf20Sopenharmony_ci break; 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci case DMX_SET_BUFFER_SIZE: 10918c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { 10928c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 10938c2ecf20Sopenharmony_ci return -ERESTARTSYS; 10948c2ecf20Sopenharmony_ci } 10958c2ecf20Sopenharmony_ci ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg); 10968c2ecf20Sopenharmony_ci mutex_unlock(&dmxdevfilter->mutex); 10978c2ecf20Sopenharmony_ci break; 10988c2ecf20Sopenharmony_ci 10998c2ecf20Sopenharmony_ci case DMX_GET_PES_PIDS: 11008c2ecf20Sopenharmony_ci if (!dmxdev->demux->get_pes_pids) { 11018c2ecf20Sopenharmony_ci ret = -EINVAL; 11028c2ecf20Sopenharmony_ci break; 11038c2ecf20Sopenharmony_ci } 11048c2ecf20Sopenharmony_ci dmxdev->demux->get_pes_pids(dmxdev->demux, parg); 11058c2ecf20Sopenharmony_ci break; 11068c2ecf20Sopenharmony_ci 11078c2ecf20Sopenharmony_ci case DMX_GET_STC: 11088c2ecf20Sopenharmony_ci if (!dmxdev->demux->get_stc) { 11098c2ecf20Sopenharmony_ci ret = -EINVAL; 11108c2ecf20Sopenharmony_ci break; 11118c2ecf20Sopenharmony_ci } 11128c2ecf20Sopenharmony_ci ret = dmxdev->demux->get_stc(dmxdev->demux, 11138c2ecf20Sopenharmony_ci ((struct dmx_stc *)parg)->num, 11148c2ecf20Sopenharmony_ci &((struct dmx_stc *)parg)->stc, 11158c2ecf20Sopenharmony_ci &((struct dmx_stc *)parg)->base); 11168c2ecf20Sopenharmony_ci break; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci case DMX_ADD_PID: 11198c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { 11208c2ecf20Sopenharmony_ci ret = -ERESTARTSYS; 11218c2ecf20Sopenharmony_ci break; 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, *(u16 *)parg); 11248c2ecf20Sopenharmony_ci mutex_unlock(&dmxdevfilter->mutex); 11258c2ecf20Sopenharmony_ci break; 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci case DMX_REMOVE_PID: 11288c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { 11298c2ecf20Sopenharmony_ci ret = -ERESTARTSYS; 11308c2ecf20Sopenharmony_ci break; 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci ret = dvb_dmxdev_remove_pid(dmxdev, dmxdevfilter, *(u16 *)parg); 11338c2ecf20Sopenharmony_ci mutex_unlock(&dmxdevfilter->mutex); 11348c2ecf20Sopenharmony_ci break; 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci#ifdef CONFIG_DVB_MMAP 11378c2ecf20Sopenharmony_ci case DMX_REQBUFS: 11388c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { 11398c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 11408c2ecf20Sopenharmony_ci return -ERESTARTSYS; 11418c2ecf20Sopenharmony_ci } 11428c2ecf20Sopenharmony_ci ret = dvb_vb2_reqbufs(&dmxdevfilter->vb2_ctx, parg); 11438c2ecf20Sopenharmony_ci mutex_unlock(&dmxdevfilter->mutex); 11448c2ecf20Sopenharmony_ci break; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci case DMX_QUERYBUF: 11478c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { 11488c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 11498c2ecf20Sopenharmony_ci return -ERESTARTSYS; 11508c2ecf20Sopenharmony_ci } 11518c2ecf20Sopenharmony_ci ret = dvb_vb2_querybuf(&dmxdevfilter->vb2_ctx, parg); 11528c2ecf20Sopenharmony_ci mutex_unlock(&dmxdevfilter->mutex); 11538c2ecf20Sopenharmony_ci break; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci case DMX_EXPBUF: 11568c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { 11578c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 11588c2ecf20Sopenharmony_ci return -ERESTARTSYS; 11598c2ecf20Sopenharmony_ci } 11608c2ecf20Sopenharmony_ci ret = dvb_vb2_expbuf(&dmxdevfilter->vb2_ctx, parg); 11618c2ecf20Sopenharmony_ci mutex_unlock(&dmxdevfilter->mutex); 11628c2ecf20Sopenharmony_ci break; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci case DMX_QBUF: 11658c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { 11668c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 11678c2ecf20Sopenharmony_ci return -ERESTARTSYS; 11688c2ecf20Sopenharmony_ci } 11698c2ecf20Sopenharmony_ci ret = dvb_vb2_qbuf(&dmxdevfilter->vb2_ctx, parg); 11708c2ecf20Sopenharmony_ci if (ret == 0 && !dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) 11718c2ecf20Sopenharmony_ci ret = dvb_vb2_stream_on(&dmxdevfilter->vb2_ctx); 11728c2ecf20Sopenharmony_ci mutex_unlock(&dmxdevfilter->mutex); 11738c2ecf20Sopenharmony_ci break; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci case DMX_DQBUF: 11768c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { 11778c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 11788c2ecf20Sopenharmony_ci return -ERESTARTSYS; 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci ret = dvb_vb2_dqbuf(&dmxdevfilter->vb2_ctx, parg); 11818c2ecf20Sopenharmony_ci mutex_unlock(&dmxdevfilter->mutex); 11828c2ecf20Sopenharmony_ci break; 11838c2ecf20Sopenharmony_ci#endif 11848c2ecf20Sopenharmony_ci default: 11858c2ecf20Sopenharmony_ci ret = -ENOTTY; 11868c2ecf20Sopenharmony_ci break; 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 11898c2ecf20Sopenharmony_ci return ret; 11908c2ecf20Sopenharmony_ci} 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cistatic long dvb_demux_ioctl(struct file *file, unsigned int cmd, 11938c2ecf20Sopenharmony_ci unsigned long arg) 11948c2ecf20Sopenharmony_ci{ 11958c2ecf20Sopenharmony_ci return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl); 11968c2ecf20Sopenharmony_ci} 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_cistatic __poll_t dvb_demux_poll(struct file *file, poll_table *wait) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci struct dmxdev_filter *dmxdevfilter = file->private_data; 12018c2ecf20Sopenharmony_ci __poll_t mask = 0; 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci poll_wait(file, &dmxdevfilter->buffer.queue, wait); 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci if ((!dmxdevfilter) || dmxdevfilter->dev->exit) 12068c2ecf20Sopenharmony_ci return EPOLLERR; 12078c2ecf20Sopenharmony_ci if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) 12088c2ecf20Sopenharmony_ci return dvb_vb2_poll(&dmxdevfilter->vb2_ctx, file, wait); 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci if (dmxdevfilter->state != DMXDEV_STATE_GO && 12118c2ecf20Sopenharmony_ci dmxdevfilter->state != DMXDEV_STATE_DONE && 12128c2ecf20Sopenharmony_ci dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT) 12138c2ecf20Sopenharmony_ci return 0; 12148c2ecf20Sopenharmony_ci 12158c2ecf20Sopenharmony_ci if (dmxdevfilter->buffer.error) 12168c2ecf20Sopenharmony_ci mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI | EPOLLERR); 12178c2ecf20Sopenharmony_ci 12188c2ecf20Sopenharmony_ci if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer)) 12198c2ecf20Sopenharmony_ci mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI); 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci return mask; 12228c2ecf20Sopenharmony_ci} 12238c2ecf20Sopenharmony_ci 12248c2ecf20Sopenharmony_ci#ifdef CONFIG_DVB_MMAP 12258c2ecf20Sopenharmony_cistatic int dvb_demux_mmap(struct file *file, struct vm_area_struct *vma) 12268c2ecf20Sopenharmony_ci{ 12278c2ecf20Sopenharmony_ci struct dmxdev_filter *dmxdevfilter = file->private_data; 12288c2ecf20Sopenharmony_ci struct dmxdev *dmxdev = dmxdevfilter->dev; 12298c2ecf20Sopenharmony_ci int ret; 12308c2ecf20Sopenharmony_ci 12318c2ecf20Sopenharmony_ci if (!dmxdev->may_do_mmap) 12328c2ecf20Sopenharmony_ci return -ENOTTY; 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdev->mutex)) 12358c2ecf20Sopenharmony_ci return -ERESTARTSYS; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { 12388c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 12398c2ecf20Sopenharmony_ci return -ERESTARTSYS; 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci ret = dvb_vb2_mmap(&dmxdevfilter->vb2_ctx, vma); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci mutex_unlock(&dmxdevfilter->mutex); 12448c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci return ret; 12478c2ecf20Sopenharmony_ci} 12488c2ecf20Sopenharmony_ci#endif 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_cistatic int dvb_demux_release(struct inode *inode, struct file *file) 12518c2ecf20Sopenharmony_ci{ 12528c2ecf20Sopenharmony_ci struct dmxdev_filter *dmxdevfilter = file->private_data; 12538c2ecf20Sopenharmony_ci struct dmxdev *dmxdev = dmxdevfilter->dev; 12548c2ecf20Sopenharmony_ci int ret; 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter); 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci mutex_lock(&dmxdev->mutex); 12598c2ecf20Sopenharmony_ci dmxdev->dvbdev->users--; 12608c2ecf20Sopenharmony_ci if (dmxdev->dvbdev->users == 1 && dmxdev->exit == 1) { 12618c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 12628c2ecf20Sopenharmony_ci wake_up(&dmxdev->dvbdev->wait_queue); 12638c2ecf20Sopenharmony_ci } else 12648c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci return ret; 12678c2ecf20Sopenharmony_ci} 12688c2ecf20Sopenharmony_ci 12698c2ecf20Sopenharmony_cistatic const struct file_operations dvb_demux_fops = { 12708c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 12718c2ecf20Sopenharmony_ci .read = dvb_demux_read, 12728c2ecf20Sopenharmony_ci .unlocked_ioctl = dvb_demux_ioctl, 12738c2ecf20Sopenharmony_ci .compat_ioctl = dvb_demux_ioctl, 12748c2ecf20Sopenharmony_ci .open = dvb_demux_open, 12758c2ecf20Sopenharmony_ci .release = dvb_demux_release, 12768c2ecf20Sopenharmony_ci .poll = dvb_demux_poll, 12778c2ecf20Sopenharmony_ci .llseek = default_llseek, 12788c2ecf20Sopenharmony_ci#ifdef CONFIG_DVB_MMAP 12798c2ecf20Sopenharmony_ci .mmap = dvb_demux_mmap, 12808c2ecf20Sopenharmony_ci#endif 12818c2ecf20Sopenharmony_ci}; 12828c2ecf20Sopenharmony_ci 12838c2ecf20Sopenharmony_cistatic const struct dvb_device dvbdev_demux = { 12848c2ecf20Sopenharmony_ci .priv = NULL, 12858c2ecf20Sopenharmony_ci .users = 1, 12868c2ecf20Sopenharmony_ci .writers = 1, 12878c2ecf20Sopenharmony_ci#if defined(CONFIG_MEDIA_CONTROLLER_DVB) 12888c2ecf20Sopenharmony_ci .name = "dvb-demux", 12898c2ecf20Sopenharmony_ci#endif 12908c2ecf20Sopenharmony_ci .fops = &dvb_demux_fops 12918c2ecf20Sopenharmony_ci}; 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_cistatic int dvb_dvr_do_ioctl(struct file *file, 12948c2ecf20Sopenharmony_ci unsigned int cmd, void *parg) 12958c2ecf20Sopenharmony_ci{ 12968c2ecf20Sopenharmony_ci struct dvb_device *dvbdev = file->private_data; 12978c2ecf20Sopenharmony_ci struct dmxdev *dmxdev = dvbdev->priv; 12988c2ecf20Sopenharmony_ci unsigned long arg = (unsigned long)parg; 12998c2ecf20Sopenharmony_ci int ret; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdev->mutex)) 13028c2ecf20Sopenharmony_ci return -ERESTARTSYS; 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci switch (cmd) { 13058c2ecf20Sopenharmony_ci case DMX_SET_BUFFER_SIZE: 13068c2ecf20Sopenharmony_ci ret = dvb_dvr_set_buffer_size(dmxdev, arg); 13078c2ecf20Sopenharmony_ci break; 13088c2ecf20Sopenharmony_ci 13098c2ecf20Sopenharmony_ci#ifdef CONFIG_DVB_MMAP 13108c2ecf20Sopenharmony_ci case DMX_REQBUFS: 13118c2ecf20Sopenharmony_ci ret = dvb_vb2_reqbufs(&dmxdev->dvr_vb2_ctx, parg); 13128c2ecf20Sopenharmony_ci break; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci case DMX_QUERYBUF: 13158c2ecf20Sopenharmony_ci ret = dvb_vb2_querybuf(&dmxdev->dvr_vb2_ctx, parg); 13168c2ecf20Sopenharmony_ci break; 13178c2ecf20Sopenharmony_ci 13188c2ecf20Sopenharmony_ci case DMX_EXPBUF: 13198c2ecf20Sopenharmony_ci ret = dvb_vb2_expbuf(&dmxdev->dvr_vb2_ctx, parg); 13208c2ecf20Sopenharmony_ci break; 13218c2ecf20Sopenharmony_ci 13228c2ecf20Sopenharmony_ci case DMX_QBUF: 13238c2ecf20Sopenharmony_ci ret = dvb_vb2_qbuf(&dmxdev->dvr_vb2_ctx, parg); 13248c2ecf20Sopenharmony_ci if (ret == 0 && !dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx)) 13258c2ecf20Sopenharmony_ci ret = dvb_vb2_stream_on(&dmxdev->dvr_vb2_ctx); 13268c2ecf20Sopenharmony_ci break; 13278c2ecf20Sopenharmony_ci 13288c2ecf20Sopenharmony_ci case DMX_DQBUF: 13298c2ecf20Sopenharmony_ci ret = dvb_vb2_dqbuf(&dmxdev->dvr_vb2_ctx, parg); 13308c2ecf20Sopenharmony_ci break; 13318c2ecf20Sopenharmony_ci#endif 13328c2ecf20Sopenharmony_ci default: 13338c2ecf20Sopenharmony_ci ret = -ENOTTY; 13348c2ecf20Sopenharmony_ci break; 13358c2ecf20Sopenharmony_ci } 13368c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 13378c2ecf20Sopenharmony_ci return ret; 13388c2ecf20Sopenharmony_ci} 13398c2ecf20Sopenharmony_ci 13408c2ecf20Sopenharmony_cistatic long dvb_dvr_ioctl(struct file *file, 13418c2ecf20Sopenharmony_ci unsigned int cmd, unsigned long arg) 13428c2ecf20Sopenharmony_ci{ 13438c2ecf20Sopenharmony_ci return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl); 13448c2ecf20Sopenharmony_ci} 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_cistatic __poll_t dvb_dvr_poll(struct file *file, poll_table *wait) 13478c2ecf20Sopenharmony_ci{ 13488c2ecf20Sopenharmony_ci struct dvb_device *dvbdev = file->private_data; 13498c2ecf20Sopenharmony_ci struct dmxdev *dmxdev = dvbdev->priv; 13508c2ecf20Sopenharmony_ci __poll_t mask = 0; 13518c2ecf20Sopenharmony_ci 13528c2ecf20Sopenharmony_ci dprintk("%s\n", __func__); 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ci poll_wait(file, &dmxdev->dvr_buffer.queue, wait); 13558c2ecf20Sopenharmony_ci 13568c2ecf20Sopenharmony_ci if (dmxdev->exit) 13578c2ecf20Sopenharmony_ci return EPOLLERR; 13588c2ecf20Sopenharmony_ci if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx)) 13598c2ecf20Sopenharmony_ci return dvb_vb2_poll(&dmxdev->dvr_vb2_ctx, file, wait); 13608c2ecf20Sopenharmony_ci 13618c2ecf20Sopenharmony_ci if (((file->f_flags & O_ACCMODE) == O_RDONLY) || 13628c2ecf20Sopenharmony_ci dmxdev->may_do_mmap) { 13638c2ecf20Sopenharmony_ci if (dmxdev->dvr_buffer.error) 13648c2ecf20Sopenharmony_ci mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI | EPOLLERR); 13658c2ecf20Sopenharmony_ci 13668c2ecf20Sopenharmony_ci if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer)) 13678c2ecf20Sopenharmony_ci mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI); 13688c2ecf20Sopenharmony_ci } else 13698c2ecf20Sopenharmony_ci mask |= (EPOLLOUT | EPOLLWRNORM | EPOLLPRI); 13708c2ecf20Sopenharmony_ci 13718c2ecf20Sopenharmony_ci return mask; 13728c2ecf20Sopenharmony_ci} 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci#ifdef CONFIG_DVB_MMAP 13758c2ecf20Sopenharmony_cistatic int dvb_dvr_mmap(struct file *file, struct vm_area_struct *vma) 13768c2ecf20Sopenharmony_ci{ 13778c2ecf20Sopenharmony_ci struct dvb_device *dvbdev = file->private_data; 13788c2ecf20Sopenharmony_ci struct dmxdev *dmxdev = dvbdev->priv; 13798c2ecf20Sopenharmony_ci int ret; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci if (!dmxdev->may_do_mmap) 13828c2ecf20Sopenharmony_ci return -ENOTTY; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci if (dmxdev->exit) 13858c2ecf20Sopenharmony_ci return -ENODEV; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci if (mutex_lock_interruptible(&dmxdev->mutex)) 13888c2ecf20Sopenharmony_ci return -ERESTARTSYS; 13898c2ecf20Sopenharmony_ci 13908c2ecf20Sopenharmony_ci ret = dvb_vb2_mmap(&dmxdev->dvr_vb2_ctx, vma); 13918c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 13928c2ecf20Sopenharmony_ci return ret; 13938c2ecf20Sopenharmony_ci} 13948c2ecf20Sopenharmony_ci#endif 13958c2ecf20Sopenharmony_ci 13968c2ecf20Sopenharmony_cistatic const struct file_operations dvb_dvr_fops = { 13978c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 13988c2ecf20Sopenharmony_ci .read = dvb_dvr_read, 13998c2ecf20Sopenharmony_ci .write = dvb_dvr_write, 14008c2ecf20Sopenharmony_ci .unlocked_ioctl = dvb_dvr_ioctl, 14018c2ecf20Sopenharmony_ci .open = dvb_dvr_open, 14028c2ecf20Sopenharmony_ci .release = dvb_dvr_release, 14038c2ecf20Sopenharmony_ci .poll = dvb_dvr_poll, 14048c2ecf20Sopenharmony_ci .llseek = default_llseek, 14058c2ecf20Sopenharmony_ci#ifdef CONFIG_DVB_MMAP 14068c2ecf20Sopenharmony_ci .mmap = dvb_dvr_mmap, 14078c2ecf20Sopenharmony_ci#endif 14088c2ecf20Sopenharmony_ci}; 14098c2ecf20Sopenharmony_ci 14108c2ecf20Sopenharmony_cistatic const struct dvb_device dvbdev_dvr = { 14118c2ecf20Sopenharmony_ci .priv = NULL, 14128c2ecf20Sopenharmony_ci .readers = 1, 14138c2ecf20Sopenharmony_ci .users = 1, 14148c2ecf20Sopenharmony_ci#if defined(CONFIG_MEDIA_CONTROLLER_DVB) 14158c2ecf20Sopenharmony_ci .name = "dvb-dvr", 14168c2ecf20Sopenharmony_ci#endif 14178c2ecf20Sopenharmony_ci .fops = &dvb_dvr_fops 14188c2ecf20Sopenharmony_ci}; 14198c2ecf20Sopenharmony_ciint dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) 14208c2ecf20Sopenharmony_ci{ 14218c2ecf20Sopenharmony_ci int i, ret; 14228c2ecf20Sopenharmony_ci 14238c2ecf20Sopenharmony_ci if (dmxdev->demux->open(dmxdev->demux) < 0) 14248c2ecf20Sopenharmony_ci return -EUSERS; 14258c2ecf20Sopenharmony_ci 14268c2ecf20Sopenharmony_ci dmxdev->filter = vmalloc(array_size(sizeof(struct dmxdev_filter), 14278c2ecf20Sopenharmony_ci dmxdev->filternum)); 14288c2ecf20Sopenharmony_ci if (!dmxdev->filter) 14298c2ecf20Sopenharmony_ci return -ENOMEM; 14308c2ecf20Sopenharmony_ci 14318c2ecf20Sopenharmony_ci mutex_init(&dmxdev->mutex); 14328c2ecf20Sopenharmony_ci spin_lock_init(&dmxdev->lock); 14338c2ecf20Sopenharmony_ci for (i = 0; i < dmxdev->filternum; i++) { 14348c2ecf20Sopenharmony_ci dmxdev->filter[i].dev = dmxdev; 14358c2ecf20Sopenharmony_ci dmxdev->filter[i].buffer.data = NULL; 14368c2ecf20Sopenharmony_ci dvb_dmxdev_filter_state_set(&dmxdev->filter[i], 14378c2ecf20Sopenharmony_ci DMXDEV_STATE_FREE); 14388c2ecf20Sopenharmony_ci } 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci ret = dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev, 14418c2ecf20Sopenharmony_ci DVB_DEVICE_DEMUX, dmxdev->filternum); 14428c2ecf20Sopenharmony_ci if (ret < 0) 14438c2ecf20Sopenharmony_ci goto err_register_dvbdev; 14448c2ecf20Sopenharmony_ci 14458c2ecf20Sopenharmony_ci ret = dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr, 14468c2ecf20Sopenharmony_ci dmxdev, DVB_DEVICE_DVR, dmxdev->filternum); 14478c2ecf20Sopenharmony_ci if (ret < 0) 14488c2ecf20Sopenharmony_ci goto err_register_dvr_dvbdev; 14498c2ecf20Sopenharmony_ci 14508c2ecf20Sopenharmony_ci dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192); 14518c2ecf20Sopenharmony_ci 14528c2ecf20Sopenharmony_ci return 0; 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_cierr_register_dvr_dvbdev: 14558c2ecf20Sopenharmony_ci dvb_unregister_device(dmxdev->dvbdev); 14568c2ecf20Sopenharmony_cierr_register_dvbdev: 14578c2ecf20Sopenharmony_ci vfree(dmxdev->filter); 14588c2ecf20Sopenharmony_ci dmxdev->filter = NULL; 14598c2ecf20Sopenharmony_ci return ret; 14608c2ecf20Sopenharmony_ci} 14618c2ecf20Sopenharmony_ci 14628c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dvb_dmxdev_init); 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_civoid dvb_dmxdev_release(struct dmxdev *dmxdev) 14658c2ecf20Sopenharmony_ci{ 14668c2ecf20Sopenharmony_ci mutex_lock(&dmxdev->mutex); 14678c2ecf20Sopenharmony_ci dmxdev->exit = 1; 14688c2ecf20Sopenharmony_ci mutex_unlock(&dmxdev->mutex); 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci if (dmxdev->dvbdev->users > 1) { 14718c2ecf20Sopenharmony_ci wait_event(dmxdev->dvbdev->wait_queue, 14728c2ecf20Sopenharmony_ci dmxdev->dvbdev->users == 1); 14738c2ecf20Sopenharmony_ci } 14748c2ecf20Sopenharmony_ci if (dmxdev->dvr_dvbdev->users > 1) { 14758c2ecf20Sopenharmony_ci wait_event(dmxdev->dvr_dvbdev->wait_queue, 14768c2ecf20Sopenharmony_ci dmxdev->dvr_dvbdev->users == 1); 14778c2ecf20Sopenharmony_ci } 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_ci dvb_unregister_device(dmxdev->dvbdev); 14808c2ecf20Sopenharmony_ci dvb_unregister_device(dmxdev->dvr_dvbdev); 14818c2ecf20Sopenharmony_ci 14828c2ecf20Sopenharmony_ci vfree(dmxdev->filter); 14838c2ecf20Sopenharmony_ci dmxdev->filter = NULL; 14848c2ecf20Sopenharmony_ci dmxdev->demux->close(dmxdev->demux); 14858c2ecf20Sopenharmony_ci} 14868c2ecf20Sopenharmony_ci 14878c2ecf20Sopenharmony_ciEXPORT_SYMBOL(dvb_dmxdev_release); 1488