* *
* Copyright (C) 2006 by Luca Risolia <luca.risolia@studio.unibo.it> *
* *
- * Informations about the chip internals to enable the I2C protocol have *
- * been taken from the documentation of the ZC030x Video4Linux1 driver *
- * written by Andrew Birkett <andy@nobugs.org> *
+ * 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> *
* *
* 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 *
#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>
#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.00"
-#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 0)
+#define ZC0301_MODULE_VERSION "1:1.03"
+#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 0, 3)
/*****************************************************************************/
"\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);
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 :
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)
(*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;
ZC0301_URB_TIMEOUT);
if (cam->state & DEV_DISCONNECTED)
return -ENODEV;
- else if (!timeout) {
+ else if (cam->stream != STREAM_OFF) {
cam->state |= DEV_MISCONFIGURED;
DBG(1, "URB timeout reached. The camera is misconfigured. To "
"use it, close and open /dev/video%d again.",
if ((r = zc0301_read_reg(cam, 0x0008)) < 0)
err += r;
- err += zc0301_write_reg(cam, 0x0008,
- r | 0x11 | (compression->quality >> 1));
+ err += zc0301_write_reg(cam, 0x0008, r | 0x11 | compression->quality);
return err ? -EIO : 0;
}
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;
if (cam->state & DEV_DISCONNECTED) {
zc0301_release_resources(cam);
+ usb_put_dev(cam->usbdev);
mutex_unlock(&cam->dev_mutex);
kfree(cam);
return 0;
static ssize_t
-zc0301_read(struct file* filp, char __user * buf,
- size_t count, loff_t* f_pos)
+zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
{
struct zc0301_device* cam = video_get_drvdata(video_devdata(filp));
struct zc0301_frame_t* f, * i;
(!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;
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;
static int
-zc0301_vidioc_gs_input(struct zc0301_device* cam, void __user * arg)
+zc0301_vidioc_g_input(struct zc0301_device* cam, void __user * arg)
+{
+ int index = 0;
+
+ if (copy_to_user(arg, &index, sizeof(index)))
+ return -EFAULT;
+
+ return 0;
+}
+
+
+static int
+zc0301_vidioc_s_input(struct zc0301_device* cam, void __user * arg)
{
int index;
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;
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;
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;
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;
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;
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,
};
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);
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;
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);
if (copy_from_user(&jc, arg, sizeof(jc)))
return -EFAULT;
- if (jc.quality < 0 || jc.quality > 3)
+ if (jc.quality != 0)
return -EINVAL;
if (cam->stream == STREAM_ON)
(!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)
return zc0301_vidioc_enuminput(cam, arg);
case VIDIOC_G_INPUT:
+ return zc0301_vidioc_g_input(cam, arg);
+
case VIDIOC_S_INPUT:
- return zc0301_vidioc_gs_input(cam, arg);
+ return zc0301_vidioc_s_input(cam, arg);
case VIDIOC_QUERYCTRL:
return zc0301_vidioc_query_ctrl(cam, arg);
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;
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;
zc0301_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;
zc0301_release_resources(cam);