/*
* QuickCam Driver For Video4Linux.
*
* Video4Linux conversion work by Alan Cox.
* Parport compatibility by Phil Blundell.
* Busy loop avoidance by Mark Cooke.
*
* Module parameters:
*
* maxpoll=<1 - 5000>
*
* When polling the QuickCam for a response, busy-wait for a
* maximum of this many loops. The default of 250 gives little
* impact on interactive response.
*
* NOTE: If this parameter is set too high, the processor
* will busy wait until this loop times out, and then
* slowly poll for a further 5 seconds before failing
* the transaction. You have been warned.
*
* yieldlines=<1 - 250>
*
* When acquiring a frame from the camera, the data gathering
* loop will yield back to the scheduler after completing
* this many lines. The default of 4 provides a trade-off
* between increased frame acquisition time and impact on
* interactive response.
*/
/* qcam-lib.c -- Library for programming with the Connectix QuickCam.
* See the included documentation for usage instructions and details
* of the protocol involved. */
/* Version 0.5, August 4, 1996 */
/* Version 0.7, August 27, 1996 */
/* Version 0.9, November 17, 1996 */
/******************************************************************
Copyright (C) 1996 by Scott Laird
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
******************************************************************/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/parport.h>
#include <linux/sched.h>
#include <linux/videodev.h>
#include <media/v4l2-common.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
#include "bw-qcam.h"
static unsigned int maxpoll=250; /* Maximum busy-loop count for qcam I/O */
static unsigned int yieldlines=4; /* Yield after this many during capture */
static int video_nr = -1;
module_param(maxpoll, int, 0);
module_param(yieldlines, int, 0);
module_param(video_nr, int, 0);
static inline int read_lpstatus(struct qcam_device *q)
{
return parport_read_status(q->pport);
}
static inline int read_lpdata(struct qcam_device *q)
{
return parport_read_data(q->pport);
}
static inline void write_lpdata(struct qcam_device *q, int d)
{
parport_write_data(q->pport, d);
}
static inline void write_lpcontrol(struct qcam_device *q, int d)
{
if (d & 0x20) {
/* Set bidirectional mode to reverse (data in) */
parport_data_reverse(q->pport);
} else {
/* Set bidirectional mode to forward (data out) */
parport_data_forward(q->pport);
}
/* Now issue the regular port command, but strip out the
* direction flag */
d &= ~0x20;
parport_write_control(q->pport, d);
}
static int qc_waithand(struct qcam_device *q, int val);
static int qc_command(struct qcam_device *q, int command);
static int qc_readparam(struct qcam_device *q);
static int qc_setscanmode(struct qcam_device *q);
static int qc_readbytes(struct qcam_device *q, char buffer[]);
static struct video_device qcam_template;
static int qc_calibrate(struct qcam_device *q)
{
/*
* Bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96
* The white balance is an individiual value for each
* quickcam.
*/
int value;
int count = 0;
qc_command(q, 27); /* AutoAdjustOffset */
qc_command(q, 0); /* Dummy Parameter, ignored by the camera */
/* GetOffset (33) will read 255 until autocalibration */
/* is finished. After that, a value of 1-254 will be */
/* returned. */
do {
qc_command(q, 33);
value = qc_readparam(q);
mdelay(1);
schedule();
count++;
} while (value == 0xff && count<2048);
q->whitebal = value;
return value;
}
/* Initialize the QuickCam driver control structure. This is where
* defaults are set for people who don't have a config file.*/
static struct qcam_device *qcam_init(struct parport *port)
{
struct qcam_device *q;
q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
if(q==NULL)
return NULL;
q->pport = port;
q->pdev = parport_register_device(port, "bw-qcam", NULL, NULL,
NULL, 0, NULL);
if (q->pdev == NULL)
{
printk(KERN_ERR "bw-qcam: couldn't register for %s.\n",
port->name);
kfree(q);
return NULL;
}
memcpy(&q->vdev