diff options
Diffstat (limited to 'drivers/media/dvb/dvb-core/dmxdev.c')
-rw-r--r-- | drivers/media/dvb/dvb-core/dmxdev.c | 1278 |
1 files changed, 1278 insertions, 0 deletions
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); | ||