V4L/DVB (9927): em28xx: use a more standard way to specify video formats
authorMauro Carvalho Chehab <mchehab@redhat.com>
Sat, 20 Dec 2008 12:06:37 +0000 (09:06 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 30 Dec 2008 11:39:20 +0000 (09:39 -0200)
This patch uses the same code for enumberating video formats that are
present on cx88, bttv and saa7134 drivers.

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/video/em28xx/em28xx-core.c
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/em28xx/em28xx.h

index f515f87..c647dcb 100644 (file)
@@ -621,10 +621,19 @@ int em28xx_capture_start(struct em28xx *dev, int start)
        return rc;
 }
 
-int em28xx_outfmt_set_yuv422(struct em28xx *dev)
+int em28xx_set_outfmt(struct em28xx *dev)
 {
-       em28xx_write_reg(dev, EM28XX_R27_OUTFMT, 0x34);
-       em28xx_write_reg(dev, EM28XX_R10_VINMODE, 0x10);
+       int ret;
+
+       ret = em28xx_write_reg_bits(dev, EM28XX_R27_OUTFMT,
+                                   dev->format->reg | 0x20, 0x3f);
+       if (ret < 0)
+               return ret;
+
+       ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, 0x10);
+       if (ret < 0)
+               return ret;
+
        return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, 0x11);
 }
 
@@ -686,7 +695,7 @@ int em28xx_resolution_set(struct em28xx *dev)
        width = norm_maxw(dev);
        height = norm_maxh(dev) >> 1;
 
-       em28xx_outfmt_set_yuv422(dev);
+       em28xx_set_outfmt(dev);
        em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
        em28xx_capture_area_set(dev, 0, 0, width >> 2, height >> 2);
        return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
index 1b56e78..dbae8bc 100644 (file)
@@ -96,6 +96,16 @@ MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
 /* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
 static unsigned long em28xx_devused;
 
+/* supported video standards */
+static struct em28xx_fmt format[] = {
+       {
+               .name     = "16bpp YUY2, 4:2:2, packed",
+               .fourcc   = V4L2_PIX_FMT_YUYV,
+               .depth    = 16,
+               .reg      = 0x14,
+       },
+};
+
 /* supported controls */
 /* Common to all boards */
 static struct v4l2_queryctrl em28xx_qctrl[] = {
@@ -386,7 +396,8 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
        struct em28xx        *dev = fh->dev;
        struct v4l2_frequency f;
 
-       *size = 16 * fh->dev->width * fh->dev->height >> 3;
+       *size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) >> 3;
+
        if (0 == *count)
                *count = EM28XX_DEF_BUF;
 
@@ -439,9 +450,7 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
        struct em28xx        *dev = fh->dev;
        int                  rc = 0, urb_init = 0;
 
-       /* FIXME: It assumes depth = 16 */
-       /* The only currently supported format is 16 bits/pixel */
-       buf->vb.size = 16 * dev->width * dev->height >> 3;
+       buf->vb.size = (fh->dev->width * fh->dev->height * dev->format->depth + 7) >> 3;
 
        if (0 != buf->vb.baddr  &&  buf->vb.bsize < buf->vb.size)
                return -EINVAL;
@@ -536,7 +545,7 @@ static int em28xx_config(struct em28xx *dev)
        dev->mute = 1;          /* maybe not the right place... */
        dev->volume = 0x1f;
 
-       em28xx_outfmt_set_yuv422(dev);
+       em28xx_set_outfmt(dev);
        em28xx_colorlevels_set_default(dev);
        em28xx_compression_disable(dev);
 
@@ -704,8 +713,8 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
 
        f->fmt.pix.width = dev->width;
        f->fmt.pix.height = dev->height;
-       f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-       f->fmt.pix.bytesperline = dev->width * 2;
+       f->fmt.pix.pixelformat = dev->format->fourcc;
+       f->fmt.pix.bytesperline = (dev->width * dev->format->depth + 7) >> 3;
        f->fmt.pix.sizeimage = f->fmt.pix.bytesperline  * dev->height;
        f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
 
@@ -717,6 +726,17 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
        return 0;
 }
 
+static struct em28xx_fmt *format_by_fourcc(unsigned int fourcc)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(format); i++)
+               if (format[i].fourcc == fourcc)
+                       return &format[i];
+
+       return NULL;
+}
+
 static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
                        struct v4l2_format *f)
 {
@@ -727,6 +747,14 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        unsigned int          maxw   = norm_maxw(dev);
        unsigned int          maxh   = norm_maxh(dev);
        unsigned int          hscale, vscale;
+       struct em28xx_fmt     *fmt;
+
+       fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+       if (!fmt) {
+               em28xx_videodbg("Fourcc format (%08x) invalid.\n",
+                               f->fmt.pix.pixelformat);
+               return -EINVAL;
+       }
 
        /* width must even because of the YUYV format
           height must be even because of interlacing */
@@ -765,9 +793,9 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
 
        f->fmt.pix.width = width;
        f->fmt.pix.height = height;
-       f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
-       f->fmt.pix.bytesperline = width * 2;
-       f->fmt.pix.sizeimage = width * 2 * height;
+       f->fmt.pix.pixelformat = fmt->fourcc;
+       f->fmt.pix.bytesperline = (dev->width * fmt->depth + 7) >> 3;
+       f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * height;
        f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
        f->fmt.pix.field = V4L2_FIELD_INTERLACED;
 
@@ -780,6 +808,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        struct em28xx_fh      *fh  = priv;
        struct em28xx         *dev = fh->dev;
        int                   rc;
+       struct em28xx_fmt     *fmt;
 
        rc = check_dev(dev);
        if (rc < 0)
@@ -789,6 +818,10 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 
        vidioc_try_fmt_vid_cap(file, priv, f);
 
+       fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+       if (!fmt)
+               return -EINVAL;
+
        if (videobuf_queue_is_busy(&fh->vb_vidq)) {
                em28xx_errdev("%s queue busy\n", __func__);
                rc = -EBUSY;
@@ -804,6 +837,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        /* set new image size */
        dev->width = f->fmt.pix.width;
        dev->height = f->fmt.pix.height;
+       dev->format = fmt;
        get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
 
        em28xx_set_alternate(dev);
@@ -1332,15 +1366,13 @@ static int vidioc_querycap(struct file *file, void  *priv,
 }
 
 static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
-                                       struct v4l2_fmtdesc *fmtd)
+                                       struct v4l2_fmtdesc *f)
 {
-       if (fmtd->index != 0)
+       if (unlikely(f->index >= ARRAY_SIZE(format)))
                return -EINVAL;
 
-       fmtd->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       strcpy(fmtd->description, "Packed YUY2");
-       fmtd->pixelformat = V4L2_PIX_FMT_YUYV;
-       memset(fmtd->reserved, 0, sizeof(fmtd->reserved));
+       strlcpy(f->description, format[f->index].name, sizeof(f->description));
+       f->pixelformat = format[f->index].fourcc;
 
        return 0;
 }
@@ -2075,6 +2107,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
        dev->em28xx_write_regs_req = em28xx_write_regs_req;
        dev->em28xx_read_reg_req = em28xx_read_reg_req;
        dev->board.is_em2800 = em28xx_boards[dev->model].is_em2800;
+       dev->format = &format[0];
 
        em28xx_pre_card_setup(dev);
 
@@ -2482,3 +2515,4 @@ static void __exit em28xx_module_exit(void)
 
 module_init(em28xx_module_init);
 module_exit(em28xx_module_exit);
+
index 54802d2..80d1d55 100644 (file)
@@ -209,9 +209,12 @@ struct em28xx_usb_isoc_ctl {
 
 };
 
+/* Struct to enumberate video formats */
 struct em28xx_fmt {
        char  *name;
        u32   fourcc;          /* v4l2 format id */
+       int   depth;
+       int   reg;
 };
 
 /* buffer for one video frame */
@@ -430,6 +433,8 @@ struct em28xx {
        unsigned int has_audio_class:1;
        unsigned int has_alsa_audio:1;
 
+       struct em28xx_fmt *format;
+
        struct em28xx_IR *ir;
 
        /* Some older em28xx chips needs a waiting time after writing */
@@ -564,7 +569,7 @@ int em28xx_audio_setup(struct em28xx *dev);
 
 int em28xx_colorlevels_set_default(struct em28xx *dev);
 int em28xx_capture_start(struct em28xx *dev, int start);
-int em28xx_outfmt_set_yuv422(struct em28xx *dev);
+int em28xx_set_outfmt(struct em28xx *dev);
 int em28xx_resolution_set(struct em28xx *dev);
 int em28xx_set_alternate(struct em28xx *dev);
 int em28xx_init_isoc(struct em28xx *dev, int max_packets,