[linuxtv-dvb-apps] 02/30: Imported Upstream version 1.1.0

Tobias Grimm tiber-guest at alioth.debian.org
Tue Sep 3 07:51:53 UTC 2013


This is an automated email from the git hooks/post-receive script.

tiber-guest pushed a commit to branch master
in repository linuxtv-dvb-apps.

commit 6e40287e2f39a80fc72bd8d0fbc1a8334d688c2d
Author: etobi <git at e-tobi.net>
Date:   Tue Sep 3 09:48:38 2013 +0200

    Imported Upstream version 1.1.0
---
 Makefile                                    |   28 +
 README                                      |   21 +
 TODO                                        |    1 +
 include/linux/dvb/audio.h                   |  125 ++
 include/linux/dvb/ca.h                      |   91 ++
 include/linux/dvb/dmx.h                     |  181 +++
 include/linux/dvb/frontend.h                |  260 ++++
 include/linux/dvb/net.h                     |   41 +
 include/linux/dvb/osd.h                     |  111 ++
 include/linux/dvb/version.h                 |   29 +
 include/linux/dvb/video.h                   |  199 +++
 libdvb2/README                              |   23 +
 test/Makefile                               |   37 +
 test/README                                 |   51 +
 test/dia                                    |    7 +
 test/diseqc.c                               |  140 ++
 test/hex_dump.c                             |   63 +
 test/hex_dump.h                             |   28 +
 test/sendburst.c                            |   55 +
 test/set22k.c                               |   50 +
 test/setpid.c                               |   87 ++
 test/setvoltage.c                           |   47 +
 test/test.c                                 |  281 ++++
 test/test_audio.c                           |  345 +++++
 test/test_av.c                              |  574 ++++++++
 test/test_av_play.c                         |  310 +++++
 test/test_dvr.c                             |  164 +++
 test/test_dvr_play.c                        |  144 ++
 test/test_front.c                           |  328 +++++
 test/test_pes.c                             |  137 ++
 test/test_sec_ne.c                          |  165 +++
 test/test_sections.c                        |  197 +++
 test/test_stc.c                             |   74 +
 test/test_stillimage.c                      |  103 ++
 test/test_switch.c                          |  355 +++++
 test/test_tt.c                              |  205 +++
 test/test_vevent.c                          |  125 ++
 test/test_video.c                           |  368 +++++
 test/video.c                                |  182 +++
 util/Makefile                               |   12 +
 util/av7110_loadkeys/Makefile               |   48 +
 util/av7110_loadkeys/README                 |   64 +
 util/av7110_loadkeys/activy.rcmm            |   54 +
 util/av7110_loadkeys/av7110_loadkeys.c      |  186 +++
 util/av7110_loadkeys/evtest.c               |  177 +++
 util/av7110_loadkeys/galaxis.rcmm           |   51 +
 util/av7110_loadkeys/hauppauge.rc5          |   25 +
 util/av7110_loadkeys/hauppauge_grey.rc5     |   40 +
 util/av7110_loadkeys/input_fake.h           |   84 ++
 util/av7110_loadkeys/mbo_81095-code_562.rc5 |   39 +
 util/av7110_loadkeys/medion_088.rc5         |   36 +
 util/av7110_loadkeys/medion_155.rc5         |   35 +
 util/av7110_loadkeys/philips.rc5            |   32 +
 util/av7110_loadkeys/philips1358.rc5        |   37 +
 util/dvbdate/Makefile                       |   25 +
 util/dvbdate/dvbdate.c                      |  346 +++++
 util/dvbnet/Makefile                        |   29 +
 util/dvbnet/dvbnet.c                        |  205 +++
 util/dvbnet/net_start.pl                    |   25 +
 util/dvbnet/net_start.sh                    |   15 +
 util/dvbnet/version.h.in                    |    1 +
 util/dvbtraffic/Makefile                    |    6 +
 util/dvbtraffic/dvbtraffic.c                |  130 ++
 util/lib/Makefile                           |   20 +
 util/lib/lnb.c                              |  101 ++
 util/lib/lnb.h                              |   24 +
 util/scan/Makefile                          |   21 +
 util/scan/README                            |   18 +
 util/scan/diseqc.c                          |  108 ++
 util/scan/diseqc.h                          |   25 +
 util/scan/dump-vdr.c                        |  161 +++
 util/scan/dump-vdr.h                        |   38 +
 util/scan/dump-zap.c                        |  119 ++
 util/scan/dump-zap.h                        |   20 +
 util/scan/dvb-c/at-Vienna                   |    3 +
 util/scan/dvb-c/ch-unknown                  |    3 +
 util/scan/dvb-c/de-Berlin                   |    4 +
 util/scan/dvb-c/de-iesy                     |    3 +
 util/scan/dvb-c/fi-3ktv                     |    3 +
 util/scan/dvb-c/fi-vaasa-oncable            |   13 +
 util/scan/dvb-s/Astra-19.2E                 |    3 +
 util/scan/dvb-s/Hispasat-30.0W              |    6 +
 util/scan/dvb-s/Hotbird-13.0E               |    3 +
 util/scan/dvb-s/PAS-43.0W                   |    6 +
 util/scan/dvb-s/Sirius-5.0E                 |    5 +
 util/scan/dvb-s/Telecom2-8.0W               |    4 +
 util/scan/dvb-s/Telstar12-15.0W             |    4 +
 util/scan/dvb-s/Thor-1.0W                   |    8 +
 util/scan/dvb-s/Turksat-42.0E               |    4 +
 util/scan/dvb-t/au-Darwin                   |    5 +
 util/scan/dvb-t/au-canberra                 |   12 +
 util/scan/dvb-t/au-sydney_north_shore       |   12 +
 util/scan/dvb-t/au-unknown                  |    3 +
 util/scan/dvb-t/de-Berlin                   |    5 +
 util/scan/dvb-t/es-Collserola               |    6 +
 util/scan/dvb-t/fi-Espoo                    |    3 +
 util/scan/dvb-t/fi-Tampere                  |    6 +
 util/scan/dvb-t/fi-Turku                    |    3 +
 util/scan/dvb-t/nl-AlphenaandenRijn         |    7 +
 util/scan/dvb-t/nl-Randstad                 |    7 +
 util/scan/dvb-t/se-Gavle                    |    6 +
 util/scan/dvb-t/uk-BlackHill                |    3 +
 util/scan/dvb-t/uk-CrystalPalace            |    3 +
 util/scan/dvb-t/uk-Hannington               |    3 +
 util/scan/dvb-t/uk-Oxford                   |    3 +
 util/scan/dvb-t/uk-PontopPike               |    3 +
 util/scan/dvb-t/uk-Redruth                  |    3 +
 util/scan/dvb-t/uk-Reigate                  |    3 +
 util/scan/dvb-t/uk-Rowridge                 |    3 +
 util/scan/dvb-t/uk-SandyHeath               |    3 +
 util/scan/dvb-t/uk-Storeton                 |    3 +
 util/scan/dvb-t/uk-WinterHill               |    3 +
 util/scan/list.h                            |  140 ++
 util/scan/scan.c                            | 1928 +++++++++++++++++++++++++++
 util/scan/scan.h                            |   29 +
 util/szap/Makefile                          |   35 +
 util/szap/README                            |   47 +
 util/szap/channels.conf-dvbc-berlin         |  171 +++
 util/szap/channels.conf-dvbs-astra          |  226 ++++
 util/szap/channels.conf-dvbt-australia      |   31 +
 util/szap/channels.conf-dvbt-berlin         |   51 +
 util/szap/channels.conf-dvbt-collserola     |   25 +
 util/szap/channels.conf-dvbt-crystal-palace |   70 +
 util/szap/channels.conf-dvbt-hannington     |   28 +
 util/szap/channels.conf-dvbt-madrid         |   16 +
 util/szap/channels.conf-dvbt-oxford         |   41 +
 util/szap/channels.conf-dvbt-reigate        |   51 +
 util/szap/channels.conf-dvbt-sandy_heath    |   13 +
 util/szap/czap.c                            |  368 +++++
 util/szap/femon.c                           |  149 +++
 util/szap/szap.c                            |  560 ++++++++
 util/szap/tzap.c                            |  477 +++++++
 util/ttusb_dec_reset/Makefile               |   17 +
 util/ttusb_dec_reset/README                 |   28 +
 util/ttusb_dec_reset/ttusb_dec_reset.c      |   53 +
 135 files changed, 12823 insertions(+)

diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..e0eadcf
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,28 @@
+# Makefile for linuxtv.org dvb-apps
+
+VERSION := 1.1.0
+PACKAGE := linuxtv-dvb-apps-$(VERSION)
+CVSROOT := $(shell cat CVS/Root)
+RELEASE_TAG := LINUXTV-DVB-$(subst .,_,$(subst -,_,$(VERSION)))
+
+all:
+
+release dist:
+	rm -rf release-tmp $(PACKAGE).tar.gz
+	mkdir release-tmp
+	( cd release-tmp; cvs -d$(CVSROOT) export -r$(RELEASE_TAG) -d$(PACKAGE) dvb-apps )
+	find release-tmp -name .cvsignore | xargs rm -v
+	( cd release-tmp; tar cjf ../$(PACKAGE).tar.bz2 $(PACKAGE) )
+	rm -rf release-tmp
+	@echo
+	@echo --------------------------------------------------------------------------------
+	@echo
+	@echo "dist package: ./$(PACKAGE).tar.bz2"
+	@echo
+	@echo --------------------------------------------------------------------------------
+	@echo
+
+%::
+#	$(MAKE) -C libdvb2 $(MAKECMDGOALS)
+	$(MAKE) -C util $(MAKECMDGOALS)
+	$(MAKE) -C test $(MAKECMDGOALS)
diff --git a/README b/README
new file mode 100644
index 0000000..190a4c4
--- /dev/null
+++ b/README
@@ -0,0 +1,21 @@
+linuxtv-dvb-apps-1.1.0
+======================
+
+Linux DVB API test/demo applications and utilities.
+
+You find a README in each subdirectory explaining what the code there does.
+For beginners utils/szap/ and utils/scan/ are probably most useful.
+
+For convenience, dvb-apps contains a copy of the DVB API include
+files as they are contained in the linuxtv-dvb-1.1.0 realease
+and the 2.6.x Linux kernel. However, since the DVB API hasn't changed,
+the apps will still work with the old "DVB" drivers, should you decide not
+to use linuxtv-dvb-1.1.0 (or the dvb-kernel CVS).
+
+
+Historical note:
+The apps have been copied from the "DVB" CVS tree, which means that
+the stuff in "DVB" is now unmaintained and out of date.
+
+
+Johannes Stezenbach <js at convergence.de>
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..416b66f
--- /dev/null
+++ b/TODO
@@ -0,0 +1 @@
+- create libdvb2, possibly merging util/lib/*
diff --git a/include/linux/dvb/audio.h b/include/linux/dvb/audio.h
new file mode 100644
index 0000000..58956c3
--- /dev/null
+++ b/include/linux/dvb/audio.h
@@ -0,0 +1,125 @@
+/* 
+ * audio.h
+ *
+ * Copyright (C) 2000 Ralph  Metzler <ralph at convergence.de>
+ *                  & Marcus Metzler <marcus at convergence.de>
+                      for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Lesser Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _DVBAUDIO_H_
+#define _DVBAUDIO_H_
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <stdint.h>
+#endif
+
+
+typedef enum {
+        AUDIO_SOURCE_DEMUX, /* Select the demux as the main source */ 
+	AUDIO_SOURCE_MEMORY /* Select internal memory as the main source */ 
+} audio_stream_source_t;
+
+
+typedef enum { 
+	AUDIO_STOPPED,      /* Device is stopped */ 
+        AUDIO_PLAYING,      /* Device is currently playing */ 
+	AUDIO_PAUSED        /* Device is paused */ 
+} audio_play_state_t;
+
+
+typedef enum {
+        AUDIO_STEREO,
+        AUDIO_MONO_LEFT, 
+	AUDIO_MONO_RIGHT 
+} audio_channel_select_t;
+
+
+typedef struct audio_mixer { 
+        unsigned int volume_left;
+        unsigned int volume_right;
+  // what else do we need? bass, pass-through, ...
+} audio_mixer_t;
+
+
+typedef struct audio_status { 
+        int                    AV_sync_state;  /* sync audio and video? */
+        int                    mute_state;     /* audio is muted */ 
+        audio_play_state_t     play_state;     /* current playback state */
+        audio_stream_source_t  stream_source;  /* current stream source */
+        audio_channel_select_t channel_select; /* currently selected channel */
+        int                    bypass_mode;    /* pass on audio data to */
+	audio_mixer_t	       mixer_state;    /* current mixer state */
+} audio_status_t;                              /* separate decoder hardware */
+
+
+typedef
+struct audio_karaoke{  /* if Vocal1 or Vocal2 are non-zero, they get mixed  */
+	int vocal1;    /* into left and right t at 70% each */
+	int vocal2;    /* if both, Vocal1 and Vocal2 are non-zero, Vocal1 gets*/
+	int melody;    /* mixed into the left channel and */
+                       /* Vocal2 into the right channel at 100% each. */
+                       /* if Melody is non-zero, the melody channel gets mixed*/
+} audio_karaoke_t;     /* into left and right  */
+
+
+typedef uint16_t audio_attributes_t;
+/*   bits: descr. */
+/*   15-13 audio coding mode (0=ac3, 2=mpeg1, 3=mpeg2ext, 4=LPCM, 6=DTS, */
+/*   12    multichannel extension */
+/*   11-10 audio type (0=not spec, 1=language included) */
+/*    9- 8 audio application mode (0=not spec, 1=karaoke, 2=surround) */
+/*    7- 6 Quantization / DRC (mpeg audio: 1=DRC exists)(lpcm: 0=16bit,  */
+/*    5- 4 Sample frequency fs (0=48kHz, 1=96kHz) */
+/*    2- 0 number of audio channels (n+1 channels) */
+ 
+
+/* for GET_CAPABILITIES and SET_FORMAT, the latter should only set one bit */
+#define AUDIO_CAP_DTS    1
+#define AUDIO_CAP_LPCM   2
+#define AUDIO_CAP_MP1    4
+#define AUDIO_CAP_MP2    8
+#define AUDIO_CAP_MP3   16
+#define AUDIO_CAP_AAC   32
+#define AUDIO_CAP_OGG   64
+#define AUDIO_CAP_SDDS 128
+#define AUDIO_CAP_AC3  256
+
+#define AUDIO_STOP                 _IO('o', 1) 
+#define AUDIO_PLAY                 _IO('o', 2)
+#define AUDIO_PAUSE                _IO('o', 3)
+#define AUDIO_CONTINUE             _IO('o', 4)
+#define AUDIO_SELECT_SOURCE        _IO('o', 5)
+#define AUDIO_SET_MUTE             _IO('o', 6)
+#define AUDIO_SET_AV_SYNC          _IO('o', 7)
+#define AUDIO_SET_BYPASS_MODE      _IO('o', 8)
+#define AUDIO_CHANNEL_SELECT       _IO('o', 9)
+#define AUDIO_GET_STATUS           _IOR('o', 10, audio_status_t)
+
+#define AUDIO_GET_CAPABILITIES     _IOR('o', 11, unsigned int)
+#define AUDIO_CLEAR_BUFFER         _IO('o',  12)
+#define AUDIO_SET_ID               _IO('o', 13)
+#define AUDIO_SET_MIXER            _IOW('o', 14, audio_mixer_t)
+#define AUDIO_SET_STREAMTYPE       _IO('o', 15)
+#define AUDIO_SET_EXT_ID           _IO('o', 16)
+#define AUDIO_SET_ATTRIBUTES       _IOW('o', 17, audio_attributes_t)
+#define AUDIO_SET_KARAOKE          _IOW('o', 18, audio_karaoke_t)
+
+#endif /* _DVBAUDIO_H_ */
+
diff --git a/include/linux/dvb/ca.h b/include/linux/dvb/ca.h
new file mode 100644
index 0000000..026e5c3
--- /dev/null
+++ b/include/linux/dvb/ca.h
@@ -0,0 +1,91 @@
+/* 
+ * ca.h
+ *
+ * Copyright (C) 2000 Ralph  Metzler <ralph at convergence.de>
+ *                  & Marcus Metzler <marcus at convergence.de>
+                      for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Lesser Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _DVBCA_H_
+#define _DVBCA_H_
+
+/* slot interface types and info */
+
+typedef struct ca_slot_info {
+        int num;               /* slot number */
+
+        int type;              /* CA interface this slot supports */
+#define CA_CI            1     /* CI high level interface */
+#define CA_CI_LINK       2     /* CI link layer level interface */
+#define CA_CI_PHYS       4     /* CI physical layer level interface */
+#define CA_DESCR         8     /* built-in descrambler */
+#define CA_SC          128     /* simple smart card interface */
+
+        unsigned int flags;
+#define CA_CI_MODULE_PRESENT 1 /* module (or card) inserted */
+#define CA_CI_MODULE_READY   2
+} ca_slot_info_t;
+
+
+/* descrambler types and info */
+
+typedef struct ca_descr_info {
+        unsigned int num;          /* number of available descramblers (keys) */
+        unsigned int type;         /* type of supported scrambling system */
+#define CA_ECD           1
+#define CA_NDS           2
+#define CA_DSS           4
+} ca_descr_info_t;
+
+typedef struct ca_caps {
+        unsigned int slot_num;     /* total number of CA card and module slots */
+        unsigned int slot_type;    /* OR of all supported types */
+        unsigned int descr_num;    /* total number of descrambler slots (keys) */
+        unsigned int descr_type;   /* OR of all supported types */
+} ca_caps_t;
+
+/* a message to/from a CI-CAM */
+typedef struct ca_msg {
+        unsigned int index;
+        unsigned int type;
+        unsigned int length;
+        unsigned char msg[256];
+} ca_msg_t;
+
+typedef struct ca_descr {
+        unsigned int index;
+        unsigned int parity;	/* 0 == even, 1 == odd */
+        unsigned char cw[8];
+} ca_descr_t;
+
+typedef struct ca_pid {
+        unsigned int pid;
+        int index;		/* -1 == disable*/
+} ca_pid_t;
+
+#define CA_RESET          _IO('o', 128)
+#define CA_GET_CAP        _IOR('o', 129, ca_caps_t)
+#define CA_GET_SLOT_INFO  _IOR('o', 130, ca_slot_info_t)
+#define CA_GET_DESCR_INFO _IOR('o', 131, ca_descr_info_t)
+#define CA_GET_MSG        _IOR('o', 132, ca_msg_t)
+#define CA_SEND_MSG       _IOW('o', 133, ca_msg_t)
+#define CA_SET_DESCR      _IOW('o', 134, ca_descr_t)
+#define CA_SET_PID        _IOW('o', 135, ca_pid_t)
+
+#endif
+
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
new file mode 100644
index 0000000..62e6217
--- /dev/null
+++ b/include/linux/dvb/dmx.h
@@ -0,0 +1,181 @@
+/* 
+ * dmx.h
+ *
+ * Copyright (C) 2000 Marcus Metzler <marcus at convergence.de>
+ *                  & Ralph  Metzler <ralph at convergence.de>
+                      for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _DVBDMX_H_
+#define _DVBDMX_H_
+
+#include <asm/types.h>
+#ifdef __KERNEL__
+#include <linux/time.h>
+#else
+#include <time.h>
+#endif
+
+
+#define DMX_FILTER_SIZE 16
+
+typedef enum
+{
+	DMX_OUT_DECODER, /* Streaming directly to decoder. */
+	DMX_OUT_TAP,     /* Output going to a memory buffer */
+	                 /* (to be retrieved via the read command).*/
+	DMX_OUT_TS_TAP   /* Output multiplexed into a new TS  */
+	                 /* (to be retrieved by reading from the */
+	                 /* logical DVR device).                 */
+} dmx_output_t;
+
+
+typedef enum
+{
+	DMX_IN_FRONTEND, /* Input from a front-end device.  */
+	DMX_IN_DVR       /* Input from the logical DVR device.  */
+} dmx_input_t;
+
+
+typedef enum
+{
+        DMX_PES_AUDIO0,
+	DMX_PES_VIDEO0,
+	DMX_PES_TELETEXT0,
+	DMX_PES_SUBTITLE0,
+	DMX_PES_PCR0,
+
+        DMX_PES_AUDIO1,
+	DMX_PES_VIDEO1,
+	DMX_PES_TELETEXT1,
+	DMX_PES_SUBTITLE1,
+	DMX_PES_PCR1,
+
+        DMX_PES_AUDIO2,
+	DMX_PES_VIDEO2,
+	DMX_PES_TELETEXT2,
+	DMX_PES_SUBTITLE2,
+	DMX_PES_PCR2,
+
+        DMX_PES_AUDIO3,
+	DMX_PES_VIDEO3,
+	DMX_PES_TELETEXT3,
+	DMX_PES_SUBTITLE3,
+	DMX_PES_PCR3,
+
+	DMX_PES_OTHER
+} dmx_pes_type_t;
+
+#define DMX_PES_AUDIO    DMX_PES_AUDIO0
+#define DMX_PES_VIDEO    DMX_PES_VIDEO0
+#define DMX_PES_TELETEXT DMX_PES_TELETEXT0
+#define DMX_PES_SUBTITLE DMX_PES_SUBTITLE0
+#define DMX_PES_PCR      DMX_PES_PCR0
+
+
+typedef enum
+{
+        DMX_SCRAMBLING_EV,
+        DMX_FRONTEND_EV
+} dmx_event_t;
+
+
+typedef enum
+{
+	DMX_SCRAMBLING_OFF,
+	DMX_SCRAMBLING_ON
+} dmx_scrambling_status_t;
+
+
+typedef struct dmx_filter
+{
+	__u8  filter[DMX_FILTER_SIZE];
+	__u8  mask[DMX_FILTER_SIZE];
+	__u8  mode[DMX_FILTER_SIZE];
+} dmx_filter_t;
+
+
+struct dmx_sct_filter_params
+{
+	__u16            pid;
+	dmx_filter_t   filter;
+	__u32            timeout;
+	__u32            flags;
+#define DMX_CHECK_CRC       1
+#define DMX_ONESHOT         2
+#define DMX_IMMEDIATE_START 4
+#define DMX_KERNEL_CLIENT   0x8000
+};
+
+
+struct dmx_pes_filter_params
+{
+	__u16            pid;
+	dmx_input_t    input;
+	dmx_output_t   output;
+	dmx_pes_type_t pes_type;
+	__u32            flags;
+};
+
+
+struct dmx_event
+{
+	dmx_event_t         event;
+	time_t              timeStamp;
+	union
+	{
+		dmx_scrambling_status_t scrambling;
+	} u;
+};
+
+typedef struct dmx_caps {
+	__u32 caps;
+	int num_decoders; 
+} dmx_caps_t;
+
+typedef enum {
+	DMX_SOURCE_FRONT0 = 0,
+	DMX_SOURCE_FRONT1,
+	DMX_SOURCE_FRONT2,
+	DMX_SOURCE_FRONT3,
+	DMX_SOURCE_DVR0   = 16,
+	DMX_SOURCE_DVR1,
+	DMX_SOURCE_DVR2,
+	DMX_SOURCE_DVR3
+} dmx_source_t;
+
+struct dmx_stc {
+	unsigned int num;	/* input : which STC? 0..N */
+	unsigned int base;	/* output: divisor for stc to get 90 kHz clock */
+	__u64 stc;		/* output: stc in 'base'*90 kHz units */
+};
+
+
+#define DMX_START                _IO('o', 41) 
+#define DMX_STOP                 _IO('o', 42)
+#define DMX_SET_FILTER           _IOW('o', 43, struct dmx_sct_filter_params)
+#define DMX_SET_PES_FILTER       _IOW('o', 44, struct dmx_pes_filter_params)
+#define DMX_SET_BUFFER_SIZE      _IO('o', 45)
+#define DMX_GET_EVENT            _IOR('o', 46, struct dmx_event)
+#define DMX_GET_PES_PIDS         _IOR('o', 47, __u16[5])
+#define DMX_GET_CAPS             _IOR('o', 48, dmx_caps_t)
+#define DMX_SET_SOURCE           _IOW('o', 49, dmx_source_t)
+#define DMX_GET_STC              _IOWR('o', 50, struct dmx_stc)
+
+#endif /*_DVBDMX_H_*/
+
diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h
new file mode 100644
index 0000000..3fa118e
--- /dev/null
+++ b/include/linux/dvb/frontend.h
@@ -0,0 +1,260 @@
+/*
+ * frontend.h
+ *
+ * Copyright (C) 2000 Marcus Metzler <marcus at convergence.de>
+ *                    Ralph  Metzler <ralph at convergence.de>
+ *                    Holger Waechtler <holger at convergence.de>
+ *                    Andre Draszik <ad at convergence.de>
+ *                    for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _DVBFRONTEND_H_
+#define _DVBFRONTEND_H_
+
+#include <asm/types.h>
+
+
+typedef enum fe_type {
+        FE_QPSK,
+        FE_QAM,
+        FE_OFDM
+} fe_type_t;
+
+
+typedef enum fe_caps {
+	FE_IS_STUPID                  = 0,
+	FE_CAN_INVERSION_AUTO         = 0x1,
+	FE_CAN_FEC_1_2                = 0x2,
+	FE_CAN_FEC_2_3                = 0x4,
+	FE_CAN_FEC_3_4                = 0x8,
+	FE_CAN_FEC_4_5                = 0x10,
+	FE_CAN_FEC_5_6                = 0x20,
+	FE_CAN_FEC_6_7                = 0x40,
+	FE_CAN_FEC_7_8                = 0x80,
+	FE_CAN_FEC_8_9                = 0x100,
+	FE_CAN_FEC_AUTO               = 0x200,
+	FE_CAN_QPSK                   = 0x400,
+	FE_CAN_QAM_16                 = 0x800,
+	FE_CAN_QAM_32                 = 0x1000,
+	FE_CAN_QAM_64                 = 0x2000,
+	FE_CAN_QAM_128                = 0x4000,
+	FE_CAN_QAM_256                = 0x8000,
+	FE_CAN_QAM_AUTO               = 0x10000,
+	FE_CAN_TRANSMISSION_MODE_AUTO = 0x20000,
+	FE_CAN_BANDWIDTH_AUTO         = 0x40000,
+	FE_CAN_GUARD_INTERVAL_AUTO    = 0x80000,
+	FE_CAN_HIERARCHY_AUTO         = 0x100000,
+	FE_CAN_RECOVER                = 0x20000000,
+	FE_CAN_CLEAN_SETUP            = 0x40000000,
+	FE_CAN_MUTE_TS                = 0x80000000
+} fe_caps_t;
+
+
+struct dvb_frontend_info {
+	char       name[128];
+        fe_type_t  type;
+        __u32      frequency_min;
+        __u32      frequency_max;
+	__u32      frequency_stepsize;
+	__u32      frequency_tolerance;
+	__u32      symbol_rate_min;
+        __u32      symbol_rate_max;
+	__u32      symbol_rate_tolerance;     /* ppm */
+	__u32      notifier_delay;            /* ms */
+	fe_caps_t  caps;
+};
+
+
+/**
+ *  Check out the DiSEqC bus spec available on http://www.eutelsat.org/ for
+ *  the meaning of this struct...
+ */
+struct dvb_diseqc_master_cmd {
+        __u8 msg [6];        /*  { framing, address, command, data [3] } */
+        __u8 msg_len;        /*  valid values are 3...6  */
+};
+
+
+struct dvb_diseqc_slave_reply {
+	__u8 msg [4];        /*  { framing, data [3] } */
+	__u8 msg_len;        /*  valid values are 0...4, 0 means no msg  */
+	int  timeout;        /*  return from ioctl after timeout ms with */
+};                           /*  errorcode when no message was received  */
+
+
+typedef enum fe_sec_voltage {
+        SEC_VOLTAGE_13,
+        SEC_VOLTAGE_18,
+	SEC_VOLTAGE_OFF
+} fe_sec_voltage_t;
+
+
+typedef enum fe_sec_tone_mode {
+        SEC_TONE_ON,
+        SEC_TONE_OFF
+} fe_sec_tone_mode_t;
+
+
+typedef enum fe_sec_mini_cmd {
+        SEC_MINI_A,
+        SEC_MINI_B
+} fe_sec_mini_cmd_t;
+
+
+typedef enum fe_status {
+	FE_HAS_SIGNAL     = 0x01,   /*  found something above the noise level */
+	FE_HAS_CARRIER    = 0x02,   /*  found a DVB signal  */
+	FE_HAS_VITERBI    = 0x04,   /*  FEC is stable  */
+	FE_HAS_SYNC       = 0x08,   /*  found sync bytes  */
+	FE_HAS_LOCK       = 0x10,   /*  everything's working... */
+	FE_TIMEDOUT       = 0x20,   /*  no lock within the last ~2 seconds */
+	FE_REINIT         = 0x40    /*  frontend was reinitialized,  */
+} fe_status_t;                      /*  application is recommended to reset */
+                                    /*  DiSEqC, tone and parameters */
+
+typedef enum fe_spectral_inversion {
+        INVERSION_OFF,
+        INVERSION_ON,
+        INVERSION_AUTO
+} fe_spectral_inversion_t;
+
+
+typedef enum fe_code_rate {
+        FEC_NONE = 0,
+        FEC_1_2,
+        FEC_2_3,
+        FEC_3_4,
+        FEC_4_5,
+        FEC_5_6,
+        FEC_6_7,
+        FEC_7_8,
+        FEC_8_9,
+        FEC_AUTO
+} fe_code_rate_t;
+
+
+typedef enum fe_modulation {
+        QPSK,
+        QAM_16,
+        QAM_32,
+        QAM_64,
+        QAM_128,
+        QAM_256,
+	QAM_AUTO
+} fe_modulation_t;
+
+
+typedef enum fe_transmit_mode {
+	TRANSMISSION_MODE_2K,
+	TRANSMISSION_MODE_8K,
+	TRANSMISSION_MODE_AUTO
+} fe_transmit_mode_t;
+
+typedef enum fe_bandwidth {
+	BANDWIDTH_8_MHZ,
+	BANDWIDTH_7_MHZ,
+	BANDWIDTH_6_MHZ,
+	BANDWIDTH_AUTO
+} fe_bandwidth_t;
+
+
+typedef enum fe_guard_interval {
+	GUARD_INTERVAL_1_32,
+	GUARD_INTERVAL_1_16,
+	GUARD_INTERVAL_1_8,
+	GUARD_INTERVAL_1_4,
+	GUARD_INTERVAL_AUTO
+} fe_guard_interval_t;
+
+
+typedef enum fe_hierarchy {
+	HIERARCHY_NONE,
+	HIERARCHY_1,
+	HIERARCHY_2,
+	HIERARCHY_4,
+	HIERARCHY_AUTO
+} fe_hierarchy_t;
+
+
+struct dvb_qpsk_parameters {
+        __u32           symbol_rate;  /* symbol rate in Symbols per second */
+        fe_code_rate_t  fec_inner;    /* forward error correction (see above) */
+};
+
+
+struct dvb_qam_parameters {
+        __u32            symbol_rate; /* symbol rate in Symbols per second */
+        fe_code_rate_t   fec_inner;   /* forward error correction (see above) */
+        fe_modulation_t  modulation;  /* modulation type (see above) */
+};
+
+
+struct dvb_ofdm_parameters {
+        fe_bandwidth_t      bandwidth;
+        fe_code_rate_t      code_rate_HP;  /* high priority stream code rate */
+        fe_code_rate_t      code_rate_LP;  /* low priority stream code rate */
+        fe_modulation_t     constellation; /* modulation type (see above) */
+        fe_transmit_mode_t  transmission_mode;
+        fe_guard_interval_t guard_interval;
+        fe_hierarchy_t      hierarchy_information;
+};
+
+
+struct dvb_frontend_parameters {
+        __u32 frequency;     /* (absolute) frequency in Hz for QAM/OFDM */
+                             /* intermediate frequency in kHz for QPSK */
+	fe_spectral_inversion_t inversion;
+	union {
+		struct dvb_qpsk_parameters qpsk;
+		struct dvb_qam_parameters  qam;
+		struct dvb_ofdm_parameters ofdm;
+	} u;
+};
+
+
+struct dvb_frontend_event {
+	fe_status_t status;
+	struct dvb_frontend_parameters parameters;
+};
+
+
+
+#define FE_GET_INFO                _IOR('o', 61, struct dvb_frontend_info)
+
+#define FE_DISEQC_RESET_OVERLOAD   _IO('o', 62)
+#define FE_DISEQC_SEND_MASTER_CMD  _IOW('o', 63, struct dvb_diseqc_master_cmd)
+#define FE_DISEQC_RECV_SLAVE_REPLY _IOR('o', 64, struct dvb_diseqc_slave_reply)
+#define FE_DISEQC_SEND_BURST       _IO('o', 65)  /* fe_sec_mini_cmd_t */
+
+#define FE_SET_TONE                _IO('o', 66)  /* fe_sec_tone_mode_t */
+#define FE_SET_VOLTAGE             _IO('o', 67)  /* fe_sec_voltage_t */
+#define FE_ENABLE_HIGH_LNB_VOLTAGE _IO('o', 68)  /* int */
+
+#define FE_READ_STATUS             _IOR('o', 69, fe_status_t)
+#define FE_READ_BER                _IOR('o', 70, __u32)
+#define FE_READ_SIGNAL_STRENGTH    _IOR('o', 71, __u16)
+#define FE_READ_SNR                _IOR('o', 72, __u16)
+#define FE_READ_UNCORRECTED_BLOCKS _IOR('o', 73, __u32)
+
+#define FE_SET_FRONTEND            _IOW('o', 76, struct dvb_frontend_parameters)
+#define FE_GET_FRONTEND            _IOR('o', 77, struct dvb_frontend_parameters)
+#define FE_GET_EVENT               _IOR('o', 78, struct dvb_frontend_event)
+
+
+#endif /*_DVBFRONTEND_H_*/
+
diff --git a/include/linux/dvb/net.h b/include/linux/dvb/net.h
new file mode 100644
index 0000000..4b8fa51
--- /dev/null
+++ b/include/linux/dvb/net.h
@@ -0,0 +1,41 @@
+/* 
+ * net.h
+ *
+ * Copyright (C) 2000 Marcus Metzler <marcus at convergence.de>
+ *                  & Ralph  Metzler <ralph at convergence.de>
+                      for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _DVBNET_H_
+#define _DVBNET_H_
+
+#include <asm/types.h>
+
+
+struct dvb_net_if {
+	__u16 pid;
+	__u16 if_num;
+};
+
+
+#define NET_ADD_IF                 _IOWR('o', 52, struct dvb_net_if)
+#define NET_REMOVE_IF              _IO('o', 53)
+#define NET_GET_IF                 _IOWR('o', 54, struct dvb_net_if)
+
+#endif /*_DVBNET_H_*/
+
diff --git a/include/linux/dvb/osd.h b/include/linux/dvb/osd.h
new file mode 100644
index 0000000..0d81439
--- /dev/null
+++ b/include/linux/dvb/osd.h
@@ -0,0 +1,111 @@
+/* 
+ * osd.h
+ *
+ * Copyright (C) 2001 Ralph  Metzler <ralph at convergence.de>
+ *                  & Marcus Metzler <marcus at convergence.de>
+                      for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Lesser Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _DVBOSD_H_
+#define _DVBOSD_H_
+
+typedef enum {
+  // All functions return -2 on "not open"
+  OSD_Close=1,    // ()
+  // Disables OSD and releases the buffers
+  // returns 0 on success
+  OSD_Open,       // (x0,y0,x1,y1,BitPerPixel[2/4/8](color&0x0F),mix[0..15](color&0xF0))
+  // Opens OSD with this size and bit depth
+  // returns 0 on success, -1 on DRAM allocation error, -2 on "already open"
+  OSD_Show,       // ()
+  // enables OSD mode
+  // returns 0 on success
+  OSD_Hide,       // ()
+  // disables OSD mode
+  // returns 0 on success
+  OSD_Clear,      // ()
+  // Sets all pixel to color 0
+  // returns 0 on success
+  OSD_Fill,       // (color)
+  // Sets all pixel to color <col>
+  // returns 0 on success
+  OSD_SetColor,   // (color,R{x0},G{y0},B{x1},opacity{y1})
+  // set palette entry <num> to <r,g,b>, <mix> and <trans> apply
+  // R,G,B: 0..255
+  // R=Red, G=Green, B=Blue
+  // opacity=0:      pixel opacity 0% (only video pixel shows)
+  // opacity=1..254: pixel opacity as specified in header
+  // opacity=255:    pixel opacity 100% (only OSD pixel shows)
+  // returns 0 on success, -1 on error
+  OSD_SetPalette, // (firstcolor{color},lastcolor{x0},data)
+  // Set a number of entries in the palette
+  // sets the entries "firstcolor" through "lastcolor" from the array "data"
+  // data has 4 byte for each color:
+  // R,G,B, and a opacity value: 0->transparent, 1..254->mix, 255->pixel
+  OSD_SetTrans,   // (transparency{color})
+  // Sets transparency of mixed pixel (0..15)
+  // returns 0 on success
+  OSD_SetPixel,   // (x0,y0,color)
+  // sets pixel <x>,<y> to color number <col>
+  // returns 0 on success, -1 on error
+  OSD_GetPixel,   // (x0,y0)
+  // returns color number of pixel <x>,<y>,  or -1
+  OSD_SetRow,     // (x0,y0,x1,data)
+  // fills pixels x0,y through  x1,y with the content of data[]
+  // returns 0 on success, -1 on clipping all pixel (no pixel drawn)
+  OSD_SetBlock,   // (x0,y0,x1,y1,increment{color},data)
+  // fills pixels x0,y0 through  x1,y1 with the content of data[]
+  // inc contains the width of one line in the data block,
+  // inc<=0 uses blockwidth as linewidth
+  // returns 0 on success, -1 on clipping all pixel
+  OSD_FillRow,    // (x0,y0,x1,color)
+  // fills pixels x0,y through  x1,y with the color <col>
+  // returns 0 on success, -1 on clipping all pixel
+  OSD_FillBlock,  // (x0,y0,x1,y1,color)
+  // fills pixels x0,y0 through  x1,y1 with the color <col>
+  // returns 0 on success, -1 on clipping all pixel
+  OSD_Line,       // (x0,y0,x1,y1,color)
+  // draw a line from x0,y0 to x1,y1 with the color <col>
+  // returns 0 on success
+  OSD_Query,      // (x0,y0,x1,y1,xasp{color}}), yasp=11
+  // fills parameters with the picture dimensions and the pixel aspect ratio
+  // returns 0 on success
+  OSD_Test,       // ()
+  // draws a test picture. for debugging purposes only
+  // returns 0 on success
+// TODO: remove "test" in final version
+  OSD_Text,       // (x0,y0,size,color,text)
+  OSD_SetWindow, //  (x0) set window with number 0<x0<8 as current
+  OSD_MoveWindow, //  move current window to (x0, y0)  
+} OSD_Command;
+
+typedef struct osd_cmd_s {
+        OSD_Command cmd;
+        int x0;
+        int y0;
+        int x1;
+        int y1;
+        int color;
+        void *data;
+} osd_cmd_t;
+
+
+#define OSD_SEND_CMD       _IOW('o', 160, osd_cmd_t)
+
+#endif
+
diff --git a/include/linux/dvb/version.h b/include/linux/dvb/version.h
new file mode 100644
index 0000000..54e256e
--- /dev/null
+++ b/include/linux/dvb/version.h
@@ -0,0 +1,29 @@
+/*
+ * version.h
+ *
+ * Copyright (C) 2000 Holger Waechtler <holger at convergence.de>
+ *                    for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _DVBVERSION_H_
+#define _DVBVERSION_H_
+
+#define DVB_API_VERSION 3
+
+#endif /*_DVBVERSION_H_*/
+
diff --git a/include/linux/dvb/video.h b/include/linux/dvb/video.h
new file mode 100644
index 0000000..a8b6008
--- /dev/null
+++ b/include/linux/dvb/video.h
@@ -0,0 +1,199 @@
+/* 
+ * video.h
+ *
+ * Copyright (C) 2000 Marcus Metzler <marcus at convergence.de>
+ *                  & Ralph  Metzler <ralph at convergence.de>
+                      for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#ifndef _DVBVIDEO_H_
+#define _DVBVIDEO_H_
+
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <stdint.h>
+#include <time.h>
+#endif
+
+
+typedef enum {
+	VIDEO_FORMAT_4_3,     /* Select 4:3 format */
+        VIDEO_FORMAT_16_9,    /* Select 16:9 format. */
+	VIDEO_FORMAT_221_1    /* 2.21:1 */
+} video_format_t;
+
+
+typedef enum {
+	 VIDEO_SYSTEM_PAL, 
+	 VIDEO_SYSTEM_NTSC, 
+	 VIDEO_SYSTEM_PALN, 
+	 VIDEO_SYSTEM_PALNc, 
+	 VIDEO_SYSTEM_PALM, 
+	 VIDEO_SYSTEM_NTSC60, 
+	 VIDEO_SYSTEM_PAL60,
+	 VIDEO_SYSTEM_PALM60
+} video_system_t;
+
+
+typedef enum {   
+        VIDEO_PAN_SCAN,       /* use pan and scan format */
+	VIDEO_LETTER_BOX,     /* use letterbox format */
+	VIDEO_CENTER_CUT_OUT  /* use center cut out format */
+} video_displayformat_t;
+
+typedef struct {
+	int w;
+	int h;
+	video_format_t aspect_ratio;
+} video_size_t;
+
+typedef enum {
+        VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */ 
+	VIDEO_SOURCE_MEMORY /* If this source is selected, the stream 
+			       comes from the user through the write 
+			       system call */ 
+} video_stream_source_t;
+
+
+typedef enum {
+	VIDEO_STOPPED, /* Video is stopped */ 
+        VIDEO_PLAYING, /* Video is currently playing */ 
+	VIDEO_FREEZED  /* Video is freezed */ 
+} video_play_state_t; 
+
+
+struct video_event { 
+        int32_t type; 
+#define VIDEO_EVENT_SIZE_CHANGED 1
+        time_t timestamp;
+	union {
+	        video_size_t size;
+	} u;
+};
+
+
+struct video_status { 
+        int                   video_blank;   /* blank video on freeze? */
+        video_play_state_t    play_state;    /* current state of playback */  
+        video_stream_source_t stream_source; /* current source (demux/memory) */
+        video_format_t        video_format;  /* current aspect ratio of stream*/
+        video_displayformat_t display_format;/* selected cropping mode */
+};
+
+
+struct video_still_picture {
+        char *iFrame;        /* pointer to a single iframe in memory */
+        int32_t size; 
+};
+
+
+typedef 
+struct video_highlight {
+	int     active;      /*    1=show highlight, 0=hide highlight */
+	uint8_t contrast1;   /*    7- 4  Pattern pixel contrast */
+                             /*    3- 0  Background pixel contrast */
+	uint8_t contrast2;   /*    7- 4  Emphasis pixel-2 contrast */
+                             /*    3- 0  Emphasis pixel-1 contrast */
+	uint8_t color1;      /*    7- 4  Pattern pixel color */
+                             /*    3- 0  Background pixel color */
+	uint8_t color2;      /*    7- 4  Emphasis pixel-2 color */
+                             /*    3- 0  Emphasis pixel-1 color */
+ 	uint32_t ypos;       /*   23-22  auto action mode */
+                             /*   21-12  start y */
+                             /*    9- 0  end y */
+	uint32_t xpos;       /*   23-22  button color number */
+                             /*   21-12  start x */
+                             /*    9- 0  end x */
+} video_highlight_t;
+
+
+typedef struct video_spu {
+	int active;
+	int stream_id;
+} video_spu_t;
+
+
+typedef struct video_spu_palette {      /* SPU Palette information */
+	int length;
+	uint8_t *palette;
+} video_spu_palette_t;
+
+
+typedef struct video_navi_pack {
+	int length;          /* 0 ... 1024 */
+	uint8_t data[1024];
+} video_navi_pack_t;
+
+
+typedef uint16_t video_attributes_t;
+/*   bits: descr. */
+/*   15-14 Video compression mode (0=MPEG-1, 1=MPEG-2) */
+/*   13-12 TV system (0=525/60, 1=625/50) */
+/*   11-10 Aspect ratio (0=4:3, 3=16:9) */
+/*    9- 8 permitted display mode on 4:3 monitor (0=both, 1=only pan-sca */
+/*    7    line 21-1 data present in GOP (1=yes, 0=no) */
+/*    6    line 21-2 data present in GOP (1=yes, 0=no) */
+/*    5- 3 source resolution (0=720x480/576, 1=704x480/576, 2=352x480/57 */
+/*    2    source letterboxed (1=yes, 0=no) */
+/*    0    film/camera mode (0=camera, 1=film (625/50 only)) */
+
+
+/* bit definitions for capabilities: */
+/* can the hardware decode MPEG1 and/or MPEG2? */
+#define VIDEO_CAP_MPEG1   1 
+#define VIDEO_CAP_MPEG2   2
+/* can you send a system and/or program stream to video device?
+   (you still have to open the video and the audio device but only 
+    send the stream to the video device) */
+#define VIDEO_CAP_SYS     4
+#define VIDEO_CAP_PROG    8
+/* can the driver also handle SPU, NAVI and CSS encoded data? 
+   (CSS API is not present yet) */
+#define VIDEO_CAP_SPU    16
+#define VIDEO_CAP_NAVI   32
+#define VIDEO_CAP_CSS    64
+
+
+#define VIDEO_STOP                 _IO('o', 21) 
+#define VIDEO_PLAY                 _IO('o', 22)
+#define VIDEO_FREEZE               _IO('o', 23)
+#define VIDEO_CONTINUE             _IO('o', 24)
+#define VIDEO_SELECT_SOURCE        _IO('o', 25)
+#define VIDEO_SET_BLANK            _IO('o', 26)
+#define VIDEO_GET_STATUS           _IOR('o', 27, struct video_status)
+#define VIDEO_GET_EVENT            _IOR('o', 28, struct video_event)
+#define VIDEO_SET_DISPLAY_FORMAT   _IO('o', 29)
+#define VIDEO_STILLPICTURE         _IOW('o', 30, struct video_still_picture)
+#define VIDEO_FAST_FORWARD         _IO('o', 31)
+#define VIDEO_SLOWMOTION           _IO('o', 32)
+#define VIDEO_GET_CAPABILITIES     _IOR('o', 33, unsigned int)
+#define VIDEO_CLEAR_BUFFER         _IO('o',  34)
+#define VIDEO_SET_ID               _IO('o', 35)
+#define VIDEO_SET_STREAMTYPE       _IO('o', 36)
+#define VIDEO_SET_FORMAT           _IO('o', 37)
+#define VIDEO_SET_SYSTEM           _IO('o', 38)
+#define VIDEO_SET_HIGHLIGHT        _IOW('o', 39, video_highlight_t)
+#define VIDEO_SET_SPU              _IOW('o', 50, video_spu_t)
+#define VIDEO_SET_SPU_PALETTE      _IOW('o', 51, video_spu_palette_t)
+#define VIDEO_GET_NAVI             _IOR('o', 52, video_navi_pack_t)
+#define VIDEO_SET_ATTRIBUTES       _IO('o', 53)
+#define VIDEO_GET_SIZE             _IOR('o', 55, video_size_t)
+
+#endif /*_DVBVIDEO_H_*/
+
diff --git a/libdvb2/README b/libdvb2/README
new file mode 100644
index 0000000..049acd6
--- /dev/null
+++ b/libdvb2/README
@@ -0,0 +1,23 @@
+Late in 2003 the idea to create a simple DVB library from the code snippets
+in the test/utility programs was discussed on the linux-dvb mailing list.
+Hopefully someone will invest some time in this project to turn the idea into
+reality...
+
+Here is an outline of what libdvb2 should be, according to my recollection:
+(For first hand information search the linux-dvb list archives for "libdvb2".)
+
+- C
+- small: The goal is to make the library usable in *any* DVB project, which
+  is easier if the library sticks to the basics. Advanced stuff can be
+  done in a second library. What exacty "basic" and "advanced" means
+  is subject of discussion, but I want avoid to impose a certain programming
+  model (e.g. multi-threaded vw. event-loop) on users of the library.
+- a prime target is to establish a standard DVB config and service list
+  format, to make this sharable between different applications
+- LGPL
+
+About the name: There already is a libdvb written by the Metzler Bros.,
+but the main drawback is that it is written in C++ and thus rejected
+by many projects.
+
+Johannes Stezenbach <js at convergence.de>
diff --git a/test/Makefile b/test/Makefile
new file mode 100644
index 0000000..ddff9ab
--- /dev/null
+++ b/test/Makefile
@@ -0,0 +1,37 @@
+# Makefile for Linux DVB API Version 3 test programs
+
+CC = gcc
+CFLAGS = -g -O2 -W -Wall -I../include
+
+TARGETS = \
+	diseqc		\
+	set22k		\
+	sendburst	\
+	setvoltage	\
+	setpid		\
+	video		\
+	test_sections	\
+	test_sec_ne	\
+	test_pes	\
+	test_dvr	\
+	test_dvr_play	\
+	test_tt		\
+	test_av		\
+	test_av_play	\
+	test_vevent	\
+	test_stc	\
+	test_stillimage
+
+#	test		\
+#	test_audio	\
+#	test_front	\
+#	test_switch	\
+#	test_video	\
+
+all: $(TARGETS)
+
+test_sections test_sec_ne test_pes test_tt: hex_dump.o
+
+clean:
+	rm -f $(TARGETS) *.o
+
diff --git a/test/README b/test/README
new file mode 100644
index 0000000..b3f0cac
--- /dev/null
+++ b/test/README
@@ -0,0 +1,51 @@
+Various small test/sample programs for the Linux DVB API Version 2
+
+The default devices used by the test programs are generally
+/dev/dvb/adapter0/*0, and can be overridden using environment
+variables:
+
+  FRONTEND=/dev/dvb/adapter0/frontend0
+  DEMUX=/dev/dvb/adapter0/demux0
+  DVR=/dev/dvb/adapter0/dvr0
+  AUDIO=/dev/dvb/adapter0/audio0
+  VIDEO=/dev/dvb/adapter0/video0
+  NET=/dev/dvb/adapter0/net0
+
+
+diseqc		: Send various diseqc sequences on a SAT frontend.
+		  Best used with a diseqc test box with some LEDs to
+		  show the result of the commands.
+set22k		: Legacy tone switching for SAT frontends.
+setvoltage	: Legacy voltage switching for SAT frontends.
+
+setpid		: Set video and audio PIDs in the demux; useful only
+		  if you have a hardware MPEG decoder.
+video		: A tiny video watching application, just starts capturing /dev/video
+		  into /dev/fb0.
+		  WARNING: May crash your box or mess up your console!
+
+test_sections	: Hex dump of section data from stream.
+test_sec_ne	: Like test_sections, but also test Not-Equal filter mode.
+test_pes	: Hex dump of PES data from stream.
+test_tt		: Demonstrate teletext decoding from PES data.
+test_av		: Test audio and video MPEG decoder API.
+test_vevent	: Test VIDEO_GET_EVENT and poll() for video events
+test_stc	: Test DMX_GET_STC.
+
+test_stillimage : Display single iframes as stillimages
+		  iframes can be created with the 'convert' tool from 
+		  imagemagick and mpeg2encode from ftp.mpeg.org, and must 
+		  have a supported size, e.g. 702x576
+		  ($ convert -sample 702x576\! test.jpg test.mpg)
+
+(test_av_play	: Test playing MPEG TS from a file (apparently broken))
+
+
+test		:
+test_audio	:
+test_dmx	:
+test_dvr	:
+test_front	:
+test_switch	:
+test_video	:
+
diff --git a/test/dia b/test/dia
new file mode 100755
index 0000000..5cb2600
--- /dev/null
+++ b/test/dia
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+for f in $@
+do /usr/X11R6/bin/convert  -geomtry 702x576 $f test.mpg
+test_video test.mpg
+rm test.mpg
+done
\ No newline at end of file
diff --git a/test/diseqc.c b/test/diseqc.c
new file mode 100644
index 0000000..8f2e411
--- /dev/null
+++ b/test/diseqc.c
@@ -0,0 +1,140 @@
+/*
+ * Test sending DiSEqC commands on a SAT frontend.
+ *
+ * usage: FRONTEND=/dev/dvb/adapterX/frontendX diseqc [test_seq_no]
+ */
+
+#include <pthread.h>
+#include <time.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <linux/dvb/frontend.h>
+
+
+struct diseqc_cmd {
+	struct dvb_diseqc_master_cmd cmd;
+	uint32_t wait;
+};
+
+
+struct diseqc_cmd switch_cmds[] = {
+	{ { { 0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xf2, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xf1, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xf3, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xf4, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xf6, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xf5, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xf7, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xf8, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xfa, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xf9, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xfb, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xfc, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xfe, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xfd, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xff, 0x00, 0x00 }, 4 }, 0 }
+};
+
+
+/*--------------------------------------------------------------------------*/
+
+static inline
+void msleep(uint32_t msec)
+{
+	struct timespec req = { msec / 1000, 1000000 * (msec % 1000) };
+
+	while (nanosleep(&req, &req))
+		;
+}
+
+
+static
+void diseqc_send_msg(int fd, fe_sec_voltage_t v, struct diseqc_cmd **cmd,
+		     fe_sec_tone_mode_t t, fe_sec_mini_cmd_t b)
+{
+	ioctl(fd, FE_SET_TONE, SEC_TONE_OFF);
+	ioctl(fd, FE_SET_VOLTAGE, v);
+
+	msleep(15);
+	while (*cmd) {
+		printf("msg: %02x %02x %02x %02x %02x %02x\n",
+		       (*cmd)->cmd.msg[0], (*cmd)->cmd.msg[1],
+		       (*cmd)->cmd.msg[2], (*cmd)->cmd.msg[3],
+		       (*cmd)->cmd.msg[4], (*cmd)->cmd.msg[5]);
+
+		ioctl(fd, FE_DISEQC_SEND_MASTER_CMD, &(*cmd)->cmd);
+		msleep((*cmd)->wait);
+		cmd++;
+	}
+
+	printf("%s: ", __FUNCTION__);
+
+	printf(" %s ", v == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
+	       v == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "???");
+
+	printf(" %s ", b == SEC_MINI_A ? "SEC_MINI_A" :
+	       b == SEC_MINI_B ? "SEC_MINI_B" : "???");
+
+	printf(" %s\n", t == SEC_TONE_ON ? "SEC_TONE_ON" :
+	       t == SEC_TONE_OFF ? "SEC_TONE_OFF" : "???");
+
+	msleep(15);
+	ioctl(fd, FE_DISEQC_SEND_BURST, b);
+
+	msleep(15);
+	ioctl(fd, FE_SET_TONE, t);
+}
+
+
+int main(int argc, char **argv)
+{
+	struct diseqc_cmd *cmd[2] = { NULL, NULL };
+	char *fedev = "/dev/dvb/adapter0/frontend0";
+	int fd;
+
+	if (getenv("FRONTEND"))
+		fedev = getenv("FRONTEND");
+
+	printf("diseqc test: using '%s'\n", fedev);
+
+	if ((fd = open(fedev, O_RDWR)) < 0) {
+		perror("open");
+		return -1;
+	}
+
+	if (argc > 1) {
+		int i = atol(argv[1]);
+		cmd[0] = &switch_cmds[i];
+		diseqc_send_msg(fd,
+				i % 2 ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13,
+				cmd,
+				(i/2) % 2 ? SEC_TONE_ON : SEC_TONE_OFF,
+				(i/4) % 2 ? SEC_MINI_B : SEC_MINI_A);
+	} else {
+		unsigned int j;
+
+		for (j=0; j<sizeof(switch_cmds)/sizeof(struct diseqc_cmd); j++)
+		{
+			cmd[0] = &switch_cmds[j];
+			diseqc_send_msg(fd,
+					j % 2 ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13,
+					cmd,
+					(j/2) % 2 ? SEC_TONE_ON : SEC_TONE_OFF,
+					(j/4) % 2 ? SEC_MINI_B : SEC_MINI_A);
+			msleep (1000);
+		}
+	}
+
+	close(fd);
+
+	return 0;
+}
+
+
diff --git a/test/hex_dump.c b/test/hex_dump.c
new file mode 100644
index 0000000..c7c8ede
--- /dev/null
+++ b/test/hex_dump.c
@@ -0,0 +1,63 @@
+/* hex_dump.h -- simple hex dump routine
+ *
+ * Copyright (C) 2002 convergence GmbH
+ * Johannes Stezenbach <js at convergence.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "hex_dump.h"
+
+
+void hex_dump(uint8_t data[], int bytes)
+{
+	int i, j;
+	uint8_t c;
+
+	for (i = 0; i < bytes; i++) {
+		if (!(i % 8) && i)
+			printf(" ");
+		if (!(i % 16) && i) {
+			printf("  ");
+			for (j = 0; j < 16; j++) {
+				c = data[i+j-16];
+				if ((c < 0x20) || (c >= 0x7f))
+					c = '.';
+				printf("%c", c);
+			}
+			printf("\n");
+		}
+		printf("%.2x ", data[i]);
+	}
+	j = (bytes % 16);
+	j = (j != 0 ? j : 16);
+	for (i = j; i < 16; i++) {
+		if (!(i % 8) && i)
+			printf(" ");
+		printf("   ");
+	}
+	printf("   ");
+	for (i = bytes - j; i < bytes; i++) {
+		c = data[i];
+		if ((c < 0x20) || (c >= 0x7f))
+			c = '.';
+		printf("%c", c);
+	}
+	printf("\n");
+}
+
diff --git a/test/hex_dump.h b/test/hex_dump.h
new file mode 100644
index 0000000..030cc37
--- /dev/null
+++ b/test/hex_dump.h
@@ -0,0 +1,28 @@
+#ifndef _HEXDUMP_H_
+#define _HEXDUMP_H_
+/* hex_dump.h -- simple hex dump routine
+ *
+ * Copyright (C) 2002 convergence GmbH
+ * Johannes Stezenbach <js at convergence.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <stdint.h>
+
+extern void hex_dump(uint8_t data[], int bytes);
+
+
+#endif /* _HEXDUMP_H_ */
diff --git a/test/sendburst.c b/test/sendburst.c
new file mode 100644
index 0000000..a96b68c
--- /dev/null
+++ b/test/sendburst.c
@@ -0,0 +1,55 @@
+/*
+ * Test sending the burst mini command A/B on a SAT frontend.
+ *
+ * usage: FRONTEND=/dev/dvb/adapterX/frontendX sendburst {a|b}
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <linux/dvb/frontend.h>
+
+
+int main (int argc, char **argv)
+{
+   char *fedev = "/dev/dvb/adapter0/frontend0";
+   int fd, r;
+
+   if (argc != 2 || (strcmp(argv[1], "a") && strcmp(argv[1], "b"))) {
+      fprintf (stderr, "usage: %s <a|b>\n", argv[0]);
+      return 1;
+   }
+
+   if (getenv("FRONTEND"))
+	   fedev = getenv("FRONTEND");
+
+   printf("set22k: using '%s'\n", fedev);
+
+   if ((fd = open (fedev, O_RDWR)) < 0) {
+      perror ("open");
+      return 1;
+   }
+
+   ioctl (fd, FE_SET_TONE, SEC_TONE_OFF);
+
+   usleep (30000);    /*  30ms according to DiSEqC spec  */
+
+   if (strcmp(argv[1], "a") == 0)
+      r = ioctl (fd, FE_DISEQC_SEND_BURST, SEC_MINI_A);
+   else
+      r = ioctl (fd, FE_DISEQC_SEND_BURST, SEC_MINI_B);
+
+   if (r == -1)
+      perror("ioctl FE_SET_TONE");
+
+   close (fd);
+
+   return 0;
+}
+
diff --git a/test/set22k.c b/test/set22k.c
new file mode 100644
index 0000000..51ffa1c
--- /dev/null
+++ b/test/set22k.c
@@ -0,0 +1,50 @@
+/*
+ * Test switching the 22kHz tone signal on and off on a SAT frontend.
+ * (Note: DiSEqC equipment ignores this after it has once seen a diseqc
+ *  sequence; reload the driver or unplug/replug the SAT cable to reset.)
+ *
+ * usage: FRONTEND=/dev/dvb/adapterX/frontendX set22k {on|off}
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <linux/dvb/frontend.h>
+
+
+int main (int argc, char **argv)
+{
+   char *fedev = "/dev/dvb/adapter0/frontend0";
+   int fd, r;
+
+   if (argc != 2 || (strcmp(argv[1], "on") && strcmp(argv[1], "off"))) {
+      fprintf (stderr, "usage: %s <on|off>\n", argv[0]);
+      return 1;
+   }
+   if (getenv("FRONTEND"))
+	   fedev = getenv("FRONTEND");
+   printf("set22k: using '%s'\n", fedev);
+
+   if ((fd = open (fedev, O_RDWR)) < 0) {
+      perror ("open");
+      return 1;
+   }
+
+   if (strcmp(argv[1], "on") == 0)
+      r = ioctl (fd, FE_SET_TONE, SEC_TONE_ON);
+   else
+      r = ioctl (fd, FE_SET_TONE, SEC_TONE_OFF);
+   if (r == -1)
+	   perror("ioctl FE_SET_TONE");
+
+   close (fd);
+
+   return 0;
+}
+
diff --git a/test/setpid.c b/test/setpid.c
new file mode 100644
index 0000000..fa0333c
--- /dev/null
+++ b/test/setpid.c
@@ -0,0 +1,87 @@
+/*
+ * Set video and audio PIDs in the demux; useful only if you have
+ * a hardware MPEG decoder and you're tuned to a transport stream.
+ *
+ * usage: DEMUX=/dev/dvb/adapterX/demuxX setpid video_pid audio_pid
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <linux/dvb/dmx.h>
+
+
+static
+int setup_demux (char *dmxdev, int video_pid, int audio_pid)
+{
+   int vfd, afd;
+   struct dmx_pes_filter_params pesfilter;
+
+   printf ("video_pid == 0x%04x\n", video_pid);
+   printf ("audio_pid == 0x%04x\n", audio_pid);
+
+   if ((vfd = open (dmxdev, O_RDWR)) < 0) {
+      perror("open 1");
+      return -1;
+   }
+
+   pesfilter.pid = video_pid;
+   pesfilter.input = DMX_IN_FRONTEND;
+   pesfilter.output = DMX_OUT_DECODER;
+   pesfilter.pes_type = DMX_PES_VIDEO;
+   pesfilter.flags = DMX_IMMEDIATE_START;
+
+   if (ioctl (vfd, DMX_SET_PES_FILTER, &pesfilter) < 0) {
+      perror("ioctl DMX_SET_PES_FILTER (video)");
+      return -1;
+   }
+
+   close (vfd);
+
+   if ((afd = open (dmxdev, O_RDWR)) < 0) {
+      perror("open 1");
+      return -1;
+   }
+
+   pesfilter.pid = audio_pid;
+   pesfilter.input = DMX_IN_FRONTEND;
+   pesfilter.output = DMX_OUT_DECODER;
+   pesfilter.pes_type = DMX_PES_AUDIO;
+   pesfilter.flags = DMX_IMMEDIATE_START;
+
+   if (ioctl (afd, DMX_SET_PES_FILTER, &pesfilter) < 0) {
+      perror("ioctl DMX_SET_PES_FILTER (audio)");
+      return -1;
+   }
+
+   close (afd);
+   return 0;
+}
+
+
+int main (int argc, char **argv)
+{
+   char *dmxdev = "/dev/dvb/adapter0/demux0";
+   int video_pid, audio_pid;
+
+   if (argc != 3) {
+      printf ("\nusage: %s <video pid> <audio pid>\n\n", argv[0]);
+      exit (1);
+   }
+   if (getenv("DEMUX"))
+      dmxdev = getenv("DEMUX");
+   printf("setpid: using '%s'\n", dmxdev);
+
+   video_pid = strtol(argv[1], NULL, 0);
+   audio_pid = strtol(argv[2], NULL, 0);
+   if (setup_demux (dmxdev, video_pid, audio_pid) < 0)
+      return 1;
+
+   return 0;
+}
+
+
diff --git a/test/setvoltage.c b/test/setvoltage.c
new file mode 100644
index 0000000..1d14a4c
--- /dev/null
+++ b/test/setvoltage.c
@@ -0,0 +1,47 @@
+/*
+ * Test switching the voltage signal high and low on a SAT frontend.
+ * (Note: DiSEqC equipment ignores this after it has once seen a diseqc
+ *  sequence; reload the driver or unplug/replug the SAT cable to reset.)
+ *
+ * usage: FRONTEND=/dev/dvb/adapterX/frontendX setvoltage {13|18}
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <linux/dvb/frontend.h>
+
+
+int main (int argc, char **argv)
+{
+   char *fedev = "/dev/dvb/adapter0/frontend0";
+   int fd, r;
+
+   if (argc != 2 || (strcmp(argv[1], "13") && strcmp(argv[1], "18"))) {
+      fprintf (stderr, "usage: %s <13|18>\n", argv[0]);
+      return -1;
+   }
+   if (getenv("FRONTEND"))
+	   fedev = getenv("FRONTEND");
+   printf("setvoltage: using '%s'\n", fedev);
+
+   if ((fd = open (fedev, O_RDWR)) < 0)
+      perror ("open");
+
+   if (strcmp(argv[1], "13") == 0)
+      r = ioctl (fd, FE_SET_VOLTAGE, SEC_VOLTAGE_13);
+   else
+      r = ioctl (fd, FE_SET_VOLTAGE, SEC_VOLTAGE_18);
+   if (r == -1)
+	   perror ("ioctl FE_SET_VOLTAGE");
+
+   close (fd);
+
+   return 0;
+}
+
diff --git a/test/test.c b/test/test.c
new file mode 100644
index 0000000..6c9af51
--- /dev/null
+++ b/test/test.c
@@ -0,0 +1,281 @@
+/* 
+ * test.c - Test program for new API
+ *
+ * Copyright (C) 2000 Ralph  Metzler <ralph at convergence.de>
+ *                  & Marcus Metzler <marcus at convergence.de>
+                      for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+
+#include <linux/dvb/dmx.h>
+#include <linux/dvb/frontend_old.h>
+#include <linux/dvb/sec.h>
+#include <linux/dvb/video.h>
+
+uint8_t reverse[] = {
+0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
+0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
+0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
+0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
+0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
+0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
+0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
+0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
+0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
+0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
+0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
+0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
+0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
+0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
+0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
+0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
+};
+
+inline t2a(uint8_t c)
+{
+  c=reverse[c]&0x7f;
+  if (c<0x20)
+    c=0x20;
+ 
+  return c;
+}
+
+void testpesfilter(void)
+{
+        uint8_t buf[4096], id;
+	int i,j;
+	int len;
+	int fd=open("/dev/ost/demux1", O_RDWR);
+	struct dmx_pes_filter_params pesFilterParams; 
+	
+	pesFilterParams.input = DMX_IN_FRONTEND; 
+	pesFilterParams.output = DMX_OUT_TS_TAP; 
+	pesFilterParams.pes_type = DMX_PES_TELETEXT; 
+	pesFilterParams.flags = DMX_IMMEDIATE_START;
+  
+	pesFilterParams.pid = 0x2c ;
+	if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
+	        printf("Could not set PES filter\n"); 
+		close(fd);
+		return;
+	}
+	ioctl(fd, DMX_STOP, 0);
+/*
+	pesFilterParams.pid = 54;
+	if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
+	        printf("Could not set PES filter\n"); 
+		close(fd);
+		return;
+	}
+	ioctl(fd, DMX_STOP, 0);
+
+	pesFilterParams.pid = 55;
+	if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0) {
+	        printf("Could not set PES filter\n"); 
+		close(fd);
+		return;
+	}
+*/
+	while(1) {
+		len=read(fd, buf, 4096);
+		if (len>0) write(1, buf, len);
+	}
+
+	do { 
+	        read(fd, buf, 4);
+		if (htonl(*(uint32_t *)buf)!=0x00001bd)
+		        continue;
+		read(fd, buf+4, 2);
+		len=(buf[4]<<8)|buf[5];
+	        read(fd, buf+6, len);
+		fprintf(stderr,"read %d bytes PES\n", len);
+		write (1, buf, len+6);
+		
+		id=buf[45];
+		fprintf(stderr,"id=%02x\n", id);
+		
+		for (i=0; i<(len+6-46)/46; i++) {
+		  for (j=6; j<46; j++) {
+		    fprintf(stderr,"%c", t2a(buf[i*46+46+j]));
+		  }
+		    fprintf(stderr,"\n");
+		}
+
+	} while (1);
+
+
+	/*
+	pesFilterParams.pid = 55;
+	pesFilterParams.input = DMX_IN_FRONTEND; 
+	pesFilterParams.output = DMX_OUT_DECODER; 
+	pesFilterParams.pes_type = DMX_PES_TELETEXT; 
+	pesFilterParams.flags = DMX_IMMEDIATE_START;
+  
+	ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams);
+	close(fd);
+	*/
+}
+
+
+senf()
+{
+  int ret;
+  int len;
+  struct secCommand scmd;
+  struct secCmdSequence scmds;
+  struct dmx_pes_filter_params pesFilterParams; 
+  struct dmx_sct_filter_params secFilterParams; 
+  FrontendParameters frp;
+  uint8_t buf[4096];
+
+  int vout=open("qv", O_RDWR|O_CREAT);
+  int aout=open("qa", O_RDWR|O_CREAT);
+
+  int fd_video=open("/dev/ost/video", O_RDWR);
+  int fd_audio=open("/dev/ost/audio", O_RDWR);
+  int fd_tt=open("/dev/ost/demux", O_RDWR);
+  int fd_frontend=open("/dev/ost/frontend", O_RDWR);
+  int fd_sec=open("/dev/ost/sec", O_RDWR);
+  int fd_demux=open("/dev/ost/demux", O_RDWR|O_NONBLOCK);
+  int fd_demux2=open("/dev/ost/demux", O_RDWR|O_NONBLOCK);
+  int fd_section=open("/dev/ost/demux", O_RDWR);
+  int fd_section2=open("/dev/ost/demux", O_RDWR);
+
+  printf("%d\n",fd_section);
+
+  //if (ioctl(fd_sec, SEC_SET_VOLTAGE, SEC_VOLTAGE_13) < 0)  return;
+  //if (ioctl(fd_sec, SEC_SET_TONE, SEC_TONE_ON) < 0)  return;
+#if 0
+  scmd.type=0;
+  scmd.u.diseqc.addr=0x10;
+  scmd.u.diseqc.cmd=0x38;
+  scmd.u.diseqc.numParams=1;
+  scmd.u.diseqc.params[0]=0xf0;
+  
+  scmds.voltage=SEC_VOLTAGE_13;
+  scmds.miniCommand=SEC_MINI_NONE;
+  scmds.continuousTone=SEC_TONE_ON;
+  scmds.numCommands=1;
+  scmds.commands=&scmd;
+  if (ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds) < 0)  return;
+  printf("SEC OK\n");
+
+  frp.Frequency=(12666000-10600000);
+  frp.u.qpsk.SymbolRate=22000000;
+  frp.u.qpsk.FEC_inner=FEC_AUTO;
+
+  if (ioctl(fd_frontend, FE_SET_FRONTEND, &frp) < 0)  return;
+  printf("QPSK OK\n");
+#endif
+
+#if 0
+  ret=ioctl(fd_demux2, DMX_SET_BUFFER_SIZE, 64*1024);
+    if (ret<0)
+      perror("DMX_SET_BUFFER_SIZE\n");
+  printf("Audio filter size OK\n");
+  pesFilterParams.pid = 0x60; 
+  pesFilterParams.input = DMX_IN_FRONTEND; 
+  pesFilterParams.output = DMX_OUT_DECODER; 
+  pesFilterParams.pes_type = DMX_PES_AUDIO; 
+  pesFilterParams.flags = DMX_IMMEDIATE_START;
+  
+  if (ioctl(fd_demux2, DMX_SET_PES_FILTER, &pesFilterParams) < 0)   return(1); 
+  printf("Audio filter OK\n");
+  
+  if (ioctl(fd_demux, DMX_SET_BUFFER_SIZE, 64*1024) < 0)  return(1); 
+  pesFilterParams.pid = 0xa2;
+  pesFilterParams.input = DMX_IN_FRONTEND; 
+  pesFilterParams.output = DMX_OUT_DECODER; 
+  pesFilterParams.pes_type = DMX_PES_VIDEO; 
+  pesFilterParams.flags = DMX_IMMEDIATE_START;
+  if (ioctl(fd_demux, DMX_SET_PES_FILTER, &pesFilterParams) < 0)  return(1); 
+  printf("Video filter OK\n");
+#endif
+  /*
+  pesFilterParams.pid = 56;
+  pesFilterParams.input = DMX_IN_FRONTEND; 
+  pesFilterParams.output = DMX_OUT_DECODER; 
+  pesFilterParams.pes_type = DMX_PES_TELETEXT; 
+  pesFilterParams.flags = DMX_IMMEDIATE_START;
+  if (ioctl(fd_tt, DMX_SET_PES_FILTER, &pesFilterParams) < 0)  return(1); 
+  printf("TT filter OK\n");
+  */
+  //while (1);
+  /* {
+    len=read(fd_demux, buf, 4096);
+    if (len>0) write (vout, buf, len);
+    len=read(fd_demux2, buf, 4096);
+    if (len>0) write (aout, buf, len);
+    }*/
+
+
+  memset(&secFilterParams.filter.filter, 0, DMX_FILTER_SIZE);
+  memset(&secFilterParams.filter.mask, 0, DMX_FILTER_SIZE);
+  secFilterParams.filter.filter[0]=0x00;
+  secFilterParams.filter.mask[0]=0x00;
+  secFilterParams.timeout=5000;
+  secFilterParams.flags=DMX_IMMEDIATE_START;
+
+  /*
+  // this one should timeout after 2 seconds
+  secFilterParams.pid=0xa4;
+  if (ioctl(fd_section, DMX_SET_FILTER, &secFilterParams) < 0)  return;
+  len=read(fd_section, buf, 4096);
+  */
+
+  /*
+  {
+    int32_t snr, str;
+    ioctl(fd_frontend, FE_READ_SNR, &snr);
+    ioctl(fd_frontend, FE_READ_SIGNAL_STRENGTH, &str);
+    
+    printf("snr=%d, str=%d\n", snr, str);
+  }
+  */
+
+  secFilterParams.pid=0x11;
+  //printf("section filter\n");
+  if (ioctl(fd_section, DMX_SET_FILTER, &secFilterParams) < 0)  return;
+  //if (ioctl(fd_section2, DMX_SET_FILTER, &secFilterParams) < 0)  return;
+  //close(fd_section2);
+  //while (1) 
+{
+    len=read(fd_section, buf, 4096);
+    if (len>0) write(1, buf, len);
+    //printf("read section with length %d\n", len);
+    //if (len>0) write(1,buf,len);
+    //len=read(fd_section2, buf, 4096);
+    //if (len>0) write(1,buf,len);
+    //printf("read section with length %d\n", len);
+  }
+  
+}
+
+main()
+{
+	//senf();
+  testpesfilter();
+}
+
diff --git a/test/test_audio.c b/test/test_audio.c
new file mode 100644
index 0000000..0abb734
--- /dev/null
+++ b/test/test_audio.c
@@ -0,0 +1,345 @@
+/* 
+ * test_audio.c - Test program for new API
+ *
+ * Copyright (C) 2000 Ralph  Metzler <ralph at convergence.de>
+ *                  & Marcus Metzler <marcus at convergence.de>
+                      for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <ost/dmx.h>
+#include <ost/frontend_old.h>
+#include <ost/sec.h>
+#include <ost/audio.h>
+#include <sys/poll.h>
+
+int audioStop(int fd)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,AUDIO_STOP,0) < 0)){
+		perror("AUDIO STOP: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+int audioPlay(int fd)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,AUDIO_PLAY) < 0)){
+		perror("AUDIO PLAY: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int audioPause(int fd)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,AUDIO_PAUSE) < 0)){
+		perror("AUDIO PAUSE: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int audioContinue(int fd)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,AUDIO_CONTINUE) < 0)){
+		perror("AUDIO CONTINUE: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+int audioSelectSource(int fd, audio_stream_source_t source)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,AUDIO_SELECT_SOURCE, source) < 0)){
+		perror("AUDIO SELECT SOURCE: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+
+int audioSetMute(int fd, boolean state)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,AUDIO_SET_MUTE, state) < 0)){
+		perror("AUDIO SET MUTE: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+int audioSetAVSync(int fd,boolean state)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,AUDIO_SET_AV_SYNC, state) < 0)){
+		perror("AUDIO SET AV SYNC: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+int audioSetBypassMode(int fd,boolean mode)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,AUDIO_SET_BYPASS_MODE, mode) < 0)){
+		perror("AUDIO SET BYPASS MODE: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int audioChannelSelect(int fd, audio_channel_select_t select)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,AUDIO_CHANNEL_SELECT, select) < 0)){
+		perror("AUDIO CHANNEL SELECT: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+int audioGetStatus(int fd)
+{
+	struct audio_status stat;
+	int ans;
+
+	if ( (ans = ioctl(fd,AUDIO_GET_STATUS, &stat) < 0)){
+		perror("AUDIO GET STATUS: ");
+		return -1;
+	}
+
+	printf("Audio Status:\n");
+	printf("  Sync State          : %s\n",
+	       (stat.AV_sync_state ? "SYNC" : "NO SYNC"));
+	printf("  Mute State          : %s\n",
+	       (stat.mute_state ? "muted" : "not muted"));
+	printf("  Play State          : ");
+	switch ((int)stat.play_state){
+	case AUDIO_STOPPED:
+		printf("STOPPED (%d)\n",stat.play_state);
+		break;
+	case AUDIO_PLAYING:
+		printf("PLAYING (%d)\n",stat.play_state);
+		break;
+	case AUDIO_PAUSED:
+		printf("PAUSED (%d)\n",stat.play_state);
+		break;
+	default:
+		printf("unknown (%d)\n",stat.play_state);
+		break;
+	}
+	
+	printf("  Stream Source       : ");
+	switch((int)stat.stream_source){
+	case AUDIO_SOURCE_DEMUX:
+		printf("DEMUX (%d)\n",stat.stream_source);
+		break;
+	case AUDIO_SOURCE_MEMORY:
+		printf("MEMORY (%d)\n",stat.stream_source);
+		break;
+	default:
+		printf("unknown (%d)\n",stat.stream_source);
+		break;
+	}
+
+	printf("  Channel Select      : ");
+	switch((int)stat.channel_select){
+	case AUDIO_STEREO:
+		printf("Stereo (%d)\n",stat.channel_select);
+		break;
+	case AUDIO_MONO_LEFT:
+		printf("Mono left(%d)\n",stat.channel_select);
+		break;
+	case AUDIO_MONO_RIGHT:
+		printf("Mono right (%d)\n",stat.channel_select);
+		break;
+	default:
+		printf("unknown (%d)\n",stat.channel_select);
+		break;
+	}
+	printf("  Bypass Mode         : %s\n",
+	       (stat.bypass_mode ? "ON" : "OFF"));
+
+	return 0;
+
+}
+
+#define BUFFY 100000
+#define NFD   2
+play_file_audio(int filefd, int fd)
+{
+	char buf[BUFFY];
+	int count;
+	int written;
+	int ch;
+	struct pollfd pfd[NFD];
+	int stopped = 0;
+	boolean mute = false;
+	boolean sync = false;
+	
+	pfd[0].fd = STDIN_FILENO;
+	pfd[0].events = POLLIN;
+
+	pfd[1].fd = fd;
+	pfd[1].events = POLLOUT;
+
+
+	while ( (count = read(filefd,buf,BUFFY)) >= 0  ){
+		written = 0;
+		while(written < count){
+			if (poll(pfd,NFD,1)){
+				if (pfd[1].revents & POLLOUT){
+					written += write(fd,buf+written,
+							count-written);
+				}
+				if (pfd[0].revents & POLLIN){
+					int c = getchar();
+					switch(c){
+					case 'z':
+						audioPause(fd);
+						printf("playback paused\n");
+						stopped = 1;
+						break;
+
+					case 's':
+						audioStop(fd);
+						printf("playback stopped\n");
+						stopped = 1;
+						break;
+						
+					case 'c':
+						audioContinue(fd);
+						printf("playback continued\n");
+						stopped = 0;
+						break;
+
+					case 'p':
+						audioPlay(fd);
+						printf("playback started\n");
+						stopped = 0;
+						break;
+
+					case 'm':
+						if (mute==false)mute=true;
+						else mute=false;
+						audioSetMute(fd,mute);
+						printf("mute %d\n",mute);
+						break;
+
+					case 'a':
+						if (sync==false)sync=true;
+						else sync=false;
+						audioSetAVSync(fd,sync);
+						printf("AV sync %d\n",sync);
+						stopped = 0;
+						break;
+
+					case 'q':
+						audioContinue(fd);
+						exit(0);
+						break;
+					}
+				}
+				
+			}
+		}
+	}
+
+}
+
+
+main(int argc, char **argv)
+{
+	int fd;
+	int filefd;
+	boolean mute = false;
+	boolean sync = false;
+
+	if (argc < 2) return -1;
+
+	if ( (filefd = open(argv[1],O_RDONLY)) < 0){
+		perror("File open:");
+		return -1;
+	}
+	    
+	if((fd = open("/dev/ost/audio",O_RDWR|O_NONBLOCK)) < 0){
+		perror("AUDIO DEVICE: ");
+		return -1;
+	}
+
+
+
+	audioSetMute(fd,mute);
+	//	audioSetBypassMode(fd,false); // not implemented
+	//audioContinue(fd);
+	audioSelectSource(fd,AUDIO_SOURCE_MEMORY);
+	audioPlay(fd);
+	//sleep(4);
+	//audioPause(fd);
+	//sleep(3);
+	//audioContinue(fd);
+	//sleep(3);
+	//audioStop(fd);
+	//audioChannelSelect(fd,AUDIO_STEREO);
+	//audioSetAVSync(fd,sync);
+	audioGetStatus(fd);
+	
+	play_file_audio(filefd,fd);
+
+	close(fd);
+	return 0;
+
+
+}
+
diff --git a/test/test_av.c b/test/test_av.c
new file mode 100644
index 0000000..5d77000
--- /dev/null
+++ b/test/test_av.c
@@ -0,0 +1,574 @@
+/* 
+ * test_av.c - Test for audio and video MPEG decoder API.
+ *
+ * Copyright (C) 2000 - 2002 convergence GmbH
+ * Ralph Metzler <rjkm at convergence.de>
+ * Marcus Metzler <mocm at convergence.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/dvb/audio.h>
+#include <linux/dvb/video.h>
+
+int audioStop(int fd, char *arg)
+{
+	if (arg)
+		return -1;
+	if (ioctl(fd, AUDIO_STOP) == -1)
+		perror("AUDIO_STOP");
+	return 0;
+}
+
+int audioPlay(int fd, char *arg)
+{
+	if (arg)
+		return -1;
+	if (ioctl(fd, AUDIO_PLAY)  == -1)
+		perror("AUDIO_PLAY");
+	return 0;
+}
+
+int audioPause(int fd, char *arg)
+{
+	if (arg)
+		return -1;
+	if (ioctl(fd, AUDIO_PAUSE) == -1)
+		perror("AUDIO_PAUSE");
+	return 0;
+}
+
+
+int audioContinue(int fd, char *arg)
+{
+	if (arg)
+		return -1;
+	if (ioctl(fd, AUDIO_CONTINUE) == -1)
+		perror("AUDIO_CONTINUE");
+	return 0;
+}
+
+int audioSelectSource(int fd, char *arg)
+{
+	int source;
+	if (!arg)
+		return -1;
+	source = atoi(arg);
+	if (ioctl(fd, AUDIO_SELECT_SOURCE, source) == -1)
+		perror("AUDIO_SELECT_SOURCE");
+	return 0;
+}
+
+int audioSetMute(int fd, char *arg)
+{
+	int mute;
+	if (!arg)
+		return -1;
+	mute = atoi(arg);
+	if (ioctl(fd, AUDIO_SET_MUTE, mute) == -1)
+		perror("AUDIO_SET_MUTE");
+	return 0;
+}
+
+int audioSetAVSync(int fd, char *arg)
+{
+	int sync;
+	if (!arg)
+		return -1;
+	sync = atoi(arg);
+	if (ioctl(fd, AUDIO_SET_AV_SYNC, sync) == -1)
+		perror("AUDIO_SET_AV_SYNC");
+	return 0;
+}
+
+int audioSetBypassMode(int fd, char *arg)
+{
+	int byp;
+	if (!arg)
+		return -1;
+	byp = atoi(arg);
+	if (ioctl(fd, AUDIO_SET_BYPASS_MODE, byp) == -1)
+		perror("AUDIO_SET_BYPASS_MODE");
+	return 0;
+}
+
+int audioChannelSelect(int fd, char *arg)
+{
+	int chan;
+	if (!arg)
+		return -1;
+	chan = atoi(arg);
+	if (ioctl(fd, AUDIO_CHANNEL_SELECT, chan) == -1)
+		perror("AUDIO_CHANNEL_SELECT");
+	return 0;
+}
+
+int audioGetStatus(int fd, char *arg)
+{
+	struct audio_status stat;
+
+	if (arg)
+		return -1;
+	if (ioctl(fd, AUDIO_GET_STATUS, &stat) == -1) {
+		perror("AUDIO_GET_STATUS");
+		return 0;
+	}
+
+	printf("Audio Status:\n");
+	printf("  Sync State          : %s\n",
+	       (stat.AV_sync_state ? "SYNC" : "NO SYNC"));
+	printf("  Mute State          : %s\n",
+	       (stat.mute_state ? "muted" : "not muted"));
+	printf("  Play State          : ");
+	switch ((int)stat.play_state){
+	case AUDIO_STOPPED:
+		printf("STOPPED (%d)\n",stat.play_state);
+		break;
+	case AUDIO_PLAYING:
+		printf("PLAYING (%d)\n",stat.play_state);
+		break;
+	case AUDIO_PAUSED:
+		printf("PAUSED (%d)\n",stat.play_state);
+		break;
+	default:
+		printf("unknown (%d)\n",stat.play_state);
+		break;
+	}
+
+	printf("  Stream Source       : ");
+	switch((int)stat.stream_source){
+	case AUDIO_SOURCE_DEMUX:
+		printf("DEMUX (%d)\n",stat.stream_source);
+		break;
+	case AUDIO_SOURCE_MEMORY:
+		printf("MEMORY (%d)\n",stat.stream_source);
+		break;
+	default:
+		printf("unknown (%d)\n",stat.stream_source);
+		break;
+	}
+
+	printf("  Channel Select      : ");
+	switch((int)stat.channel_select){
+	case AUDIO_STEREO:
+		printf("Stereo (%d)\n",stat.channel_select);
+		break;
+	case AUDIO_MONO_LEFT:
+		printf("Mono left(%d)\n",stat.channel_select);
+		break;
+	case AUDIO_MONO_RIGHT:
+		printf("Mono right (%d)\n",stat.channel_select);
+		break;
+	default:
+		printf("unknown (%d)\n",stat.channel_select);
+		break;
+	}
+	printf("  Bypass Mode         : %s\n",
+	       (stat.bypass_mode ? "ON" : "OFF"));
+
+	return 0;
+
+}
+
+int videoStop(int fd, char *arg)
+{
+	if (arg)
+		return -1;
+	if (ioctl(fd, VIDEO_STOP) == -1)
+		perror("VIDEO_STOP");
+	return 0;
+}
+
+int videoPlay(int fd, char *arg)
+{
+	if (arg)
+		return -1;
+	if (ioctl(fd, VIDEO_PLAY) == -1)
+		perror("VIDEO_PLAY");
+	return 0;
+}
+
+
+int videoFreeze(int fd, char *arg)
+{
+	if (arg)
+		return -1;
+	if (ioctl(fd, VIDEO_FREEZE) == -1)
+		perror("VIDEO_FREEZE");
+	return 0;
+}
+
+
+int videoContinue(int fd, char *arg)
+{
+	if (arg)
+		return -1;
+	if (ioctl(fd, VIDEO_CONTINUE) == -1)
+		perror("VIDEO_CONTINUE");
+	return 0;
+}
+
+int videoFormat(int fd, char *arg)
+{
+	int format;
+	if (!arg)
+		return -1;
+	format = atoi(arg);
+	if (ioctl(fd, VIDEO_SET_FORMAT, format) == -1)
+		perror("VIDEO_SET_FORMAT");
+	return 0;
+}
+
+int videoDisplayFormat(int fd, char *arg)
+{
+	int format;
+	if (!arg)
+		return -1;
+	format = atoi(arg);
+	if (ioctl(fd, VIDEO_SET_DISPLAY_FORMAT, format) == -1)
+		perror("VIDEO_SET_DISPLAY_FORMAT");
+	return 0;
+}
+
+int videoSelectSource(int fd, char *arg)
+{
+	int source;
+	if (!arg)
+		return -1;
+	source = atoi(arg);
+	if (ioctl(fd, VIDEO_SELECT_SOURCE, source) == -1)
+		perror("VIDEO_SELECT_SOURCE");
+	return 0;
+}
+
+
+
+int videoSetBlank(int fd, char *arg)
+{
+	int blank;
+	if (!arg)
+		return -1;
+	blank = atoi(arg);
+	if (ioctl(fd, VIDEO_SET_BLANK, blank) == -1)
+		perror("VIDEO_SET_BLANK");
+	return 0;
+}
+
+int videoFastForward(int fd, char *arg)
+{
+	int frames;
+	if (!arg)
+		return -1;
+	frames = atoi(arg);
+	if (ioctl(fd, VIDEO_FAST_FORWARD, frames) == -1)
+		perror("VIDEO_FAST_FORWARD");
+	return 0;
+}
+
+int videoSlowMotion(int fd, char *arg)
+{
+	int frames;
+	if (!arg)
+		return -1;
+	frames = atoi(arg);
+	if (ioctl(fd, VIDEO_SLOWMOTION, frames) == -1)
+		perror("VIDEO_SLOWMOTION");
+	return 0;
+}
+
+int videoGetStatus(int fd, char *arg)
+{
+	struct video_status stat;
+
+	if (arg)
+		return -1;
+	if (ioctl(fd, VIDEO_GET_STATUS, &stat) == -1){
+		perror("VIDEO_GET_STATUS");
+		return 0;
+	}
+
+	printf("Video Status:\n");
+	printf("  Blank State          : %s\n",
+	       (stat.video_blank ? "BLANK" : "STILL"));
+	printf("  Play State           : ");
+	switch ((int)stat.play_state){
+	case VIDEO_STOPPED:
+		printf("STOPPED (%d)\n",stat.play_state);
+		break;
+	case VIDEO_PLAYING:
+		printf("PLAYING (%d)\n",stat.play_state);
+		break;
+	case VIDEO_FREEZED:
+		printf("FREEZED (%d)\n",stat.play_state);
+		break;
+	default:
+		printf("unknown (%d)\n",stat.play_state);
+		break;
+	}
+
+	printf("  Stream Source        : ");
+	switch((int)stat.stream_source){
+	case VIDEO_SOURCE_DEMUX:
+		printf("DEMUX (%d)\n",stat.stream_source);
+		break;
+	case VIDEO_SOURCE_MEMORY:
+		printf("MEMORY (%d)\n",stat.stream_source);
+		break;
+	default:
+		printf("unknown (%d)\n",stat.stream_source);
+		break;
+	}
+
+	printf("  Format (Aspect Ratio): ");
+	switch((int)stat.video_format){
+	case VIDEO_FORMAT_4_3:
+		printf("4:3 (%d)\n",stat.video_format);
+		break;
+	case VIDEO_FORMAT_16_9:
+		printf("16:9 (%d)\n",stat.video_format);
+		break;
+	case VIDEO_FORMAT_221_1:
+		printf("2.21:1 (%d)\n",stat.video_format);
+		break;
+	default:
+		printf("unknown (%d)\n",stat.video_format);
+		break;
+	}
+
+	printf("  Display Format       : ");
+	switch((int)stat.display_format){
+	case VIDEO_PAN_SCAN:
+		printf("Pan&Scan (%d)\n",stat.display_format);
+		break;
+	case VIDEO_LETTER_BOX:
+		printf("Letterbox (%d)\n",stat.display_format);
+		break;
+	case VIDEO_CENTER_CUT_OUT:
+		printf("Center cutout (%d)\n",stat.display_format);
+		break;
+	default:
+		printf("unknown (%d)\n",stat.display_format);
+		break;
+	}
+	return 0;
+}
+
+int videoGetSize(int fd, char *arg)
+{
+	video_size_t size;
+
+	if (arg)
+		return -1;
+	if (ioctl(fd, VIDEO_GET_SIZE, &size) == -1){
+		perror("VIDEO_GET_SIZE");
+		return 0;
+	}
+
+	printf("Video Size: %ux%u ", size.w, size.h);
+	switch (size.aspect_ratio) {
+	case VIDEO_FORMAT_4_3:
+		printf("4:3 (%d)\n", size.aspect_ratio);
+		break;
+	case VIDEO_FORMAT_16_9:
+		printf("16:9 (%d)\n", size.aspect_ratio);
+		break;
+	case VIDEO_FORMAT_221_1:
+		printf("2.21:1 (%d)\n", size.aspect_ratio);
+		break;
+	default:
+		printf("unknown aspect ratio (%d)\n", size.aspect_ratio);
+		break;
+	}
+	return 0;
+}
+
+int videoStillPicture(int fd, char *arg)
+{
+	int sifd;
+	struct stat st;
+	struct video_still_picture sp;
+
+	if (!arg)
+		return -1;
+	sifd = open(arg, O_RDONLY);
+	if (sifd == -1) {
+		perror("open stillimage file");
+		printf("(%s)\n", arg);
+		return 0;
+	}
+	fstat(sifd, &st);
+
+	sp.iFrame = (char *) malloc(st.st_size);
+	sp.size = st.st_size;
+	printf("I-frame size: %d\n", sp.size);
+
+	if(!sp.iFrame) {
+		printf("No memory for I-Frame\n");
+		return 0;
+	}
+
+	printf("read: %d bytes\n",read(sifd,sp.iFrame,sp.size));
+	if (ioctl(fd, VIDEO_STILLPICTURE, &sp) == -1)
+		perror("VIDEO_STILLPICTURE");
+	return 0;
+}
+
+typedef int (* cmd_func_t)(int fd, char *args);
+typedef struct {
+	char *cmd;
+	char *param_help;
+	cmd_func_t cmd_func;
+} cmd_t;
+cmd_t audio_cmds[] =
+{
+	{ "stop", "", audioStop },
+	{ "play", "", audioPlay },
+	{ "pause", "", audioPause },
+	{ "continue", "", audioContinue },
+	{ "source", "n: 0 demux, 1 memory", audioSelectSource },
+	{ "mute", "n: 0 unmute, 1 mute", audioSetMute },
+	{ "avsync", "n: 0 unsync, 1 sync", audioSetAVSync },
+	{ "bypass", "n: 0 normal, 1 bypass", audioSetBypassMode },
+	{ "channel", "n: 0 stereo, 1 left, 2 right", audioChannelSelect },
+	{ "status", "", audioGetStatus },
+	{ NULL, NULL, NULL }
+};
+cmd_t video_cmds[] =
+{
+	{ "stop", "", videoStop },
+	{ "play", "", videoPlay },
+	{ "freeze", "", videoFreeze },
+	{ "continue", "", videoContinue },
+	{ "source", "n: 0 demux, 1 memory", videoSelectSource },
+	{ "blank", "n: 0 normal, 1 blank", videoSetBlank },
+	{ "ff", "n: number of frames", videoFastForward },
+	{ "slow", "n: number of frames", videoSlowMotion },
+	{ "status", "", videoGetStatus },
+	{ "size", "", videoGetSize },
+	{ "stillpic", "filename", videoStillPicture},
+	{ "format", "n: 0 4:3, 1 16:9", videoFormat},
+	{ "dispformat", "n: 0 pan&scan, 1 letter box, 2 center cut out", videoDisplayFormat},
+	{ NULL, NULL, NULL }
+};
+int usage(void)
+{
+	int i;
+	printf ("commands begin with a for audio and v for video:\n\n"
+	        "q : quit\n");
+	for (i=0; audio_cmds[i].cmd; i++)
+		printf("a %s %s\n", audio_cmds[i].cmd, audio_cmds[i].param_help);
+	for (i=0; video_cmds[i].cmd; i++)
+		printf("v %s %s\n", video_cmds[i].cmd, video_cmds[i].param_help);
+	printf("\n");
+	return 0;
+}
+
+int syntax_error(void)
+{
+	fprintf(stderr, "syntax error\n");
+	return 0;
+}
+
+int process_kbd_input(int vfd, int afd)
+{
+	char buf[256], *cmd;
+	int i;
+
+	if (!fgets(buf, sizeof(buf), stdin))
+		return -1;
+	cmd = strtok(buf, " \n\t");
+	if (!cmd) {
+		printf("enter command or h + enter for help\n");
+		return 0;
+	}
+	if (cmd[0] == 'q' || !strcmp(cmd, "quit"))
+		return -1;
+	if (cmd[0] == 'h' || !strcmp(cmd, "help"))
+		return usage();
+	if (cmd[0] == 'a' || !strcmp(cmd, "audio")) {
+		cmd = strtok(NULL, " \n\t");
+		if (!cmd)
+			return syntax_error();
+		for (i=0; audio_cmds[i].cmd; i++) {
+			if (!strcmp(cmd, audio_cmds[i].cmd)) {
+				cmd = strtok(NULL, " \n\t");
+				printf("calling '%s', arg '%s'\n", audio_cmds[i].cmd, cmd);
+				if (audio_cmds[i].cmd_func(afd, cmd))
+					syntax_error();
+				return 0;
+			}
+		}
+		return syntax_error();
+	} else if (buf[0] == 'v') {
+		cmd = strtok(NULL, " \n\t");
+		if (!cmd)
+			return usage();
+		for (i=0; video_cmds[i].cmd; i++) {
+			if (!strcmp(cmd, video_cmds[i].cmd)) {
+				cmd = strtok(NULL, " \n\t");
+				printf("calling '%s', arg '%s'\n", video_cmds[i].cmd, cmd);
+				if (video_cmds[i].cmd_func(vfd, cmd))
+					syntax_error();
+				return 0;
+			}
+		}
+		return syntax_error();
+	} else
+		return syntax_error();
+	return 0;
+}
+
+int main(void)
+{
+	int vfd, afd;
+	char *videodev = "/dev/dvb/adapter0/video0";
+	char *audiodev = "/dev/dvb/adapter0/audio0";
+
+	if (getenv("VIDEO"))
+		videodev = getenv("VIDEO");
+	if (getenv("AUDIO"))
+		videodev = getenv("AUDIO");
+
+	printf("using video device '%s'\n", videodev);
+	printf("using audio device '%s'\n", audiodev);
+	printf("enter command or h + enter for help\n");
+
+	if((vfd = open(videodev, O_RDWR | O_NONBLOCK)) < 0) {
+		perror("open video device");
+		return 1;
+	}
+	if((afd = open(audiodev, O_RDWR | O_NONBLOCK)) < 0) {
+		perror("open audio device");
+		return 1;
+	}
+
+	while (process_kbd_input(vfd, afd) == 0)
+		;
+
+	close(vfd);
+	close(afd);
+	return 0;
+}
+
diff --git a/test/test_av_play.c b/test/test_av_play.c
new file mode 100644
index 0000000..293d6d8
--- /dev/null
+++ b/test/test_av_play.c
@@ -0,0 +1,310 @@
+/*
+ * test_av_play.c - Test playing an MPEG A+V PES (e.g. VDR recordings) from a file.
+ *
+ * Copyright (C) 2000 Ralph  Metzler <ralph at convergence.de>
+ *                  & Marcus Metzler <marcus at convergence.de>
+ *                    for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/dvb/dmx.h>
+#include <linux/dvb/video.h>
+#include <linux/dvb/audio.h>
+#include <sys/poll.h>
+
+static int audioPlay(int fd)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,AUDIO_PLAY) < 0)){
+		perror("AUDIO PLAY: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int audioSelectSource(int fd, audio_stream_source_t source)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,AUDIO_SELECT_SOURCE, source) < 0)){
+		perror("AUDIO SELECT SOURCE: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+
+static int audioSetMute(int fd, int state)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,AUDIO_SET_MUTE, state) < 0)){
+		perror("AUDIO SET MUTE: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int audioSetAVSync(int fd, int state)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,AUDIO_SET_AV_SYNC, state) < 0)){
+		perror("AUDIO SET AV SYNC: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int videoStop(int fd)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,VIDEO_STOP,0) < 0)){
+		perror("VIDEO STOP: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int videoPlay(int fd)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,VIDEO_PLAY) < 0)){
+		perror("VIDEO PLAY: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int videoFreeze(int fd)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,VIDEO_FREEZE) < 0)){
+		perror("VIDEO FREEZE: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int videoContinue(int fd)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,VIDEO_CONTINUE) < 0)){
+		perror("VIDEO CONTINUE: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int videoSelectSource(int fd, video_stream_source_t source)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,VIDEO_SELECT_SOURCE, source) < 0)){
+		perror("VIDEO SELECT SOURCE: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int videoFastForward(int fd,int nframes)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,VIDEO_FAST_FORWARD, nframes) < 0)){
+		perror("VIDEO FAST FORWARD: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+static int videoSlowMotion(int fd,int nframes)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,VIDEO_SLOWMOTION, nframes) < 0)){
+		perror("VIDEO SLOWMOTION: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+#define BUFFY 32768
+#define NFD   2
+static void play_file_av(int filefd, int vfd, int afd)
+{
+	char buf[BUFFY];
+	int count;
+	int written;
+	struct pollfd pfd[NFD];
+	int stopped = 0;
+
+	pfd[0].fd = STDIN_FILENO;
+	pfd[0].events = POLLIN;
+
+	pfd[1].fd = vfd;
+	pfd[1].events = POLLOUT;
+
+	pfd[2].fd = afd;
+	pfd[2].events = POLLOUT;
+
+	videoSelectSource(vfd,VIDEO_SOURCE_MEMORY);
+	audioSelectSource(afd,AUDIO_SOURCE_MEMORY);
+
+	// FIXME: only seems to work if starting audio first!
+	audioPlay(afd);
+	videoPlay(vfd);
+
+	count = read(filefd,buf,BUFFY);
+	write(vfd,buf,count);
+
+	while ( (count = read(filefd,buf,BUFFY)) >= 0  ){
+		written = 0;
+		while(written < count){
+			if (poll(pfd,NFD,1)){
+				if (pfd[1].revents & POLLOUT){
+					written += write(vfd,buf+written,
+							count-written);
+				}
+				if (pfd[0].revents & POLLIN){
+					int c = getchar();
+					switch(c){
+					case 'z':
+						videoFreeze(vfd);
+						printf("playback frozen\n");
+						stopped = 1;
+						break;
+
+					case 's':
+						videoStop(vfd);
+						printf("playback stopped\n");
+						stopped = 1;
+						break;
+
+					case 'c':
+						videoContinue(vfd);
+						printf("playback continued\n");
+						stopped = 0;
+						break;
+
+					case 'p':
+						videoPlay(vfd);
+						audioPlay(afd);
+					        audioSetAVSync(afd, 1);
+						audioSetMute(afd, 0);
+						printf("playback started\n");
+						stopped = 0;
+						break;
+
+					case 'f':
+					        audioSetAVSync(afd, 0);
+						audioSetMute(afd, 1);
+						videoFastForward(vfd,0);
+						printf("fastforward\n");
+						stopped = 0;
+						break;
+
+					case 'm':
+					        audioSetAVSync(afd, 0);
+						audioSetMute(afd, 1);
+						videoSlowMotion(vfd,2);
+						printf("slowmotion\n");
+						stopped = 0;
+						break;
+
+					case 'q':
+						videoContinue(vfd);
+						exit(0);
+						break;
+					}
+				}
+			}
+		}
+	}
+}
+
+int main(int argc, char **argv)
+{
+	int vfd, afd;
+	int filefd;
+	char *videodev = "/dev/dvb/adapter0/video0";
+	char *audiodev = "/dev/dvb/adapter0/audio0";
+
+	if (argc < 2) {
+		fprintf(stderr, "usage: test_av_play mpeg_A+V_PES_file\n");
+		return 1;
+	}
+
+	if (getenv("VIDEO"))
+		videodev = getenv("VIDEO");
+	if (getenv("AUDIO"))
+		videodev = getenv("AUDIO");
+
+	printf("using video device '%s'\n", videodev);
+	printf("using audio device '%s'\n", audiodev);
+
+	if ( (filefd = open(argv[1],O_RDONLY)) < 0){
+		perror("File open:");
+		return -1;
+	}
+	if((vfd = open(videodev,O_RDWR|O_NONBLOCK)) < 0){
+		perror("VIDEO DEVICE: ");
+		return -1;
+	}
+	if((afd = open(audiodev,O_RDWR|O_NONBLOCK)) < 0){
+		perror("AUDIO DEVICE: ");
+		return -1;
+	}
+	play_file_av(filefd, vfd, afd);
+	close(vfd);
+	close(afd);
+	close(filefd);
+	return 0;
+
+
+}
+
diff --git a/test/test_dvr.c b/test/test_dvr.c
new file mode 100644
index 0000000..4cee62f
--- /dev/null
+++ b/test/test_dvr.c
@@ -0,0 +1,164 @@
+/* test_dvr.c - Test recording a TS from the dvr device.
+ * usage: test_dvr PID [more PIDs...]
+ *
+ * Copyright (C) 2003 convergence GmbH
+ * Johannes Stezenbach <js at convergence.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+//hm, I haven't tested writing large files yet... maybe it works
+#define _LARGEFILE64_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <linux/dvb/dmx.h>
+
+static unsigned long BUF_SIZE = 64 * 1024;
+static unsigned long long total_bytes;
+
+static void usage(void)
+{
+	fprintf(stderr, "usage: test_dvb file PID [more PIDs...]\n"
+			"       record a partial TS stream consisting of TS packets\n"
+			"       with the selected PIDs to the given file.\n"
+			"       Use PID 0x2000 to record the full TS stream (if\n"
+			"       the hardware supports it).\n"
+			"       The demux and dvr devices used can be changed by setting\n"
+			"       the environment variables DEMUX and DVR.\n"
+			"       You can override the input buffer size by setting BUF_SIZE to\n"
+			"       the number of bytes wanted.\n"
+			"       Note: There is no output buffering, so writing to stdout is\n"
+			"       not really supported, but you can try something like:\n"
+			"       BUF_SIZE=188 ./test_dvr /dev/stdout 0 2>/dev/null | xxd\n"
+			"       ./test_dvr /dev/stdout 0x100 0x110 2>/dev/null| xine stdin://mpeg2\n"
+			"\n");
+	exit(1);
+}
+
+
+static void process_data(int dvrfd, int tsfd)
+{
+	uint8_t buf[BUF_SIZE];
+	int bytes, b2;
+
+	bytes = read(dvrfd, buf, sizeof(buf));
+	if (bytes < 0) {
+		perror("read");
+		if (errno == EOVERFLOW)
+			return;
+		fprintf(stderr, "exiting due to read() error\n");
+		exit(1);
+	}
+	total_bytes += bytes;
+	b2 = write(tsfd, buf, bytes);
+	if (b2 == -1) {
+		perror("write");
+		exit(1);
+	} else if (b2 < bytes)
+		fprintf(stderr, "warning: read %d, but wrote only %d bytes\n", bytes, b2);
+	else
+		fprintf(stderr, "got %d bytes (%llu total)\n", bytes, total_bytes);
+}
+
+static int add_filter(unsigned int pid, const unsigned char* dmxdev)
+{
+	int fd;
+	struct dmx_pes_filter_params f;
+
+	fd = open(dmxdev, O_RDONLY);
+	if (fd == -1) {
+		perror("cannot open demux device");
+		return 1;
+	}
+
+	memset(&f, 0, sizeof(f));
+	f.pid = (uint16_t) pid;
+	f.input = DMX_IN_FRONTEND;
+	f.output = DMX_OUT_TS_TAP;
+	f.pes_type = DMX_PES_OTHER;
+	f.flags   = DMX_IMMEDIATE_START;
+
+	if (ioctl(fd, DMX_SET_PES_FILTER, &f) == -1) {
+		perror("DMX_SET_PES_FILTER");
+		return 1;
+	}
+	fprintf(stderr, "set filter for PID 0x%04x on fd %d\n", pid, fd);
+
+	//FIXME: don't leak the fd
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int dvrfd, tsfd;
+	unsigned int pid;
+	char *dmxdev = "/dev/dvb/adapter0/demux0";
+	char *dvrdev = "/dev/dvb/adapter0/dvr0";
+	int i;
+	char *chkp;
+
+	if (argc < 3)
+		usage();
+
+	if (getenv("DEMUX"))
+		dmxdev = getenv("DEMUX");
+	if (getenv("DVR"))
+		dvrdev = getenv("DVR");
+
+	fprintf(stderr, "using '%s' and '%s'\n"
+		"writing to '%s'\n", dmxdev, dvrdev, argv[1]);
+	tsfd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC | O_LARGEFILE, 0664);
+	if (tsfd == -1) {
+		perror("cannot write output file");
+		return 1;
+	}
+
+	dvrfd = open(dvrdev, O_RDONLY);
+	if (dvrfd == -1) {
+		perror("cannot open dvr device");
+		return 1;
+	}
+
+	if (getenv("BUF_SIZE") && ((BUF_SIZE = strtoul(getenv("BUF_SIZE"), NULL, 0)) > 0))
+		fprintf(stderr, "BUF_SIZE = %lu\n", BUF_SIZE);
+
+	for (i = 2; i < argc; i++) {
+		pid = strtoul(argv[i], &chkp, 0);
+		if (pid > 0x2000 || chkp == argv[i])
+			usage();
+		fprintf(stderr, "adding filter for PID 0x%04x\n", pid);
+		//FIXME: stop & close filters later...
+		if (add_filter(pid, dmxdev) != 0)
+			return 1;
+	}
+
+	for (;;) {
+		process_data(dvrfd, tsfd);
+	}
+
+	close(dvrfd);
+	return 0;
+}
+
diff --git a/test/test_dvr_play.c b/test/test_dvr_play.c
new file mode 100644
index 0000000..af963d9
--- /dev/null
+++ b/test/test_dvr_play.c
@@ -0,0 +1,144 @@
+/*
+ * test_dvr_play.c - Play TS file via dvr device.
+ *
+ * Copyright (C) 2000 Ralph  Metzler <ralph at convergence.de>
+ *                  & Marcus Metzler <marcus at convergence.de>
+ *                    for convergence integrated media GmbH
+ * Copyright (C) 2003 Convergence GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/poll.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+
+#include <linux/dvb/dmx.h>
+
+
+#define BUFSIZE (512*188)
+
+void play_file_dvr(int filefd, int dvrfd)
+{
+	char buf[BUFSIZE];
+	int count, written, bytes, total = 0;
+
+	while ((count = read(filefd, buf, BUFSIZE)) > 0) {
+		total += count;
+		fprintf(stderr, "read  %d (%d total)\n", count, total);
+		written = 0;
+		while (written < count) {
+			bytes = write(dvrfd, buf + written, count - written);
+			fprintf(stderr, "write %d\n", bytes);
+			if (bytes < 0) {
+				perror("write dvr");
+				return;
+			}
+			else if (bytes == 0) {
+				fprintf(stderr, "write dvr: 0 bytes !");
+				return;
+			}
+			written += bytes;
+		}
+	}
+}
+
+void set_pid(int fd, int pid, int type)
+{
+	struct dmx_pes_filter_params pesFilterParams;
+
+	fprintf(stderr, "set PID 0x%04x (%d)\n", pid, type);
+	if (ioctl(fd, DMX_STOP) < 0)
+		perror("DMX STOP:");
+
+	if (ioctl(fd, DMX_SET_BUFFER_SIZE, 64*1024) < 0)
+		perror("DMX SET BUFFER:");
+
+	pesFilterParams.pid = pid;
+	pesFilterParams.input = DMX_IN_DVR;
+	pesFilterParams.output = DMX_OUT_DECODER;
+	pesFilterParams.pes_type = type;
+	pesFilterParams.flags = DMX_IMMEDIATE_START;
+	if (ioctl(fd, DMX_SET_PES_FILTER, &pesFilterParams) < 0)
+		perror("DMX SET FILTER");
+}
+
+int main(int argc, char **argv)
+{
+	char *dmxdev = "/dev/dvb/adapter0/demux0";
+	char *dvrdev = "/dev/dvb/adapter0/dvr0";
+	int vpid, apid;
+	int filefd, dvrfd, vfd, afd;
+
+	if (argc < 4) {
+		fprintf(stderr, "usage: test_dvr_play TS-file video-PID audio-PID\n");
+		return 1;
+	}
+	vpid = strtoul(argv[2], NULL, 0);
+	apid = strtoul(argv[3], NULL, 0);
+
+	filefd = open(argv[1], O_RDONLY);
+	if (filefd == -1) {
+		fprintf(stderr, "Failed to open '%s': %d %m\n", argv[1], errno);
+		return 1;
+	}
+
+	fprintf(stderr, "Playing '%s', video PID 0x%04x, audio PID 0x%04x\n",
+			argv[1], vpid, apid);
+
+	if (getenv("DEMUX"))
+		dmxdev = getenv("DEMUX");
+	if (getenv("DVR"))
+		dvrdev = getenv("DVR");
+
+	if ((dvrfd = open(dvrdev, O_WRONLY)) == -1) {
+		fprintf(stderr, "Failed to open '%s': %d %m\n", dvrdev, errno);
+		return 1;
+	}
+
+	if ((vfd = open(dmxdev, O_WRONLY)) == -1) {
+		fprintf(stderr, "Failed to open video '%s': %d %m\n", dmxdev, errno);
+		return 1;
+	}
+	if ((afd = open(dmxdev, O_WRONLY)) == -1) {
+		fprintf(stderr, "Failed to open audio '%s': %d %m\n", dmxdev, errno);
+		return 1;
+	}
+
+	/* playback timing is controlled via A/V PTS, so we cannot start
+	 * writing to the DVR device before the PIDs are set...
+	 */
+	set_pid(afd, apid, DMX_PES_AUDIO);
+	set_pid(vfd, vpid, DMX_PES_VIDEO);
+
+	play_file_dvr(filefd, dvrfd);
+
+	close(dvrfd);
+	close(afd);
+	close(vfd);
+	close(filefd);
+	return 0;
+}
+
diff --git a/test/test_front.c b/test/test_front.c
new file mode 100644
index 0000000..1d08fc6
--- /dev/null
+++ b/test/test_front.c
@@ -0,0 +1,328 @@
+/* 
+ * test_front.c - Test program for new API
+ *
+ * Copyright (C) 2000 Ralph  Metzler <ralph at convergence.de>
+ *                  & Marcus Metzler <marcus at convergence.de>
+                      for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <ost/dmx.h>
+#include <ost/frontend_old.h>
+#include <ost/sec.h>
+#include <ost/audio.h>
+#include <sys/poll.h>
+
+int OSTSelftest(int fd)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,OST_SELFTEST,0) < 0)){
+		perror("OST SELF TEST: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+int OSTSetPowerState(int fd, uint32_t state)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,OST_SET_POWER_STATE,state) < 0)){
+		perror("OST SET POWER STATE: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+int OSTGetPowerState(int fd, uint32_t *state)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,OST_GET_POWER_STATE,state) < 0)){
+		perror("OST GET POWER STATE: ");
+		return -1;
+	}
+
+	switch(*state){
+	case OST_POWER_ON:
+		printf("POWER ON (%d)\n",*state);
+		break;
+	case OST_POWER_STANDBY:
+		printf("POWER STANDBY (%d)\n",*state);
+		break;
+	case OST_POWER_SUSPEND:
+		printf("POWER SUSPEND (%d)\n",*state);
+		break;
+	case OST_POWER_OFF:
+		printf("POWER OFF (%d)\n",*state);
+		break;
+	default:
+		printf("unknown (%d)\n",*state);
+		break;
+	}
+
+	return 0;
+}
+
+int FEReadStatus(int fd)
+{
+	int ans;
+	feStatus stat;
+
+	if ( (ans = ioctl(fd,FE_READ_STATUS,&stat) < 0)){
+		perror("FE READ STATUS: ");
+		return -1;
+	}
+
+	if (stat & FE_HAS_POWER)
+		printf("FE HAS POWER\n");
+
+	if (stat & FE_HAS_SIGNAL)
+		printf("FE HAS SIGNAL\n");
+
+	if (stat & QPSK_SPECTRUM_INV)
+		printf("QPSK SPEKTRUM INV\n");
+
+	return 0;
+}
+
+int FEReadBER(int fd, uint32_t *ber)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,FE_READ_BER, ber) < 0)){
+		perror("FE READ_BER: ");
+		return -1;
+	}
+	printf("BER: %d\n",*ber);
+
+	return 0;
+}
+
+int FEReadSignalStrength(int fd, int32_t *strength)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,FE_READ_SIGNAL_STRENGTH, strength) < 0)){
+		perror("FE READ SIGNAL STRENGTH: ");
+		return -1;
+	}
+	printf("SIGNAL STRENGTH: %d\n",*strength);
+
+	return 0;
+}
+
+int FEReadSNR(int fd, int32_t *snr)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,FE_READ_SNR, snr) < 0)){
+		perror("FE READ_SNR: ");
+		return -1;
+	}
+	printf("SNR: %d\n",*snr);
+
+	return 0;
+}
+
+
+int FEReadUncorrectedBlocks(int fd, uint32_t *ucb)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,FE_READ_UNCORRECTED_BLOCKS, ucb) < 0)){
+		perror("FE READ UNCORRECTED BLOCKS: ");
+		return -1;
+	}
+	printf("UBLOCKS: %d\n",*ucb);
+
+	return 0;
+}
+
+int FEGetNextFrequency(int fd, uint32_t *nfr)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,FE_GET_NEXT_FREQUENCY, nfr) < 0)){
+		perror("FE GET NEXT FREQUENCY: ");
+		return -1;
+	}
+	printf("Next Frequency: %d\n",*nfr);
+
+	return 0;
+}
+
+int FEGetNextSymbolRate(int fd, uint32_t *nsr)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,FE_GET_NEXT_SYMBOL_RATE, nsr) < 0)){
+		perror("FE GET NEXT SYMBOL RATE: ");
+		return -1;
+	}
+	printf("Next Symbol Rate: %d\n",*nsr);
+
+	return 0;
+}
+
+int QPSKTune(int fd, struct qpskParameters *param)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,QPSK_TUNE, param) < 0)){
+		perror("QPSK TUNE: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+int QPSKGetEvent (int fd, struct qpskEvent *event)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,QPSK_GET_EVENT, event) < 0)){
+		perror("QPSK GET EVENT: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+int QPSKFEInfo (int fd, struct qpskFrontendInfo *info)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,QPSK_FE_INFO, info) < 0)){
+		perror("QPSK FE INFO: ");
+		return -1;
+	}
+
+	printf("min Frequency   : %d\n", info->minFrequency);
+	printf("max Frequency   : %d\n", info->maxFrequency);
+	printf("min Symbol Rate : %d\n", info->minSymbolRate);
+	printf("max Symbol Rate : %d\n", info->maxSymbolRate);
+	printf("Hardware Type   : %d\n", info->hwType);
+	printf("Hardware Version: %d\n", info->hwVersion);
+
+	return 0;
+}
+
+int SecGetStatus (int fd, struct secStatus *state)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,SEC_GET_STATUS, state) < 0)){
+		perror("QPSK GET EVENT: ");
+		return -1;
+	}
+
+	switch (state->busMode){
+	case SEC_BUS_IDLE:
+		printf("SEC BUS MODE:  IDLE (%d)\n",state->busMode);
+		break;
+	case SEC_BUS_BUSY:
+		printf("SEC BUS MODE:  BUSY (%d)\n",state->busMode);
+		break;
+	case SEC_BUS_OFF:
+		printf("SEC BUS MODE:  OFF  (%d)\n",state->busMode);
+		break;
+	case SEC_BUS_OVERLOAD:
+		printf("SEC BUS MODE:  OVERLOAD (%d)\n",state->busMode);
+		break;
+	default:
+		printf("SEC BUS MODE:  unknown  (%d)\n",state->busMode);
+		break;
+	}
+
+	
+	switch (state->selVolt){
+	case SEC_VOLTAGE_OFF:
+		printf("SEC VOLTAGE:  OFF (%d)\n",state->selVolt);
+		break;
+	case SEC_VOLTAGE_LT:
+		printf("SEC VOLTAGE:  LT  (%d)\n",state->selVolt);
+		break;
+	case SEC_VOLTAGE_13:
+		printf("SEC VOLTAGE:  13  (%d)\n",state->selVolt);
+		break;
+	case SEC_VOLTAGE_13_5:
+		printf("SEC VOLTAGE:  13.5 (%d)\n",state->selVolt);
+		break;
+	case SEC_VOLTAGE_18:
+		printf("SEC VOLTAGE:  18 (%d)\n",state->selVolt);
+		break;
+	case SEC_VOLTAGE_18_5:
+		printf("SEC VOLTAGE:  18.5 (%d)\n",state->selVolt);
+		break;
+	default:
+		printf("SEC VOLTAGE:  unknown (%d)\n",state->selVolt);
+		break;
+	}
+
+	printf("SEC CONT TONE: %s\n", (state->contTone ? "ON" : "OFF"));
+	return 0;
+}
+
+
+main(int argc, char **argv)
+{
+	int fd,fd_sec;
+	uint32_t state;
+	int32_t strength;
+	struct qpskFrontendInfo info;
+	struct secStatus sec_state;
+
+	if((fd = open("/dev/ost/qpskfe",O_RDWR)) < 0){
+		perror("FRONTEND DEVICE: ");
+		return -1;
+	}
+	if((fd_sec = open("/dev/ost/sec",O_RDWR)) < 0){
+		perror("SEC DEVICE: ");
+		return -1;
+	}
+
+	OSTSelftest(fd);
+	OSTSetPowerState(fd, OST_POWER_ON);
+	OSTGetPowerState(fd, &state);
+	FEReadStatus(fd);
+	FEReadBER(fd, &state);
+	FEReadSignalStrength(fd, &strength);
+	FEReadSNR(fd, &state);
+	FEReadUncorrectedBlocks(fd, &state);
+	state = 12567000;
+	FEGetNextFrequency(fd, &state);
+	FEGetNextSymbolRate(fd, &state);
+	QPSKFEInfo (fd, &info);
+	SecGetStatus (fd_sec, &sec_state);
+
+	close(fd);
+	close(fd_sec);
+}
+
diff --git a/test/test_pes.c b/test/test_pes.c
new file mode 100644
index 0000000..bd5a53e
--- /dev/null
+++ b/test/test_pes.c
@@ -0,0 +1,137 @@
+/* test_pes.c - Test for PES filters.
+ * usage: DEMUX=/dev/dvb/adapterX/demuxX test_pes PID
+ *
+ * Copyright (C) 2002 convergence GmbH
+ * Johannes Stezenbach <js at convergence.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include <linux/dvb/dmx.h>
+
+#include "hex_dump.h"
+
+#define MAX_PES_SIZE (4*1024)
+
+
+void usage(void)
+{
+	fprintf(stderr, "usage: test_pes PID [filename]\n");
+	fprintf(stderr, "       Print a hexdump of PES packets from PID to stdout.\n");
+	fprintf(stderr, "  filename : Write binary PES data to file (no hexdump).\n");
+	fprintf(stderr, "       The default demux device used can be changed\n");
+	fprintf(stderr, "       using the DEMUX environment variable\n");
+	exit(1);
+}
+
+void process_pes(int fd, FILE *out)
+{
+	uint8_t buf[MAX_PES_SIZE];
+	int bytes;
+
+	bytes = read(fd, buf, sizeof(buf));
+	if (bytes < 0) {
+		if (errno == EOVERFLOW) {
+			fprintf(stderr, "read error: buffer overflow (%d)\n",
+					EOVERFLOW);
+			return;
+		}
+		else {
+			perror("read");
+			exit(1);
+		}
+	}
+	if (out == stdout) {
+		hex_dump(buf, bytes);
+		printf("\n");
+	}
+	else {
+		printf("got %d bytes\n", bytes);
+		if (fwrite(buf, 1, bytes, out) == 0)
+			perror("write output");
+	}
+}
+
+int set_filter(int fd, unsigned int pid)
+{
+	struct dmx_pes_filter_params f;
+
+	f.pid = (uint16_t) pid;
+	f.input = DMX_IN_FRONTEND;
+	f.output = DMX_OUT_TAP;
+	f.pes_type = DMX_PES_OTHER;
+	f.flags = DMX_IMMEDIATE_START;
+	if (ioctl(fd, DMX_SET_PES_FILTER, &f) == -1) {
+		perror("ioctl DMX_SET_PES_FILTER");
+		return 1;
+	}
+	return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+	int dmxfd;
+	unsigned long pid;
+	char *dmxdev = "/dev/dvb/adapter0/demux0";
+	FILE *out = stdout;
+
+	if (argc != 2 && argc != 3)
+		usage();
+
+	pid = strtoul(argv[1], NULL, 0);
+	if (pid > 0x1fff)
+		usage();
+	if (getenv("DEMUX"))
+		dmxdev = getenv("DEMUX");
+
+	fprintf(stderr, "test_pes: using '%s'\n", dmxdev);
+	fprintf(stderr, "          PID 0x%04lx\n", pid);
+
+	if (argc == 3) {
+		out = fopen(argv[2], "wb");
+		if (!out) {
+			perror("open output file");
+			exit(1);
+		}
+		fprintf(stderr, "          output to '%s'\n", argv[2]);
+	}
+
+	if ((dmxfd = open(dmxdev, O_RDWR)) < 0){
+		perror("open");
+		return 1;
+	}
+
+	if (set_filter(dmxfd, pid) != 0)
+		return 1;
+
+	for (;;) {
+		process_pes(dmxfd, out);
+	}
+
+	close(dmxfd);
+	return 0;
+}
diff --git a/test/test_sec_ne.c b/test/test_sec_ne.c
new file mode 100644
index 0000000..9fcc8b3
--- /dev/null
+++ b/test/test_sec_ne.c
@@ -0,0 +1,165 @@
+/* test_sec_ne.c - Test for Not-Equal section filters.
+ * usage: DEMUX=/dev/dvb/adapterX/demuxX test_sec_ne pid [tid [tid_ext]]
+ *
+ * Copyright (C) 2002 convergence GmbH
+ * Johannes Stezenbach <js at convergence.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include <linux/dvb/dmx.h>
+
+#include "hex_dump.h"
+
+#define MAX_SECTION_SIZE 8192
+
+static unsigned int version_number;
+
+void usage(void)
+{
+	fprintf(stderr, "usage: test_sec_ne pid [tid [tid_ext]]\n");
+	fprintf(stderr, "       Read the version_number from the first section\n");
+	fprintf(stderr, "       and sec a filter to wait for it to change.\n");
+	fprintf(stderr, "       The default demux device used can be changed\n");
+	fprintf(stderr, "       using the DEMUX environment variable;\n");
+	exit(1);
+}
+
+
+void process_section(int fd)
+{
+	uint8_t buf[MAX_SECTION_SIZE];
+	int bytes;
+
+	bytes = read(fd, buf, sizeof(buf));
+	if (bytes < 0) {
+		perror("read");
+		if (bytes != ETIMEDOUT)
+			exit(1);
+	}
+	hex_dump(buf, bytes);
+	version_number = ((buf[5] >> 1) & 0x1f);
+	printf("current version_number: %u\n\n", version_number);
+}
+
+int set_filter(int fd, unsigned int pid, unsigned int tid,
+		unsigned int tid_ext, unsigned int version_number)
+{
+	struct dmx_sct_filter_params f;
+	unsigned long bufsz;
+
+	if (getenv("BUFFER")) {
+		bufsz=strtoul(getenv("BUFFER"), NULL, 0);
+		if (bufsz > 0 && bufsz <= MAX_SECTION_SIZE) {
+			fprintf(stderr, "DMX_SET_BUFFER_SIZE %lu\n", bufsz);
+			if (ioctl(fd, DMX_SET_BUFFER_SIZE, bufsz) == -1) {
+				perror("DMX_SET_BUFFER_SIZE");
+				return 1;
+			}
+		}
+	}
+	memset(&f.filter, 0, sizeof(struct dmx_filter));
+	f.pid = (uint16_t) pid;
+	if (tid < 0x100) {
+		f.filter.filter[0] = (uint8_t) tid;
+		f.filter.mask[0]   = 0xff;
+	}
+	if (tid_ext < 0x10000) {
+		f.filter.filter[1] = (uint8_t) (tid_ext >> 8);
+		f.filter.filter[2] = (uint8_t) (tid_ext & 0xff);
+		f.filter.mask[1]   = 0xff;
+		f.filter.mask[2]   = 0xff;
+	}
+	if (version_number < 0x20) {
+		f.filter.filter[3] = (uint8_t) (version_number << 1);
+		f.filter.mask[3]   = 0x3e;
+		f.filter.mode[3]   = 0x3e;
+	}
+	f.timeout = 0;
+	f.flags = DMX_IMMEDIATE_START;
+
+	if (ioctl(fd, DMX_SET_FILTER, &f) == -1) {
+		perror("DMX_SET_FILTER");
+		return 1;
+	}
+	return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+	int dmxfd;
+	unsigned long pid, tid, tid_ext;
+	char * dmxdev = "/dev/dvb/adapter0/demux0";
+
+	if (argc < 2 || argc > 4)
+		usage();
+
+	pid = strtoul(argv[1], NULL, 0);
+	if (pid > 0x1fff)
+		usage();
+	if (argc > 2) {
+		tid = strtoul(argv[2], NULL, 0);
+		if (tid > 0xff)
+			usage();
+	} else
+		tid = 0x100;
+	if (argc > 3) {
+		tid_ext = strtoul(argv[3], NULL, 0);
+		if (tid_ext > 0xffff)
+			usage();
+	} else
+		tid_ext = 0x10000;
+
+	if (getenv("DEMUX"))
+		dmxdev = getenv("DEMUX");
+	fprintf(stderr, "test_sec_ne: using '%s'\n", dmxdev);
+	fprintf(stderr, "             PID 0x%04lx\n", pid);
+	if (tid < 0x100)
+		fprintf(stderr, "               TID 0x%02lx\n", tid);
+	if (tid_ext < 0x10000)
+		fprintf(stderr, "               TID EXT 0x%04lx\n", tid_ext);
+
+	if ((dmxfd = open(dmxdev, O_RDWR)) < 0){
+		perror("open");
+		return 1;
+	}
+
+	if (set_filter(dmxfd, pid, tid, tid_ext, 0xff) != 0)
+		return 1;
+	process_section(dmxfd);
+	while (1) {
+		if (set_filter(dmxfd, pid, tid, tid_ext, version_number) != 0)
+			return 1;
+		process_section(dmxfd);
+	}
+	for (;;) {
+		process_section(dmxfd);
+	}
+
+	close(dmxfd);
+	return 0;
+}
+
diff --git a/test/test_sections.c b/test/test_sections.c
new file mode 100644
index 0000000..d567db0
--- /dev/null
+++ b/test/test_sections.c
@@ -0,0 +1,197 @@
+/* test_sections.c - Test for section filters.
+ * usage: DEMUX=/dev/dvb/adapterX/demuxX test_sections [PID [TID]]
+ *
+ * Copyright (C) 2002 convergence GmbH
+ * Johannes Stezenbach <js at convergence.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include <linux/dvb/dmx.h>
+
+#include "hex_dump.h"
+
+#define MAX_SECTION_SIZE 8192
+
+
+#if !defined(DMX_FILTER_SIZE)
+#define DMX_FILTER_SIZE 16
+#endif
+
+static void parse_filter(unsigned char* filter, const char* filter_desc)
+{
+        int filter_idx;
+        char* end_ptr;
+
+        memset(filter, '\0', DMX_FILTER_SIZE);
+
+        for (filter_idx = 1; /* Leave first byte for tid */
+             filter_idx < DMX_FILTER_SIZE-1; ++filter_idx) {
+                filter[filter_idx] = strtoul(filter_desc, &end_ptr, 0);
+
+                if (*end_ptr == '\0' || end_ptr == filter_desc)
+                        break;
+
+                filter_desc = end_ptr;
+        }
+}
+
+void usage(void)
+{
+	fprintf(stderr, "usage: test_sections PID [TID] [FILTER] [MASK]\n");
+	fprintf(stderr, "       The default demux device used can be changed\n");
+	fprintf(stderr, "       using the DEMUX environment variable;\n");
+	fprintf(stderr, "       set env BUFFER to play with DMX_SET_BUFFER_SIZE\n");
+        fprintf(stderr, "\n");
+        fprintf(stderr, "       The optional filter and mask may be used to filter on\n");
+        fprintf(stderr, "       additional bytes. These bytes may be given in hex or dec\n");
+        fprintf(stderr, "       separated by spaces (hint: you may have to use quotes around\n");
+        fprintf(stderr, "       FILTER and MASK). TID is always the first byte of the filter,\n");
+        fprintf(stderr, "       and the first byte from FILTER applies to byte 3 of the section\n");
+        fprintf(stderr, "       data (i.e. the first byte after the section length)\n");
+	exit(1);
+}
+
+
+void process_section(int fd)
+{
+	uint8_t buf[MAX_SECTION_SIZE];
+	int bytes;
+
+	bytes = read(fd, buf, sizeof(buf));
+	if (bytes < 0) {
+		perror("read");
+		if (errno != EOVERFLOW)
+			exit(1);
+	}
+	hex_dump(buf, bytes);
+	printf("\n");
+}
+
+int set_filter(int fd, unsigned int pid,
+               const unsigned char* filter, const unsigned char* mask)
+{
+	struct dmx_sct_filter_params f;
+	unsigned long bufsz;
+
+	if (getenv("BUFFER")) {
+		bufsz=strtoul(getenv("BUFFER"), NULL, 0);
+		if (bufsz > 0 && bufsz <= MAX_SECTION_SIZE) {
+			fprintf(stderr, "DMX_SET_BUFFER_SIZE %lu\n", bufsz);
+			if (ioctl(fd, DMX_SET_BUFFER_SIZE, bufsz) == -1) {
+				perror("DMX_SET_BUFFER_SIZE");
+				return 1;
+			}
+		}
+	}
+	memset(&f.filter, 0, sizeof(struct dmx_filter));
+	f.pid = (uint16_t) pid;
+
+        memcpy(f.filter.filter, filter, DMX_FILTER_SIZE);
+        memcpy(f.filter.mask, mask, DMX_FILTER_SIZE);
+	f.timeout = 0;
+	f.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC;
+
+	if (ioctl(fd, DMX_SET_FILTER, &f) == -1) {
+		perror("DMX_SET_FILTER");
+		return 1;
+	}
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int dmxfd;
+	unsigned long pid, tid;
+	char * dmxdev = "/dev/dvb/adapter0/demux0";
+        unsigned char filter[DMX_FILTER_SIZE];
+        unsigned char mask[DMX_FILTER_SIZE];
+        int filter_idx;
+
+	if (argc < 2 || argc > 5)
+		usage();
+
+	pid = strtoul(argv[1], NULL, 0);
+	if (pid > 0x1fff)
+		usage();
+	if (argc > 2) {
+		tid = strtoul(argv[2], NULL, 0);
+		if (tid > 0xff)
+			usage();
+	} else
+		tid = 0x100;
+
+        if (argc > 3)
+                parse_filter(filter, argv[3]);
+        else
+                memset(filter, '\0', sizeof(filter));
+
+        if (argc > 4)
+                parse_filter(mask, argv[4]);
+        else
+                memset(mask, '\0', sizeof(mask));
+
+        if (tid < 0x100) {
+                filter[0] = tid;
+                mask[0]   = 0xff;
+        }
+
+	if (getenv("DEMUX"))
+		dmxdev = getenv("DEMUX");
+	fprintf(stderr, "test_sections: using '%s'\n", dmxdev);
+	fprintf(stderr, "  PID 0x%04lx\n", pid);
+	if (tid < 0x100)
+		fprintf(stderr, "  TID 0x%02lx\n", tid);
+
+
+        fprintf(stderr, "  Filter ");
+
+        for (filter_idx = 0; filter_idx < DMX_FILTER_SIZE; ++filter_idx)
+                fprintf(stderr, "0x%.2x ", filter[filter_idx]);
+        fprintf(stderr, "\n");
+
+        fprintf(stderr, "    Mask ");
+
+        for (filter_idx = 0; filter_idx < DMX_FILTER_SIZE; ++filter_idx)
+                fprintf(stderr, "0x%.2x ", mask[filter_idx]);
+
+        fprintf(stderr, "\n");
+        
+	if ((dmxfd = open(dmxdev, O_RDWR)) < 0){
+		perror("open");
+		return 1;
+	}
+
+	if (set_filter(dmxfd, pid, filter, mask) != 0)
+		return 1;
+
+	for (;;) {
+		process_section(dmxfd);
+	}
+
+	close(dmxfd);
+	return 0;
+}
+
diff --git a/test/test_stc.c b/test/test_stc.c
new file mode 100644
index 0000000..89f141d
--- /dev/null
+++ b/test/test_stc.c
@@ -0,0 +1,74 @@
+/* test_stc.c - Test for DMX_GET_STC.
+ * usage: DEMUX=/dev/dvb/adapterX/demuxX test_stc
+ *
+ * Copyright (C) 2003 convergence GmbH
+ * Johannes Stezenbach <js at convergence.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include <linux/dvb/dmx.h>
+
+
+void usage(void)
+{
+	fprintf(stderr, "usage: test_stc\n");
+	fprintf(stderr, "       The default demux device used can be changed\n");
+	fprintf(stderr, "       using the DEMUX environment variable;\n");
+        fprintf(stderr, "\n");
+	exit(1);
+}
+
+
+int main(int argc, char *argv[])
+{
+	int dmxfd;
+	char * dmxdev = "/dev/dvb/adapter0/demux0";
+	struct dmx_stc stc;
+
+	if (argc != 1 || argv[1])
+		usage();
+
+	if (getenv("DEMUX"))
+		dmxdev = getenv("DEMUX");
+	fprintf(stderr, "test_stc: using '%s'\n", dmxdev);
+
+	if ((dmxfd = open(dmxdev, O_RDWR)) < 0) {
+		perror("open");
+		return 1;
+	}
+
+	stc.num = 0;
+	if (ioctl(dmxfd, DMX_GET_STC, &stc) == -1) {
+		perror("DMX_GET_STC");
+		return 1;
+	}
+
+	printf("STC = %llu (%llu / %u)\n", stc.stc / stc.base, stc.stc, stc.base);
+
+	close(dmxfd);
+	return 0;
+}
+
diff --git a/test/test_stillimage.c b/test/test_stillimage.c
new file mode 100644
index 0000000..264b2c4
--- /dev/null
+++ b/test/test_stillimage.c
@@ -0,0 +1,103 @@
+/* display single iframes as stillimages
+ * iframes can be created with the 'convert' tool from imagemagick
+ * and mpeg2encode from ftp.mpeg.org, and must have a supported
+ * size, e.g. 702x576:
+ *   $ convert -sample 702x576\! test.jpg test.mpg
+ *
+ * or more advanced using netpbm and mpeg2enc (not mpeg2encode) :
+ *   $ cat image.jpg | jpegtopnm | pnmscale -xsize=704 -ysize=576 |\
+ *      ppmntsc --pal | ppmtoy4m  -F 25:1 -A 4:3 |\
+ *      mpeg2enc -f 7 -T 90 -F 3 -np -a 2 -o "image.mpg"
+ *
+ */
+
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/dvb/video.h>
+
+
+static const char *usage_string = "\n\t"
+	"usage: %s <still.mpg> [still.mpg ...]\n"
+	"\n\t"
+	"to use another videodev than the first, set the environment variable VIDEODEV\n\t"
+	"e.g.[user at linux]$ export VIDEODEV=\"/dev/dvb/adapter1/video1\".\n\t"
+	"to display the image <n> seconds, instead of 10, set the variable SSTIME\n\t"
+	"e.g. [user at linux]$ export SSTIME=\"60\" to display the still for 1 minute.\n\t"
+	"this options can be set in the same line as the %s command:\n\t"
+	"e.g. $ SSTIME=25 VIDEODEV=/dev/dvb/adapter1/video1 %s ...\n";
+
+
+int main (int argc, char **argv)
+{
+	int fd;
+	int filefd;
+	struct stat st;
+	struct video_still_picture sp;
+	char *videodev = "/dev/dvb/adapter0/video0";
+	char *env_sstime;
+	int i = 1;
+	int tsec = 10;
+
+	if (argc < 2) {
+		fprintf (stderr, usage_string, argv[0],argv[0],argv[0]);
+		return -1;
+	}
+
+	if (getenv ("VIDEODEV"))
+		videodev = getenv("VIDEODEV");
+
+	if (getenv ("SSTIME")) {
+		env_sstime = getenv("SSTIME");
+		tsec = atoi(env_sstime);
+	}
+
+	if ((fd = open(videodev, O_RDWR)) < 0) {
+		perror(videodev);
+		return -1;
+	}
+
+next_pic:
+	printf("I-frame     : '%s'\n", argv[i]);
+	if ((filefd = open(argv[i], O_RDONLY)) < 0) {
+		perror(argv[i]);
+		return -1;
+	}
+
+	fstat(filefd, &st);
+
+	sp.iFrame = (char *) malloc (st.st_size);
+	sp.size = st.st_size;
+	printf("I-frame size: %d\n", sp.size);
+
+	if (!sp.iFrame) {
+		fprintf (stderr, "No memory for I-Frame\n");
+		return -1;
+	}
+
+	printf ("read: %d bytes\n", read(filefd, sp.iFrame, sp.size));
+	close(filefd);
+
+	if ((ioctl(fd, VIDEO_STILLPICTURE, &sp) < 0)) {
+		perror("ioctl VIDEO_STILLPICTURE");
+		return -1;
+	}
+	free(sp.iFrame);
+
+	printf("Display image %d seconds ...\n",tsec);
+	sleep(tsec);
+	printf("Done.\n");
+	if (argc > ++i)
+		goto next_pic;
+
+	return 0;
+}
+
+
diff --git a/test/test_switch.c b/test/test_switch.c
new file mode 100644
index 0000000..7f80891
--- /dev/null
+++ b/test/test_switch.c
@@ -0,0 +1,355 @@
+/* 
+ * test_switch.c - Test program for new API
+ *
+ * Copyright (C) 2001 Ralph  Metzler <ralph at convergence.de>
+ *                  & Marcus Metzler <marcus at convergence.de>
+                      for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/poll.h>
+
+#include <linux/dvb/dmx.h>
+#include <linux/dvb/frontend_old.h>
+#include <linux/dvb/sec.h>
+#include <linux/dvb/video.h>
+
+int fd_frontend;
+int fd_sec;
+int fd_demuxa;
+int fd_demuxv;
+int fd_demuxtt;
+
+struct dmx_sct_filter_params sctFilterParams;
+	
+struct secCommand scmd;
+struct secCmdSequence scmds;
+struct dmx_pes_filter_params pesFilterParams; 
+struct dmx_pes_filter_params pesFilterParamsV; 
+struct dmx_pes_filter_params pesFilterParamsA; 
+struct dmx_pes_filter_params pesFilterParamsTT; 
+FrontendParameters frp;
+int front_type;
+
+
+set_front(void) 
+{
+	fe_status_t stat = 0;
+	int i, freq;
+	uint32_t soff;
+	  
+	scmds.miniCommand = SEC_MINI_NONE;
+	scmds.numCommands = 1;
+	scmds.commands = &scmd;
+	
+	soff = frp.u.qpsk.SymbolRate/16000;
+
+	if (ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds) < 0)
+		perror("setfront sec");
+	usleep(100000);
+		
+	freq = frp.Frequency;
+		
+	while(tune_it(&frp));
+}	        
+
+set_diseqc_nb(int nr) 
+{
+	scmd.type=0;
+	scmd.u.diseqc.addr = 0x10;
+	scmd.u.diseqc.cmd = 0x38;
+	scmd.u.diseqc.numParams = 1;
+	scmd.u.diseqc.params[0] = 0xF0 | ((nr * 4) & 0x0F) | 
+	  (scmds.continuousTone == SEC_TONE_ON ? 1 : 0) |
+	  (scmds.voltage==SEC_VOLTAGE_18 ? 2 : 0);
+}
+
+set_ttpid(ushort ttpid) 
+{  
+        if (ttpid==0 || ttpid==0xffff || ttpid==0x1fff) {
+	        ioctl(fd_demuxtt, DMX_STOP, 0);
+	        return;
+	}
+
+	pesFilterParamsTT.pid     = ttpid;
+	pesFilterParamsTT.input   = DMX_IN_FRONTEND; 
+	pesFilterParamsTT.output  = DMX_OUT_DECODER; 
+	pesFilterParamsTT.pes_type = DMX_PES_TELETEXT; 
+	pesFilterParamsTT.flags   = DMX_IMMEDIATE_START;
+	if (ioctl(fd_demuxtt, DMX_SET_PES_FILTER, 
+		  &pesFilterParamsTT) < 0) {
+	  printf("PID=%04x\n", ttpid);
+		perror("set_ttpid");
+	}
+}
+
+set_vpid(ushort vpid) 
+{  
+        if (vpid==0 || vpid==0xffff || vpid==0x1fff) {
+	        ioctl(fd_demuxv, DMX_STOP, 0);
+	        return;
+	}
+
+	pesFilterParamsV.pid     = vpid;
+	pesFilterParamsV.input   = DMX_IN_FRONTEND; 
+	pesFilterParamsV.output  = DMX_OUT_DECODER; 
+	pesFilterParamsV.pes_type = DMX_PES_VIDEO; 
+	pesFilterParamsV.flags   = DMX_IMMEDIATE_START;
+	if (ioctl(fd_demuxv, DMX_SET_PES_FILTER, 
+		  &pesFilterParamsV) < 0)
+		perror("set_vpid");
+}
+
+set_apid(ushort apid) 
+{  
+        if (apid==0 || apid==0xffff || apid==0x1fff) {
+	        ioctl(fd_demuxa, DMX_STOP, apid);
+	        return;
+	}
+	pesFilterParamsA.pid = apid;
+	pesFilterParamsA.input = DMX_IN_FRONTEND; 
+	pesFilterParamsA.output = DMX_OUT_DECODER; 
+	pesFilterParamsA.pes_type = DMX_PES_AUDIO; 
+	pesFilterParamsA.flags = DMX_IMMEDIATE_START;
+	if (ioctl(fd_demuxa, DMX_SET_PES_FILTER, 
+		  &pesFilterParamsA) < 0)
+		perror("set_apid");
+}
+
+int tune_it(FrontendParameters *frp)
+{
+	fe_status_t stat = 0;
+	int res;
+	FrontendEvent event;
+	int count = 0;
+	struct pollfd pfd[1];
+
+	if (ioctl(fd_frontend, FE_SET_FRONTEND, frp) <0)
+		perror("setfront front");
+
+
+
+	pfd[0].fd = fd_frontend;
+	pfd[0].events = POLLIN;
+
+	if (poll(pfd,1,3000)){
+		if (pfd[0].revents & POLLIN){
+			printf("Getting QPSK event\n");
+			if ( ioctl(fd_frontend, FE_GET_EVENT, &event)  
+
+			     == -EOVERFLOW){
+				perror("qpsk get event");
+				return -1;
+			}
+			printf("Received ");
+			switch(event.type){
+			case FE_UNEXPECTED_EV:
+				printf("unexpected event\n");
+				return -1;
+			case FE_FAILURE_EV:
+				printf("failure event\n");
+				return -1;
+				
+			case FE_COMPLETION_EV:
+				printf("completion event\n");
+			}
+		}
+	}
+	return 0;
+}
+
+set_tp(uint *freq, int ttk, int pol, uint srate, int dis) 
+{
+	if (*freq < 11700000) {
+		frp.Frequency = (*freq - 9750000);
+		scmds.continuousTone = SEC_TONE_OFF;
+	} else {
+		frp.Frequency = (*freq - 10600000);
+		scmds.continuousTone = SEC_TONE_ON;
+	}
+	if (pol) scmds.voltage = SEC_VOLTAGE_18;
+	else scmds.voltage = SEC_VOLTAGE_13;
+	set_diseqc_nb(dis);
+	frp.u.qpsk.SymbolRate = srate;
+	frp.u.qpsk.FEC_inner = 0;
+}
+
+get_front(void) 
+{
+	set_vpid(0);
+	set_apid(0);
+	set_ttpid(0);
+	scmds.voltage = SEC_VOLTAGE_18; 
+	scmds.miniCommand = SEC_MINI_NONE;
+	scmds.continuousTone = SEC_TONE_OFF;
+	scmds.numCommands=1;
+	scmds.commands=&scmd;
+	
+	frp.Frequency=(12073000-10600000);
+	frp.u.qpsk.SymbolRate=25378000;
+	frp.u.qpsk.FEC_inner=(fe_code_rate_t)5;
+}	        
+  
+
+void get_sect(int fd)
+{
+        u_char sec[4096];
+        int len, i;
+        uint16_t cpid = 0;
+        uint16_t length;
+        struct pollfd pfd;
+       
+        pfd.fd = fd;
+        pfd.events = POLLIN;
+       
+	while (1){
+		if (poll(&pfd, 1, 5000) != POLLIN) {
+			printf("not found\n");
+			printf("Timeout\n");
+		} else {
+			len = read(fd, sec, 4096);
+
+			length  = (sec[1]& 0x0F)<<8;
+			length |= (sec[2]& 0xFF);
+        
+
+			for (i= 0; i < length+3; i++) {
+				printf("0x%02x ",sec[i]);
+				if ( !((i+1)%8))
+					printf("\n");
+			}
+			printf("\n");
+		}
+	}
+}
+
+int FEReadStatus(int fd, fe_status_t *stat)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,FE_READ_STATUS,stat) < 0)){
+		perror("FE READ STATUS: ");
+		return -1;
+	}
+
+	if (*stat & FE_HAS_POWER)
+		printf("FE HAS POWER\n");
+
+	if (*stat & FE_HAS_SIGNAL)
+		printf("FE HAS SIGNAL\n");
+
+	if (*stat & FE_SPECTRUM_INV)
+		printf("QPSK SPEKTRUM INV\n");
+
+	return 0;
+}
+
+int has_signal()
+{
+	fe_status_t stat;
+	
+	FEReadStatus(fd_frontend, &stat);
+	if (stat & FE_HAS_SIGNAL)
+		return 1;
+	else {
+		printf("Tuning failed\n");
+		return 0;
+	}
+}
+
+main()
+{
+	int freq;
+
+	fd_demuxtt = open("/dev/ost/demux", O_RDWR|O_NONBLOCK);
+	fd_frontend = open("/dev/ost/frontend", O_RDWR);
+	fd_sec = open("/dev/ost/sec", O_RDWR);
+	fd_demuxa = open("/dev/ost/demux", O_RDWR|O_NONBLOCK);
+	fd_demuxv = open("/dev/ost/demux", O_RDWR|O_NONBLOCK);
+
+//	get_front();
+//        set_vpid(0x7d0);
+//       set_apid(0x7d2);
+//	set_ttpid(0);
+//	freq = 12073000;
+//	set_tp(&freq, 1, 1, 25378000, 3);
+//	set_diseqc_nb(dis);
+
+	scmds.voltage = SEC_VOLTAGE_18;
+//	scmds.voltage = SEC_VOLTAGE_13;
+	scmds.miniCommand = SEC_MINI_NONE;
+	scmds.continuousTone = SEC_TONE_OFF;
+	scmds.numCommands=1;
+	scmds.commands=&scmd;
+	frp.Frequency = (12073000 - 10600000);
+//	frp.Frequency = (11975000 - 10600000);
+	scmds.continuousTone = SEC_TONE_ON; 
+	frp.u.qpsk.SymbolRate = 25378000;
+//	frp.u.qpsk.SymbolRate = 27500000;
+//	frp.u.qpsk.FEC_inner = FEC_AUTO;
+	frp.u.qpsk.FEC_inner = (fe_code_rate_t)5;
+	scmd.type=0;
+	scmd.u.diseqc.addr = 0x10;
+	scmd.u.diseqc.cmd = 0x38;
+	scmd.u.diseqc.numParams = 1;
+	scmd.u.diseqc.params[0] = 0xF0 | ((3 * 4) & 0x0F) | 
+	  (scmds.continuousTone == SEC_TONE_ON ? 1 : 0) |
+	  (scmds.voltage==SEC_VOLTAGE_18 ? 2 : 0);
+
+	if (ioctl(fd_sec, SEC_SEND_SEQUENCE, &scmds) < 0)
+		perror("setfront sec");
+
+	while(tune_it(&frp));
+
+
+/*
+	if ((fd_demuxa=open("/dev/ost/demux", O_RDWR|O_NONBLOCK)) 
+	    < 0){
+		perror("DEMUX DEVICE: ");
+		return -1;
+	}
+        memset(&sctFilterParams.filter, 0, sizeof(struct dmx_filter));
+        sctFilterParams.pid                       = 0x1fff;
+        sctFilterParams.filter.filter[0]          = 0x00;
+        sctFilterParams.filter.mask[0]            = 0x00;
+        sctFilterParams.timeout                   = 0;
+        sctFilterParams.flags                     = DMX_IMMEDIATE_START;
+
+        if (ioctl(fd_demuxa, DMX_SET_FILTER, &sctFilterParams) < 0)  
+                perror("DMX SET FILTER:");
+
+
+	get_sect(fd_demuxa);
+*/
+	pesFilterParamsA.pid = 0x1fff;
+	pesFilterParamsA.input = DMX_IN_FRONTEND; 
+	pesFilterParamsA.output = DMX_OUT_TS_TAP; 
+	pesFilterParamsA.pes_type = DMX_PES_OTHER; 
+	pesFilterParamsA.flags = DMX_IMMEDIATE_START;
+	if (ioctl(fd_demuxa, DMX_SET_PES_FILTER, 
+		  &pesFilterParamsA) < 0)
+		perror("set_apid");
+
+	while(1);
+}
diff --git a/test/test_tt.c b/test/test_tt.c
new file mode 100644
index 0000000..6511f39
--- /dev/null
+++ b/test/test_tt.c
@@ -0,0 +1,205 @@
+/* test_tt.c - example of using PES filter for teletext output.
+ *             c.f. ETSI EN-300-472
+ *
+ * usage: DEMUX=/dev/dvb/adapterX/demuxX test_tt PID
+ *
+ * Copyright (C) 2002 convergence GmbH
+ * Johannes Stezenbach <js at convergence.de> based on code by
+ * Ralph Metzler <ralph at convergence.de> and Marcus Metzler <marcus at convergence.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include <linux/dvb/dmx.h>
+
+#include "hex_dump.h"
+
+#define MAX_PES_SIZE (4*1024)
+
+
+uint8_t reverse[] = {
+0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0,
+0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8,
+0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4,
+0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC,
+0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2,
+0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA,
+0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6,
+0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE,
+0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1,
+0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9,
+0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5,
+0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD,
+0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3,
+0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB,
+0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7,
+0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF
+};
+
+
+
+void usage(void)
+{
+	fprintf(stderr, "usage: test_tt PID\n");
+	fprintf(stderr, "       The default demux device used can be changed\n");
+	fprintf(stderr, "       using the DEMUX environment variable\n");
+	exit(1);
+}
+
+void safe_read(int fd, void *buf, int count)
+{
+	int bytes;
+
+	do {
+		bytes = read(fd, buf, count);
+		if (bytes < 0) {
+			if (errno == EOVERFLOW)
+				fprintf(stderr, "read error: buffer overflow (%d)\n",
+						EOVERFLOW);
+			else {
+				perror("read");
+				exit(1);
+			}
+		}
+		else if (bytes == 0) {
+			fprintf(stderr, "got EOF on demux!?\n");
+			exit(1);
+		}
+	} while (bytes < count);
+}
+
+void process_pes(int fd)
+{
+	uint8_t buf[MAX_PES_SIZE];
+	int i, plen, hlen, sid, lines, l;
+
+	/* search for start of next PES data block 0x000001bd */
+	for (;;) {
+		safe_read(fd, buf, 1);
+		if (buf[0] != 0) continue;
+		safe_read(fd, buf, 1);
+		if (buf[0] != 0) continue;
+		safe_read(fd, buf, 1);
+		if (buf[0] != 1) continue;
+		safe_read(fd, buf, 1);
+		if (buf[0] == 0xbd)
+			break;
+	}
+
+	safe_read(fd, buf, 5);
+	/* PES packet length */
+	plen = ((buf[0] << 8) | buf[1]) & 0xffff;
+
+	/* PES header data length */
+	hlen = buf[4];
+	if (hlen != 0x24) {
+		fprintf(stderr, "error: PES header data length != 0x24 (0x%02x)\n", hlen);
+		return;
+	}
+	/* skip rest of PES header */
+	safe_read(fd, buf, hlen);
+
+	/* read stream ID */
+	safe_read(fd, buf, 1);
+	sid = buf[0];
+	if (sid < 0x10 || sid > 0x1f) {
+		fprintf(stderr, "error: non-EBU stream ID 0x%02x\n", sid);
+		return;
+	}
+
+	/* number of VBI lines */
+	lines = (plen + 6) / 46 - 1;
+
+	/* read VBI data */
+	for (l = 0; l < lines; l++) {
+		safe_read(fd, buf, 46);
+		if (buf[1] != 44) {
+			fprintf(stderr, "error: VBI line has invalid length\n");
+			return;
+		}
+		/* bit twiddling */
+		for (i = 2; i < 46; i++)
+			buf[i] = reverse[buf[i]];
+		/* framing code, should be 11100100b */
+		if (buf[3] != 0x27) {
+			fprintf(stderr, "error: wrong framing code\n");
+			return;
+		}
+		/* remaining data needs to be hamming decoded, but we should
+		 * be able to read some partial strings */
+		hex_dump(buf, 46);
+		printf("\n");
+	}
+}
+
+int set_filter(int fd, unsigned int pid)
+{
+	struct dmx_pes_filter_params f;
+
+	f.pid = (uint16_t) pid;
+	f.input = DMX_IN_FRONTEND;
+	f.output = DMX_OUT_TAP;
+	f.pes_type = DMX_PES_OTHER; /* DMX_PES_TELETEXT if you want vbi insertion */
+	f.flags = DMX_IMMEDIATE_START;
+	if (ioctl(fd, DMX_SET_PES_FILTER, &f) == -1) {
+		perror("ioctl DMX_SET_PES_FILTER");
+		return 1;
+	}
+	return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+	int dmxfd;
+	unsigned long pid;
+	char * dmxdev = "/dev/dvb/adapter0/demux0";
+
+	if (argc != 2)
+		usage();
+
+	pid = strtoul(argv[1], NULL, 0);
+	if (pid > 0x1fff)
+		usage();
+	if (getenv("DEMUX"))
+		dmxdev = getenv("DEMUX");
+	fprintf(stderr, "test_tt: using '%s'\n", dmxdev);
+	fprintf(stderr, "         PID 0x%04lx\n", pid);
+
+	if ((dmxfd = open(dmxdev, O_RDWR)) < 0){
+		perror("open");
+		return 1;
+	}
+
+	if (set_filter(dmxfd, pid) != 0)
+		return 1;
+
+	for (;;) {
+		process_pes(dmxfd);
+	}
+
+	close(dmxfd);
+	return 0;
+}
+
diff --git a/test/test_vevent.c b/test/test_vevent.c
new file mode 100644
index 0000000..f61143e
--- /dev/null
+++ b/test/test_vevent.c
@@ -0,0 +1,125 @@
+/* 
+ * test_vevent.c - Test VIDEO_GET_EVENT and poll(9 for video events
+ *
+ * Copyright (C) 2003 convergence GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/poll.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/dvb/video.h>
+
+
+int videoGetSize(int fd, char *arg)
+{
+	video_size_t size;
+
+	if (arg)
+		return -1;
+	if (ioctl(fd, VIDEO_GET_SIZE, &size) == -1){
+		perror("VIDEO_GET_SIZE");
+		return 0;
+	}
+
+	printf("Video Size: %ux%u ", size.w, size.h);
+	switch (size.aspect_ratio) {
+	case VIDEO_FORMAT_4_3:
+		printf("4:3 (%d)\n", size.aspect_ratio);
+		break;
+	case VIDEO_FORMAT_16_9:
+		printf("16:9 (%d)\n", size.aspect_ratio);
+		break;
+	case VIDEO_FORMAT_221_1:
+		printf("2.21:1 (%d)\n", size.aspect_ratio);
+		break;
+	default:
+		printf("unknown aspect ratio (%d)\n", size.aspect_ratio);
+		break;
+	}
+	return 0;
+}
+
+int main(void)
+{
+	int vfd, rc;
+	char *videodev = "/dev/dvb/adapter0/video0";
+	struct pollfd pfd[1];
+	struct video_event event;
+
+	if (getenv("VIDEO"))
+		videodev = getenv("VIDEO");
+
+	printf("using video device '%s'\n", videodev);
+
+	if((vfd = open(videodev, O_RDONLY | O_NONBLOCK)) < 0) {
+		perror("open video device");
+		return 1;
+	}
+
+	videoGetSize(vfd, NULL);
+
+	pfd[0].fd = vfd;
+	pfd[0].events = POLLPRI;
+
+	for (;;) {
+		rc = poll(pfd, 1, -1);
+		if (rc == -1) {
+			perror("poll");
+			return -1;
+		}
+		printf("poll events: %#x\n", pfd[0].revents);
+		if (pfd[0].revents & POLLPRI) {
+			rc = ioctl(vfd, VIDEO_GET_EVENT, &event);
+			if (rc == -1) {
+				perror("VIDEO_GET_EVENT");
+				return -1;
+			}
+			printf("video event %d\n", event.type);
+			if (event.type == VIDEO_EVENT_SIZE_CHANGED) {
+				printf("  VIDEO_EVENT_SIZE_CHANGED %ux%u ",
+						event.u.size.w, event.u.size.h);
+				switch (event.u.size.aspect_ratio) {
+				case VIDEO_FORMAT_4_3:
+					printf("4:3 (%d)\n", event.u.size.aspect_ratio);
+					break;
+				case VIDEO_FORMAT_16_9:
+					printf("16:9 (%d)\n", event.u.size.aspect_ratio);
+					break;
+				case VIDEO_FORMAT_221_1:
+					printf("2.21:1 (%d)\n", event.u.size.aspect_ratio);
+					break;
+				default:
+					printf("unknown aspect ratio (%d)\n",
+							event.u.size.aspect_ratio);
+					break;
+				}
+			}
+		}
+	}
+
+	close(vfd);
+	return 0;
+}
+
diff --git a/test/test_video.c b/test/test_video.c
new file mode 100644
index 0000000..09c2be1
--- /dev/null
+++ b/test/test_video.c
@@ -0,0 +1,368 @@
+/* 
+ * test_video.c - Test program for new API
+ *
+ * Copyright (C) 2000 Ralph  Metzler <ralph at convergence.de>
+ *                  & Marcus Metzler <marcus at convergence.de>
+                      for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <linux/dvb/dmx.h>
+#include <linux/dvb/frontend_old.h>
+#include <linux/dvb/sec.h>
+#include <linux/dvb/video.h>
+#include <sys/poll.h>
+
+int videoStop(int fd)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,VIDEO_STOP,0) < 0)){
+		perror("VIDEO STOP: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+int videoPlay(int fd)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,VIDEO_PLAY) < 0)){
+		perror("VIDEO PLAY: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int videoFreeze(int fd)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,VIDEO_FREEZE) < 0)){
+		perror("VIDEO FREEZE: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int videoContinue(int fd)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,VIDEO_CONTINUE) < 0)){
+		perror("VIDEO CONTINUE: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+int videoSelectSource(int fd, video_stream_source_t source)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,VIDEO_SELECT_SOURCE, source) < 0)){
+		perror("VIDEO SELECT SOURCE: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+
+int videoSetBlank(int fd, boolean state)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,VIDEO_SET_BLANK, state) < 0)){
+		perror("VIDEO SET BLANK: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+int videoFastForward(int fd,int nframes)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,VIDEO_FAST_FORWARD, nframes) < 0)){
+		perror("VIDEO FAST FORWARD: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+int videoSlowMotion(int fd,int nframes)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,VIDEO_SLOWMOTION, nframes) < 0)){
+		perror("VIDEO SLOWMOTION: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+int videoGetStatus(int fd)
+{
+	struct video_status stat;
+	int ans;
+
+	if ( (ans = ioctl(fd,VIDEO_GET_STATUS, &stat) < 0)){
+		perror("VIDEO GET STATUS: ");
+		return -1;
+	}
+
+	printf("Video Status:\n");
+	printf("  Blank State          : %s\n",
+	       (stat.video_blank ? "BLANK" : "STILL"));
+	printf("  Play State           : ");
+	switch ((int)stat.play_state){
+	case VIDEO_STOPPED:
+		printf("STOPPED (%d)\n",stat.play_state);
+		break;
+	case VIDEO_PLAYING:
+		printf("PLAYING (%d)\n",stat.play_state);
+		break;
+	case VIDEO_FREEZED:
+		printf("FREEZED (%d)\n",stat.play_state);
+		break;
+	default:
+		printf("unknown (%d)\n",stat.play_state);
+		break;
+	}
+	
+	printf("  Stream Source        : ");
+	switch((int)stat.stream_source){
+	case VIDEO_SOURCE_DEMUX:
+		printf("DEMUX (%d)\n",stat.stream_source);
+		break;
+	case VIDEO_SOURCE_MEMORY:
+		printf("MEMORY (%d)\n",stat.stream_source);
+		break;
+	default:
+		printf("unknown (%d)\n",stat.stream_source);
+		break;
+	}
+
+	printf("  Format (Aspect Ratio): ");
+	switch((int)stat.video_format){
+	case VIDEO_FORMAT_4_3:
+		printf("4:3 (%d)\n",stat.video_format);
+		break;
+	case VIDEO_FORMAT_16_9:
+		printf("16:9 (%d)\n",stat.video_format);
+		break;
+	default:
+		printf("unknown (%d)\n",stat.video_format);
+		break;
+	}
+
+	printf("  Display Format       : ");
+	switch((int)stat.display_format){
+	case VIDEO_PAN_SCAN:
+		printf("Pan&Scan (%d)\n",stat.display_format);
+		break;
+	case VIDEO_LETTER_BOX:
+		printf("Letterbox (%d)\n",stat.display_format);
+		break;
+	case VIDEO_CENTER_CUT_OUT:
+		printf("Center cutout (%d)\n",stat.display_format);
+		break;
+	default:
+		printf("unknown (%d)\n",stat.display_format);
+		break;
+	}
+	return 0;
+}
+
+int videoStillPicture(int fd, struct video_still_picture *sp)
+{
+	int ans;
+
+	if ( (ans = ioctl(fd,VIDEO_STILLPICTURE, sp) < 0)){
+		perror("VIDEO STILLPICTURE: ");
+		return -1;
+	}
+
+	return 0;
+}
+
+#define BUFFY 32768
+#define NFD   2
+void play_file_video(int filefd, int fd)
+{
+	char buf[BUFFY];
+	int count;
+	int written;
+	struct pollfd pfd[NFD];
+	int stopped = 0;
+	int ch;
+
+	pfd[0].fd = STDIN_FILENO;
+	pfd[0].events = POLLIN;
+	
+	pfd[1].fd = fd;
+	pfd[1].events = POLLOUT;
+	
+	videoSelectSource(fd,VIDEO_SOURCE_MEMORY);
+	videoPlay(fd);
+	
+	
+	count = read(filefd,buf,BUFFY);
+	write(fd,buf,count);
+	
+	while ( (count = read(filefd,buf,BUFFY)) >= 0  ){
+		written = 0;
+		while(written < count){
+			if (poll(pfd,NFD,1)){
+				if (pfd[1].revents & POLLOUT){
+					written += write(fd,buf+written,
+							count-written);
+				}
+				if (pfd[0].revents & POLLIN){
+					int c = getchar();
+					switch(c){
+					case 'z':
+						videoFreeze(fd);
+						printf("playback frozen\n");
+						stopped = 1;
+						break;
+
+					case 's':
+						videoStop(fd);
+						printf("playback stopped\n");
+						stopped = 1;
+						break;
+						
+					case 'c':
+						videoContinue(fd);
+						printf("playback continued\n");
+						stopped = 0;
+						break;
+
+					case 'p':
+						videoPlay(fd);
+						printf("playback started\n");
+						stopped = 0;
+						break;
+
+					case 'f':
+						videoFastForward(fd,0);
+						printf("fastforward\n");
+						stopped = 0;
+						break;
+
+					case 'm':
+						videoSlowMotion(fd,2);
+						printf("slowmotion\n");
+						stopped = 0;
+						break;
+
+					case 'q':
+						videoContinue(fd);
+						exit(0);
+						break;
+					}
+				}
+				
+			}
+		}
+	}
+}
+
+void load_iframe(int filefd, int fd)
+{
+	struct stat st;
+	struct video_still_picture sp;
+
+	fstat(filefd, &st);
+	
+	sp.iFrame = (char *) malloc(st.st_size);
+	sp.size = st.st_size;
+	printf("I-frame size: %d\n", sp.size);
+	
+	if(!sp.iFrame) {
+		printf("No memory for I-Frame\n");
+		return;
+	}
+
+	printf("read: %d bytes\n",read(filefd,sp.iFrame,sp.size));
+	videoStillPicture(fd,&sp);
+
+	sleep(3);
+	videoPlay(fd);
+}
+
+main(int argc, char **argv)
+{
+	int fd;
+	int filefd;
+
+	if (argc < 2) return -1;
+
+	if ( (filefd = open(argv[1],O_RDONLY)) < 0){
+		perror("File open:");
+		return -1;
+	}
+	if((fd = open("/dev/ost/video1",O_RDWR|O_NONBLOCK)) < 0){
+		perror("VIDEO DEVICE: ");
+		return -1;
+	}
+	    
+	
+
+
+//	videoSetBlank(fd,false);
+	//videoPlay(fd);
+	//sleep(4);
+	//videoFreeze(fd);
+	//sleep(3);
+	//videoContinue(fd);
+	//sleep(3);
+	//videoStop(fd);
+	videoGetStatus(fd);
+
+
+	//load_iframe(filefd, fd);
+	play_file_video(filefd, fd);
+	close(fd);
+	close(filefd);
+	return 0;
+
+
+}
+
diff --git a/test/video.c b/test/video.c
new file mode 100644
index 0000000..ea9e4a2
--- /dev/null
+++ b/test/video.c
@@ -0,0 +1,182 @@
+ /**
+ *  A tiny video watching application, just starts capturing /dev/video
+ *  into /dev/fb0.
+ *  Be shure to have >8Bit/pixel color resolution and r/w access for 
+ *  /dev/video0, /dev/fb0 and /dev/tty0 to let this work...
+ *
+ *   compile with
+ *
+ *   $ gcc -g -Wall -O2 -o video video.c -I../../ost/include
+ */
+
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <linux/fb.h>
+#include <linux/videodev.h>
+
+#define VIDEO_DEV "/dev/video0"
+#define FB_DEV "/dev/fb0"
+#define VT_DEV "/dev/tty0"
+
+static char *video_devname = VIDEO_DEV;
+
+#define min(a,b)	(a) < (b) ? (a) : (b)
+
+static int zero = 0;
+static int one = 1;
+
+static struct fb_var_screeninfo fb_var;
+static struct fb_fix_screeninfo fb_fix;
+
+
+int init_fb (void)
+{
+	const char blankoff_str[] = "\033[9;0]";
+	int fd, vt_fd;
+
+	fd = open (FB_DEV, O_RDWR);
+	if (fd < 0) {
+		perror("Could not open " FB_DEV ", please check permissions\n");
+		return 1;
+	}
+
+	if ((vt_fd = open( VT_DEV, O_RDWR )) < 0) {
+		perror("Could not open " VT_DEV ", please check permissions\n");
+		return 1;
+	}
+
+	write( vt_fd, blankoff_str, strlen(blankoff_str) );
+	
+	if (ioctl (fd, FBIOGET_VSCREENINFO, &fb_var) < 0) {
+		perror("Could not get variable screen information (fb_var)\n");
+		return 1;
+	}
+
+	if (ioctl (fd, FBIOGET_FSCREENINFO, &fb_fix) < 0) {
+		perror("Could not get fixed screen information (fb_fix)\n");
+		return 1;
+	}
+
+	close (fd);
+	return 0;
+}
+
+
+int init_video (int stop)
+{
+	int fd;
+	struct video_capability vcap;
+
+	if ((fd = open (video_devname, O_RDWR)) < 0) {
+		fprintf (stderr, 
+			 "%s: Could not open %s, please check permissions\n",
+			 __FUNCTION__, video_devname);
+		return -1;
+	}
+
+	ioctl(fd, VIDIOCGCAP, &vcap);
+	
+	if (ioctl(fd, VIDIOCCAPTURE, &zero) < 0) {
+		perror("Could not stop capturing (VIDIOCCAPTURE failed)\n");
+		return -2;
+	}
+
+	if (stop)
+		return 0;
+	
+	{
+		struct video_buffer b;
+		b.base = (void*) fb_fix.smem_start;
+		b.width = fb_var.xres;
+		b.height = fb_var.yres;
+		b.depth = fb_var.bits_per_pixel;
+		b.bytesperline = fb_var.xres*((fb_var.bits_per_pixel+7)/8);
+		if (ioctl(fd, VIDIOCSFBUF, &b) < 0) {
+			fprintf(stderr, "VIDIOCSFBUF failed, must run as root?\n");
+			return -3;
+		}
+	}
+	
+	{
+		struct video_picture p;
+		if (ioctl(fd, VIDIOCGPICT, &p) < 0) {
+			perror("VIDIOCGPICT failed\n");
+			return -4;
+		}
+		p.depth = fb_var.bits_per_pixel;
+		switch (fb_var.bits_per_pixel) {
+			case 16:
+				p.palette = VIDEO_PALETTE_RGB565;
+				break;
+			case 24:
+				p.palette = VIDEO_PALETTE_RGB24;
+				break;
+			case 32:
+				p.palette = VIDEO_PALETTE_RGB32;
+				break;
+		}
+		//p.contrast = 0x8000;
+		//p.colour = 0x6000;
+		if (ioctl(fd, VIDIOCSPICT, &p) < 0) {
+			perror("VIDIOCSPICT failed\n");
+			return -5;
+		}
+	}
+	
+	{
+		struct video_window win;
+		win.width = min((__u32) vcap.maxwidth, fb_var.xres);
+		win.height = min((__u32) vcap.maxheight, fb_var.yres);
+		win.x = 0;
+		win.y = 0;
+		win.flags = 0;
+		win.clips = NULL;
+		win.clipcount = 0;
+		win.chromakey = 0;
+		if (ioctl(fd, VIDIOCSWIN, &win) < 0) {
+			perror("VIDIOCSWIN failed\n");
+			return -6;
+		}
+	}
+	
+	if (ioctl(fd, VIDIOCCAPTURE, &one) < 0) {
+		perror("Could not start capturing (VIDIOCCAPTURE failed)\n");
+		return -7;
+	}
+	
+	close (fd);
+	
+	return 0;
+}
+
+int main (int argc, char **argv)
+{
+	int err = 0, stop = 0;
+
+	if ((err = init_fb()))
+		return err;
+
+	if ((argc == 2 && strcmp(argv[1], "stop") == 0) ||
+	    (argc == 3 && strcmp(argv[2], "stop") == 0))
+		stop = 1;
+
+	if ((argc == 2 && !stop) || argc == 3)
+		video_devname = argv[1];
+
+	if (argc != 1 && argc != 2 && !(argc == 3 && stop)) {
+		fprintf (stderr, "usage: %s <devname> <stop>\n", argv[0]);
+		exit (-1);
+	}
+
+	return init_video (stop);
+}
+
diff --git a/util/Makefile b/util/Makefile
new file mode 100644
index 0000000..6e6daa3
--- /dev/null
+++ b/util/Makefile
@@ -0,0 +1,12 @@
+# Makefile for linuxtv.org dvb-apps/util
+
+%:: FORCE
+	$(MAKE) -C lib $(MAKECMDGOALS)
+	$(MAKE) -C szap $(MAKECMDGOALS)
+	$(MAKE) -C scan $(MAKECMDGOALS)
+	$(MAKE) -C dvbnet $(MAKECMDGOALS)
+	$(MAKE) -C dvbdate $(MAKECMDGOALS)
+	$(MAKE) -C dvbtraffic $(MAKECMDGOALS)
+	$(MAKE) -C av7110_loadkeys $(MAKECMDGOALS)
+
+FORCE:
diff --git a/util/av7110_loadkeys/Makefile b/util/av7110_loadkeys/Makefile
new file mode 100644
index 0000000..e83e069
--- /dev/null
+++ b/util/av7110_loadkeys/Makefile
@@ -0,0 +1,48 @@
+CC = gcc
+CFLAGS = -g -Wall -O2
+
+all: av7110_loadkeys evtest
+
+av7110_loadkeys: av7110_loadkeys.o
+
+evtest: evtest.o
+
+av7110_loadkeys.o: av7110_loadkeys.c input_keynames.h
+
+evtest.o: evtest.c input_keynames.h
+
+
+input_keynames.h: /usr/include/linux/input.h input_fake.h
+	@echo 'generate $@...'
+	@echo '#ifndef __INPUT_KEYNAMES_H__' > $@
+	@echo '#define __INPUT_KEYNAMES_H__' >> $@
+	@echo '' >> $@
+	@echo '#include <linux/input.h>' >> $@
+	@echo '' >> $@
+	@echo '#if !defined(KEY_OK)' >> $@
+	@echo '#include "input_fake.h"' >> $@
+	@echo '#endif' >> $@
+	@echo '' >> $@
+	@echo '' >> $@
+	@echo 'struct input_key_name {' >> $@
+	@echo '        const char *name;' >> $@
+	@echo '        int         key;' >> $@
+	@echo '};' >> $@
+	@echo '' >> $@
+	@echo '' >> $@
+	@echo 'static struct input_key_name key_name [] = {' >> $@
+	@for x in `cat /usr/include/linux/input.h input_fake.h | \
+	          grep KEY_ | grep "#define" | grep -v KEY_MAX | \
+		  cut -f 1 | cut -f 2 -d ' ' | sort | uniq` ; do \
+		echo "        { \"`echo $$x | cut -b 5-`\", $$x }," >> $@ \
+		; \
+	done
+	@echo '};' >> $@
+	@echo '' >> $@
+	@echo '#endif  /* __INPUT_KEYNAMES_H */' >> $@
+	@echo '' >> $@
+
+
+clean:
+	$(RM) core* *.o input_keynames.h av7110_loadkeys evtest
+
diff --git a/util/av7110_loadkeys/README b/util/av7110_loadkeys/README
new file mode 100644
index 0000000..b778e9a
--- /dev/null
+++ b/util/av7110_loadkeys/README
@@ -0,0 +1,64 @@
+Hi,
+
+this is a utility to setup IR control keymaps using the /proc/av7110_ir 
+interface.
+
+just call 
+
+   # ./av7110_loadkeys [-i|--invert] [-a|--address <num>] keymapname.(rc5|rcmm) > /proc/av7110_ir
+
+If your IR receiver hardware inverts the signal, you should use the -i 
+or --invert command line option.
+
+If you have two or more devices which use the same IR protocol, you should
+specify the -a or --address parameter. If the parameter is omitted, the
+driver listens to all device addresses. Some examples:
+
+Listen to *any* IR transmitter with uses the RC5 protocol:
+# ./av7110_loadkeys hauppauge.rc5 > /proc/av7110_ir
+
+Listen to RC5 transmitter with address 2:
+# ./av7110_loadkeys -a 2 hauppauge.rc5 > /proc/av7110_ir
+
+If you don't know the correct value for the -a parameter, take a look
+on the debug output of the driver (see below).
+
+Now you can test your hardware setup using evtest
+
+   # ./evtest /dev/input/eventX
+
+where eventX is the IR input event device, usually event0 if you don't
+use USB mice or keyboards.
+
+------------------------------------------------------------------------
+
+Keymaps are in format:
+
+   <key> <associated input keycode>
+
+   0x00   KEY_0
+   0x01   KEY_1
+   0x42   KEY_HOME
+
+------------------------------------------------------------------------
+
+In order to write a new keymap you might want to see the raw key 
+values in the kernel log. Use
+
+   # insmod dvb-ttpci.o av7110_ir_debug=1
+
+in order to enable some verbosity in the av7110_ir driver. Then watch
+the kernel log while pressing your remote control keys. When you don't see
+any messages in your kernel log you should check all electrical connections,
+the selected protocol (RC5 or RCMM?) and the inversion setting.
+
+You find a list of all linux input key identifiers in </usr/include/input.h> 
+and "./input_fake.h".
+
+Please post new keymaps on the linux-dvb mailing list or send them to 
+me <holger at convergence.de>.
+
+have fun! 
+
+Holger
+
diff --git a/util/av7110_loadkeys/activy.rcmm b/util/av7110_loadkeys/activy.rcmm
new file mode 100644
index 0000000..372df8e
--- /dev/null
+++ b/util/av7110_loadkeys/activy.rcmm
@@ -0,0 +1,54 @@
+0x00 KEY_0
+0x01 KEY_1
+0x02 KEY_2
+0x03 KEY_3
+0x04 KEY_4
+0x05 KEY_5
+0x06 KEY_6
+0x07 KEY_7
+0x08 KEY_8
+0x09 KEY_9
+
+0x0c KEY_POWER
+0x0a KEY_BACK
+
+0xfe KEY_SCROLLUP
+0xff KEY_SCROLLDOWN
+
+0x40 KEY_GOTO
+0x86 KEY_KEYBOARD
+
+0x87 KEY_RED
+0xda KEY_GREEN
+0xf3 KEY_YELLOW
+0x88 KEY_BLUE
+
+0x82 KEY_HOME
+0x54 KEY_MENU
+
+0x58 KEY_UP
+0x59 KEY_DOWN
+0x5a KEY_LEFT
+0x5b KEY_RIGHT
+
+0x5c KEY_OK
+
+0xf0 KEY_CHANNELUP
+0xef KEY_CHANNELDOWN
+
+0x10 KEY_VOLUMEUP
+0x11 KEY_VOLUMEDOWN
+
+0x81 KEY_INFO
+0x0d KEY_MUTE
+
+0x2f KEY_REWIND
+0x2c KEY_PLAYPAUSE
+0x2e KEY_FASTFORWARD
+0x37 KEY_RECORD
+
+0x21 KEY_PREVIOUS
+0x31 KEY_STOP
+0x20 KEY_NEXT
+0x42 KEY_EJECTCD
+
diff --git a/util/av7110_loadkeys/av7110_loadkeys.c b/util/av7110_loadkeys/av7110_loadkeys.c
new file mode 100644
index 0000000..e9eeea0
--- /dev/null
+++ b/util/av7110_loadkeys/av7110_loadkeys.c
@@ -0,0 +1,186 @@
+#include <asm/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "input_keynames.h"
+
+
+static
+void print_error (const char *action, const char *file)
+__attribute__ ((noreturn));
+
+
+static
+void print_error (const char *action, const char *file)
+{
+	static const char msg [] = "\nERROR: could not ";
+
+	write (0, msg, strlen(msg));
+	write (0, action, strlen(action));
+	write (0, " '", 2);
+	write (0, file, strlen(file));
+	write (0, "'\n\n", 3);
+	exit (-1);
+}
+
+
+static
+int parse_keyname (char *pos, char **nend, int limit)
+{
+	int cmp, index;
+	int l = 1;
+	int r = sizeof (key_name) / sizeof (key_name[0]);
+
+	if (limit < 5)
+		return -1;
+
+	while ((*pos == ' ' || *pos == '\t') && limit > 0) {
+		(*nend)++;
+		pos++;
+		limit--;
+	}
+
+	if (pos [0] != 'K' || pos[1] != 'E' || pos[2] != 'Y' || pos[3] != '_')
+		return -2;
+
+	(*nend) += 4;
+	pos += 4;
+	limit -= 4;
+
+	while (r >= l) {
+		int len0, len1 = 0;
+
+		index = (l + r) / 2;
+		
+		len0 = strlen(key_name[index-1].name);
+
+		while (len1 < limit && isgraph(pos[len1]))
+			len1++;
+
+		cmp = strncmp (key_name[index-1].name, pos,
+			       strlen(key_name[index-1].name));
+	
+		if (len0 < len1 && cmp == 0)
+			cmp = -1;
+
+		if (cmp == 0) {
+			*nend = pos + strlen (key_name[index-1].name);
+
+			if (**nend != '\n' &&
+			    **nend != '\t' &&
+			    **nend != ' ' &&
+			    *nend != pos)
+				return -3;
+
+			return key_name[index-1].key;
+		}
+
+		if (cmp < 0)
+			l = index + 1;
+		else
+			r = index - 1;
+
+		if (r < l) {
+			static const char msg [] = "\nunknown key '";
+			write (0, msg, strlen(msg));
+			write (0, pos-4, len1 + 4);
+			write (0, "'\n", 2);
+		}
+	};
+
+	return -4;
+}
+
+
+
+const char usage [] = "\n\tusage: av7110_loadkeys [-i|--invert] [-a|--address <num>] keymap_filename.(rc5|rcmm)\n\n";
+
+
+struct ir_setup {
+	__u32 ir_config;
+	__u16 keytab [256];
+} __attribute__ ((packed));
+
+
+int main (int argc, char **argv)
+{
+	static struct ir_setup setup;
+	int i, fd;
+	size_t len;
+	char *buf, *pos, *fname = NULL;
+
+	for (i=1; i<argc; i++) {
+		if (!strcmp("-i", argv[i]) || !strcmp("--invert", argv[i]))
+			setup.ir_config |= 0x8000;
+		else if (!strcmp("-a", argv[i]) || !strcmp("--address", argv[i])) {
+			if (++i < argc) {
+				setup.ir_config |= (atoi(argv[i]) & 0xff) << 16;
+				setup.ir_config |= 0x4000;
+			}
+		} else
+			fname = argv[i];
+	}
+
+	if (!fname) {
+		write (0, usage, strlen(usage));
+		exit (-1);
+	}
+
+	if (strncmp(".rcmm", fname + strlen(fname) - 5, 5) == 0)
+		setup.ir_config |= 0x0001;
+	else if (strncmp(".rc5", fname + strlen(fname) - 4, 4) != 0) {
+		const char msg [] = "\nERROR: "
+			"input filename must have suffix .rc5 or .rcmm\n";
+		write (0, msg, strlen(msg));
+		exit (-1);
+	}
+
+	if ((fd = open (fname, O_RDONLY)) < 0)
+		print_error ("open", fname);
+
+	len = lseek (fd, 0, SEEK_END);
+
+	if (!(pos = buf = mmap (NULL, len, PROT_READ, MAP_PRIVATE, fd, 0)))
+		print_error ("mmap", fname);
+
+	while (pos < buf + len) {
+		int key, keycode;
+		
+		while (!isxdigit(*pos) && pos < buf + len)
+			pos++;
+
+		if (pos == buf + len)
+			break;
+		
+		key = strtol (pos, &pos, 0);
+		keycode = parse_keyname (pos, &pos, buf + len - pos);
+
+		if (key < 0 || key > 0xff) {
+			const char msg [] = 
+				"\nERROR: key must be in range 0 ... 0xff!\n\n";
+
+			write (0, msg, strlen(msg));
+			exit (-1);
+		}
+
+		if (keycode < 0)
+			print_error ("parse", fname);
+
+		setup.keytab[key] = keycode;
+	}
+	
+	munmap (buf, len);
+	close (fd);
+
+	write (1, &setup, 4 + 256 * sizeof(__u16));
+
+	return 0;
+}
+
+
diff --git a/util/av7110_loadkeys/evtest.c b/util/av7110_loadkeys/evtest.c
new file mode 100644
index 0000000..6714128
--- /dev/null
+++ b/util/av7110_loadkeys/evtest.c
@@ -0,0 +1,177 @@
+/*
+ * $Id: evtest.c,v 1.1 2004/01/17 16:59:46 js Exp $
+ *
+ *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ *  Event device test program
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or 
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * 
+ * Should you need to contact me, the author, you can do so either by
+ * e-mail - mail your message to <vojtech at ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/input.h>
+
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+char *events[EV_MAX + 1] = { "Reset", "Key", "Relative", "Absolute", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+NULL, NULL, NULL, "LED", "Sound", NULL, "Repeat", "ForceFeedback", NULL, "ForceFeedbackStatus"};
+char *keys[KEY_MAX + 1] = { "Reserved", "Esc", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "Minus", "Equal", "Backspace",
+"Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "LeftBrace", "RightBrace", "Enter", "LeftControl", "A", "S", "D", "F", "G",
+"H", "J", "K", "L", "Semicolon", "Apostrophe", "Grave", "LeftShift", "BackSlash", "Z", "X", "C", "V", "B", "N", "M", "Comma", "Dot",
+"Slash", "RightShift", "KPAsterisk", "LeftAlt", "Space", "CapsLock", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10",
+"NumLock", "ScrollLock", "KP7", "KP8", "KP9", "KPMinus", "KP4", "KP5", "KP6", "KPPlus", "KP1", "KP2", "KP3", "KP0", "KPDot", "103rd",
+"F13", "102nd", "F11", "F12", "F14", "F15", "F16", "F17", "F18", "F19", "F20", "KPEnter", "RightCtrl", "KPSlash", "SysRq",
+"RightAlt", "LineFeed", "Home", "Up", "PageUp", "Left", "Right", "End", "Down", "PageDown", "Insert", "Delete", "Macro", "Mute",
+"VolumeDown", "VolumeUp", "Power", "KPEqual", "KPPlusMinus", "Pause", "F21", "F22", "F23", "F24", "KPComma", "LeftMeta", "RightMeta",
+"Compose", "Stop", "Again", "Props", "Undo", "Front", "Copy", "Open", "Paste", "Find", "Cut", "Help", "Menu", "Calc", "Setup",
+"Sleep", "WakeUp", "File", "SendFile", "DeleteFile", "X-fer", "Prog1", "Prog2", "WWW", "MSDOS", "Coffee", "Direction",
+"CycleWindows", "Mail", "Bookmarks", "Computer", "Back", "Forward", "CloseCD", "EjectCD", "EjectCloseCD", "NextSong", "PlayPause",
+"PreviousSong", "StopCD", "Record", "Rewind", "Phone", "ISOKey", "Config", "HomePage", "Refresh", "Exit", "Move", "Edit", "ScrollUp",
+"ScrollDown", "KPLeftParenthesis", "KPRightParenthesis",
+"International1", "International2", "International3", "International4", "International5",
+"International6", "International7", "International8", "International9",
+"Language1", "Language2", "Language3", "Language4", "Language5", "Language6", "Language7", "Language8", "Language9",
+NULL, 
+"PlayCD", "PauseCD", "Prog3", "Prog4", "Suspend", "Close",
+NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+"Btn0", "Btn1", "Btn2", "Btn3", "Btn4", "Btn5", "Btn6", "Btn7", "Btn8", "Btn9",
+NULL, NULL,  NULL, NULL, NULL, NULL,
+"LeftBtn", "RightBtn", "MiddleBtn", "SideBtn", "ExtraBtn", "ForwardBtn", "BackBtn",
+NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+"Trigger", "ThumbBtn", "ThumbBtn2", "TopBtn", "TopBtn2", "PinkieBtn",
+"BaseBtn", "BaseBtn2", "BaseBtn3", "BaseBtn4", "BaseBtn5", "BaseBtn6",
+NULL, NULL, NULL, "BtnDead",
+"BtnA", "BtnB", "BtnC", "BtnX", "BtnY", "BtnZ", "BtnTL", "BtnTR", "BtnTL2", "BtnTR2", "BtnSelect", "BtnStart", "BtnMode",
+"BtnThumbL", "BtnThumbR", NULL,
+"ToolPen", "ToolRubber", "ToolBrush", "ToolPencil", "ToolAirbrush", "ToolFinger", "ToolMouse", "ToolLens", NULL, NULL,
+"Touch", "Stylus", "Stylus2", NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 
+"Ok", "Select", "Goto", "Clear", "Power2", "Option", "Info", "Time", "Vendor",
+"Archive", "Program", "Channel", "Favorites", "EPG", "PVR", "MHP", "Language",
+"Title", "Subtitle", "Angle", "Zoom", "Mode", "Keyboard", "Screen", "PC", "TV",
+"TV2", "VCR", "VCR2", "Sat", "Sat2", "CD", "Tape", "Radio", "Tuner", "Player", 
+"Text", "DVD", "Aux", "MP3", "Audio", "Video", "Directory", "List", "Memo",
+"Calendar", "Red", "Green", "Yellow", "Blue", "ChannelUp", "ChannelDown", 
+"First", "Last", "AB", "Play", "Restart", "Slow", "Shuffle", "FastForward", 
+"Previous", "Next", "Digits", "Teen", "Twen", "Break" };
+
+char *absval[5] = { "Value", "Min  ", "Max  ", "Fuzz ", "Flat " };
+char *relatives[REL_MAX + 1] = { "X", "Y", "Z", NULL, NULL, NULL, "HWheel", "Dial", "Wheel" };
+char *absolutes[ABS_MAX + 1] = { "X", "Y", "Z", "Rx", "Ry", "Rz", "Throttle", "Rudder", "Wheel", "Gas", "Brake",
+NULL, NULL, NULL, NULL, NULL,
+"Hat0X", "Hat0Y", "Hat1X", "Hat1Y", "Hat2X", "Hat2Y", "Hat3X", "Hat 3Y", "Pressure", "Distance", "XTilt", "YTilt"};
+char *leds[LED_MAX + 1] = { "NumLock", "CapsLock", "ScrollLock", "Compose", "Kana", "Sleep", "Suspend", "Mute" };
+char *repeats[REP_MAX + 1] = { "Delay", "Period" };
+char *sounds[SND_MAX + 1] = { "Bell", "Click" };
+
+char **names[EV_MAX + 1] = { events, keys, relatives, absolutes, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+NULL, NULL, leds, sounds, NULL, repeats, NULL, NULL, NULL };
+
+#define BITS_PER_LONG (sizeof(long) * 8)
+#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
+#define OFF(x)  ((x)%BITS_PER_LONG)
+#define BIT(x)  (1UL<<OFF(x))
+#define LONG(x) ((x)/BITS_PER_LONG)
+#define test_bit(bit, array)	((array[LONG(bit)] >> OFF(bit)) & 1)
+
+int main (int argc, char **argv)
+{
+	int fd, rd, i, j, k;
+	struct input_event ev[64];
+	int version;
+	unsigned short id[4];
+	unsigned long bit[EV_MAX][NBITS(KEY_MAX)];
+	char name[256] = "Unknown";
+	int abs[5];
+
+	if (argc < 2) {
+		printf("Usage: evtest /dev/input/eventX\n");
+		printf("Where X = input device number\n");
+		exit(1);
+	}
+
+	if ((fd = open(argv[argc - 1], O_RDONLY)) < 0) {
+		perror("evtest");
+		exit(1);
+	}
+
+	if (ioctl(fd, EVIOCGVERSION, &version)) {
+		perror("evtest: can't get version");
+		exit(1);
+	}
+
+	printf("Input driver version is %d.%d.%d\n",
+		version >> 16, (version >> 8) & 0xff, version & 0xff);
+
+	ioctl(fd, EVIOCGID, id);
+	printf("Input device ID: bus 0x%x vendor 0x%x product 0x%x version 0x%x\n",
+		id[ID_BUS], id[ID_VENDOR], id[ID_PRODUCT], id[ID_VERSION]);
+
+	ioctl(fd, EVIOCGNAME(sizeof(name)), name);
+	printf("Input device name: \"%s\"\n", name);
+
+	memset(bit, 0, sizeof(bit));
+	ioctl(fd, EVIOCGBIT(0, EV_MAX), bit[0]);
+	printf("Supported events:\n");
+
+	for (i = 0; i < EV_MAX; i++)
+		if (test_bit(i, bit[0])) {
+			printf("  Event type %d (%s)\n", i, events[i] ? events[i] : "?");
+			ioctl(fd, EVIOCGBIT(i, KEY_MAX), bit[i]);
+			for (j = 0; j < KEY_MAX; j++) 
+				if (test_bit(j, bit[i])) {
+					printf("    Event code %d (%s)\n", j, names[i] ? (names[i][j] ? names[i][j] : "?") : "?");
+					if (i == EV_ABS) {
+						ioctl(fd, EVIOCGABS(j), abs);
+						for (k = 0; k < 5; k++)
+							if ((k < 3) || abs[k])
+								printf("      %s %6d\n", absval[k], abs[k]);
+					}
+				}
+		}
+		
+
+	printf("Testing ... (interrupt to exit)\n");
+
+	while (1) {
+		rd = read(fd, ev, sizeof(struct input_event) * 64);
+
+		if (rd < (int) sizeof(struct input_event)) {
+			printf("yyy\n");
+			perror("\nevtest: error reading");
+			exit (1);
+		}
+
+		for (i = 0; i < rd / sizeof(struct input_event); i++)
+			printf("Event: time %ld.%06ld, type %d (%s), code %d (%s), value %d\n",
+				ev[i].time.tv_sec, ev[i].time.tv_usec, ev[i].type,
+				events[ev[i].type] ? events[ev[i].type] : "?",
+				ev[i].code,
+				names[ev[i].type] ? (names[ev[i].type][ev[i].code] ? names[ev[i].type][ev[i].code] : "?") : "?",
+				ev[i].value);
+
+	}
+}
+
diff --git a/util/av7110_loadkeys/galaxis.rcmm b/util/av7110_loadkeys/galaxis.rcmm
new file mode 100644
index 0000000..86268e9
--- /dev/null
+++ b/util/av7110_loadkeys/galaxis.rcmm
@@ -0,0 +1,51 @@
+0x00 KEY_0
+0x01 KEY_1
+0x02 KEY_2
+0x03 KEY_3
+0x04 KEY_4
+0x05 KEY_5
+0x06 KEY_6
+0x07 KEY_7
+0x08 KEY_8
+0x09 KEY_9
+
+0x0a KEY_MHP
+0x0c KEY_POWER
+0x0d KEY_MUTE
+0x0f KEY_INFO
+0x10 KEY_VOLUMEUP
+0x11 KEY_VOLUMEDOWN
+0x20 KEY_CHANNELUP
+0x21 KEY_CHANNELDOWN
+0x3c KEY_TEXT
+0x3f KEY_TV
+
+0x45 KEY_SETUP
+0x4b KEY_SUBTITLE
+0x4e KEY_LANGUAGE
+
+0x50 KEY_RADIO
+0x55 KEY_EXIT
+
+0x58 KEY_UP
+0x59 KEY_DOWN
+0x5a KEY_LEFT
+0x5b KEY_RIGHT
+0x5c KEY_OK
+
+0x6d KEY_RED
+0x6e KEY_GREEN
+0x6f KEY_YELLOW
+0x70 KEY_BLUE
+	
+0x78 KEY_MENU
+0x79 KEY_LIST
+0xcc KEY_EPG
+
+0xc4 KEY_UP
+0xc5 KEY_UP
+0xc6 KEY_DOWN
+0xc7 KEY_DOWN
+
+0xff KEY_VCR
+
diff --git a/util/av7110_loadkeys/hauppauge.rc5 b/util/av7110_loadkeys/hauppauge.rc5
new file mode 100644
index 0000000..c9a65b3
--- /dev/null
+++ b/util/av7110_loadkeys/hauppauge.rc5
@@ -0,0 +1,25 @@
+0x00 KEY_0
+0x01 KEY_1
+0x02 KEY_2
+0x03 KEY_3
+0x04 KEY_4
+0x05 KEY_5
+0x06 KEY_6
+0x07 KEY_7
+0x08 KEY_8
+0x09 KEY_9
+
+0x0c KEY_RADIO
+0x0d KEY_MUTE
+0x0f KEY_TV
+
+0x10 KEY_VOLUMEUP
+0x11 KEY_VOLUMEDOWN
+0x1e KEY_VENDOR
+
+0x20 KEY_CHANNELUP
+0x21 KEY_CHANNELDOWN
+0x22 KEY_SELECT
+0x26 KEY_CYCLEWINDOWS
+0x2e KEY_SCREEN
+
diff --git a/util/av7110_loadkeys/hauppauge_grey.rc5 b/util/av7110_loadkeys/hauppauge_grey.rc5
new file mode 100644
index 0000000..ac186dc
--- /dev/null
+++ b/util/av7110_loadkeys/hauppauge_grey.rc5
@@ -0,0 +1,40 @@
+
+0x3d KEY_POWER
+0x3b KEY_GOTO
+
+0x00 KEY_0
+0x01 KEY_1
+0x02 KEY_2
+0x03 KEY_3
+0x04 KEY_4
+0x05 KEY_5
+0x06 KEY_6
+0x07 KEY_7
+0x08 KEY_8
+0x09 KEY_9
+
+0x1f KEY_EXIT
+0x0d KEY_MENU
+
+0x0b KEY_RED
+0x2e KEY_GREEN
+0x38 KEY_YELLOW
+0x29 KEY_BLUE
+
+0x11 KEY_LEFT
+0x10 KEY_RIGHT
+0x20 KEY_UP
+0x21 KEY_DOWN
+0x25 KEY_OK
+
+0x0f KEY_MUTE
+0x0c KEY_INFO
+0x3c KEY_EPG
+0x32 KEY_REWIND
+0x35 KEY_PLAY
+0x34 KEY_FASTFORWARD
+0x37 KEY_RECORD
+0x36 KEY_STOP
+0x30 KEY_PAUSE
+0x24 KEY_PREVIOUS
+0x1e KEY_NEXT
diff --git a/util/av7110_loadkeys/input_fake.h b/util/av7110_loadkeys/input_fake.h
new file mode 100644
index 0000000..7aecc9f
--- /dev/null
+++ b/util/av7110_loadkeys/input_fake.h
@@ -0,0 +1,84 @@
+#ifndef _INPUT_FAKE_H
+#define _INPUT_FAKE_H
+
+#include <linux/input.h>
+
+
+#if !defined(KEY_OK)
+
+/**
+ *  define some additional remote control keys in case they 
+ *  were not already defined above in <linux/input.h>
+ */
+
+#define KEY_OK           0x160
+#define KEY_SELECT       0x161
+#define KEY_GOTO         0x162
+#define KEY_CLEAR        0x163
+#define KEY_POWER2       0x164
+#define KEY_OPTION       0x165
+#define KEY_INFO         0x166
+#define KEY_TIME         0x167
+#define KEY_VENDOR       0x168
+#define KEY_ARCHIVE      0x169
+#define KEY_PROGRAM      0x16a
+#define KEY_CHANNEL      0x16b
+#define KEY_FAVORITES    0x16c
+#define KEY_EPG          0x16d
+#define KEY_PVR          0x16e
+#define KEY_MHP          0x16f
+#define KEY_LANGUAGE     0x170
+#define KEY_TITLE        0x171
+#define KEY_SUBTITLE     0x172
+#define KEY_ANGLE        0x173
+#define KEY_ZOOM         0x174
+#define KEY_MODE         0x175
+#define KEY_KEYBOARD     0x176
+#define KEY_SCREEN       0x177
+#define KEY_PC           0x178
+#define KEY_TV           0x179
+#define KEY_TV2          0x17a
+#define KEY_VCR          0x17b
+#define KEY_VCR2         0x17c
+#define KEY_SAT          0x17d
+#define KEY_SAT2         0x17e
+#define KEY_CD           0x17f
+#define KEY_TAPE         0x180
+#define KEY_RADIO        0x181
+#define KEY_TUNER        0x182
+#define KEY_PLAYER       0x183
+#define KEY_TEXT         0x184
+#define KEY_DVD          0x185
+#define KEY_AUX          0x186
+#define KEY_MP3          0x187
+#define KEY_AUDIO        0x188
+#define KEY_VIDEO        0x189
+#define KEY_DIRECTORY    0x18a
+#define KEY_LIST         0x18b
+#define KEY_MEMO         0x18c
+#define KEY_CALENDAR     0x18d
+#define KEY_RED          0x18e
+#define KEY_GREEN        0x18f
+#define KEY_YELLOW       0x190
+#define KEY_BLUE         0x191
+#define KEY_CHANNELUP    0x192
+#define KEY_CHANNELDOWN  0x193
+#define KEY_FIRST        0x194
+#define KEY_LAST         0x195
+#define KEY_AB           0x196
+#define KEY_PLAY         0x197
+#define KEY_RESTART      0x198
+#define KEY_SLOW         0x199
+#define KEY_SHUFFLE      0x19a
+#define KEY_FASTFORWARD  0x19b
+#define KEY_PREVIOUS     0x19c
+#define KEY_NEXT         0x19d
+#define KEY_DIGITS       0x19e
+#define KEY_TEEN         0x19f
+#define KEY_TWEN         0x1a0
+#define KEY_BREAK        0x1a1
+
+
+#endif  /* !defined(KEY_OK)  */
+#endif  /* _INPUT_FAKE_H */
+
diff --git a/util/av7110_loadkeys/mbo_81095-code_562.rc5 b/util/av7110_loadkeys/mbo_81095-code_562.rc5
new file mode 100644
index 0000000..357e410
--- /dev/null
+++ b/util/av7110_loadkeys/mbo_81095-code_562.rc5
@@ -0,0 +1,39 @@
+0x0c KEY_POWER
+
+0x01 KEY_1
+0x02 KEY_2
+0x03 KEY_3
+0x04 KEY_4
+
+0x05 KEY_5
+0x06 KEY_6
+0x07 KEY_7
+0x08 KEY_8
+
+0x09 KEY_9
+0x00 KEY_0
+0x0a KEY_F11
+0x2b KEY_F12
+
+0x3f KEY_PROGRAM
+0x23 KEY_CONFIG
+0x0d KEY_MUTE
+
+0x11 KEY_VOLUMEDOWN
+0x10 KEY_VOLUMEUP
+0x20 KEY_CHANNELUP
+0x21 KEY_CHANNELDOWN
+0x29 KEY_TV
+
+0x1a KEY_RED
+0x1b KEY_GREEN
+0x2e KEY_YELLOW
+0x24 KEY_BLUE
+
+0x32 KEY_REWIND
+0x35 KEY_PLAY
+0x34 KEY_FORWARD
+0x37 KEY_RECORD
+
+0x36 KEY_STOP
+0x30 KEY_PAUSE
diff --git a/util/av7110_loadkeys/medion_088.rc5 b/util/av7110_loadkeys/medion_088.rc5
new file mode 100644
index 0000000..ebec3fe
--- /dev/null
+++ b/util/av7110_loadkeys/medion_088.rc5
@@ -0,0 +1,36 @@
+0x00 KEY_0
+0x01 KEY_1
+0x02 KEY_2
+0x03 KEY_3
+0x04 KEY_4
+0x05 KEY_5
+0x06 KEY_6
+0x07 KEY_7
+0x08 KEY_8
+0x09 KEY_9
+
+0x0b KEY_BACK
+0x0c KEY_POWER
+0x0d KEY_MUTE
+0x0e KEY_MENU
+0x0f KEY_TV
+
+0x10 KEY_VOLUMEUP
+0x11 KEY_VOLUMEDOWN
+0x12 KEY_UP
+0x13 KEY_DOWN
+0x14 KEY_RIGHT
+0x15 KEY_LEFT
+0x1e KEY_VENDOR
+
+0x20 KEY_CHANNELUP
+0x21 KEY_CHANNELDOWN
+0x22 KEY_SELECT
+0x23 KEY_OK
+0x26 KEY_CYCLEWINDOWS
+0x2e KEY_SCREEN
+
+0x37 KEY_RED
+0x36 KEY_GREEN
+0x34 KEY_BLUE
+0x32 KEY_YELLOW
diff --git a/util/av7110_loadkeys/medion_155.rc5 b/util/av7110_loadkeys/medion_155.rc5
new file mode 100644
index 0000000..416bbd9
--- /dev/null
+++ b/util/av7110_loadkeys/medion_155.rc5
@@ -0,0 +1,35 @@
+0x00 KEY_0
+0x01 KEY_1
+0x02 KEY_2
+0x03 KEY_3
+0x04 KEY_4
+0x05 KEY_5
+0x06 KEY_6
+0x07 KEY_7
+0x08 KEY_8
+0x09 KEY_9
+
+0x35 KEY_BACK
+0x0c KEY_POWER
+0x0d KEY_MUTE
+0x3f KEY_MENU
+0x0f KEY_TV
+
+0x10 KEY_VOLUMEUP
+0x11 KEY_VOLUMEDOWN
+0x12 KEY_UP
+0x13 KEY_DOWN
+0x14 KEY_RIGHT
+0x15 KEY_LEFT
+
+0x0a KEY_CHANNELUP
+0x0b KEY_CHANNELDOWN
+0x22 KEY_SELECT
+0x23 KEY_OK
+0x26 KEY_CYCLEWINDOWS
+0x2e KEY_SCREEN
+
+0x37 KEY_RED
+0x36 KEY_GREEN
+0x34 KEY_BLUE
+0x32 KEY_YELLOW
diff --git a/util/av7110_loadkeys/philips.rc5 b/util/av7110_loadkeys/philips.rc5
new file mode 100644
index 0000000..68bc85d
--- /dev/null
+++ b/util/av7110_loadkeys/philips.rc5
@@ -0,0 +1,32 @@
+0x00 KEY_0
+0x01 KEY_1
+0x02 KEY_2
+0x03 KEY_3
+0x04 KEY_4
+0x05 KEY_5
+0x06 KEY_6
+0x07 KEY_7
+0x08 KEY_8
+0x09 KEY_9
+
+0x0b KEY_MENU
+0x0c KEY_POWER
+0x0d KEY_MUTE
+0x0e KEY_OK
+0x0f KEY_MINUS
+0x10 KEY_VOLUMEUP
+0x11 KEY_VOLUMEDOWN
+
+0x20 KEY_CHANNELUP
+0x21 KEY_CHANNELDOWN
+0x26 KEY_INFO
+0x2d KEY_ZOOM
+0x2e KEY_CYCLEWINDOWS
+
+0x32 KEY_PLAY
+0x34 KEY_FORWARD
+0x36 KEY_STOP
+0x37 KEY_REWIND
+0x38 KEY_AUX
+0x3c KEY_TEXT
+0x3f KEY_SCREEN
diff --git a/util/av7110_loadkeys/philips1358.rc5 b/util/av7110_loadkeys/philips1358.rc5
new file mode 100644
index 0000000..e30efba
--- /dev/null
+++ b/util/av7110_loadkeys/philips1358.rc5
@@ -0,0 +1,37 @@
+0x00 KEY_0
+0x01 KEY_1
+0x02 KEY_2
+0x03 KEY_3
+0x04 KEY_4
+0x05 KEY_5
+0x06 KEY_6
+0x07 KEY_7
+0x08 KEY_8
+0x09 KEY_9
+0x0C KEY_POWER
+0x0D KEY_MUTE
+0x0E KEY_OK
+0x0F KEY_DIGITS
+0x10 KEY_RIGHT
+0x11 KEY_LEFT
+0x1E KEY_STOP
+0x20 KEY_UP
+0x21 KEY_DOWN
+0x23 KEY_AB
+0x24 KEY_RECORD
+0x25 KEY_SUBTITLE
+0x26 KEY_INFO
+0x29 KEY_PLAY
+0x2A KEY_FORWARD
+0x2B KEY_PAUSE
+0x2C KEY_REWIND
+0x2D KEY_F4
+0x2E KEY_F3 
+0x32 KEY_YELLOW
+0x34 KEY_BLUE
+0x36 KEY_GREEN
+0x37 KEY_RED
+0x38 KEY_AUX
+0x3C KEY_F2 
+0x3D KEY_SCREEN
+0x3F KEY_F1 
\ No newline at end of file
diff --git a/util/dvbdate/Makefile b/util/dvbdate/Makefile
new file mode 100644
index 0000000..ea514db
--- /dev/null
+++ b/util/dvbdate/Makefile
@@ -0,0 +1,25 @@
+
+CC      = gcc
+CFLAGS  = -g -O2 -MD -Wall -I. -I../../include
+LFLAGS  =
+
+OBJS    = dvbdate.o
+TARGET  = dvbdate
+DESTDIR = /usr/local/bin/
+
+all: $(TARGET)
+
+.c.o:
+	$(CC) $(CFLAGS) -c $< -o $@
+
+$(TARGET): $(OBJS)
+	$(CC) -o $@ $(OBJS) $(LFLAGS)
+
+install: all
+	install -m 755 $(TARGET) $(DESTDIR) 
+
+clean:
+	rm -f $(TARGET) $(OBJS) core* *~ *.d
+
+-include $(wildcard *.d) dummy
+
diff --git a/util/dvbdate/dvbdate.c b/util/dvbdate/dvbdate.c
new file mode 100644
index 0000000..9821012
--- /dev/null
+++ b/util/dvbdate/dvbdate.c
@@ -0,0 +1,346 @@
+/*
+
+   dvbdate - a program to set the system date and time from a TDT multiplex
+
+   Copyright (C) Laurence Culhane 2002 <dvbdate at holmes.demon.co.uk>
+
+   Mercilessly ripped off from dvbtune, Copyright (C) Dave Chapman 2001
+
+   Revamped by Johannes Stezenbach <js at convergence.de>
+   and Michael Hunold <hunold at convergence.de>
+  
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License
+   as published by the Free Software Foundation; either version 2
+   of the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+   Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+
+   Copyright (C) Laurence Culhane 2002 <dvbdate at holmes.demon.co.uk>
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <errno.h>
+#include <getopt.h>
+#include <stdarg.h>
+
+#include <linux/dvb/dmx.h>
+
+#define bcdtoint(i) ((((i & 0xf0) >> 4) * 10) + (i & 0x0f))
+
+/* How many seconds can the system clock be out before we get warned? */
+#define ALLOWABLE_DELTA 30*60
+
+char *ProgName;
+int do_print;
+int do_set;
+int do_force;
+int do_quiet;
+int timeout = 25;
+
+void errmsg(char *message, ...)
+{
+	va_list ap;
+
+	va_start(ap, message);
+	fprintf(stderr, "%s: ", ProgName);
+	vfprintf(stderr, message, ap);
+	va_end(ap);
+}
+
+void usage()
+{
+	fprintf(stderr, "usage: %s [-p] [-s] [-f] [-q] [-h]\n", ProgName);
+	_exit(1);
+}
+
+void help()
+{
+	fprintf(stderr, "\nhelp:\n" "%s [-p] [-s] [-f] [-q] [-h] [-t n]\n" "  --print	(print current time, TDT time and delta)\n" "  --set	(set the system clock to TDT time)\n" "  --force	(force the setting of the clock)\n" "  --quiet	(be silent)\n" "  --help	(display this message)\n""  --timout n	(max seconds to wait, default: 25)\n", ProgName);
+	_exit(1);
+}
+
+int do_options(int arg_count, char **arg_strings)
+{
+	static struct option Long_Options[] = {
+		{"print", 0, 0, 'p'},
+		{"set", 0, 0, 's'},
+		{"force", 0, 0, 'f'},
+		{"quiet", 0, 0, 'q'},
+		{"help", 0, 0, 'h'},
+		{"timeout", 1, 0, 't'},
+		{0, 0, 0, 0}
+	};
+	int c;
+	int Option_Index = 0;
+
+	while (1) {
+		c = getopt_long(arg_count, arg_strings, "psfqht:", Long_Options, &Option_Index);
+		if (c == EOF)
+			break;
+		switch (c) {
+		case 't':
+			timeout = atoi(optarg);
+			if (0 == timeout) {
+				fprintf(stderr, "%s: invalid timeout value\n", ProgName);
+				usage();
+			}
+			break;
+		case 'p':
+			do_print = 1;
+			break;
+		case 's':
+			do_set = 1;
+			break;
+		case 'f':
+			do_force = 1;
+			break;
+		case 'q':
+			do_quiet = 1;
+			break;
+		case 'h':
+			help();
+			break;
+		case '?':
+			usage();
+			break;
+		case 0:
+/*
+ * Which long option has been selected?  We only need this extra switch
+ * to cope with the case of wanting to assign two long options the same
+ * short character code.
+ */
+			printf("long option index %d\n", Option_Index);
+			switch (Option_Index) {
+			case 0:	/* Print */
+			case 1:	/* Set */
+			case 2:	/* Force */
+			case 3:	/* Quiet */
+			case 4:	/* Help */
+			case 5:	/* timout */
+				break;
+			default:
+				fprintf(stderr, "%s: unknown long option %d\n", ProgName, Option_Index);
+				usage();
+			}
+			break;
+/*
+ * End of Special Long-opt handling code
+ */
+		default:
+			fprintf(stderr, "%s: unknown getopt error - returned code %02x\n", ProgName, c);
+			_exit(1);
+		}
+	}
+	return 0;
+}
+
+/*
+ * return the TDT time in UNIX time_t format
+ */
+
+time_t convert_date(char *dvb_buf)
+{
+	int i;
+	int year, month, day, hour, min, sec;
+	long int mjd;
+	struct tm dvb_time;
+
+	mjd = (dvb_buf[0] & 0xff) << 8;
+	mjd += (dvb_buf[1] & 0xff);
+	hour = bcdtoint(dvb_buf[2] & 0xff);
+	min = bcdtoint(dvb_buf[3] & 0xff);
+	sec = bcdtoint(dvb_buf[4] & 0xff);
+/*
+ * Use the routine specified in ETSI EN 300 468 V1.4.1,
+ * "Specification for Service Information in Digital Video Broadcasting"
+ * to convert from Modified Julian Date to Year, Month, Day.
+ */
+	year = (int) ((mjd - 15078.2) / 365.25);
+	month = (int) ((mjd - 14956.1 - (int) (year * 365.25)) / 30.6001);
+	day = mjd - 14956 - (int) (year * 365.25) - (int) (month * 30.6001);
+	if (month == 14 || month == 15)
+		i = 1;
+	else
+		i = 0;
+	year += i;
+	month = month - 1 - i * 12;
+
+	dvb_time.tm_sec = sec;
+	dvb_time.tm_min = min;
+	dvb_time.tm_hour = hour;
+	dvb_time.tm_mday = day;
+	dvb_time.tm_mon = month - 1;
+	dvb_time.tm_year = year;
+	dvb_time.tm_isdst = -1;
+	dvb_time.tm_wday = 0;
+	dvb_time.tm_yday = 0;
+	return (timegm(&dvb_time));
+}
+
+
+/*
+ * Get the next UTC date packet from the TDT multiplex
+ */
+
+int scan_date(time_t *dvb_time, unsigned int to)
+{
+	int fd_date;
+	int n, seclen;
+	time_t t;
+	unsigned char buf[4096];
+	struct dmx_sct_filter_params sctFilterParams;
+	struct pollfd ufd;
+	int found = 0;
+	
+	t = 0;
+	if ((fd_date = open("/dev/dvb/adapter0/demux0", O_RDWR | O_NONBLOCK)) < 0) {
+		perror("fd_date DEVICE: ");
+		return -1;
+	}
+
+	memset(&sctFilterParams, 0, sizeof(sctFilterParams));
+	sctFilterParams.pid = 0x14;
+	sctFilterParams.timeout = 0;
+	sctFilterParams.flags = DMX_IMMEDIATE_START;
+	sctFilterParams.filter.filter[0] = 0x70;
+	sctFilterParams.filter.mask[0] = 0xff;
+
+	if (ioctl(fd_date, DMX_SET_FILTER, &sctFilterParams) < 0) {
+		perror("DATE - DMX_SET_FILTER:");
+		close(fd_date);
+		return -1;
+	}
+
+	while (to > 0) {
+		int res;
+
+		memset(&ufd,0,sizeof(ufd));
+		ufd.fd=fd_date;
+		ufd.events=POLLIN;
+
+		res = poll(&ufd,1,1000);
+		if (0 == res) {
+			fprintf(stdout, ".");
+			fflush(stdout);
+			to--;
+			continue;
+  		}
+		if (1 == res) {
+			found = 1;
+			break;
+		}
+		errmsg("error polling for data");
+		close(fd_date);
+		return -1;
+	}
+	fprintf(stdout, "\n");
+	if (0 == found) {
+		errmsg("timeout - try tuning to a multiplex?\n");
+		close(fd_date);
+		return -1;
+	}
+
+	if ((n = read(fd_date, buf, 4096)) >= 3) {
+		seclen = ((buf[1] & 0x0f) << 8) | (buf[2] & 0xff);
+		if (n == seclen + 3) {
+			t = convert_date(&(buf[3]));
+		} else {
+			errmsg("Under-read bytes for DATE - wanted %d, got %d\n", seclen, n);
+			return 0;
+		}
+	} else {
+		errmsg("Nothing to read from fd_date - try tuning to a multiplex?\n");
+		return 0;
+	}
+	close(fd_date);
+	*dvb_time = t;
+	return 0;
+}
+
+
+/*
+ * Set the system time
+ */
+int set_time(time_t * new_time)
+{
+	if (stime(new_time)) {
+		perror("Unable to set time");
+		return -1;
+	}
+	return 0;
+}
+
+
+int main(int argc, char **argv)
+{
+	time_t dvb_time;
+	time_t real_time;
+	time_t offset;
+	int ret;
+
+	do_print = 0;
+	do_force = 0;
+	do_set = 0;
+	do_quiet = 0;
+	ProgName = argv[0];
+
+/*
+ * Process command line arguments
+ */
+	do_options(argc, argv);
+	if (do_quiet && do_print) {
+		errmsg("quiet and print options are mutually exclusive.\n");
+		exit(1);
+	}
+/*
+ * Get the date from the currently tuned TDT multiplex
+ */
+	ret = scan_date(&dvb_time, timeout);
+	if (ret != 0) {
+		errmsg("Unable to get time from multiplex.\n");
+		exit(1);
+	}
+	time(&real_time);
+	offset = dvb_time - real_time;
+	if (do_print) {
+		fprintf(stdout, "System time: %s", ctime(&real_time));
+		fprintf(stdout, "   TDT time: %s", ctime(&dvb_time));
+		fprintf(stdout, "     Offset: %ld seconds\n", offset);
+	} else if (!do_quiet) {
+		fprintf(stdout, "%s", ctime(&dvb_time));
+	}
+	if (do_set) {
+		if (labs(offset) > ALLOWABLE_DELTA) {
+			if (do_force) {
+				if (0 != set_time(&dvb_time)) {
+					errmsg("setting the time failed\n");
+				}
+			} else {
+				errmsg("multiplex time differs by more than %d from system.\n", ALLOWABLE_DELTA);
+				errmsg("use -f to force system clock to new time.\n");
+				exit(1);
+			}
+		} else {
+			set_time(&dvb_time);
+		}
+	}			/* #end if (do_set) */
+	return (0);
+}
diff --git a/util/dvbnet/Makefile b/util/dvbnet/Makefile
new file mode 100644
index 0000000..187dee2
--- /dev/null
+++ b/util/dvbnet/Makefile
@@ -0,0 +1,29 @@
+
+CC      = gcc
+CFLAGS  = -g -O2 -MD -Wall -I. -I../../include
+LFLAGS  =
+
+OBJS    = dvbnet.o
+TARGET  = dvbnet
+DESTDIR = /usr/local/bin/
+
+all: version.h $(TARGET)
+
+.c.o:
+	$(CC) $(CFLAGS) -c $< -o $@
+
+$(TARGET): $(OBJS)
+	$(CC) -o $@ $(OBJS) $(LFLAGS)
+
+version.h:
+	printf '#define VERSION_INFO "%s (Build %s)"\n' \
+		"`cat $@.in`" "`date +'%a %b %d %X %Y'`" > $@
+
+install: all
+	install -m 755 $(TARGET) $(DESTDIR) 
+
+clean:
+	rm -f $(TARGET) $(OBJS) version.h core* *~ *.d
+
+-include $(wildcard *.d) dummy
+
diff --git a/util/dvbnet/dvbnet.c b/util/dvbnet/dvbnet.c
new file mode 100644
index 0000000..573fa59
--- /dev/null
+++ b/util/dvbnet/dvbnet.c
@@ -0,0 +1,205 @@
+/* 
+ * dvbnet.c
+ *
+ * Copyright (C) 2003 TV Files S.p.A
+ *                    L.Y.Mesentsev <lymes at tiscalinet.it>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * 
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ * 
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+
+#include <linux/dvb/net.h>
+#include <version.h>
+
+#ifndef VERSION_INFO
+#define VERSION_INFO "1.1.0"
+#endif
+
+#define OK    0
+#define FAIL -1
+#define DVB_NET_DEVICE "/dev/dvb/adapter%d/net%d"
+#define DVB_NET_DEVICES_MAX 10
+#define IFNAME_DVB "dvb"
+
+
+enum Mode {
+	UNKNOWN,
+	LST_INTERFACE,
+	ADD_INTERFACE,
+	DEL_INTERFACE
+} op_mode;
+
+static int adapter = 0;
+static int netdev = 0;
+static struct dvb_net_if net_data;
+
+static void hello(void);
+static void usage(char *);
+static void parse_args(int, char **);
+static int queryInterface(int, int);
+
+static char dvb_net_device[40];
+
+int main(int argc, char **argv)
+{
+	int fd_net;
+
+	hello();
+
+	parse_args(argc, argv);
+
+	sprintf(dvb_net_device, DVB_NET_DEVICE, adapter, netdev);
+
+	printf("Device: %s\n", dvb_net_device);
+
+	if ((fd_net = open(dvb_net_device, O_RDWR | O_NONBLOCK)) < 0) {
+		fprintf(stderr, "Error: couldn't open device %s: %d %m\n",
+			dvb_net_device, errno);
+		return FAIL;
+	}
+
+	switch (op_mode) {
+	case DEL_INTERFACE:
+		if (ioctl(fd_net, NET_REMOVE_IF, net_data.if_num))
+			fprintf(stderr,
+				"Error: couldn't remove interface %d: %d %m.\n",
+				net_data.if_num, errno);
+		else
+			printf("Status: device %d removed successfully.\n",
+			       net_data.if_num);
+		break;
+
+	case ADD_INTERFACE:
+		if (ioctl(fd_net, NET_ADD_IF, &net_data))
+			fprintf(stderr,
+				"Error: couldn't add interface for pid %d: %d %m.\n",
+				net_data.pid, errno);
+		else
+			printf
+			    ("Status: device dvb%d_%d for pid %d created successfully.\n",
+			     adapter, net_data.if_num, net_data.pid);
+		break;
+
+	case LST_INTERFACE:
+		queryInterface(fd_net, 0);
+		break;
+
+	default:
+		usage(argv[0]);
+		return FAIL;
+	}
+
+	close(fd_net);
+	return OK;
+}
+
+
+int queryInterface(int fd_net, int dev)
+{
+	struct dvb_net_if data;
+	int IF, nIFaces = 0, ret = FAIL;
+
+	printf("Query DVB network interfaces:\n");
+	printf("-----------------------------\n");
+	for (IF = 0; IF < DVB_NET_DEVICES_MAX; IF++) {
+		data.if_num = IF;
+		if (ioctl(fd_net, NET_GET_IF, &data))
+			continue;
+
+		if (dev == data.if_num)
+			ret = OK;
+
+		printf("Found device %d: interface dvb%d_%d, "
+		       "listening on PID %d\n",
+		       IF, adapter, data.if_num, data.pid);
+
+		nIFaces++;
+	}
+
+	printf("-----------------------------\n");
+	printf("Found %d interface(s).\n\n", nIFaces);
+	return ret;
+}
+
+
+void parse_args(int argc, char **argv)
+{
+	char c, *s;
+	op_mode = UNKNOWN;
+	while ((c = getopt(argc, argv, "a:n:p:d:lvh")) != EOF) {
+		switch (c) {
+		case 'a':
+			adapter = strtol(optarg, NULL, 0);
+			break;
+		case 'n':
+			netdev = strtol(optarg, NULL, 0);
+			break;
+		case 'p':
+			net_data.pid = strtol(optarg, NULL, 0);
+			op_mode = ADD_INTERFACE;
+			break;
+		case 'd':
+			net_data.if_num = strtol(optarg, NULL, 0);
+			op_mode = DEL_INTERFACE;
+			break;
+		case 'l':
+			op_mode = LST_INTERFACE;
+			break;
+		case 'v':
+			exit(OK);
+		case 'h':
+		default:
+			s = strrchr(argv[0], '/') + 1;
+			usage((s) ? s : argv[0]);
+			exit(FAIL);
+		}
+	}
+}
+
+
+void usage(char *prog_name)
+{
+	fprintf(stderr, "Usage: %s [options]\n", prog_name);
+	fprintf(stderr, "Where options are:\n");
+	fprintf(stderr, "\t-a AD  : Adapter card AD (default 0)\n");
+	fprintf(stderr, "\t-n NET : Net demux NET (default 0)\n");
+	fprintf(stderr, "\t-p PID : Add interface listening on PID\n");
+	fprintf(stderr, "\t-d NUM : Remove interface dvbAD_NUM\n");
+	fprintf(stderr,
+		"\t-l     : List currently available interfaces\n");
+	fprintf(stderr, "\t-v     : Print current version\n\n");
+}
+
+
+void hello(void)
+{
+	printf("\nDVB Network Interface Manager\n");
+	printf("Version %s\n", VERSION_INFO);
+	printf("Copyright (C) 2003, TV Files S.p.A\n\n");
+}
diff --git a/util/dvbnet/net_start.pl b/util/dvbnet/net_start.pl
new file mode 100755
index 0000000..71e6367
--- /dev/null
+++ b/util/dvbnet/net_start.pl
@@ -0,0 +1,25 @@
+#!/usr/bin/perl
+
+$ADAPTER = 0;
+
+&dvbnet($ADAPTER, 0,  512, "192.168.11.1");
+&dvbnet($ADAPTER, 0, 2000, "192.168.21.1");
+
+
+# &dvbnet(adapter,netdev,pid,"ip_addr");
+
+sub dvbnet
+{
+  local ($ADAPTER, $NETDEV, $PID, $IP_ADDR) = @_;
+
+  $DEV_NAME = `./dvbnet -a $ADAPTER -n $NETDEV -p $PID | grep created`;
+  chop($DEV_NAME);
+
+  $DEV_NAME =~ s/(.*)device //;
+  $DEV_NAME =~ s/for (.*)//;
+
+  $X = `/sbin/ifconfig $DEV_NAME $IP_ADDR netmask 255.255.255.0`;
+
+  system("/sbin/ifconfig $DEV_NAME");
+}
+
diff --git a/util/dvbnet/net_start.sh b/util/dvbnet/net_start.sh
new file mode 100755
index 0000000..b155989
--- /dev/null
+++ b/util/dvbnet/net_start.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+PID=0x511
+DEV_NAME=dvb0_0
+IP_ADDR=10.1.1.1
+
+./dvbnet -p $PID
+
+/sbin/ifconfig $DEV_NAME $IP_ADDR
+
+#
+#  you can reconfigure the MAC adress like this:
+#
+#MAC_ADDR=00:01:02:03:04:05
+#/sbin/ifconfig $DEV_NAME hw ether $MAC_ADDR
diff --git a/util/dvbnet/version.h.in b/util/dvbnet/version.h.in
new file mode 100644
index 0000000..d0a6e20
--- /dev/null
+++ b/util/dvbnet/version.h.in
@@ -0,0 +1 @@
+1.1.0-TVF
diff --git a/util/dvbtraffic/Makefile b/util/dvbtraffic/Makefile
new file mode 100644
index 0000000..c29be40
--- /dev/null
+++ b/util/dvbtraffic/Makefile
@@ -0,0 +1,6 @@
+
+dvbtraffic: dvbtraffic.c
+	gcc -MD -g -O2 -Wall -I../../include $< -o $@
+
+clean:
+	rm -f *.o *.d dvbtraffic
diff --git a/util/dvbtraffic/dvbtraffic.c b/util/dvbtraffic/dvbtraffic.c
new file mode 100644
index 0000000..8add053
--- /dev/null
+++ b/util/dvbtraffic/dvbtraffic.c
@@ -0,0 +1,130 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/poll.h>
+#include <sys/time.h>
+#include <string.h>
+
+#include <linux/dvb/dmx.h>
+#include <linux/dvb/frontend.h>
+#include <linux/dvb/video.h>
+
+#define BSIZE 188
+
+int pidt[0x2001];
+
+int main(int argc, char **argv)
+{
+	int fd, ffd, packets = 0;
+	struct timeval startt;
+	struct dmx_pes_filter_params flt;
+	char *search;
+	unsigned char buffer[BSIZE];
+
+	fd = open("/dev/dvb/adapter0/dvr0", O_RDONLY);
+
+	ioctl(fd, DMX_SET_BUFFER_SIZE, 1024 * 1024);
+
+	ffd = open("/dev/dvb/adapter0/demux0", O_RDWR);
+	if (ffd < 0) {
+		perror("/dev/dvb/adapter0/demux0");
+		return -fd;
+	}
+
+	flt.pid = 0x2000;
+	flt.input = DMX_IN_FRONTEND;
+	flt.output = DMX_OUT_TS_TAP;
+	flt.pes_type = DMX_PES_OTHER;
+	flt.flags = 0;
+
+	if (ioctl(ffd, DMX_SET_PES_FILTER, &flt) < 0) {
+		perror("DMX_SET_PES_FILTER");
+		return -1;
+	}
+
+	if (ioctl(ffd, DMX_START, 0) < 0) {
+		perror("DMX_SET_PES_FILTER");
+		return -1;
+	}
+
+	gettimeofday(&startt, 0);
+
+	if (argc > 1)
+		search = argv[1];
+	else
+		search = 0;
+
+	while (1) {
+		int pid, r, ok;
+		if ((r = read(fd, buffer, 188)) <= 0) {
+			perror("read");
+			break;
+		}
+		if (r != 188) {
+			printf("only read %d\n", r);
+			break;
+		}
+		if (buffer[0] != 0x47) {
+			continue;
+			printf("desync (%x)\n", buffer[0]);
+			while (buffer[0] != 0x47)
+				read(fd, buffer, 1);
+			continue;
+		}
+		ok = 1;
+		pid = ((((unsigned) buffer[1]) << 8) |
+		       ((unsigned) buffer[2])) & 0x1FFF;
+
+		if (search) {
+			int i, sl = strlen(search);
+			ok = 0;
+			if (pid != 0x1fff) {
+				for (i = 0; i < (188 - sl); ++i) {
+					if (!memcmp(buffer + i, search, sl))
+						ok = 1;
+				}
+			}
+		}
+
+		if (ok) {
+			pidt[pid]++;
+			pidt[0x2000]++;
+		}
+
+		packets++;
+
+		if (!(packets & 0xFF)) {
+			struct timeval now;
+			int diff;
+			gettimeofday(&now, 0);
+			diff =
+			    (now.tv_sec - startt.tv_sec) * 1000 +
+			    (now.tv_usec - startt.tv_usec) / 1000;
+			if (diff > 1000) {
+				int pid = 0;
+				for (pid = 0; pid < 0x2001; pid++) {
+					if (pidt[pid]) {
+						printf("%04x %5d p/s %5d kb/s %5d kbit\n",
+						     pid,
+						     pidt[pid] * 1000 / diff,
+						     pidt[pid] * 1000 / diff * 188 / 1024,
+						     pidt[pid] * 8 * 1000 / diff * 188 / 1000);
+					}
+					pidt[pid] = 0;
+				}
+				printf("-PID--FREQ-----BANDWIDTH-BANDWIDTH-\n");
+				startt = now;
+			}
+		}
+	}
+
+	close(ffd);
+	close(fd);
+	return 0;
+}
+
diff --git a/util/lib/Makefile b/util/lib/Makefile
new file mode 100644
index 0000000..5f55636
--- /dev/null
+++ b/util/lib/Makefile
@@ -0,0 +1,20 @@
+
+CC = gcc
+CFLAGS = -MD -g -Wall -O2 -I../../include -I.
+LFLAGS = -g -Wall
+
+OBJS = lnb.o
+SRCS = $(OBJS:.o=.c)
+
+TARGET = lnb.o
+
+$(TARGET): $(SRCS)
+
+.c.o:
+	$(CC) $(CFLAGS) -c $< -o $@
+
+clean:
+	$(RM) *.o *.d $(TARGET)
+
+-include $(wildcard *.d) dummy
+
diff --git a/util/lib/lnb.c b/util/lib/lnb.c
new file mode 100644
index 0000000..d082181
--- /dev/null
+++ b/util/lib/lnb.c
@@ -0,0 +1,101 @@
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "lnb.h"
+
+static char *univ_desc[] = {
+		"Europe",
+		"10800 to 11800 MHz and 11600 to 12700 Mhz",
+		"Dual LO, loband 9750, hiband 10600 MHz",
+		(char *)NULL };
+
+static char *dbs_desc[] = {
+		"Expressvu, North America",
+		"12200 to 12700 MHz",
+		"Single LO, 11250 MHz",	
+		(char *)NULL };
+
+static char *standard_desc[] = {
+		"10945 to 11450 Mhz",
+		"Single LO, 10000 Mhz",
+		(char *)NULL };
+
+static char *enhan_desc[] = {
+		"Astra",
+		"10700 to 11700 MHz",
+		"Single LO, 9750 MHz",
+		(char *)NULL };
+
+static char *cband_desc[] = {
+		"Big Dish",
+		"3700 to 4200 MHz",
+		"Single LO, 5150 Mhz",
+		(char *)NULL };
+
+static struct lnb_types_st lnbs[] = {
+	{"UNIVERSAL",	univ_desc,		9750, 10600, 11700 },
+ 	{"DBS",		dbs_desc, 		11250, 0, 0 },
+	{"STANDARD",	standard_desc,		10000, 0, 0 },
+	{"ENHANCED",	enhan_desc,		9750, 0, 0 },
+	{"C-BAND",	cband_desc,		5150, 0, 0 }
+};
+
+/* Enumerate through standard types of LNB's until NULL returned.
+ * Increment curno each time
+ */
+
+struct lnb_types_st *
+lnb_enum(int curno)
+{
+	if (curno >= sizeof(lnbs) / sizeof(lnbs[0]))
+		return (struct lnb_types_st *)NULL;
+	return &lnbs[curno];
+}
+
+/* Decode an lnb type, for example given on a command line
+ * If alpha and standard type, e.g. "Universal" then match that
+ * otherwise low[,high[,switch]]
+ */
+
+int
+lnb_decode(char *str, struct lnb_types_st *lnbp)
+{
+int i;
+char *cp, *np;
+
+	memset(lnbp, 0, sizeof(*lnbp));
+	cp = str;
+	while(*cp && isspace(*cp))
+		cp++;
+	if (isalpha(*cp)) {
+		for(i = 0; i < (sizeof(lnbs) / sizeof(lnbs[0])); i++) {
+			if (!strcasecmp(lnbs[i].name, cp)) {
+				*lnbp = lnbs[i];
+				return 1;
+			}
+		}
+		return -1;
+	}
+	if (*cp == '\0' || !isdigit(*cp))
+		return -1;
+	lnbp->low_val = strtoul(cp, &np, 0);
+	if (lnbp->low_val == 0)
+		return -1;
+	cp = np;
+	while(*cp && (isspace(*cp) || *cp == ','))
+		cp++;
+	if (*cp == '\0')
+		return 1;
+	if (!isdigit(*cp))
+		return -1;
+	lnbp->high_val = strtoul(cp, &np, 0);
+	cp = np;
+	while(*cp && (isspace(*cp) || *cp == ','))
+		cp++;
+	if (*cp == '\0')
+		return 1;
+	if (!isdigit(*cp))
+		return -1;
+	lnbp->switch_val = strtoul(cp, NULL, 0);
+	return 1;
+}
diff --git a/util/lib/lnb.h b/util/lib/lnb.h
new file mode 100644
index 0000000..f78b7a6
--- /dev/null
+++ b/util/lib/lnb.h
@@ -0,0 +1,24 @@
+
+struct lnb_types_st {
+	char	*name;
+	char	**desc;
+	unsigned long	low_val;
+	unsigned long	high_val;	/* zero indicates no hiband */
+	unsigned long	switch_val;	/* zero indicates no hiband */
+};
+
+/* Enumerate through standard types of LNB's until NULL returned.
+ * Increment curno each time
+ */
+
+struct lnb_types_st *
+lnb_enum(int curno);
+
+/* Decode an lnb type, for example given on a command line
+ * If alpha and standard type, e.g. "Universal" then match that
+ * otherwise low[,high[,switch]]
+ */
+
+int
+lnb_decode(char *str, struct lnb_types_st *lnbp);
+
diff --git a/util/scan/Makefile b/util/scan/Makefile
new file mode 100644
index 0000000..a82d865
--- /dev/null
+++ b/util/scan/Makefile
@@ -0,0 +1,21 @@
+
+CC = gcc
+CFLAGS = -MD -g -Wall -O2 -I../../include -I../lib
+LFLAGS = -g -Wall
+
+OBJS = diseqc.o dump-zap.o dump-vdr.o scan.o ../lib/lnb.o
+SRCS = $(OBJS:.o=.c)
+
+TARGET = scan
+
+$(TARGET): $(OBJS)
+	$(CC) $(LFLAGS) -o $(TARGET) $(OBJS)
+
+.c.o:
+	$(CC) $(CFLAGS) -c $< -o $@
+
+clean:
+	$(RM) *.o *.d $(TARGET)
+
+-include $(wildcard *.d) dummy
+
diff --git a/util/scan/README b/util/scan/README
new file mode 100644
index 0000000..a6c1767
--- /dev/null
+++ b/util/scan/README
@@ -0,0 +1,18 @@
+Hi,
+
+this is a little channel scan utility to generate szap/tzap/czap compatible 
+channel lists. Scan does not do a frequency scan, however, so you must
+manually provide the data for tuning to one or more start transponders.
+A number of initial-tuning-data files are provided for various dvb-c, dvb-s
+and dvb-t networks around the world. If you make a new one feel free to
+submit it to the linux-dvb mailing list http://linuxtv.org/mailinglists.xml.
+
+Basic usage: ./scan dvb-s/Astra-19.2E | tee mychannels.conf
+
+If you want it to check a specific frequency, tune to that frequency 
+(e.g. using szap/tzap/czap) and then use './scan -c'.
+
+For more scan options see ./scan -h.
+
+Good luck,
+Holger + Johannes
diff --git a/util/scan/diseqc.c b/util/scan/diseqc.c
new file mode 100644
index 0000000..c763261
--- /dev/null
+++ b/util/scan/diseqc.c
@@ -0,0 +1,108 @@
+#include <linux/dvb/frontend.h>
+#include <sys/ioctl.h>
+#include <time.h>
+
+#include "scan.h"
+#include "diseqc.h"
+
+
+struct diseqc_cmd switch_cmds[] = {
+	{ { { 0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xf2, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xf1, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xf3, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xf4, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xf6, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xf5, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xf7, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xf8, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xfa, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xf9, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xfb, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xfc, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xfe, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xfd, 0x00, 0x00 }, 4 }, 0 },
+	{ { { 0xe0, 0x10, 0x38, 0xff, 0x00, 0x00 }, 4 }, 0 }
+};
+
+
+/*--------------------------------------------------------------------------*/
+
+static inline
+void msleep(uint32_t msec)
+{
+	struct timespec req = { msec / 1000, 1000000 * (msec % 1000) };
+
+	while (nanosleep(&req, &req))
+		;
+}
+
+#define printf(x...)
+
+
+int diseqc_send_msg (int fd, fe_sec_voltage_t v, struct diseqc_cmd **cmd,
+		     fe_sec_tone_mode_t t, fe_sec_mini_cmd_t b)
+{
+	int err;
+
+	if ((err = ioctl(fd, FE_SET_TONE, SEC_TONE_OFF)))
+		return err;
+
+	if ((err = ioctl(fd, FE_SET_VOLTAGE, v)))
+		return err;
+
+	msleep(15);
+	while (*cmd) {
+		debug("DiSEqC: %02x %02x %02x %02x %02x %02x\n",
+		    (*cmd)->cmd.msg[0], (*cmd)->cmd.msg[1],
+		    (*cmd)->cmd.msg[2], (*cmd)->cmd.msg[3],
+		    (*cmd)->cmd.msg[4], (*cmd)->cmd.msg[5]);
+
+		if ((err = ioctl(fd, FE_DISEQC_SEND_MASTER_CMD, &(*cmd)->cmd)))
+			return err;
+
+		msleep((*cmd)->wait);
+		cmd++;
+	}
+
+	//debug(" %s ", v == SEC_VOLTAGE_13 ? "SEC_VOLTAGE_13" :
+	//    v == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" : "???");
+
+	//debug(" %s ", b == SEC_MINI_A ? "SEC_MINI_A" :
+	//    b == SEC_MINI_B ? "SEC_MINI_B" : "???");
+
+	//debug(" %s\n", t == SEC_TONE_ON ? "SEC_TONE_ON" :
+	//    t == SEC_TONE_OFF ? "SEC_TONE_OFF" : "???");
+
+	msleep(15);
+
+	if ((err = ioctl(fd, FE_DISEQC_SEND_BURST, b)))
+		return err;
+
+	msleep(15);
+
+	return ioctl(fd, FE_SET_TONE, t);
+}
+
+
+int setup_switch (int frontend_fd, int switch_pos, int voltage_18, int hiband)
+{
+	struct diseqc_cmd *cmd[2] = { NULL, NULL };
+	int i = 4 * switch_pos + 2 * hiband + (voltage_18 ? 1 : 0);
+
+	verbose("DiSEqC: switch pos %i, %sV, %sband (index %d)\n",
+	    switch_pos, voltage_18 ? "18" : "13", hiband ? "hi" : "lo", i);
+
+	if (i < 0 || i >= sizeof(switch_cmds)/sizeof(struct diseqc_cmd))
+		return -EINVAL;
+
+	cmd[0] = &switch_cmds[i];
+
+	return diseqc_send_msg (frontend_fd,
+				i % 2 ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13,
+				cmd,
+				(i/2) % 2 ? SEC_TONE_ON : SEC_TONE_OFF,
+				(i/4) % 2 ? SEC_MINI_B : SEC_MINI_A);
+}
+
+
diff --git a/util/scan/diseqc.h b/util/scan/diseqc.h
new file mode 100644
index 0000000..d44d99b
--- /dev/null
+++ b/util/scan/diseqc.h
@@ -0,0 +1,25 @@
+#ifndef __DISEQC_H__
+#define __DISEQC_H__
+
+#include <stdint.h>
+#include <linux/dvb/frontend.h>
+
+
+struct diseqc_cmd {
+	struct dvb_diseqc_master_cmd cmd;
+	uint32_t wait;
+};
+
+
+extern int diseqc_send_msg (int fd, fe_sec_voltage_t v, struct diseqc_cmd **cmd,
+			    fe_sec_tone_mode_t t, fe_sec_mini_cmd_t b);
+
+
+/**
+ *   set up the switch to position/voltage/tone
+ */
+extern int setup_switch (int frontend_fd, int switch_pos, int voltage_18, int freq);
+
+
+#endif
+
diff --git a/util/scan/dump-vdr.c b/util/scan/dump-vdr.c
new file mode 100644
index 0000000..8f86654
--- /dev/null
+++ b/util/scan/dump-vdr.c
@@ -0,0 +1,161 @@
+#include <stdio.h>
+#include "dump-vdr.h"
+#include <linux/dvb/frontend.h>
+
+
+static const char *inv_name [] = {
+	"0",
+	"1",
+	"999"
+};
+
+static const char *fec_name [] = {
+	"0",
+	"12",
+	"23",
+	"34",
+	"45",
+	"56",
+	"67",
+	"78",
+	"89",
+	"999"
+};
+
+static const char *qam_name [] = {
+	"0",
+	"16",
+	"32",
+	"64",
+	"128",
+	"256",
+	"999"
+};
+
+
+static const char *bw_name [] = {
+	"8",
+	"7",
+	"6",
+	"999"
+};
+
+
+static const char *mode_name [] = {
+	"2",
+	"8",
+	"999"
+};
+
+static const char *guard_name [] = {
+	"32",
+	"16",
+	"8",
+	"4",
+	"999"
+};
+
+
+static const char *hierarchy_name [] = {
+	"0",
+	"1",
+	"2",
+	"4",
+	"999"
+};
+
+static const char *west_east_flag_name [] = {
+	"W",
+	"E"
+};
+
+void vdr_dump_dvb_parameters (FILE *f, fe_type_t type,
+		struct dvb_frontend_parameters *p,
+		char polarity, int orbital_pos, int we_flag)
+{
+	switch (type) {
+	case FE_QPSK:
+		fprintf (f, "%i:", p->frequency / 1000);
+		fprintf (f, "%c:", polarity);
+		fprintf (f, "S%i.%i%s:", orbital_pos/10,
+			 orbital_pos % 10, west_east_flag_name[we_flag]);
+		fprintf (f, "%i:", p->u.qpsk.symbol_rate / 1000);
+		break;
+
+	case FE_QAM:
+		fprintf (f, "%i:", p->frequency / 1000000);
+		fprintf (f, "M%s:C:", qam_name[p->u.qam.modulation]);
+		fprintf (f, "%i:", p->u.qam.symbol_rate / 1000);
+		break;
+
+	case FE_OFDM:
+		fprintf (f, "%i:", p->frequency / 1000);
+		fprintf (f, "I%s", inv_name[p->inversion]);
+		fprintf (f, "B%s", bw_name[p->u.ofdm.bandwidth]);
+		fprintf (f, "C%s", fec_name[p->u.ofdm.code_rate_HP]);
+		fprintf (f, "D%s", fec_name[p->u.ofdm.code_rate_LP]);
+		fprintf (f, "M%s", qam_name[p->u.ofdm.constellation]);
+		fprintf (f, "T%s", mode_name[p->u.ofdm.transmission_mode]);
+		fprintf (f, "G%s", guard_name[p->u.ofdm.guard_interval]);
+		fprintf (f, "Y%s", hierarchy_name[p->u.ofdm.hierarchy_information]);
+		fprintf (f, ":T:27500:");
+		break;
+
+	default:
+		;
+	};
+}
+
+void vdr_dump_service_parameter_set (FILE *f,
+				 const char *service_name,
+				 const char *provider_name,
+				 fe_type_t type,
+				 struct dvb_frontend_parameters *p,
+				 char polarity,
+				 int video_pid,
+				 int pcr_pid,
+				 uint16_t *audio_pid,
+                                 int audio_num,
+				 int teletext_pid,
+				 int scrambled,
+				 int ac3_pid,
+                                 int service_id,
+				 int network_id,
+				 int transport_stream_id,
+				 int orbital_pos,
+				 int we_flag,
+				 int dump_provider,
+				 int ca_select,
+				 int vdr_version,
+				 int dump_channum,
+				 int channel_num)
+{
+        int i;
+
+	if ((video_pid || audio_pid[0]) && ((ca_select > 0) || ((ca_select == 0) && (scrambled == 0)))) {
+		if ((dump_channum == 1) && (channel_num > 0))
+			fprintf(f, ":@%i\n", channel_num);
+		if (dump_provider == 1)
+			fprintf (f, "%s - ", provider_name);
+		fprintf (f, "%s:", service_name);
+		vdr_dump_dvb_parameters (f, type, p, polarity, orbital_pos, we_flag);
+		if ((pcr_pid != video_pid) && (video_pid > 0))
+			fprintf (f, "%i+%i:", video_pid, pcr_pid);
+		else
+			fprintf (f, "%i:", video_pid);
+		fprintf (f, "%i", audio_pid[0]);
+	        for (i = 1; i < audio_num; i++)
+			fprintf (f, ",%i", audio_pid[i]);
+		if (ac3_pid)
+			fprintf (f, ";%i", ac3_pid);
+		if (scrambled == 1) scrambled = ca_select;
+		if (vdr_version == 2) {
+			network_id = 0;
+			transport_stream_id = 0;
+		} 
+		fprintf (f, ":%d:%d:%d:%d:%d:0", teletext_pid, scrambled,
+				service_id, network_id, transport_stream_id);
+		fprintf (f, "\n");
+	}
+}
+
diff --git a/util/scan/dump-vdr.h b/util/scan/dump-vdr.h
new file mode 100644
index 0000000..0602026
--- /dev/null
+++ b/util/scan/dump-vdr.h
@@ -0,0 +1,38 @@
+#ifndef __DUMP_VDR_H__
+#define __DUMP_VDR_H__
+
+#include <stdint.h>
+#include <linux/dvb/frontend.h>
+
+extern
+void vdr_dump_dvb_parameters (FILE *f, fe_type_t type,
+		struct dvb_frontend_parameters *p,
+		char polarity, int orbital_pos, int we_flag);
+
+extern
+void vdr_dump_service_parameter_set (FILE *f,
+				 const char *service_name,
+				 const char *provider_name,
+				 fe_type_t type,
+				 struct dvb_frontend_parameters *p,
+				 char polarity,
+				 int video_pid,
+				 int pcr_pid,
+				 uint16_t *audio_pid,
+                                 int audio_num,
+				 int teletext_pid,
+				 int scrambled,
+				 int ac3_pid,
+                                 int service_id,
+				 int network_id,
+				 int transport_stream_id,
+				 int orbital_pos,
+				 int we_flag,
+				 int dump_provider,
+				 int ca_select,
+				 int vdr_version,
+				 int dump_channum,
+				 int channel_num);
+
+#endif
+
diff --git a/util/scan/dump-zap.c b/util/scan/dump-zap.c
new file mode 100644
index 0000000..fb46a2a
--- /dev/null
+++ b/util/scan/dump-zap.c
@@ -0,0 +1,119 @@
+#include <stdio.h>
+#include <linux/dvb/frontend.h>
+#include "dump-zap.h"
+
+static const char *inv_name [] = {
+	"INVERSION_OFF",
+	"INVERSION_ON",
+	"INVERSION_AUTO"
+};
+
+static const char *fec_name [] = {
+	"FEC_NONE",
+	"FEC_1_2",
+	"FEC_2_3",
+	"FEC_3_4",
+	"FEC_4_5",
+	"FEC_5_6",
+	"FEC_6_7",
+	"FEC_7_8",
+	"FEC_8_9",
+	"FEC_AUTO"
+};
+
+
+static const char *qam_name [] = {
+	"QPSK",
+	"QAM_16",
+	"QAM_32",
+	"QAM_64",
+	"QAM_128",
+	"QAM_256",
+	"QAM_AUTO"
+};
+
+
+static const char *bw_name [] = {
+	"BANDWIDTH_8_MHZ",
+	"BANDWIDTH_7_MHZ",
+	"BANDWIDTH_6_MHZ",
+	"BANDWIDTH_AUTO"
+};
+
+
+static const char *mode_name [] = {
+	"TRANSMISSION_MODE_2K",
+	"TRANSMISSION_MODE_8K",
+	"TRANSMISSION_MODE_AUTO"
+};
+
+static const char *guard_name [] = {
+	"GUARD_INTERVAL_1_32",
+	"GUARD_INTERVAL_1_16",
+	"GUARD_INTERVAL_1_8",
+	"GUARD_INTERVAL_1_4",
+	"GUARD_INTERVAL_AUTO"
+};
+
+
+static const char *hierarchy_name [] = {
+	"HIERARCHY_NONE",
+	"HIERARCHY_1",
+	"HIERARCHY_2",
+	"HIERARCHY_4",
+	"HIERARCHY_AUTO"
+};
+
+
+void zap_dump_dvb_parameters (FILE *f, fe_type_t type, struct dvb_frontend_parameters *p, char polarity, int sat_number)
+{
+	switch (type) {
+	case FE_QPSK:
+		fprintf (f, "%i:", p->frequency / 1000);	/* channels.conf wants MHz */
+		fprintf (f, "%c:", polarity);
+		fprintf (f, "%d:", sat_number);
+		fprintf (f, "%i", p->u.qpsk.symbol_rate / 1000); /* channels.conf wants kBaud */
+		/*fprintf (f, "%s", fec_name[p->u.qpsk.fec_inner]);*/
+		break;
+
+	case FE_QAM:
+		fprintf (f, "%i:", p->frequency);
+		fprintf (f, "%s:", inv_name[p->inversion]);
+		fprintf (f, "%i:", p->u.qpsk.symbol_rate);
+		fprintf (f, "%s:", fec_name[p->u.qpsk.fec_inner]);
+		fprintf (f, "%s", qam_name[p->u.qam.modulation]);
+		break;
+
+	case FE_OFDM:
+		fprintf (f, "%i:", p->frequency);
+		fprintf (f, "%s:", inv_name[p->inversion]);
+		fprintf (f, "%s:", bw_name[p->u.ofdm.bandwidth]);
+		fprintf (f, "%s:", fec_name[p->u.ofdm.code_rate_HP]);
+		fprintf (f, "%s:", fec_name[p->u.ofdm.code_rate_LP]);
+		fprintf (f, "%s:", qam_name[p->u.ofdm.constellation]);
+		fprintf (f, "%s:", mode_name[p->u.ofdm.transmission_mode]);
+		fprintf (f, "%s:", guard_name[p->u.ofdm.guard_interval]);
+		fprintf (f, "%s", hierarchy_name[p->u.ofdm.hierarchy_information]);
+		break;
+
+	default:
+		;
+	};
+}
+
+void zap_dump_service_parameter_set (FILE *f, 
+				 const char *service_name,
+				 fe_type_t type,
+				 struct dvb_frontend_parameters *p,
+				 char polarity,
+				 int sat_number,
+				 uint16_t video_pid,
+				 uint16_t *audio_pid,
+				 uint16_t service_id)
+{
+	fprintf (f, "%s:", service_name);
+	zap_dump_dvb_parameters (f, type, p, polarity, sat_number);
+	fprintf (f, ":%i:%i:%i", video_pid, audio_pid[0], service_id);
+	fprintf (f, "\n");
+}
+
diff --git a/util/scan/dump-zap.h b/util/scan/dump-zap.h
new file mode 100644
index 0000000..6763dc2
--- /dev/null
+++ b/util/scan/dump-zap.h
@@ -0,0 +1,20 @@
+#ifndef __DUMP_ZAP_H__
+#define __DUMP_ZAP_H__
+
+#include <stdint.h>
+#include <linux/dvb/frontend.h>
+
+extern void zap_dump_dvb_parameters (FILE *f, fe_type_t type,
+		struct dvb_frontend_parameters *t, char polarity, int sat);
+
+extern void zap_dump_service_parameter_set (FILE *f,
+				 const char *service_name,
+				 fe_type_t type,
+				 struct dvb_frontend_parameters *t,
+				 char polarity, int sat,
+				 uint16_t video_pid,
+				 uint16_t *audio_pid,
+				 uint16_t service_id);
+
+#endif
+
diff --git a/util/scan/dvb-c/at-Vienna b/util/scan/dvb-c/at-Vienna
new file mode 100644
index 0000000..2c3d29c
--- /dev/null
+++ b/util/scan/dvb-c/at-Vienna
@@ -0,0 +1,3 @@
+# Kabel Vienna
+# freq sr fec mod
+C 377750000 6900000 NONE QAM256
diff --git a/util/scan/dvb-c/ch-unknown b/util/scan/dvb-c/ch-unknown
new file mode 100644
index 0000000..a9852d1
--- /dev/null
+++ b/util/scan/dvb-c/ch-unknown
@@ -0,0 +1,3 @@
+# Kabel Suisse
+# freq sr fec mod
+C 530000000 6900000 NONE QAM64
diff --git a/util/scan/dvb-c/de-Berlin b/util/scan/dvb-c/de-Berlin
new file mode 100644
index 0000000..4a53b74
--- /dev/null
+++ b/util/scan/dvb-c/de-Berlin
@@ -0,0 +1,4 @@
+# Kabel Berlin
+# freq sr fec mod
+C 394000000 6900000 NONE QAM64
+C 113000000 6900000 NONE QAM64
diff --git a/util/scan/dvb-c/de-iesy b/util/scan/dvb-c/de-iesy
new file mode 100644
index 0000000..a289951
--- /dev/null
+++ b/util/scan/dvb-c/de-iesy
@@ -0,0 +1,3 @@
+# Kabel iesy
+# freq sr fec mod
+C 410000000 6900000 NONE QAM64
diff --git a/util/scan/dvb-c/fi-3ktv b/util/scan/dvb-c/fi-3ktv
new file mode 100644
index 0000000..55ccfd6
--- /dev/null
+++ b/util/scan/dvb-c/fi-3ktv
@@ -0,0 +1,3 @@
+# 3KTV
+# freq sr fec mod
+C 306000000 6875000 NONE QAM64
diff --git a/util/scan/dvb-c/fi-vaasa-oncable b/util/scan/dvb-c/fi-vaasa-oncable
new file mode 100644
index 0000000..380ccf7
--- /dev/null
+++ b/util/scan/dvb-c/fi-vaasa-oncable
@@ -0,0 +1,13 @@
+# OnCable (Finland / Vaasa)
+# freq sr fec mod
+C 386000000 6875000 NONE QAM64
+C 394000000 6875000 NONE QAM64
+C 143000000 6875000 NONE QAM64
+C 434000000 6875000 NONE QAM64
+C 362000000 6875000 NONE QAM64
+C 418000000 6875000 NONE QAM64
+C 426000000 6875000 NONE QAM64
+C 314000000 6875000 NONE QAM64
+C 410000000 6875000 NONE QAM64
+C 442000000 6875000 NONE QAM64
+C 306000000 6875000 NONE QAM64
diff --git a/util/scan/dvb-s/Astra-19.2E b/util/scan/dvb-s/Astra-19.2E
new file mode 100644
index 0000000..74e1b59
--- /dev/null
+++ b/util/scan/dvb-s/Astra-19.2E
@@ -0,0 +1,3 @@
+# Astra 19.2E SDT info service transponder
+# freq pol sr fec
+S 12551500 V 22000000 5/6
diff --git a/util/scan/dvb-s/Hispasat-30.0W b/util/scan/dvb-s/Hispasat-30.0W
new file mode 100644
index 0000000..2c200b5
--- /dev/null
+++ b/util/scan/dvb-s/Hispasat-30.0W
@@ -0,0 +1,6 @@
+# Hispasat 30.0W
+# freq pol sr fec
+S 11539000 V 24500000 5/6
+S 11931000 H 27500000 3/4
+S 12015000 V 27500000 3/4
+S 12567000 H 19850000 3/4
diff --git a/util/scan/dvb-s/Hotbird-13.0E b/util/scan/dvb-s/Hotbird-13.0E
new file mode 100644
index 0000000..f2168da
--- /dev/null
+++ b/util/scan/dvb-s/Hotbird-13.0E
@@ -0,0 +1,3 @@
+# EUTELSAT SkyPlex, Hotbird 13E
+# freq pol sr fec
+S 12539000 H 27500000 3/4
diff --git a/util/scan/dvb-s/PAS-43.0W b/util/scan/dvb-s/PAS-43.0W
new file mode 100644
index 0000000..fab84c5
--- /dev/null
+++ b/util/scan/dvb-s/PAS-43.0W
@@ -0,0 +1,6 @@
+# PAS 6/6B/3R at 43.0W
+# freq pol sr fec
+S 12578000 H 19850000 3/4
+S 12584000 V 27500000 3/4
+S 12606000 H  6616000 3/4
+S 12665000 H 19850000 7/8
diff --git a/util/scan/dvb-s/Sirius-5.0E b/util/scan/dvb-s/Sirius-5.0E
new file mode 100644
index 0000000..ec4e4ea
--- /dev/null
+++ b/util/scan/dvb-s/Sirius-5.0E
@@ -0,0 +1,5 @@
+# Sirius 5.0E
+# freq pol sr fec
+S 11823000 V 27500000 3/4
+S 11977000 V 27500000 3/4
+S 12054000 V 27500000 3/4
diff --git a/util/scan/dvb-s/Telecom2-8.0W b/util/scan/dvb-s/Telecom2-8.0W
new file mode 100644
index 0000000..91678b4
--- /dev/null
+++ b/util/scan/dvb-s/Telecom2-8.0W
@@ -0,0 +1,4 @@
+# Telecom2 8.0W
+# freq pol sr fec
+S 11635000 H 6800000 5/6
+S 12687000 V 1879000 3/4
diff --git a/util/scan/dvb-s/Telstar12-15.0W b/util/scan/dvb-s/Telstar12-15.0W
new file mode 100644
index 0000000..529b91f
--- /dev/null
+++ b/util/scan/dvb-s/Telstar12-15.0W
@@ -0,0 +1,4 @@
+# Telstar 12 15.0W
+# freq pol sr fec
+S 12041000 H 3256000 2/3
+S 12520000 V 8700000 1/2
diff --git a/util/scan/dvb-s/Thor-1.0W b/util/scan/dvb-s/Thor-1.0W
new file mode 100644
index 0000000..1f8f1d2
--- /dev/null
+++ b/util/scan/dvb-s/Thor-1.0W
@@ -0,0 +1,8 @@
+# Thor 1.0W
+# freq pol sr fec
+S 11247000 V 24500000 7/8
+S 11293000 H 24500000 7/8
+S 11325000 H 24500000 7/8
+S 12054000 H 28000000 7/8
+S 12169000 H 28000000 7/8
+S 12226000 V 28000000 7/8
diff --git a/util/scan/dvb-s/Turksat-42.0E b/util/scan/dvb-s/Turksat-42.0E
new file mode 100644
index 0000000..1ac7fd8
--- /dev/null
+++ b/util/scan/dvb-s/Turksat-42.0E
@@ -0,0 +1,4 @@
+# Turksat 42.0E
+# freq pol sr fec
+S 11594000 H 4557000 5/6
+S 10978000 V 2344000 3/4
diff --git a/util/scan/dvb-t/au-Darwin b/util/scan/dvb-t/au-Darwin
new file mode 100644
index 0000000..522bb1d
--- /dev/null
+++ b/util/scan/dvb-t/au-Darwin
@@ -0,0 +1,5 @@
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+T 543625000 7MHz 3/4 NONE QAM64 8k 1/16 NONE
+T 550500000 7MHz 2/3 NONE QAM64 8k 1/8 NONE
+T 536625000 7MHz 2/3 NONE QAM64 8k 1/8 NONE
+T 557625000 7MHz 2/3 NONE QAM64 8k 1/8 NONE
diff --git a/util/scan/dvb-t/au-canberra b/util/scan/dvb-t/au-canberra
new file mode 100644
index 0000000..5e71b07
--- /dev/null
+++ b/util/scan/dvb-t/au-canberra
@@ -0,0 +1,12 @@
+# Australia / Canberra / Woden
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+# ABC
+T 205625000 7MHz 3/4 3/4 QAM64 8k 1/16 NONE
+# Seven
+T 177500000 7MHz 2/3 NONE QAM64 8k 1/8 NONE
+# Nine
+T 191625000 7MHz 3/4 NONE QAM64 8k 1/16 NONE
+# Ten
+T 219500000 7MHz 3/4 1/2 QAM64 8k 1/16 NONE
+# SBS
+T 543500000 7MHz 2/3 NONE QAM64 8k 1/8 NONE
diff --git a/util/scan/dvb-t/au-sydney_north_shore b/util/scan/dvb-t/au-sydney_north_shore
new file mode 100644
index 0000000..0bb6dd4
--- /dev/null
+++ b/util/scan/dvb-t/au-sydney_north_shore
@@ -0,0 +1,12 @@
+# Australia / Sydney / North Shore (aka Artarmon/Gore Hill)
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+# ABC
+T 226500000 7MHz 3/4 NONE QAM64 8k 1/16 NONE
+# Seven
+T 177500000 7MHz 2/3 NONE QAM64 8k 1/8 NONE
+# Nine
+T 191625000 7MHz 3/4 NONE QAM64 8k 1/16 NONE
+# Ten
+T 219500000 7MHz 3/4 NONE QAM64 8k 1/16 NONE
+# SBS
+T 571500000 7MHz 2/3 NONE QAM64 8k 1/8 NONE
diff --git a/util/scan/dvb-t/au-unknown b/util/scan/dvb-t/au-unknown
new file mode 100644
index 0000000..9f96d9e
--- /dev/null
+++ b/util/scan/dvb-t/au-unknown
@@ -0,0 +1,3 @@
+# Australia ABC
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+T 226500000 7MHz 2/3 NONE QAM64 8k 1/8 NONE
diff --git a/util/scan/dvb-t/de-Berlin b/util/scan/dvb-t/de-Berlin
new file mode 100644
index 0000000..416bd11
--- /dev/null
+++ b/util/scan/dvb-t/de-Berlin
@@ -0,0 +1,5 @@
+# DVB-T Berlin
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+T 522000000 8MHz 2/3 NONE QAM16 8k 1/8 NONE     # ard / rbb
+T 570000000 8MHz 2/3 NONE QAM16 8k 1/8 NONE     # zdf
+T 658000000 8MHz 2/3 NONE QAM16 8k 1/8 NONE     # t-systems
diff --git a/util/scan/dvb-t/es-Collserola b/util/scan/dvb-t/es-Collserola
new file mode 100644
index 0000000..04ffe54
--- /dev/null
+++ b/util/scan/dvb-t/es-Collserola
@@ -0,0 +1,6 @@
+# DVB-T Collserola (Barcelona)
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+T 650000000 8MHz 2/3 2/3 QAM64 8k 1/32 NONE     # C43: tvc
+T 794000000 8MHz 2/3 NONE QAM64 8k 1/4 NONE     # C61: tve, t5, a3, c+
+T 834000000 8MHz 2/3 NONE QAM64 8k 1/4 NONE     # C66: veotv, nettv
+
diff --git a/util/scan/dvb-t/fi-Espoo b/util/scan/dvb-t/fi-Espoo
new file mode 100644
index 0000000..dd0619b
--- /dev/null
+++ b/util/scan/dvb-t/fi-Espoo
@@ -0,0 +1,3 @@
+# Espoo A-mux (Digita Finland)
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+T 562000000 8MHz 2/3 NONE QAM64 8k 1/8 NONE
diff --git a/util/scan/dvb-t/fi-Tampere b/util/scan/dvb-t/fi-Tampere
new file mode 100644
index 0000000..7e59894
--- /dev/null
+++ b/util/scan/dvb-t/fi-Tampere
@@ -0,0 +1,6 @@
+# Tampere DVB-T (Digita Finland)
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+T 578000000 8MHz 2/3 NONE QAM64 8k 1/8 NONE
+T 490000000 8MHz 2/3 NONE QAM64 8k 1/8 NONE
+T 770000000 8MHz 2/3 NONE QAM64 8k 1/8 NONE
+
diff --git a/util/scan/dvb-t/fi-Turku b/util/scan/dvb-t/fi-Turku
new file mode 100644
index 0000000..5f2d9b4
--- /dev/null
+++ b/util/scan/dvb-t/fi-Turku
@@ -0,0 +1,3 @@
+# Turku A-mux (Digita Finland)
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+T 714000000 8MHz 2/3 NONE QAM64 8k 1/8 NONE
diff --git a/util/scan/dvb-t/nl-AlphenaandenRijn b/util/scan/dvb-t/nl-AlphenaandenRijn
new file mode 100644
index 0000000..f95d3a4
--- /dev/null
+++ b/util/scan/dvb-t/nl-AlphenaandenRijn
@@ -0,0 +1,7 @@
+# Digitenne (Alphen aan den Rijn, The Netherlands)
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy        
+T 474000000 8MHz 1/2 NONE QAM64 8k 1/4 NONE
+T 578000000 8MHz 1/2 NONE QAM64 8k 1/4 NONE
+T 722000000 8MHz 1/2 NONE QAM64 8k 1/4 NONE
+T 762000000 8MHz 1/2 NONE QAM64 8k 1/4 NONE
+T 818000000 8MHz 1/2 NONE QAM64 8k 1/4 NONE
diff --git a/util/scan/dvb-t/nl-Randstad b/util/scan/dvb-t/nl-Randstad
new file mode 100644
index 0000000..da1a74d
--- /dev/null
+++ b/util/scan/dvb-t/nl-Randstad
@@ -0,0 +1,7 @@
+# Digitenne (Randstad, The Netherlands)
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy        
+T 474000000 8MHz 1/2 NONE QAM64 8k 1/4 NONE
+T 490000000 8MHz 1/2 NONE QAM64 8k 1/4 NONE
+T 578000000 8MHz 1/2 NONE QAM64 8k 1/4 NONE
+T 762000000 8MHz 1/2 NONE QAM64 8k 1/4 NONE
+T 818000000 8MHz 1/2 NONE QAM64 8k 1/4 NONE
diff --git a/util/scan/dvb-t/se-Gavle b/util/scan/dvb-t/se-Gavle
new file mode 100644
index 0000000..04fe333
--- /dev/null
+++ b/util/scan/dvb-t/se-Gavle
@@ -0,0 +1,6 @@
+# Gavle (Senda/Boxer Sweden)
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+T 674000000 8MHz 2/3 NONE QAM64 8k 1/8 NONE
+T 498000000 8MHz 2/3 NONE QAM64 8k 1/8 NONE
+T 562000000 8MHz 2/3 NONE QAM64 8k 1/8 NONE
+T 706000000 8MHz 2/3 NONE QAM64 8k 1/8 NONE
diff --git a/util/scan/dvb-t/uk-BlackHill b/util/scan/dvb-t/uk-BlackHill
new file mode 100644
index 0000000..17eae72
--- /dev/null
+++ b/util/scan/dvb-t/uk-BlackHill
@@ -0,0 +1,3 @@
+# uk BlackHill
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+T 634167000 8MHz 2/3 NONE QAM64 2k 1/32 NONE
diff --git a/util/scan/dvb-t/uk-CrystalPalace b/util/scan/dvb-t/uk-CrystalPalace
new file mode 100644
index 0000000..9586b25
--- /dev/null
+++ b/util/scan/dvb-t/uk-CrystalPalace
@@ -0,0 +1,3 @@
+# Crystal Palace
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+T 505833333 8MHz 3/4 NONE QAM16 2k 1/32 NONE
diff --git a/util/scan/dvb-t/uk-Hannington b/util/scan/dvb-t/uk-Hannington
new file mode 100644
index 0000000..0bbbfdd
--- /dev/null
+++ b/util/scan/dvb-t/uk-Hannington
@@ -0,0 +1,3 @@
+# Hannington, North Hampshire
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+T 706000000 8MHz 3/4 NONE QAM16 2k 1/32 NONE
diff --git a/util/scan/dvb-t/uk-Oxford b/util/scan/dvb-t/uk-Oxford
new file mode 100644
index 0000000..035603e
--- /dev/null
+++ b/util/scan/dvb-t/uk-Oxford
@@ -0,0 +1,3 @@
+# Oxford
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+T 578000000 8MHz 2/3 NONE QAM64 2k 1/32 NONE
diff --git a/util/scan/dvb-t/uk-PontopPike b/util/scan/dvb-t/uk-PontopPike
new file mode 100644
index 0000000..c24ba92
--- /dev/null
+++ b/util/scan/dvb-t/uk-PontopPike
@@ -0,0 +1,3 @@
+# Pontop Pike, UK
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+T 690000000 8MHz 1/2 NONE QAM16 2k 1/32 NONE
diff --git a/util/scan/dvb-t/uk-Redruth b/util/scan/dvb-t/uk-Redruth
new file mode 100644
index 0000000..84dcb9a
--- /dev/null
+++ b/util/scan/dvb-t/uk-Redruth
@@ -0,0 +1,3 @@
+# Redruth, Cornwall
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+T 618000000 8MHz 3/4 NONE QAM16 2k 1/32 NONE
diff --git a/util/scan/dvb-t/uk-Reigate b/util/scan/dvb-t/uk-Reigate
new file mode 100644
index 0000000..add0d8b
--- /dev/null
+++ b/util/scan/dvb-t/uk-Reigate
@@ -0,0 +1,3 @@
+# Reigate
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+T 554000000 8MHz 2/3 NONE QAM64 2k 1/32 NONE
diff --git a/util/scan/dvb-t/uk-Rowridge b/util/scan/dvb-t/uk-Rowridge
new file mode 100644
index 0000000..c0c72a0
--- /dev/null
+++ b/util/scan/dvb-t/uk-Rowridge
@@ -0,0 +1,3 @@
+# Rowridge, Isle of Wight
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+T 489833333 8MHz 3/4 NONE QAM16 2k 1/32 NONE
diff --git a/util/scan/dvb-t/uk-SandyHeath b/util/scan/dvb-t/uk-SandyHeath
new file mode 100644
index 0000000..05d0474
--- /dev/null
+++ b/util/scan/dvb-t/uk-SandyHeath
@@ -0,0 +1,3 @@
+# Sandy Heath
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+T 641833334 8MHz 2/3 NONE QAM64 2k 1/32 NONE
diff --git a/util/scan/dvb-t/uk-Storeton b/util/scan/dvb-t/uk-Storeton
new file mode 100644
index 0000000..5c93ee9
--- /dev/null
+++ b/util/scan/dvb-t/uk-Storeton
@@ -0,0 +1,3 @@
+# Storeton, Wirral
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+T 546167000 8MHz 3/4 NONE QAM16 2k 1/32 NONE
diff --git a/util/scan/dvb-t/uk-WinterHill b/util/scan/dvb-t/uk-WinterHill
new file mode 100644
index 0000000..b000623
--- /dev/null
+++ b/util/scan/dvb-t/uk-WinterHill
@@ -0,0 +1,3 @@
+# Winter Hill, North-West England
+# T freq bw fec_hi fec_lo mod transmission-mode guard-interval hierarchy
+T 754166670 8MHz 3/4 NONE QAM16 2k 1/32 NONE
diff --git a/util/scan/list.h b/util/scan/list.h
new file mode 100644
index 0000000..6032c22
--- /dev/null
+++ b/util/scan/list.h
@@ -0,0 +1,140 @@
+#ifndef _LIST_H
+#define _LIST_H
+
+
+/*
+ * Simple doubly linked list implementation.
+ *
+ * Some of the internal functions ("__xxx") are useful when
+ * manipulating whole lists rather than single entries, as
+ * sometimes we already know the next/prev entries and we can
+ * generate better code by using them directly rather than
+ * using the generic single-entry routines.
+ */
+
+struct list_head {
+	struct list_head *next, *prev;
+};
+
+#define LIST_HEAD_INIT(name) { &(name), &(name) }
+
+#define LIST_HEAD(name) \
+	struct list_head name = LIST_HEAD_INIT(name)
+
+#define INIT_LIST_HEAD(ptr) do { \
+	(ptr)->next = (ptr); (ptr)->prev = (ptr); \
+} while (0)
+
+/*
+ * Insert a new entry between two known consecutive entries. 
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_add(struct list_head * new,
+	struct list_head * prev,
+	struct list_head * next)
+{
+	next->prev = new;
+	new->next = next;
+	new->prev = prev;
+	prev->next = new;
+}
+
+/**
+ * list_add - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it after
+ *
+ * Insert a new entry after the specified head.
+ * This is good for implementing stacks.
+ */
+static __inline__ void list_add(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head, head->next);
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
+{
+	__list_add(new, head->prev, head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __list_del(struct list_head * prev,
+				  struct list_head * next)
+{
+	next->prev = prev;
+	prev->next = next;
+}
+
+/**
+ * list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
+ */
+static __inline__ void list_del(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+}
+
+/**
+ * list_del_init - deletes entry from list and reinitialize it.
+ * @entry: the element to delete from the list.
+ */
+static __inline__ void list_del_init(struct list_head *entry)
+{
+	__list_del(entry->prev, entry->next);
+	INIT_LIST_HEAD(entry); 
+}
+
+/**
+ * list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static __inline__ int list_empty(struct list_head *head)
+{
+	return head->next == head;
+}
+
+/**
+ * list_entry - get the struct for this entry
+ * @ptr:	the &struct list_head pointer.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_entry(ptr, type, member) \
+	((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
+
+/**
+ * list_for_each	-	iterate over a list
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @head:	the head for your list.
+ */
+#define list_for_each(pos, head) \
+	for (pos = (head)->next; pos != (head); pos = pos->next)
+        	
+/**
+ * list_for_each_safe	-	iterate over a list safe against removal of list entry
+ * @pos:	the &struct list_head to use as a loop counter.
+ * @n:		another &struct list_head to use as temporary storage
+ * @head:	the head for your list.
+ */
+#define list_for_each_safe(pos, n, head) \
+	for (pos = (head)->next, n = pos->next; pos != (head); \
+		pos = n, n = pos->next)
+
+#endif
diff --git a/util/scan/scan.c b/util/scan/scan.c
new file mode 100644
index 0000000..30d77a5
--- /dev/null
+++ b/util/scan/scan.c
@@ -0,0 +1,1928 @@
+/**
+ *  Simple MPEG parser to achieve network/service information.
+ *
+ *  refered standards:
+ *
+ *    ETSI EN 300 468
+ *    ETSI TR 101 211
+ *    ETSI ETR 211
+ *    ITU-T H.222.0
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <time.h>
+#include <errno.h>
+#include <signal.h>
+#include <assert.h>
+
+#include <linux/dvb/frontend.h>
+#include <linux/dvb/dmx.h>
+
+#include "list.h"
+#include "diseqc.h"
+#include "dump-zap.h"
+#include "dump-vdr.h"
+#include "scan.h"
+#include "lnb.h"
+
+
+static char demux_devname[80];
+
+static struct dvb_frontend_info fe_info = {
+	.type = -1
+};
+
+int verbosity = 2;
+
+static int long_timeout;
+static int current_tp_only;
+static int get_other_nits;
+static int vdr_dump_provider;
+static int vdr_dump_channum;
+static int ca_select = 1;
+static int serv_select = 7;
+static int vdr_version = 2;
+static struct lnb_types_st lnb_type;
+
+static enum fe_spectral_inversion spectral_inversion = INVERSION_AUTO;
+
+enum table_type {
+	PAT,
+	PMT,
+	SDT,
+	NIT
+};
+
+enum format {
+        OUTPUT_ZAP,
+        OUTPUT_VDR,
+	OUTPUT_PIDS
+};
+static enum format output_format = OUTPUT_ZAP;
+
+
+enum polarisation {
+	POLARISATION_HORIZONTAL     = 0x00,
+	POLARISATION_VERTICAL       = 0x01,
+	POLARISATION_CIRCULAR_LEFT  = 0x02,
+	POLARISATION_CIRCULAR_RIGHT = 0x03
+};
+
+enum running_mode {
+	RM_NOT_RUNNING = 0x01,
+	RM_STARTS_SOON = 0x02,
+	RM_PAUSING     = 0x03,
+	RM_RUNNING     = 0x04
+};
+
+#define AUDIO_CHAN_MAX (32)
+#define CA_SYSTEM_ID_MAX (16)
+
+struct service {
+	struct list_head list;
+	int transport_stream_id;
+	int service_id;
+	char *provider_name;
+	char *service_name;
+	uint16_t pmt_pid;
+	uint16_t pcr_pid;
+	uint16_t video_pid;
+	uint16_t audio_pid[AUDIO_CHAN_MAX];
+	char audio_lang[AUDIO_CHAN_MAX][4];
+	int audio_num;
+	uint16_t ca_id[CA_SYSTEM_ID_MAX];
+	int ca_num;
+	uint16_t teletext_pid;
+	uint16_t subtitling_pid;
+	uint16_t ac3_pid;
+	unsigned int type         : 8;
+	unsigned int scrambled	  : 1;
+	enum running_mode running;
+	void *priv;
+	int channel_num;
+};
+
+struct transponder {
+	struct list_head list;
+	struct list_head services;
+	int network_id;
+	int transport_stream_id;
+	enum fe_type type;
+	struct dvb_frontend_parameters param;
+	enum polarisation polarisation;		/* only for DVB-S */
+	int orbital_pos;			/* only for DVB-S */
+	unsigned int we_flag		  : 1;	/* West/East Flag - only for DVB-S */
+	unsigned int scan_done		  : 1;
+	unsigned int last_tuning_failed	  : 1;
+	unsigned int other_frequency_flag : 1;	/* DVB-T */
+	int n_other_f;
+	uint32_t *other_f;			/* DVB-T freqeuency-list descriptor */
+};
+
+
+struct section_buf {
+	struct list_head list;
+	const char *dmx_devname;
+	unsigned int run_once  : 1;
+	unsigned int segmented : 1;	/* segmented by table_id_ext */
+	int fd;
+	int pid;
+	int table_id;
+	int table_id_ext;
+	int section_version_number;
+	uint8_t section_done[32];
+	int sectionfilter_done;
+	unsigned char buf[1024];
+	time_t timeout;
+	time_t start_time;
+	time_t running_time;
+	struct section_buf *next_seg;	/* this is used to handle
+					 * segmented tables (like NIT-other)
+					 */
+};
+
+static LIST_HEAD(scanned_transponders);
+static LIST_HEAD(new_transponders);
+static struct transponder *current_tp;
+
+
+static void dump_dvb_parameters (FILE *f, struct transponder *p);
+
+static void setup_filter (struct section_buf* s, const char *dmx_devname,
+		          int pid, int tid, int run_once, int segmented, int timeout);
+static void add_filter (struct section_buf *s);
+
+
+/* According to the DVB standards, the combination of network_id and
+ * transport_stream_id should be unique, but in real life the satellite
+ * operators and broadcasters don't care enough to coordinate
+ * the numbering. Thus we identify TPs by frequency (scan handles only
+ * one satellite at a time). Further complication: Different NITs on
+ * one satellite sometimes list the same TP with slightly different
+ * frequencies, so we have to search within some bandwidth.
+ */
+static struct transponder *alloc_transponder(uint32_t frequency)
+{
+	struct transponder *tp = calloc(1, sizeof(*tp));
+
+	tp->param.frequency = frequency;
+	INIT_LIST_HEAD(&tp->list);
+	INIT_LIST_HEAD(&tp->services);
+	list_add_tail(&tp->list, &new_transponders);
+	return tp;
+}
+
+static int is_same_transponder(uint32_t f1, uint32_t f2)
+{
+	uint32_t diff;
+	if (f1 == f2)
+		return 1;
+	diff = (f1 > f2) ? (f1 - f2) : (f2 - f1);
+	//FIXME: use symbolrate etc. to estimate bandwidth
+	if (diff < 2000) {
+		debug("f1 = %u is same TP as f2 = %u\n", f1, f2);
+		return 1;
+	}
+	return 0;
+}
+
+static struct transponder *find_transponder(uint32_t frequency)
+{
+	struct list_head *pos;
+	struct transponder *tp;
+
+	list_for_each(pos, &scanned_transponders) {
+		tp = list_entry(pos, struct transponder, list);
+		if (is_same_transponder(tp->param.frequency, frequency))
+			return tp;
+	}
+	list_for_each(pos, &new_transponders) {
+		tp = list_entry(pos, struct transponder, list);
+		if (is_same_transponder(tp->param.frequency, frequency))
+			return tp;
+	}
+	return NULL;
+}
+
+static void copy_transponder(struct transponder *d, struct transponder *s)
+{
+	d->network_id = s->network_id;
+	d->transport_stream_id = s->transport_stream_id;
+	d->type = s->type;
+	memcpy(&d->param, &s->param, sizeof(d->param));
+	d->polarisation = s->polarisation;
+	d->orbital_pos = s->orbital_pos;
+	d->we_flag = s->we_flag;
+	d->scan_done = s->scan_done;
+	d->last_tuning_failed = s->last_tuning_failed;
+	d->other_frequency_flag = s->other_frequency_flag;
+	d->n_other_f = s->n_other_f;
+	if (d->n_other_f) {
+		d->other_f = calloc(d->n_other_f, sizeof(uint32_t));
+		memcpy(d->other_f, s->other_f, d->n_other_f * sizeof(uint32_t));
+	}
+	else
+		d->other_f = NULL;
+}
+
+/* service_ids are guaranteed to be unique within one TP
+ * (the DVB standards say theay should be unique within one
+ * network, but in real life...)
+ */
+static struct service *alloc_service(struct transponder *tp, int service_id)
+{
+	struct service *s = calloc(1, sizeof(*s));
+	INIT_LIST_HEAD(&s->list);
+	s->service_id = service_id;
+	list_add_tail(&s->list, &tp->services);
+	return s;
+}
+
+static struct service *find_service(struct transponder *tp, int service_id)
+{
+	struct list_head *pos;
+	struct service *s;
+
+	list_for_each(pos, &tp->services) {
+		s = list_entry(pos, struct service, list);
+		if (s->service_id == service_id)
+			return s;
+	}
+	return NULL;
+}
+
+
+static void parse_ca_identifier_descriptor (const unsigned char *buf,
+				     struct service *s)
+{
+	unsigned char len = buf [1];
+	int i;
+
+	buf += 2;
+
+	if (len > sizeof(s->ca_id)) {
+		len = sizeof(s->ca_id);
+		warning("too many CA system ids\n");
+	}
+	memcpy(s->ca_id, buf, len);
+	for (i = 0; i < len / sizeof(s->ca_id[0]); i++)
+		moreverbose("  CA ID 0x%04x\n", s->ca_id[i]);
+}
+
+
+static void parse_iso639_language_descriptor (const unsigned char *buf, struct service *s)
+{
+	unsigned char len = buf [1];
+
+	buf += 2;
+
+	if (len >= 4) {
+		debug("    LANG=%.3s %d\n", buf, buf[3]);
+		memcpy(s->audio_lang[s->audio_num], buf, 3);
+#if 0
+		/* seems like the audio_type is wrong all over the place */
+		//if (buf[3] == 0) -> normal
+		if (buf[3] == 1)
+			s->audio_lang[s->audio_num][3] = '!'; /* clean effects (no language) */
+		else if (buf[3] == 2)
+			s->audio_lang[s->audio_num][3] = '?'; /* for the hearing impaired */
+		else if (buf[3] == 3)
+			s->audio_lang[s->audio_num][3] = '+'; /* visually impaired commentary */
+#endif
+	}
+}
+
+static void parse_network_name_descriptor (const unsigned char *buf, void *dummy)
+{
+	unsigned char len = buf [1];
+
+	info("Network Name '%.*s'\n", len, buf + 2);
+}
+
+static void parse_terrestrial_uk_channel_number (const unsigned char *buf, void *dummy)
+{
+	int i, n, channel_num, service_id;
+	struct list_head *p1, *p2;
+	struct transponder *t;
+	struct service *s;
+
+	// 32 bits per record
+	n = buf[1] / 4;
+	if (n < 1)
+		return;
+
+	// desc id, desc len, (service id, service number)
+	buf += 2;
+	for (i = 0; i < n; i++) {
+		service_id = (buf[0]<<8)|(buf[1]&0xff);
+		channel_num = (buf[2]&0x03<<8)|(buf[3]&0xff);
+		debug("Service ID 0x%x has channel number %d ", service_id, channel_num);
+		list_for_each(p1, &scanned_transponders) {
+			t = list_entry(p1, struct transponder, list);
+			list_for_each(p2, &t->services) {
+				s = list_entry(p2, struct service, list);
+				if (s->service_id == service_id)
+					s->channel_num = channel_num;
+			}
+		}
+		buf += 4;
+	}
+}
+
+
+static long bcd32_to_cpu (const int b0, const int b1, const int b2, const int b3)
+{
+	return ((b0 >> 4) & 0x0f) * 10000000 + (b0 & 0x0f) * 1000000 +
+	       ((b1 >> 4) & 0x0f) * 100000   + (b1 & 0x0f) * 10000 +
+	       ((b2 >> 4) & 0x0f) * 1000     + (b2 & 0x0f) * 100 +
+	       ((b3 >> 4) & 0x0f) * 10       + (b3 & 0x0f);
+}
+
+
+static const fe_code_rate_t fec_tab [8] = {
+	FEC_AUTO, FEC_1_2, FEC_2_3, FEC_3_4,
+	FEC_5_6, FEC_7_8, FEC_NONE, FEC_NONE
+};
+
+
+static const fe_modulation_t qam_tab [6] = {
+	QAM_AUTO, QAM_16, QAM_32, QAM_64, QAM_128, QAM_256
+};
+
+
+static void parse_cable_delivery_system_descriptor (const unsigned char *buf,
+					     struct transponder *t)
+{
+	if (!t) {
+		warning("cable_delivery_system_descriptor outside transport stream definition (ignored)\n");
+		return;
+	}
+	t->type = FE_QAM;
+
+	t->param.frequency = bcd32_to_cpu (buf[2], buf[3], buf[4], buf[5]);
+	t->param.frequency *= 100;
+	t->param.u.qam.fec_inner = fec_tab[buf[12] & 0x07];
+	t->param.u.qam.symbol_rate = 10 * bcd32_to_cpu (buf[9],
+							buf[10],
+							buf[11],
+							buf[12] & 0xf0);
+	if ((buf[8] & 0x0f) > 5)
+		t->param.u.qam.modulation = QAM_AUTO;
+	else
+		t->param.u.qam.modulation = qam_tab[buf[8] & 0x0f];
+	t->param.inversion = spectral_inversion;
+
+	if (verbosity >= 5) {
+		debug("0x%#04x/0x%#04x ", t->network_id, t->transport_stream_id);
+		dump_dvb_parameters (stderr, t);
+		if (t->scan_done)
+			dprintf(5, " (done)");
+		if (t->last_tuning_failed)
+			dprintf(5, " (tuning failed)");
+		dprintf(5, "\n");
+	}
+}
+
+static void parse_satellite_delivery_system_descriptor (const unsigned char *buf,
+						 struct transponder *t)
+{
+	if (!t) {
+		warning("satellite_delivery_system_descriptor outside transport stream definition (ignored)\n");
+		return;
+	}
+	t->type = FE_QPSK;
+	t->param.frequency = 10 * bcd32_to_cpu (buf[2], buf[3], buf[4], buf[5]);
+	t->param.u.qpsk.fec_inner = fec_tab[buf[12] & 0x07];
+	t->param.u.qpsk.symbol_rate = 10 * bcd32_to_cpu (buf[9],
+							 buf[10],
+							 buf[11],
+							 buf[12] & 0xf0);
+
+	t->polarisation = (buf[8] >> 5) & 0x03;
+	t->param.inversion = spectral_inversion;
+
+	t->orbital_pos = bcd32_to_cpu (0x00, 0x00, buf[6], buf[7]);
+	t->we_flag = buf[8] >> 7;
+
+	if (verbosity >= 5) {
+		debug("0x%#04x/0x%#04x ", t->network_id, t->transport_stream_id);
+		dump_dvb_parameters (stderr, t);
+		if (t->scan_done)
+			dprintf(5, " (done)");
+		if (t->last_tuning_failed)
+			dprintf(5, " (tuning failed)");
+		dprintf(5, "\n");
+	}
+}
+
+
+static void parse_terrestrial_delivery_system_descriptor (const unsigned char *buf,
+						   struct transponder *t)
+{
+	static const fe_modulation_t m_tab [] = { QPSK, QAM_16, QAM_64, QAM_AUTO };
+	static const fe_code_rate_t ofec_tab [8] = { FEC_1_2, FEC_2_3, FEC_3_4,
+					       FEC_5_6, FEC_7_8 };
+	struct dvb_ofdm_parameters *o;
+
+	if (!t) {
+		warning("terrestrial_delivery_system_descriptor outside transport stream definition (ignored)\n");
+		return;
+	}
+	o = &t->param.u.ofdm;
+	t->type = FE_OFDM;
+
+	t->param.frequency = (buf[2] << 24) | (buf[3] << 16);
+	t->param.frequency |= (buf[4] << 8) | buf[5];
+	t->param.frequency *= 10;
+	t->param.inversion = spectral_inversion;
+
+	o->bandwidth = BANDWIDTH_8_MHZ + ((buf[6] >> 5) & 0x3);
+	o->constellation = m_tab[(buf[7] >> 6) & 0x3];
+	o->hierarchy_information = HIERARCHY_NONE + ((buf[7] >> 3) & 0x3);
+
+	if ((buf[7] & 0x7) > 4)
+		o->code_rate_HP = FEC_AUTO;
+	else
+		o->code_rate_HP = ofec_tab [buf[7] & 0x7];
+
+	if (((buf[8] >> 5) & 0x7) > 4)
+		o->code_rate_LP = FEC_AUTO;
+	else
+		o->code_rate_LP = ofec_tab [(buf[8] >> 5) & 0x7];
+
+	o->guard_interval = GUARD_INTERVAL_1_32 + ((buf[8] >> 3) & 0x3);
+
+	o->transmission_mode = (buf[8] & 0x2) ?
+			       TRANSMISSION_MODE_8K :
+			       TRANSMISSION_MODE_2K;
+
+	t->other_frequency_flag = (buf[8] & 0x01);
+
+	if (verbosity >= 5) {
+		debug("0x%#04x/0x%#04x ", t->network_id, t->transport_stream_id);
+		dump_dvb_parameters (stderr, t);
+		if (t->scan_done)
+			dprintf(5, " (done)");
+		if (t->last_tuning_failed)
+			dprintf(5, " (tuning failed)");
+		dprintf(5, "\n");
+	}
+}
+
+static void parse_frequency_list_descriptor (const unsigned char *buf,
+				      struct transponder *t)
+{
+	int n, i;
+	typeof(*t->other_f) f;
+
+	if (!t) {
+		warning("frequency_list_descriptor outside transport stream definition (ignored)\n");
+		return;
+	}
+	if (t->other_f)
+		return;
+
+	n = (buf[1] - 1) / 4;
+	if (n < 1 || (buf[2] & 0x03) != 3)
+		return;
+
+	t->other_f = calloc(n, sizeof(*t->other_f));
+	t->n_other_f = n;
+	buf += 3;
+	for (i = 0; i < n; i++) {
+		f = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+		t->other_f[i] = f * 10;
+		buf += 4;
+	}
+}
+
+static void parse_service_descriptor (const unsigned char *buf, struct service *s)
+{
+	unsigned char len;
+	unsigned char *src, *dest;
+
+	s->type = buf[2];
+
+	buf += 3;
+	len = *buf;
+	buf++;
+
+	if (s->provider_name)
+		free (s->provider_name);
+
+	s->provider_name = malloc (len + 1);
+	memcpy (s->provider_name, buf, len);
+	s->provider_name[len] = '\0';
+
+	/* remove control characters (FIXME: handle short/long name) */
+	/* FIXME: handle character set correctly (e.g. via iconv)
+	 * c.f. EN 300 468 annex A */
+	for (src = dest = s->provider_name; *src; src++)
+		if (*src >= 0x20 && (*src < 0x80 || *src > 0x9f))
+			*dest++ = *src;
+	*dest = '\0';
+	if (!s->provider_name[0]) {
+		/* zap zero length names */
+		free (s->provider_name);
+		s->provider_name = 0;
+	}
+
+	if (s->service_name)
+		free (s->service_name);
+
+	buf += len;
+	len = *buf;
+	buf++;
+
+	s->service_name = malloc (len + 1);
+	memcpy (s->service_name, buf, len);
+	s->service_name[len] = '\0';
+
+	/* remove control characters (FIXME: handle short/long name) */
+	/* FIXME: handle character set correctly (e.g. via iconv)
+	 * c.f. EN 300 468 annex A */
+	for (src = dest = s->service_name; *src; src++)
+		if (*src >= 0x20 && (*src < 0x80 || *src > 0x9f))
+			*dest++ = *src;
+	*dest = '\0';
+	if (!s->service_name[0]) {
+		/* zap zero length names */
+		free (s->service_name);
+		s->service_name = 0;
+	}
+
+	info("0x%04x 0x%04x: pmt_pid 0x%04x %s -- %s (%s%s)\n",
+	    s->transport_stream_id,
+	    s->service_id,
+	    s->pmt_pid,
+	    s->provider_name, s->service_name,
+	    s->running == RM_NOT_RUNNING ? "not running" :
+	    s->running == RM_STARTS_SOON ? "starts soon" :
+	    s->running == RM_PAUSING     ? "pausing" :
+	    s->running == RM_RUNNING     ? "running" : "???",
+	    s->scrambled ? ", scrambled" : "");
+}
+
+static int find_descriptor(uint8_t tag, const unsigned char *buf,
+		int descriptors_loop_len,
+		const unsigned char **desc, int *desc_len)
+{
+	while (descriptors_loop_len > 0) {
+		unsigned char descriptor_tag = buf[0];
+		unsigned char descriptor_len = buf[1] + 2;
+
+		if (!descriptor_len) {
+			warning("descriptor_tag == 0x%02x, len is 0\n", descriptor_tag);
+			break;
+		}
+
+		if (tag == descriptor_tag) {
+			if (desc)
+				*desc = buf;
+			if (desc_len)
+				*desc_len = descriptor_len;
+			return 1;
+		}
+
+		buf += descriptor_len;
+		descriptors_loop_len -= descriptor_len;
+	}
+	return 0;
+}
+
+static void parse_descriptors(enum table_type t, const unsigned char *buf,
+			      int descriptors_loop_len, void *data)
+{
+	while (descriptors_loop_len > 0) {
+		unsigned char descriptor_tag = buf[0];
+		unsigned char descriptor_len = buf[1] + 2;
+
+		if (!descriptor_len) {
+			warning("descriptor_tag == 0x%02x, len is 0\n", descriptor_tag);
+			break;
+		}
+
+		switch (descriptor_tag) {
+		case 0x0a:
+			if (t == PMT)
+				parse_iso639_language_descriptor (buf, data);
+			break;
+
+		case 0x40:
+			if (t == NIT)
+				parse_network_name_descriptor (buf, data);
+			break;
+
+		case 0x43:
+			if (t == NIT)
+				parse_satellite_delivery_system_descriptor (buf, data);
+			break;
+
+		case 0x44:
+			if (t == NIT)
+				parse_cable_delivery_system_descriptor (buf, data);
+			break;
+
+		case 0x48:
+			if (t == SDT)
+				parse_service_descriptor (buf, data);
+			break;
+
+		case 0x53:
+			if (t == SDT)
+				parse_ca_identifier_descriptor (buf, data);
+			break;
+
+		case 0x5a:
+			if (t == NIT)
+				parse_terrestrial_delivery_system_descriptor (buf, data);
+			break;
+
+		case 0x62:
+			if (t == NIT)
+				parse_frequency_list_descriptor (buf, data);
+			break;
+
+		case 0x83:
+			/* 0x83 is in the privately defined range of descriptor tags,
+			 * so we parse this only if the user says so to avoid
+			 * problems when 0x83 is something entirely different... */
+			if (t == NIT && vdr_dump_channum)
+				parse_terrestrial_uk_channel_number (buf, data);
+			break;
+
+		default:
+			verbosedebug("skip descriptor 0x%02x\n", descriptor_tag);
+		};
+
+		buf += descriptor_len;
+		descriptors_loop_len -= descriptor_len;
+	}
+}
+
+
+static void parse_pat(const unsigned char *buf, int section_length,
+		      int transport_stream_id)
+{
+	while (section_length > 0) {
+		struct service *s;
+		int service_id = (buf[0] << 8) | buf[1];
+
+		if (service_id == 0) {
+			buf += 4;		/*  skip nit pid entry... */
+			section_length -= 4;
+			continue;
+		}
+		/* SDT might have been parsed first... */
+		s = find_service(current_tp, service_id);
+		if (!s)
+			s = alloc_service(current_tp, service_id);
+		s->pmt_pid = ((buf[2] & 0x1f) << 8) | buf[3];
+		if (!s->priv && s->pmt_pid) {
+			s->priv = malloc(sizeof(struct section_buf));
+			setup_filter(s->priv, demux_devname,
+				     s->pmt_pid, 0x02, 1, 0, 5);
+
+			add_filter (s->priv);
+		}
+
+		buf += 4;
+		section_length -= 4;
+	};
+}
+
+
+static void parse_pmt (const unsigned char *buf, int section_length, int service_id)
+{
+	int program_info_len;
+	struct service *s;
+        char msg_buf[14 * AUDIO_CHAN_MAX + 1];
+        char *tmp;
+        int i;
+
+	s = find_service (current_tp, service_id);
+	if (!s) {
+		error("PMT for serivce_id 0x%04x was not in PAT\n", service_id);
+		return;
+	}
+
+	s->pcr_pid = ((buf[0] & 0x1f) << 8) | buf[1];
+
+	program_info_len = ((buf[2] & 0x0f) << 8) | buf[3];
+
+	buf += program_info_len + 4;
+	section_length -= program_info_len + 4;
+
+	while (section_length > 0) {
+		int ES_info_len = ((buf[3] & 0x0f) << 8) | buf[4];
+		int elementary_pid = ((buf[1] & 0x1f) << 8) | buf[2];
+
+		switch (buf[0]) {
+		case 0x01:
+		case 0x02:
+			moreverbose("  VIDEO     : PID 0x%04x\n", elementary_pid);
+			if (s->video_pid == 0)
+				s->video_pid = elementary_pid;
+			break;
+		case 0x03:
+		case 0x04:
+			moreverbose("  AUDIO     : PID 0x%04x\n", elementary_pid);
+			if (s->audio_num < AUDIO_CHAN_MAX) {
+				s->audio_pid[s->audio_num] = elementary_pid;
+				parse_descriptors (PMT, buf + 5, ES_info_len, s);
+				s->audio_num++;
+			}
+			else
+				warning("more than %i audio channels, truncating\n",
+				     AUDIO_CHAN_MAX);
+			break;
+		case 0x06:
+			if (find_descriptor(0x56, buf + 5, ES_info_len, NULL, NULL)) {
+				moreverbose("  TELETEXT  : PID 0x%04x\n", elementary_pid);
+				s->teletext_pid = elementary_pid;
+				break;
+			}
+			else if (find_descriptor(0x59, buf + 5, ES_info_len, NULL, NULL)) {
+				/* Note: The subtitling descriptor can also signal
+				 * teletext subtitling, but then the teletext descriptor
+				 * will also be present; so we can be quite confident
+				 * that we catch DVB subtitling streams only here, w/o
+				 * parsing the descriptor. */
+				moreverbose("  SUBTITLING: PID 0x%04x\n", elementary_pid);
+				s->subtitling_pid = elementary_pid;
+				break;
+			}
+			else if (find_descriptor(0x6a, buf + 5, ES_info_len, NULL, NULL)) {
+				moreverbose("  AC3       : PID 0x%04x\n", elementary_pid);
+				s->ac3_pid = elementary_pid;
+				break;
+			}
+			/* fall through */
+		default:
+			moreverbose("  OTHER     : PID 0x%04x TYPE 0x%02x\n", elementary_pid, buf[0]);
+		};
+
+		buf += ES_info_len + 5;
+		section_length -= ES_info_len + 5;
+	};
+
+
+        tmp = msg_buf;
+        tmp += sprintf(tmp, "0x%04x (%.4s)", s->audio_pid[0], s->audio_lang[0]);
+
+	if (s->audio_num > AUDIO_CHAN_MAX) {
+		warning("more than %i audio channels: %i, truncating to %i\n",
+		      AUDIO_CHAN_MAX, s->audio_num, AUDIO_CHAN_MAX);
+		s->audio_num = AUDIO_CHAN_MAX;
+	}
+
+        for (i=1; i<s->audio_num; i++)
+                tmp += sprintf(tmp, ", 0x%04x (%.4s)", s->audio_pid[i], s->audio_lang[i]);
+
+        debug("0x%04x 0x%04x: %s -- %s, pmt_pid 0x%04x, vpid 0x%04x, apid %s\n",
+	    s->transport_stream_id,
+	    s->service_id,
+	    s->provider_name, s->service_name,
+	    s->pmt_pid, s->video_pid, msg_buf);
+}
+
+
+static void parse_nit (const unsigned char *buf, int section_length, int network_id)
+{
+	int descriptors_loop_len = ((buf[0] & 0x0f) << 8) | buf[1];
+
+	if (section_length < descriptors_loop_len + 4)
+	{
+		warning("section too short: network_id == 0x%04x, section_length == %i, "
+		     "descriptors_loop_len == %i\n",
+		     network_id, section_length, descriptors_loop_len);
+		return;
+	}
+
+	parse_descriptors (NIT, buf + 2, descriptors_loop_len, NULL);
+
+	section_length -= descriptors_loop_len + 4;
+	buf += descriptors_loop_len + 4;
+
+	while (section_length > 6) {
+		int transport_stream_id = (buf[0] << 8) | buf[1];
+		struct transponder *t, tn;
+
+		descriptors_loop_len = ((buf[4] & 0x0f) << 8) | buf[5];
+
+		if (section_length < descriptors_loop_len + 4)
+		{
+			warning("section too short: transport_stream_id == 0x%04x, "
+			     "section_length == %i, descriptors_loop_len == %i\n",
+			     transport_stream_id, section_length,
+			     descriptors_loop_len);
+			break;
+		}
+
+		debug("transport_stream_id 0x%04x\n", transport_stream_id);
+
+		memset(&tn, 0, sizeof(tn));
+		tn.type = -1;
+		tn.network_id = network_id;
+		tn.transport_stream_id = transport_stream_id;
+
+		parse_descriptors (NIT, buf + 6, descriptors_loop_len, &tn);
+
+		if (tn.type == fe_info.type) {
+			/* only add if develivery_descriptor matches FE type */
+			t = find_transponder(tn.param.frequency);
+			if (!t)
+				t = alloc_transponder(tn.param.frequency);
+			copy_transponder(t, &tn);
+		}
+
+		section_length -= descriptors_loop_len + 6;
+		buf += descriptors_loop_len + 6;
+	};
+}
+
+
+static void parse_sdt (const unsigned char *buf, int section_length,
+		int transport_stream_id)
+{
+	buf += 3;	       /*  skip original network id + reserved field */
+
+	while (section_length > 4) {
+		int service_id = (buf[0] << 8) | buf[1];
+		int descriptors_loop_len = ((buf[3] & 0x0f) << 8) | buf[4];
+		struct service *s;
+
+		if (section_length < descriptors_loop_len || !descriptors_loop_len)
+		{
+			warning("section too short: service_id == 0x%02x, section_length == %i, "
+			     "descriptors_loop_len == %i\n",
+			     service_id, section_length,
+			     descriptors_loop_len);
+			break;
+		}
+
+		s = find_service(current_tp, service_id);
+		if (!s)
+			/* maybe PAT has not yet been parsed... */
+			s = alloc_service(current_tp, service_id);
+
+		s->running = (buf[3] >> 5) & 0x7;
+		s->scrambled = (buf[3] >> 4) & 1;
+
+		parse_descriptors (SDT, buf + 5, descriptors_loop_len, s);
+
+		section_length -= descriptors_loop_len + 5;
+		buf += descriptors_loop_len + 5;
+	};
+}
+
+
+static int get_bit (uint8_t *bitfield, int bit)
+{
+	return (bitfield[bit/8] >> (bit % 8)) & 1;
+}
+
+static void set_bit (uint8_t *bitfield, int bit)
+{
+	bitfield[bit/8] |= 1 << (bit % 8);
+}
+
+
+/**
+ *   returns 0 when more sections are expected
+ *	   1 when all sections are read on this pid
+ *	   -1 on invalid table id
+ */
+static int parse_section (struct section_buf *s)
+{
+	const unsigned char *buf = s->buf;
+	int table_id;
+	int section_length;
+	int table_id_ext;
+	int section_version_number;
+	int section_number;
+	int last_section_number;
+	int i;
+
+	table_id = buf[0];
+
+	if (s->table_id != table_id)
+		return -1;
+
+	section_length = (((buf[1] & 0x0f) << 8) | buf[2]) - 11;
+
+	table_id_ext = (buf[3] << 8) | buf[4];
+	section_version_number = (buf[5] >> 1) & 0x1f;
+	section_number = buf[6];
+	last_section_number = buf[7];
+
+	if (s->segmented && s->table_id_ext != -1 && s->table_id_ext != table_id_ext) {
+		/* find or allocate actual section_buf matching table_id_ext */
+		while (s->next_seg) {
+			s = s->next_seg;
+			if (s->table_id_ext == table_id_ext)
+				break;
+		}
+		if (s->table_id_ext != table_id_ext) {
+			assert(s->next_seg == NULL);
+			s->next_seg = calloc(1, sizeof(struct section_buf));
+			s->next_seg->segmented = s->segmented;
+			s->next_seg->run_once = s->run_once;
+			s->next_seg->timeout = s->timeout;
+			s = s->next_seg;
+			s->table_id = table_id;
+			s->table_id_ext = table_id_ext;
+			s->section_version_number = section_version_number;
+		}
+	}
+
+	if (s->section_version_number != section_version_number ||
+			s->table_id_ext != table_id_ext) {
+		struct section_buf *next_seg = s->next_seg;
+
+		if (s->section_version_number != -1 && s->table_id_ext != -1)
+			debug("section version_number or table_id_ext changed "
+				"%d -> %d / %04x -> %04x\n",
+				s->section_version_number, section_version_number,
+				s->table_id_ext, table_id_ext);
+		s->table_id_ext = table_id_ext;
+		s->section_version_number = section_version_number;
+		s->sectionfilter_done = 0;
+		memset (s->section_done, 0, sizeof(s->section_done));
+		s->next_seg = next_seg;
+	}
+
+	buf += 8;
+
+	if (!get_bit(s->section_done, section_number)) {
+		set_bit (s->section_done, section_number);
+
+		debug("pid 0x%02x tid 0x%02x table_id_ext 0x%04x, "
+		    "%i/%i (version %i)\n",
+		    s->pid, table_id, table_id_ext, section_number,
+		    last_section_number, section_version_number);
+
+		switch (table_id) {
+		case 0x00:
+			verbose("PAT\n");
+			parse_pat (buf, section_length, table_id_ext);
+			break;
+
+		case 0x02:
+			verbose("PMT 0x%04x for service 0x%04x\n", s->pid, table_id_ext);
+			parse_pmt (buf, section_length, table_id_ext);
+			break;
+
+		case 0x41:
+			verbose("////////////////////////////////////////////// NIT other\n");
+		case 0x40:
+			verbose("NIT (%s TS)\n", table_id == 0x40 ? "actual":"other");
+			parse_nit (buf, section_length, table_id_ext);
+			break;
+
+		case 0x42:
+		case 0x46:
+			verbose("SDT (%s TS)\n", table_id == 0x42 ? "actual":"other");
+			parse_sdt (buf, section_length, table_id_ext);
+			break;
+
+		default:
+			;
+		};
+
+		for (i = 0; i <= last_section_number; i++)
+			if (get_bit (s->section_done, i) == 0)
+				break;
+
+		if (i > last_section_number)
+			s->sectionfilter_done = 1;
+	}
+
+	if (s->segmented) {
+		/* always wait for timeout; this is because we don't now how
+		 * many segments there are
+		 */
+		return 0;
+	}
+	else if (s->sectionfilter_done)
+		return 1;
+
+	return 0;
+}
+
+
+static int read_sections (struct section_buf *s)
+{
+	int section_length, count;
+
+	if (s->sectionfilter_done && !s->segmented)
+		return 1;
+
+	/* the section filter API guarantess that we get one full section
+	 * per read(), provided that the buffer is large enough (it is)
+	 */
+	if (((count = read (s->fd, s->buf, sizeof(s->buf))) < 0) && errno == EOVERFLOW)
+		count = read (s->fd, s->buf, sizeof(s->buf));
+	if (count < 0) {
+		errorn("read_sections: read error");
+		return -1;
+	}
+
+	if (count < 4)
+		return -1;
+
+	section_length = ((s->buf[1] & 0x0f) << 8) | s->buf[2];
+
+	if (count != section_length + 3)
+		return -1;
+
+	if (parse_section(s) == 1)
+		return 1;
+
+	return 0;
+}
+
+
+static LIST_HEAD(running_filters);
+static LIST_HEAD(waiting_filters);
+static int n_running;
+#define MAX_RUNNING 32
+static struct pollfd poll_fds[MAX_RUNNING];
+static struct section_buf* poll_section_bufs[MAX_RUNNING];
+
+
+static void setup_filter (struct section_buf* s, const char *dmx_devname,
+			  int pid, int tid, int run_once, int segmented, int timeout)
+{
+	memset (s, 0, sizeof(struct section_buf));
+
+	s->fd = -1;
+	s->dmx_devname = dmx_devname;
+	s->pid = pid;
+	s->table_id = tid;
+
+	s->run_once = run_once;
+	s->segmented = segmented;
+
+	if (long_timeout)
+		s->timeout = 5 * timeout;
+	else
+		s->timeout = timeout;
+
+	s->table_id_ext = -1;
+	s->section_version_number = -1;
+
+	INIT_LIST_HEAD (&s->list);
+}
+
+static void update_poll_fds(void)
+{
+	struct list_head *p;
+	struct section_buf* s;
+	int i;
+
+	memset(poll_section_bufs, 0, sizeof(poll_section_bufs));
+	for (i = 0; i < MAX_RUNNING; i++)
+		poll_fds[i].fd = -1;
+	i = 0;
+	list_for_each (p, &running_filters) {
+		if (i >= MAX_RUNNING)
+			fatal("too many poll_fds\n");
+		s = list_entry (p, struct section_buf, list);
+		if (s->fd == -1)
+			fatal("s->fd == -1 on running_filters\n");
+		verbosedebug("poll fd %d\n", s->fd);
+		poll_fds[i].fd = s->fd;
+		poll_fds[i].events = POLLIN;
+		poll_fds[i].revents = 0;
+		poll_section_bufs[i] = s;
+		i++;
+	}
+	if (i != n_running)
+		fatal("n_running is hosed\n");
+}
+
+static int start_filter (struct section_buf* s)
+{
+	struct dmx_sct_filter_params f;
+
+	if (n_running >= MAX_RUNNING)
+		goto err0;
+	if ((s->fd = open (s->dmx_devname, O_RDWR | O_NONBLOCK)) < 0)
+		goto err0;
+
+	verbosedebug("start filter pid 0x%04x table_id 0x%02x\n", s->pid, s->table_id);
+
+	memset(&f, 0, sizeof(f));
+
+	f.pid = (uint16_t) s->pid;
+
+	if (s->table_id < 0x100 && s->table_id > 0) {
+		f.filter.filter[0] = (uint8_t) s->table_id;
+		f.filter.mask[0]   = 0xff;
+	}
+
+	f.timeout = 0;
+	f.flags = DMX_IMMEDIATE_START | DMX_CHECK_CRC;
+
+	if (ioctl(s->fd, DMX_SET_FILTER, &f) == -1) {
+		errorn ("ioctl DMX_SET_FILTER failed");
+		goto err1;
+	}
+
+	s->sectionfilter_done = 0;
+	time(&s->start_time);
+
+	list_del_init (&s->list);  /* might be in waiting filter list */
+	list_add (&s->list, &running_filters);
+
+	n_running++;
+	update_poll_fds();
+
+	return 0;
+
+err1:
+	ioctl (s->fd, DMX_STOP);
+	close (s->fd);
+err0:
+	return -1;
+}
+
+
+static void stop_filter (struct section_buf *s)
+{
+	verbosedebug("stop filter pid 0x%04x\n", s->pid);
+	ioctl (s->fd, DMX_STOP);
+	close (s->fd);
+	s->fd = -1;
+	list_del (&s->list);
+	s->running_time += time(NULL) - s->start_time;
+
+	n_running--;
+	update_poll_fds();
+}
+
+
+static void add_filter (struct section_buf *s)
+{
+	verbosedebug("add filter pid 0x%04x\n", s->pid);
+	if (start_filter (s))
+		list_add_tail (&s->list, &waiting_filters);
+}
+
+
+static void remove_filter (struct section_buf *s)
+{
+	verbosedebug("remove filter pid 0x%04x\n", s->pid);
+	stop_filter (s);
+
+	while (!list_empty(&waiting_filters)) {
+		struct list_head *next = waiting_filters.next;
+		s = list_entry (next, struct section_buf, list);
+		if (start_filter (s))
+			break;
+	};
+}
+
+
+static void read_filters (void)
+{
+	struct section_buf *s;
+	int i, n, done;
+
+	n = poll(poll_fds, n_running, 1000);
+	if (n == -1)
+		errorn("poll");
+
+	for (i = 0; i < n_running; i++) {
+		s = poll_section_bufs[i];
+		if (!s)
+			fatal("poll_section_bufs[%d] is NULL\n", i);
+		if (poll_fds[i].revents)
+			done = read_sections (s) == 1;
+		else
+			done = 0; /* timeout */
+		if (done || time(NULL) > s->start_time + s->timeout) {
+			if (s->run_once) {
+				if (done)
+					verbosedebug("filter done pid 0x%04x\n", s->pid);
+				else
+					warning("filter timeout pid 0x%04x\n", s->pid);
+				remove_filter (s);
+			}
+		}
+	}
+}
+
+
+static int mem_is_zero (const void *mem, int size)
+{
+	const char *p = mem;
+	unsigned long i;
+
+	for (i=0; i<size; i++) {
+		if (p[i] != 0x00)
+			return 0;
+	}
+
+	return 1;
+}
+
+
+static int switch_pos = 0;
+
+static int __tune_to_transponder (int frontend_fd, struct transponder *t)
+{
+	struct dvb_frontend_parameters p;
+	fe_status_t s;
+	int i;
+
+	current_tp = t;
+
+	if (mem_is_zero (&t->param, sizeof(struct dvb_frontend_parameters)))
+		return -1;
+
+	memcpy (&p, &t->param, sizeof(struct dvb_frontend_parameters));
+
+	if (verbosity >= 1) {
+		dprintf(1, ">>> tune to: ");
+		dump_dvb_parameters (stderr, t);
+		if (t->last_tuning_failed)
+			dprintf(1, " (tuning failed)");
+		dprintf(1, "\n");
+	}
+
+	if (t->type == FE_QPSK) {
+		int hiband = 0;
+
+		if (lnb_type.switch_val && lnb_type.high_val &&
+			p.frequency >= lnb_type.switch_val)
+			hiband = 1;
+
+		setup_switch (frontend_fd,
+			      switch_pos,
+			      t->polarisation == POLARISATION_VERTICAL ? 0 : 1,
+			      hiband);
+		usleep(50000);
+		if (hiband)
+			p.frequency = abs(p.frequency - lnb_type.high_val);
+		else
+			p.frequency = abs(p.frequency - lnb_type.low_val);
+	}
+
+	if (ioctl(frontend_fd, FE_SET_FRONTEND, &p) == -1) {
+		errorn("Setting frontend parameters failed");
+		return -1;
+	}
+
+	for (i = 0; i < 10; i++) {
+		usleep (200000);
+
+		if (ioctl(frontend_fd, FE_READ_STATUS, &s) == -1) {
+			errorn("FE_READ_STATUS failed");
+			return -1;
+		}
+
+		verbose(">>> tuning status == 0x%02x\n", s);
+
+		if (s & FE_HAS_LOCK) {
+			t->last_tuning_failed = 0;
+			return 0;
+		}
+	}
+
+	warning(">>> tuning failed!!!\n");
+
+	t->last_tuning_failed = 1;
+
+	return -1;
+}
+
+static int tune_to_transponder (int frontend_fd, struct transponder *t)
+{
+	/* move TP from "new" to "scanned" list */
+	list_del_init(&t->list);
+	list_add_tail(&t->list, &scanned_transponders);
+	t->scan_done = 1;
+
+	if (t->type != fe_info.type) {
+		/* ignore cable descriptors in sat NIT and vice versa */
+		t->last_tuning_failed = 1;
+		return -1;
+	}
+
+	if (__tune_to_transponder (frontend_fd, t) == 0)
+		return 0;
+
+	return __tune_to_transponder (frontend_fd, t);
+}
+
+
+static int tune_to_next_transponder (int frontend_fd)
+{
+	struct list_head *pos, *tmp;
+	struct transponder *t;
+
+	list_for_each_safe(pos, tmp, &new_transponders) {
+		t = list_entry (pos, struct transponder, list);
+retry:
+		if (tune_to_transponder (frontend_fd, t) == 0)
+			return 0;
+		if (t->other_frequency_flag &&
+				t->other_f &&
+				t->n_other_f) {
+			t->param.frequency = t->other_f[t->n_other_f - 1];
+			t->n_other_f--;
+			info("retrying with f=%d\n", t->param.frequency);
+			goto retry;
+		}
+	}
+	return -1;
+}
+
+struct strtab {
+	const char *str;
+	int val;
+};
+static int str2enum(const char *str, const struct strtab *tab, int deflt)
+{
+	while (tab->str) {
+		if (!strcmp(tab->str, str))
+			return tab->val;
+		tab++;
+	}
+	error("invalid enum value '%s'\n", str);
+	return deflt;
+}
+
+static enum fe_code_rate str2fec(const char *fec)
+{
+	struct strtab fectab[] = {
+		{ "NONE", FEC_NONE },
+		{ "1/2",  FEC_1_2 },
+		{ "2/3",  FEC_2_3 },
+		{ "3/4",  FEC_3_4 },
+		{ "4/5",  FEC_4_5 },
+		{ "5/6",  FEC_5_6 },
+		{ "6/7",  FEC_6_7 },
+		{ "7/8",  FEC_7_8 },
+		{ "8/9",  FEC_8_9 },
+		{ "AUTO", FEC_AUTO },
+		{ NULL, 0 }
+	};
+	return str2enum(fec, fectab, FEC_AUTO);
+}
+
+static enum fe_modulation str2qam(const char *qam)
+{
+	struct strtab qamtab[] = {
+		{ "QPSK",   QPSK },
+		{ "QAM16",  QAM_16 },
+		{ "QAM32",  QAM_32 },
+		{ "QAM64",  QAM_64 },
+		{ "QAM128", QAM_128 },
+		{ "QAM256", QAM_256 },
+		{ "AUTO",   QAM_AUTO },
+		{ NULL, 0 }
+	};
+	return str2enum(qam, qamtab, QAM_AUTO);
+}
+
+static enum fe_bandwidth str2bandwidth(const char *bw)
+{
+	struct strtab bwtab[] = {
+		{ "8MHz", BANDWIDTH_8_MHZ },
+		{ "7MHz", BANDWIDTH_7_MHZ },
+		{ "6MHz", BANDWIDTH_6_MHZ },
+		{ "AUTO", BANDWIDTH_AUTO },
+		{ NULL, 0 }
+	};
+	return str2enum(bw, bwtab, BANDWIDTH_AUTO);
+}
+
+static enum fe_transmit_mode str2mode(const char *mode)
+{
+	struct strtab modetab[] = {
+		{ "2k",   TRANSMISSION_MODE_2K },
+		{ "8k",   TRANSMISSION_MODE_8K },
+		{ "AUTO", TRANSMISSION_MODE_AUTO },
+		{ NULL, 0 }
+	};
+	return str2enum(mode, modetab, TRANSMISSION_MODE_AUTO);
+}
+
+static enum fe_guard_interval str2guard(const char *guard)
+{
+	struct strtab guardtab[] = {
+		{ "1/32", GUARD_INTERVAL_1_32 },
+		{ "1/16", GUARD_INTERVAL_1_16 },
+		{ "1/8",  GUARD_INTERVAL_1_8 },
+		{ "1/4",  GUARD_INTERVAL_1_4 },
+		{ "AUTO", GUARD_INTERVAL_AUTO },
+		{ NULL, 0 }
+	};
+	return str2enum(guard, guardtab, GUARD_INTERVAL_AUTO);
+}
+
+static enum fe_hierarchy str2hier(const char *hier)
+{
+	struct strtab hiertab[] = {
+		{ "NONE", HIERARCHY_NONE },
+		{ "1",    HIERARCHY_1 },
+		{ "2",    HIERARCHY_2 },
+		{ "4",    HIERARCHY_4 },
+		{ "AUTO", HIERARCHY_AUTO },
+		{ NULL, 0 }
+	};
+	return str2enum(hier, hiertab, HIERARCHY_AUTO);
+}
+
+static int tune_initial (int frontend_fd, const char *initial)
+{
+	FILE *inif;
+	unsigned int f, sr;
+	char buf[200];
+	char pol[20], fec[20], qam[20], bw[20], fec2[20], mode[20], guard[20], hier[20];
+	struct transponder *t;
+
+	inif = fopen(initial, "r");
+	if (!inif) {
+		error("cannot open '%s': %d %m\n", initial, errno);
+		return -1;
+	}
+	while (fgets(buf, sizeof(buf), inif)) {
+		if (buf[0] == '#' || buf[0] == '\n')
+			;
+		else if (sscanf(buf, "S %u %1[HVLR] %u %4s\n", &f, pol, &sr, fec) == 4) {
+			t = alloc_transponder(f);
+			t->type = FE_QPSK;
+			switch(pol[0]) {
+				case 'H':
+				case 'L':
+					t->polarisation = POLARISATION_HORIZONTAL;
+					break;
+				default:
+					t->polarisation = POLARISATION_VERTICAL;;
+					break;
+			}
+			t->param.inversion = spectral_inversion;
+			t->param.u.qpsk.symbol_rate = sr;
+			t->param.u.qpsk.fec_inner = str2fec(fec);
+			info("initial transponder %u %c %u %d\n",
+					t->param.frequency,
+					pol[0], sr,
+					t->param.u.qpsk.fec_inner);
+		}
+		else if (sscanf(buf, "C %u %u %4s %6s\n", &f, &sr, fec, qam) == 4) {
+			t = alloc_transponder(f);
+			t->type = FE_QAM;
+			t->param.inversion = spectral_inversion;
+			t->param.u.qam.symbol_rate = sr;
+			t->param.u.qam.fec_inner = str2fec(fec);
+			t->param.u.qam.modulation = str2qam(qam);
+			info("initial transponder %u %u %d %d\n",
+					t->param.frequency,
+					sr,
+					t->param.u.qam.fec_inner,
+					t->param.u.qam.modulation);
+		}
+		else if (sscanf(buf, "T %u %4s %4s %4s %7s %4s %4s %4s\n",
+					&f, bw, fec, fec2, qam, mode, guard, hier) == 8) {
+			t = alloc_transponder(f);
+			t->type = FE_OFDM;
+			t->param.inversion = spectral_inversion;
+			t->param.u.ofdm.bandwidth = str2bandwidth(bw);
+			t->param.u.ofdm.code_rate_HP = str2fec(fec);
+			t->param.u.ofdm.code_rate_LP = str2fec(fec2);
+			t->param.u.ofdm.constellation = str2qam(qam);
+			t->param.u.ofdm.transmission_mode = str2mode(mode);
+			t->param.u.ofdm.guard_interval = str2guard(guard);
+			t->param.u.ofdm.hierarchy_information = str2hier(hier);
+			info("initial transponder %u %d %d %d %d %d %d %d\n",
+					t->param.frequency,
+					t->param.u.ofdm.bandwidth,
+					t->param.u.ofdm.code_rate_HP,
+					t->param.u.ofdm.code_rate_LP,
+					t->param.u.ofdm.constellation,
+					t->param.u.ofdm.transmission_mode,
+					t->param.u.ofdm.guard_interval,
+					t->param.u.ofdm.hierarchy_information);
+		}
+		else
+			error("cannot parse'%s'\n", buf);
+	}
+
+	fclose(inif);
+
+	return tune_to_next_transponder(frontend_fd);
+}
+
+
+static void scan_tp (void)
+{
+	struct section_buf s0;
+	struct section_buf s1;
+	struct section_buf s2;
+	struct section_buf s3;
+
+	/**
+	 *  filter timeouts > min repetition rates specified in ETR211
+	 */
+	setup_filter (&s0, demux_devname, 0x00, 0x00, 1, 0, 5); /* PAT */
+	setup_filter (&s1, demux_devname, 0x11, 0x42, 1, 0, 5); /* SDT */
+
+	add_filter (&s0);
+	add_filter (&s1);
+
+	if (!current_tp_only || output_format != OUTPUT_PIDS) {
+		setup_filter (&s2, demux_devname, 0x10, 0x40, 1, 0, 15); /* NIT */
+		add_filter (&s2);
+		if (get_other_nits) {
+			/* get NIT-others
+			 * Note: There is more than one NIT-other: one per
+			 * network, separated by the network_id.
+			 */
+			setup_filter (&s3, demux_devname, 0x10, 0x41, 1, 1, 15);
+			add_filter (&s3);
+		}
+	}
+
+	do {
+		read_filters ();
+	} while (!(list_empty(&running_filters) &&
+		   list_empty(&waiting_filters)));
+}
+
+static void scan_network (int frontend_fd, const char *initial)
+{
+	if (tune_initial (frontend_fd, initial) < 0) {
+		error("initial tuning failed\n");
+		return;
+	}
+
+	do {
+		scan_tp();
+	} while (tune_to_next_transponder(frontend_fd) == 0);
+}
+
+
+static void pids_dump_service_parameter_set(FILE *f, struct service *s)
+{
+        int i;
+
+	fprintf(f, "%-24.24s (0x%04x) %02x: ", s->service_name, s->service_id, s->type);
+	if (!s->pcr_pid || (s->type > 2))
+		fprintf(f, "           ");
+	else if (s->pcr_pid == s->video_pid)
+		fprintf(f, "PCR == V   ");
+	else if ((s->audio_num == 1) && (s->pcr_pid == s->audio_pid[0]))
+		fprintf(f, "PCR == A   ");
+	else
+		fprintf(f, "PCR 0x%04x ", s->pcr_pid);
+	if (s->video_pid)
+		fprintf(f, "V 0x%04x", s->video_pid);
+	else
+		fprintf(f, "        ");
+	if (s->audio_num)
+		fprintf(f, " A");
+        for (i = 0; i < s->audio_num; i++) {
+		fprintf(f, " 0x%04x", s->audio_pid[i]);
+		if (s->audio_lang[i][0])
+			fprintf(f, " (%.3s)", s->audio_lang[i]);
+		else if (s->audio_num == 1)
+			fprintf(f, "      ");
+	}
+	if (s->teletext_pid)
+		fprintf(f, " TT 0x%04x", s->teletext_pid);
+	if (s->ac3_pid)
+		fprintf(f, " AC3 0x%04x", s->ac3_pid);
+	if (s->subtitling_pid)
+		fprintf(f, " SUB 0x%04x", s->subtitling_pid);
+	fprintf(f, "\n");
+}
+
+static char sat_polarisation (struct transponder *t)
+{
+	return t->polarisation == POLARISATION_VERTICAL ? 'v' : 'h';
+}
+
+static int sat_number (struct transponder *t)
+{
+	return switch_pos;
+}
+
+static void dump_lists (void)
+{
+	struct list_head *p1, *p2;
+	struct transponder *t;
+	struct service *s;
+	int n = 0, i;
+	char sn[20];
+
+	list_for_each(p1, &scanned_transponders) {
+		t = list_entry(p1, struct transponder, list);
+		list_for_each(p2, &t->services) {
+			n++;
+		}
+	}
+	info("dumping lists (%d services)\n", n);
+
+	list_for_each(p1, &scanned_transponders) {
+		t = list_entry(p1, struct transponder, list);
+		list_for_each(p2, &t->services) {
+			s = list_entry(p2, struct service, list);
+
+			if (!s->service_name) {
+				/* not in SDT */
+				snprintf(sn, sizeof(sn), "[%04x]", s->service_id);
+				s->service_name = strdup(sn);
+			}
+			/* ':' is field separator in szap and vdr service lists */
+			for (i = 0; s->service_name[i]; i++) {
+				if (s->service_name[i] == ':')
+					s->service_name[i] = ' ';
+			}
+			for (i = 0; s->provider_name && s->provider_name[i]; i++) {
+				if (s->provider_name[i] == ':')
+					s->provider_name[i] = ' ';
+			}
+			if (s->video_pid && !(serv_select & 1))
+				continue; /* no TV services */
+			if (!s->video_pid && s->audio_num && !(serv_select & 2))
+				continue; /* no radio services */
+			if (!s->video_pid && !s->audio_num && !(serv_select & 4))
+				continue; /* no data/other services */
+			if (s->scrambled && !ca_select)
+				continue; /* FTA only */
+			switch (output_format)
+			{
+			  case OUTPUT_PIDS:
+				pids_dump_service_parameter_set (stdout, s);
+				break;
+			  case OUTPUT_VDR:
+				vdr_dump_service_parameter_set (stdout,
+						    s->service_name,
+						    s->provider_name,
+						    t->type,
+						    &t->param,
+						    sat_polarisation(t),
+						    s->video_pid,
+						    s->pcr_pid,
+						    s->audio_pid,
+						    //FIXME: s->audio_lang
+						    s->audio_num,
+						    s->teletext_pid,
+						    s->scrambled,
+						    //FIXME: s->subtitling_pid
+						    s->ac3_pid,
+						    s->service_id,
+						    t->network_id,
+						    s->transport_stream_id,
+						    t->orbital_pos,
+						    t->we_flag,
+						    vdr_dump_provider,
+						    ca_select,
+						    vdr_version,
+						    vdr_dump_channum,
+						    s->channel_num);
+				break;
+			  case OUTPUT_ZAP:
+				zap_dump_service_parameter_set (stdout,
+						    s->service_name,
+						    t->type,
+						    &t->param,
+						    sat_polarisation(t),
+						    sat_number(t),
+						    s->video_pid,
+						    s->audio_pid,
+						    s->service_id);
+			  default:
+				break;
+			  }
+		}
+	}
+	info("Done.\n");
+}
+
+static void handle_sigint(int sig)
+{
+	error("interrupted by SIGINT, dumping partial result...\n");
+	dump_lists();
+	exit(2);
+}
+
+static const char *usage = "\n"
+	"usage: %s [options...] [-c | initial-tuning-data-file]\n"
+	"	scan doesn't do frequency scans, hence it needs initial\n"
+	"	tuning data for at least one transponder/channel.\n"
+	"	-c	scan on currently tuned transponder only\n"
+	"	-v 	verbose (repeat for more)\n"
+	"	-q 	quiet (repeat for less)\n"
+	"	-a N	use DVB /dev/dvb/adapterN/\n"
+	"	-f N	use DVB /dev/dvb/adapter?/frontendN\n"
+	"	-d N	use DVB /dev/dvb/adapter?/demuxN\n"
+	"	-s N	use DiSEqC switch position N (DVB-S only)\n"
+	"	-i N	spectral inversion setting (0: off, 1: on, 2: auto [default])\n"
+	"	-n	evaluate NIT-other for full network scan (slow!)\n"
+	"	-5	multiply all filter timeouts by factor 5\n"
+	"		for non-DVB-compliant section repitition rates\n"
+	"	-o fmt	output format: 'zap' (default), 'vdr' or 'pids' (default with -c)\n"
+	"	-x N	Conditional Axcess, (default 1)\n"
+	"		N=0 gets only FTA channels\n"
+	"		N=xxx sets ca field in vdr output to :xxx:\n"
+	"	-t N	Service select, Combined bitfield parameter.\n"
+	"		1 = TV, 2 = Radio, 4 = Other, (default 7)\n"
+	"	-p	for vdr output format: dump provider name\n"
+	"	-e N	VDR version, default 2 for VDR-1.2.x\n"
+	"		ANYTHING ELSE GIVES NONZERO NIT and TID\n"
+	"	-l lnb-type (DVB-S Only) (use -l help to print types) or \n"
+	"	-l low[,high[,switch]] in Mhz\n"
+	"	-u      UK DVB-T Freeview channel numbering for VDR\n";
+
+void
+bad_usage(char *pname, int prlnb)
+{
+int i;
+struct lnb_types_st *lnbp;
+char **cp;
+
+	if (!prlnb) {
+		fprintf (stderr, usage, pname);
+	} else {
+		i = 0;
+		fprintf(stderr, "-l <lnb-type> or -l low[,high[,switch]] in Mhz\nwhere <lnb-type> is:\n");
+		while(NULL != (lnbp = lnb_enum(i))) {
+			fprintf (stderr, "%s\n", lnbp->name);
+			for (cp = lnbp->desc; *cp ; cp++) {
+				fprintf (stderr, "   %s\n", *cp);
+			}
+			i++;
+		}
+	}
+}
+
+int main (int argc, char **argv)
+{
+	char frontend_devname [80];
+	int adapter = 0, frontend = 0, demux = 0;
+	int opt, i;
+	int frontend_fd;
+	int fe_open_mode;
+	const char *initial = NULL;
+
+	/* start with default lnb type */
+	lnb_type = *lnb_enum(0);
+	while ((opt = getopt(argc, argv, "5cnpa:f:d:s:o:x:e:t:i:l:vq:u")) != -1) {
+		switch (opt) {
+		case 'a':
+			adapter = strtoul(optarg, NULL, 0);
+			break;
+		case 'c':
+			current_tp_only = 1;
+			output_format = OUTPUT_PIDS;
+			break;
+		case 'n':
+			get_other_nits = 1;
+			break;
+		case 'd':
+			demux = strtoul(optarg, NULL, 0);
+			break;
+		case 'f':
+			frontend = strtoul(optarg, NULL, 0);
+			break;
+		case 'p':
+			vdr_dump_provider = 1;
+			break;
+		case 's':
+			switch_pos = strtoul(optarg, NULL, 0);
+			break;
+		case 'o':
+                        if      (strcmp(optarg, "zap") == 0) output_format = OUTPUT_ZAP;
+                        else if (strcmp(optarg, "vdr") == 0) output_format = OUTPUT_VDR;
+                        else if (strcmp(optarg, "pids") == 0) output_format = OUTPUT_PIDS;
+                        else {
+				bad_usage(argv[0], 0);
+				return -1;
+			}
+			break;
+		case '5':
+			long_timeout = 1;
+			break;
+		case 'x':
+			ca_select = strtoul(optarg, NULL, 0);
+			break;
+		case 'e':
+			vdr_version = strtoul(optarg, NULL, 0);
+			break;
+		case 't':
+			serv_select = strtoul(optarg, NULL, 0);
+			break;
+		case 'i':
+			spectral_inversion = strtoul(optarg, NULL, 0);
+			break;
+		case 'l':
+			if (lnb_decode(optarg, &lnb_type) < 0) {
+				bad_usage(argv[0], 1);
+				return -1;
+			}
+			break;
+		case 'v':
+			verbosity++;
+			break;
+		case 'q':
+			if (--verbosity < 0)
+				verbosity = 0;
+			break;
+		case 'u':
+			vdr_dump_channum = 1;
+			break;
+		default:
+			bad_usage(argv[0], 0);
+			return -1;
+		};
+	}
+
+	if (optind < argc)
+		initial = argv[optind];
+	if ((!initial && !current_tp_only) || (initial && current_tp_only) ||
+			(spectral_inversion > 2)) {
+		bad_usage(argv[0], 0);
+		return -1;
+	}
+	lnb_type.low_val *= 1000;	/* convert to kiloherz */
+	lnb_type.high_val *= 1000;	/* convert to kiloherz */
+	lnb_type.switch_val *= 1000;	/* convert to kiloherz */
+	if (switch_pos >= 4) {
+		fprintf (stderr, "switch position needs to be < 4!\n");
+		return -1;
+	}
+	if (initial)
+		info("scanning %s\n", initial);
+
+	snprintf (frontend_devname, sizeof(frontend_devname),
+		  "/dev/dvb/adapter%i/frontend%i", adapter, frontend);
+
+	snprintf (demux_devname, sizeof(demux_devname),
+		  "/dev/dvb/adapter%i/demux%i", adapter, demux);
+	info("using '%s' and '%s'\n", frontend_devname, demux_devname);
+
+	for (i = 0; i < MAX_RUNNING; i++)
+		poll_fds[i].fd = -1;
+
+	fe_open_mode = current_tp_only ? O_RDONLY : O_RDWR;
+	if ((frontend_fd = open (frontend_devname, fe_open_mode)) < 0)
+		fatal("failed to open '%s': %d %m\n", frontend_devname, errno);
+	/* determine FE type and caps */
+	if (ioctl(frontend_fd, FE_GET_INFO, &fe_info) == -1)
+		fatal("FE_GET_INFO failed: %d %m\n", errno);
+
+	if ((spectral_inversion == INVERSION_AUTO ) &&
+	    !(fe_info.caps & FE_CAN_INVERSION_AUTO)) {
+		info("Frontend can not do INVERSION_AUTO, trying INVERSION_OFF instead\n");
+		spectral_inversion = INVERSION_OFF;
+	}
+
+	signal(SIGINT, handle_sigint);
+
+	if (current_tp_only) {
+		current_tp = alloc_transponder(0); /* dummy */
+		/* move TP from "new" to "scanned" list */
+		list_del_init(&current_tp->list);
+		list_add_tail(&current_tp->list, &scanned_transponders);
+		current_tp->scan_done = 1;
+		scan_tp ();
+	}
+	else
+		scan_network (frontend_fd, initial);
+
+	close (frontend_fd);
+
+	dump_lists ();
+
+	return 0;
+}
+
+static void dump_dvb_parameters (FILE *f, struct transponder *t)
+{
+	switch (output_format) {
+		case OUTPUT_PIDS:
+		case OUTPUT_VDR:
+			vdr_dump_dvb_parameters(f, t->type, &t->param,
+					sat_polarisation (t), t->orbital_pos, t->we_flag);
+			break;
+		case OUTPUT_ZAP:
+			zap_dump_dvb_parameters (f, t->type, &t->param,
+					sat_polarisation (t), sat_number (t));
+			break;
+		default:
+			break;
+	}
+}
diff --git a/util/scan/scan.h b/util/scan/scan.h
new file mode 100644
index 0000000..8209076
--- /dev/null
+++ b/util/scan/scan.h
@@ -0,0 +1,29 @@
+#ifndef __SCAN_H__
+#define __SCAN_H__
+
+#include <stdio.h>
+#include <errno.h>
+
+extern int verbosity;
+
+#define dprintf(level, fmt...)			\
+	do {					\
+		if (level <= verbosity)		\
+			fprintf(stderr, fmt);	\
+	} while (0)
+
+#define dpprintf(level, fmt, args...) \
+	dprintf(level, "%s:%d: " fmt, __FUNCTION__, __LINE__ , ##args)
+
+#define fatal(fmt, args...) do { dpprintf(-1, "FATAL: " fmt , ##args); exit(1); } while(0)
+#define error(msg...) dprintf(0, "ERROR: " msg)
+#define errorn(msg) dprintf(0, "%s:%d: ERROR: " msg ": %d %m\n", __FUNCTION__, __LINE__, errno)
+#define warning(msg...) dprintf(1, "WARNING: " msg)
+#define info(msg...) dprintf(2, msg)
+#define verbose(msg...) dprintf(3, msg)
+#define moreverbose(msg...) dprintf(4, msg)
+#define debug(msg...) dpprintf(5, msg)
+#define verbosedebug(msg...) dpprintf(6, msg)
+
+#endif
+
diff --git a/util/szap/Makefile b/util/szap/Makefile
new file mode 100644
index 0000000..688c5d7
--- /dev/null
+++ b/util/szap/Makefile
@@ -0,0 +1,35 @@
+CC = gcc
+CFLAGS = -MD -Wall -g -O2 -I../../include -I../lib
+LFLAGS = -Wall -g -O2
+RM = rm -f
+
+TARGETS = szap tzap czap femon
+OBJS = szap.o tzap.o czap.o femon.o
+
+all: $(OBJS) $(TARGETS)
+	@echo
+	@echo "--------------------------------------------------------------------------------"
+	@echo " please copy an appropriate channels.conf-XXX channel list for DVB-S/C/T"
+	@echo
+	@echo "   to ~/.szap/channels.conf"
+	@echo "      ~/.czap/channels.conf"
+	@echo "      ~/.tzap/channels.conf"
+	@echo
+	@echo " and then call ./szap for DVB-S, ./czap for DVB-C or ./tzap for DVB-T"
+	@echo "--------------------------------------------------------------------------------"
+	@echo
+
+szap: szap.o ../lib/lnb.o
+	$(CC) $(LFLAGS) -o szap szap.o ../lib/lnb.o
+
+.c.o:
+	$(CC) $(CFLAGS) -o $@ -c $<
+
+.o:
+	$(CC) $(LFLAGS) -o $@ $<
+
+clean:
+	$(RM) $(TARGETS) core* *.o *.d .depend
+
+-include $(wildcard *.d) dummy
+
diff --git a/util/szap/README b/util/szap/README
new file mode 100644
index 0000000..5c83c67
--- /dev/null
+++ b/util/szap/README
@@ -0,0 +1,47 @@
+Hi,
+
+this are some trivial zapping applications explaining how to use the frontend
+and demux API. They are also pretty useful to test your hardware.
+
+For DVB-S, Astra Channel config file:
+
+$ ./szap -c channels.conf-dvbs-astra n24
+
+will tune to N24. For DVB-C, Berlin Cable channel config:
+
+$ ./czap -c channels.conf-dvbc-berlin Arte
+
+For DVB-T, Berlin Config:
+
+$ ./czap -c channels.conf-dvbt-berlin phoenix
+
+By default the MPEG stream is routed to a hardware decoder. If you want to 
+record the stream to disk you will route it to the DVR device by using the 
+'-r' option:
+
+$ ./czap -c channels.conf-dvbt-berlin phoenix -r
+[keep it running in one console]
+$ cat /dev/dvr/adapter0/dvr0 > /tmp/recording.ts
+[in a second console, will dump the MPEG transport stream to /tmp/recording.ts]
+
+The status messages have the following meaning:
+
+status 0x1f              --- The demodulator status bits.
+			      0x1f means all bits set, everything ok.
+
+signal [0x0000...0xffff] --- Signal Strength. Values above 0x8000 should be ok.
+
+snr [0x0000...0xffff]    --- Signal/Noise Ratio. Values above 0x8000 are ok.
+
+ber [0...0xffffffff]     --- Bit Error Rate. The less the better.
+
+unc [0...0xffffffff]     --- Number of Uncorrectable Blocks.
+			     Small numbers are Preferable.
+
+If everything is alright and all frontend circuits are working stable 
+(are locked) you should see a FE_HAS_LOCK in the rightmost line.
+
+Good luck,
+
+Holger
+
diff --git a/util/szap/channels.conf-dvbc-berlin b/util/szap/channels.conf-dvbc-berlin
new file mode 100644
index 0000000..7fb05a5
--- /dev/null
+++ b/util/szap/channels.conf-dvbc-berlin
@@ -0,0 +1,171 @@
+3sat:394000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:210:220
+ARD-Online-Kanal:426000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:1805
+CNBC:394000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:510:520
+DLF-K�ln:394000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:810
+DLR-Berlin:394000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:710
+EinsExtra:426000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:101:102
+EinsFestival:426000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:201:202
+EinsMuXx:426000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:301:302
+EuroNews:394000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:2221:2233
+Eurosport:394000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:410:420
+Fritz:426000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:901
+KiKa:394000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:310:320
+MDR FERNSEHEN:426000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:401:402
+MDR KULTUR:426000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:801
+MDR info:426000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:1101
+MHP ARD Online-Kanal:426000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:102
+NDR Fernsehen:426000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:2401:2402
+ORB-Fernsehen:426000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:501:502
+RADIOmultikulti:426000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:1301
+Radio 3:426000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:701
+SFB1:426000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:601:602
+SWR2:426000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:1401
+S�DWEST BW:410000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:801:802
+S�DWEST RP:426000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:3101:3102
+WDR 3:426000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:1501
+WDR 5:426000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:1601
+ZDF:394000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:110:120
+ZDFdigitext:394000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+ZDFdokukanal:394000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:660:670
+ZDFinfokanal:394000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:610:620
+ZDFtheaterkanal:394000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+JUMP:426000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:1001
+SPUTNIK:426000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:1201
+�sterreich 1:394000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:169
+ATV 2:434000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:631:632
+ATV 2:434000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:631:632
+Adagio:442000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+All Jazz:442000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+Avante:113000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:741:743
+B5 aktuell:410000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:3101
+BBC Prime:113000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:761:762
+BData3:402000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+BData4:402000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+BData5:402000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+BR-alpha:410000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:701:702
+Barock Fantasie:442000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+Bayerisches FS:410000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:201:202
+Bayern 1:410000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:3601
+Bayern 4 Klassik:410000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:3001
+BibelTV:113000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:731:732
+Bloomberg:346000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+CLASSICA:354000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:767:768
+COUNTRY:362000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:656
+Canal 24 Horas:121000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:991:992
+Club:113000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:711:713
+Cristal New Age:442000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+DANCE:370000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:304
+DW-tv:610000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:634:632
+Das Erste:410000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:101:102
+Detskij Mir:121000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:931:932
+ERT-Sat:434000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:691:692
+Einstein TV:113000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:701:702
+Euronews:610000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:597:596
+Eurosport News:113000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:771:772
+Extreme Sports:113000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:791:793
+Extreme Sports:346000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+Fashion TV:346000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+Fox Kids:434000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:671:672
+Fox Kids:434000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:671:673
+GOLD:370000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:320
+HITLISTE:370000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:784
+HR XXL:410000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:3501
+JAZZ:378000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:640
+Jazz legends:442000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+Kabel Wizard:346000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+Kanal 7:121000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+Kanal 7:610000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:49:52
+Kanal D:434000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:651:652
+Kanal D:434000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:651:652
+LATIN:362000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:368
+Landscape:346000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+Leitseite:346000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:2254:0
+Liberty TV:113000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:721:723
+MTV Base:113000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:781:782
+MV-Test:442000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+Modem-Setup:354000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+Movie Sounds:442000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+Musica Antica:442000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+Musica Camerata:442000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+NDR Info:410000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:3701
+NTV international:442000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+NTVI:434000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:611:612
+Nashe Kino:434000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:621:622
+NordwestRadio:410000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:3801
+OLD GOLD:362000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:336
+Opernfestival:442000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+PCNE:434000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:681:682
+PREMIERE SPORT INTERACTIVE:362000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+PREMIERE DIREKT 1:378000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+PREMIERE DIREKT 2:378000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+PREMIERE DIREKT 3:378000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+PREMIERE DIREKT 4:378000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:2815:2816
+PREMIERE EROTIK:378000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:1279:1280
+PREMIERE NOSTALGIE:378000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:2559:2560
+PREMIERE SERIE:378000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:1023:1024
+PREMIERE SPORT 1:362000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:255:258
+PREMIERE SPORT 2:378000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:3839:3840
+PREMIERE START:370000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:255:256
+Parlamentsfernsehen:610000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:33:36
+Phoenix:410000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:901:902
+Portal:402000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+RTP Internacional:434000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:661:662
+Rai 1:121000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:951:952
+Rai 2:121000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:961:962
+Rai 3:121000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:971:972
+SCHLAGER:370000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:384
+SR 1:410000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:3901
+SR Fernsehen Suedwest:410000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:501:502
+Show TV:121000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:911:912
+Sinfonica:442000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+TGRT:121000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:921:922
+TM V1.0:354000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+TV Polonia:434000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:641:642
+TVEi:121000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:981:982
+TW1:113000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:751:752
+Test-R:410000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:701:702
+Travel:610000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:595:594
+VCR-Setup:354000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+VH1 Classic:610000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:604:603
+Videotext:378000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+WDR FERNSEHEN:410000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:601:602
+ZEE TV:442000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+arte:410000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:401:403
+hessen fernsehen:410000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:301:302
+hr-chronos:410000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:3201
+hr-klassik:410000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:3401
+hr2:410000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:3301
+13 TH STREET:354000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:2303:2304
+ALTERNATIVE ROCK:370000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:544
+BEATE-UHSE.TV:354000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:1023:1024
+CHILLOUT:370000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:400
+CLASSIC ROCK:370000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:352
+DISCOVERY CHANNEL:378000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:1791:1792
+DISNEY CHANNEL:354000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:2559:2560
+DEUTSCHE HITS:370000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:800
+EASY LISTENING:378000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:608
+Einstein:346000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+FILM & MUSICAL:378000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:592
+FOX KIDS:354000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:1279:1280
+GOLDSTAR TV:354000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:3839:3840
+HARD ROCK:370000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:816
+HEIMATKANAL:354000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:1535:1536
+HIP HOP/R&B:370000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:576
+JUNIOR:354000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:255:256
+K-TOON:354000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
+KLASSIK POPUL�R:378000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:624
+KRIMI &CO:378000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:1535:1536
+LOVE SONGS:370000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:592
+NEW COUNTRY:362000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:384
+ORCHESTRALE WERKE:378000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:560
+PLANET:354000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:1791:1792
+PREMIERE 1:370000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:511:512
+PREMIERE 2:370000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:1791:1793
+PREMIERE 3:370000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:2303:2304
+PREMIERE 4:370000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:767:768
+PREMIERE 5:370000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:1279:1280
+PREMIERE 6:370000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:1535:1536
+PREMIERE 7:370000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:1023:1024
+SOUL CLASSICS:362000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:352
+STUDIO UNIVERSAL:354000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:2047:2048
+Sonnenklar TV:402000000:INVERSION_OFF:6900000:FEC_NONE:QAM_64:0:0
diff --git a/util/szap/channels.conf-dvbs-astra b/util/szap/channels.conf-dvbs-astra
new file mode 100644
index 0000000..705f710
--- /dev/null
+++ b/util/szap/channels.conf-dvbs-astra
@@ -0,0 +1,226 @@
+Das Erste:11837:h:0:27500:101:102:1:28106
+ZDF:11954:h:0:27500:110:120:1:28006
+3sat:11954:h:0:27500:210:220:1:28007
+EinsMuXx:12110:h:0:27500:301:302:1:28203
+EinsFestival:12110:h:0:27500:201:202:1:28202
+EinsExtra:12110:h:0:27500:101:102:1:28201
+MDR FERNSEHEN:12110:h:0:27500:401:402:1:28204
+ORB-Fernsehen:12110:h:0:27500:501:502:1:28205
+B1 Berlin:12110:h:0:27500:601:602:1:28206
+SWR Fernsehen:11837:h:0:27500:801:802:1:28113
+SR Fernsehen Suedwes:11837:h:0:27500:501:502:1:28110
+hessen fernsehen:11837:h:0:27500:301:302:1:28108
+WDR FERNSEHEN:11837:h:0:27500:601:602:1:28111
+Bayerisches FS:11837:h:0:27500:201:202:1:28107
+N3:12110:h:0:27500:2401:2402:1:28224
+BR-alpha:11837:h:0:27500:701:702:1:28112
+KiKa:11954:h:0:27500:310:320:1:28008
+arte:11836:h:0:27500:401:402:1:28109
+ZDF Theaterkanal:11954:h:0:27500:1110:1120:1:28016
+ZDF.info:11954:h:0:27500:610:620:1:28011
+ZDF.doku:11954:h:0:27500:660:670:1:28014
+Phoenix:11837:h:0:27500:901:902:1:28114
+DW-tv:10786:v:0:21997:305:306:1:9005
+RTL Television:12188:h:0:27500:163:104:1:12003
+SAT.1:12480:v:0:27500:1791:1792:1:46
+ProSieben:12480:v:0:27500:255:256:1:898
+RTL2:12188:h:0:27500:166:128:1:12020
+Super RTL:12188:h:0:27500:165:120:1:12040
+KABEL1:12480:v:0:27500:511:512:1:899
+VOX:12188:h:0:27500:167:136:1:12060
+tm3:12480:v:0:27500:767:768:1:897
+Bloomberg TV Germany:12552:v:0:22000:162:99:1:12160
+EuroNews:11954:h:0:27500:2221:2233:1:28015
+N24:12480:v:0:27500:2047:2048:1:47
+n-tv:12670:v:0:22000:162:96:1:12730
+DSF:12480:v:0:27500:1023:1024:1:900
+Eurosport:11954:h:0:27500:410:420:1:28009
+Via 1 - Sch ner Re:12148:h:0:27500:511:512:1:44
+Home Order Tel:12480:v:0:27500:1279:1280:1:40
+QVC GERMANY:12552:v:0:22000:165:166:1:12100
+TW 1:12692:h:0:22000:166:167:1:13013
+Canal Canarias:12441:v:0:27500:513:681:1:29700
+ProSieben A:12051:v:0:27500:161:84:1:20002
+ProSieben CH:12051:v:0:27500:289:290:1:20001
+Kabel 1 Austria:12051:v:0:27500:166:167:1:20004
+Kabel 1 Schweiz:12051:v:0:27500:162:163:1:20003
+CNN Int.:12168:v:0:27500:165:100:1:28512
+Sky News:12552:v:0:22000:305:306:1:3995
+Travel:12168:v:0:27500:163:92:1:28001
+AB SAT / XXL:12266:h:0:27500:164:96:1:17004
+MOTEURS:12266:h:0:27500:160:80:1:17000
+HOT GM:12148:h:0:27500:767:768:1:45
+KTO:12129:v:0:27500:170:120:1:8411
+LA CINQUIEME:12207:v:0:27500:160:80:1:8501
+LCP:12207:v:0:27500:165:100:1:8506
+LibertyTV.com:12611:v:0:22000:941:942:1:12280
+TV5 Europe:12611:v:0:22000:45:46:1:12240
+Motors TV:12611:v:0:22000:191:194:1:12300
+Wishline:12611:v:0:22000:214:216:1:12320
+TV 5:10786:v:0:21997:164:112:1:9001
+RTM - MAROC:10786:v:0:21997:162:96:1:9002
+ESC1 - EGYPTE:10786:v:0:21997:163:104:1:9003
+RAI 1:10786:v:0:21997:289:290:1:9004
+RTPI:10786:v:0:21997:300:301:1:9006
+TV7:10786:v:0:21997:166:128:1:9007
+ARTE:10786:v:0:21997:167:136:1:9009
+Colourbars:12611:v:0:22000:48:49:1:3982
+Alice:12611:v:0:22000:162:96:1:12200
+Video Italia:12611:v:0:22000:121:122:1:12220
+ANDALUCIA TV:11934:v:0:27500:166:104:1:29011
+TVC INT.:12441:v:0:27500:512:660:1:29701
+TV4:11992:h:0:27500:165:98:1:20365
+TV Niepokalanow:11876:h:0:27500:161:82:1:20601
+VIVA:12670:v:0:22000:309:310:1:12732
+VIVA ZWEI:12552:v:0:22000:171:172:1:12120
+MTV Central:12699:v:0:22000:3031:3032:1:28643
+ONYX:12692:h:1:27500:161:84:1:502
+VIVA polska:11603:h:1:27500:190:191:1:611
+DeeJay TV:11603:h:1:27500:160:161:1:602
+NBC:11053:h:1:27500:550:551:1:8008
+EWTN:10722:h:1:29900:1001:1201:1:4601
+MTA INTL:10722:h:1:29900:1004:1204:1:4604
+VOX:11053:h:1:27500:500:501:1:8002
+SAT.1 A:11053:h:1:27500:511:512:1:8003
+RTL2 AUSTRIA:11053:h:1:27500:520:521:1:8004
+ZDF:11053:h:1:27500:570:571:1:8011
+K-TV:11053:h:1:27500:580:581:1:8012
+RTL Television:11053:h:1:27500:160:80:1:8001
+ARTE:11059:v:1:6510:98:99:1:1
+HOT Italia:11095:h:1:27500:4194:4195:1:3714
+Olisat:11095:h:1:27500:33:34:1:3718
+VIVA-POLSKA:11128:h:1:4340:98:99:1:1
+DW-tv:11195:v:1:9099:101:102:1:5301
+Canal 24 Horas:11203:h:1:3999:4130:4131:1:5301
+TV5:11337:v:1:5631:512:640:1:1
+SAT.1 CH:11603:h:1:27500:101:102:1:601
+KurdSat:11603:h:1:27500:111:112:1:603
+ARD "Das Erste":11603:h:1:27500:172:173:1:606
+RTL 2 CH:11603:h:1:27500:175:176:1:609
+Super RTL A:11603:h:1:27500:180:181:1:610
+TV ROMANIA:11622:v:1:27500:227:247:1:10707
+MRTV:11622:v:1:27500:222:242:1:10702
+102.5 HIT Ch:11622:v:1:27500:224:244:1:10704
+TLC SAT:11622:v:1:27500:225:245:1:10705
+PRO-SAT:11622:v:1:27500:246:226:1:10706
+Channel SUN:11622:v:1:27500:229:249:1:10709
+Racing Channel:11622:v:1:27500:228:248:1:10708
+3 ABN:11622:v:1:27500:221:241:1:10701
+Bloom.Germany:11642:h:1:27500:1460:1420:1:4
+Bloomberg TV UK:11642:h:1:27500:1560:1520:1:4
+Sat 7:11642:h:1:27500:1660:1620:1:4
+EDTV 1:11746:h:1:27500:4130:4131:1:9501
+EDTV SPORT:11746:h:1:27500:4386:4387:1:9502
+EDTV BUSINESS:11746:h:1:27500:4642:4643:1:9503
+EDTV DRAMA:11746:h:1:27500:4898:4899:1:9504
+RAI1:11765:v:1:27499:160:80:1:3401
+RAI2:11765:v:1:27499:161:84:1:3402
+RAI3:11765:v:1:27499:162:88:1:3403
+RaiWayTEST2:11765:v:1:27499:516:654:1:3405
+RAIMOSAICO:11765:v:1:27499:518:8191:1:3407
+RAINews24:11803:v:1:27500:516:654:1:3301
+CAMERA DEPUTATI:11803:v:1:27500:517:655:1:3302
+TELEPACE:11803:v:1:27500:515:653:1:3304
+RAISPORTSAT:11803:v:1:27500:512:650:1:3305
+RAINettunoSAT2:11803:v:1:27500:513:651:1:3306
+RAIeducational:11803:v:1:27500:514:652:1:3307
+RAINettunoSAT1:11803:v:1:27500:519:657:1:3308
+SAT2000:11803:v:1:27500:518:656:1:3309
+I1:11918:v:1:27499:512:650:1:1
+C5:11918:v:1:27499:513:660:1:2
+R4:11918:v:1:27499:514:670:1:3
+Telesierra:12091:h:1:27500:4160:4161:1:8704
+C. Milagro:12091:h:1:27500:4368:4369:1:8711
+Italia Sat:12091:h:1:27500:4600:4601:1:8728
+TVE Internacional:12091:h:1:27500:4208:4209:1:8707
+Fiesta:12091:h:1:27500:4432:4433:1:8720
+Retelsat:12091:h:1:27500:4464:4465:1:8722
+ART EUROPE:12013:h:1:27495:164:96:1:450
+EGYPT SAT. CH. 2:12013:h:1:27495:166:104:1:470
+IQRA:12013:h:1:27495:168:112:1:474
+MAURITANIA TV:12110:v:1:27500:230:231:1:704
+ARMENIA TV:12110:v:1:27500:240:241:1:705
+SAILING CHANNEL:12110:v:1:27500:260:261:1:707
+AL JAZEERA:12110:v:1:27500:270:271:1:708
+Coming Soon TV:12110:v:1:27500:310:311:1:717
+SaluteBenessere:12110:v:1:27500:320:321:1:718
+AH-EDP1:12148:v:1:27499:96:97:1:7201
+AH-EDP2:12148:v:1:27499:112:113:1:7202
+Espresso:12148:v:1:27499:192:193:1:7203
+Alice:12148:v:1:27499:160:161:1:7220
+Nuvolari:12148:v:1:27499:176:177:1:7221
+Leonardo:12148:v:1:27499:128:129:1:7222
+AH-EDP3:12148:v:1:27499:36:37:1:7205
+OTE Promo:12187:v:1:27500:517:655:1:1001
+RTS SAT:12187:v:1:27500:519:657:1:1022
+ERT SAT:12187:v:1:27500:514:652:1:1102
+EXTRA:12187:v:1:27500:516:654:1:1106
+TRIAL:12187:v:1:27500:513:651:1:1108
+Minimax:11303:h:1:19540:300:301:1:3
+TVN1:12209:h:1:5631:4194:4195:1:1
+RR TEST:10978:v:1:8998:33:34:1:1
+TV 5 Thailand:10978:v:1:8998:1057:1058:1:2
+TEST-1:10978:v:1:8998:3105:3106:1:4
+FASHION:12244:h:1:27500:123:133:1:103
+AJARA TV:12244:h:1:27500:127:137:1:107
+SLO-TV1:12300:v:1:27495:200:201:1:3201
+POLONIA 1:12302:v:1:27500:205:206:1:3203
+SUPER 1:12302:v:1:27500:207:208:1:3207
+NAPOLI INT.:12302:v:1:27500:240:241:1:3210
+MAGIC:12302:v:1:27500:245:246:1:3211
+COUNTDOWN:12302:v:1:27500:235:236:1:3212
+TBNE:12302:v:1:27500:230:231:1:3213
+NAPOLI CHANNEL:12302:v:1:27500:227:228:1:3215
+KURDISTAN TV:12302:v:1:27500:225:226:1:3214
+ATLAS TV:12379:v:1:27500:3022:3032:1:3002
+TELE 24 SWITZERLAND:12379:v:1:27500:3023:3033:1:3003
+Abu Dhabi TV:12379:v:1:27500:3024:3034:1:3004
+RTV MONTENEGRO:12379:v:1:27500:3026:3036:1:3006
+JAAM-E-JAM 1:12436:h:1:27500:160:80:1:1
+JAAM-E-JAM 2:12436:h:1:27500:161:82:1:2
+SAHAR:12436:h:1:27500:162:84:1:3
+SAHAR 2:12436:h:1:27500:163:86:1:4
+IRINN:12436:h:1:27500:164:88:1:5
+Musicmax:11303:h:1:19540:500:501:1:6
+TEST:12474:h:1:27500:771:8191:1:10608
+EbS:12474:h:1:27500:101:201:1:10601
+MOU.2:12474:h:1:27500:42:43:1:10602
+PINK PLUS:12474:h:1:27500:308:256:1:10605
+LibertyTV.com:12474:h:1:27500:941:942:1:10603
+2M Maroc:12474:h:1:27500:601:602:1:10607
+ZEE TV:12474:h:1:27500:910:911:1:10604
+WorldNet Europe:12483:v:1:8299:4260:4220:1:1
+WorldNet:12483:v:1:8299:4560:4520:1:4
+SICILIA INTERNATIONA:12519:v:1:27499:501:502:1:8309
+SARDEGNA UNO:12519:v:1:27499:503:504:1:8310
+EuroMed:12519:v:1:27499:510:511:1:8312
+TGRT:12519:v:1:27499:505:506:1:8313
+VIDEOLINA:12519:v:1:27499:515:516:1:8318
+MEDIOLANUM:12538:h:1:27500:1131:1132:1:8987
+www.travel:12538:h:1:27500:1180:1183:1:8992
+MonteCarloSat:12538:h:1:27500:5126:5122:1:8877
+Bulgaria TV:12538:h:1:27500:4612:4613:1:8827
+TVN1:12571:h:1:5631:4194:4195:1:1
+JSTV 1:12595:v:1:27500:2000:2001:1:8213
+JSTV 2:12595:v:1:27500:2011:2013:1:8214
+MBC:12595:v:1:27500:160:80:1:8201
+ANN:12595:v:1:27500:161:84:1:8202
+BET:12595:v:1:27500:167:108:1:8208
+EuroNews:12595:v:1:27500:2221:2231:1:8211
+Sharjah        Arabs:12653:h:1:27500:1160:1120:1:1
+Qatar          Arabs:12653:h:1:27500:1260:1220:1:2
+Saudi 1        Arabs:12653:h:1:27500:1360:1320:1:3
+Kuwait         Arabs:12653:h:1:27500:1460:1420:1:4
+Libya          Arabs:12653:h:1:27500:1560:1520:1:5
+Sudan          Arabs:12653:h:1:27500:1660:1620:1:6
+Oman           Arabs:12653:h:1:27500:1760:1720:1:7
+Jordan         Arabs:12653:h:1:27500:1860:1820:1:8
+IRAQ TV:12653:h:1:27500:1960:1920:1:9
+Dubai Sport:12653:h:1:27500:1060:1020:1:10
+Digitaly:12672:v:1:27500:220:221:1:4203
+Telemarket:12672:v:1:27500:350:351:1:4211
+eVision:12672:v:1:27500:360:361:1:4214
+Thai TV5:12672:v:1:27500:200:201:1:4201
+Studio Europa:12672:v:1:27500:230:231:1:4204
+Video  Italia:12672:v:1:27500:340:341:1:4210
+GAME NETWORK:12672:v:1:27500:291:292:1:4213
diff --git a/util/szap/channels.conf-dvbt-australia b/util/szap/channels.conf-dvbt-australia
new file mode 100644
index 0000000..9709b0b
--- /dev/null
+++ b/util/szap/channels.conf-dvbt-australia
@@ -0,0 +1,31 @@
+ABC HDTV:226500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_3_4:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_16:HIERARCHY_NONE:2307:0:560
+ABC TV Melbourne:226500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_3_4:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_16:HIERARCHY_NONE:512:650:561
+ABC TV 2:226500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_3_4:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_16:HIERARCHY_NONE:512:650:562
+ABC TV 3:226500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_3_4:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_16:HIERARCHY_NONE:512:650:563
+ABC TV 4:226500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_3_4:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_16:HIERARCHY_NONE:512:650:564
+ABC DiG Radio:226500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_3_4:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_16:HIERARCHY_NONE:0:2311:566
+TEN Digital:219500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_16:HIERARCHY_NONE:512:650:1585
+TEN Digital 1:219500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_16:HIERARCHY_NONE:512:650:1586
+TEN Digital 2:219500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_16:HIERARCHY_NONE:512:650:1587
+TEN Digital 3:219500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_16:HIERARCHY_NONE:512:650:1588
+TEN Digital:219500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_16:HIERARCHY_NONE:512:650:1589
+TEN Digital 4:219500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_16:HIERARCHY_NONE:512:650:1590
+TEN Digital:219500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_16:HIERARCHY_NONE:512:650:1591
+TEN HD:219500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_16:HIERARCHY_NONE:514:0:1592
+TEN Digital:219500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_16:HIERARCHY_NONE:512:650:1593
+Nine Digital:191625000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_16:HIERARCHY_NONE:513:660:1072
+Nine Digital HD:191625000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_16:HIERARCHY_NONE:512:0:1073
+Nine Guide:191625000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_16:HIERARCHY_NONE:514:670:1074
+7 Digital:177500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_2_3:FEC_2_3:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:769:770:1328
+7 Digital 1:177500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_2_3:FEC_2_3:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:769:770:1329
+7 Digital 2:177500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_2_3:FEC_2_3:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:769:770:1330
+7 Digital 3:177500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_2_3:FEC_2_3:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:769:770:1331
+7 HD Digital:177500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_2_3:FEC_2_3:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:833:834:1332
+7 Program Guide:177500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_2_3:FEC_2_3:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:865:866:1334
+SBS HD:536500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_2_3:FEC_2_3:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:102:103:784
+SBS DIGITAL 1:536500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_2_3:FEC_2_3:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:161:81:785
+SBS DIGITAL 2:536500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_2_3:FEC_2_3:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:162:83:786
+SBS EPG:536500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_2_3:FEC_2_3:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:163:85:787
+SBS RADIO 1:536500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_2_3:FEC_2_3:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:0:201:798
+SBS RADIO 2:536500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_2_3:FEC_2_3:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:0:202:799
+
diff --git a/util/szap/channels.conf-dvbt-berlin b/util/szap/channels.conf-dvbt-berlin
new file mode 100644
index 0000000..dbddca5
--- /dev/null
+++ b/util/szap/channels.conf-dvbt-berlin
@@ -0,0 +1,51 @@
+c5:177500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:161:82
+c7:191500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_2_3:FEC_NONE:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:161:82
+c25:506000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:161:82
+c27:522000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:161:82
+c33:570000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:161:82
+c44:658000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:161:82
+c56:754000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:161:82
+c59:778000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:161:82
+
+SWR BW:177500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:257:258:16
+WDR:177500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:241:242:15
+BBC World:177500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:49:50:16387
+FAB:177500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_3_4:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:3073:3074:16576
+
+MDR Fernsehen:191500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_2_3:FEC_NONE:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:101:102:1
+arte:191500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_2_3:FEC_NONE:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:201:202:2
+NDR Fernsehen:191500000:INVERSION_OFF:BANDWIDTH_7_MHZ:FEC_2_3:FEC_NONE:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:301:302:3
+
+RTL:506000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:337:338:16405
+RTL2:506000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:353:354:16406
+Super RTL:506000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:433:434:16411
+VOX:506000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:545:546:16418
+
+Das Erste:522000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_2_3:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:1401:1402:14
+Phoenix:522000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_2_3:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:1301:1302:13
+RBB Berlin:522000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_2_3:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:1201:1202:12
+RBB Brandenburg:522000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_2_3:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:1101:1102:11
+
+ZDF:570000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:545:546:514
+Info/3sat:570000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:561:562:515
+Doku/KiKa:570000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:593:594:517
+
+Kabel 1:658000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:161:162:16394
+N24:658000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:225:226:16398
+ProSieben:658000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:305:306:16403
+SAT.1:658000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:385:386:16408
+
+DSF:754000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_2_3:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:129:130:16392
+Testkanal n-tv:754000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_2_3:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:273:274:16401
+VIVA Plus:754000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_2_3:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:529:530:16417
+Eurosport:754000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:577:578:16420
+
+Testkanal Eurosport:778000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:577:578:16420
+SUD:778000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:0:0:16642
+HUMAX DOWNLOAD SVC:778000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:0:0:16645
+IP Services:778000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:0:0:16640
+Media Broadcast Services:778000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:0:0:16641
+SUD 1:778000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:0:0:16643
+Kathrein Download:778000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:0:0:16644
+Testkanal MTV:778000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:193:194:16396
+Testkanal n-tv:778000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_16:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_8:HIERARCHY_NONE:273:274:16401
diff --git a/util/szap/channels.conf-dvbt-collserola b/util/szap/channels.conf-dvbt-collserola
new file mode 100644
index 0000000..63456b2
--- /dev/null
+++ b/util/szap/channels.conf-dvbt-collserola
@@ -0,0 +1,25 @@
+#channels.conf for DVB-T - Collserola (Barcelona) Transmitter
+
+#C43
+TV3:650000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_2_3:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:111:112:801
+K3/33:650000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_2_3:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:121:122:802
+3/24:650000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_2_3:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:131:132:803
+Canal Pilot:650000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_2_3:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:141:142:804
+3XL.net:650000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_2_3:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:151:152:805
+
+#C61
+TVE 1:794000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:101:103:1377
+TVE 2:794000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:201:203:1441
+ANTENA 3:794000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:301:303:1121
+CANAL+:794000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:501:503:1057
+TELECINCO:794000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:401:403:1185
+
+#C66
+Veo TV:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:301:302:1536
+Net TV:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:401:402:1825
+Video Promocional 1:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:210:212:425
+Video Promocional 2:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:110:0:420
+[1388]:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:0:0:5000
+[138c]:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:0:0:5004
+[138a]:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:0:0:5002
+
diff --git a/util/szap/channels.conf-dvbt-crystal-palace b/util/szap/channels.conf-dvbt-crystal-palace
new file mode 100644
index 0000000..28fa018
--- /dev/null
+++ b/util/szap/channels.conf-dvbt-crystal-palace
@@ -0,0 +1,70 @@
+#channels.conf for DVB-T - Crystal Palace Transmitter
+
+# Multiplex 1 BBC - Channel 25, Offset -, Freq 505833333
+BBCi:505833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:0:4479
+CBBC Channel:505833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:0:4671
+BBC ONE:505833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:600:601
+BBC TWO:505833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:610:611
+BBC THREE:505833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:620:621
+BBC NEWS 24:505833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:640:641
+
+# Multiplex 2 Digital 3&4 - Channel 22, Offset -, Freq 481833333
+Teletext:481833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:0
+FourText:481833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:0
+CHANNEL4:481833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2827:2828
+ITV NEWS:481833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2850:2851
+ITV 1:481833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:512:650
+ITV 2:481833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2818:2819
+Ch 14:481833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2840:2841
+
+#Multiplex A SDN - Channel 32, Offset -, Frequency 561833333
+ntl:561833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:0
+Ch 15:561833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:660
+BBC Radio 1:561833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:6210
+BBC Radio 2:561833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:6226
+BBC Radio 3:561833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:6242
+BBC Radio 4:561833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:6258
+QVC:561833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6049:6050
+FIVE:561833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6017:6018
+bid-up.tv:561833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6273:6274
+TV Travel Shop:561833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6161:6161
+
+#Multiplex B BBC - Channel 28, Offset -, Frequency 529833333
+#Community                (0x4e00) 01: PCR 0x1fff
+#703                      (0x4c80) 01: PCR 0x1fff
+BBC PARLMNT:529833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:403
+BBC FOUR:529833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:201:401
+701:529833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:204:411
+702:529833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:203:407
+CBeebies:529833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:401:402
+BBC Asian Net:529833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:435
+1Xtra BBC:529833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:434
+BBC 7:529833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:433
+BBC 6 Music:529833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:432
+BBC 5L SportsX:529833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:431
+BBC R5 Live:529833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:430
+
+# Multiplex C Crown Castle - Channel 34, Offset +, Frequency 578166666
+UKHistory:578166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:401:402
+Sky Travel:578166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:301:302
+Sky Spts News:578166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:201:202
+Sky News:578166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:101:102
+
+# Multiplex D Crown Castle - Channel 29, Offset -, Freq 537833333
+#UKBrightIdeas            (0x64c0) 01: PCR 0x1fff
+THE HITS:537833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:101:102
+TMF:537833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:201:202
+CBM:537833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:501:502
+Free2Play:537833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:0
+Q:537833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:1901
+Magic:537833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:1801
+The Hits Radio:537833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:1701
+BBC World Sv:537833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:1601
+oneworld:537833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:1501
+jazz fm:537833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:1401
+Kerrang:537833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:1301
+Smash Hits:537833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:1201
+Kiss:537833333:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:1101
+
+
+
diff --git a/util/szap/channels.conf-dvbt-hannington b/util/szap/channels.conf-dvbt-hannington
new file mode 100644
index 0000000..b83620e
--- /dev/null
+++ b/util/szap/channels.conf-dvbt-hannington
@@ -0,0 +1,28 @@
+BBC One:706000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:600:601
+BBC Two:706000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:610:611
+CBBC:706000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:620:621
+BBC Three:706000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:620:621
+BBC News 24:706000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:640:641
+CBeebies:674166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:201:401
+BBC Four:674166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:201:401
+BBC Parliament:674166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:403
+701:674166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:203:407
+702:674166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:204:411
+703:674166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:0
+ITV 1:650166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:513:651
+ITV 2:650166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2818:2819
+Channel 4:650166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2822:2823
+ITV News:650166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2822:2823
+price-drop.tv:650166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2840:2841
+Five:626166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6017:6018
+QVC:626166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6059:6050
+Tv Travel Shop:626166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6161:6162
+Channel 15:626166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:660
+bid-up.tv:626166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6273:6274
+Sky News:658166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:101:102
+Sky Sports News:658166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:201:202
+Sky Travel:658166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:301:302
+UK History:658166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:401:402
+The Hits:634166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:101:102
+TMF:634166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:201:202
+UK Bright Ideas:634166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:0
diff --git a/util/szap/channels.conf-dvbt-madrid b/util/szap/channels.conf-dvbt-madrid
new file mode 100644
index 0000000..cdf515b
--- /dev/null
+++ b/util/szap/channels.conf-dvbt-madrid
@@ -0,0 +1,16 @@
+Veo TV:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:301:302:1536
+Net TV:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:401:402:1825
+[1388]:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:0:0:5000
+[138c]:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:0:0:5004
+[138a]:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:0:0:5002
+Video Promocional:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:0:0:420
+Informe Semanal:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:0:0:425
+TVE 2:770000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:201:203:1441
+ANTENA 3:770000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:301:303:1121
+TELECINCO:770000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:401:403:1185
+CANAL+:770000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:501:503:1057
+TVE 1:770000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:101:103:1377
+Telemadrid:810000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:111:113:421
+La Otra:810000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:211:212:422
+Quiero Madrid:810000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:411:412:424
+Onda 6:810000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_1_2:QAM_64:TRANSMISSION_MODE_8K:GUARD_INTERVAL_1_4:HIERARCHY_NONE:311:312:423
diff --git a/util/szap/channels.conf-dvbt-oxford b/util/szap/channels.conf-dvbt-oxford
new file mode 100644
index 0000000..29a53a2
--- /dev/null
+++ b/util/szap/channels.conf-dvbt-oxford
@@ -0,0 +1,41 @@
+BBC-Choice:578000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:620:621
+BBC-Knowledge:578000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:630:631
+BBC-News24:578000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:640:641
+BBC-1:578000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:600:601
+BBC-Parliament:578000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:660
+BBC-2:578000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:610:611
+ITV-1:850000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:513:651
+ITV-2:850000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2818:2819
+ITV-Sport:850000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2836:2837
+FilmFour:850000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2822:2823
+C4:850000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2826:2827
+E4:850000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2831:2832
+C5:713833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6017:6018
+Shop:713833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6049:6050
+ITVSelect-Info:713833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6065:6066
+ITVSelect-1:713833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6081:6082
+ITVSelect-2:713833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6097:6098
+ITVSelect-3:713833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6113:6114
+ITVSelect-4:713833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6129:6130
+Carlton-Cinema:721833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:288:289
+Sky-One:721833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:544:545
+Sky-Sports-1:721833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:800:801
+Sky-Premier:721833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:1056:1057
+CartoonNetwork:721833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:1312:1313
+UK-Horizons:721833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2336:2337
+ITV-Sport-Plus:721833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2592:2593
+ITVSportSelect:721833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:2596
+BreezeMen&Mtrs:690000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:800:801
+Granada-Plus:690000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:544:545
+MTV:690000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:1568:1569
+Sky-Movie-Max:690000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:1312:1313
+Sky-Sports-2:690000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2080:2081
+UK-Gold:690000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:288:289
+Wellbeing:690000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:1824:1825
+PLAY-uk:538000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:288:289
+UK-Style:538000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:544:545
+no-name:538000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:800:801
+Discovery:538000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:1312:1313
+Nick/Paramount:538000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2080:2081
+Sky-Sports-3:538000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2336:2337
+Brit-Eurosport:538000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2592:2593
diff --git a/util/szap/channels.conf-dvbt-reigate b/util/szap/channels.conf-dvbt-reigate
new file mode 100644
index 0000000..f5fe7cc
--- /dev/null
+++ b/util/szap/channels.conf-dvbt-reigate
@@ -0,0 +1,51 @@
+BBC ONE:554000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:600:601
+BBC TWO:554000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:610:611
+ITV 1:474000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_1_2:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:512:650
+Channel 4:474000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_1_2:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2827:2828
+five:498000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_1_2:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6017:6018
+ITV 2:474000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_1_2:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2818:2819
+BBC THREE:554000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:0
+Teletext:474000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_1_2:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:0
+BBC FOUR:522000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:0
+Sky Travel:618166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:301:302
+UKHistory:618166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:401:402
+Ch 14:474000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_1_2:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2840:2841
+Ch 15:498000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_1_2:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:660
+QVC:498000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_1_2:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6049:6050
+TV Travel Shop:498000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_1_2:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6161:6162
+The HITS:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:101:102
+UKBrightIdeas:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:301:302
+f tn:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:0
+TMF:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:201:202
+bid-up.tv:498000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_1_2:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6273:6274
+CBM:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:501:502
+CBBC Channel:554000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:620:621
+CBeebies:522000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:201:401
+BBC NEWS 24:554000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:640:641
+ITV News:474000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_1_2:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2850:2851
+Sky News:618166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:101:102
+Sky Spts News:618166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:201:202
+BBC PARLMNT:522000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:403
+Community:522000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:0
+FourText:474000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_1_2:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:0
+BBCi:554000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:0
+ntl:498000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_1_2:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:0
+BBC Radio 1:498000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_1_2:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:6210
+1Xtra BBC:522000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:434
+BBC Radio 2:498000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_1_2:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:6226
+BBC Radio 3:498000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_1_2:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:6242
+BBC Radio 4:498000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_1_2:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:6258
+BBC R5 Live:522000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:430
+BBC 5L SportsX:522000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:431
+BBC 6 Music:522000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:432
+BBC 7:522000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:433
+BBC Asian Net.:522000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:435
+BBC World Sv.:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:1601
+Smash Hits!:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:1201
+Kiss:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:1101
+Kerrang!:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:1301
+jazz fm:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:1401
+oneword:834000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:1501
+701:522000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:203:407
+702:522000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:204:411
+703:522000000:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_3_4:FEC_NONE:QAM_16:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:0
diff --git a/util/szap/channels.conf-dvbt-sandy_heath b/util/szap/channels.conf-dvbt-sandy_heath
new file mode 100644
index 0000000..a0cc632
--- /dev/null
+++ b/util/szap/channels.conf-dvbt-sandy_heath
@@ -0,0 +1,13 @@
+BBC-Choice:641833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:620:621
+BBC-Knowledge:641833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:630:631
+BBC-News24:641833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:640:641
+BBC-1:641833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:600:601
+BBC-Parliament:641833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:0:660
+BBC-2:641833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:610:611
+ITV-1:665833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:513:651
+ITV-2:665833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2819:2820
+C4:665833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2823:2824
+E4:665833334:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:2831:2832
+C5:650166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6017:6018
+Shop:650166666:INVERSION_OFF:BANDWIDTH_8_MHZ:FEC_2_3:FEC_NONE:QAM_64:TRANSMISSION_MODE_2K:GUARD_INTERVAL_1_32:HIERARCHY_NONE:6049:6050
+
diff --git a/util/szap/czap.c b/util/szap/czap.c
new file mode 100644
index 0000000..9d183f9
--- /dev/null
+++ b/util/szap/czap.c
@@ -0,0 +1,368 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <linux/dvb/frontend.h>
+#include <linux/dvb/dmx.h>
+
+
+static char FRONTEND_DEV [80];
+static char DEMUX_DEV [80];
+
+#define CHANNEL_FILE "/.czap/channels.conf"
+
+#define ERROR(x...)							\
+	do {								\
+		fprintf(stderr, "ERROR: ");				\
+		fprintf(stderr, x);					\
+		fprintf (stderr, "\n");					\
+	} while (0)
+
+#define PERROR(x...)							\
+	do {								\
+		fprintf(stderr, "ERROR: ");				\
+		fprintf(stderr, x);					\
+		fprintf (stderr, " (%s)\n", strerror(errno));		\
+	} while (0)
+
+
+typedef struct {
+	char *name;
+	int value;
+} Param;
+
+static const Param inversion_list[] = {
+	{ "INVERSION_OFF", INVERSION_OFF },
+	{ "INVERSION_ON", INVERSION_ON },
+	{ "INVERSION_AUTO", INVERSION_AUTO }
+};
+
+static const Param fec_list[] = {
+	{ "FEC_1_2", FEC_1_2 },
+	{ "FEC_2_3", FEC_2_3 },
+	{ "FEC_3_4", FEC_3_4 },
+	{ "FEC_4_5", FEC_4_5 },
+	{ "FEC_5_6", FEC_5_6 },
+	{ "FEC_6_7", FEC_6_7 },
+	{ "FEC_7_8", FEC_7_8 },
+	{ "FEC_8_9", FEC_8_9 },
+	{ "FEC_AUTO", FEC_AUTO },
+	{ "FEC_NONE", FEC_NONE }
+};
+
+static const Param modulation_list[] = {
+	{ "QAM_16", QAM_16 },
+	{ "QAM_32", QAM_32 },
+	{ "QAM_64", QAM_64 },
+	{ "QAM_128", QAM_128 },
+	{ "QAM_256", QAM_256 },
+	{ "QAM_AUTO", QAM_AUTO }
+};
+
+#define LIST_SIZE(x) sizeof(x)/sizeof(Param)
+
+
+static
+int parse_param(const char *val, const Param * plist, int list_size)
+{
+	int i;
+
+	for (i = 0; i < list_size; i++) {
+		if (strcasecmp(plist[i].name, val) == 0)
+			return plist[i].value;
+	}
+	return -1;
+}
+
+
+static char line_buf[256];
+static
+char *find_channel(FILE *f, int list_channels, int *chan_no, const char *channel)
+{
+	size_t l;
+	int lno = 0;
+
+	l = channel ? strlen(channel) : 0;
+	while (!feof(f)) {
+		if (!fgets(line_buf, sizeof(line_buf), f))
+			return NULL;
+		lno++;
+		if (list_channels) {
+			printf("%3d %s", lno, line_buf);
+		}
+		else if (*chan_no) {
+			if (*chan_no == lno)
+				return line_buf;
+		}
+		else if ((strncasecmp(channel, line_buf, l) == 0)
+				&& (line_buf[l] == ':')) {
+			*chan_no = lno;
+			return line_buf;
+		}
+	};
+
+	return NULL;
+}
+
+
+int parse(const char *fname, int list_channels, int chan_no, const char *channel,
+	  struct dvb_frontend_parameters *frontend, int *vpid, int *apid)
+{
+	FILE *f;
+	char *chan;
+	char *name, *inv, *fec, *mod;
+
+	if ((f = fopen(fname, "r")) == NULL) {
+		PERROR("could not open file '%s'", fname);
+		return -1;
+	}
+
+	chan = find_channel(f, list_channels, &chan_no, channel);
+	fclose(f);
+	if (list_channels)
+		return 0;
+	if (!chan) {
+		ERROR("could not find channel '%s' in channel list",
+		      channel);
+		return -2;
+	}
+	printf("%3d %s", chan_no, chan);
+
+	if ((sscanf(chan, "%a[^:]:%d:%a[^:]:%d:%a[^:]:%a[^:]:%d:%d\n",
+				&name, &frontend->frequency,
+				&inv, &frontend->u.qam.symbol_rate,
+				&fec, &mod, vpid, apid) != 8)
+			|| !name || !inv || !fec | !mod) {
+		ERROR("cannot parse service data");
+		return -3;
+	}
+	frontend->inversion = parse_param(inv, inversion_list, LIST_SIZE(inversion_list));
+	if (frontend->inversion < 0) {
+		ERROR("inversion field syntax '%s'", inv);
+		return -4;
+	}
+	frontend->u.qam.fec_inner = parse_param(fec, fec_list, LIST_SIZE(fec_list));
+	if (frontend->u.qam.fec_inner < 0) {
+		ERROR("FEC field syntax '%s'", fec);
+		return -5;
+	}
+	frontend->u.qam.modulation = parse_param(mod, modulation_list,
+			LIST_SIZE(modulation_list));
+	if (frontend->u.qam.modulation < 0) {
+		ERROR("modulation field syntax '%s'", mod);
+		return -6;
+	}
+	printf("%3d %s: f %d, s %d, i %d, fec %d, qam %d, v %#x, a %#x\n",
+			chan_no, name, frontend->frequency, frontend->u.qam.symbol_rate,
+			frontend->inversion, frontend->u.qam.fec_inner,
+			frontend->u.qam.modulation, *vpid, *apid);
+	free(name);
+	free(inv);
+	free(fec);
+	free(mod);
+
+	return 0;
+}
+
+
+
+static
+int set_pesfilter (int fd, int pid, dmx_pes_type_t type, int dvr)
+{
+	struct dmx_pes_filter_params pesfilter;
+
+	if (pid <= 0 || pid >= 0x1fff)
+		return 0;
+
+	pesfilter.pid = pid;
+	pesfilter.input = DMX_IN_FRONTEND;
+	pesfilter.output = dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER;
+	pesfilter.pes_type = type;
+	pesfilter.flags = DMX_IMMEDIATE_START;
+
+	if (ioctl(fd, DMX_SET_PES_FILTER, &pesfilter) < 0) {
+		PERROR ("ioctl(DMX_SET_PES_FILTER) for %s PID failed",
+			type == DMX_PES_AUDIO ? "Audio" :
+			type == DMX_PES_VIDEO ? "Video" : "??");
+		return -1;
+	}
+
+	return 0;
+}
+
+static
+int setup_frontend(int fe_fd, struct dvb_frontend_parameters *frontend)
+{
+	struct dvb_frontend_info fe_info;
+
+	if (ioctl(fe_fd, FE_GET_INFO, &fe_info) < 0) {
+		PERROR ("ioctl FE_GET_INFO failed");
+		return -1;
+	}
+
+	if (fe_info.type != FE_QAM) {
+		ERROR ("frontend device is not a QAM (DVB-C) device");
+		return -1;
+	}
+
+	if (ioctl(fe_fd, FE_SET_FRONTEND, frontend) < 0) {
+		PERROR ("ioctl FE_SET_FRONTEND failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static
+int check_frontend (int fe_fd)
+{
+	fe_status_t status;
+	uint16_t snr, signal;
+	uint32_t ber, uncorrected_blocks;
+
+	do {
+		ioctl(fe_fd, FE_READ_STATUS, &status);
+		ioctl(fe_fd, FE_READ_SIGNAL_STRENGTH, &signal);
+		ioctl(fe_fd, FE_READ_SNR, &snr);
+		ioctl(fe_fd, FE_READ_BER, &ber);
+		ioctl(fe_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks);
+
+		printf ("status %02x | signal %04x | snr %04x | "
+			"ber %08x | unc %08x | ",
+			status, signal, snr, ber, uncorrected_blocks);
+
+		if (status & FE_HAS_LOCK)
+			printf("FE_HAS_LOCK");
+
+		usleep(1000000);
+
+		printf("\n");
+	} while (1);
+
+	return 0;
+}
+
+
+static const char *usage = "\nusage: %s [-a adapter_num] [-f frontend_id] [-d demux_id] [-c conf_file] {<channel name>| -n channel_num}\n"
+	"   or: %s [-c conf_file]  -l\n\n";
+
+
+int main(int argc, char **argv)
+{
+	struct dvb_frontend_parameters frontend_param;
+	char *homedir = getenv("HOME");
+	char *confname = NULL;
+	char *channel = NULL;
+	int adapter = 0, frontend = 0, demux = 0, dvr = 0;
+	int vpid, apid;
+	int frontend_fd, video_fd, audio_fd;
+	int opt, list_channels = 0, chan_no = 0;
+
+        while ((opt = getopt(argc, argv, "ln:hrn:a:f:d:c:")) != -1) {
+                switch (opt) {
+                case 'a':
+                        adapter = strtoul(optarg, NULL, 0);
+                        break;
+                case 'f':
+                        frontend = strtoul(optarg, NULL, 0);
+                        break;
+                case 'd':
+                        demux = strtoul(optarg, NULL, 0);
+                        break;
+                case 'r':
+                        dvr = 1;
+                        break;
+                case 'l':
+                        list_channels = 1;
+                        break;
+                case 'n':
+                        chan_no = strtoul(optarg, NULL, 0);
+                        break;
+                case 'c':
+                        confname = optarg;
+                        break;
+                case '?':
+                case 'h':
+                default:
+                        fprintf (stderr, usage, argv[0], argv[0]);
+                        return -1;
+                };
+        }
+	
+        if (optind < argc)
+                channel = argv[optind];
+
+        if (!channel && chan_no <= 0 && !list_channels) {
+                fprintf (stderr, usage, argv[0], argv[0]);
+                return -1;
+        }
+
+	if (!homedir)
+		ERROR("$HOME not set");
+
+        snprintf (FRONTEND_DEV, sizeof(FRONTEND_DEV),
+                  "/dev/dvb/adapter%i/frontend%i", adapter, frontend);
+
+        snprintf (DEMUX_DEV, sizeof(DEMUX_DEV),
+                  "/dev/dvb/adapter%i/demux%i", adapter, demux);
+
+	printf ("using '%s' and '%s'\n", FRONTEND_DEV, DEMUX_DEV);
+
+	if (!confname)
+	{
+		if (!homedir)
+			ERROR("$HOME not set");
+		confname = malloc(strlen(homedir) + strlen(CHANNEL_FILE) + 1);
+		memcpy(confname, homedir, strlen(homedir));
+		memcpy(confname + strlen(homedir), CHANNEL_FILE,
+		       strlen(CHANNEL_FILE) + 1);
+	}
+	memset(&frontend_param, 0, sizeof(struct dvb_frontend_parameters));
+
+	if (parse(confname, list_channels, chan_no, channel, &frontend_param, &vpid, &apid))
+		return -1;
+	if (list_channels)
+		return 0;
+
+	if ((frontend_fd = open(FRONTEND_DEV, O_RDWR)) < 0) {
+		PERROR("failed opening '%s'", FRONTEND_DEV);
+		return -1;
+	}
+
+	if (setup_frontend(frontend_fd, &frontend_param) < 0)
+		return -1;
+
+	if ((video_fd = open(DEMUX_DEV, O_RDWR)) < 0) {
+		PERROR("failed opening '%s'", DEMUX_DEV);
+		return -1;
+	}
+
+	if (set_pesfilter (video_fd, vpid, DMX_PES_VIDEO, dvr) < 0)
+		return -1;
+
+	if ((audio_fd = open(DEMUX_DEV, O_RDWR)) < 0) {
+		PERROR("failed opening '%s'", DEMUX_DEV);
+		return -1;
+	}
+
+	if (set_pesfilter (audio_fd, apid, DMX_PES_AUDIO, dvr) < 0)
+		return -1;
+
+	check_frontend (frontend_fd);
+
+	close (audio_fd);
+	close (video_fd);
+	close (frontend_fd);
+
+	return 0;
+}
+
diff --git a/util/szap/femon.c b/util/szap/femon.c
new file mode 100644
index 0000000..47e37a3
--- /dev/null
+++ b/util/szap/femon.c
@@ -0,0 +1,149 @@
+/* femon -- monitor frontend status
+ *
+ * Copyright (C) 2003 convergence GmbH
+ * Johannes Stezenbach <js at convergence.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/poll.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <stdint.h>
+#include <sys/time.h>
+
+#include <linux/dvb/frontend.h>
+
+#ifndef TRUE
+#define TRUE (1==1)
+#endif
+#ifndef FALSE
+#define FALSE (1==0)
+#endif
+
+
+#define FRONTENDDEVICE "/dev/dvb/adapter%d/frontend%d"
+
+static char *usage_str =
+    "\nusage: femon [options]\n"
+    "     -a number : use given adapter (default 0)\n"
+    "     -f number : use given frontend (default 0)\n\n";
+
+
+static void usage(void)
+{
+   fprintf(stderr, usage_str);
+   exit(1);
+}
+
+
+static
+int check_frontend (int fe_fd)
+{
+   fe_status_t status;
+   uint16_t snr, signal;
+   uint32_t ber, uncorrected_blocks;
+
+   do {
+      ioctl(fe_fd, FE_READ_STATUS, &status);
+      ioctl(fe_fd, FE_READ_SIGNAL_STRENGTH, &signal);
+      ioctl(fe_fd, FE_READ_SNR, &snr);
+      ioctl(fe_fd, FE_READ_BER, &ber);
+      ioctl(fe_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks);
+
+      printf ("status %02x | signal %04x | snr %04x | ber %08x | unc %08x | ",
+	      status, signal, snr, ber, uncorrected_blocks);
+
+      if (status & FE_HAS_LOCK)
+	 printf("FE_HAS_LOCK");
+
+      printf("\n");
+      usleep(1000000);
+   } while (1);
+
+   return 0;
+}
+
+
+static
+int do_mon(unsigned int adapter, unsigned int frontend)
+{
+   char fedev[128];
+   int fefd;
+   int result;
+   struct dvb_frontend_info fe_info;
+
+   snprintf(fedev, sizeof(fedev), FRONTENDDEVICE, adapter, frontend);
+   printf("using '%s'\n", fedev);
+
+   if ((fefd = open(fedev, O_RDONLY | O_NONBLOCK)) < 0) {
+      perror("opening frontend failed");
+      return FALSE;
+   }
+
+   result = ioctl(fefd, FE_GET_INFO, &fe_info);
+
+   if (result < 0) {
+      perror("ioctl FE_GET_INFO failed");
+      close(fefd);
+      return FALSE;
+   }
+
+   printf("FE: %s (%s)\n", fe_info.name, fe_info.type == FE_QPSK ? "SAT" :
+		   fe_info.type == FE_QAM ? "CABLE": "TERRESTRIAL");
+
+   check_frontend (fefd);
+
+   close(fefd);
+
+   return result;
+}
+
+int main(int argc, char *argv[])
+{
+   unsigned int adapter = 0, frontend = 0;
+   int opt;
+
+   while ((opt = getopt(argc, argv, "hlrn:a:f:d:")) != -1) {
+      switch (opt)
+      {
+	 case '?':
+	 case 'h':
+	 default:
+	    usage();
+	 case 'a':
+	    adapter = strtoul(optarg, NULL, 0);
+	    break;
+	 case 'f':
+	    frontend = strtoul(optarg, NULL, 0);
+      }
+   }
+
+   do_mon(adapter, frontend);
+
+   return FALSE;
+}
+
diff --git a/util/szap/szap.c b/util/szap/szap.c
new file mode 100644
index 0000000..581c970
--- /dev/null
+++ b/util/szap/szap.c
@@ -0,0 +1,560 @@
+/* szap -- simple zapping tool for the Linux DVB API
+ *
+ * szap operates on VDR (http://www.cadsoft.de/people/kls/vdr/index.htm)
+ * satellite channel lists (e.g. from http://www.dxandy.de/cgi-bin/dvbchan.pl).
+ * szap assumes you have a "Universal LNB" (i.e. with LOFs 9750/10600 MHz).
+ *
+ * Compilation: `gcc -Wall -I../../ost/include -O2 szap.c -o szap`
+ *  or, if your DVB driver is in the kernel source tree:
+ *              `gcc -Wall -DDVB_IN_KERNEL -O2 szap.c -o szap`
+ *
+ * Copyright (C) 2001 Johannes Stezenbach (js at convergence.de)
+ * for convergence integrated media
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/poll.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <stdint.h>
+#include <sys/time.h>
+
+#include <linux/dvb/frontend.h>
+#include <linux/dvb/dmx.h>
+#include "lnb.h"
+
+#ifndef TRUE
+#define TRUE (1==1)
+#endif
+#ifndef FALSE
+#define FALSE (1==0)
+#endif
+
+/* location of channel list file */
+#define CHANNEL_FILE "channels.conf"
+
+/* one line of the VDR channel file has the following format:
+ * ^name:frequency_MHz:polarization:sat_no:symbolrate:vpid:apid:?:service_id$
+ */
+
+
+#define FRONTENDDEVICE "/dev/dvb/adapter%d/frontend%d"
+#define DEMUXDEVICE "/dev/dvb/adapter%d/demux%d"
+
+static struct lnb_types_st lnb_type;
+
+static int exit_after_tuning;
+static int interactive;
+
+static char *usage_str =
+    "\nusage: szap -q\n"
+    "         list known channels\n"
+    "       szap [options] {-n channel-number|channel_name}\n"
+    "         zap to channel via number or full name (case insensitive)\n"
+    "     -a number : use given adapter (default 0)\n"
+    "     -f number : use given frontend (default 0)\n"
+    "     -d number : use given demux (default 0)\n"
+    "     -c file   : read channels list from 'file'\n"
+    "     -x        : exit after tuning\n"
+    "     -r        : set up /dev/dvb/adapterX/dvr0 for TS recording\n"
+    "     -l lnb-type (DVB-S Only) (use -l help to print types) or \n"
+    "     -l low[,high[,switch]] in Mhz\n"
+    "     -i        : run interactively, allowing you to type in channel names\n"
+    "                 or -n numbers for zapping\n";
+
+static int set_demux(int dmxfd, int pid, int audio, int dvr)
+{
+   struct dmx_pes_filter_params pesfilter;
+
+   if (pid <= 0 || pid >= 0x1fff) /* ignore this pid to allow radio services */
+	   return TRUE;
+
+   if (dvr) {
+      int buffersize = 64 * 1024;
+      if (ioctl(dmxfd, DMX_SET_BUFFER_SIZE, buffersize) == -1)
+        perror("DMX_SET_BUFFER_SIZE failed");
+   }
+
+   pesfilter.pid = pid;
+   pesfilter.input = DMX_IN_FRONTEND;
+   pesfilter.output = dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER;
+   pesfilter.pes_type = audio ? DMX_PES_AUDIO : DMX_PES_VIDEO;
+   pesfilter.flags = DMX_IMMEDIATE_START;
+
+   if (ioctl(dmxfd, DMX_SET_PES_FILTER, &pesfilter) == -1) {
+      fprintf(stderr, "DMX_SET_PES_FILTER failed "
+	      "(PID = 0x%04x): %d %m\n", pid, errno);
+      return FALSE;
+   }
+
+   return TRUE;
+}
+
+
+struct diseqc_cmd {
+   struct dvb_diseqc_master_cmd cmd;
+   uint32_t wait;
+};
+
+void diseqc_send_msg(int fd, fe_sec_voltage_t v, struct diseqc_cmd *cmd,
+		     fe_sec_tone_mode_t t, fe_sec_mini_cmd_t b)
+{
+   if (ioctl(fd, FE_SET_TONE, SEC_TONE_OFF) == -1)
+      perror("FE_SET_TONE failed");
+   if (ioctl(fd, FE_SET_VOLTAGE, v) == -1)
+      perror("FE_SET_VOLTAGE failed");
+   usleep(15 * 1000);
+   if (ioctl(fd, FE_DISEQC_SEND_MASTER_CMD, &cmd->cmd) == -1)
+      perror("FE_DISEQC_SEND_MASTER_CMD failed");
+   usleep(cmd->wait * 1000);
+   usleep(15 * 1000);
+   if (ioctl(fd, FE_DISEQC_SEND_BURST, b) == -1)
+      perror("FE_DISEQC_SEND_BURST failed");
+   usleep(15 * 1000);
+   if (ioctl(fd, FE_SET_TONE, t) == -1)
+      perror("FE_SET_TONE failed");
+}
+
+
+
+
+/* digital satellite equipment control,
+ * specification is available from http://www.eutelsat.com/
+ */
+static int diseqc(int secfd, int sat_no, int pol_vert, int hi_band)
+{
+   struct diseqc_cmd cmd =
+       { {{0xe0, 0x10, 0x38, 0xf0, 0x00, 0x00}, 4}, 0 };
+
+   /* param: high nibble: reset bits, low nibble set bits,
+    * bits are: option, position, polarizaion, band
+    */
+   cmd.cmd.msg[3] =
+       0xf0 | (((sat_no * 4) & 0x0f) | (hi_band ? 1 : 0) | (pol_vert ? 0 : 2));
+
+   diseqc_send_msg(secfd, pol_vert ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18,
+		   &cmd, hi_band ? SEC_TONE_ON : SEC_TONE_OFF,
+		   (sat_no / 4) % 2 ? SEC_MINI_B : SEC_MINI_A);
+
+   return TRUE;
+}
+
+static int do_tune(int fefd, unsigned int ifreq, unsigned int sr)
+{
+   struct dvb_frontend_parameters tuneto;
+   struct dvb_frontend_event ev;
+
+   /* discard stale QPSK events */
+   while (1) {
+      if (ioctl(fefd, FE_GET_EVENT, &ev) == -1)
+	 break;
+   }
+
+   tuneto.frequency = ifreq;
+   tuneto.inversion = INVERSION_AUTO;
+   tuneto.u.qpsk.symbol_rate = sr;
+   tuneto.u.qpsk.fec_inner = FEC_AUTO;
+
+   if (ioctl(fefd, FE_SET_FRONTEND, &tuneto) == -1) {
+      perror("FE_SET_FRONTEND failed");
+      return FALSE;
+   }
+
+   return TRUE;
+}
+
+
+static
+int check_frontend (int fe_fd, int dvr)
+{
+   fe_status_t status;
+   uint16_t snr, signal;
+   uint32_t ber, uncorrected_blocks;
+   int timeout = 0;
+
+   do {
+      if (ioctl(fe_fd, FE_READ_STATUS, &status) == -1)
+         perror("FE_READ_STATUS failed");
+      /* some frontends might not support all these ioctls, thus we
+       * avoid printing errors */
+      if (ioctl(fe_fd, FE_READ_SIGNAL_STRENGTH, &signal) == -1)
+         signal = -2;
+      if (ioctl(fe_fd, FE_READ_SNR, &snr) == -1)
+         snr = -2;
+      if (ioctl(fe_fd, FE_READ_BER, &ber) == -1)
+         ber = -2;
+      if (ioctl(fe_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks) == -1)
+         uncorrected_blocks = -2;
+
+      printf ("status %02x | signal %04x | snr %04x | ber %08x | unc %08x | ",
+	      status, signal, snr, ber, uncorrected_blocks);
+
+      if (status & FE_HAS_LOCK)
+	 printf("FE_HAS_LOCK");
+      printf("\n");
+
+      if (exit_after_tuning && ((status & FE_HAS_LOCK) || (++timeout >= 10)))
+         break;
+
+      usleep(1000000);
+   } while (1);
+
+   return 0;
+}
+
+
+static
+int zap_to(unsigned int adapter, unsigned int frontend, unsigned int demux,
+      unsigned int sat_no, unsigned int freq, unsigned int pol,
+      unsigned int sr, unsigned int vpid, unsigned int apid, int dvr)
+{
+   char fedev[128], dmxdev[128];
+   static int fefd, videofd, audiofd;
+   uint32_t ifreq;
+   int hiband, result;
+   static struct dvb_frontend_info fe_info;
+
+   if (!fefd) {
+      snprintf(fedev, sizeof(fedev), FRONTENDDEVICE, adapter, frontend);
+      snprintf(dmxdev, sizeof(dmxdev), DEMUXDEVICE, adapter, demux);
+      printf("using '%s' and '%s'\n", fedev, dmxdev);
+
+      if ((fefd = open(fedev, O_RDWR | O_NONBLOCK)) < 0) {
+	 perror("opening frontend failed");
+	 return FALSE;
+      }
+
+      result = ioctl(fefd, FE_GET_INFO, &fe_info);
+
+      if (result < 0) {
+	 perror("ioctl FE_GET_INFO failed");
+	 close(fefd);
+	 return FALSE;
+      }
+
+      if (fe_info.type != FE_QPSK) {
+	 fprintf(stderr, "frontend device is not a QPSK (DVB-S) device!\n");
+	 close(fefd);
+	 return FALSE;
+      }
+
+      if ((videofd = open(dmxdev, O_RDWR)) < 0) {
+	 perror("opening video demux failed");
+	 close(fefd);
+	 return FALSE;
+      }
+
+      if ((audiofd = open(dmxdev, O_RDWR)) < 0) {
+	 perror("opening audio demux failed");
+	 close(videofd);
+	 close(fefd);
+	 return FALSE;
+      }
+   }
+
+   hiband = 0;
+   if (lnb_type.switch_val && lnb_type.high_val &&
+	freq >= lnb_type.switch_val)
+	hiband = 1;
+
+   if (hiband)
+      ifreq = freq - lnb_type.high_val;
+   else {
+      if (freq < lnb_type.low_val)
+          ifreq = lnb_type.low_val - freq;
+      else
+          ifreq = freq - lnb_type.low_val;
+   }
+   result = FALSE;
+
+   if (diseqc(fefd, sat_no, pol, hiband))
+      if (do_tune(fefd, ifreq, sr))
+	 if (set_demux(videofd, vpid, 0, dvr))
+	    if (set_demux(audiofd, apid, 1, dvr))
+	       result = TRUE;
+
+   check_frontend (fefd, dvr);
+
+   if (!interactive) {
+      close(audiofd);
+      close(videofd);
+      close(fefd);
+   }
+
+   return result;
+}
+
+
+static int read_channels(const char *filename, int list_channels,
+			 uint32_t chan_no, const char *chan_name,
+			 unsigned int adapter, unsigned int frontend,
+			 unsigned int demux, int dvr)
+{
+   FILE *cfp;
+   char buf[4096];
+   char inp[256];
+   char *field, *tmp, *p;
+   unsigned int line;
+   unsigned int freq, pol, sat_no, sr, vpid, apid;
+   int ret;
+
+again:
+   line = 0;
+   if (!(cfp = fopen(filename, "r"))) {
+      fprintf(stderr, "error opening channel list '%s': %d %m\n",
+	      filename, errno);
+      return FALSE;
+   }
+
+   if (interactive) {
+      fprintf(stderr, "\n>>> ");
+      if (!fgets(inp, sizeof(inp), stdin)) {
+	 printf("\n");
+	 return -1;
+      }
+      if (inp[0] == '-' && inp[1] == 'n') {
+	 chan_no = strtoul(inp+2, NULL, 0);
+	 chan_name = NULL;
+	 if (!chan_no) {
+	    fprintf(stderr, "bad channel number\n");
+	    goto again;
+	 }
+      } else {
+	 p = strchr(inp, '\n');
+	 if (p)
+	    *p = '\0';
+	 chan_name = inp;
+	 chan_no = 0;
+      }
+   }
+
+   while (!feof(cfp)) {
+      if (fgets(buf, sizeof(buf), cfp)) {
+	 line++;
+
+	 if (chan_no && chan_no != line)
+	    continue;
+
+	 tmp = buf;
+	 field = strsep(&tmp, ":");
+
+	 if (!field)
+	    goto syntax_err;
+
+	 if (list_channels) {
+	    printf("%03u %s\n", line, field);
+	    continue;
+	 }
+
+	 if (chan_name && strcasecmp(chan_name, field) != 0)
+	    continue;
+
+	 printf("zapping to %d '%s':\n", line, field);
+
+	 if (!(field = strsep(&tmp, ":")))
+	    goto syntax_err;
+
+	 freq = strtoul(field, NULL, 0);
+
+	 if (!(field = strsep(&tmp, ":")))
+	    goto syntax_err;
+
+	 pol = (field[0] == 'h' ? 0 : 1);
+
+	 if (!(field = strsep(&tmp, ":")))
+	    goto syntax_err;
+
+	 sat_no = strtoul(field, NULL, 0);
+
+	 if (!(field = strsep(&tmp, ":")))
+	    goto syntax_err;
+
+	 sr = strtoul(field, NULL, 0) * 1000;
+
+	 if (!(field = strsep(&tmp, ":")))
+	    goto syntax_err;
+
+	 vpid = strtoul(field, NULL, 0);
+
+	 if (!(field = strsep(&tmp, ":")))
+	    goto syntax_err;
+
+	 apid = strtoul(field, NULL, 0);
+
+	 printf("sat %u, frequency = %u MHz %c, symbolrate %u, "
+		"vpid = 0x%04x, apid = 0x%04x\n",
+		sat_no, freq, pol ? 'V' : 'H', sr, vpid, apid);
+
+	 fclose(cfp);
+
+	 ret = zap_to(adapter, frontend, demux,
+		      sat_no, freq * 1000, pol, sr, vpid, apid, dvr);
+	 if (interactive)
+	    goto again;
+
+	 if (ret)
+	    return TRUE;
+
+	 return FALSE;
+
+       syntax_err:
+	 fprintf(stderr, "syntax error in line %u: '%s'\n", line, buf);
+      } else if (ferror(cfp)) {
+	 fprintf(stderr, "error reading channel list '%s': %d %m\n",
+		 filename, errno);
+	 fclose(cfp);
+	 return FALSE;
+      } else
+	 break;
+   }
+
+   fclose(cfp);
+
+   if (!list_channels) {
+      fprintf(stderr, "channel not found\n");
+      if (!interactive)
+	 return FALSE;
+   }
+   if (interactive)
+      goto again;
+
+   return TRUE;
+}
+
+
+void
+bad_usage(char *pname, int prlnb)
+{
+int i;
+struct lnb_types_st *lnbp;
+char **cp;
+
+	if (!prlnb) {
+		fprintf (stderr, usage_str, pname);
+	} else {
+		i = 0;
+		fprintf(stderr, "-l <lnb-type> or -l low[,high[,switch]] in Mhz\nwhere <lnb-type> is:\n");
+		while(NULL != (lnbp = lnb_enum(i))) {
+			fprintf (stderr, "%s\n", lnbp->name);
+			for (cp = lnbp->desc; *cp ; cp++) {
+				fprintf (stderr, "   %s\n", *cp);
+			}
+			i++;
+		}
+	}
+}
+
+int main(int argc, char *argv[])
+{
+   const char *home;
+   char chanfile[2 * PATH_MAX];
+   int list_channels = 0;
+   unsigned int chan_no = 0;
+   const char *chan_name = NULL;
+   unsigned int adapter = 0, frontend = 0, demux = 0, dvr = 0;
+   int opt, copt = 0;
+
+   lnb_type = *lnb_enum(0);
+   while ((opt = getopt(argc, argv, "hqrn:a:f:d:c:l:xi")) != -1) {
+      switch (opt)
+      {
+	 case '?':
+	 case 'h':
+	 default:
+	    bad_usage(argv[0], 0);
+	 case 'q':
+	    list_channels = 1;
+	    break;
+	 case 'r':
+	    dvr = 1;
+	    break;
+	 case 'n':
+	    chan_no = strtoul(optarg, NULL, 0);
+	    break;
+	 case 'a':
+	    adapter = strtoul(optarg, NULL, 0);
+	    break;
+	 case 'f':
+	    frontend = strtoul(optarg, NULL, 0);
+	    break;
+	 case 'd':
+	    demux = strtoul(optarg, NULL, 0);
+	    break;
+	 case 'c':
+	    copt = 1;
+	    strncpy(chanfile, optarg, sizeof(chanfile));
+	    break;
+	 case 'l':
+	    if (lnb_decode(optarg, &lnb_type) < 0) {
+		bad_usage(argv[0], 1);
+		return -1;
+	    }
+	    break;
+	 case 'x':
+	    exit_after_tuning = 1;
+	    break;
+	 case 'i':
+	    interactive = 1;
+	    exit_after_tuning = 1;
+      }
+   }
+   lnb_type.low_val *= 1000;	/* convert to kiloherz */
+   lnb_type.high_val *= 1000;	/* convert to kiloherz */
+   lnb_type.switch_val *= 1000;	/* convert to kiloherz */
+   if (optind < argc)
+      chan_name = argv[optind];
+   if (chan_name && chan_no) {
+	bad_usage(argv[0], 0);
+	return -1;
+   }
+   if (list_channels && (chan_name || chan_no)) {
+	bad_usage(argv[0], 0);
+	return -1;
+   }
+   if (!list_channels && !chan_name && !chan_no && !interactive) {
+	bad_usage(argv[0], 0);
+	return -1;
+   }
+
+   if (!copt) {
+       if (!(home = getenv("HOME"))) {
+          fprintf(stderr, "error: $HOME not set\n");
+          return TRUE;
+       }
+       strncpy(chanfile, home, sizeof(chanfile));
+       strcat(chanfile, "/.szap/" CHANNEL_FILE);
+   }
+
+   printf("reading channels from file '%s'\n", chanfile);
+
+   if (!read_channels(chanfile, list_channels, chan_no, chan_name,
+	    adapter, frontend, demux, dvr))
+      return TRUE;
+
+   return FALSE;
+}
+
diff --git a/util/szap/tzap.c b/util/szap/tzap.c
new file mode 100644
index 0000000..2527c23
--- /dev/null
+++ b/util/szap/tzap.c
@@ -0,0 +1,477 @@
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <linux/dvb/frontend.h>
+#include <linux/dvb/dmx.h>
+
+
+static char FRONTEND_DEV [80];
+static char DEMUX_DEV [80];
+
+#define CHANNEL_FILE "/.tzap/channels.conf"
+
+#define ERROR(x...)                                                     \
+        do {                                                            \
+                fprintf(stderr, "ERROR: ");                             \
+                fprintf(stderr, x);                                     \
+                fprintf (stderr, "\n");                                 \
+        } while (0)
+
+#define PERROR(x...)                                                    \
+        do {                                                            \
+                fprintf(stderr, "ERROR: ");                             \
+                fprintf(stderr, x);                                     \
+                fprintf (stderr, " (%s)\n", strerror(errno));		\
+        } while (0)
+
+
+typedef struct {
+	char *name;
+	int value;
+} Param;
+
+static const Param inversion_list [] = {
+	{ "INVERSION_OFF", INVERSION_OFF },
+	{ "INVERSION_ON", INVERSION_ON },
+	{ "INVERSION_AUTO", INVERSION_AUTO }
+};
+
+static const Param bw_list [] = {
+	{ "BANDWIDTH_6_MHZ", BANDWIDTH_6_MHZ },
+	{ "BANDWIDTH_7_MHZ", BANDWIDTH_7_MHZ },
+	{ "BANDWIDTH_8_MHZ", BANDWIDTH_8_MHZ }
+};
+
+static const Param fec_list [] = {
+	{ "FEC_1_2", FEC_1_2 },
+	{ "FEC_2_3", FEC_2_3 },
+	{ "FEC_3_4", FEC_3_4 },
+	{ "FEC_4_5", FEC_4_5 },
+	{ "FEC_5_6", FEC_5_6 },
+	{ "FEC_6_7", FEC_6_7 },
+	{ "FEC_7_8", FEC_7_8 },
+	{ "FEC_8_9", FEC_8_9 },
+	{ "FEC_AUTO", FEC_AUTO },
+	{ "FEC_NONE", FEC_NONE }
+};
+
+static const Param guard_list [] = {
+	{"GUARD_INTERVAL_1_16", GUARD_INTERVAL_1_16},
+	{"GUARD_INTERVAL_1_32", GUARD_INTERVAL_1_32},
+	{"GUARD_INTERVAL_1_4", GUARD_INTERVAL_1_4},
+	{"GUARD_INTERVAL_1_8", GUARD_INTERVAL_1_8}
+};
+
+static const Param hierarchy_list [] = {
+	{ "HIERARCHY_1", HIERARCHY_1 },
+	{ "HIERARCHY_2", HIERARCHY_2 },
+	{ "HIERARCHY_4", HIERARCHY_4 },
+	{ "HIERARCHY_NONE", HIERARCHY_NONE }
+};
+
+static const Param constellation_list [] = {
+	{ "QPSK", QPSK },
+	{ "QAM_128", QAM_128 },
+	{ "QAM_16", QAM_16 },
+	{ "QAM_256", QAM_256 },
+	{ "QAM_32", QAM_32 },
+	{ "QAM_64", QAM_64 }
+};
+
+static const Param transmissionmode_list [] = {
+	{ "TRANSMISSION_MODE_2K", TRANSMISSION_MODE_2K },
+	{ "TRANSMISSION_MODE_8K", TRANSMISSION_MODE_8K },
+};
+
+#define LIST_SIZE(x) sizeof(x)/sizeof(Param)
+
+
+static
+int parse_param (int fd, const Param * plist, int list_size, int *param)
+{
+	char c;
+	int character = 0;
+	int index = 0;
+
+	while (1) {
+		if (read(fd, &c, 1) < 1)
+			return -1;	/*  EOF? */
+
+		if ((c == ':' || c == '\n')
+		    && plist->name[character] == '\0')
+			break;
+
+		while (toupper(c) != plist->name[character]) {
+			index++;
+			plist++;
+			if (index >= list_size)	 /*  parse error, no valid */
+				return -2;	 /*  parameter name found  */
+		}
+
+		character++;
+	}
+
+	*param = plist->value;
+
+	return 0;
+}
+
+
+static
+int parse_int(int fd, int *val)
+{
+	char number[11];	/* 2^32 needs 10 digits... */
+	int character = 0;
+
+	while (1) {
+		if (read(fd, &number[character], 1) < 1)
+			return -1;	/*  EOF? */
+
+		if (number[character] == ':' || number[character] == '\n') {
+			number[character] = '\0';
+			break;
+		}
+
+		if (!isdigit(number[character]))
+			return -2;	/*  parse error, not a digit... */
+
+		character++;
+
+		if (character > 10)	/*  overflow, number too big */
+			return -3;	/*  to fit in 32 bit */
+	};
+
+	*val = strtol(number, NULL, 10);
+
+	return 0;
+}
+
+
+static
+int find_channel(int fd, const char *channel)
+{
+	int character = 0;
+
+	while (1) {
+		char c;
+
+		if (read(fd, &c, 1) < 1)
+			return -1;	/*  EOF! */
+
+		if (c == ':' && channel[character] == '\0')
+			break;
+
+		if (toupper(c) == toupper(channel[character]))
+			character++;
+		else
+			character = 0;
+	};
+
+	return 0;
+}
+
+
+static
+int try_parse_int(int fd, int *val, const char *pname)
+{
+	int err;
+
+	err = parse_int(fd, val);
+
+	if (err)
+		ERROR("error while parsing %s (%s)", pname,
+		      err == -1 ? "end of file" :
+		      err == -2 ? "not a number" : "number too big");
+
+	return err;
+}
+
+
+static
+int try_parse_param(int fd, const Param * plist, int list_size, int *param,
+		    const char *pname)
+{
+	int err;
+
+	err = parse_param(fd, plist, list_size, param);
+
+	if (err)
+		ERROR("error while parsing %s (%s)", pname,
+		      err == -1 ? "end of file" : "syntax error");
+
+	return err;
+}
+
+
+int parse(const char *fname, const char *channel,
+	  struct dvb_frontend_parameters *frontend, int *vpid, int *apid)
+{
+	int fd;
+	int err;
+
+	if ((fd = open(fname, O_RDONLY | O_NONBLOCK)) < 0) {
+		PERROR ("could not open file '%s'", fname);
+		perror ("");
+		return -1;
+	}
+
+	if (find_channel(fd, channel) < 0) {
+		ERROR("could not find channel '%s' in channel list", channel);
+		return -2;
+	}
+
+	if ((err = try_parse_int(fd, &frontend->frequency, "frequency")))
+		return -3;
+
+	if ((err = try_parse_param(fd,
+				   inversion_list, LIST_SIZE(inversion_list),
+				   (int *) &frontend->inversion,
+				   "inversion")))
+		return -4;
+
+	if ((err = try_parse_param(fd, bw_list, LIST_SIZE(bw_list),
+				   (int *) &frontend->u.ofdm.bandwidth,
+				   "bandwidth")))
+		return -5;
+
+	if ((err = try_parse_param(fd, fec_list, LIST_SIZE(fec_list),
+				   (int *) &frontend->u.ofdm.code_rate_HP,
+				   "code_rate_HP")))
+		return -6;
+
+	if ((err = try_parse_param(fd, fec_list, LIST_SIZE(fec_list),
+				   (int *) &frontend->u.ofdm.code_rate_LP,
+				   "code_rate_LP")))
+		return -7;
+
+	if ((err = try_parse_param(fd, constellation_list,
+				   LIST_SIZE(constellation_list),
+				   (int *) &frontend->u.ofdm.constellation,
+				   "constellation")))
+		return -8;
+
+	if ((err = try_parse_param(fd, transmissionmode_list,
+				   LIST_SIZE(transmissionmode_list),
+				   (int *) &frontend->u.ofdm.
+				   transmission_mode,
+				   "transmission_mode")))
+		return -9;
+
+	if ((err = try_parse_param(fd, guard_list, LIST_SIZE(guard_list),
+				   (int *) &frontend->u.ofdm.
+				   guard_interval, "guard_interval")))
+		return -10;
+
+	if ((err = try_parse_param(fd, hierarchy_list,
+				   LIST_SIZE(hierarchy_list),
+				   (int *) &frontend->u.ofdm.
+				   hierarchy_information,
+				   "hierarchy_information")))
+		return -11;
+
+	if ((err = try_parse_int(fd, vpid, "Video PID")))
+		return -12;
+
+	if ((err = try_parse_int(fd, apid, "Audio PID")))
+		return -13;
+
+	close(fd);
+
+	return 0;
+}
+
+
+static
+int set_pesfilter (int fd, int pid, dmx_pes_type_t type, int dvr)
+{
+        struct dmx_pes_filter_params pesfilter;
+
+        if (pid <= 0 || pid >= 0x1fff)
+                return 0;
+
+        pesfilter.pid = pid;
+        pesfilter.input = DMX_IN_FRONTEND;
+        pesfilter.output = dvr ? DMX_OUT_TS_TAP : DMX_OUT_DECODER;
+        pesfilter.pes_type = type;
+        pesfilter.flags = DMX_IMMEDIATE_START;
+
+        if (ioctl(fd, DMX_SET_PES_FILTER, &pesfilter) < 0) {
+                PERROR ("ioctl(DMX_SET_PES_FILTER) for %s PID failed",
+                        type == DMX_PES_AUDIO ? "Audio" :
+                        type == DMX_PES_VIDEO ? "Video" : "??");
+                return -1;
+        }
+
+        return 0;
+}
+
+
+static
+int setup_frontend (int fe_fd, struct dvb_frontend_parameters *frontend)
+{
+	struct dvb_frontend_info fe_info;
+
+	if (ioctl(fe_fd, FE_GET_INFO, &fe_info) < 0) {
+		PERROR("ioctl FE_GET_INFO failed");
+		return -1;
+	}
+
+	if (fe_info.type != FE_OFDM) {
+		ERROR ("frontend device is not a OFDM (DVB-T) device");
+		return -1;
+	}
+
+	printf ("tuning to %i Hz\n", frontend->frequency);
+
+	if (ioctl(fe_fd, FE_SET_FRONTEND, frontend) < 0) {
+		PERROR("ioctl FE_SET_FRONTEND failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static
+int check_frontend (int fe_fd)
+{
+	fe_status_t status;
+	uint16_t snr, signal;
+	uint32_t ber, uncorrected_blocks;
+
+	do {
+		ioctl(fe_fd, FE_READ_STATUS, &status);
+		ioctl(fe_fd, FE_READ_SIGNAL_STRENGTH, &signal);
+		ioctl(fe_fd, FE_READ_SNR, &snr);
+		ioctl(fe_fd, FE_READ_BER, &ber);
+		ioctl(fe_fd, FE_READ_UNCORRECTED_BLOCKS, &uncorrected_blocks);
+
+		printf ("status %02x | signal %04x | snr %04x | "
+			"ber %08x | unc %08x | ",
+			status, signal, snr, ber, uncorrected_blocks);
+
+		if (status & FE_HAS_LOCK)
+			printf("FE_HAS_LOCK");
+
+		usleep(1000000);
+
+		printf("\n");
+	} while (1);
+
+	return 0;
+}
+
+
+static const char *usage = "\nusage: %s [-a adapter_num] [-f frontend_id] [-d demux_id] [-c conf_file] [-r] <channel name>\n\n";
+
+
+int main(int argc, char **argv)
+{
+	struct dvb_frontend_parameters frontend_param;
+	char *homedir = getenv ("HOME");
+	char *confname = NULL;
+	char *channel = NULL;
+	int adapter = 0, frontend = 0, demux = 0, dvr = 0;
+	int vpid, apid;
+	int frontend_fd, audio_fd, video_fd;
+	int opt;
+
+	while ((opt = getopt(argc, argv, "hrn:a:f:d:c:")) != -1) {
+		switch (opt) {
+		case 'a':
+			adapter = strtoul(optarg, NULL, 0);
+			break;
+		case 'f':
+			frontend = strtoul(optarg, NULL, 0);
+			break;
+		case 'd':
+			demux = strtoul(optarg, NULL, 0);
+			break;
+		case 'r':
+			dvr = 1;
+			break;
+		case 'c':
+			confname = optarg;
+			break;
+		case '?':
+		case 'h':
+		default:
+			fprintf (stderr, usage, argv[0]);
+			return -1;
+		};
+	}
+
+	if (optind < argc)
+		channel = argv[optind];
+
+	if (!channel) {
+		fprintf (stderr, usage, argv[0]);
+		return -1;
+	}
+
+	snprintf (FRONTEND_DEV, sizeof(FRONTEND_DEV),
+		  "/dev/dvb/adapter%i/frontend%i", adapter, frontend);
+
+	snprintf (DEMUX_DEV, sizeof(DEMUX_DEV),
+		  "/dev/dvb/adapter%i/demux%i", adapter, demux);
+
+	printf ("using '%s' and '%s'\n", FRONTEND_DEV, DEMUX_DEV);
+
+	if (!confname)
+	{
+		if (!homedir)
+			ERROR ("$HOME not set");
+		confname = malloc (strlen(homedir) + strlen(CHANNEL_FILE) + 1);
+		memcpy (confname, homedir, strlen(homedir));
+		memcpy (confname + strlen(homedir), CHANNEL_FILE,
+	        	strlen(CHANNEL_FILE) + 1);
+	}
+
+	memset(&frontend_param, 0, sizeof(struct dvb_frontend_parameters));
+
+	if (parse (confname, channel, &frontend_param, &vpid, &apid))
+		return -1;
+
+	if ((frontend_fd = open(FRONTEND_DEV, O_RDWR)) < 0) {
+		PERROR ("failed opening '%s'", FRONTEND_DEV);
+		return -1;
+	}
+
+	if (setup_frontend (frontend_fd, &frontend_param) < 0)
+		return -1;
+
+        if ((video_fd = open(DEMUX_DEV, O_RDWR)) < 0) {
+                PERROR("failed opening '%s'", DEMUX_DEV);
+                return -1;
+        }
+
+	printf ("video pid 0x%04x, audio pid 0x%04x\n", vpid, apid);
+	if (set_pesfilter (video_fd, vpid, DMX_PES_VIDEO, dvr) < 0)
+		return -1;
+
+	if ((audio_fd = open(DEMUX_DEV, O_RDWR)) < 0) {
+                PERROR("failed opening '%s'", DEMUX_DEV);
+                return -1;
+        }
+
+	if (set_pesfilter (audio_fd, apid, DMX_PES_AUDIO, dvr) < 0)
+		return -1;
+
+	check_frontend (frontend_fd);
+
+	close (audio_fd);
+	close (video_fd);
+	close (frontend_fd);
+
+	return 0;
+}
+
diff --git a/util/ttusb_dec_reset/Makefile b/util/ttusb_dec_reset/Makefile
new file mode 100644
index 0000000..cde7de5
--- /dev/null
+++ b/util/ttusb_dec_reset/Makefile
@@ -0,0 +1,17 @@
+CC	= gcc
+RM	= rm -f
+CFLAGS	= -g -Wall -O2
+LFLAGS	= -g -Wall
+LDFLAGS = -lusb
+
+OBJS	= ttusb_dec_reset.o
+TARGET	= ttusb_dec_reset
+
+$(TARGET): $(OBJS)
+	$(CC) $(LFLAGS) $(LDFLAGS) -o $(TARGET) $(OBJS)
+
+.c.o:
+	$(CC) $(CFLAGS) -c $< -o $@
+
+clean:
+	$(RM) *.o $(TARGET)
diff --git a/util/ttusb_dec_reset/README b/util/ttusb_dec_reset/README
new file mode 100644
index 0000000..50db265
--- /dev/null
+++ b/util/ttusb_dec_reset/README
@@ -0,0 +1,28 @@
+Hello,
+
+In theory the driver could be made to send the DEC the reset sequence when
+all devices were closed.  However, due to the awkwardness of switching
+between slave and stand-alone mode, I've decided against this.  Hence this
+application, which I hope provides the user a nice compromise between
+control and ease-of-use.
+
+ttusb_dec_reset is a small utility for resetting a ttusb-dec device to
+stand-alone mode after use.  It requires libusb, which can be found here:
+
+http://libusb.sourceforge.net/
+
+There is probably a package for it included with your linux distribution
+though.
+
+For the utility to reset a device, it must have permission to access the usb
+device, and the device must not be claimed by anything else.  That means that
+the ttusb-dec module must be rmmoded before using this utility.  You probably
+want to have turned off any hotplug mechanisms before running the utility
+or the device will likely get taken over again once it comes back up.  Or you
+could just yank the usb cable out.
+
+The utility takes no arguments, you just run it:
+./ttusb_dec_reset
+
+Cheers,
+Alex
diff --git a/util/ttusb_dec_reset/ttusb_dec_reset.c b/util/ttusb_dec_reset/ttusb_dec_reset.c
new file mode 100644
index 0000000..51ddfc7
--- /dev/null
+++ b/util/ttusb_dec_reset/ttusb_dec_reset.c
@@ -0,0 +1,53 @@
+#include <stdio.h>
+#include <usb.h>
+
+void dec_reset(struct usb_device *dev)
+{
+	char message[] = {0xaa, 0x00, 0xf1, 0x01, 0x00};
+	usb_dev_handle *handle = usb_open(dev);
+
+	printf("Device found.\n");
+
+	if (handle) {
+		if (!usb_claim_interface(handle, 0)) {
+			int result;
+			printf("Reseting device.. ");
+			result = usb_bulk_write(handle, 3, message,
+						sizeof(message), 1000);
+			if (result >= 0)
+				printf("succeeded.\n");
+			else
+				printf("failed. (Error code: %d)\n", result);
+		} else {
+			printf("Couldn't claim interface.\n");
+		}
+		usb_close(handle);
+	}
+}
+
+int main()
+{
+	struct usb_bus *busses;
+	struct usb_bus *bus;
+
+	usb_init();
+	usb_find_busses();
+	usb_find_devices();
+
+	busses = usb_get_busses();
+
+	for (bus = busses; bus; bus = bus->next) {
+		struct usb_device *dev;
+
+		for (dev = bus->devices; dev; dev = dev->next) {
+			if (dev->descriptor.idVendor == 0x0b48 &&
+			    (dev->descriptor.idProduct == 0x1006 ||
+			     dev->descriptor.idProduct == 0x1008 ||
+			     dev->descriptor.idProduct == 0x1009)) {
+				dec_reset(dev);
+			}
+		}
+	}
+
+	return 0;
+}

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-vdr-dvb/linuxtv-dvb-apps.git



More information about the pkg-vdr-dvb-changes mailing list