Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * dmxdev.c - DVB demultiplexer device | |
3 | * | |
f705e6e4 AO |
4 | * Copyright (C) 2000 Ralph Metzler & Marcus Metzler |
5 | * for convergence integrated media GmbH | |
1da177e4 LT |
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 | ||
b3ad24d2 MCC |
23 | #define pr_fmt(fmt) "dmxdev: " fmt |
24 | ||
a99bbaf5 | 25 | #include <linux/sched.h> |
1da177e4 LT |
26 | #include <linux/spinlock.h> |
27 | #include <linux/slab.h> | |
28 | #include <linux/vmalloc.h> | |
29 | #include <linux/module.h> | |
1da177e4 LT |
30 | #include <linux/poll.h> |
31 | #include <linux/ioctl.h> | |
32 | #include <linux/wait.h> | |
7c0f6ba6 | 33 | #include <linux/uaccess.h> |
1da177e4 LT |
34 | #include "dmxdev.h" |
35 | ||
36 | static int debug; | |
37 | ||
38 | module_param(debug, int, 0644); | |
39 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | |
40 | ||
b3ad24d2 MCC |
41 | #define dprintk(fmt, arg...) do { \ |
42 | if (debug) \ | |
43 | printk(KERN_DEBUG pr_fmt("%s: " fmt), \ | |
44 | __func__, ##arg); \ | |
45 | } while (0) | |
1da177e4 | 46 | |
34731df2 AO |
47 | static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf, |
48 | const u8 *src, size_t len) | |
1da177e4 | 49 | { |
34731df2 | 50 | ssize_t free; |
1da177e4 LT |
51 | |
52 | if (!len) | |
53 | return 0; | |
54 | if (!buf->data) | |
55 | return 0; | |
56 | ||
34731df2 AO |
57 | free = dvb_ringbuffer_free(buf); |
58 | if (len > free) { | |
b3ad24d2 | 59 | dprintk("buffer overflow\n"); |
34731df2 | 60 | return -EOVERFLOW; |
1da177e4 | 61 | } |
34731df2 AO |
62 | |
63 | return dvb_ringbuffer_write(buf, src, len); | |
1da177e4 LT |
64 | } |
65 | ||
34731df2 | 66 | static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src, |
f705e6e4 AO |
67 | int non_blocking, char __user *buf, |
68 | size_t count, loff_t *ppos) | |
1da177e4 | 69 | { |
34731df2 AO |
70 | size_t todo; |
71 | ssize_t avail; | |
72 | ssize_t ret = 0; | |
1da177e4 LT |
73 | |
74 | if (!src->data) | |
75 | return 0; | |
76 | ||
34731df2 AO |
77 | if (src->error) { |
78 | ret = src->error; | |
79 | dvb_ringbuffer_flush(src); | |
80 | return ret; | |
1da177e4 LT |
81 | } |
82 | ||
34731df2 AO |
83 | for (todo = count; todo > 0; todo -= ret) { |
84 | if (non_blocking && dvb_ringbuffer_empty(src)) { | |
85 | ret = -EWOULDBLOCK; | |
86 | break; | |
87 | } | |
1da177e4 | 88 | |
34731df2 AO |
89 | ret = wait_event_interruptible(src->queue, |
90 | !dvb_ringbuffer_empty(src) || | |
91 | (src->error != 0)); | |
92 | if (ret < 0) | |
93 | break; | |
1da177e4 | 94 | |
34731df2 AO |
95 | if (src->error) { |
96 | ret = src->error; | |
97 | dvb_ringbuffer_flush(src); | |
98 | break; | |
1da177e4 LT |
99 | } |
100 | ||
34731df2 | 101 | avail = dvb_ringbuffer_avail(src); |
f705e6e4 AO |
102 | if (avail > todo) |
103 | avail = todo; | |
34731df2 | 104 | |
b0ba0e3a | 105 | ret = dvb_ringbuffer_read_user(src, buf, avail); |
34731df2 AO |
106 | if (ret < 0) |
107 | break; | |
108 | ||
109 | buf += ret; | |
1da177e4 | 110 | } |
34731df2 AO |
111 | |
112 | return (count - todo) ? (count - todo) : ret; | |
1da177e4 LT |
113 | } |
114 | ||
f705e6e4 | 115 | static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type) |
1da177e4 LT |
116 | { |
117 | struct list_head *head, *pos; | |
118 | ||
f705e6e4 | 119 | head = demux->get_frontends(demux); |
1da177e4 LT |
120 | if (!head) |
121 | return NULL; | |
122 | list_for_each(pos, head) | |
f705e6e4 | 123 | if (DMX_FE_ENTRY(pos)->source == type) |
1da177e4 LT |
124 | return DMX_FE_ENTRY(pos); |
125 | ||
126 | return NULL; | |
127 | } | |
128 | ||
1da177e4 LT |
129 | static int dvb_dvr_open(struct inode *inode, struct file *file) |
130 | { | |
0c53c70f JS |
131 | struct dvb_device *dvbdev = file->private_data; |
132 | struct dmxdev *dmxdev = dvbdev->priv; | |
1da177e4 LT |
133 | struct dmx_frontend *front; |
134 | ||
b3ad24d2 | 135 | dprintk("%s\n", __func__); |
1da177e4 | 136 | |
3593cab5 | 137 | if (mutex_lock_interruptible(&dmxdev->mutex)) |
1da177e4 LT |
138 | return -ERESTARTSYS; |
139 | ||
57861b43 MR |
140 | if (dmxdev->exit) { |
141 | mutex_unlock(&dmxdev->mutex); | |
142 | return -ENODEV; | |
143 | } | |
144 | ||
f705e6e4 AO |
145 | if ((file->f_flags & O_ACCMODE) == O_RDWR) { |
146 | if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) { | |
3593cab5 | 147 | mutex_unlock(&dmxdev->mutex); |
1da177e4 LT |
148 | return -EOPNOTSUPP; |
149 | } | |
150 | } | |
151 | ||
f705e6e4 | 152 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) { |
5e85bd05 TP |
153 | void *mem; |
154 | if (!dvbdev->readers) { | |
155 | mutex_unlock(&dmxdev->mutex); | |
156 | return -EBUSY; | |
157 | } | |
158 | mem = vmalloc(DVR_BUFFER_SIZE); | |
34731df2 | 159 | if (!mem) { |
f705e6e4 AO |
160 | mutex_unlock(&dmxdev->mutex); |
161 | return -ENOMEM; | |
162 | } | |
34731df2 | 163 | dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE); |
5e85bd05 | 164 | dvbdev->readers--; |
1da177e4 LT |
165 | } |
166 | ||
f705e6e4 AO |
167 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) { |
168 | dmxdev->dvr_orig_fe = dmxdev->demux->frontend; | |
1da177e4 LT |
169 | |
170 | if (!dmxdev->demux->write) { | |
3593cab5 | 171 | mutex_unlock(&dmxdev->mutex); |
1da177e4 LT |
172 | return -EOPNOTSUPP; |
173 | } | |
174 | ||
f705e6e4 | 175 | front = get_fe(dmxdev->demux, DMX_MEMORY_FE); |
1da177e4 LT |
176 | |
177 | if (!front) { | |
3593cab5 | 178 | mutex_unlock(&dmxdev->mutex); |
1da177e4 LT |
179 | return -EINVAL; |
180 | } | |
181 | dmxdev->demux->disconnect_frontend(dmxdev->demux); | |
182 | dmxdev->demux->connect_frontend(dmxdev->demux, front); | |
183 | } | |
57861b43 | 184 | dvbdev->users++; |
3593cab5 | 185 | mutex_unlock(&dmxdev->mutex); |
1da177e4 LT |
186 | return 0; |
187 | } | |
188 | ||
189 | static int dvb_dvr_release(struct inode *inode, struct file *file) | |
190 | { | |
0c53c70f JS |
191 | struct dvb_device *dvbdev = file->private_data; |
192 | struct dmxdev *dmxdev = dvbdev->priv; | |
1da177e4 | 193 | |
c2788502 | 194 | mutex_lock(&dmxdev->mutex); |
1da177e4 | 195 | |
f705e6e4 | 196 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) { |
1da177e4 LT |
197 | dmxdev->demux->disconnect_frontend(dmxdev->demux); |
198 | dmxdev->demux->connect_frontend(dmxdev->demux, | |
199 | dmxdev->dvr_orig_fe); | |
200 | } | |
f705e6e4 | 201 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) { |
5e85bd05 | 202 | dvbdev->readers++; |
1da177e4 | 203 | if (dmxdev->dvr_buffer.data) { |
f705e6e4 | 204 | void *mem = dmxdev->dvr_buffer.data; |
1da177e4 LT |
205 | mb(); |
206 | spin_lock_irq(&dmxdev->lock); | |
f705e6e4 | 207 | dmxdev->dvr_buffer.data = NULL; |
1da177e4 LT |
208 | spin_unlock_irq(&dmxdev->lock); |
209 | vfree(mem); | |
210 | } | |
211 | } | |
57861b43 MR |
212 | /* TODO */ |
213 | dvbdev->users--; | |
1c488ea9 | 214 | if (dvbdev->users == 1 && dmxdev->exit == 1) { |
57861b43 MR |
215 | mutex_unlock(&dmxdev->mutex); |
216 | wake_up(&dvbdev->wait_queue); | |
217 | } else | |
218 | mutex_unlock(&dmxdev->mutex); | |
219 | ||
1da177e4 LT |
220 | return 0; |
221 | } | |
222 | ||
223 | static ssize_t dvb_dvr_write(struct file *file, const char __user *buf, | |
f705e6e4 | 224 | size_t count, loff_t *ppos) |
1da177e4 | 225 | { |
0c53c70f JS |
226 | struct dvb_device *dvbdev = file->private_data; |
227 | struct dmxdev *dmxdev = dvbdev->priv; | |
1da177e4 LT |
228 | int ret; |
229 | ||
230 | if (!dmxdev->demux->write) | |
231 | return -EOPNOTSUPP; | |
f705e6e4 | 232 | if ((file->f_flags & O_ACCMODE) != O_WRONLY) |
1da177e4 | 233 | return -EINVAL; |
3593cab5 | 234 | if (mutex_lock_interruptible(&dmxdev->mutex)) |
1da177e4 | 235 | return -ERESTARTSYS; |
57861b43 MR |
236 | |
237 | if (dmxdev->exit) { | |
238 | mutex_unlock(&dmxdev->mutex); | |
239 | return -ENODEV; | |
240 | } | |
f705e6e4 | 241 | ret = dmxdev->demux->write(dmxdev->demux, buf, count); |
3593cab5 | 242 | mutex_unlock(&dmxdev->mutex); |
1da177e4 LT |
243 | return ret; |
244 | } | |
245 | ||
246 | static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count, | |
f705e6e4 | 247 | loff_t *ppos) |
1da177e4 | 248 | { |
0c53c70f JS |
249 | struct dvb_device *dvbdev = file->private_data; |
250 | struct dmxdev *dmxdev = dvbdev->priv; | |
1da177e4 | 251 | |
eda9f752 | 252 | if (dmxdev->exit) |
57861b43 | 253 | return -ENODEV; |
57861b43 | 254 | |
eda9f752 SA |
255 | return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, |
256 | file->f_flags & O_NONBLOCK, | |
257 | buf, count, ppos); | |
1da177e4 LT |
258 | } |
259 | ||
a095be4b AO |
260 | static int dvb_dvr_set_buffer_size(struct dmxdev *dmxdev, |
261 | unsigned long size) | |
262 | { | |
263 | struct dvb_ringbuffer *buf = &dmxdev->dvr_buffer; | |
264 | void *newmem; | |
265 | void *oldmem; | |
266 | ||
b3ad24d2 | 267 | dprintk("%s\n", __func__); |
a095be4b AO |
268 | |
269 | if (buf->size == size) | |
270 | return 0; | |
271 | if (!size) | |
272 | return -EINVAL; | |
273 | ||
274 | newmem = vmalloc(size); | |
275 | if (!newmem) | |
276 | return -ENOMEM; | |
277 | ||
278 | oldmem = buf->data; | |
279 | ||
280 | spin_lock_irq(&dmxdev->lock); | |
281 | buf->data = newmem; | |
282 | buf->size = size; | |
283 | ||
284 | /* reset and not flush in case the buffer shrinks */ | |
285 | dvb_ringbuffer_reset(buf); | |
286 | spin_unlock_irq(&dmxdev->lock); | |
287 | ||
288 | vfree(oldmem); | |
289 | ||
290 | return 0; | |
291 | } | |
292 | ||
f705e6e4 AO |
293 | static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter |
294 | *dmxdevfilter, int state) | |
1da177e4 LT |
295 | { |
296 | spin_lock_irq(&dmxdevfilter->dev->lock); | |
f705e6e4 | 297 | dmxdevfilter->state = state; |
1da177e4 LT |
298 | spin_unlock_irq(&dmxdevfilter->dev->lock); |
299 | } | |
300 | ||
f705e6e4 AO |
301 | static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, |
302 | unsigned long size) | |
1da177e4 | 303 | { |
34731df2 | 304 | struct dvb_ringbuffer *buf = &dmxdevfilter->buffer; |
a095be4b AO |
305 | void *newmem; |
306 | void *oldmem; | |
1da177e4 | 307 | |
f705e6e4 | 308 | if (buf->size == size) |
1da177e4 | 309 | return 0; |
a095be4b AO |
310 | if (!size) |
311 | return -EINVAL; | |
f705e6e4 | 312 | if (dmxdevfilter->state >= DMXDEV_STATE_GO) |
1da177e4 | 313 | return -EBUSY; |
a095be4b AO |
314 | |
315 | newmem = vmalloc(size); | |
316 | if (!newmem) | |
317 | return -ENOMEM; | |
318 | ||
319 | oldmem = buf->data; | |
320 | ||
1da177e4 | 321 | spin_lock_irq(&dmxdevfilter->dev->lock); |
a095be4b | 322 | buf->data = newmem; |
f705e6e4 | 323 | buf->size = size; |
48c01a9c AO |
324 | |
325 | /* reset and not flush in case the buffer shrinks */ | |
326 | dvb_ringbuffer_reset(buf); | |
1da177e4 | 327 | spin_unlock_irq(&dmxdevfilter->dev->lock); |
1da177e4 | 328 | |
a095be4b AO |
329 | vfree(oldmem); |
330 | ||
1da177e4 LT |
331 | return 0; |
332 | } | |
333 | ||
334 | static void dvb_dmxdev_filter_timeout(unsigned long data) | |
335 | { | |
f705e6e4 | 336 | struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data; |
1da177e4 | 337 | |
f705e6e4 | 338 | dmxdevfilter->buffer.error = -ETIMEDOUT; |
1da177e4 | 339 | spin_lock_irq(&dmxdevfilter->dev->lock); |
f705e6e4 | 340 | dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT; |
1da177e4 LT |
341 | spin_unlock_irq(&dmxdevfilter->dev->lock); |
342 | wake_up(&dmxdevfilter->buffer.queue); | |
343 | } | |
344 | ||
345 | static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter) | |
346 | { | |
f705e6e4 | 347 | struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec; |
1da177e4 LT |
348 | |
349 | del_timer(&dmxdevfilter->timer); | |
350 | if (para->timeout) { | |
f705e6e4 AO |
351 | dmxdevfilter->timer.function = dvb_dmxdev_filter_timeout; |
352 | dmxdevfilter->timer.data = (unsigned long)dmxdevfilter; | |
353 | dmxdevfilter->timer.expires = | |
354 | jiffies + 1 + (HZ / 2 + HZ * para->timeout) / 1000; | |
1da177e4 LT |
355 | add_timer(&dmxdevfilter->timer); |
356 | } | |
357 | } | |
358 | ||
359 | static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, | |
f705e6e4 | 360 | const u8 *buffer2, size_t buffer2_len, |
2f684b23 | 361 | struct dmx_section_filter *filter) |
1da177e4 | 362 | { |
0c53c70f | 363 | struct dmxdev_filter *dmxdevfilter = filter->priv; |
1da177e4 LT |
364 | int ret; |
365 | ||
366 | if (dmxdevfilter->buffer.error) { | |
367 | wake_up(&dmxdevfilter->buffer.queue); | |
368 | return 0; | |
369 | } | |
28100165 | 370 | spin_lock(&dmxdevfilter->dev->lock); |
f705e6e4 | 371 | if (dmxdevfilter->state != DMXDEV_STATE_GO) { |
28100165 | 372 | spin_unlock(&dmxdevfilter->dev->lock); |
1da177e4 LT |
373 | return 0; |
374 | } | |
375 | del_timer(&dmxdevfilter->timer); | |
b3ad24d2 | 376 | dprintk("section callback %*ph\n", 6, buffer1); |
f705e6e4 AO |
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); | |
1da177e4 | 382 | } |
414abbd2 | 383 | if (ret < 0) |
34731df2 | 384 | dmxdevfilter->buffer.error = ret; |
f705e6e4 AO |
385 | if (dmxdevfilter->params.sec.flags & DMX_ONESHOT) |
386 | dmxdevfilter->state = DMXDEV_STATE_DONE; | |
28100165 | 387 | spin_unlock(&dmxdevfilter->dev->lock); |
1da177e4 LT |
388 | wake_up(&dmxdevfilter->buffer.queue); |
389 | return 0; | |
390 | } | |
391 | ||
392 | static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, | |
f705e6e4 | 393 | const u8 *buffer2, size_t buffer2_len, |
2f684b23 | 394 | struct dmx_ts_feed *feed) |
1da177e4 | 395 | { |
0c53c70f | 396 | struct dmxdev_filter *dmxdevfilter = feed->priv; |
34731df2 | 397 | struct dvb_ringbuffer *buffer; |
1da177e4 LT |
398 | int ret; |
399 | ||
28100165 | 400 | spin_lock(&dmxdevfilter->dev->lock); |
f705e6e4 | 401 | if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) { |
28100165 | 402 | spin_unlock(&dmxdevfilter->dev->lock); |
1da177e4 LT |
403 | return 0; |
404 | } | |
405 | ||
b01cd937 PH |
406 | if (dmxdevfilter->params.pes.output == DMX_OUT_TAP |
407 | || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) | |
f705e6e4 | 408 | buffer = &dmxdevfilter->buffer; |
1da177e4 | 409 | else |
f705e6e4 | 410 | buffer = &dmxdevfilter->dev->dvr_buffer; |
1da177e4 | 411 | if (buffer->error) { |
28100165 | 412 | spin_unlock(&dmxdevfilter->dev->lock); |
1da177e4 LT |
413 | wake_up(&buffer->queue); |
414 | return 0; | |
415 | } | |
f705e6e4 AO |
416 | ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len); |
417 | if (ret == buffer1_len) | |
418 | ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len); | |
414abbd2 | 419 | if (ret < 0) |
34731df2 | 420 | buffer->error = ret; |
28100165 | 421 | spin_unlock(&dmxdevfilter->dev->lock); |
1da177e4 LT |
422 | wake_up(&buffer->queue); |
423 | return 0; | |
424 | } | |
425 | ||
1da177e4 | 426 | /* stop feed but only mark the specified filter as stopped (state set) */ |
1da177e4 LT |
427 | static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter) |
428 | { | |
1cb662a3 AO |
429 | struct dmxdev_feed *feed; |
430 | ||
1da177e4 LT |
431 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); |
432 | ||
433 | switch (dmxdevfilter->type) { | |
434 | case DMXDEV_TYPE_SEC: | |
435 | del_timer(&dmxdevfilter->timer); | |
436 | dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec); | |
437 | break; | |
438 | case DMXDEV_TYPE_PES: | |
1cb662a3 AO |
439 | list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) |
440 | feed->ts->stop_filtering(feed->ts); | |
1da177e4 LT |
441 | break; |
442 | default: | |
443 | return -EINVAL; | |
444 | } | |
445 | return 0; | |
446 | } | |
447 | ||
1da177e4 | 448 | /* start feed associated with the specified filter */ |
1da177e4 LT |
449 | static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter) |
450 | { | |
1cb662a3 AO |
451 | struct dmxdev_feed *feed; |
452 | int ret; | |
453 | ||
f705e6e4 | 454 | dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO); |
1da177e4 LT |
455 | |
456 | switch (filter->type) { | |
457 | case DMXDEV_TYPE_SEC: | |
458 | return filter->feed.sec->start_filtering(filter->feed.sec); | |
1da177e4 | 459 | case DMXDEV_TYPE_PES: |
1cb662a3 AO |
460 | list_for_each_entry(feed, &filter->feed.ts, next) { |
461 | ret = feed->ts->start_filtering(feed->ts); | |
462 | if (ret < 0) { | |
463 | dvb_dmxdev_feed_stop(filter); | |
464 | return ret; | |
465 | } | |
466 | } | |
467 | break; | |
1da177e4 LT |
468 | default: |
469 | return -EINVAL; | |
470 | } | |
471 | ||
472 | return 0; | |
473 | } | |
474 | ||
1da177e4 LT |
475 | /* restart section feed if it has filters left associated with it, |
476 | otherwise release the feed */ | |
1da177e4 LT |
477 | static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter) |
478 | { | |
479 | int i; | |
480 | struct dmxdev *dmxdev = filter->dev; | |
481 | u16 pid = filter->params.sec.pid; | |
482 | ||
f705e6e4 AO |
483 | for (i = 0; i < dmxdev->filternum; i++) |
484 | if (dmxdev->filter[i].state >= DMXDEV_STATE_GO && | |
485 | dmxdev->filter[i].type == DMXDEV_TYPE_SEC && | |
486 | dmxdev->filter[i].params.sec.pid == pid) { | |
1da177e4 LT |
487 | dvb_dmxdev_feed_start(&dmxdev->filter[i]); |
488 | return 0; | |
489 | } | |
490 | ||
f705e6e4 AO |
491 | filter->dev->demux->release_section_feed(dmxdev->demux, |
492 | filter->feed.sec); | |
1da177e4 LT |
493 | |
494 | return 0; | |
495 | } | |
496 | ||
497 | static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter) | |
498 | { | |
1cb662a3 AO |
499 | struct dmxdev_feed *feed; |
500 | struct dmx_demux *demux; | |
501 | ||
f705e6e4 | 502 | if (dmxdevfilter->state < DMXDEV_STATE_GO) |
1da177e4 LT |
503 | return 0; |
504 | ||
505 | switch (dmxdevfilter->type) { | |
506 | case DMXDEV_TYPE_SEC: | |
507 | if (!dmxdevfilter->feed.sec) | |
508 | break; | |
509 | dvb_dmxdev_feed_stop(dmxdevfilter); | |
510 | if (dmxdevfilter->filter.sec) | |
511 | dmxdevfilter->feed.sec-> | |
f705e6e4 AO |
512 | release_filter(dmxdevfilter->feed.sec, |
513 | dmxdevfilter->filter.sec); | |
1da177e4 | 514 | dvb_dmxdev_feed_restart(dmxdevfilter); |
f705e6e4 | 515 | dmxdevfilter->feed.sec = NULL; |
1da177e4 LT |
516 | break; |
517 | case DMXDEV_TYPE_PES: | |
1da177e4 | 518 | dvb_dmxdev_feed_stop(dmxdevfilter); |
1cb662a3 AO |
519 | demux = dmxdevfilter->dev->demux; |
520 | list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) { | |
521 | demux->release_ts_feed(demux, feed->ts); | |
522 | feed->ts = NULL; | |
523 | } | |
1da177e4 LT |
524 | break; |
525 | default: | |
f705e6e4 | 526 | if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED) |
1da177e4 LT |
527 | return 0; |
528 | return -EINVAL; | |
529 | } | |
34731df2 AO |
530 | |
531 | dvb_ringbuffer_flush(&dmxdevfilter->buffer); | |
1da177e4 LT |
532 | return 0; |
533 | } | |
534 | ||
1cb662a3 AO |
535 | static void dvb_dmxdev_delete_pids(struct dmxdev_filter *dmxdevfilter) |
536 | { | |
537 | struct dmxdev_feed *feed, *tmp; | |
538 | ||
539 | /* delete all PIDs */ | |
540 | list_for_each_entry_safe(feed, tmp, &dmxdevfilter->feed.ts, next) { | |
541 | list_del(&feed->next); | |
542 | kfree(feed); | |
543 | } | |
544 | ||
545 | BUG_ON(!list_empty(&dmxdevfilter->feed.ts)); | |
546 | } | |
547 | ||
1da177e4 LT |
548 | static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter) |
549 | { | |
f705e6e4 | 550 | if (dmxdevfilter->state < DMXDEV_STATE_SET) |
1da177e4 LT |
551 | return 0; |
552 | ||
1cb662a3 AO |
553 | if (dmxdevfilter->type == DMXDEV_TYPE_PES) |
554 | dvb_dmxdev_delete_pids(dmxdevfilter); | |
555 | ||
f705e6e4 | 556 | dmxdevfilter->type = DMXDEV_TYPE_NONE; |
1da177e4 LT |
557 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); |
558 | return 0; | |
559 | } | |
560 | ||
1cb662a3 AO |
561 | static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, |
562 | struct dmxdev_filter *filter, | |
563 | struct dmxdev_feed *feed) | |
564 | { | |
e95be158 | 565 | ktime_t timeout = ktime_set(0, 0); |
1cb662a3 AO |
566 | struct dmx_pes_filter_params *para = &filter->params.pes; |
567 | dmx_output_t otype; | |
568 | int ret; | |
569 | int ts_type; | |
fde04ab9 | 570 | enum dmx_ts_pes ts_pes; |
1cb662a3 AO |
571 | struct dmx_ts_feed *tsfeed; |
572 | ||
573 | feed->ts = NULL; | |
574 | otype = para->output; | |
575 | ||
9ae2ae35 | 576 | ts_pes = para->pes_type; |
1cb662a3 AO |
577 | |
578 | if (ts_pes < DMX_PES_OTHER) | |
579 | ts_type = TS_DECODER; | |
580 | else | |
581 | ts_type = 0; | |
582 | ||
583 | if (otype == DMX_OUT_TS_TAP) | |
584 | ts_type |= TS_PACKET; | |
585 | else if (otype == DMX_OUT_TSDEMUX_TAP) | |
586 | ts_type |= TS_PACKET | TS_DEMUX; | |
587 | else if (otype == DMX_OUT_TAP) | |
588 | ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY; | |
589 | ||
590 | ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux, &feed->ts, | |
591 | dvb_dmxdev_ts_callback); | |
592 | if (ret < 0) | |
593 | return ret; | |
594 | ||
595 | tsfeed = feed->ts; | |
596 | tsfeed->priv = filter; | |
597 | ||
dd79d27e | 598 | ret = tsfeed->set(tsfeed, feed->pid, ts_type, ts_pes, timeout); |
1cb662a3 AO |
599 | if (ret < 0) { |
600 | dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); | |
601 | return ret; | |
602 | } | |
603 | ||
604 | ret = tsfeed->start_filtering(tsfeed); | |
605 | if (ret < 0) { | |
606 | dmxdev->demux->release_ts_feed(dmxdev->demux, tsfeed); | |
607 | return ret; | |
608 | } | |
609 | ||
610 | return 0; | |
611 | } | |
612 | ||
1da177e4 LT |
613 | static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) |
614 | { | |
615 | struct dmxdev *dmxdev = filter->dev; | |
1cb662a3 | 616 | struct dmxdev_feed *feed; |
1da177e4 LT |
617 | void *mem; |
618 | int ret, i; | |
619 | ||
620 | if (filter->state < DMXDEV_STATE_SET) | |
621 | return -EINVAL; | |
622 | ||
623 | if (filter->state >= DMXDEV_STATE_GO) | |
624 | dvb_dmxdev_filter_stop(filter); | |
625 | ||
34731df2 | 626 | if (!filter->buffer.data) { |
1da177e4 | 627 | mem = vmalloc(filter->buffer.size); |
34731df2 AO |
628 | if (!mem) |
629 | return -ENOMEM; | |
1da177e4 | 630 | spin_lock_irq(&filter->dev->lock); |
f705e6e4 | 631 | filter->buffer.data = mem; |
1da177e4 | 632 | spin_unlock_irq(&filter->dev->lock); |
1da177e4 LT |
633 | } |
634 | ||
34731df2 | 635 | dvb_ringbuffer_flush(&filter->buffer); |
1da177e4 LT |
636 | |
637 | switch (filter->type) { | |
638 | case DMXDEV_TYPE_SEC: | |
639 | { | |
f705e6e4 AO |
640 | struct dmx_sct_filter_params *para = &filter->params.sec; |
641 | struct dmx_section_filter **secfilter = &filter->filter.sec; | |
642 | struct dmx_section_feed **secfeed = &filter->feed.sec; | |
643 | ||
644 | *secfilter = NULL; | |
645 | *secfeed = NULL; | |
1da177e4 | 646 | |
1da177e4 LT |
647 | |
648 | /* find active filter/feed with same PID */ | |
f705e6e4 | 649 | for (i = 0; i < dmxdev->filternum; i++) { |
1da177e4 | 650 | if (dmxdev->filter[i].state >= DMXDEV_STATE_GO && |
09794a6f AO |
651 | dmxdev->filter[i].type == DMXDEV_TYPE_SEC && |
652 | dmxdev->filter[i].params.sec.pid == para->pid) { | |
1da177e4 LT |
653 | *secfeed = dmxdev->filter[i].feed.sec; |
654 | break; | |
655 | } | |
656 | } | |
657 | ||
658 | /* if no feed found, try to allocate new one */ | |
659 | if (!*secfeed) { | |
f705e6e4 AO |
660 | ret = dmxdev->demux->allocate_section_feed(dmxdev->demux, |
661 | secfeed, | |
662 | dvb_dmxdev_section_callback); | |
663 | if (ret < 0) { | |
b3ad24d2 | 664 | pr_err("DVB (%s): could not alloc feed\n", |
46b4f7c1 | 665 | __func__); |
1da177e4 LT |
666 | return ret; |
667 | } | |
668 | ||
dd79d27e | 669 | ret = (*secfeed)->set(*secfeed, para->pid, |
f705e6e4 AO |
670 | (para->flags & DMX_CHECK_CRC) ? 1 : 0); |
671 | if (ret < 0) { | |
b3ad24d2 | 672 | pr_err("DVB (%s): could not set feed\n", |
46b4f7c1 | 673 | __func__); |
1da177e4 LT |
674 | dvb_dmxdev_feed_restart(filter); |
675 | return ret; | |
676 | } | |
677 | } else { | |
678 | dvb_dmxdev_feed_stop(filter); | |
679 | } | |
680 | ||
f705e6e4 | 681 | ret = (*secfeed)->allocate_filter(*secfeed, secfilter); |
1da177e4 LT |
682 | if (ret < 0) { |
683 | dvb_dmxdev_feed_restart(filter); | |
684 | filter->feed.sec->start_filtering(*secfeed); | |
f705e6e4 | 685 | dprintk("could not get filter\n"); |
1da177e4 LT |
686 | return ret; |
687 | } | |
688 | ||
689 | (*secfilter)->priv = filter; | |
690 | ||
691 | memcpy(&((*secfilter)->filter_value[3]), | |
f705e6e4 | 692 | &(para->filter.filter[1]), DMX_FILTER_SIZE - 1); |
1da177e4 | 693 | memcpy(&(*secfilter)->filter_mask[3], |
f705e6e4 | 694 | ¶->filter.mask[1], DMX_FILTER_SIZE - 1); |
1da177e4 | 695 | memcpy(&(*secfilter)->filter_mode[3], |
f705e6e4 | 696 | ¶->filter.mode[1], DMX_FILTER_SIZE - 1); |
1da177e4 | 697 | |
f705e6e4 AO |
698 | (*secfilter)->filter_value[0] = para->filter.filter[0]; |
699 | (*secfilter)->filter_mask[0] = para->filter.mask[0]; | |
700 | (*secfilter)->filter_mode[0] = para->filter.mode[0]; | |
701 | (*secfilter)->filter_mask[1] = 0; | |
702 | (*secfilter)->filter_mask[2] = 0; | |
1da177e4 LT |
703 | |
704 | filter->todo = 0; | |
705 | ||
f705e6e4 | 706 | ret = filter->feed.sec->start_filtering(filter->feed.sec); |
1da177e4 LT |
707 | if (ret < 0) |
708 | return ret; | |
709 | ||
710 | dvb_dmxdev_filter_timer(filter); | |
711 | break; | |
712 | } | |
1da177e4 | 713 | case DMXDEV_TYPE_PES: |
1cb662a3 AO |
714 | list_for_each_entry(feed, &filter->feed.ts, next) { |
715 | ret = dvb_dmxdev_start_feed(dmxdev, filter, feed); | |
716 | if (ret < 0) { | |
717 | dvb_dmxdev_filter_stop(filter); | |
718 | return ret; | |
719 | } | |
76197924 | 720 | } |
1da177e4 | 721 | break; |
1da177e4 LT |
722 | default: |
723 | return -EINVAL; | |
724 | } | |
725 | ||
726 | dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO); | |
727 | return 0; | |
728 | } | |
729 | ||
730 | static int dvb_demux_open(struct inode *inode, struct file *file) | |
731 | { | |
0c53c70f JS |
732 | struct dvb_device *dvbdev = file->private_data; |
733 | struct dmxdev *dmxdev = dvbdev->priv; | |
1da177e4 LT |
734 | int i; |
735 | struct dmxdev_filter *dmxdevfilter; | |
736 | ||
737 | if (!dmxdev->filter) | |
738 | return -EINVAL; | |
739 | ||
3593cab5 | 740 | if (mutex_lock_interruptible(&dmxdev->mutex)) |
1da177e4 LT |
741 | return -ERESTARTSYS; |
742 | ||
f705e6e4 AO |
743 | for (i = 0; i < dmxdev->filternum; i++) |
744 | if (dmxdev->filter[i].state == DMXDEV_STATE_FREE) | |
1da177e4 LT |
745 | break; |
746 | ||
f705e6e4 | 747 | if (i == dmxdev->filternum) { |
3593cab5 | 748 | mutex_unlock(&dmxdev->mutex); |
1da177e4 LT |
749 | return -EMFILE; |
750 | } | |
751 | ||
f705e6e4 | 752 | dmxdevfilter = &dmxdev->filter[i]; |
3593cab5 | 753 | mutex_init(&dmxdevfilter->mutex); |
f705e6e4 | 754 | file->private_data = dmxdevfilter; |
1da177e4 | 755 | |
34731df2 | 756 | dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192); |
f705e6e4 | 757 | dmxdevfilter->type = DMXDEV_TYPE_NONE; |
1da177e4 | 758 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); |
1da177e4 LT |
759 | init_timer(&dmxdevfilter->timer); |
760 | ||
57861b43 MR |
761 | dvbdev->users++; |
762 | ||
3593cab5 | 763 | mutex_unlock(&dmxdev->mutex); |
1da177e4 LT |
764 | return 0; |
765 | } | |
766 | ||
f705e6e4 AO |
767 | static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, |
768 | struct dmxdev_filter *dmxdevfilter) | |
1da177e4 | 769 | { |
c2788502 SA |
770 | mutex_lock(&dmxdev->mutex); |
771 | mutex_lock(&dmxdevfilter->mutex); | |
1da177e4 LT |
772 | |
773 | dvb_dmxdev_filter_stop(dmxdevfilter); | |
774 | dvb_dmxdev_filter_reset(dmxdevfilter); | |
775 | ||
776 | if (dmxdevfilter->buffer.data) { | |
f705e6e4 | 777 | void *mem = dmxdevfilter->buffer.data; |
1da177e4 LT |
778 | |
779 | spin_lock_irq(&dmxdev->lock); | |
f705e6e4 | 780 | dmxdevfilter->buffer.data = NULL; |
1da177e4 LT |
781 | spin_unlock_irq(&dmxdev->lock); |
782 | vfree(mem); | |
783 | } | |
784 | ||
785 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE); | |
786 | wake_up(&dmxdevfilter->buffer.queue); | |
3593cab5 IM |
787 | mutex_unlock(&dmxdevfilter->mutex); |
788 | mutex_unlock(&dmxdev->mutex); | |
1da177e4 LT |
789 | return 0; |
790 | } | |
791 | ||
792 | static inline void invert_mode(dmx_filter_t *filter) | |
793 | { | |
794 | int i; | |
795 | ||
f705e6e4 AO |
796 | for (i = 0; i < DMX_FILTER_SIZE; i++) |
797 | filter->mode[i] ^= 0xff; | |
1da177e4 LT |
798 | } |
799 | ||
1cb662a3 AO |
800 | static int dvb_dmxdev_add_pid(struct dmxdev *dmxdev, |
801 | struct dmxdev_filter *filter, u16 pid) | |
802 | { | |
803 | struct dmxdev_feed *feed; | |
804 | ||
805 | if ((filter->type != DMXDEV_TYPE_PES) || | |
806 | (filter->state < DMXDEV_STATE_SET)) | |
807 | return -EINVAL; | |
808 | ||
809 | /* only TS packet filters may have multiple PIDs */ | |
810 | if ((filter->params.pes.output != DMX_OUT_TSDEMUX_TAP) && | |
811 | (!list_empty(&filter->feed.ts))) | |
812 | return -EINVAL; | |
813 | ||
814 | feed = kzalloc(sizeof(struct dmxdev_feed), GFP_KERNEL); | |
815 | if (feed == NULL) | |
816 | return -ENOMEM; | |
817 | ||
818 | feed->pid = pid; | |
819 | list_add(&feed->next, &filter->feed.ts); | |
820 | ||
821 | if (filter->state >= DMXDEV_STATE_GO) | |
822 | return dvb_dmxdev_start_feed(dmxdev, filter, feed); | |
823 | ||
824 | return 0; | |
825 | } | |
826 | ||
827 | static int dvb_dmxdev_remove_pid(struct dmxdev *dmxdev, | |
828 | struct dmxdev_filter *filter, u16 pid) | |
829 | { | |
830 | struct dmxdev_feed *feed, *tmp; | |
831 | ||
832 | if ((filter->type != DMXDEV_TYPE_PES) || | |
833 | (filter->state < DMXDEV_STATE_SET)) | |
834 | return -EINVAL; | |
835 | ||
836 | list_for_each_entry_safe(feed, tmp, &filter->feed.ts, next) { | |
837 | if ((feed->pid == pid) && (feed->ts != NULL)) { | |
838 | feed->ts->stop_filtering(feed->ts); | |
839 | filter->dev->demux->release_ts_feed(filter->dev->demux, | |
840 | feed->ts); | |
841 | list_del(&feed->next); | |
842 | kfree(feed); | |
843 | } | |
844 | } | |
845 | ||
846 | return 0; | |
847 | } | |
848 | ||
1da177e4 | 849 | static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev, |
f705e6e4 AO |
850 | struct dmxdev_filter *dmxdevfilter, |
851 | struct dmx_sct_filter_params *params) | |
1da177e4 | 852 | { |
b3ad24d2 | 853 | dprintk("%s: PID=0x%04x, flags=%02x, timeout=%d\n", |
17e67d4c | 854 | __func__, params->pid, params->flags, params->timeout); |
1da177e4 LT |
855 | |
856 | dvb_dmxdev_filter_stop(dmxdevfilter); | |
857 | ||
f705e6e4 | 858 | dmxdevfilter->type = DMXDEV_TYPE_SEC; |
1da177e4 LT |
859 | memcpy(&dmxdevfilter->params.sec, |
860 | params, sizeof(struct dmx_sct_filter_params)); | |
861 | invert_mode(&dmxdevfilter->params.sec.filter); | |
862 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); | |
863 | ||
f705e6e4 | 864 | if (params->flags & DMX_IMMEDIATE_START) |
1da177e4 LT |
865 | return dvb_dmxdev_filter_start(dmxdevfilter); |
866 | ||
867 | return 0; | |
868 | } | |
869 | ||
870 | static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev, | |
f705e6e4 AO |
871 | struct dmxdev_filter *dmxdevfilter, |
872 | struct dmx_pes_filter_params *params) | |
1da177e4 | 873 | { |
1cb662a3 AO |
874 | int ret; |
875 | ||
1da177e4 | 876 | dvb_dmxdev_filter_stop(dmxdevfilter); |
1cb662a3 | 877 | dvb_dmxdev_filter_reset(dmxdevfilter); |
1da177e4 | 878 | |
31becf09 | 879 | if ((unsigned)params->pes_type > DMX_PES_OTHER) |
1da177e4 LT |
880 | return -EINVAL; |
881 | ||
f705e6e4 AO |
882 | dmxdevfilter->type = DMXDEV_TYPE_PES; |
883 | memcpy(&dmxdevfilter->params, params, | |
884 | sizeof(struct dmx_pes_filter_params)); | |
691c9ae0 | 885 | INIT_LIST_HEAD(&dmxdevfilter->feed.ts); |
1da177e4 LT |
886 | |
887 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); | |
888 | ||
1cb662a3 AO |
889 | ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, |
890 | dmxdevfilter->params.pes.pid); | |
891 | if (ret < 0) | |
892 | return ret; | |
893 | ||
f705e6e4 | 894 | if (params->flags & DMX_IMMEDIATE_START) |
1da177e4 LT |
895 | return dvb_dmxdev_filter_start(dmxdevfilter); |
896 | ||
897 | return 0; | |
898 | } | |
899 | ||
900 | static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil, | |
f705e6e4 AO |
901 | struct file *file, char __user *buf, |
902 | size_t count, loff_t *ppos) | |
1da177e4 LT |
903 | { |
904 | int result, hcount; | |
f705e6e4 AO |
905 | int done = 0; |
906 | ||
907 | if (dfil->todo <= 0) { | |
908 | hcount = 3 + dfil->todo; | |
909 | if (hcount > count) | |
910 | hcount = count; | |
911 | result = dvb_dmxdev_buffer_read(&dfil->buffer, | |
912 | file->f_flags & O_NONBLOCK, | |
913 | buf, hcount, ppos); | |
914 | if (result < 0) { | |
915 | dfil->todo = 0; | |
1da177e4 LT |
916 | return result; |
917 | } | |
f705e6e4 | 918 | if (copy_from_user(dfil->secheader - dfil->todo, buf, result)) |
1da177e4 | 919 | return -EFAULT; |
f705e6e4 AO |
920 | buf += result; |
921 | done = result; | |
922 | count -= result; | |
923 | dfil->todo -= result; | |
924 | if (dfil->todo > -3) | |
1da177e4 | 925 | return done; |
f705e6e4 | 926 | dfil->todo = ((dfil->secheader[1] << 8) | dfil->secheader[2]) & 0xfff; |
1da177e4 LT |
927 | if (!count) |
928 | return done; | |
929 | } | |
f705e6e4 AO |
930 | if (count > dfil->todo) |
931 | count = dfil->todo; | |
932 | result = dvb_dmxdev_buffer_read(&dfil->buffer, | |
933 | file->f_flags & O_NONBLOCK, | |
934 | buf, count, ppos); | |
935 | if (result < 0) | |
1da177e4 | 936 | return result; |
f705e6e4 AO |
937 | dfil->todo -= result; |
938 | return (result + done); | |
1da177e4 LT |
939 | } |
940 | ||
1da177e4 | 941 | static ssize_t |
f705e6e4 AO |
942 | dvb_demux_read(struct file *file, char __user *buf, size_t count, |
943 | loff_t *ppos) | |
1da177e4 | 944 | { |
f705e6e4 AO |
945 | struct dmxdev_filter *dmxdevfilter = file->private_data; |
946 | int ret; | |
1da177e4 | 947 | |
3593cab5 | 948 | if (mutex_lock_interruptible(&dmxdevfilter->mutex)) |
1da177e4 LT |
949 | return -ERESTARTSYS; |
950 | ||
f705e6e4 AO |
951 | if (dmxdevfilter->type == DMXDEV_TYPE_SEC) |
952 | ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos); | |
1da177e4 | 953 | else |
f705e6e4 AO |
954 | ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer, |
955 | file->f_flags & O_NONBLOCK, | |
956 | buf, count, ppos); | |
1da177e4 | 957 | |
3593cab5 | 958 | mutex_unlock(&dmxdevfilter->mutex); |
1da177e4 LT |
959 | return ret; |
960 | } | |
961 | ||
16ef8def | 962 | static int dvb_demux_do_ioctl(struct file *file, |
1da177e4 LT |
963 | unsigned int cmd, void *parg) |
964 | { | |
3ec4a307 | 965 | struct dmxdev_filter *dmxdevfilter = file->private_data; |
f705e6e4 AO |
966 | struct dmxdev *dmxdev = dmxdevfilter->dev; |
967 | unsigned long arg = (unsigned long)parg; | |
968 | int ret = 0; | |
1da177e4 | 969 | |
3593cab5 | 970 | if (mutex_lock_interruptible(&dmxdev->mutex)) |
1da177e4 LT |
971 | return -ERESTARTSYS; |
972 | ||
973 | switch (cmd) { | |
974 | case DMX_START: | |
3593cab5 IM |
975 | if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { |
976 | mutex_unlock(&dmxdev->mutex); | |
1da177e4 LT |
977 | return -ERESTARTSYS; |
978 | } | |
f705e6e4 | 979 | if (dmxdevfilter->state < DMXDEV_STATE_SET) |
1da177e4 LT |
980 | ret = -EINVAL; |
981 | else | |
982 | ret = dvb_dmxdev_filter_start(dmxdevfilter); | |
3593cab5 | 983 | mutex_unlock(&dmxdevfilter->mutex); |
1da177e4 LT |
984 | break; |
985 | ||
986 | case DMX_STOP: | |
3593cab5 IM |
987 | if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { |
988 | mutex_unlock(&dmxdev->mutex); | |
1da177e4 LT |
989 | return -ERESTARTSYS; |
990 | } | |
f705e6e4 | 991 | ret = dvb_dmxdev_filter_stop(dmxdevfilter); |
3593cab5 | 992 | mutex_unlock(&dmxdevfilter->mutex); |
1da177e4 LT |
993 | break; |
994 | ||
995 | case DMX_SET_FILTER: | |
3593cab5 IM |
996 | if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { |
997 | mutex_unlock(&dmxdev->mutex); | |
1da177e4 LT |
998 | return -ERESTARTSYS; |
999 | } | |
f705e6e4 | 1000 | ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg); |
3593cab5 | 1001 | mutex_unlock(&dmxdevfilter->mutex); |
1da177e4 LT |
1002 | break; |
1003 | ||
1004 | case DMX_SET_PES_FILTER: | |
3593cab5 IM |
1005 | if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { |
1006 | mutex_unlock(&dmxdev->mutex); | |
1da177e4 LT |
1007 | return -ERESTARTSYS; |
1008 | } | |
f705e6e4 | 1009 | ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg); |
3593cab5 | 1010 | mutex_unlock(&dmxdevfilter->mutex); |
1da177e4 LT |
1011 | break; |
1012 | ||
1013 | case DMX_SET_BUFFER_SIZE: | |
3593cab5 IM |
1014 | if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { |
1015 | mutex_unlock(&dmxdev->mutex); | |
1da177e4 LT |
1016 | return -ERESTARTSYS; |
1017 | } | |
f705e6e4 | 1018 | ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg); |
3593cab5 | 1019 | mutex_unlock(&dmxdevfilter->mutex); |
1da177e4 LT |
1020 | break; |
1021 | ||
1da177e4 LT |
1022 | case DMX_GET_PES_PIDS: |
1023 | if (!dmxdev->demux->get_pes_pids) { | |
f705e6e4 | 1024 | ret = -EINVAL; |
1da177e4 LT |
1025 | break; |
1026 | } | |
f705e6e4 | 1027 | dmxdev->demux->get_pes_pids(dmxdev->demux, parg); |
1da177e4 LT |
1028 | break; |
1029 | ||
1e92bbe0 MCC |
1030 | #if 0 |
1031 | /* Not used upstream and never documented */ | |
1032 | ||
c0510052 AO |
1033 | case DMX_GET_CAPS: |
1034 | if (!dmxdev->demux->get_caps) { | |
1035 | ret = -EINVAL; | |
1036 | break; | |
1037 | } | |
1038 | ret = dmxdev->demux->get_caps(dmxdev->demux, parg); | |
1039 | break; | |
1040 | ||
1041 | case DMX_SET_SOURCE: | |
1042 | if (!dmxdev->demux->set_source) { | |
1043 | ret = -EINVAL; | |
1044 | break; | |
1045 | } | |
1046 | ret = dmxdev->demux->set_source(dmxdev->demux, parg); | |
1047 | break; | |
1e92bbe0 | 1048 | #endif |
c0510052 | 1049 | |
1da177e4 LT |
1050 | case DMX_GET_STC: |
1051 | if (!dmxdev->demux->get_stc) { | |
f705e6e4 | 1052 | ret = -EINVAL; |
1da177e4 LT |
1053 | break; |
1054 | } | |
1055 | ret = dmxdev->demux->get_stc(dmxdev->demux, | |
f705e6e4 AO |
1056 | ((struct dmx_stc *)parg)->num, |
1057 | &((struct dmx_stc *)parg)->stc, | |
1058 | &((struct dmx_stc *)parg)->base); | |
1da177e4 LT |
1059 | break; |
1060 | ||
1cb662a3 AO |
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 | ||
1da177e4 | 1079 | default: |
f705e6e4 AO |
1080 | ret = -EINVAL; |
1081 | break; | |
1da177e4 | 1082 | } |
3593cab5 | 1083 | mutex_unlock(&dmxdev->mutex); |
1da177e4 LT |
1084 | return ret; |
1085 | } | |
1086 | ||
16ef8def AB |
1087 | static long dvb_demux_ioctl(struct file *file, unsigned int cmd, |
1088 | unsigned long arg) | |
1da177e4 | 1089 | { |
72024f1e | 1090 | return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl); |
1da177e4 LT |
1091 | } |
1092 | ||
f705e6e4 | 1093 | static unsigned int dvb_demux_poll(struct file *file, poll_table *wait) |
1da177e4 | 1094 | { |
3ec4a307 | 1095 | struct dmxdev_filter *dmxdevfilter = file->private_data; |
1da177e4 LT |
1096 | unsigned int mask = 0; |
1097 | ||
313ddec4 | 1098 | if ((!dmxdevfilter) || dmxdevfilter->dev->exit) |
236c9bfa | 1099 | return POLLERR; |
1da177e4 LT |
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 | ||
34731df2 | 1111 | if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer)) |
1da177e4 LT |
1112 | mask |= (POLLIN | POLLRDNORM | POLLPRI); |
1113 | ||
1114 | return mask; | |
1115 | } | |
1116 | ||
1da177e4 LT |
1117 | static int dvb_demux_release(struct inode *inode, struct file *file) |
1118 | { | |
3ec4a307 | 1119 | struct dmxdev_filter *dmxdevfilter = file->private_data; |
1da177e4 LT |
1120 | struct dmxdev *dmxdev = dmxdevfilter->dev; |
1121 | ||
57861b43 MR |
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) { | |
57861b43 MR |
1129 | mutex_unlock(&dmxdev->mutex); |
1130 | wake_up(&dmxdev->dvbdev->wait_queue); | |
1131 | } else | |
1132 | mutex_unlock(&dmxdev->mutex); | |
1133 | ||
1134 | return ret; | |
1da177e4 LT |
1135 | } |
1136 | ||
784e29d2 | 1137 | static const struct file_operations dvb_demux_fops = { |
f705e6e4 AO |
1138 | .owner = THIS_MODULE, |
1139 | .read = dvb_demux_read, | |
16ef8def | 1140 | .unlocked_ioctl = dvb_demux_ioctl, |
f705e6e4 AO |
1141 | .open = dvb_demux_open, |
1142 | .release = dvb_demux_release, | |
1143 | .poll = dvb_demux_poll, | |
6038f373 | 1144 | .llseek = default_llseek, |
1da177e4 LT |
1145 | }; |
1146 | ||
8afd52ef | 1147 | static const struct dvb_device dvbdev_demux = { |
f705e6e4 AO |
1148 | .priv = NULL, |
1149 | .users = 1, | |
1150 | .writers = 1, | |
8afd52ef | 1151 | #if defined(CONFIG_MEDIA_CONTROLLER_DVB) |
e4fd3bc5 | 1152 | .name = "dvb-demux", |
8afd52ef | 1153 | #endif |
f705e6e4 | 1154 | .fops = &dvb_demux_fops |
1da177e4 LT |
1155 | }; |
1156 | ||
16ef8def | 1157 | static int dvb_dvr_do_ioctl(struct file *file, |
f705e6e4 | 1158 | unsigned int cmd, void *parg) |
1da177e4 | 1159 | { |
0c53c70f JS |
1160 | struct dvb_device *dvbdev = file->private_data; |
1161 | struct dmxdev *dmxdev = dvbdev->priv; | |
a095be4b | 1162 | unsigned long arg = (unsigned long)parg; |
f705e6e4 | 1163 | int ret; |
1da177e4 | 1164 | |
3593cab5 | 1165 | if (mutex_lock_interruptible(&dmxdev->mutex)) |
1da177e4 LT |
1166 | return -ERESTARTSYS; |
1167 | ||
1168 | switch (cmd) { | |
1169 | case DMX_SET_BUFFER_SIZE: | |
a095be4b | 1170 | ret = dvb_dvr_set_buffer_size(dmxdev, arg); |
1da177e4 LT |
1171 | break; |
1172 | ||
1173 | default: | |
f705e6e4 AO |
1174 | ret = -EINVAL; |
1175 | break; | |
1da177e4 | 1176 | } |
3593cab5 | 1177 | mutex_unlock(&dmxdev->mutex); |
1da177e4 LT |
1178 | return ret; |
1179 | } | |
1180 | ||
16ef8def | 1181 | static long dvb_dvr_ioctl(struct file *file, |
f705e6e4 | 1182 | unsigned int cmd, unsigned long arg) |
1da177e4 | 1183 | { |
72024f1e | 1184 | return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl); |
1da177e4 LT |
1185 | } |
1186 | ||
f705e6e4 | 1187 | static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait) |
1da177e4 | 1188 | { |
0c53c70f JS |
1189 | struct dvb_device *dvbdev = file->private_data; |
1190 | struct dmxdev *dmxdev = dvbdev->priv; | |
1da177e4 LT |
1191 | unsigned int mask = 0; |
1192 | ||
b3ad24d2 | 1193 | dprintk("%s\n", __func__); |
1da177e4 | 1194 | |
d102cac8 CX |
1195 | if (dmxdev->exit) |
1196 | return POLLERR; | |
1197 | ||
1da177e4 LT |
1198 | poll_wait(file, &dmxdev->dvr_buffer.queue, wait); |
1199 | ||
f705e6e4 | 1200 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) { |
1da177e4 LT |
1201 | if (dmxdev->dvr_buffer.error) |
1202 | mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); | |
1203 | ||
34731df2 | 1204 | if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer)) |
1da177e4 LT |
1205 | mask |= (POLLIN | POLLRDNORM | POLLPRI); |
1206 | } else | |
1207 | mask |= (POLLOUT | POLLWRNORM | POLLPRI); | |
1208 | ||
1209 | return mask; | |
1210 | } | |
1211 | ||
828c0950 | 1212 | static const struct file_operations dvb_dvr_fops = { |
f705e6e4 AO |
1213 | .owner = THIS_MODULE, |
1214 | .read = dvb_dvr_read, | |
1215 | .write = dvb_dvr_write, | |
16ef8def | 1216 | .unlocked_ioctl = dvb_dvr_ioctl, |
f705e6e4 AO |
1217 | .open = dvb_dvr_open, |
1218 | .release = dvb_dvr_release, | |
1219 | .poll = dvb_dvr_poll, | |
6038f373 | 1220 | .llseek = default_llseek, |
1da177e4 LT |
1221 | }; |
1222 | ||
8afd52ef | 1223 | static const struct dvb_device dvbdev_dvr = { |
f705e6e4 | 1224 | .priv = NULL, |
5e85bd05 | 1225 | .readers = 1, |
57861b43 | 1226 | .users = 1, |
8afd52ef | 1227 | #if defined(CONFIG_MEDIA_CONTROLLER_DVB) |
e4fd3bc5 | 1228 | .name = "dvb-dvr", |
8afd52ef | 1229 | #endif |
f705e6e4 | 1230 | .fops = &dvb_dvr_fops |
1da177e4 | 1231 | }; |
f705e6e4 | 1232 | int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) |
1da177e4 LT |
1233 | { |
1234 | int i; | |
1235 | ||
1236 | if (dmxdev->demux->open(dmxdev->demux) < 0) | |
1237 | return -EUSERS; | |
1238 | ||
f705e6e4 | 1239 | dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter)); |
1da177e4 LT |
1240 | if (!dmxdev->filter) |
1241 | return -ENOMEM; | |
1242 | ||
3593cab5 | 1243 | mutex_init(&dmxdev->mutex); |
1da177e4 | 1244 | spin_lock_init(&dmxdev->lock); |
f705e6e4 AO |
1245 | for (i = 0; i < dmxdev->filternum; i++) { |
1246 | dmxdev->filter[i].dev = dmxdev; | |
1247 | dmxdev->filter[i].buffer.data = NULL; | |
1248 | dvb_dmxdev_filter_state_set(&dmxdev->filter[i], | |
1249 | DMXDEV_STATE_FREE); | |
1da177e4 LT |
1250 | } |
1251 | ||
f705e6e4 | 1252 | dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev, |
df2f94e5 | 1253 | DVB_DEVICE_DEMUX, dmxdev->filternum); |
f705e6e4 | 1254 | dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr, |
df2f94e5 | 1255 | dmxdev, DVB_DEVICE_DVR, dmxdev->filternum); |
1da177e4 | 1256 | |
34731df2 | 1257 | dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192); |
1da177e4 LT |
1258 | |
1259 | return 0; | |
1260 | } | |
f705e6e4 | 1261 | |
1da177e4 LT |
1262 | EXPORT_SYMBOL(dvb_dmxdev_init); |
1263 | ||
f705e6e4 | 1264 | void dvb_dmxdev_release(struct dmxdev *dmxdev) |
1da177e4 | 1265 | { |
57861b43 MR |
1266 | dmxdev->exit=1; |
1267 | if (dmxdev->dvbdev->users > 1) { | |
1268 | wait_event(dmxdev->dvbdev->wait_queue, | |
1269 | dmxdev->dvbdev->users==1); | |
1270 | } | |
1271 | if (dmxdev->dvr_dvbdev->users > 1) { | |
1272 | wait_event(dmxdev->dvr_dvbdev->wait_queue, | |
1273 | dmxdev->dvr_dvbdev->users==1); | |
1274 | } | |
1275 | ||
1da177e4 LT |
1276 | dvb_unregister_device(dmxdev->dvbdev); |
1277 | dvb_unregister_device(dmxdev->dvr_dvbdev); | |
1278 | ||
1279 | vfree(dmxdev->filter); | |
f705e6e4 | 1280 | dmxdev->filter = NULL; |
1da177e4 LT |
1281 | dmxdev->demux->close(dmxdev->demux); |
1282 | } | |
f705e6e4 | 1283 | |
1da177e4 | 1284 | EXPORT_SYMBOL(dvb_dmxdev_release); |