Commit 730947bc authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

V4L/DVB: vivi: clean up and a major overhaul

- Clean up the code
- Use the kernel's built-in vga8x16 font instead of our own.
- Drop exclusive open: now multiple users can open the device as per the V4L2 spec.
- Move the format description to the vivi device instead of keeping it in the file
  handle. Again as per the spec.
- Streamline and simplify the drawing code. It is now easy to add text on top of
  the colorbar pattern.
- Upgrade the max resolution to 1920x1200.
Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 474675ad
...@@ -543,6 +543,7 @@ config VIDEO_DAVINCI_VPIF ...@@ -543,6 +543,7 @@ config VIDEO_DAVINCI_VPIF
config VIDEO_VIVI config VIDEO_VIVI
tristate "Virtual Video Driver" tristate "Virtual Video Driver"
depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
select FONT_8x16
select VIDEOBUF_VMALLOC select VIDEOBUF_VMALLOC
default n default n
---help--- ---help---
......
static unsigned char rom8x16_bits[] = {
/* Character 0 (0x30):
ht=16, width=8
+--------+
| |
| |
| ***** |
|** ** |
|** ** |
|** *** |
|** **** |
|**** ** |
|*** ** |
|** ** |
|** ** |
| ***** |
| |
| |
| |
| |
+--------+ */
0x00,
0x00,
0x7c,
0xc6,
0xc6,
0xce,
0xde,
0xf6,
0xe6,
0xc6,
0xc6,
0x7c,
0x00,
0x00,
0x00,
0x00,
/* Character 1 (0x31):
ht=16, width=8
+--------+
| |
| |
| ** |
| **** |
| ** |
| ** |
| ** |
| ** |
| ** |
| ** |
| ** |
| ****** |
| |
| |
| |
| |
+--------+ */
0x00,
0x00,
0x18,
0x78,
0x18,
0x18,
0x18,
0x18,
0x18,
0x18,
0x18,
0x7e,
0x00,
0x00,
0x00,
0x00,
/* Character 2 (0x32):
ht=16, width=8
+--------+
| |
| |
| ***** |
|** ** |
|** ** |
| ** |
| ** |
| ** |
| ** |
| ** |
|** ** |
|******* |
| |
| |
| |
| |
+--------+ */
0x00,
0x00,
0x7c,
0xc6,
0xc6,
0x06,
0x0c,
0x18,
0x30,
0x60,
0xc6,
0xfe,
0x00,
0x00,
0x00,
0x00,
/* Character 3 (0x33):
ht=16, width=8
+--------+
| |
| |
| ***** |
|** ** |
| ** |
| ** |
| **** |
| ** |
| ** |
| ** |
|** ** |
| ***** |
| |
| |
| |
| |
+--------+ */
0x00,
0x00,
0x7c,
0xc6,
0x06,
0x06,
0x3c,
0x06,
0x06,
0x06,
0xc6,
0x7c,
0x00,
0x00,
0x00,
0x00,
/* Character 4 (0x34):
ht=16, width=8
+--------+
| |
| |
| ** |
| *** |
| **** |
| ** ** |
|** ** |
|** ** |
|******* |
| ** |
| ** |
| **** |
| |
| |
| |
| |
+--------+ */
0x00,
0x00,
0x0c,
0x1c,
0x3c,
0x6c,
0xcc,
0xcc,
0xfe,
0x0c,
0x0c,
0x1e,
0x00,
0x00,
0x00,
0x00,
/* Character 5 (0x35):
ht=16, width=8
+--------+
| |
| |
|******* |
|** |
|** |
|** |
|****** |
| ** |
| ** |
| ** |
|** ** |
| ***** |
| |
| |
| |
| |
+--------+ */
0x00,
0x00,
0xfe,
0xc0,
0xc0,
0xc0,
0xfc,
0x06,
0x06,
0x06,
0xc6,
0x7c,
0x00,
0x00,
0x00,
0x00,
/* Character 6 (0x36):
ht=16, width=8
+--------+
| |
| |
| ***** |
|** ** |
|** |
|** |
|****** |
|** ** |
|** ** |
|** ** |
|** ** |
| ***** |
| |
| |
| |
| |
+--------+ */
0x00,
0x00,
0x7c,
0xc6,
0xc0,
0xc0,
0xfc,
0xc6,
0xc6,
0xc6,
0xc6,
0x7c,
0x00,
0x00,
0x00,
0x00,
/* Character 7 (0x37):
ht=16, width=8
+--------+
| |
| |
|******* |
|** ** |
| ** |
| ** |
| ** |
| ** |
| ** |
| ** |
| ** |
| ** |
| |
| |
| |
| |
+--------+ */
0x00,
0x00,
0xfe,
0xc6,
0x06,
0x0c,
0x18,
0x30,
0x30,
0x30,
0x30,
0x30,
0x00,
0x00,
0x00,
0x00,
/* Character 8 (0x38):
ht=16, width=8
+--------+
| |
| |
| ***** |
|** ** |
|** ** |
|** ** |
| ***** |
|** ** |
|** ** |
|** ** |
|** ** |
| ***** |
| |
| |
| |
| |
+--------+ */
0x00,
0x00,
0x7c,
0xc6,
0xc6,
0xc6,
0x7c,
0xc6,
0xc6,
0xc6,
0xc6,
0x7c,
0x00,
0x00,
0x00,
0x00,
/* Character 9 (0x39):
ht=16, width=8
+--------+
| |
| |
| ***** |
|** ** |
|** ** |
|** ** |
|** ** |
| ****** |
| ** |
| ** |
|** ** |
| ***** |
| |
| |
| |
| |
+--------+ */
0x00,
0x00,
0x7c,
0xc6,
0xc6,
0xc6,
0xc6,
0x7e,
0x06,
0x06,
0xc6,
0x7c,
0x00,
0x00,
0x00,
0x00,
/* Character : (0x3a):
ht=16, width=8
+--------+
| |
| |
| |
| |
| |
| ** |
| ** |
| |
| |
| ** |
| ** |
| |
| |
| |
| |
| |
+--------+ */
0x00,
0x00,
0x00,
0x00,
0x00,
0x0c,
0x0c,
0x00,
0x00,
0x0c,
0x0c,
0x00,
0x00,
0x00,
0x00,
0x00,
};
...@@ -13,29 +13,22 @@ ...@@ -13,29 +13,22 @@
* License, or (at your option) any later version * License, or (at your option) any later version
*/ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/delay.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/fs.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/pci.h> #include <linux/font.h>
#include <linux/random.h>
#include <linux/version.h> #include <linux/version.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/videodev2.h> #include <linux/videodev2.h>
#include <linux/dma-mapping.h>
#include <linux/interrupt.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/highmem.h> #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
#include <linux/freezer.h> #include <linux/freezer.h>
#endif
#include <media/videobuf-vmalloc.h> #include <media/videobuf-vmalloc.h>
#include <media/v4l2-device.h> #include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h> #include <media/v4l2-ioctl.h>
#include "font.h" #include <media/v4l2-common.h>
#define VIVI_MODULE_NAME "vivi" #define VIVI_MODULE_NAME "vivi"
...@@ -44,8 +37,11 @@ ...@@ -44,8 +37,11 @@
#define WAKE_DENOMINATOR 1001 #define WAKE_DENOMINATOR 1001
#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */ #define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
#define MAX_WIDTH 1920
#define MAX_HEIGHT 1200
#define VIVI_MAJOR_VERSION 0 #define VIVI_MAJOR_VERSION 0
#define VIVI_MINOR_VERSION 6 #define VIVI_MINOR_VERSION 7
#define VIVI_RELEASE 0 #define VIVI_RELEASE 0
#define VIVI_VERSION \ #define VIVI_VERSION \
KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE) KERNEL_VERSION(VIVI_MAJOR_VERSION, VIVI_MINOR_VERSION, VIVI_RELEASE)
...@@ -70,56 +66,8 @@ static unsigned int vid_limit = 16; ...@@ -70,56 +66,8 @@ static unsigned int vid_limit = 16;
module_param(vid_limit, uint, 0644); module_param(vid_limit, uint, 0644);
MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes"); MODULE_PARM_DESC(vid_limit, "capture memory limit in megabytes");
/* Global font descriptor */
/* supported controls */ static const u8 *font8x16;
static struct v4l2_queryctrl vivi_qctrl[] = {
{
.id = V4L2_CID_AUDIO_VOLUME,
.name = "Volume",
.minimum = 0,
.maximum = 65535,
.step = 65535/100,
.default_value = 65535,
.flags = V4L2_CTRL_FLAG_SLIDER,
.type = V4L2_CTRL_TYPE_INTEGER,
}, {
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Brightness",
.minimum = 0,
.maximum = 255,
.step = 1,
.default_value = 127,
.flags = V4L2_CTRL_FLAG_SLIDER,
}, {
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Contrast",
.minimum = 0,
.maximum = 255,
.step = 0x1,
.default_value = 0x10,
.flags = V4L2_CTRL_FLAG_SLIDER,
}, {
.id = V4L2_CID_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Saturation",
.minimum = 0,
.maximum = 255,
.step = 0x1,
.default_value = 127,
.flags = V4L2_CTRL_FLAG_SLIDER,
}, {
.id = V4L2_CID_HUE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Hue",
.minimum = -128,
.maximum = 127,
.step = 0x1,
.default_value = 0,
.flags = V4L2_CTRL_FLAG_SLIDER,
}
};
#define dprintk(dev, level, fmt, arg...) \ #define dprintk(dev, level, fmt, arg...) \
v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg) v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ## arg)
...@@ -214,41 +162,38 @@ struct vivi_dev { ...@@ -214,41 +162,38 @@ struct vivi_dev {
struct list_head vivi_devlist; struct list_head vivi_devlist;
struct v4l2_device v4l2_dev; struct v4l2_device v4l2_dev;
/* controls */
int brightness;
int contrast;
int saturation;
int hue;
int volume;
spinlock_t slock; spinlock_t slock;
struct mutex mutex; struct mutex mutex;
int users;
/* various device info */ /* various device info */
struct video_device *vfd; struct video_device *vfd;
struct vivi_dmaqueue vidq; struct vivi_dmaqueue vidq;
/* Several counters */ /* Several counters */
int h, m, s, ms; unsigned ms;
unsigned long jiffies; unsigned long jiffies;
char timestr[13];
int mv_count; /* Controls bars movement */ int mv_count; /* Controls bars movement */
/* Input Number */ /* Input Number */
int input; int input;
/* Control 'registers' */
int qctl_regs[ARRAY_SIZE(vivi_qctrl)];
};
struct vivi_fh {
struct vivi_dev *dev;
/* video capture */ /* video capture */
struct vivi_fmt *fmt; struct vivi_fmt *fmt;
unsigned int width, height; unsigned int width, height;
struct videobuf_queue vb_vidq; struct videobuf_queue vb_vidq;
enum v4l2_buf_type type; unsigned long generating;
unsigned char bars[8][3]; u8 bars[9][3];
int input; /* Input Number on bars */ u8 line[MAX_WIDTH * 4];
}; };
/* ------------------------------------------------------------------ /* ------------------------------------------------------------------
...@@ -259,19 +204,20 @@ struct vivi_fh { ...@@ -259,19 +204,20 @@ struct vivi_fh {
enum colors { enum colors {
WHITE, WHITE,
AMBAR, AMBER,
CYAN, CYAN,
GREEN, GREEN,
MAGENTA, MAGENTA,
RED, RED,
BLUE, BLUE,
BLACK, BLACK,
TEXT_BLACK,
}; };
/* R G B */ /* R G B */
#define COLOR_WHITE {204, 204, 204} #define COLOR_WHITE {204, 204, 204}
#define COLOR_AMBAR {208, 208, 0} #define COLOR_AMBER {208, 208, 0}
#define COLOR_CIAN { 0, 206, 206} #define COLOR_CYAN { 0, 206, 206}
#define COLOR_GREEN { 0, 239, 0} #define COLOR_GREEN { 0, 239, 0}
#define COLOR_MAGENTA {239, 0, 239} #define COLOR_MAGENTA {239, 0, 239}
#define COLOR_RED {205, 0, 0} #define COLOR_RED {205, 0, 0}
...@@ -279,56 +225,24 @@ enum colors { ...@@ -279,56 +225,24 @@ enum colors {
#define COLOR_BLACK { 0, 0, 0} #define COLOR_BLACK { 0, 0, 0}
struct bar_std { struct bar_std {
u8 bar[8][3]; u8 bar[9][3];
}; };
/* Maximum number of bars are 10 - otherwise, the input print code /* Maximum number of bars are 10 - otherwise, the input print code
should be modified */ should be modified */
static struct bar_std bars[] = { static struct bar_std bars[] = {
{ /* Standard ITU-R color bar sequence */ { /* Standard ITU-R color bar sequence */
{ { COLOR_WHITE, COLOR_AMBER, COLOR_CYAN, COLOR_GREEN,
COLOR_WHITE, COLOR_MAGENTA, COLOR_RED, COLOR_BLUE, COLOR_BLACK, COLOR_BLACK }
COLOR_AMBAR,
COLOR_CIAN,
COLOR_GREEN,
COLOR_MAGENTA,
COLOR_RED,
COLOR_BLUE,
COLOR_BLACK,
}
}, { }, {
{ { COLOR_WHITE, COLOR_AMBER, COLOR_BLACK, COLOR_WHITE,
COLOR_WHITE, COLOR_AMBER, COLOR_BLACK, COLOR_WHITE, COLOR_AMBER, COLOR_BLACK }
COLOR_AMBAR,
COLOR_BLACK,
COLOR_WHITE,
COLOR_AMBAR,
COLOR_BLACK,
COLOR_WHITE,
COLOR_AMBAR,
}
}, { }, {
{ { COLOR_WHITE, COLOR_CYAN, COLOR_BLACK, COLOR_WHITE,
COLOR_WHITE, COLOR_CYAN, COLOR_BLACK, COLOR_WHITE, COLOR_CYAN, COLOR_BLACK }
COLOR_CIAN,
COLOR_BLACK,
COLOR_WHITE,
COLOR_CIAN,
COLOR_BLACK,
COLOR_WHITE,
COLOR_CIAN,
}
}, { }, {
{ { COLOR_WHITE, COLOR_GREEN, COLOR_BLACK, COLOR_WHITE,
COLOR_WHITE, COLOR_GREEN, COLOR_BLACK, COLOR_WHITE, COLOR_GREEN, COLOR_BLACK }
COLOR_GREEN,
COLOR_BLACK,
COLOR_WHITE,
COLOR_GREEN,
COLOR_BLACK,
COLOR_WHITE,
COLOR_GREEN,
}
}, },
}; };
...@@ -344,21 +258,18 @@ static struct bar_std bars[] = { ...@@ -344,21 +258,18 @@ static struct bar_std bars[] = {
(((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128) (((-9714 * r - 19070 * g + 28784 * b + 32768) >> 16) + 128)
/* precalculate color bar values to speed up rendering */ /* precalculate color bar values to speed up rendering */
static void precalculate_bars(struct vivi_fh *fh) static void precalculate_bars(struct vivi_dev *dev)
{ {
struct vivi_dev *dev = fh->dev; u8 r, g, b;
unsigned char r, g, b;
int k, is_yuv; int k, is_yuv;
fh->input = dev->input; for (k = 0; k < 9; k++) {
r = bars[dev->input].bar[k][0];
for (k = 0; k < 8; k++) { g = bars[dev->input].bar[k][1];
r = bars[fh->input].bar[k][0]; b = bars[dev->input].bar[k][2];
g = bars[fh->input].bar[k][1];
b = bars[fh->input].bar[k][2];
is_yuv = 0; is_yuv = 0;
switch (fh->fmt->fourcc) { switch (dev->fmt->fourcc) {
case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_UYVY:
is_yuv = 1; is_yuv = 1;
...@@ -378,16 +289,15 @@ static void precalculate_bars(struct vivi_fh *fh) ...@@ -378,16 +289,15 @@ static void precalculate_bars(struct vivi_fh *fh)
} }
if (is_yuv) { if (is_yuv) {
fh->bars[k][0] = TO_Y(r, g, b); /* Luma */ dev->bars[k][0] = TO_Y(r, g, b); /* Luma */
fh->bars[k][1] = TO_U(r, g, b); /* Cb */ dev->bars[k][1] = TO_U(r, g, b); /* Cb */
fh->bars[k][2] = TO_V(r, g, b); /* Cr */ dev->bars[k][2] = TO_V(r, g, b); /* Cr */
} else { } else {
fh->bars[k][0] = r; dev->bars[k][0] = r;
fh->bars[k][1] = g; dev->bars[k][1] = g;
fh->bars[k][2] = b; dev->bars[k][2] = b;
} }
} }
} }
#define TSTAMP_MIN_Y 24 #define TSTAMP_MIN_Y 24
...@@ -395,20 +305,20 @@ static void precalculate_bars(struct vivi_fh *fh) ...@@ -395,20 +305,20 @@ static void precalculate_bars(struct vivi_fh *fh)
#define TSTAMP_INPUT_X 10 #define TSTAMP_INPUT_X 10
#define TSTAMP_MIN_X (54 + TSTAMP_INPUT_X) #define TSTAMP_MIN_X (54 + TSTAMP_INPUT_X)
static void gen_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos) static void gen_twopix(struct vivi_dev *dev, u8 *buf, int colorpos)
{ {
unsigned char r_y, g_u, b_v; u8 r_y, g_u, b_v;
unsigned char *p;
int color; int color;
u8 *p;
r_y = fh->bars[colorpos][0]; /* R or precalculated Y */ r_y = dev->bars[colorpos][0]; /* R or precalculated Y */
g_u = fh->bars[colorpos][1]; /* G or precalculated U */ g_u = dev->bars[colorpos][1]; /* G or precalculated U */
b_v = fh->bars[colorpos][2]; /* B or precalculated V */ b_v = dev->bars[colorpos][2]; /* B or precalculated V */
for (color = 0; color < 4; color++) { for (color = 0; color < 4; color++) {
p = buf + color; p = buf + color;
switch (fh->fmt->fourcc) { switch (dev->fmt->fourcc) {
case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YUYV:
switch (color) { switch (color) {
case 0: case 0:
...@@ -489,123 +399,88 @@ static void gen_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos) ...@@ -489,123 +399,88 @@ static void gen_twopix(struct vivi_fh *fh, unsigned char *buf, int colorpos)
} }
} }
static void gen_line(struct vivi_fh *fh, char *basep, int inipos, int wmax, static void precalculate_line(struct vivi_dev *dev)
int hmax, int line, int count, char *timestr)
{ {
int w, i, j; int w;
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 < dev->width * 2; w += 2) {
for (w = 0; w < wmax; w++) { int colorpos = (w / (dev->width / 8) % 8);
int colorpos = ((w + count) * 8/(wmax + 1)) % 8;
gen_twopix(fh, basep + pos, colorpos); gen_twopix(dev, dev->line + w * 2, colorpos);
pos += 4; /* only 16 bpp supported for now */
} }
}
/* Prints input entry number */ static void gen_text(struct vivi_dev *dev, char *basep,
int y, int x, char *text)
/* Checks if it is possible to input number */ {
if (TSTAMP_MAX_Y >= hmax) int line;
goto end;
if (TSTAMP_INPUT_X + strlen(timestr) >= wmax) /* Checks if it is possible to show string */
goto end; if (y + 16 >= dev->height || x + strlen(text) * 8 >= dev->width)
return;
if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) { /* Print stream time */
chr = rom8x16_bits[fh->input * 16 + line - TSTAMP_MIN_Y]; for (line = y; line < y + 16; line++) {
pos = TSTAMP_INPUT_X; int j = 0;
for (i = 0; i < 7; i++) { char *pos = basep + line * dev->width * 2 + x * 2;
/* Draw white font on black background */ char *s;
if (chr & 1 << (7 - i))
gen_twopix(fh, basep + pos, WHITE);
else
gen_twopix(fh, basep + pos, BLACK);
pos += 2;
}
}
/* Checks if it is possible to show timestamp */ for (s = text; *s; s++) {
if (TSTAMP_MIN_X + strlen(timestr) >= wmax) u8 chr = font8x16[*s * 16 + line - y];
goto end; int i;
/* Print stream time */ for (i = 0; i < 7; i++, j++) {
if (line >= TSTAMP_MIN_Y && line <= TSTAMP_MAX_Y) {
j = TSTAMP_MIN_X;
for (s = timestr; *s; s++) {
chr = rom8x16_bits[(*s-0x30)*16+line-TSTAMP_MIN_Y];
for (i = 0; i < 7; i++) {
pos = inipos + j * 2;
/* Draw white font on black background */ /* Draw white font on black background */
if (chr & 1 << (7 - i)) if (chr & (1 << (7 - i)))
gen_twopix(fh, basep + pos, WHITE); gen_twopix(dev, pos + j * 2, WHITE);
else else
gen_twopix(fh, basep + pos, BLACK); gen_twopix(dev, pos + j * 2, TEXT_BLACK);
j++;
} }
} }
} }
end:
return;
} }
static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf) static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
{ {
struct vivi_dev *dev = fh->dev;
int h , pos = 0;
int hmax = buf->vb.height; int hmax = buf->vb.height;
int wmax = buf->vb.width; int wmax = buf->vb.width;
struct timeval ts; struct timeval ts;
char *tmpbuf;
void *vbuf = videobuf_to_vmalloc(&buf->vb); void *vbuf = videobuf_to_vmalloc(&buf->vb);
unsigned ms;
char str[100];
int h, line = 1;
if (!vbuf) if (!vbuf)
return; return;
tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC); for (h = 0; h < hmax; h++)
if (!tmpbuf) memcpy(vbuf + h * wmax * 2, dev->line + (dev->mv_count % wmax) * 2, wmax * 2);
return;
for (h = 0; h < hmax; h++) {
gen_line(fh, tmpbuf, 0, wmax, hmax, h, dev->mv_count,
dev->timestr);
memcpy(vbuf + pos, tmpbuf, wmax * 2);
pos += wmax*2;
}
dev->mv_count++;
kfree(tmpbuf);
/* Updates stream time */ /* Updates stream time */
dev->ms += jiffies_to_msecs(jiffies-dev->jiffies); dev->ms += jiffies_to_msecs(jiffies - dev->jiffies);
dev->jiffies = jiffies; dev->jiffies = jiffies;
if (dev->ms >= 1000) { ms = dev->ms;
dev->ms -= 1000; snprintf(str, sizeof(str), " %02d:%02d:%02d:%03d ",
dev->s++; (ms / (60 * 60 * 1000)) % 24,
if (dev->s >= 60) { (ms / (60 * 1000)) % 60,
dev->s -= 60; (ms / 1000) % 60,
dev->m++; ms % 1000);
if (dev->m > 60) { gen_text(dev, vbuf, line++ * 16, 16, str);
dev->m -= 60; snprintf(str, sizeof(str), " %dx%d, input %d ",
dev->h++; dev->width, dev->height, dev->input);
if (dev->h > 24) gen_text(dev, vbuf, line++ * 16, 16, str);
dev->h -= 24;
} snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
} dev->brightness,
} dev->contrast,
sprintf(dev->timestr, "%02d:%02d:%02d:%03d", dev->saturation,
dev->h, dev->m, dev->s, dev->ms); dev->hue);
gen_text(dev, vbuf, line++ * 16, 16, str);
dprintk(dev, 2, "vivifill at %s: Buffer 0x%08lx size= %d\n", snprintf(str, sizeof(str), " volume %3d ", dev->volume);
dev->timestr, (unsigned long)tmpbuf, pos); gen_text(dev, vbuf, line++ * 16, 16, str);
dev->mv_count += 2;
/* Advice that buffer was filled */ /* Advice that buffer was filled */
buf->vb.field_count++; buf->vb.field_count++;
...@@ -614,12 +489,10 @@ static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf) ...@@ -614,12 +489,10 @@ static void vivi_fillbuff(struct vivi_fh *fh, struct vivi_buffer *buf)
buf->vb.state = VIDEOBUF_DONE; buf->vb.state = VIDEOBUF_DONE;
} }
static void vivi_thread_tick(struct vivi_fh *fh) static void vivi_thread_tick(struct vivi_dev *dev)
{ {
struct vivi_buffer *buf;
struct vivi_dev *dev = fh->dev;
struct vivi_dmaqueue *dma_q = &dev->vidq; struct vivi_dmaqueue *dma_q = &dev->vidq;
struct vivi_buffer *buf;
unsigned long flags = 0; unsigned long flags = 0;
dprintk(dev, 1, "Thread tick\n"); dprintk(dev, 1, "Thread tick\n");
...@@ -642,22 +515,20 @@ static void vivi_thread_tick(struct vivi_fh *fh) ...@@ -642,22 +515,20 @@ static void vivi_thread_tick(struct vivi_fh *fh)
do_gettimeofday(&buf->vb.ts); do_gettimeofday(&buf->vb.ts);
/* Fill buffer */ /* Fill buffer */
vivi_fillbuff(fh, buf); vivi_fillbuff(dev, buf);
dprintk(dev, 1, "filled buffer %p\n", buf); dprintk(dev, 1, "filled buffer %p\n", buf);
wake_up(&buf->vb.done); wake_up(&buf->vb.done);
dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i); dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
unlock: unlock:
spin_unlock_irqrestore(&dev->slock, flags); spin_unlock_irqrestore(&dev->slock, flags);
return;
} }
#define frames_to_ms(frames) \ #define frames_to_ms(frames) \
((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR) ((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
static void vivi_sleep(struct vivi_fh *fh) static void vivi_sleep(struct vivi_dev *dev)
{ {
struct vivi_dev *dev = fh->dev;
struct vivi_dmaqueue *dma_q = &dev->vidq; struct vivi_dmaqueue *dma_q = &dev->vidq;
int timeout; int timeout;
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
...@@ -672,7 +543,7 @@ static void vivi_sleep(struct vivi_fh *fh) ...@@ -672,7 +543,7 @@ static void vivi_sleep(struct vivi_fh *fh)
/* Calculate time to wake up */ /* Calculate time to wake up */
timeout = msecs_to_jiffies(frames_to_ms(1)); timeout = msecs_to_jiffies(frames_to_ms(1));
vivi_thread_tick(fh); vivi_thread_tick(dev);
schedule_timeout_interruptible(timeout); schedule_timeout_interruptible(timeout);
...@@ -683,15 +554,14 @@ static void vivi_sleep(struct vivi_fh *fh) ...@@ -683,15 +554,14 @@ static void vivi_sleep(struct vivi_fh *fh)
static int vivi_thread(void *data) static int vivi_thread(void *data)
{ {
struct vivi_fh *fh = data; struct vivi_dev *dev = data;
struct vivi_dev *dev = fh->dev;
dprintk(dev, 1, "thread started\n"); dprintk(dev, 1, "thread started\n");
set_freezable(); set_freezable();
for (;;) { for (;;) {
vivi_sleep(fh); vivi_sleep(dev);
if (kthread_should_stop()) if (kthread_should_stop())
break; break;
...@@ -700,39 +570,61 @@ static int vivi_thread(void *data) ...@@ -700,39 +570,61 @@ static int vivi_thread(void *data)
return 0; return 0;
} }
static int vivi_start_thread(struct vivi_fh *fh) static void vivi_start_generating(struct file *file)
{ {
struct vivi_dev *dev = fh->dev; struct vivi_dev *dev = video_drvdata(file);
struct vivi_dmaqueue *dma_q = &dev->vidq; struct vivi_dmaqueue *dma_q = &dev->vidq;
dma_q->frame = 0;
dma_q->ini_jiffies = jiffies;
dprintk(dev, 1, "%s\n", __func__); dprintk(dev, 1, "%s\n", __func__);
dma_q->kthread = kthread_run(vivi_thread, fh, "vivi"); if (test_and_set_bit(0, &dev->generating))
return;
file->private_data = dev;
/* Resets frame counters */
dev->ms = 0;
dev->mv_count = 0;
dev->jiffies = jiffies;
dma_q->frame = 0;
dma_q->ini_jiffies = jiffies;
dma_q->kthread = kthread_run(vivi_thread, dev, dev->v4l2_dev.name);
if (IS_ERR(dma_q->kthread)) { if (IS_ERR(dma_q->kthread)) {
v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n"); v4l2_err(&dev->v4l2_dev, "kernel_thread() failed\n");
return PTR_ERR(dma_q->kthread); clear_bit(0, &dev->generating);
return;
} }
/* Wakes thread */ /* Wakes thread */
wake_up_interruptible(&dma_q->wq); wake_up_interruptible(&dma_q->wq);
dprintk(dev, 1, "returning from %s\n", __func__); dprintk(dev, 1, "returning from %s\n", __func__);
return 0;
} }
static void vivi_stop_thread(struct vivi_dmaqueue *dma_q) static void vivi_stop_generating(struct file *file)
{ {
struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq); struct vivi_dev *dev = video_drvdata(file);
struct vivi_dmaqueue *dma_q = &dev->vidq;
dprintk(dev, 1, "%s\n", __func__); dprintk(dev, 1, "%s\n", __func__);
if (!file->private_data)
return;
if (!test_and_clear_bit(0, &dev->generating))
return;
/* shutdown control thread */ /* shutdown control thread */
if (dma_q->kthread) { if (dma_q->kthread) {
kthread_stop(dma_q->kthread); kthread_stop(dma_q->kthread);
dma_q->kthread = NULL; dma_q->kthread = NULL;
} }
videobuf_stop(&dev->vb_vidq);
videobuf_mmap_free(&dev->vb_vidq);
}
static int vivi_is_generating(struct vivi_dev *dev)
{
return test_bit(0, &dev->generating);
} }
/* ------------------------------------------------------------------ /* ------------------------------------------------------------------
...@@ -741,16 +633,15 @@ static void vivi_stop_thread(struct vivi_dmaqueue *dma_q) ...@@ -741,16 +633,15 @@ static void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
static int static int
buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
{ {
struct vivi_fh *fh = vq->priv_data; struct vivi_dev *dev = vq->priv_data;
struct vivi_dev *dev = fh->dev;
*size = fh->width*fh->height*2; *size = dev->width * dev->height * 2;
if (0 == *count) if (0 == *count)
*count = 32; *count = 32;
if (*size * *count > vid_limit * 1024 * 1024) while (*size * *count > vid_limit * 1024 * 1024)
*count = (vid_limit * 1024 * 1024) / *size; (*count)--;
dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__, dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
*count, *size); *count, *size);
...@@ -760,49 +651,43 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size) ...@@ -760,49 +651,43 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf) static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
{ {
struct vivi_fh *fh = vq->priv_data; struct vivi_dev *dev = vq->priv_data;
struct vivi_dev *dev = fh->dev;
dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state); dprintk(dev, 1, "%s, state: %i\n", __func__, buf->vb.state);
if (in_interrupt())
BUG();
videobuf_vmalloc_free(&buf->vb); videobuf_vmalloc_free(&buf->vb);
dprintk(dev, 1, "free_buffer: freed\n"); dprintk(dev, 1, "free_buffer: freed\n");
buf->vb.state = VIDEOBUF_NEEDS_INIT; buf->vb.state = VIDEOBUF_NEEDS_INIT;
} }
#define norm_maxw() 1024
#define norm_maxh() 768
static int static int
buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
enum v4l2_field field) enum v4l2_field field)
{ {
struct vivi_fh *fh = vq->priv_data; struct vivi_dev *dev = vq->priv_data;
struct vivi_dev *dev = fh->dev;
struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
int rc; int rc;
dprintk(dev, 1, "%s, field=%d\n", __func__, field); dprintk(dev, 1, "%s, field=%d\n", __func__, field);
BUG_ON(NULL == fh->fmt); BUG_ON(NULL == dev->fmt);
if (fh->width < 48 || fh->width > norm_maxw() || if (dev->width < 48 || dev->width > MAX_WIDTH ||
fh->height < 32 || fh->height > norm_maxh()) dev->height < 32 || dev->height > MAX_HEIGHT)
return -EINVAL; return -EINVAL;
buf->vb.size = fh->width*fh->height*2; buf->vb.size = dev->width * dev->height * 2;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL; return -EINVAL;
/* These properties only change when queue is idle, see s_fmt */ /* These properties only change when queue is idle, see s_fmt */
buf->fmt = fh->fmt; buf->fmt = dev->fmt;
buf->vb.width = fh->width; buf->vb.width = dev->width;
buf->vb.height = fh->height; buf->vb.height = dev->height;
buf->vb.field = field; buf->vb.field = field;
precalculate_bars(fh); precalculate_bars(dev);
precalculate_line(dev);
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) { if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
rc = videobuf_iolock(vq, &buf->vb, NULL); rc = videobuf_iolock(vq, &buf->vb, NULL);
...@@ -811,7 +696,6 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, ...@@ -811,7 +696,6 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
} }
buf->vb.state = VIDEOBUF_PREPARED; buf->vb.state = VIDEOBUF_PREPARED;
return 0; return 0;
fail: fail:
...@@ -822,9 +706,8 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb, ...@@ -822,9 +706,8 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
static void static void
buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
{ {
struct vivi_dev *dev = vq->priv_data;
struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
struct vivi_fh *fh = vq->priv_data;
struct vivi_dev *dev = fh->dev;
struct vivi_dmaqueue *vidq = &dev->vidq; struct vivi_dmaqueue *vidq = &dev->vidq;
dprintk(dev, 1, "%s\n", __func__); dprintk(dev, 1, "%s\n", __func__);
...@@ -836,9 +719,8 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb) ...@@ -836,9 +719,8 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
static void buffer_release(struct videobuf_queue *vq, static void buffer_release(struct videobuf_queue *vq,
struct videobuf_buffer *vb) struct videobuf_buffer *vb)
{ {
struct vivi_dev *dev = vq->priv_data;
struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb); struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
struct vivi_fh *fh = vq->priv_data;
struct vivi_dev *dev = (struct vivi_dev *)fh->dev;
dprintk(dev, 1, "%s\n", __func__); dprintk(dev, 1, "%s\n", __func__);
...@@ -858,15 +740,13 @@ static struct videobuf_queue_ops vivi_video_qops = { ...@@ -858,15 +740,13 @@ static struct videobuf_queue_ops vivi_video_qops = {
static int vidioc_querycap(struct file *file, void *priv, static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap) struct v4l2_capability *cap)
{ {
struct vivi_fh *fh = priv; struct vivi_dev *dev = video_drvdata(file);
struct vivi_dev *dev = fh->dev;
strcpy(cap->driver, "vivi"); strcpy(cap->driver, "vivi");
strcpy(cap->card, "vivi"); strcpy(cap->card, "vivi");
strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info)); strlcpy(cap->bus_info, dev->v4l2_dev.name, sizeof(cap->bus_info));
cap->version = VIVI_VERSION; cap->version = VIVI_VERSION;
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING | \
V4L2_CAP_STREAMING |
V4L2_CAP_READWRITE; V4L2_CAP_READWRITE;
return 0; return 0;
} }
...@@ -889,28 +769,25 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv, ...@@ -889,28 +769,25 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv, static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f) struct v4l2_format *f)
{ {
struct vivi_fh *fh = priv; struct vivi_dev *dev = video_drvdata(file);
f->fmt.pix.width = fh->width; f->fmt.pix.width = dev->width;
f->fmt.pix.height = fh->height; f->fmt.pix.height = dev->height;
f->fmt.pix.field = fh->vb_vidq.field; f->fmt.pix.field = dev->vb_vidq.field;
f->fmt.pix.pixelformat = fh->fmt->fourcc; f->fmt.pix.pixelformat = dev->fmt->fourcc;
f->fmt.pix.bytesperline = f->fmt.pix.bytesperline =
(f->fmt.pix.width * fh->fmt->depth) >> 3; (f->fmt.pix.width * dev->fmt->depth) >> 3;
f->fmt.pix.sizeimage = f->fmt.pix.sizeimage =
f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.height * f->fmt.pix.bytesperline;
return 0;
return (0);
} }
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f) struct v4l2_format *f)
{ {
struct vivi_fh *fh = priv; struct vivi_dev *dev = video_drvdata(file);
struct vivi_dev *dev = fh->dev;
struct vivi_fmt *fmt; struct vivi_fmt *fmt;
enum v4l2_field field; enum v4l2_field field;
unsigned int maxw, maxh;
fmt = get_format(f); fmt = get_format(f);
if (!fmt) { if (!fmt) {
...@@ -928,113 +805,109 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv, ...@@ -928,113 +805,109 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
return -EINVAL; return -EINVAL;
} }
maxw = norm_maxw();
maxh = norm_maxh();
f->fmt.pix.field = field; f->fmt.pix.field = field;
v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2, v4l_bound_align_image(&f->fmt.pix.width, 48, MAX_WIDTH, 2,
&f->fmt.pix.height, 32, maxh, 0, 0); &f->fmt.pix.height, 32, MAX_HEIGHT, 0, 0);
f->fmt.pix.bytesperline = f->fmt.pix.bytesperline =
(f->fmt.pix.width * fmt->depth) >> 3; (f->fmt.pix.width * fmt->depth) >> 3;
f->fmt.pix.sizeimage = f->fmt.pix.sizeimage =
f->fmt.pix.height * f->fmt.pix.bytesperline; f->fmt.pix.height * f->fmt.pix.bytesperline;
return 0; return 0;
} }
/*FIXME: This seems to be generic enough to be at videodev2 */
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f) struct v4l2_format *f)
{ {
struct vivi_fh *fh = priv; struct vivi_dev *dev = video_drvdata(file);
struct videobuf_queue *q = &fh->vb_vidq; struct videobuf_queue *q = &dev->vb_vidq;
int ret = vidioc_try_fmt_vid_cap(file, fh, f); int ret = vidioc_try_fmt_vid_cap(file, priv, f);
if (ret < 0) if (ret < 0)
return ret; return ret;
mutex_lock(&q->vb_lock); mutex_lock(&q->vb_lock);
if (videobuf_queue_is_busy(&fh->vb_vidq)) { if (vivi_is_generating(dev)) {
dprintk(fh->dev, 1, "%s queue busy\n", __func__); dprintk(dev, 1, "%s device busy\n", __func__);
ret = -EBUSY; ret = -EBUSY;
goto out; goto out;
} }
fh->fmt = get_format(f); dev->fmt = get_format(f);
fh->width = f->fmt.pix.width; dev->width = f->fmt.pix.width;
fh->height = f->fmt.pix.height; dev->height = f->fmt.pix.height;
fh->vb_vidq.field = f->fmt.pix.field; dev->vb_vidq.field = f->fmt.pix.field;
fh->type = f->type;
ret = 0; ret = 0;
out: out:
mutex_unlock(&q->vb_lock); mutex_unlock(&q->vb_lock);
return ret; return ret;
} }
static int vidioc_reqbufs(struct file *file, void *priv, static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p) struct v4l2_requestbuffers *p)
{ {
struct vivi_fh *fh = priv; struct vivi_dev *dev = video_drvdata(file);
return (videobuf_reqbufs(&fh->vb_vidq, p)); return videobuf_reqbufs(&dev->vb_vidq, p);
} }
static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p) static int vidioc_querybuf(struct file *file, void *priv, struct v4l2_buffer *p)
{ {
struct vivi_fh *fh = priv; struct vivi_dev *dev = video_drvdata(file);
return (videobuf_querybuf(&fh->vb_vidq, p)); return videobuf_querybuf(&dev->vb_vidq, p);
} }
static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p) static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{ {
struct vivi_fh *fh = priv; struct vivi_dev *dev = video_drvdata(file);
return (videobuf_qbuf(&fh->vb_vidq, p)); return videobuf_qbuf(&dev->vb_vidq, p);
} }
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p) static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
{ {
struct vivi_fh *fh = priv; struct vivi_dev *dev = video_drvdata(file);
return (videobuf_dqbuf(&fh->vb_vidq, p, return videobuf_dqbuf(&dev->vb_vidq, p,
file->f_flags & O_NONBLOCK)); file->f_flags & O_NONBLOCK);
} }
#ifdef CONFIG_VIDEO_V4L1_COMPAT #ifdef CONFIG_VIDEO_V4L1_COMPAT
static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf) static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
{ {
struct vivi_fh *fh = priv; struct vivi_dev *dev = video_drvdata(file);
return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8); return videobuf_cgmbuf(&dev->vb_vidq, mbuf, 8);
} }
#endif #endif
static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i) static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{ {
struct vivi_fh *fh = priv; struct vivi_dev *dev = video_drvdata(file);
int ret;
if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (i != fh->type)
return -EINVAL; return -EINVAL;
ret = videobuf_streamon(&dev->vb_vidq);
if (ret)
return ret;
return videobuf_streamon(&fh->vb_vidq); vivi_start_generating(file);
return 0;
} }
static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i) static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
{ {
struct vivi_fh *fh = priv; struct vivi_dev *dev = video_drvdata(file);
int ret;
if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL; return -EINVAL;
if (i != fh->type) ret = videobuf_streamoff(&dev->vb_vidq);
return -EINVAL; if (!ret)
vivi_stop_generating(file);
return videobuf_streamoff(&fh->vb_vidq); return ret;
} }
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i) static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
...@@ -1052,78 +925,102 @@ static int vidioc_enum_input(struct file *file, void *priv, ...@@ -1052,78 +925,102 @@ static int vidioc_enum_input(struct file *file, void *priv,
inp->type = V4L2_INPUT_TYPE_CAMERA; inp->type = V4L2_INPUT_TYPE_CAMERA;
inp->std = V4L2_STD_525_60; inp->std = V4L2_STD_525_60;
sprintf(inp->name, "Camera %u", inp->index); sprintf(inp->name, "Camera %u", inp->index);
return 0;
return (0);
} }
static int vidioc_g_input(struct file *file, void *priv, unsigned int *i) static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
{ {
struct vivi_fh *fh = priv; struct vivi_dev *dev = video_drvdata(file);
struct vivi_dev *dev = fh->dev;
*i = dev->input; *i = dev->input;
return 0;
return (0);
} }
static int vidioc_s_input(struct file *file, void *priv, unsigned int i) static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
{ {
struct vivi_fh *fh = priv; struct vivi_dev *dev = video_drvdata(file);
struct vivi_dev *dev = fh->dev;
if (i >= NUM_INPUTS) if (i >= NUM_INPUTS)
return -EINVAL; return -EINVAL;
dev->input = i; dev->input = i;
precalculate_bars(fh); precalculate_bars(dev);
precalculate_line(dev);
return (0); return 0;
} }
/* --- controls ---------------------------------------------- */ /* --- controls ---------------------------------------------- */
static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc) struct v4l2_queryctrl *qc)
{ {
int i; switch (qc->id) {
case V4L2_CID_AUDIO_VOLUME:
for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) return v4l2_ctrl_query_fill(qc, 0, 255, 1, 200);
if (qc->id && qc->id == vivi_qctrl[i].id) { case V4L2_CID_BRIGHTNESS:
memcpy(qc, &(vivi_qctrl[i]), return v4l2_ctrl_query_fill(qc, 0, 255, 1, 127);
sizeof(*qc)); case V4L2_CID_CONTRAST:
return (0); return v4l2_ctrl_query_fill(qc, 0, 255, 1, 16);
case V4L2_CID_SATURATION:
return v4l2_ctrl_query_fill(qc, 0, 255, 1, 127);
case V4L2_CID_HUE:
return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
} }
return -EINVAL; return -EINVAL;
} }
static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl) struct v4l2_control *ctrl)
{ {
struct vivi_fh *fh = priv; struct vivi_dev *dev = video_drvdata(file);
struct vivi_dev *dev = fh->dev;
int i;
for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) switch (ctrl->id) {
if (ctrl->id == vivi_qctrl[i].id) { case V4L2_CID_AUDIO_VOLUME:
ctrl->value = dev->qctl_regs[i]; ctrl->value = dev->volume;
return 0;
case V4L2_CID_BRIGHTNESS:
ctrl->value = dev->brightness;
return 0;
case V4L2_CID_CONTRAST:
ctrl->value = dev->contrast;
return 0;
case V4L2_CID_SATURATION:
ctrl->value = dev->saturation;
return 0;
case V4L2_CID_HUE:
ctrl->value = dev->hue;
return 0; return 0;
} }
return -EINVAL; return -EINVAL;
} }
static int vidioc_s_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl) struct v4l2_control *ctrl)
{ {
struct vivi_fh *fh = priv; struct vivi_dev *dev = video_drvdata(file);
struct vivi_dev *dev = fh->dev; struct v4l2_queryctrl qc;
int i; int err;
for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++) qc.id = ctrl->id;
if (ctrl->id == vivi_qctrl[i].id) { err = vidioc_queryctrl(file, priv, &qc);
if (ctrl->value < vivi_qctrl[i].minimum || if (err < 0)
ctrl->value > vivi_qctrl[i].maximum) { return err;
if (ctrl->value < qc.minimum || ctrl->value > qc.maximum)
return -ERANGE; return -ERANGE;
} switch (ctrl->id) {
dev->qctl_regs[i] = ctrl->value; case V4L2_CID_AUDIO_VOLUME:
dev->volume = ctrl->value;
return 0;
case V4L2_CID_BRIGHTNESS:
dev->brightness = ctrl->value;
return 0;
case V4L2_CID_CONTRAST:
dev->contrast = ctrl->value;
return 0;
case V4L2_CID_SATURATION:
dev->saturation = ctrl->value;
return 0;
case V4L2_CID_HUE:
dev->hue = ctrl->value;
return 0; return 0;
} }
return -EINVAL; return -EINVAL;
...@@ -1133,134 +1030,58 @@ static int vidioc_s_ctrl(struct file *file, void *priv, ...@@ -1133,134 +1030,58 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
File operations for the device File operations for the device
------------------------------------------------------------------*/ ------------------------------------------------------------------*/
static int vivi_open(struct file *file)
{
struct vivi_dev *dev = video_drvdata(file);
struct vivi_fh *fh = NULL;
int retval = 0;
mutex_lock(&dev->mutex);
dev->users++;
if (dev->users > 1) {
dev->users--;
mutex_unlock(&dev->mutex);
return -EBUSY;
}
dprintk(dev, 1, "open %s type=%s users=%d\n",
video_device_node_name(dev->vfd),
v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
/* allocate + initialize per filehandle data */
fh = kzalloc(sizeof(*fh), GFP_KERNEL);
if (NULL == fh) {
dev->users--;
retval = -ENOMEM;
}
mutex_unlock(&dev->mutex);
if (retval)
return retval;
file->private_data = fh;
fh->dev = dev;
fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fh->fmt = &formats[0];
fh->width = 640;
fh->height = 480;
/* Resets frame counters */
dev->h = 0;
dev->m = 0;
dev->s = 0;
dev->ms = 0;
dev->mv_count = 0;
dev->jiffies = jiffies;
sprintf(dev->timestr, "%02d:%02d:%02d:%03d",
dev->h, dev->m, dev->s, dev->ms);
videobuf_queue_vmalloc_init(&fh->vb_vidq, &vivi_video_qops,
NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
sizeof(struct vivi_buffer), fh);
vivi_start_thread(fh);
return 0;
}
static ssize_t static ssize_t
vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos) vivi_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{ {
struct vivi_fh *fh = file->private_data; struct vivi_dev *dev = video_drvdata(file);
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { vivi_start_generating(file);
return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0, return videobuf_read_stream(&dev->vb_vidq, data, count, ppos, 0,
file->f_flags & O_NONBLOCK); file->f_flags & O_NONBLOCK);
}
return 0;
} }
static unsigned int static unsigned int
vivi_poll(struct file *file, struct poll_table_struct *wait) vivi_poll(struct file *file, struct poll_table_struct *wait)
{ {
struct vivi_fh *fh = file->private_data; struct vivi_dev *dev = video_drvdata(file);
struct vivi_dev *dev = fh->dev; struct videobuf_queue *q = &dev->vb_vidq;
struct videobuf_queue *q = &fh->vb_vidq;
dprintk(dev, 1, "%s\n", __func__); dprintk(dev, 1, "%s\n", __func__);
if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type) vivi_start_generating(file);
return POLLERR;
return videobuf_poll_stream(file, q, wait); return videobuf_poll_stream(file, q, wait);
} }
static int vivi_close(struct file *file) static int vivi_close(struct file *file)
{ {
struct vivi_fh *fh = file->private_data;
struct vivi_dev *dev = fh->dev;
struct vivi_dmaqueue *vidq = &dev->vidq;
struct video_device *vdev = video_devdata(file); struct video_device *vdev = video_devdata(file);
struct vivi_dev *dev = video_drvdata(file);
vivi_stop_thread(vidq); vivi_stop_generating(file);
videobuf_stop(&fh->vb_vidq);
videobuf_mmap_free(&fh->vb_vidq);
kfree(fh);
mutex_lock(&dev->mutex);
dev->users--;
mutex_unlock(&dev->mutex);
dprintk(dev, 1, "close called (dev=%s, users=%d)\n",
video_device_node_name(vdev), dev->users);
dprintk(dev, 1, "close called (dev=%s)\n",
video_device_node_name(vdev));
return 0; return 0;
} }
static int vivi_mmap(struct file *file, struct vm_area_struct *vma) static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
{ {
struct vivi_fh *fh = file->private_data; struct vivi_dev *dev = video_drvdata(file);
struct vivi_dev *dev = fh->dev;
int ret; int ret;
dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma); dprintk(dev, 1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
ret = videobuf_mmap_mapper(&fh->vb_vidq, vma); ret = videobuf_mmap_mapper(&dev->vb_vidq, vma);
dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n", dprintk(dev, 1, "vma start=0x%08lx, size=%ld, ret=%d\n",
(unsigned long)vma->vm_start, (unsigned long)vma->vm_start,
(unsigned long)vma->vm_end-(unsigned long)vma->vm_start, (unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
ret); ret);
return ret; return ret;
} }
static const struct v4l2_file_operations vivi_fops = { static const struct v4l2_file_operations vivi_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = vivi_open,
.release = vivi_close, .release = vivi_close,
.read = vivi_read, .read = vivi_read,
.poll = vivi_poll, .poll = vivi_poll,
...@@ -1282,11 +1103,11 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = { ...@@ -1282,11 +1103,11 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
.vidioc_enum_input = vidioc_enum_input, .vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input, .vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input, .vidioc_s_input = vidioc_s_input,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
.vidioc_queryctrl = vidioc_queryctrl, .vidioc_queryctrl = vidioc_queryctrl,
.vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_g_ctrl = vidioc_g_ctrl,
.vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
#ifdef CONFIG_VIDEO_V4L1_COMPAT #ifdef CONFIG_VIDEO_V4L1_COMPAT
.vidiocgmbuf = vidiocgmbuf, .vidiocgmbuf = vidiocgmbuf,
#endif #endif
...@@ -1330,7 +1151,7 @@ static int __init vivi_create_instance(int inst) ...@@ -1330,7 +1151,7 @@ static int __init vivi_create_instance(int inst)
{ {
struct vivi_dev *dev; struct vivi_dev *dev;
struct video_device *vfd; struct video_device *vfd;
int ret, i; int ret;
dev = kzalloc(sizeof(*dev), GFP_KERNEL); dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) if (!dev)
...@@ -1342,6 +1163,20 @@ static int __init vivi_create_instance(int inst) ...@@ -1342,6 +1163,20 @@ static int __init vivi_create_instance(int inst)
if (ret) if (ret)
goto free_dev; goto free_dev;
dev->fmt = &formats[0];
dev->width = 640;
dev->height = 480;
dev->volume = 200;
dev->brightness = 127;
dev->contrast = 16;
dev->saturation = 127;
dev->hue = 0;
videobuf_queue_vmalloc_init(&dev->vb_vidq, &vivi_video_qops,
NULL, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct vivi_buffer), dev);
/* init video dma queues */ /* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active); INIT_LIST_HEAD(&dev->vidq.active);
init_waitqueue_head(&dev->vidq.wq); init_waitqueue_head(&dev->vidq.wq);
...@@ -1357,6 +1192,7 @@ static int __init vivi_create_instance(int inst) ...@@ -1357,6 +1192,7 @@ static int __init vivi_create_instance(int inst)
*vfd = vivi_template; *vfd = vivi_template;
vfd->debug = debug; vfd->debug = debug;
vfd->v4l2_dev = &dev->v4l2_dev;
ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr); ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
if (ret < 0) if (ret < 0)
...@@ -1364,10 +1200,6 @@ static int __init vivi_create_instance(int inst) ...@@ -1364,10 +1200,6 @@ static int __init vivi_create_instance(int inst)
video_set_drvdata(vfd, dev); video_set_drvdata(vfd, dev);
/* Set all controls to their default value. */
for (i = 0; i < ARRAY_SIZE(vivi_qctrl); i++)
dev->qctl_regs[i] = vivi_qctrl[i].default_value;
/* Now that everything is fine, let's add it to device list */ /* Now that everything is fine, let's add it to device list */
list_add_tail(&dev->vivi_devlist, &vivi_devlist); list_add_tail(&dev->vivi_devlist, &vivi_devlist);
...@@ -1396,8 +1228,15 @@ static int __init vivi_create_instance(int inst) ...@@ -1396,8 +1228,15 @@ static int __init vivi_create_instance(int inst)
*/ */
static int __init vivi_init(void) static int __init vivi_init(void)
{ {
const struct font_desc *font = find_font("VGA8x16");
int ret = 0, i; int ret = 0, i;
if (font == NULL) {
printk(KERN_ERR "vivi: could not find font\n");
return -ENODEV;
}
font8x16 = font->data;
if (n_devs <= 0) if (n_devs <= 0)
n_devs = 1; n_devs = 1;
...@@ -1412,7 +1251,7 @@ static int __init vivi_init(void) ...@@ -1412,7 +1251,7 @@ static int __init vivi_init(void)
} }
if (ret < 0) { if (ret < 0) {
printk(KERN_INFO "Error %d while loading vivi driver\n", ret); printk(KERN_ERR "vivi: error %d while loading driver\n", ret);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment