Re: DVB-S2 multistream support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



hello Christian,

first of all thank you for the great work. so, i have few follow-ups about it:

1. since your current patch contains patches that are kernel-specific
changes (i.e. some general changes to the V4L code for the kernel you
use), changes related to the BBFrame-support and hardware-specific
changes (i.e. related to the TBS 6925 card, which at the moment is the
only affordable hardware at least i know that can handle BBFrames) in
order for more easy use in different kernels as well for the purpose
of others to review the changes related to the BBFrame-support in V4L
'dvb-core' i split your patch to 3 separate patches (they are attached
to this email):

- 01-bb-dmx.patch : it's supposed to contains all changes you made to
the demux part of V4L 'dvb-core' - i didn't make any further changes -
just collected your original changes in the patch; it should apply
clean to all recent kernel released in the last several months (i
believe at least in the last 6 months), because no changes in this
parts of 'dvb-core' were made recently

- 02-bb-fe.patch : those are changes for BBFrame-support related to
the frontend - i separated those changes and i didn't include them in
'01-bb-dmx.patch', because recently a lot of changes were made to that
part of V4L. so, this patch will apply clean to
"tbs-linux-drivers_v120206" and to other V4L trees most probably it
will require to manually apply the changes to the respective files,
but since it changes less than 10 lines in only 3 files that's just
fine for manual patching

- 03-bb-tbs.patch : those are all changes specific to the TBS 6925
hardware. additionally to your changes i defined "tsout" module
parameter to both 'stv090x' and 'saa716x_tbs-dvb' - that's convenient
to change between TS and BB mode just with reloading the modules with
rmmod/modprobe

2. so i used the above 3 patches with "tbs-linux-drivers_v120206" and
after i applied them:

# cd linux-tbs-drivers
# patch -p1 < ../01-bb-dmx.patch
# patch -p1 < ../02-bb-fe.patch
# patch -p1 < ../03-bb-tbs.patch

the driver builds successfully, but i'm not sure if i didn't miss
something from your original patch. also, i put file called
'tbs6925.conf' in /etc/modprobe.d with lines in it:

options stv090x tsout=0
options saa716x_tbs-dvb tsout=0

for easy enable/disable of the BB mode with just reloading the modules
in order to make the testing easier.

3. so on the test i did every few seconds i get the following errors:

_dvb_dmx_swfilter_bbframe: invalid use of reserved TS/GS value 1

_dvb_dmx_swfilter_bbframe: invalid data field length (length 0, left 10)

and hex-dump of the BBFrame data. is that supposed to happen? please,
can you confirm if it happens or not in your environment with your
original patch or i messed-up something when i prepared the 3 patches
from point 1. so, that request is in relation to my seconds request -
please, review the 3 patches from point 1 and confirm they are correct
and i didn't miss anything - if they are correct patch 01 and 02 can
be used for review of the code.

many thanks,
konstantin

On Mon, Mar 19, 2012 at 10:46 AM, Christian Prähauser
<cpraehaus@xxxxxxxxxxxxxx> wrote:
> Dear all,
>
> I decided to post a patch against the TBS drivers for all those who want to
> experiment
> with the very preliminary base-band demultiplexer until I have a repository
> to properly host
> this stuff. Currently it only works for the
> TBS 6925 card. The bb-dmx was created for Linux v3.3, so the patch also
> contains some
> changes that made it into Linux since TBS driver release v111118. You can
> get the TBS source
> code via this direct link (I know there's a newer version but the patch is
> against the old driver package):
>
> http://www.tbsdtv.com/download/document/common/tbs-linux-drivers_v111118.zip
>
> And then you can download the bb-dmx patch from here:
>
> http://www.cosy.sbg.ac.at/~cpraehaus/download/tbs_v111118_bb-dmx_2012-03-19.patch.gz
>
>
> Tuning and configuration of the card is as normal, notice however that the
> card is currently
> put in base-band data mode irrespective of any configuration. This means
> that you probably wont
> be able to receive DVB-S.
>
> To test the bb-dmx support, there is a patch against dvbsnoop 1.4.5. You can
> get the source from the SF site:
>
> http://dvbsnoop.sourceforge.net/
>
> and the patch from here:
>
> http://www.cosy.sbg.ac.at/~cpraehaus/download/dvbsnoop-1.4.50_bb-dmx_2012-03-19.patch
>
> Usage:
> dvbsnoop -s bb <ISI>    (receive bbframes from <ISI>)
>
> dvbsnoop -s bb -tsraw   (receive everything)
>
>
> Sorry, its still all very experimental and DVB-S2 specific, but I'd be happy
> to get feedback from those interested.
>
> Thanks and kind regards,
> Christian.
>
>
> Am 15.03.2012 um 10:40 schrieb Christian Prähauser:
>
>
>> Dear all,
>>
>> First, thanks for your interest in this functionality. I think the
>> modifications
>> are in a shape where they begin to be useful for others. Currently
>> I'm (still) trying to get some GIT repo where I can host the whole stuff.
>>
>> Thank you all for your support, testing will indeed by important after the
>> first
>> version is "in the wild" :-). I definitely want to keep this going and be
>> sure
>> that I tell you as soon as the code can be accessed.
>>
>> Kind regards,
>> Christian.
>>
>> Am 13.03.2012 um 16:47 schrieb Bob W:
>>
>>>
>>>
>>> Hi Konstantin,
>>>
>>>
>>>> all work to support BBFrames in the Linux kernel is done by Christian
>>>> - in fact it's a long lost work from 5 years ago:
>>>>
>>>> http://www.linuxtv.org/pipermail/linux-dvb/2007-December/022217.html
>>>
>>>
>>> yep, I have followed the history back...  and like Christian said, the
>>> old repo is nolonger working.  :(
>>>
>>>>
>>>> and i hope it won't be lost again. i just encouraged Christian that
>>>> his work is important and there are people interested in it - you're
>>>> one such example. so, i offered Christian to help him with i can. i
>>>> guess more people appreciating what his doing and encourage him will
>>>> give him better motivation to release the code to the public. however,
>>>> i guess the delay is more, because it's not easy and it requires time
>>>> to prepare the code for initial public release and that's why the
>>>> delay. so, i don't have Christian's code and i'm eager as you're to be
>>>> able to try it out, but we need to be patient. i'm sure that after
>>>> there is some public release and repository more people will be
>>>> interested to contribute to that work.
>>>>
>>>> best regards,
>>>> konstantin
>>>
>>>
>>>
>>> Agreed, I understand the pressure of releasing publicly.  Once released,
>>> the nit picking begins.. lol.   I will keep watch on the list.
>>> Christian, if you want an extra tester to help yah, count me in.  I'll
>>> help also with what I can.
>>>
>>> Bob
>>>
>>>
>>>
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-media" in
>>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>>
>> ---
>> Dipl.-Ing. Christian Praehauser <cpraehaus@xxxxxxxxxxxxxx>
>>
>> || //\\//\\ || Multimedia Communications Group,
>> ||//  \/  \\|| Department of Computer Sciences, University of Salzburg
>> http://www.cosy.sbg.ac.at/~cpraehaus/
>> http://www.network-research.org/
>> http://www.uni-salzburg.at/
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-media" in
>> the body of a message to majordomo@xxxxxxxxxxxxxxx
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>
> ---
> Dipl.-Ing. Christian Praehauser <cpraehaus@xxxxxxxxxxxxxx>
>
> || //\\//\\ || Multimedia Communications Group,
> ||//  \/  \\|| Department of Computer Sciences, University of Salzburg
> http://www.cosy.sbg.ac.at/~cpraehaus/
> http://www.network-research.org/
> http://www.uni-salzburg.at/
--- a/linux/include/linux/dvb/dmx.h	2012-03-19 14:39:46.185144879 +0200
+++ b/linux/include/linux/dvb/dmx.h	2012-03-19 14:38:26.913145875 +0200
@@ -141,6 +141,52 @@
 	__u64 stc;		/* output: stc in 'base'*90 kHz units */
 };
 
+/**
+ * Base-band filter output types.
+ */
+typedef enum {
+	/// Only deliver Transport Stream packets received with frames using TS compatibility mode
+	DMX_BB_TSCOMPAT = 0,
+	/// Output raw BBFrames
+	DMX_BB_FRAME,
+	/// Only deliver generic continuous stream data (not including BBFrame header)
+	DMX_BB_CONT,
+	/// Only deliver generic packetized stream data (not including BBFrame header)
+	DMX_BB_PACK
+} dmx_bb_type_t;
+
+/**
+ * @brief Special ISI value for receiving only SIS-mode streams.
+ * @note this filter wont deliver any data if the channel uses multiple 
+ * input stream mode (MIS-mode),
+ */
+#define DMX_ISI_SIS	-1
+/**
+ * @brief Special ISI value for receiving all available input sreams.
+ * @note This value is only allowed for base-band filter type DMX_BB_FRAME
+ */
+#define DMX_ISI_ALL	-2
+
+struct dmx_bb_filter_params
+{
+	/**
+	 * @brief Identifies a single base-band stream multiplexed on a single channel.
+	 * This may be an input stream for DVB-S2 or a physical layer pipe (PLP) in the case
+	 * of DVB-T2.
+	 */
+	__s16		isi;
+	dmx_input_t	input;
+	/**
+	 * @brief Tells the filter where the data should be routed to (e.g. dvr device or 
+	 * demux file handle.
+	 */
+	dmx_output_t	output;
+	/**
+	 * @brief Specifies what type of data should be delivered by this filter.
+	 */
+	dmx_bb_type_t	type;
+	__u32		flags;
+};
 
 #define DMX_START                _IO('o', 41)
 #define DMX_STOP                 _IO('o', 42)
@@ -153,5 +199,6 @@
 #define DMX_GET_STC              _IOWR('o', 50, struct dmx_stc)
 #define DMX_ADD_PID              _IOW('o', 51, __u16)
 #define DMX_REMOVE_PID           _IOW('o', 52, __u16)
+#define DMX_SET_BB_FILTER       _IOW('o', 53, struct dmx_bb_filter_params)
 
 #endif /*_DVBDMX_H_*/
--- a/linux/drivers/media/dvb/dvb-core/demux.h	2012-03-19 14:39:46.117144880 +0200
+++ b/linux/drivers/media/dvb/dvb-core/demux.h	2012-03-19 14:38:26.893145875 +0200
@@ -173,6 +173,32 @@
 };
 
 /*--------------------------------------------------------------------------*/
+/* Base-band frame reception */
+/*--------------------------------------------------------------------------*/
+
+/// @brief Deliver full BBFrames (incl. header) to demux feed (default)
+#define BB_FRAME	0x01
+/// @brief Deliver Packetized Generic Stream to demux feed
+#define BB_PACK_GS	0x00
+/// @brief Deliver Continues Generic Stream to demux feed
+#define BB_CONT_GS	0x40		
+/// @brief Deliver Transport Stream (if stream is using TS-Compatibility mode) to demux feed
+#define BB_TS		0xc0
+
+#define BB_ISI_ALL	DMX_ISI_ALL
+#define BB_ISI_SIS	DMX_ISI_SIS
+
+struct dmx_bb_feed {
+	int is_filtering; /* Set to non-zero when filtering in progress */
+	struct dmx_demux *parent; /* Back-pointer */
+	void *priv; /* Pointer to private data of the API client */
+	int (*set) (struct dmx_bb_feed *feed, int isi, int type, 
+		size_t circular_buffer_size, struct timespec timeout);
+	int (*start_filtering) (struct dmx_bb_feed* feed);
+	int (*stop_filtering) (struct dmx_bb_feed* feed);
+};
+
+/*--------------------------------------------------------------------------*/
 /* Callback functions */
 /*--------------------------------------------------------------------------*/
 
@@ -190,6 +216,9 @@
 				struct dmx_section_filter * source,
 				enum dmx_success success);
 
+typedef void (*dmx_bb_cb)(const u8 *buffer, size_t len, size_t upl, 
+	struct dmx_bb_feed* source, enum dmx_success success);
+
 /*--------------------------------------------------------------------------*/
 /* DVB Front-End */
 /*--------------------------------------------------------------------------*/
@@ -258,6 +287,11 @@
 				      dmx_section_cb callback);
 	int (*release_section_feed) (struct dmx_demux* demux,
 				     struct dmx_section_feed* feed);
+	int (*allocate_bb_feed) (struct dmx_demux* demux,
+				 struct dmx_bb_feed** feed,
+				 dmx_bb_cb callback);
+	int (*release_bb_feed) (struct dmx_demux* demux,
+				struct dmx_bb_feed* feed);
 	int (*add_frontend) (struct dmx_demux* demux,
 			     struct dmx_frontend* frontend);
 	int (*remove_frontend) (struct dmx_demux* demux,
--- a/linux/drivers/media/dvb/dvb-core/dmxdev.c	2012-03-19 14:39:46.117144880 +0200
+++ b/linux/drivers/media/dvb/dvb-core/dmxdev.c	2012-03-19 14:38:26.893145875 +0200
@@ -428,6 +428,36 @@
 	return 0;
 }
 
+static void dvb_dmxdev_bb_callback(const u8 *buf, size_t len, size_t upl, 
+	struct dmx_bb_feed *feed, enum dmx_success success)
+{
+	struct dmxdev_filter *dmxdevfilter = feed->priv;
+	struct dvb_ringbuffer *buffer;
+	int ret;
+
+	dprintk("dmxdev: bb callback len=%u, upl=%u\n",
+			(unsigned) len, (unsigned) upl);
+
+	spin_lock(&dmxdevfilter->dev->lock);
+
+	if (dmxdevfilter->params.bb.output == DMX_OUT_TAP)
+		buffer = &dmxdevfilter->buffer;
+	else
+		buffer = &dmxdevfilter->dev->dvr_buffer;
+	if (buffer->error) {
+		spin_unlock(&dmxdevfilter->dev->lock);
+		wake_up(&buffer->queue);
+		return;
+	}
+	ret = dvb_dmxdev_buffer_write(buffer, buf, len);
+	if (ret < 0) {
+		dvb_ringbuffer_flush(buffer);
+		buffer->error = ret;
+	}
+	spin_unlock(&dmxdevfilter->dev->lock);
+	wake_up(&buffer->queue);
+}
+
 /* stop feed but only mark the specified filter as stopped (state set) */
 static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
 {
@@ -444,6 +474,9 @@
 		list_for_each_entry(feed, &dmxdevfilter->feed.ts, next)
 			feed->ts->stop_filtering(feed->ts);
 		break;
+	case DMXDEV_TYPE_BB:
+		dmxdevfilter->feed.bb->stop_filtering(dmxdevfilter->feed.bb);
+		break;
 	default:
 		return -EINVAL;
 	}
@@ -470,6 +503,8 @@
 			}
 		}
 		break;
+	case DMXDEV_TYPE_BB:
+		return filter->feed.bb->start_filtering(filter->feed.bb);
 	default:
 		return -EINVAL;
 	}
@@ -527,6 +562,15 @@
 			feed->ts = NULL;
 		}
 		break;
+	case DMXDEV_TYPE_BB:
+		if (!dmxdevfilter->feed.bb)
+			break;
+		dvb_dmxdev_feed_stop(dmxdevfilter);
+		dmxdevfilter->dev->demux->
+		    release_bb_feed(dmxdevfilter->dev->demux,
+				    dmxdevfilter->feed.bb);
+		dmxdevfilter->feed.bb = NULL;
+		break;
 	default:
 		if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED)
 			return 0;
@@ -724,6 +768,46 @@
 			}
 		}
 		break;
+	case DMXDEV_TYPE_BB:
+	{
+		static const int bb_types[] = { BB_TS, BB_FRAME, BB_CONT_GS, BB_PACK_GS };
+		struct timespec timeout = { 0 };
+		struct dmx_bb_filter_params *para = &filter->params.bb;
+		struct dmx_demux *demux = dmxdev->demux;
+		int ret;
+		struct dmx_bb_feed **feed = &filter->feed.bb;
+		
+		ret = demux->allocate_bb_feed(demux, feed, dvb_dmxdev_bb_callback);
+		if (ret < 0) {
+			printk("DVB (%s): could not alloc bb feed\n",
+				       __FUNCTION__);
+			return ret;
+		}
+		
+		(*feed)->priv = filter;
+		ret = (*feed)->set(*feed,
+				para->isi,		/* isi */
+				bb_types[para->type],	/* type */
+				10*7274,   		/* circular buffer size */
+				timeout			/* timeout */
+				);
+		if (ret < 0) {
+			printk("DVB (%s): could not set bb feed\n",
+				       __FUNCTION__);
+			demux->release_bb_feed(demux, *feed);
+			return ret;
+		}
+		
+		ret = (*feed)->start_filtering(*feed);
+		if (ret < 0) {
+			printk("DVB (%s): could not start filtering on bb feed\n",
+				       __FUNCTION__);
+			dmxdev->demux->release_bb_feed(dmxdev->demux,
+						       *feed);
+			return ret;
+		}
+		break;
+	}
 	default:
 		return -EINVAL;
 	}
@@ -901,6 +985,29 @@
 	return 0;
 }
 
+static int dvb_dmxdev_bb_filter_set(struct dmxdev *dmxdev,
+				     struct dmxdev_filter *dmxdevfilter,
+				     struct dmx_bb_filter_params *params)
+{
+	dvb_dmxdev_filter_stop(dmxdevfilter);
+
+	if (params->output != DMX_OUT_TAP && params->output != DMX_OUT_TS_TAP)
+		return -EINVAL;
+	else if (params->type < DMX_BB_TSCOMPAT || params->type > DMX_BB_PACK)
+		return -EINVAL;
+	
+	dmxdevfilter->type = DMXDEV_TYPE_BB;
+	memcpy(&dmxdevfilter->params, params,
+	       sizeof(struct dmx_bb_filter_params));
+
+	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
+
+	if (params->flags & DMX_IMMEDIATE_START)
+		return dvb_dmxdev_filter_start(dmxdevfilter);
+
+	return 0;
+}
+
 static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil,
 				   struct file *file, char __user *buf,
 				   size_t count, loff_t *ppos)
@@ -1014,6 +1121,15 @@
 		mutex_unlock(&dmxdevfilter->mutex);
 		break;
 
+	case DMX_SET_BB_FILTER:
+		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+			mutex_unlock(&dmxdev->mutex);
+			return -ERESTARTSYS;
+		}
+		ret = dvb_dmxdev_bb_filter_set(dmxdev, dmxdevfilter, parg);
+		mutex_unlock(&dmxdevfilter->mutex);
+		break;
+
 	case DMX_SET_BUFFER_SIZE:
 		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
 			mutex_unlock(&dmxdev->mutex);
--- a/linux/drivers/media/dvb/dvb-core/dmxdev.h	2012-03-19 14:39:46.117144880 +0200
+++ b/linux/drivers/media/dvb/dvb-core/dmxdev.h	2012-03-19 14:38:26.893145875 +0200
@@ -43,6 +43,7 @@
 	DMXDEV_TYPE_NONE,
 	DMXDEV_TYPE_SEC,
 	DMXDEV_TYPE_PES,
+	DMXDEV_TYPE_BB
 };
 
 enum dmxdev_state {
@@ -69,11 +70,13 @@
 		/* list of TS and PES feeds (struct dmxdev_feed) */
 		struct list_head ts;
 		struct dmx_section_feed *sec;
+		struct dmx_bb_feed *bb;
 	} feed;
 
 	union {
 		struct dmx_sct_filter_params sec;
 		struct dmx_pes_filter_params pes;
+		struct dmx_bb_filter_params bb;
 	} params;
 
 	enum dmxdev_type type;
--- a/linux/drivers/media/dvb/dvb-core/dvb_demux.c	2012-03-19 14:39:46.117144880 +0200
+++ b/linux/drivers/media/dvb/dvb-core/dvb_demux.c	2012-03-19 14:38:26.897145875 +0200
@@ -21,6 +21,7 @@
  *
  */
 
+#include <linux/version.h>
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 #include <linux/slab.h>
@@ -32,6 +33,8 @@
 #include <asm/uaccess.h>
 #include <asm/div64.h>
 
+#include <linux/dvb/frontend.h>
+
 #include "dvb_demux.h"
 
 #define NOBUFS
@@ -40,6 +43,16 @@
 */
 // #define DVB_DEMUX_SECTION_LOSS_LOG
 
+/**
+ * @brief Use table-driven CRC-8 calculation for Base-band demultiplexer
+ */
+#define BB_CRC8_TABLE_DRIVEN	1
+
+/**
+ * Define this to enable verbose debugging information from the Base-band demux
+ */
+//#define DVB_DEMUX_DEBUG_BB
+
 static int dvb_demux_tscheck;
 module_param(dvb_demux_tscheck, int, 0644);
 MODULE_PARM_DESC(dvb_demux_tscheck,
@@ -55,6 +68,35 @@
 			printk(x);                              \
 	} while (0)
 
+#ifdef BB_CRC8_TABLE_DRIVEN
+
+/* CRC-8 table for generator polynom 0xd5
+ * Created with PYCRC (http://www.tty1.net/pycrc/) using the following commandline:
+ * python pycrc.py --generate table -o /tmp/bb-crc8-table.c --width=8 --poly=0xd5 
+ *	--reflect-in=false --reflect-out=false --xor-in=0xff --xor-out=0x00
+ */
+static const u8 bb_crc8_table[256] = {
+	0x00, 0xd5, 0x7f, 0xaa, 0xfe, 0x2b, 0x81, 0x54, 0x29, 0xfc, 0x56, 0x83, 0xd7, 0x02, 0xa8, 0x7d,
+	0x52, 0x87, 0x2d, 0xf8, 0xac, 0x79, 0xd3, 0x06, 0x7b, 0xae, 0x04, 0xd1, 0x85, 0x50, 0xfa, 0x2f,
+	0xa4, 0x71, 0xdb, 0x0e, 0x5a, 0x8f, 0x25, 0xf0, 0x8d, 0x58, 0xf2, 0x27, 0x73, 0xa6, 0x0c, 0xd9,
+	0xf6, 0x23, 0x89, 0x5c, 0x08, 0xdd, 0x77, 0xa2, 0xdf, 0x0a, 0xa0, 0x75, 0x21, 0xf4, 0x5e, 0x8b,
+	0x9d, 0x48, 0xe2, 0x37, 0x63, 0xb6, 0x1c, 0xc9, 0xb4, 0x61, 0xcb, 0x1e, 0x4a, 0x9f, 0x35, 0xe0,
+	0xcf, 0x1a, 0xb0, 0x65, 0x31, 0xe4, 0x4e, 0x9b, 0xe6, 0x33, 0x99, 0x4c, 0x18, 0xcd, 0x67, 0xb2,
+	0x39, 0xec, 0x46, 0x93, 0xc7, 0x12, 0xb8, 0x6d, 0x10, 0xc5, 0x6f, 0xba, 0xee, 0x3b, 0x91, 0x44,
+	0x6b, 0xbe, 0x14, 0xc1, 0x95, 0x40, 0xea, 0x3f, 0x42, 0x97, 0x3d, 0xe8, 0xbc, 0x69, 0xc3, 0x16,
+	0xef, 0x3a, 0x90, 0x45, 0x11, 0xc4, 0x6e, 0xbb, 0xc6, 0x13, 0xb9, 0x6c, 0x38, 0xed, 0x47, 0x92,
+	0xbd, 0x68, 0xc2, 0x17, 0x43, 0x96, 0x3c, 0xe9, 0x94, 0x41, 0xeb, 0x3e, 0x6a, 0xbf, 0x15, 0xc0,
+	0x4b, 0x9e, 0x34, 0xe1, 0xb5, 0x60, 0xca, 0x1f, 0x62, 0xb7, 0x1d, 0xc8, 0x9c, 0x49, 0xe3, 0x36,
+	0x19, 0xcc, 0x66, 0xb3, 0xe7, 0x32, 0x98, 0x4d, 0x30, 0xe5, 0x4f, 0x9a, 0xce, 0x1b, 0xb1, 0x64,
+	0x72, 0xa7, 0x0d, 0xd8, 0x8c, 0x59, 0xf3, 0x26, 0x5b, 0x8e, 0x24, 0xf1, 0xa5, 0x70, 0xda, 0x0f,
+	0x20, 0xf5, 0x5f, 0x8a, 0xde, 0x0b, 0xa1, 0x74, 0x09, 0xdc, 0x76, 0xa3, 0xf7, 0x22, 0x88, 0x5d,
+	0xd6, 0x03, 0xa9, 0x7c, 0x28, 0xfd, 0x57, 0x82, 0xff, 0x2a, 0x80, 0x55, 0x01, 0xd4, 0x7e, 0xab,
+	0x84, 0x51, 0xfb, 0x2e, 0x7a, 0xaf, 0x05, 0xd0, 0xad, 0x78, 0xd2, 0x07, 0x53, 0x86, 0x2c, 0xf9
+};
+
+#endif 
+
+
 /******************************************************************************
  * static inlined helper functions
  ******************************************************************************/
@@ -95,6 +137,44 @@
 	memcpy(d, s, len);
 }
 
+#ifndef BB_CRC8_TABLE_DRIVEN
+
+// CRC8 bit-by-bit
+
+#define BB_CRC8_POLY    0xd5
+static u8 bb_crc8_single(u8 crc, u8 data)
+{
+        int i;
+	for (i = 0x80; i > 0; i >>= 1) {
+		bit = crc & 0x80;
+		if (data & i) {
+			bit = !bit;
+		}
+		crc <<= 1;
+		if (bit) {
+			crc ^= BB_CRC8_POLY;
+		}
+	}
+        return crc;
+}
+
+#endif
+
+/**
+ * @brief CRC-8 for DVB-S2 Base-band demultiplexer
+ */
+static u8 bb_crc8(u8 crc, const u8 *src, size_t len)
+{
+	const unsigned char *end = src + len;
+	while(src < end)
+#ifdef BB_CRC8_TABLE_DRIVEN
+		crc = bb_crc8_table[crc ^ *src++];
+#else
+		crc = bb_crc8_single(crc, *src++);
+#endif
+        return crc;
+}
+
 /******************************************************************************
  * Software filter functions
  ******************************************************************************/
@@ -447,7 +527,8 @@
 	};
 
 	list_for_each_entry(feed, &demux->feed_list, list_head) {
-		if ((feed->pid != pid) && (feed->pid != 0x2000))
+		if (feed->type != DMX_TYPE_TS || (
+			(feed->pid != pid) && (feed->pid != 0x2000)))
 			continue;
 
 		/* copy each packet only once to the dvr device, even
@@ -455,8 +536,11 @@
 		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;
+		}
 		else if (feed->pid == 0x2000)
 			feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
 	}
@@ -568,6 +652,362 @@
 }
 EXPORT_SYMBOL(dvb_dmx_swfilter_204);
 
+/***********************************
+ * DVB-S2 Base-band demultiplexer  *
+ ***********************************/
+
+#define dprintk(x...) do { printk(x); } while (0)
+/**
+ * @brief Process a stream of (possibly fragmented) User Packets (UPs) from a
+ * Generic Packetized Stream or Transport Sream for a specific demux feed.
+ * @param feed The feed on which the UPs should be delivered
+ * @param df Pointer to the data field (df) of a BBFrame containing (fragments of) UPs
+ * @param dfl The length of the data field
+ * @param upl User Packet Length as stated in the BBHEADER
+ * @param upl Sync Distance as stated in the BBHEADER
+ * @param upl Sync Byte as stated in the BBHEADER
+ * @return
+ *	@retval 0 in case of success
+ *	@retval <0 in case of errors
+ * @todo Add support for feed callback timeouts
+ */
+int dvb_dmx_swfilter_bbups(struct dvb_demux_feed *feed, const u8 *df, u16 dfl, 
+	u16 upl, u16 syncd, u8 sync)
+{
+	u8 crc8;
+	u16 rupl = !sync ? upl-1 : upl; /*real upl */
+	size_t len, maxlen;
+#ifdef DVB_DEMUX_DEBUG_BB	
+	dprintk("%s: feed=%p, df=%p, dfl=%hu, upl=%hu, syncd=%hu, sync=%02x\n",
+				__FUNCTION__, feed, df, dfl, upl, syncd, 
+				(unsigned int) sync);
+#endif
+	if (!upl || syncd >= dfl)
+		return -EINVAL;
+	else if (!feed->buffer || upl > feed->buffer_size)
+		return -ENOBUFS;
+	
+	/* NOTE: if the original input stream does not contain a sync byte,
+	 * the DVB-S2 mode adaptation layer inserts a dummy sync byte (value 0) 
+	 * for holding the CRC-8 and also increments the upl.
+	 * We respect that by using the "real upl" (rupl) variable for packets
+	 * in the feed buffer.
+	 */
+		
+	// Limit size of usable buffer part to always store an integral number of packets
+	maxlen = (feed->buffer_size/upl) * upl;
+		
+	if (syncd == (u16) -1) {
+		// No packet starts here, so just copy the df to our buffer
+		len = min((size_t) dfl, maxlen-feed->bb.bufpos);
+		if (len > 0) {
+			memcpy(&feed->buffer[feed->bb.bufpos], df, len);
+			feed->bb.bufpos += len;
+		} else 
+			feed->bb.bufpos = 0;
+	} else {
+		const u8 *pkt = df;
+		const u8 *const dfend = df+dfl;
+		size_t partlen = feed->bb.bufpos % rupl;
+		/* If at least one packet starts in this data field,
+		 * check, if the data until the start of this packet
+		 * completes a partial packet in our buffer
+		 */
+		 if (syncd > 0) {
+			if ((partlen+syncd) == rupl && syncd <= (maxlen-feed->bb.bufpos)) {
+				memcpy(&feed->buffer[feed->bb.bufpos], pkt, syncd);
+				feed->bb.bufpos += syncd;
+			} else {
+				/* Assume that we lost a fragment of the partial 
+				 * packet contained in the buffer and thus
+				 * drop the partial packet.
+				 */
+				BUG_ON(feed->bb.bufpos < partlen); 
+				feed->bb.bufpos -= partlen;
+			}
+			pkt += syncd;
+		} else if (partlen > 0) {
+			/* Assume that we lost a fragment of the partial 
+			 * packet contained in the buffer and thus
+			 * drop the partial packet.
+			 */
+			feed->bb.bufpos -= partlen;
+		}
+		
+		
+		/* NOTE: pkt is synced to a packet start, i.e. *pkt contains the
+		 * CRC-8 of the last packet on this feed.
+		 */
+		while (pkt < dfend) {
+#ifdef DVB_DEMUX_DEBUG_BB			
+			dprintk("%s: pkt=%p, dfend=%p, bufpos=%u (of %u), upl=%hu, rupl=%hu\n",
+				__FUNCTION__, pkt, dfend, feed->bb.bufpos, maxlen, upl, rupl);
+#endif			
+			if ((feed->bb.bufpos-feed->bb.crcpos) >= rupl) {
+				/* verify the last packet in the buffer (not including the sync byte) */
+				crc8 = bb_crc8(0x00, 
+					&feed->buffer[feed->bb.crcpos+1], upl-1);
+				if (crc8 != *pkt) {
+					// discard packet
+					feed->bb.bufpos -= upl;
+				} else if (feed->bb.bufpos >= maxlen) {
+					// Flush feed buffer 
+			
+					/* NOTE: at this point, all packets in the feed 
+					 * buffer have been verified, so we're allowed to deliver
+					 * them to the feed callback.
+					 */
+				
+					// Invoke feed callback
+					feed->cb.bb(feed->buffer, feed->bb.bufpos, 
+						rupl, &feed->feed.bb, DMX_OK);
+					
+					feed->bb.crcpos = feed->bb.bufpos = 0;
+				}
+				else
+					feed->bb.crcpos = feed->bb.bufpos;
+			}
+			
+			BUG_ON(feed->bb.bufpos+rupl > maxlen);
+			
+			if (sync) // Sync byte present?
+				feed->buffer[feed->bb.bufpos++] = sync;
+			pkt++;
+			
+			len = min((u16) (upl-1), (u16) (dfend-pkt));
+			/* NOTE: we do not check for len == 0, as it hopefully does not
+			 * happen too often.
+			 */
+			memcpy(&feed->buffer[feed->bb.bufpos], pkt, len);
+			pkt += len;
+			feed->bb.bufpos += len;
+		}
+	}
+	return 0;
+}
+
+/* Structure of a Base-Band frame:
+ 
+ *  < ------------------------------ BBFrame ----------------------------------- >
+ *    2 bytes 2 bytes  2 bytes  1 B  2 bytes  1 B            DFL bits
+ *  |--------|--------|--------|----|--------|----|------------------------------|
+ *  +--------+--------+--------+----+--------+----+-------------//---------------+
+ *  | MATYPE |   UPL  |   DFL  |SYNC| SYNCD  |CRC8|          Data Field          |
+ *  +--------+--------+--------+----+--------+----+-------------//---------------+
+ *
+ * Sub-structure of the MATYPE field:
+ *  +--------+----+----+----+----+--------+------------------------------------+
+ *  | TS/GS  |SIS/|CCM/|IS- |NPD |   RO   |           ISI or unused            |
+ *  |        |MIS |ACM |SYI |    |        |                                    |
+ *  +--------+----+----+----+----+--------+------------------------------------+
+ *
+ */
+
+
+/**
+ * @todo Invoke feed callbacks in case of an error 
+ * @todo If mode == BB_TS and SIS-mode is active then we could by default forward
+ * the TS to the TS demux. This would avoid the need to explicitely setup 
+ * TS compatibility mode using dvb_dmx_set_ts_compat().
+ * @note assumes that the caller has locked demux->lock.
+ */
+ssize_t _dvb_dmx_swfilter_bbframe(struct dvb_demux *demux, const u8 *frame, size_t len)
+{
+	ssize_t rv = -1;
+	u16 framelen;
+	int isi, mode;
+	struct dvb_demux_feed *feed;
+	u8 crc8;
+	
+	if (len < 10 || len > 7274) {
+		// No complete BBHEADER present
+		rv = -EINVAL;
+		goto done;
+	}
+	
+	// Verify CRC-8 of BBHEADER (frame[9])
+	crc8 = bb_crc8(0x00, frame, 9);
+	if (crc8 != frame[9]) {
+		printk(KERN_NOTICE "%s: CRC check failed for BBHEADER "
+			"(calculated %02x, received %02x)\n", __FUNCTION__, 
+			(int) crc8, (int) frame[9]);
+		goto done;
+	}
+	
+	if (frame[0] & 0x20) { // Single Input Stream (SIS)
+		isi = -1;
+	} else { // Multiple Input Stream (MIS)
+		isi = frame[1];
+	}
+	mode = (frame[0] & 0xc0);
+	
+	//  length values are measured in bits -> convert to bytes
+	framelen = (frame[4] << 8) | frame[5];
+	framelen >>= 3;
+	
+	if (!framelen || ((len-10) < framelen)) {
+		printk(KERN_NOTICE "%s: invalid data field length (length %hu, left %u)\n",
+			__FUNCTION__, framelen, len);
+		rv = -1;
+		goto done;
+	}
+#ifdef DVB_DEMUX_DEBUG_BB
+	dprintk("%s: received frame for input stream %d (df length %u)\n",
+		__FUNCTION__, isi, (unsigned int) framelen);
+#endif	
+	// First, give the raw frame to all BB_FRAME feeds 
+	list_for_each_entry(feed, &demux->feed_list, list_head) {
+		if (feed->type != DMX_TYPE_BB || feed->bb.type != BB_FRAME)
+			continue;
+		else if (feed->bb.isi != isi && feed->bb.isi != BB_ISI_ALL)
+			continue;
+		else 
+			feed->cb.bb(frame, framelen+10, 0, &feed->feed.bb, DMX_OK);
+	}
+	
+	if (mode == BB_TS || mode == BB_PACK_GS) {
+		// Packetized stream
+		u16 upl = ((frame[2] << 8) | frame[3]) >> 3;
+		u16 syncd = ((frame[7] << 8) | frame[8]) >> 3;
+		if (!upl) {
+			if (mode == BB_TS)
+				upl = 188;
+			else {
+				printk(KERN_NOTICE "%s: invalid user packet length of zero\n",
+					__FUNCTION__);
+				goto done;
+			}
+		}
+		
+		list_for_each_entry(feed, &demux->feed_list, list_head) {
+			if (feed->type != DMX_TYPE_BB || feed->bb.type != mode)
+				continue;
+			else if (feed->bb.isi != isi && feed->bb.isi != BB_ISI_ALL)
+				continue;
+			else
+				dvb_dmx_swfilter_bbups(feed, frame+10, framelen, 
+					upl, syncd, frame[6]);
+		}
+	} else if (mode == BB_CONT_GS) {
+		// Continuos stream
+		list_for_each_entry(feed, &demux->feed_list, list_head) {
+			if (feed->type != DMX_TYPE_BB || feed->bb.type != BB_CONT_GS)
+				continue;
+			else if (feed->bb.isi != isi && feed->bb.isi != BB_ISI_ALL)
+				continue;
+			else
+				feed->cb.bb(frame+10, framelen, 0, &feed->feed.bb, DMX_OK);
+		}
+	} else {
+		printk(KERN_NOTICE "%s: invalid use of reserved TS/GS value 1\n",
+			__FUNCTION__);
+		goto done;
+	}
+
+	rv = framelen+10;
+	
+done:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
+	///@todo Make this configurable via sysfs or module param
+	if (rv < 0) {
+		print_hex_dump(KERN_DEBUG, "[BBFrame] ", DUMP_PREFIX_OFFSET, 16, 
+			1, (void*) frame,  len, 0);
+	}
+#endif
+	return rv;
+}
+
+ssize_t dvb_dmx_swfilter_bbframe(struct dvb_demux *demux, const u8 *frame, size_t len)
+{
+	ssize_t rv;
+	spin_lock(&demux->lock);
+	rv = _dvb_dmx_swfilter_bbframe(demux, frame, len);
+	spin_unlock(&demux->lock);
+	return rv;
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter_bbframe);
+
+#define BB_FRAME_LEN(ptr) (10 + ((((ptr)[4] << 8) | (ptr)[5]) >> 3))
+void dvb_dmx_swfilter_data(struct dvb_demux *demux, fe_data_format_t dfmt, 
+	const u8 *data, size_t len)
+{
+#ifdef DVB_DEMUX_DEBUG_BB
+	dprintk("%s: demux=%p, dfmt=%d, data=%p, len=%u\n",
+				__FUNCTION__, demux, dfmt, data,
+				(unsigned int) len);
+#endif
+	spin_lock(&demux->lock);
+
+	if(dfmt == FE_DFMT_BB_FRAME) {
+		// A sequence of base-band frames as a stream of bytes
+		u16 bblen;
+		ssize_t res;
+		size_t clen;
+		while(demux->bb.wr > 0 && len > 0) {
+#ifdef DVB_DEMUX_DEBUG_BB
+	dprintk("%s: wr=%u, data=%p, len=%u\n",
+				__FUNCTION__, demux->bb.wr, data, (unsigned int) len);
+#endif
+			if(demux->bb.wr < 10) {
+				clen = min(10-demux->bb.wr, len);
+				clen = min(clen, DMX_BB_BUFSZ-demux->bb.wr);
+				memcpy(&demux->bb.buf[demux->bb.wr], data, clen);
+				demux->bb.wr += clen;
+				data += clen;
+				len -= clen;
+			} else {
+				if(bb_crc8(0x00, &demux->bb.buf[0], 10) != 0) {
+					demux->bb.wr -= 1;
+					memmove(&demux->bb.buf[0], &demux->bb.buf[1], demux->bb.wr);
+					continue;
+				}
+				bblen = BB_FRAME_LEN(demux->bb.buf);
+				if(demux->bb.wr < bblen) {
+					clen = min(bblen-demux->bb.wr, len);
+					clen = min(clen, DMX_BB_BUFSZ-demux->bb.wr);
+					memcpy(&demux->bb.buf[demux->bb.wr], data, clen);
+					demux->bb.wr += clen;
+					data += clen;
+					len -= clen;
+				}
+				if(demux->bb.wr >= bblen) {
+					res = _dvb_dmx_swfilter_bbframe(demux, &demux->bb.buf[0], bblen);
+					demux->bb.wr -= bblen;
+					if(demux->bb.wr > 0)
+						memmove(&demux->bb.buf[0], &demux->bb.buf[bblen], demux->bb.wr);
+				}
+			}
+			if(demux->bb.wr == DMX_BB_BUFSZ)
+				demux->bb.wr = 0;
+		}
+		if(demux->bb.wr == 0) {
+			while(len > 9) {
+				if(bb_crc8(0x00, data, 10) != 0) {
+					bblen = 1;
+				} else {
+					bblen = BB_FRAME_LEN(data);
+					if(len < bblen) {
+						break;
+					}
+					res = _dvb_dmx_swfilter_bbframe(demux, data, bblen);
+				}
+				data += bblen;
+				len -= bblen;
+			}
+		}
+		// copy remaining part to buffer
+		BUG_ON((demux->bb.wr + len) > DMX_BB_BUFSZ);
+		memcpy(&demux->bb.buf[demux->bb.wr], data, len);
+		demux->bb.wr += len;
+	} else {
+		///@todo implement TS path
+	}
+
+	spin_unlock(&demux->lock);
+}
+
+EXPORT_SYMBOL(dvb_dmx_swfilter_data);
+
 static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux)
 {
 	int i;
@@ -1093,6 +1533,180 @@
 }
 
 /******************************************************************************
+ * dmx_bb_feed calls
+ ******************************************************************************/
+
+static int dmx_bb_feed_set(struct dmx_bb_feed *bb_feed, int isi, int mode,
+	size_t circular_buffer_size, struct timespec timeout)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed*) bb_feed;
+	struct dvb_demux *demux = feed->demux;
+
+#ifdef DVB_DEMUX_DEBUG_BB
+	dprintk("%s: bb_feed=%p, isi=%d, mode=%d, bufsz=%u\n",
+		__FUNCTION__, bb_feed, isi, mode, circular_buffer_size);
+#endif
+	///@todo Max ISI may be dependent on delivery system
+	if (isi > 255 || (isi < 0 && isi != BB_ISI_ALL && isi != BB_ISI_SIS))
+		return -EINVAL;
+	else if (mode != BB_FRAME && mode != BB_PACK_GS && mode != BB_CONT_GS && 
+		mode != BB_TS)
+		return -EINVAL;
+	else if (isi == BB_ISI_ALL && mode != BB_FRAME)
+		return -EINVAL;
+
+	feed->buffer_size = circular_buffer_size; 
+	if (feed->buffer_size) {
+		feed->buffer = vmalloc(feed->buffer_size);
+		if (!feed->buffer) {
+			return -ENOMEM;
+		}
+	} else if (mode == BB_PACK_GS || mode == BB_TS) {
+		// we need a buffer for packetized streams!
+		return -EINVAL;
+	}
+	
+	feed->bb.isi = isi;
+	feed->bb.type = mode;
+	feed->state = DMX_STATE_READY;
+	
+	if (mutex_lock_interruptible(&demux->mutex))
+		return -ERESTARTSYS;
+	
+	dvb_demux_feed_add(feed);
+	
+	mutex_unlock(&demux->mutex);
+	return 0;
+}
+
+static int dmx_bb_feed_start_filtering(struct dmx_bb_feed *bb_feed)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)bb_feed;
+	struct dvb_demux *demux = feed->demux;
+	int ret;
+
+	if (mutex_lock_interruptible(&demux->mutex))
+		return -ERESTARTSYS;
+
+	if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_BB) {
+		mutex_unlock(&demux->mutex);
+		return -EINVAL;
+	}
+
+	if (!demux->start_feed) {
+		mutex_unlock(&demux->mutex);
+		return -ENODEV;
+	}
+
+	if ((ret = demux->start_feed(feed)) < 0) {
+		mutex_unlock(&demux->mutex);
+		return ret;
+	}
+
+	spin_lock_irq(&demux->lock);
+	bb_feed->is_filtering = 1;
+	feed->state = DMX_STATE_GO;
+	spin_unlock_irq(&demux->lock);
+	mutex_unlock(&demux->mutex);
+
+	return 0;
+}
+
+static int dmx_bb_feed_stop_filtering(struct dmx_bb_feed *bb_feed)
+{
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed *)bb_feed;
+	struct dvb_demux *demux = feed->demux;
+	int ret;
+
+	mutex_lock(&demux->mutex);
+
+	if (feed->state < DMX_STATE_GO) {
+		mutex_unlock(&demux->mutex);
+		return -EINVAL;
+	}
+
+	if (!demux->stop_feed) {
+		mutex_unlock(&demux->mutex);
+		return -ENODEV;
+	}
+
+	ret = demux->stop_feed(feed);
+
+	spin_lock_irq(&demux->lock);
+	bb_feed->is_filtering = 0;
+	feed->state = DMX_STATE_READY;
+	spin_unlock_irq(&demux->lock);
+	mutex_unlock(&demux->mutex);
+
+	return ret;
+}
+
+static int dvbdmx_allocate_bb_feed(struct dmx_demux *dmx, struct dmx_bb_feed **bb_feed,
+	dmx_bb_cb callback)
+{
+	struct dvb_demux *demux = (struct dvb_demux *)dmx;
+	struct dvb_demux_feed *feed;
+
+#ifdef DVB_DEMUX_DEBUG_BB
+	dprintk("%s: dmx=%p, bb_feed=%p, callback=%p\n",
+		__FUNCTION__, dmx, bb_feed, callback);
+#endif
+	
+	if (mutex_lock_interruptible(&demux->mutex))
+		return -ERESTARTSYS;
+
+	if (!(feed = dvb_dmx_feed_alloc(demux))) {
+		mutex_unlock(&demux->mutex);
+		return -EBUSY;
+	}
+
+	feed->type = DMX_TYPE_BB;
+	feed->cb.bb = callback;
+	feed->demux = demux;
+	feed->bb.isi = BB_ISI_SIS;
+	feed->bb.type = BB_FRAME;
+	feed->buffer = NULL;
+	feed->bb.bufpos = 0;
+	feed->bb.crcpos = 0;
+	
+	*bb_feed = &feed->feed.bb;
+	(*bb_feed)->parent = dmx;
+	(*bb_feed)->priv = NULL;
+	(*bb_feed)->is_filtering = 0;
+	(*bb_feed)->start_filtering = dmx_bb_feed_start_filtering;
+	(*bb_feed)->stop_filtering = dmx_bb_feed_stop_filtering;
+	(*bb_feed)->set = dmx_bb_feed_set;
+	
+	mutex_unlock(&demux->mutex);
+	return 0;
+}
+
+static int dvbdmx_release_bb_feed(struct dmx_demux *dmx, struct dmx_bb_feed *bb_feed)
+{
+	struct dvb_demux *demux = (struct dvb_demux *)dmx;
+	struct dvb_demux_feed *feed = (struct dvb_demux_feed*) bb_feed;
+
+#ifdef DVB_DEMUX_DEBUG_BB
+	dprintk("%s: dmx=%p, bb_feed=%p\n",
+		__FUNCTION__, dmx, bb_feed);
+#endif
+
+	mutex_lock(&demux->mutex);
+
+	if (feed->state == DMX_STATE_FREE) {
+		mutex_unlock(&demux->mutex);
+		return -EINVAL;
+	}
+
+	feed->state = DMX_STATE_FREE;
+
+	dvb_demux_feed_del(feed);
+
+	mutex_unlock(&demux->mutex);
+	return 0;
+}
+
+/******************************************************************************
  * dvb_demux kernel data API calls
  ******************************************************************************/
 
@@ -1214,6 +1828,104 @@
 	return 0;
 }
 
+static void dvb_dmx_ts_compat_bb_callback(const u8 *buf, size_t len, size_t upl, 
+	struct dmx_bb_feed* source, enum dmx_success success)
+{
+	unsigned int count;
+#ifdef DVB_DEMUX_DEBUG_BB
+	dprintk("%s: buf=%p, len=%u, upl=%u, source=%p, success=%d\n",
+		__FUNCTION__, buf, len, upl, source, success);
+#endif
+	if (success != DMX_OK || upl != 188)
+		return;
+	for(count=len/188; count > 0; count--, buf+=188)
+		dvb_dmx_swfilter_packet((struct dvb_demux*) source->parent, buf); 
+	
+}
+
+/**
+ * @brief Enable or disable TS compatibility mode on the specified input stream (ISI).
+ */
+static int dvb_dmx_set_ts_compat(struct dvb_demux *dvbdemux, int isi, int enable)
+{
+	int rv = -1, found = 0;
+	struct dmx_demux *demux = &dvbdemux->dmx;
+	struct dmx_bb_feed *feed;
+	struct dvb_demux_feed *dvbfeed;
+	struct timespec timeout = {0, 1*1000*1000}; /* 1 ms */
+	
+	if (!demux->allocate_bb_feed) {
+		printk(KERN_ERR "%s: demux does not support bb feeds\n", 
+			__FUNCTION__);
+		goto done;
+	}
+	
+	spin_lock(&dvbdemux->lock);
+	list_for_each_entry(dvbfeed, &dvbdemux->feed_list, list_head) {
+		if ((dvbfeed->type != DMX_TYPE_BB) || (dvbfeed->bb.type != BB_TS) || 
+			(dvbfeed->bb.isi != isi) || 
+			(dvbfeed->cb.bb != dvb_dmx_ts_compat_bb_callback))
+			continue;
+		found = 1;
+		break;
+	}
+	spin_unlock(&dvbdemux->lock);
+	
+	if (enable && !found) {
+		dprintk("%s: alloc bb feed\n", __FUNCTION__);
+		
+		rv = demux->allocate_bb_feed(demux, &feed, dvb_dmx_ts_compat_bb_callback);
+		if (rv < 0) {
+			printk(KERN_ERR "%s: could not allocate bb feed\n", 
+				__FUNCTION__);
+			goto done;
+		}
+		
+		feed->priv = NULL;
+		rv = feed->set(feed,
+				isi,		/* isi */
+				BB_TS,		/* type */
+				7274,   	/* circular buffer size */
+				timeout		/* timeout */
+				);
+		if (rv < 0) {
+			printk(KERN_ERR "%s: could not set bb feed\n", __FUNCTION__);
+			demux->release_bb_feed(demux, feed);
+			goto done;
+		}
+	
+		dprintk("%s: start filtering\n", __FUNCTION__);
+		
+		if (isi == BB_ISI_ALL)
+			printk("%s: enabled TS-Compatibility mode on all ISIs\n", 
+				__FUNCTION__);
+		else
+			printk("%s: enabled TS-Compatibility mode on ISI %d\n", 
+				__FUNCTION__, isi);
+		
+		feed->start_filtering(feed);
+	} else if (!enable && found) {
+		feed = &dvbfeed->feed.bb;
+		if (feed->is_filtering) {
+			dprintk("%s: stop filtering\n", __FUNCTION__);
+			feed->stop_filtering(feed);
+		}
+		dprintk("%s: release bb feed\n", __FUNCTION__);
+		demux->release_bb_feed(demux, feed);
+		
+		if (isi == BB_ISI_ALL)
+			printk("%s: disabled TS-Compatibility mode on all ISIs\n", 
+				__FUNCTION__);
+		else
+			printk("%s: disabled TS-Compatibility mode on ISI %d\n", 
+				__FUNCTION__, isi);
+	}
+	
+	rv = 0;
+done:
+	return rv;
+}
+
 int dvb_dmx_init(struct dvb_demux *dvbdemux)
 {
 	int i;
@@ -1273,6 +1985,8 @@
 	dmx->release_ts_feed = dvbdmx_release_ts_feed;
 	dmx->allocate_section_feed = dvbdmx_allocate_section_feed;
 	dmx->release_section_feed = dvbdmx_release_section_feed;
+	dmx->allocate_bb_feed = dvbdmx_allocate_bb_feed;
+	dmx->release_bb_feed = dvbdmx_release_bb_feed;
 
 	dmx->add_frontend = dvbdmx_add_frontend;
 	dmx->remove_frontend = dvbdmx_remove_frontend;
@@ -1284,6 +1998,14 @@
 	mutex_init(&dvbdemux->mutex);
 	spin_lock_init(&dvbdemux->lock);
 
+	dvbdemux->bb.buf = vmalloc(DMX_BB_BUFSZ);
+	if (!dvbdemux->bb.buf)
+		return -ENOMEM;
+	dvbdemux->bb.wr = 0;
+
+
+	/* Activate TS-Compat mode for single-input stream channels */
+	//dvb_dmx_set_ts_compat(dvbdemux, BB_ISI_SIS, 1);
 	return 0;
 }
 
@@ -1291,9 +2013,11 @@
 
 void dvb_dmx_release(struct dvb_demux *dvbdemux)
 {
+	dvb_dmx_set_ts_compat(dvbdemux, BB_ISI_SIS, 0);
 	vfree(dvbdemux->cnt_storage);
 	vfree(dvbdemux->filter);
 	vfree(dvbdemux->feed);
+	vfree(dvbdemux->bb.buf);
 }
 
 EXPORT_SYMBOL(dvb_dmx_release);
--- a/linux/drivers/media/dvb/dvb-core/dvb_demux.h	2012-03-19 14:39:46.117144880 +0200
+++ b/linux/drivers/media/dvb/dvb-core/dvb_demux.h	2012-03-19 14:38:26.897145875 +0200
@@ -28,11 +28,14 @@
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
 
+#include <linux/dvb/frontend.h>
+
 #include "demux.h"
 
 #define DMX_TYPE_TS  0
 #define DMX_TYPE_SEC 1
 #define DMX_TYPE_PES 2
+#define DMX_TYPE_BB  3
 
 #define DMX_STATE_FREE      0
 #define DMX_STATE_ALLOCATED 1
@@ -68,11 +71,13 @@
 	union {
 		struct dmx_ts_feed ts;
 		struct dmx_section_feed sec;
+		struct dmx_bb_feed bb;
 	} feed;
 
 	union {
 		dmx_ts_cb ts;
 		dmx_section_cb sec;
+		dmx_bb_cb bb;
 	} cb;
 
 	struct dvb_demux *demux;
@@ -94,6 +99,21 @@
 
 	u16 peslen;
 
+	/* Data for the Base-band demux */
+	struct {
+		/// Input Stream Identifier. A value of -1 indicates Single Input Stream operation
+		int isi;
+		/// Feed type (BB_FRAME, BB_PACK_GS, BB_CONT_GS or BB_TS)
+		u8 type;
+		/// Position in buffer (feed->buffer)
+		unsigned int bufpos;
+		/**
+		 * This is the offset of the last packet in the buffer which needs CRC validation.
+		 * @note All packets in the buffer with offsets < crcpos have already been validated.
+		 */
+		unsigned int crcpos;
+	} bb;
+
 	struct list_head list_head;
 	unsigned int index;	/* a unique index for each feed (can be used as hardware pid filter index) */
 };
@@ -129,6 +149,16 @@
 	u8 tsbuf[204];
 	int tsbufp;
 
+
+	/**
+	 * Members which are specific to the BB-Demux 
+	 */
+	struct {
+#define DMX_BB_BUFSZ	8192
+		u8 *buf;
+		unsigned int wr;
+	} bb;
+
 	struct mutex mutex;
 	spinlock_t lock;
 
@@ -145,5 +175,17 @@
 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);
+/**
+ * Pass a single Base-band frame (BBFrame) to the demultiplexer
+ * @param demux Pointer to DVB demux context
+ * @param frame Buffer containing the full BBFrame
+ * @param len Length of the BBFrame in \c frame
+ * @return The length of the BBFrame or a value < 0 in case of an error
+ * @note This function MUST NOT be call from inside a feed callback
+ */
+ssize_t dvb_dmx_swfilter_bbframe(struct dvb_demux *demux, const u8 *frame, size_t len);
+
+void dvb_dmx_swfilter_data(struct dvb_demux *demux, fe_data_format_t dfmt, 
+	const u8 *data, size_t len);
 
 #endif /* _DVB_DEMUX_H_ */
--- a/linux/include/linux/dvb/frontend.h	2011-05-21 02:59:30.000000000 +0300
+++ b/linux/include/linux/dvb/frontend.h	2012-03-19 15:01:11.533128721 +0200
@@ -351,6 +351,14 @@
 	SYS_DVBT2,
 } fe_delivery_system_t;
 
+/*
+ * Format of data transferred from DVB adapter (frontend) to host.
+*/
+typedef enum fe_data_format {
+	FE_DFMT_TS_PACKET,
+	FE_DFMT_BB_FRAME
+} fe_data_format_t;
+
 struct dtv_cmds_h {
 	char	*name;		/* A display name for debugging purposes */
 
--- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c	2011-10-09 22:20:56.000000000 +0300
+++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c	2012-03-19 15:05:57.273125129 +0200
@@ -878,6 +878,7 @@
 	c->symbol_rate = QAM_AUTO;
 	c->code_rate_HP = FEC_AUTO;
 	c->code_rate_LP = FEC_AUTO;
+	c->dfmt = FE_DFMT_TS_PACKET;
 
 	c->isdbt_partial_reception = -1;
 	c->isdbt_sb_mode = -1;
--- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.h	2011-05-21 02:59:30.000000000 +0300
+++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.h	2012-03-19 15:06:47.441124498 +0200
@@ -342,6 +342,8 @@
 
 	fe_delivery_system_t	delivery_system;
 
+	fe_data_format_t	dfmt;
+
 	/* ISDB-T specifics */
 	u8			isdbt_partial_reception;
 	u8			isdbt_sb_mode;
--- a/linux/drivers/media/common/saa716x/saa716x_tbs.c	2012-02-06 15:05:41.000000000 +0200
+++ b/linux/drivers/media/common/saa716x/saa716x_tbs.c	2012-03-19 16:34:35.344928347 +0200
@@ -76,6 +76,10 @@
 module_param(ci_mode, int, 0644);
 MODULE_PARM_DESC(ci_mode, "for internal use only: default 0");
 
+static int tsout = 1;
+module_param(tsout, int, 0644);
+MODULE_PARM_DESC(tsout, "TBS 6925 output format 1=TS, 0=BB (default:1)");
+
 #define DRIVER_NAME "SAA716x TBS"
 
 static int __devinit saa716x_tbs_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
@@ -356,7 +360,11 @@
 				u8 * data = (u8 *)saa716x->fgpi[3].dma_buf[activeBuffer].mem_virt;
 				dprintk(SAA716x_DEBUG, 1, "%02X%02X%02X%02X",
 					data[0], data[1], data[2], data[3]);
-				dvb_dmx_swfilter_packets(&saa716x->saa716x_adap[0].demux, data, 348);
+				if (tsout == 0)
+					dvb_dmx_swfilter_data(&saa716x->saa716x_adap[0].demux, 
+									FE_DFMT_BB_FRAME, data, 348*188);
+				else
+					dvb_dmx_swfilter_packets(&saa716x->saa716x_adap[0].demux, data, 348);
 			}
 			if (fgpiStatus) {
 				SAA716x_EPWR(FGPI3, INT_CLR_STATUS, fgpiStatus);
--- a/linux/drivers/media/dvb/frontends/stv090x.c	2011-10-09 23:15:32.000000000 +0300
+++ b/linux/drivers/media/dvb/frontends/stv090x.c	2012-03-19 18:00:03.690919513 +0200
@@ -38,6 +38,10 @@
 static unsigned int verbose;
 module_param(verbose, int, 0644);
 
+static int tsout = 1;
+module_param(tsout, int, 0644);
+MODULE_PARM_DESC(tsout, "Output data 1=TS, 0=BB (default:1)");
+
 /* internal params node */
 struct stv090x_dev {
 	/* pointer for internal params, one for each pair of demods */
@@ -3166,6 +3170,40 @@
 	return -1;
 }
 
+/* Set data output format of Transport Stream Merger.
+ * This function configures the packet delineator and the stream merger units
+ * of the STV0900 for frame (Base-band frame) or packet (Transport Stream) output.
+ */
+static int stv090x_set_dfmt(struct stv090x_state *state, fe_data_format_t dfmt)
+{
+	u32 reg;
+
+	// Px_PDELCTRL2: Packet delineator additional configuration
+	switch(dfmt)
+	{
+		case FE_DFMT_TS_PACKET:
+			reg = STV090x_READ_DEMOD(state, PDELCTRL2);
+			STV090x_SETFIELD_Px(reg, FRAME_MODE_FIELD, 0);
+			if (STV090x_WRITE_DEMOD(state, PDELCTRL2, reg) < 0)
+				goto err;
+			break;
+		case FE_DFMT_BB_FRAME:
+			reg = STV090x_READ_DEMOD(state, PDELCTRL2);
+			STV090x_SETFIELD_Px(reg, FRAME_MODE_FIELD, 1);
+			if (STV090x_WRITE_DEMOD(state, PDELCTRL2, reg) < 0)
+				goto err;
+			break;
+		default:
+			dprintk(FE_ERROR, 1, "Invalid data format %d", dfmt);
+			goto err;
+	}
+	
+	//
+	return 0;
+err:
+	dprintk(FE_ERROR, 1, "Failed to set FE data format");
+	return -1;
+}
 
 static enum stv090x_signal_state stv090x_algo(struct stv090x_state *state)
 {
@@ -3434,6 +3472,15 @@
 	if (p->frequency == 0)
 		return DVBFE_ALGO_SEARCH_INVALID;
 
+	if (tsout == 0) { /* bb mode enabled */
+		//if(stv090x_set_dfmt(state, props->dfmt) != 0)
+		if(stv090x_set_dfmt(state, FE_DFMT_BB_FRAME) != 0)
+			return DVBFE_ALGO_SEARCH_ERROR;
+	} else {
+		if(stv090x_set_dfmt(state, FE_DFMT_TS_PACKET) != 0)
+			return DVBFE_ALGO_SEARCH_ERROR;
+	}
+
 	state->delsys = props->delivery_system;
 	state->frequency = p->frequency;
 	state->srate = p->u.qpsk.symbol_rate;

[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux