V4L/DVB (9297): cx18: Fix memory leak on card initialization failure
[safe/jmp/linux-2.6] / drivers / media / video / bw-qcam.c
index cf61c59..ace4ff9 100644 (file)
@@ -73,6 +73,8 @@ OTHER DEALINGS IN THE SOFTWARE.
 #include <linux/parport.h>
 #include <linux/sched.h>
 #include <linux/videodev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
 #include <linux/mutex.h>
 #include <asm/uaccess.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);
 }
 
@@ -319,6 +337,9 @@ 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++)
@@ -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 */
+       }
 }
 
 
@@ -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,7 +524,7 @@ 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)
        {
@@ -627,7 +651,7 @@ 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++)
        {
@@ -759,7 +783,7 @@ 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;
 
@@ -870,27 +894,44 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
        return len;
 }
 
-static struct file_operations qcam_fops = {
+static int qcam_exclusive_open(struct inode *inode, 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 inode *inode, 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 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,
+#ifdef CONFIG_COMPAT
        .compat_ioctl   = v4l_compat_ioctl32,
+#endif
        .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)
 {
@@ -923,8 +964,7 @@ static int init_bwqcam(struct parport *port)
 
        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;