summaryrefslogtreecommitdiff
path: root/drivers/media/video/vivi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/vivi.c')
-rw-r--r--drivers/media/video/vivi.c285
1 files changed, 213 insertions, 72 deletions
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 8ba8daafd7ea..7d7e51def461 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -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 = r_y;
+ break;
+ case 1:
+ *p = g_u;
+ break;
+ case 3:
+ *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 = TO_Y(r, g, b); /* Luma */
+ *p = (r_y << 3) | (g_u >> 3);
break;
case 1:
- *p = TO_U(r, g, b); /* Cb */
+ case 3:
+ *p = (g_u << 5) | b_v;
+ break;
+ }
+ 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 = TO_V(r, g, b); /* Cr */
+ *p = (g_u << 5) | b_v;
break;
}
- pos++;
+ 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);
@@ -898,9 +1034,11 @@ static int vivi_open(struct inode *inode, struct file *file)
printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor);
+ lock_kernel();
list_for_each_entry(dev, &vivi_devlist, vivi_devlist)
if (dev->vfd->minor == minor)
goto found;
+ unlock_kernel();
return -ENODEV;
found:
@@ -925,14 +1063,16 @@ found:
}
unlock:
mutex_unlock(&dev->mutex);
- if (retval)
+ if (retval) {
+ unlock_kernel();
return retval;
+ }
file->private_data = fh;
fh->dev = dev;
fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fh->fmt = &format;
+ fh->fmt = &formats[0];
fh->width = 640;
fh->height = 480;
@@ -955,6 +1095,7 @@ unlock:
sizeof(struct vivi_buffer), fh);
vivi_start_thread(fh);
+ unlock_kernel();
return 0;
}