[media] dvb: move the dvb core one level up
authorMauro Carvalho Chehab <mchehab@redhat.com>
Thu, 14 Jun 2012 19:35:53 +0000 (16:35 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 14 Aug 2012 02:08:14 +0000 (23:08 -0300)
just like the V4L2 core, move the DVB core to drivers/media, as the
intention is to get rid of both "video" and "dvb" directories.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
83 files changed:
drivers/media/Kconfig
drivers/media/Makefile
drivers/media/common/tuners/Makefile
drivers/media/dvb-core/Kconfig [new file with mode: 0644]
drivers/media/dvb-core/Makefile [new file with mode: 0644]
drivers/media/dvb-core/demux.h [new file with mode: 0644]
drivers/media/dvb-core/dmxdev.c [new file with mode: 0644]
drivers/media/dvb-core/dmxdev.h [new file with mode: 0644]
drivers/media/dvb-core/dvb-usb-ids.h [new file with mode: 0644]
drivers/media/dvb-core/dvb_ca_en50221.c [new file with mode: 0644]
drivers/media/dvb-core/dvb_ca_en50221.h [new file with mode: 0644]
drivers/media/dvb-core/dvb_demux.c [new file with mode: 0644]
drivers/media/dvb-core/dvb_demux.h [new file with mode: 0644]
drivers/media/dvb-core/dvb_filter.c [new file with mode: 0644]
drivers/media/dvb-core/dvb_filter.h [new file with mode: 0644]
drivers/media/dvb-core/dvb_frontend.c [new file with mode: 0644]
drivers/media/dvb-core/dvb_frontend.h [new file with mode: 0644]
drivers/media/dvb-core/dvb_math.c [new file with mode: 0644]
drivers/media/dvb-core/dvb_math.h [new file with mode: 0644]
drivers/media/dvb-core/dvb_net.c [new file with mode: 0644]
drivers/media/dvb-core/dvb_net.h [new file with mode: 0644]
drivers/media/dvb-core/dvb_ringbuffer.c [new file with mode: 0644]
drivers/media/dvb-core/dvb_ringbuffer.h [new file with mode: 0644]
drivers/media/dvb-core/dvbdev.c [new file with mode: 0644]
drivers/media/dvb-core/dvbdev.h [new file with mode: 0644]
drivers/media/dvb/Kconfig
drivers/media/dvb/Makefile
drivers/media/dvb/b2c2/Makefile
drivers/media/dvb/bt8xx/Makefile
drivers/media/dvb/ddbridge/Makefile
drivers/media/dvb/dm1105/Makefile
drivers/media/dvb/dvb-core/Makefile [deleted file]
drivers/media/dvb/dvb-core/demux.h [deleted file]
drivers/media/dvb/dvb-core/dmxdev.c [deleted file]
drivers/media/dvb/dvb-core/dmxdev.h [deleted file]
drivers/media/dvb/dvb-core/dvb-usb-ids.h [deleted file]
drivers/media/dvb/dvb-core/dvb_ca_en50221.c [deleted file]
drivers/media/dvb/dvb-core/dvb_ca_en50221.h [deleted file]
drivers/media/dvb/dvb-core/dvb_demux.c [deleted file]
drivers/media/dvb/dvb-core/dvb_demux.h [deleted file]
drivers/media/dvb/dvb-core/dvb_filter.c [deleted file]
drivers/media/dvb/dvb-core/dvb_filter.h [deleted file]
drivers/media/dvb/dvb-core/dvb_frontend.c [deleted file]
drivers/media/dvb/dvb-core/dvb_frontend.h [deleted file]
drivers/media/dvb/dvb-core/dvb_math.c [deleted file]
drivers/media/dvb/dvb-core/dvb_math.h [deleted file]
drivers/media/dvb/dvb-core/dvb_net.c [deleted file]
drivers/media/dvb/dvb-core/dvb_net.h [deleted file]
drivers/media/dvb/dvb-core/dvb_ringbuffer.c [deleted file]
drivers/media/dvb/dvb-core/dvb_ringbuffer.h [deleted file]
drivers/media/dvb/dvb-core/dvbdev.c [deleted file]
drivers/media/dvb/dvb-core/dvbdev.h [deleted file]
drivers/media/dvb/dvb-usb-v2/Makefile
drivers/media/dvb/dvb-usb/Makefile
drivers/media/dvb/firewire/Makefile
drivers/media/dvb/frontends/Makefile
drivers/media/dvb/mantis/Makefile
drivers/media/dvb/ngene/Makefile
drivers/media/dvb/pluto2/Makefile
drivers/media/dvb/pt1/Makefile
drivers/media/dvb/siano/Makefile
drivers/media/dvb/ttpci/Makefile
drivers/media/dvb/ttusb-budget/Makefile
drivers/media/dvb/ttusb-dec/Makefile
drivers/media/v4l2-core/Makefile
drivers/media/video/Makefile
drivers/media/video/au0828/Makefile
drivers/media/video/bt8xx/Makefile
drivers/media/video/cx18/Makefile
drivers/media/video/cx231xx/Makefile
drivers/media/video/cx23885/Makefile
drivers/media/video/cx25821/Makefile
drivers/media/video/cx88/Makefile
drivers/media/video/em28xx/Makefile
drivers/media/video/ivtv/Makefile
drivers/media/video/pvrusb2/Makefile
drivers/media/video/saa7134/Makefile
drivers/media/video/saa7164/Makefile
drivers/media/video/tlg2300/Makefile
drivers/media/video/tm6000/Makefile
drivers/staging/media/as102/Makefile
drivers/staging/media/cxd2099/Makefile
drivers/staging/media/go7007/Makefile

index e6253628059ac88ecb61a43a9571d4936ebeb4d2..bda568af986f56ac8ff4281404f4fbaa37616a7f 100644 (file)
@@ -161,6 +161,7 @@ source "drivers/media/radio/Kconfig"
 # DVB adapters
 #
 
+source "drivers/media/dvb-core/Kconfig"
 source "drivers/media/dvb/Kconfig"
 
 endif # MEDIA_SUPPORT
index 2f9abaad18f75b583de8cd7515690895d422e153..7f9f99ab6ccc31e3e92259df11671f0a072578c1 100644 (file)
@@ -11,4 +11,4 @@ endif
 obj-y += v4l2-core/ common/ rc/ video/
 
 obj-$(CONFIG_VIDEO_DEV) += radio/
-obj-$(CONFIG_DVB_CORE)  += dvb/
+obj-$(CONFIG_DVB_CORE)  += dvb-core/ dvb/
index 891b80e60808d6aac66c81053c13eb4d106689bd..2ddbb2cf0e2ca25de42a2618493d4b3b1cf22a59 100644 (file)
@@ -33,5 +33,5 @@ obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o
 obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o
 obj-$(CONFIG_MEDIA_TUNER_FC0013) += fc0013.o
 
-ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
diff --git a/drivers/media/dvb-core/Kconfig b/drivers/media/dvb-core/Kconfig
new file mode 100644 (file)
index 0000000..fa7a249
--- /dev/null
@@ -0,0 +1,29 @@
+#
+# DVB device configuration
+#
+
+config DVB_MAX_ADAPTERS
+       int "maximum number of DVB/ATSC adapters"
+       depends on DVB_CORE
+       default 8
+       range 1 255
+       help
+         Maximum number of DVB/ATSC adapters. Increasing this number
+         increases the memory consumption of the DVB subsystem even
+         if a much lower number of DVB/ATSC adapters is present.
+         Only values in the range 4-32 are tested.
+
+         If you are unsure about this, use the default value 8
+
+config DVB_DYNAMIC_MINORS
+       bool "Dynamic DVB minor allocation"
+       depends on DVB_CORE
+       default n
+       help
+         If you say Y here, the DVB subsystem will use dynamic minor
+         allocation for any device that uses the DVB major number.
+         This means that you can have more than 4 of a single type
+         of device (like demuxes and frontends) per adapter, but udev
+         will be required to manage the device nodes.
+
+         If you are unsure about this, say N here.
diff --git a/drivers/media/dvb-core/Makefile b/drivers/media/dvb-core/Makefile
new file mode 100644 (file)
index 0000000..8f22bcd
--- /dev/null
@@ -0,0 +1,11 @@
+#
+# Makefile for the kernel DVB device drivers.
+#
+
+dvb-net-$(CONFIG_DVB_NET) := dvb_net.o
+
+dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o    \
+                dvb_ca_en50221.o dvb_frontend.o                \
+                $(dvb-net-y) dvb_ringbuffer.o dvb_math.o
+
+obj-$(CONFIG_DVB_CORE) += dvb-core.o
diff --git a/drivers/media/dvb-core/demux.h b/drivers/media/dvb-core/demux.h
new file mode 100644 (file)
index 0000000..eb91fd8
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * demux.h
+ *
+ * Copyright (c) 2002 Convergence GmbH
+ *
+ * based on code:
+ * Copyright (c) 2000 Nokia Research Center
+ *                    Tampere, FINLAND
+ *
+ * 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 __DEMUX_H
+#define __DEMUX_H
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/list.h>
+#include <linux/time.h>
+#include <linux/dvb/dmx.h>
+
+/*--------------------------------------------------------------------------*/
+/* Common definitions */
+/*--------------------------------------------------------------------------*/
+
+/*
+ * DMX_MAX_FILTER_SIZE: Maximum length (in bytes) of a section/PES filter.
+ */
+
+#ifndef DMX_MAX_FILTER_SIZE
+#define DMX_MAX_FILTER_SIZE 18
+#endif
+
+/*
+ * DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed filter.
+ */
+
+#ifndef DMX_MAX_SECTION_SIZE
+#define DMX_MAX_SECTION_SIZE 4096
+#endif
+#ifndef DMX_MAX_SECFEED_SIZE
+#define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188)
+#endif
+
+
+/*
+ * enum dmx_success: Success codes for the Demux Callback API.
+ */
+
+enum dmx_success {
+  DMX_OK = 0, /* Received Ok */
+  DMX_LENGTH_ERROR, /* Incorrect length */
+  DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */
+  DMX_CRC_ERROR, /* Incorrect CRC */
+  DMX_FRAME_ERROR, /* Frame alignment error */
+  DMX_FIFO_ERROR, /* Receiver FIFO overrun */
+  DMX_MISSED_ERROR /* Receiver missed packet */
+} ;
+
+/*--------------------------------------------------------------------------*/
+/* TS packet reception */
+/*--------------------------------------------------------------------------*/
+
+/* TS filter type for set() */
+
+#define TS_PACKET       1   /* send TS packets (188 bytes) to callback (default) */
+#define        TS_PAYLOAD_ONLY 2   /* in case TS_PACKET is set, only send the TS
+                              payload (<=184 bytes per packet) to callback */
+#define TS_DECODER      4   /* send stream to built-in decoder (if present) */
+#define TS_DEMUX        8   /* in case TS_PACKET is set, send the TS to
+                              the demux device, not to the dvr device */
+
+/* PES type for filters which write to built-in decoder */
+/* these should be kept identical to the types in dmx.h */
+
+enum dmx_ts_pes
+{  /* also send packets to decoder (if it exists) */
+       DMX_TS_PES_AUDIO0,
+       DMX_TS_PES_VIDEO0,
+       DMX_TS_PES_TELETEXT0,
+       DMX_TS_PES_SUBTITLE0,
+       DMX_TS_PES_PCR0,
+
+       DMX_TS_PES_AUDIO1,
+       DMX_TS_PES_VIDEO1,
+       DMX_TS_PES_TELETEXT1,
+       DMX_TS_PES_SUBTITLE1,
+       DMX_TS_PES_PCR1,
+
+       DMX_TS_PES_AUDIO2,
+       DMX_TS_PES_VIDEO2,
+       DMX_TS_PES_TELETEXT2,
+       DMX_TS_PES_SUBTITLE2,
+       DMX_TS_PES_PCR2,
+
+       DMX_TS_PES_AUDIO3,
+       DMX_TS_PES_VIDEO3,
+       DMX_TS_PES_TELETEXT3,
+       DMX_TS_PES_SUBTITLE3,
+       DMX_TS_PES_PCR3,
+
+       DMX_TS_PES_OTHER
+};
+
+#define DMX_TS_PES_AUDIO    DMX_TS_PES_AUDIO0
+#define DMX_TS_PES_VIDEO    DMX_TS_PES_VIDEO0
+#define DMX_TS_PES_TELETEXT DMX_TS_PES_TELETEXT0
+#define DMX_TS_PES_SUBTITLE DMX_TS_PES_SUBTITLE0
+#define DMX_TS_PES_PCR      DMX_TS_PES_PCR0
+
+
+struct dmx_ts_feed {
+       int is_filtering; /* Set to non-zero when filtering in progress */
+       struct dmx_demux *parent; /* Back-pointer */
+       void *priv; /* Pointer to private data of the API client */
+       int (*set) (struct dmx_ts_feed *feed,
+                   u16 pid,
+                   int type,
+                   enum dmx_ts_pes pes_type,
+                   size_t circular_buffer_size,
+                   struct timespec timeout);
+       int (*start_filtering) (struct dmx_ts_feed* feed);
+       int (*stop_filtering) (struct dmx_ts_feed* feed);
+};
+
+/*--------------------------------------------------------------------------*/
+/* Section reception */
+/*--------------------------------------------------------------------------*/
+
+struct dmx_section_filter {
+       u8 filter_value [DMX_MAX_FILTER_SIZE];
+       u8 filter_mask [DMX_MAX_FILTER_SIZE];
+       u8 filter_mode [DMX_MAX_FILTER_SIZE];
+       struct dmx_section_feed* parent; /* Back-pointer */
+       void* priv; /* Pointer to private data of the API client */
+};
+
+struct dmx_section_feed {
+       int is_filtering; /* Set to non-zero when filtering in progress */
+       struct dmx_demux* parent; /* Back-pointer */
+       void* priv; /* Pointer to private data of the API client */
+
+       int check_crc;
+       u32 crc_val;
+
+       u8 *secbuf;
+       u8 secbuf_base[DMX_MAX_SECFEED_SIZE];
+       u16 secbufp, seclen, tsfeedp;
+
+       int (*set) (struct dmx_section_feed* feed,
+                   u16 pid,
+                   size_t circular_buffer_size,
+                   int check_crc);
+       int (*allocate_filter) (struct dmx_section_feed* feed,
+                               struct dmx_section_filter** filter);
+       int (*release_filter) (struct dmx_section_feed* feed,
+                              struct dmx_section_filter* filter);
+       int (*start_filtering) (struct dmx_section_feed* feed);
+       int (*stop_filtering) (struct dmx_section_feed* feed);
+};
+
+/*--------------------------------------------------------------------------*/
+/* Callback functions */
+/*--------------------------------------------------------------------------*/
+
+typedef int (*dmx_ts_cb) ( const u8 * buffer1,
+                          size_t buffer1_length,
+                          const u8 * buffer2,
+                          size_t buffer2_length,
+                          struct dmx_ts_feed* source,
+                          enum dmx_success success);
+
+typedef int (*dmx_section_cb) (        const u8 * buffer1,
+                               size_t buffer1_len,
+                               const u8 * buffer2,
+                               size_t buffer2_len,
+                               struct dmx_section_filter * source,
+                               enum dmx_success success);
+
+/*--------------------------------------------------------------------------*/
+/* DVB Front-End */
+/*--------------------------------------------------------------------------*/
+
+enum dmx_frontend_source {
+       DMX_MEMORY_FE,
+       DMX_FRONTEND_0,
+       DMX_FRONTEND_1,
+       DMX_FRONTEND_2,
+       DMX_FRONTEND_3,
+       DMX_STREAM_0,    /* external stream input, e.g. LVDS */
+       DMX_STREAM_1,
+       DMX_STREAM_2,
+       DMX_STREAM_3
+};
+
+struct dmx_frontend {
+       struct list_head connectivity_list; /* List of front-ends that can
+                                              be connected to a particular
+                                              demux */
+       enum dmx_frontend_source source;
+};
+
+/*--------------------------------------------------------------------------*/
+/* MPEG-2 TS Demux */
+/*--------------------------------------------------------------------------*/
+
+/*
+ * Flags OR'ed in the capabilities field of struct dmx_demux.
+ */
+
+#define DMX_TS_FILTERING                        1
+#define DMX_PES_FILTERING                       2
+#define DMX_SECTION_FILTERING                   4
+#define DMX_MEMORY_BASED_FILTERING              8    /* write() available */
+#define DMX_CRC_CHECKING                        16
+#define DMX_TS_DESCRAMBLING                     32
+
+/*
+ * Demux resource type identifier.
+*/
+
+/*
+ * DMX_FE_ENTRY(): Casts elements in the list of registered
+ * front-ends from the generic type struct list_head
+ * to the type * struct dmx_frontend
+ *.
+*/
+
+#define DMX_FE_ENTRY(list) list_entry(list, struct dmx_frontend, connectivity_list)
+
+struct dmx_demux {
+       u32 capabilities;            /* Bitfield of capability flags */
+       struct dmx_frontend* frontend;    /* Front-end connected to the demux */
+       void* priv;                  /* Pointer to private data of the API client */
+       int (*open) (struct dmx_demux* demux);
+       int (*close) (struct dmx_demux* demux);
+       int (*write) (struct dmx_demux* demux, const char __user *buf, size_t count);
+       int (*allocate_ts_feed) (struct dmx_demux* demux,
+                                struct dmx_ts_feed** feed,
+                                dmx_ts_cb callback);
+       int (*release_ts_feed) (struct dmx_demux* demux,
+                               struct dmx_ts_feed* feed);
+       int (*allocate_section_feed) (struct dmx_demux* demux,
+                                     struct dmx_section_feed** feed,
+                                     dmx_section_cb callback);
+       int (*release_section_feed) (struct dmx_demux* demux,
+                                    struct dmx_section_feed* feed);
+       int (*add_frontend) (struct dmx_demux* demux,
+                            struct dmx_frontend* frontend);
+       int (*remove_frontend) (struct dmx_demux* demux,
+                               struct dmx_frontend* frontend);
+       struct list_head* (*get_frontends) (struct dmx_demux* demux);
+       int (*connect_frontend) (struct dmx_demux* demux,
+                                struct dmx_frontend* frontend);
+       int (*disconnect_frontend) (struct dmx_demux* demux);
+
+       int (*get_pes_pids) (struct dmx_demux* demux, u16 *pids);
+
+       int (*get_caps) (struct dmx_demux* demux, struct dmx_caps *caps);
+
+       int (*set_source) (struct dmx_demux* demux, const dmx_source_t *src);
+
+       int (*get_stc) (struct dmx_demux* demux, unsigned int num,
+                       u64 *stc, unsigned int *base);
+};
+
+#endif /* #ifndef __DEMUX_H */
diff --git a/drivers/media/dvb-core/dmxdev.c b/drivers/media/dvb-core/dmxdev.c
new file mode 100644 (file)
index 0000000..889c9c1
--- /dev/null
@@ -0,0 +1,1275 @@
+/*
+ * dmxdev.c - DVB demultiplexer device
+ *
+ * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
+ *                   for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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 <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/ioctl.h>
+#include <linux/wait.h>
+#include <asm/uaccess.h>
+#include "dmxdev.h"
+
+static int debug;
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define dprintk        if (debug) printk
+
+static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
+                                  const u8 *src, size_t len)
+{
+       ssize_t free;
+
+       if (!len)
+               return 0;
+       if (!buf->data)
+               return 0;
+
+       free = dvb_ringbuffer_free(buf);
+       if (len > free) {
+               dprintk("dmxdev: buffer overflow\n");
+               return -EOVERFLOW;
+       }
+
+       return dvb_ringbuffer_write(buf, src, len);
+}
+
+static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
+                                     int non_blocking, char __user *buf,
+                                     size_t count, loff_t *ppos)
+{
+       size_t todo;
+       ssize_t avail;
+       ssize_t ret = 0;
+
+       if (!src->data)
+               return 0;
+
+       if (src->error) {
+               ret = src->error;
+               dvb_ringbuffer_flush(src);
+               return ret;
+       }
+
+       for (todo = count; todo > 0; todo -= ret) {
+               if (non_blocking && dvb_ringbuffer_empty(src)) {
+                       ret = -EWOULDBLOCK;
+                       break;
+               }
+
+               ret = wait_event_interruptible(src->queue,
+                                              !dvb_ringbuffer_empty(src) ||
+                                              (src->error != 0));
+               if (ret < 0)
+                       break;
+
+               if (src->error) {
+                       ret = src->error;
+                       dvb_ringbuffer_flush(src);
+                       break;
+               }
+
+               avail = dvb_ringbuffer_avail(src);
+               if (avail > todo)
+                       avail = todo;
+
+               ret = dvb_ringbuffer_read_user(src, buf, avail);
+               if (ret < 0)
+                       break;
+
+               buf += ret;
+       }
+
+       return (count - todo) ? (count - todo) : ret;
+}
+
+static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type)
+{
+       struct list_head *head, *pos;
+
+       head = demux->get_frontends(demux);
+       if (!head)
+               return NULL;
+       list_for_each(pos, head)
+               if (DMX_FE_ENTRY(pos)->source == type)
+                       return DMX_FE_ENTRY(pos);
+
+       return NULL;
+}
+
+static int dvb_dvr_open(struct inode *inode, struct file *file)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dmxdev *dmxdev = dvbdev->priv;
+       struct dmx_frontend *front;
+
+       dprintk("function : %s\n", __func__);
+
+       if (mutex_lock_interruptible(&dmxdev->mutex))
+               return -ERESTARTSYS;
+
+       if (dmxdev->exit) {
+               mutex_unlock(&dmxdev->mutex);
+               return -ENODEV;
+       }
+
+       if ((file->f_flags & O_ACCMODE) == O_RDWR) {
+               if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -EOPNOTSUPP;
+               }
+       }
+
+       if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+               void *mem;
+               if (!dvbdev->readers) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -EBUSY;
+               }
+               mem = vmalloc(DVR_BUFFER_SIZE);
+               if (!mem) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -ENOMEM;
+               }
+               dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
+               dvbdev->readers--;
+       }
+
+       if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
+               dmxdev->dvr_orig_fe = dmxdev->demux->frontend;
+
+               if (!dmxdev->demux->write) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -EOPNOTSUPP;
+               }
+
+               front = get_fe(dmxdev->demux, DMX_MEMORY_FE);
+
+               if (!front) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -EINVAL;
+               }
+               dmxdev->demux->disconnect_frontend(dmxdev->demux);
+               dmxdev->demux->connect_frontend(dmxdev->demux, front);
+       }
+       dvbdev->users++;
+       mutex_unlock(&dmxdev->mutex);
+       return 0;
+}
+
+static int dvb_dvr_release(struct inode *inode, struct file *file)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dmxdev *dmxdev = dvbdev->priv;
+
+       mutex_lock(&dmxdev->mutex);
+
+       if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
+               dmxdev->demux->disconnect_frontend(dmxdev->demux);
+               dmxdev->demux->connect_frontend(dmxdev->demux,
+                                               dmxdev->dvr_orig_fe);
+       }
+       if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+               dvbdev->readers++;
+               if (dmxdev->dvr_buffer.data) {
+                       void *mem = dmxdev->dvr_buffer.data;
+                       mb();
+                       spin_lock_irq(&dmxdev->lock);
+                       dmxdev->dvr_buffer.data = NULL;
+                       spin_unlock_irq(&dmxdev->lock);
+                       vfree(mem);
+               }
+       }
+       /* TODO */
+       dvbdev->users--;
+       if (dvbdev->users == 1 && dmxdev->exit == 1) {
+               fops_put(file->f_op);
+               file->f_op = NULL;
+               mutex_unlock(&dmxdev->mutex);
+               wake_up(&dvbdev->wait_queue);
+       } else
+               mutex_unlock(&dmxdev->mutex);
+
+       return 0;
+}
+
+static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
+                            size_t count, loff_t *ppos)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dmxdev *dmxdev = dvbdev->priv;
+       int ret;
+
+       if (!dmxdev->demux->write)
+               return -EOPNOTSUPP;
+       if ((file->f_flags & O_ACCMODE) != O_WRONLY)
+               return -EINVAL;
+       if (mutex_lock_interruptible(&dmxdev->mutex))
+               return -ERESTARTSYS;
+
+       if (dmxdev->exit) {
+               mutex_unlock(&dmxdev->mutex);
+               return -ENODEV;
+       }
+       ret = dmxdev->demux->write(dmxdev->demux, buf, count);
+       mutex_unlock(&dmxdev->mutex);
+       return ret;
+}
+
+static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
+                           loff_t *ppos)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dmxdev *dmxdev = dvbdev->priv;
+
+       if (dmxdev->exit)
+               return -ENODEV;
+
+       return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
+                                     file->f_flags & O_NONBLOCK,
+                                     buf, count, ppos);
+}
+
+static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
+                                     unsigned long size)
+{
+       struct dvb_ringbuffer *buf = &dmxdev->dvr_buffer;
+       void *newmem;
+       void *oldmem;
+
+       dprintk("function : %s\n", __func__);
+
+       if (buf->size == size)
+               return 0;
+       if (!size)
+               return -EINVAL;
+
+       newmem = vmalloc(size);
+       if (!newmem)
+               return -ENOMEM;
+
+       oldmem = buf->data;
+
+       spin_lock_irq(&dmxdev->lock);
+       buf->data = newmem;
+       buf->size = size;
+
+       /* reset and not flush in case the buffer shrinks */
+       dvb_ringbuffer_reset(buf);
+       spin_unlock_irq(&dmxdev->lock);
+
+       vfree(oldmem);
+
+       return 0;
+}
+
+static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter
+                                              *dmxdevfilter, int state)
+{
+       spin_lock_irq(&dmxdevfilter->dev->lock);
+       dmxdevfilter->state = state;
+       spin_unlock_irq(&dmxdevfilter->dev->lock);
+}
+
+static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter,
+                                     unsigned long size)
+{
+       struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
+       void *newmem;
+       void *oldmem;
+
+       if (buf->size == size)
+               return 0;
+       if (!size)
+               return -EINVAL;
+       if (dmxdevfilter->state >= DMXDEV_STATE_GO)
+               return -EBUSY;
+
+       newmem = vmalloc(size);
+       if (!newmem)
+               return -ENOMEM;
+
+       oldmem = buf->data;
+
+       spin_lock_irq(&dmxdevfilter->dev->lock);
+       buf->data = newmem;
+       buf->size = size;
+
+       /* reset and not flush in case the buffer shrinks */
+       dvb_ringbuffer_reset(buf);
+       spin_unlock_irq(&dmxdevfilter->dev->lock);
+
+       vfree(oldmem);
+
+       return 0;
+}
+
+static void dvb_dmxdev_filter_timeout(unsigned long data)
+{
+       struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data;
+
+       dmxdevfilter->buffer.error = -ETIMEDOUT;
+       spin_lock_irq(&dmxdevfilter->dev->lock);
+       dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
+       spin_unlock_irq(&dmxdevfilter->dev->lock);
+       wake_up(&dmxdevfilter->buffer.queue);
+}
+
+static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
+{
+       struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec;
+
+       del_timer(&dmxdevfilter->timer);
+       if (para->timeout) {
+               dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout;
+               dmxdevfilter->timer.data = (unsigned long)dmxdevfilter;
+               dmxdevfilter->timer.expires =
+                   jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000;
+               add_timer(&dmxdevfilter->timer);
+       }
+}
+
+static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
+                                      const u8 *buffer2, size_t buffer2_len,
+                                      struct dmx_section_filter *filter,
+                                      enum dmx_success success)
+{
+       struct dmxdev_filter *dmxdevfilter = filter->priv;
+       int ret;
+
+       if (dmxdevfilter->buffer.error) {
+               wake_up(&dmxdevfilter->buffer.queue);
+               return 0;
+       }
+       spin_lock(&dmxdevfilter->dev->lock);
+       if (dmxdevfilter->state != DMXDEV_STATE_GO) {
+               spin_unlock(&dmxdevfilter->dev->lock);
+               return 0;
+       }
+       del_timer(&dmxdevfilter->timer);
+       dprintk("dmxdev: section callback %*ph\n", 6, buffer1);
+       ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,
+                                     buffer1_len);
+       if (ret == buffer1_len) {
+               ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2,
+                                             buffer2_len);
+       }
+       if (ret < 0) {
+               dvb_ringbuffer_flush(&dmxdevfilter->buffer);
+               dmxdevfilter->buffer.error = ret;
+       }
+       if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
+               dmxdevfilter->state = DMXDEV_STATE_DONE;
+       spin_unlock(&dmxdevfilter->dev->lock);
+       wake_up(&dmxdevfilter->buffer.queue);
+       return 0;
+}
+
+static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
+                                 const u8 *buffer2, size_t buffer2_len,
+                                 struct dmx_ts_feed *feed,
+                                 enum dmx_success success)
+{
+       struct dmxdev_filter *dmxdevfilter = feed->priv;
+       struct dvb_ringbuffer *buffer;
+       int ret;
+
+       spin_lock(&dmxdevfilter->dev->lock);
+       if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
+               spin_unlock(&dmxdevfilter->dev->lock);
+               return 0;
+       }
+
+       if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
+           || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
+               buffer = &dmxdevfilter->buffer;
+       else
+               buffer = &dmxdevfilter->dev->dvr_buffer;
+       if (buffer->error) {
+               spin_unlock(&dmxdevfilter->dev->lock);
+               wake_up(&buffer->queue);
+               return 0;
+       }
+       ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
+       if (ret == buffer1_len)
+               ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
+       if (ret < 0) {
+               dvb_ringbuffer_flush(buffer);
+               buffer->error = ret;
+       }
+       spin_unlock(&dmxdevfilter->dev->lock);
+       wake_up(&buffer->queue);
+       return 0;
+}
+
+/* stop feed but only mark the specified filter as stopped (state set) */
+static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
+{
+       struct dmxdev_feed *feed;
+
+       dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
+
+       switch (dmxdevfilter->type) {
+       case DMXDEV_TYPE_SEC:
+               del_timer(&dmxdevfilter->timer);
+               dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec);
+               break;
+       case DMXDEV_TYPE_PES:
+               list_for_each_entry(feed, &dmxdevfilter->feed.ts, next)
+                       feed->ts->stop_filtering(feed->ts);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+
+/* start feed associated with the specified filter */
+static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter)
+{
+       struct dmxdev_feed *feed;
+       int ret;
+
+       dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
+
+       switch (filter->type) {
+       case DMXDEV_TYPE_SEC:
+               return filter->feed.sec->start_filtering(filter->feed.sec);
+       case DMXDEV_TYPE_PES:
+               list_for_each_entry(feed, &filter->feed.ts, next) {
+                       ret = feed->ts->start_filtering(feed->ts);
+                       if (ret < 0) {
+                               dvb_dmxdev_feed_stop(filter);
+                               return ret;
+                       }
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* restart section feed if it has filters left associated with it,
+   otherwise release the feed */
+static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter)
+{
+       int i;
+       struct dmxdev *dmxdev = filter->dev;
+       u16 pid = filter->params.sec.pid;
+
+       for (i = 0; i < dmxdev->filternum; i++)
+               if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
+                   dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
+                   dmxdev->filter[i].params.sec.pid == pid) {
+                       dvb_dmxdev_feed_start(&dmxdev->filter[i]);
+                       return 0;
+               }
+
+       filter->dev->demux->release_section_feed(dmxdev->demux,
+                                                filter->feed.sec);
+
+       return 0;
+}
+
+static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
+{
+       struct dmxdev_feed *feed;
+       struct dmx_demux *demux;
+
+       if (dmxdevfilter->state < DMXDEV_STATE_GO)
+               return 0;
+
+       switch (dmxdevfilter->type) {
+       case DMXDEV_TYPE_SEC:
+               if (!dmxdevfilter->feed.sec)
+                       break;
+               dvb_dmxdev_feed_stop(dmxdevfilter);
+               if (dmxdevfilter->filter.sec)
+                       dmxdevfilter->feed.sec->
+                           release_filter(dmxdevfilter->feed.sec,
+                                          dmxdevfilter->filter.sec);
+               dvb_dmxdev_feed_restart(dmxdevfilter);
+               dmxdevfilter->feed.sec = NULL;
+               break;
+       case DMXDEV_TYPE_PES:
+               dvb_dmxdev_feed_stop(dmxdevfilter);
+               demux = dmxdevfilter->dev->demux;
+               list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
+                       demux->release_ts_feed(demux, feed->ts);
+                       feed->ts = NULL;
+               }
+               break;
+       default:
+               if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED)
+                       return 0;
+               return -EINVAL;
+       }
+
+       dvb_ringbuffer_flush(&dmxdevfilter->buffer);
+       return 0;
+}
+
+static void dvb_dmxdev_delete_pids(struct dmxdev_filter *dmxdevfilter)
+{
+       struct dmxdev_feed *feed, *tmp;
+
+       /* delete all PIDs */
+       list_for_each_entry_safe(feed, tmp, &dmxdevfilter->feed.ts, next) {
+               list_del(&feed->next);
+               kfree(feed);
+       }
+
+       BUG_ON(!list_empty(&dmxdevfilter->feed.ts));
+}
+
+static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter)
+{
+       if (dmxdevfilter->state < DMXDEV_STATE_SET)
+               return 0;
+
+       if (dmxdevfilter->type == DMXDEV_TYPE_PES)
+               dvb_dmxdev_delete_pids(dmxdevfilter);
+
+       dmxdevfilter->type = DMXDEV_TYPE_NONE;
+       dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
+       return 0;
+}
+
+static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
+                                struct dmxdev_filter *filter,
+                                struct dmxdev_feed *feed)
+{
+       struct timespec timeout = { 0 };
+       struct dmx_pes_filter_params *para = &filter->params.pes;
+       dmx_output_t otype;
+       int ret;
+       int ts_type;
+       dmx_pes_type_t ts_pes;
+       struct dmx_ts_feed *tsfeed;
+
+       feed->ts = NULL;
+       otype = para->output;
+
+       ts_pes = para->pes_type;
+
+       if (ts_pes < DMX_PES_OTHER)
+               ts_type = TS_DECODER;
+       else
+               ts_type = 0;
+
+       if (otype == DMX_OUT_TS_TAP)
+               ts_type |= TS_PACKET;
+       else if (otype == DMX_OUT_TSDEMUX_TAP)
+               ts_type |= TS_PACKET | TS_DEMUX;
+       else if (otype == DMX_OUT_TAP)
+               ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY;
+
+       ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, &feed->ts,
+                                             dvb_dmxdev_ts_callback);
+       if (ret < 0)
+               return ret;
+
+       tsfeed = feed->ts;
+       tsfeed->priv = filter;
+
+       ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout);
+       if (ret < 0) {
+               dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
+               return ret;
+       }
+
+       ret = tsfeed->start_filtering(tsfeed);
+       if (ret < 0) {
+               dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
+{
+       struct dmxdev *dmxdev = filter->dev;
+       struct dmxdev_feed *feed;
+       void *mem;
+       int ret, i;
+
+       if (filter->state < DMXDEV_STATE_SET)
+               return -EINVAL;
+
+       if (filter->state >= DMXDEV_STATE_GO)
+               dvb_dmxdev_filter_stop(filter);
+
+       if (!filter->buffer.data) {
+               mem = vmalloc(filter->buffer.size);
+               if (!mem)
+                       return -ENOMEM;
+               spin_lock_irq(&filter->dev->lock);
+               filter->buffer.data = mem;
+               spin_unlock_irq(&filter->dev->lock);
+       }
+
+       dvb_ringbuffer_flush(&filter->buffer);
+
+       switch (filter->type) {
+       case DMXDEV_TYPE_SEC:
+       {
+               struct dmx_sct_filter_params *para = &filter->params.sec;
+               struct dmx_section_filter **secfilter = &filter->filter.sec;
+               struct dmx_section_feed **secfeed = &filter->feed.sec;
+
+               *secfilter = NULL;
+               *secfeed = NULL;
+
+
+               /* find active filter/feed with same PID */
+               for (i = 0; i < dmxdev->filternum; i++) {
+                       if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
+                           dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
+                           dmxdev->filter[i].params.sec.pid == para->pid) {
+                               *secfeed = dmxdev->filter[i].feed.sec;
+                               break;
+                       }
+               }
+
+               /* if no feed found, try to allocate new one */
+               if (!*secfeed) {
+                       ret = dmxdev->demux->allocate_section_feed(dmxdev->demux,
+                                                                  secfeed,
+                                                                  dvb_dmxdev_section_callback);
+                       if (ret < 0) {
+                               printk("DVB (%s): could not alloc feed\n",
+                                      __func__);
+                               return ret;
+                       }
+
+                       ret = (*secfeed)->set(*secfeed, para->pid, 32768,
+                                             (para->flags & DMX_CHECK_CRC) ? 1 : 0);
+                       if (ret < 0) {
+                               printk("DVB (%s): could not set feed\n",
+                                      __func__);
+                               dvb_dmxdev_feed_restart(filter);
+                               return ret;
+                       }
+               } else {
+                       dvb_dmxdev_feed_stop(filter);
+               }
+
+               ret = (*secfeed)->allocate_filter(*secfeed, secfilter);
+               if (ret < 0) {
+                       dvb_dmxdev_feed_restart(filter);
+                       filter->feed.sec->start_filtering(*secfeed);
+                       dprintk("could not get filter\n");
+                       return ret;
+               }
+
+               (*secfilter)->priv = filter;
+
+               memcpy(&((*secfilter)->filter_value[3]),
+                      &(para->filter.filter[1]), DMX_FILTER_SIZE - 1);
+               memcpy(&(*secfilter)->filter_mask[3],
+                      &para->filter.mask[1], DMX_FILTER_SIZE - 1);
+               memcpy(&(*secfilter)->filter_mode[3],
+                      &para->filter.mode[1], DMX_FILTER_SIZE - 1);
+
+               (*secfilter)->filter_value[0] = para->filter.filter[0];
+               (*secfilter)->filter_mask[0] = para->filter.mask[0];
+               (*secfilter)->filter_mode[0] = para->filter.mode[0];
+               (*secfilter)->filter_mask[1] = 0;
+               (*secfilter)->filter_mask[2] = 0;
+
+               filter->todo = 0;
+
+               ret = filter->feed.sec->start_filtering(filter->feed.sec);
+               if (ret < 0)
+                       return ret;
+
+               dvb_dmxdev_filter_timer(filter);
+               break;
+       }
+       case DMXDEV_TYPE_PES:
+               list_for_each_entry(feed, &filter->feed.ts, next) {
+                       ret = dvb_dmxdev_start_feed(dmxdev, filter, feed);
+                       if (ret < 0) {
+                               dvb_dmxdev_filter_stop(filter);
+                               return ret;
+                       }
+               }
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
+       return 0;
+}
+
+static int dvb_demux_open(struct inode *inode, struct file *file)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dmxdev *dmxdev = dvbdev->priv;
+       int i;
+       struct dmxdev_filter *dmxdevfilter;
+
+       if (!dmxdev->filter)
+               return -EINVAL;
+
+       if (mutex_lock_interruptible(&dmxdev->mutex))
+               return -ERESTARTSYS;
+
+       for (i = 0; i < dmxdev->filternum; i++)
+               if (dmxdev->filter[i].state == DMXDEV_STATE_FREE)
+                       break;
+
+       if (i == dmxdev->filternum) {
+               mutex_unlock(&dmxdev->mutex);
+               return -EMFILE;
+       }
+
+       dmxdevfilter = &dmxdev->filter[i];
+       mutex_init(&dmxdevfilter->mutex);
+       file->private_data = dmxdevfilter;
+
+       dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
+       dmxdevfilter->type = DMXDEV_TYPE_NONE;
+       dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
+       init_timer(&dmxdevfilter->timer);
+
+       dvbdev->users++;
+
+       mutex_unlock(&dmxdev->mutex);
+       return 0;
+}
+
+static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
+                                 struct dmxdev_filter *dmxdevfilter)
+{
+       mutex_lock(&dmxdev->mutex);
+       mutex_lock(&dmxdevfilter->mutex);
+
+       dvb_dmxdev_filter_stop(dmxdevfilter);
+       dvb_dmxdev_filter_reset(dmxdevfilter);
+
+       if (dmxdevfilter->buffer.data) {
+               void *mem = dmxdevfilter->buffer.data;
+
+               spin_lock_irq(&dmxdev->lock);
+               dmxdevfilter->buffer.data = NULL;
+               spin_unlock_irq(&dmxdev->lock);
+               vfree(mem);
+       }
+
+       dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE);
+       wake_up(&dmxdevfilter->buffer.queue);
+       mutex_unlock(&dmxdevfilter->mutex);
+       mutex_unlock(&dmxdev->mutex);
+       return 0;
+}
+
+static inline void invert_mode(dmx_filter_t *filter)
+{
+       int i;
+
+       for (i = 0; i < DMX_FILTER_SIZE; i++)
+               filter->mode[i] ^= 0xff;
+}
+
+static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev,
+                             struct dmxdev_filter *filter, u16 pid)
+{
+       struct dmxdev_feed *feed;
+
+       if ((filter->type != DMXDEV_TYPE_PES) ||
+           (filter->state < DMXDEV_STATE_SET))
+               return -EINVAL;
+
+       /* only TS packet filters may have multiple PIDs */
+       if ((filter->params.pes.output != DMX_OUT_TSDEMUX_TAP) &&
+           (!list_empty(&filter->feed.ts)))
+               return -EINVAL;
+
+       feed = kzalloc(sizeof(struct dmxdev_feed), GFP_KERNEL);
+       if (feed == NULL)
+               return -ENOMEM;
+
+       feed->pid = pid;
+       list_add(&feed->next, &filter->feed.ts);
+
+       if (filter->state >= DMXDEV_STATE_GO)
+               return dvb_dmxdev_start_feed(dmxdev, filter, feed);
+
+       return 0;
+}
+
+static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev,
+                                 struct dmxdev_filter *filter, u16 pid)
+{
+       struct dmxdev_feed *feed, *tmp;
+
+       if ((filter->type != DMXDEV_TYPE_PES) ||
+           (filter->state < DMXDEV_STATE_SET))
+               return -EINVAL;
+
+       list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) {
+               if ((feed->pid == pid) && (feed->ts != NULL)) {
+                       feed->ts->stop_filtering(feed->ts);
+                       filter->dev->demux->release_ts_feed(filter->dev->demux,
+                                                           feed->ts);
+                       list_del(&feed->next);
+                       kfree(feed);
+               }
+       }
+
+       return 0;
+}
+
+static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
+                                struct dmxdev_filter *dmxdevfilter,
+                                struct dmx_sct_filter_params *params)
+{
+       dprintk("function : %s\n", __func__);
+
+       dvb_dmxdev_filter_stop(dmxdevfilter);
+
+       dmxdevfilter->type = DMXDEV_TYPE_SEC;
+       memcpy(&dmxdevfilter->params.sec,
+              params, sizeof(struct dmx_sct_filter_params));
+       invert_mode(&dmxdevfilter->params.sec.filter);
+       dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
+
+       if (params->flags & DMX_IMMEDIATE_START)
+               return dvb_dmxdev_filter_start(dmxdevfilter);
+
+       return 0;
+}
+
+static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
+                                    struct dmxdev_filter *dmxdevfilter,
+                                    struct dmx_pes_filter_params *params)
+{
+       int ret;
+
+       dvb_dmxdev_filter_stop(dmxdevfilter);
+       dvb_dmxdev_filter_reset(dmxdevfilter);
+
+       if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0)
+               return -EINVAL;
+
+       dmxdevfilter->type = DMXDEV_TYPE_PES;
+       memcpy(&dmxdevfilter->params, params,
+              sizeof(struct dmx_pes_filter_params));
+       INIT_LIST_HEAD(&dmxdevfilter->feed.ts);
+
+       dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
+
+       ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter,
+                                dmxdevfilter->params.pes.pid);
+       if (ret < 0)
+               return ret;
+
+       if (params->flags & DMX_IMMEDIATE_START)
+               return dvb_dmxdev_filter_start(dmxdevfilter);
+
+       return 0;
+}
+
+static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil,
+                                  struct file *file, char __user *buf,
+                                  size_t count, loff_t *ppos)
+{
+       int result, hcount;
+       int done = 0;
+
+       if (dfil->todo <= 0) {
+               hcount = 3 + dfil->todo;
+               if (hcount > count)
+                       hcount = count;
+               result = dvb_dmxdev_buffer_read(&dfil->buffer,
+                                               file->f_flags & O_NONBLOCK,
+                                               buf, hcount, ppos);
+               if (result < 0) {
+                       dfil->todo = 0;
+                       return result;
+               }
+               if (copy_from_user(dfil->secheader - dfil->todo, buf, result))
+                       return -EFAULT;
+               buf += result;
+               done = result;
+               count -= result;
+               dfil->todo -= result;
+               if (dfil->todo > -3)
+                       return done;
+               dfil->todo = ((dfil->secheader[1] << 8) | dfil->secheader[2]) & 0xfff;
+               if (!count)
+                       return done;
+       }
+       if (count > dfil->todo)
+               count = dfil->todo;
+       result = dvb_dmxdev_buffer_read(&dfil->buffer,
+                                       file->f_flags & O_NONBLOCK,
+                                       buf, count, ppos);
+       if (result < 0)
+               return result;
+       dfil->todo -= result;
+       return (result + done);
+}
+
+static ssize_t
+dvb_demux_read(struct file *file, char __user *buf, size_t count,
+              loff_t *ppos)
+{
+       struct dmxdev_filter *dmxdevfilter = file->private_data;
+       int ret;
+
+       if (mutex_lock_interruptible(&dmxdevfilter->mutex))
+               return -ERESTARTSYS;
+
+       if (dmxdevfilter->type == DMXDEV_TYPE_SEC)
+               ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
+       else
+               ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
+                                            file->f_flags & O_NONBLOCK,
+                                            buf, count, ppos);
+
+       mutex_unlock(&dmxdevfilter->mutex);
+       return ret;
+}
+
+static int dvb_demux_do_ioctl(struct file *file,
+                             unsigned int cmd, void *parg)
+{
+       struct dmxdev_filter *dmxdevfilter = file->private_data;
+       struct dmxdev *dmxdev = dmxdevfilter->dev;
+       unsigned long arg = (unsigned long)parg;
+       int ret = 0;
+
+       if (mutex_lock_interruptible(&dmxdev->mutex))
+               return -ERESTARTSYS;
+
+       switch (cmd) {
+       case DMX_START:
+               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -ERESTARTSYS;
+               }
+               if (dmxdevfilter->state < DMXDEV_STATE_SET)
+                       ret = -EINVAL;
+               else
+                       ret = dvb_dmxdev_filter_start(dmxdevfilter);
+               mutex_unlock(&dmxdevfilter->mutex);
+               break;
+
+       case DMX_STOP:
+               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -ERESTARTSYS;
+               }
+               ret = dvb_dmxdev_filter_stop(dmxdevfilter);
+               mutex_unlock(&dmxdevfilter->mutex);
+               break;
+
+       case DMX_SET_FILTER:
+               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -ERESTARTSYS;
+               }
+               ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg);
+               mutex_unlock(&dmxdevfilter->mutex);
+               break;
+
+       case DMX_SET_PES_FILTER:
+               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -ERESTARTSYS;
+               }
+               ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg);
+               mutex_unlock(&dmxdevfilter->mutex);
+               break;
+
+       case DMX_SET_BUFFER_SIZE:
+               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+                       mutex_unlock(&dmxdev->mutex);
+                       return -ERESTARTSYS;
+               }
+               ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg);
+               mutex_unlock(&dmxdevfilter->mutex);
+               break;
+
+       case DMX_GET_PES_PIDS:
+               if (!dmxdev->demux->get_pes_pids) {
+                       ret = -EINVAL;
+                       break;
+               }
+               dmxdev->demux->get_pes_pids(dmxdev->demux, parg);
+               break;
+
+       case DMX_GET_CAPS:
+               if (!dmxdev->demux->get_caps) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = dmxdev->demux->get_caps(dmxdev->demux, parg);
+               break;
+
+       case DMX_SET_SOURCE:
+               if (!dmxdev->demux->set_source) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = dmxdev->demux->set_source(dmxdev->demux, parg);
+               break;
+
+       case DMX_GET_STC:
+               if (!dmxdev->demux->get_stc) {
+                       ret = -EINVAL;
+                       break;
+               }
+               ret = dmxdev->demux->get_stc(dmxdev->demux,
+                                            ((struct dmx_stc *)parg)->num,
+                                            &((struct dmx_stc *)parg)->stc,
+                                            &((struct dmx_stc *)parg)->base);
+               break;
+
+       case DMX_ADD_PID:
+               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+               ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
+               mutex_unlock(&dmxdevfilter->mutex);
+               break;
+
+       case DMX_REMOVE_PID:
+               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+               ret = dvb_dmxdev_remove_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
+               mutex_unlock(&dmxdevfilter->mutex);
+               break;
+
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       mutex_unlock(&dmxdev->mutex);
+       return ret;
+}
+
+static long dvb_demux_ioctl(struct file *file, unsigned int cmd,
+                           unsigned long arg)
+{
+       return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl);
+}
+
+static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
+{
+       struct dmxdev_filter *dmxdevfilter = file->private_data;
+       unsigned int mask = 0;
+
+       if (!dmxdevfilter)
+               return -EINVAL;
+
+       poll_wait(file, &dmxdevfilter->buffer.queue, wait);
+
+       if (dmxdevfilter->state != DMXDEV_STATE_GO &&
+           dmxdevfilter->state != DMXDEV_STATE_DONE &&
+           dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT)
+               return 0;
+
+       if (dmxdevfilter->buffer.error)
+               mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
+
+       if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
+               mask |= (POLLIN | POLLRDNORM | POLLPRI);
+
+       return mask;
+}
+
+static int dvb_demux_release(struct inode *inode, struct file *file)
+{
+       struct dmxdev_filter *dmxdevfilter = file->private_data;
+       struct dmxdev *dmxdev = dmxdevfilter->dev;
+
+       int ret;
+
+       ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
+
+       mutex_lock(&dmxdev->mutex);
+       dmxdev->dvbdev->users--;
+       if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) {
+               fops_put(file->f_op);
+               file->f_op = NULL;
+               mutex_unlock(&dmxdev->mutex);
+               wake_up(&dmxdev->dvbdev->wait_queue);
+       } else
+               mutex_unlock(&dmxdev->mutex);
+
+       return ret;
+}
+
+static const struct file_operations dvb_demux_fops = {
+       .owner = THIS_MODULE,
+       .read = dvb_demux_read,
+       .unlocked_ioctl = dvb_demux_ioctl,
+       .open = dvb_demux_open,
+       .release = dvb_demux_release,
+       .poll = dvb_demux_poll,
+       .llseek = default_llseek,
+};
+
+static struct dvb_device dvbdev_demux = {
+       .priv = NULL,
+       .users = 1,
+       .writers = 1,
+       .fops = &dvb_demux_fops
+};
+
+static int dvb_dvr_do_ioctl(struct file *file,
+                           unsigned int cmd, void *parg)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dmxdev *dmxdev = dvbdev->priv;
+       unsigned long arg = (unsigned long)parg;
+       int ret;
+
+       if (mutex_lock_interruptible(&dmxdev->mutex))
+               return -ERESTARTSYS;
+
+       switch (cmd) {
+       case DMX_SET_BUFFER_SIZE:
+               ret = dvb_dvr_set_buffer_size(dmxdev, arg);
+               break;
+
+       default:
+               ret = -EINVAL;
+               break;
+       }
+       mutex_unlock(&dmxdev->mutex);
+       return ret;
+}
+
+static long dvb_dvr_ioctl(struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl);
+}
+
+static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dmxdev *dmxdev = dvbdev->priv;
+       unsigned int mask = 0;
+
+       dprintk("function : %s\n", __func__);
+
+       poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
+
+       if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+               if (dmxdev->dvr_buffer.error)
+                       mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
+
+               if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
+                       mask |= (POLLIN | POLLRDNORM | POLLPRI);
+       } else
+               mask |= (POLLOUT | POLLWRNORM | POLLPRI);
+
+       return mask;
+}
+
+static const struct file_operations dvb_dvr_fops = {
+       .owner = THIS_MODULE,
+       .read = dvb_dvr_read,
+       .write = dvb_dvr_write,
+       .unlocked_ioctl = dvb_dvr_ioctl,
+       .open = dvb_dvr_open,
+       .release = dvb_dvr_release,
+       .poll = dvb_dvr_poll,
+       .llseek = default_llseek,
+};
+
+static struct dvb_device dvbdev_dvr = {
+       .priv = NULL,
+       .readers = 1,
+       .users = 1,
+       .fops = &dvb_dvr_fops
+};
+
+int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
+{
+       int i;
+
+       if (dmxdev->demux->open(dmxdev->demux) < 0)
+               return -EUSERS;
+
+       dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter));
+       if (!dmxdev->filter)
+               return -ENOMEM;
+
+       mutex_init(&dmxdev->mutex);
+       spin_lock_init(&dmxdev->lock);
+       for (i = 0; i < dmxdev->filternum; i++) {
+               dmxdev->filter[i].dev = dmxdev;
+               dmxdev->filter[i].buffer.data = NULL;
+               dvb_dmxdev_filter_state_set(&dmxdev->filter[i],
+                                           DMXDEV_STATE_FREE);
+       }
+
+       dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
+                           DVB_DEVICE_DEMUX);
+       dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
+                           dmxdev, DVB_DEVICE_DVR);
+
+       dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
+
+       return 0;
+}
+
+EXPORT_SYMBOL(dvb_dmxdev_init);
+
+void dvb_dmxdev_release(struct dmxdev *dmxdev)
+{
+       dmxdev->exit=1;
+       if (dmxdev->dvbdev->users > 1) {
+               wait_event(dmxdev->dvbdev->wait_queue,
+                               dmxdev->dvbdev->users==1);
+       }
+       if (dmxdev->dvr_dvbdev->users > 1) {
+               wait_event(dmxdev->dvr_dvbdev->wait_queue,
+                               dmxdev->dvr_dvbdev->users==1);
+       }
+
+       dvb_unregister_device(dmxdev->dvbdev);
+       dvb_unregister_device(dmxdev->dvr_dvbdev);
+
+       vfree(dmxdev->filter);
+       dmxdev->filter = NULL;
+       dmxdev->demux->close(dmxdev->demux);
+}
+
+EXPORT_SYMBOL(dvb_dmxdev_release);
diff --git a/drivers/media/dvb-core/dmxdev.h b/drivers/media/dvb-core/dmxdev.h
new file mode 100644 (file)
index 0000000..02ebe28
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * dmxdev.h
+ *
+ * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
+ *                    for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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 _DMXDEV_H_
+#define _DMXDEV_H_
+
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/timer.h>
+#include <linux/wait.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <linux/dvb/dmx.h>
+
+#include "dvbdev.h"
+#include "demux.h"
+#include "dvb_ringbuffer.h"
+
+enum dmxdev_type {
+       DMXDEV_TYPE_NONE,
+       DMXDEV_TYPE_SEC,
+       DMXDEV_TYPE_PES,
+};
+
+enum dmxdev_state {
+       DMXDEV_STATE_FREE,
+       DMXDEV_STATE_ALLOCATED,
+       DMXDEV_STATE_SET,
+       DMXDEV_STATE_GO,
+       DMXDEV_STATE_DONE,
+       DMXDEV_STATE_TIMEDOUT
+};
+
+struct dmxdev_feed {
+       u16 pid;
+       struct dmx_ts_feed *ts;
+       struct list_head next;
+};
+
+struct dmxdev_filter {
+       union {
+               struct dmx_section_filter *sec;
+       } filter;
+
+       union {
+               /* list of TS and PES feeds (struct dmxdev_feed) */
+               struct list_head ts;
+               struct dmx_section_feed *sec;
+       } feed;
+
+       union {
+               struct dmx_sct_filter_params sec;
+               struct dmx_pes_filter_params pes;
+       } params;
+
+       enum dmxdev_type type;
+       enum dmxdev_state state;
+       struct dmxdev *dev;
+       struct dvb_ringbuffer buffer;
+
+       struct mutex mutex;
+
+       /* only for sections */
+       struct timer_list timer;
+       int todo;
+       u8 secheader[3];
+};
+
+
+struct dmxdev {
+       struct dvb_device *dvbdev;
+       struct dvb_device *dvr_dvbdev;
+
+       struct dmxdev_filter *filter;
+       struct dmx_demux *demux;
+
+       int filternum;
+       int capabilities;
+
+       unsigned int exit:1;
+#define DMXDEV_CAP_DUPLEX 1
+       struct dmx_frontend *dvr_orig_fe;
+
+       struct dvb_ringbuffer dvr_buffer;
+#define DVR_BUFFER_SIZE (10*188*1024)
+
+       struct mutex mutex;
+       spinlock_t lock;
+};
+
+
+int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *);
+void dvb_dmxdev_release(struct dmxdev *dmxdev);
+
+#endif /* _DMXDEV_H_ */
diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
new file mode 100644 (file)
index 0000000..26c4481
--- /dev/null
@@ -0,0 +1,361 @@
+/* dvb-usb-ids.h is part of the DVB USB library.
+ *
+ * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) see
+ * dvb-usb-init.c for copyright information.
+ *
+ * a header file containing define's for the USB device supported by the
+ * various drivers.
+ */
+#ifndef _DVB_USB_IDS_H_
+#define _DVB_USB_IDS_H_
+
+/* Vendor IDs */
+#define USB_VID_ADSTECH                                0x06e1
+#define USB_VID_AFATECH                                0x15a4
+#define USB_VID_ALCOR_MICRO                    0x058f
+#define USB_VID_ALINK                          0x05e3
+#define USB_VID_AMT                            0x1c73
+#define USB_VID_ANCHOR                         0x0547
+#define USB_VID_ANSONIC                                0x10b9
+#define USB_VID_ANUBIS_ELECTRONIC              0x10fd
+#define USB_VID_ASUS                           0x0b05
+#define USB_VID_AVERMEDIA                      0x07ca
+#define USB_VID_COMPRO                         0x185b
+#define USB_VID_COMPRO_UNK                     0x145f
+#define USB_VID_CONEXANT                       0x0572
+#define USB_VID_CYPRESS                                0x04b4
+#define USB_VID_DIBCOM                         0x10b8
+#define USB_VID_DPOSH                          0x1498
+#define USB_VID_DVICO                          0x0fe9
+#define USB_VID_E3C                            0x18b4
+#define USB_VID_ELGATO                         0x0fd9
+#define USB_VID_EMPIA                          0xeb1a
+#define USB_VID_GENPIX                         0x09c0
+#define USB_VID_GRANDTEC                       0x5032
+#define USB_VID_GTEK                           0x1f4d
+#define USB_VID_HANFTEK                                0x15f4
+#define USB_VID_HAUPPAUGE                      0x2040
+#define USB_VID_HYPER_PALTEK                   0x1025
+#define USB_VID_INTEL                          0x8086
+#define USB_VID_ITETECH                                0x048d
+#define USB_VID_KWORLD                         0xeb2a
+#define USB_VID_KWORLD_2                       0x1b80
+#define USB_VID_KYE                            0x0458
+#define USB_VID_LEADTEK                                0x0413
+#define USB_VID_LITEON                         0x04ca
+#define USB_VID_MEDION                         0x1660
+#define USB_VID_MIGLIA                         0x18f3
+#define USB_VID_MSI                            0x0db0
+#define USB_VID_MSI_2                          0x1462
+#define USB_VID_OPERA1                         0x695c
+#define USB_VID_PINNACLE                       0x2304
+#define USB_VID_PCTV                           0x2013
+#define USB_VID_PIXELVIEW                      0x1554
+#define USB_VID_REALTEK                                0x0bda
+#define USB_VID_TECHNOTREND                    0x0b48
+#define USB_VID_TERRATEC                       0x0ccd
+#define USB_VID_TELESTAR                       0x10b9
+#define USB_VID_VISIONPLUS                     0x13d3
+#define USB_VID_SONY                           0x1415
+#define USB_VID_TWINHAN                                0x1822
+#define USB_VID_ULTIMA_ELECTRONIC              0x05d8
+#define USB_VID_UNIWILL                                0x1584
+#define USB_VID_WIDEVIEW                       0x14aa
+#define USB_VID_GIGABYTE                       0x1044
+#define USB_VID_YUAN                           0x1164
+#define USB_VID_XTENSIONS                      0x1ae7
+#define USB_VID_HUMAX_COEX                     0x10b9
+#define USB_VID_774                            0x7a69
+#define USB_VID_EVOLUTEPC                      0x1e59
+#define USB_VID_AZUREWAVE                      0x13d3
+#define USB_VID_TECHNISAT                      0x14f7
+
+/* Product IDs */
+#define USB_PID_ADSTECH_USB2_COLD                      0xa333
+#define USB_PID_ADSTECH_USB2_WARM                      0xa334
+#define USB_PID_AFATECH_AF9005                         0x9020
+#define USB_PID_AFATECH_AF9015_9015                    0x9015
+#define USB_PID_AFATECH_AF9015_9016                    0x9016
+#define USB_PID_AFATECH_AF9035_1000                    0x1000
+#define USB_PID_AFATECH_AF9035_1001                    0x1001
+#define USB_PID_AFATECH_AF9035_1002                    0x1002
+#define USB_PID_AFATECH_AF9035_1003                    0x1003
+#define USB_PID_AFATECH_AF9035_9035                    0x9035
+#define USB_PID_TREKSTOR_DVBT                          0x901b
+#define USB_VID_ALINK_DTU                              0xf170
+#define USB_PID_ANSONIC_DVBT_USB                       0x6000
+#define USB_PID_ANYSEE                                 0x861f
+#define USB_PID_AZUREWAVE_AD_TU700                     0x3237
+#define USB_PID_AZUREWAVE_6007                         0x0ccd
+#define USB_PID_AVERMEDIA_DVBT_USB_COLD                        0x0001
+#define USB_PID_AVERMEDIA_DVBT_USB_WARM                        0x0002
+#define USB_PID_AVERMEDIA_DVBT_USB2_COLD               0xa800
+#define USB_PID_AVERMEDIA_DVBT_USB2_WARM               0xa801
+#define USB_PID_COMPRO_DVBU2000_COLD                   0xd000
+#define USB_PID_COMPRO_DVBU2000_WARM                   0xd001
+#define USB_PID_COMPRO_DVBU2000_UNK_COLD               0x010c
+#define USB_PID_COMPRO_DVBU2000_UNK_WARM               0x010d
+#define USB_PID_COMPRO_VIDEOMATE_U500                  0x1e78
+#define USB_PID_COMPRO_VIDEOMATE_U500_PC               0x1e80
+#define USB_PID_CONCEPTRONIC_CTVDIGRCU                 0xe397
+#define USB_PID_CONEXANT_D680_DMB                      0x86d6
+#define USB_PID_CREATIX_CTX1921                                0x1921
+#define USB_PID_DELOCK_USB2_DVBT                       0xb803
+#define USB_PID_DIBCOM_HOOK_DEFAULT                    0x0064
+#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM             0x0065
+#define USB_PID_DIBCOM_MOD3000_COLD                    0x0bb8
+#define USB_PID_DIBCOM_MOD3000_WARM                    0x0bb9
+#define USB_PID_DIBCOM_MOD3001_COLD                    0x0bc6
+#define USB_PID_DIBCOM_MOD3001_WARM                    0x0bc7
+#define USB_PID_DIBCOM_STK7700P                                0x1e14
+#define USB_PID_DIBCOM_STK7700P_PC                     0x1e78
+#define USB_PID_DIBCOM_STK7700D                                0x1ef0
+#define USB_PID_DIBCOM_STK7700_U7000                   0x7001
+#define USB_PID_DIBCOM_STK7070P                                0x1ebc
+#define USB_PID_DIBCOM_STK7070PD                       0x1ebe
+#define USB_PID_DIBCOM_STK807XP                                0x1f90
+#define USB_PID_DIBCOM_STK807XPVR                      0x1f98
+#define USB_PID_DIBCOM_STK8096GP                        0x1fa0
+#define USB_PID_DIBCOM_NIM8096MD                        0x1fa8
+#define USB_PID_DIBCOM_TFE8096P                                0x1f9C
+#define USB_PID_DIBCOM_ANCHOR_2135_COLD                        0x2131
+#define USB_PID_DIBCOM_STK7770P                                0x1e80
+#define USB_PID_DIBCOM_NIM7090                         0x1bb2
+#define USB_PID_DIBCOM_TFE7090PVR                      0x1bb4
+#define USB_PID_DIBCOM_TFE7090E                                0x1bb7
+#define USB_PID_DIBCOM_TFE7790E                                0x1e6e
+#define USB_PID_DIBCOM_NIM9090M                                0x2383
+#define USB_PID_DIBCOM_NIM9090MD                       0x2384
+#define USB_PID_DPOSH_M9206_COLD                       0x9206
+#define USB_PID_DPOSH_M9206_WARM                       0xa090
+#define USB_PID_E3C_EC168                              0x1689
+#define USB_PID_E3C_EC168_2                            0xfffa
+#define USB_PID_E3C_EC168_3                            0xfffb
+#define USB_PID_E3C_EC168_4                            0x1001
+#define USB_PID_E3C_EC168_5                            0x1002
+#define USB_PID_FREECOM_DVBT                           0x0160
+#define USB_PID_FREECOM_DVBT_2                         0x0161
+#define USB_PID_UNIWILL_STK7700P                       0x6003
+#define USB_PID_GENIUS_TVGO_DVB_T03                    0x4012
+#define USB_PID_GRANDTEC_DVBT_USB_COLD                 0x0fa0
+#define USB_PID_GRANDTEC_DVBT_USB_WARM                 0x0fa1
+#define USB_PID_INTEL_CE9500                           0x9500
+#define USB_PID_ITETECH_IT9135                         0x9135
+#define USB_PID_ITETECH_IT9135_9005                    0x9005
+#define USB_PID_ITETECH_IT9135_9006                    0x9006
+#define USB_PID_KWORLD_399U                            0xe399
+#define USB_PID_KWORLD_399U_2                          0xe400
+#define USB_PID_KWORLD_395U                            0xe396
+#define USB_PID_KWORLD_395U_2                          0xe39b
+#define USB_PID_KWORLD_395U_3                          0xe395
+#define USB_PID_KWORLD_395U_4                          0xe39a
+#define USB_PID_KWORLD_MC810                           0xc810
+#define USB_PID_KWORLD_PC160_2T                                0xc160
+#define USB_PID_KWORLD_PC160_T                         0xc161
+#define USB_PID_KWORLD_UB383_T                         0xe383
+#define USB_PID_KWORLD_UB499_2T_T09                    0xe409
+#define USB_PID_KWORLD_VSTREAM_COLD                    0x17de
+#define USB_PID_KWORLD_VSTREAM_WARM                    0x17df
+#define USB_PID_TERRATEC_CINERGY_T_USB_XE              0x0055
+#define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2         0x0069
+#define USB_PID_TERRATEC_CINERGY_T_STICK               0x0093
+#define USB_PID_TERRATEC_CINERGY_T_STICK_RC            0x0097
+#define USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC       0x0099
+#define USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1    0x00a9
+#define USB_PID_TWINHAN_VP7041_COLD                    0x3201
+#define USB_PID_TWINHAN_VP7041_WARM                    0x3202
+#define USB_PID_TWINHAN_VP7020_COLD                    0x3203
+#define USB_PID_TWINHAN_VP7020_WARM                    0x3204
+#define USB_PID_TWINHAN_VP7045_COLD                    0x3205
+#define USB_PID_TWINHAN_VP7045_WARM                    0x3206
+#define USB_PID_TWINHAN_VP7021_COLD                    0x3207
+#define USB_PID_TWINHAN_VP7021_WARM                    0x3208
+#define USB_PID_TINYTWIN                               0x3226
+#define USB_PID_TINYTWIN_2                             0xe402
+#define USB_PID_TINYTWIN_3                             0x9016
+#define USB_PID_DNTV_TINYUSB2_COLD                     0x3223
+#define USB_PID_DNTV_TINYUSB2_WARM                     0x3224
+#define USB_PID_ULTIMA_TVBOX_COLD                      0x8105
+#define USB_PID_ULTIMA_TVBOX_WARM                      0x8106
+#define USB_PID_ULTIMA_TVBOX_AN2235_COLD               0x8107
+#define USB_PID_ULTIMA_TVBOX_AN2235_WARM               0x8108
+#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD               0x2235
+#define USB_PID_ULTIMA_TVBOX_USB2_COLD                 0x8109
+#define USB_PID_ULTIMA_TVBOX_USB2_WARM                 0x810a
+#define USB_PID_ARTEC_T14_COLD                         0x810b
+#define USB_PID_ARTEC_T14_WARM                         0x810c
+#define USB_PID_ARTEC_T14BR                            0x810f
+#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD              0x8613
+#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM              0x1002
+#define USB_PID_UNK_HYPER_PALTEK_COLD                  0x005e
+#define USB_PID_UNK_HYPER_PALTEK_WARM                  0x005f
+#define USB_PID_HANFTEK_UMT_010_COLD                   0x0001
+#define USB_PID_HANFTEK_UMT_010_WARM                   0x0015
+#define USB_PID_DTT200U_COLD                           0x0201
+#define USB_PID_DTT200U_WARM                           0x0301
+#define USB_PID_WT220U_ZAP250_COLD                     0x0220
+#define USB_PID_WT220U_COLD                            0x0222
+#define USB_PID_WT220U_WARM                            0x0221
+#define USB_PID_WT220U_FC_COLD                         0x0225
+#define USB_PID_WT220U_FC_WARM                         0x0226
+#define USB_PID_WT220U_ZL0353_COLD                     0x022a
+#define USB_PID_WT220U_ZL0353_WARM                     0x022b
+#define USB_PID_WINTV_NOVA_T_USB2_COLD                 0x9300
+#define USB_PID_WINTV_NOVA_T_USB2_WARM                 0x9301
+#define USB_PID_HAUPPAUGE_NOVA_T_500                   0x9941
+#define USB_PID_HAUPPAUGE_NOVA_T_500_2                 0x9950
+#define USB_PID_HAUPPAUGE_NOVA_T_500_3                 0x8400
+#define USB_PID_HAUPPAUGE_NOVA_T_STICK                 0x7050
+#define USB_PID_HAUPPAUGE_NOVA_T_STICK_2               0x7060
+#define USB_PID_HAUPPAUGE_NOVA_T_STICK_3               0x7070
+#define USB_PID_HAUPPAUGE_MYTV_T                       0x7080
+#define USB_PID_HAUPPAUGE_NOVA_TD_STICK                        0x9580
+#define USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009          0x5200
+#define USB_PID_HAUPPAUGE_TIGER_ATSC                   0xb200
+#define USB_PID_HAUPPAUGE_TIGER_ATSC_B210              0xb210
+#define USB_PID_AVERMEDIA_EXPRESS                      0xb568
+#define USB_PID_AVERMEDIA_VOLAR                                0xa807
+#define USB_PID_AVERMEDIA_VOLAR_2                      0xb808
+#define USB_PID_AVERMEDIA_VOLAR_A868R                  0xa868
+#define USB_PID_AVERMEDIA_MCE_USB_M038                 0x1228
+#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R       0x0039
+#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_ATSC  0x1039
+#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_DVBT  0x2039
+#define USB_PID_AVERMEDIA_VOLAR_X                      0xa815
+#define USB_PID_AVERMEDIA_VOLAR_X_2                    0x8150
+#define USB_PID_AVERMEDIA_A309                         0xa309
+#define USB_PID_AVERMEDIA_A310                         0xa310
+#define USB_PID_AVERMEDIA_A850                         0x850a
+#define USB_PID_AVERMEDIA_A850T                                0x850b
+#define USB_PID_AVERMEDIA_A805                         0xa805
+#define USB_PID_AVERMEDIA_A815M                                0x815a
+#define USB_PID_AVERMEDIA_A835                         0xa835
+#define USB_PID_AVERMEDIA_B835                         0xb835
+#define USB_PID_AVERMEDIA_1867                         0x1867
+#define USB_PID_AVERMEDIA_A867                         0xa867
+#define USB_PID_AVERMEDIA_TWINSTAR                     0x0825
+#define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
+#define USB_PID_TECHNOTREND_CONNECT_CT3650             0x300d
+#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY       0x005a
+#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2     0x0081
+#define USB_PID_TERRATEC_CINERGY_HT_USB_XE             0x0058
+#define USB_PID_TERRATEC_CINERGY_HT_EXPRESS            0x0060
+#define USB_PID_TERRATEC_CINERGY_T_EXPRESS             0x0062
+#define USB_PID_TERRATEC_CINERGY_T_XXS                 0x0078
+#define USB_PID_TERRATEC_CINERGY_T_XXS_2               0x00ab
+#define USB_PID_TERRATEC_H7                            0x10b4
+#define USB_PID_TERRATEC_H7_2                          0x10a3
+#define USB_PID_TERRATEC_T3                            0x10a0
+#define USB_PID_TERRATEC_T5                            0x10a1
+#define USB_PID_NOXON_DAB_STICK                                0x00b3
+#define USB_PID_PINNACLE_EXPRESSCARD_320CX             0x022e
+#define USB_PID_PINNACLE_PCTV2000E                     0x022c
+#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH              0x0228
+#define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T     0x0229
+#define USB_PID_PINNACLE_PCTV71E                       0x022b
+#define USB_PID_PINNACLE_PCTV72E                       0x0236
+#define USB_PID_PINNACLE_PCTV73E                       0x0237
+#define USB_PID_PINNACLE_PCTV310E                      0x3211
+#define USB_PID_PINNACLE_PCTV801E                      0x023a
+#define USB_PID_PINNACLE_PCTV801E_SE                   0x023b
+#define USB_PID_PINNACLE_PCTV340E                      0x023d
+#define USB_PID_PINNACLE_PCTV340E_SE                   0x023e
+#define USB_PID_PINNACLE_PCTV73A                       0x0243
+#define USB_PID_PINNACLE_PCTV73ESE                     0x0245
+#define USB_PID_PINNACLE_PCTV74E                       0x0246
+#define USB_PID_PINNACLE_PCTV282E                      0x0248
+#define USB_PID_PIXELVIEW_SBTVD                                0x5010
+#define USB_PID_PCTV_200E                              0x020e
+#define USB_PID_PCTV_400E                              0x020f
+#define USB_PID_PCTV_450E                              0x0222
+#define USB_PID_PCTV_452E                              0x021f
+#define USB_PID_REALTEK_RTL2831U                       0x2831
+#define USB_PID_REALTEK_RTL2832U                       0x2832
+#define USB_PID_TECHNOTREND_CONNECT_S2_3600            0x3007
+#define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI         0x300a
+#define USB_PID_NEBULA_DIGITV                          0x0201
+#define USB_PID_DVICO_BLUEBIRD_LGDT                    0xd820
+#define USB_PID_DVICO_BLUEBIRD_LG064F_COLD             0xd500
+#define USB_PID_DVICO_BLUEBIRD_LG064F_WARM             0xd501
+#define USB_PID_DVICO_BLUEBIRD_LGZ201_COLD             0xdb00
+#define USB_PID_DVICO_BLUEBIRD_LGZ201_WARM             0xdb01
+#define USB_PID_DVICO_BLUEBIRD_TH7579_COLD             0xdb10
+#define USB_PID_DVICO_BLUEBIRD_TH7579_WARM             0xdb11
+#define USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD             0xdb50
+#define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM             0xdb51
+#define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD             0xdb58
+#define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM             0xdb59
+#define USB_PID_DVICO_BLUEBIRD_DUAL_4                  0xdb78
+#define USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2            0xdb98
+#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2            0xdb70
+#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM   0xdb71
+#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD                0xdb54
+#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM                0xdb55
+#define USB_PID_MEDION_MD95700                         0x0932
+#define USB_PID_MSI_MEGASKY580                         0x5580
+#define USB_PID_MSI_MEGASKY580_55801                   0x5581
+#define USB_PID_KYE_DVB_T_COLD                         0x701e
+#define USB_PID_KYE_DVB_T_WARM                         0x701f
+#define USB_PID_LITEON_DVB_T_COLD                      0xf000
+#define USB_PID_LITEON_DVB_T_WARM                      0xf001
+#define USB_PID_DIGIVOX_MINI_SL_COLD                   0xe360
+#define USB_PID_DIGIVOX_MINI_SL_WARM                   0xe361
+#define USB_PID_GRANDTEC_DVBT_USB2_COLD                        0x0bc6
+#define USB_PID_GRANDTEC_DVBT_USB2_WARM                        0x0bc7
+#define USB_PID_WINFAST_DTV2000DS                      0x6a04
+#define USB_PID_WINFAST_DTV_DONGLE_COLD                        0x6025
+#define USB_PID_WINFAST_DTV_DONGLE_WARM                        0x6026
+#define USB_PID_WINFAST_DTV_DONGLE_STK7700P            0x6f00
+#define USB_PID_WINFAST_DTV_DONGLE_H                   0x60f6
+#define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2          0x6f01
+#define USB_PID_WINFAST_DTV_DONGLE_GOLD                        0x6029
+#define USB_PID_GENPIX_8PSK_REV_1_COLD                 0x0200
+#define USB_PID_GENPIX_8PSK_REV_1_WARM                 0x0201
+#define USB_PID_GENPIX_8PSK_REV_2                      0x0202
+#define USB_PID_GENPIX_SKYWALKER_1                     0x0203
+#define USB_PID_GENPIX_SKYWALKER_CW3K                  0x0204
+#define USB_PID_GENPIX_SKYWALKER_2                     0x0206
+#define USB_PID_SIGMATEK_DVB_110                       0x6610
+#define USB_PID_MSI_DIGI_VOX_MINI_II                   0x1513
+#define USB_PID_MSI_DIGIVOX_DUO                                0x8801
+#define USB_PID_OPERA1_COLD                            0x2830
+#define USB_PID_OPERA1_WARM                            0x3829
+#define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD           0x0514
+#define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM           0x0513
+#define USB_PID_GIGABYTE_U7000                         0x7001
+#define USB_PID_GIGABYTE_U8000                         0x7002
+#define USB_PID_ASUS_U3000                             0x171f
+#define USB_PID_ASUS_U3000H                            0x1736
+#define USB_PID_ASUS_U3100                             0x173f
+#define USB_PID_YUAN_EC372S                            0x1edc
+#define USB_PID_YUAN_STK7700PH                         0x1f08
+#define USB_PID_YUAN_PD378S                            0x2edc
+#define USB_PID_YUAN_MC770                             0x0871
+#define USB_PID_YUAN_STK7700D                          0x1efc
+#define USB_PID_YUAN_STK7700D_2                                0x1e8c
+#define USB_PID_DW2102                                 0x2102
+#define USB_PID_XTENSIONS_XD_380                       0x0381
+#define USB_PID_TELESTAR_STARSTICK_2                   0x8000
+#define USB_PID_MSI_DIGI_VOX_MINI_III                   0x8807
+#define USB_PID_SONY_PLAYTV                            0x0003
+#define USB_PID_MYGICA_D689                            0xd811
+#define USB_PID_ELGATO_EYETV_DIVERSITY                 0x0011
+#define USB_PID_ELGATO_EYETV_DTT                       0x0021
+#define USB_PID_ELGATO_EYETV_DTT_2                     0x003f
+#define USB_PID_ELGATO_EYETV_DTT_Dlx                   0x0020
+#define USB_PID_ELGATO_EYETV_SAT                       0x002a
+#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD                0x5000
+#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM                0x5001
+#define USB_PID_FRIIO_WHITE                            0x0001
+#define USB_PID_TVWAY_PLUS                             0x0002
+#define USB_PID_SVEON_STV20                            0xe39d
+#define USB_PID_SVEON_STV22                            0xe401
+#define USB_PID_SVEON_STV22_IT9137                     0xe411
+#define USB_PID_AZUREWAVE_AZ6027                       0x3275
+#define USB_PID_TERRATEC_DVBS2CI_V1                    0x10a4
+#define USB_PID_TERRATEC_DVBS2CI_V2                    0x10ac
+#define USB_PID_TECHNISAT_USB2_HDCI_V1                 0x0001
+#define USB_PID_TECHNISAT_USB2_HDCI_V2                 0x0002
+#define USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2          0x0004
+#define USB_PID_TECHNISAT_USB2_DVB_S2                  0x0500
+#endif
diff --git a/drivers/media/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb-core/dvb_ca_en50221.c
new file mode 100644 (file)
index 0000000..9be65a3
--- /dev/null
@@ -0,0 +1,1753 @@
+/*
+ * dvb_ca.c: generic DVB functions for EN50221 CAM interfaces
+ *
+ * Copyright (C) 2004 Andrew de Quincey
+ *
+ * Parts of this file were based on sources as follows:
+ *
+ * Copyright (C) 2003 Ralph Metzler <rjkm@metzlerbros.de>
+ *
+ * based on code:
+ *
+ * Copyright (C) 1999-2002 Ralph  Metzler
+ *                       & Marcus Metzler for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * 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 <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/vmalloc.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+
+#include "dvb_ca_en50221.h"
+#include "dvb_ringbuffer.h"
+
+static int dvb_ca_en50221_debug;
+
+module_param_named(cam_debug, dvb_ca_en50221_debug, int, 0644);
+MODULE_PARM_DESC(cam_debug, "enable verbose debug messages");
+
+#define dprintk if (dvb_ca_en50221_debug) printk
+
+#define INIT_TIMEOUT_SECS 10
+
+#define HOST_LINK_BUF_SIZE 0x200
+
+#define RX_BUFFER_SIZE 65535
+
+#define MAX_RX_PACKETS_PER_ITERATION 10
+
+#define CTRLIF_DATA      0
+#define CTRLIF_COMMAND   1
+#define CTRLIF_STATUS    1
+#define CTRLIF_SIZE_LOW  2
+#define CTRLIF_SIZE_HIGH 3
+
+#define CMDREG_HC        1     /* Host control */
+#define CMDREG_SW        2     /* Size write */
+#define CMDREG_SR        4     /* Size read */
+#define CMDREG_RS        8     /* Reset interface */
+#define CMDREG_FRIE   0x40     /* Enable FR interrupt */
+#define CMDREG_DAIE   0x80     /* Enable DA interrupt */
+#define IRQEN (CMDREG_DAIE)
+
+#define STATUSREG_RE     1     /* read error */
+#define STATUSREG_WE     2     /* write error */
+#define STATUSREG_FR  0x40     /* module free */
+#define STATUSREG_DA  0x80     /* data available */
+#define STATUSREG_TXERR (STATUSREG_RE|STATUSREG_WE)    /* general transfer error */
+
+
+#define DVB_CA_SLOTSTATE_NONE           0
+#define DVB_CA_SLOTSTATE_UNINITIALISED  1
+#define DVB_CA_SLOTSTATE_RUNNING        2
+#define DVB_CA_SLOTSTATE_INVALID        3
+#define DVB_CA_SLOTSTATE_WAITREADY      4
+#define DVB_CA_SLOTSTATE_VALIDATE       5
+#define DVB_CA_SLOTSTATE_WAITFR         6
+#define DVB_CA_SLOTSTATE_LINKINIT       7
+
+
+/* Information on a CA slot */
+struct dvb_ca_slot {
+
+       /* current state of the CAM */
+       int slot_state;
+
+       /* mutex used for serializing access to one CI slot */
+       struct mutex slot_lock;
+
+       /* Number of CAMCHANGES that have occurred since last processing */
+       atomic_t camchange_count;
+
+       /* Type of last CAMCHANGE */
+       int camchange_type;
+
+       /* base address of CAM config */
+       u32 config_base;
+
+       /* value to write into Config Control register */
+       u8 config_option;
+
+       /* if 1, the CAM supports DA IRQs */
+       u8 da_irq_supported:1;
+
+       /* size of the buffer to use when talking to the CAM */
+       int link_buf_size;
+
+       /* buffer for incoming packets */
+       struct dvb_ringbuffer rx_buffer;
+
+       /* timer used during various states of the slot */
+       unsigned long timeout;
+};
+
+/* Private CA-interface information */
+struct dvb_ca_private {
+
+       /* pointer back to the public data structure */
+       struct dvb_ca_en50221 *pub;
+
+       /* the DVB device */
+       struct dvb_device *dvbdev;
+
+       /* Flags describing the interface (DVB_CA_FLAG_*) */
+       u32 flags;
+
+       /* number of slots supported by this CA interface */
+       unsigned int slot_count;
+
+       /* information on each slot */
+       struct dvb_ca_slot *slot_info;
+
+       /* wait queues for read() and write() operations */
+       wait_queue_head_t wait_queue;
+
+       /* PID of the monitoring thread */
+       struct task_struct *thread;
+
+       /* Flag indicating if the CA device is open */
+       unsigned int open:1;
+
+       /* Flag indicating the thread should wake up now */
+       unsigned int wakeup:1;
+
+       /* Delay the main thread should use */
+       unsigned long delay;
+
+       /* Slot to start looking for data to read from in the next user-space read operation */
+       int next_read_slot;
+};
+
+static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca);
+static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount);
+static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount);
+
+
+/**
+ * Safely find needle in haystack.
+ *
+ * @param haystack Buffer to look in.
+ * @param hlen Number of bytes in haystack.
+ * @param needle Buffer to find.
+ * @param nlen Number of bytes in needle.
+ * @return Pointer into haystack needle was found at, or NULL if not found.
+ */
+static char *findstr(char * haystack, int hlen, char * needle, int nlen)
+{
+       int i;
+
+       if (hlen < nlen)
+               return NULL;
+
+       for (i = 0; i <= hlen - nlen; i++) {
+               if (!strncmp(haystack + i, needle, nlen))
+                       return haystack + i;
+       }
+
+       return NULL;
+}
+
+
+
+/* ******************************************************************************** */
+/* EN50221 physical interface functions */
+
+
+/**
+ * Check CAM status.
+ */
+static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot)
+{
+       int slot_status;
+       int cam_present_now;
+       int cam_changed;
+
+       /* IRQ mode */
+       if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) {
+               return (atomic_read(&ca->slot_info[slot].camchange_count) != 0);
+       }
+
+       /* poll mode */
+       slot_status = ca->pub->poll_slot_status(ca->pub, slot, ca->open);
+
+       cam_present_now = (slot_status & DVB_CA_EN50221_POLL_CAM_PRESENT) ? 1 : 0;
+       cam_changed = (slot_status & DVB_CA_EN50221_POLL_CAM_CHANGED) ? 1 : 0;
+       if (!cam_changed) {
+               int cam_present_old = (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE);
+               cam_changed = (cam_present_now != cam_present_old);
+       }
+
+       if (cam_changed) {
+               if (!cam_present_now) {
+                       ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;
+               } else {
+                       ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_INSERTED;
+               }
+               atomic_set(&ca->slot_info[slot].camchange_count, 1);
+       } else {
+               if ((ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) &&
+                   (slot_status & DVB_CA_EN50221_POLL_CAM_READY)) {
+                       // move to validate state if reset is completed
+                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE;
+               }
+       }
+
+       return cam_changed;
+}
+
+
+/**
+ * Wait for flags to become set on the STATUS register on a CAM interface,
+ * checking for errors and timeout.
+ *
+ * @param ca CA instance.
+ * @param slot Slot on interface.
+ * @param waitfor Flags to wait for.
+ * @param timeout_ms Timeout in milliseconds.
+ *
+ * @return 0 on success, nonzero on error.
+ */
+static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot,
+                                        u8 waitfor, int timeout_hz)
+{
+       unsigned long timeout;
+       unsigned long start;
+
+       dprintk("%s\n", __func__);
+
+       /* loop until timeout elapsed */
+       start = jiffies;
+       timeout = jiffies + timeout_hz;
+       while (1) {
+               /* read the status and check for error */
+               int res = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
+               if (res < 0)
+                       return -EIO;
+
+               /* if we got the flags, it was successful! */
+               if (res & waitfor) {
+                       dprintk("%s succeeded timeout:%lu\n", __func__, jiffies - start);
+                       return 0;
+               }
+
+               /* check for timeout */
+               if (time_after(jiffies, timeout)) {
+                       break;
+               }
+
+               /* wait for a bit */
+               msleep(1);
+       }
+
+       dprintk("%s failed timeout:%lu\n", __func__, jiffies - start);
+
+       /* if we get here, we've timed out */
+       return -ETIMEDOUT;
+}
+
+
+/**
+ * Initialise the link layer connection to a CAM.
+ *
+ * @param ca CA instance.
+ * @param slot Slot id.
+ *
+ * @return 0 on success, nonzero on failure.
+ */
+static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot)
+{
+       int ret;
+       int buf_size;
+       u8 buf[2];
+
+       dprintk("%s\n", __func__);
+
+       /* we'll be determining these during this function */
+       ca->slot_info[slot].da_irq_supported = 0;
+
+       /* set the host link buffer size temporarily. it will be overwritten with the
+        * real negotiated size later. */
+       ca->slot_info[slot].link_buf_size = 2;
+
+       /* read the buffer size from the CAM */
+       if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SR)) != 0)
+               return ret;
+       if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ / 10)) != 0)
+               return ret;
+       if ((ret = dvb_ca_en50221_read_data(ca, slot, buf, 2)) != 2)
+               return -EIO;
+       if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0)
+               return ret;
+
+       /* store it, and choose the minimum of our buffer and the CAM's buffer size */
+       buf_size = (buf[0] << 8) | buf[1];
+       if (buf_size > HOST_LINK_BUF_SIZE)
+               buf_size = HOST_LINK_BUF_SIZE;
+       ca->slot_info[slot].link_buf_size = buf_size;
+       buf[0] = buf_size >> 8;
+       buf[1] = buf_size & 0xff;
+       dprintk("Chosen link buffer size of %i\n", buf_size);
+
+       /* write the buffer size to the CAM */
+       if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SW)) != 0)
+               return ret;
+       if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10)) != 0)
+               return ret;
+       if ((ret = dvb_ca_en50221_write_data(ca, slot, buf, 2)) != 2)
+               return -EIO;
+       if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0)
+               return ret;
+
+       /* success */
+       return 0;
+}
+
+/**
+ * Read a tuple from attribute memory.
+ *
+ * @param ca CA instance.
+ * @param slot Slot id.
+ * @param address Address to read from. Updated.
+ * @param tupleType Tuple id byte. Updated.
+ * @param tupleLength Tuple length. Updated.
+ * @param tuple Dest buffer for tuple (must be 256 bytes). Updated.
+ *
+ * @return 0 on success, nonzero on error.
+ */
+static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot,
+                                    int *address, int *tupleType, int *tupleLength, u8 * tuple)
+{
+       int i;
+       int _tupleType;
+       int _tupleLength;
+       int _address = *address;
+
+       /* grab the next tuple length and type */
+       if ((_tupleType = ca->pub->read_attribute_mem(ca->pub, slot, _address)) < 0)
+               return _tupleType;
+       if (_tupleType == 0xff) {
+               dprintk("END OF CHAIN TUPLE type:0x%x\n", _tupleType);
+               *address += 2;
+               *tupleType = _tupleType;
+               *tupleLength = 0;
+               return 0;
+       }
+       if ((_tupleLength = ca->pub->read_attribute_mem(ca->pub, slot, _address + 2)) < 0)
+               return _tupleLength;
+       _address += 4;
+
+       dprintk("TUPLE type:0x%x length:%i\n", _tupleType, _tupleLength);
+
+       /* read in the whole tuple */
+       for (i = 0; i < _tupleLength; i++) {
+               tuple[i] = ca->pub->read_attribute_mem(ca->pub, slot, _address + (i * 2));
+               dprintk("  0x%02x: 0x%02x %c\n",
+                       i, tuple[i] & 0xff,
+                       ((tuple[i] > 31) && (tuple[i] < 127)) ? tuple[i] : '.');
+       }
+       _address += (_tupleLength * 2);
+
+       // success
+       *tupleType = _tupleType;
+       *tupleLength = _tupleLength;
+       *address = _address;
+       return 0;
+}
+
+
+/**
+ * Parse attribute memory of a CAM module, extracting Config register, and checking
+ * it is a DVB CAM module.
+ *
+ * @param ca CA instance.
+ * @param slot Slot id.
+ *
+ * @return 0 on success, <0 on failure.
+ */
+static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
+{
+       int address = 0;
+       int tupleLength;
+       int tupleType;
+       u8 tuple[257];
+       char *dvb_str;
+       int rasz;
+       int status;
+       int got_cftableentry = 0;
+       int end_chain = 0;
+       int i;
+       u16 manfid = 0;
+       u16 devid = 0;
+
+
+       // CISTPL_DEVICE_0A
+       if ((status =
+            dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
+               return status;
+       if (tupleType != 0x1D)
+               return -EINVAL;
+
+
+
+       // CISTPL_DEVICE_0C
+       if ((status =
+            dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
+               return status;
+       if (tupleType != 0x1C)
+               return -EINVAL;
+
+
+
+       // CISTPL_VERS_1
+       if ((status =
+            dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
+               return status;
+       if (tupleType != 0x15)
+               return -EINVAL;
+
+
+
+       // CISTPL_MANFID
+       if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
+                                               &tupleLength, tuple)) < 0)
+               return status;
+       if (tupleType != 0x20)
+               return -EINVAL;
+       if (tupleLength != 4)
+               return -EINVAL;
+       manfid = (tuple[1] << 8) | tuple[0];
+       devid = (tuple[3] << 8) | tuple[2];
+
+
+
+       // CISTPL_CONFIG
+       if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
+                                               &tupleLength, tuple)) < 0)
+               return status;
+       if (tupleType != 0x1A)
+               return -EINVAL;
+       if (tupleLength < 3)
+               return -EINVAL;
+
+       /* extract the configbase */
+       rasz = tuple[0] & 3;
+       if (tupleLength < (3 + rasz + 14))
+               return -EINVAL;
+       ca->slot_info[slot].config_base = 0;
+       for (i = 0; i < rasz + 1; i++) {
+               ca->slot_info[slot].config_base |= (tuple[2 + i] << (8 * i));
+       }
+
+       /* check it contains the correct DVB string */
+       dvb_str = findstr((char *)tuple, tupleLength, "DVB_CI_V", 8);
+       if (dvb_str == NULL)
+               return -EINVAL;
+       if (tupleLength < ((dvb_str - (char *) tuple) + 12))
+               return -EINVAL;
+
+       /* is it a version we support? */
+       if (strncmp(dvb_str + 8, "1.00", 4)) {
+               printk("dvb_ca adapter %d: Unsupported DVB CAM module version %c%c%c%c\n",
+                      ca->dvbdev->adapter->num, dvb_str[8], dvb_str[9], dvb_str[10], dvb_str[11]);
+               return -EINVAL;
+       }
+
+       /* process the CFTABLE_ENTRY tuples, and any after those */
+       while ((!end_chain) && (address < 0x1000)) {
+               if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
+                                                       &tupleLength, tuple)) < 0)
+                       return status;
+               switch (tupleType) {
+               case 0x1B:      // CISTPL_CFTABLE_ENTRY
+                       if (tupleLength < (2 + 11 + 17))
+                               break;
+
+                       /* if we've already parsed one, just use it */
+                       if (got_cftableentry)
+                               break;
+
+                       /* get the config option */
+                       ca->slot_info[slot].config_option = tuple[0] & 0x3f;
+
+                       /* OK, check it contains the correct strings */
+                       if ((findstr((char *)tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
+                           (findstr((char *)tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
+                               break;
+
+                       got_cftableentry = 1;
+                       break;
+
+               case 0x14:      // CISTPL_NO_LINK
+                       break;
+
+               case 0xFF:      // CISTPL_END
+                       end_chain = 1;
+                       break;
+
+               default:        /* Unknown tuple type - just skip this tuple and move to the next one */
+                       dprintk("dvb_ca: Skipping unknown tuple type:0x%x length:0x%x\n", tupleType,
+                               tupleLength);
+                       break;
+               }
+       }
+
+       if ((address > 0x1000) || (!got_cftableentry))
+               return -EINVAL;
+
+       dprintk("Valid DVB CAM detected MANID:%x DEVID:%x CONFIGBASE:0x%x CONFIGOPTION:0x%x\n",
+               manfid, devid, ca->slot_info[slot].config_base, ca->slot_info[slot].config_option);
+
+       // success!
+       return 0;
+}
+
+
+/**
+ * Set CAM's configoption correctly.
+ *
+ * @param ca CA instance.
+ * @param slot Slot containing the CAM.
+ */
+static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot)
+{
+       int configoption;
+
+       dprintk("%s\n", __func__);
+
+       /* set the config option */
+       ca->pub->write_attribute_mem(ca->pub, slot,
+                                    ca->slot_info[slot].config_base,
+                                    ca->slot_info[slot].config_option);
+
+       /* check it */
+       configoption = ca->pub->read_attribute_mem(ca->pub, slot, ca->slot_info[slot].config_base);
+       dprintk("Set configoption 0x%x, read configoption 0x%x\n",
+               ca->slot_info[slot].config_option, configoption & 0x3f);
+
+       /* fine! */
+       return 0;
+
+}
+
+
+/**
+ * This function talks to an EN50221 CAM control interface. It reads a buffer of
+ * data from the CAM. The data can either be stored in a supplied buffer, or
+ * automatically be added to the slot's rx_buffer.
+ *
+ * @param ca CA instance.
+ * @param slot Slot to read from.
+ * @param ebuf If non-NULL, the data will be written to this buffer. If NULL,
+ * the data will be added into the buffering system as a normal fragment.
+ * @param ecount Size of ebuf. Ignored if ebuf is NULL.
+ *
+ * @return Number of bytes read, or < 0 on error
+ */
+static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount)
+{
+       int bytes_read;
+       int status;
+       u8 buf[HOST_LINK_BUF_SIZE];
+       int i;
+
+       dprintk("%s\n", __func__);
+
+       /* check if we have space for a link buf in the rx_buffer */
+       if (ebuf == NULL) {
+               int buf_free;
+
+               if (ca->slot_info[slot].rx_buffer.data == NULL) {
+                       status = -EIO;
+                       goto exit;
+               }
+               buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer);
+
+               if (buf_free < (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) {
+                       status = -EAGAIN;
+                       goto exit;
+               }
+       }
+
+       /* check if there is data available */
+       if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
+               goto exit;
+       if (!(status & STATUSREG_DA)) {
+               /* no data */
+               status = 0;
+               goto exit;
+       }
+
+       /* read the amount of data */
+       if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH)) < 0)
+               goto exit;
+       bytes_read = status << 8;
+       if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW)) < 0)
+               goto exit;
+       bytes_read |= status;
+
+       /* check it will fit */
+       if (ebuf == NULL) {
+               if (bytes_read > ca->slot_info[slot].link_buf_size) {
+                       printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n",
+                              ca->dvbdev->adapter->num, bytes_read, ca->slot_info[slot].link_buf_size);
+                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+                       status = -EIO;
+                       goto exit;
+               }
+               if (bytes_read < 2) {
+                       printk("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n",
+                              ca->dvbdev->adapter->num);
+                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+                       status = -EIO;
+                       goto exit;
+               }
+       } else {
+               if (bytes_read > ecount) {
+                       printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n",
+                              ca->dvbdev->adapter->num);
+                       status = -EIO;
+                       goto exit;
+               }
+       }
+
+       /* fill the buffer */
+       for (i = 0; i < bytes_read; i++) {
+               /* read byte and check */
+               if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_DATA)) < 0)
+                       goto exit;
+
+               /* OK, store it in the buffer */
+               buf[i] = status;
+       }
+
+       /* check for read error (RE should now be 0) */
+       if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
+               goto exit;
+       if (status & STATUSREG_RE) {
+               ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+               status = -EIO;
+               goto exit;
+       }
+
+       /* OK, add it to the receive buffer, or copy into external buffer if supplied */
+       if (ebuf == NULL) {
+               if (ca->slot_info[slot].rx_buffer.data == NULL) {
+                       status = -EIO;
+                       goto exit;
+               }
+               dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read);
+       } else {
+               memcpy(ebuf, buf, bytes_read);
+       }
+
+       dprintk("Received CA packet for slot %i connection id 0x%x last_frag:%i size:0x%x\n", slot,
+               buf[0], (buf[1] & 0x80) == 0, bytes_read);
+
+       /* wake up readers when a last_fragment is received */
+       if ((buf[1] & 0x80) == 0x00) {
+               wake_up_interruptible(&ca->wait_queue);
+       }
+       status = bytes_read;
+
+exit:
+       return status;
+}
+
+
+/**
+ * This function talks to an EN50221 CAM control interface. It writes a buffer of data
+ * to a CAM.
+ *
+ * @param ca CA instance.
+ * @param slot Slot to write to.
+ * @param ebuf The data in this buffer is treated as a complete link-level packet to
+ * be written.
+ * @param count Size of ebuf.
+ *
+ * @return Number of bytes written, or < 0 on error.
+ */
+static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * buf, int bytes_write)
+{
+       int status;
+       int i;
+
+       dprintk("%s\n", __func__);
+
+
+       /* sanity check */
+       if (bytes_write > ca->slot_info[slot].link_buf_size)
+               return -EINVAL;
+
+       /* it is possible we are dealing with a single buffer implementation,
+          thus if there is data available for read or if there is even a read
+          already in progress, we do nothing but awake the kernel thread to
+          process the data if necessary. */
+       if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
+               goto exitnowrite;
+       if (status & (STATUSREG_DA | STATUSREG_RE)) {
+               if (status & STATUSREG_DA)
+                       dvb_ca_en50221_thread_wakeup(ca);
+
+               status = -EAGAIN;
+               goto exitnowrite;
+       }
+
+       /* OK, set HC bit */
+       if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,
+                                                IRQEN | CMDREG_HC)) != 0)
+               goto exit;
+
+       /* check if interface is still free */
+       if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
+               goto exit;
+       if (!(status & STATUSREG_FR)) {
+               /* it wasn't free => try again later */
+               status = -EAGAIN;
+               goto exit;
+       }
+
+       /* send the amount of data */
+       if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0)
+               goto exit;
+       if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW,
+                                                bytes_write & 0xff)) != 0)
+               goto exit;
+
+       /* send the buffer */
+       for (i = 0; i < bytes_write; i++) {
+               if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_DATA, buf[i])) != 0)
+                       goto exit;
+       }
+
+       /* check for write error (WE should now be 0) */
+       if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
+               goto exit;
+       if (status & STATUSREG_WE) {
+               ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+               status = -EIO;
+               goto exit;
+       }
+       status = bytes_write;
+
+       dprintk("Wrote CA packet for slot %i, connection id 0x%x last_frag:%i size:0x%x\n", slot,
+               buf[0], (buf[1] & 0x80) == 0, bytes_write);
+
+exit:
+       ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);
+
+exitnowrite:
+       return status;
+}
+EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq);
+
+
+
+/* ******************************************************************************** */
+/* EN50221 higher level functions */
+
+
+/**
+ * A CAM has been removed => shut it down.
+ *
+ * @param ca CA instance.
+ * @param slot Slot to shut down.
+ */
+static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot)
+{
+       dprintk("%s\n", __func__);
+
+       ca->pub->slot_shutdown(ca->pub, slot);
+       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+
+       /* need to wake up all processes to check if they're now
+          trying to write to a defunct CAM */
+       wake_up_interruptible(&ca->wait_queue);
+
+       dprintk("Slot %i shutdown\n", slot);
+
+       /* success */
+       return 0;
+}
+EXPORT_SYMBOL(dvb_ca_en50221_camready_irq);
+
+
+/**
+ * A CAMCHANGE IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ * @param change_type One of the DVB_CA_CAMCHANGE_* values.
+ */
+void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221 *pubca, int slot, int change_type)
+{
+       struct dvb_ca_private *ca = pubca->private;
+
+       dprintk("CAMCHANGE IRQ slot:%i change_type:%i\n", slot, change_type);
+
+       switch (change_type) {
+       case DVB_CA_EN50221_CAMCHANGE_REMOVED:
+       case DVB_CA_EN50221_CAMCHANGE_INSERTED:
+               break;
+
+       default:
+               return;
+       }
+
+       ca->slot_info[slot].camchange_type = change_type;
+       atomic_inc(&ca->slot_info[slot].camchange_count);
+       dvb_ca_en50221_thread_wakeup(ca);
+}
+EXPORT_SYMBOL(dvb_ca_en50221_frda_irq);
+
+
+/**
+ * A CAMREADY IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ */
+void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot)
+{
+       struct dvb_ca_private *ca = pubca->private;
+
+       dprintk("CAMREADY IRQ slot:%i\n", slot);
+
+       if (ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) {
+               ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE;
+               dvb_ca_en50221_thread_wakeup(ca);
+       }
+}
+
+
+/**
+ * An FR or DA IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ */
+void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot)
+{
+       struct dvb_ca_private *ca = pubca->private;
+       int flags;
+
+       dprintk("FR/DA IRQ slot:%i\n", slot);
+
+       switch (ca->slot_info[slot].slot_state) {
+       case DVB_CA_SLOTSTATE_LINKINIT:
+               flags = ca->pub->read_cam_control(pubca, slot, CTRLIF_STATUS);
+               if (flags & STATUSREG_DA) {
+                       dprintk("CAM supports DA IRQ\n");
+                       ca->slot_info[slot].da_irq_supported = 1;
+               }
+               break;
+
+       case DVB_CA_SLOTSTATE_RUNNING:
+               if (ca->open)
+                       dvb_ca_en50221_thread_wakeup(ca);
+               break;
+       }
+}
+
+
+
+/* ******************************************************************************** */
+/* EN50221 thread functions */
+
+/**
+ * Wake up the DVB CA thread
+ *
+ * @param ca CA instance.
+ */
+static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca)
+{
+
+       dprintk("%s\n", __func__);
+
+       ca->wakeup = 1;
+       mb();
+       wake_up_process(ca->thread);
+}
+
+/**
+ * Update the delay used by the thread.
+ *
+ * @param ca CA instance.
+ */
+static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca)
+{
+       int delay;
+       int curdelay = 100000000;
+       int slot;
+
+       /* Beware of too high polling frequency, because one polling
+        * call might take several hundred milliseconds until timeout!
+        */
+       for (slot = 0; slot < ca->slot_count; slot++) {
+               switch (ca->slot_info[slot].slot_state) {
+               default:
+               case DVB_CA_SLOTSTATE_NONE:
+                       delay = HZ * 60;  /* 60s */
+                       if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+                               delay = HZ * 5;  /* 5s */
+                       break;
+               case DVB_CA_SLOTSTATE_INVALID:
+                       delay = HZ * 60;  /* 60s */
+                       if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+                               delay = HZ / 10;  /* 100ms */
+                       break;
+
+               case DVB_CA_SLOTSTATE_UNINITIALISED:
+               case DVB_CA_SLOTSTATE_WAITREADY:
+               case DVB_CA_SLOTSTATE_VALIDATE:
+               case DVB_CA_SLOTSTATE_WAITFR:
+               case DVB_CA_SLOTSTATE_LINKINIT:
+                       delay = HZ / 10;  /* 100ms */
+                       break;
+
+               case DVB_CA_SLOTSTATE_RUNNING:
+                       delay = HZ * 60;  /* 60s */
+                       if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
+                               delay = HZ / 10;  /* 100ms */
+                       if (ca->open) {
+                               if ((!ca->slot_info[slot].da_irq_supported) ||
+                                   (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA)))
+                                       delay = HZ / 10;  /* 100ms */
+                       }
+                       break;
+               }
+
+               if (delay < curdelay)
+                       curdelay = delay;
+       }
+
+       ca->delay = curdelay;
+}
+
+
+
+/**
+ * Kernel thread which monitors CA slots for CAM changes, and performs data transfers.
+ */
+static int dvb_ca_en50221_thread(void *data)
+{
+       struct dvb_ca_private *ca = data;
+       int slot;
+       int flags;
+       int status;
+       int pktcount;
+       void *rxbuf;
+
+       dprintk("%s\n", __func__);
+
+       /* choose the correct initial delay */
+       dvb_ca_en50221_thread_update_delay(ca);
+
+       /* main loop */
+       while (!kthread_should_stop()) {
+               /* sleep for a bit */
+               if (!ca->wakeup) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       schedule_timeout(ca->delay);
+                       if (kthread_should_stop())
+                               return 0;
+               }
+               ca->wakeup = 0;
+
+               /* go through all the slots processing them */
+               for (slot = 0; slot < ca->slot_count; slot++) {
+
+                       mutex_lock(&ca->slot_info[slot].slot_lock);
+
+                       // check the cam status + deal with CAMCHANGEs
+                       while (dvb_ca_en50221_check_camstatus(ca, slot)) {
+                               /* clear down an old CI slot if necessary */
+                               if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE)
+                                       dvb_ca_en50221_slot_shutdown(ca, slot);
+
+                               /* if a CAM is NOW present, initialise it */
+                               if (ca->slot_info[slot].camchange_type == DVB_CA_EN50221_CAMCHANGE_INSERTED) {
+                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_UNINITIALISED;
+                               }
+
+                               /* we've handled one CAMCHANGE */
+                               dvb_ca_en50221_thread_update_delay(ca);
+                               atomic_dec(&ca->slot_info[slot].camchange_count);
+                       }
+
+                       // CAM state machine
+                       switch (ca->slot_info[slot].slot_state) {
+                       case DVB_CA_SLOTSTATE_NONE:
+                       case DVB_CA_SLOTSTATE_INVALID:
+                               // no action needed
+                               break;
+
+                       case DVB_CA_SLOTSTATE_UNINITIALISED:
+                               ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITREADY;
+                               ca->pub->slot_reset(ca->pub, slot);
+                               ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);
+                               break;
+
+                       case DVB_CA_SLOTSTATE_WAITREADY:
+                               if (time_after(jiffies, ca->slot_info[slot].timeout)) {
+                                       printk("dvb_ca adaptor %d: PC card did not respond :(\n",
+                                              ca->dvbdev->adapter->num);
+                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+                                       dvb_ca_en50221_thread_update_delay(ca);
+                                       break;
+                               }
+                               // no other action needed; will automatically change state when ready
+                               break;
+
+                       case DVB_CA_SLOTSTATE_VALIDATE:
+                               if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) {
+                                       /* we need this extra check for annoying interfaces like the budget-av */
+                                       if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
+                                           (ca->pub->poll_slot_status)) {
+                                               status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+                                               if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+                                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+                                                       dvb_ca_en50221_thread_update_delay(ca);
+                                                       break;
+                                               }
+                                       }
+
+                                       printk("dvb_ca adapter %d: Invalid PC card inserted :(\n",
+                                              ca->dvbdev->adapter->num);
+                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+                                       dvb_ca_en50221_thread_update_delay(ca);
+                                       break;
+                               }
+                               if (dvb_ca_en50221_set_configoption(ca, slot) != 0) {
+                                       printk("dvb_ca adapter %d: Unable to initialise CAM :(\n",
+                                              ca->dvbdev->adapter->num);
+                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+                                       dvb_ca_en50221_thread_update_delay(ca);
+                                       break;
+                               }
+                               if (ca->pub->write_cam_control(ca->pub, slot,
+                                                              CTRLIF_COMMAND, CMDREG_RS) != 0) {
+                                       printk("dvb_ca adapter %d: Unable to reset CAM IF\n",
+                                              ca->dvbdev->adapter->num);
+                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+                                       dvb_ca_en50221_thread_update_delay(ca);
+                                       break;
+                               }
+                               dprintk("DVB CAM validated successfully\n");
+
+                               ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);
+                               ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITFR;
+                               ca->wakeup = 1;
+                               break;
+
+                       case DVB_CA_SLOTSTATE_WAITFR:
+                               if (time_after(jiffies, ca->slot_info[slot].timeout)) {
+                                       printk("dvb_ca adapter %d: DVB CAM did not respond :(\n",
+                                              ca->dvbdev->adapter->num);
+                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+                                       dvb_ca_en50221_thread_update_delay(ca);
+                                       break;
+                               }
+
+                               flags = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
+                               if (flags & STATUSREG_FR) {
+                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
+                                       ca->wakeup = 1;
+                               }
+                               break;
+
+                       case DVB_CA_SLOTSTATE_LINKINIT:
+                               if (dvb_ca_en50221_link_init(ca, slot) != 0) {
+                                       /* we need this extra check for annoying interfaces like the budget-av */
+                                       if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
+                                           (ca->pub->poll_slot_status)) {
+                                               status = ca->pub->poll_slot_status(ca->pub, slot, 0);
+                                               if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
+                                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
+                                                       dvb_ca_en50221_thread_update_delay(ca);
+                                                       break;
+                                               }
+                                       }
+
+                                       printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num);
+                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+                                       dvb_ca_en50221_thread_update_delay(ca);
+                                       break;
+                               }
+
+                               if (ca->slot_info[slot].rx_buffer.data == NULL) {
+                                       rxbuf = vmalloc(RX_BUFFER_SIZE);
+                                       if (rxbuf == NULL) {
+                                               printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num);
+                                               ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
+                                               dvb_ca_en50221_thread_update_delay(ca);
+                                               break;
+                                       }
+                                       dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE);
+                               }
+
+                               ca->pub->slot_ts_enable(ca->pub, slot);
+                               ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING;
+                               dvb_ca_en50221_thread_update_delay(ca);
+                               printk("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", ca->dvbdev->adapter->num);
+                               break;
+
+                       case DVB_CA_SLOTSTATE_RUNNING:
+                               if (!ca->open)
+                                       break;
+
+                               // poll slots for data
+                               pktcount = 0;
+                               while ((status = dvb_ca_en50221_read_data(ca, slot, NULL, 0)) > 0) {
+                                       if (!ca->open)
+                                               break;
+
+                                       /* if a CAMCHANGE occurred at some point, do not do any more processing of this slot */
+                                       if (dvb_ca_en50221_check_camstatus(ca, slot)) {
+                                               // we dont want to sleep on the next iteration so we can handle the cam change
+                                               ca->wakeup = 1;
+                                               break;
+                                       }
+
+                                       /* check if we've hit our limit this time */
+                                       if (++pktcount >= MAX_RX_PACKETS_PER_ITERATION) {
+                                               // dont sleep; there is likely to be more data to read
+                                               ca->wakeup = 1;
+                                               break;
+                                       }
+                               }
+                               break;
+                       }
+
+                       mutex_unlock(&ca->slot_info[slot].slot_lock);
+               }
+       }
+
+       return 0;
+}
+
+
+
+/* ******************************************************************************** */
+/* EN50221 IO interface functions */
+
+/**
+ * Real ioctl implementation.
+ * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them.
+ *
+ * @param inode Inode concerned.
+ * @param file File concerned.
+ * @param cmd IOCTL command.
+ * @param arg Associated argument.
+ *
+ * @return 0 on success, <0 on error.
+ */
+static int dvb_ca_en50221_io_do_ioctl(struct file *file,
+                                     unsigned int cmd, void *parg)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_ca_private *ca = dvbdev->priv;
+       int err = 0;
+       int slot;
+
+       dprintk("%s\n", __func__);
+
+       switch (cmd) {
+       case CA_RESET:
+               for (slot = 0; slot < ca->slot_count; slot++) {
+                       mutex_lock(&ca->slot_info[slot].slot_lock);
+                       if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) {
+                               dvb_ca_en50221_slot_shutdown(ca, slot);
+                               if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)
+                                       dvb_ca_en50221_camchange_irq(ca->pub,
+                                                                    slot,
+                                                                    DVB_CA_EN50221_CAMCHANGE_INSERTED);
+                       }
+                       mutex_unlock(&ca->slot_info[slot].slot_lock);
+               }
+               ca->next_read_slot = 0;
+               dvb_ca_en50221_thread_wakeup(ca);
+               break;
+
+       case CA_GET_CAP: {
+               struct ca_caps *caps = parg;
+
+               caps->slot_num = ca->slot_count;
+               caps->slot_type = CA_CI_LINK;
+               caps->descr_num = 0;
+               caps->descr_type = 0;
+               break;
+       }
+
+       case CA_GET_SLOT_INFO: {
+               struct ca_slot_info *info = parg;
+
+               if ((info->num > ca->slot_count) || (info->num < 0))
+                       return -EINVAL;
+
+               info->type = CA_CI_LINK;
+               info->flags = 0;
+               if ((ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_NONE)
+                       && (ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_INVALID)) {
+                       info->flags = CA_CI_MODULE_PRESENT;
+               }
+               if (ca->slot_info[info->num].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
+                       info->flags |= CA_CI_MODULE_READY;
+               }
+               break;
+       }
+
+       default:
+               err = -EINVAL;
+               break;
+       }
+
+       return err;
+}
+
+
+/**
+ * Wrapper for ioctl implementation.
+ *
+ * @param inode Inode concerned.
+ * @param file File concerned.
+ * @param cmd IOCTL command.
+ * @param arg Associated argument.
+ *
+ * @return 0 on success, <0 on error.
+ */
+static long dvb_ca_en50221_io_ioctl(struct file *file,
+                                   unsigned int cmd, unsigned long arg)
+{
+       return dvb_usercopy(file, cmd, arg, dvb_ca_en50221_io_do_ioctl);
+}
+
+
+/**
+ * Implementation of write() syscall.
+ *
+ * @param file File structure.
+ * @param buf Source buffer.
+ * @param count Size of source buffer.
+ * @param ppos Position in file (ignored).
+ *
+ * @return Number of bytes read, or <0 on error.
+ */
+static ssize_t dvb_ca_en50221_io_write(struct file *file,
+                                      const char __user * buf, size_t count, loff_t * ppos)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_ca_private *ca = dvbdev->priv;
+       u8 slot, connection_id;
+       int status;
+       u8 fragbuf[HOST_LINK_BUF_SIZE];
+       int fragpos = 0;
+       int fraglen;
+       unsigned long timeout;
+       int written;
+
+       dprintk("%s\n", __func__);
+
+       /* Incoming packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
+       if (count < 2)
+               return -EINVAL;
+
+       /* extract slot & connection id */
+       if (copy_from_user(&slot, buf, 1))
+               return -EFAULT;
+       if (copy_from_user(&connection_id, buf + 1, 1))
+               return -EFAULT;
+       buf += 2;
+       count -= 2;
+
+       /* check if the slot is actually running */
+       if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING)
+               return -EINVAL;
+
+       /* fragment the packets & store in the buffer */
+       while (fragpos < count) {
+               fraglen = ca->slot_info[slot].link_buf_size - 2;
+               if (fraglen < 0)
+                       break;
+               if (fraglen > HOST_LINK_BUF_SIZE - 2)
+                       fraglen = HOST_LINK_BUF_SIZE - 2;
+               if ((count - fragpos) < fraglen)
+                       fraglen = count - fragpos;
+
+               fragbuf[0] = connection_id;
+               fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00;
+               status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen);
+               if (status) {
+                       status = -EFAULT;
+                       goto exit;
+               }
+
+               timeout = jiffies + HZ / 2;
+               written = 0;
+               while (!time_after(jiffies, timeout)) {
+                       /* check the CAM hasn't been removed/reset in the meantime */
+                       if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) {
+                               status = -EIO;
+                               goto exit;
+                       }
+
+                       mutex_lock(&ca->slot_info[slot].slot_lock);
+                       status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen + 2);
+                       mutex_unlock(&ca->slot_info[slot].slot_lock);
+                       if (status == (fraglen + 2)) {
+                               written = 1;
+                               break;
+                       }
+                       if (status != -EAGAIN)
+                               goto exit;
+
+                       msleep(1);
+               }
+               if (!written) {
+                       status = -EIO;
+                       goto exit;
+               }
+
+               fragpos += fraglen;
+       }
+       status = count + 2;
+
+exit:
+       return status;
+}
+
+
+/**
+ * Condition for waking up in dvb_ca_en50221_io_read_condition
+ */
+static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca,
+                                           int *result, int *_slot)
+{
+       int slot;
+       int slot_count = 0;
+       int idx;
+       size_t fraglen;
+       int connection_id = -1;
+       int found = 0;
+       u8 hdr[2];
+
+       slot = ca->next_read_slot;
+       while ((slot_count < ca->slot_count) && (!found)) {
+               if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING)
+                       goto nextslot;
+
+               if (ca->slot_info[slot].rx_buffer.data == NULL) {
+                       return 0;
+               }
+
+               idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
+               while (idx != -1) {
+                       dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2);
+                       if (connection_id == -1)
+                               connection_id = hdr[0];
+                       if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) {
+                               *_slot = slot;
+                               found = 1;
+                               break;
+                       }
+
+                       idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen);
+               }
+
+nextslot:
+               slot = (slot + 1) % ca->slot_count;
+               slot_count++;
+       }
+
+       ca->next_read_slot = slot;
+       return found;
+}
+
+
+/**
+ * Implementation of read() syscall.
+ *
+ * @param file File structure.
+ * @param buf Destination buffer.
+ * @param count Size of destination buffer.
+ * @param ppos Position in file (ignored).
+ *
+ * @return Number of bytes read, or <0 on error.
+ */
+static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
+                                     size_t count, loff_t * ppos)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_ca_private *ca = dvbdev->priv;
+       int status;
+       int result = 0;
+       u8 hdr[2];
+       int slot;
+       int connection_id = -1;
+       size_t idx, idx2;
+       int last_fragment = 0;
+       size_t fraglen;
+       int pktlen;
+       int dispose = 0;
+
+       dprintk("%s\n", __func__);
+
+       /* Outgoing packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
+       if (count < 2)
+               return -EINVAL;
+
+       /* wait for some data */
+       if ((status = dvb_ca_en50221_io_read_condition(ca, &result, &slot)) == 0) {
+
+               /* if we're in nonblocking mode, exit immediately */
+               if (file->f_flags & O_NONBLOCK)
+                       return -EWOULDBLOCK;
+
+               /* wait for some data */
+               status = wait_event_interruptible(ca->wait_queue,
+                                                 dvb_ca_en50221_io_read_condition
+                                                 (ca, &result, &slot));
+       }
+       if ((status < 0) || (result < 0)) {
+               if (result)
+                       return result;
+               return status;
+       }
+
+       idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
+       pktlen = 2;
+       do {
+               if (idx == -1) {
+                       printk("dvb_ca adapter %d: BUG: read packet ended before last_fragment encountered\n", ca->dvbdev->adapter->num);
+                       status = -EIO;
+                       goto exit;
+               }
+
+               dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2);
+               if (connection_id == -1)
+                       connection_id = hdr[0];
+               if (hdr[0] == connection_id) {
+                       if (pktlen < count) {
+                               if ((pktlen + fraglen - 2) > count) {
+                                       fraglen = count - pktlen;
+                               } else {
+                                       fraglen -= 2;
+                               }
+
+                               if ((status = dvb_ringbuffer_pkt_read_user(&ca->slot_info[slot].rx_buffer, idx, 2,
+                                                                     buf + pktlen, fraglen)) < 0) {
+                                       goto exit;
+                               }
+                               pktlen += fraglen;
+                       }
+
+                       if ((hdr[1] & 0x80) == 0)
+                               last_fragment = 1;
+                       dispose = 1;
+               }
+
+               idx2 = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen);
+               if (dispose)
+                       dvb_ringbuffer_pkt_dispose(&ca->slot_info[slot].rx_buffer, idx);
+               idx = idx2;
+               dispose = 0;
+       } while (!last_fragment);
+
+       hdr[0] = slot;
+       hdr[1] = connection_id;
+       status = copy_to_user(buf, hdr, 2);
+       if (status) {
+               status = -EFAULT;
+               goto exit;
+       }
+       status = pktlen;
+
+exit:
+       return status;
+}
+
+
+/**
+ * Implementation of file open syscall.
+ *
+ * @param inode Inode concerned.
+ * @param file File concerned.
+ *
+ * @return 0 on success, <0 on failure.
+ */
+static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_ca_private *ca = dvbdev->priv;
+       int err;
+       int i;
+
+       dprintk("%s\n", __func__);
+
+       if (!try_module_get(ca->pub->owner))
+               return -EIO;
+
+       err = dvb_generic_open(inode, file);
+       if (err < 0) {
+               module_put(ca->pub->owner);
+               return err;
+       }
+
+       for (i = 0; i < ca->slot_count; i++) {
+
+               if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
+                       if (ca->slot_info[i].rx_buffer.data != NULL) {
+                               /* it is safe to call this here without locks because
+                                * ca->open == 0. Data is not read in this case */
+                               dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer);
+                       }
+               }
+       }
+
+       ca->open = 1;
+       dvb_ca_en50221_thread_update_delay(ca);
+       dvb_ca_en50221_thread_wakeup(ca);
+
+       return 0;
+}
+
+
+/**
+ * Implementation of file close syscall.
+ *
+ * @param inode Inode concerned.
+ * @param file File concerned.
+ *
+ * @return 0 on success, <0 on failure.
+ */
+static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_ca_private *ca = dvbdev->priv;
+       int err;
+
+       dprintk("%s\n", __func__);
+
+       /* mark the CA device as closed */
+       ca->open = 0;
+       dvb_ca_en50221_thread_update_delay(ca);
+
+       err = dvb_generic_release(inode, file);
+
+       module_put(ca->pub->owner);
+
+       return err;
+}
+
+
+/**
+ * Implementation of poll() syscall.
+ *
+ * @param file File concerned.
+ * @param wait poll wait table.
+ *
+ * @return Standard poll mask.
+ */
+static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table * wait)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_ca_private *ca = dvbdev->priv;
+       unsigned int mask = 0;
+       int slot;
+       int result = 0;
+
+       dprintk("%s\n", __func__);
+
+       if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
+               mask |= POLLIN;
+       }
+
+       /* if there is something, return now */
+       if (mask)
+               return mask;
+
+       /* wait for something to happen */
+       poll_wait(file, &ca->wait_queue, wait);
+
+       if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
+               mask |= POLLIN;
+       }
+
+       return mask;
+}
+EXPORT_SYMBOL(dvb_ca_en50221_init);
+
+
+static const struct file_operations dvb_ca_fops = {
+       .owner = THIS_MODULE,
+       .read = dvb_ca_en50221_io_read,
+       .write = dvb_ca_en50221_io_write,
+       .unlocked_ioctl = dvb_ca_en50221_io_ioctl,
+       .open = dvb_ca_en50221_io_open,
+       .release = dvb_ca_en50221_io_release,
+       .poll = dvb_ca_en50221_io_poll,
+       .llseek = noop_llseek,
+};
+
+static struct dvb_device dvbdev_ca = {
+       .priv = NULL,
+       .users = 1,
+       .readers = 1,
+       .writers = 1,
+       .fops = &dvb_ca_fops,
+};
+
+
+/* ******************************************************************************** */
+/* Initialisation/shutdown functions */
+
+
+/**
+ * Initialise a new DVB CA EN50221 interface device.
+ *
+ * @param dvb_adapter DVB adapter to attach the new CA device to.
+ * @param ca The dvb_ca instance.
+ * @param flags Flags describing the CA device (DVB_CA_FLAG_*).
+ * @param slot_count Number of slots supported.
+ *
+ * @return 0 on success, nonzero on failure
+ */
+int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
+                       struct dvb_ca_en50221 *pubca, int flags, int slot_count)
+{
+       int ret;
+       struct dvb_ca_private *ca = NULL;
+       int i;
+
+       dprintk("%s\n", __func__);
+
+       if (slot_count < 1)
+               return -EINVAL;
+
+       /* initialise the system data */
+       if ((ca = kzalloc(sizeof(struct dvb_ca_private), GFP_KERNEL)) == NULL) {
+               ret = -ENOMEM;
+               goto error;
+       }
+       ca->pub = pubca;
+       ca->flags = flags;
+       ca->slot_count = slot_count;
+       if ((ca->slot_info = kcalloc(slot_count, sizeof(struct dvb_ca_slot), GFP_KERNEL)) == NULL) {
+               ret = -ENOMEM;
+               goto error;
+       }
+       init_waitqueue_head(&ca->wait_queue);
+       ca->open = 0;
+       ca->wakeup = 0;
+       ca->next_read_slot = 0;
+       pubca->private = ca;
+
+       /* register the DVB device */
+       ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA);
+       if (ret)
+               goto error;
+
+       /* now initialise each slot */
+       for (i = 0; i < slot_count; i++) {
+               memset(&ca->slot_info[i], 0, sizeof(struct dvb_ca_slot));
+               ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE;
+               atomic_set(&ca->slot_info[i].camchange_count, 0);
+               ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;
+               mutex_init(&ca->slot_info[i].slot_lock);
+       }
+
+       if (signal_pending(current)) {
+               ret = -EINTR;
+               goto error;
+       }
+       mb();
+
+       /* create a kthread for monitoring this CA device */
+       ca->thread = kthread_run(dvb_ca_en50221_thread, ca, "kdvb-ca-%i:%i",
+                                ca->dvbdev->adapter->num, ca->dvbdev->id);
+       if (IS_ERR(ca->thread)) {
+               ret = PTR_ERR(ca->thread);
+               printk("dvb_ca_init: failed to start kernel_thread (%d)\n",
+                       ret);
+               goto error;
+       }
+       return 0;
+
+error:
+       if (ca != NULL) {
+               if (ca->dvbdev != NULL)
+                       dvb_unregister_device(ca->dvbdev);
+               kfree(ca->slot_info);
+               kfree(ca);
+       }
+       pubca->private = NULL;
+       return ret;
+}
+EXPORT_SYMBOL(dvb_ca_en50221_release);
+
+
+
+/**
+ * Release a DVB CA EN50221 interface device.
+ *
+ * @param ca_dev The dvb_device_t instance for the CA device.
+ * @param ca The associated dvb_ca instance.
+ */
+void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
+{
+       struct dvb_ca_private *ca = pubca->private;
+       int i;
+
+       dprintk("%s\n", __func__);
+
+       /* shutdown the thread if there was one */
+       kthread_stop(ca->thread);
+
+       for (i = 0; i < ca->slot_count; i++) {
+               dvb_ca_en50221_slot_shutdown(ca, i);
+               vfree(ca->slot_info[i].rx_buffer.data);
+       }
+       kfree(ca->slot_info);
+       dvb_unregister_device(ca->dvbdev);
+       kfree(ca);
+       pubca->private = NULL;
+}
diff --git a/drivers/media/dvb-core/dvb_ca_en50221.h b/drivers/media/dvb-core/dvb_ca_en50221.h
new file mode 100644 (file)
index 0000000..7df2e14
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * dvb_ca.h: generic DVB functions for EN50221 CA interfaces
+ *
+ * Copyright (C) 2004 Andrew de Quincey
+ *
+ * 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 _DVB_CA_EN50221_H_
+#define _DVB_CA_EN50221_H_
+
+#include <linux/list.h>
+#include <linux/dvb/ca.h>
+
+#include "dvbdev.h"
+
+#define DVB_CA_EN50221_POLL_CAM_PRESENT        1
+#define DVB_CA_EN50221_POLL_CAM_CHANGED        2
+#define DVB_CA_EN50221_POLL_CAM_READY          4
+
+#define DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE      1
+#define DVB_CA_EN50221_FLAG_IRQ_FR             2
+#define DVB_CA_EN50221_FLAG_IRQ_DA             4
+
+#define DVB_CA_EN50221_CAMCHANGE_REMOVED               0
+#define DVB_CA_EN50221_CAMCHANGE_INSERTED              1
+
+
+
+/* Structure describing a CA interface */
+struct dvb_ca_en50221 {
+
+       /* the module owning this structure */
+       struct module* owner;
+
+       /* NOTE: the read_*, write_* and poll_slot_status functions will be
+        * called for different slots concurrently and need to use locks where
+        * and if appropriate. There will be no concurrent access to one slot.
+        */
+
+       /* functions for accessing attribute memory on the CAM */
+       int (*read_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address);
+       int (*write_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address, u8 value);
+
+       /* functions for accessing the control interface on the CAM */
+       int (*read_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address);
+       int (*write_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address, u8 value);
+
+       /* Functions for controlling slots */
+       int (*slot_reset)(struct dvb_ca_en50221* ca, int slot);
+       int (*slot_shutdown)(struct dvb_ca_en50221* ca, int slot);
+       int (*slot_ts_enable)(struct dvb_ca_en50221* ca, int slot);
+
+       /*
+       * Poll slot status.
+       * Only necessary if DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set
+       */
+       int (*poll_slot_status)(struct dvb_ca_en50221* ca, int slot, int open);
+
+       /* private data, used by caller */
+       void* data;
+
+       /* Opaque data used by the dvb_ca core. Do not modify! */
+       void* private;
+};
+
+
+
+
+/* ******************************************************************************** */
+/* Functions for reporting IRQ events */
+
+/**
+ * A CAMCHANGE IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ * @param change_type One of the DVB_CA_CAMCHANGE_* values
+ */
+void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221* pubca, int slot, int change_type);
+
+/**
+ * A CAMREADY IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ */
+void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221* pubca, int slot);
+
+/**
+ * An FR or a DA IRQ has occurred.
+ *
+ * @param ca CA instance.
+ * @param slot Slot concerned.
+ */
+void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221* ca, int slot);
+
+
+
+/* ******************************************************************************** */
+/* Initialisation/shutdown functions */
+
+/**
+ * Initialise a new DVB CA device.
+ *
+ * @param dvb_adapter DVB adapter to attach the new CA device to.
+ * @param ca The dvb_ca instance.
+ * @param flags Flags describing the CA device (DVB_CA_EN50221_FLAG_*).
+ * @param slot_count Number of slots supported.
+ *
+ * @return 0 on success, nonzero on failure
+ */
+extern int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221* ca, int flags, int slot_count);
+
+/**
+ * Release a DVB CA device.
+ *
+ * @param ca The associated dvb_ca instance.
+ */
+extern void dvb_ca_en50221_release(struct dvb_ca_en50221* ca);
+
+
+
+#endif
diff --git a/drivers/media/dvb-core/dvb_demux.c b/drivers/media/dvb-core/dvb_demux.c
new file mode 100644 (file)
index 0000000..17cb81f
--- /dev/null
@@ -0,0 +1,1318 @@
+/*
+ * dvb_demux.c - DVB kernel demux API
+ *
+ * Copyright (C) 2000-2001 Ralph  Metzler <ralph@convergence.de>
+ *                    & Marcus Metzler <marcus@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 <linux/sched.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/string.h>
+#include <linux/crc32.h>
+#include <asm/uaccess.h>
+#include <asm/div64.h>
+
+#include "dvb_demux.h"
+
+#define NOBUFS
+/*
+** #define DVB_DEMUX_SECTION_LOSS_LOG to monitor payload loss in the syslog
+*/
+// #define DVB_DEMUX_SECTION_LOSS_LOG
+
+static int dvb_demux_tscheck;
+module_param(dvb_demux_tscheck, int, 0644);
+MODULE_PARM_DESC(dvb_demux_tscheck,
+               "enable transport stream continuity and TEI check");
+
+static int dvb_demux_speedcheck;
+module_param(dvb_demux_speedcheck, int, 0644);
+MODULE_PARM_DESC(dvb_demux_speedcheck,
+               "enable transport stream speed check");
+
+static int dvb_demux_feed_err_pkts = 1;
+module_param(dvb_demux_feed_err_pkts, int, 0644);
+MODULE_PARM_DESC(dvb_demux_feed_err_pkts,
+                "when set to 0, drop packets with the TEI bit set (1 by default)");
+
+#define dprintk_tscheck(x...) do {                              \
+               if (dvb_demux_tscheck && printk_ratelimit())    \
+                       printk(x);                              \
+       } while (0)
+
+/******************************************************************************
+ * static inlined helper functions
+ ******************************************************************************/
+
+static inline u16 section_length(const u8 *buf)
+{
+       return 3 + ((buf[1] & 0x0f) << 8) + buf[2];
+}
+
+static inline u16 ts_pid(const u8 *buf)
+{
+       return ((buf[1] & 0x1f) << 8) + buf[2];
+}
+
+static inline u8 payload(const u8 *tsp)
+{
+       if (!(tsp[3] & 0x10))   // no payload?
+               return 0;
+
+       if (tsp[3] & 0x20) {    // adaptation field?
+               if (tsp[4] > 183)       // corrupted data?
+                       return 0;
+               else
+                       return 184 - 1 - tsp[4];
+       }
+
+       return 184;
+}
+
+static u32 dvb_dmx_crc32(struct dvb_demux_feed *f, const u8 *src, size_t len)
+{
+       return (f->feed.sec.crc_val = crc32_be(f->feed.sec.crc_val, src, len));
+}
+
+static void dvb_dmx_memcopy(struct dvb_demux_feed *f, u8 *d, const u8 *s,
+                           size_t len)
+{
+       memcpy(d, s, len);
+}
+
+/******************************************************************************
+ * Software filter functions
+ ******************************************************************************/
+
+static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
+                                          const u8 *buf)
+{
+       int count = payload(buf);
+       int p;
+       //int ccok;
+       //u8 cc;
+
+       if (count == 0)
+               return -1;
+
+       p = 188 - count;
+
+       /*
+       cc = buf[3] & 0x0f;
+       ccok = ((feed->cc + 1) & 0x0f) == cc;
+       feed->cc = cc;
+       if (!ccok)
+               printk("missed packet!\n");
+       */
+
+       if (buf[1] & 0x40)      // PUSI ?
+               feed->peslen = 0xfffa;
+
+       feed->peslen += count;
+
+       return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK);
+}
+
+static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
+                                         struct dvb_demux_filter *f)
+{
+       u8 neq = 0;
+       int i;
+
+       for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
+               u8 xor = f->filter.filter_value[i] ^ feed->feed.sec.secbuf[i];
+
+               if (f->maskandmode[i] & xor)
+                       return 0;
+
+               neq |= f->maskandnotmode[i] & xor;
+       }
+
+       if (f->doneq && !neq)
+               return 0;
+
+       return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen,
+                           NULL, 0, &f->filter, DMX_OK);
+}
+
+static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
+{
+       struct dvb_demux *demux = feed->demux;
+       struct dvb_demux_filter *f = feed->filter;
+       struct dmx_section_feed *sec = &feed->feed.sec;
+       int section_syntax_indicator;
+
+       if (!sec->is_filtering)
+               return 0;
+
+       if (!f)
+               return 0;
+
+       if (sec->check_crc) {
+               section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0);
+               if (section_syntax_indicator &&
+                   demux->check_crc32(feed, sec->secbuf, sec->seclen))
+                       return -1;
+       }
+
+       do {
+               if (dvb_dmx_swfilter_sectionfilter(feed, f) < 0)
+                       return -1;
+       } while ((f = f->next) && sec->is_filtering);
+
+       sec->seclen = 0;
+
+       return 0;
+}
+
+static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
+{
+       struct dmx_section_feed *sec = &feed->feed.sec;
+
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+       if (sec->secbufp < sec->tsfeedp) {
+               int i, n = sec->tsfeedp - sec->secbufp;
+
+               /*
+                * Section padding is done with 0xff bytes entirely.
+                * Due to speed reasons, we won't check all of them
+                * but just first and last.
+                */
+               if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) {
+                       printk("dvb_demux.c section ts padding loss: %d/%d\n",
+                              n, sec->tsfeedp);
+                       printk("dvb_demux.c pad data:");
+                       for (i = 0; i < n; i++)
+                               printk(" %02x", sec->secbuf[i]);
+                       printk("\n");
+               }
+       }
+#endif
+
+       sec->tsfeedp = sec->secbufp = sec->seclen = 0;
+       sec->secbuf = sec->secbuf_base;
+}
+
+/*
+ * Losless Section Demux 1.4.1 by Emard
+ * Valsecchi Patrick:
+ *  - middle of section A  (no PUSI)
+ *  - end of section A and start of section B
+ *    (with PUSI pointing to the start of the second section)
+ *
+ *  In this case, without feed->pusi_seen you'll receive a garbage section
+ *  consisting of the end of section A. Basically because tsfeedp
+ *  is incemented and the use=0 condition is not raised
+ *  when the second packet arrives.
+ *
+ * Fix:
+ * when demux is started, let feed->pusi_seen = 0 to
+ * prevent initial feeding of garbage from the end of
+ * previous section. When you for the first time see PUSI=1
+ * then set feed->pusi_seen = 1
+ */
+static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
+                                             const u8 *buf, u8 len)
+{
+       struct dvb_demux *demux = feed->demux;
+       struct dmx_section_feed *sec = &feed->feed.sec;
+       u16 limit, seclen, n;
+
+       if (sec->tsfeedp >= DMX_MAX_SECFEED_SIZE)
+               return 0;
+
+       if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) {
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+               printk("dvb_demux.c section buffer full loss: %d/%d\n",
+                      sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE,
+                      DMX_MAX_SECFEED_SIZE);
+#endif
+               len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp;
+       }
+
+       if (len <= 0)
+               return 0;
+
+       demux->memcopy(feed, sec->secbuf_base + sec->tsfeedp, buf, len);
+       sec->tsfeedp += len;
+
+       /*
+        * Dump all the sections we can find in the data (Emard)
+        */
+       limit = sec->tsfeedp;
+       if (limit > DMX_MAX_SECFEED_SIZE)
+               return -1;      /* internal error should never happen */
+
+       /* to be sure always set secbuf */
+       sec->secbuf = sec->secbuf_base + sec->secbufp;
+
+       for (n = 0; sec->secbufp + 2 < limit; n++) {
+               seclen = section_length(sec->secbuf);
+               if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE
+                   || seclen + sec->secbufp > limit)
+                       return 0;
+               sec->seclen = seclen;
+               sec->crc_val = ~0;
+               /* dump [secbuf .. secbuf+seclen) */
+               if (feed->pusi_seen)
+                       dvb_dmx_swfilter_section_feed(feed);
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+               else
+                       printk("dvb_demux.c pusi not seen, discarding section data\n");
+#endif
+               sec->secbufp += seclen; /* secbufp and secbuf moving together is */
+               sec->secbuf += seclen;  /* redundant but saves pointer arithmetic */
+       }
+
+       return 0;
+}
+
+static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
+                                          const u8 *buf)
+{
+       u8 p, count;
+       int ccok, dc_i = 0;
+       u8 cc;
+
+       count = payload(buf);
+
+       if (count == 0)         /* count == 0 if no payload or out of range */
+               return -1;
+
+       p = 188 - count;        /* payload start */
+
+       cc = buf[3] & 0x0f;
+       ccok = ((feed->cc + 1) & 0x0f) == cc;
+       feed->cc = cc;
+
+       if (buf[3] & 0x20) {
+               /* adaption field present, check for discontinuity_indicator */
+               if ((buf[4] > 0) && (buf[5] & 0x80))
+                       dc_i = 1;
+       }
+
+       if (!ccok || dc_i) {
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+               printk("dvb_demux.c discontinuity detected %d bytes lost\n",
+                      count);
+               /*
+                * those bytes under sume circumstances will again be reported
+                * in the following dvb_dmx_swfilter_section_new
+                */
+#endif
+               /*
+                * Discontinuity detected. Reset pusi_seen = 0 to
+                * stop feeding of suspicious data until next PUSI=1 arrives
+                */
+               feed->pusi_seen = 0;
+               dvb_dmx_swfilter_section_new(feed);
+       }
+
+       if (buf[1] & 0x40) {
+               /* PUSI=1 (is set), section boundary is here */
+               if (count > 1 && buf[p] < count) {
+                       const u8 *before = &buf[p + 1];
+                       u8 before_len = buf[p];
+                       const u8 *after = &before[before_len];
+                       u8 after_len = count - 1 - before_len;
+
+                       dvb_dmx_swfilter_section_copy_dump(feed, before,
+                                                          before_len);
+                       /* before start of new section, set pusi_seen = 1 */
+                       feed->pusi_seen = 1;
+                       dvb_dmx_swfilter_section_new(feed);
+                       dvb_dmx_swfilter_section_copy_dump(feed, after,
+                                                          after_len);
+               }
+#ifdef DVB_DEMUX_SECTION_LOSS_LOG
+               else if (count > 0)
+                       printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count);
+#endif
+       } else {
+               /* PUSI=0 (is not set), no section boundary */
+               dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count);
+       }
+
+       return 0;
+}
+
+static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
+                                               const u8 *buf)
+{
+       switch (feed->type) {
+       case DMX_TYPE_TS:
+               if (!feed->feed.ts.is_filtering)
+                       break;
+               if (feed->ts_type & TS_PACKET) {
+                       if (feed->ts_type & TS_PAYLOAD_ONLY)
+                               dvb_dmx_swfilter_payload(feed, buf);
+                       else
+                               feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
+                                           DMX_OK);
+               }
+               if (feed->ts_type & TS_DECODER)
+                       if (feed->demux->write_to_decoder)
+                               feed->demux->write_to_decoder(feed, buf, 188);
+               break;
+
+       case DMX_TYPE_SEC:
+               if (!feed->feed.sec.is_filtering)
+                       break;
+               if (dvb_dmx_swfilter_section_packet(feed, buf) < 0)
+                       feed->feed.sec.seclen = feed->feed.sec.secbufp = 0;
+               break;
+
+       default:
+               break;
+       }
+}
+
+#define DVR_FEED(f)                                                    \
+       (((f)->type == DMX_TYPE_TS) &&                                  \
+       ((f)->feed.ts.is_filtering) &&                                  \
+       (((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET))
+
+static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
+{
+       struct dvb_demux_feed *feed;
+       u16 pid = ts_pid(buf);
+       int dvr_done = 0;
+
+       if (dvb_demux_speedcheck) {
+               struct timespec cur_time, delta_time;
+               u64 speed_bytes, speed_timedelta;
+
+               demux->speed_pkts_cnt++;
+
+               /* show speed every SPEED_PKTS_INTERVAL packets */
+               if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) {
+                       cur_time = current_kernel_time();
+
+                       if (demux->speed_last_time.tv_sec != 0 &&
+                                       demux->speed_last_time.tv_nsec != 0) {
+                               delta_time = timespec_sub(cur_time,
+                                               demux->speed_last_time);
+                               speed_bytes = (u64)demux->speed_pkts_cnt
+                                       * 188 * 8;
+                               /* convert to 1024 basis */
+                               speed_bytes = 1000 * div64_u64(speed_bytes,
+                                               1024);
+                               speed_timedelta =
+                                       (u64)timespec_to_ns(&delta_time);
+                               speed_timedelta = div64_u64(speed_timedelta,
+                                               1000000); /* nsec -> usec */
+                               printk(KERN_INFO "TS speed %llu Kbits/sec \n",
+                                               div64_u64(speed_bytes,
+                                                       speed_timedelta));
+                       };
+
+                       demux->speed_last_time = cur_time;
+                       demux->speed_pkts_cnt = 0;
+               };
+       };
+
+       if (buf[1] & 0x80) {
+               dprintk_tscheck("TEI detected. "
+                               "PID=0x%x data1=0x%x\n",
+                               pid, buf[1]);
+               /* data in this packet cant be trusted - drop it unless
+                * module option dvb_demux_feed_err_pkts is set */
+               if (!dvb_demux_feed_err_pkts)
+                       return;
+       } else /* if TEI bit is set, pid may be wrong- skip pkt counter */
+       if (demux->cnt_storage && dvb_demux_tscheck) {
+               /* check pkt counter */
+               if (pid < MAX_PID) {
+                       if ((buf[3] & 0xf) != demux->cnt_storage[pid])
+                               dprintk_tscheck("TS packet counter mismatch. "
+                                               "PID=0x%x expected 0x%x "
+                                               "got 0x%x\n",
+                                               pid, demux->cnt_storage[pid],
+                                               buf[3] & 0xf);
+
+                       demux->cnt_storage[pid] = ((buf[3] & 0xf) + 1)&0xf;
+               };
+               /* end check */
+       };
+
+       list_for_each_entry(feed, &demux->feed_list, list_head) {
+               if ((feed->pid != pid) && (feed->pid != 0x2000))
+                       continue;
+
+               /* copy each packet only once to the dvr device, even
+                * if a PID is in multiple filters (e.g. video + PCR) */
+               if ((DVR_FEED(feed)) && (dvr_done++))
+                       continue;
+
+               if (feed->pid == pid)
+                       dvb_dmx_swfilter_packet_type(feed, buf);
+               else if (feed->pid == 0x2000)
+                       feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
+       }
+}
+
+void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
+                             size_t count)
+{
+       spin_lock(&demux->lock);
+
+       while (count--) {
+               if (buf[0] == 0x47)
+                       dvb_dmx_swfilter_packet(demux, buf);
+               buf += 188;
+       }
+
+       spin_unlock(&demux->lock);
+}
+
+EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
+
+static inline int find_next_packet(const u8 *buf, int pos, size_t count,
+                                  const int pktsize)
+{
+       int start = pos, lost;
+
+       while (pos < count) {
+               if (buf[pos] == 0x47 ||
+                   (pktsize == 204 && buf[pos] == 0xB8))
+                       break;
+               pos++;
+       }
+
+       lost = pos - start;
+       if (lost) {
+               /* This garbage is part of a valid packet? */
+               int backtrack = pos - pktsize;
+               if (backtrack >= 0 && (buf[backtrack] == 0x47 ||
+                   (pktsize == 204 && buf[backtrack] == 0xB8)))
+                       return backtrack;
+       }
+
+       return pos;
+}
+
+/* Filter all pktsize= 188 or 204 sized packets and skip garbage. */
+static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
+               size_t count, const int pktsize)
+{
+       int p = 0, i, j;
+       const u8 *q;
+
+       spin_lock(&demux->lock);
+
+       if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
+               i = demux->tsbufp;
+               j = pktsize - i;
+               if (count < j) {
+                       memcpy(&demux->tsbuf[i], buf, count);
+                       demux->tsbufp += count;
+                       goto bailout;
+               }
+               memcpy(&demux->tsbuf[i], buf, j);
+               if (demux->tsbuf[0] == 0x47) /* double check */
+                       dvb_dmx_swfilter_packet(demux, demux->tsbuf);
+               demux->tsbufp = 0;
+               p += j;
+       }
+
+       while (1) {
+               p = find_next_packet(buf, p, count, pktsize);
+               if (p >= count)
+                       break;
+               if (count - p < pktsize)
+                       break;
+
+               q = &buf[p];
+
+               if (pktsize == 204 && (*q == 0xB8)) {
+                       memcpy(demux->tsbuf, q, 188);
+                       demux->tsbuf[0] = 0x47;
+                       q = demux->tsbuf;
+               }
+               dvb_dmx_swfilter_packet(demux, q);
+               p += pktsize;
+       }
+
+       i = count - p;
+       if (i) {
+               memcpy(demux->tsbuf, &buf[p], i);
+               demux->tsbufp = i;
+               if (pktsize == 204 && demux->tsbuf[0] == 0xB8)
+                       demux->tsbuf[0] = 0x47;
+       }
+
+bailout:
+       spin_unlock(&demux->lock);
+}
+
+void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
+{
+       _dvb_dmx_swfilter(demux, buf, count, 188);
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter);
+
+void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
+{
+       _dvb_dmx_swfilter(demux, buf, count, 204);
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter_204);
+
+void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
+{
+       spin_lock(&demux->lock);
+
+       demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts, DMX_OK);
+
+       spin_unlock(&demux->lock);
+}
+EXPORT_SYMBOL(dvb_dmx_swfilter_raw);
+
+static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux)
+{
+       int i;
+
+       for (i = 0; i < demux->filternum; i++)
+               if (demux->filter[i].state == DMX_STATE_FREE)
+                       break;
+
+       if (i == demux->filternum)
+               return NULL;
+
+       demux->filter[i].state = DMX_STATE_ALLOCATED;
+
+       return &demux->filter[i];
+}
+
+static struct dvb_demux_feed *dvb_dmx_feed_alloc(struct dvb_demux *demux)
+{
+       int i;
+
+       for (i = 0; i < demux->feednum; i++)
+               if (demux->feed[i].state == DMX_STATE_FREE)
+                       break;
+
+       if (i == demux->feednum)
+               return NULL;
+
+       demux->feed[i].state = DMX_STATE_ALLOCATED;
+
+       return &demux->feed[i];
+}
+
+static int dvb_demux_feed_find(struct dvb_demux_feed *feed)
+{
+       struct dvb_demux_feed *entry;
+
+       list_for_each_entry(entry, &feed->demux->feed_list, list_head)
+               if (entry == feed)
+                       return 1;
+
+       return 0;
+}
+
+static void dvb_demux_feed_add(struct dvb_demux_feed *feed)
+{
+       spin_lock_irq(&feed->demux->lock);
+       if (dvb_demux_feed_find(feed)) {
+               printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n",
+                      __func__, feed->type, feed->state, feed->pid);
+               goto out;
+       }
+
+       list_add(&feed->list_head, &feed->demux->feed_list);
+out:
+       spin_unlock_irq(&feed->demux->lock);
+}
+
+static void dvb_demux_feed_del(struct dvb_demux_feed *feed)
+{
+       spin_lock_irq(&feed->demux->lock);
+       if (!(dvb_demux_feed_find(feed))) {
+               printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n",
+                      __func__, feed->type, feed->state, feed->pid);
+               goto out;
+       }
+
+       list_del(&feed->list_head);
+out:
+       spin_unlock_irq(&feed->demux->lock);
+}
+
+static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type,
+                          enum dmx_ts_pes pes_type,
+                          size_t circular_buffer_size, struct timespec timeout)
+{
+       struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+       struct dvb_demux *demux = feed->demux;
+
+       if (pid > DMX_MAX_PID)
+               return -EINVAL;
+
+       if (mutex_lock_interruptible(&demux->mutex))
+               return -ERESTARTSYS;
+
+       if (ts_type & TS_DECODER) {
+               if (pes_type >= DMX_TS_PES_OTHER) {
+                       mutex_unlock(&demux->mutex);
+                       return -EINVAL;
+               }
+
+               if (demux->pesfilter[pes_type] &&
+                   demux->pesfilter[pes_type] != feed) {
+                       mutex_unlock(&demux->mutex);
+                       return -EINVAL;
+               }
+
+               demux->pesfilter[pes_type] = feed;
+               demux->pids[pes_type] = pid;
+       }
+
+       dvb_demux_feed_add(feed);
+
+       feed->pid = pid;
+       feed->buffer_size = circular_buffer_size;
+       feed->timeout = timeout;
+       feed->ts_type = ts_type;
+       feed->pes_type = pes_type;
+
+       if (feed->buffer_size) {
+#ifdef NOBUFS
+               feed->buffer = NULL;
+#else
+               feed->buffer = vmalloc(feed->buffer_size);
+               if (!feed->buffer) {
+                       mutex_unlock(&demux->mutex);
+                       return -ENOMEM;
+               }
+#endif
+       }
+
+       feed->state = DMX_STATE_READY;
+       mutex_unlock(&demux->mutex);
+
+       return 0;
+}
+
+static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed)
+{
+       struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+       struct dvb_demux *demux = feed->demux;
+       int ret;
+
+       if (mutex_lock_interruptible(&demux->mutex))
+               return -ERESTARTSYS;
+
+       if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) {
+               mutex_unlock(&demux->mutex);
+               return -EINVAL;
+       }
+
+       if (!demux->start_feed) {
+               mutex_unlock(&demux->mutex);
+               return -ENODEV;
+       }
+
+       if ((ret = demux->start_feed(feed)) < 0) {
+               mutex_unlock(&demux->mutex);
+               return ret;
+       }
+
+       spin_lock_irq(&demux->lock);
+       ts_feed->is_filtering = 1;
+       feed->state = DMX_STATE_GO;
+       spin_unlock_irq(&demux->lock);
+       mutex_unlock(&demux->mutex);
+
+       return 0;
+}
+
+static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed)
+{
+       struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+       struct dvb_demux *demux = feed->demux;
+       int ret;
+
+       mutex_lock(&demux->mutex);
+
+       if (feed->state < DMX_STATE_GO) {
+               mutex_unlock(&demux->mutex);
+               return -EINVAL;
+       }
+
+       if (!demux->stop_feed) {
+               mutex_unlock(&demux->mutex);
+               return -ENODEV;
+       }
+
+       ret = demux->stop_feed(feed);
+
+       spin_lock_irq(&demux->lock);
+       ts_feed->is_filtering = 0;
+       feed->state = DMX_STATE_ALLOCATED;
+       spin_unlock_irq(&demux->lock);
+       mutex_unlock(&demux->mutex);
+
+       return ret;
+}
+
+static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
+                                  struct dmx_ts_feed **ts_feed,
+                                  dmx_ts_cb callback)
+{
+       struct dvb_demux *demux = (struct dvb_demux *)dmx;
+       struct dvb_demux_feed *feed;
+
+       if (mutex_lock_interruptible(&demux->mutex))
+               return -ERESTARTSYS;
+
+       if (!(feed = dvb_dmx_feed_alloc(demux))) {
+               mutex_unlock(&demux->mutex);
+               return -EBUSY;
+       }
+
+       feed->type = DMX_TYPE_TS;
+       feed->cb.ts = callback;
+       feed->demux = demux;
+       feed->pid = 0xffff;
+       feed->peslen = 0xfffa;
+       feed->buffer = NULL;
+
+       (*ts_feed) = &feed->feed.ts;
+       (*ts_feed)->parent = dmx;
+       (*ts_feed)->priv = NULL;
+       (*ts_feed)->is_filtering = 0;
+       (*ts_feed)->start_filtering = dmx_ts_feed_start_filtering;
+       (*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering;
+       (*ts_feed)->set = dmx_ts_feed_set;
+
+       if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
+               feed->state = DMX_STATE_FREE;
+               mutex_unlock(&demux->mutex);
+               return -EBUSY;
+       }
+
+       feed->filter->type = DMX_TYPE_TS;
+       feed->filter->feed = feed;
+       feed->filter->state = DMX_STATE_READY;
+
+       mutex_unlock(&demux->mutex);
+
+       return 0;
+}
+
+static int dvbdmx_release_ts_feed(struct dmx_demux *dmx,
+                                 struct dmx_ts_feed *ts_feed)
+{
+       struct dvb_demux *demux = (struct dvb_demux *)dmx;
+       struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
+
+       mutex_lock(&demux->mutex);
+
+       if (feed->state == DMX_STATE_FREE) {
+               mutex_unlock(&demux->mutex);
+               return -EINVAL;
+       }
+#ifndef NOBUFS
+       vfree(feed->buffer);
+       feed->buffer = NULL;
+#endif
+
+       feed->state = DMX_STATE_FREE;
+       feed->filter->state = DMX_STATE_FREE;
+
+       dvb_demux_feed_del(feed);
+
+       feed->pid = 0xffff;
+
+       if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER)
+               demux->pesfilter[feed->pes_type] = NULL;
+
+       mutex_unlock(&demux->mutex);
+       return 0;
+}
+
+/******************************************************************************
+ * dmx_section_feed API calls
+ ******************************************************************************/
+
+static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed,
+                                           struct dmx_section_filter **filter)
+{
+       struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+       struct dvb_demux *dvbdemux = dvbdmxfeed->demux;
+       struct dvb_demux_filter *dvbdmxfilter;
+
+       if (mutex_lock_interruptible(&dvbdemux->mutex))
+               return -ERESTARTSYS;
+
+       dvbdmxfilter = dvb_dmx_filter_alloc(dvbdemux);
+       if (!dvbdmxfilter) {
+               mutex_unlock(&dvbdemux->mutex);
+               return -EBUSY;
+       }
+
+       spin_lock_irq(&dvbdemux->lock);
+       *filter = &dvbdmxfilter->filter;
+       (*filter)->parent = feed;
+       (*filter)->priv = NULL;
+       dvbdmxfilter->feed = dvbdmxfeed;
+       dvbdmxfilter->type = DMX_TYPE_SEC;
+       dvbdmxfilter->state = DMX_STATE_READY;
+       dvbdmxfilter->next = dvbdmxfeed->filter;
+       dvbdmxfeed->filter = dvbdmxfilter;
+       spin_unlock_irq(&dvbdemux->lock);
+
+       mutex_unlock(&dvbdemux->mutex);
+       return 0;
+}
+
+static int dmx_section_feed_set(struct dmx_section_feed *feed,
+                               u16 pid, size_t circular_buffer_size,
+                               int check_crc)
+{
+       struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+       struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+
+       if (pid > 0x1fff)
+               return -EINVAL;
+
+       if (mutex_lock_interruptible(&dvbdmx->mutex))
+               return -ERESTARTSYS;
+
+       dvb_demux_feed_add(dvbdmxfeed);
+
+       dvbdmxfeed->pid = pid;
+       dvbdmxfeed->buffer_size = circular_buffer_size;
+       dvbdmxfeed->feed.sec.check_crc = check_crc;
+
+#ifdef NOBUFS
+       dvbdmxfeed->buffer = NULL;
+#else
+       dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size);
+       if (!dvbdmxfeed->buffer) {
+               mutex_unlock(&dvbdmx->mutex);
+               return -ENOMEM;
+       }
+#endif
+
+       dvbdmxfeed->state = DMX_STATE_READY;
+       mutex_unlock(&dvbdmx->mutex);
+       return 0;
+}
+
+static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed)
+{
+       int i;
+       struct dvb_demux_filter *f;
+       struct dmx_section_filter *sf;
+       u8 mask, mode, doneq;
+
+       if (!(f = dvbdmxfeed->filter))
+               return;
+       do {
+               sf = &f->filter;
+               doneq = 0;
+               for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
+                       mode = sf->filter_mode[i];
+                       mask = sf->filter_mask[i];
+                       f->maskandmode[i] = mask & mode;
+                       doneq |= f->maskandnotmode[i] = mask & ~mode;
+               }
+               f->doneq = doneq ? 1 : 0;
+       } while ((f = f->next));
+}
+
+static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
+{
+       struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+       struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+       int ret;
+
+       if (mutex_lock_interruptible(&dvbdmx->mutex))
+               return -ERESTARTSYS;
+
+       if (feed->is_filtering) {
+               mutex_unlock(&dvbdmx->mutex);
+               return -EBUSY;
+       }
+
+       if (!dvbdmxfeed->filter) {
+               mutex_unlock(&dvbdmx->mutex);
+               return -EINVAL;
+       }
+
+       dvbdmxfeed->feed.sec.tsfeedp = 0;
+       dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
+       dvbdmxfeed->feed.sec.secbufp = 0;
+       dvbdmxfeed->feed.sec.seclen = 0;
+
+       if (!dvbdmx->start_feed) {
+               mutex_unlock(&dvbdmx->mutex);
+               return -ENODEV;
+       }
+
+       prepare_secfilters(dvbdmxfeed);
+
+       if ((ret = dvbdmx->start_feed(dvbdmxfeed)) < 0) {
+               mutex_unlock(&dvbdmx->mutex);
+               return ret;
+       }
+
+       spin_lock_irq(&dvbdmx->lock);
+       feed->is_filtering = 1;
+       dvbdmxfeed->state = DMX_STATE_GO;
+       spin_unlock_irq(&dvbdmx->lock);
+
+       mutex_unlock(&dvbdmx->mutex);
+       return 0;
+}
+
+static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed)
+{
+       struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+       struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+       int ret;
+
+       mutex_lock(&dvbdmx->mutex);
+
+       if (!dvbdmx->stop_feed) {
+               mutex_unlock(&dvbdmx->mutex);
+               return -ENODEV;
+       }
+
+       ret = dvbdmx->stop_feed(dvbdmxfeed);
+
+       spin_lock_irq(&dvbdmx->lock);
+       dvbdmxfeed->state = DMX_STATE_READY;
+       feed->is_filtering = 0;
+       spin_unlock_irq(&dvbdmx->lock);
+
+       mutex_unlock(&dvbdmx->mutex);
+       return ret;
+}
+
+static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
+                                          struct dmx_section_filter *filter)
+{
+       struct dvb_demux_filter *dvbdmxfilter = (struct dvb_demux_filter *)filter, *f;
+       struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+       struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+
+       mutex_lock(&dvbdmx->mutex);
+
+       if (dvbdmxfilter->feed != dvbdmxfeed) {
+               mutex_unlock(&dvbdmx->mutex);
+               return -EINVAL;
+       }
+
+       if (feed->is_filtering)
+               feed->stop_filtering(feed);
+
+       spin_lock_irq(&dvbdmx->lock);
+       f = dvbdmxfeed->filter;
+
+       if (f == dvbdmxfilter) {
+               dvbdmxfeed->filter = dvbdmxfilter->next;
+       } else {
+               while (f->next != dvbdmxfilter)
+                       f = f->next;
+               f->next = f->next->next;
+       }
+
+       dvbdmxfilter->state = DMX_STATE_FREE;
+       spin_unlock_irq(&dvbdmx->lock);
+       mutex_unlock(&dvbdmx->mutex);
+       return 0;
+}
+
+static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
+                                       struct dmx_section_feed **feed,
+                                       dmx_section_cb callback)
+{
+       struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
+       struct dvb_demux_feed *dvbdmxfeed;
+
+       if (mutex_lock_interruptible(&dvbdmx->mutex))
+               return -ERESTARTSYS;
+
+       if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) {
+               mutex_unlock(&dvbdmx->mutex);
+               return -EBUSY;
+       }
+
+       dvbdmxfeed->type = DMX_TYPE_SEC;
+       dvbdmxfeed->cb.sec = callback;
+       dvbdmxfeed->demux = dvbdmx;
+       dvbdmxfeed->pid = 0xffff;
+       dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
+       dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0;
+       dvbdmxfeed->feed.sec.tsfeedp = 0;
+       dvbdmxfeed->filter = NULL;
+       dvbdmxfeed->buffer = NULL;
+
+       (*feed) = &dvbdmxfeed->feed.sec;
+       (*feed)->is_filtering = 0;
+       (*feed)->parent = demux;
+       (*feed)->priv = NULL;
+
+       (*feed)->set = dmx_section_feed_set;
+       (*feed)->allocate_filter = dmx_section_feed_allocate_filter;
+       (*feed)->start_filtering = dmx_section_feed_start_filtering;
+       (*feed)->stop_filtering = dmx_section_feed_stop_filtering;
+       (*feed)->release_filter = dmx_section_feed_release_filter;
+
+       mutex_unlock(&dvbdmx->mutex);
+       return 0;
+}
+
+static int dvbdmx_release_section_feed(struct dmx_demux *demux,
+                                      struct dmx_section_feed *feed)
+{
+       struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
+       struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
+
+       mutex_lock(&dvbdmx->mutex);
+
+       if (dvbdmxfeed->state == DMX_STATE_FREE) {
+               mutex_unlock(&dvbdmx->mutex);
+               return -EINVAL;
+       }
+#ifndef NOBUFS
+       vfree(dvbdmxfeed->buffer);
+       dvbdmxfeed->buffer = NULL;
+#endif
+       dvbdmxfeed->state = DMX_STATE_FREE;
+
+       dvb_demux_feed_del(dvbdmxfeed);
+
+       dvbdmxfeed->pid = 0xffff;
+
+       mutex_unlock(&dvbdmx->mutex);
+       return 0;
+}
+
+/******************************************************************************
+ * dvb_demux kernel data API calls
+ ******************************************************************************/
+
+static int dvbdmx_open(struct dmx_demux *demux)
+{
+       struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+       if (dvbdemux->users >= MAX_DVB_DEMUX_USERS)
+               return -EUSERS;
+
+       dvbdemux->users++;
+       return 0;
+}
+
+static int dvbdmx_close(struct dmx_demux *demux)
+{
+       struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+       if (dvbdemux->users == 0)
+               return -ENODEV;
+
+       dvbdemux->users--;
+       //FIXME: release any unneeded resources if users==0
+       return 0;
+}
+
+static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count)
+{
+       struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+       void *p;
+
+       if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
+               return -EINVAL;
+
+       p = memdup_user(buf, count);
+       if (IS_ERR(p))
+               return PTR_ERR(p);
+       if (mutex_lock_interruptible(&dvbdemux->mutex)) {
+               kfree(p);
+               return -ERESTARTSYS;
+       }
+       dvb_dmx_swfilter(dvbdemux, p, count);
+       kfree(p);
+       mutex_unlock(&dvbdemux->mutex);
+
+       if (signal_pending(current))
+               return -EINTR;
+       return count;
+}
+
+static int dvbdmx_add_frontend(struct dmx_demux *demux,
+                              struct dmx_frontend *frontend)
+{
+       struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+       struct list_head *head = &dvbdemux->frontend_list;
+
+       list_add(&(frontend->connectivity_list), head);
+
+       return 0;
+}
+
+static int dvbdmx_remove_frontend(struct dmx_demux *demux,
+                                 struct dmx_frontend *frontend)
+{
+       struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+       struct list_head *pos, *n, *head = &dvbdemux->frontend_list;
+
+       list_for_each_safe(pos, n, head) {
+               if (DMX_FE_ENTRY(pos) == frontend) {
+                       list_del(pos);
+                       return 0;
+               }
+       }
+
+       return -ENODEV;
+}
+
+static struct list_head *dvbdmx_get_frontends(struct dmx_demux *demux)
+{
+       struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+       if (list_empty(&dvbdemux->frontend_list))
+               return NULL;
+
+       return &dvbdemux->frontend_list;
+}
+
+static int dvbdmx_connect_frontend(struct dmx_demux *demux,
+                                  struct dmx_frontend *frontend)
+{
+       struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+       if (demux->frontend)
+               return -EINVAL;
+
+       mutex_lock(&dvbdemux->mutex);
+
+       demux->frontend = frontend;
+       mutex_unlock(&dvbdemux->mutex);
+       return 0;
+}
+
+static int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
+{
+       struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+       mutex_lock(&dvbdemux->mutex);
+
+       demux->frontend = NULL;
+       mutex_unlock(&dvbdemux->mutex);
+       return 0;
+}
+
+static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 * pids)
+{
+       struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
+
+       memcpy(pids, dvbdemux->pids, 5 * sizeof(u16));
+       return 0;
+}
+
+int dvb_dmx_init(struct dvb_demux *dvbdemux)
+{
+       int i;
+       struct dmx_demux *dmx = &dvbdemux->dmx;
+
+       dvbdemux->cnt_storage = NULL;
+       dvbdemux->users = 0;
+       dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter));
+
+       if (!dvbdemux->filter)
+               return -ENOMEM;
+
+       dvbdemux->feed = vmalloc(dvbdemux->feednum * sizeof(struct dvb_demux_feed));
+       if (!dvbdemux->feed) {
+               vfree(dvbdemux->filter);
+               dvbdemux->filter = NULL;
+               return -ENOMEM;
+       }
+       for (i = 0; i < dvbdemux->filternum; i++) {
+               dvbdemux->filter[i].state = DMX_STATE_FREE;
+               dvbdemux->filter[i].index = i;
+       }
+       for (i = 0; i < dvbdemux->feednum; i++) {
+               dvbdemux->feed[i].state = DMX_STATE_FREE;
+               dvbdemux->feed[i].index = i;
+       }
+
+       dvbdemux->cnt_storage = vmalloc(MAX_PID + 1);
+       if (!dvbdemux->cnt_storage)
+               printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n");
+
+       INIT_LIST_HEAD(&dvbdemux->frontend_list);
+
+       for (i = 0; i < DMX_TS_PES_OTHER; i++) {
+               dvbdemux->pesfilter[i] = NULL;
+               dvbdemux->pids[i] = 0xffff;
+       }
+
+       INIT_LIST_HEAD(&dvbdemux->feed_list);
+
+       dvbdemux->playing = 0;
+       dvbdemux->recording = 0;
+       dvbdemux->tsbufp = 0;
+
+       if (!dvbdemux->check_crc32)
+               dvbdemux->check_crc32 = dvb_dmx_crc32;
+
+       if (!dvbdemux->memcopy)
+               dvbdemux->memcopy = dvb_dmx_memcopy;
+
+       dmx->frontend = NULL;
+       dmx->priv = dvbdemux;
+       dmx->open = dvbdmx_open;
+       dmx->close = dvbdmx_close;
+       dmx->write = dvbdmx_write;
+       dmx->allocate_ts_feed = dvbdmx_allocate_ts_feed;
+       dmx->release_ts_feed = dvbdmx_release_ts_feed;
+       dmx->allocate_section_feed = dvbdmx_allocate_section_feed;
+       dmx->release_section_feed = dvbdmx_release_section_feed;
+
+       dmx->add_frontend = dvbdmx_add_frontend;
+       dmx->remove_frontend = dvbdmx_remove_frontend;
+       dmx->get_frontends = dvbdmx_get_frontends;
+       dmx->connect_frontend = dvbdmx_connect_frontend;
+       dmx->disconnect_frontend = dvbdmx_disconnect_frontend;
+       dmx->get_pes_pids = dvbdmx_get_pes_pids;
+
+       mutex_init(&dvbdemux->mutex);
+       spin_lock_init(&dvbdemux->lock);
+
+       return 0;
+}
+
+EXPORT_SYMBOL(dvb_dmx_init);
+
+void dvb_dmx_release(struct dvb_demux *dvbdemux)
+{
+       vfree(dvbdemux->cnt_storage);
+       vfree(dvbdemux->filter);
+       vfree(dvbdemux->feed);
+}
+
+EXPORT_SYMBOL(dvb_dmx_release);
diff --git a/drivers/media/dvb-core/dvb_demux.h b/drivers/media/dvb-core/dvb_demux.h
new file mode 100644 (file)
index 0000000..fa7188a
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * dvb_demux.h: DVB kernel demux API
+ *
+ * Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler
+ *                         for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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 _DVB_DEMUX_H_
+#define _DVB_DEMUX_H_
+
+#include <linux/time.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+
+#include "demux.h"
+
+#define DMX_TYPE_TS  0
+#define DMX_TYPE_SEC 1
+#define DMX_TYPE_PES 2
+
+#define DMX_STATE_FREE      0
+#define DMX_STATE_ALLOCATED 1
+#define DMX_STATE_SET       2
+#define DMX_STATE_READY     3
+#define DMX_STATE_GO        4
+
+#define DVB_DEMUX_MASK_MAX 18
+
+#define MAX_PID 0x1fff
+
+#define SPEED_PKTS_INTERVAL 50000
+
+struct dvb_demux_filter {
+       struct dmx_section_filter filter;
+       u8 maskandmode[DMX_MAX_FILTER_SIZE];
+       u8 maskandnotmode[DMX_MAX_FILTER_SIZE];
+       int doneq;
+
+       struct dvb_demux_filter *next;
+       struct dvb_demux_feed *feed;
+       int index;
+       int state;
+       int type;
+
+       u16 hw_handle;
+       struct timer_list timer;
+};
+
+#define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head)
+
+struct dvb_demux_feed {
+       union {
+               struct dmx_ts_feed ts;
+               struct dmx_section_feed sec;
+       } feed;
+
+       union {
+               dmx_ts_cb ts;
+               dmx_section_cb sec;
+       } cb;
+
+       struct dvb_demux *demux;
+       void *priv;
+       int type;
+       int state;
+       u16 pid;
+       u8 *buffer;
+       int buffer_size;
+
+       struct timespec timeout;
+       struct dvb_demux_filter *filter;
+
+       int ts_type;
+       enum dmx_ts_pes pes_type;
+
+       int cc;
+       int pusi_seen;          /* prevents feeding of garbage from previous section */
+
+       u16 peslen;
+
+       struct list_head list_head;
+       unsigned int index;     /* a unique index for each feed (can be used as hardware pid filter index) */
+};
+
+struct dvb_demux {
+       struct dmx_demux dmx;
+       void *priv;
+       int filternum;
+       int feednum;
+       int (*start_feed)(struct dvb_demux_feed *feed);
+       int (*stop_feed)(struct dvb_demux_feed *feed);
+       int (*write_to_decoder)(struct dvb_demux_feed *feed,
+                                const u8 *buf, size_t len);
+       u32 (*check_crc32)(struct dvb_demux_feed *feed,
+                           const u8 *buf, size_t len);
+       void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst,
+                        const u8 *src, size_t len);
+
+       int users;
+#define MAX_DVB_DEMUX_USERS 10
+       struct dvb_demux_filter *filter;
+       struct dvb_demux_feed *feed;
+
+       struct list_head frontend_list;
+
+       struct dvb_demux_feed *pesfilter[DMX_TS_PES_OTHER];
+       u16 pids[DMX_TS_PES_OTHER];
+       int playing;
+       int recording;
+
+#define DMX_MAX_PID 0x2000
+       struct list_head feed_list;
+       u8 tsbuf[204];
+       int tsbufp;
+
+       struct mutex mutex;
+       spinlock_t lock;
+
+       uint8_t *cnt_storage; /* for TS continuity check */
+
+       struct timespec speed_last_time; /* for TS speed check */
+       uint32_t speed_pkts_cnt; /* for TS speed check */
+};
+
+int dvb_dmx_init(struct dvb_demux *dvbdemux);
+void dvb_dmx_release(struct dvb_demux *dvbdemux);
+void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf,
+                             size_t count);
+void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
+void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf,
+                         size_t count);
+void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf,
+                         size_t count);
+
+#endif /* _DVB_DEMUX_H_ */
diff --git a/drivers/media/dvb-core/dvb_filter.c b/drivers/media/dvb-core/dvb_filter.c
new file mode 100644 (file)
index 0000000..772003f
--- /dev/null
@@ -0,0 +1,603 @@
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include "dvb_filter.h"
+
+#if 0
+static unsigned int bitrates[3][16] =
+{{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0},
+ {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0},
+ {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}};
+#endif
+
+static u32 freq[4] = {480, 441, 320, 0};
+
+static unsigned int ac3_bitrates[32] =
+    {32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640,
+     0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+static u32 ac3_frames[3][32] =
+    {{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024,
+      1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0},
+     {69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114,
+      1253,1393,0,0,0,0,0,0,0,0,0,0,0,0,0},
+     {96,120,144,168,192,240,288,336,384,480,576,672,768,960,1152,1344,
+      1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+
+
+
+#if 0
+static void setup_ts2pes(ipack *pa, ipack *pv, u16 *pida, u16 *pidv,
+                 void (*pes_write)(u8 *buf, int count, void *data),
+                 void *priv)
+{
+       dvb_filter_ipack_init(pa, IPACKS, pes_write);
+       dvb_filter_ipack_init(pv, IPACKS, pes_write);
+       pa->pid = pida;
+       pv->pid = pidv;
+       pa->data = priv;
+       pv->data = priv;
+}
+#endif
+
+#if 0
+static void ts_to_pes(ipack *p, u8 *buf) // don't need count (=188)
+{
+       u8 off = 0;
+
+       if (!buf || !p ){
+               printk("NULL POINTER IDIOT\n");
+               return;
+       }
+       if (buf[1]&PAY_START) {
+               if (p->plength == MMAX_PLENGTH-6 && p->found>6){
+                       p->plength = p->found-6;
+                       p->found = 0;
+                       send_ipack(p);
+                       dvb_filter_ipack_reset(p);
+               }
+       }
+       if (buf[3] & ADAPT_FIELD) {  // adaptation field?
+               off = buf[4] + 1;
+               if (off+4 > 187) return;
+       }
+       dvb_filter_instant_repack(buf+4+off, TS_SIZE-4-off, p);
+}
+#endif
+
+#if 0
+/* needs 5 byte input, returns picture coding type*/
+static int read_picture_header(u8 *headr, struct mpg_picture *pic, int field, int pr)
+{
+       u8 pct;
+
+       if (pr) printk( "Pic header: ");
+       pic->temporal_reference[field] = (( headr[0] << 2 ) |
+                                         (headr[1] & 0x03) )& 0x03ff;
+       if (pr) printk( " temp ref: 0x%04x", pic->temporal_reference[field]);
+
+       pct = ( headr[1] >> 2 ) & 0x07;
+       pic->picture_coding_type[field] = pct;
+       if (pr) {
+               switch(pct){
+                       case I_FRAME:
+                               printk( "  I-FRAME");
+                               break;
+                       case B_FRAME:
+                               printk( "  B-FRAME");
+                               break;
+                       case P_FRAME:
+                               printk( "  P-FRAME");
+                               break;
+               }
+       }
+
+
+       pic->vinfo.vbv_delay  = (( headr[1] >> 5 ) | ( headr[2] << 3) |
+                                ( (headr[3] & 0x1F) << 11) ) & 0xffff;
+
+       if (pr) printk( " vbv delay: 0x%04x", pic->vinfo.vbv_delay);
+
+       pic->picture_header_parameter = ( headr[3] & 0xe0 ) |
+               ((headr[4] & 0x80) >> 3);
+
+       if ( pct == B_FRAME ){
+               pic->picture_header_parameter |= ( headr[4] >> 3 ) & 0x0f;
+       }
+       if (pr) printk( " pic head param: 0x%x",
+                       pic->picture_header_parameter);
+
+       return pct;
+}
+#endif
+
+#if 0
+/* needs 4 byte input */
+static int read_gop_header(u8 *headr, struct mpg_picture *pic, int pr)
+{
+       if (pr) printk("GOP header: ");
+
+       pic->time_code  = (( headr[0] << 17 ) | ( headr[1] << 9) |
+                          ( headr[2] << 1 ) | (headr[3] &0x01)) & 0x1ffffff;
+
+       if (pr) printk(" time: %d:%d.%d ", (headr[0]>>2)& 0x1F,
+                      ((headr[0]<<4)& 0x30)| ((headr[1]>>4)& 0x0F),
+                      ((headr[1]<<3)& 0x38)| ((headr[2]>>5)& 0x0F));
+
+       if ( ( headr[3] & 0x40 ) != 0 ){
+               pic->closed_gop = 1;
+       } else {
+               pic->closed_gop = 0;
+       }
+       if (pr) printk("closed: %d", pic->closed_gop);
+
+       if ( ( headr[3] & 0x20 ) != 0 ){
+               pic->broken_link = 1;
+       } else {
+               pic->broken_link = 0;
+       }
+       if (pr) printk(" broken: %d\n", pic->broken_link);
+
+       return 0;
+}
+#endif
+
+#if 0
+/* needs 8 byte input */
+static int read_sequence_header(u8 *headr, struct dvb_video_info *vi, int pr)
+{
+       int sw;
+       int form = -1;
+
+       if (pr) printk("Reading sequence header\n");
+
+       vi->horizontal_size     = ((headr[1] &0xF0) >> 4) | (headr[0] << 4);
+       vi->vertical_size       = ((headr[1] &0x0F) << 8) | (headr[2]);
+
+       sw = (int)((headr[3]&0xF0) >> 4) ;
+
+       switch( sw ){
+       case 1:
+               if (pr)
+                       printk("Videostream: ASPECT: 1:1");
+               vi->aspect_ratio = 100;
+               break;
+       case 2:
+               if (pr)
+                       printk("Videostream: ASPECT: 4:3");
+               vi->aspect_ratio = 133;
+               break;
+       case 3:
+               if (pr)
+                       printk("Videostream: ASPECT: 16:9");
+               vi->aspect_ratio = 177;
+               break;
+       case 4:
+               if (pr)
+                       printk("Videostream: ASPECT: 2.21:1");
+               vi->aspect_ratio = 221;
+               break;
+
+       case 5 ... 15:
+               if (pr)
+                       printk("Videostream: ASPECT: reserved");
+               vi->aspect_ratio = 0;
+               break;
+
+       default:
+               vi->aspect_ratio = 0;
+               return -1;
+       }
+
+       if (pr)
+               printk("  Size = %dx%d",vi->horizontal_size,vi->vertical_size);
+
+       sw = (int)(headr[3]&0x0F);
+
+       switch ( sw ) {
+       case 1:
+               if (pr)
+                       printk("  FRate: 23.976 fps");
+               vi->framerate = 23976;
+               form = -1;
+               break;
+       case 2:
+               if (pr)
+                       printk("  FRate: 24 fps");
+               vi->framerate = 24000;
+               form = -1;
+               break;
+       case 3:
+               if (pr)
+                       printk("  FRate: 25 fps");
+               vi->framerate = 25000;
+               form = VIDEO_MODE_PAL;
+               break;
+       case 4:
+               if (pr)
+                       printk("  FRate: 29.97 fps");
+               vi->framerate = 29970;
+               form = VIDEO_MODE_NTSC;
+               break;
+       case 5:
+               if (pr)
+                       printk("  FRate: 30 fps");
+               vi->framerate = 30000;
+               form = VIDEO_MODE_NTSC;
+               break;
+       case 6:
+               if (pr)
+                       printk("  FRate: 50 fps");
+               vi->framerate = 50000;
+               form = VIDEO_MODE_PAL;
+               break;
+       case 7:
+               if (pr)
+                       printk("  FRate: 60 fps");
+               vi->framerate = 60000;
+               form = VIDEO_MODE_NTSC;
+               break;
+       }
+
+       vi->bit_rate = (headr[4] << 10) | (headr[5] << 2) | (headr[6] & 0x03);
+
+       vi->vbv_buffer_size
+               = (( headr[6] & 0xF8) >> 3 ) | (( headr[7] & 0x1F )<< 5);
+
+       if (pr){
+               printk("  BRate: %d Mbit/s",4*(vi->bit_rate)/10000);
+               printk("  vbvbuffer %d",16*1024*(vi->vbv_buffer_size));
+               printk("\n");
+       }
+
+       vi->video_format = form;
+
+       return 0;
+}
+#endif
+
+
+#if 0
+static int get_vinfo(u8 *mbuf, int count, struct dvb_video_info *vi, int pr)
+{
+       u8 *headr;
+       int found = 0;
+       int c = 0;
+
+       while (found < 4 && c+4 < count){
+               u8 *b;
+
+               b = mbuf+c;
+               if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01
+                    && b[3] == 0xb3) found = 4;
+               else {
+                       c++;
+               }
+       }
+
+       if (! found) return -1;
+       c += 4;
+       if (c+12 >= count) return -1;
+       headr = mbuf+c;
+       if (read_sequence_header(headr, vi, pr) < 0) return -1;
+       vi->off = c-4;
+       return 0;
+}
+#endif
+
+
+#if 0
+static int get_ainfo(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr)
+{
+       u8 *headr;
+       int found = 0;
+       int c = 0;
+       int fr = 0;
+
+       while (found < 2 && c < count){
+               u8 b[2];
+               memcpy( b, mbuf+c, 2);
+
+               if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8)
+                       found = 2;
+               else {
+                       c++;
+               }
+       }
+
+       if (!found) return -1;
+
+       if (c+3 >= count) return -1;
+       headr = mbuf+c;
+
+       ai->layer = (headr[1] & 0x06) >> 1;
+
+       if (pr)
+               printk("Audiostream: Layer: %d", 4-ai->layer);
+
+
+       ai->bit_rate = bitrates[(3-ai->layer)][(headr[2] >> 4 )]*1000;
+
+       if (pr){
+               if (ai->bit_rate == 0)
+                       printk("  Bit rate: free");
+               else if (ai->bit_rate == 0xf)
+                       printk("  BRate: reserved");
+               else
+                       printk("  BRate: %d kb/s", ai->bit_rate/1000);
+       }
+
+       fr = (headr[2] & 0x0c ) >> 2;
+       ai->frequency = freq[fr]*100;
+       if (pr){
+               if (ai->frequency == 3)
+                       printk("  Freq: reserved\n");
+               else
+                       printk("  Freq: %d kHz\n",ai->frequency);
+
+       }
+       ai->off = c;
+       return 0;
+}
+#endif
+
+
+int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr)
+{
+       u8 *headr;
+       int found = 0;
+       int c = 0;
+       u8 frame = 0;
+       int fr = 0;
+
+       while ( !found  && c < count){
+               u8 *b = mbuf+c;
+
+               if ( b[0] == 0x0b &&  b[1] == 0x77 )
+                       found = 1;
+               else {
+                       c++;
+               }
+       }
+
+       if (!found) return -1;
+       if (pr)
+               printk("Audiostream: AC3");
+
+       ai->off = c;
+       if (c+5 >= count) return -1;
+
+       ai->layer = 0;  // 0 for AC3
+       headr = mbuf+c+2;
+
+       frame = (headr[2]&0x3f);
+       ai->bit_rate = ac3_bitrates[frame >> 1]*1000;
+
+       if (pr)
+               printk("  BRate: %d kb/s", (int) ai->bit_rate/1000);
+
+       ai->frequency = (headr[2] & 0xc0 ) >> 6;
+       fr = (headr[2] & 0xc0 ) >> 6;
+       ai->frequency = freq[fr]*100;
+       if (pr) printk ("  Freq: %d Hz\n", (int) ai->frequency);
+
+
+       ai->framesize = ac3_frames[fr][frame >> 1];
+       if ((frame & 1) &&  (fr == 1)) ai->framesize++;
+       ai->framesize = ai->framesize << 1;
+       if (pr) printk ("  Framesize %d\n",(int) ai->framesize);
+
+
+       return 0;
+}
+EXPORT_SYMBOL(dvb_filter_get_ac3info);
+
+
+#if 0
+static u8 *skip_pes_header(u8 **bufp)
+{
+       u8 *inbuf = *bufp;
+       u8 *buf = inbuf;
+       u8 *pts = NULL;
+       int skip = 0;
+
+       static const int mpeg1_skip_table[16] = {
+               1, 0xffff,      5,     10, 0xffff, 0xffff, 0xffff, 0xffff,
+               0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
+       };
+
+
+       if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */
+               if (buf[7] & PTS_ONLY)
+                       pts = buf+9;
+               else pts = NULL;
+               buf = inbuf + 9 + inbuf[8];
+       } else {        /* mpeg1 */
+               for (buf = inbuf + 6; *buf == 0xff; buf++)
+                       if (buf == inbuf + 6 + 16) {
+                               break;
+                       }
+               if ((*buf & 0xc0) == 0x40)
+                       buf += 2;
+               skip = mpeg1_skip_table [*buf >> 4];
+               if (skip == 5 || skip == 10) pts = buf;
+               else pts = NULL;
+
+               buf += mpeg1_skip_table [*buf >> 4];
+       }
+
+       *bufp = buf;
+       return pts;
+}
+#endif
+
+#if 0
+static void initialize_quant_matrix( u32 *matrix )
+{
+       int i;
+
+       matrix[0]  = 0x08101013;
+       matrix[1]  = 0x10131616;
+       matrix[2]  = 0x16161616;
+       matrix[3]  = 0x1a181a1b;
+       matrix[4]  = 0x1b1b1a1a;
+       matrix[5]  = 0x1a1a1b1b;
+       matrix[6]  = 0x1b1d1d1d;
+       matrix[7]  = 0x2222221d;
+       matrix[8]  = 0x1d1d1b1b;
+       matrix[9]  = 0x1d1d2020;
+       matrix[10] = 0x22222526;
+       matrix[11] = 0x25232322;
+       matrix[12] = 0x23262628;
+       matrix[13] = 0x28283030;
+       matrix[14] = 0x2e2e3838;
+       matrix[15] = 0x3a454553;
+
+       for ( i = 16 ; i < 32 ; i++ )
+               matrix[i] = 0x10101010;
+}
+#endif
+
+#if 0
+static void initialize_mpg_picture(struct mpg_picture *pic)
+{
+       int i;
+
+       /* set MPEG1 */
+       pic->mpeg1_flag = 1;
+       pic->profile_and_level = 0x4A ;        /* MP@LL */
+       pic->progressive_sequence = 1;
+       pic->low_delay = 0;
+
+       pic->sequence_display_extension_flag = 0;
+       for ( i = 0 ; i < 4 ; i++ ){
+               pic->frame_centre_horizontal_offset[i] = 0;
+               pic->frame_centre_vertical_offset[i] = 0;
+       }
+       pic->last_frame_centre_horizontal_offset = 0;
+       pic->last_frame_centre_vertical_offset = 0;
+
+       pic->picture_display_extension_flag[0] = 0;
+       pic->picture_display_extension_flag[1] = 0;
+       pic->sequence_header_flag = 0;
+       pic->gop_flag = 0;
+       pic->sequence_end_flag = 0;
+}
+#endif
+
+#if 0
+static void mpg_set_picture_parameter( int32_t field_type, struct mpg_picture *pic )
+{
+       int16_t last_h_offset;
+       int16_t last_v_offset;
+
+       int16_t *p_h_offset;
+       int16_t *p_v_offset;
+
+       if ( pic->mpeg1_flag ){
+               pic->picture_structure[field_type] = VIDEO_FRAME_PICTURE;
+               pic->top_field_first = 0;
+               pic->repeat_first_field = 0;
+               pic->progressive_frame = 1;
+               pic->picture_coding_parameter = 0x000010;
+       }
+
+       /* Reset flag */
+       pic->picture_display_extension_flag[field_type] = 0;
+
+       last_h_offset = pic->last_frame_centre_horizontal_offset;
+       last_v_offset = pic->last_frame_centre_vertical_offset;
+       if ( field_type == FIRST_FIELD ){
+               p_h_offset = pic->frame_centre_horizontal_offset;
+               p_v_offset = pic->frame_centre_vertical_offset;
+               *p_h_offset = last_h_offset;
+               *(p_h_offset + 1) = last_h_offset;
+               *(p_h_offset + 2) = last_h_offset;
+               *p_v_offset = last_v_offset;
+               *(p_v_offset + 1) = last_v_offset;
+               *(p_v_offset + 2) = last_v_offset;
+       } else {
+               pic->frame_centre_horizontal_offset[3] = last_h_offset;
+               pic->frame_centre_vertical_offset[3] = last_v_offset;
+       }
+}
+#endif
+
+#if 0
+static void init_mpg_picture( struct mpg_picture *pic, int chan, int32_t field_type)
+{
+       pic->picture_header = 0;
+       pic->sequence_header_data
+               = ( INIT_HORIZONTAL_SIZE << 20 )
+                       | ( INIT_VERTICAL_SIZE << 8 )
+                       | ( INIT_ASPECT_RATIO << 4 )
+                       | ( INIT_FRAME_RATE );
+       pic->mpeg1_flag = 0;
+       pic->vinfo.horizontal_size
+               = INIT_DISP_HORIZONTAL_SIZE;
+       pic->vinfo.vertical_size
+               = INIT_DISP_VERTICAL_SIZE;
+       pic->picture_display_extension_flag[field_type]
+               = 0;
+       pic->pts_flag[field_type] = 0;
+
+       pic->sequence_gop_header = 0;
+       pic->picture_header = 0;
+       pic->sequence_header_flag = 0;
+       pic->gop_flag = 0;
+       pic->sequence_end_flag = 0;
+       pic->sequence_display_extension_flag = 0;
+       pic->last_frame_centre_horizontal_offset = 0;
+       pic->last_frame_centre_vertical_offset = 0;
+       pic->channel = chan;
+}
+#endif
+
+void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
+                           dvb_filter_pes2ts_cb_t *cb, void *priv)
+{
+       unsigned char *buf=p2ts->buf;
+
+       buf[0]=0x47;
+       buf[1]=(pid>>8);
+       buf[2]=pid&0xff;
+       p2ts->cc=0;
+       p2ts->cb=cb;
+       p2ts->priv=priv;
+}
+EXPORT_SYMBOL(dvb_filter_pes2ts_init);
+
+int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
+                     int len, int payload_start)
+{
+       unsigned char *buf=p2ts->buf;
+       int ret=0, rest;
+
+       //len=6+((pes[4]<<8)|pes[5]);
+
+       if (payload_start)
+               buf[1]|=0x40;
+       else
+               buf[1]&=~0x40;
+       while (len>=184) {
+               buf[3]=0x10|((p2ts->cc++)&0x0f);
+               memcpy(buf+4, pes, 184);
+               if ((ret=p2ts->cb(p2ts->priv, buf)))
+                       return ret;
+               len-=184; pes+=184;
+               buf[1]&=~0x40;
+       }
+       if (!len)
+               return 0;
+       buf[3]=0x30|((p2ts->cc++)&0x0f);
+       rest=183-len;
+       if (rest) {
+               buf[5]=0x00;
+               if (rest-1)
+                       memset(buf+6, 0xff, rest-1);
+       }
+       buf[4]=rest;
+       memcpy(buf+5+rest, pes, len);
+       return p2ts->cb(p2ts->priv, buf);
+}
+EXPORT_SYMBOL(dvb_filter_pes2ts);
diff --git a/drivers/media/dvb-core/dvb_filter.h b/drivers/media/dvb-core/dvb_filter.h
new file mode 100644 (file)
index 0000000..375e3be
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * dvb_filter.h
+ *
+ * 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.
+ */
+
+#ifndef _DVB_FILTER_H_
+#define _DVB_FILTER_H_
+
+#include <linux/slab.h>
+
+#include "demux.h"
+
+typedef int (dvb_filter_pes2ts_cb_t) (void *, unsigned char *);
+
+struct dvb_filter_pes2ts {
+       unsigned char buf[188];
+       unsigned char cc;
+       dvb_filter_pes2ts_cb_t *cb;
+       void *priv;
+};
+
+void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
+                           dvb_filter_pes2ts_cb_t *cb, void *priv);
+
+int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
+                     int len, int payload_start);
+
+
+#define PROG_STREAM_MAP  0xBC
+#define PRIVATE_STREAM1  0xBD
+#define PADDING_STREAM   0xBE
+#define PRIVATE_STREAM2  0xBF
+#define AUDIO_STREAM_S   0xC0
+#define AUDIO_STREAM_E   0xDF
+#define VIDEO_STREAM_S   0xE0
+#define VIDEO_STREAM_E   0xEF
+#define ECM_STREAM       0xF0
+#define EMM_STREAM       0xF1
+#define DSM_CC_STREAM    0xF2
+#define ISO13522_STREAM  0xF3
+#define PROG_STREAM_DIR  0xFF
+
+#define DVB_PICTURE_START    0x00
+#define DVB_USER_START       0xb2
+#define DVB_SEQUENCE_HEADER  0xb3
+#define DVB_SEQUENCE_ERROR   0xb4
+#define DVB_EXTENSION_START  0xb5
+#define DVB_SEQUENCE_END     0xb7
+#define DVB_GOP_START        0xb8
+#define DVB_EXCEPT_SLICE     0xb0
+
+#define SEQUENCE_EXTENSION           0x01
+#define SEQUENCE_DISPLAY_EXTENSION   0x02
+#define PICTURE_CODING_EXTENSION     0x08
+#define QUANT_MATRIX_EXTENSION       0x03
+#define PICTURE_DISPLAY_EXTENSION    0x07
+
+#define I_FRAME 0x01
+#define B_FRAME 0x02
+#define P_FRAME 0x03
+
+/* Initialize sequence_data */
+#define INIT_HORIZONTAL_SIZE        720
+#define INIT_VERTICAL_SIZE          576
+#define INIT_ASPECT_RATIO          0x02
+#define INIT_FRAME_RATE            0x03
+#define INIT_DISP_HORIZONTAL_SIZE   540
+#define INIT_DISP_VERTICAL_SIZE     576
+
+
+//flags2
+#define PTS_DTS_FLAGS    0xC0
+#define ESCR_FLAG        0x20
+#define ES_RATE_FLAG     0x10
+#define DSM_TRICK_FLAG   0x08
+#define ADD_CPY_FLAG     0x04
+#define PES_CRC_FLAG     0x02
+#define PES_EXT_FLAG     0x01
+
+//pts_dts flags
+#define PTS_ONLY         0x80
+#define PTS_DTS          0xC0
+
+#define TS_SIZE        188
+#define TRANS_ERROR    0x80
+#define PAY_START      0x40
+#define TRANS_PRIO     0x20
+#define PID_MASK_HI    0x1F
+//flags
+#define TRANS_SCRMBL1  0x80
+#define TRANS_SCRMBL2  0x40
+#define ADAPT_FIELD    0x20
+#define PAYLOAD        0x10
+#define COUNT_MASK     0x0F
+
+// adaptation flags
+#define DISCON_IND     0x80
+#define RAND_ACC_IND   0x40
+#define ES_PRI_IND     0x20
+#define PCR_FLAG       0x10
+#define OPCR_FLAG      0x08
+#define SPLICE_FLAG    0x04
+#define TRANS_PRIV     0x02
+#define ADAP_EXT_FLAG  0x01
+
+// adaptation extension flags
+#define LTW_FLAG       0x80
+#define PIECE_RATE     0x40
+#define SEAM_SPLICE    0x20
+
+
+#define MAX_PLENGTH 0xFFFF
+#define MMAX_PLENGTH (256*MAX_PLENGTH)
+
+#ifndef IPACKS
+#define IPACKS 2048
+#endif
+
+struct ipack {
+       int size;
+       int found;
+       u8 *buf;
+       u8 cid;
+       u32 plength;
+       u8 plen[2];
+       u8 flag1;
+       u8 flag2;
+       u8 hlength;
+       u8 pts[5];
+       u16 *pid;
+       int mpeg;
+       u8 check;
+       int which;
+       int done;
+       void *data;
+       void (*func)(u8 *buf,  int size, void *priv);
+       int count;
+       int repack_subids;
+};
+
+struct dvb_video_info {
+       u32 horizontal_size;
+       u32 vertical_size;
+       u32 aspect_ratio;
+       u32 framerate;
+       u32 video_format;
+       u32 bit_rate;
+       u32 comp_bit_rate;
+       u32 vbv_buffer_size;
+       s16 vbv_delay;
+       u32 CSPF;
+       u32 off;
+};
+
+#define OFF_SIZE 4
+#define FIRST_FIELD 0
+#define SECOND_FIELD 1
+#define VIDEO_FRAME_PICTURE 0x03
+
+struct mpg_picture {
+       int       channel;
+       struct dvb_video_info vinfo;
+       u32      *sequence_gop_header;
+       u32      *picture_header;
+       s32       time_code;
+       int       low_delay;
+       int       closed_gop;
+       int       broken_link;
+       int       sequence_header_flag;
+       int       gop_flag;
+       int       sequence_end_flag;
+
+       u8        profile_and_level;
+       s32       picture_coding_parameter;
+       u32       matrix[32];
+       s8        matrix_change_flag;
+
+       u8        picture_header_parameter;
+  /* bit 0 - 2: bwd f code
+     bit 3    : fpb vector
+     bit 4 - 6: fwd f code
+     bit 7    : fpf vector */
+
+       int       mpeg1_flag;
+       int       progressive_sequence;
+       int       sequence_display_extension_flag;
+       u32       sequence_header_data;
+       s16       last_frame_centre_horizontal_offset;
+       s16       last_frame_centre_vertical_offset;
+
+       u32       pts[2]; /* [0] 1st field, [1] 2nd field */
+       int       top_field_first;
+       int       repeat_first_field;
+       int       progressive_frame;
+       int       bank;
+       int       forward_bank;
+       int       backward_bank;
+       int       compress;
+       s16       frame_centre_horizontal_offset[OFF_SIZE];
+                 /* [0-2] 1st field, [3] 2nd field */
+       s16       frame_centre_vertical_offset[OFF_SIZE];
+                 /* [0-2] 1st field, [3] 2nd field */
+       s16       temporal_reference[2];
+                 /* [0] 1st field, [1] 2nd field */
+
+       s8        picture_coding_type[2];
+                 /* [0] 1st field, [1] 2nd field */
+       s8        picture_structure[2];
+                 /* [0] 1st field, [1] 2nd field */
+       s8        picture_display_extension_flag[2];
+                 /* [0] 1st field, [1] 2nd field */
+                 /* picture_display_extenion() 0:no 1:exit*/
+       s8        pts_flag[2];
+                 /* [0] 1st field, [1] 2nd field */
+};
+
+struct dvb_audio_info {
+       int layer;
+       u32 bit_rate;
+       u32 frequency;
+       u32 mode;
+       u32 mode_extension ;
+       u32 emphasis;
+       u32 framesize;
+       u32 off;
+};
+
+int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr);
+
+
+#endif
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
new file mode 100644 (file)
index 0000000..12e5eb1
--- /dev/null
@@ -0,0 +1,2553 @@
+/*
+ * dvb_frontend.c: DVB frontend tuning interface/thread
+ *
+ *
+ * Copyright (C) 1999-2001 Ralph  Metzler
+ *                        Marcus Metzler
+ *                        Holger Waechtler
+ *                                   for convergence integrated media GmbH
+ *
+ * Copyright (C) 2004 Andrew de Quincey (tuning thread cleanup)
+ *
+ * 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
+ */
+
+/* Enables DVBv3 compatibility bits at the headers */
+#define __DVB_CORE__
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/slab.h>
+#include <linux/poll.h>
+#include <linux/semaphore.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/freezer.h>
+#include <linux/jiffies.h>
+#include <linux/kthread.h>
+#include <asm/processor.h>
+
+#include "dvb_frontend.h"
+#include "dvbdev.h"
+#include <linux/dvb/version.h>
+
+static int dvb_frontend_debug;
+static int dvb_shutdown_timeout;
+static int dvb_force_auto_inversion;
+static int dvb_override_tune_delay;
+static int dvb_powerdown_on_sleep = 1;
+static int dvb_mfe_wait_time = 5;
+
+module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
+MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off).");
+module_param(dvb_shutdown_timeout, int, 0644);
+MODULE_PARM_DESC(dvb_shutdown_timeout, "wait <shutdown_timeout> seconds after close() before suspending hardware");
+module_param(dvb_force_auto_inversion, int, 0644);
+MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always");
+module_param(dvb_override_tune_delay, int, 0644);
+MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
+module_param(dvb_powerdown_on_sleep, int, 0644);
+MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)");
+module_param(dvb_mfe_wait_time, int, 0644);
+MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open() for multi-frontend to become available (default:5 seconds)");
+
+#define dprintk if (dvb_frontend_debug) printk
+
+#define FESTATE_IDLE 1
+#define FESTATE_RETUNE 2
+#define FESTATE_TUNING_FAST 4
+#define FESTATE_TUNING_SLOW 8
+#define FESTATE_TUNED 16
+#define FESTATE_ZIGZAG_FAST 32
+#define FESTATE_ZIGZAG_SLOW 64
+#define FESTATE_DISEQC 128
+#define FESTATE_ERROR 256
+#define FESTATE_WAITFORLOCK (FESTATE_TUNING_FAST | FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW | FESTATE_DISEQC)
+#define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST)
+#define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)
+#define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW)
+
+#define FE_ALGO_HW             1
+/*
+ * FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling.
+ * FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune.
+ * FESTATE_TUNING_FAST. Tuning parameters have been supplied and fast zigzag scan is in progress.
+ * FESTATE_TUNING_SLOW. Tuning parameters have been supplied. Fast zigzag failed, so we're trying again, but slower.
+ * FESTATE_TUNED. The frontend has successfully locked on.
+ * FESTATE_ZIGZAG_FAST. The lock has been lost, and a fast zigzag has been initiated to try and regain it.
+ * FESTATE_ZIGZAG_SLOW. The lock has been lost. Fast zigzag has been failed, so we're trying again, but slower.
+ * FESTATE_DISEQC. A DISEQC command has just been issued.
+ * FESTATE_WAITFORLOCK. When we're waiting for a lock.
+ * FESTATE_SEARCHING_FAST. When we're searching for a signal using a fast zigzag scan.
+ * FESTATE_SEARCHING_SLOW. When we're searching for a signal using a slow zigzag scan.
+ * FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.
+ */
+
+#define DVB_FE_NO_EXIT 0
+#define DVB_FE_NORMAL_EXIT     1
+#define DVB_FE_DEVICE_REMOVED  2
+
+static DEFINE_MUTEX(frontend_mutex);
+
+struct dvb_frontend_private {
+
+       /* thread/frontend values */
+       struct dvb_device *dvbdev;
+       struct dvb_frontend_parameters parameters_out;
+       struct dvb_fe_events events;
+       struct semaphore sem;
+       struct list_head list_head;
+       wait_queue_head_t wait_queue;
+       struct task_struct *thread;
+       unsigned long release_jiffies;
+       unsigned int exit;
+       unsigned int wakeup;
+       fe_status_t status;
+       unsigned long tune_mode_flags;
+       unsigned int delay;
+       unsigned int reinitialise;
+       int tone;
+       int voltage;
+
+       /* swzigzag values */
+       unsigned int state;
+       unsigned int bending;
+       int lnb_drift;
+       unsigned int inversion;
+       unsigned int auto_step;
+       unsigned int auto_sub_step;
+       unsigned int started_auto_step;
+       unsigned int min_delay;
+       unsigned int max_drift;
+       unsigned int step_size;
+       int quality;
+       unsigned int check_wrapped;
+       enum dvbfe_search algo_status;
+};
+
+static void dvb_frontend_wakeup(struct dvb_frontend *fe);
+static int dtv_get_frontend(struct dvb_frontend *fe,
+                           struct dvb_frontend_parameters *p_out);
+static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
+                                          struct dvb_frontend_parameters *p);
+
+static bool has_get_frontend(struct dvb_frontend *fe)
+{
+       return fe->ops.get_frontend != NULL;
+}
+
+/*
+ * Due to DVBv3 API calls, a delivery system should be mapped into one of
+ * the 4 DVBv3 delivery systems (FE_QPSK, FE_QAM, FE_OFDM or FE_ATSC),
+ * otherwise, a DVBv3 call will fail.
+ */
+enum dvbv3_emulation_type {
+       DVBV3_UNKNOWN,
+       DVBV3_QPSK,
+       DVBV3_QAM,
+       DVBV3_OFDM,
+       DVBV3_ATSC,
+};
+
+static enum dvbv3_emulation_type dvbv3_type(u32 delivery_system)
+{
+       switch (delivery_system) {
+       case SYS_DVBC_ANNEX_A:
+       case SYS_DVBC_ANNEX_C:
+               return DVBV3_QAM;
+       case SYS_DVBS:
+       case SYS_DVBS2:
+       case SYS_TURBO:
+       case SYS_ISDBS:
+       case SYS_DSS:
+               return DVBV3_QPSK;
+       case SYS_DVBT:
+       case SYS_DVBT2:
+       case SYS_ISDBT:
+       case SYS_DTMB:
+               return DVBV3_OFDM;
+       case SYS_ATSC:
+       case SYS_ATSCMH:
+       case SYS_DVBC_ANNEX_B:
+               return DVBV3_ATSC;
+       case SYS_UNDEFINED:
+       case SYS_ISDBC:
+       case SYS_DVBH:
+       case SYS_DAB:
+       default:
+               /*
+                * Doesn't know how to emulate those types and/or
+                * there's no frontend driver from this type yet
+                * with some emulation code, so, we're not sure yet how
+                * to handle them, or they're not compatible with a DVBv3 call.
+                */
+               return DVBV3_UNKNOWN;
+       }
+}
+
+static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
+{
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dvb_fe_events *events = &fepriv->events;
+       struct dvb_frontend_event *e;
+       int wp;
+
+       dprintk ("%s\n", __func__);
+
+       if ((status & FE_HAS_LOCK) && has_get_frontend(fe))
+               dtv_get_frontend(fe, &fepriv->parameters_out);
+
+       mutex_lock(&events->mtx);
+
+       wp = (events->eventw + 1) % MAX_EVENT;
+       if (wp == events->eventr) {
+               events->overflow = 1;
+               events->eventr = (events->eventr + 1) % MAX_EVENT;
+       }
+
+       e = &events->events[events->eventw];
+       e->status = status;
+       e->parameters = fepriv->parameters_out;
+
+       events->eventw = wp;
+
+       mutex_unlock(&events->mtx);
+
+       wake_up_interruptible (&events->wait_queue);
+}
+
+static int dvb_frontend_get_event(struct dvb_frontend *fe,
+                           struct dvb_frontend_event *event, int flags)
+{
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dvb_fe_events *events = &fepriv->events;
+
+       dprintk ("%s\n", __func__);
+
+       if (events->overflow) {
+               events->overflow = 0;
+               return -EOVERFLOW;
+       }
+
+       if (events->eventw == events->eventr) {
+               int ret;
+
+               if (flags & O_NONBLOCK)
+                       return -EWOULDBLOCK;
+
+               up(&fepriv->sem);
+
+               ret = wait_event_interruptible (events->wait_queue,
+                                               events->eventw != events->eventr);
+
+               if (down_interruptible (&fepriv->sem))
+                       return -ERESTARTSYS;
+
+               if (ret < 0)
+                       return ret;
+       }
+
+       mutex_lock(&events->mtx);
+       *event = events->events[events->eventr];
+       events->eventr = (events->eventr + 1) % MAX_EVENT;
+       mutex_unlock(&events->mtx);
+
+       return 0;
+}
+
+static void dvb_frontend_clear_events(struct dvb_frontend *fe)
+{
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dvb_fe_events *events = &fepriv->events;
+
+       mutex_lock(&events->mtx);
+       events->eventr = events->eventw;
+       mutex_unlock(&events->mtx);
+}
+
+static void dvb_frontend_init(struct dvb_frontend *fe)
+{
+       dprintk ("DVB: initialising adapter %i frontend %i (%s)...\n",
+                fe->dvb->num,
+                fe->id,
+                fe->ops.info.name);
+
+       if (fe->ops.init)
+               fe->ops.init(fe);
+       if (fe->ops.tuner_ops.init) {
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 1);
+               fe->ops.tuner_ops.init(fe);
+               if (fe->ops.i2c_gate_ctrl)
+                       fe->ops.i2c_gate_ctrl(fe, 0);
+       }
+}
+
+void dvb_frontend_reinitialise(struct dvb_frontend *fe)
+{
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+       fepriv->reinitialise = 1;
+       dvb_frontend_wakeup(fe);
+}
+EXPORT_SYMBOL(dvb_frontend_reinitialise);
+
+static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked)
+{
+       int q2;
+
+       dprintk ("%s\n", __func__);
+
+       if (locked)
+               (fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256;
+       else
+               (fepriv->quality) = (fepriv->quality * 220 + 0) / 256;
+
+       q2 = fepriv->quality - 128;
+       q2 *= q2;
+
+       fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128);
+}
+
+/**
+ * Performs automatic twiddling of frontend parameters.
+ *
+ * @param fe The frontend concerned.
+ * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT
+ * @returns Number of complete iterations that have been performed.
+ */
+static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped)
+{
+       int autoinversion;
+       int ready = 0;
+       int fe_set_err = 0;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp;
+       int original_inversion = c->inversion;
+       u32 original_frequency = c->frequency;
+
+       /* are we using autoinversion? */
+       autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
+                        (c->inversion == INVERSION_AUTO));
+
+       /* setup parameters correctly */
+       while(!ready) {
+               /* calculate the lnb_drift */
+               fepriv->lnb_drift = fepriv->auto_step * fepriv->step_size;
+
+               /* wrap the auto_step if we've exceeded the maximum drift */
+               if (fepriv->lnb_drift > fepriv->max_drift) {
+                       fepriv->auto_step = 0;
+                       fepriv->auto_sub_step = 0;
+                       fepriv->lnb_drift = 0;
+               }
+
+               /* perform inversion and +/- zigzag */
+               switch(fepriv->auto_sub_step) {
+               case 0:
+                       /* try with the current inversion and current drift setting */
+                       ready = 1;
+                       break;
+
+               case 1:
+                       if (!autoinversion) break;
+
+                       fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;
+                       ready = 1;
+                       break;
+
+               case 2:
+                       if (fepriv->lnb_drift == 0) break;
+
+                       fepriv->lnb_drift = -fepriv->lnb_drift;
+                       ready = 1;
+                       break;
+
+               case 3:
+                       if (fepriv->lnb_drift == 0) break;
+                       if (!autoinversion) break;
+
+                       fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;
+                       fepriv->lnb_drift = -fepriv->lnb_drift;
+                       ready = 1;
+                       break;
+
+               default:
+                       fepriv->auto_step++;
+                       fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */
+                       break;
+               }
+
+               if (!ready) fepriv->auto_sub_step++;
+       }
+
+       /* if this attempt would hit where we started, indicate a complete
+        * iteration has occurred */
+       if ((fepriv->auto_step == fepriv->started_auto_step) &&
+           (fepriv->auto_sub_step == 0) && check_wrapped) {
+               return 1;
+       }
+
+       dprintk("%s: drift:%i inversion:%i auto_step:%i "
+               "auto_sub_step:%i started_auto_step:%i\n",
+               __func__, fepriv->lnb_drift, fepriv->inversion,
+               fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step);
+
+       /* set the frontend itself */
+       c->frequency += fepriv->lnb_drift;
+       if (autoinversion)
+               c->inversion = fepriv->inversion;
+       tmp = *c;
+       if (fe->ops.set_frontend)
+               fe_set_err = fe->ops.set_frontend(fe);
+       *c = tmp;
+       if (fe_set_err < 0) {
+               fepriv->state = FESTATE_ERROR;
+               return fe_set_err;
+       }
+
+       c->frequency = original_frequency;
+       c->inversion = original_inversion;
+
+       fepriv->auto_sub_step++;
+       return 0;
+}
+
+static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
+{
+       fe_status_t s = 0;
+       int retval = 0;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp;
+
+       /* if we've got no parameters, just keep idling */
+       if (fepriv->state & FESTATE_IDLE) {
+               fepriv->delay = 3*HZ;
+               fepriv->quality = 0;
+               return;
+       }
+
+       /* in SCAN mode, we just set the frontend when asked and leave it alone */
+       if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
+               if (fepriv->state & FESTATE_RETUNE) {
+                       tmp = *c;
+                       if (fe->ops.set_frontend)
+                               retval = fe->ops.set_frontend(fe);
+                       *c = tmp;
+                       if (retval < 0)
+                               fepriv->state = FESTATE_ERROR;
+                       else
+                               fepriv->state = FESTATE_TUNED;
+               }
+               fepriv->delay = 3*HZ;
+               fepriv->quality = 0;
+               return;
+       }
+
+       /* get the frontend status */
+       if (fepriv->state & FESTATE_RETUNE) {
+               s = 0;
+       } else {
+               if (fe->ops.read_status)
+                       fe->ops.read_status(fe, &s);
+               if (s != fepriv->status) {
+                       dvb_frontend_add_event(fe, s);
+                       fepriv->status = s;
+               }
+       }
+
+       /* if we're not tuned, and we have a lock, move to the TUNED state */
+       if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
+               dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+               fepriv->state = FESTATE_TUNED;
+
+               /* if we're tuned, then we have determined the correct inversion */
+               if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
+                   (c->inversion == INVERSION_AUTO)) {
+                       c->inversion = fepriv->inversion;
+               }
+               return;
+       }
+
+       /* if we are tuned already, check we're still locked */
+       if (fepriv->state & FESTATE_TUNED) {
+               dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+
+               /* we're tuned, and the lock is still good... */
+               if (s & FE_HAS_LOCK) {
+                       return;
+               } else { /* if we _WERE_ tuned, but now don't have a lock */
+                       fepriv->state = FESTATE_ZIGZAG_FAST;
+                       fepriv->started_auto_step = fepriv->auto_step;
+                       fepriv->check_wrapped = 0;
+               }
+       }
+
+       /* don't actually do anything if we're in the LOSTLOCK state,
+        * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
+       if ((fepriv->state & FESTATE_LOSTLOCK) &&
+           (fe->ops.info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
+               dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+               return;
+       }
+
+       /* don't do anything if we're in the DISEQC state, since this
+        * might be someone with a motorized dish controlled by DISEQC.
+        * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */
+       if (fepriv->state & FESTATE_DISEQC) {
+               dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+               return;
+       }
+
+       /* if we're in the RETUNE state, set everything up for a brand
+        * new scan, keeping the current inversion setting, as the next
+        * tune is _very_ likely to require the same */
+       if (fepriv->state & FESTATE_RETUNE) {
+               fepriv->lnb_drift = 0;
+               fepriv->auto_step = 0;
+               fepriv->auto_sub_step = 0;
+               fepriv->started_auto_step = 0;
+               fepriv->check_wrapped = 0;
+       }
+
+       /* fast zigzag. */
+       if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
+               fepriv->delay = fepriv->min_delay;
+
+               /* perform a tune */
+               retval = dvb_frontend_swzigzag_autotune(fe,
+                                                       fepriv->check_wrapped);
+               if (retval < 0) {
+                       return;
+               } else if (retval) {
+                       /* OK, if we've run out of trials at the fast speed.
+                        * Drop back to slow for the _next_ attempt */
+                       fepriv->state = FESTATE_SEARCHING_SLOW;
+                       fepriv->started_auto_step = fepriv->auto_step;
+                       return;
+               }
+               fepriv->check_wrapped = 1;
+
+               /* if we've just retuned, enter the ZIGZAG_FAST state.
+                * This ensures we cannot return from an
+                * FE_SET_FRONTEND ioctl before the first frontend tune
+                * occurs */
+               if (fepriv->state & FESTATE_RETUNE) {
+                       fepriv->state = FESTATE_TUNING_FAST;
+               }
+       }
+
+       /* slow zigzag */
+       if (fepriv->state & FESTATE_SEARCHING_SLOW) {
+               dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
+
+               /* Note: don't bother checking for wrapping; we stay in this
+                * state until we get a lock */
+               dvb_frontend_swzigzag_autotune(fe, 0);
+       }
+}
+
+static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
+{
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+       if (fepriv->exit != DVB_FE_NO_EXIT)
+               return 1;
+
+       if (fepriv->dvbdev->writers == 1)
+               if (time_after_eq(jiffies, fepriv->release_jiffies +
+                                 dvb_shutdown_timeout * HZ))
+                       return 1;
+
+       return 0;
+}
+
+static int dvb_frontend_should_wakeup(struct dvb_frontend *fe)
+{
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+       if (fepriv->wakeup) {
+               fepriv->wakeup = 0;
+               return 1;
+       }
+       return dvb_frontend_is_exiting(fe);
+}
+
+static void dvb_frontend_wakeup(struct dvb_frontend *fe)
+{
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+       fepriv->wakeup = 1;
+       wake_up_interruptible(&fepriv->wait_queue);
+}
+
+static int dvb_frontend_thread(void *data)
+{
+       struct dvb_frontend *fe = data;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       fe_status_t s;
+       enum dvbfe_algo algo;
+
+       bool re_tune = false;
+
+       dprintk("%s\n", __func__);
+
+       fepriv->check_wrapped = 0;
+       fepriv->quality = 0;
+       fepriv->delay = 3*HZ;
+       fepriv->status = 0;
+       fepriv->wakeup = 0;
+       fepriv->reinitialise = 0;
+
+       dvb_frontend_init(fe);
+
+       set_freezable();
+       while (1) {
+               up(&fepriv->sem);           /* is locked when we enter the thread... */
+restart:
+               wait_event_interruptible_timeout(fepriv->wait_queue,
+                       dvb_frontend_should_wakeup(fe) || kthread_should_stop()
+                               || freezing(current),
+                       fepriv->delay);
+
+               if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
+                       /* got signal or quitting */
+                       fepriv->exit = DVB_FE_NORMAL_EXIT;
+                       break;
+               }
+
+               if (try_to_freeze())
+                       goto restart;
+
+               if (down_interruptible(&fepriv->sem))
+                       break;
+
+               if (fepriv->reinitialise) {
+                       dvb_frontend_init(fe);
+                       if (fe->ops.set_tone && fepriv->tone != -1)
+                               fe->ops.set_tone(fe, fepriv->tone);
+                       if (fe->ops.set_voltage && fepriv->voltage != -1)
+                               fe->ops.set_voltage(fe, fepriv->voltage);
+                       fepriv->reinitialise = 0;
+               }
+
+               /* do an iteration of the tuning loop */
+               if (fe->ops.get_frontend_algo) {
+                       algo = fe->ops.get_frontend_algo(fe);
+                       switch (algo) {
+                       case DVBFE_ALGO_HW:
+                               dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__);
+
+                               if (fepriv->state & FESTATE_RETUNE) {
+                                       dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
+                                       re_tune = true;
+                                       fepriv->state = FESTATE_TUNED;
+                               } else {
+                                       re_tune = false;
+                               }
+
+                               if (fe->ops.tune)
+                                       fe->ops.tune(fe, re_tune, fepriv->tune_mode_flags, &fepriv->delay, &s);
+
+                               if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) {
+                                       dprintk("%s: state changed, adding current state\n", __func__);
+                                       dvb_frontend_add_event(fe, s);
+                                       fepriv->status = s;
+                               }
+                               break;
+                       case DVBFE_ALGO_SW:
+                               dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__);
+                               dvb_frontend_swzigzag(fe);
+                               break;
+                       case DVBFE_ALGO_CUSTOM:
+                               dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state);
+                               if (fepriv->state & FESTATE_RETUNE) {
+                                       dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__);
+                                       fepriv->state = FESTATE_TUNED;
+                               }
+                               /* Case where we are going to search for a carrier
+                                * User asked us to retune again for some reason, possibly
+                                * requesting a search with a new set of parameters
+                                */
+                               if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {
+                                       if (fe->ops.search) {
+                                               fepriv->algo_status = fe->ops.search(fe);
+                                               /* We did do a search as was requested, the flags are
+                                                * now unset as well and has the flags wrt to search.
+                                                */
+                                       } else {
+                                               fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN;
+                                       }
+                               }
+                               /* Track the carrier if the search was successful */
+                               if (fepriv->algo_status != DVBFE_ALGO_SEARCH_SUCCESS) {
+                                       fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+                                       fepriv->delay = HZ / 2;
+                               }
+                               dtv_property_legacy_params_sync(fe, &fepriv->parameters_out);
+                               fe->ops.read_status(fe, &s);
+                               if (s != fepriv->status) {
+                                       dvb_frontend_add_event(fe, s); /* update event list */
+                                       fepriv->status = s;
+                                       if (!(s & FE_HAS_LOCK)) {
+                                               fepriv->delay = HZ / 10;
+                                               fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+                                       } else {
+                                               fepriv->delay = 60 * HZ;
+                                       }
+                               }
+                               break;
+                       default:
+                               dprintk("%s: UNDEFINED ALGO !\n", __func__);
+                               break;
+                       }
+               } else {
+                       dvb_frontend_swzigzag(fe);
+               }
+       }
+
+       if (dvb_powerdown_on_sleep) {
+               if (fe->ops.set_voltage)
+                       fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
+               if (fe->ops.tuner_ops.sleep) {
+                       if (fe->ops.i2c_gate_ctrl)
+                               fe->ops.i2c_gate_ctrl(fe, 1);
+                       fe->ops.tuner_ops.sleep(fe);
+                       if (fe->ops.i2c_gate_ctrl)
+                               fe->ops.i2c_gate_ctrl(fe, 0);
+               }
+               if (fe->ops.sleep)
+                       fe->ops.sleep(fe);
+       }
+
+       fepriv->thread = NULL;
+       if (kthread_should_stop())
+               fepriv->exit = DVB_FE_DEVICE_REMOVED;
+       else
+               fepriv->exit = DVB_FE_NO_EXIT;
+       mb();
+
+       dvb_frontend_wakeup(fe);
+       return 0;
+}
+
+static void dvb_frontend_stop(struct dvb_frontend *fe)
+{
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+       dprintk ("%s\n", __func__);
+
+       fepriv->exit = DVB_FE_NORMAL_EXIT;
+       mb();
+
+       if (!fepriv->thread)
+               return;
+
+       kthread_stop(fepriv->thread);
+
+       sema_init(&fepriv->sem, 1);
+       fepriv->state = FESTATE_IDLE;
+
+       /* paranoia check in case a signal arrived */
+       if (fepriv->thread)
+               printk("dvb_frontend_stop: warning: thread %p won't exit\n",
+                               fepriv->thread);
+}
+
+s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime)
+{
+       return ((curtime.tv_usec < lasttime.tv_usec) ?
+               1000000 - lasttime.tv_usec + curtime.tv_usec :
+               curtime.tv_usec - lasttime.tv_usec);
+}
+EXPORT_SYMBOL(timeval_usec_diff);
+
+static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec)
+{
+       curtime->tv_usec += add_usec;
+       if (curtime->tv_usec >= 1000000) {
+               curtime->tv_usec -= 1000000;
+               curtime->tv_sec++;
+       }
+}
+
+/*
+ * Sleep until gettimeofday() > waketime + add_usec
+ * This needs to be as precise as possible, but as the delay is
+ * usually between 2ms and 32ms, it is done using a scheduled msleep
+ * followed by usleep (normally a busy-wait loop) for the remainder
+ */
+void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec)
+{
+       struct timeval lasttime;
+       s32 delta, newdelta;
+
+       timeval_usec_add(waketime, add_usec);
+
+       do_gettimeofday(&lasttime);
+       delta = timeval_usec_diff(lasttime, *waketime);
+       if (delta > 2500) {
+               msleep((delta - 1500) / 1000);
+               do_gettimeofday(&lasttime);
+               newdelta = timeval_usec_diff(lasttime, *waketime);
+               delta = (newdelta > delta) ? 0 : newdelta;
+       }
+       if (delta > 0)
+               udelay(delta);
+}
+EXPORT_SYMBOL(dvb_frontend_sleep_until);
+
+static int dvb_frontend_start(struct dvb_frontend *fe)
+{
+       int ret;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct task_struct *fe_thread;
+
+       dprintk ("%s\n", __func__);
+
+       if (fepriv->thread) {
+               if (fepriv->exit == DVB_FE_NO_EXIT)
+                       return 0;
+               else
+                       dvb_frontend_stop (fe);
+       }
+
+       if (signal_pending(current))
+               return -EINTR;
+       if (down_interruptible (&fepriv->sem))
+               return -EINTR;
+
+       fepriv->state = FESTATE_IDLE;
+       fepriv->exit = DVB_FE_NO_EXIT;
+       fepriv->thread = NULL;
+       mb();
+
+       fe_thread = kthread_run(dvb_frontend_thread, fe,
+               "kdvb-ad-%i-fe-%i", fe->dvb->num,fe->id);
+       if (IS_ERR(fe_thread)) {
+               ret = PTR_ERR(fe_thread);
+               printk("dvb_frontend_start: failed to start kthread (%d)\n", ret);
+               up(&fepriv->sem);
+               return ret;
+       }
+       fepriv->thread = fe_thread;
+       return 0;
+}
+
+static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe,
+                                       u32 *freq_min, u32 *freq_max)
+{
+       *freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min);
+
+       if (fe->ops.info.frequency_max == 0)
+               *freq_max = fe->ops.tuner_ops.info.frequency_max;
+       else if (fe->ops.tuner_ops.info.frequency_max == 0)
+               *freq_max = fe->ops.info.frequency_max;
+       else
+               *freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max);
+
+       if (*freq_min == 0 || *freq_max == 0)
+               printk(KERN_WARNING "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n",
+                      fe->dvb->num,fe->id);
+}
+
+static int dvb_frontend_check_parameters(struct dvb_frontend *fe)
+{
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       u32 freq_min;
+       u32 freq_max;
+
+       /* range check: frequency */
+       dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max);
+       if ((freq_min && c->frequency < freq_min) ||
+           (freq_max && c->frequency > freq_max)) {
+               printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n",
+                      fe->dvb->num, fe->id, c->frequency, freq_min, freq_max);
+               return -EINVAL;
+       }
+
+       /* range check: symbol rate */
+       switch (c->delivery_system) {
+       case SYS_DVBS:
+       case SYS_DVBS2:
+       case SYS_TURBO:
+       case SYS_DVBC_ANNEX_A:
+       case SYS_DVBC_ANNEX_C:
+               if ((fe->ops.info.symbol_rate_min &&
+                    c->symbol_rate < fe->ops.info.symbol_rate_min) ||
+                   (fe->ops.info.symbol_rate_max &&
+                    c->symbol_rate > fe->ops.info.symbol_rate_max)) {
+                       printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",
+                              fe->dvb->num, fe->id, c->symbol_rate,
+                              fe->ops.info.symbol_rate_min,
+                              fe->ops.info.symbol_rate_max);
+                       return -EINVAL;
+               }
+       default:
+               break;
+       }
+
+       return 0;
+}
+
+static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
+{
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int i;
+       u32 delsys;
+
+       delsys = c->delivery_system;
+       memset(c, 0, sizeof(struct dtv_frontend_properties));
+       c->delivery_system = delsys;
+
+       c->state = DTV_CLEAR;
+
+       dprintk("%s() Clearing cache for delivery system %d\n", __func__,
+               c->delivery_system);
+
+       c->transmission_mode = TRANSMISSION_MODE_AUTO;
+       c->bandwidth_hz = 0;    /* AUTO */
+       c->guard_interval = GUARD_INTERVAL_AUTO;
+       c->hierarchy = HIERARCHY_AUTO;
+       c->symbol_rate = 0;
+       c->code_rate_HP = FEC_AUTO;
+       c->code_rate_LP = FEC_AUTO;
+       c->fec_inner = FEC_AUTO;
+       c->rolloff = ROLLOFF_AUTO;
+       c->voltage = SEC_VOLTAGE_OFF;
+       c->sectone = SEC_TONE_OFF;
+       c->pilot = PILOT_AUTO;
+
+       c->isdbt_partial_reception = 0;
+       c->isdbt_sb_mode = 0;
+       c->isdbt_sb_subchannel = 0;
+       c->isdbt_sb_segment_idx = 0;
+       c->isdbt_sb_segment_count = 0;
+       c->isdbt_layer_enabled = 0;
+       for (i = 0; i < 3; i++) {
+               c->layer[i].fec = FEC_AUTO;
+               c->layer[i].modulation = QAM_AUTO;
+               c->layer[i].interleaving = 0;
+               c->layer[i].segment_count = 0;
+       }
+
+       c->isdbs_ts_id = 0;
+       c->dvbt2_plp_id = 0;
+
+       switch (c->delivery_system) {
+       case SYS_DVBS:
+       case SYS_DVBS2:
+       case SYS_TURBO:
+               c->modulation = QPSK;   /* implied for DVB-S in legacy API */
+               c->rolloff = ROLLOFF_35;/* implied for DVB-S */
+               break;
+       case SYS_ATSC:
+               c->modulation = VSB_8;
+               break;
+       default:
+               c->modulation = QAM_AUTO;
+               break;
+       }
+
+       return 0;
+}
+
+#define _DTV_CMD(n, s, b) \
+[n] = { \
+       .name = #n, \
+       .cmd  = n, \
+       .set  = s,\
+       .buffer = b \
+}
+
+static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
+       _DTV_CMD(DTV_TUNE, 1, 0),
+       _DTV_CMD(DTV_CLEAR, 1, 0),
+
+       /* Set */
+       _DTV_CMD(DTV_FREQUENCY, 1, 0),
+       _DTV_CMD(DTV_BANDWIDTH_HZ, 1, 0),
+       _DTV_CMD(DTV_MODULATION, 1, 0),
+       _DTV_CMD(DTV_INVERSION, 1, 0),
+       _DTV_CMD(DTV_DISEQC_MASTER, 1, 1),
+       _DTV_CMD(DTV_SYMBOL_RATE, 1, 0),
+       _DTV_CMD(DTV_INNER_FEC, 1, 0),
+       _DTV_CMD(DTV_VOLTAGE, 1, 0),
+       _DTV_CMD(DTV_TONE, 1, 0),
+       _DTV_CMD(DTV_PILOT, 1, 0),
+       _DTV_CMD(DTV_ROLLOFF, 1, 0),
+       _DTV_CMD(DTV_DELIVERY_SYSTEM, 1, 0),
+       _DTV_CMD(DTV_HIERARCHY, 1, 0),
+       _DTV_CMD(DTV_CODE_RATE_HP, 1, 0),
+       _DTV_CMD(DTV_CODE_RATE_LP, 1, 0),
+       _DTV_CMD(DTV_GUARD_INTERVAL, 1, 0),
+       _DTV_CMD(DTV_TRANSMISSION_MODE, 1, 0),
+       _DTV_CMD(DTV_INTERLEAVING, 1, 0),
+
+       _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 1, 0),
+       _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 1, 0),
+       _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 1, 0),
+       _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 1, 0),
+       _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 1, 0),
+       _DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 1, 0),
+       _DTV_CMD(DTV_ISDBT_LAYERA_FEC, 1, 0),
+       _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 1, 0),
+       _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 1, 0),
+       _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 1, 0),
+       _DTV_CMD(DTV_ISDBT_LAYERB_FEC, 1, 0),
+       _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 1, 0),
+       _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 1, 0),
+       _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 1, 0),
+       _DTV_CMD(DTV_ISDBT_LAYERC_FEC, 1, 0),
+       _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 1, 0),
+       _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 1, 0),
+       _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 1, 0),
+
+       _DTV_CMD(DTV_ISDBS_TS_ID, 1, 0),
+       _DTV_CMD(DTV_DVBT2_PLP_ID, 1, 0),
+
+       /* Get */
+       _DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1),
+       _DTV_CMD(DTV_API_VERSION, 0, 0),
+       _DTV_CMD(DTV_CODE_RATE_HP, 0, 0),
+       _DTV_CMD(DTV_CODE_RATE_LP, 0, 0),
+       _DTV_CMD(DTV_GUARD_INTERVAL, 0, 0),
+       _DTV_CMD(DTV_TRANSMISSION_MODE, 0, 0),
+       _DTV_CMD(DTV_HIERARCHY, 0, 0),
+       _DTV_CMD(DTV_INTERLEAVING, 0, 0),
+
+       _DTV_CMD(DTV_ENUM_DELSYS, 0, 0),
+
+       _DTV_CMD(DTV_ATSCMH_PARADE_ID, 1, 0),
+       _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 1, 0),
+
+       _DTV_CMD(DTV_ATSCMH_FIC_VER, 0, 0),
+       _DTV_CMD(DTV_ATSCMH_PARADE_ID, 0, 0),
+       _DTV_CMD(DTV_ATSCMH_NOG, 0, 0),
+       _DTV_CMD(DTV_ATSCMH_TNOG, 0, 0),
+       _DTV_CMD(DTV_ATSCMH_SGN, 0, 0),
+       _DTV_CMD(DTV_ATSCMH_PRC, 0, 0),
+       _DTV_CMD(DTV_ATSCMH_RS_FRAME_MODE, 0, 0),
+       _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 0, 0),
+       _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_PRI, 0, 0),
+       _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_SEC, 0, 0),
+       _DTV_CMD(DTV_ATSCMH_SCCC_BLOCK_MODE, 0, 0),
+       _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_A, 0, 0),
+       _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B, 0, 0),
+       _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C, 0, 0),
+       _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D, 0, 0),
+};
+
+static void dtv_property_dump(struct dtv_property *tvp)
+{
+       int i;
+
+       if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
+               printk(KERN_WARNING "%s: tvp.cmd = 0x%08x undefined\n",
+                       __func__, tvp->cmd);
+               return;
+       }
+
+       dprintk("%s() tvp.cmd    = 0x%08x (%s)\n"
+               ,__func__
+               ,tvp->cmd
+               ,dtv_cmds[ tvp->cmd ].name);
+
+       if(dtv_cmds[ tvp->cmd ].buffer) {
+
+               dprintk("%s() tvp.u.buffer.len = 0x%02x\n"
+                       ,__func__
+                       ,tvp->u.buffer.len);
+
+               for(i = 0; i < tvp->u.buffer.len; i++)
+                       dprintk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"
+                               ,__func__
+                               ,i
+                               ,tvp->u.buffer.data[i]);
+
+       } else
+               dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data);
+}
+
+/* Synchronise the legacy tuning parameters into the cache, so that demodulator
+ * drivers can use a single set_frontend tuning function, regardless of whether
+ * it's being used for the legacy or new API, reducing code and complexity.
+ */
+static int dtv_property_cache_sync(struct dvb_frontend *fe,
+                                  struct dtv_frontend_properties *c,
+                                  const struct dvb_frontend_parameters *p)
+{
+       c->frequency = p->frequency;
+       c->inversion = p->inversion;
+
+       switch (dvbv3_type(c->delivery_system)) {
+       case DVBV3_QPSK:
+               dprintk("%s() Preparing QPSK req\n", __func__);
+               c->symbol_rate = p->u.qpsk.symbol_rate;
+               c->fec_inner = p->u.qpsk.fec_inner;
+               break;
+       case DVBV3_QAM:
+               dprintk("%s() Preparing QAM req\n", __func__);
+               c->symbol_rate = p->u.qam.symbol_rate;
+               c->fec_inner = p->u.qam.fec_inner;
+               c->modulation = p->u.qam.modulation;
+               break;
+       case DVBV3_OFDM:
+               dprintk("%s() Preparing OFDM req\n", __func__);
+               switch (p->u.ofdm.bandwidth) {
+               case BANDWIDTH_10_MHZ:
+                       c->bandwidth_hz = 10000000;
+                       break;
+               case BANDWIDTH_8_MHZ:
+                       c->bandwidth_hz = 8000000;
+                       break;
+               case BANDWIDTH_7_MHZ:
+                       c->bandwidth_hz = 7000000;
+                       break;
+               case BANDWIDTH_6_MHZ:
+                       c->bandwidth_hz = 6000000;
+                       break;
+               case BANDWIDTH_5_MHZ:
+                       c->bandwidth_hz = 5000000;
+                       break;
+               case BANDWIDTH_1_712_MHZ:
+                       c->bandwidth_hz = 1712000;
+                       break;
+               case BANDWIDTH_AUTO:
+                       c->bandwidth_hz = 0;
+               }
+
+               c->code_rate_HP = p->u.ofdm.code_rate_HP;
+               c->code_rate_LP = p->u.ofdm.code_rate_LP;
+               c->modulation = p->u.ofdm.constellation;
+               c->transmission_mode = p->u.ofdm.transmission_mode;
+               c->guard_interval = p->u.ofdm.guard_interval;
+               c->hierarchy = p->u.ofdm.hierarchy_information;
+               break;
+       case DVBV3_ATSC:
+               dprintk("%s() Preparing ATSC req\n", __func__);
+               c->modulation = p->u.vsb.modulation;
+               if (c->delivery_system == SYS_ATSCMH)
+                       break;
+               if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
+                       c->delivery_system = SYS_ATSC;
+               else
+                       c->delivery_system = SYS_DVBC_ANNEX_B;
+               break;
+       case DVBV3_UNKNOWN:
+               printk(KERN_ERR
+                      "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n",
+                      __func__, c->delivery_system);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* Ensure the cached values are set correctly in the frontend
+ * legacy tuning structures, for the advanced tuning API.
+ */
+static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
+                                           struct dvb_frontend_parameters *p)
+{
+       const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+       p->frequency = c->frequency;
+       p->inversion = c->inversion;
+
+       switch (dvbv3_type(c->delivery_system)) {
+       case DVBV3_UNKNOWN:
+               printk(KERN_ERR
+                      "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n",
+                      __func__, c->delivery_system);
+               return -EINVAL;
+       case DVBV3_QPSK:
+               dprintk("%s() Preparing QPSK req\n", __func__);
+               p->u.qpsk.symbol_rate = c->symbol_rate;
+               p->u.qpsk.fec_inner = c->fec_inner;
+               break;
+       case DVBV3_QAM:
+               dprintk("%s() Preparing QAM req\n", __func__);
+               p->u.qam.symbol_rate = c->symbol_rate;
+               p->u.qam.fec_inner = c->fec_inner;
+               p->u.qam.modulation = c->modulation;
+               break;
+       case DVBV3_OFDM:
+               dprintk("%s() Preparing OFDM req\n", __func__);
+
+               switch (c->bandwidth_hz) {
+               case 10000000:
+                       p->u.ofdm.bandwidth = BANDWIDTH_10_MHZ;
+                       break;
+               case 8000000:
+                       p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
+                       break;
+               case 7000000:
+                       p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
+                       break;
+               case 6000000:
+                       p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+                       break;
+               case 5000000:
+                       p->u.ofdm.bandwidth = BANDWIDTH_5_MHZ;
+                       break;
+               case 1712000:
+                       p->u.ofdm.bandwidth = BANDWIDTH_1_712_MHZ;
+                       break;
+               case 0:
+               default:
+                       p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
+               }
+               p->u.ofdm.code_rate_HP = c->code_rate_HP;
+               p->u.ofdm.code_rate_LP = c->code_rate_LP;
+               p->u.ofdm.constellation = c->modulation;
+               p->u.ofdm.transmission_mode = c->transmission_mode;
+               p->u.ofdm.guard_interval = c->guard_interval;
+               p->u.ofdm.hierarchy_information = c->hierarchy;
+               break;
+       case DVBV3_ATSC:
+               dprintk("%s() Preparing VSB req\n", __func__);
+               p->u.vsb.modulation = c->modulation;
+               break;
+       }
+       return 0;
+}
+
+/**
+ * dtv_get_frontend - calls a callback for retrieving DTV parameters
+ * @fe:                struct dvb_frontend pointer
+ * @c:         struct dtv_frontend_properties pointer (DVBv5 cache)
+ * @p_out      struct dvb_frontend_parameters pointer (DVBv3 FE struct)
+ *
+ * This routine calls either the DVBv3 or DVBv5 get_frontend call.
+ * If c is not null, it will update the DVBv5 cache struct pointed by it.
+ * If p_out is not null, it will update the DVBv3 params pointed by it.
+ */
+static int dtv_get_frontend(struct dvb_frontend *fe,
+                           struct dvb_frontend_parameters *p_out)
+{
+       int r;
+
+       if (fe->ops.get_frontend) {
+               r = fe->ops.get_frontend(fe);
+               if (unlikely(r < 0))
+                       return r;
+               if (p_out)
+                       dtv_property_legacy_params_sync(fe, p_out);
+               return 0;
+       }
+
+       /* As everything is in cache, get_frontend fops are always supported */
+       return 0;
+}
+
+static int dvb_frontend_ioctl_legacy(struct file *file,
+                       unsigned int cmd, void *parg);
+static int dvb_frontend_ioctl_properties(struct file *file,
+                       unsigned int cmd, void *parg);
+
+static int dtv_property_process_get(struct dvb_frontend *fe,
+                                   const struct dtv_frontend_properties *c,
+                                   struct dtv_property *tvp,
+                                   struct file *file)
+{
+       int r, ncaps;
+
+       switch(tvp->cmd) {
+       case DTV_ENUM_DELSYS:
+               ncaps = 0;
+               while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+                       tvp->u.buffer.data[ncaps] = fe->ops.delsys[ncaps];
+                       ncaps++;
+               }
+               tvp->u.buffer.len = ncaps;
+               break;
+       case DTV_FREQUENCY:
+               tvp->u.data = c->frequency;
+               break;
+       case DTV_MODULATION:
+               tvp->u.data = c->modulation;
+               break;
+       case DTV_BANDWIDTH_HZ:
+               tvp->u.data = c->bandwidth_hz;
+               break;
+       case DTV_INVERSION:
+               tvp->u.data = c->inversion;
+               break;
+       case DTV_SYMBOL_RATE:
+               tvp->u.data = c->symbol_rate;
+               break;
+       case DTV_INNER_FEC:
+               tvp->u.data = c->fec_inner;
+               break;
+       case DTV_PILOT:
+               tvp->u.data = c->pilot;
+               break;
+       case DTV_ROLLOFF:
+               tvp->u.data = c->rolloff;
+               break;
+       case DTV_DELIVERY_SYSTEM:
+               tvp->u.data = c->delivery_system;
+               break;
+       case DTV_VOLTAGE:
+               tvp->u.data = c->voltage;
+               break;
+       case DTV_TONE:
+               tvp->u.data = c->sectone;
+               break;
+       case DTV_API_VERSION:
+               tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;
+               break;
+       case DTV_CODE_RATE_HP:
+               tvp->u.data = c->code_rate_HP;
+               break;
+       case DTV_CODE_RATE_LP:
+               tvp->u.data = c->code_rate_LP;
+               break;
+       case DTV_GUARD_INTERVAL:
+               tvp->u.data = c->guard_interval;
+               break;
+       case DTV_TRANSMISSION_MODE:
+               tvp->u.data = c->transmission_mode;
+               break;
+       case DTV_HIERARCHY:
+               tvp->u.data = c->hierarchy;
+               break;
+       case DTV_INTERLEAVING:
+               tvp->u.data = c->interleaving;
+               break;
+
+       /* ISDB-T Support here */
+       case DTV_ISDBT_PARTIAL_RECEPTION:
+               tvp->u.data = c->isdbt_partial_reception;
+               break;
+       case DTV_ISDBT_SOUND_BROADCASTING:
+               tvp->u.data = c->isdbt_sb_mode;
+               break;
+       case DTV_ISDBT_SB_SUBCHANNEL_ID:
+               tvp->u.data = c->isdbt_sb_subchannel;
+               break;
+       case DTV_ISDBT_SB_SEGMENT_IDX:
+               tvp->u.data = c->isdbt_sb_segment_idx;
+               break;
+       case DTV_ISDBT_SB_SEGMENT_COUNT:
+               tvp->u.data = c->isdbt_sb_segment_count;
+               break;
+       case DTV_ISDBT_LAYER_ENABLED:
+               tvp->u.data = c->isdbt_layer_enabled;
+               break;
+       case DTV_ISDBT_LAYERA_FEC:
+               tvp->u.data = c->layer[0].fec;
+               break;
+       case DTV_ISDBT_LAYERA_MODULATION:
+               tvp->u.data = c->layer[0].modulation;
+               break;
+       case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
+               tvp->u.data = c->layer[0].segment_count;
+               break;
+       case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
+               tvp->u.data = c->layer[0].interleaving;
+               break;
+       case DTV_ISDBT_LAYERB_FEC:
+               tvp->u.data = c->layer[1].fec;
+               break;
+       case DTV_ISDBT_LAYERB_MODULATION:
+               tvp->u.data = c->layer[1].modulation;
+               break;
+       case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
+               tvp->u.data = c->layer[1].segment_count;
+               break;
+       case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
+               tvp->u.data = c->layer[1].interleaving;
+               break;
+       case DTV_ISDBT_LAYERC_FEC:
+               tvp->u.data = c->layer[2].fec;
+               break;
+       case DTV_ISDBT_LAYERC_MODULATION:
+               tvp->u.data = c->layer[2].modulation;
+               break;
+       case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
+               tvp->u.data = c->layer[2].segment_count;
+               break;
+       case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
+               tvp->u.data = c->layer[2].interleaving;
+               break;
+       case DTV_ISDBS_TS_ID:
+               tvp->u.data = c->isdbs_ts_id;
+               break;
+       case DTV_DVBT2_PLP_ID:
+               tvp->u.data = c->dvbt2_plp_id;
+               break;
+
+       /* ATSC-MH */
+       case DTV_ATSCMH_FIC_VER:
+               tvp->u.data = fe->dtv_property_cache.atscmh_fic_ver;
+               break;
+       case DTV_ATSCMH_PARADE_ID:
+               tvp->u.data = fe->dtv_property_cache.atscmh_parade_id;
+               break;
+       case DTV_ATSCMH_NOG:
+               tvp->u.data = fe->dtv_property_cache.atscmh_nog;
+               break;
+       case DTV_ATSCMH_TNOG:
+               tvp->u.data = fe->dtv_property_cache.atscmh_tnog;
+               break;
+       case DTV_ATSCMH_SGN:
+               tvp->u.data = fe->dtv_property_cache.atscmh_sgn;
+               break;
+       case DTV_ATSCMH_PRC:
+               tvp->u.data = fe->dtv_property_cache.atscmh_prc;
+               break;
+       case DTV_ATSCMH_RS_FRAME_MODE:
+               tvp->u.data = fe->dtv_property_cache.atscmh_rs_frame_mode;
+               break;
+       case DTV_ATSCMH_RS_FRAME_ENSEMBLE:
+               tvp->u.data = fe->dtv_property_cache.atscmh_rs_frame_ensemble;
+               break;
+       case DTV_ATSCMH_RS_CODE_MODE_PRI:
+               tvp->u.data = fe->dtv_property_cache.atscmh_rs_code_mode_pri;
+               break;
+       case DTV_ATSCMH_RS_CODE_MODE_SEC:
+               tvp->u.data = fe->dtv_property_cache.atscmh_rs_code_mode_sec;
+               break;
+       case DTV_ATSCMH_SCCC_BLOCK_MODE:
+               tvp->u.data = fe->dtv_property_cache.atscmh_sccc_block_mode;
+               break;
+       case DTV_ATSCMH_SCCC_CODE_MODE_A:
+               tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_a;
+               break;
+       case DTV_ATSCMH_SCCC_CODE_MODE_B:
+               tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_b;
+               break;
+       case DTV_ATSCMH_SCCC_CODE_MODE_C:
+               tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_c;
+               break;
+       case DTV_ATSCMH_SCCC_CODE_MODE_D:
+               tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_d;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       /* Allow the frontend to override outgoing properties */
+       if (fe->ops.get_property) {
+               r = fe->ops.get_property(fe, tvp);
+               if (r < 0)
+                       return r;
+       }
+
+       dtv_property_dump(tvp);
+
+       return 0;
+}
+
+static int dtv_set_frontend(struct dvb_frontend *fe);
+
+static bool is_dvbv3_delsys(u32 delsys)
+{
+       bool status;
+
+       status = (delsys == SYS_DVBT) || (delsys == SYS_DVBC_ANNEX_A) ||
+                (delsys == SYS_DVBS) || (delsys == SYS_ATSC);
+
+       return status;
+}
+
+static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system)
+{
+       int ncaps, i;
+       u32 delsys = SYS_UNDEFINED;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       enum dvbv3_emulation_type type;
+
+       /*
+        * It was reported that some old DVBv5 applications were
+        * filling delivery_system with SYS_UNDEFINED. If this happens,
+        * assume that the application wants to use the first supported
+        * delivery system.
+        */
+       if (c->delivery_system == SYS_UNDEFINED)
+               c->delivery_system = fe->ops.delsys[0];
+
+       if (desired_system == SYS_UNDEFINED) {
+               /*
+                * A DVBv3 call doesn't know what's the desired system.
+                * Also, DVBv3 applications don't know that ops.info->type
+                * could be changed, and they simply dies when it doesn't
+                * match.
+                * So, don't change the current delivery system, as it
+                * may be trying to do the wrong thing, like setting an
+                * ISDB-T frontend as DVB-T. Instead, find the closest
+                * DVBv3 system that matches the delivery system.
+                */
+               if (is_dvbv3_delsys(c->delivery_system)) {
+                       dprintk("%s() Using delivery system to %d\n",
+                               __func__, c->delivery_system);
+                       return 0;
+               }
+               type = dvbv3_type(c->delivery_system);
+               switch (type) {
+               case DVBV3_QPSK:
+                       desired_system = SYS_DVBS;
+                       break;
+               case DVBV3_QAM:
+                       desired_system = SYS_DVBC_ANNEX_A;
+                       break;
+               case DVBV3_ATSC:
+                       desired_system = SYS_ATSC;
+                       break;
+               case DVBV3_OFDM:
+                       desired_system = SYS_DVBT;
+                       break;
+               default:
+                       dprintk("%s(): This frontend doesn't support DVBv3 calls\n",
+                               __func__);
+                       return -EINVAL;
+               }
+               /*
+                * Get a delivery system that is compatible with DVBv3
+                * NOTE: in order for this to work with softwares like Kaffeine that
+                *      uses a DVBv5 call for DVB-S2 and a DVBv3 call to go back to
+                *      DVB-S, drivers that support both should put the SYS_DVBS entry
+                *      before the SYS_DVBS2, otherwise it won't switch back to DVB-S.
+                *      The real fix is that userspace applications should not use DVBv3
+                *      and not trust on calling FE_SET_FRONTEND to switch the delivery
+                *      system.
+                */
+               ncaps = 0;
+               while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+                       if (fe->ops.delsys[ncaps] == desired_system) {
+                               delsys = desired_system;
+                               break;
+                       }
+                       ncaps++;
+               }
+               if (delsys == SYS_UNDEFINED) {
+                       dprintk("%s() Couldn't find a delivery system that matches %d\n",
+                               __func__, desired_system);
+               }
+       } else {
+               /*
+                * This is a DVBv5 call. So, it likely knows the supported
+                * delivery systems.
+                */
+
+               /* Check if the desired delivery system is supported */
+               ncaps = 0;
+               while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+                       if (fe->ops.delsys[ncaps] == desired_system) {
+                               c->delivery_system = desired_system;
+                               dprintk("%s() Changing delivery system to %d\n",
+                                       __func__, desired_system);
+                               return 0;
+                       }
+                       ncaps++;
+               }
+               type = dvbv3_type(desired_system);
+
+               /*
+                * The delivery system is not supported. See if it can be
+                * emulated.
+                * The emulation only works if the desired system is one of the
+                * DVBv3 delivery systems
+                */
+               if (!is_dvbv3_delsys(desired_system)) {
+                       dprintk("%s() can't use a DVBv3 FE_SET_FRONTEND call on this frontend\n",
+                               __func__);
+                       return -EINVAL;
+               }
+
+               /*
+                * Get the last non-DVBv3 delivery system that has the same type
+                * of the desired system
+                */
+               ncaps = 0;
+               while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
+                       if ((dvbv3_type(fe->ops.delsys[ncaps]) == type) &&
+                           !is_dvbv3_delsys(fe->ops.delsys[ncaps]))
+                               delsys = fe->ops.delsys[ncaps];
+                       ncaps++;
+               }
+               /* There's nothing compatible with the desired delivery system */
+               if (delsys == SYS_UNDEFINED) {
+                       dprintk("%s() Incompatible DVBv3 FE_SET_FRONTEND call for this frontend\n",
+                               __func__);
+                       return -EINVAL;
+               }
+       }
+
+       c->delivery_system = delsys;
+
+       /*
+        * The DVBv3 or DVBv5 call is requesting a different system. So,
+        * emulation is needed.
+        *
+        * Emulate newer delivery systems like ISDBT, DVBT and DTMB
+        * for older DVBv5 applications. The emulation will try to use
+        * the auto mode for most things, and will assume that the desired
+        * delivery system is the last one at the ops.delsys[] array
+        */
+       dprintk("%s() Using delivery system %d emulated as if it were a %d\n",
+               __func__, delsys, desired_system);
+
+       /*
+        * For now, handles ISDB-T calls. More code may be needed here for the
+        * other emulated stuff
+        */
+       if (type == DVBV3_OFDM) {
+               if (c->delivery_system == SYS_ISDBT) {
+                       dprintk("%s() Using defaults for SYS_ISDBT\n",
+                               __func__);
+                       if (!c->bandwidth_hz)
+                               c->bandwidth_hz = 6000000;
+
+                       c->isdbt_partial_reception = 0;
+                       c->isdbt_sb_mode = 0;
+                       c->isdbt_sb_subchannel = 0;
+                       c->isdbt_sb_segment_idx = 0;
+                       c->isdbt_sb_segment_count = 0;
+                       c->isdbt_layer_enabled = 0;
+                       for (i = 0; i < 3; i++) {
+                               c->layer[i].fec = FEC_AUTO;
+                               c->layer[i].modulation = QAM_AUTO;
+                               c->layer[i].interleaving = 0;
+                               c->layer[i].segment_count = 0;
+                       }
+               }
+       }
+       dprintk("change delivery system on cache to %d\n", c->delivery_system);
+
+       return 0;
+}
+
+static int dtv_property_process_set(struct dvb_frontend *fe,
+                                   struct dtv_property *tvp,
+                                   struct file *file)
+{
+       int r = 0;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+       /* Allow the frontend to validate incoming properties */
+       if (fe->ops.set_property) {
+               r = fe->ops.set_property(fe, tvp);
+               if (r < 0)
+                       return r;
+       }
+
+       switch(tvp->cmd) {
+       case DTV_CLEAR:
+               /*
+                * Reset a cache of data specific to the frontend here. This does
+                * not effect hardware.
+                */
+               dvb_frontend_clear_cache(fe);
+               break;
+       case DTV_TUNE:
+               /* interpret the cache of data, build either a traditional frontend
+                * tunerequest so we can pass validation in the FE_SET_FRONTEND
+                * ioctl.
+                */
+               c->state = tvp->cmd;
+               dprintk("%s() Finalised property cache\n", __func__);
+
+               r = dtv_set_frontend(fe);
+               break;
+       case DTV_FREQUENCY:
+               c->frequency = tvp->u.data;
+               break;
+       case DTV_MODULATION:
+               c->modulation = tvp->u.data;
+               break;
+       case DTV_BANDWIDTH_HZ:
+               c->bandwidth_hz = tvp->u.data;
+               break;
+       case DTV_INVERSION:
+               c->inversion = tvp->u.data;
+               break;
+       case DTV_SYMBOL_RATE:
+               c->symbol_rate = tvp->u.data;
+               break;
+       case DTV_INNER_FEC:
+               c->fec_inner = tvp->u.data;
+               break;
+       case DTV_PILOT:
+               c->pilot = tvp->u.data;
+               break;
+       case DTV_ROLLOFF:
+               c->rolloff = tvp->u.data;
+               break;
+       case DTV_DELIVERY_SYSTEM:
+               r = set_delivery_system(fe, tvp->u.data);
+               break;
+       case DTV_VOLTAGE:
+               c->voltage = tvp->u.data;
+               r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE,
+                       (void *)c->voltage);
+               break;
+       case DTV_TONE:
+               c->sectone = tvp->u.data;
+               r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE,
+                       (void *)c->sectone);
+               break;
+       case DTV_CODE_RATE_HP:
+               c->code_rate_HP = tvp->u.data;
+               break;
+       case DTV_CODE_RATE_LP:
+               c->code_rate_LP = tvp->u.data;
+               break;
+       case DTV_GUARD_INTERVAL:
+               c->guard_interval = tvp->u.data;
+               break;
+       case DTV_TRANSMISSION_MODE:
+               c->transmission_mode = tvp->u.data;
+               break;
+       case DTV_HIERARCHY:
+               c->hierarchy = tvp->u.data;
+               break;
+       case DTV_INTERLEAVING:
+               c->interleaving = tvp->u.data;
+               break;
+
+       /* ISDB-T Support here */
+       case DTV_ISDBT_PARTIAL_RECEPTION:
+               c->isdbt_partial_reception = tvp->u.data;
+               break;
+       case DTV_ISDBT_SOUND_BROADCASTING:
+               c->isdbt_sb_mode = tvp->u.data;
+               break;
+       case DTV_ISDBT_SB_SUBCHANNEL_ID:
+               c->isdbt_sb_subchannel = tvp->u.data;
+               break;
+       case DTV_ISDBT_SB_SEGMENT_IDX:
+               c->isdbt_sb_segment_idx = tvp->u.data;
+               break;
+       case DTV_ISDBT_SB_SEGMENT_COUNT:
+               c->isdbt_sb_segment_count = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYER_ENABLED:
+               c->isdbt_layer_enabled = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERA_FEC:
+               c->layer[0].fec = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERA_MODULATION:
+               c->layer[0].modulation = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
+               c->layer[0].segment_count = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
+               c->layer[0].interleaving = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERB_FEC:
+               c->layer[1].fec = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERB_MODULATION:
+               c->layer[1].modulation = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
+               c->layer[1].segment_count = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
+               c->layer[1].interleaving = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERC_FEC:
+               c->layer[2].fec = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERC_MODULATION:
+               c->layer[2].modulation = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
+               c->layer[2].segment_count = tvp->u.data;
+               break;
+       case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
+               c->layer[2].interleaving = tvp->u.data;
+               break;
+       case DTV_ISDBS_TS_ID:
+               c->isdbs_ts_id = tvp->u.data;
+               break;
+       case DTV_DVBT2_PLP_ID:
+               c->dvbt2_plp_id = tvp->u.data;
+               break;
+
+       /* ATSC-MH */
+       case DTV_ATSCMH_PARADE_ID:
+               fe->dtv_property_cache.atscmh_parade_id = tvp->u.data;
+               break;
+       case DTV_ATSCMH_RS_FRAME_ENSEMBLE:
+               fe->dtv_property_cache.atscmh_rs_frame_ensemble = tvp->u.data;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return r;
+}
+
+static int dvb_frontend_ioctl(struct file *file,
+                       unsigned int cmd, void *parg)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_frontend *fe = dvbdev->priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       int err = -EOPNOTSUPP;
+
+       dprintk("%s (%d)\n", __func__, _IOC_NR(cmd));
+
+       if (fepriv->exit != DVB_FE_NO_EXIT)
+               return -ENODEV;
+
+       if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
+           (_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT ||
+            cmd == FE_DISEQC_RECV_SLAVE_REPLY))
+               return -EPERM;
+
+       if (down_interruptible (&fepriv->sem))
+               return -ERESTARTSYS;
+
+       if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
+               err = dvb_frontend_ioctl_properties(file, cmd, parg);
+       else {
+               c->state = DTV_UNDEFINED;
+               err = dvb_frontend_ioctl_legacy(file, cmd, parg);
+       }
+
+       up(&fepriv->sem);
+       return err;
+}
+
+static int dvb_frontend_ioctl_properties(struct file *file,
+                       unsigned int cmd, void *parg)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_frontend *fe = dvbdev->priv;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int err = 0;
+
+       struct dtv_properties *tvps = NULL;
+       struct dtv_property *tvp = NULL;
+       int i;
+
+       dprintk("%s\n", __func__);
+
+       if(cmd == FE_SET_PROPERTY) {
+               tvps = (struct dtv_properties __user *)parg;
+
+               dprintk("%s() properties.num = %d\n", __func__, tvps->num);
+               dprintk("%s() properties.props = %p\n", __func__, tvps->props);
+
+               /* Put an arbitrary limit on the number of messages that can
+                * be sent at once */
+               if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
+                       return -EINVAL;
+
+               tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
+               if (!tvp) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+
+               if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
+                       err = -EFAULT;
+                       goto out;
+               }
+
+               for (i = 0; i < tvps->num; i++) {
+                       err = dtv_property_process_set(fe, tvp + i, file);
+                       if (err < 0)
+                               goto out;
+                       (tvp + i)->result = err;
+               }
+
+               if (c->state == DTV_TUNE)
+                       dprintk("%s() Property cache is full, tuning\n", __func__);
+
+       } else
+       if(cmd == FE_GET_PROPERTY) {
+               tvps = (struct dtv_properties __user *)parg;
+
+               dprintk("%s() properties.num = %d\n", __func__, tvps->num);
+               dprintk("%s() properties.props = %p\n", __func__, tvps->props);
+
+               /* Put an arbitrary limit on the number of messages that can
+                * be sent at once */
+               if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
+                       return -EINVAL;
+
+               tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
+               if (!tvp) {
+                       err = -ENOMEM;
+                       goto out;
+               }
+
+               if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
+                       err = -EFAULT;
+                       goto out;
+               }
+
+               /*
+                * Fills the cache out struct with the cache contents, plus
+                * the data retrieved from get_frontend, if the frontend
+                * is not idle. Otherwise, returns the cached content
+                */
+               if (fepriv->state != FESTATE_IDLE) {
+                       err = dtv_get_frontend(fe, NULL);
+                       if (err < 0)
+                               goto out;
+               }
+               for (i = 0; i < tvps->num; i++) {
+                       err = dtv_property_process_get(fe, c, tvp + i, file);
+                       if (err < 0)
+                               goto out;
+                       (tvp + i)->result = err;
+               }
+
+               if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
+                       err = -EFAULT;
+                       goto out;
+               }
+
+       } else
+               err = -EOPNOTSUPP;
+
+out:
+       kfree(tvp);
+       return err;
+}
+
+static int dtv_set_frontend(struct dvb_frontend *fe)
+{
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct dvb_frontend_tune_settings fetunesettings;
+       u32 rolloff = 0;
+
+       if (dvb_frontend_check_parameters(fe) < 0)
+               return -EINVAL;
+
+       /*
+        * Initialize output parameters to match the values given by
+        * the user. FE_SET_FRONTEND triggers an initial frontend event
+        * with status = 0, which copies output parameters to userspace.
+        */
+       dtv_property_legacy_params_sync(fe, &fepriv->parameters_out);
+
+       /*
+        * Be sure that the bandwidth will be filled for all
+        * non-satellite systems, as tuners need to know what
+        * low pass/Nyquist half filter should be applied, in
+        * order to avoid inter-channel noise.
+        *
+        * ISDB-T and DVB-T/T2 already sets bandwidth.
+        * ATSC and DVB-C don't set, so, the core should fill it.
+        *
+        * On DVB-C Annex A and C, the bandwidth is a function of
+        * the roll-off and symbol rate. Annex B defines different
+        * roll-off factors depending on the modulation. Fortunately,
+        * Annex B is only used with 6MHz, so there's no need to
+        * calculate it.
+        *
+        * While not officially supported, a side effect of handling it at
+        * the cache level is that a program could retrieve the bandwidth
+        * via DTV_BANDWIDTH_HZ, which may be useful for test programs.
+        */
+       switch (c->delivery_system) {
+       case SYS_ATSC:
+       case SYS_DVBC_ANNEX_B:
+               c->bandwidth_hz = 6000000;
+               break;
+       case SYS_DVBC_ANNEX_A:
+               rolloff = 115;
+               break;
+       case SYS_DVBC_ANNEX_C:
+               rolloff = 113;
+               break;
+       default:
+               break;
+       }
+       if (rolloff)
+               c->bandwidth_hz = (c->symbol_rate * rolloff) / 100;
+
+       /* force auto frequency inversion if requested */
+       if (dvb_force_auto_inversion)
+               c->inversion = INVERSION_AUTO;
+
+       /*
+        * without hierarchical coding code_rate_LP is irrelevant,
+        * so we tolerate the otherwise invalid FEC_NONE setting
+        */
+       if (c->hierarchy == HIERARCHY_NONE && c->code_rate_LP == FEC_NONE)
+               c->code_rate_LP = FEC_AUTO;
+
+       /* get frontend-specific tuning settings */
+       memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
+       if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) {
+               fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
+               fepriv->max_drift = fetunesettings.max_drift;
+               fepriv->step_size = fetunesettings.step_size;
+       } else {
+               /* default values */
+               switch (c->delivery_system) {
+               case SYS_DVBS:
+               case SYS_DVBS2:
+               case SYS_ISDBS:
+               case SYS_TURBO:
+               case SYS_DVBC_ANNEX_A:
+               case SYS_DVBC_ANNEX_C:
+                       fepriv->min_delay = HZ / 20;
+                       fepriv->step_size = c->symbol_rate / 16000;
+                       fepriv->max_drift = c->symbol_rate / 2000;
+                       break;
+               case SYS_DVBT:
+               case SYS_DVBT2:
+               case SYS_ISDBT:
+               case SYS_DTMB:
+                       fepriv->min_delay = HZ / 20;
+                       fepriv->step_size = fe->ops.info.frequency_stepsize * 2;
+                       fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
+                       break;
+               default:
+                       /*
+                        * FIXME: This sounds wrong! if freqency_stepsize is
+                        * defined by the frontend, why not use it???
+                        */
+                       fepriv->min_delay = HZ / 20;
+                       fepriv->step_size = 0; /* no zigzag */
+                       fepriv->max_drift = 0;
+                       break;
+               }
+       }
+       if (dvb_override_tune_delay > 0)
+               fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000;
+
+       fepriv->state = FESTATE_RETUNE;
+
+       /* Request the search algorithm to search */
+       fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
+
+       dvb_frontend_clear_events(fe);
+       dvb_frontend_add_event(fe, 0);
+       dvb_frontend_wakeup(fe);
+       fepriv->status = 0;
+
+       return 0;
+}
+
+
+static int dvb_frontend_ioctl_legacy(struct file *file,
+                       unsigned int cmd, void *parg)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_frontend *fe = dvbdev->priv;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int err = -EOPNOTSUPP;
+
+       switch (cmd) {
+       case FE_GET_INFO: {
+               struct dvb_frontend_info* info = parg;
+
+               memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
+               dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max);
+
+               /*
+                * Associate the 4 delivery systems supported by DVBv3
+                * API with their DVBv5 counterpart. For the other standards,
+                * use the closest type, assuming that it would hopefully
+                * work with a DVBv3 application.
+                * It should be noticed that, on multi-frontend devices with
+                * different types (terrestrial and cable, for example),
+                * a pure DVBv3 application won't be able to use all delivery
+                * systems. Yet, changing the DVBv5 cache to the other delivery
+                * system should be enough for making it work.
+                */
+               switch (dvbv3_type(c->delivery_system)) {
+               case DVBV3_QPSK:
+                       info->type = FE_QPSK;
+                       break;
+               case DVBV3_ATSC:
+                       info->type = FE_ATSC;
+                       break;
+               case DVBV3_QAM:
+                       info->type = FE_QAM;
+                       break;
+               case DVBV3_OFDM:
+                       info->type = FE_OFDM;
+                       break;
+               default:
+                       printk(KERN_ERR
+                              "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n",
+                              __func__, c->delivery_system);
+                       fe->ops.info.type = FE_OFDM;
+               }
+               dprintk("current delivery system on cache: %d, V3 type: %d\n",
+                       c->delivery_system, fe->ops.info.type);
+
+               /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
+                * do it, it is done for it. */
+               info->caps |= FE_CAN_INVERSION_AUTO;
+               err = 0;
+               break;
+       }
+
+       case FE_READ_STATUS: {
+               fe_status_t* status = parg;
+
+               /* if retune was requested but hasn't occurred yet, prevent
+                * that user get signal state from previous tuning */
+               if (fepriv->state == FESTATE_RETUNE ||
+                   fepriv->state == FESTATE_ERROR) {
+                       err=0;
+                       *status = 0;
+                       break;
+               }
+
+               if (fe->ops.read_status)
+                       err = fe->ops.read_status(fe, status);
+               break;
+       }
+       case FE_READ_BER:
+               if (fe->ops.read_ber)
+                       err = fe->ops.read_ber(fe, (__u32*) parg);
+               break;
+
+       case FE_READ_SIGNAL_STRENGTH:
+               if (fe->ops.read_signal_strength)
+                       err = fe->ops.read_signal_strength(fe, (__u16*) parg);
+               break;
+
+       case FE_READ_SNR:
+               if (fe->ops.read_snr)
+                       err = fe->ops.read_snr(fe, (__u16*) parg);
+               break;
+
+       case FE_READ_UNCORRECTED_BLOCKS:
+               if (fe->ops.read_ucblocks)
+                       err = fe->ops.read_ucblocks(fe, (__u32*) parg);
+               break;
+
+
+       case FE_DISEQC_RESET_OVERLOAD:
+               if (fe->ops.diseqc_reset_overload) {
+                       err = fe->ops.diseqc_reset_overload(fe);
+                       fepriv->state = FESTATE_DISEQC;
+                       fepriv->status = 0;
+               }
+               break;
+
+       case FE_DISEQC_SEND_MASTER_CMD:
+               if (fe->ops.diseqc_send_master_cmd) {
+                       err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
+                       fepriv->state = FESTATE_DISEQC;
+                       fepriv->status = 0;
+               }
+               break;
+
+       case FE_DISEQC_SEND_BURST:
+               if (fe->ops.diseqc_send_burst) {
+                       err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
+                       fepriv->state = FESTATE_DISEQC;
+                       fepriv->status = 0;
+               }
+               break;
+
+       case FE_SET_TONE:
+               if (fe->ops.set_tone) {
+                       err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg);
+                       fepriv->tone = (fe_sec_tone_mode_t) parg;
+                       fepriv->state = FESTATE_DISEQC;
+                       fepriv->status = 0;
+               }
+               break;
+
+       case FE_SET_VOLTAGE:
+               if (fe->ops.set_voltage) {
+                       err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg);
+                       fepriv->voltage = (fe_sec_voltage_t) parg;
+                       fepriv->state = FESTATE_DISEQC;
+                       fepriv->status = 0;
+               }
+               break;
+
+       case FE_DISHNETWORK_SEND_LEGACY_CMD:
+               if (fe->ops.dishnetwork_send_legacy_command) {
+                       err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg);
+                       fepriv->state = FESTATE_DISEQC;
+                       fepriv->status = 0;
+               } else if (fe->ops.set_voltage) {
+                       /*
+                        * NOTE: This is a fallback condition.  Some frontends
+                        * (stv0299 for instance) take longer than 8msec to
+                        * respond to a set_voltage command.  Those switches
+                        * need custom routines to switch properly.  For all
+                        * other frontends, the following should work ok.
+                        * Dish network legacy switches (as used by Dish500)
+                        * are controlled by sending 9-bit command words
+                        * spaced 8msec apart.
+                        * the actual command word is switch/port dependent
+                        * so it is up to the userspace application to send
+                        * the right command.
+                        * The command must always start with a '0' after
+                        * initialization, so parg is 8 bits and does not
+                        * include the initialization or start bit
+                        */
+                       unsigned long swcmd = ((unsigned long) parg) << 1;
+                       struct timeval nexttime;
+                       struct timeval tv[10];
+                       int i;
+                       u8 last = 1;
+                       if (dvb_frontend_debug)
+                               printk("%s switch command: 0x%04lx\n", __func__, swcmd);
+                       do_gettimeofday(&nexttime);
+                       if (dvb_frontend_debug)
+                               memcpy(&tv[0], &nexttime, sizeof(struct timeval));
+                       /* before sending a command, initialize by sending
+                        * a 32ms 18V to the switch
+                        */
+                       fe->ops.set_voltage(fe, SEC_VOLTAGE_18);
+                       dvb_frontend_sleep_until(&nexttime, 32000);
+
+                       for (i = 0; i < 9; i++) {
+                               if (dvb_frontend_debug)
+                                       do_gettimeofday(&tv[i + 1]);
+                               if ((swcmd & 0x01) != last) {
+                                       /* set voltage to (last ? 13V : 18V) */
+                                       fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
+                                       last = (last) ? 0 : 1;
+                               }
+                               swcmd = swcmd >> 1;
+                               if (i != 8)
+                                       dvb_frontend_sleep_until(&nexttime, 8000);
+                       }
+                       if (dvb_frontend_debug) {
+                               printk("%s(%d): switch delay (should be 32k followed by all 8k\n",
+                                       __func__, fe->dvb->num);
+                               for (i = 1; i < 10; i++)
+                                       printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));
+                       }
+                       err = 0;
+                       fepriv->state = FESTATE_DISEQC;
+                       fepriv->status = 0;
+               }
+               break;
+
+       case FE_DISEQC_RECV_SLAVE_REPLY:
+               if (fe->ops.diseqc_recv_slave_reply)
+                       err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
+               break;
+
+       case FE_ENABLE_HIGH_LNB_VOLTAGE:
+               if (fe->ops.enable_high_lnb_voltage)
+                       err = fe->ops.enable_high_lnb_voltage(fe, (long) parg);
+               break;
+
+       case FE_SET_FRONTEND:
+               err = set_delivery_system(fe, SYS_UNDEFINED);
+               if (err)
+                       break;
+
+               err = dtv_property_cache_sync(fe, c, parg);
+               if (err)
+                       break;
+               err = dtv_set_frontend(fe);
+               break;
+       case FE_GET_EVENT:
+               err = dvb_frontend_get_event (fe, parg, file->f_flags);
+               break;
+
+       case FE_GET_FRONTEND:
+               err = dtv_get_frontend(fe, parg);
+               break;
+
+       case FE_SET_FRONTEND_TUNE_MODE:
+               fepriv->tune_mode_flags = (unsigned long) parg;
+               err = 0;
+               break;
+       };
+
+       return err;
+}
+
+
+static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_frontend *fe = dvbdev->priv;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+
+       dprintk ("%s\n", __func__);
+
+       poll_wait (file, &fepriv->events.wait_queue, wait);
+
+       if (fepriv->events.eventw != fepriv->events.eventr)
+               return (POLLIN | POLLRDNORM | POLLPRI);
+
+       return 0;
+}
+
+static int dvb_frontend_open(struct inode *inode, struct file *file)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_frontend *fe = dvbdev->priv;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       struct dvb_adapter *adapter = fe->dvb;
+       int ret;
+
+       dprintk ("%s\n", __func__);
+       if (fepriv->exit == DVB_FE_DEVICE_REMOVED)
+               return -ENODEV;
+
+       if (adapter->mfe_shared) {
+               mutex_lock (&adapter->mfe_lock);
+
+               if (adapter->mfe_dvbdev == NULL)
+                       adapter->mfe_dvbdev = dvbdev;
+
+               else if (adapter->mfe_dvbdev != dvbdev) {
+                       struct dvb_device
+                               *mfedev = adapter->mfe_dvbdev;
+                       struct dvb_frontend
+                               *mfe = mfedev->priv;
+                       struct dvb_frontend_private
+                               *mfepriv = mfe->frontend_priv;
+                       int mferetry = (dvb_mfe_wait_time << 1);
+
+                       mutex_unlock (&adapter->mfe_lock);
+                       while (mferetry-- && (mfedev->users != -1 ||
+                                       mfepriv->thread != NULL)) {
+                               if(msleep_interruptible(500)) {
+                                       if(signal_pending(current))
+                                               return -EINTR;
+                               }
+                       }
+
+                       mutex_lock (&adapter->mfe_lock);
+                       if(adapter->mfe_dvbdev != dvbdev) {
+                               mfedev = adapter->mfe_dvbdev;
+                               mfe = mfedev->priv;
+                               mfepriv = mfe->frontend_priv;
+                               if (mfedev->users != -1 ||
+                                               mfepriv->thread != NULL) {
+                                       mutex_unlock (&adapter->mfe_lock);
+                                       return -EBUSY;
+                               }
+                               adapter->mfe_dvbdev = dvbdev;
+                       }
+               }
+       }
+
+       if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
+               if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
+                       goto err0;
+
+               /* If we took control of the bus, we need to force
+                  reinitialization.  This is because many ts_bus_ctrl()
+                  functions strobe the RESET pin on the demod, and if the
+                  frontend thread already exists then the dvb_init() routine
+                  won't get called (which is what usually does initial
+                  register configuration). */
+               fepriv->reinitialise = 1;
+       }
+
+       if ((ret = dvb_generic_open (inode, file)) < 0)
+               goto err1;
+
+       if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+               /* normal tune mode when opened R/W */
+               fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
+               fepriv->tone = -1;
+               fepriv->voltage = -1;
+
+               ret = dvb_frontend_start (fe);
+               if (ret)
+                       goto err2;
+
+               /*  empty event queue */
+               fepriv->events.eventr = fepriv->events.eventw = 0;
+       }
+
+       if (adapter->mfe_shared)
+               mutex_unlock (&adapter->mfe_lock);
+       return ret;
+
+err2:
+       dvb_generic_release(inode, file);
+err1:
+       if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
+               fe->ops.ts_bus_ctrl(fe, 0);
+err0:
+       if (adapter->mfe_shared)
+               mutex_unlock (&adapter->mfe_lock);
+       return ret;
+}
+
+static int dvb_frontend_release(struct inode *inode, struct file *file)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_frontend *fe = dvbdev->priv;
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       int ret;
+
+       dprintk ("%s\n", __func__);
+
+       if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+               fepriv->release_jiffies = jiffies;
+               mb();
+       }
+
+       ret = dvb_generic_release (inode, file);
+
+       if (dvbdev->users == -1) {
+               wake_up(&fepriv->wait_queue);
+               if (fepriv->exit != DVB_FE_NO_EXIT) {
+                       fops_put(file->f_op);
+                       file->f_op = NULL;
+                       wake_up(&dvbdev->wait_queue);
+               }
+               if (fe->ops.ts_bus_ctrl)
+                       fe->ops.ts_bus_ctrl(fe, 0);
+       }
+
+       return ret;
+}
+
+static const struct file_operations dvb_frontend_fops = {
+       .owner          = THIS_MODULE,
+       .unlocked_ioctl = dvb_generic_ioctl,
+       .poll           = dvb_frontend_poll,
+       .open           = dvb_frontend_open,
+       .release        = dvb_frontend_release,
+       .llseek         = noop_llseek,
+};
+
+int dvb_register_frontend(struct dvb_adapter* dvb,
+                         struct dvb_frontend* fe)
+{
+       struct dvb_frontend_private *fepriv;
+       static const struct dvb_device dvbdev_template = {
+               .users = ~0,
+               .writers = 1,
+               .readers = (~0)-1,
+               .fops = &dvb_frontend_fops,
+               .kernel_ioctl = dvb_frontend_ioctl
+       };
+
+       dprintk ("%s\n", __func__);
+
+       if (mutex_lock_interruptible(&frontend_mutex))
+               return -ERESTARTSYS;
+
+       fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL);
+       if (fe->frontend_priv == NULL) {
+               mutex_unlock(&frontend_mutex);
+               return -ENOMEM;
+       }
+       fepriv = fe->frontend_priv;
+
+       sema_init(&fepriv->sem, 1);
+       init_waitqueue_head (&fepriv->wait_queue);
+       init_waitqueue_head (&fepriv->events.wait_queue);
+       mutex_init(&fepriv->events.mtx);
+       fe->dvb = dvb;
+       fepriv->inversion = INVERSION_OFF;
+
+       printk ("DVB: registering adapter %i frontend %i (%s)...\n",
+               fe->dvb->num,
+               fe->id,
+               fe->ops.info.name);
+
+       dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
+                            fe, DVB_DEVICE_FRONTEND);
+
+       /*
+        * Initialize the cache to the proper values according with the
+        * first supported delivery system (ops->delsys[0])
+        */
+
+        fe->dtv_property_cache.delivery_system = fe->ops.delsys[0];
+       dvb_frontend_clear_cache(fe);
+
+       mutex_unlock(&frontend_mutex);
+       return 0;
+}
+EXPORT_SYMBOL(dvb_register_frontend);
+
+int dvb_unregister_frontend(struct dvb_frontend* fe)
+{
+       struct dvb_frontend_private *fepriv = fe->frontend_priv;
+       dprintk ("%s\n", __func__);
+
+       mutex_lock(&frontend_mutex);
+       dvb_frontend_stop (fe);
+       mutex_unlock(&frontend_mutex);
+
+       if (fepriv->dvbdev->users < -1)
+               wait_event(fepriv->dvbdev->wait_queue,
+                               fepriv->dvbdev->users==-1);
+
+       mutex_lock(&frontend_mutex);
+       dvb_unregister_device (fepriv->dvbdev);
+
+       /* fe is invalid now */
+       kfree(fepriv);
+       mutex_unlock(&frontend_mutex);
+       return 0;
+}
+EXPORT_SYMBOL(dvb_unregister_frontend);
+
+#ifdef CONFIG_MEDIA_ATTACH
+void dvb_frontend_detach(struct dvb_frontend* fe)
+{
+       void *ptr;
+
+       if (fe->ops.release_sec) {
+               fe->ops.release_sec(fe);
+               symbol_put_addr(fe->ops.release_sec);
+       }
+       if (fe->ops.tuner_ops.release) {
+               fe->ops.tuner_ops.release(fe);
+               symbol_put_addr(fe->ops.tuner_ops.release);
+       }
+       if (fe->ops.analog_ops.release) {
+               fe->ops.analog_ops.release(fe);
+               symbol_put_addr(fe->ops.analog_ops.release);
+       }
+       ptr = (void*)fe->ops.release;
+       if (ptr) {
+               fe->ops.release(fe);
+               symbol_put_addr(ptr);
+       }
+}
+#else
+void dvb_frontend_detach(struct dvb_frontend* fe)
+{
+       if (fe->ops.release_sec)
+               fe->ops.release_sec(fe);
+       if (fe->ops.tuner_ops.release)
+               fe->ops.tuner_ops.release(fe);
+       if (fe->ops.analog_ops.release)
+               fe->ops.analog_ops.release(fe);
+       if (fe->ops.release)
+               fe->ops.release(fe);
+}
+#endif
+EXPORT_SYMBOL(dvb_frontend_detach);
diff --git a/drivers/media/dvb-core/dvb_frontend.h b/drivers/media/dvb-core/dvb_frontend.h
new file mode 100644 (file)
index 0000000..de410cc
--- /dev/null
@@ -0,0 +1,425 @@
+/*
+ * dvb_frontend.h
+ *
+ * Copyright (C) 2001 convergence integrated media GmbH
+ * Copyright (C) 2004 convergence GmbH
+ *
+ * Written by Ralph Metzler
+ * Overhauled by Holger Waechtler
+ * Kernel I2C stuff by Michael Hunold <hunold@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.
+ *
+ */
+
+#ifndef _DVB_FRONTEND_H_
+#define _DVB_FRONTEND_H_
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/ioctl.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+
+#include <linux/dvb/frontend.h>
+
+#include "dvbdev.h"
+
+/*
+ * Maximum number of Delivery systems per frontend. It
+ * should be smaller or equal to 32
+ */
+#define MAX_DELSYS     8
+
+struct dvb_frontend_tune_settings {
+       int min_delay_ms;
+       int step_size;
+       int max_drift;
+};
+
+struct dvb_frontend;
+
+struct dvb_tuner_info {
+       char name[128];
+
+       u32 frequency_min;
+       u32 frequency_max;
+       u32 frequency_step;
+
+       u32 bandwidth_min;
+       u32 bandwidth_max;
+       u32 bandwidth_step;
+};
+
+struct analog_parameters {
+       unsigned int frequency;
+       unsigned int mode;
+       unsigned int audmode;
+       u64 std;
+};
+
+enum dvbfe_modcod {
+       DVBFE_MODCOD_DUMMY_PLFRAME      = 0,
+       DVBFE_MODCOD_QPSK_1_4,
+       DVBFE_MODCOD_QPSK_1_3,
+       DVBFE_MODCOD_QPSK_2_5,
+       DVBFE_MODCOD_QPSK_1_2,
+       DVBFE_MODCOD_QPSK_3_5,
+       DVBFE_MODCOD_QPSK_2_3,
+       DVBFE_MODCOD_QPSK_3_4,
+       DVBFE_MODCOD_QPSK_4_5,
+       DVBFE_MODCOD_QPSK_5_6,
+       DVBFE_MODCOD_QPSK_8_9,
+       DVBFE_MODCOD_QPSK_9_10,
+       DVBFE_MODCOD_8PSK_3_5,
+       DVBFE_MODCOD_8PSK_2_3,
+       DVBFE_MODCOD_8PSK_3_4,
+       DVBFE_MODCOD_8PSK_5_6,
+       DVBFE_MODCOD_8PSK_8_9,
+       DVBFE_MODCOD_8PSK_9_10,
+       DVBFE_MODCOD_16APSK_2_3,
+       DVBFE_MODCOD_16APSK_3_4,
+       DVBFE_MODCOD_16APSK_4_5,
+       DVBFE_MODCOD_16APSK_5_6,
+       DVBFE_MODCOD_16APSK_8_9,
+       DVBFE_MODCOD_16APSK_9_10,
+       DVBFE_MODCOD_32APSK_3_4,
+       DVBFE_MODCOD_32APSK_4_5,
+       DVBFE_MODCOD_32APSK_5_6,
+       DVBFE_MODCOD_32APSK_8_9,
+       DVBFE_MODCOD_32APSK_9_10,
+       DVBFE_MODCOD_RESERVED_1,
+       DVBFE_MODCOD_BPSK_1_3,
+       DVBFE_MODCOD_BPSK_1_4,
+       DVBFE_MODCOD_RESERVED_2
+};
+
+enum tuner_param {
+       DVBFE_TUNER_FREQUENCY           = (1 <<  0),
+       DVBFE_TUNER_TUNERSTEP           = (1 <<  1),
+       DVBFE_TUNER_IFFREQ              = (1 <<  2),
+       DVBFE_TUNER_BANDWIDTH           = (1 <<  3),
+       DVBFE_TUNER_REFCLOCK            = (1 <<  4),
+       DVBFE_TUNER_IQSENSE             = (1 <<  5),
+       DVBFE_TUNER_DUMMY               = (1 << 31)
+};
+
+/*
+ * ALGO_HW: (Hardware Algorithm)
+ * ----------------------------------------------------------------
+ * Devices that support this algorithm do everything in hardware
+ * and no software support is needed to handle them.
+ * Requesting these devices to LOCK is the only thing required,
+ * device is supposed to do everything in the hardware.
+ *
+ * ALGO_SW: (Software Algorithm)
+ * ----------------------------------------------------------------
+ * These are dumb devices, that require software to do everything
+ *
+ * ALGO_CUSTOM: (Customizable Agorithm)
+ * ----------------------------------------------------------------
+ * Devices having this algorithm can be customized to have specific
+ * algorithms in the frontend driver, rather than simply doing a
+ * software zig-zag. In this case the zigzag maybe hardware assisted
+ * or it maybe completely done in hardware. In all cases, usage of
+ * this algorithm, in conjunction with the search and track
+ * callbacks, utilizes the driver specific algorithm.
+ *
+ * ALGO_RECOVERY: (Recovery Algorithm)
+ * ----------------------------------------------------------------
+ * These devices have AUTO recovery capabilities from LOCK failure
+ */
+enum dvbfe_algo {
+       DVBFE_ALGO_HW                   = (1 <<  0),
+       DVBFE_ALGO_SW                   = (1 <<  1),
+       DVBFE_ALGO_CUSTOM               = (1 <<  2),
+       DVBFE_ALGO_RECOVERY             = (1 << 31)
+};
+
+struct tuner_state {
+       u32 frequency;
+       u32 tunerstep;
+       u32 ifreq;
+       u32 bandwidth;
+       u32 iqsense;
+       u32 refclock;
+};
+
+/*
+ * search callback possible return status
+ *
+ * DVBFE_ALGO_SEARCH_SUCCESS
+ * The frontend search algorithm completed and returned successfully
+ *
+ * DVBFE_ALGO_SEARCH_ASLEEP
+ * The frontend search algorithm is sleeping
+ *
+ * DVBFE_ALGO_SEARCH_FAILED
+ * The frontend search for a signal failed
+ *
+ * DVBFE_ALGO_SEARCH_INVALID
+ * The frontend search algorith was probably supplied with invalid
+ * parameters and the search is an invalid one
+ *
+ * DVBFE_ALGO_SEARCH_ERROR
+ * The frontend search algorithm failed due to some error
+ *
+ * DVBFE_ALGO_SEARCH_AGAIN
+ * The frontend search algorithm was requested to search again
+ */
+enum dvbfe_search {
+       DVBFE_ALGO_SEARCH_SUCCESS       = (1 <<  0),
+       DVBFE_ALGO_SEARCH_ASLEEP        = (1 <<  1),
+       DVBFE_ALGO_SEARCH_FAILED        = (1 <<  2),
+       DVBFE_ALGO_SEARCH_INVALID       = (1 <<  3),
+       DVBFE_ALGO_SEARCH_AGAIN         = (1 <<  4),
+       DVBFE_ALGO_SEARCH_ERROR         = (1 << 31),
+};
+
+
+struct dvb_tuner_ops {
+
+       struct dvb_tuner_info info;
+
+       int (*release)(struct dvb_frontend *fe);
+       int (*init)(struct dvb_frontend *fe);
+       int (*sleep)(struct dvb_frontend *fe);
+
+       /** This is for simple PLLs - set all parameters in one go. */
+       int (*set_params)(struct dvb_frontend *fe);
+       int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p);
+
+       /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
+       int (*calc_regs)(struct dvb_frontend *fe, u8 *buf, int buf_len);
+
+       /** This is to allow setting tuner-specific configs */
+       int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
+
+       int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
+       int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
+       int (*get_if_frequency)(struct dvb_frontend *fe, u32 *frequency);
+
+#define TUNER_STATUS_LOCKED 1
+#define TUNER_STATUS_STEREO 2
+       int (*get_status)(struct dvb_frontend *fe, u32 *status);
+       int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
+       int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
+
+       /** These are provided separately from set_params in order to facilitate silicon
+        * tuners which require sophisticated tuning loops, controlling each parameter separately. */
+       int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
+       int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
+
+       /*
+        * These are provided separately from set_params in order to facilitate silicon
+        * tuners which require sophisticated tuning loops, controlling each parameter separately.
+        */
+       int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
+       int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
+};
+
+struct analog_demod_info {
+       char *name;
+};
+
+struct analog_demod_ops {
+
+       struct analog_demod_info info;
+
+       void (*set_params)(struct dvb_frontend *fe,
+                          struct analog_parameters *params);
+       int  (*has_signal)(struct dvb_frontend *fe);
+       int  (*get_afc)(struct dvb_frontend *fe);
+       void (*tuner_status)(struct dvb_frontend *fe);
+       void (*standby)(struct dvb_frontend *fe);
+       void (*release)(struct dvb_frontend *fe);
+       int  (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable);
+
+       /** This is to allow setting tuner-specific configuration */
+       int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
+};
+
+struct dtv_frontend_properties;
+
+struct dvb_frontend_ops {
+
+       struct dvb_frontend_info info;
+
+       u8 delsys[MAX_DELSYS];
+
+       void (*release)(struct dvb_frontend* fe);
+       void (*release_sec)(struct dvb_frontend* fe);
+
+       int (*init)(struct dvb_frontend* fe);
+       int (*sleep)(struct dvb_frontend* fe);
+
+       int (*write)(struct dvb_frontend* fe, const u8 buf[], int len);
+
+       /* if this is set, it overrides the default swzigzag */
+       int (*tune)(struct dvb_frontend* fe,
+                   bool re_tune,
+                   unsigned int mode_flags,
+                   unsigned int *delay,
+                   fe_status_t *status);
+       /* get frontend tuning algorithm from the module */
+       enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe);
+
+       /* these two are only used for the swzigzag code */
+       int (*set_frontend)(struct dvb_frontend *fe);
+       int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
+
+       int (*get_frontend)(struct dvb_frontend *fe);
+
+       int (*read_status)(struct dvb_frontend* fe, fe_status_t* status);
+       int (*read_ber)(struct dvb_frontend* fe, u32* ber);
+       int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
+       int (*read_snr)(struct dvb_frontend* fe, u16* snr);
+       int (*read_ucblocks)(struct dvb_frontend* fe, u32* ucblocks);
+
+       int (*diseqc_reset_overload)(struct dvb_frontend* fe);
+       int (*diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd);
+       int (*diseqc_recv_slave_reply)(struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply);
+       int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
+       int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
+       int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
+       int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
+       int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
+       int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
+       int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
+
+       /* These callbacks are for devices that implement their own
+        * tuning algorithms, rather than a simple swzigzag
+        */
+       enum dvbfe_search (*search)(struct dvb_frontend *fe);
+
+       struct dvb_tuner_ops tuner_ops;
+       struct analog_demod_ops analog_ops;
+
+       int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
+       int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
+};
+
+#ifdef __DVB_CORE__
+#define MAX_EVENT 8
+
+struct dvb_fe_events {
+       struct dvb_frontend_event events[MAX_EVENT];
+       int                       eventw;
+       int                       eventr;
+       int                       overflow;
+       wait_queue_head_t         wait_queue;
+       struct mutex              mtx;
+};
+#endif
+
+struct dtv_frontend_properties {
+
+       /* Cache State */
+       u32                     state;
+
+       u32                     frequency;
+       fe_modulation_t         modulation;
+
+       fe_sec_voltage_t        voltage;
+       fe_sec_tone_mode_t      sectone;
+       fe_spectral_inversion_t inversion;
+       fe_code_rate_t          fec_inner;
+       fe_transmit_mode_t      transmission_mode;
+       u32                     bandwidth_hz;   /* 0 = AUTO */
+       fe_guard_interval_t     guard_interval;
+       fe_hierarchy_t          hierarchy;
+       u32                     symbol_rate;
+       fe_code_rate_t          code_rate_HP;
+       fe_code_rate_t          code_rate_LP;
+
+       fe_pilot_t              pilot;
+       fe_rolloff_t            rolloff;
+
+       fe_delivery_system_t    delivery_system;
+
+       enum fe_interleaving    interleaving;
+
+       /* ISDB-T specifics */
+       u8                      isdbt_partial_reception;
+       u8                      isdbt_sb_mode;
+       u8                      isdbt_sb_subchannel;
+       u32                     isdbt_sb_segment_idx;
+       u32                     isdbt_sb_segment_count;
+       u8                      isdbt_layer_enabled;
+       struct {
+           u8                  segment_count;
+           fe_code_rate_t      fec;
+           fe_modulation_t     modulation;
+           u8                  interleaving;
+       } layer[3];
+
+       /* ISDB-T specifics */
+       u32                     isdbs_ts_id;
+
+       /* DVB-T2 specifics */
+       u32                     dvbt2_plp_id;
+
+       /* ATSC-MH specifics */
+       u8                      atscmh_fic_ver;
+       u8                      atscmh_parade_id;
+       u8                      atscmh_nog;
+       u8                      atscmh_tnog;
+       u8                      atscmh_sgn;
+       u8                      atscmh_prc;
+
+       u8                      atscmh_rs_frame_mode;
+       u8                      atscmh_rs_frame_ensemble;
+       u8                      atscmh_rs_code_mode_pri;
+       u8                      atscmh_rs_code_mode_sec;
+       u8                      atscmh_sccc_block_mode;
+       u8                      atscmh_sccc_code_mode_a;
+       u8                      atscmh_sccc_code_mode_b;
+       u8                      atscmh_sccc_code_mode_c;
+       u8                      atscmh_sccc_code_mode_d;
+};
+
+struct dvb_frontend {
+       struct dvb_frontend_ops ops;
+       struct dvb_adapter *dvb;
+       void *demodulator_priv;
+       void *tuner_priv;
+       void *frontend_priv;
+       void *sec_priv;
+       void *analog_demod_priv;
+       struct dtv_frontend_properties dtv_property_cache;
+#define DVB_FRONTEND_COMPONENT_TUNER 0
+#define DVB_FRONTEND_COMPONENT_DEMOD 1
+       int (*callback)(void *adapter_priv, int component, int cmd, int arg);
+       int id;
+};
+
+extern int dvb_register_frontend(struct dvb_adapter *dvb,
+                                struct dvb_frontend *fe);
+
+extern int dvb_unregister_frontend(struct dvb_frontend *fe);
+
+extern void dvb_frontend_detach(struct dvb_frontend *fe);
+
+extern void dvb_frontend_reinitialise(struct dvb_frontend *fe);
+
+extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec);
+extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime);
+
+#endif
diff --git a/drivers/media/dvb-core/dvb_math.c b/drivers/media/dvb-core/dvb_math.c
new file mode 100644 (file)
index 0000000..beb7c93
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * dvb-math provides some complex fixed-point math
+ * operations shared between the dvb related stuff
+ *
+ * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/bitops.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <asm/bug.h>
+#include "dvb_math.h"
+
+static const unsigned short logtable[256] = {
+       0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
+       0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508,
+       0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6,
+       0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37,
+       0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f,
+       0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41,
+       0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1,
+       0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142,
+       0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68,
+       0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355,
+       0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c,
+       0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490,
+       0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3,
+       0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507,
+       0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe,
+       0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca,
+       0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c,
+       0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7,
+       0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c,
+       0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c,
+       0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a,
+       0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065,
+       0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730,
+       0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc,
+       0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469,
+       0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9,
+       0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c,
+       0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765,
+       0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83,
+       0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387,
+       0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973,
+       0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47
+};
+
+unsigned int intlog2(u32 value)
+{
+       /**
+        *      returns: log2(value) * 2^24
+        *      wrong result if value = 0 (log2(0) is undefined)
+        */
+       unsigned int msb;
+       unsigned int logentry;
+       unsigned int significand;
+       unsigned int interpolation;
+
+       if (unlikely(value == 0)) {
+               WARN_ON(1);
+               return 0;
+       }
+
+       /* first detect the msb (count begins at 0) */
+       msb = fls(value) - 1;
+
+       /**
+        *      now we use a logtable after the following method:
+        *
+        *      log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24
+        *      where x = msb and therefore 1 <= y < 2
+        *      first y is determined by shifting the value left
+        *      so that msb is bit 31
+        *              0x00231f56 -> 0x8C7D5800
+        *      the result is y * 2^31 -> "significand"
+        *      then the highest 9 bits are used for a table lookup
+        *      the highest bit is discarded because it's always set
+        *      the highest nine bits in our example are 100011000
+        *      so we would use the entry 0x18
+        */
+       significand = value << (31 - msb);
+       logentry = (significand >> 23) & 0xff;
+
+       /**
+        *      last step we do is interpolation because of the
+        *      limitations of the log table the error is that part of
+        *      the significand which isn't used for lookup then we
+        *      compute the ratio between the error and the next table entry
+        *      and interpolate it between the log table entry used and the
+        *      next one the biggest error possible is 0x7fffff
+        *      (in our example it's 0x7D5800)
+        *      needed value for next table entry is 0x800000
+        *      so the interpolation is
+        *      (error / 0x800000) * (logtable_next - logtable_current)
+        *      in the implementation the division is moved to the end for
+        *      better accuracy there is also an overflow correction if
+        *      logtable_next is 256
+        */
+       interpolation = ((significand & 0x7fffff) *
+                       ((logtable[(logentry + 1) & 0xff] -
+                         logtable[logentry]) & 0xffff)) >> 15;
+
+       /* now we return the result */
+       return ((msb << 24) + (logtable[logentry] << 8) + interpolation);
+}
+EXPORT_SYMBOL(intlog2);
+
+unsigned int intlog10(u32 value)
+{
+       /**
+        *      returns: log10(value) * 2^24
+        *      wrong result if value = 0 (log10(0) is undefined)
+        */
+       u64 log;
+
+       if (unlikely(value == 0)) {
+               WARN_ON(1);
+               return 0;
+       }
+
+       log = intlog2(value);
+
+       /**
+        *      we use the following method:
+        *      log10(x) = log2(x) * log10(2)
+        */
+
+       return (log * 646456993) >> 31;
+}
+EXPORT_SYMBOL(intlog10);
diff --git a/drivers/media/dvb-core/dvb_math.h b/drivers/media/dvb-core/dvb_math.h
new file mode 100644 (file)
index 0000000..aecc867
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * dvb-math provides some complex fixed-point math
+ * operations shared between the dvb related stuff
+ *
+ * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
+ *
+ * This library 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __DVB_MATH_H
+#define __DVB_MATH_H
+
+#include <linux/types.h>
+
+/**
+ * computes log2 of a value; the result is shifted left by 24 bits
+ *
+ * to use rational values you can use the following method:
+ *   intlog2(value) = intlog2(value * 2^x) - x * 2^24
+ *
+ * example: intlog2(8) will give 3 << 24 = 3 * 2^24
+ * example: intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
+ * example: intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
+ *
+ * @param value The value (must be != 0)
+ * @return log2(value) * 2^24
+ */
+extern unsigned int intlog2(u32 value);
+
+/**
+ * computes log10 of a value; the result is shifted left by 24 bits
+ *
+ * to use rational values you can use the following method:
+ *   intlog10(value) = intlog10(value * 10^x) - x * 2^24
+ *
+ * example: intlog10(1000) will give 3 << 24 = 3 * 2^24
+ *   due to the implementation intlog10(1000) might be not exactly 3 * 2^24
+ *
+ * look at intlog2 for similar examples
+ *
+ * @param value The value (must be != 0)
+ * @return log10(value) * 2^24
+ */
+extern unsigned int intlog10(u32 value);
+
+#endif
diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c
new file mode 100644 (file)
index 0000000..8766ce8
--- /dev/null
@@ -0,0 +1,1516 @@
+/*
+ * dvb_net.c
+ *
+ * Copyright (C) 2001 Convergence integrated media GmbH
+ *                    Ralph Metzler <ralph@convergence.de>
+ * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
+ *
+ * ULE Decapsulation code:
+ * Copyright (C) 2003, 2004 gcs - Global Communication & Services GmbH.
+ *                      and Department of Scientific Computing
+ *                          Paris Lodron University of Salzburg.
+ *                          Hilmar Linder <hlinder@cosy.sbg.ac.at>
+ *                      and Wolfram Stering <wstering@cosy.sbg.ac.at>
+ *
+ * ULE Decaps according to RFC 4326.
+ *
+ * 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
+ */
+
+/*
+ * ULE ChangeLog:
+ * Feb 2004: hl/ws v1: Implementing draft-fair-ipdvb-ule-01.txt
+ *
+ * Dec 2004: hl/ws v2: Implementing draft-ietf-ipdvb-ule-03.txt:
+ *                       ULE Extension header handling.
+ *                     Bugreports by Moritz Vieth and Hanno Tersteegen,
+ *                       Fraunhofer Institute for Open Communication Systems
+ *                       Competence Center for Advanced Satellite Communications.
+ *                     Bugfixes and robustness improvements.
+ *                     Filtering on dest MAC addresses, if present (D-Bit = 0)
+ *                     ULE_DEBUG compile-time option.
+ * Apr 2006: cp v3:    Bugfixes and compliency with RFC 4326 (ULE) by
+ *                       Christian Praehauser <cpraehaus@cosy.sbg.ac.at>,
+ *                       Paris Lodron University of Salzburg.
+ */
+
+/*
+ * FIXME / TODO (dvb_net.c):
+ *
+ * Unloading does not work for 2.6.9 kernels: a refcount doesn't go to zero.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/dvb/net.h>
+#include <linux/uio.h>
+#include <asm/uaccess.h>
+#include <linux/crc32.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+
+#include "dvb_demux.h"
+#include "dvb_net.h"
+
+static int dvb_net_debug;
+module_param(dvb_net_debug, int, 0444);
+MODULE_PARM_DESC(dvb_net_debug, "enable debug messages");
+
+#define dprintk(x...) do { if (dvb_net_debug) printk(x); } while (0)
+
+
+static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
+{
+       unsigned int j;
+       for (j = 0; j < cnt; j++)
+               c = crc32_be( c, iov[j].iov_base, iov[j].iov_len );
+       return c;
+}
+
+
+#define DVB_NET_MULTICAST_MAX 10
+
+#undef ULE_DEBUG
+
+#ifdef ULE_DEBUG
+
+#define MAC_ADDR_PRINTFMT "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"
+#define MAX_ADDR_PRINTFMT_ARGS(macap) (macap)[0],(macap)[1],(macap)[2],(macap)[3],(macap)[4],(macap)[5]
+
+#define isprint(c)     ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
+
+static void hexdump( const unsigned char *buf, unsigned short len )
+{
+       char str[80], octet[10];
+       int ofs, i, l;
+
+       for (ofs = 0; ofs < len; ofs += 16) {
+               sprintf( str, "%03d: ", ofs );
+
+               for (i = 0; i < 16; i++) {
+                       if ((i + ofs) < len)
+                               sprintf( octet, "%02x ", buf[ofs + i] );
+                       else
+                               strcpy( octet, "   " );
+
+                       strcat( str, octet );
+               }
+               strcat( str, "  " );
+               l = strlen( str );
+
+               for (i = 0; (i < 16) && ((i + ofs) < len); i++)
+                       str[l++] = isprint( buf[ofs + i] ) ? buf[ofs + i] : '.';
+
+               str[l] = '\0';
+               printk( KERN_WARNING "%s\n", str );
+       }
+}
+
+#endif
+
+struct dvb_net_priv {
+       int in_use;
+       u16 pid;
+       struct net_device *net;
+       struct dvb_net *host;
+       struct dmx_demux *demux;
+       struct dmx_section_feed *secfeed;
+       struct dmx_section_filter *secfilter;
+       struct dmx_ts_feed *tsfeed;
+       int multi_num;
+       struct dmx_section_filter *multi_secfilter[DVB_NET_MULTICAST_MAX];
+       unsigned char multi_macs[DVB_NET_MULTICAST_MAX][6];
+       int rx_mode;
+#define RX_MODE_UNI 0
+#define RX_MODE_MULTI 1
+#define RX_MODE_ALL_MULTI 2
+#define RX_MODE_PROMISC 3
+       struct work_struct set_multicast_list_wq;
+       struct work_struct restart_net_feed_wq;
+       unsigned char feedtype;                 /* Either FEED_TYPE_ or FEED_TYPE_ULE */
+       int need_pusi;                          /* Set to 1, if synchronization on PUSI required. */
+       unsigned char tscc;                     /* TS continuity counter after sync on PUSI. */
+       struct sk_buff *ule_skb;                /* ULE SNDU decodes into this buffer. */
+       unsigned char *ule_next_hdr;            /* Pointer into skb to next ULE extension header. */
+       unsigned short ule_sndu_len;            /* ULE SNDU length in bytes, w/o D-Bit. */
+       unsigned short ule_sndu_type;           /* ULE SNDU type field, complete. */
+       unsigned char ule_sndu_type_1;          /* ULE SNDU type field, if split across 2 TS cells. */
+       unsigned char ule_dbit;                 /* Whether the DestMAC address present
+                                                * or not (bit is set). */
+       unsigned char ule_bridged;              /* Whether the ULE_BRIDGED extension header was found. */
+       int ule_sndu_remain;                    /* Nr. of bytes still required for current ULE SNDU. */
+       unsigned long ts_count;                 /* Current ts cell counter. */
+       struct mutex mutex;
+};
+
+
+/**
+ *     Determine the packet's protocol ID. The rule here is that we
+ *     assume 802.3 if the type field is short enough to be a length.
+ *     This is normal practice and works for any 'now in use' protocol.
+ *
+ *  stolen from eth.c out of the linux kernel, hacked for dvb-device
+ *  by Michael Holzt <kju@debian.org>
+ */
+static __be16 dvb_net_eth_type_trans(struct sk_buff *skb,
+                                     struct net_device *dev)
+{
+       struct ethhdr *eth;
+       unsigned char *rawp;
+
+       skb_reset_mac_header(skb);
+       skb_pull(skb,dev->hard_header_len);
+       eth = eth_hdr(skb);
+
+       if (*eth->h_dest & 1) {
+               if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)
+                       skb->pkt_type=PACKET_BROADCAST;
+               else
+                       skb->pkt_type=PACKET_MULTICAST;
+       }
+
+       if (ntohs(eth->h_proto) >= 1536)
+               return eth->h_proto;
+
+       rawp = skb->data;
+
+       /**
+        *      This is a magic hack to spot IPX packets. Older Novell breaks
+        *      the protocol design and runs IPX over 802.3 without an 802.2 LLC
+        *      layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
+        *      won't work for fault tolerant netware but does for the rest.
+        */
+       if (*(unsigned short *)rawp == 0xFFFF)
+               return htons(ETH_P_802_3);
+
+       /**
+        *      Real 802.2 LLC
+        */
+       return htons(ETH_P_802_2);
+}
+
+#define TS_SZ  188
+#define TS_SYNC        0x47
+#define TS_TEI 0x80
+#define TS_SC  0xC0
+#define TS_PUSI        0x40
+#define TS_AF_A        0x20
+#define TS_AF_D        0x10
+
+/* ULE Extension Header handlers. */
+
+#define ULE_TEST       0
+#define ULE_BRIDGED    1
+
+#define ULE_OPTEXTHDR_PADDING 0
+
+static int ule_test_sndu( struct dvb_net_priv *p )
+{
+       return -1;
+}
+
+static int ule_bridged_sndu( struct dvb_net_priv *p )
+{
+       struct ethhdr *hdr = (struct ethhdr*) p->ule_next_hdr;
+       if(ntohs(hdr->h_proto) < 1536) {
+               int framelen = p->ule_sndu_len - ((p->ule_next_hdr+sizeof(struct ethhdr)) - p->ule_skb->data);
+               /* A frame Type < 1536 for a bridged frame, introduces a LLC Length field. */
+               if(framelen != ntohs(hdr->h_proto)) {
+                       return -1;
+               }
+       }
+       /* Note:
+        * From RFC4326:
+        *  "A bridged SNDU is a Mandatory Extension Header of Type 1.
+        *   It must be the final (or only) extension header specified in the header chain of a SNDU."
+        * The 'ule_bridged' flag will cause the extension header processing loop to terminate.
+        */
+       p->ule_bridged = 1;
+       return 0;
+}
+
+static int ule_exthdr_padding(struct dvb_net_priv *p)
+{
+       return 0;
+}
+
+/** Handle ULE extension headers.
+ *  Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding.
+ *  Returns: >= 0: nr. of bytes consumed by next extension header
+ *          -1:   Mandatory extension header that is not recognized or TEST SNDU; discard.
+ */
+static int handle_one_ule_extension( struct dvb_net_priv *p )
+{
+       /* Table of mandatory extension header handlers.  The header type is the index. */
+       static int (*ule_mandatory_ext_handlers[255])( struct dvb_net_priv *p ) =
+               { [0] = ule_test_sndu, [1] = ule_bridged_sndu, [2] = NULL,  };
+
+       /* Table of optional extension header handlers.  The header type is the index. */
+       static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) =
+               { [0] = ule_exthdr_padding, [1] = NULL, };
+
+       int ext_len = 0;
+       unsigned char hlen = (p->ule_sndu_type & 0x0700) >> 8;
+       unsigned char htype = p->ule_sndu_type & 0x00FF;
+
+       /* Discriminate mandatory and optional extension headers. */
+       if (hlen == 0) {
+               /* Mandatory extension header */
+               if (ule_mandatory_ext_handlers[htype]) {
+                       ext_len = ule_mandatory_ext_handlers[htype]( p );
+                       if(ext_len >= 0) {
+                               p->ule_next_hdr += ext_len;
+                               if (!p->ule_bridged) {
+                                       p->ule_sndu_type = ntohs(*(__be16 *)p->ule_next_hdr);
+                                       p->ule_next_hdr += 2;
+                               } else {
+                                       p->ule_sndu_type = ntohs(*(__be16 *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)));
+                                       /* This assures the extension handling loop will terminate. */
+                               }
+                       }
+                       // else: extension handler failed or SNDU should be discarded
+               } else
+                       ext_len = -1;   /* SNDU has to be discarded. */
+       } else {
+               /* Optional extension header.  Calculate the length. */
+               ext_len = hlen << 1;
+               /* Process the optional extension header according to its type. */
+               if (ule_optional_ext_handlers[htype])
+                       (void)ule_optional_ext_handlers[htype]( p );
+               p->ule_next_hdr += ext_len;
+               p->ule_sndu_type = ntohs( *(__be16 *)(p->ule_next_hdr-2) );
+               /*
+                * note: the length of the next header type is included in the
+                * length of THIS optional extension header
+                */
+       }
+
+       return ext_len;
+}
+
+static int handle_ule_extensions( struct dvb_net_priv *p )
+{
+       int total_ext_len = 0, l;
+
+       p->ule_next_hdr = p->ule_skb->data;
+       do {
+               l = handle_one_ule_extension( p );
+               if (l < 0)
+                       return l;       /* Stop extension header processing and discard SNDU. */
+               total_ext_len += l;
+#ifdef ULE_DEBUG
+               dprintk("handle_ule_extensions: ule_next_hdr=%p, ule_sndu_type=%i, "
+                       "l=%i, total_ext_len=%i\n", p->ule_next_hdr,
+                       (int) p->ule_sndu_type, l, total_ext_len);
+#endif
+
+       } while (p->ule_sndu_type < 1536);
+
+       return total_ext_len;
+}
+
+
+/** Prepare for a new ULE SNDU: reset the decoder state. */
+static inline void reset_ule( struct dvb_net_priv *p )
+{
+       p->ule_skb = NULL;
+       p->ule_next_hdr = NULL;
+       p->ule_sndu_len = 0;
+       p->ule_sndu_type = 0;
+       p->ule_sndu_type_1 = 0;
+       p->ule_sndu_remain = 0;
+       p->ule_dbit = 0xFF;
+       p->ule_bridged = 0;
+}
+
+/**
+ * Decode ULE SNDUs according to draft-ietf-ipdvb-ule-03.txt from a sequence of
+ * TS cells of a single PID.
+ */
+static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
+{
+       struct dvb_net_priv *priv = netdev_priv(dev);
+       unsigned long skipped = 0L;
+       const u8 *ts, *ts_end, *from_where = NULL;
+       u8 ts_remain = 0, how_much = 0, new_ts = 1;
+       struct ethhdr *ethh = NULL;
+       bool error = false;
+
+#ifdef ULE_DEBUG
+       /* The code inside ULE_DEBUG keeps a history of the last 100 TS cells processed. */
+       static unsigned char ule_hist[100*TS_SZ];
+       static unsigned char *ule_where = ule_hist, ule_dump;
+#endif
+
+       /* For all TS cells in current buffer.
+        * Appearently, we are called for every single TS cell.
+        */
+       for (ts = buf, ts_end = buf + buf_len; ts < ts_end; /* no default incr. */ ) {
+
+               if (new_ts) {
+                       /* We are about to process a new TS cell. */
+
+#ifdef ULE_DEBUG
+                       if (ule_where >= &ule_hist[100*TS_SZ]) ule_where = ule_hist;
+                       memcpy( ule_where, ts, TS_SZ );
+                       if (ule_dump) {
+                               hexdump( ule_where, TS_SZ );
+                               ule_dump = 0;
+                       }
+                       ule_where += TS_SZ;
+#endif
+
+                       /* Check TS error conditions: sync_byte, transport_error_indicator, scrambling_control . */
+                       if ((ts[0] != TS_SYNC) || (ts[1] & TS_TEI) || ((ts[3] & TS_SC) != 0)) {
+                               printk(KERN_WARNING "%lu: Invalid TS cell: SYNC %#x, TEI %u, SC %#x.\n",
+                                      priv->ts_count, ts[0], ts[1] & TS_TEI >> 7, ts[3] & 0xC0 >> 6);
+
+                               /* Drop partly decoded SNDU, reset state, resync on PUSI. */
+                               if (priv->ule_skb) {
+                                       dev_kfree_skb( priv->ule_skb );
+                                       /* Prepare for next SNDU. */
+                                       dev->stats.rx_errors++;
+                                       dev->stats.rx_frame_errors++;
+                               }
+                               reset_ule(priv);
+                               priv->need_pusi = 1;
+
+                               /* Continue with next TS cell. */
+                               ts += TS_SZ;
+                               priv->ts_count++;
+                               continue;
+                       }
+
+                       ts_remain = 184;
+                       from_where = ts + 4;
+               }
+               /* Synchronize on PUSI, if required. */
+               if (priv->need_pusi) {
+                       if (ts[1] & TS_PUSI) {
+                               /* Find beginning of first ULE SNDU in current TS cell. */
+                               /* Synchronize continuity counter. */
+                               priv->tscc = ts[3] & 0x0F;
+                               /* There is a pointer field here. */
+                               if (ts[4] > ts_remain) {
+                                       printk(KERN_ERR "%lu: Invalid ULE packet "
+                                              "(pointer field %d)\n", priv->ts_count, ts[4]);
+                                       ts += TS_SZ;
+                                       priv->ts_count++;
+                                       continue;
+                               }
+                               /* Skip to destination of pointer field. */
+                               from_where = &ts[5] + ts[4];
+                               ts_remain -= 1 + ts[4];
+                               skipped = 0;
+                       } else {
+                               skipped++;
+                               ts += TS_SZ;
+                               priv->ts_count++;
+                               continue;
+                       }
+               }
+
+               if (new_ts) {
+                       /* Check continuity counter. */
+                       if ((ts[3] & 0x0F) == priv->tscc)
+                               priv->tscc = (priv->tscc + 1) & 0x0F;
+                       else {
+                               /* TS discontinuity handling: */
+                               printk(KERN_WARNING "%lu: TS discontinuity: got %#x, "
+                                      "expected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc);
+                               /* Drop partly decoded SNDU, reset state, resync on PUSI. */
+                               if (priv->ule_skb) {
+                                       dev_kfree_skb( priv->ule_skb );
+                                       /* Prepare for next SNDU. */
+                                       // reset_ule(priv);  moved to below.
+                                       dev->stats.rx_errors++;
+                                       dev->stats.rx_frame_errors++;
+                               }
+                               reset_ule(priv);
+                               /* skip to next PUSI. */
+                               priv->need_pusi = 1;
+                               continue;
+                       }
+                       /* If we still have an incomplete payload, but PUSI is
+                        * set; some TS cells are missing.
+                        * This is only possible here, if we missed exactly 16 TS
+                        * cells (continuity counter wrap). */
+                       if (ts[1] & TS_PUSI) {
+                               if (! priv->need_pusi) {
+                                       if (!(*from_where < (ts_remain-1)) || *from_where != priv->ule_sndu_remain) {
+                                               /* Pointer field is invalid.  Drop this TS cell and any started ULE SNDU. */
+                                               printk(KERN_WARNING "%lu: Invalid pointer "
+                                                      "field: %u.\n", priv->ts_count, *from_where);
+
+                                               /* Drop partly decoded SNDU, reset state, resync on PUSI. */
+                                               if (priv->ule_skb) {
+                                                       error = true;
+                                                       dev_kfree_skb(priv->ule_skb);
+                                               }
+
+                                               if (error || priv->ule_sndu_remain) {
+                                                       dev->stats.rx_errors++;
+                                                       dev->stats.rx_frame_errors++;
+                                                       error = false;
+                                               }
+
+                                               reset_ule(priv);
+                                               priv->need_pusi = 1;
+                                               continue;
+                                       }
+                                       /* Skip pointer field (we're processing a
+                                        * packed payload). */
+                                       from_where += 1;
+                                       ts_remain -= 1;
+                               } else
+                                       priv->need_pusi = 0;
+
+                               if (priv->ule_sndu_remain > 183) {
+                                       /* Current SNDU lacks more data than there could be available in the
+                                        * current TS cell. */
+                                       dev->stats.rx_errors++;
+                                       dev->stats.rx_length_errors++;
+                                       printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but "
+                                              "got PUSI (pf %d, ts_remain %d).  Flushing incomplete payload.\n",
+                                              priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain);
+                                       dev_kfree_skb(priv->ule_skb);
+                                       /* Prepare for next SNDU. */
+                                       reset_ule(priv);
+                                       /* Resync: go to where pointer field points to: start of next ULE SNDU. */
+                                       from_where += ts[4];
+                                       ts_remain -= ts[4];
+                               }
+                       }
+               }
+
+               /* Check if new payload needs to be started. */
+               if (priv->ule_skb == NULL) {
+                       /* Start a new payload with skb.
+                        * Find ULE header.  It is only guaranteed that the
+                        * length field (2 bytes) is contained in the current
+                        * TS.
+                        * Check ts_remain has to be >= 2 here. */
+                       if (ts_remain < 2) {
+                               printk(KERN_WARNING "Invalid payload packing: only %d "
+                                      "bytes left in TS.  Resyncing.\n", ts_remain);
+                               priv->ule_sndu_len = 0;
+                               priv->need_pusi = 1;
+                               ts += TS_SZ;
+                               continue;
+                       }
+
+                       if (! priv->ule_sndu_len) {
+                               /* Got at least two bytes, thus extrace the SNDU length. */
+                               priv->ule_sndu_len = from_where[0] << 8 | from_where[1];
+                               if (priv->ule_sndu_len & 0x8000) {
+                                       /* D-Bit is set: no dest mac present. */
+                                       priv->ule_sndu_len &= 0x7FFF;
+                                       priv->ule_dbit = 1;
+                               } else
+                                       priv->ule_dbit = 0;
+
+                               if (priv->ule_sndu_len < 5) {
+                                       printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. "
+                                              "Resyncing.\n", priv->ts_count, priv->ule_sndu_len);
+                                       dev->stats.rx_errors++;
+                                       dev->stats.rx_length_errors++;
+                                       priv->ule_sndu_len = 0;
+                                       priv->need_pusi = 1;
+                                       new_ts = 1;
+                                       ts += TS_SZ;
+                                       priv->ts_count++;
+                                       continue;
+                               }
+                               ts_remain -= 2; /* consume the 2 bytes SNDU length. */
+                               from_where += 2;
+                       }
+
+                       priv->ule_sndu_remain = priv->ule_sndu_len + 2;
+                       /*
+                        * State of current TS:
+                        *   ts_remain (remaining bytes in the current TS cell)
+                        *   0  ule_type is not available now, we need the next TS cell
+                        *   1  the first byte of the ule_type is present
+                        * >=2  full ULE header present, maybe some payload data as well.
+                        */
+                       switch (ts_remain) {
+                               case 1:
+                                       priv->ule_sndu_remain--;
+                                       priv->ule_sndu_type = from_where[0] << 8;
+                                       priv->ule_sndu_type_1 = 1; /* first byte of ule_type is set. */
+                                       ts_remain -= 1; from_where += 1;
+                                       /* Continue w/ next TS. */
+                               case 0:
+                                       new_ts = 1;
+                                       ts += TS_SZ;
+                                       priv->ts_count++;
+                                       continue;
+
+                               default: /* complete ULE header is present in current TS. */
+                                       /* Extract ULE type field. */
+                                       if (priv->ule_sndu_type_1) {
+                                               priv->ule_sndu_type_1 = 0;
+                                               priv->ule_sndu_type |= from_where[0];
+                                               from_where += 1; /* points to payload start. */
+                                               ts_remain -= 1;
+                                       } else {
+                                               /* Complete type is present in new TS. */
+                                               priv->ule_sndu_type = from_where[0] << 8 | from_where[1];
+                                               from_where += 2; /* points to payload start. */
+                                               ts_remain -= 2;
+                                       }
+                                       break;
+                       }
+
+                       /* Allocate the skb (decoder target buffer) with the correct size, as follows:
+                        * prepare for the largest case: bridged SNDU with MAC address (dbit = 0). */
+                       priv->ule_skb = dev_alloc_skb( priv->ule_sndu_len + ETH_HLEN + ETH_ALEN );
+                       if (priv->ule_skb == NULL) {
+                               printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
+                                      dev->name);
+                               dev->stats.rx_dropped++;
+                               return;
+                       }
+
+                       /* This includes the CRC32 _and_ dest mac, if !dbit. */
+                       priv->ule_sndu_remain = priv->ule_sndu_len;
+                       priv->ule_skb->dev = dev;
+                       /* Leave space for Ethernet or bridged SNDU header (eth hdr plus one MAC addr). */
+                       skb_reserve( priv->ule_skb, ETH_HLEN + ETH_ALEN );
+               }
+
+               /* Copy data into our current skb. */
+               how_much = min(priv->ule_sndu_remain, (int)ts_remain);
+               memcpy(skb_put(priv->ule_skb, how_much), from_where, how_much);
+               priv->ule_sndu_remain -= how_much;
+               ts_remain -= how_much;
+               from_where += how_much;
+
+               /* Check for complete payload. */
+               if (priv->ule_sndu_remain <= 0) {
+                       /* Check CRC32, we've got it in our skb already. */
+                       __be16 ulen = htons(priv->ule_sndu_len);
+                       __be16 utype = htons(priv->ule_sndu_type);
+                       const u8 *tail;
+                       struct kvec iov[3] = {
+                               { &ulen, sizeof ulen },
+                               { &utype, sizeof utype },
+                               { priv->ule_skb->data, priv->ule_skb->len - 4 }
+                       };
+                       u32 ule_crc = ~0L, expected_crc;
+                       if (priv->ule_dbit) {
+                               /* Set D-bit for CRC32 verification,
+                                * if it was set originally. */
+                               ulen |= htons(0x8000);
+                       }
+
+                       ule_crc = iov_crc32(ule_crc, iov, 3);
+                       tail = skb_tail_pointer(priv->ule_skb);
+                       expected_crc = *(tail - 4) << 24 |
+                                      *(tail - 3) << 16 |
+                                      *(tail - 2) << 8 |
+                                      *(tail - 1);
+                       if (ule_crc != expected_crc) {
+                               printk(KERN_WARNING "%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n",
+                                      priv->ts_count, ule_crc, expected_crc, priv->ule_sndu_len, priv->ule_sndu_type, ts_remain, ts_remain > 2 ? *(unsigned short *)from_where : 0);
+
+#ifdef ULE_DEBUG
+                               hexdump( iov[0].iov_base, iov[0].iov_len );
+                               hexdump( iov[1].iov_base, iov[1].iov_len );
+                               hexdump( iov[2].iov_base, iov[2].iov_len );
+
+                               if (ule_where == ule_hist) {
+                                       hexdump( &ule_hist[98*TS_SZ], TS_SZ );
+                                       hexdump( &ule_hist[99*TS_SZ], TS_SZ );
+                               } else if (ule_where == &ule_hist[TS_SZ]) {
+                                       hexdump( &ule_hist[99*TS_SZ], TS_SZ );
+                                       hexdump( ule_hist, TS_SZ );
+                               } else {
+                                       hexdump( ule_where - TS_SZ - TS_SZ, TS_SZ );
+                                       hexdump( ule_where - TS_SZ, TS_SZ );
+                               }
+                               ule_dump = 1;
+#endif
+
+                               dev->stats.rx_errors++;
+                               dev->stats.rx_crc_errors++;
+                               dev_kfree_skb(priv->ule_skb);
+                       } else {
+                               /* CRC32 verified OK. */
+                               u8 dest_addr[ETH_ALEN];
+                               static const u8 bc_addr[ETH_ALEN] =
+                                       { [ 0 ... ETH_ALEN-1] = 0xff };
+
+                               /* CRC32 was OK. Remove it from skb. */
+                               priv->ule_skb->tail -= 4;
+                               priv->ule_skb->len -= 4;
+
+                               if (!priv->ule_dbit) {
+                                       /*
+                                        * The destination MAC address is the
+                                        * next data in the skb.  It comes
+                                        * before any extension headers.
+                                        *
+                                        * Check if the payload of this SNDU
+                                        * should be passed up the stack.
+                                        */
+                                       register int drop = 0;
+                                       if (priv->rx_mode != RX_MODE_PROMISC) {
+                                               if (priv->ule_skb->data[0] & 0x01) {
+                                                       /* multicast or broadcast */
+                                                       if (memcmp(priv->ule_skb->data, bc_addr, ETH_ALEN)) {
+                                                               /* multicast */
+                                                               if (priv->rx_mode == RX_MODE_MULTI) {
+                                                                       int i;
+                                                                       for(i = 0; i < priv->multi_num && memcmp(priv->ule_skb->data, priv->multi_macs[i], ETH_ALEN); i++)
+                                                                               ;
+                                                                       if (i == priv->multi_num)
+                                                                               drop = 1;
+                                                               } else if (priv->rx_mode != RX_MODE_ALL_MULTI)
+                                                                       drop = 1; /* no broadcast; */
+                                                               /* else: all multicast mode: accept all multicast packets */
+                                                       }
+                                                       /* else: broadcast */
+                                               }
+                                               else if (memcmp(priv->ule_skb->data, dev->dev_addr, ETH_ALEN))
+                                                       drop = 1;
+                                               /* else: destination address matches the MAC address of our receiver device */
+                                       }
+                                       /* else: promiscuous mode; pass everything up the stack */
+
+                                       if (drop) {
+#ifdef ULE_DEBUG
+                                               dprintk("Dropping SNDU: MAC destination address does not match: dest addr: "MAC_ADDR_PRINTFMT", dev addr: "MAC_ADDR_PRINTFMT"\n",
+                                                       MAX_ADDR_PRINTFMT_ARGS(priv->ule_skb->data), MAX_ADDR_PRINTFMT_ARGS(dev->dev_addr));
+#endif
+                                               dev_kfree_skb(priv->ule_skb);
+                                               goto sndu_done;
+                                       }
+                                       else
+                                       {
+                                               skb_copy_from_linear_data(priv->ule_skb,
+                                                             dest_addr,
+                                                             ETH_ALEN);
+                                               skb_pull(priv->ule_skb, ETH_ALEN);
+                                       }
+                               }
+
+                               /* Handle ULE Extension Headers. */
+                               if (priv->ule_sndu_type < 1536) {
+                                       /* There is an extension header.  Handle it accordingly. */
+                                       int l = handle_ule_extensions(priv);
+                                       if (l < 0) {
+                                               /* Mandatory extension header unknown or TEST SNDU.  Drop it. */
+                                               // printk( KERN_WARNING "Dropping SNDU, extension headers.\n" );
+                                               dev_kfree_skb(priv->ule_skb);
+                                               goto sndu_done;
+                                       }
+                                       skb_pull(priv->ule_skb, l);
+                               }
+
+                               /*
+                                * Construct/assure correct ethernet header.
+                                * Note: in bridged mode (priv->ule_bridged !=
+                                * 0) we already have the (original) ethernet
+                                * header at the start of the payload (after
+                                * optional dest. address and any extension
+                                * headers).
+                                */
+
+                               if (!priv->ule_bridged) {
+                                       skb_push(priv->ule_skb, ETH_HLEN);
+                                       ethh = (struct ethhdr *)priv->ule_skb->data;
+                                       if (!priv->ule_dbit) {
+                                                /* dest_addr buffer is only valid if priv->ule_dbit == 0 */
+                                               memcpy(ethh->h_dest, dest_addr, ETH_ALEN);
+                                               memset(ethh->h_source, 0, ETH_ALEN);
+                                       }
+                                       else /* zeroize source and dest */
+                                               memset( ethh, 0, ETH_ALEN*2 );
+
+                                       ethh->h_proto = htons(priv->ule_sndu_type);
+                               }
+                               /* else:  skb is in correct state; nothing to do. */
+                               priv->ule_bridged = 0;
+
+                               /* Stuff into kernel's protocol stack. */
+                               priv->ule_skb->protocol = dvb_net_eth_type_trans(priv->ule_skb, dev);
+                               /* If D-bit is set (i.e. destination MAC address not present),
+                                * receive the packet anyhow. */
+                               /* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST)
+                                       priv->ule_skb->pkt_type = PACKET_HOST; */
+                               dev->stats.rx_packets++;
+                               dev->stats.rx_bytes += priv->ule_skb->len;
+                               netif_rx(priv->ule_skb);
+                       }
+                       sndu_done:
+                       /* Prepare for next SNDU. */
+                       reset_ule(priv);
+               }
+
+               /* More data in current TS (look at the bytes following the CRC32)? */
+               if (ts_remain >= 2 && *((unsigned short *)from_where) != 0xFFFF) {
+                       /* Next ULE SNDU starts right there. */
+                       new_ts = 0;
+                       priv->ule_skb = NULL;
+                       priv->ule_sndu_type_1 = 0;
+                       priv->ule_sndu_len = 0;
+                       // printk(KERN_WARNING "More data in current TS: [%#x %#x %#x %#x]\n",
+                       //      *(from_where + 0), *(from_where + 1),
+                       //      *(from_where + 2), *(from_where + 3));
+                       // printk(KERN_WARNING "ts @ %p, stopped @ %p:\n", ts, from_where + 0);
+                       // hexdump(ts, 188);
+               } else {
+                       new_ts = 1;
+                       ts += TS_SZ;
+                       priv->ts_count++;
+                       if (priv->ule_skb == NULL) {
+                               priv->need_pusi = 1;
+                               priv->ule_sndu_type_1 = 0;
+                               priv->ule_sndu_len = 0;
+                       }
+               }
+       }       /* for all available TS cells */
+}
+
+static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len,
+                              const u8 *buffer2, size_t buffer2_len,
+                              struct dmx_ts_feed *feed, enum dmx_success success)
+{
+       struct net_device *dev = feed->priv;
+
+       if (buffer2)
+               printk(KERN_WARNING "buffer2 not NULL: %p.\n", buffer2);
+       if (buffer1_len > 32768)
+               printk(KERN_WARNING "length > 32k: %zu.\n", buffer1_len);
+       /* printk("TS callback: %u bytes, %u TS cells @ %p.\n",
+                 buffer1_len, buffer1_len / TS_SZ, buffer1); */
+       dvb_net_ule(dev, buffer1, buffer1_len);
+       return 0;
+}
+
+
+static void dvb_net_sec(struct net_device *dev,
+                       const u8 *pkt, int pkt_len)
+{
+       u8 *eth;
+       struct sk_buff *skb;
+       struct net_device_stats *stats = &dev->stats;
+       int snap = 0;
+
+       /* note: pkt_len includes a 32bit checksum */
+       if (pkt_len < 16) {
+               printk("%s: IP/MPE packet length = %d too small.\n",
+                       dev->name, pkt_len);
+               stats->rx_errors++;
+               stats->rx_length_errors++;
+               return;
+       }
+/* it seems some ISPs manage to screw up here, so we have to
+ * relax the error checks... */
+#if 0
+       if ((pkt[5] & 0xfd) != 0xc1) {
+               /* drop scrambled or broken packets */
+#else
+       if ((pkt[5] & 0x3c) != 0x00) {
+               /* drop scrambled */
+#endif
+               stats->rx_errors++;
+               stats->rx_crc_errors++;
+               return;
+       }
+       if (pkt[5] & 0x02) {
+               /* handle LLC/SNAP, see rfc-1042 */
+               if (pkt_len < 24 || memcmp(&pkt[12], "\xaa\xaa\x03\0\0\0", 6)) {
+                       stats->rx_dropped++;
+                       return;
+               }
+               snap = 8;
+       }
+       if (pkt[7]) {
+               /* FIXME: assemble datagram from multiple sections */
+               stats->rx_errors++;
+               stats->rx_frame_errors++;
+               return;
+       }
+
+       /* we have 14 byte ethernet header (ip header follows);
+        * 12 byte MPE header; 4 byte checksum; + 2 byte alignment, 8 byte LLC/SNAP
+        */
+       if (!(skb = dev_alloc_skb(pkt_len - 4 - 12 + 14 + 2 - snap))) {
+               //printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
+               stats->rx_dropped++;
+               return;
+       }
+       skb_reserve(skb, 2);    /* longword align L3 header */
+       skb->dev = dev;
+
+       /* copy L3 payload */
+       eth = (u8 *) skb_put(skb, pkt_len - 12 - 4 + 14 - snap);
+       memcpy(eth + 14, pkt + 12 + snap, pkt_len - 12 - 4 - snap);
+
+       /* create ethernet header: */
+       eth[0]=pkt[0x0b];
+       eth[1]=pkt[0x0a];
+       eth[2]=pkt[0x09];
+       eth[3]=pkt[0x08];
+       eth[4]=pkt[0x04];
+       eth[5]=pkt[0x03];
+
+       eth[6]=eth[7]=eth[8]=eth[9]=eth[10]=eth[11]=0;
+
+       if (snap) {
+               eth[12] = pkt[18];
+               eth[13] = pkt[19];
+       } else {
+               /* protocol numbers are from rfc-1700 or
+                * http://www.iana.org/assignments/ethernet-numbers
+                */
+               if (pkt[12] >> 4 == 6) { /* version field from IP header */
+                       eth[12] = 0x86; /* IPv6 */
+                       eth[13] = 0xdd;
+               } else {
+                       eth[12] = 0x08; /* IPv4 */
+                       eth[13] = 0x00;
+               }
+       }
+
+       skb->protocol = dvb_net_eth_type_trans(skb, dev);
+
+       stats->rx_packets++;
+       stats->rx_bytes+=skb->len;
+       netif_rx(skb);
+}
+
+static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len,
+                const u8 *buffer2, size_t buffer2_len,
+                struct dmx_section_filter *filter,
+                enum dmx_success success)
+{
+       struct net_device *dev = filter->priv;
+
+       /**
+        * we rely on the DVB API definition where exactly one complete
+        * section is delivered in buffer1
+        */
+       dvb_net_sec (dev, buffer1, buffer1_len);
+       return 0;
+}
+
+static int dvb_net_tx(struct sk_buff *skb, struct net_device *dev)
+{
+       dev_kfree_skb(skb);
+       return NETDEV_TX_OK;
+}
+
+static u8 mask_normal[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
+static u8 mask_allmulti[6]={0xff, 0xff, 0xff, 0x00, 0x00, 0x00};
+static u8 mac_allmulti[6]={0x01, 0x00, 0x5e, 0x00, 0x00, 0x00};
+static u8 mask_promisc[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+static int dvb_net_filter_sec_set(struct net_device *dev,
+                  struct dmx_section_filter **secfilter,
+                  u8 *mac, u8 *mac_mask)
+{
+       struct dvb_net_priv *priv = netdev_priv(dev);
+       int ret;
+
+       *secfilter=NULL;
+       ret = priv->secfeed->allocate_filter(priv->secfeed, secfilter);
+       if (ret<0) {
+               printk("%s: could not get filter\n", dev->name);
+               return ret;
+       }
+
+       (*secfilter)->priv=(void *) dev;
+
+       memset((*secfilter)->filter_value, 0x00, DMX_MAX_FILTER_SIZE);
+       memset((*secfilter)->filter_mask,  0x00, DMX_MAX_FILTER_SIZE);
+       memset((*secfilter)->filter_mode,  0xff, DMX_MAX_FILTER_SIZE);
+
+       (*secfilter)->filter_value[0]=0x3e;
+       (*secfilter)->filter_value[3]=mac[5];
+       (*secfilter)->filter_value[4]=mac[4];
+       (*secfilter)->filter_value[8]=mac[3];
+       (*secfilter)->filter_value[9]=mac[2];
+       (*secfilter)->filter_value[10]=mac[1];
+       (*secfilter)->filter_value[11]=mac[0];
+
+       (*secfilter)->filter_mask[0] = 0xff;
+       (*secfilter)->filter_mask[3] = mac_mask[5];
+       (*secfilter)->filter_mask[4] = mac_mask[4];
+       (*secfilter)->filter_mask[8] = mac_mask[3];
+       (*secfilter)->filter_mask[9] = mac_mask[2];
+       (*secfilter)->filter_mask[10] = mac_mask[1];
+       (*secfilter)->filter_mask[11]=mac_mask[0];
+
+       dprintk("%s: filter mac=%pM\n", dev->name, mac);
+       dprintk("%s: filter mask=%pM\n", dev->name, mac_mask);
+
+       return 0;
+}
+
+static int dvb_net_feed_start(struct net_device *dev)
+{
+       int ret = 0, i;
+       struct dvb_net_priv *priv = netdev_priv(dev);
+       struct dmx_demux *demux = priv->demux;
+       unsigned char *mac = (unsigned char *) dev->dev_addr;
+
+       dprintk("%s: rx_mode %i\n", __func__, priv->rx_mode);
+       mutex_lock(&priv->mutex);
+       if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0])
+               printk("%s: BUG %d\n", __func__, __LINE__);
+
+       priv->secfeed=NULL;
+       priv->secfilter=NULL;
+       priv->tsfeed = NULL;
+
+       if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
+               dprintk("%s: alloc secfeed\n", __func__);
+               ret=demux->allocate_section_feed(demux, &priv->secfeed,
+                                        dvb_net_sec_callback);
+               if (ret<0) {
+                       printk("%s: could not allocate section feed\n", dev->name);
+                       goto error;
+               }
+
+               ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1);
+
+               if (ret<0) {
+                       printk("%s: could not set section feed\n", dev->name);
+                       priv->demux->release_section_feed(priv->demux, priv->secfeed);
+                       priv->secfeed=NULL;
+                       goto error;
+               }
+
+               if (priv->rx_mode != RX_MODE_PROMISC) {
+                       dprintk("%s: set secfilter\n", __func__);
+                       dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_normal);
+               }
+
+               switch (priv->rx_mode) {
+               case RX_MODE_MULTI:
+                       for (i = 0; i < priv->multi_num; i++) {
+                               dprintk("%s: set multi_secfilter[%d]\n", __func__, i);
+                               dvb_net_filter_sec_set(dev, &priv->multi_secfilter[i],
+                                                      priv->multi_macs[i], mask_normal);
+                       }
+                       break;
+               case RX_MODE_ALL_MULTI:
+                       priv->multi_num=1;
+                       dprintk("%s: set multi_secfilter[0]\n", __func__);
+                       dvb_net_filter_sec_set(dev, &priv->multi_secfilter[0],
+                                              mac_allmulti, mask_allmulti);
+                       break;
+               case RX_MODE_PROMISC:
+                       priv->multi_num=0;
+                       dprintk("%s: set secfilter\n", __func__);
+                       dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_promisc);
+                       break;
+               }
+
+               dprintk("%s: start filtering\n", __func__);
+               priv->secfeed->start_filtering(priv->secfeed);
+       } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
+               struct timespec timeout = { 0, 10000000 }; // 10 msec
+
+               /* we have payloads encapsulated in TS */
+               dprintk("%s: alloc tsfeed\n", __func__);
+               ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback);
+               if (ret < 0) {
+                       printk("%s: could not allocate ts feed\n", dev->name);
+                       goto error;
+               }
+
+               /* Set netdevice pointer for ts decaps callback. */
+               priv->tsfeed->priv = (void *)dev;
+               ret = priv->tsfeed->set(priv->tsfeed,
+                                       priv->pid, /* pid */
+                                       TS_PACKET, /* type */
+                                       DMX_TS_PES_OTHER, /* pes type */
+                                       32768,     /* circular buffer size */
+                                       timeout    /* timeout */
+                                       );
+
+               if (ret < 0) {
+                       printk("%s: could not set ts feed\n", dev->name);
+                       priv->demux->release_ts_feed(priv->demux, priv->tsfeed);
+                       priv->tsfeed = NULL;
+                       goto error;
+               }
+
+               dprintk("%s: start filtering\n", __func__);
+               priv->tsfeed->start_filtering(priv->tsfeed);
+       } else
+               ret = -EINVAL;
+
+error:
+       mutex_unlock(&priv->mutex);
+       return ret;
+}
+
+static int dvb_net_feed_stop(struct net_device *dev)
+{
+       struct dvb_net_priv *priv = netdev_priv(dev);
+       int i, ret = 0;
+
+       dprintk("%s\n", __func__);
+       mutex_lock(&priv->mutex);
+       if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
+               if (priv->secfeed) {
+                       if (priv->secfeed->is_filtering) {
+                               dprintk("%s: stop secfeed\n", __func__);
+                               priv->secfeed->stop_filtering(priv->secfeed);
+                       }
+
+                       if (priv->secfilter) {
+                               dprintk("%s: release secfilter\n", __func__);
+                               priv->secfeed->release_filter(priv->secfeed,
+                                                             priv->secfilter);
+                               priv->secfilter=NULL;
+                       }
+
+                       for (i=0; i<priv->multi_num; i++) {
+                               if (priv->multi_secfilter[i]) {
+                                       dprintk("%s: release multi_filter[%d]\n",
+                                               __func__, i);
+                                       priv->secfeed->release_filter(priv->secfeed,
+                                                                     priv->multi_secfilter[i]);
+                                       priv->multi_secfilter[i] = NULL;
+                               }
+                       }
+
+                       priv->demux->release_section_feed(priv->demux, priv->secfeed);
+                       priv->secfeed = NULL;
+               } else
+                       printk("%s: no feed to stop\n", dev->name);
+       } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
+               if (priv->tsfeed) {
+                       if (priv->tsfeed->is_filtering) {
+                               dprintk("%s: stop tsfeed\n", __func__);
+                               priv->tsfeed->stop_filtering(priv->tsfeed);
+                       }
+                       priv->demux->release_ts_feed(priv->demux, priv->tsfeed);
+                       priv->tsfeed = NULL;
+               }
+               else
+                       printk("%s: no ts feed to stop\n", dev->name);
+       } else
+               ret = -EINVAL;
+       mutex_unlock(&priv->mutex);
+       return ret;
+}
+
+
+static int dvb_set_mc_filter(struct net_device *dev, unsigned char *addr)
+{
+       struct dvb_net_priv *priv = netdev_priv(dev);
+
+       if (priv->multi_num == DVB_NET_MULTICAST_MAX)
+               return -ENOMEM;
+
+       memcpy(priv->multi_macs[priv->multi_num], addr, ETH_ALEN);
+
+       priv->multi_num++;
+       return 0;
+}
+
+
+static void wq_set_multicast_list (struct work_struct *work)
+{
+       struct dvb_net_priv *priv =
+               container_of(work, struct dvb_net_priv, set_multicast_list_wq);
+       struct net_device *dev = priv->net;
+
+       dvb_net_feed_stop(dev);
+       priv->rx_mode = RX_MODE_UNI;
+       netif_addr_lock_bh(dev);
+
+       if (dev->flags & IFF_PROMISC) {
+               dprintk("%s: promiscuous mode\n", dev->name);
+               priv->rx_mode = RX_MODE_PROMISC;
+       } else if ((dev->flags & IFF_ALLMULTI)) {
+               dprintk("%s: allmulti mode\n", dev->name);
+               priv->rx_mode = RX_MODE_ALL_MULTI;
+       } else if (!netdev_mc_empty(dev)) {
+               struct netdev_hw_addr *ha;
+
+               dprintk("%s: set_mc_list, %d entries\n",
+                       dev->name, netdev_mc_count(dev));
+
+               priv->rx_mode = RX_MODE_MULTI;
+               priv->multi_num = 0;
+
+               netdev_for_each_mc_addr(ha, dev)
+                       dvb_set_mc_filter(dev, ha->addr);
+       }
+
+       netif_addr_unlock_bh(dev);
+       dvb_net_feed_start(dev);
+}
+
+
+static void dvb_net_set_multicast_list (struct net_device *dev)
+{
+       struct dvb_net_priv *priv = netdev_priv(dev);
+       schedule_work(&priv->set_multicast_list_wq);
+}
+
+
+static void wq_restart_net_feed (struct work_struct *work)
+{
+       struct dvb_net_priv *priv =
+               container_of(work, struct dvb_net_priv, restart_net_feed_wq);
+       struct net_device *dev = priv->net;
+
+       if (netif_running(dev)) {
+               dvb_net_feed_stop(dev);
+               dvb_net_feed_start(dev);
+       }
+}
+
+
+static int dvb_net_set_mac (struct net_device *dev, void *p)
+{
+       struct dvb_net_priv *priv = netdev_priv(dev);
+       struct sockaddr *addr=p;
+
+       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+       if (netif_running(dev))
+               schedule_work(&priv->restart_net_feed_wq);
+
+       return 0;
+}
+
+
+static int dvb_net_open(struct net_device *dev)
+{
+       struct dvb_net_priv *priv = netdev_priv(dev);
+
+       priv->in_use++;
+       dvb_net_feed_start(dev);
+       return 0;
+}
+
+
+static int dvb_net_stop(struct net_device *dev)
+{
+       struct dvb_net_priv *priv = netdev_priv(dev);
+
+       priv->in_use--;
+       return dvb_net_feed_stop(dev);
+}
+
+static const struct header_ops dvb_header_ops = {
+       .create         = eth_header,
+       .parse          = eth_header_parse,
+       .rebuild        = eth_rebuild_header,
+};
+
+
+static const struct net_device_ops dvb_netdev_ops = {
+       .ndo_open               = dvb_net_open,
+       .ndo_stop               = dvb_net_stop,
+       .ndo_start_xmit         = dvb_net_tx,
+       .ndo_set_rx_mode        = dvb_net_set_multicast_list,
+       .ndo_set_mac_address    = dvb_net_set_mac,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+static void dvb_net_setup(struct net_device *dev)
+{
+       ether_setup(dev);
+
+       dev->header_ops         = &dvb_header_ops;
+       dev->netdev_ops         = &dvb_netdev_ops;
+       dev->mtu                = 4096;
+
+       dev->flags |= IFF_NOARP;
+}
+
+static int get_if(struct dvb_net *dvbnet)
+{
+       int i;
+
+       for (i=0; i<DVB_NET_DEVICES_MAX; i++)
+               if (!dvbnet->state[i])
+                       break;
+
+       if (i == DVB_NET_DEVICES_MAX)
+               return -1;
+
+       dvbnet->state[i]=1;
+       return i;
+}
+
+static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype)
+{
+       struct net_device *net;
+       struct dvb_net_priv *priv;
+       int result;
+       int if_num;
+
+       if (feedtype != DVB_NET_FEEDTYPE_MPE && feedtype != DVB_NET_FEEDTYPE_ULE)
+               return -EINVAL;
+       if ((if_num = get_if(dvbnet)) < 0)
+               return -EINVAL;
+
+       net = alloc_netdev(sizeof(struct dvb_net_priv), "dvb", dvb_net_setup);
+       if (!net)
+               return -ENOMEM;
+
+       if (dvbnet->dvbdev->id)
+               snprintf(net->name, IFNAMSIZ, "dvb%d%u%d",
+                        dvbnet->dvbdev->adapter->num, dvbnet->dvbdev->id, if_num);
+       else
+               /* compatibility fix to keep dvb0_0 format */
+               snprintf(net->name, IFNAMSIZ, "dvb%d_%d",
+                        dvbnet->dvbdev->adapter->num, if_num);
+
+       net->addr_len = 6;
+       memcpy(net->dev_addr, dvbnet->dvbdev->adapter->proposed_mac, 6);
+
+       dvbnet->device[if_num] = net;
+
+       priv = netdev_priv(net);
+       priv->net = net;
+       priv->demux = dvbnet->demux;
+       priv->pid = pid;
+       priv->rx_mode = RX_MODE_UNI;
+       priv->need_pusi = 1;
+       priv->tscc = 0;
+       priv->feedtype = feedtype;
+       reset_ule(priv);
+
+       INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list);
+       INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed);
+       mutex_init(&priv->mutex);
+
+       net->base_addr = pid;
+
+       if ((result = register_netdev(net)) < 0) {
+               dvbnet->device[if_num] = NULL;
+               free_netdev(net);
+               return result;
+       }
+       printk("dvb_net: created network interface %s\n", net->name);
+
+       return if_num;
+}
+
+static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num)
+{
+       struct net_device *net = dvbnet->device[num];
+       struct dvb_net_priv *priv;
+
+       if (!dvbnet->state[num])
+               return -EINVAL;
+       priv = netdev_priv(net);
+       if (priv->in_use)
+               return -EBUSY;
+
+       dvb_net_stop(net);
+       flush_work_sync(&priv->set_multicast_list_wq);
+       flush_work_sync(&priv->restart_net_feed_wq);
+       printk("dvb_net: removed network interface %s\n", net->name);
+       unregister_netdev(net);
+       dvbnet->state[num]=0;
+       dvbnet->device[num] = NULL;
+       free_netdev(net);
+
+       return 0;
+}
+
+static int dvb_net_do_ioctl(struct file *file,
+                 unsigned int cmd, void *parg)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_net *dvbnet = dvbdev->priv;
+
+       if (((file->f_flags&O_ACCMODE)==O_RDONLY))
+               return -EPERM;
+
+       switch (cmd) {
+       case NET_ADD_IF:
+       {
+               struct dvb_net_if *dvbnetif = parg;
+               int result;
+
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+
+               if (!try_module_get(dvbdev->adapter->module))
+                       return -EPERM;
+
+               result=dvb_net_add_if(dvbnet, dvbnetif->pid, dvbnetif->feedtype);
+               if (result<0) {
+                       module_put(dvbdev->adapter->module);
+                       return result;
+               }
+               dvbnetif->if_num=result;
+               break;
+       }
+       case NET_GET_IF:
+       {
+               struct net_device *netdev;
+               struct dvb_net_priv *priv_data;
+               struct dvb_net_if *dvbnetif = parg;
+
+               if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
+                   !dvbnet->state[dvbnetif->if_num])
+                       return -EINVAL;
+
+               netdev = dvbnet->device[dvbnetif->if_num];
+
+               priv_data = netdev_priv(netdev);
+               dvbnetif->pid=priv_data->pid;
+               dvbnetif->feedtype=priv_data->feedtype;
+               break;
+       }
+       case NET_REMOVE_IF:
+       {
+               int ret;
+
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+               if ((unsigned long) parg >= DVB_NET_DEVICES_MAX)
+                       return -EINVAL;
+               ret = dvb_net_remove_if(dvbnet, (unsigned long) parg);
+               if (!ret)
+                       module_put(dvbdev->adapter->module);
+               return ret;
+       }
+
+       /* binary compatibility cruft */
+       case __NET_ADD_IF_OLD:
+       {
+               struct __dvb_net_if_old *dvbnetif = parg;
+               int result;
+
+               if (!capable(CAP_SYS_ADMIN))
+                       return -EPERM;
+
+               if (!try_module_get(dvbdev->adapter->module))
+                       return -EPERM;
+
+               result=dvb_net_add_if(dvbnet, dvbnetif->pid, DVB_NET_FEEDTYPE_MPE);
+               if (result<0) {
+                       module_put(dvbdev->adapter->module);
+                       return result;
+               }
+               dvbnetif->if_num=result;
+               break;
+       }
+       case __NET_GET_IF_OLD:
+       {
+               struct net_device *netdev;
+               struct dvb_net_priv *priv_data;
+               struct __dvb_net_if_old *dvbnetif = parg;
+
+               if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
+                   !dvbnet->state[dvbnetif->if_num])
+                       return -EINVAL;
+
+               netdev = dvbnet->device[dvbnetif->if_num];
+
+               priv_data = netdev_priv(netdev);
+               dvbnetif->pid=priv_data->pid;
+               break;
+       }
+       default:
+               return -ENOTTY;
+       }
+       return 0;
+}
+
+static long dvb_net_ioctl(struct file *file,
+             unsigned int cmd, unsigned long arg)
+{
+       return dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl);
+}
+
+static int dvb_net_close(struct inode *inode, struct file *file)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct dvb_net *dvbnet = dvbdev->priv;
+
+       dvb_generic_release(inode, file);
+
+       if(dvbdev->users == 1 && dvbnet->exit == 1) {
+               fops_put(file->f_op);
+               file->f_op = NULL;
+               wake_up(&dvbdev->wait_queue);
+       }
+       return 0;
+}
+
+
+static const struct file_operations dvb_net_fops = {
+       .owner = THIS_MODULE,
+       .unlocked_ioctl = dvb_net_ioctl,
+       .open = dvb_generic_open,
+       .release = dvb_net_close,
+       .llseek = noop_llseek,
+};
+
+static struct dvb_device dvbdev_net = {
+       .priv = NULL,
+       .users = 1,
+       .writers = 1,
+       .fops = &dvb_net_fops,
+};
+
+
+void dvb_net_release (struct dvb_net *dvbnet)
+{
+       int i;
+
+       dvbnet->exit = 1;
+       if (dvbnet->dvbdev->users < 1)
+               wait_event(dvbnet->dvbdev->wait_queue,
+                               dvbnet->dvbdev->users==1);
+
+       dvb_unregister_device(dvbnet->dvbdev);
+
+       for (i=0; i<DVB_NET_DEVICES_MAX; i++) {
+               if (!dvbnet->state[i])
+                       continue;
+               dvb_net_remove_if(dvbnet, i);
+       }
+}
+EXPORT_SYMBOL(dvb_net_release);
+
+
+int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet,
+                 struct dmx_demux *dmx)
+{
+       int i;
+
+       dvbnet->demux = dmx;
+
+       for (i=0; i<DVB_NET_DEVICES_MAX; i++)
+               dvbnet->state[i] = 0;
+
+       return dvb_register_device(adap, &dvbnet->dvbdev, &dvbdev_net,
+                            dvbnet, DVB_DEVICE_NET);
+}
+EXPORT_SYMBOL(dvb_net_init);
diff --git a/drivers/media/dvb-core/dvb_net.h b/drivers/media/dvb-core/dvb_net.h
new file mode 100644 (file)
index 0000000..1e53acd
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * dvb_net.h
+ *
+ * Copyright (C) 2001 Ralph Metzler for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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 _DVB_NET_H_
+#define _DVB_NET_H_
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include "dvbdev.h"
+
+#define DVB_NET_DEVICES_MAX 10
+
+#ifdef CONFIG_DVB_NET
+
+struct dvb_net {
+       struct dvb_device *dvbdev;
+       struct net_device *device[DVB_NET_DEVICES_MAX];
+       int state[DVB_NET_DEVICES_MAX];
+       unsigned int exit:1;
+       struct dmx_demux *demux;
+};
+
+void dvb_net_release(struct dvb_net *);
+int  dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *);
+
+#else
+
+struct dvb_net {
+       struct dvb_device *dvbdev;
+};
+
+static inline void dvb_net_release(struct dvb_net *dvbnet)
+{
+}
+
+static inline int dvb_net_init(struct dvb_adapter *adap,
+                              struct dvb_net *dvbnet, struct dmx_demux *dmx)
+{
+       return 0;
+}
+
+#endif /* ifdef CONFIG_DVB_NET */
+
+#endif
diff --git a/drivers/media/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb-core/dvb_ringbuffer.c
new file mode 100644 (file)
index 0000000..a5712cd
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+ *
+ * dvb_ringbuffer.c: ring buffer implementation for the dvb driver
+ *
+ * Copyright (C) 2003 Oliver Endriss
+ * Copyright (C) 2004 Andrew de Quincey
+ *
+ * based on code originally found in av7110.c & dvb_ci.c:
+ * Copyright (C) 1999-2003 Ralph  Metzler
+ *                       & Marcus Metzler for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
+
+#include "dvb_ringbuffer.h"
+
+#define PKT_READY 0
+#define PKT_DISPOSED 1
+
+
+void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
+{
+       rbuf->pread=rbuf->pwrite=0;
+       rbuf->data=data;
+       rbuf->size=len;
+       rbuf->error=0;
+
+       init_waitqueue_head(&rbuf->queue);
+
+       spin_lock_init(&(rbuf->lock));
+}
+
+
+
+int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf)
+{
+       return (rbuf->pread==rbuf->pwrite);
+}
+
+
+
+ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf)
+{
+       ssize_t free;
+
+       free = rbuf->pread - rbuf->pwrite;
+       if (free <= 0)
+               free += rbuf->size;
+       return free-1;
+}
+
+
+
+ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
+{
+       ssize_t avail;
+
+       avail = rbuf->pwrite - rbuf->pread;
+       if (avail < 0)
+               avail += rbuf->size;
+       return avail;
+}
+
+
+
+void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
+{
+       rbuf->pread = rbuf->pwrite;
+       rbuf->error = 0;
+}
+EXPORT_SYMBOL(dvb_ringbuffer_flush);
+
+void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf)
+{
+       rbuf->pread = rbuf->pwrite = 0;
+       rbuf->error = 0;
+}
+
+void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&rbuf->lock, flags);
+       dvb_ringbuffer_flush(rbuf);
+       spin_unlock_irqrestore(&rbuf->lock, flags);
+
+       wake_up(&rbuf->queue);
+}
+
+ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, size_t len)
+{
+       size_t todo = len;
+       size_t split;
+
+       split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
+       if (split > 0) {
+               if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
+                       return -EFAULT;
+               buf += split;
+               todo -= split;
+               rbuf->pread = 0;
+       }
+       if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
+               return -EFAULT;
+
+       rbuf->pread = (rbuf->pread + todo) % rbuf->size;
+
+       return len;
+}
+
+void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len)
+{
+       size_t todo = len;
+       size_t split;
+
+       split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
+       if (split > 0) {
+               memcpy(buf, rbuf->data+rbuf->pread, split);
+               buf += split;
+               todo -= split;
+               rbuf->pread = 0;
+       }
+       memcpy(buf, rbuf->data+rbuf->pread, todo);
+
+       rbuf->pread = (rbuf->pread + todo) % rbuf->size;
+}
+
+
+ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len)
+{
+       size_t todo = len;
+       size_t split;
+
+       split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
+
+       if (split > 0) {
+               memcpy(rbuf->data+rbuf->pwrite, buf, split);
+               buf += split;
+               todo -= split;
+               rbuf->pwrite = 0;
+       }
+       memcpy(rbuf->data+rbuf->pwrite, buf, todo);
+       rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
+
+       return len;
+}
+
+ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len)
+{
+       int status;
+       ssize_t oldpwrite = rbuf->pwrite;
+
+       DVB_RINGBUFFER_WRITE_BYTE(rbuf, len >> 8);
+       DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff);
+       DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_READY);
+       status = dvb_ringbuffer_write(rbuf, buf, len);
+
+       if (status < 0) rbuf->pwrite = oldpwrite;
+       return status;
+}
+
+ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
+                               int offset, u8 __user *buf, size_t len)
+{
+       size_t todo;
+       size_t split;
+       size_t pktlen;
+
+       pktlen = rbuf->data[idx] << 8;
+       pktlen |= rbuf->data[(idx + 1) % rbuf->size];
+       if (offset > pktlen) return -EINVAL;
+       if ((offset + len) > pktlen) len = pktlen - offset;
+
+       idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
+       todo = len;
+       split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
+       if (split > 0) {
+               if (copy_to_user(buf, rbuf->data+idx, split))
+                       return -EFAULT;
+               buf += split;
+               todo -= split;
+               idx = 0;
+       }
+       if (copy_to_user(buf, rbuf->data+idx, todo))
+               return -EFAULT;
+
+       return len;
+}
+
+ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
+                               int offset, u8* buf, size_t len)
+{
+       size_t todo;
+       size_t split;
+       size_t pktlen;
+
+       pktlen = rbuf->data[idx] << 8;
+       pktlen |= rbuf->data[(idx + 1) % rbuf->size];
+       if (offset > pktlen) return -EINVAL;
+       if ((offset + len) > pktlen) len = pktlen - offset;
+
+       idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
+       todo = len;
+       split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
+       if (split > 0) {
+               memcpy(buf, rbuf->data+idx, split);
+               buf += split;
+               todo -= split;
+               idx = 0;
+       }
+       memcpy(buf, rbuf->data+idx, todo);
+       return len;
+}
+
+void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx)
+{
+       size_t pktlen;
+
+       rbuf->data[(idx + 2) % rbuf->size] = PKT_DISPOSED;
+
+       // clean up disposed packets
+       while(dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) {
+               if (DVB_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) {
+                       pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8;
+                       pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1);
+                       DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE);
+               } else {
+                       // first packet is not disposed, so we stop cleaning now
+                       break;
+               }
+       }
+}
+
+ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen)
+{
+       int consumed;
+       int curpktlen;
+       int curpktstatus;
+
+       if (idx == -1) {
+              idx = rbuf->pread;
+       } else {
+               curpktlen = rbuf->data[idx] << 8;
+               curpktlen |= rbuf->data[(idx + 1) % rbuf->size];
+               idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
+       }
+
+       consumed = (idx - rbuf->pread) % rbuf->size;
+
+       while((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) {
+
+               curpktlen = rbuf->data[idx] << 8;
+               curpktlen |= rbuf->data[(idx + 1) % rbuf->size];
+               curpktstatus = rbuf->data[(idx + 2) % rbuf->size];
+
+               if (curpktstatus == PKT_READY) {
+                       *pktlen = curpktlen;
+                       return idx;
+               }
+
+               consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE;
+               idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
+       }
+
+       // no packets available
+       return -1;
+}
+
+
+
+EXPORT_SYMBOL(dvb_ringbuffer_init);
+EXPORT_SYMBOL(dvb_ringbuffer_empty);
+EXPORT_SYMBOL(dvb_ringbuffer_free);
+EXPORT_SYMBOL(dvb_ringbuffer_avail);
+EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
+EXPORT_SYMBOL(dvb_ringbuffer_read_user);
+EXPORT_SYMBOL(dvb_ringbuffer_read);
+EXPORT_SYMBOL(dvb_ringbuffer_write);
diff --git a/drivers/media/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb-core/dvb_ringbuffer.h
new file mode 100644 (file)
index 0000000..41f04da
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+ *
+ * dvb_ringbuffer.h: ring buffer implementation for the dvb driver
+ *
+ * Copyright (C) 2003 Oliver Endriss
+ * Copyright (C) 2004 Andrew de Quincey
+ *
+ * based on code originally found in av7110.c & dvb_ci.c:
+ * Copyright (C) 1999-2003 Ralph Metzler & Marcus Metzler
+ *                         for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef _DVB_RINGBUFFER_H_
+#define _DVB_RINGBUFFER_H_
+
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+
+struct dvb_ringbuffer {
+       u8               *data;
+       ssize_t           size;
+       ssize_t           pread;
+       ssize_t           pwrite;
+       int               error;
+
+       wait_queue_head_t queue;
+       spinlock_t        lock;
+};
+
+#define DVB_RINGBUFFER_PKTHDRSIZE 3
+
+
+/*
+** Notes:
+** ------
+** (1) For performance reasons read and write routines don't check buffer sizes
+**     and/or number of bytes free/available. This has to be done before these
+**     routines are called. For example:
+**
+**     *** write <buflen> bytes ***
+**     free = dvb_ringbuffer_free(rbuf);
+**     if (free >= buflen)
+**         count = dvb_ringbuffer_write(rbuf, buffer, buflen);
+**     else
+**         ...
+**
+**     *** read min. 1000, max. <bufsize> bytes ***
+**     avail = dvb_ringbuffer_avail(rbuf);
+**     if (avail >= 1000)
+**         count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize));
+**     else
+**         ...
+**
+** (2) If there is exactly one reader and one writer, there is no need
+**     to lock read or write operations.
+**     Two or more readers must be locked against each other.
+**     Flushing the buffer counts as a read operation.
+**     Resetting the buffer counts as a read and write operation.
+**     Two or more writers must be locked against each other.
+*/
+
+/* initialize ring buffer, lock and queue */
+extern void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len);
+
+/* test whether buffer is empty */
+extern int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf);
+
+/* return the number of free bytes in the buffer */
+extern ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf);
+
+/* return the number of bytes waiting in the buffer */
+extern ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf);
+
+
+/*
+** Reset the read and write pointers to zero and flush the buffer
+** This counts as a read and write operation
+*/
+extern void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf);
+
+
+/* read routines & macros */
+/* ---------------------- */
+/* flush buffer */
+extern void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf);
+
+/* flush buffer protected by spinlock and wake-up waiting task(s) */
+extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf);
+
+/* peek at byte <offs> in the buffer */
+#define DVB_RINGBUFFER_PEEK(rbuf,offs) \
+                       (rbuf)->data[((rbuf)->pread+(offs))%(rbuf)->size]
+
+/* advance read ptr by <num> bytes */
+#define DVB_RINGBUFFER_SKIP(rbuf,num)  \
+                       (rbuf)->pread=((rbuf)->pread+(num))%(rbuf)->size
+
+/*
+** read <len> bytes from ring buffer into <buf>
+** <usermem> specifies whether <buf> resides in user space
+** returns number of bytes transferred or -EFAULT
+*/
+extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf,
+                                  u8 __user *buf, size_t len);
+extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf,
+                                  u8 *buf, size_t len);
+
+
+/* write routines & macros */
+/* ----------------------- */
+/* write single byte to ring buffer */
+#define DVB_RINGBUFFER_WRITE_BYTE(rbuf,byte)   \
+                       { (rbuf)->data[(rbuf)->pwrite]=(byte); \
+                       (rbuf)->pwrite=((rbuf)->pwrite+1)%(rbuf)->size; }
+/*
+** write <len> bytes to ring buffer
+** <usermem> specifies whether <buf> resides in user space
+** returns number of bytes transferred or -EFAULT
+*/
+extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
+                                   size_t len);
+
+
+/**
+ * Write a packet into the ringbuffer.
+ *
+ * <rbuf> Ringbuffer to write to.
+ * <buf> Buffer to write.
+ * <len> Length of buffer (currently limited to 65535 bytes max).
+ * returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
+ */
+extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
+                                       size_t len);
+
+/**
+ * Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this
+ * does NOT update the read pointer in the ringbuffer. You must use
+ * dvb_ringbuffer_pkt_dispose() to mark a packet as no longer required.
+ *
+ * <rbuf> Ringbuffer concerned.
+ * <idx> Packet index as returned by dvb_ringbuffer_pkt_next().
+ * <offset> Offset into packet to read from.
+ * <buf> Destination buffer for data.
+ * <len> Size of destination buffer.
+ * <usermem> Set to 1 if <buf> is in userspace.
+ * returns Number of bytes read, or -EFAULT.
+ */
+extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
+                                      int offset, u8 __user *buf, size_t len);
+extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
+                                      int offset, u8 *buf, size_t len);
+
+/**
+ * Dispose of a packet in the ring buffer.
+ *
+ * <rbuf> Ring buffer concerned.
+ * <idx> Packet index as returned by dvb_ringbuffer_pkt_next().
+ */
+extern void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx);
+
+/**
+ * Get the index of the next packet in a ringbuffer.
+ *
+ * <rbuf> Ringbuffer concerned.
+ * <idx> Previous packet index, or -1 to return the first packet index.
+ * <pktlen> On success, will be updated to contain the length of the packet in bytes.
+ * returns Packet index (if >=0), or -1 if no packets available.
+ */
+extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen);
+
+
+#endif /* _DVB_RINGBUFFER_H_ */
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
new file mode 100644 (file)
index 0000000..39eab73
--- /dev/null
@@ -0,0 +1,507 @@
+/*
+ * dvbdev.c
+ *
+ * Copyright (C) 2000 Ralph  Metzler <ralph@convergence.de>
+ *                  & Marcus Metzler <marcus@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 <linux/types.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/mutex.h>
+#include "dvbdev.h"
+
+static DEFINE_MUTEX(dvbdev_mutex);
+static int dvbdev_debug;
+
+module_param(dvbdev_debug, int, 0644);
+MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off).");
+
+#define dprintk if (dvbdev_debug) printk
+
+static LIST_HEAD(dvb_adapter_list);
+static DEFINE_MUTEX(dvbdev_register_lock);
+
+static const char * const dnames[] = {
+       "video", "audio", "sec", "frontend", "demux", "dvr", "ca",
+       "net", "osd"
+};
+
+#ifdef CONFIG_DVB_DYNAMIC_MINORS
+#define MAX_DVB_MINORS         256
+#define DVB_MAX_IDS            MAX_DVB_MINORS
+#else
+#define DVB_MAX_IDS            4
+#define nums2minor(num,type,id)        ((num << 6) | (id << 4) | type)
+#define MAX_DVB_MINORS         (DVB_MAX_ADAPTERS*64)
+#endif
+
+static struct class *dvb_class;
+
+static struct dvb_device *dvb_minors[MAX_DVB_MINORS];
+static DECLARE_RWSEM(minor_rwsem);
+
+static int dvb_device_open(struct inode *inode, struct file *file)
+{
+       struct dvb_device *dvbdev;
+
+       mutex_lock(&dvbdev_mutex);
+       down_read(&minor_rwsem);
+       dvbdev = dvb_minors[iminor(inode)];
+
+       if (dvbdev && dvbdev->fops) {
+               int err = 0;
+               const struct file_operations *old_fops;
+
+               file->private_data = dvbdev;
+               old_fops = file->f_op;
+               file->f_op = fops_get(dvbdev->fops);
+               if (file->f_op == NULL) {
+                       file->f_op = old_fops;
+                       goto fail;
+               }
+               if(file->f_op->open)
+                       err = file->f_op->open(inode,file);
+               if (err) {
+                       fops_put(file->f_op);
+                       file->f_op = fops_get(old_fops);
+               }
+               fops_put(old_fops);
+               up_read(&minor_rwsem);
+               mutex_unlock(&dvbdev_mutex);
+               return err;
+       }
+fail:
+       up_read(&minor_rwsem);
+       mutex_unlock(&dvbdev_mutex);
+       return -ENODEV;
+}
+
+
+static const struct file_operations dvb_device_fops =
+{
+       .owner =        THIS_MODULE,
+       .open =         dvb_device_open,
+       .llseek =       noop_llseek,
+};
+
+static struct cdev dvb_device_cdev;
+
+int dvb_generic_open(struct inode *inode, struct file *file)
+{
+       struct dvb_device *dvbdev = file->private_data;
+
+       if (!dvbdev)
+               return -ENODEV;
+
+       if (!dvbdev->users)
+               return -EBUSY;
+
+       if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+               if (!dvbdev->readers)
+                       return -EBUSY;
+               dvbdev->readers--;
+       } else {
+               if (!dvbdev->writers)
+                       return -EBUSY;
+               dvbdev->writers--;
+       }
+
+       dvbdev->users--;
+       return 0;
+}
+EXPORT_SYMBOL(dvb_generic_open);
+
+
+int dvb_generic_release(struct inode *inode, struct file *file)
+{
+       struct dvb_device *dvbdev = file->private_data;
+
+       if (!dvbdev)
+               return -ENODEV;
+
+       if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
+               dvbdev->readers++;
+       } else {
+               dvbdev->writers++;
+       }
+
+       dvbdev->users++;
+       return 0;
+}
+EXPORT_SYMBOL(dvb_generic_release);
+
+
+long dvb_generic_ioctl(struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       struct dvb_device *dvbdev = file->private_data;
+
+       if (!dvbdev)
+               return -ENODEV;
+
+       if (!dvbdev->kernel_ioctl)
+               return -EINVAL;
+
+       return dvb_usercopy(file, cmd, arg, dvbdev->kernel_ioctl);
+}
+EXPORT_SYMBOL(dvb_generic_ioctl);
+
+
+static int dvbdev_get_free_id (struct dvb_adapter *adap, int type)
+{
+       u32 id = 0;
+
+       while (id < DVB_MAX_IDS) {
+               struct dvb_device *dev;
+               list_for_each_entry(dev, &adap->device_list, list_head)
+                       if (dev->type == type && dev->id == id)
+                               goto skip;
+               return id;
+skip:
+               id++;
+       }
+       return -ENFILE;
+}
+
+
+int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
+                       const struct dvb_device *template, void *priv, int type)
+{
+       struct dvb_device *dvbdev;
+       struct file_operations *dvbdevfops;
+       struct device *clsdev;
+       int minor;
+       int id;
+
+       mutex_lock(&dvbdev_register_lock);
+
+       if ((id = dvbdev_get_free_id (adap, type)) < 0){
+               mutex_unlock(&dvbdev_register_lock);
+               *pdvbdev = NULL;
+               printk(KERN_ERR "%s: couldn't find free device id\n", __func__);
+               return -ENFILE;
+       }
+
+       *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL);
+
+       if (!dvbdev){
+               mutex_unlock(&dvbdev_register_lock);
+               return -ENOMEM;
+       }
+
+       dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
+
+       if (!dvbdevfops){
+               kfree (dvbdev);
+               mutex_unlock(&dvbdev_register_lock);
+               return -ENOMEM;
+       }
+
+       memcpy(dvbdev, template, sizeof(struct dvb_device));
+       dvbdev->type = type;
+       dvbdev->id = id;
+       dvbdev->adapter = adap;
+       dvbdev->priv = priv;
+       dvbdev->fops = dvbdevfops;
+       init_waitqueue_head (&dvbdev->wait_queue);
+
+       memcpy(dvbdevfops, template->fops, sizeof(struct file_operations));
+       dvbdevfops->owner = adap->module;
+
+       list_add_tail (&dvbdev->list_head, &adap->device_list);
+
+       down_write(&minor_rwsem);
+#ifdef CONFIG_DVB_DYNAMIC_MINORS
+       for (minor = 0; minor < MAX_DVB_MINORS; minor++)
+               if (dvb_minors[minor] == NULL)
+                       break;
+
+       if (minor == MAX_DVB_MINORS) {
+               kfree(dvbdevfops);
+               kfree(dvbdev);
+               up_write(&minor_rwsem);
+               mutex_unlock(&dvbdev_register_lock);
+               return -EINVAL;
+       }
+#else
+       minor = nums2minor(adap->num, type, id);
+#endif
+
+       dvbdev->minor = minor;
+       dvb_minors[minor] = dvbdev;
+       up_write(&minor_rwsem);
+
+       mutex_unlock(&dvbdev_register_lock);
+
+       clsdev = device_create(dvb_class, adap->device,
+                              MKDEV(DVB_MAJOR, minor),
+                              dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
+       if (IS_ERR(clsdev)) {
+               printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
+                      __func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
+               return PTR_ERR(clsdev);
+       }
+
+       dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
+               adap->num, dnames[type], id, minor, minor);
+
+       return 0;
+}
+EXPORT_SYMBOL(dvb_register_device);
+
+
+void dvb_unregister_device(struct dvb_device *dvbdev)
+{
+       if (!dvbdev)
+               return;
+
+       down_write(&minor_rwsem);
+       dvb_minors[dvbdev->minor] = NULL;
+       up_write(&minor_rwsem);
+
+       device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
+
+       list_del (&dvbdev->list_head);
+       kfree (dvbdev->fops);
+       kfree (dvbdev);
+}
+EXPORT_SYMBOL(dvb_unregister_device);
+
+static int dvbdev_check_free_adapter_num(int num)
+{
+       struct list_head *entry;
+       list_for_each(entry, &dvb_adapter_list) {
+               struct dvb_adapter *adap;
+               adap = list_entry(entry, struct dvb_adapter, list_head);
+               if (adap->num == num)
+                       return 0;
+       }
+       return 1;
+}
+
+static int dvbdev_get_free_adapter_num (void)
+{
+       int num = 0;
+
+       while (num < DVB_MAX_ADAPTERS) {
+               if (dvbdev_check_free_adapter_num(num))
+                       return num;
+               num++;
+       }
+
+       return -ENFILE;
+}
+
+
+int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
+                        struct module *module, struct device *device,
+                        short *adapter_nums)
+{
+       int i, num;
+
+       mutex_lock(&dvbdev_register_lock);
+
+       for (i = 0; i < DVB_MAX_ADAPTERS; ++i) {
+               num = adapter_nums[i];
+               if (num >= 0  &&  num < DVB_MAX_ADAPTERS) {
+               /* use the one the driver asked for */
+                       if (dvbdev_check_free_adapter_num(num))
+                               break;
+               } else {
+                       num = dvbdev_get_free_adapter_num();
+                       break;
+               }
+               num = -1;
+       }
+
+       if (num < 0) {
+               mutex_unlock(&dvbdev_register_lock);
+               return -ENFILE;
+       }
+
+       memset (adap, 0, sizeof(struct dvb_adapter));
+       INIT_LIST_HEAD (&adap->device_list);
+
+       printk(KERN_INFO "DVB: registering new adapter (%s)\n", name);
+
+       adap->num = num;
+       adap->name = name;
+       adap->module = module;
+       adap->device = device;
+       adap->mfe_shared = 0;
+       adap->mfe_dvbdev = NULL;
+       mutex_init (&adap->mfe_lock);
+
+       list_add_tail (&adap->list_head, &dvb_adapter_list);
+
+       mutex_unlock(&dvbdev_register_lock);
+
+       return num;
+}
+EXPORT_SYMBOL(dvb_register_adapter);
+
+
+int dvb_unregister_adapter(struct dvb_adapter *adap)
+{
+       mutex_lock(&dvbdev_register_lock);
+       list_del (&adap->list_head);
+       mutex_unlock(&dvbdev_register_lock);
+       return 0;
+}
+EXPORT_SYMBOL(dvb_unregister_adapter);
+
+/* if the miracle happens and "generic_usercopy()" is included into
+   the kernel, then this can vanish. please don't make the mistake and
+   define this as video_usercopy(). this will introduce a dependecy
+   to the v4l "videodev.o" module, which is unnecessary for some
+   cards (ie. the budget dvb-cards don't need the v4l module...) */
+int dvb_usercopy(struct file *file,
+                    unsigned int cmd, unsigned long arg,
+                    int (*func)(struct file *file,
+                    unsigned int cmd, void *arg))
+{
+       char    sbuf[128];
+       void    *mbuf = NULL;
+       void    *parg = NULL;
+       int     err  = -EINVAL;
+
+       /*  Copy arguments into temp kernel buffer  */
+       switch (_IOC_DIR(cmd)) {
+       case _IOC_NONE:
+               /*
+                * For this command, the pointer is actually an integer
+                * argument.
+                */
+               parg = (void *) arg;
+               break;
+       case _IOC_READ: /* some v4l ioctls are marked wrong ... */
+       case _IOC_WRITE:
+       case (_IOC_WRITE | _IOC_READ):
+               if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
+                       parg = sbuf;
+               } else {
+                       /* too big to allocate from stack */
+                       mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
+                       if (NULL == mbuf)
+                               return -ENOMEM;
+                       parg = mbuf;
+               }
+
+               err = -EFAULT;
+               if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
+                       goto out;
+               break;
+       }
+
+       /* call driver */
+       mutex_lock(&dvbdev_mutex);
+       if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD)
+               err = -EINVAL;
+       mutex_unlock(&dvbdev_mutex);
+
+       if (err < 0)
+               goto out;
+
+       /*  Copy results into user buffer  */
+       switch (_IOC_DIR(cmd))
+       {
+       case _IOC_READ:
+       case (_IOC_WRITE | _IOC_READ):
+               if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
+                       err = -EFAULT;
+               break;
+       }
+
+out:
+       kfree(mbuf);
+       return err;
+}
+
+static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+       struct dvb_device *dvbdev = dev_get_drvdata(dev);
+
+       add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num);
+       add_uevent_var(env, "DVB_DEVICE_TYPE=%s", dnames[dvbdev->type]);
+       add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id);
+       return 0;
+}
+
+static char *dvb_devnode(struct device *dev, umode_t *mode)
+{
+       struct dvb_device *dvbdev = dev_get_drvdata(dev);
+
+       return kasprintf(GFP_KERNEL, "dvb/adapter%d/%s%d",
+               dvbdev->adapter->num, dnames[dvbdev->type], dvbdev->id);
+}
+
+
+static int __init init_dvbdev(void)
+{
+       int retval;
+       dev_t dev = MKDEV(DVB_MAJOR, 0);
+
+       if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
+               printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR);
+               return retval;
+       }
+
+       cdev_init(&dvb_device_cdev, &dvb_device_fops);
+       if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) {
+               printk(KERN_ERR "dvb-core: unable register character device\n");
+               goto error;
+       }
+
+       dvb_class = class_create(THIS_MODULE, "dvb");
+       if (IS_ERR(dvb_class)) {
+               retval = PTR_ERR(dvb_class);
+               goto error;
+       }
+       dvb_class->dev_uevent = dvb_uevent;
+       dvb_class->devnode = dvb_devnode;
+       return 0;
+
+error:
+       cdev_del(&dvb_device_cdev);
+       unregister_chrdev_region(dev, MAX_DVB_MINORS);
+       return retval;
+}
+
+
+static void __exit exit_dvbdev(void)
+{
+       class_destroy(dvb_class);
+       cdev_del(&dvb_device_cdev);
+       unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS);
+}
+
+subsys_initcall(init_dvbdev);
+module_exit(exit_dvbdev);
+
+MODULE_DESCRIPTION("DVB Core Driver");
+MODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-core/dvbdev.h b/drivers/media/dvb-core/dvbdev.h
new file mode 100644 (file)
index 0000000..93a9470
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * dvbdev.h
+ *
+ * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
+ *                    for convergence integrated media GmbH
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General 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 _DVBDEV_H_
+#define _DVBDEV_H_
+
+#include <linux/types.h>
+#include <linux/poll.h>
+#include <linux/fs.h>
+#include <linux/list.h>
+
+#define DVB_MAJOR 212
+
+#if defined(CONFIG_DVB_MAX_ADAPTERS) && CONFIG_DVB_MAX_ADAPTERS > 0
+  #define DVB_MAX_ADAPTERS CONFIG_DVB_MAX_ADAPTERS
+#else
+  #define DVB_MAX_ADAPTERS 8
+#endif
+
+#define DVB_UNSET (-1)
+
+#define DVB_DEVICE_VIDEO      0
+#define DVB_DEVICE_AUDIO      1
+#define DVB_DEVICE_SEC        2
+#define DVB_DEVICE_FRONTEND   3
+#define DVB_DEVICE_DEMUX      4
+#define DVB_DEVICE_DVR        5
+#define DVB_DEVICE_CA         6
+#define DVB_DEVICE_NET        7
+#define DVB_DEVICE_OSD        8
+
+#define DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr) \
+       static short adapter_nr[] = \
+               {[0 ... (DVB_MAX_ADAPTERS - 1)] = DVB_UNSET }; \
+       module_param_array(adapter_nr, short, NULL, 0444); \
+       MODULE_PARM_DESC(adapter_nr, "DVB adapter numbers")
+
+struct dvb_frontend;
+
+struct dvb_adapter {
+       int num;
+       struct list_head list_head;
+       struct list_head device_list;
+       const char *name;
+       u8 proposed_mac [6];
+       void* priv;
+
+       struct device *device;
+
+       struct module *module;
+
+       int mfe_shared;                 /* indicates mutually exclusive frontends */
+       struct dvb_device *mfe_dvbdev;  /* frontend device in use */
+       struct mutex mfe_lock;          /* access lock for thread creation */
+};
+
+
+struct dvb_device {
+       struct list_head list_head;
+       const struct file_operations *fops;
+       struct dvb_adapter *adapter;
+       int type;
+       int minor;
+       u32 id;
+
+       /* in theory, 'users' can vanish now,
+          but I don't want to change too much now... */
+       int readers;
+       int writers;
+       int users;
+
+       wait_queue_head_t         wait_queue;
+       /* don't really need those !? -- FIXME: use video_usercopy  */
+       int (*kernel_ioctl)(struct file *file, unsigned int cmd, void *arg);
+
+       void *priv;
+};
+
+
+extern int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
+                               struct module *module, struct device *device,
+                               short *adapter_nums);
+extern int dvb_unregister_adapter (struct dvb_adapter *adap);
+
+extern int dvb_register_device (struct dvb_adapter *adap,
+                               struct dvb_device **pdvbdev,
+                               const struct dvb_device *template,
+                               void *priv,
+                               int type);
+
+extern void dvb_unregister_device (struct dvb_device *dvbdev);
+
+extern int dvb_generic_open (struct inode *inode, struct file *file);
+extern int dvb_generic_release (struct inode *inode, struct file *file);
+extern long dvb_generic_ioctl (struct file *file,
+                             unsigned int cmd, unsigned long arg);
+
+/* we don't mess with video_usercopy() any more,
+we simply define out own dvb_usercopy(), which will hopefully become
+generic_usercopy()  someday... */
+
+extern int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
+                           int (*func)(struct file *file, unsigned int cmd, void *arg));
+
+/** generic DVB attach function. */
+#ifdef CONFIG_MEDIA_ATTACH
+#define dvb_attach(FUNCTION, ARGS...) ({ \
+       void *__r = NULL; \
+       typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
+       if (__a) { \
+               __r = (void *) __a(ARGS); \
+               if (__r == NULL) \
+                       symbol_put(FUNCTION); \
+       } else { \
+               printk(KERN_ERR "DVB: Unable to find symbol "#FUNCTION"()\n"); \
+       } \
+       __r; \
+})
+
+#else
+#define dvb_attach(FUNCTION, ARGS...) ({ \
+       FUNCTION(ARGS); \
+})
+
+#endif
+
+#endif /* #ifndef _DVBDEV_H_ */
index 3a6ccbc02addcc9e247b76984f9779e261869abb..5a2c4bd75480199eff3d6cbf32b091f90edc4780 100644 (file)
@@ -2,32 +2,6 @@
 # DVB device configuration
 #
 
-config DVB_MAX_ADAPTERS
-       int "maximum number of DVB/ATSC adapters"
-       depends on DVB_CORE
-       default 8
-       range 1 255
-       help
-         Maximum number of DVB/ATSC adapters. Increasing this number
-         increases the memory consumption of the DVB subsystem even
-         if a much lower number of DVB/ATSC adapters is present.
-         Only values in the range 4-32 are tested.
-
-         If you are unsure about this, use the default value 8
-
-config DVB_DYNAMIC_MINORS
-       bool "Dynamic DVB minor allocation"
-       depends on DVB_CORE
-       default n
-       help
-         If you say Y here, the DVB subsystem will use dynamic minor
-         allocation for any device that uses the DVB major number.
-         This means that you can have more than 4 of a single type
-         of device (like demuxes and frontends) per adapter, but udev
-         will be required to manage the device nodes.
-
-         If you are unsure about this, say N here.
-
 menuconfig DVB_CAPTURE_DRIVERS
        bool "DVB/ATSC adapters"
        depends on DVB_CORE
index 8f7e0129d70e3840f1cfda8162228238a454d01a..b14aa9dd0156bc41aa58340d4fff0a70a8f01042 100644 (file)
@@ -2,8 +2,7 @@
 # Makefile for the kernel multimedia device drivers.
 #
 
-obj-y        := dvb-core/      \
-               frontends/      \
+obj-y        :=        frontends/      \
                ttpci/          \
                ttusb-dec/      \
                ttusb-budget/   \
index 3d04a8dba99e962d30572de670a7f1816fdbb363..e4291e4aba2347bb24d60ddd8b9e2adc4767d69f 100644 (file)
@@ -12,5 +12,5 @@ obj-$(CONFIG_DVB_B2C2_FLEXCOP_PCI) += b2c2-flexcop-pci.o
 b2c2-flexcop-usb-objs = flexcop-usb.o
 obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
 
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb/frontends/
 ccflags-y += -Idrivers/media/common/tuners/
index 0713b3af205071361fbd42218f090c85133faff8..7c2dd04d37e47073730bb9e5d6be6e5eaf1dfeb2 100644 (file)
@@ -1,6 +1,6 @@
 obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
 
-ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb-core
 ccflags-y += -Idrivers/media/dvb/frontends
 ccflags-y += -Idrivers/media/video/bt8xx
 ccflags-y += -Idrivers/media/common/tuners
index 38019bafb862246b992f6026f77314f460cb2c78..9eca27dd732840045fac9dfe7c4f96a1c46f3b88 100644 (file)
@@ -6,7 +6,7 @@ ddbridge-objs := ddbridge-core.o
 
 obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
 
-ccflags-y += -Idrivers/media/dvb/dvb-core/
+ccflags-y += -Idrivers/media/dvb-core/
 ccflags-y += -Idrivers/media/dvb/frontends/
 ccflags-y += -Idrivers/media/common/tuners/
 
index 95a008b71fe539aae8db1d4276bc9f137460c2c5..0dc5963ee807e5d8ed99740ce04a15f353adf3c1 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_DM1105) += dm1105.o
 
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb/frontends
diff --git a/drivers/media/dvb/dvb-core/Makefile b/drivers/media/dvb/dvb-core/Makefile
deleted file mode 100644 (file)
index 8f22bcd..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Makefile for the kernel DVB device drivers.
-#
-
-dvb-net-$(CONFIG_DVB_NET) := dvb_net.o
-
-dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o    \
-                dvb_ca_en50221.o dvb_frontend.o                \
-                $(dvb-net-y) dvb_ringbuffer.o dvb_math.o
-
-obj-$(CONFIG_DVB_CORE) += dvb-core.o
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
deleted file mode 100644 (file)
index eb91fd8..0000000
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * demux.h
- *
- * Copyright (c) 2002 Convergence GmbH
- *
- * based on code:
- * Copyright (c) 2000 Nokia Research Center
- *                    Tampere, FINLAND
- *
- * 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 __DEMUX_H
-#define __DEMUX_H
-
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/list.h>
-#include <linux/time.h>
-#include <linux/dvb/dmx.h>
-
-/*--------------------------------------------------------------------------*/
-/* Common definitions */
-/*--------------------------------------------------------------------------*/
-
-/*
- * DMX_MAX_FILTER_SIZE: Maximum length (in bytes) of a section/PES filter.
- */
-
-#ifndef DMX_MAX_FILTER_SIZE
-#define DMX_MAX_FILTER_SIZE 18
-#endif
-
-/*
- * DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed filter.
- */
-
-#ifndef DMX_MAX_SECTION_SIZE
-#define DMX_MAX_SECTION_SIZE 4096
-#endif
-#ifndef DMX_MAX_SECFEED_SIZE
-#define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188)
-#endif
-
-
-/*
- * enum dmx_success: Success codes for the Demux Callback API.
- */
-
-enum dmx_success {
-  DMX_OK = 0, /* Received Ok */
-  DMX_LENGTH_ERROR, /* Incorrect length */
-  DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */
-  DMX_CRC_ERROR, /* Incorrect CRC */
-  DMX_FRAME_ERROR, /* Frame alignment error */
-  DMX_FIFO_ERROR, /* Receiver FIFO overrun */
-  DMX_MISSED_ERROR /* Receiver missed packet */
-} ;
-
-/*--------------------------------------------------------------------------*/
-/* TS packet reception */
-/*--------------------------------------------------------------------------*/
-
-/* TS filter type for set() */
-
-#define TS_PACKET       1   /* send TS packets (188 bytes) to callback (default) */
-#define        TS_PAYLOAD_ONLY 2   /* in case TS_PACKET is set, only send the TS
-                              payload (<=184 bytes per packet) to callback */
-#define TS_DECODER      4   /* send stream to built-in decoder (if present) */
-#define TS_DEMUX        8   /* in case TS_PACKET is set, send the TS to
-                              the demux device, not to the dvr device */
-
-/* PES type for filters which write to built-in decoder */
-/* these should be kept identical to the types in dmx.h */
-
-enum dmx_ts_pes
-{  /* also send packets to decoder (if it exists) */
-       DMX_TS_PES_AUDIO0,
-       DMX_TS_PES_VIDEO0,
-       DMX_TS_PES_TELETEXT0,
-       DMX_TS_PES_SUBTITLE0,
-       DMX_TS_PES_PCR0,
-
-       DMX_TS_PES_AUDIO1,
-       DMX_TS_PES_VIDEO1,
-       DMX_TS_PES_TELETEXT1,
-       DMX_TS_PES_SUBTITLE1,
-       DMX_TS_PES_PCR1,
-
-       DMX_TS_PES_AUDIO2,
-       DMX_TS_PES_VIDEO2,
-       DMX_TS_PES_TELETEXT2,
-       DMX_TS_PES_SUBTITLE2,
-       DMX_TS_PES_PCR2,
-
-       DMX_TS_PES_AUDIO3,
-       DMX_TS_PES_VIDEO3,
-       DMX_TS_PES_TELETEXT3,
-       DMX_TS_PES_SUBTITLE3,
-       DMX_TS_PES_PCR3,
-
-       DMX_TS_PES_OTHER
-};
-
-#define DMX_TS_PES_AUDIO    DMX_TS_PES_AUDIO0
-#define DMX_TS_PES_VIDEO    DMX_TS_PES_VIDEO0
-#define DMX_TS_PES_TELETEXT DMX_TS_PES_TELETEXT0
-#define DMX_TS_PES_SUBTITLE DMX_TS_PES_SUBTITLE0
-#define DMX_TS_PES_PCR      DMX_TS_PES_PCR0
-
-
-struct dmx_ts_feed {
-       int is_filtering; /* Set to non-zero when filtering in progress */
-       struct dmx_demux *parent; /* Back-pointer */
-       void *priv; /* Pointer to private data of the API client */
-       int (*set) (struct dmx_ts_feed *feed,
-                   u16 pid,
-                   int type,
-                   enum dmx_ts_pes pes_type,
-                   size_t circular_buffer_size,
-                   struct timespec timeout);
-       int (*start_filtering) (struct dmx_ts_feed* feed);
-       int (*stop_filtering) (struct dmx_ts_feed* feed);
-};
-
-/*--------------------------------------------------------------------------*/
-/* Section reception */
-/*--------------------------------------------------------------------------*/
-
-struct dmx_section_filter {
-       u8 filter_value [DMX_MAX_FILTER_SIZE];
-       u8 filter_mask [DMX_MAX_FILTER_SIZE];
-       u8 filter_mode [DMX_MAX_FILTER_SIZE];
-       struct dmx_section_feed* parent; /* Back-pointer */
-       void* priv; /* Pointer to private data of the API client */
-};
-
-struct dmx_section_feed {
-       int is_filtering; /* Set to non-zero when filtering in progress */
-       struct dmx_demux* parent; /* Back-pointer */
-       void* priv; /* Pointer to private data of the API client */
-
-       int check_crc;
-       u32 crc_val;
-
-       u8 *secbuf;
-       u8 secbuf_base[DMX_MAX_SECFEED_SIZE];
-       u16 secbufp, seclen, tsfeedp;
-
-       int (*set) (struct dmx_section_feed* feed,
-                   u16 pid,
-                   size_t circular_buffer_size,
-                   int check_crc);
-       int (*allocate_filter) (struct dmx_section_feed* feed,
-                               struct dmx_section_filter** filter);
-       int (*release_filter) (struct dmx_section_feed* feed,
-                              struct dmx_section_filter* filter);
-       int (*start_filtering) (struct dmx_section_feed* feed);
-       int (*stop_filtering) (struct dmx_section_feed* feed);
-};
-
-/*--------------------------------------------------------------------------*/
-/* Callback functions */
-/*--------------------------------------------------------------------------*/
-
-typedef int (*dmx_ts_cb) ( const u8 * buffer1,
-                          size_t buffer1_length,
-                          const u8 * buffer2,
-                          size_t buffer2_length,
-                          struct dmx_ts_feed* source,
-                          enum dmx_success success);
-
-typedef int (*dmx_section_cb) (        const u8 * buffer1,
-                               size_t buffer1_len,
-                               const u8 * buffer2,
-                               size_t buffer2_len,
-                               struct dmx_section_filter * source,
-                               enum dmx_success success);
-
-/*--------------------------------------------------------------------------*/
-/* DVB Front-End */
-/*--------------------------------------------------------------------------*/
-
-enum dmx_frontend_source {
-       DMX_MEMORY_FE,
-       DMX_FRONTEND_0,
-       DMX_FRONTEND_1,
-       DMX_FRONTEND_2,
-       DMX_FRONTEND_3,
-       DMX_STREAM_0,    /* external stream input, e.g. LVDS */
-       DMX_STREAM_1,
-       DMX_STREAM_2,
-       DMX_STREAM_3
-};
-
-struct dmx_frontend {
-       struct list_head connectivity_list; /* List of front-ends that can
-                                              be connected to a particular
-                                              demux */
-       enum dmx_frontend_source source;
-};
-
-/*--------------------------------------------------------------------------*/
-/* MPEG-2 TS Demux */
-/*--------------------------------------------------------------------------*/
-
-/*
- * Flags OR'ed in the capabilities field of struct dmx_demux.
- */
-
-#define DMX_TS_FILTERING                        1
-#define DMX_PES_FILTERING                       2
-#define DMX_SECTION_FILTERING                   4
-#define DMX_MEMORY_BASED_FILTERING              8    /* write() available */
-#define DMX_CRC_CHECKING                        16
-#define DMX_TS_DESCRAMBLING                     32
-
-/*
- * Demux resource type identifier.
-*/
-
-/*
- * DMX_FE_ENTRY(): Casts elements in the list of registered
- * front-ends from the generic type struct list_head
- * to the type * struct dmx_frontend
- *.
-*/
-
-#define DMX_FE_ENTRY(list) list_entry(list, struct dmx_frontend, connectivity_list)
-
-struct dmx_demux {
-       u32 capabilities;            /* Bitfield of capability flags */
-       struct dmx_frontend* frontend;    /* Front-end connected to the demux */
-       void* priv;                  /* Pointer to private data of the API client */
-       int (*open) (struct dmx_demux* demux);
-       int (*close) (struct dmx_demux* demux);
-       int (*write) (struct dmx_demux* demux, const char __user *buf, size_t count);
-       int (*allocate_ts_feed) (struct dmx_demux* demux,
-                                struct dmx_ts_feed** feed,
-                                dmx_ts_cb callback);
-       int (*release_ts_feed) (struct dmx_demux* demux,
-                               struct dmx_ts_feed* feed);
-       int (*allocate_section_feed) (struct dmx_demux* demux,
-                                     struct dmx_section_feed** feed,
-                                     dmx_section_cb callback);
-       int (*release_section_feed) (struct dmx_demux* demux,
-                                    struct dmx_section_feed* feed);
-       int (*add_frontend) (struct dmx_demux* demux,
-                            struct dmx_frontend* frontend);
-       int (*remove_frontend) (struct dmx_demux* demux,
-                               struct dmx_frontend* frontend);
-       struct list_head* (*get_frontends) (struct dmx_demux* demux);
-       int (*connect_frontend) (struct dmx_demux* demux,
-                                struct dmx_frontend* frontend);
-       int (*disconnect_frontend) (struct dmx_demux* demux);
-
-       int (*get_pes_pids) (struct dmx_demux* demux, u16 *pids);
-
-       int (*get_caps) (struct dmx_demux* demux, struct dmx_caps *caps);
-
-       int (*set_source) (struct dmx_demux* demux, const dmx_source_t *src);
-
-       int (*get_stc) (struct dmx_demux* demux, unsigned int num,
-                       u64 *stc, unsigned int *base);
-};
-
-#endif /* #ifndef __DEMUX_H */
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
deleted file mode 100644 (file)
index 889c9c1..0000000
+++ /dev/null
@@ -1,1275 +0,0 @@
-/*
- * dmxdev.c - DVB demultiplexer device
- *
- * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
- *                   for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU 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 <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/ioctl.h>
-#include <linux/wait.h>
-#include <asm/uaccess.h>
-#include "dmxdev.h"
-
-static int debug;
-
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
-
-#define dprintk        if (debug) printk
-
-static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
-                                  const u8 *src, size_t len)
-{
-       ssize_t free;
-
-       if (!len)
-               return 0;
-       if (!buf->data)
-               return 0;
-
-       free = dvb_ringbuffer_free(buf);
-       if (len > free) {
-               dprintk("dmxdev: buffer overflow\n");
-               return -EOVERFLOW;
-       }
-
-       return dvb_ringbuffer_write(buf, src, len);
-}
-
-static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
-                                     int non_blocking, char __user *buf,
-                                     size_t count, loff_t *ppos)
-{
-       size_t todo;
-       ssize_t avail;
-       ssize_t ret = 0;
-
-       if (!src->data)
-               return 0;
-
-       if (src->error) {
-               ret = src->error;
-               dvb_ringbuffer_flush(src);
-               return ret;
-       }
-
-       for (todo = count; todo > 0; todo -= ret) {
-               if (non_blocking && dvb_ringbuffer_empty(src)) {
-                       ret = -EWOULDBLOCK;
-                       break;
-               }
-
-               ret = wait_event_interruptible(src->queue,
-                                              !dvb_ringbuffer_empty(src) ||
-                                              (src->error != 0));
-               if (ret < 0)
-                       break;
-
-               if (src->error) {
-                       ret = src->error;
-                       dvb_ringbuffer_flush(src);
-                       break;
-               }
-
-               avail = dvb_ringbuffer_avail(src);
-               if (avail > todo)
-                       avail = todo;
-
-               ret = dvb_ringbuffer_read_user(src, buf, avail);
-               if (ret < 0)
-                       break;
-
-               buf += ret;
-       }
-
-       return (count - todo) ? (count - todo) : ret;
-}
-
-static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type)
-{
-       struct list_head *head, *pos;
-
-       head = demux->get_frontends(demux);
-       if (!head)
-               return NULL;
-       list_for_each(pos, head)
-               if (DMX_FE_ENTRY(pos)->source == type)
-                       return DMX_FE_ENTRY(pos);
-
-       return NULL;
-}
-
-static int dvb_dvr_open(struct inode *inode, struct file *file)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dmxdev *dmxdev = dvbdev->priv;
-       struct dmx_frontend *front;
-
-       dprintk("function : %s\n", __func__);
-
-       if (mutex_lock_interruptible(&dmxdev->mutex))
-               return -ERESTARTSYS;
-
-       if (dmxdev->exit) {
-               mutex_unlock(&dmxdev->mutex);
-               return -ENODEV;
-       }
-
-       if ((file->f_flags & O_ACCMODE) == O_RDWR) {
-               if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
-                       mutex_unlock(&dmxdev->mutex);
-                       return -EOPNOTSUPP;
-               }
-       }
-
-       if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
-               void *mem;
-               if (!dvbdev->readers) {
-                       mutex_unlock(&dmxdev->mutex);
-                       return -EBUSY;
-               }
-               mem = vmalloc(DVR_BUFFER_SIZE);
-               if (!mem) {
-                       mutex_unlock(&dmxdev->mutex);
-                       return -ENOMEM;
-               }
-               dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
-               dvbdev->readers--;
-       }
-
-       if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
-               dmxdev->dvr_orig_fe = dmxdev->demux->frontend;
-
-               if (!dmxdev->demux->write) {
-                       mutex_unlock(&dmxdev->mutex);
-                       return -EOPNOTSUPP;
-               }
-
-               front = get_fe(dmxdev->demux, DMX_MEMORY_FE);
-
-               if (!front) {
-                       mutex_unlock(&dmxdev->mutex);
-                       return -EINVAL;
-               }
-               dmxdev->demux->disconnect_frontend(dmxdev->demux);
-               dmxdev->demux->connect_frontend(dmxdev->demux, front);
-       }
-       dvbdev->users++;
-       mutex_unlock(&dmxdev->mutex);
-       return 0;
-}
-
-static int dvb_dvr_release(struct inode *inode, struct file *file)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dmxdev *dmxdev = dvbdev->priv;
-
-       mutex_lock(&dmxdev->mutex);
-
-       if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
-               dmxdev->demux->disconnect_frontend(dmxdev->demux);
-               dmxdev->demux->connect_frontend(dmxdev->demux,
-                                               dmxdev->dvr_orig_fe);
-       }
-       if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
-               dvbdev->readers++;
-               if (dmxdev->dvr_buffer.data) {
-                       void *mem = dmxdev->dvr_buffer.data;
-                       mb();
-                       spin_lock_irq(&dmxdev->lock);
-                       dmxdev->dvr_buffer.data = NULL;
-                       spin_unlock_irq(&dmxdev->lock);
-                       vfree(mem);
-               }
-       }
-       /* TODO */
-       dvbdev->users--;
-       if (dvbdev->users == 1 && dmxdev->exit == 1) {
-               fops_put(file->f_op);
-               file->f_op = NULL;
-               mutex_unlock(&dmxdev->mutex);
-               wake_up(&dvbdev->wait_queue);
-       } else
-               mutex_unlock(&dmxdev->mutex);
-
-       return 0;
-}
-
-static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
-                            size_t count, loff_t *ppos)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dmxdev *dmxdev = dvbdev->priv;
-       int ret;
-
-       if (!dmxdev->demux->write)
-               return -EOPNOTSUPP;
-       if ((file->f_flags & O_ACCMODE) != O_WRONLY)
-               return -EINVAL;
-       if (mutex_lock_interruptible(&dmxdev->mutex))
-               return -ERESTARTSYS;
-
-       if (dmxdev->exit) {
-               mutex_unlock(&dmxdev->mutex);
-               return -ENODEV;
-       }
-       ret = dmxdev->demux->write(dmxdev->demux, buf, count);
-       mutex_unlock(&dmxdev->mutex);
-       return ret;
-}
-
-static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
-                           loff_t *ppos)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dmxdev *dmxdev = dvbdev->priv;
-
-       if (dmxdev->exit)
-               return -ENODEV;
-
-       return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
-                                     file->f_flags & O_NONBLOCK,
-                                     buf, count, ppos);
-}
-
-static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev,
-                                     unsigned long size)
-{
-       struct dvb_ringbuffer *buf = &dmxdev->dvr_buffer;
-       void *newmem;
-       void *oldmem;
-
-       dprintk("function : %s\n", __func__);
-
-       if (buf->size == size)
-               return 0;
-       if (!size)
-               return -EINVAL;
-
-       newmem = vmalloc(size);
-       if (!newmem)
-               return -ENOMEM;
-
-       oldmem = buf->data;
-
-       spin_lock_irq(&dmxdev->lock);
-       buf->data = newmem;
-       buf->size = size;
-
-       /* reset and not flush in case the buffer shrinks */
-       dvb_ringbuffer_reset(buf);
-       spin_unlock_irq(&dmxdev->lock);
-
-       vfree(oldmem);
-
-       return 0;
-}
-
-static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter
-                                              *dmxdevfilter, int state)
-{
-       spin_lock_irq(&dmxdevfilter->dev->lock);
-       dmxdevfilter->state = state;
-       spin_unlock_irq(&dmxdevfilter->dev->lock);
-}
-
-static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter,
-                                     unsigned long size)
-{
-       struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
-       void *newmem;
-       void *oldmem;
-
-       if (buf->size == size)
-               return 0;
-       if (!size)
-               return -EINVAL;
-       if (dmxdevfilter->state >= DMXDEV_STATE_GO)
-               return -EBUSY;
-
-       newmem = vmalloc(size);
-       if (!newmem)
-               return -ENOMEM;
-
-       oldmem = buf->data;
-
-       spin_lock_irq(&dmxdevfilter->dev->lock);
-       buf->data = newmem;
-       buf->size = size;
-
-       /* reset and not flush in case the buffer shrinks */
-       dvb_ringbuffer_reset(buf);
-       spin_unlock_irq(&dmxdevfilter->dev->lock);
-
-       vfree(oldmem);
-
-       return 0;
-}
-
-static void dvb_dmxdev_filter_timeout(unsigned long data)
-{
-       struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data;
-
-       dmxdevfilter->buffer.error = -ETIMEDOUT;
-       spin_lock_irq(&dmxdevfilter->dev->lock);
-       dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
-       spin_unlock_irq(&dmxdevfilter->dev->lock);
-       wake_up(&dmxdevfilter->buffer.queue);
-}
-
-static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
-{
-       struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec;
-
-       del_timer(&dmxdevfilter->timer);
-       if (para->timeout) {
-               dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout;
-               dmxdevfilter->timer.data = (unsigned long)dmxdevfilter;
-               dmxdevfilter->timer.expires =
-                   jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000;
-               add_timer(&dmxdevfilter->timer);
-       }
-}
-
-static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
-                                      const u8 *buffer2, size_t buffer2_len,
-                                      struct dmx_section_filter *filter,
-                                      enum dmx_success success)
-{
-       struct dmxdev_filter *dmxdevfilter = filter->priv;
-       int ret;
-
-       if (dmxdevfilter->buffer.error) {
-               wake_up(&dmxdevfilter->buffer.queue);
-               return 0;
-       }
-       spin_lock(&dmxdevfilter->dev->lock);
-       if (dmxdevfilter->state != DMXDEV_STATE_GO) {
-               spin_unlock(&dmxdevfilter->dev->lock);
-               return 0;
-       }
-       del_timer(&dmxdevfilter->timer);
-       dprintk("dmxdev: section callback %*ph\n", 6, buffer1);
-       ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,
-                                     buffer1_len);
-       if (ret == buffer1_len) {
-               ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2,
-                                             buffer2_len);
-       }
-       if (ret < 0) {
-               dvb_ringbuffer_flush(&dmxdevfilter->buffer);
-               dmxdevfilter->buffer.error = ret;
-       }
-       if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
-               dmxdevfilter->state = DMXDEV_STATE_DONE;
-       spin_unlock(&dmxdevfilter->dev->lock);
-       wake_up(&dmxdevfilter->buffer.queue);
-       return 0;
-}
-
-static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
-                                 const u8 *buffer2, size_t buffer2_len,
-                                 struct dmx_ts_feed *feed,
-                                 enum dmx_success success)
-{
-       struct dmxdev_filter *dmxdevfilter = feed->priv;
-       struct dvb_ringbuffer *buffer;
-       int ret;
-
-       spin_lock(&dmxdevfilter->dev->lock);
-       if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
-               spin_unlock(&dmxdevfilter->dev->lock);
-               return 0;
-       }
-
-       if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
-           || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
-               buffer = &dmxdevfilter->buffer;
-       else
-               buffer = &dmxdevfilter->dev->dvr_buffer;
-       if (buffer->error) {
-               spin_unlock(&dmxdevfilter->dev->lock);
-               wake_up(&buffer->queue);
-               return 0;
-       }
-       ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
-       if (ret == buffer1_len)
-               ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
-       if (ret < 0) {
-               dvb_ringbuffer_flush(buffer);
-               buffer->error = ret;
-       }
-       spin_unlock(&dmxdevfilter->dev->lock);
-       wake_up(&buffer->queue);
-       return 0;
-}
-
-/* stop feed but only mark the specified filter as stopped (state set) */
-static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
-{
-       struct dmxdev_feed *feed;
-
-       dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
-
-       switch (dmxdevfilter->type) {
-       case DMXDEV_TYPE_SEC:
-               del_timer(&dmxdevfilter->timer);
-               dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec);
-               break;
-       case DMXDEV_TYPE_PES:
-               list_for_each_entry(feed, &dmxdevfilter->feed.ts, next)
-                       feed->ts->stop_filtering(feed->ts);
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-
-/* start feed associated with the specified filter */
-static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter)
-{
-       struct dmxdev_feed *feed;
-       int ret;
-
-       dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
-
-       switch (filter->type) {
-       case DMXDEV_TYPE_SEC:
-               return filter->feed.sec->start_filtering(filter->feed.sec);
-       case DMXDEV_TYPE_PES:
-               list_for_each_entry(feed, &filter->feed.ts, next) {
-                       ret = feed->ts->start_filtering(feed->ts);
-                       if (ret < 0) {
-                               dvb_dmxdev_feed_stop(filter);
-                               return ret;
-                       }
-               }
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/* restart section feed if it has filters left associated with it,
-   otherwise release the feed */
-static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter)
-{
-       int i;
-       struct dmxdev *dmxdev = filter->dev;
-       u16 pid = filter->params.sec.pid;
-
-       for (i = 0; i < dmxdev->filternum; i++)
-               if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
-                   dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
-                   dmxdev->filter[i].params.sec.pid == pid) {
-                       dvb_dmxdev_feed_start(&dmxdev->filter[i]);
-                       return 0;
-               }
-
-       filter->dev->demux->release_section_feed(dmxdev->demux,
-                                                filter->feed.sec);
-
-       return 0;
-}
-
-static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
-{
-       struct dmxdev_feed *feed;
-       struct dmx_demux *demux;
-
-       if (dmxdevfilter->state < DMXDEV_STATE_GO)
-               return 0;
-
-       switch (dmxdevfilter->type) {
-       case DMXDEV_TYPE_SEC:
-               if (!dmxdevfilter->feed.sec)
-                       break;
-               dvb_dmxdev_feed_stop(dmxdevfilter);
-               if (dmxdevfilter->filter.sec)
-                       dmxdevfilter->feed.sec->
-                           release_filter(dmxdevfilter->feed.sec,
-                                          dmxdevfilter->filter.sec);
-               dvb_dmxdev_feed_restart(dmxdevfilter);
-               dmxdevfilter->feed.sec = NULL;
-               break;
-       case DMXDEV_TYPE_PES:
-               dvb_dmxdev_feed_stop(dmxdevfilter);
-               demux = dmxdevfilter->dev->demux;
-               list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) {
-                       demux->release_ts_feed(demux, feed->ts);
-                       feed->ts = NULL;
-               }
-               break;
-       default:
-               if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED)
-                       return 0;
-               return -EINVAL;
-       }
-
-       dvb_ringbuffer_flush(&dmxdevfilter->buffer);
-       return 0;
-}
-
-static void dvb_dmxdev_delete_pids(struct dmxdev_filter *dmxdevfilter)
-{
-       struct dmxdev_feed *feed, *tmp;
-
-       /* delete all PIDs */
-       list_for_each_entry_safe(feed, tmp, &dmxdevfilter->feed.ts, next) {
-               list_del(&feed->next);
-               kfree(feed);
-       }
-
-       BUG_ON(!list_empty(&dmxdevfilter->feed.ts));
-}
-
-static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter)
-{
-       if (dmxdevfilter->state < DMXDEV_STATE_SET)
-               return 0;
-
-       if (dmxdevfilter->type == DMXDEV_TYPE_PES)
-               dvb_dmxdev_delete_pids(dmxdevfilter);
-
-       dmxdevfilter->type = DMXDEV_TYPE_NONE;
-       dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
-       return 0;
-}
-
-static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
-                                struct dmxdev_filter *filter,
-                                struct dmxdev_feed *feed)
-{
-       struct timespec timeout = { 0 };
-       struct dmx_pes_filter_params *para = &filter->params.pes;
-       dmx_output_t otype;
-       int ret;
-       int ts_type;
-       dmx_pes_type_t ts_pes;
-       struct dmx_ts_feed *tsfeed;
-
-       feed->ts = NULL;
-       otype = para->output;
-
-       ts_pes = para->pes_type;
-
-       if (ts_pes < DMX_PES_OTHER)
-               ts_type = TS_DECODER;
-       else
-               ts_type = 0;
-
-       if (otype == DMX_OUT_TS_TAP)
-               ts_type |= TS_PACKET;
-       else if (otype == DMX_OUT_TSDEMUX_TAP)
-               ts_type |= TS_PACKET | TS_DEMUX;
-       else if (otype == DMX_OUT_TAP)
-               ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY;
-
-       ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, &feed->ts,
-                                             dvb_dmxdev_ts_callback);
-       if (ret < 0)
-               return ret;
-
-       tsfeed = feed->ts;
-       tsfeed->priv = filter;
-
-       ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout);
-       if (ret < 0) {
-               dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
-               return ret;
-       }
-
-       ret = tsfeed->start_filtering(tsfeed);
-       if (ret < 0) {
-               dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed);
-               return ret;
-       }
-
-       return 0;
-}
-
-static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
-{
-       struct dmxdev *dmxdev = filter->dev;
-       struct dmxdev_feed *feed;
-       void *mem;
-       int ret, i;
-
-       if (filter->state < DMXDEV_STATE_SET)
-               return -EINVAL;
-
-       if (filter->state >= DMXDEV_STATE_GO)
-               dvb_dmxdev_filter_stop(filter);
-
-       if (!filter->buffer.data) {
-               mem = vmalloc(filter->buffer.size);
-               if (!mem)
-                       return -ENOMEM;
-               spin_lock_irq(&filter->dev->lock);
-               filter->buffer.data = mem;
-               spin_unlock_irq(&filter->dev->lock);
-       }
-
-       dvb_ringbuffer_flush(&filter->buffer);
-
-       switch (filter->type) {
-       case DMXDEV_TYPE_SEC:
-       {
-               struct dmx_sct_filter_params *para = &filter->params.sec;
-               struct dmx_section_filter **secfilter = &filter->filter.sec;
-               struct dmx_section_feed **secfeed = &filter->feed.sec;
-
-               *secfilter = NULL;
-               *secfeed = NULL;
-
-
-               /* find active filter/feed with same PID */
-               for (i = 0; i < dmxdev->filternum; i++) {
-                       if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
-                           dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
-                           dmxdev->filter[i].params.sec.pid == para->pid) {
-                               *secfeed = dmxdev->filter[i].feed.sec;
-                               break;
-                       }
-               }
-
-               /* if no feed found, try to allocate new one */
-               if (!*secfeed) {
-                       ret = dmxdev->demux->allocate_section_feed(dmxdev->demux,
-                                                                  secfeed,
-                                                                  dvb_dmxdev_section_callback);
-                       if (ret < 0) {
-                               printk("DVB (%s): could not alloc feed\n",
-                                      __func__);
-                               return ret;
-                       }
-
-                       ret = (*secfeed)->set(*secfeed, para->pid, 32768,
-                                             (para->flags & DMX_CHECK_CRC) ? 1 : 0);
-                       if (ret < 0) {
-                               printk("DVB (%s): could not set feed\n",
-                                      __func__);
-                               dvb_dmxdev_feed_restart(filter);
-                               return ret;
-                       }
-               } else {
-                       dvb_dmxdev_feed_stop(filter);
-               }
-
-               ret = (*secfeed)->allocate_filter(*secfeed, secfilter);
-               if (ret < 0) {
-                       dvb_dmxdev_feed_restart(filter);
-                       filter->feed.sec->start_filtering(*secfeed);
-                       dprintk("could not get filter\n");
-                       return ret;
-               }
-
-               (*secfilter)->priv = filter;
-
-               memcpy(&((*secfilter)->filter_value[3]),
-                      &(para->filter.filter[1]), DMX_FILTER_SIZE - 1);
-               memcpy(&(*secfilter)->filter_mask[3],
-                      &para->filter.mask[1], DMX_FILTER_SIZE - 1);
-               memcpy(&(*secfilter)->filter_mode[3],
-                      &para->filter.mode[1], DMX_FILTER_SIZE - 1);
-
-               (*secfilter)->filter_value[0] = para->filter.filter[0];
-               (*secfilter)->filter_mask[0] = para->filter.mask[0];
-               (*secfilter)->filter_mode[0] = para->filter.mode[0];
-               (*secfilter)->filter_mask[1] = 0;
-               (*secfilter)->filter_mask[2] = 0;
-
-               filter->todo = 0;
-
-               ret = filter->feed.sec->start_filtering(filter->feed.sec);
-               if (ret < 0)
-                       return ret;
-
-               dvb_dmxdev_filter_timer(filter);
-               break;
-       }
-       case DMXDEV_TYPE_PES:
-               list_for_each_entry(feed, &filter->feed.ts, next) {
-                       ret = dvb_dmxdev_start_feed(dmxdev, filter, feed);
-                       if (ret < 0) {
-                               dvb_dmxdev_filter_stop(filter);
-                               return ret;
-                       }
-               }
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
-       return 0;
-}
-
-static int dvb_demux_open(struct inode *inode, struct file *file)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dmxdev *dmxdev = dvbdev->priv;
-       int i;
-       struct dmxdev_filter *dmxdevfilter;
-
-       if (!dmxdev->filter)
-               return -EINVAL;
-
-       if (mutex_lock_interruptible(&dmxdev->mutex))
-               return -ERESTARTSYS;
-
-       for (i = 0; i < dmxdev->filternum; i++)
-               if (dmxdev->filter[i].state == DMXDEV_STATE_FREE)
-                       break;
-
-       if (i == dmxdev->filternum) {
-               mutex_unlock(&dmxdev->mutex);
-               return -EMFILE;
-       }
-
-       dmxdevfilter = &dmxdev->filter[i];
-       mutex_init(&dmxdevfilter->mutex);
-       file->private_data = dmxdevfilter;
-
-       dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
-       dmxdevfilter->type = DMXDEV_TYPE_NONE;
-       dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
-       init_timer(&dmxdevfilter->timer);
-
-       dvbdev->users++;
-
-       mutex_unlock(&dmxdev->mutex);
-       return 0;
-}
-
-static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
-                                 struct dmxdev_filter *dmxdevfilter)
-{
-       mutex_lock(&dmxdev->mutex);
-       mutex_lock(&dmxdevfilter->mutex);
-
-       dvb_dmxdev_filter_stop(dmxdevfilter);
-       dvb_dmxdev_filter_reset(dmxdevfilter);
-
-       if (dmxdevfilter->buffer.data) {
-               void *mem = dmxdevfilter->buffer.data;
-
-               spin_lock_irq(&dmxdev->lock);
-               dmxdevfilter->buffer.data = NULL;
-               spin_unlock_irq(&dmxdev->lock);
-               vfree(mem);
-       }
-
-       dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE);
-       wake_up(&dmxdevfilter->buffer.queue);
-       mutex_unlock(&dmxdevfilter->mutex);
-       mutex_unlock(&dmxdev->mutex);
-       return 0;
-}
-
-static inline void invert_mode(dmx_filter_t *filter)
-{
-       int i;
-
-       for (i = 0; i < DMX_FILTER_SIZE; i++)
-               filter->mode[i] ^= 0xff;
-}
-
-static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev,
-                             struct dmxdev_filter *filter, u16 pid)
-{
-       struct dmxdev_feed *feed;
-
-       if ((filter->type != DMXDEV_TYPE_PES) ||
-           (filter->state < DMXDEV_STATE_SET))
-               return -EINVAL;
-
-       /* only TS packet filters may have multiple PIDs */
-       if ((filter->params.pes.output != DMX_OUT_TSDEMUX_TAP) &&
-           (!list_empty(&filter->feed.ts)))
-               return -EINVAL;
-
-       feed = kzalloc(sizeof(struct dmxdev_feed), GFP_KERNEL);
-       if (feed == NULL)
-               return -ENOMEM;
-
-       feed->pid = pid;
-       list_add(&feed->next, &filter->feed.ts);
-
-       if (filter->state >= DMXDEV_STATE_GO)
-               return dvb_dmxdev_start_feed(dmxdev, filter, feed);
-
-       return 0;
-}
-
-static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev,
-                                 struct dmxdev_filter *filter, u16 pid)
-{
-       struct dmxdev_feed *feed, *tmp;
-
-       if ((filter->type != DMXDEV_TYPE_PES) ||
-           (filter->state < DMXDEV_STATE_SET))
-               return -EINVAL;
-
-       list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) {
-               if ((feed->pid == pid) && (feed->ts != NULL)) {
-                       feed->ts->stop_filtering(feed->ts);
-                       filter->dev->demux->release_ts_feed(filter->dev->demux,
-                                                           feed->ts);
-                       list_del(&feed->next);
-                       kfree(feed);
-               }
-       }
-
-       return 0;
-}
-
-static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
-                                struct dmxdev_filter *dmxdevfilter,
-                                struct dmx_sct_filter_params *params)
-{
-       dprintk("function : %s\n", __func__);
-
-       dvb_dmxdev_filter_stop(dmxdevfilter);
-
-       dmxdevfilter->type = DMXDEV_TYPE_SEC;
-       memcpy(&dmxdevfilter->params.sec,
-              params, sizeof(struct dmx_sct_filter_params));
-       invert_mode(&dmxdevfilter->params.sec.filter);
-       dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
-
-       if (params->flags & DMX_IMMEDIATE_START)
-               return dvb_dmxdev_filter_start(dmxdevfilter);
-
-       return 0;
-}
-
-static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
-                                    struct dmxdev_filter *dmxdevfilter,
-                                    struct dmx_pes_filter_params *params)
-{
-       int ret;
-
-       dvb_dmxdev_filter_stop(dmxdevfilter);
-       dvb_dmxdev_filter_reset(dmxdevfilter);
-
-       if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0)
-               return -EINVAL;
-
-       dmxdevfilter->type = DMXDEV_TYPE_PES;
-       memcpy(&dmxdevfilter->params, params,
-              sizeof(struct dmx_pes_filter_params));
-       INIT_LIST_HEAD(&dmxdevfilter->feed.ts);
-
-       dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);
-
-       ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter,
-                                dmxdevfilter->params.pes.pid);
-       if (ret < 0)
-               return ret;
-
-       if (params->flags & DMX_IMMEDIATE_START)
-               return dvb_dmxdev_filter_start(dmxdevfilter);
-
-       return 0;
-}
-
-static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil,
-                                  struct file *file, char __user *buf,
-                                  size_t count, loff_t *ppos)
-{
-       int result, hcount;
-       int done = 0;
-
-       if (dfil->todo <= 0) {
-               hcount = 3 + dfil->todo;
-               if (hcount > count)
-                       hcount = count;
-               result = dvb_dmxdev_buffer_read(&dfil->buffer,
-                                               file->f_flags & O_NONBLOCK,
-                                               buf, hcount, ppos);
-               if (result < 0) {
-                       dfil->todo = 0;
-                       return result;
-               }
-               if (copy_from_user(dfil->secheader - dfil->todo, buf, result))
-                       return -EFAULT;
-               buf += result;
-               done = result;
-               count -= result;
-               dfil->todo -= result;
-               if (dfil->todo > -3)
-                       return done;
-               dfil->todo = ((dfil->secheader[1] << 8) | dfil->secheader[2]) & 0xfff;
-               if (!count)
-                       return done;
-       }
-       if (count > dfil->todo)
-               count = dfil->todo;
-       result = dvb_dmxdev_buffer_read(&dfil->buffer,
-                                       file->f_flags & O_NONBLOCK,
-                                       buf, count, ppos);
-       if (result < 0)
-               return result;
-       dfil->todo -= result;
-       return (result + done);
-}
-
-static ssize_t
-dvb_demux_read(struct file *file, char __user *buf, size_t count,
-              loff_t *ppos)
-{
-       struct dmxdev_filter *dmxdevfilter = file->private_data;
-       int ret;
-
-       if (mutex_lock_interruptible(&dmxdevfilter->mutex))
-               return -ERESTARTSYS;
-
-       if (dmxdevfilter->type == DMXDEV_TYPE_SEC)
-               ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
-       else
-               ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
-                                            file->f_flags & O_NONBLOCK,
-                                            buf, count, ppos);
-
-       mutex_unlock(&dmxdevfilter->mutex);
-       return ret;
-}
-
-static int dvb_demux_do_ioctl(struct file *file,
-                             unsigned int cmd, void *parg)
-{
-       struct dmxdev_filter *dmxdevfilter = file->private_data;
-       struct dmxdev *dmxdev = dmxdevfilter->dev;
-       unsigned long arg = (unsigned long)parg;
-       int ret = 0;
-
-       if (mutex_lock_interruptible(&dmxdev->mutex))
-               return -ERESTARTSYS;
-
-       switch (cmd) {
-       case DMX_START:
-               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
-                       mutex_unlock(&dmxdev->mutex);
-                       return -ERESTARTSYS;
-               }
-               if (dmxdevfilter->state < DMXDEV_STATE_SET)
-                       ret = -EINVAL;
-               else
-                       ret = dvb_dmxdev_filter_start(dmxdevfilter);
-               mutex_unlock(&dmxdevfilter->mutex);
-               break;
-
-       case DMX_STOP:
-               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
-                       mutex_unlock(&dmxdev->mutex);
-                       return -ERESTARTSYS;
-               }
-               ret = dvb_dmxdev_filter_stop(dmxdevfilter);
-               mutex_unlock(&dmxdevfilter->mutex);
-               break;
-
-       case DMX_SET_FILTER:
-               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
-                       mutex_unlock(&dmxdev->mutex);
-                       return -ERESTARTSYS;
-               }
-               ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg);
-               mutex_unlock(&dmxdevfilter->mutex);
-               break;
-
-       case DMX_SET_PES_FILTER:
-               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
-                       mutex_unlock(&dmxdev->mutex);
-                       return -ERESTARTSYS;
-               }
-               ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg);
-               mutex_unlock(&dmxdevfilter->mutex);
-               break;
-
-       case DMX_SET_BUFFER_SIZE:
-               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
-                       mutex_unlock(&dmxdev->mutex);
-                       return -ERESTARTSYS;
-               }
-               ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg);
-               mutex_unlock(&dmxdevfilter->mutex);
-               break;
-
-       case DMX_GET_PES_PIDS:
-               if (!dmxdev->demux->get_pes_pids) {
-                       ret = -EINVAL;
-                       break;
-               }
-               dmxdev->demux->get_pes_pids(dmxdev->demux, parg);
-               break;
-
-       case DMX_GET_CAPS:
-               if (!dmxdev->demux->get_caps) {
-                       ret = -EINVAL;
-                       break;
-               }
-               ret = dmxdev->demux->get_caps(dmxdev->demux, parg);
-               break;
-
-       case DMX_SET_SOURCE:
-               if (!dmxdev->demux->set_source) {
-                       ret = -EINVAL;
-                       break;
-               }
-               ret = dmxdev->demux->set_source(dmxdev->demux, parg);
-               break;
-
-       case DMX_GET_STC:
-               if (!dmxdev->demux->get_stc) {
-                       ret = -EINVAL;
-                       break;
-               }
-               ret = dmxdev->demux->get_stc(dmxdev->demux,
-                                            ((struct dmx_stc *)parg)->num,
-                                            &((struct dmx_stc *)parg)->stc,
-                                            &((struct dmx_stc *)parg)->base);
-               break;
-
-       case DMX_ADD_PID:
-               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
-                       ret = -ERESTARTSYS;
-                       break;
-               }
-               ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
-               mutex_unlock(&dmxdevfilter->mutex);
-               break;
-
-       case DMX_REMOVE_PID:
-               if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
-                       ret = -ERESTARTSYS;
-                       break;
-               }
-               ret = dvb_dmxdev_remove_pid(dmxdev, dmxdevfilter, *(u16 *)parg);
-               mutex_unlock(&dmxdevfilter->mutex);
-               break;
-
-       default:
-               ret = -EINVAL;
-               break;
-       }
-       mutex_unlock(&dmxdev->mutex);
-       return ret;
-}
-
-static long dvb_demux_ioctl(struct file *file, unsigned int cmd,
-                           unsigned long arg)
-{
-       return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl);
-}
-
-static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
-{
-       struct dmxdev_filter *dmxdevfilter = file->private_data;
-       unsigned int mask = 0;
-
-       if (!dmxdevfilter)
-               return -EINVAL;
-
-       poll_wait(file, &dmxdevfilter->buffer.queue, wait);
-
-       if (dmxdevfilter->state != DMXDEV_STATE_GO &&
-           dmxdevfilter->state != DMXDEV_STATE_DONE &&
-           dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT)
-               return 0;
-
-       if (dmxdevfilter->buffer.error)
-               mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
-
-       if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
-               mask |= (POLLIN | POLLRDNORM | POLLPRI);
-
-       return mask;
-}
-
-static int dvb_demux_release(struct inode *inode, struct file *file)
-{
-       struct dmxdev_filter *dmxdevfilter = file->private_data;
-       struct dmxdev *dmxdev = dmxdevfilter->dev;
-
-       int ret;
-
-       ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
-
-       mutex_lock(&dmxdev->mutex);
-       dmxdev->dvbdev->users--;
-       if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) {
-               fops_put(file->f_op);
-               file->f_op = NULL;
-               mutex_unlock(&dmxdev->mutex);
-               wake_up(&dmxdev->dvbdev->wait_queue);
-       } else
-               mutex_unlock(&dmxdev->mutex);
-
-       return ret;
-}
-
-static const struct file_operations dvb_demux_fops = {
-       .owner = THIS_MODULE,
-       .read = dvb_demux_read,
-       .unlocked_ioctl = dvb_demux_ioctl,
-       .open = dvb_demux_open,
-       .release = dvb_demux_release,
-       .poll = dvb_demux_poll,
-       .llseek = default_llseek,
-};
-
-static struct dvb_device dvbdev_demux = {
-       .priv = NULL,
-       .users = 1,
-       .writers = 1,
-       .fops = &dvb_demux_fops
-};
-
-static int dvb_dvr_do_ioctl(struct file *file,
-                           unsigned int cmd, void *parg)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dmxdev *dmxdev = dvbdev->priv;
-       unsigned long arg = (unsigned long)parg;
-       int ret;
-
-       if (mutex_lock_interruptible(&dmxdev->mutex))
-               return -ERESTARTSYS;
-
-       switch (cmd) {
-       case DMX_SET_BUFFER_SIZE:
-               ret = dvb_dvr_set_buffer_size(dmxdev, arg);
-               break;
-
-       default:
-               ret = -EINVAL;
-               break;
-       }
-       mutex_unlock(&dmxdev->mutex);
-       return ret;
-}
-
-static long dvb_dvr_ioctl(struct file *file,
-                        unsigned int cmd, unsigned long arg)
-{
-       return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl);
-}
-
-static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dmxdev *dmxdev = dvbdev->priv;
-       unsigned int mask = 0;
-
-       dprintk("function : %s\n", __func__);
-
-       poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
-
-       if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
-               if (dmxdev->dvr_buffer.error)
-                       mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
-
-               if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
-                       mask |= (POLLIN | POLLRDNORM | POLLPRI);
-       } else
-               mask |= (POLLOUT | POLLWRNORM | POLLPRI);
-
-       return mask;
-}
-
-static const struct file_operations dvb_dvr_fops = {
-       .owner = THIS_MODULE,
-       .read = dvb_dvr_read,
-       .write = dvb_dvr_write,
-       .unlocked_ioctl = dvb_dvr_ioctl,
-       .open = dvb_dvr_open,
-       .release = dvb_dvr_release,
-       .poll = dvb_dvr_poll,
-       .llseek = default_llseek,
-};
-
-static struct dvb_device dvbdev_dvr = {
-       .priv = NULL,
-       .readers = 1,
-       .users = 1,
-       .fops = &dvb_dvr_fops
-};
-
-int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
-{
-       int i;
-
-       if (dmxdev->demux->open(dmxdev->demux) < 0)
-               return -EUSERS;
-
-       dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter));
-       if (!dmxdev->filter)
-               return -ENOMEM;
-
-       mutex_init(&dmxdev->mutex);
-       spin_lock_init(&dmxdev->lock);
-       for (i = 0; i < dmxdev->filternum; i++) {
-               dmxdev->filter[i].dev = dmxdev;
-               dmxdev->filter[i].buffer.data = NULL;
-               dvb_dmxdev_filter_state_set(&dmxdev->filter[i],
-                                           DMXDEV_STATE_FREE);
-       }
-
-       dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
-                           DVB_DEVICE_DEMUX);
-       dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
-                           dmxdev, DVB_DEVICE_DVR);
-
-       dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
-
-       return 0;
-}
-
-EXPORT_SYMBOL(dvb_dmxdev_init);
-
-void dvb_dmxdev_release(struct dmxdev *dmxdev)
-{
-       dmxdev->exit=1;
-       if (dmxdev->dvbdev->users > 1) {
-               wait_event(dmxdev->dvbdev->wait_queue,
-                               dmxdev->dvbdev->users==1);
-       }
-       if (dmxdev->dvr_dvbdev->users > 1) {
-               wait_event(dmxdev->dvr_dvbdev->wait_queue,
-                               dmxdev->dvr_dvbdev->users==1);
-       }
-
-       dvb_unregister_device(dmxdev->dvbdev);
-       dvb_unregister_device(dmxdev->dvr_dvbdev);
-
-       vfree(dmxdev->filter);
-       dmxdev->filter = NULL;
-       dmxdev->demux->close(dmxdev->demux);
-}
-
-EXPORT_SYMBOL(dvb_dmxdev_release);
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h
deleted file mode 100644 (file)
index 02ebe28..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * dmxdev.h
- *
- * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
- *                    for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU 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 _DMXDEV_H_
-#define _DMXDEV_H_
-
-#include <linux/types.h>
-#include <linux/spinlock.h>
-#include <linux/kernel.h>
-#include <linux/timer.h>
-#include <linux/wait.h>
-#include <linux/fs.h>
-#include <linux/string.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-
-#include <linux/dvb/dmx.h>
-
-#include "dvbdev.h"
-#include "demux.h"
-#include "dvb_ringbuffer.h"
-
-enum dmxdev_type {
-       DMXDEV_TYPE_NONE,
-       DMXDEV_TYPE_SEC,
-       DMXDEV_TYPE_PES,
-};
-
-enum dmxdev_state {
-       DMXDEV_STATE_FREE,
-       DMXDEV_STATE_ALLOCATED,
-       DMXDEV_STATE_SET,
-       DMXDEV_STATE_GO,
-       DMXDEV_STATE_DONE,
-       DMXDEV_STATE_TIMEDOUT
-};
-
-struct dmxdev_feed {
-       u16 pid;
-       struct dmx_ts_feed *ts;
-       struct list_head next;
-};
-
-struct dmxdev_filter {
-       union {
-               struct dmx_section_filter *sec;
-       } filter;
-
-       union {
-               /* list of TS and PES feeds (struct dmxdev_feed) */
-               struct list_head ts;
-               struct dmx_section_feed *sec;
-       } feed;
-
-       union {
-               struct dmx_sct_filter_params sec;
-               struct dmx_pes_filter_params pes;
-       } params;
-
-       enum dmxdev_type type;
-       enum dmxdev_state state;
-       struct dmxdev *dev;
-       struct dvb_ringbuffer buffer;
-
-       struct mutex mutex;
-
-       /* only for sections */
-       struct timer_list timer;
-       int todo;
-       u8 secheader[3];
-};
-
-
-struct dmxdev {
-       struct dvb_device *dvbdev;
-       struct dvb_device *dvr_dvbdev;
-
-       struct dmxdev_filter *filter;
-       struct dmx_demux *demux;
-
-       int filternum;
-       int capabilities;
-
-       unsigned int exit:1;
-#define DMXDEV_CAP_DUPLEX 1
-       struct dmx_frontend *dvr_orig_fe;
-
-       struct dvb_ringbuffer dvr_buffer;
-#define DVR_BUFFER_SIZE (10*188*1024)
-
-       struct mutex mutex;
-       spinlock_t lock;
-};
-
-
-int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *);
-void dvb_dmxdev_release(struct dmxdev *dmxdev);
-
-#endif /* _DMXDEV_H_ */
diff --git a/drivers/media/dvb/dvb-core/dvb-usb-ids.h b/drivers/media/dvb/dvb-core/dvb-usb-ids.h
deleted file mode 100644 (file)
index 26c4481..0000000
+++ /dev/null
@@ -1,361 +0,0 @@
-/* dvb-usb-ids.h is part of the DVB USB library.
- *
- * Copyright (C) 2004-5 Patrick Boettcher (patrick.boettcher@desy.de) see
- * dvb-usb-init.c for copyright information.
- *
- * a header file containing define's for the USB device supported by the
- * various drivers.
- */
-#ifndef _DVB_USB_IDS_H_
-#define _DVB_USB_IDS_H_
-
-/* Vendor IDs */
-#define USB_VID_ADSTECH                                0x06e1
-#define USB_VID_AFATECH                                0x15a4
-#define USB_VID_ALCOR_MICRO                    0x058f
-#define USB_VID_ALINK                          0x05e3
-#define USB_VID_AMT                            0x1c73
-#define USB_VID_ANCHOR                         0x0547
-#define USB_VID_ANSONIC                                0x10b9
-#define USB_VID_ANUBIS_ELECTRONIC              0x10fd
-#define USB_VID_ASUS                           0x0b05
-#define USB_VID_AVERMEDIA                      0x07ca
-#define USB_VID_COMPRO                         0x185b
-#define USB_VID_COMPRO_UNK                     0x145f
-#define USB_VID_CONEXANT                       0x0572
-#define USB_VID_CYPRESS                                0x04b4
-#define USB_VID_DIBCOM                         0x10b8
-#define USB_VID_DPOSH                          0x1498
-#define USB_VID_DVICO                          0x0fe9
-#define USB_VID_E3C                            0x18b4
-#define USB_VID_ELGATO                         0x0fd9
-#define USB_VID_EMPIA                          0xeb1a
-#define USB_VID_GENPIX                         0x09c0
-#define USB_VID_GRANDTEC                       0x5032
-#define USB_VID_GTEK                           0x1f4d
-#define USB_VID_HANFTEK                                0x15f4
-#define USB_VID_HAUPPAUGE                      0x2040
-#define USB_VID_HYPER_PALTEK                   0x1025
-#define USB_VID_INTEL                          0x8086
-#define USB_VID_ITETECH                                0x048d
-#define USB_VID_KWORLD                         0xeb2a
-#define USB_VID_KWORLD_2                       0x1b80
-#define USB_VID_KYE                            0x0458
-#define USB_VID_LEADTEK                                0x0413
-#define USB_VID_LITEON                         0x04ca
-#define USB_VID_MEDION                         0x1660
-#define USB_VID_MIGLIA                         0x18f3
-#define USB_VID_MSI                            0x0db0
-#define USB_VID_MSI_2                          0x1462
-#define USB_VID_OPERA1                         0x695c
-#define USB_VID_PINNACLE                       0x2304
-#define USB_VID_PCTV                           0x2013
-#define USB_VID_PIXELVIEW                      0x1554
-#define USB_VID_REALTEK                                0x0bda
-#define USB_VID_TECHNOTREND                    0x0b48
-#define USB_VID_TERRATEC                       0x0ccd
-#define USB_VID_TELESTAR                       0x10b9
-#define USB_VID_VISIONPLUS                     0x13d3
-#define USB_VID_SONY                           0x1415
-#define USB_VID_TWINHAN                                0x1822
-#define USB_VID_ULTIMA_ELECTRONIC              0x05d8
-#define USB_VID_UNIWILL                                0x1584
-#define USB_VID_WIDEVIEW                       0x14aa
-#define USB_VID_GIGABYTE                       0x1044
-#define USB_VID_YUAN                           0x1164
-#define USB_VID_XTENSIONS                      0x1ae7
-#define USB_VID_HUMAX_COEX                     0x10b9
-#define USB_VID_774                            0x7a69
-#define USB_VID_EVOLUTEPC                      0x1e59
-#define USB_VID_AZUREWAVE                      0x13d3
-#define USB_VID_TECHNISAT                      0x14f7
-
-/* Product IDs */
-#define USB_PID_ADSTECH_USB2_COLD                      0xa333
-#define USB_PID_ADSTECH_USB2_WARM                      0xa334
-#define USB_PID_AFATECH_AF9005                         0x9020
-#define USB_PID_AFATECH_AF9015_9015                    0x9015
-#define USB_PID_AFATECH_AF9015_9016                    0x9016
-#define USB_PID_AFATECH_AF9035_1000                    0x1000
-#define USB_PID_AFATECH_AF9035_1001                    0x1001
-#define USB_PID_AFATECH_AF9035_1002                    0x1002
-#define USB_PID_AFATECH_AF9035_1003                    0x1003
-#define USB_PID_AFATECH_AF9035_9035                    0x9035
-#define USB_PID_TREKSTOR_DVBT                          0x901b
-#define USB_VID_ALINK_DTU                              0xf170
-#define USB_PID_ANSONIC_DVBT_USB                       0x6000
-#define USB_PID_ANYSEE                                 0x861f
-#define USB_PID_AZUREWAVE_AD_TU700                     0x3237
-#define USB_PID_AZUREWAVE_6007                         0x0ccd
-#define USB_PID_AVERMEDIA_DVBT_USB_COLD                        0x0001
-#define USB_PID_AVERMEDIA_DVBT_USB_WARM                        0x0002
-#define USB_PID_AVERMEDIA_DVBT_USB2_COLD               0xa800
-#define USB_PID_AVERMEDIA_DVBT_USB2_WARM               0xa801
-#define USB_PID_COMPRO_DVBU2000_COLD                   0xd000
-#define USB_PID_COMPRO_DVBU2000_WARM                   0xd001
-#define USB_PID_COMPRO_DVBU2000_UNK_COLD               0x010c
-#define USB_PID_COMPRO_DVBU2000_UNK_WARM               0x010d
-#define USB_PID_COMPRO_VIDEOMATE_U500                  0x1e78
-#define USB_PID_COMPRO_VIDEOMATE_U500_PC               0x1e80
-#define USB_PID_CONCEPTRONIC_CTVDIGRCU                 0xe397
-#define USB_PID_CONEXANT_D680_DMB                      0x86d6
-#define USB_PID_CREATIX_CTX1921                                0x1921
-#define USB_PID_DELOCK_USB2_DVBT                       0xb803
-#define USB_PID_DIBCOM_HOOK_DEFAULT                    0x0064
-#define USB_PID_DIBCOM_HOOK_DEFAULT_REENUM             0x0065
-#define USB_PID_DIBCOM_MOD3000_COLD                    0x0bb8
-#define USB_PID_DIBCOM_MOD3000_WARM                    0x0bb9
-#define USB_PID_DIBCOM_MOD3001_COLD                    0x0bc6
-#define USB_PID_DIBCOM_MOD3001_WARM                    0x0bc7
-#define USB_PID_DIBCOM_STK7700P                                0x1e14
-#define USB_PID_DIBCOM_STK7700P_PC                     0x1e78
-#define USB_PID_DIBCOM_STK7700D                                0x1ef0
-#define USB_PID_DIBCOM_STK7700_U7000                   0x7001
-#define USB_PID_DIBCOM_STK7070P                                0x1ebc
-#define USB_PID_DIBCOM_STK7070PD                       0x1ebe
-#define USB_PID_DIBCOM_STK807XP                                0x1f90
-#define USB_PID_DIBCOM_STK807XPVR                      0x1f98
-#define USB_PID_DIBCOM_STK8096GP                        0x1fa0
-#define USB_PID_DIBCOM_NIM8096MD                        0x1fa8
-#define USB_PID_DIBCOM_TFE8096P                                0x1f9C
-#define USB_PID_DIBCOM_ANCHOR_2135_COLD                        0x2131
-#define USB_PID_DIBCOM_STK7770P                                0x1e80
-#define USB_PID_DIBCOM_NIM7090                         0x1bb2
-#define USB_PID_DIBCOM_TFE7090PVR                      0x1bb4
-#define USB_PID_DIBCOM_TFE7090E                                0x1bb7
-#define USB_PID_DIBCOM_TFE7790E                                0x1e6e
-#define USB_PID_DIBCOM_NIM9090M                                0x2383
-#define USB_PID_DIBCOM_NIM9090MD                       0x2384
-#define USB_PID_DPOSH_M9206_COLD                       0x9206
-#define USB_PID_DPOSH_M9206_WARM                       0xa090
-#define USB_PID_E3C_EC168                              0x1689
-#define USB_PID_E3C_EC168_2                            0xfffa
-#define USB_PID_E3C_EC168_3                            0xfffb
-#define USB_PID_E3C_EC168_4                            0x1001
-#define USB_PID_E3C_EC168_5                            0x1002
-#define USB_PID_FREECOM_DVBT                           0x0160
-#define USB_PID_FREECOM_DVBT_2                         0x0161
-#define USB_PID_UNIWILL_STK7700P                       0x6003
-#define USB_PID_GENIUS_TVGO_DVB_T03                    0x4012
-#define USB_PID_GRANDTEC_DVBT_USB_COLD                 0x0fa0
-#define USB_PID_GRANDTEC_DVBT_USB_WARM                 0x0fa1
-#define USB_PID_INTEL_CE9500                           0x9500
-#define USB_PID_ITETECH_IT9135                         0x9135
-#define USB_PID_ITETECH_IT9135_9005                    0x9005
-#define USB_PID_ITETECH_IT9135_9006                    0x9006
-#define USB_PID_KWORLD_399U                            0xe399
-#define USB_PID_KWORLD_399U_2                          0xe400
-#define USB_PID_KWORLD_395U                            0xe396
-#define USB_PID_KWORLD_395U_2                          0xe39b
-#define USB_PID_KWORLD_395U_3                          0xe395
-#define USB_PID_KWORLD_395U_4                          0xe39a
-#define USB_PID_KWORLD_MC810                           0xc810
-#define USB_PID_KWORLD_PC160_2T                                0xc160
-#define USB_PID_KWORLD_PC160_T                         0xc161
-#define USB_PID_KWORLD_UB383_T                         0xe383
-#define USB_PID_KWORLD_UB499_2T_T09                    0xe409
-#define USB_PID_KWORLD_VSTREAM_COLD                    0x17de
-#define USB_PID_KWORLD_VSTREAM_WARM                    0x17df
-#define USB_PID_TERRATEC_CINERGY_T_USB_XE              0x0055
-#define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2         0x0069
-#define USB_PID_TERRATEC_CINERGY_T_STICK               0x0093
-#define USB_PID_TERRATEC_CINERGY_T_STICK_RC            0x0097
-#define USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC       0x0099
-#define USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1    0x00a9
-#define USB_PID_TWINHAN_VP7041_COLD                    0x3201
-#define USB_PID_TWINHAN_VP7041_WARM                    0x3202
-#define USB_PID_TWINHAN_VP7020_COLD                    0x3203
-#define USB_PID_TWINHAN_VP7020_WARM                    0x3204
-#define USB_PID_TWINHAN_VP7045_COLD                    0x3205
-#define USB_PID_TWINHAN_VP7045_WARM                    0x3206
-#define USB_PID_TWINHAN_VP7021_COLD                    0x3207
-#define USB_PID_TWINHAN_VP7021_WARM                    0x3208
-#define USB_PID_TINYTWIN                               0x3226
-#define USB_PID_TINYTWIN_2                             0xe402
-#define USB_PID_TINYTWIN_3                             0x9016
-#define USB_PID_DNTV_TINYUSB2_COLD                     0x3223
-#define USB_PID_DNTV_TINYUSB2_WARM                     0x3224
-#define USB_PID_ULTIMA_TVBOX_COLD                      0x8105
-#define USB_PID_ULTIMA_TVBOX_WARM                      0x8106
-#define USB_PID_ULTIMA_TVBOX_AN2235_COLD               0x8107
-#define USB_PID_ULTIMA_TVBOX_AN2235_WARM               0x8108
-#define USB_PID_ULTIMA_TVBOX_ANCHOR_COLD               0x2235
-#define USB_PID_ULTIMA_TVBOX_USB2_COLD                 0x8109
-#define USB_PID_ULTIMA_TVBOX_USB2_WARM                 0x810a
-#define USB_PID_ARTEC_T14_COLD                         0x810b
-#define USB_PID_ARTEC_T14_WARM                         0x810c
-#define USB_PID_ARTEC_T14BR                            0x810f
-#define USB_PID_ULTIMA_TVBOX_USB2_FX_COLD              0x8613
-#define USB_PID_ULTIMA_TVBOX_USB2_FX_WARM              0x1002
-#define USB_PID_UNK_HYPER_PALTEK_COLD                  0x005e
-#define USB_PID_UNK_HYPER_PALTEK_WARM                  0x005f
-#define USB_PID_HANFTEK_UMT_010_COLD                   0x0001
-#define USB_PID_HANFTEK_UMT_010_WARM                   0x0015
-#define USB_PID_DTT200U_COLD                           0x0201
-#define USB_PID_DTT200U_WARM                           0x0301
-#define USB_PID_WT220U_ZAP250_COLD                     0x0220
-#define USB_PID_WT220U_COLD                            0x0222
-#define USB_PID_WT220U_WARM                            0x0221
-#define USB_PID_WT220U_FC_COLD                         0x0225
-#define USB_PID_WT220U_FC_WARM                         0x0226
-#define USB_PID_WT220U_ZL0353_COLD                     0x022a
-#define USB_PID_WT220U_ZL0353_WARM                     0x022b
-#define USB_PID_WINTV_NOVA_T_USB2_COLD                 0x9300
-#define USB_PID_WINTV_NOVA_T_USB2_WARM                 0x9301
-#define USB_PID_HAUPPAUGE_NOVA_T_500                   0x9941
-#define USB_PID_HAUPPAUGE_NOVA_T_500_2                 0x9950
-#define USB_PID_HAUPPAUGE_NOVA_T_500_3                 0x8400
-#define USB_PID_HAUPPAUGE_NOVA_T_STICK                 0x7050
-#define USB_PID_HAUPPAUGE_NOVA_T_STICK_2               0x7060
-#define USB_PID_HAUPPAUGE_NOVA_T_STICK_3               0x7070
-#define USB_PID_HAUPPAUGE_MYTV_T                       0x7080
-#define USB_PID_HAUPPAUGE_NOVA_TD_STICK                        0x9580
-#define USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009          0x5200
-#define USB_PID_HAUPPAUGE_TIGER_ATSC                   0xb200
-#define USB_PID_HAUPPAUGE_TIGER_ATSC_B210              0xb210
-#define USB_PID_AVERMEDIA_EXPRESS                      0xb568
-#define USB_PID_AVERMEDIA_VOLAR                                0xa807
-#define USB_PID_AVERMEDIA_VOLAR_2                      0xb808
-#define USB_PID_AVERMEDIA_VOLAR_A868R                  0xa868
-#define USB_PID_AVERMEDIA_MCE_USB_M038                 0x1228
-#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R       0x0039
-#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_ATSC  0x1039
-#define USB_PID_AVERMEDIA_HYBRID_ULTRA_USB_M039R_DVBT  0x2039
-#define USB_PID_AVERMEDIA_VOLAR_X                      0xa815
-#define USB_PID_AVERMEDIA_VOLAR_X_2                    0x8150
-#define USB_PID_AVERMEDIA_A309                         0xa309
-#define USB_PID_AVERMEDIA_A310                         0xa310
-#define USB_PID_AVERMEDIA_A850                         0x850a
-#define USB_PID_AVERMEDIA_A850T                                0x850b
-#define USB_PID_AVERMEDIA_A805                         0xa805
-#define USB_PID_AVERMEDIA_A815M                                0x815a
-#define USB_PID_AVERMEDIA_A835                         0xa835
-#define USB_PID_AVERMEDIA_B835                         0xb835
-#define USB_PID_AVERMEDIA_1867                         0x1867
-#define USB_PID_AVERMEDIA_A867                         0xa867
-#define USB_PID_AVERMEDIA_TWINSTAR                     0x0825
-#define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
-#define USB_PID_TECHNOTREND_CONNECT_CT3650             0x300d
-#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY       0x005a
-#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2     0x0081
-#define USB_PID_TERRATEC_CINERGY_HT_USB_XE             0x0058
-#define USB_PID_TERRATEC_CINERGY_HT_EXPRESS            0x0060
-#define USB_PID_TERRATEC_CINERGY_T_EXPRESS             0x0062
-#define USB_PID_TERRATEC_CINERGY_T_XXS                 0x0078
-#define USB_PID_TERRATEC_CINERGY_T_XXS_2               0x00ab
-#define USB_PID_TERRATEC_H7                            0x10b4
-#define USB_PID_TERRATEC_H7_2                          0x10a3
-#define USB_PID_TERRATEC_T3                            0x10a0
-#define USB_PID_TERRATEC_T5                            0x10a1
-#define USB_PID_NOXON_DAB_STICK                                0x00b3
-#define USB_PID_PINNACLE_EXPRESSCARD_320CX             0x022e
-#define USB_PID_PINNACLE_PCTV2000E                     0x022c
-#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH              0x0228
-#define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T     0x0229
-#define USB_PID_PINNACLE_PCTV71E                       0x022b
-#define USB_PID_PINNACLE_PCTV72E                       0x0236
-#define USB_PID_PINNACLE_PCTV73E                       0x0237
-#define USB_PID_PINNACLE_PCTV310E                      0x3211
-#define USB_PID_PINNACLE_PCTV801E                      0x023a
-#define USB_PID_PINNACLE_PCTV801E_SE                   0x023b
-#define USB_PID_PINNACLE_PCTV340E                      0x023d
-#define USB_PID_PINNACLE_PCTV340E_SE                   0x023e
-#define USB_PID_PINNACLE_PCTV73A                       0x0243
-#define USB_PID_PINNACLE_PCTV73ESE                     0x0245
-#define USB_PID_PINNACLE_PCTV74E                       0x0246
-#define USB_PID_PINNACLE_PCTV282E                      0x0248
-#define USB_PID_PIXELVIEW_SBTVD                                0x5010
-#define USB_PID_PCTV_200E                              0x020e
-#define USB_PID_PCTV_400E                              0x020f
-#define USB_PID_PCTV_450E                              0x0222
-#define USB_PID_PCTV_452E                              0x021f
-#define USB_PID_REALTEK_RTL2831U                       0x2831
-#define USB_PID_REALTEK_RTL2832U                       0x2832
-#define USB_PID_TECHNOTREND_CONNECT_S2_3600            0x3007
-#define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI         0x300a
-#define USB_PID_NEBULA_DIGITV                          0x0201
-#define USB_PID_DVICO_BLUEBIRD_LGDT                    0xd820
-#define USB_PID_DVICO_BLUEBIRD_LG064F_COLD             0xd500
-#define USB_PID_DVICO_BLUEBIRD_LG064F_WARM             0xd501
-#define USB_PID_DVICO_BLUEBIRD_LGZ201_COLD             0xdb00
-#define USB_PID_DVICO_BLUEBIRD_LGZ201_WARM             0xdb01
-#define USB_PID_DVICO_BLUEBIRD_TH7579_COLD             0xdb10
-#define USB_PID_DVICO_BLUEBIRD_TH7579_WARM             0xdb11
-#define USB_PID_DVICO_BLUEBIRD_DUAL_1_COLD             0xdb50
-#define USB_PID_DVICO_BLUEBIRD_DUAL_1_WARM             0xdb51
-#define USB_PID_DVICO_BLUEBIRD_DUAL_2_COLD             0xdb58
-#define USB_PID_DVICO_BLUEBIRD_DUAL_2_WARM             0xdb59
-#define USB_PID_DVICO_BLUEBIRD_DUAL_4                  0xdb78
-#define USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2            0xdb98
-#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2            0xdb70
-#define USB_PID_DVICO_BLUEBIRD_DVB_T_NANO_2_NFW_WARM   0xdb71
-#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_COLD                0xdb54
-#define USB_PID_DIGITALNOW_BLUEBIRD_DUAL_1_WARM                0xdb55
-#define USB_PID_MEDION_MD95700                         0x0932
-#define USB_PID_MSI_MEGASKY580                         0x5580
-#define USB_PID_MSI_MEGASKY580_55801                   0x5581
-#define USB_PID_KYE_DVB_T_COLD                         0x701e
-#define USB_PID_KYE_DVB_T_WARM                         0x701f
-#define USB_PID_LITEON_DVB_T_COLD                      0xf000
-#define USB_PID_LITEON_DVB_T_WARM                      0xf001
-#define USB_PID_DIGIVOX_MINI_SL_COLD                   0xe360
-#define USB_PID_DIGIVOX_MINI_SL_WARM                   0xe361
-#define USB_PID_GRANDTEC_DVBT_USB2_COLD                        0x0bc6
-#define USB_PID_GRANDTEC_DVBT_USB2_WARM                        0x0bc7
-#define USB_PID_WINFAST_DTV2000DS                      0x6a04
-#define USB_PID_WINFAST_DTV_DONGLE_COLD                        0x6025
-#define USB_PID_WINFAST_DTV_DONGLE_WARM                        0x6026
-#define USB_PID_WINFAST_DTV_DONGLE_STK7700P            0x6f00
-#define USB_PID_WINFAST_DTV_DONGLE_H                   0x60f6
-#define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2          0x6f01
-#define USB_PID_WINFAST_DTV_DONGLE_GOLD                        0x6029
-#define USB_PID_GENPIX_8PSK_REV_1_COLD                 0x0200
-#define USB_PID_GENPIX_8PSK_REV_1_WARM                 0x0201
-#define USB_PID_GENPIX_8PSK_REV_2                      0x0202
-#define USB_PID_GENPIX_SKYWALKER_1                     0x0203
-#define USB_PID_GENPIX_SKYWALKER_CW3K                  0x0204
-#define USB_PID_GENPIX_SKYWALKER_2                     0x0206
-#define USB_PID_SIGMATEK_DVB_110                       0x6610
-#define USB_PID_MSI_DIGI_VOX_MINI_II                   0x1513
-#define USB_PID_MSI_DIGIVOX_DUO                                0x8801
-#define USB_PID_OPERA1_COLD                            0x2830
-#define USB_PID_OPERA1_WARM                            0x3829
-#define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD           0x0514
-#define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM           0x0513
-#define USB_PID_GIGABYTE_U7000                         0x7001
-#define USB_PID_GIGABYTE_U8000                         0x7002
-#define USB_PID_ASUS_U3000                             0x171f
-#define USB_PID_ASUS_U3000H                            0x1736
-#define USB_PID_ASUS_U3100                             0x173f
-#define USB_PID_YUAN_EC372S                            0x1edc
-#define USB_PID_YUAN_STK7700PH                         0x1f08
-#define USB_PID_YUAN_PD378S                            0x2edc
-#define USB_PID_YUAN_MC770                             0x0871
-#define USB_PID_YUAN_STK7700D                          0x1efc
-#define USB_PID_YUAN_STK7700D_2                                0x1e8c
-#define USB_PID_DW2102                                 0x2102
-#define USB_PID_XTENSIONS_XD_380                       0x0381
-#define USB_PID_TELESTAR_STARSTICK_2                   0x8000
-#define USB_PID_MSI_DIGI_VOX_MINI_III                   0x8807
-#define USB_PID_SONY_PLAYTV                            0x0003
-#define USB_PID_MYGICA_D689                            0xd811
-#define USB_PID_ELGATO_EYETV_DIVERSITY                 0x0011
-#define USB_PID_ELGATO_EYETV_DTT                       0x0021
-#define USB_PID_ELGATO_EYETV_DTT_2                     0x003f
-#define USB_PID_ELGATO_EYETV_DTT_Dlx                   0x0020
-#define USB_PID_ELGATO_EYETV_SAT                       0x002a
-#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD                0x5000
-#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM                0x5001
-#define USB_PID_FRIIO_WHITE                            0x0001
-#define USB_PID_TVWAY_PLUS                             0x0002
-#define USB_PID_SVEON_STV20                            0xe39d
-#define USB_PID_SVEON_STV22                            0xe401
-#define USB_PID_SVEON_STV22_IT9137                     0xe411
-#define USB_PID_AZUREWAVE_AZ6027                       0x3275
-#define USB_PID_TERRATEC_DVBS2CI_V1                    0x10a4
-#define USB_PID_TERRATEC_DVBS2CI_V2                    0x10ac
-#define USB_PID_TECHNISAT_USB2_HDCI_V1                 0x0001
-#define USB_PID_TECHNISAT_USB2_HDCI_V2                 0x0002
-#define USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2          0x0004
-#define USB_PID_TECHNISAT_USB2_DVB_S2                  0x0500
-#endif
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
deleted file mode 100644 (file)
index 9be65a3..0000000
+++ /dev/null
@@ -1,1753 +0,0 @@
-/*
- * dvb_ca.c: generic DVB functions for EN50221 CAM interfaces
- *
- * Copyright (C) 2004 Andrew de Quincey
- *
- * Parts of this file were based on sources as follows:
- *
- * Copyright (C) 2003 Ralph Metzler <rjkm@metzlerbros.de>
- *
- * based on code:
- *
- * Copyright (C) 1999-2002 Ralph  Metzler
- *                       & Marcus Metzler for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * 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 <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/vmalloc.h>
-#include <linux/delay.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include <linux/kthread.h>
-
-#include "dvb_ca_en50221.h"
-#include "dvb_ringbuffer.h"
-
-static int dvb_ca_en50221_debug;
-
-module_param_named(cam_debug, dvb_ca_en50221_debug, int, 0644);
-MODULE_PARM_DESC(cam_debug, "enable verbose debug messages");
-
-#define dprintk if (dvb_ca_en50221_debug) printk
-
-#define INIT_TIMEOUT_SECS 10
-
-#define HOST_LINK_BUF_SIZE 0x200
-
-#define RX_BUFFER_SIZE 65535
-
-#define MAX_RX_PACKETS_PER_ITERATION 10
-
-#define CTRLIF_DATA      0
-#define CTRLIF_COMMAND   1
-#define CTRLIF_STATUS    1
-#define CTRLIF_SIZE_LOW  2
-#define CTRLIF_SIZE_HIGH 3
-
-#define CMDREG_HC        1     /* Host control */
-#define CMDREG_SW        2     /* Size write */
-#define CMDREG_SR        4     /* Size read */
-#define CMDREG_RS        8     /* Reset interface */
-#define CMDREG_FRIE   0x40     /* Enable FR interrupt */
-#define CMDREG_DAIE   0x80     /* Enable DA interrupt */
-#define IRQEN (CMDREG_DAIE)
-
-#define STATUSREG_RE     1     /* read error */
-#define STATUSREG_WE     2     /* write error */
-#define STATUSREG_FR  0x40     /* module free */
-#define STATUSREG_DA  0x80     /* data available */
-#define STATUSREG_TXERR (STATUSREG_RE|STATUSREG_WE)    /* general transfer error */
-
-
-#define DVB_CA_SLOTSTATE_NONE           0
-#define DVB_CA_SLOTSTATE_UNINITIALISED  1
-#define DVB_CA_SLOTSTATE_RUNNING        2
-#define DVB_CA_SLOTSTATE_INVALID        3
-#define DVB_CA_SLOTSTATE_WAITREADY      4
-#define DVB_CA_SLOTSTATE_VALIDATE       5
-#define DVB_CA_SLOTSTATE_WAITFR         6
-#define DVB_CA_SLOTSTATE_LINKINIT       7
-
-
-/* Information on a CA slot */
-struct dvb_ca_slot {
-
-       /* current state of the CAM */
-       int slot_state;
-
-       /* mutex used for serializing access to one CI slot */
-       struct mutex slot_lock;
-
-       /* Number of CAMCHANGES that have occurred since last processing */
-       atomic_t camchange_count;
-
-       /* Type of last CAMCHANGE */
-       int camchange_type;
-
-       /* base address of CAM config */
-       u32 config_base;
-
-       /* value to write into Config Control register */
-       u8 config_option;
-
-       /* if 1, the CAM supports DA IRQs */
-       u8 da_irq_supported:1;
-
-       /* size of the buffer to use when talking to the CAM */
-       int link_buf_size;
-
-       /* buffer for incoming packets */
-       struct dvb_ringbuffer rx_buffer;
-
-       /* timer used during various states of the slot */
-       unsigned long timeout;
-};
-
-/* Private CA-interface information */
-struct dvb_ca_private {
-
-       /* pointer back to the public data structure */
-       struct dvb_ca_en50221 *pub;
-
-       /* the DVB device */
-       struct dvb_device *dvbdev;
-
-       /* Flags describing the interface (DVB_CA_FLAG_*) */
-       u32 flags;
-
-       /* number of slots supported by this CA interface */
-       unsigned int slot_count;
-
-       /* information on each slot */
-       struct dvb_ca_slot *slot_info;
-
-       /* wait queues for read() and write() operations */
-       wait_queue_head_t wait_queue;
-
-       /* PID of the monitoring thread */
-       struct task_struct *thread;
-
-       /* Flag indicating if the CA device is open */
-       unsigned int open:1;
-
-       /* Flag indicating the thread should wake up now */
-       unsigned int wakeup:1;
-
-       /* Delay the main thread should use */
-       unsigned long delay;
-
-       /* Slot to start looking for data to read from in the next user-space read operation */
-       int next_read_slot;
-};
-
-static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca);
-static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount);
-static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount);
-
-
-/**
- * Safely find needle in haystack.
- *
- * @param haystack Buffer to look in.
- * @param hlen Number of bytes in haystack.
- * @param needle Buffer to find.
- * @param nlen Number of bytes in needle.
- * @return Pointer into haystack needle was found at, or NULL if not found.
- */
-static char *findstr(char * haystack, int hlen, char * needle, int nlen)
-{
-       int i;
-
-       if (hlen < nlen)
-               return NULL;
-
-       for (i = 0; i <= hlen - nlen; i++) {
-               if (!strncmp(haystack + i, needle, nlen))
-                       return haystack + i;
-       }
-
-       return NULL;
-}
-
-
-
-/* ******************************************************************************** */
-/* EN50221 physical interface functions */
-
-
-/**
- * Check CAM status.
- */
-static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot)
-{
-       int slot_status;
-       int cam_present_now;
-       int cam_changed;
-
-       /* IRQ mode */
-       if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) {
-               return (atomic_read(&ca->slot_info[slot].camchange_count) != 0);
-       }
-
-       /* poll mode */
-       slot_status = ca->pub->poll_slot_status(ca->pub, slot, ca->open);
-
-       cam_present_now = (slot_status & DVB_CA_EN50221_POLL_CAM_PRESENT) ? 1 : 0;
-       cam_changed = (slot_status & DVB_CA_EN50221_POLL_CAM_CHANGED) ? 1 : 0;
-       if (!cam_changed) {
-               int cam_present_old = (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE);
-               cam_changed = (cam_present_now != cam_present_old);
-       }
-
-       if (cam_changed) {
-               if (!cam_present_now) {
-                       ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;
-               } else {
-                       ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_INSERTED;
-               }
-               atomic_set(&ca->slot_info[slot].camchange_count, 1);
-       } else {
-               if ((ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) &&
-                   (slot_status & DVB_CA_EN50221_POLL_CAM_READY)) {
-                       // move to validate state if reset is completed
-                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE;
-               }
-       }
-
-       return cam_changed;
-}
-
-
-/**
- * Wait for flags to become set on the STATUS register on a CAM interface,
- * checking for errors and timeout.
- *
- * @param ca CA instance.
- * @param slot Slot on interface.
- * @param waitfor Flags to wait for.
- * @param timeout_ms Timeout in milliseconds.
- *
- * @return 0 on success, nonzero on error.
- */
-static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot,
-                                        u8 waitfor, int timeout_hz)
-{
-       unsigned long timeout;
-       unsigned long start;
-
-       dprintk("%s\n", __func__);
-
-       /* loop until timeout elapsed */
-       start = jiffies;
-       timeout = jiffies + timeout_hz;
-       while (1) {
-               /* read the status and check for error */
-               int res = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
-               if (res < 0)
-                       return -EIO;
-
-               /* if we got the flags, it was successful! */
-               if (res & waitfor) {
-                       dprintk("%s succeeded timeout:%lu\n", __func__, jiffies - start);
-                       return 0;
-               }
-
-               /* check for timeout */
-               if (time_after(jiffies, timeout)) {
-                       break;
-               }
-
-               /* wait for a bit */
-               msleep(1);
-       }
-
-       dprintk("%s failed timeout:%lu\n", __func__, jiffies - start);
-
-       /* if we get here, we've timed out */
-       return -ETIMEDOUT;
-}
-
-
-/**
- * Initialise the link layer connection to a CAM.
- *
- * @param ca CA instance.
- * @param slot Slot id.
- *
- * @return 0 on success, nonzero on failure.
- */
-static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot)
-{
-       int ret;
-       int buf_size;
-       u8 buf[2];
-
-       dprintk("%s\n", __func__);
-
-       /* we'll be determining these during this function */
-       ca->slot_info[slot].da_irq_supported = 0;
-
-       /* set the host link buffer size temporarily. it will be overwritten with the
-        * real negotiated size later. */
-       ca->slot_info[slot].link_buf_size = 2;
-
-       /* read the buffer size from the CAM */
-       if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SR)) != 0)
-               return ret;
-       if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ / 10)) != 0)
-               return ret;
-       if ((ret = dvb_ca_en50221_read_data(ca, slot, buf, 2)) != 2)
-               return -EIO;
-       if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0)
-               return ret;
-
-       /* store it, and choose the minimum of our buffer and the CAM's buffer size */
-       buf_size = (buf[0] << 8) | buf[1];
-       if (buf_size > HOST_LINK_BUF_SIZE)
-               buf_size = HOST_LINK_BUF_SIZE;
-       ca->slot_info[slot].link_buf_size = buf_size;
-       buf[0] = buf_size >> 8;
-       buf[1] = buf_size & 0xff;
-       dprintk("Chosen link buffer size of %i\n", buf_size);
-
-       /* write the buffer size to the CAM */
-       if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SW)) != 0)
-               return ret;
-       if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10)) != 0)
-               return ret;
-       if ((ret = dvb_ca_en50221_write_data(ca, slot, buf, 2)) != 2)
-               return -EIO;
-       if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0)
-               return ret;
-
-       /* success */
-       return 0;
-}
-
-/**
- * Read a tuple from attribute memory.
- *
- * @param ca CA instance.
- * @param slot Slot id.
- * @param address Address to read from. Updated.
- * @param tupleType Tuple id byte. Updated.
- * @param tupleLength Tuple length. Updated.
- * @param tuple Dest buffer for tuple (must be 256 bytes). Updated.
- *
- * @return 0 on success, nonzero on error.
- */
-static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot,
-                                    int *address, int *tupleType, int *tupleLength, u8 * tuple)
-{
-       int i;
-       int _tupleType;
-       int _tupleLength;
-       int _address = *address;
-
-       /* grab the next tuple length and type */
-       if ((_tupleType = ca->pub->read_attribute_mem(ca->pub, slot, _address)) < 0)
-               return _tupleType;
-       if (_tupleType == 0xff) {
-               dprintk("END OF CHAIN TUPLE type:0x%x\n", _tupleType);
-               *address += 2;
-               *tupleType = _tupleType;
-               *tupleLength = 0;
-               return 0;
-       }
-       if ((_tupleLength = ca->pub->read_attribute_mem(ca->pub, slot, _address + 2)) < 0)
-               return _tupleLength;
-       _address += 4;
-
-       dprintk("TUPLE type:0x%x length:%i\n", _tupleType, _tupleLength);
-
-       /* read in the whole tuple */
-       for (i = 0; i < _tupleLength; i++) {
-               tuple[i] = ca->pub->read_attribute_mem(ca->pub, slot, _address + (i * 2));
-               dprintk("  0x%02x: 0x%02x %c\n",
-                       i, tuple[i] & 0xff,
-                       ((tuple[i] > 31) && (tuple[i] < 127)) ? tuple[i] : '.');
-       }
-       _address += (_tupleLength * 2);
-
-       // success
-       *tupleType = _tupleType;
-       *tupleLength = _tupleLength;
-       *address = _address;
-       return 0;
-}
-
-
-/**
- * Parse attribute memory of a CAM module, extracting Config register, and checking
- * it is a DVB CAM module.
- *
- * @param ca CA instance.
- * @param slot Slot id.
- *
- * @return 0 on success, <0 on failure.
- */
-static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
-{
-       int address = 0;
-       int tupleLength;
-       int tupleType;
-       u8 tuple[257];
-       char *dvb_str;
-       int rasz;
-       int status;
-       int got_cftableentry = 0;
-       int end_chain = 0;
-       int i;
-       u16 manfid = 0;
-       u16 devid = 0;
-
-
-       // CISTPL_DEVICE_0A
-       if ((status =
-            dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
-               return status;
-       if (tupleType != 0x1D)
-               return -EINVAL;
-
-
-
-       // CISTPL_DEVICE_0C
-       if ((status =
-            dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
-               return status;
-       if (tupleType != 0x1C)
-               return -EINVAL;
-
-
-
-       // CISTPL_VERS_1
-       if ((status =
-            dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0)
-               return status;
-       if (tupleType != 0x15)
-               return -EINVAL;
-
-
-
-       // CISTPL_MANFID
-       if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
-                                               &tupleLength, tuple)) < 0)
-               return status;
-       if (tupleType != 0x20)
-               return -EINVAL;
-       if (tupleLength != 4)
-               return -EINVAL;
-       manfid = (tuple[1] << 8) | tuple[0];
-       devid = (tuple[3] << 8) | tuple[2];
-
-
-
-       // CISTPL_CONFIG
-       if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
-                                               &tupleLength, tuple)) < 0)
-               return status;
-       if (tupleType != 0x1A)
-               return -EINVAL;
-       if (tupleLength < 3)
-               return -EINVAL;
-
-       /* extract the configbase */
-       rasz = tuple[0] & 3;
-       if (tupleLength < (3 + rasz + 14))
-               return -EINVAL;
-       ca->slot_info[slot].config_base = 0;
-       for (i = 0; i < rasz + 1; i++) {
-               ca->slot_info[slot].config_base |= (tuple[2 + i] << (8 * i));
-       }
-
-       /* check it contains the correct DVB string */
-       dvb_str = findstr((char *)tuple, tupleLength, "DVB_CI_V", 8);
-       if (dvb_str == NULL)
-               return -EINVAL;
-       if (tupleLength < ((dvb_str - (char *) tuple) + 12))
-               return -EINVAL;
-
-       /* is it a version we support? */
-       if (strncmp(dvb_str + 8, "1.00", 4)) {
-               printk("dvb_ca adapter %d: Unsupported DVB CAM module version %c%c%c%c\n",
-                      ca->dvbdev->adapter->num, dvb_str[8], dvb_str[9], dvb_str[10], dvb_str[11]);
-               return -EINVAL;
-       }
-
-       /* process the CFTABLE_ENTRY tuples, and any after those */
-       while ((!end_chain) && (address < 0x1000)) {
-               if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType,
-                                                       &tupleLength, tuple)) < 0)
-                       return status;
-               switch (tupleType) {
-               case 0x1B:      // CISTPL_CFTABLE_ENTRY
-                       if (tupleLength < (2 + 11 + 17))
-                               break;
-
-                       /* if we've already parsed one, just use it */
-                       if (got_cftableentry)
-                               break;
-
-                       /* get the config option */
-                       ca->slot_info[slot].config_option = tuple[0] & 0x3f;
-
-                       /* OK, check it contains the correct strings */
-                       if ((findstr((char *)tuple, tupleLength, "DVB_HOST", 8) == NULL) ||
-                           (findstr((char *)tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL))
-                               break;
-
-                       got_cftableentry = 1;
-                       break;
-
-               case 0x14:      // CISTPL_NO_LINK
-                       break;
-
-               case 0xFF:      // CISTPL_END
-                       end_chain = 1;
-                       break;
-
-               default:        /* Unknown tuple type - just skip this tuple and move to the next one */
-                       dprintk("dvb_ca: Skipping unknown tuple type:0x%x length:0x%x\n", tupleType,
-                               tupleLength);
-                       break;
-               }
-       }
-
-       if ((address > 0x1000) || (!got_cftableentry))
-               return -EINVAL;
-
-       dprintk("Valid DVB CAM detected MANID:%x DEVID:%x CONFIGBASE:0x%x CONFIGOPTION:0x%x\n",
-               manfid, devid, ca->slot_info[slot].config_base, ca->slot_info[slot].config_option);
-
-       // success!
-       return 0;
-}
-
-
-/**
- * Set CAM's configoption correctly.
- *
- * @param ca CA instance.
- * @param slot Slot containing the CAM.
- */
-static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot)
-{
-       int configoption;
-
-       dprintk("%s\n", __func__);
-
-       /* set the config option */
-       ca->pub->write_attribute_mem(ca->pub, slot,
-                                    ca->slot_info[slot].config_base,
-                                    ca->slot_info[slot].config_option);
-
-       /* check it */
-       configoption = ca->pub->read_attribute_mem(ca->pub, slot, ca->slot_info[slot].config_base);
-       dprintk("Set configoption 0x%x, read configoption 0x%x\n",
-               ca->slot_info[slot].config_option, configoption & 0x3f);
-
-       /* fine! */
-       return 0;
-
-}
-
-
-/**
- * This function talks to an EN50221 CAM control interface. It reads a buffer of
- * data from the CAM. The data can either be stored in a supplied buffer, or
- * automatically be added to the slot's rx_buffer.
- *
- * @param ca CA instance.
- * @param slot Slot to read from.
- * @param ebuf If non-NULL, the data will be written to this buffer. If NULL,
- * the data will be added into the buffering system as a normal fragment.
- * @param ecount Size of ebuf. Ignored if ebuf is NULL.
- *
- * @return Number of bytes read, or < 0 on error
- */
-static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount)
-{
-       int bytes_read;
-       int status;
-       u8 buf[HOST_LINK_BUF_SIZE];
-       int i;
-
-       dprintk("%s\n", __func__);
-
-       /* check if we have space for a link buf in the rx_buffer */
-       if (ebuf == NULL) {
-               int buf_free;
-
-               if (ca->slot_info[slot].rx_buffer.data == NULL) {
-                       status = -EIO;
-                       goto exit;
-               }
-               buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer);
-
-               if (buf_free < (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) {
-                       status = -EAGAIN;
-                       goto exit;
-               }
-       }
-
-       /* check if there is data available */
-       if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
-               goto exit;
-       if (!(status & STATUSREG_DA)) {
-               /* no data */
-               status = 0;
-               goto exit;
-       }
-
-       /* read the amount of data */
-       if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH)) < 0)
-               goto exit;
-       bytes_read = status << 8;
-       if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW)) < 0)
-               goto exit;
-       bytes_read |= status;
-
-       /* check it will fit */
-       if (ebuf == NULL) {
-               if (bytes_read > ca->slot_info[slot].link_buf_size) {
-                       printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n",
-                              ca->dvbdev->adapter->num, bytes_read, ca->slot_info[slot].link_buf_size);
-                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
-                       status = -EIO;
-                       goto exit;
-               }
-               if (bytes_read < 2) {
-                       printk("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n",
-                              ca->dvbdev->adapter->num);
-                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
-                       status = -EIO;
-                       goto exit;
-               }
-       } else {
-               if (bytes_read > ecount) {
-                       printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n",
-                              ca->dvbdev->adapter->num);
-                       status = -EIO;
-                       goto exit;
-               }
-       }
-
-       /* fill the buffer */
-       for (i = 0; i < bytes_read; i++) {
-               /* read byte and check */
-               if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_DATA)) < 0)
-                       goto exit;
-
-               /* OK, store it in the buffer */
-               buf[i] = status;
-       }
-
-       /* check for read error (RE should now be 0) */
-       if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
-               goto exit;
-       if (status & STATUSREG_RE) {
-               ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
-               status = -EIO;
-               goto exit;
-       }
-
-       /* OK, add it to the receive buffer, or copy into external buffer if supplied */
-       if (ebuf == NULL) {
-               if (ca->slot_info[slot].rx_buffer.data == NULL) {
-                       status = -EIO;
-                       goto exit;
-               }
-               dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read);
-       } else {
-               memcpy(ebuf, buf, bytes_read);
-       }
-
-       dprintk("Received CA packet for slot %i connection id 0x%x last_frag:%i size:0x%x\n", slot,
-               buf[0], (buf[1] & 0x80) == 0, bytes_read);
-
-       /* wake up readers when a last_fragment is received */
-       if ((buf[1] & 0x80) == 0x00) {
-               wake_up_interruptible(&ca->wait_queue);
-       }
-       status = bytes_read;
-
-exit:
-       return status;
-}
-
-
-/**
- * This function talks to an EN50221 CAM control interface. It writes a buffer of data
- * to a CAM.
- *
- * @param ca CA instance.
- * @param slot Slot to write to.
- * @param ebuf The data in this buffer is treated as a complete link-level packet to
- * be written.
- * @param count Size of ebuf.
- *
- * @return Number of bytes written, or < 0 on error.
- */
-static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * buf, int bytes_write)
-{
-       int status;
-       int i;
-
-       dprintk("%s\n", __func__);
-
-
-       /* sanity check */
-       if (bytes_write > ca->slot_info[slot].link_buf_size)
-               return -EINVAL;
-
-       /* it is possible we are dealing with a single buffer implementation,
-          thus if there is data available for read or if there is even a read
-          already in progress, we do nothing but awake the kernel thread to
-          process the data if necessary. */
-       if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
-               goto exitnowrite;
-       if (status & (STATUSREG_DA | STATUSREG_RE)) {
-               if (status & STATUSREG_DA)
-                       dvb_ca_en50221_thread_wakeup(ca);
-
-               status = -EAGAIN;
-               goto exitnowrite;
-       }
-
-       /* OK, set HC bit */
-       if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND,
-                                                IRQEN | CMDREG_HC)) != 0)
-               goto exit;
-
-       /* check if interface is still free */
-       if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
-               goto exit;
-       if (!(status & STATUSREG_FR)) {
-               /* it wasn't free => try again later */
-               status = -EAGAIN;
-               goto exit;
-       }
-
-       /* send the amount of data */
-       if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0)
-               goto exit;
-       if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW,
-                                                bytes_write & 0xff)) != 0)
-               goto exit;
-
-       /* send the buffer */
-       for (i = 0; i < bytes_write; i++) {
-               if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_DATA, buf[i])) != 0)
-                       goto exit;
-       }
-
-       /* check for write error (WE should now be 0) */
-       if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0)
-               goto exit;
-       if (status & STATUSREG_WE) {
-               ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
-               status = -EIO;
-               goto exit;
-       }
-       status = bytes_write;
-
-       dprintk("Wrote CA packet for slot %i, connection id 0x%x last_frag:%i size:0x%x\n", slot,
-               buf[0], (buf[1] & 0x80) == 0, bytes_write);
-
-exit:
-       ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN);
-
-exitnowrite:
-       return status;
-}
-EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq);
-
-
-
-/* ******************************************************************************** */
-/* EN50221 higher level functions */
-
-
-/**
- * A CAM has been removed => shut it down.
- *
- * @param ca CA instance.
- * @param slot Slot to shut down.
- */
-static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot)
-{
-       dprintk("%s\n", __func__);
-
-       ca->pub->slot_shutdown(ca->pub, slot);
-       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
-
-       /* need to wake up all processes to check if they're now
-          trying to write to a defunct CAM */
-       wake_up_interruptible(&ca->wait_queue);
-
-       dprintk("Slot %i shutdown\n", slot);
-
-       /* success */
-       return 0;
-}
-EXPORT_SYMBOL(dvb_ca_en50221_camready_irq);
-
-
-/**
- * A CAMCHANGE IRQ has occurred.
- *
- * @param ca CA instance.
- * @param slot Slot concerned.
- * @param change_type One of the DVB_CA_CAMCHANGE_* values.
- */
-void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221 *pubca, int slot, int change_type)
-{
-       struct dvb_ca_private *ca = pubca->private;
-
-       dprintk("CAMCHANGE IRQ slot:%i change_type:%i\n", slot, change_type);
-
-       switch (change_type) {
-       case DVB_CA_EN50221_CAMCHANGE_REMOVED:
-       case DVB_CA_EN50221_CAMCHANGE_INSERTED:
-               break;
-
-       default:
-               return;
-       }
-
-       ca->slot_info[slot].camchange_type = change_type;
-       atomic_inc(&ca->slot_info[slot].camchange_count);
-       dvb_ca_en50221_thread_wakeup(ca);
-}
-EXPORT_SYMBOL(dvb_ca_en50221_frda_irq);
-
-
-/**
- * A CAMREADY IRQ has occurred.
- *
- * @param ca CA instance.
- * @param slot Slot concerned.
- */
-void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot)
-{
-       struct dvb_ca_private *ca = pubca->private;
-
-       dprintk("CAMREADY IRQ slot:%i\n", slot);
-
-       if (ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) {
-               ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE;
-               dvb_ca_en50221_thread_wakeup(ca);
-       }
-}
-
-
-/**
- * An FR or DA IRQ has occurred.
- *
- * @param ca CA instance.
- * @param slot Slot concerned.
- */
-void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot)
-{
-       struct dvb_ca_private *ca = pubca->private;
-       int flags;
-
-       dprintk("FR/DA IRQ slot:%i\n", slot);
-
-       switch (ca->slot_info[slot].slot_state) {
-       case DVB_CA_SLOTSTATE_LINKINIT:
-               flags = ca->pub->read_cam_control(pubca, slot, CTRLIF_STATUS);
-               if (flags & STATUSREG_DA) {
-                       dprintk("CAM supports DA IRQ\n");
-                       ca->slot_info[slot].da_irq_supported = 1;
-               }
-               break;
-
-       case DVB_CA_SLOTSTATE_RUNNING:
-               if (ca->open)
-                       dvb_ca_en50221_thread_wakeup(ca);
-               break;
-       }
-}
-
-
-
-/* ******************************************************************************** */
-/* EN50221 thread functions */
-
-/**
- * Wake up the DVB CA thread
- *
- * @param ca CA instance.
- */
-static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca)
-{
-
-       dprintk("%s\n", __func__);
-
-       ca->wakeup = 1;
-       mb();
-       wake_up_process(ca->thread);
-}
-
-/**
- * Update the delay used by the thread.
- *
- * @param ca CA instance.
- */
-static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca)
-{
-       int delay;
-       int curdelay = 100000000;
-       int slot;
-
-       /* Beware of too high polling frequency, because one polling
-        * call might take several hundred milliseconds until timeout!
-        */
-       for (slot = 0; slot < ca->slot_count; slot++) {
-               switch (ca->slot_info[slot].slot_state) {
-               default:
-               case DVB_CA_SLOTSTATE_NONE:
-                       delay = HZ * 60;  /* 60s */
-                       if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
-                               delay = HZ * 5;  /* 5s */
-                       break;
-               case DVB_CA_SLOTSTATE_INVALID:
-                       delay = HZ * 60;  /* 60s */
-                       if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
-                               delay = HZ / 10;  /* 100ms */
-                       break;
-
-               case DVB_CA_SLOTSTATE_UNINITIALISED:
-               case DVB_CA_SLOTSTATE_WAITREADY:
-               case DVB_CA_SLOTSTATE_VALIDATE:
-               case DVB_CA_SLOTSTATE_WAITFR:
-               case DVB_CA_SLOTSTATE_LINKINIT:
-                       delay = HZ / 10;  /* 100ms */
-                       break;
-
-               case DVB_CA_SLOTSTATE_RUNNING:
-                       delay = HZ * 60;  /* 60s */
-                       if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE))
-                               delay = HZ / 10;  /* 100ms */
-                       if (ca->open) {
-                               if ((!ca->slot_info[slot].da_irq_supported) ||
-                                   (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA)))
-                                       delay = HZ / 10;  /* 100ms */
-                       }
-                       break;
-               }
-
-               if (delay < curdelay)
-                       curdelay = delay;
-       }
-
-       ca->delay = curdelay;
-}
-
-
-
-/**
- * Kernel thread which monitors CA slots for CAM changes, and performs data transfers.
- */
-static int dvb_ca_en50221_thread(void *data)
-{
-       struct dvb_ca_private *ca = data;
-       int slot;
-       int flags;
-       int status;
-       int pktcount;
-       void *rxbuf;
-
-       dprintk("%s\n", __func__);
-
-       /* choose the correct initial delay */
-       dvb_ca_en50221_thread_update_delay(ca);
-
-       /* main loop */
-       while (!kthread_should_stop()) {
-               /* sleep for a bit */
-               if (!ca->wakeup) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(ca->delay);
-                       if (kthread_should_stop())
-                               return 0;
-               }
-               ca->wakeup = 0;
-
-               /* go through all the slots processing them */
-               for (slot = 0; slot < ca->slot_count; slot++) {
-
-                       mutex_lock(&ca->slot_info[slot].slot_lock);
-
-                       // check the cam status + deal with CAMCHANGEs
-                       while (dvb_ca_en50221_check_camstatus(ca, slot)) {
-                               /* clear down an old CI slot if necessary */
-                               if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE)
-                                       dvb_ca_en50221_slot_shutdown(ca, slot);
-
-                               /* if a CAM is NOW present, initialise it */
-                               if (ca->slot_info[slot].camchange_type == DVB_CA_EN50221_CAMCHANGE_INSERTED) {
-                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_UNINITIALISED;
-                               }
-
-                               /* we've handled one CAMCHANGE */
-                               dvb_ca_en50221_thread_update_delay(ca);
-                               atomic_dec(&ca->slot_info[slot].camchange_count);
-                       }
-
-                       // CAM state machine
-                       switch (ca->slot_info[slot].slot_state) {
-                       case DVB_CA_SLOTSTATE_NONE:
-                       case DVB_CA_SLOTSTATE_INVALID:
-                               // no action needed
-                               break;
-
-                       case DVB_CA_SLOTSTATE_UNINITIALISED:
-                               ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITREADY;
-                               ca->pub->slot_reset(ca->pub, slot);
-                               ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);
-                               break;
-
-                       case DVB_CA_SLOTSTATE_WAITREADY:
-                               if (time_after(jiffies, ca->slot_info[slot].timeout)) {
-                                       printk("dvb_ca adaptor %d: PC card did not respond :(\n",
-                                              ca->dvbdev->adapter->num);
-                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-                                       dvb_ca_en50221_thread_update_delay(ca);
-                                       break;
-                               }
-                               // no other action needed; will automatically change state when ready
-                               break;
-
-                       case DVB_CA_SLOTSTATE_VALIDATE:
-                               if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) {
-                                       /* we need this extra check for annoying interfaces like the budget-av */
-                                       if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
-                                           (ca->pub->poll_slot_status)) {
-                                               status = ca->pub->poll_slot_status(ca->pub, slot, 0);
-                                               if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
-                                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
-                                                       dvb_ca_en50221_thread_update_delay(ca);
-                                                       break;
-                                               }
-                                       }
-
-                                       printk("dvb_ca adapter %d: Invalid PC card inserted :(\n",
-                                              ca->dvbdev->adapter->num);
-                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-                                       dvb_ca_en50221_thread_update_delay(ca);
-                                       break;
-                               }
-                               if (dvb_ca_en50221_set_configoption(ca, slot) != 0) {
-                                       printk("dvb_ca adapter %d: Unable to initialise CAM :(\n",
-                                              ca->dvbdev->adapter->num);
-                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-                                       dvb_ca_en50221_thread_update_delay(ca);
-                                       break;
-                               }
-                               if (ca->pub->write_cam_control(ca->pub, slot,
-                                                              CTRLIF_COMMAND, CMDREG_RS) != 0) {
-                                       printk("dvb_ca adapter %d: Unable to reset CAM IF\n",
-                                              ca->dvbdev->adapter->num);
-                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-                                       dvb_ca_en50221_thread_update_delay(ca);
-                                       break;
-                               }
-                               dprintk("DVB CAM validated successfully\n");
-
-                               ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ);
-                               ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITFR;
-                               ca->wakeup = 1;
-                               break;
-
-                       case DVB_CA_SLOTSTATE_WAITFR:
-                               if (time_after(jiffies, ca->slot_info[slot].timeout)) {
-                                       printk("dvb_ca adapter %d: DVB CAM did not respond :(\n",
-                                              ca->dvbdev->adapter->num);
-                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-                                       dvb_ca_en50221_thread_update_delay(ca);
-                                       break;
-                               }
-
-                               flags = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS);
-                               if (flags & STATUSREG_FR) {
-                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT;
-                                       ca->wakeup = 1;
-                               }
-                               break;
-
-                       case DVB_CA_SLOTSTATE_LINKINIT:
-                               if (dvb_ca_en50221_link_init(ca, slot) != 0) {
-                                       /* we need this extra check for annoying interfaces like the budget-av */
-                                       if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) &&
-                                           (ca->pub->poll_slot_status)) {
-                                               status = ca->pub->poll_slot_status(ca->pub, slot, 0);
-                                               if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) {
-                                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE;
-                                                       dvb_ca_en50221_thread_update_delay(ca);
-                                                       break;
-                                               }
-                                       }
-
-                                       printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num);
-                                       ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-                                       dvb_ca_en50221_thread_update_delay(ca);
-                                       break;
-                               }
-
-                               if (ca->slot_info[slot].rx_buffer.data == NULL) {
-                                       rxbuf = vmalloc(RX_BUFFER_SIZE);
-                                       if (rxbuf == NULL) {
-                                               printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num);
-                                               ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID;
-                                               dvb_ca_en50221_thread_update_delay(ca);
-                                               break;
-                                       }
-                                       dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE);
-                               }
-
-                               ca->pub->slot_ts_enable(ca->pub, slot);
-                               ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING;
-                               dvb_ca_en50221_thread_update_delay(ca);
-                               printk("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", ca->dvbdev->adapter->num);
-                               break;
-
-                       case DVB_CA_SLOTSTATE_RUNNING:
-                               if (!ca->open)
-                                       break;
-
-                               // poll slots for data
-                               pktcount = 0;
-                               while ((status = dvb_ca_en50221_read_data(ca, slot, NULL, 0)) > 0) {
-                                       if (!ca->open)
-                                               break;
-
-                                       /* if a CAMCHANGE occurred at some point, do not do any more processing of this slot */
-                                       if (dvb_ca_en50221_check_camstatus(ca, slot)) {
-                                               // we dont want to sleep on the next iteration so we can handle the cam change
-                                               ca->wakeup = 1;
-                                               break;
-                                       }
-
-                                       /* check if we've hit our limit this time */
-                                       if (++pktcount >= MAX_RX_PACKETS_PER_ITERATION) {
-                                               // dont sleep; there is likely to be more data to read
-                                               ca->wakeup = 1;
-                                               break;
-                                       }
-                               }
-                               break;
-                       }
-
-                       mutex_unlock(&ca->slot_info[slot].slot_lock);
-               }
-       }
-
-       return 0;
-}
-
-
-
-/* ******************************************************************************** */
-/* EN50221 IO interface functions */
-
-/**
- * Real ioctl implementation.
- * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them.
- *
- * @param inode Inode concerned.
- * @param file File concerned.
- * @param cmd IOCTL command.
- * @param arg Associated argument.
- *
- * @return 0 on success, <0 on error.
- */
-static int dvb_ca_en50221_io_do_ioctl(struct file *file,
-                                     unsigned int cmd, void *parg)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dvb_ca_private *ca = dvbdev->priv;
-       int err = 0;
-       int slot;
-
-       dprintk("%s\n", __func__);
-
-       switch (cmd) {
-       case CA_RESET:
-               for (slot = 0; slot < ca->slot_count; slot++) {
-                       mutex_lock(&ca->slot_info[slot].slot_lock);
-                       if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) {
-                               dvb_ca_en50221_slot_shutdown(ca, slot);
-                               if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)
-                                       dvb_ca_en50221_camchange_irq(ca->pub,
-                                                                    slot,
-                                                                    DVB_CA_EN50221_CAMCHANGE_INSERTED);
-                       }
-                       mutex_unlock(&ca->slot_info[slot].slot_lock);
-               }
-               ca->next_read_slot = 0;
-               dvb_ca_en50221_thread_wakeup(ca);
-               break;
-
-       case CA_GET_CAP: {
-               struct ca_caps *caps = parg;
-
-               caps->slot_num = ca->slot_count;
-               caps->slot_type = CA_CI_LINK;
-               caps->descr_num = 0;
-               caps->descr_type = 0;
-               break;
-       }
-
-       case CA_GET_SLOT_INFO: {
-               struct ca_slot_info *info = parg;
-
-               if ((info->num > ca->slot_count) || (info->num < 0))
-                       return -EINVAL;
-
-               info->type = CA_CI_LINK;
-               info->flags = 0;
-               if ((ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_NONE)
-                       && (ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_INVALID)) {
-                       info->flags = CA_CI_MODULE_PRESENT;
-               }
-               if (ca->slot_info[info->num].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
-                       info->flags |= CA_CI_MODULE_READY;
-               }
-               break;
-       }
-
-       default:
-               err = -EINVAL;
-               break;
-       }
-
-       return err;
-}
-
-
-/**
- * Wrapper for ioctl implementation.
- *
- * @param inode Inode concerned.
- * @param file File concerned.
- * @param cmd IOCTL command.
- * @param arg Associated argument.
- *
- * @return 0 on success, <0 on error.
- */
-static long dvb_ca_en50221_io_ioctl(struct file *file,
-                                   unsigned int cmd, unsigned long arg)
-{
-       return dvb_usercopy(file, cmd, arg, dvb_ca_en50221_io_do_ioctl);
-}
-
-
-/**
- * Implementation of write() syscall.
- *
- * @param file File structure.
- * @param buf Source buffer.
- * @param count Size of source buffer.
- * @param ppos Position in file (ignored).
- *
- * @return Number of bytes read, or <0 on error.
- */
-static ssize_t dvb_ca_en50221_io_write(struct file *file,
-                                      const char __user * buf, size_t count, loff_t * ppos)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dvb_ca_private *ca = dvbdev->priv;
-       u8 slot, connection_id;
-       int status;
-       u8 fragbuf[HOST_LINK_BUF_SIZE];
-       int fragpos = 0;
-       int fraglen;
-       unsigned long timeout;
-       int written;
-
-       dprintk("%s\n", __func__);
-
-       /* Incoming packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
-       if (count < 2)
-               return -EINVAL;
-
-       /* extract slot & connection id */
-       if (copy_from_user(&slot, buf, 1))
-               return -EFAULT;
-       if (copy_from_user(&connection_id, buf + 1, 1))
-               return -EFAULT;
-       buf += 2;
-       count -= 2;
-
-       /* check if the slot is actually running */
-       if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING)
-               return -EINVAL;
-
-       /* fragment the packets & store in the buffer */
-       while (fragpos < count) {
-               fraglen = ca->slot_info[slot].link_buf_size - 2;
-               if (fraglen < 0)
-                       break;
-               if (fraglen > HOST_LINK_BUF_SIZE - 2)
-                       fraglen = HOST_LINK_BUF_SIZE - 2;
-               if ((count - fragpos) < fraglen)
-                       fraglen = count - fragpos;
-
-               fragbuf[0] = connection_id;
-               fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00;
-               status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen);
-               if (status) {
-                       status = -EFAULT;
-                       goto exit;
-               }
-
-               timeout = jiffies + HZ / 2;
-               written = 0;
-               while (!time_after(jiffies, timeout)) {
-                       /* check the CAM hasn't been removed/reset in the meantime */
-                       if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) {
-                               status = -EIO;
-                               goto exit;
-                       }
-
-                       mutex_lock(&ca->slot_info[slot].slot_lock);
-                       status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen + 2);
-                       mutex_unlock(&ca->slot_info[slot].slot_lock);
-                       if (status == (fraglen + 2)) {
-                               written = 1;
-                               break;
-                       }
-                       if (status != -EAGAIN)
-                               goto exit;
-
-                       msleep(1);
-               }
-               if (!written) {
-                       status = -EIO;
-                       goto exit;
-               }
-
-               fragpos += fraglen;
-       }
-       status = count + 2;
-
-exit:
-       return status;
-}
-
-
-/**
- * Condition for waking up in dvb_ca_en50221_io_read_condition
- */
-static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca,
-                                           int *result, int *_slot)
-{
-       int slot;
-       int slot_count = 0;
-       int idx;
-       size_t fraglen;
-       int connection_id = -1;
-       int found = 0;
-       u8 hdr[2];
-
-       slot = ca->next_read_slot;
-       while ((slot_count < ca->slot_count) && (!found)) {
-               if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING)
-                       goto nextslot;
-
-               if (ca->slot_info[slot].rx_buffer.data == NULL) {
-                       return 0;
-               }
-
-               idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
-               while (idx != -1) {
-                       dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2);
-                       if (connection_id == -1)
-                               connection_id = hdr[0];
-                       if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) {
-                               *_slot = slot;
-                               found = 1;
-                               break;
-                       }
-
-                       idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen);
-               }
-
-nextslot:
-               slot = (slot + 1) % ca->slot_count;
-               slot_count++;
-       }
-
-       ca->next_read_slot = slot;
-       return found;
-}
-
-
-/**
- * Implementation of read() syscall.
- *
- * @param file File structure.
- * @param buf Destination buffer.
- * @param count Size of destination buffer.
- * @param ppos Position in file (ignored).
- *
- * @return Number of bytes read, or <0 on error.
- */
-static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
-                                     size_t count, loff_t * ppos)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dvb_ca_private *ca = dvbdev->priv;
-       int status;
-       int result = 0;
-       u8 hdr[2];
-       int slot;
-       int connection_id = -1;
-       size_t idx, idx2;
-       int last_fragment = 0;
-       size_t fraglen;
-       int pktlen;
-       int dispose = 0;
-
-       dprintk("%s\n", __func__);
-
-       /* Outgoing packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */
-       if (count < 2)
-               return -EINVAL;
-
-       /* wait for some data */
-       if ((status = dvb_ca_en50221_io_read_condition(ca, &result, &slot)) == 0) {
-
-               /* if we're in nonblocking mode, exit immediately */
-               if (file->f_flags & O_NONBLOCK)
-                       return -EWOULDBLOCK;
-
-               /* wait for some data */
-               status = wait_event_interruptible(ca->wait_queue,
-                                                 dvb_ca_en50221_io_read_condition
-                                                 (ca, &result, &slot));
-       }
-       if ((status < 0) || (result < 0)) {
-               if (result)
-                       return result;
-               return status;
-       }
-
-       idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen);
-       pktlen = 2;
-       do {
-               if (idx == -1) {
-                       printk("dvb_ca adapter %d: BUG: read packet ended before last_fragment encountered\n", ca->dvbdev->adapter->num);
-                       status = -EIO;
-                       goto exit;
-               }
-
-               dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2);
-               if (connection_id == -1)
-                       connection_id = hdr[0];
-               if (hdr[0] == connection_id) {
-                       if (pktlen < count) {
-                               if ((pktlen + fraglen - 2) > count) {
-                                       fraglen = count - pktlen;
-                               } else {
-                                       fraglen -= 2;
-                               }
-
-                               if ((status = dvb_ringbuffer_pkt_read_user(&ca->slot_info[slot].rx_buffer, idx, 2,
-                                                                     buf + pktlen, fraglen)) < 0) {
-                                       goto exit;
-                               }
-                               pktlen += fraglen;
-                       }
-
-                       if ((hdr[1] & 0x80) == 0)
-                               last_fragment = 1;
-                       dispose = 1;
-               }
-
-               idx2 = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen);
-               if (dispose)
-                       dvb_ringbuffer_pkt_dispose(&ca->slot_info[slot].rx_buffer, idx);
-               idx = idx2;
-               dispose = 0;
-       } while (!last_fragment);
-
-       hdr[0] = slot;
-       hdr[1] = connection_id;
-       status = copy_to_user(buf, hdr, 2);
-       if (status) {
-               status = -EFAULT;
-               goto exit;
-       }
-       status = pktlen;
-
-exit:
-       return status;
-}
-
-
-/**
- * Implementation of file open syscall.
- *
- * @param inode Inode concerned.
- * @param file File concerned.
- *
- * @return 0 on success, <0 on failure.
- */
-static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dvb_ca_private *ca = dvbdev->priv;
-       int err;
-       int i;
-
-       dprintk("%s\n", __func__);
-
-       if (!try_module_get(ca->pub->owner))
-               return -EIO;
-
-       err = dvb_generic_open(inode, file);
-       if (err < 0) {
-               module_put(ca->pub->owner);
-               return err;
-       }
-
-       for (i = 0; i < ca->slot_count; i++) {
-
-               if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) {
-                       if (ca->slot_info[i].rx_buffer.data != NULL) {
-                               /* it is safe to call this here without locks because
-                                * ca->open == 0. Data is not read in this case */
-                               dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer);
-                       }
-               }
-       }
-
-       ca->open = 1;
-       dvb_ca_en50221_thread_update_delay(ca);
-       dvb_ca_en50221_thread_wakeup(ca);
-
-       return 0;
-}
-
-
-/**
- * Implementation of file close syscall.
- *
- * @param inode Inode concerned.
- * @param file File concerned.
- *
- * @return 0 on success, <0 on failure.
- */
-static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dvb_ca_private *ca = dvbdev->priv;
-       int err;
-
-       dprintk("%s\n", __func__);
-
-       /* mark the CA device as closed */
-       ca->open = 0;
-       dvb_ca_en50221_thread_update_delay(ca);
-
-       err = dvb_generic_release(inode, file);
-
-       module_put(ca->pub->owner);
-
-       return err;
-}
-
-
-/**
- * Implementation of poll() syscall.
- *
- * @param file File concerned.
- * @param wait poll wait table.
- *
- * @return Standard poll mask.
- */
-static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table * wait)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dvb_ca_private *ca = dvbdev->priv;
-       unsigned int mask = 0;
-       int slot;
-       int result = 0;
-
-       dprintk("%s\n", __func__);
-
-       if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
-               mask |= POLLIN;
-       }
-
-       /* if there is something, return now */
-       if (mask)
-               return mask;
-
-       /* wait for something to happen */
-       poll_wait(file, &ca->wait_queue, wait);
-
-       if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) {
-               mask |= POLLIN;
-       }
-
-       return mask;
-}
-EXPORT_SYMBOL(dvb_ca_en50221_init);
-
-
-static const struct file_operations dvb_ca_fops = {
-       .owner = THIS_MODULE,
-       .read = dvb_ca_en50221_io_read,
-       .write = dvb_ca_en50221_io_write,
-       .unlocked_ioctl = dvb_ca_en50221_io_ioctl,
-       .open = dvb_ca_en50221_io_open,
-       .release = dvb_ca_en50221_io_release,
-       .poll = dvb_ca_en50221_io_poll,
-       .llseek = noop_llseek,
-};
-
-static struct dvb_device dvbdev_ca = {
-       .priv = NULL,
-       .users = 1,
-       .readers = 1,
-       .writers = 1,
-       .fops = &dvb_ca_fops,
-};
-
-
-/* ******************************************************************************** */
-/* Initialisation/shutdown functions */
-
-
-/**
- * Initialise a new DVB CA EN50221 interface device.
- *
- * @param dvb_adapter DVB adapter to attach the new CA device to.
- * @param ca The dvb_ca instance.
- * @param flags Flags describing the CA device (DVB_CA_FLAG_*).
- * @param slot_count Number of slots supported.
- *
- * @return 0 on success, nonzero on failure
- */
-int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
-                       struct dvb_ca_en50221 *pubca, int flags, int slot_count)
-{
-       int ret;
-       struct dvb_ca_private *ca = NULL;
-       int i;
-
-       dprintk("%s\n", __func__);
-
-       if (slot_count < 1)
-               return -EINVAL;
-
-       /* initialise the system data */
-       if ((ca = kzalloc(sizeof(struct dvb_ca_private), GFP_KERNEL)) == NULL) {
-               ret = -ENOMEM;
-               goto error;
-       }
-       ca->pub = pubca;
-       ca->flags = flags;
-       ca->slot_count = slot_count;
-       if ((ca->slot_info = kcalloc(slot_count, sizeof(struct dvb_ca_slot), GFP_KERNEL)) == NULL) {
-               ret = -ENOMEM;
-               goto error;
-       }
-       init_waitqueue_head(&ca->wait_queue);
-       ca->open = 0;
-       ca->wakeup = 0;
-       ca->next_read_slot = 0;
-       pubca->private = ca;
-
-       /* register the DVB device */
-       ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA);
-       if (ret)
-               goto error;
-
-       /* now initialise each slot */
-       for (i = 0; i < slot_count; i++) {
-               memset(&ca->slot_info[i], 0, sizeof(struct dvb_ca_slot));
-               ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE;
-               atomic_set(&ca->slot_info[i].camchange_count, 0);
-               ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED;
-               mutex_init(&ca->slot_info[i].slot_lock);
-       }
-
-       if (signal_pending(current)) {
-               ret = -EINTR;
-               goto error;
-       }
-       mb();
-
-       /* create a kthread for monitoring this CA device */
-       ca->thread = kthread_run(dvb_ca_en50221_thread, ca, "kdvb-ca-%i:%i",
-                                ca->dvbdev->adapter->num, ca->dvbdev->id);
-       if (IS_ERR(ca->thread)) {
-               ret = PTR_ERR(ca->thread);
-               printk("dvb_ca_init: failed to start kernel_thread (%d)\n",
-                       ret);
-               goto error;
-       }
-       return 0;
-
-error:
-       if (ca != NULL) {
-               if (ca->dvbdev != NULL)
-                       dvb_unregister_device(ca->dvbdev);
-               kfree(ca->slot_info);
-               kfree(ca);
-       }
-       pubca->private = NULL;
-       return ret;
-}
-EXPORT_SYMBOL(dvb_ca_en50221_release);
-
-
-
-/**
- * Release a DVB CA EN50221 interface device.
- *
- * @param ca_dev The dvb_device_t instance for the CA device.
- * @param ca The associated dvb_ca instance.
- */
-void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
-{
-       struct dvb_ca_private *ca = pubca->private;
-       int i;
-
-       dprintk("%s\n", __func__);
-
-       /* shutdown the thread if there was one */
-       kthread_stop(ca->thread);
-
-       for (i = 0; i < ca->slot_count; i++) {
-               dvb_ca_en50221_slot_shutdown(ca, i);
-               vfree(ca->slot_info[i].rx_buffer.data);
-       }
-       kfree(ca->slot_info);
-       dvb_unregister_device(ca->dvbdev);
-       kfree(ca);
-       pubca->private = NULL;
-}
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.h b/drivers/media/dvb/dvb-core/dvb_ca_en50221.h
deleted file mode 100644 (file)
index 7df2e14..0000000
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * dvb_ca.h: generic DVB functions for EN50221 CA interfaces
- *
- * Copyright (C) 2004 Andrew de Quincey
- *
- * 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 _DVB_CA_EN50221_H_
-#define _DVB_CA_EN50221_H_
-
-#include <linux/list.h>
-#include <linux/dvb/ca.h>
-
-#include "dvbdev.h"
-
-#define DVB_CA_EN50221_POLL_CAM_PRESENT        1
-#define DVB_CA_EN50221_POLL_CAM_CHANGED        2
-#define DVB_CA_EN50221_POLL_CAM_READY          4
-
-#define DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE      1
-#define DVB_CA_EN50221_FLAG_IRQ_FR             2
-#define DVB_CA_EN50221_FLAG_IRQ_DA             4
-
-#define DVB_CA_EN50221_CAMCHANGE_REMOVED               0
-#define DVB_CA_EN50221_CAMCHANGE_INSERTED              1
-
-
-
-/* Structure describing a CA interface */
-struct dvb_ca_en50221 {
-
-       /* the module owning this structure */
-       struct module* owner;
-
-       /* NOTE: the read_*, write_* and poll_slot_status functions will be
-        * called for different slots concurrently and need to use locks where
-        * and if appropriate. There will be no concurrent access to one slot.
-        */
-
-       /* functions for accessing attribute memory on the CAM */
-       int (*read_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address);
-       int (*write_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address, u8 value);
-
-       /* functions for accessing the control interface on the CAM */
-       int (*read_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address);
-       int (*write_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address, u8 value);
-
-       /* Functions for controlling slots */
-       int (*slot_reset)(struct dvb_ca_en50221* ca, int slot);
-       int (*slot_shutdown)(struct dvb_ca_en50221* ca, int slot);
-       int (*slot_ts_enable)(struct dvb_ca_en50221* ca, int slot);
-
-       /*
-       * Poll slot status.
-       * Only necessary if DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set
-       */
-       int (*poll_slot_status)(struct dvb_ca_en50221* ca, int slot, int open);
-
-       /* private data, used by caller */
-       void* data;
-
-       /* Opaque data used by the dvb_ca core. Do not modify! */
-       void* private;
-};
-
-
-
-
-/* ******************************************************************************** */
-/* Functions for reporting IRQ events */
-
-/**
- * A CAMCHANGE IRQ has occurred.
- *
- * @param ca CA instance.
- * @param slot Slot concerned.
- * @param change_type One of the DVB_CA_CAMCHANGE_* values
- */
-void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221* pubca, int slot, int change_type);
-
-/**
- * A CAMREADY IRQ has occurred.
- *
- * @param ca CA instance.
- * @param slot Slot concerned.
- */
-void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221* pubca, int slot);
-
-/**
- * An FR or a DA IRQ has occurred.
- *
- * @param ca CA instance.
- * @param slot Slot concerned.
- */
-void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221* ca, int slot);
-
-
-
-/* ******************************************************************************** */
-/* Initialisation/shutdown functions */
-
-/**
- * Initialise a new DVB CA device.
- *
- * @param dvb_adapter DVB adapter to attach the new CA device to.
- * @param ca The dvb_ca instance.
- * @param flags Flags describing the CA device (DVB_CA_EN50221_FLAG_*).
- * @param slot_count Number of slots supported.
- *
- * @return 0 on success, nonzero on failure
- */
-extern int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221* ca, int flags, int slot_count);
-
-/**
- * Release a DVB CA device.
- *
- * @param ca The associated dvb_ca instance.
- */
-extern void dvb_ca_en50221_release(struct dvb_ca_en50221* ca);
-
-
-
-#endif
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
deleted file mode 100644 (file)
index 17cb81f..0000000
+++ /dev/null
@@ -1,1318 +0,0 @@
-/*
- * dvb_demux.c - DVB kernel demux API
- *
- * Copyright (C) 2000-2001 Ralph  Metzler <ralph@convergence.de>
- *                    & Marcus Metzler <marcus@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 <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/string.h>
-#include <linux/crc32.h>
-#include <asm/uaccess.h>
-#include <asm/div64.h>
-
-#include "dvb_demux.h"
-
-#define NOBUFS
-/*
-** #define DVB_DEMUX_SECTION_LOSS_LOG to monitor payload loss in the syslog
-*/
-// #define DVB_DEMUX_SECTION_LOSS_LOG
-
-static int dvb_demux_tscheck;
-module_param(dvb_demux_tscheck, int, 0644);
-MODULE_PARM_DESC(dvb_demux_tscheck,
-               "enable transport stream continuity and TEI check");
-
-static int dvb_demux_speedcheck;
-module_param(dvb_demux_speedcheck, int, 0644);
-MODULE_PARM_DESC(dvb_demux_speedcheck,
-               "enable transport stream speed check");
-
-static int dvb_demux_feed_err_pkts = 1;
-module_param(dvb_demux_feed_err_pkts, int, 0644);
-MODULE_PARM_DESC(dvb_demux_feed_err_pkts,
-                "when set to 0, drop packets with the TEI bit set (1 by default)");
-
-#define dprintk_tscheck(x...) do {                              \
-               if (dvb_demux_tscheck && printk_ratelimit())    \
-                       printk(x);                              \
-       } while (0)
-
-/******************************************************************************
- * static inlined helper functions
- ******************************************************************************/
-
-static inline u16 section_length(const u8 *buf)
-{
-       return 3 + ((buf[1] & 0x0f) << 8) + buf[2];
-}
-
-static inline u16 ts_pid(const u8 *buf)
-{
-       return ((buf[1] & 0x1f) << 8) + buf[2];
-}
-
-static inline u8 payload(const u8 *tsp)
-{
-       if (!(tsp[3] & 0x10))   // no payload?
-               return 0;
-
-       if (tsp[3] & 0x20) {    // adaptation field?
-               if (tsp[4] > 183)       // corrupted data?
-                       return 0;
-               else
-                       return 184 - 1 - tsp[4];
-       }
-
-       return 184;
-}
-
-static u32 dvb_dmx_crc32(struct dvb_demux_feed *f, const u8 *src, size_t len)
-{
-       return (f->feed.sec.crc_val = crc32_be(f->feed.sec.crc_val, src, len));
-}
-
-static void dvb_dmx_memcopy(struct dvb_demux_feed *f, u8 *d, const u8 *s,
-                           size_t len)
-{
-       memcpy(d, s, len);
-}
-
-/******************************************************************************
- * Software filter functions
- ******************************************************************************/
-
-static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
-                                          const u8 *buf)
-{
-       int count = payload(buf);
-       int p;
-       //int ccok;
-       //u8 cc;
-
-       if (count == 0)
-               return -1;
-
-       p = 188 - count;
-
-       /*
-       cc = buf[3] & 0x0f;
-       ccok = ((feed->cc + 1) & 0x0f) == cc;
-       feed->cc = cc;
-       if (!ccok)
-               printk("missed packet!\n");
-       */
-
-       if (buf[1] & 0x40)      // PUSI ?
-               feed->peslen = 0xfffa;
-
-       feed->peslen += count;
-
-       return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK);
-}
-
-static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
-                                         struct dvb_demux_filter *f)
-{
-       u8 neq = 0;
-       int i;
-
-       for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
-               u8 xor = f->filter.filter_value[i] ^ feed->feed.sec.secbuf[i];
-
-               if (f->maskandmode[i] & xor)
-                       return 0;
-
-               neq |= f->maskandnotmode[i] & xor;
-       }
-
-       if (f->doneq && !neq)
-               return 0;
-
-       return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen,
-                           NULL, 0, &f->filter, DMX_OK);
-}
-
-static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
-{
-       struct dvb_demux *demux = feed->demux;
-       struct dvb_demux_filter *f = feed->filter;
-       struct dmx_section_feed *sec = &feed->feed.sec;
-       int section_syntax_indicator;
-
-       if (!sec->is_filtering)
-               return 0;
-
-       if (!f)
-               return 0;
-
-       if (sec->check_crc) {
-               section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0);
-               if (section_syntax_indicator &&
-                   demux->check_crc32(feed, sec->secbuf, sec->seclen))
-                       return -1;
-       }
-
-       do {
-               if (dvb_dmx_swfilter_sectionfilter(feed, f) < 0)
-                       return -1;
-       } while ((f = f->next) && sec->is_filtering);
-
-       sec->seclen = 0;
-
-       return 0;
-}
-
-static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
-{
-       struct dmx_section_feed *sec = &feed->feed.sec;
-
-#ifdef DVB_DEMUX_SECTION_LOSS_LOG
-       if (sec->secbufp < sec->tsfeedp) {
-               int i, n = sec->tsfeedp - sec->secbufp;
-
-               /*
-                * Section padding is done with 0xff bytes entirely.
-                * Due to speed reasons, we won't check all of them
-                * but just first and last.
-                */
-               if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) {
-                       printk("dvb_demux.c section ts padding loss: %d/%d\n",
-                              n, sec->tsfeedp);
-                       printk("dvb_demux.c pad data:");
-                       for (i = 0; i < n; i++)
-                               printk(" %02x", sec->secbuf[i]);
-                       printk("\n");
-               }
-       }
-#endif
-
-       sec->tsfeedp = sec->secbufp = sec->seclen = 0;
-       sec->secbuf = sec->secbuf_base;
-}
-
-/*
- * Losless Section Demux 1.4.1 by Emard
- * Valsecchi Patrick:
- *  - middle of section A  (no PUSI)
- *  - end of section A and start of section B
- *    (with PUSI pointing to the start of the second section)
- *
- *  In this case, without feed->pusi_seen you'll receive a garbage section
- *  consisting of the end of section A. Basically because tsfeedp
- *  is incemented and the use=0 condition is not raised
- *  when the second packet arrives.
- *
- * Fix:
- * when demux is started, let feed->pusi_seen = 0 to
- * prevent initial feeding of garbage from the end of
- * previous section. When you for the first time see PUSI=1
- * then set feed->pusi_seen = 1
- */
-static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
-                                             const u8 *buf, u8 len)
-{
-       struct dvb_demux *demux = feed->demux;
-       struct dmx_section_feed *sec = &feed->feed.sec;
-       u16 limit, seclen, n;
-
-       if (sec->tsfeedp >= DMX_MAX_SECFEED_SIZE)
-               return 0;
-
-       if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) {
-#ifdef DVB_DEMUX_SECTION_LOSS_LOG
-               printk("dvb_demux.c section buffer full loss: %d/%d\n",
-                      sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE,
-                      DMX_MAX_SECFEED_SIZE);
-#endif
-               len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp;
-       }
-
-       if (len <= 0)
-               return 0;
-
-       demux->memcopy(feed, sec->secbuf_base + sec->tsfeedp, buf, len);
-       sec->tsfeedp += len;
-
-       /*
-        * Dump all the sections we can find in the data (Emard)
-        */
-       limit = sec->tsfeedp;
-       if (limit > DMX_MAX_SECFEED_SIZE)
-               return -1;      /* internal error should never happen */
-
-       /* to be sure always set secbuf */
-       sec->secbuf = sec->secbuf_base + sec->secbufp;
-
-       for (n = 0; sec->secbufp + 2 < limit; n++) {
-               seclen = section_length(sec->secbuf);
-               if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE
-                   || seclen + sec->secbufp > limit)
-                       return 0;
-               sec->seclen = seclen;
-               sec->crc_val = ~0;
-               /* dump [secbuf .. secbuf+seclen) */
-               if (feed->pusi_seen)
-                       dvb_dmx_swfilter_section_feed(feed);
-#ifdef DVB_DEMUX_SECTION_LOSS_LOG
-               else
-                       printk("dvb_demux.c pusi not seen, discarding section data\n");
-#endif
-               sec->secbufp += seclen; /* secbufp and secbuf moving together is */
-               sec->secbuf += seclen;  /* redundant but saves pointer arithmetic */
-       }
-
-       return 0;
-}
-
-static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
-                                          const u8 *buf)
-{
-       u8 p, count;
-       int ccok, dc_i = 0;
-       u8 cc;
-
-       count = payload(buf);
-
-       if (count == 0)         /* count == 0 if no payload or out of range */
-               return -1;
-
-       p = 188 - count;        /* payload start */
-
-       cc = buf[3] & 0x0f;
-       ccok = ((feed->cc + 1) & 0x0f) == cc;
-       feed->cc = cc;
-
-       if (buf[3] & 0x20) {
-               /* adaption field present, check for discontinuity_indicator */
-               if ((buf[4] > 0) && (buf[5] & 0x80))
-                       dc_i = 1;
-       }
-
-       if (!ccok || dc_i) {
-#ifdef DVB_DEMUX_SECTION_LOSS_LOG
-               printk("dvb_demux.c discontinuity detected %d bytes lost\n",
-                      count);
-               /*
-                * those bytes under sume circumstances will again be reported
-                * in the following dvb_dmx_swfilter_section_new
-                */
-#endif
-               /*
-                * Discontinuity detected. Reset pusi_seen = 0 to
-                * stop feeding of suspicious data until next PUSI=1 arrives
-                */
-               feed->pusi_seen = 0;
-               dvb_dmx_swfilter_section_new(feed);
-       }
-
-       if (buf[1] & 0x40) {
-               /* PUSI=1 (is set), section boundary is here */
-               if (count > 1 && buf[p] < count) {
-                       const u8 *before = &buf[p + 1];
-                       u8 before_len = buf[p];
-                       const u8 *after = &before[before_len];
-                       u8 after_len = count - 1 - before_len;
-
-                       dvb_dmx_swfilter_section_copy_dump(feed, before,
-                                                          before_len);
-                       /* before start of new section, set pusi_seen = 1 */
-                       feed->pusi_seen = 1;
-                       dvb_dmx_swfilter_section_new(feed);
-                       dvb_dmx_swfilter_section_copy_dump(feed, after,
-                                                          after_len);
-               }
-#ifdef DVB_DEMUX_SECTION_LOSS_LOG
-               else if (count > 0)
-                       printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count);
-#endif
-       } else {
-               /* PUSI=0 (is not set), no section boundary */
-               dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count);
-       }
-
-       return 0;
-}
-
-static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
-                                               const u8 *buf)
-{
-       switch (feed->type) {
-       case DMX_TYPE_TS:
-               if (!feed->feed.ts.is_filtering)
-                       break;
-               if (feed->ts_type & TS_PACKET) {
-                       if (feed->ts_type & TS_PAYLOAD_ONLY)
-                               dvb_dmx_swfilter_payload(feed, buf);
-                       else
-                               feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
-                                           DMX_OK);
-               }
-               if (feed->ts_type & TS_DECODER)
-                       if (feed->demux->write_to_decoder)
-                               feed->demux->write_to_decoder(feed, buf, 188);
-               break;
-
-       case DMX_TYPE_SEC:
-               if (!feed->feed.sec.is_filtering)
-                       break;
-               if (dvb_dmx_swfilter_section_packet(feed, buf) < 0)
-                       feed->feed.sec.seclen = feed->feed.sec.secbufp = 0;
-               break;
-
-       default:
-               break;
-       }
-}
-
-#define DVR_FEED(f)                                                    \
-       (((f)->type == DMX_TYPE_TS) &&                                  \
-       ((f)->feed.ts.is_filtering) &&                                  \
-       (((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET))
-
-static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
-{
-       struct dvb_demux_feed *feed;
-       u16 pid = ts_pid(buf);
-       int dvr_done = 0;
-
-       if (dvb_demux_speedcheck) {
-               struct timespec cur_time, delta_time;
-               u64 speed_bytes, speed_timedelta;
-
-               demux->speed_pkts_cnt++;
-
-               /* show speed every SPEED_PKTS_INTERVAL packets */
-               if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) {
-                       cur_time = current_kernel_time();
-
-                       if (demux->speed_last_time.tv_sec != 0 &&
-                                       demux->speed_last_time.tv_nsec != 0) {
-                               delta_time = timespec_sub(cur_time,
-                                               demux->speed_last_time);
-                               speed_bytes = (u64)demux->speed_pkts_cnt
-                                       * 188 * 8;
-                               /* convert to 1024 basis */
-                               speed_bytes = 1000 * div64_u64(speed_bytes,
-                                               1024);
-                               speed_timedelta =
-                                       (u64)timespec_to_ns(&delta_time);
-                               speed_timedelta = div64_u64(speed_timedelta,
-                                               1000000); /* nsec -> usec */
-                               printk(KERN_INFO "TS speed %llu Kbits/sec \n",
-                                               div64_u64(speed_bytes,
-                                                       speed_timedelta));
-                       };
-
-                       demux->speed_last_time = cur_time;
-                       demux->speed_pkts_cnt = 0;
-               };
-       };
-
-       if (buf[1] & 0x80) {
-               dprintk_tscheck("TEI detected. "
-                               "PID=0x%x data1=0x%x\n",
-                               pid, buf[1]);
-               /* data in this packet cant be trusted - drop it unless
-                * module option dvb_demux_feed_err_pkts is set */
-               if (!dvb_demux_feed_err_pkts)
-                       return;
-       } else /* if TEI bit is set, pid may be wrong- skip pkt counter */
-       if (demux->cnt_storage && dvb_demux_tscheck) {
-               /* check pkt counter */
-               if (pid < MAX_PID) {
-                       if ((buf[3] & 0xf) != demux->cnt_storage[pid])
-                               dprintk_tscheck("TS packet counter mismatch. "
-                                               "PID=0x%x expected 0x%x "
-                                               "got 0x%x\n",
-                                               pid, demux->cnt_storage[pid],
-                                               buf[3] & 0xf);
-
-                       demux->cnt_storage[pid] = ((buf[3] & 0xf) + 1)&0xf;
-               };
-               /* end check */
-       };
-
-       list_for_each_entry(feed, &demux->feed_list, list_head) {
-               if ((feed->pid != pid) && (feed->pid != 0x2000))
-                       continue;
-
-               /* copy each packet only once to the dvr device, even
-                * if a PID is in multiple filters (e.g. video + PCR) */
-               if ((DVR_FEED(feed)) && (dvr_done++))
-                       continue;
-
-               if (feed->pid == pid)
-                       dvb_dmx_swfilter_packet_type(feed, buf);
-               else if (feed->pid == 0x2000)
-                       feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK);
-       }
-}
-
-void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
-                             size_t count)
-{
-       spin_lock(&demux->lock);
-
-       while (count--) {
-               if (buf[0] == 0x47)
-                       dvb_dmx_swfilter_packet(demux, buf);
-               buf += 188;
-       }
-
-       spin_unlock(&demux->lock);
-}
-
-EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
-
-static inline int find_next_packet(const u8 *buf, int pos, size_t count,
-                                  const int pktsize)
-{
-       int start = pos, lost;
-
-       while (pos < count) {
-               if (buf[pos] == 0x47 ||
-                   (pktsize == 204 && buf[pos] == 0xB8))
-                       break;
-               pos++;
-       }
-
-       lost = pos - start;
-       if (lost) {
-               /* This garbage is part of a valid packet? */
-               int backtrack = pos - pktsize;
-               if (backtrack >= 0 && (buf[backtrack] == 0x47 ||
-                   (pktsize == 204 && buf[backtrack] == 0xB8)))
-                       return backtrack;
-       }
-
-       return pos;
-}
-
-/* Filter all pktsize= 188 or 204 sized packets and skip garbage. */
-static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf,
-               size_t count, const int pktsize)
-{
-       int p = 0, i, j;
-       const u8 *q;
-
-       spin_lock(&demux->lock);
-
-       if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */
-               i = demux->tsbufp;
-               j = pktsize - i;
-               if (count < j) {
-                       memcpy(&demux->tsbuf[i], buf, count);
-                       demux->tsbufp += count;
-                       goto bailout;
-               }
-               memcpy(&demux->tsbuf[i], buf, j);
-               if (demux->tsbuf[0] == 0x47) /* double check */
-                       dvb_dmx_swfilter_packet(demux, demux->tsbuf);
-               demux->tsbufp = 0;
-               p += j;
-       }
-
-       while (1) {
-               p = find_next_packet(buf, p, count, pktsize);
-               if (p >= count)
-                       break;
-               if (count - p < pktsize)
-                       break;
-
-               q = &buf[p];
-
-               if (pktsize == 204 && (*q == 0xB8)) {
-                       memcpy(demux->tsbuf, q, 188);
-                       demux->tsbuf[0] = 0x47;
-                       q = demux->tsbuf;
-               }
-               dvb_dmx_swfilter_packet(demux, q);
-               p += pktsize;
-       }
-
-       i = count - p;
-       if (i) {
-               memcpy(demux->tsbuf, &buf[p], i);
-               demux->tsbufp = i;
-               if (pktsize == 204 && demux->tsbuf[0] == 0xB8)
-                       demux->tsbuf[0] = 0x47;
-       }
-
-bailout:
-       spin_unlock(&demux->lock);
-}
-
-void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
-{
-       _dvb_dmx_swfilter(demux, buf, count, 188);
-}
-EXPORT_SYMBOL(dvb_dmx_swfilter);
-
-void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
-{
-       _dvb_dmx_swfilter(demux, buf, count, 204);
-}
-EXPORT_SYMBOL(dvb_dmx_swfilter_204);
-
-void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
-{
-       spin_lock(&demux->lock);
-
-       demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts, DMX_OK);
-
-       spin_unlock(&demux->lock);
-}
-EXPORT_SYMBOL(dvb_dmx_swfilter_raw);
-
-static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux)
-{
-       int i;
-
-       for (i = 0; i < demux->filternum; i++)
-               if (demux->filter[i].state == DMX_STATE_FREE)
-                       break;
-
-       if (i == demux->filternum)
-               return NULL;
-
-       demux->filter[i].state = DMX_STATE_ALLOCATED;
-
-       return &demux->filter[i];
-}
-
-static struct dvb_demux_feed *dvb_dmx_feed_alloc(struct dvb_demux *demux)
-{
-       int i;
-
-       for (i = 0; i < demux->feednum; i++)
-               if (demux->feed[i].state == DMX_STATE_FREE)
-                       break;
-
-       if (i == demux->feednum)
-               return NULL;
-
-       demux->feed[i].state = DMX_STATE_ALLOCATED;
-
-       return &demux->feed[i];
-}
-
-static int dvb_demux_feed_find(struct dvb_demux_feed *feed)
-{
-       struct dvb_demux_feed *entry;
-
-       list_for_each_entry(entry, &feed->demux->feed_list, list_head)
-               if (entry == feed)
-                       return 1;
-
-       return 0;
-}
-
-static void dvb_demux_feed_add(struct dvb_demux_feed *feed)
-{
-       spin_lock_irq(&feed->demux->lock);
-       if (dvb_demux_feed_find(feed)) {
-               printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n",
-                      __func__, feed->type, feed->state, feed->pid);
-               goto out;
-       }
-
-       list_add(&feed->list_head, &feed->demux->feed_list);
-out:
-       spin_unlock_irq(&feed->demux->lock);
-}
-
-static void dvb_demux_feed_del(struct dvb_demux_feed *feed)
-{
-       spin_lock_irq(&feed->demux->lock);
-       if (!(dvb_demux_feed_find(feed))) {
-               printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n",
-                      __func__, feed->type, feed->state, feed->pid);
-               goto out;
-       }
-
-       list_del(&feed->list_head);
-out:
-       spin_unlock_irq(&feed->demux->lock);
-}
-
-static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type,
-                          enum dmx_ts_pes pes_type,
-                          size_t circular_buffer_size, struct timespec timeout)
-{
-       struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
-       struct dvb_demux *demux = feed->demux;
-
-       if (pid > DMX_MAX_PID)
-               return -EINVAL;
-
-       if (mutex_lock_interruptible(&demux->mutex))
-               return -ERESTARTSYS;
-
-       if (ts_type & TS_DECODER) {
-               if (pes_type >= DMX_TS_PES_OTHER) {
-                       mutex_unlock(&demux->mutex);
-                       return -EINVAL;
-               }
-
-               if (demux->pesfilter[pes_type] &&
-                   demux->pesfilter[pes_type] != feed) {
-                       mutex_unlock(&demux->mutex);
-                       return -EINVAL;
-               }
-
-               demux->pesfilter[pes_type] = feed;
-               demux->pids[pes_type] = pid;
-       }
-
-       dvb_demux_feed_add(feed);
-
-       feed->pid = pid;
-       feed->buffer_size = circular_buffer_size;
-       feed->timeout = timeout;
-       feed->ts_type = ts_type;
-       feed->pes_type = pes_type;
-
-       if (feed->buffer_size) {
-#ifdef NOBUFS
-               feed->buffer = NULL;
-#else
-               feed->buffer = vmalloc(feed->buffer_size);
-               if (!feed->buffer) {
-                       mutex_unlock(&demux->mutex);
-                       return -ENOMEM;
-               }
-#endif
-       }
-
-       feed->state = DMX_STATE_READY;
-       mutex_unlock(&demux->mutex);
-
-       return 0;
-}
-
-static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed)
-{
-       struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
-       struct dvb_demux *demux = feed->demux;
-       int ret;
-
-       if (mutex_lock_interruptible(&demux->mutex))
-               return -ERESTARTSYS;
-
-       if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) {
-               mutex_unlock(&demux->mutex);
-               return -EINVAL;
-       }
-
-       if (!demux->start_feed) {
-               mutex_unlock(&demux->mutex);
-               return -ENODEV;
-       }
-
-       if ((ret = demux->start_feed(feed)) < 0) {
-               mutex_unlock(&demux->mutex);
-               return ret;
-       }
-
-       spin_lock_irq(&demux->lock);
-       ts_feed->is_filtering = 1;
-       feed->state = DMX_STATE_GO;
-       spin_unlock_irq(&demux->lock);
-       mutex_unlock(&demux->mutex);
-
-       return 0;
-}
-
-static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed)
-{
-       struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
-       struct dvb_demux *demux = feed->demux;
-       int ret;
-
-       mutex_lock(&demux->mutex);
-
-       if (feed->state < DMX_STATE_GO) {
-               mutex_unlock(&demux->mutex);
-               return -EINVAL;
-       }
-
-       if (!demux->stop_feed) {
-               mutex_unlock(&demux->mutex);
-               return -ENODEV;
-       }
-
-       ret = demux->stop_feed(feed);
-
-       spin_lock_irq(&demux->lock);
-       ts_feed->is_filtering = 0;
-       feed->state = DMX_STATE_ALLOCATED;
-       spin_unlock_irq(&demux->lock);
-       mutex_unlock(&demux->mutex);
-
-       return ret;
-}
-
-static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
-                                  struct dmx_ts_feed **ts_feed,
-                                  dmx_ts_cb callback)
-{
-       struct dvb_demux *demux = (struct dvb_demux *)dmx;
-       struct dvb_demux_feed *feed;
-
-       if (mutex_lock_interruptible(&demux->mutex))
-               return -ERESTARTSYS;
-
-       if (!(feed = dvb_dmx_feed_alloc(demux))) {
-               mutex_unlock(&demux->mutex);
-               return -EBUSY;
-       }
-
-       feed->type = DMX_TYPE_TS;
-       feed->cb.ts = callback;
-       feed->demux = demux;
-       feed->pid = 0xffff;
-       feed->peslen = 0xfffa;
-       feed->buffer = NULL;
-
-       (*ts_feed) = &feed->feed.ts;
-       (*ts_feed)->parent = dmx;
-       (*ts_feed)->priv = NULL;
-       (*ts_feed)->is_filtering = 0;
-       (*ts_feed)->start_filtering = dmx_ts_feed_start_filtering;
-       (*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering;
-       (*ts_feed)->set = dmx_ts_feed_set;
-
-       if (!(feed->filter = dvb_dmx_filter_alloc(demux))) {
-               feed->state = DMX_STATE_FREE;
-               mutex_unlock(&demux->mutex);
-               return -EBUSY;
-       }
-
-       feed->filter->type = DMX_TYPE_TS;
-       feed->filter->feed = feed;
-       feed->filter->state = DMX_STATE_READY;
-
-       mutex_unlock(&demux->mutex);
-
-       return 0;
-}
-
-static int dvbdmx_release_ts_feed(struct dmx_demux *dmx,
-                                 struct dmx_ts_feed *ts_feed)
-{
-       struct dvb_demux *demux = (struct dvb_demux *)dmx;
-       struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed;
-
-       mutex_lock(&demux->mutex);
-
-       if (feed->state == DMX_STATE_FREE) {
-               mutex_unlock(&demux->mutex);
-               return -EINVAL;
-       }
-#ifndef NOBUFS
-       vfree(feed->buffer);
-       feed->buffer = NULL;
-#endif
-
-       feed->state = DMX_STATE_FREE;
-       feed->filter->state = DMX_STATE_FREE;
-
-       dvb_demux_feed_del(feed);
-
-       feed->pid = 0xffff;
-
-       if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER)
-               demux->pesfilter[feed->pes_type] = NULL;
-
-       mutex_unlock(&demux->mutex);
-       return 0;
-}
-
-/******************************************************************************
- * dmx_section_feed API calls
- ******************************************************************************/
-
-static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed,
-                                           struct dmx_section_filter **filter)
-{
-       struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
-       struct dvb_demux *dvbdemux = dvbdmxfeed->demux;
-       struct dvb_demux_filter *dvbdmxfilter;
-
-       if (mutex_lock_interruptible(&dvbdemux->mutex))
-               return -ERESTARTSYS;
-
-       dvbdmxfilter = dvb_dmx_filter_alloc(dvbdemux);
-       if (!dvbdmxfilter) {
-               mutex_unlock(&dvbdemux->mutex);
-               return -EBUSY;
-       }
-
-       spin_lock_irq(&dvbdemux->lock);
-       *filter = &dvbdmxfilter->filter;
-       (*filter)->parent = feed;
-       (*filter)->priv = NULL;
-       dvbdmxfilter->feed = dvbdmxfeed;
-       dvbdmxfilter->type = DMX_TYPE_SEC;
-       dvbdmxfilter->state = DMX_STATE_READY;
-       dvbdmxfilter->next = dvbdmxfeed->filter;
-       dvbdmxfeed->filter = dvbdmxfilter;
-       spin_unlock_irq(&dvbdemux->lock);
-
-       mutex_unlock(&dvbdemux->mutex);
-       return 0;
-}
-
-static int dmx_section_feed_set(struct dmx_section_feed *feed,
-                               u16 pid, size_t circular_buffer_size,
-                               int check_crc)
-{
-       struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
-       struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-
-       if (pid > 0x1fff)
-               return -EINVAL;
-
-       if (mutex_lock_interruptible(&dvbdmx->mutex))
-               return -ERESTARTSYS;
-
-       dvb_demux_feed_add(dvbdmxfeed);
-
-       dvbdmxfeed->pid = pid;
-       dvbdmxfeed->buffer_size = circular_buffer_size;
-       dvbdmxfeed->feed.sec.check_crc = check_crc;
-
-#ifdef NOBUFS
-       dvbdmxfeed->buffer = NULL;
-#else
-       dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size);
-       if (!dvbdmxfeed->buffer) {
-               mutex_unlock(&dvbdmx->mutex);
-               return -ENOMEM;
-       }
-#endif
-
-       dvbdmxfeed->state = DMX_STATE_READY;
-       mutex_unlock(&dvbdmx->mutex);
-       return 0;
-}
-
-static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed)
-{
-       int i;
-       struct dvb_demux_filter *f;
-       struct dmx_section_filter *sf;
-       u8 mask, mode, doneq;
-
-       if (!(f = dvbdmxfeed->filter))
-               return;
-       do {
-               sf = &f->filter;
-               doneq = 0;
-               for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
-                       mode = sf->filter_mode[i];
-                       mask = sf->filter_mask[i];
-                       f->maskandmode[i] = mask & mode;
-                       doneq |= f->maskandnotmode[i] = mask & ~mode;
-               }
-               f->doneq = doneq ? 1 : 0;
-       } while ((f = f->next));
-}
-
-static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
-{
-       struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
-       struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-       int ret;
-
-       if (mutex_lock_interruptible(&dvbdmx->mutex))
-               return -ERESTARTSYS;
-
-       if (feed->is_filtering) {
-               mutex_unlock(&dvbdmx->mutex);
-               return -EBUSY;
-       }
-
-       if (!dvbdmxfeed->filter) {
-               mutex_unlock(&dvbdmx->mutex);
-               return -EINVAL;
-       }
-
-       dvbdmxfeed->feed.sec.tsfeedp = 0;
-       dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
-       dvbdmxfeed->feed.sec.secbufp = 0;
-       dvbdmxfeed->feed.sec.seclen = 0;
-
-       if (!dvbdmx->start_feed) {
-               mutex_unlock(&dvbdmx->mutex);
-               return -ENODEV;
-       }
-
-       prepare_secfilters(dvbdmxfeed);
-
-       if ((ret = dvbdmx->start_feed(dvbdmxfeed)) < 0) {
-               mutex_unlock(&dvbdmx->mutex);
-               return ret;
-       }
-
-       spin_lock_irq(&dvbdmx->lock);
-       feed->is_filtering = 1;
-       dvbdmxfeed->state = DMX_STATE_GO;
-       spin_unlock_irq(&dvbdmx->lock);
-
-       mutex_unlock(&dvbdmx->mutex);
-       return 0;
-}
-
-static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed)
-{
-       struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
-       struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-       int ret;
-
-       mutex_lock(&dvbdmx->mutex);
-
-       if (!dvbdmx->stop_feed) {
-               mutex_unlock(&dvbdmx->mutex);
-               return -ENODEV;
-       }
-
-       ret = dvbdmx->stop_feed(dvbdmxfeed);
-
-       spin_lock_irq(&dvbdmx->lock);
-       dvbdmxfeed->state = DMX_STATE_READY;
-       feed->is_filtering = 0;
-       spin_unlock_irq(&dvbdmx->lock);
-
-       mutex_unlock(&dvbdmx->mutex);
-       return ret;
-}
-
-static int dmx_section_feed_release_filter(struct dmx_section_feed *feed,
-                                          struct dmx_section_filter *filter)
-{
-       struct dvb_demux_filter *dvbdmxfilter = (struct dvb_demux_filter *)filter, *f;
-       struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
-       struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
-
-       mutex_lock(&dvbdmx->mutex);
-
-       if (dvbdmxfilter->feed != dvbdmxfeed) {
-               mutex_unlock(&dvbdmx->mutex);
-               return -EINVAL;
-       }
-
-       if (feed->is_filtering)
-               feed->stop_filtering(feed);
-
-       spin_lock_irq(&dvbdmx->lock);
-       f = dvbdmxfeed->filter;
-
-       if (f == dvbdmxfilter) {
-               dvbdmxfeed->filter = dvbdmxfilter->next;
-       } else {
-               while (f->next != dvbdmxfilter)
-                       f = f->next;
-               f->next = f->next->next;
-       }
-
-       dvbdmxfilter->state = DMX_STATE_FREE;
-       spin_unlock_irq(&dvbdmx->lock);
-       mutex_unlock(&dvbdmx->mutex);
-       return 0;
-}
-
-static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
-                                       struct dmx_section_feed **feed,
-                                       dmx_section_cb callback)
-{
-       struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
-       struct dvb_demux_feed *dvbdmxfeed;
-
-       if (mutex_lock_interruptible(&dvbdmx->mutex))
-               return -ERESTARTSYS;
-
-       if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) {
-               mutex_unlock(&dvbdmx->mutex);
-               return -EBUSY;
-       }
-
-       dvbdmxfeed->type = DMX_TYPE_SEC;
-       dvbdmxfeed->cb.sec = callback;
-       dvbdmxfeed->demux = dvbdmx;
-       dvbdmxfeed->pid = 0xffff;
-       dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
-       dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0;
-       dvbdmxfeed->feed.sec.tsfeedp = 0;
-       dvbdmxfeed->filter = NULL;
-       dvbdmxfeed->buffer = NULL;
-
-       (*feed) = &dvbdmxfeed->feed.sec;
-       (*feed)->is_filtering = 0;
-       (*feed)->parent = demux;
-       (*feed)->priv = NULL;
-
-       (*feed)->set = dmx_section_feed_set;
-       (*feed)->allocate_filter = dmx_section_feed_allocate_filter;
-       (*feed)->start_filtering = dmx_section_feed_start_filtering;
-       (*feed)->stop_filtering = dmx_section_feed_stop_filtering;
-       (*feed)->release_filter = dmx_section_feed_release_filter;
-
-       mutex_unlock(&dvbdmx->mutex);
-       return 0;
-}
-
-static int dvbdmx_release_section_feed(struct dmx_demux *demux,
-                                      struct dmx_section_feed *feed)
-{
-       struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed;
-       struct dvb_demux *dvbdmx = (struct dvb_demux *)demux;
-
-       mutex_lock(&dvbdmx->mutex);
-
-       if (dvbdmxfeed->state == DMX_STATE_FREE) {
-               mutex_unlock(&dvbdmx->mutex);
-               return -EINVAL;
-       }
-#ifndef NOBUFS
-       vfree(dvbdmxfeed->buffer);
-       dvbdmxfeed->buffer = NULL;
-#endif
-       dvbdmxfeed->state = DMX_STATE_FREE;
-
-       dvb_demux_feed_del(dvbdmxfeed);
-
-       dvbdmxfeed->pid = 0xffff;
-
-       mutex_unlock(&dvbdmx->mutex);
-       return 0;
-}
-
-/******************************************************************************
- * dvb_demux kernel data API calls
- ******************************************************************************/
-
-static int dvbdmx_open(struct dmx_demux *demux)
-{
-       struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-
-       if (dvbdemux->users >= MAX_DVB_DEMUX_USERS)
-               return -EUSERS;
-
-       dvbdemux->users++;
-       return 0;
-}
-
-static int dvbdmx_close(struct dmx_demux *demux)
-{
-       struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-
-       if (dvbdemux->users == 0)
-               return -ENODEV;
-
-       dvbdemux->users--;
-       //FIXME: release any unneeded resources if users==0
-       return 0;
-}
-
-static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count)
-{
-       struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-       void *p;
-
-       if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
-               return -EINVAL;
-
-       p = memdup_user(buf, count);
-       if (IS_ERR(p))
-               return PTR_ERR(p);
-       if (mutex_lock_interruptible(&dvbdemux->mutex)) {
-               kfree(p);
-               return -ERESTARTSYS;
-       }
-       dvb_dmx_swfilter(dvbdemux, p, count);
-       kfree(p);
-       mutex_unlock(&dvbdemux->mutex);
-
-       if (signal_pending(current))
-               return -EINTR;
-       return count;
-}
-
-static int dvbdmx_add_frontend(struct dmx_demux *demux,
-                              struct dmx_frontend *frontend)
-{
-       struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-       struct list_head *head = &dvbdemux->frontend_list;
-
-       list_add(&(frontend->connectivity_list), head);
-
-       return 0;
-}
-
-static int dvbdmx_remove_frontend(struct dmx_demux *demux,
-                                 struct dmx_frontend *frontend)
-{
-       struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-       struct list_head *pos, *n, *head = &dvbdemux->frontend_list;
-
-       list_for_each_safe(pos, n, head) {
-               if (DMX_FE_ENTRY(pos) == frontend) {
-                       list_del(pos);
-                       return 0;
-               }
-       }
-
-       return -ENODEV;
-}
-
-static struct list_head *dvbdmx_get_frontends(struct dmx_demux *demux)
-{
-       struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-
-       if (list_empty(&dvbdemux->frontend_list))
-               return NULL;
-
-       return &dvbdemux->frontend_list;
-}
-
-static int dvbdmx_connect_frontend(struct dmx_demux *demux,
-                                  struct dmx_frontend *frontend)
-{
-       struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-
-       if (demux->frontend)
-               return -EINVAL;
-
-       mutex_lock(&dvbdemux->mutex);
-
-       demux->frontend = frontend;
-       mutex_unlock(&dvbdemux->mutex);
-       return 0;
-}
-
-static int dvbdmx_disconnect_frontend(struct dmx_demux *demux)
-{
-       struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-
-       mutex_lock(&dvbdemux->mutex);
-
-       demux->frontend = NULL;
-       mutex_unlock(&dvbdemux->mutex);
-       return 0;
-}
-
-static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 * pids)
-{
-       struct dvb_demux *dvbdemux = (struct dvb_demux *)demux;
-
-       memcpy(pids, dvbdemux->pids, 5 * sizeof(u16));
-       return 0;
-}
-
-int dvb_dmx_init(struct dvb_demux *dvbdemux)
-{
-       int i;
-       struct dmx_demux *dmx = &dvbdemux->dmx;
-
-       dvbdemux->cnt_storage = NULL;
-       dvbdemux->users = 0;
-       dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter));
-
-       if (!dvbdemux->filter)
-               return -ENOMEM;
-
-       dvbdemux->feed = vmalloc(dvbdemux->feednum * sizeof(struct dvb_demux_feed));
-       if (!dvbdemux->feed) {
-               vfree(dvbdemux->filter);
-               dvbdemux->filter = NULL;
-               return -ENOMEM;
-       }
-       for (i = 0; i < dvbdemux->filternum; i++) {
-               dvbdemux->filter[i].state = DMX_STATE_FREE;
-               dvbdemux->filter[i].index = i;
-       }
-       for (i = 0; i < dvbdemux->feednum; i++) {
-               dvbdemux->feed[i].state = DMX_STATE_FREE;
-               dvbdemux->feed[i].index = i;
-       }
-
-       dvbdemux->cnt_storage = vmalloc(MAX_PID + 1);
-       if (!dvbdemux->cnt_storage)
-               printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n");
-
-       INIT_LIST_HEAD(&dvbdemux->frontend_list);
-
-       for (i = 0; i < DMX_TS_PES_OTHER; i++) {
-               dvbdemux->pesfilter[i] = NULL;
-               dvbdemux->pids[i] = 0xffff;
-       }
-
-       INIT_LIST_HEAD(&dvbdemux->feed_list);
-
-       dvbdemux->playing = 0;
-       dvbdemux->recording = 0;
-       dvbdemux->tsbufp = 0;
-
-       if (!dvbdemux->check_crc32)
-               dvbdemux->check_crc32 = dvb_dmx_crc32;
-
-       if (!dvbdemux->memcopy)
-               dvbdemux->memcopy = dvb_dmx_memcopy;
-
-       dmx->frontend = NULL;
-       dmx->priv = dvbdemux;
-       dmx->open = dvbdmx_open;
-       dmx->close = dvbdmx_close;
-       dmx->write = dvbdmx_write;
-       dmx->allocate_ts_feed = dvbdmx_allocate_ts_feed;
-       dmx->release_ts_feed = dvbdmx_release_ts_feed;
-       dmx->allocate_section_feed = dvbdmx_allocate_section_feed;
-       dmx->release_section_feed = dvbdmx_release_section_feed;
-
-       dmx->add_frontend = dvbdmx_add_frontend;
-       dmx->remove_frontend = dvbdmx_remove_frontend;
-       dmx->get_frontends = dvbdmx_get_frontends;
-       dmx->connect_frontend = dvbdmx_connect_frontend;
-       dmx->disconnect_frontend = dvbdmx_disconnect_frontend;
-       dmx->get_pes_pids = dvbdmx_get_pes_pids;
-
-       mutex_init(&dvbdemux->mutex);
-       spin_lock_init(&dvbdemux->lock);
-
-       return 0;
-}
-
-EXPORT_SYMBOL(dvb_dmx_init);
-
-void dvb_dmx_release(struct dvb_demux *dvbdemux)
-{
-       vfree(dvbdemux->cnt_storage);
-       vfree(dvbdemux->filter);
-       vfree(dvbdemux->feed);
-}
-
-EXPORT_SYMBOL(dvb_dmx_release);
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.h b/drivers/media/dvb/dvb-core/dvb_demux.h
deleted file mode 100644 (file)
index fa7188a..0000000
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * dvb_demux.h: DVB kernel demux API
- *
- * Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler
- *                         for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU 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 _DVB_DEMUX_H_
-#define _DVB_DEMUX_H_
-
-#include <linux/time.h>
-#include <linux/timer.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-
-#include "demux.h"
-
-#define DMX_TYPE_TS  0
-#define DMX_TYPE_SEC 1
-#define DMX_TYPE_PES 2
-
-#define DMX_STATE_FREE      0
-#define DMX_STATE_ALLOCATED 1
-#define DMX_STATE_SET       2
-#define DMX_STATE_READY     3
-#define DMX_STATE_GO        4
-
-#define DVB_DEMUX_MASK_MAX 18
-
-#define MAX_PID 0x1fff
-
-#define SPEED_PKTS_INTERVAL 50000
-
-struct dvb_demux_filter {
-       struct dmx_section_filter filter;
-       u8 maskandmode[DMX_MAX_FILTER_SIZE];
-       u8 maskandnotmode[DMX_MAX_FILTER_SIZE];
-       int doneq;
-
-       struct dvb_demux_filter *next;
-       struct dvb_demux_feed *feed;
-       int index;
-       int state;
-       int type;
-
-       u16 hw_handle;
-       struct timer_list timer;
-};
-
-#define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head)
-
-struct dvb_demux_feed {
-       union {
-               struct dmx_ts_feed ts;
-               struct dmx_section_feed sec;
-       } feed;
-
-       union {
-               dmx_ts_cb ts;
-               dmx_section_cb sec;
-       } cb;
-
-       struct dvb_demux *demux;
-       void *priv;
-       int type;
-       int state;
-       u16 pid;
-       u8 *buffer;
-       int buffer_size;
-
-       struct timespec timeout;
-       struct dvb_demux_filter *filter;
-
-       int ts_type;
-       enum dmx_ts_pes pes_type;
-
-       int cc;
-       int pusi_seen;          /* prevents feeding of garbage from previous section */
-
-       u16 peslen;
-
-       struct list_head list_head;
-       unsigned int index;     /* a unique index for each feed (can be used as hardware pid filter index) */
-};
-
-struct dvb_demux {
-       struct dmx_demux dmx;
-       void *priv;
-       int filternum;
-       int feednum;
-       int (*start_feed)(struct dvb_demux_feed *feed);
-       int (*stop_feed)(struct dvb_demux_feed *feed);
-       int (*write_to_decoder)(struct dvb_demux_feed *feed,
-                                const u8 *buf, size_t len);
-       u32 (*check_crc32)(struct dvb_demux_feed *feed,
-                           const u8 *buf, size_t len);
-       void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst,
-                        const u8 *src, size_t len);
-
-       int users;
-#define MAX_DVB_DEMUX_USERS 10
-       struct dvb_demux_filter *filter;
-       struct dvb_demux_feed *feed;
-
-       struct list_head frontend_list;
-
-       struct dvb_demux_feed *pesfilter[DMX_TS_PES_OTHER];
-       u16 pids[DMX_TS_PES_OTHER];
-       int playing;
-       int recording;
-
-#define DMX_MAX_PID 0x2000
-       struct list_head feed_list;
-       u8 tsbuf[204];
-       int tsbufp;
-
-       struct mutex mutex;
-       spinlock_t lock;
-
-       uint8_t *cnt_storage; /* for TS continuity check */
-
-       struct timespec speed_last_time; /* for TS speed check */
-       uint32_t speed_pkts_cnt; /* for TS speed check */
-};
-
-int dvb_dmx_init(struct dvb_demux *dvbdemux);
-void dvb_dmx_release(struct dvb_demux *dvbdemux);
-void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf,
-                             size_t count);
-void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
-void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf,
-                         size_t count);
-void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf,
-                         size_t count);
-
-#endif /* _DVB_DEMUX_H_ */
diff --git a/drivers/media/dvb/dvb-core/dvb_filter.c b/drivers/media/dvb/dvb-core/dvb_filter.c
deleted file mode 100644 (file)
index 772003f..0000000
+++ /dev/null
@@ -1,603 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include "dvb_filter.h"
-
-#if 0
-static unsigned int bitrates[3][16] =
-{{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0},
- {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0},
- {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}};
-#endif
-
-static u32 freq[4] = {480, 441, 320, 0};
-
-static unsigned int ac3_bitrates[32] =
-    {32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640,
-     0,0,0,0,0,0,0,0,0,0,0,0,0};
-
-static u32 ac3_frames[3][32] =
-    {{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024,
-      1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0},
-     {69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114,
-      1253,1393,0,0,0,0,0,0,0,0,0,0,0,0,0},
-     {96,120,144,168,192,240,288,336,384,480,576,672,768,960,1152,1344,
-      1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}};
-
-
-
-#if 0
-static void setup_ts2pes(ipack *pa, ipack *pv, u16 *pida, u16 *pidv,
-                 void (*pes_write)(u8 *buf, int count, void *data),
-                 void *priv)
-{
-       dvb_filter_ipack_init(pa, IPACKS, pes_write);
-       dvb_filter_ipack_init(pv, IPACKS, pes_write);
-       pa->pid = pida;
-       pv->pid = pidv;
-       pa->data = priv;
-       pv->data = priv;
-}
-#endif
-
-#if 0
-static void ts_to_pes(ipack *p, u8 *buf) // don't need count (=188)
-{
-       u8 off = 0;
-
-       if (!buf || !p ){
-               printk("NULL POINTER IDIOT\n");
-               return;
-       }
-       if (buf[1]&PAY_START) {
-               if (p->plength == MMAX_PLENGTH-6 && p->found>6){
-                       p->plength = p->found-6;
-                       p->found = 0;
-                       send_ipack(p);
-                       dvb_filter_ipack_reset(p);
-               }
-       }
-       if (buf[3] & ADAPT_FIELD) {  // adaptation field?
-               off = buf[4] + 1;
-               if (off+4 > 187) return;
-       }
-       dvb_filter_instant_repack(buf+4+off, TS_SIZE-4-off, p);
-}
-#endif
-
-#if 0
-/* needs 5 byte input, returns picture coding type*/
-static int read_picture_header(u8 *headr, struct mpg_picture *pic, int field, int pr)
-{
-       u8 pct;
-
-       if (pr) printk( "Pic header: ");
-       pic->temporal_reference[field] = (( headr[0] << 2 ) |
-                                         (headr[1] & 0x03) )& 0x03ff;
-       if (pr) printk( " temp ref: 0x%04x", pic->temporal_reference[field]);
-
-       pct = ( headr[1] >> 2 ) & 0x07;
-       pic->picture_coding_type[field] = pct;
-       if (pr) {
-               switch(pct){
-                       case I_FRAME:
-                               printk( "  I-FRAME");
-                               break;
-                       case B_FRAME:
-                               printk( "  B-FRAME");
-                               break;
-                       case P_FRAME:
-                               printk( "  P-FRAME");
-                               break;
-               }
-       }
-
-
-       pic->vinfo.vbv_delay  = (( headr[1] >> 5 ) | ( headr[2] << 3) |
-                                ( (headr[3] & 0x1F) << 11) ) & 0xffff;
-
-       if (pr) printk( " vbv delay: 0x%04x", pic->vinfo.vbv_delay);
-
-       pic->picture_header_parameter = ( headr[3] & 0xe0 ) |
-               ((headr[4] & 0x80) >> 3);
-
-       if ( pct == B_FRAME ){
-               pic->picture_header_parameter |= ( headr[4] >> 3 ) & 0x0f;
-       }
-       if (pr) printk( " pic head param: 0x%x",
-                       pic->picture_header_parameter);
-
-       return pct;
-}
-#endif
-
-#if 0
-/* needs 4 byte input */
-static int read_gop_header(u8 *headr, struct mpg_picture *pic, int pr)
-{
-       if (pr) printk("GOP header: ");
-
-       pic->time_code  = (( headr[0] << 17 ) | ( headr[1] << 9) |
-                          ( headr[2] << 1 ) | (headr[3] &0x01)) & 0x1ffffff;
-
-       if (pr) printk(" time: %d:%d.%d ", (headr[0]>>2)& 0x1F,
-                      ((headr[0]<<4)& 0x30)| ((headr[1]>>4)& 0x0F),
-                      ((headr[1]<<3)& 0x38)| ((headr[2]>>5)& 0x0F));
-
-       if ( ( headr[3] & 0x40 ) != 0 ){
-               pic->closed_gop = 1;
-       } else {
-               pic->closed_gop = 0;
-       }
-       if (pr) printk("closed: %d", pic->closed_gop);
-
-       if ( ( headr[3] & 0x20 ) != 0 ){
-               pic->broken_link = 1;
-       } else {
-               pic->broken_link = 0;
-       }
-       if (pr) printk(" broken: %d\n", pic->broken_link);
-
-       return 0;
-}
-#endif
-
-#if 0
-/* needs 8 byte input */
-static int read_sequence_header(u8 *headr, struct dvb_video_info *vi, int pr)
-{
-       int sw;
-       int form = -1;
-
-       if (pr) printk("Reading sequence header\n");
-
-       vi->horizontal_size     = ((headr[1] &0xF0) >> 4) | (headr[0] << 4);
-       vi->vertical_size       = ((headr[1] &0x0F) << 8) | (headr[2]);
-
-       sw = (int)((headr[3]&0xF0) >> 4) ;
-
-       switch( sw ){
-       case 1:
-               if (pr)
-                       printk("Videostream: ASPECT: 1:1");
-               vi->aspect_ratio = 100;
-               break;
-       case 2:
-               if (pr)
-                       printk("Videostream: ASPECT: 4:3");
-               vi->aspect_ratio = 133;
-               break;
-       case 3:
-               if (pr)
-                       printk("Videostream: ASPECT: 16:9");
-               vi->aspect_ratio = 177;
-               break;
-       case 4:
-               if (pr)
-                       printk("Videostream: ASPECT: 2.21:1");
-               vi->aspect_ratio = 221;
-               break;
-
-       case 5 ... 15:
-               if (pr)
-                       printk("Videostream: ASPECT: reserved");
-               vi->aspect_ratio = 0;
-               break;
-
-       default:
-               vi->aspect_ratio = 0;
-               return -1;
-       }
-
-       if (pr)
-               printk("  Size = %dx%d",vi->horizontal_size,vi->vertical_size);
-
-       sw = (int)(headr[3]&0x0F);
-
-       switch ( sw ) {
-       case 1:
-               if (pr)
-                       printk("  FRate: 23.976 fps");
-               vi->framerate = 23976;
-               form = -1;
-               break;
-       case 2:
-               if (pr)
-                       printk("  FRate: 24 fps");
-               vi->framerate = 24000;
-               form = -1;
-               break;
-       case 3:
-               if (pr)
-                       printk("  FRate: 25 fps");
-               vi->framerate = 25000;
-               form = VIDEO_MODE_PAL;
-               break;
-       case 4:
-               if (pr)
-                       printk("  FRate: 29.97 fps");
-               vi->framerate = 29970;
-               form = VIDEO_MODE_NTSC;
-               break;
-       case 5:
-               if (pr)
-                       printk("  FRate: 30 fps");
-               vi->framerate = 30000;
-               form = VIDEO_MODE_NTSC;
-               break;
-       case 6:
-               if (pr)
-                       printk("  FRate: 50 fps");
-               vi->framerate = 50000;
-               form = VIDEO_MODE_PAL;
-               break;
-       case 7:
-               if (pr)
-                       printk("  FRate: 60 fps");
-               vi->framerate = 60000;
-               form = VIDEO_MODE_NTSC;
-               break;
-       }
-
-       vi->bit_rate = (headr[4] << 10) | (headr[5] << 2) | (headr[6] & 0x03);
-
-       vi->vbv_buffer_size
-               = (( headr[6] & 0xF8) >> 3 ) | (( headr[7] & 0x1F )<< 5);
-
-       if (pr){
-               printk("  BRate: %d Mbit/s",4*(vi->bit_rate)/10000);
-               printk("  vbvbuffer %d",16*1024*(vi->vbv_buffer_size));
-               printk("\n");
-       }
-
-       vi->video_format = form;
-
-       return 0;
-}
-#endif
-
-
-#if 0
-static int get_vinfo(u8 *mbuf, int count, struct dvb_video_info *vi, int pr)
-{
-       u8 *headr;
-       int found = 0;
-       int c = 0;
-
-       while (found < 4 && c+4 < count){
-               u8 *b;
-
-               b = mbuf+c;
-               if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01
-                    && b[3] == 0xb3) found = 4;
-               else {
-                       c++;
-               }
-       }
-
-       if (! found) return -1;
-       c += 4;
-       if (c+12 >= count) return -1;
-       headr = mbuf+c;
-       if (read_sequence_header(headr, vi, pr) < 0) return -1;
-       vi->off = c-4;
-       return 0;
-}
-#endif
-
-
-#if 0
-static int get_ainfo(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr)
-{
-       u8 *headr;
-       int found = 0;
-       int c = 0;
-       int fr = 0;
-
-       while (found < 2 && c < count){
-               u8 b[2];
-               memcpy( b, mbuf+c, 2);
-
-               if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8)
-                       found = 2;
-               else {
-                       c++;
-               }
-       }
-
-       if (!found) return -1;
-
-       if (c+3 >= count) return -1;
-       headr = mbuf+c;
-
-       ai->layer = (headr[1] & 0x06) >> 1;
-
-       if (pr)
-               printk("Audiostream: Layer: %d", 4-ai->layer);
-
-
-       ai->bit_rate = bitrates[(3-ai->layer)][(headr[2] >> 4 )]*1000;
-
-       if (pr){
-               if (ai->bit_rate == 0)
-                       printk("  Bit rate: free");
-               else if (ai->bit_rate == 0xf)
-                       printk("  BRate: reserved");
-               else
-                       printk("  BRate: %d kb/s", ai->bit_rate/1000);
-       }
-
-       fr = (headr[2] & 0x0c ) >> 2;
-       ai->frequency = freq[fr]*100;
-       if (pr){
-               if (ai->frequency == 3)
-                       printk("  Freq: reserved\n");
-               else
-                       printk("  Freq: %d kHz\n",ai->frequency);
-
-       }
-       ai->off = c;
-       return 0;
-}
-#endif
-
-
-int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr)
-{
-       u8 *headr;
-       int found = 0;
-       int c = 0;
-       u8 frame = 0;
-       int fr = 0;
-
-       while ( !found  && c < count){
-               u8 *b = mbuf+c;
-
-               if ( b[0] == 0x0b &&  b[1] == 0x77 )
-                       found = 1;
-               else {
-                       c++;
-               }
-       }
-
-       if (!found) return -1;
-       if (pr)
-               printk("Audiostream: AC3");
-
-       ai->off = c;
-       if (c+5 >= count) return -1;
-
-       ai->layer = 0;  // 0 for AC3
-       headr = mbuf+c+2;
-
-       frame = (headr[2]&0x3f);
-       ai->bit_rate = ac3_bitrates[frame >> 1]*1000;
-
-       if (pr)
-               printk("  BRate: %d kb/s", (int) ai->bit_rate/1000);
-
-       ai->frequency = (headr[2] & 0xc0 ) >> 6;
-       fr = (headr[2] & 0xc0 ) >> 6;
-       ai->frequency = freq[fr]*100;
-       if (pr) printk ("  Freq: %d Hz\n", (int) ai->frequency);
-
-
-       ai->framesize = ac3_frames[fr][frame >> 1];
-       if ((frame & 1) &&  (fr == 1)) ai->framesize++;
-       ai->framesize = ai->framesize << 1;
-       if (pr) printk ("  Framesize %d\n",(int) ai->framesize);
-
-
-       return 0;
-}
-EXPORT_SYMBOL(dvb_filter_get_ac3info);
-
-
-#if 0
-static u8 *skip_pes_header(u8 **bufp)
-{
-       u8 *inbuf = *bufp;
-       u8 *buf = inbuf;
-       u8 *pts = NULL;
-       int skip = 0;
-
-       static const int mpeg1_skip_table[16] = {
-               1, 0xffff,      5,     10, 0xffff, 0xffff, 0xffff, 0xffff,
-               0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
-       };
-
-
-       if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */
-               if (buf[7] & PTS_ONLY)
-                       pts = buf+9;
-               else pts = NULL;
-               buf = inbuf + 9 + inbuf[8];
-       } else {        /* mpeg1 */
-               for (buf = inbuf + 6; *buf == 0xff; buf++)
-                       if (buf == inbuf + 6 + 16) {
-                               break;
-                       }
-               if ((*buf & 0xc0) == 0x40)
-                       buf += 2;
-               skip = mpeg1_skip_table [*buf >> 4];
-               if (skip == 5 || skip == 10) pts = buf;
-               else pts = NULL;
-
-               buf += mpeg1_skip_table [*buf >> 4];
-       }
-
-       *bufp = buf;
-       return pts;
-}
-#endif
-
-#if 0
-static void initialize_quant_matrix( u32 *matrix )
-{
-       int i;
-
-       matrix[0]  = 0x08101013;
-       matrix[1]  = 0x10131616;
-       matrix[2]  = 0x16161616;
-       matrix[3]  = 0x1a181a1b;
-       matrix[4]  = 0x1b1b1a1a;
-       matrix[5]  = 0x1a1a1b1b;
-       matrix[6]  = 0x1b1d1d1d;
-       matrix[7]  = 0x2222221d;
-       matrix[8]  = 0x1d1d1b1b;
-       matrix[9]  = 0x1d1d2020;
-       matrix[10] = 0x22222526;
-       matrix[11] = 0x25232322;
-       matrix[12] = 0x23262628;
-       matrix[13] = 0x28283030;
-       matrix[14] = 0x2e2e3838;
-       matrix[15] = 0x3a454553;
-
-       for ( i = 16 ; i < 32 ; i++ )
-               matrix[i] = 0x10101010;
-}
-#endif
-
-#if 0
-static void initialize_mpg_picture(struct mpg_picture *pic)
-{
-       int i;
-
-       /* set MPEG1 */
-       pic->mpeg1_flag = 1;
-       pic->profile_and_level = 0x4A ;        /* MP@LL */
-       pic->progressive_sequence = 1;
-       pic->low_delay = 0;
-
-       pic->sequence_display_extension_flag = 0;
-       for ( i = 0 ; i < 4 ; i++ ){
-               pic->frame_centre_horizontal_offset[i] = 0;
-               pic->frame_centre_vertical_offset[i] = 0;
-       }
-       pic->last_frame_centre_horizontal_offset = 0;
-       pic->last_frame_centre_vertical_offset = 0;
-
-       pic->picture_display_extension_flag[0] = 0;
-       pic->picture_display_extension_flag[1] = 0;
-       pic->sequence_header_flag = 0;
-       pic->gop_flag = 0;
-       pic->sequence_end_flag = 0;
-}
-#endif
-
-#if 0
-static void mpg_set_picture_parameter( int32_t field_type, struct mpg_picture *pic )
-{
-       int16_t last_h_offset;
-       int16_t last_v_offset;
-
-       int16_t *p_h_offset;
-       int16_t *p_v_offset;
-
-       if ( pic->mpeg1_flag ){
-               pic->picture_structure[field_type] = VIDEO_FRAME_PICTURE;
-               pic->top_field_first = 0;
-               pic->repeat_first_field = 0;
-               pic->progressive_frame = 1;
-               pic->picture_coding_parameter = 0x000010;
-       }
-
-       /* Reset flag */
-       pic->picture_display_extension_flag[field_type] = 0;
-
-       last_h_offset = pic->last_frame_centre_horizontal_offset;
-       last_v_offset = pic->last_frame_centre_vertical_offset;
-       if ( field_type == FIRST_FIELD ){
-               p_h_offset = pic->frame_centre_horizontal_offset;
-               p_v_offset = pic->frame_centre_vertical_offset;
-               *p_h_offset = last_h_offset;
-               *(p_h_offset + 1) = last_h_offset;
-               *(p_h_offset + 2) = last_h_offset;
-               *p_v_offset = last_v_offset;
-               *(p_v_offset + 1) = last_v_offset;
-               *(p_v_offset + 2) = last_v_offset;
-       } else {
-               pic->frame_centre_horizontal_offset[3] = last_h_offset;
-               pic->frame_centre_vertical_offset[3] = last_v_offset;
-       }
-}
-#endif
-
-#if 0
-static void init_mpg_picture( struct mpg_picture *pic, int chan, int32_t field_type)
-{
-       pic->picture_header = 0;
-       pic->sequence_header_data
-               = ( INIT_HORIZONTAL_SIZE << 20 )
-                       | ( INIT_VERTICAL_SIZE << 8 )
-                       | ( INIT_ASPECT_RATIO << 4 )
-                       | ( INIT_FRAME_RATE );
-       pic->mpeg1_flag = 0;
-       pic->vinfo.horizontal_size
-               = INIT_DISP_HORIZONTAL_SIZE;
-       pic->vinfo.vertical_size
-               = INIT_DISP_VERTICAL_SIZE;
-       pic->picture_display_extension_flag[field_type]
-               = 0;
-       pic->pts_flag[field_type] = 0;
-
-       pic->sequence_gop_header = 0;
-       pic->picture_header = 0;
-       pic->sequence_header_flag = 0;
-       pic->gop_flag = 0;
-       pic->sequence_end_flag = 0;
-       pic->sequence_display_extension_flag = 0;
-       pic->last_frame_centre_horizontal_offset = 0;
-       pic->last_frame_centre_vertical_offset = 0;
-       pic->channel = chan;
-}
-#endif
-
-void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
-                           dvb_filter_pes2ts_cb_t *cb, void *priv)
-{
-       unsigned char *buf=p2ts->buf;
-
-       buf[0]=0x47;
-       buf[1]=(pid>>8);
-       buf[2]=pid&0xff;
-       p2ts->cc=0;
-       p2ts->cb=cb;
-       p2ts->priv=priv;
-}
-EXPORT_SYMBOL(dvb_filter_pes2ts_init);
-
-int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
-                     int len, int payload_start)
-{
-       unsigned char *buf=p2ts->buf;
-       int ret=0, rest;
-
-       //len=6+((pes[4]<<8)|pes[5]);
-
-       if (payload_start)
-               buf[1]|=0x40;
-       else
-               buf[1]&=~0x40;
-       while (len>=184) {
-               buf[3]=0x10|((p2ts->cc++)&0x0f);
-               memcpy(buf+4, pes, 184);
-               if ((ret=p2ts->cb(p2ts->priv, buf)))
-                       return ret;
-               len-=184; pes+=184;
-               buf[1]&=~0x40;
-       }
-       if (!len)
-               return 0;
-       buf[3]=0x30|((p2ts->cc++)&0x0f);
-       rest=183-len;
-       if (rest) {
-               buf[5]=0x00;
-               if (rest-1)
-                       memset(buf+6, 0xff, rest-1);
-       }
-       buf[4]=rest;
-       memcpy(buf+5+rest, pes, len);
-       return p2ts->cb(p2ts->priv, buf);
-}
-EXPORT_SYMBOL(dvb_filter_pes2ts);
diff --git a/drivers/media/dvb/dvb-core/dvb_filter.h b/drivers/media/dvb/dvb-core/dvb_filter.h
deleted file mode 100644 (file)
index 375e3be..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * dvb_filter.h
- *
- * 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.
- */
-
-#ifndef _DVB_FILTER_H_
-#define _DVB_FILTER_H_
-
-#include <linux/slab.h>
-
-#include "demux.h"
-
-typedef int (dvb_filter_pes2ts_cb_t) (void *, unsigned char *);
-
-struct dvb_filter_pes2ts {
-       unsigned char buf[188];
-       unsigned char cc;
-       dvb_filter_pes2ts_cb_t *cb;
-       void *priv;
-};
-
-void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
-                           dvb_filter_pes2ts_cb_t *cb, void *priv);
-
-int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
-                     int len, int payload_start);
-
-
-#define PROG_STREAM_MAP  0xBC
-#define PRIVATE_STREAM1  0xBD
-#define PADDING_STREAM   0xBE
-#define PRIVATE_STREAM2  0xBF
-#define AUDIO_STREAM_S   0xC0
-#define AUDIO_STREAM_E   0xDF
-#define VIDEO_STREAM_S   0xE0
-#define VIDEO_STREAM_E   0xEF
-#define ECM_STREAM       0xF0
-#define EMM_STREAM       0xF1
-#define DSM_CC_STREAM    0xF2
-#define ISO13522_STREAM  0xF3
-#define PROG_STREAM_DIR  0xFF
-
-#define DVB_PICTURE_START    0x00
-#define DVB_USER_START       0xb2
-#define DVB_SEQUENCE_HEADER  0xb3
-#define DVB_SEQUENCE_ERROR   0xb4
-#define DVB_EXTENSION_START  0xb5
-#define DVB_SEQUENCE_END     0xb7
-#define DVB_GOP_START        0xb8
-#define DVB_EXCEPT_SLICE     0xb0
-
-#define SEQUENCE_EXTENSION           0x01
-#define SEQUENCE_DISPLAY_EXTENSION   0x02
-#define PICTURE_CODING_EXTENSION     0x08
-#define QUANT_MATRIX_EXTENSION       0x03
-#define PICTURE_DISPLAY_EXTENSION    0x07
-
-#define I_FRAME 0x01
-#define B_FRAME 0x02
-#define P_FRAME 0x03
-
-/* Initialize sequence_data */
-#define INIT_HORIZONTAL_SIZE        720
-#define INIT_VERTICAL_SIZE          576
-#define INIT_ASPECT_RATIO          0x02
-#define INIT_FRAME_RATE            0x03
-#define INIT_DISP_HORIZONTAL_SIZE   540
-#define INIT_DISP_VERTICAL_SIZE     576
-
-
-//flags2
-#define PTS_DTS_FLAGS    0xC0
-#define ESCR_FLAG        0x20
-#define ES_RATE_FLAG     0x10
-#define DSM_TRICK_FLAG   0x08
-#define ADD_CPY_FLAG     0x04
-#define PES_CRC_FLAG     0x02
-#define PES_EXT_FLAG     0x01
-
-//pts_dts flags
-#define PTS_ONLY         0x80
-#define PTS_DTS          0xC0
-
-#define TS_SIZE        188
-#define TRANS_ERROR    0x80
-#define PAY_START      0x40
-#define TRANS_PRIO     0x20
-#define PID_MASK_HI    0x1F
-//flags
-#define TRANS_SCRMBL1  0x80
-#define TRANS_SCRMBL2  0x40
-#define ADAPT_FIELD    0x20
-#define PAYLOAD        0x10
-#define COUNT_MASK     0x0F
-
-// adaptation flags
-#define DISCON_IND     0x80
-#define RAND_ACC_IND   0x40
-#define ES_PRI_IND     0x20
-#define PCR_FLAG       0x10
-#define OPCR_FLAG      0x08
-#define SPLICE_FLAG    0x04
-#define TRANS_PRIV     0x02
-#define ADAP_EXT_FLAG  0x01
-
-// adaptation extension flags
-#define LTW_FLAG       0x80
-#define PIECE_RATE     0x40
-#define SEAM_SPLICE    0x20
-
-
-#define MAX_PLENGTH 0xFFFF
-#define MMAX_PLENGTH (256*MAX_PLENGTH)
-
-#ifndef IPACKS
-#define IPACKS 2048
-#endif
-
-struct ipack {
-       int size;
-       int found;
-       u8 *buf;
-       u8 cid;
-       u32 plength;
-       u8 plen[2];
-       u8 flag1;
-       u8 flag2;
-       u8 hlength;
-       u8 pts[5];
-       u16 *pid;
-       int mpeg;
-       u8 check;
-       int which;
-       int done;
-       void *data;
-       void (*func)(u8 *buf,  int size, void *priv);
-       int count;
-       int repack_subids;
-};
-
-struct dvb_video_info {
-       u32 horizontal_size;
-       u32 vertical_size;
-       u32 aspect_ratio;
-       u32 framerate;
-       u32 video_format;
-       u32 bit_rate;
-       u32 comp_bit_rate;
-       u32 vbv_buffer_size;
-       s16 vbv_delay;
-       u32 CSPF;
-       u32 off;
-};
-
-#define OFF_SIZE 4
-#define FIRST_FIELD 0
-#define SECOND_FIELD 1
-#define VIDEO_FRAME_PICTURE 0x03
-
-struct mpg_picture {
-       int       channel;
-       struct dvb_video_info vinfo;
-       u32      *sequence_gop_header;
-       u32      *picture_header;
-       s32       time_code;
-       int       low_delay;
-       int       closed_gop;
-       int       broken_link;
-       int       sequence_header_flag;
-       int       gop_flag;
-       int       sequence_end_flag;
-
-       u8        profile_and_level;
-       s32       picture_coding_parameter;
-       u32       matrix[32];
-       s8        matrix_change_flag;
-
-       u8        picture_header_parameter;
-  /* bit 0 - 2: bwd f code
-     bit 3    : fpb vector
-     bit 4 - 6: fwd f code
-     bit 7    : fpf vector */
-
-       int       mpeg1_flag;
-       int       progressive_sequence;
-       int       sequence_display_extension_flag;
-       u32       sequence_header_data;
-       s16       last_frame_centre_horizontal_offset;
-       s16       last_frame_centre_vertical_offset;
-
-       u32       pts[2]; /* [0] 1st field, [1] 2nd field */
-       int       top_field_first;
-       int       repeat_first_field;
-       int       progressive_frame;
-       int       bank;
-       int       forward_bank;
-       int       backward_bank;
-       int       compress;
-       s16       frame_centre_horizontal_offset[OFF_SIZE];
-                 /* [0-2] 1st field, [3] 2nd field */
-       s16       frame_centre_vertical_offset[OFF_SIZE];
-                 /* [0-2] 1st field, [3] 2nd field */
-       s16       temporal_reference[2];
-                 /* [0] 1st field, [1] 2nd field */
-
-       s8        picture_coding_type[2];
-                 /* [0] 1st field, [1] 2nd field */
-       s8        picture_structure[2];
-                 /* [0] 1st field, [1] 2nd field */
-       s8        picture_display_extension_flag[2];
-                 /* [0] 1st field, [1] 2nd field */
-                 /* picture_display_extenion() 0:no 1:exit*/
-       s8        pts_flag[2];
-                 /* [0] 1st field, [1] 2nd field */
-};
-
-struct dvb_audio_info {
-       int layer;
-       u32 bit_rate;
-       u32 frequency;
-       u32 mode;
-       u32 mode_extension ;
-       u32 emphasis;
-       u32 framesize;
-       u32 off;
-};
-
-int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr);
-
-
-#endif
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
deleted file mode 100644 (file)
index 12e5eb1..0000000
+++ /dev/null
@@ -1,2553 +0,0 @@
-/*
- * dvb_frontend.c: DVB frontend tuning interface/thread
- *
- *
- * Copyright (C) 1999-2001 Ralph  Metzler
- *                        Marcus Metzler
- *                        Holger Waechtler
- *                                   for convergence integrated media GmbH
- *
- * Copyright (C) 2004 Andrew de Quincey (tuning thread cleanup)
- *
- * 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
- */
-
-/* Enables DVBv3 compatibility bits at the headers */
-#define __DVB_CORE__
-
-#include <linux/string.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-#include <linux/semaphore.h>
-#include <linux/module.h>
-#include <linux/list.h>
-#include <linux/freezer.h>
-#include <linux/jiffies.h>
-#include <linux/kthread.h>
-#include <asm/processor.h>
-
-#include "dvb_frontend.h"
-#include "dvbdev.h"
-#include <linux/dvb/version.h>
-
-static int dvb_frontend_debug;
-static int dvb_shutdown_timeout;
-static int dvb_force_auto_inversion;
-static int dvb_override_tune_delay;
-static int dvb_powerdown_on_sleep = 1;
-static int dvb_mfe_wait_time = 5;
-
-module_param_named(frontend_debug, dvb_frontend_debug, int, 0644);
-MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off).");
-module_param(dvb_shutdown_timeout, int, 0644);
-MODULE_PARM_DESC(dvb_shutdown_timeout, "wait <shutdown_timeout> seconds after close() before suspending hardware");
-module_param(dvb_force_auto_inversion, int, 0644);
-MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always");
-module_param(dvb_override_tune_delay, int, 0644);
-MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt");
-module_param(dvb_powerdown_on_sleep, int, 0644);
-MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)");
-module_param(dvb_mfe_wait_time, int, 0644);
-MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open() for multi-frontend to become available (default:5 seconds)");
-
-#define dprintk if (dvb_frontend_debug) printk
-
-#define FESTATE_IDLE 1
-#define FESTATE_RETUNE 2
-#define FESTATE_TUNING_FAST 4
-#define FESTATE_TUNING_SLOW 8
-#define FESTATE_TUNED 16
-#define FESTATE_ZIGZAG_FAST 32
-#define FESTATE_ZIGZAG_SLOW 64
-#define FESTATE_DISEQC 128
-#define FESTATE_ERROR 256
-#define FESTATE_WAITFORLOCK (FESTATE_TUNING_FAST | FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW | FESTATE_DISEQC)
-#define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST)
-#define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW)
-#define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW)
-
-#define FE_ALGO_HW             1
-/*
- * FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling.
- * FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune.
- * FESTATE_TUNING_FAST. Tuning parameters have been supplied and fast zigzag scan is in progress.
- * FESTATE_TUNING_SLOW. Tuning parameters have been supplied. Fast zigzag failed, so we're trying again, but slower.
- * FESTATE_TUNED. The frontend has successfully locked on.
- * FESTATE_ZIGZAG_FAST. The lock has been lost, and a fast zigzag has been initiated to try and regain it.
- * FESTATE_ZIGZAG_SLOW. The lock has been lost. Fast zigzag has been failed, so we're trying again, but slower.
- * FESTATE_DISEQC. A DISEQC command has just been issued.
- * FESTATE_WAITFORLOCK. When we're waiting for a lock.
- * FESTATE_SEARCHING_FAST. When we're searching for a signal using a fast zigzag scan.
- * FESTATE_SEARCHING_SLOW. When we're searching for a signal using a slow zigzag scan.
- * FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again.
- */
-
-#define DVB_FE_NO_EXIT 0
-#define DVB_FE_NORMAL_EXIT     1
-#define DVB_FE_DEVICE_REMOVED  2
-
-static DEFINE_MUTEX(frontend_mutex);
-
-struct dvb_frontend_private {
-
-       /* thread/frontend values */
-       struct dvb_device *dvbdev;
-       struct dvb_frontend_parameters parameters_out;
-       struct dvb_fe_events events;
-       struct semaphore sem;
-       struct list_head list_head;
-       wait_queue_head_t wait_queue;
-       struct task_struct *thread;
-       unsigned long release_jiffies;
-       unsigned int exit;
-       unsigned int wakeup;
-       fe_status_t status;
-       unsigned long tune_mode_flags;
-       unsigned int delay;
-       unsigned int reinitialise;
-       int tone;
-       int voltage;
-
-       /* swzigzag values */
-       unsigned int state;
-       unsigned int bending;
-       int lnb_drift;
-       unsigned int inversion;
-       unsigned int auto_step;
-       unsigned int auto_sub_step;
-       unsigned int started_auto_step;
-       unsigned int min_delay;
-       unsigned int max_drift;
-       unsigned int step_size;
-       int quality;
-       unsigned int check_wrapped;
-       enum dvbfe_search algo_status;
-};
-
-static void dvb_frontend_wakeup(struct dvb_frontend *fe);
-static int dtv_get_frontend(struct dvb_frontend *fe,
-                           struct dvb_frontend_parameters *p_out);
-static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
-                                          struct dvb_frontend_parameters *p);
-
-static bool has_get_frontend(struct dvb_frontend *fe)
-{
-       return fe->ops.get_frontend != NULL;
-}
-
-/*
- * Due to DVBv3 API calls, a delivery system should be mapped into one of
- * the 4 DVBv3 delivery systems (FE_QPSK, FE_QAM, FE_OFDM or FE_ATSC),
- * otherwise, a DVBv3 call will fail.
- */
-enum dvbv3_emulation_type {
-       DVBV3_UNKNOWN,
-       DVBV3_QPSK,
-       DVBV3_QAM,
-       DVBV3_OFDM,
-       DVBV3_ATSC,
-};
-
-static enum dvbv3_emulation_type dvbv3_type(u32 delivery_system)
-{
-       switch (delivery_system) {
-       case SYS_DVBC_ANNEX_A:
-       case SYS_DVBC_ANNEX_C:
-               return DVBV3_QAM;
-       case SYS_DVBS:
-       case SYS_DVBS2:
-       case SYS_TURBO:
-       case SYS_ISDBS:
-       case SYS_DSS:
-               return DVBV3_QPSK;
-       case SYS_DVBT:
-       case SYS_DVBT2:
-       case SYS_ISDBT:
-       case SYS_DTMB:
-               return DVBV3_OFDM;
-       case SYS_ATSC:
-       case SYS_ATSCMH:
-       case SYS_DVBC_ANNEX_B:
-               return DVBV3_ATSC;
-       case SYS_UNDEFINED:
-       case SYS_ISDBC:
-       case SYS_DVBH:
-       case SYS_DAB:
-       default:
-               /*
-                * Doesn't know how to emulate those types and/or
-                * there's no frontend driver from this type yet
-                * with some emulation code, so, we're not sure yet how
-                * to handle them, or they're not compatible with a DVBv3 call.
-                */
-               return DVBV3_UNKNOWN;
-       }
-}
-
-static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status)
-{
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       struct dvb_fe_events *events = &fepriv->events;
-       struct dvb_frontend_event *e;
-       int wp;
-
-       dprintk ("%s\n", __func__);
-
-       if ((status & FE_HAS_LOCK) && has_get_frontend(fe))
-               dtv_get_frontend(fe, &fepriv->parameters_out);
-
-       mutex_lock(&events->mtx);
-
-       wp = (events->eventw + 1) % MAX_EVENT;
-       if (wp == events->eventr) {
-               events->overflow = 1;
-               events->eventr = (events->eventr + 1) % MAX_EVENT;
-       }
-
-       e = &events->events[events->eventw];
-       e->status = status;
-       e->parameters = fepriv->parameters_out;
-
-       events->eventw = wp;
-
-       mutex_unlock(&events->mtx);
-
-       wake_up_interruptible (&events->wait_queue);
-}
-
-static int dvb_frontend_get_event(struct dvb_frontend *fe,
-                           struct dvb_frontend_event *event, int flags)
-{
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       struct dvb_fe_events *events = &fepriv->events;
-
-       dprintk ("%s\n", __func__);
-
-       if (events->overflow) {
-               events->overflow = 0;
-               return -EOVERFLOW;
-       }
-
-       if (events->eventw == events->eventr) {
-               int ret;
-
-               if (flags & O_NONBLOCK)
-                       return -EWOULDBLOCK;
-
-               up(&fepriv->sem);
-
-               ret = wait_event_interruptible (events->wait_queue,
-                                               events->eventw != events->eventr);
-
-               if (down_interruptible (&fepriv->sem))
-                       return -ERESTARTSYS;
-
-               if (ret < 0)
-                       return ret;
-       }
-
-       mutex_lock(&events->mtx);
-       *event = events->events[events->eventr];
-       events->eventr = (events->eventr + 1) % MAX_EVENT;
-       mutex_unlock(&events->mtx);
-
-       return 0;
-}
-
-static void dvb_frontend_clear_events(struct dvb_frontend *fe)
-{
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       struct dvb_fe_events *events = &fepriv->events;
-
-       mutex_lock(&events->mtx);
-       events->eventr = events->eventw;
-       mutex_unlock(&events->mtx);
-}
-
-static void dvb_frontend_init(struct dvb_frontend *fe)
-{
-       dprintk ("DVB: initialising adapter %i frontend %i (%s)...\n",
-                fe->dvb->num,
-                fe->id,
-                fe->ops.info.name);
-
-       if (fe->ops.init)
-               fe->ops.init(fe);
-       if (fe->ops.tuner_ops.init) {
-               if (fe->ops.i2c_gate_ctrl)
-                       fe->ops.i2c_gate_ctrl(fe, 1);
-               fe->ops.tuner_ops.init(fe);
-               if (fe->ops.i2c_gate_ctrl)
-                       fe->ops.i2c_gate_ctrl(fe, 0);
-       }
-}
-
-void dvb_frontend_reinitialise(struct dvb_frontend *fe)
-{
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-
-       fepriv->reinitialise = 1;
-       dvb_frontend_wakeup(fe);
-}
-EXPORT_SYMBOL(dvb_frontend_reinitialise);
-
-static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked)
-{
-       int q2;
-
-       dprintk ("%s\n", __func__);
-
-       if (locked)
-               (fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256;
-       else
-               (fepriv->quality) = (fepriv->quality * 220 + 0) / 256;
-
-       q2 = fepriv->quality - 128;
-       q2 *= q2;
-
-       fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128);
-}
-
-/**
- * Performs automatic twiddling of frontend parameters.
- *
- * @param fe The frontend concerned.
- * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT
- * @returns Number of complete iterations that have been performed.
- */
-static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped)
-{
-       int autoinversion;
-       int ready = 0;
-       int fe_set_err = 0;
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp;
-       int original_inversion = c->inversion;
-       u32 original_frequency = c->frequency;
-
-       /* are we using autoinversion? */
-       autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
-                        (c->inversion == INVERSION_AUTO));
-
-       /* setup parameters correctly */
-       while(!ready) {
-               /* calculate the lnb_drift */
-               fepriv->lnb_drift = fepriv->auto_step * fepriv->step_size;
-
-               /* wrap the auto_step if we've exceeded the maximum drift */
-               if (fepriv->lnb_drift > fepriv->max_drift) {
-                       fepriv->auto_step = 0;
-                       fepriv->auto_sub_step = 0;
-                       fepriv->lnb_drift = 0;
-               }
-
-               /* perform inversion and +/- zigzag */
-               switch(fepriv->auto_sub_step) {
-               case 0:
-                       /* try with the current inversion and current drift setting */
-                       ready = 1;
-                       break;
-
-               case 1:
-                       if (!autoinversion) break;
-
-                       fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;
-                       ready = 1;
-                       break;
-
-               case 2:
-                       if (fepriv->lnb_drift == 0) break;
-
-                       fepriv->lnb_drift = -fepriv->lnb_drift;
-                       ready = 1;
-                       break;
-
-               case 3:
-                       if (fepriv->lnb_drift == 0) break;
-                       if (!autoinversion) break;
-
-                       fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF;
-                       fepriv->lnb_drift = -fepriv->lnb_drift;
-                       ready = 1;
-                       break;
-
-               default:
-                       fepriv->auto_step++;
-                       fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */
-                       break;
-               }
-
-               if (!ready) fepriv->auto_sub_step++;
-       }
-
-       /* if this attempt would hit where we started, indicate a complete
-        * iteration has occurred */
-       if ((fepriv->auto_step == fepriv->started_auto_step) &&
-           (fepriv->auto_sub_step == 0) && check_wrapped) {
-               return 1;
-       }
-
-       dprintk("%s: drift:%i inversion:%i auto_step:%i "
-               "auto_sub_step:%i started_auto_step:%i\n",
-               __func__, fepriv->lnb_drift, fepriv->inversion,
-               fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step);
-
-       /* set the frontend itself */
-       c->frequency += fepriv->lnb_drift;
-       if (autoinversion)
-               c->inversion = fepriv->inversion;
-       tmp = *c;
-       if (fe->ops.set_frontend)
-               fe_set_err = fe->ops.set_frontend(fe);
-       *c = tmp;
-       if (fe_set_err < 0) {
-               fepriv->state = FESTATE_ERROR;
-               return fe_set_err;
-       }
-
-       c->frequency = original_frequency;
-       c->inversion = original_inversion;
-
-       fepriv->auto_sub_step++;
-       return 0;
-}
-
-static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
-{
-       fe_status_t s = 0;
-       int retval = 0;
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp;
-
-       /* if we've got no parameters, just keep idling */
-       if (fepriv->state & FESTATE_IDLE) {
-               fepriv->delay = 3*HZ;
-               fepriv->quality = 0;
-               return;
-       }
-
-       /* in SCAN mode, we just set the frontend when asked and leave it alone */
-       if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) {
-               if (fepriv->state & FESTATE_RETUNE) {
-                       tmp = *c;
-                       if (fe->ops.set_frontend)
-                               retval = fe->ops.set_frontend(fe);
-                       *c = tmp;
-                       if (retval < 0)
-                               fepriv->state = FESTATE_ERROR;
-                       else
-                               fepriv->state = FESTATE_TUNED;
-               }
-               fepriv->delay = 3*HZ;
-               fepriv->quality = 0;
-               return;
-       }
-
-       /* get the frontend status */
-       if (fepriv->state & FESTATE_RETUNE) {
-               s = 0;
-       } else {
-               if (fe->ops.read_status)
-                       fe->ops.read_status(fe, &s);
-               if (s != fepriv->status) {
-                       dvb_frontend_add_event(fe, s);
-                       fepriv->status = s;
-               }
-       }
-
-       /* if we're not tuned, and we have a lock, move to the TUNED state */
-       if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) {
-               dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
-               fepriv->state = FESTATE_TUNED;
-
-               /* if we're tuned, then we have determined the correct inversion */
-               if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) &&
-                   (c->inversion == INVERSION_AUTO)) {
-                       c->inversion = fepriv->inversion;
-               }
-               return;
-       }
-
-       /* if we are tuned already, check we're still locked */
-       if (fepriv->state & FESTATE_TUNED) {
-               dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
-
-               /* we're tuned, and the lock is still good... */
-               if (s & FE_HAS_LOCK) {
-                       return;
-               } else { /* if we _WERE_ tuned, but now don't have a lock */
-                       fepriv->state = FESTATE_ZIGZAG_FAST;
-                       fepriv->started_auto_step = fepriv->auto_step;
-                       fepriv->check_wrapped = 0;
-               }
-       }
-
-       /* don't actually do anything if we're in the LOSTLOCK state,
-        * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */
-       if ((fepriv->state & FESTATE_LOSTLOCK) &&
-           (fe->ops.info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) {
-               dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
-               return;
-       }
-
-       /* don't do anything if we're in the DISEQC state, since this
-        * might be someone with a motorized dish controlled by DISEQC.
-        * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */
-       if (fepriv->state & FESTATE_DISEQC) {
-               dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
-               return;
-       }
-
-       /* if we're in the RETUNE state, set everything up for a brand
-        * new scan, keeping the current inversion setting, as the next
-        * tune is _very_ likely to require the same */
-       if (fepriv->state & FESTATE_RETUNE) {
-               fepriv->lnb_drift = 0;
-               fepriv->auto_step = 0;
-               fepriv->auto_sub_step = 0;
-               fepriv->started_auto_step = 0;
-               fepriv->check_wrapped = 0;
-       }
-
-       /* fast zigzag. */
-       if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
-               fepriv->delay = fepriv->min_delay;
-
-               /* perform a tune */
-               retval = dvb_frontend_swzigzag_autotune(fe,
-                                                       fepriv->check_wrapped);
-               if (retval < 0) {
-                       return;
-               } else if (retval) {
-                       /* OK, if we've run out of trials at the fast speed.
-                        * Drop back to slow for the _next_ attempt */
-                       fepriv->state = FESTATE_SEARCHING_SLOW;
-                       fepriv->started_auto_step = fepriv->auto_step;
-                       return;
-               }
-               fepriv->check_wrapped = 1;
-
-               /* if we've just retuned, enter the ZIGZAG_FAST state.
-                * This ensures we cannot return from an
-                * FE_SET_FRONTEND ioctl before the first frontend tune
-                * occurs */
-               if (fepriv->state & FESTATE_RETUNE) {
-                       fepriv->state = FESTATE_TUNING_FAST;
-               }
-       }
-
-       /* slow zigzag */
-       if (fepriv->state & FESTATE_SEARCHING_SLOW) {
-               dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK);
-
-               /* Note: don't bother checking for wrapping; we stay in this
-                * state until we get a lock */
-               dvb_frontend_swzigzag_autotune(fe, 0);
-       }
-}
-
-static int dvb_frontend_is_exiting(struct dvb_frontend *fe)
-{
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-
-       if (fepriv->exit != DVB_FE_NO_EXIT)
-               return 1;
-
-       if (fepriv->dvbdev->writers == 1)
-               if (time_after_eq(jiffies, fepriv->release_jiffies +
-                                 dvb_shutdown_timeout * HZ))
-                       return 1;
-
-       return 0;
-}
-
-static int dvb_frontend_should_wakeup(struct dvb_frontend *fe)
-{
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-
-       if (fepriv->wakeup) {
-               fepriv->wakeup = 0;
-               return 1;
-       }
-       return dvb_frontend_is_exiting(fe);
-}
-
-static void dvb_frontend_wakeup(struct dvb_frontend *fe)
-{
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-
-       fepriv->wakeup = 1;
-       wake_up_interruptible(&fepriv->wait_queue);
-}
-
-static int dvb_frontend_thread(void *data)
-{
-       struct dvb_frontend *fe = data;
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       fe_status_t s;
-       enum dvbfe_algo algo;
-
-       bool re_tune = false;
-
-       dprintk("%s\n", __func__);
-
-       fepriv->check_wrapped = 0;
-       fepriv->quality = 0;
-       fepriv->delay = 3*HZ;
-       fepriv->status = 0;
-       fepriv->wakeup = 0;
-       fepriv->reinitialise = 0;
-
-       dvb_frontend_init(fe);
-
-       set_freezable();
-       while (1) {
-               up(&fepriv->sem);           /* is locked when we enter the thread... */
-restart:
-               wait_event_interruptible_timeout(fepriv->wait_queue,
-                       dvb_frontend_should_wakeup(fe) || kthread_should_stop()
-                               || freezing(current),
-                       fepriv->delay);
-
-               if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) {
-                       /* got signal or quitting */
-                       fepriv->exit = DVB_FE_NORMAL_EXIT;
-                       break;
-               }
-
-               if (try_to_freeze())
-                       goto restart;
-
-               if (down_interruptible(&fepriv->sem))
-                       break;
-
-               if (fepriv->reinitialise) {
-                       dvb_frontend_init(fe);
-                       if (fe->ops.set_tone && fepriv->tone != -1)
-                               fe->ops.set_tone(fe, fepriv->tone);
-                       if (fe->ops.set_voltage && fepriv->voltage != -1)
-                               fe->ops.set_voltage(fe, fepriv->voltage);
-                       fepriv->reinitialise = 0;
-               }
-
-               /* do an iteration of the tuning loop */
-               if (fe->ops.get_frontend_algo) {
-                       algo = fe->ops.get_frontend_algo(fe);
-                       switch (algo) {
-                       case DVBFE_ALGO_HW:
-                               dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__);
-
-                               if (fepriv->state & FESTATE_RETUNE) {
-                                       dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__);
-                                       re_tune = true;
-                                       fepriv->state = FESTATE_TUNED;
-                               } else {
-                                       re_tune = false;
-                               }
-
-                               if (fe->ops.tune)
-                                       fe->ops.tune(fe, re_tune, fepriv->tune_mode_flags, &fepriv->delay, &s);
-
-                               if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) {
-                                       dprintk("%s: state changed, adding current state\n", __func__);
-                                       dvb_frontend_add_event(fe, s);
-                                       fepriv->status = s;
-                               }
-                               break;
-                       case DVBFE_ALGO_SW:
-                               dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__);
-                               dvb_frontend_swzigzag(fe);
-                               break;
-                       case DVBFE_ALGO_CUSTOM:
-                               dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state);
-                               if (fepriv->state & FESTATE_RETUNE) {
-                                       dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__);
-                                       fepriv->state = FESTATE_TUNED;
-                               }
-                               /* Case where we are going to search for a carrier
-                                * User asked us to retune again for some reason, possibly
-                                * requesting a search with a new set of parameters
-                                */
-                               if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) {
-                                       if (fe->ops.search) {
-                                               fepriv->algo_status = fe->ops.search(fe);
-                                               /* We did do a search as was requested, the flags are
-                                                * now unset as well and has the flags wrt to search.
-                                                */
-                                       } else {
-                                               fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN;
-                                       }
-                               }
-                               /* Track the carrier if the search was successful */
-                               if (fepriv->algo_status != DVBFE_ALGO_SEARCH_SUCCESS) {
-                                       fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
-                                       fepriv->delay = HZ / 2;
-                               }
-                               dtv_property_legacy_params_sync(fe, &fepriv->parameters_out);
-                               fe->ops.read_status(fe, &s);
-                               if (s != fepriv->status) {
-                                       dvb_frontend_add_event(fe, s); /* update event list */
-                                       fepriv->status = s;
-                                       if (!(s & FE_HAS_LOCK)) {
-                                               fepriv->delay = HZ / 10;
-                                               fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
-                                       } else {
-                                               fepriv->delay = 60 * HZ;
-                                       }
-                               }
-                               break;
-                       default:
-                               dprintk("%s: UNDEFINED ALGO !\n", __func__);
-                               break;
-                       }
-               } else {
-                       dvb_frontend_swzigzag(fe);
-               }
-       }
-
-       if (dvb_powerdown_on_sleep) {
-               if (fe->ops.set_voltage)
-                       fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF);
-               if (fe->ops.tuner_ops.sleep) {
-                       if (fe->ops.i2c_gate_ctrl)
-                               fe->ops.i2c_gate_ctrl(fe, 1);
-                       fe->ops.tuner_ops.sleep(fe);
-                       if (fe->ops.i2c_gate_ctrl)
-                               fe->ops.i2c_gate_ctrl(fe, 0);
-               }
-               if (fe->ops.sleep)
-                       fe->ops.sleep(fe);
-       }
-
-       fepriv->thread = NULL;
-       if (kthread_should_stop())
-               fepriv->exit = DVB_FE_DEVICE_REMOVED;
-       else
-               fepriv->exit = DVB_FE_NO_EXIT;
-       mb();
-
-       dvb_frontend_wakeup(fe);
-       return 0;
-}
-
-static void dvb_frontend_stop(struct dvb_frontend *fe)
-{
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-
-       dprintk ("%s\n", __func__);
-
-       fepriv->exit = DVB_FE_NORMAL_EXIT;
-       mb();
-
-       if (!fepriv->thread)
-               return;
-
-       kthread_stop(fepriv->thread);
-
-       sema_init(&fepriv->sem, 1);
-       fepriv->state = FESTATE_IDLE;
-
-       /* paranoia check in case a signal arrived */
-       if (fepriv->thread)
-               printk("dvb_frontend_stop: warning: thread %p won't exit\n",
-                               fepriv->thread);
-}
-
-s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime)
-{
-       return ((curtime.tv_usec < lasttime.tv_usec) ?
-               1000000 - lasttime.tv_usec + curtime.tv_usec :
-               curtime.tv_usec - lasttime.tv_usec);
-}
-EXPORT_SYMBOL(timeval_usec_diff);
-
-static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec)
-{
-       curtime->tv_usec += add_usec;
-       if (curtime->tv_usec >= 1000000) {
-               curtime->tv_usec -= 1000000;
-               curtime->tv_sec++;
-       }
-}
-
-/*
- * Sleep until gettimeofday() > waketime + add_usec
- * This needs to be as precise as possible, but as the delay is
- * usually between 2ms and 32ms, it is done using a scheduled msleep
- * followed by usleep (normally a busy-wait loop) for the remainder
- */
-void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec)
-{
-       struct timeval lasttime;
-       s32 delta, newdelta;
-
-       timeval_usec_add(waketime, add_usec);
-
-       do_gettimeofday(&lasttime);
-       delta = timeval_usec_diff(lasttime, *waketime);
-       if (delta > 2500) {
-               msleep((delta - 1500) / 1000);
-               do_gettimeofday(&lasttime);
-               newdelta = timeval_usec_diff(lasttime, *waketime);
-               delta = (newdelta > delta) ? 0 : newdelta;
-       }
-       if (delta > 0)
-               udelay(delta);
-}
-EXPORT_SYMBOL(dvb_frontend_sleep_until);
-
-static int dvb_frontend_start(struct dvb_frontend *fe)
-{
-       int ret;
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       struct task_struct *fe_thread;
-
-       dprintk ("%s\n", __func__);
-
-       if (fepriv->thread) {
-               if (fepriv->exit == DVB_FE_NO_EXIT)
-                       return 0;
-               else
-                       dvb_frontend_stop (fe);
-       }
-
-       if (signal_pending(current))
-               return -EINTR;
-       if (down_interruptible (&fepriv->sem))
-               return -EINTR;
-
-       fepriv->state = FESTATE_IDLE;
-       fepriv->exit = DVB_FE_NO_EXIT;
-       fepriv->thread = NULL;
-       mb();
-
-       fe_thread = kthread_run(dvb_frontend_thread, fe,
-               "kdvb-ad-%i-fe-%i", fe->dvb->num,fe->id);
-       if (IS_ERR(fe_thread)) {
-               ret = PTR_ERR(fe_thread);
-               printk("dvb_frontend_start: failed to start kthread (%d)\n", ret);
-               up(&fepriv->sem);
-               return ret;
-       }
-       fepriv->thread = fe_thread;
-       return 0;
-}
-
-static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe,
-                                       u32 *freq_min, u32 *freq_max)
-{
-       *freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min);
-
-       if (fe->ops.info.frequency_max == 0)
-               *freq_max = fe->ops.tuner_ops.info.frequency_max;
-       else if (fe->ops.tuner_ops.info.frequency_max == 0)
-               *freq_max = fe->ops.info.frequency_max;
-       else
-               *freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max);
-
-       if (*freq_min == 0 || *freq_max == 0)
-               printk(KERN_WARNING "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n",
-                      fe->dvb->num,fe->id);
-}
-
-static int dvb_frontend_check_parameters(struct dvb_frontend *fe)
-{
-       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-       u32 freq_min;
-       u32 freq_max;
-
-       /* range check: frequency */
-       dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max);
-       if ((freq_min && c->frequency < freq_min) ||
-           (freq_max && c->frequency > freq_max)) {
-               printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n",
-                      fe->dvb->num, fe->id, c->frequency, freq_min, freq_max);
-               return -EINVAL;
-       }
-
-       /* range check: symbol rate */
-       switch (c->delivery_system) {
-       case SYS_DVBS:
-       case SYS_DVBS2:
-       case SYS_TURBO:
-       case SYS_DVBC_ANNEX_A:
-       case SYS_DVBC_ANNEX_C:
-               if ((fe->ops.info.symbol_rate_min &&
-                    c->symbol_rate < fe->ops.info.symbol_rate_min) ||
-                   (fe->ops.info.symbol_rate_max &&
-                    c->symbol_rate > fe->ops.info.symbol_rate_max)) {
-                       printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n",
-                              fe->dvb->num, fe->id, c->symbol_rate,
-                              fe->ops.info.symbol_rate_min,
-                              fe->ops.info.symbol_rate_max);
-                       return -EINVAL;
-               }
-       default:
-               break;
-       }
-
-       return 0;
-}
-
-static int dvb_frontend_clear_cache(struct dvb_frontend *fe)
-{
-       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-       int i;
-       u32 delsys;
-
-       delsys = c->delivery_system;
-       memset(c, 0, sizeof(struct dtv_frontend_properties));
-       c->delivery_system = delsys;
-
-       c->state = DTV_CLEAR;
-
-       dprintk("%s() Clearing cache for delivery system %d\n", __func__,
-               c->delivery_system);
-
-       c->transmission_mode = TRANSMISSION_MODE_AUTO;
-       c->bandwidth_hz = 0;    /* AUTO */
-       c->guard_interval = GUARD_INTERVAL_AUTO;
-       c->hierarchy = HIERARCHY_AUTO;
-       c->symbol_rate = 0;
-       c->code_rate_HP = FEC_AUTO;
-       c->code_rate_LP = FEC_AUTO;
-       c->fec_inner = FEC_AUTO;
-       c->rolloff = ROLLOFF_AUTO;
-       c->voltage = SEC_VOLTAGE_OFF;
-       c->sectone = SEC_TONE_OFF;
-       c->pilot = PILOT_AUTO;
-
-       c->isdbt_partial_reception = 0;
-       c->isdbt_sb_mode = 0;
-       c->isdbt_sb_subchannel = 0;
-       c->isdbt_sb_segment_idx = 0;
-       c->isdbt_sb_segment_count = 0;
-       c->isdbt_layer_enabled = 0;
-       for (i = 0; i < 3; i++) {
-               c->layer[i].fec = FEC_AUTO;
-               c->layer[i].modulation = QAM_AUTO;
-               c->layer[i].interleaving = 0;
-               c->layer[i].segment_count = 0;
-       }
-
-       c->isdbs_ts_id = 0;
-       c->dvbt2_plp_id = 0;
-
-       switch (c->delivery_system) {
-       case SYS_DVBS:
-       case SYS_DVBS2:
-       case SYS_TURBO:
-               c->modulation = QPSK;   /* implied for DVB-S in legacy API */
-               c->rolloff = ROLLOFF_35;/* implied for DVB-S */
-               break;
-       case SYS_ATSC:
-               c->modulation = VSB_8;
-               break;
-       default:
-               c->modulation = QAM_AUTO;
-               break;
-       }
-
-       return 0;
-}
-
-#define _DTV_CMD(n, s, b) \
-[n] = { \
-       .name = #n, \
-       .cmd  = n, \
-       .set  = s,\
-       .buffer = b \
-}
-
-static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = {
-       _DTV_CMD(DTV_TUNE, 1, 0),
-       _DTV_CMD(DTV_CLEAR, 1, 0),
-
-       /* Set */
-       _DTV_CMD(DTV_FREQUENCY, 1, 0),
-       _DTV_CMD(DTV_BANDWIDTH_HZ, 1, 0),
-       _DTV_CMD(DTV_MODULATION, 1, 0),
-       _DTV_CMD(DTV_INVERSION, 1, 0),
-       _DTV_CMD(DTV_DISEQC_MASTER, 1, 1),
-       _DTV_CMD(DTV_SYMBOL_RATE, 1, 0),
-       _DTV_CMD(DTV_INNER_FEC, 1, 0),
-       _DTV_CMD(DTV_VOLTAGE, 1, 0),
-       _DTV_CMD(DTV_TONE, 1, 0),
-       _DTV_CMD(DTV_PILOT, 1, 0),
-       _DTV_CMD(DTV_ROLLOFF, 1, 0),
-       _DTV_CMD(DTV_DELIVERY_SYSTEM, 1, 0),
-       _DTV_CMD(DTV_HIERARCHY, 1, 0),
-       _DTV_CMD(DTV_CODE_RATE_HP, 1, 0),
-       _DTV_CMD(DTV_CODE_RATE_LP, 1, 0),
-       _DTV_CMD(DTV_GUARD_INTERVAL, 1, 0),
-       _DTV_CMD(DTV_TRANSMISSION_MODE, 1, 0),
-       _DTV_CMD(DTV_INTERLEAVING, 1, 0),
-
-       _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 1, 0),
-       _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 1, 0),
-       _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 1, 0),
-       _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 1, 0),
-       _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERA_FEC, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERB_FEC, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERC_FEC, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 1, 0),
-       _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 1, 0),
-
-       _DTV_CMD(DTV_ISDBS_TS_ID, 1, 0),
-       _DTV_CMD(DTV_DVBT2_PLP_ID, 1, 0),
-
-       /* Get */
-       _DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1),
-       _DTV_CMD(DTV_API_VERSION, 0, 0),
-       _DTV_CMD(DTV_CODE_RATE_HP, 0, 0),
-       _DTV_CMD(DTV_CODE_RATE_LP, 0, 0),
-       _DTV_CMD(DTV_GUARD_INTERVAL, 0, 0),
-       _DTV_CMD(DTV_TRANSMISSION_MODE, 0, 0),
-       _DTV_CMD(DTV_HIERARCHY, 0, 0),
-       _DTV_CMD(DTV_INTERLEAVING, 0, 0),
-
-       _DTV_CMD(DTV_ENUM_DELSYS, 0, 0),
-
-       _DTV_CMD(DTV_ATSCMH_PARADE_ID, 1, 0),
-       _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 1, 0),
-
-       _DTV_CMD(DTV_ATSCMH_FIC_VER, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_PARADE_ID, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_NOG, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_TNOG, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_SGN, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_PRC, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_RS_FRAME_MODE, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_PRI, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_SEC, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_SCCC_BLOCK_MODE, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_A, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C, 0, 0),
-       _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D, 0, 0),
-};
-
-static void dtv_property_dump(struct dtv_property *tvp)
-{
-       int i;
-
-       if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) {
-               printk(KERN_WARNING "%s: tvp.cmd = 0x%08x undefined\n",
-                       __func__, tvp->cmd);
-               return;
-       }
-
-       dprintk("%s() tvp.cmd    = 0x%08x (%s)\n"
-               ,__func__
-               ,tvp->cmd
-               ,dtv_cmds[ tvp->cmd ].name);
-
-       if(dtv_cmds[ tvp->cmd ].buffer) {
-
-               dprintk("%s() tvp.u.buffer.len = 0x%02x\n"
-                       ,__func__
-                       ,tvp->u.buffer.len);
-
-               for(i = 0; i < tvp->u.buffer.len; i++)
-                       dprintk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n"
-                               ,__func__
-                               ,i
-                               ,tvp->u.buffer.data[i]);
-
-       } else
-               dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data);
-}
-
-/* Synchronise the legacy tuning parameters into the cache, so that demodulator
- * drivers can use a single set_frontend tuning function, regardless of whether
- * it's being used for the legacy or new API, reducing code and complexity.
- */
-static int dtv_property_cache_sync(struct dvb_frontend *fe,
-                                  struct dtv_frontend_properties *c,
-                                  const struct dvb_frontend_parameters *p)
-{
-       c->frequency = p->frequency;
-       c->inversion = p->inversion;
-
-       switch (dvbv3_type(c->delivery_system)) {
-       case DVBV3_QPSK:
-               dprintk("%s() Preparing QPSK req\n", __func__);
-               c->symbol_rate = p->u.qpsk.symbol_rate;
-               c->fec_inner = p->u.qpsk.fec_inner;
-               break;
-       case DVBV3_QAM:
-               dprintk("%s() Preparing QAM req\n", __func__);
-               c->symbol_rate = p->u.qam.symbol_rate;
-               c->fec_inner = p->u.qam.fec_inner;
-               c->modulation = p->u.qam.modulation;
-               break;
-       case DVBV3_OFDM:
-               dprintk("%s() Preparing OFDM req\n", __func__);
-               switch (p->u.ofdm.bandwidth) {
-               case BANDWIDTH_10_MHZ:
-                       c->bandwidth_hz = 10000000;
-                       break;
-               case BANDWIDTH_8_MHZ:
-                       c->bandwidth_hz = 8000000;
-                       break;
-               case BANDWIDTH_7_MHZ:
-                       c->bandwidth_hz = 7000000;
-                       break;
-               case BANDWIDTH_6_MHZ:
-                       c->bandwidth_hz = 6000000;
-                       break;
-               case BANDWIDTH_5_MHZ:
-                       c->bandwidth_hz = 5000000;
-                       break;
-               case BANDWIDTH_1_712_MHZ:
-                       c->bandwidth_hz = 1712000;
-                       break;
-               case BANDWIDTH_AUTO:
-                       c->bandwidth_hz = 0;
-               }
-
-               c->code_rate_HP = p->u.ofdm.code_rate_HP;
-               c->code_rate_LP = p->u.ofdm.code_rate_LP;
-               c->modulation = p->u.ofdm.constellation;
-               c->transmission_mode = p->u.ofdm.transmission_mode;
-               c->guard_interval = p->u.ofdm.guard_interval;
-               c->hierarchy = p->u.ofdm.hierarchy_information;
-               break;
-       case DVBV3_ATSC:
-               dprintk("%s() Preparing ATSC req\n", __func__);
-               c->modulation = p->u.vsb.modulation;
-               if (c->delivery_system == SYS_ATSCMH)
-                       break;
-               if ((c->modulation == VSB_8) || (c->modulation == VSB_16))
-                       c->delivery_system = SYS_ATSC;
-               else
-                       c->delivery_system = SYS_DVBC_ANNEX_B;
-               break;
-       case DVBV3_UNKNOWN:
-               printk(KERN_ERR
-                      "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n",
-                      __func__, c->delivery_system);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/* Ensure the cached values are set correctly in the frontend
- * legacy tuning structures, for the advanced tuning API.
- */
-static int dtv_property_legacy_params_sync(struct dvb_frontend *fe,
-                                           struct dvb_frontend_parameters *p)
-{
-       const struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-
-       p->frequency = c->frequency;
-       p->inversion = c->inversion;
-
-       switch (dvbv3_type(c->delivery_system)) {
-       case DVBV3_UNKNOWN:
-               printk(KERN_ERR
-                      "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n",
-                      __func__, c->delivery_system);
-               return -EINVAL;
-       case DVBV3_QPSK:
-               dprintk("%s() Preparing QPSK req\n", __func__);
-               p->u.qpsk.symbol_rate = c->symbol_rate;
-               p->u.qpsk.fec_inner = c->fec_inner;
-               break;
-       case DVBV3_QAM:
-               dprintk("%s() Preparing QAM req\n", __func__);
-               p->u.qam.symbol_rate = c->symbol_rate;
-               p->u.qam.fec_inner = c->fec_inner;
-               p->u.qam.modulation = c->modulation;
-               break;
-       case DVBV3_OFDM:
-               dprintk("%s() Preparing OFDM req\n", __func__);
-
-               switch (c->bandwidth_hz) {
-               case 10000000:
-                       p->u.ofdm.bandwidth = BANDWIDTH_10_MHZ;
-                       break;
-               case 8000000:
-                       p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ;
-                       break;
-               case 7000000:
-                       p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ;
-                       break;
-               case 6000000:
-                       p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
-                       break;
-               case 5000000:
-                       p->u.ofdm.bandwidth = BANDWIDTH_5_MHZ;
-                       break;
-               case 1712000:
-                       p->u.ofdm.bandwidth = BANDWIDTH_1_712_MHZ;
-                       break;
-               case 0:
-               default:
-                       p->u.ofdm.bandwidth = BANDWIDTH_AUTO;
-               }
-               p->u.ofdm.code_rate_HP = c->code_rate_HP;
-               p->u.ofdm.code_rate_LP = c->code_rate_LP;
-               p->u.ofdm.constellation = c->modulation;
-               p->u.ofdm.transmission_mode = c->transmission_mode;
-               p->u.ofdm.guard_interval = c->guard_interval;
-               p->u.ofdm.hierarchy_information = c->hierarchy;
-               break;
-       case DVBV3_ATSC:
-               dprintk("%s() Preparing VSB req\n", __func__);
-               p->u.vsb.modulation = c->modulation;
-               break;
-       }
-       return 0;
-}
-
-/**
- * dtv_get_frontend - calls a callback for retrieving DTV parameters
- * @fe:                struct dvb_frontend pointer
- * @c:         struct dtv_frontend_properties pointer (DVBv5 cache)
- * @p_out      struct dvb_frontend_parameters pointer (DVBv3 FE struct)
- *
- * This routine calls either the DVBv3 or DVBv5 get_frontend call.
- * If c is not null, it will update the DVBv5 cache struct pointed by it.
- * If p_out is not null, it will update the DVBv3 params pointed by it.
- */
-static int dtv_get_frontend(struct dvb_frontend *fe,
-                           struct dvb_frontend_parameters *p_out)
-{
-       int r;
-
-       if (fe->ops.get_frontend) {
-               r = fe->ops.get_frontend(fe);
-               if (unlikely(r < 0))
-                       return r;
-               if (p_out)
-                       dtv_property_legacy_params_sync(fe, p_out);
-               return 0;
-       }
-
-       /* As everything is in cache, get_frontend fops are always supported */
-       return 0;
-}
-
-static int dvb_frontend_ioctl_legacy(struct file *file,
-                       unsigned int cmd, void *parg);
-static int dvb_frontend_ioctl_properties(struct file *file,
-                       unsigned int cmd, void *parg);
-
-static int dtv_property_process_get(struct dvb_frontend *fe,
-                                   const struct dtv_frontend_properties *c,
-                                   struct dtv_property *tvp,
-                                   struct file *file)
-{
-       int r, ncaps;
-
-       switch(tvp->cmd) {
-       case DTV_ENUM_DELSYS:
-               ncaps = 0;
-               while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
-                       tvp->u.buffer.data[ncaps] = fe->ops.delsys[ncaps];
-                       ncaps++;
-               }
-               tvp->u.buffer.len = ncaps;
-               break;
-       case DTV_FREQUENCY:
-               tvp->u.data = c->frequency;
-               break;
-       case DTV_MODULATION:
-               tvp->u.data = c->modulation;
-               break;
-       case DTV_BANDWIDTH_HZ:
-               tvp->u.data = c->bandwidth_hz;
-               break;
-       case DTV_INVERSION:
-               tvp->u.data = c->inversion;
-               break;
-       case DTV_SYMBOL_RATE:
-               tvp->u.data = c->symbol_rate;
-               break;
-       case DTV_INNER_FEC:
-               tvp->u.data = c->fec_inner;
-               break;
-       case DTV_PILOT:
-               tvp->u.data = c->pilot;
-               break;
-       case DTV_ROLLOFF:
-               tvp->u.data = c->rolloff;
-               break;
-       case DTV_DELIVERY_SYSTEM:
-               tvp->u.data = c->delivery_system;
-               break;
-       case DTV_VOLTAGE:
-               tvp->u.data = c->voltage;
-               break;
-       case DTV_TONE:
-               tvp->u.data = c->sectone;
-               break;
-       case DTV_API_VERSION:
-               tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR;
-               break;
-       case DTV_CODE_RATE_HP:
-               tvp->u.data = c->code_rate_HP;
-               break;
-       case DTV_CODE_RATE_LP:
-               tvp->u.data = c->code_rate_LP;
-               break;
-       case DTV_GUARD_INTERVAL:
-               tvp->u.data = c->guard_interval;
-               break;
-       case DTV_TRANSMISSION_MODE:
-               tvp->u.data = c->transmission_mode;
-               break;
-       case DTV_HIERARCHY:
-               tvp->u.data = c->hierarchy;
-               break;
-       case DTV_INTERLEAVING:
-               tvp->u.data = c->interleaving;
-               break;
-
-       /* ISDB-T Support here */
-       case DTV_ISDBT_PARTIAL_RECEPTION:
-               tvp->u.data = c->isdbt_partial_reception;
-               break;
-       case DTV_ISDBT_SOUND_BROADCASTING:
-               tvp->u.data = c->isdbt_sb_mode;
-               break;
-       case DTV_ISDBT_SB_SUBCHANNEL_ID:
-               tvp->u.data = c->isdbt_sb_subchannel;
-               break;
-       case DTV_ISDBT_SB_SEGMENT_IDX:
-               tvp->u.data = c->isdbt_sb_segment_idx;
-               break;
-       case DTV_ISDBT_SB_SEGMENT_COUNT:
-               tvp->u.data = c->isdbt_sb_segment_count;
-               break;
-       case DTV_ISDBT_LAYER_ENABLED:
-               tvp->u.data = c->isdbt_layer_enabled;
-               break;
-       case DTV_ISDBT_LAYERA_FEC:
-               tvp->u.data = c->layer[0].fec;
-               break;
-       case DTV_ISDBT_LAYERA_MODULATION:
-               tvp->u.data = c->layer[0].modulation;
-               break;
-       case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
-               tvp->u.data = c->layer[0].segment_count;
-               break;
-       case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
-               tvp->u.data = c->layer[0].interleaving;
-               break;
-       case DTV_ISDBT_LAYERB_FEC:
-               tvp->u.data = c->layer[1].fec;
-               break;
-       case DTV_ISDBT_LAYERB_MODULATION:
-               tvp->u.data = c->layer[1].modulation;
-               break;
-       case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
-               tvp->u.data = c->layer[1].segment_count;
-               break;
-       case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
-               tvp->u.data = c->layer[1].interleaving;
-               break;
-       case DTV_ISDBT_LAYERC_FEC:
-               tvp->u.data = c->layer[2].fec;
-               break;
-       case DTV_ISDBT_LAYERC_MODULATION:
-               tvp->u.data = c->layer[2].modulation;
-               break;
-       case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
-               tvp->u.data = c->layer[2].segment_count;
-               break;
-       case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
-               tvp->u.data = c->layer[2].interleaving;
-               break;
-       case DTV_ISDBS_TS_ID:
-               tvp->u.data = c->isdbs_ts_id;
-               break;
-       case DTV_DVBT2_PLP_ID:
-               tvp->u.data = c->dvbt2_plp_id;
-               break;
-
-       /* ATSC-MH */
-       case DTV_ATSCMH_FIC_VER:
-               tvp->u.data = fe->dtv_property_cache.atscmh_fic_ver;
-               break;
-       case DTV_ATSCMH_PARADE_ID:
-               tvp->u.data = fe->dtv_property_cache.atscmh_parade_id;
-               break;
-       case DTV_ATSCMH_NOG:
-               tvp->u.data = fe->dtv_property_cache.atscmh_nog;
-               break;
-       case DTV_ATSCMH_TNOG:
-               tvp->u.data = fe->dtv_property_cache.atscmh_tnog;
-               break;
-       case DTV_ATSCMH_SGN:
-               tvp->u.data = fe->dtv_property_cache.atscmh_sgn;
-               break;
-       case DTV_ATSCMH_PRC:
-               tvp->u.data = fe->dtv_property_cache.atscmh_prc;
-               break;
-       case DTV_ATSCMH_RS_FRAME_MODE:
-               tvp->u.data = fe->dtv_property_cache.atscmh_rs_frame_mode;
-               break;
-       case DTV_ATSCMH_RS_FRAME_ENSEMBLE:
-               tvp->u.data = fe->dtv_property_cache.atscmh_rs_frame_ensemble;
-               break;
-       case DTV_ATSCMH_RS_CODE_MODE_PRI:
-               tvp->u.data = fe->dtv_property_cache.atscmh_rs_code_mode_pri;
-               break;
-       case DTV_ATSCMH_RS_CODE_MODE_SEC:
-               tvp->u.data = fe->dtv_property_cache.atscmh_rs_code_mode_sec;
-               break;
-       case DTV_ATSCMH_SCCC_BLOCK_MODE:
-               tvp->u.data = fe->dtv_property_cache.atscmh_sccc_block_mode;
-               break;
-       case DTV_ATSCMH_SCCC_CODE_MODE_A:
-               tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_a;
-               break;
-       case DTV_ATSCMH_SCCC_CODE_MODE_B:
-               tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_b;
-               break;
-       case DTV_ATSCMH_SCCC_CODE_MODE_C:
-               tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_c;
-               break;
-       case DTV_ATSCMH_SCCC_CODE_MODE_D:
-               tvp->u.data = fe->dtv_property_cache.atscmh_sccc_code_mode_d;
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       /* Allow the frontend to override outgoing properties */
-       if (fe->ops.get_property) {
-               r = fe->ops.get_property(fe, tvp);
-               if (r < 0)
-                       return r;
-       }
-
-       dtv_property_dump(tvp);
-
-       return 0;
-}
-
-static int dtv_set_frontend(struct dvb_frontend *fe);
-
-static bool is_dvbv3_delsys(u32 delsys)
-{
-       bool status;
-
-       status = (delsys == SYS_DVBT) || (delsys == SYS_DVBC_ANNEX_A) ||
-                (delsys == SYS_DVBS) || (delsys == SYS_ATSC);
-
-       return status;
-}
-
-static int set_delivery_system(struct dvb_frontend *fe, u32 desired_system)
-{
-       int ncaps, i;
-       u32 delsys = SYS_UNDEFINED;
-       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-       enum dvbv3_emulation_type type;
-
-       /*
-        * It was reported that some old DVBv5 applications were
-        * filling delivery_system with SYS_UNDEFINED. If this happens,
-        * assume that the application wants to use the first supported
-        * delivery system.
-        */
-       if (c->delivery_system == SYS_UNDEFINED)
-               c->delivery_system = fe->ops.delsys[0];
-
-       if (desired_system == SYS_UNDEFINED) {
-               /*
-                * A DVBv3 call doesn't know what's the desired system.
-                * Also, DVBv3 applications don't know that ops.info->type
-                * could be changed, and they simply dies when it doesn't
-                * match.
-                * So, don't change the current delivery system, as it
-                * may be trying to do the wrong thing, like setting an
-                * ISDB-T frontend as DVB-T. Instead, find the closest
-                * DVBv3 system that matches the delivery system.
-                */
-               if (is_dvbv3_delsys(c->delivery_system)) {
-                       dprintk("%s() Using delivery system to %d\n",
-                               __func__, c->delivery_system);
-                       return 0;
-               }
-               type = dvbv3_type(c->delivery_system);
-               switch (type) {
-               case DVBV3_QPSK:
-                       desired_system = SYS_DVBS;
-                       break;
-               case DVBV3_QAM:
-                       desired_system = SYS_DVBC_ANNEX_A;
-                       break;
-               case DVBV3_ATSC:
-                       desired_system = SYS_ATSC;
-                       break;
-               case DVBV3_OFDM:
-                       desired_system = SYS_DVBT;
-                       break;
-               default:
-                       dprintk("%s(): This frontend doesn't support DVBv3 calls\n",
-                               __func__);
-                       return -EINVAL;
-               }
-               /*
-                * Get a delivery system that is compatible with DVBv3
-                * NOTE: in order for this to work with softwares like Kaffeine that
-                *      uses a DVBv5 call for DVB-S2 and a DVBv3 call to go back to
-                *      DVB-S, drivers that support both should put the SYS_DVBS entry
-                *      before the SYS_DVBS2, otherwise it won't switch back to DVB-S.
-                *      The real fix is that userspace applications should not use DVBv3
-                *      and not trust on calling FE_SET_FRONTEND to switch the delivery
-                *      system.
-                */
-               ncaps = 0;
-               while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
-                       if (fe->ops.delsys[ncaps] == desired_system) {
-                               delsys = desired_system;
-                               break;
-                       }
-                       ncaps++;
-               }
-               if (delsys == SYS_UNDEFINED) {
-                       dprintk("%s() Couldn't find a delivery system that matches %d\n",
-                               __func__, desired_system);
-               }
-       } else {
-               /*
-                * This is a DVBv5 call. So, it likely knows the supported
-                * delivery systems.
-                */
-
-               /* Check if the desired delivery system is supported */
-               ncaps = 0;
-               while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
-                       if (fe->ops.delsys[ncaps] == desired_system) {
-                               c->delivery_system = desired_system;
-                               dprintk("%s() Changing delivery system to %d\n",
-                                       __func__, desired_system);
-                               return 0;
-                       }
-                       ncaps++;
-               }
-               type = dvbv3_type(desired_system);
-
-               /*
-                * The delivery system is not supported. See if it can be
-                * emulated.
-                * The emulation only works if the desired system is one of the
-                * DVBv3 delivery systems
-                */
-               if (!is_dvbv3_delsys(desired_system)) {
-                       dprintk("%s() can't use a DVBv3 FE_SET_FRONTEND call on this frontend\n",
-                               __func__);
-                       return -EINVAL;
-               }
-
-               /*
-                * Get the last non-DVBv3 delivery system that has the same type
-                * of the desired system
-                */
-               ncaps = 0;
-               while (fe->ops.delsys[ncaps] && ncaps < MAX_DELSYS) {
-                       if ((dvbv3_type(fe->ops.delsys[ncaps]) == type) &&
-                           !is_dvbv3_delsys(fe->ops.delsys[ncaps]))
-                               delsys = fe->ops.delsys[ncaps];
-                       ncaps++;
-               }
-               /* There's nothing compatible with the desired delivery system */
-               if (delsys == SYS_UNDEFINED) {
-                       dprintk("%s() Incompatible DVBv3 FE_SET_FRONTEND call for this frontend\n",
-                               __func__);
-                       return -EINVAL;
-               }
-       }
-
-       c->delivery_system = delsys;
-
-       /*
-        * The DVBv3 or DVBv5 call is requesting a different system. So,
-        * emulation is needed.
-        *
-        * Emulate newer delivery systems like ISDBT, DVBT and DTMB
-        * for older DVBv5 applications. The emulation will try to use
-        * the auto mode for most things, and will assume that the desired
-        * delivery system is the last one at the ops.delsys[] array
-        */
-       dprintk("%s() Using delivery system %d emulated as if it were a %d\n",
-               __func__, delsys, desired_system);
-
-       /*
-        * For now, handles ISDB-T calls. More code may be needed here for the
-        * other emulated stuff
-        */
-       if (type == DVBV3_OFDM) {
-               if (c->delivery_system == SYS_ISDBT) {
-                       dprintk("%s() Using defaults for SYS_ISDBT\n",
-                               __func__);
-                       if (!c->bandwidth_hz)
-                               c->bandwidth_hz = 6000000;
-
-                       c->isdbt_partial_reception = 0;
-                       c->isdbt_sb_mode = 0;
-                       c->isdbt_sb_subchannel = 0;
-                       c->isdbt_sb_segment_idx = 0;
-                       c->isdbt_sb_segment_count = 0;
-                       c->isdbt_layer_enabled = 0;
-                       for (i = 0; i < 3; i++) {
-                               c->layer[i].fec = FEC_AUTO;
-                               c->layer[i].modulation = QAM_AUTO;
-                               c->layer[i].interleaving = 0;
-                               c->layer[i].segment_count = 0;
-                       }
-               }
-       }
-       dprintk("change delivery system on cache to %d\n", c->delivery_system);
-
-       return 0;
-}
-
-static int dtv_property_process_set(struct dvb_frontend *fe,
-                                   struct dtv_property *tvp,
-                                   struct file *file)
-{
-       int r = 0;
-       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-
-       /* Allow the frontend to validate incoming properties */
-       if (fe->ops.set_property) {
-               r = fe->ops.set_property(fe, tvp);
-               if (r < 0)
-                       return r;
-       }
-
-       switch(tvp->cmd) {
-       case DTV_CLEAR:
-               /*
-                * Reset a cache of data specific to the frontend here. This does
-                * not effect hardware.
-                */
-               dvb_frontend_clear_cache(fe);
-               break;
-       case DTV_TUNE:
-               /* interpret the cache of data, build either a traditional frontend
-                * tunerequest so we can pass validation in the FE_SET_FRONTEND
-                * ioctl.
-                */
-               c->state = tvp->cmd;
-               dprintk("%s() Finalised property cache\n", __func__);
-
-               r = dtv_set_frontend(fe);
-               break;
-       case DTV_FREQUENCY:
-               c->frequency = tvp->u.data;
-               break;
-       case DTV_MODULATION:
-               c->modulation = tvp->u.data;
-               break;
-       case DTV_BANDWIDTH_HZ:
-               c->bandwidth_hz = tvp->u.data;
-               break;
-       case DTV_INVERSION:
-               c->inversion = tvp->u.data;
-               break;
-       case DTV_SYMBOL_RATE:
-               c->symbol_rate = tvp->u.data;
-               break;
-       case DTV_INNER_FEC:
-               c->fec_inner = tvp->u.data;
-               break;
-       case DTV_PILOT:
-               c->pilot = tvp->u.data;
-               break;
-       case DTV_ROLLOFF:
-               c->rolloff = tvp->u.data;
-               break;
-       case DTV_DELIVERY_SYSTEM:
-               r = set_delivery_system(fe, tvp->u.data);
-               break;
-       case DTV_VOLTAGE:
-               c->voltage = tvp->u.data;
-               r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE,
-                       (void *)c->voltage);
-               break;
-       case DTV_TONE:
-               c->sectone = tvp->u.data;
-               r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE,
-                       (void *)c->sectone);
-               break;
-       case DTV_CODE_RATE_HP:
-               c->code_rate_HP = tvp->u.data;
-               break;
-       case DTV_CODE_RATE_LP:
-               c->code_rate_LP = tvp->u.data;
-               break;
-       case DTV_GUARD_INTERVAL:
-               c->guard_interval = tvp->u.data;
-               break;
-       case DTV_TRANSMISSION_MODE:
-               c->transmission_mode = tvp->u.data;
-               break;
-       case DTV_HIERARCHY:
-               c->hierarchy = tvp->u.data;
-               break;
-       case DTV_INTERLEAVING:
-               c->interleaving = tvp->u.data;
-               break;
-
-       /* ISDB-T Support here */
-       case DTV_ISDBT_PARTIAL_RECEPTION:
-               c->isdbt_partial_reception = tvp->u.data;
-               break;
-       case DTV_ISDBT_SOUND_BROADCASTING:
-               c->isdbt_sb_mode = tvp->u.data;
-               break;
-       case DTV_ISDBT_SB_SUBCHANNEL_ID:
-               c->isdbt_sb_subchannel = tvp->u.data;
-               break;
-       case DTV_ISDBT_SB_SEGMENT_IDX:
-               c->isdbt_sb_segment_idx = tvp->u.data;
-               break;
-       case DTV_ISDBT_SB_SEGMENT_COUNT:
-               c->isdbt_sb_segment_count = tvp->u.data;
-               break;
-       case DTV_ISDBT_LAYER_ENABLED:
-               c->isdbt_layer_enabled = tvp->u.data;
-               break;
-       case DTV_ISDBT_LAYERA_FEC:
-               c->layer[0].fec = tvp->u.data;
-               break;
-       case DTV_ISDBT_LAYERA_MODULATION:
-               c->layer[0].modulation = tvp->u.data;
-               break;
-       case DTV_ISDBT_LAYERA_SEGMENT_COUNT:
-               c->layer[0].segment_count = tvp->u.data;
-               break;
-       case DTV_ISDBT_LAYERA_TIME_INTERLEAVING:
-               c->layer[0].interleaving = tvp->u.data;
-               break;
-       case DTV_ISDBT_LAYERB_FEC:
-               c->layer[1].fec = tvp->u.data;
-               break;
-       case DTV_ISDBT_LAYERB_MODULATION:
-               c->layer[1].modulation = tvp->u.data;
-               break;
-       case DTV_ISDBT_LAYERB_SEGMENT_COUNT:
-               c->layer[1].segment_count = tvp->u.data;
-               break;
-       case DTV_ISDBT_LAYERB_TIME_INTERLEAVING:
-               c->layer[1].interleaving = tvp->u.data;
-               break;
-       case DTV_ISDBT_LAYERC_FEC:
-               c->layer[2].fec = tvp->u.data;
-               break;
-       case DTV_ISDBT_LAYERC_MODULATION:
-               c->layer[2].modulation = tvp->u.data;
-               break;
-       case DTV_ISDBT_LAYERC_SEGMENT_COUNT:
-               c->layer[2].segment_count = tvp->u.data;
-               break;
-       case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
-               c->layer[2].interleaving = tvp->u.data;
-               break;
-       case DTV_ISDBS_TS_ID:
-               c->isdbs_ts_id = tvp->u.data;
-               break;
-       case DTV_DVBT2_PLP_ID:
-               c->dvbt2_plp_id = tvp->u.data;
-               break;
-
-       /* ATSC-MH */
-       case DTV_ATSCMH_PARADE_ID:
-               fe->dtv_property_cache.atscmh_parade_id = tvp->u.data;
-               break;
-       case DTV_ATSCMH_RS_FRAME_ENSEMBLE:
-               fe->dtv_property_cache.atscmh_rs_frame_ensemble = tvp->u.data;
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       return r;
-}
-
-static int dvb_frontend_ioctl(struct file *file,
-                       unsigned int cmd, void *parg)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dvb_frontend *fe = dvbdev->priv;
-       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       int err = -EOPNOTSUPP;
-
-       dprintk("%s (%d)\n", __func__, _IOC_NR(cmd));
-
-       if (fepriv->exit != DVB_FE_NO_EXIT)
-               return -ENODEV;
-
-       if ((file->f_flags & O_ACCMODE) == O_RDONLY &&
-           (_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT ||
-            cmd == FE_DISEQC_RECV_SLAVE_REPLY))
-               return -EPERM;
-
-       if (down_interruptible (&fepriv->sem))
-               return -ERESTARTSYS;
-
-       if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY))
-               err = dvb_frontend_ioctl_properties(file, cmd, parg);
-       else {
-               c->state = DTV_UNDEFINED;
-               err = dvb_frontend_ioctl_legacy(file, cmd, parg);
-       }
-
-       up(&fepriv->sem);
-       return err;
-}
-
-static int dvb_frontend_ioctl_properties(struct file *file,
-                       unsigned int cmd, void *parg)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dvb_frontend *fe = dvbdev->priv;
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-       int err = 0;
-
-       struct dtv_properties *tvps = NULL;
-       struct dtv_property *tvp = NULL;
-       int i;
-
-       dprintk("%s\n", __func__);
-
-       if(cmd == FE_SET_PROPERTY) {
-               tvps = (struct dtv_properties __user *)parg;
-
-               dprintk("%s() properties.num = %d\n", __func__, tvps->num);
-               dprintk("%s() properties.props = %p\n", __func__, tvps->props);
-
-               /* Put an arbitrary limit on the number of messages that can
-                * be sent at once */
-               if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
-                       return -EINVAL;
-
-               tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
-               if (!tvp) {
-                       err = -ENOMEM;
-                       goto out;
-               }
-
-               if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
-                       err = -EFAULT;
-                       goto out;
-               }
-
-               for (i = 0; i < tvps->num; i++) {
-                       err = dtv_property_process_set(fe, tvp + i, file);
-                       if (err < 0)
-                               goto out;
-                       (tvp + i)->result = err;
-               }
-
-               if (c->state == DTV_TUNE)
-                       dprintk("%s() Property cache is full, tuning\n", __func__);
-
-       } else
-       if(cmd == FE_GET_PROPERTY) {
-               tvps = (struct dtv_properties __user *)parg;
-
-               dprintk("%s() properties.num = %d\n", __func__, tvps->num);
-               dprintk("%s() properties.props = %p\n", __func__, tvps->props);
-
-               /* Put an arbitrary limit on the number of messages that can
-                * be sent at once */
-               if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS))
-                       return -EINVAL;
-
-               tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL);
-               if (!tvp) {
-                       err = -ENOMEM;
-                       goto out;
-               }
-
-               if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) {
-                       err = -EFAULT;
-                       goto out;
-               }
-
-               /*
-                * Fills the cache out struct with the cache contents, plus
-                * the data retrieved from get_frontend, if the frontend
-                * is not idle. Otherwise, returns the cached content
-                */
-               if (fepriv->state != FESTATE_IDLE) {
-                       err = dtv_get_frontend(fe, NULL);
-                       if (err < 0)
-                               goto out;
-               }
-               for (i = 0; i < tvps->num; i++) {
-                       err = dtv_property_process_get(fe, c, tvp + i, file);
-                       if (err < 0)
-                               goto out;
-                       (tvp + i)->result = err;
-               }
-
-               if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) {
-                       err = -EFAULT;
-                       goto out;
-               }
-
-       } else
-               err = -EOPNOTSUPP;
-
-out:
-       kfree(tvp);
-       return err;
-}
-
-static int dtv_set_frontend(struct dvb_frontend *fe)
-{
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-       struct dvb_frontend_tune_settings fetunesettings;
-       u32 rolloff = 0;
-
-       if (dvb_frontend_check_parameters(fe) < 0)
-               return -EINVAL;
-
-       /*
-        * Initialize output parameters to match the values given by
-        * the user. FE_SET_FRONTEND triggers an initial frontend event
-        * with status = 0, which copies output parameters to userspace.
-        */
-       dtv_property_legacy_params_sync(fe, &fepriv->parameters_out);
-
-       /*
-        * Be sure that the bandwidth will be filled for all
-        * non-satellite systems, as tuners need to know what
-        * low pass/Nyquist half filter should be applied, in
-        * order to avoid inter-channel noise.
-        *
-        * ISDB-T and DVB-T/T2 already sets bandwidth.
-        * ATSC and DVB-C don't set, so, the core should fill it.
-        *
-        * On DVB-C Annex A and C, the bandwidth is a function of
-        * the roll-off and symbol rate. Annex B defines different
-        * roll-off factors depending on the modulation. Fortunately,
-        * Annex B is only used with 6MHz, so there's no need to
-        * calculate it.
-        *
-        * While not officially supported, a side effect of handling it at
-        * the cache level is that a program could retrieve the bandwidth
-        * via DTV_BANDWIDTH_HZ, which may be useful for test programs.
-        */
-       switch (c->delivery_system) {
-       case SYS_ATSC:
-       case SYS_DVBC_ANNEX_B:
-               c->bandwidth_hz = 6000000;
-               break;
-       case SYS_DVBC_ANNEX_A:
-               rolloff = 115;
-               break;
-       case SYS_DVBC_ANNEX_C:
-               rolloff = 113;
-               break;
-       default:
-               break;
-       }
-       if (rolloff)
-               c->bandwidth_hz = (c->symbol_rate * rolloff) / 100;
-
-       /* force auto frequency inversion if requested */
-       if (dvb_force_auto_inversion)
-               c->inversion = INVERSION_AUTO;
-
-       /*
-        * without hierarchical coding code_rate_LP is irrelevant,
-        * so we tolerate the otherwise invalid FEC_NONE setting
-        */
-       if (c->hierarchy == HIERARCHY_NONE && c->code_rate_LP == FEC_NONE)
-               c->code_rate_LP = FEC_AUTO;
-
-       /* get frontend-specific tuning settings */
-       memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings));
-       if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) {
-               fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000;
-               fepriv->max_drift = fetunesettings.max_drift;
-               fepriv->step_size = fetunesettings.step_size;
-       } else {
-               /* default values */
-               switch (c->delivery_system) {
-               case SYS_DVBS:
-               case SYS_DVBS2:
-               case SYS_ISDBS:
-               case SYS_TURBO:
-               case SYS_DVBC_ANNEX_A:
-               case SYS_DVBC_ANNEX_C:
-                       fepriv->min_delay = HZ / 20;
-                       fepriv->step_size = c->symbol_rate / 16000;
-                       fepriv->max_drift = c->symbol_rate / 2000;
-                       break;
-               case SYS_DVBT:
-               case SYS_DVBT2:
-               case SYS_ISDBT:
-               case SYS_DTMB:
-                       fepriv->min_delay = HZ / 20;
-                       fepriv->step_size = fe->ops.info.frequency_stepsize * 2;
-                       fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
-                       break;
-               default:
-                       /*
-                        * FIXME: This sounds wrong! if freqency_stepsize is
-                        * defined by the frontend, why not use it???
-                        */
-                       fepriv->min_delay = HZ / 20;
-                       fepriv->step_size = 0; /* no zigzag */
-                       fepriv->max_drift = 0;
-                       break;
-               }
-       }
-       if (dvb_override_tune_delay > 0)
-               fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000;
-
-       fepriv->state = FESTATE_RETUNE;
-
-       /* Request the search algorithm to search */
-       fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN;
-
-       dvb_frontend_clear_events(fe);
-       dvb_frontend_add_event(fe, 0);
-       dvb_frontend_wakeup(fe);
-       fepriv->status = 0;
-
-       return 0;
-}
-
-
-static int dvb_frontend_ioctl_legacy(struct file *file,
-                       unsigned int cmd, void *parg)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dvb_frontend *fe = dvbdev->priv;
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
-       int err = -EOPNOTSUPP;
-
-       switch (cmd) {
-       case FE_GET_INFO: {
-               struct dvb_frontend_info* info = parg;
-
-               memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
-               dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max);
-
-               /*
-                * Associate the 4 delivery systems supported by DVBv3
-                * API with their DVBv5 counterpart. For the other standards,
-                * use the closest type, assuming that it would hopefully
-                * work with a DVBv3 application.
-                * It should be noticed that, on multi-frontend devices with
-                * different types (terrestrial and cable, for example),
-                * a pure DVBv3 application won't be able to use all delivery
-                * systems. Yet, changing the DVBv5 cache to the other delivery
-                * system should be enough for making it work.
-                */
-               switch (dvbv3_type(c->delivery_system)) {
-               case DVBV3_QPSK:
-                       info->type = FE_QPSK;
-                       break;
-               case DVBV3_ATSC:
-                       info->type = FE_ATSC;
-                       break;
-               case DVBV3_QAM:
-                       info->type = FE_QAM;
-                       break;
-               case DVBV3_OFDM:
-                       info->type = FE_OFDM;
-                       break;
-               default:
-                       printk(KERN_ERR
-                              "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n",
-                              __func__, c->delivery_system);
-                       fe->ops.info.type = FE_OFDM;
-               }
-               dprintk("current delivery system on cache: %d, V3 type: %d\n",
-                       c->delivery_system, fe->ops.info.type);
-
-               /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
-                * do it, it is done for it. */
-               info->caps |= FE_CAN_INVERSION_AUTO;
-               err = 0;
-               break;
-       }
-
-       case FE_READ_STATUS: {
-               fe_status_t* status = parg;
-
-               /* if retune was requested but hasn't occurred yet, prevent
-                * that user get signal state from previous tuning */
-               if (fepriv->state == FESTATE_RETUNE ||
-                   fepriv->state == FESTATE_ERROR) {
-                       err=0;
-                       *status = 0;
-                       break;
-               }
-
-               if (fe->ops.read_status)
-                       err = fe->ops.read_status(fe, status);
-               break;
-       }
-       case FE_READ_BER:
-               if (fe->ops.read_ber)
-                       err = fe->ops.read_ber(fe, (__u32*) parg);
-               break;
-
-       case FE_READ_SIGNAL_STRENGTH:
-               if (fe->ops.read_signal_strength)
-                       err = fe->ops.read_signal_strength(fe, (__u16*) parg);
-               break;
-
-       case FE_READ_SNR:
-               if (fe->ops.read_snr)
-                       err = fe->ops.read_snr(fe, (__u16*) parg);
-               break;
-
-       case FE_READ_UNCORRECTED_BLOCKS:
-               if (fe->ops.read_ucblocks)
-                       err = fe->ops.read_ucblocks(fe, (__u32*) parg);
-               break;
-
-
-       case FE_DISEQC_RESET_OVERLOAD:
-               if (fe->ops.diseqc_reset_overload) {
-                       err = fe->ops.diseqc_reset_overload(fe);
-                       fepriv->state = FESTATE_DISEQC;
-                       fepriv->status = 0;
-               }
-               break;
-
-       case FE_DISEQC_SEND_MASTER_CMD:
-               if (fe->ops.diseqc_send_master_cmd) {
-                       err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg);
-                       fepriv->state = FESTATE_DISEQC;
-                       fepriv->status = 0;
-               }
-               break;
-
-       case FE_DISEQC_SEND_BURST:
-               if (fe->ops.diseqc_send_burst) {
-                       err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg);
-                       fepriv->state = FESTATE_DISEQC;
-                       fepriv->status = 0;
-               }
-               break;
-
-       case FE_SET_TONE:
-               if (fe->ops.set_tone) {
-                       err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg);
-                       fepriv->tone = (fe_sec_tone_mode_t) parg;
-                       fepriv->state = FESTATE_DISEQC;
-                       fepriv->status = 0;
-               }
-               break;
-
-       case FE_SET_VOLTAGE:
-               if (fe->ops.set_voltage) {
-                       err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg);
-                       fepriv->voltage = (fe_sec_voltage_t) parg;
-                       fepriv->state = FESTATE_DISEQC;
-                       fepriv->status = 0;
-               }
-               break;
-
-       case FE_DISHNETWORK_SEND_LEGACY_CMD:
-               if (fe->ops.dishnetwork_send_legacy_command) {
-                       err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg);
-                       fepriv->state = FESTATE_DISEQC;
-                       fepriv->status = 0;
-               } else if (fe->ops.set_voltage) {
-                       /*
-                        * NOTE: This is a fallback condition.  Some frontends
-                        * (stv0299 for instance) take longer than 8msec to
-                        * respond to a set_voltage command.  Those switches
-                        * need custom routines to switch properly.  For all
-                        * other frontends, the following should work ok.
-                        * Dish network legacy switches (as used by Dish500)
-                        * are controlled by sending 9-bit command words
-                        * spaced 8msec apart.
-                        * the actual command word is switch/port dependent
-                        * so it is up to the userspace application to send
-                        * the right command.
-                        * The command must always start with a '0' after
-                        * initialization, so parg is 8 bits and does not
-                        * include the initialization or start bit
-                        */
-                       unsigned long swcmd = ((unsigned long) parg) << 1;
-                       struct timeval nexttime;
-                       struct timeval tv[10];
-                       int i;
-                       u8 last = 1;
-                       if (dvb_frontend_debug)
-                               printk("%s switch command: 0x%04lx\n", __func__, swcmd);
-                       do_gettimeofday(&nexttime);
-                       if (dvb_frontend_debug)
-                               memcpy(&tv[0], &nexttime, sizeof(struct timeval));
-                       /* before sending a command, initialize by sending
-                        * a 32ms 18V to the switch
-                        */
-                       fe->ops.set_voltage(fe, SEC_VOLTAGE_18);
-                       dvb_frontend_sleep_until(&nexttime, 32000);
-
-                       for (i = 0; i < 9; i++) {
-                               if (dvb_frontend_debug)
-                                       do_gettimeofday(&tv[i + 1]);
-                               if ((swcmd & 0x01) != last) {
-                                       /* set voltage to (last ? 13V : 18V) */
-                                       fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18);
-                                       last = (last) ? 0 : 1;
-                               }
-                               swcmd = swcmd >> 1;
-                               if (i != 8)
-                                       dvb_frontend_sleep_until(&nexttime, 8000);
-                       }
-                       if (dvb_frontend_debug) {
-                               printk("%s(%d): switch delay (should be 32k followed by all 8k\n",
-                                       __func__, fe->dvb->num);
-                               for (i = 1; i < 10; i++)
-                                       printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i]));
-                       }
-                       err = 0;
-                       fepriv->state = FESTATE_DISEQC;
-                       fepriv->status = 0;
-               }
-               break;
-
-       case FE_DISEQC_RECV_SLAVE_REPLY:
-               if (fe->ops.diseqc_recv_slave_reply)
-                       err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg);
-               break;
-
-       case FE_ENABLE_HIGH_LNB_VOLTAGE:
-               if (fe->ops.enable_high_lnb_voltage)
-                       err = fe->ops.enable_high_lnb_voltage(fe, (long) parg);
-               break;
-
-       case FE_SET_FRONTEND:
-               err = set_delivery_system(fe, SYS_UNDEFINED);
-               if (err)
-                       break;
-
-               err = dtv_property_cache_sync(fe, c, parg);
-               if (err)
-                       break;
-               err = dtv_set_frontend(fe);
-               break;
-       case FE_GET_EVENT:
-               err = dvb_frontend_get_event (fe, parg, file->f_flags);
-               break;
-
-       case FE_GET_FRONTEND:
-               err = dtv_get_frontend(fe, parg);
-               break;
-
-       case FE_SET_FRONTEND_TUNE_MODE:
-               fepriv->tune_mode_flags = (unsigned long) parg;
-               err = 0;
-               break;
-       };
-
-       return err;
-}
-
-
-static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dvb_frontend *fe = dvbdev->priv;
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-
-       dprintk ("%s\n", __func__);
-
-       poll_wait (file, &fepriv->events.wait_queue, wait);
-
-       if (fepriv->events.eventw != fepriv->events.eventr)
-               return (POLLIN | POLLRDNORM | POLLPRI);
-
-       return 0;
-}
-
-static int dvb_frontend_open(struct inode *inode, struct file *file)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dvb_frontend *fe = dvbdev->priv;
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       struct dvb_adapter *adapter = fe->dvb;
-       int ret;
-
-       dprintk ("%s\n", __func__);
-       if (fepriv->exit == DVB_FE_DEVICE_REMOVED)
-               return -ENODEV;
-
-       if (adapter->mfe_shared) {
-               mutex_lock (&adapter->mfe_lock);
-
-               if (adapter->mfe_dvbdev == NULL)
-                       adapter->mfe_dvbdev = dvbdev;
-
-               else if (adapter->mfe_dvbdev != dvbdev) {
-                       struct dvb_device
-                               *mfedev = adapter->mfe_dvbdev;
-                       struct dvb_frontend
-                               *mfe = mfedev->priv;
-                       struct dvb_frontend_private
-                               *mfepriv = mfe->frontend_priv;
-                       int mferetry = (dvb_mfe_wait_time << 1);
-
-                       mutex_unlock (&adapter->mfe_lock);
-                       while (mferetry-- && (mfedev->users != -1 ||
-                                       mfepriv->thread != NULL)) {
-                               if(msleep_interruptible(500)) {
-                                       if(signal_pending(current))
-                                               return -EINTR;
-                               }
-                       }
-
-                       mutex_lock (&adapter->mfe_lock);
-                       if(adapter->mfe_dvbdev != dvbdev) {
-                               mfedev = adapter->mfe_dvbdev;
-                               mfe = mfedev->priv;
-                               mfepriv = mfe->frontend_priv;
-                               if (mfedev->users != -1 ||
-                                               mfepriv->thread != NULL) {
-                                       mutex_unlock (&adapter->mfe_lock);
-                                       return -EBUSY;
-                               }
-                               adapter->mfe_dvbdev = dvbdev;
-                       }
-               }
-       }
-
-       if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) {
-               if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0)
-                       goto err0;
-
-               /* If we took control of the bus, we need to force
-                  reinitialization.  This is because many ts_bus_ctrl()
-                  functions strobe the RESET pin on the demod, and if the
-                  frontend thread already exists then the dvb_init() routine
-                  won't get called (which is what usually does initial
-                  register configuration). */
-               fepriv->reinitialise = 1;
-       }
-
-       if ((ret = dvb_generic_open (inode, file)) < 0)
-               goto err1;
-
-       if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
-               /* normal tune mode when opened R/W */
-               fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT;
-               fepriv->tone = -1;
-               fepriv->voltage = -1;
-
-               ret = dvb_frontend_start (fe);
-               if (ret)
-                       goto err2;
-
-               /*  empty event queue */
-               fepriv->events.eventr = fepriv->events.eventw = 0;
-       }
-
-       if (adapter->mfe_shared)
-               mutex_unlock (&adapter->mfe_lock);
-       return ret;
-
-err2:
-       dvb_generic_release(inode, file);
-err1:
-       if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl)
-               fe->ops.ts_bus_ctrl(fe, 0);
-err0:
-       if (adapter->mfe_shared)
-               mutex_unlock (&adapter->mfe_lock);
-       return ret;
-}
-
-static int dvb_frontend_release(struct inode *inode, struct file *file)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dvb_frontend *fe = dvbdev->priv;
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       int ret;
-
-       dprintk ("%s\n", __func__);
-
-       if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
-               fepriv->release_jiffies = jiffies;
-               mb();
-       }
-
-       ret = dvb_generic_release (inode, file);
-
-       if (dvbdev->users == -1) {
-               wake_up(&fepriv->wait_queue);
-               if (fepriv->exit != DVB_FE_NO_EXIT) {
-                       fops_put(file->f_op);
-                       file->f_op = NULL;
-                       wake_up(&dvbdev->wait_queue);
-               }
-               if (fe->ops.ts_bus_ctrl)
-                       fe->ops.ts_bus_ctrl(fe, 0);
-       }
-
-       return ret;
-}
-
-static const struct file_operations dvb_frontend_fops = {
-       .owner          = THIS_MODULE,
-       .unlocked_ioctl = dvb_generic_ioctl,
-       .poll           = dvb_frontend_poll,
-       .open           = dvb_frontend_open,
-       .release        = dvb_frontend_release,
-       .llseek         = noop_llseek,
-};
-
-int dvb_register_frontend(struct dvb_adapter* dvb,
-                         struct dvb_frontend* fe)
-{
-       struct dvb_frontend_private *fepriv;
-       static const struct dvb_device dvbdev_template = {
-               .users = ~0,
-               .writers = 1,
-               .readers = (~0)-1,
-               .fops = &dvb_frontend_fops,
-               .kernel_ioctl = dvb_frontend_ioctl
-       };
-
-       dprintk ("%s\n", __func__);
-
-       if (mutex_lock_interruptible(&frontend_mutex))
-               return -ERESTARTSYS;
-
-       fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL);
-       if (fe->frontend_priv == NULL) {
-               mutex_unlock(&frontend_mutex);
-               return -ENOMEM;
-       }
-       fepriv = fe->frontend_priv;
-
-       sema_init(&fepriv->sem, 1);
-       init_waitqueue_head (&fepriv->wait_queue);
-       init_waitqueue_head (&fepriv->events.wait_queue);
-       mutex_init(&fepriv->events.mtx);
-       fe->dvb = dvb;
-       fepriv->inversion = INVERSION_OFF;
-
-       printk ("DVB: registering adapter %i frontend %i (%s)...\n",
-               fe->dvb->num,
-               fe->id,
-               fe->ops.info.name);
-
-       dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template,
-                            fe, DVB_DEVICE_FRONTEND);
-
-       /*
-        * Initialize the cache to the proper values according with the
-        * first supported delivery system (ops->delsys[0])
-        */
-
-        fe->dtv_property_cache.delivery_system = fe->ops.delsys[0];
-       dvb_frontend_clear_cache(fe);
-
-       mutex_unlock(&frontend_mutex);
-       return 0;
-}
-EXPORT_SYMBOL(dvb_register_frontend);
-
-int dvb_unregister_frontend(struct dvb_frontend* fe)
-{
-       struct dvb_frontend_private *fepriv = fe->frontend_priv;
-       dprintk ("%s\n", __func__);
-
-       mutex_lock(&frontend_mutex);
-       dvb_frontend_stop (fe);
-       mutex_unlock(&frontend_mutex);
-
-       if (fepriv->dvbdev->users < -1)
-               wait_event(fepriv->dvbdev->wait_queue,
-                               fepriv->dvbdev->users==-1);
-
-       mutex_lock(&frontend_mutex);
-       dvb_unregister_device (fepriv->dvbdev);
-
-       /* fe is invalid now */
-       kfree(fepriv);
-       mutex_unlock(&frontend_mutex);
-       return 0;
-}
-EXPORT_SYMBOL(dvb_unregister_frontend);
-
-#ifdef CONFIG_MEDIA_ATTACH
-void dvb_frontend_detach(struct dvb_frontend* fe)
-{
-       void *ptr;
-
-       if (fe->ops.release_sec) {
-               fe->ops.release_sec(fe);
-               symbol_put_addr(fe->ops.release_sec);
-       }
-       if (fe->ops.tuner_ops.release) {
-               fe->ops.tuner_ops.release(fe);
-               symbol_put_addr(fe->ops.tuner_ops.release);
-       }
-       if (fe->ops.analog_ops.release) {
-               fe->ops.analog_ops.release(fe);
-               symbol_put_addr(fe->ops.analog_ops.release);
-       }
-       ptr = (void*)fe->ops.release;
-       if (ptr) {
-               fe->ops.release(fe);
-               symbol_put_addr(ptr);
-       }
-}
-#else
-void dvb_frontend_detach(struct dvb_frontend* fe)
-{
-       if (fe->ops.release_sec)
-               fe->ops.release_sec(fe);
-       if (fe->ops.tuner_ops.release)
-               fe->ops.tuner_ops.release(fe);
-       if (fe->ops.analog_ops.release)
-               fe->ops.analog_ops.release(fe);
-       if (fe->ops.release)
-               fe->ops.release(fe);
-}
-#endif
-EXPORT_SYMBOL(dvb_frontend_detach);
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
deleted file mode 100644 (file)
index de410cc..0000000
+++ /dev/null
@@ -1,425 +0,0 @@
-/*
- * dvb_frontend.h
- *
- * Copyright (C) 2001 convergence integrated media GmbH
- * Copyright (C) 2004 convergence GmbH
- *
- * Written by Ralph Metzler
- * Overhauled by Holger Waechtler
- * Kernel I2C stuff by Michael Hunold <hunold@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.
- *
- */
-
-#ifndef _DVB_FRONTEND_H_
-#define _DVB_FRONTEND_H_
-
-#include <linux/types.h>
-#include <linux/sched.h>
-#include <linux/ioctl.h>
-#include <linux/i2c.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/delay.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-
-#include <linux/dvb/frontend.h>
-
-#include "dvbdev.h"
-
-/*
- * Maximum number of Delivery systems per frontend. It
- * should be smaller or equal to 32
- */
-#define MAX_DELSYS     8
-
-struct dvb_frontend_tune_settings {
-       int min_delay_ms;
-       int step_size;
-       int max_drift;
-};
-
-struct dvb_frontend;
-
-struct dvb_tuner_info {
-       char name[128];
-
-       u32 frequency_min;
-       u32 frequency_max;
-       u32 frequency_step;
-
-       u32 bandwidth_min;
-       u32 bandwidth_max;
-       u32 bandwidth_step;
-};
-
-struct analog_parameters {
-       unsigned int frequency;
-       unsigned int mode;
-       unsigned int audmode;
-       u64 std;
-};
-
-enum dvbfe_modcod {
-       DVBFE_MODCOD_DUMMY_PLFRAME      = 0,
-       DVBFE_MODCOD_QPSK_1_4,
-       DVBFE_MODCOD_QPSK_1_3,
-       DVBFE_MODCOD_QPSK_2_5,
-       DVBFE_MODCOD_QPSK_1_2,
-       DVBFE_MODCOD_QPSK_3_5,
-       DVBFE_MODCOD_QPSK_2_3,
-       DVBFE_MODCOD_QPSK_3_4,
-       DVBFE_MODCOD_QPSK_4_5,
-       DVBFE_MODCOD_QPSK_5_6,
-       DVBFE_MODCOD_QPSK_8_9,
-       DVBFE_MODCOD_QPSK_9_10,
-       DVBFE_MODCOD_8PSK_3_5,
-       DVBFE_MODCOD_8PSK_2_3,
-       DVBFE_MODCOD_8PSK_3_4,
-       DVBFE_MODCOD_8PSK_5_6,
-       DVBFE_MODCOD_8PSK_8_9,
-       DVBFE_MODCOD_8PSK_9_10,
-       DVBFE_MODCOD_16APSK_2_3,
-       DVBFE_MODCOD_16APSK_3_4,
-       DVBFE_MODCOD_16APSK_4_5,
-       DVBFE_MODCOD_16APSK_5_6,
-       DVBFE_MODCOD_16APSK_8_9,
-       DVBFE_MODCOD_16APSK_9_10,
-       DVBFE_MODCOD_32APSK_3_4,
-       DVBFE_MODCOD_32APSK_4_5,
-       DVBFE_MODCOD_32APSK_5_6,
-       DVBFE_MODCOD_32APSK_8_9,
-       DVBFE_MODCOD_32APSK_9_10,
-       DVBFE_MODCOD_RESERVED_1,
-       DVBFE_MODCOD_BPSK_1_3,
-       DVBFE_MODCOD_BPSK_1_4,
-       DVBFE_MODCOD_RESERVED_2
-};
-
-enum tuner_param {
-       DVBFE_TUNER_FREQUENCY           = (1 <<  0),
-       DVBFE_TUNER_TUNERSTEP           = (1 <<  1),
-       DVBFE_TUNER_IFFREQ              = (1 <<  2),
-       DVBFE_TUNER_BANDWIDTH           = (1 <<  3),
-       DVBFE_TUNER_REFCLOCK            = (1 <<  4),
-       DVBFE_TUNER_IQSENSE             = (1 <<  5),
-       DVBFE_TUNER_DUMMY               = (1 << 31)
-};
-
-/*
- * ALGO_HW: (Hardware Algorithm)
- * ----------------------------------------------------------------
- * Devices that support this algorithm do everything in hardware
- * and no software support is needed to handle them.
- * Requesting these devices to LOCK is the only thing required,
- * device is supposed to do everything in the hardware.
- *
- * ALGO_SW: (Software Algorithm)
- * ----------------------------------------------------------------
- * These are dumb devices, that require software to do everything
- *
- * ALGO_CUSTOM: (Customizable Agorithm)
- * ----------------------------------------------------------------
- * Devices having this algorithm can be customized to have specific
- * algorithms in the frontend driver, rather than simply doing a
- * software zig-zag. In this case the zigzag maybe hardware assisted
- * or it maybe completely done in hardware. In all cases, usage of
- * this algorithm, in conjunction with the search and track
- * callbacks, utilizes the driver specific algorithm.
- *
- * ALGO_RECOVERY: (Recovery Algorithm)
- * ----------------------------------------------------------------
- * These devices have AUTO recovery capabilities from LOCK failure
- */
-enum dvbfe_algo {
-       DVBFE_ALGO_HW                   = (1 <<  0),
-       DVBFE_ALGO_SW                   = (1 <<  1),
-       DVBFE_ALGO_CUSTOM               = (1 <<  2),
-       DVBFE_ALGO_RECOVERY             = (1 << 31)
-};
-
-struct tuner_state {
-       u32 frequency;
-       u32 tunerstep;
-       u32 ifreq;
-       u32 bandwidth;
-       u32 iqsense;
-       u32 refclock;
-};
-
-/*
- * search callback possible return status
- *
- * DVBFE_ALGO_SEARCH_SUCCESS
- * The frontend search algorithm completed and returned successfully
- *
- * DVBFE_ALGO_SEARCH_ASLEEP
- * The frontend search algorithm is sleeping
- *
- * DVBFE_ALGO_SEARCH_FAILED
- * The frontend search for a signal failed
- *
- * DVBFE_ALGO_SEARCH_INVALID
- * The frontend search algorith was probably supplied with invalid
- * parameters and the search is an invalid one
- *
- * DVBFE_ALGO_SEARCH_ERROR
- * The frontend search algorithm failed due to some error
- *
- * DVBFE_ALGO_SEARCH_AGAIN
- * The frontend search algorithm was requested to search again
- */
-enum dvbfe_search {
-       DVBFE_ALGO_SEARCH_SUCCESS       = (1 <<  0),
-       DVBFE_ALGO_SEARCH_ASLEEP        = (1 <<  1),
-       DVBFE_ALGO_SEARCH_FAILED        = (1 <<  2),
-       DVBFE_ALGO_SEARCH_INVALID       = (1 <<  3),
-       DVBFE_ALGO_SEARCH_AGAIN         = (1 <<  4),
-       DVBFE_ALGO_SEARCH_ERROR         = (1 << 31),
-};
-
-
-struct dvb_tuner_ops {
-
-       struct dvb_tuner_info info;
-
-       int (*release)(struct dvb_frontend *fe);
-       int (*init)(struct dvb_frontend *fe);
-       int (*sleep)(struct dvb_frontend *fe);
-
-       /** This is for simple PLLs - set all parameters in one go. */
-       int (*set_params)(struct dvb_frontend *fe);
-       int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p);
-
-       /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */
-       int (*calc_regs)(struct dvb_frontend *fe, u8 *buf, int buf_len);
-
-       /** This is to allow setting tuner-specific configs */
-       int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
-
-       int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency);
-       int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
-       int (*get_if_frequency)(struct dvb_frontend *fe, u32 *frequency);
-
-#define TUNER_STATUS_LOCKED 1
-#define TUNER_STATUS_STEREO 2
-       int (*get_status)(struct dvb_frontend *fe, u32 *status);
-       int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength);
-       int (*get_afc)(struct dvb_frontend *fe, s32 *afc);
-
-       /** These are provided separately from set_params in order to facilitate silicon
-        * tuners which require sophisticated tuning loops, controlling each parameter separately. */
-       int (*set_frequency)(struct dvb_frontend *fe, u32 frequency);
-       int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
-
-       /*
-        * These are provided separately from set_params in order to facilitate silicon
-        * tuners which require sophisticated tuning loops, controlling each parameter separately.
-        */
-       int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
-       int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state);
-};
-
-struct analog_demod_info {
-       char *name;
-};
-
-struct analog_demod_ops {
-
-       struct analog_demod_info info;
-
-       void (*set_params)(struct dvb_frontend *fe,
-                          struct analog_parameters *params);
-       int  (*has_signal)(struct dvb_frontend *fe);
-       int  (*get_afc)(struct dvb_frontend *fe);
-       void (*tuner_status)(struct dvb_frontend *fe);
-       void (*standby)(struct dvb_frontend *fe);
-       void (*release)(struct dvb_frontend *fe);
-       int  (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable);
-
-       /** This is to allow setting tuner-specific configuration */
-       int (*set_config)(struct dvb_frontend *fe, void *priv_cfg);
-};
-
-struct dtv_frontend_properties;
-
-struct dvb_frontend_ops {
-
-       struct dvb_frontend_info info;
-
-       u8 delsys[MAX_DELSYS];
-
-       void (*release)(struct dvb_frontend* fe);
-       void (*release_sec)(struct dvb_frontend* fe);
-
-       int (*init)(struct dvb_frontend* fe);
-       int (*sleep)(struct dvb_frontend* fe);
-
-       int (*write)(struct dvb_frontend* fe, const u8 buf[], int len);
-
-       /* if this is set, it overrides the default swzigzag */
-       int (*tune)(struct dvb_frontend* fe,
-                   bool re_tune,
-                   unsigned int mode_flags,
-                   unsigned int *delay,
-                   fe_status_t *status);
-       /* get frontend tuning algorithm from the module */
-       enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe);
-
-       /* these two are only used for the swzigzag code */
-       int (*set_frontend)(struct dvb_frontend *fe);
-       int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings);
-
-       int (*get_frontend)(struct dvb_frontend *fe);
-
-       int (*read_status)(struct dvb_frontend* fe, fe_status_t* status);
-       int (*read_ber)(struct dvb_frontend* fe, u32* ber);
-       int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength);
-       int (*read_snr)(struct dvb_frontend* fe, u16* snr);
-       int (*read_ucblocks)(struct dvb_frontend* fe, u32* ucblocks);
-
-       int (*diseqc_reset_overload)(struct dvb_frontend* fe);
-       int (*diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd);
-       int (*diseqc_recv_slave_reply)(struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply);
-       int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd);
-       int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone);
-       int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
-       int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg);
-       int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd);
-       int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
-       int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire);
-
-       /* These callbacks are for devices that implement their own
-        * tuning algorithms, rather than a simple swzigzag
-        */
-       enum dvbfe_search (*search)(struct dvb_frontend *fe);
-
-       struct dvb_tuner_ops tuner_ops;
-       struct analog_demod_ops analog_ops;
-
-       int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
-       int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
-};
-
-#ifdef __DVB_CORE__
-#define MAX_EVENT 8
-
-struct dvb_fe_events {
-       struct dvb_frontend_event events[MAX_EVENT];
-       int                       eventw;
-       int                       eventr;
-       int                       overflow;
-       wait_queue_head_t         wait_queue;
-       struct mutex              mtx;
-};
-#endif
-
-struct dtv_frontend_properties {
-
-       /* Cache State */
-       u32                     state;
-
-       u32                     frequency;
-       fe_modulation_t         modulation;
-
-       fe_sec_voltage_t        voltage;
-       fe_sec_tone_mode_t      sectone;
-       fe_spectral_inversion_t inversion;
-       fe_code_rate_t          fec_inner;
-       fe_transmit_mode_t      transmission_mode;
-       u32                     bandwidth_hz;   /* 0 = AUTO */
-       fe_guard_interval_t     guard_interval;
-       fe_hierarchy_t          hierarchy;
-       u32                     symbol_rate;
-       fe_code_rate_t          code_rate_HP;
-       fe_code_rate_t          code_rate_LP;
-
-       fe_pilot_t              pilot;
-       fe_rolloff_t            rolloff;
-
-       fe_delivery_system_t    delivery_system;
-
-       enum fe_interleaving    interleaving;
-
-       /* ISDB-T specifics */
-       u8                      isdbt_partial_reception;
-       u8                      isdbt_sb_mode;
-       u8                      isdbt_sb_subchannel;
-       u32                     isdbt_sb_segment_idx;
-       u32                     isdbt_sb_segment_count;
-       u8                      isdbt_layer_enabled;
-       struct {
-           u8                  segment_count;
-           fe_code_rate_t      fec;
-           fe_modulation_t     modulation;
-           u8                  interleaving;
-       } layer[3];
-
-       /* ISDB-T specifics */
-       u32                     isdbs_ts_id;
-
-       /* DVB-T2 specifics */
-       u32                     dvbt2_plp_id;
-
-       /* ATSC-MH specifics */
-       u8                      atscmh_fic_ver;
-       u8                      atscmh_parade_id;
-       u8                      atscmh_nog;
-       u8                      atscmh_tnog;
-       u8                      atscmh_sgn;
-       u8                      atscmh_prc;
-
-       u8                      atscmh_rs_frame_mode;
-       u8                      atscmh_rs_frame_ensemble;
-       u8                      atscmh_rs_code_mode_pri;
-       u8                      atscmh_rs_code_mode_sec;
-       u8                      atscmh_sccc_block_mode;
-       u8                      atscmh_sccc_code_mode_a;
-       u8                      atscmh_sccc_code_mode_b;
-       u8                      atscmh_sccc_code_mode_c;
-       u8                      atscmh_sccc_code_mode_d;
-};
-
-struct dvb_frontend {
-       struct dvb_frontend_ops ops;
-       struct dvb_adapter *dvb;
-       void *demodulator_priv;
-       void *tuner_priv;
-       void *frontend_priv;
-       void *sec_priv;
-       void *analog_demod_priv;
-       struct dtv_frontend_properties dtv_property_cache;
-#define DVB_FRONTEND_COMPONENT_TUNER 0
-#define DVB_FRONTEND_COMPONENT_DEMOD 1
-       int (*callback)(void *adapter_priv, int component, int cmd, int arg);
-       int id;
-};
-
-extern int dvb_register_frontend(struct dvb_adapter *dvb,
-                                struct dvb_frontend *fe);
-
-extern int dvb_unregister_frontend(struct dvb_frontend *fe);
-
-extern void dvb_frontend_detach(struct dvb_frontend *fe);
-
-extern void dvb_frontend_reinitialise(struct dvb_frontend *fe);
-
-extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec);
-extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime);
-
-#endif
diff --git a/drivers/media/dvb/dvb-core/dvb_math.c b/drivers/media/dvb/dvb-core/dvb_math.c
deleted file mode 100644 (file)
index beb7c93..0000000
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * dvb-math provides some complex fixed-point math
- * operations shared between the dvb related stuff
- *
- * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/bitops.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/bug.h>
-#include "dvb_math.h"
-
-static const unsigned short logtable[256] = {
-       0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
-       0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508,
-       0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6,
-       0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37,
-       0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f,
-       0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41,
-       0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1,
-       0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142,
-       0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68,
-       0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355,
-       0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c,
-       0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490,
-       0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3,
-       0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507,
-       0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe,
-       0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca,
-       0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c,
-       0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7,
-       0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c,
-       0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c,
-       0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a,
-       0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065,
-       0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730,
-       0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc,
-       0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469,
-       0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9,
-       0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c,
-       0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765,
-       0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83,
-       0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387,
-       0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973,
-       0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47
-};
-
-unsigned int intlog2(u32 value)
-{
-       /**
-        *      returns: log2(value) * 2^24
-        *      wrong result if value = 0 (log2(0) is undefined)
-        */
-       unsigned int msb;
-       unsigned int logentry;
-       unsigned int significand;
-       unsigned int interpolation;
-
-       if (unlikely(value == 0)) {
-               WARN_ON(1);
-               return 0;
-       }
-
-       /* first detect the msb (count begins at 0) */
-       msb = fls(value) - 1;
-
-       /**
-        *      now we use a logtable after the following method:
-        *
-        *      log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24
-        *      where x = msb and therefore 1 <= y < 2
-        *      first y is determined by shifting the value left
-        *      so that msb is bit 31
-        *              0x00231f56 -> 0x8C7D5800
-        *      the result is y * 2^31 -> "significand"
-        *      then the highest 9 bits are used for a table lookup
-        *      the highest bit is discarded because it's always set
-        *      the highest nine bits in our example are 100011000
-        *      so we would use the entry 0x18
-        */
-       significand = value << (31 - msb);
-       logentry = (significand >> 23) & 0xff;
-
-       /**
-        *      last step we do is interpolation because of the
-        *      limitations of the log table the error is that part of
-        *      the significand which isn't used for lookup then we
-        *      compute the ratio between the error and the next table entry
-        *      and interpolate it between the log table entry used and the
-        *      next one the biggest error possible is 0x7fffff
-        *      (in our example it's 0x7D5800)
-        *      needed value for next table entry is 0x800000
-        *      so the interpolation is
-        *      (error / 0x800000) * (logtable_next - logtable_current)
-        *      in the implementation the division is moved to the end for
-        *      better accuracy there is also an overflow correction if
-        *      logtable_next is 256
-        */
-       interpolation = ((significand & 0x7fffff) *
-                       ((logtable[(logentry + 1) & 0xff] -
-                         logtable[logentry]) & 0xffff)) >> 15;
-
-       /* now we return the result */
-       return ((msb << 24) + (logtable[logentry] << 8) + interpolation);
-}
-EXPORT_SYMBOL(intlog2);
-
-unsigned int intlog10(u32 value)
-{
-       /**
-        *      returns: log10(value) * 2^24
-        *      wrong result if value = 0 (log10(0) is undefined)
-        */
-       u64 log;
-
-       if (unlikely(value == 0)) {
-               WARN_ON(1);
-               return 0;
-       }
-
-       log = intlog2(value);
-
-       /**
-        *      we use the following method:
-        *      log10(x) = log2(x) * log10(2)
-        */
-
-       return (log * 646456993) >> 31;
-}
-EXPORT_SYMBOL(intlog10);
diff --git a/drivers/media/dvb/dvb-core/dvb_math.h b/drivers/media/dvb/dvb-core/dvb_math.h
deleted file mode 100644 (file)
index aecc867..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * dvb-math provides some complex fixed-point math
- * operations shared between the dvb related stuff
- *
- * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com)
- *
- * This library 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef __DVB_MATH_H
-#define __DVB_MATH_H
-
-#include <linux/types.h>
-
-/**
- * computes log2 of a value; the result is shifted left by 24 bits
- *
- * to use rational values you can use the following method:
- *   intlog2(value) = intlog2(value * 2^x) - x * 2^24
- *
- * example: intlog2(8) will give 3 << 24 = 3 * 2^24
- * example: intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24
- * example: intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24
- *
- * @param value The value (must be != 0)
- * @return log2(value) * 2^24
- */
-extern unsigned int intlog2(u32 value);
-
-/**
- * computes log10 of a value; the result is shifted left by 24 bits
- *
- * to use rational values you can use the following method:
- *   intlog10(value) = intlog10(value * 10^x) - x * 2^24
- *
- * example: intlog10(1000) will give 3 << 24 = 3 * 2^24
- *   due to the implementation intlog10(1000) might be not exactly 3 * 2^24
- *
- * look at intlog2 for similar examples
- *
- * @param value The value (must be != 0)
- * @return log10(value) * 2^24
- */
-extern unsigned int intlog10(u32 value);
-
-#endif
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
deleted file mode 100644 (file)
index 8766ce8..0000000
+++ /dev/null
@@ -1,1516 +0,0 @@
-/*
- * dvb_net.c
- *
- * Copyright (C) 2001 Convergence integrated media GmbH
- *                    Ralph Metzler <ralph@convergence.de>
- * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>
- *
- * ULE Decapsulation code:
- * Copyright (C) 2003, 2004 gcs - Global Communication & Services GmbH.
- *                      and Department of Scientific Computing
- *                          Paris Lodron University of Salzburg.
- *                          Hilmar Linder <hlinder@cosy.sbg.ac.at>
- *                      and Wolfram Stering <wstering@cosy.sbg.ac.at>
- *
- * ULE Decaps according to RFC 4326.
- *
- * 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
- */
-
-/*
- * ULE ChangeLog:
- * Feb 2004: hl/ws v1: Implementing draft-fair-ipdvb-ule-01.txt
- *
- * Dec 2004: hl/ws v2: Implementing draft-ietf-ipdvb-ule-03.txt:
- *                       ULE Extension header handling.
- *                     Bugreports by Moritz Vieth and Hanno Tersteegen,
- *                       Fraunhofer Institute for Open Communication Systems
- *                       Competence Center for Advanced Satellite Communications.
- *                     Bugfixes and robustness improvements.
- *                     Filtering on dest MAC addresses, if present (D-Bit = 0)
- *                     ULE_DEBUG compile-time option.
- * Apr 2006: cp v3:    Bugfixes and compliency with RFC 4326 (ULE) by
- *                       Christian Praehauser <cpraehaus@cosy.sbg.ac.at>,
- *                       Paris Lodron University of Salzburg.
- */
-
-/*
- * FIXME / TODO (dvb_net.c):
- *
- * Unloading does not work for 2.6.9 kernels: a refcount doesn't go to zero.
- *
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/dvb/net.h>
-#include <linux/uio.h>
-#include <asm/uaccess.h>
-#include <linux/crc32.h>
-#include <linux/mutex.h>
-#include <linux/sched.h>
-
-#include "dvb_demux.h"
-#include "dvb_net.h"
-
-static int dvb_net_debug;
-module_param(dvb_net_debug, int, 0444);
-MODULE_PARM_DESC(dvb_net_debug, "enable debug messages");
-
-#define dprintk(x...) do { if (dvb_net_debug) printk(x); } while (0)
-
-
-static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
-{
-       unsigned int j;
-       for (j = 0; j < cnt; j++)
-               c = crc32_be( c, iov[j].iov_base, iov[j].iov_len );
-       return c;
-}
-
-
-#define DVB_NET_MULTICAST_MAX 10
-
-#undef ULE_DEBUG
-
-#ifdef ULE_DEBUG
-
-#define MAC_ADDR_PRINTFMT "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"
-#define MAX_ADDR_PRINTFMT_ARGS(macap) (macap)[0],(macap)[1],(macap)[2],(macap)[3],(macap)[4],(macap)[5]
-
-#define isprint(c)     ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
-
-static void hexdump( const unsigned char *buf, unsigned short len )
-{
-       char str[80], octet[10];
-       int ofs, i, l;
-
-       for (ofs = 0; ofs < len; ofs += 16) {
-               sprintf( str, "%03d: ", ofs );
-
-               for (i = 0; i < 16; i++) {
-                       if ((i + ofs) < len)
-                               sprintf( octet, "%02x ", buf[ofs + i] );
-                       else
-                               strcpy( octet, "   " );
-
-                       strcat( str, octet );
-               }
-               strcat( str, "  " );
-               l = strlen( str );
-
-               for (i = 0; (i < 16) && ((i + ofs) < len); i++)
-                       str[l++] = isprint( buf[ofs + i] ) ? buf[ofs + i] : '.';
-
-               str[l] = '\0';
-               printk( KERN_WARNING "%s\n", str );
-       }
-}
-
-#endif
-
-struct dvb_net_priv {
-       int in_use;
-       u16 pid;
-       struct net_device *net;
-       struct dvb_net *host;
-       struct dmx_demux *demux;
-       struct dmx_section_feed *secfeed;
-       struct dmx_section_filter *secfilter;
-       struct dmx_ts_feed *tsfeed;
-       int multi_num;
-       struct dmx_section_filter *multi_secfilter[DVB_NET_MULTICAST_MAX];
-       unsigned char multi_macs[DVB_NET_MULTICAST_MAX][6];
-       int rx_mode;
-#define RX_MODE_UNI 0
-#define RX_MODE_MULTI 1
-#define RX_MODE_ALL_MULTI 2
-#define RX_MODE_PROMISC 3
-       struct work_struct set_multicast_list_wq;
-       struct work_struct restart_net_feed_wq;
-       unsigned char feedtype;                 /* Either FEED_TYPE_ or FEED_TYPE_ULE */
-       int need_pusi;                          /* Set to 1, if synchronization on PUSI required. */
-       unsigned char tscc;                     /* TS continuity counter after sync on PUSI. */
-       struct sk_buff *ule_skb;                /* ULE SNDU decodes into this buffer. */
-       unsigned char *ule_next_hdr;            /* Pointer into skb to next ULE extension header. */
-       unsigned short ule_sndu_len;            /* ULE SNDU length in bytes, w/o D-Bit. */
-       unsigned short ule_sndu_type;           /* ULE SNDU type field, complete. */
-       unsigned char ule_sndu_type_1;          /* ULE SNDU type field, if split across 2 TS cells. */
-       unsigned char ule_dbit;                 /* Whether the DestMAC address present
-                                                * or not (bit is set). */
-       unsigned char ule_bridged;              /* Whether the ULE_BRIDGED extension header was found. */
-       int ule_sndu_remain;                    /* Nr. of bytes still required for current ULE SNDU. */
-       unsigned long ts_count;                 /* Current ts cell counter. */
-       struct mutex mutex;
-};
-
-
-/**
- *     Determine the packet's protocol ID. The rule here is that we
- *     assume 802.3 if the type field is short enough to be a length.
- *     This is normal practice and works for any 'now in use' protocol.
- *
- *  stolen from eth.c out of the linux kernel, hacked for dvb-device
- *  by Michael Holzt <kju@debian.org>
- */
-static __be16 dvb_net_eth_type_trans(struct sk_buff *skb,
-                                     struct net_device *dev)
-{
-       struct ethhdr *eth;
-       unsigned char *rawp;
-
-       skb_reset_mac_header(skb);
-       skb_pull(skb,dev->hard_header_len);
-       eth = eth_hdr(skb);
-
-       if (*eth->h_dest & 1) {
-               if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0)
-                       skb->pkt_type=PACKET_BROADCAST;
-               else
-                       skb->pkt_type=PACKET_MULTICAST;
-       }
-
-       if (ntohs(eth->h_proto) >= 1536)
-               return eth->h_proto;
-
-       rawp = skb->data;
-
-       /**
-        *      This is a magic hack to spot IPX packets. Older Novell breaks
-        *      the protocol design and runs IPX over 802.3 without an 802.2 LLC
-        *      layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
-        *      won't work for fault tolerant netware but does for the rest.
-        */
-       if (*(unsigned short *)rawp == 0xFFFF)
-               return htons(ETH_P_802_3);
-
-       /**
-        *      Real 802.2 LLC
-        */
-       return htons(ETH_P_802_2);
-}
-
-#define TS_SZ  188
-#define TS_SYNC        0x47
-#define TS_TEI 0x80
-#define TS_SC  0xC0
-#define TS_PUSI        0x40
-#define TS_AF_A        0x20
-#define TS_AF_D        0x10
-
-/* ULE Extension Header handlers. */
-
-#define ULE_TEST       0
-#define ULE_BRIDGED    1
-
-#define ULE_OPTEXTHDR_PADDING 0
-
-static int ule_test_sndu( struct dvb_net_priv *p )
-{
-       return -1;
-}
-
-static int ule_bridged_sndu( struct dvb_net_priv *p )
-{
-       struct ethhdr *hdr = (struct ethhdr*) p->ule_next_hdr;
-       if(ntohs(hdr->h_proto) < 1536) {
-               int framelen = p->ule_sndu_len - ((p->ule_next_hdr+sizeof(struct ethhdr)) - p->ule_skb->data);
-               /* A frame Type < 1536 for a bridged frame, introduces a LLC Length field. */
-               if(framelen != ntohs(hdr->h_proto)) {
-                       return -1;
-               }
-       }
-       /* Note:
-        * From RFC4326:
-        *  "A bridged SNDU is a Mandatory Extension Header of Type 1.
-        *   It must be the final (or only) extension header specified in the header chain of a SNDU."
-        * The 'ule_bridged' flag will cause the extension header processing loop to terminate.
-        */
-       p->ule_bridged = 1;
-       return 0;
-}
-
-static int ule_exthdr_padding(struct dvb_net_priv *p)
-{
-       return 0;
-}
-
-/** Handle ULE extension headers.
- *  Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding.
- *  Returns: >= 0: nr. of bytes consumed by next extension header
- *          -1:   Mandatory extension header that is not recognized or TEST SNDU; discard.
- */
-static int handle_one_ule_extension( struct dvb_net_priv *p )
-{
-       /* Table of mandatory extension header handlers.  The header type is the index. */
-       static int (*ule_mandatory_ext_handlers[255])( struct dvb_net_priv *p ) =
-               { [0] = ule_test_sndu, [1] = ule_bridged_sndu, [2] = NULL,  };
-
-       /* Table of optional extension header handlers.  The header type is the index. */
-       static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) =
-               { [0] = ule_exthdr_padding, [1] = NULL, };
-
-       int ext_len = 0;
-       unsigned char hlen = (p->ule_sndu_type & 0x0700) >> 8;
-       unsigned char htype = p->ule_sndu_type & 0x00FF;
-
-       /* Discriminate mandatory and optional extension headers. */
-       if (hlen == 0) {
-               /* Mandatory extension header */
-               if (ule_mandatory_ext_handlers[htype]) {
-                       ext_len = ule_mandatory_ext_handlers[htype]( p );
-                       if(ext_len >= 0) {
-                               p->ule_next_hdr += ext_len;
-                               if (!p->ule_bridged) {
-                                       p->ule_sndu_type = ntohs(*(__be16 *)p->ule_next_hdr);
-                                       p->ule_next_hdr += 2;
-                               } else {
-                                       p->ule_sndu_type = ntohs(*(__be16 *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)));
-                                       /* This assures the extension handling loop will terminate. */
-                               }
-                       }
-                       // else: extension handler failed or SNDU should be discarded
-               } else
-                       ext_len = -1;   /* SNDU has to be discarded. */
-       } else {
-               /* Optional extension header.  Calculate the length. */
-               ext_len = hlen << 1;
-               /* Process the optional extension header according to its type. */
-               if (ule_optional_ext_handlers[htype])
-                       (void)ule_optional_ext_handlers[htype]( p );
-               p->ule_next_hdr += ext_len;
-               p->ule_sndu_type = ntohs( *(__be16 *)(p->ule_next_hdr-2) );
-               /*
-                * note: the length of the next header type is included in the
-                * length of THIS optional extension header
-                */
-       }
-
-       return ext_len;
-}
-
-static int handle_ule_extensions( struct dvb_net_priv *p )
-{
-       int total_ext_len = 0, l;
-
-       p->ule_next_hdr = p->ule_skb->data;
-       do {
-               l = handle_one_ule_extension( p );
-               if (l < 0)
-                       return l;       /* Stop extension header processing and discard SNDU. */
-               total_ext_len += l;
-#ifdef ULE_DEBUG
-               dprintk("handle_ule_extensions: ule_next_hdr=%p, ule_sndu_type=%i, "
-                       "l=%i, total_ext_len=%i\n", p->ule_next_hdr,
-                       (int) p->ule_sndu_type, l, total_ext_len);
-#endif
-
-       } while (p->ule_sndu_type < 1536);
-
-       return total_ext_len;
-}
-
-
-/** Prepare for a new ULE SNDU: reset the decoder state. */
-static inline void reset_ule( struct dvb_net_priv *p )
-{
-       p->ule_skb = NULL;
-       p->ule_next_hdr = NULL;
-       p->ule_sndu_len = 0;
-       p->ule_sndu_type = 0;
-       p->ule_sndu_type_1 = 0;
-       p->ule_sndu_remain = 0;
-       p->ule_dbit = 0xFF;
-       p->ule_bridged = 0;
-}
-
-/**
- * Decode ULE SNDUs according to draft-ietf-ipdvb-ule-03.txt from a sequence of
- * TS cells of a single PID.
- */
-static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
-{
-       struct dvb_net_priv *priv = netdev_priv(dev);
-       unsigned long skipped = 0L;
-       const u8 *ts, *ts_end, *from_where = NULL;
-       u8 ts_remain = 0, how_much = 0, new_ts = 1;
-       struct ethhdr *ethh = NULL;
-       bool error = false;
-
-#ifdef ULE_DEBUG
-       /* The code inside ULE_DEBUG keeps a history of the last 100 TS cells processed. */
-       static unsigned char ule_hist[100*TS_SZ];
-       static unsigned char *ule_where = ule_hist, ule_dump;
-#endif
-
-       /* For all TS cells in current buffer.
-        * Appearently, we are called for every single TS cell.
-        */
-       for (ts = buf, ts_end = buf + buf_len; ts < ts_end; /* no default incr. */ ) {
-
-               if (new_ts) {
-                       /* We are about to process a new TS cell. */
-
-#ifdef ULE_DEBUG
-                       if (ule_where >= &ule_hist[100*TS_SZ]) ule_where = ule_hist;
-                       memcpy( ule_where, ts, TS_SZ );
-                       if (ule_dump) {
-                               hexdump( ule_where, TS_SZ );
-                               ule_dump = 0;
-                       }
-                       ule_where += TS_SZ;
-#endif
-
-                       /* Check TS error conditions: sync_byte, transport_error_indicator, scrambling_control . */
-                       if ((ts[0] != TS_SYNC) || (ts[1] & TS_TEI) || ((ts[3] & TS_SC) != 0)) {
-                               printk(KERN_WARNING "%lu: Invalid TS cell: SYNC %#x, TEI %u, SC %#x.\n",
-                                      priv->ts_count, ts[0], ts[1] & TS_TEI >> 7, ts[3] & 0xC0 >> 6);
-
-                               /* Drop partly decoded SNDU, reset state, resync on PUSI. */
-                               if (priv->ule_skb) {
-                                       dev_kfree_skb( priv->ule_skb );
-                                       /* Prepare for next SNDU. */
-                                       dev->stats.rx_errors++;
-                                       dev->stats.rx_frame_errors++;
-                               }
-                               reset_ule(priv);
-                               priv->need_pusi = 1;
-
-                               /* Continue with next TS cell. */
-                               ts += TS_SZ;
-                               priv->ts_count++;
-                               continue;
-                       }
-
-                       ts_remain = 184;
-                       from_where = ts + 4;
-               }
-               /* Synchronize on PUSI, if required. */
-               if (priv->need_pusi) {
-                       if (ts[1] & TS_PUSI) {
-                               /* Find beginning of first ULE SNDU in current TS cell. */
-                               /* Synchronize continuity counter. */
-                               priv->tscc = ts[3] & 0x0F;
-                               /* There is a pointer field here. */
-                               if (ts[4] > ts_remain) {
-                                       printk(KERN_ERR "%lu: Invalid ULE packet "
-                                              "(pointer field %d)\n", priv->ts_count, ts[4]);
-                                       ts += TS_SZ;
-                                       priv->ts_count++;
-                                       continue;
-                               }
-                               /* Skip to destination of pointer field. */
-                               from_where = &ts[5] + ts[4];
-                               ts_remain -= 1 + ts[4];
-                               skipped = 0;
-                       } else {
-                               skipped++;
-                               ts += TS_SZ;
-                               priv->ts_count++;
-                               continue;
-                       }
-               }
-
-               if (new_ts) {
-                       /* Check continuity counter. */
-                       if ((ts[3] & 0x0F) == priv->tscc)
-                               priv->tscc = (priv->tscc + 1) & 0x0F;
-                       else {
-                               /* TS discontinuity handling: */
-                               printk(KERN_WARNING "%lu: TS discontinuity: got %#x, "
-                                      "expected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc);
-                               /* Drop partly decoded SNDU, reset state, resync on PUSI. */
-                               if (priv->ule_skb) {
-                                       dev_kfree_skb( priv->ule_skb );
-                                       /* Prepare for next SNDU. */
-                                       // reset_ule(priv);  moved to below.
-                                       dev->stats.rx_errors++;
-                                       dev->stats.rx_frame_errors++;
-                               }
-                               reset_ule(priv);
-                               /* skip to next PUSI. */
-                               priv->need_pusi = 1;
-                               continue;
-                       }
-                       /* If we still have an incomplete payload, but PUSI is
-                        * set; some TS cells are missing.
-                        * This is only possible here, if we missed exactly 16 TS
-                        * cells (continuity counter wrap). */
-                       if (ts[1] & TS_PUSI) {
-                               if (! priv->need_pusi) {
-                                       if (!(*from_where < (ts_remain-1)) || *from_where != priv->ule_sndu_remain) {
-                                               /* Pointer field is invalid.  Drop this TS cell and any started ULE SNDU. */
-                                               printk(KERN_WARNING "%lu: Invalid pointer "
-                                                      "field: %u.\n", priv->ts_count, *from_where);
-
-                                               /* Drop partly decoded SNDU, reset state, resync on PUSI. */
-                                               if (priv->ule_skb) {
-                                                       error = true;
-                                                       dev_kfree_skb(priv->ule_skb);
-                                               }
-
-                                               if (error || priv->ule_sndu_remain) {
-                                                       dev->stats.rx_errors++;
-                                                       dev->stats.rx_frame_errors++;
-                                                       error = false;
-                                               }
-
-                                               reset_ule(priv);
-                                               priv->need_pusi = 1;
-                                               continue;
-                                       }
-                                       /* Skip pointer field (we're processing a
-                                        * packed payload). */
-                                       from_where += 1;
-                                       ts_remain -= 1;
-                               } else
-                                       priv->need_pusi = 0;
-
-                               if (priv->ule_sndu_remain > 183) {
-                                       /* Current SNDU lacks more data than there could be available in the
-                                        * current TS cell. */
-                                       dev->stats.rx_errors++;
-                                       dev->stats.rx_length_errors++;
-                                       printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but "
-                                              "got PUSI (pf %d, ts_remain %d).  Flushing incomplete payload.\n",
-                                              priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain);
-                                       dev_kfree_skb(priv->ule_skb);
-                                       /* Prepare for next SNDU. */
-                                       reset_ule(priv);
-                                       /* Resync: go to where pointer field points to: start of next ULE SNDU. */
-                                       from_where += ts[4];
-                                       ts_remain -= ts[4];
-                               }
-                       }
-               }
-
-               /* Check if new payload needs to be started. */
-               if (priv->ule_skb == NULL) {
-                       /* Start a new payload with skb.
-                        * Find ULE header.  It is only guaranteed that the
-                        * length field (2 bytes) is contained in the current
-                        * TS.
-                        * Check ts_remain has to be >= 2 here. */
-                       if (ts_remain < 2) {
-                               printk(KERN_WARNING "Invalid payload packing: only %d "
-                                      "bytes left in TS.  Resyncing.\n", ts_remain);
-                               priv->ule_sndu_len = 0;
-                               priv->need_pusi = 1;
-                               ts += TS_SZ;
-                               continue;
-                       }
-
-                       if (! priv->ule_sndu_len) {
-                               /* Got at least two bytes, thus extrace the SNDU length. */
-                               priv->ule_sndu_len = from_where[0] << 8 | from_where[1];
-                               if (priv->ule_sndu_len & 0x8000) {
-                                       /* D-Bit is set: no dest mac present. */
-                                       priv->ule_sndu_len &= 0x7FFF;
-                                       priv->ule_dbit = 1;
-                               } else
-                                       priv->ule_dbit = 0;
-
-                               if (priv->ule_sndu_len < 5) {
-                                       printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. "
-                                              "Resyncing.\n", priv->ts_count, priv->ule_sndu_len);
-                                       dev->stats.rx_errors++;
-                                       dev->stats.rx_length_errors++;
-                                       priv->ule_sndu_len = 0;
-                                       priv->need_pusi = 1;
-                                       new_ts = 1;
-                                       ts += TS_SZ;
-                                       priv->ts_count++;
-                                       continue;
-                               }
-                               ts_remain -= 2; /* consume the 2 bytes SNDU length. */
-                               from_where += 2;
-                       }
-
-                       priv->ule_sndu_remain = priv->ule_sndu_len + 2;
-                       /*
-                        * State of current TS:
-                        *   ts_remain (remaining bytes in the current TS cell)
-                        *   0  ule_type is not available now, we need the next TS cell
-                        *   1  the first byte of the ule_type is present
-                        * >=2  full ULE header present, maybe some payload data as well.
-                        */
-                       switch (ts_remain) {
-                               case 1:
-                                       priv->ule_sndu_remain--;
-                                       priv->ule_sndu_type = from_where[0] << 8;
-                                       priv->ule_sndu_type_1 = 1; /* first byte of ule_type is set. */
-                                       ts_remain -= 1; from_where += 1;
-                                       /* Continue w/ next TS. */
-                               case 0:
-                                       new_ts = 1;
-                                       ts += TS_SZ;
-                                       priv->ts_count++;
-                                       continue;
-
-                               default: /* complete ULE header is present in current TS. */
-                                       /* Extract ULE type field. */
-                                       if (priv->ule_sndu_type_1) {
-                                               priv->ule_sndu_type_1 = 0;
-                                               priv->ule_sndu_type |= from_where[0];
-                                               from_where += 1; /* points to payload start. */
-                                               ts_remain -= 1;
-                                       } else {
-                                               /* Complete type is present in new TS. */
-                                               priv->ule_sndu_type = from_where[0] << 8 | from_where[1];
-                                               from_where += 2; /* points to payload start. */
-                                               ts_remain -= 2;
-                                       }
-                                       break;
-                       }
-
-                       /* Allocate the skb (decoder target buffer) with the correct size, as follows:
-                        * prepare for the largest case: bridged SNDU with MAC address (dbit = 0). */
-                       priv->ule_skb = dev_alloc_skb( priv->ule_sndu_len + ETH_HLEN + ETH_ALEN );
-                       if (priv->ule_skb == NULL) {
-                               printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
-                                      dev->name);
-                               dev->stats.rx_dropped++;
-                               return;
-                       }
-
-                       /* This includes the CRC32 _and_ dest mac, if !dbit. */
-                       priv->ule_sndu_remain = priv->ule_sndu_len;
-                       priv->ule_skb->dev = dev;
-                       /* Leave space for Ethernet or bridged SNDU header (eth hdr plus one MAC addr). */
-                       skb_reserve( priv->ule_skb, ETH_HLEN + ETH_ALEN );
-               }
-
-               /* Copy data into our current skb. */
-               how_much = min(priv->ule_sndu_remain, (int)ts_remain);
-               memcpy(skb_put(priv->ule_skb, how_much), from_where, how_much);
-               priv->ule_sndu_remain -= how_much;
-               ts_remain -= how_much;
-               from_where += how_much;
-
-               /* Check for complete payload. */
-               if (priv->ule_sndu_remain <= 0) {
-                       /* Check CRC32, we've got it in our skb already. */
-                       __be16 ulen = htons(priv->ule_sndu_len);
-                       __be16 utype = htons(priv->ule_sndu_type);
-                       const u8 *tail;
-                       struct kvec iov[3] = {
-                               { &ulen, sizeof ulen },
-                               { &utype, sizeof utype },
-                               { priv->ule_skb->data, priv->ule_skb->len - 4 }
-                       };
-                       u32 ule_crc = ~0L, expected_crc;
-                       if (priv->ule_dbit) {
-                               /* Set D-bit for CRC32 verification,
-                                * if it was set originally. */
-                               ulen |= htons(0x8000);
-                       }
-
-                       ule_crc = iov_crc32(ule_crc, iov, 3);
-                       tail = skb_tail_pointer(priv->ule_skb);
-                       expected_crc = *(tail - 4) << 24 |
-                                      *(tail - 3) << 16 |
-                                      *(tail - 2) << 8 |
-                                      *(tail - 1);
-                       if (ule_crc != expected_crc) {
-                               printk(KERN_WARNING "%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n",
-                                      priv->ts_count, ule_crc, expected_crc, priv->ule_sndu_len, priv->ule_sndu_type, ts_remain, ts_remain > 2 ? *(unsigned short *)from_where : 0);
-
-#ifdef ULE_DEBUG
-                               hexdump( iov[0].iov_base, iov[0].iov_len );
-                               hexdump( iov[1].iov_base, iov[1].iov_len );
-                               hexdump( iov[2].iov_base, iov[2].iov_len );
-
-                               if (ule_where == ule_hist) {
-                                       hexdump( &ule_hist[98*TS_SZ], TS_SZ );
-                                       hexdump( &ule_hist[99*TS_SZ], TS_SZ );
-                               } else if (ule_where == &ule_hist[TS_SZ]) {
-                                       hexdump( &ule_hist[99*TS_SZ], TS_SZ );
-                                       hexdump( ule_hist, TS_SZ );
-                               } else {
-                                       hexdump( ule_where - TS_SZ - TS_SZ, TS_SZ );
-                                       hexdump( ule_where - TS_SZ, TS_SZ );
-                               }
-                               ule_dump = 1;
-#endif
-
-                               dev->stats.rx_errors++;
-                               dev->stats.rx_crc_errors++;
-                               dev_kfree_skb(priv->ule_skb);
-                       } else {
-                               /* CRC32 verified OK. */
-                               u8 dest_addr[ETH_ALEN];
-                               static const u8 bc_addr[ETH_ALEN] =
-                                       { [ 0 ... ETH_ALEN-1] = 0xff };
-
-                               /* CRC32 was OK. Remove it from skb. */
-                               priv->ule_skb->tail -= 4;
-                               priv->ule_skb->len -= 4;
-
-                               if (!priv->ule_dbit) {
-                                       /*
-                                        * The destination MAC address is the
-                                        * next data in the skb.  It comes
-                                        * before any extension headers.
-                                        *
-                                        * Check if the payload of this SNDU
-                                        * should be passed up the stack.
-                                        */
-                                       register int drop = 0;
-                                       if (priv->rx_mode != RX_MODE_PROMISC) {
-                                               if (priv->ule_skb->data[0] & 0x01) {
-                                                       /* multicast or broadcast */
-                                                       if (memcmp(priv->ule_skb->data, bc_addr, ETH_ALEN)) {
-                                                               /* multicast */
-                                                               if (priv->rx_mode == RX_MODE_MULTI) {
-                                                                       int i;
-                                                                       for(i = 0; i < priv->multi_num && memcmp(priv->ule_skb->data, priv->multi_macs[i], ETH_ALEN); i++)
-                                                                               ;
-                                                                       if (i == priv->multi_num)
-                                                                               drop = 1;
-                                                               } else if (priv->rx_mode != RX_MODE_ALL_MULTI)
-                                                                       drop = 1; /* no broadcast; */
-                                                               /* else: all multicast mode: accept all multicast packets */
-                                                       }
-                                                       /* else: broadcast */
-                                               }
-                                               else if (memcmp(priv->ule_skb->data, dev->dev_addr, ETH_ALEN))
-                                                       drop = 1;
-                                               /* else: destination address matches the MAC address of our receiver device */
-                                       }
-                                       /* else: promiscuous mode; pass everything up the stack */
-
-                                       if (drop) {
-#ifdef ULE_DEBUG
-                                               dprintk("Dropping SNDU: MAC destination address does not match: dest addr: "MAC_ADDR_PRINTFMT", dev addr: "MAC_ADDR_PRINTFMT"\n",
-                                                       MAX_ADDR_PRINTFMT_ARGS(priv->ule_skb->data), MAX_ADDR_PRINTFMT_ARGS(dev->dev_addr));
-#endif
-                                               dev_kfree_skb(priv->ule_skb);
-                                               goto sndu_done;
-                                       }
-                                       else
-                                       {
-                                               skb_copy_from_linear_data(priv->ule_skb,
-                                                             dest_addr,
-                                                             ETH_ALEN);
-                                               skb_pull(priv->ule_skb, ETH_ALEN);
-                                       }
-                               }
-
-                               /* Handle ULE Extension Headers. */
-                               if (priv->ule_sndu_type < 1536) {
-                                       /* There is an extension header.  Handle it accordingly. */
-                                       int l = handle_ule_extensions(priv);
-                                       if (l < 0) {
-                                               /* Mandatory extension header unknown or TEST SNDU.  Drop it. */
-                                               // printk( KERN_WARNING "Dropping SNDU, extension headers.\n" );
-                                               dev_kfree_skb(priv->ule_skb);
-                                               goto sndu_done;
-                                       }
-                                       skb_pull(priv->ule_skb, l);
-                               }
-
-                               /*
-                                * Construct/assure correct ethernet header.
-                                * Note: in bridged mode (priv->ule_bridged !=
-                                * 0) we already have the (original) ethernet
-                                * header at the start of the payload (after
-                                * optional dest. address and any extension
-                                * headers).
-                                */
-
-                               if (!priv->ule_bridged) {
-                                       skb_push(priv->ule_skb, ETH_HLEN);
-                                       ethh = (struct ethhdr *)priv->ule_skb->data;
-                                       if (!priv->ule_dbit) {
-                                                /* dest_addr buffer is only valid if priv->ule_dbit == 0 */
-                                               memcpy(ethh->h_dest, dest_addr, ETH_ALEN);
-                                               memset(ethh->h_source, 0, ETH_ALEN);
-                                       }
-                                       else /* zeroize source and dest */
-                                               memset( ethh, 0, ETH_ALEN*2 );
-
-                                       ethh->h_proto = htons(priv->ule_sndu_type);
-                               }
-                               /* else:  skb is in correct state; nothing to do. */
-                               priv->ule_bridged = 0;
-
-                               /* Stuff into kernel's protocol stack. */
-                               priv->ule_skb->protocol = dvb_net_eth_type_trans(priv->ule_skb, dev);
-                               /* If D-bit is set (i.e. destination MAC address not present),
-                                * receive the packet anyhow. */
-                               /* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST)
-                                       priv->ule_skb->pkt_type = PACKET_HOST; */
-                               dev->stats.rx_packets++;
-                               dev->stats.rx_bytes += priv->ule_skb->len;
-                               netif_rx(priv->ule_skb);
-                       }
-                       sndu_done:
-                       /* Prepare for next SNDU. */
-                       reset_ule(priv);
-               }
-
-               /* More data in current TS (look at the bytes following the CRC32)? */
-               if (ts_remain >= 2 && *((unsigned short *)from_where) != 0xFFFF) {
-                       /* Next ULE SNDU starts right there. */
-                       new_ts = 0;
-                       priv->ule_skb = NULL;
-                       priv->ule_sndu_type_1 = 0;
-                       priv->ule_sndu_len = 0;
-                       // printk(KERN_WARNING "More data in current TS: [%#x %#x %#x %#x]\n",
-                       //      *(from_where + 0), *(from_where + 1),
-                       //      *(from_where + 2), *(from_where + 3));
-                       // printk(KERN_WARNING "ts @ %p, stopped @ %p:\n", ts, from_where + 0);
-                       // hexdump(ts, 188);
-               } else {
-                       new_ts = 1;
-                       ts += TS_SZ;
-                       priv->ts_count++;
-                       if (priv->ule_skb == NULL) {
-                               priv->need_pusi = 1;
-                               priv->ule_sndu_type_1 = 0;
-                               priv->ule_sndu_len = 0;
-                       }
-               }
-       }       /* for all available TS cells */
-}
-
-static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len,
-                              const u8 *buffer2, size_t buffer2_len,
-                              struct dmx_ts_feed *feed, enum dmx_success success)
-{
-       struct net_device *dev = feed->priv;
-
-       if (buffer2)
-               printk(KERN_WARNING "buffer2 not NULL: %p.\n", buffer2);
-       if (buffer1_len > 32768)
-               printk(KERN_WARNING "length > 32k: %zu.\n", buffer1_len);
-       /* printk("TS callback: %u bytes, %u TS cells @ %p.\n",
-                 buffer1_len, buffer1_len / TS_SZ, buffer1); */
-       dvb_net_ule(dev, buffer1, buffer1_len);
-       return 0;
-}
-
-
-static void dvb_net_sec(struct net_device *dev,
-                       const u8 *pkt, int pkt_len)
-{
-       u8 *eth;
-       struct sk_buff *skb;
-       struct net_device_stats *stats = &dev->stats;
-       int snap = 0;
-
-       /* note: pkt_len includes a 32bit checksum */
-       if (pkt_len < 16) {
-               printk("%s: IP/MPE packet length = %d too small.\n",
-                       dev->name, pkt_len);
-               stats->rx_errors++;
-               stats->rx_length_errors++;
-               return;
-       }
-/* it seems some ISPs manage to screw up here, so we have to
- * relax the error checks... */
-#if 0
-       if ((pkt[5] & 0xfd) != 0xc1) {
-               /* drop scrambled or broken packets */
-#else
-       if ((pkt[5] & 0x3c) != 0x00) {
-               /* drop scrambled */
-#endif
-               stats->rx_errors++;
-               stats->rx_crc_errors++;
-               return;
-       }
-       if (pkt[5] & 0x02) {
-               /* handle LLC/SNAP, see rfc-1042 */
-               if (pkt_len < 24 || memcmp(&pkt[12], "\xaa\xaa\x03\0\0\0", 6)) {
-                       stats->rx_dropped++;
-                       return;
-               }
-               snap = 8;
-       }
-       if (pkt[7]) {
-               /* FIXME: assemble datagram from multiple sections */
-               stats->rx_errors++;
-               stats->rx_frame_errors++;
-               return;
-       }
-
-       /* we have 14 byte ethernet header (ip header follows);
-        * 12 byte MPE header; 4 byte checksum; + 2 byte alignment, 8 byte LLC/SNAP
-        */
-       if (!(skb = dev_alloc_skb(pkt_len - 4 - 12 + 14 + 2 - snap))) {
-               //printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
-               stats->rx_dropped++;
-               return;
-       }
-       skb_reserve(skb, 2);    /* longword align L3 header */
-       skb->dev = dev;
-
-       /* copy L3 payload */
-       eth = (u8 *) skb_put(skb, pkt_len - 12 - 4 + 14 - snap);
-       memcpy(eth + 14, pkt + 12 + snap, pkt_len - 12 - 4 - snap);
-
-       /* create ethernet header: */
-       eth[0]=pkt[0x0b];
-       eth[1]=pkt[0x0a];
-       eth[2]=pkt[0x09];
-       eth[3]=pkt[0x08];
-       eth[4]=pkt[0x04];
-       eth[5]=pkt[0x03];
-
-       eth[6]=eth[7]=eth[8]=eth[9]=eth[10]=eth[11]=0;
-
-       if (snap) {
-               eth[12] = pkt[18];
-               eth[13] = pkt[19];
-       } else {
-               /* protocol numbers are from rfc-1700 or
-                * http://www.iana.org/assignments/ethernet-numbers
-                */
-               if (pkt[12] >> 4 == 6) { /* version field from IP header */
-                       eth[12] = 0x86; /* IPv6 */
-                       eth[13] = 0xdd;
-               } else {
-                       eth[12] = 0x08; /* IPv4 */
-                       eth[13] = 0x00;
-               }
-       }
-
-       skb->protocol = dvb_net_eth_type_trans(skb, dev);
-
-       stats->rx_packets++;
-       stats->rx_bytes+=skb->len;
-       netif_rx(skb);
-}
-
-static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len,
-                const u8 *buffer2, size_t buffer2_len,
-                struct dmx_section_filter *filter,
-                enum dmx_success success)
-{
-       struct net_device *dev = filter->priv;
-
-       /**
-        * we rely on the DVB API definition where exactly one complete
-        * section is delivered in buffer1
-        */
-       dvb_net_sec (dev, buffer1, buffer1_len);
-       return 0;
-}
-
-static int dvb_net_tx(struct sk_buff *skb, struct net_device *dev)
-{
-       dev_kfree_skb(skb);
-       return NETDEV_TX_OK;
-}
-
-static u8 mask_normal[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
-static u8 mask_allmulti[6]={0xff, 0xff, 0xff, 0x00, 0x00, 0x00};
-static u8 mac_allmulti[6]={0x01, 0x00, 0x5e, 0x00, 0x00, 0x00};
-static u8 mask_promisc[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-
-static int dvb_net_filter_sec_set(struct net_device *dev,
-                  struct dmx_section_filter **secfilter,
-                  u8 *mac, u8 *mac_mask)
-{
-       struct dvb_net_priv *priv = netdev_priv(dev);
-       int ret;
-
-       *secfilter=NULL;
-       ret = priv->secfeed->allocate_filter(priv->secfeed, secfilter);
-       if (ret<0) {
-               printk("%s: could not get filter\n", dev->name);
-               return ret;
-       }
-
-       (*secfilter)->priv=(void *) dev;
-
-       memset((*secfilter)->filter_value, 0x00, DMX_MAX_FILTER_SIZE);
-       memset((*secfilter)->filter_mask,  0x00, DMX_MAX_FILTER_SIZE);
-       memset((*secfilter)->filter_mode,  0xff, DMX_MAX_FILTER_SIZE);
-
-       (*secfilter)->filter_value[0]=0x3e;
-       (*secfilter)->filter_value[3]=mac[5];
-       (*secfilter)->filter_value[4]=mac[4];
-       (*secfilter)->filter_value[8]=mac[3];
-       (*secfilter)->filter_value[9]=mac[2];
-       (*secfilter)->filter_value[10]=mac[1];
-       (*secfilter)->filter_value[11]=mac[0];
-
-       (*secfilter)->filter_mask[0] = 0xff;
-       (*secfilter)->filter_mask[3] = mac_mask[5];
-       (*secfilter)->filter_mask[4] = mac_mask[4];
-       (*secfilter)->filter_mask[8] = mac_mask[3];
-       (*secfilter)->filter_mask[9] = mac_mask[2];
-       (*secfilter)->filter_mask[10] = mac_mask[1];
-       (*secfilter)->filter_mask[11]=mac_mask[0];
-
-       dprintk("%s: filter mac=%pM\n", dev->name, mac);
-       dprintk("%s: filter mask=%pM\n", dev->name, mac_mask);
-
-       return 0;
-}
-
-static int dvb_net_feed_start(struct net_device *dev)
-{
-       int ret = 0, i;
-       struct dvb_net_priv *priv = netdev_priv(dev);
-       struct dmx_demux *demux = priv->demux;
-       unsigned char *mac = (unsigned char *) dev->dev_addr;
-
-       dprintk("%s: rx_mode %i\n", __func__, priv->rx_mode);
-       mutex_lock(&priv->mutex);
-       if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0])
-               printk("%s: BUG %d\n", __func__, __LINE__);
-
-       priv->secfeed=NULL;
-       priv->secfilter=NULL;
-       priv->tsfeed = NULL;
-
-       if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
-               dprintk("%s: alloc secfeed\n", __func__);
-               ret=demux->allocate_section_feed(demux, &priv->secfeed,
-                                        dvb_net_sec_callback);
-               if (ret<0) {
-                       printk("%s: could not allocate section feed\n", dev->name);
-                       goto error;
-               }
-
-               ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1);
-
-               if (ret<0) {
-                       printk("%s: could not set section feed\n", dev->name);
-                       priv->demux->release_section_feed(priv->demux, priv->secfeed);
-                       priv->secfeed=NULL;
-                       goto error;
-               }
-
-               if (priv->rx_mode != RX_MODE_PROMISC) {
-                       dprintk("%s: set secfilter\n", __func__);
-                       dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_normal);
-               }
-
-               switch (priv->rx_mode) {
-               case RX_MODE_MULTI:
-                       for (i = 0; i < priv->multi_num; i++) {
-                               dprintk("%s: set multi_secfilter[%d]\n", __func__, i);
-                               dvb_net_filter_sec_set(dev, &priv->multi_secfilter[i],
-                                                      priv->multi_macs[i], mask_normal);
-                       }
-                       break;
-               case RX_MODE_ALL_MULTI:
-                       priv->multi_num=1;
-                       dprintk("%s: set multi_secfilter[0]\n", __func__);
-                       dvb_net_filter_sec_set(dev, &priv->multi_secfilter[0],
-                                              mac_allmulti, mask_allmulti);
-                       break;
-               case RX_MODE_PROMISC:
-                       priv->multi_num=0;
-                       dprintk("%s: set secfilter\n", __func__);
-                       dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_promisc);
-                       break;
-               }
-
-               dprintk("%s: start filtering\n", __func__);
-               priv->secfeed->start_filtering(priv->secfeed);
-       } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
-               struct timespec timeout = { 0, 10000000 }; // 10 msec
-
-               /* we have payloads encapsulated in TS */
-               dprintk("%s: alloc tsfeed\n", __func__);
-               ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback);
-               if (ret < 0) {
-                       printk("%s: could not allocate ts feed\n", dev->name);
-                       goto error;
-               }
-
-               /* Set netdevice pointer for ts decaps callback. */
-               priv->tsfeed->priv = (void *)dev;
-               ret = priv->tsfeed->set(priv->tsfeed,
-                                       priv->pid, /* pid */
-                                       TS_PACKET, /* type */
-                                       DMX_TS_PES_OTHER, /* pes type */
-                                       32768,     /* circular buffer size */
-                                       timeout    /* timeout */
-                                       );
-
-               if (ret < 0) {
-                       printk("%s: could not set ts feed\n", dev->name);
-                       priv->demux->release_ts_feed(priv->demux, priv->tsfeed);
-                       priv->tsfeed = NULL;
-                       goto error;
-               }
-
-               dprintk("%s: start filtering\n", __func__);
-               priv->tsfeed->start_filtering(priv->tsfeed);
-       } else
-               ret = -EINVAL;
-
-error:
-       mutex_unlock(&priv->mutex);
-       return ret;
-}
-
-static int dvb_net_feed_stop(struct net_device *dev)
-{
-       struct dvb_net_priv *priv = netdev_priv(dev);
-       int i, ret = 0;
-
-       dprintk("%s\n", __func__);
-       mutex_lock(&priv->mutex);
-       if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
-               if (priv->secfeed) {
-                       if (priv->secfeed->is_filtering) {
-                               dprintk("%s: stop secfeed\n", __func__);
-                               priv->secfeed->stop_filtering(priv->secfeed);
-                       }
-
-                       if (priv->secfilter) {
-                               dprintk("%s: release secfilter\n", __func__);
-                               priv->secfeed->release_filter(priv->secfeed,
-                                                             priv->secfilter);
-                               priv->secfilter=NULL;
-                       }
-
-                       for (i=0; i<priv->multi_num; i++) {
-                               if (priv->multi_secfilter[i]) {
-                                       dprintk("%s: release multi_filter[%d]\n",
-                                               __func__, i);
-                                       priv->secfeed->release_filter(priv->secfeed,
-                                                                     priv->multi_secfilter[i]);
-                                       priv->multi_secfilter[i] = NULL;
-                               }
-                       }
-
-                       priv->demux->release_section_feed(priv->demux, priv->secfeed);
-                       priv->secfeed = NULL;
-               } else
-                       printk("%s: no feed to stop\n", dev->name);
-       } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
-               if (priv->tsfeed) {
-                       if (priv->tsfeed->is_filtering) {
-                               dprintk("%s: stop tsfeed\n", __func__);
-                               priv->tsfeed->stop_filtering(priv->tsfeed);
-                       }
-                       priv->demux->release_ts_feed(priv->demux, priv->tsfeed);
-                       priv->tsfeed = NULL;
-               }
-               else
-                       printk("%s: no ts feed to stop\n", dev->name);
-       } else
-               ret = -EINVAL;
-       mutex_unlock(&priv->mutex);
-       return ret;
-}
-
-
-static int dvb_set_mc_filter(struct net_device *dev, unsigned char *addr)
-{
-       struct dvb_net_priv *priv = netdev_priv(dev);
-
-       if (priv->multi_num == DVB_NET_MULTICAST_MAX)
-               return -ENOMEM;
-
-       memcpy(priv->multi_macs[priv->multi_num], addr, ETH_ALEN);
-
-       priv->multi_num++;
-       return 0;
-}
-
-
-static void wq_set_multicast_list (struct work_struct *work)
-{
-       struct dvb_net_priv *priv =
-               container_of(work, struct dvb_net_priv, set_multicast_list_wq);
-       struct net_device *dev = priv->net;
-
-       dvb_net_feed_stop(dev);
-       priv->rx_mode = RX_MODE_UNI;
-       netif_addr_lock_bh(dev);
-
-       if (dev->flags & IFF_PROMISC) {
-               dprintk("%s: promiscuous mode\n", dev->name);
-               priv->rx_mode = RX_MODE_PROMISC;
-       } else if ((dev->flags & IFF_ALLMULTI)) {
-               dprintk("%s: allmulti mode\n", dev->name);
-               priv->rx_mode = RX_MODE_ALL_MULTI;
-       } else if (!netdev_mc_empty(dev)) {
-               struct netdev_hw_addr *ha;
-
-               dprintk("%s: set_mc_list, %d entries\n",
-                       dev->name, netdev_mc_count(dev));
-
-               priv->rx_mode = RX_MODE_MULTI;
-               priv->multi_num = 0;
-
-               netdev_for_each_mc_addr(ha, dev)
-                       dvb_set_mc_filter(dev, ha->addr);
-       }
-
-       netif_addr_unlock_bh(dev);
-       dvb_net_feed_start(dev);
-}
-
-
-static void dvb_net_set_multicast_list (struct net_device *dev)
-{
-       struct dvb_net_priv *priv = netdev_priv(dev);
-       schedule_work(&priv->set_multicast_list_wq);
-}
-
-
-static void wq_restart_net_feed (struct work_struct *work)
-{
-       struct dvb_net_priv *priv =
-               container_of(work, struct dvb_net_priv, restart_net_feed_wq);
-       struct net_device *dev = priv->net;
-
-       if (netif_running(dev)) {
-               dvb_net_feed_stop(dev);
-               dvb_net_feed_start(dev);
-       }
-}
-
-
-static int dvb_net_set_mac (struct net_device *dev, void *p)
-{
-       struct dvb_net_priv *priv = netdev_priv(dev);
-       struct sockaddr *addr=p;
-
-       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
-
-       if (netif_running(dev))
-               schedule_work(&priv->restart_net_feed_wq);
-
-       return 0;
-}
-
-
-static int dvb_net_open(struct net_device *dev)
-{
-       struct dvb_net_priv *priv = netdev_priv(dev);
-
-       priv->in_use++;
-       dvb_net_feed_start(dev);
-       return 0;
-}
-
-
-static int dvb_net_stop(struct net_device *dev)
-{
-       struct dvb_net_priv *priv = netdev_priv(dev);
-
-       priv->in_use--;
-       return dvb_net_feed_stop(dev);
-}
-
-static const struct header_ops dvb_header_ops = {
-       .create         = eth_header,
-       .parse          = eth_header_parse,
-       .rebuild        = eth_rebuild_header,
-};
-
-
-static const struct net_device_ops dvb_netdev_ops = {
-       .ndo_open               = dvb_net_open,
-       .ndo_stop               = dvb_net_stop,
-       .ndo_start_xmit         = dvb_net_tx,
-       .ndo_set_rx_mode        = dvb_net_set_multicast_list,
-       .ndo_set_mac_address    = dvb_net_set_mac,
-       .ndo_change_mtu         = eth_change_mtu,
-       .ndo_validate_addr      = eth_validate_addr,
-};
-
-static void dvb_net_setup(struct net_device *dev)
-{
-       ether_setup(dev);
-
-       dev->header_ops         = &dvb_header_ops;
-       dev->netdev_ops         = &dvb_netdev_ops;
-       dev->mtu                = 4096;
-
-       dev->flags |= IFF_NOARP;
-}
-
-static int get_if(struct dvb_net *dvbnet)
-{
-       int i;
-
-       for (i=0; i<DVB_NET_DEVICES_MAX; i++)
-               if (!dvbnet->state[i])
-                       break;
-
-       if (i == DVB_NET_DEVICES_MAX)
-               return -1;
-
-       dvbnet->state[i]=1;
-       return i;
-}
-
-static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype)
-{
-       struct net_device *net;
-       struct dvb_net_priv *priv;
-       int result;
-       int if_num;
-
-       if (feedtype != DVB_NET_FEEDTYPE_MPE && feedtype != DVB_NET_FEEDTYPE_ULE)
-               return -EINVAL;
-       if ((if_num = get_if(dvbnet)) < 0)
-               return -EINVAL;
-
-       net = alloc_netdev(sizeof(struct dvb_net_priv), "dvb", dvb_net_setup);
-       if (!net)
-               return -ENOMEM;
-
-       if (dvbnet->dvbdev->id)
-               snprintf(net->name, IFNAMSIZ, "dvb%d%u%d",
-                        dvbnet->dvbdev->adapter->num, dvbnet->dvbdev->id, if_num);
-       else
-               /* compatibility fix to keep dvb0_0 format */
-               snprintf(net->name, IFNAMSIZ, "dvb%d_%d",
-                        dvbnet->dvbdev->adapter->num, if_num);
-
-       net->addr_len = 6;
-       memcpy(net->dev_addr, dvbnet->dvbdev->adapter->proposed_mac, 6);
-
-       dvbnet->device[if_num] = net;
-
-       priv = netdev_priv(net);
-       priv->net = net;
-       priv->demux = dvbnet->demux;
-       priv->pid = pid;
-       priv->rx_mode = RX_MODE_UNI;
-       priv->need_pusi = 1;
-       priv->tscc = 0;
-       priv->feedtype = feedtype;
-       reset_ule(priv);
-
-       INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list);
-       INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed);
-       mutex_init(&priv->mutex);
-
-       net->base_addr = pid;
-
-       if ((result = register_netdev(net)) < 0) {
-               dvbnet->device[if_num] = NULL;
-               free_netdev(net);
-               return result;
-       }
-       printk("dvb_net: created network interface %s\n", net->name);
-
-       return if_num;
-}
-
-static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num)
-{
-       struct net_device *net = dvbnet->device[num];
-       struct dvb_net_priv *priv;
-
-       if (!dvbnet->state[num])
-               return -EINVAL;
-       priv = netdev_priv(net);
-       if (priv->in_use)
-               return -EBUSY;
-
-       dvb_net_stop(net);
-       flush_work_sync(&priv->set_multicast_list_wq);
-       flush_work_sync(&priv->restart_net_feed_wq);
-       printk("dvb_net: removed network interface %s\n", net->name);
-       unregister_netdev(net);
-       dvbnet->state[num]=0;
-       dvbnet->device[num] = NULL;
-       free_netdev(net);
-
-       return 0;
-}
-
-static int dvb_net_do_ioctl(struct file *file,
-                 unsigned int cmd, void *parg)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dvb_net *dvbnet = dvbdev->priv;
-
-       if (((file->f_flags&O_ACCMODE)==O_RDONLY))
-               return -EPERM;
-
-       switch (cmd) {
-       case NET_ADD_IF:
-       {
-               struct dvb_net_if *dvbnetif = parg;
-               int result;
-
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-
-               if (!try_module_get(dvbdev->adapter->module))
-                       return -EPERM;
-
-               result=dvb_net_add_if(dvbnet, dvbnetif->pid, dvbnetif->feedtype);
-               if (result<0) {
-                       module_put(dvbdev->adapter->module);
-                       return result;
-               }
-               dvbnetif->if_num=result;
-               break;
-       }
-       case NET_GET_IF:
-       {
-               struct net_device *netdev;
-               struct dvb_net_priv *priv_data;
-               struct dvb_net_if *dvbnetif = parg;
-
-               if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
-                   !dvbnet->state[dvbnetif->if_num])
-                       return -EINVAL;
-
-               netdev = dvbnet->device[dvbnetif->if_num];
-
-               priv_data = netdev_priv(netdev);
-               dvbnetif->pid=priv_data->pid;
-               dvbnetif->feedtype=priv_data->feedtype;
-               break;
-       }
-       case NET_REMOVE_IF:
-       {
-               int ret;
-
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-               if ((unsigned long) parg >= DVB_NET_DEVICES_MAX)
-                       return -EINVAL;
-               ret = dvb_net_remove_if(dvbnet, (unsigned long) parg);
-               if (!ret)
-                       module_put(dvbdev->adapter->module);
-               return ret;
-       }
-
-       /* binary compatibility cruft */
-       case __NET_ADD_IF_OLD:
-       {
-               struct __dvb_net_if_old *dvbnetif = parg;
-               int result;
-
-               if (!capable(CAP_SYS_ADMIN))
-                       return -EPERM;
-
-               if (!try_module_get(dvbdev->adapter->module))
-                       return -EPERM;
-
-               result=dvb_net_add_if(dvbnet, dvbnetif->pid, DVB_NET_FEEDTYPE_MPE);
-               if (result<0) {
-                       module_put(dvbdev->adapter->module);
-                       return result;
-               }
-               dvbnetif->if_num=result;
-               break;
-       }
-       case __NET_GET_IF_OLD:
-       {
-               struct net_device *netdev;
-               struct dvb_net_priv *priv_data;
-               struct __dvb_net_if_old *dvbnetif = parg;
-
-               if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX ||
-                   !dvbnet->state[dvbnetif->if_num])
-                       return -EINVAL;
-
-               netdev = dvbnet->device[dvbnetif->if_num];
-
-               priv_data = netdev_priv(netdev);
-               dvbnetif->pid=priv_data->pid;
-               break;
-       }
-       default:
-               return -ENOTTY;
-       }
-       return 0;
-}
-
-static long dvb_net_ioctl(struct file *file,
-             unsigned int cmd, unsigned long arg)
-{
-       return dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl);
-}
-
-static int dvb_net_close(struct inode *inode, struct file *file)
-{
-       struct dvb_device *dvbdev = file->private_data;
-       struct dvb_net *dvbnet = dvbdev->priv;
-
-       dvb_generic_release(inode, file);
-
-       if(dvbdev->users == 1 && dvbnet->exit == 1) {
-               fops_put(file->f_op);
-               file->f_op = NULL;
-               wake_up(&dvbdev->wait_queue);
-       }
-       return 0;
-}
-
-
-static const struct file_operations dvb_net_fops = {
-       .owner = THIS_MODULE,
-       .unlocked_ioctl = dvb_net_ioctl,
-       .open = dvb_generic_open,
-       .release = dvb_net_close,
-       .llseek = noop_llseek,
-};
-
-static struct dvb_device dvbdev_net = {
-       .priv = NULL,
-       .users = 1,
-       .writers = 1,
-       .fops = &dvb_net_fops,
-};
-
-
-void dvb_net_release (struct dvb_net *dvbnet)
-{
-       int i;
-
-       dvbnet->exit = 1;
-       if (dvbnet->dvbdev->users < 1)
-               wait_event(dvbnet->dvbdev->wait_queue,
-                               dvbnet->dvbdev->users==1);
-
-       dvb_unregister_device(dvbnet->dvbdev);
-
-       for (i=0; i<DVB_NET_DEVICES_MAX; i++) {
-               if (!dvbnet->state[i])
-                       continue;
-               dvb_net_remove_if(dvbnet, i);
-       }
-}
-EXPORT_SYMBOL(dvb_net_release);
-
-
-int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet,
-                 struct dmx_demux *dmx)
-{
-       int i;
-
-       dvbnet->demux = dmx;
-
-       for (i=0; i<DVB_NET_DEVICES_MAX; i++)
-               dvbnet->state[i] = 0;
-
-       return dvb_register_device(adap, &dvbnet->dvbdev, &dvbdev_net,
-                            dvbnet, DVB_DEVICE_NET);
-}
-EXPORT_SYMBOL(dvb_net_init);
diff --git a/drivers/media/dvb/dvb-core/dvb_net.h b/drivers/media/dvb/dvb-core/dvb_net.h
deleted file mode 100644 (file)
index 1e53acd..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * dvb_net.h
- *
- * Copyright (C) 2001 Ralph Metzler for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU 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 _DVB_NET_H_
-#define _DVB_NET_H_
-
-#include <linux/module.h>
-#include <linux/netdevice.h>
-#include <linux/inetdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include "dvbdev.h"
-
-#define DVB_NET_DEVICES_MAX 10
-
-#ifdef CONFIG_DVB_NET
-
-struct dvb_net {
-       struct dvb_device *dvbdev;
-       struct net_device *device[DVB_NET_DEVICES_MAX];
-       int state[DVB_NET_DEVICES_MAX];
-       unsigned int exit:1;
-       struct dmx_demux *demux;
-};
-
-void dvb_net_release(struct dvb_net *);
-int  dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *);
-
-#else
-
-struct dvb_net {
-       struct dvb_device *dvbdev;
-};
-
-static inline void dvb_net_release(struct dvb_net *dvbnet)
-{
-}
-
-static inline int dvb_net_init(struct dvb_adapter *adap,
-                              struct dvb_net *dvbnet, struct dmx_demux *dmx)
-{
-       return 0;
-}
-
-#endif /* ifdef CONFIG_DVB_NET */
-
-#endif
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c
deleted file mode 100644 (file)
index a5712cd..0000000
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- *
- * dvb_ringbuffer.c: ring buffer implementation for the dvb driver
- *
- * Copyright (C) 2003 Oliver Endriss
- * Copyright (C) 2004 Andrew de Quincey
- *
- * based on code originally found in av7110.c & dvb_ci.c:
- * Copyright (C) 1999-2003 Ralph  Metzler
- *                       & Marcus Metzler for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-
-
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <asm/uaccess.h>
-
-#include "dvb_ringbuffer.h"
-
-#define PKT_READY 0
-#define PKT_DISPOSED 1
-
-
-void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len)
-{
-       rbuf->pread=rbuf->pwrite=0;
-       rbuf->data=data;
-       rbuf->size=len;
-       rbuf->error=0;
-
-       init_waitqueue_head(&rbuf->queue);
-
-       spin_lock_init(&(rbuf->lock));
-}
-
-
-
-int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf)
-{
-       return (rbuf->pread==rbuf->pwrite);
-}
-
-
-
-ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf)
-{
-       ssize_t free;
-
-       free = rbuf->pread - rbuf->pwrite;
-       if (free <= 0)
-               free += rbuf->size;
-       return free-1;
-}
-
-
-
-ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf)
-{
-       ssize_t avail;
-
-       avail = rbuf->pwrite - rbuf->pread;
-       if (avail < 0)
-               avail += rbuf->size;
-       return avail;
-}
-
-
-
-void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf)
-{
-       rbuf->pread = rbuf->pwrite;
-       rbuf->error = 0;
-}
-EXPORT_SYMBOL(dvb_ringbuffer_flush);
-
-void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf)
-{
-       rbuf->pread = rbuf->pwrite = 0;
-       rbuf->error = 0;
-}
-
-void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&rbuf->lock, flags);
-       dvb_ringbuffer_flush(rbuf);
-       spin_unlock_irqrestore(&rbuf->lock, flags);
-
-       wake_up(&rbuf->queue);
-}
-
-ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, size_t len)
-{
-       size_t todo = len;
-       size_t split;
-
-       split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
-       if (split > 0) {
-               if (copy_to_user(buf, rbuf->data+rbuf->pread, split))
-                       return -EFAULT;
-               buf += split;
-               todo -= split;
-               rbuf->pread = 0;
-       }
-       if (copy_to_user(buf, rbuf->data+rbuf->pread, todo))
-               return -EFAULT;
-
-       rbuf->pread = (rbuf->pread + todo) % rbuf->size;
-
-       return len;
-}
-
-void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len)
-{
-       size_t todo = len;
-       size_t split;
-
-       split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0;
-       if (split > 0) {
-               memcpy(buf, rbuf->data+rbuf->pread, split);
-               buf += split;
-               todo -= split;
-               rbuf->pread = 0;
-       }
-       memcpy(buf, rbuf->data+rbuf->pread, todo);
-
-       rbuf->pread = (rbuf->pread + todo) % rbuf->size;
-}
-
-
-ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len)
-{
-       size_t todo = len;
-       size_t split;
-
-       split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0;
-
-       if (split > 0) {
-               memcpy(rbuf->data+rbuf->pwrite, buf, split);
-               buf += split;
-               todo -= split;
-               rbuf->pwrite = 0;
-       }
-       memcpy(rbuf->data+rbuf->pwrite, buf, todo);
-       rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size;
-
-       return len;
-}
-
-ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len)
-{
-       int status;
-       ssize_t oldpwrite = rbuf->pwrite;
-
-       DVB_RINGBUFFER_WRITE_BYTE(rbuf, len >> 8);
-       DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff);
-       DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_READY);
-       status = dvb_ringbuffer_write(rbuf, buf, len);
-
-       if (status < 0) rbuf->pwrite = oldpwrite;
-       return status;
-}
-
-ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
-                               int offset, u8 __user *buf, size_t len)
-{
-       size_t todo;
-       size_t split;
-       size_t pktlen;
-
-       pktlen = rbuf->data[idx] << 8;
-       pktlen |= rbuf->data[(idx + 1) % rbuf->size];
-       if (offset > pktlen) return -EINVAL;
-       if ((offset + len) > pktlen) len = pktlen - offset;
-
-       idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
-       todo = len;
-       split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
-       if (split > 0) {
-               if (copy_to_user(buf, rbuf->data+idx, split))
-                       return -EFAULT;
-               buf += split;
-               todo -= split;
-               idx = 0;
-       }
-       if (copy_to_user(buf, rbuf->data+idx, todo))
-               return -EFAULT;
-
-       return len;
-}
-
-ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
-                               int offset, u8* buf, size_t len)
-{
-       size_t todo;
-       size_t split;
-       size_t pktlen;
-
-       pktlen = rbuf->data[idx] << 8;
-       pktlen |= rbuf->data[(idx + 1) % rbuf->size];
-       if (offset > pktlen) return -EINVAL;
-       if ((offset + len) > pktlen) len = pktlen - offset;
-
-       idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size;
-       todo = len;
-       split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0;
-       if (split > 0) {
-               memcpy(buf, rbuf->data+idx, split);
-               buf += split;
-               todo -= split;
-               idx = 0;
-       }
-       memcpy(buf, rbuf->data+idx, todo);
-       return len;
-}
-
-void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx)
-{
-       size_t pktlen;
-
-       rbuf->data[(idx + 2) % rbuf->size] = PKT_DISPOSED;
-
-       // clean up disposed packets
-       while(dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) {
-               if (DVB_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) {
-                       pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8;
-                       pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1);
-                       DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE);
-               } else {
-                       // first packet is not disposed, so we stop cleaning now
-                       break;
-               }
-       }
-}
-
-ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen)
-{
-       int consumed;
-       int curpktlen;
-       int curpktstatus;
-
-       if (idx == -1) {
-              idx = rbuf->pread;
-       } else {
-               curpktlen = rbuf->data[idx] << 8;
-               curpktlen |= rbuf->data[(idx + 1) % rbuf->size];
-               idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
-       }
-
-       consumed = (idx - rbuf->pread) % rbuf->size;
-
-       while((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) {
-
-               curpktlen = rbuf->data[idx] << 8;
-               curpktlen |= rbuf->data[(idx + 1) % rbuf->size];
-               curpktstatus = rbuf->data[(idx + 2) % rbuf->size];
-
-               if (curpktstatus == PKT_READY) {
-                       *pktlen = curpktlen;
-                       return idx;
-               }
-
-               consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE;
-               idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size;
-       }
-
-       // no packets available
-       return -1;
-}
-
-
-
-EXPORT_SYMBOL(dvb_ringbuffer_init);
-EXPORT_SYMBOL(dvb_ringbuffer_empty);
-EXPORT_SYMBOL(dvb_ringbuffer_free);
-EXPORT_SYMBOL(dvb_ringbuffer_avail);
-EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup);
-EXPORT_SYMBOL(dvb_ringbuffer_read_user);
-EXPORT_SYMBOL(dvb_ringbuffer_read);
-EXPORT_SYMBOL(dvb_ringbuffer_write);
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h
deleted file mode 100644 (file)
index 41f04da..0000000
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- *
- * dvb_ringbuffer.h: ring buffer implementation for the dvb driver
- *
- * Copyright (C) 2003 Oliver Endriss
- * Copyright (C) 2004 Andrew de Quincey
- *
- * based on code originally found in av7110.c & dvb_ci.c:
- * Copyright (C) 1999-2003 Ralph Metzler & Marcus Metzler
- *                         for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- */
-
-#ifndef _DVB_RINGBUFFER_H_
-#define _DVB_RINGBUFFER_H_
-
-#include <linux/spinlock.h>
-#include <linux/wait.h>
-
-struct dvb_ringbuffer {
-       u8               *data;
-       ssize_t           size;
-       ssize_t           pread;
-       ssize_t           pwrite;
-       int               error;
-
-       wait_queue_head_t queue;
-       spinlock_t        lock;
-};
-
-#define DVB_RINGBUFFER_PKTHDRSIZE 3
-
-
-/*
-** Notes:
-** ------
-** (1) For performance reasons read and write routines don't check buffer sizes
-**     and/or number of bytes free/available. This has to be done before these
-**     routines are called. For example:
-**
-**     *** write <buflen> bytes ***
-**     free = dvb_ringbuffer_free(rbuf);
-**     if (free >= buflen)
-**         count = dvb_ringbuffer_write(rbuf, buffer, buflen);
-**     else
-**         ...
-**
-**     *** read min. 1000, max. <bufsize> bytes ***
-**     avail = dvb_ringbuffer_avail(rbuf);
-**     if (avail >= 1000)
-**         count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize));
-**     else
-**         ...
-**
-** (2) If there is exactly one reader and one writer, there is no need
-**     to lock read or write operations.
-**     Two or more readers must be locked against each other.
-**     Flushing the buffer counts as a read operation.
-**     Resetting the buffer counts as a read and write operation.
-**     Two or more writers must be locked against each other.
-*/
-
-/* initialize ring buffer, lock and queue */
-extern void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len);
-
-/* test whether buffer is empty */
-extern int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf);
-
-/* return the number of free bytes in the buffer */
-extern ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf);
-
-/* return the number of bytes waiting in the buffer */
-extern ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf);
-
-
-/*
-** Reset the read and write pointers to zero and flush the buffer
-** This counts as a read and write operation
-*/
-extern void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf);
-
-
-/* read routines & macros */
-/* ---------------------- */
-/* flush buffer */
-extern void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf);
-
-/* flush buffer protected by spinlock and wake-up waiting task(s) */
-extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf);
-
-/* peek at byte <offs> in the buffer */
-#define DVB_RINGBUFFER_PEEK(rbuf,offs) \
-                       (rbuf)->data[((rbuf)->pread+(offs))%(rbuf)->size]
-
-/* advance read ptr by <num> bytes */
-#define DVB_RINGBUFFER_SKIP(rbuf,num)  \
-                       (rbuf)->pread=((rbuf)->pread+(num))%(rbuf)->size
-
-/*
-** read <len> bytes from ring buffer into <buf>
-** <usermem> specifies whether <buf> resides in user space
-** returns number of bytes transferred or -EFAULT
-*/
-extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf,
-                                  u8 __user *buf, size_t len);
-extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf,
-                                  u8 *buf, size_t len);
-
-
-/* write routines & macros */
-/* ----------------------- */
-/* write single byte to ring buffer */
-#define DVB_RINGBUFFER_WRITE_BYTE(rbuf,byte)   \
-                       { (rbuf)->data[(rbuf)->pwrite]=(byte); \
-                       (rbuf)->pwrite=((rbuf)->pwrite+1)%(rbuf)->size; }
-/*
-** write <len> bytes to ring buffer
-** <usermem> specifies whether <buf> resides in user space
-** returns number of bytes transferred or -EFAULT
-*/
-extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf,
-                                   size_t len);
-
-
-/**
- * Write a packet into the ringbuffer.
- *
- * <rbuf> Ringbuffer to write to.
- * <buf> Buffer to write.
- * <len> Length of buffer (currently limited to 65535 bytes max).
- * returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL.
- */
-extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf,
-                                       size_t len);
-
-/**
- * Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this
- * does NOT update the read pointer in the ringbuffer. You must use
- * dvb_ringbuffer_pkt_dispose() to mark a packet as no longer required.
- *
- * <rbuf> Ringbuffer concerned.
- * <idx> Packet index as returned by dvb_ringbuffer_pkt_next().
- * <offset> Offset into packet to read from.
- * <buf> Destination buffer for data.
- * <len> Size of destination buffer.
- * <usermem> Set to 1 if <buf> is in userspace.
- * returns Number of bytes read, or -EFAULT.
- */
-extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx,
-                                      int offset, u8 __user *buf, size_t len);
-extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx,
-                                      int offset, u8 *buf, size_t len);
-
-/**
- * Dispose of a packet in the ring buffer.
- *
- * <rbuf> Ring buffer concerned.
- * <idx> Packet index as returned by dvb_ringbuffer_pkt_next().
- */
-extern void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx);
-
-/**
- * Get the index of the next packet in a ringbuffer.
- *
- * <rbuf> Ringbuffer concerned.
- * <idx> Previous packet index, or -1 to return the first packet index.
- * <pktlen> On success, will be updated to contain the length of the packet in bytes.
- * returns Packet index (if >=0), or -1 if no packets available.
- */
-extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen);
-
-
-#endif /* _DVB_RINGBUFFER_H_ */
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
deleted file mode 100644 (file)
index 39eab73..0000000
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * dvbdev.c
- *
- * Copyright (C) 2000 Ralph  Metzler <ralph@convergence.de>
- *                  & Marcus Metzler <marcus@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 <linux/types.h>
-#include <linux/errno.h>
-#include <linux/string.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/cdev.h>
-#include <linux/mutex.h>
-#include "dvbdev.h"
-
-static DEFINE_MUTEX(dvbdev_mutex);
-static int dvbdev_debug;
-
-module_param(dvbdev_debug, int, 0644);
-MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off).");
-
-#define dprintk if (dvbdev_debug) printk
-
-static LIST_HEAD(dvb_adapter_list);
-static DEFINE_MUTEX(dvbdev_register_lock);
-
-static const char * const dnames[] = {
-       "video", "audio", "sec", "frontend", "demux", "dvr", "ca",
-       "net", "osd"
-};
-
-#ifdef CONFIG_DVB_DYNAMIC_MINORS
-#define MAX_DVB_MINORS         256
-#define DVB_MAX_IDS            MAX_DVB_MINORS
-#else
-#define DVB_MAX_IDS            4
-#define nums2minor(num,type,id)        ((num << 6) | (id << 4) | type)
-#define MAX_DVB_MINORS         (DVB_MAX_ADAPTERS*64)
-#endif
-
-static struct class *dvb_class;
-
-static struct dvb_device *dvb_minors[MAX_DVB_MINORS];
-static DECLARE_RWSEM(minor_rwsem);
-
-static int dvb_device_open(struct inode *inode, struct file *file)
-{
-       struct dvb_device *dvbdev;
-
-       mutex_lock(&dvbdev_mutex);
-       down_read(&minor_rwsem);
-       dvbdev = dvb_minors[iminor(inode)];
-
-       if (dvbdev && dvbdev->fops) {
-               int err = 0;
-               const struct file_operations *old_fops;
-
-               file->private_data = dvbdev;
-               old_fops = file->f_op;
-               file->f_op = fops_get(dvbdev->fops);
-               if (file->f_op == NULL) {
-                       file->f_op = old_fops;
-                       goto fail;
-               }
-               if(file->f_op->open)
-                       err = file->f_op->open(inode,file);
-               if (err) {
-                       fops_put(file->f_op);
-                       file->f_op = fops_get(old_fops);
-               }
-               fops_put(old_fops);
-               up_read(&minor_rwsem);
-               mutex_unlock(&dvbdev_mutex);
-               return err;
-       }
-fail:
-       up_read(&minor_rwsem);
-       mutex_unlock(&dvbdev_mutex);
-       return -ENODEV;
-}
-
-
-static const struct file_operations dvb_device_fops =
-{
-       .owner =        THIS_MODULE,
-       .open =         dvb_device_open,
-       .llseek =       noop_llseek,
-};
-
-static struct cdev dvb_device_cdev;
-
-int dvb_generic_open(struct inode *inode, struct file *file)
-{
-       struct dvb_device *dvbdev = file->private_data;
-
-       if (!dvbdev)
-               return -ENODEV;
-
-       if (!dvbdev->users)
-               return -EBUSY;
-
-       if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
-               if (!dvbdev->readers)
-                       return -EBUSY;
-               dvbdev->readers--;
-       } else {
-               if (!dvbdev->writers)
-                       return -EBUSY;
-               dvbdev->writers--;
-       }
-
-       dvbdev->users--;
-       return 0;
-}
-EXPORT_SYMBOL(dvb_generic_open);
-
-
-int dvb_generic_release(struct inode *inode, struct file *file)
-{
-       struct dvb_device *dvbdev = file->private_data;
-
-       if (!dvbdev)
-               return -ENODEV;
-
-       if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
-               dvbdev->readers++;
-       } else {
-               dvbdev->writers++;
-       }
-
-       dvbdev->users++;
-       return 0;
-}
-EXPORT_SYMBOL(dvb_generic_release);
-
-
-long dvb_generic_ioctl(struct file *file,
-                      unsigned int cmd, unsigned long arg)
-{
-       struct dvb_device *dvbdev = file->private_data;
-
-       if (!dvbdev)
-               return -ENODEV;
-
-       if (!dvbdev->kernel_ioctl)
-               return -EINVAL;
-
-       return dvb_usercopy(file, cmd, arg, dvbdev->kernel_ioctl);
-}
-EXPORT_SYMBOL(dvb_generic_ioctl);
-
-
-static int dvbdev_get_free_id (struct dvb_adapter *adap, int type)
-{
-       u32 id = 0;
-
-       while (id < DVB_MAX_IDS) {
-               struct dvb_device *dev;
-               list_for_each_entry(dev, &adap->device_list, list_head)
-                       if (dev->type == type && dev->id == id)
-                               goto skip;
-               return id;
-skip:
-               id++;
-       }
-       return -ENFILE;
-}
-
-
-int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
-                       const struct dvb_device *template, void *priv, int type)
-{
-       struct dvb_device *dvbdev;
-       struct file_operations *dvbdevfops;
-       struct device *clsdev;
-       int minor;
-       int id;
-
-       mutex_lock(&dvbdev_register_lock);
-
-       if ((id = dvbdev_get_free_id (adap, type)) < 0){
-               mutex_unlock(&dvbdev_register_lock);
-               *pdvbdev = NULL;
-               printk(KERN_ERR "%s: couldn't find free device id\n", __func__);
-               return -ENFILE;
-       }
-
-       *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL);
-
-       if (!dvbdev){
-               mutex_unlock(&dvbdev_register_lock);
-               return -ENOMEM;
-       }
-
-       dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
-
-       if (!dvbdevfops){
-               kfree (dvbdev);
-               mutex_unlock(&dvbdev_register_lock);
-               return -ENOMEM;
-       }
-
-       memcpy(dvbdev, template, sizeof(struct dvb_device));
-       dvbdev->type = type;
-       dvbdev->id = id;
-       dvbdev->adapter = adap;
-       dvbdev->priv = priv;
-       dvbdev->fops = dvbdevfops;
-       init_waitqueue_head (&dvbdev->wait_queue);
-
-       memcpy(dvbdevfops, template->fops, sizeof(struct file_operations));
-       dvbdevfops->owner = adap->module;
-
-       list_add_tail (&dvbdev->list_head, &adap->device_list);
-
-       down_write(&minor_rwsem);
-#ifdef CONFIG_DVB_DYNAMIC_MINORS
-       for (minor = 0; minor < MAX_DVB_MINORS; minor++)
-               if (dvb_minors[minor] == NULL)
-                       break;
-
-       if (minor == MAX_DVB_MINORS) {
-               kfree(dvbdevfops);
-               kfree(dvbdev);
-               up_write(&minor_rwsem);
-               mutex_unlock(&dvbdev_register_lock);
-               return -EINVAL;
-       }
-#else
-       minor = nums2minor(adap->num, type, id);
-#endif
-
-       dvbdev->minor = minor;
-       dvb_minors[minor] = dvbdev;
-       up_write(&minor_rwsem);
-
-       mutex_unlock(&dvbdev_register_lock);
-
-       clsdev = device_create(dvb_class, adap->device,
-                              MKDEV(DVB_MAJOR, minor),
-                              dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
-       if (IS_ERR(clsdev)) {
-               printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n",
-                      __func__, adap->num, dnames[type], id, PTR_ERR(clsdev));
-               return PTR_ERR(clsdev);
-       }
-
-       dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
-               adap->num, dnames[type], id, minor, minor);
-
-       return 0;
-}
-EXPORT_SYMBOL(dvb_register_device);
-
-
-void dvb_unregister_device(struct dvb_device *dvbdev)
-{
-       if (!dvbdev)
-               return;
-
-       down_write(&minor_rwsem);
-       dvb_minors[dvbdev->minor] = NULL;
-       up_write(&minor_rwsem);
-
-       device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor));
-
-       list_del (&dvbdev->list_head);
-       kfree (dvbdev->fops);
-       kfree (dvbdev);
-}
-EXPORT_SYMBOL(dvb_unregister_device);
-
-static int dvbdev_check_free_adapter_num(int num)
-{
-       struct list_head *entry;
-       list_for_each(entry, &dvb_adapter_list) {
-               struct dvb_adapter *adap;
-               adap = list_entry(entry, struct dvb_adapter, list_head);
-               if (adap->num == num)
-                       return 0;
-       }
-       return 1;
-}
-
-static int dvbdev_get_free_adapter_num (void)
-{
-       int num = 0;
-
-       while (num < DVB_MAX_ADAPTERS) {
-               if (dvbdev_check_free_adapter_num(num))
-                       return num;
-               num++;
-       }
-
-       return -ENFILE;
-}
-
-
-int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
-                        struct module *module, struct device *device,
-                        short *adapter_nums)
-{
-       int i, num;
-
-       mutex_lock(&dvbdev_register_lock);
-
-       for (i = 0; i < DVB_MAX_ADAPTERS; ++i) {
-               num = adapter_nums[i];
-               if (num >= 0  &&  num < DVB_MAX_ADAPTERS) {
-               /* use the one the driver asked for */
-                       if (dvbdev_check_free_adapter_num(num))
-                               break;
-               } else {
-                       num = dvbdev_get_free_adapter_num();
-                       break;
-               }
-               num = -1;
-       }
-
-       if (num < 0) {
-               mutex_unlock(&dvbdev_register_lock);
-               return -ENFILE;
-       }
-
-       memset (adap, 0, sizeof(struct dvb_adapter));
-       INIT_LIST_HEAD (&adap->device_list);
-
-       printk(KERN_INFO "DVB: registering new adapter (%s)\n", name);
-
-       adap->num = num;
-       adap->name = name;
-       adap->module = module;
-       adap->device = device;
-       adap->mfe_shared = 0;
-       adap->mfe_dvbdev = NULL;
-       mutex_init (&adap->mfe_lock);
-
-       list_add_tail (&adap->list_head, &dvb_adapter_list);
-
-       mutex_unlock(&dvbdev_register_lock);
-
-       return num;
-}
-EXPORT_SYMBOL(dvb_register_adapter);
-
-
-int dvb_unregister_adapter(struct dvb_adapter *adap)
-{
-       mutex_lock(&dvbdev_register_lock);
-       list_del (&adap->list_head);
-       mutex_unlock(&dvbdev_register_lock);
-       return 0;
-}
-EXPORT_SYMBOL(dvb_unregister_adapter);
-
-/* if the miracle happens and "generic_usercopy()" is included into
-   the kernel, then this can vanish. please don't make the mistake and
-   define this as video_usercopy(). this will introduce a dependecy
-   to the v4l "videodev.o" module, which is unnecessary for some
-   cards (ie. the budget dvb-cards don't need the v4l module...) */
-int dvb_usercopy(struct file *file,
-                    unsigned int cmd, unsigned long arg,
-                    int (*func)(struct file *file,
-                    unsigned int cmd, void *arg))
-{
-       char    sbuf[128];
-       void    *mbuf = NULL;
-       void    *parg = NULL;
-       int     err  = -EINVAL;
-
-       /*  Copy arguments into temp kernel buffer  */
-       switch (_IOC_DIR(cmd)) {
-       case _IOC_NONE:
-               /*
-                * For this command, the pointer is actually an integer
-                * argument.
-                */
-               parg = (void *) arg;
-               break;
-       case _IOC_READ: /* some v4l ioctls are marked wrong ... */
-       case _IOC_WRITE:
-       case (_IOC_WRITE | _IOC_READ):
-               if (_IOC_SIZE(cmd) <= sizeof(sbuf)) {
-                       parg = sbuf;
-               } else {
-                       /* too big to allocate from stack */
-                       mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL);
-                       if (NULL == mbuf)
-                               return -ENOMEM;
-                       parg = mbuf;
-               }
-
-               err = -EFAULT;
-               if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd)))
-                       goto out;
-               break;
-       }
-
-       /* call driver */
-       mutex_lock(&dvbdev_mutex);
-       if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD)
-               err = -EINVAL;
-       mutex_unlock(&dvbdev_mutex);
-
-       if (err < 0)
-               goto out;
-
-       /*  Copy results into user buffer  */
-       switch (_IOC_DIR(cmd))
-       {
-       case _IOC_READ:
-       case (_IOC_WRITE | _IOC_READ):
-               if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd)))
-                       err = -EFAULT;
-               break;
-       }
-
-out:
-       kfree(mbuf);
-       return err;
-}
-
-static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
-{
-       struct dvb_device *dvbdev = dev_get_drvdata(dev);
-
-       add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num);
-       add_uevent_var(env, "DVB_DEVICE_TYPE=%s", dnames[dvbdev->type]);
-       add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id);
-       return 0;
-}
-
-static char *dvb_devnode(struct device *dev, umode_t *mode)
-{
-       struct dvb_device *dvbdev = dev_get_drvdata(dev);
-
-       return kasprintf(GFP_KERNEL, "dvb/adapter%d/%s%d",
-               dvbdev->adapter->num, dnames[dvbdev->type], dvbdev->id);
-}
-
-
-static int __init init_dvbdev(void)
-{
-       int retval;
-       dev_t dev = MKDEV(DVB_MAJOR, 0);
-
-       if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) {
-               printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR);
-               return retval;
-       }
-
-       cdev_init(&dvb_device_cdev, &dvb_device_fops);
-       if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) {
-               printk(KERN_ERR "dvb-core: unable register character device\n");
-               goto error;
-       }
-
-       dvb_class = class_create(THIS_MODULE, "dvb");
-       if (IS_ERR(dvb_class)) {
-               retval = PTR_ERR(dvb_class);
-               goto error;
-       }
-       dvb_class->dev_uevent = dvb_uevent;
-       dvb_class->devnode = dvb_devnode;
-       return 0;
-
-error:
-       cdev_del(&dvb_device_cdev);
-       unregister_chrdev_region(dev, MAX_DVB_MINORS);
-       return retval;
-}
-
-
-static void __exit exit_dvbdev(void)
-{
-       class_destroy(dvb_class);
-       cdev_del(&dvb_device_cdev);
-       unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS);
-}
-
-subsys_initcall(init_dvbdev);
-module_exit(exit_dvbdev);
-
-MODULE_DESCRIPTION("DVB Core Driver");
-MODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h
deleted file mode 100644 (file)
index 93a9470..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * dvbdev.h
- *
- * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
- *                    for convergence integrated media GmbH
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General 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 _DVBDEV_H_
-#define _DVBDEV_H_
-
-#include <linux/types.h>
-#include <linux/poll.h>
-#include <linux/fs.h>
-#include <linux/list.h>
-
-#define DVB_MAJOR 212
-
-#if defined(CONFIG_DVB_MAX_ADAPTERS) && CONFIG_DVB_MAX_ADAPTERS > 0
-  #define DVB_MAX_ADAPTERS CONFIG_DVB_MAX_ADAPTERS
-#else
-  #define DVB_MAX_ADAPTERS 8
-#endif
-
-#define DVB_UNSET (-1)
-
-#define DVB_DEVICE_VIDEO      0
-#define DVB_DEVICE_AUDIO      1
-#define DVB_DEVICE_SEC        2
-#define DVB_DEVICE_FRONTEND   3
-#define DVB_DEVICE_DEMUX      4
-#define DVB_DEVICE_DVR        5
-#define DVB_DEVICE_CA         6
-#define DVB_DEVICE_NET        7
-#define DVB_DEVICE_OSD        8
-
-#define DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr) \
-       static short adapter_nr[] = \
-               {[0 ... (DVB_MAX_ADAPTERS - 1)] = DVB_UNSET }; \
-       module_param_array(adapter_nr, short, NULL, 0444); \
-       MODULE_PARM_DESC(adapter_nr, "DVB adapter numbers")
-
-struct dvb_frontend;
-
-struct dvb_adapter {
-       int num;
-       struct list_head list_head;
-       struct list_head device_list;
-       const char *name;
-       u8 proposed_mac [6];
-       void* priv;
-
-       struct device *device;
-
-       struct module *module;
-
-       int mfe_shared;                 /* indicates mutually exclusive frontends */
-       struct dvb_device *mfe_dvbdev;  /* frontend device in use */
-       struct mutex mfe_lock;          /* access lock for thread creation */
-};
-
-
-struct dvb_device {
-       struct list_head list_head;
-       const struct file_operations *fops;
-       struct dvb_adapter *adapter;
-       int type;
-       int minor;
-       u32 id;
-
-       /* in theory, 'users' can vanish now,
-          but I don't want to change too much now... */
-       int readers;
-       int writers;
-       int users;
-
-       wait_queue_head_t         wait_queue;
-       /* don't really need those !? -- FIXME: use video_usercopy  */
-       int (*kernel_ioctl)(struct file *file, unsigned int cmd, void *arg);
-
-       void *priv;
-};
-
-
-extern int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
-                               struct module *module, struct device *device,
-                               short *adapter_nums);
-extern int dvb_unregister_adapter (struct dvb_adapter *adap);
-
-extern int dvb_register_device (struct dvb_adapter *adap,
-                               struct dvb_device **pdvbdev,
-                               const struct dvb_device *template,
-                               void *priv,
-                               int type);
-
-extern void dvb_unregister_device (struct dvb_device *dvbdev);
-
-extern int dvb_generic_open (struct inode *inode, struct file *file);
-extern int dvb_generic_release (struct inode *inode, struct file *file);
-extern long dvb_generic_ioctl (struct file *file,
-                             unsigned int cmd, unsigned long arg);
-
-/* we don't mess with video_usercopy() any more,
-we simply define out own dvb_usercopy(), which will hopefully become
-generic_usercopy()  someday... */
-
-extern int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
-                           int (*func)(struct file *file, unsigned int cmd, void *arg));
-
-/** generic DVB attach function. */
-#ifdef CONFIG_MEDIA_ATTACH
-#define dvb_attach(FUNCTION, ARGS...) ({ \
-       void *__r = NULL; \
-       typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
-       if (__a) { \
-               __r = (void *) __a(ARGS); \
-               if (__r == NULL) \
-                       symbol_put(FUNCTION); \
-       } else { \
-               printk(KERN_ERR "DVB: Unable to find symbol "#FUNCTION"()\n"); \
-       } \
-       __r; \
-})
-
-#else
-#define dvb_attach(FUNCTION, ARGS...) ({ \
-       FUNCTION(ARGS); \
-})
-
-#endif
-
-#endif /* #ifndef _DVBDEV_H_ */
index 61b0f53669e8256300c95fc1ed632a1c382e65da..9fef543dac21bc912547ed7650d567dbb465c5a5 100644 (file)
@@ -42,7 +42,7 @@ obj-$(CONFIG_DVB_USB_MXL111SF) += mxl111sf-tuner.o
 dvb-usb-rtl28xxu-objs = rtl28xxu.o
 obj-$(CONFIG_DVB_USB_RTL28XXU) += dvb-usb-rtl28xxu.o
 
-ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb/frontends/
 ccflags-y += -I$(srctree)/drivers/media/common/tuners
 
index 061d5448fa1ea644bf9a7b45ef9e2e58e193539e..cc95b116bbc25829aeae572dcaa1cddfeb01bee3 100644 (file)
@@ -75,7 +75,7 @@ obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o
 dvb-usb-technisat-usb2-objs = technisat-usb2.o
 obj-$(CONFIG_DVB_USB_TECHNISAT_USB2) += dvb-usb-technisat-usb2.o
 
-ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb/frontends/
 # due to tuner-xc3028
 ccflags-y += -I$(srctree)/drivers/media/common/tuners
index 357b3aab186b2d1645419a073bee2e26acdf9ba7..f3148138c96314371f4396ffe4aa3b7094853139 100644 (file)
@@ -3,4 +3,4 @@ obj-$(CONFIG_DVB_FIREDTV) += firedtv.o
 firedtv-y := firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o firedtv-fw.o
 firedtv-$(CONFIG_DVB_FIREDTV_INPUT)    += firedtv-rc.o
 
-ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb-core
index 185bb8b51952ec0190aa4a35c2c0bd0cbfbef42e..a378c529376495842f4f14c9f9e23f61c18332ed 100644 (file)
@@ -2,7 +2,7 @@
 # Makefile for the kernel DVB frontend device drivers.
 #
 
-ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core/
+ccflags-y += -I$(srctree)/drivers/media/dvb-core/
 ccflags-y += -I$(srctree)/drivers/media/common/tuners/
 
 stb0899-objs = stb0899_drv.o stb0899_algo.o
index ec8116dcb368cea9f43bebe1bc1e28f8f64915c0..33841191736196c3aa16ffa71d3047bc9b5d2c48 100644 (file)
@@ -25,4 +25,4 @@ obj-$(CONFIG_MANTIS_CORE)     += mantis_core.o
 obj-$(CONFIG_DVB_MANTIS)       += mantis.o
 obj-$(CONFIG_DVB_HOPPER)       += hopper.o
 
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb/frontends/
index 13ebeffb705ffeee530c91e5859ef22e1512b66f..dae76597fc3196bb860102d4d24a854a41fac3bd 100644 (file)
@@ -6,7 +6,7 @@ ngene-objs := ngene-core.o ngene-i2c.o ngene-cards.o ngene-dvb.o
 
 obj-$(CONFIG_DVB_NGENE) += ngene.o
 
-ccflags-y += -Idrivers/media/dvb/dvb-core/
+ccflags-y += -Idrivers/media/dvb-core/
 ccflags-y += -Idrivers/media/dvb/frontends/
 ccflags-y += -Idrivers/media/common/tuners/
 
index 700822350ec5def033151293ea8e0ffc6585aa17..14fa5789c748babe1f40185d31bf7f1cf05f9dfc 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_PLUTO2) += pluto2.o
 
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb/frontends/
index d80d8e8e7c572b7218bd1103e669ab50ed352f97..c80492a1039e80ba6a9dc11cb91217eae522d74c 100644 (file)
@@ -2,4 +2,4 @@ earth-pt1-objs := pt1.o va1j5jf8007s.o va1j5jf8007t.o
 
 obj-$(CONFIG_DVB_PT1) += earth-pt1.o
 
-ccflags-y += -Idrivers/media/dvb/dvb-core -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/dvb-core -Idrivers/media/dvb/frontends
index f233b57c86fb61144a6a32c11ed82e10c823d1c0..14756bdb6eaa055954d08dbd06790bc898842722 100644 (file)
@@ -5,7 +5,7 @@ obj-$(CONFIG_SMS_SIANO_MDTV) += smsmdtv.o smsdvb.o
 obj-$(CONFIG_SMS_USB_DRV) += smsusb.o
 obj-$(CONFIG_SMS_SDIO_DRV) += smssdio.o
 
-ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb-core
 
 ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
 
index f6e869372e303f3f7dfac8b497e2c0e76a40be6c..b0ddb4544cb7d8fbb54ca6bc2c14aef9f6eab1d4 100644 (file)
@@ -17,5 +17,5 @@ obj-$(CONFIG_DVB_BUDGET_CI) += budget-ci.o
 obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o
 obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
 
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb/frontends/
 ccflags-y += -Idrivers/media/common/tuners
index 8d6c4acb7f1d49eada6f692b545d0940dff6fb03..c5abe78ae04f27d4e6b6a1c3037d0cb8aac05309 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_TTUSB_BUDGET) += dvb-ttusb-budget.o
 
-ccflags-y += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends
+ccflags-y += -Idrivers/media/dvb-core/ -Idrivers/media/dvb/frontends
index ed28b5384d20c190b78c3ab66d83119d1288e41b..5352740d2353c92eb0949000bddffb7a77a4d8c7 100644 (file)
@@ -1,3 +1,3 @@
 obj-$(CONFIG_DVB_TTUSB_DEC) += ttusb_dec.o ttusbdecfe.o
 
-ccflags-y += -Idrivers/media/dvb/dvb-core/
+ccflags-y += -Idrivers/media/dvb-core/
index 7319c27e256b2f4cb30b24891470b76095d5cd14..f5036d1ec7c37b1b352e638e1c29aad461819a05 100644 (file)
@@ -29,7 +29,7 @@ obj-$(CONFIG_VIDEOBUF2_VMALLOC) += videobuf2-vmalloc.o
 obj-$(CONFIG_VIDEOBUF2_DMA_CONTIG) += videobuf2-dma-contig.o
 obj-$(CONFIG_VIDEOBUF2_DMA_SG) += videobuf2-dma-sg.o
 
-ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
 ccflags-y += -I$(srctree)/drivers/media/common/tuners
 
index 839e2c982376571571d9347a1136a97baf79e52c..9f4b063f03dafbfe087ce28eca643074a9285d0e 100644 (file)
@@ -190,6 +190,6 @@ obj-y       += davinci/
 
 obj-$(CONFIG_ARCH_OMAP)        += omap/
 
-ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
 ccflags-y += -I$(srctree)/drivers/media/common/tuners
index bd22223f8d9f943a2a94fcf1aab1a4b625192f4d..59d15b31f23fd8cf0bc60d9b68293c042258fcbb 100644 (file)
@@ -3,7 +3,7 @@ au0828-objs     := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-vid
 obj-$(CONFIG_VIDEO_AU0828) += au0828.o
 
 ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb-core
 ccflags-y += -Idrivers/media/dvb/frontends
 
 ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
index 3f9a2b22d3d414533dfd73a640b22fe8dc6feaa3..4cba4eff36d85858868dda5428f618f5fe3f86e8 100644 (file)
@@ -10,4 +10,4 @@ obj-$(CONFIG_VIDEO_BT848) += bttv.o
 
 ccflags-y += -Idrivers/media/video
 ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb-core
index a86bab5893ef0a3fd86d2357347d7ded1f841cde..e0701e92f4eebf2eadef8cdffe814f880019a395 100644 (file)
@@ -8,6 +8,6 @@ cx18-alsa-objs := cx18-alsa-main.o cx18-alsa-pcm.o
 obj-$(CONFIG_VIDEO_CX18) += cx18.o
 obj-$(CONFIG_VIDEO_CX18_ALSA) += cx18-alsa.o
 
-ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb-core
 ccflags-y += -Idrivers/media/dvb/frontends
 ccflags-y += -Idrivers/media/common/tuners
index cb06b022e011f7ac927794c34ded02f70f5c23a0..2151c3d1275b3d210164679a5168a6985fecd6d4 100644 (file)
@@ -10,6 +10,6 @@ obj-$(CONFIG_VIDEO_CX231XX_DVB) += cx231xx-dvb.o
 
 ccflags-y += -Idrivers/media/video
 ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb-core
 ccflags-y += -Idrivers/media/dvb/frontends
 
index f81f2796a0f9e45fc0bb717bed3d79e2525e48ba..3608f327a4b0f237ca301318cb13c8e21caa9cf3 100644 (file)
@@ -9,7 +9,7 @@ obj-$(CONFIG_MEDIA_ALTERA_CI) += altera-ci.o
 
 ccflags-y += -Idrivers/media/video
 ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb-core
 ccflags-y += -Idrivers/media/dvb/frontends
 
 ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
index aedde18c68f96f68e377e43eb2d3d2824c7b213c..1628aa3b13fb4e1e2aafaab7d020164d082dba34 100644 (file)
@@ -9,5 +9,5 @@ obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.o
 
 ccflags-y := -Idrivers/media/video
 ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb-core
 ccflags-y += -Idrivers/media/dvb/frontends
index c1a2785ba2431a607e9791edeeae6fa4f05adb5c..1902366f9b81695377ddae01582f02e9d39df141 100644 (file)
@@ -12,5 +12,5 @@ obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o
 
 ccflags-y += -Idrivers/media/video
 ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb-core
 ccflags-y += -Idrivers/media/dvb/frontends
index c8b338d4be05b270c9415899d9fd771a05a8d933..b00298a02d5d095a96d072574d95e130e54d4478 100644 (file)
@@ -11,5 +11,5 @@ obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o
 
 ccflags-y += -Idrivers/media/video
 ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb-core
 ccflags-y += -Idrivers/media/dvb/frontends
index 77de8a45b46f56ca4a0d42e732164b562fb0c951..c54cfe12e20257e4ebb6905ed2d3b4571b5fa58d 100644 (file)
@@ -9,6 +9,6 @@ obj-$(CONFIG_VIDEO_FB_IVTV) += ivtvfb.o
 
 ccflags-y += -I$(srctree)/drivers/media/video
 ccflags-y += -I$(srctree)/drivers/media/common/tuners
-ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
 
index c17f37d964ad00460700abcc3a4105e3f84605d9..298a9306e767d5239b71196868d043ae90378544 100644 (file)
@@ -18,5 +18,5 @@ obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o
 
 ccflags-y += -Idrivers/media/video
 ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb-core
 ccflags-y += -Idrivers/media/dvb/frontends
index da3899329f52bd9cad6e83d24643f84e4b4a24e0..364891fb8e355e0319d9a0d0b4245bb08bb7ae09 100644 (file)
@@ -12,5 +12,5 @@ obj-$(CONFIG_VIDEO_SAA7134_DVB) += saa7134-dvb.o
 
 ccflags-y += -I$(srctree)/drivers/media/video
 ccflags-y += -I$(srctree)/drivers/media/common/tuners
-ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
index 068443af30c8066e29c184d84788c9301ec592b2..50e19f943e78fe08ffb8bd0a679e14e6c81a236b 100644 (file)
@@ -6,7 +6,7 @@ obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o
 
 ccflags-y += -I$(srctree)/drivers/media/video
 ccflags-y += -I$(srctree)/drivers/media/common/tuners
-ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
+ccflags-y += -I$(srctree)/drivers/media/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
 
 ccflags-y += $(extra-cflags-y) $(extra-cflags-m)
index ea09b9af2d30b102a32fbb7b7b425dc2e079de8f..f0f4f6a221805c1b306dac10d3d2b5ecc4843be3 100644 (file)
@@ -4,6 +4,6 @@ obj-$(CONFIG_VIDEO_TLG2300) += poseidon.o
 
 ccflags-y += -Idrivers/media/video
 ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb-core
 ccflags-y += -Idrivers/media/dvb/frontends
 
index 395515b4a888af254cfdd9020f8127ef3045de13..b797a8a8bae4fb92bb994e9d4761e0f81d95b445 100644 (file)
@@ -11,5 +11,5 @@ obj-$(CONFIG_VIDEO_TM6000_DVB) += tm6000-dvb.o
 
 ccflags-y := -Idrivers/media/video
 ccflags-y += -Idrivers/media/common/tuners
-ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb-core
 ccflags-y += -Idrivers/media/dvb/frontends
index 1bca43e847c7c0c301e6d711ea128e96e7db58c5..d8dfb757f1e2f829ede7f0cd5720542f584aff25 100644 (file)
@@ -3,4 +3,4 @@ dvb-as102-objs := as102_drv.o as102_fw.o as10x_cmd.o as10x_cmd_stream.o \
 
 obj-$(CONFIG_DVB_AS102) += dvb-as102.o
 
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb-core
index 64cfc77be357a223abe90936528657c7962be71b..b0833fa361bee10ab7482959e3540ad4db98ff2a 100644 (file)
@@ -1,5 +1,5 @@
 obj-$(CONFIG_DVB_CXD2099) += cxd2099.o
 
-ccflags-y += -Idrivers/media/dvb/dvb-core/
+ccflags-y += -Idrivers/media/dvb-core/
 ccflags-y += -Idrivers/media/dvb/frontends/
 ccflags-y += -Idrivers/media/common/tuners/
index 6ee837c56706308b5a7fb951d088b878573e6072..eea1e72dfa0969397bead2d5f1b97691a73713a9 100644 (file)
@@ -27,4 +27,4 @@ s2250-y := s2250-board.o
 ccflags-$(CONFIG_VIDEO_GO7007_USB_S2250_BOARD:m=y) += -Idrivers/media/dvb/dvb-usb
 
 ccflags-y += -Idrivers/media/dvb/frontends
-ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-y += -Idrivers/media/dvb-core