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