Path: blob/master/drivers/media/dvb/dvb-core/dmxdev.c
15112 views
/*1* dmxdev.c - DVB demultiplexer device2*3* Copyright (C) 2000 Ralph Metzler & Marcus Metzler4* for convergence integrated media GmbH5*6* This program is free software; you can redistribute it and/or7* modify it under the terms of the GNU Lesser General Public License8* as published by the Free Software Foundation; either version 2.19* of the License, or (at your option) any later version.10*11* This program is distributed in the hope that it will be useful,12* but WITHOUT ANY WARRANTY; without even the implied warranty of13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the14* GNU General Public License for more details.15*16* You should have received a copy of the GNU Lesser General Public License17* along with this program; if not, write to the Free Software18* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.19*20*/2122#include <linux/sched.h>23#include <linux/spinlock.h>24#include <linux/slab.h>25#include <linux/vmalloc.h>26#include <linux/module.h>27#include <linux/poll.h>28#include <linux/ioctl.h>29#include <linux/wait.h>30#include <asm/uaccess.h>31#include <asm/system.h>32#include "dmxdev.h"3334static int debug;3536module_param(debug, int, 0644);37MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");3839#define dprintk if (debug) printk4041static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,42const u8 *src, size_t len)43{44ssize_t free;4546if (!len)47return 0;48if (!buf->data)49return 0;5051free = dvb_ringbuffer_free(buf);52if (len > free) {53dprintk("dmxdev: buffer overflow\n");54return -EOVERFLOW;55}5657return dvb_ringbuffer_write(buf, src, len);58}5960static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,61int non_blocking, char __user *buf,62size_t count, loff_t *ppos)63{64size_t todo;65ssize_t avail;66ssize_t ret = 0;6768if (!src->data)69return 0;7071if (src->error) {72ret = src->error;73dvb_ringbuffer_flush(src);74return ret;75}7677for (todo = count; todo > 0; todo -= ret) {78if (non_blocking && dvb_ringbuffer_empty(src)) {79ret = -EWOULDBLOCK;80break;81}8283ret = wait_event_interruptible(src->queue,84!dvb_ringbuffer_empty(src) ||85(src->error != 0));86if (ret < 0)87break;8889if (src->error) {90ret = src->error;91dvb_ringbuffer_flush(src);92break;93}9495avail = dvb_ringbuffer_avail(src);96if (avail > todo)97avail = todo;9899ret = dvb_ringbuffer_read_user(src, buf, avail);100if (ret < 0)101break;102103buf += ret;104}105106return (count - todo) ? (count - todo) : ret;107}108109static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type)110{111struct list_head *head, *pos;112113head = demux->get_frontends(demux);114if (!head)115return NULL;116list_for_each(pos, head)117if (DMX_FE_ENTRY(pos)->source == type)118return DMX_FE_ENTRY(pos);119120return NULL;121}122123static int dvb_dvr_open(struct inode *inode, struct file *file)124{125struct dvb_device *dvbdev = file->private_data;126struct dmxdev *dmxdev = dvbdev->priv;127struct dmx_frontend *front;128129dprintk("function : %s\n", __func__);130131if (mutex_lock_interruptible(&dmxdev->mutex))132return -ERESTARTSYS;133134if (dmxdev->exit) {135mutex_unlock(&dmxdev->mutex);136return -ENODEV;137}138139if ((file->f_flags & O_ACCMODE) == O_RDWR) {140if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {141mutex_unlock(&dmxdev->mutex);142return -EOPNOTSUPP;143}144}145146if ((file->f_flags & O_ACCMODE) == O_RDONLY) {147void *mem;148if (!dvbdev->readers) {149mutex_unlock(&dmxdev->mutex);150return -EBUSY;151}152mem = vmalloc(DVR_BUFFER_SIZE);153if (!mem) {154mutex_unlock(&dmxdev->mutex);155return -ENOMEM;156}157dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);158dvbdev->readers--;159}160161if ((file->f_flags & O_ACCMODE) == O_WRONLY) {162dmxdev->dvr_orig_fe = dmxdev->demux->frontend;163164if (!dmxdev->demux->write) {165mutex_unlock(&dmxdev->mutex);166return -EOPNOTSUPP;167}168169front = get_fe(dmxdev->demux, DMX_MEMORY_FE);170171if (!front) {172mutex_unlock(&dmxdev->mutex);173return -EINVAL;174}175dmxdev->demux->disconnect_frontend(dmxdev->demux);176dmxdev->demux->connect_frontend(dmxdev->demux, front);177}178dvbdev->users++;179mutex_unlock(&dmxdev->mutex);180return 0;181}182183static int dvb_dvr_release(struct inode *inode, struct file *file)184{185struct dvb_device *dvbdev = file->private_data;186struct dmxdev *dmxdev = dvbdev->priv;187188mutex_lock(&dmxdev->mutex);189190if ((file->f_flags & O_ACCMODE) == O_WRONLY) {191dmxdev->demux->disconnect_frontend(dmxdev->demux);192dmxdev->demux->connect_frontend(dmxdev->demux,193dmxdev->dvr_orig_fe);194}195if ((file->f_flags & O_ACCMODE) == O_RDONLY) {196dvbdev->readers++;197if (dmxdev->dvr_buffer.data) {198void *mem = dmxdev->dvr_buffer.data;199mb();200spin_lock_irq(&dmxdev->lock);201dmxdev->dvr_buffer.data = NULL;202spin_unlock_irq(&dmxdev->lock);203vfree(mem);204}205}206/* TODO */207dvbdev->users--;208if (dvbdev->users == 1 && dmxdev->exit == 1) {209fops_put(file->f_op);210file->f_op = NULL;211mutex_unlock(&dmxdev->mutex);212wake_up(&dvbdev->wait_queue);213} else214mutex_unlock(&dmxdev->mutex);215216return 0;217}218219static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,220size_t count, loff_t *ppos)221{222struct dvb_device *dvbdev = file->private_data;223struct dmxdev *dmxdev = dvbdev->priv;224int ret;225226if (!dmxdev->demux->write)227return -EOPNOTSUPP;228if ((file->f_flags & O_ACCMODE) != O_WRONLY)229return -EINVAL;230if (mutex_lock_interruptible(&dmxdev->mutex))231return -ERESTARTSYS;232233if (dmxdev->exit) {234mutex_unlock(&dmxdev->mutex);235return -ENODEV;236}237ret = dmxdev->demux->write(dmxdev->demux, buf, count);238mutex_unlock(&dmxdev->mutex);239return ret;240}241242static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,243loff_t *ppos)244{245struct dvb_device *dvbdev = file->private_data;246struct dmxdev *dmxdev = dvbdev->priv;247248if (dmxdev->exit)249return -ENODEV;250251return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,252file->f_flags & O_NONBLOCK,253buf, count, ppos);254}255256static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,257unsigned long size)258{259struct dvb_ringbuffer *buf = &dmxdev->dvr_buffer;260void *newmem;261void *oldmem;262263dprintk("function : %s\n", __func__);264265if (buf->size == size)266return 0;267if (!size)268return -EINVAL;269270newmem = vmalloc(size);271if (!newmem)272return -ENOMEM;273274oldmem = buf->data;275276spin_lock_irq(&dmxdev->lock);277buf->data = newmem;278buf->size = size;279280/* reset and not flush in case the buffer shrinks */281dvb_ringbuffer_reset(buf);282spin_unlock_irq(&dmxdev->lock);283284vfree(oldmem);285286return 0;287}288289static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter290*dmxdevfilter, int state)291{292spin_lock_irq(&dmxdevfilter->dev->lock);293dmxdevfilter->state = state;294spin_unlock_irq(&dmxdevfilter->dev->lock);295}296297static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter,298unsigned long size)299{300struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;301void *newmem;302void *oldmem;303304if (buf->size == size)305return 0;306if (!size)307return -EINVAL;308if (dmxdevfilter->state >= DMXDEV_STATE_GO)309return -EBUSY;310311newmem = vmalloc(size);312if (!newmem)313return -ENOMEM;314315oldmem = buf->data;316317spin_lock_irq(&dmxdevfilter->dev->lock);318buf->data = newmem;319buf->size = size;320321/* reset and not flush in case the buffer shrinks */322dvb_ringbuffer_reset(buf);323spin_unlock_irq(&dmxdevfilter->dev->lock);324325vfree(oldmem);326327return 0;328}329330static void dvb_dmxdev_filter_timeout(unsigned long data)331{332struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data;333334dmxdevfilter->buffer.error = -ETIMEDOUT;335spin_lock_irq(&dmxdevfilter->dev->lock);336dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;337spin_unlock_irq(&dmxdevfilter->dev->lock);338wake_up(&dmxdevfilter->buffer.queue);339}340341static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)342{343struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec;344345del_timer(&dmxdevfilter->timer);346if (para->timeout) {347dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout;348dmxdevfilter->timer.data = (unsigned long)dmxdevfilter;349dmxdevfilter->timer.expires =350jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000;351add_timer(&dmxdevfilter->timer);352}353}354355static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,356const u8 *buffer2, size_t buffer2_len,357struct dmx_section_filter *filter,358enum dmx_success success)359{360struct dmxdev_filter *dmxdevfilter = filter->priv;361int ret;362363if (dmxdevfilter->buffer.error) {364wake_up(&dmxdevfilter->buffer.queue);365return 0;366}367spin_lock(&dmxdevfilter->dev->lock);368if (dmxdevfilter->state != DMXDEV_STATE_GO) {369spin_unlock(&dmxdevfilter->dev->lock);370return 0;371}372del_timer(&dmxdevfilter->timer);373dprintk("dmxdev: section callback %02x %02x %02x %02x %02x %02x\n",374buffer1[0], buffer1[1],375buffer1[2], buffer1[3], buffer1[4], buffer1[5]);376ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,377buffer1_len);378if (ret == buffer1_len) {379ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2,380buffer2_len);381}382if (ret < 0) {383dvb_ringbuffer_flush(&dmxdevfilter->buffer);384dmxdevfilter->buffer.error = ret;385}386if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)387dmxdevfilter->state = DMXDEV_STATE_DONE;388spin_unlock(&dmxdevfilter->dev->lock);389wake_up(&dmxdevfilter->buffer.queue);390return 0;391}392393static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,394const u8 *buffer2, size_t buffer2_len,395struct dmx_ts_feed *feed,396enum dmx_success success)397{398struct dmxdev_filter *dmxdevfilter = feed->priv;399struct dvb_ringbuffer *buffer;400int ret;401402spin_lock(&dmxdevfilter->dev->lock);403if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {404spin_unlock(&dmxdevfilter->dev->lock);405return 0;406}407408if (dmxdevfilter->params.pes.output == DMX_OUT_TAP409|| dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)410buffer = &dmxdevfilter->buffer;411else412buffer = &dmxdevfilter->dev->dvr_buffer;413if (buffer->error) {414spin_unlock(&dmxdevfilter->dev->lock);415wake_up(&buffer->queue);416return 0;417}418ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);419if (ret == buffer1_len)420ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);421if (ret < 0) {422dvb_ringbuffer_flush(buffer);423buffer->error = ret;424}425spin_unlock(&dmxdevfilter->dev->lock);426wake_up(&buffer->queue);427return 0;428}429430/* stop feed but only mark the specified filter as stopped (state set) */431static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)432{433struct dmxdev_feed *feed;434435dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);436437switch (dmxdevfilter->type) {438case DMXDEV_TYPE_SEC:439del_timer(&dmxdevfilter->timer);440dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec);441break;442case DMXDEV_TYPE_PES:443list_for_each_entry(feed, &dmxdevfilter->feed.ts, next)444feed->ts->stop_filtering(feed->ts);445break;446default:447return -EINVAL;448}449return 0;450}451452/* start feed associated with the specified filter */453static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter)454{455struct dmxdev_feed *feed;456int ret;457458dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);459460switch (filter->type) {461case DMXDEV_TYPE_SEC:462return filter->feed.sec->start_filtering(filter->feed.sec);463case DMXDEV_TYPE_PES:464list_for_each_entry(feed, &filter->feed.ts, next) {465ret = feed->ts->start_filtering(feed->ts);466if (ret < 0) {467dvb_dmxdev_feed_stop(filter);468return ret;469}470}471break;472default:473return -EINVAL;474}475476return 0;477}478479/* restart section feed if it has filters left associated with it,480otherwise release the feed */481static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter)482{483int i;484struct dmxdev *dmxdev = filter->dev;485u16 pid = filter->params.sec.pid;486487for (i = 0; i < dmxdev->filternum; i++)488if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&489dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&490dmxdev->filter[i].params.sec.pid == pid) {491dvb_dmxdev_feed_start(&dmxdev->filter[i]);492return 0;493}494495filter->dev->demux->release_section_feed(dmxdev->demux,496filter->feed.sec);497498return 0;499}500501static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)502{503struct dmxdev_feed *feed;504struct dmx_demux *demux;505506if (dmxdevfilter->state < DMXDEV_STATE_GO)507return 0;508509switch (dmxdevfilter->type) {510case DMXDEV_TYPE_SEC:511if (!dmxdevfilter->feed.sec)512break;513dvb_dmxdev_feed_stop(dmxdevfilter);514if (dmxdevfilter->filter.sec)515dmxdevfilter->feed.sec->516release_filter(dmxdevfilter->feed.sec,517dmxdevfilter->filter.sec);518dvb_dmxdev_feed_restart(dmxdevfilter);519dmxdevfilter->feed.sec = NULL;520break;521case DMXDEV_TYPE_PES:522dvb_dmxdev_feed_stop(dmxdevfilter);523demux = dmxdevfilter->dev->demux;524list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {525demux->release_ts_feed(demux, feed->ts);526feed->ts = NULL;527}528break;529default:530if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED)531return 0;532return -EINVAL;533}534535dvb_ringbuffer_flush(&dmxdevfilter->buffer);536return 0;537}538539static void dvb_dmxdev_delete_pids(struct dmxdev_filter *dmxdevfilter)540{541struct dmxdev_feed *feed, *tmp;542543/* delete all PIDs */544list_for_each_entry_safe(feed, tmp, &dmxdevfilter->feed.ts, next) {545list_del(&feed->next);546kfree(feed);547}548549BUG_ON(!list_empty(&dmxdevfilter->feed.ts));550}551552static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter)553{554if (dmxdevfilter->state < DMXDEV_STATE_SET)555return 0;556557if (dmxdevfilter->type == DMXDEV_TYPE_PES)558dvb_dmxdev_delete_pids(dmxdevfilter);559560dmxdevfilter->type = DMXDEV_TYPE_NONE;561dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);562return 0;563}564565static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,566struct dmxdev_filter *filter,567struct dmxdev_feed *feed)568{569struct timespec timeout = { 0 };570struct dmx_pes_filter_params *para = &filter->params.pes;571dmx_output_t otype;572int ret;573int ts_type;574dmx_pes_type_t ts_pes;575struct dmx_ts_feed *tsfeed;576577feed->ts = NULL;578otype = para->output;579580ts_pes = para->pes_type;581582if (ts_pes < DMX_PES_OTHER)583ts_type = TS_DECODER;584else585ts_type = 0;586587if (otype == DMX_OUT_TS_TAP)588ts_type |= TS_PACKET;589else if (otype == DMX_OUT_TSDEMUX_TAP)590ts_type |= TS_PACKET | TS_DEMUX;591else if (otype == DMX_OUT_TAP)592ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY;593594ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, &feed->ts,595dvb_dmxdev_ts_callback);596if (ret < 0)597return ret;598599tsfeed = feed->ts;600tsfeed->priv = filter;601602ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout);603if (ret < 0) {604dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);605return ret;606}607608ret = tsfeed->start_filtering(tsfeed);609if (ret < 0) {610dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);611return ret;612}613614return 0;615}616617static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)618{619struct dmxdev *dmxdev = filter->dev;620struct dmxdev_feed *feed;621void *mem;622int ret, i;623624if (filter->state < DMXDEV_STATE_SET)625return -EINVAL;626627if (filter->state >= DMXDEV_STATE_GO)628dvb_dmxdev_filter_stop(filter);629630if (!filter->buffer.data) {631mem = vmalloc(filter->buffer.size);632if (!mem)633return -ENOMEM;634spin_lock_irq(&filter->dev->lock);635filter->buffer.data = mem;636spin_unlock_irq(&filter->dev->lock);637}638639dvb_ringbuffer_flush(&filter->buffer);640641switch (filter->type) {642case DMXDEV_TYPE_SEC:643{644struct dmx_sct_filter_params *para = &filter->params.sec;645struct dmx_section_filter **secfilter = &filter->filter.sec;646struct dmx_section_feed **secfeed = &filter->feed.sec;647648*secfilter = NULL;649*secfeed = NULL;650651652/* find active filter/feed with same PID */653for (i = 0; i < dmxdev->filternum; i++) {654if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&655dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&656dmxdev->filter[i].params.sec.pid == para->pid) {657*secfeed = dmxdev->filter[i].feed.sec;658break;659}660}661662/* if no feed found, try to allocate new one */663if (!*secfeed) {664ret = dmxdev->demux->allocate_section_feed(dmxdev->demux,665secfeed,666dvb_dmxdev_section_callback);667if (ret < 0) {668printk("DVB (%s): could not alloc feed\n",669__func__);670return ret;671}672673ret = (*secfeed)->set(*secfeed, para->pid, 32768,674(para->flags & DMX_CHECK_CRC) ? 1 : 0);675if (ret < 0) {676printk("DVB (%s): could not set feed\n",677__func__);678dvb_dmxdev_feed_restart(filter);679return ret;680}681} else {682dvb_dmxdev_feed_stop(filter);683}684685ret = (*secfeed)->allocate_filter(*secfeed, secfilter);686if (ret < 0) {687dvb_dmxdev_feed_restart(filter);688filter->feed.sec->start_filtering(*secfeed);689dprintk("could not get filter\n");690return ret;691}692693(*secfilter)->priv = filter;694695memcpy(&((*secfilter)->filter_value[3]),696&(para->filter.filter[1]), DMX_FILTER_SIZE - 1);697memcpy(&(*secfilter)->filter_mask[3],698¶->filter.mask[1], DMX_FILTER_SIZE - 1);699memcpy(&(*secfilter)->filter_mode[3],700¶->filter.mode[1], DMX_FILTER_SIZE - 1);701702(*secfilter)->filter_value[0] = para->filter.filter[0];703(*secfilter)->filter_mask[0] = para->filter.mask[0];704(*secfilter)->filter_mode[0] = para->filter.mode[0];705(*secfilter)->filter_mask[1] = 0;706(*secfilter)->filter_mask[2] = 0;707708filter->todo = 0;709710ret = filter->feed.sec->start_filtering(filter->feed.sec);711if (ret < 0)712return ret;713714dvb_dmxdev_filter_timer(filter);715break;716}717case DMXDEV_TYPE_PES:718list_for_each_entry(feed, &filter->feed.ts, next) {719ret = dvb_dmxdev_start_feed(dmxdev, filter, feed);720if (ret < 0) {721dvb_dmxdev_filter_stop(filter);722return ret;723}724}725break;726default:727return -EINVAL;728}729730dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);731return 0;732}733734static int dvb_demux_open(struct inode *inode, struct file *file)735{736struct dvb_device *dvbdev = file->private_data;737struct dmxdev *dmxdev = dvbdev->priv;738int i;739struct dmxdev_filter *dmxdevfilter;740741if (!dmxdev->filter)742return -EINVAL;743744if (mutex_lock_interruptible(&dmxdev->mutex))745return -ERESTARTSYS;746747for (i = 0; i < dmxdev->filternum; i++)748if (dmxdev->filter[i].state == DMXDEV_STATE_FREE)749break;750751if (i == dmxdev->filternum) {752mutex_unlock(&dmxdev->mutex);753return -EMFILE;754}755756dmxdevfilter = &dmxdev->filter[i];757mutex_init(&dmxdevfilter->mutex);758file->private_data = dmxdevfilter;759760dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);761dmxdevfilter->type = DMXDEV_TYPE_NONE;762dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);763init_timer(&dmxdevfilter->timer);764765dvbdev->users++;766767mutex_unlock(&dmxdev->mutex);768return 0;769}770771static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,772struct dmxdev_filter *dmxdevfilter)773{774mutex_lock(&dmxdev->mutex);775mutex_lock(&dmxdevfilter->mutex);776777dvb_dmxdev_filter_stop(dmxdevfilter);778dvb_dmxdev_filter_reset(dmxdevfilter);779780if (dmxdevfilter->buffer.data) {781void *mem = dmxdevfilter->buffer.data;782783spin_lock_irq(&dmxdev->lock);784dmxdevfilter->buffer.data = NULL;785spin_unlock_irq(&dmxdev->lock);786vfree(mem);787}788789dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE);790wake_up(&dmxdevfilter->buffer.queue);791mutex_unlock(&dmxdevfilter->mutex);792mutex_unlock(&dmxdev->mutex);793return 0;794}795796static inline void invert_mode(dmx_filter_t *filter)797{798int i;799800for (i = 0; i < DMX_FILTER_SIZE; i++)801filter->mode[i] ^= 0xff;802}803804static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev,805struct dmxdev_filter *filter, u16 pid)806{807struct dmxdev_feed *feed;808809if ((filter->type != DMXDEV_TYPE_PES) ||810(filter->state < DMXDEV_STATE_SET))811return -EINVAL;812813/* only TS packet filters may have multiple PIDs */814if ((filter->params.pes.output != DMX_OUT_TSDEMUX_TAP) &&815(!list_empty(&filter->feed.ts)))816return -EINVAL;817818feed = kzalloc(sizeof(struct dmxdev_feed), GFP_KERNEL);819if (feed == NULL)820return -ENOMEM;821822feed->pid = pid;823list_add(&feed->next, &filter->feed.ts);824825if (filter->state >= DMXDEV_STATE_GO)826return dvb_dmxdev_start_feed(dmxdev, filter, feed);827828return 0;829}830831static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev,832struct dmxdev_filter *filter, u16 pid)833{834struct dmxdev_feed *feed, *tmp;835836if ((filter->type != DMXDEV_TYPE_PES) ||837(filter->state < DMXDEV_STATE_SET))838return -EINVAL;839840list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) {841if ((feed->pid == pid) && (feed->ts != NULL)) {842feed->ts->stop_filtering(feed->ts);843filter->dev->demux->release_ts_feed(filter->dev->demux,844feed->ts);845list_del(&feed->next);846kfree(feed);847}848}849850return 0;851}852853static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,854struct dmxdev_filter *dmxdevfilter,855struct dmx_sct_filter_params *params)856{857dprintk("function : %s\n", __func__);858859dvb_dmxdev_filter_stop(dmxdevfilter);860861dmxdevfilter->type = DMXDEV_TYPE_SEC;862memcpy(&dmxdevfilter->params.sec,863params, sizeof(struct dmx_sct_filter_params));864invert_mode(&dmxdevfilter->params.sec.filter);865dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);866867if (params->flags & DMX_IMMEDIATE_START)868return dvb_dmxdev_filter_start(dmxdevfilter);869870return 0;871}872873static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,874struct dmxdev_filter *dmxdevfilter,875struct dmx_pes_filter_params *params)876{877int ret;878879dvb_dmxdev_filter_stop(dmxdevfilter);880dvb_dmxdev_filter_reset(dmxdevfilter);881882if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0)883return -EINVAL;884885dmxdevfilter->type = DMXDEV_TYPE_PES;886memcpy(&dmxdevfilter->params, params,887sizeof(struct dmx_pes_filter_params));888INIT_LIST_HEAD(&dmxdevfilter->feed.ts);889890dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);891892ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter,893dmxdevfilter->params.pes.pid);894if (ret < 0)895return ret;896897if (params->flags & DMX_IMMEDIATE_START)898return dvb_dmxdev_filter_start(dmxdevfilter);899900return 0;901}902903static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil,904struct file *file, char __user *buf,905size_t count, loff_t *ppos)906{907int result, hcount;908int done = 0;909910if (dfil->todo <= 0) {911hcount = 3 + dfil->todo;912if (hcount > count)913hcount = count;914result = dvb_dmxdev_buffer_read(&dfil->buffer,915file->f_flags & O_NONBLOCK,916buf, hcount, ppos);917if (result < 0) {918dfil->todo = 0;919return result;920}921if (copy_from_user(dfil->secheader - dfil->todo, buf, result))922return -EFAULT;923buf += result;924done = result;925count -= result;926dfil->todo -= result;927if (dfil->todo > -3)928return done;929dfil->todo = ((dfil->secheader[1] << 8) | dfil->secheader[2]) & 0xfff;930if (!count)931return done;932}933if (count > dfil->todo)934count = dfil->todo;935result = dvb_dmxdev_buffer_read(&dfil->buffer,936file->f_flags & O_NONBLOCK,937buf, count, ppos);938if (result < 0)939return result;940dfil->todo -= result;941return (result + done);942}943944static ssize_t945dvb_demux_read(struct file *file, char __user *buf, size_t count,946loff_t *ppos)947{948struct dmxdev_filter *dmxdevfilter = file->private_data;949int ret;950951if (mutex_lock_interruptible(&dmxdevfilter->mutex))952return -ERESTARTSYS;953954if (dmxdevfilter->type == DMXDEV_TYPE_SEC)955ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);956else957ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,958file->f_flags & O_NONBLOCK,959buf, count, ppos);960961mutex_unlock(&dmxdevfilter->mutex);962return ret;963}964965static int dvb_demux_do_ioctl(struct file *file,966unsigned int cmd, void *parg)967{968struct dmxdev_filter *dmxdevfilter = file->private_data;969struct dmxdev *dmxdev = dmxdevfilter->dev;970unsigned long arg = (unsigned long)parg;971int ret = 0;972973if (mutex_lock_interruptible(&dmxdev->mutex))974return -ERESTARTSYS;975976switch (cmd) {977case DMX_START:978if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {979mutex_unlock(&dmxdev->mutex);980return -ERESTARTSYS;981}982if (dmxdevfilter->state < DMXDEV_STATE_SET)983ret = -EINVAL;984else985ret = dvb_dmxdev_filter_start(dmxdevfilter);986mutex_unlock(&dmxdevfilter->mutex);987break;988989case DMX_STOP:990if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {991mutex_unlock(&dmxdev->mutex);992return -ERESTARTSYS;993}994ret = dvb_dmxdev_filter_stop(dmxdevfilter);995mutex_unlock(&dmxdevfilter->mutex);996break;997998case DMX_SET_FILTER:999if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {1000mutex_unlock(&dmxdev->mutex);1001return -ERESTARTSYS;1002}1003ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg);1004mutex_unlock(&dmxdevfilter->mutex);1005break;10061007case DMX_SET_PES_FILTER:1008if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {1009mutex_unlock(&dmxdev->mutex);1010return -ERESTARTSYS;1011}1012ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg);1013mutex_unlock(&dmxdevfilter->mutex);1014break;10151016case DMX_SET_BUFFER_SIZE:1017if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {1018mutex_unlock(&dmxdev->mutex);1019return -ERESTARTSYS;1020}1021ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg);1022mutex_unlock(&dmxdevfilter->mutex);1023break;10241025case DMX_GET_PES_PIDS:1026if (!dmxdev->demux->get_pes_pids) {1027ret = -EINVAL;1028break;1029}1030dmxdev->demux->get_pes_pids(dmxdev->demux, parg);1031break;10321033case DMX_GET_CAPS:1034if (!dmxdev->demux->get_caps) {1035ret = -EINVAL;1036break;1037}1038ret = dmxdev->demux->get_caps(dmxdev->demux, parg);1039break;10401041case DMX_SET_SOURCE:1042if (!dmxdev->demux->set_source) {1043ret = -EINVAL;1044break;1045}1046ret = dmxdev->demux->set_source(dmxdev->demux, parg);1047break;10481049case DMX_GET_STC:1050if (!dmxdev->demux->get_stc) {1051ret = -EINVAL;1052break;1053}1054ret = dmxdev->demux->get_stc(dmxdev->demux,1055((struct dmx_stc *)parg)->num,1056&((struct dmx_stc *)parg)->stc,1057&((struct dmx_stc *)parg)->base);1058break;10591060case DMX_ADD_PID:1061if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {1062ret = -ERESTARTSYS;1063break;1064}1065ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, *(u16 *)parg);1066mutex_unlock(&dmxdevfilter->mutex);1067break;10681069case DMX_REMOVE_PID:1070if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {1071ret = -ERESTARTSYS;1072break;1073}1074ret = dvb_dmxdev_remove_pid(dmxdev, dmxdevfilter, *(u16 *)parg);1075mutex_unlock(&dmxdevfilter->mutex);1076break;10771078default:1079ret = -EINVAL;1080break;1081}1082mutex_unlock(&dmxdev->mutex);1083return ret;1084}10851086static long dvb_demux_ioctl(struct file *file, unsigned int cmd,1087unsigned long arg)1088{1089return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl);1090}10911092static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)1093{1094struct dmxdev_filter *dmxdevfilter = file->private_data;1095unsigned int mask = 0;10961097if (!dmxdevfilter)1098return -EINVAL;10991100poll_wait(file, &dmxdevfilter->buffer.queue, wait);11011102if (dmxdevfilter->state != DMXDEV_STATE_GO &&1103dmxdevfilter->state != DMXDEV_STATE_DONE &&1104dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT)1105return 0;11061107if (dmxdevfilter->buffer.error)1108mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);11091110if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))1111mask |= (POLLIN | POLLRDNORM | POLLPRI);11121113return mask;1114}11151116static int dvb_demux_release(struct inode *inode, struct file *file)1117{1118struct dmxdev_filter *dmxdevfilter = file->private_data;1119struct dmxdev *dmxdev = dmxdevfilter->dev;11201121int ret;11221123ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);11241125mutex_lock(&dmxdev->mutex);1126dmxdev->dvbdev->users--;1127if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) {1128fops_put(file->f_op);1129file->f_op = NULL;1130mutex_unlock(&dmxdev->mutex);1131wake_up(&dmxdev->dvbdev->wait_queue);1132} else1133mutex_unlock(&dmxdev->mutex);11341135return ret;1136}11371138static const struct file_operations dvb_demux_fops = {1139.owner = THIS_MODULE,1140.read = dvb_demux_read,1141.unlocked_ioctl = dvb_demux_ioctl,1142.open = dvb_demux_open,1143.release = dvb_demux_release,1144.poll = dvb_demux_poll,1145.llseek = default_llseek,1146};11471148static struct dvb_device dvbdev_demux = {1149.priv = NULL,1150.users = 1,1151.writers = 1,1152.fops = &dvb_demux_fops1153};11541155static int dvb_dvr_do_ioctl(struct file *file,1156unsigned int cmd, void *parg)1157{1158struct dvb_device *dvbdev = file->private_data;1159struct dmxdev *dmxdev = dvbdev->priv;1160unsigned long arg = (unsigned long)parg;1161int ret;11621163if (mutex_lock_interruptible(&dmxdev->mutex))1164return -ERESTARTSYS;11651166switch (cmd) {1167case DMX_SET_BUFFER_SIZE:1168ret = dvb_dvr_set_buffer_size(dmxdev, arg);1169break;11701171default:1172ret = -EINVAL;1173break;1174}1175mutex_unlock(&dmxdev->mutex);1176return ret;1177}11781179static long dvb_dvr_ioctl(struct file *file,1180unsigned int cmd, unsigned long arg)1181{1182return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl);1183}11841185static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)1186{1187struct dvb_device *dvbdev = file->private_data;1188struct dmxdev *dmxdev = dvbdev->priv;1189unsigned int mask = 0;11901191dprintk("function : %s\n", __func__);11921193poll_wait(file, &dmxdev->dvr_buffer.queue, wait);11941195if ((file->f_flags & O_ACCMODE) == O_RDONLY) {1196if (dmxdev->dvr_buffer.error)1197mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);11981199if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))1200mask |= (POLLIN | POLLRDNORM | POLLPRI);1201} else1202mask |= (POLLOUT | POLLWRNORM | POLLPRI);12031204return mask;1205}12061207static const struct file_operations dvb_dvr_fops = {1208.owner = THIS_MODULE,1209.read = dvb_dvr_read,1210.write = dvb_dvr_write,1211.unlocked_ioctl = dvb_dvr_ioctl,1212.open = dvb_dvr_open,1213.release = dvb_dvr_release,1214.poll = dvb_dvr_poll,1215.llseek = default_llseek,1216};12171218static struct dvb_device dvbdev_dvr = {1219.priv = NULL,1220.readers = 1,1221.users = 1,1222.fops = &dvb_dvr_fops1223};12241225int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)1226{1227int i;12281229if (dmxdev->demux->open(dmxdev->demux) < 0)1230return -EUSERS;12311232dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter));1233if (!dmxdev->filter)1234return -ENOMEM;12351236mutex_init(&dmxdev->mutex);1237spin_lock_init(&dmxdev->lock);1238for (i = 0; i < dmxdev->filternum; i++) {1239dmxdev->filter[i].dev = dmxdev;1240dmxdev->filter[i].buffer.data = NULL;1241dvb_dmxdev_filter_state_set(&dmxdev->filter[i],1242DMXDEV_STATE_FREE);1243}12441245dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,1246DVB_DEVICE_DEMUX);1247dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,1248dmxdev, DVB_DEVICE_DVR);12491250dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);12511252return 0;1253}12541255EXPORT_SYMBOL(dvb_dmxdev_init);12561257void dvb_dmxdev_release(struct dmxdev *dmxdev)1258{1259dmxdev->exit=1;1260if (dmxdev->dvbdev->users > 1) {1261wait_event(dmxdev->dvbdev->wait_queue,1262dmxdev->dvbdev->users==1);1263}1264if (dmxdev->dvr_dvbdev->users > 1) {1265wait_event(dmxdev->dvr_dvbdev->wait_queue,1266dmxdev->dvr_dvbdev->users==1);1267}12681269dvb_unregister_device(dmxdev->dvbdev);1270dvb_unregister_device(dmxdev->dvr_dvbdev);12711272vfree(dmxdev->filter);1273dmxdev->filter = NULL;1274dmxdev->demux->close(dmxdev->demux);1275}12761277EXPORT_SYMBOL(dvb_dmxdev_release);127812791280