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

Commit 2ffab02f authored by Luca Risolia's avatar Luca Risolia Committed by Greg Kroah-Hartman
Browse files

[PATCH] USB: SN9C10x driver updates



SN9C10x driver updates.

Changes: + new, - removed, * cleanup, @ bugfix

@ Fix stream_interrupt()
@ Fix vidioc_enum_input() and split vidioc_gs_input()
@ Need usb_get|put_dev() when disconnecting, if the device is open
* Use wait_event_interruptible_timeout() instead of wait_event_interruptible()
  when waiting for video frames
* replace wake_up_interruptible(&wait_stream) with wake_up(&wait_stream)
* Cleanups and updates in the documentation
+ Use per-device sensor structures
+ Add support for PAS202BCA image sensors
+ Add frame_timeout module parameter

Signed-off-by: default avatarLuca Risolia <luca.risolia@studio.unibo.it>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 7039f422
Loading
Loading
Loading
Loading
+11 −0
Original line number Original line Diff line number Diff line
@@ -196,6 +196,14 @@ Description: Force the application to unmap previously mapped buffer memory
                1 = force memory unmapping (save memory)
                1 = force memory unmapping (save memory)
Default:        0
Default:        0
-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
Name:           frame_timeout
Type:           uint array (min = 0, max = 64)
Syntax:         <n[,...]>
Description:    Timeout for a video frame in seconds. This parameter is
                specific for each detected camera. This parameter can be
                changed at runtime thanks to the /sys filesystem interface.
Default:        2
-------------------------------------------------------------------------------
Name:           debug
Name:           debug
Type:           ushort
Type:           ushort
Syntax:         <n> 
Syntax:         <n> 
@@ -321,6 +329,7 @@ Vendor ID Product ID
---------  ----------
---------  ----------
0x0c45     0x6001
0x0c45     0x6001
0x0c45     0x6005
0x0c45     0x6005
0x0c45     0x6007
0x0c45     0x6009
0x0c45     0x6009
0x0c45     0x600d
0x0c45     0x600d
0x0c45     0x6024
0x0c45     0x6024
@@ -370,6 +379,7 @@ HV7131D Hynix Semiconductor, Inc.
MI-0343     Micron Technology, Inc.
MI-0343     Micron Technology, Inc.
OV7630      OmniVision Technologies, Inc.
OV7630      OmniVision Technologies, Inc.
PAS106B     PixArt Imaging, Inc.
PAS106B     PixArt Imaging, Inc.
PAS202BCA   PixArt Imaging, Inc.
PAS202BCB   PixArt Imaging, Inc.
PAS202BCB   PixArt Imaging, Inc.
TAS5110C1B  Taiwan Advanced Sensor Corporation
TAS5110C1B  Taiwan Advanced Sensor Corporation
TAS5130D1B  Taiwan Advanced Sensor Corporation
TAS5130D1B  Taiwan Advanced Sensor Corporation
@@ -493,6 +503,7 @@ Many thanks to following persons for their contribute (listed in alphabetical
order):
order):


- Luca Capello for the donation of a webcam;
- Luca Capello for the donation of a webcam;
- Philippe Coval for having helped testing the PAS202BCA image sensor;
- Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the
- Joao Rodrigo Fuzaro, Joao Limirio, Claudio Filho and Caio Begotti for the
  donation of a webcam;
  donation of a webcam;
- Jon Hollstrom for the donation of a webcam;
- Jon Hollstrom for the donation of a webcam;
+4 −1
Original line number Original line Diff line number Diff line
@@ -2,7 +2,10 @@
# Makefile for USB Media drivers
# Makefile for USB Media drivers
#
#


sn9c102-objs	:= sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bcb.o sn9c102_tas5110c1b.o sn9c102_tas5130d1b.o
sn9c102-objs	:= sn9c102_core.o sn9c102_hv7131d.o sn9c102_mi0343.o \
		   sn9c102_ov7630.o sn9c102_pas106b.o sn9c102_pas202bca.o \
		   sn9c102_pas202bcb.o sn9c102_tas5110c1b.o \
		   sn9c102_tas5130d1b.o
et61x251-objs	:= et61x251_core.o et61x251_tas5130d1b.o
et61x251-objs	:= et61x251_core.o et61x251_tas5130d1b.o
zc0301-objs	:= zc0301_core.o zc0301_pas202bcb.o
zc0301-objs	:= zc0301_core.o zc0301_pas202bcb.o


+18 −5
Original line number Original line Diff line number Diff line
@@ -34,7 +34,8 @@
#include <linux/param.h>
#include <linux/param.h>
#include <linux/rwsem.h>
#include <linux/rwsem.h>
#include <linux/mutex.h>
#include <linux/mutex.h>
#include <asm/semaphore.h>
#include <linux/string.h>
#include <linux/stddef.h>


#include "sn9c102_sensor.h"
#include "sn9c102_sensor.h"


@@ -51,6 +52,7 @@
#define SN9C102_ALTERNATE_SETTING 8
#define SN9C102_ALTERNATE_SETTING 8
#define SN9C102_URB_TIMEOUT       msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
#define SN9C102_URB_TIMEOUT       msecs_to_jiffies(2 * SN9C102_ISO_PACKETS)
#define SN9C102_CTRL_TIMEOUT      300
#define SN9C102_CTRL_TIMEOUT      300
#define SN9C102_FRAME_TIMEOUT     2


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


@@ -108,6 +110,7 @@ struct sn9c102_sysfs_attr {


struct sn9c102_module_param {
struct sn9c102_module_param {
	u8 force_munmap;
	u8 force_munmap;
	u16 frame_timeout;
};
};


static DEFINE_MUTEX(sn9c102_sysfs_lock);
static DEFINE_MUTEX(sn9c102_sysfs_lock);
@@ -117,7 +120,7 @@ struct sn9c102_device {
	struct video_device* v4ldev;
	struct video_device* v4ldev;


	enum sn9c102_bridge bridge;
	enum sn9c102_bridge bridge;
	struct sn9c102_sensor* sensor;
	struct sn9c102_sensor sensor;


	struct usb_device* usbdev;
	struct usb_device* usbdev;
	struct urb* urb[SN9C102_URBS];
	struct urb* urb[SN9C102_URBS];
@@ -149,12 +152,21 @@ struct sn9c102_device {


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


struct sn9c102_device*
sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id)
{
	if (usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id))
		return cam;

	return NULL;
}


void
void
sn9c102_attach_sensor(struct sn9c102_device* cam,
sn9c102_attach_sensor(struct sn9c102_device* cam,
                      struct sn9c102_sensor* sensor)
                      struct sn9c102_sensor* sensor)
{
{
	cam->sensor = sensor;
	memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor));
	cam->sensor->usbdev = cam->usbdev;
}
}


/*****************************************************************************/
/*****************************************************************************/
@@ -197,7 +209,8 @@ do { \


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


#undef PDBGG
#undef PDBGG
#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
+100 −70
Original line number Original line Diff line number Diff line
@@ -25,11 +25,9 @@
#include <linux/moduleparam.h>
#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/device.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/stddef.h>
#include <linux/compiler.h>
#include <linux/compiler.h>
#include <linux/ioctl.h>
#include <linux/ioctl.h>
#include <linux/poll.h>
#include <linux/poll.h>
@@ -49,8 +47,8 @@
#define SN9C102_MODULE_AUTHOR   "(C) 2004-2006 Luca Risolia"
#define SN9C102_MODULE_AUTHOR   "(C) 2004-2006 Luca Risolia"
#define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
#define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
#define SN9C102_MODULE_LICENSE  "GPL"
#define SN9C102_MODULE_LICENSE  "GPL"
#define SN9C102_MODULE_VERSION  "1:1.26"
#define SN9C102_MODULE_VERSION  "1:1.27"
#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 26)
#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 27)


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


@@ -89,6 +87,15 @@ MODULE_PARM_DESC(force_munmap,
                 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
                 "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
                 "\n");
                 "\n");


static unsigned int frame_timeout[] = {[0 ... SN9C102_MAX_DEVICES-1] =
                                       SN9C102_FRAME_TIMEOUT};
module_param_array(frame_timeout, uint, NULL, 0644);
MODULE_PARM_DESC(frame_timeout,
                 "\n<n[,...]> Timeout for a video frame in seconds."
                 "\nThis parameter is specific for each detected camera."
                 "\nDefault value is "__MODULE_STRING(SN9C102_FRAME_TIMEOUT)"."
                 "\n");

#ifdef SN9C102_DEBUG
#ifdef SN9C102_DEBUG
static unsigned short debug = SN9C102_DEBUG_LEVEL;
static unsigned short debug = SN9C102_DEBUG_LEVEL;
module_param(debug, ushort, 0644);
module_param(debug, ushort, 0644);
@@ -128,8 +135,8 @@ static u32
sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, 
sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, 
                        enum sn9c102_io_method io)
                        enum sn9c102_io_method io)
{
{
	struct v4l2_pix_format* p = &(cam->sensor->pix_format);
	struct v4l2_pix_format* p = &(cam->sensor.pix_format);
	struct v4l2_rect* r = &(cam->sensor->cropcap.bounds);
	struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
	const size_t imagesize = cam->module_param.force_munmap ||
	const size_t imagesize = cam->module_param.force_munmap ||
	                         io == IO_READ ?
	                         io == IO_READ ?
	                         (p->width * p->height * p->priv) / 8 :
	                         (p->width * p->height * p->priv) / 8 :
@@ -449,19 +456,13 @@ sn9c102_i2c_try_write(struct sn9c102_device* cam,


int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address)
int sn9c102_i2c_read(struct sn9c102_device* cam, u8 address)
{
{
	if (!cam->sensor)
	return sn9c102_i2c_try_read(cam, &cam->sensor, address);
		return -1;

	return sn9c102_i2c_try_read(cam, cam->sensor, address);
}
}




int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
int sn9c102_i2c_write(struct sn9c102_device* cam, u8 address, u8 value)
{
{
	if (!cam->sensor)
	return sn9c102_i2c_try_write(cam, &cam->sensor, address, value);
		return -1;

	return sn9c102_i2c_try_write(cam, cam->sensor, address, value);
}
}


/*****************************************************************************/
/*****************************************************************************/
@@ -505,7 +506,7 @@ sn9c102_find_eof_header(struct sn9c102_device* cam, void* mem, size_t len)
	size_t eoflen = sizeof(sn9c102_eof_header_t), i;
	size_t eoflen = sizeof(sn9c102_eof_header_t), i;
	unsigned j, n = sizeof(sn9c102_eof_header) / eoflen;
	unsigned j, n = sizeof(sn9c102_eof_header) / eoflen;


	if (cam->sensor->pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
	if (cam->sensor.pix_format.pixelformat == V4L2_PIX_FMT_SN9C10X)
		return NULL; /* EOF header does not exist in compressed data */
		return NULL; /* EOF header does not exist in compressed data */


	for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++)
	for (i = 0; (len >= eoflen) && (i <= len - eoflen); i++)
@@ -535,7 +536,7 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
		if ((*f))
		if ((*f))
			(*f)->state = F_QUEUED;
			(*f)->state = F_QUEUED;
		DBG(3, "Stream interrupted");
		DBG(3, "Stream interrupted");
		wake_up_interruptible(&cam->wait_stream);
		wake_up(&cam->wait_stream);
	}
	}


	if (cam->state & DEV_DISCONNECTED)
	if (cam->state & DEV_DISCONNECTED)
@@ -553,9 +554,9 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
		(*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t,
		(*f) = list_entry(cam->inqueue.next, struct sn9c102_frame_t,
		                  frame);
		                  frame);


	imagesize = (cam->sensor->pix_format.width *
	imagesize = (cam->sensor.pix_format.width *
	             cam->sensor->pix_format.height *
	             cam->sensor.pix_format.height *
	             cam->sensor->pix_format.priv) / 8;
	             cam->sensor.pix_format.priv) / 8;


	soflen = (cam->bridge) == BRIDGE_SN9C103 ?
	soflen = (cam->bridge) == BRIDGE_SN9C103 ?
	                          sizeof(sn9c103_sof_header_t) :
	                          sizeof(sn9c103_sof_header_t) :
@@ -579,7 +580,7 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)


redo:
redo:
		sof = sn9c102_find_sof_header(cam, pos, len);
		sof = sn9c102_find_sof_header(cam, pos, len);
		if (!sof) {
		if (likely(!sof)) {
			eof = sn9c102_find_eof_header(cam, pos, len);
			eof = sn9c102_find_eof_header(cam, pos, len);
			if ((*f)->state == F_GRABBING) {
			if ((*f)->state == F_GRABBING) {
end_of_frame:
end_of_frame:
@@ -589,7 +590,8 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
					img = (eof > pos) ? eof - pos - 1 : 0;
					img = (eof > pos) ? eof - pos - 1 : 0;


				if ((*f)->buf.bytesused+img > imagesize) {
				if ((*f)->buf.bytesused+img > imagesize) {
					u32 b = (*f)->buf.bytesused + img -
					u32 b;
					b = (*f)->buf.bytesused + img -
					    imagesize;
					    imagesize;
					img = imagesize - (*f)->buf.bytesused;
					img = imagesize - (*f)->buf.bytesused;
					DBG(3, "Expected EOF not found: "
					DBG(3, "Expected EOF not found: "
@@ -608,9 +610,10 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
				(*f)->buf.bytesused += img;
				(*f)->buf.bytesused += img;


				if ((*f)->buf.bytesused == imagesize ||
				if ((*f)->buf.bytesused == imagesize ||
				    (cam->sensor->pix_format.pixelformat ==
				    (cam->sensor.pix_format.pixelformat ==
				                V4L2_PIX_FMT_SN9C10X && eof)) {
				                V4L2_PIX_FMT_SN9C10X && eof)) {
					u32 b = (*f)->buf.bytesused;
					u32 b;
					b = (*f)->buf.bytesused;
					(*f)->state = F_DONE;
					(*f)->state = F_DONE;
					(*f)->buf.sequence= ++cam->frame_count;
					(*f)->buf.sequence= ++cam->frame_count;
					spin_lock(&cam->queue_lock);
					spin_lock(&cam->queue_lock);
@@ -667,7 +670,7 @@ static void sn9c102_urb_complete(struct urb *urb, struct pt_regs* regs)
			if (eof && eof < sof)
			if (eof && eof < sof)
				goto end_of_frame; /* (1) */
				goto end_of_frame; /* (1) */
			else {
			else {
				if (cam->sensor->pix_format.pixelformat ==
				if (cam->sensor.pix_format.pixelformat ==
				    V4L2_PIX_FMT_SN9C10X) {
				    V4L2_PIX_FMT_SN9C10X) {
					eof = sof - soflen;
					eof = sof - soflen;
					goto end_of_frame;
					goto end_of_frame;
@@ -808,20 +811,21 @@ static int sn9c102_stop_transfer(struct sn9c102_device* cam)


static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
static int sn9c102_stream_interrupt(struct sn9c102_device* cam)
{
{
	int err = 0;
	long timeout;


	cam->stream = STREAM_INTERRUPT;
	cam->stream = STREAM_INTERRUPT;
	err = wait_event_timeout(cam->wait_stream,
	timeout = wait_event_timeout(cam->wait_stream,
	                             (cam->stream == STREAM_OFF) ||
	                             (cam->stream == STREAM_OFF) ||
	                             (cam->state & DEV_DISCONNECTED),
	                             (cam->state & DEV_DISCONNECTED),
	                             SN9C102_URB_TIMEOUT);
	                             SN9C102_URB_TIMEOUT);
	if (cam->state & DEV_DISCONNECTED)
	if (cam->state & DEV_DISCONNECTED)
		return -ENODEV;
		return -ENODEV;
	else if (err) {
	else if (cam->stream != STREAM_OFF) {
		cam->state |= DEV_MISCONFIGURED;
		cam->state |= DEV_MISCONFIGURED;
		DBG(1, "The camera is misconfigured. To use it, close and "
		DBG(1, "URB timeout reached. The camera is misconfigured. "
		       "open /dev/video%d again.", cam->v4ldev->minor);
		       "To use it, close and open /dev/video%d again.",
		return err;
		    cam->v4ldev->minor);
		return -EIO;
	}
	}


	return 0;
	return 0;
@@ -1057,7 +1061,7 @@ static ssize_t sn9c102_show_i2c_val(struct class_device* cd, char* buf)
		return -ENODEV;
		return -ENODEV;
	}
	}


	if (!(cam->sensor->sysfs_ops & SN9C102_I2C_READ)) {
	if (!(cam->sensor.sysfs_ops & SN9C102_I2C_READ)) {
		mutex_unlock(&sn9c102_sysfs_lock);
		mutex_unlock(&sn9c102_sysfs_lock);
		return -ENOSYS;
		return -ENOSYS;
	}
	}
@@ -1094,7 +1098,7 @@ sn9c102_store_i2c_val(struct class_device* cd, const char* buf, size_t len)
		return -ENODEV;
		return -ENODEV;
	}
	}


	if (!(cam->sensor->sysfs_ops & SN9C102_I2C_WRITE)) {
	if (!(cam->sensor.sysfs_ops & SN9C102_I2C_WRITE)) {
		mutex_unlock(&sn9c102_sysfs_lock);
		mutex_unlock(&sn9c102_sysfs_lock);
		return -ENOSYS;
		return -ENOSYS;
	}
	}
@@ -1249,7 +1253,7 @@ static void sn9c102_create_sysfs(struct sn9c102_device* cam)
		video_device_create_file(v4ldev, &class_device_attr_blue);
		video_device_create_file(v4ldev, &class_device_attr_blue);
		video_device_create_file(v4ldev, &class_device_attr_red);
		video_device_create_file(v4ldev, &class_device_attr_red);
	}
	}
	if (cam->sensor && cam->sensor->sysfs_ops) {
	if (cam->sensor.sysfs_ops) {
		video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
		video_device_create_file(v4ldev, &class_device_attr_i2c_reg);
		video_device_create_file(v4ldev, &class_device_attr_i2c_val);
		video_device_create_file(v4ldev, &class_device_attr_i2c_val);
	}
	}
@@ -1312,7 +1316,7 @@ static int sn9c102_set_scale(struct sn9c102_device* cam, u8 scale)


static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)
{
{
	struct sn9c102_sensor* s = cam->sensor;
	struct sn9c102_sensor* s = &cam->sensor;
	u8 h_start = (u8)(rect->left - s->cropcap.bounds.left),
	u8 h_start = (u8)(rect->left - s->cropcap.bounds.left),
	   v_start = (u8)(rect->top - s->cropcap.bounds.top),
	   v_start = (u8)(rect->top - s->cropcap.bounds.top),
	   h_size = (u8)(rect->width / 16),
	   h_size = (u8)(rect->width / 16),
@@ -1335,7 +1339,7 @@ static int sn9c102_set_crop(struct sn9c102_device* cam, struct v4l2_rect* rect)


static int sn9c102_init(struct sn9c102_device* cam)
static int sn9c102_init(struct sn9c102_device* cam)
{
{
	struct sn9c102_sensor* s = cam->sensor;
	struct sn9c102_sensor* s = &cam->sensor;
	struct v4l2_control ctrl;
	struct v4l2_control ctrl;
	struct v4l2_queryctrl *qctrl;
	struct v4l2_queryctrl *qctrl;
	struct v4l2_rect* rect;
	struct v4l2_rect* rect;
@@ -1428,6 +1432,8 @@ static void sn9c102_release_resources(struct sn9c102_device* cam)
	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);

	mutex_unlock(&sn9c102_sysfs_lock);
	mutex_unlock(&sn9c102_sysfs_lock);


	kfree(cam->control_buffer);
	kfree(cam->control_buffer);
@@ -1541,6 +1547,7 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
	struct sn9c102_device* cam = video_get_drvdata(video_devdata(filp));
	struct sn9c102_frame_t* f, * i;
	struct sn9c102_frame_t* f, * i;
	unsigned long lock_flags;
	unsigned long lock_flags;
	long timeout;
	int err = 0;
	int err = 0;


	if (mutex_lock_interruptible(&cam->fileop_mutex))
	if (mutex_lock_interruptible(&cam->fileop_mutex))
@@ -1592,20 +1599,22 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
			mutex_unlock(&cam->fileop_mutex);
			mutex_unlock(&cam->fileop_mutex);
			return -EAGAIN;
			return -EAGAIN;
		}
		}
		err = wait_event_interruptible
		timeout = wait_event_interruptible_timeout
		          ( cam->wait_frame,
		          ( cam->wait_frame,
		            (!list_empty(&cam->outqueue)) ||
		            (!list_empty(&cam->outqueue)) ||
		            (cam->state & DEV_DISCONNECTED) ||
		            (cam->state & DEV_DISCONNECTED) ||
			(cam->state & DEV_MISCONFIGURED) );
		            (cam->state & DEV_MISCONFIGURED),
		if (err) {
		            cam->module_param.frame_timeout *
		            1000 * msecs_to_jiffies(1) );
		if (timeout < 0) {
			mutex_unlock(&cam->fileop_mutex);
			mutex_unlock(&cam->fileop_mutex);
			return err;
			return timeout;
		}
		}
		if (cam->state & DEV_DISCONNECTED) {
		if (cam->state & DEV_DISCONNECTED) {
			mutex_unlock(&cam->fileop_mutex);
			mutex_unlock(&cam->fileop_mutex);
			return -ENODEV;
			return -ENODEV;
		}
		}
		if (cam->state & DEV_MISCONFIGURED) {
		if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
			mutex_unlock(&cam->fileop_mutex);
			mutex_unlock(&cam->fileop_mutex);
			return -EIO;
			return -EIO;
		}
		}
@@ -1816,6 +1825,7 @@ sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)


	memset(&i, 0, sizeof(i));
	memset(&i, 0, sizeof(i));
	strcpy(i.name, "Camera");
	strcpy(i.name, "Camera");
	i.type = V4L2_INPUT_TYPE_CAMERA;


	if (copy_to_user(arg, &i, sizeof(i)))
	if (copy_to_user(arg, &i, sizeof(i)))
		return -EFAULT;
		return -EFAULT;
@@ -1825,7 +1835,19 @@ sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)




static int
static int
sn9c102_vidioc_gs_input(struct sn9c102_device* cam, void __user * arg)
sn9c102_vidioc_g_input(struct sn9c102_device* cam, void __user * arg)
{
	int index = 0;

	if (copy_to_user(arg, &index, sizeof(index)))
		return -EFAULT;

	return 0;
}


static int
sn9c102_vidioc_s_input(struct sn9c102_device* cam, void __user * arg)
{
{
	int index;
	int index;


@@ -1842,7 +1864,7 @@ sn9c102_vidioc_gs_input(struct sn9c102_device* cam, void __user * arg)
static int
static int
sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
{
{
	struct sn9c102_sensor* s = cam->sensor;
	struct sn9c102_sensor* s = &cam->sensor;
	struct v4l2_queryctrl qc;
	struct v4l2_queryctrl qc;
	u8 i;
	u8 i;


@@ -1864,7 +1886,7 @@ sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
static int
static int
sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg)
sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg)
{
{
	struct sn9c102_sensor* s = cam->sensor;
	struct sn9c102_sensor* s = &cam->sensor;
	struct v4l2_control ctrl;
	struct v4l2_control ctrl;
	int err = 0;
	int err = 0;
	u8 i;
	u8 i;
@@ -1896,7 +1918,7 @@ sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg)
static int
static int
sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
{
{
	struct sn9c102_sensor* s = cam->sensor;
	struct sn9c102_sensor* s = &cam->sensor;
	struct v4l2_control ctrl;
	struct v4l2_control ctrl;
	u8 i;
	u8 i;
	int err = 0;
	int err = 0;
@@ -1909,6 +1931,8 @@ sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)


	for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
	for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
		if (ctrl.id == s->qctrl[i].id) {
		if (ctrl.id == s->qctrl[i].id) {
			if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
				return -EINVAL;
			if (ctrl.value < s->qctrl[i].minimum ||
			if (ctrl.value < s->qctrl[i].minimum ||
			    ctrl.value > s->qctrl[i].maximum)
			    ctrl.value > s->qctrl[i].maximum)
				return -ERANGE;
				return -ERANGE;
@@ -1931,7 +1955,7 @@ sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
static int
static int
sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
{
{
	struct v4l2_cropcap* cc = &(cam->sensor->cropcap);
	struct v4l2_cropcap* cc = &(cam->sensor.cropcap);


	cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	cc->pixelaspect.numerator = 1;
	cc->pixelaspect.numerator = 1;
@@ -1947,7 +1971,7 @@ sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
static int
static int
sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
{
{
	struct sn9c102_sensor* s = cam->sensor;
	struct sn9c102_sensor* s = &cam->sensor;
	struct v4l2_crop crop = {
	struct v4l2_crop crop = {
		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
	};
	};
@@ -1964,7 +1988,7 @@ sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
static int
static int
sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
sn9c102_vidioc_s_crop(struct sn9c102_device* cam, void __user * arg)
{
{
	struct sn9c102_sensor* s = cam->sensor;
	struct sn9c102_sensor* s = &cam->sensor;
	struct v4l2_crop crop;
	struct v4l2_crop crop;
	struct v4l2_rect* rect;
	struct v4l2_rect* rect;
	struct v4l2_rect* bounds = &(s->cropcap.bounds);
	struct v4l2_rect* bounds = &(s->cropcap.bounds);
@@ -2105,7 +2129,7 @@ static int
sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
{
{
	struct v4l2_format format;
	struct v4l2_format format;
	struct v4l2_pix_format* pfmt = &(cam->sensor->pix_format);
	struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);


	if (copy_from_user(&format, arg, sizeof(format)))
	if (copy_from_user(&format, arg, sizeof(format)))
		return -EFAULT;
		return -EFAULT;
@@ -2130,7 +2154,7 @@ static int
sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
                         void __user * arg)
                         void __user * arg)
{
{
	struct sn9c102_sensor* s = cam->sensor;
	struct sn9c102_sensor* s = &cam->sensor;
	struct v4l2_format format;
	struct v4l2_format format;
	struct v4l2_pix_format* pix;
	struct v4l2_pix_format* pix;
	struct v4l2_pix_format* pfmt = &(s->pix_format);
	struct v4l2_pix_format* pfmt = &(s->pix_format);
@@ -2417,7 +2441,7 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
	struct v4l2_buffer b;
	struct v4l2_buffer b;
	struct sn9c102_frame_t *f;
	struct sn9c102_frame_t *f;
	unsigned long lock_flags;
	unsigned long lock_flags;
	int err = 0;
	long timeout;


	if (copy_from_user(&b, arg, sizeof(b)))
	if (copy_from_user(&b, arg, sizeof(b)))
		return -EFAULT;
		return -EFAULT;
@@ -2430,16 +2454,18 @@ sn9c102_vidioc_dqbuf(struct sn9c102_device* cam, struct file* filp,
			return -EINVAL;
			return -EINVAL;
		if (filp->f_flags & O_NONBLOCK)
		if (filp->f_flags & O_NONBLOCK)
			return -EAGAIN;
			return -EAGAIN;
		err = wait_event_interruptible
		timeout = wait_event_interruptible_timeout
		          ( cam->wait_frame,
		          ( cam->wait_frame,
		            (!list_empty(&cam->outqueue)) ||
		            (!list_empty(&cam->outqueue)) ||
		            (cam->state & DEV_DISCONNECTED) ||
		            (cam->state & DEV_DISCONNECTED) ||
		        (cam->state & DEV_MISCONFIGURED) );
		            (cam->state & DEV_MISCONFIGURED),
		if (err)
		            cam->module_param.frame_timeout *
			return err;
		            1000 * msecs_to_jiffies(1) );
		if (timeout < 0)
			return timeout;
		if (cam->state & DEV_DISCONNECTED)
		if (cam->state & DEV_DISCONNECTED)
			return -ENODEV;
			return -ENODEV;
		if (cam->state & DEV_MISCONFIGURED)
		if (!timeout || (cam->state & DEV_MISCONFIGURED))
			return -EIO;
			return -EIO;
	}
	}


@@ -2571,8 +2597,10 @@ static int sn9c102_ioctl_v4l2(struct inode* inode, struct file* filp,
		return sn9c102_vidioc_enuminput(cam, arg);
		return sn9c102_vidioc_enuminput(cam, arg);


	case VIDIOC_G_INPUT:
	case VIDIOC_G_INPUT:
		return sn9c102_vidioc_g_input(cam, arg);

	case VIDIOC_S_INPUT:
	case VIDIOC_S_INPUT:
		return sn9c102_vidioc_gs_input(cam, arg);
		return sn9c102_vidioc_s_input(cam, arg);


	case VIDIOC_QUERYCTRL:
	case VIDIOC_QUERYCTRL:
		return sn9c102_vidioc_query_ctrl(cam, arg);
		return sn9c102_vidioc_query_ctrl(cam, arg);
@@ -2752,10 +2780,10 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
			break;
			break;
	}
	}


	if (!err && cam->sensor) {
	if (!err) {
		DBG(2, "%s image sensor detected", cam->sensor->name);
		DBG(2, "%s image sensor detected", cam->sensor.name);
		DBG(3, "Support for %s maintained by %s",
		DBG(3, "Support for %s maintained by %s",
		    cam->sensor->name, cam->sensor->maintainer);
		    cam->sensor.name, cam->sensor.maintainer);
	} else {
	} else {
		DBG(1, "No supported image sensor detected");
		DBG(1, "No supported image sensor detected");
		err = -ENODEV;
		err = -ENODEV;
@@ -2793,6 +2821,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
	DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);
	DBG(2, "V4L2 device registered as /dev/video%d", cam->v4ldev->minor);


	cam->module_param.force_munmap = force_munmap[dev_nr];
	cam->module_param.force_munmap = force_munmap[dev_nr];
	cam->module_param.frame_timeout = frame_timeout[dev_nr];


	dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;
	dev_nr = (dev_nr < SN9C102_MAX_DEVICES-1) ? dev_nr+1 : 0;


@@ -2841,7 +2870,8 @@ static void sn9c102_usb_disconnect(struct usb_interface* intf)
		sn9c102_stop_transfer(cam);
		sn9c102_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_interruptible(&cam->wait_stream);
		wake_up(&cam->wait_stream);
		usb_get_dev(cam->usbdev);
	} else {
	} else {
		cam->state |= DEV_DISCONNECTED;
		cam->state |= DEV_DISCONNECTED;
		sn9c102_release_resources(cam);
		sn9c102_release_resources(cam);
+19 −14
Original line number Original line Diff line number Diff line
@@ -34,8 +34,8 @@ static int ov7630_init(struct sn9c102_device* cam)
	err += sn9c102_write_reg(cam, 0x0f, 0x18);
	err += sn9c102_write_reg(cam, 0x0f, 0x18);
	err += sn9c102_write_reg(cam, 0x50, 0x19);
	err += sn9c102_write_reg(cam, 0x50, 0x19);


	err += sn9c102_i2c_write(cam, 0x12, 0x8d);
	err += sn9c102_i2c_write(cam, 0x12, 0x80);
	err += sn9c102_i2c_write(cam, 0x11, 0x00);
	err += sn9c102_i2c_write(cam, 0x11, 0x01);
	err += sn9c102_i2c_write(cam, 0x15, 0x34);
	err += sn9c102_i2c_write(cam, 0x15, 0x34);
	err += sn9c102_i2c_write(cam, 0x16, 0x03);
	err += sn9c102_i2c_write(cam, 0x16, 0x03);
	err += sn9c102_i2c_write(cam, 0x17, 0x1c);
	err += sn9c102_i2c_write(cam, 0x17, 0x1c);
@@ -43,12 +43,14 @@ static int ov7630_init(struct sn9c102_device* cam)
	err += sn9c102_i2c_write(cam, 0x19, 0x06);
	err += sn9c102_i2c_write(cam, 0x19, 0x06);
	err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
	err += sn9c102_i2c_write(cam, 0x1a, 0xf6);
	err += sn9c102_i2c_write(cam, 0x1b, 0x04);
	err += sn9c102_i2c_write(cam, 0x1b, 0x04);
	err += sn9c102_i2c_write(cam, 0x20, 0x44);
	err += sn9c102_i2c_write(cam, 0x20, 0xf6);
	err += sn9c102_i2c_write(cam, 0x23, 0xee);
	err += sn9c102_i2c_write(cam, 0x23, 0xee);
	err += sn9c102_i2c_write(cam, 0x26, 0xa0);
	err += sn9c102_i2c_write(cam, 0x26, 0xa0);
	err += sn9c102_i2c_write(cam, 0x27, 0x9a);
	err += sn9c102_i2c_write(cam, 0x27, 0x9a);
	err += sn9c102_i2c_write(cam, 0x28, 0x20);
	err += sn9c102_i2c_write(cam, 0x28, 0xa0);
	err += sn9c102_i2c_write(cam, 0x29, 0x30);
	err += sn9c102_i2c_write(cam, 0x29, 0x30);
	err += sn9c102_i2c_write(cam, 0x2a, 0xa0);
	err += sn9c102_i2c_write(cam, 0x2b, 0x1f);
	err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
	err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
	err += sn9c102_i2c_write(cam, 0x30, 0x24);
	err += sn9c102_i2c_write(cam, 0x30, 0x24);
	err += sn9c102_i2c_write(cam, 0x32, 0x86);
	err += sn9c102_i2c_write(cam, 0x32, 0x86);
@@ -80,7 +82,7 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
		err += sn9c102_i2c_write(cam, 0x02, ctrl->value);
		err += sn9c102_i2c_write(cam, 0x02, ctrl->value);
		break;
		break;
	case V4L2_CID_BLUE_BALANCE:
	case V4L2_CID_BLUE_BALANCE:
		err += sn9c102_i2c_write(cam, 0x03, ctrl->value);
		err += sn9c102_i2c_write(cam, 0x01, ctrl->value);
		break;
		break;
	case V4L2_CID_GAIN:
	case V4L2_CID_GAIN:
		err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
		err += sn9c102_i2c_write(cam, 0x00, ctrl->value);
@@ -108,7 +110,7 @@ static int ov7630_set_ctrl(struct sn9c102_device* cam,
		err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
		err += sn9c102_i2c_write(cam, 0x0d, ctrl->value);
		break;
		break;
	case V4L2_CID_AUTO_WHITE_BALANCE:
	case V4L2_CID_AUTO_WHITE_BALANCE:
		err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x09);
		err += sn9c102_i2c_write(cam, 0x12, (ctrl->value << 2) | 0x78);
		break;
		break;
	case V4L2_CID_AUTOGAIN:
	case V4L2_CID_AUTOGAIN:
		err += sn9c102_i2c_write(cam, 0x13, ctrl->value);
		err += sn9c102_i2c_write(cam, 0x13, ctrl->value);
@@ -371,26 +373,29 @@ static struct sn9c102_sensor ov7630 = {


int sn9c102_probe_ov7630(struct sn9c102_device* cam)
int sn9c102_probe_ov7630(struct sn9c102_device* cam)
{
{
	const struct usb_device_id ov7630_id_table[] = {
		{ USB_DEVICE(0x0c45, 0x602c), },
		{ USB_DEVICE(0x0c45, 0x602d), },
		{ USB_DEVICE(0x0c45, 0x608f), },
		{ USB_DEVICE(0x0c45, 0x60b0), },
		{ }
	};
	int err = 0;
	int err = 0;


	sn9c102_attach_sensor(cam, &ov7630);
	if (!sn9c102_match_id(cam, ov7630_id_table))

	if (le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602c &&
	    le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x602d &&
	    le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x608f &&
	    le16_to_cpu(ov7630.usbdev->descriptor.idProduct) != 0x60b0)
		return -ENODEV;
		return -ENODEV;


	err += sn9c102_write_reg(cam, 0x01, 0x01);
	err += sn9c102_write_reg(cam, 0x01, 0x01);
	err += sn9c102_write_reg(cam, 0x00, 0x01);
	err += sn9c102_write_reg(cam, 0x00, 0x01);
	err += sn9c102_write_reg(cam, 0x28, 0x17);
	err += sn9c102_write_reg(cam, 0x28, 0x17);

	if (err)
	if (err)
		return -EIO;
		return -EIO;


	err += sn9c102_i2c_write(cam, 0x0b, 0);
	err += sn9c102_i2c_try_write(cam, &ov7630, 0x0b, 0);
	if (err)
	if (err)
		return -ENODEV;
		return -ENODEV;


	sn9c102_attach_sensor(cam, &ov7630);

	return 0;
	return 0;
}
}
Loading