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 @@
#
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) += crc32.o
......@@ -144,6 +144,14 @@ struct dmx_section_feed_s {
int is_filtering; /* Set to non-zero when filtering in progress */
struct dmx_demux_s* parent; /* Back-pointer */
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,
__u16 pid,
size_t circular_buffer_size,
......@@ -162,16 +170,16 @@ typedef struct dmx_section_feed_s dmx_section_feed_t;
/* Callback functions */
/*--------------------------------------------------------------------------*/
typedef int (*dmx_ts_cb) ( __u8 * buffer1,
typedef int (*dmx_ts_cb) ( const u8 * buffer1,
size_t buffer1_length,
__u8 * buffer2,
const u8 * buffer2,
size_t buffer2_length,
dmx_ts_feed_t* source,
dmx_success_t success);
typedef int (*dmx_section_cb) ( __u8 * buffer1,
typedef int (*dmx_section_cb) ( const u8 * buffer1,
size_t buffer1_len,
__u8 * buffer2,
const u8 * buffer2,
size_t buffer2_len,
dmx_section_filter_t * source,
dmx_success_t success);
......@@ -278,6 +286,9 @@ struct dmx_demux_s {
int (*disconnect_frontend) (struct dmx_demux_s* demux);
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;
......
......@@ -24,11 +24,13 @@
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/videodev.h>
#include <asm/uaccess.h>
#include "dmxdev.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51)
#include "compat.h"
#endif
//MODULE_DESCRIPTION("");
//MODULE_AUTHOR("Ralph Metzler, Marcus Metzler");
......@@ -63,8 +65,8 @@ dvb_dmxdev_buffer_init(dmxdev_buffer_t *buffer)
init_waitqueue_head(&buffer->queue);
}
static inline int
dvb_dmxdev_buffer_write(dmxdev_buffer_t *buf, uint8_t *src, int len)
static inline
int dvb_dmxdev_buffer_write(dmxdev_buffer_t *buf, const u8 *src, int len)
{
int split;
int free;
......@@ -356,10 +358,9 @@ dvb_dmxdev_filter_timer(dmxdev_filter_t *dmxdevfilter)
}
static int
dvb_dmxdev_section_callback(u8 *buffer1, size_t buffer1_len,
u8 *buffer2, size_t buffer2_len,
dmx_section_filter_t *filter,
dmx_success_t success)
dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
const u8 *buffer2, size_t buffer2_len,
dmx_section_filter_t *filter, dmx_success_t success)
{
dmxdev_filter_t *dmxdevfilter=(dmxdev_filter_t *) filter->priv;
int ret;
......@@ -394,10 +395,9 @@ dvb_dmxdev_section_callback(u8 *buffer1, size_t buffer1_len,
}
static int
dvb_dmxdev_ts_callback(u8 *buffer1, size_t buffer1_len,
u8 *buffer2, size_t buffer2_len,
dmx_ts_feed_t *feed,
dmx_success_t success)
dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
const u8 *buffer2, size_t buffer2_len,
dmx_ts_feed_t *feed, dmx_success_t success)
{
dmxdev_filter_t *dmxdevfilter=(dmxdev_filter_t *) feed->priv;
dmxdev_buffer_t *buffer;
......@@ -455,21 +455,22 @@ dvb_dmxdev_feed_stop(dmxdev_filter_t *dmxdevfilter)
/* start feed associated with the specified filter */
static int
dvb_dmxdev_feed_start(dmxdev_filter_t *dmxdevfilter)
static
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:
dmxdevfilter->feed.sec->start_filtering(dmxdevfilter->feed.sec);
return filter->feed.sec->start_filtering(filter->feed.sec);
break;
case DMXDEV_TYPE_PES:
dmxdevfilter->feed.ts->start_filtering(dmxdevfilter->feed.ts);
return filter->feed.ts->start_filtering(filter->feed.ts);
break;
default:
return -EINVAL;
}
return 0;
}
......@@ -477,12 +478,12 @@ dvb_dmxdev_feed_start(dmxdev_filter_t *dmxdevfilter)
/* restart section feed if it has filters left associated with it,
otherwise release the feed */
static int
dvb_dmxdev_feed_restart(dmxdev_filter_t *dmxdevfilter)
static
int dvb_dmxdev_feed_restart(dmxdev_filter_t *filter)
{
int i;
dmxdev_t *dmxdev=dmxdevfilter->dev;
uint16_t pid=dmxdevfilter->params.sec.pid;
dmxdev_t *dmxdev = filter->dev;
uint16_t pid = filter->params.sec.pid;
for (i=0; i<dmxdev->filternum; i++)
if (dmxdev->filter[i].state>=DMXDEV_STATE_GO &&
......@@ -492,9 +493,7 @@ dvb_dmxdev_feed_restart(dmxdev_filter_t *dmxdevfilter)
return 0;
}
dmxdevfilter->dev->demux->
release_section_feed(dmxdev->demux,
dmxdevfilter->feed.sec);
filter->dev->demux->release_section_feed(dmxdev->demux, filter->feed.sec);
return 0;
}
......@@ -548,48 +547,48 @@ dvb_dmxdev_filter_reset(dmxdev_filter_t *dmxdevfilter)
}
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;
int ret, i;
if (dmxdevfilter->state<DMXDEV_STATE_SET)
if (filter->state < DMXDEV_STATE_SET)
return -EINVAL;
if (dmxdevfilter->state>=DMXDEV_STATE_GO)
dvb_dmxdev_filter_stop(dmxdevfilter);
mem=dmxdevfilter->buffer.data;
if (!mem) {
mem=vmalloc(dmxdevfilter->buffer.size);
spin_lock_irq(&dmxdevfilter->dev->lock);
dmxdevfilter->buffer.data=mem;
spin_unlock_irq(&dmxdevfilter->dev->lock);
if (!dmxdevfilter->buffer.data)
if (filter->state >= DMXDEV_STATE_GO)
dvb_dmxdev_filter_stop(filter);
if (!(mem = filter->buffer.data)) {
mem = vmalloc(filter->buffer.size);
spin_lock_irq(&filter->dev->lock);
filter->buffer.data=mem;
spin_unlock_irq(&filter->dev->lock);
if (!filter->buffer.data)
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:
{
struct dmx_sct_filter_params *para=&dmxdevfilter->params.sec;
dmx_section_filter_t **secfilter=&dmxdevfilter->filter.sec;
dmx_section_feed_t **secfeed=&dmxdevfilter->feed.sec;
struct dmx_sct_filter_params *para=&filter->params.sec;
dmx_section_filter_t **secfilter=&filter->filter.sec;
dmx_section_feed_t **secfeed=&filter->feed.sec;
*secfilter=0;
*secfeed=0;
/* find active filter/feed with same PID */
for (i=0; i<dmxdev->filternum; i++)
if (dmxdev->filter[i].state>=DMXDEV_STATE_GO &&
dmxdev->filter[i].pid==para->pid) {
if (dmxdev->filter[i].type!=DMXDEV_TYPE_SEC)
return -EBUSY;
*secfeed=dmxdev->filter[i].feed.sec;
for (i=0; i<dmxdev->filternum; i++) {
if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
dmxdev->filter[i].pid == para->pid &&
dmxdev->filter[i].type == DMXDEV_TYPE_SEC) {
*secfeed = dmxdev->filter[i].feed.sec;
break;
}
}
/* if no feed found, try to allocate new one */
if (!*secfeed) {
......@@ -608,22 +607,23 @@ dvb_dmxdev_filter_start(dmxdev_filter_t *dmxdevfilter)
if (ret<0) {
printk ("DVB (%s): could not set feed\n",
__FUNCTION__);
dvb_dmxdev_feed_restart(dmxdevfilter);
dvb_dmxdev_feed_restart(filter);
return ret;
}
} else {
dvb_dmxdev_feed_stop(filter);
}
else
dvb_dmxdev_feed_stop(dmxdevfilter);
ret=(*secfeed)->allocate_filter(*secfeed, secfilter);
if (ret<0) {
dvb_dmxdev_feed_restart(dmxdevfilter);
dmxdevfilter->feed.sec->start_filtering(*secfeed);
if (ret < 0) {
dvb_dmxdev_feed_restart(filter);
filter->feed.sec->start_filtering(*secfeed);
dprintk ("could not get filter\n");
return ret;
}
(*secfilter)->priv=(void *) dmxdevfilter;
(*secfilter)->priv = filter;
memcpy(&((*secfilter)->filter_value[3]),
&(para->filter.filter[1]), DMX_FILTER_SIZE-1);
......@@ -638,23 +638,28 @@ dvb_dmxdev_filter_start(dmxdev_filter_t *dmxdevfilter)
(*secfilter)->filter_mask[1]=0;
(*secfilter)->filter_mask[2]=0;
dmxdevfilter->todo=0;
dmxdevfilter->feed.sec->start_filtering(dmxdevfilter->feed.sec);
dvb_dmxdev_filter_timer(dmxdevfilter);
filter->todo = 0;
ret = filter->feed.sec->start_filtering (filter->feed.sec);
if (ret < 0)
return ret;
dvb_dmxdev_filter_timer(filter);
break;
}
case DMXDEV_TYPE_PES:
{
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;
int ret;
int ts_type;
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;
ts_pes=(dmx_ts_pes_t) para->pes_type;
......@@ -664,11 +669,11 @@ dvb_dmxdev_filter_start(dmxdev_filter_t *dmxdevfilter)
else
ts_type=0;
if (otype==DMX_OUT_TS_TAP)
ts_type|=TS_PACKET;
if (otype == DMX_OUT_TS_TAP)
ts_type |= TS_PACKET;
if (otype==DMX_OUT_TAP)
ts_type|=TS_PAYLOAD_ONLY|TS_PACKET;
if (otype == DMX_OUT_TAP)
ts_type |= TS_PAYLOAD_ONLY|TS_PACKET;
ret=dmxdev->demux->allocate_ts_feed(dmxdev->demux,
tsfeed,
......@@ -676,19 +681,28 @@ dvb_dmxdev_filter_start(dmxdev_filter_t *dmxdevfilter)
if (ret<0)
return ret;
(*tsfeed)->priv=(void *) dmxdevfilter;
ret=(*tsfeed)->set(*tsfeed, para->pid, ts_type, ts_pes, 188, 32768, 0, timeout);
if (ret<0) {
(*tsfeed)->priv = (void *) filter;
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);
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;
}
default:
return -EINVAL;
}
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_GO);
dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
return 0;
}
......@@ -701,16 +715,21 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
if (!dmxdev->filter)
return -EINVAL;
if (down_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
for (i=0; i<dmxdev->filternum; i++)
if (dmxdev->filter[i].state==DMXDEV_STATE_FREE)
break;
if (i==dmxdev->filternum) {
up(&dmxdev->mutex);
return -EMFILE;
}
dmxdevfilter=&dmxdev->filter[i];
sema_init(&dmxdevfilter->mutex, 1);
dmxdevfilter->dvbdev=dmxdev->dvbdev;
file->private_data=dmxdevfilter;
......@@ -724,12 +743,18 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
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))
return -ERESTARTSYS;
if (down_interruptible(&dmxdevfilter->mutex)) {
up(&dmxdev->mutex);
return -ERESTARTSYS;
}
dvb_dmxdev_filter_stop(dmxdevfilter);
dvb_dmxdev_filter_reset(dmxdevfilter);
......@@ -741,8 +766,10 @@ dvb_dmxdev_filter_free(dmxdev_t *dmxdev, dmxdev_filter_t *dmxdevfilter)
spin_unlock_irq(&dmxdev->lock);
vfree(mem);
}
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE);
wake_up(&dmxdevfilter->buffer.queue);
up(&dmxdevfilter->mutex);
up(&dmxdev->mutex);
return 0;
}
......@@ -845,18 +872,19 @@ ssize_t
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_t *dmxdev=dmxdevfilter->dev;
int ret=0;
// semaphore should not be necessary (I hope ...)
//down(&dmxdev->mutex);
if (down_interruptible(&dmxdevfilter->mutex))
return -ERESTARTSYS;
if (dmxdevfilter->type==DMXDEV_TYPE_SEC)
ret=dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
else
ret=dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
file->f_flags&O_NONBLOCK,
buf, count, ppos);
//up(&dmxdev->mutex);
up(&dmxdevfilter->mutex);
return ret;
}
......@@ -874,28 +902,53 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
switch (cmd) {
case DMX_START:
if (down_interruptible(&dmxdevfilter->mutex)) {
up(&dmxdev->mutex);
return -ERESTARTSYS;
}
if (dmxdevfilter->state<DMXDEV_STATE_SET)
ret=-EINVAL;
ret = -EINVAL;
else
ret=dvb_dmxdev_filter_start(dmxdevfilter);
ret = dvb_dmxdev_filter_start(dmxdevfilter);
up(&dmxdevfilter->mutex);
break;
case DMX_STOP:
if (down_interruptible(&dmxdevfilter->mutex)) {
up(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret=dvb_dmxdev_filter_stop(dmxdevfilter);
up(&dmxdevfilter->mutex);
break;
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);
up(&dmxdevfilter->mutex);
break;
case DMX_SET_PES_FILTER:
if (down_interruptible(&dmxdevfilter->mutex)) {
up(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret=dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter,
(struct dmx_pes_filter_params *)parg);
up(&dmxdevfilter->mutex);
break;
case DMX_SET_BUFFER_SIZE:
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:
......@@ -909,6 +962,17 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
dmxdev->demux->get_pes_pids(dmxdev->demux, (uint16_t *)parg);
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:
ret=-EINVAL;
}
......@@ -919,47 +983,40 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
static int dvb_demux_ioctl(struct inode *inode, struct file *file,
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)
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);
if (dmxdevfilter->state==DMXDEV_STATE_FREE)
if (dmxdevfilter->state != DMXDEV_STATE_GO &&
dmxdevfilter->state != DMXDEV_STATE_DONE)
return 0;
if (dmxdevfilter->buffer.error)
return (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
if (dmxdevfilter->buffer.pread!=dmxdevfilter->buffer.pwrite)
return (POLLIN | POLLRDNORM | POLLPRI);
if (dmxdevfilter->buffer.pread != dmxdevfilter->buffer.pwrite)
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_t *dmxdev=dmxdevfilter->dev;
dmxdev_filter_t *dmxdevfilter = dvb_dmxdev_file_to_filter(file);
dmxdev_t *dmxdev = dmxdevfilter->dev;
return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
}
......@@ -1007,45 +1064,43 @@ static int dvb_dvr_do_ioctl(struct inode *inode, struct file *file,
static int dvb_dvr_ioctl(struct inode *inode, struct file *file,
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;
dmxdev_t *dmxdev=(dmxdev_t *) dvbdev->priv;
struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
dmxdev_t *dmxdev = (dmxdev_t *) dvbdev->priv;
unsigned int mask = 0;
dprintk ("function : %s\n", __FUNCTION__);
if ((file->f_flags&O_ACCMODE)==O_RDONLY) {
if (dmxdev->dvr_buffer.error)
return (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
if (dmxdev->dvr_buffer.pread!=dmxdev->dvr_buffer.pwrite)
return (POLLIN | POLLRDNORM | POLLPRI);
poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
if ((file->f_flags&O_ACCMODE) == O_RDONLY) {
if (dmxdev->dvr_buffer.error)
return (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
if (dmxdev->dvr_buffer.pread!=dmxdev->dvr_buffer.pwrite)
return (POLLIN | POLLRDNORM | POLLPRI);
return 0;
mask |= (POLLIN | POLLRDNORM | POLLPRI);
} 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,
.read = dvb_dvr_read,
.write = dvb_dvr_write,
.ioctl = dvb_dvr_ioctl,
.open = dvb_dvr_open,
.release = dvb_dvr_release,
.poll =dvb_dvr_poll,
.poll = dvb_dvr_poll,
};
static struct dvb_device dvbdev_dvr = {
......@@ -1088,7 +1143,8 @@ dvb_dmxdev_init(dmxdev_t *dmxdev, struct dvb_adapter *dvb_adapter)
dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr, dmxdev, DVB_DEVICE_DVR);
dvb_dmxdev_buffer_init(&dmxdev->dvr_buffer);
MOD_INC_USE_COUNT;
/* fixme: is this correct? */
try_module_get(THIS_MODULE);
return 0;
}
......@@ -1106,7 +1162,8 @@ dvb_dmxdev_release(dmxdev_t *dmxdev)
dmxdev->dvr=0;
}
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 {
struct dmxdev_s *dev;
dmxdev_buffer_t buffer;
struct semaphore mutex;
// only for sections
struct timer_list timer;
int todo;
......
......@@ -27,27 +27,36 @@
#include <linux/version.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"
#define NOBUFS
LIST_HEAD(dmx_muxs);
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))
return -EINVAL;
list_for_each(pos, head)
{
list_for_each(pos, &dmx_muxs) {
if (!strcmp(DMX_DIR_ENTRY(pos)->id, demux->id))
return -EEXIST;
}
demux->users=0;
list_add(&(demux->reg_list), head);
MOD_INC_USE_COUNT;
demux->users = 0;
list_add(&demux->reg_list, &dmx_muxs);
/* fixme: is this correct? */
try_module_get(THIS_MODULE);
return 0;
}
......@@ -55,17 +64,17 @@ int dmx_unregister_demux(dmx_demux_t* demux)
{
struct list_head *pos, *n, *head=&dmx_muxs;
list_for_each_safe (pos, n, head)
{
if (DMX_DIR_ENTRY(pos)==demux)
{
list_for_each_safe (pos, n, head) {
if (DMX_DIR_ENTRY(pos) == demux) {
if (demux->users>0)
return -EINVAL;
list_del(pos);
MOD_DEC_USE_COUNT;
/* fixme: is this correct? */
module_put(THIS_MODULE);
return 0;
}
}
return -ENODEV;
}
......@@ -82,20 +91,23 @@ struct list_head *dmx_get_demuxes(void)
* 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];
}
static inline u16
ts_pid(const u8 *buf)
static inline
u16 ts_pid(const u8 *buf)
{
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?
return 0;
......@@ -109,71 +121,30 @@ payload(const u8 *tsp)
}
static u32
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)
void dvb_set_crc32(u8 *data, int length)
{
int i;
u32 crc = 0xffffffff;
u32 crc;
for (i=0; i<len; i++)
crc = (crc << 8) ^ dvb_crc_table[((crc >> 24) ^ *data++) & 0xff];
return crc;
crc = crc32_le(~0, data, length);
data[length] = (crc >> 24) & 0xff;
data[length+1] = (crc >> 16) & 0xff;
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;
data[length+1] = (crc>>16)&0xff;
data[length+2] = (crc>>8)&0xff;
data[length+3] = (crc)&0xff;
static
void dvb_dmx_memcopy (struct dvb_demux_feed *f, u8 *d, const u8 *s, size_t len)
{
memcpy (d, s, len);
}
......@@ -181,16 +152,19 @@ void dvb_set_crc32(u8 *data, int length)
* Software filter functions
******************************************************************************/
static inline int
dvb_dmx_swfilter_payload(struct dvb_demux_feed *dvbdmxfeed, const u8 *buf)
static inline
int dvb_dmx_swfilter_payload (struct dvb_demux_feed *feed, const u8 *buf)
{
int p, count;
int count = payload(buf);
int p;
//int ccok;
//u8 cc;
if (!(count=payload(buf)))
if (count == 0)
return -1;
p=188-count;
p = 188-count;
/*
cc=buf[3]&0x0f;
ccok=((dvbdmxfeed->cc+1)&0x0f)==cc ? 1 : 0;
......@@ -198,178 +172,223 @@ dvb_dmx_swfilter_payload(struct dvb_demux_feed *dvbdmxfeed, const u8 *buf)
if (!ccok)
printk("missed packet!\n");
*/
if (buf[1]&0x40) // PUSI ?
dvbdmxfeed->peslen=0xfffa;
dvbdmxfeed->peslen+=count;
return dvbdmxfeed->cb.ts((u8 *)&buf[p], count, 0, 0,
&dvbdmxfeed->feed.ts, DMX_OK);
if (buf[1] & 0x40) // PUSI ?
feed->peslen = 0xfffa;
feed->peslen += count;
return feed->cb.ts (&buf[p], count, 0, 0, &feed->feed.ts, DMX_OK);
}
static int
dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *dvbdmxfeed,
static
int dvb_dmx_swfilter_sectionfilter (struct dvb_demux_feed *feed,
struct dvb_demux_filter *f)
{
dmx_section_filter_t *filter=&f->filter;
u8 neq = 0;
int i;
u8 xor, neq=0;
for (i=0; i<DVB_DEMUX_MASK_MAX; i++) {
xor=filter->filter_value[i]^dvbdmxfeed->secbuf[i];
if (f->maskandmode[i]&xor)
u8 xor = f->filter.filter_value[i] ^ feed->feed.sec.secbuf[i];
if (f->maskandmode[i] & xor)
return 0;
neq|=f->maskandnotmode[i]&xor;
neq |= f->maskandnotmode[i] & xor;
}
if (f->doneq && !neq)
if (f->doneq & !neq)
return 0;
return dvbdmxfeed->cb.sec(dvbdmxfeed->secbuf, dvbdmxfeed->seclen,
0, 0, filter, DMX_OK);
return feed->cb.sec (feed->feed.sec.secbuf, feed->feed.sec.seclen,
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_filter *f;
struct dvb_demux *demux = feed->demux;
struct dvb_demux_filter *f = feed->filter;
dmx_section_feed_t *sec = &feed->feed.sec;
u8 *buf = sec->secbuf;
if (dvbdmxfeed->secbufp!=dvbdmxfeed->seclen)
if (sec->secbufp != sec->seclen)
return -1;
if (!dvbdmxfeed->feed.sec.is_filtering)
if (!sec->is_filtering)
return 0;
if (!(f=dvbdmxfeed->filter))
if (!f)
return 0;
do
if (dvb_dmx_swfilter_sectionfilter(dvbdmxfeed, f)<0)
if (sec->check_crc && demux->check_crc32(feed, sec->secbuf, sec->seclen))
return -1;
while ((f=f->next) && dvbdmxfeed->feed.sec.is_filtering);
dvbdmxfeed->secbufp=dvbdmxfeed->seclen=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)
{
struct dvb_demux *demux = feed->demux;
dmx_section_feed_t *sec = &feed->feed.sec;
int p, count;
int ccok, rest;
u8 cc;
if (!(count=payload(buf)))
if (!(count = payload(buf)))
return -1;
p=188-count;
cc=buf[3]&0x0f;
ccok=((dvbdmxfeed->cc+1)&0x0f)==cc ? 1 : 0;
dvbdmxfeed->cc=cc;
p = 188-count;
cc = buf[3] & 0x0f;
ccok = ((feed->cc+1) & 0x0f) == cc ? 1 : 0;
feed->cc = cc;
if (buf[1]&0x40) { // PUSI set
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
return -1;
if (buf[p] && ccok) { // rest of previous section?
// did we have enough data in last packet to calc length?
int tmp=3-dvbdmxfeed->secbufp;
if (tmp>0 && tmp!=3) {
if (p+tmp>=187)
int tmp = 3 - sec->secbufp;
if (tmp > 0 && tmp != 3) {
if (p + tmp >= 187)
return -1;
memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp,
demux->memcopy (feed, sec->secbuf+sec->secbufp,
buf+p+1, tmp);
dvbdmxfeed->seclen=section_length(dvbdmxfeed->secbuf);
if (dvbdmxfeed->seclen>4096)
sec->seclen = section_length(sec->secbuf);
if (sec->seclen > 4096)
return -1;
}
rest=dvbdmxfeed->seclen-dvbdmxfeed->secbufp;
if (rest==buf[p] && dvbdmxfeed->seclen) {
memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp,
rest = sec->seclen - sec->secbufp;
if (rest == buf[p] && sec->seclen) {
demux->memcopy (feed, sec->secbuf + sec->secbufp,
buf+p+1, buf[p]);
dvbdmxfeed->secbufp+=buf[p];
dvb_dmx_swfilter_section_feed(dvbdmxfeed);
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) {
p += buf[p] + 1; // skip rest of last section
count = 188 - p;
while (count) {
sec->crc_val = ~0;
if ((count>2) && // enough data to determine sec length?
((dvbdmxfeed->seclen=section_length(buf+p))<=count)) {
if (dvbdmxfeed->seclen>4096)
((sec->seclen = section_length(buf+p)) <= count)) {
if (sec->seclen>4096)
return -1;
memcpy(dvbdmxfeed->secbuf, buf+p,
dvbdmxfeed->seclen);
dvbdmxfeed->secbufp=dvbdmxfeed->seclen;
p+=dvbdmxfeed->seclen;
count=188-p;
dvb_dmx_swfilter_section_feed(dvbdmxfeed);
demux->memcopy (feed, sec->secbuf, buf+p,
sec->seclen);
sec->secbufp = sec->seclen;
p += sec->seclen;
count = 188 - p;
dvb_dmx_swfilter_section_feed(feed);
// filling bytes until packet end?
if (count && buf[p]==0xff)
count=0;
} else { // section continues to following TS packet
memcpy(dvbdmxfeed->secbuf, buf+p, count);
dvbdmxfeed->secbufp+=count;
demux->memcopy(feed, sec->secbuf, buf+p, count);
sec->secbufp+=count;
count=0;
}
}
return 0;
}
// section continued below
if (!ccok)
return -1;
if (!dvbdmxfeed->secbufp) // any data in last ts packet?
if (!sec->secbufp) // any data in last ts packet?
return -1;
// did we have enough data in last packet to calc section length?
if (dvbdmxfeed->secbufp<3) {
int tmp=3-dvbdmxfeed->secbufp;
if (sec->secbufp < 3) {
int tmp = 3 - sec->secbufp;
if (tmp>count)
return -1;
memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, buf+p, tmp);
dvbdmxfeed->seclen=section_length(dvbdmxfeed->secbuf);
if (dvbdmxfeed->seclen>4096)
sec->crc_val = ~0;
demux->memcopy (feed, sec->secbuf + sec->secbufp, buf+p, tmp);
sec->seclen = section_length(sec->secbuf);
if (sec->seclen > 4096)
return -1;
}
rest=dvbdmxfeed->seclen-dvbdmxfeed->secbufp;
if (rest<0)
rest = sec->seclen - sec->secbufp;
if (rest < 0)
return -1;
if (rest<=count) { // section completed in this TS packet
memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, buf+p, rest);
dvbdmxfeed->secbufp+=rest;
dvb_dmx_swfilter_section_feed(dvbdmxfeed);
if (rest <= count) { // section completed in this TS packet
demux->memcopy (feed, sec->secbuf + sec->secbufp, buf+p, rest);
sec->secbufp += rest;
dvb_dmx_swfilter_section_feed(feed);
} else { // section continues in following ts packet
memcpy(dvbdmxfeed->secbuf+dvbdmxfeed->secbufp, buf+p, count);
dvbdmxfeed->secbufp+=count;
demux->memcopy (feed, sec->secbuf + sec->secbufp, buf+p, count);
sec->secbufp += count;
}
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:
if (!dvbdmxfeed->feed.ts.is_filtering)
if (!feed->feed.ts.is_filtering)
break;
if (dvbdmxfeed->ts_type & TS_PACKET) {
if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)
dvb_dmx_swfilter_payload(dvbdmxfeed, buf);
if (feed->ts_type & TS_PACKET) {
if (feed->ts_type & TS_PAYLOAD_ONLY)
dvb_dmx_swfilter_payload(feed, buf);
else
dvbdmxfeed->cb.ts((u8 *)buf, 188, 0, 0,
&dvbdmxfeed->feed.ts, DMX_OK);
feed->cb.ts(buf, 188, 0, 0, &feed->feed.ts, DMX_OK);
}
if (dvbdmxfeed->ts_type & TS_DECODER)
if (dvbdmxfeed->demux->write_to_decoder)
dvbdmxfeed->demux->
write_to_decoder(dvbdmxfeed, (u8 *)buf, 188);
if (feed->ts_type & TS_DECODER)
if (feed->demux->write_to_decoder)
feed->demux->write_to_decoder(feed, buf, 188);
break;
case DMX_TYPE_SEC:
if (!dvbdmxfeed->feed.sec.is_filtering)
if (!feed->feed.sec.is_filtering)
break;
if (dvb_dmx_swfilter_section_packet(dvbdmxfeed, buf)<0)
dvbdmxfeed->seclen=dvbdmxfeed->secbufp=0;
if (dvb_dmx_swfilter_section_packet(feed, buf) < 0)
feed->feed.sec.seclen = feed->feed.sec.secbufp=0;
break;
default:
......@@ -377,59 +396,61 @@ dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *dvbdmxfeed, const u8 *buf)
}
}
void
dvb_dmx_swfilter_packet(struct dvb_demux *dvbdmx, const u8 *buf)
{
struct dvb_demux_feed *dvbdmxfeed;
if (!(dvbdmxfeed=dvbdmx->pid2feed[ts_pid(buf)]))
return;
dvb_dmx_swfilter_packet_type(dvbdmxfeed, buf);
void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *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);
if ((dvbdmxfeed=dvbdmx->pid2feed[0x2000]))
dvbdmxfeed->cb.ts((u8 *)buf, count*188, 0, 0,
&dvbdmxfeed->feed.ts, DMX_OK);
while (count) {
dvb_dmx_swfilter_packet(dvbdmx, buf);
count--;
buf+=188;
while (count--) {
dvb_dmx_swfilter_packet(demux, buf);
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 (count<(j=188-i)) {
memcpy(&dvbdmx->tsbuf[i], buf, count);
dvbdmx->tsbufp+=count;
if ((i = demux->tsbufp)) {
if (count < (j=188-i)) {
memcpy(&demux->tsbuf[i], buf, count);
demux->tsbufp += count;
return;
}
memcpy(&dvbdmx->tsbuf[i], buf, j);
dvb_dmx_swfilter_packet(dvbdmx, dvbdmx->tsbuf);
dvbdmx->tsbufp=0;
p+=j;
memcpy(&demux->tsbuf[i], buf, j);
dvb_dmx_swfilter_packet(demux, demux->tsbuf);
demux->tsbufp = 0;
p += j;
}
while (p<count) {
if (buf[p]==0x47) {
if (count-p>=188) {
dvb_dmx_swfilter_packet(dvbdmx, buf+p);
p+=188;
while (p < count) {
if (buf[p] == 0x47) {
if (count-p >= 188) {
dvb_dmx_swfilter_packet(demux, buf+p);
p += 188;
} else {
i=count-p;
memcpy(dvbdmx->tsbuf, buf+p, i);
dvbdmx->tsbufp=i;
i = count-p;
memcpy(demux->tsbuf, buf+p, i);
demux->tsbufp=i;
return;
}
} else
......@@ -438,271 +459,292 @@ dvb_dmx_swfilter(struct dvb_demux *dvbdmx, const u8 *buf, size_t count)
}
/******************************************************************************
******************************************************************************
* DVB DEMUX API LEVEL FUNCTIONS
******************************************************************************
******************************************************************************/
static struct dvb_demux_filter *
dvb_dmx_filter_alloc(struct dvb_demux *dvbdmx)
static
struct dvb_demux_filter* dvb_dmx_filter_alloc(struct dvb_demux *demux)
{
int i;
for (i=0; i<dvbdmx->filternum; i++)
if (dvbdmx->filter[i].state==DMX_STATE_FREE)
for (i=0; i<demux->filternum; i++)
if (demux->filter[i].state == DMX_STATE_FREE)
break;
if (i==dvbdmx->filternum)
return 0;
dvbdmx->filter[i].state=DMX_STATE_ALLOCATED;
return &dvbdmx->filter[i];
if (i == demux->filternum)
return NULL;
demux->filter[i].state = DMX_STATE_ALLOCATED;
return &demux->filter[i];
}
static struct dvb_demux_feed *
dvb_dmx_feed_alloc(struct dvb_demux *dvbdmx)
static
struct dvb_demux_feed* dvb_dmx_feed_alloc(struct dvb_demux *demux)
{
int i;
for (i=0; i<dvbdmx->feednum; i++)
if (dvbdmx->feed[i].state==DMX_STATE_FREE)
for (i=0; i<demux->feednum; i++)
if (demux->feed[i].state == DMX_STATE_FREE)
break;
if (i==dvbdmx->feednum)
return 0;
dvbdmx->feed[i].state=DMX_STATE_ALLOCATED;
return &dvbdmx->feed[i];
}
if (i == demux->feednum)
return NULL;
/******************************************************************************
* dmx_ts_feed API calls
******************************************************************************/
demux->feed[i].state = DMX_STATE_ALLOCATED;
static int
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_feed **pid2feed=dvbdmx->pid2feed;
struct dvb_demux *demux = feed->demux;
struct list_head *pos, *n, *head=&demux->feed_list;
if (pid>DMX_MAX_PID)
if (pid > DMX_MAX_PID)
return -EINVAL;
if (dvbdmxfeed->pid!=0xffff) {
if (dvbdmxfeed->pid<=DMX_MAX_PID)
pid2feed[dvbdmxfeed->pid]=0;
dvbdmxfeed->pid=0xffff;
}
if (pid2feed[pid]) {
return -EBUSY;
if (pid == feed->pid)
return 0;
if (feed->pid <= DMX_MAX_PID)
list_for_each_safe(pos, n, head)
if (DMX_FEED_ENTRY(pos)->pid == feed->pid) {
list_del(pos);
break;
}
pid2feed[pid]=dvbdmxfeed;
dvbdmxfeed->pid=pid;
list_add(&feed->list_head, head);
feed->pid = pid;
return 0;
}
static int
dmx_ts_feed_set(struct dmx_ts_feed_s* feed,
u16 pid,
int ts_type,
dmx_ts_pes_t pes_type,
size_t callback_length,
size_t circular_buffer_size,
int descramble,
struct timespec timeout
)
static
int dmx_ts_feed_set (struct dmx_ts_feed_s* ts_feed, u16 pid, int ts_type,
dmx_ts_pes_t pes_type, 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 *dvbdmx=dvbdmxfeed->demux;
struct dvb_demux_feed *feed = (struct dvb_demux_feed *) ts_feed;
struct dvb_demux *demux = feed->demux;
int ret;
if (down_interruptible (&dvbdmx->mutex))
if (down_interruptible (&demux->mutex))
return -ERESTARTSYS;
if (ts_type & TS_DECODER) {
if (pes_type >= DMX_TS_PES_OTHER) {
up(&dvbdmx->mutex);
up(&demux->mutex);
return -EINVAL;
}
if (dvbdmx->pesfilter[pes_type] &&
(dvbdmx->pesfilter[pes_type]!=dvbdmxfeed)) {
up(&dvbdmx->mutex);
if (demux->pesfilter[pes_type] &&
demux->pesfilter[pes_type] != feed) {
up(&demux->mutex);
return -EINVAL;
}
if ((pes_type != DMX_TS_PES_PCR0) &&
(pes_type != DMX_TS_PES_PCR1) &&
(pes_type != DMX_TS_PES_PCR2) &&
(pes_type != DMX_TS_PES_PCR3)) {
if ((ret=dmx_pid_set(pid, dvbdmxfeed))<0) {
up(&dvbdmx->mutex);
if ((ret = dmx_pid_set(pid, feed))<0) {
up(&demux->mutex);
return ret;
} else
dvbdmxfeed->pid=pid;
}
dvbdmx->pesfilter[pes_type]=dvbdmxfeed;
dvbdmx->pids[pes_type]=dvbdmxfeed->pid;
} else
if ((ret=dmx_pid_set(pid, dvbdmxfeed))<0) {
up(&dvbdmx->mutex);
feed->pid = pid;
demux->pesfilter[pes_type] = feed;
demux->pids[pes_type] = feed->pid;
} else {
if ((ret = dmx_pid_set(pid, feed))<0) {
up(&demux->mutex);
return ret;
}
}
dvbdmxfeed->buffer_size=circular_buffer_size;
dvbdmxfeed->descramble=descramble;
dvbdmxfeed->timeout=timeout;
dvbdmxfeed->cb_length=callback_length;
dvbdmxfeed->ts_type=ts_type;
dvbdmxfeed->pes_type=pes_type;
feed->buffer_size = circular_buffer_size;
feed->descramble = descramble;
feed->timeout = timeout;
feed->cb_length = callback_length;
feed->ts_type = ts_type;
feed->pes_type = pes_type;
if (dvbdmxfeed->descramble) {
up(&dvbdmx->mutex);
if (feed->descramble) {
up(&demux->mutex);
return -ENOSYS;
}
if (dvbdmxfeed->buffer_size) {
if (feed->buffer_size) {
#ifdef NOBUFS
dvbdmxfeed->buffer=0;
feed->buffer=0;
#else
dvbdmxfeed->buffer=vmalloc(dvbdmxfeed->buffer_size);
if (!dvbdmxfeed->buffer) {
up(&dvbdmx->mutex);
feed->buffer = vmalloc(feed->buffer_size);
if (!feed->buffer) {
up(&demux->mutex);
return -ENOMEM;
}
#endif
}
dvbdmxfeed->state=DMX_STATE_READY;
up(&dvbdmx->mutex);
feed->state = DMX_STATE_READY;
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 *dvbdmx=dvbdmxfeed->demux;
struct dvb_demux_feed *feed = (struct dvb_demux_feed *) ts_feed;
struct dvb_demux *demux = feed->demux;
int ret;
if (down_interruptible (&dvbdmx->mutex))
if (down_interruptible (&demux->mutex))
return -ERESTARTSYS;
if (dvbdmxfeed->state!=DMX_STATE_READY ||
dvbdmxfeed->type!=DMX_TYPE_TS) {
up(&dvbdmx->mutex);
if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) {
up(&demux->mutex);
return -EINVAL;
}
if (!dvbdmx->start_feed) {
up(&dvbdmx->mutex);
return -1;
if (!demux->start_feed) {
up(&demux->mutex);
return -ENODEV;
}
ret=dvbdmx->start_feed(dvbdmxfeed);
if (ret<0) {
up(&dvbdmx->mutex);
if ((ret = demux->start_feed(feed)) < 0) {
up(&demux->mutex);
return ret;
}
spin_lock_irq(&dvbdmx->lock);
feed->is_filtering=1;
dvbdmxfeed->state=DMX_STATE_GO;
spin_unlock_irq(&dvbdmx->lock);
up(&dvbdmx->mutex);
spin_lock_irq(&demux->lock);
ts_feed->is_filtering = 1;
feed->state = DMX_STATE_GO;
spin_unlock_irq(&demux->lock);
up(&demux->mutex);
return 0;
}
static int
dmx_ts_feed_stop_filtering(struct dmx_ts_feed_s* feed)
static
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 *dvbdmx=dvbdmxfeed->demux;
struct dvb_demux_feed *feed = (struct dvb_demux_feed *) ts_feed;
struct dvb_demux *demux = feed->demux;
int ret;
if (down_interruptible (&dvbdmx->mutex))
if (down_interruptible (&demux->mutex))
return -ERESTARTSYS;
if (dvbdmxfeed->state<DMX_STATE_GO) {
up(&dvbdmx->mutex);
if (feed->state<DMX_STATE_GO) {
up(&demux->mutex);
return -EINVAL;
}
if (!dvbdmx->stop_feed) {
up(&dvbdmx->mutex);
return -1;
if (!demux->stop_feed) {
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);
up(&dvbdmx->mutex);
ret = demux->stop_feed(feed);
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,
dmx_ts_feed_t **feed,
static
int dvbdmx_allocate_ts_feed (dmx_demux_t *dmx, dmx_ts_feed_t **ts_feed,
dmx_ts_cb callback)
{
struct dvb_demux *dvbdmx=(struct dvb_demux *) demux;
struct dvb_demux_feed *dvbdmxfeed;
struct dvb_demux *demux = (struct dvb_demux *) dmx;
struct dvb_demux_feed *feed;
if (down_interruptible (&dvbdmx->mutex))
if (down_interruptible (&demux->mutex))
return -ERESTARTSYS;
if (!(dvbdmxfeed=dvb_dmx_feed_alloc(dvbdmx))) {
up(&dvbdmx->mutex);
if (!(feed = dvb_dmx_feed_alloc(demux))) {
up(&demux->mutex);
return -EBUSY;
}
dvbdmxfeed->type=DMX_TYPE_TS;
dvbdmxfeed->cb.ts=callback;
dvbdmxfeed->demux=dvbdmx;
dvbdmxfeed->pid=0xffff;
dvbdmxfeed->peslen=0xfffa;
dvbdmxfeed->buffer=0;
(*feed)=&dvbdmxfeed->feed.ts;
(*feed)->is_filtering=0;
(*feed)->parent=demux;
(*feed)->priv=0;
(*feed)->set=dmx_ts_feed_set;
(*feed)->start_filtering=dmx_ts_feed_start_filtering;
(*feed)->stop_filtering=dmx_ts_feed_stop_filtering;
if (!(dvbdmxfeed->filter=dvb_dmx_filter_alloc(dvbdmx))) {
dvbdmxfeed->state=DMX_STATE_FREE;
up(&dvbdmx->mutex);
feed->type = DMX_TYPE_TS;
feed->cb.ts = callback;
feed->demux = demux;
feed->pid = 0xffff;
feed->peslen = 0xfffa;
feed->buffer = 0;
(*ts_feed) = &feed->feed.ts;
(*ts_feed)->is_filtering = 0;
(*ts_feed)->parent = dmx;
(*ts_feed)->priv = 0;
(*ts_feed)->set = dmx_ts_feed_set;
(*ts_feed)->start_filtering = dmx_ts_feed_start_filtering;
(*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering;
if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
feed->state = DMX_STATE_FREE;
up(&demux->mutex);
return -EBUSY;
}
dvbdmxfeed->filter->type=DMX_TYPE_TS;
dvbdmxfeed->filter->feed=dvbdmxfeed;
dvbdmxfeed->filter->state=DMX_STATE_READY;
feed->filter->type = DMX_TYPE_TS;
feed->filter->feed = feed;
feed->filter->state = DMX_STATE_READY;
up(&demux->mutex);
up(&dvbdmx->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_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed;
struct dvb_demux *demux = (struct dvb_demux *) dmx;
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;
if (dvbdmxfeed->state==DMX_STATE_FREE) {
up(&dvbdmx->mutex);
if (feed->state == DMX_STATE_FREE) {
up(&demux->mutex);
return -EINVAL;
}
#ifndef NOBUFS
if (dvbdmxfeed->buffer) {
vfree(dvbdmxfeed->buffer);
dvbdmxfeed->buffer=0;
if (feed->buffer) {
vfree(feed->buffer);
feed->buffer=0;
}
#endif
dvbdmxfeed->state=DMX_STATE_FREE;
dvbdmxfeed->filter->state=DMX_STATE_FREE;
if (dvbdmxfeed->pid<=DMX_MAX_PID) {
dvbdmxfeed->demux->pid2feed[dvbdmxfeed->pid]=0;
dvbdmxfeed->pid=0xffff;
feed->state = DMX_STATE_FREE;
feed->filter->state = DMX_STATE_FREE;
if (feed->pid <= DMX_MAX_PID) {
list_for_each_safe(pos, n, head)
if (DMX_FEED_ENTRY(pos)->pid == feed->pid) {
list_del(pos);
break;
}
feed->pid = 0xffff;
}
up(&dvbdmx->mutex);
if (feed->ts_type & TS_DECODER)
demux->pesfilter[feed->pes_type] = NULL;
up(&demux->mutex);
return 0;
}
......@@ -749,6 +791,7 @@ dmx_section_feed_set(struct dmx_section_feed_s* feed,
{
struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed;
struct dvb_demux *dvbdmx=dvbdmxfeed->demux;
struct list_head *pos, *n, *head=&dvbdmx->feed_list;
if (pid>0x1fff)
return -EINVAL;
......@@ -756,15 +799,14 @@ dmx_section_feed_set(struct dmx_section_feed_s* feed,
if (down_interruptible (&dvbdmx->mutex))
return -ERESTARTSYS;
if (dvbdmxfeed->pid!=0xffff) {
dvbdmx->pid2feed[dvbdmxfeed->pid]=0;
dvbdmxfeed->pid=0xffff;
}
if (dvbdmx->pid2feed[pid]) {
up(&dvbdmx->mutex);
return -EBUSY;
if (dvbdmxfeed->pid <= DMX_MAX_PID)
list_for_each_safe(pos, n, head)
if (DMX_FEED_ENTRY(pos)->pid == dvbdmxfeed->pid) {
list_del(pos);
break;
}
dvbdmx->pid2feed[pid]=dvbdmxfeed;
list_add(&dvbdmxfeed->list_head, head);
dvbdmxfeed->pid=pid;
dvbdmxfeed->buffer_size=circular_buffer_size;
......@@ -774,7 +816,7 @@ dmx_section_feed_set(struct dmx_section_feed_s* feed,
return -ENOSYS;
}
dvbdmxfeed->check_crc=check_crc;
dvbdmxfeed->feed.sec.check_crc=check_crc;
#ifdef NOBUFS
dvbdmxfeed->buffer=0;
#else
......@@ -830,19 +872,21 @@ dmx_section_feed_start_filtering(dmx_section_feed_t *feed)
up(&dvbdmx->mutex);
return -EINVAL;
}
dvbdmxfeed->secbufp=0;
dvbdmxfeed->seclen=0;
dvbdmxfeed->feed.sec.secbufp=0;
dvbdmxfeed->feed.sec.seclen=0;
if (!dvbdmx->start_feed) {
up(&dvbdmx->mutex);
return -1;
return -ENODEV;
}
prepare_secfilters(dvbdmxfeed);
ret=dvbdmx->start_feed(dvbdmxfeed);
if (ret<0) {
if ((ret = dvbdmx->start_feed(dvbdmxfeed)) < 0) {
up(&dvbdmx->mutex);
return ret;
}
spin_lock_irq(&dvbdmx->lock);
feed->is_filtering=1;
dvbdmxfeed->state=DMX_STATE_GO;
......@@ -863,7 +907,7 @@ dmx_section_feed_stop_filtering(struct dmx_section_feed_s* feed)
if (!dvbdmx->stop_feed) {
up(&dvbdmx->mutex);
return -1;
return -ENODEV;
}
ret=dvbdmx->stop_feed(dvbdmxfeed);
spin_lock_irq(&dvbdmx->lock);
......@@ -925,7 +969,7 @@ static int dvbdmx_allocate_section_feed(dmx_demux_t *demux,
dvbdmxfeed->cb.sec=callback;
dvbdmxfeed->demux=dvbdmx;
dvbdmxfeed->pid=0xffff;
dvbdmxfeed->secbufp=0;
dvbdmxfeed->feed.sec.secbufp=0;
dvbdmxfeed->filter=0;
dvbdmxfeed->buffer=0;
......@@ -948,6 +992,7 @@ static int dvbdmx_release_section_feed(dmx_demux_t *demux,
{
struct dvb_demux_feed *dvbdmxfeed=(struct dvb_demux_feed *) feed;
struct dvb_demux *dvbdmx=(struct dvb_demux *) demux;
struct list_head *pos, *n, *head=&dvbdmx->feed_list;
if (down_interruptible (&dvbdmx->mutex))
return -ERESTARTSYS;
......@@ -963,9 +1008,16 @@ static int dvbdmx_release_section_feed(dmx_demux_t *demux,
}
#endif
dvbdmxfeed->state=DMX_STATE_FREE;
dvbdmxfeed->demux->pid2feed[dvbdmxfeed->pid]=0;
if (dvbdmxfeed->pid!=0xffff)
dvbdmxfeed->demux->pid2feed[dvbdmxfeed->pid]=0;
if (dvbdmxfeed->pid <= DMX_MAX_PID) {
list_for_each_safe(pos, n, head)
if (DMX_FEED_ENTRY(pos)->pid == dvbdmxfeed->pid) {
list_del(pos);
break;
}
dvbdmxfeed->pid = 0xffff;
}
up(&dvbdmx->mutex);
return 0;
}
......@@ -1125,9 +1177,15 @@ dvb_dmx_init(struct dvb_demux *dvbdemux)
dvbdemux->pids[i]=0xffff;
}
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;
if (!dvbdemux->check_crc32)
dvbdemux->check_crc32 = dvb_dmx_crc32;
if (!dvbdemux->memcopy)
dvbdemux->memcopy = dvb_dmx_memcopy;
dmx->frontend=0;
dmx->reg_list.next=dmx->reg_list.prev=&dmx->reg_list;
dmx->priv=(void *) dvbdemux;
......
......@@ -25,6 +25,9 @@
#ifndef _DVB_DEMUX_H_
#define _DVB_DEMUX_H_
#include <asm/semaphore.h>
#include <linux/timer.h>
#include "demux.h"
#define DMX_TYPE_TS 0
......@@ -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 {
union {
dmx_ts_feed_t ts;
......@@ -71,13 +76,13 @@ struct dvb_demux_feed {
} cb;
struct dvb_demux *demux;
void *priv;
int type;
int state;
u16 pid;
u8 *buffer;
int buffer_size;
int descramble;
int check_crc;
struct timespec timeout;
struct dvb_demux_filter *filter;
......@@ -86,12 +91,11 @@ struct dvb_demux_feed {
int ts_type;
dmx_ts_pes_t pes_type;
u8 secbuf[4096];
int secbufp;
int seclen;
int cc;
u16 peslen;
struct list_head list_head;
};
struct dvb_demux {
......@@ -99,10 +103,14 @@ struct dvb_demux {
void *priv;
int filternum;
int feednum;
int (*start_feed)(struct dvb_demux_feed *);
int (*stop_feed)(struct dvb_demux_feed *);
int (*write_to_decoder)(struct dvb_demux_feed *, u8 *, size_t);
int (*start_feed) (struct dvb_demux_feed *feed);
int (*stop_feed) (struct dvb_demux_feed *feed);
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;
#define MAX_DVB_DEMUX_USERS 10
......@@ -117,7 +125,7 @@ struct dvb_demux {
int recording;
#define DMX_MAX_PID 0x2000
struct dvb_demux_feed *pid2feed[DMX_MAX_PID+1];
struct list_head feed_list;
u8 tsbuf[188];
int tsbufp;
......@@ -129,6 +137,7 @@ struct dvb_demux {
int dvb_dmx_init(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_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_ */
#include <linux/module.h>
#include <linux/videodev.h>
#include "dvb_filter.h"
unsigned int bitrates[3][16] =
......@@ -346,8 +345,8 @@ int get_ainfo(uint8_t *mbuf, int count, AudioInfo *ai, int pr)
}
#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;
int found = 0;
......@@ -605,397 +604,3 @@ int dvb_filter_pes2ts(dvb_filter_pes2ts_t *p2ts, unsigned char *pes, int len)
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 {
void dvb_filter_pes2ts_init(dvb_filter_pes2ts_t *p2ts, unsigned short pid,
dvb_filter_pes2ts_cb_t *cb, void *priv);
int dvb_filter_pes2ts(dvb_filter_pes2ts_t *p2ts, unsigned char *pes, int len);
......@@ -223,12 +224,7 @@ typedef struct audio_i{
uint32_t off;
} 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
......@@ -27,16 +27,14 @@
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/module.h>
#include <linux/compatmac.h>
#include <linux/list.h>
#include "compat.h"
#include "dvb_frontend.h"
#include "dvbdev.h"
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
......@@ -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_info *info;
struct dvb_frontend frontend;
struct dvb_device *dvbdev;
struct list_head notifier_callbacks;
struct dvb_frontend_parameters parameters;
struct dvb_fe_events events;
struct semaphore sem;
......@@ -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_ioctl_list);
static LIST_HEAD(frontend_notifier_list);
static DECLARE_MUTEX(frontend_mutex);
......@@ -153,6 +152,7 @@ void dvb_bend_frequency (struct dvb_frontend_data *this_fe, int recursive)
if (!recursive) {
if (down_interruptible (&frontend_mutex))
return;
this_fe->bending = 0;
}
......@@ -170,7 +170,7 @@ void dvb_bend_frequency (struct dvb_frontend_data *this_fe, int recursive)
frequency += this_fe->lnb_drift;
frequency += this_fe->bending;
if (this_fe != fe &&
if (this_fe != fe && fe->lost_sync_count != -1 &&
frequency > f - stepsize && frequency < f + stepsize)
{
if (recursive % 2)
......@@ -192,9 +192,6 @@ static
void dvb_call_frontend_notifiers (struct dvb_frontend_data *fe,
fe_status_t s)
{
struct list_head *e;
struct dvb_fe_notifier_callbacks *c;
dprintk ("%s\n", __FUNCTION__);
if ((fe->status & FE_HAS_LOCK) && !(s & FE_HAS_LOCK))
......@@ -211,10 +208,8 @@ void dvb_call_frontend_notifiers (struct dvb_frontend_data *fe,
/**
* now tell the Demux about the TS status changes...
*/
list_for_each (e, &fe->notifier_callbacks) {
c = list_entry (e, struct dvb_fe_notifier_callbacks, list_head);
c->callback (fe->status, c->data);
}
if (fe->frontend.notifier_callback)
fe->frontend.notifier_callback(fe->status, fe->frontend.notifier_data);
}
......@@ -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
int dvb_frontend_set_parameters (struct dvb_frontend_data *fe,
struct dvb_frontend_parameters *param,
......@@ -336,8 +299,6 @@ int dvb_frontend_set_parameters (struct dvb_frontend_data *fe,
struct dvb_frontend *frontend = &fe->frontend;
int err;
dvb_bend_frequency (fe, 0);
if (first_trial) {
fe->timeout_count = 0;
fe->lost_sync_count = 0;
......@@ -349,6 +310,8 @@ int dvb_frontend_set_parameters (struct dvb_frontend_data *fe,
sizeof (struct dvb_frontend_parameters));
}
dvb_bend_frequency (fe, 0);
dprintk ("%s: f == %i, drift == %i\n",
__FUNCTION__, param->frequency, fe->lnb_drift);
......@@ -365,23 +328,12 @@ static
void dvb_frontend_init (struct dvb_frontend_data *fe)
{
struct dvb_frontend *frontend = &fe->frontend;
struct dvb_frontend_parameters *init_param;
printk ("DVB: initialising frontend %i:%i (%s)...\n",
frontend->i2c->adapter->num, frontend->i2c->id, fe->info->name);
dprintk ("DVB: initialising frontend %i:%i (%s)...\n",
frontend->i2c->adapter->num, frontend->i2c->id,
fe->info->name);
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)
if (fe->exit)
return 1;
if (fe->dvbdev->users == 0 && dvb_shutdown_timeout)
if (fe->dvbdev->writers == 1)
if (jiffies - fe->release_jiffies > dvb_shutdown_timeout * HZ)
return 1;
......@@ -482,13 +434,27 @@ int dvb_frontend_thread (void *data)
dprintk ("%s\n", __FUNCTION__);
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;
snprintf (current->comm, sizeof (current->comm), "kdvb-fe-%i:%i",
fe->frontend.i2c->adapter->num, fe->frontend.i2c->id);
unlock_kernel ();
dvb_call_frontend_notifiers (fe, 0);
dvb_frontend_init (fe);
fe->lost_sync_count = -1;
while (!dvb_frontend_is_exiting (fe)) {
up (&fe->sem); /* is locked when we enter the thread... */
......@@ -499,6 +465,9 @@ int dvb_frontend_thread (void *data)
return -ERESTARTSYS;
}
if (fe->lost_sync_count == -1)
continue;
if (dvb_frontend_is_exiting (fe))
break;
......@@ -513,10 +482,14 @@ int dvb_frontend_thread (void *data)
fe->lost_sync_count = 0;
} else {
fe->lost_sync_count++;
if (fe->lost_sync_count < 10) /* XXX FIXME CHECKME! */
if (!(fe->info->caps & FE_CAN_RECOVER)) {
if (!(fe->info->caps & FE_CAN_CLEAN_SETUP)) {
if (fe->lost_sync_count < 10)
continue;
}
dvb_frontend_recover (fe);
delay = HZ/5;
}
if (jiffies - fe->lost_sync_jiffies > TIMEOUT) {
s |= FE_TIMEDOUT;
if ((fe->status & FE_TIMEDOUT) == 0)
......@@ -528,7 +501,9 @@ int dvb_frontend_thread (void *data)
dvb_frontend_add_event (fe, s);
};
if (dvb_shutdown_timeout)
dvb_frontend_internal_ioctl (&fe->frontend, FE_SLEEP, NULL);
up (&fe->sem);
fe->thread = NULL;
return 0;
......@@ -536,30 +511,36 @@ int dvb_frontend_thread (void *data)
static
void dvb_frontend_start (struct dvb_frontend_data *fe)
void dvb_frontend_stop (struct dvb_frontend_data *fe)
{
dprintk ("%s\n", __FUNCTION__);
if (!fe->exit && !fe->thread) {
if (down_interruptible (&fe->sem))
return;
kernel_thread (dvb_frontend_thread, fe, 0);
}
while (fe->thread) {
fe->exit = 1;
wake_up_interruptible (&fe->wait_queue);
current->state = TASK_INTERRUPTIBLE;
schedule_timeout (5);
if (signal_pending(current))
break;
};
}
static
void dvb_frontend_stop (struct dvb_frontend_data *fe)
void dvb_frontend_start (struct dvb_frontend_data *fe)
{
dprintk ("%s\n", __FUNCTION__);
fe->exit = 1;
wake_up_interruptible (&fe->wait_queue);
if (fe->thread)
dvb_frontend_stop (fe);
while (fe->thread) {
current->state = TASK_INTERRUPTIBLE;
schedule_timeout (5);
};
if (down_interruptible (&fe->sem))
return;
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
dprintk ("%s\n", __FUNCTION__);
if (fe->events.eventw != fe->events.eventr)
return (POLLIN | POLLRDNORM | POLLPRI);
poll_wait (file, &fe->events.wait_queue, wait);
if (fe->events.eventw != fe->events.eventr)
......@@ -639,10 +617,12 @@ int dvb_frontend_open (struct inode *inode, struct file *file)
if ((ret = dvb_generic_open (inode, file)) < 0)
return ret;
if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
dvb_frontend_start (fe);
/* empty event queue */
fe->events.eventr = fe->events.eventw;
}
return ret;
}
......@@ -656,6 +636,7 @@ int dvb_frontend_release (struct inode *inode, struct file *file)
dprintk ("%s\n", __FUNCTION__);
if ((file->f_flags & O_ACCMODE) != O_RDONLY)
fe->release_jiffies = jiffies;
return dvb_generic_release (inode, file);
......@@ -673,7 +654,6 @@ dvb_add_frontend_ioctls (struct dvb_adapter *adapter,
{
struct dvb_frontend_ioctl_data *ioctl;
struct list_head *entry;
int frontend_count = 0;
dprintk ("%s\n", __FUNCTION__);
......@@ -706,14 +686,12 @@ dvb_add_frontend_ioctls (struct dvb_adapter *adapter,
fe->frontend.before_ioctl = before_ioctl;
fe->frontend.after_ioctl = after_ioctl;
fe->frontend.before_after_data = before_after_data;
dvb_frontend_start (fe);
frontend_count++;
}
}
up (&frontend_mutex);
return frontend_count;
return 0;
}
......@@ -724,12 +702,11 @@ dvb_remove_frontend_ioctls (struct dvb_adapter *adapter,
int (*after_ioctl) (struct dvb_frontend *frontend,
unsigned int cmd, void *arg))
{
struct list_head *entry;
struct list_head *entry, *n;
dprintk ("%s\n", __FUNCTION__);
if (down_interruptible (&frontend_mutex))
return;
down (&frontend_mutex);
list_for_each (entry, &frontend_list) {
struct dvb_frontend_data *fe;
......@@ -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);
}
......@@ -755,6 +748,7 @@ dvb_add_frontend_notifier (struct dvb_adapter *adapter,
void (*callback) (fe_status_t s, void *data),
void *data)
{
struct dvb_frontend_notifier_data *notifier;
struct list_head *entry;
dprintk ("%s\n", __FUNCTION__);
......@@ -762,34 +756,35 @@ dvb_add_frontend_notifier (struct dvb_adapter *adapter,
if (down_interruptible (&frontend_mutex))
return -ERESTARTSYS;
list_for_each (entry, &frontend_list) {
struct dvb_frontend_data *fe;
fe = list_entry (entry, struct dvb_frontend_data, list_head);
if (fe->frontend.i2c->adapter == adapter) {
struct dvb_fe_notifier_callbacks *e;
notifier = kmalloc (sizeof(struct dvb_frontend_notifier_data), GFP_KERNEL);
e = kmalloc (sizeof(struct dvb_fe_notifier_callbacks),
GFP_KERNEL);
if (!e) {
if (!notifier) {
up (&frontend_mutex);
return -ENOMEM;
}
e->callback = callback;
e->data = data;
list_add_tail (&e->list_head, &fe->notifier_callbacks);
notifier->adapter = adapter;
notifier->callback = callback;
notifier->data = data;
up (&frontend_mutex);
return 0;
list_add_tail (&notifier->list_head, &frontend_notifier_list);
list_for_each (entry, &frontend_list) {
struct dvb_frontend_data *fe;
fe = list_entry (entry, struct dvb_frontend_data, list_head);
if (fe->frontend.i2c->adapter == adapter &&
fe->frontend.notifier_callback == NULL)
{
fe->frontend.notifier_callback = callback;
fe->frontend.notifier_data = data;
}
}
up (&frontend_mutex);
return -ENODEV;
return 0;
}
......@@ -797,31 +792,38 @@ void
dvb_remove_frontend_notifier (struct dvb_adapter *adapter,
void (*callback) (fe_status_t s, void *data))
{
struct list_head *entry;
struct list_head *entry, *n;
dprintk ("%s\n", __FUNCTION__);
if (down_interruptible (&frontend_mutex))
return;
down (&frontend_mutex);
list_for_each (entry, &frontend_list) {
struct dvb_frontend_data *fe;
fe = list_entry (entry, struct dvb_frontend_data, list_head);
if (fe->frontend.i2c->adapter == adapter) {
struct list_head *e0, *n0;
list_for_each_safe (e0, n0, &fe->notifier_callbacks) {
struct dvb_fe_notifier_callbacks *e;
if (fe->frontend.i2c->adapter == adapter &&
fe->frontend.notifier_callback == callback)
{
fe->frontend.notifier_callback = NULL;
e = list_entry (e0,
struct dvb_fe_notifier_callbacks,
list_head);
list_del (&e->list_head);
kfree (e);
}
}
list_for_each_safe (entry, n, &frontend_notifier_list) {
struct dvb_frontend_notifier_data *notifier;
notifier = list_entry (entry, struct dvb_frontend_notifier_data, list_head);
if (notifier->adapter == adapter &&
notifier->callback == callback)
{
list_del (&notifier->list_head);
kfree (notifier);
break;
}
}
up (&frontend_mutex);
......@@ -849,7 +851,7 @@ dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend,
struct list_head *entry;
struct dvb_frontend_data *fe;
static const struct dvb_device dvbdev_template = {
.users = 1,
.users = ~0,
.writers = 1,
.fops = &dvb_frontend_fops,
.kernel_ioctl = dvb_frontend_ioctl
......@@ -873,7 +875,6 @@ dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend,
init_MUTEX (&fe->events.sem);
fe->events.eventw = fe->events.eventr = 0;
fe->events.overflow = 0;
INIT_LIST_HEAD (&fe->notifier_callbacks);
fe->frontend.ioctl = ioctl;
fe->frontend.i2c = i2c;
......@@ -891,13 +892,30 @@ dvb_register_frontend (int (*ioctl) (struct dvb_frontend *frontend,
fe->frontend.before_ioctl = ioctl->before_ioctl;
fe->frontend.after_ioctl = ioctl->after_ioctl;
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;
}
}
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,
fe, DVB_DEVICE_FRONTEND);
......@@ -915,8 +933,7 @@ int dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend,
dprintk ("%s\n", __FUNCTION__);
if (down_interruptible (&frontend_mutex))
return -ERESTARTSYS;
down (&frontend_mutex);
list_for_each_safe (entry, n, &frontend_list) {
struct dvb_frontend_data *fe;
......@@ -925,10 +942,8 @@ int dvb_unregister_frontend (int (*ioctl) (struct dvb_frontend *frontend,
if (fe->frontend.ioctl == ioctl && fe->frontend.i2c == i2c) {
dvb_unregister_device (fe->dvbdev);
list_del (entry);
up (&frontend_mutex);
dvb_frontend_stop (fe);
kfree (fe);
return 0;
......
......@@ -52,8 +52,10 @@ struct dvb_frontend {
int (*before_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);
void (*notifier_callback) (fe_status_t s, void *data);
struct dvb_i2c_bus *i2c;
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... */
};
......
......@@ -22,10 +22,13 @@
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/version.h>
#include "compat.h"
#include "dvb_i2c.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51)
#include "compat.h"
#endif
#include "dvb_i2c.h"
struct dvb_i2c_device {
struct list_head list_head;
......@@ -34,13 +37,11 @@ struct dvb_i2c_device {
void (*detach) (struct dvb_i2c_bus *i2c);
};
LIST_HEAD(dvb_i2c_buslist);
LIST_HEAD(dvb_i2c_devicelist);
DECLARE_MUTEX(dvb_i2c_mutex);
static
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
void try_attach_device (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev)
{
if (try_module_get(dev->owner)) {
if (dev->attach(i2c) == 0)
register_i2c_client(i2c, dev);
else
module_put(dev->owner);
if (dev->owner) {
if (!try_module_get(dev->owner))
return;
}
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)
static
void detach_device (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *dev)
{
dev->detach(i2c);
module_put(dev->owner);
dev->detach (i2c);
if (dev->owner)
module_put (dev->owner);
}
......@@ -84,25 +92,27 @@ static
void unregister_i2c_client_from_bus (struct dvb_i2c_device *dev,
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;
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);
}
}
}
static
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;
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)
struct list_head *entry, *n;
list_for_each_safe (entry, n, &(i2c->client_list)) {
struct dvb_i2c_device *client;
client = list_entry (entry, struct dvb_i2c_device, list_head);
struct dvb_i2c_device *dev;
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
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)
}
struct dvb_i2c_bus*
dvb_register_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
struct i2c_msg msgs[], int num),
void *data,
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*
dvb_register_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
const struct i2c_msg *msgs, int num),
void *data, struct dvb_adapter *adapter, int id)
{
struct dvb_i2c_bus *i2c;
if (down_interruptible (&dvb_i2c_mutex))
return NULL;
if (!(i2c = kmalloc (sizeof (struct dvb_i2c_bus), GFP_KERNEL)))
return NULL;
......@@ -184,54 +214,27 @@ dvb_register_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
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);
return NULL;
return i2c;
}
void dvb_unregister_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
struct i2c_msg msgs[], int num),
struct dvb_adapter *adapter,
int id)
const struct i2c_msg msgs[], int num),
struct dvb_adapter *adapter, 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);
list_del (&i2c->list_head);
kfree (i2c);
}
up (&dvb_i2c_mutex);
}
......@@ -267,8 +270,7 @@ int dvb_unregister_i2c_device (int (*attach) (struct dvb_i2c_bus *i2c))
{
struct list_head *entry, *n;
if (down_interruptible (&dvb_i2c_mutex))
return -ERESTARTSYS;
down (&dvb_i2c_mutex);
list_for_each_safe (entry, n, &dvb_i2c_devicelist) {
struct dvb_i2c_device *dev;
......
......@@ -30,7 +30,9 @@
struct dvb_i2c_bus {
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;
struct dvb_adapter *adapter;
int id;
......@@ -38,17 +40,16 @@ struct dvb_i2c_bus {
};
extern
struct dvb_i2c_bus* dvb_register_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
struct i2c_msg msgs[],
int num),
extern struct dvb_i2c_bus*
dvb_register_i2c_bus (int (*xfer) (struct dvb_i2c_bus *i2c,
const struct i2c_msg *msgs, int num),
void *data,
struct dvb_adapter *adapter,
int id);
extern
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,
int id);
......
......@@ -8,6 +8,69 @@
#include "dvb_demux.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_release);
......@@ -15,6 +78,7 @@ EXPORT_SYMBOL(dvb_dmx_init);
EXPORT_SYMBOL(dvb_dmx_release);
EXPORT_SYMBOL(dvb_dmx_swfilter_packet);
EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
EXPORT_SYMBOL(dvb_dmx_swfilter);
EXPORT_SYMBOL(dvb_register_frontend);
EXPORT_SYMBOL(dvb_unregister_frontend);
......@@ -39,11 +103,7 @@ EXPORT_SYMBOL(dvb_generic_ioctl);
EXPORT_SYMBOL(dvb_generic_open);
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);
EXPORT_SYMBOL(dvb_filter_get_ac3info);
......@@ -3,29 +3,52 @@
*
* Copyright (C) 2001 Convergence integrated media GmbH
* Ralph Metzler <ralph@convergence.de>
* Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* 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 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
* 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 "demux.h"
#include <linux/dvb/net.h>
#include "dvb_demux.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
* 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)
}
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;
struct sk_buff *skb;
......@@ -86,7 +109,7 @@ dvb_net_sec(struct net_device *dev, u8 *pkt, int pkt_len)
if (skb == NULL) {
printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
dev->name);
((dvb_net_priv_t *)dev->priv)->stats.rx_dropped++;
((struct dvb_net_priv *)dev->priv)->stats.rx_dropped++;
return;
}
eth=(u8 *) skb_put(skb, pkt_len+2);
......@@ -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->dev=dev;
((dvb_net_priv_t *)dev->priv)->stats.rx_packets++;
((dvb_net_priv_t *)dev->priv)->stats.rx_bytes+=skb->len;
//sti();
((struct dvb_net_priv *)dev->priv)->stats.rx_packets++;
((struct dvb_net_priv *)dev->priv)->stats.rx_bytes+=skb->len;
netif_rx(skb);
}
static int
dvb_net_callback(u8 *buffer1, size_t buffer1_len,
u8 *buffer2, size_t buffer2_len,
dvb_net_callback(const u8 *buffer1, size_t buffer1_len,
const u8 *buffer2, size_t buffer2_len,
dmx_section_filter_t *filter,
dmx_success_t success)
{
......@@ -130,18 +152,21 @@ dvb_net_tx(struct sk_buff *skb, struct net_device *dev)
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
dvb_net_filter_set(struct net_device *dev,
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;
*secfilter=0;
ret=priv->secfeed->allocate_filter(priv->secfeed, secfilter);
ret = priv->secfeed->allocate_filter(priv->secfeed, secfilter);
if (ret<0) {
printk("%s: could not get filter\n", dev->name);
return ret;
......@@ -149,25 +174,26 @@ dvb_net_filter_set(struct net_device *dev,
(*secfilter)->priv=(void *) dev;
memset((*secfilter)->filter_value, 0, DMX_MAX_FILTER_SIZE);
memset((*secfilter)->filter_mask , 0, DMX_MAX_FILTER_SIZE);
memset((*secfilter)->filter_value, 0x00, 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_mask[0]=MASK;
(*secfilter)->filter_mask[0]=0xff;
(*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_mask[4]=MASK;
(*secfilter)->filter_mask[4]=mac_mask[4];
(*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_mask[9]=MASK;
(*secfilter)->filter_mask[9]=mac_mask[2];
(*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_mask[11]=MASK;
(*secfilter)->filter_mask[11]=mac_mask[0];
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]);
......@@ -178,9 +204,9 @@ static int
dvb_net_feed_start(struct net_device *dev)
{
int ret, i;
dvb_net_priv_t *priv=(dvb_net_priv_t *)dev->priv;
dmx_demux_t *demux=priv->demux;
unsigned char *mac=(unsigned char *) dev->dev_addr;
struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
dmx_demux_t *demux = priv->demux;
unsigned char *mac = (unsigned char *) dev->dev_addr;
priv->secfeed=0;
priv->secfilter=0;
......@@ -200,28 +226,41 @@ dvb_net_feed_start(struct net_device *dev)
priv->secfeed=0;
return ret;
}
MOD_INC_USE_COUNT;
/* fixme: is this correct? */
try_module_get(THIS_MODULE);
if (priv->mode<3)
dvb_net_filter_set(dev, &priv->secfilter, mac, mask_normal);
dvb_net_filter_set(dev, &priv->secfilter, mac);
switch (priv->mode) {
case 1:
for (i=0; i<priv->multi_num; i++)
dvb_net_filter_set(dev, &priv->secfilter,
priv->multi_macs[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);
printk("%s: feed_started\n", dev->name);
return 0;
}
static void
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;
if (priv->secfeed) {
if (priv->secfeed->is_filtering)
priv->secfeed->stop_filtering(priv->secfeed);
printk("%s: feed_stopped\n", dev->name);
if (priv->secfilter)
priv->secfeed->
release_filter(priv->secfeed,
......@@ -238,62 +277,70 @@ dvb_net_feed_stop(struct net_device *dev)
priv->demux->
release_section_feed(priv->demux, priv->secfeed);
priv->secfeed=0;
MOD_DEC_USE_COUNT;
/* fixme: is this correct? */
module_put(THIS_MODULE);
} else
printk("%s: no feed to stop\n", dev->name);
}
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;
printk("%s: set_mc_filter %d: %02x %02x %02x %02x %02x %02x\n",
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]);
ret = memcmp(priv->multi_macs[priv->multi_num], mc->dmi_addr, 6);
memcpy(priv->multi_macs[priv->multi_num], mc->dmi_addr, 6);
priv->multi_num++;
return 0;
return ret;
}
static void
dvb_net_set_multi(struct net_device *dev)
{
dvb_net_priv_t *priv=(dvb_net_priv_t *)dev->priv;
printk("%s: set_multi()\n", dev->name);
dvb_net_feed_stop(dev);
if (dev->flags&IFF_PROMISC) {
/* Enable promiscuous mode */
printk("%s: promiscuous mode\n", dev->name);
} else if((dev->flags&IFF_ALLMULTI)) {
/* Disable promiscuous mode, use normal mode. */
printk("%s: normal mode\n", dev->name);
} else if(dev->mc_count) {
int mci;
struct dvb_net_priv *priv = (struct dvb_net_priv*) dev->priv;
struct dev_mc_list *mc;
printk("%s: set_mc_list, %d entries\n",
dev->name, dev->mc_count);
priv->multi_num=0;
for (mci=0, mc=dev->mc_list;
mci<dev->mc_count;
mc=mc->next, mci++) {
dvb_set_mc_filter(dev, mc);
}
int mci;
int update = 0;
if(dev->flags & IFF_PROMISC) {
// printk("%s: promiscuous mode\n", dev->name);
if(priv->mode != 3)
update = 1;
priv->mode = 3;
} else if(dev->flags & IFF_ALLMULTI) {
// printk("%s: allmulti mode\n", dev->name);
if(priv->mode != 2)
update = 1;
priv->mode = 2;
} else if(dev->mc_count > 0) {
// printk("%s: set_mc_list, %d entries\n",
// dev->name, dev->mc_count);
if(priv->mode != 1)
update = 1;
priv->mode = 1;
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);
}
}
static int
......@@ -308,9 +355,11 @@ static int
dvb_net_set_mac(struct net_device *dev, void *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);
if (netif_running(dev)) {
if (netif_running(dev) != 0 && update > 0) {
dvb_net_feed_stop(dev);
dvb_net_feed_start(dev);
}
......@@ -335,15 +384,13 @@ dvb_net_stop(struct net_device *dev)
static struct net_device_stats *
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
dvb_net_init_dev(struct net_device *dev)
{
printk("dvb_net: dvb_net_init_dev()\n");
ether_setup(dev);
dev->open = dvb_net_open;
......@@ -354,6 +401,7 @@ dvb_net_init_dev(struct net_device *dev)
dev->set_config = dvb_net_set_config;
dev->set_mac_address = dvb_net_set_mac;
dev->mtu = 4096;
dev->mc_count = 0;
dev->flags |= IFF_NOARP;
dev->hard_header_cache = NULL;
......@@ -364,7 +412,7 @@ dvb_net_init_dev(struct net_device *dev)
}
static int
get_if(dvb_net_t *dvbnet)
get_if(struct dvb_net *dvbnet)
{
int i;
......@@ -379,10 +427,11 @@ get_if(dvb_net_t *dvbnet)
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;
dmx_demux_t *demux;
struct dvb_net_priv *priv;
int result;
int if_num;
......@@ -402,25 +451,29 @@ dvb_net_add_if(dvb_net_t *dvbnet, u16 pid)
net->name[5]=if_num+0x30;
net->next = NULL;
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)
return -ENOMEM;
memset(net->priv, 0, sizeof(dvb_net_priv_t));
((dvb_net_priv_t *)net->priv)->demux=demux;
((dvb_net_priv_t *)net->priv)->pid=pid;
priv = net->priv;
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) {
return result;
}
MOD_INC_USE_COUNT;
/* fixme: is this correct? */
try_module_get(THIS_MODULE);
return if_num;
}
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])
return -EINVAL;
......@@ -428,15 +481,17 @@ dvb_net_remove_if(dvb_net_t *dvbnet, int num)
kfree(dvbnet->device[num].priv);
unregister_netdev(&dvbnet->device[num]);
dvbnet->state[num]=0;
MOD_DEC_USE_COUNT;
/* fixme: is this correct? */
module_put(THIS_MODULE);
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)
{
struct dvb_device *dvbdev=(struct dvb_device *) file->private_data;
dvb_net_t *dvbnet=(dvb_net_t *) dvbdev->priv;
struct dvb_device *dvbdev = (struct dvb_device *) file->private_data;
struct dvb_net *dvbnet = (struct dvb_net *) dvbdev->priv;
if (((file->f_flags&O_ACCMODE)==O_RDONLY))
return -EPERM;
......@@ -453,6 +508,21 @@ int dvb_net_ioctl(struct inode *inode, struct file *file,
dvbnetif->if_num=result;
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:
return dvb_net_remove_if(dvbnet, (int) parg);
default:
......@@ -461,11 +531,21 @@ int dvb_net_ioctl(struct inode *inode, struct file *file,
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 = {
.owner = THIS_MODULE,
.ioctl = dvb_generic_ioctl,
.read = 0,
.write = 0,
.ioctl = dvb_net_ioctl,
.open = dvb_generic_open,
.release = dvb_generic_release,
.poll = 0,
};
static struct dvb_device dvbdev_net = {
......@@ -473,11 +553,10 @@ static struct dvb_device dvbdev_net = {
.users = 1,
.writers = 1,
.fops = &dvb_net_fops,
.kernel_ioctl = dvb_net_ioctl,
};
void
dvb_net_release(dvb_net_t *dvbnet)
dvb_net_release(struct dvb_net *dvbnet)
{
int i;
......@@ -490,15 +569,19 @@ dvb_net_release(dvb_net_t *dvbnet)
}
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;
dvbnet->demux=demux;
dvbnet->dev_num=DVB_NET_DEVICES_MAX;
dvbnet->demux = dmx;
dvbnet->dev_num = DVB_NET_DEVICES_MAX;
for (i=0; i<dvbnet->dev_num; i++)
dvbnet->state[i]=0;
dvb_register_device(adap, &dvbnet->dvbdev, &dvbdev_net, dvbnet, DVB_DEVICE_NET);
dvbnet->state[i] = 0;
dvb_register_device (adap, &dvbnet->dvbdev, &dvbdev_net,
dvbnet, DVB_DEVICE_NET);
return 0;
}
......@@ -32,23 +32,9 @@
#include "dvbdev.h"
#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 {
typedef struct dvb_net {
struct dvb_device *dvbdev;
int card_num;
int dev_num;
struct net_device device[DVB_NET_DEVICES_MAX];
......@@ -57,7 +43,8 @@ typedef struct dvb_net_s {
} dvb_net_t;
void dvb_net_release(dvb_net_t *);
int dvb_net_init(struct dvb_adapter *, dvb_net_t *, dmx_demux_t *);
void dvb_net_release(struct dvb_net *);
int dvb_net_init(struct dvb_adapter *, struct dvb_net *, dmx_demux_t *);
#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 @@
#include <asm/system.h>
#include <linux/kmod.h>
#include <linux/slab.h>
#include <linux/videodev.h>
#include "compat.h"
#include "dvbdev.h"
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,51)
#include "compat.h"
#endif
static int dvbdev_debug = 0;
#define dprintk if (dvbdev_debug) printk
......@@ -57,7 +59,6 @@ static char *dnames[] = {
#define DVB_MAX_IDS 4
#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type)
static
struct dvb_device* dvbdev_find_device (int minor)
{
......@@ -160,7 +161,7 @@ int dvb_generic_ioctl(struct inode *inode, struct file *file,
if (!dvbdev->kernel_ioctl)
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)
}
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;
int num;
......@@ -288,12 +289,14 @@ int dvb_register_adapter(struct dvb_adapter **padap, char *name)
memset (adap, 0, sizeof(struct dvb_adapter));
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);
adap->devfs_handle = devfs_mk_dir("dvb/adapter%d", num);
adap->num = num;
adap->name = name;
list_add_tail (&adap->list_head, &dvb_adapter_list);
......@@ -311,7 +314,8 @@ int dvb_unregister_adapter(struct dvb_adapter *adap)
list_del (&adap->list_head);
up (&dvbdev_register_lock);
kfree (adap);
MOD_DEC_USE_COUNT;
/* fixme: is this correct? */
module_put(THIS_MODULE);
return 0;
}
......
......@@ -48,6 +48,7 @@ struct dvb_adapter {
devfs_handle_t devfs_handle;
struct list_head list_head;
struct list_head device_list;
const char *name;
};
......@@ -70,7 +71,7 @@ struct dvb_device {
};
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_register_device (struct dvb_adapter *adap,
......@@ -85,6 +86,9 @@ 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_ioctl (struct inode *inode, struct file *file,
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_ */
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