diff options
Diffstat (limited to 'drivers/media/dvb/dvb-core')
20 files changed, 11384 insertions, 0 deletions
diff --git a/drivers/media/dvb/dvb-core/Makefile b/drivers/media/dvb/dvb-core/Makefile new file mode 100644 index 00000000000..8f22bcd7c1f --- /dev/null +++ b/drivers/media/dvb/dvb-core/Makefile | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | # | ||
| 2 | # Makefile for the kernel DVB device drivers. | ||
| 3 | # | ||
| 4 | |||
| 5 | dvb-net-$(CONFIG_DVB_NET) := dvb_net.o | ||
| 6 | |||
| 7 | dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \ | ||
| 8 | dvb_ca_en50221.o dvb_frontend.o \ | ||
| 9 | $(dvb-net-y) dvb_ringbuffer.o dvb_math.o | ||
| 10 | |||
| 11 | 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 new file mode 100644 index 00000000000..eb91fd808c1 --- /dev/null +++ b/drivers/media/dvb/dvb-core/demux.h | |||
| @@ -0,0 +1,280 @@ | |||
| 1 | /* | ||
| 2 | * demux.h | ||
| 3 | * | ||
| 4 | * Copyright (c) 2002 Convergence GmbH | ||
| 5 | * | ||
| 6 | * based on code: | ||
| 7 | * Copyright (c) 2000 Nokia Research Center | ||
| 8 | * Tampere, FINLAND | ||
| 9 | * | ||
| 10 | * This program is free software; you can redistribute it and/or | ||
| 11 | * modify it under the terms of the GNU Lesser General Public License | ||
| 12 | * as published by the Free Software Foundation; either version 2.1 | ||
| 13 | * of the License, or (at your option) any later version. | ||
| 14 | * | ||
| 15 | * This program is distributed in the hope that it will be useful, | ||
| 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | * GNU General Public License for more details. | ||
| 19 | * | ||
| 20 | * You should have received a copy of the GNU Lesser General Public License | ||
| 21 | * along with this program; if not, write to the Free Software | ||
| 22 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 23 | * | ||
| 24 | */ | ||
| 25 | |||
| 26 | #ifndef __DEMUX_H | ||
| 27 | #define __DEMUX_H | ||
| 28 | |||
| 29 | #include <linux/types.h> | ||
| 30 | #include <linux/errno.h> | ||
| 31 | #include <linux/list.h> | ||
| 32 | #include <linux/time.h> | ||
| 33 | #include <linux/dvb/dmx.h> | ||
| 34 | |||
| 35 | /*--------------------------------------------------------------------------*/ | ||
| 36 | /* Common definitions */ | ||
| 37 | /*--------------------------------------------------------------------------*/ | ||
| 38 | |||
| 39 | /* | ||
| 40 | * DMX_MAX_FILTER_SIZE: Maximum length (in bytes) of a section/PES filter. | ||
| 41 | */ | ||
| 42 | |||
| 43 | #ifndef DMX_MAX_FILTER_SIZE | ||
| 44 | #define DMX_MAX_FILTER_SIZE 18 | ||
| 45 | #endif | ||
| 46 | |||
| 47 | /* | ||
| 48 | * DMX_MAX_SECFEED_SIZE: Maximum length (in bytes) of a private section feed filter. | ||
| 49 | */ | ||
| 50 | |||
| 51 | #ifndef DMX_MAX_SECTION_SIZE | ||
| 52 | #define DMX_MAX_SECTION_SIZE 4096 | ||
| 53 | #endif | ||
| 54 | #ifndef DMX_MAX_SECFEED_SIZE | ||
| 55 | #define DMX_MAX_SECFEED_SIZE (DMX_MAX_SECTION_SIZE + 188) | ||
| 56 | #endif | ||
| 57 | |||
| 58 | |||
| 59 | /* | ||
| 60 | * enum dmx_success: Success codes for the Demux Callback API. | ||
| 61 | */ | ||
| 62 | |||
| 63 | enum dmx_success { | ||
| 64 | DMX_OK = 0, /* Received Ok */ | ||
| 65 | DMX_LENGTH_ERROR, /* Incorrect length */ | ||
| 66 | DMX_OVERRUN_ERROR, /* Receiver ring buffer overrun */ | ||
| 67 | DMX_CRC_ERROR, /* Incorrect CRC */ | ||
| 68 | DMX_FRAME_ERROR, /* Frame alignment error */ | ||
| 69 | DMX_FIFO_ERROR, /* Receiver FIFO overrun */ | ||
| 70 | DMX_MISSED_ERROR /* Receiver missed packet */ | ||
| 71 | } ; | ||
| 72 | |||
| 73 | /*--------------------------------------------------------------------------*/ | ||
| 74 | /* TS packet reception */ | ||
| 75 | /*--------------------------------------------------------------------------*/ | ||
| 76 | |||
| 77 | /* TS filter type for set() */ | ||
| 78 | |||
| 79 | #define TS_PACKET 1 /* send TS packets (188 bytes) to callback (default) */ | ||
| 80 | #define TS_PAYLOAD_ONLY 2 /* in case TS_PACKET is set, only send the TS | ||
| 81 | payload (<=184 bytes per packet) to callback */ | ||
| 82 | #define TS_DECODER 4 /* send stream to built-in decoder (if present) */ | ||
| 83 | #define TS_DEMUX 8 /* in case TS_PACKET is set, send the TS to | ||
| 84 | the demux device, not to the dvr device */ | ||
| 85 | |||
| 86 | /* PES type for filters which write to built-in decoder */ | ||
| 87 | /* these should be kept identical to the types in dmx.h */ | ||
| 88 | |||
| 89 | enum dmx_ts_pes | ||
| 90 | { /* also send packets to decoder (if it exists) */ | ||
| 91 | DMX_TS_PES_AUDIO0, | ||
| 92 | DMX_TS_PES_VIDEO0, | ||
| 93 | DMX_TS_PES_TELETEXT0, | ||
| 94 | DMX_TS_PES_SUBTITLE0, | ||
| 95 | DMX_TS_PES_PCR0, | ||
| 96 | |||
| 97 | DMX_TS_PES_AUDIO1, | ||
| 98 | DMX_TS_PES_VIDEO1, | ||
| 99 | DMX_TS_PES_TELETEXT1, | ||
| 100 | DMX_TS_PES_SUBTITLE1, | ||
| 101 | DMX_TS_PES_PCR1, | ||
| 102 | |||
| 103 | DMX_TS_PES_AUDIO2, | ||
| 104 | DMX_TS_PES_VIDEO2, | ||
| 105 | DMX_TS_PES_TELETEXT2, | ||
| 106 | DMX_TS_PES_SUBTITLE2, | ||
| 107 | DMX_TS_PES_PCR2, | ||
| 108 | |||
| 109 | DMX_TS_PES_AUDIO3, | ||
| 110 | DMX_TS_PES_VIDEO3, | ||
| 111 | DMX_TS_PES_TELETEXT3, | ||
| 112 | DMX_TS_PES_SUBTITLE3, | ||
| 113 | DMX_TS_PES_PCR3, | ||
| 114 | |||
| 115 | DMX_TS_PES_OTHER | ||
| 116 | }; | ||
| 117 | |||
| 118 | #define DMX_TS_PES_AUDIO DMX_TS_PES_AUDIO0 | ||
| 119 | #define DMX_TS_PES_VIDEO DMX_TS_PES_VIDEO0 | ||
| 120 | #define DMX_TS_PES_TELETEXT DMX_TS_PES_TELETEXT0 | ||
| 121 | #define DMX_TS_PES_SUBTITLE DMX_TS_PES_SUBTITLE0 | ||
| 122 | #define DMX_TS_PES_PCR DMX_TS_PES_PCR0 | ||
| 123 | |||
| 124 | |||
| 125 | struct dmx_ts_feed { | ||
| 126 | int is_filtering; /* Set to non-zero when filtering in progress */ | ||
| 127 | struct dmx_demux *parent; /* Back-pointer */ | ||
| 128 | void *priv; /* Pointer to private data of the API client */ | ||
| 129 | int (*set) (struct dmx_ts_feed *feed, | ||
| 130 | u16 pid, | ||
| 131 | int type, | ||
| 132 | enum dmx_ts_pes pes_type, | ||
| 133 | size_t circular_buffer_size, | ||
| 134 | struct timespec timeout); | ||
| 135 | int (*start_filtering) (struct dmx_ts_feed* feed); | ||
| 136 | int (*stop_filtering) (struct dmx_ts_feed* feed); | ||
| 137 | }; | ||
| 138 | |||
| 139 | /*--------------------------------------------------------------------------*/ | ||
| 140 | /* Section reception */ | ||
| 141 | /*--------------------------------------------------------------------------*/ | ||
| 142 | |||
| 143 | struct dmx_section_filter { | ||
| 144 | u8 filter_value [DMX_MAX_FILTER_SIZE]; | ||
| 145 | u8 filter_mask [DMX_MAX_FILTER_SIZE]; | ||
| 146 | u8 filter_mode [DMX_MAX_FILTER_SIZE]; | ||
| 147 | struct dmx_section_feed* parent; /* Back-pointer */ | ||
| 148 | void* priv; /* Pointer to private data of the API client */ | ||
| 149 | }; | ||
| 150 | |||
| 151 | struct dmx_section_feed { | ||
| 152 | int is_filtering; /* Set to non-zero when filtering in progress */ | ||
| 153 | struct dmx_demux* parent; /* Back-pointer */ | ||
| 154 | void* priv; /* Pointer to private data of the API client */ | ||
| 155 | |||
| 156 | int check_crc; | ||
| 157 | u32 crc_val; | ||
| 158 | |||
| 159 | u8 *secbuf; | ||
| 160 | u8 secbuf_base[DMX_MAX_SECFEED_SIZE]; | ||
| 161 | u16 secbufp, seclen, tsfeedp; | ||
| 162 | |||
| 163 | int (*set) (struct dmx_section_feed* feed, | ||
| 164 | u16 pid, | ||
| 165 | size_t circular_buffer_size, | ||
| 166 | int check_crc); | ||
| 167 | int (*allocate_filter) (struct dmx_section_feed* feed, | ||
| 168 | struct dmx_section_filter** filter); | ||
| 169 | int (*release_filter) (struct dmx_section_feed* feed, | ||
| 170 | struct dmx_section_filter* filter); | ||
| 171 | int (*start_filtering) (struct dmx_section_feed* feed); | ||
| 172 | int (*stop_filtering) (struct dmx_section_feed* feed); | ||
| 173 | }; | ||
| 174 | |||
| 175 | /*--------------------------------------------------------------------------*/ | ||
| 176 | /* Callback functions */ | ||
| 177 | /*--------------------------------------------------------------------------*/ | ||
| 178 | |||
| 179 | typedef int (*dmx_ts_cb) ( const u8 * buffer1, | ||
| 180 | size_t buffer1_length, | ||
| 181 | const u8 * buffer2, | ||
| 182 | size_t buffer2_length, | ||
| 183 | struct dmx_ts_feed* source, | ||
| 184 | enum dmx_success success); | ||
| 185 | |||
| 186 | typedef int (*dmx_section_cb) ( const u8 * buffer1, | ||
| 187 | size_t buffer1_len, | ||
| 188 | const u8 * buffer2, | ||
| 189 | size_t buffer2_len, | ||
| 190 | struct dmx_section_filter * source, | ||
| 191 | enum dmx_success success); | ||
| 192 | |||
| 193 | /*--------------------------------------------------------------------------*/ | ||
| 194 | /* DVB Front-End */ | ||
| 195 | /*--------------------------------------------------------------------------*/ | ||
| 196 | |||
| 197 | enum dmx_frontend_source { | ||
| 198 | DMX_MEMORY_FE, | ||
| 199 | DMX_FRONTEND_0, | ||
| 200 | DMX_FRONTEND_1, | ||
| 201 | DMX_FRONTEND_2, | ||
| 202 | DMX_FRONTEND_3, | ||
| 203 | DMX_STREAM_0, /* external stream input, e.g. LVDS */ | ||
| 204 | DMX_STREAM_1, | ||
| 205 | DMX_STREAM_2, | ||
| 206 | DMX_STREAM_3 | ||
| 207 | }; | ||
| 208 | |||
| 209 | struct dmx_frontend { | ||
| 210 | struct list_head connectivity_list; /* List of front-ends that can | ||
| 211 | be connected to a particular | ||
| 212 | demux */ | ||
| 213 | enum dmx_frontend_source source; | ||
| 214 | }; | ||
| 215 | |||
| 216 | /*--------------------------------------------------------------------------*/ | ||
| 217 | /* MPEG-2 TS Demux */ | ||
| 218 | /*--------------------------------------------------------------------------*/ | ||
| 219 | |||
| 220 | /* | ||
| 221 | * Flags OR'ed in the capabilities field of struct dmx_demux. | ||
| 222 | */ | ||
| 223 | |||
| 224 | #define DMX_TS_FILTERING 1 | ||
| 225 | #define DMX_PES_FILTERING 2 | ||
| 226 | #define DMX_SECTION_FILTERING 4 | ||
| 227 | #define DMX_MEMORY_BASED_FILTERING 8 /* write() available */ | ||
| 228 | #define DMX_CRC_CHECKING 16 | ||
| 229 | #define DMX_TS_DESCRAMBLING 32 | ||
| 230 | |||
| 231 | /* | ||
| 232 | * Demux resource type identifier. | ||
| 233 | */ | ||
| 234 | |||
| 235 | /* | ||
| 236 | * DMX_FE_ENTRY(): Casts elements in the list of registered | ||
| 237 | * front-ends from the generic type struct list_head | ||
| 238 | * to the type * struct dmx_frontend | ||
| 239 | *. | ||
| 240 | */ | ||
| 241 | |||
| 242 | #define DMX_FE_ENTRY(list) list_entry(list, struct dmx_frontend, connectivity_list) | ||
| 243 | |||
| 244 | struct dmx_demux { | ||
| 245 | u32 capabilities; /* Bitfield of capability flags */ | ||
| 246 | struct dmx_frontend* frontend; /* Front-end connected to the demux */ | ||
| 247 | void* priv; /* Pointer to private data of the API client */ | ||
| 248 | int (*open) (struct dmx_demux* demux); | ||
| 249 | int (*close) (struct dmx_demux* demux); | ||
| 250 | int (*write) (struct dmx_demux* demux, const char __user *buf, size_t count); | ||
| 251 | int (*allocate_ts_feed) (struct dmx_demux* demux, | ||
| 252 | struct dmx_ts_feed** feed, | ||
| 253 | dmx_ts_cb callback); | ||
| 254 | int (*release_ts_feed) (struct dmx_demux* demux, | ||
| 255 | struct dmx_ts_feed* feed); | ||
| 256 | int (*allocate_section_feed) (struct dmx_demux* demux, | ||
| 257 | struct dmx_section_feed** feed, | ||
| 258 | dmx_section_cb callback); | ||
| 259 | int (*release_section_feed) (struct dmx_demux* demux, | ||
| 260 | struct dmx_section_feed* feed); | ||
| 261 | int (*add_frontend) (struct dmx_demux* demux, | ||
| 262 | struct dmx_frontend* frontend); | ||
| 263 | int (*remove_frontend) (struct dmx_demux* demux, | ||
| 264 | struct dmx_frontend* frontend); | ||
| 265 | struct list_head* (*get_frontends) (struct dmx_demux* demux); | ||
| 266 | int (*connect_frontend) (struct dmx_demux* demux, | ||
| 267 | struct dmx_frontend* frontend); | ||
| 268 | int (*disconnect_frontend) (struct dmx_demux* demux); | ||
| 269 | |||
| 270 | int (*get_pes_pids) (struct dmx_demux* demux, u16 *pids); | ||
| 271 | |||
| 272 | int (*get_caps) (struct dmx_demux* demux, struct dmx_caps *caps); | ||
| 273 | |||
| 274 | int (*set_source) (struct dmx_demux* demux, const dmx_source_t *src); | ||
| 275 | |||
| 276 | int (*get_stc) (struct dmx_demux* demux, unsigned int num, | ||
| 277 | u64 *stc, unsigned int *base); | ||
| 278 | }; | ||
| 279 | |||
| 280 | #endif /* #ifndef __DEMUX_H */ | ||
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c new file mode 100644 index 00000000000..e4b5c03ae51 --- /dev/null +++ b/drivers/media/dvb/dvb-core/dmxdev.c | |||
| @@ -0,0 +1,1278 @@ | |||
| 1 | /* | ||
| 2 | * dmxdev.c - DVB demultiplexer device | ||
| 3 | * | ||
| 4 | * Copyright (C) 2000 Ralph Metzler & Marcus Metzler | ||
| 5 | * for convergence integrated media GmbH | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU Lesser General Public License | ||
| 9 | * as published by the Free Software Foundation; either version 2.1 | ||
| 10 | * of the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #include <linux/sched.h> | ||
| 24 | #include <linux/spinlock.h> | ||
| 25 | #include <linux/slab.h> | ||
| 26 | #include <linux/vmalloc.h> | ||
| 27 | #include <linux/module.h> | ||
| 28 | #include <linux/poll.h> | ||
| 29 | #include <linux/ioctl.h> | ||
| 30 | #include <linux/wait.h> | ||
| 31 | #include <asm/uaccess.h> | ||
| 32 | #include <asm/system.h> | ||
| 33 | #include "dmxdev.h" | ||
| 34 | |||
| 35 | static int debug; | ||
| 36 | |||
| 37 | module_param(debug, int, 0644); | ||
| 38 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | ||
| 39 | |||
| 40 | #define dprintk if (debug) printk | ||
| 41 | |||
| 42 | static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf, | ||
| 43 | const u8 *src, size_t len) | ||
| 44 | { | ||
| 45 | ssize_t free; | ||
| 46 | |||
| 47 | if (!len) | ||
| 48 | return 0; | ||
| 49 | if (!buf->data) | ||
| 50 | return 0; | ||
| 51 | |||
| 52 | free = dvb_ringbuffer_free(buf); | ||
| 53 | if (len > free) { | ||
| 54 | dprintk("dmxdev: buffer overflow\n"); | ||
| 55 | return -EOVERFLOW; | ||
| 56 | } | ||
| 57 | |||
| 58 | return dvb_ringbuffer_write(buf, src, len); | ||
| 59 | } | ||
| 60 | |||
| 61 | static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src, | ||
| 62 | int non_blocking, char __user *buf, | ||
| 63 | size_t count, loff_t *ppos) | ||
| 64 | { | ||
| 65 | size_t todo; | ||
| 66 | ssize_t avail; | ||
| 67 | ssize_t ret = 0; | ||
| 68 | |||
| 69 | if (!src->data) | ||
| 70 | return 0; | ||
| 71 | |||
| 72 | if (src->error) { | ||
| 73 | ret = src->error; | ||
| 74 | dvb_ringbuffer_flush(src); | ||
| 75 | return ret; | ||
| 76 | } | ||
| 77 | |||
| 78 | for (todo = count; todo > 0; todo -= ret) { | ||
| 79 | if (non_blocking && dvb_ringbuffer_empty(src)) { | ||
| 80 | ret = -EWOULDBLOCK; | ||
| 81 | break; | ||
| 82 | } | ||
| 83 | |||
| 84 | ret = wait_event_interruptible(src->queue, | ||
| 85 | !dvb_ringbuffer_empty(src) || | ||
| 86 | (src->error != 0)); | ||
| 87 | if (ret < 0) | ||
| 88 | break; | ||
| 89 | |||
| 90 | if (src->error) { | ||
| 91 | ret = src->error; | ||
| 92 | dvb_ringbuffer_flush(src); | ||
| 93 | break; | ||
| 94 | } | ||
| 95 | |||
| 96 | avail = dvb_ringbuffer_avail(src); | ||
| 97 | if (avail > todo) | ||
| 98 | avail = todo; | ||
| 99 | |||
| 100 | ret = dvb_ringbuffer_read_user(src, buf, avail); | ||
| 101 | if (ret < 0) | ||
| 102 | break; | ||
| 103 | |||
| 104 | buf += ret; | ||
| 105 | } | ||
| 106 | |||
| 107 | return (count - todo) ? (count - todo) : ret; | ||
| 108 | } | ||
| 109 | |||
| 110 | static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type) | ||
| 111 | { | ||
| 112 | struct list_head *head, *pos; | ||
| 113 | |||
| 114 | head = demux->get_frontends(demux); | ||
| 115 | if (!head) | ||
| 116 | return NULL; | ||
| 117 | list_for_each(pos, head) | ||
| 118 | if (DMX_FE_ENTRY(pos)->source == type) | ||
| 119 | return DMX_FE_ENTRY(pos); | ||
| 120 | |||
| 121 | return NULL; | ||
| 122 | } | ||
| 123 | |||
| 124 | static int dvb_dvr_open(struct inode *inode, struct file *file) | ||
| 125 | { | ||
| 126 | struct dvb_device *dvbdev = file->private_data; | ||
| 127 | struct dmxdev *dmxdev = dvbdev->priv; | ||
| 128 | struct dmx_frontend *front; | ||
| 129 | |||
| 130 | dprintk("function : %s\n", __func__); | ||
| 131 | |||
| 132 | if (mutex_lock_interruptible(&dmxdev->mutex)) | ||
| 133 | return -ERESTARTSYS; | ||
| 134 | |||
| 135 | if (dmxdev->exit) { | ||
| 136 | mutex_unlock(&dmxdev->mutex); | ||
| 137 | return -ENODEV; | ||
| 138 | } | ||
| 139 | |||
| 140 | if ((file->f_flags & O_ACCMODE) == O_RDWR) { | ||
| 141 | if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) { | ||
| 142 | mutex_unlock(&dmxdev->mutex); | ||
| 143 | return -EOPNOTSUPP; | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) { | ||
| 148 | void *mem; | ||
| 149 | if (!dvbdev->readers) { | ||
| 150 | mutex_unlock(&dmxdev->mutex); | ||
| 151 | return -EBUSY; | ||
| 152 | } | ||
| 153 | mem = vmalloc(DVR_BUFFER_SIZE); | ||
| 154 | if (!mem) { | ||
| 155 | mutex_unlock(&dmxdev->mutex); | ||
| 156 | return -ENOMEM; | ||
| 157 | } | ||
| 158 | dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE); | ||
| 159 | dvbdev->readers--; | ||
| 160 | } | ||
| 161 | |||
| 162 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) { | ||
| 163 | dmxdev->dvr_orig_fe = dmxdev->demux->frontend; | ||
| 164 | |||
| 165 | if (!dmxdev->demux->write) { | ||
| 166 | mutex_unlock(&dmxdev->mutex); | ||
| 167 | return -EOPNOTSUPP; | ||
| 168 | } | ||
| 169 | |||
| 170 | front = get_fe(dmxdev->demux, DMX_MEMORY_FE); | ||
| 171 | |||
| 172 | if (!front) { | ||
| 173 | mutex_unlock(&dmxdev->mutex); | ||
| 174 | return -EINVAL; | ||
| 175 | } | ||
| 176 | dmxdev->demux->disconnect_frontend(dmxdev->demux); | ||
| 177 | dmxdev->demux->connect_frontend(dmxdev->demux, front); | ||
| 178 | } | ||
| 179 | dvbdev->users++; | ||
| 180 | mutex_unlock(&dmxdev->mutex); | ||
| 181 | return 0; | ||
| 182 | } | ||
| 183 | |||
| 184 | static int dvb_dvr_release(struct inode *inode, struct file *file) | ||
| 185 | { | ||
| 186 | struct dvb_device *dvbdev = file->private_data; | ||
| 187 | struct dmxdev *dmxdev = dvbdev->priv; | ||
| 188 | |||
| 189 | mutex_lock(&dmxdev->mutex); | ||
| 190 | |||
| 191 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) { | ||
| 192 | dmxdev->demux->disconnect_frontend(dmxdev->demux); | ||
| 193 | dmxdev->demux->connect_frontend(dmxdev->demux, | ||
| 194 | dmxdev->dvr_orig_fe); | ||
| 195 | } | ||
| 196 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) { | ||
| 197 | dvbdev->readers++; | ||
| 198 | if (dmxdev->dvr_buffer.data) { | ||
| 199 | void *mem = dmxdev->dvr_buffer.data; | ||
| 200 | mb(); | ||
| 201 | spin_lock_irq(&dmxdev->lock); | ||
| 202 | dmxdev->dvr_buffer.data = NULL; | ||
| 203 | spin_unlock_irq(&dmxdev->lock); | ||
| 204 | vfree(mem); | ||
| 205 | } | ||
| 206 | } | ||
| 207 | /* TODO */ | ||
| 208 | dvbdev->users--; | ||
| 209 | if (dvbdev->users == 1 && dmxdev->exit == 1) { | ||
| 210 | fops_put(file->f_op); | ||
| 211 | file->f_op = NULL; | ||
| 212 | mutex_unlock(&dmxdev->mutex); | ||
| 213 | wake_up(&dvbdev->wait_queue); | ||
| 214 | } else | ||
| 215 | mutex_unlock(&dmxdev->mutex); | ||
| 216 | |||
| 217 | return 0; | ||
| 218 | } | ||
| 219 | |||
| 220 | static ssize_t dvb_dvr_write(struct file *file, const char __user *buf, | ||
| 221 | size_t count, loff_t *ppos) | ||
| 222 | { | ||
| 223 | struct dvb_device *dvbdev = file->private_data; | ||
| 224 | struct dmxdev *dmxdev = dvbdev->priv; | ||
| 225 | int ret; | ||
| 226 | |||
| 227 | if (!dmxdev->demux->write) | ||
| 228 | return -EOPNOTSUPP; | ||
| 229 | if ((file->f_flags & O_ACCMODE) != O_WRONLY) | ||
| 230 | return -EINVAL; | ||
| 231 | if (mutex_lock_interruptible(&dmxdev->mutex)) | ||
| 232 | return -ERESTARTSYS; | ||
| 233 | |||
| 234 | if (dmxdev->exit) { | ||
| 235 | mutex_unlock(&dmxdev->mutex); | ||
| 236 | return -ENODEV; | ||
| 237 | } | ||
| 238 | ret = dmxdev->demux->write(dmxdev->demux, buf, count); | ||
| 239 | mutex_unlock(&dmxdev->mutex); | ||
| 240 | return ret; | ||
| 241 | } | ||
| 242 | |||
| 243 | static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count, | ||
| 244 | loff_t *ppos) | ||
| 245 | { | ||
| 246 | struct dvb_device *dvbdev = file->private_data; | ||
| 247 | struct dmxdev *dmxdev = dvbdev->priv; | ||
| 248 | |||
| 249 | if (dmxdev->exit) | ||
| 250 | return -ENODEV; | ||
| 251 | |||
| 252 | return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, | ||
| 253 | file->f_flags & O_NONBLOCK, | ||
| 254 | buf, count, ppos); | ||
| 255 | } | ||
| 256 | |||
| 257 | static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev, | ||
| 258 | unsigned long size) | ||
| 259 | { | ||
| 260 | struct dvb_ringbuffer *buf = &dmxdev->dvr_buffer; | ||
| 261 | void *newmem; | ||
| 262 | void *oldmem; | ||
| 263 | |||
| 264 | dprintk("function : %s\n", __func__); | ||
| 265 | |||
| 266 | if (buf->size == size) | ||
| 267 | return 0; | ||
| 268 | if (!size) | ||
| 269 | return -EINVAL; | ||
| 270 | |||
| 271 | newmem = vmalloc(size); | ||
| 272 | if (!newmem) | ||
| 273 | return -ENOMEM; | ||
| 274 | |||
| 275 | oldmem = buf->data; | ||
| 276 | |||
| 277 | spin_lock_irq(&dmxdev->lock); | ||
| 278 | buf->data = newmem; | ||
| 279 | buf->size = size; | ||
| 280 | |||
| 281 | /* reset and not flush in case the buffer shrinks */ | ||
| 282 | dvb_ringbuffer_reset(buf); | ||
| 283 | spin_unlock_irq(&dmxdev->lock); | ||
| 284 | |||
| 285 | vfree(oldmem); | ||
| 286 | |||
| 287 | return 0; | ||
| 288 | } | ||
| 289 | |||
| 290 | static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter | ||
| 291 | *dmxdevfilter, int state) | ||
| 292 | { | ||
| 293 | spin_lock_irq(&dmxdevfilter->dev->lock); | ||
| 294 | dmxdevfilter->state = state; | ||
| 295 | spin_unlock_irq(&dmxdevfilter->dev->lock); | ||
| 296 | } | ||
| 297 | |||
| 298 | static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, | ||
| 299 | unsigned long size) | ||
| 300 | { | ||
| 301 | struct dvb_ringbuffer *buf = &dmxdevfilter->buffer; | ||
| 302 | void *newmem; | ||
| 303 | void *oldmem; | ||
| 304 | |||
| 305 | if (buf->size == size) | ||
| 306 | return 0; | ||
| 307 | if (!size) | ||
| 308 | return -EINVAL; | ||
| 309 | if (dmxdevfilter->state >= DMXDEV_STATE_GO) | ||
| 310 | return -EBUSY; | ||
| 311 | |||
| 312 | newmem = vmalloc(size); | ||
| 313 | if (!newmem) | ||
| 314 | return -ENOMEM; | ||
| 315 | |||
| 316 | oldmem = buf->data; | ||
| 317 | |||
| 318 | spin_lock_irq(&dmxdevfilter->dev->lock); | ||
| 319 | buf->data = newmem; | ||
| 320 | buf->size = size; | ||
| 321 | |||
| 322 | /* reset and not flush in case the buffer shrinks */ | ||
| 323 | dvb_ringbuffer_reset(buf); | ||
| 324 | spin_unlock_irq(&dmxdevfilter->dev->lock); | ||
| 325 | |||
| 326 | vfree(oldmem); | ||
| 327 | |||
| 328 | return 0; | ||
| 329 | } | ||
| 330 | |||
| 331 | static void dvb_dmxdev_filter_timeout(unsigned long data) | ||
| 332 | { | ||
| 333 | struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data; | ||
| 334 | |||
| 335 | dmxdevfilter->buffer.error = -ETIMEDOUT; | ||
| 336 | spin_lock_irq(&dmxdevfilter->dev->lock); | ||
| 337 | dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT; | ||
| 338 | spin_unlock_irq(&dmxdevfilter->dev->lock); | ||
| 339 | wake_up(&dmxdevfilter->buffer.queue); | ||
| 340 | } | ||
| 341 | |||
| 342 | static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter) | ||
| 343 | { | ||
| 344 | struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec; | ||
| 345 | |||
| 346 | del_timer(&dmxdevfilter->timer); | ||
| 347 | if (para->timeout) { | ||
| 348 | dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout; | ||
| 349 | dmxdevfilter->timer.data = (unsigned long)dmxdevfilter; | ||
| 350 | dmxdevfilter->timer.expires = | ||
| 351 | jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000; | ||
| 352 | add_timer(&dmxdevfilter->timer); | ||
| 353 | } | ||
| 354 | } | ||
| 355 | |||
| 356 | static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, | ||
| 357 | const u8 *buffer2, size_t buffer2_len, | ||
| 358 | struct dmx_section_filter *filter, | ||
| 359 | enum dmx_success success) | ||
| 360 | { | ||
| 361 | struct dmxdev_filter *dmxdevfilter = filter->priv; | ||
| 362 | int ret; | ||
| 363 | |||
| 364 | if (dmxdevfilter->buffer.error) { | ||
| 365 | wake_up(&dmxdevfilter->buffer.queue); | ||
| 366 | return 0; | ||
| 367 | } | ||
| 368 | spin_lock(&dmxdevfilter->dev->lock); | ||
| 369 | if (dmxdevfilter->state != DMXDEV_STATE_GO) { | ||
| 370 | spin_unlock(&dmxdevfilter->dev->lock); | ||
| 371 | return 0; | ||
| 372 | } | ||
| 373 | del_timer(&dmxdevfilter->timer); | ||
| 374 | dprintk("dmxdev: section callback %02x %02x %02x %02x %02x %02x\n", | ||
| 375 | buffer1[0], buffer1[1], | ||
| 376 | buffer1[2], buffer1[3], buffer1[4], buffer1[5]); | ||
| 377 | ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, | ||
| 378 | buffer1_len); | ||
| 379 | if (ret == buffer1_len) { | ||
| 380 | ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, | ||
| 381 | buffer2_len); | ||
| 382 | } | ||
| 383 | if (ret < 0) { | ||
| 384 | dvb_ringbuffer_flush(&dmxdevfilter->buffer); | ||
| 385 | dmxdevfilter->buffer.error = ret; | ||
| 386 | } | ||
| 387 | if (dmxdevfilter->params.sec.flags & DMX_ONESHOT) | ||
| 388 | dmxdevfilter->state = DMXDEV_STATE_DONE; | ||
| 389 | spin_unlock(&dmxdevfilter->dev->lock); | ||
| 390 | wake_up(&dmxdevfilter->buffer.queue); | ||
| 391 | return 0; | ||
| 392 | } | ||
| 393 | |||
| 394 | static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, | ||
| 395 | const u8 *buffer2, size_t buffer2_len, | ||
| 396 | struct dmx_ts_feed *feed, | ||
| 397 | enum dmx_success success) | ||
| 398 | { | ||
| 399 | struct dmxdev_filter *dmxdevfilter = feed->priv; | ||
| 400 | struct dvb_ringbuffer *buffer; | ||
| 401 | int ret; | ||
| 402 | |||
| 403 | spin_lock(&dmxdevfilter->dev->lock); | ||
| 404 | if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) { | ||
| 405 | spin_unlock(&dmxdevfilter->dev->lock); | ||
| 406 | return 0; | ||
| 407 | } | ||
| 408 | |||
| 409 | if (dmxdevfilter->params.pes.output == DMX_OUT_TAP | ||
| 410 | || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) | ||
| 411 | buffer = &dmxdevfilter->buffer; | ||
| 412 | else | ||
| 413 | buffer = &dmxdevfilter->dev->dvr_buffer; | ||
| 414 | if (buffer->error) { | ||
| 415 | spin_unlock(&dmxdevfilter->dev->lock); | ||
| 416 | wake_up(&buffer->queue); | ||
| 417 | return 0; | ||
| 418 | } | ||
| 419 | ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len); | ||
| 420 | if (ret == buffer1_len) | ||
| 421 | ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len); | ||
| 422 | if (ret < 0) { | ||
| 423 | dvb_ringbuffer_flush(buffer); | ||
| 424 | buffer->error = ret; | ||
| 425 | } | ||
| 426 | spin_unlock(&dmxdevfilter->dev->lock); | ||
| 427 | wake_up(&buffer->queue); | ||
| 428 | return 0; | ||
| 429 | } | ||
| 430 | |||
| 431 | /* stop feed but only mark the specified filter as stopped (state set) */ | ||
| 432 | static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter) | ||
| 433 | { | ||
| 434 | struct dmxdev_feed *feed; | ||
| 435 | |||
| 436 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); | ||
| 437 | |||
| 438 | switch (dmxdevfilter->type) { | ||
| 439 | case DMXDEV_TYPE_SEC: | ||
| 440 | del_timer(&dmxdevfilter->timer); | ||
| 441 | dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec); | ||
| 442 | break; | ||
| 443 | case DMXDEV_TYPE_PES: | ||
| 444 | list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) | ||
| 445 | feed->ts->stop_filtering(feed->ts); | ||
| 446 | break; | ||
| 447 | default: | ||
| 448 | return -EINVAL; | ||
| 449 | } | ||
| 450 | return 0; | ||
| 451 | } | ||
| 452 | |||
| 453 | /* start feed associated with the specified filter */ | ||
| 454 | static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter) | ||
| 455 | { | ||
| 456 | struct dmxdev_feed *feed; | ||
| 457 | int ret; | ||
| 458 | |||
| 459 | dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO); | ||
| 460 | |||
| 461 | switch (filter->type) { | ||
| 462 | case DMXDEV_TYPE_SEC: | ||
| 463 | return filter->feed.sec->start_filtering(filter->feed.sec); | ||
| 464 | case DMXDEV_TYPE_PES: | ||
| 465 | list_for_each_entry(feed, &filter->feed.ts, next) { | ||
| 466 | ret = feed->ts->start_filtering(feed->ts); | ||
| 467 | if (ret < 0) { | ||
| 468 | dvb_dmxdev_feed_stop(filter); | ||
| 469 | return ret; | ||
| 470 | } | ||
| 471 | } | ||
| 472 | break; | ||
| 473 | default: | ||
| 474 | return -EINVAL; | ||
| 475 | } | ||
| 476 | |||
| 477 | return 0; | ||
| 478 | } | ||
| 479 | |||
| 480 | /* restart section feed if it has filters left associated with it, | ||
| 481 | otherwise release the feed */ | ||
| 482 | static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter) | ||
| 483 | { | ||
| 484 | int i; | ||
| 485 | struct dmxdev *dmxdev = filter->dev; | ||
| 486 | u16 pid = filter->params.sec.pid; | ||
| 487 | |||
| 488 | for (i = 0; i < dmxdev->filternum; i++) | ||
| 489 | if (dmxdev->filter[i].state >= DMXDEV_STATE_GO && | ||
| 490 | dmxdev->filter[i].type == DMXDEV_TYPE_SEC && | ||
| 491 | dmxdev->filter[i].params.sec.pid == pid) { | ||
| 492 | dvb_dmxdev_feed_start(&dmxdev->filter[i]); | ||
| 493 | return 0; | ||
| 494 | } | ||
| 495 | |||
| 496 | filter->dev->demux->release_section_feed(dmxdev->demux, | ||
| 497 | filter->feed.sec); | ||
| 498 | |||
| 499 | return 0; | ||
| 500 | } | ||
| 501 | |||
| 502 | static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter) | ||
| 503 | { | ||
| 504 | struct dmxdev_feed *feed; | ||
| 505 | struct dmx_demux *demux; | ||
| 506 | |||
| 507 | if (dmxdevfilter->state < DMXDEV_STATE_GO) | ||
| 508 | return 0; | ||
| 509 | |||
| 510 | switch (dmxdevfilter->type) { | ||
| 511 | case DMXDEV_TYPE_SEC: | ||
| 512 | if (!dmxdevfilter->feed.sec) | ||
| 513 | break; | ||
| 514 | dvb_dmxdev_feed_stop(dmxdevfilter); | ||
| 515 | if (dmxdevfilter->filter.sec) | ||
| 516 | dmxdevfilter->feed.sec-> | ||
| 517 | release_filter(dmxdevfilter->feed.sec, | ||
| 518 | dmxdevfilter->filter.sec); | ||
| 519 | dvb_dmxdev_feed_restart(dmxdevfilter); | ||
| 520 | dmxdevfilter->feed.sec = NULL; | ||
| 521 | break; | ||
| 522 | case DMXDEV_TYPE_PES: | ||
| 523 | dvb_dmxdev_feed_stop(dmxdevfilter); | ||
| 524 | demux = dmxdevfilter->dev->demux; | ||
| 525 | list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) { | ||
| 526 | demux->release_ts_feed(demux, feed->ts); | ||
| 527 | feed->ts = NULL; | ||
| 528 | } | ||
| 529 | break; | ||
| 530 | default: | ||
| 531 | if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED) | ||
| 532 | return 0; | ||
| 533 | return -EINVAL; | ||
| 534 | } | ||
| 535 | |||
| 536 | dvb_ringbuffer_flush(&dmxdevfilter->buffer); | ||
| 537 | return 0; | ||
| 538 | } | ||
| 539 | |||
| 540 | static void dvb_dmxdev_delete_pids(struct dmxdev_filter *dmxdevfilter) | ||
| 541 | { | ||
| 542 | struct dmxdev_feed *feed, *tmp; | ||
| 543 | |||
| 544 | /* delete all PIDs */ | ||
| 545 | list_for_each_entry_safe(feed, tmp, &dmxdevfilter->feed.ts, next) { | ||
| 546 | list_del(&feed->next); | ||
| 547 | kfree(feed); | ||
| 548 | } | ||
| 549 | |||
| 550 | BUG_ON(!list_empty(&dmxdevfilter->feed.ts)); | ||
| 551 | } | ||
| 552 | |||
| 553 | static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter) | ||
| 554 | { | ||
| 555 | if (dmxdevfilter->state < DMXDEV_STATE_SET) | ||
| 556 | return 0; | ||
| 557 | |||
| 558 | if (dmxdevfilter->type == DMXDEV_TYPE_PES) | ||
| 559 | dvb_dmxdev_delete_pids(dmxdevfilter); | ||
| 560 | |||
| 561 | dmxdevfilter->type = DMXDEV_TYPE_NONE; | ||
| 562 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); | ||
| 563 | return 0; | ||
| 564 | } | ||
| 565 | |||
| 566 | static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, | ||
| 567 | struct dmxdev_filter *filter, | ||
| 568 | struct dmxdev_feed *feed) | ||
| 569 | { | ||
| 570 | struct timespec timeout = { 0 }; | ||
| 571 | struct dmx_pes_filter_params *para = &filter->params.pes; | ||
| 572 | dmx_output_t otype; | ||
| 573 | int ret; | ||
| 574 | int ts_type; | ||
| 575 | dmx_pes_type_t ts_pes; | ||
| 576 | struct dmx_ts_feed *tsfeed; | ||
| 577 | |||
| 578 | feed->ts = NULL; | ||
| 579 | otype = para->output; | ||
| 580 | |||
| 581 | ts_pes = para->pes_type; | ||
| 582 | |||
| 583 | if (ts_pes < DMX_PES_OTHER) | ||
| 584 | ts_type = TS_DECODER; | ||
| 585 | else | ||
| 586 | ts_type = 0; | ||
| 587 | |||
| 588 | if (otype == DMX_OUT_TS_TAP) | ||
| 589 | ts_type |= TS_PACKET; | ||
| 590 | else if (otype == DMX_OUT_TSDEMUX_TAP) | ||
| 591 | ts_type |= TS_PACKET | TS_DEMUX; | ||
| 592 | else if (otype == DMX_OUT_TAP) | ||
| 593 | ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY; | ||
| 594 | |||
| 595 | ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, &feed->ts, | ||
| 596 | dvb_dmxdev_ts_callback); | ||
| 597 | if (ret < 0) | ||
| 598 | return ret; | ||
| 599 | |||
| 600 | tsfeed = feed->ts; | ||
| 601 | tsfeed->priv = filter; | ||
| 602 | |||
| 603 | ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, 32768, timeout); | ||
| 604 | if (ret < 0) { | ||
| 605 | dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); | ||
| 606 | return ret; | ||
| 607 | } | ||
| 608 | |||
| 609 | ret = tsfeed->start_filtering(tsfeed); | ||
| 610 | if (ret < 0) { | ||
| 611 | dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); | ||
| 612 | return ret; | ||
| 613 | } | ||
| 614 | |||
| 615 | return 0; | ||
| 616 | } | ||
| 617 | |||
| 618 | static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) | ||
| 619 | { | ||
| 620 | struct dmxdev *dmxdev = filter->dev; | ||
| 621 | struct dmxdev_feed *feed; | ||
| 622 | void *mem; | ||
| 623 | int ret, i; | ||
| 624 | |||
| 625 | if (filter->state < DMXDEV_STATE_SET) | ||
| 626 | return -EINVAL; | ||
| 627 | |||
| 628 | if (filter->state >= DMXDEV_STATE_GO) | ||
| 629 | dvb_dmxdev_filter_stop(filter); | ||
| 630 | |||
| 631 | if (!filter->buffer.data) { | ||
| 632 | mem = vmalloc(filter->buffer.size); | ||
| 633 | if (!mem) | ||
| 634 | return -ENOMEM; | ||
| 635 | spin_lock_irq(&filter->dev->lock); | ||
| 636 | filter->buffer.data = mem; | ||
| 637 | spin_unlock_irq(&filter->dev->lock); | ||
| 638 | } | ||
| 639 | |||
| 640 | dvb_ringbuffer_flush(&filter->buffer); | ||
| 641 | |||
| 642 | switch (filter->type) { | ||
| 643 | case DMXDEV_TYPE_SEC: | ||
| 644 | { | ||
| 645 | struct dmx_sct_filter_params *para = &filter->params.sec; | ||
| 646 | struct dmx_section_filter **secfilter = &filter->filter.sec; | ||
| 647 | struct dmx_section_feed **secfeed = &filter->feed.sec; | ||
| 648 | |||
| 649 | *secfilter = NULL; | ||
| 650 | *secfeed = NULL; | ||
| 651 | |||
| 652 | |||
| 653 | /* find active filter/feed with same PID */ | ||
| 654 | for (i = 0; i < dmxdev->filternum; i++) { | ||
| 655 | if (dmxdev->filter[i].state >= DMXDEV_STATE_GO && | ||
| 656 | dmxdev->filter[i].type == DMXDEV_TYPE_SEC && | ||
| 657 | dmxdev->filter[i].params.sec.pid == para->pid) { | ||
| 658 | *secfeed = dmxdev->filter[i].feed.sec; | ||
| 659 | break; | ||
| 660 | } | ||
| 661 | } | ||
| 662 | |||
| 663 | /* if no feed found, try to allocate new one */ | ||
| 664 | if (!*secfeed) { | ||
| 665 | ret = dmxdev->demux->allocate_section_feed(dmxdev->demux, | ||
| 666 | secfeed, | ||
| 667 | dvb_dmxdev_section_callback); | ||
| 668 | if (ret < 0) { | ||
| 669 | printk("DVB (%s): could not alloc feed\n", | ||
| 670 | __func__); | ||
| 671 | return ret; | ||
| 672 | } | ||
| 673 | |||
| 674 | ret = (*secfeed)->set(*secfeed, para->pid, 32768, | ||
| 675 | (para->flags & DMX_CHECK_CRC) ? 1 : 0); | ||
| 676 | if (ret < 0) { | ||
| 677 | printk("DVB (%s): could not set feed\n", | ||
| 678 | __func__); | ||
| 679 | dvb_dmxdev_feed_restart(filter); | ||
| 680 | return ret; | ||
| 681 | } | ||
| 682 | } else { | ||
| 683 | dvb_dmxdev_feed_stop(filter); | ||
| 684 | } | ||
| 685 | |||
| 686 | ret = (*secfeed)->allocate_filter(*secfeed, secfilter); | ||
| 687 | if (ret < 0) { | ||
| 688 | dvb_dmxdev_feed_restart(filter); | ||
| 689 | filter->feed.sec->start_filtering(*secfeed); | ||
| 690 | dprintk("could not get filter\n"); | ||
| 691 | return ret; | ||
| 692 | } | ||
| 693 | |||
| 694 | (*secfilter)->priv = filter; | ||
| 695 | |||
| 696 | memcpy(&((*secfilter)->filter_value[3]), | ||
| 697 | &(para->filter.filter[1]), DMX_FILTER_SIZE - 1); | ||
| 698 | memcpy(&(*secfilter)->filter_mask[3], | ||
| 699 | ¶->filter.mask[1], DMX_FILTER_SIZE - 1); | ||
| 700 | memcpy(&(*secfilter)->filter_mode[3], | ||
| 701 | ¶->filter.mode[1], DMX_FILTER_SIZE - 1); | ||
| 702 | |||
| 703 | (*secfilter)->filter_value[0] = para->filter.filter[0]; | ||
| 704 | (*secfilter)->filter_mask[0] = para->filter.mask[0]; | ||
| 705 | (*secfilter)->filter_mode[0] = para->filter.mode[0]; | ||
| 706 | (*secfilter)->filter_mask[1] = 0; | ||
| 707 | (*secfilter)->filter_mask[2] = 0; | ||
| 708 | |||
| 709 | filter->todo = 0; | ||
| 710 | |||
| 711 | ret = filter->feed.sec->start_filtering(filter->feed.sec); | ||
| 712 | if (ret < 0) | ||
| 713 | return ret; | ||
| 714 | |||
| 715 | dvb_dmxdev_filter_timer(filter); | ||
| 716 | break; | ||
| 717 | } | ||
| 718 | case DMXDEV_TYPE_PES: | ||
| 719 | list_for_each_entry(feed, &filter->feed.ts, next) { | ||
| 720 | ret = dvb_dmxdev_start_feed(dmxdev, filter, feed); | ||
| 721 | if (ret < 0) { | ||
| 722 | dvb_dmxdev_filter_stop(filter); | ||
| 723 | return ret; | ||
| 724 | } | ||
| 725 | } | ||
| 726 | break; | ||
| 727 | default: | ||
| 728 | return -EINVAL; | ||
| 729 | } | ||
| 730 | |||
| 731 | dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO); | ||
| 732 | return 0; | ||
| 733 | } | ||
| 734 | |||
| 735 | static int dvb_demux_open(struct inode *inode, struct file *file) | ||
| 736 | { | ||
| 737 | struct dvb_device *dvbdev = file->private_data; | ||
| 738 | struct dmxdev *dmxdev = dvbdev->priv; | ||
| 739 | int i; | ||
| 740 | struct dmxdev_filter *dmxdevfilter; | ||
| 741 | |||
| 742 | if (!dmxdev->filter) | ||
| 743 | return -EINVAL; | ||
| 744 | |||
| 745 | if (mutex_lock_interruptible(&dmxdev->mutex)) | ||
| 746 | return -ERESTARTSYS; | ||
| 747 | |||
| 748 | for (i = 0; i < dmxdev->filternum; i++) | ||
| 749 | if (dmxdev->filter[i].state == DMXDEV_STATE_FREE) | ||
| 750 | break; | ||
| 751 | |||
| 752 | if (i == dmxdev->filternum) { | ||
| 753 | mutex_unlock(&dmxdev->mutex); | ||
| 754 | return -EMFILE; | ||
| 755 | } | ||
| 756 | |||
| 757 | dmxdevfilter = &dmxdev->filter[i]; | ||
| 758 | mutex_init(&dmxdevfilter->mutex); | ||
| 759 | file->private_data = dmxdevfilter; | ||
| 760 | |||
| 761 | dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192); | ||
| 762 | dmxdevfilter->type = DMXDEV_TYPE_NONE; | ||
| 763 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); | ||
| 764 | init_timer(&dmxdevfilter->timer); | ||
| 765 | |||
| 766 | dvbdev->users++; | ||
| 767 | |||
| 768 | mutex_unlock(&dmxdev->mutex); | ||
| 769 | return 0; | ||
| 770 | } | ||
| 771 | |||
| 772 | static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, | ||
| 773 | struct dmxdev_filter *dmxdevfilter) | ||
| 774 | { | ||
| 775 | mutex_lock(&dmxdev->mutex); | ||
| 776 | mutex_lock(&dmxdevfilter->mutex); | ||
| 777 | |||
| 778 | dvb_dmxdev_filter_stop(dmxdevfilter); | ||
| 779 | dvb_dmxdev_filter_reset(dmxdevfilter); | ||
| 780 | |||
| 781 | if (dmxdevfilter->buffer.data) { | ||
| 782 | void *mem = dmxdevfilter->buffer.data; | ||
| 783 | |||
| 784 | spin_lock_irq(&dmxdev->lock); | ||
| 785 | dmxdevfilter->buffer.data = NULL; | ||
| 786 | spin_unlock_irq(&dmxdev->lock); | ||
| 787 | vfree(mem); | ||
| 788 | } | ||
| 789 | |||
| 790 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE); | ||
| 791 | wake_up(&dmxdevfilter->buffer.queue); | ||
| 792 | mutex_unlock(&dmxdevfilter->mutex); | ||
| 793 | mutex_unlock(&dmxdev->mutex); | ||
| 794 | return 0; | ||
| 795 | } | ||
| 796 | |||
| 797 | static inline void invert_mode(dmx_filter_t *filter) | ||
| 798 | { | ||
| 799 | int i; | ||
| 800 | |||
| 801 | for (i = 0; i < DMX_FILTER_SIZE; i++) | ||
| 802 | filter->mode[i] ^= 0xff; | ||
| 803 | } | ||
| 804 | |||
| 805 | static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev, | ||
| 806 | struct dmxdev_filter *filter, u16 pid) | ||
| 807 | { | ||
| 808 | struct dmxdev_feed *feed; | ||
| 809 | |||
| 810 | if ((filter->type != DMXDEV_TYPE_PES) || | ||
| 811 | (filter->state < DMXDEV_STATE_SET)) | ||
| 812 | return -EINVAL; | ||
| 813 | |||
| 814 | /* only TS packet filters may have multiple PIDs */ | ||
| 815 | if ((filter->params.pes.output != DMX_OUT_TSDEMUX_TAP) && | ||
| 816 | (!list_empty(&filter->feed.ts))) | ||
| 817 | return -EINVAL; | ||
| 818 | |||
| 819 | feed = kzalloc(sizeof(struct dmxdev_feed), GFP_KERNEL); | ||
| 820 | if (feed == NULL) | ||
| 821 | return -ENOMEM; | ||
| 822 | |||
| 823 | feed->pid = pid; | ||
| 824 | list_add(&feed->next, &filter->feed.ts); | ||
| 825 | |||
| 826 | if (filter->state >= DMXDEV_STATE_GO) | ||
| 827 | return dvb_dmxdev_start_feed(dmxdev, filter, feed); | ||
| 828 | |||
| 829 | return 0; | ||
| 830 | } | ||
| 831 | |||
| 832 | static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev, | ||
| 833 | struct dmxdev_filter *filter, u16 pid) | ||
| 834 | { | ||
| 835 | struct dmxdev_feed *feed, *tmp; | ||
| 836 | |||
| 837 | if ((filter->type != DMXDEV_TYPE_PES) || | ||
| 838 | (filter->state < DMXDEV_STATE_SET)) | ||
| 839 | return -EINVAL; | ||
| 840 | |||
| 841 | list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) { | ||
| 842 | if ((feed->pid == pid) && (feed->ts != NULL)) { | ||
| 843 | feed->ts->stop_filtering(feed->ts); | ||
| 844 | filter->dev->demux->release_ts_feed(filter->dev->demux, | ||
| 845 | feed->ts); | ||
| 846 | list_del(&feed->next); | ||
| 847 | kfree(feed); | ||
| 848 | } | ||
| 849 | } | ||
| 850 | |||
| 851 | return 0; | ||
| 852 | } | ||
| 853 | |||
| 854 | static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev, | ||
| 855 | struct dmxdev_filter *dmxdevfilter, | ||
| 856 | struct dmx_sct_filter_params *params) | ||
| 857 | { | ||
| 858 | dprintk("function : %s\n", __func__); | ||
| 859 | |||
| 860 | dvb_dmxdev_filter_stop(dmxdevfilter); | ||
| 861 | |||
| 862 | dmxdevfilter->type = DMXDEV_TYPE_SEC; | ||
| 863 | memcpy(&dmxdevfilter->params.sec, | ||
| 864 | params, sizeof(struct dmx_sct_filter_params)); | ||
| 865 | invert_mode(&dmxdevfilter->params.sec.filter); | ||
| 866 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); | ||
| 867 | |||
| 868 | if (params->flags & DMX_IMMEDIATE_START) | ||
| 869 | return dvb_dmxdev_filter_start(dmxdevfilter); | ||
| 870 | |||
| 871 | return 0; | ||
| 872 | } | ||
| 873 | |||
| 874 | static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev, | ||
| 875 | struct dmxdev_filter *dmxdevfilter, | ||
| 876 | struct dmx_pes_filter_params *params) | ||
| 877 | { | ||
| 878 | int ret; | ||
| 879 | |||
| 880 | dvb_dmxdev_filter_stop(dmxdevfilter); | ||
| 881 | dvb_dmxdev_filter_reset(dmxdevfilter); | ||
| 882 | |||
| 883 | if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0) | ||
| 884 | return -EINVAL; | ||
| 885 | |||
| 886 | dmxdevfilter->type = DMXDEV_TYPE_PES; | ||
| 887 | memcpy(&dmxdevfilter->params, params, | ||
| 888 | sizeof(struct dmx_pes_filter_params)); | ||
| 889 | INIT_LIST_HEAD(&dmxdevfilter->feed.ts); | ||
| 890 | |||
| 891 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); | ||
| 892 | |||
| 893 | ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, | ||
| 894 | dmxdevfilter->params.pes.pid); | ||
| 895 | if (ret < 0) | ||
| 896 | return ret; | ||
| 897 | |||
| 898 | if (params->flags & DMX_IMMEDIATE_START) | ||
| 899 | return dvb_dmxdev_filter_start(dmxdevfilter); | ||
| 900 | |||
| 901 | return 0; | ||
| 902 | } | ||
| 903 | |||
| 904 | static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil, | ||
| 905 | struct file *file, char __user *buf, | ||
| 906 | size_t count, loff_t *ppos) | ||
| 907 | { | ||
| 908 | int result, hcount; | ||
| 909 | int done = 0; | ||
| 910 | |||
| 911 | if (dfil->todo <= 0) { | ||
| 912 | hcount = 3 + dfil->todo; | ||
| 913 | if (hcount > count) | ||
| 914 | hcount = count; | ||
| 915 | result = dvb_dmxdev_buffer_read(&dfil->buffer, | ||
| 916 | file->f_flags & O_NONBLOCK, | ||
| 917 | buf, hcount, ppos); | ||
| 918 | if (result < 0) { | ||
| 919 | dfil->todo = 0; | ||
| 920 | return result; | ||
| 921 | } | ||
| 922 | if (copy_from_user(dfil->secheader - dfil->todo, buf, result)) | ||
| 923 | return -EFAULT; | ||
| 924 | buf += result; | ||
| 925 | done = result; | ||
| 926 | count -= result; | ||
| 927 | dfil->todo -= result; | ||
| 928 | if (dfil->todo > -3) | ||
| 929 | return done; | ||
| 930 | dfil->todo = ((dfil->secheader[1] << 8) | dfil->secheader[2]) & 0xfff; | ||
| 931 | if (!count) | ||
| 932 | return done; | ||
| 933 | } | ||
| 934 | if (count > dfil->todo) | ||
| 935 | count = dfil->todo; | ||
| 936 | result = dvb_dmxdev_buffer_read(&dfil->buffer, | ||
| 937 | file->f_flags & O_NONBLOCK, | ||
| 938 | buf, count, ppos); | ||
| 939 | if (result < 0) | ||
| 940 | return result; | ||
| 941 | dfil->todo -= result; | ||
| 942 | return (result + done); | ||
| 943 | } | ||
| 944 | |||
| 945 | static ssize_t | ||
| 946 | dvb_demux_read(struct file *file, char __user *buf, size_t count, | ||
| 947 | loff_t *ppos) | ||
| 948 | { | ||
| 949 | struct dmxdev_filter *dmxdevfilter = file->private_data; | ||
| 950 | int ret; | ||
| 951 | |||
| 952 | if (mutex_lock_interruptible(&dmxdevfilter->mutex)) | ||
| 953 | return -ERESTARTSYS; | ||
| 954 | |||
| 955 | if (dmxdevfilter->type == DMXDEV_TYPE_SEC) | ||
| 956 | ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos); | ||
| 957 | else | ||
| 958 | ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer, | ||
| 959 | file->f_flags & O_NONBLOCK, | ||
| 960 | buf, count, ppos); | ||
| 961 | |||
| 962 | mutex_unlock(&dmxdevfilter->mutex); | ||
| 963 | return ret; | ||
| 964 | } | ||
| 965 | |||
| 966 | static int dvb_demux_do_ioctl(struct file *file, | ||
| 967 | unsigned int cmd, void *parg) | ||
| 968 | { | ||
| 969 | struct dmxdev_filter *dmxdevfilter = file->private_data; | ||
| 970 | struct dmxdev *dmxdev = dmxdevfilter->dev; | ||
| 971 | unsigned long arg = (unsigned long)parg; | ||
| 972 | int ret = 0; | ||
| 973 | |||
| 974 | if (mutex_lock_interruptible(&dmxdev->mutex)) | ||
| 975 | return -ERESTARTSYS; | ||
| 976 | |||
| 977 | switch (cmd) { | ||
| 978 | case DMX_START: | ||
| 979 | if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { | ||
| 980 | mutex_unlock(&dmxdev->mutex); | ||
| 981 | return -ERESTARTSYS; | ||
| 982 | } | ||
| 983 | if (dmxdevfilter->state < DMXDEV_STATE_SET) | ||
| 984 | ret = -EINVAL; | ||
| 985 | else | ||
| 986 | ret = dvb_dmxdev_filter_start(dmxdevfilter); | ||
| 987 | mutex_unlock(&dmxdevfilter->mutex); | ||
| 988 | break; | ||
| 989 | |||
| 990 | case DMX_STOP: | ||
| 991 | if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { | ||
| 992 | mutex_unlock(&dmxdev->mutex); | ||
| 993 | return -ERESTARTSYS; | ||
| 994 | } | ||
| 995 | ret = dvb_dmxdev_filter_stop(dmxdevfilter); | ||
| 996 | mutex_unlock(&dmxdevfilter->mutex); | ||
| 997 | break; | ||
| 998 | |||
| 999 | case DMX_SET_FILTER: | ||
| 1000 | if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { | ||
| 1001 | mutex_unlock(&dmxdev->mutex); | ||
| 1002 | return -ERESTARTSYS; | ||
| 1003 | } | ||
| 1004 | ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg); | ||
| 1005 | mutex_unlock(&dmxdevfilter->mutex); | ||
| 1006 | break; | ||
| 1007 | |||
| 1008 | case DMX_SET_PES_FILTER: | ||
| 1009 | if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { | ||
| 1010 | mutex_unlock(&dmxdev->mutex); | ||
| 1011 | return -ERESTARTSYS; | ||
| 1012 | } | ||
| 1013 | ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg); | ||
| 1014 | mutex_unlock(&dmxdevfilter->mutex); | ||
| 1015 | break; | ||
| 1016 | |||
| 1017 | case DMX_SET_BUFFER_SIZE: | ||
| 1018 | if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { | ||
| 1019 | mutex_unlock(&dmxdev->mutex); | ||
| 1020 | return -ERESTARTSYS; | ||
| 1021 | } | ||
| 1022 | ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg); | ||
| 1023 | mutex_unlock(&dmxdevfilter->mutex); | ||
| 1024 | break; | ||
| 1025 | |||
| 1026 | case DMX_GET_PES_PIDS: | ||
| 1027 | if (!dmxdev->demux->get_pes_pids) { | ||
| 1028 | ret = -EINVAL; | ||
| 1029 | break; | ||
| 1030 | } | ||
| 1031 | dmxdev->demux->get_pes_pids(dmxdev->demux, parg); | ||
| 1032 | break; | ||
| 1033 | |||
| 1034 | case DMX_GET_CAPS: | ||
| 1035 | if (!dmxdev->demux->get_caps) { | ||
| 1036 | ret = -EINVAL; | ||
| 1037 | break; | ||
| 1038 | } | ||
| 1039 | ret = dmxdev->demux->get_caps(dmxdev->demux, parg); | ||
| 1040 | break; | ||
| 1041 | |||
| 1042 | case DMX_SET_SOURCE: | ||
| 1043 | if (!dmxdev->demux->set_source) { | ||
| 1044 | ret = -EINVAL; | ||
| 1045 | break; | ||
| 1046 | } | ||
| 1047 | ret = dmxdev->demux->set_source(dmxdev->demux, parg); | ||
| 1048 | break; | ||
| 1049 | |||
| 1050 | case DMX_GET_STC: | ||
| 1051 | if (!dmxdev->demux->get_stc) { | ||
| 1052 | ret = -EINVAL; | ||
| 1053 | break; | ||
| 1054 | } | ||
| 1055 | ret = dmxdev->demux->get_stc(dmxdev->demux, | ||
| 1056 | ((struct dmx_stc *)parg)->num, | ||
| 1057 | &((struct dmx_stc *)parg)->stc, | ||
| 1058 | &((struct dmx_stc *)parg)->base); | ||
| 1059 | break; | ||
| 1060 | |||
| 1061 | case DMX_ADD_PID: | ||
| 1062 | if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { | ||
| 1063 | ret = -ERESTARTSYS; | ||
| 1064 | break; | ||
| 1065 | } | ||
| 1066 | ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, *(u16 *)parg); | ||
| 1067 | mutex_unlock(&dmxdevfilter->mutex); | ||
| 1068 | break; | ||
| 1069 | |||
| 1070 | case DMX_REMOVE_PID: | ||
| 1071 | if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { | ||
| 1072 | ret = -ERESTARTSYS; | ||
| 1073 | break; | ||
| 1074 | } | ||
| 1075 | ret = dvb_dmxdev_remove_pid(dmxdev, dmxdevfilter, *(u16 *)parg); | ||
| 1076 | mutex_unlock(&dmxdevfilter->mutex); | ||
| 1077 | break; | ||
| 1078 | |||
| 1079 | default: | ||
| 1080 | ret = -EINVAL; | ||
| 1081 | break; | ||
| 1082 | } | ||
| 1083 | mutex_unlock(&dmxdev->mutex); | ||
| 1084 | return ret; | ||
| 1085 | } | ||
| 1086 | |||
| 1087 | static long dvb_demux_ioctl(struct file *file, unsigned int cmd, | ||
| 1088 | unsigned long arg) | ||
| 1089 | { | ||
| 1090 | return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl); | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | static unsigned int dvb_demux_poll(struct file *file, poll_table *wait) | ||
| 1094 | { | ||
| 1095 | struct dmxdev_filter *dmxdevfilter = file->private_data; | ||
| 1096 | unsigned int mask = 0; | ||
| 1097 | |||
| 1098 | if (!dmxdevfilter) | ||
| 1099 | return -EINVAL; | ||
| 1100 | |||
| 1101 | poll_wait(file, &dmxdevfilter->buffer.queue, wait); | ||
| 1102 | |||
| 1103 | if (dmxdevfilter->state != DMXDEV_STATE_GO && | ||
| 1104 | dmxdevfilter->state != DMXDEV_STATE_DONE && | ||
| 1105 | dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT) | ||
| 1106 | return 0; | ||
| 1107 | |||
| 1108 | if (dmxdevfilter->buffer.error) | ||
| 1109 | mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); | ||
| 1110 | |||
| 1111 | if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer)) | ||
| 1112 | mask |= (POLLIN | POLLRDNORM | POLLPRI); | ||
| 1113 | |||
| 1114 | return mask; | ||
| 1115 | } | ||
| 1116 | |||
| 1117 | static int dvb_demux_release(struct inode *inode, struct file *file) | ||
| 1118 | { | ||
| 1119 | struct dmxdev_filter *dmxdevfilter = file->private_data; | ||
| 1120 | struct dmxdev *dmxdev = dmxdevfilter->dev; | ||
| 1121 | |||
| 1122 | int ret; | ||
| 1123 | |||
| 1124 | ret = dvb_dmxdev_filter_free(dmxdev, dmxdevfilter); | ||
| 1125 | |||
| 1126 | mutex_lock(&dmxdev->mutex); | ||
| 1127 | dmxdev->dvbdev->users--; | ||
| 1128 | if(dmxdev->dvbdev->users==1 && dmxdev->exit==1) { | ||
| 1129 | fops_put(file->f_op); | ||
| 1130 | file->f_op = NULL; | ||
| 1131 | mutex_unlock(&dmxdev->mutex); | ||
| 1132 | wake_up(&dmxdev->dvbdev->wait_queue); | ||
| 1133 | } else | ||
| 1134 | mutex_unlock(&dmxdev->mutex); | ||
| 1135 | |||
| 1136 | return ret; | ||
| 1137 | } | ||
| 1138 | |||
| 1139 | static const struct file_operations dvb_demux_fops = { | ||
| 1140 | .owner = THIS_MODULE, | ||
| 1141 | .read = dvb_demux_read, | ||
| 1142 | .unlocked_ioctl = dvb_demux_ioctl, | ||
| 1143 | .open = dvb_demux_open, | ||
| 1144 | .release = dvb_demux_release, | ||
| 1145 | .poll = dvb_demux_poll, | ||
| 1146 | .llseek = default_llseek, | ||
| 1147 | }; | ||
| 1148 | |||
| 1149 | static struct dvb_device dvbdev_demux = { | ||
| 1150 | .priv = NULL, | ||
| 1151 | .users = 1, | ||
| 1152 | .writers = 1, | ||
| 1153 | .fops = &dvb_demux_fops | ||
| 1154 | }; | ||
| 1155 | |||
| 1156 | static int dvb_dvr_do_ioctl(struct file *file, | ||
| 1157 | unsigned int cmd, void *parg) | ||
| 1158 | { | ||
| 1159 | struct dvb_device *dvbdev = file->private_data; | ||
| 1160 | struct dmxdev *dmxdev = dvbdev->priv; | ||
| 1161 | unsigned long arg = (unsigned long)parg; | ||
| 1162 | int ret; | ||
| 1163 | |||
| 1164 | if (mutex_lock_interruptible(&dmxdev->mutex)) | ||
| 1165 | return -ERESTARTSYS; | ||
| 1166 | |||
| 1167 | switch (cmd) { | ||
| 1168 | case DMX_SET_BUFFER_SIZE: | ||
| 1169 | ret = dvb_dvr_set_buffer_size(dmxdev, arg); | ||
| 1170 | break; | ||
| 1171 | |||
| 1172 | default: | ||
| 1173 | ret = -EINVAL; | ||
| 1174 | break; | ||
| 1175 | } | ||
| 1176 | mutex_unlock(&dmxdev->mutex); | ||
| 1177 | return ret; | ||
| 1178 | } | ||
| 1179 | |||
| 1180 | static long dvb_dvr_ioctl(struct file *file, | ||
| 1181 | unsigned int cmd, unsigned long arg) | ||
| 1182 | { | ||
| 1183 | return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl); | ||
| 1184 | } | ||
| 1185 | |||
| 1186 | static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait) | ||
| 1187 | { | ||
| 1188 | struct dvb_device *dvbdev = file->private_data; | ||
| 1189 | struct dmxdev *dmxdev = dvbdev->priv; | ||
| 1190 | unsigned int mask = 0; | ||
| 1191 | |||
| 1192 | dprintk("function : %s\n", __func__); | ||
| 1193 | |||
| 1194 | poll_wait(file, &dmxdev->dvr_buffer.queue, wait); | ||
| 1195 | |||
| 1196 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) { | ||
| 1197 | if (dmxdev->dvr_buffer.error) | ||
| 1198 | mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); | ||
| 1199 | |||
| 1200 | if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer)) | ||
| 1201 | mask |= (POLLIN | POLLRDNORM | POLLPRI); | ||
| 1202 | } else | ||
| 1203 | mask |= (POLLOUT | POLLWRNORM | POLLPRI); | ||
| 1204 | |||
| 1205 | return mask; | ||
| 1206 | } | ||
| 1207 | |||
| 1208 | static const struct file_operations dvb_dvr_fops = { | ||
| 1209 | .owner = THIS_MODULE, | ||
| 1210 | .read = dvb_dvr_read, | ||
| 1211 | .write = dvb_dvr_write, | ||
| 1212 | .unlocked_ioctl = dvb_dvr_ioctl, | ||
| 1213 | .open = dvb_dvr_open, | ||
| 1214 | .release = dvb_dvr_release, | ||
| 1215 | .poll = dvb_dvr_poll, | ||
| 1216 | .llseek = default_llseek, | ||
| 1217 | }; | ||
| 1218 | |||
| 1219 | static struct dvb_device dvbdev_dvr = { | ||
| 1220 | .priv = NULL, | ||
| 1221 | .readers = 1, | ||
| 1222 | .users = 1, | ||
| 1223 | .fops = &dvb_dvr_fops | ||
| 1224 | }; | ||
| 1225 | |||
| 1226 | int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) | ||
| 1227 | { | ||
| 1228 | int i; | ||
| 1229 | |||
| 1230 | if (dmxdev->demux->open(dmxdev->demux) < 0) | ||
| 1231 | return -EUSERS; | ||
| 1232 | |||
| 1233 | dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter)); | ||
| 1234 | if (!dmxdev->filter) | ||
| 1235 | return -ENOMEM; | ||
| 1236 | |||
| 1237 | mutex_init(&dmxdev->mutex); | ||
| 1238 | spin_lock_init(&dmxdev->lock); | ||
| 1239 | for (i = 0; i < dmxdev->filternum; i++) { | ||
| 1240 | dmxdev->filter[i].dev = dmxdev; | ||
| 1241 | dmxdev->filter[i].buffer.data = NULL; | ||
| 1242 | dvb_dmxdev_filter_state_set(&dmxdev->filter[i], | ||
| 1243 | DMXDEV_STATE_FREE); | ||
| 1244 | } | ||
| 1245 | |||
| 1246 | dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev, | ||
| 1247 | DVB_DEVICE_DEMUX); | ||
| 1248 | dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr, | ||
| 1249 | dmxdev, DVB_DEVICE_DVR); | ||
| 1250 | |||
| 1251 | dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192); | ||
| 1252 | |||
| 1253 | return 0; | ||
| 1254 | } | ||
| 1255 | |||
| 1256 | EXPORT_SYMBOL(dvb_dmxdev_init); | ||
| 1257 | |||
| 1258 | void dvb_dmxdev_release(struct dmxdev *dmxdev) | ||
| 1259 | { | ||
| 1260 | dmxdev->exit=1; | ||
| 1261 | if (dmxdev->dvbdev->users > 1) { | ||
| 1262 | wait_event(dmxdev->dvbdev->wait_queue, | ||
| 1263 | dmxdev->dvbdev->users==1); | ||
| 1264 | } | ||
| 1265 | if (dmxdev->dvr_dvbdev->users > 1) { | ||
| 1266 | wait_event(dmxdev->dvr_dvbdev->wait_queue, | ||
| 1267 | dmxdev->dvr_dvbdev->users==1); | ||
| 1268 | } | ||
| 1269 | |||
| 1270 | dvb_unregister_device(dmxdev->dvbdev); | ||
| 1271 | dvb_unregister_device(dmxdev->dvr_dvbdev); | ||
| 1272 | |||
| 1273 | vfree(dmxdev->filter); | ||
| 1274 | dmxdev->filter = NULL; | ||
| 1275 | dmxdev->demux->close(dmxdev->demux); | ||
| 1276 | } | ||
| 1277 | |||
| 1278 | EXPORT_SYMBOL(dvb_dmxdev_release); | ||
diff --git a/drivers/media/dvb/dvb-core/dmxdev.h b/drivers/media/dvb/dvb-core/dmxdev.h new file mode 100644 index 00000000000..02ebe28f830 --- /dev/null +++ b/drivers/media/dvb/dvb-core/dmxdev.h | |||
| @@ -0,0 +1,118 @@ | |||
| 1 | /* | ||
| 2 | * dmxdev.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2000 Ralph Metzler & Marcus Metzler | ||
| 5 | * for convergence integrated media GmbH | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU Lesser General Public License | ||
| 9 | * as published by the Free Software Foundation; either version 2.1 | ||
| 10 | * of the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #ifndef _DMXDEV_H_ | ||
| 24 | #define _DMXDEV_H_ | ||
| 25 | |||
| 26 | #include <linux/types.h> | ||
| 27 | #include <linux/spinlock.h> | ||
| 28 | #include <linux/kernel.h> | ||
| 29 | #include <linux/timer.h> | ||
| 30 | #include <linux/wait.h> | ||
| 31 | #include <linux/fs.h> | ||
| 32 | #include <linux/string.h> | ||
| 33 | #include <linux/mutex.h> | ||
| 34 | #include <linux/slab.h> | ||
| 35 | |||
| 36 | #include <linux/dvb/dmx.h> | ||
| 37 | |||
| 38 | #include "dvbdev.h" | ||
| 39 | #include "demux.h" | ||
| 40 | #include "dvb_ringbuffer.h" | ||
| 41 | |||
| 42 | enum dmxdev_type { | ||
| 43 | DMXDEV_TYPE_NONE, | ||
| 44 | DMXDEV_TYPE_SEC, | ||
| 45 | DMXDEV_TYPE_PES, | ||
| 46 | }; | ||
| 47 | |||
| 48 | enum dmxdev_state { | ||
| 49 | DMXDEV_STATE_FREE, | ||
| 50 | DMXDEV_STATE_ALLOCATED, | ||
| 51 | DMXDEV_STATE_SET, | ||
| 52 | DMXDEV_STATE_GO, | ||
| 53 | DMXDEV_STATE_DONE, | ||
| 54 | DMXDEV_STATE_TIMEDOUT | ||
| 55 | }; | ||
| 56 | |||
| 57 | struct dmxdev_feed { | ||
| 58 | u16 pid; | ||
| 59 | struct dmx_ts_feed *ts; | ||
| 60 | struct list_head next; | ||
| 61 | }; | ||
| 62 | |||
| 63 | struct dmxdev_filter { | ||
| 64 | union { | ||
| 65 | struct dmx_section_filter *sec; | ||
| 66 | } filter; | ||
| 67 | |||
| 68 | union { | ||
| 69 | /* list of TS and PES feeds (struct dmxdev_feed) */ | ||
| 70 | struct list_head ts; | ||
| 71 | struct dmx_section_feed *sec; | ||
| 72 | } feed; | ||
| 73 | |||
| 74 | union { | ||
| 75 | struct dmx_sct_filter_params sec; | ||
| 76 | struct dmx_pes_filter_params pes; | ||
| 77 | } params; | ||
| 78 | |||
| 79 | enum dmxdev_type type; | ||
| 80 | enum dmxdev_state state; | ||
| 81 | struct dmxdev *dev; | ||
| 82 | struct dvb_ringbuffer buffer; | ||
| 83 | |||
| 84 | struct mutex mutex; | ||
| 85 | |||
| 86 | /* only for sections */ | ||
| 87 | struct timer_list timer; | ||
| 88 | int todo; | ||
| 89 | u8 secheader[3]; | ||
| 90 | }; | ||
| 91 | |||
| 92 | |||
| 93 | struct dmxdev { | ||
| 94 | struct dvb_device *dvbdev; | ||
| 95 | struct dvb_device *dvr_dvbdev; | ||
| 96 | |||
| 97 | struct dmxdev_filter *filter; | ||
| 98 | struct dmx_demux *demux; | ||
| 99 | |||
| 100 | int filternum; | ||
| 101 | int capabilities; | ||
| 102 | |||
| 103 | unsigned int exit:1; | ||
| 104 | #define DMXDEV_CAP_DUPLEX 1 | ||
| 105 | struct dmx_frontend *dvr_orig_fe; | ||
| 106 | |||
| 107 | struct dvb_ringbuffer dvr_buffer; | ||
| 108 | #define DVR_BUFFER_SIZE (10*188*1024) | ||
| 109 | |||
| 110 | struct mutex mutex; | ||
| 111 | spinlock_t lock; | ||
| 112 | }; | ||
| 113 | |||
| 114 | |||
| 115 | int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *); | ||
| 116 | void dvb_dmxdev_release(struct dmxdev *dmxdev); | ||
| 117 | |||
| 118 | #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 new file mode 100644 index 00000000000..7ea517b7e18 --- /dev/null +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c | |||
| @@ -0,0 +1,1749 @@ | |||
| 1 | /* | ||
| 2 | * dvb_ca.c: generic DVB functions for EN50221 CAM interfaces | ||
| 3 | * | ||
| 4 | * Copyright (C) 2004 Andrew de Quincey | ||
| 5 | * | ||
| 6 | * Parts of this file were based on sources as follows: | ||
| 7 | * | ||
| 8 | * Copyright (C) 2003 Ralph Metzler <rjkm@metzlerbros.de> | ||
| 9 | * | ||
| 10 | * based on code: | ||
| 11 | * | ||
| 12 | * Copyright (C) 1999-2002 Ralph Metzler | ||
| 13 | * & Marcus Metzler for convergence integrated media GmbH | ||
| 14 | * | ||
| 15 | * This program is free software; you can redistribute it and/or | ||
| 16 | * modify it under the terms of the GNU General Public License | ||
| 17 | * as published by the Free Software Foundation; either version 2 | ||
| 18 | * of the License, or (at your option) any later version. | ||
| 19 | * | ||
| 20 | * This program is distributed in the hope that it will be useful, | ||
| 21 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 23 | * GNU General Public License for more details. | ||
| 24 | * | ||
| 25 | * You should have received a copy of the GNU General Public License | ||
| 26 | * along with this program; if not, write to the Free Software | ||
| 27 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 28 | * Or, point your browser to http://www.gnu.org/copyleft/gpl.html | ||
| 29 | */ | ||
| 30 | |||
| 31 | #include <linux/errno.h> | ||
| 32 | #include <linux/slab.h> | ||
| 33 | #include <linux/list.h> | ||
| 34 | #include <linux/module.h> | ||
| 35 | #include <linux/vmalloc.h> | ||
| 36 | #include <linux/delay.h> | ||
| 37 | #include <linux/spinlock.h> | ||
| 38 | #include <linux/sched.h> | ||
| 39 | #include <linux/kthread.h> | ||
| 40 | |||
| 41 | #include "dvb_ca_en50221.h" | ||
| 42 | #include "dvb_ringbuffer.h" | ||
| 43 | |||
| 44 | static int dvb_ca_en50221_debug; | ||
| 45 | |||
| 46 | module_param_named(cam_debug, dvb_ca_en50221_debug, int, 0644); | ||
| 47 | MODULE_PARM_DESC(cam_debug, "enable verbose debug messages"); | ||
| 48 | |||
| 49 | #define dprintk if (dvb_ca_en50221_debug) printk | ||
| 50 | |||
| 51 | #define INIT_TIMEOUT_SECS 10 | ||
| 52 | |||
| 53 | #define HOST_LINK_BUF_SIZE 0x200 | ||
| 54 | |||
| 55 | #define RX_BUFFER_SIZE 65535 | ||
| 56 | |||
| 57 | #define MAX_RX_PACKETS_PER_ITERATION 10 | ||
| 58 | |||
| 59 | #define CTRLIF_DATA 0 | ||
| 60 | #define CTRLIF_COMMAND 1 | ||
| 61 | #define CTRLIF_STATUS 1 | ||
| 62 | #define CTRLIF_SIZE_LOW 2 | ||
| 63 | #define CTRLIF_SIZE_HIGH 3 | ||
| 64 | |||
| 65 | #define CMDREG_HC 1 /* Host control */ | ||
| 66 | #define CMDREG_SW 2 /* Size write */ | ||
| 67 | #define CMDREG_SR 4 /* Size read */ | ||
| 68 | #define CMDREG_RS 8 /* Reset interface */ | ||
| 69 | #define CMDREG_FRIE 0x40 /* Enable FR interrupt */ | ||
| 70 | #define CMDREG_DAIE 0x80 /* Enable DA interrupt */ | ||
| 71 | #define IRQEN (CMDREG_DAIE) | ||
| 72 | |||
| 73 | #define STATUSREG_RE 1 /* read error */ | ||
| 74 | #define STATUSREG_WE 2 /* write error */ | ||
| 75 | #define STATUSREG_FR 0x40 /* module free */ | ||
| 76 | #define STATUSREG_DA 0x80 /* data available */ | ||
| 77 | #define STATUSREG_TXERR (STATUSREG_RE|STATUSREG_WE) /* general transfer error */ | ||
| 78 | |||
| 79 | |||
| 80 | #define DVB_CA_SLOTSTATE_NONE 0 | ||
| 81 | #define DVB_CA_SLOTSTATE_UNINITIALISED 1 | ||
| 82 | #define DVB_CA_SLOTSTATE_RUNNING 2 | ||
| 83 | #define DVB_CA_SLOTSTATE_INVALID 3 | ||
| 84 | #define DVB_CA_SLOTSTATE_WAITREADY 4 | ||
| 85 | #define DVB_CA_SLOTSTATE_VALIDATE 5 | ||
| 86 | #define DVB_CA_SLOTSTATE_WAITFR 6 | ||
| 87 | #define DVB_CA_SLOTSTATE_LINKINIT 7 | ||
| 88 | |||
| 89 | |||
| 90 | /* Information on a CA slot */ | ||
| 91 | struct dvb_ca_slot { | ||
| 92 | |||
| 93 | /* current state of the CAM */ | ||
| 94 | int slot_state; | ||
| 95 | |||
| 96 | /* mutex used for serializing access to one CI slot */ | ||
| 97 | struct mutex slot_lock; | ||
| 98 | |||
| 99 | /* Number of CAMCHANGES that have occurred since last processing */ | ||
| 100 | atomic_t camchange_count; | ||
| 101 | |||
| 102 | /* Type of last CAMCHANGE */ | ||
| 103 | int camchange_type; | ||
| 104 | |||
| 105 | /* base address of CAM config */ | ||
| 106 | u32 config_base; | ||
| 107 | |||
| 108 | /* value to write into Config Control register */ | ||
| 109 | u8 config_option; | ||
| 110 | |||
| 111 | /* if 1, the CAM supports DA IRQs */ | ||
| 112 | u8 da_irq_supported:1; | ||
| 113 | |||
| 114 | /* size of the buffer to use when talking to the CAM */ | ||
| 115 | int link_buf_size; | ||
| 116 | |||
| 117 | /* buffer for incoming packets */ | ||
| 118 | struct dvb_ringbuffer rx_buffer; | ||
| 119 | |||
| 120 | /* timer used during various states of the slot */ | ||
| 121 | unsigned long timeout; | ||
| 122 | }; | ||
| 123 | |||
| 124 | /* Private CA-interface information */ | ||
| 125 | struct dvb_ca_private { | ||
| 126 | |||
| 127 | /* pointer back to the public data structure */ | ||
| 128 | struct dvb_ca_en50221 *pub; | ||
| 129 | |||
| 130 | /* the DVB device */ | ||
| 131 | struct dvb_device *dvbdev; | ||
| 132 | |||
| 133 | /* Flags describing the interface (DVB_CA_FLAG_*) */ | ||
| 134 | u32 flags; | ||
| 135 | |||
| 136 | /* number of slots supported by this CA interface */ | ||
| 137 | unsigned int slot_count; | ||
| 138 | |||
| 139 | /* information on each slot */ | ||
| 140 | struct dvb_ca_slot *slot_info; | ||
| 141 | |||
| 142 | /* wait queues for read() and write() operations */ | ||
| 143 | wait_queue_head_t wait_queue; | ||
| 144 | |||
| 145 | /* PID of the monitoring thread */ | ||
| 146 | struct task_struct *thread; | ||
| 147 | |||
| 148 | /* Flag indicating if the CA device is open */ | ||
| 149 | unsigned int open:1; | ||
| 150 | |||
| 151 | /* Flag indicating the thread should wake up now */ | ||
| 152 | unsigned int wakeup:1; | ||
| 153 | |||
| 154 | /* Delay the main thread should use */ | ||
| 155 | unsigned long delay; | ||
| 156 | |||
| 157 | /* Slot to start looking for data to read from in the next user-space read operation */ | ||
| 158 | int next_read_slot; | ||
| 159 | }; | ||
| 160 | |||
| 161 | static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca); | ||
| 162 | static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount); | ||
| 163 | static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount); | ||
| 164 | |||
| 165 | |||
| 166 | /** | ||
| 167 | * Safely find needle in haystack. | ||
| 168 | * | ||
| 169 | * @param haystack Buffer to look in. | ||
| 170 | * @param hlen Number of bytes in haystack. | ||
| 171 | * @param needle Buffer to find. | ||
| 172 | * @param nlen Number of bytes in needle. | ||
| 173 | * @return Pointer into haystack needle was found at, or NULL if not found. | ||
| 174 | */ | ||
| 175 | static char *findstr(char * haystack, int hlen, char * needle, int nlen) | ||
| 176 | { | ||
| 177 | int i; | ||
| 178 | |||
| 179 | if (hlen < nlen) | ||
| 180 | return NULL; | ||
| 181 | |||
| 182 | for (i = 0; i <= hlen - nlen; i++) { | ||
| 183 | if (!strncmp(haystack + i, needle, nlen)) | ||
| 184 | return haystack + i; | ||
| 185 | } | ||
| 186 | |||
| 187 | return NULL; | ||
| 188 | } | ||
| 189 | |||
| 190 | |||
| 191 | |||
| 192 | /* ******************************************************************************** */ | ||
| 193 | /* EN50221 physical interface functions */ | ||
| 194 | |||
| 195 | |||
| 196 | /** | ||
| 197 | * Check CAM status. | ||
| 198 | */ | ||
| 199 | static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot) | ||
| 200 | { | ||
| 201 | int slot_status; | ||
| 202 | int cam_present_now; | ||
| 203 | int cam_changed; | ||
| 204 | |||
| 205 | /* IRQ mode */ | ||
| 206 | if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) { | ||
| 207 | return (atomic_read(&ca->slot_info[slot].camchange_count) != 0); | ||
| 208 | } | ||
| 209 | |||
| 210 | /* poll mode */ | ||
| 211 | slot_status = ca->pub->poll_slot_status(ca->pub, slot, ca->open); | ||
| 212 | |||
| 213 | cam_present_now = (slot_status & DVB_CA_EN50221_POLL_CAM_PRESENT) ? 1 : 0; | ||
| 214 | cam_changed = (slot_status & DVB_CA_EN50221_POLL_CAM_CHANGED) ? 1 : 0; | ||
| 215 | if (!cam_changed) { | ||
| 216 | int cam_present_old = (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE); | ||
| 217 | cam_changed = (cam_present_now != cam_present_old); | ||
| 218 | } | ||
| 219 | |||
| 220 | if (cam_changed) { | ||
| 221 | if (!cam_present_now) { | ||
| 222 | ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; | ||
| 223 | } else { | ||
| 224 | ca->slot_info[slot].camchange_type = DVB_CA_EN50221_CAMCHANGE_INSERTED; | ||
| 225 | } | ||
| 226 | atomic_set(&ca->slot_info[slot].camchange_count, 1); | ||
| 227 | } else { | ||
| 228 | if ((ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) && | ||
| 229 | (slot_status & DVB_CA_EN50221_POLL_CAM_READY)) { | ||
| 230 | // move to validate state if reset is completed | ||
| 231 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE; | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | return cam_changed; | ||
| 236 | } | ||
| 237 | |||
| 238 | |||
| 239 | /** | ||
| 240 | * Wait for flags to become set on the STATUS register on a CAM interface, | ||
| 241 | * checking for errors and timeout. | ||
| 242 | * | ||
| 243 | * @param ca CA instance. | ||
| 244 | * @param slot Slot on interface. | ||
| 245 | * @param waitfor Flags to wait for. | ||
| 246 | * @param timeout_ms Timeout in milliseconds. | ||
| 247 | * | ||
| 248 | * @return 0 on success, nonzero on error. | ||
| 249 | */ | ||
| 250 | static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot, | ||
| 251 | u8 waitfor, int timeout_hz) | ||
| 252 | { | ||
| 253 | unsigned long timeout; | ||
| 254 | unsigned long start; | ||
| 255 | |||
| 256 | dprintk("%s\n", __func__); | ||
| 257 | |||
| 258 | /* loop until timeout elapsed */ | ||
| 259 | start = jiffies; | ||
| 260 | timeout = jiffies + timeout_hz; | ||
| 261 | while (1) { | ||
| 262 | /* read the status and check for error */ | ||
| 263 | int res = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); | ||
| 264 | if (res < 0) | ||
| 265 | return -EIO; | ||
| 266 | |||
| 267 | /* if we got the flags, it was successful! */ | ||
| 268 | if (res & waitfor) { | ||
| 269 | dprintk("%s succeeded timeout:%lu\n", __func__, jiffies - start); | ||
| 270 | return 0; | ||
| 271 | } | ||
| 272 | |||
| 273 | /* check for timeout */ | ||
| 274 | if (time_after(jiffies, timeout)) { | ||
| 275 | break; | ||
| 276 | } | ||
| 277 | |||
| 278 | /* wait for a bit */ | ||
| 279 | msleep(1); | ||
| 280 | } | ||
| 281 | |||
| 282 | dprintk("%s failed timeout:%lu\n", __func__, jiffies - start); | ||
| 283 | |||
| 284 | /* if we get here, we've timed out */ | ||
| 285 | return -ETIMEDOUT; | ||
| 286 | } | ||
| 287 | |||
| 288 | |||
| 289 | /** | ||
| 290 | * Initialise the link layer connection to a CAM. | ||
| 291 | * | ||
| 292 | * @param ca CA instance. | ||
| 293 | * @param slot Slot id. | ||
| 294 | * | ||
| 295 | * @return 0 on success, nonzero on failure. | ||
| 296 | */ | ||
| 297 | static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot) | ||
| 298 | { | ||
| 299 | int ret; | ||
| 300 | int buf_size; | ||
| 301 | u8 buf[2]; | ||
| 302 | |||
| 303 | dprintk("%s\n", __func__); | ||
| 304 | |||
| 305 | /* we'll be determining these during this function */ | ||
| 306 | ca->slot_info[slot].da_irq_supported = 0; | ||
| 307 | |||
| 308 | /* set the host link buffer size temporarily. it will be overwritten with the | ||
| 309 | * real negotiated size later. */ | ||
| 310 | ca->slot_info[slot].link_buf_size = 2; | ||
| 311 | |||
| 312 | /* read the buffer size from the CAM */ | ||
| 313 | if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SR)) != 0) | ||
| 314 | return ret; | ||
| 315 | if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_DA, HZ / 10)) != 0) | ||
| 316 | return ret; | ||
| 317 | if ((ret = dvb_ca_en50221_read_data(ca, slot, buf, 2)) != 2) | ||
| 318 | return -EIO; | ||
| 319 | if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0) | ||
| 320 | return ret; | ||
| 321 | |||
| 322 | /* store it, and choose the minimum of our buffer and the CAM's buffer size */ | ||
| 323 | buf_size = (buf[0] << 8) | buf[1]; | ||
| 324 | if (buf_size > HOST_LINK_BUF_SIZE) | ||
| 325 | buf_size = HOST_LINK_BUF_SIZE; | ||
| 326 | ca->slot_info[slot].link_buf_size = buf_size; | ||
| 327 | buf[0] = buf_size >> 8; | ||
| 328 | buf[1] = buf_size & 0xff; | ||
| 329 | dprintk("Chosen link buffer size of %i\n", buf_size); | ||
| 330 | |||
| 331 | /* write the buffer size to the CAM */ | ||
| 332 | if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | CMDREG_SW)) != 0) | ||
| 333 | return ret; | ||
| 334 | if ((ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10)) != 0) | ||
| 335 | return ret; | ||
| 336 | if ((ret = dvb_ca_en50221_write_data(ca, slot, buf, 2)) != 2) | ||
| 337 | return -EIO; | ||
| 338 | if ((ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN)) != 0) | ||
| 339 | return ret; | ||
| 340 | |||
| 341 | /* success */ | ||
| 342 | return 0; | ||
| 343 | } | ||
| 344 | |||
| 345 | /** | ||
| 346 | * Read a tuple from attribute memory. | ||
| 347 | * | ||
| 348 | * @param ca CA instance. | ||
| 349 | * @param slot Slot id. | ||
| 350 | * @param address Address to read from. Updated. | ||
| 351 | * @param tupleType Tuple id byte. Updated. | ||
| 352 | * @param tupleLength Tuple length. Updated. | ||
| 353 | * @param tuple Dest buffer for tuple (must be 256 bytes). Updated. | ||
| 354 | * | ||
| 355 | * @return 0 on success, nonzero on error. | ||
| 356 | */ | ||
| 357 | static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot, | ||
| 358 | int *address, int *tupleType, int *tupleLength, u8 * tuple) | ||
| 359 | { | ||
| 360 | int i; | ||
| 361 | int _tupleType; | ||
| 362 | int _tupleLength; | ||
| 363 | int _address = *address; | ||
| 364 | |||
| 365 | /* grab the next tuple length and type */ | ||
| 366 | if ((_tupleType = ca->pub->read_attribute_mem(ca->pub, slot, _address)) < 0) | ||
| 367 | return _tupleType; | ||
| 368 | if (_tupleType == 0xff) { | ||
| 369 | dprintk("END OF CHAIN TUPLE type:0x%x\n", _tupleType); | ||
| 370 | *address += 2; | ||
| 371 | *tupleType = _tupleType; | ||
| 372 | *tupleLength = 0; | ||
| 373 | return 0; | ||
| 374 | } | ||
| 375 | if ((_tupleLength = ca->pub->read_attribute_mem(ca->pub, slot, _address + 2)) < 0) | ||
| 376 | return _tupleLength; | ||
| 377 | _address += 4; | ||
| 378 | |||
| 379 | dprintk("TUPLE type:0x%x length:%i\n", _tupleType, _tupleLength); | ||
| 380 | |||
| 381 | /* read in the whole tuple */ | ||
| 382 | for (i = 0; i < _tupleLength; i++) { | ||
| 383 | tuple[i] = ca->pub->read_attribute_mem(ca->pub, slot, _address + (i * 2)); | ||
| 384 | dprintk(" 0x%02x: 0x%02x %c\n", | ||
| 385 | i, tuple[i] & 0xff, | ||
| 386 | ((tuple[i] > 31) && (tuple[i] < 127)) ? tuple[i] : '.'); | ||
| 387 | } | ||
| 388 | _address += (_tupleLength * 2); | ||
| 389 | |||
| 390 | // success | ||
| 391 | *tupleType = _tupleType; | ||
| 392 | *tupleLength = _tupleLength; | ||
| 393 | *address = _address; | ||
| 394 | return 0; | ||
| 395 | } | ||
| 396 | |||
| 397 | |||
| 398 | /** | ||
| 399 | * Parse attribute memory of a CAM module, extracting Config register, and checking | ||
| 400 | * it is a DVB CAM module. | ||
| 401 | * | ||
| 402 | * @param ca CA instance. | ||
| 403 | * @param slot Slot id. | ||
| 404 | * | ||
| 405 | * @return 0 on success, <0 on failure. | ||
| 406 | */ | ||
| 407 | static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot) | ||
| 408 | { | ||
| 409 | int address = 0; | ||
| 410 | int tupleLength; | ||
| 411 | int tupleType; | ||
| 412 | u8 tuple[257]; | ||
| 413 | char *dvb_str; | ||
| 414 | int rasz; | ||
| 415 | int status; | ||
| 416 | int got_cftableentry = 0; | ||
| 417 | int end_chain = 0; | ||
| 418 | int i; | ||
| 419 | u16 manfid = 0; | ||
| 420 | u16 devid = 0; | ||
| 421 | |||
| 422 | |||
| 423 | // CISTPL_DEVICE_0A | ||
| 424 | if ((status = | ||
| 425 | dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) | ||
| 426 | return status; | ||
| 427 | if (tupleType != 0x1D) | ||
| 428 | return -EINVAL; | ||
| 429 | |||
| 430 | |||
| 431 | |||
| 432 | // CISTPL_DEVICE_0C | ||
| 433 | if ((status = | ||
| 434 | dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) | ||
| 435 | return status; | ||
| 436 | if (tupleType != 0x1C) | ||
| 437 | return -EINVAL; | ||
| 438 | |||
| 439 | |||
| 440 | |||
| 441 | // CISTPL_VERS_1 | ||
| 442 | if ((status = | ||
| 443 | dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, &tupleLength, tuple)) < 0) | ||
| 444 | return status; | ||
| 445 | if (tupleType != 0x15) | ||
| 446 | return -EINVAL; | ||
| 447 | |||
| 448 | |||
| 449 | |||
| 450 | // CISTPL_MANFID | ||
| 451 | if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, | ||
| 452 | &tupleLength, tuple)) < 0) | ||
| 453 | return status; | ||
| 454 | if (tupleType != 0x20) | ||
| 455 | return -EINVAL; | ||
| 456 | if (tupleLength != 4) | ||
| 457 | return -EINVAL; | ||
| 458 | manfid = (tuple[1] << 8) | tuple[0]; | ||
| 459 | devid = (tuple[3] << 8) | tuple[2]; | ||
| 460 | |||
| 461 | |||
| 462 | |||
| 463 | // CISTPL_CONFIG | ||
| 464 | if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, | ||
| 465 | &tupleLength, tuple)) < 0) | ||
| 466 | return status; | ||
| 467 | if (tupleType != 0x1A) | ||
| 468 | return -EINVAL; | ||
| 469 | if (tupleLength < 3) | ||
| 470 | return -EINVAL; | ||
| 471 | |||
| 472 | /* extract the configbase */ | ||
| 473 | rasz = tuple[0] & 3; | ||
| 474 | if (tupleLength < (3 + rasz + 14)) | ||
| 475 | return -EINVAL; | ||
| 476 | ca->slot_info[slot].config_base = 0; | ||
| 477 | for (i = 0; i < rasz + 1; i++) { | ||
| 478 | ca->slot_info[slot].config_base |= (tuple[2 + i] << (8 * i)); | ||
| 479 | } | ||
| 480 | |||
| 481 | /* check it contains the correct DVB string */ | ||
| 482 | dvb_str = findstr((char *)tuple, tupleLength, "DVB_CI_V", 8); | ||
| 483 | if (dvb_str == NULL) | ||
| 484 | return -EINVAL; | ||
| 485 | if (tupleLength < ((dvb_str - (char *) tuple) + 12)) | ||
| 486 | return -EINVAL; | ||
| 487 | |||
| 488 | /* is it a version we support? */ | ||
| 489 | if (strncmp(dvb_str + 8, "1.00", 4)) { | ||
| 490 | printk("dvb_ca adapter %d: Unsupported DVB CAM module version %c%c%c%c\n", | ||
| 491 | ca->dvbdev->adapter->num, dvb_str[8], dvb_str[9], dvb_str[10], dvb_str[11]); | ||
| 492 | return -EINVAL; | ||
| 493 | } | ||
| 494 | |||
| 495 | /* process the CFTABLE_ENTRY tuples, and any after those */ | ||
| 496 | while ((!end_chain) && (address < 0x1000)) { | ||
| 497 | if ((status = dvb_ca_en50221_read_tuple(ca, slot, &address, &tupleType, | ||
| 498 | &tupleLength, tuple)) < 0) | ||
| 499 | return status; | ||
| 500 | switch (tupleType) { | ||
| 501 | case 0x1B: // CISTPL_CFTABLE_ENTRY | ||
| 502 | if (tupleLength < (2 + 11 + 17)) | ||
| 503 | break; | ||
| 504 | |||
| 505 | /* if we've already parsed one, just use it */ | ||
| 506 | if (got_cftableentry) | ||
| 507 | break; | ||
| 508 | |||
| 509 | /* get the config option */ | ||
| 510 | ca->slot_info[slot].config_option = tuple[0] & 0x3f; | ||
| 511 | |||
| 512 | /* OK, check it contains the correct strings */ | ||
| 513 | if ((findstr((char *)tuple, tupleLength, "DVB_HOST", 8) == NULL) || | ||
| 514 | (findstr((char *)tuple, tupleLength, "DVB_CI_MODULE", 13) == NULL)) | ||
| 515 | break; | ||
| 516 | |||
| 517 | got_cftableentry = 1; | ||
| 518 | break; | ||
| 519 | |||
| 520 | case 0x14: // CISTPL_NO_LINK | ||
| 521 | break; | ||
| 522 | |||
| 523 | case 0xFF: // CISTPL_END | ||
| 524 | end_chain = 1; | ||
| 525 | break; | ||
| 526 | |||
| 527 | default: /* Unknown tuple type - just skip this tuple and move to the next one */ | ||
| 528 | dprintk("dvb_ca: Skipping unknown tuple type:0x%x length:0x%x\n", tupleType, | ||
| 529 | tupleLength); | ||
| 530 | break; | ||
| 531 | } | ||
| 532 | } | ||
| 533 | |||
| 534 | if ((address > 0x1000) || (!got_cftableentry)) | ||
| 535 | return -EINVAL; | ||
| 536 | |||
| 537 | dprintk("Valid DVB CAM detected MANID:%x DEVID:%x CONFIGBASE:0x%x CONFIGOPTION:0x%x\n", | ||
| 538 | manfid, devid, ca->slot_info[slot].config_base, ca->slot_info[slot].config_option); | ||
| 539 | |||
| 540 | // success! | ||
| 541 | return 0; | ||
| 542 | } | ||
| 543 | |||
| 544 | |||
| 545 | /** | ||
| 546 | * Set CAM's configoption correctly. | ||
| 547 | * | ||
| 548 | * @param ca CA instance. | ||
| 549 | * @param slot Slot containing the CAM. | ||
| 550 | */ | ||
| 551 | static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot) | ||
| 552 | { | ||
| 553 | int configoption; | ||
| 554 | |||
| 555 | dprintk("%s\n", __func__); | ||
| 556 | |||
| 557 | /* set the config option */ | ||
| 558 | ca->pub->write_attribute_mem(ca->pub, slot, | ||
| 559 | ca->slot_info[slot].config_base, | ||
| 560 | ca->slot_info[slot].config_option); | ||
| 561 | |||
| 562 | /* check it */ | ||
| 563 | configoption = ca->pub->read_attribute_mem(ca->pub, slot, ca->slot_info[slot].config_base); | ||
| 564 | dprintk("Set configoption 0x%x, read configoption 0x%x\n", | ||
| 565 | ca->slot_info[slot].config_option, configoption & 0x3f); | ||
| 566 | |||
| 567 | /* fine! */ | ||
| 568 | return 0; | ||
| 569 | |||
| 570 | } | ||
| 571 | |||
| 572 | |||
| 573 | /** | ||
| 574 | * This function talks to an EN50221 CAM control interface. It reads a buffer of | ||
| 575 | * data from the CAM. The data can either be stored in a supplied buffer, or | ||
| 576 | * automatically be added to the slot's rx_buffer. | ||
| 577 | * | ||
| 578 | * @param ca CA instance. | ||
| 579 | * @param slot Slot to read from. | ||
| 580 | * @param ebuf If non-NULL, the data will be written to this buffer. If NULL, | ||
| 581 | * the data will be added into the buffering system as a normal fragment. | ||
| 582 | * @param ecount Size of ebuf. Ignored if ebuf is NULL. | ||
| 583 | * | ||
| 584 | * @return Number of bytes read, or < 0 on error | ||
| 585 | */ | ||
| 586 | static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 * ebuf, int ecount) | ||
| 587 | { | ||
| 588 | int bytes_read; | ||
| 589 | int status; | ||
| 590 | u8 buf[HOST_LINK_BUF_SIZE]; | ||
| 591 | int i; | ||
| 592 | |||
| 593 | dprintk("%s\n", __func__); | ||
| 594 | |||
| 595 | /* check if we have space for a link buf in the rx_buffer */ | ||
| 596 | if (ebuf == NULL) { | ||
| 597 | int buf_free; | ||
| 598 | |||
| 599 | if (ca->slot_info[slot].rx_buffer.data == NULL) { | ||
| 600 | status = -EIO; | ||
| 601 | goto exit; | ||
| 602 | } | ||
| 603 | buf_free = dvb_ringbuffer_free(&ca->slot_info[slot].rx_buffer); | ||
| 604 | |||
| 605 | if (buf_free < (ca->slot_info[slot].link_buf_size + DVB_RINGBUFFER_PKTHDRSIZE)) { | ||
| 606 | status = -EAGAIN; | ||
| 607 | goto exit; | ||
| 608 | } | ||
| 609 | } | ||
| 610 | |||
| 611 | /* check if there is data available */ | ||
| 612 | if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) | ||
| 613 | goto exit; | ||
| 614 | if (!(status & STATUSREG_DA)) { | ||
| 615 | /* no data */ | ||
| 616 | status = 0; | ||
| 617 | goto exit; | ||
| 618 | } | ||
| 619 | |||
| 620 | /* read the amount of data */ | ||
| 621 | if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH)) < 0) | ||
| 622 | goto exit; | ||
| 623 | bytes_read = status << 8; | ||
| 624 | if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW)) < 0) | ||
| 625 | goto exit; | ||
| 626 | bytes_read |= status; | ||
| 627 | |||
| 628 | /* check it will fit */ | ||
| 629 | if (ebuf == NULL) { | ||
| 630 | if (bytes_read > ca->slot_info[slot].link_buf_size) { | ||
| 631 | printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the link buffer size (%i > %i)!\n", | ||
| 632 | ca->dvbdev->adapter->num, bytes_read, ca->slot_info[slot].link_buf_size); | ||
| 633 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; | ||
| 634 | status = -EIO; | ||
| 635 | goto exit; | ||
| 636 | } | ||
| 637 | if (bytes_read < 2) { | ||
| 638 | printk("dvb_ca adapter %d: CAM sent a buffer that was less than 2 bytes!\n", | ||
| 639 | ca->dvbdev->adapter->num); | ||
| 640 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; | ||
| 641 | status = -EIO; | ||
| 642 | goto exit; | ||
| 643 | } | ||
| 644 | } else { | ||
| 645 | if (bytes_read > ecount) { | ||
| 646 | printk("dvb_ca adapter %d: CAM tried to send a buffer larger than the ecount size!\n", | ||
| 647 | ca->dvbdev->adapter->num); | ||
| 648 | status = -EIO; | ||
| 649 | goto exit; | ||
| 650 | } | ||
| 651 | } | ||
| 652 | |||
| 653 | /* fill the buffer */ | ||
| 654 | for (i = 0; i < bytes_read; i++) { | ||
| 655 | /* read byte and check */ | ||
| 656 | if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_DATA)) < 0) | ||
| 657 | goto exit; | ||
| 658 | |||
| 659 | /* OK, store it in the buffer */ | ||
| 660 | buf[i] = status; | ||
| 661 | } | ||
| 662 | |||
| 663 | /* check for read error (RE should now be 0) */ | ||
| 664 | if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) | ||
| 665 | goto exit; | ||
| 666 | if (status & STATUSREG_RE) { | ||
| 667 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; | ||
| 668 | status = -EIO; | ||
| 669 | goto exit; | ||
| 670 | } | ||
| 671 | |||
| 672 | /* OK, add it to the receive buffer, or copy into external buffer if supplied */ | ||
| 673 | if (ebuf == NULL) { | ||
| 674 | if (ca->slot_info[slot].rx_buffer.data == NULL) { | ||
| 675 | status = -EIO; | ||
| 676 | goto exit; | ||
| 677 | } | ||
| 678 | dvb_ringbuffer_pkt_write(&ca->slot_info[slot].rx_buffer, buf, bytes_read); | ||
| 679 | } else { | ||
| 680 | memcpy(ebuf, buf, bytes_read); | ||
| 681 | } | ||
| 682 | |||
| 683 | dprintk("Received CA packet for slot %i connection id 0x%x last_frag:%i size:0x%x\n", slot, | ||
| 684 | buf[0], (buf[1] & 0x80) == 0, bytes_read); | ||
| 685 | |||
| 686 | /* wake up readers when a last_fragment is received */ | ||
| 687 | if ((buf[1] & 0x80) == 0x00) { | ||
| 688 | wake_up_interruptible(&ca->wait_queue); | ||
| 689 | } | ||
| 690 | status = bytes_read; | ||
| 691 | |||
| 692 | exit: | ||
| 693 | return status; | ||
| 694 | } | ||
| 695 | |||
| 696 | |||
| 697 | /** | ||
| 698 | * This function talks to an EN50221 CAM control interface. It writes a buffer of data | ||
| 699 | * to a CAM. | ||
| 700 | * | ||
| 701 | * @param ca CA instance. | ||
| 702 | * @param slot Slot to write to. | ||
| 703 | * @param ebuf The data in this buffer is treated as a complete link-level packet to | ||
| 704 | * be written. | ||
| 705 | * @param count Size of ebuf. | ||
| 706 | * | ||
| 707 | * @return Number of bytes written, or < 0 on error. | ||
| 708 | */ | ||
| 709 | static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 * buf, int bytes_write) | ||
| 710 | { | ||
| 711 | int status; | ||
| 712 | int i; | ||
| 713 | |||
| 714 | dprintk("%s\n", __func__); | ||
| 715 | |||
| 716 | |||
| 717 | /* sanity check */ | ||
| 718 | if (bytes_write > ca->slot_info[slot].link_buf_size) | ||
| 719 | return -EINVAL; | ||
| 720 | |||
| 721 | /* it is possible we are dealing with a single buffer implementation, | ||
| 722 | thus if there is data available for read or if there is even a read | ||
| 723 | already in progress, we do nothing but awake the kernel thread to | ||
| 724 | process the data if necessary. */ | ||
| 725 | if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) | ||
| 726 | goto exitnowrite; | ||
| 727 | if (status & (STATUSREG_DA | STATUSREG_RE)) { | ||
| 728 | if (status & STATUSREG_DA) | ||
| 729 | dvb_ca_en50221_thread_wakeup(ca); | ||
| 730 | |||
| 731 | status = -EAGAIN; | ||
| 732 | goto exitnowrite; | ||
| 733 | } | ||
| 734 | |||
| 735 | /* OK, set HC bit */ | ||
| 736 | if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, | ||
| 737 | IRQEN | CMDREG_HC)) != 0) | ||
| 738 | goto exit; | ||
| 739 | |||
| 740 | /* check if interface is still free */ | ||
| 741 | if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) | ||
| 742 | goto exit; | ||
| 743 | if (!(status & STATUSREG_FR)) { | ||
| 744 | /* it wasn't free => try again later */ | ||
| 745 | status = -EAGAIN; | ||
| 746 | goto exit; | ||
| 747 | } | ||
| 748 | |||
| 749 | /* send the amount of data */ | ||
| 750 | if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_HIGH, bytes_write >> 8)) != 0) | ||
| 751 | goto exit; | ||
| 752 | if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_SIZE_LOW, | ||
| 753 | bytes_write & 0xff)) != 0) | ||
| 754 | goto exit; | ||
| 755 | |||
| 756 | /* send the buffer */ | ||
| 757 | for (i = 0; i < bytes_write; i++) { | ||
| 758 | if ((status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_DATA, buf[i])) != 0) | ||
| 759 | goto exit; | ||
| 760 | } | ||
| 761 | |||
| 762 | /* check for write error (WE should now be 0) */ | ||
| 763 | if ((status = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS)) < 0) | ||
| 764 | goto exit; | ||
| 765 | if (status & STATUSREG_WE) { | ||
| 766 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; | ||
| 767 | status = -EIO; | ||
| 768 | goto exit; | ||
| 769 | } | ||
| 770 | status = bytes_write; | ||
| 771 | |||
| 772 | dprintk("Wrote CA packet for slot %i, connection id 0x%x last_frag:%i size:0x%x\n", slot, | ||
| 773 | buf[0], (buf[1] & 0x80) == 0, bytes_write); | ||
| 774 | |||
| 775 | exit: | ||
| 776 | ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN); | ||
| 777 | |||
| 778 | exitnowrite: | ||
| 779 | return status; | ||
| 780 | } | ||
| 781 | EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq); | ||
| 782 | |||
| 783 | |||
| 784 | |||
| 785 | /* ******************************************************************************** */ | ||
| 786 | /* EN50221 higher level functions */ | ||
| 787 | |||
| 788 | |||
| 789 | /** | ||
| 790 | * A CAM has been removed => shut it down. | ||
| 791 | * | ||
| 792 | * @param ca CA instance. | ||
| 793 | * @param slot Slot to shut down. | ||
| 794 | */ | ||
| 795 | static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot) | ||
| 796 | { | ||
| 797 | dprintk("%s\n", __func__); | ||
| 798 | |||
| 799 | ca->pub->slot_shutdown(ca->pub, slot); | ||
| 800 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; | ||
| 801 | |||
| 802 | /* need to wake up all processes to check if they're now | ||
| 803 | trying to write to a defunct CAM */ | ||
| 804 | wake_up_interruptible(&ca->wait_queue); | ||
| 805 | |||
| 806 | dprintk("Slot %i shutdown\n", slot); | ||
| 807 | |||
| 808 | /* success */ | ||
| 809 | return 0; | ||
| 810 | } | ||
| 811 | EXPORT_SYMBOL(dvb_ca_en50221_camready_irq); | ||
| 812 | |||
| 813 | |||
| 814 | /** | ||
| 815 | * A CAMCHANGE IRQ has occurred. | ||
| 816 | * | ||
| 817 | * @param ca CA instance. | ||
| 818 | * @param slot Slot concerned. | ||
| 819 | * @param change_type One of the DVB_CA_CAMCHANGE_* values. | ||
| 820 | */ | ||
| 821 | void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221 *pubca, int slot, int change_type) | ||
| 822 | { | ||
| 823 | struct dvb_ca_private *ca = pubca->private; | ||
| 824 | |||
| 825 | dprintk("CAMCHANGE IRQ slot:%i change_type:%i\n", slot, change_type); | ||
| 826 | |||
| 827 | switch (change_type) { | ||
| 828 | case DVB_CA_EN50221_CAMCHANGE_REMOVED: | ||
| 829 | case DVB_CA_EN50221_CAMCHANGE_INSERTED: | ||
| 830 | break; | ||
| 831 | |||
| 832 | default: | ||
| 833 | return; | ||
| 834 | } | ||
| 835 | |||
| 836 | ca->slot_info[slot].camchange_type = change_type; | ||
| 837 | atomic_inc(&ca->slot_info[slot].camchange_count); | ||
| 838 | dvb_ca_en50221_thread_wakeup(ca); | ||
| 839 | } | ||
| 840 | EXPORT_SYMBOL(dvb_ca_en50221_frda_irq); | ||
| 841 | |||
| 842 | |||
| 843 | /** | ||
| 844 | * A CAMREADY IRQ has occurred. | ||
| 845 | * | ||
| 846 | * @param ca CA instance. | ||
| 847 | * @param slot Slot concerned. | ||
| 848 | */ | ||
| 849 | void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot) | ||
| 850 | { | ||
| 851 | struct dvb_ca_private *ca = pubca->private; | ||
| 852 | |||
| 853 | dprintk("CAMREADY IRQ slot:%i\n", slot); | ||
| 854 | |||
| 855 | if (ca->slot_info[slot].slot_state == DVB_CA_SLOTSTATE_WAITREADY) { | ||
| 856 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_VALIDATE; | ||
| 857 | dvb_ca_en50221_thread_wakeup(ca); | ||
| 858 | } | ||
| 859 | } | ||
| 860 | |||
| 861 | |||
| 862 | /** | ||
| 863 | * An FR or DA IRQ has occurred. | ||
| 864 | * | ||
| 865 | * @param ca CA instance. | ||
| 866 | * @param slot Slot concerned. | ||
| 867 | */ | ||
| 868 | void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot) | ||
| 869 | { | ||
| 870 | struct dvb_ca_private *ca = pubca->private; | ||
| 871 | int flags; | ||
| 872 | |||
| 873 | dprintk("FR/DA IRQ slot:%i\n", slot); | ||
| 874 | |||
| 875 | switch (ca->slot_info[slot].slot_state) { | ||
| 876 | case DVB_CA_SLOTSTATE_LINKINIT: | ||
| 877 | flags = ca->pub->read_cam_control(pubca, slot, CTRLIF_STATUS); | ||
| 878 | if (flags & STATUSREG_DA) { | ||
| 879 | dprintk("CAM supports DA IRQ\n"); | ||
| 880 | ca->slot_info[slot].da_irq_supported = 1; | ||
| 881 | } | ||
| 882 | break; | ||
| 883 | |||
| 884 | case DVB_CA_SLOTSTATE_RUNNING: | ||
| 885 | if (ca->open) | ||
| 886 | dvb_ca_en50221_thread_wakeup(ca); | ||
| 887 | break; | ||
| 888 | } | ||
| 889 | } | ||
| 890 | |||
| 891 | |||
| 892 | |||
| 893 | /* ******************************************************************************** */ | ||
| 894 | /* EN50221 thread functions */ | ||
| 895 | |||
| 896 | /** | ||
| 897 | * Wake up the DVB CA thread | ||
| 898 | * | ||
| 899 | * @param ca CA instance. | ||
| 900 | */ | ||
| 901 | static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca) | ||
| 902 | { | ||
| 903 | |||
| 904 | dprintk("%s\n", __func__); | ||
| 905 | |||
| 906 | ca->wakeup = 1; | ||
| 907 | mb(); | ||
| 908 | wake_up_process(ca->thread); | ||
| 909 | } | ||
| 910 | |||
| 911 | /** | ||
| 912 | * Update the delay used by the thread. | ||
| 913 | * | ||
| 914 | * @param ca CA instance. | ||
| 915 | */ | ||
| 916 | static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca) | ||
| 917 | { | ||
| 918 | int delay; | ||
| 919 | int curdelay = 100000000; | ||
| 920 | int slot; | ||
| 921 | |||
| 922 | /* Beware of too high polling frequency, because one polling | ||
| 923 | * call might take several hundred milliseconds until timeout! | ||
| 924 | */ | ||
| 925 | for (slot = 0; slot < ca->slot_count; slot++) { | ||
| 926 | switch (ca->slot_info[slot].slot_state) { | ||
| 927 | default: | ||
| 928 | case DVB_CA_SLOTSTATE_NONE: | ||
| 929 | delay = HZ * 60; /* 60s */ | ||
| 930 | if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) | ||
| 931 | delay = HZ * 5; /* 5s */ | ||
| 932 | break; | ||
| 933 | case DVB_CA_SLOTSTATE_INVALID: | ||
| 934 | delay = HZ * 60; /* 60s */ | ||
| 935 | if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) | ||
| 936 | delay = HZ / 10; /* 100ms */ | ||
| 937 | break; | ||
| 938 | |||
| 939 | case DVB_CA_SLOTSTATE_UNINITIALISED: | ||
| 940 | case DVB_CA_SLOTSTATE_WAITREADY: | ||
| 941 | case DVB_CA_SLOTSTATE_VALIDATE: | ||
| 942 | case DVB_CA_SLOTSTATE_WAITFR: | ||
| 943 | case DVB_CA_SLOTSTATE_LINKINIT: | ||
| 944 | delay = HZ / 10; /* 100ms */ | ||
| 945 | break; | ||
| 946 | |||
| 947 | case DVB_CA_SLOTSTATE_RUNNING: | ||
| 948 | delay = HZ * 60; /* 60s */ | ||
| 949 | if (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) | ||
| 950 | delay = HZ / 10; /* 100ms */ | ||
| 951 | if (ca->open) { | ||
| 952 | if ((!ca->slot_info[slot].da_irq_supported) || | ||
| 953 | (!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_DA))) | ||
| 954 | delay = HZ / 10; /* 100ms */ | ||
| 955 | } | ||
| 956 | break; | ||
| 957 | } | ||
| 958 | |||
| 959 | if (delay < curdelay) | ||
| 960 | curdelay = delay; | ||
| 961 | } | ||
| 962 | |||
| 963 | ca->delay = curdelay; | ||
| 964 | } | ||
| 965 | |||
| 966 | |||
| 967 | |||
| 968 | /** | ||
| 969 | * Kernel thread which monitors CA slots for CAM changes, and performs data transfers. | ||
| 970 | */ | ||
| 971 | static int dvb_ca_en50221_thread(void *data) | ||
| 972 | { | ||
| 973 | struct dvb_ca_private *ca = data; | ||
| 974 | int slot; | ||
| 975 | int flags; | ||
| 976 | int status; | ||
| 977 | int pktcount; | ||
| 978 | void *rxbuf; | ||
| 979 | |||
| 980 | dprintk("%s\n", __func__); | ||
| 981 | |||
| 982 | /* choose the correct initial delay */ | ||
| 983 | dvb_ca_en50221_thread_update_delay(ca); | ||
| 984 | |||
| 985 | /* main loop */ | ||
| 986 | while (!kthread_should_stop()) { | ||
| 987 | /* sleep for a bit */ | ||
| 988 | if (!ca->wakeup) { | ||
| 989 | set_current_state(TASK_INTERRUPTIBLE); | ||
| 990 | schedule_timeout(ca->delay); | ||
| 991 | if (kthread_should_stop()) | ||
| 992 | return 0; | ||
| 993 | } | ||
| 994 | ca->wakeup = 0; | ||
| 995 | |||
| 996 | /* go through all the slots processing them */ | ||
| 997 | for (slot = 0; slot < ca->slot_count; slot++) { | ||
| 998 | |||
| 999 | mutex_lock(&ca->slot_info[slot].slot_lock); | ||
| 1000 | |||
| 1001 | // check the cam status + deal with CAMCHANGEs | ||
| 1002 | while (dvb_ca_en50221_check_camstatus(ca, slot)) { | ||
| 1003 | /* clear down an old CI slot if necessary */ | ||
| 1004 | if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) | ||
| 1005 | dvb_ca_en50221_slot_shutdown(ca, slot); | ||
| 1006 | |||
| 1007 | /* if a CAM is NOW present, initialise it */ | ||
| 1008 | if (ca->slot_info[slot].camchange_type == DVB_CA_EN50221_CAMCHANGE_INSERTED) { | ||
| 1009 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_UNINITIALISED; | ||
| 1010 | } | ||
| 1011 | |||
| 1012 | /* we've handled one CAMCHANGE */ | ||
| 1013 | dvb_ca_en50221_thread_update_delay(ca); | ||
| 1014 | atomic_dec(&ca->slot_info[slot].camchange_count); | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | // CAM state machine | ||
| 1018 | switch (ca->slot_info[slot].slot_state) { | ||
| 1019 | case DVB_CA_SLOTSTATE_NONE: | ||
| 1020 | case DVB_CA_SLOTSTATE_INVALID: | ||
| 1021 | // no action needed | ||
| 1022 | break; | ||
| 1023 | |||
| 1024 | case DVB_CA_SLOTSTATE_UNINITIALISED: | ||
| 1025 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITREADY; | ||
| 1026 | ca->pub->slot_reset(ca->pub, slot); | ||
| 1027 | ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ); | ||
| 1028 | break; | ||
| 1029 | |||
| 1030 | case DVB_CA_SLOTSTATE_WAITREADY: | ||
| 1031 | if (time_after(jiffies, ca->slot_info[slot].timeout)) { | ||
| 1032 | printk("dvb_ca adaptor %d: PC card did not respond :(\n", | ||
| 1033 | ca->dvbdev->adapter->num); | ||
| 1034 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; | ||
| 1035 | dvb_ca_en50221_thread_update_delay(ca); | ||
| 1036 | break; | ||
| 1037 | } | ||
| 1038 | // no other action needed; will automatically change state when ready | ||
| 1039 | break; | ||
| 1040 | |||
| 1041 | case DVB_CA_SLOTSTATE_VALIDATE: | ||
| 1042 | if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) { | ||
| 1043 | /* we need this extra check for annoying interfaces like the budget-av */ | ||
| 1044 | if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) && | ||
| 1045 | (ca->pub->poll_slot_status)) { | ||
| 1046 | status = ca->pub->poll_slot_status(ca->pub, slot, 0); | ||
| 1047 | if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) { | ||
| 1048 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; | ||
| 1049 | dvb_ca_en50221_thread_update_delay(ca); | ||
| 1050 | break; | ||
| 1051 | } | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | printk("dvb_ca adapter %d: Invalid PC card inserted :(\n", | ||
| 1055 | ca->dvbdev->adapter->num); | ||
| 1056 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; | ||
| 1057 | dvb_ca_en50221_thread_update_delay(ca); | ||
| 1058 | break; | ||
| 1059 | } | ||
| 1060 | if (dvb_ca_en50221_set_configoption(ca, slot) != 0) { | ||
| 1061 | printk("dvb_ca adapter %d: Unable to initialise CAM :(\n", | ||
| 1062 | ca->dvbdev->adapter->num); | ||
| 1063 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; | ||
| 1064 | dvb_ca_en50221_thread_update_delay(ca); | ||
| 1065 | break; | ||
| 1066 | } | ||
| 1067 | if (ca->pub->write_cam_control(ca->pub, slot, | ||
| 1068 | CTRLIF_COMMAND, CMDREG_RS) != 0) { | ||
| 1069 | printk("dvb_ca adapter %d: Unable to reset CAM IF\n", | ||
| 1070 | ca->dvbdev->adapter->num); | ||
| 1071 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; | ||
| 1072 | dvb_ca_en50221_thread_update_delay(ca); | ||
| 1073 | break; | ||
| 1074 | } | ||
| 1075 | dprintk("DVB CAM validated successfully\n"); | ||
| 1076 | |||
| 1077 | ca->slot_info[slot].timeout = jiffies + (INIT_TIMEOUT_SECS * HZ); | ||
| 1078 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_WAITFR; | ||
| 1079 | ca->wakeup = 1; | ||
| 1080 | break; | ||
| 1081 | |||
| 1082 | case DVB_CA_SLOTSTATE_WAITFR: | ||
| 1083 | if (time_after(jiffies, ca->slot_info[slot].timeout)) { | ||
| 1084 | printk("dvb_ca adapter %d: DVB CAM did not respond :(\n", | ||
| 1085 | ca->dvbdev->adapter->num); | ||
| 1086 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; | ||
| 1087 | dvb_ca_en50221_thread_update_delay(ca); | ||
| 1088 | break; | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | flags = ca->pub->read_cam_control(ca->pub, slot, CTRLIF_STATUS); | ||
| 1092 | if (flags & STATUSREG_FR) { | ||
| 1093 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_LINKINIT; | ||
| 1094 | ca->wakeup = 1; | ||
| 1095 | } | ||
| 1096 | break; | ||
| 1097 | |||
| 1098 | case DVB_CA_SLOTSTATE_LINKINIT: | ||
| 1099 | if (dvb_ca_en50221_link_init(ca, slot) != 0) { | ||
| 1100 | /* we need this extra check for annoying interfaces like the budget-av */ | ||
| 1101 | if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) && | ||
| 1102 | (ca->pub->poll_slot_status)) { | ||
| 1103 | status = ca->pub->poll_slot_status(ca->pub, slot, 0); | ||
| 1104 | if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) { | ||
| 1105 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; | ||
| 1106 | dvb_ca_en50221_thread_update_delay(ca); | ||
| 1107 | break; | ||
| 1108 | } | ||
| 1109 | } | ||
| 1110 | |||
| 1111 | printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num); | ||
| 1112 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; | ||
| 1113 | dvb_ca_en50221_thread_update_delay(ca); | ||
| 1114 | break; | ||
| 1115 | } | ||
| 1116 | |||
| 1117 | if (ca->slot_info[slot].rx_buffer.data == NULL) { | ||
| 1118 | rxbuf = vmalloc(RX_BUFFER_SIZE); | ||
| 1119 | if (rxbuf == NULL) { | ||
| 1120 | printk("dvb_ca adapter %d: Unable to allocate CAM rx buffer :(\n", ca->dvbdev->adapter->num); | ||
| 1121 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; | ||
| 1122 | dvb_ca_en50221_thread_update_delay(ca); | ||
| 1123 | break; | ||
| 1124 | } | ||
| 1125 | dvb_ringbuffer_init(&ca->slot_info[slot].rx_buffer, rxbuf, RX_BUFFER_SIZE); | ||
| 1126 | } | ||
| 1127 | |||
| 1128 | ca->pub->slot_ts_enable(ca->pub, slot); | ||
| 1129 | ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_RUNNING; | ||
| 1130 | dvb_ca_en50221_thread_update_delay(ca); | ||
| 1131 | printk("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", ca->dvbdev->adapter->num); | ||
| 1132 | break; | ||
| 1133 | |||
| 1134 | case DVB_CA_SLOTSTATE_RUNNING: | ||
| 1135 | if (!ca->open) | ||
| 1136 | break; | ||
| 1137 | |||
| 1138 | // poll slots for data | ||
| 1139 | pktcount = 0; | ||
| 1140 | while ((status = dvb_ca_en50221_read_data(ca, slot, NULL, 0)) > 0) { | ||
| 1141 | if (!ca->open) | ||
| 1142 | break; | ||
| 1143 | |||
| 1144 | /* if a CAMCHANGE occurred at some point, do not do any more processing of this slot */ | ||
| 1145 | if (dvb_ca_en50221_check_camstatus(ca, slot)) { | ||
| 1146 | // we dont want to sleep on the next iteration so we can handle the cam change | ||
| 1147 | ca->wakeup = 1; | ||
| 1148 | break; | ||
| 1149 | } | ||
| 1150 | |||
| 1151 | /* check if we've hit our limit this time */ | ||
| 1152 | if (++pktcount >= MAX_RX_PACKETS_PER_ITERATION) { | ||
| 1153 | // dont sleep; there is likely to be more data to read | ||
| 1154 | ca->wakeup = 1; | ||
| 1155 | break; | ||
| 1156 | } | ||
| 1157 | } | ||
| 1158 | break; | ||
| 1159 | } | ||
| 1160 | |||
| 1161 | mutex_unlock(&ca->slot_info[slot].slot_lock); | ||
| 1162 | } | ||
| 1163 | } | ||
| 1164 | |||
| 1165 | return 0; | ||
| 1166 | } | ||
| 1167 | |||
| 1168 | |||
| 1169 | |||
| 1170 | /* ******************************************************************************** */ | ||
| 1171 | /* EN50221 IO interface functions */ | ||
| 1172 | |||
| 1173 | /** | ||
| 1174 | * Real ioctl implementation. | ||
| 1175 | * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them. | ||
| 1176 | * | ||
| 1177 | * @param inode Inode concerned. | ||
| 1178 | * @param file File concerned. | ||
| 1179 | * @param cmd IOCTL command. | ||
| 1180 | * @param arg Associated argument. | ||
| 1181 | * | ||
| 1182 | * @return 0 on success, <0 on error. | ||
| 1183 | */ | ||
| 1184 | static int dvb_ca_en50221_io_do_ioctl(struct file *file, | ||
| 1185 | unsigned int cmd, void *parg) | ||
| 1186 | { | ||
| 1187 | struct dvb_device *dvbdev = file->private_data; | ||
| 1188 | struct dvb_ca_private *ca = dvbdev->priv; | ||
| 1189 | int err = 0; | ||
| 1190 | int slot; | ||
| 1191 | |||
| 1192 | dprintk("%s\n", __func__); | ||
| 1193 | |||
| 1194 | switch (cmd) { | ||
| 1195 | case CA_RESET: | ||
| 1196 | for (slot = 0; slot < ca->slot_count; slot++) { | ||
| 1197 | mutex_lock(&ca->slot_info[slot].slot_lock); | ||
| 1198 | if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_NONE) { | ||
| 1199 | dvb_ca_en50221_slot_shutdown(ca, slot); | ||
| 1200 | if (ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE) | ||
| 1201 | dvb_ca_en50221_camchange_irq(ca->pub, | ||
| 1202 | slot, | ||
| 1203 | DVB_CA_EN50221_CAMCHANGE_INSERTED); | ||
| 1204 | } | ||
| 1205 | mutex_unlock(&ca->slot_info[slot].slot_lock); | ||
| 1206 | } | ||
| 1207 | ca->next_read_slot = 0; | ||
| 1208 | dvb_ca_en50221_thread_wakeup(ca); | ||
| 1209 | break; | ||
| 1210 | |||
| 1211 | case CA_GET_CAP: { | ||
| 1212 | struct ca_caps *caps = parg; | ||
| 1213 | |||
| 1214 | caps->slot_num = ca->slot_count; | ||
| 1215 | caps->slot_type = CA_CI_LINK; | ||
| 1216 | caps->descr_num = 0; | ||
| 1217 | caps->descr_type = 0; | ||
| 1218 | break; | ||
| 1219 | } | ||
| 1220 | |||
| 1221 | case CA_GET_SLOT_INFO: { | ||
| 1222 | struct ca_slot_info *info = parg; | ||
| 1223 | |||
| 1224 | if ((info->num > ca->slot_count) || (info->num < 0)) | ||
| 1225 | return -EINVAL; | ||
| 1226 | |||
| 1227 | info->type = CA_CI_LINK; | ||
| 1228 | info->flags = 0; | ||
| 1229 | if ((ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_NONE) | ||
| 1230 | && (ca->slot_info[info->num].slot_state != DVB_CA_SLOTSTATE_INVALID)) { | ||
| 1231 | info->flags = CA_CI_MODULE_PRESENT; | ||
| 1232 | } | ||
| 1233 | if (ca->slot_info[info->num].slot_state == DVB_CA_SLOTSTATE_RUNNING) { | ||
| 1234 | info->flags |= CA_CI_MODULE_READY; | ||
| 1235 | } | ||
| 1236 | break; | ||
| 1237 | } | ||
| 1238 | |||
| 1239 | default: | ||
| 1240 | err = -EINVAL; | ||
| 1241 | break; | ||
| 1242 | } | ||
| 1243 | |||
| 1244 | return err; | ||
| 1245 | } | ||
| 1246 | |||
| 1247 | |||
| 1248 | /** | ||
| 1249 | * Wrapper for ioctl implementation. | ||
| 1250 | * | ||
| 1251 | * @param inode Inode concerned. | ||
| 1252 | * @param file File concerned. | ||
| 1253 | * @param cmd IOCTL command. | ||
| 1254 | * @param arg Associated argument. | ||
| 1255 | * | ||
| 1256 | * @return 0 on success, <0 on error. | ||
| 1257 | */ | ||
| 1258 | static long dvb_ca_en50221_io_ioctl(struct file *file, | ||
| 1259 | unsigned int cmd, unsigned long arg) | ||
| 1260 | { | ||
| 1261 | return dvb_usercopy(file, cmd, arg, dvb_ca_en50221_io_do_ioctl); | ||
| 1262 | } | ||
| 1263 | |||
| 1264 | |||
| 1265 | /** | ||
| 1266 | * Implementation of write() syscall. | ||
| 1267 | * | ||
| 1268 | * @param file File structure. | ||
| 1269 | * @param buf Source buffer. | ||
| 1270 | * @param count Size of source buffer. | ||
| 1271 | * @param ppos Position in file (ignored). | ||
| 1272 | * | ||
| 1273 | * @return Number of bytes read, or <0 on error. | ||
| 1274 | */ | ||
| 1275 | static ssize_t dvb_ca_en50221_io_write(struct file *file, | ||
| 1276 | const char __user * buf, size_t count, loff_t * ppos) | ||
| 1277 | { | ||
| 1278 | struct dvb_device *dvbdev = file->private_data; | ||
| 1279 | struct dvb_ca_private *ca = dvbdev->priv; | ||
| 1280 | u8 slot, connection_id; | ||
| 1281 | int status; | ||
| 1282 | u8 fragbuf[HOST_LINK_BUF_SIZE]; | ||
| 1283 | int fragpos = 0; | ||
| 1284 | int fraglen; | ||
| 1285 | unsigned long timeout; | ||
| 1286 | int written; | ||
| 1287 | |||
| 1288 | dprintk("%s\n", __func__); | ||
| 1289 | |||
| 1290 | /* Incoming packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */ | ||
| 1291 | if (count < 2) | ||
| 1292 | return -EINVAL; | ||
| 1293 | |||
| 1294 | /* extract slot & connection id */ | ||
| 1295 | if (copy_from_user(&slot, buf, 1)) | ||
| 1296 | return -EFAULT; | ||
| 1297 | if (copy_from_user(&connection_id, buf + 1, 1)) | ||
| 1298 | return -EFAULT; | ||
| 1299 | buf += 2; | ||
| 1300 | count -= 2; | ||
| 1301 | |||
| 1302 | /* check if the slot is actually running */ | ||
| 1303 | if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) | ||
| 1304 | return -EINVAL; | ||
| 1305 | |||
| 1306 | /* fragment the packets & store in the buffer */ | ||
| 1307 | while (fragpos < count) { | ||
| 1308 | fraglen = ca->slot_info[slot].link_buf_size - 2; | ||
| 1309 | if ((count - fragpos) < fraglen) | ||
| 1310 | fraglen = count - fragpos; | ||
| 1311 | |||
| 1312 | fragbuf[0] = connection_id; | ||
| 1313 | fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00; | ||
| 1314 | status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen); | ||
| 1315 | if (status) { | ||
| 1316 | status = -EFAULT; | ||
| 1317 | goto exit; | ||
| 1318 | } | ||
| 1319 | |||
| 1320 | timeout = jiffies + HZ / 2; | ||
| 1321 | written = 0; | ||
| 1322 | while (!time_after(jiffies, timeout)) { | ||
| 1323 | /* check the CAM hasn't been removed/reset in the meantime */ | ||
| 1324 | if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) { | ||
| 1325 | status = -EIO; | ||
| 1326 | goto exit; | ||
| 1327 | } | ||
| 1328 | |||
| 1329 | mutex_lock(&ca->slot_info[slot].slot_lock); | ||
| 1330 | status = dvb_ca_en50221_write_data(ca, slot, fragbuf, fraglen + 2); | ||
| 1331 | mutex_unlock(&ca->slot_info[slot].slot_lock); | ||
| 1332 | if (status == (fraglen + 2)) { | ||
| 1333 | written = 1; | ||
| 1334 | break; | ||
| 1335 | } | ||
| 1336 | if (status != -EAGAIN) | ||
| 1337 | goto exit; | ||
| 1338 | |||
| 1339 | msleep(1); | ||
| 1340 | } | ||
| 1341 | if (!written) { | ||
| 1342 | status = -EIO; | ||
| 1343 | goto exit; | ||
| 1344 | } | ||
| 1345 | |||
| 1346 | fragpos += fraglen; | ||
| 1347 | } | ||
| 1348 | status = count + 2; | ||
| 1349 | |||
| 1350 | exit: | ||
| 1351 | return status; | ||
| 1352 | } | ||
| 1353 | |||
| 1354 | |||
| 1355 | /** | ||
| 1356 | * Condition for waking up in dvb_ca_en50221_io_read_condition | ||
| 1357 | */ | ||
| 1358 | static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, | ||
| 1359 | int *result, int *_slot) | ||
| 1360 | { | ||
| 1361 | int slot; | ||
| 1362 | int slot_count = 0; | ||
| 1363 | int idx; | ||
| 1364 | size_t fraglen; | ||
| 1365 | int connection_id = -1; | ||
| 1366 | int found = 0; | ||
| 1367 | u8 hdr[2]; | ||
| 1368 | |||
| 1369 | slot = ca->next_read_slot; | ||
| 1370 | while ((slot_count < ca->slot_count) && (!found)) { | ||
| 1371 | if (ca->slot_info[slot].slot_state != DVB_CA_SLOTSTATE_RUNNING) | ||
| 1372 | goto nextslot; | ||
| 1373 | |||
| 1374 | if (ca->slot_info[slot].rx_buffer.data == NULL) { | ||
| 1375 | return 0; | ||
| 1376 | } | ||
| 1377 | |||
| 1378 | idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen); | ||
| 1379 | while (idx != -1) { | ||
| 1380 | dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2); | ||
| 1381 | if (connection_id == -1) | ||
| 1382 | connection_id = hdr[0]; | ||
| 1383 | if ((hdr[0] == connection_id) && ((hdr[1] & 0x80) == 0)) { | ||
| 1384 | *_slot = slot; | ||
| 1385 | found = 1; | ||
| 1386 | break; | ||
| 1387 | } | ||
| 1388 | |||
| 1389 | idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen); | ||
| 1390 | } | ||
| 1391 | |||
| 1392 | nextslot: | ||
| 1393 | slot = (slot + 1) % ca->slot_count; | ||
| 1394 | slot_count++; | ||
| 1395 | } | ||
| 1396 | |||
| 1397 | ca->next_read_slot = slot; | ||
| 1398 | return found; | ||
| 1399 | } | ||
| 1400 | |||
| 1401 | |||
| 1402 | /** | ||
| 1403 | * Implementation of read() syscall. | ||
| 1404 | * | ||
| 1405 | * @param file File structure. | ||
| 1406 | * @param buf Destination buffer. | ||
| 1407 | * @param count Size of destination buffer. | ||
| 1408 | * @param ppos Position in file (ignored). | ||
| 1409 | * | ||
| 1410 | * @return Number of bytes read, or <0 on error. | ||
| 1411 | */ | ||
| 1412 | static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf, | ||
| 1413 | size_t count, loff_t * ppos) | ||
| 1414 | { | ||
| 1415 | struct dvb_device *dvbdev = file->private_data; | ||
| 1416 | struct dvb_ca_private *ca = dvbdev->priv; | ||
| 1417 | int status; | ||
| 1418 | int result = 0; | ||
| 1419 | u8 hdr[2]; | ||
| 1420 | int slot; | ||
| 1421 | int connection_id = -1; | ||
| 1422 | size_t idx, idx2; | ||
| 1423 | int last_fragment = 0; | ||
| 1424 | size_t fraglen; | ||
| 1425 | int pktlen; | ||
| 1426 | int dispose = 0; | ||
| 1427 | |||
| 1428 | dprintk("%s\n", __func__); | ||
| 1429 | |||
| 1430 | /* Outgoing packet has a 2 byte header. hdr[0] = slot_id, hdr[1] = connection_id */ | ||
| 1431 | if (count < 2) | ||
| 1432 | return -EINVAL; | ||
| 1433 | |||
| 1434 | /* wait for some data */ | ||
| 1435 | if ((status = dvb_ca_en50221_io_read_condition(ca, &result, &slot)) == 0) { | ||
| 1436 | |||
| 1437 | /* if we're in nonblocking mode, exit immediately */ | ||
| 1438 | if (file->f_flags & O_NONBLOCK) | ||
| 1439 | return -EWOULDBLOCK; | ||
| 1440 | |||
| 1441 | /* wait for some data */ | ||
| 1442 | status = wait_event_interruptible(ca->wait_queue, | ||
| 1443 | dvb_ca_en50221_io_read_condition | ||
| 1444 | (ca, &result, &slot)); | ||
| 1445 | } | ||
| 1446 | if ((status < 0) || (result < 0)) { | ||
| 1447 | if (result) | ||
| 1448 | return result; | ||
| 1449 | return status; | ||
| 1450 | } | ||
| 1451 | |||
| 1452 | idx = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, -1, &fraglen); | ||
| 1453 | pktlen = 2; | ||
| 1454 | do { | ||
| 1455 | if (idx == -1) { | ||
| 1456 | printk("dvb_ca adapter %d: BUG: read packet ended before last_fragment encountered\n", ca->dvbdev->adapter->num); | ||
| 1457 | status = -EIO; | ||
| 1458 | goto exit; | ||
| 1459 | } | ||
| 1460 | |||
| 1461 | dvb_ringbuffer_pkt_read(&ca->slot_info[slot].rx_buffer, idx, 0, hdr, 2); | ||
| 1462 | if (connection_id == -1) | ||
| 1463 | connection_id = hdr[0]; | ||
| 1464 | if (hdr[0] == connection_id) { | ||
| 1465 | if (pktlen < count) { | ||
| 1466 | if ((pktlen + fraglen - 2) > count) { | ||
| 1467 | fraglen = count - pktlen; | ||
| 1468 | } else { | ||
| 1469 | fraglen -= 2; | ||
| 1470 | } | ||
| 1471 | |||
| 1472 | if ((status = dvb_ringbuffer_pkt_read_user(&ca->slot_info[slot].rx_buffer, idx, 2, | ||
| 1473 | buf + pktlen, fraglen)) < 0) { | ||
| 1474 | goto exit; | ||
| 1475 | } | ||
| 1476 | pktlen += fraglen; | ||
| 1477 | } | ||
| 1478 | |||
| 1479 | if ((hdr[1] & 0x80) == 0) | ||
| 1480 | last_fragment = 1; | ||
| 1481 | dispose = 1; | ||
| 1482 | } | ||
| 1483 | |||
| 1484 | idx2 = dvb_ringbuffer_pkt_next(&ca->slot_info[slot].rx_buffer, idx, &fraglen); | ||
| 1485 | if (dispose) | ||
| 1486 | dvb_ringbuffer_pkt_dispose(&ca->slot_info[slot].rx_buffer, idx); | ||
| 1487 | idx = idx2; | ||
| 1488 | dispose = 0; | ||
| 1489 | } while (!last_fragment); | ||
| 1490 | |||
| 1491 | hdr[0] = slot; | ||
| 1492 | hdr[1] = connection_id; | ||
| 1493 | status = copy_to_user(buf, hdr, 2); | ||
| 1494 | if (status) { | ||
| 1495 | status = -EFAULT; | ||
| 1496 | goto exit; | ||
| 1497 | } | ||
| 1498 | status = pktlen; | ||
| 1499 | |||
| 1500 | exit: | ||
| 1501 | return status; | ||
| 1502 | } | ||
| 1503 | |||
| 1504 | |||
| 1505 | /** | ||
| 1506 | * Implementation of file open syscall. | ||
| 1507 | * | ||
| 1508 | * @param inode Inode concerned. | ||
| 1509 | * @param file File concerned. | ||
| 1510 | * | ||
| 1511 | * @return 0 on success, <0 on failure. | ||
| 1512 | */ | ||
| 1513 | static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) | ||
| 1514 | { | ||
| 1515 | struct dvb_device *dvbdev = file->private_data; | ||
| 1516 | struct dvb_ca_private *ca = dvbdev->priv; | ||
| 1517 | int err; | ||
| 1518 | int i; | ||
| 1519 | |||
| 1520 | dprintk("%s\n", __func__); | ||
| 1521 | |||
| 1522 | if (!try_module_get(ca->pub->owner)) | ||
| 1523 | return -EIO; | ||
| 1524 | |||
| 1525 | err = dvb_generic_open(inode, file); | ||
| 1526 | if (err < 0) { | ||
| 1527 | module_put(ca->pub->owner); | ||
| 1528 | return err; | ||
| 1529 | } | ||
| 1530 | |||
| 1531 | for (i = 0; i < ca->slot_count; i++) { | ||
| 1532 | |||
| 1533 | if (ca->slot_info[i].slot_state == DVB_CA_SLOTSTATE_RUNNING) { | ||
| 1534 | if (ca->slot_info[i].rx_buffer.data != NULL) { | ||
| 1535 | /* it is safe to call this here without locks because | ||
| 1536 | * ca->open == 0. Data is not read in this case */ | ||
| 1537 | dvb_ringbuffer_flush(&ca->slot_info[i].rx_buffer); | ||
| 1538 | } | ||
| 1539 | } | ||
| 1540 | } | ||
| 1541 | |||
| 1542 | ca->open = 1; | ||
| 1543 | dvb_ca_en50221_thread_update_delay(ca); | ||
| 1544 | dvb_ca_en50221_thread_wakeup(ca); | ||
| 1545 | |||
| 1546 | return 0; | ||
| 1547 | } | ||
| 1548 | |||
| 1549 | |||
| 1550 | /** | ||
| 1551 | * Implementation of file close syscall. | ||
| 1552 | * | ||
| 1553 | * @param inode Inode concerned. | ||
| 1554 | * @param file File concerned. | ||
| 1555 | * | ||
| 1556 | * @return 0 on success, <0 on failure. | ||
| 1557 | */ | ||
| 1558 | static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) | ||
| 1559 | { | ||
| 1560 | struct dvb_device *dvbdev = file->private_data; | ||
| 1561 | struct dvb_ca_private *ca = dvbdev->priv; | ||
| 1562 | int err; | ||
| 1563 | |||
| 1564 | dprintk("%s\n", __func__); | ||
| 1565 | |||
| 1566 | /* mark the CA device as closed */ | ||
| 1567 | ca->open = 0; | ||
| 1568 | dvb_ca_en50221_thread_update_delay(ca); | ||
| 1569 | |||
| 1570 | err = dvb_generic_release(inode, file); | ||
| 1571 | |||
| 1572 | module_put(ca->pub->owner); | ||
| 1573 | |||
| 1574 | return err; | ||
| 1575 | } | ||
| 1576 | |||
| 1577 | |||
| 1578 | /** | ||
| 1579 | * Implementation of poll() syscall. | ||
| 1580 | * | ||
| 1581 | * @param file File concerned. | ||
| 1582 | * @param wait poll wait table. | ||
| 1583 | * | ||
| 1584 | * @return Standard poll mask. | ||
| 1585 | */ | ||
| 1586 | static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table * wait) | ||
| 1587 | { | ||
| 1588 | struct dvb_device *dvbdev = file->private_data; | ||
| 1589 | struct dvb_ca_private *ca = dvbdev->priv; | ||
| 1590 | unsigned int mask = 0; | ||
| 1591 | int slot; | ||
| 1592 | int result = 0; | ||
| 1593 | |||
| 1594 | dprintk("%s\n", __func__); | ||
| 1595 | |||
| 1596 | if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { | ||
| 1597 | mask |= POLLIN; | ||
| 1598 | } | ||
| 1599 | |||
| 1600 | /* if there is something, return now */ | ||
| 1601 | if (mask) | ||
| 1602 | return mask; | ||
| 1603 | |||
| 1604 | /* wait for something to happen */ | ||
| 1605 | poll_wait(file, &ca->wait_queue, wait); | ||
| 1606 | |||
| 1607 | if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) { | ||
| 1608 | mask |= POLLIN; | ||
| 1609 | } | ||
| 1610 | |||
| 1611 | return mask; | ||
| 1612 | } | ||
| 1613 | EXPORT_SYMBOL(dvb_ca_en50221_init); | ||
| 1614 | |||
| 1615 | |||
| 1616 | static const struct file_operations dvb_ca_fops = { | ||
| 1617 | .owner = THIS_MODULE, | ||
| 1618 | .read = dvb_ca_en50221_io_read, | ||
| 1619 | .write = dvb_ca_en50221_io_write, | ||
| 1620 | .unlocked_ioctl = dvb_ca_en50221_io_ioctl, | ||
| 1621 | .open = dvb_ca_en50221_io_open, | ||
| 1622 | .release = dvb_ca_en50221_io_release, | ||
| 1623 | .poll = dvb_ca_en50221_io_poll, | ||
| 1624 | .llseek = noop_llseek, | ||
| 1625 | }; | ||
| 1626 | |||
| 1627 | static struct dvb_device dvbdev_ca = { | ||
| 1628 | .priv = NULL, | ||
| 1629 | .users = 1, | ||
| 1630 | .readers = 1, | ||
| 1631 | .writers = 1, | ||
| 1632 | .fops = &dvb_ca_fops, | ||
| 1633 | }; | ||
| 1634 | |||
| 1635 | |||
| 1636 | /* ******************************************************************************** */ | ||
| 1637 | /* Initialisation/shutdown functions */ | ||
| 1638 | |||
| 1639 | |||
| 1640 | /** | ||
| 1641 | * Initialise a new DVB CA EN50221 interface device. | ||
| 1642 | * | ||
| 1643 | * @param dvb_adapter DVB adapter to attach the new CA device to. | ||
| 1644 | * @param ca The dvb_ca instance. | ||
| 1645 | * @param flags Flags describing the CA device (DVB_CA_FLAG_*). | ||
| 1646 | * @param slot_count Number of slots supported. | ||
| 1647 | * | ||
| 1648 | * @return 0 on success, nonzero on failure | ||
| 1649 | */ | ||
| 1650 | int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, | ||
| 1651 | struct dvb_ca_en50221 *pubca, int flags, int slot_count) | ||
| 1652 | { | ||
| 1653 | int ret; | ||
| 1654 | struct dvb_ca_private *ca = NULL; | ||
| 1655 | int i; | ||
| 1656 | |||
| 1657 | dprintk("%s\n", __func__); | ||
| 1658 | |||
| 1659 | if (slot_count < 1) | ||
| 1660 | return -EINVAL; | ||
| 1661 | |||
| 1662 | /* initialise the system data */ | ||
| 1663 | if ((ca = kzalloc(sizeof(struct dvb_ca_private), GFP_KERNEL)) == NULL) { | ||
| 1664 | ret = -ENOMEM; | ||
| 1665 | goto error; | ||
| 1666 | } | ||
| 1667 | ca->pub = pubca; | ||
| 1668 | ca->flags = flags; | ||
| 1669 | ca->slot_count = slot_count; | ||
| 1670 | if ((ca->slot_info = kcalloc(slot_count, sizeof(struct dvb_ca_slot), GFP_KERNEL)) == NULL) { | ||
| 1671 | ret = -ENOMEM; | ||
| 1672 | goto error; | ||
| 1673 | } | ||
| 1674 | init_waitqueue_head(&ca->wait_queue); | ||
| 1675 | ca->open = 0; | ||
| 1676 | ca->wakeup = 0; | ||
| 1677 | ca->next_read_slot = 0; | ||
| 1678 | pubca->private = ca; | ||
| 1679 | |||
| 1680 | /* register the DVB device */ | ||
| 1681 | ret = dvb_register_device(dvb_adapter, &ca->dvbdev, &dvbdev_ca, ca, DVB_DEVICE_CA); | ||
| 1682 | if (ret) | ||
| 1683 | goto error; | ||
| 1684 | |||
| 1685 | /* now initialise each slot */ | ||
| 1686 | for (i = 0; i < slot_count; i++) { | ||
| 1687 | memset(&ca->slot_info[i], 0, sizeof(struct dvb_ca_slot)); | ||
| 1688 | ca->slot_info[i].slot_state = DVB_CA_SLOTSTATE_NONE; | ||
| 1689 | atomic_set(&ca->slot_info[i].camchange_count, 0); | ||
| 1690 | ca->slot_info[i].camchange_type = DVB_CA_EN50221_CAMCHANGE_REMOVED; | ||
| 1691 | mutex_init(&ca->slot_info[i].slot_lock); | ||
| 1692 | } | ||
| 1693 | |||
| 1694 | if (signal_pending(current)) { | ||
| 1695 | ret = -EINTR; | ||
| 1696 | goto error; | ||
| 1697 | } | ||
| 1698 | mb(); | ||
| 1699 | |||
| 1700 | /* create a kthread for monitoring this CA device */ | ||
| 1701 | ca->thread = kthread_run(dvb_ca_en50221_thread, ca, "kdvb-ca-%i:%i", | ||
| 1702 | ca->dvbdev->adapter->num, ca->dvbdev->id); | ||
| 1703 | if (IS_ERR(ca->thread)) { | ||
| 1704 | ret = PTR_ERR(ca->thread); | ||
| 1705 | printk("dvb_ca_init: failed to start kernel_thread (%d)\n", | ||
| 1706 | ret); | ||
| 1707 | goto error; | ||
| 1708 | } | ||
| 1709 | return 0; | ||
| 1710 | |||
| 1711 | error: | ||
| 1712 | if (ca != NULL) { | ||
| 1713 | if (ca->dvbdev != NULL) | ||
| 1714 | dvb_unregister_device(ca->dvbdev); | ||
| 1715 | kfree(ca->slot_info); | ||
| 1716 | kfree(ca); | ||
| 1717 | } | ||
| 1718 | pubca->private = NULL; | ||
| 1719 | return ret; | ||
| 1720 | } | ||
| 1721 | EXPORT_SYMBOL(dvb_ca_en50221_release); | ||
| 1722 | |||
| 1723 | |||
| 1724 | |||
| 1725 | /** | ||
| 1726 | * Release a DVB CA EN50221 interface device. | ||
| 1727 | * | ||
| 1728 | * @param ca_dev The dvb_device_t instance for the CA device. | ||
| 1729 | * @param ca The associated dvb_ca instance. | ||
| 1730 | */ | ||
| 1731 | void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) | ||
| 1732 | { | ||
| 1733 | struct dvb_ca_private *ca = pubca->private; | ||
| 1734 | int i; | ||
| 1735 | |||
| 1736 | dprintk("%s\n", __func__); | ||
| 1737 | |||
| 1738 | /* shutdown the thread if there was one */ | ||
| 1739 | kthread_stop(ca->thread); | ||
| 1740 | |||
| 1741 | for (i = 0; i < ca->slot_count; i++) { | ||
| 1742 | dvb_ca_en50221_slot_shutdown(ca, i); | ||
| 1743 | vfree(ca->slot_info[i].rx_buffer.data); | ||
| 1744 | } | ||
| 1745 | kfree(ca->slot_info); | ||
| 1746 | dvb_unregister_device(ca->dvbdev); | ||
| 1747 | kfree(ca); | ||
| 1748 | pubca->private = NULL; | ||
| 1749 | } | ||
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.h b/drivers/media/dvb/dvb-core/dvb_ca_en50221.h new file mode 100644 index 00000000000..7df2e141187 --- /dev/null +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.h | |||
| @@ -0,0 +1,136 @@ | |||
| 1 | /* | ||
| 2 | * dvb_ca.h: generic DVB functions for EN50221 CA interfaces | ||
| 3 | * | ||
| 4 | * Copyright (C) 2004 Andrew de Quincey | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public License | ||
| 8 | * as published by the Free Software Foundation; either version 2.1 | ||
| 9 | * of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef _DVB_CA_EN50221_H_ | ||
| 22 | #define _DVB_CA_EN50221_H_ | ||
| 23 | |||
| 24 | #include <linux/list.h> | ||
| 25 | #include <linux/dvb/ca.h> | ||
| 26 | |||
| 27 | #include "dvbdev.h" | ||
| 28 | |||
| 29 | #define DVB_CA_EN50221_POLL_CAM_PRESENT 1 | ||
| 30 | #define DVB_CA_EN50221_POLL_CAM_CHANGED 2 | ||
| 31 | #define DVB_CA_EN50221_POLL_CAM_READY 4 | ||
| 32 | |||
| 33 | #define DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE 1 | ||
| 34 | #define DVB_CA_EN50221_FLAG_IRQ_FR 2 | ||
| 35 | #define DVB_CA_EN50221_FLAG_IRQ_DA 4 | ||
| 36 | |||
| 37 | #define DVB_CA_EN50221_CAMCHANGE_REMOVED 0 | ||
| 38 | #define DVB_CA_EN50221_CAMCHANGE_INSERTED 1 | ||
| 39 | |||
| 40 | |||
| 41 | |||
| 42 | /* Structure describing a CA interface */ | ||
| 43 | struct dvb_ca_en50221 { | ||
| 44 | |||
| 45 | /* the module owning this structure */ | ||
| 46 | struct module* owner; | ||
| 47 | |||
| 48 | /* NOTE: the read_*, write_* and poll_slot_status functions will be | ||
| 49 | * called for different slots concurrently and need to use locks where | ||
| 50 | * and if appropriate. There will be no concurrent access to one slot. | ||
| 51 | */ | ||
| 52 | |||
| 53 | /* functions for accessing attribute memory on the CAM */ | ||
| 54 | int (*read_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address); | ||
| 55 | int (*write_attribute_mem)(struct dvb_ca_en50221* ca, int slot, int address, u8 value); | ||
| 56 | |||
| 57 | /* functions for accessing the control interface on the CAM */ | ||
| 58 | int (*read_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address); | ||
| 59 | int (*write_cam_control)(struct dvb_ca_en50221* ca, int slot, u8 address, u8 value); | ||
| 60 | |||
| 61 | /* Functions for controlling slots */ | ||
| 62 | int (*slot_reset)(struct dvb_ca_en50221* ca, int slot); | ||
| 63 | int (*slot_shutdown)(struct dvb_ca_en50221* ca, int slot); | ||
| 64 | int (*slot_ts_enable)(struct dvb_ca_en50221* ca, int slot); | ||
| 65 | |||
| 66 | /* | ||
| 67 | * Poll slot status. | ||
| 68 | * Only necessary if DVB_CA_FLAG_EN50221_IRQ_CAMCHANGE is not set | ||
| 69 | */ | ||
| 70 | int (*poll_slot_status)(struct dvb_ca_en50221* ca, int slot, int open); | ||
| 71 | |||
| 72 | /* private data, used by caller */ | ||
| 73 | void* data; | ||
| 74 | |||
| 75 | /* Opaque data used by the dvb_ca core. Do not modify! */ | ||
| 76 | void* private; | ||
| 77 | }; | ||
| 78 | |||
| 79 | |||
| 80 | |||
| 81 | |||
| 82 | /* ******************************************************************************** */ | ||
| 83 | /* Functions for reporting IRQ events */ | ||
| 84 | |||
| 85 | /** | ||
| 86 | * A CAMCHANGE IRQ has occurred. | ||
| 87 | * | ||
| 88 | * @param ca CA instance. | ||
| 89 | * @param slot Slot concerned. | ||
| 90 | * @param change_type One of the DVB_CA_CAMCHANGE_* values | ||
| 91 | */ | ||
| 92 | void dvb_ca_en50221_camchange_irq(struct dvb_ca_en50221* pubca, int slot, int change_type); | ||
| 93 | |||
| 94 | /** | ||
| 95 | * A CAMREADY IRQ has occurred. | ||
| 96 | * | ||
| 97 | * @param ca CA instance. | ||
| 98 | * @param slot Slot concerned. | ||
| 99 | */ | ||
| 100 | void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221* pubca, int slot); | ||
| 101 | |||
| 102 | /** | ||
| 103 | * An FR or a DA IRQ has occurred. | ||
| 104 | * | ||
| 105 | * @param ca CA instance. | ||
| 106 | * @param slot Slot concerned. | ||
| 107 | */ | ||
| 108 | void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221* ca, int slot); | ||
| 109 | |||
| 110 | |||
| 111 | |||
| 112 | /* ******************************************************************************** */ | ||
| 113 | /* Initialisation/shutdown functions */ | ||
| 114 | |||
| 115 | /** | ||
| 116 | * Initialise a new DVB CA device. | ||
| 117 | * | ||
| 118 | * @param dvb_adapter DVB adapter to attach the new CA device to. | ||
| 119 | * @param ca The dvb_ca instance. | ||
| 120 | * @param flags Flags describing the CA device (DVB_CA_EN50221_FLAG_*). | ||
| 121 | * @param slot_count Number of slots supported. | ||
| 122 | * | ||
| 123 | * @return 0 on success, nonzero on failure | ||
| 124 | */ | ||
| 125 | extern int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221* ca, int flags, int slot_count); | ||
| 126 | |||
| 127 | /** | ||
| 128 | * Release a DVB CA device. | ||
| 129 | * | ||
| 130 | * @param ca The associated dvb_ca instance. | ||
| 131 | */ | ||
| 132 | extern void dvb_ca_en50221_release(struct dvb_ca_en50221* ca); | ||
| 133 | |||
| 134 | |||
| 135 | |||
| 136 | #endif | ||
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c new file mode 100644 index 00000000000..faa3671b649 --- /dev/null +++ b/drivers/media/dvb/dvb-core/dvb_demux.c | |||
| @@ -0,0 +1,1299 @@ | |||
| 1 | /* | ||
| 2 | * dvb_demux.c - DVB kernel demux API | ||
| 3 | * | ||
| 4 | * Copyright (C) 2000-2001 Ralph Metzler <ralph@convergence.de> | ||
| 5 | * & Marcus Metzler <marcus@convergence.de> | ||
| 6 | * for convergence integrated media GmbH | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU Lesser General Public License | ||
| 10 | * as published by the Free Software Foundation; either version 2.1 | ||
| 11 | * of the License, or (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU Lesser General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 21 | * | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/sched.h> | ||
| 25 | #include <linux/spinlock.h> | ||
| 26 | #include <linux/slab.h> | ||
| 27 | #include <linux/vmalloc.h> | ||
| 28 | #include <linux/module.h> | ||
| 29 | #include <linux/poll.h> | ||
| 30 | #include <linux/string.h> | ||
| 31 | #include <linux/crc32.h> | ||
| 32 | #include <asm/uaccess.h> | ||
| 33 | #include <asm/div64.h> | ||
| 34 | |||
| 35 | #include "dvb_demux.h" | ||
| 36 | |||
| 37 | #define NOBUFS | ||
| 38 | /* | ||
| 39 | ** #define DVB_DEMUX_SECTION_LOSS_LOG to monitor payload loss in the syslog | ||
| 40 | */ | ||
| 41 | // #define DVB_DEMUX_SECTION_LOSS_LOG | ||
| 42 | |||
| 43 | static int dvb_demux_tscheck; | ||
| 44 | module_param(dvb_demux_tscheck, int, 0644); | ||
| 45 | MODULE_PARM_DESC(dvb_demux_tscheck, | ||
| 46 | "enable transport stream continuity and TEI check"); | ||
| 47 | |||
| 48 | static int dvb_demux_speedcheck; | ||
| 49 | module_param(dvb_demux_speedcheck, int, 0644); | ||
| 50 | MODULE_PARM_DESC(dvb_demux_speedcheck, | ||
| 51 | "enable transport stream speed check"); | ||
| 52 | |||
| 53 | #define dprintk_tscheck(x...) do { \ | ||
| 54 | if (dvb_demux_tscheck && printk_ratelimit()) \ | ||
| 55 | printk(x); \ | ||
| 56 | } while (0) | ||
| 57 | |||
| 58 | /****************************************************************************** | ||
| 59 | * static inlined helper functions | ||
| 60 | ******************************************************************************/ | ||
| 61 | |||
| 62 | static inline u16 section_length(const u8 *buf) | ||
| 63 | { | ||
| 64 | return 3 + ((buf[1] & 0x0f) << 8) + buf[2]; | ||
| 65 | } | ||
| 66 | |||
| 67 | static inline u16 ts_pid(const u8 *buf) | ||
| 68 | { | ||
| 69 | return ((buf[1] & 0x1f) << 8) + buf[2]; | ||
| 70 | } | ||
| 71 | |||
| 72 | static inline u8 payload(const u8 *tsp) | ||
| 73 | { | ||
| 74 | if (!(tsp[3] & 0x10)) // no payload? | ||
| 75 | return 0; | ||
| 76 | |||
| 77 | if (tsp[3] & 0x20) { // adaptation field? | ||
| 78 | if (tsp[4] > 183) // corrupted data? | ||
| 79 | return 0; | ||
| 80 | else | ||
| 81 | return 184 - 1 - tsp[4]; | ||
| 82 | } | ||
| 83 | |||
| 84 | return 184; | ||
| 85 | } | ||
| 86 | |||
| 87 | static u32 dvb_dmx_crc32(struct dvb_demux_feed *f, const u8 *src, size_t len) | ||
| 88 | { | ||
| 89 | return (f->feed.sec.crc_val = crc32_be(f->feed.sec.crc_val, src, len)); | ||
| 90 | } | ||
| 91 | |||
| 92 | static void dvb_dmx_memcopy(struct dvb_demux_feed *f, u8 *d, const u8 *s, | ||
| 93 | size_t len) | ||
| 94 | { | ||
| 95 | memcpy(d, s, len); | ||
| 96 | } | ||
| 97 | |||
| 98 | /****************************************************************************** | ||
| 99 | * Software filter functions | ||
| 100 | ******************************************************************************/ | ||
| 101 | |||
| 102 | static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed, | ||
| 103 | const u8 *buf) | ||
| 104 | { | ||
| 105 | int count = payload(buf); | ||
| 106 | int p; | ||
| 107 | //int ccok; | ||
| 108 | //u8 cc; | ||
| 109 | |||
| 110 | if (count == 0) | ||
| 111 | return -1; | ||
| 112 | |||
| 113 | p = 188 - count; | ||
| 114 | |||
| 115 | /* | ||
| 116 | cc = buf[3] & 0x0f; | ||
| 117 | ccok = ((feed->cc + 1) & 0x0f) == cc; | ||
| 118 | feed->cc = cc; | ||
| 119 | if (!ccok) | ||
| 120 | printk("missed packet!\n"); | ||
| 121 | */ | ||
| 122 | |||
| 123 | if (buf[1] & 0x40) // PUSI ? | ||
| 124 | feed->peslen = 0xfffa; | ||
| 125 | |||
| 126 | feed->peslen += count; | ||
| 127 | |||
| 128 | return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, DMX_OK); | ||
| 129 | } | ||
| 130 | |||
| 131 | static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed, | ||
| 132 | struct dvb_demux_filter *f) | ||
| 133 | { | ||
| 134 | u8 neq = 0; | ||
| 135 | int i; | ||
| 136 | |||
| 137 | for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { | ||
| 138 | u8 xor = f->filter.filter_value[i] ^ feed->feed.sec.secbuf[i]; | ||
| 139 | |||
| 140 | if (f->maskandmode[i] & xor) | ||
| 141 | return 0; | ||
| 142 | |||
| 143 | neq |= f->maskandnotmode[i] & xor; | ||
| 144 | } | ||
| 145 | |||
| 146 | if (f->doneq && !neq) | ||
| 147 | return 0; | ||
| 148 | |||
| 149 | return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen, | ||
| 150 | NULL, 0, &f->filter, DMX_OK); | ||
| 151 | } | ||
| 152 | |||
| 153 | static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed) | ||
| 154 | { | ||
| 155 | struct dvb_demux *demux = feed->demux; | ||
| 156 | struct dvb_demux_filter *f = feed->filter; | ||
| 157 | struct dmx_section_feed *sec = &feed->feed.sec; | ||
| 158 | int section_syntax_indicator; | ||
| 159 | |||
| 160 | if (!sec->is_filtering) | ||
| 161 | return 0; | ||
| 162 | |||
| 163 | if (!f) | ||
| 164 | return 0; | ||
| 165 | |||
| 166 | if (sec->check_crc) { | ||
| 167 | section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0); | ||
| 168 | if (section_syntax_indicator && | ||
| 169 | demux->check_crc32(feed, sec->secbuf, sec->seclen)) | ||
| 170 | return -1; | ||
| 171 | } | ||
| 172 | |||
| 173 | do { | ||
| 174 | if (dvb_dmx_swfilter_sectionfilter(feed, f) < 0) | ||
| 175 | return -1; | ||
| 176 | } while ((f = f->next) && sec->is_filtering); | ||
| 177 | |||
| 178 | sec->seclen = 0; | ||
| 179 | |||
| 180 | return 0; | ||
| 181 | } | ||
| 182 | |||
| 183 | static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) | ||
| 184 | { | ||
| 185 | struct dmx_section_feed *sec = &feed->feed.sec; | ||
| 186 | |||
| 187 | #ifdef DVB_DEMUX_SECTION_LOSS_LOG | ||
| 188 | if (sec->secbufp < sec->tsfeedp) { | ||
| 189 | int i, n = sec->tsfeedp - sec->secbufp; | ||
| 190 | |||
| 191 | /* | ||
| 192 | * Section padding is done with 0xff bytes entirely. | ||
| 193 | * Due to speed reasons, we won't check all of them | ||
| 194 | * but just first and last. | ||
| 195 | */ | ||
| 196 | if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) { | ||
| 197 | printk("dvb_demux.c section ts padding loss: %d/%d\n", | ||
| 198 | n, sec->tsfeedp); | ||
| 199 | printk("dvb_demux.c pad data:"); | ||
| 200 | for (i = 0; i < n; i++) | ||
| 201 | printk(" %02x", sec->secbuf[i]); | ||
| 202 | printk("\n"); | ||
| 203 | } | ||
| 204 | } | ||
| 205 | #endif | ||
| 206 | |||
| 207 | sec->tsfeedp = sec->secbufp = sec->seclen = 0; | ||
| 208 | sec->secbuf = sec->secbuf_base; | ||
| 209 | } | ||
| 210 | |||
| 211 | /* | ||
| 212 | * Losless Section Demux 1.4.1 by Emard | ||
| 213 | * Valsecchi Patrick: | ||
| 214 | * - middle of section A (no PUSI) | ||
| 215 | * - end of section A and start of section B | ||
| 216 | * (with PUSI pointing to the start of the second section) | ||
| 217 | * | ||
| 218 | * In this case, without feed->pusi_seen you'll receive a garbage section | ||
| 219 | * consisting of the end of section A. Basically because tsfeedp | ||
| 220 | * is incemented and the use=0 condition is not raised | ||
| 221 | * when the second packet arrives. | ||
| 222 | * | ||
| 223 | * Fix: | ||
| 224 | * when demux is started, let feed->pusi_seen = 0 to | ||
| 225 | * prevent initial feeding of garbage from the end of | ||
| 226 | * previous section. When you for the first time see PUSI=1 | ||
| 227 | * then set feed->pusi_seen = 1 | ||
| 228 | */ | ||
| 229 | static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, | ||
| 230 | const u8 *buf, u8 len) | ||
| 231 | { | ||
| 232 | struct dvb_demux *demux = feed->demux; | ||
| 233 | struct dmx_section_feed *sec = &feed->feed.sec; | ||
| 234 | u16 limit, seclen, n; | ||
| 235 | |||
| 236 | if (sec->tsfeedp >= DMX_MAX_SECFEED_SIZE) | ||
| 237 | return 0; | ||
| 238 | |||
| 239 | if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) { | ||
| 240 | #ifdef DVB_DEMUX_SECTION_LOSS_LOG | ||
| 241 | printk("dvb_demux.c section buffer full loss: %d/%d\n", | ||
| 242 | sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, | ||
| 243 | DMX_MAX_SECFEED_SIZE); | ||
| 244 | #endif | ||
| 245 | len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp; | ||
| 246 | } | ||
| 247 | |||
| 248 | if (len <= 0) | ||
| 249 | return 0; | ||
| 250 | |||
| 251 | demux->memcopy(feed, sec->secbuf_base + sec->tsfeedp, buf, len); | ||
| 252 | sec->tsfeedp += len; | ||
| 253 | |||
| 254 | /* | ||
| 255 | * Dump all the sections we can find in the data (Emard) | ||
| 256 | */ | ||
| 257 | limit = sec->tsfeedp; | ||
| 258 | if (limit > DMX_MAX_SECFEED_SIZE) | ||
| 259 | return -1; /* internal error should never happen */ | ||
| 260 | |||
| 261 | /* to be sure always set secbuf */ | ||
| 262 | sec->secbuf = sec->secbuf_base + sec->secbufp; | ||
| 263 | |||
| 264 | for (n = 0; sec->secbufp + 2 < limit; n++) { | ||
| 265 | seclen = section_length(sec->secbuf); | ||
| 266 | if (seclen <= 0 || seclen > DMX_MAX_SECTION_SIZE | ||
| 267 | || seclen + sec->secbufp > limit) | ||
| 268 | return 0; | ||
| 269 | sec->seclen = seclen; | ||
| 270 | sec->crc_val = ~0; | ||
| 271 | /* dump [secbuf .. secbuf+seclen) */ | ||
| 272 | if (feed->pusi_seen) | ||
| 273 | dvb_dmx_swfilter_section_feed(feed); | ||
| 274 | #ifdef DVB_DEMUX_SECTION_LOSS_LOG | ||
| 275 | else | ||
| 276 | printk("dvb_demux.c pusi not seen, discarding section data\n"); | ||
| 277 | #endif | ||
| 278 | sec->secbufp += seclen; /* secbufp and secbuf moving together is */ | ||
| 279 | sec->secbuf += seclen; /* redundant but saves pointer arithmetic */ | ||
| 280 | } | ||
| 281 | |||
| 282 | return 0; | ||
| 283 | } | ||
| 284 | |||
| 285 | static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, | ||
| 286 | const u8 *buf) | ||
| 287 | { | ||
| 288 | u8 p, count; | ||
| 289 | int ccok, dc_i = 0; | ||
| 290 | u8 cc; | ||
| 291 | |||
| 292 | count = payload(buf); | ||
| 293 | |||
| 294 | if (count == 0) /* count == 0 if no payload or out of range */ | ||
| 295 | return -1; | ||
| 296 | |||
| 297 | p = 188 - count; /* payload start */ | ||
| 298 | |||
| 299 | cc = buf[3] & 0x0f; | ||
| 300 | ccok = ((feed->cc + 1) & 0x0f) == cc; | ||
| 301 | feed->cc = cc; | ||
| 302 | |||
| 303 | if (buf[3] & 0x20) { | ||
| 304 | /* adaption field present, check for discontinuity_indicator */ | ||
| 305 | if ((buf[4] > 0) && (buf[5] & 0x80)) | ||
| 306 | dc_i = 1; | ||
| 307 | } | ||
| 308 | |||
| 309 | if (!ccok || dc_i) { | ||
| 310 | #ifdef DVB_DEMUX_SECTION_LOSS_LOG | ||
| 311 | printk("dvb_demux.c discontinuity detected %d bytes lost\n", | ||
| 312 | count); | ||
| 313 | /* | ||
| 314 | * those bytes under sume circumstances will again be reported | ||
| 315 | * in the following dvb_dmx_swfilter_section_new | ||
| 316 | */ | ||
| 317 | #endif | ||
| 318 | /* | ||
| 319 | * Discontinuity detected. Reset pusi_seen = 0 to | ||
| 320 | * stop feeding of suspicious data until next PUSI=1 arrives | ||
| 321 | */ | ||
| 322 | feed->pusi_seen = 0; | ||
| 323 | dvb_dmx_swfilter_section_new(feed); | ||
| 324 | } | ||
| 325 | |||
| 326 | if (buf[1] & 0x40) { | ||
| 327 | /* PUSI=1 (is set), section boundary is here */ | ||
| 328 | if (count > 1 && buf[p] < count) { | ||
| 329 | const u8 *before = &buf[p + 1]; | ||
| 330 | u8 before_len = buf[p]; | ||
| 331 | const u8 *after = &before[before_len]; | ||
| 332 | u8 after_len = count - 1 - before_len; | ||
| 333 | |||
| 334 | dvb_dmx_swfilter_section_copy_dump(feed, before, | ||
| 335 | before_len); | ||
| 336 | /* before start of new section, set pusi_seen = 1 */ | ||
| 337 | feed->pusi_seen = 1; | ||
| 338 | dvb_dmx_swfilter_section_new(feed); | ||
| 339 | dvb_dmx_swfilter_section_copy_dump(feed, after, | ||
| 340 | after_len); | ||
| 341 | } | ||
| 342 | #ifdef DVB_DEMUX_SECTION_LOSS_LOG | ||
| 343 | else if (count > 0) | ||
| 344 | printk("dvb_demux.c PUSI=1 but %d bytes lost\n", count); | ||
| 345 | #endif | ||
| 346 | } else { | ||
| 347 | /* PUSI=0 (is not set), no section boundary */ | ||
| 348 | dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count); | ||
| 349 | } | ||
| 350 | |||
| 351 | return 0; | ||
| 352 | } | ||
| 353 | |||
| 354 | static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, | ||
| 355 | const u8 *buf) | ||
| 356 | { | ||
| 357 | switch (feed->type) { | ||
| 358 | case DMX_TYPE_TS: | ||
| 359 | if (!feed->feed.ts.is_filtering) | ||
| 360 | break; | ||
| 361 | if (feed->ts_type & TS_PACKET) { | ||
| 362 | if (feed->ts_type & TS_PAYLOAD_ONLY) | ||
| 363 | dvb_dmx_swfilter_payload(feed, buf); | ||
| 364 | else | ||
| 365 | feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, | ||
| 366 | DMX_OK); | ||
| 367 | } | ||
| 368 | if (feed->ts_type & TS_DECODER) | ||
| 369 | if (feed->demux->write_to_decoder) | ||
| 370 | feed->demux->write_to_decoder(feed, buf, 188); | ||
| 371 | break; | ||
| 372 | |||
| 373 | case DMX_TYPE_SEC: | ||
| 374 | if (!feed->feed.sec.is_filtering) | ||
| 375 | break; | ||
| 376 | if (dvb_dmx_swfilter_section_packet(feed, buf) < 0) | ||
| 377 | feed->feed.sec.seclen = feed->feed.sec.secbufp = 0; | ||
| 378 | break; | ||
| 379 | |||
| 380 | default: | ||
| 381 | break; | ||
| 382 | } | ||
| 383 | } | ||
| 384 | |||
| 385 | #define DVR_FEED(f) \ | ||
| 386 | (((f)->type == DMX_TYPE_TS) && \ | ||
| 387 | ((f)->feed.ts.is_filtering) && \ | ||
| 388 | (((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET)) | ||
| 389 | |||
| 390 | static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) | ||
| 391 | { | ||
| 392 | struct dvb_demux_feed *feed; | ||
| 393 | u16 pid = ts_pid(buf); | ||
| 394 | int dvr_done = 0; | ||
| 395 | |||
| 396 | if (dvb_demux_speedcheck) { | ||
| 397 | struct timespec cur_time, delta_time; | ||
| 398 | u64 speed_bytes, speed_timedelta; | ||
| 399 | |||
| 400 | demux->speed_pkts_cnt++; | ||
| 401 | |||
| 402 | /* show speed every SPEED_PKTS_INTERVAL packets */ | ||
| 403 | if (!(demux->speed_pkts_cnt % SPEED_PKTS_INTERVAL)) { | ||
| 404 | cur_time = current_kernel_time(); | ||
| 405 | |||
| 406 | if (demux->speed_last_time.tv_sec != 0 && | ||
| 407 | demux->speed_last_time.tv_nsec != 0) { | ||
| 408 | delta_time = timespec_sub(cur_time, | ||
| 409 | demux->speed_last_time); | ||
| 410 | speed_bytes = (u64)demux->speed_pkts_cnt | ||
| 411 | * 188 * 8; | ||
| 412 | /* convert to 1024 basis */ | ||
| 413 | speed_bytes = 1000 * div64_u64(speed_bytes, | ||
| 414 | 1024); | ||
| 415 | speed_timedelta = | ||
| 416 | (u64)timespec_to_ns(&delta_time); | ||
| 417 | speed_timedelta = div64_u64(speed_timedelta, | ||
| 418 | 1000000); /* nsec -> usec */ | ||
| 419 | printk(KERN_INFO "TS speed %llu Kbits/sec \n", | ||
| 420 | div64_u64(speed_bytes, | ||
| 421 | speed_timedelta)); | ||
| 422 | }; | ||
| 423 | |||
| 424 | demux->speed_last_time = cur_time; | ||
| 425 | demux->speed_pkts_cnt = 0; | ||
| 426 | }; | ||
| 427 | }; | ||
| 428 | |||
| 429 | if (demux->cnt_storage && dvb_demux_tscheck) { | ||
| 430 | /* check pkt counter */ | ||
| 431 | if (pid < MAX_PID) { | ||
| 432 | if (buf[1] & 0x80) | ||
| 433 | dprintk_tscheck("TEI detected. " | ||
| 434 | "PID=0x%x data1=0x%x\n", | ||
| 435 | pid, buf[1]); | ||
| 436 | |||
| 437 | if ((buf[3] & 0xf) != demux->cnt_storage[pid]) | ||
| 438 | dprintk_tscheck("TS packet counter mismatch. " | ||
| 439 | "PID=0x%x expected 0x%x " | ||
| 440 | "got 0x%x\n", | ||
| 441 | pid, demux->cnt_storage[pid], | ||
| 442 | buf[3] & 0xf); | ||
| 443 | |||
| 444 | demux->cnt_storage[pid] = ((buf[3] & 0xf) + 1)&0xf; | ||
| 445 | }; | ||
| 446 | /* end check */ | ||
| 447 | }; | ||
| 448 | |||
| 449 | list_for_each_entry(feed, &demux->feed_list, list_head) { | ||
| 450 | if ((feed->pid != pid) && (feed->pid != 0x2000)) | ||
| 451 | continue; | ||
| 452 | |||
| 453 | /* copy each packet only once to the dvr device, even | ||
| 454 | * if a PID is in multiple filters (e.g. video + PCR) */ | ||
| 455 | if ((DVR_FEED(feed)) && (dvr_done++)) | ||
| 456 | continue; | ||
| 457 | |||
| 458 | if (feed->pid == pid) | ||
| 459 | dvb_dmx_swfilter_packet_type(feed, buf); | ||
| 460 | else if (feed->pid == 0x2000) | ||
| 461 | feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, DMX_OK); | ||
| 462 | } | ||
| 463 | } | ||
| 464 | |||
| 465 | void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, | ||
| 466 | size_t count) | ||
| 467 | { | ||
| 468 | spin_lock(&demux->lock); | ||
| 469 | |||
| 470 | while (count--) { | ||
| 471 | if (buf[0] == 0x47) | ||
| 472 | dvb_dmx_swfilter_packet(demux, buf); | ||
| 473 | buf += 188; | ||
| 474 | } | ||
| 475 | |||
| 476 | spin_unlock(&demux->lock); | ||
| 477 | } | ||
| 478 | |||
| 479 | EXPORT_SYMBOL(dvb_dmx_swfilter_packets); | ||
| 480 | |||
| 481 | static inline int find_next_packet(const u8 *buf, int pos, size_t count, | ||
| 482 | const int pktsize) | ||
| 483 | { | ||
| 484 | int start = pos, lost; | ||
| 485 | |||
| 486 | while (pos < count) { | ||
| 487 | if (buf[pos] == 0x47 || | ||
| 488 | (pktsize == 204 && buf[pos] == 0xB8)) | ||
| 489 | break; | ||
| 490 | pos++; | ||
| 491 | } | ||
| 492 | |||
| 493 | lost = pos - start; | ||
| 494 | if (lost) { | ||
| 495 | /* This garbage is part of a valid packet? */ | ||
| 496 | int backtrack = pos - pktsize; | ||
| 497 | if (backtrack >= 0 && (buf[backtrack] == 0x47 || | ||
| 498 | (pktsize == 204 && buf[backtrack] == 0xB8))) | ||
| 499 | return backtrack; | ||
| 500 | } | ||
| 501 | |||
| 502 | return pos; | ||
| 503 | } | ||
| 504 | |||
| 505 | /* Filter all pktsize= 188 or 204 sized packets and skip garbage. */ | ||
| 506 | static inline void _dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, | ||
| 507 | size_t count, const int pktsize) | ||
| 508 | { | ||
| 509 | int p = 0, i, j; | ||
| 510 | const u8 *q; | ||
| 511 | |||
| 512 | spin_lock(&demux->lock); | ||
| 513 | |||
| 514 | if (demux->tsbufp) { /* tsbuf[0] is now 0x47. */ | ||
| 515 | i = demux->tsbufp; | ||
| 516 | j = pktsize - i; | ||
| 517 | if (count < j) { | ||
| 518 | memcpy(&demux->tsbuf[i], buf, count); | ||
| 519 | demux->tsbufp += count; | ||
| 520 | goto bailout; | ||
| 521 | } | ||
| 522 | memcpy(&demux->tsbuf[i], buf, j); | ||
| 523 | if (demux->tsbuf[0] == 0x47) /* double check */ | ||
| 524 | dvb_dmx_swfilter_packet(demux, demux->tsbuf); | ||
| 525 | demux->tsbufp = 0; | ||
| 526 | p += j; | ||
| 527 | } | ||
| 528 | |||
| 529 | while (1) { | ||
| 530 | p = find_next_packet(buf, p, count, pktsize); | ||
| 531 | if (p >= count) | ||
| 532 | break; | ||
| 533 | if (count - p < pktsize) | ||
| 534 | break; | ||
| 535 | |||
| 536 | q = &buf[p]; | ||
| 537 | |||
| 538 | if (pktsize == 204 && (*q == 0xB8)) { | ||
| 539 | memcpy(demux->tsbuf, q, 188); | ||
| 540 | demux->tsbuf[0] = 0x47; | ||
| 541 | q = demux->tsbuf; | ||
| 542 | } | ||
| 543 | dvb_dmx_swfilter_packet(demux, q); | ||
| 544 | p += pktsize; | ||
| 545 | } | ||
| 546 | |||
| 547 | i = count - p; | ||
| 548 | if (i) { | ||
| 549 | memcpy(demux->tsbuf, &buf[p], i); | ||
| 550 | demux->tsbufp = i; | ||
| 551 | if (pktsize == 204 && demux->tsbuf[0] == 0xB8) | ||
| 552 | demux->tsbuf[0] = 0x47; | ||
| 553 | } | ||
| 554 | |||
| 555 | bailout: | ||
| 556 | spin_unlock(&demux->lock); | ||
| 557 | } | ||
| 558 | |||
| 559 | void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count) | ||
| 560 | { | ||
| 561 | _dvb_dmx_swfilter(demux, buf, count, 188); | ||
| 562 | } | ||
| 563 | EXPORT_SYMBOL(dvb_dmx_swfilter); | ||
| 564 | |||
| 565 | void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) | ||
| 566 | { | ||
| 567 | _dvb_dmx_swfilter(demux, buf, count, 204); | ||
| 568 | } | ||
| 569 | EXPORT_SYMBOL(dvb_dmx_swfilter_204); | ||
| 570 | |||
| 571 | static struct dvb_demux_filter *dvb_dmx_filter_alloc(struct dvb_demux *demux) | ||
| 572 | { | ||
| 573 | int i; | ||
| 574 | |||
| 575 | for (i = 0; i < demux->filternum; i++) | ||
| 576 | if (demux->filter[i].state == DMX_STATE_FREE) | ||
| 577 | break; | ||
| 578 | |||
| 579 | if (i == demux->filternum) | ||
| 580 | return NULL; | ||
| 581 | |||
| 582 | demux->filter[i].state = DMX_STATE_ALLOCATED; | ||
| 583 | |||
| 584 | return &demux->filter[i]; | ||
| 585 | } | ||
| 586 | |||
| 587 | static struct dvb_demux_feed *dvb_dmx_feed_alloc(struct dvb_demux *demux) | ||
| 588 | { | ||
| 589 | int i; | ||
| 590 | |||
| 591 | for (i = 0; i < demux->feednum; i++) | ||
| 592 | if (demux->feed[i].state == DMX_STATE_FREE) | ||
| 593 | break; | ||
| 594 | |||
| 595 | if (i == demux->feednum) | ||
| 596 | return NULL; | ||
| 597 | |||
| 598 | demux->feed[i].state = DMX_STATE_ALLOCATED; | ||
| 599 | |||
| 600 | return &demux->feed[i]; | ||
| 601 | } | ||
| 602 | |||
| 603 | static int dvb_demux_feed_find(struct dvb_demux_feed *feed) | ||
| 604 | { | ||
| 605 | struct dvb_demux_feed *entry; | ||
| 606 | |||
| 607 | list_for_each_entry(entry, &feed->demux->feed_list, list_head) | ||
| 608 | if (entry == feed) | ||
| 609 | return 1; | ||
| 610 | |||
| 611 | return 0; | ||
| 612 | } | ||
| 613 | |||
| 614 | static void dvb_demux_feed_add(struct dvb_demux_feed *feed) | ||
| 615 | { | ||
| 616 | spin_lock_irq(&feed->demux->lock); | ||
| 617 | if (dvb_demux_feed_find(feed)) { | ||
| 618 | printk(KERN_ERR "%s: feed already in list (type=%x state=%x pid=%x)\n", | ||
| 619 | __func__, feed->type, feed->state, feed->pid); | ||
| 620 | goto out; | ||
| 621 | } | ||
| 622 | |||
| 623 | list_add(&feed->list_head, &feed->demux->feed_list); | ||
| 624 | out: | ||
| 625 | spin_unlock_irq(&feed->demux->lock); | ||
| 626 | } | ||
| 627 | |||
| 628 | static void dvb_demux_feed_del(struct dvb_demux_feed *feed) | ||
| 629 | { | ||
| 630 | spin_lock_irq(&feed->demux->lock); | ||
| 631 | if (!(dvb_demux_feed_find(feed))) { | ||
| 632 | printk(KERN_ERR "%s: feed not in list (type=%x state=%x pid=%x)\n", | ||
| 633 | __func__, feed->type, feed->state, feed->pid); | ||
| 634 | goto out; | ||
| 635 | } | ||
| 636 | |||
| 637 | list_del(&feed->list_head); | ||
| 638 | out: | ||
| 639 | spin_unlock_irq(&feed->demux->lock); | ||
| 640 | } | ||
| 641 | |||
| 642 | static int dmx_ts_feed_set(struct dmx_ts_feed *ts_feed, u16 pid, int ts_type, | ||
| 643 | enum dmx_ts_pes pes_type, | ||
| 644 | size_t circular_buffer_size, struct timespec timeout) | ||
| 645 | { | ||
| 646 | struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; | ||
| 647 | struct dvb_demux *demux = feed->demux; | ||
| 648 | |||
| 649 | if (pid > DMX_MAX_PID) | ||
| 650 | return -EINVAL; | ||
| 651 | |||
| 652 | if (mutex_lock_interruptible(&demux->mutex)) | ||
| 653 | return -ERESTARTSYS; | ||
| 654 | |||
| 655 | if (ts_type & TS_DECODER) { | ||
| 656 | if (pes_type >= DMX_TS_PES_OTHER) { | ||
| 657 | mutex_unlock(&demux->mutex); | ||
| 658 | return -EINVAL; | ||
| 659 | } | ||
| 660 | |||
| 661 | if (demux->pesfilter[pes_type] && | ||
| 662 | demux->pesfilter[pes_type] != feed) { | ||
| 663 | mutex_unlock(&demux->mutex); | ||
| 664 | return -EINVAL; | ||
| 665 | } | ||
| 666 | |||
| 667 | demux->pesfilter[pes_type] = feed; | ||
| 668 | demux->pids[pes_type] = pid; | ||
| 669 | } | ||
| 670 | |||
| 671 | dvb_demux_feed_add(feed); | ||
| 672 | |||
| 673 | feed->pid = pid; | ||
| 674 | feed->buffer_size = circular_buffer_size; | ||
| 675 | feed->timeout = timeout; | ||
| 676 | feed->ts_type = ts_type; | ||
| 677 | feed->pes_type = pes_type; | ||
| 678 | |||
| 679 | if (feed->buffer_size) { | ||
| 680 | #ifdef NOBUFS | ||
| 681 | feed->buffer = NULL; | ||
| 682 | #else | ||
| 683 | feed->buffer = vmalloc(feed->buffer_size); | ||
| 684 | if (!feed->buffer) { | ||
| 685 | mutex_unlock(&demux->mutex); | ||
| 686 | return -ENOMEM; | ||
| 687 | } | ||
| 688 | #endif | ||
| 689 | } | ||
| 690 | |||
| 691 | feed->state = DMX_STATE_READY; | ||
| 692 | mutex_unlock(&demux->mutex); | ||
| 693 | |||
| 694 | return 0; | ||
| 695 | } | ||
| 696 | |||
| 697 | static int dmx_ts_feed_start_filtering(struct dmx_ts_feed *ts_feed) | ||
| 698 | { | ||
| 699 | struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; | ||
| 700 | struct dvb_demux *demux = feed->demux; | ||
| 701 | int ret; | ||
| 702 | |||
| 703 | if (mutex_lock_interruptible(&demux->mutex)) | ||
| 704 | return -ERESTARTSYS; | ||
| 705 | |||
| 706 | if (feed->state != DMX_STATE_READY || feed->type != DMX_TYPE_TS) { | ||
| 707 | mutex_unlock(&demux->mutex); | ||
| 708 | return -EINVAL; | ||
| 709 | } | ||
| 710 | |||
| 711 | if (!demux->start_feed) { | ||
| 712 | mutex_unlock(&demux->mutex); | ||
| 713 | return -ENODEV; | ||
| 714 | } | ||
| 715 | |||
| 716 | if ((ret = demux->start_feed(feed)) < 0) { | ||
| 717 | mutex_unlock(&demux->mutex); | ||
| 718 | return ret; | ||
| 719 | } | ||
| 720 | |||
| 721 | spin_lock_irq(&demux->lock); | ||
| 722 | ts_feed->is_filtering = 1; | ||
| 723 | feed->state = DMX_STATE_GO; | ||
| 724 | spin_unlock_irq(&demux->lock); | ||
| 725 | mutex_unlock(&demux->mutex); | ||
| 726 | |||
| 727 | return 0; | ||
| 728 | } | ||
| 729 | |||
| 730 | static int dmx_ts_feed_stop_filtering(struct dmx_ts_feed *ts_feed) | ||
| 731 | { | ||
| 732 | struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; | ||
| 733 | struct dvb_demux *demux = feed->demux; | ||
| 734 | int ret; | ||
| 735 | |||
| 736 | mutex_lock(&demux->mutex); | ||
| 737 | |||
| 738 | if (feed->state < DMX_STATE_GO) { | ||
| 739 | mutex_unlock(&demux->mutex); | ||
| 740 | return -EINVAL; | ||
| 741 | } | ||
| 742 | |||
| 743 | if (!demux->stop_feed) { | ||
| 744 | mutex_unlock(&demux->mutex); | ||
| 745 | return -ENODEV; | ||
| 746 | } | ||
| 747 | |||
| 748 | ret = demux->stop_feed(feed); | ||
| 749 | |||
| 750 | spin_lock_irq(&demux->lock); | ||
| 751 | ts_feed->is_filtering = 0; | ||
| 752 | feed->state = DMX_STATE_ALLOCATED; | ||
| 753 | spin_unlock_irq(&demux->lock); | ||
| 754 | mutex_unlock(&demux->mutex); | ||
| 755 | |||
| 756 | return ret; | ||
| 757 | } | ||
| 758 | |||
| 759 | static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx, | ||
| 760 | struct dmx_ts_feed **ts_feed, | ||
| 761 | dmx_ts_cb callback) | ||
| 762 | { | ||
| 763 | struct dvb_demux *demux = (struct dvb_demux *)dmx; | ||
| 764 | struct dvb_demux_feed *feed; | ||
| 765 | |||
| 766 | if (mutex_lock_interruptible(&demux->mutex)) | ||
| 767 | return -ERESTARTSYS; | ||
| 768 | |||
| 769 | if (!(feed = dvb_dmx_feed_alloc(demux))) { | ||
| 770 | mutex_unlock(&demux->mutex); | ||
| 771 | return -EBUSY; | ||
| 772 | } | ||
| 773 | |||
| 774 | feed->type = DMX_TYPE_TS; | ||
| 775 | feed->cb.ts = callback; | ||
| 776 | feed->demux = demux; | ||
| 777 | feed->pid = 0xffff; | ||
| 778 | feed->peslen = 0xfffa; | ||
| 779 | feed->buffer = NULL; | ||
| 780 | |||
| 781 | (*ts_feed) = &feed->feed.ts; | ||
| 782 | (*ts_feed)->parent = dmx; | ||
| 783 | (*ts_feed)->priv = NULL; | ||
| 784 | (*ts_feed)->is_filtering = 0; | ||
| 785 | (*ts_feed)->start_filtering = dmx_ts_feed_start_filtering; | ||
| 786 | (*ts_feed)->stop_filtering = dmx_ts_feed_stop_filtering; | ||
| 787 | (*ts_feed)->set = dmx_ts_feed_set; | ||
| 788 | |||
| 789 | if (!(feed->filter = dvb_dmx_filter_alloc(demux))) { | ||
| 790 | feed->state = DMX_STATE_FREE; | ||
| 791 | mutex_unlock(&demux->mutex); | ||
| 792 | return -EBUSY; | ||
| 793 | } | ||
| 794 | |||
| 795 | feed->filter->type = DMX_TYPE_TS; | ||
| 796 | feed->filter->feed = feed; | ||
| 797 | feed->filter->state = DMX_STATE_READY; | ||
| 798 | |||
| 799 | mutex_unlock(&demux->mutex); | ||
| 800 | |||
| 801 | return 0; | ||
| 802 | } | ||
| 803 | |||
| 804 | static int dvbdmx_release_ts_feed(struct dmx_demux *dmx, | ||
| 805 | struct dmx_ts_feed *ts_feed) | ||
| 806 | { | ||
| 807 | struct dvb_demux *demux = (struct dvb_demux *)dmx; | ||
| 808 | struct dvb_demux_feed *feed = (struct dvb_demux_feed *)ts_feed; | ||
| 809 | |||
| 810 | mutex_lock(&demux->mutex); | ||
| 811 | |||
| 812 | if (feed->state == DMX_STATE_FREE) { | ||
| 813 | mutex_unlock(&demux->mutex); | ||
| 814 | return -EINVAL; | ||
| 815 | } | ||
| 816 | #ifndef NOBUFS | ||
| 817 | vfree(feed->buffer); | ||
| 818 | feed->buffer = NULL; | ||
| 819 | #endif | ||
| 820 | |||
| 821 | feed->state = DMX_STATE_FREE; | ||
| 822 | feed->filter->state = DMX_STATE_FREE; | ||
| 823 | |||
| 824 | dvb_demux_feed_del(feed); | ||
| 825 | |||
| 826 | feed->pid = 0xffff; | ||
| 827 | |||
| 828 | if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_TS_PES_OTHER) | ||
| 829 | demux->pesfilter[feed->pes_type] = NULL; | ||
| 830 | |||
| 831 | mutex_unlock(&demux->mutex); | ||
| 832 | return 0; | ||
| 833 | } | ||
| 834 | |||
| 835 | /****************************************************************************** | ||
| 836 | * dmx_section_feed API calls | ||
| 837 | ******************************************************************************/ | ||
| 838 | |||
| 839 | static int dmx_section_feed_allocate_filter(struct dmx_section_feed *feed, | ||
| 840 | struct dmx_section_filter **filter) | ||
| 841 | { | ||
| 842 | struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; | ||
| 843 | struct dvb_demux *dvbdemux = dvbdmxfeed->demux; | ||
| 844 | struct dvb_demux_filter *dvbdmxfilter; | ||
| 845 | |||
| 846 | if (mutex_lock_interruptible(&dvbdemux->mutex)) | ||
| 847 | return -ERESTARTSYS; | ||
| 848 | |||
| 849 | dvbdmxfilter = dvb_dmx_filter_alloc(dvbdemux); | ||
| 850 | if (!dvbdmxfilter) { | ||
| 851 | mutex_unlock(&dvbdemux->mutex); | ||
| 852 | return -EBUSY; | ||
| 853 | } | ||
| 854 | |||
| 855 | spin_lock_irq(&dvbdemux->lock); | ||
| 856 | *filter = &dvbdmxfilter->filter; | ||
| 857 | (*filter)->parent = feed; | ||
| 858 | (*filter)->priv = NULL; | ||
| 859 | dvbdmxfilter->feed = dvbdmxfeed; | ||
| 860 | dvbdmxfilter->type = DMX_TYPE_SEC; | ||
| 861 | dvbdmxfilter->state = DMX_STATE_READY; | ||
| 862 | dvbdmxfilter->next = dvbdmxfeed->filter; | ||
| 863 | dvbdmxfeed->filter = dvbdmxfilter; | ||
| 864 | spin_unlock_irq(&dvbdemux->lock); | ||
| 865 | |||
| 866 | mutex_unlock(&dvbdemux->mutex); | ||
| 867 | return 0; | ||
| 868 | } | ||
| 869 | |||
| 870 | static int dmx_section_feed_set(struct dmx_section_feed *feed, | ||
| 871 | u16 pid, size_t circular_buffer_size, | ||
| 872 | int check_crc) | ||
| 873 | { | ||
| 874 | struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; | ||
| 875 | struct dvb_demux *dvbdmx = dvbdmxfeed->demux; | ||
| 876 | |||
| 877 | if (pid > 0x1fff) | ||
| 878 | return -EINVAL; | ||
| 879 | |||
| 880 | if (mutex_lock_interruptible(&dvbdmx->mutex)) | ||
| 881 | return -ERESTARTSYS; | ||
| 882 | |||
| 883 | dvb_demux_feed_add(dvbdmxfeed); | ||
| 884 | |||
| 885 | dvbdmxfeed->pid = pid; | ||
| 886 | dvbdmxfeed->buffer_size = circular_buffer_size; | ||
| 887 | dvbdmxfeed->feed.sec.check_crc = check_crc; | ||
| 888 | |||
| 889 | #ifdef NOBUFS | ||
| 890 | dvbdmxfeed->buffer = NULL; | ||
| 891 | #else | ||
| 892 | dvbdmxfeed->buffer = vmalloc(dvbdmxfeed->buffer_size); | ||
| 893 | if (!dvbdmxfeed->buffer) { | ||
| 894 | mutex_unlock(&dvbdmx->mutex); | ||
| 895 | return -ENOMEM; | ||
| 896 | } | ||
| 897 | #endif | ||
| 898 | |||
| 899 | dvbdmxfeed->state = DMX_STATE_READY; | ||
| 900 | mutex_unlock(&dvbdmx->mutex); | ||
| 901 | return 0; | ||
| 902 | } | ||
| 903 | |||
| 904 | static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed) | ||
| 905 | { | ||
| 906 | int i; | ||
| 907 | struct dvb_demux_filter *f; | ||
| 908 | struct dmx_section_filter *sf; | ||
| 909 | u8 mask, mode, doneq; | ||
| 910 | |||
| 911 | if (!(f = dvbdmxfeed->filter)) | ||
| 912 | return; | ||
| 913 | do { | ||
| 914 | sf = &f->filter; | ||
| 915 | doneq = 0; | ||
| 916 | for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { | ||
| 917 | mode = sf->filter_mode[i]; | ||
| 918 | mask = sf->filter_mask[i]; | ||
| 919 | f->maskandmode[i] = mask & mode; | ||
| 920 | doneq |= f->maskandnotmode[i] = mask & ~mode; | ||
| 921 | } | ||
| 922 | f->doneq = doneq ? 1 : 0; | ||
| 923 | } while ((f = f->next)); | ||
| 924 | } | ||
| 925 | |||
| 926 | static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed) | ||
| 927 | { | ||
| 928 | struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; | ||
| 929 | struct dvb_demux *dvbdmx = dvbdmxfeed->demux; | ||
| 930 | int ret; | ||
| 931 | |||
| 932 | if (mutex_lock_interruptible(&dvbdmx->mutex)) | ||
| 933 | return -ERESTARTSYS; | ||
| 934 | |||
| 935 | if (feed->is_filtering) { | ||
| 936 | mutex_unlock(&dvbdmx->mutex); | ||
| 937 | return -EBUSY; | ||
| 938 | } | ||
| 939 | |||
| 940 | if (!dvbdmxfeed->filter) { | ||
| 941 | mutex_unlock(&dvbdmx->mutex); | ||
| 942 | return -EINVAL; | ||
| 943 | } | ||
| 944 | |||
| 945 | dvbdmxfeed->feed.sec.tsfeedp = 0; | ||
| 946 | dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; | ||
| 947 | dvbdmxfeed->feed.sec.secbufp = 0; | ||
| 948 | dvbdmxfeed->feed.sec.seclen = 0; | ||
| 949 | |||
| 950 | if (!dvbdmx->start_feed) { | ||
| 951 | mutex_unlock(&dvbdmx->mutex); | ||
| 952 | return -ENODEV; | ||
| 953 | } | ||
| 954 | |||
| 955 | prepare_secfilters(dvbdmxfeed); | ||
| 956 | |||
| 957 | if ((ret = dvbdmx->start_feed(dvbdmxfeed)) < 0) { | ||
| 958 | mutex_unlock(&dvbdmx->mutex); | ||
| 959 | return ret; | ||
| 960 | } | ||
| 961 | |||
| 962 | spin_lock_irq(&dvbdmx->lock); | ||
| 963 | feed->is_filtering = 1; | ||
| 964 | dvbdmxfeed->state = DMX_STATE_GO; | ||
| 965 | spin_unlock_irq(&dvbdmx->lock); | ||
| 966 | |||
| 967 | mutex_unlock(&dvbdmx->mutex); | ||
| 968 | return 0; | ||
| 969 | } | ||
| 970 | |||
| 971 | static int dmx_section_feed_stop_filtering(struct dmx_section_feed *feed) | ||
| 972 | { | ||
| 973 | struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; | ||
| 974 | struct dvb_demux *dvbdmx = dvbdmxfeed->demux; | ||
| 975 | int ret; | ||
| 976 | |||
| 977 | mutex_lock(&dvbdmx->mutex); | ||
| 978 | |||
| 979 | if (!dvbdmx->stop_feed) { | ||
| 980 | mutex_unlock(&dvbdmx->mutex); | ||
| 981 | return -ENODEV; | ||
| 982 | } | ||
| 983 | |||
| 984 | ret = dvbdmx->stop_feed(dvbdmxfeed); | ||
| 985 | |||
| 986 | spin_lock_irq(&dvbdmx->lock); | ||
| 987 | dvbdmxfeed->state = DMX_STATE_READY; | ||
| 988 | feed->is_filtering = 0; | ||
| 989 | spin_unlock_irq(&dvbdmx->lock); | ||
| 990 | |||
| 991 | mutex_unlock(&dvbdmx->mutex); | ||
| 992 | return ret; | ||
| 993 | } | ||
| 994 | |||
| 995 | static int dmx_section_feed_release_filter(struct dmx_section_feed *feed, | ||
| 996 | struct dmx_section_filter *filter) | ||
| 997 | { | ||
| 998 | struct dvb_demux_filter *dvbdmxfilter = (struct dvb_demux_filter *)filter, *f; | ||
| 999 | struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; | ||
| 1000 | struct dvb_demux *dvbdmx = dvbdmxfeed->demux; | ||
| 1001 | |||
| 1002 | mutex_lock(&dvbdmx->mutex); | ||
| 1003 | |||
| 1004 | if (dvbdmxfilter->feed != dvbdmxfeed) { | ||
| 1005 | mutex_unlock(&dvbdmx->mutex); | ||
| 1006 | return -EINVAL; | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | if (feed->is_filtering) | ||
| 1010 | feed->stop_filtering(feed); | ||
| 1011 | |||
| 1012 | spin_lock_irq(&dvbdmx->lock); | ||
| 1013 | f = dvbdmxfeed->filter; | ||
| 1014 | |||
| 1015 | if (f == dvbdmxfilter) { | ||
| 1016 | dvbdmxfeed->filter = dvbdmxfilter->next; | ||
| 1017 | } else { | ||
| 1018 | while (f->next != dvbdmxfilter) | ||
| 1019 | f = f->next; | ||
| 1020 | f->next = f->next->next; | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | dvbdmxfilter->state = DMX_STATE_FREE; | ||
| 1024 | spin_unlock_irq(&dvbdmx->lock); | ||
| 1025 | mutex_unlock(&dvbdmx->mutex); | ||
| 1026 | return 0; | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, | ||
| 1030 | struct dmx_section_feed **feed, | ||
| 1031 | dmx_section_cb callback) | ||
| 1032 | { | ||
| 1033 | struct dvb_demux *dvbdmx = (struct dvb_demux *)demux; | ||
| 1034 | struct dvb_demux_feed *dvbdmxfeed; | ||
| 1035 | |||
| 1036 | if (mutex_lock_interruptible(&dvbdmx->mutex)) | ||
| 1037 | return -ERESTARTSYS; | ||
| 1038 | |||
| 1039 | if (!(dvbdmxfeed = dvb_dmx_feed_alloc(dvbdmx))) { | ||
| 1040 | mutex_unlock(&dvbdmx->mutex); | ||
| 1041 | return -EBUSY; | ||
| 1042 | } | ||
| 1043 | |||
| 1044 | dvbdmxfeed->type = DMX_TYPE_SEC; | ||
| 1045 | dvbdmxfeed->cb.sec = callback; | ||
| 1046 | dvbdmxfeed->demux = dvbdmx; | ||
| 1047 | dvbdmxfeed->pid = 0xffff; | ||
| 1048 | dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; | ||
| 1049 | dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0; | ||
| 1050 | dvbdmxfeed->feed.sec.tsfeedp = 0; | ||
| 1051 | dvbdmxfeed->filter = NULL; | ||
| 1052 | dvbdmxfeed->buffer = NULL; | ||
| 1053 | |||
| 1054 | (*feed) = &dvbdmxfeed->feed.sec; | ||
| 1055 | (*feed)->is_filtering = 0; | ||
| 1056 | (*feed)->parent = demux; | ||
| 1057 | (*feed)->priv = NULL; | ||
| 1058 | |||
| 1059 | (*feed)->set = dmx_section_feed_set; | ||
| 1060 | (*feed)->allocate_filter = dmx_section_feed_allocate_filter; | ||
| 1061 | (*feed)->start_filtering = dmx_section_feed_start_filtering; | ||
| 1062 | (*feed)->stop_filtering = dmx_section_feed_stop_filtering; | ||
| 1063 | (*feed)->release_filter = dmx_section_feed_release_filter; | ||
| 1064 | |||
| 1065 | mutex_unlock(&dvbdmx->mutex); | ||
| 1066 | return 0; | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | static int dvbdmx_release_section_feed(struct dmx_demux *demux, | ||
| 1070 | struct dmx_section_feed *feed) | ||
| 1071 | { | ||
| 1072 | struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)feed; | ||
| 1073 | struct dvb_demux *dvbdmx = (struct dvb_demux *)demux; | ||
| 1074 | |||
| 1075 | mutex_lock(&dvbdmx->mutex); | ||
| 1076 | |||
| 1077 | if (dvbdmxfeed->state == DMX_STATE_FREE) { | ||
| 1078 | mutex_unlock(&dvbdmx->mutex); | ||
| 1079 | return -EINVAL; | ||
| 1080 | } | ||
| 1081 | #ifndef NOBUFS | ||
| 1082 | vfree(dvbdmxfeed->buffer); | ||
| 1083 | dvbdmxfeed->buffer = NULL; | ||
| 1084 | #endif | ||
| 1085 | dvbdmxfeed->state = DMX_STATE_FREE; | ||
| 1086 | |||
| 1087 | dvb_demux_feed_del(dvbdmxfeed); | ||
| 1088 | |||
| 1089 | dvbdmxfeed->pid = 0xffff; | ||
| 1090 | |||
| 1091 | mutex_unlock(&dvbdmx->mutex); | ||
| 1092 | return 0; | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | /****************************************************************************** | ||
| 1096 | * dvb_demux kernel data API calls | ||
| 1097 | ******************************************************************************/ | ||
| 1098 | |||
| 1099 | static int dvbdmx_open(struct dmx_demux *demux) | ||
| 1100 | { | ||
| 1101 | struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; | ||
| 1102 | |||
| 1103 | if (dvbdemux->users >= MAX_DVB_DEMUX_USERS) | ||
| 1104 | return -EUSERS; | ||
| 1105 | |||
| 1106 | dvbdemux->users++; | ||
| 1107 | return 0; | ||
| 1108 | } | ||
| 1109 | |||
| 1110 | static int dvbdmx_close(struct dmx_demux *demux) | ||
| 1111 | { | ||
| 1112 | struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; | ||
| 1113 | |||
| 1114 | if (dvbdemux->users == 0) | ||
| 1115 | return -ENODEV; | ||
| 1116 | |||
| 1117 | dvbdemux->users--; | ||
| 1118 | //FIXME: release any unneeded resources if users==0 | ||
| 1119 | return 0; | ||
| 1120 | } | ||
| 1121 | |||
| 1122 | static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t count) | ||
| 1123 | { | ||
| 1124 | struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; | ||
| 1125 | void *p; | ||
| 1126 | |||
| 1127 | if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE)) | ||
| 1128 | return -EINVAL; | ||
| 1129 | |||
| 1130 | p = memdup_user(buf, count); | ||
| 1131 | if (IS_ERR(p)) | ||
| 1132 | return PTR_ERR(p); | ||
| 1133 | if (mutex_lock_interruptible(&dvbdemux->mutex)) { | ||
| 1134 | kfree(p); | ||
| 1135 | return -ERESTARTSYS; | ||
| 1136 | } | ||
| 1137 | dvb_dmx_swfilter(dvbdemux, p, count); | ||
| 1138 | kfree(p); | ||
| 1139 | mutex_unlock(&dvbdemux->mutex); | ||
| 1140 | |||
| 1141 | if (signal_pending(current)) | ||
| 1142 | return -EINTR; | ||
| 1143 | return count; | ||
| 1144 | } | ||
| 1145 | |||
| 1146 | static int dvbdmx_add_frontend(struct dmx_demux *demux, | ||
| 1147 | struct dmx_frontend *frontend) | ||
| 1148 | { | ||
| 1149 | struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; | ||
| 1150 | struct list_head *head = &dvbdemux->frontend_list; | ||
| 1151 | |||
| 1152 | list_add(&(frontend->connectivity_list), head); | ||
| 1153 | |||
| 1154 | return 0; | ||
| 1155 | } | ||
| 1156 | |||
| 1157 | static int dvbdmx_remove_frontend(struct dmx_demux *demux, | ||
| 1158 | struct dmx_frontend *frontend) | ||
| 1159 | { | ||
| 1160 | struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; | ||
| 1161 | struct list_head *pos, *n, *head = &dvbdemux->frontend_list; | ||
| 1162 | |||
| 1163 | list_for_each_safe(pos, n, head) { | ||
| 1164 | if (DMX_FE_ENTRY(pos) == frontend) { | ||
| 1165 | list_del(pos); | ||
| 1166 | return 0; | ||
| 1167 | } | ||
| 1168 | } | ||
| 1169 | |||
| 1170 | return -ENODEV; | ||
| 1171 | } | ||
| 1172 | |||
| 1173 | static struct list_head *dvbdmx_get_frontends(struct dmx_demux *demux) | ||
| 1174 | { | ||
| 1175 | struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; | ||
| 1176 | |||
| 1177 | if (list_empty(&dvbdemux->frontend_list)) | ||
| 1178 | return NULL; | ||
| 1179 | |||
| 1180 | return &dvbdemux->frontend_list; | ||
| 1181 | } | ||
| 1182 | |||
| 1183 | static int dvbdmx_connect_frontend(struct dmx_demux *demux, | ||
| 1184 | struct dmx_frontend *frontend) | ||
| 1185 | { | ||
| 1186 | struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; | ||
| 1187 | |||
| 1188 | if (demux->frontend) | ||
| 1189 | return -EINVAL; | ||
| 1190 | |||
| 1191 | mutex_lock(&dvbdemux->mutex); | ||
| 1192 | |||
| 1193 | demux->frontend = frontend; | ||
| 1194 | mutex_unlock(&dvbdemux->mutex); | ||
| 1195 | return 0; | ||
| 1196 | } | ||
| 1197 | |||
| 1198 | static int dvbdmx_disconnect_frontend(struct dmx_demux *demux) | ||
| 1199 | { | ||
| 1200 | struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; | ||
| 1201 | |||
| 1202 | mutex_lock(&dvbdemux->mutex); | ||
| 1203 | |||
| 1204 | demux->frontend = NULL; | ||
| 1205 | mutex_unlock(&dvbdemux->mutex); | ||
| 1206 | return 0; | ||
| 1207 | } | ||
| 1208 | |||
| 1209 | static int dvbdmx_get_pes_pids(struct dmx_demux *demux, u16 * pids) | ||
| 1210 | { | ||
| 1211 | struct dvb_demux *dvbdemux = (struct dvb_demux *)demux; | ||
| 1212 | |||
| 1213 | memcpy(pids, dvbdemux->pids, 5 * sizeof(u16)); | ||
| 1214 | return 0; | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | int dvb_dmx_init(struct dvb_demux *dvbdemux) | ||
| 1218 | { | ||
| 1219 | int i; | ||
| 1220 | struct dmx_demux *dmx = &dvbdemux->dmx; | ||
| 1221 | |||
| 1222 | dvbdemux->cnt_storage = NULL; | ||
| 1223 | dvbdemux->users = 0; | ||
| 1224 | dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter)); | ||
| 1225 | |||
| 1226 | if (!dvbdemux->filter) | ||
| 1227 | return -ENOMEM; | ||
| 1228 | |||
| 1229 | dvbdemux->feed = vmalloc(dvbdemux->feednum * sizeof(struct dvb_demux_feed)); | ||
| 1230 | if (!dvbdemux->feed) { | ||
| 1231 | vfree(dvbdemux->filter); | ||
| 1232 | dvbdemux->filter = NULL; | ||
| 1233 | return -ENOMEM; | ||
| 1234 | } | ||
| 1235 | for (i = 0; i < dvbdemux->filternum; i++) { | ||
| 1236 | dvbdemux->filter[i].state = DMX_STATE_FREE; | ||
| 1237 | dvbdemux->filter[i].index = i; | ||
| 1238 | } | ||
| 1239 | for (i = 0; i < dvbdemux->feednum; i++) { | ||
| 1240 | dvbdemux->feed[i].state = DMX_STATE_FREE; | ||
| 1241 | dvbdemux->feed[i].index = i; | ||
| 1242 | } | ||
| 1243 | |||
| 1244 | dvbdemux->cnt_storage = vmalloc(MAX_PID + 1); | ||
| 1245 | if (!dvbdemux->cnt_storage) | ||
| 1246 | printk(KERN_WARNING "Couldn't allocate memory for TS/TEI check. Disabling it\n"); | ||
| 1247 | |||
| 1248 | INIT_LIST_HEAD(&dvbdemux->frontend_list); | ||
| 1249 | |||
| 1250 | for (i = 0; i < DMX_TS_PES_OTHER; i++) { | ||
| 1251 | dvbdemux->pesfilter[i] = NULL; | ||
| 1252 | dvbdemux->pids[i] = 0xffff; | ||
| 1253 | } | ||
| 1254 | |||
| 1255 | INIT_LIST_HEAD(&dvbdemux->feed_list); | ||
| 1256 | |||
| 1257 | dvbdemux->playing = 0; | ||
| 1258 | dvbdemux->recording = 0; | ||
| 1259 | dvbdemux->tsbufp = 0; | ||
| 1260 | |||
| 1261 | if (!dvbdemux->check_crc32) | ||
| 1262 | dvbdemux->check_crc32 = dvb_dmx_crc32; | ||
| 1263 | |||
| 1264 | if (!dvbdemux->memcopy) | ||
| 1265 | dvbdemux->memcopy = dvb_dmx_memcopy; | ||
| 1266 | |||
| 1267 | dmx->frontend = NULL; | ||
| 1268 | dmx->priv = dvbdemux; | ||
| 1269 | dmx->open = dvbdmx_open; | ||
| 1270 | dmx->close = dvbdmx_close; | ||
| 1271 | dmx->write = dvbdmx_write; | ||
| 1272 | dmx->allocate_ts_feed = dvbdmx_allocate_ts_feed; | ||
| 1273 | dmx->release_ts_feed = dvbdmx_release_ts_feed; | ||
| 1274 | dmx->allocate_section_feed = dvbdmx_allocate_section_feed; | ||
| 1275 | dmx->release_section_feed = dvbdmx_release_section_feed; | ||
| 1276 | |||
| 1277 | dmx->add_frontend = dvbdmx_add_frontend; | ||
| 1278 | dmx->remove_frontend = dvbdmx_remove_frontend; | ||
| 1279 | dmx->get_frontends = dvbdmx_get_frontends; | ||
| 1280 | dmx->connect_frontend = dvbdmx_connect_frontend; | ||
| 1281 | dmx->disconnect_frontend = dvbdmx_disconnect_frontend; | ||
| 1282 | dmx->get_pes_pids = dvbdmx_get_pes_pids; | ||
| 1283 | |||
| 1284 | mutex_init(&dvbdemux->mutex); | ||
| 1285 | spin_lock_init(&dvbdemux->lock); | ||
| 1286 | |||
| 1287 | return 0; | ||
| 1288 | } | ||
| 1289 | |||
| 1290 | EXPORT_SYMBOL(dvb_dmx_init); | ||
| 1291 | |||
| 1292 | void dvb_dmx_release(struct dvb_demux *dvbdemux) | ||
| 1293 | { | ||
| 1294 | vfree(dvbdemux->cnt_storage); | ||
| 1295 | vfree(dvbdemux->filter); | ||
| 1296 | vfree(dvbdemux->feed); | ||
| 1297 | } | ||
| 1298 | |||
| 1299 | 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 new file mode 100644 index 00000000000..a7d876fd02d --- /dev/null +++ b/drivers/media/dvb/dvb-core/dvb_demux.h | |||
| @@ -0,0 +1,149 @@ | |||
| 1 | /* | ||
| 2 | * dvb_demux.h: DVB kernel demux API | ||
| 3 | * | ||
| 4 | * Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler | ||
| 5 | * for convergence integrated media GmbH | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU Lesser General Public License | ||
| 9 | * as published by the Free Software Foundation; either version 2.1 | ||
| 10 | * of the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #ifndef _DVB_DEMUX_H_ | ||
| 24 | #define _DVB_DEMUX_H_ | ||
| 25 | |||
| 26 | #include <linux/time.h> | ||
| 27 | #include <linux/timer.h> | ||
| 28 | #include <linux/spinlock.h> | ||
| 29 | #include <linux/mutex.h> | ||
| 30 | |||
| 31 | #include "demux.h" | ||
| 32 | |||
| 33 | #define DMX_TYPE_TS 0 | ||
| 34 | #define DMX_TYPE_SEC 1 | ||
| 35 | #define DMX_TYPE_PES 2 | ||
| 36 | |||
| 37 | #define DMX_STATE_FREE 0 | ||
| 38 | #define DMX_STATE_ALLOCATED 1 | ||
| 39 | #define DMX_STATE_SET 2 | ||
| 40 | #define DMX_STATE_READY 3 | ||
| 41 | #define DMX_STATE_GO 4 | ||
| 42 | |||
| 43 | #define DVB_DEMUX_MASK_MAX 18 | ||
| 44 | |||
| 45 | #define MAX_PID 0x1fff | ||
| 46 | |||
| 47 | #define SPEED_PKTS_INTERVAL 50000 | ||
| 48 | |||
| 49 | struct dvb_demux_filter { | ||
| 50 | struct dmx_section_filter filter; | ||
| 51 | u8 maskandmode[DMX_MAX_FILTER_SIZE]; | ||
| 52 | u8 maskandnotmode[DMX_MAX_FILTER_SIZE]; | ||
| 53 | int doneq; | ||
| 54 | |||
| 55 | struct dvb_demux_filter *next; | ||
| 56 | struct dvb_demux_feed *feed; | ||
| 57 | int index; | ||
| 58 | int state; | ||
| 59 | int type; | ||
| 60 | |||
| 61 | u16 hw_handle; | ||
| 62 | struct timer_list timer; | ||
| 63 | }; | ||
| 64 | |||
| 65 | #define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head) | ||
| 66 | |||
| 67 | struct dvb_demux_feed { | ||
| 68 | union { | ||
| 69 | struct dmx_ts_feed ts; | ||
| 70 | struct dmx_section_feed sec; | ||
| 71 | } feed; | ||
| 72 | |||
| 73 | union { | ||
| 74 | dmx_ts_cb ts; | ||
| 75 | dmx_section_cb sec; | ||
| 76 | } cb; | ||
| 77 | |||
| 78 | struct dvb_demux *demux; | ||
| 79 | void *priv; | ||
| 80 | int type; | ||
| 81 | int state; | ||
| 82 | u16 pid; | ||
| 83 | u8 *buffer; | ||
| 84 | int buffer_size; | ||
| 85 | |||
| 86 | struct timespec timeout; | ||
| 87 | struct dvb_demux_filter *filter; | ||
| 88 | |||
| 89 | int ts_type; | ||
| 90 | enum dmx_ts_pes pes_type; | ||
| 91 | |||
| 92 | int cc; | ||
| 93 | int pusi_seen; /* prevents feeding of garbage from previous section */ | ||
| 94 | |||
| 95 | u16 peslen; | ||
| 96 | |||
| 97 | struct list_head list_head; | ||
| 98 | unsigned int index; /* a unique index for each feed (can be used as hardware pid filter index) */ | ||
| 99 | }; | ||
| 100 | |||
| 101 | struct dvb_demux { | ||
| 102 | struct dmx_demux dmx; | ||
| 103 | void *priv; | ||
| 104 | int filternum; | ||
| 105 | int feednum; | ||
| 106 | int (*start_feed)(struct dvb_demux_feed *feed); | ||
| 107 | int (*stop_feed)(struct dvb_demux_feed *feed); | ||
| 108 | int (*write_to_decoder)(struct dvb_demux_feed *feed, | ||
| 109 | const u8 *buf, size_t len); | ||
| 110 | u32 (*check_crc32)(struct dvb_demux_feed *feed, | ||
| 111 | const u8 *buf, size_t len); | ||
| 112 | void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst, | ||
| 113 | const u8 *src, size_t len); | ||
| 114 | |||
| 115 | int users; | ||
| 116 | #define MAX_DVB_DEMUX_USERS 10 | ||
| 117 | struct dvb_demux_filter *filter; | ||
| 118 | struct dvb_demux_feed *feed; | ||
| 119 | |||
| 120 | struct list_head frontend_list; | ||
| 121 | |||
| 122 | struct dvb_demux_feed *pesfilter[DMX_TS_PES_OTHER]; | ||
| 123 | u16 pids[DMX_TS_PES_OTHER]; | ||
| 124 | int playing; | ||
| 125 | int recording; | ||
| 126 | |||
| 127 | #define DMX_MAX_PID 0x2000 | ||
| 128 | struct list_head feed_list; | ||
| 129 | u8 tsbuf[204]; | ||
| 130 | int tsbufp; | ||
| 131 | |||
| 132 | struct mutex mutex; | ||
| 133 | spinlock_t lock; | ||
| 134 | |||
| 135 | uint8_t *cnt_storage; /* for TS continuity check */ | ||
| 136 | |||
| 137 | struct timespec speed_last_time; /* for TS speed check */ | ||
| 138 | uint32_t speed_pkts_cnt; /* for TS speed check */ | ||
| 139 | }; | ||
| 140 | |||
| 141 | int dvb_dmx_init(struct dvb_demux *dvbdemux); | ||
| 142 | void dvb_dmx_release(struct dvb_demux *dvbdemux); | ||
| 143 | void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, | ||
| 144 | size_t count); | ||
| 145 | void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count); | ||
| 146 | void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, | ||
| 147 | size_t count); | ||
| 148 | |||
| 149 | #endif /* _DVB_DEMUX_H_ */ | ||
diff --git a/drivers/media/dvb/dvb-core/dvb_filter.c b/drivers/media/dvb/dvb-core/dvb_filter.c new file mode 100644 index 00000000000..772003fb182 --- /dev/null +++ b/drivers/media/dvb/dvb-core/dvb_filter.c | |||
| @@ -0,0 +1,603 @@ | |||
| 1 | #include <linux/kernel.h> | ||
| 2 | #include <linux/module.h> | ||
| 3 | #include <linux/string.h> | ||
| 4 | #include "dvb_filter.h" | ||
| 5 | |||
| 6 | #if 0 | ||
| 7 | static unsigned int bitrates[3][16] = | ||
| 8 | {{0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}, | ||
| 9 | {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0}, | ||
| 10 | {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}}; | ||
| 11 | #endif | ||
| 12 | |||
| 13 | static u32 freq[4] = {480, 441, 320, 0}; | ||
| 14 | |||
| 15 | static unsigned int ac3_bitrates[32] = | ||
| 16 | {32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640, | ||
| 17 | 0,0,0,0,0,0,0,0,0,0,0,0,0}; | ||
| 18 | |||
| 19 | static u32 ac3_frames[3][32] = | ||
| 20 | {{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024, | ||
| 21 | 1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0}, | ||
| 22 | {69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114, | ||
| 23 | 1253,1393,0,0,0,0,0,0,0,0,0,0,0,0,0}, | ||
| 24 | {96,120,144,168,192,240,288,336,384,480,576,672,768,960,1152,1344, | ||
| 25 | 1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}}; | ||
| 26 | |||
| 27 | |||
| 28 | |||
| 29 | #if 0 | ||
| 30 | static void setup_ts2pes(ipack *pa, ipack *pv, u16 *pida, u16 *pidv, | ||
| 31 | void (*pes_write)(u8 *buf, int count, void *data), | ||
| 32 | void *priv) | ||
| 33 | { | ||
| 34 | dvb_filter_ipack_init(pa, IPACKS, pes_write); | ||
| 35 | dvb_filter_ipack_init(pv, IPACKS, pes_write); | ||
| 36 | pa->pid = pida; | ||
| 37 | pv->pid = pidv; | ||
| 38 | pa->data = priv; | ||
| 39 | pv->data = priv; | ||
| 40 | } | ||
| 41 | #endif | ||
| 42 | |||
| 43 | #if 0 | ||
| 44 | static void ts_to_pes(ipack *p, u8 *buf) // don't need count (=188) | ||
| 45 | { | ||
| 46 | u8 off = 0; | ||
| 47 | |||
| 48 | if (!buf || !p ){ | ||
| 49 | printk("NULL POINTER IDIOT\n"); | ||
| 50 | return; | ||
| 51 | } | ||
| 52 | if (buf[1]&PAY_START) { | ||
| 53 | if (p->plength == MMAX_PLENGTH-6 && p->found>6){ | ||
| 54 | p->plength = p->found-6; | ||
| 55 | p->found = 0; | ||
| 56 | send_ipack(p); | ||
| 57 | dvb_filter_ipack_reset(p); | ||
| 58 | } | ||
| 59 | } | ||
| 60 | if (buf[3] & ADAPT_FIELD) { // adaptation field? | ||
| 61 | off = buf[4] + 1; | ||
| 62 | if (off+4 > 187) return; | ||
| 63 | } | ||
| 64 | dvb_filter_instant_repack(buf+4+off, TS_SIZE-4-off, p); | ||
| 65 | } | ||
| 66 | #endif | ||
| 67 | |||
| 68 | #if 0 | ||
| 69 | /* needs 5 byte input, returns picture coding type*/ | ||
| 70 | static int read_picture_header(u8 *headr, struct mpg_picture *pic, int field, int pr) | ||
| 71 | { | ||
| 72 | u8 pct; | ||
| 73 | |||
| 74 | if (pr) printk( "Pic header: "); | ||
| 75 | pic->temporal_reference[field] = (( headr[0] << 2 ) | | ||
| 76 | (headr[1] & 0x03) )& 0x03ff; | ||
| 77 | if (pr) printk( " temp ref: 0x%04x", pic->temporal_reference[field]); | ||
| 78 | |||
| 79 | pct = ( headr[1] >> 2 ) & 0x07; | ||
| 80 | pic->picture_coding_type[field] = pct; | ||
| 81 | if (pr) { | ||
| 82 | switch(pct){ | ||
| 83 | case I_FRAME: | ||
| 84 | printk( " I-FRAME"); | ||
| 85 | break; | ||
| 86 | case B_FRAME: | ||
| 87 | printk( " B-FRAME"); | ||
| 88 | break; | ||
| 89 | case P_FRAME: | ||
| 90 | printk( " P-FRAME"); | ||
| 91 | break; | ||
| 92 | } | ||
| 93 | } | ||
| 94 | |||
| 95 | |||
| 96 | pic->vinfo.vbv_delay = (( headr[1] >> 5 ) | ( headr[2] << 3) | | ||
| 97 | ( (headr[3] & 0x1F) << 11) ) & 0xffff; | ||
| 98 | |||
| 99 | if (pr) printk( " vbv delay: 0x%04x", pic->vinfo.vbv_delay); | ||
| 100 | |||
| 101 | pic->picture_header_parameter = ( headr[3] & 0xe0 ) | | ||
| 102 | ((headr[4] & 0x80) >> 3); | ||
| 103 | |||
| 104 | if ( pct == B_FRAME ){ | ||
| 105 | pic->picture_header_parameter |= ( headr[4] >> 3 ) & 0x0f; | ||
| 106 | } | ||
| 107 | if (pr) printk( " pic head param: 0x%x", | ||
| 108 | pic->picture_header_parameter); | ||
| 109 | |||
| 110 | return pct; | ||
| 111 | } | ||
| 112 | #endif | ||
| 113 | |||
| 114 | #if 0 | ||
| 115 | /* needs 4 byte input */ | ||
| 116 | static int read_gop_header(u8 *headr, struct mpg_picture *pic, int pr) | ||
| 117 | { | ||
| 118 | if (pr) printk("GOP header: "); | ||
| 119 | |||
| 120 | pic->time_code = (( headr[0] << 17 ) | ( headr[1] << 9) | | ||
| 121 | ( headr[2] << 1 ) | (headr[3] &0x01)) & 0x1ffffff; | ||
| 122 | |||
| 123 | if (pr) printk(" time: %d:%d.%d ", (headr[0]>>2)& 0x1F, | ||
| 124 | ((headr[0]<<4)& 0x30)| ((headr[1]>>4)& 0x0F), | ||
| 125 | ((headr[1]<<3)& 0x38)| ((headr[2]>>5)& 0x0F)); | ||
| 126 | |||
| 127 | if ( ( headr[3] & 0x40 ) != 0 ){ | ||
| 128 | pic->closed_gop = 1; | ||
| 129 | } else { | ||
| 130 | pic->closed_gop = 0; | ||
| 131 | } | ||
| 132 | if (pr) printk("closed: %d", pic->closed_gop); | ||
| 133 | |||
| 134 | if ( ( headr[3] & 0x20 ) != 0 ){ | ||
| 135 | pic->broken_link = 1; | ||
| 136 | } else { | ||
| 137 | pic->broken_link = 0; | ||
| 138 | } | ||
| 139 | if (pr) printk(" broken: %d\n", pic->broken_link); | ||
| 140 | |||
| 141 | return 0; | ||
| 142 | } | ||
| 143 | #endif | ||
| 144 | |||
| 145 | #if 0 | ||
| 146 | /* needs 8 byte input */ | ||
| 147 | static int read_sequence_header(u8 *headr, struct dvb_video_info *vi, int pr) | ||
| 148 | { | ||
| 149 | int sw; | ||
| 150 | int form = -1; | ||
| 151 | |||
| 152 | if (pr) printk("Reading sequence header\n"); | ||
| 153 | |||
| 154 | vi->horizontal_size = ((headr[1] &0xF0) >> 4) | (headr[0] << 4); | ||
| 155 | vi->vertical_size = ((headr[1] &0x0F) << 8) | (headr[2]); | ||
| 156 | |||
| 157 | sw = (int)((headr[3]&0xF0) >> 4) ; | ||
| 158 | |||
| 159 | switch( sw ){ | ||
| 160 | case 1: | ||
| 161 | if (pr) | ||
| 162 | printk("Videostream: ASPECT: 1:1"); | ||
| 163 | vi->aspect_ratio = 100; | ||
| 164 | break; | ||
| 165 | case 2: | ||
| 166 | if (pr) | ||
| 167 | printk("Videostream: ASPECT: 4:3"); | ||
| 168 | vi->aspect_ratio = 133; | ||
| 169 | break; | ||
| 170 | case 3: | ||
| 171 | if (pr) | ||
| 172 | printk("Videostream: ASPECT: 16:9"); | ||
| 173 | vi->aspect_ratio = 177; | ||
| 174 | break; | ||
| 175 | case 4: | ||
| 176 | if (pr) | ||
| 177 | printk("Videostream: ASPECT: 2.21:1"); | ||
| 178 | vi->aspect_ratio = 221; | ||
| 179 | break; | ||
| 180 | |||
| 181 | case 5 ... 15: | ||
| 182 | if (pr) | ||
| 183 | printk("Videostream: ASPECT: reserved"); | ||
| 184 | vi->aspect_ratio = 0; | ||
| 185 | break; | ||
| 186 | |||
| 187 | default: | ||
| 188 | vi->aspect_ratio = 0; | ||
| 189 | return -1; | ||
| 190 | } | ||
| 191 | |||
| 192 | if (pr) | ||
| 193 | printk(" Size = %dx%d",vi->horizontal_size,vi->vertical_size); | ||
| 194 | |||
| 195 | sw = (int)(headr[3]&0x0F); | ||
| 196 | |||
| 197 | switch ( sw ) { | ||
| 198 | case 1: | ||
| 199 | if (pr) | ||
| 200 | printk(" FRate: 23.976 fps"); | ||
| 201 | vi->framerate = 23976; | ||
| 202 | form = -1; | ||
| 203 | break; | ||
| 204 | case 2: | ||
| 205 | if (pr) | ||
| 206 | printk(" FRate: 24 fps"); | ||
| 207 | vi->framerate = 24000; | ||
| 208 | form = -1; | ||
| 209 | break; | ||
| 210 | case 3: | ||
| 211 | if (pr) | ||
| 212 | printk(" FRate: 25 fps"); | ||
| 213 | vi->framerate = 25000; | ||
| 214 | form = VIDEO_MODE_PAL; | ||
| 215 | break; | ||
| 216 | case 4: | ||
| 217 | if (pr) | ||
| 218 | printk(" FRate: 29.97 fps"); | ||
| 219 | vi->framerate = 29970; | ||
| 220 | form = VIDEO_MODE_NTSC; | ||
| 221 | break; | ||
| 222 | case 5: | ||
| 223 | if (pr) | ||
| 224 | printk(" FRate: 30 fps"); | ||
| 225 | vi->framerate = 30000; | ||
| 226 | form = VIDEO_MODE_NTSC; | ||
| 227 | break; | ||
| 228 | case 6: | ||
| 229 | if (pr) | ||
| 230 | printk(" FRate: 50 fps"); | ||
| 231 | vi->framerate = 50000; | ||
| 232 | form = VIDEO_MODE_PAL; | ||
| 233 | break; | ||
| 234 | case 7: | ||
| 235 | if (pr) | ||
| 236 | printk(" FRate: 60 fps"); | ||
| 237 | vi->framerate = 60000; | ||
| 238 | form = VIDEO_MODE_NTSC; | ||
| 239 | break; | ||
| 240 | } | ||
| 241 | |||
| 242 | vi->bit_rate = (headr[4] << 10) | (headr[5] << 2) | (headr[6] & 0x03); | ||
| 243 | |||
| 244 | vi->vbv_buffer_size | ||
| 245 | = (( headr[6] & 0xF8) >> 3 ) | (( headr[7] & 0x1F )<< 5); | ||
| 246 | |||
| 247 | if (pr){ | ||
| 248 | printk(" BRate: %d Mbit/s",4*(vi->bit_rate)/10000); | ||
| 249 | printk(" vbvbuffer %d",16*1024*(vi->vbv_buffer_size)); | ||
| 250 | printk("\n"); | ||
| 251 | } | ||
| 252 | |||
| 253 | vi->video_format = form; | ||
| 254 | |||
| 255 | return 0; | ||
| 256 | } | ||
| 257 | #endif | ||
| 258 | |||
| 259 | |||
| 260 | #if 0 | ||
| 261 | static int get_vinfo(u8 *mbuf, int count, struct dvb_video_info *vi, int pr) | ||
| 262 | { | ||
| 263 | u8 *headr; | ||
| 264 | int found = 0; | ||
| 265 | int c = 0; | ||
| 266 | |||
| 267 | while (found < 4 && c+4 < count){ | ||
| 268 | u8 *b; | ||
| 269 | |||
| 270 | b = mbuf+c; | ||
| 271 | if ( b[0] == 0x00 && b[1] == 0x00 && b[2] == 0x01 | ||
| 272 | && b[3] == 0xb3) found = 4; | ||
| 273 | else { | ||
| 274 | c++; | ||
| 275 | } | ||
| 276 | } | ||
| 277 | |||
| 278 | if (! found) return -1; | ||
| 279 | c += 4; | ||
| 280 | if (c+12 >= count) return -1; | ||
| 281 | headr = mbuf+c; | ||
| 282 | if (read_sequence_header(headr, vi, pr) < 0) return -1; | ||
| 283 | vi->off = c-4; | ||
| 284 | return 0; | ||
| 285 | } | ||
| 286 | #endif | ||
| 287 | |||
| 288 | |||
| 289 | #if 0 | ||
| 290 | static int get_ainfo(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr) | ||
| 291 | { | ||
| 292 | u8 *headr; | ||
| 293 | int found = 0; | ||
| 294 | int c = 0; | ||
| 295 | int fr = 0; | ||
| 296 | |||
| 297 | while (found < 2 && c < count){ | ||
| 298 | u8 b[2]; | ||
| 299 | memcpy( b, mbuf+c, 2); | ||
| 300 | |||
| 301 | if ( b[0] == 0xff && (b[1] & 0xf8) == 0xf8) | ||
| 302 | found = 2; | ||
| 303 | else { | ||
| 304 | c++; | ||
| 305 | } | ||
| 306 | } | ||
| 307 | |||
| 308 | if (!found) return -1; | ||
| 309 | |||
| 310 | if (c+3 >= count) return -1; | ||
| 311 | headr = mbuf+c; | ||
| 312 | |||
| 313 | ai->layer = (headr[1] & 0x06) >> 1; | ||
| 314 | |||
| 315 | if (pr) | ||
| 316 | printk("Audiostream: Layer: %d", 4-ai->layer); | ||
| 317 | |||
| 318 | |||
| 319 | ai->bit_rate = bitrates[(3-ai->layer)][(headr[2] >> 4 )]*1000; | ||
| 320 | |||
| 321 | if (pr){ | ||
| 322 | if (ai->bit_rate == 0) | ||
| 323 | printk(" Bit rate: free"); | ||
| 324 | else if (ai->bit_rate == 0xf) | ||
| 325 | printk(" BRate: reserved"); | ||
| 326 | else | ||
| 327 | printk(" BRate: %d kb/s", ai->bit_rate/1000); | ||
| 328 | } | ||
| 329 | |||
| 330 | fr = (headr[2] & 0x0c ) >> 2; | ||
| 331 | ai->frequency = freq[fr]*100; | ||
| 332 | if (pr){ | ||
| 333 | if (ai->frequency == 3) | ||
| 334 | printk(" Freq: reserved\n"); | ||
| 335 | else | ||
| 336 | printk(" Freq: %d kHz\n",ai->frequency); | ||
| 337 | |||
| 338 | } | ||
| 339 | ai->off = c; | ||
| 340 | return 0; | ||
| 341 | } | ||
| 342 | #endif | ||
| 343 | |||
| 344 | |||
| 345 | int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr) | ||
| 346 | { | ||
| 347 | u8 *headr; | ||
| 348 | int found = 0; | ||
| 349 | int c = 0; | ||
| 350 | u8 frame = 0; | ||
| 351 | int fr = 0; | ||
| 352 | |||
| 353 | while ( !found && c < count){ | ||
| 354 | u8 *b = mbuf+c; | ||
| 355 | |||
| 356 | if ( b[0] == 0x0b && b[1] == 0x77 ) | ||
| 357 | found = 1; | ||
| 358 | else { | ||
| 359 | c++; | ||
| 360 | } | ||
| 361 | } | ||
| 362 | |||
| 363 | if (!found) return -1; | ||
| 364 | if (pr) | ||
| 365 | printk("Audiostream: AC3"); | ||
| 366 | |||
| 367 | ai->off = c; | ||
| 368 | if (c+5 >= count) return -1; | ||
| 369 | |||
| 370 | ai->layer = 0; // 0 for AC3 | ||
| 371 | headr = mbuf+c+2; | ||
| 372 | |||
| 373 | frame = (headr[2]&0x3f); | ||
| 374 | ai->bit_rate = ac3_bitrates[frame >> 1]*1000; | ||
| 375 | |||
| 376 | if (pr) | ||
| 377 | printk(" BRate: %d kb/s", (int) ai->bit_rate/1000); | ||
| 378 | |||
| 379 | ai->frequency = (headr[2] & 0xc0 ) >> 6; | ||
| 380 | fr = (headr[2] & 0xc0 ) >> 6; | ||
| 381 | ai->frequency = freq[fr]*100; | ||
| 382 | if (pr) printk (" Freq: %d Hz\n", (int) ai->frequency); | ||
| 383 | |||
| 384 | |||
| 385 | ai->framesize = ac3_frames[fr][frame >> 1]; | ||
| 386 | if ((frame & 1) && (fr == 1)) ai->framesize++; | ||
| 387 | ai->framesize = ai->framesize << 1; | ||
| 388 | if (pr) printk (" Framesize %d\n",(int) ai->framesize); | ||
| 389 | |||
| 390 | |||
| 391 | return 0; | ||
| 392 | } | ||
| 393 | EXPORT_SYMBOL(dvb_filter_get_ac3info); | ||
| 394 | |||
| 395 | |||
| 396 | #if 0 | ||
| 397 | static u8 *skip_pes_header(u8 **bufp) | ||
| 398 | { | ||
| 399 | u8 *inbuf = *bufp; | ||
| 400 | u8 *buf = inbuf; | ||
| 401 | u8 *pts = NULL; | ||
| 402 | int skip = 0; | ||
| 403 | |||
| 404 | static const int mpeg1_skip_table[16] = { | ||
| 405 | 1, 0xffff, 5, 10, 0xffff, 0xffff, 0xffff, 0xffff, | ||
| 406 | 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff | ||
| 407 | }; | ||
| 408 | |||
| 409 | |||
| 410 | if ((inbuf[6] & 0xc0) == 0x80){ /* mpeg2 */ | ||
| 411 | if (buf[7] & PTS_ONLY) | ||
| 412 | pts = buf+9; | ||
| 413 | else pts = NULL; | ||
| 414 | buf = inbuf + 9 + inbuf[8]; | ||
| 415 | } else { /* mpeg1 */ | ||
| 416 | for (buf = inbuf + 6; *buf == 0xff; buf++) | ||
| 417 | if (buf == inbuf + 6 + 16) { | ||
| 418 | break; | ||
| 419 | } | ||
| 420 | if ((*buf & 0xc0) == 0x40) | ||
| 421 | buf += 2; | ||
| 422 | skip = mpeg1_skip_table [*buf >> 4]; | ||
| 423 | if (skip == 5 || skip == 10) pts = buf; | ||
| 424 | else pts = NULL; | ||
| 425 | |||
| 426 | buf += mpeg1_skip_table [*buf >> 4]; | ||
| 427 | } | ||
| 428 | |||
| 429 | *bufp = buf; | ||
| 430 | return pts; | ||
| 431 | } | ||
| 432 | #endif | ||
| 433 | |||
| 434 | #if 0 | ||
| 435 | static void initialize_quant_matrix( u32 *matrix ) | ||
| 436 | { | ||
| 437 | int i; | ||
| 438 | |||
| 439 | matrix[0] = 0x08101013; | ||
| 440 | matrix[1] = 0x10131616; | ||
| 441 | matrix[2] = 0x16161616; | ||
| 442 | matrix[3] = 0x1a181a1b; | ||
| 443 | matrix[4] = 0x1b1b1a1a; | ||
| 444 | matrix[5] = 0x1a1a1b1b; | ||
| 445 | matrix[6] = 0x1b1d1d1d; | ||
| 446 | matrix[7] = 0x2222221d; | ||
| 447 | matrix[8] = 0x1d1d1b1b; | ||
| 448 | matrix[9] = 0x1d1d2020; | ||
| 449 | matrix[10] = 0x22222526; | ||
| 450 | matrix[11] = 0x25232322; | ||
| 451 | matrix[12] = 0x23262628; | ||
| 452 | matrix[13] = 0x28283030; | ||
| 453 | matrix[14] = 0x2e2e3838; | ||
| 454 | matrix[15] = 0x3a454553; | ||
| 455 | |||
| 456 | for ( i = 16 ; i < 32 ; i++ ) | ||
| 457 | matrix[i] = 0x10101010; | ||
| 458 | } | ||
| 459 | #endif | ||
| 460 | |||
| 461 | #if 0 | ||
| 462 | static void initialize_mpg_picture(struct mpg_picture *pic) | ||
| 463 | { | ||
| 464 | int i; | ||
| 465 | |||
| 466 | /* set MPEG1 */ | ||
| 467 | pic->mpeg1_flag = 1; | ||
| 468 | pic->profile_and_level = 0x4A ; /* MP@LL */ | ||
| 469 | pic->progressive_sequence = 1; | ||
| 470 | pic->low_delay = 0; | ||
| 471 | |||
| 472 | pic->sequence_display_extension_flag = 0; | ||
| 473 | for ( i = 0 ; i < 4 ; i++ ){ | ||
| 474 | pic->frame_centre_horizontal_offset[i] = 0; | ||
| 475 | pic->frame_centre_vertical_offset[i] = 0; | ||
| 476 | } | ||
| 477 | pic->last_frame_centre_horizontal_offset = 0; | ||
| 478 | pic->last_frame_centre_vertical_offset = 0; | ||
| 479 | |||
| 480 | pic->picture_display_extension_flag[0] = 0; | ||
| 481 | pic->picture_display_extension_flag[1] = 0; | ||
| 482 | pic->sequence_header_flag = 0; | ||
| 483 | pic->gop_flag = 0; | ||
| 484 | pic->sequence_end_flag = 0; | ||
| 485 | } | ||
| 486 | #endif | ||
| 487 | |||
| 488 | #if 0 | ||
| 489 | static void mpg_set_picture_parameter( int32_t field_type, struct mpg_picture *pic ) | ||
| 490 | { | ||
| 491 | int16_t last_h_offset; | ||
| 492 | int16_t last_v_offset; | ||
| 493 | |||
| 494 | int16_t *p_h_offset; | ||
| 495 | int16_t *p_v_offset; | ||
| 496 | |||
| 497 | if ( pic->mpeg1_flag ){ | ||
| 498 | pic->picture_structure[field_type] = VIDEO_FRAME_PICTURE; | ||
| 499 | pic->top_field_first = 0; | ||
| 500 | pic->repeat_first_field = 0; | ||
| 501 | pic->progressive_frame = 1; | ||
| 502 | pic->picture_coding_parameter = 0x000010; | ||
| 503 | } | ||
| 504 | |||
| 505 | /* Reset flag */ | ||
| 506 | pic->picture_display_extension_flag[field_type] = 0; | ||
| 507 | |||
| 508 | last_h_offset = pic->last_frame_centre_horizontal_offset; | ||
| 509 | last_v_offset = pic->last_frame_centre_vertical_offset; | ||
| 510 | if ( field_type == FIRST_FIELD ){ | ||
| 511 | p_h_offset = pic->frame_centre_horizontal_offset; | ||
| 512 | p_v_offset = pic->frame_centre_vertical_offset; | ||
| 513 | *p_h_offset = last_h_offset; | ||
| 514 | *(p_h_offset + 1) = last_h_offset; | ||
| 515 | *(p_h_offset + 2) = last_h_offset; | ||
| 516 | *p_v_offset = last_v_offset; | ||
| 517 | *(p_v_offset + 1) = last_v_offset; | ||
| 518 | *(p_v_offset + 2) = last_v_offset; | ||
| 519 | } else { | ||
| 520 | pic->frame_centre_horizontal_offset[3] = last_h_offset; | ||
| 521 | pic->frame_centre_vertical_offset[3] = last_v_offset; | ||
| 522 | } | ||
| 523 | } | ||
| 524 | #endif | ||
| 525 | |||
| 526 | #if 0 | ||
| 527 | static void init_mpg_picture( struct mpg_picture *pic, int chan, int32_t field_type) | ||
| 528 | { | ||
| 529 | pic->picture_header = 0; | ||
| 530 | pic->sequence_header_data | ||
| 531 | = ( INIT_HORIZONTAL_SIZE << 20 ) | ||
| 532 | | ( INIT_VERTICAL_SIZE << 8 ) | ||
| 533 | | ( INIT_ASPECT_RATIO << 4 ) | ||
| 534 | | ( INIT_FRAME_RATE ); | ||
| 535 | pic->mpeg1_flag = 0; | ||
| 536 | pic->vinfo.horizontal_size | ||
| 537 | = INIT_DISP_HORIZONTAL_SIZE; | ||
| 538 | pic->vinfo.vertical_size | ||
| 539 | = INIT_DISP_VERTICAL_SIZE; | ||
| 540 | pic->picture_display_extension_flag[field_type] | ||
| 541 | = 0; | ||
| 542 | pic->pts_flag[field_type] = 0; | ||
| 543 | |||
| 544 | pic->sequence_gop_header = 0; | ||
| 545 | pic->picture_header = 0; | ||
| 546 | pic->sequence_header_flag = 0; | ||
| 547 | pic->gop_flag = 0; | ||
| 548 | pic->sequence_end_flag = 0; | ||
| 549 | pic->sequence_display_extension_flag = 0; | ||
| 550 | pic->last_frame_centre_horizontal_offset = 0; | ||
| 551 | pic->last_frame_centre_vertical_offset = 0; | ||
| 552 | pic->channel = chan; | ||
| 553 | } | ||
| 554 | #endif | ||
| 555 | |||
| 556 | void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid, | ||
| 557 | dvb_filter_pes2ts_cb_t *cb, void *priv) | ||
| 558 | { | ||
| 559 | unsigned char *buf=p2ts->buf; | ||
| 560 | |||
| 561 | buf[0]=0x47; | ||
| 562 | buf[1]=(pid>>8); | ||
| 563 | buf[2]=pid&0xff; | ||
| 564 | p2ts->cc=0; | ||
| 565 | p2ts->cb=cb; | ||
| 566 | p2ts->priv=priv; | ||
| 567 | } | ||
| 568 | EXPORT_SYMBOL(dvb_filter_pes2ts_init); | ||
| 569 | |||
| 570 | int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, | ||
| 571 | int len, int payload_start) | ||
| 572 | { | ||
| 573 | unsigned char *buf=p2ts->buf; | ||
| 574 | int ret=0, rest; | ||
| 575 | |||
| 576 | //len=6+((pes[4]<<8)|pes[5]); | ||
| 577 | |||
| 578 | if (payload_start) | ||
| 579 | buf[1]|=0x40; | ||
| 580 | else | ||
| 581 | buf[1]&=~0x40; | ||
| 582 | while (len>=184) { | ||
| 583 | buf[3]=0x10|((p2ts->cc++)&0x0f); | ||
| 584 | memcpy(buf+4, pes, 184); | ||
| 585 | if ((ret=p2ts->cb(p2ts->priv, buf))) | ||
| 586 | return ret; | ||
| 587 | len-=184; pes+=184; | ||
| 588 | buf[1]&=~0x40; | ||
| 589 | } | ||
| 590 | if (!len) | ||
| 591 | return 0; | ||
| 592 | buf[3]=0x30|((p2ts->cc++)&0x0f); | ||
| 593 | rest=183-len; | ||
| 594 | if (rest) { | ||
| 595 | buf[5]=0x00; | ||
| 596 | if (rest-1) | ||
| 597 | memset(buf+6, 0xff, rest-1); | ||
| 598 | } | ||
| 599 | buf[4]=rest; | ||
| 600 | memcpy(buf+5+rest, pes, len); | ||
| 601 | return p2ts->cb(p2ts->priv, buf); | ||
| 602 | } | ||
| 603 | 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 new file mode 100644 index 00000000000..375e3be184b --- /dev/null +++ b/drivers/media/dvb/dvb-core/dvb_filter.h | |||
| @@ -0,0 +1,246 @@ | |||
| 1 | /* | ||
| 2 | * dvb_filter.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2003 Convergence GmbH | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public License | ||
| 8 | * as published by the Free Software Foundation; either version 2.1 | ||
| 9 | * of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 19 | */ | ||
| 20 | |||
| 21 | #ifndef _DVB_FILTER_H_ | ||
| 22 | #define _DVB_FILTER_H_ | ||
| 23 | |||
| 24 | #include <linux/slab.h> | ||
| 25 | |||
| 26 | #include "demux.h" | ||
| 27 | |||
| 28 | typedef int (dvb_filter_pes2ts_cb_t) (void *, unsigned char *); | ||
| 29 | |||
| 30 | struct dvb_filter_pes2ts { | ||
| 31 | unsigned char buf[188]; | ||
| 32 | unsigned char cc; | ||
| 33 | dvb_filter_pes2ts_cb_t *cb; | ||
| 34 | void *priv; | ||
| 35 | }; | ||
| 36 | |||
| 37 | void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid, | ||
| 38 | dvb_filter_pes2ts_cb_t *cb, void *priv); | ||
| 39 | |||
| 40 | int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes, | ||
| 41 | int len, int payload_start); | ||
| 42 | |||
| 43 | |||
| 44 | #define PROG_STREAM_MAP 0xBC | ||
| 45 | #define PRIVATE_STREAM1 0xBD | ||
| 46 | #define PADDING_STREAM 0xBE | ||
| 47 | #define PRIVATE_STREAM2 0xBF | ||
| 48 | #define AUDIO_STREAM_S 0xC0 | ||
| 49 | #define AUDIO_STREAM_E 0xDF | ||
| 50 | #define VIDEO_STREAM_S 0xE0 | ||
| 51 | #define VIDEO_STREAM_E 0xEF | ||
| 52 | #define ECM_STREAM 0xF0 | ||
| 53 | #define EMM_STREAM 0xF1 | ||
| 54 | #define DSM_CC_STREAM 0xF2 | ||
| 55 | #define ISO13522_STREAM 0xF3 | ||
| 56 | #define PROG_STREAM_DIR 0xFF | ||
| 57 | |||
| 58 | #define DVB_PICTURE_START 0x00 | ||
| 59 | #define DVB_USER_START 0xb2 | ||
| 60 | #define DVB_SEQUENCE_HEADER 0xb3 | ||
| 61 | #define DVB_SEQUENCE_ERROR 0xb4 | ||
| 62 | #define DVB_EXTENSION_START 0xb5 | ||
| 63 | #define DVB_SEQUENCE_END 0xb7 | ||
| 64 | #define DVB_GOP_START 0xb8 | ||
| 65 | #define DVB_EXCEPT_SLICE 0xb0 | ||
| 66 | |||
| 67 | #define SEQUENCE_EXTENSION 0x01 | ||
| 68 | #define SEQUENCE_DISPLAY_EXTENSION 0x02 | ||
| 69 | #define PICTURE_CODING_EXTENSION 0x08 | ||
| 70 | #define QUANT_MATRIX_EXTENSION 0x03 | ||
| 71 | #define PICTURE_DISPLAY_EXTENSION 0x07 | ||
| 72 | |||
| 73 | #define I_FRAME 0x01 | ||
| 74 | #define B_FRAME 0x02 | ||
| 75 | #define P_FRAME 0x03 | ||
| 76 | |||
| 77 | /* Initialize sequence_data */ | ||
| 78 | #define INIT_HORIZONTAL_SIZE 720 | ||
| 79 | #define INIT_VERTICAL_SIZE 576 | ||
| 80 | #define INIT_ASPECT_RATIO 0x02 | ||
| 81 | #define INIT_FRAME_RATE 0x03 | ||
| 82 | #define INIT_DISP_HORIZONTAL_SIZE 540 | ||
| 83 | #define INIT_DISP_VERTICAL_SIZE 576 | ||
| 84 | |||
| 85 | |||
| 86 | //flags2 | ||
| 87 | #define PTS_DTS_FLAGS 0xC0 | ||
| 88 | #define ESCR_FLAG 0x20 | ||
| 89 | #define ES_RATE_FLAG 0x10 | ||
| 90 | #define DSM_TRICK_FLAG 0x08 | ||
| 91 | #define ADD_CPY_FLAG 0x04 | ||
| 92 | #define PES_CRC_FLAG 0x02 | ||
| 93 | #define PES_EXT_FLAG 0x01 | ||
| 94 | |||
| 95 | //pts_dts flags | ||
| 96 | #define PTS_ONLY 0x80 | ||
| 97 | #define PTS_DTS 0xC0 | ||
| 98 | |||
| 99 | #define TS_SIZE 188 | ||
| 100 | #define TRANS_ERROR 0x80 | ||
| 101 | #define PAY_START 0x40 | ||
| 102 | #define TRANS_PRIO 0x20 | ||
| 103 | #define PID_MASK_HI 0x1F | ||
| 104 | //flags | ||
| 105 | #define TRANS_SCRMBL1 0x80 | ||
| 106 | #define TRANS_SCRMBL2 0x40 | ||
| 107 | #define ADAPT_FIELD 0x20 | ||
| 108 | #define PAYLOAD 0x10 | ||
| 109 | #define COUNT_MASK 0x0F | ||
| 110 | |||
| 111 | // adaptation flags | ||
| 112 | #define DISCON_IND 0x80 | ||
| 113 | #define RAND_ACC_IND 0x40 | ||
| 114 | #define ES_PRI_IND 0x20 | ||
| 115 | #define PCR_FLAG 0x10 | ||
| 116 | #define OPCR_FLAG 0x08 | ||
| 117 | #define SPLICE_FLAG 0x04 | ||
| 118 | #define TRANS_PRIV 0x02 | ||
| 119 | #define ADAP_EXT_FLAG 0x01 | ||
| 120 | |||
| 121 | // adaptation extension flags | ||
| 122 | #define LTW_FLAG 0x80 | ||
| 123 | #define PIECE_RATE 0x40 | ||
| 124 | #define SEAM_SPLICE 0x20 | ||
| 125 | |||
| 126 | |||
| 127 | #define MAX_PLENGTH 0xFFFF | ||
| 128 | #define MMAX_PLENGTH (256*MAX_PLENGTH) | ||
| 129 | |||
| 130 | #ifndef IPACKS | ||
| 131 | #define IPACKS 2048 | ||
| 132 | #endif | ||
| 133 | |||
| 134 | struct ipack { | ||
| 135 | int size; | ||
| 136 | int found; | ||
| 137 | u8 *buf; | ||
| 138 | u8 cid; | ||
| 139 | u32 plength; | ||
| 140 | u8 plen[2]; | ||
| 141 | u8 flag1; | ||
| 142 | u8 flag2; | ||
| 143 | u8 hlength; | ||
| 144 | u8 pts[5]; | ||
| 145 | u16 *pid; | ||
| 146 | int mpeg; | ||
| 147 | u8 check; | ||
| 148 | int which; | ||
| 149 | int done; | ||
| 150 | void *data; | ||
| 151 | void (*func)(u8 *buf, int size, void *priv); | ||
| 152 | int count; | ||
| 153 | int repack_subids; | ||
| 154 | }; | ||
| 155 | |||
| 156 | struct dvb_video_info { | ||
| 157 | u32 horizontal_size; | ||
| 158 | u32 vertical_size; | ||
| 159 | u32 aspect_ratio; | ||
| 160 | u32 framerate; | ||
| 161 | u32 video_format; | ||
| 162 | u32 bit_rate; | ||
| 163 | u32 comp_bit_rate; | ||
| 164 | u32 vbv_buffer_size; | ||
| 165 | s16 vbv_delay; | ||
| 166 | u32 CSPF; | ||
| 167 | u32 off; | ||
| 168 | }; | ||
| 169 | |||
| 170 | #define OFF_SIZE 4 | ||
| 171 | #define FIRST_FIELD 0 | ||
| 172 | #define SECOND_FIELD 1 | ||
| 173 | #define VIDEO_FRAME_PICTURE 0x03 | ||
| 174 | |||
| 175 | struct mpg_picture { | ||
| 176 | int channel; | ||
| 177 | struct dvb_video_info vinfo; | ||
| 178 | u32 *sequence_gop_header; | ||
| 179 | u32 *picture_header; | ||
| 180 | s32 time_code; | ||
| 181 | int low_delay; | ||
| 182 | int closed_gop; | ||
| 183 | int broken_link; | ||
| 184 | int sequence_header_flag; | ||
| 185 | int gop_flag; | ||
| 186 | int sequence_end_flag; | ||
| 187 | |||
| 188 | u8 profile_and_level; | ||
| 189 | s32 picture_coding_parameter; | ||
| 190 | u32 matrix[32]; | ||
| 191 | s8 matrix_change_flag; | ||
| 192 | |||
| 193 | u8 picture_header_parameter; | ||
| 194 | /* bit 0 - 2: bwd f code | ||
| 195 | bit 3 : fpb vector | ||
| 196 | bit 4 - 6: fwd f code | ||
| 197 | bit 7 : fpf vector */ | ||
| 198 | |||
| 199 | int mpeg1_flag; | ||
| 200 | int progressive_sequence; | ||
| 201 | int sequence_display_extension_flag; | ||
| 202 | u32 sequence_header_data; | ||
| 203 | s16 last_frame_centre_horizontal_offset; | ||
| 204 | s16 last_frame_centre_vertical_offset; | ||
| 205 | |||
| 206 | u32 pts[2]; /* [0] 1st field, [1] 2nd field */ | ||
| 207 | int top_field_first; | ||
| 208 | int repeat_first_field; | ||
| 209 | int progressive_frame; | ||
| 210 | int bank; | ||
| 211 | int forward_bank; | ||
| 212 | int backward_bank; | ||
| 213 | int compress; | ||
| 214 | s16 frame_centre_horizontal_offset[OFF_SIZE]; | ||
| 215 | /* [0-2] 1st field, [3] 2nd field */ | ||
| 216 | s16 frame_centre_vertical_offset[OFF_SIZE]; | ||
| 217 | /* [0-2] 1st field, [3] 2nd field */ | ||
| 218 | s16 temporal_reference[2]; | ||
| 219 | /* [0] 1st field, [1] 2nd field */ | ||
| 220 | |||
| 221 | s8 picture_coding_type[2]; | ||
| 222 | /* [0] 1st field, [1] 2nd field */ | ||
| 223 | s8 picture_structure[2]; | ||
| 224 | /* [0] 1st field, [1] 2nd field */ | ||
| 225 | s8 picture_display_extension_flag[2]; | ||
| 226 | /* [0] 1st field, [1] 2nd field */ | ||
| 227 | /* picture_display_extenion() 0:no 1:exit*/ | ||
| 228 | s8 pts_flag[2]; | ||
| 229 | /* [0] 1st field, [1] 2nd field */ | ||
| 230 | }; | ||
| 231 | |||
| 232 | struct dvb_audio_info { | ||
| 233 | int layer; | ||
| 234 | u32 bit_rate; | ||
| 235 | u32 frequency; | ||
| 236 | u32 mode; | ||
| 237 | u32 mode_extension ; | ||
| 238 | u32 emphasis; | ||
| 239 | u32 framesize; | ||
| 240 | u32 off; | ||
| 241 | }; | ||
| 242 | |||
| 243 | int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr); | ||
| 244 | |||
| 245 | |||
| 246 | #endif | ||
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c new file mode 100644 index 00000000000..efe9c30605e --- /dev/null +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c | |||
| @@ -0,0 +1,2173 @@ | |||
| 1 | /* | ||
| 2 | * dvb_frontend.c: DVB frontend tuning interface/thread | ||
| 3 | * | ||
| 4 | * | ||
| 5 | * Copyright (C) 1999-2001 Ralph Metzler | ||
| 6 | * Marcus Metzler | ||
| 7 | * Holger Waechtler | ||
| 8 | * for convergence integrated media GmbH | ||
| 9 | * | ||
| 10 | * Copyright (C) 2004 Andrew de Quincey (tuning thread cleanup) | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or | ||
| 13 | * modify it under the terms of the GNU General Public License | ||
| 14 | * as published by the Free Software Foundation; either version 2 | ||
| 15 | * of the License, or (at your option) any later version. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU General Public License for more details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU General Public License | ||
| 23 | * along with this program; if not, write to the Free Software | ||
| 24 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 25 | * Or, point your browser to http://www.gnu.org/copyleft/gpl.html | ||
| 26 | */ | ||
| 27 | |||
| 28 | #include <linux/string.h> | ||
| 29 | #include <linux/kernel.h> | ||
| 30 | #include <linux/sched.h> | ||
| 31 | #include <linux/wait.h> | ||
| 32 | #include <linux/slab.h> | ||
| 33 | #include <linux/poll.h> | ||
| 34 | #include <linux/semaphore.h> | ||
| 35 | #include <linux/module.h> | ||
| 36 | #include <linux/list.h> | ||
| 37 | #include <linux/freezer.h> | ||
| 38 | #include <linux/jiffies.h> | ||
| 39 | #include <linux/kthread.h> | ||
| 40 | #include <asm/processor.h> | ||
| 41 | |||
| 42 | #include "dvb_frontend.h" | ||
| 43 | #include "dvbdev.h" | ||
| 44 | #include <linux/dvb/version.h> | ||
| 45 | |||
| 46 | static int dvb_frontend_debug; | ||
| 47 | static int dvb_shutdown_timeout; | ||
| 48 | static int dvb_force_auto_inversion; | ||
| 49 | static int dvb_override_tune_delay; | ||
| 50 | static int dvb_powerdown_on_sleep = 1; | ||
| 51 | static int dvb_mfe_wait_time = 5; | ||
| 52 | |||
| 53 | module_param_named(frontend_debug, dvb_frontend_debug, int, 0644); | ||
| 54 | MODULE_PARM_DESC(frontend_debug, "Turn on/off frontend core debugging (default:off)."); | ||
| 55 | module_param(dvb_shutdown_timeout, int, 0644); | ||
| 56 | MODULE_PARM_DESC(dvb_shutdown_timeout, "wait <shutdown_timeout> seconds after close() before suspending hardware"); | ||
| 57 | module_param(dvb_force_auto_inversion, int, 0644); | ||
| 58 | MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AUTO forced always"); | ||
| 59 | module_param(dvb_override_tune_delay, int, 0644); | ||
| 60 | MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt"); | ||
| 61 | module_param(dvb_powerdown_on_sleep, int, 0644); | ||
| 62 | MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)"); | ||
| 63 | module_param(dvb_mfe_wait_time, int, 0644); | ||
| 64 | MODULE_PARM_DESC(dvb_mfe_wait_time, "Wait up to <mfe_wait_time> seconds on open() for multi-frontend to become available (default:5 seconds)"); | ||
| 65 | |||
| 66 | #define dprintk if (dvb_frontend_debug) printk | ||
| 67 | |||
| 68 | #define FESTATE_IDLE 1 | ||
| 69 | #define FESTATE_RETUNE 2 | ||
| 70 | #define FESTATE_TUNING_FAST 4 | ||
| 71 | #define FESTATE_TUNING_SLOW 8 | ||
| 72 | #define FESTATE_TUNED 16 | ||
| 73 | #define FESTATE_ZIGZAG_FAST 32 | ||
| 74 | #define FESTATE_ZIGZAG_SLOW 64 | ||
| 75 | #define FESTATE_DISEQC 128 | ||
| 76 | #define FESTATE_ERROR 256 | ||
| 77 | #define FESTATE_WAITFORLOCK (FESTATE_TUNING_FAST | FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW | FESTATE_DISEQC) | ||
| 78 | #define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST) | ||
| 79 | #define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW) | ||
| 80 | #define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW) | ||
| 81 | |||
| 82 | #define FE_ALGO_HW 1 | ||
| 83 | /* | ||
| 84 | * FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling. | ||
| 85 | * FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune. | ||
| 86 | * FESTATE_TUNING_FAST. Tuning parameters have been supplied and fast zigzag scan is in progress. | ||
| 87 | * FESTATE_TUNING_SLOW. Tuning parameters have been supplied. Fast zigzag failed, so we're trying again, but slower. | ||
| 88 | * FESTATE_TUNED. The frontend has successfully locked on. | ||
| 89 | * FESTATE_ZIGZAG_FAST. The lock has been lost, and a fast zigzag has been initiated to try and regain it. | ||
| 90 | * FESTATE_ZIGZAG_SLOW. The lock has been lost. Fast zigzag has been failed, so we're trying again, but slower. | ||
| 91 | * FESTATE_DISEQC. A DISEQC command has just been issued. | ||
| 92 | * FESTATE_WAITFORLOCK. When we're waiting for a lock. | ||
| 93 | * FESTATE_SEARCHING_FAST. When we're searching for a signal using a fast zigzag scan. | ||
| 94 | * FESTATE_SEARCHING_SLOW. When we're searching for a signal using a slow zigzag scan. | ||
| 95 | * FESTATE_LOSTLOCK. When the lock has been lost, and we're searching it again. | ||
| 96 | */ | ||
| 97 | |||
| 98 | #define DVB_FE_NO_EXIT 0 | ||
| 99 | #define DVB_FE_NORMAL_EXIT 1 | ||
| 100 | #define DVB_FE_DEVICE_REMOVED 2 | ||
| 101 | |||
| 102 | static DEFINE_MUTEX(frontend_mutex); | ||
| 103 | |||
| 104 | struct dvb_frontend_private { | ||
| 105 | |||
| 106 | /* thread/frontend values */ | ||
| 107 | struct dvb_device *dvbdev; | ||
| 108 | struct dvb_frontend_parameters parameters_in; | ||
| 109 | struct dvb_frontend_parameters parameters_out; | ||
| 110 | struct dvb_fe_events events; | ||
| 111 | struct semaphore sem; | ||
| 112 | struct list_head list_head; | ||
| 113 | wait_queue_head_t wait_queue; | ||
| 114 | struct task_struct *thread; | ||
| 115 | unsigned long release_jiffies; | ||
| 116 | unsigned int exit; | ||
| 117 | unsigned int wakeup; | ||
| 118 | fe_status_t status; | ||
| 119 | unsigned long tune_mode_flags; | ||
| 120 | unsigned int delay; | ||
| 121 | unsigned int reinitialise; | ||
| 122 | int tone; | ||
| 123 | int voltage; | ||
| 124 | |||
| 125 | /* swzigzag values */ | ||
| 126 | unsigned int state; | ||
| 127 | unsigned int bending; | ||
| 128 | int lnb_drift; | ||
| 129 | unsigned int inversion; | ||
| 130 | unsigned int auto_step; | ||
| 131 | unsigned int auto_sub_step; | ||
| 132 | unsigned int started_auto_step; | ||
| 133 | unsigned int min_delay; | ||
| 134 | unsigned int max_drift; | ||
| 135 | unsigned int step_size; | ||
| 136 | int quality; | ||
| 137 | unsigned int check_wrapped; | ||
| 138 | enum dvbfe_search algo_status; | ||
| 139 | }; | ||
| 140 | |||
| 141 | static void dvb_frontend_wakeup(struct dvb_frontend *fe); | ||
| 142 | |||
| 143 | static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) | ||
| 144 | { | ||
| 145 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 146 | struct dvb_fe_events *events = &fepriv->events; | ||
| 147 | struct dvb_frontend_event *e; | ||
| 148 | int wp; | ||
| 149 | |||
| 150 | dprintk ("%s\n", __func__); | ||
| 151 | |||
| 152 | if (mutex_lock_interruptible (&events->mtx)) | ||
| 153 | return; | ||
| 154 | |||
| 155 | wp = (events->eventw + 1) % MAX_EVENT; | ||
| 156 | |||
| 157 | if (wp == events->eventr) { | ||
| 158 | events->overflow = 1; | ||
| 159 | events->eventr = (events->eventr + 1) % MAX_EVENT; | ||
| 160 | } | ||
| 161 | |||
| 162 | e = &events->events[events->eventw]; | ||
| 163 | |||
| 164 | if (status & FE_HAS_LOCK) | ||
| 165 | if (fe->ops.get_frontend) | ||
| 166 | fe->ops.get_frontend(fe, &fepriv->parameters_out); | ||
| 167 | |||
| 168 | e->parameters = fepriv->parameters_out; | ||
| 169 | |||
| 170 | events->eventw = wp; | ||
| 171 | |||
| 172 | mutex_unlock(&events->mtx); | ||
| 173 | |||
| 174 | e->status = status; | ||
| 175 | |||
| 176 | wake_up_interruptible (&events->wait_queue); | ||
| 177 | } | ||
| 178 | |||
| 179 | static int dvb_frontend_get_event(struct dvb_frontend *fe, | ||
| 180 | struct dvb_frontend_event *event, int flags) | ||
| 181 | { | ||
| 182 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 183 | struct dvb_fe_events *events = &fepriv->events; | ||
| 184 | |||
| 185 | dprintk ("%s\n", __func__); | ||
| 186 | |||
| 187 | if (events->overflow) { | ||
| 188 | events->overflow = 0; | ||
| 189 | return -EOVERFLOW; | ||
| 190 | } | ||
| 191 | |||
| 192 | if (events->eventw == events->eventr) { | ||
| 193 | int ret; | ||
| 194 | |||
| 195 | if (flags & O_NONBLOCK) | ||
| 196 | return -EWOULDBLOCK; | ||
| 197 | |||
| 198 | up(&fepriv->sem); | ||
| 199 | |||
| 200 | ret = wait_event_interruptible (events->wait_queue, | ||
| 201 | events->eventw != events->eventr); | ||
| 202 | |||
| 203 | if (down_interruptible (&fepriv->sem)) | ||
| 204 | return -ERESTARTSYS; | ||
| 205 | |||
| 206 | if (ret < 0) | ||
| 207 | return ret; | ||
| 208 | } | ||
| 209 | |||
| 210 | if (mutex_lock_interruptible (&events->mtx)) | ||
| 211 | return -ERESTARTSYS; | ||
| 212 | |||
| 213 | memcpy (event, &events->events[events->eventr], | ||
| 214 | sizeof(struct dvb_frontend_event)); | ||
| 215 | |||
| 216 | events->eventr = (events->eventr + 1) % MAX_EVENT; | ||
| 217 | |||
| 218 | mutex_unlock(&events->mtx); | ||
| 219 | |||
| 220 | return 0; | ||
| 221 | } | ||
| 222 | |||
| 223 | static void dvb_frontend_init(struct dvb_frontend *fe) | ||
| 224 | { | ||
| 225 | dprintk ("DVB: initialising adapter %i frontend %i (%s)...\n", | ||
| 226 | fe->dvb->num, | ||
| 227 | fe->id, | ||
| 228 | fe->ops.info.name); | ||
| 229 | |||
| 230 | if (fe->ops.init) | ||
| 231 | fe->ops.init(fe); | ||
| 232 | if (fe->ops.tuner_ops.init) { | ||
| 233 | if (fe->ops.i2c_gate_ctrl) | ||
| 234 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
| 235 | fe->ops.tuner_ops.init(fe); | ||
| 236 | if (fe->ops.i2c_gate_ctrl) | ||
| 237 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
| 238 | } | ||
| 239 | } | ||
| 240 | |||
| 241 | void dvb_frontend_reinitialise(struct dvb_frontend *fe) | ||
| 242 | { | ||
| 243 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 244 | |||
| 245 | fepriv->reinitialise = 1; | ||
| 246 | dvb_frontend_wakeup(fe); | ||
| 247 | } | ||
| 248 | EXPORT_SYMBOL(dvb_frontend_reinitialise); | ||
| 249 | |||
| 250 | static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepriv, int locked) | ||
| 251 | { | ||
| 252 | int q2; | ||
| 253 | |||
| 254 | dprintk ("%s\n", __func__); | ||
| 255 | |||
| 256 | if (locked) | ||
| 257 | (fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256; | ||
| 258 | else | ||
| 259 | (fepriv->quality) = (fepriv->quality * 220 + 0) / 256; | ||
| 260 | |||
| 261 | q2 = fepriv->quality - 128; | ||
| 262 | q2 *= q2; | ||
| 263 | |||
| 264 | fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128); | ||
| 265 | } | ||
| 266 | |||
| 267 | /** | ||
| 268 | * Performs automatic twiddling of frontend parameters. | ||
| 269 | * | ||
| 270 | * @param fe The frontend concerned. | ||
| 271 | * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT | ||
| 272 | * @returns Number of complete iterations that have been performed. | ||
| 273 | */ | ||
| 274 | static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped) | ||
| 275 | { | ||
| 276 | int autoinversion; | ||
| 277 | int ready = 0; | ||
| 278 | int fe_set_err = 0; | ||
| 279 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 280 | int original_inversion = fepriv->parameters_in.inversion; | ||
| 281 | u32 original_frequency = fepriv->parameters_in.frequency; | ||
| 282 | |||
| 283 | /* are we using autoinversion? */ | ||
| 284 | autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) && | ||
| 285 | (fepriv->parameters_in.inversion == INVERSION_AUTO)); | ||
| 286 | |||
| 287 | /* setup parameters correctly */ | ||
| 288 | while(!ready) { | ||
| 289 | /* calculate the lnb_drift */ | ||
| 290 | fepriv->lnb_drift = fepriv->auto_step * fepriv->step_size; | ||
| 291 | |||
| 292 | /* wrap the auto_step if we've exceeded the maximum drift */ | ||
| 293 | if (fepriv->lnb_drift > fepriv->max_drift) { | ||
| 294 | fepriv->auto_step = 0; | ||
| 295 | fepriv->auto_sub_step = 0; | ||
| 296 | fepriv->lnb_drift = 0; | ||
| 297 | } | ||
| 298 | |||
| 299 | /* perform inversion and +/- zigzag */ | ||
| 300 | switch(fepriv->auto_sub_step) { | ||
| 301 | case 0: | ||
| 302 | /* try with the current inversion and current drift setting */ | ||
| 303 | ready = 1; | ||
| 304 | break; | ||
| 305 | |||
| 306 | case 1: | ||
| 307 | if (!autoinversion) break; | ||
| 308 | |||
| 309 | fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF; | ||
| 310 | ready = 1; | ||
| 311 | break; | ||
| 312 | |||
| 313 | case 2: | ||
| 314 | if (fepriv->lnb_drift == 0) break; | ||
| 315 | |||
| 316 | fepriv->lnb_drift = -fepriv->lnb_drift; | ||
| 317 | ready = 1; | ||
| 318 | break; | ||
| 319 | |||
| 320 | case 3: | ||
| 321 | if (fepriv->lnb_drift == 0) break; | ||
| 322 | if (!autoinversion) break; | ||
| 323 | |||
| 324 | fepriv->inversion = (fepriv->inversion == INVERSION_OFF) ? INVERSION_ON : INVERSION_OFF; | ||
| 325 | fepriv->lnb_drift = -fepriv->lnb_drift; | ||
| 326 | ready = 1; | ||
| 327 | break; | ||
| 328 | |||
| 329 | default: | ||
| 330 | fepriv->auto_step++; | ||
| 331 | fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */ | ||
| 332 | break; | ||
| 333 | } | ||
| 334 | |||
| 335 | if (!ready) fepriv->auto_sub_step++; | ||
| 336 | } | ||
| 337 | |||
| 338 | /* if this attempt would hit where we started, indicate a complete | ||
| 339 | * iteration has occurred */ | ||
| 340 | if ((fepriv->auto_step == fepriv->started_auto_step) && | ||
| 341 | (fepriv->auto_sub_step == 0) && check_wrapped) { | ||
| 342 | return 1; | ||
| 343 | } | ||
| 344 | |||
| 345 | dprintk("%s: drift:%i inversion:%i auto_step:%i " | ||
| 346 | "auto_sub_step:%i started_auto_step:%i\n", | ||
| 347 | __func__, fepriv->lnb_drift, fepriv->inversion, | ||
| 348 | fepriv->auto_step, fepriv->auto_sub_step, fepriv->started_auto_step); | ||
| 349 | |||
| 350 | /* set the frontend itself */ | ||
| 351 | fepriv->parameters_in.frequency += fepriv->lnb_drift; | ||
| 352 | if (autoinversion) | ||
| 353 | fepriv->parameters_in.inversion = fepriv->inversion; | ||
| 354 | if (fe->ops.set_frontend) | ||
| 355 | fe_set_err = fe->ops.set_frontend(fe, &fepriv->parameters_in); | ||
| 356 | fepriv->parameters_out = fepriv->parameters_in; | ||
| 357 | if (fe_set_err < 0) { | ||
| 358 | fepriv->state = FESTATE_ERROR; | ||
| 359 | return fe_set_err; | ||
| 360 | } | ||
| 361 | |||
| 362 | fepriv->parameters_in.frequency = original_frequency; | ||
| 363 | fepriv->parameters_in.inversion = original_inversion; | ||
| 364 | |||
| 365 | fepriv->auto_sub_step++; | ||
| 366 | return 0; | ||
| 367 | } | ||
| 368 | |||
| 369 | static void dvb_frontend_swzigzag(struct dvb_frontend *fe) | ||
| 370 | { | ||
| 371 | fe_status_t s = 0; | ||
| 372 | int retval = 0; | ||
| 373 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 374 | |||
| 375 | /* if we've got no parameters, just keep idling */ | ||
| 376 | if (fepriv->state & FESTATE_IDLE) { | ||
| 377 | fepriv->delay = 3*HZ; | ||
| 378 | fepriv->quality = 0; | ||
| 379 | return; | ||
| 380 | } | ||
| 381 | |||
| 382 | /* in SCAN mode, we just set the frontend when asked and leave it alone */ | ||
| 383 | if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) { | ||
| 384 | if (fepriv->state & FESTATE_RETUNE) { | ||
| 385 | if (fe->ops.set_frontend) | ||
| 386 | retval = fe->ops.set_frontend(fe, | ||
| 387 | &fepriv->parameters_in); | ||
| 388 | fepriv->parameters_out = fepriv->parameters_in; | ||
| 389 | if (retval < 0) | ||
| 390 | fepriv->state = FESTATE_ERROR; | ||
| 391 | else | ||
| 392 | fepriv->state = FESTATE_TUNED; | ||
| 393 | } | ||
| 394 | fepriv->delay = 3*HZ; | ||
| 395 | fepriv->quality = 0; | ||
| 396 | return; | ||
| 397 | } | ||
| 398 | |||
| 399 | /* get the frontend status */ | ||
| 400 | if (fepriv->state & FESTATE_RETUNE) { | ||
| 401 | s = 0; | ||
| 402 | } else { | ||
| 403 | if (fe->ops.read_status) | ||
| 404 | fe->ops.read_status(fe, &s); | ||
| 405 | if (s != fepriv->status) { | ||
| 406 | dvb_frontend_add_event(fe, s); | ||
| 407 | fepriv->status = s; | ||
| 408 | } | ||
| 409 | } | ||
| 410 | |||
| 411 | /* if we're not tuned, and we have a lock, move to the TUNED state */ | ||
| 412 | if ((fepriv->state & FESTATE_WAITFORLOCK) && (s & FE_HAS_LOCK)) { | ||
| 413 | dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); | ||
| 414 | fepriv->state = FESTATE_TUNED; | ||
| 415 | |||
| 416 | /* if we're tuned, then we have determined the correct inversion */ | ||
| 417 | if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) && | ||
| 418 | (fepriv->parameters_in.inversion == INVERSION_AUTO)) { | ||
| 419 | fepriv->parameters_in.inversion = fepriv->inversion; | ||
| 420 | } | ||
| 421 | return; | ||
| 422 | } | ||
| 423 | |||
| 424 | /* if we are tuned already, check we're still locked */ | ||
| 425 | if (fepriv->state & FESTATE_TUNED) { | ||
| 426 | dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); | ||
| 427 | |||
| 428 | /* we're tuned, and the lock is still good... */ | ||
| 429 | if (s & FE_HAS_LOCK) { | ||
| 430 | return; | ||
| 431 | } else { /* if we _WERE_ tuned, but now don't have a lock */ | ||
| 432 | fepriv->state = FESTATE_ZIGZAG_FAST; | ||
| 433 | fepriv->started_auto_step = fepriv->auto_step; | ||
| 434 | fepriv->check_wrapped = 0; | ||
| 435 | } | ||
| 436 | } | ||
| 437 | |||
| 438 | /* don't actually do anything if we're in the LOSTLOCK state, | ||
| 439 | * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */ | ||
| 440 | if ((fepriv->state & FESTATE_LOSTLOCK) && | ||
| 441 | (fe->ops.info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) { | ||
| 442 | dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); | ||
| 443 | return; | ||
| 444 | } | ||
| 445 | |||
| 446 | /* don't do anything if we're in the DISEQC state, since this | ||
| 447 | * might be someone with a motorized dish controlled by DISEQC. | ||
| 448 | * If its actually a re-tune, there will be a SET_FRONTEND soon enough. */ | ||
| 449 | if (fepriv->state & FESTATE_DISEQC) { | ||
| 450 | dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); | ||
| 451 | return; | ||
| 452 | } | ||
| 453 | |||
| 454 | /* if we're in the RETUNE state, set everything up for a brand | ||
| 455 | * new scan, keeping the current inversion setting, as the next | ||
| 456 | * tune is _very_ likely to require the same */ | ||
| 457 | if (fepriv->state & FESTATE_RETUNE) { | ||
| 458 | fepriv->lnb_drift = 0; | ||
| 459 | fepriv->auto_step = 0; | ||
| 460 | fepriv->auto_sub_step = 0; | ||
| 461 | fepriv->started_auto_step = 0; | ||
| 462 | fepriv->check_wrapped = 0; | ||
| 463 | } | ||
| 464 | |||
| 465 | /* fast zigzag. */ | ||
| 466 | if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) { | ||
| 467 | fepriv->delay = fepriv->min_delay; | ||
| 468 | |||
| 469 | /* perform a tune */ | ||
| 470 | retval = dvb_frontend_swzigzag_autotune(fe, | ||
| 471 | fepriv->check_wrapped); | ||
| 472 | if (retval < 0) { | ||
| 473 | return; | ||
| 474 | } else if (retval) { | ||
| 475 | /* OK, if we've run out of trials at the fast speed. | ||
| 476 | * Drop back to slow for the _next_ attempt */ | ||
| 477 | fepriv->state = FESTATE_SEARCHING_SLOW; | ||
| 478 | fepriv->started_auto_step = fepriv->auto_step; | ||
| 479 | return; | ||
| 480 | } | ||
| 481 | fepriv->check_wrapped = 1; | ||
| 482 | |||
| 483 | /* if we've just retuned, enter the ZIGZAG_FAST state. | ||
| 484 | * This ensures we cannot return from an | ||
| 485 | * FE_SET_FRONTEND ioctl before the first frontend tune | ||
| 486 | * occurs */ | ||
| 487 | if (fepriv->state & FESTATE_RETUNE) { | ||
| 488 | fepriv->state = FESTATE_TUNING_FAST; | ||
| 489 | } | ||
| 490 | } | ||
| 491 | |||
| 492 | /* slow zigzag */ | ||
| 493 | if (fepriv->state & FESTATE_SEARCHING_SLOW) { | ||
| 494 | dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); | ||
| 495 | |||
| 496 | /* Note: don't bother checking for wrapping; we stay in this | ||
| 497 | * state until we get a lock */ | ||
| 498 | dvb_frontend_swzigzag_autotune(fe, 0); | ||
| 499 | } | ||
| 500 | } | ||
| 501 | |||
| 502 | static int dvb_frontend_is_exiting(struct dvb_frontend *fe) | ||
| 503 | { | ||
| 504 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 505 | |||
| 506 | if (fepriv->exit != DVB_FE_NO_EXIT) | ||
| 507 | return 1; | ||
| 508 | |||
| 509 | if (fepriv->dvbdev->writers == 1) | ||
| 510 | if (time_after(jiffies, fepriv->release_jiffies + | ||
| 511 | dvb_shutdown_timeout * HZ)) | ||
| 512 | return 1; | ||
| 513 | |||
| 514 | return 0; | ||
| 515 | } | ||
| 516 | |||
| 517 | static int dvb_frontend_should_wakeup(struct dvb_frontend *fe) | ||
| 518 | { | ||
| 519 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 520 | |||
| 521 | if (fepriv->wakeup) { | ||
| 522 | fepriv->wakeup = 0; | ||
| 523 | return 1; | ||
| 524 | } | ||
| 525 | return dvb_frontend_is_exiting(fe); | ||
| 526 | } | ||
| 527 | |||
| 528 | static void dvb_frontend_wakeup(struct dvb_frontend *fe) | ||
| 529 | { | ||
| 530 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 531 | |||
| 532 | fepriv->wakeup = 1; | ||
| 533 | wake_up_interruptible(&fepriv->wait_queue); | ||
| 534 | } | ||
| 535 | |||
| 536 | static int dvb_frontend_thread(void *data) | ||
| 537 | { | ||
| 538 | struct dvb_frontend *fe = data; | ||
| 539 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 540 | unsigned long timeout; | ||
| 541 | fe_status_t s; | ||
| 542 | enum dvbfe_algo algo; | ||
| 543 | |||
| 544 | struct dvb_frontend_parameters *params; | ||
| 545 | |||
| 546 | dprintk("%s\n", __func__); | ||
| 547 | |||
| 548 | fepriv->check_wrapped = 0; | ||
| 549 | fepriv->quality = 0; | ||
| 550 | fepriv->delay = 3*HZ; | ||
| 551 | fepriv->status = 0; | ||
| 552 | fepriv->wakeup = 0; | ||
| 553 | fepriv->reinitialise = 0; | ||
| 554 | |||
| 555 | dvb_frontend_init(fe); | ||
| 556 | |||
| 557 | set_freezable(); | ||
| 558 | while (1) { | ||
| 559 | up(&fepriv->sem); /* is locked when we enter the thread... */ | ||
| 560 | restart: | ||
| 561 | timeout = wait_event_interruptible_timeout(fepriv->wait_queue, | ||
| 562 | dvb_frontend_should_wakeup(fe) || kthread_should_stop() | ||
| 563 | || freezing(current), | ||
| 564 | fepriv->delay); | ||
| 565 | |||
| 566 | if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) { | ||
| 567 | /* got signal or quitting */ | ||
| 568 | fepriv->exit = DVB_FE_NORMAL_EXIT; | ||
| 569 | break; | ||
| 570 | } | ||
| 571 | |||
| 572 | if (try_to_freeze()) | ||
| 573 | goto restart; | ||
| 574 | |||
| 575 | if (down_interruptible(&fepriv->sem)) | ||
| 576 | break; | ||
| 577 | |||
| 578 | if (fepriv->reinitialise) { | ||
| 579 | dvb_frontend_init(fe); | ||
| 580 | if (fepriv->tone != -1) { | ||
| 581 | fe->ops.set_tone(fe, fepriv->tone); | ||
| 582 | } | ||
| 583 | if (fepriv->voltage != -1) { | ||
| 584 | fe->ops.set_voltage(fe, fepriv->voltage); | ||
| 585 | } | ||
| 586 | fepriv->reinitialise = 0; | ||
| 587 | } | ||
| 588 | |||
| 589 | /* do an iteration of the tuning loop */ | ||
| 590 | if (fe->ops.get_frontend_algo) { | ||
| 591 | algo = fe->ops.get_frontend_algo(fe); | ||
| 592 | switch (algo) { | ||
| 593 | case DVBFE_ALGO_HW: | ||
| 594 | dprintk("%s: Frontend ALGO = DVBFE_ALGO_HW\n", __func__); | ||
| 595 | params = NULL; /* have we been asked to RETUNE ? */ | ||
| 596 | |||
| 597 | if (fepriv->state & FESTATE_RETUNE) { | ||
| 598 | dprintk("%s: Retune requested, FESTATE_RETUNE\n", __func__); | ||
| 599 | params = &fepriv->parameters_in; | ||
| 600 | fepriv->state = FESTATE_TUNED; | ||
| 601 | } | ||
| 602 | |||
| 603 | if (fe->ops.tune) | ||
| 604 | fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); | ||
| 605 | if (params) | ||
| 606 | fepriv->parameters_out = *params; | ||
| 607 | |||
| 608 | if (s != fepriv->status && !(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) { | ||
| 609 | dprintk("%s: state changed, adding current state\n", __func__); | ||
| 610 | dvb_frontend_add_event(fe, s); | ||
| 611 | fepriv->status = s; | ||
| 612 | } | ||
| 613 | break; | ||
| 614 | case DVBFE_ALGO_SW: | ||
| 615 | dprintk("%s: Frontend ALGO = DVBFE_ALGO_SW\n", __func__); | ||
| 616 | dvb_frontend_swzigzag(fe); | ||
| 617 | break; | ||
| 618 | case DVBFE_ALGO_CUSTOM: | ||
| 619 | dprintk("%s: Frontend ALGO = DVBFE_ALGO_CUSTOM, state=%d\n", __func__, fepriv->state); | ||
| 620 | if (fepriv->state & FESTATE_RETUNE) { | ||
| 621 | dprintk("%s: Retune requested, FESTAT_RETUNE\n", __func__); | ||
| 622 | fepriv->state = FESTATE_TUNED; | ||
| 623 | } | ||
| 624 | /* Case where we are going to search for a carrier | ||
| 625 | * User asked us to retune again for some reason, possibly | ||
| 626 | * requesting a search with a new set of parameters | ||
| 627 | */ | ||
| 628 | if (fepriv->algo_status & DVBFE_ALGO_SEARCH_AGAIN) { | ||
| 629 | if (fe->ops.search) { | ||
| 630 | fepriv->algo_status = fe->ops.search(fe, &fepriv->parameters_in); | ||
| 631 | /* We did do a search as was requested, the flags are | ||
| 632 | * now unset as well and has the flags wrt to search. | ||
| 633 | */ | ||
| 634 | } else { | ||
| 635 | fepriv->algo_status &= ~DVBFE_ALGO_SEARCH_AGAIN; | ||
| 636 | } | ||
| 637 | } | ||
| 638 | /* Track the carrier if the search was successful */ | ||
| 639 | if (fepriv->algo_status == DVBFE_ALGO_SEARCH_SUCCESS) { | ||
| 640 | if (fe->ops.track) | ||
| 641 | fe->ops.track(fe, &fepriv->parameters_in); | ||
| 642 | } else { | ||
| 643 | fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; | ||
| 644 | fepriv->delay = HZ / 2; | ||
| 645 | } | ||
| 646 | fepriv->parameters_out = fepriv->parameters_in; | ||
| 647 | fe->ops.read_status(fe, &s); | ||
| 648 | if (s != fepriv->status) { | ||
| 649 | dvb_frontend_add_event(fe, s); /* update event list */ | ||
| 650 | fepriv->status = s; | ||
| 651 | if (!(s & FE_HAS_LOCK)) { | ||
| 652 | fepriv->delay = HZ / 10; | ||
| 653 | fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; | ||
| 654 | } else { | ||
| 655 | fepriv->delay = 60 * HZ; | ||
| 656 | } | ||
| 657 | } | ||
| 658 | break; | ||
| 659 | default: | ||
| 660 | dprintk("%s: UNDEFINED ALGO !\n", __func__); | ||
| 661 | break; | ||
| 662 | } | ||
| 663 | } else { | ||
| 664 | dvb_frontend_swzigzag(fe); | ||
| 665 | } | ||
| 666 | } | ||
| 667 | |||
| 668 | if (dvb_powerdown_on_sleep) { | ||
| 669 | if (fe->ops.set_voltage) | ||
| 670 | fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF); | ||
| 671 | if (fe->ops.tuner_ops.sleep) { | ||
| 672 | if (fe->ops.i2c_gate_ctrl) | ||
| 673 | fe->ops.i2c_gate_ctrl(fe, 1); | ||
| 674 | fe->ops.tuner_ops.sleep(fe); | ||
| 675 | if (fe->ops.i2c_gate_ctrl) | ||
| 676 | fe->ops.i2c_gate_ctrl(fe, 0); | ||
| 677 | } | ||
| 678 | if (fe->ops.sleep) | ||
| 679 | fe->ops.sleep(fe); | ||
| 680 | } | ||
| 681 | |||
| 682 | fepriv->thread = NULL; | ||
| 683 | if (kthread_should_stop()) | ||
| 684 | fepriv->exit = DVB_FE_DEVICE_REMOVED; | ||
| 685 | else | ||
| 686 | fepriv->exit = DVB_FE_NO_EXIT; | ||
| 687 | mb(); | ||
| 688 | |||
| 689 | dvb_frontend_wakeup(fe); | ||
| 690 | return 0; | ||
| 691 | } | ||
| 692 | |||
| 693 | static void dvb_frontend_stop(struct dvb_frontend *fe) | ||
| 694 | { | ||
| 695 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 696 | |||
| 697 | dprintk ("%s\n", __func__); | ||
| 698 | |||
| 699 | fepriv->exit = DVB_FE_NORMAL_EXIT; | ||
| 700 | mb(); | ||
| 701 | |||
| 702 | if (!fepriv->thread) | ||
| 703 | return; | ||
| 704 | |||
| 705 | kthread_stop(fepriv->thread); | ||
| 706 | |||
| 707 | sema_init(&fepriv->sem, 1); | ||
| 708 | fepriv->state = FESTATE_IDLE; | ||
| 709 | |||
| 710 | /* paranoia check in case a signal arrived */ | ||
| 711 | if (fepriv->thread) | ||
| 712 | printk("dvb_frontend_stop: warning: thread %p won't exit\n", | ||
| 713 | fepriv->thread); | ||
| 714 | } | ||
| 715 | |||
| 716 | s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime) | ||
| 717 | { | ||
| 718 | return ((curtime.tv_usec < lasttime.tv_usec) ? | ||
| 719 | 1000000 - lasttime.tv_usec + curtime.tv_usec : | ||
| 720 | curtime.tv_usec - lasttime.tv_usec); | ||
| 721 | } | ||
| 722 | EXPORT_SYMBOL(timeval_usec_diff); | ||
| 723 | |||
| 724 | static inline void timeval_usec_add(struct timeval *curtime, u32 add_usec) | ||
| 725 | { | ||
| 726 | curtime->tv_usec += add_usec; | ||
| 727 | if (curtime->tv_usec >= 1000000) { | ||
| 728 | curtime->tv_usec -= 1000000; | ||
| 729 | curtime->tv_sec++; | ||
| 730 | } | ||
| 731 | } | ||
| 732 | |||
| 733 | /* | ||
| 734 | * Sleep until gettimeofday() > waketime + add_usec | ||
| 735 | * This needs to be as precise as possible, but as the delay is | ||
| 736 | * usually between 2ms and 32ms, it is done using a scheduled msleep | ||
| 737 | * followed by usleep (normally a busy-wait loop) for the remainder | ||
| 738 | */ | ||
| 739 | void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec) | ||
| 740 | { | ||
| 741 | struct timeval lasttime; | ||
| 742 | s32 delta, newdelta; | ||
| 743 | |||
| 744 | timeval_usec_add(waketime, add_usec); | ||
| 745 | |||
| 746 | do_gettimeofday(&lasttime); | ||
| 747 | delta = timeval_usec_diff(lasttime, *waketime); | ||
| 748 | if (delta > 2500) { | ||
| 749 | msleep((delta - 1500) / 1000); | ||
| 750 | do_gettimeofday(&lasttime); | ||
| 751 | newdelta = timeval_usec_diff(lasttime, *waketime); | ||
| 752 | delta = (newdelta > delta) ? 0 : newdelta; | ||
| 753 | } | ||
| 754 | if (delta > 0) | ||
| 755 | udelay(delta); | ||
| 756 | } | ||
| 757 | EXPORT_SYMBOL(dvb_frontend_sleep_until); | ||
| 758 | |||
| 759 | static int dvb_frontend_start(struct dvb_frontend *fe) | ||
| 760 | { | ||
| 761 | int ret; | ||
| 762 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 763 | struct task_struct *fe_thread; | ||
| 764 | |||
| 765 | dprintk ("%s\n", __func__); | ||
| 766 | |||
| 767 | if (fepriv->thread) { | ||
| 768 | if (fepriv->exit == DVB_FE_NO_EXIT) | ||
| 769 | return 0; | ||
| 770 | else | ||
| 771 | dvb_frontend_stop (fe); | ||
| 772 | } | ||
| 773 | |||
| 774 | if (signal_pending(current)) | ||
| 775 | return -EINTR; | ||
| 776 | if (down_interruptible (&fepriv->sem)) | ||
| 777 | return -EINTR; | ||
| 778 | |||
| 779 | fepriv->state = FESTATE_IDLE; | ||
| 780 | fepriv->exit = DVB_FE_NO_EXIT; | ||
| 781 | fepriv->thread = NULL; | ||
| 782 | mb(); | ||
| 783 | |||
| 784 | fe_thread = kthread_run(dvb_frontend_thread, fe, | ||
| 785 | "kdvb-ad-%i-fe-%i", fe->dvb->num,fe->id); | ||
| 786 | if (IS_ERR(fe_thread)) { | ||
| 787 | ret = PTR_ERR(fe_thread); | ||
| 788 | printk("dvb_frontend_start: failed to start kthread (%d)\n", ret); | ||
| 789 | up(&fepriv->sem); | ||
| 790 | return ret; | ||
| 791 | } | ||
| 792 | fepriv->thread = fe_thread; | ||
| 793 | return 0; | ||
| 794 | } | ||
| 795 | |||
| 796 | static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe, | ||
| 797 | u32 *freq_min, u32 *freq_max) | ||
| 798 | { | ||
| 799 | *freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min); | ||
| 800 | |||
| 801 | if (fe->ops.info.frequency_max == 0) | ||
| 802 | *freq_max = fe->ops.tuner_ops.info.frequency_max; | ||
| 803 | else if (fe->ops.tuner_ops.info.frequency_max == 0) | ||
| 804 | *freq_max = fe->ops.info.frequency_max; | ||
| 805 | else | ||
| 806 | *freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max); | ||
| 807 | |||
| 808 | if (*freq_min == 0 || *freq_max == 0) | ||
| 809 | printk(KERN_WARNING "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n", | ||
| 810 | fe->dvb->num,fe->id); | ||
| 811 | } | ||
| 812 | |||
| 813 | static int dvb_frontend_check_parameters(struct dvb_frontend *fe, | ||
| 814 | struct dvb_frontend_parameters *parms) | ||
| 815 | { | ||
| 816 | u32 freq_min; | ||
| 817 | u32 freq_max; | ||
| 818 | |||
| 819 | /* range check: frequency */ | ||
| 820 | dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max); | ||
| 821 | if ((freq_min && parms->frequency < freq_min) || | ||
| 822 | (freq_max && parms->frequency > freq_max)) { | ||
| 823 | printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n", | ||
| 824 | fe->dvb->num, fe->id, parms->frequency, freq_min, freq_max); | ||
| 825 | return -EINVAL; | ||
| 826 | } | ||
| 827 | |||
| 828 | /* range check: symbol rate */ | ||
| 829 | if (fe->ops.info.type == FE_QPSK) { | ||
| 830 | if ((fe->ops.info.symbol_rate_min && | ||
| 831 | parms->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) || | ||
| 832 | (fe->ops.info.symbol_rate_max && | ||
| 833 | parms->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) { | ||
| 834 | printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n", | ||
| 835 | fe->dvb->num, fe->id, parms->u.qpsk.symbol_rate, | ||
| 836 | fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max); | ||
| 837 | return -EINVAL; | ||
| 838 | } | ||
| 839 | |||
| 840 | } else if (fe->ops.info.type == FE_QAM) { | ||
| 841 | if ((fe->ops.info.symbol_rate_min && | ||
| 842 | parms->u.qam.symbol_rate < fe->ops.info.symbol_rate_min) || | ||
| 843 | (fe->ops.info.symbol_rate_max && | ||
| 844 | parms->u.qam.symbol_rate > fe->ops.info.symbol_rate_max)) { | ||
| 845 | printk(KERN_WARNING "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n", | ||
| 846 | fe->dvb->num, fe->id, parms->u.qam.symbol_rate, | ||
| 847 | fe->ops.info.symbol_rate_min, fe->ops.info.symbol_rate_max); | ||
| 848 | return -EINVAL; | ||
| 849 | } | ||
| 850 | } | ||
| 851 | |||
| 852 | /* check for supported modulation */ | ||
| 853 | if (fe->ops.info.type == FE_QAM && | ||
| 854 | (parms->u.qam.modulation > QAM_AUTO || | ||
| 855 | !((1 << (parms->u.qam.modulation + 10)) & fe->ops.info.caps))) { | ||
| 856 | printk(KERN_WARNING "DVB: adapter %i frontend %i modulation %u not supported\n", | ||
| 857 | fe->dvb->num, fe->id, parms->u.qam.modulation); | ||
| 858 | return -EINVAL; | ||
| 859 | } | ||
| 860 | |||
| 861 | return 0; | ||
| 862 | } | ||
| 863 | |||
| 864 | static int dvb_frontend_clear_cache(struct dvb_frontend *fe) | ||
| 865 | { | ||
| 866 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
| 867 | int i; | ||
| 868 | |||
| 869 | memset(c, 0, sizeof(struct dtv_frontend_properties)); | ||
| 870 | |||
| 871 | c->state = DTV_CLEAR; | ||
| 872 | c->delivery_system = SYS_UNDEFINED; | ||
| 873 | c->inversion = INVERSION_AUTO; | ||
| 874 | c->fec_inner = FEC_AUTO; | ||
| 875 | c->transmission_mode = TRANSMISSION_MODE_AUTO; | ||
| 876 | c->bandwidth_hz = BANDWIDTH_AUTO; | ||
| 877 | c->guard_interval = GUARD_INTERVAL_AUTO; | ||
| 878 | c->hierarchy = HIERARCHY_AUTO; | ||
| 879 | c->symbol_rate = QAM_AUTO; | ||
| 880 | c->code_rate_HP = FEC_AUTO; | ||
| 881 | c->code_rate_LP = FEC_AUTO; | ||
| 882 | |||
| 883 | c->isdbt_partial_reception = -1; | ||
| 884 | c->isdbt_sb_mode = -1; | ||
| 885 | c->isdbt_sb_subchannel = -1; | ||
| 886 | c->isdbt_sb_segment_idx = -1; | ||
| 887 | c->isdbt_sb_segment_count = -1; | ||
| 888 | c->isdbt_layer_enabled = 0x7; | ||
| 889 | for (i = 0; i < 3; i++) { | ||
| 890 | c->layer[i].fec = FEC_AUTO; | ||
| 891 | c->layer[i].modulation = QAM_AUTO; | ||
| 892 | c->layer[i].interleaving = -1; | ||
| 893 | c->layer[i].segment_count = -1; | ||
| 894 | } | ||
| 895 | |||
| 896 | return 0; | ||
| 897 | } | ||
| 898 | |||
| 899 | #define _DTV_CMD(n, s, b) \ | ||
| 900 | [n] = { \ | ||
| 901 | .name = #n, \ | ||
| 902 | .cmd = n, \ | ||
| 903 | .set = s,\ | ||
| 904 | .buffer = b \ | ||
| 905 | } | ||
| 906 | |||
| 907 | static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { | ||
| 908 | _DTV_CMD(DTV_TUNE, 1, 0), | ||
| 909 | _DTV_CMD(DTV_CLEAR, 1, 0), | ||
| 910 | |||
| 911 | /* Set */ | ||
| 912 | _DTV_CMD(DTV_FREQUENCY, 1, 0), | ||
| 913 | _DTV_CMD(DTV_BANDWIDTH_HZ, 1, 0), | ||
| 914 | _DTV_CMD(DTV_MODULATION, 1, 0), | ||
| 915 | _DTV_CMD(DTV_INVERSION, 1, 0), | ||
| 916 | _DTV_CMD(DTV_DISEQC_MASTER, 1, 1), | ||
| 917 | _DTV_CMD(DTV_SYMBOL_RATE, 1, 0), | ||
| 918 | _DTV_CMD(DTV_INNER_FEC, 1, 0), | ||
| 919 | _DTV_CMD(DTV_VOLTAGE, 1, 0), | ||
| 920 | _DTV_CMD(DTV_TONE, 1, 0), | ||
| 921 | _DTV_CMD(DTV_PILOT, 1, 0), | ||
| 922 | _DTV_CMD(DTV_ROLLOFF, 1, 0), | ||
| 923 | _DTV_CMD(DTV_DELIVERY_SYSTEM, 1, 0), | ||
| 924 | _DTV_CMD(DTV_HIERARCHY, 1, 0), | ||
| 925 | _DTV_CMD(DTV_CODE_RATE_HP, 1, 0), | ||
| 926 | _DTV_CMD(DTV_CODE_RATE_LP, 1, 0), | ||
| 927 | _DTV_CMD(DTV_GUARD_INTERVAL, 1, 0), | ||
| 928 | _DTV_CMD(DTV_TRANSMISSION_MODE, 1, 0), | ||
| 929 | |||
| 930 | _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 1, 0), | ||
| 931 | _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 1, 0), | ||
| 932 | _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 1, 0), | ||
| 933 | _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 1, 0), | ||
| 934 | _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 1, 0), | ||
| 935 | _DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 1, 0), | ||
| 936 | _DTV_CMD(DTV_ISDBT_LAYERA_FEC, 1, 0), | ||
| 937 | _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 1, 0), | ||
| 938 | _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 1, 0), | ||
| 939 | _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 1, 0), | ||
| 940 | _DTV_CMD(DTV_ISDBT_LAYERB_FEC, 1, 0), | ||
| 941 | _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 1, 0), | ||
| 942 | _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 1, 0), | ||
| 943 | _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 1, 0), | ||
| 944 | _DTV_CMD(DTV_ISDBT_LAYERC_FEC, 1, 0), | ||
| 945 | _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 1, 0), | ||
| 946 | _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 1, 0), | ||
| 947 | _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 1, 0), | ||
| 948 | |||
| 949 | _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 0, 0), | ||
| 950 | _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 0, 0), | ||
| 951 | _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 0, 0), | ||
| 952 | _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 0, 0), | ||
| 953 | _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 0, 0), | ||
| 954 | _DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 0, 0), | ||
| 955 | _DTV_CMD(DTV_ISDBT_LAYERA_FEC, 0, 0), | ||
| 956 | _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 0, 0), | ||
| 957 | _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 0, 0), | ||
| 958 | _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 0, 0), | ||
| 959 | _DTV_CMD(DTV_ISDBT_LAYERB_FEC, 0, 0), | ||
| 960 | _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 0, 0), | ||
| 961 | _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 0, 0), | ||
| 962 | _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 0, 0), | ||
| 963 | _DTV_CMD(DTV_ISDBT_LAYERC_FEC, 0, 0), | ||
| 964 | _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 0, 0), | ||
| 965 | _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 0, 0), | ||
| 966 | _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 0, 0), | ||
| 967 | |||
| 968 | _DTV_CMD(DTV_ISDBS_TS_ID, 1, 0), | ||
| 969 | _DTV_CMD(DTV_DVBT2_PLP_ID, 1, 0), | ||
| 970 | |||
| 971 | /* Get */ | ||
| 972 | _DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1), | ||
| 973 | _DTV_CMD(DTV_API_VERSION, 0, 0), | ||
| 974 | _DTV_CMD(DTV_CODE_RATE_HP, 0, 0), | ||
| 975 | _DTV_CMD(DTV_CODE_RATE_LP, 0, 0), | ||
| 976 | _DTV_CMD(DTV_GUARD_INTERVAL, 0, 0), | ||
| 977 | _DTV_CMD(DTV_TRANSMISSION_MODE, 0, 0), | ||
| 978 | _DTV_CMD(DTV_HIERARCHY, 0, 0), | ||
| 979 | }; | ||
| 980 | |||
| 981 | static void dtv_property_dump(struct dtv_property *tvp) | ||
| 982 | { | ||
| 983 | int i; | ||
| 984 | |||
| 985 | if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) { | ||
| 986 | printk(KERN_WARNING "%s: tvp.cmd = 0x%08x undefined\n", | ||
| 987 | __func__, tvp->cmd); | ||
| 988 | return; | ||
| 989 | } | ||
| 990 | |||
| 991 | dprintk("%s() tvp.cmd = 0x%08x (%s)\n" | ||
| 992 | ,__func__ | ||
| 993 | ,tvp->cmd | ||
| 994 | ,dtv_cmds[ tvp->cmd ].name); | ||
| 995 | |||
| 996 | if(dtv_cmds[ tvp->cmd ].buffer) { | ||
| 997 | |||
| 998 | dprintk("%s() tvp.u.buffer.len = 0x%02x\n" | ||
| 999 | ,__func__ | ||
| 1000 | ,tvp->u.buffer.len); | ||
| 1001 | |||
| 1002 | for(i = 0; i < tvp->u.buffer.len; i++) | ||
| 1003 | dprintk("%s() tvp.u.buffer.data[0x%02x] = 0x%02x\n" | ||
| 1004 | ,__func__ | ||
| 1005 | ,i | ||
| 1006 | ,tvp->u.buffer.data[i]); | ||
| 1007 | |||
| 1008 | } else | ||
| 1009 | dprintk("%s() tvp.u.data = 0x%08x\n", __func__, tvp->u.data); | ||
| 1010 | } | ||
| 1011 | |||
| 1012 | static int is_legacy_delivery_system(fe_delivery_system_t s) | ||
| 1013 | { | ||
| 1014 | if((s == SYS_UNDEFINED) || (s == SYS_DVBC_ANNEX_AC) || | ||
| 1015 | (s == SYS_DVBC_ANNEX_B) || (s == SYS_DVBT) || (s == SYS_DVBS) || | ||
| 1016 | (s == SYS_ATSC)) | ||
| 1017 | return 1; | ||
| 1018 | |||
| 1019 | return 0; | ||
| 1020 | } | ||
| 1021 | |||
| 1022 | /* Synchronise the legacy tuning parameters into the cache, so that demodulator | ||
| 1023 | * drivers can use a single set_frontend tuning function, regardless of whether | ||
| 1024 | * it's being used for the legacy or new API, reducing code and complexity. | ||
| 1025 | */ | ||
| 1026 | static void dtv_property_cache_sync(struct dvb_frontend *fe, | ||
| 1027 | struct dtv_frontend_properties *c, | ||
| 1028 | const struct dvb_frontend_parameters *p) | ||
| 1029 | { | ||
| 1030 | c->frequency = p->frequency; | ||
| 1031 | c->inversion = p->inversion; | ||
| 1032 | |||
| 1033 | switch (fe->ops.info.type) { | ||
| 1034 | case FE_QPSK: | ||
| 1035 | c->modulation = QPSK; /* implied for DVB-S in legacy API */ | ||
| 1036 | c->rolloff = ROLLOFF_35;/* implied for DVB-S */ | ||
| 1037 | c->symbol_rate = p->u.qpsk.symbol_rate; | ||
| 1038 | c->fec_inner = p->u.qpsk.fec_inner; | ||
| 1039 | c->delivery_system = SYS_DVBS; | ||
| 1040 | break; | ||
| 1041 | case FE_QAM: | ||
| 1042 | c->symbol_rate = p->u.qam.symbol_rate; | ||
| 1043 | c->fec_inner = p->u.qam.fec_inner; | ||
| 1044 | c->modulation = p->u.qam.modulation; | ||
| 1045 | c->delivery_system = SYS_DVBC_ANNEX_AC; | ||
| 1046 | break; | ||
| 1047 | case FE_OFDM: | ||
| 1048 | if (p->u.ofdm.bandwidth == BANDWIDTH_6_MHZ) | ||
| 1049 | c->bandwidth_hz = 6000000; | ||
| 1050 | else if (p->u.ofdm.bandwidth == BANDWIDTH_7_MHZ) | ||
| 1051 | c->bandwidth_hz = 7000000; | ||
| 1052 | else if (p->u.ofdm.bandwidth == BANDWIDTH_8_MHZ) | ||
| 1053 | c->bandwidth_hz = 8000000; | ||
| 1054 | else | ||
| 1055 | /* Including BANDWIDTH_AUTO */ | ||
| 1056 | c->bandwidth_hz = 0; | ||
| 1057 | c->code_rate_HP = p->u.ofdm.code_rate_HP; | ||
| 1058 | c->code_rate_LP = p->u.ofdm.code_rate_LP; | ||
| 1059 | c->modulation = p->u.ofdm.constellation; | ||
| 1060 | c->transmission_mode = p->u.ofdm.transmission_mode; | ||
| 1061 | c->guard_interval = p->u.ofdm.guard_interval; | ||
| 1062 | c->hierarchy = p->u.ofdm.hierarchy_information; | ||
| 1063 | c->delivery_system = SYS_DVBT; | ||
| 1064 | break; | ||
| 1065 | case FE_ATSC: | ||
| 1066 | c->modulation = p->u.vsb.modulation; | ||
| 1067 | if ((c->modulation == VSB_8) || (c->modulation == VSB_16)) | ||
| 1068 | c->delivery_system = SYS_ATSC; | ||
| 1069 | else | ||
| 1070 | c->delivery_system = SYS_DVBC_ANNEX_B; | ||
| 1071 | break; | ||
| 1072 | } | ||
| 1073 | } | ||
| 1074 | |||
| 1075 | /* Ensure the cached values are set correctly in the frontend | ||
| 1076 | * legacy tuning structures, for the advanced tuning API. | ||
| 1077 | */ | ||
| 1078 | static void dtv_property_legacy_params_sync(struct dvb_frontend *fe) | ||
| 1079 | { | ||
| 1080 | const struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
| 1081 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 1082 | struct dvb_frontend_parameters *p = &fepriv->parameters_in; | ||
| 1083 | |||
| 1084 | p->frequency = c->frequency; | ||
| 1085 | p->inversion = c->inversion; | ||
| 1086 | |||
| 1087 | switch (fe->ops.info.type) { | ||
| 1088 | case FE_QPSK: | ||
| 1089 | dprintk("%s() Preparing QPSK req\n", __func__); | ||
| 1090 | p->u.qpsk.symbol_rate = c->symbol_rate; | ||
| 1091 | p->u.qpsk.fec_inner = c->fec_inner; | ||
| 1092 | break; | ||
| 1093 | case FE_QAM: | ||
| 1094 | dprintk("%s() Preparing QAM req\n", __func__); | ||
| 1095 | p->u.qam.symbol_rate = c->symbol_rate; | ||
| 1096 | p->u.qam.fec_inner = c->fec_inner; | ||
| 1097 | p->u.qam.modulation = c->modulation; | ||
| 1098 | break; | ||
| 1099 | case FE_OFDM: | ||
| 1100 | dprintk("%s() Preparing OFDM req\n", __func__); | ||
| 1101 | if (c->bandwidth_hz == 6000000) | ||
| 1102 | p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; | ||
| 1103 | else if (c->bandwidth_hz == 7000000) | ||
| 1104 | p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; | ||
| 1105 | else if (c->bandwidth_hz == 8000000) | ||
| 1106 | p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; | ||
| 1107 | else | ||
| 1108 | p->u.ofdm.bandwidth = BANDWIDTH_AUTO; | ||
| 1109 | p->u.ofdm.code_rate_HP = c->code_rate_HP; | ||
| 1110 | p->u.ofdm.code_rate_LP = c->code_rate_LP; | ||
| 1111 | p->u.ofdm.constellation = c->modulation; | ||
| 1112 | p->u.ofdm.transmission_mode = c->transmission_mode; | ||
| 1113 | p->u.ofdm.guard_interval = c->guard_interval; | ||
| 1114 | p->u.ofdm.hierarchy_information = c->hierarchy; | ||
| 1115 | break; | ||
| 1116 | case FE_ATSC: | ||
| 1117 | dprintk("%s() Preparing VSB req\n", __func__); | ||
| 1118 | p->u.vsb.modulation = c->modulation; | ||
| 1119 | break; | ||
| 1120 | } | ||
| 1121 | } | ||
| 1122 | |||
| 1123 | /* Ensure the cached values are set correctly in the frontend | ||
| 1124 | * legacy tuning structures, for the legacy tuning API. | ||
| 1125 | */ | ||
| 1126 | static void dtv_property_adv_params_sync(struct dvb_frontend *fe) | ||
| 1127 | { | ||
| 1128 | const struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
| 1129 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 1130 | struct dvb_frontend_parameters *p = &fepriv->parameters_in; | ||
| 1131 | |||
| 1132 | p->frequency = c->frequency; | ||
| 1133 | p->inversion = c->inversion; | ||
| 1134 | |||
| 1135 | switch(c->modulation) { | ||
| 1136 | case PSK_8: | ||
| 1137 | case APSK_16: | ||
| 1138 | case APSK_32: | ||
| 1139 | case QPSK: | ||
| 1140 | p->u.qpsk.symbol_rate = c->symbol_rate; | ||
| 1141 | p->u.qpsk.fec_inner = c->fec_inner; | ||
| 1142 | break; | ||
| 1143 | default: | ||
| 1144 | break; | ||
| 1145 | } | ||
| 1146 | |||
| 1147 | /* Fake out a generic DVB-T request so we pass validation in the ioctl */ | ||
| 1148 | if ((c->delivery_system == SYS_ISDBT) || | ||
| 1149 | (c->delivery_system == SYS_DVBT2)) { | ||
| 1150 | p->u.ofdm.constellation = QAM_AUTO; | ||
| 1151 | p->u.ofdm.code_rate_HP = FEC_AUTO; | ||
| 1152 | p->u.ofdm.code_rate_LP = FEC_AUTO; | ||
| 1153 | p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO; | ||
| 1154 | p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO; | ||
| 1155 | p->u.ofdm.hierarchy_information = HIERARCHY_AUTO; | ||
| 1156 | if (c->bandwidth_hz == 8000000) | ||
| 1157 | p->u.ofdm.bandwidth = BANDWIDTH_8_MHZ; | ||
| 1158 | else if (c->bandwidth_hz == 7000000) | ||
| 1159 | p->u.ofdm.bandwidth = BANDWIDTH_7_MHZ; | ||
| 1160 | else if (c->bandwidth_hz == 6000000) | ||
| 1161 | p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ; | ||
| 1162 | else | ||
| 1163 | p->u.ofdm.bandwidth = BANDWIDTH_AUTO; | ||
| 1164 | } | ||
| 1165 | } | ||
| 1166 | |||
| 1167 | static void dtv_property_cache_submit(struct dvb_frontend *fe) | ||
| 1168 | { | ||
| 1169 | const struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
| 1170 | |||
| 1171 | /* For legacy delivery systems we don't need the delivery_system to | ||
| 1172 | * be specified, but we populate the older structures from the cache | ||
| 1173 | * so we can call set_frontend on older drivers. | ||
| 1174 | */ | ||
| 1175 | if(is_legacy_delivery_system(c->delivery_system)) { | ||
| 1176 | |||
| 1177 | dprintk("%s() legacy, modulation = %d\n", __func__, c->modulation); | ||
| 1178 | dtv_property_legacy_params_sync(fe); | ||
| 1179 | |||
| 1180 | } else { | ||
| 1181 | dprintk("%s() adv, modulation = %d\n", __func__, c->modulation); | ||
| 1182 | |||
| 1183 | /* For advanced delivery systems / modulation types ... | ||
| 1184 | * we seed the lecacy dvb_frontend_parameters structure | ||
| 1185 | * so that the sanity checking code later in the IOCTL processing | ||
| 1186 | * can validate our basic frequency ranges, symbolrates, modulation | ||
| 1187 | * etc. | ||
| 1188 | */ | ||
| 1189 | dtv_property_adv_params_sync(fe); | ||
| 1190 | } | ||
| 1191 | } | ||
| 1192 | |||
| 1193 | static int dvb_frontend_ioctl_legacy(struct file *file, | ||
| 1194 | unsigned int cmd, void *parg); | ||
| 1195 | static int dvb_frontend_ioctl_properties(struct file *file, | ||
| 1196 | unsigned int cmd, void *parg); | ||
| 1197 | |||
| 1198 | static int dtv_property_process_get(struct dvb_frontend *fe, | ||
| 1199 | struct dtv_property *tvp, | ||
| 1200 | struct file *file) | ||
| 1201 | { | ||
| 1202 | const struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
| 1203 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 1204 | struct dtv_frontend_properties cdetected; | ||
| 1205 | int r; | ||
| 1206 | |||
| 1207 | /* | ||
| 1208 | * If the driver implements a get_frontend function, then convert | ||
| 1209 | * detected parameters to S2API properties. | ||
| 1210 | */ | ||
| 1211 | if (fe->ops.get_frontend) { | ||
| 1212 | cdetected = *c; | ||
| 1213 | dtv_property_cache_sync(fe, &cdetected, &fepriv->parameters_out); | ||
| 1214 | c = &cdetected; | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | switch(tvp->cmd) { | ||
| 1218 | case DTV_FREQUENCY: | ||
| 1219 | tvp->u.data = c->frequency; | ||
| 1220 | break; | ||
| 1221 | case DTV_MODULATION: | ||
| 1222 | tvp->u.data = c->modulation; | ||
| 1223 | break; | ||
| 1224 | case DTV_BANDWIDTH_HZ: | ||
| 1225 | tvp->u.data = c->bandwidth_hz; | ||
| 1226 | break; | ||
| 1227 | case DTV_INVERSION: | ||
| 1228 | tvp->u.data = c->inversion; | ||
| 1229 | break; | ||
| 1230 | case DTV_SYMBOL_RATE: | ||
| 1231 | tvp->u.data = c->symbol_rate; | ||
| 1232 | break; | ||
| 1233 | case DTV_INNER_FEC: | ||
| 1234 | tvp->u.data = c->fec_inner; | ||
| 1235 | break; | ||
| 1236 | case DTV_PILOT: | ||
| 1237 | tvp->u.data = c->pilot; | ||
| 1238 | break; | ||
| 1239 | case DTV_ROLLOFF: | ||
| 1240 | tvp->u.data = c->rolloff; | ||
| 1241 | break; | ||
| 1242 | case DTV_DELIVERY_SYSTEM: | ||
| 1243 | tvp->u.data = c->delivery_system; | ||
| 1244 | break; | ||
| 1245 | case DTV_VOLTAGE: | ||
| 1246 | tvp->u.data = c->voltage; | ||
| 1247 | break; | ||
| 1248 | case DTV_TONE: | ||
| 1249 | tvp->u.data = c->sectone; | ||
| 1250 | break; | ||
| 1251 | case DTV_API_VERSION: | ||
| 1252 | tvp->u.data = (DVB_API_VERSION << 8) | DVB_API_VERSION_MINOR; | ||
| 1253 | break; | ||
| 1254 | case DTV_CODE_RATE_HP: | ||
| 1255 | tvp->u.data = c->code_rate_HP; | ||
| 1256 | break; | ||
| 1257 | case DTV_CODE_RATE_LP: | ||
| 1258 | tvp->u.data = c->code_rate_LP; | ||
| 1259 | break; | ||
| 1260 | case DTV_GUARD_INTERVAL: | ||
| 1261 | tvp->u.data = c->guard_interval; | ||
| 1262 | break; | ||
| 1263 | case DTV_TRANSMISSION_MODE: | ||
| 1264 | tvp->u.data = c->transmission_mode; | ||
| 1265 | break; | ||
| 1266 | case DTV_HIERARCHY: | ||
| 1267 | tvp->u.data = c->hierarchy; | ||
| 1268 | break; | ||
| 1269 | |||
| 1270 | /* ISDB-T Support here */ | ||
| 1271 | case DTV_ISDBT_PARTIAL_RECEPTION: | ||
| 1272 | tvp->u.data = c->isdbt_partial_reception; | ||
| 1273 | break; | ||
| 1274 | case DTV_ISDBT_SOUND_BROADCASTING: | ||
| 1275 | tvp->u.data = c->isdbt_sb_mode; | ||
| 1276 | break; | ||
| 1277 | case DTV_ISDBT_SB_SUBCHANNEL_ID: | ||
| 1278 | tvp->u.data = c->isdbt_sb_subchannel; | ||
| 1279 | break; | ||
| 1280 | case DTV_ISDBT_SB_SEGMENT_IDX: | ||
| 1281 | tvp->u.data = c->isdbt_sb_segment_idx; | ||
| 1282 | break; | ||
| 1283 | case DTV_ISDBT_SB_SEGMENT_COUNT: | ||
| 1284 | tvp->u.data = c->isdbt_sb_segment_count; | ||
| 1285 | break; | ||
| 1286 | case DTV_ISDBT_LAYER_ENABLED: | ||
| 1287 | tvp->u.data = c->isdbt_layer_enabled; | ||
| 1288 | break; | ||
| 1289 | case DTV_ISDBT_LAYERA_FEC: | ||
| 1290 | tvp->u.data = c->layer[0].fec; | ||
| 1291 | break; | ||
| 1292 | case DTV_ISDBT_LAYERA_MODULATION: | ||
| 1293 | tvp->u.data = c->layer[0].modulation; | ||
| 1294 | break; | ||
| 1295 | case DTV_ISDBT_LAYERA_SEGMENT_COUNT: | ||
| 1296 | tvp->u.data = c->layer[0].segment_count; | ||
| 1297 | break; | ||
| 1298 | case DTV_ISDBT_LAYERA_TIME_INTERLEAVING: | ||
| 1299 | tvp->u.data = c->layer[0].interleaving; | ||
| 1300 | break; | ||
| 1301 | case DTV_ISDBT_LAYERB_FEC: | ||
| 1302 | tvp->u.data = c->layer[1].fec; | ||
| 1303 | break; | ||
| 1304 | case DTV_ISDBT_LAYERB_MODULATION: | ||
| 1305 | tvp->u.data = c->layer[1].modulation; | ||
| 1306 | break; | ||
| 1307 | case DTV_ISDBT_LAYERB_SEGMENT_COUNT: | ||
| 1308 | tvp->u.data = c->layer[1].segment_count; | ||
| 1309 | break; | ||
| 1310 | case DTV_ISDBT_LAYERB_TIME_INTERLEAVING: | ||
| 1311 | tvp->u.data = c->layer[1].interleaving; | ||
| 1312 | break; | ||
| 1313 | case DTV_ISDBT_LAYERC_FEC: | ||
| 1314 | tvp->u.data = c->layer[2].fec; | ||
| 1315 | break; | ||
| 1316 | case DTV_ISDBT_LAYERC_MODULATION: | ||
| 1317 | tvp->u.data = c->layer[2].modulation; | ||
| 1318 | break; | ||
| 1319 | case DTV_ISDBT_LAYERC_SEGMENT_COUNT: | ||
| 1320 | tvp->u.data = c->layer[2].segment_count; | ||
| 1321 | break; | ||
| 1322 | case DTV_ISDBT_LAYERC_TIME_INTERLEAVING: | ||
| 1323 | tvp->u.data = c->layer[2].interleaving; | ||
| 1324 | break; | ||
| 1325 | case DTV_ISDBS_TS_ID: | ||
| 1326 | tvp->u.data = c->isdbs_ts_id; | ||
| 1327 | break; | ||
| 1328 | case DTV_DVBT2_PLP_ID: | ||
| 1329 | tvp->u.data = c->dvbt2_plp_id; | ||
| 1330 | break; | ||
| 1331 | default: | ||
| 1332 | return -EINVAL; | ||
| 1333 | } | ||
| 1334 | |||
| 1335 | /* Allow the frontend to override outgoing properties */ | ||
| 1336 | if (fe->ops.get_property) { | ||
| 1337 | r = fe->ops.get_property(fe, tvp); | ||
| 1338 | if (r < 0) | ||
| 1339 | return r; | ||
| 1340 | } | ||
| 1341 | |||
| 1342 | dtv_property_dump(tvp); | ||
| 1343 | |||
| 1344 | return 0; | ||
| 1345 | } | ||
| 1346 | |||
| 1347 | static int dtv_property_process_set(struct dvb_frontend *fe, | ||
| 1348 | struct dtv_property *tvp, | ||
| 1349 | struct file *file) | ||
| 1350 | { | ||
| 1351 | int r = 0; | ||
| 1352 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
| 1353 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 1354 | dtv_property_dump(tvp); | ||
| 1355 | |||
| 1356 | /* Allow the frontend to validate incoming properties */ | ||
| 1357 | if (fe->ops.set_property) { | ||
| 1358 | r = fe->ops.set_property(fe, tvp); | ||
| 1359 | if (r < 0) | ||
| 1360 | return r; | ||
| 1361 | } | ||
| 1362 | |||
| 1363 | switch(tvp->cmd) { | ||
| 1364 | case DTV_CLEAR: | ||
| 1365 | /* Reset a cache of data specific to the frontend here. This does | ||
| 1366 | * not effect hardware. | ||
| 1367 | */ | ||
| 1368 | dvb_frontend_clear_cache(fe); | ||
| 1369 | dprintk("%s() Flushing property cache\n", __func__); | ||
| 1370 | break; | ||
| 1371 | case DTV_TUNE: | ||
| 1372 | /* interpret the cache of data, build either a traditional frontend | ||
| 1373 | * tunerequest so we can pass validation in the FE_SET_FRONTEND | ||
| 1374 | * ioctl. | ||
| 1375 | */ | ||
| 1376 | c->state = tvp->cmd; | ||
| 1377 | dprintk("%s() Finalised property cache\n", __func__); | ||
| 1378 | dtv_property_cache_submit(fe); | ||
| 1379 | |||
| 1380 | r = dvb_frontend_ioctl_legacy(file, FE_SET_FRONTEND, | ||
| 1381 | &fepriv->parameters_in); | ||
| 1382 | break; | ||
| 1383 | case DTV_FREQUENCY: | ||
| 1384 | c->frequency = tvp->u.data; | ||
| 1385 | break; | ||
| 1386 | case DTV_MODULATION: | ||
| 1387 | c->modulation = tvp->u.data; | ||
| 1388 | break; | ||
| 1389 | case DTV_BANDWIDTH_HZ: | ||
| 1390 | c->bandwidth_hz = tvp->u.data; | ||
| 1391 | break; | ||
| 1392 | case DTV_INVERSION: | ||
| 1393 | c->inversion = tvp->u.data; | ||
| 1394 | break; | ||
| 1395 | case DTV_SYMBOL_RATE: | ||
| 1396 | c->symbol_rate = tvp->u.data; | ||
| 1397 | break; | ||
| 1398 | case DTV_INNER_FEC: | ||
| 1399 | c->fec_inner = tvp->u.data; | ||
| 1400 | break; | ||
| 1401 | case DTV_PILOT: | ||
| 1402 | c->pilot = tvp->u.data; | ||
| 1403 | break; | ||
| 1404 | case DTV_ROLLOFF: | ||
| 1405 | c->rolloff = tvp->u.data; | ||
| 1406 | break; | ||
| 1407 | case DTV_DELIVERY_SYSTEM: | ||
| 1408 | c->delivery_system = tvp->u.data; | ||
| 1409 | break; | ||
| 1410 | case DTV_VOLTAGE: | ||
| 1411 | c->voltage = tvp->u.data; | ||
| 1412 | r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE, | ||
| 1413 | (void *)c->voltage); | ||
| 1414 | break; | ||
| 1415 | case DTV_TONE: | ||
| 1416 | c->sectone = tvp->u.data; | ||
| 1417 | r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE, | ||
| 1418 | (void *)c->sectone); | ||
| 1419 | break; | ||
| 1420 | case DTV_CODE_RATE_HP: | ||
| 1421 | c->code_rate_HP = tvp->u.data; | ||
| 1422 | break; | ||
| 1423 | case DTV_CODE_RATE_LP: | ||
| 1424 | c->code_rate_LP = tvp->u.data; | ||
| 1425 | break; | ||
| 1426 | case DTV_GUARD_INTERVAL: | ||
| 1427 | c->guard_interval = tvp->u.data; | ||
| 1428 | break; | ||
| 1429 | case DTV_TRANSMISSION_MODE: | ||
| 1430 | c->transmission_mode = tvp->u.data; | ||
| 1431 | break; | ||
| 1432 | case DTV_HIERARCHY: | ||
| 1433 | c->hierarchy = tvp->u.data; | ||
| 1434 | break; | ||
| 1435 | |||
| 1436 | /* ISDB-T Support here */ | ||
| 1437 | case DTV_ISDBT_PARTIAL_RECEPTION: | ||
| 1438 | c->isdbt_partial_reception = tvp->u.data; | ||
| 1439 | break; | ||
| 1440 | case DTV_ISDBT_SOUND_BROADCASTING: | ||
| 1441 | c->isdbt_sb_mode = tvp->u.data; | ||
| 1442 | break; | ||
| 1443 | case DTV_ISDBT_SB_SUBCHANNEL_ID: | ||
| 1444 | c->isdbt_sb_subchannel = tvp->u.data; | ||
| 1445 | break; | ||
| 1446 | case DTV_ISDBT_SB_SEGMENT_IDX: | ||
| 1447 | c->isdbt_sb_segment_idx = tvp->u.data; | ||
| 1448 | break; | ||
| 1449 | case DTV_ISDBT_SB_SEGMENT_COUNT: | ||
| 1450 | c->isdbt_sb_segment_count = tvp->u.data; | ||
| 1451 | break; | ||
| 1452 | case DTV_ISDBT_LAYER_ENABLED: | ||
| 1453 | c->isdbt_layer_enabled = tvp->u.data; | ||
| 1454 | break; | ||
| 1455 | case DTV_ISDBT_LAYERA_FEC: | ||
| 1456 | c->layer[0].fec = tvp->u.data; | ||
| 1457 | break; | ||
| 1458 | case DTV_ISDBT_LAYERA_MODULATION: | ||
| 1459 | c->layer[0].modulation = tvp->u.data; | ||
| 1460 | break; | ||
| 1461 | case DTV_ISDBT_LAYERA_SEGMENT_COUNT: | ||
| 1462 | c->layer[0].segment_count = tvp->u.data; | ||
| 1463 | break; | ||
| 1464 | case DTV_ISDBT_LAYERA_TIME_INTERLEAVING: | ||
| 1465 | c->layer[0].interleaving = tvp->u.data; | ||
| 1466 | break; | ||
| 1467 | case DTV_ISDBT_LAYERB_FEC: | ||
| 1468 | c->layer[1].fec = tvp->u.data; | ||
| 1469 | break; | ||
| 1470 | case DTV_ISDBT_LAYERB_MODULATION: | ||
| 1471 | c->layer[1].modulation = tvp->u.data; | ||
| 1472 | break; | ||
| 1473 | case DTV_ISDBT_LAYERB_SEGMENT_COUNT: | ||
| 1474 | c->layer[1].segment_count = tvp->u.data; | ||
| 1475 | break; | ||
| 1476 | case DTV_ISDBT_LAYERB_TIME_INTERLEAVING: | ||
| 1477 | c->layer[1].interleaving = tvp->u.data; | ||
| 1478 | break; | ||
| 1479 | case DTV_ISDBT_LAYERC_FEC: | ||
| 1480 | c->layer[2].fec = tvp->u.data; | ||
| 1481 | break; | ||
| 1482 | case DTV_ISDBT_LAYERC_MODULATION: | ||
| 1483 | c->layer[2].modulation = tvp->u.data; | ||
| 1484 | break; | ||
| 1485 | case DTV_ISDBT_LAYERC_SEGMENT_COUNT: | ||
| 1486 | c->layer[2].segment_count = tvp->u.data; | ||
| 1487 | break; | ||
| 1488 | case DTV_ISDBT_LAYERC_TIME_INTERLEAVING: | ||
| 1489 | c->layer[2].interleaving = tvp->u.data; | ||
| 1490 | break; | ||
| 1491 | case DTV_ISDBS_TS_ID: | ||
| 1492 | c->isdbs_ts_id = tvp->u.data; | ||
| 1493 | break; | ||
| 1494 | case DTV_DVBT2_PLP_ID: | ||
| 1495 | c->dvbt2_plp_id = tvp->u.data; | ||
| 1496 | break; | ||
| 1497 | default: | ||
| 1498 | return -EINVAL; | ||
| 1499 | } | ||
| 1500 | |||
| 1501 | return r; | ||
| 1502 | } | ||
| 1503 | |||
| 1504 | static int dvb_frontend_ioctl(struct file *file, | ||
| 1505 | unsigned int cmd, void *parg) | ||
| 1506 | { | ||
| 1507 | struct dvb_device *dvbdev = file->private_data; | ||
| 1508 | struct dvb_frontend *fe = dvbdev->priv; | ||
| 1509 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
| 1510 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 1511 | int err = -EOPNOTSUPP; | ||
| 1512 | |||
| 1513 | dprintk("%s (%d)\n", __func__, _IOC_NR(cmd)); | ||
| 1514 | |||
| 1515 | if (fepriv->exit != DVB_FE_NO_EXIT) | ||
| 1516 | return -ENODEV; | ||
| 1517 | |||
| 1518 | if ((file->f_flags & O_ACCMODE) == O_RDONLY && | ||
| 1519 | (_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT || | ||
| 1520 | cmd == FE_DISEQC_RECV_SLAVE_REPLY)) | ||
| 1521 | return -EPERM; | ||
| 1522 | |||
| 1523 | if (down_interruptible (&fepriv->sem)) | ||
| 1524 | return -ERESTARTSYS; | ||
| 1525 | |||
| 1526 | if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY)) | ||
| 1527 | err = dvb_frontend_ioctl_properties(file, cmd, parg); | ||
| 1528 | else { | ||
| 1529 | c->state = DTV_UNDEFINED; | ||
| 1530 | err = dvb_frontend_ioctl_legacy(file, cmd, parg); | ||
| 1531 | } | ||
| 1532 | |||
| 1533 | up(&fepriv->sem); | ||
| 1534 | return err; | ||
| 1535 | } | ||
| 1536 | |||
| 1537 | static int dvb_frontend_ioctl_properties(struct file *file, | ||
| 1538 | unsigned int cmd, void *parg) | ||
| 1539 | { | ||
| 1540 | struct dvb_device *dvbdev = file->private_data; | ||
| 1541 | struct dvb_frontend *fe = dvbdev->priv; | ||
| 1542 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
| 1543 | int err = 0; | ||
| 1544 | |||
| 1545 | struct dtv_properties *tvps = NULL; | ||
| 1546 | struct dtv_property *tvp = NULL; | ||
| 1547 | int i; | ||
| 1548 | |||
| 1549 | dprintk("%s\n", __func__); | ||
| 1550 | |||
| 1551 | if(cmd == FE_SET_PROPERTY) { | ||
| 1552 | tvps = (struct dtv_properties __user *)parg; | ||
| 1553 | |||
| 1554 | dprintk("%s() properties.num = %d\n", __func__, tvps->num); | ||
| 1555 | dprintk("%s() properties.props = %p\n", __func__, tvps->props); | ||
| 1556 | |||
| 1557 | /* Put an arbitrary limit on the number of messages that can | ||
| 1558 | * be sent at once */ | ||
| 1559 | if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) | ||
| 1560 | return -EINVAL; | ||
| 1561 | |||
| 1562 | tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL); | ||
| 1563 | if (!tvp) { | ||
| 1564 | err = -ENOMEM; | ||
| 1565 | goto out; | ||
| 1566 | } | ||
| 1567 | |||
| 1568 | if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) { | ||
| 1569 | err = -EFAULT; | ||
| 1570 | goto out; | ||
| 1571 | } | ||
| 1572 | |||
| 1573 | for (i = 0; i < tvps->num; i++) { | ||
| 1574 | err = dtv_property_process_set(fe, tvp + i, file); | ||
| 1575 | if (err < 0) | ||
| 1576 | goto out; | ||
| 1577 | (tvp + i)->result = err; | ||
| 1578 | } | ||
| 1579 | |||
| 1580 | if (c->state == DTV_TUNE) | ||
| 1581 | dprintk("%s() Property cache is full, tuning\n", __func__); | ||
| 1582 | |||
| 1583 | } else | ||
| 1584 | if(cmd == FE_GET_PROPERTY) { | ||
| 1585 | |||
| 1586 | tvps = (struct dtv_properties __user *)parg; | ||
| 1587 | |||
| 1588 | dprintk("%s() properties.num = %d\n", __func__, tvps->num); | ||
| 1589 | dprintk("%s() properties.props = %p\n", __func__, tvps->props); | ||
| 1590 | |||
| 1591 | /* Put an arbitrary limit on the number of messages that can | ||
| 1592 | * be sent at once */ | ||
| 1593 | if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) | ||
| 1594 | return -EINVAL; | ||
| 1595 | |||
| 1596 | tvp = kmalloc(tvps->num * sizeof(struct dtv_property), GFP_KERNEL); | ||
| 1597 | if (!tvp) { | ||
| 1598 | err = -ENOMEM; | ||
| 1599 | goto out; | ||
| 1600 | } | ||
| 1601 | |||
| 1602 | if (copy_from_user(tvp, tvps->props, tvps->num * sizeof(struct dtv_property))) { | ||
| 1603 | err = -EFAULT; | ||
| 1604 | goto out; | ||
| 1605 | } | ||
| 1606 | |||
| 1607 | for (i = 0; i < tvps->num; i++) { | ||
| 1608 | err = dtv_property_process_get(fe, tvp + i, file); | ||
| 1609 | if (err < 0) | ||
| 1610 | goto out; | ||
| 1611 | (tvp + i)->result = err; | ||
| 1612 | } | ||
| 1613 | |||
| 1614 | if (copy_to_user(tvps->props, tvp, tvps->num * sizeof(struct dtv_property))) { | ||
| 1615 | err = -EFAULT; | ||
| 1616 | goto out; | ||
| 1617 | } | ||
| 1618 | |||
| 1619 | } else | ||
| 1620 | err = -EOPNOTSUPP; | ||
| 1621 | |||
| 1622 | out: | ||
| 1623 | kfree(tvp); | ||
| 1624 | return err; | ||
| 1625 | } | ||
| 1626 | |||
| 1627 | static int dvb_frontend_ioctl_legacy(struct file *file, | ||
| 1628 | unsigned int cmd, void *parg) | ||
| 1629 | { | ||
| 1630 | struct dvb_device *dvbdev = file->private_data; | ||
| 1631 | struct dvb_frontend *fe = dvbdev->priv; | ||
| 1632 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 1633 | int cb_err, err = -EOPNOTSUPP; | ||
| 1634 | |||
| 1635 | if (fe->dvb->fe_ioctl_override) { | ||
| 1636 | cb_err = fe->dvb->fe_ioctl_override(fe, cmd, parg, | ||
| 1637 | DVB_FE_IOCTL_PRE); | ||
| 1638 | if (cb_err < 0) | ||
| 1639 | return cb_err; | ||
| 1640 | if (cb_err > 0) | ||
| 1641 | return 0; | ||
| 1642 | /* fe_ioctl_override returning 0 allows | ||
| 1643 | * dvb-core to continue handling the ioctl */ | ||
| 1644 | } | ||
| 1645 | |||
| 1646 | switch (cmd) { | ||
| 1647 | case FE_GET_INFO: { | ||
| 1648 | struct dvb_frontend_info* info = parg; | ||
| 1649 | memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info)); | ||
| 1650 | dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max); | ||
| 1651 | |||
| 1652 | /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't | ||
| 1653 | * do it, it is done for it. */ | ||
| 1654 | info->caps |= FE_CAN_INVERSION_AUTO; | ||
| 1655 | err = 0; | ||
| 1656 | break; | ||
| 1657 | } | ||
| 1658 | |||
| 1659 | case FE_READ_STATUS: { | ||
| 1660 | fe_status_t* status = parg; | ||
| 1661 | |||
| 1662 | /* if retune was requested but hasn't occurred yet, prevent | ||
| 1663 | * that user get signal state from previous tuning */ | ||
| 1664 | if (fepriv->state == FESTATE_RETUNE || | ||
| 1665 | fepriv->state == FESTATE_ERROR) { | ||
| 1666 | err=0; | ||
| 1667 | *status = 0; | ||
| 1668 | break; | ||
| 1669 | } | ||
| 1670 | |||
| 1671 | if (fe->ops.read_status) | ||
| 1672 | err = fe->ops.read_status(fe, status); | ||
| 1673 | break; | ||
| 1674 | } | ||
| 1675 | case FE_READ_BER: | ||
| 1676 | if (fe->ops.read_ber) | ||
| 1677 | err = fe->ops.read_ber(fe, (__u32*) parg); | ||
| 1678 | break; | ||
| 1679 | |||
| 1680 | case FE_READ_SIGNAL_STRENGTH: | ||
| 1681 | if (fe->ops.read_signal_strength) | ||
| 1682 | err = fe->ops.read_signal_strength(fe, (__u16*) parg); | ||
| 1683 | break; | ||
| 1684 | |||
| 1685 | case FE_READ_SNR: | ||
| 1686 | if (fe->ops.read_snr) | ||
| 1687 | err = fe->ops.read_snr(fe, (__u16*) parg); | ||
| 1688 | break; | ||
| 1689 | |||
| 1690 | case FE_READ_UNCORRECTED_BLOCKS: | ||
| 1691 | if (fe->ops.read_ucblocks) | ||
| 1692 | err = fe->ops.read_ucblocks(fe, (__u32*) parg); | ||
| 1693 | break; | ||
| 1694 | |||
| 1695 | |||
| 1696 | case FE_DISEQC_RESET_OVERLOAD: | ||
| 1697 | if (fe->ops.diseqc_reset_overload) { | ||
| 1698 | err = fe->ops.diseqc_reset_overload(fe); | ||
| 1699 | fepriv->state = FESTATE_DISEQC; | ||
| 1700 | fepriv->status = 0; | ||
| 1701 | } | ||
| 1702 | break; | ||
| 1703 | |||
| 1704 | case FE_DISEQC_SEND_MASTER_CMD: | ||
| 1705 | if (fe->ops.diseqc_send_master_cmd) { | ||
| 1706 | err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg); | ||
| 1707 | fepriv->state = FESTATE_DISEQC; | ||
| 1708 | fepriv->status = 0; | ||
| 1709 | } | ||
| 1710 | break; | ||
| 1711 | |||
| 1712 | case FE_DISEQC_SEND_BURST: | ||
| 1713 | if (fe->ops.diseqc_send_burst) { | ||
| 1714 | err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg); | ||
| 1715 | fepriv->state = FESTATE_DISEQC; | ||
| 1716 | fepriv->status = 0; | ||
| 1717 | } | ||
| 1718 | break; | ||
| 1719 | |||
| 1720 | case FE_SET_TONE: | ||
| 1721 | if (fe->ops.set_tone) { | ||
| 1722 | err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg); | ||
| 1723 | fepriv->tone = (fe_sec_tone_mode_t) parg; | ||
| 1724 | fepriv->state = FESTATE_DISEQC; | ||
| 1725 | fepriv->status = 0; | ||
| 1726 | } | ||
| 1727 | break; | ||
| 1728 | |||
| 1729 | case FE_SET_VOLTAGE: | ||
| 1730 | if (fe->ops.set_voltage) { | ||
| 1731 | err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg); | ||
| 1732 | fepriv->voltage = (fe_sec_voltage_t) parg; | ||
| 1733 | fepriv->state = FESTATE_DISEQC; | ||
| 1734 | fepriv->status = 0; | ||
| 1735 | } | ||
| 1736 | break; | ||
| 1737 | |||
| 1738 | case FE_DISHNETWORK_SEND_LEGACY_CMD: | ||
| 1739 | if (fe->ops.dishnetwork_send_legacy_command) { | ||
| 1740 | err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg); | ||
| 1741 | fepriv->state = FESTATE_DISEQC; | ||
| 1742 | fepriv->status = 0; | ||
| 1743 | } else if (fe->ops.set_voltage) { | ||
| 1744 | /* | ||
| 1745 | * NOTE: This is a fallback condition. Some frontends | ||
| 1746 | * (stv0299 for instance) take longer than 8msec to | ||
| 1747 | * respond to a set_voltage command. Those switches | ||
| 1748 | * need custom routines to switch properly. For all | ||
| 1749 | * other frontends, the following should work ok. | ||
| 1750 | * Dish network legacy switches (as used by Dish500) | ||
| 1751 | * are controlled by sending 9-bit command words | ||
| 1752 | * spaced 8msec apart. | ||
| 1753 | * the actual command word is switch/port dependent | ||
| 1754 | * so it is up to the userspace application to send | ||
| 1755 | * the right command. | ||
| 1756 | * The command must always start with a '0' after | ||
| 1757 | * initialization, so parg is 8 bits and does not | ||
| 1758 | * include the initialization or start bit | ||
| 1759 | */ | ||
| 1760 | unsigned long swcmd = ((unsigned long) parg) << 1; | ||
| 1761 | struct timeval nexttime; | ||
| 1762 | struct timeval tv[10]; | ||
| 1763 | int i; | ||
| 1764 | u8 last = 1; | ||
| 1765 | if (dvb_frontend_debug) | ||
| 1766 | printk("%s switch command: 0x%04lx\n", __func__, swcmd); | ||
| 1767 | do_gettimeofday(&nexttime); | ||
| 1768 | if (dvb_frontend_debug) | ||
| 1769 | memcpy(&tv[0], &nexttime, sizeof(struct timeval)); | ||
| 1770 | /* before sending a command, initialize by sending | ||
| 1771 | * a 32ms 18V to the switch | ||
| 1772 | */ | ||
| 1773 | fe->ops.set_voltage(fe, SEC_VOLTAGE_18); | ||
| 1774 | dvb_frontend_sleep_until(&nexttime, 32000); | ||
| 1775 | |||
| 1776 | for (i = 0; i < 9; i++) { | ||
| 1777 | if (dvb_frontend_debug) | ||
| 1778 | do_gettimeofday(&tv[i + 1]); | ||
| 1779 | if ((swcmd & 0x01) != last) { | ||
| 1780 | /* set voltage to (last ? 13V : 18V) */ | ||
| 1781 | fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18); | ||
| 1782 | last = (last) ? 0 : 1; | ||
| 1783 | } | ||
| 1784 | swcmd = swcmd >> 1; | ||
| 1785 | if (i != 8) | ||
| 1786 | dvb_frontend_sleep_until(&nexttime, 8000); | ||
| 1787 | } | ||
| 1788 | if (dvb_frontend_debug) { | ||
| 1789 | printk("%s(%d): switch delay (should be 32k followed by all 8k\n", | ||
| 1790 | __func__, fe->dvb->num); | ||
| 1791 | for (i = 1; i < 10; i++) | ||
| 1792 | printk("%d: %d\n", i, timeval_usec_diff(tv[i-1] , tv[i])); | ||
| 1793 | } | ||
| 1794 | err = 0; | ||
| 1795 | fepriv->state = FESTATE_DISEQC; | ||
| 1796 | fepriv->status = 0; | ||
| 1797 | } | ||
| 1798 | break; | ||
| 1799 | |||
| 1800 | case FE_DISEQC_RECV_SLAVE_REPLY: | ||
| 1801 | if (fe->ops.diseqc_recv_slave_reply) | ||
| 1802 | err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg); | ||
| 1803 | break; | ||
| 1804 | |||
| 1805 | case FE_ENABLE_HIGH_LNB_VOLTAGE: | ||
| 1806 | if (fe->ops.enable_high_lnb_voltage) | ||
| 1807 | err = fe->ops.enable_high_lnb_voltage(fe, (long) parg); | ||
| 1808 | break; | ||
| 1809 | |||
| 1810 | case FE_SET_FRONTEND: { | ||
| 1811 | struct dtv_frontend_properties *c = &fe->dtv_property_cache; | ||
| 1812 | struct dvb_frontend_tune_settings fetunesettings; | ||
| 1813 | |||
| 1814 | if (c->state == DTV_TUNE) { | ||
| 1815 | if (dvb_frontend_check_parameters(fe, &fepriv->parameters_in) < 0) { | ||
| 1816 | err = -EINVAL; | ||
| 1817 | break; | ||
| 1818 | } | ||
| 1819 | } else { | ||
| 1820 | if (dvb_frontend_check_parameters(fe, parg) < 0) { | ||
| 1821 | err = -EINVAL; | ||
| 1822 | break; | ||
| 1823 | } | ||
| 1824 | |||
| 1825 | memcpy (&fepriv->parameters_in, parg, | ||
| 1826 | sizeof (struct dvb_frontend_parameters)); | ||
| 1827 | dtv_property_cache_sync(fe, c, &fepriv->parameters_in); | ||
| 1828 | } | ||
| 1829 | |||
| 1830 | memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings)); | ||
| 1831 | memcpy(&fetunesettings.parameters, parg, | ||
| 1832 | sizeof (struct dvb_frontend_parameters)); | ||
| 1833 | |||
| 1834 | /* force auto frequency inversion if requested */ | ||
| 1835 | if (dvb_force_auto_inversion) { | ||
| 1836 | fepriv->parameters_in.inversion = INVERSION_AUTO; | ||
| 1837 | fetunesettings.parameters.inversion = INVERSION_AUTO; | ||
| 1838 | } | ||
| 1839 | if (fe->ops.info.type == FE_OFDM) { | ||
| 1840 | /* without hierarchical coding code_rate_LP is irrelevant, | ||
| 1841 | * so we tolerate the otherwise invalid FEC_NONE setting */ | ||
| 1842 | if (fepriv->parameters_in.u.ofdm.hierarchy_information == HIERARCHY_NONE && | ||
| 1843 | fepriv->parameters_in.u.ofdm.code_rate_LP == FEC_NONE) | ||
| 1844 | fepriv->parameters_in.u.ofdm.code_rate_LP = FEC_AUTO; | ||
| 1845 | } | ||
| 1846 | |||
| 1847 | /* get frontend-specific tuning settings */ | ||
| 1848 | if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) { | ||
| 1849 | fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000; | ||
| 1850 | fepriv->max_drift = fetunesettings.max_drift; | ||
| 1851 | fepriv->step_size = fetunesettings.step_size; | ||
| 1852 | } else { | ||
| 1853 | /* default values */ | ||
| 1854 | switch(fe->ops.info.type) { | ||
| 1855 | case FE_QPSK: | ||
| 1856 | fepriv->min_delay = HZ/20; | ||
| 1857 | fepriv->step_size = fepriv->parameters_in.u.qpsk.symbol_rate / 16000; | ||
| 1858 | fepriv->max_drift = fepriv->parameters_in.u.qpsk.symbol_rate / 2000; | ||
| 1859 | break; | ||
| 1860 | |||
| 1861 | case FE_QAM: | ||
| 1862 | fepriv->min_delay = HZ/20; | ||
| 1863 | fepriv->step_size = 0; /* no zigzag */ | ||
| 1864 | fepriv->max_drift = 0; | ||
| 1865 | break; | ||
| 1866 | |||
| 1867 | case FE_OFDM: | ||
| 1868 | fepriv->min_delay = HZ/20; | ||
| 1869 | fepriv->step_size = fe->ops.info.frequency_stepsize * 2; | ||
| 1870 | fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1; | ||
| 1871 | break; | ||
| 1872 | case FE_ATSC: | ||
| 1873 | fepriv->min_delay = HZ/20; | ||
| 1874 | fepriv->step_size = 0; | ||
| 1875 | fepriv->max_drift = 0; | ||
| 1876 | break; | ||
| 1877 | } | ||
| 1878 | } | ||
| 1879 | if (dvb_override_tune_delay > 0) | ||
| 1880 | fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000; | ||
| 1881 | |||
| 1882 | fepriv->state = FESTATE_RETUNE; | ||
| 1883 | |||
| 1884 | /* Request the search algorithm to search */ | ||
| 1885 | fepriv->algo_status |= DVBFE_ALGO_SEARCH_AGAIN; | ||
| 1886 | |||
| 1887 | dvb_frontend_wakeup(fe); | ||
| 1888 | dvb_frontend_add_event(fe, 0); | ||
| 1889 | fepriv->status = 0; | ||
| 1890 | err = 0; | ||
| 1891 | break; | ||
| 1892 | } | ||
| 1893 | |||
| 1894 | case FE_GET_EVENT: | ||
| 1895 | err = dvb_frontend_get_event (fe, parg, file->f_flags); | ||
| 1896 | break; | ||
| 1897 | |||
| 1898 | case FE_GET_FRONTEND: | ||
| 1899 | if (fe->ops.get_frontend) { | ||
| 1900 | err = fe->ops.get_frontend(fe, &fepriv->parameters_out); | ||
| 1901 | memcpy(parg, &fepriv->parameters_out, sizeof(struct dvb_frontend_parameters)); | ||
| 1902 | } | ||
| 1903 | break; | ||
| 1904 | |||
| 1905 | case FE_SET_FRONTEND_TUNE_MODE: | ||
| 1906 | fepriv->tune_mode_flags = (unsigned long) parg; | ||
| 1907 | err = 0; | ||
| 1908 | break; | ||
| 1909 | }; | ||
| 1910 | |||
| 1911 | if (fe->dvb->fe_ioctl_override) { | ||
| 1912 | cb_err = fe->dvb->fe_ioctl_override(fe, cmd, parg, | ||
| 1913 | DVB_FE_IOCTL_POST); | ||
| 1914 | if (cb_err < 0) | ||
| 1915 | return cb_err; | ||
| 1916 | } | ||
| 1917 | |||
| 1918 | return err; | ||
| 1919 | } | ||
| 1920 | |||
| 1921 | |||
| 1922 | static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait) | ||
| 1923 | { | ||
| 1924 | struct dvb_device *dvbdev = file->private_data; | ||
| 1925 | struct dvb_frontend *fe = dvbdev->priv; | ||
| 1926 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 1927 | |||
| 1928 | dprintk ("%s\n", __func__); | ||
| 1929 | |||
| 1930 | poll_wait (file, &fepriv->events.wait_queue, wait); | ||
| 1931 | |||
| 1932 | if (fepriv->events.eventw != fepriv->events.eventr) | ||
| 1933 | return (POLLIN | POLLRDNORM | POLLPRI); | ||
| 1934 | |||
| 1935 | return 0; | ||
| 1936 | } | ||
| 1937 | |||
| 1938 | static int dvb_frontend_open(struct inode *inode, struct file *file) | ||
| 1939 | { | ||
| 1940 | struct dvb_device *dvbdev = file->private_data; | ||
| 1941 | struct dvb_frontend *fe = dvbdev->priv; | ||
| 1942 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 1943 | struct dvb_adapter *adapter = fe->dvb; | ||
| 1944 | int ret; | ||
| 1945 | |||
| 1946 | dprintk ("%s\n", __func__); | ||
| 1947 | if (fepriv->exit == DVB_FE_DEVICE_REMOVED) | ||
| 1948 | return -ENODEV; | ||
| 1949 | |||
| 1950 | if (adapter->mfe_shared) { | ||
| 1951 | mutex_lock (&adapter->mfe_lock); | ||
| 1952 | |||
| 1953 | if (adapter->mfe_dvbdev == NULL) | ||
| 1954 | adapter->mfe_dvbdev = dvbdev; | ||
| 1955 | |||
| 1956 | else if (adapter->mfe_dvbdev != dvbdev) { | ||
| 1957 | struct dvb_device | ||
| 1958 | *mfedev = adapter->mfe_dvbdev; | ||
| 1959 | struct dvb_frontend | ||
| 1960 | *mfe = mfedev->priv; | ||
| 1961 | struct dvb_frontend_private | ||
| 1962 | *mfepriv = mfe->frontend_priv; | ||
| 1963 | int mferetry = (dvb_mfe_wait_time << 1); | ||
| 1964 | |||
| 1965 | mutex_unlock (&adapter->mfe_lock); | ||
| 1966 | while (mferetry-- && (mfedev->users != -1 || | ||
| 1967 | mfepriv->thread != NULL)) { | ||
| 1968 | if(msleep_interruptible(500)) { | ||
| 1969 | if(signal_pending(current)) | ||
| 1970 | return -EINTR; | ||
| 1971 | } | ||
| 1972 | } | ||
| 1973 | |||
| 1974 | mutex_lock (&adapter->mfe_lock); | ||
| 1975 | if(adapter->mfe_dvbdev != dvbdev) { | ||
| 1976 | mfedev = adapter->mfe_dvbdev; | ||
| 1977 | mfe = mfedev->priv; | ||
| 1978 | mfepriv = mfe->frontend_priv; | ||
| 1979 | if (mfedev->users != -1 || | ||
| 1980 | mfepriv->thread != NULL) { | ||
| 1981 | mutex_unlock (&adapter->mfe_lock); | ||
| 1982 | return -EBUSY; | ||
| 1983 | } | ||
| 1984 | adapter->mfe_dvbdev = dvbdev; | ||
| 1985 | } | ||
| 1986 | } | ||
| 1987 | } | ||
| 1988 | |||
| 1989 | if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) { | ||
| 1990 | if ((ret = fe->ops.ts_bus_ctrl(fe, 1)) < 0) | ||
| 1991 | goto err0; | ||
| 1992 | |||
| 1993 | /* If we took control of the bus, we need to force | ||
| 1994 | reinitialization. This is because many ts_bus_ctrl() | ||
| 1995 | functions strobe the RESET pin on the demod, and if the | ||
| 1996 | frontend thread already exists then the dvb_init() routine | ||
| 1997 | won't get called (which is what usually does initial | ||
| 1998 | register configuration). */ | ||
| 1999 | fepriv->reinitialise = 1; | ||
| 2000 | } | ||
| 2001 | |||
| 2002 | if ((ret = dvb_generic_open (inode, file)) < 0) | ||
| 2003 | goto err1; | ||
| 2004 | |||
| 2005 | if ((file->f_flags & O_ACCMODE) != O_RDONLY) { | ||
| 2006 | /* normal tune mode when opened R/W */ | ||
| 2007 | fepriv->tune_mode_flags &= ~FE_TUNE_MODE_ONESHOT; | ||
| 2008 | fepriv->tone = -1; | ||
| 2009 | fepriv->voltage = -1; | ||
| 2010 | |||
| 2011 | ret = dvb_frontend_start (fe); | ||
| 2012 | if (ret) | ||
| 2013 | goto err2; | ||
| 2014 | |||
| 2015 | /* empty event queue */ | ||
| 2016 | fepriv->events.eventr = fepriv->events.eventw = 0; | ||
| 2017 | } | ||
| 2018 | |||
| 2019 | if (adapter->mfe_shared) | ||
| 2020 | mutex_unlock (&adapter->mfe_lock); | ||
| 2021 | return ret; | ||
| 2022 | |||
| 2023 | err2: | ||
| 2024 | dvb_generic_release(inode, file); | ||
| 2025 | err1: | ||
| 2026 | if (dvbdev->users == -1 && fe->ops.ts_bus_ctrl) | ||
| 2027 | fe->ops.ts_bus_ctrl(fe, 0); | ||
| 2028 | err0: | ||
| 2029 | if (adapter->mfe_shared) | ||
| 2030 | mutex_unlock (&adapter->mfe_lock); | ||
| 2031 | return ret; | ||
| 2032 | } | ||
| 2033 | |||
| 2034 | static int dvb_frontend_release(struct inode *inode, struct file *file) | ||
| 2035 | { | ||
| 2036 | struct dvb_device *dvbdev = file->private_data; | ||
| 2037 | struct dvb_frontend *fe = dvbdev->priv; | ||
| 2038 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 2039 | int ret; | ||
| 2040 | |||
| 2041 | dprintk ("%s\n", __func__); | ||
| 2042 | |||
| 2043 | if ((file->f_flags & O_ACCMODE) != O_RDONLY) | ||
| 2044 | fepriv->release_jiffies = jiffies; | ||
| 2045 | |||
| 2046 | ret = dvb_generic_release (inode, file); | ||
| 2047 | |||
| 2048 | if (dvbdev->users == -1) { | ||
| 2049 | if (fepriv->exit != DVB_FE_NO_EXIT) { | ||
| 2050 | fops_put(file->f_op); | ||
| 2051 | file->f_op = NULL; | ||
| 2052 | wake_up(&dvbdev->wait_queue); | ||
| 2053 | } | ||
| 2054 | if (fe->ops.ts_bus_ctrl) | ||
| 2055 | fe->ops.ts_bus_ctrl(fe, 0); | ||
| 2056 | } | ||
| 2057 | |||
| 2058 | return ret; | ||
| 2059 | } | ||
| 2060 | |||
| 2061 | static const struct file_operations dvb_frontend_fops = { | ||
| 2062 | .owner = THIS_MODULE, | ||
| 2063 | .unlocked_ioctl = dvb_generic_ioctl, | ||
| 2064 | .poll = dvb_frontend_poll, | ||
| 2065 | .open = dvb_frontend_open, | ||
| 2066 | .release = dvb_frontend_release, | ||
| 2067 | .llseek = noop_llseek, | ||
| 2068 | }; | ||
| 2069 | |||
| 2070 | int dvb_register_frontend(struct dvb_adapter* dvb, | ||
| 2071 | struct dvb_frontend* fe) | ||
| 2072 | { | ||
| 2073 | struct dvb_frontend_private *fepriv; | ||
| 2074 | static const struct dvb_device dvbdev_template = { | ||
| 2075 | .users = ~0, | ||
| 2076 | .writers = 1, | ||
| 2077 | .readers = (~0)-1, | ||
| 2078 | .fops = &dvb_frontend_fops, | ||
| 2079 | .kernel_ioctl = dvb_frontend_ioctl | ||
| 2080 | }; | ||
| 2081 | |||
| 2082 | dprintk ("%s\n", __func__); | ||
| 2083 | |||
| 2084 | if (mutex_lock_interruptible(&frontend_mutex)) | ||
| 2085 | return -ERESTARTSYS; | ||
| 2086 | |||
| 2087 | fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL); | ||
| 2088 | if (fe->frontend_priv == NULL) { | ||
| 2089 | mutex_unlock(&frontend_mutex); | ||
| 2090 | return -ENOMEM; | ||
| 2091 | } | ||
| 2092 | fepriv = fe->frontend_priv; | ||
| 2093 | |||
| 2094 | sema_init(&fepriv->sem, 1); | ||
| 2095 | init_waitqueue_head (&fepriv->wait_queue); | ||
| 2096 | init_waitqueue_head (&fepriv->events.wait_queue); | ||
| 2097 | mutex_init(&fepriv->events.mtx); | ||
| 2098 | fe->dvb = dvb; | ||
| 2099 | fepriv->inversion = INVERSION_OFF; | ||
| 2100 | |||
| 2101 | printk ("DVB: registering adapter %i frontend %i (%s)...\n", | ||
| 2102 | fe->dvb->num, | ||
| 2103 | fe->id, | ||
| 2104 | fe->ops.info.name); | ||
| 2105 | |||
| 2106 | dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template, | ||
| 2107 | fe, DVB_DEVICE_FRONTEND); | ||
| 2108 | |||
| 2109 | mutex_unlock(&frontend_mutex); | ||
| 2110 | return 0; | ||
| 2111 | } | ||
| 2112 | EXPORT_SYMBOL(dvb_register_frontend); | ||
| 2113 | |||
| 2114 | int dvb_unregister_frontend(struct dvb_frontend* fe) | ||
| 2115 | { | ||
| 2116 | struct dvb_frontend_private *fepriv = fe->frontend_priv; | ||
| 2117 | dprintk ("%s\n", __func__); | ||
| 2118 | |||
| 2119 | mutex_lock(&frontend_mutex); | ||
| 2120 | dvb_frontend_stop (fe); | ||
| 2121 | mutex_unlock(&frontend_mutex); | ||
| 2122 | |||
| 2123 | if (fepriv->dvbdev->users < -1) | ||
| 2124 | wait_event(fepriv->dvbdev->wait_queue, | ||
| 2125 | fepriv->dvbdev->users==-1); | ||
| 2126 | |||
| 2127 | mutex_lock(&frontend_mutex); | ||
| 2128 | dvb_unregister_device (fepriv->dvbdev); | ||
| 2129 | |||
| 2130 | /* fe is invalid now */ | ||
| 2131 | kfree(fepriv); | ||
| 2132 | mutex_unlock(&frontend_mutex); | ||
| 2133 | return 0; | ||
| 2134 | } | ||
| 2135 | EXPORT_SYMBOL(dvb_unregister_frontend); | ||
| 2136 | |||
| 2137 | #ifdef CONFIG_MEDIA_ATTACH | ||
| 2138 | void dvb_frontend_detach(struct dvb_frontend* fe) | ||
| 2139 | { | ||
| 2140 | void *ptr; | ||
| 2141 | |||
| 2142 | if (fe->ops.release_sec) { | ||
| 2143 | fe->ops.release_sec(fe); | ||
| 2144 | symbol_put_addr(fe->ops.release_sec); | ||
| 2145 | } | ||
| 2146 | if (fe->ops.tuner_ops.release) { | ||
| 2147 | fe->ops.tuner_ops.release(fe); | ||
| 2148 | symbol_put_addr(fe->ops.tuner_ops.release); | ||
| 2149 | } | ||
| 2150 | if (fe->ops.analog_ops.release) { | ||
| 2151 | fe->ops.analog_ops.release(fe); | ||
| 2152 | symbol_put_addr(fe->ops.analog_ops.release); | ||
| 2153 | } | ||
| 2154 | ptr = (void*)fe->ops.release; | ||
| 2155 | if (ptr) { | ||
| 2156 | fe->ops.release(fe); | ||
| 2157 | symbol_put_addr(ptr); | ||
| 2158 | } | ||
| 2159 | } | ||
| 2160 | #else | ||
| 2161 | void dvb_frontend_detach(struct dvb_frontend* fe) | ||
| 2162 | { | ||
| 2163 | if (fe->ops.release_sec) | ||
| 2164 | fe->ops.release_sec(fe); | ||
| 2165 | if (fe->ops.tuner_ops.release) | ||
| 2166 | fe->ops.tuner_ops.release(fe); | ||
| 2167 | if (fe->ops.analog_ops.release) | ||
| 2168 | fe->ops.analog_ops.release(fe); | ||
| 2169 | if (fe->ops.release) | ||
| 2170 | fe->ops.release(fe); | ||
| 2171 | } | ||
| 2172 | #endif | ||
| 2173 | EXPORT_SYMBOL(dvb_frontend_detach); | ||
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h new file mode 100644 index 00000000000..5590eb6eb40 --- /dev/null +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h | |||
| @@ -0,0 +1,392 @@ | |||
| 1 | /* | ||
| 2 | * dvb_frontend.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2001 convergence integrated media GmbH | ||
| 5 | * Copyright (C) 2004 convergence GmbH | ||
| 6 | * | ||
| 7 | * Written by Ralph Metzler | ||
| 8 | * Overhauled by Holger Waechtler | ||
| 9 | * Kernel I2C stuff by Michael Hunold <hunold@convergence.de> | ||
| 10 | * | ||
| 11 | * This program is free software; you can redistribute it and/or | ||
| 12 | * modify it under the terms of the GNU Lesser General Public License | ||
| 13 | * as published by the Free Software Foundation; either version 2.1 | ||
| 14 | * of the License, or (at your option) any later version. | ||
| 15 | * | ||
| 16 | * This program is distributed in the hope that it will be useful, | ||
| 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 19 | * GNU General Public License for more details. | ||
| 20 | * | ||
| 21 | |||
| 22 | * You should have received a copy of the GNU Lesser General Public License | ||
| 23 | * along with this program; if not, write to the Free Software | ||
| 24 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 25 | * | ||
| 26 | */ | ||
| 27 | |||
| 28 | #ifndef _DVB_FRONTEND_H_ | ||
| 29 | #define _DVB_FRONTEND_H_ | ||
| 30 | |||
| 31 | #include <linux/types.h> | ||
| 32 | #include <linux/sched.h> | ||
| 33 | #include <linux/ioctl.h> | ||
| 34 | #include <linux/i2c.h> | ||
| 35 | #include <linux/module.h> | ||
| 36 | #include <linux/errno.h> | ||
| 37 | #include <linux/delay.h> | ||
| 38 | #include <linux/mutex.h> | ||
| 39 | #include <linux/slab.h> | ||
| 40 | |||
| 41 | #include <linux/dvb/frontend.h> | ||
| 42 | |||
| 43 | #include "dvbdev.h" | ||
| 44 | |||
| 45 | struct dvb_frontend_tune_settings { | ||
| 46 | int min_delay_ms; | ||
| 47 | int step_size; | ||
| 48 | int max_drift; | ||
| 49 | struct dvb_frontend_parameters parameters; | ||
| 50 | }; | ||
| 51 | |||
| 52 | struct dvb_frontend; | ||
| 53 | |||
| 54 | struct dvb_tuner_info { | ||
| 55 | char name[128]; | ||
| 56 | |||
| 57 | u32 frequency_min; | ||
| 58 | u32 frequency_max; | ||
| 59 | u32 frequency_step; | ||
| 60 | |||
| 61 | u32 bandwidth_min; | ||
| 62 | u32 bandwidth_max; | ||
| 63 | u32 bandwidth_step; | ||
| 64 | }; | ||
| 65 | |||
| 66 | struct analog_parameters { | ||
| 67 | unsigned int frequency; | ||
| 68 | unsigned int mode; | ||
| 69 | unsigned int audmode; | ||
| 70 | u64 std; | ||
| 71 | }; | ||
| 72 | |||
| 73 | enum dvbfe_modcod { | ||
| 74 | DVBFE_MODCOD_DUMMY_PLFRAME = 0, | ||
| 75 | DVBFE_MODCOD_QPSK_1_4, | ||
| 76 | DVBFE_MODCOD_QPSK_1_3, | ||
| 77 | DVBFE_MODCOD_QPSK_2_5, | ||
| 78 | DVBFE_MODCOD_QPSK_1_2, | ||
| 79 | DVBFE_MODCOD_QPSK_3_5, | ||
| 80 | DVBFE_MODCOD_QPSK_2_3, | ||
| 81 | DVBFE_MODCOD_QPSK_3_4, | ||
| 82 | DVBFE_MODCOD_QPSK_4_5, | ||
| 83 | DVBFE_MODCOD_QPSK_5_6, | ||
| 84 | DVBFE_MODCOD_QPSK_8_9, | ||
| 85 | DVBFE_MODCOD_QPSK_9_10, | ||
| 86 | DVBFE_MODCOD_8PSK_3_5, | ||
| 87 | DVBFE_MODCOD_8PSK_2_3, | ||
| 88 | DVBFE_MODCOD_8PSK_3_4, | ||
| 89 | DVBFE_MODCOD_8PSK_5_6, | ||
| 90 | DVBFE_MODCOD_8PSK_8_9, | ||
| 91 | DVBFE_MODCOD_8PSK_9_10, | ||
| 92 | DVBFE_MODCOD_16APSK_2_3, | ||
| 93 | DVBFE_MODCOD_16APSK_3_4, | ||
| 94 | DVBFE_MODCOD_16APSK_4_5, | ||
| 95 | DVBFE_MODCOD_16APSK_5_6, | ||
| 96 | DVBFE_MODCOD_16APSK_8_9, | ||
| 97 | DVBFE_MODCOD_16APSK_9_10, | ||
| 98 | DVBFE_MODCOD_32APSK_3_4, | ||
| 99 | DVBFE_MODCOD_32APSK_4_5, | ||
| 100 | DVBFE_MODCOD_32APSK_5_6, | ||
| 101 | DVBFE_MODCOD_32APSK_8_9, | ||
| 102 | DVBFE_MODCOD_32APSK_9_10, | ||
| 103 | DVBFE_MODCOD_RESERVED_1, | ||
| 104 | DVBFE_MODCOD_BPSK_1_3, | ||
| 105 | DVBFE_MODCOD_BPSK_1_4, | ||
| 106 | DVBFE_MODCOD_RESERVED_2 | ||
| 107 | }; | ||
| 108 | |||
| 109 | enum tuner_param { | ||
| 110 | DVBFE_TUNER_FREQUENCY = (1 << 0), | ||
| 111 | DVBFE_TUNER_TUNERSTEP = (1 << 1), | ||
| 112 | DVBFE_TUNER_IFFREQ = (1 << 2), | ||
| 113 | DVBFE_TUNER_BANDWIDTH = (1 << 3), | ||
| 114 | DVBFE_TUNER_REFCLOCK = (1 << 4), | ||
| 115 | DVBFE_TUNER_IQSENSE = (1 << 5), | ||
| 116 | DVBFE_TUNER_DUMMY = (1 << 31) | ||
| 117 | }; | ||
| 118 | |||
| 119 | /* | ||
| 120 | * ALGO_HW: (Hardware Algorithm) | ||
| 121 | * ---------------------------------------------------------------- | ||
| 122 | * Devices that support this algorithm do everything in hardware | ||
| 123 | * and no software support is needed to handle them. | ||
| 124 | * Requesting these devices to LOCK is the only thing required, | ||
| 125 | * device is supposed to do everything in the hardware. | ||
| 126 | * | ||
| 127 | * ALGO_SW: (Software Algorithm) | ||
| 128 | * ---------------------------------------------------------------- | ||
| 129 | * These are dumb devices, that require software to do everything | ||
| 130 | * | ||
| 131 | * ALGO_CUSTOM: (Customizable Agorithm) | ||
| 132 | * ---------------------------------------------------------------- | ||
| 133 | * Devices having this algorithm can be customized to have specific | ||
| 134 | * algorithms in the frontend driver, rather than simply doing a | ||
| 135 | * software zig-zag. In this case the zigzag maybe hardware assisted | ||
| 136 | * or it maybe completely done in hardware. In all cases, usage of | ||
| 137 | * this algorithm, in conjunction with the search and track | ||
| 138 | * callbacks, utilizes the driver specific algorithm. | ||
| 139 | * | ||
| 140 | * ALGO_RECOVERY: (Recovery Algorithm) | ||
| 141 | * ---------------------------------------------------------------- | ||
| 142 | * These devices have AUTO recovery capabilities from LOCK failure | ||
| 143 | */ | ||
| 144 | enum dvbfe_algo { | ||
| 145 | DVBFE_ALGO_HW = (1 << 0), | ||
| 146 | DVBFE_ALGO_SW = (1 << 1), | ||
| 147 | DVBFE_ALGO_CUSTOM = (1 << 2), | ||
| 148 | DVBFE_ALGO_RECOVERY = (1 << 31) | ||
| 149 | }; | ||
| 150 | |||
| 151 | struct tuner_state { | ||
| 152 | u32 frequency; | ||
| 153 | u32 tunerstep; | ||
| 154 | u32 ifreq; | ||
| 155 | u32 bandwidth; | ||
| 156 | u32 iqsense; | ||
| 157 | u32 refclock; | ||
| 158 | }; | ||
| 159 | |||
| 160 | /* | ||
| 161 | * search callback possible return status | ||
| 162 | * | ||
| 163 | * DVBFE_ALGO_SEARCH_SUCCESS | ||
| 164 | * The frontend search algorithm completed and returned successfully | ||
| 165 | * | ||
| 166 | * DVBFE_ALGO_SEARCH_ASLEEP | ||
| 167 | * The frontend search algorithm is sleeping | ||
| 168 | * | ||
| 169 | * DVBFE_ALGO_SEARCH_FAILED | ||
| 170 | * The frontend search for a signal failed | ||
| 171 | * | ||
| 172 | * DVBFE_ALGO_SEARCH_INVALID | ||
| 173 | * The frontend search algorith was probably supplied with invalid | ||
| 174 | * parameters and the search is an invalid one | ||
| 175 | * | ||
| 176 | * DVBFE_ALGO_SEARCH_ERROR | ||
| 177 | * The frontend search algorithm failed due to some error | ||
| 178 | * | ||
| 179 | * DVBFE_ALGO_SEARCH_AGAIN | ||
| 180 | * The frontend search algorithm was requested to search again | ||
| 181 | */ | ||
| 182 | enum dvbfe_search { | ||
| 183 | DVBFE_ALGO_SEARCH_SUCCESS = (1 << 0), | ||
| 184 | DVBFE_ALGO_SEARCH_ASLEEP = (1 << 1), | ||
| 185 | DVBFE_ALGO_SEARCH_FAILED = (1 << 2), | ||
| 186 | DVBFE_ALGO_SEARCH_INVALID = (1 << 3), | ||
| 187 | DVBFE_ALGO_SEARCH_AGAIN = (1 << 4), | ||
| 188 | DVBFE_ALGO_SEARCH_ERROR = (1 << 31), | ||
| 189 | }; | ||
| 190 | |||
| 191 | |||
| 192 | struct dvb_tuner_ops { | ||
| 193 | |||
| 194 | struct dvb_tuner_info info; | ||
| 195 | |||
| 196 | int (*release)(struct dvb_frontend *fe); | ||
| 197 | int (*init)(struct dvb_frontend *fe); | ||
| 198 | int (*sleep)(struct dvb_frontend *fe); | ||
| 199 | |||
| 200 | /** This is for simple PLLs - set all parameters in one go. */ | ||
| 201 | int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); | ||
| 202 | int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p); | ||
| 203 | |||
| 204 | /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */ | ||
| 205 | int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len); | ||
| 206 | |||
| 207 | /** This is to allow setting tuner-specific configs */ | ||
| 208 | int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); | ||
| 209 | |||
| 210 | int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency); | ||
| 211 | int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); | ||
| 212 | |||
| 213 | #define TUNER_STATUS_LOCKED 1 | ||
| 214 | #define TUNER_STATUS_STEREO 2 | ||
| 215 | int (*get_status)(struct dvb_frontend *fe, u32 *status); | ||
| 216 | int (*get_rf_strength)(struct dvb_frontend *fe, u16 *strength); | ||
| 217 | |||
| 218 | /** These are provided separately from set_params in order to facilitate silicon | ||
| 219 | * tuners which require sophisticated tuning loops, controlling each parameter separately. */ | ||
| 220 | int (*set_frequency)(struct dvb_frontend *fe, u32 frequency); | ||
| 221 | int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); | ||
| 222 | |||
| 223 | /* | ||
| 224 | * These are provided separately from set_params in order to facilitate silicon | ||
| 225 | * tuners which require sophisticated tuning loops, controlling each parameter separately. | ||
| 226 | */ | ||
| 227 | int (*set_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state); | ||
| 228 | int (*get_state)(struct dvb_frontend *fe, enum tuner_param param, struct tuner_state *state); | ||
| 229 | }; | ||
| 230 | |||
| 231 | struct analog_demod_info { | ||
| 232 | char *name; | ||
| 233 | }; | ||
| 234 | |||
| 235 | struct analog_demod_ops { | ||
| 236 | |||
| 237 | struct analog_demod_info info; | ||
| 238 | |||
| 239 | void (*set_params)(struct dvb_frontend *fe, | ||
| 240 | struct analog_parameters *params); | ||
| 241 | int (*has_signal)(struct dvb_frontend *fe); | ||
| 242 | int (*get_afc)(struct dvb_frontend *fe); | ||
| 243 | void (*tuner_status)(struct dvb_frontend *fe); | ||
| 244 | void (*standby)(struct dvb_frontend *fe); | ||
| 245 | void (*release)(struct dvb_frontend *fe); | ||
| 246 | int (*i2c_gate_ctrl)(struct dvb_frontend *fe, int enable); | ||
| 247 | |||
| 248 | /** This is to allow setting tuner-specific configuration */ | ||
| 249 | int (*set_config)(struct dvb_frontend *fe, void *priv_cfg); | ||
| 250 | }; | ||
| 251 | |||
| 252 | struct dvb_frontend_ops { | ||
| 253 | |||
| 254 | struct dvb_frontend_info info; | ||
| 255 | |||
| 256 | void (*release)(struct dvb_frontend* fe); | ||
| 257 | void (*release_sec)(struct dvb_frontend* fe); | ||
| 258 | |||
| 259 | int (*init)(struct dvb_frontend* fe); | ||
| 260 | int (*sleep)(struct dvb_frontend* fe); | ||
| 261 | |||
| 262 | int (*write)(struct dvb_frontend* fe, const u8 buf[], int len); | ||
| 263 | |||
| 264 | /* if this is set, it overrides the default swzigzag */ | ||
| 265 | int (*tune)(struct dvb_frontend* fe, | ||
| 266 | struct dvb_frontend_parameters* params, | ||
| 267 | unsigned int mode_flags, | ||
| 268 | unsigned int *delay, | ||
| 269 | fe_status_t *status); | ||
| 270 | /* get frontend tuning algorithm from the module */ | ||
| 271 | enum dvbfe_algo (*get_frontend_algo)(struct dvb_frontend *fe); | ||
| 272 | |||
| 273 | /* these two are only used for the swzigzag code */ | ||
| 274 | int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); | ||
| 275 | int (*get_tune_settings)(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* settings); | ||
| 276 | |||
| 277 | int (*get_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); | ||
| 278 | |||
| 279 | int (*read_status)(struct dvb_frontend* fe, fe_status_t* status); | ||
| 280 | int (*read_ber)(struct dvb_frontend* fe, u32* ber); | ||
| 281 | int (*read_signal_strength)(struct dvb_frontend* fe, u16* strength); | ||
| 282 | int (*read_snr)(struct dvb_frontend* fe, u16* snr); | ||
| 283 | int (*read_ucblocks)(struct dvb_frontend* fe, u32* ucblocks); | ||
| 284 | |||
| 285 | int (*diseqc_reset_overload)(struct dvb_frontend* fe); | ||
| 286 | int (*diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd); | ||
| 287 | int (*diseqc_recv_slave_reply)(struct dvb_frontend* fe, struct dvb_diseqc_slave_reply* reply); | ||
| 288 | int (*diseqc_send_burst)(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd); | ||
| 289 | int (*set_tone)(struct dvb_frontend* fe, fe_sec_tone_mode_t tone); | ||
| 290 | int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage); | ||
| 291 | int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg); | ||
| 292 | int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); | ||
| 293 | int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable); | ||
| 294 | int (*ts_bus_ctrl)(struct dvb_frontend* fe, int acquire); | ||
| 295 | |||
| 296 | /* These callbacks are for devices that implement their own | ||
| 297 | * tuning algorithms, rather than a simple swzigzag | ||
| 298 | */ | ||
| 299 | enum dvbfe_search (*search)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); | ||
| 300 | int (*track)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); | ||
| 301 | |||
| 302 | struct dvb_tuner_ops tuner_ops; | ||
| 303 | struct analog_demod_ops analog_ops; | ||
| 304 | |||
| 305 | int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp); | ||
| 306 | int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp); | ||
| 307 | }; | ||
| 308 | |||
| 309 | #define MAX_EVENT 8 | ||
| 310 | |||
| 311 | struct dvb_fe_events { | ||
| 312 | struct dvb_frontend_event events[MAX_EVENT]; | ||
| 313 | int eventw; | ||
| 314 | int eventr; | ||
| 315 | int overflow; | ||
| 316 | wait_queue_head_t wait_queue; | ||
| 317 | struct mutex mtx; | ||
| 318 | }; | ||
| 319 | |||
| 320 | struct dtv_frontend_properties { | ||
| 321 | |||
| 322 | /* Cache State */ | ||
| 323 | u32 state; | ||
| 324 | |||
| 325 | u32 frequency; | ||
| 326 | fe_modulation_t modulation; | ||
| 327 | |||
| 328 | fe_sec_voltage_t voltage; | ||
| 329 | fe_sec_tone_mode_t sectone; | ||
| 330 | fe_spectral_inversion_t inversion; | ||
| 331 | fe_code_rate_t fec_inner; | ||
| 332 | fe_transmit_mode_t transmission_mode; | ||
| 333 | u32 bandwidth_hz; /* 0 = AUTO */ | ||
| 334 | fe_guard_interval_t guard_interval; | ||
| 335 | fe_hierarchy_t hierarchy; | ||
| 336 | u32 symbol_rate; | ||
| 337 | fe_code_rate_t code_rate_HP; | ||
| 338 | fe_code_rate_t code_rate_LP; | ||
| 339 | |||
| 340 | fe_pilot_t pilot; | ||
| 341 | fe_rolloff_t rolloff; | ||
| 342 | |||
| 343 | fe_delivery_system_t delivery_system; | ||
| 344 | |||
| 345 | /* ISDB-T specifics */ | ||
| 346 | u8 isdbt_partial_reception; | ||
| 347 | u8 isdbt_sb_mode; | ||
| 348 | u8 isdbt_sb_subchannel; | ||
| 349 | u32 isdbt_sb_segment_idx; | ||
| 350 | u32 isdbt_sb_segment_count; | ||
| 351 | u8 isdbt_layer_enabled; | ||
| 352 | struct { | ||
| 353 | u8 segment_count; | ||
| 354 | fe_code_rate_t fec; | ||
| 355 | fe_modulation_t modulation; | ||
| 356 | u8 interleaving; | ||
| 357 | } layer[3]; | ||
| 358 | |||
| 359 | /* ISDB-T specifics */ | ||
| 360 | u32 isdbs_ts_id; | ||
| 361 | |||
| 362 | /* DVB-T2 specifics */ | ||
| 363 | u32 dvbt2_plp_id; | ||
| 364 | }; | ||
| 365 | |||
| 366 | struct dvb_frontend { | ||
| 367 | struct dvb_frontend_ops ops; | ||
| 368 | struct dvb_adapter *dvb; | ||
| 369 | void *demodulator_priv; | ||
| 370 | void *tuner_priv; | ||
| 371 | void *frontend_priv; | ||
| 372 | void *sec_priv; | ||
| 373 | void *analog_demod_priv; | ||
| 374 | struct dtv_frontend_properties dtv_property_cache; | ||
| 375 | #define DVB_FRONTEND_COMPONENT_TUNER 0 | ||
| 376 | int (*callback)(void *adapter_priv, int component, int cmd, int arg); | ||
| 377 | int id; | ||
| 378 | }; | ||
| 379 | |||
| 380 | extern int dvb_register_frontend(struct dvb_adapter *dvb, | ||
| 381 | struct dvb_frontend *fe); | ||
| 382 | |||
| 383 | extern int dvb_unregister_frontend(struct dvb_frontend *fe); | ||
| 384 | |||
| 385 | extern void dvb_frontend_detach(struct dvb_frontend *fe); | ||
| 386 | |||
| 387 | extern void dvb_frontend_reinitialise(struct dvb_frontend *fe); | ||
| 388 | |||
| 389 | extern void dvb_frontend_sleep_until(struct timeval *waketime, u32 add_usec); | ||
| 390 | extern s32 timeval_usec_diff(struct timeval lasttime, struct timeval curtime); | ||
| 391 | |||
| 392 | #endif | ||
diff --git a/drivers/media/dvb/dvb-core/dvb_math.c b/drivers/media/dvb/dvb-core/dvb_math.c new file mode 100644 index 00000000000..beb7c93aa6c --- /dev/null +++ b/drivers/media/dvb/dvb-core/dvb_math.c | |||
| @@ -0,0 +1,145 @@ | |||
| 1 | /* | ||
| 2 | * dvb-math provides some complex fixed-point math | ||
| 3 | * operations shared between the dvb related stuff | ||
| 4 | * | ||
| 5 | * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com) | ||
| 6 | * | ||
| 7 | * This library is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU Lesser General Public License as | ||
| 9 | * published by the Free Software Foundation; either version 2.1 of | ||
| 10 | * the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public | ||
| 18 | * License along with this library; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #include <linux/bitops.h> | ||
| 23 | #include <linux/kernel.h> | ||
| 24 | #include <linux/module.h> | ||
| 25 | #include <asm/bug.h> | ||
| 26 | #include "dvb_math.h" | ||
| 27 | |||
| 28 | static const unsigned short logtable[256] = { | ||
| 29 | 0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7, | ||
| 30 | 0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508, | ||
| 31 | 0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6, | ||
| 32 | 0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37, | ||
| 33 | 0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f, | ||
| 34 | 0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41, | ||
| 35 | 0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1, | ||
| 36 | 0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142, | ||
| 37 | 0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68, | ||
| 38 | 0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355, | ||
| 39 | 0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c, | ||
| 40 | 0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490, | ||
| 41 | 0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3, | ||
| 42 | 0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507, | ||
| 43 | 0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe, | ||
| 44 | 0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca, | ||
| 45 | 0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c, | ||
| 46 | 0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7, | ||
| 47 | 0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c, | ||
| 48 | 0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c, | ||
| 49 | 0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a, | ||
| 50 | 0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065, | ||
| 51 | 0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730, | ||
| 52 | 0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc, | ||
| 53 | 0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469, | ||
| 54 | 0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9, | ||
| 55 | 0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c, | ||
| 56 | 0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765, | ||
| 57 | 0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83, | ||
| 58 | 0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387, | ||
| 59 | 0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973, | ||
| 60 | 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47 | ||
| 61 | }; | ||
| 62 | |||
| 63 | unsigned int intlog2(u32 value) | ||
| 64 | { | ||
| 65 | /** | ||
| 66 | * returns: log2(value) * 2^24 | ||
| 67 | * wrong result if value = 0 (log2(0) is undefined) | ||
| 68 | */ | ||
| 69 | unsigned int msb; | ||
| 70 | unsigned int logentry; | ||
| 71 | unsigned int significand; | ||
| 72 | unsigned int interpolation; | ||
| 73 | |||
| 74 | if (unlikely(value == 0)) { | ||
| 75 | WARN_ON(1); | ||
| 76 | return 0; | ||
| 77 | } | ||
| 78 | |||
| 79 | /* first detect the msb (count begins at 0) */ | ||
| 80 | msb = fls(value) - 1; | ||
| 81 | |||
| 82 | /** | ||
| 83 | * now we use a logtable after the following method: | ||
| 84 | * | ||
| 85 | * log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24 | ||
| 86 | * where x = msb and therefore 1 <= y < 2 | ||
| 87 | * first y is determined by shifting the value left | ||
| 88 | * so that msb is bit 31 | ||
| 89 | * 0x00231f56 -> 0x8C7D5800 | ||
| 90 | * the result is y * 2^31 -> "significand" | ||
| 91 | * then the highest 9 bits are used for a table lookup | ||
| 92 | * the highest bit is discarded because it's always set | ||
| 93 | * the highest nine bits in our example are 100011000 | ||
| 94 | * so we would use the entry 0x18 | ||
| 95 | */ | ||
| 96 | significand = value << (31 - msb); | ||
| 97 | logentry = (significand >> 23) & 0xff; | ||
| 98 | |||
| 99 | /** | ||
| 100 | * last step we do is interpolation because of the | ||
| 101 | * limitations of the log table the error is that part of | ||
| 102 | * the significand which isn't used for lookup then we | ||
| 103 | * compute the ratio between the error and the next table entry | ||
| 104 | * and interpolate it between the log table entry used and the | ||
| 105 | * next one the biggest error possible is 0x7fffff | ||
| 106 | * (in our example it's 0x7D5800) | ||
| 107 | * needed value for next table entry is 0x800000 | ||
| 108 | * so the interpolation is | ||
| 109 | * (error / 0x800000) * (logtable_next - logtable_current) | ||
| 110 | * in the implementation the division is moved to the end for | ||
| 111 | * better accuracy there is also an overflow correction if | ||
| 112 | * logtable_next is 256 | ||
| 113 | */ | ||
| 114 | interpolation = ((significand & 0x7fffff) * | ||
| 115 | ((logtable[(logentry + 1) & 0xff] - | ||
| 116 | logtable[logentry]) & 0xffff)) >> 15; | ||
| 117 | |||
| 118 | /* now we return the result */ | ||
| 119 | return ((msb << 24) + (logtable[logentry] << 8) + interpolation); | ||
| 120 | } | ||
| 121 | EXPORT_SYMBOL(intlog2); | ||
| 122 | |||
| 123 | unsigned int intlog10(u32 value) | ||
| 124 | { | ||
| 125 | /** | ||
| 126 | * returns: log10(value) * 2^24 | ||
| 127 | * wrong result if value = 0 (log10(0) is undefined) | ||
| 128 | */ | ||
| 129 | u64 log; | ||
| 130 | |||
| 131 | if (unlikely(value == 0)) { | ||
| 132 | WARN_ON(1); | ||
| 133 | return 0; | ||
| 134 | } | ||
| 135 | |||
| 136 | log = intlog2(value); | ||
| 137 | |||
| 138 | /** | ||
| 139 | * we use the following method: | ||
| 140 | * log10(x) = log2(x) * log10(2) | ||
| 141 | */ | ||
| 142 | |||
| 143 | return (log * 646456993) >> 31; | ||
| 144 | } | ||
| 145 | EXPORT_SYMBOL(intlog10); | ||
diff --git a/drivers/media/dvb/dvb-core/dvb_math.h b/drivers/media/dvb/dvb-core/dvb_math.h new file mode 100644 index 00000000000..aecc867e940 --- /dev/null +++ b/drivers/media/dvb/dvb-core/dvb_math.h | |||
| @@ -0,0 +1,58 @@ | |||
| 1 | /* | ||
| 2 | * dvb-math provides some complex fixed-point math | ||
| 3 | * operations shared between the dvb related stuff | ||
| 4 | * | ||
| 5 | * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com) | ||
| 6 | * | ||
| 7 | * This library is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU Lesser General Public License as | ||
| 9 | * published by the Free Software Foundation; either version 2.1 of | ||
| 10 | * the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU Lesser General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public | ||
| 18 | * License along with this library; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 20 | */ | ||
| 21 | |||
| 22 | #ifndef __DVB_MATH_H | ||
| 23 | #define __DVB_MATH_H | ||
| 24 | |||
| 25 | #include <linux/types.h> | ||
| 26 | |||
| 27 | /** | ||
| 28 | * computes log2 of a value; the result is shifted left by 24 bits | ||
| 29 | * | ||
| 30 | * to use rational values you can use the following method: | ||
| 31 | * intlog2(value) = intlog2(value * 2^x) - x * 2^24 | ||
| 32 | * | ||
| 33 | * example: intlog2(8) will give 3 << 24 = 3 * 2^24 | ||
| 34 | * example: intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24 | ||
| 35 | * example: intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24 | ||
| 36 | * | ||
| 37 | * @param value The value (must be != 0) | ||
| 38 | * @return log2(value) * 2^24 | ||
| 39 | */ | ||
| 40 | extern unsigned int intlog2(u32 value); | ||
| 41 | |||
| 42 | /** | ||
| 43 | * computes log10 of a value; the result is shifted left by 24 bits | ||
| 44 | * | ||
| 45 | * to use rational values you can use the following method: | ||
| 46 | * intlog10(value) = intlog10(value * 10^x) - x * 2^24 | ||
| 47 | * | ||
| 48 | * example: intlog10(1000) will give 3 << 24 = 3 * 2^24 | ||
| 49 | * due to the implementation intlog10(1000) might be not exactly 3 * 2^24 | ||
| 50 | * | ||
| 51 | * look at intlog2 for similar examples | ||
| 52 | * | ||
| 53 | * @param value The value (must be != 0) | ||
| 54 | * @return log10(value) * 2^24 | ||
| 55 | */ | ||
| 56 | extern unsigned int intlog10(u32 value); | ||
| 57 | |||
| 58 | #endif | ||
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c new file mode 100644 index 00000000000..51752a9ef7a --- /dev/null +++ b/drivers/media/dvb/dvb-core/dvb_net.c | |||
| @@ -0,0 +1,1518 @@ | |||
| 1 | /* | ||
| 2 | * dvb_net.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2001 Convergence integrated media GmbH | ||
| 5 | * Ralph Metzler <ralph@convergence.de> | ||
| 6 | * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de> | ||
| 7 | * | ||
| 8 | * ULE Decapsulation code: | ||
| 9 | * Copyright (C) 2003, 2004 gcs - Global Communication & Services GmbH. | ||
| 10 | * and Department of Scientific Computing | ||
| 11 | * Paris Lodron University of Salzburg. | ||
| 12 | * Hilmar Linder <hlinder@cosy.sbg.ac.at> | ||
| 13 | * and Wolfram Stering <wstering@cosy.sbg.ac.at> | ||
| 14 | * | ||
| 15 | * ULE Decaps according to RFC 4326. | ||
| 16 | * | ||
| 17 | * This program is free software; you can redistribute it and/or | ||
| 18 | * modify it under the terms of the GNU General Public License | ||
| 19 | * as published by the Free Software Foundation; either version 2 | ||
| 20 | * of the License, or (at your option) any later version. | ||
| 21 | * | ||
| 22 | * This program is distributed in the hope that it will be useful, | ||
| 23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 25 | * GNU General Public License for more details. | ||
| 26 | * | ||
| 27 | * You should have received a copy of the GNU General Public License | ||
| 28 | * along with this program; if not, write to the Free Software | ||
| 29 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 30 | * Or, point your browser to http://www.gnu.org/copyleft/gpl.html | ||
| 31 | */ | ||
| 32 | |||
| 33 | /* | ||
| 34 | * ULE ChangeLog: | ||
| 35 | * Feb 2004: hl/ws v1: Implementing draft-fair-ipdvb-ule-01.txt | ||
| 36 | * | ||
| 37 | * Dec 2004: hl/ws v2: Implementing draft-ietf-ipdvb-ule-03.txt: | ||
| 38 | * ULE Extension header handling. | ||
| 39 | * Bugreports by Moritz Vieth and Hanno Tersteegen, | ||
| 40 | * Fraunhofer Institute for Open Communication Systems | ||
| 41 | * Competence Center for Advanced Satellite Communications. | ||
| 42 | * Bugfixes and robustness improvements. | ||
| 43 | * Filtering on dest MAC addresses, if present (D-Bit = 0) | ||
| 44 | * ULE_DEBUG compile-time option. | ||
| 45 | * Apr 2006: cp v3: Bugfixes and compliency with RFC 4326 (ULE) by | ||
| 46 | * Christian Praehauser <cpraehaus@cosy.sbg.ac.at>, | ||
| 47 | * Paris Lodron University of Salzburg. | ||
| 48 | */ | ||
| 49 | |||
| 50 | /* | ||
| 51 | * FIXME / TODO (dvb_net.c): | ||
| 52 | * | ||
| 53 | * Unloading does not work for 2.6.9 kernels: a refcount doesn't go to zero. | ||
| 54 | * | ||
| 55 | */ | ||
| 56 | |||
| 57 | #include <linux/module.h> | ||
| 58 | #include <linux/kernel.h> | ||
| 59 | #include <linux/netdevice.h> | ||
| 60 | #include <linux/etherdevice.h> | ||
| 61 | #include <linux/dvb/net.h> | ||
| 62 | #include <linux/uio.h> | ||
| 63 | #include <asm/uaccess.h> | ||
| 64 | #include <linux/crc32.h> | ||
| 65 | #include <linux/mutex.h> | ||
| 66 | #include <linux/sched.h> | ||
| 67 | |||
| 68 | #include "dvb_demux.h" | ||
| 69 | #include "dvb_net.h" | ||
| 70 | |||
| 71 | static int dvb_net_debug; | ||
| 72 | module_param(dvb_net_debug, int, 0444); | ||
| 73 | MODULE_PARM_DESC(dvb_net_debug, "enable debug messages"); | ||
| 74 | |||
| 75 | #define dprintk(x...) do { if (dvb_net_debug) printk(x); } while (0) | ||
| 76 | |||
| 77 | |||
| 78 | static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt ) | ||
| 79 | { | ||
| 80 | unsigned int j; | ||
| 81 | for (j = 0; j < cnt; j++) | ||
| 82 | c = crc32_be( c, iov[j].iov_base, iov[j].iov_len ); | ||
| 83 | return c; | ||
| 84 | } | ||
| 85 | |||
| 86 | |||
| 87 | #define DVB_NET_MULTICAST_MAX 10 | ||
| 88 | |||
| 89 | #undef ULE_DEBUG | ||
| 90 | |||
| 91 | #ifdef ULE_DEBUG | ||
| 92 | |||
| 93 | #define MAC_ADDR_PRINTFMT "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" | ||
| 94 | #define MAX_ADDR_PRINTFMT_ARGS(macap) (macap)[0],(macap)[1],(macap)[2],(macap)[3],(macap)[4],(macap)[5] | ||
| 95 | |||
| 96 | #define isprint(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) | ||
| 97 | |||
| 98 | static void hexdump( const unsigned char *buf, unsigned short len ) | ||
| 99 | { | ||
| 100 | char str[80], octet[10]; | ||
| 101 | int ofs, i, l; | ||
| 102 | |||
| 103 | for (ofs = 0; ofs < len; ofs += 16) { | ||
| 104 | sprintf( str, "%03d: ", ofs ); | ||
| 105 | |||
| 106 | for (i = 0; i < 16; i++) { | ||
| 107 | if ((i + ofs) < len) | ||
| 108 | sprintf( octet, "%02x ", buf[ofs + i] ); | ||
| 109 | else | ||
| 110 | strcpy( octet, " " ); | ||
| 111 | |||
| 112 | strcat( str, octet ); | ||
| 113 | } | ||
| 114 | strcat( str, " " ); | ||
| 115 | l = strlen( str ); | ||
| 116 | |||
| 117 | for (i = 0; (i < 16) && ((i + ofs) < len); i++) | ||
| 118 | str[l++] = isprint( buf[ofs + i] ) ? buf[ofs + i] : '.'; | ||
| 119 | |||
| 120 | str[l] = '\0'; | ||
| 121 | printk( KERN_WARNING "%s\n", str ); | ||
| 122 | } | ||
| 123 | } | ||
| 124 | |||
| 125 | #endif | ||
| 126 | |||
| 127 | struct dvb_net_priv { | ||
| 128 | int in_use; | ||
| 129 | u16 pid; | ||
| 130 | struct net_device *net; | ||
| 131 | struct dvb_net *host; | ||
| 132 | struct dmx_demux *demux; | ||
| 133 | struct dmx_section_feed *secfeed; | ||
| 134 | struct dmx_section_filter *secfilter; | ||
| 135 | struct dmx_ts_feed *tsfeed; | ||
| 136 | int multi_num; | ||
| 137 | struct dmx_section_filter *multi_secfilter[DVB_NET_MULTICAST_MAX]; | ||
| 138 | unsigned char multi_macs[DVB_NET_MULTICAST_MAX][6]; | ||
| 139 | int rx_mode; | ||
| 140 | #define RX_MODE_UNI 0 | ||
| 141 | #define RX_MODE_MULTI 1 | ||
| 142 | #define RX_MODE_ALL_MULTI 2 | ||
| 143 | #define RX_MODE_PROMISC 3 | ||
| 144 | struct work_struct set_multicast_list_wq; | ||
| 145 | struct work_struct restart_net_feed_wq; | ||
| 146 | unsigned char feedtype; /* Either FEED_TYPE_ or FEED_TYPE_ULE */ | ||
| 147 | int need_pusi; /* Set to 1, if synchronization on PUSI required. */ | ||
| 148 | unsigned char tscc; /* TS continuity counter after sync on PUSI. */ | ||
| 149 | struct sk_buff *ule_skb; /* ULE SNDU decodes into this buffer. */ | ||
| 150 | unsigned char *ule_next_hdr; /* Pointer into skb to next ULE extension header. */ | ||
| 151 | unsigned short ule_sndu_len; /* ULE SNDU length in bytes, w/o D-Bit. */ | ||
| 152 | unsigned short ule_sndu_type; /* ULE SNDU type field, complete. */ | ||
| 153 | unsigned char ule_sndu_type_1; /* ULE SNDU type field, if split across 2 TS cells. */ | ||
| 154 | unsigned char ule_dbit; /* Whether the DestMAC address present | ||
| 155 | * or not (bit is set). */ | ||
| 156 | unsigned char ule_bridged; /* Whether the ULE_BRIDGED extension header was found. */ | ||
| 157 | int ule_sndu_remain; /* Nr. of bytes still required for current ULE SNDU. */ | ||
| 158 | unsigned long ts_count; /* Current ts cell counter. */ | ||
| 159 | struct mutex mutex; | ||
| 160 | }; | ||
| 161 | |||
| 162 | |||
| 163 | /** | ||
| 164 | * Determine the packet's protocol ID. The rule here is that we | ||
| 165 | * assume 802.3 if the type field is short enough to be a length. | ||
| 166 | * This is normal practice and works for any 'now in use' protocol. | ||
| 167 | * | ||
| 168 | * stolen from eth.c out of the linux kernel, hacked for dvb-device | ||
| 169 | * by Michael Holzt <kju@debian.org> | ||
| 170 | */ | ||
| 171 | static __be16 dvb_net_eth_type_trans(struct sk_buff *skb, | ||
| 172 | struct net_device *dev) | ||
| 173 | { | ||
| 174 | struct ethhdr *eth; | ||
| 175 | unsigned char *rawp; | ||
| 176 | |||
| 177 | skb_reset_mac_header(skb); | ||
| 178 | skb_pull(skb,dev->hard_header_len); | ||
| 179 | eth = eth_hdr(skb); | ||
| 180 | |||
| 181 | if (*eth->h_dest & 1) { | ||
| 182 | if(memcmp(eth->h_dest,dev->broadcast, ETH_ALEN)==0) | ||
| 183 | skb->pkt_type=PACKET_BROADCAST; | ||
| 184 | else | ||
| 185 | skb->pkt_type=PACKET_MULTICAST; | ||
| 186 | } | ||
| 187 | |||
| 188 | if (ntohs(eth->h_proto) >= 1536) | ||
| 189 | return eth->h_proto; | ||
| 190 | |||
| 191 | rawp = skb->data; | ||
| 192 | |||
| 193 | /** | ||
| 194 | * This is a magic hack to spot IPX packets. Older Novell breaks | ||
| 195 | * the protocol design and runs IPX over 802.3 without an 802.2 LLC | ||
| 196 | * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This | ||
| 197 | * won't work for fault tolerant netware but does for the rest. | ||
| 198 | */ | ||
| 199 | if (*(unsigned short *)rawp == 0xFFFF) | ||
| 200 | return htons(ETH_P_802_3); | ||
| 201 | |||
| 202 | /** | ||
| 203 | * Real 802.2 LLC | ||
| 204 | */ | ||
| 205 | return htons(ETH_P_802_2); | ||
| 206 | } | ||
| 207 | |||
| 208 | #define TS_SZ 188 | ||
| 209 | #define TS_SYNC 0x47 | ||
| 210 | #define TS_TEI 0x80 | ||
| 211 | #define TS_SC 0xC0 | ||
| 212 | #define TS_PUSI 0x40 | ||
| 213 | #define TS_AF_A 0x20 | ||
| 214 | #define TS_AF_D 0x10 | ||
| 215 | |||
| 216 | /* ULE Extension Header handlers. */ | ||
| 217 | |||
| 218 | #define ULE_TEST 0 | ||
| 219 | #define ULE_BRIDGED 1 | ||
| 220 | |||
| 221 | #define ULE_OPTEXTHDR_PADDING 0 | ||
| 222 | |||
| 223 | static int ule_test_sndu( struct dvb_net_priv *p ) | ||
| 224 | { | ||
| 225 | return -1; | ||
| 226 | } | ||
| 227 | |||
| 228 | static int ule_bridged_sndu( struct dvb_net_priv *p ) | ||
| 229 | { | ||
| 230 | struct ethhdr *hdr = (struct ethhdr*) p->ule_next_hdr; | ||
| 231 | if(ntohs(hdr->h_proto) < 1536) { | ||
| 232 | int framelen = p->ule_sndu_len - ((p->ule_next_hdr+sizeof(struct ethhdr)) - p->ule_skb->data); | ||
| 233 | /* A frame Type < 1536 for a bridged frame, introduces a LLC Length field. */ | ||
| 234 | if(framelen != ntohs(hdr->h_proto)) { | ||
| 235 | return -1; | ||
| 236 | } | ||
| 237 | } | ||
| 238 | /* Note: | ||
| 239 | * From RFC4326: | ||
| 240 | * "A bridged SNDU is a Mandatory Extension Header of Type 1. | ||
| 241 | * It must be the final (or only) extension header specified in the header chain of a SNDU." | ||
| 242 | * The 'ule_bridged' flag will cause the extension header processing loop to terminate. | ||
| 243 | */ | ||
| 244 | p->ule_bridged = 1; | ||
| 245 | return 0; | ||
| 246 | } | ||
| 247 | |||
| 248 | static int ule_exthdr_padding(struct dvb_net_priv *p) | ||
| 249 | { | ||
| 250 | return 0; | ||
| 251 | } | ||
| 252 | |||
| 253 | /** Handle ULE extension headers. | ||
| 254 | * Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding. | ||
| 255 | * Returns: >= 0: nr. of bytes consumed by next extension header | ||
| 256 | * -1: Mandatory extension header that is not recognized or TEST SNDU; discard. | ||
| 257 | */ | ||
| 258 | static int handle_one_ule_extension( struct dvb_net_priv *p ) | ||
| 259 | { | ||
| 260 | /* Table of mandatory extension header handlers. The header type is the index. */ | ||
| 261 | static int (*ule_mandatory_ext_handlers[255])( struct dvb_net_priv *p ) = | ||
| 262 | { [0] = ule_test_sndu, [1] = ule_bridged_sndu, [2] = NULL, }; | ||
| 263 | |||
| 264 | /* Table of optional extension header handlers. The header type is the index. */ | ||
| 265 | static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) = | ||
| 266 | { [0] = ule_exthdr_padding, [1] = NULL, }; | ||
| 267 | |||
| 268 | int ext_len = 0; | ||
| 269 | unsigned char hlen = (p->ule_sndu_type & 0x0700) >> 8; | ||
| 270 | unsigned char htype = p->ule_sndu_type & 0x00FF; | ||
| 271 | |||
| 272 | /* Discriminate mandatory and optional extension headers. */ | ||
| 273 | if (hlen == 0) { | ||
| 274 | /* Mandatory extension header */ | ||
| 275 | if (ule_mandatory_ext_handlers[htype]) { | ||
| 276 | ext_len = ule_mandatory_ext_handlers[htype]( p ); | ||
| 277 | if(ext_len >= 0) { | ||
| 278 | p->ule_next_hdr += ext_len; | ||
| 279 | if (!p->ule_bridged) { | ||
| 280 | p->ule_sndu_type = ntohs(*(__be16 *)p->ule_next_hdr); | ||
| 281 | p->ule_next_hdr += 2; | ||
| 282 | } else { | ||
| 283 | p->ule_sndu_type = ntohs(*(__be16 *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN))); | ||
| 284 | /* This assures the extension handling loop will terminate. */ | ||
| 285 | } | ||
| 286 | } | ||
| 287 | // else: extension handler failed or SNDU should be discarded | ||
| 288 | } else | ||
| 289 | ext_len = -1; /* SNDU has to be discarded. */ | ||
| 290 | } else { | ||
| 291 | /* Optional extension header. Calculate the length. */ | ||
| 292 | ext_len = hlen << 1; | ||
| 293 | /* Process the optional extension header according to its type. */ | ||
| 294 | if (ule_optional_ext_handlers[htype]) | ||
| 295 | (void)ule_optional_ext_handlers[htype]( p ); | ||
| 296 | p->ule_next_hdr += ext_len; | ||
| 297 | p->ule_sndu_type = ntohs( *(__be16 *)(p->ule_next_hdr-2) ); | ||
| 298 | /* | ||
| 299 | * note: the length of the next header type is included in the | ||
| 300 | * length of THIS optional extension header | ||
| 301 | */ | ||
| 302 | } | ||
| 303 | |||
| 304 | return ext_len; | ||
| 305 | } | ||
| 306 | |||
| 307 | static int handle_ule_extensions( struct dvb_net_priv *p ) | ||
| 308 | { | ||
| 309 | int total_ext_len = 0, l; | ||
| 310 | |||
| 311 | p->ule_next_hdr = p->ule_skb->data; | ||
| 312 | do { | ||
| 313 | l = handle_one_ule_extension( p ); | ||
| 314 | if (l < 0) | ||
| 315 | return l; /* Stop extension header processing and discard SNDU. */ | ||
| 316 | total_ext_len += l; | ||
| 317 | #ifdef ULE_DEBUG | ||
| 318 | dprintk("handle_ule_extensions: ule_next_hdr=%p, ule_sndu_type=%i, " | ||
| 319 | "l=%i, total_ext_len=%i\n", p->ule_next_hdr, | ||
| 320 | (int) p->ule_sndu_type, l, total_ext_len); | ||
| 321 | #endif | ||
| 322 | |||
| 323 | } while (p->ule_sndu_type < 1536); | ||
| 324 | |||
| 325 | return total_ext_len; | ||
| 326 | } | ||
| 327 | |||
| 328 | |||
| 329 | /** Prepare for a new ULE SNDU: reset the decoder state. */ | ||
| 330 | static inline void reset_ule( struct dvb_net_priv *p ) | ||
| 331 | { | ||
| 332 | p->ule_skb = NULL; | ||
| 333 | p->ule_next_hdr = NULL; | ||
| 334 | p->ule_sndu_len = 0; | ||
| 335 | p->ule_sndu_type = 0; | ||
| 336 | p->ule_sndu_type_1 = 0; | ||
| 337 | p->ule_sndu_remain = 0; | ||
| 338 | p->ule_dbit = 0xFF; | ||
| 339 | p->ule_bridged = 0; | ||
| 340 | } | ||
| 341 | |||
| 342 | /** | ||
| 343 | * Decode ULE SNDUs according to draft-ietf-ipdvb-ule-03.txt from a sequence of | ||
| 344 | * TS cells of a single PID. | ||
| 345 | */ | ||
| 346 | static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) | ||
| 347 | { | ||
| 348 | struct dvb_net_priv *priv = netdev_priv(dev); | ||
| 349 | unsigned long skipped = 0L; | ||
| 350 | const u8 *ts, *ts_end, *from_where = NULL; | ||
| 351 | u8 ts_remain = 0, how_much = 0, new_ts = 1; | ||
| 352 | struct ethhdr *ethh = NULL; | ||
| 353 | bool error = false; | ||
| 354 | |||
| 355 | #ifdef ULE_DEBUG | ||
| 356 | /* The code inside ULE_DEBUG keeps a history of the last 100 TS cells processed. */ | ||
| 357 | static unsigned char ule_hist[100*TS_SZ]; | ||
| 358 | static unsigned char *ule_where = ule_hist, ule_dump; | ||
| 359 | #endif | ||
| 360 | |||
| 361 | /* For all TS cells in current buffer. | ||
| 362 | * Appearently, we are called for every single TS cell. | ||
| 363 | */ | ||
| 364 | for (ts = buf, ts_end = buf + buf_len; ts < ts_end; /* no default incr. */ ) { | ||
| 365 | |||
| 366 | if (new_ts) { | ||
| 367 | /* We are about to process a new TS cell. */ | ||
| 368 | |||
| 369 | #ifdef ULE_DEBUG | ||
| 370 | if (ule_where >= &ule_hist[100*TS_SZ]) ule_where = ule_hist; | ||
| 371 | memcpy( ule_where, ts, TS_SZ ); | ||
| 372 | if (ule_dump) { | ||
| 373 | hexdump( ule_where, TS_SZ ); | ||
| 374 | ule_dump = 0; | ||
| 375 | } | ||
| 376 | ule_where += TS_SZ; | ||
| 377 | #endif | ||
| 378 | |||
| 379 | /* Check TS error conditions: sync_byte, transport_error_indicator, scrambling_control . */ | ||
| 380 | if ((ts[0] != TS_SYNC) || (ts[1] & TS_TEI) || ((ts[3] & TS_SC) != 0)) { | ||
| 381 | printk(KERN_WARNING "%lu: Invalid TS cell: SYNC %#x, TEI %u, SC %#x.\n", | ||
| 382 | priv->ts_count, ts[0], ts[1] & TS_TEI >> 7, ts[3] & 0xC0 >> 6); | ||
| 383 | |||
| 384 | /* Drop partly decoded SNDU, reset state, resync on PUSI. */ | ||
| 385 | if (priv->ule_skb) { | ||
| 386 | dev_kfree_skb( priv->ule_skb ); | ||
| 387 | /* Prepare for next SNDU. */ | ||
| 388 | dev->stats.rx_errors++; | ||
| 389 | dev->stats.rx_frame_errors++; | ||
| 390 | } | ||
| 391 | reset_ule(priv); | ||
| 392 | priv->need_pusi = 1; | ||
| 393 | |||
| 394 | /* Continue with next TS cell. */ | ||
| 395 | ts += TS_SZ; | ||
| 396 | priv->ts_count++; | ||
| 397 | continue; | ||
| 398 | } | ||
| 399 | |||
| 400 | ts_remain = 184; | ||
| 401 | from_where = ts + 4; | ||
| 402 | } | ||
| 403 | /* Synchronize on PUSI, if required. */ | ||
| 404 | if (priv->need_pusi) { | ||
| 405 | if (ts[1] & TS_PUSI) { | ||
| 406 | /* Find beginning of first ULE SNDU in current TS cell. */ | ||
| 407 | /* Synchronize continuity counter. */ | ||
| 408 | priv->tscc = ts[3] & 0x0F; | ||
| 409 | /* There is a pointer field here. */ | ||
| 410 | if (ts[4] > ts_remain) { | ||
| 411 | printk(KERN_ERR "%lu: Invalid ULE packet " | ||
| 412 | "(pointer field %d)\n", priv->ts_count, ts[4]); | ||
| 413 | ts += TS_SZ; | ||
| 414 | priv->ts_count++; | ||
| 415 | continue; | ||
| 416 | } | ||
| 417 | /* Skip to destination of pointer field. */ | ||
| 418 | from_where = &ts[5] + ts[4]; | ||
| 419 | ts_remain -= 1 + ts[4]; | ||
| 420 | skipped = 0; | ||
| 421 | } else { | ||
| 422 | skipped++; | ||
| 423 | ts += TS_SZ; | ||
| 424 | priv->ts_count++; | ||
| 425 | continue; | ||
| 426 | } | ||
| 427 | } | ||
| 428 | |||
| 429 | if (new_ts) { | ||
| 430 | /* Check continuity counter. */ | ||
| 431 | if ((ts[3] & 0x0F) == priv->tscc) | ||
| 432 | priv->tscc = (priv->tscc + 1) & 0x0F; | ||
| 433 | else { | ||
| 434 | /* TS discontinuity handling: */ | ||
| 435 | printk(KERN_WARNING "%lu: TS discontinuity: got %#x, " | ||
| 436 | "expected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc); | ||
| 437 | /* Drop partly decoded SNDU, reset state, resync on PUSI. */ | ||
| 438 | if (priv->ule_skb) { | ||
| 439 | dev_kfree_skb( priv->ule_skb ); | ||
| 440 | /* Prepare for next SNDU. */ | ||
| 441 | // reset_ule(priv); moved to below. | ||
| 442 | dev->stats.rx_errors++; | ||
| 443 | dev->stats.rx_frame_errors++; | ||
| 444 | } | ||
| 445 | reset_ule(priv); | ||
| 446 | /* skip to next PUSI. */ | ||
| 447 | priv->need_pusi = 1; | ||
| 448 | continue; | ||
| 449 | } | ||
| 450 | /* If we still have an incomplete payload, but PUSI is | ||
| 451 | * set; some TS cells are missing. | ||
| 452 | * This is only possible here, if we missed exactly 16 TS | ||
| 453 | * cells (continuity counter wrap). */ | ||
| 454 | if (ts[1] & TS_PUSI) { | ||
| 455 | if (! priv->need_pusi) { | ||
| 456 | if (!(*from_where < (ts_remain-1)) || *from_where != priv->ule_sndu_remain) { | ||
| 457 | /* Pointer field is invalid. Drop this TS cell and any started ULE SNDU. */ | ||
| 458 | printk(KERN_WARNING "%lu: Invalid pointer " | ||
| 459 | "field: %u.\n", priv->ts_count, *from_where); | ||
| 460 | |||
| 461 | /* Drop partly decoded SNDU, reset state, resync on PUSI. */ | ||
| 462 | if (priv->ule_skb) { | ||
| 463 | error = true; | ||
| 464 | dev_kfree_skb(priv->ule_skb); | ||
| 465 | } | ||
| 466 | |||
| 467 | if (error || priv->ule_sndu_remain) { | ||
| 468 | dev->stats.rx_errors++; | ||
| 469 | dev->stats.rx_frame_errors++; | ||
| 470 | error = false; | ||
| 471 | } | ||
| 472 | |||
| 473 | reset_ule(priv); | ||
| 474 | priv->need_pusi = 1; | ||
| 475 | continue; | ||
| 476 | } | ||
| 477 | /* Skip pointer field (we're processing a | ||
| 478 | * packed payload). */ | ||
| 479 | from_where += 1; | ||
| 480 | ts_remain -= 1; | ||
| 481 | } else | ||
| 482 | priv->need_pusi = 0; | ||
| 483 | |||
| 484 | if (priv->ule_sndu_remain > 183) { | ||
| 485 | /* Current SNDU lacks more data than there could be available in the | ||
| 486 | * current TS cell. */ | ||
| 487 | dev->stats.rx_errors++; | ||
| 488 | dev->stats.rx_length_errors++; | ||
| 489 | printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but " | ||
| 490 | "got PUSI (pf %d, ts_remain %d). Flushing incomplete payload.\n", | ||
| 491 | priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain); | ||
| 492 | dev_kfree_skb(priv->ule_skb); | ||
| 493 | /* Prepare for next SNDU. */ | ||
| 494 | reset_ule(priv); | ||
| 495 | /* Resync: go to where pointer field points to: start of next ULE SNDU. */ | ||
| 496 | from_where += ts[4]; | ||
| 497 | ts_remain -= ts[4]; | ||
| 498 | } | ||
| 499 | } | ||
| 500 | } | ||
| 501 | |||
| 502 | /* Check if new payload needs to be started. */ | ||
| 503 | if (priv->ule_skb == NULL) { | ||
| 504 | /* Start a new payload with skb. | ||
| 505 | * Find ULE header. It is only guaranteed that the | ||
| 506 | * length field (2 bytes) is contained in the current | ||
| 507 | * TS. | ||
| 508 | * Check ts_remain has to be >= 2 here. */ | ||
| 509 | if (ts_remain < 2) { | ||
| 510 | printk(KERN_WARNING "Invalid payload packing: only %d " | ||
| 511 | "bytes left in TS. Resyncing.\n", ts_remain); | ||
| 512 | priv->ule_sndu_len = 0; | ||
| 513 | priv->need_pusi = 1; | ||
| 514 | ts += TS_SZ; | ||
| 515 | continue; | ||
| 516 | } | ||
| 517 | |||
| 518 | if (! priv->ule_sndu_len) { | ||
| 519 | /* Got at least two bytes, thus extrace the SNDU length. */ | ||
| 520 | priv->ule_sndu_len = from_where[0] << 8 | from_where[1]; | ||
| 521 | if (priv->ule_sndu_len & 0x8000) { | ||
| 522 | /* D-Bit is set: no dest mac present. */ | ||
| 523 | priv->ule_sndu_len &= 0x7FFF; | ||
| 524 | priv->ule_dbit = 1; | ||
| 525 | } else | ||
| 526 | priv->ule_dbit = 0; | ||
| 527 | |||
| 528 | if (priv->ule_sndu_len < 5) { | ||
| 529 | printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. " | ||
| 530 | "Resyncing.\n", priv->ts_count, priv->ule_sndu_len); | ||
| 531 | dev->stats.rx_errors++; | ||
| 532 | dev->stats.rx_length_errors++; | ||
| 533 | priv->ule_sndu_len = 0; | ||
| 534 | priv->need_pusi = 1; | ||
| 535 | new_ts = 1; | ||
| 536 | ts += TS_SZ; | ||
| 537 | priv->ts_count++; | ||
| 538 | continue; | ||
| 539 | } | ||
| 540 | ts_remain -= 2; /* consume the 2 bytes SNDU length. */ | ||
| 541 | from_where += 2; | ||
| 542 | } | ||
| 543 | |||
| 544 | priv->ule_sndu_remain = priv->ule_sndu_len + 2; | ||
| 545 | /* | ||
| 546 | * State of current TS: | ||
| 547 | * ts_remain (remaining bytes in the current TS cell) | ||
| 548 | * 0 ule_type is not available now, we need the next TS cell | ||
| 549 | * 1 the first byte of the ule_type is present | ||
| 550 | * >=2 full ULE header present, maybe some payload data as well. | ||
| 551 | */ | ||
| 552 | switch (ts_remain) { | ||
| 553 | case 1: | ||
| 554 | priv->ule_sndu_remain--; | ||
| 555 | priv->ule_sndu_type = from_where[0] << 8; | ||
| 556 | priv->ule_sndu_type_1 = 1; /* first byte of ule_type is set. */ | ||
| 557 | ts_remain -= 1; from_where += 1; | ||
| 558 | /* Continue w/ next TS. */ | ||
| 559 | case 0: | ||
| 560 | new_ts = 1; | ||
| 561 | ts += TS_SZ; | ||
| 562 | priv->ts_count++; | ||
| 563 | continue; | ||
| 564 | |||
| 565 | default: /* complete ULE header is present in current TS. */ | ||
| 566 | /* Extract ULE type field. */ | ||
| 567 | if (priv->ule_sndu_type_1) { | ||
| 568 | priv->ule_sndu_type_1 = 0; | ||
| 569 | priv->ule_sndu_type |= from_where[0]; | ||
| 570 | from_where += 1; /* points to payload start. */ | ||
| 571 | ts_remain -= 1; | ||
| 572 | } else { | ||
| 573 | /* Complete type is present in new TS. */ | ||
| 574 | priv->ule_sndu_type = from_where[0] << 8 | from_where[1]; | ||
| 575 | from_where += 2; /* points to payload start. */ | ||
| 576 | ts_remain -= 2; | ||
| 577 | } | ||
| 578 | break; | ||
| 579 | } | ||
| 580 | |||
| 581 | /* Allocate the skb (decoder target buffer) with the correct size, as follows: | ||
| 582 | * prepare for the largest case: bridged SNDU with MAC address (dbit = 0). */ | ||
| 583 | priv->ule_skb = dev_alloc_skb( priv->ule_sndu_len + ETH_HLEN + ETH_ALEN ); | ||
| 584 | if (priv->ule_skb == NULL) { | ||
| 585 | printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", | ||
| 586 | dev->name); | ||
| 587 | dev->stats.rx_dropped++; | ||
| 588 | return; | ||
| 589 | } | ||
| 590 | |||
| 591 | /* This includes the CRC32 _and_ dest mac, if !dbit. */ | ||
| 592 | priv->ule_sndu_remain = priv->ule_sndu_len; | ||
| 593 | priv->ule_skb->dev = dev; | ||
| 594 | /* Leave space for Ethernet or bridged SNDU header (eth hdr plus one MAC addr). */ | ||
| 595 | skb_reserve( priv->ule_skb, ETH_HLEN + ETH_ALEN ); | ||
| 596 | } | ||
| 597 | |||
| 598 | /* Copy data into our current skb. */ | ||
| 599 | how_much = min(priv->ule_sndu_remain, (int)ts_remain); | ||
| 600 | memcpy(skb_put(priv->ule_skb, how_much), from_where, how_much); | ||
| 601 | priv->ule_sndu_remain -= how_much; | ||
| 602 | ts_remain -= how_much; | ||
| 603 | from_where += how_much; | ||
| 604 | |||
| 605 | /* Check for complete payload. */ | ||
| 606 | if (priv->ule_sndu_remain <= 0) { | ||
| 607 | /* Check CRC32, we've got it in our skb already. */ | ||
| 608 | __be16 ulen = htons(priv->ule_sndu_len); | ||
| 609 | __be16 utype = htons(priv->ule_sndu_type); | ||
| 610 | const u8 *tail; | ||
| 611 | struct kvec iov[3] = { | ||
| 612 | { &ulen, sizeof ulen }, | ||
| 613 | { &utype, sizeof utype }, | ||
| 614 | { priv->ule_skb->data, priv->ule_skb->len - 4 } | ||
| 615 | }; | ||
| 616 | u32 ule_crc = ~0L, expected_crc; | ||
| 617 | if (priv->ule_dbit) { | ||
| 618 | /* Set D-bit for CRC32 verification, | ||
| 619 | * if it was set originally. */ | ||
| 620 | ulen |= htons(0x8000); | ||
| 621 | } | ||
| 622 | |||
| 623 | ule_crc = iov_crc32(ule_crc, iov, 3); | ||
| 624 | tail = skb_tail_pointer(priv->ule_skb); | ||
| 625 | expected_crc = *(tail - 4) << 24 | | ||
| 626 | *(tail - 3) << 16 | | ||
| 627 | *(tail - 2) << 8 | | ||
| 628 | *(tail - 1); | ||
| 629 | if (ule_crc != expected_crc) { | ||
| 630 | printk(KERN_WARNING "%lu: CRC32 check FAILED: %08x / %08x, SNDU len %d type %#x, ts_remain %d, next 2: %x.\n", | ||
| 631 | 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); | ||
| 632 | |||
| 633 | #ifdef ULE_DEBUG | ||
| 634 | hexdump( iov[0].iov_base, iov[0].iov_len ); | ||
| 635 | hexdump( iov[1].iov_base, iov[1].iov_len ); | ||
| 636 | hexdump( iov[2].iov_base, iov[2].iov_len ); | ||
| 637 | |||
| 638 | if (ule_where == ule_hist) { | ||
| 639 | hexdump( &ule_hist[98*TS_SZ], TS_SZ ); | ||
| 640 | hexdump( &ule_hist[99*TS_SZ], TS_SZ ); | ||
| 641 | } else if (ule_where == &ule_hist[TS_SZ]) { | ||
| 642 | hexdump( &ule_hist[99*TS_SZ], TS_SZ ); | ||
| 643 | hexdump( ule_hist, TS_SZ ); | ||
| 644 | } else { | ||
| 645 | hexdump( ule_where - TS_SZ - TS_SZ, TS_SZ ); | ||
| 646 | hexdump( ule_where - TS_SZ, TS_SZ ); | ||
| 647 | } | ||
| 648 | ule_dump = 1; | ||
| 649 | #endif | ||
| 650 | |||
| 651 | dev->stats.rx_errors++; | ||
| 652 | dev->stats.rx_crc_errors++; | ||
| 653 | dev_kfree_skb(priv->ule_skb); | ||
| 654 | } else { | ||
| 655 | /* CRC32 verified OK. */ | ||
| 656 | u8 dest_addr[ETH_ALEN]; | ||
| 657 | static const u8 bc_addr[ETH_ALEN] = | ||
| 658 | { [ 0 ... ETH_ALEN-1] = 0xff }; | ||
| 659 | |||
| 660 | /* CRC32 was OK. Remove it from skb. */ | ||
| 661 | priv->ule_skb->tail -= 4; | ||
| 662 | priv->ule_skb->len -= 4; | ||
| 663 | |||
| 664 | if (!priv->ule_dbit) { | ||
| 665 | /* | ||
| 666 | * The destination MAC address is the | ||
| 667 | * next data in the skb. It comes | ||
| 668 | * before any extension headers. | ||
| 669 | * | ||
| 670 | * Check if the payload of this SNDU | ||
| 671 | * should be passed up the stack. | ||
| 672 | */ | ||
| 673 | register int drop = 0; | ||
| 674 | if (priv->rx_mode != RX_MODE_PROMISC) { | ||
| 675 | if (priv->ule_skb->data[0] & 0x01) { | ||
| 676 | /* multicast or broadcast */ | ||
| 677 | if (memcmp(priv->ule_skb->data, bc_addr, ETH_ALEN)) { | ||
| 678 | /* multicast */ | ||
| 679 | if (priv->rx_mode == RX_MODE_MULTI) { | ||
| 680 | int i; | ||
| 681 | for(i = 0; i < priv->multi_num && memcmp(priv->ule_skb->data, priv->multi_macs[i], ETH_ALEN); i++) | ||
| 682 | ; | ||
| 683 | if (i == priv->multi_num) | ||
| 684 | drop = 1; | ||
| 685 | } else if (priv->rx_mode != RX_MODE_ALL_MULTI) | ||
| 686 | drop = 1; /* no broadcast; */ | ||
| 687 | /* else: all multicast mode: accept all multicast packets */ | ||
| 688 | } | ||
| 689 | /* else: broadcast */ | ||
| 690 | } | ||
| 691 | else if (memcmp(priv->ule_skb->data, dev->dev_addr, ETH_ALEN)) | ||
| 692 | drop = 1; | ||
| 693 | /* else: destination address matches the MAC address of our receiver device */ | ||
| 694 | } | ||
| 695 | /* else: promiscuous mode; pass everything up the stack */ | ||
| 696 | |||
| 697 | if (drop) { | ||
| 698 | #ifdef ULE_DEBUG | ||
| 699 | dprintk("Dropping SNDU: MAC destination address does not match: dest addr: "MAC_ADDR_PRINTFMT", dev addr: "MAC_ADDR_PRINTFMT"\n", | ||
| 700 | MAX_ADDR_PRINTFMT_ARGS(priv->ule_skb->data), MAX_ADDR_PRINTFMT_ARGS(dev->dev_addr)); | ||
| 701 | #endif | ||
| 702 | dev_kfree_skb(priv->ule_skb); | ||
| 703 | goto sndu_done; | ||
| 704 | } | ||
| 705 | else | ||
| 706 | { | ||
| 707 | skb_copy_from_linear_data(priv->ule_skb, | ||
| 708 | dest_addr, | ||
| 709 | ETH_ALEN); | ||
| 710 | skb_pull(priv->ule_skb, ETH_ALEN); | ||
| 711 | } | ||
| 712 | } | ||
| 713 | |||
| 714 | /* Handle ULE Extension Headers. */ | ||
| 715 | if (priv->ule_sndu_type < 1536) { | ||
| 716 | /* There is an extension header. Handle it accordingly. */ | ||
| 717 | int l = handle_ule_extensions(priv); | ||
| 718 | if (l < 0) { | ||
| 719 | /* Mandatory extension header unknown or TEST SNDU. Drop it. */ | ||
| 720 | // printk( KERN_WARNING "Dropping SNDU, extension headers.\n" ); | ||
| 721 | dev_kfree_skb(priv->ule_skb); | ||
| 722 | goto sndu_done; | ||
| 723 | } | ||
| 724 | skb_pull(priv->ule_skb, l); | ||
| 725 | } | ||
| 726 | |||
| 727 | /* | ||
| 728 | * Construct/assure correct ethernet header. | ||
| 729 | * Note: in bridged mode (priv->ule_bridged != | ||
| 730 | * 0) we already have the (original) ethernet | ||
| 731 | * header at the start of the payload (after | ||
| 732 | * optional dest. address and any extension | ||
| 733 | * headers). | ||
| 734 | */ | ||
| 735 | |||
| 736 | if (!priv->ule_bridged) { | ||
| 737 | skb_push(priv->ule_skb, ETH_HLEN); | ||
| 738 | ethh = (struct ethhdr *)priv->ule_skb->data; | ||
| 739 | if (!priv->ule_dbit) { | ||
| 740 | /* dest_addr buffer is only valid if priv->ule_dbit == 0 */ | ||
| 741 | memcpy(ethh->h_dest, dest_addr, ETH_ALEN); | ||
| 742 | memset(ethh->h_source, 0, ETH_ALEN); | ||
| 743 | } | ||
| 744 | else /* zeroize source and dest */ | ||
| 745 | memset( ethh, 0, ETH_ALEN*2 ); | ||
| 746 | |||
| 747 | ethh->h_proto = htons(priv->ule_sndu_type); | ||
| 748 | } | ||
| 749 | /* else: skb is in correct state; nothing to do. */ | ||
| 750 | priv->ule_bridged = 0; | ||
| 751 | |||
| 752 | /* Stuff into kernel's protocol stack. */ | ||
| 753 | priv->ule_skb->protocol = dvb_net_eth_type_trans(priv->ule_skb, dev); | ||
| 754 | /* If D-bit is set (i.e. destination MAC address not present), | ||
| 755 | * receive the packet anyhow. */ | ||
| 756 | /* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST) | ||
| 757 | priv->ule_skb->pkt_type = PACKET_HOST; */ | ||
| 758 | dev->stats.rx_packets++; | ||
| 759 | dev->stats.rx_bytes += priv->ule_skb->len; | ||
| 760 | netif_rx(priv->ule_skb); | ||
| 761 | } | ||
| 762 | sndu_done: | ||
| 763 | /* Prepare for next SNDU. */ | ||
| 764 | reset_ule(priv); | ||
| 765 | } | ||
| 766 | |||
| 767 | /* More data in current TS (look at the bytes following the CRC32)? */ | ||
| 768 | if (ts_remain >= 2 && *((unsigned short *)from_where) != 0xFFFF) { | ||
| 769 | /* Next ULE SNDU starts right there. */ | ||
| 770 | new_ts = 0; | ||
| 771 | priv->ule_skb = NULL; | ||
| 772 | priv->ule_sndu_type_1 = 0; | ||
| 773 | priv->ule_sndu_len = 0; | ||
| 774 | // printk(KERN_WARNING "More data in current TS: [%#x %#x %#x %#x]\n", | ||
| 775 | // *(from_where + 0), *(from_where + 1), | ||
| 776 | // *(from_where + 2), *(from_where + 3)); | ||
| 777 | // printk(KERN_WARNING "ts @ %p, stopped @ %p:\n", ts, from_where + 0); | ||
| 778 | // hexdump(ts, 188); | ||
| 779 | } else { | ||
| 780 | new_ts = 1; | ||
| 781 | ts += TS_SZ; | ||
| 782 | priv->ts_count++; | ||
| 783 | if (priv->ule_skb == NULL) { | ||
| 784 | priv->need_pusi = 1; | ||
| 785 | priv->ule_sndu_type_1 = 0; | ||
| 786 | priv->ule_sndu_len = 0; | ||
| 787 | } | ||
| 788 | } | ||
| 789 | } /* for all available TS cells */ | ||
| 790 | } | ||
| 791 | |||
| 792 | static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len, | ||
| 793 | const u8 *buffer2, size_t buffer2_len, | ||
| 794 | struct dmx_ts_feed *feed, enum dmx_success success) | ||
| 795 | { | ||
| 796 | struct net_device *dev = feed->priv; | ||
| 797 | |||
| 798 | if (buffer2) | ||
| 799 | printk(KERN_WARNING "buffer2 not NULL: %p.\n", buffer2); | ||
| 800 | if (buffer1_len > 32768) | ||
| 801 | printk(KERN_WARNING "length > 32k: %zu.\n", buffer1_len); | ||
| 802 | /* printk("TS callback: %u bytes, %u TS cells @ %p.\n", | ||
| 803 | buffer1_len, buffer1_len / TS_SZ, buffer1); */ | ||
| 804 | dvb_net_ule(dev, buffer1, buffer1_len); | ||
| 805 | return 0; | ||
| 806 | } | ||
| 807 | |||
| 808 | |||
| 809 | static void dvb_net_sec(struct net_device *dev, | ||
| 810 | const u8 *pkt, int pkt_len) | ||
| 811 | { | ||
| 812 | u8 *eth; | ||
| 813 | struct sk_buff *skb; | ||
| 814 | struct net_device_stats *stats = &dev->stats; | ||
| 815 | int snap = 0; | ||
| 816 | |||
| 817 | /* note: pkt_len includes a 32bit checksum */ | ||
| 818 | if (pkt_len < 16) { | ||
| 819 | printk("%s: IP/MPE packet length = %d too small.\n", | ||
| 820 | dev->name, pkt_len); | ||
| 821 | stats->rx_errors++; | ||
| 822 | stats->rx_length_errors++; | ||
| 823 | return; | ||
| 824 | } | ||
| 825 | /* it seems some ISPs manage to screw up here, so we have to | ||
| 826 | * relax the error checks... */ | ||
| 827 | #if 0 | ||
| 828 | if ((pkt[5] & 0xfd) != 0xc1) { | ||
| 829 | /* drop scrambled or broken packets */ | ||
| 830 | #else | ||
| 831 | if ((pkt[5] & 0x3c) != 0x00) { | ||
| 832 | /* drop scrambled */ | ||
| 833 | #endif | ||
| 834 | stats->rx_errors++; | ||
| 835 | stats->rx_crc_errors++; | ||
| 836 | return; | ||
| 837 | } | ||
| 838 | if (pkt[5] & 0x02) { | ||
| 839 | /* handle LLC/SNAP, see rfc-1042 */ | ||
| 840 | if (pkt_len < 24 || memcmp(&pkt[12], "\xaa\xaa\x03\0\0\0", 6)) { | ||
| 841 | stats->rx_dropped++; | ||
| 842 | return; | ||
| 843 | } | ||
| 844 | snap = 8; | ||
| 845 | } | ||
| 846 | if (pkt[7]) { | ||
| 847 | /* FIXME: assemble datagram from multiple sections */ | ||
| 848 | stats->rx_errors++; | ||
| 849 | stats->rx_frame_errors++; | ||
| 850 | return; | ||
| 851 | } | ||
| 852 | |||
| 853 | /* we have 14 byte ethernet header (ip header follows); | ||
| 854 | * 12 byte MPE header; 4 byte checksum; + 2 byte alignment, 8 byte LLC/SNAP | ||
| 855 | */ | ||
| 856 | if (!(skb = dev_alloc_skb(pkt_len - 4 - 12 + 14 + 2 - snap))) { | ||
| 857 | //printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); | ||
| 858 | stats->rx_dropped++; | ||
| 859 | return; | ||
| 860 | } | ||
| 861 | skb_reserve(skb, 2); /* longword align L3 header */ | ||
| 862 | skb->dev = dev; | ||
| 863 | |||
| 864 | /* copy L3 payload */ | ||
| 865 | eth = (u8 *) skb_put(skb, pkt_len - 12 - 4 + 14 - snap); | ||
| 866 | memcpy(eth + 14, pkt + 12 + snap, pkt_len - 12 - 4 - snap); | ||
| 867 | |||
| 868 | /* create ethernet header: */ | ||
| 869 | eth[0]=pkt[0x0b]; | ||
| 870 | eth[1]=pkt[0x0a]; | ||
| 871 | eth[2]=pkt[0x09]; | ||
| 872 | eth[3]=pkt[0x08]; | ||
| 873 | eth[4]=pkt[0x04]; | ||
| 874 | eth[5]=pkt[0x03]; | ||
| 875 | |||
| 876 | eth[6]=eth[7]=eth[8]=eth[9]=eth[10]=eth[11]=0; | ||
| 877 | |||
| 878 | if (snap) { | ||
| 879 | eth[12] = pkt[18]; | ||
| 880 | eth[13] = pkt[19]; | ||
| 881 | } else { | ||
| 882 | /* protocol numbers are from rfc-1700 or | ||
| 883 | * http://www.iana.org/assignments/ethernet-numbers | ||
| 884 | */ | ||
| 885 | if (pkt[12] >> 4 == 6) { /* version field from IP header */ | ||
| 886 | eth[12] = 0x86; /* IPv6 */ | ||
| 887 | eth[13] = 0xdd; | ||
| 888 | } else { | ||
| 889 | eth[12] = 0x08; /* IPv4 */ | ||
| 890 | eth[13] = 0x00; | ||
| 891 | } | ||
| 892 | } | ||
| 893 | |||
| 894 | skb->protocol = dvb_net_eth_type_trans(skb, dev); | ||
| 895 | |||
| 896 | stats->rx_packets++; | ||
| 897 | stats->rx_bytes+=skb->len; | ||
| 898 | netif_rx(skb); | ||
| 899 | } | ||
| 900 | |||
| 901 | static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len, | ||
| 902 | const u8 *buffer2, size_t buffer2_len, | ||
| 903 | struct dmx_section_filter *filter, | ||
| 904 | enum dmx_success success) | ||
| 905 | { | ||
| 906 | struct net_device *dev = filter->priv; | ||
| 907 | |||
| 908 | /** | ||
| 909 | * we rely on the DVB API definition where exactly one complete | ||
| 910 | * section is delivered in buffer1 | ||
| 911 | */ | ||
| 912 | dvb_net_sec (dev, buffer1, buffer1_len); | ||
| 913 | return 0; | ||
| 914 | } | ||
| 915 | |||
| 916 | static int dvb_net_tx(struct sk_buff *skb, struct net_device *dev) | ||
| 917 | { | ||
| 918 | dev_kfree_skb(skb); | ||
| 919 | return NETDEV_TX_OK; | ||
| 920 | } | ||
| 921 | |||
| 922 | static u8 mask_normal[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; | ||
| 923 | static u8 mask_allmulti[6]={0xff, 0xff, 0xff, 0x00, 0x00, 0x00}; | ||
| 924 | static u8 mac_allmulti[6]={0x01, 0x00, 0x5e, 0x00, 0x00, 0x00}; | ||
| 925 | static u8 mask_promisc[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; | ||
| 926 | |||
| 927 | static int dvb_net_filter_sec_set(struct net_device *dev, | ||
| 928 | struct dmx_section_filter **secfilter, | ||
| 929 | u8 *mac, u8 *mac_mask) | ||
| 930 | { | ||
| 931 | struct dvb_net_priv *priv = netdev_priv(dev); | ||
| 932 | int ret; | ||
| 933 | |||
| 934 | *secfilter=NULL; | ||
| 935 | ret = priv->secfeed->allocate_filter(priv->secfeed, secfilter); | ||
| 936 | if (ret<0) { | ||
| 937 | printk("%s: could not get filter\n", dev->name); | ||
| 938 | return ret; | ||
| 939 | } | ||
| 940 | |||
| 941 | (*secfilter)->priv=(void *) dev; | ||
| 942 | |||
| 943 | memset((*secfilter)->filter_value, 0x00, DMX_MAX_FILTER_SIZE); | ||
| 944 | memset((*secfilter)->filter_mask, 0x00, DMX_MAX_FILTER_SIZE); | ||
| 945 | memset((*secfilter)->filter_mode, 0xff, DMX_MAX_FILTER_SIZE); | ||
| 946 | |||
| 947 | (*secfilter)->filter_value[0]=0x3e; | ||
| 948 | (*secfilter)->filter_value[3]=mac[5]; | ||
| 949 | (*secfilter)->filter_value[4]=mac[4]; | ||
| 950 | (*secfilter)->filter_value[8]=mac[3]; | ||
| 951 | (*secfilter)->filter_value[9]=mac[2]; | ||
| 952 | (*secfilter)->filter_value[10]=mac[1]; | ||
| 953 | (*secfilter)->filter_value[11]=mac[0]; | ||
| 954 | |||
| 955 | (*secfilter)->filter_mask[0] = 0xff; | ||
| 956 | (*secfilter)->filter_mask[3] = mac_mask[5]; | ||
| 957 | (*secfilter)->filter_mask[4] = mac_mask[4]; | ||
| 958 | (*secfilter)->filter_mask[8] = mac_mask[3]; | ||
| 959 | (*secfilter)->filter_mask[9] = mac_mask[2]; | ||
| 960 | (*secfilter)->filter_mask[10] = mac_mask[1]; | ||
| 961 | (*secfilter)->filter_mask[11]=mac_mask[0]; | ||
| 962 | |||
| 963 | dprintk("%s: filter mac=%pM\n", dev->name, mac); | ||
| 964 | dprintk("%s: filter mask=%pM\n", dev->name, mac_mask); | ||
| 965 | |||
| 966 | return 0; | ||
| 967 | } | ||
| 968 | |||
| 969 | static int dvb_net_feed_start(struct net_device *dev) | ||
| 970 | { | ||
| 971 | int ret = 0, i; | ||
| 972 | struct dvb_net_priv *priv = netdev_priv(dev); | ||
| 973 | struct dmx_demux *demux = priv->demux; | ||
| 974 | unsigned char *mac = (unsigned char *) dev->dev_addr; | ||
| 975 | |||
| 976 | dprintk("%s: rx_mode %i\n", __func__, priv->rx_mode); | ||
| 977 | mutex_lock(&priv->mutex); | ||
| 978 | if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0]) | ||
| 979 | printk("%s: BUG %d\n", __func__, __LINE__); | ||
| 980 | |||
| 981 | priv->secfeed=NULL; | ||
| 982 | priv->secfilter=NULL; | ||
| 983 | priv->tsfeed = NULL; | ||
| 984 | |||
| 985 | if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) { | ||
| 986 | dprintk("%s: alloc secfeed\n", __func__); | ||
| 987 | ret=demux->allocate_section_feed(demux, &priv->secfeed, | ||
| 988 | dvb_net_sec_callback); | ||
| 989 | if (ret<0) { | ||
| 990 | printk("%s: could not allocate section feed\n", dev->name); | ||
| 991 | goto error; | ||
| 992 | } | ||
| 993 | |||
| 994 | ret = priv->secfeed->set(priv->secfeed, priv->pid, 32768, 1); | ||
| 995 | |||
| 996 | if (ret<0) { | ||
| 997 | printk("%s: could not set section feed\n", dev->name); | ||
| 998 | priv->demux->release_section_feed(priv->demux, priv->secfeed); | ||
| 999 | priv->secfeed=NULL; | ||
| 1000 | goto error; | ||
| 1001 | } | ||
| 1002 | |||
| 1003 | if (priv->rx_mode != RX_MODE_PROMISC) { | ||
| 1004 | dprintk("%s: set secfilter\n", __func__); | ||
| 1005 | dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_normal); | ||
| 1006 | } | ||
| 1007 | |||
| 1008 | switch (priv->rx_mode) { | ||
| 1009 | case RX_MODE_MULTI: | ||
| 1010 | for (i = 0; i < priv->multi_num; i++) { | ||
| 1011 | dprintk("%s: set multi_secfilter[%d]\n", __func__, i); | ||
| 1012 | dvb_net_filter_sec_set(dev, &priv->multi_secfilter[i], | ||
| 1013 | priv->multi_macs[i], mask_normal); | ||
| 1014 | } | ||
| 1015 | break; | ||
| 1016 | case RX_MODE_ALL_MULTI: | ||
| 1017 | priv->multi_num=1; | ||
| 1018 | dprintk("%s: set multi_secfilter[0]\n", __func__); | ||
| 1019 | dvb_net_filter_sec_set(dev, &priv->multi_secfilter[0], | ||
| 1020 | mac_allmulti, mask_allmulti); | ||
| 1021 | break; | ||
| 1022 | case RX_MODE_PROMISC: | ||
| 1023 | priv->multi_num=0; | ||
| 1024 | dprintk("%s: set secfilter\n", __func__); | ||
| 1025 | dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_promisc); | ||
| 1026 | break; | ||
| 1027 | } | ||
| 1028 | |||
| 1029 | dprintk("%s: start filtering\n", __func__); | ||
| 1030 | priv->secfeed->start_filtering(priv->secfeed); | ||
| 1031 | } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) { | ||
| 1032 | struct timespec timeout = { 0, 10000000 }; // 10 msec | ||
| 1033 | |||
| 1034 | /* we have payloads encapsulated in TS */ | ||
| 1035 | dprintk("%s: alloc tsfeed\n", __func__); | ||
| 1036 | ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback); | ||
| 1037 | if (ret < 0) { | ||
| 1038 | printk("%s: could not allocate ts feed\n", dev->name); | ||
| 1039 | goto error; | ||
| 1040 | } | ||
| 1041 | |||
| 1042 | /* Set netdevice pointer for ts decaps callback. */ | ||
| 1043 | priv->tsfeed->priv = (void *)dev; | ||
| 1044 | ret = priv->tsfeed->set(priv->tsfeed, | ||
| 1045 | priv->pid, /* pid */ | ||
| 1046 | TS_PACKET, /* type */ | ||
| 1047 | DMX_TS_PES_OTHER, /* pes type */ | ||
| 1048 | 32768, /* circular buffer size */ | ||
| 1049 | timeout /* timeout */ | ||
| 1050 | ); | ||
| 1051 | |||
| 1052 | if (ret < 0) { | ||
| 1053 | printk("%s: could not set ts feed\n", dev->name); | ||
| 1054 | priv->demux->release_ts_feed(priv->demux, priv->tsfeed); | ||
| 1055 | priv->tsfeed = NULL; | ||
| 1056 | goto error; | ||
| 1057 | } | ||
| 1058 | |||
| 1059 | dprintk("%s: start filtering\n", __func__); | ||
| 1060 | priv->tsfeed->start_filtering(priv->tsfeed); | ||
| 1061 | } else | ||
| 1062 | ret = -EINVAL; | ||
| 1063 | |||
| 1064 | error: | ||
| 1065 | mutex_unlock(&priv->mutex); | ||
| 1066 | return ret; | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | static int dvb_net_feed_stop(struct net_device *dev) | ||
| 1070 | { | ||
| 1071 | struct dvb_net_priv *priv = netdev_priv(dev); | ||
| 1072 | int i, ret = 0; | ||
| 1073 | |||
| 1074 | dprintk("%s\n", __func__); | ||
| 1075 | mutex_lock(&priv->mutex); | ||
| 1076 | if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) { | ||
| 1077 | if (priv->secfeed) { | ||
| 1078 | if (priv->secfeed->is_filtering) { | ||
| 1079 | dprintk("%s: stop secfeed\n", __func__); | ||
| 1080 | priv->secfeed->stop_filtering(priv->secfeed); | ||
| 1081 | } | ||
| 1082 | |||
| 1083 | if (priv->secfilter) { | ||
| 1084 | dprintk("%s: release secfilter\n", __func__); | ||
| 1085 | priv->secfeed->release_filter(priv->secfeed, | ||
| 1086 | priv->secfilter); | ||
| 1087 | priv->secfilter=NULL; | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | for (i=0; i<priv->multi_num; i++) { | ||
| 1091 | if (priv->multi_secfilter[i]) { | ||
| 1092 | dprintk("%s: release multi_filter[%d]\n", | ||
| 1093 | __func__, i); | ||
| 1094 | priv->secfeed->release_filter(priv->secfeed, | ||
| 1095 | priv->multi_secfilter[i]); | ||
| 1096 | priv->multi_secfilter[i] = NULL; | ||
| 1097 | } | ||
| 1098 | } | ||
| 1099 | |||
| 1100 | priv->demux->release_section_feed(priv->demux, priv->secfeed); | ||
| 1101 | priv->secfeed = NULL; | ||
| 1102 | } else | ||
| 1103 | printk("%s: no feed to stop\n", dev->name); | ||
| 1104 | } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) { | ||
| 1105 | if (priv->tsfeed) { | ||
| 1106 | if (priv->tsfeed->is_filtering) { | ||
| 1107 | dprintk("%s: stop tsfeed\n", __func__); | ||
| 1108 | priv->tsfeed->stop_filtering(priv->tsfeed); | ||
| 1109 | } | ||
| 1110 | priv->demux->release_ts_feed(priv->demux, priv->tsfeed); | ||
| 1111 | priv->tsfeed = NULL; | ||
| 1112 | } | ||
| 1113 | else | ||
| 1114 | printk("%s: no ts feed to stop\n", dev->name); | ||
| 1115 | } else | ||
| 1116 | ret = -EINVAL; | ||
| 1117 | mutex_unlock(&priv->mutex); | ||
| 1118 | return ret; | ||
| 1119 | } | ||
| 1120 | |||
| 1121 | |||
| 1122 | static int dvb_set_mc_filter(struct net_device *dev, unsigned char *addr) | ||
| 1123 | { | ||
| 1124 | struct dvb_net_priv *priv = netdev_priv(dev); | ||
| 1125 | |||
| 1126 | if (priv->multi_num == DVB_NET_MULTICAST_MAX) | ||
| 1127 | return -ENOMEM; | ||
| 1128 | |||
| 1129 | memcpy(priv->multi_macs[priv->multi_num], addr, ETH_ALEN); | ||
| 1130 | |||
| 1131 | priv->multi_num++; | ||
| 1132 | return 0; | ||
| 1133 | } | ||
| 1134 | |||
| 1135 | |||
| 1136 | static void wq_set_multicast_list (struct work_struct *work) | ||
| 1137 | { | ||
| 1138 | struct dvb_net_priv *priv = | ||
| 1139 | container_of(work, struct dvb_net_priv, set_multicast_list_wq); | ||
| 1140 | struct net_device *dev = priv->net; | ||
| 1141 | |||
| 1142 | dvb_net_feed_stop(dev); | ||
| 1143 | priv->rx_mode = RX_MODE_UNI; | ||
| 1144 | netif_addr_lock_bh(dev); | ||
| 1145 | |||
| 1146 | if (dev->flags & IFF_PROMISC) { | ||
| 1147 | dprintk("%s: promiscuous mode\n", dev->name); | ||
| 1148 | priv->rx_mode = RX_MODE_PROMISC; | ||
| 1149 | } else if ((dev->flags & IFF_ALLMULTI)) { | ||
| 1150 | dprintk("%s: allmulti mode\n", dev->name); | ||
| 1151 | priv->rx_mode = RX_MODE_ALL_MULTI; | ||
| 1152 | } else if (!netdev_mc_empty(dev)) { | ||
| 1153 | struct netdev_hw_addr *ha; | ||
| 1154 | |||
| 1155 | dprintk("%s: set_mc_list, %d entries\n", | ||
| 1156 | dev->name, netdev_mc_count(dev)); | ||
| 1157 | |||
| 1158 | priv->rx_mode = RX_MODE_MULTI; | ||
| 1159 | priv->multi_num = 0; | ||
| 1160 | |||
| 1161 | netdev_for_each_mc_addr(ha, dev) | ||
| 1162 | dvb_set_mc_filter(dev, ha->addr); | ||
| 1163 | } | ||
| 1164 | |||
| 1165 | netif_addr_unlock_bh(dev); | ||
| 1166 | dvb_net_feed_start(dev); | ||
| 1167 | } | ||
| 1168 | |||
| 1169 | |||
| 1170 | static void dvb_net_set_multicast_list (struct net_device *dev) | ||
| 1171 | { | ||
| 1172 | struct dvb_net_priv *priv = netdev_priv(dev); | ||
| 1173 | schedule_work(&priv->set_multicast_list_wq); | ||
| 1174 | } | ||
| 1175 | |||
| 1176 | |||
| 1177 | static void wq_restart_net_feed (struct work_struct *work) | ||
| 1178 | { | ||
| 1179 | struct dvb_net_priv *priv = | ||
| 1180 | container_of(work, struct dvb_net_priv, restart_net_feed_wq); | ||
| 1181 | struct net_device *dev = priv->net; | ||
| 1182 | |||
| 1183 | if (netif_running(dev)) { | ||
| 1184 | dvb_net_feed_stop(dev); | ||
| 1185 | dvb_net_feed_start(dev); | ||
| 1186 | } | ||
| 1187 | } | ||
| 1188 | |||
| 1189 | |||
| 1190 | static int dvb_net_set_mac (struct net_device *dev, void *p) | ||
| 1191 | { | ||
| 1192 | struct dvb_net_priv *priv = netdev_priv(dev); | ||
| 1193 | struct sockaddr *addr=p; | ||
| 1194 | |||
| 1195 | memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); | ||
| 1196 | |||
| 1197 | if (netif_running(dev)) | ||
| 1198 | schedule_work(&priv->restart_net_feed_wq); | ||
| 1199 | |||
| 1200 | return 0; | ||
| 1201 | } | ||
| 1202 | |||
| 1203 | |||
| 1204 | static int dvb_net_open(struct net_device *dev) | ||
| 1205 | { | ||
| 1206 | struct dvb_net_priv *priv = netdev_priv(dev); | ||
| 1207 | |||
| 1208 | priv->in_use++; | ||
| 1209 | dvb_net_feed_start(dev); | ||
| 1210 | return 0; | ||
| 1211 | } | ||
| 1212 | |||
| 1213 | |||
| 1214 | static int dvb_net_stop(struct net_device *dev) | ||
| 1215 | { | ||
| 1216 | struct dvb_net_priv *priv = netdev_priv(dev); | ||
| 1217 | |||
| 1218 | priv->in_use--; | ||
| 1219 | return dvb_net_feed_stop(dev); | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | static const struct header_ops dvb_header_ops = { | ||
| 1223 | .create = eth_header, | ||
| 1224 | .parse = eth_header_parse, | ||
| 1225 | .rebuild = eth_rebuild_header, | ||
| 1226 | }; | ||
| 1227 | |||
| 1228 | |||
| 1229 | static const struct net_device_ops dvb_netdev_ops = { | ||
| 1230 | .ndo_open = dvb_net_open, | ||
| 1231 | .ndo_stop = dvb_net_stop, | ||
| 1232 | .ndo_start_xmit = dvb_net_tx, | ||
| 1233 | .ndo_set_multicast_list = dvb_net_set_multicast_list, | ||
| 1234 | .ndo_set_mac_address = dvb_net_set_mac, | ||
| 1235 | .ndo_change_mtu = eth_change_mtu, | ||
| 1236 | .ndo_validate_addr = eth_validate_addr, | ||
| 1237 | }; | ||
| 1238 | |||
| 1239 | static void dvb_net_setup(struct net_device *dev) | ||
| 1240 | { | ||
| 1241 | ether_setup(dev); | ||
| 1242 | |||
| 1243 | dev->header_ops = &dvb_header_ops; | ||
| 1244 | dev->netdev_ops = &dvb_netdev_ops; | ||
| 1245 | dev->mtu = 4096; | ||
| 1246 | |||
| 1247 | dev->flags |= IFF_NOARP; | ||
| 1248 | } | ||
| 1249 | |||
| 1250 | static int get_if(struct dvb_net *dvbnet) | ||
| 1251 | { | ||
| 1252 | int i; | ||
| 1253 | |||
| 1254 | for (i=0; i<DVB_NET_DEVICES_MAX; i++) | ||
| 1255 | if (!dvbnet->state[i]) | ||
| 1256 | break; | ||
| 1257 | |||
| 1258 | if (i == DVB_NET_DEVICES_MAX) | ||
| 1259 | return -1; | ||
| 1260 | |||
| 1261 | dvbnet->state[i]=1; | ||
| 1262 | return i; | ||
| 1263 | } | ||
| 1264 | |||
| 1265 | static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype) | ||
| 1266 | { | ||
| 1267 | struct net_device *net; | ||
| 1268 | struct dvb_net_priv *priv; | ||
| 1269 | int result; | ||
| 1270 | int if_num; | ||
| 1271 | |||
| 1272 | if (feedtype != DVB_NET_FEEDTYPE_MPE && feedtype != DVB_NET_FEEDTYPE_ULE) | ||
| 1273 | return -EINVAL; | ||
| 1274 | if ((if_num = get_if(dvbnet)) < 0) | ||
| 1275 | return -EINVAL; | ||
| 1276 | |||
| 1277 | net = alloc_netdev(sizeof(struct dvb_net_priv), "dvb", dvb_net_setup); | ||
| 1278 | if (!net) | ||
| 1279 | return -ENOMEM; | ||
| 1280 | |||
| 1281 | if (dvbnet->dvbdev->id) | ||
| 1282 | snprintf(net->name, IFNAMSIZ, "dvb%d%u%d", | ||
| 1283 | dvbnet->dvbdev->adapter->num, dvbnet->dvbdev->id, if_num); | ||
| 1284 | else | ||
| 1285 | /* compatibility fix to keep dvb0_0 format */ | ||
| 1286 | snprintf(net->name, IFNAMSIZ, "dvb%d_%d", | ||
| 1287 | dvbnet->dvbdev->adapter->num, if_num); | ||
| 1288 | |||
| 1289 | net->addr_len = 6; | ||
| 1290 | memcpy(net->dev_addr, dvbnet->dvbdev->adapter->proposed_mac, 6); | ||
| 1291 | |||
| 1292 | dvbnet->device[if_num] = net; | ||
| 1293 | |||
| 1294 | priv = netdev_priv(net); | ||
| 1295 | priv->net = net; | ||
| 1296 | priv->demux = dvbnet->demux; | ||
| 1297 | priv->pid = pid; | ||
| 1298 | priv->rx_mode = RX_MODE_UNI; | ||
| 1299 | priv->need_pusi = 1; | ||
| 1300 | priv->tscc = 0; | ||
| 1301 | priv->feedtype = feedtype; | ||
| 1302 | reset_ule(priv); | ||
| 1303 | |||
| 1304 | INIT_WORK(&priv->set_multicast_list_wq, wq_set_multicast_list); | ||
| 1305 | INIT_WORK(&priv->restart_net_feed_wq, wq_restart_net_feed); | ||
| 1306 | mutex_init(&priv->mutex); | ||
| 1307 | |||
| 1308 | net->base_addr = pid; | ||
| 1309 | |||
| 1310 | if ((result = register_netdev(net)) < 0) { | ||
| 1311 | dvbnet->device[if_num] = NULL; | ||
| 1312 | free_netdev(net); | ||
| 1313 | return result; | ||
| 1314 | } | ||
| 1315 | printk("dvb_net: created network interface %s\n", net->name); | ||
| 1316 | |||
| 1317 | return if_num; | ||
| 1318 | } | ||
| 1319 | |||
| 1320 | static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num) | ||
| 1321 | { | ||
| 1322 | struct net_device *net = dvbnet->device[num]; | ||
| 1323 | struct dvb_net_priv *priv; | ||
| 1324 | |||
| 1325 | if (!dvbnet->state[num]) | ||
| 1326 | return -EINVAL; | ||
| 1327 | priv = netdev_priv(net); | ||
| 1328 | if (priv->in_use) | ||
| 1329 | return -EBUSY; | ||
| 1330 | |||
| 1331 | dvb_net_stop(net); | ||
| 1332 | flush_work_sync(&priv->set_multicast_list_wq); | ||
| 1333 | flush_work_sync(&priv->restart_net_feed_wq); | ||
| 1334 | printk("dvb_net: removed network interface %s\n", net->name); | ||
| 1335 | unregister_netdev(net); | ||
| 1336 | dvbnet->state[num]=0; | ||
| 1337 | dvbnet->device[num] = NULL; | ||
| 1338 | free_netdev(net); | ||
| 1339 | |||
| 1340 | return 0; | ||
| 1341 | } | ||
| 1342 | |||
| 1343 | static int dvb_net_do_ioctl(struct file *file, | ||
| 1344 | unsigned int cmd, void *parg) | ||
| 1345 | { | ||
| 1346 | struct dvb_device *dvbdev = file->private_data; | ||
| 1347 | struct dvb_net *dvbnet = dvbdev->priv; | ||
| 1348 | |||
| 1349 | if (((file->f_flags&O_ACCMODE)==O_RDONLY)) | ||
| 1350 | return -EPERM; | ||
| 1351 | |||
| 1352 | switch (cmd) { | ||
| 1353 | case NET_ADD_IF: | ||
| 1354 | { | ||
| 1355 | struct dvb_net_if *dvbnetif = parg; | ||
| 1356 | int result; | ||
| 1357 | |||
| 1358 | if (!capable(CAP_SYS_ADMIN)) | ||
| 1359 | return -EPERM; | ||
| 1360 | |||
| 1361 | if (!try_module_get(dvbdev->adapter->module)) | ||
| 1362 | return -EPERM; | ||
| 1363 | |||
| 1364 | result=dvb_net_add_if(dvbnet, dvbnetif->pid, dvbnetif->feedtype); | ||
| 1365 | if (result<0) { | ||
| 1366 | module_put(dvbdev->adapter->module); | ||
| 1367 | return result; | ||
| 1368 | } | ||
| 1369 | dvbnetif->if_num=result; | ||
| 1370 | break; | ||
| 1371 | } | ||
| 1372 | case NET_GET_IF: | ||
| 1373 | { | ||
| 1374 | struct net_device *netdev; | ||
| 1375 | struct dvb_net_priv *priv_data; | ||
| 1376 | struct dvb_net_if *dvbnetif = parg; | ||
| 1377 | |||
| 1378 | if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX || | ||
| 1379 | !dvbnet->state[dvbnetif->if_num]) | ||
| 1380 | return -EINVAL; | ||
| 1381 | |||
| 1382 | netdev = dvbnet->device[dvbnetif->if_num]; | ||
| 1383 | |||
| 1384 | priv_data = netdev_priv(netdev); | ||
| 1385 | dvbnetif->pid=priv_data->pid; | ||
| 1386 | dvbnetif->feedtype=priv_data->feedtype; | ||
| 1387 | break; | ||
| 1388 | } | ||
| 1389 | case NET_REMOVE_IF: | ||
| 1390 | { | ||
| 1391 | int ret; | ||
| 1392 | |||
| 1393 | if (!capable(CAP_SYS_ADMIN)) | ||
| 1394 | return -EPERM; | ||
| 1395 | if ((unsigned long) parg >= DVB_NET_DEVICES_MAX) | ||
| 1396 | return -EINVAL; | ||
| 1397 | ret = dvb_net_remove_if(dvbnet, (unsigned long) parg); | ||
| 1398 | if (!ret) | ||
| 1399 | module_put(dvbdev->adapter->module); | ||
| 1400 | return ret; | ||
| 1401 | } | ||
| 1402 | |||
| 1403 | /* binary compatibility cruft */ | ||
| 1404 | case __NET_ADD_IF_OLD: | ||
| 1405 | { | ||
| 1406 | struct __dvb_net_if_old *dvbnetif = parg; | ||
| 1407 | int result; | ||
| 1408 | |||
| 1409 | if (!capable(CAP_SYS_ADMIN)) | ||
| 1410 | return -EPERM; | ||
| 1411 | |||
| 1412 | if (!try_module_get(dvbdev->adapter->module)) | ||
| 1413 | return -EPERM; | ||
| 1414 | |||
| 1415 | result=dvb_net_add_if(dvbnet, dvbnetif->pid, DVB_NET_FEEDTYPE_MPE); | ||
| 1416 | if (result<0) { | ||
| 1417 | module_put(dvbdev->adapter->module); | ||
| 1418 | return result; | ||
| 1419 | } | ||
| 1420 | dvbnetif->if_num=result; | ||
| 1421 | break; | ||
| 1422 | } | ||
| 1423 | case __NET_GET_IF_OLD: | ||
| 1424 | { | ||
| 1425 | struct net_device *netdev; | ||
| 1426 | struct dvb_net_priv *priv_data; | ||
| 1427 | struct __dvb_net_if_old *dvbnetif = parg; | ||
| 1428 | |||
| 1429 | if (dvbnetif->if_num >= DVB_NET_DEVICES_MAX || | ||
| 1430 | !dvbnet->state[dvbnetif->if_num]) | ||
| 1431 | return -EINVAL; | ||
| 1432 | |||
| 1433 | netdev = dvbnet->device[dvbnetif->if_num]; | ||
| 1434 | |||
| 1435 | priv_data = netdev_priv(netdev); | ||
| 1436 | dvbnetif->pid=priv_data->pid; | ||
| 1437 | break; | ||
| 1438 | } | ||
| 1439 | default: | ||
| 1440 | return -ENOTTY; | ||
| 1441 | } | ||
| 1442 | return 0; | ||
| 1443 | } | ||
| 1444 | |||
| 1445 | static long dvb_net_ioctl(struct file *file, | ||
| 1446 | unsigned int cmd, unsigned long arg) | ||
| 1447 | { | ||
| 1448 | return dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl); | ||
| 1449 | } | ||
| 1450 | |||
| 1451 | static int dvb_net_close(struct inode *inode, struct file *file) | ||
| 1452 | { | ||
| 1453 | struct dvb_device *dvbdev = file->private_data; | ||
| 1454 | struct dvb_net *dvbnet = dvbdev->priv; | ||
| 1455 | |||
| 1456 | dvb_generic_release(inode, file); | ||
| 1457 | |||
| 1458 | if(dvbdev->users == 1 && dvbnet->exit == 1) { | ||
| 1459 | fops_put(file->f_op); | ||
| 1460 | file->f_op = NULL; | ||
| 1461 | wake_up(&dvbdev->wait_queue); | ||
| 1462 | } | ||
| 1463 | return 0; | ||
| 1464 | } | ||
| 1465 | |||
| 1466 | |||
| 1467 | static const struct file_operations dvb_net_fops = { | ||
| 1468 | .owner = THIS_MODULE, | ||
| 1469 | .unlocked_ioctl = dvb_net_ioctl, | ||
| 1470 | .open = dvb_generic_open, | ||
| 1471 | .release = dvb_net_close, | ||
| 1472 | .llseek = noop_llseek, | ||
| 1473 | }; | ||
| 1474 | |||
| 1475 | static struct dvb_device dvbdev_net = { | ||
| 1476 | .priv = NULL, | ||
| 1477 | .users = 1, | ||
| 1478 | .writers = 1, | ||
| 1479 | .fops = &dvb_net_fops, | ||
| 1480 | }; | ||
| 1481 | |||
| 1482 | |||
| 1483 | void dvb_net_release (struct dvb_net *dvbnet) | ||
| 1484 | { | ||
| 1485 | int i; | ||
| 1486 | |||
| 1487 | dvbnet->exit = 1; | ||
| 1488 | if (dvbnet->dvbdev->users < 1) | ||
| 1489 | wait_event(dvbnet->dvbdev->wait_queue, | ||
| 1490 | dvbnet->dvbdev->users==1); | ||
| 1491 | |||
| 1492 | dvb_unregister_device(dvbnet->dvbdev); | ||
| 1493 | |||
| 1494 | for (i=0; i<DVB_NET_DEVICES_MAX; i++) { | ||
| 1495 | if (!dvbnet->state[i]) | ||
| 1496 | continue; | ||
| 1497 | dvb_net_remove_if(dvbnet, i); | ||
| 1498 | } | ||
| 1499 | } | ||
| 1500 | EXPORT_SYMBOL(dvb_net_release); | ||
| 1501 | |||
| 1502 | |||
| 1503 | int dvb_net_init (struct dvb_adapter *adap, struct dvb_net *dvbnet, | ||
| 1504 | struct dmx_demux *dmx) | ||
| 1505 | { | ||
| 1506 | int i; | ||
| 1507 | |||
| 1508 | dvbnet->demux = dmx; | ||
| 1509 | |||
| 1510 | for (i=0; i<DVB_NET_DEVICES_MAX; i++) | ||
| 1511 | dvbnet->state[i] = 0; | ||
| 1512 | |||
| 1513 | dvb_register_device (adap, &dvbnet->dvbdev, &dvbdev_net, | ||
| 1514 | dvbnet, DVB_DEVICE_NET); | ||
| 1515 | |||
| 1516 | return 0; | ||
| 1517 | } | ||
| 1518 | 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 new file mode 100644 index 00000000000..1e53acd50cf --- /dev/null +++ b/drivers/media/dvb/dvb-core/dvb_net.h | |||
| @@ -0,0 +1,66 @@ | |||
| 1 | /* | ||
| 2 | * dvb_net.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2001 Ralph Metzler for convergence integrated media GmbH | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or | ||
| 7 | * modify it under the terms of the GNU Lesser General Public License | ||
| 8 | * as published by the Free Software Foundation; either version 2.1 | ||
| 9 | * of the License, or (at your option) any later version. | ||
| 10 | * | ||
| 11 | * This program is distributed in the hope that it will be useful, | ||
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | * GNU General Public License for more details. | ||
| 15 | * | ||
| 16 | * You should have received a copy of the GNU Lesser General Public License | ||
| 17 | * along with this program; if not, write to the Free Software | ||
| 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 19 | * | ||
| 20 | */ | ||
| 21 | |||
| 22 | #ifndef _DVB_NET_H_ | ||
| 23 | #define _DVB_NET_H_ | ||
| 24 | |||
| 25 | #include <linux/module.h> | ||
| 26 | #include <linux/netdevice.h> | ||
| 27 | #include <linux/inetdevice.h> | ||
| 28 | #include <linux/etherdevice.h> | ||
| 29 | #include <linux/skbuff.h> | ||
| 30 | |||
| 31 | #include "dvbdev.h" | ||
| 32 | |||
| 33 | #define DVB_NET_DEVICES_MAX 10 | ||
| 34 | |||
| 35 | #ifdef CONFIG_DVB_NET | ||
| 36 | |||
| 37 | struct dvb_net { | ||
| 38 | struct dvb_device *dvbdev; | ||
| 39 | struct net_device *device[DVB_NET_DEVICES_MAX]; | ||
| 40 | int state[DVB_NET_DEVICES_MAX]; | ||
| 41 | unsigned int exit:1; | ||
| 42 | struct dmx_demux *demux; | ||
| 43 | }; | ||
| 44 | |||
| 45 | void dvb_net_release(struct dvb_net *); | ||
| 46 | int dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *); | ||
| 47 | |||
| 48 | #else | ||
| 49 | |||
| 50 | struct dvb_net { | ||
| 51 | struct dvb_device *dvbdev; | ||
| 52 | }; | ||
| 53 | |||
| 54 | static inline void dvb_net_release(struct dvb_net *dvbnet) | ||
| 55 | { | ||
| 56 | } | ||
| 57 | |||
| 58 | static inline int dvb_net_init(struct dvb_adapter *adap, | ||
| 59 | struct dvb_net *dvbnet, struct dmx_demux *dmx) | ||
| 60 | { | ||
| 61 | return 0; | ||
| 62 | } | ||
| 63 | |||
| 64 | #endif /* ifdef CONFIG_DVB_NET */ | ||
| 65 | |||
| 66 | #endif | ||
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c new file mode 100644 index 00000000000..a5712cd7c65 --- /dev/null +++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.c | |||
| @@ -0,0 +1,299 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * dvb_ringbuffer.c: ring buffer implementation for the dvb driver | ||
| 4 | * | ||
| 5 | * Copyright (C) 2003 Oliver Endriss | ||
| 6 | * Copyright (C) 2004 Andrew de Quincey | ||
| 7 | * | ||
| 8 | * based on code originally found in av7110.c & dvb_ci.c: | ||
| 9 | * Copyright (C) 1999-2003 Ralph Metzler | ||
| 10 | * & Marcus Metzler for convergence integrated media GmbH | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or | ||
| 13 | * modify it under the terms of the GNU Lesser General Public License | ||
| 14 | * as published by the Free Software Foundation; either version 2.1 | ||
| 15 | * of the License, or (at your option) any later version. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU Lesser General Public License for more details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU Lesser General Public License | ||
| 23 | * along with this program; if not, write to the Free Software | ||
| 24 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 25 | */ | ||
| 26 | |||
| 27 | |||
| 28 | |||
| 29 | #include <linux/errno.h> | ||
| 30 | #include <linux/kernel.h> | ||
| 31 | #include <linux/module.h> | ||
| 32 | #include <linux/sched.h> | ||
| 33 | #include <linux/string.h> | ||
| 34 | #include <asm/uaccess.h> | ||
| 35 | |||
| 36 | #include "dvb_ringbuffer.h" | ||
| 37 | |||
| 38 | #define PKT_READY 0 | ||
| 39 | #define PKT_DISPOSED 1 | ||
| 40 | |||
| 41 | |||
| 42 | void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len) | ||
| 43 | { | ||
| 44 | rbuf->pread=rbuf->pwrite=0; | ||
| 45 | rbuf->data=data; | ||
| 46 | rbuf->size=len; | ||
| 47 | rbuf->error=0; | ||
| 48 | |||
| 49 | init_waitqueue_head(&rbuf->queue); | ||
| 50 | |||
| 51 | spin_lock_init(&(rbuf->lock)); | ||
| 52 | } | ||
| 53 | |||
| 54 | |||
| 55 | |||
| 56 | int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf) | ||
| 57 | { | ||
| 58 | return (rbuf->pread==rbuf->pwrite); | ||
| 59 | } | ||
| 60 | |||
| 61 | |||
| 62 | |||
| 63 | ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf) | ||
| 64 | { | ||
| 65 | ssize_t free; | ||
| 66 | |||
| 67 | free = rbuf->pread - rbuf->pwrite; | ||
| 68 | if (free <= 0) | ||
| 69 | free += rbuf->size; | ||
| 70 | return free-1; | ||
| 71 | } | ||
| 72 | |||
| 73 | |||
| 74 | |||
| 75 | ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf) | ||
| 76 | { | ||
| 77 | ssize_t avail; | ||
| 78 | |||
| 79 | avail = rbuf->pwrite - rbuf->pread; | ||
| 80 | if (avail < 0) | ||
| 81 | avail += rbuf->size; | ||
| 82 | return avail; | ||
| 83 | } | ||
| 84 | |||
| 85 | |||
| 86 | |||
| 87 | void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf) | ||
| 88 | { | ||
| 89 | rbuf->pread = rbuf->pwrite; | ||
| 90 | rbuf->error = 0; | ||
| 91 | } | ||
| 92 | EXPORT_SYMBOL(dvb_ringbuffer_flush); | ||
| 93 | |||
| 94 | void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf) | ||
| 95 | { | ||
| 96 | rbuf->pread = rbuf->pwrite = 0; | ||
| 97 | rbuf->error = 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf) | ||
| 101 | { | ||
| 102 | unsigned long flags; | ||
| 103 | |||
| 104 | spin_lock_irqsave(&rbuf->lock, flags); | ||
| 105 | dvb_ringbuffer_flush(rbuf); | ||
| 106 | spin_unlock_irqrestore(&rbuf->lock, flags); | ||
| 107 | |||
| 108 | wake_up(&rbuf->queue); | ||
| 109 | } | ||
| 110 | |||
| 111 | ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, u8 __user *buf, size_t len) | ||
| 112 | { | ||
| 113 | size_t todo = len; | ||
| 114 | size_t split; | ||
| 115 | |||
| 116 | split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0; | ||
| 117 | if (split > 0) { | ||
| 118 | if (copy_to_user(buf, rbuf->data+rbuf->pread, split)) | ||
| 119 | return -EFAULT; | ||
| 120 | buf += split; | ||
| 121 | todo -= split; | ||
| 122 | rbuf->pread = 0; | ||
| 123 | } | ||
| 124 | if (copy_to_user(buf, rbuf->data+rbuf->pread, todo)) | ||
| 125 | return -EFAULT; | ||
| 126 | |||
| 127 | rbuf->pread = (rbuf->pread + todo) % rbuf->size; | ||
| 128 | |||
| 129 | return len; | ||
| 130 | } | ||
| 131 | |||
| 132 | void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, u8 *buf, size_t len) | ||
| 133 | { | ||
| 134 | size_t todo = len; | ||
| 135 | size_t split; | ||
| 136 | |||
| 137 | split = (rbuf->pread + len > rbuf->size) ? rbuf->size - rbuf->pread : 0; | ||
| 138 | if (split > 0) { | ||
| 139 | memcpy(buf, rbuf->data+rbuf->pread, split); | ||
| 140 | buf += split; | ||
| 141 | todo -= split; | ||
| 142 | rbuf->pread = 0; | ||
| 143 | } | ||
| 144 | memcpy(buf, rbuf->data+rbuf->pread, todo); | ||
| 145 | |||
| 146 | rbuf->pread = (rbuf->pread + todo) % rbuf->size; | ||
| 147 | } | ||
| 148 | |||
| 149 | |||
| 150 | ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, size_t len) | ||
| 151 | { | ||
| 152 | size_t todo = len; | ||
| 153 | size_t split; | ||
| 154 | |||
| 155 | split = (rbuf->pwrite + len > rbuf->size) ? rbuf->size - rbuf->pwrite : 0; | ||
| 156 | |||
| 157 | if (split > 0) { | ||
| 158 | memcpy(rbuf->data+rbuf->pwrite, buf, split); | ||
| 159 | buf += split; | ||
| 160 | todo -= split; | ||
| 161 | rbuf->pwrite = 0; | ||
| 162 | } | ||
| 163 | memcpy(rbuf->data+rbuf->pwrite, buf, todo); | ||
| 164 | rbuf->pwrite = (rbuf->pwrite + todo) % rbuf->size; | ||
| 165 | |||
| 166 | return len; | ||
| 167 | } | ||
| 168 | |||
| 169 | ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, size_t len) | ||
| 170 | { | ||
| 171 | int status; | ||
| 172 | ssize_t oldpwrite = rbuf->pwrite; | ||
| 173 | |||
| 174 | DVB_RINGBUFFER_WRITE_BYTE(rbuf, len >> 8); | ||
| 175 | DVB_RINGBUFFER_WRITE_BYTE(rbuf, len & 0xff); | ||
| 176 | DVB_RINGBUFFER_WRITE_BYTE(rbuf, PKT_READY); | ||
| 177 | status = dvb_ringbuffer_write(rbuf, buf, len); | ||
| 178 | |||
| 179 | if (status < 0) rbuf->pwrite = oldpwrite; | ||
| 180 | return status; | ||
| 181 | } | ||
| 182 | |||
| 183 | ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx, | ||
| 184 | int offset, u8 __user *buf, size_t len) | ||
| 185 | { | ||
| 186 | size_t todo; | ||
| 187 | size_t split; | ||
| 188 | size_t pktlen; | ||
| 189 | |||
| 190 | pktlen = rbuf->data[idx] << 8; | ||
| 191 | pktlen |= rbuf->data[(idx + 1) % rbuf->size]; | ||
| 192 | if (offset > pktlen) return -EINVAL; | ||
| 193 | if ((offset + len) > pktlen) len = pktlen - offset; | ||
| 194 | |||
| 195 | idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size; | ||
| 196 | todo = len; | ||
| 197 | split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0; | ||
| 198 | if (split > 0) { | ||
| 199 | if (copy_to_user(buf, rbuf->data+idx, split)) | ||
| 200 | return -EFAULT; | ||
| 201 | buf += split; | ||
| 202 | todo -= split; | ||
| 203 | idx = 0; | ||
| 204 | } | ||
| 205 | if (copy_to_user(buf, rbuf->data+idx, todo)) | ||
| 206 | return -EFAULT; | ||
| 207 | |||
| 208 | return len; | ||
| 209 | } | ||
| 210 | |||
| 211 | ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, | ||
| 212 | int offset, u8* buf, size_t len) | ||
| 213 | { | ||
| 214 | size_t todo; | ||
| 215 | size_t split; | ||
| 216 | size_t pktlen; | ||
| 217 | |||
| 218 | pktlen = rbuf->data[idx] << 8; | ||
| 219 | pktlen |= rbuf->data[(idx + 1) % rbuf->size]; | ||
| 220 | if (offset > pktlen) return -EINVAL; | ||
| 221 | if ((offset + len) > pktlen) len = pktlen - offset; | ||
| 222 | |||
| 223 | idx = (idx + DVB_RINGBUFFER_PKTHDRSIZE + offset) % rbuf->size; | ||
| 224 | todo = len; | ||
| 225 | split = ((idx + len) > rbuf->size) ? rbuf->size - idx : 0; | ||
| 226 | if (split > 0) { | ||
| 227 | memcpy(buf, rbuf->data+idx, split); | ||
| 228 | buf += split; | ||
| 229 | todo -= split; | ||
| 230 | idx = 0; | ||
| 231 | } | ||
| 232 | memcpy(buf, rbuf->data+idx, todo); | ||
| 233 | return len; | ||
| 234 | } | ||
| 235 | |||
| 236 | void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx) | ||
| 237 | { | ||
| 238 | size_t pktlen; | ||
| 239 | |||
| 240 | rbuf->data[(idx + 2) % rbuf->size] = PKT_DISPOSED; | ||
| 241 | |||
| 242 | // clean up disposed packets | ||
| 243 | while(dvb_ringbuffer_avail(rbuf) > DVB_RINGBUFFER_PKTHDRSIZE) { | ||
| 244 | if (DVB_RINGBUFFER_PEEK(rbuf, 2) == PKT_DISPOSED) { | ||
| 245 | pktlen = DVB_RINGBUFFER_PEEK(rbuf, 0) << 8; | ||
| 246 | pktlen |= DVB_RINGBUFFER_PEEK(rbuf, 1); | ||
| 247 | DVB_RINGBUFFER_SKIP(rbuf, pktlen + DVB_RINGBUFFER_PKTHDRSIZE); | ||
| 248 | } else { | ||
| 249 | // first packet is not disposed, so we stop cleaning now | ||
| 250 | break; | ||
| 251 | } | ||
| 252 | } | ||
| 253 | } | ||
| 254 | |||
| 255 | ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen) | ||
| 256 | { | ||
| 257 | int consumed; | ||
| 258 | int curpktlen; | ||
| 259 | int curpktstatus; | ||
| 260 | |||
| 261 | if (idx == -1) { | ||
| 262 | idx = rbuf->pread; | ||
| 263 | } else { | ||
| 264 | curpktlen = rbuf->data[idx] << 8; | ||
| 265 | curpktlen |= rbuf->data[(idx + 1) % rbuf->size]; | ||
| 266 | idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size; | ||
| 267 | } | ||
| 268 | |||
| 269 | consumed = (idx - rbuf->pread) % rbuf->size; | ||
| 270 | |||
| 271 | while((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) { | ||
| 272 | |||
| 273 | curpktlen = rbuf->data[idx] << 8; | ||
| 274 | curpktlen |= rbuf->data[(idx + 1) % rbuf->size]; | ||
| 275 | curpktstatus = rbuf->data[(idx + 2) % rbuf->size]; | ||
| 276 | |||
| 277 | if (curpktstatus == PKT_READY) { | ||
| 278 | *pktlen = curpktlen; | ||
| 279 | return idx; | ||
| 280 | } | ||
| 281 | |||
| 282 | consumed += curpktlen + DVB_RINGBUFFER_PKTHDRSIZE; | ||
| 283 | idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size; | ||
| 284 | } | ||
| 285 | |||
| 286 | // no packets available | ||
| 287 | return -1; | ||
| 288 | } | ||
| 289 | |||
| 290 | |||
| 291 | |||
| 292 | EXPORT_SYMBOL(dvb_ringbuffer_init); | ||
| 293 | EXPORT_SYMBOL(dvb_ringbuffer_empty); | ||
| 294 | EXPORT_SYMBOL(dvb_ringbuffer_free); | ||
| 295 | EXPORT_SYMBOL(dvb_ringbuffer_avail); | ||
| 296 | EXPORT_SYMBOL(dvb_ringbuffer_flush_spinlock_wakeup); | ||
| 297 | EXPORT_SYMBOL(dvb_ringbuffer_read_user); | ||
| 298 | EXPORT_SYMBOL(dvb_ringbuffer_read); | ||
| 299 | EXPORT_SYMBOL(dvb_ringbuffer_write); | ||
diff --git a/drivers/media/dvb/dvb-core/dvb_ringbuffer.h b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h new file mode 100644 index 00000000000..41f04dae69b --- /dev/null +++ b/drivers/media/dvb/dvb-core/dvb_ringbuffer.h | |||
| @@ -0,0 +1,186 @@ | |||
| 1 | /* | ||
| 2 | * | ||
| 3 | * dvb_ringbuffer.h: ring buffer implementation for the dvb driver | ||
| 4 | * | ||
| 5 | * Copyright (C) 2003 Oliver Endriss | ||
| 6 | * Copyright (C) 2004 Andrew de Quincey | ||
| 7 | * | ||
| 8 | * based on code originally found in av7110.c & dvb_ci.c: | ||
| 9 | * Copyright (C) 1999-2003 Ralph Metzler & Marcus Metzler | ||
| 10 | * for convergence integrated media GmbH | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or | ||
| 13 | * modify it under the terms of the GNU Lesser General Public License | ||
| 14 | * as published by the Free Software Foundation; either version 2.1 | ||
| 15 | * of the License, or (at your option) any later version. | ||
| 16 | * | ||
| 17 | * This program is distributed in the hope that it will be useful, | ||
| 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 20 | * GNU Lesser General Public License for more details. | ||
| 21 | * | ||
| 22 | * You should have received a copy of the GNU Lesser General Public License | ||
| 23 | * along with this program; if not, write to the Free Software | ||
| 24 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 25 | */ | ||
| 26 | |||
| 27 | #ifndef _DVB_RINGBUFFER_H_ | ||
| 28 | #define _DVB_RINGBUFFER_H_ | ||
| 29 | |||
| 30 | #include <linux/spinlock.h> | ||
| 31 | #include <linux/wait.h> | ||
| 32 | |||
| 33 | struct dvb_ringbuffer { | ||
| 34 | u8 *data; | ||
| 35 | ssize_t size; | ||
| 36 | ssize_t pread; | ||
| 37 | ssize_t pwrite; | ||
| 38 | int error; | ||
| 39 | |||
| 40 | wait_queue_head_t queue; | ||
| 41 | spinlock_t lock; | ||
| 42 | }; | ||
| 43 | |||
| 44 | #define DVB_RINGBUFFER_PKTHDRSIZE 3 | ||
| 45 | |||
| 46 | |||
| 47 | /* | ||
| 48 | ** Notes: | ||
| 49 | ** ------ | ||
| 50 | ** (1) For performance reasons read and write routines don't check buffer sizes | ||
| 51 | ** and/or number of bytes free/available. This has to be done before these | ||
| 52 | ** routines are called. For example: | ||
| 53 | ** | ||
| 54 | ** *** write <buflen> bytes *** | ||
| 55 | ** free = dvb_ringbuffer_free(rbuf); | ||
| 56 | ** if (free >= buflen) | ||
| 57 | ** count = dvb_ringbuffer_write(rbuf, buffer, buflen); | ||
| 58 | ** else | ||
| 59 | ** ... | ||
| 60 | ** | ||
| 61 | ** *** read min. 1000, max. <bufsize> bytes *** | ||
| 62 | ** avail = dvb_ringbuffer_avail(rbuf); | ||
| 63 | ** if (avail >= 1000) | ||
| 64 | ** count = dvb_ringbuffer_read(rbuf, buffer, min(avail, bufsize)); | ||
| 65 | ** else | ||
| 66 | ** ... | ||
| 67 | ** | ||
| 68 | ** (2) If there is exactly one reader and one writer, there is no need | ||
| 69 | ** to lock read or write operations. | ||
| 70 | ** Two or more readers must be locked against each other. | ||
| 71 | ** Flushing the buffer counts as a read operation. | ||
| 72 | ** Resetting the buffer counts as a read and write operation. | ||
| 73 | ** Two or more writers must be locked against each other. | ||
| 74 | */ | ||
| 75 | |||
| 76 | /* initialize ring buffer, lock and queue */ | ||
| 77 | extern void dvb_ringbuffer_init(struct dvb_ringbuffer *rbuf, void *data, size_t len); | ||
| 78 | |||
| 79 | /* test whether buffer is empty */ | ||
| 80 | extern int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf); | ||
| 81 | |||
| 82 | /* return the number of free bytes in the buffer */ | ||
| 83 | extern ssize_t dvb_ringbuffer_free(struct dvb_ringbuffer *rbuf); | ||
| 84 | |||
| 85 | /* return the number of bytes waiting in the buffer */ | ||
| 86 | extern ssize_t dvb_ringbuffer_avail(struct dvb_ringbuffer *rbuf); | ||
| 87 | |||
| 88 | |||
| 89 | /* | ||
| 90 | ** Reset the read and write pointers to zero and flush the buffer | ||
| 91 | ** This counts as a read and write operation | ||
| 92 | */ | ||
| 93 | extern void dvb_ringbuffer_reset(struct dvb_ringbuffer *rbuf); | ||
| 94 | |||
| 95 | |||
| 96 | /* read routines & macros */ | ||
| 97 | /* ---------------------- */ | ||
| 98 | /* flush buffer */ | ||
| 99 | extern void dvb_ringbuffer_flush(struct dvb_ringbuffer *rbuf); | ||
| 100 | |||
| 101 | /* flush buffer protected by spinlock and wake-up waiting task(s) */ | ||
| 102 | extern void dvb_ringbuffer_flush_spinlock_wakeup(struct dvb_ringbuffer *rbuf); | ||
| 103 | |||
| 104 | /* peek at byte <offs> in the buffer */ | ||
| 105 | #define DVB_RINGBUFFER_PEEK(rbuf,offs) \ | ||
| 106 | (rbuf)->data[((rbuf)->pread+(offs))%(rbuf)->size] | ||
| 107 | |||
| 108 | /* advance read ptr by <num> bytes */ | ||
| 109 | #define DVB_RINGBUFFER_SKIP(rbuf,num) \ | ||
| 110 | (rbuf)->pread=((rbuf)->pread+(num))%(rbuf)->size | ||
| 111 | |||
| 112 | /* | ||
| 113 | ** read <len> bytes from ring buffer into <buf> | ||
| 114 | ** <usermem> specifies whether <buf> resides in user space | ||
| 115 | ** returns number of bytes transferred or -EFAULT | ||
| 116 | */ | ||
| 117 | extern ssize_t dvb_ringbuffer_read_user(struct dvb_ringbuffer *rbuf, | ||
| 118 | u8 __user *buf, size_t len); | ||
| 119 | extern void dvb_ringbuffer_read(struct dvb_ringbuffer *rbuf, | ||
| 120 | u8 *buf, size_t len); | ||
| 121 | |||
| 122 | |||
| 123 | /* write routines & macros */ | ||
| 124 | /* ----------------------- */ | ||
| 125 | /* write single byte to ring buffer */ | ||
| 126 | #define DVB_RINGBUFFER_WRITE_BYTE(rbuf,byte) \ | ||
| 127 | { (rbuf)->data[(rbuf)->pwrite]=(byte); \ | ||
| 128 | (rbuf)->pwrite=((rbuf)->pwrite+1)%(rbuf)->size; } | ||
| 129 | /* | ||
| 130 | ** write <len> bytes to ring buffer | ||
| 131 | ** <usermem> specifies whether <buf> resides in user space | ||
| 132 | ** returns number of bytes transferred or -EFAULT | ||
| 133 | */ | ||
| 134 | extern ssize_t dvb_ringbuffer_write(struct dvb_ringbuffer *rbuf, const u8 *buf, | ||
| 135 | size_t len); | ||
| 136 | |||
| 137 | |||
| 138 | /** | ||
| 139 | * Write a packet into the ringbuffer. | ||
| 140 | * | ||
| 141 | * <rbuf> Ringbuffer to write to. | ||
| 142 | * <buf> Buffer to write. | ||
| 143 | * <len> Length of buffer (currently limited to 65535 bytes max). | ||
| 144 | * returns Number of bytes written, or -EFAULT, -ENOMEM, -EVINAL. | ||
| 145 | */ | ||
| 146 | extern ssize_t dvb_ringbuffer_pkt_write(struct dvb_ringbuffer *rbuf, u8* buf, | ||
| 147 | size_t len); | ||
| 148 | |||
| 149 | /** | ||
| 150 | * Read from a packet in the ringbuffer. Note: unlike dvb_ringbuffer_read(), this | ||
| 151 | * does NOT update the read pointer in the ringbuffer. You must use | ||
| 152 | * dvb_ringbuffer_pkt_dispose() to mark a packet as no longer required. | ||
| 153 | * | ||
| 154 | * <rbuf> Ringbuffer concerned. | ||
| 155 | * <idx> Packet index as returned by dvb_ringbuffer_pkt_next(). | ||
| 156 | * <offset> Offset into packet to read from. | ||
| 157 | * <buf> Destination buffer for data. | ||
| 158 | * <len> Size of destination buffer. | ||
| 159 | * <usermem> Set to 1 if <buf> is in userspace. | ||
| 160 | * returns Number of bytes read, or -EFAULT. | ||
| 161 | */ | ||
| 162 | extern ssize_t dvb_ringbuffer_pkt_read_user(struct dvb_ringbuffer *rbuf, size_t idx, | ||
| 163 | int offset, u8 __user *buf, size_t len); | ||
| 164 | extern ssize_t dvb_ringbuffer_pkt_read(struct dvb_ringbuffer *rbuf, size_t idx, | ||
| 165 | int offset, u8 *buf, size_t len); | ||
| 166 | |||
| 167 | /** | ||
| 168 | * Dispose of a packet in the ring buffer. | ||
| 169 | * | ||
| 170 | * <rbuf> Ring buffer concerned. | ||
| 171 | * <idx> Packet index as returned by dvb_ringbuffer_pkt_next(). | ||
| 172 | */ | ||
| 173 | extern void dvb_ringbuffer_pkt_dispose(struct dvb_ringbuffer *rbuf, size_t idx); | ||
| 174 | |||
| 175 | /** | ||
| 176 | * Get the index of the next packet in a ringbuffer. | ||
| 177 | * | ||
| 178 | * <rbuf> Ringbuffer concerned. | ||
| 179 | * <idx> Previous packet index, or -1 to return the first packet index. | ||
| 180 | * <pktlen> On success, will be updated to contain the length of the packet in bytes. | ||
| 181 | * returns Packet index (if >=0), or -1 if no packets available. | ||
| 182 | */ | ||
| 183 | extern ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* pktlen); | ||
| 184 | |||
| 185 | |||
| 186 | #endif /* _DVB_RINGBUFFER_H_ */ | ||
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c new file mode 100644 index 00000000000..f7328777595 --- /dev/null +++ b/drivers/media/dvb/dvb-core/dvbdev.c | |||
| @@ -0,0 +1,506 @@ | |||
| 1 | /* | ||
| 2 | * dvbdev.c | ||
| 3 | * | ||
| 4 | * Copyright (C) 2000 Ralph Metzler <ralph@convergence.de> | ||
| 5 | * & Marcus Metzler <marcus@convergence.de> | ||
| 6 | * for convergence integrated media GmbH | ||
| 7 | * | ||
| 8 | * This program is free software; you can redistribute it and/or | ||
| 9 | * modify it under the terms of the GNU Lesser General Public License | ||
| 10 | * as published by the Free Software Foundation; either version 2.1 | ||
| 11 | * of the License, or (at your option) any later version. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope that it will be useful, | ||
| 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 16 | * GNU General Public License for more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU Lesser General Public License | ||
| 19 | * along with this program; if not, write to the Free Software | ||
| 20 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 21 | * | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/types.h> | ||
| 25 | #include <linux/errno.h> | ||
| 26 | #include <linux/string.h> | ||
| 27 | #include <linux/module.h> | ||
| 28 | #include <linux/kernel.h> | ||
| 29 | #include <linux/init.h> | ||
| 30 | #include <linux/slab.h> | ||
| 31 | #include <linux/device.h> | ||
| 32 | #include <linux/fs.h> | ||
| 33 | #include <linux/cdev.h> | ||
| 34 | #include <linux/mutex.h> | ||
| 35 | #include "dvbdev.h" | ||
| 36 | |||
| 37 | static DEFINE_MUTEX(dvbdev_mutex); | ||
| 38 | static int dvbdev_debug; | ||
| 39 | |||
| 40 | module_param(dvbdev_debug, int, 0644); | ||
| 41 | MODULE_PARM_DESC(dvbdev_debug, "Turn on/off device debugging (default:off)."); | ||
| 42 | |||
| 43 | #define dprintk if (dvbdev_debug) printk | ||
| 44 | |||
| 45 | static LIST_HEAD(dvb_adapter_list); | ||
| 46 | static DEFINE_MUTEX(dvbdev_register_lock); | ||
| 47 | |||
| 48 | static const char * const dnames[] = { | ||
| 49 | "video", "audio", "sec", "frontend", "demux", "dvr", "ca", | ||
| 50 | "net", "osd" | ||
| 51 | }; | ||
| 52 | |||
| 53 | #ifdef CONFIG_DVB_DYNAMIC_MINORS | ||
| 54 | #define MAX_DVB_MINORS 256 | ||
| 55 | #define DVB_MAX_IDS MAX_DVB_MINORS | ||
| 56 | #else | ||
| 57 | #define DVB_MAX_IDS 4 | ||
| 58 | #define nums2minor(num,type,id) ((num << 6) | (id << 4) | type) | ||
| 59 | #define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64) | ||
| 60 | #endif | ||
| 61 | |||
| 62 | static struct class *dvb_class; | ||
| 63 | |||
| 64 | static struct dvb_device *dvb_minors[MAX_DVB_MINORS]; | ||
| 65 | static DECLARE_RWSEM(minor_rwsem); | ||
| 66 | |||
| 67 | static int dvb_device_open(struct inode *inode, struct file *file) | ||
| 68 | { | ||
| 69 | struct dvb_device *dvbdev; | ||
| 70 | |||
| 71 | mutex_lock(&dvbdev_mutex); | ||
| 72 | down_read(&minor_rwsem); | ||
| 73 | dvbdev = dvb_minors[iminor(inode)]; | ||
| 74 | |||
| 75 | if (dvbdev && dvbdev->fops) { | ||
| 76 | int err = 0; | ||
| 77 | const struct file_operations *old_fops; | ||
| 78 | |||
| 79 | file->private_data = dvbdev; | ||
| 80 | old_fops = file->f_op; | ||
| 81 | file->f_op = fops_get(dvbdev->fops); | ||
| 82 | if (file->f_op == NULL) { | ||
| 83 | file->f_op = old_fops; | ||
| 84 | goto fail; | ||
| 85 | } | ||
| 86 | if(file->f_op->open) | ||
| 87 | err = file->f_op->open(inode,file); | ||
| 88 | if (err) { | ||
| 89 | fops_put(file->f_op); | ||
| 90 | file->f_op = fops_get(old_fops); | ||
| 91 | } | ||
| 92 | fops_put(old_fops); | ||
| 93 | up_read(&minor_rwsem); | ||
| 94 | mutex_unlock(&dvbdev_mutex); | ||
| 95 | return err; | ||
| 96 | } | ||
| 97 | fail: | ||
| 98 | up_read(&minor_rwsem); | ||
| 99 | mutex_unlock(&dvbdev_mutex); | ||
| 100 | return -ENODEV; | ||
| 101 | } | ||
| 102 | |||
| 103 | |||
| 104 | static const struct file_operations dvb_device_fops = | ||
| 105 | { | ||
| 106 | .owner = THIS_MODULE, | ||
| 107 | .open = dvb_device_open, | ||
| 108 | .llseek = noop_llseek, | ||
| 109 | }; | ||
| 110 | |||
| 111 | static struct cdev dvb_device_cdev; | ||
| 112 | |||
| 113 | int dvb_generic_open(struct inode *inode, struct file *file) | ||
| 114 | { | ||
| 115 | struct dvb_device *dvbdev = file->private_data; | ||
| 116 | |||
| 117 | if (!dvbdev) | ||
| 118 | return -ENODEV; | ||
| 119 | |||
| 120 | if (!dvbdev->users) | ||
| 121 | return -EBUSY; | ||
| 122 | |||
| 123 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) { | ||
| 124 | if (!dvbdev->readers) | ||
| 125 | return -EBUSY; | ||
| 126 | dvbdev->readers--; | ||
| 127 | } else { | ||
| 128 | if (!dvbdev->writers) | ||
| 129 | return -EBUSY; | ||
| 130 | dvbdev->writers--; | ||
| 131 | } | ||
| 132 | |||
| 133 | dvbdev->users--; | ||
| 134 | return 0; | ||
| 135 | } | ||
| 136 | EXPORT_SYMBOL(dvb_generic_open); | ||
| 137 | |||
| 138 | |||
| 139 | int dvb_generic_release(struct inode *inode, struct file *file) | ||
| 140 | { | ||
| 141 | struct dvb_device *dvbdev = file->private_data; | ||
| 142 | |||
| 143 | if (!dvbdev) | ||
| 144 | return -ENODEV; | ||
| 145 | |||
| 146 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) { | ||
| 147 | dvbdev->readers++; | ||
| 148 | } else { | ||
| 149 | dvbdev->writers++; | ||
| 150 | } | ||
| 151 | |||
| 152 | dvbdev->users++; | ||
| 153 | return 0; | ||
| 154 | } | ||
| 155 | EXPORT_SYMBOL(dvb_generic_release); | ||
| 156 | |||
| 157 | |||
| 158 | long dvb_generic_ioctl(struct file *file, | ||
| 159 | unsigned int cmd, unsigned long arg) | ||
| 160 | { | ||
| 161 | struct dvb_device *dvbdev = file->private_data; | ||
| 162 | |||
| 163 | if (!dvbdev) | ||
| 164 | return -ENODEV; | ||
| 165 | |||
| 166 | if (!dvbdev->kernel_ioctl) | ||
| 167 | return -EINVAL; | ||
| 168 | |||
| 169 | return dvb_usercopy(file, cmd, arg, dvbdev->kernel_ioctl); | ||
| 170 | } | ||
| 171 | EXPORT_SYMBOL(dvb_generic_ioctl); | ||
| 172 | |||
| 173 | |||
| 174 | static int dvbdev_get_free_id (struct dvb_adapter *adap, int type) | ||
| 175 | { | ||
| 176 | u32 id = 0; | ||
| 177 | |||
| 178 | while (id < DVB_MAX_IDS) { | ||
| 179 | struct dvb_device *dev; | ||
| 180 | list_for_each_entry(dev, &adap->device_list, list_head) | ||
| 181 | if (dev->type == type && dev->id == id) | ||
| 182 | goto skip; | ||
| 183 | return id; | ||
| 184 | skip: | ||
| 185 | id++; | ||
| 186 | } | ||
| 187 | return -ENFILE; | ||
| 188 | } | ||
| 189 | |||
| 190 | |||
| 191 | int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, | ||
| 192 | const struct dvb_device *template, void *priv, int type) | ||
| 193 | { | ||
| 194 | struct dvb_device *dvbdev; | ||
| 195 | struct file_operations *dvbdevfops; | ||
| 196 | struct device *clsdev; | ||
| 197 | int minor; | ||
| 198 | int id; | ||
| 199 | |||
| 200 | mutex_lock(&dvbdev_register_lock); | ||
| 201 | |||
| 202 | if ((id = dvbdev_get_free_id (adap, type)) < 0){ | ||
| 203 | mutex_unlock(&dvbdev_register_lock); | ||
| 204 | *pdvbdev = NULL; | ||
| 205 | printk(KERN_ERR "%s: couldn't find free device id\n", __func__); | ||
| 206 | return -ENFILE; | ||
| 207 | } | ||
| 208 | |||
| 209 | *pdvbdev = dvbdev = kmalloc(sizeof(struct dvb_device), GFP_KERNEL); | ||
| 210 | |||
| 211 | if (!dvbdev){ | ||
| 212 | mutex_unlock(&dvbdev_register_lock); | ||
| 213 | return -ENOMEM; | ||
| 214 | } | ||
| 215 | |||
| 216 | dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL); | ||
| 217 | |||
| 218 | if (!dvbdevfops){ | ||
| 219 | kfree (dvbdev); | ||
| 220 | mutex_unlock(&dvbdev_register_lock); | ||
| 221 | return -ENOMEM; | ||
| 222 | } | ||
| 223 | |||
| 224 | memcpy(dvbdev, template, sizeof(struct dvb_device)); | ||
| 225 | dvbdev->type = type; | ||
| 226 | dvbdev->id = id; | ||
| 227 | dvbdev->adapter = adap; | ||
| 228 | dvbdev->priv = priv; | ||
| 229 | dvbdev->fops = dvbdevfops; | ||
| 230 | init_waitqueue_head (&dvbdev->wait_queue); | ||
| 231 | |||
| 232 | memcpy(dvbdevfops, template->fops, sizeof(struct file_operations)); | ||
| 233 | dvbdevfops->owner = adap->module; | ||
| 234 | |||
| 235 | list_add_tail (&dvbdev->list_head, &adap->device_list); | ||
| 236 | |||
| 237 | down_write(&minor_rwsem); | ||
| 238 | #ifdef CONFIG_DVB_DYNAMIC_MINORS | ||
| 239 | for (minor = 0; minor < MAX_DVB_MINORS; minor++) | ||
| 240 | if (dvb_minors[minor] == NULL) | ||
| 241 | break; | ||
| 242 | |||
| 243 | if (minor == MAX_DVB_MINORS) { | ||
| 244 | kfree(dvbdevfops); | ||
| 245 | kfree(dvbdev); | ||
| 246 | mutex_unlock(&dvbdev_register_lock); | ||
| 247 | return -EINVAL; | ||
| 248 | } | ||
| 249 | #else | ||
| 250 | minor = nums2minor(adap->num, type, id); | ||
| 251 | #endif | ||
| 252 | |||
| 253 | dvbdev->minor = minor; | ||
| 254 | dvb_minors[minor] = dvbdev; | ||
| 255 | up_write(&minor_rwsem); | ||
| 256 | |||
| 257 | mutex_unlock(&dvbdev_register_lock); | ||
| 258 | |||
| 259 | clsdev = device_create(dvb_class, adap->device, | ||
| 260 | MKDEV(DVB_MAJOR, minor), | ||
| 261 | dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id); | ||
| 262 | if (IS_ERR(clsdev)) { | ||
| 263 | printk(KERN_ERR "%s: failed to create device dvb%d.%s%d (%ld)\n", | ||
| 264 | __func__, adap->num, dnames[type], id, PTR_ERR(clsdev)); | ||
| 265 | return PTR_ERR(clsdev); | ||
| 266 | } | ||
| 267 | |||
| 268 | dprintk(KERN_DEBUG "DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", | ||
| 269 | adap->num, dnames[type], id, minor, minor); | ||
| 270 | |||
| 271 | return 0; | ||
| 272 | } | ||
| 273 | EXPORT_SYMBOL(dvb_register_device); | ||
| 274 | |||
| 275 | |||
| 276 | void dvb_unregister_device(struct dvb_device *dvbdev) | ||
| 277 | { | ||
| 278 | if (!dvbdev) | ||
| 279 | return; | ||
| 280 | |||
| 281 | down_write(&minor_rwsem); | ||
| 282 | dvb_minors[dvbdev->minor] = NULL; | ||
| 283 | up_write(&minor_rwsem); | ||
| 284 | |||
| 285 | device_destroy(dvb_class, MKDEV(DVB_MAJOR, dvbdev->minor)); | ||
| 286 | |||
| 287 | list_del (&dvbdev->list_head); | ||
| 288 | kfree (dvbdev->fops); | ||
| 289 | kfree (dvbdev); | ||
| 290 | } | ||
| 291 | EXPORT_SYMBOL(dvb_unregister_device); | ||
| 292 | |||
| 293 | static int dvbdev_check_free_adapter_num(int num) | ||
| 294 | { | ||
| 295 | struct list_head *entry; | ||
| 296 | list_for_each(entry, &dvb_adapter_list) { | ||
| 297 | struct dvb_adapter *adap; | ||
| 298 | adap = list_entry(entry, struct dvb_adapter, list_head); | ||
| 299 | if (adap->num == num) | ||
| 300 | return 0; | ||
| 301 | } | ||
| 302 | return 1; | ||
| 303 | } | ||
| 304 | |||
| 305 | static int dvbdev_get_free_adapter_num (void) | ||
| 306 | { | ||
| 307 | int num = 0; | ||
| 308 | |||
| 309 | while (num < DVB_MAX_ADAPTERS) { | ||
| 310 | if (dvbdev_check_free_adapter_num(num)) | ||
| 311 | return num; | ||
| 312 | num++; | ||
| 313 | } | ||
| 314 | |||
| 315 | return -ENFILE; | ||
| 316 | } | ||
| 317 | |||
| 318 | |||
| 319 | int dvb_register_adapter(struct dvb_adapter *adap, const char *name, | ||
| 320 | struct module *module, struct device *device, | ||
| 321 | short *adapter_nums) | ||
| 322 | { | ||
| 323 | int i, num; | ||
| 324 | |||
| 325 | mutex_lock(&dvbdev_register_lock); | ||
| 326 | |||
| 327 | for (i = 0; i < DVB_MAX_ADAPTERS; ++i) { | ||
| 328 | num = adapter_nums[i]; | ||
| 329 | if (num >= 0 && num < DVB_MAX_ADAPTERS) { | ||
| 330 | /* use the one the driver asked for */ | ||
| 331 | if (dvbdev_check_free_adapter_num(num)) | ||
| 332 | break; | ||
| 333 | } else { | ||
| 334 | num = dvbdev_get_free_adapter_num(); | ||
| 335 | break; | ||
| 336 | } | ||
| 337 | num = -1; | ||
| 338 | } | ||
| 339 | |||
| 340 | if (num < 0) { | ||
| 341 | mutex_unlock(&dvbdev_register_lock); | ||
| 342 | return -ENFILE; | ||
| 343 | } | ||
| 344 | |||
| 345 | memset (adap, 0, sizeof(struct dvb_adapter)); | ||
| 346 | INIT_LIST_HEAD (&adap->device_list); | ||
| 347 | |||
| 348 | printk(KERN_INFO "DVB: registering new adapter (%s)\n", name); | ||
| 349 | |||
| 350 | adap->num = num; | ||
| 351 | adap->name = name; | ||
| 352 | adap->module = module; | ||
| 353 | adap->device = device; | ||
| 354 | adap->mfe_shared = 0; | ||
| 355 | adap->mfe_dvbdev = NULL; | ||
| 356 | mutex_init (&adap->mfe_lock); | ||
| 357 | |||
| 358 | list_add_tail (&adap->list_head, &dvb_adapter_list); | ||
| 359 | |||
| 360 | mutex_unlock(&dvbdev_register_lock); | ||
| 361 | |||
| 362 | return num; | ||
| 363 | } | ||
| 364 | EXPORT_SYMBOL(dvb_register_adapter); | ||
| 365 | |||
| 366 | |||
| 367 | int dvb_unregister_adapter(struct dvb_adapter *adap) | ||
| 368 | { | ||
| 369 | mutex_lock(&dvbdev_register_lock); | ||
| 370 | list_del (&adap->list_head); | ||
| 371 | mutex_unlock(&dvbdev_register_lock); | ||
| 372 | return 0; | ||
| 373 | } | ||
| 374 | EXPORT_SYMBOL(dvb_unregister_adapter); | ||
| 375 | |||
| 376 | /* if the miracle happens and "generic_usercopy()" is included into | ||
| 377 | the kernel, then this can vanish. please don't make the mistake and | ||
| 378 | define this as video_usercopy(). this will introduce a dependecy | ||
| 379 | to the v4l "videodev.o" module, which is unnecessary for some | ||
| 380 | cards (ie. the budget dvb-cards don't need the v4l module...) */ | ||
| 381 | int dvb_usercopy(struct file *file, | ||
| 382 | unsigned int cmd, unsigned long arg, | ||
| 383 | int (*func)(struct file *file, | ||
| 384 | unsigned int cmd, void *arg)) | ||
| 385 | { | ||
| 386 | char sbuf[128]; | ||
| 387 | void *mbuf = NULL; | ||
| 388 | void *parg = NULL; | ||
| 389 | int err = -EINVAL; | ||
| 390 | |||
| 391 | /* Copy arguments into temp kernel buffer */ | ||
| 392 | switch (_IOC_DIR(cmd)) { | ||
| 393 | case _IOC_NONE: | ||
| 394 | /* | ||
| 395 | * For this command, the pointer is actually an integer | ||
| 396 | * argument. | ||
| 397 | */ | ||
| 398 | parg = (void *) arg; | ||
| 399 | break; | ||
| 400 | case _IOC_READ: /* some v4l ioctls are marked wrong ... */ | ||
| 401 | case _IOC_WRITE: | ||
| 402 | case (_IOC_WRITE | _IOC_READ): | ||
| 403 | if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { | ||
| 404 | parg = sbuf; | ||
| 405 | } else { | ||
| 406 | /* too big to allocate from stack */ | ||
| 407 | mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); | ||
| 408 | if (NULL == mbuf) | ||
| 409 | return -ENOMEM; | ||
| 410 | parg = mbuf; | ||
| 411 | } | ||
| 412 | |||
| 413 | err = -EFAULT; | ||
| 414 | if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) | ||
| 415 | goto out; | ||
| 416 | break; | ||
| 417 | } | ||
| 418 | |||
| 419 | /* call driver */ | ||
| 420 | mutex_lock(&dvbdev_mutex); | ||
| 421 | if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD) | ||
| 422 | err = -EINVAL; | ||
| 423 | mutex_unlock(&dvbdev_mutex); | ||
| 424 | |||
| 425 | if (err < 0) | ||
| 426 | goto out; | ||
| 427 | |||
| 428 | /* Copy results into user buffer */ | ||
| 429 | switch (_IOC_DIR(cmd)) | ||
| 430 | { | ||
| 431 | case _IOC_READ: | ||
| 432 | case (_IOC_WRITE | _IOC_READ): | ||
| 433 | if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) | ||
| 434 | err = -EFAULT; | ||
| 435 | break; | ||
| 436 | } | ||
| 437 | |||
| 438 | out: | ||
| 439 | kfree(mbuf); | ||
| 440 | return err; | ||
| 441 | } | ||
| 442 | |||
| 443 | static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env) | ||
| 444 | { | ||
| 445 | struct dvb_device *dvbdev = dev_get_drvdata(dev); | ||
| 446 | |||
| 447 | add_uevent_var(env, "DVB_ADAPTER_NUM=%d", dvbdev->adapter->num); | ||
| 448 | add_uevent_var(env, "DVB_DEVICE_TYPE=%s", dnames[dvbdev->type]); | ||
| 449 | add_uevent_var(env, "DVB_DEVICE_NUM=%d", dvbdev->id); | ||
| 450 | return 0; | ||
| 451 | } | ||
| 452 | |||
| 453 | static char *dvb_devnode(struct device *dev, mode_t *mode) | ||
| 454 | { | ||
| 455 | struct dvb_device *dvbdev = dev_get_drvdata(dev); | ||
| 456 | |||
| 457 | return kasprintf(GFP_KERNEL, "dvb/adapter%d/%s%d", | ||
| 458 | dvbdev->adapter->num, dnames[dvbdev->type], dvbdev->id); | ||
| 459 | } | ||
| 460 | |||
| 461 | |||
| 462 | static int __init init_dvbdev(void) | ||
| 463 | { | ||
| 464 | int retval; | ||
| 465 | dev_t dev = MKDEV(DVB_MAJOR, 0); | ||
| 466 | |||
| 467 | if ((retval = register_chrdev_region(dev, MAX_DVB_MINORS, "DVB")) != 0) { | ||
| 468 | printk(KERN_ERR "dvb-core: unable to get major %d\n", DVB_MAJOR); | ||
| 469 | return retval; | ||
| 470 | } | ||
| 471 | |||
| 472 | cdev_init(&dvb_device_cdev, &dvb_device_fops); | ||
| 473 | if ((retval = cdev_add(&dvb_device_cdev, dev, MAX_DVB_MINORS)) != 0) { | ||
| 474 | printk(KERN_ERR "dvb-core: unable register character device\n"); | ||
| 475 | goto error; | ||
| 476 | } | ||
| 477 | |||
| 478 | dvb_class = class_create(THIS_MODULE, "dvb"); | ||
| 479 | if (IS_ERR(dvb_class)) { | ||
| 480 | retval = PTR_ERR(dvb_class); | ||
| 481 | goto error; | ||
| 482 | } | ||
| 483 | dvb_class->dev_uevent = dvb_uevent; | ||
| 484 | dvb_class->devnode = dvb_devnode; | ||
| 485 | return 0; | ||
| 486 | |||
| 487 | error: | ||
| 488 | cdev_del(&dvb_device_cdev); | ||
| 489 | unregister_chrdev_region(dev, MAX_DVB_MINORS); | ||
| 490 | return retval; | ||
| 491 | } | ||
| 492 | |||
| 493 | |||
| 494 | static void __exit exit_dvbdev(void) | ||
| 495 | { | ||
| 496 | class_destroy(dvb_class); | ||
| 497 | cdev_del(&dvb_device_cdev); | ||
| 498 | unregister_chrdev_region(MKDEV(DVB_MAJOR, 0), MAX_DVB_MINORS); | ||
| 499 | } | ||
| 500 | |||
| 501 | subsys_initcall(init_dvbdev); | ||
| 502 | module_exit(exit_dvbdev); | ||
| 503 | |||
| 504 | MODULE_DESCRIPTION("DVB Core Driver"); | ||
| 505 | MODULE_AUTHOR("Marcus Metzler, Ralph Metzler, Holger Waechtler"); | ||
| 506 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h new file mode 100644 index 00000000000..fcc6ae98745 --- /dev/null +++ b/drivers/media/dvb/dvb-core/dvbdev.h | |||
| @@ -0,0 +1,172 @@ | |||
| 1 | /* | ||
| 2 | * dvbdev.h | ||
| 3 | * | ||
| 4 | * Copyright (C) 2000 Ralph Metzler & Marcus Metzler | ||
| 5 | * for convergence integrated media GmbH | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Lesser Public License | ||
| 9 | * as published by the Free Software Foundation; either version 2.1 | ||
| 10 | * of the License, or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU Lesser General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
| 20 | * | ||
| 21 | */ | ||
| 22 | |||
| 23 | #ifndef _DVBDEV_H_ | ||
| 24 | #define _DVBDEV_H_ | ||
| 25 | |||
| 26 | #include <linux/types.h> | ||
| 27 | #include <linux/poll.h> | ||
| 28 | #include <linux/fs.h> | ||
| 29 | #include <linux/list.h> | ||
| 30 | |||
| 31 | #define DVB_MAJOR 212 | ||
| 32 | |||
| 33 | #if defined(CONFIG_DVB_MAX_ADAPTERS) && CONFIG_DVB_MAX_ADAPTERS > 0 | ||
| 34 | #define DVB_MAX_ADAPTERS CONFIG_DVB_MAX_ADAPTERS | ||
| 35 | #else | ||
| 36 | #define DVB_MAX_ADAPTERS 8 | ||
| 37 | #endif | ||
| 38 | |||
| 39 | #define DVB_UNSET (-1) | ||
| 40 | |||
| 41 | #define DVB_DEVICE_VIDEO 0 | ||
| 42 | #define DVB_DEVICE_AUDIO 1 | ||
| 43 | #define DVB_DEVICE_SEC 2 | ||
| 44 | #define DVB_DEVICE_FRONTEND 3 | ||
| 45 | #define DVB_DEVICE_DEMUX 4 | ||
| 46 | #define DVB_DEVICE_DVR 5 | ||
| 47 | #define DVB_DEVICE_CA 6 | ||
| 48 | #define DVB_DEVICE_NET 7 | ||
| 49 | #define DVB_DEVICE_OSD 8 | ||
| 50 | |||
| 51 | #define DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr) \ | ||
| 52 | static short adapter_nr[] = \ | ||
| 53 | {[0 ... (DVB_MAX_ADAPTERS - 1)] = DVB_UNSET }; \ | ||
| 54 | module_param_array(adapter_nr, short, NULL, 0444); \ | ||
| 55 | MODULE_PARM_DESC(adapter_nr, "DVB adapter numbers") | ||
| 56 | |||
| 57 | struct dvb_frontend; | ||
| 58 | |||
| 59 | struct dvb_adapter { | ||
| 60 | int num; | ||
| 61 | struct list_head list_head; | ||
| 62 | struct list_head device_list; | ||
| 63 | const char *name; | ||
| 64 | u8 proposed_mac [6]; | ||
| 65 | void* priv; | ||
| 66 | |||
| 67 | struct device *device; | ||
| 68 | |||
| 69 | struct module *module; | ||
| 70 | |||
| 71 | int mfe_shared; /* indicates mutually exclusive frontends */ | ||
| 72 | struct dvb_device *mfe_dvbdev; /* frontend device in use */ | ||
| 73 | struct mutex mfe_lock; /* access lock for thread creation */ | ||
| 74 | |||
| 75 | /* Allow the adapter/bridge driver to perform an action before and/or | ||
| 76 | * after the core handles an ioctl: | ||
| 77 | * | ||
| 78 | * DVB_FE_IOCTL_PRE indicates that the ioctl has not yet been handled. | ||
| 79 | * DVB_FE_IOCTL_POST indicates that the ioctl has been handled. | ||
| 80 | * | ||
| 81 | * When DVB_FE_IOCTL_PRE is passed to the callback as the stage arg: | ||
| 82 | * | ||
| 83 | * return 0 to allow dvb-core to handle the ioctl. | ||
| 84 | * return a positive int to prevent dvb-core from handling the ioctl, | ||
| 85 | * and exit without error. | ||
| 86 | * return a negative int to prevent dvb-core from handling the ioctl, | ||
| 87 | * and return that value as an error. | ||
| 88 | * | ||
| 89 | * When DVB_FE_IOCTL_POST is passed to the callback as the stage arg: | ||
| 90 | * | ||
| 91 | * return 0 to allow the dvb_frontend ioctl handler to exit normally. | ||
| 92 | * return a negative int to cause the dvb_frontend ioctl handler to | ||
| 93 | * return that value as an error. | ||
| 94 | */ | ||
| 95 | #define DVB_FE_IOCTL_PRE 0 | ||
| 96 | #define DVB_FE_IOCTL_POST 1 | ||
| 97 | int (*fe_ioctl_override)(struct dvb_frontend *fe, | ||
| 98 | unsigned int cmd, void *parg, | ||
| 99 | unsigned int stage); | ||
| 100 | }; | ||
| 101 | |||
| 102 | |||
| 103 | struct dvb_device { | ||
| 104 | struct list_head list_head; | ||
| 105 | const struct file_operations *fops; | ||
| 106 | struct dvb_adapter *adapter; | ||
| 107 | int type; | ||
| 108 | int minor; | ||
| 109 | u32 id; | ||
| 110 | |||
| 111 | /* in theory, 'users' can vanish now, | ||
| 112 | but I don't want to change too much now... */ | ||
| 113 | int readers; | ||
| 114 | int writers; | ||
| 115 | int users; | ||
| 116 | |||
| 117 | wait_queue_head_t wait_queue; | ||
| 118 | /* don't really need those !? -- FIXME: use video_usercopy */ | ||
| 119 | int (*kernel_ioctl)(struct file *file, unsigned int cmd, void *arg); | ||
| 120 | |||
| 121 | void *priv; | ||
| 122 | }; | ||
| 123 | |||
| 124 | |||
| 125 | extern int dvb_register_adapter(struct dvb_adapter *adap, const char *name, | ||
| 126 | struct module *module, struct device *device, | ||
| 127 | short *adapter_nums); | ||
| 128 | extern int dvb_unregister_adapter (struct dvb_adapter *adap); | ||
| 129 | |||
| 130 | extern int dvb_register_device (struct dvb_adapter *adap, | ||
| 131 | struct dvb_device **pdvbdev, | ||
| 132 | const struct dvb_device *template, | ||
| 133 | void *priv, | ||
| 134 | int type); | ||
| 135 | |||
| 136 | extern void dvb_unregister_device (struct dvb_device *dvbdev); | ||
| 137 | |||
| 138 | extern int dvb_generic_open (struct inode *inode, struct file *file); | ||
| 139 | extern int dvb_generic_release (struct inode *inode, struct file *file); | ||
| 140 | extern long dvb_generic_ioctl (struct file *file, | ||
| 141 | unsigned int cmd, unsigned long arg); | ||
| 142 | |||
| 143 | /* we don't mess with video_usercopy() any more, | ||
| 144 | we simply define out own dvb_usercopy(), which will hopefully become | ||
| 145 | generic_usercopy() someday... */ | ||
| 146 | |||
| 147 | extern int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg, | ||
| 148 | int (*func)(struct file *file, unsigned int cmd, void *arg)); | ||
| 149 | |||
| 150 | /** generic DVB attach function. */ | ||
| 151 | #ifdef CONFIG_MEDIA_ATTACH | ||
| 152 | #define dvb_attach(FUNCTION, ARGS...) ({ \ | ||
| 153 | void *__r = NULL; \ | ||
| 154 | typeof(&FUNCTION) __a = symbol_request(FUNCTION); \ | ||
| 155 | if (__a) { \ | ||
| 156 | __r = (void *) __a(ARGS); \ | ||
| 157 | if (__r == NULL) \ | ||
| 158 | symbol_put(FUNCTION); \ | ||
| 159 | } else { \ | ||
| 160 | printk(KERN_ERR "DVB: Unable to find symbol "#FUNCTION"()\n"); \ | ||
| 161 | } \ | ||
| 162 | __r; \ | ||
| 163 | }) | ||
| 164 | |||
| 165 | #else | ||
| 166 | #define dvb_attach(FUNCTION, ARGS...) ({ \ | ||
| 167 | FUNCTION(ARGS); \ | ||
| 168 | }) | ||
| 169 | |||
| 170 | #endif | ||
| 171 | |||
| 172 | #endif /* #ifndef _DVBDEV_H_ */ | ||
