From b7deb66fda3accee36c079e200d1773c5e0fcc67 Mon Sep 17 00:00:00 2001 From: "Igor M. Liplianin" Date: Sun, 9 Nov 2008 16:35:13 +0200 Subject: Bug fix: For legacy applications stv0899 performs search only first time after insmod. From: Igor M. Liplianin For legacy applications stv0899 performs search only first time after insmod due to not set DVBFE_ALGO_SEARCH_AGAIN bit Signed-off-by: Igor M. Liplianin Signed-off-by: Manu Abraham --- linux/drivers/media/dvb/dvb-core/dvb_frontend.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'linux/drivers/media/dvb/dvb-core') diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c index 01a9ceb37..60a9c80a1 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -1396,9 +1396,6 @@ static int dtv_property_process_set(struct dvb_frontend *fe, dprintk("%s() Finalised property cache\n", __func__); dtv_property_cache_submit(fe); - /* Request the search algorithm to search */ - fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; - r |= dvb_frontend_ioctl_legacy(inode, file, FE_SET_FRONTEND, &fepriv->parameters); break; @@ -1832,6 +1829,10 @@ static int dvb_frontend_ioctl_legacy(struct inode *inode, struct file *file, fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000; fepriv->state = FESTATE_RETUNE; + + /* Request the search algorithm to search */ + fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; + dvb_frontend_wakeup(fe); dvb_frontend_add_event(fe, 0); fepriv->status = 0; -- cgit v1.2.3 From 3165ca2068855d7118d78396adce4c49a4e7f636 Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Mon, 4 May 2009 20:43:02 -0400 Subject: dvb_frontend: fix race condition resulting in dropped tuning commands From: Devin Heitmueller A race condition was detected in the case that putting the tuner to sleep takes an unusually long period of time, combined with applications that quickly close/open the dvb frontend. The kaffeine channel scanner closes and reopens the dvb frontend between each tuning attempt. If it takes an unusually longer period of time to put the tuner to sleep (for example, the Pinnacle 801e takes 660 ms), the dvb_frontend thread will still be in a running state (and hence fepriv->thread is still set) but the fepriv->exit field will still be zero. As a result, if a dvb_frontend_start() call arrives while the frontend thread is in the process of terminating, the call will return 0 without actually starting a new thread. This results in the tuning request being dropped. To address this, mark fepriv->exit as soon as we know the thread is going to be terminated, so that dvb_frontend_start() knows to start a new instance. Problem encountered with Kaffeine 0.8.7 doing ATSC scanning against the Pinnacle 801e tuner, in conjunction with new code to power down the xc5000 when not in use. Priority: normal Signed-off-by: Devin Heitmueller --- linux/drivers/media/dvb/dvb-core/dvb_frontend.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux/drivers/media/dvb/dvb-core') diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c index da2890b22..d359f6841 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -554,6 +554,7 @@ restart: if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) { /* got signal or quitting */ + fepriv->exit = 1; break; } -- cgit v1.2.3 From 3e94e24e59b323cdacd22598b28769753866bfc3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 12 May 2009 20:39:28 +0000 Subject: core: fix potential mutex_unlock without mutex_lock in dvb_dvr_read From: Simon Arlott dvb_dvr_read may unlock the dmxdev mutex and return -ENODEV, except this function is a file op and will never be called with the mutex held. There's existing mutex_lock and mutex_unlock around the actual read but it's commented out. These should probably be uncommented but the read blocks and this could block another non-blocking reader on the mutex instead. This change comments out the extra mutex_unlock. [akpm@linux-foundation.org: cleanups, simplification] Signed-off-by: Simon Arlott Signed-off-by: Andrew Morton Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/dvb/dvb-core/dmxdev.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) (limited to 'linux/drivers/media/dvb/dvb-core') diff --git a/linux/drivers/media/dvb/dvb-core/dmxdev.c b/linux/drivers/media/dvb/dvb-core/dmxdev.c index c35fbb8d8..6d6121eb5 100644 --- a/linux/drivers/media/dvb/dvb-core/dmxdev.c +++ b/linux/drivers/media/dvb/dvb-core/dmxdev.c @@ -244,19 +244,13 @@ static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count, { struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv; - int ret; - if (dmxdev->exit) { - mutex_unlock(&dmxdev->mutex); + if (dmxdev->exit) return -ENODEV; - } - //mutex_lock(&dmxdev->mutex); - ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, - file->f_flags & O_NONBLOCK, - buf, count, ppos); - //mutex_unlock(&dmxdev->mutex); - return ret; + return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, + file->f_flags & O_NONBLOCK, + buf, count, ppos); } static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev, -- cgit v1.2.3 From 5f623f9662748ffe9662ee5b0561fe746ef3279d Mon Sep 17 00:00:00 2001 From: Devin Heitmueller Date: Wed, 20 May 2009 22:58:16 -0400 Subject: dvb_frontend: fix case where fepriv->exit not reset From: Devin Heitmueller The fact that we now explicitly set fepriv->exit = 1 when the thread is shutting down exposed an edge case where it was not being reset back to zero once the thread went away in some cases. This resulted in failures in cases where the frontend was closed, and then opened O_RDONLY, since in that case the thread is not being restarted but it was checking the fepriv->exit flag. Thanks to Thierry Lelegard, who and encountered and debugged a large portion of the issue in the same twelve hours that I did (as well as testing my patch). Priority: high Signed-off-by: Devin Heitmueller Cc: Thierry Lelegard --- linux/drivers/media/dvb/dvb-core/dvb_frontend.c | 1 + 1 file changed, 1 insertion(+) (limited to 'linux/drivers/media/dvb/dvb-core') diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c index d359f6841..41166d407 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -668,6 +668,7 @@ restart: } fepriv->thread = NULL; + fepriv->exit = 0; mb(); dvb_frontend_wakeup(fe); -- cgit v1.2.3 From 7ef1e386396d4ebc645310511099bf2526e519c4 Mon Sep 17 00:00:00 2001 From: Abylay Ospan Date: Sat, 6 Jun 2009 16:31:34 +0400 Subject: TS continuity check: show error message when discontinuity detected or TEI flag detected in header Signed-off-by: Abylay Ospan --- linux/drivers/media/dvb/dvb-core/dvb_demux.c | 42 ++++++++++++++++++++++++++++ linux/drivers/media/dvb/dvb-core/dvb_demux.h | 4 +++ 2 files changed, 46 insertions(+) (limited to 'linux/drivers/media/dvb/dvb-core') diff --git a/linux/drivers/media/dvb/dvb-core/dvb_demux.c b/linux/drivers/media/dvb/dvb-core/dvb_demux.c index e2eca0b1f..cfe2768d2 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/linux/drivers/media/dvb/dvb-core/dvb_demux.c @@ -38,6 +38,16 @@ */ // #define DVB_DEMUX_SECTION_LOSS_LOG +static int dvb_demux_tscheck; +module_param(dvb_demux_tscheck, int, 0644); +MODULE_PARM_DESC(dvb_demux_tscheck, + "enable transport stream continuity and TEI check"); + +#define dprintk_tscheck(x...) do { \ + if (dvb_demux_tscheck && printk_ratelimit()) \ + printk(x); \ + } while (0) + /****************************************************************************** * static inlined helper functions ******************************************************************************/ @@ -376,6 +386,36 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) u16 pid = ts_pid(buf); int dvr_done = 0; + if (dvb_demux_tscheck) { + if (!demux->cnt_storage) + demux->cnt_storage = vmalloc(MAX_PID + 1); + + if (!demux->cnt_storage) { + printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n"); + dvb_demux_tscheck = 0; + goto no_dvb_demux_tscheck; + } + + /* check pkt counter */ + if (pid < MAX_PID) { + if (buf[1] & 0x80) + dprintk_tscheck("TEI detected. " + "PID=0x%x data1=0x%x\n", + pid, buf[1]); + + if ((buf[3] & 0xf) != demux->cnt_storage[pid]) + dprintk_tscheck("TS packet counter mismatch. " + "PID=0x%x expected 0x%x " + "got 0x%x\n", + pid, demux->cnt_storage[pid], + buf[3] & 0xf); + + demux->cnt_storage[pid] = ((buf[3] & 0xf) + 1)&0xf; + }; + /* end check */ + }; +no_dvb_demux_tscheck: + list_for_each_entry(feed, &demux->feed_list, list_head) { if ((feed->pid != pid) && (feed->pid != 0x2000)) continue; @@ -1160,6 +1200,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) int i; struct dmx_demux *dmx = &dvbdemux->dmx; + dvbdemux->cnt_storage = NULL; dvbdemux->users = 0; dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter)); @@ -1226,6 +1267,7 @@ EXPORT_SYMBOL(dvb_dmx_init); void dvb_dmx_release(struct dvb_demux *dvbdemux) { + vfree(dvbdemux->cnt_storage); vfree(dvbdemux->filter); vfree(dvbdemux->feed); } diff --git a/linux/drivers/media/dvb/dvb-core/dvb_demux.h b/linux/drivers/media/dvb/dvb-core/dvb_demux.h index 933397c24..1e0ade4ec 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_demux.h +++ b/linux/drivers/media/dvb/dvb-core/dvb_demux.h @@ -43,6 +43,8 @@ #define DVB_DEMUX_MASK_MAX 18 +#define MAX_PID 0x1fff + struct dvb_demux_filter { struct dmx_section_filter filter; u8 maskandmode[DMX_MAX_FILTER_SIZE]; @@ -128,6 +130,8 @@ struct dvb_demux { struct mutex mutex; spinlock_t lock; + + uint8_t *cnt_storage; /* for TS continuity check */ }; int dvb_dmx_init(struct dvb_demux *dvbdemux); -- cgit v1.2.3 From 9204bc59f7e30d4441efb2262a1debc8782b5b74 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 16 Jun 2009 19:02:10 -0300 Subject: dvb-net: backport upstream changes fb875333c8 and 0eade1f930 From: Mauro Carvalho Chehab kernel-sync: commit fb875333c80942455551f690f306a899ceeee5df Author: Stephen Hemminger Date: Wed Jan 7 18:02:53 2009 -0800 dvb: update network device to current API Use internal network_device_stats that exist in network device and net_device_ops. Compile tested only. commit 0eade1f930fa3ba6461b34baf3ed8fa7c4abc40f Author: Wang Chen Date: Wed Dec 3 21:13:13 2008 -0800 dvb: Kill directly reference of netdev->priv Simply replace netdev->priv with netdev_priv(). Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/dvb/dvb-core/dvb_net.c | 65 +++++++++++++++++++++++++++++- 1 file changed, 64 insertions(+), 1 deletion(-) (limited to 'linux/drivers/media/dvb/dvb-core') diff --git a/linux/drivers/media/dvb/dvb-core/dvb_net.c b/linux/drivers/media/dvb/dvb-core/dvb_net.c index 5f4856c6d..1eede48a9 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_net.c +++ b/linux/drivers/media/dvb/dvb-core/dvb_net.c @@ -126,7 +126,9 @@ static void hexdump( const unsigned char *buf, unsigned short len ) struct dvb_net_priv { int in_use; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) struct net_device_stats stats; +#endif u16 pid; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) struct net_device *net; @@ -391,8 +393,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_skb) { dev_kfree_skb( priv->ule_skb ); /* Prepare for next SNDU. */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) priv->stats.rx_errors++; priv->stats.rx_frame_errors++; +#else + dev->stats.rx_errors++; + dev->stats.rx_frame_errors++; +#endif } reset_ule(priv); priv->need_pusi = 1; @@ -445,8 +452,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) dev_kfree_skb( priv->ule_skb ); /* Prepare for next SNDU. */ // reset_ule(priv); moved to below. +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) priv->stats.rx_errors++; priv->stats.rx_frame_errors++; +#else + dev->stats.rx_errors++; + dev->stats.rx_frame_errors++; +#endif } reset_ule(priv); /* skip to next PUSI. */ @@ -467,8 +479,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) /* Drop partly decoded SNDU, reset state, resync on PUSI. */ if (priv->ule_skb) { dev_kfree_skb( priv->ule_skb ); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) priv->stats.rx_errors++; priv->stats.rx_frame_errors++; +#else + dev->stats.rx_errors++; + dev->stats.rx_frame_errors++; +#endif } reset_ule(priv); priv->need_pusi = 1; @@ -484,8 +501,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_sndu_remain > 183) { /* Current SNDU lacks more data than there could be available in the * current TS cell. */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) priv->stats.rx_errors++; priv->stats.rx_length_errors++; +#else + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; +#endif printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but " "got PUSI (pf %d, ts_remain %d). Flushing incomplete payload.\n", priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain); @@ -527,8 +549,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_sndu_len < 5) { printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. " "Resyncing.\n", priv->ts_count, priv->ule_sndu_len); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) priv->stats.rx_errors++; priv->stats.rx_length_errors++; +#else + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; +#endif priv->ule_sndu_len = 0; priv->need_pusi = 1; new_ts = 1; @@ -580,7 +607,11 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_skb == NULL) { printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) priv->stats.rx_dropped++; +#else + dev->stats.rx_dropped++; +#endif return; } @@ -653,8 +684,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) ule_dump = 1; #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) priv->stats.rx_errors++; priv->stats.rx_crc_errors++; +#else + dev->stats.rx_errors++; + dev->stats.rx_crc_errors++; +#endif dev_kfree_skb(priv->ule_skb); } else { /* CRC32 verified OK. */ @@ -764,8 +800,13 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) * receive the packet anyhow. */ /* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST) priv->ule_skb->pkt_type = PACKET_HOST; */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) priv->stats.rx_packets++; priv->stats.rx_bytes += priv->ule_skb->len; +#else + dev->stats.rx_packets++; + dev->stats.rx_bytes += priv->ule_skb->len; +#endif netif_rx(priv->ule_skb); } sndu_done: @@ -820,8 +861,12 @@ static void dvb_net_sec(struct net_device *dev, { u8 *eth; struct sk_buff *skb; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) struct net_device_stats *stats = &((struct dvb_net_priv *) netdev_priv(dev))->stats; +#else + struct net_device_stats *stats = &dev->stats; +#endif int snap = 0; /* note: pkt_len includes a 32bit checksum */ @@ -1269,11 +1314,12 @@ static int dvb_net_stop(struct net_device *dev) return dvb_net_feed_stop(dev); } +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) static struct net_device_stats * dvb_net_get_stats(struct net_device *dev) { return &((struct dvb_net_priv *) netdev_priv(dev))->stats; } - +#endif #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) static const struct header_ops dvb_header_ops = { .create = eth_header, @@ -1282,6 +1328,19 @@ static const struct header_ops dvb_header_ops = { }; #endif + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 29) +static const struct net_device_ops dvb_netdev_ops = { + .ndo_open = dvb_net_open, + .ndo_stop = dvb_net_stop, + .ndo_start_xmit = dvb_net_tx, + .ndo_set_multicast_list = dvb_net_set_multicast_list, + .ndo_set_mac_address = dvb_net_set_mac, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, +}; +#endif + static void dvb_net_setup(struct net_device *dev) { ether_setup(dev); @@ -1291,12 +1350,16 @@ static void dvb_net_setup(struct net_device *dev) #else dev->hard_header_cache = NULL; #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) dev->open = dvb_net_open; dev->stop = dvb_net_stop; dev->hard_start_xmit = dvb_net_tx; dev->get_stats = dvb_net_get_stats; dev->set_multicast_list = dvb_net_set_multicast_list; dev->set_mac_address = dvb_net_set_mac; +#else + dev->netdev_ops = &dvb_netdev_ops; +#endif dev->mtu = 4096; dev->mc_count = 0; -- cgit v1.2.3 From 9a656496a57cf7f0b434af1b04d02c20e3976cbc Mon Sep 17 00:00:00 2001 From: Andreas Oberritter Date: Wed, 15 Jul 2009 01:28:50 +0200 Subject: Add two new ioctls: DMX_ADD_PID and DMX_REMOVE_PID From: Andreas Oberritter DMX_ADD_PID allows to add multiple PIDs to a transport stream filter previously set up with DMX_SET_PES_FILTER and output=DMX_OUT_TSDEMUX_TAP. DMX_REMOVE_PID is used to drop a PID from a filter. These ioctls are to be used by readers of /dev/dvb/adapterX/demuxY. They may be called at any time, i.e. before or after the first filter on the shared file descriptor was started. They make it possible to record multiple services without the need to de- or re-multiplex TS packets. To accomplish this, dmxdev_filter->feed.ts has been converted to a list of struct dmxdev_feeds, each containing a PID value and a pointer to a struct dmx_ts_feed. Priority: normal Signed-off-by: Andreas Oberritter --- linux/drivers/media/dvb/dvb-core/dmxdev.c | 231 ++++++++++++++++++++++-------- linux/drivers/media/dvb/dvb-core/dmxdev.h | 9 +- 2 files changed, 182 insertions(+), 58 deletions(-) (limited to 'linux/drivers/media/dvb/dvb-core') diff --git a/linux/drivers/media/dvb/dvb-core/dmxdev.c b/linux/drivers/media/dvb/dvb-core/dmxdev.c index 6d6121eb5..3750ff48c 100644 --- a/linux/drivers/media/dvb/dvb-core/dmxdev.c +++ b/linux/drivers/media/dvb/dvb-core/dmxdev.c @@ -430,6 +430,8 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, /* stop feed but only mark the specified filter as stopped (state set) */ static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter) { + struct dmxdev_feed *feed; + dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); switch (dmxdevfilter->type) { @@ -438,7 +440,8 @@ static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter) dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec); break; case DMXDEV_TYPE_PES: - dmxdevfilter->feed.ts->stop_filtering(dmxdevfilter->feed.ts); + list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) + feed->ts->stop_filtering(feed->ts); break; default: return -EINVAL; @@ -449,13 +452,23 @@ static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter) /* start feed associated with the specified filter */ static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter) { + struct dmxdev_feed *feed; + int ret; + dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO); switch (filter->type) { case DMXDEV_TYPE_SEC: return filter->feed.sec->start_filtering(filter->feed.sec); case DMXDEV_TYPE_PES: - return filter->feed.ts->start_filtering(filter->feed.ts); + list_for_each_entry(feed, &filter->feed.ts, next) { + ret = feed->ts->start_filtering(feed->ts); + if (ret < 0) { + dvb_dmxdev_feed_stop(filter); + return ret; + } + } + break; default: return -EINVAL; } @@ -487,6 +500,9 @@ static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter) static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter) { + struct dmxdev_feed *feed; + struct dmx_demux *demux; + if (dmxdevfilter->state < DMXDEV_STATE_GO) return 0; @@ -503,13 +519,12 @@ static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter) dmxdevfilter->feed.sec = NULL; break; case DMXDEV_TYPE_PES: - if (!dmxdevfilter->feed.ts) - break; dvb_dmxdev_feed_stop(dmxdevfilter); - dmxdevfilter->dev->demux-> - release_ts_feed(dmxdevfilter->dev->demux, - dmxdevfilter->feed.ts); - dmxdevfilter->feed.ts = NULL; + demux = dmxdevfilter->dev->demux; + list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) { + demux->release_ts_feed(demux, feed->ts); + feed->ts = NULL; + } break; default: if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED) @@ -521,19 +536,88 @@ static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter) return 0; } +static void dvb_dmxdev_delete_pids(struct dmxdev_filter *dmxdevfilter) +{ + struct dmxdev_feed *feed, *tmp; + + /* delete all PIDs */ + list_for_each_entry_safe(feed, tmp, &dmxdevfilter->feed.ts, next) { + list_del(&feed->next); + kfree(feed); + } + + BUG_ON(!list_empty(&dmxdevfilter->feed.ts)); +} + static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter) { if (dmxdevfilter->state < DMXDEV_STATE_SET) return 0; + if (dmxdevfilter->type == DMXDEV_TYPE_PES) + dvb_dmxdev_delete_pids(dmxdevfilter); + dmxdevfilter->type = DMXDEV_TYPE_NONE; dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); return 0; } +static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, + struct dmxdev_filter *filter, + struct dmxdev_feed *feed) +{ + struct timespec timeout = { 0 }; + struct dmx_pes_filter_params *para = &filter->params.pes; + dmx_output_t otype; + int ret; + int ts_type; + enum dmx_ts_pes ts_pes; + struct dmx_ts_feed *tsfeed; + + feed->ts = NULL; + otype = para->output; + + ts_pes = (enum dmx_ts_pes)para->pes_type; + + if (ts_pes < DMX_PES_OTHER) + ts_type = TS_DECODER; + else + ts_type = 0; + + if (otype == DMX_OUT_TS_TAP) + ts_type |= TS_PACKET; + else if (otype == DMX_OUT_TSDEMUX_TAP) + ts_type |= TS_PACKET | TS_DEMUX; + else if (otype == DMX_OUT_TAP) + ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY; + + ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, &feed->ts, + dvb_dmxdev_ts_callback); + if (ret < 0) + return ret; + + tsfeed = feed->ts; + tsfeed->priv = filter; + + ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout); + if (ret < 0) { + dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); + return ret; + } + + ret = tsfeed->start_filtering(tsfeed); + if (ret < 0) { + dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); + return ret; + } + + return 0; +} + static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) { struct dmxdev *dmxdev = filter->dev; + struct dmxdev_feed *feed; void *mem; int ret, i; @@ -631,56 +715,14 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) break; } case DMXDEV_TYPE_PES: - { - struct timespec timeout = { 0 }; - struct dmx_pes_filter_params *para = &filter->params.pes; - dmx_output_t otype; - int ts_type; - enum dmx_ts_pes ts_pes; - struct dmx_ts_feed **tsfeed = &filter->feed.ts; - - filter->feed.ts = NULL; - otype = para->output; - - ts_pes = (enum dmx_ts_pes)para->pes_type; - - if (ts_pes < DMX_PES_OTHER) - ts_type = TS_DECODER; - else - ts_type = 0; - - if (otype == DMX_OUT_TS_TAP) - ts_type |= TS_PACKET; - else if (otype == DMX_OUT_TSDEMUX_TAP) - ts_type |= TS_PACKET | TS_DEMUX; - else if (otype == DMX_OUT_TAP) - ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY; - - ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, - tsfeed, - dvb_dmxdev_ts_callback); - if (ret < 0) - return ret; - - (*tsfeed)->priv = filter; - - ret = (*tsfeed)->set(*tsfeed, para->pid, ts_type, ts_pes, - 32768, timeout); - if (ret < 0) { - dmxdev->demux->release_ts_feed(dmxdev->demux, - *tsfeed); - return ret; - } - - ret = filter->feed.ts->start_filtering(filter->feed.ts); - if (ret < 0) { - dmxdev->demux->release_ts_feed(dmxdev->demux, - *tsfeed); - return ret; + list_for_each_entry(feed, &filter->feed.ts, next) { + ret = dvb_dmxdev_start_feed(dmxdev, filter, feed); + if (ret < 0) { + dvb_dmxdev_filter_stop(filter); + return ret; + } } - break; - } default: return -EINVAL; } @@ -718,7 +760,7 @@ static int dvb_demux_open(struct inode *inode, struct file *file) dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192); dmxdevfilter->type = DMXDEV_TYPE_NONE; dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); - dmxdevfilter->feed.ts = NULL; + INIT_LIST_HEAD(&dmxdevfilter->feed.ts); init_timer(&dmxdevfilter->timer); dvbdev->users++; @@ -760,6 +802,55 @@ static inline void invert_mode(dmx_filter_t *filter) filter->mode[i] ^= 0xff; } +static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev, + struct dmxdev_filter *filter, u16 pid) +{ + struct dmxdev_feed *feed; + + if ((filter->type != DMXDEV_TYPE_PES) || + (filter->state < DMXDEV_STATE_SET)) + return -EINVAL; + + /* only TS packet filters may have multiple PIDs */ + if ((filter->params.pes.output != DMX_OUT_TSDEMUX_TAP) && + (!list_empty(&filter->feed.ts))) + return -EINVAL; + + feed = kzalloc(sizeof(struct dmxdev_feed), GFP_KERNEL); + if (feed == NULL) + return -ENOMEM; + + feed->pid = pid; + list_add(&feed->next, &filter->feed.ts); + + if (filter->state >= DMXDEV_STATE_GO) + return dvb_dmxdev_start_feed(dmxdev, filter, feed); + + return 0; +} + +static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev, + struct dmxdev_filter *filter, u16 pid) +{ + struct dmxdev_feed *feed, *tmp; + + if ((filter->type != DMXDEV_TYPE_PES) || + (filter->state < DMXDEV_STATE_SET)) + return -EINVAL; + + list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) { + if ((feed->pid == pid) && (feed->ts != NULL)) { + feed->ts->stop_filtering(feed->ts); + filter->dev->demux->release_ts_feed(filter->dev->demux, + feed->ts); + list_del(&feed->next); + kfree(feed); + } + } + + return 0; +} + static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev, struct dmxdev_filter *dmxdevfilter, struct dmx_sct_filter_params *params) @@ -784,7 +875,10 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev, struct dmxdev_filter *dmxdevfilter, struct dmx_pes_filter_params *params) { + int ret; + dvb_dmxdev_filter_stop(dmxdevfilter); + dvb_dmxdev_filter_reset(dmxdevfilter); if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0) return -EINVAL; @@ -795,6 +889,11 @@ static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev, dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); + ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, + dmxdevfilter->params.pes.pid); + if (ret < 0) + return ret; + if (params->flags & DMX_IMMEDIATE_START) return dvb_dmxdev_filter_start(dmxdevfilter); @@ -958,6 +1057,24 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file, &((struct dmx_stc *)parg)->base); break; + case DMX_ADD_PID: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + ret = -ERESTARTSYS; + break; + } + ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, *(u16 *)parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_REMOVE_PID: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + ret = -ERESTARTSYS; + break; + } + ret = dvb_dmxdev_remove_pid(dmxdev, dmxdevfilter, *(u16 *)parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + default: ret = -EINVAL; break; diff --git a/linux/drivers/media/dvb/dvb-core/dmxdev.h b/linux/drivers/media/dvb/dvb-core/dmxdev.h index 7e8137d0b..be63783ad 100644 --- a/linux/drivers/media/dvb/dvb-core/dmxdev.h +++ b/linux/drivers/media/dvb/dvb-core/dmxdev.h @@ -54,13 +54,20 @@ enum dmxdev_state { DMXDEV_STATE_TIMEDOUT }; +struct dmxdev_feed { + u16 pid; + struct dmx_ts_feed *ts; + struct list_head next; +}; + struct dmxdev_filter { union { struct dmx_section_filter *sec; } filter; union { - struct dmx_ts_feed *ts; + /* list of TS and PES feeds (struct dmxdev_feed) */ + struct list_head ts; struct dmx_section_feed *sec; } feed; -- cgit v1.2.3 From 02d22c9b0bfab80d3180aac81f95ca44084fc116 Mon Sep 17 00:00:00 2001 From: Andreas Oberritter Date: Wed, 15 Jul 2009 01:48:37 +0200 Subject: Remove a useless check from dvb_dmx_swfilter_packet() From: Andreas Oberritter Values for 'pid' range from 0 to 0x1fff. Therefore 'feed->pid' can never be equal to both 'pid' and 0x2000. This makes the continue statement have no effect. Priority: normal Signed-off-by: Andreas Oberritter --- linux/drivers/media/dvb/dvb-core/dvb_demux.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'linux/drivers/media/dvb/dvb-core') diff --git a/linux/drivers/media/dvb/dvb-core/dvb_demux.c b/linux/drivers/media/dvb/dvb-core/dvb_demux.c index cfe2768d2..eef6d3616 100644 --- a/linux/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/linux/drivers/media/dvb/dvb-core/dvb_demux.c @@ -425,13 +425,9 @@ no_dvb_demux_tscheck: if ((DVR_FEED(feed)) && (dvr_done++)) continue; - if (feed->pid == pid) { + if (feed->pid == pid) dvb_dmx_swfilter_packet_type(feed, buf); - if (DVR_FEED(feed)) - continue; - } - - if (feed->pid == 0x2000) + else if (feed->pid == 0x2000) feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK); } } -- cgit v1.2.3 From d614ff9f8b6297350f6d1690599733960e186b77 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 21 Jul 2009 09:17:24 -0300 Subject: backport commit 405f55712dfe464b3240d7816cc4fe4174831be2 kernel-sync: Author: Alexey Dobriyan Date: Sat Jul 11 22:08:37 2009 +0400 headers: smp_lock.h redux * Remove smp_lock.h from files which don't need it (including some headers!) * Add smp_lock.h to files which do need it * Make smp_lock.h include conditional in hardirq.h It's needed only for one kernel_locked() usage which is under CONFIG_PREEMPT This will make hardirq.h inclusion cheaper for every PREEMPT=n config (which includes allmodconfig/allyesconfig, BTW) Priority: normal Signed-off-by: Mauro Carvalho Chehab --- linux/drivers/media/dvb/dvb-core/dvbdev.h | 1 - 1 file changed, 1 deletion(-) (limited to 'linux/drivers/media/dvb/dvb-core') diff --git a/linux/drivers/media/dvb/dvb-core/dvbdev.h b/linux/drivers/media/dvb/dvb-core/dvbdev.h index 79927305e..487919bea 100644 --- a/linux/drivers/media/dvb/dvb-core/dvbdev.h +++ b/linux/drivers/media/dvb/dvb-core/dvbdev.h @@ -27,7 +27,6 @@ #include #include #include -#include #define DVB_MAJOR 212 -- cgit v1.2.3