[PATCH] USB: ZC0301 driver updates
authorLuca Risolia <luca.risolia@studio.unibo.it>
Sat, 25 Feb 2006 06:57:49 +0000 (06:57 +0000)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 20 Mar 2006 22:50:00 +0000 (14:50 -0800)
ZC0301 driver updates.

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

@ Need usb_get|put_dev() when disconnecting, if the device is open
* Cleanups and updates in the documentation
+ Use per-device sensor structures
+ 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/zc0301.txt
drivers/usb/media/zc0301.h
drivers/usb/media/zc0301_core.c
drivers/usb/media/zc0301_pas202bcb.c
drivers/usb/media/zc0301_sensor.h

index 0889ae6ac7d8df00500a052cfa7bd4fb8e5acdc7..095838420e82e9d130877add8c3f139ff551d0d3 100644 (file)
@@ -68,11 +68,6 @@ Some of the features of the driver are:
   data transfers;
 - automatic detection of image sensor;
 - video format is standard JPEG;
-- full support for the capabilities of every possible image sensors that can
-  be connected to the ZC0301 bridges, including, for istance, red, green,
-  blue and global gain adjustments and exposure control (see "Supported
-  devices" paragraph for details);
-- use of default color settings for sunlight conditions;
 - dynamic driver control thanks to various module parameters (see "Module
   parameters" paragraph);
 - up to 64 cameras can be handled at the same time; they can be connected and
@@ -171,6 +166,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>
@@ -198,17 +201,23 @@ devices mounting the ZC0301 Image Processor and Control Chips:
 
 Vendor ID  Product ID
 ---------  ----------
+0x10fd     0x8050
+0x041e     0x0417
+0x041e     0x041e
+0x041e     0x081c
+0x041e     0x0834
+0x041e     0x0835
 0x046d     0x08ae
+0x0ac8     0x0301
 
-The following image sensors are supported:
+The list above does not imply that all those devices work with this driver: up
+until now only the ones that mount the following image sensors are supported;
+kernel messages will always tell you whether this is the case:
 
 Model       Manufacturer
 -----       ------------
 PAS202BCB   PixArt Imaging, Inc.
 
-All the available control settings of each image sensor are supported through
-the V4L2 interface.
-
 
 9. Notes for V4L2 application developers
 ========================================
@@ -240,6 +249,6 @@ the fingerprint is: '88E8 F32F 7244 68BA 3958  5D40 99DA 5D2A FCE6 35A4'.
 - Informations about the chip internals needed to enable the I2C protocol have
   been taken from the documentation of the ZC030x Video4Linux1 driver written
   by Andrew Birkett <andy@nobugs.org>;
-- Initialization values of the ZC0301 controller connected to the PAS202BCB
+- The initialization values of the ZC0301 controller connected to the PAS202BCB
   image sensor have been taken from the SPCA5XX driver maintained by
   Michel Xhaard <mxhaard@magic.fr>.
index cb1a0823bc63f907423c184bda4b689295b545fb..9ba9135e824becc7b63a81188917179aa9b626d5 100644 (file)
@@ -34,7 +34,8 @@
 #include <linux/param.h>
 #include <linux/mutex.h>
 #include <linux/rwsem.h>
-#include <asm/semaphore.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
 
 #include "zc0301_sensor.h"
 
@@ -51,7 +52,7 @@
 #define ZC0301_ALTERNATE_SETTING   7
 #define ZC0301_URB_TIMEOUT         msecs_to_jiffies(2 * ZC0301_ISO_PACKETS)
 #define ZC0301_CTRL_TIMEOUT        100
-#define ZC0301_FRAME_TIMEOUT       2 * 1000 * msecs_to_jiffies(1)
+#define ZC0301_FRAME_TIMEOUT       2
 
 /*****************************************************************************/
 
@@ -94,6 +95,7 @@ enum zc0301_stream_state {
 
 struct zc0301_module_param {
        u8 force_munmap;
+       u16 frame_timeout;
 };
 
 static DECLARE_RWSEM(zc0301_disconnect);
@@ -101,7 +103,7 @@ static DECLARE_RWSEM(zc0301_disconnect);
 struct zc0301_device {
        struct video_device* v4ldev;
 
-       struct zc0301_sensor* sensor;
+       struct zc0301_sensor sensor;
 
        struct usb_device* usbdev;
        struct urb* urb[ZC0301_URBS];
@@ -129,11 +131,19 @@ struct zc0301_device {
 
 /*****************************************************************************/
 
+struct zc0301_device*
+zc0301_match_id(struct zc0301_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
 zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor)
 {
-       cam->sensor = sensor;
-       cam->sensor->usbdev = cam->usbdev;
+       memcpy(&cam->sensor, sensor, sizeof(struct zc0301_sensor));
 }
 
 /*****************************************************************************/
index 7e8b1676d144fa07ac79b52dbcc3e4432b90cb65..5773688d3dae8e923e832fdc11025f43819e93a4 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>
@@ -54,8 +52,8 @@
 #define ZC0301_MODULE_AUTHOR  "(C) 2006 Luca Risolia"
 #define ZC0301_AUTHOR_EMAIL   "<luca.risolia@studio.unibo.it>"
 #define ZC0301_MODULE_LICENSE "GPL"
-#define ZC0301_MODULE_VERSION "1:1.01"
-#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 1)
+#define ZC0301_MODULE_VERSION "1:1.02"
+#define ZC0301_MODULE_VERSION_CODE  KERNEL_VERSION(1, 0, 2)
 
 /*****************************************************************************/
 
@@ -94,6 +92,15 @@ MODULE_PARM_DESC(force_munmap,
                  "\nDefault value is "__MODULE_STRING(SN9C102_FORCE_MUNMAP)"."
                  "\n");
 
+static unsigned int frame_timeout[] = {[0 ... ZC0301_MAX_DEVICES-1] =
+                                       ZC0301_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(ZC0301_FRAME_TIMEOUT)"."
+                 "\n");
+
 #ifdef ZC0301_DEBUG
 static unsigned short debug = ZC0301_DEBUG_LEVEL;
 module_param(debug, ushort, 0644);
@@ -115,8 +122,8 @@ static u32
 zc0301_request_buffers(struct zc0301_device* cam, u32 count,
                        enum zc0301_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 :
@@ -332,9 +339,9 @@ static void zc0301_urb_complete(struct urb *urb, struct pt_regs* regs)
                (*f) = list_entry(cam->inqueue.next, struct zc0301_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;
 
        for (i = 0; i < urb->number_of_packets; i++) {
                unsigned int len, status;
@@ -555,7 +562,7 @@ zc0301_set_compression(struct zc0301_device* cam,
 
 static int zc0301_init(struct zc0301_device* cam)
 {
-       struct zc0301_sensor* s = cam->sensor;
+       struct zc0301_sensor* s = &cam->sensor;
        struct v4l2_control ctrl;
        struct v4l2_queryctrl *qctrl;
        struct v4l2_rect* rect;
@@ -630,6 +637,7 @@ static void zc0301_release_resources(struct zc0301_device* cam)
        DBG(2, "V4L2 device /dev/video%d deregistered", cam->v4ldev->minor);
        video_set_drvdata(cam->v4ldev, NULL);
        video_unregister_device(cam->v4ldev);
+       usb_put_dev(cam->usbdev);
        kfree(cam->control_buffer);
 }
 
@@ -798,7 +806,8 @@ zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
                            (!list_empty(&cam->outqueue)) ||
                            (cam->state & DEV_DISCONNECTED) ||
                            (cam->state & DEV_MISCONFIGURED),
-                           ZC0301_FRAME_TIMEOUT );
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
                if (timeout < 0) {
                        mutex_unlock(&cam->fileop_mutex);
                        return timeout;
@@ -1056,7 +1065,7 @@ zc0301_vidioc_s_input(struct zc0301_device* cam, void __user * arg)
 static int
 zc0301_vidioc_query_ctrl(struct zc0301_device* cam, void __user * arg)
 {
-       struct zc0301_sensor* s = cam->sensor;
+       struct zc0301_sensor* s = &cam->sensor;
        struct v4l2_queryctrl qc;
        u8 i;
 
@@ -1078,7 +1087,7 @@ zc0301_vidioc_query_ctrl(struct zc0301_device* cam, void __user * arg)
 static int
 zc0301_vidioc_g_ctrl(struct zc0301_device* cam, void __user * arg)
 {
-       struct zc0301_sensor* s = cam->sensor;
+       struct zc0301_sensor* s = &cam->sensor;
        struct v4l2_control ctrl;
        int err = 0;
        u8 i;
@@ -1110,7 +1119,7 @@ exit:
 static int
 zc0301_vidioc_s_ctrl(struct zc0301_device* cam, void __user * arg)
 {
-       struct zc0301_sensor* s = cam->sensor;
+       struct zc0301_sensor* s = &cam->sensor;
        struct v4l2_control ctrl;
        u8 i;
        int err = 0;
@@ -1123,6 +1132,8 @@ zc0301_vidioc_s_ctrl(struct zc0301_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;
@@ -1142,7 +1153,7 @@ zc0301_vidioc_s_ctrl(struct zc0301_device* cam, void __user * arg)
 static int
 zc0301_vidioc_cropcap(struct zc0301_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;
@@ -1158,7 +1169,7 @@ zc0301_vidioc_cropcap(struct zc0301_device* cam, void __user * arg)
 static int
 zc0301_vidioc_g_crop(struct zc0301_device* cam, void __user * arg)
 {
-       struct zc0301_sensor* s = cam->sensor;
+       struct zc0301_sensor* s = &cam->sensor;
        struct v4l2_crop crop = {
                .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
        };
@@ -1175,7 +1186,7 @@ zc0301_vidioc_g_crop(struct zc0301_device* cam, void __user * arg)
 static int
 zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg)
 {
-       struct zc0301_sensor* s = cam->sensor;
+       struct zc0301_sensor* s = &cam->sensor;
        struct v4l2_crop crop;
        struct v4l2_rect* rect;
        struct v4l2_rect* bounds = &(s->cropcap.bounds);
@@ -1304,7 +1315,7 @@ static int
 zc0301_vidioc_g_fmt(struct zc0301_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;
@@ -1328,7 +1339,7 @@ static int
 zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd,
                         void __user * arg)
 {
-       struct zc0301_sensor* s = cam->sensor;
+       struct zc0301_sensor* s = &cam->sensor;
        struct v4l2_format format;
        struct v4l2_pix_format* pix;
        struct v4l2_pix_format* pfmt = &(s->pix_format);
@@ -1612,7 +1623,8 @@ zc0301_vidioc_dqbuf(struct zc0301_device* cam, struct file* filp,
                            (!list_empty(&cam->outqueue)) ||
                            (cam->state & DEV_DISCONNECTED) ||
                            (cam->state & DEV_MISCONFIGURED),
-                           ZC0301_FRAME_TIMEOUT );
+                           cam->module_param.frame_timeout *
+                           1000 * msecs_to_jiffies(1) );
                if (timeout < 0)
                        return timeout;
                if (cam->state & DEV_DISCONNECTED)
@@ -1911,8 +1923,8 @@ zc0301_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);
        else {
                DBG(1, "No supported image sensor detected");
                err = -ENODEV;
@@ -1950,6 +1962,7 @@ zc0301_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 < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
 
@@ -1994,6 +2007,7 @@ static void zc0301_usb_disconnect(struct usb_interface* intf)
                cam->state |= DEV_DISCONNECTED;
                wake_up_interruptible(&cam->wait_frame);
                wake_up(&cam->wait_stream);
+               usb_get_dev(cam->usbdev);
        } else {
                cam->state |= DEV_DISCONNECTED;
                zc0301_release_resources(cam);
index 32b9b9329cbf90ad5a02d8d7195928aec6b96598..9d282a22c15fff5d00bc4ce884bc7015a46ba904 100644 (file)
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.               *
  ***************************************************************************/
 
+/*
+   NOTE: Sensor controls are disabled for now, becouse changing them while
+         streaming sometimes results in out-of-sync video frames. We'll use
+         the default initialization, until we know how to stop and start video
+         in the chip. However, the image quality still looks good under various
+         light conditions.
+*/
+
 #include <linux/delay.h>
 #include "zc0301_sensor.h"
 
@@ -245,7 +253,7 @@ static struct zc0301_sensor pas202bcb = {
                        .maximum = 0x3fff,
                        .step = 0x0001,
                        .default_value = 0x01e5,
-                       .flags = 0,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
                },
                {
                        .id = V4L2_CID_GAIN,
@@ -255,7 +263,17 @@ static struct zc0301_sensor pas202bcb = {
                        .maximum = 0x1f,
                        .step = 0x01,
                        .default_value = 0x0c,
-                       .flags = 0,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
+               },
+               {
+                       .id = ZC0301_V4L2_CID_DAC_MAGNITUDE,
+                       .type = V4L2_CTRL_TYPE_INTEGER,
+                       .name = "DAC magnitude",
+                       .minimum = 0x00,
+                       .maximum = 0xff,
+                       .step = 0x01,
+                       .default_value = 0x00,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
                },
                {
                        .id = V4L2_CID_RED_BALANCE,
@@ -265,7 +283,7 @@ static struct zc0301_sensor pas202bcb = {
                        .maximum = 0x0f,
                        .step = 0x01,
                        .default_value = 0x01,
-                       .flags = 0,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
                },
                {
                        .id = V4L2_CID_BLUE_BALANCE,
@@ -275,7 +293,7 @@ static struct zc0301_sensor pas202bcb = {
                        .maximum = 0x0f,
                        .step = 0x01,
                        .default_value = 0x05,
-                       .flags = 0,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
                },
                {
                        .id = ZC0301_V4L2_CID_GREEN_BALANCE,
@@ -285,17 +303,7 @@ static struct zc0301_sensor pas202bcb = {
                        .maximum = 0x0f,
                        .step = 0x01,
                        .default_value = 0x00,
-                       .flags = 0,
-               },
-               {
-                       .id = ZC0301_V4L2_CID_DAC_MAGNITUDE,
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .name = "DAC magnitude",
-                       .minimum = 0x00,
-                       .maximum = 0xff,
-                       .step = 0x01,
-                       .default_value = 0x04,
-                       .flags = 0,
+                       .flags = V4L2_CTRL_FLAG_DISABLED,
                },
        },
        .get_ctrl = &pas202bcb_get_ctrl,
index 8890e32405d4224c7838af6b952f6b5457b19c06..e3cb6cc920ca9b0924d6b76bbe83ba80ba71140c 100644 (file)
@@ -43,9 +43,11 @@ static int (*zc0301_sensor_table[])(struct zc0301_device*) = {                \
        NULL,                                                                 \
 };
 
+extern struct zc0301_device*
+zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id);
+
 extern void
-zc0301_attach_sensor(struct zc0301_device* cam,
-                       struct zc0301_sensor* sensor);
+zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor);
 
 #define ZC0301_USB_DEVICE(vend, prod, intclass)                               \
        .match_flags = USB_DEVICE_ID_MATCH_DEVICE |                           \
@@ -56,7 +58,14 @@ zc0301_attach_sensor(struct zc0301_device* cam,
 
 #define ZC0301_ID_TABLE                                                       \
 static const struct usb_device_id zc0301_id_table[] =  {                      \
+       { ZC0301_USB_DEVICE(0x10fd, 0x8050, 0xff), }, /* TAS5130D */          \
+       { ZC0301_USB_DEVICE(0x041e, 0x0417, 0xff), },                         \
+       { ZC0301_USB_DEVICE(0x041e, 0x041e, 0xff), }, /* HV7131B */           \
+       { ZC0301_USB_DEVICE(0x041e, 0x081c, 0xff), }, /* PAS106 */            \
+       { ZC0301_USB_DEVICE(0x041e, 0x0834, 0xff), }, /* PAS106 */            \
+       { ZC0301_USB_DEVICE(0x041e, 0x0835, 0xff), }, /* PAS106 */            \
        { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202BCB */         \
+       { ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), },                         \
        { }                                                                   \
 };
 
@@ -80,15 +89,11 @@ struct zc0301_sensor {
        struct v4l2_cropcap cropcap;
        struct v4l2_pix_format pix_format;
 
-       int (*init)(struct zc0301_device* cam);
-       int (*get_ctrl)(struct zc0301_device* cam,
-                       struct v4l2_control* ctrl);
-       int (*set_ctrl)(struct zc0301_device* cam,
+       int (*init)(struct zc0301_device*);
+       int (*get_ctrl)(struct zc0301_device*, struct v4l2_control* ctrl);
+       int (*set_ctrl)(struct zc0301_device*,
                        const struct v4l2_control* ctrl);
-       int (*set_crop)(struct zc0301_device* cam,
-                       const struct v4l2_rect* rect);
-
-       const struct usb_device* usbdev;
+       int (*set_crop)(struct zc0301_device*, const struct v4l2_rect* rect);
 
        /* Private */
        struct v4l2_queryctrl _qctrl[ZC0301_MAX_CTRLS];