Commit 28003225 authored by Alan Cox's avatar Alan Cox Committed by Linus Torvalds

[PATCH] update the dvb core

parent c8639e86
...@@ -3,6 +3,6 @@ ...@@ -3,6 +3,6 @@
# #
dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \ dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
dvb_frontend.o dvb_i2c.o dvb_net.o dvb_ksyms.o dvb_frontend.o dvb_i2c.o dvb_net.o dvb_ksyms.o dvb_ringbuffer.o
obj-$(CONFIG_DVB_CORE) += dvb-core.o obj-$(CONFIG_DVB_CORE) += dvb-core.o
obj-$(CONFIG_DVB_CORE) += crc32.o
...@@ -144,6 +144,14 @@ struct dmx_section_feed_s { ...@@ -144,6 +144,14 @@ struct dmx_section_feed_s {
int is_filtering; /* Set to non-zero when filtering in progress */ int is_filtering; /* Set to non-zero when filtering in progress */
struct dmx_demux_s* parent; /* Back-pointer */ struct dmx_demux_s* parent; /* Back-pointer */
void* priv; /* Pointer to private data of the API client */ void* priv; /* Pointer to private data of the API client */
int check_crc;
u32 crc_val;
u8 secbuf[4096];
int secbufp;
int seclen;
int (*set) (struct dmx_section_feed_s* feed, int (*set) (struct dmx_section_feed_s* feed,
__u16 pid, __u16 pid,
size_t circular_buffer_size, size_t circular_buffer_size,
...@@ -162,16 +170,16 @@ typedef struct dmx_section_feed_s dmx_section_feed_t; ...@@ -162,16 +170,16 @@ typedef struct dmx_section_feed_s dmx_section_feed_t;
/* Callback functions */ /* Callback functions */
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
typedef int (*dmx_ts_cb) ( __u8 * buffer1, typedef int (*dmx_ts_cb) ( const u8 * buffer1,
size_t buffer1_length, size_t buffer1_length,
__u8 * buffer2, const u8 * buffer2,
size_t buffer2_length, size_t buffer2_length,
dmx_ts_feed_t* source, dmx_ts_feed_t* source,
dmx_success_t success); dmx_success_t success);
typedef int (*dmx_section_cb) ( __u8 * buffer1, typedef int (*dmx_section_cb) ( const u8 * buffer1,
size_t buffer1_len, size_t buffer1_len,
__u8 * buffer2, const u8 * buffer2,
size_t buffer2_len, size_t buffer2_len,
dmx_section_filter_t * source, dmx_section_filter_t * source,
dmx_success_t success); dmx_success_t success);
...@@ -278,6 +286,9 @@ struct dmx_demux_s { ...@@ -278,6 +286,9 @@ struct dmx_demux_s {
int (*disconnect_frontend) (struct dmx_demux_s* demux); int (*disconnect_frontend) (struct dmx_demux_s* demux);
int (*get_pes_pids) (struct dmx_demux_s* demux, __u16 *pids); int (*get_pes_pids) (struct dmx_demux_s* demux, __u16 *pids);
int (*get_stc) (struct dmx_demux_s* demux, unsigned int num,
uint64_t *stc, unsigned int *base);
}; };
typedef struct dmx_demux_s dmx_demux_t; typedef struct dmx_demux_s dmx_demux_t;
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* dmxdev.c - DVB demultiplexer device * dmxdev.c - DVB demultiplexer device
* *
* Copyright (C) 2000 Ralph Metzler <ralph@convergence.de> * Copyright (C) 2000 Ralph Metzler <ralph@convergence.de>
* & Marcus Metzler <marcus@convergence.de> * & Marcus Metzler <marcus@convergence.de>
for convergence integrated media GmbH for convergence integrated media GmbH
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License * modify it under the terms of the GNU Lesser General Public License
...@@ -24,11 +24,13 @@ ...@@ -24,11 +24,13 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/videodev.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "dmxdev.h" #include "dmxdev.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51)
#include "compat.h"
#endif
//MODULE_DESCRIPTION(""); //MODULE_DESCRIPTION("");
//MODULE_AUTHOR("Ralph Metzler, Marcus Metzler"); //MODULE_AUTHOR("Ralph Metzler, Marcus Metzler");
...@@ -43,133 +45,133 @@ static int debug = 0; ...@@ -43,133 +45,133 @@ static int debug = 0;
inline dmxdev_filter_t * inline dmxdev_filter_t *
dvb_dmxdev_file_to_filter(struct file *file) dvb_dmxdev_file_to_filter(struct file *file)
{ {
return (dmxdev_filter_t *) file->private_data; return (dmxdev_filter_t *) file->private_data;
} }
inline dmxdev_dvr_t * inline dmxdev_dvr_t *
dvb_dmxdev_file_to_dvr(dmxdev_t *dmxdev, struct file *file) dvb_dmxdev_file_to_dvr(dmxdev_t *dmxdev, struct file *file)
{ {
return (dmxdev_dvr_t *) file->private_data; return (dmxdev_dvr_t *) file->private_data;
} }
static inline void static inline void
dvb_dmxdev_buffer_init(dmxdev_buffer_t *buffer) dvb_dmxdev_buffer_init(dmxdev_buffer_t *buffer)
{ {
buffer->data=0; buffer->data=0;
buffer->size=8192; buffer->size=8192;
buffer->pread=0; buffer->pread=0;
buffer->pwrite=0; buffer->pwrite=0;
buffer->error=0; buffer->error=0;
init_waitqueue_head(&buffer->queue); init_waitqueue_head(&buffer->queue);
} }
static inline int static inline
dvb_dmxdev_buffer_write(dmxdev_buffer_t *buf, uint8_t *src, int len) int dvb_dmxdev_buffer_write(dmxdev_buffer_t *buf, const u8 *src, int len)
{ {
int split; int split;
int free; int free;
int todo; int todo;
if (!len) if (!len)
return 0; return 0;
if (!buf->data) if (!buf->data)
return 0; return 0;
free=buf->pread-buf->pwrite; free=buf->pread-buf->pwrite;
split=0; split=0;
if (free<=0) { if (free<=0) {
free+=buf->size; free+=buf->size;
split=buf->size-buf->pwrite; split=buf->size-buf->pwrite;
} }
if (len>=free) { if (len>=free) {
dprintk("dmxdev: buffer overflow\n"); dprintk("dmxdev: buffer overflow\n");
return -1; return -1;
} }
if (split>=len) if (split>=len)
split=0; split=0;
todo=len; todo=len;
if (split) { if (split) {
memcpy(buf->data + buf->pwrite, src, split); memcpy(buf->data + buf->pwrite, src, split);
todo-=split; todo-=split;
buf->pwrite=0; buf->pwrite=0;
} }
memcpy(buf->data + buf->pwrite, src+split, todo); memcpy(buf->data + buf->pwrite, src+split, todo);
buf->pwrite=(buf->pwrite+todo)%buf->size; buf->pwrite=(buf->pwrite+todo)%buf->size;
return len; return len;
} }
static ssize_t static ssize_t
dvb_dmxdev_buffer_read(dmxdev_buffer_t *src, int non_blocking, dvb_dmxdev_buffer_read(dmxdev_buffer_t *src, int non_blocking,
char *buf, size_t count, loff_t *ppos) char *buf, size_t count, loff_t *ppos)
{ {
unsigned long todo=count; unsigned long todo=count;
int split, avail, error; int split, avail, error;
if (!src->data) if (!src->data)
return 0; return 0;
if ((error=src->error)) { if ((error=src->error)) {
src->pwrite=src->pread; src->pwrite=src->pread;
src->error=0; src->error=0;
return error; return error;
} }
if (non_blocking && (src->pwrite==src->pread)) if (non_blocking && (src->pwrite==src->pread))
return -EWOULDBLOCK; return -EWOULDBLOCK;
while (todo>0) { while (todo>0) {
if (non_blocking && (src->pwrite==src->pread)) if (non_blocking && (src->pwrite==src->pread))
return (count-todo) ? (count-todo) : -EWOULDBLOCK; return (count-todo) ? (count-todo) : -EWOULDBLOCK;
if (wait_event_interruptible(src->queue, if (wait_event_interruptible(src->queue,
(src->pread!=src->pwrite) || (src->pread!=src->pwrite) ||
(src->error))<0) (src->error))<0)
return count-todo; return count-todo;
if ((error=src->error)) { if ((error=src->error)) {
src->pwrite=src->pread; src->pwrite=src->pread;
src->error=0; src->error=0;
return error; return error;
} }
split=src->size; split=src->size;
avail=src->pwrite - src->pread; avail=src->pwrite - src->pread;
if (avail<0) { if (avail<0) {
avail+=src->size; avail+=src->size;
split=src->size - src->pread; split=src->size - src->pread;
} }
if (avail>todo) if (avail>todo)
avail=todo; avail=todo;
if (split<avail) { if (split<avail) {
if (copy_to_user(buf, src->data+src->pread, split)) if (copy_to_user(buf, src->data+src->pread, split))
return -EFAULT; return -EFAULT;
buf+=split; buf+=split;
src->pread=0; src->pread=0;
todo-=split; todo-=split;
avail-=split; avail-=split;
} }
if (avail) { if (avail) {
if (copy_to_user(buf, src->data+src->pread, avail)) if (copy_to_user(buf, src->data+src->pread, avail))
return -EFAULT; return -EFAULT;
src->pread = (src->pread + avail) % src->size; src->pread = (src->pread + avail) % src->size;
todo-=avail; todo-=avail;
buf+=avail; buf+=avail;
} }
} }
return count; return count;
} }
static dmx_frontend_t * static dmx_frontend_t *
get_fe(dmx_demux_t *demux, int type) get_fe(dmx_demux_t *demux, int type)
{ {
struct list_head *head, *pos; struct list_head *head, *pos;
head=demux->get_frontends(demux); head=demux->get_frontends(demux);
if (!head) if (!head)
return 0; return 0;
list_for_each(pos, head) list_for_each(pos, head)
if (DMX_FE_ENTRY(pos)->source==type) if (DMX_FE_ENTRY(pos)->source==type)
return DMX_FE_ENTRY(pos); return DMX_FE_ENTRY(pos);
return 0; return 0;
} }
...@@ -177,8 +179,8 @@ get_fe(dmx_demux_t *demux, int type) ...@@ -177,8 +179,8 @@ get_fe(dmx_demux_t *demux, int type)
static inline void static inline void
dvb_dmxdev_dvr_state_set(dmxdev_dvr_t *dmxdevdvr, int state) dvb_dmxdev_dvr_state_set(dmxdev_dvr_t *dmxdevdvr, int state)
{ {
spin_lock_irq(&dmxdevdvr->dev->lock); spin_lock_irq(&dmxdevdvr->dev->lock);
dmxdevdvr->state=state; dmxdevdvr->state=state;
spin_unlock_irq(&dmxdevdvr->dev->lock); spin_unlock_irq(&dmxdevdvr->dev->lock);
} }
...@@ -186,17 +188,17 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) ...@@ -186,17 +188,17 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
{ {
struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;
dmxdev_t *dmxdev=(dmxdev_t *) dvbdev->priv; dmxdev_t *dmxdev=(dmxdev_t *) dvbdev->priv;
dmx_frontend_t *front; dmx_frontend_t *front;
dprintk ("function : %s\n", __FUNCTION__); dprintk ("function : %s\n", __FUNCTION__);
if (down_interruptible (&dmxdev->mutex)) if (down_interruptible (&dmxdev->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
if ((file->f_flags&O_ACCMODE)==O_RDWR) { if ((file->f_flags&O_ACCMODE)==O_RDWR) {
if (!(dmxdev->capabilities&DMXDEV_CAP_DUPLEX)) { if (!(dmxdev->capabilities&DMXDEV_CAP_DUPLEX)) {
up(&dmxdev->mutex); up(&dmxdev->mutex);
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
} }
...@@ -206,12 +208,12 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) ...@@ -206,12 +208,12 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
dmxdev->dvr_buffer.data=vmalloc(DVR_BUFFER_SIZE); dmxdev->dvr_buffer.data=vmalloc(DVR_BUFFER_SIZE);
if (!dmxdev->dvr_buffer.data) { if (!dmxdev->dvr_buffer.data) {
up(&dmxdev->mutex); up(&dmxdev->mutex);
return -ENOMEM; return -ENOMEM;
} }
} }
if ((file->f_flags&O_ACCMODE)==O_WRONLY) { if ((file->f_flags&O_ACCMODE)==O_WRONLY) {
dmxdev->dvr_orig_fe=dmxdev->demux->frontend; dmxdev->dvr_orig_fe=dmxdev->demux->frontend;
if (!dmxdev->demux->write) { if (!dmxdev->demux->write) {
up(&dmxdev->mutex); up(&dmxdev->mutex);
...@@ -222,13 +224,13 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) ...@@ -222,13 +224,13 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
if (!front) { if (!front) {
up(&dmxdev->mutex); up(&dmxdev->mutex);
return -EINVAL; return -EINVAL;
} }
dmxdev->demux->disconnect_frontend(dmxdev->demux); dmxdev->demux->disconnect_frontend(dmxdev->demux);
dmxdev->demux->connect_frontend(dmxdev->demux, front); dmxdev->demux->connect_frontend(dmxdev->demux, front);
} }
up(&dmxdev->mutex); up(&dmxdev->mutex);
return 0; return 0;
} }
static int dvb_dvr_release(struct inode *inode, struct file *file) static int dvb_dvr_release(struct inode *inode, struct file *file)
...@@ -236,25 +238,25 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) ...@@ -236,25 +238,25 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;
dmxdev_t *dmxdev=(dmxdev_t *) dvbdev->priv; dmxdev_t *dmxdev=(dmxdev_t *) dvbdev->priv;
if (down_interruptible (&dmxdev->mutex)) if (down_interruptible (&dmxdev->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
if ((file->f_flags&O_ACCMODE)==O_WRONLY) { if ((file->f_flags&O_ACCMODE)==O_WRONLY) {
dmxdev->demux->disconnect_frontend(dmxdev->demux); dmxdev->demux->disconnect_frontend(dmxdev->demux);
dmxdev->demux->connect_frontend(dmxdev->demux, dmxdev->demux->connect_frontend(dmxdev->demux,
dmxdev->dvr_orig_fe); dmxdev->dvr_orig_fe);
} }
if ((file->f_flags&O_ACCMODE)==O_RDONLY) { if ((file->f_flags&O_ACCMODE)==O_RDONLY) {
if (dmxdev->dvr_buffer.data) { if (dmxdev->dvr_buffer.data) {
void *mem=dmxdev->dvr_buffer.data; void *mem=dmxdev->dvr_buffer.data;
mb(); mb();
spin_lock_irq(&dmxdev->lock); spin_lock_irq(&dmxdev->lock);
dmxdev->dvr_buffer.data=0; dmxdev->dvr_buffer.data=0;
spin_unlock_irq(&dmxdev->lock); spin_unlock_irq(&dmxdev->lock);
vfree(mem); vfree(mem);
} }
} }
up(&dmxdev->mutex); up(&dmxdev->mutex);
return 0; return 0;
} }
...@@ -265,14 +267,14 @@ dvb_dvr_write(struct file *file, const char *buf, size_t count, loff_t *ppos) ...@@ -265,14 +267,14 @@ dvb_dvr_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
dmxdev_t *dmxdev=(dmxdev_t *) dvbdev->priv; dmxdev_t *dmxdev=(dmxdev_t *) dvbdev->priv;
int ret; int ret;
if (!dmxdev->demux->write) if (!dmxdev->demux->write)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if ((file->f_flags&O_ACCMODE)!=O_WRONLY) if ((file->f_flags&O_ACCMODE)!=O_WRONLY)
return -EINVAL; return -EINVAL;
if (down_interruptible (&dmxdev->mutex)) if (down_interruptible (&dmxdev->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
ret=dmxdev->demux->write(dmxdev->demux, buf, count); ret=dmxdev->demux->write(dmxdev->demux, buf, count);
up(&dmxdev->mutex); up(&dmxdev->mutex);
return ret; return ret;
} }
...@@ -283,19 +285,19 @@ dvb_dvr_read(struct file *file, char *buf, size_t count, loff_t *ppos) ...@@ -283,19 +285,19 @@ dvb_dvr_read(struct file *file, char *buf, size_t count, loff_t *ppos)
dmxdev_t *dmxdev=(dmxdev_t *) dvbdev->priv; dmxdev_t *dmxdev=(dmxdev_t *) dvbdev->priv;
int ret; int ret;
//down(&dmxdev->mutex); //down(&dmxdev->mutex);
ret= dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, ret= dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
file->f_flags&O_NONBLOCK, file->f_flags&O_NONBLOCK,
buf, count, ppos); buf, count, ppos);
//up(&dmxdev->mutex); //up(&dmxdev->mutex);
return ret; return ret;
} }
static inline void static inline void
dvb_dmxdev_filter_state_set(dmxdev_filter_t *dmxdevfilter, int state) dvb_dmxdev_filter_state_set(dmxdev_filter_t *dmxdevfilter, int state)
{ {
spin_lock_irq(&dmxdevfilter->dev->lock); spin_lock_irq(&dmxdevfilter->dev->lock);
dmxdevfilter->state=state; dmxdevfilter->state=state;
spin_unlock_irq(&dmxdevfilter->dev->lock); spin_unlock_irq(&dmxdevfilter->dev->lock);
} }
...@@ -306,25 +308,25 @@ dvb_dmxdev_set_buffer_size(dmxdev_filter_t *dmxdevfilter, unsigned long size) ...@@ -306,25 +308,25 @@ dvb_dmxdev_set_buffer_size(dmxdev_filter_t *dmxdevfilter, unsigned long size)
void *mem; void *mem;
if (buf->size==size) if (buf->size==size)
return 0; return 0;
if (dmxdevfilter->state>=DMXDEV_STATE_GO) if (dmxdevfilter->state>=DMXDEV_STATE_GO)
return -EBUSY; return -EBUSY;
spin_lock_irq(&dmxdevfilter->dev->lock); spin_lock_irq(&dmxdevfilter->dev->lock);
mem=buf->data; mem=buf->data;
buf->data=0; buf->data=0;
buf->size=size; buf->size=size;
buf->pwrite=buf->pread=0; buf->pwrite=buf->pread=0;
spin_unlock_irq(&dmxdevfilter->dev->lock); spin_unlock_irq(&dmxdevfilter->dev->lock);
if (mem) if (mem)
vfree(mem); vfree(mem);
if (buf->size) { if (buf->size) {
mem=vmalloc(dmxdevfilter->buffer.size); mem=vmalloc(dmxdevfilter->buffer.size);
if (!mem) if (!mem)
return -ENOMEM; return -ENOMEM;
spin_lock_irq(&dmxdevfilter->dev->lock); spin_lock_irq(&dmxdevfilter->dev->lock);
buf->data=mem; buf->data=mem;
spin_unlock_irq(&dmxdevfilter->dev->lock); spin_unlock_irq(&dmxdevfilter->dev->lock);
} }
return 0; return 0;
} }
...@@ -332,23 +334,23 @@ dvb_dmxdev_set_buffer_size(dmxdev_filter_t *dmxdevfilter, unsigned long size) ...@@ -332,23 +334,23 @@ dvb_dmxdev_set_buffer_size(dmxdev_filter_t *dmxdevfilter, unsigned long size)
static void static void
dvb_dmxdev_filter_timeout(unsigned long data) dvb_dmxdev_filter_timeout(unsigned long data)
{ {
dmxdev_filter_t *dmxdevfilter=(dmxdev_filter_t *)data; dmxdev_filter_t *dmxdevfilter=(dmxdev_filter_t *)data;
dmxdevfilter->buffer.error=-ETIMEDOUT; dmxdevfilter->buffer.error=-ETIMEDOUT;
spin_lock_irq(&dmxdevfilter->dev->lock); spin_lock_irq(&dmxdevfilter->dev->lock);
dmxdevfilter->state=DMXDEV_STATE_TIMEDOUT; dmxdevfilter->state=DMXDEV_STATE_TIMEDOUT;
spin_unlock_irq(&dmxdevfilter->dev->lock); spin_unlock_irq(&dmxdevfilter->dev->lock);
wake_up(&dmxdevfilter->buffer.queue); wake_up(&dmxdevfilter->buffer.queue);
} }
static void static void
dvb_dmxdev_filter_timer(dmxdev_filter_t *dmxdevfilter) dvb_dmxdev_filter_timer(dmxdev_filter_t *dmxdevfilter)
{ {
struct dmx_sct_filter_params *para=&dmxdevfilter->params.sec; struct dmx_sct_filter_params *para=&dmxdevfilter->params.sec;
del_timer(&dmxdevfilter->timer); del_timer(&dmxdevfilter->timer);
if (para->timeout) { if (para->timeout) {
dmxdevfilter->timer.function=dvb_dmxdev_filter_timeout; dmxdevfilter->timer.function=dvb_dmxdev_filter_timeout;
dmxdevfilter->timer.data=(unsigned long) dmxdevfilter; dmxdevfilter->timer.data=(unsigned long) dmxdevfilter;
dmxdevfilter->timer.expires=jiffies+1+(HZ/2+HZ*para->timeout)/1000; dmxdevfilter->timer.expires=jiffies+1+(HZ/2+HZ*para->timeout)/1000;
add_timer(&dmxdevfilter->timer); add_timer(&dmxdevfilter->timer);
...@@ -356,53 +358,51 @@ dvb_dmxdev_filter_timer(dmxdev_filter_t *dmxdevfilter) ...@@ -356,53 +358,51 @@ dvb_dmxdev_filter_timer(dmxdev_filter_t *dmxdevfilter)
} }
static int static int
dvb_dmxdev_section_callback(u8 *buffer1, size_t buffer1_len, dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
u8 *buffer2, size_t buffer2_len, const u8 *buffer2, size_t buffer2_len,
dmx_section_filter_t *filter, dmx_section_filter_t *filter, dmx_success_t success)
dmx_success_t success)
{ {
dmxdev_filter_t *dmxdevfilter=(dmxdev_filter_t *) filter->priv; dmxdev_filter_t *dmxdevfilter=(dmxdev_filter_t *) filter->priv;
int ret; int ret;
if (dmxdevfilter->buffer.error) { if (dmxdevfilter->buffer.error) {
wake_up(&dmxdevfilter->buffer.queue); wake_up(&dmxdevfilter->buffer.queue);
return 0; return 0;
} }
spin_lock(&dmxdevfilter->dev->lock); spin_lock(&dmxdevfilter->dev->lock);
if (dmxdevfilter->state!=DMXDEV_STATE_GO) { if (dmxdevfilter->state!=DMXDEV_STATE_GO) {
spin_unlock(&dmxdevfilter->dev->lock); spin_unlock(&dmxdevfilter->dev->lock);
return 0; return 0;
} }
del_timer(&dmxdevfilter->timer); del_timer(&dmxdevfilter->timer);
dprintk("dmxdev: section callback %02x %02x %02x %02x %02x %02x\n", dprintk("dmxdev: section callback %02x %02x %02x %02x %02x %02x\n",
buffer1[0], buffer1[1], buffer1[0], buffer1[1],
buffer1[2], buffer1[3], buffer1[2], buffer1[3],
buffer1[4], buffer1[5]); buffer1[4], buffer1[5]);
ret=dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, buffer1_len); ret=dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, buffer1_len);
if (ret==buffer1_len) { if (ret==buffer1_len) {
ret=dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, buffer2_len); ret=dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, buffer2_len);
} }
if (ret<0) { if (ret<0) {
dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread; dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread;
dmxdevfilter->buffer.error=-EOVERFLOW; dmxdevfilter->buffer.error=-EOVERFLOW;
} }
if (dmxdevfilter->params.sec.flags&DMX_ONESHOT) if (dmxdevfilter->params.sec.flags&DMX_ONESHOT)
dmxdevfilter->state=DMXDEV_STATE_DONE; dmxdevfilter->state=DMXDEV_STATE_DONE;
spin_unlock(&dmxdevfilter->dev->lock); spin_unlock(&dmxdevfilter->dev->lock);
wake_up(&dmxdevfilter->buffer.queue); wake_up(&dmxdevfilter->buffer.queue);
return 0; return 0;
} }
static int static int
dvb_dmxdev_ts_callback(u8 *buffer1, size_t buffer1_len, dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
u8 *buffer2, size_t buffer2_len, const u8 *buffer2, size_t buffer2_len,
dmx_ts_feed_t *feed, dmx_ts_feed_t *feed, dmx_success_t success)
dmx_success_t success)
{ {
dmxdev_filter_t *dmxdevfilter=(dmxdev_filter_t *) feed->priv; dmxdev_filter_t *dmxdevfilter=(dmxdev_filter_t *) feed->priv;
dmxdev_buffer_t *buffer; dmxdev_buffer_t *buffer;
int ret; int ret;
spin_lock(&dmxdevfilter->dev->lock); spin_lock(&dmxdevfilter->dev->lock);
if (dmxdevfilter->params.pes.output==DMX_OUT_DECODER) { if (dmxdevfilter->params.pes.output==DMX_OUT_DECODER) {
spin_unlock(&dmxdevfilter->dev->lock); spin_unlock(&dmxdevfilter->dev->lock);
...@@ -410,20 +410,20 @@ dvb_dmxdev_ts_callback(u8 *buffer1, size_t buffer1_len, ...@@ -410,20 +410,20 @@ dvb_dmxdev_ts_callback(u8 *buffer1, size_t buffer1_len,
} }
if (dmxdevfilter->params.pes.output==DMX_OUT_TAP) if (dmxdevfilter->params.pes.output==DMX_OUT_TAP)
buffer=&dmxdevfilter->buffer; buffer=&dmxdevfilter->buffer;
else else
buffer=&dmxdevfilter->dev->dvr_buffer; buffer=&dmxdevfilter->dev->dvr_buffer;
if (buffer->error) { if (buffer->error) {
spin_unlock(&dmxdevfilter->dev->lock); spin_unlock(&dmxdevfilter->dev->lock);
wake_up(&buffer->queue); wake_up(&buffer->queue);
return 0; return 0;
} }
ret=dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len); ret=dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
if (ret==buffer1_len) if (ret==buffer1_len)
ret=dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len); ret=dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
if (ret<0) { if (ret<0) {
buffer->pwrite=buffer->pread; buffer->pwrite=buffer->pread;
buffer->error=-EOVERFLOW; buffer->error=-EOVERFLOW;
} }
spin_unlock(&dmxdevfilter->dev->lock); spin_unlock(&dmxdevfilter->dev->lock);
wake_up(&buffer->queue); wake_up(&buffer->queue);
...@@ -440,49 +440,50 @@ dvb_dmxdev_feed_stop(dmxdev_filter_t *dmxdevfilter) ...@@ -440,49 +440,50 @@ dvb_dmxdev_feed_stop(dmxdev_filter_t *dmxdevfilter)
switch (dmxdevfilter->type) { switch (dmxdevfilter->type) {
case DMXDEV_TYPE_SEC: case DMXDEV_TYPE_SEC:
del_timer(&dmxdevfilter->timer); del_timer(&dmxdevfilter->timer);
dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec); dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec);
break; break;
case DMXDEV_TYPE_PES: case DMXDEV_TYPE_PES:
dmxdevfilter->feed.ts->stop_filtering(dmxdevfilter->feed.ts); dmxdevfilter->feed.ts->stop_filtering(dmxdevfilter->feed.ts);
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
return 0; return 0;
} }
/* start feed associated with the specified filter */ /* start feed associated with the specified filter */
static int static
dvb_dmxdev_feed_start(dmxdev_filter_t *dmxdevfilter) int dvb_dmxdev_feed_start(dmxdev_filter_t *filter)
{ {
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_GO); dvb_dmxdev_filter_state_set (filter, DMXDEV_STATE_GO);
switch (dmxdevfilter->type) { switch (filter->type) {
case DMXDEV_TYPE_SEC: case DMXDEV_TYPE_SEC:
dmxdevfilter->feed.sec->start_filtering(dmxdevfilter->feed.sec); return filter->feed.sec->start_filtering(filter->feed.sec);
break; break;
case DMXDEV_TYPE_PES: case DMXDEV_TYPE_PES:
dmxdevfilter->feed.ts->start_filtering(dmxdevfilter->feed.ts); return filter->feed.ts->start_filtering(filter->feed.ts);
break; break;
default: default:
return -EINVAL; return -EINVAL;
} }
return 0;
return 0;
} }
/* restart section feed if it has filters left associated with it, /* restart section feed if it has filters left associated with it,
otherwise release the feed */ otherwise release the feed */
static int static
dvb_dmxdev_feed_restart(dmxdev_filter_t *dmxdevfilter) int dvb_dmxdev_feed_restart(dmxdev_filter_t *filter)
{ {
int i; int i;
dmxdev_t *dmxdev=dmxdevfilter->dev; dmxdev_t *dmxdev = filter->dev;
uint16_t pid=dmxdevfilter->params.sec.pid; uint16_t pid = filter->params.sec.pid;
for (i=0; i<dmxdev->filternum; i++) for (i=0; i<dmxdev->filternum; i++)
if (dmxdev->filter[i].state>=DMXDEV_STATE_GO && if (dmxdev->filter[i].state>=DMXDEV_STATE_GO &&
...@@ -492,36 +493,34 @@ dvb_dmxdev_feed_restart(dmxdev_filter_t *dmxdevfilter) ...@@ -492,36 +493,34 @@ dvb_dmxdev_feed_restart(dmxdev_filter_t *dmxdevfilter)
return 0; return 0;
} }
dmxdevfilter->dev->demux-> filter->dev->demux->release_section_feed(dmxdev->demux, filter->feed.sec);
release_section_feed(dmxdev->demux,
dmxdevfilter->feed.sec);
return 0; return 0;
} }
static int static int
dvb_dmxdev_filter_stop(dmxdev_filter_t *dmxdevfilter) dvb_dmxdev_filter_stop(dmxdev_filter_t *dmxdevfilter)
{ {
if (dmxdevfilter->state<DMXDEV_STATE_GO) if (dmxdevfilter->state<DMXDEV_STATE_GO)
return 0; return 0;
switch (dmxdevfilter->type) { switch (dmxdevfilter->type) {
case DMXDEV_TYPE_SEC: case DMXDEV_TYPE_SEC:
if (!dmxdevfilter->feed.sec) if (!dmxdevfilter->feed.sec)
break; break;
dvb_dmxdev_feed_stop(dmxdevfilter); dvb_dmxdev_feed_stop(dmxdevfilter);
if (dmxdevfilter->filter.sec) if (dmxdevfilter->filter.sec)
dmxdevfilter->feed.sec-> dmxdevfilter->feed.sec->
release_filter(dmxdevfilter->feed.sec, release_filter(dmxdevfilter->feed.sec,
dmxdevfilter->filter.sec); dmxdevfilter->filter.sec);
dvb_dmxdev_feed_restart(dmxdevfilter); dvb_dmxdev_feed_restart(dmxdevfilter);
dmxdevfilter->feed.sec=0; dmxdevfilter->feed.sec=0;
break; break;
case DMXDEV_TYPE_PES: case DMXDEV_TYPE_PES:
if (!dmxdevfilter->feed.ts) if (!dmxdevfilter->feed.ts)
break; break;
dvb_dmxdev_feed_stop(dmxdevfilter); dvb_dmxdev_feed_stop(dmxdevfilter);
dmxdevfilter->dev->demux-> dmxdevfilter->dev->demux->
release_ts_feed(dmxdevfilter->dev->demux, release_ts_feed(dmxdevfilter->dev->demux,
dmxdevfilter->feed.ts); dmxdevfilter->feed.ts);
dmxdevfilter->feed.ts=0; dmxdevfilter->feed.ts=0;
...@@ -529,10 +528,10 @@ dvb_dmxdev_filter_stop(dmxdev_filter_t *dmxdevfilter) ...@@ -529,10 +528,10 @@ dvb_dmxdev_filter_stop(dmxdev_filter_t *dmxdevfilter)
default: default:
if (dmxdevfilter->state==DMXDEV_STATE_ALLOCATED) if (dmxdevfilter->state==DMXDEV_STATE_ALLOCATED)
return 0; return 0;
return -EINVAL; return -EINVAL;
} }
dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread=0; dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread=0;
return 0; return 0;
} }
static inline int static inline int
...@@ -544,58 +543,58 @@ dvb_dmxdev_filter_reset(dmxdev_filter_t *dmxdevfilter) ...@@ -544,58 +543,58 @@ dvb_dmxdev_filter_reset(dmxdev_filter_t *dmxdevfilter)
dmxdevfilter->type=DMXDEV_TYPE_NONE; dmxdevfilter->type=DMXDEV_TYPE_NONE;
dmxdevfilter->pid=0xffff; dmxdevfilter->pid=0xffff;
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
return 0; return 0;
} }
static int static int
dvb_dmxdev_filter_start(dmxdev_filter_t *dmxdevfilter) dvb_dmxdev_filter_start(dmxdev_filter_t *filter)
{ {
dmxdev_t *dmxdev=dmxdevfilter->dev; dmxdev_t *dmxdev = filter->dev;
void *mem; void *mem;
int ret, i; int ret, i;
if (dmxdevfilter->state<DMXDEV_STATE_SET) if (filter->state < DMXDEV_STATE_SET)
return -EINVAL; return -EINVAL;
if (dmxdevfilter->state>=DMXDEV_STATE_GO)
dvb_dmxdev_filter_stop(dmxdevfilter); if (filter->state >= DMXDEV_STATE_GO)
dvb_dmxdev_filter_stop(filter);
mem=dmxdevfilter->buffer.data;
if (!mem) { if (!(mem = filter->buffer.data)) {
mem=vmalloc(dmxdevfilter->buffer.size); mem = vmalloc(filter->buffer.size);
spin_lock_irq(&dmxdevfilter->dev->lock); spin_lock_irq(&filter->dev->lock);
dmxdevfilter->buffer.data=mem; filter->buffer.data=mem;
spin_unlock_irq(&dmxdevfilter->dev->lock); spin_unlock_irq(&filter->dev->lock);
if (!dmxdevfilter->buffer.data) if (!filter->buffer.data)
return -ENOMEM; return -ENOMEM;
} }
dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread=0; filter->buffer.pwrite = filter->buffer.pread = 0;
switch (dmxdevfilter->type) { switch (filter->type) {
case DMXDEV_TYPE_SEC: case DMXDEV_TYPE_SEC:
{ {
struct dmx_sct_filter_params *para=&dmxdevfilter->params.sec; struct dmx_sct_filter_params *para=&filter->params.sec;
dmx_section_filter_t **secfilter=&dmxdevfilter->filter.sec; dmx_section_filter_t **secfilter=&filter->filter.sec;
dmx_section_feed_t **secfeed=&dmxdevfilter->feed.sec; dmx_section_feed_t **secfeed=&filter->feed.sec;
*secfilter=0; *secfilter=0;
*secfeed=0; *secfeed=0;
/* find active filter/feed with same PID */ /* find active filter/feed with same PID */
for (i=0; i<dmxdev->filternum; i++) for (i=0; i<dmxdev->filternum; i++) {
if (dmxdev->filter[i].state>=DMXDEV_STATE_GO && if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
dmxdev->filter[i].pid==para->pid) { dmxdev->filter[i].pid == para->pid &&
if (dmxdev->filter[i].type!=DMXDEV_TYPE_SEC) dmxdev->filter[i].type == DMXDEV_TYPE_SEC) {
return -EBUSY; *secfeed = dmxdev->filter[i].feed.sec;
*secfeed=dmxdev->filter[i].feed.sec;
break; break;
} }
}
/* if no feed found, try to allocate new one */ /* if no feed found, try to allocate new one */
if (!*secfeed) { if (!*secfeed) {
ret=dmxdev->demux->allocate_section_feed(dmxdev->demux, ret=dmxdev->demux->allocate_section_feed(dmxdev->demux,
secfeed, secfeed,
dvb_dmxdev_section_callback); dvb_dmxdev_section_callback);
if (ret<0) { if (ret<0) {
printk ("DVB (%s): could not alloc feed\n", printk ("DVB (%s): could not alloc feed\n",
__FUNCTION__); __FUNCTION__);
...@@ -608,22 +607,23 @@ dvb_dmxdev_filter_start(dmxdev_filter_t *dmxdevfilter) ...@@ -608,22 +607,23 @@ dvb_dmxdev_filter_start(dmxdev_filter_t *dmxdevfilter)
if (ret<0) { if (ret<0) {
printk ("DVB (%s): could not set feed\n", printk ("DVB (%s): could not set feed\n",
__FUNCTION__); __FUNCTION__);
dvb_dmxdev_feed_restart(dmxdevfilter); dvb_dmxdev_feed_restart(filter);
return ret; return ret;
} }
} else {
dvb_dmxdev_feed_stop(filter);
} }
else
dvb_dmxdev_feed_stop(dmxdevfilter);
ret=(*secfeed)->allocate_filter(*secfeed, secfilter); ret=(*secfeed)->allocate_filter(*secfeed, secfilter);
if (ret<0) {
dvb_dmxdev_feed_restart(dmxdevfilter); if (ret < 0) {
dmxdevfilter->feed.sec->start_filtering(*secfeed); dvb_dmxdev_feed_restart(filter);
filter->feed.sec->start_filtering(*secfeed);
dprintk ("could not get filter\n"); dprintk ("could not get filter\n");
return ret; return ret;
} }
(*secfilter)->priv=(void *) dmxdevfilter; (*secfilter)->priv = filter;
memcpy(&((*secfilter)->filter_value[3]), memcpy(&((*secfilter)->filter_value[3]),
&(para->filter.filter[1]), DMX_FILTER_SIZE-1); &(para->filter.filter[1]), DMX_FILTER_SIZE-1);
...@@ -638,23 +638,28 @@ dvb_dmxdev_filter_start(dmxdev_filter_t *dmxdevfilter) ...@@ -638,23 +638,28 @@ dvb_dmxdev_filter_start(dmxdev_filter_t *dmxdevfilter)
(*secfilter)->filter_mask[1]=0; (*secfilter)->filter_mask[1]=0;
(*secfilter)->filter_mask[2]=0; (*secfilter)->filter_mask[2]=0;
dmxdevfilter->todo=0; filter->todo = 0;
dmxdevfilter->feed.sec->start_filtering(dmxdevfilter->feed.sec);
dvb_dmxdev_filter_timer(dmxdevfilter); ret = filter->feed.sec->start_filtering (filter->feed.sec);
if (ret < 0)
return ret;
dvb_dmxdev_filter_timer(filter);
break; break;
} }
case DMXDEV_TYPE_PES: case DMXDEV_TYPE_PES:
{ {
struct timespec timeout = { 0 }; struct timespec timeout = { 0 };
struct dmx_pes_filter_params *para=&dmxdevfilter->params.pes; struct dmx_pes_filter_params *para = &filter->params.pes;
dmx_output_t otype; dmx_output_t otype;
int ret; int ret;
int ts_type; int ts_type;
dmx_ts_pes_t ts_pes; dmx_ts_pes_t ts_pes;
dmx_ts_feed_t **tsfeed=&dmxdevfilter->feed.ts; dmx_ts_feed_t **tsfeed = &filter->feed.ts;
dmxdevfilter->feed.ts=0; filter->feed.ts = 0;
otype=para->output; otype=para->output;
ts_pes=(dmx_ts_pes_t) para->pes_type; ts_pes=(dmx_ts_pes_t) para->pes_type;
...@@ -664,11 +669,11 @@ dvb_dmxdev_filter_start(dmxdev_filter_t *dmxdevfilter) ...@@ -664,11 +669,11 @@ dvb_dmxdev_filter_start(dmxdev_filter_t *dmxdevfilter)
else else
ts_type=0; ts_type=0;
if (otype==DMX_OUT_TS_TAP) if (otype == DMX_OUT_TS_TAP)
ts_type|=TS_PACKET; ts_type |= TS_PACKET;
if (otype==DMX_OUT_TAP) if (otype == DMX_OUT_TAP)
ts_type|=TS_PAYLOAD_ONLY|TS_PACKET; ts_type |= TS_PAYLOAD_ONLY|TS_PACKET;
ret=dmxdev->demux->allocate_ts_feed(dmxdev->demux, ret=dmxdev->demux->allocate_ts_feed(dmxdev->demux,
tsfeed, tsfeed,
...@@ -676,75 +681,97 @@ dvb_dmxdev_filter_start(dmxdev_filter_t *dmxdevfilter) ...@@ -676,75 +681,97 @@ dvb_dmxdev_filter_start(dmxdev_filter_t *dmxdevfilter)
if (ret<0) if (ret<0)
return ret; return ret;
(*tsfeed)->priv=(void *) dmxdevfilter; (*tsfeed)->priv = (void *) filter;
ret=(*tsfeed)->set(*tsfeed, para->pid, ts_type, ts_pes, 188, 32768, 0, timeout);
if (ret<0) { ret = (*tsfeed)->set(*tsfeed, para->pid, ts_type, ts_pes,
188, 32768, 0, timeout);
if (ret < 0) {
dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed); dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed);
return ret; return ret;
} }
dmxdevfilter->feed.ts->start_filtering(dmxdevfilter->feed.ts);
ret = filter->feed.ts->start_filtering(filter->feed.ts);
if (ret < 0)
return ret;
break; break;
} }
default: default:
return -EINVAL; return -EINVAL;
} }
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_GO);
return 0; dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
return 0;
} }
static int dvb_demux_open(struct inode *inode, struct file *file) static int dvb_demux_open(struct inode *inode, struct file *file)
{ {
struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;
dmxdev_t *dmxdev=(dmxdev_t *) dvbdev->priv; dmxdev_t *dmxdev=(dmxdev_t *) dvbdev->priv;
int i; int i;
dmxdev_filter_t *dmxdevfilter; dmxdev_filter_t *dmxdevfilter;
if (!dmxdev->filter) if (!dmxdev->filter)
return -EINVAL; return -EINVAL;
if (down_interruptible(&dmxdev->mutex))
if (down_interruptible(&dmxdev->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
for (i=0; i<dmxdev->filternum; i++)
if (dmxdev->filter[i].state==DMXDEV_STATE_FREE) for (i=0; i<dmxdev->filternum; i++)
break; if (dmxdev->filter[i].state==DMXDEV_STATE_FREE)
if (i==dmxdev->filternum) { break;
up(&dmxdev->mutex);
return -EMFILE; if (i==dmxdev->filternum) {
up(&dmxdev->mutex);
return -EMFILE;
} }
dmxdevfilter=&dmxdev->filter[i];
dmxdevfilter->dvbdev=dmxdev->dvbdev; dmxdevfilter=&dmxdev->filter[i];
sema_init(&dmxdevfilter->mutex, 1);
dmxdevfilter->dvbdev=dmxdev->dvbdev;
file->private_data=dmxdevfilter; file->private_data=dmxdevfilter;
dvb_dmxdev_buffer_init(&dmxdevfilter->buffer); dvb_dmxdev_buffer_init(&dmxdevfilter->buffer);
dmxdevfilter->type=DMXDEV_TYPE_NONE; dmxdevfilter->type=DMXDEV_TYPE_NONE;
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
dmxdevfilter->feed.ts=0; dmxdevfilter->feed.ts=0;
init_timer(&dmxdevfilter->timer); init_timer(&dmxdevfilter->timer);
up(&dmxdev->mutex); up(&dmxdev->mutex);
return 0; return 0;
} }
int
dvb_dmxdev_filter_free(dmxdev_t *dmxdev, dmxdev_filter_t *dmxdevfilter) static
int dvb_dmxdev_filter_free(dmxdev_t *dmxdev, dmxdev_filter_t *dmxdevfilter)
{ {
if (down_interruptible(&dmxdev->mutex)) if (down_interruptible(&dmxdev->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
dvb_dmxdev_filter_stop(dmxdevfilter); if (down_interruptible(&dmxdevfilter->mutex)) {
up(&dmxdev->mutex);
return -ERESTARTSYS;
}
dvb_dmxdev_filter_stop(dmxdevfilter);
dvb_dmxdev_filter_reset(dmxdevfilter); dvb_dmxdev_filter_reset(dmxdevfilter);
if (dmxdevfilter->buffer.data) { if (dmxdevfilter->buffer.data) {
void *mem=dmxdevfilter->buffer.data; void *mem=dmxdevfilter->buffer.data;
spin_lock_irq(&dmxdev->lock); spin_lock_irq(&dmxdev->lock);
dmxdevfilter->buffer.data=0; dmxdevfilter->buffer.data=0;
spin_unlock_irq(&dmxdev->lock); spin_unlock_irq(&dmxdev->lock);
vfree(mem); vfree(mem);
} }
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE); dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE);
wake_up(&dmxdevfilter->buffer.queue); wake_up(&dmxdevfilter->buffer.queue);
up(&dmxdevfilter->mutex);
up(&dmxdev->mutex); up(&dmxdev->mutex);
return 0; return 0;
} }
static inline void static inline void
...@@ -759,83 +786,83 @@ invert_mode(dmx_filter_t *filter) ...@@ -759,83 +786,83 @@ invert_mode(dmx_filter_t *filter)
static int static int
dvb_dmxdev_filter_set(dmxdev_t *dmxdev, dvb_dmxdev_filter_set(dmxdev_t *dmxdev,
dmxdev_filter_t *dmxdevfilter, dmxdev_filter_t *dmxdevfilter,
struct dmx_sct_filter_params *params) struct dmx_sct_filter_params *params)
{ {
dprintk ("function : %s\n", __FUNCTION__); dprintk ("function : %s\n", __FUNCTION__);
dvb_dmxdev_filter_stop(dmxdevfilter); dvb_dmxdev_filter_stop(dmxdevfilter);
dmxdevfilter->type=DMXDEV_TYPE_SEC; dmxdevfilter->type=DMXDEV_TYPE_SEC;
dmxdevfilter->pid=params->pid; dmxdevfilter->pid=params->pid;
memcpy(&dmxdevfilter->params.sec, memcpy(&dmxdevfilter->params.sec,
params, sizeof(struct dmx_sct_filter_params)); params, sizeof(struct dmx_sct_filter_params));
invert_mode(&dmxdevfilter->params.sec.filter); invert_mode(&dmxdevfilter->params.sec.filter);
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
if (params->flags&DMX_IMMEDIATE_START) if (params->flags&DMX_IMMEDIATE_START)
return dvb_dmxdev_filter_start(dmxdevfilter); return dvb_dmxdev_filter_start(dmxdevfilter);
return 0; return 0;
} }
static int static int
dvb_dmxdev_pes_filter_set(dmxdev_t *dmxdev, dvb_dmxdev_pes_filter_set(dmxdev_t *dmxdev,
dmxdev_filter_t *dmxdevfilter, dmxdev_filter_t *dmxdevfilter,
struct dmx_pes_filter_params *params) struct dmx_pes_filter_params *params)
{ {
dvb_dmxdev_filter_stop(dmxdevfilter); dvb_dmxdev_filter_stop(dmxdevfilter);
if (params->pes_type>DMX_PES_OTHER || params->pes_type<0) if (params->pes_type>DMX_PES_OTHER || params->pes_type<0)
return -EINVAL; return -EINVAL;
dmxdevfilter->type=DMXDEV_TYPE_PES; dmxdevfilter->type=DMXDEV_TYPE_PES;
dmxdevfilter->pid=params->pid; dmxdevfilter->pid=params->pid;
memcpy(&dmxdevfilter->params, params, sizeof(struct dmx_pes_filter_params)); memcpy(&dmxdevfilter->params, params, sizeof(struct dmx_pes_filter_params));
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
if (params->flags&DMX_IMMEDIATE_START) if (params->flags&DMX_IMMEDIATE_START)
return dvb_dmxdev_filter_start(dmxdevfilter); return dvb_dmxdev_filter_start(dmxdevfilter);
return 0; return 0;
} }
static ssize_t static ssize_t
dvb_dmxdev_read_sec(dmxdev_filter_t *dfil, struct file *file, dvb_dmxdev_read_sec(dmxdev_filter_t *dfil, struct file *file,
char *buf, size_t count, loff_t *ppos) char *buf, size_t count, loff_t *ppos)
{ {
int result, hcount; int result, hcount;
int done=0; int done=0;
if (dfil->todo<=0) { if (dfil->todo<=0) {
hcount=3+dfil->todo; hcount=3+dfil->todo;
if (hcount>count) if (hcount>count)
hcount=count; hcount=count;
result=dvb_dmxdev_buffer_read(&dfil->buffer, file->f_flags&O_NONBLOCK, result=dvb_dmxdev_buffer_read(&dfil->buffer, file->f_flags&O_NONBLOCK,
buf, hcount, ppos); buf, hcount, ppos);
if (result<0) { if (result<0) {
dfil->todo=0; dfil->todo=0;
return result; return result;
} }
if (copy_from_user(dfil->secheader-dfil->todo, buf, result)) if (copy_from_user(dfil->secheader-dfil->todo, buf, result))
return -EFAULT; return -EFAULT;
buf+=result; buf+=result;
done=result; done=result;
count-=result; count-=result;
dfil->todo-=result; dfil->todo-=result;
if (dfil->todo>-3) if (dfil->todo>-3)
return done; return done;
dfil->todo=((dfil->secheader[1]<<8)|dfil->secheader[2])&0xfff; dfil->todo=((dfil->secheader[1]<<8)|dfil->secheader[2])&0xfff;
if (!count) if (!count)
return done; return done;
} }
if (count>dfil->todo) if (count>dfil->todo)
count=dfil->todo; count=dfil->todo;
result=dvb_dmxdev_buffer_read(&dfil->buffer, file->f_flags&O_NONBLOCK, result=dvb_dmxdev_buffer_read(&dfil->buffer, file->f_flags&O_NONBLOCK,
buf, count, ppos); buf, count, ppos);
if (result<0) if (result<0)
return result; return result;
dfil->todo-=result; dfil->todo-=result;
return (result+done); return (result+done);
} }
...@@ -844,19 +871,20 @@ dvb_dmxdev_read_sec(dmxdev_filter_t *dfil, struct file *file, ...@@ -844,19 +871,20 @@ dvb_dmxdev_read_sec(dmxdev_filter_t *dfil, struct file *file,
ssize_t ssize_t
dvb_demux_read(struct file *file, char *buf, size_t count, loff_t *ppos) dvb_demux_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{ {
dmxdev_filter_t *dmxdevfilter=dvb_dmxdev_file_to_filter(file); dmxdev_filter_t *dmxdevfilter=dvb_dmxdev_file_to_filter(file);
//dmxdev_t *dmxdev=dmxdevfilter->dev;
int ret=0; int ret=0;
// semaphore should not be necessary (I hope ...) if (down_interruptible(&dmxdevfilter->mutex))
//down(&dmxdev->mutex); return -ERESTARTSYS;
if (dmxdevfilter->type==DMXDEV_TYPE_SEC) if (dmxdevfilter->type==DMXDEV_TYPE_SEC)
ret=dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos); ret=dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
else else
ret=dvb_dmxdev_buffer_read(&dmxdevfilter->buffer, ret=dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
file->f_flags&O_NONBLOCK, file->f_flags&O_NONBLOCK,
buf, count, ppos); buf, count, ppos);
//up(&dmxdev->mutex);
up(&dmxdevfilter->mutex);
return ret; return ret;
} }
...@@ -864,102 +892,131 @@ dvb_demux_read(struct file *file, char *buf, size_t count, loff_t *ppos) ...@@ -864,102 +892,131 @@ dvb_demux_read(struct file *file, char *buf, size_t count, loff_t *ppos)
static int dvb_demux_do_ioctl(struct inode *inode, struct file *file, static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *parg) unsigned int cmd, void *parg)
{ {
dmxdev_filter_t *dmxdevfilter=dvb_dmxdev_file_to_filter(file); dmxdev_filter_t *dmxdevfilter=dvb_dmxdev_file_to_filter(file);
dmxdev_t *dmxdev=dmxdevfilter->dev; dmxdev_t *dmxdev=dmxdevfilter->dev;
unsigned long arg=(unsigned long) parg; unsigned long arg=(unsigned long) parg;
int ret=0; int ret=0;
if (down_interruptible (&dmxdev->mutex)) if (down_interruptible (&dmxdev->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
switch (cmd) { switch (cmd) {
case DMX_START: case DMX_START:
if (dmxdevfilter->state<DMXDEV_STATE_SET) if (down_interruptible(&dmxdevfilter->mutex)) {
ret=-EINVAL; up(&dmxdev->mutex);
return -ERESTARTSYS;
}
if (dmxdevfilter->state<DMXDEV_STATE_SET)
ret = -EINVAL;
else else
ret=dvb_dmxdev_filter_start(dmxdevfilter); ret = dvb_dmxdev_filter_start(dmxdevfilter);
up(&dmxdevfilter->mutex);
break; break;
case DMX_STOP: case DMX_STOP:
if (down_interruptible(&dmxdevfilter->mutex)) {
up(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret=dvb_dmxdev_filter_stop(dmxdevfilter); ret=dvb_dmxdev_filter_stop(dmxdevfilter);
up(&dmxdevfilter->mutex);
break; break;
case DMX_SET_FILTER: case DMX_SET_FILTER:
ret=dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, if (down_interruptible(&dmxdevfilter->mutex)) {
up(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter,
(struct dmx_sct_filter_params *)parg); (struct dmx_sct_filter_params *)parg);
up(&dmxdevfilter->mutex);
break; break;
case DMX_SET_PES_FILTER: case DMX_SET_PES_FILTER:
if (down_interruptible(&dmxdevfilter->mutex)) {
up(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret=dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, ret=dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter,
(struct dmx_pes_filter_params *)parg); (struct dmx_pes_filter_params *)parg);
up(&dmxdevfilter->mutex);
break; break;
case DMX_SET_BUFFER_SIZE: case DMX_SET_BUFFER_SIZE:
ret=dvb_dmxdev_set_buffer_size(dmxdevfilter, arg); if (down_interruptible(&dmxdevfilter->mutex)) {
up(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret=dvb_dmxdev_set_buffer_size(dmxdevfilter, arg);
up(&dmxdevfilter->mutex);
break;
case DMX_GET_EVENT:
break; break;
case DMX_GET_EVENT:
break;
case DMX_GET_PES_PIDS: case DMX_GET_PES_PIDS:
if (!dmxdev->demux->get_pes_pids) { if (!dmxdev->demux->get_pes_pids) {
ret=-EINVAL; ret=-EINVAL;
break; break;
} }
dmxdev->demux->get_pes_pids(dmxdev->demux, (uint16_t *)parg); dmxdev->demux->get_pes_pids(dmxdev->demux, (uint16_t *)parg);
break; break;
case DMX_GET_STC:
if (!dmxdev->demux->get_stc) {
ret=-EINVAL;
break;
}
ret = dmxdev->demux->get_stc(dmxdev->demux,
((struct dmx_stc *)parg)->num,
&((struct dmx_stc *)parg)->stc,
&((struct dmx_stc *)parg)->base);
break;
default: default:
ret=-EINVAL; ret=-EINVAL;
} }
up(&dmxdev->mutex); up(&dmxdev->mutex);
return ret; return ret;
} }
static int dvb_demux_ioctl(struct inode *inode, struct file *file, static int dvb_demux_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
return video_usercopy(inode, file, cmd, arg, dvb_demux_do_ioctl); return dvb_usercopy(inode, file, cmd, arg, dvb_demux_do_ioctl);
} }
static unsigned int dvb_demux_poll(struct file *file, poll_table *wait) static
unsigned int dvb_demux_poll (struct file *file, poll_table *wait)
{ {
dmxdev_filter_t *dmxdevfilter=dvb_dmxdev_file_to_filter(file); dmxdev_filter_t *dmxdevfilter = dvb_dmxdev_file_to_filter(file);
unsigned int mask = 0;
if (!dmxdevfilter) if (!dmxdevfilter)
return -EINVAL; return -EINVAL;
if (dmxdevfilter->state==DMXDEV_STATE_FREE)
return 0;
if (dmxdevfilter->buffer.error)
return (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
if (dmxdevfilter->buffer.pread!=dmxdevfilter->buffer.pwrite)
return (POLLIN | POLLRDNORM | POLLPRI);
if (dmxdevfilter->state!=DMXDEV_STATE_GO)
return 0;
poll_wait(file, &dmxdevfilter->buffer.queue, wait); poll_wait(file, &dmxdevfilter->buffer.queue, wait);
if (dmxdevfilter->state==DMXDEV_STATE_FREE) if (dmxdevfilter->state != DMXDEV_STATE_GO &&
return 0; dmxdevfilter->state != DMXDEV_STATE_DONE)
return 0;
if (dmxdevfilter->buffer.error) if (dmxdevfilter->buffer.error)
return (POLLIN | POLLRDNORM | POLLPRI | POLLERR); mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
if (dmxdevfilter->buffer.pread!=dmxdevfilter->buffer.pwrite) if (dmxdevfilter->buffer.pread != dmxdevfilter->buffer.pwrite)
return (POLLIN | POLLRDNORM | POLLPRI); mask |= (POLLIN | POLLRDNORM | POLLPRI);
return 0; return mask;
} }
static int dvb_demux_release(struct inode *inode, struct file *file)
static
int dvb_demux_release(struct inode *inode, struct file *file)
{ {
dmxdev_filter_t *dmxdevfilter=dvb_dmxdev_file_to_filter(file); dmxdev_filter_t *dmxdevfilter = dvb_dmxdev_file_to_filter(file);
dmxdev_t *dmxdev=dmxdevfilter->dev; dmxdev_t *dmxdev = dmxdevfilter->dev;
return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter); return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
} }
...@@ -988,64 +1045,62 @@ static int dvb_dvr_do_ioctl(struct inode *inode, struct file *file, ...@@ -988,64 +1045,62 @@ static int dvb_dvr_do_ioctl(struct inode *inode, struct file *file,
int ret=0; int ret=0;
if (down_interruptible (&dmxdev->mutex)) if (down_interruptible (&dmxdev->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
switch (cmd) { switch (cmd) {
case DMX_SET_BUFFER_SIZE: case DMX_SET_BUFFER_SIZE:
// FIXME: implement // FIXME: implement
ret=0; ret=0;
break; break;
default: default:
ret=-EINVAL; ret=-EINVAL;
} }
up(&dmxdev->mutex); up(&dmxdev->mutex);
return ret; return ret;
} }
static int dvb_dvr_ioctl(struct inode *inode, struct file *file, static int dvb_dvr_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
return video_usercopy(inode, file, cmd, arg, dvb_dvr_do_ioctl); return dvb_usercopy(inode, file, cmd, arg, dvb_dvr_do_ioctl);
} }
static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait) static
unsigned int dvb_dvr_poll (struct file *file, poll_table *wait)
{ {
struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
dmxdev_t *dmxdev=(dmxdev_t *) dvbdev->priv; dmxdev_t *dmxdev = (dmxdev_t *) dvbdev->priv;
unsigned int mask = 0;
dprintk ("function : %s\n", __FUNCTION__); dprintk ("function : %s\n", __FUNCTION__);
if ((file->f_flags&O_ACCMODE)==O_RDONLY) { poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
if (dmxdev->dvr_buffer.error)
return (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
if (dmxdev->dvr_buffer.pread!=dmxdev->dvr_buffer.pwrite) if ((file->f_flags&O_ACCMODE) == O_RDONLY) {
return (POLLIN | POLLRDNORM | POLLPRI);
poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
if (dmxdev->dvr_buffer.error) if (dmxdev->dvr_buffer.error)
return (POLLIN | POLLRDNORM | POLLPRI | POLLERR); mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
if (dmxdev->dvr_buffer.pread!=dmxdev->dvr_buffer.pwrite) if (dmxdev->dvr_buffer.pread!=dmxdev->dvr_buffer.pwrite)
return (POLLIN | POLLRDNORM | POLLPRI); mask |= (POLLIN | POLLRDNORM | POLLPRI);
return 0;
} else } else
return (POLLOUT | POLLWRNORM | POLLPRI); mask |= (POLLOUT | POLLWRNORM | POLLPRI);
return mask;
} }
static struct file_operations dvb_dvr_fops = {
static
struct file_operations dvb_dvr_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.read = dvb_dvr_read, .read = dvb_dvr_read,
.write = dvb_dvr_write, .write = dvb_dvr_write,
.ioctl = dvb_dvr_ioctl, .ioctl = dvb_dvr_ioctl,
.open = dvb_dvr_open, .open = dvb_dvr_open,
.release = dvb_dvr_release, .release = dvb_dvr_release,
.poll =dvb_dvr_poll, .poll = dvb_dvr_poll,
}; };
static struct dvb_device dvbdev_dvr = { static struct dvb_device dvbdev_dvr = {
...@@ -1058,37 +1113,38 @@ static struct dvb_device dvbdev_dvr = { ...@@ -1058,37 +1113,38 @@ static struct dvb_device dvbdev_dvr = {
int int
dvb_dmxdev_init(dmxdev_t *dmxdev, struct dvb_adapter *dvb_adapter) dvb_dmxdev_init(dmxdev_t *dmxdev, struct dvb_adapter *dvb_adapter)
{ {
int i; int i;
if (dmxdev->demux->open(dmxdev->demux)<0) if (dmxdev->demux->open(dmxdev->demux)<0)
return -EUSERS; return -EUSERS;
dmxdev->filter=vmalloc(dmxdev->filternum*sizeof(dmxdev_filter_t)); dmxdev->filter=vmalloc(dmxdev->filternum*sizeof(dmxdev_filter_t));
if (!dmxdev->filter) if (!dmxdev->filter)
return -ENOMEM; return -ENOMEM;
dmxdev->dvr=vmalloc(dmxdev->filternum*sizeof(dmxdev_dvr_t)); dmxdev->dvr=vmalloc(dmxdev->filternum*sizeof(dmxdev_dvr_t));
if (!dmxdev->dvr) { if (!dmxdev->dvr) {
vfree(dmxdev->filter); vfree(dmxdev->filter);
dmxdev->filter=0; dmxdev->filter=0;
return -ENOMEM; return -ENOMEM;
} }
sema_init(&dmxdev->mutex, 1); sema_init(&dmxdev->mutex, 1);
spin_lock_init(&dmxdev->lock); spin_lock_init(&dmxdev->lock);
for (i=0; i<dmxdev->filternum; i++) { for (i=0; i<dmxdev->filternum; i++) {
dmxdev->filter[i].dev=dmxdev; dmxdev->filter[i].dev=dmxdev;
dmxdev->filter[i].buffer.data=0; dmxdev->filter[i].buffer.data=0;
dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE); dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE);
dmxdev->dvr[i].dev=dmxdev; dmxdev->dvr[i].dev=dmxdev;
dmxdev->dvr[i].buffer.data=0; dmxdev->dvr[i].buffer.data=0;
dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE); dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE);
dvb_dmxdev_dvr_state_set(&dmxdev->dvr[i], DMXDEV_STATE_FREE); dvb_dmxdev_dvr_state_set(&dmxdev->dvr[i], DMXDEV_STATE_FREE);
} }
dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev, DVB_DEVICE_DEMUX); dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev, DVB_DEVICE_DEMUX);
dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr, dmxdev, DVB_DEVICE_DVR); dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr, dmxdev, DVB_DEVICE_DVR);
dvb_dmxdev_buffer_init(&dmxdev->dvr_buffer); dvb_dmxdev_buffer_init(&dmxdev->dvr_buffer);
MOD_INC_USE_COUNT; /* fixme: is this correct? */
try_module_get(THIS_MODULE);
return 0; return 0;
} }
...@@ -1098,15 +1154,16 @@ dvb_dmxdev_release(dmxdev_t *dmxdev) ...@@ -1098,15 +1154,16 @@ dvb_dmxdev_release(dmxdev_t *dmxdev)
dvb_unregister_device(dmxdev->dvbdev); dvb_unregister_device(dmxdev->dvbdev);
dvb_unregister_device(dmxdev->dvr_dvbdev); dvb_unregister_device(dmxdev->dvr_dvbdev);
if (dmxdev->filter) { if (dmxdev->filter) {
vfree(dmxdev->filter); vfree(dmxdev->filter);
dmxdev->filter=0; dmxdev->filter=0;
} }
if (dmxdev->dvr) { if (dmxdev->dvr) {
vfree(dmxdev->dvr); vfree(dmxdev->dvr);
dmxdev->dvr=0; dmxdev->dvr=0;
} }
dmxdev->demux->close(dmxdev->demux); dmxdev->demux->close(dmxdev->demux);
MOD_DEC_USE_COUNT; /* fixme: is this correct? */
module_put(THIS_MODULE);
} }
...@@ -85,6 +85,8 @@ typedef struct dmxdev_filter_s { ...@@ -85,6 +85,8 @@ typedef struct dmxdev_filter_s {
struct dmxdev_s *dev; struct dmxdev_s *dev;
dmxdev_buffer_t buffer; dmxdev_buffer_t buffer;
struct semaphore mutex;
// only for sections // only for sections
struct timer_list timer; struct timer_list timer;
int todo; int todo;
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* dvb_demux.c - DVB kernel demux API * dvb_demux.c - DVB kernel demux API
* *
* Copyright (C) 2000-2001 Ralph Metzler <ralph@convergence.de> * Copyright (C) 2000-2001 Ralph Metzler <ralph@convergence.de>
* & Marcus Metzler <marcus@convergence.de> * & Marcus Metzler <marcus@convergence.de>
* for convergence integrated media GmbH * for convergence integrated media GmbH
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License * modify it under the terms of the GNU Lesser General Public License
...@@ -27,27 +27,36 @@ ...@@ -27,27 +27,36 @@
#include <linux/version.h> #include <linux/version.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "compat.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51)
#include "compat.h"
#else
#include <linux/crc32.h>
#endif
#include "dvb_demux.h" #include "dvb_demux.h"
#define NOBUFS #define NOBUFS
LIST_HEAD(dmx_muxs); LIST_HEAD(dmx_muxs);
int dmx_register_demux(dmx_demux_t *demux) int dmx_register_demux(dmx_demux_t *demux)
{ {
struct list_head *pos, *head=&dmx_muxs; struct list_head *pos;
if (!(demux->id && demux->vendor && demux->model)) if (!(demux->id && demux->vendor && demux->model))
return -EINVAL; return -EINVAL;
list_for_each(pos, head)
{ list_for_each(pos, &dmx_muxs) {
if (!strcmp(DMX_DIR_ENTRY(pos)->id, demux->id)) if (!strcmp(DMX_DIR_ENTRY(pos)->id, demux->id))
return -EEXIST; return -EEXIST;
} }
demux->users=0;
list_add(&(demux->reg_list), head); demux->users = 0;
MOD_INC_USE_COUNT; list_add(&demux->reg_list, &dmx_muxs);
/* fixme: is this correct? */
try_module_get(THIS_MODULE);
return 0; return 0;
} }
...@@ -55,25 +64,25 @@ int dmx_unregister_demux(dmx_demux_t* demux) ...@@ -55,25 +64,25 @@ int dmx_unregister_demux(dmx_demux_t* demux)
{ {
struct list_head *pos, *n, *head=&dmx_muxs; struct list_head *pos, *n, *head=&dmx_muxs;
list_for_each_safe (pos, n, head) list_for_each_safe (pos, n, head) {
{ if (DMX_DIR_ENTRY(pos) == demux) {
if (DMX_DIR_ENTRY(pos)==demux) if (demux->users>0)
{ return -EINVAL;
if (demux->users>0) list_del(pos);
return -EINVAL; /* fixme: is this correct? */
list_del(pos); module_put(THIS_MODULE);
MOD_DEC_USE_COUNT;
return 0; return 0;
} }
} }
return -ENODEV; return -ENODEV;
} }
struct list_head *dmx_get_demuxes(void) struct list_head *dmx_get_demuxes(void)
{ {
if (list_empty(&dmx_muxs)) if (list_empty(&dmx_muxs))
return NULL; return NULL;
return &dmx_muxs; return &dmx_muxs;
} }
...@@ -82,628 +91,661 @@ struct list_head *dmx_get_demuxes(void) ...@@ -82,628 +91,661 @@ struct list_head *dmx_get_demuxes(void)
* static inlined helper functions * static inlined helper functions
******************************************************************************/ ******************************************************************************/
static inline u16
section_length(const u8 *buf) static inline
u16 section_length(const u8 *buf)
{ {
return 3+((buf[1]&0x0f)<<8)+buf[2]; return 3+((buf[1]&0x0f)<<8)+buf[2];
} }
static inline u16
ts_pid(const u8 *buf) static inline
u16 ts_pid(const u8 *buf)
{ {
return ((buf[1]&0x1f)<<8)+buf[2]; return ((buf[1]&0x1f)<<8)+buf[2];
} }
static inline int
payload(const u8 *tsp) static inline
int payload(const u8 *tsp)
{ {
if (!(tsp[3]&0x10)) // no payload? if (!(tsp[3]&0x10)) // no payload?
return 0; return 0;
if (tsp[3]&0x20) { // adaptation field? if (tsp[3]&0x20) { // adaptation field?
if (tsp[4]>183) // corrupted data? if (tsp[4]>183) // corrupted data?
return 0; return 0;
else else
return 184-1-tsp[4]; return 184-1-tsp[4];
} }
return 184; return 184;
} }
static u32 void dvb_set_crc32(u8 *data, int length)
dvb_crc_table[256] = {
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4};
u32 dvb_crc32(u8 *data, int len)
{ {
int i; u32 crc;
u32 crc = 0xffffffff;
crc = crc32_le(~0, data, length);
for (i=0; i<len; i++) data[length] = (crc >> 24) & 0xff;
crc = (crc << 8) ^ dvb_crc_table[((crc >> 24) ^ *data++) & 0xff]; data[length+1] = (crc >> 16) & 0xff;
return crc; data[length+2] = (crc >> 8) & 0xff;
data[length+3] = (crc) & 0xff;
} }
void dvb_set_crc32(u8 *data, int length)
static
u32 dvb_dmx_crc32 (struct dvb_demux_feed *f, const u8 *src, size_t len)
{ {
u32 crc; return (f->feed.sec.crc_val = crc32_le (f->feed.sec.crc_val, src, len));
}
crc=dvb_crc32(data,length);
data[length] = (crc>>24)&0xff; static
data[length+1] = (crc>>16)&0xff; void dvb_dmx_memcopy (struct dvb_demux_feed *f, u8 *d, const u8 *s, size_t len)
data[length+2] = (crc>>8)&0xff; {
data[length+3] = (crc)&0xff; memcpy (d, s, len);
} }
/****************************************************************************** /******************************************************************************
* Software filter functions * Software filter functions
******************************************************************************/ ******************************************************************************/
static inline int static inline
dvb_dmx_swfilter_payload(struct dvb_demux_feed *dvbdmxfeed, const u8 *buf) int dvb_dmx_swfilter_payload (struct dvb_demux_feed *feed, const u8 *buf)
{ {
int p, count; int count = payload(buf);
int p;
//int ccok; //int ccok;
//u8 cc; //u8 cc;
if (!(count=payload(buf))) if (count == 0)
return -1; return -1;
p=188-count;
/* p = 188-count;
/*
cc=buf[3]&0x0f; cc=buf[3]&0x0f;
ccok=((dvbdmxfeed->cc+1)&0x0f)==cc ? 1 : 0; ccok=((dvbdmxfeed->cc+1)&0x0f)==cc ? 1 : 0;
dvbdmxfeed->cc=cc; dvbdmxfeed->cc=cc;
if (!ccok) if (!ccok)
printk("missed packet!\n"); printk("missed packet!\n");
*/ */
if (buf[1]&0x40) // PUSI ?
dvbdmxfeed->peslen=0xfffa; if (buf[1] & 0x40) // PUSI ?
dvbdmxfeed->peslen+=count; feed->peslen = 0xfffa;
return dvbdmxfeed->cb.ts((u8 *)&buf[p], count, 0, 0, feed->peslen += count;
&dvbdmxfeed->feed.ts, DMX_OK);
return feed->cb.ts (&buf[p], count, 0, 0, &feed->feed.ts, DMX_OK);
} }
static int static
dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *dvbdmxfeed, int dvb_dmx_swfilter_sectionfilter (struct dvb_demux_feed *feed,
struct dvb_demux_filter *f) struct dvb_demux_filter *f)
{ {
dmx_section_filter_t *filter=&f->filter; u8 neq = 0;
int i; int i;
u8 xor, neq=0;
for (i=0; i<DVB_DEMUX_MASK_MAX; i++) {
u8 xor = f->filter.filter_value[i] ^ feed->feed.sec.secbuf[i];
for (i=0; i<DVB_DEMUX_MASK_MAX; i++) { if (f->maskandmode[i] & xor)
xor=filter->filter_value[i]^dvbdmxfeed->secbuf[i];
if (f->maskandmode[i]&xor)
return 0; return 0;
neq|=f->maskandnotmode[i]&xor;
neq |= f->maskandnotmode[i] & xor;
} }
if (f->doneq && !neq)
if (f->doneq & !neq)
return 0; return 0;
return dvbdmxfeed->cb.sec(dvbdmxfeed->secbuf, dvbdmxfeed->seclen, return feed->cb.sec (feed->feed.sec.secbuf, feed->feed.sec.seclen,
0, 0, filter, DMX_OK); 0, 0, &f->filter, DMX_OK);
} }
static inline int
dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *dvbdmxfeed) static inline
int dvb_dmx_swfilter_section_feed (struct dvb_demux_feed *feed)
{ {
u8 *buf=dvbdmxfeed->secbuf; struct dvb_demux *demux = feed->demux;
struct dvb_demux_filter *f; struct dvb_demux_filter *f = feed->filter;
dmx_section_feed_t *sec = &feed->feed.sec;
if (dvbdmxfeed->secbufp!=dvbdmxfeed->seclen) u8 *buf = sec->secbuf;
return -1;
if (!dvbdmxfeed->feed.sec.is_filtering) if (sec->secbufp != sec->seclen)
return 0; return -1;
if (!(f=dvbdmxfeed->filter))
return 0; if (!sec->is_filtering)
do return 0;
if (dvb_dmx_swfilter_sectionfilter(dvbdmxfeed, f)<0)
return -1; if (!f)
while ((f=f->next) && dvbdmxfeed->feed.sec.is_filtering); return 0;
dvbdmxfeed->secbufp=dvbdmxfeed->seclen=0; if (sec->check_crc && demux->check_crc32(feed, sec->secbuf, sec->seclen))
memset(buf, 0, DVB_DEMUX_MASK_MAX); return -1;
return 0;
do {
if (dvb_dmx_swfilter_sectionfilter(feed, f) < 0)
return -1;
} while ((f = f->next) && sec->is_filtering);
sec->secbufp = sec->seclen = 0;
memset(buf, 0, DVB_DEMUX_MASK_MAX);
return 0;
} }
static inline int
dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *dvbdmxfeed, const u8 *buf) static
int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 *buf)
{ {
int p, count; struct dvb_demux *demux = feed->demux;
int ccok, rest; dmx_section_feed_t *sec = &feed->feed.sec;
int p, count;
int ccok, rest;
u8 cc; u8 cc;
if (!(count=payload(buf))) if (!(count = payload(buf)))
return -1; return -1;
p=188-count;
cc=buf[3]&0x0f; p = 188-count;
ccok=((dvbdmxfeed->cc+1)&0x0f)==cc ? 1 : 0;
dvbdmxfeed->cc=cc;
if (buf[1]&0x40) { // PUSI set cc = buf[3] & 0x0f;
// offset to start of first section is in buf[p] ccok = ((feed->cc+1) & 0x0f) == cc ? 1 : 0;
feed->cc = cc;
if (buf[1] & 0x40) { // PUSI set
// offset to start of first section is in buf[p]
if (p+buf[p]>187) // trash if it points beyond packet if (p+buf[p]>187) // trash if it points beyond packet
return -1; return -1;
if (buf[p] && ccok) { // rest of previous section?
// did we have enough data in last packet to calc length? if (buf[p] && ccok) { // rest of previous section?
int tmp=3-dvbdmxfeed->secbufp; // did we have enough data in last packet to calc length?
if (tmp>0 && tmp!=3) { int tmp = 3 - sec->secbufp;
if (p+tmp>=187)
if (tmp > 0 && tmp != 3) {
if (p + tmp >= 187)
return -1; return -1;
memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp,
buf+p+1, tmp); demux->memcopy (feed, sec->secbuf+sec->secbufp,
dvbdmxfeed->seclen=section_length(dvbdmxfeed->secbuf); buf+p+1, tmp);
if (dvbdmxfeed->seclen>4096)
sec->seclen = section_length(sec->secbuf);
if (sec->seclen > 4096)
return -1; return -1;
} }
rest=dvbdmxfeed->seclen-dvbdmxfeed->secbufp;
if (rest==buf[p] && dvbdmxfeed->seclen) { rest = sec->seclen - sec->secbufp;
memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp,
buf+p+1, buf[p]); if (rest == buf[p] && sec->seclen) {
dvbdmxfeed->secbufp+=buf[p]; demux->memcopy (feed, sec->secbuf + sec->secbufp,
dvb_dmx_swfilter_section_feed(dvbdmxfeed); buf+p+1, buf[p]);
} sec->secbufp += buf[p];
} dvb_dmx_swfilter_section_feed(feed);
p+=buf[p]+1; // skip rest of last section }
count=188-p; }
while (count>0) {
if ((count>2) && // enough data to determine sec length? p += buf[p] + 1; // skip rest of last section
((dvbdmxfeed->seclen=section_length(buf+p))<=count)) { count = 188 - p;
if (dvbdmxfeed->seclen>4096)
while (count) {
sec->crc_val = ~0;
if ((count>2) && // enough data to determine sec length?
((sec->seclen = section_length(buf+p)) <= count)) {
if (sec->seclen>4096)
return -1; return -1;
memcpy(dvbdmxfeed->secbuf, buf+p,
dvbdmxfeed->seclen); demux->memcopy (feed, sec->secbuf, buf+p,
dvbdmxfeed->secbufp=dvbdmxfeed->seclen; sec->seclen);
p+=dvbdmxfeed->seclen;
count=188-p; sec->secbufp = sec->seclen;
dvb_dmx_swfilter_section_feed(dvbdmxfeed); p += sec->seclen;
count = 188 - p;
// filling bytes until packet end?
if (count && buf[p]==0xff) dvb_dmx_swfilter_section_feed(feed);
count=0;
} else { // section continues to following TS packet // filling bytes until packet end?
memcpy(dvbdmxfeed->secbuf, buf+p, count); if (count && buf[p]==0xff)
dvbdmxfeed->secbufp+=count; count=0;
count=0;
} } else { // section continues to following TS packet
} demux->memcopy(feed, sec->secbuf, buf+p, count);
sec->secbufp+=count;
count=0;
}
}
return 0; return 0;
} }
// section continued below // section continued below
if (!ccok) if (!ccok)
return -1; return -1;
if (!dvbdmxfeed->secbufp) // any data in last ts packet?
if (!sec->secbufp) // any data in last ts packet?
return -1; return -1;
// did we have enough data in last packet to calc section length? // did we have enough data in last packet to calc section length?
if (dvbdmxfeed->secbufp<3) { if (sec->secbufp < 3) {
int tmp=3-dvbdmxfeed->secbufp; int tmp = 3 - sec->secbufp;
if (tmp>count) if (tmp>count)
return -1; return -1;
memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, buf+p, tmp);
dvbdmxfeed->seclen=section_length(dvbdmxfeed->secbuf); sec->crc_val = ~0;
if (dvbdmxfeed->seclen>4096)
demux->memcopy (feed, sec->secbuf + sec->secbufp, buf+p, tmp);
sec->seclen = section_length(sec->secbuf);
if (sec->seclen > 4096)
return -1; return -1;
} }
rest=dvbdmxfeed->seclen-dvbdmxfeed->secbufp;
if (rest<0) rest = sec->seclen - sec->secbufp;
if (rest < 0)
return -1; return -1;
if (rest<=count) { // section completed in this TS packet
memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, buf+p, rest); if (rest <= count) { // section completed in this TS packet
dvbdmxfeed->secbufp+=rest; demux->memcopy (feed, sec->secbuf + sec->secbufp, buf+p, rest);
dvb_dmx_swfilter_section_feed(dvbdmxfeed); sec->secbufp += rest;
dvb_dmx_swfilter_section_feed(feed);
} else { // section continues in following ts packet } else { // section continues in following ts packet
memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, buf+p, count); demux->memcopy (feed, sec->secbuf + sec->secbufp, buf+p, count);
dvbdmxfeed->secbufp+=count; sec->secbufp += count;
} }
return 0;
return 0;
} }
static inline void
dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *dvbdmxfeed, const u8 *buf) static inline
void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, const u8 *buf)
{ {
switch(dvbdmxfeed->type) { switch(feed->type) {
case DMX_TYPE_TS: case DMX_TYPE_TS:
if (!dvbdmxfeed->feed.ts.is_filtering) if (!feed->feed.ts.is_filtering)
break; break;
if (dvbdmxfeed->ts_type & TS_PACKET) { if (feed->ts_type & TS_PACKET) {
if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY) if (feed->ts_type & TS_PAYLOAD_ONLY)
dvb_dmx_swfilter_payload(dvbdmxfeed, buf); dvb_dmx_swfilter_payload(feed, buf);
else else
dvbdmxfeed->cb.ts((u8 *)buf, 188, 0, 0, feed->cb.ts(buf, 188, 0, 0, &feed->feed.ts, DMX_OK);
&dvbdmxfeed->feed.ts, DMX_OK); }
} if (feed->ts_type & TS_DECODER)
if (dvbdmxfeed->ts_type & TS_DECODER) if (feed->demux->write_to_decoder)
if (dvbdmxfeed->demux->write_to_decoder) feed->demux->write_to_decoder(feed, buf, 188);
dvbdmxfeed->demux-> break;
write_to_decoder(dvbdmxfeed, (u8 *)buf, 188);
break; case DMX_TYPE_SEC:
if (!feed->feed.sec.is_filtering)
case DMX_TYPE_SEC: break;
if (!dvbdmxfeed->feed.sec.is_filtering) if (dvb_dmx_swfilter_section_packet(feed, buf) < 0)
break; feed->feed.sec.seclen = feed->feed.sec.secbufp=0;
if (dvb_dmx_swfilter_section_packet(dvbdmxfeed, buf)<0) break;
dvbdmxfeed->seclen=dvbdmxfeed->secbufp=0;
break; default:
break;
default: }
break;
}
} }
void
dvb_dmx_swfilter_packet(struct dvb_demux *dvbdmx, const u8 *buf)
{
struct dvb_demux_feed *dvbdmxfeed;
if (!(dvbdmxfeed=dvbdmx->pid2feed[ts_pid(buf)])) void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
return; {
dvb_dmx_swfilter_packet_type(dvbdmxfeed, buf); struct dvb_demux_feed *feed;
struct list_head *pos, *head=&demux->feed_list;
u16 pid = ts_pid(buf);
list_for_each(pos, head) {
feed = list_entry(pos, struct dvb_demux_feed, list_head);
if (feed->pid == pid)
dvb_dmx_swfilter_packet_type (feed, buf);
if (feed->pid == 0x2000)
feed->cb.ts(buf, 188, 0, 0, &feed->feed.ts, DMX_OK);
}
} }
void
dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, int count) void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, size_t count)
{ {
struct dvb_demux_feed *dvbdmxfeed; spin_lock(&demux->lock);
spin_lock(&dvbdmx->lock); while (count--) {
if ((dvbdmxfeed=dvbdmx->pid2feed[0x2000])) dvb_dmx_swfilter_packet(demux, buf);
dvbdmxfeed->cb.ts((u8 *)buf, count*188, 0, 0, buf += 188;
&dvbdmxfeed->feed.ts, DMX_OK);
while (count) {
dvb_dmx_swfilter_packet(dvbdmx, buf);
count--;
buf+=188;
} }
spin_unlock(&dvbdmx->lock);
spin_unlock(&demux->lock);
} }
static inline void
dvb_dmx_swfilter(struct dvb_demux *dvbdmx, const u8 *buf, size_t count) void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
{ {
int p=0,i, j; int p = 0,i, j;
if ((i=dvbdmx->tsbufp)) { if ((i = demux->tsbufp)) {
if (count<(j=188-i)) { if (count < (j=188-i)) {
memcpy(&dvbdmx->tsbuf[i], buf, count); memcpy(&demux->tsbuf[i], buf, count);
dvbdmx->tsbufp+=count; demux->tsbufp += count;
return; return;
} }
memcpy(&dvbdmx->tsbuf[i], buf, j); memcpy(&demux->tsbuf[i], buf, j);
dvb_dmx_swfilter_packet(dvbdmx, dvbdmx->tsbuf); dvb_dmx_swfilter_packet(demux, demux->tsbuf);
dvbdmx->tsbufp=0; demux->tsbufp = 0;
p+=j; p += j;
} }
while (p<count) { while (p < count) {
if (buf[p]==0x47) { if (buf[p] == 0x47) {
if (count-p>=188) { if (count-p >= 188) {
dvb_dmx_swfilter_packet(dvbdmx, buf+p); dvb_dmx_swfilter_packet(demux, buf+p);
p+=188; p += 188;
} else { } else {
i=count-p; i = count-p;
memcpy(dvbdmx->tsbuf, buf+p, i); memcpy(demux->tsbuf, buf+p, i);
dvbdmx->tsbufp=i; demux->tsbufp=i;
return; return;
} }
} else } else
p++; p++;
} }
} }
/****************************************************************************** static
****************************************************************************** struct dvb_demux_filter* dvb_dmx_filter_alloc(struct dvb_demux *demux)
* DVB DEMUX API LEVEL FUNCTIONS
******************************************************************************
******************************************************************************/
static struct dvb_demux_filter *
dvb_dmx_filter_alloc(struct dvb_demux *dvbdmx)
{ {
int i; int i;
for (i=0; i<dvbdmx->filternum; i++) for (i=0; i<demux->filternum; i++)
if (dvbdmx->filter[i].state==DMX_STATE_FREE) if (demux->filter[i].state == DMX_STATE_FREE)
break; break;
if (i==dvbdmx->filternum)
return 0; if (i == demux->filternum)
dvbdmx->filter[i].state=DMX_STATE_ALLOCATED; return NULL;
return &dvbdmx->filter[i];
demux->filter[i].state = DMX_STATE_ALLOCATED;
return &demux->filter[i];
} }
static struct dvb_demux_feed * static
dvb_dmx_feed_alloc(struct dvb_demux *dvbdmx) struct dvb_demux_feed* dvb_dmx_feed_alloc(struct dvb_demux *demux)
{ {
int i; int i;
for (i=0; i<dvbdmx->feednum; i++)
if (dvbdmx->feed[i].state==DMX_STATE_FREE)
break;
if (i==dvbdmx->feednum)
return 0;
dvbdmx->feed[i].state=DMX_STATE_ALLOCATED;
return &dvbdmx->feed[i];
}
for (i=0; i<demux->feednum; i++)
if (demux->feed[i].state == DMX_STATE_FREE)
break;
/****************************************************************************** if (i == demux->feednum)
* dmx_ts_feed API calls return NULL;
******************************************************************************/
static int demux->feed[i].state = DMX_STATE_ALLOCATED;
dmx_pid_set(u16 pid, struct dvb_demux_feed *dvbdmxfeed)
return &demux->feed[i];
}
static
int dmx_pid_set (u16 pid, struct dvb_demux_feed *feed)
{ {
struct dvb_demux *dvbdmx=dvbdmxfeed->demux; struct dvb_demux *demux = feed->demux;
struct dvb_demux_feed **pid2feed=dvbdmx->pid2feed; struct list_head *pos, *n, *head=&demux->feed_list;
if (pid>DMX_MAX_PID) if (pid > DMX_MAX_PID)
return -EINVAL; return -EINVAL;
if (dvbdmxfeed->pid!=0xffff) {
if (dvbdmxfeed->pid<=DMX_MAX_PID) if (pid == feed->pid)
pid2feed[dvbdmxfeed->pid]=0; return 0;
dvbdmxfeed->pid=0xffff;
} if (feed->pid <= DMX_MAX_PID)
if (pid2feed[pid]) { list_for_each_safe(pos, n, head)
return -EBUSY; if (DMX_FEED_ENTRY(pos)->pid == feed->pid) {
} list_del(pos);
pid2feed[pid]=dvbdmxfeed; break;
dvbdmxfeed->pid=pid; }
list_add(&feed->list_head, head);
feed->pid = pid;
return 0; return 0;
} }
static int static
dmx_ts_feed_set(struct dmx_ts_feed_s* feed, int dmx_ts_feed_set (struct dmx_ts_feed_s* ts_feed, u16 pid, int ts_type,
u16 pid, dmx_ts_pes_t pes_type, size_t callback_length,
int ts_type, size_t circular_buffer_size, int descramble,
dmx_ts_pes_t pes_type, struct timespec timeout)
size_t callback_length,
size_t circular_buffer_size,
int descramble,
struct timespec timeout
)
{ {
struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed; struct dvb_demux_feed *feed = (struct dvb_demux_feed *) ts_feed;
struct dvb_demux *dvbdmx=dvbdmxfeed->demux; struct dvb_demux *demux = feed->demux;
int ret; int ret;
if (down_interruptible (&dvbdmx->mutex)) if (down_interruptible (&demux->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
if (ts_type & TS_DECODER) { if (ts_type & TS_DECODER) {
if (pes_type >= DMX_TS_PES_OTHER) { if (pes_type >= DMX_TS_PES_OTHER) {
up(&dvbdmx->mutex); up(&demux->mutex);
return -EINVAL; return -EINVAL;
} }
if (dvbdmx->pesfilter[pes_type] &&
(dvbdmx->pesfilter[pes_type]!=dvbdmxfeed)) { if (demux->pesfilter[pes_type] &&
up(&dvbdmx->mutex); demux->pesfilter[pes_type] != feed) {
return -EINVAL; up(&demux->mutex);
return -EINVAL;
} }
if ((pes_type != DMX_TS_PES_PCR0) && if ((pes_type != DMX_TS_PES_PCR0) &&
(pes_type != DMX_TS_PES_PCR1) && (pes_type != DMX_TS_PES_PCR1) &&
(pes_type != DMX_TS_PES_PCR2) && (pes_type != DMX_TS_PES_PCR2) &&
(pes_type != DMX_TS_PES_PCR3)) { (pes_type != DMX_TS_PES_PCR3)) {
if ((ret=dmx_pid_set(pid, dvbdmxfeed))<0) { if ((ret = dmx_pid_set(pid, feed))<0) {
up(&dvbdmx->mutex); up(&demux->mutex);
return ret; return ret;
} else }
dvbdmxfeed->pid=pid; } else
} feed->pid = pid;
dvbdmx->pesfilter[pes_type]=dvbdmxfeed;
dvbdmx->pids[pes_type]=dvbdmxfeed->pid; demux->pesfilter[pes_type] = feed;
} else demux->pids[pes_type] = feed->pid;
if ((ret=dmx_pid_set(pid, dvbdmxfeed))<0) { } else {
up(&dvbdmx->mutex); if ((ret = dmx_pid_set(pid, feed))<0) {
up(&demux->mutex);
return ret; return ret;
} }
}
dvbdmxfeed->buffer_size=circular_buffer_size; feed->buffer_size = circular_buffer_size;
dvbdmxfeed->descramble=descramble; feed->descramble = descramble;
dvbdmxfeed->timeout=timeout; feed->timeout = timeout;
dvbdmxfeed->cb_length=callback_length; feed->cb_length = callback_length;
dvbdmxfeed->ts_type=ts_type; feed->ts_type = ts_type;
dvbdmxfeed->pes_type=pes_type; feed->pes_type = pes_type;
if (dvbdmxfeed->descramble) { if (feed->descramble) {
up(&dvbdmx->mutex); up(&demux->mutex);
return -ENOSYS; return -ENOSYS;
} }
if (dvbdmxfeed->buffer_size) { if (feed->buffer_size) {
#ifdef NOBUFS #ifdef NOBUFS
dvbdmxfeed->buffer=0; feed->buffer=0;
#else #else
dvbdmxfeed->buffer=vmalloc(dvbdmxfeed->buffer_size); feed->buffer = vmalloc(feed->buffer_size);
if (!dvbdmxfeed->buffer) { if (!feed->buffer) {
up(&dvbdmx->mutex); up(&demux->mutex);
return -ENOMEM; return -ENOMEM;
} }
#endif #endif
} }
dvbdmxfeed->state=DMX_STATE_READY;
up(&dvbdmx->mutex); feed->state = DMX_STATE_READY;
return 0; up(&demux->mutex);
return 0;
} }
static int
dmx_ts_feed_start_filtering(struct dmx_ts_feed_s* feed) static
int dmx_ts_feed_start_filtering(struct dmx_ts_feed_s* ts_feed)
{ {
struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed; struct dvb_demux_feed *feed = (struct dvb_demux_feed *) ts_feed;
struct dvb_demux *dvbdmx=dvbdmxfeed->demux; struct dvb_demux *demux = feed->demux;
int ret; int ret;
if (down_interruptible (&dvbdmx->mutex)) if (down_interruptible (&demux->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
if (dvbdmxfeed->state!=DMX_STATE_READY || if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) {
dvbdmxfeed->type!=DMX_TYPE_TS) { up(&demux->mutex);
up(&dvbdmx->mutex); return -EINVAL;
return -EINVAL;
} }
if (!dvbdmx->start_feed) {
up(&dvbdmx->mutex); if (!demux->start_feed) {
return -1; up(&demux->mutex);
return -ENODEV;
} }
ret=dvbdmx->start_feed(dvbdmxfeed);
if (ret<0) { if ((ret = demux->start_feed(feed)) < 0) {
up(&dvbdmx->mutex); up(&demux->mutex);
return ret; return ret;
} }
spin_lock_irq(&dvbdmx->lock);
feed->is_filtering=1; spin_lock_irq(&demux->lock);
dvbdmxfeed->state=DMX_STATE_GO; ts_feed->is_filtering = 1;
spin_unlock_irq(&dvbdmx->lock); feed->state = DMX_STATE_GO;
up(&dvbdmx->mutex); spin_unlock_irq(&demux->lock);
up(&demux->mutex);
return 0; return 0;
} }
static int static
dmx_ts_feed_stop_filtering(struct dmx_ts_feed_s* feed) int dmx_ts_feed_stop_filtering(struct dmx_ts_feed_s* ts_feed)
{ {
struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed; struct dvb_demux_feed *feed = (struct dvb_demux_feed *) ts_feed;
struct dvb_demux *dvbdmx=dvbdmxfeed->demux; struct dvb_demux *demux = feed->demux;
int ret; int ret;
if (down_interruptible (&dvbdmx->mutex)) if (down_interruptible (&demux->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
if (dvbdmxfeed->state<DMX_STATE_GO) { if (feed->state<DMX_STATE_GO) {
up(&dvbdmx->mutex); up(&demux->mutex);
return -EINVAL; return -EINVAL;
} }
if (!dvbdmx->stop_feed) {
up(&dvbdmx->mutex); if (!demux->stop_feed) {
return -1; up(&demux->mutex);
return -ENODEV;
} }
ret=dvbdmx->stop_feed(dvbdmxfeed);
spin_lock_irq(&dvbdmx->lock);
feed->is_filtering=0;
dvbdmxfeed->state=DMX_STATE_ALLOCATED;
spin_unlock_irq(&dvbdmx->lock); ret = demux->stop_feed(feed);
up(&dvbdmx->mutex);
return ret; spin_lock_irq(&demux->lock);
ts_feed->is_filtering = 0;
feed->state = DMX_STATE_ALLOCATED;
spin_unlock_irq(&demux->lock);
up(&demux->mutex);
return ret;
} }
static int dvbdmx_allocate_ts_feed(dmx_demux_t *demux, static
dmx_ts_feed_t **feed, int dvbdmx_allocate_ts_feed (dmx_demux_t *dmx, dmx_ts_feed_t **ts_feed,
dmx_ts_cb callback) dmx_ts_cb callback)
{ {
struct dvb_demux *dvbdmx=(struct dvb_demux *) demux; struct dvb_demux *demux = (struct dvb_demux *) dmx;
struct dvb_demux_feed *dvbdmxfeed; struct dvb_demux_feed *feed;
if (down_interruptible (&dvbdmx->mutex)) if (down_interruptible (&demux->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
if (!(dvbdmxfeed=dvb_dmx_feed_alloc(dvbdmx))) { if (!(feed = dvb_dmx_feed_alloc(demux))) {
up(&dvbdmx->mutex); up(&demux->mutex);
return -EBUSY; return -EBUSY;
} }
dvbdmxfeed->type=DMX_TYPE_TS;
dvbdmxfeed->cb.ts=callback; feed->type = DMX_TYPE_TS;
dvbdmxfeed->demux=dvbdmx; feed->cb.ts = callback;
dvbdmxfeed->pid=0xffff; feed->demux = demux;
dvbdmxfeed->peslen=0xfffa; feed->pid = 0xffff;
dvbdmxfeed->buffer=0; feed->peslen = 0xfffa;
feed->buffer = 0;
(*feed)=&dvbdmxfeed->feed.ts;
(*feed)->is_filtering=0; (*ts_feed) = &feed->feed.ts;
(*feed)->parent=demux; (*ts_feed)->is_filtering = 0;
(*feed)->priv=0; (*ts_feed)->parent = dmx;
(*feed)->set=dmx_ts_feed_set; (*ts_feed)->priv = 0;
(*feed)->start_filtering=dmx_ts_feed_start_filtering; (*ts_feed)->set = dmx_ts_feed_set;
(*feed)->stop_filtering=dmx_ts_feed_stop_filtering; (*ts_feed)->start_filtering = dmx_ts_feed_start_filtering;
(*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering;
if (!(dvbdmxfeed->filter=dvb_dmx_filter_alloc(dvbdmx))) {
dvbdmxfeed->state=DMX_STATE_FREE; if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
up(&dvbdmx->mutex); feed->state = DMX_STATE_FREE;
return -EBUSY; up(&demux->mutex);
} return -EBUSY;
}
dvbdmxfeed->filter->type=DMX_TYPE_TS;
dvbdmxfeed->filter->feed=dvbdmxfeed; feed->filter->type = DMX_TYPE_TS;
dvbdmxfeed->filter->state=DMX_STATE_READY; feed->filter->feed = feed;
feed->filter->state = DMX_STATE_READY;
up(&dvbdmx->mutex);
return 0; up(&demux->mutex);
return 0;
} }
static int dvbdmx_release_ts_feed(dmx_demux_t *demux, dmx_ts_feed_t *feed) static
int dvbdmx_release_ts_feed(dmx_demux_t *dmx, dmx_ts_feed_t *ts_feed)
{ {
struct dvb_demux *dvbdmx=(struct dvb_demux *) demux; struct dvb_demux *demux = (struct dvb_demux *) dmx;
struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed; struct dvb_demux_feed *feed = (struct dvb_demux_feed *) ts_feed;
struct list_head *pos, *n, *head=&demux->feed_list;
if (down_interruptible (&dvbdmx->mutex)) if (down_interruptible (&demux->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
if (dvbdmxfeed->state==DMX_STATE_FREE) { if (feed->state == DMX_STATE_FREE) {
up(&dvbdmx->mutex); up(&demux->mutex);
return -EINVAL; return -EINVAL;
} }
#ifndef NOBUFS #ifndef NOBUFS
if (dvbdmxfeed->buffer) { if (feed->buffer) {
vfree(dvbdmxfeed->buffer); vfree(feed->buffer);
dvbdmxfeed->buffer=0; feed->buffer=0;
} }
#endif #endif
dvbdmxfeed->state=DMX_STATE_FREE;
dvbdmxfeed->filter->state=DMX_STATE_FREE; feed->state = DMX_STATE_FREE;
if (dvbdmxfeed->pid<=DMX_MAX_PID) { feed->filter->state = DMX_STATE_FREE;
dvbdmxfeed->demux->pid2feed[dvbdmxfeed->pid]=0;
dvbdmxfeed->pid=0xffff; if (feed->pid <= DMX_MAX_PID) {
} list_for_each_safe(pos, n, head)
if (DMX_FEED_ENTRY(pos)->pid == feed->pid) {
up(&dvbdmx->mutex); list_del(pos);
return 0; break;
}
feed->pid = 0xffff;
}
if (feed->ts_type & TS_DECODER)
demux->pesfilter[feed->pes_type] = NULL;
up(&demux->mutex);
return 0;
} }
...@@ -713,92 +755,92 @@ static int dvbdmx_release_ts_feed(dmx_demux_t *demux, dmx_ts_feed_t *feed) ...@@ -713,92 +755,92 @@ static int dvbdmx_release_ts_feed(dmx_demux_t *demux, dmx_ts_feed_t *feed)
static int static int
dmx_section_feed_allocate_filter(struct dmx_section_feed_s* feed, dmx_section_feed_allocate_filter(struct dmx_section_feed_s* feed,
dmx_section_filter_t** filter) dmx_section_filter_t** filter)
{ {
struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed; struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed;
struct dvb_demux *dvbdemux=dvbdmxfeed->demux; struct dvb_demux *dvbdemux=dvbdmxfeed->demux;
struct dvb_demux_filter *dvbdmxfilter; struct dvb_demux_filter *dvbdmxfilter;
if (down_interruptible (&dvbdemux->mutex)) if (down_interruptible (&dvbdemux->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
dvbdmxfilter=dvb_dmx_filter_alloc(dvbdemux); dvbdmxfilter=dvb_dmx_filter_alloc(dvbdemux);
if (!dvbdmxfilter) { if (!dvbdmxfilter) {
up(&dvbdemux->mutex); up(&dvbdemux->mutex);
return -ENOSPC; return -ENOSPC;
} }
spin_lock_irq(&dvbdemux->lock); spin_lock_irq(&dvbdemux->lock);
*filter=&dvbdmxfilter->filter; *filter=&dvbdmxfilter->filter;
(*filter)->parent=feed; (*filter)->parent=feed;
(*filter)->priv=0; (*filter)->priv=0;
dvbdmxfilter->feed=dvbdmxfeed; dvbdmxfilter->feed=dvbdmxfeed;
dvbdmxfilter->type=DMX_TYPE_SEC; dvbdmxfilter->type=DMX_TYPE_SEC;
dvbdmxfilter->state=DMX_STATE_READY; dvbdmxfilter->state=DMX_STATE_READY;
dvbdmxfilter->next=dvbdmxfeed->filter; dvbdmxfilter->next=dvbdmxfeed->filter;
dvbdmxfeed->filter=dvbdmxfilter; dvbdmxfeed->filter=dvbdmxfilter;
spin_unlock_irq(&dvbdemux->lock); spin_unlock_irq(&dvbdemux->lock);
up(&dvbdemux->mutex); up(&dvbdemux->mutex);
return 0; return 0;
} }
static int static int
dmx_section_feed_set(struct dmx_section_feed_s* feed, dmx_section_feed_set(struct dmx_section_feed_s* feed,
u16 pid, size_t circular_buffer_size, u16 pid, size_t circular_buffer_size,
int descramble, int check_crc) int descramble, int check_crc)
{ {
struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed; struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed;
struct dvb_demux *dvbdmx=dvbdmxfeed->demux; struct dvb_demux *dvbdmx=dvbdmxfeed->demux;
struct list_head *pos, *n, *head=&dvbdmx->feed_list;
if (pid>0x1fff) if (pid>0x1fff)
return -EINVAL; return -EINVAL;
if (down_interruptible (&dvbdmx->mutex)) if (down_interruptible (&dvbdmx->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
if (dvbdmxfeed->pid!=0xffff) { if (dvbdmxfeed->pid <= DMX_MAX_PID)
dvbdmx->pid2feed[dvbdmxfeed->pid]=0; list_for_each_safe(pos, n, head)
dvbdmxfeed->pid=0xffff; if (DMX_FEED_ENTRY(pos)->pid == dvbdmxfeed->pid) {
} list_del(pos);
if (dvbdmx->pid2feed[pid]) { break;
}
list_add(&dvbdmxfeed->list_head, head);
dvbdmxfeed->pid=pid;
dvbdmxfeed->buffer_size=circular_buffer_size;
dvbdmxfeed->descramble=descramble;
if (dvbdmxfeed->descramble) {
up(&dvbdmx->mutex); up(&dvbdmx->mutex);
return -EBUSY; return -ENOSYS;
} }
dvbdmx->pid2feed[pid]=dvbdmxfeed;
dvbdmxfeed->pid=pid;
dvbdmxfeed->buffer_size=circular_buffer_size; dvbdmxfeed->feed.sec.check_crc=check_crc;
dvbdmxfeed->descramble=descramble;
if (dvbdmxfeed->descramble) {
up(&dvbdmx->mutex);
return -ENOSYS;
}
dvbdmxfeed->check_crc=check_crc;
#ifdef NOBUFS #ifdef NOBUFS
dvbdmxfeed->buffer=0; dvbdmxfeed->buffer=0;
#else #else
dvbdmxfeed->buffer=vmalloc(dvbdmxfeed->buffer_size); dvbdmxfeed->buffer=vmalloc(dvbdmxfeed->buffer_size);
if (!dvbdmxfeed->buffer) { if (!dvbdmxfeed->buffer) {
up(&dvbdmx->mutex); up(&dvbdmx->mutex);
return -ENOMEM; return -ENOMEM;
} }
#endif #endif
dvbdmxfeed->state=DMX_STATE_READY; dvbdmxfeed->state=DMX_STATE_READY;
up(&dvbdmx->mutex); up(&dvbdmx->mutex);
return 0; return 0;
} }
static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed) static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed)
{ {
int i; int i;
dmx_section_filter_t *sf; dmx_section_filter_t *sf;
struct dvb_demux_filter *f; struct dvb_demux_filter *f;
u8 mask, mode, doneq; u8 mask, mode, doneq;
if (!(f=dvbdmxfeed->filter)) if (!(f=dvbdmxfeed->filter))
return; return;
do { do {
sf=&f->filter; sf=&f->filter;
doneq=0; doneq=0;
for (i=0; i<DVB_DEMUX_MASK_MAX; i++) { for (i=0; i<DVB_DEMUX_MASK_MAX; i++) {
...@@ -815,159 +857,169 @@ static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed) ...@@ -815,159 +857,169 @@ static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed)
static int static int
dmx_section_feed_start_filtering(dmx_section_feed_t *feed) dmx_section_feed_start_filtering(dmx_section_feed_t *feed)
{ {
struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed; struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed;
struct dvb_demux *dvbdmx=dvbdmxfeed->demux; struct dvb_demux *dvbdmx=dvbdmxfeed->demux;
int ret; int ret;
if (down_interruptible (&dvbdmx->mutex)) if (down_interruptible (&dvbdmx->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
if (feed->is_filtering) { if (feed->is_filtering) {
up(&dvbdmx->mutex); up(&dvbdmx->mutex);
return -EBUSY; return -EBUSY;
} }
if (!dvbdmxfeed->filter) { if (!dvbdmxfeed->filter) {
up(&dvbdmx->mutex); up(&dvbdmx->mutex);
return -EINVAL; return -EINVAL;
} }
dvbdmxfeed->secbufp=0; dvbdmxfeed->feed.sec.secbufp=0;
dvbdmxfeed->seclen=0; dvbdmxfeed->feed.sec.seclen=0;
if (!dvbdmx->start_feed) { if (!dvbdmx->start_feed) {
up(&dvbdmx->mutex); up(&dvbdmx->mutex);
return -1; return -ENODEV;
} }
prepare_secfilters(dvbdmxfeed); prepare_secfilters(dvbdmxfeed);
ret=dvbdmx->start_feed(dvbdmxfeed);
if (ret<0) { if ((ret = dvbdmx->start_feed(dvbdmxfeed)) < 0) {
up(&dvbdmx->mutex); up(&dvbdmx->mutex);
return ret; return ret;
} }
spin_lock_irq(&dvbdmx->lock); spin_lock_irq(&dvbdmx->lock);
feed->is_filtering=1; feed->is_filtering=1;
dvbdmxfeed->state=DMX_STATE_GO; dvbdmxfeed->state=DMX_STATE_GO;
spin_unlock_irq(&dvbdmx->lock); spin_unlock_irq(&dvbdmx->lock);
up(&dvbdmx->mutex); up(&dvbdmx->mutex);
return 0; return 0;
} }
static int static int
dmx_section_feed_stop_filtering(struct dmx_section_feed_s* feed) dmx_section_feed_stop_filtering(struct dmx_section_feed_s* feed)
{ {
struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed; struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed;
struct dvb_demux *dvbdmx=dvbdmxfeed->demux; struct dvb_demux *dvbdmx=dvbdmxfeed->demux;
int ret; int ret;
if (down_interruptible (&dvbdmx->mutex)) if (down_interruptible (&dvbdmx->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
if (!dvbdmx->stop_feed) { if (!dvbdmx->stop_feed) {
up(&dvbdmx->mutex); up(&dvbdmx->mutex);
return -1; return -ENODEV;
} }
ret=dvbdmx->stop_feed(dvbdmxfeed); ret=dvbdmx->stop_feed(dvbdmxfeed);
spin_lock_irq(&dvbdmx->lock); spin_lock_irq(&dvbdmx->lock);
dvbdmxfeed->state=DMX_STATE_READY; dvbdmxfeed->state=DMX_STATE_READY;
feed->is_filtering=0; feed->is_filtering=0;
spin_unlock_irq(&dvbdmx->lock); spin_unlock_irq(&dvbdmx->lock);
up(&dvbdmx->mutex); up(&dvbdmx->mutex);
return ret; return ret;
} }
static int static int
dmx_section_feed_release_filter(dmx_section_feed_t *feed, dmx_section_feed_release_filter(dmx_section_feed_t *feed,
dmx_section_filter_t* filter) dmx_section_filter_t* filter)
{ {
struct dvb_demux_filter *dvbdmxfilter=(struct dvb_demux_filter *) filter, *f; struct dvb_demux_filter *dvbdmxfilter=(struct dvb_demux_filter *) filter, *f;
struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed; struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed;
struct dvb_demux *dvbdmx=dvbdmxfeed->demux; struct dvb_demux *dvbdmx=dvbdmxfeed->demux;
if (down_interruptible (&dvbdmx->mutex)) if (down_interruptible (&dvbdmx->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
if (dvbdmxfilter->feed!=dvbdmxfeed) { if (dvbdmxfilter->feed!=dvbdmxfeed) {
up(&dvbdmx->mutex); up(&dvbdmx->mutex);
return -EINVAL; return -EINVAL;
} }
if (feed->is_filtering) if (feed->is_filtering)
feed->stop_filtering(feed); feed->stop_filtering(feed);
spin_lock_irq(&dvbdmx->lock); spin_lock_irq(&dvbdmx->lock);
f=dvbdmxfeed->filter; f=dvbdmxfeed->filter;
if (f==dvbdmxfilter) if (f==dvbdmxfilter)
dvbdmxfeed->filter=dvbdmxfilter->next; dvbdmxfeed->filter=dvbdmxfilter->next;
else { else {
while(f->next!=dvbdmxfilter) while(f->next!=dvbdmxfilter)
f=f->next; f=f->next;
f->next=f->next->next; f->next=f->next->next;
} }
dvbdmxfilter->state=DMX_STATE_FREE; dvbdmxfilter->state=DMX_STATE_FREE;
spin_unlock_irq(&dvbdmx->lock); spin_unlock_irq(&dvbdmx->lock);
up(&dvbdmx->mutex); up(&dvbdmx->mutex);
return 0; return 0;
} }
static int dvbdmx_allocate_section_feed(dmx_demux_t *demux, static int dvbdmx_allocate_section_feed(dmx_demux_t *demux,
dmx_section_feed_t **feed, dmx_section_feed_t **feed,
dmx_section_cb callback) dmx_section_cb callback)
{ {
struct dvb_demux *dvbdmx=(struct dvb_demux *) demux; struct dvb_demux *dvbdmx=(struct dvb_demux *) demux;
struct dvb_demux_feed *dvbdmxfeed; struct dvb_demux_feed *dvbdmxfeed;
if (down_interruptible (&dvbdmx->mutex)) if (down_interruptible (&dvbdmx->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
if (!(dvbdmxfeed=dvb_dmx_feed_alloc(dvbdmx))) { if (!(dvbdmxfeed=dvb_dmx_feed_alloc(dvbdmx))) {
up(&dvbdmx->mutex); up(&dvbdmx->mutex);
return -EBUSY; return -EBUSY;
} }
dvbdmxfeed->type=DMX_TYPE_SEC; dvbdmxfeed->type=DMX_TYPE_SEC;
dvbdmxfeed->cb.sec=callback; dvbdmxfeed->cb.sec=callback;
dvbdmxfeed->demux=dvbdmx; dvbdmxfeed->demux=dvbdmx;
dvbdmxfeed->pid=0xffff; dvbdmxfeed->pid=0xffff;
dvbdmxfeed->secbufp=0; dvbdmxfeed->feed.sec.secbufp=0;
dvbdmxfeed->filter=0; dvbdmxfeed->filter=0;
dvbdmxfeed->buffer=0; dvbdmxfeed->buffer=0;
(*feed)=&dvbdmxfeed->feed.sec; (*feed)=&dvbdmxfeed->feed.sec;
(*feed)->is_filtering=0; (*feed)->is_filtering=0;
(*feed)->parent=demux; (*feed)->parent=demux;
(*feed)->priv=0; (*feed)->priv=0;
(*feed)->set=dmx_section_feed_set; (*feed)->set=dmx_section_feed_set;
(*feed)->allocate_filter=dmx_section_feed_allocate_filter; (*feed)->allocate_filter=dmx_section_feed_allocate_filter;
(*feed)->release_filter=dmx_section_feed_release_filter; (*feed)->release_filter=dmx_section_feed_release_filter;
(*feed)->start_filtering=dmx_section_feed_start_filtering; (*feed)->start_filtering=dmx_section_feed_start_filtering;
(*feed)->stop_filtering=dmx_section_feed_stop_filtering; (*feed)->stop_filtering=dmx_section_feed_stop_filtering;
up(&dvbdmx->mutex); up(&dvbdmx->mutex);
return 0; return 0;
} }
static int dvbdmx_release_section_feed(dmx_demux_t *demux, static int dvbdmx_release_section_feed(dmx_demux_t *demux,
dmx_section_feed_t *feed) dmx_section_feed_t *feed)
{ {
struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed; struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed;
struct dvb_demux *dvbdmx=(struct dvb_demux *) demux; struct dvb_demux *dvbdmx=(struct dvb_demux *) demux;
struct list_head *pos, *n, *head=&dvbdmx->feed_list;
if (down_interruptible (&dvbdmx->mutex)) if (down_interruptible (&dvbdmx->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
if (dvbdmxfeed->state==DMX_STATE_FREE) { if (dvbdmxfeed->state==DMX_STATE_FREE) {
up(&dvbdmx->mutex); up(&dvbdmx->mutex);
return -EINVAL; return -EINVAL;
} }
#ifndef NOBUFS #ifndef NOBUFS
if (dvbdmxfeed->buffer) { if (dvbdmxfeed->buffer) {
vfree(dvbdmxfeed->buffer); vfree(dvbdmxfeed->buffer);
dvbdmxfeed->buffer=0; dvbdmxfeed->buffer=0;
} }
#endif #endif
dvbdmxfeed->state=DMX_STATE_FREE; dvbdmxfeed->state=DMX_STATE_FREE;
dvbdmxfeed->demux->pid2feed[dvbdmxfeed->pid]=0;
if (dvbdmxfeed->pid!=0xffff) if (dvbdmxfeed->pid <= DMX_MAX_PID) {
dvbdmxfeed->demux->pid2feed[dvbdmxfeed->pid]=0; list_for_each_safe(pos, n, head)
up(&dvbdmx->mutex); if (DMX_FEED_ENTRY(pos)->pid == dvbdmxfeed->pid) {
return 0; list_del(pos);
break;
}
dvbdmxfeed->pid = 0xffff;
}
up(&dvbdmx->mutex);
return 0;
} }
...@@ -977,72 +1029,72 @@ static int dvbdmx_release_section_feed(dmx_demux_t *demux, ...@@ -977,72 +1029,72 @@ static int dvbdmx_release_section_feed(dmx_demux_t *demux,
static int dvbdmx_open(dmx_demux_t *demux) static int dvbdmx_open(dmx_demux_t *demux)
{ {
struct dvb_demux *dvbdemux=(struct dvb_demux *) demux; struct dvb_demux *dvbdemux=(struct dvb_demux *) demux;
if (dvbdemux->users>=MAX_DVB_DEMUX_USERS) if (dvbdemux->users>=MAX_DVB_DEMUX_USERS)
return -EUSERS; return -EUSERS;
dvbdemux->users++; dvbdemux->users++;
return 0; return 0;
} }
static int dvbdmx_close(struct dmx_demux_s *demux) static int dvbdmx_close(struct dmx_demux_s *demux)
{ {
struct dvb_demux *dvbdemux=(struct dvb_demux *) demux; struct dvb_demux *dvbdemux=(struct dvb_demux *) demux;
if (dvbdemux->users==0) if (dvbdemux->users==0)
return -ENODEV; return -ENODEV;
dvbdemux->users--; dvbdemux->users--;
//FIXME: release any unneeded resources if users==0 //FIXME: release any unneeded resources if users==0
return 0; return 0;
} }
static int dvbdmx_write(dmx_demux_t *demux, const char *buf, size_t count) static int dvbdmx_write(dmx_demux_t *demux, const char *buf, size_t count)
{ {
struct dvb_demux *dvbdemux=(struct dvb_demux *) demux; struct dvb_demux *dvbdemux=(struct dvb_demux *) demux;
if ((!demux->frontend) || if ((!demux->frontend) ||
(demux->frontend->source!=DMX_MEMORY_FE)) (demux->frontend->source!=DMX_MEMORY_FE))
return -EINVAL; return -EINVAL;
if (down_interruptible (&dvbdemux->mutex)) if (down_interruptible (&dvbdemux->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
dvb_dmx_swfilter(dvbdemux, buf, count); dvb_dmx_swfilter(dvbdemux, buf, count);
up(&dvbdemux->mutex); up(&dvbdemux->mutex);
return count; return count;
} }
static int dvbdmx_add_frontend(dmx_demux_t *demux, static int dvbdmx_add_frontend(dmx_demux_t *demux,
dmx_frontend_t *frontend) dmx_frontend_t *frontend)
{ {
struct dvb_demux *dvbdemux=(struct dvb_demux *) demux; struct dvb_demux *dvbdemux=(struct dvb_demux *) demux;
struct list_head *pos, *head=&dvbdemux->frontend_list; struct list_head *pos, *head=&dvbdemux->frontend_list;
if (!(frontend->id && frontend->vendor && frontend->model)) if (!(frontend->id && frontend->vendor && frontend->model))
return -EINVAL; return -EINVAL;
list_for_each(pos, head) list_for_each(pos, head)
{ {
if (!strcmp(DMX_FE_ENTRY(pos)->id, frontend->id)) if (!strcmp(DMX_FE_ENTRY(pos)->id, frontend->id))
return -EEXIST; return -EEXIST;
} }
list_add(&(frontend->connectivity_list), head); list_add(&(frontend->connectivity_list), head);
return 0; return 0;
} }
static int static int
dvbdmx_remove_frontend(dmx_demux_t *demux, dvbdmx_remove_frontend(dmx_demux_t *demux,
dmx_frontend_t *frontend) dmx_frontend_t *frontend)
{ {
struct dvb_demux *dvbdemux=(struct dvb_demux *) demux; struct dvb_demux *dvbdemux=(struct dvb_demux *) demux;
struct list_head *pos, *n, *head=&dvbdemux->frontend_list; struct list_head *pos, *n, *head=&dvbdemux->frontend_list;
list_for_each_safe (pos, n, head) list_for_each_safe (pos, n, head)
{ {
if (DMX_FE_ENTRY(pos)==frontend) if (DMX_FE_ENTRY(pos)==frontend)
{ {
list_del(pos); list_del(pos);
return 0; return 0;
} }
} }
...@@ -1052,123 +1104,129 @@ dvbdmx_remove_frontend(dmx_demux_t *demux, ...@@ -1052,123 +1104,129 @@ dvbdmx_remove_frontend(dmx_demux_t *demux,
static struct list_head * static struct list_head *
dvbdmx_get_frontends(dmx_demux_t *demux) dvbdmx_get_frontends(dmx_demux_t *demux)
{ {
struct dvb_demux *dvbdemux=(struct dvb_demux *) demux; struct dvb_demux *dvbdemux=(struct dvb_demux *) demux;
if (list_empty(&dvbdemux->frontend_list)) if (list_empty(&dvbdemux->frontend_list))
return NULL; return NULL;
return &dvbdemux->frontend_list; return &dvbdemux->frontend_list;
} }
static int dvbdmx_connect_frontend(dmx_demux_t *demux, static int dvbdmx_connect_frontend(dmx_demux_t *demux,
dmx_frontend_t *frontend) dmx_frontend_t *frontend)
{ {
struct dvb_demux *dvbdemux=(struct dvb_demux *) demux; struct dvb_demux *dvbdemux=(struct dvb_demux *) demux;
if (demux->frontend) if (demux->frontend)
return -EINVAL; return -EINVAL;
if (down_interruptible (&dvbdemux->mutex)) if (down_interruptible (&dvbdemux->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
demux->frontend=frontend; demux->frontend=frontend;
up(&dvbdemux->mutex); up(&dvbdemux->mutex);
return 0; return 0;
} }
static int dvbdmx_disconnect_frontend(dmx_demux_t *demux) static int dvbdmx_disconnect_frontend(dmx_demux_t *demux)
{ {
struct dvb_demux *dvbdemux=(struct dvb_demux *) demux; struct dvb_demux *dvbdemux=(struct dvb_demux *) demux;
if (down_interruptible (&dvbdemux->mutex)) if (down_interruptible (&dvbdemux->mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
demux->frontend=NULL; demux->frontend=NULL;
up(&dvbdemux->mutex); up(&dvbdemux->mutex);
return 0; return 0;
} }
static int dvbdmx_get_pes_pids(dmx_demux_t *demux, u16 *pids) static int dvbdmx_get_pes_pids(dmx_demux_t *demux, u16 *pids)
{ {
struct dvb_demux *dvbdemux=(struct dvb_demux *) demux; struct dvb_demux *dvbdemux=(struct dvb_demux *) demux;
memcpy(pids, dvbdemux->pids, 5*sizeof(u16)); memcpy(pids, dvbdemux->pids, 5*sizeof(u16));
return 0; return 0;
} }
int int
dvb_dmx_init(struct dvb_demux *dvbdemux) dvb_dmx_init(struct dvb_demux *dvbdemux)
{ {
int i; int i;
dmx_demux_t *dmx=&dvbdemux->dmx; dmx_demux_t *dmx=&dvbdemux->dmx;
dvbdemux->users=0; dvbdemux->users=0;
dvbdemux->filter=vmalloc(dvbdemux->filternum*sizeof(struct dvb_demux_filter)); dvbdemux->filter=vmalloc(dvbdemux->filternum*sizeof(struct dvb_demux_filter));
if (!dvbdemux->filter) if (!dvbdemux->filter)
return -ENOMEM; return -ENOMEM;
dvbdemux->feed=vmalloc(dvbdemux->feednum*sizeof(struct dvb_demux_feed)); dvbdemux->feed=vmalloc(dvbdemux->feednum*sizeof(struct dvb_demux_feed));
if (!dvbdemux->feed) { if (!dvbdemux->feed) {
vfree(dvbdemux->filter); vfree(dvbdemux->filter);
return -ENOMEM; return -ENOMEM;
}
for (i=0; i<dvbdemux->filternum; i++) {
dvbdemux->filter[i].state=DMX_STATE_FREE;
dvbdemux->filter[i].index=i;
} }
for (i=0; i<dvbdemux->filternum; i++) { for (i=0; i<dvbdemux->feednum; i++)
dvbdemux->filter[i].state=DMX_STATE_FREE; dvbdemux->feed[i].state=DMX_STATE_FREE;
dvbdemux->filter[i].index=i; dvbdemux->frontend_list.next=
} dvbdemux->frontend_list.prev=
for (i=0; i<dvbdemux->feednum; i++) &dvbdemux->frontend_list;
dvbdemux->feed[i].state=DMX_STATE_FREE; for (i=0; i<DMX_TS_PES_OTHER; i++) {
dvbdemux->frontend_list.next= dvbdemux->pesfilter[i]=NULL;
dvbdemux->frontend_list.prev= dvbdemux->pids[i]=0xffff;
&dvbdemux->frontend_list;
for (i=0; i<DMX_TS_PES_OTHER; i++) {
dvbdemux->pesfilter[i]=NULL;
dvbdemux->pids[i]=0xffff;
} }
dvbdemux->playing=dvbdemux->recording=0; dvbdemux->playing=dvbdemux->recording=0;
memset(dvbdemux->pid2feed, 0, (DMX_MAX_PID+1)*sizeof(struct dvb_demux_feed *)); INIT_LIST_HEAD(&dvbdemux->feed_list);
dvbdemux->tsbufp=0; dvbdemux->tsbufp=0;
dmx->frontend=0; if (!dvbdemux->check_crc32)
dmx->reg_list.next=dmx->reg_list.prev=&dmx->reg_list; dvbdemux->check_crc32 = dvb_dmx_crc32;
dmx->priv=(void *) dvbdemux;
//dmx->users=0; // reset in dmx_register_demux() if (!dvbdemux->memcopy)
dmx->open=dvbdmx_open; dvbdemux->memcopy = dvb_dmx_memcopy;
dmx->close=dvbdmx_close;
dmx->write=dvbdmx_write; dmx->frontend=0;
dmx->allocate_ts_feed=dvbdmx_allocate_ts_feed; dmx->reg_list.next=dmx->reg_list.prev=&dmx->reg_list;
dmx->release_ts_feed=dvbdmx_release_ts_feed; dmx->priv=(void *) dvbdemux;
dmx->allocate_section_feed=dvbdmx_allocate_section_feed; //dmx->users=0; // reset in dmx_register_demux()
dmx->release_section_feed=dvbdmx_release_section_feed; dmx->open=dvbdmx_open;
dmx->close=dvbdmx_close;
dmx->descramble_mac_address=NULL; dmx->write=dvbdmx_write;
dmx->descramble_section_payload=NULL; dmx->allocate_ts_feed=dvbdmx_allocate_ts_feed;
dmx->release_ts_feed=dvbdmx_release_ts_feed;
dmx->add_frontend=dvbdmx_add_frontend; dmx->allocate_section_feed=dvbdmx_allocate_section_feed;
dmx->remove_frontend=dvbdmx_remove_frontend; dmx->release_section_feed=dvbdmx_release_section_feed;
dmx->get_frontends=dvbdmx_get_frontends;
dmx->connect_frontend=dvbdmx_connect_frontend; dmx->descramble_mac_address=NULL;
dmx->disconnect_frontend=dvbdmx_disconnect_frontend; dmx->descramble_section_payload=NULL;
dmx->get_pes_pids=dvbdmx_get_pes_pids;
sema_init(&dvbdemux->mutex, 1); dmx->add_frontend=dvbdmx_add_frontend;
dmx->remove_frontend=dvbdmx_remove_frontend;
dmx->get_frontends=dvbdmx_get_frontends;
dmx->connect_frontend=dvbdmx_connect_frontend;
dmx->disconnect_frontend=dvbdmx_disconnect_frontend;
dmx->get_pes_pids=dvbdmx_get_pes_pids;
sema_init(&dvbdemux->mutex, 1);
spin_lock_init(&dvbdemux->lock); spin_lock_init(&dvbdemux->lock);
if (dmx_register_demux(dmx)<0) if (dmx_register_demux(dmx)<0)
return -1; return -1;
return 0; return 0;
} }
int int
dvb_dmx_release(struct dvb_demux *dvbdemux) dvb_dmx_release(struct dvb_demux *dvbdemux)
{ {
dmx_demux_t *dmx=&dvbdemux->dmx; dmx_demux_t *dmx=&dvbdemux->dmx;
dmx_unregister_demux(dmx); dmx_unregister_demux(dmx);
if (dvbdemux->filter) if (dvbdemux->filter)
vfree(dvbdemux->filter); vfree(dvbdemux->filter);
if (dvbdemux->feed) if (dvbdemux->feed)
vfree(dvbdemux->feed); vfree(dvbdemux->feed);
return 0; return 0;
} }
#if 0 #if 0
......
...@@ -25,6 +25,9 @@ ...@@ -25,6 +25,9 @@
#ifndef _DVB_DEMUX_H_ #ifndef _DVB_DEMUX_H_
#define _DVB_DEMUX_H_ #define _DVB_DEMUX_H_
#include <asm/semaphore.h>
#include <linux/timer.h>
#include "demux.h" #include "demux.h"
#define DMX_TYPE_TS 0 #define DMX_TYPE_TS 0
...@@ -59,6 +62,8 @@ struct dvb_demux_filter { ...@@ -59,6 +62,8 @@ struct dvb_demux_filter {
}; };
#define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head)
struct dvb_demux_feed { struct dvb_demux_feed {
union { union {
dmx_ts_feed_t ts; dmx_ts_feed_t ts;
...@@ -71,13 +76,13 @@ struct dvb_demux_feed { ...@@ -71,13 +76,13 @@ struct dvb_demux_feed {
} cb; } cb;
struct dvb_demux *demux; struct dvb_demux *demux;
void *priv;
int type; int type;
int state; int state;
u16 pid; u16 pid;
u8 *buffer; u8 *buffer;
int buffer_size; int buffer_size;
int descramble; int descramble;
int check_crc;
struct timespec timeout; struct timespec timeout;
struct dvb_demux_filter *filter; struct dvb_demux_filter *filter;
...@@ -86,12 +91,11 @@ struct dvb_demux_feed { ...@@ -86,12 +91,11 @@ struct dvb_demux_feed {
int ts_type; int ts_type;
dmx_ts_pes_t pes_type; dmx_ts_pes_t pes_type;
u8 secbuf[4096];
int secbufp;
int seclen;
int cc; int cc;
u16 peslen; u16 peslen;
struct list_head list_head;
}; };
struct dvb_demux { struct dvb_demux {
...@@ -99,10 +103,14 @@ struct dvb_demux { ...@@ -99,10 +103,14 @@ struct dvb_demux {
void *priv; void *priv;
int filternum; int filternum;
int feednum; int feednum;
int (*start_feed)(struct dvb_demux_feed *); int (*start_feed) (struct dvb_demux_feed *feed);
int (*stop_feed)(struct dvb_demux_feed *); int (*stop_feed) (struct dvb_demux_feed *feed);
int (*write_to_decoder)(struct dvb_demux_feed *, u8 *, size_t); int (*write_to_decoder) (struct dvb_demux_feed *feed,
const u8 *buf, size_t len);
u32 (*check_crc32) (struct dvb_demux_feed *feed,
const u8 *buf, size_t len);
void (*memcopy) (struct dvb_demux_feed *feed, u8 *dst,
const u8 *src, size_t len);
int users; int users;
#define MAX_DVB_DEMUX_USERS 10 #define MAX_DVB_DEMUX_USERS 10
...@@ -117,7 +125,7 @@ struct dvb_demux { ...@@ -117,7 +125,7 @@ struct dvb_demux {
int recording; int recording;
#define DMX_MAX_PID 0x2000 #define DMX_MAX_PID 0x2000
struct dvb_demux_feed *pid2feed[DMX_MAX_PID+1]; struct list_head feed_list;
u8 tsbuf[188]; u8 tsbuf[188];
int tsbufp; int tsbufp;
...@@ -129,6 +137,7 @@ struct dvb_demux { ...@@ -129,6 +137,7 @@ struct dvb_demux {
int dvb_dmx_init(struct dvb_demux *dvbdemux); int dvb_dmx_init(struct dvb_demux *dvbdemux);
int dvb_dmx_release(struct dvb_demux *dvbdemux); int dvb_dmx_release(struct dvb_demux *dvbdemux);
void dvb_dmx_swfilter_packet(struct dvb_demux *dvbdmx, const u8 *buf); void dvb_dmx_swfilter_packet(struct dvb_demux *dvbdmx, const u8 *buf);
void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, int count); void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, size_t count);
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
#endif /* _DVB_DEMUX_H_ */ #endif /* _DVB_DEMUX_H_ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/videodev.h>
#include "dvb_filter.h" #include "dvb_filter.h"
unsigned int bitrates[3][16] = unsigned int bitrates[3][16] =
...@@ -52,10 +51,10 @@ void ts_to_pes(ipack *p, u8 *buf) // don't need count (=188) ...@@ -52,10 +51,10 @@ void ts_to_pes(ipack *p, u8 *buf) // don't need count (=188)
if (buf[1]&PAY_START) { if (buf[1]&PAY_START) {
if (p->plength == MMAX_PLENGTH-6 && p->found>6){ if (p->plength == MMAX_PLENGTH-6 && p->found>6){
p->plength = p->found-6; p->plength = p->found-6;
p->found = 0; p->found = 0;
send_ipack(p); send_ipack(p);
dvb_filter_ipack_reset(p); dvb_filter_ipack_reset(p);
} }
} }
if (buf[3] & ADAPT_FIELD) { // adaptation field? if (buf[3] & ADAPT_FIELD) { // adaptation field?
off = buf[4] + 1; off = buf[4] + 1;
...@@ -71,12 +70,12 @@ static ...@@ -71,12 +70,12 @@ static
int read_picture_header(uint8_t *headr, mpg_picture *pic, int field, int pr) int read_picture_header(uint8_t *headr, mpg_picture *pic, int field, int pr)
{ {
uint8_t pct; uint8_t pct;
if (pr) printk( "Pic header: "); if (pr) printk( "Pic header: ");
pic->temporal_reference[field] = (( headr[0] << 2 ) | pic->temporal_reference[field] = (( headr[0] << 2 ) |
(headr[1] & 0x03) )& 0x03ff; (headr[1] & 0x03) )& 0x03ff;
if (pr) printk( " temp ref: 0x%04x", pic->temporal_reference[field]); if (pr) printk( " temp ref: 0x%04x", pic->temporal_reference[field]);
pct = ( headr[1] >> 2 ) & 0x07; pct = ( headr[1] >> 2 ) & 0x07;
pic->picture_coding_type[field] = pct; pic->picture_coding_type[field] = pct;
if (pr) { if (pr) {
...@@ -90,26 +89,26 @@ int read_picture_header(uint8_t *headr, mpg_picture *pic, int field, int pr) ...@@ -90,26 +89,26 @@ int read_picture_header(uint8_t *headr, mpg_picture *pic, int field, int pr)
case P_FRAME: case P_FRAME:
printk( " P-FRAME"); printk( " P-FRAME");
break; break;
} }
} }
pic->vinfo.vbv_delay = (( headr[1] >> 5 ) | ( headr[2] << 3) | pic->vinfo.vbv_delay = (( headr[1] >> 5 ) | ( headr[2] << 3) |
( (headr[3] & 0x1F) << 11) ) & 0xffff; ( (headr[3] & 0x1F) << 11) ) & 0xffff;
if (pr) printk( " vbv delay: 0x%04x", pic->vinfo.vbv_delay); if (pr) printk( " vbv delay: 0x%04x", pic->vinfo.vbv_delay);
pic->picture_header_parameter = ( headr[3] & 0xe0 ) | pic->picture_header_parameter = ( headr[3] & 0xe0 ) |
((headr[4] & 0x80) >> 3); ((headr[4] & 0x80) >> 3);
if ( pct == B_FRAME ){ if ( pct == B_FRAME ){
pic->picture_header_parameter |= ( headr[4] >> 3 ) & 0x0f; pic->picture_header_parameter |= ( headr[4] >> 3 ) & 0x0f;
} }
if (pr) printk( " pic head param: 0x%x", if (pr) printk( " pic head param: 0x%x",
pic->picture_header_parameter); pic->picture_header_parameter);
return pct; return pct;
} }
#endif #endif
#if 0 #if 0
...@@ -130,14 +129,14 @@ int read_gop_header(uint8_t *headr, mpg_picture *pic, int pr) ...@@ -130,14 +129,14 @@ int read_gop_header(uint8_t *headr, mpg_picture *pic, int pr)
pic->closed_gop = 1; pic->closed_gop = 1;
} else { } else {
pic->closed_gop = 0; pic->closed_gop = 0;
} }
if (pr) printk("closed: %d", pic->closed_gop); if (pr) printk("closed: %d", pic->closed_gop);
if ( ( headr[3] & 0x20 ) != 0 ){ if ( ( headr[3] & 0x20 ) != 0 ){
pic->broken_link = 1; pic->broken_link = 1;
} else { } else {
pic->broken_link = 0; pic->broken_link = 0;
} }
if (pr) printk(" broken: %d\n", pic->broken_link); if (pr) printk(" broken: %d\n", pic->broken_link);
return 0; return 0;
...@@ -160,37 +159,37 @@ int read_sequence_header(uint8_t *headr, VideoInfo *vi, int pr) ...@@ -160,37 +159,37 @@ int read_sequence_header(uint8_t *headr, VideoInfo *vi, int pr)
sw = (int)((headr[3]&0xF0) >> 4) ; sw = (int)((headr[3]&0xF0) >> 4) ;
switch( sw ){ switch( sw ){
case 1: case 1:
if (pr) if (pr)
printk("Videostream: ASPECT: 1:1"); printk("Videostream: ASPECT: 1:1");
vi->aspect_ratio = 100; vi->aspect_ratio = 100;
break; break;
case 2: case 2:
if (pr) if (pr)
printk("Videostream: ASPECT: 4:3"); printk("Videostream: ASPECT: 4:3");
vi->aspect_ratio = 133; vi->aspect_ratio = 133;
break; break;
case 3: case 3:
if (pr) if (pr)
printk("Videostream: ASPECT: 16:9"); printk("Videostream: ASPECT: 16:9");
vi->aspect_ratio = 177; vi->aspect_ratio = 177;
break; break;
case 4: case 4:
if (pr) if (pr)
printk("Videostream: ASPECT: 2.21:1"); printk("Videostream: ASPECT: 2.21:1");
vi->aspect_ratio = 221; vi->aspect_ratio = 221;
break; break;
case 5 ... 15: case 5 ... 15:
if (pr) if (pr)
printk("Videostream: ASPECT: reserved"); printk("Videostream: ASPECT: reserved");
vi->aspect_ratio = 0; vi->aspect_ratio = 0;
break; break;
default: default:
vi->aspect_ratio = 0; vi->aspect_ratio = 0;
return -1; return -1;
} }
if (pr) if (pr)
printk(" Size = %dx%d",vi->horizontal_size,vi->vertical_size); printk(" Size = %dx%d",vi->horizontal_size,vi->vertical_size);
...@@ -221,29 +220,29 @@ int read_sequence_header(uint8_t *headr, VideoInfo *vi, int pr) ...@@ -221,29 +220,29 @@ int read_sequence_header(uint8_t *headr, VideoInfo *vi, int pr)
printk(" FRate: 29.97 fps"); printk(" FRate: 29.97 fps");
vi->framerate = 29970; vi->framerate = 29970;
form = VIDEO_MODE_NTSC; form = VIDEO_MODE_NTSC;
break; break;
case 5: case 5:
if (pr) if (pr)
printk(" FRate: 30 fps"); printk(" FRate: 30 fps");
vi->framerate = 30000; vi->framerate = 30000;
form = VIDEO_MODE_NTSC; form = VIDEO_MODE_NTSC;
break; break;
case 6: case 6:
if (pr) if (pr)
printk(" FRate: 50 fps"); printk(" FRate: 50 fps");
vi->framerate = 50000; vi->framerate = 50000;
form = VIDEO_MODE_PAL; form = VIDEO_MODE_PAL;
break; break;
case 7: case 7:
if (pr) if (pr)
printk(" FRate: 60 fps"); printk(" FRate: 60 fps");
vi->framerate = 60000; vi->framerate = 60000;
form = VIDEO_MODE_NTSC; form = VIDEO_MODE_NTSC;
break; break;
} }
vi->bit_rate = (headr[4] << 10) | (headr[5] << 2) | (headr[6] & 0x03);
vi->bit_rate = (headr[4] << 10) | (headr[5] << 2) | (headr[6] & 0x03);
vi->vbv_buffer_size vi->vbv_buffer_size
= (( headr[6] & 0xF8) >> 3 ) | (( headr[7] & 0x1F )<< 5); = (( headr[6] & 0xF8) >> 3 ) | (( headr[7] & 0x1F )<< 5);
...@@ -259,7 +258,7 @@ int read_sequence_header(uint8_t *headr, VideoInfo *vi, int pr) ...@@ -259,7 +258,7 @@ int read_sequence_header(uint8_t *headr, VideoInfo *vi, int pr)
} }
#endif #endif
#if 0 #if 0
static static
int get_vinfo(uint8_t *mbuf, int count, VideoInfo *vi, int pr) int get_vinfo(uint8_t *mbuf, int count, VideoInfo *vi, int pr)
...@@ -267,7 +266,7 @@ int get_vinfo(uint8_t *mbuf, int count, VideoInfo *vi, int pr) ...@@ -267,7 +266,7 @@ int get_vinfo(uint8_t *mbuf, int count, VideoInfo *vi, int pr)
uint8_t *headr; uint8_t *headr;
int found = 0; int found = 0;
int c = 0; int c = 0;
while (found < 4 && c+4 < count){ while (found < 4 && c+4 < count){
uint8_t *b; uint8_t *b;
...@@ -277,7 +276,7 @@ int get_vinfo(uint8_t *mbuf, int count, VideoInfo *vi, int pr) ...@@ -277,7 +276,7 @@ int get_vinfo(uint8_t *mbuf, int count, VideoInfo *vi, int pr)
else { else {
c++; c++;
} }
} }
if (! found) return -1; if (! found) return -1;
c += 4; c += 4;
...@@ -288,7 +287,7 @@ int get_vinfo(uint8_t *mbuf, int count, VideoInfo *vi, int pr) ...@@ -288,7 +287,7 @@ int get_vinfo(uint8_t *mbuf, int count, VideoInfo *vi, int pr)
return 0; return 0;
} }
#endif #endif
#if 0 #if 0
static static
...@@ -306,9 +305,9 @@ int get_ainfo(uint8_t *mbuf, int count, AudioInfo *ai, int pr) ...@@ -306,9 +305,9 @@ int get_ainfo(uint8_t *mbuf, int count, AudioInfo *ai, int pr)
if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8) if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8)
found = 2; found = 2;
else { else {
c++; c++;
} }
} }
if (!found) return -1; if (!found) return -1;
...@@ -330,7 +329,7 @@ int get_ainfo(uint8_t *mbuf, int count, AudioInfo *ai, int pr) ...@@ -330,7 +329,7 @@ int get_ainfo(uint8_t *mbuf, int count, AudioInfo *ai, int pr)
printk(" BRate: reserved"); printk(" BRate: reserved");
else else
printk(" BRate: %d kb/s", ai->bit_rate/1000); printk(" BRate: %d kb/s", ai->bit_rate/1000);
} }
fr = (headr[2] & 0x0c ) >> 2; fr = (headr[2] & 0x0c ) >> 2;
ai->frequency = freq[fr]*100; ai->frequency = freq[fr]*100;
...@@ -340,41 +339,41 @@ int get_ainfo(uint8_t *mbuf, int count, AudioInfo *ai, int pr) ...@@ -340,41 +339,41 @@ int get_ainfo(uint8_t *mbuf, int count, AudioInfo *ai, int pr)
else else
printk(" Freq: %d kHz\n",ai->frequency); printk(" Freq: %d kHz\n",ai->frequency);
} }
ai->off = c; ai->off = c;
return 0; return 0;
} }
#endif #endif
static
int get_ac3info(uint8_t *mbuf, int count, AudioInfo *ai, int pr) int dvb_filter_get_ac3info(uint8_t *mbuf, int count, AudioInfo *ai, int pr)
{ {
uint8_t *headr; uint8_t *headr;
int found = 0; int found = 0;
int c = 0; int c = 0;
uint8_t frame = 0; uint8_t frame = 0;
int fr = 0; int fr = 0;
while ( !found && c < count){ while ( !found && c < count){
uint8_t *b = mbuf+c; uint8_t *b = mbuf+c;
if ( b[0] == 0x0b && b[1] == 0x77 ) if ( b[0] == 0x0b && b[1] == 0x77 )
found = 1; found = 1;
else { else {
c++; c++;
} }
} }
if (!found) return -1; if (!found) return -1;
if (pr) if (pr)
printk("Audiostream: AC3"); printk("Audiostream: AC3");
ai->off = c; ai->off = c;
if (c+5 >= count) return -1; if (c+5 >= count) return -1;
ai->layer = 0; // 0 for AC3 ai->layer = 0; // 0 for AC3
headr = mbuf+c+2; headr = mbuf+c+2;
frame = (headr[2]&0x3f); frame = (headr[2]&0x3f);
ai->bit_rate = ac3_bitrates[frame >> 1]*1000; ai->bit_rate = ac3_bitrates[frame >> 1]*1000;
...@@ -420,8 +419,8 @@ uint8_t *skip_pes_header(uint8_t **bufp) ...@@ -420,8 +419,8 @@ uint8_t *skip_pes_header(uint8_t **bufp)
} else { /* mpeg1 */ } else { /* mpeg1 */
for (buf = inbuf + 6; *buf == 0xff; buf++) for (buf = inbuf + 6; *buf == 0xff; buf++)
if (buf == inbuf + 6 + 16) { if (buf == inbuf + 6 + 16) {
break; break;
} }
if ((*buf & 0xc0) == 0x40) if ((*buf & 0xc0) == 0x40)
buf += 2; buf += 2;
skip = mpeg1_skip_table [*buf >> 4]; skip = mpeg1_skip_table [*buf >> 4];
...@@ -433,7 +432,7 @@ uint8_t *skip_pes_header(uint8_t **bufp) ...@@ -433,7 +432,7 @@ uint8_t *skip_pes_header(uint8_t **bufp)
*bufp = buf; *bufp = buf;
return pts; return pts;
} }
#endif #endif
#if 0 #if 0
...@@ -509,7 +508,7 @@ void mpg_set_picture_parameter( int32_t field_type, mpg_picture *pic ) ...@@ -509,7 +508,7 @@ void mpg_set_picture_parameter( int32_t field_type, mpg_picture *pic )
pic->progressive_frame = 1; pic->progressive_frame = 1;
pic->picture_coding_parameter = 0x000010; pic->picture_coding_parameter = 0x000010;
} }
/* Reset flag */ /* Reset flag */
pic->picture_display_extension_flag[field_type] = 0; pic->picture_display_extension_flag[field_type] = 0;
...@@ -527,7 +526,7 @@ void mpg_set_picture_parameter( int32_t field_type, mpg_picture *pic ) ...@@ -527,7 +526,7 @@ void mpg_set_picture_parameter( int32_t field_type, mpg_picture *pic )
} else { } else {
pic->frame_centre_horizontal_offset[3] = last_h_offset; pic->frame_centre_horizontal_offset[3] = last_h_offset;
pic->frame_centre_vertical_offset[3] = last_v_offset; pic->frame_centre_vertical_offset[3] = last_v_offset;
} }
} }
#endif #endif
...@@ -566,7 +565,7 @@ void dvb_filter_pes2ts_init(dvb_filter_pes2ts_t *p2ts, unsigned short pid, ...@@ -566,7 +565,7 @@ void dvb_filter_pes2ts_init(dvb_filter_pes2ts_t *p2ts, unsigned short pid,
dvb_filter_pes2ts_cb_t *cb, void *priv) dvb_filter_pes2ts_cb_t *cb, void *priv)
{ {
unsigned char *buf=p2ts->buf; unsigned char *buf=p2ts->buf;
buf[0]=0x47; buf[0]=0x47;
buf[1]=(pid>>8); buf[1]=(pid>>8);
buf[2]=pid&0xff; buf[2]=pid&0xff;
...@@ -579,7 +578,7 @@ int dvb_filter_pes2ts(dvb_filter_pes2ts_t *p2ts, unsigned char *pes, int len) ...@@ -579,7 +578,7 @@ int dvb_filter_pes2ts(dvb_filter_pes2ts_t *p2ts, unsigned char *pes, int len)
{ {
unsigned char *buf=p2ts->buf; unsigned char *buf=p2ts->buf;
int ret=0, rest; int ret=0, rest;
//len=6+((pes[4]<<8)|pes[5]); //len=6+((pes[4]<<8)|pes[5]);
buf[1]|=0x40; buf[1]|=0x40;
...@@ -592,7 +591,7 @@ int dvb_filter_pes2ts(dvb_filter_pes2ts_t *p2ts, unsigned char *pes, int len) ...@@ -592,7 +591,7 @@ int dvb_filter_pes2ts(dvb_filter_pes2ts_t *p2ts, unsigned char *pes, int len)
buf[1]&=~0x40; buf[1]&=~0x40;
} }
if (!len) if (!len)
return 0; return 0;
buf[3]=0x30|((p2ts->cc++)&0x0f); buf[3]=0x30|((p2ts->cc++)&0x0f);
rest=183-len; rest=183-len;
if (rest) { if (rest) {
...@@ -605,397 +604,3 @@ int dvb_filter_pes2ts(dvb_filter_pes2ts_t *p2ts, unsigned char *pes, int len) ...@@ -605,397 +604,3 @@ int dvb_filter_pes2ts(dvb_filter_pes2ts_t *p2ts, unsigned char *pes, int len)
return p2ts->cb(p2ts->priv, buf); return p2ts->cb(p2ts->priv, buf);
} }
void dvb_filter_ipack_reset(ipack *p)
{
p->found = 0;
p->cid = 0;
p->plength = 0;
p->flag1 = 0;
p->flag2 = 0;
p->hlength = 0;
p->mpeg = 0;
p->check = 0;
p->which = 0;
p->done = 0;
p->count = 0;
}
void dvb_filter_ipack_init(ipack *p, int size,
void (*func)(u8 *buf, int size, void *priv))
{
if ( !(p->buf = vmalloc(size*sizeof(u8))) ){
printk ("Couldn't allocate memory for ipack\n");
}
p->size = size;
p->func = func;
p->repack_subids = 0;
dvb_filter_ipack_reset(p);
}
void dvb_filter_ipack_free(ipack * p)
{
if (p->buf) vfree(p->buf);
}
static
void send_ipack(ipack *p)
{
int off;
AudioInfo ai;
int ac3_off = 0;
int streamid=0;
int nframes= 0;
int f=0;
switch ( p->mpeg ){
case 2:
if (p->count < 10) return;
p->buf[3] = p->cid;
p->buf[4] = (u8)(((p->count-6) & 0xFF00) >> 8);
p->buf[5] = (u8)((p->count-6) & 0x00FF);
if (p->repack_subids && p->cid == PRIVATE_STREAM1){
off = 9+p->buf[8];
streamid = p->buf[off];
if ((streamid & 0xF8) == 0x80){
ai.off = 0;
ac3_off = ((p->buf[off+2] << 8)|
p->buf[off+3]);
if (ac3_off < p->count)
f=get_ac3info(p->buf+off+3+ac3_off,
p->count-ac3_off, &ai,0);
if ( !f ){
nframes = (p->count-off-3-ac3_off)/
ai.framesize + 1;
p->buf[off+2] = (ac3_off >> 8)& 0xFF;
p->buf[off+3] = (ac3_off)& 0xFF;
p->buf[off+1] = nframes;
ac3_off += nframes * ai.framesize -
p->count;
}
}
}
p->func(p->buf, p->count, p->data);
p->buf[6] = 0x80;
p->buf[7] = 0x00;
p->buf[8] = 0x00;
p->count = 9;
if (p->repack_subids && p->cid == PRIVATE_STREAM1
&& (streamid & 0xF8)==0x80 ){
p->count += 4;
p->buf[9] = streamid;
p->buf[10] = (ac3_off >> 8)& 0xFF;
p->buf[11] = (ac3_off)& 0xFF;
p->buf[12] = 0;
}
break;
case 1:
if (p->count < 8) return;
p->buf[3] = p->cid;
p->buf[4] = (u8)(((p->count-6) & 0xFF00) >> 8);
p->buf[5] = (u8)((p->count-6) & 0x00FF);
p->func(p->buf, p->count, p->data);
p->buf[6] = 0x0F;
p->count = 7;
break;
}
}
void dvb_filter_ipack_flush(ipack *p)
{
if (p->plength != MMAX_PLENGTH-6 || p->found<=6)
return;
p->plength = p->found-6;
p->found = 0;
send_ipack(p);
dvb_filter_ipack_reset(p);
}
static
void write_ipack(ipack *p, u8 *data, int count)
{
u8 headr[3] = { 0x00, 0x00, 0x01} ;
if (p->count < 6){
memcpy(p->buf, headr, 3);
p->count = 6;
}
if (p->count + count < p->size){
memcpy(p->buf+p->count, data, count);
p->count += count;
} else {
int rest = p->size - p->count;
memcpy(p->buf+p->count, data, rest);
p->count += rest;
send_ipack(p);
if (count - rest > 0)
write_ipack(p, data+rest, count-rest);
}
}
int dvb_filter_instant_repack(u8 *buf, int count, ipack *p)
{
int l;
int c=0;
while (c < count && (p->mpeg == 0 ||
(p->mpeg == 1 && p->found < 7) ||
(p->mpeg == 2 && p->found < 9))
&& (p->found < 5 || !p->done)){
switch ( p->found ){
case 0:
case 1:
if (buf[c] == 0x00) p->found++;
else p->found = 0;
c++;
break;
case 2:
if (buf[c] == 0x01) p->found++;
else if (buf[c] == 0) {
p->found = 2;
} else p->found = 0;
c++;
break;
case 3:
p->cid = 0;
switch (buf[c]){
case PROG_STREAM_MAP:
case PRIVATE_STREAM2:
case PROG_STREAM_DIR:
case ECM_STREAM :
case EMM_STREAM :
case PADDING_STREAM :
case DSM_CC_STREAM :
case ISO13522_STREAM:
p->done = 1;
case PRIVATE_STREAM1:
case VIDEO_STREAM_S ... VIDEO_STREAM_E:
case AUDIO_STREAM_S ... AUDIO_STREAM_E:
p->found++;
p->cid = buf[c];
c++;
break;
default:
p->found = 0;
break;
}
break;
case 4:
if (count-c > 1){
p->plen[0] = buf[c];
c++;
p->plen[1] = buf[c];
c++;
p->found+=2;
p->plength=(p->plen[0]<<8)|p->plen[1];
} else {
p->plen[0] = buf[c];
p->found++;
return count;
}
break;
case 5:
p->plen[1] = buf[c];
c++;
p->found++;
p->plength=(p->plen[0]<<8)|p->plen[1];
break;
case 6:
if (!p->done){
p->flag1 = buf[c];
c++;
p->found++;
if ( (p->flag1 & 0xC0) == 0x80 ) p->mpeg = 2;
else {
p->hlength = 0;
p->which = 0;
p->mpeg = 1;
p->flag2 = 0;
}
}
break;
case 7:
if ( !p->done && p->mpeg == 2) {
p->flag2 = buf[c];
c++;
p->found++;
}
break;
case 8:
if ( !p->done && p->mpeg == 2) {
p->hlength = buf[c];
c++;
p->found++;
}
break;
default:
break;
}
}
if (c == count) return count;
if (!p->plength) p->plength = MMAX_PLENGTH-6;
if ( p->done || ((p->mpeg == 2 && p->found >= 9) ||
(p->mpeg == 1 && p->found >= 7)) ){
switch (p->cid){
case AUDIO_STREAM_S ... AUDIO_STREAM_E:
case VIDEO_STREAM_S ... VIDEO_STREAM_E:
case PRIVATE_STREAM1:
if (p->mpeg == 2 && p->found == 9) {
write_ipack(p, &p->flag1, 1);
write_ipack(p, &p->flag2, 1);
write_ipack(p, &p->hlength, 1);
}
if (p->mpeg == 1 && p->found == 7)
write_ipack(p, &p->flag1, 1);
if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) &&
p->found < 14) {
while (c < count && p->found < 14) {
p->pts[p->found-9] = buf[c];
write_ipack(p, buf+c, 1);
c++;
p->found++;
}
if (c == count) return count;
}
if (p->mpeg == 1 && p->which < 2000) {
if (p->found == 7) {
p->check = p->flag1;
p->hlength = 1;
}
while (!p->which && c < count &&
p->check == 0xFF){
p->check = buf[c];
write_ipack(p, buf+c, 1);
c++;
p->found++;
p->hlength++;
}
if ( c == count) return count;
if ( (p->check & 0xC0) == 0x40 && !p->which){
p->check = buf[c];
write_ipack(p, buf+c, 1);
c++;
p->found++;
p->hlength++;
p->which = 1;
if ( c == count) return count;
p->check = buf[c];
write_ipack(p, buf+c, 1);
c++;
p->found++;
p->hlength++;
p->which = 2;
if ( c == count) return count;
}
if (p->which == 1){
p->check = buf[c];
write_ipack(p, buf+c, 1);
c++;
p->found++;
p->hlength++;
p->which = 2;
if ( c == count) return count;
}
if ( (p->check & 0x30) && p->check != 0xFF){
p->flag2 = (p->check & 0xF0) << 2;
p->pts[0] = p->check;
p->which = 3;
}
if ( c == count) return count;
if (p->which > 2){
if ((p->flag2 & PTS_DTS_FLAGS)
== PTS_ONLY){
while (c < count &&
p->which < 7){
p->pts[p->which-2] =
buf[c];
write_ipack(p,buf+c,1);
c++;
p->found++;
p->which++;
p->hlength++;
}
if ( c == count) return count;
} else if ((p->flag2 & PTS_DTS_FLAGS)
== PTS_DTS){
while (c < count &&
p->which< 12){
if (p->which< 7)
p->pts[p->which
-2] =
buf[c];
write_ipack(p,buf+c,1);
c++;
p->found++;
p->which++;
p->hlength++;
}
if ( c == count) return count;
}
p->which = 2000;
}
}
while (c < count && p->found < p->plength+6){
l = count -c;
if (l+p->found > p->plength+6)
l = p->plength+6-p->found;
write_ipack(p, buf+c, l);
p->found += l;
c += l;
}
break;
}
if ( p->done ){
if( p->found + count - c < p->plength+6){
p->found += count-c;
c = count;
} else {
c += p->plength+6 - p->found;
p->found = p->plength+6;
}
}
if (p->plength && p->found == p->plength+6) {
send_ipack(p);
dvb_filter_ipack_reset(p);
if (c < count)
dvb_filter_instant_repack(buf+c, count-c, p);
}
}
return count;
}
...@@ -17,6 +17,7 @@ typedef struct dvb_filter_pes2ts_s { ...@@ -17,6 +17,7 @@ typedef struct dvb_filter_pes2ts_s {
void dvb_filter_pes2ts_init(dvb_filter_pes2ts_t *p2ts, unsigned short pid, void dvb_filter_pes2ts_init(dvb_filter_pes2ts_t *p2ts, unsigned short pid,
dvb_filter_pes2ts_cb_t *cb, void *priv); dvb_filter_pes2ts_cb_t *cb, void *priv);
int dvb_filter_pes2ts(dvb_filter_pes2ts_t *p2ts, unsigned char *pes, int len); int dvb_filter_pes2ts(dvb_filter_pes2ts_t *p2ts, unsigned char *pes, int len);
...@@ -223,12 +224,7 @@ typedef struct audio_i{ ...@@ -223,12 +224,7 @@ typedef struct audio_i{
uint32_t off; uint32_t off;
} AudioInfo; } AudioInfo;
int dvb_filter_get_ac3info(uint8_t *mbuf, int count, AudioInfo *ai, int pr);
void dvb_filter_ipack_reset(ipack *p);
int dvb_filter_instant_repack(u8 *buf, int count, ipack *p);
void dvb_filter_ipack_init(ipack *p, int size,
void (*func)(u8 *buf, int size, void *priv));
void dvb_filter_ipack_free(ipack * p);
void dvb_filter_ipack_flush(ipack *p);
#endif #endif
...@@ -27,16 +27,14 @@ ...@@ -27,16 +27,14 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/compatmac.h>
#include <linux/list.h> #include <linux/list.h>
#include "compat.h"
#include "dvb_frontend.h" #include "dvb_frontend.h"
#include "dvbdev.h" #include "dvbdev.h"
static int dvb_frontend_debug = 0; static int dvb_frontend_debug = 0;
static int dvb_shutdown_timeout = 0; static int dvb_shutdown_timeout = 5;
#define dprintk if (dvb_frontend_debug) printk #define dprintk if (dvb_frontend_debug) printk
...@@ -52,18 +50,10 @@ struct dvb_fe_events { ...@@ -52,18 +50,10 @@ struct dvb_fe_events {
}; };
struct dvb_fe_notifier_callbacks {
struct list_head list_head;
void (*callback) (fe_status_t s, void *data);
void *data;
};
struct dvb_frontend_data { struct dvb_frontend_data {
struct dvb_frontend_info *info; struct dvb_frontend_info *info;
struct dvb_frontend frontend; struct dvb_frontend frontend;
struct dvb_device *dvbdev; struct dvb_device *dvbdev;
struct list_head notifier_callbacks;
struct dvb_frontend_parameters parameters; struct dvb_frontend_parameters parameters;
struct dvb_fe_events events; struct dvb_fe_events events;
struct semaphore sem; struct semaphore sem;
...@@ -92,8 +82,17 @@ struct dvb_frontend_ioctl_data { ...@@ -92,8 +82,17 @@ struct dvb_frontend_ioctl_data {
}; };
struct dvb_frontend_notifier_data {
struct list_head list_head;
struct dvb_adapter *adapter;
void (*callback) (fe_status_t s, void *data);
void *data;
};
static LIST_HEAD(frontend_list); static LIST_HEAD(frontend_list);
static LIST_HEAD(frontend_ioctl_list); static LIST_HEAD(frontend_ioctl_list);
static LIST_HEAD(frontend_notifier_list);
static DECLARE_MUTEX(frontend_mutex); static DECLARE_MUTEX(frontend_mutex);
...@@ -153,6 +152,7 @@ void dvb_bend_frequency (struct dvb_frontend_data *this_fe, int recursive) ...@@ -153,6 +152,7 @@ void dvb_bend_frequency (struct dvb_frontend_data *this_fe, int recursive)
if (!recursive) { if (!recursive) {
if (down_interruptible (&frontend_mutex)) if (down_interruptible (&frontend_mutex))
return; return;
this_fe->bending = 0; this_fe->bending = 0;
} }
...@@ -170,7 +170,7 @@ void dvb_bend_frequency (struct dvb_frontend_data *this_fe, int recursive) ...@@ -170,7 +170,7 @@ void dvb_bend_frequency (struct dvb_frontend_data *this_fe, int recursive)
frequency += this_fe->lnb_drift; frequency += this_fe->lnb_drift;
frequency += this_fe->bending; frequency += this_fe->bending;
if (this_fe != fe && if (this_fe != fe && fe->lost_sync_count != -1 &&
frequency > f - stepsize && frequency < f + stepsize) frequency > f - stepsize && frequency < f + stepsize)
{ {
if (recursive % 2) if (recursive % 2)
...@@ -192,9 +192,6 @@ static ...@@ -192,9 +192,6 @@ static
void dvb_call_frontend_notifiers (struct dvb_frontend_data *fe, void dvb_call_frontend_notifiers (struct dvb_frontend_data *fe,
fe_status_t s) fe_status_t s)
{ {
struct list_head *e;
struct dvb_fe_notifier_callbacks *c;
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
if ((fe->status & FE_HAS_LOCK) && !(s & FE_HAS_LOCK)) if ((fe->status & FE_HAS_LOCK) && !(s & FE_HAS_LOCK))
...@@ -211,10 +208,8 @@ void dvb_call_frontend_notifiers (struct dvb_frontend_data *fe, ...@@ -211,10 +208,8 @@ void dvb_call_frontend_notifiers (struct dvb_frontend_data *fe,
/** /**
* now tell the Demux about the TS status changes... * now tell the Demux about the TS status changes...
*/ */
list_for_each (e, &fe->notifier_callbacks) { if (fe->frontend.notifier_callback)
c = list_entry (e, struct dvb_fe_notifier_callbacks, list_head); fe->frontend.notifier_callback(fe->status, fe->frontend.notifier_data);
c->callback (fe->status, c->data);
}
} }
...@@ -296,38 +291,6 @@ int dvb_frontend_get_event (struct dvb_frontend_data *fe, ...@@ -296,38 +291,6 @@ int dvb_frontend_get_event (struct dvb_frontend_data *fe,
} }
static
struct dvb_frontend_parameters default_param [] = {
{ /* NTV on Astra */
frequency: 12669500-10600000,
inversion: INVERSION_OFF,
{ qpsk: { symbol_rate: 22000000, fec_inner: FEC_AUTO } }
},
{ /* Cable */
frequency: 394000000,
inversion: INVERSION_OFF,
{ qam: { symbol_rate: 6900000,
fec_inner: FEC_AUTO,
modulation: QAM_64
}
}
},
{ /* DVB-T */
frequency: 730000000,
inversion: INVERSION_OFF,
{ ofdm: { bandwidth: BANDWIDTH_8_MHZ,
code_rate_HP: FEC_2_3,
code_rate_LP: FEC_1_2,
constellation: QAM_16,
transmission_mode: TRANSMISSION_MODE_2K,
guard_interval: GUARD_INTERVAL_1_8,
hierarchy_information: HIERARCHY_NONE
}
}
}
};
static static
int dvb_frontend_set_parameters (struct dvb_frontend_data *fe, int dvb_frontend_set_parameters (struct dvb_frontend_data *fe,
struct dvb_frontend_parameters *param, struct dvb_frontend_parameters *param,
...@@ -336,8 +299,6 @@ int dvb_frontend_set_parameters (struct dvb_frontend_data *fe, ...@@ -336,8 +299,6 @@ int dvb_frontend_set_parameters (struct dvb_frontend_data *fe,
struct dvb_frontend *frontend = &fe->frontend; struct dvb_frontend *frontend = &fe->frontend;
int err; int err;
dvb_bend_frequency (fe, 0);
if (first_trial) { if (first_trial) {
fe->timeout_count = 0; fe->timeout_count = 0;
fe->lost_sync_count = 0; fe->lost_sync_count = 0;
...@@ -349,6 +310,8 @@ int dvb_frontend_set_parameters (struct dvb_frontend_data *fe, ...@@ -349,6 +310,8 @@ int dvb_frontend_set_parameters (struct dvb_frontend_data *fe,
sizeof (struct dvb_frontend_parameters)); sizeof (struct dvb_frontend_parameters));
} }
dvb_bend_frequency (fe, 0);
dprintk ("%s: f == %i, drift == %i\n", dprintk ("%s: f == %i, drift == %i\n",
__FUNCTION__, param->frequency, fe->lnb_drift); __FUNCTION__, param->frequency, fe->lnb_drift);
...@@ -365,23 +328,12 @@ static ...@@ -365,23 +328,12 @@ static
void dvb_frontend_init (struct dvb_frontend_data *fe) void dvb_frontend_init (struct dvb_frontend_data *fe)
{ {
struct dvb_frontend *frontend = &fe->frontend; struct dvb_frontend *frontend = &fe->frontend;
struct dvb_frontend_parameters *init_param;
printk ("DVB: initialising frontend %i:%i (%s)...\n", dprintk ("DVB: initialising frontend %i:%i (%s)...\n",
frontend->i2c->adapter->num, frontend->i2c->id, fe->info->name); frontend->i2c->adapter->num, frontend->i2c->id,
fe->info->name);
dvb_frontend_internal_ioctl (frontend, FE_INIT, NULL); dvb_frontend_internal_ioctl (frontend, FE_INIT, NULL);
if (fe->info->type == FE_QPSK) {
dvb_frontend_internal_ioctl (frontend, FE_SET_VOLTAGE,
(void*) SEC_VOLTAGE_13);
dvb_frontend_internal_ioctl (frontend, FE_SET_TONE,
(void*) SEC_TONE_ON);
}
init_param = &default_param[fe->info->type-FE_QPSK];
dvb_frontend_set_parameters (fe, init_param, 1);
} }
...@@ -464,7 +416,7 @@ int dvb_frontend_is_exiting (struct dvb_frontend_data *fe) ...@@ -464,7 +416,7 @@ int dvb_frontend_is_exiting (struct dvb_frontend_data *fe)
if (fe->exit) if (fe->exit)
return 1; return 1;
if (fe->dvbdev->users == 0 && dvb_shutdown_timeout) if (fe->dvbdev->writers == 1)
if (jiffies - fe->release_jiffies > dvb_shutdown_timeout * HZ) if (jiffies - fe->release_jiffies > dvb_shutdown_timeout * HZ)
return 1; return 1;
...@@ -482,13 +434,27 @@ int dvb_frontend_thread (void *data) ...@@ -482,13 +434,27 @@ int dvb_frontend_thread (void *data)
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
lock_kernel (); lock_kernel ();
daemonize("kdvb-fe"); #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,61))
daemonize ();
#else
daemonize ("dvb fe");
#endif
/* not needed anymore in 2.5.x, done in daemonize() */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
reparent_to_init ();
#endif
sigfillset (&current->blocked);
fe->thread = current; fe->thread = current;
snprintf (current->comm, sizeof (current->comm), "kdvb-fe-%i:%i",
fe->frontend.i2c->adapter->num, fe->frontend.i2c->id);
unlock_kernel (); unlock_kernel ();
dvb_call_frontend_notifiers (fe, 0); dvb_call_frontend_notifiers (fe, 0);
dvb_frontend_init (fe); dvb_frontend_init (fe);
fe->lost_sync_count = -1;
while (!dvb_frontend_is_exiting (fe)) { while (!dvb_frontend_is_exiting (fe)) {
up (&fe->sem); /* is locked when we enter the thread... */ up (&fe->sem); /* is locked when we enter the thread... */
...@@ -499,6 +465,9 @@ int dvb_frontend_thread (void *data) ...@@ -499,6 +465,9 @@ int dvb_frontend_thread (void *data)
return -ERESTARTSYS; return -ERESTARTSYS;
} }
if (fe->lost_sync_count == -1)
continue;
if (dvb_frontend_is_exiting (fe)) if (dvb_frontend_is_exiting (fe))
break; break;
...@@ -513,10 +482,14 @@ int dvb_frontend_thread (void *data) ...@@ -513,10 +482,14 @@ int dvb_frontend_thread (void *data)
fe->lost_sync_count = 0; fe->lost_sync_count = 0;
} else { } else {
fe->lost_sync_count++; fe->lost_sync_count++;
if (fe->lost_sync_count < 10) /* XXX FIXME CHECKME! */ if (!(fe->info->caps & FE_CAN_RECOVER)) {
continue; if (!(fe->info->caps & FE_CAN_CLEAN_SETUP)) {
dvb_frontend_recover (fe); if (fe->lost_sync_count < 10)
delay = HZ/5; continue;
}
dvb_frontend_recover (fe);
delay = HZ/5;
}
if (jiffies - fe->lost_sync_jiffies > TIMEOUT) { if (jiffies - fe->lost_sync_jiffies > TIMEOUT) {
s |= FE_TIMEDOUT; s |= FE_TIMEDOUT;
if ((fe->status & FE_TIMEDOUT) == 0) if ((fe->status & FE_TIMEDOUT) == 0)
...@@ -528,7 +501,9 @@ int dvb_frontend_thread (void *data) ...@@ -528,7 +501,9 @@ int dvb_frontend_thread (void *data)
dvb_frontend_add_event (fe, s); dvb_frontend_add_event (fe, s);
}; };
dvb_frontend_internal_ioctl (&fe->frontend, FE_SLEEP, NULL); if (dvb_shutdown_timeout)
dvb_frontend_internal_ioctl (&fe->frontend, FE_SLEEP, NULL);
up (&fe->sem); up (&fe->sem);
fe->thread = NULL; fe->thread = NULL;
return 0; return 0;
...@@ -536,30 +511,36 @@ int dvb_frontend_thread (void *data) ...@@ -536,30 +511,36 @@ int dvb_frontend_thread (void *data)
static static
void dvb_frontend_start (struct dvb_frontend_data *fe) void dvb_frontend_stop (struct dvb_frontend_data *fe)
{ {
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
if (!fe->exit && !fe->thread) { while (fe->thread) {
if (down_interruptible (&fe->sem)) fe->exit = 1;
return; wake_up_interruptible (&fe->wait_queue);
kernel_thread (dvb_frontend_thread, fe, 0); current->state = TASK_INTERRUPTIBLE;
} schedule_timeout (5);
if (signal_pending(current))
break;
};
} }
static static
void dvb_frontend_stop (struct dvb_frontend_data *fe) void dvb_frontend_start (struct dvb_frontend_data *fe)
{ {
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
fe->exit = 1; if (fe->thread)
wake_up_interruptible (&fe->wait_queue); dvb_frontend_stop (fe);
while (fe->thread) { if (down_interruptible (&fe->sem))
current->state = TASK_INTERRUPTIBLE; return;
schedule_timeout (5);
}; fe->exit = 0;
fe->thread = (void*) ~0;
kernel_thread (dvb_frontend_thread, fe, 0);
} }
...@@ -615,9 +596,6 @@ unsigned int dvb_frontend_poll (struct file *file, struct poll_table_struct *wai ...@@ -615,9 +596,6 @@ unsigned int dvb_frontend_poll (struct file *file, struct poll_table_struct *wai
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
if (fe->events.eventw != fe->events.eventr)
return (POLLIN | POLLRDNORM | POLLPRI);
poll_wait (file, &fe->events.wait_queue, wait); poll_wait (file, &fe->events.wait_queue, wait);
if (fe->events.eventw != fe->events.eventr) if (fe->events.eventw != fe->events.eventr)
...@@ -639,10 +617,12 @@ int dvb_frontend_open (struct inode *inode, struct file *file) ...@@ -639,10 +617,12 @@ int dvb_frontend_open (struct inode *inode, struct file *file)
if ((ret = dvb_generic_open (inode, file)) < 0) if ((ret = dvb_generic_open (inode, file)) < 0)
return ret; return ret;
dvb_frontend_start (fe); if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
dvb_frontend_start (fe);
/* empty event queue */ /* empty event queue */
fe->events.eventr = fe->events.eventw; fe->events.eventr = fe->events.eventw;
}
return ret; return ret;
} }
...@@ -656,7 +636,8 @@ int dvb_frontend_release (struct inode *inode, struct file *file) ...@@ -656,7 +636,8 @@ int dvb_frontend_release (struct inode *inode, struct file *file)
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
fe->release_jiffies = jiffies; if ((file->f_flags & O_ACCMODE) != O_RDONLY)
fe->release_jiffies = jiffies;
return dvb_generic_release (inode, file); return dvb_generic_release (inode, file);
} }
...@@ -673,7 +654,6 @@ dvb_add_frontend_ioctls (struct dvb_adapter *adapter, ...@@ -673,7 +654,6 @@ dvb_add_frontend_ioctls (struct dvb_adapter *adapter,
{ {
struct dvb_frontend_ioctl_data *ioctl; struct dvb_frontend_ioctl_data *ioctl;
struct list_head *entry; struct list_head *entry;
int frontend_count = 0;
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
...@@ -706,14 +686,12 @@ dvb_add_frontend_ioctls (struct dvb_adapter *adapter, ...@@ -706,14 +686,12 @@ dvb_add_frontend_ioctls (struct dvb_adapter *adapter,
fe->frontend.before_ioctl = before_ioctl; fe->frontend.before_ioctl = before_ioctl;
fe->frontend.after_ioctl = after_ioctl; fe->frontend.after_ioctl = after_ioctl;
fe->frontend.before_after_data = before_after_data; fe->frontend.before_after_data = before_after_data;
dvb_frontend_start (fe);
frontend_count++;
} }
} }
up (&frontend_mutex); up (&frontend_mutex);
return frontend_count; return 0;
} }
...@@ -724,12 +702,11 @@ dvb_remove_frontend_ioctls (struct dvb_adapter *adapter, ...@@ -724,12 +702,11 @@ dvb_remove_frontend_ioctls (struct dvb_adapter *adapter,
int (*after_ioctl) (struct dvb_frontend *frontend, int (*after_ioctl) (struct dvb_frontend *frontend,
unsigned int cmd, void *arg)) unsigned int cmd, void *arg))
{ {
struct list_head *entry; struct list_head *entry, *n;
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
if (down_interruptible (&frontend_mutex)) down (&frontend_mutex);
return;
list_for_each (entry, &frontend_list) { list_for_each (entry, &frontend_list) {
struct dvb_frontend_data *fe; struct dvb_frontend_data *fe;
...@@ -746,6 +723,22 @@ dvb_remove_frontend_ioctls (struct dvb_adapter *adapter, ...@@ -746,6 +723,22 @@ dvb_remove_frontend_ioctls (struct dvb_adapter *adapter,
} }
} }
list_for_each_safe (entry, n, &frontend_ioctl_list) {
struct dvb_frontend_ioctl_data *ioctl;
ioctl = list_entry (entry, struct dvb_frontend_ioctl_data, list_head);
if (ioctl->adapter == adapter &&
ioctl->before_ioctl == before_ioctl &&
ioctl->after_ioctl == after_ioctl)
{
list_del (&ioctl->list_head);
kfree (ioctl);
break;
}
}
up (&frontend_mutex); up (&frontend_mutex);
} }
...@@ -755,41 +748,43 @@ dvb_add_frontend_notifier (struct dvb_adapter *adapter, ...@@ -755,41 +748,43 @@ dvb_add_frontend_notifier (struct dvb_adapter *adapter,
void (*callback) (fe_status_t s, void *data), void (*callback) (fe_status_t s, void *data),
void *data) void *data)
{ {
struct list_head *entry; struct dvb_frontend_notifier_data *notifier;
struct list_head *entry;
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
if (down_interruptible (&frontend_mutex)) if (down_interruptible (&frontend_mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
list_for_each (entry, &frontend_list) { notifier = kmalloc (sizeof(struct dvb_frontend_notifier_data), GFP_KERNEL);
struct dvb_frontend_data *fe;
fe = list_entry (entry, struct dvb_frontend_data, list_head); if (!notifier) {
up (&frontend_mutex);
return -ENOMEM;
}
if (fe->frontend.i2c->adapter == adapter) { notifier->adapter = adapter;
struct dvb_fe_notifier_callbacks *e; notifier->callback = callback;
notifier->data = data;
e = kmalloc (sizeof(struct dvb_fe_notifier_callbacks), list_add_tail (&notifier->list_head, &frontend_notifier_list);
GFP_KERNEL);
if (!e) { list_for_each (entry, &frontend_list) {
up (&frontend_mutex); struct dvb_frontend_data *fe;
return -ENOMEM;
}
e->callback = callback; fe = list_entry (entry, struct dvb_frontend_data, list_head);
e->data = data;
list_add_tail (&e->list_head, &fe->notifier_callbacks);
up (&frontend_mutex); if (fe->frontend.i2c->adapter == adapter &&
return 0; fe->frontend.notifier_callback == NULL)
{
fe->frontend.notifier_callback = callback;
fe->frontend.notifier_data = data;
} }
} }
up (&frontend_mutex); up (&frontend_mutex);
return -ENODEV; return 0;
} }
...@@ -797,30 +792,37 @@ void ...@@ -797,30 +792,37 @@ void
dvb_remove_frontend_notifier (struct dvb_adapter *adapter, dvb_remove_frontend_notifier (struct dvb_adapter *adapter,
void (*callback) (fe_status_t s, void *data)) void (*callback) (fe_status_t s, void *data))
{ {
struct list_head *entry; struct list_head *entry, *n;
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
if (down_interruptible (&frontend_mutex)) down (&frontend_mutex);
return;
list_for_each (entry, &frontend_list) { list_for_each (entry, &frontend_list) {
struct dvb_frontend_data *fe; struct dvb_frontend_data *fe;
fe = list_entry (entry, struct dvb_frontend_data, list_head); fe = list_entry (entry, struct dvb_frontend_data, list_head);
if (fe->frontend.i2c->adapter == adapter) { if (fe->frontend.i2c->adapter == adapter &&
struct list_head *e0, *n0; fe->frontend.notifier_callback == callback)
{
fe->frontend.notifier_callback = NULL;
list_for_each_safe (e0, n0, &fe->notifier_callbacks) { }
struct dvb_fe_notifier_callbacks *e; }
e = list_entry (e0, list_for_each_safe (entry, n, &frontend_notifier_list) {
struct dvb_fe_notifier_callbacks, struct dvb_frontend_notifier_data *notifier;
list_head);
list_del (&e->list_head); notifier = list_entry (entry, struct dvb_frontend_notifier_data, list_head);
kfree (e);
} if (notifier->adapter == adapter &&
notifier->callback == callback)
{
list_del (&notifier->list_head);
kfree (notifier);
break;
} }
} }
...@@ -849,7 +851,7 @@ dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend, ...@@ -849,7 +851,7 @@ dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend,
struct list_head *entry; struct list_head *entry;
struct dvb_frontend_data *fe; struct dvb_frontend_data *fe;
static const struct dvb_device dvbdev_template = { static const struct dvb_device dvbdev_template = {
.users = 1, .users = ~0,
.writers = 1, .writers = 1,
.fops = &dvb_frontend_fops, .fops = &dvb_frontend_fops,
.kernel_ioctl = dvb_frontend_ioctl .kernel_ioctl = dvb_frontend_ioctl
...@@ -873,7 +875,6 @@ dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend, ...@@ -873,7 +875,6 @@ dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend,
init_MUTEX (&fe->events.sem); init_MUTEX (&fe->events.sem);
fe->events.eventw = fe->events.eventr = 0; fe->events.eventw = fe->events.eventr = 0;
fe->events.overflow = 0; fe->events.overflow = 0;
INIT_LIST_HEAD (&fe->notifier_callbacks);
fe->frontend.ioctl = ioctl; fe->frontend.ioctl = ioctl;
fe->frontend.i2c = i2c; fe->frontend.i2c = i2c;
...@@ -891,13 +892,30 @@ dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend, ...@@ -891,13 +892,30 @@ dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend,
fe->frontend.before_ioctl = ioctl->before_ioctl; fe->frontend.before_ioctl = ioctl->before_ioctl;
fe->frontend.after_ioctl = ioctl->after_ioctl; fe->frontend.after_ioctl = ioctl->after_ioctl;
fe->frontend.before_after_data = ioctl->before_after_data; fe->frontend.before_after_data = ioctl->before_after_data;
dvb_frontend_start (fe); break;
}
}
list_for_each (entry, &frontend_notifier_list) {
struct dvb_frontend_notifier_data *notifier;
notifier = list_entry (entry,
struct dvb_frontend_notifier_data,
list_head);
if (notifier->adapter == i2c->adapter) {
fe->frontend.notifier_callback = notifier->callback;
fe->frontend.notifier_data = notifier->data;
break; break;
} }
} }
list_add_tail (&fe->list_head, &frontend_list); list_add_tail (&fe->list_head, &frontend_list);
printk ("DVB: registering frontend %i:%i (%s)...\n",
fe->frontend.i2c->adapter->num, fe->frontend.i2c->id,
fe->info->name);
dvb_register_device (i2c->adapter, &fe->dvbdev, &dvbdev_template, dvb_register_device (i2c->adapter, &fe->dvbdev, &dvbdev_template,
fe, DVB_DEVICE_FRONTEND); fe, DVB_DEVICE_FRONTEND);
...@@ -915,8 +933,7 @@ int dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend, ...@@ -915,8 +933,7 @@ int dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend,
dprintk ("%s\n", __FUNCTION__); dprintk ("%s\n", __FUNCTION__);
if (down_interruptible (&frontend_mutex)) down (&frontend_mutex);
return -ERESTARTSYS;
list_for_each_safe (entry, n, &frontend_list) { list_for_each_safe (entry, n, &frontend_list) {
struct dvb_frontend_data *fe; struct dvb_frontend_data *fe;
...@@ -925,10 +942,8 @@ int dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend, ...@@ -925,10 +942,8 @@ int dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend,
if (fe->frontend.ioctl == ioctl && fe->frontend.i2c == i2c) { if (fe->frontend.ioctl == ioctl && fe->frontend.i2c == i2c) {
dvb_unregister_device (fe->dvbdev); dvb_unregister_device (fe->dvbdev);
list_del (entry); list_del (entry);
up (&frontend_mutex); up (&frontend_mutex);
dvb_frontend_stop (fe); dvb_frontend_stop (fe);
kfree (fe); kfree (fe);
return 0; return 0;
......
...@@ -52,8 +52,10 @@ struct dvb_frontend { ...@@ -52,8 +52,10 @@ struct dvb_frontend {
int (*before_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg); int (*before_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg);
int (*ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg); int (*ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg);
int (*after_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg); int (*after_ioctl) (struct dvb_frontend *frontend, unsigned int cmd, void *arg);
void (*notifier_callback) (fe_status_t s, void *data);
struct dvb_i2c_bus *i2c; struct dvb_i2c_bus *i2c;
void *before_after_data; /* can be used by hardware module... */ void *before_after_data; /* can be used by hardware module... */
void *notifier_data; /* can be used by hardware module... */
void *data; /* can be used by hardware module... */ void *data; /* can be used by hardware module... */
}; };
......
...@@ -22,10 +22,13 @@ ...@@ -22,10 +22,13 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/version.h>
#include "compat.h" #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51)
#include "dvb_i2c.h" #include "compat.h"
#endif
#include "dvb_i2c.h"
struct dvb_i2c_device { struct dvb_i2c_device {
struct list_head list_head; struct list_head list_head;
...@@ -34,13 +37,11 @@ struct dvb_i2c_device { ...@@ -34,13 +37,11 @@ struct dvb_i2c_device {
void (*detach) (struct dvb_i2c_bus *i2c); void (*detach) (struct dvb_i2c_bus *i2c);
}; };
LIST_HEAD(dvb_i2c_buslist); LIST_HEAD(dvb_i2c_buslist);
LIST_HEAD(dvb_i2c_devicelist); LIST_HEAD(dvb_i2c_devicelist);
DECLARE_MUTEX(dvb_i2c_mutex); DECLARE_MUTEX(dvb_i2c_mutex);
static static
int register_i2c_client (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev) int register_i2c_client (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev)
{ {
...@@ -63,11 +64,16 @@ int register_i2c_client (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev) ...@@ -63,11 +64,16 @@ int register_i2c_client (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev)
static static
void try_attach_device (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev) void try_attach_device (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev)
{ {
if (try_module_get(dev->owner)) { if (dev->owner) {
if (dev->attach(i2c) == 0) if (!try_module_get(dev->owner))
register_i2c_client(i2c, dev); return;
else }
module_put(dev->owner);
if (dev->attach (i2c) == 0) {
register_i2c_client (i2c, dev);
} else {
if (dev->owner)
module_put (dev->owner);
} }
} }
...@@ -75,8 +81,10 @@ void try_attach_device (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev) ...@@ -75,8 +81,10 @@ void try_attach_device (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev)
static static
void detach_device (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev) void detach_device (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev)
{ {
dev->detach(i2c); dev->detach (i2c);
module_put(dev->owner);
if (dev->owner)
module_put (dev->owner);
} }
...@@ -84,15 +92,17 @@ static ...@@ -84,15 +92,17 @@ static
void unregister_i2c_client_from_bus (struct dvb_i2c_device *dev, void unregister_i2c_client_from_bus (struct dvb_i2c_device *dev,
struct dvb_i2c_bus *i2c) struct dvb_i2c_bus *i2c)
{ {
struct list_head *entry; struct list_head *entry, *n;
list_for_each (entry, &i2c->client_list) { list_for_each_safe (entry, n, &i2c->client_list) {
struct dvb_i2c_device *client; struct dvb_i2c_device *client;
client = list_entry (entry, struct dvb_i2c_device, list_head); client = list_entry (entry, struct dvb_i2c_device, list_head);
if (client->detach == dev->detach) if (client->detach == dev->detach) {
list_del (entry);
detach_device (i2c, dev); detach_device (i2c, dev);
}
} }
} }
...@@ -100,9 +110,9 @@ void unregister_i2c_client_from_bus (struct dvb_i2c_device *dev, ...@@ -100,9 +110,9 @@ void unregister_i2c_client_from_bus (struct dvb_i2c_device *dev,
static static
void unregister_i2c_client_from_all_busses (struct dvb_i2c_device *dev) void unregister_i2c_client_from_all_busses (struct dvb_i2c_device *dev)
{ {
struct list_head *entry; struct list_head *entry, *n;
list_for_each (entry, &dvb_i2c_buslist) { list_for_each_safe (entry, n, &dvb_i2c_buslist) {
struct dvb_i2c_bus *i2c; struct dvb_i2c_bus *i2c;
i2c = list_entry (entry, struct dvb_i2c_bus, list_head); i2c = list_entry (entry, struct dvb_i2c_bus, list_head);
...@@ -118,18 +128,15 @@ void unregister_all_clients_from_bus (struct dvb_i2c_bus *i2c) ...@@ -118,18 +128,15 @@ void unregister_all_clients_from_bus (struct dvb_i2c_bus *i2c)
struct list_head *entry, *n; struct list_head *entry, *n;
list_for_each_safe (entry, n, &(i2c->client_list)) { list_for_each_safe (entry, n, &(i2c->client_list)) {
struct dvb_i2c_device *client; struct dvb_i2c_device *dev;
client = list_entry (entry, struct dvb_i2c_device, list_head);
detach_device (i2c, client); dev = list_entry (entry, struct dvb_i2c_device, list_head);
list_del (entry); unregister_i2c_client_from_bus (dev, i2c);
} }
} }
static static
void probe_device_on_all_busses (struct dvb_i2c_device *dev) void probe_device_on_all_busses (struct dvb_i2c_device *dev)
{ {
...@@ -160,15 +167,38 @@ void probe_devices_on_bus (struct dvb_i2c_bus *i2c) ...@@ -160,15 +167,38 @@ void probe_devices_on_bus (struct dvb_i2c_bus *i2c)
} }
static
struct dvb_i2c_bus* dvb_find_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
const struct i2c_msg msgs[],
int num),
struct dvb_adapter *adapter,
int id)
{
struct list_head *entry;
list_for_each (entry, &dvb_i2c_buslist) {
struct dvb_i2c_bus *i2c;
i2c = list_entry (entry, struct dvb_i2c_bus, list_head);
if (i2c->xfer == xfer && i2c->adapter == adapter && i2c->id == id)
return i2c;
}
return NULL;
}
struct dvb_i2c_bus* struct dvb_i2c_bus*
dvb_register_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c, dvb_register_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
struct i2c_msg msgs[], int num), const struct i2c_msg *msgs, int num),
void *data, void *data, struct dvb_adapter *adapter, int id)
struct dvb_adapter *adapter,
int id)
{ {
struct dvb_i2c_bus *i2c; struct dvb_i2c_bus *i2c;
if (down_interruptible (&dvb_i2c_mutex))
return NULL;
if (!(i2c = kmalloc (sizeof (struct dvb_i2c_bus), GFP_KERNEL))) if (!(i2c = kmalloc (sizeof (struct dvb_i2c_bus), GFP_KERNEL)))
return NULL; return NULL;
...@@ -184,54 +214,27 @@ dvb_register_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c, ...@@ -184,54 +214,27 @@ dvb_register_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
list_add_tail (&i2c->list_head, &dvb_i2c_buslist); list_add_tail (&i2c->list_head, &dvb_i2c_buslist);
return i2c;
}
struct dvb_i2c_bus*
dvb_find_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
struct i2c_msg msgs[], int num),
struct dvb_adapter *adapter,
int id)
{
struct list_head *entry;
if (down_interruptible (&dvb_i2c_mutex))
return NULL;
list_for_each (entry, &dvb_i2c_buslist) {
struct dvb_i2c_bus *i2c;
i2c = list_entry (entry, struct dvb_i2c_bus, list_head);
if (i2c->xfer == xfer &&
i2c->adapter == adapter &&
i2c->id == id)
{
up (&dvb_i2c_mutex);
return i2c;
}
}
up (&dvb_i2c_mutex); up (&dvb_i2c_mutex);
return NULL; return i2c;
} }
void dvb_unregister_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c, void dvb_unregister_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
struct i2c_msg msgs[], int num), const struct i2c_msg msgs[], int num),
struct dvb_adapter *adapter, struct dvb_adapter *adapter, int id)
int id)
{ {
struct dvb_i2c_bus *i2c = dvb_find_i2c_bus (xfer, adapter, id); struct dvb_i2c_bus *i2c;
down (&dvb_i2c_mutex);
if (i2c) { if ((i2c = dvb_find_i2c_bus (xfer, adapter, id))) {
unregister_all_clients_from_bus (i2c); unregister_all_clients_from_bus (i2c);
list_del (&i2c->list_head); list_del (&i2c->list_head);
kfree (i2c); kfree (i2c);
} }
up (&dvb_i2c_mutex);
} }
...@@ -267,8 +270,7 @@ int dvb_unregister_i2c_device (int (*attach) (struct dvb_i2c_bus *i2c)) ...@@ -267,8 +270,7 @@ int dvb_unregister_i2c_device (int (*attach) (struct dvb_i2c_bus *i2c))
{ {
struct list_head *entry, *n; struct list_head *entry, *n;
if (down_interruptible (&dvb_i2c_mutex)) down (&dvb_i2c_mutex);
return -ERESTARTSYS;
list_for_each_safe (entry, n, &dvb_i2c_devicelist) { list_for_each_safe (entry, n, &dvb_i2c_devicelist) {
struct dvb_i2c_device *dev; struct dvb_i2c_device *dev;
......
...@@ -30,7 +30,9 @@ ...@@ -30,7 +30,9 @@
struct dvb_i2c_bus { struct dvb_i2c_bus {
struct list_head list_head; struct list_head list_head;
int (*xfer) (struct dvb_i2c_bus *i2c, struct i2c_msg msgs[], int num); int (*xfer) (struct dvb_i2c_bus *i2c,
const struct i2c_msg msgs[],
int num);
void *data; void *data;
struct dvb_adapter *adapter; struct dvb_adapter *adapter;
int id; int id;
...@@ -38,17 +40,16 @@ struct dvb_i2c_bus { ...@@ -38,17 +40,16 @@ struct dvb_i2c_bus {
}; };
extern extern struct dvb_i2c_bus*
struct dvb_i2c_bus* dvb_register_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c, dvb_register_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
struct i2c_msg msgs[], const struct i2c_msg *msgs, int num),
int num), void *data,
void *data, struct dvb_adapter *adapter,
struct dvb_adapter *adapter, int id);
int id);
extern extern
void dvb_unregister_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c, void dvb_unregister_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
struct i2c_msg msgs[], int num), const struct i2c_msg msgs[], int num),
struct dvb_adapter *adapter, struct dvb_adapter *adapter,
int id); int id);
......
...@@ -8,6 +8,69 @@ ...@@ -8,6 +8,69 @@
#include "dvb_demux.h" #include "dvb_demux.h"
#include "dvb_net.h" #include "dvb_net.h"
/* if the miracle happens and "generic_usercopy()" is included into
the kernel, then this can vanish. please don't make the mistake and
define this as video_usercopy(). this will introduce a dependecy
to the v4l "videodev.o" module, which is unnecessary for some
cards (ie. the budget dvb-cards don't need the v4l module...) */
int dvb_usercopy(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg,
int (*func)(struct inode *inode, struct file *file,
unsigned int cmd, void *arg))
{
char sbuf[128];
void *mbuf = NULL;
void *parg = NULL;
int err = -EINVAL;
/* Copy arguments into temp kernel buffer */
switch (_IOC_DIR(cmd)) {
case _IOC_NONE:
parg = (void *)arg;
break;
case _IOC_READ: /* some v4l ioctls are marked wrong ... */
case _IOC_WRITE:
case (_IOC_WRITE | _IOC_READ):
if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
parg = sbuf;
} else {
/* too big to allocate from stack */
mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
if (NULL == mbuf)
return -ENOMEM;
parg = mbuf;
}
err = -EFAULT;
if (copy_from_user(parg, (void *)arg, _IOC_SIZE(cmd)))
goto out;
break;
}
/* call driver */
if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD)
err = -EINVAL;
if (err < 0)
goto out;
/* Copy results into user buffer */
switch (_IOC_DIR(cmd))
{
case _IOC_READ:
case (_IOC_WRITE | _IOC_READ):
if (copy_to_user((void *)arg, parg, _IOC_SIZE(cmd)))
err = -EFAULT;
break;
}
out:
if (mbuf)
kfree(mbuf);
return err;
}
EXPORT_SYMBOL(dvb_usercopy);
EXPORT_SYMBOL(dvb_dmxdev_init); EXPORT_SYMBOL(dvb_dmxdev_init);
EXPORT_SYMBOL(dvb_dmxdev_release); EXPORT_SYMBOL(dvb_dmxdev_release);
...@@ -15,6 +78,7 @@ EXPORT_SYMBOL(dvb_dmx_init); ...@@ -15,6 +78,7 @@ EXPORT_SYMBOL(dvb_dmx_init);
EXPORT_SYMBOL(dvb_dmx_release); EXPORT_SYMBOL(dvb_dmx_release);
EXPORT_SYMBOL(dvb_dmx_swfilter_packet); EXPORT_SYMBOL(dvb_dmx_swfilter_packet);
EXPORT_SYMBOL(dvb_dmx_swfilter_packets); EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
EXPORT_SYMBOL(dvb_dmx_swfilter);
EXPORT_SYMBOL(dvb_register_frontend); EXPORT_SYMBOL(dvb_register_frontend);
EXPORT_SYMBOL(dvb_unregister_frontend); EXPORT_SYMBOL(dvb_unregister_frontend);
...@@ -39,11 +103,7 @@ EXPORT_SYMBOL(dvb_generic_ioctl); ...@@ -39,11 +103,7 @@ EXPORT_SYMBOL(dvb_generic_ioctl);
EXPORT_SYMBOL(dvb_generic_open); EXPORT_SYMBOL(dvb_generic_open);
EXPORT_SYMBOL(dvb_generic_release); EXPORT_SYMBOL(dvb_generic_release);
EXPORT_SYMBOL(dvb_filter_ipack_init);
EXPORT_SYMBOL(dvb_filter_ipack_reset);
EXPORT_SYMBOL(dvb_filter_ipack_free);
EXPORT_SYMBOL(dvb_filter_ipack_flush);
EXPORT_SYMBOL(dvb_filter_instant_repack);
EXPORT_SYMBOL(dvb_filter_pes2ts_init); EXPORT_SYMBOL(dvb_filter_pes2ts_init);
EXPORT_SYMBOL(dvb_filter_pes2ts); EXPORT_SYMBOL(dvb_filter_pes2ts);
EXPORT_SYMBOL(dvb_filter_get_ac3info);
...@@ -3,29 +3,52 @@ ...@@ -3,29 +3,52 @@
* *
* Copyright (C) 2001 Convergence integrated media GmbH * Copyright (C) 2001 Convergence integrated media GmbH
* Ralph Metzler <ralph@convergence.de> * Ralph Metzler <ralph@convergence.de>
* Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License * modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2.1 * as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version. * of the License, or (at your option) any later version.
*
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
*
* *
* You should have received a copy of the GNU Lesser General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*/ */
#include <linux/dvb/net.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include "demux.h"
#include <linux/dvb/net.h>
#include "dvb_demux.h"
#include "dvb_net.h" #include "dvb_net.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51)
#include "compat.h"
#endif
#define DVB_NET_MULTICAST_MAX 10
struct dvb_net_priv {
struct net_device_stats stats;
char name[6];
u16 pid;
struct dmx_demux_s *demux;
dmx_section_feed_t *secfeed;
dmx_section_filter_t *secfilter;
int multi_num;
dmx_section_filter_t *multi_secfilter[DVB_NET_MULTICAST_MAX];
unsigned char multi_macs[DVB_NET_MULTICAST_MAX][6];
int mode;
};
/* /*
* Determine the packet's protocol ID. The rule here is that we * Determine the packet's protocol ID. The rule here is that we
* assume 802.3 if the type field is short enough to be a length. * assume 802.3 if the type field is short enough to be a length.
...@@ -73,7 +96,7 @@ unsigned short my_eth_type_trans(struct sk_buff *skb, struct net_device *dev) ...@@ -73,7 +96,7 @@ unsigned short my_eth_type_trans(struct sk_buff *skb, struct net_device *dev)
} }
static void static void
dvb_net_sec(struct net_device *dev, u8 *pkt, int pkt_len) dvb_net_sec(struct net_device *dev, const u8 *pkt, int pkt_len)
{ {
u8 *eth; u8 *eth;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -86,7 +109,7 @@ dvb_net_sec(struct net_device *dev, u8 *pkt, int pkt_len) ...@@ -86,7 +109,7 @@ dvb_net_sec(struct net_device *dev, u8 *pkt, int pkt_len)
if (skb == NULL) { if (skb == NULL) {
printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
dev->name); dev->name);
((dvb_net_priv_t *)dev->priv)->stats.rx_dropped++; ((struct dvb_net_priv *)dev->priv)->stats.rx_dropped++;
return; return;
} }
eth=(u8 *) skb_put(skb, pkt_len+2); eth=(u8 *) skb_put(skb, pkt_len+2);
...@@ -104,15 +127,14 @@ dvb_net_sec(struct net_device *dev, u8 *pkt, int pkt_len) ...@@ -104,15 +127,14 @@ dvb_net_sec(struct net_device *dev, u8 *pkt, int pkt_len)
skb->protocol=my_eth_type_trans(skb,dev); skb->protocol=my_eth_type_trans(skb,dev);
skb->dev=dev; skb->dev=dev;
((dvb_net_priv_t *)dev->priv)->stats.rx_packets++; ((struct dvb_net_priv *)dev->priv)->stats.rx_packets++;
((dvb_net_priv_t *)dev->priv)->stats.rx_bytes+=skb->len; ((struct dvb_net_priv *)dev->priv)->stats.rx_bytes+=skb->len;
//sti();
netif_rx(skb); netif_rx(skb);
} }
static int static int
dvb_net_callback(u8 *buffer1, size_t buffer1_len, dvb_net_callback(const u8 *buffer1, size_t buffer1_len,
u8 *buffer2, size_t buffer2_len, const u8 *buffer2, size_t buffer2_len,
dmx_section_filter_t *filter, dmx_section_filter_t *filter,
dmx_success_t success) dmx_success_t success)
{ {
...@@ -130,18 +152,21 @@ dvb_net_tx(struct sk_buff *skb, struct net_device *dev) ...@@ -130,18 +152,21 @@ dvb_net_tx(struct sk_buff *skb, struct net_device *dev)
return 0; return 0;
} }
#define MASK 0x00; static u8 mask_normal[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
static u8 mask_allmulti[6]={0xff, 0xff, 0xff, 0x00, 0x00, 0x00};
static u8 mac_allmulti[6]={0x01, 0x00, 0x5e, 0x00, 0x00, 0x00};
static u8 mask_promisc[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static int static int
dvb_net_filter_set(struct net_device *dev, dvb_net_filter_set(struct net_device *dev,
dmx_section_filter_t **secfilter, dmx_section_filter_t **secfilter,
unsigned char *mac) u8 *mac, u8 *mac_mask)
{ {
dvb_net_priv_t *priv=(dvb_net_priv_t *)dev->priv; struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
int ret; int ret;
*secfilter=0; *secfilter=0;
ret=priv->secfeed->allocate_filter(priv->secfeed, secfilter); ret = priv->secfeed->allocate_filter(priv->secfeed, secfilter);
if (ret<0) { if (ret<0) {
printk("%s: could not get filter\n", dev->name); printk("%s: could not get filter\n", dev->name);
return ret; return ret;
...@@ -149,25 +174,26 @@ dvb_net_filter_set(struct net_device *dev, ...@@ -149,25 +174,26 @@ dvb_net_filter_set(struct net_device *dev,
(*secfilter)->priv=(void *) dev; (*secfilter)->priv=(void *) dev;
memset((*secfilter)->filter_value, 0, DMX_MAX_FILTER_SIZE); memset((*secfilter)->filter_value, 0x00, DMX_MAX_FILTER_SIZE);
memset((*secfilter)->filter_mask , 0, DMX_MAX_FILTER_SIZE); memset((*secfilter)->filter_mask, 0x00, DMX_MAX_FILTER_SIZE);
memset((*secfilter)->filter_mode, 0xff, DMX_MAX_FILTER_SIZE);
(*secfilter)->filter_value[0]=0x3e; (*secfilter)->filter_value[0]=0x3e;
(*secfilter)->filter_mask[0]=MASK; (*secfilter)->filter_mask[0]=0xff;
(*secfilter)->filter_value[3]=mac[5]; (*secfilter)->filter_value[3]=mac[5];
(*secfilter)->filter_mask[3]=MASK; (*secfilter)->filter_mask[3]=mac_mask[5];
(*secfilter)->filter_value[4]=mac[4]; (*secfilter)->filter_value[4]=mac[4];
(*secfilter)->filter_mask[4]=MASK; (*secfilter)->filter_mask[4]=mac_mask[4];
(*secfilter)->filter_value[8]=mac[3]; (*secfilter)->filter_value[8]=mac[3];
(*secfilter)->filter_mask[8]=MASK; (*secfilter)->filter_mask[8]=mac_mask[3];
(*secfilter)->filter_value[9]=mac[2]; (*secfilter)->filter_value[9]=mac[2];
(*secfilter)->filter_mask[9]=MASK; (*secfilter)->filter_mask[9]=mac_mask[2];
(*secfilter)->filter_value[10]=mac[1]; (*secfilter)->filter_value[10]=mac[1];
(*secfilter)->filter_mask[10]=MASK; (*secfilter)->filter_mask[10]=mac_mask[1];
(*secfilter)->filter_value[11]=mac[0]; (*secfilter)->filter_value[11]=mac[0];
(*secfilter)->filter_mask[11]=MASK; (*secfilter)->filter_mask[11]=mac_mask[0];
printk("%s: filter mac=%02x %02x %02x %02x %02x %02x\n", printk("%s: filter mac=%02x %02x %02x %02x %02x %02x\n",
dev->name, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); dev->name, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
...@@ -178,9 +204,9 @@ static int ...@@ -178,9 +204,9 @@ static int
dvb_net_feed_start(struct net_device *dev) dvb_net_feed_start(struct net_device *dev)
{ {
int ret, i; int ret, i;
dvb_net_priv_t *priv=(dvb_net_priv_t *)dev->priv; struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
dmx_demux_t *demux=priv->demux; dmx_demux_t *demux = priv->demux;
unsigned char *mac=(unsigned char *) dev->dev_addr; unsigned char *mac = (unsigned char *) dev->dev_addr;
priv->secfeed=0; priv->secfeed=0;
priv->secfilter=0; priv->secfilter=0;
...@@ -200,28 +226,41 @@ dvb_net_feed_start(struct net_device *dev) ...@@ -200,28 +226,41 @@ dvb_net_feed_start(struct net_device *dev)
priv->secfeed=0; priv->secfeed=0;
return ret; return ret;
} }
MOD_INC_USE_COUNT; /* fixme: is this correct? */
try_module_get(THIS_MODULE);
dvb_net_filter_set(dev, &priv->secfilter, mac); if (priv->mode<3)
for (i=0; i<priv->multi_num; i++) dvb_net_filter_set(dev, &priv->secfilter, mac, mask_normal);
dvb_net_filter_set(dev, &priv->secfilter,
priv->multi_macs[i]);
switch (priv->mode) {
case 1:
for (i=0; i<priv->multi_num; i++)
dvb_net_filter_set(dev, &priv->multi_secfilter[i],
priv->multi_macs[i], mask_normal);
break;
case 2:
priv->multi_num=1;
dvb_net_filter_set(dev, &priv->multi_secfilter[0], mac_allmulti, mask_allmulti);
break;
case 3:
priv->multi_num=0;
dvb_net_filter_set(dev, &priv->secfilter, mac, mask_promisc);
break;
}
priv->secfeed->start_filtering(priv->secfeed); priv->secfeed->start_filtering(priv->secfeed);
printk("%s: feed_started\n", dev->name);
return 0; return 0;
} }
static void static void
dvb_net_feed_stop(struct net_device *dev) dvb_net_feed_stop(struct net_device *dev)
{ {
dvb_net_priv_t *priv=(dvb_net_priv_t *)dev->priv; struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
int i; int i;
if (priv->secfeed) { if (priv->secfeed) {
if (priv->secfeed->is_filtering) if (priv->secfeed->is_filtering)
priv->secfeed->stop_filtering(priv->secfeed); priv->secfeed->stop_filtering(priv->secfeed);
printk("%s: feed_stopped\n", dev->name);
if (priv->secfilter) if (priv->secfilter)
priv->secfeed-> priv->secfeed->
release_filter(priv->secfeed, release_filter(priv->secfeed,
...@@ -238,62 +277,70 @@ dvb_net_feed_stop(struct net_device *dev) ...@@ -238,62 +277,70 @@ dvb_net_feed_stop(struct net_device *dev)
priv->demux-> priv->demux->
release_section_feed(priv->demux, priv->secfeed); release_section_feed(priv->demux, priv->secfeed);
priv->secfeed=0; priv->secfeed=0;
MOD_DEC_USE_COUNT; /* fixme: is this correct? */
module_put(THIS_MODULE);
} else } else
printk("%s: no feed to stop\n", dev->name); printk("%s: no feed to stop\n", dev->name);
} }
static int static int
dvb_set_mc_filter(struct net_device *dev, struct dev_mc_list *mc) dvb_add_mc_filter(struct net_device *dev, struct dev_mc_list *mc)
{ {
dvb_net_priv_t *priv=(dvb_net_priv_t *)dev->priv; struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
int ret;
if (priv->multi_num==DVB_NET_MULTICAST_MAX) if (priv->multi_num >= DVB_NET_MULTICAST_MAX)
return -ENOMEM; return -ENOMEM;
printk("%s: set_mc_filter %d: %02x %02x %02x %02x %02x %02x\n", ret = memcmp(priv->multi_macs[priv->multi_num], mc->dmi_addr, 6);
dev->name,
priv->multi_num,
mc->dmi_addr[0],
mc->dmi_addr[1],
mc->dmi_addr[2],
mc->dmi_addr[3],
mc->dmi_addr[4],
mc->dmi_addr[5]);
memcpy(priv->multi_macs[priv->multi_num], mc->dmi_addr, 6); memcpy(priv->multi_macs[priv->multi_num], mc->dmi_addr, 6);
priv->multi_num++; priv->multi_num++;
return 0;
return ret;
} }
static void static void
dvb_net_set_multi(struct net_device *dev) dvb_net_set_multi(struct net_device *dev)
{ {
dvb_net_priv_t *priv=(dvb_net_priv_t *)dev->priv; struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
struct dev_mc_list *mc;
printk("%s: set_multi()\n", dev->name); int mci;
dvb_net_feed_stop(dev); int update = 0;
if (dev->flags&IFF_PROMISC) { if(dev->flags & IFF_PROMISC) {
/* Enable promiscuous mode */ // printk("%s: promiscuous mode\n", dev->name);
printk("%s: promiscuous mode\n", dev->name); if(priv->mode != 3)
} else if((dev->flags&IFF_ALLMULTI)) { update = 1;
/* Disable promiscuous mode, use normal mode. */ priv->mode = 3;
printk("%s: normal mode\n", dev->name); } else if(dev->flags & IFF_ALLMULTI) {
} else if(dev->mc_count) { // printk("%s: allmulti mode\n", dev->name);
int mci; if(priv->mode != 2)
struct dev_mc_list *mc; update = 1;
priv->mode = 2;
printk("%s: set_mc_list, %d entries\n", } else if(dev->mc_count > 0) {
dev->name, dev->mc_count); // printk("%s: set_mc_list, %d entries\n",
priv->multi_num=0; // dev->name, dev->mc_count);
for (mci=0, mc=dev->mc_list; if(priv->mode != 1)
mci<dev->mc_count; update = 1;
mc=mc->next, mci++) { priv->mode = 1;
dvb_set_mc_filter(dev, mc); priv->multi_num = 0;
} for (mci = 0, mc=dev->mc_list;
mci < dev->mc_count;
mc=mc->next, mci++)
if(dvb_add_mc_filter(dev, mc) != 0)
update = 1;
} else {
if(priv->mode != 0)
update = 1;
priv->mode = 0;
}
if(netif_running(dev) != 0 && update > 0)
{
dvb_net_feed_stop(dev);
dvb_net_feed_start(dev);
} }
dvb_net_feed_start(dev);
} }
static int static int
...@@ -308,13 +355,15 @@ static int ...@@ -308,13 +355,15 @@ static int
dvb_net_set_mac(struct net_device *dev, void *p) dvb_net_set_mac(struct net_device *dev, void *p)
{ {
struct sockaddr *addr=p; struct sockaddr *addr=p;
int update;
update = memcmp(dev->dev_addr, addr->sa_data, dev->addr_len);
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
if (netif_running(dev)) { if (netif_running(dev) != 0 && update > 0) {
dvb_net_feed_stop(dev); dvb_net_feed_stop(dev);
dvb_net_feed_start(dev); dvb_net_feed_start(dev);
} }
return 0; return 0;
} }
...@@ -335,15 +384,13 @@ dvb_net_stop(struct net_device *dev) ...@@ -335,15 +384,13 @@ dvb_net_stop(struct net_device *dev)
static struct net_device_stats * static struct net_device_stats *
dvb_net_get_stats(struct net_device *dev) dvb_net_get_stats(struct net_device *dev)
{ {
return &((dvb_net_priv_t *)dev->priv)->stats; return &((struct dvb_net_priv*) dev->priv)->stats;
} }
static int static int
dvb_net_init_dev(struct net_device *dev) dvb_net_init_dev(struct net_device *dev)
{ {
printk("dvb_net: dvb_net_init_dev()\n");
ether_setup(dev); ether_setup(dev);
dev->open = dvb_net_open; dev->open = dvb_net_open;
...@@ -354,6 +401,7 @@ dvb_net_init_dev(struct net_device *dev) ...@@ -354,6 +401,7 @@ dvb_net_init_dev(struct net_device *dev)
dev->set_config = dvb_net_set_config; dev->set_config = dvb_net_set_config;
dev->set_mac_address = dvb_net_set_mac; dev->set_mac_address = dvb_net_set_mac;
dev->mtu = 4096; dev->mtu = 4096;
dev->mc_count = 0;
dev->flags |= IFF_NOARP; dev->flags |= IFF_NOARP;
dev->hard_header_cache = NULL; dev->hard_header_cache = NULL;
...@@ -364,7 +412,7 @@ dvb_net_init_dev(struct net_device *dev) ...@@ -364,7 +412,7 @@ dvb_net_init_dev(struct net_device *dev)
} }
static int static int
get_if(dvb_net_t *dvbnet) get_if(struct dvb_net *dvbnet)
{ {
int i; int i;
...@@ -379,10 +427,11 @@ get_if(dvb_net_t *dvbnet) ...@@ -379,10 +427,11 @@ get_if(dvb_net_t *dvbnet)
int int
dvb_net_add_if(dvb_net_t *dvbnet, u16 pid) dvb_net_add_if(struct dvb_net *dvbnet, u16 pid)
{ {
struct net_device *net; struct net_device *net;
dmx_demux_t *demux; dmx_demux_t *demux;
struct dvb_net_priv *priv;
int result; int result;
int if_num; int if_num;
...@@ -402,25 +451,29 @@ dvb_net_add_if(dvb_net_t *dvbnet, u16 pid) ...@@ -402,25 +451,29 @@ dvb_net_add_if(dvb_net_t *dvbnet, u16 pid)
net->name[5]=if_num+0x30; net->name[5]=if_num+0x30;
net->next = NULL; net->next = NULL;
net->init = dvb_net_init_dev; net->init = dvb_net_init_dev;
net->priv = kmalloc(sizeof(dvb_net_priv_t), GFP_KERNEL); net->priv = kmalloc(sizeof(struct dvb_net_priv), GFP_KERNEL);
if (net->priv == NULL) if (net->priv == NULL)
return -ENOMEM; return -ENOMEM;
memset(net->priv, 0, sizeof(dvb_net_priv_t));
((dvb_net_priv_t *)net->priv)->demux=demux; priv = net->priv;
((dvb_net_priv_t *)net->priv)->pid=pid; memset(priv, 0, sizeof(struct dvb_net_priv));
priv->demux = demux;
priv->pid = pid;
priv->mode = 0;
net->base_addr=pid; net->base_addr = pid;
if ((result = register_netdev(net)) < 0) { if ((result = register_netdev(net)) < 0) {
return result; return result;
} }
MOD_INC_USE_COUNT; /* fixme: is this correct? */
try_module_get(THIS_MODULE);
return if_num; return if_num;
} }
int int
dvb_net_remove_if(dvb_net_t *dvbnet, int num) dvb_net_remove_if(struct dvb_net *dvbnet, int num)
{ {
if (!dvbnet->state[num]) if (!dvbnet->state[num])
return -EINVAL; return -EINVAL;
...@@ -428,15 +481,17 @@ dvb_net_remove_if(dvb_net_t *dvbnet, int num) ...@@ -428,15 +481,17 @@ dvb_net_remove_if(dvb_net_t *dvbnet, int num)
kfree(dvbnet->device[num].priv); kfree(dvbnet->device[num].priv);
unregister_netdev(&dvbnet->device[num]); unregister_netdev(&dvbnet->device[num]);
dvbnet->state[num]=0; dvbnet->state[num]=0;
MOD_DEC_USE_COUNT; /* fixme: is this correct? */
module_put(THIS_MODULE);
return 0; return 0;
} }
int dvb_net_ioctl(struct inode *inode, struct file *file, int dvb_net_do_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *parg) unsigned int cmd, void *parg)
{ {
struct dvb_device *dvbdev=(struct dvb_device *) file->private_data; struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
dvb_net_t *dvbnet=(dvb_net_t *) dvbdev->priv; struct dvb_net *dvbnet = (struct dvb_net *) dvbdev->priv;
if (((file->f_flags&O_ACCMODE)==O_RDONLY)) if (((file->f_flags&O_ACCMODE)==O_RDONLY))
return -EPERM; return -EPERM;
...@@ -453,6 +508,21 @@ int dvb_net_ioctl(struct inode *inode, struct file *file, ...@@ -453,6 +508,21 @@ int dvb_net_ioctl(struct inode *inode, struct file *file,
dvbnetif->if_num=result; dvbnetif->if_num=result;
break; break;
} }
case NET_GET_IF:
{
struct net_device *netdev;
struct dvb_net_priv *priv_data;
struct dvb_net_if *dvbnetif=(struct dvb_net_if *)parg;
if (dvbnetif->if_num >= dvbnet->dev_num ||
!dvbnet->state[dvbnetif->if_num])
return -EFAULT;
netdev=(struct net_device*)&dvbnet->device[dvbnetif->if_num];
priv_data=(struct dvb_net_priv*)netdev->priv;
dvbnetif->pid=priv_data->pid;
break;
}
case NET_REMOVE_IF: case NET_REMOVE_IF:
return dvb_net_remove_if(dvbnet, (int) parg); return dvb_net_remove_if(dvbnet, (int) parg);
default: default:
...@@ -461,23 +531,32 @@ int dvb_net_ioctl(struct inode *inode, struct file *file, ...@@ -461,23 +531,32 @@ int dvb_net_ioctl(struct inode *inode, struct file *file,
return 0; return 0;
} }
static int
dvb_net_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg)
{
return dvb_usercopy(inode, file, cmd, arg, dvb_net_do_ioctl);
}
static struct file_operations dvb_net_fops = { static struct file_operations dvb_net_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.ioctl = dvb_generic_ioctl, .read = 0,
.open = dvb_generic_open, .write = 0,
.release = dvb_generic_release, .ioctl = dvb_net_ioctl,
.open = dvb_generic_open,
.release = dvb_generic_release,
.poll = 0,
}; };
static struct dvb_device dvbdev_net = { static struct dvb_device dvbdev_net = {
.priv = 0, .priv = 0,
.users = 1, .users = 1,
.writers = 1, .writers = 1,
.fops = &dvb_net_fops, .fops = &dvb_net_fops,
.kernel_ioctl = dvb_net_ioctl,
}; };
void void
dvb_net_release(dvb_net_t *dvbnet) dvb_net_release(struct dvb_net *dvbnet)
{ {
int i; int i;
...@@ -490,15 +569,19 @@ dvb_net_release(dvb_net_t *dvbnet) ...@@ -490,15 +569,19 @@ dvb_net_release(dvb_net_t *dvbnet)
} }
int int
dvb_net_init(struct dvb_adapter *adap, dvb_net_t *dvbnet, dmx_demux_t *demux) dvb_net_init(struct dvb_adapter *adap, struct dvb_net *dvbnet, dmx_demux_t *dmx)
{ {
int i; int i;
dvbnet->demux=demux; dvbnet->demux = dmx;
dvbnet->dev_num=DVB_NET_DEVICES_MAX; dvbnet->dev_num = DVB_NET_DEVICES_MAX;
for (i=0; i<dvbnet->dev_num; i++) for (i=0; i<dvbnet->dev_num; i++)
dvbnet->state[i]=0; dvbnet->state[i] = 0;
dvb_register_device(adap, &dvbnet->dvbdev, &dvbdev_net, dvbnet, DVB_DEVICE_NET);
dvb_register_device (adap, &dvbnet->dvbdev, &dvbdev_net,
dvbnet, DVB_DEVICE_NET);
return 0; return 0;
} }
...@@ -32,23 +32,9 @@ ...@@ -32,23 +32,9 @@
#include "dvbdev.h" #include "dvbdev.h"
#define DVB_NET_DEVICES_MAX 10 #define DVB_NET_DEVICES_MAX 10
#define DVB_NET_MULTICAST_MAX 10
typedef struct dvb_net_priv_s {
struct net_device_stats stats;
char name[6];
u16 pid;
dmx_demux_t *demux;
dmx_section_feed_t *secfeed;
dmx_section_filter_t *secfilter;
int multi_num;
dmx_section_filter_t *multi_secfilter[DVB_NET_MULTICAST_MAX];
unsigned char multi_macs[DVB_NET_MULTICAST_MAX][6];
} dvb_net_priv_t;
typedef struct dvb_net_s {
struct dvb_device *dvbdev;
typedef struct dvb_net {
struct dvb_device *dvbdev;
int card_num; int card_num;
int dev_num; int dev_num;
struct net_device device[DVB_NET_DEVICES_MAX]; struct net_device device[DVB_NET_DEVICES_MAX];
...@@ -57,7 +43,8 @@ typedef struct dvb_net_s { ...@@ -57,7 +43,8 @@ typedef struct dvb_net_s {
} dvb_net_t; } dvb_net_t;
void dvb_net_release(dvb_net_t *); void dvb_net_release(struct dvb_net *);
int dvb_net_init(struct dvb_adapter *, dvb_net_t *, dmx_demux_t *); int dvb_net_init(struct dvb_adapter *, struct dvb_net *, dmx_demux_t *);
#endif #endif
/*
*
* dvb_ringbuffer.c: ring buffer implementation for the dvb driver
*
* Copyright (C) 2003 Oliver Endriss
*
* based on code originally found in av7110.c:
* Copyright (C) 1999-2002 Ralph Metzler
* & Marcus Metzler for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
* the project's page is at http://www.linuxtv.org/dvb/
*/
#define __KERNEL_SYSCALLS__
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include "dvb_ringbuffer.h"
void dvb_ringbuffer_init(dvb_ringbuffer_t *rbuf, void *data, size_t len)
{
rbuf->pread=rbuf->pwrite=0;
rbuf->data=data;
rbuf->size=len;
init_waitqueue_head(&rbuf->queue);
spin_lock_init(&(rbuf->lock));
rbuf->lock=SPIN_LOCK_UNLOCKED;
}
int dvb_ringbuffer_empty(dvb_ringbuffer_t *rbuf)
{
return (rbuf->pread==rbuf->pwrite);
}
ssize_t dvb_ringbuffer_free(dvb_ringbuffer_t *rbuf)
{
ssize_t free;
free = rbuf->pread - rbuf->pwrite;
if (free <= 0)
free += rbuf->size;
return free-1;
}
ssize_t dvb_ringbuffer_avail(dvb_ringbuffer_t *rbuf)
{
ssize_t avail;
avail = rbuf->pwrite - rbuf->pread;
if (avail < 0)
avail += rbuf->size;
return avail;
}
void dvb_ringbuffer_flush(dvb_ringbuffer_t *rbuf)
{
rbuf->pread = rbuf->pwrite;
}
void dvb_ringbuffer_flush_spinlock_wakeup(dvb_ringbuffer_t *rbuf)
{
unsigned long flags;
spin_lock_irqsave(&rbuf->lock, flags);
dvb_ringbuffer_flush(rbuf);
spin_unlock_irqrestore(&rbuf->lock, flags);
wake_up(&rbuf->queue);
}
ssize_t dvb_ringbuffer_read(dvb_ringbuffer_t *rbuf, u8 *buf, size_t len, int usermem)
{
size_t todo = len;
size_t split;
split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
if (split > 0) {
if (!usermem)
memcpy(buf, rbuf->data+rbuf->pread, split);
else
if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
return -EFAULT;
buf += split;
todo -= split;
rbuf->pread = 0;
}
if (!usermem)
memcpy(buf, rbuf->data+rbuf->pread, todo);
else
if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
return -EFAULT;
rbuf->pread = (rbuf->pread + len) % rbuf->size;
return len;
}
ssize_t dvb_ringbuffer_write(dvb_ringbuffer_t *rbuf, const u8 *buf,
size_t len, int usermem)
{
size_t todo = len;
size_t split;
split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
if (split > 0) {
if (!usermem)
memcpy(rbuf->data+rbuf->pwrite, buf, split);
else
if (copy_from_user(rbuf->data+rbuf->pwrite,
buf, split))
return -EFAULT;
buf += split;
todo -= split;
rbuf->pwrite = 0;
}
if (!usermem)
memcpy(rbuf->data+rbuf->pwrite, buf, todo);
else
if (copy_from_user(rbuf->data+rbuf->pwrite, buf, todo))
return -EFAULT;
rbuf->pwrite = (rbuf->pwrite + len) % rbuf->size;
return len;
}
EXPORT_SYMBOL_GPL(dvb_ringbuffer_init);
EXPORT_SYMBOL_GPL(dvb_ringbuffer_empty);
EXPORT_SYMBOL_GPL(dvb_ringbuffer_free);
EXPORT_SYMBOL_GPL(dvb_ringbuffer_avail);
EXPORT_SYMBOL_GPL(dvb_ringbuffer_flush);
EXPORT_SYMBOL_GPL(dvb_ringbuffer_flush_spinlock_wakeup);
EXPORT_SYMBOL_GPL(dvb_ringbuffer_read);
EXPORT_SYMBOL_GPL(dvb_ringbuffer_write);
/*
*
* dvb_ringbuffer.h: ring buffer implementation for the dvb driver
*
* Copyright (C) 2003 Oliver Endriss
*
* based on code originally found in av7110.c:
* Copyright (C) 1999-2002 Ralph Metzler
* & Marcus Metzler for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
* the project's page is at http://www.linuxtv.org/dvb/
*/
#ifndef _DVB_RINGBUFFER_H_
#define _DVB_RINGBUFFER_H_
typedef struct dvb_ringbuffer {
u8 *data;
ssize_t size;
ssize_t pread;
ssize_t pwrite;
wait_queue_head_t queue;
spinlock_t lock;
} dvb_ringbuffer_t;
/*
** Notes:
** ------
** (1) For performance reasons read and write routines don't check buffer sizes
** and/or number of bytes free/available. This has to be done before these
** routines are called. For example:
**
** *** write <buflen> bytes ***
** free = dvb_ringbuffer_free(rbuf);
** if (free >= buflen)
** count = dvb_ringbuffer_write(rbuf, buffer, buflen, 0);
** else
** ...
**
** *** read min. 1000, max. <bufsize> bytes ***
** avail = dvb_ringbuffer_avail(rbuf);
** if (avail >= 1000)
** count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize), 0);
** else
** ...
**
** (2) If there is exactly one reader and one writer, there is no need
** to lock read or write operations.
** Two or more readers must be locked against each other.
** Flushing the buffer counts as a read operation.
** Two or more writers must be locked against each other.
*/
/* initialize ring buffer, lock and queue */
extern void dvb_ringbuffer_init(dvb_ringbuffer_t *rbuf, void *data, size_t len);
/* test whether buffer is empty */
extern int dvb_ringbuffer_empty(dvb_ringbuffer_t *rbuf);
/* return the number of free bytes in the buffer */
extern ssize_t dvb_ringbuffer_free(dvb_ringbuffer_t *rbuf);
/* return the number of bytes waiting in the buffer */
extern ssize_t dvb_ringbuffer_avail(dvb_ringbuffer_t *rbuf);
/* read routines & macros */
/* ---------------------- */
/* flush buffer */
extern void dvb_ringbuffer_flush(dvb_ringbuffer_t *rbuf);
/* flush buffer protected by spinlock and wake-up waiting task(s) */
extern void dvb_ringbuffer_flush_spinlock_wakeup(dvb_ringbuffer_t *rbuf);
/* peek at byte <offs> in the buffer */
#define DVB_RINGBUFFER_PEEK(rbuf,offs) \
(rbuf)->data[((rbuf)->pread+(offs))%(rbuf)->size]
/* advance read ptr by <num> bytes */
#define DVB_RINGBUFFER_SKIP(rbuf,num) \
(rbuf)->pread=((rbuf)->pread+(num))%(rbuf)->size
/*
** read <len> bytes from ring buffer into <buf>
** <usermem> specifies whether <buf> resides in user space
** returns number of bytes transferred or -EFAULT
*/
extern ssize_t dvb_ringbuffer_read(dvb_ringbuffer_t *rbuf, u8 *buf,
size_t len, int usermem);
/* write routines & macros */
/* ----------------------- */
/* write single byte to ring buffer */
#define DVB_RINGBUFFER_WRITE_BYTE(rbuf,byte) \
{ (rbuf)->data[(rbuf)->pwrite]=(byte); \
(rbuf)->pwrite=((rbuf)->pwrite+1)%(rbuf)->size; }
/*
** write <len> bytes to ring buffer
** <usermem> specifies whether <buf> resides in user space
** returns number of bytes transferred or -EFAULT
*/
extern ssize_t dvb_ringbuffer_write(dvb_ringbuffer_t *rbuf, const u8 *buf,
size_t len, int usermem);
#endif /* _DVB_RINGBUFFER_H_ */
...@@ -35,11 +35,13 @@ ...@@ -35,11 +35,13 @@
#include <asm/system.h> #include <asm/system.h>
#include <linux/kmod.h> #include <linux/kmod.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/videodev.h>
#include "compat.h"
#include "dvbdev.h" #include "dvbdev.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51)
#include "compat.h"
#endif
static int dvbdev_debug = 0; static int dvbdev_debug = 0;
#define dprintk if (dvbdev_debug) printk #define dprintk if (dvbdev_debug) printk
...@@ -57,7 +59,6 @@ static char *dnames[] = { ...@@ -57,7 +59,6 @@ static char *dnames[] = {
#define DVB_MAX_IDS 4 #define DVB_MAX_IDS 4
#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type) #define nums2minor(num,type,id) ((num << 6) | (id << 4) | type)
static static
struct dvb_device* dvbdev_find_device (int minor) struct dvb_device* dvbdev_find_device (int minor)
{ {
...@@ -160,7 +161,7 @@ int dvb_generic_ioctl(struct inode *inode, struct file *file, ...@@ -160,7 +161,7 @@ int dvb_generic_ioctl(struct inode *inode, struct file *file,
if (!dvbdev->kernel_ioctl) if (!dvbdev->kernel_ioctl)
return -EINVAL; return -EINVAL;
return video_usercopy (inode, file, cmd, arg, dvbdev->kernel_ioctl); return dvb_usercopy (inode, file, cmd, arg, dvbdev->kernel_ioctl);
} }
...@@ -267,7 +268,7 @@ int dvbdev_get_free_adapter_num (void) ...@@ -267,7 +268,7 @@ int dvbdev_get_free_adapter_num (void)
} }
int dvb_register_adapter(struct dvb_adapter **padap, char *name) int dvb_register_adapter(struct dvb_adapter **padap, const char *name)
{ {
struct dvb_adapter *adap; struct dvb_adapter *adap;
int num; int num;
...@@ -288,12 +289,14 @@ int dvb_register_adapter(struct dvb_adapter **padap, char *name) ...@@ -288,12 +289,14 @@ int dvb_register_adapter(struct dvb_adapter **padap, char *name)
memset (adap, 0, sizeof(struct dvb_adapter)); memset (adap, 0, sizeof(struct dvb_adapter));
INIT_LIST_HEAD (&adap->device_list); INIT_LIST_HEAD (&adap->device_list);
MOD_INC_USE_COUNT; /* fixme: is this correct? */
try_module_get(THIS_MODULE);
printk ("DVB: registering new adapter (%s).\n", name); printk ("DVB: registering new adapter (%s).\n", name);
adap->devfs_handle = devfs_mk_dir("dvb/adapter%d", num); adap->devfs_handle = devfs_mk_dir("dvb/adapter%d", num);
adap->num = num; adap->num = num;
adap->name = name;
list_add_tail (&adap->list_head, &dvb_adapter_list); list_add_tail (&adap->list_head, &dvb_adapter_list);
...@@ -311,7 +314,8 @@ int dvb_unregister_adapter(struct dvb_adapter *adap) ...@@ -311,7 +314,8 @@ int dvb_unregister_adapter(struct dvb_adapter *adap)
list_del (&adap->list_head); list_del (&adap->list_head);
up (&dvbdev_register_lock); up (&dvbdev_register_lock);
kfree (adap); kfree (adap);
MOD_DEC_USE_COUNT; /* fixme: is this correct? */
module_put(THIS_MODULE);
return 0; return 0;
} }
......
...@@ -48,6 +48,7 @@ struct dvb_adapter { ...@@ -48,6 +48,7 @@ struct dvb_adapter {
devfs_handle_t devfs_handle; devfs_handle_t devfs_handle;
struct list_head list_head; struct list_head list_head;
struct list_head device_list; struct list_head device_list;
const char *name;
}; };
...@@ -63,14 +64,14 @@ struct dvb_device { ...@@ -63,14 +64,14 @@ struct dvb_device {
int writers; int writers;
/* don't really need those !? -- FIXME: use video_usercopy */ /* don't really need those !? -- FIXME: use video_usercopy */
int (*kernel_ioctl)(struct inode *inode, struct file *file, int (*kernel_ioctl)(struct inode *inode, struct file *file,
unsigned int cmd, void *arg); unsigned int cmd, void *arg);
void *priv; void *priv;
}; };
extern int dvb_register_adapter (struct dvb_adapter **padap, char *name); extern int dvb_register_adapter (struct dvb_adapter **padap, const char *name);
extern int dvb_unregister_adapter (struct dvb_adapter *adap); extern int dvb_unregister_adapter (struct dvb_adapter *adap);
extern int dvb_register_device (struct dvb_adapter *adap, extern int dvb_register_device (struct dvb_adapter *adap,
...@@ -84,7 +85,10 @@ extern void dvb_unregister_device (struct dvb_device *dvbdev); ...@@ -84,7 +85,10 @@ extern void dvb_unregister_device (struct dvb_device *dvbdev);
extern int dvb_generic_open (struct inode *inode, struct file *file); extern int dvb_generic_open (struct inode *inode, struct file *file);
extern int dvb_generic_release (struct inode *inode, struct file *file); extern int dvb_generic_release (struct inode *inode, struct file *file);
extern int dvb_generic_ioctl (struct inode *inode, struct file *file, extern int dvb_generic_ioctl (struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg); unsigned int cmd, unsigned long arg);
int dvb_usercopy(struct inode *inode, struct file *file,
unsigned int cmd, unsigned long arg,
int (*func)(struct inode *inode, struct file *file,
unsigned int cmd, void *arg));
#endif /* #ifndef _DVBDEV_H_ */ #endif /* #ifndef _DVBDEV_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment