]>
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 | ||
a99bbaf5 | 23 | #include <linux/sched.h> |
1da177e4 LT |
24 | #include <linux/spinlock.h> |
25 | #include <linux/slab.h> | |
26 | #include <linux/vmalloc.h> | |
27 | #include <linux/module.h> | |
1da177e4 LT |
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> | |
1da177e4 LT |
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 | ||
34731df2 AO |
42 | static int dvb_dmxdev_buffer_write(struct dvb_ringbuffer *buf, |
43 | const u8 *src, size_t len) | |
1da177e4 | 44 | { |
34731df2 | 45 | ssize_t free; |
1da177e4 LT |
46 | |
47 | if (!len) | |
48 | return 0; | |
49 | if (!buf->data) | |
50 | return 0; | |
51 | ||
34731df2 AO |
52 | free = dvb_ringbuffer_free(buf); |
53 | if (len > free) { | |
1da177e4 | 54 | dprintk("dmxdev: buffer overflow\n"); |
34731df2 | 55 | return -EOVERFLOW; |
1da177e4 | 56 | } |
34731df2 AO |
57 | |
58 | return dvb_ringbuffer_write(buf, src, len); | |
1da177e4 LT |
59 | } |
60 | ||
34731df2 | 61 | static ssize_t dvb_dmxdev_buffer_read(struct dvb_ringbuffer *src, |
f705e6e4 AO |
62 | int non_blocking, char __user *buf, |
63 | size_t count, loff_t *ppos) | |
1da177e4 | 64 | { |
34731df2 AO |
65 | size_t todo; |
66 | ssize_t avail; | |
67 | ssize_t ret = 0; | |
1da177e4 LT |
68 | |
69 | if (!src->data) | |
70 | return 0; | |
71 | ||
34731df2 AO |
72 | if (src->error) { |
73 | ret = src->error; | |
74 | dvb_ringbuffer_flush(src); | |
75 | return ret; | |
1da177e4 LT |
76 | } |
77 | ||
34731df2 AO |
78 | for (todo = count; todo > 0; todo -= ret) { |
79 | if (non_blocking && dvb_ringbuffer_empty(src)) { | |
80 | ret = -EWOULDBLOCK; | |
81 | break; | |
82 | } | |
1da177e4 | 83 | |
34731df2 AO |
84 | ret = wait_event_interruptible(src->queue, |
85 | !dvb_ringbuffer_empty(src) || | |
86 | (src->error != 0)); | |
87 | if (ret < 0) | |
88 | break; | |
1da177e4 | 89 | |
34731df2 AO |
90 | if (src->error) { |
91 | ret = src->error; | |
92 | dvb_ringbuffer_flush(src); | |
93 | break; | |
1da177e4 LT |
94 | } |
95 | ||
34731df2 | 96 | avail = dvb_ringbuffer_avail(src); |
f705e6e4 AO |
97 | if (avail > todo) |
98 | avail = todo; | |
34731df2 | 99 | |
b0ba0e3a | 100 | ret = dvb_ringbuffer_read_user(src, buf, avail); |
34731df2 AO |
101 | if (ret < 0) |
102 | break; | |
103 | ||
104 | buf += ret; | |
1da177e4 | 105 | } |
34731df2 AO |
106 | |
107 | return (count - todo) ? (count - todo) : ret; | |
1da177e4 LT |
108 | } |
109 | ||
f705e6e4 | 110 | static struct dmx_frontend *get_fe(struct dmx_demux *demux, int type) |
1da177e4 LT |
111 | { |
112 | struct list_head *head, *pos; | |
113 | ||
f705e6e4 | 114 | head = demux->get_frontends(demux); |
1da177e4 LT |
115 | if (!head) |
116 | return NULL; | |
117 | list_for_each(pos, head) | |
f705e6e4 | 118 | if (DMX_FE_ENTRY(pos)->source == type) |
1da177e4 LT |
119 | return DMX_FE_ENTRY(pos); |
120 | ||
121 | return NULL; | |
122 | } | |
123 | ||
1da177e4 LT |
124 | static int dvb_dvr_open(struct inode *inode, struct file *file) |
125 | { | |
0c53c70f JS |
126 | struct dvb_device *dvbdev = file->private_data; |
127 | struct dmxdev *dmxdev = dvbdev->priv; | |
1da177e4 LT |
128 | struct dmx_frontend *front; |
129 | ||
46b4f7c1 | 130 | dprintk("function : %s\n", __func__); |
1da177e4 | 131 | |
3593cab5 | 132 | if (mutex_lock_interruptible(&dmxdev->mutex)) |
1da177e4 LT |
133 | return -ERESTARTSYS; |
134 | ||
57861b43 MR |
135 | if (dmxdev->exit) { |
136 | mutex_unlock(&dmxdev->mutex); | |
137 | return -ENODEV; | |
138 | } | |
139 | ||
f705e6e4 AO |
140 | if ((file->f_flags & O_ACCMODE) == O_RDWR) { |
141 | if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) { | |
3593cab5 | 142 | mutex_unlock(&dmxdev->mutex); |
1da177e4 LT |
143 | return -EOPNOTSUPP; |
144 | } | |
145 | } | |
146 | ||
f705e6e4 | 147 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) { |
5e85bd05 TP |
148 | void *mem; |
149 | if (!dvbdev->readers) { | |
150 | mutex_unlock(&dmxdev->mutex); | |
151 | return -EBUSY; | |
152 | } | |
153 | mem = vmalloc(DVR_BUFFER_SIZE); | |
34731df2 | 154 | if (!mem) { |
f705e6e4 AO |
155 | mutex_unlock(&dmxdev->mutex); |
156 | return -ENOMEM; | |
157 | } | |
34731df2 | 158 | dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE); |
5e85bd05 | 159 | dvbdev->readers--; |
1da177e4 LT |
160 | } |
161 | ||
f705e6e4 AO |
162 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) { |
163 | dmxdev->dvr_orig_fe = dmxdev->demux->frontend; | |
1da177e4 LT |
164 | |
165 | if (!dmxdev->demux->write) { | |
3593cab5 | 166 | mutex_unlock(&dmxdev->mutex); |
1da177e4 LT |
167 | return -EOPNOTSUPP; |
168 | } | |
169 | ||
f705e6e4 | 170 | front = get_fe(dmxdev->demux, DMX_MEMORY_FE); |
1da177e4 LT |
171 | |
172 | if (!front) { | |
3593cab5 | 173 | mutex_unlock(&dmxdev->mutex); |
1da177e4 LT |
174 | return -EINVAL; |
175 | } | |
176 | dmxdev->demux->disconnect_frontend(dmxdev->demux); | |
177 | dmxdev->demux->connect_frontend(dmxdev->demux, front); | |
178 | } | |
57861b43 | 179 | dvbdev->users++; |
3593cab5 | 180 | mutex_unlock(&dmxdev->mutex); |
1da177e4 LT |
181 | return 0; |
182 | } | |
183 | ||
184 | static int dvb_dvr_release(struct inode *inode, struct file *file) | |
185 | { | |
0c53c70f JS |
186 | struct dvb_device *dvbdev = file->private_data; |
187 | struct dmxdev *dmxdev = dvbdev->priv; | |
1da177e4 | 188 | |
c2788502 | 189 | mutex_lock(&dmxdev->mutex); |
1da177e4 | 190 | |
f705e6e4 | 191 | if ((file->f_flags & O_ACCMODE) == O_WRONLY) { |
1da177e4 LT |
192 | dmxdev->demux->disconnect_frontend(dmxdev->demux); |
193 | dmxdev->demux->connect_frontend(dmxdev->demux, | |
194 | dmxdev->dvr_orig_fe); | |
195 | } | |
f705e6e4 | 196 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) { |
5e85bd05 | 197 | dvbdev->readers++; |
1da177e4 | 198 | if (dmxdev->dvr_buffer.data) { |
f705e6e4 | 199 | void *mem = dmxdev->dvr_buffer.data; |
1da177e4 LT |
200 | mb(); |
201 | spin_lock_irq(&dmxdev->lock); | |
f705e6e4 | 202 | dmxdev->dvr_buffer.data = NULL; |
1da177e4 LT |
203 | spin_unlock_irq(&dmxdev->lock); |
204 | vfree(mem); | |
205 | } | |
206 | } | |
57861b43 MR |
207 | /* TODO */ |
208 | dvbdev->users--; | |
1c488ea9 | 209 | if (dvbdev->users == 1 && dmxdev->exit == 1) { |
57861b43 MR |
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 | ||
1da177e4 LT |
217 | return 0; |
218 | } | |
219 | ||
220 | static ssize_t dvb_dvr_write(struct file *file, const char __user *buf, | |
f705e6e4 | 221 | size_t count, loff_t *ppos) |
1da177e4 | 222 | { |
0c53c70f JS |
223 | struct dvb_device *dvbdev = file->private_data; |
224 | struct dmxdev *dmxdev = dvbdev->priv; | |
1da177e4 LT |
225 | int ret; |
226 | ||
227 | if (!dmxdev->demux->write) | |
228 | return -EOPNOTSUPP; | |
f705e6e4 | 229 | if ((file->f_flags & O_ACCMODE) != O_WRONLY) |
1da177e4 | 230 | return -EINVAL; |
3593cab5 | 231 | if (mutex_lock_interruptible(&dmxdev->mutex)) |
1da177e4 | 232 | return -ERESTARTSYS; |
57861b43 MR |
233 | |
234 | if (dmxdev->exit) { | |
235 | mutex_unlock(&dmxdev->mutex); | |
236 | return -ENODEV; | |
237 | } | |
f705e6e4 | 238 | ret = dmxdev->demux->write(dmxdev->demux, buf, count); |
3593cab5 | 239 | mutex_unlock(&dmxdev->mutex); |
1da177e4 LT |
240 | return ret; |
241 | } | |
242 | ||
243 | static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count, | |
f705e6e4 | 244 | loff_t *ppos) |
1da177e4 | 245 | { |
0c53c70f JS |
246 | struct dvb_device *dvbdev = file->private_data; |
247 | struct dmxdev *dmxdev = dvbdev->priv; | |
1da177e4 | 248 | |
eda9f752 | 249 | if (dmxdev->exit) |
57861b43 | 250 | return -ENODEV; |
57861b43 | 251 | |
eda9f752 SA |
252 | return dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, |
253 | file->f_flags & O_NONBLOCK, | |
254 | buf, count, ppos); | |
1da177e4 LT |
255 | } |
256 | ||
a095be4b AO |
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 | ||
f705e6e4 AO |
290 | static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter |
291 | *dmxdevfilter, int state) | |
1da177e4 LT |
292 | { |
293 | spin_lock_irq(&dmxdevfilter->dev->lock); | |
f705e6e4 | 294 | dmxdevfilter->state = state; |
1da177e4 LT |
295 | spin_unlock_irq(&dmxdevfilter->dev->lock); |
296 | } | |
297 | ||
f705e6e4 AO |
298 | static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, |
299 | unsigned long size) | |
1da177e4 | 300 | { |
34731df2 | 301 | struct dvb_ringbuffer *buf = &dmxdevfilter->buffer; |
a095be4b AO |
302 | void *newmem; |
303 | void *oldmem; | |
1da177e4 | 304 | |
f705e6e4 | 305 | if (buf->size == size) |
1da177e4 | 306 | return 0; |
a095be4b AO |
307 | if (!size) |
308 | return -EINVAL; | |
f705e6e4 | 309 | if (dmxdevfilter->state >= DMXDEV_STATE_GO) |
1da177e4 | 310 | return -EBUSY; |
a095be4b AO |
311 | |
312 | newmem = vmalloc(size); | |
313 | if (!newmem) | |
314 | return -ENOMEM; | |
315 | ||
316 | oldmem = buf->data; | |
317 | ||
1da177e4 | 318 | spin_lock_irq(&dmxdevfilter->dev->lock); |
a095be4b | 319 | buf->data = newmem; |
f705e6e4 | 320 | buf->size = size; |
48c01a9c AO |
321 | |
322 | /* reset and not flush in case the buffer shrinks */ | |
323 | dvb_ringbuffer_reset(buf); | |
1da177e4 | 324 | spin_unlock_irq(&dmxdevfilter->dev->lock); |
1da177e4 | 325 | |
a095be4b AO |
326 | vfree(oldmem); |
327 | ||
1da177e4 LT |
328 | return 0; |
329 | } | |
330 | ||
331 | static void dvb_dmxdev_filter_timeout(unsigned long data) | |
332 | { | |
f705e6e4 | 333 | struct dmxdev_filter *dmxdevfilter = (struct dmxdev_filter *)data; |
1da177e4 | 334 | |
f705e6e4 | 335 | dmxdevfilter->buffer.error = -ETIMEDOUT; |
1da177e4 | 336 | spin_lock_irq(&dmxdevfilter->dev->lock); |
f705e6e4 | 337 | dmxdevfilter->state = DMXDEV_STATE_TIMEDOUT; |
1da177e4 LT |
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 | { | |
f705e6e4 | 344 | struct dmx_sct_filter_params *para = &dmxdevfilter->params.sec; |
1da177e4 LT |
345 | |
346 | del_timer(&dmxdevfilter->timer); | |
347 | if (para->timeout) { | |
f705e6e4 AO |
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; | |
1da177e4 LT |
352 | add_timer(&dmxdevfilter->timer); |
353 | } | |
354 | } | |
355 | ||
356 | static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, | |
f705e6e4 AO |
357 | const u8 *buffer2, size_t buffer2_len, |
358 | struct dmx_section_filter *filter, | |
359 | enum dmx_success success) | |
1da177e4 | 360 | { |
0c53c70f | 361 | struct dmxdev_filter *dmxdevfilter = filter->priv; |
1da177e4 LT |
362 | int ret; |
363 | ||
364 | if (dmxdevfilter->buffer.error) { | |
365 | wake_up(&dmxdevfilter->buffer.queue); | |
366 | return 0; | |
367 | } | |
28100165 | 368 | spin_lock(&dmxdevfilter->dev->lock); |
f705e6e4 | 369 | if (dmxdevfilter->state != DMXDEV_STATE_GO) { |
28100165 | 370 | spin_unlock(&dmxdevfilter->dev->lock); |
1da177e4 LT |
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], | |
f705e6e4 AO |
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); | |
1da177e4 | 382 | } |
f705e6e4 | 383 | if (ret < 0) { |
34731df2 AO |
384 | dvb_ringbuffer_flush(&dmxdevfilter->buffer); |
385 | dmxdevfilter->buffer.error = ret; | |
1da177e4 | 386 | } |
f705e6e4 AO |
387 | if (dmxdevfilter->params.sec.flags & DMX_ONESHOT) |
388 | dmxdevfilter->state = DMXDEV_STATE_DONE; | |
28100165 | 389 | spin_unlock(&dmxdevfilter->dev->lock); |
1da177e4 LT |
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, | |
f705e6e4 AO |
395 | const u8 *buffer2, size_t buffer2_len, |
396 | struct dmx_ts_feed *feed, | |
397 | enum dmx_success success) | |
1da177e4 | 398 | { |
0c53c70f | 399 | struct dmxdev_filter *dmxdevfilter = feed->priv; |
34731df2 | 400 | struct dvb_ringbuffer *buffer; |
1da177e4 LT |
401 | int ret; |
402 | ||
28100165 | 403 | spin_lock(&dmxdevfilter->dev->lock); |
f705e6e4 | 404 | if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) { |
28100165 | 405 | spin_unlock(&dmxdevfilter->dev->lock); |
1da177e4 LT |
406 | return 0; |
407 | } | |
408 | ||
b01cd937 PH |
409 | if (dmxdevfilter->params.pes.output == DMX_OUT_TAP |
410 | || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) | |
f705e6e4 | 411 | buffer = &dmxdevfilter->buffer; |
1da177e4 | 412 | else |
f705e6e4 | 413 | buffer = &dmxdevfilter->dev->dvr_buffer; |
1da177e4 | 414 | if (buffer->error) { |
28100165 | 415 | spin_unlock(&dmxdevfilter->dev->lock); |
1da177e4 LT |
416 | wake_up(&buffer->queue); |
417 | return 0; | |
418 | } | |
f705e6e4 AO |
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) { | |
34731df2 AO |
423 | dvb_ringbuffer_flush(buffer); |
424 | buffer->error = ret; | |
1da177e4 | 425 | } |
28100165 | 426 | spin_unlock(&dmxdevfilter->dev->lock); |
1da177e4 LT |
427 | wake_up(&buffer->queue); |
428 | return 0; | |
429 | } | |
430 | ||
1da177e4 | 431 | /* stop feed but only mark the specified filter as stopped (state set) */ |
1da177e4 LT |
432 | static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter) |
433 | { | |
1cb662a3 AO |
434 | struct dmxdev_feed *feed; |
435 | ||
1da177e4 LT |
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: | |
1cb662a3 AO |
444 | list_for_each_entry(feed, &dmxdevfilter->feed.ts, next) |
445 | feed->ts->stop_filtering(feed->ts); | |
1da177e4 LT |
446 | break; |
447 | default: | |
448 | return -EINVAL; | |
449 | } | |
450 | return 0; | |
451 | } | |
452 | ||
1da177e4 | 453 | /* start feed associated with the specified filter */ |
1da177e4 LT |
454 | static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter) |
455 | { | |
1cb662a3 AO |
456 | struct dmxdev_feed *feed; |
457 | int ret; | |
458 | ||
f705e6e4 | 459 | dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO); |
1da177e4 LT |
460 | |
461 | switch (filter->type) { | |
462 | case DMXDEV_TYPE_SEC: | |
463 | return filter->feed.sec->start_filtering(filter->feed.sec); | |
1da177e4 | 464 | case DMXDEV_TYPE_PES: |
1cb662a3 AO |
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; | |
1da177e4 LT |
473 | default: |
474 | return -EINVAL; | |
475 | } | |
476 | ||
477 | return 0; | |
478 | } | |
479 | ||
1da177e4 LT |
480 | /* restart section feed if it has filters left associated with it, |
481 | otherwise release the feed */ | |
1da177e4 LT |
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 | ||
f705e6e4 AO |
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) { | |
1da177e4 LT |
492 | dvb_dmxdev_feed_start(&dmxdev->filter[i]); |
493 | return 0; | |
494 | } | |
495 | ||
f705e6e4 AO |
496 | filter->dev->demux->release_section_feed(dmxdev->demux, |
497 | filter->feed.sec); | |
1da177e4 LT |
498 | |
499 | return 0; | |
500 | } | |
501 | ||
502 | static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter) | |
503 | { | |
1cb662a3 AO |
504 | struct dmxdev_feed *feed; |
505 | struct dmx_demux *demux; | |
506 | ||
f705e6e4 | 507 | if (dmxdevfilter->state < DMXDEV_STATE_GO) |
1da177e4 LT |
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-> | |
f705e6e4 AO |
517 | release_filter(dmxdevfilter->feed.sec, |
518 | dmxdevfilter->filter.sec); | |
1da177e4 | 519 | dvb_dmxdev_feed_restart(dmxdevfilter); |
f705e6e4 | 520 | dmxdevfilter->feed.sec = NULL; |
1da177e4 LT |
521 | break; |
522 | case DMXDEV_TYPE_PES: | |
1da177e4 | 523 | dvb_dmxdev_feed_stop(dmxdevfilter); |
1cb662a3 AO |
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 | } | |
1da177e4 LT |
529 | break; |
530 | default: | |
f705e6e4 | 531 | if (dmxdevfilter->state == DMXDEV_STATE_ALLOCATED) |
1da177e4 LT |
532 | return 0; |
533 | return -EINVAL; | |
534 | } | |
34731df2 AO |
535 | |
536 | dvb_ringbuffer_flush(&dmxdevfilter->buffer); | |
1da177e4 LT |
537 | return 0; |
538 | } | |
539 | ||
1cb662a3 AO |
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 | ||
1da177e4 LT |
553 | static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter) |
554 | { | |
f705e6e4 | 555 | if (dmxdevfilter->state < DMXDEV_STATE_SET) |
1da177e4 LT |
556 | return 0; |
557 | ||
1cb662a3 AO |
558 | if (dmxdevfilter->type == DMXDEV_TYPE_PES) |
559 | dvb_dmxdev_delete_pids(dmxdevfilter); | |
560 | ||
f705e6e4 | 561 | dmxdevfilter->type = DMXDEV_TYPE_NONE; |
1da177e4 LT |
562 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); |
563 | return 0; | |
564 | } | |
565 | ||
1cb662a3 AO |
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 | enum dmx_ts_pes ts_pes; | |
576 | struct dmx_ts_feed *tsfeed; | |
577 | ||
578 | feed->ts = NULL; | |
579 | otype = para->output; | |
580 | ||
581 | ts_pes = (enum dmx_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 | ||
1da177e4 LT |
618 | static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) |
619 | { | |
620 | struct dmxdev *dmxdev = filter->dev; | |
1cb662a3 | 621 | struct dmxdev_feed *feed; |
1da177e4 LT |
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 | ||
34731df2 | 631 | if (!filter->buffer.data) { |
1da177e4 | 632 | mem = vmalloc(filter->buffer.size); |
34731df2 AO |
633 | if (!mem) |
634 | return -ENOMEM; | |
1da177e4 | 635 | spin_lock_irq(&filter->dev->lock); |
f705e6e4 | 636 | filter->buffer.data = mem; |
1da177e4 | 637 | spin_unlock_irq(&filter->dev->lock); |
1da177e4 LT |
638 | } |
639 | ||
34731df2 | 640 | dvb_ringbuffer_flush(&filter->buffer); |
1da177e4 LT |
641 | |
642 | switch (filter->type) { | |
643 | case DMXDEV_TYPE_SEC: | |
644 | { | |
f705e6e4 AO |
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; | |
1da177e4 | 651 | |
1da177e4 LT |
652 | |
653 | /* find active filter/feed with same PID */ | |
f705e6e4 | 654 | for (i = 0; i < dmxdev->filternum; i++) { |
1da177e4 | 655 | if (dmxdev->filter[i].state >= DMXDEV_STATE_GO && |
09794a6f AO |
656 | dmxdev->filter[i].type == DMXDEV_TYPE_SEC && |
657 | dmxdev->filter[i].params.sec.pid == para->pid) { | |
1da177e4 LT |
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) { | |
f705e6e4 AO |
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", | |
46b4f7c1 | 670 | __func__); |
1da177e4 LT |
671 | return ret; |
672 | } | |
673 | ||
f705e6e4 AO |
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", | |
46b4f7c1 | 678 | __func__); |
1da177e4 LT |
679 | dvb_dmxdev_feed_restart(filter); |
680 | return ret; | |
681 | } | |
682 | } else { | |
683 | dvb_dmxdev_feed_stop(filter); | |
684 | } | |
685 | ||
f705e6e4 | 686 | ret = (*secfeed)->allocate_filter(*secfeed, secfilter); |
1da177e4 LT |
687 | if (ret < 0) { |
688 | dvb_dmxdev_feed_restart(filter); | |
689 | filter->feed.sec->start_filtering(*secfeed); | |
f705e6e4 | 690 | dprintk("could not get filter\n"); |
1da177e4 LT |
691 | return ret; |
692 | } | |
693 | ||
694 | (*secfilter)->priv = filter; | |
695 | ||
696 | memcpy(&((*secfilter)->filter_value[3]), | |
f705e6e4 | 697 | &(para->filter.filter[1]), DMX_FILTER_SIZE - 1); |
1da177e4 | 698 | memcpy(&(*secfilter)->filter_mask[3], |
f705e6e4 | 699 | ¶->filter.mask[1], DMX_FILTER_SIZE - 1); |
1da177e4 | 700 | memcpy(&(*secfilter)->filter_mode[3], |
f705e6e4 | 701 | ¶->filter.mode[1], DMX_FILTER_SIZE - 1); |
1da177e4 | 702 | |
f705e6e4 AO |
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; | |
1da177e4 LT |
708 | |
709 | filter->todo = 0; | |
710 | ||
f705e6e4 | 711 | ret = filter->feed.sec->start_filtering(filter->feed.sec); |
1da177e4 LT |
712 | if (ret < 0) |
713 | return ret; | |
714 | ||
715 | dvb_dmxdev_filter_timer(filter); | |
716 | break; | |
717 | } | |
1da177e4 | 718 | case DMXDEV_TYPE_PES: |
1cb662a3 AO |
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 | } | |
76197924 | 725 | } |
1da177e4 | 726 | break; |
1da177e4 LT |
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 | { | |
0c53c70f JS |
737 | struct dvb_device *dvbdev = file->private_data; |
738 | struct dmxdev *dmxdev = dvbdev->priv; | |
1da177e4 LT |
739 | int i; |
740 | struct dmxdev_filter *dmxdevfilter; | |
741 | ||
742 | if (!dmxdev->filter) | |
743 | return -EINVAL; | |
744 | ||
3593cab5 | 745 | if (mutex_lock_interruptible(&dmxdev->mutex)) |
1da177e4 LT |
746 | return -ERESTARTSYS; |
747 | ||
f705e6e4 AO |
748 | for (i = 0; i < dmxdev->filternum; i++) |
749 | if (dmxdev->filter[i].state == DMXDEV_STATE_FREE) | |
1da177e4 LT |
750 | break; |
751 | ||
f705e6e4 | 752 | if (i == dmxdev->filternum) { |
3593cab5 | 753 | mutex_unlock(&dmxdev->mutex); |
1da177e4 LT |
754 | return -EMFILE; |
755 | } | |
756 | ||
f705e6e4 | 757 | dmxdevfilter = &dmxdev->filter[i]; |
3593cab5 | 758 | mutex_init(&dmxdevfilter->mutex); |
f705e6e4 | 759 | file->private_data = dmxdevfilter; |
1da177e4 | 760 | |
34731df2 | 761 | dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192); |
f705e6e4 | 762 | dmxdevfilter->type = DMXDEV_TYPE_NONE; |
1da177e4 | 763 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); |
1da177e4 LT |
764 | init_timer(&dmxdevfilter->timer); |
765 | ||
57861b43 MR |
766 | dvbdev->users++; |
767 | ||
3593cab5 | 768 | mutex_unlock(&dmxdev->mutex); |
1da177e4 LT |
769 | return 0; |
770 | } | |
771 | ||
f705e6e4 AO |
772 | static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, |
773 | struct dmxdev_filter *dmxdevfilter) | |
1da177e4 | 774 | { |
c2788502 SA |
775 | mutex_lock(&dmxdev->mutex); |
776 | mutex_lock(&dmxdevfilter->mutex); | |
1da177e4 LT |
777 | |
778 | dvb_dmxdev_filter_stop(dmxdevfilter); | |
779 | dvb_dmxdev_filter_reset(dmxdevfilter); | |
780 | ||
781 | if (dmxdevfilter->buffer.data) { | |
f705e6e4 | 782 | void *mem = dmxdevfilter->buffer.data; |
1da177e4 LT |
783 | |
784 | spin_lock_irq(&dmxdev->lock); | |
f705e6e4 | 785 | dmxdevfilter->buffer.data = NULL; |
1da177e4 LT |
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); | |
3593cab5 IM |
792 | mutex_unlock(&dmxdevfilter->mutex); |
793 | mutex_unlock(&dmxdev->mutex); | |
1da177e4 LT |
794 | return 0; |
795 | } | |
796 | ||
797 | static inline void invert_mode(dmx_filter_t *filter) | |
798 | { | |
799 | int i; | |
800 | ||
f705e6e4 AO |
801 | for (i = 0; i < DMX_FILTER_SIZE; i++) |
802 | filter->mode[i] ^= 0xff; | |
1da177e4 LT |
803 | } |
804 | ||
1cb662a3 AO |
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 | ||
1da177e4 | 854 | static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev, |
f705e6e4 AO |
855 | struct dmxdev_filter *dmxdevfilter, |
856 | struct dmx_sct_filter_params *params) | |
1da177e4 | 857 | { |
46b4f7c1 | 858 | dprintk("function : %s\n", __func__); |
1da177e4 LT |
859 | |
860 | dvb_dmxdev_filter_stop(dmxdevfilter); | |
861 | ||
f705e6e4 | 862 | dmxdevfilter->type = DMXDEV_TYPE_SEC; |
1da177e4 LT |
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 | ||
f705e6e4 | 868 | if (params->flags & DMX_IMMEDIATE_START) |
1da177e4 LT |
869 | return dvb_dmxdev_filter_start(dmxdevfilter); |
870 | ||
871 | return 0; | |
872 | } | |
873 | ||
874 | static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev, | |
f705e6e4 AO |
875 | struct dmxdev_filter *dmxdevfilter, |
876 | struct dmx_pes_filter_params *params) | |
1da177e4 | 877 | { |
1cb662a3 AO |
878 | int ret; |
879 | ||
1da177e4 | 880 | dvb_dmxdev_filter_stop(dmxdevfilter); |
1cb662a3 | 881 | dvb_dmxdev_filter_reset(dmxdevfilter); |
1da177e4 | 882 | |
f705e6e4 | 883 | if (params->pes_type > DMX_PES_OTHER || params->pes_type < 0) |
1da177e4 LT |
884 | return -EINVAL; |
885 | ||
f705e6e4 AO |
886 | dmxdevfilter->type = DMXDEV_TYPE_PES; |
887 | memcpy(&dmxdevfilter->params, params, | |
888 | sizeof(struct dmx_pes_filter_params)); | |
691c9ae0 | 889 | INIT_LIST_HEAD(&dmxdevfilter->feed.ts); |
1da177e4 LT |
890 | |
891 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); | |
892 | ||
1cb662a3 AO |
893 | ret = dvb_dmxdev_add_pid(dmxdev, dmxdevfilter, |
894 | dmxdevfilter->params.pes.pid); | |
895 | if (ret < 0) | |
896 | return ret; | |
897 | ||
f705e6e4 | 898 | if (params->flags & DMX_IMMEDIATE_START) |
1da177e4 LT |
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, | |
f705e6e4 AO |
905 | struct file *file, char __user *buf, |
906 | size_t count, loff_t *ppos) | |
1da177e4 LT |
907 | { |
908 | int result, hcount; | |
f705e6e4 AO |
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; | |
1da177e4 LT |
920 | return result; |
921 | } | |
f705e6e4 | 922 | if (copy_from_user(dfil->secheader - dfil->todo, buf, result)) |
1da177e4 | 923 | return -EFAULT; |
f705e6e4 AO |
924 | buf += result; |
925 | done = result; | |
926 | count -= result; | |
927 | dfil->todo -= result; | |
928 | if (dfil->todo > -3) | |
1da177e4 | 929 | return done; |
f705e6e4 | 930 | dfil->todo = ((dfil->secheader[1] << 8) | dfil->secheader[2]) & 0xfff; |
1da177e4 LT |
931 | if (!count) |
932 | return done; | |
933 | } | |
f705e6e4 AO |
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) | |
1da177e4 | 940 | return result; |
f705e6e4 AO |
941 | dfil->todo -= result; |
942 | return (result + done); | |
1da177e4 LT |
943 | } |
944 | ||
1da177e4 | 945 | static ssize_t |
f705e6e4 AO |
946 | dvb_demux_read(struct file *file, char __user *buf, size_t count, |
947 | loff_t *ppos) | |
1da177e4 | 948 | { |
f705e6e4 AO |
949 | struct dmxdev_filter *dmxdevfilter = file->private_data; |
950 | int ret; | |
1da177e4 | 951 | |
3593cab5 | 952 | if (mutex_lock_interruptible(&dmxdevfilter->mutex)) |
1da177e4 LT |
953 | return -ERESTARTSYS; |
954 | ||
f705e6e4 AO |
955 | if (dmxdevfilter->type == DMXDEV_TYPE_SEC) |
956 | ret = dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos); | |
1da177e4 | 957 | else |
f705e6e4 AO |
958 | ret = dvb_dmxdev_buffer_read(&dmxdevfilter->buffer, |
959 | file->f_flags & O_NONBLOCK, | |
960 | buf, count, ppos); | |
1da177e4 | 961 | |
3593cab5 | 962 | mutex_unlock(&dmxdevfilter->mutex); |
1da177e4 LT |
963 | return ret; |
964 | } | |
965 | ||
16ef8def | 966 | static int dvb_demux_do_ioctl(struct file *file, |
1da177e4 LT |
967 | unsigned int cmd, void *parg) |
968 | { | |
3ec4a307 | 969 | struct dmxdev_filter *dmxdevfilter = file->private_data; |
f705e6e4 AO |
970 | struct dmxdev *dmxdev = dmxdevfilter->dev; |
971 | unsigned long arg = (unsigned long)parg; | |
972 | int ret = 0; | |
1da177e4 | 973 | |
3593cab5 | 974 | if (mutex_lock_interruptible(&dmxdev->mutex)) |
1da177e4 LT |
975 | return -ERESTARTSYS; |
976 | ||
977 | switch (cmd) { | |
978 | case DMX_START: | |
3593cab5 IM |
979 | if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { |
980 | mutex_unlock(&dmxdev->mutex); | |
1da177e4 LT |
981 | return -ERESTARTSYS; |
982 | } | |
f705e6e4 | 983 | if (dmxdevfilter->state < DMXDEV_STATE_SET) |
1da177e4 LT |
984 | ret = -EINVAL; |
985 | else | |
986 | ret = dvb_dmxdev_filter_start(dmxdevfilter); | |
3593cab5 | 987 | mutex_unlock(&dmxdevfilter->mutex); |
1da177e4 LT |
988 | break; |
989 | ||
990 | case DMX_STOP: | |
3593cab5 IM |
991 | if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { |
992 | mutex_unlock(&dmxdev->mutex); | |
1da177e4 LT |
993 | return -ERESTARTSYS; |
994 | } | |
f705e6e4 | 995 | ret = dvb_dmxdev_filter_stop(dmxdevfilter); |
3593cab5 | 996 | mutex_unlock(&dmxdevfilter->mutex); |
1da177e4 LT |
997 | break; |
998 | ||
999 | case DMX_SET_FILTER: | |
3593cab5 IM |
1000 | if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { |
1001 | mutex_unlock(&dmxdev->mutex); | |
1da177e4 LT |
1002 | return -ERESTARTSYS; |
1003 | } | |
f705e6e4 | 1004 | ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, parg); |
3593cab5 | 1005 | mutex_unlock(&dmxdevfilter->mutex); |
1da177e4 LT |
1006 | break; |
1007 | ||
1008 | case DMX_SET_PES_FILTER: | |
3593cab5 IM |
1009 | if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { |
1010 | mutex_unlock(&dmxdev->mutex); | |
1da177e4 LT |
1011 | return -ERESTARTSYS; |
1012 | } | |
f705e6e4 | 1013 | ret = dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, parg); |
3593cab5 | 1014 | mutex_unlock(&dmxdevfilter->mutex); |
1da177e4 LT |
1015 | break; |
1016 | ||
1017 | case DMX_SET_BUFFER_SIZE: | |
3593cab5 IM |
1018 | if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { |
1019 | mutex_unlock(&dmxdev->mutex); | |
1da177e4 LT |
1020 | return -ERESTARTSYS; |
1021 | } | |
f705e6e4 | 1022 | ret = dvb_dmxdev_set_buffer_size(dmxdevfilter, arg); |
3593cab5 | 1023 | mutex_unlock(&dmxdevfilter->mutex); |
1da177e4 LT |
1024 | break; |
1025 | ||
1da177e4 LT |
1026 | case DMX_GET_PES_PIDS: |
1027 | if (!dmxdev->demux->get_pes_pids) { | |
f705e6e4 | 1028 | ret = -EINVAL; |
1da177e4 LT |
1029 | break; |
1030 | } | |
f705e6e4 | 1031 | dmxdev->demux->get_pes_pids(dmxdev->demux, parg); |
1da177e4 LT |
1032 | break; |
1033 | ||
c0510052 AO |
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 | ||
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 | ||
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 | ||
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) { | |
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; | |
1da177e4 LT |
1137 | } |
1138 | ||
784e29d2 | 1139 | static const struct file_operations dvb_demux_fops = { |
f705e6e4 AO |
1140 | .owner = THIS_MODULE, |
1141 | .read = dvb_demux_read, | |
16ef8def | 1142 | .unlocked_ioctl = dvb_demux_ioctl, |
f705e6e4 AO |
1143 | .open = dvb_demux_open, |
1144 | .release = dvb_demux_release, | |
1145 | .poll = dvb_demux_poll, | |
6038f373 | 1146 | .llseek = default_llseek, |
1da177e4 LT |
1147 | }; |
1148 | ||
1da177e4 | 1149 | static struct dvb_device dvbdev_demux = { |
f705e6e4 AO |
1150 | .priv = NULL, |
1151 | .users = 1, | |
1152 | .writers = 1, | |
1153 | .fops = &dvb_demux_fops | |
1da177e4 LT |
1154 | }; |
1155 | ||
16ef8def | 1156 | static int dvb_dvr_do_ioctl(struct file *file, |
f705e6e4 | 1157 | unsigned int cmd, void *parg) |
1da177e4 | 1158 | { |
0c53c70f JS |
1159 | struct dvb_device *dvbdev = file->private_data; |
1160 | struct dmxdev *dmxdev = dvbdev->priv; | |
a095be4b | 1161 | unsigned long arg = (unsigned long)parg; |
f705e6e4 | 1162 | int ret; |
1da177e4 | 1163 | |
3593cab5 | 1164 | if (mutex_lock_interruptible(&dmxdev->mutex)) |
1da177e4 LT |
1165 | return -ERESTARTSYS; |
1166 | ||
1167 | switch (cmd) { | |
1168 | case DMX_SET_BUFFER_SIZE: | |
a095be4b | 1169 | ret = dvb_dvr_set_buffer_size(dmxdev, arg); |
1da177e4 LT |
1170 | break; |
1171 | ||
1172 | default: | |
f705e6e4 AO |
1173 | ret = -EINVAL; |
1174 | break; | |
1da177e4 | 1175 | } |
3593cab5 | 1176 | mutex_unlock(&dmxdev->mutex); |
1da177e4 LT |
1177 | return ret; |
1178 | } | |
1179 | ||
16ef8def | 1180 | static long dvb_dvr_ioctl(struct file *file, |
f705e6e4 | 1181 | unsigned int cmd, unsigned long arg) |
1da177e4 | 1182 | { |
72024f1e | 1183 | return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl); |
1da177e4 LT |
1184 | } |
1185 | ||
f705e6e4 | 1186 | static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait) |
1da177e4 | 1187 | { |
0c53c70f JS |
1188 | struct dvb_device *dvbdev = file->private_data; |
1189 | struct dmxdev *dmxdev = dvbdev->priv; | |
1da177e4 LT |
1190 | unsigned int mask = 0; |
1191 | ||
46b4f7c1 | 1192 | dprintk("function : %s\n", __func__); |
1da177e4 LT |
1193 | |
1194 | poll_wait(file, &dmxdev->dvr_buffer.queue, wait); | |
1195 | ||
f705e6e4 | 1196 | if ((file->f_flags & O_ACCMODE) == O_RDONLY) { |
1da177e4 LT |
1197 | if (dmxdev->dvr_buffer.error) |
1198 | mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); | |
1199 | ||
34731df2 | 1200 | if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer)) |
1da177e4 LT |
1201 | mask |= (POLLIN | POLLRDNORM | POLLPRI); |
1202 | } else | |
1203 | mask |= (POLLOUT | POLLWRNORM | POLLPRI); | |
1204 | ||
1205 | return mask; | |
1206 | } | |
1207 | ||
828c0950 | 1208 | static const struct file_operations dvb_dvr_fops = { |
f705e6e4 AO |
1209 | .owner = THIS_MODULE, |
1210 | .read = dvb_dvr_read, | |
1211 | .write = dvb_dvr_write, | |
16ef8def | 1212 | .unlocked_ioctl = dvb_dvr_ioctl, |
f705e6e4 AO |
1213 | .open = dvb_dvr_open, |
1214 | .release = dvb_dvr_release, | |
1215 | .poll = dvb_dvr_poll, | |
6038f373 | 1216 | .llseek = default_llseek, |
1da177e4 LT |
1217 | }; |
1218 | ||
1219 | static struct dvb_device dvbdev_dvr = { | |
f705e6e4 | 1220 | .priv = NULL, |
5e85bd05 | 1221 | .readers = 1, |
57861b43 | 1222 | .users = 1, |
f705e6e4 | 1223 | .fops = &dvb_dvr_fops |
1da177e4 LT |
1224 | }; |
1225 | ||
f705e6e4 | 1226 | int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) |
1da177e4 LT |
1227 | { |
1228 | int i; | |
1229 | ||
1230 | if (dmxdev->demux->open(dmxdev->demux) < 0) | |
1231 | return -EUSERS; | |
1232 | ||
f705e6e4 | 1233 | dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter)); |
1da177e4 LT |
1234 | if (!dmxdev->filter) |
1235 | return -ENOMEM; | |
1236 | ||
3593cab5 | 1237 | mutex_init(&dmxdev->mutex); |
1da177e4 | 1238 | spin_lock_init(&dmxdev->lock); |
f705e6e4 AO |
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); | |
1da177e4 LT |
1244 | } |
1245 | ||
f705e6e4 AO |
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); | |
1da177e4 | 1250 | |
34731df2 | 1251 | dvb_ringbuffer_init(&dmxdev->dvr_buffer, NULL, 8192); |
1da177e4 LT |
1252 | |
1253 | return 0; | |
1254 | } | |
f705e6e4 | 1255 | |
1da177e4 LT |
1256 | EXPORT_SYMBOL(dvb_dmxdev_init); |
1257 | ||
f705e6e4 | 1258 | void dvb_dmxdev_release(struct dmxdev *dmxdev) |
1da177e4 | 1259 | { |
57861b43 MR |
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 | ||
1da177e4 LT |
1270 | dvb_unregister_device(dmxdev->dvbdev); |
1271 | dvb_unregister_device(dmxdev->dvr_dvbdev); | |
1272 | ||
1273 | vfree(dmxdev->filter); | |
f705e6e4 | 1274 | dmxdev->filter = NULL; |
1da177e4 LT |
1275 | dmxdev->demux->close(dmxdev->demux); |
1276 | } | |
f705e6e4 | 1277 | |
1da177e4 | 1278 | EXPORT_SYMBOL(dvb_dmxdev_release); |