diff options
Diffstat (limited to 'drivers/usb/media/w9968cf.c')
-rw-r--r-- | drivers/usb/media/w9968cf.c | 75 |
1 files changed, 41 insertions, 34 deletions
diff --git a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c index 78cd1a577d26..b57dec3782e0 100644 --- a/drivers/usb/media/w9968cf.c +++ b/drivers/usb/media/w9968cf.c | |||
@@ -47,6 +47,13 @@ | |||
47 | #include "w9968cf.h" | 47 | #include "w9968cf.h" |
48 | #include "w9968cf_decoder.h" | 48 | #include "w9968cf_decoder.h" |
49 | 49 | ||
50 | static struct w9968cf_vpp_t* w9968cf_vpp; | ||
51 | static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait); | ||
52 | |||
53 | static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */ | ||
54 | static DEFINE_MUTEX(w9968cf_devlist_mutex); /* semaphore for list traversal */ | ||
55 | |||
56 | static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */ | ||
50 | 57 | ||
51 | 58 | ||
52 | /**************************************************************************** | 59 | /**************************************************************************** |
@@ -2418,7 +2425,7 @@ w9968cf_configure_camera(struct w9968cf_device* cam, | |||
2418 | enum w9968cf_model_id mod_id, | 2425 | enum w9968cf_model_id mod_id, |
2419 | const unsigned short dev_nr) | 2426 | const unsigned short dev_nr) |
2420 | { | 2427 | { |
2421 | init_MUTEX(&cam->fileop_sem); | 2428 | mutex_init(&cam->fileop_mutex); |
2422 | init_waitqueue_head(&cam->open); | 2429 | init_waitqueue_head(&cam->open); |
2423 | spin_lock_init(&cam->urb_lock); | 2430 | spin_lock_init(&cam->urb_lock); |
2424 | spin_lock_init(&cam->flist_lock); | 2431 | spin_lock_init(&cam->flist_lock); |
@@ -2646,7 +2653,7 @@ static void w9968cf_adjust_configuration(struct w9968cf_device* cam) | |||
2646 | --------------------------------------------------------------------------*/ | 2653 | --------------------------------------------------------------------------*/ |
2647 | static void w9968cf_release_resources(struct w9968cf_device* cam) | 2654 | static void w9968cf_release_resources(struct w9968cf_device* cam) |
2648 | { | 2655 | { |
2649 | down(&w9968cf_devlist_sem); | 2656 | mutex_lock(&w9968cf_devlist_mutex); |
2650 | 2657 | ||
2651 | DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->minor) | 2658 | DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->minor) |
2652 | 2659 | ||
@@ -2657,7 +2664,7 @@ static void w9968cf_release_resources(struct w9968cf_device* cam) | |||
2657 | kfree(cam->control_buffer); | 2664 | kfree(cam->control_buffer); |
2658 | kfree(cam->data_buffer); | 2665 | kfree(cam->data_buffer); |
2659 | 2666 | ||
2660 | up(&w9968cf_devlist_sem); | 2667 | mutex_unlock(&w9968cf_devlist_mutex); |
2661 | } | 2668 | } |
2662 | 2669 | ||
2663 | 2670 | ||
@@ -2677,14 +2684,14 @@ static int w9968cf_open(struct inode* inode, struct file* filp) | |||
2677 | 2684 | ||
2678 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | 2685 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); |
2679 | 2686 | ||
2680 | down(&cam->dev_sem); | 2687 | mutex_lock(&cam->dev_mutex); |
2681 | 2688 | ||
2682 | if (cam->sensor == CC_UNKNOWN) { | 2689 | if (cam->sensor == CC_UNKNOWN) { |
2683 | DBG(2, "No supported image sensor has been detected by the " | 2690 | DBG(2, "No supported image sensor has been detected by the " |
2684 | "'ovcamchip' module for the %s (/dev/video%d). Make " | 2691 | "'ovcamchip' module for the %s (/dev/video%d). Make " |
2685 | "sure it is loaded *before* (re)connecting the camera.", | 2692 | "sure it is loaded *before* (re)connecting the camera.", |
2686 | symbolic(camlist, cam->id), cam->v4ldev->minor) | 2693 | symbolic(camlist, cam->id), cam->v4ldev->minor) |
2687 | up(&cam->dev_sem); | 2694 | mutex_unlock(&cam->dev_mutex); |
2688 | up_read(&w9968cf_disconnect); | 2695 | up_read(&w9968cf_disconnect); |
2689 | return -ENODEV; | 2696 | return -ENODEV; |
2690 | } | 2697 | } |
@@ -2693,11 +2700,11 @@ static int w9968cf_open(struct inode* inode, struct file* filp) | |||
2693 | DBG(2, "%s (/dev/video%d) has been already occupied by '%s'", | 2700 | DBG(2, "%s (/dev/video%d) has been already occupied by '%s'", |
2694 | symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command) | 2701 | symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command) |
2695 | if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) { | 2702 | if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) { |
2696 | up(&cam->dev_sem); | 2703 | mutex_unlock(&cam->dev_mutex); |
2697 | up_read(&w9968cf_disconnect); | 2704 | up_read(&w9968cf_disconnect); |
2698 | return -EWOULDBLOCK; | 2705 | return -EWOULDBLOCK; |
2699 | } | 2706 | } |
2700 | up(&cam->dev_sem); | 2707 | mutex_unlock(&cam->dev_mutex); |
2701 | err = wait_event_interruptible_exclusive(cam->open, | 2708 | err = wait_event_interruptible_exclusive(cam->open, |
2702 | cam->disconnected || | 2709 | cam->disconnected || |
2703 | !cam->users); | 2710 | !cam->users); |
@@ -2709,7 +2716,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp) | |||
2709 | up_read(&w9968cf_disconnect); | 2716 | up_read(&w9968cf_disconnect); |
2710 | return -ENODEV; | 2717 | return -ENODEV; |
2711 | } | 2718 | } |
2712 | down(&cam->dev_sem); | 2719 | mutex_lock(&cam->dev_mutex); |
2713 | } | 2720 | } |
2714 | 2721 | ||
2715 | DBG(5, "Opening '%s', /dev/video%d ...", | 2722 | DBG(5, "Opening '%s', /dev/video%d ...", |
@@ -2738,7 +2745,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp) | |||
2738 | 2745 | ||
2739 | DBG(5, "Video device is open") | 2746 | DBG(5, "Video device is open") |
2740 | 2747 | ||
2741 | up(&cam->dev_sem); | 2748 | mutex_unlock(&cam->dev_mutex); |
2742 | up_read(&w9968cf_disconnect); | 2749 | up_read(&w9968cf_disconnect); |
2743 | 2750 | ||
2744 | return 0; | 2751 | return 0; |
@@ -2746,7 +2753,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp) | |||
2746 | deallocate_memory: | 2753 | deallocate_memory: |
2747 | w9968cf_deallocate_memory(cam); | 2754 | w9968cf_deallocate_memory(cam); |
2748 | DBG(2, "Failed to open the video device") | 2755 | DBG(2, "Failed to open the video device") |
2749 | up(&cam->dev_sem); | 2756 | mutex_unlock(&cam->dev_mutex); |
2750 | up_read(&w9968cf_disconnect); | 2757 | up_read(&w9968cf_disconnect); |
2751 | return err; | 2758 | return err; |
2752 | } | 2759 | } |
@@ -2758,13 +2765,13 @@ static int w9968cf_release(struct inode* inode, struct file* filp) | |||
2758 | 2765 | ||
2759 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | 2766 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); |
2760 | 2767 | ||
2761 | down(&cam->dev_sem); /* prevent disconnect() to be called */ | 2768 | mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ |
2762 | 2769 | ||
2763 | w9968cf_stop_transfer(cam); | 2770 | w9968cf_stop_transfer(cam); |
2764 | 2771 | ||
2765 | if (cam->disconnected) { | 2772 | if (cam->disconnected) { |
2766 | w9968cf_release_resources(cam); | 2773 | w9968cf_release_resources(cam); |
2767 | up(&cam->dev_sem); | 2774 | mutex_unlock(&cam->dev_mutex); |
2768 | kfree(cam); | 2775 | kfree(cam); |
2769 | return 0; | 2776 | return 0; |
2770 | } | 2777 | } |
@@ -2774,7 +2781,7 @@ static int w9968cf_release(struct inode* inode, struct file* filp) | |||
2774 | wake_up_interruptible_nr(&cam->open, 1); | 2781 | wake_up_interruptible_nr(&cam->open, 1); |
2775 | 2782 | ||
2776 | DBG(5, "Video device closed") | 2783 | DBG(5, "Video device closed") |
2777 | up(&cam->dev_sem); | 2784 | mutex_unlock(&cam->dev_mutex); |
2778 | return 0; | 2785 | return 0; |
2779 | } | 2786 | } |
2780 | 2787 | ||
@@ -2791,18 +2798,18 @@ w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | |||
2791 | if (filp->f_flags & O_NONBLOCK) | 2798 | if (filp->f_flags & O_NONBLOCK) |
2792 | return -EWOULDBLOCK; | 2799 | return -EWOULDBLOCK; |
2793 | 2800 | ||
2794 | if (down_interruptible(&cam->fileop_sem)) | 2801 | if (mutex_lock_interruptible(&cam->fileop_mutex)) |
2795 | return -ERESTARTSYS; | 2802 | return -ERESTARTSYS; |
2796 | 2803 | ||
2797 | if (cam->disconnected) { | 2804 | if (cam->disconnected) { |
2798 | DBG(2, "Device not present") | 2805 | DBG(2, "Device not present") |
2799 | up(&cam->fileop_sem); | 2806 | mutex_unlock(&cam->fileop_mutex); |
2800 | return -ENODEV; | 2807 | return -ENODEV; |
2801 | } | 2808 | } |
2802 | 2809 | ||
2803 | if (cam->misconfigured) { | 2810 | if (cam->misconfigured) { |
2804 | DBG(2, "The camera is misconfigured. Close and open it again.") | 2811 | DBG(2, "The camera is misconfigured. Close and open it again.") |
2805 | up(&cam->fileop_sem); | 2812 | mutex_unlock(&cam->fileop_mutex); |
2806 | return -EIO; | 2813 | return -EIO; |
2807 | } | 2814 | } |
2808 | 2815 | ||
@@ -2817,11 +2824,11 @@ w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | |||
2817 | cam->frame[1].status == F_READY || | 2824 | cam->frame[1].status == F_READY || |
2818 | cam->disconnected); | 2825 | cam->disconnected); |
2819 | if (err) { | 2826 | if (err) { |
2820 | up(&cam->fileop_sem); | 2827 | mutex_unlock(&cam->fileop_mutex); |
2821 | return err; | 2828 | return err; |
2822 | } | 2829 | } |
2823 | if (cam->disconnected) { | 2830 | if (cam->disconnected) { |
2824 | up(&cam->fileop_sem); | 2831 | mutex_unlock(&cam->fileop_mutex); |
2825 | return -ENODEV; | 2832 | return -ENODEV; |
2826 | } | 2833 | } |
2827 | 2834 | ||
@@ -2835,7 +2842,7 @@ w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | |||
2835 | 2842 | ||
2836 | if (copy_to_user(buf, fr->buffer, count)) { | 2843 | if (copy_to_user(buf, fr->buffer, count)) { |
2837 | fr->status = F_UNUSED; | 2844 | fr->status = F_UNUSED; |
2838 | up(&cam->fileop_sem); | 2845 | mutex_unlock(&cam->fileop_mutex); |
2839 | return -EFAULT; | 2846 | return -EFAULT; |
2840 | } | 2847 | } |
2841 | *f_pos += count; | 2848 | *f_pos += count; |
@@ -2844,7 +2851,7 @@ w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | |||
2844 | 2851 | ||
2845 | DBG(5, "%zu bytes read", count) | 2852 | DBG(5, "%zu bytes read", count) |
2846 | 2853 | ||
2847 | up(&cam->fileop_sem); | 2854 | mutex_unlock(&cam->fileop_mutex); |
2848 | return count; | 2855 | return count; |
2849 | } | 2856 | } |
2850 | 2857 | ||
@@ -2898,24 +2905,24 @@ w9968cf_ioctl(struct inode* inode, struct file* filp, | |||
2898 | 2905 | ||
2899 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | 2906 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); |
2900 | 2907 | ||
2901 | if (down_interruptible(&cam->fileop_sem)) | 2908 | if (mutex_lock_interruptible(&cam->fileop_mutex)) |
2902 | return -ERESTARTSYS; | 2909 | return -ERESTARTSYS; |
2903 | 2910 | ||
2904 | if (cam->disconnected) { | 2911 | if (cam->disconnected) { |
2905 | DBG(2, "Device not present") | 2912 | DBG(2, "Device not present") |
2906 | up(&cam->fileop_sem); | 2913 | mutex_unlock(&cam->fileop_mutex); |
2907 | return -ENODEV; | 2914 | return -ENODEV; |
2908 | } | 2915 | } |
2909 | 2916 | ||
2910 | if (cam->misconfigured) { | 2917 | if (cam->misconfigured) { |
2911 | DBG(2, "The camera is misconfigured. Close and open it again.") | 2918 | DBG(2, "The camera is misconfigured. Close and open it again.") |
2912 | up(&cam->fileop_sem); | 2919 | mutex_unlock(&cam->fileop_mutex); |
2913 | return -EIO; | 2920 | return -EIO; |
2914 | } | 2921 | } |
2915 | 2922 | ||
2916 | err = w9968cf_v4l_ioctl(inode, filp, cmd, (void __user *)arg); | 2923 | err = w9968cf_v4l_ioctl(inode, filp, cmd, (void __user *)arg); |
2917 | 2924 | ||
2918 | up(&cam->fileop_sem); | 2925 | mutex_unlock(&cam->fileop_mutex); |
2919 | return err; | 2926 | return err; |
2920 | } | 2927 | } |
2921 | 2928 | ||
@@ -3502,8 +3509,8 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
3502 | if (!cam) | 3509 | if (!cam) |
3503 | return -ENOMEM; | 3510 | return -ENOMEM; |
3504 | 3511 | ||
3505 | init_MUTEX(&cam->dev_sem); | 3512 | mutex_init(&cam->dev_mutex); |
3506 | down(&cam->dev_sem); | 3513 | mutex_lock(&cam->dev_mutex); |
3507 | 3514 | ||
3508 | cam->usbdev = udev; | 3515 | cam->usbdev = udev; |
3509 | /* NOTE: a local copy is used to avoid possible race conditions */ | 3516 | /* NOTE: a local copy is used to avoid possible race conditions */ |
@@ -3515,10 +3522,10 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
3515 | simcams = W9968CF_SIMCAMS; | 3522 | simcams = W9968CF_SIMCAMS; |
3516 | 3523 | ||
3517 | /* How many cameras are connected ? */ | 3524 | /* How many cameras are connected ? */ |
3518 | down(&w9968cf_devlist_sem); | 3525 | mutex_lock(&w9968cf_devlist_mutex); |
3519 | list_for_each(ptr, &w9968cf_dev_list) | 3526 | list_for_each(ptr, &w9968cf_dev_list) |
3520 | sc++; | 3527 | sc++; |
3521 | up(&w9968cf_devlist_sem); | 3528 | mutex_unlock(&w9968cf_devlist_mutex); |
3522 | 3529 | ||
3523 | if (sc >= simcams) { | 3530 | if (sc >= simcams) { |
3524 | DBG(2, "Device rejected: too many connected cameras " | 3531 | DBG(2, "Device rejected: too many connected cameras " |
@@ -3578,9 +3585,9 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
3578 | w9968cf_configure_camera(cam, udev, mod_id, dev_nr); | 3585 | w9968cf_configure_camera(cam, udev, mod_id, dev_nr); |
3579 | 3586 | ||
3580 | /* Add a new entry into the list of V4L registered devices */ | 3587 | /* Add a new entry into the list of V4L registered devices */ |
3581 | down(&w9968cf_devlist_sem); | 3588 | mutex_lock(&w9968cf_devlist_mutex); |
3582 | list_add(&cam->v4llist, &w9968cf_dev_list); | 3589 | list_add(&cam->v4llist, &w9968cf_dev_list); |
3583 | up(&w9968cf_devlist_sem); | 3590 | mutex_unlock(&w9968cf_devlist_mutex); |
3584 | dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0; | 3591 | dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0; |
3585 | 3592 | ||
3586 | w9968cf_turn_on_led(cam); | 3593 | w9968cf_turn_on_led(cam); |
@@ -3588,7 +3595,7 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
3588 | w9968cf_i2c_init(cam); | 3595 | w9968cf_i2c_init(cam); |
3589 | 3596 | ||
3590 | usb_set_intfdata(intf, cam); | 3597 | usb_set_intfdata(intf, cam); |
3591 | up(&cam->dev_sem); | 3598 | mutex_unlock(&cam->dev_mutex); |
3592 | return 0; | 3599 | return 0; |
3593 | 3600 | ||
3594 | fail: /* Free unused memory */ | 3601 | fail: /* Free unused memory */ |
@@ -3596,7 +3603,7 @@ fail: /* Free unused memory */ | |||
3596 | kfree(cam->data_buffer); | 3603 | kfree(cam->data_buffer); |
3597 | if (cam->v4ldev) | 3604 | if (cam->v4ldev) |
3598 | video_device_release(cam->v4ldev); | 3605 | video_device_release(cam->v4ldev); |
3599 | up(&cam->dev_sem); | 3606 | mutex_unlock(&cam->dev_mutex); |
3600 | kfree(cam); | 3607 | kfree(cam); |
3601 | return err; | 3608 | return err; |
3602 | } | 3609 | } |
@@ -3611,7 +3618,7 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf) | |||
3611 | 3618 | ||
3612 | if (cam) { | 3619 | if (cam) { |
3613 | /* Prevent concurrent accesses to data */ | 3620 | /* Prevent concurrent accesses to data */ |
3614 | down(&cam->dev_sem); | 3621 | mutex_lock(&cam->dev_mutex); |
3615 | 3622 | ||
3616 | cam->disconnected = 1; | 3623 | cam->disconnected = 1; |
3617 | 3624 | ||
@@ -3630,7 +3637,7 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf) | |||
3630 | } else | 3637 | } else |
3631 | w9968cf_release_resources(cam); | 3638 | w9968cf_release_resources(cam); |
3632 | 3639 | ||
3633 | up(&cam->dev_sem); | 3640 | mutex_unlock(&cam->dev_mutex); |
3634 | 3641 | ||
3635 | if (!cam->users) | 3642 | if (!cam->users) |
3636 | kfree(cam); | 3643 | kfree(cam); |