diff options
Diffstat (limited to 'drivers/usb/media/w9968cf.c')
-rw-r--r-- | drivers/usb/media/w9968cf.c | 88 |
1 files changed, 45 insertions, 43 deletions
diff --git a/drivers/usb/media/w9968cf.c b/drivers/usb/media/w9968cf.c index 9937fc64c8bf..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 | /**************************************************************************** |
@@ -695,13 +702,12 @@ static int w9968cf_allocate_memory(struct w9968cf_device* cam) | |||
695 | /* Allocate memory for the isochronous transfer buffers */ | 702 | /* Allocate memory for the isochronous transfer buffers */ |
696 | for (i = 0; i < W9968CF_URBS; i++) { | 703 | for (i = 0; i < W9968CF_URBS; i++) { |
697 | if (!(cam->transfer_buffer[i] = | 704 | if (!(cam->transfer_buffer[i] = |
698 | kmalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) { | 705 | kzalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) { |
699 | DBG(1, "Couldn't allocate memory for the isochronous " | 706 | DBG(1, "Couldn't allocate memory for the isochronous " |
700 | "transfer buffers (%u bytes)", | 707 | "transfer buffers (%u bytes)", |
701 | p_size * W9968CF_ISO_PACKETS) | 708 | p_size * W9968CF_ISO_PACKETS) |
702 | return -ENOMEM; | 709 | return -ENOMEM; |
703 | } | 710 | } |
704 | memset(cam->transfer_buffer[i], 0, W9968CF_ISO_PACKETS*p_size); | ||
705 | } | 711 | } |
706 | 712 | ||
707 | /* Allocate memory for the temporary frame buffer */ | 713 | /* Allocate memory for the temporary frame buffer */ |
@@ -2419,7 +2425,7 @@ w9968cf_configure_camera(struct w9968cf_device* cam, | |||
2419 | enum w9968cf_model_id mod_id, | 2425 | enum w9968cf_model_id mod_id, |
2420 | const unsigned short dev_nr) | 2426 | const unsigned short dev_nr) |
2421 | { | 2427 | { |
2422 | init_MUTEX(&cam->fileop_sem); | 2428 | mutex_init(&cam->fileop_mutex); |
2423 | init_waitqueue_head(&cam->open); | 2429 | init_waitqueue_head(&cam->open); |
2424 | spin_lock_init(&cam->urb_lock); | 2430 | spin_lock_init(&cam->urb_lock); |
2425 | spin_lock_init(&cam->flist_lock); | 2431 | spin_lock_init(&cam->flist_lock); |
@@ -2647,7 +2653,7 @@ static void w9968cf_adjust_configuration(struct w9968cf_device* cam) | |||
2647 | --------------------------------------------------------------------------*/ | 2653 | --------------------------------------------------------------------------*/ |
2648 | static void w9968cf_release_resources(struct w9968cf_device* cam) | 2654 | static void w9968cf_release_resources(struct w9968cf_device* cam) |
2649 | { | 2655 | { |
2650 | down(&w9968cf_devlist_sem); | 2656 | mutex_lock(&w9968cf_devlist_mutex); |
2651 | 2657 | ||
2652 | DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->minor) | 2658 | DBG(2, "V4L device deregistered: /dev/video%d", cam->v4ldev->minor) |
2653 | 2659 | ||
@@ -2658,7 +2664,7 @@ static void w9968cf_release_resources(struct w9968cf_device* cam) | |||
2658 | kfree(cam->control_buffer); | 2664 | kfree(cam->control_buffer); |
2659 | kfree(cam->data_buffer); | 2665 | kfree(cam->data_buffer); |
2660 | 2666 | ||
2661 | up(&w9968cf_devlist_sem); | 2667 | mutex_unlock(&w9968cf_devlist_mutex); |
2662 | } | 2668 | } |
2663 | 2669 | ||
2664 | 2670 | ||
@@ -2678,14 +2684,14 @@ static int w9968cf_open(struct inode* inode, struct file* filp) | |||
2678 | 2684 | ||
2679 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | 2685 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); |
2680 | 2686 | ||
2681 | down(&cam->dev_sem); | 2687 | mutex_lock(&cam->dev_mutex); |
2682 | 2688 | ||
2683 | if (cam->sensor == CC_UNKNOWN) { | 2689 | if (cam->sensor == CC_UNKNOWN) { |
2684 | DBG(2, "No supported image sensor has been detected by the " | 2690 | DBG(2, "No supported image sensor has been detected by the " |
2685 | "'ovcamchip' module for the %s (/dev/video%d). Make " | 2691 | "'ovcamchip' module for the %s (/dev/video%d). Make " |
2686 | "sure it is loaded *before* (re)connecting the camera.", | 2692 | "sure it is loaded *before* (re)connecting the camera.", |
2687 | symbolic(camlist, cam->id), cam->v4ldev->minor) | 2693 | symbolic(camlist, cam->id), cam->v4ldev->minor) |
2688 | up(&cam->dev_sem); | 2694 | mutex_unlock(&cam->dev_mutex); |
2689 | up_read(&w9968cf_disconnect); | 2695 | up_read(&w9968cf_disconnect); |
2690 | return -ENODEV; | 2696 | return -ENODEV; |
2691 | } | 2697 | } |
@@ -2694,11 +2700,11 @@ static int w9968cf_open(struct inode* inode, struct file* filp) | |||
2694 | 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'", |
2695 | symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command) | 2701 | symbolic(camlist, cam->id),cam->v4ldev->minor,cam->command) |
2696 | if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) { | 2702 | if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) { |
2697 | up(&cam->dev_sem); | 2703 | mutex_unlock(&cam->dev_mutex); |
2698 | up_read(&w9968cf_disconnect); | 2704 | up_read(&w9968cf_disconnect); |
2699 | return -EWOULDBLOCK; | 2705 | return -EWOULDBLOCK; |
2700 | } | 2706 | } |
2701 | up(&cam->dev_sem); | 2707 | mutex_unlock(&cam->dev_mutex); |
2702 | err = wait_event_interruptible_exclusive(cam->open, | 2708 | err = wait_event_interruptible_exclusive(cam->open, |
2703 | cam->disconnected || | 2709 | cam->disconnected || |
2704 | !cam->users); | 2710 | !cam->users); |
@@ -2710,7 +2716,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp) | |||
2710 | up_read(&w9968cf_disconnect); | 2716 | up_read(&w9968cf_disconnect); |
2711 | return -ENODEV; | 2717 | return -ENODEV; |
2712 | } | 2718 | } |
2713 | down(&cam->dev_sem); | 2719 | mutex_lock(&cam->dev_mutex); |
2714 | } | 2720 | } |
2715 | 2721 | ||
2716 | DBG(5, "Opening '%s', /dev/video%d ...", | 2722 | DBG(5, "Opening '%s', /dev/video%d ...", |
@@ -2739,7 +2745,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp) | |||
2739 | 2745 | ||
2740 | DBG(5, "Video device is open") | 2746 | DBG(5, "Video device is open") |
2741 | 2747 | ||
2742 | up(&cam->dev_sem); | 2748 | mutex_unlock(&cam->dev_mutex); |
2743 | up_read(&w9968cf_disconnect); | 2749 | up_read(&w9968cf_disconnect); |
2744 | 2750 | ||
2745 | return 0; | 2751 | return 0; |
@@ -2747,7 +2753,7 @@ static int w9968cf_open(struct inode* inode, struct file* filp) | |||
2747 | deallocate_memory: | 2753 | deallocate_memory: |
2748 | w9968cf_deallocate_memory(cam); | 2754 | w9968cf_deallocate_memory(cam); |
2749 | DBG(2, "Failed to open the video device") | 2755 | DBG(2, "Failed to open the video device") |
2750 | up(&cam->dev_sem); | 2756 | mutex_unlock(&cam->dev_mutex); |
2751 | up_read(&w9968cf_disconnect); | 2757 | up_read(&w9968cf_disconnect); |
2752 | return err; | 2758 | return err; |
2753 | } | 2759 | } |
@@ -2759,13 +2765,13 @@ static int w9968cf_release(struct inode* inode, struct file* filp) | |||
2759 | 2765 | ||
2760 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | 2766 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); |
2761 | 2767 | ||
2762 | down(&cam->dev_sem); /* prevent disconnect() to be called */ | 2768 | mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */ |
2763 | 2769 | ||
2764 | w9968cf_stop_transfer(cam); | 2770 | w9968cf_stop_transfer(cam); |
2765 | 2771 | ||
2766 | if (cam->disconnected) { | 2772 | if (cam->disconnected) { |
2767 | w9968cf_release_resources(cam); | 2773 | w9968cf_release_resources(cam); |
2768 | up(&cam->dev_sem); | 2774 | mutex_unlock(&cam->dev_mutex); |
2769 | kfree(cam); | 2775 | kfree(cam); |
2770 | return 0; | 2776 | return 0; |
2771 | } | 2777 | } |
@@ -2775,7 +2781,7 @@ static int w9968cf_release(struct inode* inode, struct file* filp) | |||
2775 | wake_up_interruptible_nr(&cam->open, 1); | 2781 | wake_up_interruptible_nr(&cam->open, 1); |
2776 | 2782 | ||
2777 | DBG(5, "Video device closed") | 2783 | DBG(5, "Video device closed") |
2778 | up(&cam->dev_sem); | 2784 | mutex_unlock(&cam->dev_mutex); |
2779 | return 0; | 2785 | return 0; |
2780 | } | 2786 | } |
2781 | 2787 | ||
@@ -2792,18 +2798,18 @@ w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | |||
2792 | if (filp->f_flags & O_NONBLOCK) | 2798 | if (filp->f_flags & O_NONBLOCK) |
2793 | return -EWOULDBLOCK; | 2799 | return -EWOULDBLOCK; |
2794 | 2800 | ||
2795 | if (down_interruptible(&cam->fileop_sem)) | 2801 | if (mutex_lock_interruptible(&cam->fileop_mutex)) |
2796 | return -ERESTARTSYS; | 2802 | return -ERESTARTSYS; |
2797 | 2803 | ||
2798 | if (cam->disconnected) { | 2804 | if (cam->disconnected) { |
2799 | DBG(2, "Device not present") | 2805 | DBG(2, "Device not present") |
2800 | up(&cam->fileop_sem); | 2806 | mutex_unlock(&cam->fileop_mutex); |
2801 | return -ENODEV; | 2807 | return -ENODEV; |
2802 | } | 2808 | } |
2803 | 2809 | ||
2804 | if (cam->misconfigured) { | 2810 | if (cam->misconfigured) { |
2805 | DBG(2, "The camera is misconfigured. Close and open it again.") | 2811 | DBG(2, "The camera is misconfigured. Close and open it again.") |
2806 | up(&cam->fileop_sem); | 2812 | mutex_unlock(&cam->fileop_mutex); |
2807 | return -EIO; | 2813 | return -EIO; |
2808 | } | 2814 | } |
2809 | 2815 | ||
@@ -2818,11 +2824,11 @@ w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | |||
2818 | cam->frame[1].status == F_READY || | 2824 | cam->frame[1].status == F_READY || |
2819 | cam->disconnected); | 2825 | cam->disconnected); |
2820 | if (err) { | 2826 | if (err) { |
2821 | up(&cam->fileop_sem); | 2827 | mutex_unlock(&cam->fileop_mutex); |
2822 | return err; | 2828 | return err; |
2823 | } | 2829 | } |
2824 | if (cam->disconnected) { | 2830 | if (cam->disconnected) { |
2825 | up(&cam->fileop_sem); | 2831 | mutex_unlock(&cam->fileop_mutex); |
2826 | return -ENODEV; | 2832 | return -ENODEV; |
2827 | } | 2833 | } |
2828 | 2834 | ||
@@ -2836,7 +2842,7 @@ w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | |||
2836 | 2842 | ||
2837 | if (copy_to_user(buf, fr->buffer, count)) { | 2843 | if (copy_to_user(buf, fr->buffer, count)) { |
2838 | fr->status = F_UNUSED; | 2844 | fr->status = F_UNUSED; |
2839 | up(&cam->fileop_sem); | 2845 | mutex_unlock(&cam->fileop_mutex); |
2840 | return -EFAULT; | 2846 | return -EFAULT; |
2841 | } | 2847 | } |
2842 | *f_pos += count; | 2848 | *f_pos += count; |
@@ -2845,7 +2851,7 @@ w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos) | |||
2845 | 2851 | ||
2846 | DBG(5, "%zu bytes read", count) | 2852 | DBG(5, "%zu bytes read", count) |
2847 | 2853 | ||
2848 | up(&cam->fileop_sem); | 2854 | mutex_unlock(&cam->fileop_mutex); |
2849 | return count; | 2855 | return count; |
2850 | } | 2856 | } |
2851 | 2857 | ||
@@ -2899,24 +2905,24 @@ w9968cf_ioctl(struct inode* inode, struct file* filp, | |||
2899 | 2905 | ||
2900 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); | 2906 | cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp)); |
2901 | 2907 | ||
2902 | if (down_interruptible(&cam->fileop_sem)) | 2908 | if (mutex_lock_interruptible(&cam->fileop_mutex)) |
2903 | return -ERESTARTSYS; | 2909 | return -ERESTARTSYS; |
2904 | 2910 | ||
2905 | if (cam->disconnected) { | 2911 | if (cam->disconnected) { |
2906 | DBG(2, "Device not present") | 2912 | DBG(2, "Device not present") |
2907 | up(&cam->fileop_sem); | 2913 | mutex_unlock(&cam->fileop_mutex); |
2908 | return -ENODEV; | 2914 | return -ENODEV; |
2909 | } | 2915 | } |
2910 | 2916 | ||
2911 | if (cam->misconfigured) { | 2917 | if (cam->misconfigured) { |
2912 | DBG(2, "The camera is misconfigured. Close and open it again.") | 2918 | DBG(2, "The camera is misconfigured. Close and open it again.") |
2913 | up(&cam->fileop_sem); | 2919 | mutex_unlock(&cam->fileop_mutex); |
2914 | return -EIO; | 2920 | return -EIO; |
2915 | } | 2921 | } |
2916 | 2922 | ||
2917 | err = w9968cf_v4l_ioctl(inode, filp, cmd, (void __user *)arg); | 2923 | err = w9968cf_v4l_ioctl(inode, filp, cmd, (void __user *)arg); |
2918 | 2924 | ||
2919 | up(&cam->fileop_sem); | 2925 | mutex_unlock(&cam->fileop_mutex); |
2920 | return err; | 2926 | return err; |
2921 | } | 2927 | } |
2922 | 2928 | ||
@@ -3499,14 +3505,12 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
3499 | return -ENODEV; | 3505 | return -ENODEV; |
3500 | 3506 | ||
3501 | cam = (struct w9968cf_device*) | 3507 | cam = (struct w9968cf_device*) |
3502 | kmalloc(sizeof(struct w9968cf_device), GFP_KERNEL); | 3508 | kzalloc(sizeof(struct w9968cf_device), GFP_KERNEL); |
3503 | if (!cam) | 3509 | if (!cam) |
3504 | return -ENOMEM; | 3510 | return -ENOMEM; |
3505 | 3511 | ||
3506 | memset(cam, 0, sizeof(*cam)); | 3512 | mutex_init(&cam->dev_mutex); |
3507 | 3513 | mutex_lock(&cam->dev_mutex); | |
3508 | init_MUTEX(&cam->dev_sem); | ||
3509 | down(&cam->dev_sem); | ||
3510 | 3514 | ||
3511 | cam->usbdev = udev; | 3515 | cam->usbdev = udev; |
3512 | /* NOTE: a local copy is used to avoid possible race conditions */ | 3516 | /* NOTE: a local copy is used to avoid possible race conditions */ |
@@ -3518,10 +3522,10 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
3518 | simcams = W9968CF_SIMCAMS; | 3522 | simcams = W9968CF_SIMCAMS; |
3519 | 3523 | ||
3520 | /* How many cameras are connected ? */ | 3524 | /* How many cameras are connected ? */ |
3521 | down(&w9968cf_devlist_sem); | 3525 | mutex_lock(&w9968cf_devlist_mutex); |
3522 | list_for_each(ptr, &w9968cf_dev_list) | 3526 | list_for_each(ptr, &w9968cf_dev_list) |
3523 | sc++; | 3527 | sc++; |
3524 | up(&w9968cf_devlist_sem); | 3528 | mutex_unlock(&w9968cf_devlist_mutex); |
3525 | 3529 | ||
3526 | if (sc >= simcams) { | 3530 | if (sc >= simcams) { |
3527 | DBG(2, "Device rejected: too many connected cameras " | 3531 | DBG(2, "Device rejected: too many connected cameras " |
@@ -3532,21 +3536,19 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
3532 | 3536 | ||
3533 | 3537 | ||
3534 | /* Allocate 2 bytes of memory for camera control USB transfers */ | 3538 | /* Allocate 2 bytes of memory for camera control USB transfers */ |
3535 | if (!(cam->control_buffer = kmalloc(2, GFP_KERNEL))) { | 3539 | if (!(cam->control_buffer = kzalloc(2, GFP_KERNEL))) { |
3536 | DBG(1,"Couldn't allocate memory for camera control transfers") | 3540 | DBG(1,"Couldn't allocate memory for camera control transfers") |
3537 | err = -ENOMEM; | 3541 | err = -ENOMEM; |
3538 | goto fail; | 3542 | goto fail; |
3539 | } | 3543 | } |
3540 | memset(cam->control_buffer, 0, 2); | ||
3541 | 3544 | ||
3542 | /* Allocate 8 bytes of memory for USB data transfers to the FSB */ | 3545 | /* Allocate 8 bytes of memory for USB data transfers to the FSB */ |
3543 | if (!(cam->data_buffer = kmalloc(8, GFP_KERNEL))) { | 3546 | if (!(cam->data_buffer = kzalloc(8, GFP_KERNEL))) { |
3544 | DBG(1, "Couldn't allocate memory for data " | 3547 | DBG(1, "Couldn't allocate memory for data " |
3545 | "transfers to the FSB") | 3548 | "transfers to the FSB") |
3546 | err = -ENOMEM; | 3549 | err = -ENOMEM; |
3547 | goto fail; | 3550 | goto fail; |
3548 | } | 3551 | } |
3549 | memset(cam->data_buffer, 0, 8); | ||
3550 | 3552 | ||
3551 | /* Register the V4L device */ | 3553 | /* Register the V4L device */ |
3552 | cam->v4ldev = video_device_alloc(); | 3554 | cam->v4ldev = video_device_alloc(); |
@@ -3583,9 +3585,9 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
3583 | w9968cf_configure_camera(cam, udev, mod_id, dev_nr); | 3585 | w9968cf_configure_camera(cam, udev, mod_id, dev_nr); |
3584 | 3586 | ||
3585 | /* Add a new entry into the list of V4L registered devices */ | 3587 | /* Add a new entry into the list of V4L registered devices */ |
3586 | down(&w9968cf_devlist_sem); | 3588 | mutex_lock(&w9968cf_devlist_mutex); |
3587 | list_add(&cam->v4llist, &w9968cf_dev_list); | 3589 | list_add(&cam->v4llist, &w9968cf_dev_list); |
3588 | up(&w9968cf_devlist_sem); | 3590 | mutex_unlock(&w9968cf_devlist_mutex); |
3589 | 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; |
3590 | 3592 | ||
3591 | w9968cf_turn_on_led(cam); | 3593 | w9968cf_turn_on_led(cam); |
@@ -3593,7 +3595,7 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id) | |||
3593 | w9968cf_i2c_init(cam); | 3595 | w9968cf_i2c_init(cam); |
3594 | 3596 | ||
3595 | usb_set_intfdata(intf, cam); | 3597 | usb_set_intfdata(intf, cam); |
3596 | up(&cam->dev_sem); | 3598 | mutex_unlock(&cam->dev_mutex); |
3597 | return 0; | 3599 | return 0; |
3598 | 3600 | ||
3599 | fail: /* Free unused memory */ | 3601 | fail: /* Free unused memory */ |
@@ -3601,7 +3603,7 @@ fail: /* Free unused memory */ | |||
3601 | kfree(cam->data_buffer); | 3603 | kfree(cam->data_buffer); |
3602 | if (cam->v4ldev) | 3604 | if (cam->v4ldev) |
3603 | video_device_release(cam->v4ldev); | 3605 | video_device_release(cam->v4ldev); |
3604 | up(&cam->dev_sem); | 3606 | mutex_unlock(&cam->dev_mutex); |
3605 | kfree(cam); | 3607 | kfree(cam); |
3606 | return err; | 3608 | return err; |
3607 | } | 3609 | } |
@@ -3616,7 +3618,7 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf) | |||
3616 | 3618 | ||
3617 | if (cam) { | 3619 | if (cam) { |
3618 | /* Prevent concurrent accesses to data */ | 3620 | /* Prevent concurrent accesses to data */ |
3619 | down(&cam->dev_sem); | 3621 | mutex_lock(&cam->dev_mutex); |
3620 | 3622 | ||
3621 | cam->disconnected = 1; | 3623 | cam->disconnected = 1; |
3622 | 3624 | ||
@@ -3635,7 +3637,7 @@ static void w9968cf_usb_disconnect(struct usb_interface* intf) | |||
3635 | } else | 3637 | } else |
3636 | w9968cf_release_resources(cam); | 3638 | w9968cf_release_resources(cam); |
3637 | 3639 | ||
3638 | up(&cam->dev_sem); | 3640 | mutex_unlock(&cam->dev_mutex); |
3639 | 3641 | ||
3640 | if (!cam->users) | 3642 | if (!cam->users) |
3641 | kfree(cam); | 3643 | kfree(cam); |