diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-06-14 21:35:53 +0200 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-14 04:08:14 +0200 |
commit | 3d6c2bc08ac4f75bf3597740357c98f2207ca412 (patch) | |
tree | dfe6d7c9e466cef06224ffadd3310d61f41a4678 /drivers/media/dvb | |
parent | [media] v4l: move v4l2 core into a separate directory (diff) | |
download | linux-3d6c2bc08ac4f75bf3597740357c98f2207ca412.tar.xz linux-3d6c2bc08ac4f75bf3597740357c98f2207ca412.zip |
[media] dvb: move the dvb core one level up
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>
Diffstat (limited to 'drivers/media/dvb')
39 files changed, 17 insertions, 12197 deletions
diff --git a/drivers/media/dvb/Kconfig b/drivers/media/dvb/Kconfig index 3a6ccbc02add..5a2c4bd75480 100644 --- a/drivers/media/dvb/Kconfig +++ b/drivers/media/dvb/Kconfig @@ -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 diff --git a/drivers/media/dvb/Makefile b/drivers/media/dvb/Makefile index 8f7e0129d70e..b14aa9dd0156 100644 --- a/drivers/media/dvb/Makefile +++ b/drivers/media/dvb/Makefile @@ -2,8 +2,7 @@ # Makefile for the kernel multimedia device drivers. # -obj-y := dvb-core/ \ - frontends/ \ +obj-y := frontends/ \ ttpci/ \ ttusb-dec/ \ ttusb-budget/ \ diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile index 3d04a8dba99e..e4291e4aba23 100644 --- a/drivers/media/dvb/b2c2/Makefile +++ b/drivers/media/dvb/b2c2/Makefile @@ -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/ diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile index 0713b3af2050..7c2dd04d37e4 100644 --- a/drivers/media/dvb/bt8xx/Makefile +++ b/drivers/media/dvb/bt8xx/Makefile @@ -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 diff --git a/drivers/media/dvb/ddbridge/Makefile b/drivers/media/dvb/ddbridge/Makefile index 38019bafb862..9eca27dd7328 100644 --- a/drivers/media/dvb/ddbridge/Makefile +++ b/drivers/media/dvb/ddbridge/Makefile @@ -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/ diff --git a/drivers/media/dvb/dm1105/Makefile b/drivers/media/dvb/dm1105/Makefile index 95a008b71fe5..0dc5963ee807 100644 --- a/drivers/media/dvb/dm1105/Makefile +++ b/drivers/media/dvb/dm1105/Makefile @@ -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 index 8f22bcd7c1f9..000000000000 --- a/drivers/media/dvb/dvb-core/Makefile +++ /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 index eb91fd808c16..000000000000 --- a/drivers/media/dvb/dvb-core/demux.h +++ /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 index 889c9c16c6df..000000000000 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ /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], - ¶->filter.mask[1], DMX_FILTER_SIZE - 1); - memcpy(&(*secfilter)->filter_mode[3], - ¶->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 index 02ebe28f830d..000000000000 --- a/drivers/media/dvb/dvb-core/dmxdev.h +++ /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 index 26c44818a5ab..000000000000 --- a/drivers/media/dvb/dvb-core/dvb-usb-ids.h +++ /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 index 9be65a3b931f..000000000000 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ /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 index 7df2e141187a..000000000000 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.h +++ /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 index 17cb81fd194c..000000000000 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ /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 index fa7188a253aa..000000000000 --- a/drivers/media/dvb/dvb-core/dvb_demux.h +++ /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 index 772003fb1821..000000000000 --- a/drivers/media/dvb/dvb-core/dvb_filter.c +++ /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 index 375e3be184b1..000000000000 --- a/drivers/media/dvb/dvb-core/dvb_filter.h +++ /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 index 12e5eb1fff76..000000000000 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ /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 index de410cc94fbb..000000000000 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ /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 index beb7c93aa6cb..000000000000 --- a/drivers/media/dvb/dvb-core/dvb_math.c +++ /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 index aecc867e9404..000000000000 --- a/drivers/media/dvb/dvb-core/dvb_math.h +++ /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 index 8766ce8c354d..000000000000 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ /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 index 1e53acd50cf4..000000000000 --- a/drivers/media/dvb/dvb-core/dvb_net.h +++ /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 index a5712cd7c65f..000000000000 --- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c +++ /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 index 41f04dae69b6..000000000000 --- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h +++ /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 index 39eab73b01ae..000000000000 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ /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 index 93a9470d3f0c..000000000000 --- a/drivers/media/dvb/dvb-core/dvbdev.h +++ /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_ */ diff --git a/drivers/media/dvb/dvb-usb-v2/Makefile b/drivers/media/dvb/dvb-usb-v2/Makefile index 61b0f53669e8..9fef543dac21 100644 --- a/drivers/media/dvb/dvb-usb-v2/Makefile +++ b/drivers/media/dvb/dvb-usb-v2/Makefile @@ -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 diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 061d5448fa1e..cc95b116bbc2 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -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 diff --git a/drivers/media/dvb/firewire/Makefile b/drivers/media/dvb/firewire/Makefile index 357b3aab186b..f3148138c963 100644 --- a/drivers/media/dvb/firewire/Makefile +++ b/drivers/media/dvb/firewire/Makefile @@ -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 diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index 185bb8b51952..a378c5293764 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -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 diff --git a/drivers/media/dvb/mantis/Makefile b/drivers/media/dvb/mantis/Makefile index ec8116dcb368..338411917361 100644 --- a/drivers/media/dvb/mantis/Makefile +++ b/drivers/media/dvb/mantis/Makefile @@ -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/ diff --git a/drivers/media/dvb/ngene/Makefile b/drivers/media/dvb/ngene/Makefile index 13ebeffb705f..dae76597fc31 100644 --- a/drivers/media/dvb/ngene/Makefile +++ b/drivers/media/dvb/ngene/Makefile @@ -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/ diff --git a/drivers/media/dvb/pluto2/Makefile b/drivers/media/dvb/pluto2/Makefile index 700822350ec5..14fa5789c748 100644 --- a/drivers/media/dvb/pluto2/Makefile +++ b/drivers/media/dvb/pluto2/Makefile @@ -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/ diff --git a/drivers/media/dvb/pt1/Makefile b/drivers/media/dvb/pt1/Makefile index d80d8e8e7c57..c80492a1039e 100644 --- a/drivers/media/dvb/pt1/Makefile +++ b/drivers/media/dvb/pt1/Makefile @@ -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 diff --git a/drivers/media/dvb/siano/Makefile b/drivers/media/dvb/siano/Makefile index f233b57c86fb..14756bdb6eaa 100644 --- a/drivers/media/dvb/siano/Makefile +++ b/drivers/media/dvb/siano/Makefile @@ -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) diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile index f6e869372e30..b0ddb4544cb7 100644 --- a/drivers/media/dvb/ttpci/Makefile +++ b/drivers/media/dvb/ttpci/Makefile @@ -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 diff --git a/drivers/media/dvb/ttusb-budget/Makefile b/drivers/media/dvb/ttusb-budget/Makefile index 8d6c4acb7f1d..c5abe78ae04f 100644 --- a/drivers/media/dvb/ttusb-budget/Makefile +++ b/drivers/media/dvb/ttusb-budget/Makefile @@ -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 diff --git a/drivers/media/dvb/ttusb-dec/Makefile b/drivers/media/dvb/ttusb-dec/Makefile index ed28b5384d20..5352740d2353 100644 --- a/drivers/media/dvb/ttusb-dec/Makefile +++ b/drivers/media/dvb/ttusb-dec/Makefile @@ -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/ |