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

[PATCH] update the dvb core

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