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 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)
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
Type:           ushort
Syntax:         <n> 
@@ -321,6 +329,7 @@ Vendor ID Product ID
---------  ----------
0x0c45     0x6001
0x0c45     0x6005
0x0c45     0x6007
0x0c45     0x6009
0x0c45     0x600d
0x0c45     0x6024
@@ -370,6 +379,7 @@ HV7131D Hynix Semiconductor, Inc.
MI-0343     Micron Technology, Inc.
OV7630      OmniVision Technologies, Inc.
PAS106B     PixArt Imaging, Inc.
PAS202BCA   PixArt Imaging, Inc.
PAS202BCB   PixArt Imaging, Inc.
TAS5110C1B  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):

- 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
  donation of a webcam;
- Jon Hollstrom for the donation of a webcam;
+4 −1
Original line number Diff line number Diff line
@@ -2,7 +2,10 @@
# 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
zc0301-objs	:= zc0301_core.o zc0301_pas202bcb.o

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

#include "sn9c102_sensor.h"

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

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

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

struct sn9c102_module_param {
	u8 force_munmap;
	u16 frame_timeout;
};

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

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

	struct usb_device* usbdev;
	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
sn9c102_attach_sensor(struct sn9c102_device* cam,
                      struct sn9c102_sensor* sensor)
{
	cam->sensor = sensor;
	cam->sensor->usbdev = cam->usbdev;
	memcpy(&cam->sensor, sensor, sizeof(struct sn9c102_sensor));
}

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

#undef PDBG
#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
#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
+100 −70
Original line number Diff line number Diff line
@@ -25,11 +25,9 @@
#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/stddef.h>
#include <linux/compiler.h>
#include <linux/ioctl.h>
#include <linux/poll.h>
@@ -49,8 +47,8 @@
#define SN9C102_MODULE_AUTHOR   "(C) 2004-2006 Luca Risolia"
#define SN9C102_AUTHOR_EMAIL    "<luca.risolia@studio.unibo.it>"
#define SN9C102_MODULE_LICENSE  "GPL"
#define SN9C102_MODULE_VERSION  "1:1.26"
#define SN9C102_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 26)
#define SN9C102_MODULE_VERSION  "1:1.27"
#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)"."
                 "\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
static unsigned short debug = SN9C102_DEBUG_LEVEL;
module_param(debug, ushort, 0644);
@@ -128,8 +135,8 @@ static u32
sn9c102_request_buffers(struct sn9c102_device* cam, u32 count, 
                        enum sn9c102_io_method io)
{
	struct v4l2_pix_format* p = &(cam->sensor->pix_format);
	struct v4l2_rect* r = &(cam->sensor->cropcap.bounds);
	struct v4l2_pix_format* p = &(cam->sensor.pix_format);
	struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
	const size_t imagesize = cam->module_param.force_munmap ||
	                         io == IO_READ ?
	                         (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)
{
	if (!cam->sensor)
		return -1;

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


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

	return sn9c102_i2c_try_write(cam, cam->sensor, address, value);
	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;
	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 */

	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))
			(*f)->state = F_QUEUED;
		DBG(3, "Stream interrupted");
		wake_up_interruptible(&cam->wait_stream);
		wake_up(&cam->wait_stream);
	}

	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,
		                  frame);

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

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

redo:
		sof = sn9c102_find_sof_header(cam, pos, len);
		if (!sof) {
		if (likely(!sof)) {
			eof = sn9c102_find_eof_header(cam, pos, len);
			if ((*f)->state == F_GRABBING) {
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;

				if ((*f)->buf.bytesused+img > imagesize) {
					u32 b = (*f)->buf.bytesused + img -
					u32 b;
					b = (*f)->buf.bytesused + img -
					    imagesize;
					img = imagesize - (*f)->buf.bytesused;
					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;

				if ((*f)->buf.bytesused == imagesize ||
				    (cam->sensor->pix_format.pixelformat ==
				    (cam->sensor.pix_format.pixelformat ==
				                V4L2_PIX_FMT_SN9C10X && eof)) {
					u32 b = (*f)->buf.bytesused;
					u32 b;
					b = (*f)->buf.bytesused;
					(*f)->state = F_DONE;
					(*f)->buf.sequence= ++cam->frame_count;
					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)
				goto end_of_frame; /* (1) */
			else {
				if (cam->sensor->pix_format.pixelformat ==
				if (cam->sensor.pix_format.pixelformat ==
				    V4L2_PIX_FMT_SN9C10X) {
					eof = sof - soflen;
					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)
{
	int err = 0;
	long timeout;

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

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

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

	if (!(cam->sensor->sysfs_ops & SN9C102_I2C_WRITE)) {
	if (!(cam->sensor.sysfs_ops & SN9C102_I2C_WRITE)) {
		mutex_unlock(&sn9c102_sysfs_lock);
		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_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_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)
{
	struct sn9c102_sensor* s = cam->sensor;
	struct sn9c102_sensor* s = &cam->sensor;
	u8 h_start = (u8)(rect->left - s->cropcap.bounds.left),
	   v_start = (u8)(rect->top - s->cropcap.bounds.top),
	   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)
{
	struct sn9c102_sensor* s = cam->sensor;
	struct sn9c102_sensor* s = &cam->sensor;
	struct v4l2_control ctrl;
	struct v4l2_queryctrl *qctrl;
	struct v4l2_rect* rect;
@@ -1428,6 +1432,8 @@ static void sn9c102_release_resources(struct sn9c102_device* cam)
	video_set_drvdata(cam->v4ldev, NULL);
	video_unregister_device(cam->v4ldev);

	usb_put_dev(cam->usbdev);

	mutex_unlock(&sn9c102_sysfs_lock);

	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_frame_t* f, * i;
	unsigned long lock_flags;
	long timeout;
	int err = 0;

	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);
			return -EAGAIN;
		}
		err = wait_event_interruptible
		timeout = wait_event_interruptible_timeout
		          ( cam->wait_frame,
		            (!list_empty(&cam->outqueue)) ||
		            (cam->state & DEV_DISCONNECTED) ||
			(cam->state & DEV_MISCONFIGURED) );
		if (err) {
		            (cam->state & DEV_MISCONFIGURED),
		            cam->module_param.frame_timeout *
		            1000 * msecs_to_jiffies(1) );
		if (timeout < 0) {
			mutex_unlock(&cam->fileop_mutex);
			return err;
			return timeout;
		}
		if (cam->state & DEV_DISCONNECTED) {
			mutex_unlock(&cam->fileop_mutex);
			return -ENODEV;
		}
		if (cam->state & DEV_MISCONFIGURED) {
		if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
			mutex_unlock(&cam->fileop_mutex);
			return -EIO;
		}
@@ -1816,6 +1825,7 @@ sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)

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

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


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;

@@ -1842,7 +1864,7 @@ sn9c102_vidioc_gs_input(struct sn9c102_device* cam, void __user * arg)
static int
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;
	u8 i;

@@ -1864,7 +1886,7 @@ sn9c102_vidioc_query_ctrl(struct sn9c102_device* cam, void __user * arg)
static int
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;
	int err = 0;
	u8 i;
@@ -1896,7 +1918,7 @@ sn9c102_vidioc_g_ctrl(struct sn9c102_device* cam, void __user * arg)
static int
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;
	u8 i;
	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++)
		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 ||
			    ctrl.value > s->qctrl[i].maximum)
				return -ERANGE;
@@ -1931,7 +1955,7 @@ sn9c102_vidioc_s_ctrl(struct sn9c102_device* cam, void __user * arg)
static int
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->pixelaspect.numerator = 1;
@@ -1947,7 +1971,7 @@ sn9c102_vidioc_cropcap(struct sn9c102_device* cam, void __user * arg)
static int
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 = {
		.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
	};
@@ -1964,7 +1988,7 @@ sn9c102_vidioc_g_crop(struct sn9c102_device* cam, void __user * arg)
static int
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_rect* rect;
	struct v4l2_rect* bounds = &(s->cropcap.bounds);
@@ -2105,7 +2129,7 @@ static int
sn9c102_vidioc_g_fmt(struct sn9c102_device* cam, void __user * arg)
{
	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)))
		return -EFAULT;
@@ -2130,7 +2154,7 @@ static int
sn9c102_vidioc_try_s_fmt(struct sn9c102_device* cam, unsigned int cmd,
                         void __user * arg)
{
	struct sn9c102_sensor* s = cam->sensor;
	struct sn9c102_sensor* s = &cam->sensor;
	struct v4l2_format format;
	struct v4l2_pix_format* pix;
	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 sn9c102_frame_t *f;
	unsigned long lock_flags;
	int err = 0;
	long timeout;

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

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

	case VIDIOC_G_INPUT:
		return sn9c102_vidioc_g_input(cam, arg);

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

	case VIDIOC_QUERYCTRL:
		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;
	}

	if (!err && cam->sensor) {
		DBG(2, "%s image sensor detected", cam->sensor->name);
	if (!err) {
		DBG(2, "%s image sensor detected", cam->sensor.name);
		DBG(3, "Support for %s maintained by %s",
		    cam->sensor->name, cam->sensor->maintainer);
		    cam->sensor.name, cam->sensor.maintainer);
	} else {
		DBG(1, "No supported image sensor detected");
		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);

	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;

@@ -2841,7 +2870,8 @@ static void sn9c102_usb_disconnect(struct usb_interface* intf)
		sn9c102_stop_transfer(cam);
		cam->state |= DEV_DISCONNECTED;
		wake_up_interruptible(&cam->wait_frame);
		wake_up_interruptible(&cam->wait_stream);
		wake_up(&cam->wait_stream);
		usb_get_dev(cam->usbdev);
	} else {
		cam->state |= DEV_DISCONNECTED;
		sn9c102_release_resources(cam);
+19 −14
Original line number 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, 0x50, 0x19);

	err += sn9c102_i2c_write(cam, 0x12, 0x8d);
	err += sn9c102_i2c_write(cam, 0x11, 0x00);
	err += sn9c102_i2c_write(cam, 0x12, 0x80);
	err += sn9c102_i2c_write(cam, 0x11, 0x01);
	err += sn9c102_i2c_write(cam, 0x15, 0x34);
	err += sn9c102_i2c_write(cam, 0x16, 0x03);
	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, 0x1a, 0xf6);
	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, 0x26, 0xa0);
	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, 0x2a, 0xa0);
	err += sn9c102_i2c_write(cam, 0x2b, 0x1f);
	err += sn9c102_i2c_write(cam, 0x2f, 0x3d);
	err += sn9c102_i2c_write(cam, 0x30, 0x24);
	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);
		break;
	case V4L2_CID_BLUE_BALANCE:
		err += sn9c102_i2c_write(cam, 0x03, ctrl->value);
		err += sn9c102_i2c_write(cam, 0x01, ctrl->value);
		break;
	case V4L2_CID_GAIN:
		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);
		break;
	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;
	case V4L2_CID_AUTOGAIN:
		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)
{
	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;

	sn9c102_attach_sensor(cam, &ov7630);

	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)
	if (!sn9c102_match_id(cam, ov7630_id_table))
		return -ENODEV;

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

	if (err)
		return -EIO;

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

	sn9c102_attach_sensor(cam, &ov7630);

	return 0;
}
Loading