vserver 1.9.5.x5
[linux-2.6.git] / drivers / media / dvb / dvb-core / dvb_demux.c
index ad096f1..7901398 100644 (file)
@@ -31,7 +31,6 @@
 #include <asm/uaccess.h>
 
 #include "dvb_demux.h"
-#include "dvb_functions.h"
 
 #define NOBUFS  
 /* 
@@ -160,7 +159,7 @@ static inline int dvb_dmx_swfilter_payload (struct dvb_demux_feed *feed, const u
 
        feed->peslen += count;
 
-       return feed->cb.ts (&buf[p], count, 0, 0, &feed->feed.ts, DMX_OK); 
+       return feed->cb.ts (&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK); 
 }
 
 
@@ -179,11 +178,11 @@ static int dvb_dmx_swfilter_sectionfilter (struct dvb_demux_feed *feed,
                neq |= f->maskandnotmode[i] & xor;
        }
 
-       if (f->doneq & !neq)
+       if (f->doneq && !neq)
                return 0;
 
        return feed->cb.sec (feed->feed.sec.secbuf, feed->feed.sec.seclen, 
-                            0, 0, &f->filter, DMX_OK); 
+                            NULL, 0, &f->filter, DMX_OK); 
 }
 
 
@@ -248,7 +247,22 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
                }
 
 /* 
-** Losless Section Demux 1.4 by Emard
+** Losless Section Demux 1.4.1 by Emard
+** Valsecchi Patrick:
+**  - middle of section A  (no PUSI)
+**  - end of section A and start of section B 
+**    (with PUSI pointing to the start of the second section)
+**  
+**  In this case, without feed->pusi_seen you'll receive a garbage section
+**  consisting of the end of section A. Basically because tsfeedp
+**  is incemented and the use=0 condition is not raised
+**  when the second packet arrives.
+**
+** Fix:
+** when demux is started, let feed->pusi_seen = 0 to
+** prevent initial feeding of garbage from the end of
+** previous section. When you for the first time see PUSI=1
+** then set feed->pusi_seen = 1
 */
 static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, const u8 *buf, u8 len)
 {
@@ -294,7 +308,12 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, const
                sec->seclen = seclen;
                sec->crc_val = ~0;
                /* dump [secbuf .. secbuf+seclen) */
+               if(feed->pusi_seen)
                dvb_dmx_swfilter_section_feed(feed);
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+               else
+                       printk("dvb_demux.c pusi not seen, discarding section data\n");
+#endif
                sec->secbufp += seclen; /* secbufp and secbuf moving together is */
                sec->secbuf += seclen; /* redundand but saves pointer arithmetic */
                }
@@ -306,7 +325,7 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, const
 static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 *buf) 
 {
        u8 p, count;
-       int ccok;
+       int ccok, dc_i = 0;
        u8 cc;
 
        count = payload(buf);
@@ -317,31 +336,41 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8
        p = 188-count; /* payload start */
 
        cc = buf[3] & 0x0f;
-       ccok = ((feed->cc+1) & 0x0f) == cc ? 1 : 0;
+       ccok = ((feed->cc + 1) & 0x0f) == cc;
        feed->cc = cc;
-       if(ccok == 0)
-       {
+
+       if (buf[3] & 0x20) {
+               /* adaption field present, check for discontinuity_indicator */
+               if ((buf[4] > 0) && (buf[5] & 0x80))
+                       dc_i = 1;
+       }
+
+       if (!ccok || dc_i) {
 #ifdef DVB_DEMUX_SECTION_LOSS_LOG
                printk("dvb_demux.c discontinuity detected %d bytes lost\n", count);
                /* those bytes under sume circumstances will again be reported
                ** in the following dvb_dmx_swfilter_section_new
                */
 #endif
+               /* Discontinuity detected. Reset pusi_seen = 0 to
+               ** stop feeding of suspicious data until next PUSI=1 arrives
+               */
+               feed->pusi_seen = 0;
                dvb_dmx_swfilter_section_new(feed);
                return 0;
        }
 
-       if(buf[1] & 0x40)
-       {
+       if (buf[1] & 0x40) {
                // PUSI=1 (is set), section boundary is here
-               if(count > 1 && buf[p] < count)
-               {
+               if (count > 1 && buf[p] < count) {
                        const u8 *before = buf+p+1;
                        u8 before_len = buf[p];
                        const u8 *after = before+before_len;
                        u8 after_len = count-1-before_len;
 
                        dvb_dmx_swfilter_section_copy_dump(feed, before, before_len);
+                       /* before start of new section, set pusi_seen = 1 */
+                       feed->pusi_seen = 1;
                        dvb_dmx_swfilter_section_new(feed);
                        dvb_dmx_swfilter_section_copy_dump(feed, after, after_len);
                }
@@ -350,9 +379,7 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8
                        if(count > 0)
                                printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count);
 #endif
-       }
-       else
-       {
+       } else {
                // PUSI=0 (is not set), no section boundary
                const u8 *entire = buf+p;
                u8 entire_len = count;
@@ -373,7 +400,7 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, con
                        if (feed->ts_type & TS_PAYLOAD_ONLY)
                                dvb_dmx_swfilter_payload(feed, buf);
                        else
-                               feed->cb.ts(buf, 188, 0, 0, &feed->feed.ts, DMX_OK); 
+                               feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK); 
                }
                if (feed->ts_type & TS_DECODER) 
                        if (feed->demux->write_to_decoder)
@@ -422,10 +449,10 @@ void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
                }
 
                if (feed->pid == 0x2000)
-                       feed->cb.ts(buf, 188, 0, 0, &feed->feed.ts, DMX_OK);
+                       feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
        }
 }
-
+EXPORT_SYMBOL(dvb_dmx_swfilter_packet);
 
 void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, size_t count)
 {
@@ -440,6 +467,7 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, size_t cou
 
        spin_unlock(&demux->lock);
 }
+EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
 
 
 void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
@@ -479,6 +507,7 @@ void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
 bailout:
        spin_unlock(&demux->lock);
 }
+EXPORT_SYMBOL(dvb_dmx_swfilter);
 
 void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
 {
@@ -523,6 +552,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
 bailout:
        spin_unlock(&demux->lock);
 }
+EXPORT_SYMBOL(dvb_dmx_swfilter_204);
 
 
 static struct dvb_demux_filter * dvb_dmx_filter_alloc(struct dvb_demux *demux)
@@ -570,24 +600,30 @@ static int dvb_demux_feed_find(struct dvb_demux_feed *feed)
 
 static void dvb_demux_feed_add(struct dvb_demux_feed *feed)
 {
+       spin_lock_irq(&feed->demux->lock);
        if (dvb_demux_feed_find(feed)) {
                printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n",
                                __FUNCTION__, feed->type, feed->state, feed->pid);
-               return;
+               goto out;
        }
 
        list_add(&feed->list_head, &feed->demux->feed_list);
+out:
+       spin_unlock_irq(&feed->demux->lock);
 }
 
 static void dvb_demux_feed_del(struct dvb_demux_feed *feed)
 {
+       spin_lock_irq(&feed->demux->lock);
        if (!(dvb_demux_feed_find(feed))) {
                printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n",
                                __FUNCTION__, feed->type, feed->state, feed->pid);
-               return;
+               goto out;
 }
 
        list_del(&feed->list_head);
+out:
+       spin_unlock_irq(&feed->demux->lock);
 }
 
 static int dmx_ts_feed_set (struct dmx_ts_feed* ts_feed, u16 pid, int ts_type, 
@@ -637,7 +673,7 @@ static int dmx_ts_feed_set (struct dmx_ts_feed* ts_feed, u16 pid, int ts_type,
 
        if (feed->buffer_size) {
 #ifdef NOBUFS
-               feed->buffer=0;
+               feed->buffer=NULL;
 #else
                feed->buffer = vmalloc(feed->buffer_size);
                if (!feed->buffer) {
@@ -736,11 +772,11 @@ static int dvbdmx_allocate_ts_feed (struct dmx_demux *dmx, struct dmx_ts_feed **
        feed->demux = demux;
        feed->pid = 0xffff;
        feed->peslen = 0xfffa;
-       feed->buffer = 0;
+       feed->buffer = NULL;
 
        (*ts_feed) = &feed->feed.ts;
        (*ts_feed)->parent = dmx;
-       (*ts_feed)->priv = 0;
+       (*ts_feed)->priv = NULL;
        (*ts_feed)->is_filtering = 0;
        (*ts_feed)->start_filtering = dmx_ts_feed_start_filtering;
        (*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering;
@@ -776,10 +812,8 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, struct dmx_ts_feed *ts_
        }
 
 #ifndef NOBUFS
-       if (feed->buffer) { 
                vfree(feed->buffer);
                feed->buffer=0;
-       }
 #endif
 
        feed->state = DMX_STATE_FREE;
@@ -789,7 +823,7 @@ static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, struct dmx_ts_feed *ts_
 
                feed->pid = 0xffff;
        
-       if (feed->ts_type & TS_DECODER)
+       if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER)
                demux->pesfilter[feed->pes_type] = NULL;
 
        up(&demux->mutex);
@@ -820,7 +854,7 @@ static int dmx_section_feed_allocate_filter(struct dmx_section_feed* feed,
        spin_lock_irq(&dvbdemux->lock);
        *filter=&dvbdmxfilter->filter;
        (*filter)->parent=feed;
-       (*filter)->priv=0;
+       (*filter)->priv=NULL;
        dvbdmxfilter->feed=dvbdmxfeed;
        dvbdmxfilter->type=DMX_TYPE_SEC;
        dvbdmxfilter->state=DMX_STATE_READY;
@@ -858,7 +892,7 @@ static int dmx_section_feed_set(struct dmx_section_feed* feed,
 
        dvbdmxfeed->feed.sec.check_crc=check_crc;
 #ifdef NOBUFS
-       dvbdmxfeed->buffer=0;
+       dvbdmxfeed->buffer=NULL;
 #else
        dvbdmxfeed->buffer=vmalloc(dvbdmxfeed->buffer_size);
        if (!dvbdmxfeed->buffer) {
@@ -1015,13 +1049,13 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
        dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
        dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0;
        dvbdmxfeed->feed.sec.tsfeedp = 0;
-       dvbdmxfeed->filter=0;
-       dvbdmxfeed->buffer=0;
+       dvbdmxfeed->filter=NULL;
+       dvbdmxfeed->buffer=NULL;
 
        (*feed)=&dvbdmxfeed->feed.sec;
        (*feed)->is_filtering=0;
        (*feed)->parent=demux;
-       (*feed)->priv=0;
+       (*feed)->priv=NULL;
 
        (*feed)->set=dmx_section_feed_set;
        (*feed)->allocate_filter=dmx_section_feed_allocate_filter;
@@ -1047,10 +1081,8 @@ static int dvbdmx_release_section_feed(struct dmx_demux *demux,
                return -EINVAL;
        }
 #ifndef NOBUFS
-       if (dvbdmxfeed->buffer) {
                vfree(dvbdmxfeed->buffer);
                dvbdmxfeed->buffer=0;
-       }
 #endif
        dvbdmxfeed->state=DMX_STATE_FREE;
 
@@ -1158,6 +1190,7 @@ int dvbdmx_connect_frontend(struct dmx_demux *demux, struct dmx_frontend *fronte
        up(&dvbdemux->mutex);
        return 0;
 }
+EXPORT_SYMBOL(dvbdmx_connect_frontend);
 
 
 int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
@@ -1171,6 +1204,7 @@ int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
        up(&dvbdemux->mutex);
        return 0;
 }
+EXPORT_SYMBOL(dvbdmx_disconnect_frontend);
 
 
 static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 *pids)
@@ -1223,7 +1257,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
         if (!dvbdemux->memcopy)
                 dvbdemux->memcopy = dvb_dmx_memcopy;
 
-       dmx->frontend=0;
+       dmx->frontend=NULL;
        dmx->reg_list.prev = dmx->reg_list.next = &dmx->reg_list;
        dmx->priv=(void *) dvbdemux;
        dmx->open=dvbdmx_open;
@@ -1251,6 +1285,7 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
 
        return 0;
 }
+EXPORT_SYMBOL(dvb_dmx_init);
 
 
 int dvb_dmx_release(struct dvb_demux *dvbdemux)
@@ -1258,9 +1293,9 @@ int dvb_dmx_release(struct dvb_demux *dvbdemux)
        struct dmx_demux *dmx = &dvbdemux->dmx;
 
        dmx_unregister_demux(dmx);
-       if (dvbdemux->filter)
                vfree(dvbdemux->filter);
-       if (dvbdemux->feed)
                vfree(dvbdemux->feed);
        return 0;
 }
+EXPORT_SYMBOL(dvb_dmx_release);
+