diff options
author | Luca Risolia <luca.risolia@studio.unibo.it> | 2006-02-25 06:57:49 +0000 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2006-03-20 14:50:00 -0800 |
commit | a847423905c6a8ccd6671d05f5877d893d10cd9f (patch) | |
tree | ca7a67a3f37889bf7c612d246fa5173dfbef320a | |
parent | ccad7789d5e557644d1c866b018394872af0ec5b (diff) |
[PATCH] USB: ZC0301 driver updates
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>
-rw-r--r-- | Documentation/usb/zc0301.txt | 29 | ||||
-rw-r--r-- | drivers/usb/media/zc0301.h | 20 | ||||
-rw-r--r-- | drivers/usb/media/zc0301_core.c | 58 | ||||
-rw-r--r-- | drivers/usb/media/zc0301_pas202bcb.c | 38 | ||||
-rw-r--r-- | drivers/usb/media/zc0301_sensor.h | 25 |
5 files changed, 108 insertions, 62 deletions
diff --git a/Documentation/usb/zc0301.txt b/Documentation/usb/zc0301.txt index 0889ae6ac7d8..095838420e82 100644 --- a/Documentation/usb/zc0301.txt +++ b/Documentation/usb/zc0301.txt @@ -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>. diff --git a/drivers/usb/media/zc0301.h b/drivers/usb/media/zc0301.h index cb1a0823bc63..9ba9135e824b 100644 --- a/drivers/usb/media/zc0301.h +++ b/drivers/usb/media/zc0301.h @@ -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)); } /*****************************************************************************/ diff --git a/drivers/usb/media/zc0301_core.c b/drivers/usb/media/zc0301_core.c index 7e8b1676d144..5773688d3dae 100644 --- a/drivers/usb/media/zc0301_core.c +++ b/drivers/usb/media/zc0301_core.c @@ -29,11 +29,9 @@ #include <linux/moduleparam.h> #include <linux/errno.h> #include <linux/slab.h> -#include <linux/string.h> #include <linux/device.h> #include <linux/fs.h> #include <linux/delay.h> -#include <linux/stddef.h> #include <linux/compiler.h> #include <linux/ioctl.h> #include <linux/poll.h> @@ -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); diff --git a/drivers/usb/media/zc0301_pas202bcb.c b/drivers/usb/media/zc0301_pas202bcb.c index 32b9b9329cbf..9d282a22c15f 100644 --- a/drivers/usb/media/zc0301_pas202bcb.c +++ b/drivers/usb/media/zc0301_pas202bcb.c @@ -22,6 +22,14 @@ * 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, diff --git a/drivers/usb/media/zc0301_sensor.h b/drivers/usb/media/zc0301_sensor.h index 8890e32405d4..e3cb6cc920ca 100644 --- a/drivers/usb/media/zc0301_sensor.h +++ b/drivers/usb/media/zc0301_sensor.h @@ -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]; |