]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/media/video/stk-webcam.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/lethal/sh-2.6
[linux-2.6-omap-h63xx.git] / drivers / media / video / stk-webcam.c
index f308c38d744fb2e7747328baf339492282ca8beb..e9eb6d754d5c85db037e9d41fa398a1e2589830a 100644 (file)
 #include <linux/kernel.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
-#include <linux/kref.h>
 
 #include <linux/usb.h>
 #include <linux/mm.h>
 #include <linux/vmalloc.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
 
 #include "stk-webcam.h"
 
@@ -64,22 +64,6 @@ static struct usb_device_id stkwebcam_table[] = {
 };
 MODULE_DEVICE_TABLE(usb, stkwebcam_table);
 
-static void stk_camera_cleanup(struct kref *kref)
-{
-       struct stk_camera *dev = to_stk_camera(kref);
-
-       STK_INFO("Syntek USB2.0 Camera release resources"
-               " video device /dev/video%d\n", dev->vdev.minor);
-       video_unregister_device(&dev->vdev);
-       dev->vdev.priv = NULL;
-
-       if (dev->sio_bufs != NULL || dev->isobufs != NULL)
-               STK_ERROR("We are leaking memory\n");
-       usb_put_intf(dev->interface);
-       kfree(dev);
-}
-
-
 /*
  * Basic stuff
  */
@@ -340,17 +324,19 @@ static int stk_create_sysfs_files(struct video_device *vdev)
 {
        int ret;
 
-       ret = video_device_create_file(vdev, &dev_attr_brightness);
-       ret += video_device_create_file(vdev, &dev_attr_hflip);
-       ret += video_device_create_file(vdev, &dev_attr_vflip);
+       ret = device_create_file(&vdev->dev, &dev_attr_brightness);
+       ret += device_create_file(&vdev->dev, &dev_attr_hflip);
+       ret += device_create_file(&vdev->dev, &dev_attr_vflip);
+       if (ret)
+               STK_WARNING("Could not create sysfs files\n");
        return ret;
 }
 
 static void stk_remove_sysfs_files(struct video_device *vdev)
 {
-       video_device_remove_file(vdev, &dev_attr_brightness);
-       video_device_remove_file(vdev, &dev_attr_hflip);
-       video_device_remove_file(vdev, &dev_attr_vflip);
+       device_remove_file(&vdev->dev, &dev_attr_brightness);
+       device_remove_file(&vdev->dev, &dev_attr_hflip);
+       device_remove_file(&vdev->dev, &dev_attr_vflip);
 }
 
 #else
@@ -442,18 +428,19 @@ static void stk_isoc_handler(struct urb *urb)
                                fb->v4lbuf.bytesused = 0;
                                fill = fb->buffer;
                        } else if (fb->v4lbuf.bytesused == dev->frame_size) {
-                               list_move_tail(dev->sio_avail.next,
-                                       &dev->sio_full);
-                               wake_up(&dev->wait_frame);
-                               if (list_empty(&dev->sio_avail)) {
-                                       (void) (printk_ratelimit() &&
-                                       STK_ERROR("No buffer available\n"));
-                                       goto resubmit;
+                               if (list_is_singular(&dev->sio_avail)) {
+                                       /* Always reuse the last buffer */
+                                       fb->v4lbuf.bytesused = 0;
+                                       fill = fb->buffer;
+                               } else {
+                                       list_move_tail(dev->sio_avail.next,
+                                               &dev->sio_full);
+                                       wake_up(&dev->wait_frame);
+                                       fb = list_first_entry(&dev->sio_avail,
+                                               struct stk_sio_buffer, list);
+                                       fb->v4lbuf.bytesused = 0;
+                                       fill = fb->buffer;
                                }
-                               fb = list_first_entry(&dev->sio_avail,
-                                       struct stk_sio_buffer, list);
-                               fb->v4lbuf.bytesused = 0;
-                               fill = fb->buffer;
                        }
                } else {
                        framelen -= 4;
@@ -572,7 +559,7 @@ static void stk_clean_iso(struct stk_camera *dev)
 
                urb = dev->isobufs[i].urb;
                if (urb) {
-                       if (atomic_read(&dev->urbs_used))
+                       if (atomic_read(&dev->urbs_used) && is_present(dev))
                                usb_kill_urb(urb);
                        usb_free_urb(urb);
                }
@@ -685,45 +672,30 @@ static int v4l_stk_open(struct inode *inode, struct file *fp)
        vdev = video_devdata(fp);
        dev = vdev_to_camera(vdev);
 
-       if (dev == NULL || !is_present(dev))
+       lock_kernel();
+       if (dev == NULL || !is_present(dev)) {
+               unlock_kernel();
                return -ENXIO;
-       fp->private_data = vdev;
-       kref_get(&dev->kref);
+       }
+       fp->private_data = dev;
        usb_autopm_get_interface(dev->interface);
+       unlock_kernel();
 
        return 0;
 }
 
 static int v4l_stk_release(struct inode *inode, struct file *fp)
 {
-       struct stk_camera *dev;
-       struct video_device *vdev;
+       struct stk_camera *dev = fp->private_data;
 
-       vdev = video_devdata(fp);
-       if (vdev == NULL) {
-               STK_ERROR("v4l_release called w/o video devdata\n");
-               return -EFAULT;
-       }
-       dev = vdev_to_camera(vdev);
-       if (dev == NULL) {
-               STK_ERROR("v4l_release called on removed device\n");
-               return -ENODEV;
+       if (dev->owner == fp) {
+               stk_stop_stream(dev);
+               stk_free_buffers(dev);
+               dev->owner = NULL;
        }
 
-       if (dev->owner != fp) {
+       if(is_present(dev))
                usb_autopm_put_interface(dev->interface);
-               kref_put(&dev->kref, stk_camera_cleanup);
-               return 0;
-       }
-
-       stk_stop_stream(dev);
-
-       stk_free_buffers(dev);
-
-       dev->owner = NULL;
-
-       usb_autopm_put_interface(dev->interface);
-       kref_put(&dev->kref, stk_camera_cleanup);
 
        return 0;
 }
@@ -734,17 +706,8 @@ static ssize_t v4l_stk_read(struct file *fp, char __user *buf,
        int i;
        int ret;
        unsigned long flags;
-       struct stk_camera *dev;
-       struct video_device *vdev;
        struct stk_sio_buffer *sbuf;
-
-       vdev = video_devdata(fp);
-       if (vdev == NULL)
-               return -EFAULT;
-       dev = vdev_to_camera(vdev);
-
-       if (dev == NULL)
-               return -EIO;
+       struct stk_camera *dev = fp->private_data;
 
        if (!is_present(dev))
                return -EIO;
@@ -800,17 +763,7 @@ static ssize_t v4l_stk_read(struct file *fp, char __user *buf,
 
 static unsigned int v4l_stk_poll(struct file *fp, poll_table *wait)
 {
-       struct stk_camera *dev;
-       struct video_device *vdev;
-
-       vdev = video_devdata(fp);
-
-       if (vdev == NULL)
-               return -EFAULT;
-
-       dev = vdev_to_camera(vdev);
-       if (dev == NULL)
-               return -ENODEV;
+       struct stk_camera *dev = fp->private_data;
 
        poll_wait(fp, &dev->wait_frame, wait);
 
@@ -846,16 +799,12 @@ static int v4l_stk_mmap(struct file *fp, struct vm_area_struct *vma)
        unsigned int i;
        int ret;
        unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-       struct stk_camera *dev;
-       struct video_device *vdev;
+       struct stk_camera *dev = fp->private_data;
        struct stk_sio_buffer *sbuf = NULL;
 
        if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
                return -EINVAL;
 
-       vdev = video_devdata(fp);
-       dev = vdev_to_camera(vdev);
-
        for (i = 0; i < dev->n_sbufs; i++) {
                if (dev->sio_bufs[i].v4lbuf.m.offset == offset) {
                        sbuf = dev->sio_bufs + i;
@@ -1327,20 +1276,7 @@ static struct file_operations v4l_stk_fops = {
        .llseek = no_llseek
 };
 
-static void stk_v4l_dev_release(struct video_device *vd)
-{
-}
-
-static struct video_device stk_v4l_data = {
-       .name = "stkwebcam",
-       .type = VFL_TYPE_GRABBER,
-       .type2 = VID_TYPE_CAPTURE,
-       .minor = -1,
-       .tvnorms = V4L2_STD_UNKNOWN,
-       .current_norm = V4L2_STD_UNKNOWN,
-       .fops = &v4l_stk_fops,
-       .release = stk_v4l_dev_release,
-
+static const struct v4l2_ioctl_ops v4l_stk_ioctl_ops = {
        .vidioc_querycap = stk_vidioc_querycap,
        .vidioc_enum_fmt_vid_cap = stk_vidioc_enum_fmt_vid_cap,
        .vidioc_try_fmt_vid_cap = stk_vidioc_try_fmt_vid_cap,
@@ -1362,6 +1298,26 @@ static struct video_device stk_v4l_data = {
        .vidioc_g_parm = stk_vidioc_g_parm,
 };
 
+static void stk_v4l_dev_release(struct video_device *vd)
+{
+       struct stk_camera *dev = vdev_to_camera(vd);
+
+       if (dev->sio_bufs != NULL || dev->isobufs != NULL)
+               STK_ERROR("We are leaking memory\n");
+       usb_put_intf(dev->interface);
+       kfree(dev);
+}
+
+static struct video_device stk_v4l_data = {
+       .name = "stkwebcam",
+       .minor = -1,
+       .tvnorms = V4L2_STD_UNKNOWN,
+       .current_norm = V4L2_STD_UNKNOWN,
+       .fops = &v4l_stk_fops,
+       .ioctl_ops = &v4l_stk_ioctl_ops,
+       .release = stk_v4l_dev_release,
+};
+
 
 static int stk_register_video_device(struct stk_camera *dev)
 {
@@ -1369,14 +1325,13 @@ static int stk_register_video_device(struct stk_camera *dev)
 
        dev->vdev = stk_v4l_data;
        dev->vdev.debug = debug;
-       dev->vdev.dev = &dev->interface->dev;
-       dev->vdev.priv = dev;
+       dev->vdev.parent = &dev->interface->dev;
        err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1);
        if (err)
                STK_ERROR("v4l registration failed\n");
        else
                STK_INFO("Syntek USB2.0 Camera is now controlling video device"
-                       " /dev/video%d\n", dev->vdev.minor);
+                       " /dev/video%d\n", dev->vdev.num);
        return err;
 }
 
@@ -1387,7 +1342,7 @@ static int stk_camera_probe(struct usb_interface *interface,
                const struct usb_device_id *id)
 {
        int i;
-       int err;
+       int err = 0;
 
        struct stk_camera *dev = NULL;
        struct usb_device *udev = interface_to_usbdev(interface);
@@ -1400,7 +1355,6 @@ static int stk_camera_probe(struct usb_interface *interface,
                return -ENOMEM;
        }
 
-       kref_init(&dev->kref);
        spin_lock_init(&dev->spinlock);
        init_waitqueue_head(&dev->wait_frame);
 
@@ -1433,8 +1387,8 @@ static int stk_camera_probe(struct usb_interface *interface,
        }
        if (!dev->isoc_ep) {
                STK_ERROR("Could not find isoc-in endpoint");
-               kref_put(&dev->kref, stk_camera_cleanup);
-               return -ENODEV;
+               err = -ENODEV;
+               goto error;
        }
        dev->vsettings.brightness = 0x7fff;
        dev->vsettings.palette = V4L2_PIX_FMT_RGB565;
@@ -1448,14 +1402,17 @@ static int stk_camera_probe(struct usb_interface *interface,
 
        err = stk_register_video_device(dev);
        if (err) {
-               kref_put(&dev->kref, stk_camera_cleanup);
-               return err;
+               goto error;
        }
 
        stk_create_sysfs_files(&dev->vdev);
        usb_autopm_enable(dev->interface);
 
        return 0;
+
+error:
+       kfree(dev);
+       return err;
 }
 
 static void stk_camera_disconnect(struct usb_interface *interface)
@@ -1468,7 +1425,10 @@ static void stk_camera_disconnect(struct usb_interface *interface)
        wake_up_interruptible(&dev->wait_frame);
        stk_remove_sysfs_files(&dev->vdev);
 
-       kref_put(&dev->kref, stk_camera_cleanup);
+       STK_INFO("Syntek USB2.0 Camera release resources "
+               "video device /dev/video%d\n", dev->vdev.num);
+
+       video_unregister_device(&dev->vdev);
 }
 
 #ifdef CONFIG_PM