dmxdev.c 26.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3
/*
 * dmxdev.c - DVB demultiplexer device
 *
4 5
 * Copyright (C) 2000 Ralph Metzler & Marcus Metzler
 *		      for convergence integrated media GmbH
L
Linus Torvalds 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 */

#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/poll.h>
#include <linux/ioctl.h>
#include <linux/wait.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include "dmxdev.h"

static int debug;

module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");

#define dprintk	if (debug) printk

42 43
static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf,
				   const u8 *src, size_t len)
L
Linus Torvalds 已提交
44
{
45
	ssize_t free;
L
Linus Torvalds 已提交
46 47 48 49 50 51

	if (!len)
		return 0;
	if (!buf->data)
		return 0;

52 53
	free = dvb_ringbuffer_free(buf);
	if (len > free) {
L
Linus Torvalds 已提交
54
		dprintk("dmxdev: buffer overflow\n");
55
		return -EOVERFLOW;
L
Linus Torvalds 已提交
56
	}
57 58

	return dvb_ringbuffer_write(buf, src, len);
L
Linus Torvalds 已提交
59 60
}

61
static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src,
62 63
				      int non_blocking, char __user *buf,
				      size_t count, loff_t *ppos)
L
Linus Torvalds 已提交
64
{
65 66 67
	size_t todo;
	ssize_t avail;
	ssize_t ret = 0;
L
Linus Torvalds 已提交
68 69 70 71

	if (!src->data)
		return 0;

72 73 74 75
	if (src->error) {
		ret = src->error;
		dvb_ringbuffer_flush(src);
		return ret;
L
Linus Torvalds 已提交
76 77
	}

78 79 80 81 82
	for (todo = count; todo > 0; todo -= ret) {
		if (non_blocking && dvb_ringbuffer_empty(src)) {
			ret = -EWOULDBLOCK;
			break;
		}
L
Linus Torvalds 已提交
83

84 85 86 87 88
		ret = wait_event_interruptible(src->queue,
					       !dvb_ringbuffer_empty(src) ||
					       (src->error != 0));
		if (ret < 0)
			break;
L
Linus Torvalds 已提交
89

90 91 92 93
		if (src->error) {
			ret = src->error;
			dvb_ringbuffer_flush(src);
			break;
L
Linus Torvalds 已提交
94 95
		}

96
		avail = dvb_ringbuffer_avail(src);
97 98
		if (avail > todo)
			avail = todo;
99 100 101 102 103 104

		ret = dvb_ringbuffer_read(src, buf, avail, 1);
		if (ret < 0)
			break;

		buf += ret;
L
Linus Torvalds 已提交
105
	}
106 107

	return (count - todo) ? (count - todo) : ret;
L
Linus Torvalds 已提交
108 109
}

110
static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type)
L
Linus Torvalds 已提交
111 112 113
{
	struct list_head *head, *pos;

114
	head = demux->get_frontends(demux);
L
Linus Torvalds 已提交
115 116 117
	if (!head)
		return NULL;
	list_for_each(pos, head)
118
		if (DMX_FE_ENTRY(pos)->source == type)
L
Linus Torvalds 已提交
119 120 121 122 123 124 125
			return DMX_FE_ENTRY(pos);

	return NULL;
}

static int dvb_dvr_open(struct inode *inode, struct file *file)
{
126 127
	struct dvb_device *dvbdev = file->private_data;
	struct dmxdev *dmxdev = dvbdev->priv;
L
Linus Torvalds 已提交
128 129
	struct dmx_frontend *front;

130
	dprintk("function : %s\n", __FUNCTION__);
L
Linus Torvalds 已提交
131

132
	if (mutex_lock_interruptible(&dmxdev->mutex))
L
Linus Torvalds 已提交
133 134
		return -ERESTARTSYS;

135 136
	if ((file->f_flags & O_ACCMODE) == O_RDWR) {
		if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
137
			mutex_unlock(&dmxdev->mutex);
L
Linus Torvalds 已提交
138 139 140 141
			return -EOPNOTSUPP;
		}
	}

142
	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
143 144 145 146 147 148
		void *mem;
		if (!dvbdev->readers) {
			mutex_unlock(&dmxdev->mutex);
			return -EBUSY;
		}
		mem = vmalloc(DVR_BUFFER_SIZE);
149
		if (!mem) {
150 151 152
			mutex_unlock(&dmxdev->mutex);
			return -ENOMEM;
		}
153
		dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
154
		dvbdev->readers--;
L
Linus Torvalds 已提交
155 156
	}

157 158
	if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
		dmxdev->dvr_orig_fe = dmxdev->demux->frontend;
L
Linus Torvalds 已提交
159 160

		if (!dmxdev->demux->write) {
161
			mutex_unlock(&dmxdev->mutex);
L
Linus Torvalds 已提交
162 163 164
			return -EOPNOTSUPP;
		}

165
		front = get_fe(dmxdev->demux, DMX_MEMORY_FE);
L
Linus Torvalds 已提交
166 167

		if (!front) {
168
			mutex_unlock(&dmxdev->mutex);
L
Linus Torvalds 已提交
169 170 171 172 173
			return -EINVAL;
		}
		dmxdev->demux->disconnect_frontend(dmxdev->demux);
		dmxdev->demux->connect_frontend(dmxdev->demux, front);
	}
174
	mutex_unlock(&dmxdev->mutex);
L
Linus Torvalds 已提交
175 176 177 178 179
	return 0;
}

static int dvb_dvr_release(struct inode *inode, struct file *file)
{
180 181
	struct dvb_device *dvbdev = file->private_data;
	struct dmxdev *dmxdev = dvbdev->priv;
L
Linus Torvalds 已提交
182

183
	mutex_lock(&dmxdev->mutex);
L
Linus Torvalds 已提交
184

185
	if ((file->f_flags & O_ACCMODE) == O_WRONLY) {
L
Linus Torvalds 已提交
186 187 188 189
		dmxdev->demux->disconnect_frontend(dmxdev->demux);
		dmxdev->demux->connect_frontend(dmxdev->demux,
						dmxdev->dvr_orig_fe);
	}
190
	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
191
		dvbdev->readers++;
L
Linus Torvalds 已提交
192
		if (dmxdev->dvr_buffer.data) {
193
			void *mem = dmxdev->dvr_buffer.data;
L
Linus Torvalds 已提交
194 195
			mb();
			spin_lock_irq(&dmxdev->lock);
196
			dmxdev->dvr_buffer.data = NULL;
L
Linus Torvalds 已提交
197 198 199 200
			spin_unlock_irq(&dmxdev->lock);
			vfree(mem);
		}
	}
201
	mutex_unlock(&dmxdev->mutex);
L
Linus Torvalds 已提交
202 203 204 205
	return 0;
}

static ssize_t dvb_dvr_write(struct file *file, const char __user *buf,
206
			     size_t count, loff_t *ppos)
L
Linus Torvalds 已提交
207
{
208 209
	struct dvb_device *dvbdev = file->private_data;
	struct dmxdev *dmxdev = dvbdev->priv;
L
Linus Torvalds 已提交
210 211 212 213
	int ret;

	if (!dmxdev->demux->write)
		return -EOPNOTSUPP;
214
	if ((file->f_flags & O_ACCMODE) != O_WRONLY)
L
Linus Torvalds 已提交
215
		return -EINVAL;
216
	if (mutex_lock_interruptible(&dmxdev->mutex))
L
Linus Torvalds 已提交
217
		return -ERESTARTSYS;
218
	ret = dmxdev->demux->write(dmxdev->demux, buf, count);
219
	mutex_unlock(&dmxdev->mutex);
L
Linus Torvalds 已提交
220 221 222 223
	return ret;
}

static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count,
224
			    loff_t *ppos)
L
Linus Torvalds 已提交
225
{
226 227
	struct dvb_device *dvbdev = file->private_data;
	struct dmxdev *dmxdev = dvbdev->priv;
L
Linus Torvalds 已提交
228 229
	int ret;

230
	//mutex_lock(&dmxdev->mutex);
231 232 233
	ret = dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer,
				     file->f_flags & O_NONBLOCK,
				     buf, count, ppos);
234
	//mutex_unlock(&dmxdev->mutex);
L
Linus Torvalds 已提交
235 236 237
	return ret;
}

238 239
static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter
					       *dmxdevfilter, int state)
L
Linus Torvalds 已提交
240 241
{
	spin_lock_irq(&dmxdevfilter->dev->lock);
242
	dmxdevfilter->state = state;
L
Linus Torvalds 已提交
243 244 245
	spin_unlock_irq(&dmxdevfilter->dev->lock);
}

246 247
static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter,
				      unsigned long size)
L
Linus Torvalds 已提交
248
{
249
	struct dvb_ringbuffer *buf = &dmxdevfilter->buffer;
L
Linus Torvalds 已提交
250 251
	void *mem;

252
	if (buf->size == size)
L
Linus Torvalds 已提交
253
		return 0;
254
	if (dmxdevfilter->state >= DMXDEV_STATE_GO)
L
Linus Torvalds 已提交
255 256
		return -EBUSY;
	spin_lock_irq(&dmxdevfilter->dev->lock);
257 258 259
	mem = buf->data;
	buf->data = NULL;
	buf->size = size;
260
	dvb_ringbuffer_flush(buf);
L
Linus Torvalds 已提交
261 262 263 264
	spin_unlock_irq(&dmxdevfilter->dev->lock);
	vfree(mem);

	if (buf->size) {
265
		mem = vmalloc(dmxdevfilter->buffer.size);
L
Linus Torvalds 已提交
266 267 268
		if (!mem)
			return -ENOMEM;
		spin_lock_irq(&dmxdevfilter->dev->lock);
269
		buf->data = mem;
L
Linus Torvalds 已提交
270 271 272 273 274 275 276
		spin_unlock_irq(&dmxdevfilter->dev->lock);
	}
	return 0;
}

static void dvb_dmxdev_filter_timeout(unsigned long data)
{
277
	struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data;
L
Linus Torvalds 已提交
278

279
	dmxdevfilter->buffer.error = -ETIMEDOUT;
L
Linus Torvalds 已提交
280
	spin_lock_irq(&dmxdevfilter->dev->lock);
281
	dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT;
L
Linus Torvalds 已提交
282 283 284 285 286 287
	spin_unlock_irq(&dmxdevfilter->dev->lock);
	wake_up(&dmxdevfilter->buffer.queue);
}

static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
{
288
	struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec;
L
Linus Torvalds 已提交
289 290 291

	del_timer(&dmxdevfilter->timer);
	if (para->timeout) {
292 293 294 295
		dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout;
		dmxdevfilter->timer.data = (unsigned long)dmxdevfilter;
		dmxdevfilter->timer.expires =
		    jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000;
L
Linus Torvalds 已提交
296 297 298 299 300
		add_timer(&dmxdevfilter->timer);
	}
}

static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
301 302 303
				       const u8 *buffer2, size_t buffer2_len,
				       struct dmx_section_filter *filter,
				       enum dmx_success success)
L
Linus Torvalds 已提交
304
{
305
	struct dmxdev_filter *dmxdevfilter = filter->priv;
L
Linus Torvalds 已提交
306 307 308 309 310 311 312
	int ret;

	if (dmxdevfilter->buffer.error) {
		wake_up(&dmxdevfilter->buffer.queue);
		return 0;
	}
	spin_lock(&dmxdevfilter->dev->lock);
313
	if (dmxdevfilter->state != DMXDEV_STATE_GO) {
L
Linus Torvalds 已提交
314 315 316 317 318 319
		spin_unlock(&dmxdevfilter->dev->lock);
		return 0;
	}
	del_timer(&dmxdevfilter->timer);
	dprintk("dmxdev: section callback %02x %02x %02x %02x %02x %02x\n",
		buffer1[0], buffer1[1],
320 321 322 323 324 325
		buffer1[2], buffer1[3], buffer1[4], buffer1[5]);
	ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,
				      buffer1_len);
	if (ret == buffer1_len) {
		ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2,
					      buffer2_len);
L
Linus Torvalds 已提交
326
	}
327
	if (ret < 0) {
328 329
		dvb_ringbuffer_flush(&dmxdevfilter->buffer);
		dmxdevfilter->buffer.error = ret;
L
Linus Torvalds 已提交
330
	}
331 332
	if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
		dmxdevfilter->state = DMXDEV_STATE_DONE;
L
Linus Torvalds 已提交
333 334 335 336 337 338
	spin_unlock(&dmxdevfilter->dev->lock);
	wake_up(&dmxdevfilter->buffer.queue);
	return 0;
}

static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
339 340 341
				  const u8 *buffer2, size_t buffer2_len,
				  struct dmx_ts_feed *feed,
				  enum dmx_success success)
L
Linus Torvalds 已提交
342
{
343
	struct dmxdev_filter *dmxdevfilter = feed->priv;
344
	struct dvb_ringbuffer *buffer;
L
Linus Torvalds 已提交
345 346 347
	int ret;

	spin_lock(&dmxdevfilter->dev->lock);
348
	if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
L
Linus Torvalds 已提交
349 350 351 352
		spin_unlock(&dmxdevfilter->dev->lock);
		return 0;
	}

353 354
	if (dmxdevfilter->params.pes.output == DMX_OUT_TAP)
		buffer = &dmxdevfilter->buffer;
L
Linus Torvalds 已提交
355
	else
356
		buffer = &dmxdevfilter->dev->dvr_buffer;
L
Linus Torvalds 已提交
357 358 359 360 361
	if (buffer->error) {
		spin_unlock(&dmxdevfilter->dev->lock);
		wake_up(&buffer->queue);
		return 0;
	}
362 363 364 365
	ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
	if (ret == buffer1_len)
		ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
	if (ret < 0) {
366 367
		dvb_ringbuffer_flush(buffer);
		buffer->error = ret;
L
Linus Torvalds 已提交
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395
	}
	spin_unlock(&dmxdevfilter->dev->lock);
	wake_up(&buffer->queue);
	return 0;
}

/* stop feed but only mark the specified filter as stopped (state set) */
static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter)
{
	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);

	switch (dmxdevfilter->type) {
	case DMXDEV_TYPE_SEC:
		del_timer(&dmxdevfilter->timer);
		dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec);
		break;
	case DMXDEV_TYPE_PES:
		dmxdevfilter->feed.ts->stop_filtering(dmxdevfilter->feed.ts);
		break;
	default:
		return -EINVAL;
	}
	return 0;
}

/* start feed associated with the specified filter */
static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter)
{
396
	dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
L
Linus Torvalds 已提交
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417

	switch (filter->type) {
	case DMXDEV_TYPE_SEC:
		return filter->feed.sec->start_filtering(filter->feed.sec);
	case DMXDEV_TYPE_PES:
		return filter->feed.ts->start_filtering(filter->feed.ts);
	default:
		return -EINVAL;
	}

	return 0;
}

/* restart section feed if it has filters left associated with it,
   otherwise release the feed */
static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter)
{
	int i;
	struct dmxdev *dmxdev = filter->dev;
	u16 pid = filter->params.sec.pid;

418 419 420 421
	for (i = 0; i < dmxdev->filternum; i++)
		if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
		    dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
		    dmxdev->filter[i].params.sec.pid == pid) {
L
Linus Torvalds 已提交
422 423 424 425
			dvb_dmxdev_feed_start(&dmxdev->filter[i]);
			return 0;
		}

426 427
	filter->dev->demux->release_section_feed(dmxdev->demux,
						 filter->feed.sec);
L
Linus Torvalds 已提交
428 429 430 431 432 433

	return 0;
}

static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter)
{
434
	if (dmxdevfilter->state < DMXDEV_STATE_GO)
L
Linus Torvalds 已提交
435 436 437 438 439 440 441 442 443
		return 0;

	switch (dmxdevfilter->type) {
	case DMXDEV_TYPE_SEC:
		if (!dmxdevfilter->feed.sec)
			break;
		dvb_dmxdev_feed_stop(dmxdevfilter);
		if (dmxdevfilter->filter.sec)
			dmxdevfilter->feed.sec->
444 445
			    release_filter(dmxdevfilter->feed.sec,
					   dmxdevfilter->filter.sec);
L
Linus Torvalds 已提交
446
		dvb_dmxdev_feed_restart(dmxdevfilter);
447
		dmxdevfilter->feed.sec = NULL;
L
Linus Torvalds 已提交
448 449 450 451 452 453
		break;
	case DMXDEV_TYPE_PES:
		if (!dmxdevfilter->feed.ts)
			break;
		dvb_dmxdev_feed_stop(dmxdevfilter);
		dmxdevfilter->dev->demux->
454 455 456
		    release_ts_feed(dmxdevfilter->dev->demux,
				    dmxdevfilter->feed.ts);
		dmxdevfilter->feed.ts = NULL;
L
Linus Torvalds 已提交
457 458
		break;
	default:
459
		if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED)
L
Linus Torvalds 已提交
460 461 462
			return 0;
		return -EINVAL;
	}
463 464

	dvb_ringbuffer_flush(&dmxdevfilter->buffer);
L
Linus Torvalds 已提交
465 466 467 468 469
	return 0;
}

static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter)
{
470
	if (dmxdevfilter->state < DMXDEV_STATE_SET)
L
Linus Torvalds 已提交
471 472
		return 0;

473
	dmxdevfilter->type = DMXDEV_TYPE_NONE;
L
Linus Torvalds 已提交
474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
	return 0;
}

static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
{
	struct dmxdev *dmxdev = filter->dev;
	void *mem;
	int ret, i;

	if (filter->state < DMXDEV_STATE_SET)
		return -EINVAL;

	if (filter->state >= DMXDEV_STATE_GO)
		dvb_dmxdev_filter_stop(filter);

490
	if (!filter->buffer.data) {
L
Linus Torvalds 已提交
491
		mem = vmalloc(filter->buffer.size);
492 493
		if (!mem)
			return -ENOMEM;
L
Linus Torvalds 已提交
494
		spin_lock_irq(&filter->dev->lock);
495
		filter->buffer.data = mem;
L
Linus Torvalds 已提交
496 497 498
		spin_unlock_irq(&filter->dev->lock);
	}

499
	dvb_ringbuffer_flush(&filter->buffer);
L
Linus Torvalds 已提交
500 501 502 503

	switch (filter->type) {
	case DMXDEV_TYPE_SEC:
	{
504 505 506 507 508 509
		struct dmx_sct_filter_params *para = &filter->params.sec;
		struct dmx_section_filter **secfilter = &filter->filter.sec;
		struct dmx_section_feed **secfeed = &filter->feed.sec;

		*secfilter = NULL;
		*secfeed = NULL;
L
Linus Torvalds 已提交
510 511 512


		/* find active filter/feed with same PID */
513
		for (i = 0; i < dmxdev->filternum; i++) {
L
Linus Torvalds 已提交
514
			if (dmxdev->filter[i].state >= DMXDEV_STATE_GO &&
515 516
			    dmxdev->filter[i].type == DMXDEV_TYPE_SEC &&
			    dmxdev->filter[i].params.sec.pid == para->pid) {
L
Linus Torvalds 已提交
517 518 519 520 521 522 523
				*secfeed = dmxdev->filter[i].feed.sec;
				break;
			}
		}

		/* if no feed found, try to allocate new one */
		if (!*secfeed) {
524 525 526 527 528 529
			ret = dmxdev->demux->allocate_section_feed(dmxdev->demux,
								   secfeed,
								   dvb_dmxdev_section_callback);
			if (ret < 0) {
				printk("DVB (%s): could not alloc feed\n",
				       __FUNCTION__);
L
Linus Torvalds 已提交
530 531 532
				return ret;
			}

533 534 535 536 537
			ret = (*secfeed)->set(*secfeed, para->pid, 32768,
					      (para->flags & DMX_CHECK_CRC) ? 1 : 0);
			if (ret < 0) {
				printk("DVB (%s): could not set feed\n",
				       __FUNCTION__);
L
Linus Torvalds 已提交
538 539 540 541 542 543 544
				dvb_dmxdev_feed_restart(filter);
				return ret;
			}
		} else {
			dvb_dmxdev_feed_stop(filter);
		}

545
		ret = (*secfeed)->allocate_filter(*secfeed, secfilter);
L
Linus Torvalds 已提交
546 547 548
		if (ret < 0) {
			dvb_dmxdev_feed_restart(filter);
			filter->feed.sec->start_filtering(*secfeed);
549
			dprintk("could not get filter\n");
L
Linus Torvalds 已提交
550 551 552 553 554 555
			return ret;
		}

		(*secfilter)->priv = filter;

		memcpy(&((*secfilter)->filter_value[3]),
556
		       &(para->filter.filter[1]), DMX_FILTER_SIZE - 1);
L
Linus Torvalds 已提交
557
		memcpy(&(*secfilter)->filter_mask[3],
558
		       &para->filter.mask[1], DMX_FILTER_SIZE - 1);
L
Linus Torvalds 已提交
559
		memcpy(&(*secfilter)->filter_mode[3],
560
		       &para->filter.mode[1], DMX_FILTER_SIZE - 1);
L
Linus Torvalds 已提交
561

562 563 564 565 566
		(*secfilter)->filter_value[0] = para->filter.filter[0];
		(*secfilter)->filter_mask[0] = para->filter.mask[0];
		(*secfilter)->filter_mode[0] = para->filter.mode[0];
		(*secfilter)->filter_mask[1] = 0;
		(*secfilter)->filter_mask[2] = 0;
L
Linus Torvalds 已提交
567 568 569

		filter->todo = 0;

570
		ret = filter->feed.sec->start_filtering(filter->feed.sec);
L
Linus Torvalds 已提交
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
		if (ret < 0)
			return ret;

		dvb_dmxdev_filter_timer(filter);
		break;
	}
	case DMXDEV_TYPE_PES:
	{
		struct timespec timeout = { 0 };
		struct dmx_pes_filter_params *para = &filter->params.pes;
		dmx_output_t otype;
		int ret;
		int ts_type;
		enum dmx_ts_pes ts_pes;
		struct dmx_ts_feed **tsfeed = &filter->feed.ts;

		filter->feed.ts = NULL;
588
		otype = para->output;
L
Linus Torvalds 已提交
589

590
		ts_pes = (enum dmx_ts_pes)para->pes_type;
L
Linus Torvalds 已提交
591

592 593
		if (ts_pes < DMX_PES_OTHER)
			ts_type = TS_DECODER;
L
Linus Torvalds 已提交
594
		else
595
			ts_type = 0;
L
Linus Torvalds 已提交
596 597 598 599 600

		if (otype == DMX_OUT_TS_TAP)
			ts_type |= TS_PACKET;

		if (otype == DMX_OUT_TAP)
601
			ts_type |= TS_PAYLOAD_ONLY | TS_PACKET;
L
Linus Torvalds 已提交
602

603 604 605 606
		ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux,
						      tsfeed,
						      dvb_dmxdev_ts_callback);
		if (ret < 0)
L
Linus Torvalds 已提交
607 608
			return ret;

609
		(*tsfeed)->priv = filter;
L
Linus Torvalds 已提交
610 611

		ret = (*tsfeed)->set(*tsfeed, para->pid, ts_type, ts_pes,
612
				     32768, timeout);
L
Linus Torvalds 已提交
613
		if (ret < 0) {
614 615
			dmxdev->demux->release_ts_feed(dmxdev->demux,
						       *tsfeed);
L
Linus Torvalds 已提交
616 617 618 619
			return ret;
		}

		ret = filter->feed.ts->start_filtering(filter->feed.ts);
620
		if (ret < 0) {
621 622
			dmxdev->demux->release_ts_feed(dmxdev->demux,
						       *tsfeed);
L
Linus Torvalds 已提交
623
			return ret;
624
		}
L
Linus Torvalds 已提交
625 626 627 628 629 630 631 632 633 634 635 636 637

		break;
	}
	default:
		return -EINVAL;
	}

	dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO);
	return 0;
}

static int dvb_demux_open(struct inode *inode, struct file *file)
{
638 639
	struct dvb_device *dvbdev = file->private_data;
	struct dmxdev *dmxdev = dvbdev->priv;
L
Linus Torvalds 已提交
640 641 642 643 644 645
	int i;
	struct dmxdev_filter *dmxdevfilter;

	if (!dmxdev->filter)
		return -EINVAL;

646
	if (mutex_lock_interruptible(&dmxdev->mutex))
L
Linus Torvalds 已提交
647 648
		return -ERESTARTSYS;

649 650
	for (i = 0; i < dmxdev->filternum; i++)
		if (dmxdev->filter[i].state == DMXDEV_STATE_FREE)
L
Linus Torvalds 已提交
651 652
			break;

653
	if (i == dmxdev->filternum) {
654
		mutex_unlock(&dmxdev->mutex);
L
Linus Torvalds 已提交
655 656 657
		return -EMFILE;
	}

658
	dmxdevfilter = &dmxdev->filter[i];
659
	mutex_init(&dmxdevfilter->mutex);
660
	file->private_data = dmxdevfilter;
L
Linus Torvalds 已提交
661

662
	dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
663
	dmxdevfilter->type = DMXDEV_TYPE_NONE;
L
Linus Torvalds 已提交
664
	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
665
	dmxdevfilter->feed.ts = NULL;
L
Linus Torvalds 已提交
666 667
	init_timer(&dmxdevfilter->timer);

668
	mutex_unlock(&dmxdev->mutex);
L
Linus Torvalds 已提交
669 670 671
	return 0;
}

672 673
static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
				  struct dmxdev_filter *dmxdevfilter)
L
Linus Torvalds 已提交
674
{
675 676
	mutex_lock(&dmxdev->mutex);
	mutex_lock(&dmxdevfilter->mutex);
L
Linus Torvalds 已提交
677 678 679 680 681

	dvb_dmxdev_filter_stop(dmxdevfilter);
	dvb_dmxdev_filter_reset(dmxdevfilter);

	if (dmxdevfilter->buffer.data) {
682
		void *mem = dmxdevfilter->buffer.data;
L
Linus Torvalds 已提交
683 684

		spin_lock_irq(&dmxdev->lock);
685
		dmxdevfilter->buffer.data = NULL;
L
Linus Torvalds 已提交
686 687 688 689 690 691
		spin_unlock_irq(&dmxdev->lock);
		vfree(mem);
	}

	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE);
	wake_up(&dmxdevfilter->buffer.queue);
692 693
	mutex_unlock(&dmxdevfilter->mutex);
	mutex_unlock(&dmxdev->mutex);
L
Linus Torvalds 已提交
694 695 696 697 698 699 700
	return 0;
}

static inline void invert_mode(dmx_filter_t *filter)
{
	int i;

701 702
	for (i = 0; i < DMX_FILTER_SIZE; i++)
		filter->mode[i] ^= 0xff;
L
Linus Torvalds 已提交
703 704 705
}

static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev,
706 707
				 struct dmxdev_filter *dmxdevfilter,
				 struct dmx_sct_filter_params *params)
L
Linus Torvalds 已提交
708
{
709
	dprintk("function : %s\n", __FUNCTION__);
L
Linus Torvalds 已提交
710 711 712

	dvb_dmxdev_filter_stop(dmxdevfilter);

713
	dmxdevfilter->type = DMXDEV_TYPE_SEC;
L
Linus Torvalds 已提交
714 715 716 717 718
	memcpy(&dmxdevfilter->params.sec,
	       params, sizeof(struct dmx_sct_filter_params));
	invert_mode(&dmxdevfilter->params.sec.filter);
	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);

719
	if (params->flags & DMX_IMMEDIATE_START)
L
Linus Torvalds 已提交
720 721 722 723 724 725
		return dvb_dmxdev_filter_start(dmxdevfilter);

	return 0;
}

static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev,
726 727
				     struct dmxdev_filter *dmxdevfilter,
				     struct dmx_pes_filter_params *params)
L
Linus Torvalds 已提交
728 729 730
{
	dvb_dmxdev_filter_stop(dmxdevfilter);

731
	if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0)
L
Linus Torvalds 已提交
732 733
		return -EINVAL;

734 735 736
	dmxdevfilter->type = DMXDEV_TYPE_PES;
	memcpy(&dmxdevfilter->params, params,
	       sizeof(struct dmx_pes_filter_params));
L
Linus Torvalds 已提交
737 738 739

	dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET);

740
	if (params->flags & DMX_IMMEDIATE_START)
L
Linus Torvalds 已提交
741 742 743 744 745 746
		return dvb_dmxdev_filter_start(dmxdevfilter);

	return 0;
}

static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil,
747 748
				   struct file *file, char __user *buf,
				   size_t count, loff_t *ppos)
L
Linus Torvalds 已提交
749 750
{
	int result, hcount;
751 752 753 754 755 756 757 758 759 760 761
	int done = 0;

	if (dfil->todo <= 0) {
		hcount = 3 + dfil->todo;
		if (hcount > count)
			hcount = count;
		result = dvb_dmxdev_buffer_read(&dfil->buffer,
						file->f_flags & O_NONBLOCK,
						buf, hcount, ppos);
		if (result < 0) {
			dfil->todo = 0;
L
Linus Torvalds 已提交
762 763
			return result;
		}
764
		if (copy_from_user(dfil->secheader - dfil->todo, buf, result))
L
Linus Torvalds 已提交
765
			return -EFAULT;
766 767 768 769 770
		buf += result;
		done = result;
		count -= result;
		dfil->todo -= result;
		if (dfil->todo > -3)
L
Linus Torvalds 已提交
771
			return done;
772
		dfil->todo = ((dfil->secheader[1] << 8) | dfil->secheader[2]) & 0xfff;
L
Linus Torvalds 已提交
773 774 775
		if (!count)
			return done;
	}
776 777 778 779 780 781
	if (count > dfil->todo)
		count = dfil->todo;
	result = dvb_dmxdev_buffer_read(&dfil->buffer,
					file->f_flags & O_NONBLOCK,
					buf, count, ppos);
	if (result < 0)
L
Linus Torvalds 已提交
782
		return result;
783 784
	dfil->todo -= result;
	return (result + done);
L
Linus Torvalds 已提交
785 786 787
}

static ssize_t
788 789
dvb_demux_read(struct file *file, char __user *buf, size_t count,
	       loff_t *ppos)
L
Linus Torvalds 已提交
790
{
791 792
	struct dmxdev_filter *dmxdevfilter = file->private_data;
	int ret;
L
Linus Torvalds 已提交
793

794
	if (mutex_lock_interruptible(&dmxdevfilter->mutex))
L
Linus Torvalds 已提交
795 796
		return -ERESTARTSYS;

797 798
	if (dmxdevfilter->type == DMXDEV_TYPE_SEC)
		ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos);
L
Linus Torvalds 已提交
799
	else
800 801 802
		ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer,
					     file->f_flags & O_NONBLOCK,
					     buf, count, ppos);
L
Linus Torvalds 已提交
803

804
	mutex_unlock(&dmxdevfilter->mutex);
L
Linus Torvalds 已提交
805 806 807 808 809 810
	return ret;
}

static int dvb_demux_do_ioctl(struct inode *inode, struct file *file,
			      unsigned int cmd, void *parg)
{
811
	struct dmxdev_filter *dmxdevfilter = file->private_data;
812 813 814
	struct dmxdev *dmxdev = dmxdevfilter->dev;
	unsigned long arg = (unsigned long)parg;
	int ret = 0;
L
Linus Torvalds 已提交
815

816
	if (mutex_lock_interruptible(&dmxdev->mutex))
L
Linus Torvalds 已提交
817 818 819 820
		return -ERESTARTSYS;

	switch (cmd) {
	case DMX_START:
821 822
		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
			mutex_unlock(&dmxdev->mutex);
L
Linus Torvalds 已提交
823 824
			return -ERESTARTSYS;
		}
825
		if (dmxdevfilter->state < DMXDEV_STATE_SET)
L
Linus Torvalds 已提交
826 827 828
			ret = -EINVAL;
		else
			ret = dvb_dmxdev_filter_start(dmxdevfilter);
829
		mutex_unlock(&dmxdevfilter->mutex);
L
Linus Torvalds 已提交
830 831 832
		break;

	case DMX_STOP:
833 834
		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
			mutex_unlock(&dmxdev->mutex);
L
Linus Torvalds 已提交
835 836
			return -ERESTARTSYS;
		}
837
		ret = dvb_dmxdev_filter_stop(dmxdevfilter);
838
		mutex_unlock(&dmxdevfilter->mutex);
L
Linus Torvalds 已提交
839 840 841
		break;

	case DMX_SET_FILTER:
842 843
		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
			mutex_unlock(&dmxdev->mutex);
L
Linus Torvalds 已提交
844 845
			return -ERESTARTSYS;
		}
846
		ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg);
847
		mutex_unlock(&dmxdevfilter->mutex);
L
Linus Torvalds 已提交
848 849 850
		break;

	case DMX_SET_PES_FILTER:
851 852
		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
			mutex_unlock(&dmxdev->mutex);
L
Linus Torvalds 已提交
853 854
			return -ERESTARTSYS;
		}
855
		ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg);
856
		mutex_unlock(&dmxdevfilter->mutex);
L
Linus Torvalds 已提交
857 858 859
		break;

	case DMX_SET_BUFFER_SIZE:
860 861
		if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
			mutex_unlock(&dmxdev->mutex);
L
Linus Torvalds 已提交
862 863
			return -ERESTARTSYS;
		}
864
		ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg);
865
		mutex_unlock(&dmxdevfilter->mutex);
L
Linus Torvalds 已提交
866 867 868 869
		break;

	case DMX_GET_PES_PIDS:
		if (!dmxdev->demux->get_pes_pids) {
870
			ret = -EINVAL;
L
Linus Torvalds 已提交
871 872
			break;
		}
873
		dmxdev->demux->get_pes_pids(dmxdev->demux, parg);
L
Linus Torvalds 已提交
874 875
		break;

876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891
	case DMX_GET_CAPS:
		if (!dmxdev->demux->get_caps) {
			ret = -EINVAL;
			break;
		}
		ret = dmxdev->demux->get_caps(dmxdev->demux, parg);
		break;

	case DMX_SET_SOURCE:
		if (!dmxdev->demux->set_source) {
			ret = -EINVAL;
			break;
		}
		ret = dmxdev->demux->set_source(dmxdev->demux, parg);
		break;

L
Linus Torvalds 已提交
892 893
	case DMX_GET_STC:
		if (!dmxdev->demux->get_stc) {
894
			ret = -EINVAL;
L
Linus Torvalds 已提交
895 896 897
			break;
		}
		ret = dmxdev->demux->get_stc(dmxdev->demux,
898 899 900
					     ((struct dmx_stc *)parg)->num,
					     &((struct dmx_stc *)parg)->stc,
					     &((struct dmx_stc *)parg)->base);
L
Linus Torvalds 已提交
901 902 903
		break;

	default:
904 905
		ret = -EINVAL;
		break;
L
Linus Torvalds 已提交
906
	}
907
	mutex_unlock(&dmxdev->mutex);
L
Linus Torvalds 已提交
908 909 910 911 912 913 914 915 916
	return ret;
}

static int dvb_demux_ioctl(struct inode *inode, struct file *file,
			   unsigned int cmd, unsigned long arg)
{
	return dvb_usercopy(inode, file, cmd, arg, dvb_demux_do_ioctl);
}

917
static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
L
Linus Torvalds 已提交
918
{
919
	struct dmxdev_filter *dmxdevfilter = file->private_data;
L
Linus Torvalds 已提交
920 921 922 923 924 925 926 927 928 929 930 931 932 933 934
	unsigned int mask = 0;

	if (!dmxdevfilter)
		return -EINVAL;

	poll_wait(file, &dmxdevfilter->buffer.queue, wait);

	if (dmxdevfilter->state != DMXDEV_STATE_GO &&
	    dmxdevfilter->state != DMXDEV_STATE_DONE &&
	    dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT)
		return 0;

	if (dmxdevfilter->buffer.error)
		mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);

935
	if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
L
Linus Torvalds 已提交
936 937 938 939 940 941 942
		mask |= (POLLIN | POLLRDNORM | POLLPRI);

	return mask;
}

static int dvb_demux_release(struct inode *inode, struct file *file)
{
943
	struct dmxdev_filter *dmxdevfilter = file->private_data;
L
Linus Torvalds 已提交
944 945 946 947 948 949
	struct dmxdev *dmxdev = dmxdevfilter->dev;

	return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter);
}

static struct file_operations dvb_demux_fops = {
950 951 952 953 954 955
	.owner = THIS_MODULE,
	.read = dvb_demux_read,
	.ioctl = dvb_demux_ioctl,
	.open = dvb_demux_open,
	.release = dvb_demux_release,
	.poll = dvb_demux_poll,
L
Linus Torvalds 已提交
956 957 958
};

static struct dvb_device dvbdev_demux = {
959 960 961 962
	.priv = NULL,
	.users = 1,
	.writers = 1,
	.fops = &dvb_demux_fops
L
Linus Torvalds 已提交
963 964 965
};

static int dvb_dvr_do_ioctl(struct inode *inode, struct file *file,
966
			    unsigned int cmd, void *parg)
L
Linus Torvalds 已提交
967
{
968 969
	struct dvb_device *dvbdev = file->private_data;
	struct dmxdev *dmxdev = dvbdev->priv;
970
	int ret;
L
Linus Torvalds 已提交
971

972
	if (mutex_lock_interruptible(&dmxdev->mutex))
L
Linus Torvalds 已提交
973 974 975 976 977
		return -ERESTARTSYS;

	switch (cmd) {
	case DMX_SET_BUFFER_SIZE:
		// FIXME: implement
978
		ret = 0;
L
Linus Torvalds 已提交
979 980 981
		break;

	default:
982 983
		ret = -EINVAL;
		break;
L
Linus Torvalds 已提交
984
	}
985
	mutex_unlock(&dmxdev->mutex);
L
Linus Torvalds 已提交
986 987 988 989
	return ret;
}

static int dvb_dvr_ioctl(struct inode *inode, struct file *file,
990
			 unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
991 992 993 994
{
	return dvb_usercopy(inode, file, cmd, arg, dvb_dvr_do_ioctl);
}

995
static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
L
Linus Torvalds 已提交
996
{
997 998
	struct dvb_device *dvbdev = file->private_data;
	struct dmxdev *dmxdev = dvbdev->priv;
L
Linus Torvalds 已提交
999 1000
	unsigned int mask = 0;

1001
	dprintk("function : %s\n", __FUNCTION__);
L
Linus Torvalds 已提交
1002 1003 1004

	poll_wait(file, &dmxdev->dvr_buffer.queue, wait);

1005
	if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
L
Linus Torvalds 已提交
1006 1007 1008
		if (dmxdev->dvr_buffer.error)
			mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);

1009
		if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
L
Linus Torvalds 已提交
1010 1011 1012 1013 1014 1015 1016 1017
			mask |= (POLLIN | POLLRDNORM | POLLPRI);
	} else
		mask |= (POLLOUT | POLLWRNORM | POLLPRI);

	return mask;
}

static struct file_operations dvb_dvr_fops = {
1018 1019 1020 1021 1022 1023 1024
	.owner = THIS_MODULE,
	.read = dvb_dvr_read,
	.write = dvb_dvr_write,
	.ioctl = dvb_dvr_ioctl,
	.open = dvb_dvr_open,
	.release = dvb_dvr_release,
	.poll = dvb_dvr_poll,
L
Linus Torvalds 已提交
1025 1026 1027
};

static struct dvb_device dvbdev_dvr = {
1028
	.priv = NULL,
1029
	.readers = 1,
1030
	.fops = &dvb_dvr_fops
L
Linus Torvalds 已提交
1031 1032
};

1033
int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
L
Linus Torvalds 已提交
1034 1035 1036 1037 1038 1039
{
	int i;

	if (dmxdev->demux->open(dmxdev->demux) < 0)
		return -EUSERS;

1040
	dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter));
L
Linus Torvalds 已提交
1041 1042 1043
	if (!dmxdev->filter)
		return -ENOMEM;

1044
	mutex_init(&dmxdev->mutex);
L
Linus Torvalds 已提交
1045
	spin_lock_init(&dmxdev->lock);
1046 1047 1048 1049 1050
	for (i = 0; i < dmxdev->filternum; i++) {
		dmxdev->filter[i].dev = dmxdev;
		dmxdev->filter[i].buffer.data = NULL;
		dvb_dmxdev_filter_state_set(&dmxdev->filter[i],
					    DMXDEV_STATE_FREE);
L
Linus Torvalds 已提交
1051 1052
	}

1053 1054 1055 1056
	dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev,
			    DVB_DEVICE_DEMUX);
	dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr,
			    dmxdev, DVB_DEVICE_DVR);
L
Linus Torvalds 已提交
1057

1058
	dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192);
L
Linus Torvalds 已提交
1059 1060 1061

	return 0;
}
1062

L
Linus Torvalds 已提交
1063 1064
EXPORT_SYMBOL(dvb_dmxdev_init);

1065
void dvb_dmxdev_release(struct dmxdev *dmxdev)
L
Linus Torvalds 已提交
1066 1067 1068 1069 1070
{
	dvb_unregister_device(dmxdev->dvbdev);
	dvb_unregister_device(dmxdev->dvr_dvbdev);

	vfree(dmxdev->filter);
1071
	dmxdev->filter = NULL;
L
Linus Torvalds 已提交
1072 1073
	dmxdev->demux->close(dmxdev->demux);
}
1074

L
Linus Torvalds 已提交
1075
EXPORT_SYMBOL(dvb_dmxdev_release);