#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/ioctl.h>
#include <linux/wait.h>
#define dprintk if (debug) printk
-static inline void dvb_dmxdev_buffer_init(struct dmxdev_buffer *buffer)
+static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
+ const u8 *src, size_t len)
{
- buffer->data = NULL;
- buffer->size = 8192;
- buffer->pread = 0;
- buffer->pwrite = 0;
- buffer->error = 0;
- init_waitqueue_head(&buffer->queue);
-}
-
-static inline int dvb_dmxdev_buffer_write(struct dmxdev_buffer *buf,
- const u8 *src, int len)
-{
- int split;
- int free;
- int todo;
+ ssize_t free;
if (!len)
return 0;
if (!buf->data)
return 0;
- free = buf->pread - buf->pwrite;
- split = 0;
- if (free <= 0) {
- free += buf->size;
- split = buf->size - buf->pwrite;
- }
- if (len >= free) {
+ free = dvb_ringbuffer_free(buf);
+ if (len > free) {
dprintk("dmxdev: buffer overflow\n");
- return -1;
+ return -EOVERFLOW;
}
- if (split >= len)
- split = 0;
- todo = len;
- if (split) {
- memcpy(buf->data + buf->pwrite, src, split);
- todo -= split;
- buf->pwrite = 0;
- }
- memcpy(buf->data + buf->pwrite, src + split, todo);
- buf->pwrite = (buf->pwrite + todo) % buf->size;
- return len;
+
+ return dvb_ringbuffer_write(buf, src, len);
}
-static ssize_t dvb_dmxdev_buffer_read(struct dmxdev_buffer *src,
+static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
int non_blocking, char __user *buf,
size_t count, loff_t *ppos)
{
- unsigned long todo = count;
- int split, avail, error;
+ size_t todo;
+ ssize_t avail;
+ ssize_t ret = 0;
if (!src->data)
return 0;
- if ((error = src->error)) {
- src->pwrite = src->pread;
- src->error = 0;
- return error;
+ if (src->error) {
+ ret = src->error;
+ dvb_ringbuffer_flush(src);
+ return ret;
}
- if (non_blocking && (src->pwrite == src->pread))
- return -EWOULDBLOCK;
-
- while (todo > 0) {
- if (non_blocking && (src->pwrite == src->pread))
- return (count - todo) ? (count - todo) : -EWOULDBLOCK;
+ for (todo = count; todo > 0; todo -= ret) {
+ if (non_blocking && dvb_ringbuffer_empty(src)) {
+ ret = -EWOULDBLOCK;
+ break;
+ }
- if (wait_event_interruptible(src->queue,
- (src->pread != src->pwrite) ||
- (src->error)) < 0)
- return count - todo;
+ ret = wait_event_interruptible(src->queue,
+ !dvb_ringbuffer_empty(src) ||
+ (src->error != 0));
+ if (ret < 0)
+ break;
- if ((error = src->error)) {
- src->pwrite = src->pread;
- src->error = 0;
- return error;
+ if (src->error) {
+ ret = src->error;
+ dvb_ringbuffer_flush(src);
+ break;
}
- split = src->size;
- avail = src->pwrite - src->pread;
- if (avail < 0) {
- avail += src->size;
- split = src->size - src->pread;
- }
+ avail = dvb_ringbuffer_avail(src);
if (avail > todo)
avail = todo;
- if (split < avail) {
- if (copy_to_user(buf, src->data + src->pread, split))
- return -EFAULT;
- buf += split;
- src->pread = 0;
- todo -= split;
- avail -= split;
- }
- if (avail) {
- if (copy_to_user(buf, src->data + src->pread, avail))
- return -EFAULT;
- src->pread = (src->pread + avail) % src->size;
- todo -= avail;
- buf += avail;
- }
+
+ ret = dvb_ringbuffer_read_user(src, buf, avail);
+ if (ret < 0)
+ break;
+
+ buf += ret;
}
- return count;
+
+ return (count - todo) ? (count - todo) : ret;
}
static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type)
struct dmxdev *dmxdev = dvbdev->priv;
struct dmx_frontend *front;
- dprintk("function : %s\n", __FUNCTION__);
+ dprintk("function : %s\n", __func__);
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
+ if (dmxdev->exit) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ENODEV;
+ }
+
if ((file->f_flags & O_ACCMODE) == O_RDWR) {
if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
mutex_unlock(&dmxdev->mutex);
}
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
- dvb_dmxdev_buffer_init(&dmxdev->dvr_buffer);
- dmxdev->dvr_buffer.size = DVR_BUFFER_SIZE;
- dmxdev->dvr_buffer.data = vmalloc(DVR_BUFFER_SIZE);
- if (!dmxdev->dvr_buffer.data) {
+ void *mem;
+ if (!dvbdev->readers) {
+ mutex_unlock(&dmxdev->mutex);
+ return -EBUSY;
+ }
+ mem = vmalloc(DVR_BUFFER_SIZE);
+ if (!mem) {
mutex_unlock(&dmxdev->mutex);
return -ENOMEM;
}
+ dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
+ dvbdev->readers--;
}
if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
dmxdev->demux->disconnect_frontend(dmxdev->demux);
dmxdev->demux->connect_frontend(dmxdev->demux, front);
}
+ dvbdev->users++;
mutex_unlock(&dmxdev->mutex);
return 0;
}
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
- if (mutex_lock_interruptible(&dmxdev->mutex))
- return -ERESTARTSYS;
+ mutex_lock(&dmxdev->mutex);
if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
dmxdev->demux->disconnect_frontend(dmxdev->demux);
dmxdev->dvr_orig_fe);
}
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+ dvbdev->readers++;
if (dmxdev->dvr_buffer.data) {
void *mem = dmxdev->dvr_buffer.data;
mb();
vfree(mem);
}
}
- mutex_unlock(&dmxdev->mutex);
+ /* TODO */
+ dvbdev->users--;
+ if(dvbdev->users==-1 && dmxdev->exit==1) {
+ fops_put(file->f_op);
+ file->f_op = NULL;
+ mutex_unlock(&dmxdev->mutex);
+ wake_up(&dvbdev->wait_queue);
+ } else
+ mutex_unlock(&dmxdev->mutex);
+
return 0;
}
return -EINVAL;
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
+
+ if (dmxdev->exit) {
+ mutex_unlock(&dmxdev->mutex);
+ return -ENODEV;
+ }
ret = dmxdev->demux->write(dmxdev->demux, buf, count);
mutex_unlock(&dmxdev->mutex);
return ret;
{
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
- int ret;
- //mutex_lock(&dmxdev->mutex);
- ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
- file->f_flags & O_NONBLOCK,
- buf, count, ppos);
- //mutex_unlock(&dmxdev->mutex);
- return ret;
+ if (dmxdev->exit)
+ return -ENODEV;
+
+ return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
+ file->f_flags & O_NONBLOCK,
+ buf, count, ppos);
+}
+
+static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
+ unsigned long size)
+{
+ struct dvb_ringbuffer *buf = &dmxdev->dvr_buffer;
+ void *newmem;
+ void *oldmem;
+
+ dprintk("function : %s\n", __func__);
+
+ if (buf->size == size)
+ return 0;
+ if (!size)
+ return -EINVAL;
+
+ newmem = vmalloc(size);
+ if (!newmem)
+ return -ENOMEM;
+
+ oldmem = buf->data;
+
+ spin_lock_irq(&dmxdev->lock);
+ buf->data = newmem;
+ buf->size = size;
+
+ /* reset and not flush in case the buffer shrinks */
+ dvb_ringbuffer_reset(buf);
+ spin_unlock_irq(&dmxdev->lock);
+
+ vfree(oldmem);
+
+ return 0;
}
static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter
static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter,
unsigned long size)
{
- struct dmxdev_buffer *buf = &dmxdevfilter->buffer;
- void *mem;
+ struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
+ void *newmem;
+ void *oldmem;
if (buf->size == size)
return 0;
+ if (!size)
+ return -EINVAL;
if (dmxdevfilter->state >= DMXDEV_STATE_GO)
return -EBUSY;
+
+ newmem = vmalloc(size);
+ if (!newmem)
+ return -ENOMEM;
+
+ oldmem = buf->data;
+
spin_lock_irq(&dmxdevfilter->dev->lock);
- mem = buf->data;
- buf->data = NULL;
+ buf->data = newmem;
buf->size = size;
- buf->pwrite = buf->pread = 0;
+
+ /* reset and not flush in case the buffer shrinks */
+ dvb_ringbuffer_reset(buf);
spin_unlock_irq(&dmxdevfilter->dev->lock);
- vfree(mem);
- if (buf->size) {
- mem = vmalloc(dmxdevfilter->buffer.size);
- if (!mem)
- return -ENOMEM;
- spin_lock_irq(&dmxdevfilter->dev->lock);
- buf->data = mem;
- spin_unlock_irq(&dmxdevfilter->dev->lock);
- }
+ vfree(oldmem);
+
return 0;
}
buffer2_len);
}
if (ret < 0) {
- dmxdevfilter->buffer.pwrite = dmxdevfilter->buffer.pread;
- dmxdevfilter->buffer.error = -EOVERFLOW;
+ dvb_ringbuffer_flush(&dmxdevfilter->buffer);
+ dmxdevfilter->buffer.error = ret;
}
if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
dmxdevfilter->state = DMXDEV_STATE_DONE;
enum dmx_success success)
{
struct dmxdev_filter *dmxdevfilter = feed->priv;
- struct dmxdev_buffer *buffer;
+ struct dvb_ringbuffer *buffer;
int ret;
spin_lock(&dmxdevfilter->dev->lock);
return 0;
}
- if (dmxdevfilter->params.pes.output == DMX_OUT_TAP)
+ if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
+ || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
buffer = &dmxdevfilter->buffer;
else
buffer = &dmxdevfilter->dev->dvr_buffer;
if (ret == buffer1_len)
ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
if (ret < 0) {
- buffer->pwrite = buffer->pread;
- buffer->error = -EOVERFLOW;
+ dvb_ringbuffer_flush(buffer);
+ buffer->error = ret;
}
spin_unlock(&dmxdevfilter->dev->lock);
wake_up(&buffer->queue);
/* stop feed but only mark the specified filter as stopped (state set) */
static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
{
+ struct dmxdev_feed *feed;
+
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
switch (dmxdevfilter->type) {
dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec);
break;
case DMXDEV_TYPE_PES:
- dmxdevfilter->feed.ts->stop_filtering(dmxdevfilter->feed.ts);
+ list_for_each_entry(feed, &dmxdevfilter->feed.ts, next)
+ feed->ts->stop_filtering(feed->ts);
break;
default:
return -EINVAL;
/* start feed associated with the specified filter */
static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter)
{
+ struct dmxdev_feed *feed;
+ int ret;
+
dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
switch (filter->type) {
case DMXDEV_TYPE_SEC:
return filter->feed.sec->start_filtering(filter->feed.sec);
case DMXDEV_TYPE_PES:
- return filter->feed.ts->start_filtering(filter->feed.ts);
+ list_for_each_entry(feed, &filter->feed.ts, next) {
+ ret = feed->ts->start_filtering(feed->ts);
+ if (ret < 0) {
+ dvb_dmxdev_feed_stop(filter);
+ return ret;
+ }
+ }
+ break;
default:
return -EINVAL;
}
static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
{
+ struct dmxdev_feed *feed;
+ struct dmx_demux *demux;
+
if (dmxdevfilter->state < DMXDEV_STATE_GO)
return 0;
dmxdevfilter->feed.sec = NULL;
break;
case DMXDEV_TYPE_PES:
- if (!dmxdevfilter->feed.ts)
- break;
dvb_dmxdev_feed_stop(dmxdevfilter);
- dmxdevfilter->dev->demux->
- release_ts_feed(dmxdevfilter->dev->demux,
- dmxdevfilter->feed.ts);
- dmxdevfilter->feed.ts = NULL;
+ demux = dmxdevfilter->dev->demux;
+ list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
+ demux->release_ts_feed(demux, feed->ts);
+ feed->ts = NULL;
+ }
break;
default:
if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED)
return 0;
return -EINVAL;
}
- dmxdevfilter->buffer.pwrite = dmxdevfilter->buffer.pread = 0;
+
+ dvb_ringbuffer_flush(&dmxdevfilter->buffer);
return 0;
}
+static void dvb_dmxdev_delete_pids(struct dmxdev_filter *dmxdevfilter)
+{
+ struct dmxdev_feed *feed, *tmp;
+
+ /* delete all PIDs */
+ list_for_each_entry_safe(feed, tmp, &dmxdevfilter->feed.ts, next) {
+ list_del(&feed->next);
+ kfree(feed);
+ }
+
+ BUG_ON(!list_empty(&dmxdevfilter->feed.ts));
+}
+
static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter)
{
if (dmxdevfilter->state < DMXDEV_STATE_SET)
return 0;
+ if (dmxdevfilter->type == DMXDEV_TYPE_PES)
+ dvb_dmxdev_delete_pids(dmxdevfilter);
+
dmxdevfilter->type = DMXDEV_TYPE_NONE;
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
return 0;
}
+static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
+ struct dmxdev_filter *filter,
+ struct dmxdev_feed *feed)
+{
+ struct timespec timeout = { 0 };
+ struct dmx_pes_filter_params *para = &filter->params.pes;
+ dmx_output_t otype;
+ int ret;
+ int ts_type;
+ enum dmx_ts_pes ts_pes;
+ struct dmx_ts_feed *tsfeed;
+
+ feed->ts = NULL;
+ otype = para->output;
+
+ ts_pes = (enum dmx_ts_pes)para->pes_type;
+
+ if (ts_pes < DMX_PES_OTHER)
+ ts_type = TS_DECODER;
+ else
+ ts_type = 0;
+
+ if (otype == DMX_OUT_TS_TAP)
+ ts_type |= TS_PACKET;
+ else if (otype == DMX_OUT_TSDEMUX_TAP)
+ ts_type |= TS_PACKET | TS_DEMUX;
+ else if (otype == DMX_OUT_TAP)
+ ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY;
+
+ ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, &feed->ts,
+ dvb_dmxdev_ts_callback);
+ if (ret < 0)
+ return ret;
+
+ tsfeed = feed->ts;
+ tsfeed->priv = filter;
+
+ ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout);
+ if (ret < 0) {
+ dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
+ return ret;
+ }
+
+ ret = tsfeed->start_filtering(tsfeed);
+ if (ret < 0) {
+ dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
+ return ret;
+ }
+
+ return 0;
+}
+
static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
{
struct dmxdev *dmxdev = filter->dev;
+ struct dmxdev_feed *feed;
void *mem;
int ret, i;
if (filter->state >= DMXDEV_STATE_GO)
dvb_dmxdev_filter_stop(filter);
- if (!(mem = filter->buffer.data)) {
+ if (!filter->buffer.data) {
mem = vmalloc(filter->buffer.size);
+ if (!mem)
+ return -ENOMEM;
spin_lock_irq(&filter->dev->lock);
filter->buffer.data = mem;
spin_unlock_irq(&filter->dev->lock);
- if (!filter->buffer.data)
- return -ENOMEM;
}
- filter->buffer.pwrite = filter->buffer.pread = 0;
+ dvb_ringbuffer_flush(&filter->buffer);
switch (filter->type) {
case DMXDEV_TYPE_SEC:
dvb_dmxdev_section_callback);
if (ret < 0) {
printk("DVB (%s): could not alloc feed\n",
- __FUNCTION__);
+ __func__);
return ret;
}
(para->flags & DMX_CHECK_CRC) ? 1 : 0);
if (ret < 0) {
printk("DVB (%s): could not set feed\n",
- __FUNCTION__);
+ __func__);
dvb_dmxdev_feed_restart(filter);
return ret;
}
break;
}
case DMXDEV_TYPE_PES:
- {
- struct timespec timeout = { 0 };
- struct dmx_pes_filter_params *para = &filter->params.pes;
- dmx_output_t otype;
- int ret;
- int ts_type;
- enum dmx_ts_pes ts_pes;
- struct dmx_ts_feed **tsfeed = &filter->feed.ts;
-
- filter->feed.ts = NULL;
- otype = para->output;
-
- ts_pes = (enum dmx_ts_pes)para->pes_type;
-
- if (ts_pes < DMX_PES_OTHER)
- ts_type = TS_DECODER;
- else
- ts_type = 0;
-
- if (otype == DMX_OUT_TS_TAP)
- ts_type |= TS_PACKET;
-
- if (otype == DMX_OUT_TAP)
- ts_type |= TS_PAYLOAD_ONLY | TS_PACKET;
-
- ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux,
- tsfeed,
- dvb_dmxdev_ts_callback);
- if (ret < 0)
- return ret;
-
- (*tsfeed)->priv = filter;
-
- ret = (*tsfeed)->set(*tsfeed, para->pid, ts_type, ts_pes,
- 32768, timeout);
- if (ret < 0) {
- dmxdev->demux->release_ts_feed(dmxdev->demux,
- *tsfeed);
- return ret;
- }
-
- ret = filter->feed.ts->start_filtering(filter->feed.ts);
- if (ret < 0) {
- dmxdev->demux->release_ts_feed(dmxdev->demux,
- *tsfeed);
- return ret;
+ list_for_each_entry(feed, &filter->feed.ts, next) {
+ ret = dvb_dmxdev_start_feed(dmxdev, filter, feed);
+ if (ret < 0) {
+ dvb_dmxdev_filter_stop(filter);
+ return ret;
+ }
}
-
break;
- }
default:
return -EINVAL;
}
mutex_init(&dmxdevfilter->mutex);
file->private_data = dmxdevfilter;
- dvb_dmxdev_buffer_init(&dmxdevfilter->buffer);
+ dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
dmxdevfilter->type = DMXDEV_TYPE_NONE;
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
- dmxdevfilter->feed.ts = NULL;
+ INIT_LIST_HEAD(&dmxdevfilter->feed.ts);
init_timer(&dmxdevfilter->timer);
+ dvbdev->users++;
+
mutex_unlock(&dmxdev->mutex);
return 0;
}
static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
struct dmxdev_filter *dmxdevfilter)
{
- if (mutex_lock_interruptible(&dmxdev->mutex))
- return -ERESTARTSYS;
-
- if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
- mutex_unlock(&dmxdev->mutex);
- return -ERESTARTSYS;
- }
+ mutex_lock(&dmxdev->mutex);
+ mutex_lock(&dmxdevfilter->mutex);
dvb_dmxdev_filter_stop(dmxdevfilter);
dvb_dmxdev_filter_reset(dmxdevfilter);
filter->mode[i] ^= 0xff;
}
+static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev,
+ struct dmxdev_filter *filter, u16 pid)
+{
+ struct dmxdev_feed *feed;
+
+ if ((filter->type != DMXDEV_TYPE_PES) ||
+ (filter->state < DMXDEV_STATE_SET))
+ return -EINVAL;
+
+ /* only TS packet filters may have multiple PIDs */
+ if ((filter->params.pes.output != DMX_OUT_TSDEMUX_TAP) &&
+ (!list_empty(&filter->feed.ts)))
+ return -EINVAL;
+
+ feed = kzalloc(sizeof(struct dmxdev_feed), GFP_KERNEL);
+ if (feed == NULL)
+ return -ENOMEM;
+
+ feed->pid = pid;
+ list_add(&feed->next, &filter->feed.ts);
+
+ if (filter->state >= DMXDEV_STATE_GO)
+ return dvb_dmxdev_start_feed(dmxdev, filter, feed);
+
+ return 0;
+}
+
+static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev,
+ struct dmxdev_filter *filter, u16 pid)
+{
+ struct dmxdev_feed *feed, *tmp;
+
+ if ((filter->type != DMXDEV_TYPE_PES) ||
+ (filter->state < DMXDEV_STATE_SET))
+ return -EINVAL;
+
+ list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) {
+ if ((feed->pid == pid) && (feed->ts != NULL)) {
+ feed->ts->stop_filtering(feed->ts);
+ filter->dev->demux->release_ts_feed(filter->dev->demux,
+ feed->ts);
+ list_del(&feed->next);
+ kfree(feed);
+ }
+ }
+
+ return 0;
+}
+
static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
struct dmxdev_filter *dmxdevfilter,
struct dmx_sct_filter_params *params)
{
- dprintk("function : %s\n", __FUNCTION__);
+ dprintk("function : %s\n", __func__);
dvb_dmxdev_filter_stop(dmxdevfilter);
struct dmxdev_filter *dmxdevfilter,
struct dmx_pes_filter_params *params)
{
+ int ret;
+
dvb_dmxdev_filter_stop(dmxdevfilter);
+ dvb_dmxdev_filter_reset(dmxdevfilter);
if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0)
return -EINVAL;
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
+ ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter,
+ dmxdevfilter->params.pes.pid);
+ if (ret < 0)
+ return ret;
+
if (params->flags & DMX_IMMEDIATE_START)
return dvb_dmxdev_filter_start(dmxdevfilter);
mutex_unlock(&dmxdevfilter->mutex);
break;
- case DMX_GET_EVENT:
- break;
-
case DMX_GET_PES_PIDS:
if (!dmxdev->demux->get_pes_pids) {
ret = -EINVAL;
&((struct dmx_stc *)parg)->base);
break;
+ case DMX_ADD_PID:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
+ case DMX_REMOVE_PID:
+ if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+ ret = dvb_dmxdev_remove_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
+ mutex_unlock(&dmxdevfilter->mutex);
+ break;
+
default:
ret = -EINVAL;
break;
if (dmxdevfilter->buffer.error)
mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
- if (dmxdevfilter->buffer.pread != dmxdevfilter->buffer.pwrite)
+ if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
mask |= (POLLIN | POLLRDNORM | POLLPRI);
return mask;
struct dmxdev_filter *dmxdevfilter = file->private_data;
struct dmxdev *dmxdev = dmxdevfilter->dev;
- return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
+ int ret;
+
+ ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
+
+ mutex_lock(&dmxdev->mutex);
+ dmxdev->dvbdev->users--;
+ if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) {
+ fops_put(file->f_op);
+ file->f_op = NULL;
+ mutex_unlock(&dmxdev->mutex);
+ wake_up(&dmxdev->dvbdev->wait_queue);
+ } else
+ mutex_unlock(&dmxdev->mutex);
+
+ return ret;
}
-static struct file_operations dvb_demux_fops = {
+static const struct file_operations dvb_demux_fops = {
.owner = THIS_MODULE,
.read = dvb_demux_read,
.ioctl = dvb_demux_ioctl,
{
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
+ unsigned long arg = (unsigned long)parg;
int ret;
if (mutex_lock_interruptible(&dmxdev->mutex))
switch (cmd) {
case DMX_SET_BUFFER_SIZE:
- // FIXME: implement
- ret = 0;
+ ret = dvb_dvr_set_buffer_size(dmxdev, arg);
break;
default:
struct dmxdev *dmxdev = dvbdev->priv;
unsigned int mask = 0;
- dprintk("function : %s\n", __FUNCTION__);
+ dprintk("function : %s\n", __func__);
poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
if (dmxdev->dvr_buffer.error)
mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
- if (dmxdev->dvr_buffer.pread != dmxdev->dvr_buffer.pwrite)
+ if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
mask |= (POLLIN | POLLRDNORM | POLLPRI);
} else
mask |= (POLLOUT | POLLWRNORM | POLLPRI);
return mask;
}
-static struct file_operations dvb_dvr_fops = {
+static const struct file_operations dvb_dvr_fops = {
.owner = THIS_MODULE,
.read = dvb_dvr_read,
.write = dvb_dvr_write,
static struct dvb_device dvbdev_dvr = {
.priv = NULL,
+ .readers = 1,
.users = 1,
- .writers = 1,
.fops = &dvb_dvr_fops
};
dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
dmxdev, DVB_DEVICE_DVR);
- dvb_dmxdev_buffer_init(&dmxdev->dvr_buffer);
+ dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
return 0;
}
void dvb_dmxdev_release(struct dmxdev *dmxdev)
{
+ dmxdev->exit=1;
+ if (dmxdev->dvbdev->users > 1) {
+ wait_event(dmxdev->dvbdev->wait_queue,
+ dmxdev->dvbdev->users==1);
+ }
+ if (dmxdev->dvr_dvbdev->users > 1) {
+ wait_event(dmxdev->dvr_dvbdev->wait_queue,
+ dmxdev->dvr_dvbdev->users==1);
+ }
+
dvb_unregister_device(dmxdev->dvbdev);
dvb_unregister_device(dmxdev->dvr_dvbdev);