]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * dmxdev.c - DVB demultiplexer device | |
3 | * | |
4 | * Copyright (C) 2000 Ralph Metzler <ralph@convergence.de> | |
5 | * & Marcus Metzler <marcus@convergence.de> | |
6 | for convergence integrated media GmbH | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public License | |
10 | * as published by the Free Software Foundation; either version 2.1 | |
11 | * of the License, or (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU Lesser General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
21 | * | |
22 | */ | |
23 | ||
24 | #include <linux/spinlock.h> | |
25 | #include <linux/slab.h> | |
26 | #include <linux/vmalloc.h> | |
27 | #include <linux/module.h> | |
28 | #include <linux/moduleparam.h> | |
29 | #include <linux/sched.h> | |
30 | #include <linux/poll.h> | |
31 | #include <linux/ioctl.h> | |
32 | #include <linux/wait.h> | |
33 | #include <asm/uaccess.h> | |
34 | #include <asm/system.h> | |
35 | ||
36 | #include "dmxdev.h" | |
37 | ||
38 | static int debug; | |
39 | ||
40 | module_param(debug, int, 0644); | |
41 | MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); | |
42 | ||
43 | #define dprintk if (debug) printk | |
44 | ||
1da177e4 LT |
45 | static inline void dvb_dmxdev_buffer_init(struct dmxdev_buffer *buffer) |
46 | { | |
47 | buffer->data=NULL; | |
48 | buffer->size=8192; | |
49 | buffer->pread=0; | |
50 | buffer->pwrite=0; | |
51 | buffer->error=0; | |
52 | init_waitqueue_head(&buffer->queue); | |
53 | } | |
54 | ||
55 | static inline int dvb_dmxdev_buffer_write(struct dmxdev_buffer *buf, const u8 *src, int len) | |
56 | { | |
57 | int split; | |
58 | int free; | |
59 | int todo; | |
60 | ||
61 | if (!len) | |
62 | return 0; | |
63 | if (!buf->data) | |
64 | return 0; | |
65 | ||
66 | free=buf->pread-buf->pwrite; | |
67 | split=0; | |
68 | if (free<=0) { | |
69 | free+=buf->size; | |
70 | split=buf->size-buf->pwrite; | |
71 | } | |
72 | if (len>=free) { | |
73 | dprintk("dmxdev: buffer overflow\n"); | |
74 | return -1; | |
75 | } | |
76 | if (split>=len) | |
77 | split=0; | |
78 | todo=len; | |
79 | if (split) { | |
80 | memcpy(buf->data + buf->pwrite, src, split); | |
81 | todo-=split; | |
82 | buf->pwrite=0; | |
83 | } | |
84 | memcpy(buf->data + buf->pwrite, src+split, todo); | |
85 | buf->pwrite=(buf->pwrite+todo)%buf->size; | |
86 | return len; | |
87 | } | |
88 | ||
89 | static ssize_t dvb_dmxdev_buffer_read(struct dmxdev_buffer *src, | |
90 | int non_blocking, char __user *buf, size_t count, loff_t *ppos) | |
91 | { | |
92 | unsigned long todo=count; | |
93 | int split, avail, error; | |
94 | ||
95 | if (!src->data) | |
96 | return 0; | |
97 | ||
98 | if ((error=src->error)) { | |
99 | src->pwrite=src->pread; | |
100 | src->error=0; | |
101 | return error; | |
102 | } | |
103 | ||
104 | if (non_blocking && (src->pwrite==src->pread)) | |
105 | return -EWOULDBLOCK; | |
106 | ||
107 | while (todo>0) { | |
108 | if (non_blocking && (src->pwrite==src->pread)) | |
109 | return (count-todo) ? (count-todo) : -EWOULDBLOCK; | |
110 | ||
111 | if (wait_event_interruptible(src->queue, | |
112 | (src->pread!=src->pwrite) || | |
113 | (src->error))<0) | |
114 | return count-todo; | |
115 | ||
116 | if ((error=src->error)) { | |
117 | src->pwrite=src->pread; | |
118 | src->error=0; | |
119 | return error; | |
120 | } | |
121 | ||
122 | split=src->size; | |
123 | avail=src->pwrite - src->pread; | |
124 | if (avail<0) { | |
125 | avail+=src->size; | |
126 | split=src->size - src->pread; | |
127 | } | |
128 | if (avail>todo) | |
129 | avail=todo; | |
130 | if (split<avail) { | |
131 | if (copy_to_user(buf, src->data+src->pread, split)) | |
132 | return -EFAULT; | |
133 | buf+=split; | |
134 | src->pread=0; | |
135 | todo-=split; | |
136 | avail-=split; | |
137 | } | |
138 | if (avail) { | |
139 | if (copy_to_user(buf, src->data+src->pread, avail)) | |
140 | return -EFAULT; | |
141 | src->pread = (src->pread + avail) % src->size; | |
142 | todo-=avail; | |
143 | buf+=avail; | |
144 | } | |
145 | } | |
146 | return count; | |
147 | } | |
148 | ||
149 | static struct dmx_frontend * get_fe(struct dmx_demux *demux, int type) | |
150 | { | |
151 | struct list_head *head, *pos; | |
152 | ||
153 | head=demux->get_frontends(demux); | |
154 | if (!head) | |
155 | return NULL; | |
156 | list_for_each(pos, head) | |
157 | if (DMX_FE_ENTRY(pos)->source==type) | |
158 | return DMX_FE_ENTRY(pos); | |
159 | ||
160 | return NULL; | |
161 | } | |
162 | ||
163 | static inline void dvb_dmxdev_dvr_state_set(struct dmxdev_dvr *dmxdevdvr, int state) | |
164 | { | |
165 | spin_lock_irq(&dmxdevdvr->dev->lock); | |
166 | dmxdevdvr->state=state; | |
167 | spin_unlock_irq(&dmxdevdvr->dev->lock); | |
168 | } | |
169 | ||
170 | static int dvb_dvr_open(struct inode *inode, struct file *file) | |
171 | { | |
0c53c70f JS |
172 | struct dvb_device *dvbdev = file->private_data; |
173 | struct dmxdev *dmxdev = dvbdev->priv; | |
1da177e4 LT |
174 | struct dmx_frontend *front; |
175 | ||
176 | dprintk ("function : %s\n", __FUNCTION__); | |
177 | ||
178 | if (down_interruptible (&dmxdev->mutex)) | |
179 | return -ERESTARTSYS; | |
180 | ||
181 | if ((file->f_flags&O_ACCMODE)==O_RDWR) { | |
182 | if (!(dmxdev->capabilities&DMXDEV_CAP_DUPLEX)) { | |
183 | up(&dmxdev->mutex); | |
184 | return -EOPNOTSUPP; | |
185 | } | |
186 | } | |
187 | ||
188 | if ((file->f_flags&O_ACCMODE)==O_RDONLY) { | |
189 | dvb_dmxdev_buffer_init(&dmxdev->dvr_buffer); | |
190 | dmxdev->dvr_buffer.size=DVR_BUFFER_SIZE; | |
191 | dmxdev->dvr_buffer.data=vmalloc(DVR_BUFFER_SIZE); | |
192 | if (!dmxdev->dvr_buffer.data) { | |
193 | up(&dmxdev->mutex); | |
194 | return -ENOMEM; | |
195 | } | |
196 | } | |
197 | ||
198 | if ((file->f_flags&O_ACCMODE)==O_WRONLY) { | |
199 | dmxdev->dvr_orig_fe=dmxdev->demux->frontend; | |
200 | ||
201 | if (!dmxdev->demux->write) { | |
202 | up(&dmxdev->mutex); | |
203 | return -EOPNOTSUPP; | |
204 | } | |
205 | ||
206 | front=get_fe(dmxdev->demux, DMX_MEMORY_FE); | |
207 | ||
208 | if (!front) { | |
209 | up(&dmxdev->mutex); | |
210 | return -EINVAL; | |
211 | } | |
212 | dmxdev->demux->disconnect_frontend(dmxdev->demux); | |
213 | dmxdev->demux->connect_frontend(dmxdev->demux, front); | |
214 | } | |
215 | up(&dmxdev->mutex); | |
216 | return 0; | |
217 | } | |
218 | ||
219 | static int dvb_dvr_release(struct inode *inode, struct file *file) | |
220 | { | |
0c53c70f JS |
221 | struct dvb_device *dvbdev = file->private_data; |
222 | struct dmxdev *dmxdev = dvbdev->priv; | |
1da177e4 LT |
223 | |
224 | if (down_interruptible (&dmxdev->mutex)) | |
225 | return -ERESTARTSYS; | |
226 | ||
227 | if ((file->f_flags&O_ACCMODE)==O_WRONLY) { | |
228 | dmxdev->demux->disconnect_frontend(dmxdev->demux); | |
229 | dmxdev->demux->connect_frontend(dmxdev->demux, | |
230 | dmxdev->dvr_orig_fe); | |
231 | } | |
232 | if ((file->f_flags&O_ACCMODE)==O_RDONLY) { | |
233 | if (dmxdev->dvr_buffer.data) { | |
234 | void *mem=dmxdev->dvr_buffer.data; | |
235 | mb(); | |
236 | spin_lock_irq(&dmxdev->lock); | |
237 | dmxdev->dvr_buffer.data=NULL; | |
238 | spin_unlock_irq(&dmxdev->lock); | |
239 | vfree(mem); | |
240 | } | |
241 | } | |
242 | up(&dmxdev->mutex); | |
243 | return 0; | |
244 | } | |
245 | ||
246 | static ssize_t dvb_dvr_write(struct file *file, const char __user *buf, | |
247 | size_t count, loff_t *ppos) | |
248 | { | |
0c53c70f JS |
249 | struct dvb_device *dvbdev = file->private_data; |
250 | struct dmxdev *dmxdev = dvbdev->priv; | |
1da177e4 LT |
251 | int ret; |
252 | ||
253 | if (!dmxdev->demux->write) | |
254 | return -EOPNOTSUPP; | |
255 | if ((file->f_flags&O_ACCMODE)!=O_WRONLY) | |
256 | return -EINVAL; | |
257 | if (down_interruptible (&dmxdev->mutex)) | |
258 | return -ERESTARTSYS; | |
259 | ret=dmxdev->demux->write(dmxdev->demux, buf, count); | |
260 | up(&dmxdev->mutex); | |
261 | return ret; | |
262 | } | |
263 | ||
264 | static ssize_t dvb_dvr_read(struct file *file, char __user *buf, size_t count, | |
265 | loff_t *ppos) | |
266 | { | |
0c53c70f JS |
267 | struct dvb_device *dvbdev = file->private_data; |
268 | struct dmxdev *dmxdev = dvbdev->priv; | |
1da177e4 LT |
269 | int ret; |
270 | ||
271 | //down(&dmxdev->mutex); | |
272 | ret= dvb_dmxdev_buffer_read(&dmxdev->dvr_buffer, | |
273 | file->f_flags&O_NONBLOCK, | |
274 | buf, count, ppos); | |
275 | //up(&dmxdev->mutex); | |
276 | return ret; | |
277 | } | |
278 | ||
279 | static inline void dvb_dmxdev_filter_state_set(struct dmxdev_filter *dmxdevfilter, int state) | |
280 | { | |
281 | spin_lock_irq(&dmxdevfilter->dev->lock); | |
282 | dmxdevfilter->state=state; | |
283 | spin_unlock_irq(&dmxdevfilter->dev->lock); | |
284 | } | |
285 | ||
286 | static int dvb_dmxdev_set_buffer_size(struct dmxdev_filter *dmxdevfilter, unsigned long size) | |
287 | { | |
288 | struct dmxdev_buffer *buf=&dmxdevfilter->buffer; | |
289 | void *mem; | |
290 | ||
291 | if (buf->size==size) | |
292 | return 0; | |
293 | if (dmxdevfilter->state>=DMXDEV_STATE_GO) | |
294 | return -EBUSY; | |
295 | spin_lock_irq(&dmxdevfilter->dev->lock); | |
296 | mem=buf->data; | |
297 | buf->data=NULL; | |
298 | buf->size=size; | |
299 | buf->pwrite=buf->pread=0; | |
300 | spin_unlock_irq(&dmxdevfilter->dev->lock); | |
301 | vfree(mem); | |
302 | ||
303 | if (buf->size) { | |
304 | mem=vmalloc(dmxdevfilter->buffer.size); | |
305 | if (!mem) | |
306 | return -ENOMEM; | |
307 | spin_lock_irq(&dmxdevfilter->dev->lock); | |
308 | buf->data=mem; | |
309 | spin_unlock_irq(&dmxdevfilter->dev->lock); | |
310 | } | |
311 | return 0; | |
312 | } | |
313 | ||
314 | static void dvb_dmxdev_filter_timeout(unsigned long data) | |
315 | { | |
316 | struct dmxdev_filter *dmxdevfilter=(struct dmxdev_filter *)data; | |
317 | ||
318 | dmxdevfilter->buffer.error=-ETIMEDOUT; | |
319 | spin_lock_irq(&dmxdevfilter->dev->lock); | |
320 | dmxdevfilter->state=DMXDEV_STATE_TIMEDOUT; | |
321 | spin_unlock_irq(&dmxdevfilter->dev->lock); | |
322 | wake_up(&dmxdevfilter->buffer.queue); | |
323 | } | |
324 | ||
325 | static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter) | |
326 | { | |
327 | struct dmx_sct_filter_params *para=&dmxdevfilter->params.sec; | |
328 | ||
329 | del_timer(&dmxdevfilter->timer); | |
330 | if (para->timeout) { | |
331 | dmxdevfilter->timer.function=dvb_dmxdev_filter_timeout; | |
332 | dmxdevfilter->timer.data=(unsigned long) dmxdevfilter; | |
333 | dmxdevfilter->timer.expires=jiffies+1+(HZ/2+HZ*para->timeout)/1000; | |
334 | add_timer(&dmxdevfilter->timer); | |
335 | } | |
336 | } | |
337 | ||
338 | static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, | |
339 | const u8 *buffer2, size_t buffer2_len, | |
340 | struct dmx_section_filter *filter, enum dmx_success success) | |
341 | { | |
0c53c70f | 342 | struct dmxdev_filter *dmxdevfilter = filter->priv; |
1da177e4 LT |
343 | int ret; |
344 | ||
345 | if (dmxdevfilter->buffer.error) { | |
346 | wake_up(&dmxdevfilter->buffer.queue); | |
347 | return 0; | |
348 | } | |
349 | spin_lock(&dmxdevfilter->dev->lock); | |
350 | if (dmxdevfilter->state!=DMXDEV_STATE_GO) { | |
351 | spin_unlock(&dmxdevfilter->dev->lock); | |
352 | return 0; | |
353 | } | |
354 | del_timer(&dmxdevfilter->timer); | |
355 | dprintk("dmxdev: section callback %02x %02x %02x %02x %02x %02x\n", | |
356 | buffer1[0], buffer1[1], | |
357 | buffer1[2], buffer1[3], | |
358 | buffer1[4], buffer1[5]); | |
359 | ret=dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, buffer1_len); | |
360 | if (ret==buffer1_len) { | |
361 | ret=dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, buffer2_len); | |
362 | } | |
363 | if (ret<0) { | |
364 | dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread; | |
365 | dmxdevfilter->buffer.error=-EOVERFLOW; | |
366 | } | |
367 | if (dmxdevfilter->params.sec.flags&DMX_ONESHOT) | |
368 | dmxdevfilter->state=DMXDEV_STATE_DONE; | |
369 | spin_unlock(&dmxdevfilter->dev->lock); | |
370 | wake_up(&dmxdevfilter->buffer.queue); | |
371 | return 0; | |
372 | } | |
373 | ||
374 | static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, | |
375 | const u8 *buffer2, size_t buffer2_len, | |
376 | struct dmx_ts_feed *feed, enum dmx_success success) | |
377 | { | |
0c53c70f | 378 | struct dmxdev_filter *dmxdevfilter = feed->priv; |
1da177e4 LT |
379 | struct dmxdev_buffer *buffer; |
380 | int ret; | |
381 | ||
382 | spin_lock(&dmxdevfilter->dev->lock); | |
383 | if (dmxdevfilter->params.pes.output==DMX_OUT_DECODER) { | |
384 | spin_unlock(&dmxdevfilter->dev->lock); | |
385 | return 0; | |
386 | } | |
387 | ||
388 | if (dmxdevfilter->params.pes.output==DMX_OUT_TAP) | |
389 | buffer=&dmxdevfilter->buffer; | |
390 | else | |
391 | buffer=&dmxdevfilter->dev->dvr_buffer; | |
392 | if (buffer->error) { | |
393 | spin_unlock(&dmxdevfilter->dev->lock); | |
394 | wake_up(&buffer->queue); | |
395 | return 0; | |
396 | } | |
397 | ret=dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len); | |
398 | if (ret==buffer1_len) | |
399 | ret=dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len); | |
400 | if (ret<0) { | |
401 | buffer->pwrite=buffer->pread; | |
402 | buffer->error=-EOVERFLOW; | |
403 | } | |
404 | spin_unlock(&dmxdevfilter->dev->lock); | |
405 | wake_up(&buffer->queue); | |
406 | return 0; | |
407 | } | |
408 | ||
409 | ||
410 | /* stop feed but only mark the specified filter as stopped (state set) */ | |
411 | ||
412 | static int dvb_dmxdev_feed_stop(struct dmxdev_filter *dmxdevfilter) | |
413 | { | |
414 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); | |
415 | ||
416 | switch (dmxdevfilter->type) { | |
417 | case DMXDEV_TYPE_SEC: | |
418 | del_timer(&dmxdevfilter->timer); | |
419 | dmxdevfilter->feed.sec->stop_filtering(dmxdevfilter->feed.sec); | |
420 | break; | |
421 | case DMXDEV_TYPE_PES: | |
422 | dmxdevfilter->feed.ts->stop_filtering(dmxdevfilter->feed.ts); | |
423 | break; | |
424 | default: | |
425 | return -EINVAL; | |
426 | } | |
427 | return 0; | |
428 | } | |
429 | ||
430 | ||
431 | /* start feed associated with the specified filter */ | |
432 | ||
433 | static int dvb_dmxdev_feed_start(struct dmxdev_filter *filter) | |
434 | { | |
435 | dvb_dmxdev_filter_state_set (filter, DMXDEV_STATE_GO); | |
436 | ||
437 | switch (filter->type) { | |
438 | case DMXDEV_TYPE_SEC: | |
439 | return filter->feed.sec->start_filtering(filter->feed.sec); | |
440 | break; | |
441 | case DMXDEV_TYPE_PES: | |
442 | return filter->feed.ts->start_filtering(filter->feed.ts); | |
443 | break; | |
444 | default: | |
445 | return -EINVAL; | |
446 | } | |
447 | ||
448 | return 0; | |
449 | } | |
450 | ||
451 | ||
452 | /* restart section feed if it has filters left associated with it, | |
453 | otherwise release the feed */ | |
454 | ||
455 | static int dvb_dmxdev_feed_restart(struct dmxdev_filter *filter) | |
456 | { | |
457 | int i; | |
458 | struct dmxdev *dmxdev = filter->dev; | |
459 | u16 pid = filter->params.sec.pid; | |
460 | ||
461 | for (i=0; i<dmxdev->filternum; i++) | |
462 | if (dmxdev->filter[i].state>=DMXDEV_STATE_GO && | |
463 | dmxdev->filter[i].type==DMXDEV_TYPE_SEC && | |
464 | dmxdev->filter[i].pid==pid) { | |
465 | dvb_dmxdev_feed_start(&dmxdev->filter[i]); | |
466 | return 0; | |
467 | } | |
468 | ||
469 | filter->dev->demux->release_section_feed(dmxdev->demux, filter->feed.sec); | |
470 | ||
471 | return 0; | |
472 | } | |
473 | ||
474 | static int dvb_dmxdev_filter_stop(struct dmxdev_filter *dmxdevfilter) | |
475 | { | |
476 | if (dmxdevfilter->state<DMXDEV_STATE_GO) | |
477 | return 0; | |
478 | ||
479 | switch (dmxdevfilter->type) { | |
480 | case DMXDEV_TYPE_SEC: | |
481 | if (!dmxdevfilter->feed.sec) | |
482 | break; | |
483 | dvb_dmxdev_feed_stop(dmxdevfilter); | |
484 | if (dmxdevfilter->filter.sec) | |
485 | dmxdevfilter->feed.sec-> | |
486 | release_filter(dmxdevfilter->feed.sec, | |
487 | dmxdevfilter->filter.sec); | |
488 | dvb_dmxdev_feed_restart(dmxdevfilter); | |
489 | dmxdevfilter->feed.sec=NULL; | |
490 | break; | |
491 | case DMXDEV_TYPE_PES: | |
492 | if (!dmxdevfilter->feed.ts) | |
493 | break; | |
494 | dvb_dmxdev_feed_stop(dmxdevfilter); | |
495 | dmxdevfilter->dev->demux-> | |
496 | release_ts_feed(dmxdevfilter->dev->demux, | |
497 | dmxdevfilter->feed.ts); | |
498 | dmxdevfilter->feed.ts=NULL; | |
499 | break; | |
500 | default: | |
501 | if (dmxdevfilter->state==DMXDEV_STATE_ALLOCATED) | |
502 | return 0; | |
503 | return -EINVAL; | |
504 | } | |
505 | dmxdevfilter->buffer.pwrite=dmxdevfilter->buffer.pread=0; | |
506 | return 0; | |
507 | } | |
508 | ||
509 | static inline int dvb_dmxdev_filter_reset(struct dmxdev_filter *dmxdevfilter) | |
510 | { | |
511 | if (dmxdevfilter->state<DMXDEV_STATE_SET) | |
512 | return 0; | |
513 | ||
514 | dmxdevfilter->type=DMXDEV_TYPE_NONE; | |
515 | dmxdevfilter->pid=0xffff; | |
516 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); | |
517 | return 0; | |
518 | } | |
519 | ||
520 | static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) | |
521 | { | |
522 | struct dmxdev *dmxdev = filter->dev; | |
523 | void *mem; | |
524 | int ret, i; | |
525 | ||
526 | if (filter->state < DMXDEV_STATE_SET) | |
527 | return -EINVAL; | |
528 | ||
529 | if (filter->state >= DMXDEV_STATE_GO) | |
530 | dvb_dmxdev_filter_stop(filter); | |
531 | ||
532 | if (!(mem = filter->buffer.data)) { | |
533 | mem = vmalloc(filter->buffer.size); | |
534 | spin_lock_irq(&filter->dev->lock); | |
535 | filter->buffer.data=mem; | |
536 | spin_unlock_irq(&filter->dev->lock); | |
537 | if (!filter->buffer.data) | |
538 | return -ENOMEM; | |
539 | } | |
540 | ||
541 | filter->buffer.pwrite = filter->buffer.pread = 0; | |
542 | ||
543 | switch (filter->type) { | |
544 | case DMXDEV_TYPE_SEC: | |
545 | { | |
546 | struct dmx_sct_filter_params *para=&filter->params.sec; | |
547 | struct dmx_section_filter **secfilter=&filter->filter.sec; | |
548 | struct dmx_section_feed **secfeed=&filter->feed.sec; | |
549 | ||
550 | *secfilter=NULL; | |
551 | *secfeed=NULL; | |
552 | ||
553 | /* find active filter/feed with same PID */ | |
554 | for (i=0; i<dmxdev->filternum; i++) { | |
555 | if (dmxdev->filter[i].state >= DMXDEV_STATE_GO && | |
556 | dmxdev->filter[i].pid == para->pid && | |
557 | dmxdev->filter[i].type == DMXDEV_TYPE_SEC) { | |
558 | *secfeed = dmxdev->filter[i].feed.sec; | |
559 | break; | |
560 | } | |
561 | } | |
562 | ||
563 | /* if no feed found, try to allocate new one */ | |
564 | if (!*secfeed) { | |
565 | ret=dmxdev->demux->allocate_section_feed(dmxdev->demux, | |
566 | secfeed, | |
567 | dvb_dmxdev_section_callback); | |
568 | if (ret<0) { | |
569 | printk ("DVB (%s): could not alloc feed\n", | |
570 | __FUNCTION__); | |
571 | return ret; | |
572 | } | |
573 | ||
5d2cd163 | 574 | ret=(*secfeed)->set(*secfeed, para->pid, 32768, |
1da177e4 LT |
575 | (para->flags & DMX_CHECK_CRC) ? 1 : 0); |
576 | ||
577 | if (ret<0) { | |
578 | printk ("DVB (%s): could not set feed\n", | |
579 | __FUNCTION__); | |
580 | dvb_dmxdev_feed_restart(filter); | |
581 | return ret; | |
582 | } | |
583 | } else { | |
584 | dvb_dmxdev_feed_stop(filter); | |
585 | } | |
586 | ||
587 | ret=(*secfeed)->allocate_filter(*secfeed, secfilter); | |
588 | ||
589 | if (ret < 0) { | |
590 | dvb_dmxdev_feed_restart(filter); | |
591 | filter->feed.sec->start_filtering(*secfeed); | |
592 | dprintk ("could not get filter\n"); | |
593 | return ret; | |
594 | } | |
595 | ||
596 | (*secfilter)->priv = filter; | |
597 | ||
598 | memcpy(&((*secfilter)->filter_value[3]), | |
599 | &(para->filter.filter[1]), DMX_FILTER_SIZE-1); | |
600 | memcpy(&(*secfilter)->filter_mask[3], | |
601 | ¶->filter.mask[1], DMX_FILTER_SIZE-1); | |
602 | memcpy(&(*secfilter)->filter_mode[3], | |
603 | ¶->filter.mode[1], DMX_FILTER_SIZE-1); | |
604 | ||
605 | (*secfilter)->filter_value[0]=para->filter.filter[0]; | |
606 | (*secfilter)->filter_mask[0]=para->filter.mask[0]; | |
607 | (*secfilter)->filter_mode[0]=para->filter.mode[0]; | |
608 | (*secfilter)->filter_mask[1]=0; | |
609 | (*secfilter)->filter_mask[2]=0; | |
610 | ||
611 | filter->todo = 0; | |
612 | ||
613 | ret = filter->feed.sec->start_filtering (filter->feed.sec); | |
614 | ||
615 | if (ret < 0) | |
616 | return ret; | |
617 | ||
618 | dvb_dmxdev_filter_timer(filter); | |
619 | break; | |
620 | } | |
621 | ||
622 | case DMXDEV_TYPE_PES: | |
623 | { | |
624 | struct timespec timeout = { 0 }; | |
625 | struct dmx_pes_filter_params *para = &filter->params.pes; | |
626 | dmx_output_t otype; | |
627 | int ret; | |
628 | int ts_type; | |
629 | enum dmx_ts_pes ts_pes; | |
630 | struct dmx_ts_feed **tsfeed = &filter->feed.ts; | |
631 | ||
632 | filter->feed.ts = NULL; | |
633 | otype=para->output; | |
634 | ||
635 | ts_pes=(enum dmx_ts_pes) para->pes_type; | |
636 | ||
637 | if (ts_pes<DMX_PES_OTHER) | |
638 | ts_type=TS_DECODER; | |
639 | else | |
640 | ts_type=0; | |
641 | ||
642 | if (otype == DMX_OUT_TS_TAP) | |
643 | ts_type |= TS_PACKET; | |
644 | ||
645 | if (otype == DMX_OUT_TAP) | |
646 | ts_type |= TS_PAYLOAD_ONLY|TS_PACKET; | |
647 | ||
648 | ret=dmxdev->demux->allocate_ts_feed(dmxdev->demux, | |
649 | tsfeed, | |
650 | dvb_dmxdev_ts_callback); | |
651 | if (ret<0) | |
652 | return ret; | |
653 | ||
654 | (*tsfeed)->priv = (void *) filter; | |
655 | ||
656 | ret = (*tsfeed)->set(*tsfeed, para->pid, ts_type, ts_pes, | |
5d2cd163 | 657 | 32768, timeout); |
1da177e4 LT |
658 | |
659 | if (ret < 0) { | |
660 | dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed); | |
661 | return ret; | |
662 | } | |
663 | ||
664 | ret = filter->feed.ts->start_filtering(filter->feed.ts); | |
665 | ||
76197924 PB |
666 | if (ret < 0) { |
667 | dmxdev->demux->release_ts_feed(dmxdev->demux, *tsfeed); | |
1da177e4 | 668 | return ret; |
76197924 | 669 | } |
1da177e4 LT |
670 | |
671 | break; | |
672 | } | |
673 | default: | |
674 | return -EINVAL; | |
675 | } | |
676 | ||
677 | dvb_dmxdev_filter_state_set(filter, DMXDEV_STATE_GO); | |
678 | return 0; | |
679 | } | |
680 | ||
681 | static int dvb_demux_open(struct inode *inode, struct file *file) | |
682 | { | |
0c53c70f JS |
683 | struct dvb_device *dvbdev = file->private_data; |
684 | struct dmxdev *dmxdev = dvbdev->priv; | |
1da177e4 LT |
685 | int i; |
686 | struct dmxdev_filter *dmxdevfilter; | |
687 | ||
688 | if (!dmxdev->filter) | |
689 | return -EINVAL; | |
690 | ||
691 | if (down_interruptible(&dmxdev->mutex)) | |
692 | return -ERESTARTSYS; | |
693 | ||
694 | for (i=0; i<dmxdev->filternum; i++) | |
695 | if (dmxdev->filter[i].state==DMXDEV_STATE_FREE) | |
696 | break; | |
697 | ||
698 | if (i==dmxdev->filternum) { | |
699 | up(&dmxdev->mutex); | |
700 | return -EMFILE; | |
701 | } | |
702 | ||
703 | dmxdevfilter=&dmxdev->filter[i]; | |
704 | sema_init(&dmxdevfilter->mutex, 1); | |
705 | dmxdevfilter->dvbdev=dmxdev->dvbdev; | |
706 | file->private_data=dmxdevfilter; | |
707 | ||
708 | dvb_dmxdev_buffer_init(&dmxdevfilter->buffer); | |
709 | dmxdevfilter->type=DMXDEV_TYPE_NONE; | |
710 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); | |
711 | dmxdevfilter->feed.ts=NULL; | |
712 | init_timer(&dmxdevfilter->timer); | |
713 | ||
714 | up(&dmxdev->mutex); | |
715 | return 0; | |
716 | } | |
717 | ||
718 | ||
719 | static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, struct dmxdev_filter *dmxdevfilter) | |
720 | { | |
721 | if (down_interruptible(&dmxdev->mutex)) | |
722 | return -ERESTARTSYS; | |
723 | ||
724 | if (down_interruptible(&dmxdevfilter->mutex)) { | |
725 | up(&dmxdev->mutex); | |
726 | return -ERESTARTSYS; | |
727 | } | |
728 | ||
729 | dvb_dmxdev_filter_stop(dmxdevfilter); | |
730 | dvb_dmxdev_filter_reset(dmxdevfilter); | |
731 | ||
732 | if (dmxdevfilter->buffer.data) { | |
733 | void *mem=dmxdevfilter->buffer.data; | |
734 | ||
735 | spin_lock_irq(&dmxdev->lock); | |
736 | dmxdevfilter->buffer.data=NULL; | |
737 | spin_unlock_irq(&dmxdev->lock); | |
738 | vfree(mem); | |
739 | } | |
740 | ||
741 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_FREE); | |
742 | wake_up(&dmxdevfilter->buffer.queue); | |
743 | up(&dmxdevfilter->mutex); | |
744 | up(&dmxdev->mutex); | |
745 | return 0; | |
746 | } | |
747 | ||
748 | static inline void invert_mode(dmx_filter_t *filter) | |
749 | { | |
750 | int i; | |
751 | ||
752 | for (i=0; i<DMX_FILTER_SIZE; i++) | |
753 | filter->mode[i]^=0xff; | |
754 | } | |
755 | ||
756 | ||
757 | static int dvb_dmxdev_filter_set(struct dmxdev *dmxdev, | |
758 | struct dmxdev_filter *dmxdevfilter, | |
759 | struct dmx_sct_filter_params *params) | |
760 | { | |
761 | dprintk ("function : %s\n", __FUNCTION__); | |
762 | ||
763 | dvb_dmxdev_filter_stop(dmxdevfilter); | |
764 | ||
765 | dmxdevfilter->type=DMXDEV_TYPE_SEC; | |
766 | dmxdevfilter->pid=params->pid; | |
767 | memcpy(&dmxdevfilter->params.sec, | |
768 | params, sizeof(struct dmx_sct_filter_params)); | |
769 | invert_mode(&dmxdevfilter->params.sec.filter); | |
770 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); | |
771 | ||
772 | if (params->flags&DMX_IMMEDIATE_START) | |
773 | return dvb_dmxdev_filter_start(dmxdevfilter); | |
774 | ||
775 | return 0; | |
776 | } | |
777 | ||
778 | static int dvb_dmxdev_pes_filter_set(struct dmxdev *dmxdev, | |
779 | struct dmxdev_filter *dmxdevfilter, | |
780 | struct dmx_pes_filter_params *params) | |
781 | { | |
782 | dvb_dmxdev_filter_stop(dmxdevfilter); | |
783 | ||
784 | if (params->pes_type>DMX_PES_OTHER || params->pes_type<0) | |
785 | return -EINVAL; | |
786 | ||
787 | dmxdevfilter->type=DMXDEV_TYPE_PES; | |
788 | dmxdevfilter->pid=params->pid; | |
789 | memcpy(&dmxdevfilter->params, params, sizeof(struct dmx_pes_filter_params)); | |
790 | ||
791 | dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_SET); | |
792 | ||
793 | if (params->flags&DMX_IMMEDIATE_START) | |
794 | return dvb_dmxdev_filter_start(dmxdevfilter); | |
795 | ||
796 | return 0; | |
797 | } | |
798 | ||
799 | static ssize_t dvb_dmxdev_read_sec(struct dmxdev_filter *dfil, | |
800 | struct file *file, char __user *buf, size_t count, loff_t *ppos) | |
801 | { | |
802 | int result, hcount; | |
803 | int done=0; | |
804 | ||
805 | if (dfil->todo<=0) { | |
806 | hcount=3+dfil->todo; | |
807 | if (hcount>count) | |
808 | hcount=count; | |
809 | result=dvb_dmxdev_buffer_read(&dfil->buffer, file->f_flags&O_NONBLOCK, | |
810 | buf, hcount, ppos); | |
811 | if (result<0) { | |
812 | dfil->todo=0; | |
813 | return result; | |
814 | } | |
815 | if (copy_from_user(dfil->secheader-dfil->todo, buf, result)) | |
816 | return -EFAULT; | |
817 | buf+=result; | |
818 | done=result; | |
819 | count-=result; | |
820 | dfil->todo-=result; | |
821 | if (dfil->todo>-3) | |
822 | return done; | |
823 | dfil->todo=((dfil->secheader[1]<<8)|dfil->secheader[2])&0xfff; | |
824 | if (!count) | |
825 | return done; | |
826 | } | |
827 | if (count>dfil->todo) | |
828 | count=dfil->todo; | |
829 | result=dvb_dmxdev_buffer_read(&dfil->buffer, file->f_flags&O_NONBLOCK, | |
830 | buf, count, ppos); | |
831 | if (result<0) | |
832 | return result; | |
833 | dfil->todo-=result; | |
834 | return (result+done); | |
835 | } | |
836 | ||
837 | ||
838 | static ssize_t | |
839 | dvb_demux_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | |
840 | { | |
3ec4a307 | 841 | struct dmxdev_filter *dmxdevfilter= file->private_data; |
1da177e4 LT |
842 | int ret=0; |
843 | ||
844 | if (down_interruptible(&dmxdevfilter->mutex)) | |
845 | return -ERESTARTSYS; | |
846 | ||
847 | if (dmxdevfilter->type==DMXDEV_TYPE_SEC) | |
848 | ret=dvb_dmxdev_read_sec(dmxdevfilter, file, buf, count, ppos); | |
849 | else | |
850 | ret=dvb_dmxdev_buffer_read(&dmxdevfilter->buffer, | |
851 | file->f_flags&O_NONBLOCK, | |
852 | buf, count, ppos); | |
853 | ||
854 | up(&dmxdevfilter->mutex); | |
855 | return ret; | |
856 | } | |
857 | ||
858 | ||
859 | static int dvb_demux_do_ioctl(struct inode *inode, struct file *file, | |
860 | unsigned int cmd, void *parg) | |
861 | { | |
3ec4a307 | 862 | struct dmxdev_filter *dmxdevfilter = file->private_data; |
1da177e4 LT |
863 | struct dmxdev *dmxdev=dmxdevfilter->dev; |
864 | unsigned long arg=(unsigned long) parg; | |
865 | int ret=0; | |
866 | ||
867 | if (down_interruptible (&dmxdev->mutex)) | |
868 | return -ERESTARTSYS; | |
869 | ||
870 | switch (cmd) { | |
871 | case DMX_START: | |
872 | if (down_interruptible(&dmxdevfilter->mutex)) { | |
873 | up(&dmxdev->mutex); | |
874 | return -ERESTARTSYS; | |
875 | } | |
876 | if (dmxdevfilter->state<DMXDEV_STATE_SET) | |
877 | ret = -EINVAL; | |
878 | else | |
879 | ret = dvb_dmxdev_filter_start(dmxdevfilter); | |
880 | up(&dmxdevfilter->mutex); | |
881 | break; | |
882 | ||
883 | case DMX_STOP: | |
884 | if (down_interruptible(&dmxdevfilter->mutex)) { | |
885 | up(&dmxdev->mutex); | |
886 | return -ERESTARTSYS; | |
887 | } | |
888 | ret=dvb_dmxdev_filter_stop(dmxdevfilter); | |
889 | up(&dmxdevfilter->mutex); | |
890 | break; | |
891 | ||
892 | case DMX_SET_FILTER: | |
893 | if (down_interruptible(&dmxdevfilter->mutex)) { | |
894 | up(&dmxdev->mutex); | |
895 | return -ERESTARTSYS; | |
896 | } | |
897 | ret = dvb_dmxdev_filter_set(dmxdev, dmxdevfilter, | |
898 | (struct dmx_sct_filter_params *)parg); | |
899 | up(&dmxdevfilter->mutex); | |
900 | break; | |
901 | ||
902 | case DMX_SET_PES_FILTER: | |
903 | if (down_interruptible(&dmxdevfilter->mutex)) { | |
904 | up(&dmxdev->mutex); | |
905 | return -ERESTARTSYS; | |
906 | } | |
907 | ret=dvb_dmxdev_pes_filter_set(dmxdev, dmxdevfilter, | |
908 | (struct dmx_pes_filter_params *)parg); | |
909 | up(&dmxdevfilter->mutex); | |
910 | break; | |
911 | ||
912 | case DMX_SET_BUFFER_SIZE: | |
913 | if (down_interruptible(&dmxdevfilter->mutex)) { | |
914 | up(&dmxdev->mutex); | |
915 | return -ERESTARTSYS; | |
916 | } | |
917 | ret=dvb_dmxdev_set_buffer_size(dmxdevfilter, arg); | |
918 | up(&dmxdevfilter->mutex); | |
919 | break; | |
920 | ||
921 | case DMX_GET_EVENT: | |
922 | break; | |
923 | ||
924 | case DMX_GET_PES_PIDS: | |
925 | if (!dmxdev->demux->get_pes_pids) { | |
926 | ret=-EINVAL; | |
927 | break; | |
928 | } | |
929 | dmxdev->demux->get_pes_pids(dmxdev->demux, (u16 *)parg); | |
930 | break; | |
931 | ||
c0510052 AO |
932 | case DMX_GET_CAPS: |
933 | if (!dmxdev->demux->get_caps) { | |
934 | ret = -EINVAL; | |
935 | break; | |
936 | } | |
937 | ret = dmxdev->demux->get_caps(dmxdev->demux, parg); | |
938 | break; | |
939 | ||
940 | case DMX_SET_SOURCE: | |
941 | if (!dmxdev->demux->set_source) { | |
942 | ret = -EINVAL; | |
943 | break; | |
944 | } | |
945 | ret = dmxdev->demux->set_source(dmxdev->demux, parg); | |
946 | break; | |
947 | ||
1da177e4 LT |
948 | case DMX_GET_STC: |
949 | if (!dmxdev->demux->get_stc) { | |
afd1a0c9 | 950 | ret=-EINVAL; |
1da177e4 LT |
951 | break; |
952 | } | |
953 | ret = dmxdev->demux->get_stc(dmxdev->demux, | |
954 | ((struct dmx_stc *)parg)->num, | |
955 | &((struct dmx_stc *)parg)->stc, | |
956 | &((struct dmx_stc *)parg)->base); | |
957 | break; | |
958 | ||
959 | default: | |
960 | ret=-EINVAL; | |
961 | } | |
962 | up(&dmxdev->mutex); | |
963 | return ret; | |
964 | } | |
965 | ||
966 | static int dvb_demux_ioctl(struct inode *inode, struct file *file, | |
967 | unsigned int cmd, unsigned long arg) | |
968 | { | |
969 | return dvb_usercopy(inode, file, cmd, arg, dvb_demux_do_ioctl); | |
970 | } | |
971 | ||
972 | ||
973 | static unsigned int dvb_demux_poll (struct file *file, poll_table *wait) | |
974 | { | |
3ec4a307 | 975 | struct dmxdev_filter *dmxdevfilter = file->private_data; |
1da177e4 LT |
976 | unsigned int mask = 0; |
977 | ||
978 | if (!dmxdevfilter) | |
979 | return -EINVAL; | |
980 | ||
981 | poll_wait(file, &dmxdevfilter->buffer.queue, wait); | |
982 | ||
983 | if (dmxdevfilter->state != DMXDEV_STATE_GO && | |
984 | dmxdevfilter->state != DMXDEV_STATE_DONE && | |
985 | dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT) | |
986 | return 0; | |
987 | ||
988 | if (dmxdevfilter->buffer.error) | |
989 | mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); | |
990 | ||
991 | if (dmxdevfilter->buffer.pread != dmxdevfilter->buffer.pwrite) | |
992 | mask |= (POLLIN | POLLRDNORM | POLLPRI); | |
993 | ||
994 | return mask; | |
995 | } | |
996 | ||
997 | ||
998 | static int dvb_demux_release(struct inode *inode, struct file *file) | |
999 | { | |
3ec4a307 | 1000 | struct dmxdev_filter *dmxdevfilter = file->private_data; |
1da177e4 LT |
1001 | struct dmxdev *dmxdev = dmxdevfilter->dev; |
1002 | ||
1003 | return dvb_dmxdev_filter_free(dmxdev, dmxdevfilter); | |
1004 | } | |
1005 | ||
1006 | ||
1007 | static struct file_operations dvb_demux_fops = { | |
1008 | .owner = THIS_MODULE, | |
1009 | .read = dvb_demux_read, | |
1010 | .ioctl = dvb_demux_ioctl, | |
1011 | .open = dvb_demux_open, | |
1012 | .release = dvb_demux_release, | |
1013 | .poll = dvb_demux_poll, | |
1014 | }; | |
1015 | ||
1016 | ||
1017 | static struct dvb_device dvbdev_demux = { | |
1018 | .priv = NULL, | |
1019 | .users = 1, | |
1020 | .writers = 1, | |
1021 | .fops = &dvb_demux_fops | |
1022 | }; | |
1023 | ||
1024 | ||
1025 | static int dvb_dvr_do_ioctl(struct inode *inode, struct file *file, | |
1026 | unsigned int cmd, void *parg) | |
1027 | { | |
0c53c70f JS |
1028 | struct dvb_device *dvbdev = file->private_data; |
1029 | struct dmxdev *dmxdev = dvbdev->priv; | |
1da177e4 LT |
1030 | |
1031 | int ret=0; | |
1032 | ||
1033 | if (down_interruptible (&dmxdev->mutex)) | |
1034 | return -ERESTARTSYS; | |
1035 | ||
1036 | switch (cmd) { | |
1037 | case DMX_SET_BUFFER_SIZE: | |
1038 | // FIXME: implement | |
1039 | ret=0; | |
1040 | break; | |
1041 | ||
1042 | default: | |
1043 | ret=-EINVAL; | |
1044 | } | |
1045 | up(&dmxdev->mutex); | |
1046 | return ret; | |
1047 | } | |
1048 | ||
1049 | ||
1050 | static int dvb_dvr_ioctl(struct inode *inode, struct file *file, | |
1051 | unsigned int cmd, unsigned long arg) | |
1052 | { | |
1053 | return dvb_usercopy(inode, file, cmd, arg, dvb_dvr_do_ioctl); | |
1054 | } | |
1055 | ||
1056 | ||
1057 | static unsigned int dvb_dvr_poll (struct file *file, poll_table *wait) | |
1058 | { | |
0c53c70f JS |
1059 | struct dvb_device *dvbdev = file->private_data; |
1060 | struct dmxdev *dmxdev = dvbdev->priv; | |
1da177e4 LT |
1061 | unsigned int mask = 0; |
1062 | ||
1063 | dprintk ("function : %s\n", __FUNCTION__); | |
1064 | ||
1065 | poll_wait(file, &dmxdev->dvr_buffer.queue, wait); | |
1066 | ||
1067 | if ((file->f_flags&O_ACCMODE) == O_RDONLY) { | |
1068 | if (dmxdev->dvr_buffer.error) | |
1069 | mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); | |
1070 | ||
1071 | if (dmxdev->dvr_buffer.pread!=dmxdev->dvr_buffer.pwrite) | |
1072 | mask |= (POLLIN | POLLRDNORM | POLLPRI); | |
1073 | } else | |
1074 | mask |= (POLLOUT | POLLWRNORM | POLLPRI); | |
1075 | ||
1076 | return mask; | |
1077 | } | |
1078 | ||
1079 | ||
1080 | static struct file_operations dvb_dvr_fops = { | |
1081 | .owner = THIS_MODULE, | |
1082 | .read = dvb_dvr_read, | |
1083 | .write = dvb_dvr_write, | |
1084 | .ioctl = dvb_dvr_ioctl, | |
1085 | .open = dvb_dvr_open, | |
1086 | .release = dvb_dvr_release, | |
1087 | .poll = dvb_dvr_poll, | |
1088 | }; | |
1089 | ||
1090 | static struct dvb_device dvbdev_dvr = { | |
1091 | .priv = NULL, | |
1092 | .users = 1, | |
1093 | .writers = 1, | |
1094 | .fops = &dvb_dvr_fops | |
1095 | }; | |
1096 | ||
1097 | int | |
1098 | dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) | |
1099 | { | |
1100 | int i; | |
1101 | ||
1102 | if (dmxdev->demux->open(dmxdev->demux) < 0) | |
1103 | return -EUSERS; | |
1104 | ||
1105 | dmxdev->filter = vmalloc(dmxdev->filternum*sizeof(struct dmxdev_filter)); | |
1106 | if (!dmxdev->filter) | |
1107 | return -ENOMEM; | |
1108 | ||
1109 | dmxdev->dvr = vmalloc(dmxdev->filternum*sizeof(struct dmxdev_dvr)); | |
1110 | if (!dmxdev->dvr) { | |
1111 | vfree(dmxdev->filter); | |
1112 | dmxdev->filter = NULL; | |
1113 | return -ENOMEM; | |
1114 | } | |
1115 | ||
1116 | sema_init(&dmxdev->mutex, 1); | |
1117 | spin_lock_init(&dmxdev->lock); | |
1118 | for (i=0; i<dmxdev->filternum; i++) { | |
1119 | dmxdev->filter[i].dev=dmxdev; | |
1120 | dmxdev->filter[i].buffer.data=NULL; | |
1121 | dvb_dmxdev_filter_state_set(&dmxdev->filter[i], DMXDEV_STATE_FREE); | |
1122 | dmxdev->dvr[i].dev=dmxdev; | |
1123 | dmxdev->dvr[i].buffer.data=NULL; | |
1da177e4 LT |
1124 | dvb_dmxdev_dvr_state_set(&dmxdev->dvr[i], DMXDEV_STATE_FREE); |
1125 | } | |
1126 | ||
1127 | dvb_register_device(dvb_adapter, &dmxdev->dvbdev, &dvbdev_demux, dmxdev, DVB_DEVICE_DEMUX); | |
1128 | dvb_register_device(dvb_adapter, &dmxdev->dvr_dvbdev, &dvbdev_dvr, dmxdev, DVB_DEVICE_DVR); | |
1129 | ||
1130 | dvb_dmxdev_buffer_init(&dmxdev->dvr_buffer); | |
1131 | ||
1132 | return 0; | |
1133 | } | |
1134 | EXPORT_SYMBOL(dvb_dmxdev_init); | |
1135 | ||
1136 | void | |
1137 | dvb_dmxdev_release(struct dmxdev *dmxdev) | |
1138 | { | |
1139 | dvb_unregister_device(dmxdev->dvbdev); | |
1140 | dvb_unregister_device(dmxdev->dvr_dvbdev); | |
1141 | ||
1142 | vfree(dmxdev->filter); | |
1143 | dmxdev->filter=NULL; | |
1144 | vfree(dmxdev->dvr); | |
1145 | dmxdev->dvr=NULL; | |
1146 | dmxdev->demux->close(dmxdev->demux); | |
1147 | } | |
1148 | EXPORT_SYMBOL(dvb_dmxdev_release); |