#include <linux/parport.h>
#include <linux/sched.h>
#include <linux/videodev.h>
-#include <asm/semaphore.h>
+#include <media/v4l2-common.h>
+#include <linux/mutex.h>
#include <asm/uaccess.h>
#include "bw-qcam.h"
static unsigned int yieldlines=4; /* Yield after this many during capture */
static int video_nr = -1;
-MODULE_PARM(maxpoll,"i");
-MODULE_PARM(yieldlines,"i");
-MODULE_PARM(video_nr,"i");
+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_lpcontrol(struct qcam_device *q)
-{
- return parport_read_control(q->pport);
-}
-
static inline int read_lpdata(struct qcam_device *q)
{
return parport_read_data(q->pport);
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)
+ if (q->pdev == NULL)
{
printk(KERN_ERR "bw-qcam: couldn't register for %s.\n",
port->name);
kfree(q);
return NULL;
}
-
+
memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
-
- init_MUTEX(&q->lock);
+
+ mutex_init(&q->lock);
q->port_mode = (QC_ANY | QC_NOTSET);
q->width = 320;
while (!((status = read_lpstatus(q)) & 8))
{
/* 1000 is enough spins on the I/O for all normal
- cases, at that point we start to poll slowly
+ cases, at that point we start to poll slowly
until the camera wakes up. However, we are
busy blocked until the camera responds, so
setting it lower is much better for interactive
response. */
-
+
if(runs++>maxpoll)
{
- current->state=TASK_INTERRUPTIBLE;
- schedule_timeout(HZ/200);
+ msleep_interruptible(5);
}
if(runs>(maxpoll+1000)) /* 5 seconds */
return -1;
while (((status = read_lpstatus(q)) & 8))
{
/* 1000 is enough spins on the I/O for all normal
- cases, at that point we start to poll slowly
+ cases, at that point we start to poll slowly
until the camera wakes up. However, we are
busy blocked until the camera responds, so
setting it lower is much better for interactive
response. */
-
+
if(runs++>maxpoll)
{
- current->state=TASK_INTERRUPTIBLE;
- schedule_timeout(HZ/200);
+ msleep_interruptible(5);
}
if(runs++>(maxpoll+1000)) /* 5 seconds */
return -1;
{
unsigned int status;
int runs=0;
-
- do
+
+ do
{
status = read_lpdata(q);
/* 1000 is enough spins on the I/O for all normal
- cases, at that point we start to poll slowly
+ cases, at that point we start to poll slowly
until the camera wakes up. However, we are
busy blocked until the camera responds, so
setting it lower is much better for interactive
response. */
-
+
if(runs++>maxpoll)
{
- current->state=TASK_INTERRUPTIBLE;
- schedule_timeout(HZ/200);
+ msleep_interruptible(5);
}
if(runs++>(maxpoll+1000)) /* 5 seconds */
return 0;
lastreg = reg = read_lpstatus(q) & 0xf0;
- for (i = 0; i < 500; i++)
+ for (i = 0; i < 500; i++)
{
reg = read_lpstatus(q) & 0xf0;
if (reg != lastreg)
static void qc_reset(struct qcam_device *q)
{
- switch (q->port_mode & QC_FORCE_MASK)
+ switch (q->port_mode & QC_FORCE_MASK)
{
case QC_FORCE_UNIDIR:
q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
case QC_ANY:
write_lpcontrol(q, 0x20);
write_lpdata(q, 0x75);
-
+
if (read_lpdata(q) != 0x75) {
q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
} else {
static int qc_setscanmode(struct qcam_device *q)
{
int old_mode = q->mode;
-
- switch (q->transfer_scale)
+
+ switch (q->transfer_scale)
{
case 1:
q->mode = 0;
break;
}
- switch (q->bpp)
+ switch (q->bpp)
{
case 4:
break;
break;
}
- switch (q->port_mode & QC_MODE_MASK)
+ switch (q->port_mode & QC_MODE_MASK)
{
case QC_BIDIR:
q->mode += 1;
case QC_UNIDIR:
break;
}
-
+
if (q->mode != old_mode)
q->status |= QC_PARAM_CHANGE;
-
+
return 0;
}
/* Reset the QuickCam and program for brightness, contrast,
* white-balance, and resolution. */
-void qc_set(struct qcam_device *q)
+static void qc_set(struct qcam_device *q)
{
int val;
int val2;
/* Set the brightness. Yes, this is repetitive, but it works.
* Shorter versions seem to fail subtly. Feel free to try :-). */
/* I think the problem was in qc_command, not here -- bls */
-
+
qc_command(q, 0xb);
qc_command(q, q->brightness);
unsigned int hi2, lo2;
static int state = 0;
- if (buffer == NULL)
+ if (buffer == NULL)
{
state = 0;
return 0;
}
-
- switch (q->port_mode & QC_MODE_MASK)
+
+ switch (q->port_mode & QC_MODE_MASK)
{
case QC_BIDIR: /* Bi-directional Port */
write_lpcontrol(q, 0x26);
write_lpcontrol(q, 0x2e);
lo2 = (qc_waithand2(q, 0) >> 1);
hi2 = (read_lpstatus(q) >> 3) & 0x1f;
- switch (q->bpp)
+ switch (q->bpp)
{
case 4:
buffer[0] = lo & 0xf;
write_lpcontrol(q, 0xe);
hi = (qc_waithand(q, 0) & 0xf0) >> 4;
- switch (q->bpp)
+ switch (q->bpp)
{
case 4:
buffer[0] = lo;
ret = 2;
break;
case 6:
- switch (state)
+ switch (state)
{
case 0:
buffer[0] = (lo << 2) | ((hi & 0xc) >> 2);
* n=2^(bit depth)-1. Ask me for more details if you don't understand
* this. */
-long qc_capture(struct qcam_device * q, char *buf, unsigned long len)
+static long qc_capture(struct qcam_device * q, char __user *buf, unsigned long len)
{
int i, j, k, yield;
int bytes;
int shift=8-q->bpp;
char invert;
- if (q->mode == -1)
+ if (q->mode == -1)
return -ENXIO;
qc_command(q, 0x7);
qc_command(q, q->mode);
- if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR)
+ if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR)
{
write_lpcontrol(q, 0x2e); /* turn port around */
write_lpcontrol(q, 0x26);
write_lpcontrol(q, 0x2e);
(void) qc_waithand(q, 0);
}
-
+
/* strange -- should be 15:63 below, but 4bpp is odd */
invert = (q->bpp == 4) ? 16 : 63;
q->transfer_scale;
transperline = (transperline + divisor - 1) / divisor;
- for (i = 0, yield = yieldlines; i < linestotrans; i++)
+ for (i = 0, yield = yieldlines; i < linestotrans; i++)
{
- for (pixels_read = j = 0; j < transperline; j++)
+ for (pixels_read = j = 0; j < transperline; j++)
{
bytes = qc_readbytes(q, buffer);
- for (k = 0; k < bytes && (pixels_read + k) < pixels_per_line; k++)
+ for (k = 0; k < bytes && (pixels_read + k) < pixels_per_line; k++)
{
int o;
- if (buffer[k] == 0 && invert == 16)
+ if (buffer[k] == 0 && invert == 16)
{
/* 4bpp is odd (again) -- inverter is 16, not 15, but output
must be 0-15 -- bls */
}
pixels_read += bytes;
}
- (void) qc_readbytes(q, 0); /* reset state machine */
-
+ (void) qc_readbytes(q, NULL); /* reset state machine */
+
/* Grabbing an entire frame from the quickcam is a lengthy
process. We don't (usually) want to busy-block the
processor for the entire frame. yieldlines is a module
time will be 240 / 200 = 1.2 seconds. The compile-time
default is to yield every 4 lines. */
if (i >= yield) {
- current->state=TASK_INTERRUPTIBLE;
- schedule_timeout(HZ/200);
+ msleep_interruptible(5);
yield = i + yieldlines;
}
}
- if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR)
+ if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR)
{
write_lpcontrol(q, 2);
write_lpcontrol(q, 6);
{
struct video_device *dev = video_devdata(file);
struct qcam_device *qcam=(struct qcam_device *)dev;
-
+
switch(cmd)
{
case VIDIOCGCAP:
{
struct video_picture *p = arg;
if(p->palette!=VIDEO_PALETTE_GREY)
- return -EINVAL;
+ return -EINVAL;
if(p->depth!=4 && p->depth!=6)
return -EINVAL;
-
+
/*
* Now load the camera.
*/
qcam->whitebal = p->whiteness>>8;
qcam->bpp = p->depth;
- down(&qcam->lock);
+ mutex_lock(&qcam->lock);
qc_setscanmode(qcam);
- up(&qcam->lock);
+ mutex_unlock(&qcam->lock);
qcam->status |= QC_PARAM_CHANGE;
return 0;
return -EINVAL;
if(vw->width<80||vw->width>320)
return -EINVAL;
-
+
qcam->width = 320;
qcam->height = 240;
qcam->transfer_scale = 4;
-
+
if(vw->width>=160 && vw->height>=120)
{
qcam->transfer_scale = 2;
qcam->height = 240;
qcam->transfer_scale = 1;
}
- down(&qcam->lock);
+ mutex_lock(&qcam->lock);
qc_setscanmode(qcam);
- up(&qcam->lock);
-
+ mutex_unlock(&qcam->lock);
+
/* We must update the camera before we grab. We could
just have changed the grab size */
qcam->status |= QC_PARAM_CHANGE;
-
+
/* Ok we figured out what to use from our wide choice */
return 0;
}
return video_usercopy(inode, file, cmd, arg, qcam_do_ioctl);
}
-static ssize_t qcam_read(struct file *file, char *buf,
+static ssize_t qcam_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct video_device *v = video_devdata(file);
struct qcam_device *qcam=(struct qcam_device *)v;
int len;
parport_claim_or_block(qcam->pdev);
-
- down(&qcam->lock);
-
+
+ mutex_lock(&qcam->lock);
+
qc_reset(qcam);
/* Update the camera parameters if we need to */
qc_set(qcam);
len=qc_capture(qcam, buf,count);
-
- up(&qcam->lock);
-
+
+ mutex_unlock(&qcam->lock);
+
parport_release(qcam->pdev);
return len;
}
-
+
static struct file_operations qcam_fops = {
.owner = THIS_MODULE,
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = qcam_ioctl,
+ .compat_ioctl = v4l_compat_ioctl32,
.read = qcam_read,
.llseek = no_llseek,
};
static struct qcam_device *qcams[MAX_CAMS];
static unsigned int num_cams = 0;
-int init_bwqcam(struct parport *port)
+static int init_bwqcam(struct parport *port)
{
struct qcam_device *qcam;
qcam=qcam_init(port);
if(qcam==NULL)
return -ENODEV;
-
+
parport_claim_or_block(qcam->pdev);
qc_reset(qcam);
-
+
if(qc_detect(qcam)==0)
{
parport_release(qcam->pdev);
qc_calibrate(qcam);
parport_release(qcam->pdev);
-
+
printk(KERN_INFO "Connectix Quickcam on %s\n", qcam->pport->name);
-
+
if(video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr)==-1)
{
parport_unregister_device(qcam->pdev);
return 0;
}
-void close_bwqcam(struct qcam_device *qcam)
+static void close_bwqcam(struct qcam_device *qcam)
{
video_unregister_device(&qcam->vdev);
parport_unregister_device(qcam->pdev);
* -- March 14, 1999 Billy Donahue <billy@escape.com> */
#ifdef MODULE
static char *parport[MAX_CAMS] = { NULL, };
-MODULE_PARM(parport, "1-" __MODULE_STRING(MAX_CAMS) "s");
+module_param_array(parport, charp, NULL, 0);
#endif
static int accept_bwqcam(struct parport *port)
printk("Connectix Quickcam max-poll was above 5000. Using 5000.\n");
maxpoll = 5000;
}
-
+
if (yieldlines < 1) {
printk("Connectix Quickcam yieldlines was less than 1. Using 1.\n");
yieldlines = 1;