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

[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
......@@ -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;
......
......@@ -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
......
......@@ -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 */
......
......@@ -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,8 +590,9 @@ 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 -
imagesize;
u32 b;
b = (*f)->buf.bytesused + img -
imagesize;
img = imagesize - (*f)->buf.bytesused;
DBG(3, "Expected EOF not found: "
"video frame cut");
......@@ -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,
(cam->stream == STREAM_OFF) ||
(cam->state & DEV_DISCONNECTED),
SN9C102_URB_TIMEOUT);
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
( cam->wait_frame,
(!list_empty(&cam->outqueue)) ||
(cam->state & DEV_DISCONNECTED) ||
(cam->state & DEV_MISCONFIGURED) );
if (err) {
timeout = wait_event_interruptible_timeout
( cam->wait_frame,
(!list_empty(&cam->outqueue)) ||
(cam->state & DEV_DISCONNECTED) ||
(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
( cam->wait_frame,
(!list_empty(&cam->outqueue)) ||
(cam->state & DEV_DISCONNECTED) ||
(cam->state & DEV_MISCONFIGURED) );
if (err)
return err;
timeout = wait_event_interruptible_timeout
( cam->wait_frame,
(!list_empty(&cam->outqueue)) ||
(cam->state & DEV_DISCONNECTED) ||
(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);
......
......@@ -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;
}
/***************************************************************************
* Plug-in for PAS202BCA image sensor connected to the SN9C10x PC Camera *
* Controllers *
* *
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
***************************************************************************/
#include <linux/delay.h>
#include "sn9c102_sensor.h"
static struct sn9c102_sensor pas202bca;
static int pas202bca_init(struct sn9c102_device* cam)
{
int err = 0;
err += sn9c102_write_reg(cam, 0x00, 0x10);
err += sn9c102_write_reg(cam, 0x00, 0x11);
err += sn9c102_write_reg(cam, 0x00, 0x14);
err += sn9c102_write_reg(cam, 0x20, 0x17);
err += sn9c102_write_reg(cam, 0x30, 0x19);
err += sn9c102_write_reg(cam, 0x09, 0x18);
err += sn9c102_i2c_write(cam, 0x02, 0x14);
err += sn9c102_i2c_write(cam, 0x03, 0x40);
err += sn9c102_i2c_write(cam, 0x0d, 0x2c);
err += sn9c102_i2c_write(cam, 0x0e, 0x01);
err += sn9c102_i2c_write(cam, 0x0f, 0xa9);
err += sn9c102_i2c_write(cam, 0x10, 0x08);
err += sn9c102_i2c_write(cam, 0x13, 0x63);
err += sn9c102_i2c_write(cam, 0x15, 0x70);
err += sn9c102_i2c_write(cam, 0x11, 0x01);
msleep(400);
return err;
}
static int pas202bca_set_pix_format(struct sn9c102_device* cam,
const struct v4l2_pix_format* pix)
{
int err = 0;
if (pix->pixelformat == V4L2_PIX_FMT_SN9C10X)
err += sn9c102_write_reg(cam, 0x24, 0x17);
else
err += sn9c102_write_reg(cam, 0x20, 0x17);
return err;
}
static int pas202bca_set_ctrl(struct sn9c102_device* cam,
const struct v4l2_control* ctrl)
{
int err = 0;
switch (ctrl->id) {
case V4L2_CID_EXPOSURE:
err += sn9c102_i2c_write(cam, 0x04, ctrl->value >> 6);
err += sn9c102_i2c_write(cam, 0x05, ctrl->value & 0x3f);
break;
case V4L2_CID_RED_BALANCE:
err += sn9c102_i2c_write(cam, 0x09, ctrl->value);
break;
case V4L2_CID_BLUE_BALANCE:
err += sn9c102_i2c_write(cam, 0x07, ctrl->value);
break;
case V4L2_CID_GAIN:
err += sn9c102_i2c_write(cam, 0x10, ctrl->value);
break;
case SN9C102_V4L2_CID_GREEN_BALANCE:
err += sn9c102_i2c_write(cam, 0x08, ctrl->value);
break;
case SN9C102_V4L2_CID_DAC_MAGNITUDE:
err += sn9c102_i2c_write(cam, 0x0c, ctrl->value);
break;
default:
return -EINVAL;
}
err += sn9c102_i2c_write(cam, 0x11, 0x01);
return err ? -EIO : 0;
}
static int pas202bca_set_crop(struct sn9c102_device* cam,
const struct v4l2_rect* rect)
{
struct sn9c102_sensor* s = &pas202bca;
int err = 0;
u8 h_start = (u8)(rect->left - s->cropcap.bounds.left) + 3,
v_start = (u8)(rect->top - s->cropcap.bounds.top) + 3;
err += sn9c102_write_reg(cam, h_start, 0x12);
err += sn9c102_write_reg(cam, v_start, 0x13);
return err;
}
static struct sn9c102_sensor pas202bca = {
.name = "PAS202BCA",
.maintainer = "Luca Risolia <luca.risolia@studio.unibo.it>",
.sysfs_ops = SN9C102_I2C_READ | SN9C102_I2C_WRITE,
.frequency = SN9C102_I2C_400KHZ | SN9C102_I2C_100KHZ,
.interface = SN9C102_I2C_2WIRES,
.i2c_slave_id = 0x40,
.init = &pas202bca_init,
.qctrl = {
{
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "exposure",
.minimum = 0x01e5,
.maximum = 0x3fff,
.step = 0x0001,
.default_value = 0x01e5,
.flags = 0,
},
{
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "global gain",
.minimum = 0x00,
.maximum = 0x1f,
.step = 0x01,
.default_value = 0x0c,
.flags = 0,
},
{
.id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "red balance",
.minimum = 0x00,
.maximum = 0x0f,
.step = 0x01,
.default_value = 0x01,
.flags = 0,
},
{
.id = V4L2_CID_BLUE_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "blue balance",
.minimum = 0x00,
.maximum = 0x0f,
.step = 0x01,
.default_value = 0x05,
.flags = 0,
},
{
.id = SN9C102_V4L2_CID_GREEN_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "green balance",
.minimum = 0x00,
.maximum = 0x0f,
.step = 0x01,
.default_value = 0x00,
.flags = 0,
},
{
.id = SN9C102_V4L2_CID_DAC_MAGNITUDE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "DAC magnitude",
.minimum = 0x00,
.maximum = 0xff,
.step = 0x01,
.default_value = 0x04,
.flags = 0,
},
},
.set_ctrl = &pas202bca_set_ctrl,
.cropcap = {
.bounds = {
.left = 0,
.top = 0,
.width = 640,
.height = 480,
},
.defrect = {
.left = 0,
.top = 0,
.width = 640,
.height = 480,
},
},
.set_crop = &pas202bca_set_crop,
.pix_format = {
.width = 640,
.height = 480,
.pixelformat = V4L2_PIX_FMT_SBGGR8,
.priv = 8,
},
.set_pix_format = &pas202bca_set_pix_format
};
int sn9c102_probe_pas202bca(struct sn9c102_device* cam)
{
const struct usb_device_id pas202bca_id_table[] = {
{ USB_DEVICE(0x0c45, 0x60af), },
{ }
};
int err = 0;
if (!sn9c102_match_id(cam,pas202bca_id_table))
return -ENODEV;
err += sn9c102_write_reg(cam, 0x01, 0x01);
err += sn9c102_write_reg(cam, 0x40, 0x01);
err += sn9c102_write_reg(cam, 0x28, 0x17);
if (err)
return -EIO;
if (sn9c102_i2c_try_write(cam, &pas202bca, 0x10, 0)) /* try to write */
return -ENODEV;
sn9c102_attach_sensor(cam, &pas202bca);
return 0;
}
......@@ -263,7 +263,7 @@ static struct sn9c102_sensor pas202bcb = {
int sn9c102_probe_pas202bcb(struct sn9c102_device* cam)
{
{
int r0 = 0, r1 = 0, err = 0;
unsigned int pid = 0;
......
......@@ -66,6 +66,7 @@ extern int sn9c102_probe_hv7131d(struct sn9c102_device* cam);
extern int sn9c102_probe_mi0343(struct sn9c102_device* cam);
extern int sn9c102_probe_ov7630(struct sn9c102_device* cam);
extern int sn9c102_probe_pas106b(struct sn9c102_device* cam);
extern int sn9c102_probe_pas202bca(struct sn9c102_device* cam);
extern int sn9c102_probe_pas202bcb(struct sn9c102_device* cam);
extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
extern int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam);
......@@ -81,12 +82,17 @@ static int (*sn9c102_sensor_table[])(struct sn9c102_device*) = { \
&sn9c102_probe_pas106b, /* strong detection based on SENSOR ids */ \
&sn9c102_probe_pas202bcb, /* strong detection based on SENSOR ids */ \
&sn9c102_probe_hv7131d, /* strong detection based on SENSOR ids */ \
&sn9c102_probe_pas202bca, /* detection mostly based on USB pid/vid */ \
&sn9c102_probe_ov7630, /* detection mostly based on USB pid/vid */ \
&sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ \
&sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ \
NULL, \
};
/* Device identification */
extern struct sn9c102_device*
sn9c102_match_id(struct sn9c102_device* cam, const struct usb_device_id *id);
/* Attach a probed sensor to the camera. */
extern void
sn9c102_attach_sensor(struct sn9c102_device* cam,
......@@ -108,6 +114,7 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
static const struct usb_device_id sn9c102_id_table[] = { \
{ USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */ \
{ USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */ \
{ USB_DEVICE(0x0c45, 0x6007), }, \
{ USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */ \
{ USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */ \
{ USB_DEVICE(0x0c45, 0x6024), }, \
......@@ -126,7 +133,7 @@ static const struct usb_device_id sn9c102_id_table[] = { \
{ SN9C102_USB_DEVICE(0x0c45, 0x6088, 0xff), }, \
{ SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), }, \
{ SN9C102_USB_DEVICE(0x0c45, 0x608b, 0xff), }, \
{ SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131x */ \
{ SN9C102_USB_DEVICE(0x0c45, 0x608c, 0xff), }, /* HV7131/R */ \
{ SN9C102_USB_DEVICE(0x0c45, 0x608e, 0xff), }, /* CIS-VF10 */ \
{ SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */ \
{ SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), }, \
......@@ -359,12 +366,6 @@ struct sn9c102_sensor {
error code without rolling back.
*/
const struct usb_device* usbdev;
/*
Points to the usb_device struct after the sensor is attached.
Do not touch unless you know what you are doing.
*/
/*
Do NOT write to the data below, it's READ ONLY. It is used by the
core module to store successfully updated values of the above
......
......@@ -142,14 +142,18 @@ static struct sn9c102_sensor tas5110c1b = {
int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
{
/* This sensor has no identifiers, so let's attach it anyway */
sn9c102_attach_sensor(cam, &tas5110c1b);
const struct usb_device_id tas5110c1b_id_table[] = {
{ USB_DEVICE(0x0c45, 0x6001), },
{ USB_DEVICE(0x0c45, 0x6005), },
{ USB_DEVICE(0x0c45, 0x60ab), },
{ }
};
/* Sensor detection is based on USB pid/vid */
if (le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x6001 &&
le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x6005 &&
le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x60ab)
if (!sn9c102_match_id(cam, tas5110c1b_id_table))
return -ENODEV;
sn9c102_attach_sensor(cam, &tas5110c1b);
return 0;
}
......@@ -153,13 +153,17 @@ static struct sn9c102_sensor tas5130d1b = {
int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
{
/* This sensor has no identifiers, so let's attach it anyway */
sn9c102_attach_sensor(cam, &tas5130d1b);
const struct usb_device_id tas5130d1b_id_table[] = {
{ USB_DEVICE(0x0c45, 0x6025), },
{ USB_DEVICE(0x0c45, 0x60aa), },
{ }
};
/* Sensor detection is based on USB pid/vid */
if (le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x6025 &&
le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x60aa)
if (!sn9c102_match_id(cam, tas5130d1b_id_table))
return -ENODEV;
sn9c102_attach_sensor(cam, &tas5130d1b);
return 0;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment