Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3b2ae0be authored by Luca Risolia's avatar Luca Risolia Committed by Mauro Carvalho Chehab
Browse files

V4L/DVB (5766): ET61x251 driver updates



- Make the driver depend on V4L2 only (KConfig)
- Better and safe locking mechanism of the device structure on open(),
  close() and disconnect()
- Use kref for handling device deallocation
- Generic cleanups

Signed-off-by: default avatarLuca Risolia <luca.risolia@studio.unibo.it>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 3770be34
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
config USB_ET61X251
config USB_ET61X251
	tristate "USB ET61X[12]51 PC Camera Controller support"
	tristate "USB ET61X[12]51 PC Camera Controller support"
	depends on VIDEO_V4L1
	depends on VIDEO_V4L2
	---help---
	---help---
	  Say Y here if you want support for cameras based on Etoms ET61X151
	  Say Y here if you want support for cameras based on Etoms ET61X151
	  or ET61X251 PC Camera Controllers.
	  or ET61X251 PC Camera Controllers.
+13 −10
Original line number Original line Diff line number Diff line
@@ -36,6 +36,7 @@
#include <linux/mutex.h>
#include <linux/mutex.h>
#include <linux/stddef.h>
#include <linux/stddef.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/kref.h>


#include "et61x251_sensor.h"
#include "et61x251_sensor.h"


@@ -134,7 +135,7 @@ struct et61x251_module_param {
};
};


static DEFINE_MUTEX(et61x251_sysfs_lock);
static DEFINE_MUTEX(et61x251_sysfs_lock);
static DECLARE_RWSEM(et61x251_disconnect);
static DECLARE_RWSEM(et61x251_dev_lock);


struct et61x251_device {
struct et61x251_device {
	struct video_device* v4ldev;
	struct video_device* v4ldev;
@@ -158,12 +159,14 @@ struct et61x251_device {
	struct et61x251_sysfs_attr sysfs;
	struct et61x251_sysfs_attr sysfs;
	struct et61x251_module_param module_param;
	struct et61x251_module_param module_param;


	struct kref kref;
	enum et61x251_dev_state state;
	enum et61x251_dev_state state;
	u8 users;
	u8 users;


	struct mutex dev_mutex, fileop_mutex;
	struct completion probe;
	struct mutex open_mutex, fileop_mutex;
	spinlock_t queue_lock;
	spinlock_t queue_lock;
	wait_queue_head_t open, wait_frame, wait_stream;
	wait_queue_head_t wait_open, wait_frame, wait_stream;
};
};


/*****************************************************************************/
/*****************************************************************************/
@@ -177,7 +180,7 @@ et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id)


void
void
et61x251_attach_sensor(struct et61x251_device* cam,
et61x251_attach_sensor(struct et61x251_device* cam,
		       struct et61x251_sensor* sensor)
		       const struct et61x251_sensor* sensor)
{
{
	memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor));
	memcpy(&cam->sensor, sensor, sizeof(struct et61x251_sensor));
}
}
@@ -195,8 +198,8 @@ do { \
		else if ((level) == 2)                                        \
		else if ((level) == 2)                                        \
			dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
			dev_info(&cam->usbdev->dev, fmt "\n", ## args);       \
		else if ((level) >= 3)                                        \
		else if ((level) >= 3)                                        \
			dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",      \
			dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n",   \
				 __FUNCTION__, __LINE__ , ## args);           \
				 __FILE__, __FUNCTION__, __LINE__ , ## args); \
	}                                                                     \
	}                                                                     \
} while (0)
} while (0)
#	define KDBG(level, fmt, args...)                                      \
#	define KDBG(level, fmt, args...)                                      \
@@ -205,8 +208,8 @@ do { \
		if ((level) == 1 || (level) == 2)                             \
		if ((level) == 1 || (level) == 2)                             \
			pr_info("et61x251: " fmt "\n", ## args);              \
			pr_info("et61x251: " fmt "\n", ## args);              \
		else if ((level) == 3)                                        \
		else if ((level) == 3)                                        \
			pr_debug("et61x251: [%s:%d] " fmt "\n", __FUNCTION__, \
			pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__,   \
				 __LINE__ , ## args);                         \
				 __FUNCTION__, __LINE__ , ## args);           \
	}                                                                     \
	}                                                                     \
} while (0)
} while (0)
#	define V4LDBG(level, name, cmd)                                       \
#	define V4LDBG(level, name, cmd)                                       \
@@ -222,8 +225,8 @@ do { \


#undef PDBG
#undef PDBG
#define PDBG(fmt, args...)                                                    \
#define PDBG(fmt, args...)                                                    \
dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n",                              \
dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__,   \
	 __FUNCTION__, __LINE__ , ## args)
	 __LINE__ , ## args)


#undef PDBGG
#undef PDBGG
#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
+101 −88
Original line number Original line Diff line number Diff line
@@ -45,11 +45,11 @@


#define ET61X251_MODULE_NAME    "V4L2 driver for ET61X[12]51 "                \
#define ET61X251_MODULE_NAME    "V4L2 driver for ET61X[12]51 "                \
				"PC Camera Controllers"
				"PC Camera Controllers"
#define ET61X251_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
#define ET61X251_MODULE_AUTHOR  "(C) 2006-2007 Luca Risolia"
#define ET61X251_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
#define ET61X251_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
#define ET61X251_MODULE_LICENSE "GPL"
#define ET61X251_MODULE_LICENSE "GPL"
#define ET61X251_MODULE_VERSION "1:1.04"
#define ET61X251_MODULE_VERSION "1:1.09"
#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 4)
#define ET61X251_MODULE_VERSION_CODE  KERNEL_VERSION(1, 1, 9)


/*****************************************************************************/
/*****************************************************************************/


@@ -245,7 +245,8 @@ int et61x251_read_reg(struct et61x251_device* cam, u16 index)




static int
static int
et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor)
et61x251_i2c_wait(struct et61x251_device* cam,
		  const struct et61x251_sensor* sensor)
{
{
	int i, r;
	int i, r;


@@ -270,7 +271,7 @@ et61x251_i2c_wait(struct et61x251_device* cam, struct et61x251_sensor* sensor)


int
int
et61x251_i2c_try_read(struct et61x251_device* cam,
et61x251_i2c_try_read(struct et61x251_device* cam,
		      struct et61x251_sensor* sensor, u8 address)
		      const struct et61x251_sensor* sensor, u8 address)
{
{
	struct usb_device* udev = cam->usbdev;
	struct usb_device* udev = cam->usbdev;
	u8* data = cam->control_buffer;
	u8* data = cam->control_buffer;
@@ -303,7 +304,8 @@ et61x251_i2c_try_read(struct et61x251_device* cam,


int
int
et61x251_i2c_try_write(struct et61x251_device* cam,
et61x251_i2c_try_write(struct et61x251_device* cam,
		       struct et61x251_sensor* sensor, u8 address, u8 value)
		       const struct et61x251_sensor* sensor, u8 address,
		       u8 value)
{
{
	struct usb_device* udev = cam->usbdev;
	struct usb_device* udev = cam->usbdev;
	u8* data = cam->control_buffer;
	u8* data = cam->control_buffer;
@@ -682,7 +684,7 @@ static u8 et61x251_strtou8(const char* buff, size_t len, ssize_t* count)


	if (len < 4) {
	if (len < 4) {
		strncpy(str, buff, len);
		strncpy(str, buff, len);
		str[len+1] = '\0';
		str[len] = '\0';
	} else {
	} else {
		strncpy(str, buff, 4);
		strncpy(str, buff, 4);
		str[4] = '\0';
		str[4] = '\0';
@@ -977,30 +979,30 @@ static CLASS_DEVICE_ATTR(i2c_val, S_IRUGO | S_IWUSR,


static int et61x251_create_sysfs(struct et61x251_device* cam)
static int et61x251_create_sysfs(struct et61x251_device* cam)
{
{
	struct video_device *v4ldev = cam->v4ldev;
	struct class_device *classdev = &(cam->v4ldev->class_dev);
	int err = 0;
	int err = 0;


	if ((err = video_device_create_file(v4ldev, &class_device_attr_reg)))
	if ((err = class_device_create_file(classdev, &class_device_attr_reg)))
		goto err_out;
		goto err_out;
	if ((err = video_device_create_file(v4ldev, &class_device_attr_val)))
	if ((err = class_device_create_file(classdev, &class_device_attr_val)))
		goto err_reg;
		goto err_reg;


	if (cam->sensor.sysfs_ops) {
	if (cam->sensor.sysfs_ops) {
		if ((err = video_device_create_file(v4ldev,
		if ((err = class_device_create_file(classdev,
						  &class_device_attr_i2c_reg)))
						  &class_device_attr_i2c_reg)))
			goto err_val;
			goto err_val;
		if ((err = video_device_create_file(v4ldev,
		if ((err = class_device_create_file(classdev,
						  &class_device_attr_i2c_val)))
						  &class_device_attr_i2c_val)))
			goto err_i2c_reg;
			goto err_i2c_reg;
	}
	}


err_i2c_reg:
err_i2c_reg:
	if (cam->sensor.sysfs_ops)
	if (cam->sensor.sysfs_ops)
	video_device_remove_file(v4ldev, &class_device_attr_i2c_reg);
		class_device_remove_file(classdev, &class_device_attr_i2c_reg);
err_val:
err_val:
	video_device_remove_file(v4ldev, &class_device_attr_val);
	class_device_remove_file(classdev, &class_device_attr_val);
err_reg:
err_reg:
	video_device_remove_file(v4ldev, &class_device_attr_reg);
	class_device_remove_file(classdev, &class_device_attr_reg);
err_out:
err_out:
	return err;
	return err;
}
}
@@ -1103,7 +1105,8 @@ static int et61x251_init(struct et61x251_device* cam)
	int err = 0;
	int err = 0;


	if (!(cam->state & DEV_INITIALIZED)) {
	if (!(cam->state & DEV_INITIALIZED)) {
		init_waitqueue_head(&cam->open);
		mutex_init(&cam->open_mutex);
		init_waitqueue_head(&cam->wait_open);
		qctrl = s->qctrl;
		qctrl = s->qctrl;
		rect = &(s->cropcap.defrect);
		rect = &(s->cropcap.defrect);
		cam->compression.quality = ET61X251_COMPRESSION_QUALITY;
		cam->compression.quality = ET61X251_COMPRESSION_QUALITY;
@@ -1177,64 +1180,80 @@ static int et61x251_init(struct et61x251_device* cam)
	return 0;
	return 0;
}
}


/*****************************************************************************/


static void et61x251_release_resources(struct et61x251_device* cam)
static void et61x251_release_resources(struct kref *kref)
{
{
	struct et61x251_device *cam;

	mutex_lock(&et61x251_sysfs_lock);
	mutex_lock(&et61x251_sysfs_lock);


	cam = container_of(kref, struct et61x251_device, kref);

	DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
	DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
	video_set_drvdata(cam->v4ldev, NULL);
	video_set_drvdata(cam->v4ldev, NULL);
	video_unregister_device(cam->v4ldev);
	video_unregister_device(cam->v4ldev);
	usb_put_dev(cam->usbdev);
	kfree(cam->control_buffer);
	kfree(cam);


	mutex_unlock(&et61x251_sysfs_lock);
	mutex_unlock(&et61x251_sysfs_lock);

	kfree(cam->control_buffer);
}
}


/*****************************************************************************/


static int et61x251_open(struct inode* inode, struct file* filp)
static int et61x251_open(struct inode* inode, struct file* filp)
{
{
	struct et61x251_device* cam;
	struct et61x251_device* cam;
	int err = 0;
	int err = 0;


	/*
	if (!down_read_trylock(&et61x251_dev_lock))
	   This is the only safe way to prevent race conditions with
	   disconnect
	*/
	if (!down_read_trylock(&et61x251_disconnect))
		return -ERESTARTSYS;
		return -ERESTARTSYS;


	cam = video_get_drvdata(video_devdata(filp));
	cam = video_get_drvdata(video_devdata(filp));


	if (mutex_lock_interruptible(&cam->dev_mutex)) {
	if (wait_for_completion_interruptible(&cam->probe)) {
		up_read(&et61x251_disconnect);
		up_read(&et61x251_dev_lock);
		return -ERESTARTSYS;
		return -ERESTARTSYS;
	}
	}


	kref_get(&cam->kref);

	if (mutex_lock_interruptible(&cam->open_mutex)) {
		kref_put(&cam->kref, et61x251_release_resources);
		up_read(&et61x251_dev_lock);
		return -ERESTARTSYS;
	}

	if (cam->state & DEV_DISCONNECTED) {
		DBG(1, "Device not present");
		err = -ENODEV;
		goto out;
	}

	if (cam->users) {
	if (cam->users) {
		DBG(2, "Device /dev/video%d is busy...", cam->v4ldev->minor);
		DBG(2, "Device /dev/video%d is already in use",
		       cam->v4ldev->minor);
		DBG(3, "Simultaneous opens are not supported");
		if ((filp->f_flags & O_NONBLOCK) ||
		if ((filp->f_flags & O_NONBLOCK) ||
		    (filp->f_flags & O_NDELAY)) {
		    (filp->f_flags & O_NDELAY)) {
			err = -EWOULDBLOCK;
			err = -EWOULDBLOCK;
			goto out;
			goto out;
		}
		}
		mutex_unlock(&cam->dev_mutex);
		DBG(2, "A blocking open() has been requested. Wait for the "
		err = wait_event_interruptible_exclusive(cam->open,
		       "device to be released...");
						  cam->state & DEV_DISCONNECTED
		up_read(&et61x251_dev_lock);
		err = wait_event_interruptible_exclusive(cam->wait_open,
						(cam->state & DEV_DISCONNECTED)
							 || !cam->users);
							 || !cam->users);
		if (err) {
		down_read(&et61x251_dev_lock);
			up_read(&et61x251_disconnect);
		if (err)
			return err;
			goto out;
		}
		if (cam->state & DEV_DISCONNECTED) {
		if (cam->state & DEV_DISCONNECTED) {
			up_read(&et61x251_disconnect);
			err = -ENODEV;
			return -ENODEV;
			goto out;
		}
		}
		mutex_lock(&cam->dev_mutex);
	}
	}



	if (cam->state & DEV_MISCONFIGURED) {
	if (cam->state & DEV_MISCONFIGURED) {
		err = et61x251_init(cam);
		err = et61x251_init(cam);
		if (err) {
		if (err) {
@@ -1259,36 +1278,32 @@ static int et61x251_open(struct inode* inode, struct file* filp)
	DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);
	DBG(3, "Video device /dev/video%d is open", cam->v4ldev->minor);


out:
out:
	mutex_unlock(&cam->dev_mutex);
	mutex_unlock(&cam->open_mutex);
	up_read(&et61x251_disconnect);
	if (err)
		kref_put(&cam->kref, et61x251_release_resources);
	up_read(&et61x251_dev_lock);
	return err;
	return err;
}
}




static int et61x251_release(struct inode* inode, struct file* filp)
static int et61x251_release(struct inode* inode, struct file* filp)
{
{
	struct et61x251_device* cam = video_get_drvdata(video_devdata(filp));
	struct et61x251_device* cam;


	mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
	down_write(&et61x251_dev_lock);


	et61x251_stop_transfer(cam);
	cam = video_get_drvdata(video_devdata(filp));


	et61x251_stop_transfer(cam);
	et61x251_release_buffers(cam);
	et61x251_release_buffers(cam);

	if (cam->state & DEV_DISCONNECTED) {
		et61x251_release_resources(cam);
		usb_put_dev(cam->usbdev);
		mutex_unlock(&cam->dev_mutex);
		kfree(cam);
		return 0;
	}

	cam->users--;
	cam->users--;
	wake_up_interruptible_nr(&cam->open, 1);
	wake_up_interruptible_nr(&cam->wait_open, 1);


	DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);
	DBG(3, "Video device /dev/video%d closed", cam->v4ldev->minor);


	mutex_unlock(&cam->dev_mutex);
	kref_put(&cam->kref, et61x251_release_resources);

	up_write(&et61x251_dev_lock);


	return 0;
	return 0;
}
}
@@ -1324,7 +1339,7 @@ et61x251_read(struct file* filp, char __user * buf,
		DBG(3, "Close and open the device again to choose the read "
		DBG(3, "Close and open the device again to choose the read "
		       "method");
		       "method");
		mutex_unlock(&cam->fileop_mutex);
		mutex_unlock(&cam->fileop_mutex);
		return -EINVAL;
		return -EBUSY;
	}
	}


	if (cam->io == IO_NONE) {
	if (cam->io == IO_NONE) {
@@ -1504,7 +1519,12 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)
		return -EIO;
		return -EIO;
	}
	}


	if (cam->io != IO_MMAP || !(vma->vm_flags & VM_WRITE) ||
	if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
		mutex_unlock(&cam->fileop_mutex);
		return -EACCES;
	}

	if (cam->io != IO_MMAP ||
	    size != PAGE_ALIGN(cam->frame[0].buf.length)) {
	    size != PAGE_ALIGN(cam->frame[0].buf.length)) {
		mutex_unlock(&cam->fileop_mutex);
		mutex_unlock(&cam->fileop_mutex);
		return -EINVAL;
		return -EINVAL;
@@ -1535,7 +1555,6 @@ static int et61x251_mmap(struct file* filp, struct vm_area_struct *vma)


	vma->vm_ops = &et61x251_vm_ops;
	vma->vm_ops = &et61x251_vm_ops;
	vma->vm_private_data = &cam->frame[i];
	vma->vm_private_data = &cam->frame[i];

	et61x251_vm_open(vma);
	et61x251_vm_open(vma);


	mutex_unlock(&cam->fileop_mutex);
	mutex_unlock(&cam->fileop_mutex);
@@ -1764,7 +1783,7 @@ et61x251_vidioc_s_crop(struct et61x251_device* cam, void __user * arg)
			if (cam->frame[i].vma_use_count) {
			if (cam->frame[i].vma_use_count) {
				DBG(3, "VIDIOC_S_CROP failed. "
				DBG(3, "VIDIOC_S_CROP failed. "
				       "Unmap the buffers first.");
				       "Unmap the buffers first.");
				return -EINVAL;
				return -EBUSY;
			}
			}


	/* Preserve R,G or B origin */
	/* Preserve R,G or B origin */
@@ -1921,6 +1940,8 @@ et61x251_vidioc_g_fmt(struct et61x251_device* cam, void __user * arg)
	if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
	if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
		return -EINVAL;
		return -EINVAL;


	pfmt->colorspace = (pfmt->pixelformat == V4L2_PIX_FMT_ET61X251) ?
			   0 : V4L2_COLORSPACE_SRGB;
	pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251)
	pfmt->bytesperline = (pfmt->pixelformat==V4L2_PIX_FMT_ET61X251)
			     ? 0 : (pfmt->width * pfmt->priv) / 8;
			     ? 0 : (pfmt->width * pfmt->priv) / 8;
	pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
	pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
@@ -1996,6 +2017,8 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
	    pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
	    pix->pixelformat != V4L2_PIX_FMT_SBGGR8)
		pix->pixelformat = pfmt->pixelformat;
		pix->pixelformat = pfmt->pixelformat;
	pix->priv = pfmt->priv; /* bpp */
	pix->priv = pfmt->priv; /* bpp */
	pix->colorspace = (pix->pixelformat == V4L2_PIX_FMT_ET61X251) ?
			  0 : V4L2_COLORSPACE_SRGB;
	pix->colorspace = pfmt->colorspace;
	pix->colorspace = pfmt->colorspace;
	pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
	pix->bytesperline = (pix->pixelformat == V4L2_PIX_FMT_ET61X251)
			    ? 0 : (pix->width * pix->priv) / 8;
			    ? 0 : (pix->width * pix->priv) / 8;
@@ -2013,7 +2036,7 @@ et61x251_vidioc_try_s_fmt(struct et61x251_device* cam, unsigned int cmd,
			if (cam->frame[i].vma_use_count) {
			if (cam->frame[i].vma_use_count) {
				DBG(3, "VIDIOC_S_FMT failed. "
				DBG(3, "VIDIOC_S_FMT failed. "
				       "Unmap the buffers first.");
				       "Unmap the buffers first.");
				return -EINVAL;
				return -EBUSY;
			}
			}


	if (cam->stream == STREAM_ON)
	if (cam->stream == STREAM_ON)
@@ -2129,14 +2152,14 @@ et61x251_vidioc_reqbufs(struct et61x251_device* cam, void __user * arg)
	if (cam->io == IO_READ) {
	if (cam->io == IO_READ) {
		DBG(3, "Close and open the device again to choose the mmap "
		DBG(3, "Close and open the device again to choose the mmap "
		       "I/O method");
		       "I/O method");
		return -EINVAL;
		return -EBUSY;
	}
	}


	for (i = 0; i < cam->nbuffers; i++)
	for (i = 0; i < cam->nbuffers; i++)
		if (cam->frame[i].vma_use_count) {
		if (cam->frame[i].vma_use_count) {
			DBG(3, "VIDIOC_REQBUFS failed. "
			DBG(3, "VIDIOC_REQBUFS failed. "
			       "Previous buffers are still mapped.");
			       "Previous buffers are still mapped.");
			return -EINVAL;
			return -EBUSY;
		}
		}


	if (cam->stream == STREAM_ON)
	if (cam->stream == STREAM_ON)
@@ -2284,9 +2307,6 @@ et61x251_vidioc_streamon(struct et61x251_device* cam, void __user * arg)
	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
	if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
		return -EINVAL;
		return -EINVAL;


	if (list_empty(&cam->inqueue))
		return -EINVAL;

	cam->stream = STREAM_ON;
	cam->stream = STREAM_ON;


	DBG(3, "Stream on");
	DBG(3, "Stream on");
@@ -2535,8 +2555,6 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
		goto fail;
		goto fail;
	}
	}


	mutex_init(&cam->dev_mutex);

	DBG(2, "ET61X[12]51 PC Camera Controller detected "
	DBG(2, "ET61X[12]51 PC Camera Controller detected "
	       "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
	       "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);


@@ -2568,7 +2586,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
	cam->v4ldev->release = video_device_release;
	cam->v4ldev->release = video_device_release;
	video_set_drvdata(cam->v4ldev, cam);
	video_set_drvdata(cam->v4ldev, cam);


	mutex_lock(&cam->dev_mutex);
	init_completion(&cam->probe);


	err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
	err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
				    video_nr[dev_nr]);
				    video_nr[dev_nr]);
@@ -2578,7 +2596,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
			DBG(1, "Free /dev/videoX node not found");
			DBG(1, "Free /dev/videoX node not found");
		video_nr[dev_nr] = -1;
		video_nr[dev_nr] = -1;
		dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
		dev_nr = (dev_nr < ET61X251_MAX_DEVICES-1) ? dev_nr+1 : 0;
		mutex_unlock(&cam->dev_mutex);
		complete_all(&cam->probe);
		goto fail;
		goto fail;
	}
	}


@@ -2599,11 +2617,15 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
		       "device controlling. Error #%d", err);
		       "device controlling. Error #%d", err);
#else
#else
	DBG(2, "Optional device control through 'sysfs' interface disabled");
	DBG(2, "Optional device control through 'sysfs' interface disabled");
	DBG(3, "Compile the kernel with the 'CONFIG_VIDEO_ADV_DEBUG' "
	       "configuration option to enable it.");
#endif
#endif


	usb_set_intfdata(intf, cam);
	usb_set_intfdata(intf, cam);
	kref_init(&cam->kref);
	usb_get_dev(cam->usbdev);


	mutex_unlock(&cam->dev_mutex);
	complete_all(&cam->probe);


	return 0;
	return 0;


@@ -2620,40 +2642,31 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)


static void et61x251_usb_disconnect(struct usb_interface* intf)
static void et61x251_usb_disconnect(struct usb_interface* intf)
{
{
	struct et61x251_device* cam = usb_get_intfdata(intf);
	struct et61x251_device* cam;

	if (!cam)
		return;


	down_write(&et61x251_disconnect);
	down_write(&et61x251_dev_lock);


	mutex_lock(&cam->dev_mutex);
	cam = usb_get_intfdata(intf);


	DBG(2, "Disconnecting %s...", cam->v4ldev->name);
	DBG(2, "Disconnecting %s...", cam->v4ldev->name);


	wake_up_interruptible_all(&cam->open);

	if (cam->users) {
	if (cam->users) {
		DBG(2, "Device /dev/video%d is open! Deregistration and "
		DBG(2, "Device /dev/video%d is open! Deregistration and "
		       "memory deallocation are deferred on close.",
		       "memory deallocation are deferred.",
		    cam->v4ldev->minor);
		    cam->v4ldev->minor);
		cam->state |= DEV_MISCONFIGURED;
		cam->state |= DEV_MISCONFIGURED;
		et61x251_stop_transfer(cam);
		et61x251_stop_transfer(cam);
		cam->state |= DEV_DISCONNECTED;
		cam->state |= DEV_DISCONNECTED;
		wake_up_interruptible(&cam->wait_frame);
		wake_up_interruptible(&cam->wait_frame);
		wake_up(&cam->wait_stream);
		wake_up(&cam->wait_stream);
		usb_get_dev(cam->usbdev);
	} else
	} else {
		cam->state |= DEV_DISCONNECTED;
		cam->state |= DEV_DISCONNECTED;
		et61x251_release_resources(cam);
	}


	mutex_unlock(&cam->dev_mutex);
	wake_up_interruptible_all(&cam->wait_open);


	if (!cam->users)
	kref_put(&cam->kref, et61x251_release_resources);
		kfree(cam);


	up_write(&et61x251_disconnect);
	up_write(&et61x251_dev_lock);
}
}




+4 −4
Original line number Original line Diff line number Diff line
@@ -22,7 +22,7 @@
#define _ET61X251_SENSOR_H_
#define _ET61X251_SENSOR_H_


#include <linux/usb.h>
#include <linux/usb.h>
#include <linux/videodev.h>
#include <linux/videodev2.h>
#include <linux/device.h>
#include <linux/device.h>
#include <linux/stddef.h>
#include <linux/stddef.h>
#include <linux/errno.h>
#include <linux/errno.h>
@@ -47,7 +47,7 @@ et61x251_match_id(struct et61x251_device* cam, const struct usb_device_id *id);


extern void
extern void
et61x251_attach_sensor(struct et61x251_device* cam,
et61x251_attach_sensor(struct et61x251_device* cam,
		       struct et61x251_sensor* sensor);
		       const struct et61x251_sensor* sensor);


/*****************************************************************************/
/*****************************************************************************/


@@ -56,10 +56,10 @@ extern int et61x251_read_reg(struct et61x251_device*, u16 index);
extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value);
extern int et61x251_i2c_write(struct et61x251_device*, u8 address, u8 value);
extern int et61x251_i2c_read(struct et61x251_device*, u8 address);
extern int et61x251_i2c_read(struct et61x251_device*, u8 address);
extern int et61x251_i2c_try_write(struct et61x251_device*,
extern int et61x251_i2c_try_write(struct et61x251_device*,
				  struct et61x251_sensor*, u8 address,
				  const struct et61x251_sensor*, u8 address,
				  u8 value);
				  u8 value);
extern int et61x251_i2c_try_read(struct et61x251_device*,
extern int et61x251_i2c_try_read(struct et61x251_device*,
				 struct et61x251_sensor*, u8 address);
				 const struct et61x251_sensor*, u8 address);
extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1,
extern int et61x251_i2c_raw_write(struct et61x251_device*, u8 n, u8 data1,
				  u8 data2, u8 data3, u8 data4, u8 data5,
				  u8 data2, u8 data3, u8 data4, u8 data5,
				  u8 data6, u8 data7, u8 data8, u8 address);
				  u8 data6, u8 data7, u8 data8, u8 address);
+1 −1
Original line number Original line Diff line number Diff line
@@ -69,7 +69,7 @@ static int tas5130d1b_set_ctrl(struct et61x251_device* cam,
}
}




static struct et61x251_sensor tas5130d1b = {
static const struct et61x251_sensor tas5130d1b = {
	.name = "TAS5130D1B",
	.name = "TAS5130D1B",
	.interface = ET61X251_I2C_3WIRES,
	.interface = ET61X251_I2C_3WIRES,
	.rsta = ET61X251_I2C_RSTA_STOP,
	.rsta = ET61X251_I2C_RSTA_STOP,