Merge remote-tracking branch 'remotes/aosp/android-3.0' into develop-3.0
[firefly-linux-kernel-4.4.55.git] / drivers / media / video / s2255drv.c
index 8ec7c9a45a172ec2a62020de156d175e74891f36..5b9dce85645c351220330db9a14b0f39cf628763 100644 (file)
@@ -49,7 +49,6 @@
 #include <linux/videodev2.h>
 #include <linux/version.h>
 #include <linux/mm.h>
-#include <linux/smp_lock.h>
 #include <media/videobuf-vmalloc.h>
 #include <media/v4l2-common.h>
 #include <media/v4l2-device.h>
@@ -58,7 +57,7 @@
 #include <linux/usb.h>
 
 #define S2255_MAJOR_VERSION    1
-#define S2255_MINOR_VERSION    20
+#define S2255_MINOR_VERSION    21
 #define S2255_RELEASE          0
 #define S2255_VERSION          KERNEL_VERSION(S2255_MAJOR_VERSION, \
                                               S2255_MINOR_VERSION, \
@@ -269,7 +268,7 @@ struct s2255_dev {
        struct v4l2_device      v4l2_dev;
        atomic_t                num_channels;
        int                     frames;
-       struct mutex            lock;
+       struct mutex            lock;   /* channels[].vdev.lock */
        struct mutex            open_lock;
        struct usb_device       *udev;
        struct usb_interface    *interface;
@@ -313,9 +312,9 @@ struct s2255_fh {
 };
 
 /* current cypress EEPROM firmware version */
-#define S2255_CUR_USB_FWVER    ((3 << 8) | 6)
+#define S2255_CUR_USB_FWVER    ((3 << 8) | 11)
 /* current DSP FW version */
-#define S2255_CUR_DSP_FWVER     8
+#define S2255_CUR_DSP_FWVER     10102
 /* Need DSP version 5+ for video status feature */
 #define S2255_MIN_DSP_STATUS      5
 #define S2255_MIN_DSP_COLORFILTER 8
@@ -395,12 +394,17 @@ static unsigned int vid_limit = 16;       /* Video memory limit, in Mb */
 /* start video number */
 static int video_nr = -1;      /* /dev/videoN, -1 for autodetect */
 
+/* Enable jpeg capture. */
+static int jpeg_enable = 1;
+
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "Debug level(0-100) default 0");
 module_param(vid_limit, int, 0644);
 MODULE_PARM_DESC(vid_limit, "video memory limit(Mb)");
 module_param(video_nr, int, 0644);
 MODULE_PARM_DESC(video_nr, "start video minor(-1 default autodetect)");
+module_param(jpeg_enable, int, 0644);
+MODULE_PARM_DESC(jpeg_enable, "Jpeg enable(1-on 0-off) default 1");
 
 /* USB device table */
 #define USB_SENSORAY_VID       0x1943
@@ -414,6 +418,7 @@ MODULE_DEVICE_TABLE(usb, s2255_table);
 #define BUFFER_TIMEOUT msecs_to_jiffies(400)
 
 /* image formats.  */
+/* JPEG formats must be defined last to support jpeg_enable parameter */
 static const struct s2255_fmt formats[] = {
        {
                .name = "4:2:2, planar, YUV422P",
@@ -429,14 +434,18 @@ static const struct s2255_fmt formats[] = {
                .name = "4:2:2, packed, UYVY",
                .fourcc = V4L2_PIX_FMT_UYVY,
                .depth = 16
+       }, {
+               .name = "8bpp GREY",
+               .fourcc = V4L2_PIX_FMT_GREY,
+               .depth = 8
        }, {
                .name = "JPG",
                .fourcc = V4L2_PIX_FMT_JPEG,
                .depth = 24
        }, {
-               .name = "8bpp GREY",
-               .fourcc = V4L2_PIX_FMT_GREY,
-               .depth = 8
+               .name = "MJPG",
+               .fourcc = V4L2_PIX_FMT_MJPEG,
+               .depth = 24
        }
 };
 
@@ -493,9 +502,11 @@ static void planar422p_to_yuv_packed(const unsigned char *in,
 
 static void s2255_reset_dsppower(struct s2255_dev *dev)
 {
-       s2255_vendor_req(dev, 0x40, 0x0b0b, 0x0b0b, NULL, 0, 1);
+       s2255_vendor_req(dev, 0x40, 0x0b0b, 0x0b01, NULL, 0, 1);
        msleep(10);
        s2255_vendor_req(dev, 0x50, 0x0000, 0x0000, NULL, 0, 1);
+       msleep(600);
+       s2255_vendor_req(dev, 0x10, 0x0000, 0x0000, NULL, 0, 1);
        return;
 }
 
@@ -600,7 +611,7 @@ static int s2255_got_frame(struct s2255_channel *channel, int jpgsize)
        dprintk(2, "%s: [buf/i] [%p/%d]\n", __func__, buf, buf->vb.i);
 unlock:
        spin_unlock_irqrestore(&dev->slock, flags);
-       return 0;
+       return rc;
 }
 
 static const struct s2255_fmt *format_by_fourcc(int fourcc)
@@ -609,6 +620,9 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc)
        for (i = 0; i < ARRAY_SIZE(formats); i++) {
                if (-1 == formats[i].fourcc)
                        continue;
+       if (!jpeg_enable && ((formats[i].fourcc == V4L2_PIX_FMT_JPEG) ||
+                            (formats[i].fourcc == V4L2_PIX_FMT_MJPEG)))
+           continue;
                if (formats[i].fourcc == fourcc)
                        return formats + i;
        }
@@ -652,6 +666,7 @@ static void s2255_fillbuff(struct s2255_channel *channel,
                        memcpy(vbuf, tmpbuf, buf->vb.width * buf->vb.height);
                        break;
                case V4L2_PIX_FMT_JPEG:
+               case V4L2_PIX_FMT_MJPEG:
                        buf->vb.size = jpgsize;
                        memcpy(vbuf, tmpbuf, buf->vb.size);
                        break;
@@ -781,20 +796,14 @@ static struct videobuf_queue_ops s2255_video_qops = {
 
 static int res_get(struct s2255_fh *fh)
 {
-       struct s2255_dev *dev = fh->dev;
-       /* is it free? */
        struct s2255_channel *channel = fh->channel;
-       mutex_lock(&dev->lock);
-       if (channel->resources) {
-               /* no, someone else uses it */
-               mutex_unlock(&dev->lock);
-               return 0;
-       }
+       /* is it free? */
+       if (channel->resources)
+               return 0; /* no, someone else uses it */
        /* it's free, grab it */
        channel->resources = 1;
        fh->resources = 1;
        dprintk(1, "s2255: res: get\n");
-       mutex_unlock(&dev->lock);
        return 1;
 }
 
@@ -812,11 +821,8 @@ static int res_check(struct s2255_fh *fh)
 static void res_free(struct s2255_fh *fh)
 {
        struct s2255_channel *channel = fh->channel;
-       struct s2255_dev *dev = fh->dev;
-       mutex_lock(&dev->lock);
        channel->resources = 0;
        fh->resources = 0;
-       mutex_unlock(&dev->lock);
        dprintk(1, "res: put\n");
 }
 
@@ -864,7 +870,9 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
 
        if (index >= ARRAY_SIZE(formats))
                return -EINVAL;
-
+    if (!jpeg_enable && ((formats[index].fourcc == V4L2_PIX_FMT_JPEG) ||
+                        (formats[index].fourcc == V4L2_PIX_FMT_MJPEG)))
+       return -EINVAL;
        dprintk(4, "name %s\n", formats[index].name);
        strlcpy(f->description, formats[index].name, sizeof(f->description));
        f->pixelformat = formats[index].fourcc;
@@ -1045,6 +1053,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                mode.color |= COLOR_Y8;
                break;
        case V4L2_PIX_FMT_JPEG:
+       case V4L2_PIX_FMT_MJPEG:
                mode.color &= ~MASK_COLOR;
                mode.color |= COLOR_JPG;
                mode.color |= (channel->jc.quality << 8);
@@ -1107,15 +1116,6 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
        return rc;
 }
 
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidioc_cgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-{
-       struct s2255_fh *fh = priv;
-
-       return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
-}
-#endif
-
 /* write to the configuration pipe, synchronously */
 static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf,
                              int size)
@@ -1219,7 +1219,6 @@ static int s2255_set_mode(struct s2255_channel *channel,
        __le32 *buffer;
        unsigned long chn_rev;
        struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
-       mutex_lock(&dev->lock);
        chn_rev = G_chnmap[channel->idx];
        dprintk(3, "%s channel: %d\n", __func__, channel->idx);
        /* if JPEG, set the quality */
@@ -1236,7 +1235,6 @@ static int s2255_set_mode(struct s2255_channel *channel,
        buffer = kzalloc(512, GFP_KERNEL);
        if (buffer == NULL) {
                dev_err(&dev->udev->dev, "out of mem\n");
-               mutex_unlock(&dev->lock);
                return -ENOMEM;
        }
        /* set the mode */
@@ -1261,7 +1259,6 @@ static int s2255_set_mode(struct s2255_channel *channel,
        }
        /* clear the restart flag */
        channel->mode.restart = 0;
-       mutex_unlock(&dev->lock);
        dprintk(1, "%s chn %d, result: %d\n", __func__, channel->idx, res);
        return res;
 }
@@ -1272,13 +1269,11 @@ static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus)
        __le32 *buffer;
        u32 chn_rev;
        struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
-       mutex_lock(&dev->lock);
        chn_rev = G_chnmap[channel->idx];
        dprintk(4, "%s chan %d\n", __func__, channel->idx);
        buffer = kzalloc(512, GFP_KERNEL);
        if (buffer == NULL) {
                dev_err(&dev->udev->dev, "out of mem\n");
-               mutex_unlock(&dev->lock);
                return -ENOMEM;
        }
        /* form the get vid status command */
@@ -1298,7 +1293,6 @@ static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus)
        }
        *pstatus = channel->vidstatus;
        dprintk(4, "%s, vid status %d\n", __func__, *pstatus);
-       mutex_unlock(&dev->lock);
        return res;
 }
 
@@ -1817,7 +1811,8 @@ static int s2255_open(struct file *file)
                                    NULL, &dev->slock,
                                    fh->type,
                                    V4L2_FIELD_INTERLACED,
-                                   sizeof(struct s2255_buffer), fh);
+                                   sizeof(struct s2255_buffer),
+                                   fh, vdev->lock);
        return 0;
 }
 
@@ -1900,7 +1895,7 @@ static const struct v4l2_file_operations s2255_fops_v4l = {
        .open = s2255_open,
        .release = s2255_release,
        .poll = s2255_poll,
-       .ioctl = video_ioctl2,  /* V4L2 ioctl handler */
+       .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
        .mmap = s2255_mmap_v4l,
 };
 
@@ -1924,9 +1919,6 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
        .vidioc_s_ctrl = vidioc_s_ctrl,
        .vidioc_streamon = vidioc_streamon,
        .vidioc_streamoff = vidioc_streamoff,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-       .vidiocgmbuf = vidioc_cgmbuf,
-#endif
        .vidioc_s_jpegcomp = vidioc_s_jpegcomp,
        .vidioc_g_jpegcomp = vidioc_g_jpegcomp,
        .vidioc_s_parm = vidioc_s_parm,
@@ -1970,6 +1962,7 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
                channel->vidq.dev = dev;
                /* register 4 video devices */
                channel->vdev = template;
+               channel->vdev.lock = &dev->lock;
                channel->vdev.v4l2_dev = &dev->v4l2_dev;
                video_set_drvdata(&channel->vdev, channel);
                if (video_nr == -1)
@@ -2406,7 +2399,7 @@ static void read_pipe_completion(struct urb *purb)
                          read_pipe_completion, pipe_info);
 
        if (pipe_info->state != 0) {
-               if (usb_submit_urb(pipe_info->stream_urb, GFP_KERNEL)) {
+               if (usb_submit_urb(pipe_info->stream_urb, GFP_ATOMIC)) {
                        dev_err(&dev->udev->dev, "error submitting urb\n");
                }
        } else {
@@ -2676,7 +2669,9 @@ static void s2255_disconnect(struct usb_interface *interface)
        struct s2255_dev *dev = to_s2255_dev(usb_get_intfdata(interface));
        int i;
        int channels = atomic_read(&dev->num_channels);
+       mutex_lock(&dev->lock);
        v4l2_device_disconnect(&dev->v4l2_dev);
+       mutex_unlock(&dev->lock);
        /*see comments in the uvc_driver.c usb disconnect function */
        atomic_inc(&dev->num_channels);
        /* unregister each video device. */