]> err.no Git - linux-2.6/commitdiff
[PATCH] USB: SN9C10x driver updates
authorLuca Risolia <luca.risolia@studio.unibo.it>
Sat, 25 Feb 2006 06:50:47 +0000 (06:50 +0000)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 20 Mar 2006 22:49:59 +0000 (14:49 -0800)
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>
Documentation/usb/sn9c102.txt
drivers/usb/media/Makefile
drivers/usb/media/sn9c102.h
drivers/usb/media/sn9c102_core.c
drivers/usb/media/sn9c102_ov7630.c
drivers/usb/media/sn9c102_pas202bca.c [new file with mode: 0644]
drivers/usb/media/sn9c102_pas202bcb.c
drivers/usb/media/sn9c102_sensor.h
drivers/usb/media/sn9c102_tas5110c1b.c
drivers/usb/media/sn9c102_tas5130d1b.c

index c6b76414172cd74455103acbec763b2e49882b90..b957beae5607619c4a75764dd8982999167fd756 100644 (file)
@@ -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;
index 333bf09ca2d65e41af54f0d7c76686ea52e76391..50e89a33b85ec02bd4d3d8f6f4ba14da93d37f3a 100644 (file)
@@ -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
 
index 59e44be27cb4b48e2113039dc30c3c66b3361f7f..1d70a62b9f2386906cd6cbf00f4b4d2bd1d4bc80 100644 (file)
@@ -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 */
index 30119080871be8fc60adde267183d182cface1a4..4c6cc6395723bdb6f9040996c84da08cd766714e 100644 (file)
 #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 @@ end_of_frame:
                                        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 @@ end_of_frame:
                                (*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 @@ start_of_frame:
                        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 @@ exit:
 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);
index 4a36519b5af40f067c05d80c3c1310cd01a4d612..42852b7cb04206b9e3d0be2c8e7eb2995e295721 100644 (file)
@@ -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;
 }
diff --git a/drivers/usb/media/sn9c102_pas202bca.c b/drivers/usb/media/sn9c102_pas202bca.c
new file mode 100644 (file)
index 0000000..3453237
--- /dev/null
@@ -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;
+}
index 5ca54c7daaf2bebf1305d6a2afa1e35bc4135641..d068616ab337490a0c43a2cb20adf16f91d6431f 100644 (file)
@@ -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;
 
index 7d953b24f2f2a168cc52fe30c06e53c090c35bfc..2afd9e9d09bb4c1fb7e48096fdd1b29138d316b3 100644 (file)
@@ -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
index 32ddf236cafed990b242404473cc3dc41f82f102..2e08c552f40a85ce69630c8e8754fc77f020d8a9 100644 (file)
@@ -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;
 }
index a0728f0ae00cdd72ea5890aab6835176f9e192fb..c7b339740bbf6b016335c529e03f9fdd107b2cab 100644 (file)
@@ -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;
 }