PCI: complain about devices that seem to be broken
[safe/jmp/linux-2.6] / drivers / media / video / bw-qcam.c
index 6bad93e..9e39bc5 100644 (file)
@@ -73,7 +73,9 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include <linux/parport.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
-#include <asm/semaphore.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <linux/mutex.h>
 #include <asm/uaccess.h>
 
 #include "bw-qcam.h"
@@ -81,11 +83,16 @@ OTHER DEALINGS IN THE SOFTWARE.
 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;
+static unsigned int force_init;                /* Whether to probe aggressively */
 
 module_param(maxpoll, int, 0);
 module_param(yieldlines, int, 0);
 module_param(video_nr, int, 0);
 
+/* Set force_init=1 to avoid detection by polling status register and
+ * immediately attempt to initialize qcam */
+module_param(force_init, int, 0);
+
 static inline int read_lpstatus(struct qcam_device *q)
 {
        return parport_read_status(q->pport);
@@ -103,6 +110,17 @@ static inline void write_lpdata(struct qcam_device *q, int 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);
 }
 
@@ -150,7 +168,7 @@ static int qc_calibrate(struct qcam_device *q)
 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;
@@ -158,17 +176,17 @@ static struct qcam_device *qcam_init(struct parport *port)
        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;
@@ -236,12 +254,12 @@ static int qc_waithand(struct qcam_device *q, int val)
                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)
                        {
                                msleep_interruptible(5);
@@ -255,12 +273,12 @@ static int qc_waithand(struct qcam_device *q, int val)
                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)
                        {
                                msleep_interruptible(5);
@@ -282,17 +300,17 @@ static unsigned int qc_waithand2(struct qcam_device *q, int val)
 {
        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)
                {
                        msleep_interruptible(5);
@@ -319,9 +337,12 @@ static int qc_detect(struct qcam_device *q)
        int count = 0;
        int i;
 
+       if (force_init)
+               return 1;
+
        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)
@@ -342,11 +363,14 @@ static int qc_detect(struct qcam_device *q)
 
        /* Be (even more) liberal in what you accept...  */
 
-/*     if (count > 30 && count < 200) */
-       if (count > 20 && count < 300)
+       if (count > 20 && count < 400) {
                return 1;       /* found */
-       else
+       } else {
+               printk(KERN_ERR "No Quickcam found on port %s\n",
+                       q->pport->name);
+               printk(KERN_DEBUG "Quickcam detection counter: %u\n", count);
                return 0;       /* not found */
+       }
 }
 
 
@@ -357,7 +381,7 @@ static int qc_detect(struct qcam_device *q)
 
 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;
@@ -370,7 +394,7 @@ static void qc_reset(struct qcam_device *q)
                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 {
@@ -398,8 +422,8 @@ static void qc_reset(struct qcam_device *q)
 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;
@@ -412,7 +436,7 @@ static int qc_setscanmode(struct qcam_device *q)
                        break;
        }
 
-       switch (q->bpp) 
+       switch (q->bpp)
        {
                case 4:
                        break;
@@ -421,7 +445,7 @@ static int qc_setscanmode(struct qcam_device *q)
                        break;
        }
 
-       switch (q->port_mode & QC_MODE_MASK) 
+       switch (q->port_mode & QC_MODE_MASK)
        {
                case QC_BIDIR:
                        q->mode += 1;
@@ -430,10 +454,10 @@ static int qc_setscanmode(struct qcam_device *q)
                case QC_UNIDIR:
                        break;
        }
-       
+
        if (q->mode != old_mode)
                q->status |= QC_PARAM_CHANGE;
-       
+
        return 0;
 }
 
@@ -451,7 +475,7 @@ static void qc_set(struct qcam_device *q)
        /* 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);
 
@@ -471,7 +495,7 @@ static void qc_set(struct qcam_device *q)
                val2 = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) *
                    q->transfer_scale;
        }
-       val = (val + val2 - 1) / val2;
+       val = DIV_ROUND_UP(val, val2);
        qc_command(q, 0x13);
        qc_command(q, val);
 
@@ -500,15 +524,15 @@ static inline int qc_readbytes(struct qcam_device *q, char buffer[])
        int ret=1;
        unsigned int hi, lo;
        unsigned int hi2, lo2;
-       static int state = 0;
+       static int state;
 
-       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);
@@ -517,7 +541,7 @@ static inline int qc_readbytes(struct qcam_device *q, char buffer[])
                        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;
@@ -544,7 +568,7 @@ static inline int qc_readbytes(struct qcam_device *q, char buffer[])
                        write_lpcontrol(q, 0xe);
                        hi = (qc_waithand(q, 0) & 0xf0) >> 4;
 
-                       switch (q->bpp) 
+                       switch (q->bpp)
                        {
                                case 4:
                                        buffer[0] = lo;
@@ -552,7 +576,7 @@ static inline int qc_readbytes(struct qcam_device *q, char buffer[])
                                        ret = 2;
                                        break;
                                case 6:
-                                       switch (state) 
+                                       switch (state)
                                        {
                                                case 0:
                                                        buffer[0] = (lo << 2) | ((hi & 0xc) >> 2);
@@ -604,13 +628,13 @@ static long qc_capture(struct qcam_device * q, char __user *buf, unsigned long l
        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);
@@ -618,7 +642,7 @@ static long qc_capture(struct qcam_device * q, char __user *buf, unsigned long l
                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;
 
@@ -627,17 +651,17 @@ static long qc_capture(struct qcam_device * q, char __user *buf, unsigned long l
        transperline = q->width * q->bpp;
        divisor = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) *
            q->transfer_scale;
-       transperline = (transperline + divisor - 1) / divisor;
+       transperline = DIV_ROUND_UP(transperline, 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 */
@@ -653,7 +677,7 @@ static long qc_capture(struct qcam_device * q, char __user *buf, unsigned long l
                        pixels_read += bytes;
                }
                (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
@@ -666,7 +690,7 @@ static long qc_capture(struct qcam_device * q, char __user *buf, unsigned long l
                }
        }
 
-       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);
@@ -682,12 +706,11 @@ static long qc_capture(struct qcam_device * q, char __user *buf, unsigned long l
  *     Video4linux interfacing
  */
 
-static int qcam_do_ioctl(struct inode *inode, struct file *file,
-                        unsigned int cmd, void *arg)
+static long qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
 {
        struct video_device *dev = video_devdata(file);
        struct qcam_device *qcam=(struct qcam_device *)dev;
-       
+
        switch(cmd)
        {
                case VIDIOCGCAP:
@@ -759,10 +782,10 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
                {
                        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.
                         */
@@ -772,9 +795,9 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
                        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;
@@ -790,11 +813,11 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
                                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;
@@ -805,14 +828,14 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
                                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;
                }
@@ -840,10 +863,10 @@ static int qcam_do_ioctl(struct inode *inode, struct file *file,
        return 0;
 }
 
-static int qcam_ioctl(struct inode *inode, struct file *file,
+static long qcam_ioctl(struct file *file,
                     unsigned int cmd, unsigned long arg)
 {
-       return video_usercopy(inode, file, cmd, arg, qcam_do_ioctl);
+       return video_usercopy(file, cmd, arg, qcam_do_ioctl);
 }
 
 static ssize_t qcam_read(struct file *file, char __user *buf,
@@ -853,9 +876,9 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
        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 */
@@ -863,34 +886,47 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
                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 = {
+
+static int qcam_exclusive_open(struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct qcam_device *qcam = (struct qcam_device *)dev;
+
+       return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0;
+}
+
+static int qcam_exclusive_release(struct file *file)
+{
+       struct video_device *dev = video_devdata(file);
+       struct qcam_device *qcam = (struct qcam_device *)dev;
+
+       clear_bit(0, &qcam->in_use);
+       return 0;
+}
+
+static const struct v4l2_file_operations qcam_fops = {
        .owner          = THIS_MODULE,
-       .open           = video_exclusive_open,
-       .release        = video_exclusive_release,
+       .open           = qcam_exclusive_open,
+       .release        = qcam_exclusive_release,
        .ioctl          = qcam_ioctl,
-       .compat_ioctl   = v4l_compat_ioctl32,
        .read           = qcam_read,
-       .llseek         = no_llseek,
 };
 static struct video_device qcam_template=
 {
-       .owner          = THIS_MODULE,
        .name           = "Connectix Quickcam",
-       .type           = VID_TYPE_CAPTURE,
-       .hardware       = VID_HARDWARE_QCAM_BW,
        .fops           = &qcam_fops,
+       .release        = video_device_release_empty,
 };
 
 #define MAX_CAMS 4
 static struct qcam_device *qcams[MAX_CAMS];
-static unsigned int num_cams = 0;
+static unsigned int num_cams;
 
 static int init_bwqcam(struct parport *port)
 {
@@ -905,11 +941,11 @@ static int init_bwqcam(struct parport *port)
        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);
@@ -920,11 +956,10 @@ static int init_bwqcam(struct parport *port)
        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)
-       {
+
+       if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
                parport_unregister_device(qcam->pdev);
                kfree(qcam);
                return -ENODEV;
@@ -957,7 +992,7 @@ static int accept_bwqcam(struct parport *port)
 
        if (parport[0] && strncmp(parport[0], "auto", 4) != 0) {
                /* user gave parport parameters */
-               for(n=0; parport[n] && n<MAX_CAMS; n++){
+               for (n = 0; n < MAX_CAMS && parport[n]; n++) {
                        char *ep;
                        unsigned long r;
                        r = simple_strtoul(parport[n], &ep, 0);
@@ -1013,7 +1048,7 @@ static int __init init_bw_qcams(void)
                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;