diff options
Diffstat (limited to 'drivers/media/dvb/dvb-core')
| -rw-r--r-- | drivers/media/dvb/dvb-core/Kconfig | 11 | ||||
| -rw-r--r-- | drivers/media/dvb/dvb-core/Makefile | 9 | ||||
| -rw-r--r-- | drivers/media/dvb/dvb-core/demux.h | 275 | ||||
| -rw-r--r-- | drivers/media/dvb/dvb-core/dmxdev.c | 1148 | ||||
| -rw-r--r-- | drivers/media/dvb/dvb-core/dmxdev.h | 128 | ||||
| -rw-r--r-- | drivers/media/dvb/dvb-core/dvb_ca_en50221.c | 1779 | ||||
| -rw-r--r-- | drivers/media/dvb/dvb-core/dvb_ca_en50221.h | 134 | ||||
| -rw-r--r-- | drivers/media/dvb/dvb-core/dvb_demux.c | 1232 | ||||
| -rw-r--r-- | drivers/media/dvb/dvb-core/dvb_demux.h | 140 | ||||
| -rw-r--r-- | drivers/media/dvb/dvb-core/dvb_filter.c | 603 | ||||
| -rw-r--r-- | drivers/media/dvb/dvb-core/dvb_filter.h | 246 | ||||
| -rw-r--r-- | drivers/media/dvb/dvb-core/dvb_frontend.c | 948 | ||||
| -rw-r--r-- | drivers/media/dvb/dvb-core/dvb_frontend.h | 104 | ||||
| -rw-r--r-- | drivers/media/dvb/dvb-core/dvb_net.c | 1391 | ||||
| -rw-r--r-- | drivers/media/dvb/dvb-core/dvb_net.h | 46 | ||||
| -rw-r--r-- | drivers/media/dvb/dvb-core/dvb_ringbuffer.c | 270 | ||||
| -rw-r--r-- | drivers/media/dvb/dvb-core/dvb_ringbuffer.h | 173 | ||||
| -rw-r--r-- | drivers/media/dvb/dvb-core/dvbdev.c | 441 | ||||
| -rw-r--r-- | drivers/media/dvb/dvb-core/dvbdev.h | 104 |
19 files changed, 0 insertions, 9182 deletions
diff --git a/drivers/media/dvb/dvb-core/Kconfig b/drivers/media/dvb/dvb-core/Kconfig deleted file mode 100644 index a9a7b342104..00000000000 --- a/drivers/media/dvb/dvb-core/Kconfig +++ /dev/null @@ -1,11 +0,0 @@ -config DVB_CORE - tristate "DVB Core Support" - depends on DVB - select CRC32 - help - DVB core utility functions for device handling, software fallbacks etc. - Say Y when you have a DVB card and want to use it. Say Y if your want - to build your drivers outside the kernel, but need the DVB core. All - in-kernel drivers will select this automatically if needed. - If unsure say N. - diff --git a/drivers/media/dvb/dvb-core/Makefile b/drivers/media/dvb/dvb-core/Makefile deleted file mode 100644 index c6baac20f52..00000000000 --- a/drivers/media/dvb/dvb-core/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# -# Makefile for the kernel DVB device drivers. -# - -dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \ - dvb_ca_en50221.o dvb_frontend.o \ - dvb_net.o dvb_ringbuffer.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 9719a3b30f7..00000000000 --- a/drivers/media/dvb/dvb-core/demux.h +++ /dev/null @@ -1,275 +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_SECFEED_SIZE -#define DMX_MAX_SECFEED_SIZE 4096 -#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) */ - -/* 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 capabilites 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* 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 8028c3a5e28..00000000000 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ /dev/null @@ -1,1148 +0,0 @@ -/* - * dmxdev.c - DVB demultiplexer device - * - * 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/spinlock.h> -#include <linux/slab.h> -#include <linux/vmalloc.h> -#include <linux/module.h> -#include <linux/moduleparam.h> -#include <linux/sched.h> -#include <linux/poll.h> -#include <linux/ioctl.h> -#include <linux/wait.h> -#include <asm/uaccess.h> -#include <asm/system.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 inline void dvb_dmxdev_buffer_init(struct dmxdev_buffer *buffer) -{ - buffer->data=NULL; - buffer->size=8192; - buffer->pread=0; - buffer->pwrite=0; - buffer->error=0; - init_waitqueue_head(&buffer->queue); -} - -static inline int dvb_dmxdev_buffer_write(struct dmxdev_buffer *buf, const u8 *src, int len) -{ - int split; - int free; - int todo; - - if (!len) - return 0; - if (!buf->data) - return 0; - - free=buf->pread-buf->pwrite; - split=0; - if (free<=0) { - free+=buf->size; - split=buf->size-buf->pwrite; - } - if (len>=free) { - dprintk("dmxdev: buffer overflow\n"); - return -1; - } - if (split>=len) - split=0; - todo=len; - if (split) { - memcpy(buf->data + buf->pwrite, src, split); - todo-=split; - buf->pwrite=0; - } - memcpy(buf->data + buf->pwrite, src+split, todo); - buf->pwrite=(buf->pwrite+todo)%buf->size; - return len; -} - -static ssize_t dvb_dmxdev_buffer_read(struct dmxdev_buffer *src, - int non_blocking, char __user *buf, size_t count, loff_t *ppos) -{ - unsigned long todo=count; - int split, avail, error; - - if (!src->data) - return 0; - - if ((error=src->error)) { - src->pwrite=src->pread; - src->error=0; - return error; - } - - if (non_blocking && (src->pwrite==src->pread)) - return -EWOULDBLOCK; - - while (todo>0) { - if (non_blocking && (src->pwrite==src->pread)) - return (count-todo) ? (count-todo) : -EWOULDBLOCK; - - if (wait_event_interruptible(src->queue, - (src->pread!=src->pwrite) || - (src->error))<0) - return count-todo; - - if ((error=src->error)) { - src->pwrite=src->pread; - src->error=0; - return error; - } - - split=src->size; - avail=src->pwrite - src->pread; - if (avail<0) { - avail+=src->size; - split=src->size - src->pread; - } - if (avail>todo) - avail=todo; - if (split<avail) { - if (copy_to_user(buf, src->data+src->pread, split)) - return -EFAULT; - buf+=split; - src->pread=0; - todo-=split; - avail-=split; - } - if (avail) { - if (copy_to_user(buf, src->data+src->pread, avail)) - return -EFAULT; - src->pread = (src->pread + avail) % src->size; - todo-=avail; - buf+=avail; - } - } - return count; -} - -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 inline void dvb_dmxdev_dvr_state_set(struct dmxdev_dvr *dmxdevdvr, int state) -{ - spin_lock_irq(&dmxdevdvr->dev->lock); - dmxdevdvr->state=state; - spin_unlock_irq(&dmxdevdvr->dev->lock); -} - -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", __FUNCTION__); - - if (down_interruptible (&dmxdev->mutex)) - return -ERESTARTSYS; - - if ((file->f_flags&O_ACCMODE)==O_RDWR) { - if (!(dmxdev->capabilities&DMXDEV_CAP_DUPLEX)) { - up(&dmxdev->mutex); - return -EOPNOTSUPP; - } - } - - if ((file->f_flags&O_ACCMODE)==O_RDONLY) { - dvb_dmxdev_buffer_init(&dmxdev->dvr_buffer); - dmxdev->dvr_buffer.size=DVR_BUFFER_SIZE; - dmxdev->dvr_buffer.data=vmalloc(DVR_BUFFER_SIZE); - if (!dmxdev->dvr_buffer.data) { - up(&dmxdev->mutex); - return -ENOMEM; - } - } - - if ((file->f_flags&O_ACCMODE)==O_WRONLY) { - dmxdev->dvr_orig_fe=dmxdev->demux->frontend; - - if (!dmxdev->demux->write) { - up(&dmxdev->mutex); - return -EOPNOTSUPP; - } - - front=get_fe(dmxdev->demux, DMX_MEMORY_FE); - - if (!front) { - up(&dmxdev->mutex); - return -EINVAL; - } - dmxdev->demux->disconnect_frontend(dmxdev->demux); - dmxdev->demux->connect_frontend(dmxdev->demux, front); - } - up(&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; - - if (down_interruptible (&dmxdev->mutex)) - return -ERESTARTSYS; - - 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) { - 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); - } - } - up(&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 (down_interruptible (&dmxdev->mutex)) - return -ERESTARTSYS; - ret=dmxdev->demux->write(dmxdev->demux, buf, count); - up(&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; - int ret; - - //down(&dmxdev->mutex); - ret= dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, - file->f_flags&O_NONBLOCK, - buf, count, ppos); - //up(&dmxdev->mutex); - return ret; -} - -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 dmxdev_buffer *buf=&dmxdevfilter->buffer; - void *mem; - - if (buf->size==size) - return 0; - if (dmxdevfilter->state>=DMXDEV_STATE_GO) - return -EBUSY; - spin_lock_irq(&dmxdevfilter->dev->lock); - mem=buf->data; - buf->data=NULL; - buf->size=size; - buf->pwrite=buf->pread=0; - spin_unlock_irq(&dmxdevfilter->dev->lock); - vfree(mem); - - if (buf->size) { - mem=vmalloc(dmxdevfilter->buffer.size); - if (!mem) - return -ENOMEM; - spin_lock_irq(&dmxdevfilter->dev->lock); - buf->data=mem; - spin_unlock_irq(&dmxdevfilter->dev->lock); - } - 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 %02x %02x %02x %02x %02x %02x\n", - buffer1[0], buffer1[1], - buffer1[2], buffer1[3], - buffer1[4], buffer1[5]); - 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) { - dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread; - dmxdevfilter->buffer.error=-EOVERFLOW; - } - 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 dmxdev_buffer *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) - 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) { - buffer->pwrite=buffer->pread; - buffer->error=-EOVERFLOW; - } - 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) -{ - 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: - dmxdevfilter->feed.ts->stop_filtering(dmxdevfilter->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) -{ - 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); - break; - case DMXDEV_TYPE_PES: - return filter->feed.ts->start_filtering(filter->feed.ts); - 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].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) -{ - 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: - if (!dmxdevfilter->feed.ts) - break; - dvb_dmxdev_feed_stop(dmxdevfilter); - dmxdevfilter->dev->demux-> - release_ts_feed(dmxdevfilter->dev->demux, - dmxdevfilter->feed.ts); - dmxdevfilter->feed.ts=NULL; - break; - default: - if (dmxdevfilter->state==DMXDEV_STATE_ALLOCATED) - return 0; - return -EINVAL; - } - dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread=0; - return 0; -} - -static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter) -{ - if (dmxdevfilter->state<DMXDEV_STATE_SET) - return 0; - - dmxdevfilter->type=DMXDEV_TYPE_NONE; - dmxdevfilter->pid=0xffff; - dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); - return 0; -} - -static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) -{ - struct dmxdev *dmxdev = filter->dev; - 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 (!(mem = filter->buffer.data)) { - mem = vmalloc(filter->buffer.size); - spin_lock_irq(&filter->dev->lock); - filter->buffer.data=mem; - spin_unlock_irq(&filter->dev->lock); - if (!filter->buffer.data) - return -ENOMEM; - } - - filter->buffer.pwrite = filter->buffer.pread = 0; - - 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].pid == para->pid && - dmxdev->filter[i].type == DMXDEV_TYPE_SEC) { - *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", - __FUNCTION__); - 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", - __FUNCTION__); - 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: - { - struct timespec timeout = { 0 }; - struct dmx_pes_filter_params *para = &filter->params.pes; - dmx_output_t otype; - int ret; - int ts_type; - enum dmx_ts_pes ts_pes; - struct dmx_ts_feed **tsfeed = &filter->feed.ts; - - filter->feed.ts = NULL; - otype=para->output; - - ts_pes=(enum dmx_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; - - if (otype == DMX_OUT_TAP) - ts_type |= TS_PAYLOAD_ONLY|TS_PACKET; - - ret=dmxdev->demux->allocate_ts_feed(dmxdev->demux, - tsfeed, - dvb_dmxdev_ts_callback); - if (ret<0) - return ret; - - (*tsfeed)->priv = (void *) filter; - - ret = (*tsfeed)->set(*tsfeed, para->pid, ts_type, ts_pes, - 32768, timeout); - - if (ret < 0) { - dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed); - return ret; - } - - ret = filter->feed.ts->start_filtering(filter->feed.ts); - - if (ret < 0) { - dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed); - 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 (down_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) { - up(&dmxdev->mutex); - return -EMFILE; - } - - dmxdevfilter=&dmxdev->filter[i]; - sema_init(&dmxdevfilter->mutex, 1); - dmxdevfilter->dvbdev=dmxdev->dvbdev; - file->private_data=dmxdevfilter; - - dvb_dmxdev_buffer_init(&dmxdevfilter->buffer); - dmxdevfilter->type=DMXDEV_TYPE_NONE; - dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); - dmxdevfilter->feed.ts=NULL; - init_timer(&dmxdevfilter->timer); - - up(&dmxdev->mutex); - return 0; -} - - -static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, struct dmxdev_filter *dmxdevfilter) -{ - if (down_interruptible(&dmxdev->mutex)) - return -ERESTARTSYS; - - if (down_interruptible(&dmxdevfilter->mutex)) { - up(&dmxdev->mutex); - return -ERESTARTSYS; - } - - 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); - up(&dmxdevfilter->mutex); - up(&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_filter_set(struct dmxdev *dmxdev, - struct dmxdev_filter *dmxdevfilter, - struct dmx_sct_filter_params *params) -{ - dprintk ("function : %s\n", __FUNCTION__); - - dvb_dmxdev_filter_stop(dmxdevfilter); - - dmxdevfilter->type=DMXDEV_TYPE_SEC; - dmxdevfilter->pid=params->pid; - 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) -{ - dvb_dmxdev_filter_stop(dmxdevfilter); - - if (params->pes_type>DMX_PES_OTHER || params->pes_type<0) - return -EINVAL; - - dmxdevfilter->type=DMXDEV_TYPE_PES; - dmxdevfilter->pid=params->pid; - memcpy(&dmxdevfilter->params, params, sizeof(struct dmx_pes_filter_params)); - - dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); - - if (params->flags&DMX_IMMEDIATE_START) - return dvb_dmxdev_filter_start(dmxdevfilter); - - return 0; -} - -static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil, - struct file *file, char __user *buf, size_t count, loff_t *ppos) -{ - 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=0; - - if (down_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); - - up(&dmxdevfilter->mutex); - return ret; -} - - -static int dvb_demux_do_ioctl(struct inode *inode, 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 (down_interruptible (&dmxdev->mutex)) - return -ERESTARTSYS; - - switch (cmd) { - case DMX_START: - if (down_interruptible(&dmxdevfilter->mutex)) { - up(&dmxdev->mutex); - return -ERESTARTSYS; - } - if (dmxdevfilter->state<DMXDEV_STATE_SET) - ret = -EINVAL; - else - ret = dvb_dmxdev_filter_start(dmxdevfilter); - up(&dmxdevfilter->mutex); - break; - - case DMX_STOP: - if (down_interruptible(&dmxdevfilter->mutex)) { - up(&dmxdev->mutex); - return -ERESTARTSYS; - } - ret=dvb_dmxdev_filter_stop(dmxdevfilter); - up(&dmxdevfilter->mutex); - break; - - case DMX_SET_FILTER: - if (down_interruptible(&dmxdevfilter->mutex)) { - up(&dmxdev->mutex); - return -ERESTARTSYS; - } - ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, - (struct dmx_sct_filter_params *)parg); - up(&dmxdevfilter->mutex); - break; - - case DMX_SET_PES_FILTER: - if (down_interruptible(&dmxdevfilter->mutex)) { - up(&dmxdev->mutex); - return -ERESTARTSYS; - } - ret=dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, - (struct dmx_pes_filter_params *)parg); - up(&dmxdevfilter->mutex); - break; - - case DMX_SET_BUFFER_SIZE: - if (down_interruptible(&dmxdevfilter->mutex)) { - up(&dmxdev->mutex); - return -ERESTARTSYS; - } - ret=dvb_dmxdev_set_buffer_size(dmxdevfilter, arg); - up(&dmxdevfilter->mutex); - break; - - case DMX_GET_EVENT: - break; - - case DMX_GET_PES_PIDS: - if (!dmxdev->demux->get_pes_pids) { - ret=-EINVAL; - break; - } - dmxdev->demux->get_pes_pids(dmxdev->demux, (u16 *)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; - - default: - ret=-EINVAL; - } - up(&dmxdev->mutex); - return ret; -} - -static int dvb_demux_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return dvb_usercopy(inode, 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 (dmxdevfilter->buffer.pread != dmxdevfilter->buffer.pwrite) - 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; - - return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter); -} - - -static struct file_operations dvb_demux_fops = { - .owner = THIS_MODULE, - .read = dvb_demux_read, - .ioctl = dvb_demux_ioctl, - .open = dvb_demux_open, - .release = dvb_demux_release, - .poll = dvb_demux_poll, -}; - - -static struct dvb_device dvbdev_demux = { - .priv = NULL, - .users = 1, - .writers = 1, - .fops = &dvb_demux_fops -}; - - -static int dvb_dvr_do_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, void *parg) -{ - struct dvb_device *dvbdev = file->private_data; - struct dmxdev *dmxdev = dvbdev->priv; - - int ret=0; - - if (down_interruptible (&dmxdev->mutex)) - return -ERESTARTSYS; - - switch (cmd) { - case DMX_SET_BUFFER_SIZE: - // FIXME: implement - ret=0; - break; - - default: - ret=-EINVAL; - } - up(&dmxdev->mutex); - return ret; -} - - -static int dvb_dvr_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return dvb_usercopy(inode, 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", __FUNCTION__); - - 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 (dmxdev->dvr_buffer.pread!=dmxdev->dvr_buffer.pwrite) - mask |= (POLLIN | POLLRDNORM | POLLPRI); - } else - mask |= (POLLOUT | POLLWRNORM | POLLPRI); - - return mask; -} - - -static struct file_operations dvb_dvr_fops = { - .owner = THIS_MODULE, - .read = dvb_dvr_read, - .write = dvb_dvr_write, - .ioctl = dvb_dvr_ioctl, - .open = dvb_dvr_open, - .release = dvb_dvr_release, - .poll = dvb_dvr_poll, -}; - -static struct dvb_device dvbdev_dvr = { - .priv = NULL, - .users = 1, - .writers = 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; - - dmxdev->dvr = vmalloc(dmxdev->filternum*sizeof(struct dmxdev_dvr)); - if (!dmxdev->dvr) { - vfree(dmxdev->filter); - dmxdev->filter = NULL; - return -ENOMEM; - } - - sema_init(&dmxdev->mutex, 1); - 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); - dmxdev->dvr[i].dev=dmxdev; - dmxdev->dvr[i].buffer.data=NULL; - dvb_dmxdev_dvr_state_set(&dmxdev->dvr[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_dmxdev_buffer_init(&dmxdev->dvr_buffer); - - return 0; -} -EXPORT_SYMBOL(dvb_dmxdev_init); - -void -dvb_dmxdev_release(struct dmxdev *dmxdev) -{ - dvb_unregister_device(dmxdev->dvbdev); - dvb_unregister_device(dmxdev->dvr_dvbdev); - - vfree(dmxdev->filter); - dmxdev->filter=NULL; - vfree(dmxdev->dvr); - dmxdev->dvr=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 395a9cd7501..00000000000 --- a/drivers/media/dvb/dvb-core/dmxdev.h +++ /dev/null @@ -1,128 +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 <asm/semaphore.h> - -#include <linux/dvb/dmx.h> - -#include "dvbdev.h" -#include "demux.h" - -enum dmxdevype { - 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_buffer { - u8 *data; - int size; - int pread; - int pwrite; - wait_queue_head_t queue; - int error; -}; - -struct dmxdev_filter { - struct dvb_device *dvbdev; - - union { - struct dmx_section_filter *sec; - } filter; - - union { - struct dmx_ts_feed *ts; - struct dmx_section_feed *sec; - } feed; - - union { - struct dmx_sct_filter_params sec; - struct dmx_pes_filter_params pes; - } params; - - int type; - enum dmxdev_state state; - struct dmxdev *dev; - struct dmxdev_buffer buffer; - - struct semaphore mutex; - - /* only for sections */ - struct timer_list timer; - int todo; - u8 secheader[3]; - - u16 pid; -}; - - -struct dmxdev_dvr { - int state; - struct dmxdev *dev; - struct dmxdev_buffer buffer; -}; - - -struct dmxdev { - struct dvb_device *dvbdev; - struct dvb_device *dvr_dvbdev; - - struct dmxdev_filter *filter; - struct dmxdev_dvr *dvr; - struct dmx_demux *demux; - - int filternum; - int capabilities; -#define DMXDEV_CAP_DUPLEX 1 - struct dmx_frontend *dvr_orig_fe; - - struct dmxdev_buffer dvr_buffer; -#define DVR_BUFFER_SIZE (10*188*1024) - - struct semaphore 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_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c deleted file mode 100644 index 2aa767f9bd7..00000000000 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ /dev/null @@ -1,1779 +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/moduleparam.h> -#include <linux/vmalloc.h> -#include <linux/delay.h> -#include <linux/rwsem.h> -#include <linux/sched.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; - - /* 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; - - /* semaphore for syncing access to slot structure */ - struct rw_semaphore sem; - - /* 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 */ - pid_t thread_pid; - - /* Wait queue used when shutting thread down */ - wait_queue_head_t thread_queue; - - /* Flag indicating when thread should exit */ - unsigned int exit:1; - - /* 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 u8 *findstr(u8 * haystack, int hlen, u8 * 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", __FUNCTION__); - - /* 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", __FUNCTION__, 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", __FUNCTION__, 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", __FUNCTION__); - - /* 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(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(tuple, tupleLength, "DVB_HOST", 8) == NULL) || - (findstr(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", __FUNCTION__); - - /* 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", __FUNCTION__); - - /* check if we have space for a link buf in the rx_buffer */ - if (ebuf == NULL) { - int buf_free; - - down_read(&ca->slot_info[slot].sem); - if (ca->slot_info[slot].rx_buffer.data == NULL) { - up_read(&ca->slot_info[slot].sem); - status = -EIO; - goto exit; - } - buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer); - up_read(&ca->slot_info[slot].sem); - - 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) { - down_read(&ca->slot_info[slot].sem); - if (ca->slot_info[slot].rx_buffer.data == NULL) { - up_read(&ca->slot_info[slot].sem); - status = -EIO; - goto exit; - } - dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read); - up_read(&ca->slot_info[slot].sem); - } 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", __FUNCTION__); - - - // sanity check - if (bytes_write > ca->slot_info[slot].link_buf_size) - return -EINVAL; - - /* check if interface is actually waiting for us to read from it, or if a read is in progress */ - if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) - goto exitnowrite; - if (status & (STATUSREG_DA | STATUSREG_RE)) { - 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", __FUNCTION__); - - down_write(&ca->slot_info[slot].sem); - ca->pub->slot_shutdown(ca->pub, slot); - ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; - vfree(ca->slot_info[slot].rx_buffer.data); - ca->slot_info[slot].rx_buffer.data = NULL; - up_write(&ca->slot_info[slot].sem); - - /* 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_read_data(ca, slot, NULL, 0); - 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", __FUNCTION__); - - ca->wakeup = 1; - mb(); - wake_up_interruptible(&ca->thread_queue); -} - -/** - * Used by the CA thread to determine if an early wakeup is necessary - * - * @param ca CA instance. - */ -static int dvb_ca_en50221_thread_should_wakeup(struct dvb_ca_private *ca) -{ - if (ca->wakeup) { - ca->wakeup = 0; - return 1; - } - if (ca->exit) - return 1; - - return 0; -} - - -/** - * 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; - - for (slot = 0; slot < ca->slot_count; slot++) { - switch (ca->slot_info[slot].slot_state) { - default: - case DVB_CA_SLOTSTATE_NONE: - case DVB_CA_SLOTSTATE_INVALID: - delay = HZ * 60; - if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) { - delay = HZ / 10; - } - 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; - break; - - case DVB_CA_SLOTSTATE_RUNNING: - delay = HZ * 60; - if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) { - delay = HZ / 10; - } - if (ca->open) { - if ((!ca->slot_info[slot].da_irq_supported) || - (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA))) { - delay = HZ / 10; - } - } - 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; - char name[15]; - int slot; - int flags; - int status; - int pktcount; - void *rxbuf; - - dprintk("%s\n", __FUNCTION__); - - /* setup kernel thread */ - snprintf(name, sizeof(name), "kdvb-ca-%i:%i", ca->dvbdev->adapter->num, ca->dvbdev->id); - - lock_kernel(); - daemonize(name); - sigfillset(¤t->blocked); - unlock_kernel(); - - /* choose the correct initial delay */ - dvb_ca_en50221_thread_update_delay(ca); - - /* main loop */ - while (!ca->exit) { - /* sleep for a bit */ - if (!ca->wakeup) { - flags = wait_event_interruptible_timeout(ca->thread_queue, - dvb_ca_en50221_thread_should_wakeup(ca), - ca->delay); - if ((flags == -ERESTARTSYS) || ca->exit) { - /* got signal or quitting */ - break; - } - } - ca->wakeup = 0; - - /* go through all the slots processing them */ - for (slot = 0; slot < ca->slot_count; slot++) { - - // 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) { - 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) { - 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; - } - - 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; - } - down_write(&ca->slot_info[slot].sem); - dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE); - up_write(&ca->slot_info[slot].sem); - - 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) - continue; - - // no need to poll if the CAM supports IRQs - if (ca->slot_info[slot].da_irq_supported) - break; - - // poll mode - 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; - } - } - } - - /* completed */ - ca->thread_pid = 0; - mb(); - wake_up_interruptible(&ca->thread_queue); - 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 inode *inode, 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", __FUNCTION__); - - switch (cmd) { - case CA_RESET: - for (slot = 0; slot < ca->slot_count; slot++) { - 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); - } - } - 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 int dvb_ca_en50221_io_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return dvb_usercopy(inode, 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; - char fragbuf[HOST_LINK_BUF_SIZE]; - int fragpos = 0; - int fraglen; - unsigned long timeout; - int written; - - dprintk("%s\n", __FUNCTION__); - - /* 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 ((count - fragpos) < fraglen) - fraglen = count - fragpos; - - fragbuf[0] = connection_id; - fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00; - if ((status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen)) != 0) - 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; - } - - status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen + 2); - 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; - int 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; - - down_read(&ca->slot_info[slot].sem); - - if (ca->slot_info[slot].rx_buffer.data == NULL) { - up_read(&ca->slot_info[slot].sem); - 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, 0); - 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); - } - - if (!found) - up_read(&ca->slot_info[slot].sem); - - 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", __FUNCTION__); - - /* 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, 0); - 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(&ca->slot_info[slot].rx_buffer, idx, 2, - buf + pktlen, fraglen, 1)) < 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; - if ((status = copy_to_user(buf, hdr, 2)) != 0) - goto exit; - status = pktlen; - - exit: - up_read(&ca->slot_info[slot].sem); - 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", __FUNCTION__); - - if (!try_module_get(ca->pub->owner)) - return -EIO; - - err = dvb_generic_open(inode, file); - if (err < 0) - return err; - - for (i = 0; i < ca->slot_count; i++) { - - if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) { - down_write(&ca->slot_info[i].sem); - if (ca->slot_info[i].rx_buffer.data != NULL) { - dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer); - } - up_write(&ca->slot_info[i].sem); - } - } - - 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 = 0; - - dprintk("%s\n", __FUNCTION__); - - /* 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 0; -} - - -/** - * 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", __FUNCTION__); - - if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { - up_read(&ca->slot_info[slot].sem); - 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) { - up_read(&ca->slot_info[slot].sem); - mask |= POLLIN; - } - - return mask; -} -EXPORT_SYMBOL(dvb_ca_en50221_init); - - -static struct file_operations dvb_ca_fops = { - .owner = THIS_MODULE, - .read = dvb_ca_en50221_io_read, - .write = dvb_ca_en50221_io_write, - .ioctl = dvb_ca_en50221_io_ioctl, - .open = dvb_ca_en50221_io_open, - .release = dvb_ca_en50221_io_release, - .poll = dvb_ca_en50221_io_poll, -}; - -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", __FUNCTION__); - - if (slot_count < 1) - return -EINVAL; - - /* initialise the system data */ - if ((ca = - (struct dvb_ca_private *) kmalloc(sizeof(struct dvb_ca_private), - GFP_KERNEL)) == NULL) { - ret = -ENOMEM; - goto error; - } - memset(ca, 0, sizeof(struct dvb_ca_private)); - ca->pub = pubca; - ca->flags = flags; - ca->slot_count = slot_count; - if ((ca->slot_info = kmalloc(sizeof(struct dvb_ca_slot) * slot_count, GFP_KERNEL)) == NULL) { - ret = -ENOMEM; - goto error; - } - memset(ca->slot_info, 0, sizeof(struct dvb_ca_slot) * slot_count); - init_waitqueue_head(&ca->wait_queue); - ca->thread_pid = 0; - init_waitqueue_head(&ca->thread_queue); - ca->exit = 0; - 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; - init_rwsem(&ca->slot_info[i].sem); - } - - if (signal_pending(current)) { - ret = -EINTR; - goto error; - } - mb(); - - /* create a kthread for monitoring this CA device */ - - ret = kernel_thread(dvb_ca_en50221_thread, ca, 0); - - if (ret < 0) { - printk("dvb_ca_init: failed to start kernel_thread (%d)\n", ret); - goto error; - } - ca->thread_pid = ret; - 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", __FUNCTION__); - - /* shutdown the thread if there was one */ - if (ca->thread_pid) { - if (kill_proc(ca->thread_pid, 0, 1) == -ESRCH) { - printk("dvb_ca_release adapter %d: thread PID %d already died\n", - ca->dvbdev->adapter->num, ca->thread_pid); - } else { - ca->exit = 1; - mb(); - dvb_ca_en50221_thread_wakeup(ca); - wait_event_interruptible(ca->thread_queue, ca->thread_pid == 0); - } - } - - for (i = 0; i < ca->slot_count; i++) { - dvb_ca_en50221_slot_shutdown(ca, i); - } - 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 8467e63ddc0..00000000000 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.h +++ /dev/null @@ -1,134 +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 must use locks as - * they may be called from several threads at once */ - - /* 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 dc476dda2b7..00000000000 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ /dev/null @@ -1,1232 +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/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 "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 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_SECFEED_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_PAYLOAD_ONLY)) == TS_PACKET)) - -static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) -{ - struct dvb_demux_feed *feed; - struct list_head *pos, *head = &demux->feed_list; - u16 pid = ts_pid(buf); - int dvr_done = 0; - - list_for_each(pos, head) { - feed = list_entry(pos, struct dvb_demux_feed, 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); - if (DVR_FEED(feed)) - continue; - } - - 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); - -void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) -{ - int p = 0, i, j; - - spin_lock(&demux->lock); - - if (demux->tsbufp) { - i = demux->tsbufp; - j = 188 - 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) - dvb_dmx_swfilter_packet(demux, demux->tsbuf); - demux->tsbufp = 0; - p += j; - } - - while (p < count) { - if (buf[p] == 0x47) { - if (count - p >= 188) { - dvb_dmx_swfilter_packet(demux, &buf[p]); - p += 188; - } else { - i = count - p; - memcpy(demux->tsbuf, &buf[p], i); - demux->tsbufp = i; - goto bailout; - } - } else - p++; - } - -bailout: - spin_unlock(&demux->lock); -} - -EXPORT_SYMBOL(dvb_dmx_swfilter); - -void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) -{ - int p = 0, i, j; - u8 tmppack[188]; - - spin_lock(&demux->lock); - - if (demux->tsbufp) { - i = demux->tsbufp; - j = 204 - 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) | (demux->tsbuf[0] == 0xB8)) { - memcpy(tmppack, demux->tsbuf, 188); - if (tmppack[0] == 0xB8) - tmppack[0] = 0x47; - dvb_dmx_swfilter_packet(demux, tmppack); - } - demux->tsbufp = 0; - p += j; - } - - while (p < count) { - if ((buf[p] == 0x47) | (buf[p] == 0xB8)) { - if (count - p >= 204) { - memcpy(tmppack, &buf[p], 188); - if (tmppack[0] == 0xB8) - tmppack[0] = 0x47; - dvb_dmx_swfilter_packet(demux, tmppack); - p += 204; - } else { - i = count - p; - memcpy(demux->tsbuf, &buf[p], i); - demux->tsbufp = i; - goto bailout; - } - } else { - p++; - } - } - -bailout: - spin_unlock(&demux->lock); -} - -EXPORT_SYMBOL(dvb_dmx_swfilter_204); - -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", - __FUNCTION__, 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", - __FUNCTION__, 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 (down_interruptible(&demux->mutex)) - return -ERESTARTSYS; - - if (ts_type & TS_DECODER) { - if (pes_type >= DMX_TS_PES_OTHER) { - up(&demux->mutex); - return -EINVAL; - } - - if (demux->pesfilter[pes_type] && - demux->pesfilter[pes_type] != feed) { - up(&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) { - up(&demux->mutex); - return -ENOMEM; - } -#endif - } - - feed->state = DMX_STATE_READY; - up(&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 (down_interruptible(&demux->mutex)) - return -ERESTARTSYS; - - if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) { - up(&demux->mutex); - return -EINVAL; - } - - if (!demux->start_feed) { - up(&demux->mutex); - return -ENODEV; - } - - if ((ret = demux->start_feed(feed)) < 0) { - up(&demux->mutex); - return ret; - } - - spin_lock_irq(&demux->lock); - ts_feed->is_filtering = 1; - feed->state = DMX_STATE_GO; - spin_unlock_irq(&demux->lock); - up(&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; - - if (down_interruptible(&demux->mutex)) - return -ERESTARTSYS; - - if (feed->state < DMX_STATE_GO) { - up(&demux->mutex); - return -EINVAL; - } - - if (!demux->stop_feed) { - up(&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); - up(&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 (down_interruptible(&demux->mutex)) - return -ERESTARTSYS; - - if (!(feed = dvb_dmx_feed_alloc(demux))) { - up(&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; - up(&demux->mutex); - return -EBUSY; - } - - feed->filter->type = DMX_TYPE_TS; - feed->filter->feed = feed; - feed->filter->state = DMX_STATE_READY; - - up(&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; - - if (down_interruptible(&demux->mutex)) - return -ERESTARTSYS; - - if (feed->state == DMX_STATE_FREE) { - up(&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; - - up(&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 (down_interruptible(&dvbdemux->mutex)) - return -ERESTARTSYS; - - dvbdmxfilter = dvb_dmx_filter_alloc(dvbdemux); - if (!dvbdmxfilter) { - up(&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); - - up(&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 (down_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) { - up(&dvbdmx->mutex); - return -ENOMEM; - } -#endif - - dvbdmxfeed->state = DMX_STATE_READY; - up(&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 (down_interruptible(&dvbdmx->mutex)) - return -ERESTARTSYS; - - if (feed->is_filtering) { - up(&dvbdmx->mutex); - return -EBUSY; - } - - if (!dvbdmxfeed->filter) { - up(&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) { - up(&dvbdmx->mutex); - return -ENODEV; - } - - prepare_secfilters(dvbdmxfeed); - - if ((ret = dvbdmx->start_feed(dvbdmxfeed)) < 0) { - up(&dvbdmx->mutex); - return ret; - } - - spin_lock_irq(&dvbdmx->lock); - feed->is_filtering = 1; - dvbdmxfeed->state = DMX_STATE_GO; - spin_unlock_irq(&dvbdmx->lock); - - up(&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; - - if (down_interruptible(&dvbdmx->mutex)) - return -ERESTARTSYS; - - if (!dvbdmx->stop_feed) { - up(&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); - - up(&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; - - if (down_interruptible(&dvbdmx->mutex)) - return -ERESTARTSYS; - - if (dvbdmxfilter->feed != dvbdmxfeed) { - up(&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); - up(&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 (down_interruptible(&dvbdmx->mutex)) - return -ERESTARTSYS; - - if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) { - up(&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; - - up(&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; - - if (down_interruptible(&dvbdmx->mutex)) - return -ERESTARTSYS; - - if (dvbdmxfeed->state == DMX_STATE_FREE) { - up(&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; - - up(&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 *buf, size_t count) -{ - struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - - if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE)) - return -EINVAL; - - if (down_interruptible(&dvbdemux->mutex)) - return -ERESTARTSYS; - dvb_dmx_swfilter(dvbdemux, buf, count); - up(&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; - - if (down_interruptible(&dvbdemux->mutex)) - return -ERESTARTSYS; - - demux->frontend = frontend; - up(&dvbdemux->mutex); - return 0; -} - -static int dvbdmx_disconnect_frontend(struct dmx_demux *demux) -{ - struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; - - if (down_interruptible(&dvbdemux->mutex)) - return -ERESTARTSYS; - - demux->frontend = NULL; - up(&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->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); - 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; - } - - 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; - - sema_init(&dvbdemux->mutex, 1); - spin_lock_init(&dvbdemux->lock); - - return 0; -} - -EXPORT_SYMBOL(dvb_dmx_init); - -void dvb_dmx_release(struct dvb_demux *dvbdemux) -{ - 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 0cc888339d5..00000000000 --- a/drivers/media/dvb/dvb-core/dvb_demux.h +++ /dev/null @@ -1,140 +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 <asm/semaphore.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 - -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 semaphore mutex; - spinlock_t lock; -}; - -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); - -#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 bd514390608..00000000000 --- 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 b0848f7836b..00000000000 --- 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 a8bc84240b5..00000000000 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ /dev/null @@ -1,948 +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 - */ - -#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/module.h> -#include <linux/moduleparam.h> -#include <linux/list.h> -#include <linux/suspend.h> -#include <linux/jiffies.h> -#include <asm/processor.h> -#include <asm/semaphore.h> - -#include "dvb_frontend.h" -#include "dvbdev.h" - -// #define DEBUG_LOCKLOSS 1 - -static int dvb_frontend_debug; -static int dvb_shutdown_timeout = 5; -static int dvb_force_auto_inversion; -static int dvb_override_tune_delay; -static int dvb_powerdown_on_sleep = 1; - -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, 0444); -MODULE_PARM_DESC(dvb_shutdown_timeout, "wait <shutdown_timeout> seconds after close() before suspending hardware"); -module_param(dvb_force_auto_inversion, int, 0444); -MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always"); -module_param(dvb_override_tune_delay, int, 0444); -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, 0444); -MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB volatage off on sleep (default)"); - -#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_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) -/* - * 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. - */ - -static DECLARE_MUTEX(frontend_mutex); - -struct dvb_frontend_private { - - struct dvb_device *dvbdev; - struct dvb_frontend_parameters parameters; - struct dvb_fe_events events; - struct semaphore sem; - struct list_head list_head; - wait_queue_head_t wait_queue; - pid_t thread_pid; - unsigned long release_jiffies; - int state; - int bending; - int lnb_drift; - int inversion; - int auto_step; - int auto_sub_step; - int started_auto_step; - int min_delay; - int max_drift; - int step_size; - int exit; - int wakeup; - fe_status_t status; - fe_sec_tone_mode_t tone; -}; - - -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", __FUNCTION__); - - if (down_interruptible (&events->sem)) - return; - - 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]; - - memcpy (&e->parameters, &fepriv->parameters, - sizeof (struct dvb_frontend_parameters)); - - if (status & FE_HAS_LOCK) - if (fe->ops->get_frontend) - fe->ops->get_frontend(fe, &e->parameters); - - events->eventw = wp; - - up (&events->sem); - - e->status = status; - - 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", __FUNCTION__); - - 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; - } - - if (down_interruptible (&events->sem)) - return -ERESTARTSYS; - - memcpy (event, &events->events[events->eventr], - sizeof(struct dvb_frontend_event)); - - events->eventr = (events->eventr + 1) % MAX_EVENT; - - up (&events->sem); - - return 0; -} - -static void dvb_frontend_init(struct dvb_frontend *fe) -{ - dprintk ("DVB: initialising frontend %i (%s)...\n", - fe->dvb->num, - fe->ops->info.name); - - if (fe->ops->init) - fe->ops->init(fe); -} - -static void update_delay(int *quality, int *delay, int min_delay, int locked) -{ - int q2; - - dprintk ("%s\n", __FUNCTION__); - - if (locked) - (*quality) = (*quality * 220 + 36*256) / 256; - else - (*quality) = (*quality * 220 + 0) / 256; - - q2 = *quality - 128; - q2 *= q2; - - *delay = 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_autotune(struct dvb_frontend *fe, int check_wrapped) -{ - int autoinversion; - int ready = 0; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - int original_inversion = fepriv->parameters.inversion; - u32 original_frequency = fepriv->parameters.frequency; - - /* are we using autoinversion? */ - autoinversion = ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) && - (fepriv->parameters.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", - __FUNCTION__, fepriv->lnb_drift, fepriv->inversion, - fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step); - - /* set the frontend itself */ - fepriv->parameters.frequency += fepriv->lnb_drift; - if (autoinversion) - fepriv->parameters.inversion = fepriv->inversion; - if (fe->ops->set_frontend) - fe->ops->set_frontend(fe, &fepriv->parameters); - - fepriv->parameters.frequency = original_frequency; - fepriv->parameters.inversion = original_inversion; - - fepriv->auto_sub_step++; - return 0; -} - -static int dvb_frontend_is_exiting(struct dvb_frontend *fe) -{ - struct dvb_frontend_private *fepriv = fe->frontend_priv; - - if (fepriv->exit) - return 1; - - if (fepriv->dvbdev->writers == 1) - if (time_after(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); -} - -/* - * FIXME: use linux/kthread.h - */ -static int dvb_frontend_thread(void *data) -{ - struct dvb_frontend *fe = data; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - unsigned long timeout; - char name [15]; - int quality = 0, delay = 3*HZ; - fe_status_t s; - int check_wrapped = 0; - - dprintk("%s\n", __FUNCTION__); - - snprintf (name, sizeof(name), "kdvb-fe-%i", fe->dvb->num); - - lock_kernel(); - daemonize(name); - sigfillset(¤t->blocked); - unlock_kernel(); - - fepriv->status = 0; - dvb_frontend_init(fe); - fepriv->wakeup = 0; - - while (1) { - up(&fepriv->sem); /* is locked when we enter the thread... */ - - timeout = wait_event_interruptible_timeout(fepriv->wait_queue, - dvb_frontend_should_wakeup(fe), - delay); - if (0 != dvb_frontend_is_exiting(fe)) { - /* got signal or quitting */ - break; - } - - try_to_freeze(); - - if (down_interruptible(&fepriv->sem)) - break; - - /* if we've got no parameters, just keep idling */ - if (fepriv->state & FESTATE_IDLE) { - delay = 3*HZ; - quality = 0; - continue; - } - - /* 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)) { - update_delay(&quality, &delay, fepriv->min_delay, 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)) && - (fepriv->parameters.inversion == INVERSION_AUTO)) { - fepriv->parameters.inversion = fepriv->inversion; - } - continue; - } - - /* if we are tuned already, check we're still locked */ - if (fepriv->state & FESTATE_TUNED) { - update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK); - - /* we're tuned, and the lock is still good... */ - if (s & FE_HAS_LOCK) - continue; - else { /* if we _WERE_ tuned, but now don't have a lock */ -#ifdef DEBUG_LOCKLOSS - /* first of all try setting the tone again if it was on - this - * sometimes works around problems with noisy power supplies */ - if (fe->ops->set_tone && (fepriv->tone == SEC_TONE_ON)) { - fe->ops->set_tone(fe, fepriv->tone); - mdelay(100); - s = 0; - fe->ops->read_status(fe, &s); - if (s & FE_HAS_LOCK) { - printk("DVB%i: Lock was lost, but regained by setting " - "the tone. This may indicate your power supply " - "is noisy/slightly incompatable with this DVB-S " - "adapter\n", fe->dvb->num); - fepriv->state = FESTATE_TUNED; - continue; - } - } -#endif - /* some other reason for losing the lock - start zigzagging */ - fepriv->state = FESTATE_ZIGZAG_FAST; - fepriv->started_auto_step = fepriv->auto_step; - 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)) { - update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK); - continue; - } - - /* 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) { - update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK); - continue; - } - - /* 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; - check_wrapped = 0; - } - - /* fast zigzag. */ - if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) { - delay = fepriv->min_delay; - - /* peform a tune */ - if (dvb_frontend_autotune(fe, check_wrapped)) { - /* 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; - continue; - } - 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) { - update_delay(&quality, &delay, fepriv->min_delay, s & FE_HAS_LOCK); - - /* Note: don't bother checking for wrapping; we stay in this - * state until we get a lock */ - dvb_frontend_autotune(fe, 0); - } - } - - if (dvb_shutdown_timeout) { - if (dvb_powerdown_on_sleep) - if (fe->ops->set_voltage) - fe->ops->set_voltage(fe, SEC_VOLTAGE_OFF); - if (fe->ops->sleep) - fe->ops->sleep(fe); - } - - fepriv->thread_pid = 0; - mb(); - - dvb_frontend_wakeup(fe); - return 0; -} - -static void dvb_frontend_stop(struct dvb_frontend *fe) -{ - unsigned long ret; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - - dprintk ("%s\n", __FUNCTION__); - - fepriv->exit = 1; - mb(); - - if (!fepriv->thread_pid) - return; - - /* check if the thread is really alive */ - if (kill_proc(fepriv->thread_pid, 0, 1) == -ESRCH) { - printk("dvb_frontend_stop: thread PID %d already died\n", - fepriv->thread_pid); - /* make sure the mutex was not held by the thread */ - init_MUTEX (&fepriv->sem); - return; - } - - /* wake up the frontend thread, so it notices that fe->exit == 1 */ - dvb_frontend_wakeup(fe); - - /* wait until the frontend thread has exited */ - ret = wait_event_interruptible(fepriv->wait_queue,0 == fepriv->thread_pid); - if (-ERESTARTSYS != ret) { - fepriv->state = FESTATE_IDLE; - return; - } - fepriv->state = FESTATE_IDLE; - - /* paranoia check in case a signal arrived */ - if (fepriv->thread_pid) - printk("dvb_frontend_stop: warning: thread PID %d won't exit\n", - fepriv->thread_pid); -} - -static int dvb_frontend_start(struct dvb_frontend *fe) -{ - int ret; - struct dvb_frontend_private *fepriv = fe->frontend_priv; - - dprintk ("%s\n", __FUNCTION__); - - if (fepriv->thread_pid) { - if (!fepriv->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 = 0; - fepriv->thread_pid = 0; - mb(); - - ret = kernel_thread (dvb_frontend_thread, fe, 0); - - if (ret < 0) { - printk("dvb_frontend_start: failed to start kernel_thread (%d)\n", ret); - up(&fepriv->sem); - return ret; - } - fepriv->thread_pid = ret; - - return 0; -} - -static int dvb_frontend_ioctl(struct inode *inode, 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; - int err = -EOPNOTSUPP; - - dprintk ("%s\n", __FUNCTION__); - - if (!fe || fepriv->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; - - switch (cmd) { - case FE_GET_INFO: { - struct dvb_frontend_info* info = parg; - memcpy(info, &fe->ops->info, sizeof(struct dvb_frontend_info)); - - /* 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 occured yet, prevent - * that user get signal state from previous tuning */ - if(fepriv->state == FESTATE_RETUNE) { - 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->state = FESTATE_DISEQC; - fepriv->status = 0; - fepriv->tone = (fe_sec_tone_mode_t) parg; - } - break; - - case FE_SET_VOLTAGE: - if (fe->ops->set_voltage) { - err = fe->ops->set_voltage(fe, (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 int) parg); - 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, (int) parg); - break; - - case FE_SET_FRONTEND: { - struct dvb_frontend_tune_settings fetunesettings; - - memcpy (&fepriv->parameters, parg, - sizeof (struct dvb_frontend_parameters)); - - memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings)); - memcpy(&fetunesettings.parameters, parg, - sizeof (struct dvb_frontend_parameters)); - - /* force auto frequency inversion if requested */ - if (dvb_force_auto_inversion) { - fepriv->parameters.inversion = INVERSION_AUTO; - fetunesettings.parameters.inversion = INVERSION_AUTO; - } - if (fe->ops->info.type == FE_OFDM) { - /* without hierachical coding code_rate_LP is irrelevant, - * so we tolerate the otherwise invalid FEC_NONE setting */ - if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE && - fepriv->parameters.u.ofdm.code_rate_LP == FEC_NONE) - fepriv->parameters.u.ofdm.code_rate_LP = FEC_AUTO; - } - - /* get frontend-specific tuning 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(fe->ops->info.type) { - case FE_QPSK: - fepriv->min_delay = HZ/20; - fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000; - fepriv->max_drift = fepriv->parameters.u.qpsk.symbol_rate / 2000; - break; - - case FE_QAM: - fepriv->min_delay = HZ/20; - fepriv->step_size = 0; /* no zigzag */ - fepriv->max_drift = 0; - break; - - case FE_OFDM: - 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; - case FE_ATSC: - printk("dvb-core: FE_ATSC not handled yet.\n"); - break; - } - } - if (dvb_override_tune_delay > 0) - fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000; - - fepriv->state = FESTATE_RETUNE; - dvb_frontend_wakeup(fe); - dvb_frontend_add_event(fe, 0); - fepriv->status = 0; - err = 0; - break; - } - - case FE_GET_EVENT: - err = dvb_frontend_get_event (fe, parg, file->f_flags); - break; - - case FE_GET_FRONTEND: - if (fe->ops->get_frontend) { - memcpy (parg, &fepriv->parameters, sizeof (struct dvb_frontend_parameters)); - err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg); - } - break; - }; - - up (&fepriv->sem); - 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", __FUNCTION__); - - 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; - int ret; - - dprintk ("%s\n", __FUNCTION__); - - if ((ret = dvb_generic_open (inode, file)) < 0) - return ret; - - if ((file->f_flags & O_ACCMODE) != O_RDONLY) { - ret = dvb_frontend_start (fe); - if (ret) - dvb_generic_release (inode, file); - - /* empty event queue */ - fepriv->events.eventr = fepriv->events.eventw = 0; - } - - 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; - - dprintk ("%s\n", __FUNCTION__); - - if ((file->f_flags & O_ACCMODE) != O_RDONLY) - fepriv->release_jiffies = jiffies; - - return dvb_generic_release (inode, file); -} - -static struct file_operations dvb_frontend_fops = { - .owner = THIS_MODULE, - .ioctl = dvb_generic_ioctl, - .poll = dvb_frontend_poll, - .open = dvb_frontend_open, - .release = dvb_frontend_release -}; - -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", __FUNCTION__); - - if (down_interruptible (&frontend_mutex)) - return -ERESTARTSYS; - - fe->frontend_priv = kmalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL); - if (fe->frontend_priv == NULL) { - up(&frontend_mutex); - return -ENOMEM; - } - fepriv = fe->frontend_priv; - memset(fe->frontend_priv, 0, sizeof(struct dvb_frontend_private)); - - init_MUTEX (&fepriv->sem); - init_waitqueue_head (&fepriv->wait_queue); - init_waitqueue_head (&fepriv->events.wait_queue); - init_MUTEX (&fepriv->events.sem); - fe->dvb = dvb; - fepriv->inversion = INVERSION_OFF; - fepriv->tone = SEC_TONE_OFF; - - printk ("DVB: registering frontend %i (%s)...\n", - fe->dvb->num, - fe->ops->info.name); - - dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template, - fe, DVB_DEVICE_FRONTEND); - - up (&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", __FUNCTION__); - - down (&frontend_mutex); - dvb_unregister_device (fepriv->dvbdev); - dvb_frontend_stop (fe); - if (fe->ops->release) - fe->ops->release(fe); - else - printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops->info.name); - /* fe is invalid now */ - kfree(fepriv); - up (&frontend_mutex); - return 0; -} -EXPORT_SYMBOL(dvb_unregister_frontend); 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 9c2c1d1136b..00000000000 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ /dev/null @@ -1,104 +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/dvb/frontend.h> - -#include "dvbdev.h" - -struct dvb_frontend_tune_settings { - int min_delay_ms; - int step_size; - int max_drift; - struct dvb_frontend_parameters parameters; -}; - -struct dvb_frontend; - -struct dvb_frontend_ops { - - struct dvb_frontend_info info; - - void (*release)(struct dvb_frontend* fe); - - int (*init)(struct dvb_frontend* fe); - int (*sleep)(struct dvb_frontend* fe); - - int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); - int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); - int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings); - - 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, int arg); - int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd); -}; - -#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 semaphore sem; -}; - -struct dvb_frontend { - struct dvb_frontend_ops* ops; - struct dvb_adapter *dvb; - void* demodulator_priv; - void* frontend_priv; -}; - -extern int dvb_register_frontend(struct dvb_adapter* dvb, - struct dvb_frontend* fe); - -extern int dvb_unregister_frontend(struct dvb_frontend* fe); - -#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 87935490bfb..00000000000 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ /dev/null @@ -1,1391 +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 draft-ietf-ipdvb-ule-03.txt. - * - * 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. - */ - -/* - * FIXME / TODO (dvb_net.c): - * - * Unloading does not work for 2.6.9 kernels: a refcount doesn't go to zero. - * - * TS_FEED callback is called once for every single TS cell although it is - * registered (in dvb_net_feed_start()) for 100 TS cells (used for dvb_net_ule()). - * - */ - -#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 "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 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; - struct net_device_stats stats; - u16 pid; - 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. */ -}; - - -/** - * 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 unsigned short dvb_net_eth_type_trans(struct sk_buff *skb, - struct net_device *dev) -{ - struct ethhdr *eth; - unsigned char *rawp; - - skb->mac.raw=skb->data; - 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 - -static int ule_test_sndu( struct dvb_net_priv *p ) -{ - return -1; -} - -static int ule_bridged_sndu( struct dvb_net_priv *p ) -{ - /* BRIDGE SNDU handling sucks in draft-ietf-ipdvb-ule-03.txt. - * This has to be the last extension header, otherwise it won't work. - * Blame the authors! - */ - p->ule_bridged = 1; - 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 ) = { 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 ); - p->ule_next_hdr += ext_len; - if (! p->ule_bridged) { - p->ule_sndu_type = ntohs( *(unsigned short *)p->ule_next_hdr ); - p->ule_next_hdr += 2; - } else { - p->ule_sndu_type = ntohs( *(unsigned short *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)) ); - /* This assures the extension handling loop will terminate. */ - } - } else - ext_len = -1; /* SNDU has to be discarded. */ - } else { - /* Optional extension header. Calculate the length. */ - ext_len = hlen << 2; - /* 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( *(unsigned short *)p->ule_next_hdr ); - p->ule_next_hdr += 2; - } - - 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 == -1) return -1; /* Stop extension header processing and discard SNDU. */ - total_ext_len += l; - - } 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 = dev->priv; - unsigned long skipped = 0L; - u8 *ts, *ts_end, *from_where = NULL, ts_remain = 0, how_much = 0, new_ts = 1; - struct ethhdr *ethh = NULL; - -#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 = 0; -#endif - - if (dev == NULL) { - printk( KERN_ERR "NO netdev struct!\n" ); - return; - } - - /* For all TS cells in current buffer. - * Appearently, we are called for every single TS cell. - */ - for (ts = (char *)buf, ts_end = (char *)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. */ - ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++; - ((struct dvb_net_priv *) dev->priv)->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; - } - } - - /* Check continuity counter. */ - if (new_ts) { - if ((ts[3] & 0x0F) == priv->tscc) - priv->tscc = (priv->tscc + 1) & 0x0F; - else { - /* TS discontinuity handling: */ - printk(KERN_WARNING "%lu: TS discontinuity: got %#x, " - "exptected %#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. - ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++; - ((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++; - } - reset_ule(priv); - /* skip to next PUSI. */ - priv->need_pusi = 1; - ts += TS_SZ; - priv->ts_count++; - 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 > 181) { - /* 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) { - dev_kfree_skb( priv->ule_skb ); - ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++; - ((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++; - } - reset_ule(priv); - priv->need_pusi = 1; - ts += TS_SZ; - priv->ts_count++; - 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. */ - ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++; - ((struct dvb_net_priv *) dev->priv)->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; - 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 > 32763) { - printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. " - "Resyncing.\n", priv->ts_count, priv->ule_sndu_len); - 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; - } - - /* - * 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_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 |= 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); - ((struct dvb_net_priv *)dev->priv)->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. */ - unsigned short ulen = htons(priv->ule_sndu_len); - unsigned short utype = htons(priv->ule_sndu_type); - struct kvec iov[3] = { - { &ulen, sizeof ulen }, - { &utype, sizeof utype }, - { priv->ule_skb->data, priv->ule_skb->len - 4 } - }; - unsigned long ule_crc = ~0L, expected_crc; - if (priv->ule_dbit) { - /* Set D-bit for CRC32 verification, - * if it was set originally. */ - ulen |= 0x0080; - } - - ule_crc = iov_crc32(ule_crc, iov, 3); - expected_crc = *((u8 *)priv->ule_skb->tail - 4) << 24 | - *((u8 *)priv->ule_skb->tail - 3) << 16 | - *((u8 *)priv->ule_skb->tail - 2) << 8 | - *((u8 *)priv->ule_skb->tail - 1); - if (ule_crc != expected_crc) { - printk(KERN_WARNING "%lu: CRC32 check FAILED: %#lx / %#lx, 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 - - ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++; - ((struct dvb_net_priv *) dev->priv)->stats.rx_crc_errors++; - dev_kfree_skb(priv->ule_skb); - } else { - /* CRC32 verified OK. */ - /* 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 ); - } - - /* CRC32 was OK. Remove it from skb. */ - priv->ule_skb->tail -= 4; - priv->ule_skb->len -= 4; - - /* Filter on receiver's destination MAC address, if present. */ - if (!priv->ule_dbit) { - /* The destination MAC address is the next data in the skb. */ - if (memcmp( priv->ule_skb->data, dev->dev_addr, ETH_ALEN )) { - /* MAC addresses don't match. Drop SNDU. */ - // printk( KERN_WARNING "Dropping SNDU, MAC address.\n" ); - dev_kfree_skb( priv->ule_skb ); - goto sndu_done; - } - if (! priv->ule_bridged) { - skb_push( priv->ule_skb, ETH_ALEN + 2 ); - ethh = (struct ethhdr *)priv->ule_skb->data; - memcpy( ethh->h_dest, ethh->h_source, ETH_ALEN ); - memset( ethh->h_source, 0, ETH_ALEN ); - ethh->h_proto = htons( priv->ule_sndu_type ); - } else { - /* Skip the Receiver destination MAC address. */ - skb_pull( priv->ule_skb, ETH_ALEN ); - } - } else { - if (! priv->ule_bridged) { - skb_push( priv->ule_skb, ETH_HLEN ); - ethh = (struct ethhdr *)priv->ule_skb->data; - memcpy( ethh->h_dest, dev->dev_addr, ETH_ALEN ); - memset( ethh->h_source, 0, ETH_ALEN ); - 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; */ - ((struct dvb_net_priv *) dev->priv)->stats.rx_packets++; - ((struct dvb_net_priv *) dev->priv)->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 != 0) - printk(KERN_WARNING "buffer2 not 0: %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, u8 *pkt, int pkt_len) -{ - u8 *eth; - struct sk_buff *skb; - struct net_device_stats *stats = &(((struct dvb_net_priv *) dev->priv)->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, (u8*) buffer1, buffer1_len); - return 0; -} - -static int dvb_net_tx(struct sk_buff *skb, struct net_device *dev) -{ - dev_kfree_skb(skb); - return 0; -} - -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 = dev->priv; - 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=%02x %02x %02x %02x %02x %02x\n", - dev->name, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); - dprintk("%s: filter mask=%02x %02x %02x %02x %02x %02x\n", - dev->name, mac_mask[0], mac_mask[1], mac_mask[2], - mac_mask[3], mac_mask[4], mac_mask[5]); - - return 0; -} - -static int dvb_net_feed_start(struct net_device *dev) -{ - int ret, i; - struct dvb_net_priv *priv = dev->priv; - struct dmx_demux *demux = priv->demux; - unsigned char *mac = (unsigned char *) dev->dev_addr; - - dprintk("%s: rx_mode %i\n", __FUNCTION__, priv->rx_mode); - if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0]) - printk("%s: BUG %d\n", __FUNCTION__, __LINE__); - - priv->secfeed=NULL; - priv->secfilter=NULL; - priv->tsfeed = NULL; - - if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) { - dprintk("%s: alloc secfeed\n", __FUNCTION__); - 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); - return ret; - } - - 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; - return ret; - } - - if (priv->rx_mode != RX_MODE_PROMISC) { - dprintk("%s: set secfilter\n", __FUNCTION__); - 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", __FUNCTION__, 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", __FUNCTION__); - 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", __FUNCTION__); - dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_promisc); - break; - } - - dprintk("%s: start filtering\n", __FUNCTION__); - priv->secfeed->start_filtering(priv->secfeed); - } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) { - struct timespec timeout = { 0, 30000000 }; // 30 msec - - /* we have payloads encapsulated in TS */ - dprintk("%s: alloc tsfeed\n", __FUNCTION__); - 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); - return ret; - } - - /* Set netdevice pointer for ts decaps callback. */ - priv->tsfeed->priv = (void *)dev; - ret = priv->tsfeed->set(priv->tsfeed, priv->pid, - TS_PACKET, DMX_TS_PES_OTHER, - 32768, /* circular buffer size */ - 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; - return ret; - } - - dprintk("%s: start filtering\n", __FUNCTION__); - priv->tsfeed->start_filtering(priv->tsfeed); - } else - return -EINVAL; - - return 0; -} - -static int dvb_net_feed_stop(struct net_device *dev) -{ - struct dvb_net_priv *priv = dev->priv; - int i; - - dprintk("%s\n", __FUNCTION__); - if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) { - if (priv->secfeed) { - if (priv->secfeed->is_filtering) { - dprintk("%s: stop secfeed\n", __FUNCTION__); - priv->secfeed->stop_filtering(priv->secfeed); - } - - if (priv->secfilter) { - dprintk("%s: release secfilter\n", __FUNCTION__); - 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", - __FUNCTION__, 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", __FUNCTION__); - 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 - return -EINVAL; - return 0; -} - - -static int dvb_set_mc_filter (struct net_device *dev, struct dev_mc_list *mc) -{ - struct dvb_net_priv *priv = dev->priv; - - if (priv->multi_num == DVB_NET_MULTICAST_MAX) - return -ENOMEM; - - memcpy(priv->multi_macs[priv->multi_num], mc->dmi_addr, 6); - - priv->multi_num++; - return 0; -} - - -static void wq_set_multicast_list (void *data) -{ - struct net_device *dev = data; - struct dvb_net_priv *priv = dev->priv; - - dvb_net_feed_stop(dev); - - priv->rx_mode = RX_MODE_UNI; - - 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 (dev->mc_count) { - int mci; - struct dev_mc_list *mc; - - dprintk("%s: set_mc_list, %d entries\n", - dev->name, dev->mc_count); - - priv->rx_mode = RX_MODE_MULTI; - priv->multi_num = 0; - - for (mci = 0, mc=dev->mc_list; - mci < dev->mc_count; - mc = mc->next, mci++) { - dvb_set_mc_filter(dev, mc); - } - } - - dvb_net_feed_start(dev); -} - - -static void dvb_net_set_multicast_list (struct net_device *dev) -{ - struct dvb_net_priv *priv = dev->priv; - schedule_work(&priv->set_multicast_list_wq); -} - - -static void wq_restart_net_feed (void *data) -{ - struct net_device *dev = data; - - 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 = dev->priv; - 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 = dev->priv; - - priv->in_use++; - dvb_net_feed_start(dev); - return 0; -} - - -static int dvb_net_stop(struct net_device *dev) -{ - struct dvb_net_priv *priv = dev->priv; - - priv->in_use--; - return dvb_net_feed_stop(dev); -} - -static struct net_device_stats * dvb_net_get_stats(struct net_device *dev) -{ - return &((struct dvb_net_priv*) dev->priv)->stats; -} - -static void dvb_net_setup(struct net_device *dev) -{ - ether_setup(dev); - - dev->open = dvb_net_open; - dev->stop = dvb_net_stop; - dev->hard_start_xmit = dvb_net_tx; - dev->get_stats = dvb_net_get_stats; - dev->set_multicast_list = dvb_net_set_multicast_list; - dev->set_mac_address = dvb_net_set_mac; - dev->mtu = 4096; - dev->mc_count = 0; - dev->hard_header_cache = NULL; - 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 = net->priv; - 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, net); - INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed, net); - - 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 int num) -{ - struct net_device *net = dvbnet->device[num]; - struct dvb_net_priv *priv; - - if (!dvbnet->state[num]) - return -EINVAL; - priv = net->priv; - if (priv->in_use) - return -EBUSY; - - dvb_net_stop(net); - flush_scheduled_work(); - 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 inode *inode, 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; - 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 int) parg >= DVB_NET_DEVICES_MAX) - return -EINVAL; - ret = dvb_net_remove_if(dvbnet, (unsigned int) parg); - if (!ret) - module_put(dvbdev->adapter->module); - return ret; - } - - /* binary compatiblity 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; - dvbnetif->pid=priv_data->pid; - break; - } - default: - return -ENOTTY; - } - return 0; -} - -static int dvb_net_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg) -{ - return dvb_usercopy(inode, file, cmd, arg, dvb_net_do_ioctl); -} - -static struct file_operations dvb_net_fops = { - .owner = THIS_MODULE, - .ioctl = dvb_net_ioctl, - .open = dvb_generic_open, - .release = dvb_generic_release, -}; - -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; - - 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; - - dvb_register_device (adap, &dvbnet->dvbdev, &dvbdev_net, - dvbnet, DVB_DEVICE_NET); - - return 0; -} -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 f14e4ca3857..00000000000 --- a/drivers/media/dvb/dvb-core/dvb_net.h +++ /dev/null @@ -1,46 +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 - -struct dvb_net { - struct dvb_device *dvbdev; - struct net_device *device[DVB_NET_DEVICES_MAX]; - int state[DVB_NET_DEVICES_MAX]; - struct dmx_demux *demux; -}; - - -void dvb_net_release(struct dvb_net *); -int dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *); - -#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 fb6d94a69d7..00000000000 --- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c +++ /dev/null @@ -1,270 +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. - */ - - - -#define __KERNEL_SYSCALLS__ -#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; - - 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; -} - - - -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(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len, int usermem) -{ - size_t todo = len; - size_t split; - - split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0; - if (split > 0) { - if (!usermem) - memcpy(buf, rbuf->data+rbuf->pread, split); - else - if (copy_to_user(buf, rbuf->data+rbuf->pread, split)) - return -EFAULT; - buf += split; - todo -= split; - rbuf->pread = 0; - } - if (!usermem) - memcpy(buf, rbuf->data+rbuf->pread, todo); - else - if (copy_to_user(buf, rbuf->data+rbuf->pread, todo)) - return -EFAULT; - - rbuf->pread = (rbuf->pread + todo) % rbuf->size; - - return len; -} - - - -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(struct dvb_ringbuffer *rbuf, size_t idx, - int offset, u8* buf, size_t len, int usermem) -{ - 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 (!usermem) - memcpy(buf, rbuf->data+idx, split); - else - if (copy_to_user(buf, rbuf->data+idx, split)) - return -EFAULT; - buf += split; - todo -= split; - idx = 0; - } - if (!usermem) - memcpy(buf, rbuf->data+idx, todo); - else - if (copy_to_user(buf, rbuf->data+idx, todo)) - return -EFAULT; - - 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); -EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup); -EXPORT_SYMBOL(dvb_ringbuffer_read); -EXPORT_SYMBOL(dvb_ringbuffer_write); -EXPORT_SYMBOL(dvb_ringbuffer_pkt_write); -EXPORT_SYMBOL(dvb_ringbuffer_pkt_read); -EXPORT_SYMBOL(dvb_ringbuffer_pkt_dispose); -EXPORT_SYMBOL(dvb_ringbuffer_pkt_next); 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 d18e9c4ba9e..00000000000 --- a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h +++ /dev/null @@ -1,173 +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; - - 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), 0); -** 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. -** 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); - - -/* 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(struct dvb_ringbuffer *rbuf, u8 *buf, - size_t len, int usermem); - - -/* 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(struct dvb_ringbuffer *rbuf, size_t idx, - int offset, u8* buf, size_t len, int usermem); - -/** - * 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 477b4fa5643..00000000000 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ /dev/null @@ -1,441 +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/moduleparam.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/init.h> -#include <linux/slab.h> -#include <linux/device.h> -#include <linux/fs.h> -#include <linux/cdev.h> - -#include "dvbdev.h" - -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 DECLARE_MUTEX(dvbdev_register_lock); - -static const char * const dnames[] = { - "video", "audio", "sec", "frontend", "demux", "dvr", "ca", - "net", "osd" -}; - -#define DVB_MAX_ADAPTERS 8 -#define DVB_MAX_IDS 4 -#define nums2minor(num,type,id) ((num << 6) | (id << 4) | type) -#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64) - -static struct class *dvb_class; - -static struct dvb_device* dvbdev_find_device (int minor) -{ - struct list_head *entry; - - list_for_each (entry, &dvb_adapter_list) { - struct list_head *entry0; - struct dvb_adapter *adap; - adap = list_entry (entry, struct dvb_adapter, list_head); - list_for_each (entry0, &adap->device_list) { - struct dvb_device *dev; - dev = list_entry (entry0, struct dvb_device, list_head); - if (nums2minor(adap->num, dev->type, dev->id) == minor) - return dev; - } - } - - return NULL; -} - - -static int dvb_device_open(struct inode *inode, struct file *file) -{ - struct dvb_device *dvbdev; - - dvbdev = dvbdev_find_device (iminor(inode)); - - if (dvbdev && dvbdev->fops) { - int err = 0; - 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->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); - return err; - } - return -ENODEV; -} - - -static struct file_operations dvb_device_fops = -{ - .owner = THIS_MODULE, - .open = dvb_device_open, -}; - -static struct cdev dvb_device_cdev = { - .kobj = {.name = "dvb", }, - .owner = THIS_MODULE, -}; - -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); - - -int dvb_generic_ioctl(struct inode *inode, 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 (inode, 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 list_head *entry; - list_for_each (entry, &adap->device_list) { - struct dvb_device *dev; - dev = list_entry (entry, struct dvb_device, 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; - int id; - - if (down_interruptible (&dvbdev_register_lock)) - return -ERESTARTSYS; - - if ((id = dvbdev_get_free_id (adap, type)) < 0) { - up (&dvbdev_register_lock); - *pdvbdev = NULL; - printk ("%s: could get find free device id...\n", __FUNCTION__); - return -ENFILE; - } - - *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL); - - if (!dvbdev) { - up(&dvbdev_register_lock); - return -ENOMEM; - } - - up (&dvbdev_register_lock); - - memcpy(dvbdev, template, sizeof(struct dvb_device)); - dvbdev->type = type; - dvbdev->id = id; - dvbdev->adapter = adap; - dvbdev->priv = priv; - - dvbdev->fops->owner = adap->module; - - list_add_tail (&dvbdev->list_head, &adap->device_list); - - devfs_mk_cdev(MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), - S_IFCHR | S_IRUSR | S_IWUSR, - "dvb/adapter%d/%s%d", adap->num, dnames[type], id); - - class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), - NULL, "dvb%d.%s%d", adap->num, dnames[type], id); - - dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", - adap->num, dnames[type], id, nums2minor(adap->num, type, id), - nums2minor(adap->num, type, id)); - - return 0; -} -EXPORT_SYMBOL(dvb_register_device); - - -void dvb_unregister_device(struct dvb_device *dvbdev) -{ - if (!dvbdev) - return; - - devfs_remove("dvb/adapter%d/%s%d", dvbdev->adapter->num, - dnames[dvbdev->type], dvbdev->id); - - class_device_destroy(dvb_class, MKDEV(DVB_MAJOR, nums2minor(dvbdev->adapter->num, - dvbdev->type, dvbdev->id))); - - list_del (&dvbdev->list_head); - kfree (dvbdev); -} -EXPORT_SYMBOL(dvb_unregister_device); - - -static int dvbdev_get_free_adapter_num (void) -{ - int num = 0; - - while (num < DVB_MAX_ADAPTERS) { - 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) - goto skip; - } - return num; -skip: - num++; - } - - return -ENFILE; -} - - -int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module) -{ - int num; - - if (down_interruptible (&dvbdev_register_lock)) - return -ERESTARTSYS; - - if ((num = dvbdev_get_free_adapter_num ()) < 0) { - up (&dvbdev_register_lock); - return -ENFILE; - } - - memset (adap, 0, sizeof(struct dvb_adapter)); - INIT_LIST_HEAD (&adap->device_list); - - printk ("DVB: registering new adapter (%s).\n", name); - - devfs_mk_dir("dvb/adapter%d", num); - adap->num = num; - adap->name = name; - adap->module = module; - - list_add_tail (&adap->list_head, &dvb_adapter_list); - - up (&dvbdev_register_lock); - - return num; -} -EXPORT_SYMBOL(dvb_register_adapter); - - -int dvb_unregister_adapter(struct dvb_adapter *adap) -{ - devfs_remove("dvb/adapter%d", adap->num); - - if (down_interruptible (&dvbdev_register_lock)) - return -ERESTARTSYS; - list_del (&adap->list_head); - up (&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 inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, - int (*func)(struct inode *inode, 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 */ - if ((err = func(inode, file, cmd, parg)) == -ENOIOCTLCMD) - err = -EINVAL; - - 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 __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("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("dvb-core: unable to get major %d\n", DVB_MAJOR); - goto error; - } - - devfs_mk_dir("dvb"); - - dvb_class = class_create(THIS_MODULE, "dvb"); - if (IS_ERR(dvb_class)) { - retval = PTR_ERR(dvb_class); - goto error; - } - return 0; - -error: - cdev_del(&dvb_device_cdev); - unregister_chrdev_region(dev, MAX_DVB_MINORS); - return retval; -} - - -static void __exit exit_dvbdev(void) -{ - devfs_remove("dvb"); - class_destroy(dvb_class); - cdev_del(&dvb_device_cdev); - unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS); -} - -module_init(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 a251867f30f..00000000000 --- a/drivers/media/dvb/dvb-core/dvbdev.h +++ /dev/null @@ -1,104 +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> -#include <linux/devfs_fs_kernel.h> -#include <linux/smp_lock.h> - -#define DVB_MAJOR 212 - -#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 - - -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 module *module; -}; - - -struct dvb_device { - struct list_head list_head; - struct file_operations *fops; - struct dvb_adapter *adapter; - int type; - u32 id; - - /* in theory, 'users' can vanish now, - but I don't want to change too much now... */ - int readers; - int writers; - int users; - - /* don't really need those !? -- FIXME: use video_usercopy */ - int (*kernel_ioctl)(struct inode *inode, 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); -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 int dvb_generic_ioctl (struct inode *inode, 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 inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, - int (*func)(struct inode *inode, struct file *file, - unsigned int cmd, void *arg)); - -#endif /* #ifndef _DVBDEV_H_ */ |
