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;