#include <linux/highmem.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
#include <media/videobuf-vmalloc.h>
struct zr364xx_camera {
struct usb_device *udev; /* save off the usb device pointer */
struct usb_interface *interface;/* the interface for this device */
+ struct v4l2_device v4l2_dev;
struct video_device vdev; /* v4l video device */
int nb;
struct zr364xx_bufferi buffer;
int height;
int method;
struct mutex lock;
- struct mutex open_lock;
int users;
spinlock_t slock;
transfer_buffer, size, CTRL_TIMEOUT);
kfree(transfer_buffer);
-
- if (status < 0)
- dev_err(&udev->dev,
- "Failed sending control message, error %d.\n", status);
-
return status;
}
loff_t * ppos)
{
struct zr364xx_camera *cam = video_drvdata(file);
+ int err = 0;
_DBG("%s\n", __func__);
if (!count)
return -EINVAL;
+ if (mutex_lock_interruptible(&cam->lock))
+ return -ERESTARTSYS;
+
if (cam->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
zr364xx_vidioc_streamon(file, cam, cam->type) == 0) {
DBG("%s: reading %d bytes at pos %d.\n", __func__, (int) count,
(int) *ppos);
/* NoMan Sux ! */
- return videobuf_read_one(&cam->vb_vidq, buf, count, ppos,
+ err = videobuf_read_one(&cam->vb_vidq, buf, count, ppos,
file->f_flags & O_NONBLOCK);
}
-
- return 0;
+ mutex_unlock(&cam->lock);
+ return err;
}
/* video buffer vmalloc implementation based partly on VIVI driver which is
static int res_get(struct zr364xx_camera *cam)
{
/* is it free? */
- mutex_lock(&cam->lock);
if (cam->resources) {
/* no, someone else uses it */
- mutex_unlock(&cam->lock);
return 0;
}
/* it's free, grab it */
cam->resources = 1;
_DBG("res: get\n");
- mutex_unlock(&cam->lock);
return 1;
}
static void res_free(struct zr364xx_camera *cam)
{
- mutex_lock(&cam->lock);
cam->resources = 0;
- mutex_unlock(&cam->lock);
_DBG("res: put\n");
}
case V4L2_CID_BRIGHTNESS:
cam->mode.brightness = c->value;
/* hardware brightness */
- mutex_lock(&cam->lock);
send_control_msg(cam->udev, 1, 0x2001, 0, NULL, 0);
temp = (0x60 << 8) + 127 - cam->mode.brightness;
send_control_msg(cam->udev, 1, temp, 0, NULL, 0);
- mutex_unlock(&cam->lock);
break;
default:
return -EINVAL;
DBG("%s\n", __func__);
- mutex_lock(&cam->open_lock);
+ if (mutex_lock_interruptible(&cam->lock))
+ return -ERESTARTSYS;
if (cam->users) {
err = -EBUSY;
NULL, &cam->slock,
cam->type,
V4L2_FIELD_NONE,
- sizeof(struct zr364xx_buffer), cam, NULL);
+ sizeof(struct zr364xx_buffer), cam, &cam->lock);
/* Added some delay here, since opening/closing the camera quickly,
* like Ekiga does during its startup, can crash the webcam
err = 0;
out:
- mutex_unlock(&cam->open_lock);
+ mutex_unlock(&cam->lock);
DBG("%s: %d\n", __func__, err);
return err;
}
-static void zr364xx_destroy(struct zr364xx_camera *cam)
+static void zr364xx_release(struct v4l2_device *v4l2_dev)
{
+ struct zr364xx_camera *cam =
+ container_of(v4l2_dev, struct zr364xx_camera, v4l2_dev);
unsigned long i;
- if (!cam) {
- printk(KERN_ERR KBUILD_MODNAME ", %s: no device\n", __func__);
- return;
- }
- mutex_lock(&cam->open_lock);
- video_unregister_device(&cam->vdev);
-
- /* stops the read pipe if it is running */
- if (cam->b_acquire)
- zr364xx_stop_acquire(cam);
+ v4l2_device_unregister(&cam->v4l2_dev);
- zr364xx_stop_readpipe(cam);
+ videobuf_mmap_free(&cam->vb_vidq);
/* release sys buffers */
for (i = 0; i < FRAMES; i++) {
/* release transfer buffer */
kfree(cam->pipe->transfer_buffer);
- cam->pipe->transfer_buffer = NULL;
- mutex_unlock(&cam->open_lock);
kfree(cam);
}
/* release the camera */
-static int zr364xx_release(struct file *file)
+static int zr364xx_close(struct file *file)
{
struct zr364xx_camera *cam;
struct usb_device *udev;
- int i, err;
+ int i;
DBG("%s\n", __func__);
cam = video_drvdata(file);
- if (!cam)
- return -ENODEV;
-
- mutex_lock(&cam->open_lock);
+ mutex_lock(&cam->lock);
udev = cam->udev;
/* turn off stream */
file->private_data = NULL;
for (i = 0; i < 2; i++) {
- err =
- send_control_msg(udev, 1, init[cam->method][i].value,
+ send_control_msg(udev, 1, init[cam->method][i].value,
0, init[cam->method][i].bytes,
init[cam->method][i].size);
- if (err < 0) {
- dev_err(&udev->dev, "error during release sequence\n");
- goto out;
- }
}
/* Added some delay here, since opening/closing the camera quickly,
* like Ekiga does during its startup, can crash the webcam
*/
mdelay(100);
- err = 0;
-
-out:
- mutex_unlock(&cam->open_lock);
-
- return err;
+ mutex_unlock(&cam->lock);
+ return 0;
}
static const struct v4l2_file_operations zr364xx_fops = {
.owner = THIS_MODULE,
.open = zr364xx_open,
- .release = zr364xx_release,
+ .release = zr364xx_close,
.read = zr364xx_read,
.mmap = zr364xx_mmap,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.poll = zr364xx_poll,
};
dev_err(&udev->dev, "cam: out of memory !\n");
return -ENOMEM;
}
+
+ cam->v4l2_dev.release = zr364xx_release;
+ err = v4l2_device_register(&intf->dev, &cam->v4l2_dev);
+ if (err < 0) {
+ dev_err(&udev->dev, "couldn't register v4l2_device\n");
+ kfree(cam);
+ return err;
+ }
/* save the init method used by this camera */
cam->method = id->driver_info;
+ mutex_init(&cam->lock);
cam->vdev = zr364xx_template;
- cam->vdev.parent = &intf->dev;
+ cam->vdev.lock = &cam->lock;
+ cam->vdev.v4l2_dev = &cam->v4l2_dev;
video_set_drvdata(&cam->vdev, cam);
if (debug)
cam->vdev.debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
cam->users = 0;
cam->nb = 0;
cam->mode.brightness = 64;
- mutex_init(&cam->lock);
- mutex_init(&cam->open_lock);
DBG("dev: %p, udev %p interface %p\n", cam, cam->udev, intf);
if (!cam->read_endpoint) {
dev_err(&intf->dev, "Could not find bulk-in endpoint\n");
+ v4l2_device_unregister(&cam->v4l2_dev);
kfree(cam);
return -ENOMEM;
}
err = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
if (err) {
dev_err(&udev->dev, "video_register_device failed\n");
+ v4l2_device_unregister(&cam->v4l2_dev);
kfree(cam);
return err;
}
static void zr364xx_disconnect(struct usb_interface *intf)
{
struct zr364xx_camera *cam = usb_get_intfdata(intf);
- videobuf_mmap_free(&cam->vb_vidq);
+
+ mutex_lock(&cam->lock);
usb_set_intfdata(intf, NULL);
dev_info(&intf->dev, DRIVER_DESC " webcam unplugged\n");
- zr364xx_destroy(cam);
+ video_unregister_device(&cam->vdev);
+ v4l2_device_disconnect(&cam->v4l2_dev);
+
+ /* stops the read pipe if it is running */
+ if (cam->b_acquire)
+ zr364xx_stop_acquire(cam);
+
+ zr364xx_stop_readpipe(cam);
+ mutex_unlock(&cam->lock);
+ v4l2_device_put(&cam->v4l2_dev);
}