[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: Luca Risolia <luca.risolia@studio.unibo.it> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
7039f4224d
commit
2ffab02fea
@@ -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;
|
||||||
|
@@ -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
|
||||||
|
|
||||||
|
@@ -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 */
|
||||||
|
@@ -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 @@ end_of_frame:
|
|||||||
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 @@ end_of_frame:
|
|||||||
(*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 @@ start_of_frame:
|
|||||||
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 @@ exit:
|
|||||||
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);
|
||||||
|
@@ -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;
|
||||||
}
|
}
|
||||||
|
238
drivers/usb/media/sn9c102_pas202bca.c
Normal file
238
drivers/usb/media/sn9c102_pas202bca.c
Normal file
@@ -0,0 +1,238 @@
|
|||||||
|
/***************************************************************************
|
||||||
|
* 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;
|
||||||
|
}
|
@@ -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_mi0343(struct sn9c102_device* cam);
|
||||||
extern int sn9c102_probe_ov7630(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_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_pas202bcb(struct sn9c102_device* cam);
|
||||||
extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
|
extern int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam);
|
||||||
extern int sn9c102_probe_tas5130d1b(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_pas106b, /* strong detection based on SENSOR ids */ \
|
||||||
&sn9c102_probe_pas202bcb, /* 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_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_ov7630, /* detection mostly based on USB pid/vid */ \
|
||||||
&sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ \
|
&sn9c102_probe_tas5110c1b, /* detection based on USB pid/vid */ \
|
||||||
&sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ \
|
&sn9c102_probe_tas5130d1b, /* detection based on USB pid/vid */ \
|
||||||
NULL, \
|
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. */
|
/* Attach a probed sensor to the camera. */
|
||||||
extern void
|
extern void
|
||||||
sn9c102_attach_sensor(struct sn9c102_device* cam,
|
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[] = { \
|
static const struct usb_device_id sn9c102_id_table[] = { \
|
||||||
{ USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */ \
|
{ USB_DEVICE(0x0c45, 0x6001), }, /* TAS5110C1B */ \
|
||||||
{ USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */ \
|
{ USB_DEVICE(0x0c45, 0x6005), }, /* TAS5110C1B */ \
|
||||||
|
{ USB_DEVICE(0x0c45, 0x6007), }, \
|
||||||
{ USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */ \
|
{ USB_DEVICE(0x0c45, 0x6009), }, /* PAS106B */ \
|
||||||
{ USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */ \
|
{ USB_DEVICE(0x0c45, 0x600d), }, /* PAS106B */ \
|
||||||
{ USB_DEVICE(0x0c45, 0x6024), }, \
|
{ 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, 0x6088, 0xff), }, \
|
||||||
{ SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), }, \
|
{ SN9C102_USB_DEVICE(0x0c45, 0x608a, 0xff), }, \
|
||||||
{ SN9C102_USB_DEVICE(0x0c45, 0x608b, 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, 0x608e, 0xff), }, /* CIS-VF10 */ \
|
||||||
{ SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */ \
|
{ SN9C102_USB_DEVICE(0x0c45, 0x608f, 0xff), }, /* OV7630 */ \
|
||||||
{ SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), }, \
|
{ SN9C102_USB_DEVICE(0x0c45, 0x60a0, 0xff), }, \
|
||||||
@@ -359,12 +366,6 @@ struct sn9c102_sensor {
|
|||||||
error code without rolling back.
|
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
|
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
|
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)
|
int sn9c102_probe_tas5110c1b(struct sn9c102_device* cam)
|
||||||
{
|
{
|
||||||
/* This sensor has no identifiers, so let's attach it anyway */
|
const struct usb_device_id tas5110c1b_id_table[] = {
|
||||||
sn9c102_attach_sensor(cam, &tas5110c1b);
|
{ USB_DEVICE(0x0c45, 0x6001), },
|
||||||
|
{ USB_DEVICE(0x0c45, 0x6005), },
|
||||||
|
{ USB_DEVICE(0x0c45, 0x60ab), },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
/* Sensor detection is based on USB pid/vid */
|
/* Sensor detection is based on USB pid/vid */
|
||||||
if (le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x6001 &&
|
if (!sn9c102_match_id(cam, tas5110c1b_id_table))
|
||||||
le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x6005 &&
|
|
||||||
le16_to_cpu(tas5110c1b.usbdev->descriptor.idProduct) != 0x60ab)
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
sn9c102_attach_sensor(cam, &tas5110c1b);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@@ -153,13 +153,17 @@ static struct sn9c102_sensor tas5130d1b = {
|
|||||||
|
|
||||||
int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
|
int sn9c102_probe_tas5130d1b(struct sn9c102_device* cam)
|
||||||
{
|
{
|
||||||
/* This sensor has no identifiers, so let's attach it anyway */
|
const struct usb_device_id tas5130d1b_id_table[] = {
|
||||||
sn9c102_attach_sensor(cam, &tas5130d1b);
|
{ USB_DEVICE(0x0c45, 0x6025), },
|
||||||
|
{ USB_DEVICE(0x0c45, 0x60aa), },
|
||||||
|
{ }
|
||||||
|
};
|
||||||
|
|
||||||
/* Sensor detection is based on USB pid/vid */
|
/* Sensor detection is based on USB pid/vid */
|
||||||
if (le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x6025 &&
|
if (!sn9c102_match_id(cam, tas5130d1b_id_table))
|
||||||
le16_to_cpu(tas5130d1b.usbdev->descriptor.idProduct) != 0x60aa)
|
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
sn9c102_attach_sensor(cam, &tas5130d1b);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user