Commit | Line | Data |
---|---|---|
7a7d9a89 MCC |
1 | /* |
2 | * generic helper functions for handling video4linux capture buffers | |
3 | * | |
4 | * (c) 2007 Mauro Carvalho Chehab, <mchehab@infradead.org> | |
5 | * | |
6 | * Highly based on video-buf written originally by: | |
7 | * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> | |
8 | * (c) 2006 Mauro Carvalho Chehab, <mchehab@infradead.org> | |
9 | * (c) 2006 Ted Walther and John Sokol | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or modify | |
12 | * it under the terms of the GNU General Public License as published by | |
13 | * the Free Software Foundation; either version 2 | |
14 | */ | |
15 | ||
16 | #include <linux/init.h> | |
17 | #include <linux/module.h> | |
18 | #include <linux/moduleparam.h> | |
27ac792c | 19 | #include <linux/mm.h> |
d43c36dc | 20 | #include <linux/sched.h> |
7a7d9a89 MCC |
21 | #include <linux/slab.h> |
22 | #include <linux/interrupt.h> | |
23 | ||
24 | #include <media/videobuf-core.h> | |
25 | ||
26 | #define MAGIC_BUFFER 0x20070728 | |
e2c77314 MCC |
27 | #define MAGIC_CHECK(is, should) do { \ |
28 | if (unlikely((is) != (should))) { \ | |
29 | printk(KERN_ERR "magic mismatch: %x (expected %x)\n", is, should); \ | |
30 | BUG(); } } while (0) | |
7a7d9a89 | 31 | |
e2c77314 | 32 | static int debug; |
7a7d9a89 MCC |
33 | module_param(debug, int, 0644); |
34 | ||
35 | MODULE_DESCRIPTION("helper module to manage video4linux buffers"); | |
36 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>"); | |
37 | MODULE_LICENSE("GPL"); | |
38 | ||
e2c77314 MCC |
39 | #define dprintk(level, fmt, arg...) do { \ |
40 | if (debug >= level) \ | |
41 | printk(KERN_DEBUG "vbuf: " fmt , ## arg); } while (0) | |
7a7d9a89 MCC |
42 | |
43 | /* --------------------------------------------------------------------- */ | |
44 | ||
45 | #define CALL(q, f, arg...) \ | |
e2c77314 | 46 | ((q->int_ops->f) ? q->int_ops->f(arg) : 0) |
7a7d9a89 | 47 | |
e2c77314 | 48 | void *videobuf_alloc(struct videobuf_queue *q) |
7a7d9a89 MCC |
49 | { |
50 | struct videobuf_buffer *vb; | |
51 | ||
e2c77314 | 52 | BUG_ON(q->msize < sizeof(*vb)); |
7a7d9a89 MCC |
53 | |
54 | if (!q->int_ops || !q->int_ops->alloc) { | |
55 | printk(KERN_ERR "No specific ops defined!\n"); | |
56 | BUG(); | |
57 | } | |
58 | ||
59 | vb = q->int_ops->alloc(q->msize); | |
60 | ||
61 | if (NULL != vb) { | |
62 | init_waitqueue_head(&vb->done); | |
63 | vb->magic = MAGIC_BUFFER; | |
64 | } | |
65 | ||
66 | return vb; | |
67 | } | |
68 | ||
009a9059 BP |
69 | #define WAITON_CONDITION (vb->state != VIDEOBUF_ACTIVE &&\ |
70 | vb->state != VIDEOBUF_QUEUED) | |
7a7d9a89 MCC |
71 | int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr) |
72 | { | |
e2c77314 | 73 | MAGIC_CHECK(vb->magic, MAGIC_BUFFER); |
009a9059 BP |
74 | |
75 | if (non_blocking) { | |
76 | if (WAITON_CONDITION) | |
77 | return 0; | |
78 | else | |
79 | return -EAGAIN; | |
7a7d9a89 | 80 | } |
009a9059 BP |
81 | |
82 | if (intr) | |
83 | return wait_event_interruptible(vb->done, WAITON_CONDITION); | |
84 | else | |
85 | wait_event(vb->done, WAITON_CONDITION); | |
86 | ||
87 | return 0; | |
7a7d9a89 MCC |
88 | } |
89 | ||
e2c77314 | 90 | int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb, |
7a7d9a89 MCC |
91 | struct v4l2_framebuffer *fbuf) |
92 | { | |
e2c77314 MCC |
93 | MAGIC_CHECK(vb->magic, MAGIC_BUFFER); |
94 | MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); | |
7a7d9a89 | 95 | |
e2c77314 | 96 | return CALL(q, iolock, q, vb, fbuf); |
7a7d9a89 MCC |
97 | } |
98 | ||
59d34489 MCC |
99 | void *videobuf_queue_to_vmalloc (struct videobuf_queue *q, |
100 | struct videobuf_buffer *buf) | |
101 | { | |
a6a3a17b HH |
102 | if (q->int_ops->vmalloc) |
103 | return q->int_ops->vmalloc(buf); | |
104 | else | |
105 | return NULL; | |
59d34489 MCC |
106 | } |
107 | EXPORT_SYMBOL_GPL(videobuf_queue_to_vmalloc); | |
108 | ||
7a7d9a89 MCC |
109 | /* --------------------------------------------------------------------- */ |
110 | ||
111 | ||
e2c77314 | 112 | void videobuf_queue_core_init(struct videobuf_queue *q, |
7a7d9a89 | 113 | struct videobuf_queue_ops *ops, |
e9bcf667 | 114 | struct device *dev, |
7a7d9a89 MCC |
115 | spinlock_t *irqlock, |
116 | enum v4l2_buf_type type, | |
117 | enum v4l2_field field, | |
118 | unsigned int msize, | |
d4cae5a5 MCC |
119 | void *priv, |
120 | struct videobuf_qtype_ops *int_ops) | |
7a7d9a89 | 121 | { |
96ceea27 | 122 | BUG_ON(!q); |
e2c77314 | 123 | memset(q, 0, sizeof(*q)); |
d4cae5a5 MCC |
124 | q->irqlock = irqlock; |
125 | q->dev = dev; | |
126 | q->type = type; | |
127 | q->field = field; | |
128 | q->msize = msize; | |
129 | q->ops = ops; | |
7a7d9a89 | 130 | q->priv_data = priv; |
d4cae5a5 | 131 | q->int_ops = int_ops; |
7a7d9a89 MCC |
132 | |
133 | /* All buffer operations are mandatory */ | |
e2c77314 MCC |
134 | BUG_ON(!q->ops->buf_setup); |
135 | BUG_ON(!q->ops->buf_prepare); | |
136 | BUG_ON(!q->ops->buf_queue); | |
137 | BUG_ON(!q->ops->buf_release); | |
7a7d9a89 | 138 | |
0cf4daee BP |
139 | /* Lock is mandatory for queue_cancel to work */ |
140 | BUG_ON(!irqlock); | |
141 | ||
d4cae5a5 | 142 | /* Having implementations for abstract methods are mandatory */ |
e2c77314 | 143 | BUG_ON(!q->int_ops); |
d4cae5a5 | 144 | |
64f9477f | 145 | mutex_init(&q->vb_lock); |
137d1cb1 | 146 | init_waitqueue_head(&q->wait); |
7a7d9a89 MCC |
147 | INIT_LIST_HEAD(&q->stream); |
148 | } | |
149 | ||
19bc5133 | 150 | /* Locking: Only usage in bttv unsafe find way to remove */ |
7a7d9a89 MCC |
151 | int videobuf_queue_is_busy(struct videobuf_queue *q) |
152 | { | |
153 | int i; | |
154 | ||
e2c77314 | 155 | MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); |
7a7d9a89 MCC |
156 | |
157 | if (q->streaming) { | |
e2c77314 | 158 | dprintk(1, "busy: streaming active\n"); |
7a7d9a89 MCC |
159 | return 1; |
160 | } | |
161 | if (q->reading) { | |
e2c77314 | 162 | dprintk(1, "busy: pending read #1\n"); |
7a7d9a89 MCC |
163 | return 1; |
164 | } | |
165 | if (q->read_buf) { | |
e2c77314 | 166 | dprintk(1, "busy: pending read #2\n"); |
7a7d9a89 MCC |
167 | return 1; |
168 | } | |
169 | for (i = 0; i < VIDEO_MAX_FRAME; i++) { | |
170 | if (NULL == q->bufs[i]) | |
171 | continue; | |
851c0c96 | 172 | if (q->bufs[i]->map) { |
e2c77314 | 173 | dprintk(1, "busy: buffer #%d mapped\n", i); |
7a7d9a89 MCC |
174 | return 1; |
175 | } | |
0fc0686e | 176 | if (q->bufs[i]->state == VIDEOBUF_QUEUED) { |
e2c77314 | 177 | dprintk(1, "busy: buffer #%d queued\n", i); |
7a7d9a89 MCC |
178 | return 1; |
179 | } | |
0fc0686e | 180 | if (q->bufs[i]->state == VIDEOBUF_ACTIVE) { |
e2c77314 | 181 | dprintk(1, "busy: buffer #%d avtive\n", i); |
7a7d9a89 MCC |
182 | return 1; |
183 | } | |
184 | } | |
185 | return 0; | |
186 | } | |
187 | ||
64f9477f | 188 | /* Locking: Caller holds q->vb_lock */ |
7a7d9a89 MCC |
189 | void videobuf_queue_cancel(struct videobuf_queue *q) |
190 | { | |
e2c77314 | 191 | unsigned long flags = 0; |
7a7d9a89 MCC |
192 | int i; |
193 | ||
137d1cb1 BP |
194 | q->streaming = 0; |
195 | q->reading = 0; | |
196 | wake_up_interruptible_sync(&q->wait); | |
197 | ||
7a7d9a89 | 198 | /* remove queued buffers from list */ |
0cf4daee | 199 | spin_lock_irqsave(q->irqlock, flags); |
7a7d9a89 MCC |
200 | for (i = 0; i < VIDEO_MAX_FRAME; i++) { |
201 | if (NULL == q->bufs[i]) | |
202 | continue; | |
0fc0686e | 203 | if (q->bufs[i]->state == VIDEOBUF_QUEUED) { |
7a7d9a89 | 204 | list_del(&q->bufs[i]->queue); |
0fc0686e | 205 | q->bufs[i]->state = VIDEOBUF_ERROR; |
b608f432 | 206 | wake_up_all(&q->bufs[i]->done); |
7a7d9a89 MCC |
207 | } |
208 | } | |
0cf4daee | 209 | spin_unlock_irqrestore(q->irqlock, flags); |
7a7d9a89 MCC |
210 | |
211 | /* free all buffers + clear queue */ | |
212 | for (i = 0; i < VIDEO_MAX_FRAME; i++) { | |
213 | if (NULL == q->bufs[i]) | |
214 | continue; | |
e2c77314 | 215 | q->ops->buf_release(q, q->bufs[i]); |
7a7d9a89 MCC |
216 | } |
217 | INIT_LIST_HEAD(&q->stream); | |
218 | } | |
219 | ||
220 | /* --------------------------------------------------------------------- */ | |
221 | ||
64f9477f | 222 | /* Locking: Caller holds q->vb_lock */ |
7a7d9a89 MCC |
223 | enum v4l2_field videobuf_next_field(struct videobuf_queue *q) |
224 | { | |
225 | enum v4l2_field field = q->field; | |
226 | ||
227 | BUG_ON(V4L2_FIELD_ANY == field); | |
228 | ||
229 | if (V4L2_FIELD_ALTERNATE == field) { | |
230 | if (V4L2_FIELD_TOP == q->last) { | |
231 | field = V4L2_FIELD_BOTTOM; | |
232 | q->last = V4L2_FIELD_BOTTOM; | |
233 | } else { | |
234 | field = V4L2_FIELD_TOP; | |
235 | q->last = V4L2_FIELD_TOP; | |
236 | } | |
237 | } | |
238 | return field; | |
239 | } | |
240 | ||
64f9477f | 241 | /* Locking: Caller holds q->vb_lock */ |
7a7d9a89 MCC |
242 | static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b, |
243 | struct videobuf_buffer *vb, enum v4l2_buf_type type) | |
244 | { | |
e2c77314 MCC |
245 | MAGIC_CHECK(vb->magic, MAGIC_BUFFER); |
246 | MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); | |
7a7d9a89 MCC |
247 | |
248 | b->index = vb->i; | |
249 | b->type = type; | |
250 | ||
251 | b->memory = vb->memory; | |
252 | switch (b->memory) { | |
253 | case V4L2_MEMORY_MMAP: | |
254 | b->m.offset = vb->boff; | |
255 | b->length = vb->bsize; | |
256 | break; | |
257 | case V4L2_MEMORY_USERPTR: | |
258 | b->m.userptr = vb->baddr; | |
259 | b->length = vb->bsize; | |
260 | break; | |
261 | case V4L2_MEMORY_OVERLAY: | |
262 | b->m.offset = vb->boff; | |
263 | break; | |
264 | } | |
265 | ||
266 | b->flags = 0; | |
851c0c96 | 267 | if (vb->map) |
7a7d9a89 MCC |
268 | b->flags |= V4L2_BUF_FLAG_MAPPED; |
269 | ||
270 | switch (vb->state) { | |
0fc0686e BP |
271 | case VIDEOBUF_PREPARED: |
272 | case VIDEOBUF_QUEUED: | |
273 | case VIDEOBUF_ACTIVE: | |
7a7d9a89 MCC |
274 | b->flags |= V4L2_BUF_FLAG_QUEUED; |
275 | break; | |
0fc0686e BP |
276 | case VIDEOBUF_DONE: |
277 | case VIDEOBUF_ERROR: | |
7a7d9a89 MCC |
278 | b->flags |= V4L2_BUF_FLAG_DONE; |
279 | break; | |
0fc0686e BP |
280 | case VIDEOBUF_NEEDS_INIT: |
281 | case VIDEOBUF_IDLE: | |
7a7d9a89 MCC |
282 | /* nothing */ |
283 | break; | |
284 | } | |
285 | ||
286 | if (vb->input != UNSET) { | |
287 | b->flags |= V4L2_BUF_FLAG_INPUT; | |
288 | b->input = vb->input; | |
289 | } | |
290 | ||
291 | b->field = vb->field; | |
292 | b->timestamp = vb->ts; | |
293 | b->bytesused = vb->size; | |
294 | b->sequence = vb->field_count >> 1; | |
295 | } | |
296 | ||
64f9477f | 297 | /* Locking: Caller holds q->vb_lock */ |
19bc5133 BP |
298 | static int __videobuf_mmap_free(struct videobuf_queue *q) |
299 | { | |
300 | int i; | |
301 | int rc; | |
302 | ||
303 | if (!q) | |
304 | return 0; | |
305 | ||
e2c77314 | 306 | MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); |
19bc5133 | 307 | |
d05051c8 | 308 | |
e2c77314 | 309 | rc = CALL(q, mmap_free, q); |
d05051c8 MCC |
310 | |
311 | q->is_mmapped = 0; | |
312 | ||
e2c77314 | 313 | if (rc < 0) |
19bc5133 BP |
314 | return rc; |
315 | ||
316 | for (i = 0; i < VIDEO_MAX_FRAME; i++) { | |
317 | if (NULL == q->bufs[i]) | |
318 | continue; | |
e2c77314 | 319 | q->ops->buf_release(q, q->bufs[i]); |
19bc5133 BP |
320 | kfree(q->bufs[i]); |
321 | q->bufs[i] = NULL; | |
322 | } | |
323 | ||
324 | return rc; | |
325 | } | |
326 | ||
327 | int videobuf_mmap_free(struct videobuf_queue *q) | |
328 | { | |
329 | int ret; | |
64f9477f | 330 | mutex_lock(&q->vb_lock); |
19bc5133 | 331 | ret = __videobuf_mmap_free(q); |
64f9477f | 332 | mutex_unlock(&q->vb_lock); |
19bc5133 BP |
333 | return ret; |
334 | } | |
335 | ||
64f9477f | 336 | /* Locking: Caller holds q->vb_lock */ |
81b2dbca | 337 | int __videobuf_mmap_setup(struct videobuf_queue *q, |
19bc5133 BP |
338 | unsigned int bcount, unsigned int bsize, |
339 | enum v4l2_memory memory) | |
340 | { | |
341 | unsigned int i; | |
342 | int err; | |
343 | ||
e2c77314 | 344 | MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); |
19bc5133 BP |
345 | |
346 | err = __videobuf_mmap_free(q); | |
347 | if (0 != err) | |
348 | return err; | |
349 | ||
350 | /* Allocate and initialize buffers */ | |
351 | for (i = 0; i < bcount; i++) { | |
352 | q->bufs[i] = videobuf_alloc(q); | |
353 | ||
354 | if (q->bufs[i] == NULL) | |
355 | break; | |
356 | ||
357 | q->bufs[i]->i = i; | |
358 | q->bufs[i]->input = UNSET; | |
359 | q->bufs[i]->memory = memory; | |
360 | q->bufs[i]->bsize = bsize; | |
361 | switch (memory) { | |
362 | case V4L2_MEMORY_MMAP: | |
363 | q->bufs[i]->boff = bsize * i; | |
364 | break; | |
365 | case V4L2_MEMORY_USERPTR: | |
366 | case V4L2_MEMORY_OVERLAY: | |
367 | /* nothing */ | |
368 | break; | |
369 | } | |
370 | } | |
371 | ||
372 | if (!i) | |
373 | return -ENOMEM; | |
374 | ||
e2c77314 | 375 | dprintk(1, "mmap setup: %d buffers, %d bytes each\n", |
19bc5133 BP |
376 | i, bsize); |
377 | ||
378 | return i; | |
379 | } | |
380 | ||
381 | int videobuf_mmap_setup(struct videobuf_queue *q, | |
382 | unsigned int bcount, unsigned int bsize, | |
383 | enum v4l2_memory memory) | |
384 | { | |
385 | int ret; | |
64f9477f | 386 | mutex_lock(&q->vb_lock); |
19bc5133 | 387 | ret = __videobuf_mmap_setup(q, bcount, bsize, memory); |
64f9477f | 388 | mutex_unlock(&q->vb_lock); |
19bc5133 BP |
389 | return ret; |
390 | } | |
391 | ||
7a7d9a89 MCC |
392 | int videobuf_reqbufs(struct videobuf_queue *q, |
393 | struct v4l2_requestbuffers *req) | |
394 | { | |
e2c77314 | 395 | unsigned int size, count; |
7a7d9a89 MCC |
396 | int retval; |
397 | ||
7a7d9a89 | 398 | if (req->count < 1) { |
e2c77314 | 399 | dprintk(1, "reqbufs: count invalid (%d)\n", req->count); |
7a7d9a89 MCC |
400 | return -EINVAL; |
401 | } | |
19bc5133 | 402 | |
7a7d9a89 MCC |
403 | if (req->memory != V4L2_MEMORY_MMAP && |
404 | req->memory != V4L2_MEMORY_USERPTR && | |
405 | req->memory != V4L2_MEMORY_OVERLAY) { | |
e2c77314 | 406 | dprintk(1, "reqbufs: memory type invalid\n"); |
7a7d9a89 MCC |
407 | return -EINVAL; |
408 | } | |
409 | ||
64f9477f | 410 | mutex_lock(&q->vb_lock); |
19bc5133 | 411 | if (req->type != q->type) { |
e2c77314 | 412 | dprintk(1, "reqbufs: queue type invalid\n"); |
19bc5133 BP |
413 | retval = -EINVAL; |
414 | goto done; | |
415 | } | |
416 | ||
7a7d9a89 | 417 | if (q->streaming) { |
e2c77314 | 418 | dprintk(1, "reqbufs: streaming already exists\n"); |
00f98d08 BP |
419 | retval = -EBUSY; |
420 | goto done; | |
7a7d9a89 MCC |
421 | } |
422 | if (!list_empty(&q->stream)) { | |
e2c77314 | 423 | dprintk(1, "reqbufs: stream running\n"); |
00f98d08 BP |
424 | retval = -EBUSY; |
425 | goto done; | |
7a7d9a89 MCC |
426 | } |
427 | ||
7a7d9a89 MCC |
428 | count = req->count; |
429 | if (count > VIDEO_MAX_FRAME) | |
430 | count = VIDEO_MAX_FRAME; | |
431 | size = 0; | |
e2c77314 | 432 | q->ops->buf_setup(q, &count, &size); |
7a7d9a89 | 433 | size = PAGE_ALIGN(size); |
e2c77314 | 434 | dprintk(1, "reqbufs: bufs=%d, size=0x%x [%d pages total]\n", |
7a7d9a89 MCC |
435 | count, size, (count*size)>>PAGE_SHIFT); |
436 | ||
e2c77314 | 437 | retval = __videobuf_mmap_setup(q, count, size, req->memory); |
7a7d9a89 | 438 | if (retval < 0) { |
e2c77314 | 439 | dprintk(1, "reqbufs: mmap setup returned %d\n", retval); |
7a7d9a89 MCC |
440 | goto done; |
441 | } | |
442 | ||
49ee718e | 443 | req->count = retval; |
925d74ae | 444 | retval = 0; |
7a7d9a89 MCC |
445 | |
446 | done: | |
64f9477f | 447 | mutex_unlock(&q->vb_lock); |
7a7d9a89 MCC |
448 | return retval; |
449 | } | |
450 | ||
451 | int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b) | |
452 | { | |
19bc5133 BP |
453 | int ret = -EINVAL; |
454 | ||
64f9477f | 455 | mutex_lock(&q->vb_lock); |
7a7d9a89 | 456 | if (unlikely(b->type != q->type)) { |
e2c77314 | 457 | dprintk(1, "querybuf: Wrong type.\n"); |
19bc5133 | 458 | goto done; |
7a7d9a89 | 459 | } |
223ffe5f | 460 | if (unlikely(b->index >= VIDEO_MAX_FRAME)) { |
e2c77314 | 461 | dprintk(1, "querybuf: index out of range.\n"); |
19bc5133 | 462 | goto done; |
7a7d9a89 MCC |
463 | } |
464 | if (unlikely(NULL == q->bufs[b->index])) { | |
e2c77314 | 465 | dprintk(1, "querybuf: buffer is null.\n"); |
19bc5133 | 466 | goto done; |
7a7d9a89 | 467 | } |
19bc5133 | 468 | |
e2c77314 | 469 | videobuf_status(q, b, q->bufs[b->index], q->type); |
19bc5133 BP |
470 | |
471 | ret = 0; | |
472 | done: | |
64f9477f | 473 | mutex_unlock(&q->vb_lock); |
19bc5133 | 474 | return ret; |
7a7d9a89 MCC |
475 | } |
476 | ||
477 | int videobuf_qbuf(struct videobuf_queue *q, | |
478 | struct v4l2_buffer *b) | |
479 | { | |
480 | struct videobuf_buffer *buf; | |
481 | enum v4l2_field field; | |
e2c77314 | 482 | unsigned long flags = 0; |
7a7d9a89 MCC |
483 | int retval; |
484 | ||
e2c77314 | 485 | MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); |
7a7d9a89 | 486 | |
9900132f ML |
487 | if (b->memory == V4L2_MEMORY_MMAP) |
488 | down_read(¤t->mm->mmap_sem); | |
489 | ||
64f9477f | 490 | mutex_lock(&q->vb_lock); |
7a7d9a89 MCC |
491 | retval = -EBUSY; |
492 | if (q->reading) { | |
e2c77314 | 493 | dprintk(1, "qbuf: Reading running...\n"); |
7a7d9a89 MCC |
494 | goto done; |
495 | } | |
496 | retval = -EINVAL; | |
497 | if (b->type != q->type) { | |
e2c77314 | 498 | dprintk(1, "qbuf: Wrong type.\n"); |
7a7d9a89 MCC |
499 | goto done; |
500 | } | |
223ffe5f | 501 | if (b->index >= VIDEO_MAX_FRAME) { |
e2c77314 | 502 | dprintk(1, "qbuf: index out of range.\n"); |
7a7d9a89 MCC |
503 | goto done; |
504 | } | |
505 | buf = q->bufs[b->index]; | |
506 | if (NULL == buf) { | |
e2c77314 | 507 | dprintk(1, "qbuf: buffer is null.\n"); |
7a7d9a89 MCC |
508 | goto done; |
509 | } | |
e2c77314 | 510 | MAGIC_CHECK(buf->magic, MAGIC_BUFFER); |
7a7d9a89 | 511 | if (buf->memory != b->memory) { |
e2c77314 | 512 | dprintk(1, "qbuf: memory type is wrong.\n"); |
7a7d9a89 MCC |
513 | goto done; |
514 | } | |
0fc0686e | 515 | if (buf->state != VIDEOBUF_NEEDS_INIT && buf->state != VIDEOBUF_IDLE) { |
e2c77314 | 516 | dprintk(1, "qbuf: buffer is already queued or active.\n"); |
7a7d9a89 MCC |
517 | goto done; |
518 | } | |
519 | ||
520 | if (b->flags & V4L2_BUF_FLAG_INPUT) { | |
521 | if (b->input >= q->inputs) { | |
e2c77314 | 522 | dprintk(1, "qbuf: wrong input.\n"); |
7a7d9a89 MCC |
523 | goto done; |
524 | } | |
525 | buf->input = b->input; | |
526 | } else { | |
527 | buf->input = UNSET; | |
528 | } | |
529 | ||
530 | switch (b->memory) { | |
531 | case V4L2_MEMORY_MMAP: | |
532 | if (0 == buf->baddr) { | |
e2c77314 MCC |
533 | dprintk(1, "qbuf: mmap requested " |
534 | "but buffer addr is zero!\n"); | |
7a7d9a89 MCC |
535 | goto done; |
536 | } | |
537 | break; | |
538 | case V4L2_MEMORY_USERPTR: | |
539 | if (b->length < buf->bsize) { | |
e2c77314 | 540 | dprintk(1, "qbuf: buffer length is not enough\n"); |
7a7d9a89 MCC |
541 | goto done; |
542 | } | |
e2c77314 MCC |
543 | if (VIDEOBUF_NEEDS_INIT != buf->state && |
544 | buf->baddr != b->m.userptr) | |
545 | q->ops->buf_release(q, buf); | |
7a7d9a89 MCC |
546 | buf->baddr = b->m.userptr; |
547 | break; | |
548 | case V4L2_MEMORY_OVERLAY: | |
549 | buf->boff = b->m.offset; | |
550 | break; | |
551 | default: | |
e2c77314 | 552 | dprintk(1, "qbuf: wrong memory type\n"); |
7a7d9a89 MCC |
553 | goto done; |
554 | } | |
555 | ||
e2c77314 | 556 | dprintk(1, "qbuf: requesting next field\n"); |
7a7d9a89 | 557 | field = videobuf_next_field(q); |
e2c77314 | 558 | retval = q->ops->buf_prepare(q, buf, field); |
7a7d9a89 | 559 | if (0 != retval) { |
e2c77314 | 560 | dprintk(1, "qbuf: buffer_prepare returned %d\n", retval); |
7a7d9a89 MCC |
561 | goto done; |
562 | } | |
563 | ||
e2c77314 | 564 | list_add_tail(&buf->stream, &q->stream); |
7a7d9a89 | 565 | if (q->streaming) { |
0cf4daee | 566 | spin_lock_irqsave(q->irqlock, flags); |
e2c77314 | 567 | q->ops->buf_queue(q, buf); |
0cf4daee | 568 | spin_unlock_irqrestore(q->irqlock, flags); |
7a7d9a89 | 569 | } |
e2c77314 | 570 | dprintk(1, "qbuf: succeded\n"); |
7a7d9a89 | 571 | retval = 0; |
137d1cb1 | 572 | wake_up_interruptible_sync(&q->wait); |
7a7d9a89 MCC |
573 | |
574 | done: | |
64f9477f | 575 | mutex_unlock(&q->vb_lock); |
9900132f ML |
576 | |
577 | if (b->memory == V4L2_MEMORY_MMAP) | |
578 | up_read(¤t->mm->mmap_sem); | |
579 | ||
7a7d9a89 MCC |
580 | return retval; |
581 | } | |
582 | ||
137d1cb1 BP |
583 | |
584 | /* Locking: Caller holds q->vb_lock */ | |
585 | static int stream_next_buffer_check_queue(struct videobuf_queue *q, int noblock) | |
7a7d9a89 | 586 | { |
7a7d9a89 MCC |
587 | int retval; |
588 | ||
137d1cb1 BP |
589 | checks: |
590 | if (!q->streaming) { | |
591 | dprintk(1, "next_buffer: Not streaming\n"); | |
592 | retval = -EINVAL; | |
7a7d9a89 MCC |
593 | goto done; |
594 | } | |
137d1cb1 | 595 | |
7a7d9a89 | 596 | if (list_empty(&q->stream)) { |
137d1cb1 BP |
597 | if (noblock) { |
598 | retval = -EAGAIN; | |
599 | dprintk(2, "next_buffer: no buffers to dequeue\n"); | |
600 | goto done; | |
601 | } else { | |
602 | dprintk(2, "next_buffer: waiting on buffer\n"); | |
603 | ||
604 | /* Drop lock to avoid deadlock with qbuf */ | |
605 | mutex_unlock(&q->vb_lock); | |
606 | ||
607 | /* Checking list_empty and streaming is safe without | |
608 | * locks because we goto checks to validate while | |
609 | * holding locks before proceeding */ | |
610 | retval = wait_event_interruptible(q->wait, | |
611 | !list_empty(&q->stream) || !q->streaming); | |
612 | mutex_lock(&q->vb_lock); | |
613 | ||
614 | if (retval) | |
615 | goto done; | |
616 | ||
617 | goto checks; | |
618 | } | |
7a7d9a89 | 619 | } |
137d1cb1 BP |
620 | |
621 | retval = 0; | |
622 | ||
623 | done: | |
624 | return retval; | |
625 | } | |
626 | ||
627 | ||
628 | /* Locking: Caller holds q->vb_lock */ | |
629 | static int stream_next_buffer(struct videobuf_queue *q, | |
630 | struct videobuf_buffer **vb, int nonblocking) | |
631 | { | |
632 | int retval; | |
633 | struct videobuf_buffer *buf = NULL; | |
634 | ||
635 | retval = stream_next_buffer_check_queue(q, nonblocking); | |
636 | if (retval) | |
637 | goto done; | |
638 | ||
7a7d9a89 MCC |
639 | buf = list_entry(q->stream.next, struct videobuf_buffer, stream); |
640 | retval = videobuf_waiton(buf, nonblocking, 1); | |
137d1cb1 BP |
641 | if (retval < 0) |
642 | goto done; | |
643 | ||
644 | *vb = buf; | |
645 | done: | |
646 | return retval; | |
647 | } | |
648 | ||
649 | int videobuf_dqbuf(struct videobuf_queue *q, | |
650 | struct v4l2_buffer *b, int nonblocking) | |
651 | { | |
652 | struct videobuf_buffer *buf = NULL; | |
653 | int retval; | |
654 | ||
655 | MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); | |
656 | ||
e43d76b4 | 657 | mutex_lock(&q->vb_lock); |
137d1cb1 BP |
658 | |
659 | retval = stream_next_buffer(q, &buf, nonblocking); | |
7a7d9a89 | 660 | if (retval < 0) { |
137d1cb1 | 661 | dprintk(1, "dqbuf: next_buffer error: %i\n", retval); |
7a7d9a89 MCC |
662 | goto done; |
663 | } | |
137d1cb1 | 664 | |
7a7d9a89 | 665 | switch (buf->state) { |
0fc0686e | 666 | case VIDEOBUF_ERROR: |
e2c77314 | 667 | dprintk(1, "dqbuf: state is error\n"); |
7a7d9a89 | 668 | retval = -EIO; |
e2c77314 | 669 | CALL(q, sync, q, buf); |
0fc0686e | 670 | buf->state = VIDEOBUF_IDLE; |
7a7d9a89 | 671 | break; |
0fc0686e | 672 | case VIDEOBUF_DONE: |
e2c77314 MCC |
673 | dprintk(1, "dqbuf: state is done\n"); |
674 | CALL(q, sync, q, buf); | |
0fc0686e | 675 | buf->state = VIDEOBUF_IDLE; |
7a7d9a89 MCC |
676 | break; |
677 | default: | |
e2c77314 | 678 | dprintk(1, "dqbuf: state invalid\n"); |
7a7d9a89 MCC |
679 | retval = -EINVAL; |
680 | goto done; | |
681 | } | |
682 | list_del(&buf->stream); | |
e2c77314 MCC |
683 | memset(b, 0, sizeof(*b)); |
684 | videobuf_status(q, b, buf, q->type); | |
7a7d9a89 MCC |
685 | |
686 | done: | |
64f9477f | 687 | mutex_unlock(&q->vb_lock); |
7a7d9a89 MCC |
688 | return retval; |
689 | } | |
690 | ||
691 | int videobuf_streamon(struct videobuf_queue *q) | |
692 | { | |
693 | struct videobuf_buffer *buf; | |
e2c77314 | 694 | unsigned long flags = 0; |
7a7d9a89 MCC |
695 | int retval; |
696 | ||
64f9477f | 697 | mutex_lock(&q->vb_lock); |
7a7d9a89 MCC |
698 | retval = -EBUSY; |
699 | if (q->reading) | |
700 | goto done; | |
701 | retval = 0; | |
702 | if (q->streaming) | |
703 | goto done; | |
704 | q->streaming = 1; | |
0cf4daee | 705 | spin_lock_irqsave(q->irqlock, flags); |
a991f44b | 706 | list_for_each_entry(buf, &q->stream, stream) |
0fc0686e | 707 | if (buf->state == VIDEOBUF_PREPARED) |
e2c77314 | 708 | q->ops->buf_queue(q, buf); |
0cf4daee | 709 | spin_unlock_irqrestore(q->irqlock, flags); |
7a7d9a89 | 710 | |
137d1cb1 | 711 | wake_up_interruptible_sync(&q->wait); |
7a7d9a89 | 712 | done: |
64f9477f | 713 | mutex_unlock(&q->vb_lock); |
7a7d9a89 MCC |
714 | return retval; |
715 | } | |
716 | ||
64f9477f | 717 | /* Locking: Caller holds q->vb_lock */ |
19bc5133 | 718 | static int __videobuf_streamoff(struct videobuf_queue *q) |
7a7d9a89 | 719 | { |
7a7d9a89 | 720 | if (!q->streaming) |
19bc5133 BP |
721 | return -EINVAL; |
722 | ||
7a7d9a89 | 723 | videobuf_queue_cancel(q); |
7a7d9a89 | 724 | |
19bc5133 BP |
725 | return 0; |
726 | } | |
727 | ||
728 | int videobuf_streamoff(struct videobuf_queue *q) | |
729 | { | |
730 | int retval; | |
731 | ||
64f9477f | 732 | mutex_lock(&q->vb_lock); |
19bc5133 | 733 | retval = __videobuf_streamoff(q); |
64f9477f | 734 | mutex_unlock(&q->vb_lock); |
19bc5133 | 735 | |
7a7d9a89 MCC |
736 | return retval; |
737 | } | |
738 | ||
64f9477f | 739 | /* Locking: Caller holds q->vb_lock */ |
7a7d9a89 MCC |
740 | static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q, |
741 | char __user *data, | |
742 | size_t count, loff_t *ppos) | |
743 | { | |
744 | enum v4l2_field field; | |
e2c77314 | 745 | unsigned long flags = 0; |
7a7d9a89 MCC |
746 | int retval; |
747 | ||
e2c77314 | 748 | MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); |
7a7d9a89 MCC |
749 | |
750 | /* setup stuff */ | |
751 | q->read_buf = videobuf_alloc(q); | |
752 | if (NULL == q->read_buf) | |
753 | return -ENOMEM; | |
754 | ||
755 | q->read_buf->memory = V4L2_MEMORY_USERPTR; | |
756 | q->read_buf->baddr = (unsigned long)data; | |
757 | q->read_buf->bsize = count; | |
758 | ||
759 | field = videobuf_next_field(q); | |
e2c77314 | 760 | retval = q->ops->buf_prepare(q, q->read_buf, field); |
7a7d9a89 MCC |
761 | if (0 != retval) |
762 | goto done; | |
763 | ||
764 | /* start capture & wait */ | |
0cf4daee | 765 | spin_lock_irqsave(q->irqlock, flags); |
e2c77314 | 766 | q->ops->buf_queue(q, q->read_buf); |
0cf4daee | 767 | spin_unlock_irqrestore(q->irqlock, flags); |
e2c77314 | 768 | retval = videobuf_waiton(q->read_buf, 0, 0); |
7a7d9a89 | 769 | if (0 == retval) { |
e2c77314 | 770 | CALL(q, sync, q, q->read_buf); |
0fc0686e | 771 | if (VIDEOBUF_ERROR == q->read_buf->state) |
7a7d9a89 MCC |
772 | retval = -EIO; |
773 | else | |
774 | retval = q->read_buf->size; | |
775 | } | |
776 | ||
777 | done: | |
778 | /* cleanup */ | |
e2c77314 | 779 | q->ops->buf_release(q, q->read_buf); |
7a7d9a89 MCC |
780 | kfree(q->read_buf); |
781 | q->read_buf = NULL; | |
782 | return retval; | |
783 | } | |
784 | ||
785 | ssize_t videobuf_read_one(struct videobuf_queue *q, | |
786 | char __user *data, size_t count, loff_t *ppos, | |
787 | int nonblocking) | |
788 | { | |
789 | enum v4l2_field field; | |
e2c77314 | 790 | unsigned long flags = 0; |
7daa4a88 | 791 | unsigned size = 0, nbufs = 1; |
7a7d9a89 MCC |
792 | int retval; |
793 | ||
e2c77314 | 794 | MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); |
7a7d9a89 | 795 | |
64f9477f | 796 | mutex_lock(&q->vb_lock); |
7a7d9a89 | 797 | |
e2c77314 | 798 | q->ops->buf_setup(q, &nbufs, &size); |
7a7d9a89 MCC |
799 | |
800 | if (NULL == q->read_buf && | |
801 | count >= size && | |
802 | !nonblocking) { | |
e2c77314 | 803 | retval = videobuf_read_zerocopy(q, data, count, ppos); |
7a7d9a89 MCC |
804 | if (retval >= 0 || retval == -EIO) |
805 | /* ok, all done */ | |
806 | goto done; | |
807 | /* fallback to kernel bounce buffer on failures */ | |
808 | } | |
809 | ||
810 | if (NULL == q->read_buf) { | |
811 | /* need to capture a new frame */ | |
812 | retval = -ENOMEM; | |
813 | q->read_buf = videobuf_alloc(q); | |
814 | ||
e2c77314 | 815 | dprintk(1, "video alloc=0x%p\n", q->read_buf); |
7a7d9a89 MCC |
816 | if (NULL == q->read_buf) |
817 | goto done; | |
818 | q->read_buf->memory = V4L2_MEMORY_USERPTR; | |
819 | q->read_buf->bsize = count; /* preferred size */ | |
820 | field = videobuf_next_field(q); | |
e2c77314 | 821 | retval = q->ops->buf_prepare(q, q->read_buf, field); |
7a7d9a89 MCC |
822 | |
823 | if (0 != retval) { | |
e2c77314 | 824 | kfree(q->read_buf); |
7a7d9a89 MCC |
825 | q->read_buf = NULL; |
826 | goto done; | |
827 | } | |
7a7d9a89 | 828 | |
0cf4daee | 829 | spin_lock_irqsave(q->irqlock, flags); |
e2c77314 | 830 | q->ops->buf_queue(q, q->read_buf); |
0cf4daee BP |
831 | spin_unlock_irqrestore(q->irqlock, flags); |
832 | ||
7a7d9a89 MCC |
833 | q->read_off = 0; |
834 | } | |
835 | ||
836 | /* wait until capture is done */ | |
837 | retval = videobuf_waiton(q->read_buf, nonblocking, 1); | |
838 | if (0 != retval) | |
839 | goto done; | |
840 | ||
e2c77314 | 841 | CALL(q, sync, q, q->read_buf); |
7a7d9a89 | 842 | |
0fc0686e | 843 | if (VIDEOBUF_ERROR == q->read_buf->state) { |
7a7d9a89 | 844 | /* catch I/O errors */ |
e2c77314 | 845 | q->ops->buf_release(q, q->read_buf); |
7a7d9a89 MCC |
846 | kfree(q->read_buf); |
847 | q->read_buf = NULL; | |
848 | retval = -EIO; | |
849 | goto done; | |
850 | } | |
851 | ||
852 | /* Copy to userspace */ | |
e2c77314 MCC |
853 | retval = CALL(q, video_copy_to_user, q, data, count, nonblocking); |
854 | if (retval < 0) | |
7a7d9a89 MCC |
855 | goto done; |
856 | ||
857 | q->read_off += retval; | |
858 | if (q->read_off == q->read_buf->size) { | |
859 | /* all data copied, cleanup */ | |
e2c77314 | 860 | q->ops->buf_release(q, q->read_buf); |
7a7d9a89 MCC |
861 | kfree(q->read_buf); |
862 | q->read_buf = NULL; | |
863 | } | |
864 | ||
865 | done: | |
64f9477f | 866 | mutex_unlock(&q->vb_lock); |
7a7d9a89 MCC |
867 | return retval; |
868 | } | |
869 | ||
64f9477f | 870 | /* Locking: Caller holds q->vb_lock */ |
225ba900 | 871 | static int __videobuf_read_start(struct videobuf_queue *q) |
7a7d9a89 MCC |
872 | { |
873 | enum v4l2_field field; | |
e2c77314 | 874 | unsigned long flags = 0; |
49ee718e | 875 | unsigned int count = 0, size = 0; |
7a7d9a89 MCC |
876 | int err, i; |
877 | ||
e2c77314 | 878 | q->ops->buf_setup(q, &count, &size); |
7a7d9a89 MCC |
879 | if (count < 2) |
880 | count = 2; | |
881 | if (count > VIDEO_MAX_FRAME) | |
882 | count = VIDEO_MAX_FRAME; | |
883 | size = PAGE_ALIGN(size); | |
884 | ||
19bc5133 | 885 | err = __videobuf_mmap_setup(q, count, size, V4L2_MEMORY_USERPTR); |
49ee718e | 886 | if (err < 0) |
7a7d9a89 MCC |
887 | return err; |
888 | ||
49ee718e BP |
889 | count = err; |
890 | ||
7a7d9a89 MCC |
891 | for (i = 0; i < count; i++) { |
892 | field = videobuf_next_field(q); | |
e2c77314 | 893 | err = q->ops->buf_prepare(q, q->bufs[i], field); |
7a7d9a89 MCC |
894 | if (err) |
895 | return err; | |
896 | list_add_tail(&q->bufs[i]->stream, &q->stream); | |
897 | } | |
0cf4daee | 898 | spin_lock_irqsave(q->irqlock, flags); |
7a7d9a89 | 899 | for (i = 0; i < count; i++) |
e2c77314 | 900 | q->ops->buf_queue(q, q->bufs[i]); |
0cf4daee | 901 | spin_unlock_irqrestore(q->irqlock, flags); |
7a7d9a89 MCC |
902 | q->reading = 1; |
903 | return 0; | |
904 | } | |
905 | ||
19bc5133 | 906 | static void __videobuf_read_stop(struct videobuf_queue *q) |
7a7d9a89 MCC |
907 | { |
908 | int i; | |
909 | ||
910 | videobuf_queue_cancel(q); | |
19bc5133 | 911 | __videobuf_mmap_free(q); |
7a7d9a89 MCC |
912 | INIT_LIST_HEAD(&q->stream); |
913 | for (i = 0; i < VIDEO_MAX_FRAME; i++) { | |
914 | if (NULL == q->bufs[i]) | |
915 | continue; | |
916 | kfree(q->bufs[i]); | |
917 | q->bufs[i] = NULL; | |
918 | } | |
919 | q->read_buf = NULL; | |
e2c77314 | 920 | |
19bc5133 BP |
921 | } |
922 | ||
19fb1457 MCC |
923 | int videobuf_read_start(struct videobuf_queue *q) |
924 | { | |
925 | int rc; | |
926 | ||
64f9477f | 927 | mutex_lock(&q->vb_lock); |
19fb1457 | 928 | rc = __videobuf_read_start(q); |
64f9477f | 929 | mutex_unlock(&q->vb_lock); |
19fb1457 MCC |
930 | |
931 | return rc; | |
932 | } | |
933 | ||
19bc5133 BP |
934 | void videobuf_read_stop(struct videobuf_queue *q) |
935 | { | |
64f9477f | 936 | mutex_lock(&q->vb_lock); |
19bc5133 | 937 | __videobuf_read_stop(q); |
64f9477f | 938 | mutex_unlock(&q->vb_lock); |
19bc5133 BP |
939 | } |
940 | ||
941 | void videobuf_stop(struct videobuf_queue *q) | |
942 | { | |
64f9477f | 943 | mutex_lock(&q->vb_lock); |
19bc5133 BP |
944 | |
945 | if (q->streaming) | |
946 | __videobuf_streamoff(q); | |
947 | ||
948 | if (q->reading) | |
949 | __videobuf_read_stop(q); | |
950 | ||
64f9477f | 951 | mutex_unlock(&q->vb_lock); |
7a7d9a89 MCC |
952 | } |
953 | ||
19bc5133 | 954 | |
7a7d9a89 MCC |
955 | ssize_t videobuf_read_stream(struct videobuf_queue *q, |
956 | char __user *data, size_t count, loff_t *ppos, | |
957 | int vbihack, int nonblocking) | |
958 | { | |
959 | int rc, retval; | |
e2c77314 | 960 | unsigned long flags = 0; |
7a7d9a89 | 961 | |
e2c77314 | 962 | MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); |
7a7d9a89 | 963 | |
7e28adb2 | 964 | dprintk(2, "%s\n", __func__); |
64f9477f | 965 | mutex_lock(&q->vb_lock); |
7a7d9a89 MCC |
966 | retval = -EBUSY; |
967 | if (q->streaming) | |
968 | goto done; | |
969 | if (!q->reading) { | |
3f84307a | 970 | retval = __videobuf_read_start(q); |
7a7d9a89 MCC |
971 | if (retval < 0) |
972 | goto done; | |
973 | } | |
974 | ||
975 | retval = 0; | |
976 | while (count > 0) { | |
977 | /* get / wait for data */ | |
978 | if (NULL == q->read_buf) { | |
979 | q->read_buf = list_entry(q->stream.next, | |
980 | struct videobuf_buffer, | |
981 | stream); | |
982 | list_del(&q->read_buf->stream); | |
983 | q->read_off = 0; | |
984 | } | |
985 | rc = videobuf_waiton(q->read_buf, nonblocking, 1); | |
986 | if (rc < 0) { | |
987 | if (0 == retval) | |
988 | retval = rc; | |
989 | break; | |
990 | } | |
991 | ||
0fc0686e | 992 | if (q->read_buf->state == VIDEOBUF_DONE) { |
e2c77314 | 993 | rc = CALL(q, copy_stream, q, data + retval, count, |
7a7d9a89 MCC |
994 | retval, vbihack, nonblocking); |
995 | if (rc < 0) { | |
996 | retval = rc; | |
997 | break; | |
998 | } | |
999 | retval += rc; | |
1000 | count -= rc; | |
1001 | q->read_off += rc; | |
1002 | } else { | |
1003 | /* some error */ | |
1004 | q->read_off = q->read_buf->size; | |
1005 | if (0 == retval) | |
1006 | retval = -EIO; | |
1007 | } | |
1008 | ||
1009 | /* requeue buffer when done with copying */ | |
1010 | if (q->read_off == q->read_buf->size) { | |
1011 | list_add_tail(&q->read_buf->stream, | |
1012 | &q->stream); | |
0cf4daee | 1013 | spin_lock_irqsave(q->irqlock, flags); |
e2c77314 | 1014 | q->ops->buf_queue(q, q->read_buf); |
0cf4daee | 1015 | spin_unlock_irqrestore(q->irqlock, flags); |
7a7d9a89 MCC |
1016 | q->read_buf = NULL; |
1017 | } | |
1018 | if (retval < 0) | |
1019 | break; | |
1020 | } | |
1021 | ||
1022 | done: | |
64f9477f | 1023 | mutex_unlock(&q->vb_lock); |
7a7d9a89 MCC |
1024 | return retval; |
1025 | } | |
1026 | ||
1027 | unsigned int videobuf_poll_stream(struct file *file, | |
1028 | struct videobuf_queue *q, | |
1029 | poll_table *wait) | |
1030 | { | |
1031 | struct videobuf_buffer *buf = NULL; | |
1032 | unsigned int rc = 0; | |
1033 | ||
64f9477f | 1034 | mutex_lock(&q->vb_lock); |
7a7d9a89 MCC |
1035 | if (q->streaming) { |
1036 | if (!list_empty(&q->stream)) | |
1037 | buf = list_entry(q->stream.next, | |
1038 | struct videobuf_buffer, stream); | |
1039 | } else { | |
1040 | if (!q->reading) | |
3f84307a | 1041 | __videobuf_read_start(q); |
7a7d9a89 MCC |
1042 | if (!q->reading) { |
1043 | rc = POLLERR; | |
1044 | } else if (NULL == q->read_buf) { | |
1045 | q->read_buf = list_entry(q->stream.next, | |
1046 | struct videobuf_buffer, | |
1047 | stream); | |
1048 | list_del(&q->read_buf->stream); | |
1049 | q->read_off = 0; | |
1050 | } | |
1051 | buf = q->read_buf; | |
1052 | } | |
1053 | if (!buf) | |
1054 | rc = POLLERR; | |
1055 | ||
1056 | if (0 == rc) { | |
1057 | poll_wait(file, &buf->done, wait); | |
0fc0686e BP |
1058 | if (buf->state == VIDEOBUF_DONE || |
1059 | buf->state == VIDEOBUF_ERROR) | |
7a7d9a89 MCC |
1060 | rc = POLLIN|POLLRDNORM; |
1061 | } | |
64f9477f | 1062 | mutex_unlock(&q->vb_lock); |
7a7d9a89 MCC |
1063 | return rc; |
1064 | } | |
1065 | ||
7a7d9a89 MCC |
1066 | int videobuf_mmap_mapper(struct videobuf_queue *q, |
1067 | struct vm_area_struct *vma) | |
1068 | { | |
1069 | int retval; | |
1070 | ||
e2c77314 | 1071 | MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); |
7a7d9a89 | 1072 | |
64f9477f | 1073 | mutex_lock(&q->vb_lock); |
e2c77314 | 1074 | retval = CALL(q, mmap_mapper, q, vma); |
d05051c8 | 1075 | q->is_mmapped = 1; |
64f9477f | 1076 | mutex_unlock(&q->vb_lock); |
7a7d9a89 MCC |
1077 | |
1078 | return retval; | |
1079 | } | |
1080 | ||
1081 | #ifdef CONFIG_VIDEO_V4L1_COMPAT | |
1082 | int videobuf_cgmbuf(struct videobuf_queue *q, | |
1083 | struct video_mbuf *mbuf, int count) | |
1084 | { | |
1085 | struct v4l2_requestbuffers req; | |
e2c77314 | 1086 | int rc, i; |
7a7d9a89 | 1087 | |
e2c77314 | 1088 | MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS); |
7a7d9a89 | 1089 | |
e2c77314 | 1090 | memset(&req, 0, sizeof(req)); |
7a7d9a89 MCC |
1091 | req.type = q->type; |
1092 | req.count = count; | |
1093 | req.memory = V4L2_MEMORY_MMAP; | |
e2c77314 | 1094 | rc = videobuf_reqbufs(q, &req); |
7a7d9a89 MCC |
1095 | if (rc < 0) |
1096 | return rc; | |
1097 | ||
1098 | mbuf->frames = req.count; | |
1099 | mbuf->size = 0; | |
1100 | for (i = 0; i < mbuf->frames; i++) { | |
1101 | mbuf->offsets[i] = q->bufs[i]->boff; | |
1102 | mbuf->size += q->bufs[i]->bsize; | |
1103 | } | |
1104 | ||
1105 | return 0; | |
1106 | } | |
a13625c5 | 1107 | EXPORT_SYMBOL_GPL(videobuf_cgmbuf); |
7a7d9a89 MCC |
1108 | #endif |
1109 | ||
1110 | /* --------------------------------------------------------------------- */ | |
1111 | ||
1112 | EXPORT_SYMBOL_GPL(videobuf_waiton); | |
1113 | EXPORT_SYMBOL_GPL(videobuf_iolock); | |
1114 | ||
1115 | EXPORT_SYMBOL_GPL(videobuf_alloc); | |
1116 | ||
d4cae5a5 | 1117 | EXPORT_SYMBOL_GPL(videobuf_queue_core_init); |
7a7d9a89 MCC |
1118 | EXPORT_SYMBOL_GPL(videobuf_queue_cancel); |
1119 | EXPORT_SYMBOL_GPL(videobuf_queue_is_busy); | |
1120 | ||
1121 | EXPORT_SYMBOL_GPL(videobuf_next_field); | |
1122 | EXPORT_SYMBOL_GPL(videobuf_reqbufs); | |
1123 | EXPORT_SYMBOL_GPL(videobuf_querybuf); | |
1124 | EXPORT_SYMBOL_GPL(videobuf_qbuf); | |
1125 | EXPORT_SYMBOL_GPL(videobuf_dqbuf); | |
7a7d9a89 MCC |
1126 | EXPORT_SYMBOL_GPL(videobuf_streamon); |
1127 | EXPORT_SYMBOL_GPL(videobuf_streamoff); | |
1128 | ||
19fb1457 | 1129 | EXPORT_SYMBOL_GPL(videobuf_read_start); |
7a7d9a89 | 1130 | EXPORT_SYMBOL_GPL(videobuf_read_stop); |
19bc5133 | 1131 | EXPORT_SYMBOL_GPL(videobuf_stop); |
7a7d9a89 MCC |
1132 | EXPORT_SYMBOL_GPL(videobuf_read_stream); |
1133 | EXPORT_SYMBOL_GPL(videobuf_read_one); | |
1134 | EXPORT_SYMBOL_GPL(videobuf_poll_stream); | |
1135 | ||
81b2dbca | 1136 | EXPORT_SYMBOL_GPL(__videobuf_mmap_setup); |
7a7d9a89 MCC |
1137 | EXPORT_SYMBOL_GPL(videobuf_mmap_setup); |
1138 | EXPORT_SYMBOL_GPL(videobuf_mmap_free); | |
1139 | EXPORT_SYMBOL_GPL(videobuf_mmap_mapper); |