Skip to content

Commit

Permalink
[PATCH] USB: ZC0301 driver updates
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Luca Risolia authored and Greg Kroah-Hartman committed Mar 20, 2006
1 parent ccad778 commit a847423
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 62 deletions.
29 changes: 19 additions & 10 deletions Documentation/usb/zc0301.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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>
Expand Down Expand Up @@ -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
========================================
Expand Down Expand Up @@ -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>.
20 changes: 15 additions & 5 deletions drivers/usb/media/zc0301.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand All @@ -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

/*****************************************************************************/

Expand Down Expand Up @@ -94,14 +95,15 @@ enum zc0301_stream_state {

struct zc0301_module_param {
u8 force_munmap;
u16 frame_timeout;
};

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];
Expand Down Expand Up @@ -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));
}

/*****************************************************************************/
Expand Down
58 changes: 36 additions & 22 deletions drivers/usb/media/zc0301_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand All @@ -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)

/*****************************************************************************/

Expand Down Expand Up @@ -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);
Expand All @@ -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 :
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand All @@ -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;
Expand Down Expand Up @@ -1110,7 +1119,7 @@ zc0301_vidioc_g_ctrl(struct zc0301_device* cam, void __user * arg)
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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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,
};
Expand All @@ -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);
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit a847423

Please sign in to comment.