diff options
author | Brandon Philips <brandon@ifup.org> | 2008-04-02 17:10:59 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@infradead.org> | 2008-04-24 13:07:57 -0400 |
commit | 78718e5d44cd450431d5b16ee36d3a7de1db6dfa (patch) | |
tree | 6f229f1abbd2655433d22f6d054fda4515d4a8da /drivers/media/video/vivi.c | |
parent | aa9dbac426d263b5b86d1684993d18ae187d7588 (diff) |
V4L/DVB (7492): vivi: Simplify the vivi driver and avoid deadlocks
vivi previously had a very complex queuing system and held spinlocks while
doing copy_to_user, kmalloc, etc. This caused the driver to easily deadlock
when a multi-threaded application used it and revealed bugs in videobuf too.
This replaces the copy_to_user with memcpy since we were never copying to user
space addresses. And makes the kmalloc atomic.
Signed-off-by: Brandon Philips <bphilips@suse.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/vivi.c')
-rw-r--r-- | drivers/media/video/vivi.c | 313 |
1 files changed, 81 insertions, 232 deletions
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c index 02a232768e3b..8353deb8a1d4 100644 --- a/drivers/media/video/vivi.c +++ b/drivers/media/video/vivi.c | |||
@@ -146,8 +146,6 @@ struct vivi_buffer { | |||
146 | 146 | ||
147 | struct vivi_dmaqueue { | 147 | struct vivi_dmaqueue { |
148 | struct list_head active; | 148 | struct list_head active; |
149 | struct list_head queued; | ||
150 | struct timer_list timeout; | ||
151 | 149 | ||
152 | /* thread for generating video stream*/ | 150 | /* thread for generating video stream*/ |
153 | struct task_struct *kthread; | 151 | struct task_struct *kthread; |
@@ -162,7 +160,6 @@ static LIST_HEAD(vivi_devlist); | |||
162 | struct vivi_dev { | 160 | struct vivi_dev { |
163 | struct list_head vivi_devlist; | 161 | struct list_head vivi_devlist; |
164 | 162 | ||
165 | struct mutex lock; | ||
166 | spinlock_t slock; | 163 | spinlock_t slock; |
167 | struct mutex mutex; | 164 | struct mutex mutex; |
168 | 165 | ||
@@ -323,24 +320,26 @@ static void gen_line(char *basep, int inipos, int wmax, | |||
323 | end: | 320 | end: |
324 | return; | 321 | return; |
325 | } | 322 | } |
323 | |||
326 | static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) | 324 | static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) |
327 | { | 325 | { |
328 | int h , pos = 0; | 326 | int h , pos = 0; |
329 | int hmax = buf->vb.height; | 327 | int hmax = buf->vb.height; |
330 | int wmax = buf->vb.width; | 328 | int wmax = buf->vb.width; |
331 | struct timeval ts; | 329 | struct timeval ts; |
332 | char *tmpbuf = kmalloc(wmax * 2, GFP_KERNEL); | 330 | char *tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC); |
333 | void *vbuf = videobuf_to_vmalloc(&buf->vb); | 331 | void *vbuf = videobuf_to_vmalloc(&buf->vb); |
334 | 332 | ||
335 | if (!tmpbuf) | 333 | if (!tmpbuf) |
336 | return; | 334 | return; |
337 | 335 | ||
336 | if (!vbuf) | ||
337 | return; | ||
338 | |||
338 | for (h = 0; h < hmax; h++) { | 339 | for (h = 0; h < hmax; h++) { |
339 | gen_line(tmpbuf, 0, wmax, hmax, h, dev->mv_count, | 340 | gen_line(tmpbuf, 0, wmax, hmax, h, dev->mv_count, |
340 | dev->timestr); | 341 | dev->timestr); |
341 | /* FIXME: replacing to __copy_to_user */ | 342 | memcpy(vbuf + pos, tmpbuf, wmax * 2); |
342 | if (copy_to_user(vbuf + pos, tmpbuf, wmax * 2) != 0) | ||
343 | dprintk(dev, 2, "vivifill copy_to_user failed.\n"); | ||
344 | pos += wmax*2; | 343 | pos += wmax*2; |
345 | } | 344 | } |
346 | 345 | ||
@@ -373,67 +372,58 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf) | |||
373 | dev->timestr, (unsigned long)tmpbuf, pos); | 372 | dev->timestr, (unsigned long)tmpbuf, pos); |
374 | 373 | ||
375 | /* Advice that buffer was filled */ | 374 | /* Advice that buffer was filled */ |
376 | buf->vb.state = VIDEOBUF_DONE; | ||
377 | buf->vb.field_count++; | 375 | buf->vb.field_count++; |
378 | do_gettimeofday(&ts); | 376 | do_gettimeofday(&ts); |
379 | buf->vb.ts = ts; | 377 | buf->vb.ts = ts; |
380 | 378 | buf->vb.state = VIDEOBUF_DONE; | |
381 | list_del(&buf->vb.queue); | ||
382 | wake_up(&buf->vb.done); | ||
383 | } | 379 | } |
384 | 380 | ||
385 | static int restart_video_queue(struct vivi_dmaqueue *dma_q); | 381 | static void vivi_thread_tick(struct vivi_fh *fh) |
386 | |||
387 | static void vivi_thread_tick(struct vivi_dmaqueue *dma_q) | ||
388 | { | 382 | { |
389 | struct vivi_buffer *buf; | 383 | struct vivi_buffer *buf; |
390 | struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); | 384 | struct vivi_dev *dev = fh->dev; |
385 | struct vivi_dmaqueue *dma_q = &dev->vidq; | ||
391 | 386 | ||
392 | int bc; | 387 | unsigned long flags = 0; |
393 | 388 | ||
394 | spin_lock(&dev->slock); | 389 | dprintk(dev, 1, "Thread tick\n"); |
395 | /* Announces videobuf that all went ok */ | ||
396 | for (bc = 0;; bc++) { | ||
397 | if (list_empty(&dma_q->active)) { | ||
398 | dprintk(dev, 1, "No active queue to serve\n"); | ||
399 | break; | ||
400 | } | ||
401 | 390 | ||
402 | buf = list_entry(dma_q->active.next, | 391 | spin_lock_irqsave(&dev->slock, flags); |
403 | struct vivi_buffer, vb.queue); | 392 | if (list_empty(&dma_q->active)) { |
393 | dprintk(dev, 1, "No active queue to serve\n"); | ||
394 | goto unlock; | ||
395 | } | ||
404 | 396 | ||
405 | /* Nobody is waiting something to be done, just return */ | 397 | buf = list_entry(dma_q->active.next, |
406 | if (!waitqueue_active(&buf->vb.done)) { | 398 | struct vivi_buffer, vb.queue); |
407 | mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); | ||
408 | spin_unlock(&dev->slock); | ||
409 | return; | ||
410 | } | ||
411 | 399 | ||
412 | do_gettimeofday(&buf->vb.ts); | 400 | /* Nobody is waiting on this buffer, return */ |
413 | dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i); | 401 | if (!waitqueue_active(&buf->vb.done)) |
402 | goto unlock; | ||
414 | 403 | ||
415 | /* Fill buffer */ | 404 | list_del(&buf->vb.queue); |
416 | vivi_fillbuff(dev, buf); | ||
417 | 405 | ||
418 | if (list_empty(&dma_q->active)) { | 406 | do_gettimeofday(&buf->vb.ts); |
419 | del_timer(&dma_q->timeout); | 407 | |
420 | } else { | 408 | /* Fill buffer */ |
421 | mod_timer(&dma_q->timeout, jiffies + BUFFER_TIMEOUT); | 409 | vivi_fillbuff(dev, buf); |
422 | } | 410 | dprintk(dev, 1, "filled buffer %p\n", buf); |
423 | } | 411 | |
424 | if (bc != 1) | 412 | wake_up(&buf->vb.done); |
425 | dprintk(dev, 1, "%s: %d buffers handled (should be 1)\n", | 413 | dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i); |
426 | __FUNCTION__, bc); | 414 | unlock: |
427 | spin_unlock(&dev->slock); | 415 | spin_unlock_irqrestore(&dev->slock, flags); |
416 | return; | ||
428 | } | 417 | } |
429 | 418 | ||
430 | #define frames_to_ms(frames) \ | 419 | #define frames_to_ms(frames) \ |
431 | ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR) | 420 | ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR) |
432 | 421 | ||
433 | static void vivi_sleep(struct vivi_dmaqueue *dma_q) | 422 | static void vivi_sleep(struct vivi_fh *fh) |
434 | { | 423 | { |
435 | struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); | 424 | struct vivi_dev *dev = fh->dev; |
436 | int timeout, running_time; | 425 | struct vivi_dmaqueue *dma_q = &dev->vidq; |
426 | int timeout; | ||
437 | DECLARE_WAITQUEUE(wait, current); | 427 | DECLARE_WAITQUEUE(wait, current); |
438 | 428 | ||
439 | dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__, | 429 | dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__, |
@@ -443,37 +433,10 @@ static void vivi_sleep(struct vivi_dmaqueue *dma_q) | |||
443 | if (kthread_should_stop()) | 433 | if (kthread_should_stop()) |
444 | goto stop_task; | 434 | goto stop_task; |
445 | 435 | ||
446 | running_time = jiffies - dma_q->ini_jiffies; | ||
447 | dma_q->frame++; | ||
448 | |||
449 | /* Calculate time to wake up */ | 436 | /* Calculate time to wake up */ |
450 | timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame)) - running_time; | 437 | timeout = msecs_to_jiffies(frames_to_ms(1)); |
451 | 438 | ||
452 | if (timeout > msecs_to_jiffies(frames_to_ms(2)) || timeout <= 0) { | 439 | vivi_thread_tick(fh); |
453 | int old = dma_q->frame; | ||
454 | int nframes; | ||
455 | |||
456 | dma_q->frame = (jiffies_to_msecs(running_time) / | ||
457 | frames_to_ms(1)) + 1; | ||
458 | |||
459 | timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame)) | ||
460 | - running_time; | ||
461 | |||
462 | if (unlikely (timeout <= 0)) | ||
463 | timeout = 1; | ||
464 | |||
465 | nframes = (dma_q->frame > old)? | ||
466 | dma_q->frame - old : old - dma_q->frame; | ||
467 | |||
468 | dprintk(dev, 1, "%ld: %s %d frames. " | ||
469 | "Current frame is %d. Will sleep for %d jiffies\n", | ||
470 | jiffies, | ||
471 | (dma_q->frame > old)? "Underrun, losed" : "Overrun of", | ||
472 | nframes, dma_q->frame, timeout); | ||
473 | } else | ||
474 | dprintk(dev, 1, "will sleep for %d jiffies\n", timeout); | ||
475 | |||
476 | vivi_thread_tick(dma_q); | ||
477 | 440 | ||
478 | schedule_timeout_interruptible(timeout); | 441 | schedule_timeout_interruptible(timeout); |
479 | 442 | ||
@@ -484,16 +447,15 @@ stop_task: | |||
484 | 447 | ||
485 | static int vivi_thread(void *data) | 448 | static int vivi_thread(void *data) |
486 | { | 449 | { |
487 | struct vivi_dmaqueue *dma_q = data; | 450 | struct vivi_fh *fh = data; |
488 | struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); | 451 | struct vivi_dev *dev = fh->dev; |
489 | 452 | ||
490 | dprintk(dev, 1, "thread started\n"); | 453 | dprintk(dev, 1, "thread started\n"); |
491 | 454 | ||
492 | mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); | ||
493 | set_freezable(); | 455 | set_freezable(); |
494 | 456 | ||
495 | for (;;) { | 457 | for (;;) { |
496 | vivi_sleep(dma_q); | 458 | vivi_sleep(fh); |
497 | 459 | ||
498 | if (kthread_should_stop()) | 460 | if (kthread_should_stop()) |
499 | break; | 461 | break; |
@@ -502,16 +464,17 @@ static int vivi_thread(void *data) | |||
502 | return 0; | 464 | return 0; |
503 | } | 465 | } |
504 | 466 | ||
505 | static int vivi_start_thread(struct vivi_dmaqueue *dma_q) | 467 | static int vivi_start_thread(struct vivi_fh *fh) |
506 | { | 468 | { |
507 | struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); | 469 | struct vivi_dev *dev = fh->dev; |
470 | struct vivi_dmaqueue *dma_q = &dev->vidq; | ||
508 | 471 | ||
509 | dma_q->frame = 0; | 472 | dma_q->frame = 0; |
510 | dma_q->ini_jiffies = jiffies; | 473 | dma_q->ini_jiffies = jiffies; |
511 | 474 | ||
512 | dprintk(dev, 1, "%s\n", __FUNCTION__); | 475 | dprintk(dev, 1, "%s\n", __FUNCTION__); |
513 | 476 | ||
514 | dma_q->kthread = kthread_run(vivi_thread, dma_q, "vivi"); | 477 | dma_q->kthread = kthread_run(vivi_thread, fh, "vivi"); |
515 | 478 | ||
516 | if (IS_ERR(dma_q->kthread)) { | 479 | if (IS_ERR(dma_q->kthread)) { |
517 | printk(KERN_ERR "vivi: kernel_thread() failed\n"); | 480 | printk(KERN_ERR "vivi: kernel_thread() failed\n"); |
@@ -536,91 +499,6 @@ static void vivi_stop_thread(struct vivi_dmaqueue *dma_q) | |||
536 | } | 499 | } |
537 | } | 500 | } |
538 | 501 | ||
539 | static int restart_video_queue(struct vivi_dmaqueue *dma_q) | ||
540 | { | ||
541 | struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); | ||
542 | struct vivi_buffer *buf, *prev; | ||
543 | |||
544 | dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__, | ||
545 | (unsigned long)dma_q); | ||
546 | |||
547 | if (!list_empty(&dma_q->active)) { | ||
548 | buf = list_entry(dma_q->active.next, | ||
549 | struct vivi_buffer, vb.queue); | ||
550 | dprintk(dev, 2, "restart_queue [%p/%d]: restart dma\n", | ||
551 | buf, buf->vb.i); | ||
552 | |||
553 | dprintk(dev, 1, "Restarting video dma\n"); | ||
554 | vivi_stop_thread(dma_q); | ||
555 | |||
556 | /* cancel all outstanding capture / vbi requests */ | ||
557 | list_for_each_entry_safe(buf, prev, &dma_q->active, vb.queue) { | ||
558 | list_del(&buf->vb.queue); | ||
559 | buf->vb.state = VIDEOBUF_ERROR; | ||
560 | wake_up(&buf->vb.done); | ||
561 | } | ||
562 | mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); | ||
563 | |||
564 | return 0; | ||
565 | } | ||
566 | |||
567 | prev = NULL; | ||
568 | for (;;) { | ||
569 | if (list_empty(&dma_q->queued)) | ||
570 | return 0; | ||
571 | buf = list_entry(dma_q->queued.next, | ||
572 | struct vivi_buffer, vb.queue); | ||
573 | if (NULL == prev) { | ||
574 | list_del(&buf->vb.queue); | ||
575 | list_add_tail(&buf->vb.queue, &dma_q->active); | ||
576 | |||
577 | dprintk(dev, 1, "Restarting video dma\n"); | ||
578 | vivi_stop_thread(dma_q); | ||
579 | vivi_start_thread(dma_q); | ||
580 | |||
581 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
582 | mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT); | ||
583 | dprintk(dev, 2, | ||
584 | "[%p/%d] restart_queue - first active\n", | ||
585 | buf, buf->vb.i); | ||
586 | |||
587 | } else if (prev->vb.width == buf->vb.width && | ||
588 | prev->vb.height == buf->vb.height && | ||
589 | prev->fmt == buf->fmt) { | ||
590 | list_del(&buf->vb.queue); | ||
591 | list_add_tail(&buf->vb.queue, &dma_q->active); | ||
592 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
593 | dprintk(dev, 2, | ||
594 | "[%p/%d] restart_queue - move to active\n", | ||
595 | buf, buf->vb.i); | ||
596 | } else { | ||
597 | return 0; | ||
598 | } | ||
599 | prev = buf; | ||
600 | } | ||
601 | } | ||
602 | |||
603 | static void vivi_vid_timeout(unsigned long data) | ||
604 | { | ||
605 | struct vivi_dev *dev = (struct vivi_dev *)data; | ||
606 | struct vivi_dmaqueue *vidq = &dev->vidq; | ||
607 | struct vivi_buffer *buf; | ||
608 | |||
609 | spin_lock(&dev->slock); | ||
610 | |||
611 | while (!list_empty(&vidq->active)) { | ||
612 | buf = list_entry(vidq->active.next, | ||
613 | struct vivi_buffer, vb.queue); | ||
614 | list_del(&buf->vb.queue); | ||
615 | buf->vb.state = VIDEOBUF_ERROR; | ||
616 | wake_up(&buf->vb.done); | ||
617 | printk(KERN_INFO "vivi/0: [%p/%d] timeout\n", buf, buf->vb.i); | ||
618 | } | ||
619 | restart_video_queue(vidq); | ||
620 | |||
621 | spin_unlock(&dev->slock); | ||
622 | } | ||
623 | |||
624 | /* ------------------------------------------------------------------ | 502 | /* ------------------------------------------------------------------ |
625 | Videobuf operations | 503 | Videobuf operations |
626 | ------------------------------------------------------------------*/ | 504 | ------------------------------------------------------------------*/ |
@@ -649,13 +527,13 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) | |||
649 | struct vivi_fh *fh = vq->priv_data; | 527 | struct vivi_fh *fh = vq->priv_data; |
650 | struct vivi_dev *dev = fh->dev; | 528 | struct vivi_dev *dev = fh->dev; |
651 | 529 | ||
652 | dprintk(dev, 1, "%s\n", __FUNCTION__); | 530 | dprintk(dev, 1, "%s, state: %i\n", __FUNCTION__, buf->vb.state); |
653 | 531 | ||
654 | if (in_interrupt()) | 532 | if (in_interrupt()) |
655 | BUG(); | 533 | BUG(); |
656 | 534 | ||
657 | videobuf_waiton(&buf->vb, 0, 0); | ||
658 | videobuf_vmalloc_free(&buf->vb); | 535 | videobuf_vmalloc_free(&buf->vb); |
536 | dprintk(dev, 1, "free_buffer: freed"); | ||
659 | buf->vb.state = VIDEOBUF_NEEDS_INIT; | 537 | buf->vb.state = VIDEOBUF_NEEDS_INIT; |
660 | } | 538 | } |
661 | 539 | ||
@@ -668,28 +546,25 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, | |||
668 | struct vivi_fh *fh = vq->priv_data; | 546 | struct vivi_fh *fh = vq->priv_data; |
669 | struct vivi_dev *dev = fh->dev; | 547 | struct vivi_dev *dev = fh->dev; |
670 | struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); | 548 | struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); |
671 | int rc, init_buffer = 0; | 549 | int rc; |
672 | 550 | ||
673 | dprintk(dev, 1, "%s, field=%d\n", __FUNCTION__, field); | 551 | dprintk(dev, 1, "%s, field=%d\n", __FUNCTION__, field); |
674 | 552 | ||
675 | BUG_ON(NULL == fh->fmt); | 553 | BUG_ON(NULL == fh->fmt); |
554 | |||
676 | if (fh->width < 48 || fh->width > norm_maxw() || | 555 | if (fh->width < 48 || fh->width > norm_maxw() || |
677 | fh->height < 32 || fh->height > norm_maxh()) | 556 | fh->height < 32 || fh->height > norm_maxh()) |
678 | return -EINVAL; | 557 | return -EINVAL; |
558 | |||
679 | buf->vb.size = fh->width*fh->height*2; | 559 | buf->vb.size = fh->width*fh->height*2; |
680 | if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) | 560 | if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) |
681 | return -EINVAL; | 561 | return -EINVAL; |
682 | 562 | ||
683 | if (buf->fmt != fh->fmt || | 563 | /* These properties only change when queue is idle, see s_fmt */ |
684 | buf->vb.width != fh->width || | 564 | buf->fmt = fh->fmt; |
685 | buf->vb.height != fh->height || | 565 | buf->vb.width = fh->width; |
686 | buf->vb.field != field) { | 566 | buf->vb.height = fh->height; |
687 | buf->fmt = fh->fmt; | 567 | buf->vb.field = field; |
688 | buf->vb.width = fh->width; | ||
689 | buf->vb.height = fh->height; | ||
690 | buf->vb.field = field; | ||
691 | init_buffer = 1; | ||
692 | } | ||
693 | 568 | ||
694 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { | 569 | if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { |
695 | rc = videobuf_iolock(vq, &buf->vb, NULL); | 570 | rc = videobuf_iolock(vq, &buf->vb, NULL); |
@@ -712,45 +587,12 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) | |||
712 | struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); | 587 | struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); |
713 | struct vivi_fh *fh = vq->priv_data; | 588 | struct vivi_fh *fh = vq->priv_data; |
714 | struct vivi_dev *dev = fh->dev; | 589 | struct vivi_dev *dev = fh->dev; |
715 | struct vivi_dmaqueue *vidq = &dev->vidq; | 590 | struct vivi_dmaqueue *vidq = &dev->vidq; |
716 | struct vivi_buffer *prev; | 591 | |
717 | 592 | dprintk(dev, 1, "%s\n", __FUNCTION__); | |
718 | if (!list_empty(&vidq->queued)) { | 593 | |
719 | dprintk(dev, 1, "adding vb queue=0x%08lx\n", | 594 | buf->vb.state = VIDEOBUF_QUEUED; |
720 | (unsigned long)&buf->vb.queue); | 595 | list_add_tail(&buf->vb.queue, &vidq->active); |
721 | list_add_tail(&buf->vb.queue, &vidq->queued); | ||
722 | buf->vb.state = VIDEOBUF_QUEUED; | ||
723 | dprintk(dev, 2, "[%p/%d] buffer_queue - append to queued\n", | ||
724 | buf, buf->vb.i); | ||
725 | } else if (list_empty(&vidq->active)) { | ||
726 | list_add_tail(&buf->vb.queue, &vidq->active); | ||
727 | |||
728 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
729 | mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT); | ||
730 | dprintk(dev, 2, "[%p/%d] buffer_queue - first active\n", | ||
731 | buf, buf->vb.i); | ||
732 | |||
733 | vivi_start_thread(vidq); | ||
734 | } else { | ||
735 | prev = list_entry(vidq->active.prev, | ||
736 | struct vivi_buffer, vb.queue); | ||
737 | if (prev->vb.width == buf->vb.width && | ||
738 | prev->vb.height == buf->vb.height && | ||
739 | prev->fmt == buf->fmt) { | ||
740 | list_add_tail(&buf->vb.queue, &vidq->active); | ||
741 | buf->vb.state = VIDEOBUF_ACTIVE; | ||
742 | dprintk(dev, 2, | ||
743 | "[%p/%d] buffer_queue - append to active\n", | ||
744 | buf, buf->vb.i); | ||
745 | |||
746 | } else { | ||
747 | list_add_tail(&buf->vb.queue, &vidq->queued); | ||
748 | buf->vb.state = VIDEOBUF_QUEUED; | ||
749 | dprintk(dev, 2, | ||
750 | "[%p/%d] buffer_queue - first queued\n", | ||
751 | buf, buf->vb.i); | ||
752 | } | ||
753 | } | ||
754 | } | 596 | } |
755 | 597 | ||
756 | static void buffer_release(struct videobuf_queue *vq, | 598 | static void buffer_release(struct videobuf_queue *vq, |
@@ -759,12 +601,9 @@ static void buffer_release(struct videobuf_queue *vq, | |||
759 | struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); | 601 | struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); |
760 | struct vivi_fh *fh = vq->priv_data; | 602 | struct vivi_fh *fh = vq->priv_data; |
761 | struct vivi_dev *dev = (struct vivi_dev *)fh->dev; | 603 | struct vivi_dev *dev = (struct vivi_dev *)fh->dev; |
762 | struct vivi_dmaqueue *vidq = &dev->vidq; | ||
763 | 604 | ||
764 | dprintk(dev, 1, "%s\n", __FUNCTION__); | 605 | dprintk(dev, 1, "%s\n", __FUNCTION__); |
765 | 606 | ||
766 | vivi_stop_thread(vidq); | ||
767 | |||
768 | free_buffer(vq, buf); | 607 | free_buffer(vq, buf); |
769 | } | 608 | } |
770 | 609 | ||
@@ -870,17 +709,31 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv, | |||
870 | struct v4l2_format *f) | 709 | struct v4l2_format *f) |
871 | { | 710 | { |
872 | struct vivi_fh *fh = priv; | 711 | struct vivi_fh *fh = priv; |
712 | struct videobuf_queue *q = &fh->vb_vidq; | ||
713 | |||
873 | int ret = vidioc_try_fmt_cap(file, fh, f); | 714 | int ret = vidioc_try_fmt_cap(file, fh, f); |
874 | if (ret < 0) | 715 | if (ret < 0) |
875 | return (ret); | 716 | return (ret); |
876 | 717 | ||
718 | mutex_lock(&q->vb_lock); | ||
719 | |||
720 | if (videobuf_queue_is_busy(&fh->vb_vidq)) { | ||
721 | dprintk(fh->dev, 1, "%s queue busy\n", __FUNCTION__); | ||
722 | ret = -EBUSY; | ||
723 | goto out; | ||
724 | } | ||
725 | |||
877 | fh->fmt = &format; | 726 | fh->fmt = &format; |
878 | fh->width = f->fmt.pix.width; | 727 | fh->width = f->fmt.pix.width; |
879 | fh->height = f->fmt.pix.height; | 728 | fh->height = f->fmt.pix.height; |
880 | fh->vb_vidq.field = f->fmt.pix.field; | 729 | fh->vb_vidq.field = f->fmt.pix.field; |
881 | fh->type = f->type; | 730 | fh->type = f->type; |
882 | 731 | ||
883 | return (0); | 732 | ret = 0; |
733 | out: | ||
734 | mutex_unlock(&q->vb_lock); | ||
735 | |||
736 | return (ret); | ||
884 | } | 737 | } |
885 | 738 | ||
886 | static int vidioc_reqbufs(struct file *file, void *priv, | 739 | static int vidioc_reqbufs(struct file *file, void *priv, |
@@ -1097,6 +950,8 @@ unlock: | |||
1097 | NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED, | 950 | NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED, |
1098 | sizeof(struct vivi_buffer), fh); | 951 | sizeof(struct vivi_buffer), fh); |
1099 | 952 | ||
953 | vivi_start_thread(fh); | ||
954 | |||
1100 | return 0; | 955 | return 0; |
1101 | } | 956 | } |
1102 | 957 | ||
@@ -1252,18 +1107,12 @@ static int __init vivi_init(void) | |||
1252 | 1107 | ||
1253 | /* init video dma queues */ | 1108 | /* init video dma queues */ |
1254 | INIT_LIST_HEAD(&dev->vidq.active); | 1109 | INIT_LIST_HEAD(&dev->vidq.active); |
1255 | INIT_LIST_HEAD(&dev->vidq.queued); | ||
1256 | init_waitqueue_head(&dev->vidq.wq); | 1110 | init_waitqueue_head(&dev->vidq.wq); |
1257 | 1111 | ||
1258 | /* initialize locks */ | 1112 | /* initialize locks */ |
1259 | mutex_init(&dev->lock); | ||
1260 | spin_lock_init(&dev->slock); | 1113 | spin_lock_init(&dev->slock); |
1261 | mutex_init(&dev->mutex); | 1114 | mutex_init(&dev->mutex); |
1262 | 1115 | ||
1263 | dev->vidq.timeout.function = vivi_vid_timeout; | ||
1264 | dev->vidq.timeout.data = (unsigned long)dev; | ||
1265 | init_timer(&dev->vidq.timeout); | ||
1266 | |||
1267 | vfd = video_device_alloc(); | 1116 | vfd = video_device_alloc(); |
1268 | if (NULL == vfd) | 1117 | if (NULL == vfd) |
1269 | break; | 1118 | break; |