[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>
This commit is contained in:
Luca Risolia 2006-02-25 06:57:49 +00:00 committed by Greg Kroah-Hartman
parent ccad7789d5
commit a847423905
5 changed files with 108 additions and 62 deletions

View 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>.

View 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));
}
/*****************************************************************************/

View File

@ -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);

View File

@ -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,

View 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];