]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/media/video/vivi.c
Merge branch 'x86-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-omap-h63xx.git] / drivers / media / video / vivi.c
index 65c8af18e767a7e889ac239517b23823e71c9993..e15e48f04be7511e788b5022f413952d10d93bc7 100644 (file)
@@ -128,12 +128,56 @@ struct vivi_fmt {
        int   depth;
 };
 
-static struct vivi_fmt format = {
-       .name     = "4:2:2, packed, YUYV",
-       .fourcc   = V4L2_PIX_FMT_YUYV,
-       .depth    = 16,
+static struct vivi_fmt formats[] = {
+       {
+               .name     = "4:2:2, packed, YUYV",
+               .fourcc   = V4L2_PIX_FMT_YUYV,
+               .depth    = 16,
+       },
+       {
+               .name     = "4:2:2, packed, UYVY",
+               .fourcc   = V4L2_PIX_FMT_UYVY,
+               .depth    = 16,
+       },
+       {
+               .name     = "RGB565 (LE)",
+               .fourcc   = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
+               .depth    = 16,
+       },
+       {
+               .name     = "RGB565 (BE)",
+               .fourcc   = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
+               .depth    = 16,
+       },
+       {
+               .name     = "RGB555 (LE)",
+               .fourcc   = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
+               .depth    = 16,
+       },
+       {
+               .name     = "RGB555 (BE)",
+               .fourcc   = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
+               .depth    = 16,
+       },
 };
 
+static struct vivi_fmt *get_format(struct v4l2_format *f)
+{
+       struct vivi_fmt *fmt;
+       unsigned int k;
+
+       for (k = 0; k < ARRAY_SIZE(formats); k++) {
+               fmt = &formats[k];
+               if (fmt->fourcc == f->fmt.pix.pixelformat)
+                       break;
+       }
+
+       if (k == ARRAY_SIZE(formats))
+               return NULL;
+
+       return &formats[k];
+}
+
 struct sg_to_addr {
        int pos;
        struct scatterlist *sg;
@@ -190,6 +234,7 @@ struct vivi_fh {
        struct videobuf_queue      vb_vidq;
 
        enum v4l2_buf_type         type;
+       unsigned char              bars[8][3];
 };
 
 /* ------------------------------------------------------------------
@@ -234,42 +279,118 @@ static u8 bars[8][3] = {
 #define TSTAMP_MAX_Y TSTAMP_MIN_Y+15
 #define TSTAMP_MIN_X 64
 
-static void gen_line(char *basep, int inipos, int wmax,
-               int hmax, int line, int count, char *timestr)
+static void gen_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos)
 {
-       int  w, i, j, y;
-       int pos = inipos;
-       char *p, *s;
-       u8   chr, r, g, b, color;
+       unsigned char r_y, g_u, b_v;
+       unsigned char *p;
+       int color;
 
-       /* We will just duplicate the second pixel at the packet */
-       wmax /= 2;
+       r_y = fh->bars[colorpos][0]; /* R or precalculated Y */
+       g_u = fh->bars[colorpos][1]; /* G or precalculated U */
+       b_v = fh->bars[colorpos][2]; /* B or precalculated V */
 
-       /* Generate a standard color bar pattern */
-       for (w = 0; w < wmax; w++) {
-               int colorpos = ((w + count) * 8/(wmax + 1)) % 8;
-               r = bars[colorpos][0];
-               g = bars[colorpos][1];
-               b = bars[colorpos][2];
-
-               for (color = 0; color < 4; color++) {
-                       p = basep + pos;
+       for (color = 0; color < 4; color++) {
+               p = buf + color;
 
+               switch (fh->fmt->fourcc) {
+               case V4L2_PIX_FMT_YUYV:
                        switch (color) {
                        case 0:
                        case 2:
-                               *p = TO_Y(r, g, b);     /* Luma */
+                               *p = r_y;
                                break;
                        case 1:
-                               *p = TO_U(r, g, b);     /* Cb */
+                               *p = g_u;
                                break;
                        case 3:
-                               *p = TO_V(r, g, b);     /* Cr */
+                               *p = b_v;
+                               break;
+                       }
+                       break;
+               case V4L2_PIX_FMT_UYVY:
+                       switch (color) {
+                       case 1:
+                       case 3:
+                               *p = r_y;
+                               break;
+                       case 0:
+                               *p = g_u;
+                               break;
+                       case 2:
+                               *p = b_v;
+                               break;
+                       }
+                       break;
+               case V4L2_PIX_FMT_RGB565:
+                       switch (color) {
+                       case 0:
+                       case 2:
+                               *p = (g_u << 5) | b_v;
+                               break;
+                       case 1:
+                       case 3:
+                               *p = (r_y << 3) | (g_u >> 3);
+                               break;
+                       }
+                       break;
+               case V4L2_PIX_FMT_RGB565X:
+                       switch (color) {
+                       case 0:
+                       case 2:
+                               *p = (r_y << 3) | (g_u >> 3);
+                               break;
+                       case 1:
+                       case 3:
+                               *p = (g_u << 5) | b_v;
                                break;
                        }
-                       pos++;
+                       break;
+               case V4L2_PIX_FMT_RGB555:
+                       switch (color) {
+                       case 0:
+                       case 2:
+                               *p = (g_u << 5) | b_v;
+                               break;
+                       case 1:
+                       case 3:
+                               *p = (r_y << 2) | (g_u >> 3);
+                               break;
+                       }
+                       break;
+               case V4L2_PIX_FMT_RGB555X:
+                       switch (color) {
+                       case 0:
+                       case 2:
+                               *p = (r_y << 2) | (g_u >> 3);
+                               break;
+                       case 1:
+                       case 3:
+                               *p = (g_u << 5) | b_v;
+                               break;
+                       }
+                       break;
                }
        }
+}
+
+static void gen_line(struct vivi_fh *fh, char *basep, int inipos, int wmax,
+               int hmax, int line, int count, char *timestr)
+{
+       int  w, i, j;
+       int pos = inipos;
+       char *s;
+       u8 chr;
+
+       /* We will just duplicate the second pixel at the packet */
+       wmax /= 2;
+
+       /* Generate a standard color bar pattern */
+       for (w = 0; w < wmax; w++) {
+               int colorpos = ((w + count) * 8/(wmax + 1)) % 8;
+
+               gen_twopix(fh, basep + pos, colorpos);
+               pos += 4; /* only 16 bpp supported for now */
+       }
 
        /* Checks if it is possible to show timestamp */
        if (TSTAMP_MAX_Y >= hmax)
@@ -283,38 +404,12 @@ static void gen_line(char *basep, int inipos, int wmax,
                for (s = timestr; *s; s++) {
                        chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y];
                        for (i = 0; i < 7; i++) {
-                               if (chr & 1 << (7 - i)) {
-                                       /* Font color*/
-                                       r = 0;
-                                       g = 198;
-                                       b = 0;
-                               } else {
-                                       /* Background color */
-                                       r = bars[BLACK][0];
-                                       g = bars[BLACK][1];
-                                       b = bars[BLACK][2];
-                               }
-
                                pos = inipos + j * 2;
-                               for (color = 0; color < 4; color++) {
-                                       p = basep + pos;
-
-                                       y = TO_Y(r, g, b);
-
-                                       switch (color) {
-                                       case 0:
-                                       case 2:
-                                               *p = TO_Y(r, g, b); /* Luma */
-                                               break;
-                                       case 1:
-                                               *p = TO_U(r, g, b); /* Cb */
-                                               break;
-                                       case 3:
-                                               *p = TO_V(r, g, b); /* Cr */
-                                               break;
-                                       }
-                                       pos++;
-                               }
+                               /* Draw white font on black background */
+                               if (chr & 1 << (7 - i))
+                                       gen_twopix(fh, basep + pos, WHITE);
+                               else
+                                       gen_twopix(fh, basep + pos, BLACK);
                                j++;
                        }
                }
@@ -324,8 +419,9 @@ end:
        return;
 }
 
-static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
+static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf)
 {
+       struct vivi_dev *dev = fh->dev;
        int h , pos = 0;
        int hmax  = buf->vb.height;
        int wmax  = buf->vb.width;
@@ -341,7 +437,7 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
                return;
 
        for (h = 0; h < hmax; h++) {
-               gen_line(tmpbuf, 0, wmax, hmax, h, dev->mv_count,
+               gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count,
                         dev->timestr);
                memcpy(vbuf + pos, tmpbuf, wmax * 2);
                pos += wmax*2;
@@ -410,7 +506,7 @@ static void vivi_thread_tick(struct vivi_fh *fh)
        do_gettimeofday(&buf->vb.ts);
 
        /* Fill buffer */
-       vivi_fillbuff(dev, buf);
+       vivi_fillbuff(fh, buf);
        dprintk(dev, 1, "filled buffer %p\n", buf);
 
        wake_up(&buf->vb.done);
@@ -636,11 +732,15 @@ static int vidioc_querycap(struct file *file, void  *priv,
 static int vidioc_enum_fmt_vid_cap(struct file *file, void  *priv,
                                        struct v4l2_fmtdesc *f)
 {
-       if (f->index > 0)
+       struct vivi_fmt *fmt;
+
+       if (f->index >= ARRAY_SIZE(formats))
                return -EINVAL;
 
-       strlcpy(f->description, format.name, sizeof(f->description));
-       f->pixelformat = format.fourcc;
+       fmt = &formats[f->index];
+
+       strlcpy(f->description, fmt->name, sizeof(f->description));
+       f->pixelformat = fmt->fourcc;
        return 0;
 }
 
@@ -670,13 +770,12 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
        enum v4l2_field field;
        unsigned int maxw, maxh;
 
-       if (format.fourcc != f->fmt.pix.pixelformat) {
-               dprintk(dev, 1, "Fourcc format (0x%08x) invalid. "
-                       "Driver accepts only 0x%08x\n",
-                       f->fmt.pix.pixelformat, format.fourcc);
+       fmt = get_format(f);
+       if (!fmt) {
+               dprintk(dev, 1, "Fourcc format (0x%08x) invalid.\n",
+                       f->fmt.pix.pixelformat);
                return -EINVAL;
        }
-       fmt = &format;
 
        field = f->fmt.pix.field;
 
@@ -714,6 +813,8 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
 {
        struct vivi_fh  *fh = priv;
        struct videobuf_queue *q = &fh->vb_vidq;
+       unsigned char r, g, b;
+       int k, is_yuv;
 
        int ret = vidioc_try_fmt_vid_cap(file, fh, f);
        if (ret < 0)
@@ -727,12 +828,49 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
                goto out;
        }
 
-       fh->fmt           = &format;
+       fh->fmt           = get_format(f);
        fh->width         = f->fmt.pix.width;
        fh->height        = f->fmt.pix.height;
        fh->vb_vidq.field = f->fmt.pix.field;
        fh->type          = f->type;
 
+       /* precalculate color bar values to speed up rendering */
+       for (k = 0; k < 8; k++) {
+               r = bars[k][0];
+               g = bars[k][1];
+               b = bars[k][2];
+               is_yuv = 0;
+
+               switch (fh->fmt->fourcc) {
+               case V4L2_PIX_FMT_YUYV:
+               case V4L2_PIX_FMT_UYVY:
+                       is_yuv = 1;
+                       break;
+               case V4L2_PIX_FMT_RGB565:
+               case V4L2_PIX_FMT_RGB565X:
+                       r >>= 3;
+                       g >>= 2;
+                       b >>= 3;
+                       break;
+               case V4L2_PIX_FMT_RGB555:
+               case V4L2_PIX_FMT_RGB555X:
+                       r >>= 3;
+                       g >>= 3;
+                       b >>= 3;
+                       break;
+               }
+
+               if (is_yuv) {
+                       fh->bars[k][0] = TO_Y(r, g, b); /* Luma */
+                       fh->bars[k][1] = TO_U(r, g, b); /* Cb */
+                       fh->bars[k][2] = TO_V(r, g, b); /* Cr */
+               } else {
+                       fh->bars[k][0] = r;
+                       fh->bars[k][1] = g;
+                       fh->bars[k][2] = b;
+               }
+       }
+
        ret = 0;
 out:
        mutex_unlock(&q->vb_lock);
@@ -886,8 +1024,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
        File operations for the device
    ------------------------------------------------------------------*/
 
-#define line_buf_size(norm) (norm_maxw(norm)*(format.depth+7)/8)
-
 static int vivi_open(struct inode *inode, struct file *file)
 {
        int minor = iminor(inode);
@@ -936,7 +1072,7 @@ unlock:
        fh->dev      = dev;
 
        fh->type     = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-       fh->fmt      = &format;
+       fh->fmt      = &formats[0];
        fh->width    = 640;
        fh->height   = 480;
 
@@ -1027,11 +1163,11 @@ static int vivi_release(void)
 
                if (-1 != dev->vfd->minor) {
                        printk(KERN_INFO "%s: unregistering /dev/video%d\n",
-                               VIVI_MODULE_NAME, dev->vfd->minor);
+                               VIVI_MODULE_NAME, dev->vfd->num);
                        video_unregister_device(dev->vfd);
                } else {
                        printk(KERN_INFO "%s: releasing /dev/video%d\n",
-                               VIVI_MODULE_NAME, dev->vfd->minor);
+                               VIVI_MODULE_NAME, dev->vfd->num);
                        video_device_release(dev->vfd);
                }
 
@@ -1171,7 +1307,7 @@ static int __init vivi_init(void)
 
                dev->vfd = vfd;
                printk(KERN_INFO "%s: V4L2 device registered as /dev/video%d\n",
-                       VIVI_MODULE_NAME, vfd->minor);
+                       VIVI_MODULE_NAME, vfd->num);
        }
 
        if (ret < 0) {