]> git.hungrycats.org Git - linux/commitdiff
[PATCH] dvb: Update DVB core
authorAndrew Morton <akpm@osdl.org>
Tue, 30 Dec 2003 07:41:31 +0000 (23:41 -0800)
committerLinus Torvalds <torvalds@home.osdl.org>
Tue, 30 Dec 2003 07:41:31 +0000 (23:41 -0800)
From: Michael Hunold <hunold@linuxtv.org>

add a parameter to dvb_filter_pes2ts function to specify whether the packet
is a payload unit start or not.

new section demux code by emard

change license GPL -> LGPL for dvb_ringbuffer, like all other DVB core files

fix rare crash on invalid packets, patch by Asier Aguirre

i2c: copy the data variable as well on register client so that detach sees it.

drivers/media/dvb/dvb-core/demux.h
drivers/media/dvb/dvb-core/dvb_demux.c
drivers/media/dvb/dvb-core/dvb_demux.h
drivers/media/dvb/dvb-core/dvb_filter.c
drivers/media/dvb/dvb-core/dvb_filter.h
drivers/media/dvb/dvb-core/dvb_i2c.c
drivers/media/dvb/dvb-core/dvb_ksyms.c
drivers/media/dvb/dvb-core/dvb_ringbuffer.c
drivers/media/dvb/dvb-core/dvb_ringbuffer.h

index 19f4fe2fe184d9451d5de5cfb8d8c9b38185614f..8ff49c0f7a034fae55066494a6956d9fab8b83ad 100644 (file)
 #define DMX_MAX_FILTER_SIZE 18
 #endif 
 
+/*
+ * DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed filter.
+ */ 
+
+#ifndef DMX_MAX_SECFEED_SIZE 
+#define DMX_MAX_SECFEED_SIZE 4096
+#endif 
+
+
 /*
  * enum dmx_success: Success codes for the Demux Callback API. 
  */ 
@@ -143,9 +152,9 @@ struct dmx_section_feed {
         int check_crc;
        u32 crc_val;
 
-        u8 secbuf[4096];
-        int secbufp;
-        int seclen;
+        u8 *secbuf;
+        u8 secbuf_base[DMX_MAX_SECFEED_SIZE];
+        u16 secbufp, seclen, tsfeedp;
 
         int (*set) (struct dmx_section_feed* feed, 
                    u16 pid, 
index e0181c00cc6800021b30b2f1f48a1382d75c45a6..41b5dab890a14505e89d804afbbcebc5a1ec50a5 100644 (file)
 #include "dvb_functions.h"
 
 #define NOBUFS  
+/* 
+** #define DVB_DEMUX_SECTION_LOSS_LOG to monitor payload loss in the syslog
+*/
+// #define DVB_DEMUX_SECTION_LOSS_LOG
+
 
 LIST_HEAD(dmx_muxs);
 
@@ -87,7 +92,7 @@ static inline u16 ts_pid(const u8 *buf)
 }
 
 
-static inline int payload(const u8 *tsp)
+static inline u8 payload(const u8 *tsp)
 {
        if (!(tsp[3]&0x10)) // no payload?
                return 0;
@@ -188,9 +193,7 @@ static inline int dvb_dmx_swfilter_section_feed (struct dvb_demux_feed *feed)
        struct dvb_demux_filter *f = feed->filter;
        struct dmx_section_feed *sec = &feed->feed.sec;
        u8 *buf = sec->secbuf;
-
-       if (sec->secbufp != sec->seclen)
-               return -1;
+       int section_syntax_indicator;
 
        if (!sec->is_filtering)
                return 0;
@@ -198,15 +201,19 @@ static inline int dvb_dmx_swfilter_section_feed (struct dvb_demux_feed *feed)
        if (!f)
                return 0;
 
-       if (sec->check_crc && demux->check_crc32(feed, sec->secbuf, sec->seclen))
+       if (sec->check_crc) {
+               section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0);
+               if (section_syntax_indicator &&
+                   demux->check_crc32(feed, sec->secbuf, sec->seclen))
                return -1;
+       }
 
        do {
                if (dvb_dmx_swfilter_sectionfilter(feed, f) < 0)
                        return -1;
        } while ((f = f->next) && sec->is_filtering);
 
-       sec->secbufp = sec->seclen = 0;
+       sec->seclen = 0;
 
        memset(buf, 0, DVB_DEMUX_MASK_MAX);
  
@@ -214,128 +221,147 @@ static inline int dvb_dmx_swfilter_section_feed (struct dvb_demux_feed *feed)
 }
 
 
-static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 *buf) 
+static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
 {
-       struct dvb_demux *demux = feed->demux;
        struct dmx_section_feed *sec = &feed->feed.sec;
-       int p, count;
-       int ccok, rest;
-       u8 cc;
-
-       if (!(count = payload(buf)))
-               return -1;
-
-       p = 188-count;
 
-       cc = buf[3] & 0x0f;
-       ccok = ((feed->cc+1) & 0x0f) == cc ? 1 : 0;
-       feed->cc = cc;
-
-       if (buf[1] & 0x40) { // PUSI set
-               // offset to start of first section is in buf[p] 
-               if (p+buf[p]>187) // trash if it points beyond packet
-                       return -1;
-
-               if (buf[p] && ccok) { // rest of previous section?
-                       // did we have enough data in last packet to calc length?
-                       int tmp = 3 - sec->secbufp;
-
-                       if (tmp > 0 && tmp != 3) {
-                               if (p + tmp >= 187)
-                                       return -1;
-
-                               demux->memcopy (feed, sec->secbuf+sec->secbufp,
-                                              buf+p+1, tmp);
-
-                               sec->seclen = section_length(sec->secbuf);
-
-                               if (sec->seclen > 4096) 
-                                       return -1;
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+       if(sec->secbufp < sec->tsfeedp)
+       {
+               int i, n = sec->tsfeedp - sec->secbufp;
+
+               /* section padding is done with 0xff bytes entirely.
+               ** due to speed reasons, we won't check all of them
+               ** but just first and last
+               */
+               if(sec->secbuf[0] != 0xff || sec->secbuf[n-1] != 0xff)
+               {
+                       printk("dvb_demux.c section ts padding loss: %d/%d\n", 
+                              n, sec->tsfeedp);
+                       printk("dvb_demux.c pad data:");
+                       for(i = 0; i < n; i++)
+                               printk(" %02x", sec->secbuf[i]);
+                       printk("\n");
                        }
-
-                       rest = sec->seclen - sec->secbufp;
-
-                       if (rest == buf[p] && sec->seclen) {
-                               demux->memcopy (feed, sec->secbuf + sec->secbufp,
-                                              buf+p+1, buf[p]);
-                               sec->secbufp += buf[p];
-                               dvb_dmx_swfilter_section_feed(feed);
                        }
+#endif
+
+       sec->tsfeedp = sec->secbufp = sec->seclen = 0;
+       sec->secbuf = sec->secbuf_base;
                }
 
-               p += buf[p] + 1;                // skip rest of last section
-               count = 188 - p;
+/* 
+** Losless Section Demux 1.4 by Emard
+*/
+static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, const u8 *buf, u8 len)
+{
+       struct dvb_demux *demux = feed->demux;
+       struct dmx_section_feed *sec = &feed->feed.sec;
+       u16 limit, seclen, n;
 
-               while (count) {
+       if(sec->tsfeedp >= DMX_MAX_SECFEED_SIZE)
+               return 0;
 
-                       sec->crc_val = ~0;
+       if(sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE)
+       {
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+               printk("dvb_demux.c section buffer full loss: %d/%d\n", 
+                      sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, DMX_MAX_SECFEED_SIZE);
+#endif
+               len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp;
+       }
 
-                       if ((count>2) && // enough data to determine sec length?
-                           ((sec->seclen = section_length(buf+p)) <= count)) {
-                               if (sec->seclen>4096) 
-                                       return -1;
+       if(len <= 0)
+               return 0;
 
-                               demux->memcopy (feed, sec->secbuf, buf+p,
-                                              sec->seclen);
+       demux->memcopy(feed, sec->secbuf_base + sec->tsfeedp, buf, len);
+       sec->tsfeedp += len;
 
-                               sec->secbufp = sec->seclen;
-                               p += sec->seclen;
-                               count = 188 - p;
+       /* -----------------------------------------------------
+       ** Dump all the sections we can find in the data (Emard)
+       */
 
-                               dvb_dmx_swfilter_section_feed(feed);
+       limit = sec->tsfeedp;
+       if(limit > DMX_MAX_SECFEED_SIZE)
+               return -1; /* internal error should never happen */
 
-                               // filling bytes until packet end?
-                               if (count && buf[p]==0xff) 
-                                       count=0;
+       /* to be sure always set secbuf */
+       sec->secbuf = sec->secbuf_base + sec->secbufp;
 
-                       } else { // section continues to following TS packet
-                               demux->memcopy(feed, sec->secbuf, buf+p, count);
-                               sec->secbufp+=count;
-                               count=0;
-                       }
+       for(n = 0; sec->secbufp + 2 < limit; n++)
+       {
+               seclen = section_length(sec->secbuf);
+               if(seclen <= 0 || seclen > DMX_MAX_SECFEED_SIZE 
+                  || seclen + sec->secbufp > limit)
+                       return 0;
+               sec->seclen = seclen;
+               sec->crc_val = ~0;
+               /* dump [secbuf .. secbuf+seclen) */
+               dvb_dmx_swfilter_section_feed(feed);
+               sec->secbufp += seclen; /* secbufp and secbuf moving together is */
+               sec->secbuf += seclen; /* redundand but saves pointer arithmetic */
                }
 
                return 0;
        }
 
-       // section continued below
-       if (!ccok)
-               return -1;
 
-       if (!sec->secbufp) // any data in last ts packet?
-               return -1;
+static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, const u8 *buf) 
+{
+       u8 p, count;
+       int ccok;
+       u8 cc;
 
-       // did we have enough data in last packet to calc section length?
-       if (sec->secbufp < 3) {
-               int tmp = 3 - sec->secbufp;
+       count = payload(buf);
                
-               if (tmp>count)
+       if (count == 0)  /* count == 0 if no payload or out of range */
                        return -1;
 
-               sec->crc_val = ~0;
-
-               demux->memcopy (feed, sec->secbuf + sec->secbufp, buf+p, tmp);
+       p = 188-count; /* payload start */
 
-               sec->seclen = section_length(sec->secbuf);
-
-               if (sec->seclen > 4096) 
-                       return -1;
+       cc = buf[3] & 0x0f;
+       ccok = ((feed->cc+1) & 0x0f) == cc ? 1 : 0;
+       feed->cc = cc;
+       if(ccok == 0)
+       {
+#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
+               dvb_dmx_swfilter_section_new(feed);
+               return 0;
        }
 
-       rest = sec->seclen - sec->secbufp;
-
-       if (rest < 0)
-               return -1;
-
-       if (rest <= count) {    // section completed in this TS packet
-               demux->memcopy (feed, sec->secbuf + sec->secbufp, buf+p, rest);
-               sec->secbufp += rest;
-               dvb_dmx_swfilter_section_feed(feed);
-       } else  {       // section continues in following ts packet
-               demux->memcopy (feed, sec->secbuf + sec->secbufp, buf+p, count);
-               sec->secbufp += count;
+       if(buf[1] & 0x40)
+       {
+               // PUSI=1 (is set), section boundary is here
+               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);
+                       dvb_dmx_swfilter_section_new(feed);
+                       dvb_dmx_swfilter_section_copy_dump(feed, after, after_len);
+               }
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+               else
+                       if(count > 0)
+                               printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count);
+#endif
        }
+       else
+       {
+               // PUSI=0 (is not set), no section boundary
+               const u8 *entire = buf+p;
+               u8 entire_len = count;
 
+               dvb_dmx_swfilter_section_copy_dump(feed, entire, entire_len);
+       }
        return 0;
 }
 
@@ -439,6 +465,50 @@ bailout:
        spin_unlock(&demux->lock);
 }
 
+void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
+{
+       int p = 0,i, j;
+       u8 tmppack[188];
+       spin_lock(&demux->lock);
+
+       if ((i = demux->tsbufp)) {
+               if (count < (j=204-i)) {
+                       memcpy(&demux->tsbuf[i], buf, count);
+                       demux->tsbufp += count;
+                       goto bailout;
+               }
+               memcpy(&demux->tsbuf[i], buf, j);
+               if ((demux->tsbuf[0] == 0x47)|(demux->tsbuf[0]==0xB8))  {
+                       memcpy(tmppack, demux->tsbuf, 188);
+                       if (tmppack[0] == 0xB8) tmppack[0] = 0x47;
+                       dvb_dmx_swfilter_packet(demux, tmppack);
+               }
+               demux->tsbufp = 0;
+               p += j;
+       }
+
+       while (p < count) {
+               if ((buf[p] == 0x47)|(buf[p] == 0xB8)) {
+                       if (count-p >= 204) {
+                               memcpy(tmppack, buf+p, 188);
+                               if (tmppack[0] == 0xB8) tmppack[0] = 0x47;
+                               dvb_dmx_swfilter_packet(demux, tmppack);
+                               p += 204;
+                       } else {
+                               i = count-p;
+                               memcpy(demux->tsbuf, buf+p, i);
+                               demux->tsbufp=i;
+                               goto bailout;
+                       }
+               } else { 
+                       p++;
+               }
+       }
+
+bailout:
+       spin_unlock(&demux->lock);
+}
+
 
 static struct dvb_demux_filter * dvb_dmx_filter_alloc(struct dvb_demux *demux)
 {
@@ -848,6 +918,9 @@ static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
                up(&dvbdmx->mutex);
                return -EINVAL;
        }
+
+       dvbdmxfeed->feed.sec.tsfeedp = 0;
+       dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
        dvbdmxfeed->feed.sec.secbufp=0;
        dvbdmxfeed->feed.sec.seclen=0;
        
@@ -946,7 +1019,9 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
        dvbdmxfeed->cb.sec=callback;
        dvbdmxfeed->demux=dvbdmx;
        dvbdmxfeed->pid=0xffff;
-       dvbdmxfeed->feed.sec.secbufp=0;
+       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;
 
index 742f53e1452739ae412862e82f44ca33620bc11c..98acadbe1b8c447869b4b8c161657127b2a112db 100644 (file)
@@ -127,7 +127,7 @@ struct dvb_demux {
 
 #define DMX_MAX_PID 0x2000
        struct list_head feed_list;
-        u8 tsbuf[188];
+        u8 tsbuf[204];
         int tsbufp;
 
        struct semaphore mutex;
@@ -140,6 +140,7 @@ int dvb_dmx_release(struct dvb_demux *dvbdemux);
 void dvb_dmx_swfilter_packet(struct dvb_demux *dvbdmx, const u8 *buf);
 void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, size_t count);
 void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
+void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count);
 
 int dvbdmx_connect_frontend(struct dmx_demux *demux, struct dmx_frontend *frontend);
 int dvbdmx_disconnect_frontend(struct dmx_demux *demux);
index a9e81251a327acb59d60690f796cd2088c1d210f..829c43820d5ce3833556b05628f60a963b20670d 100644 (file)
@@ -564,14 +564,18 @@ void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
        p2ts->priv=priv;
 }
 
-int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, int len)
+int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
+                     int len, int payload_start)
 {
        unsigned char *buf=p2ts->buf;
        int ret=0, rest;
        
        //len=6+((pes[4]<<8)|pes[5]);
 
+       if (payload_start)
        buf[1]|=0x40;
+       else
+               buf[1]&=~0x40;
        while (len>=184) {
                buf[3]=0x10|((p2ts->cc++)&0x0f);
                memcpy(buf+4, pes, 184);
index 109c691f05a400ecc3060ec4a0a0a6f30d1f7cca..e55f80ca85af767eedb1379cd5abcbfd24b3bc0f 100644 (file)
@@ -37,7 +37,8 @@ struct dvb_filter_pes2ts {
 void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid, 
                            dvb_filter_pes2ts_cb_t *cb, void *priv);
 
-int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, int len);
+int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
+                     int len, int payload_start);
 
 
 #define PROG_STREAM_MAP  0xBC
index 7be068ac634c3b477459d36c0744a3de77f9d1b8..fd4989f4f53ed1a1ece5abe216895c3b1d054780 100644 (file)
@@ -51,6 +51,7 @@ static int register_i2c_client (struct dvb_i2c_bus *i2c, struct dvb_i2c_device *
 
        client->detach = dev->detach;
        client->owner = dev->owner;
+       client->data = dev->data;
 
        INIT_LIST_HEAD(&client->list_head);
 
index ccc0de7cd233d59be4f002b4df110e3a3dbf001a..6b471c44c0af754166ae904fb44f4b5710906abf 100644 (file)
@@ -18,6 +18,7 @@ EXPORT_SYMBOL(dvb_dmx_release);
 EXPORT_SYMBOL(dvb_dmx_swfilter_packet);
 EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
 EXPORT_SYMBOL(dvb_dmx_swfilter);
+EXPORT_SYMBOL(dvb_dmx_swfilter_204);
 EXPORT_SYMBOL(dvbdmx_connect_frontend);
 EXPORT_SYMBOL(dvbdmx_disconnect_frontend);
 
index 86674212a9e31bdad60c58cdf358f13d83d2fba6..c2fa6e04a7311e9d6a4f5923f2d2d1199ae97877 100644 (file)
@@ -9,24 +9,18 @@
  *                       & 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
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
  * 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.
- * 
+ * GNU Lesser General Public License for more details.
  *
- * You should have received a copy of the GNU General Public License
+ * You should have received a copy of the GNU Lesser 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/
  */
 
 
@@ -167,11 +161,11 @@ ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
 }
 
 
-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);
+EXPORT_SYMBOL(dvb_ringbuffer_init);
+EXPORT_SYMBOL(dvb_ringbuffer_empty);
+EXPORT_SYMBOL(dvb_ringbuffer_free);
+EXPORT_SYMBOL(dvb_ringbuffer_avail);
+EXPORT_SYMBOL(dvb_ringbuffer_flush);
+EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
+EXPORT_SYMBOL(dvb_ringbuffer_read);
+EXPORT_SYMBOL(dvb_ringbuffer_write);
index d0f791602c17ab82c31d5354ba120ae94b797ed0..9e6feebe8dacb7cf87576f1222ee070f5f999edd 100644 (file)
@@ -16,7 +16,7 @@
  * 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.
+ * GNU Lesser General Public License for more details.
  * 
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program; if not, write to the Free Software