Commit 773f7f2f authored by Stelian Pop's avatar Stelian Pop Committed by Linus Torvalds

[PATCH] meye: add v4l2 support

Signed-off-by: default avatarStelian Pop <stelian@popies.net>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 4a5f5e21
...@@ -46,6 +46,8 @@ module argument syntax (<param>=<value> when passing the option to the ...@@ -46,6 +46,8 @@ module argument syntax (<param>=<value> when passing the option to the
module or meye.<param>=<value> on the kernel boot line when meye is module or meye.<param>=<value> on the kernel boot line when meye is
statically linked into the kernel). Those options are: statically linked into the kernel). Those options are:
forcev4l1: force use of V4L1 API instead of V4L2
gbuffers: number of capture buffers, default is 2 (32 max) gbuffers: number of capture buffers, default is 2 (32 max)
gbufsize: size of each capture buffer, default is 614400 gbufsize: size of each capture buffer, default is 614400
...@@ -78,8 +80,9 @@ Usage: ...@@ -78,8 +80,9 @@ Usage:
Private API: Private API:
------------ ------------
The driver supports frame grabbing with the video4linux API, so The driver supports frame grabbing with the video4linux API
all video4linux tools (like xawtv) should work with this driver. (either v4l1 or v4l2), so all video4linux tools (like xawtv)
should work with this driver.
Besides the video4linux interface, the driver has a private interface Besides the video4linux interface, the driver has a private interface
for accessing the Motion Eye extended parameters (camera sharpness, for accessing the Motion Eye extended parameters (camera sharpness,
...@@ -121,13 +124,7 @@ Private API: ...@@ -121,13 +124,7 @@ Private API:
Bugs / Todo: Bugs / Todo:
------------ ------------
- overlay output is not supported (although the camera is capable of). - the driver could be much cleaned up by removing the v4l1 support.
(it should not be too hard to to it, provided we found how...) However, this means all v4l1-only applications will stop working.
- mjpeg hardware playback doesn't work (depends on overlay...)
- rewrite the driver to use some common video4linux API for snapshot - 'motioneye' still uses the meye private v4l1 API extensions.
and mjpeg capture. Unfortunately, video4linux1 does not permit it,
the BUZ API seems to be targeted to TV cards only. The video4linux 2
API may be an option, if it goes into the kernel (maybe 2.5
material ?).
...@@ -46,6 +46,11 @@ MODULE_DESCRIPTION("v4l/v4l2 driver for the MotionEye camera"); ...@@ -46,6 +46,11 @@ MODULE_DESCRIPTION("v4l/v4l2 driver for the MotionEye camera");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_VERSION(MEYE_DRIVER_VERSION); MODULE_VERSION(MEYE_DRIVER_VERSION);
/* force usage of V4L1 API */
static int forcev4l1; /* = 0 */
module_param(forcev4l1, int, 0644);
MODULE_PARM_DESC(forcev4l1, "force use of V4L1 instead of V4L2");
/* number of grab buffers */ /* number of grab buffers */
static unsigned int gbuffers = 2; static unsigned int gbuffers = 2;
module_param(gbuffers, int, 0444); module_param(gbuffers, int, 0444);
...@@ -781,6 +786,8 @@ static irqreturn_t meye_irq(int irq, void *dev_id, struct pt_regs *regs) ...@@ -781,6 +786,8 @@ static irqreturn_t meye_irq(int irq, void *dev_id, struct pt_regs *regs)
{ {
u32 v; u32 v;
int reqnr; int reqnr;
static int sequence = 0;
v = mchip_read(MCHIP_MM_INTA); v = mchip_read(MCHIP_MM_INTA);
if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_OUT && if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_OUT &&
...@@ -802,6 +809,8 @@ static irqreturn_t meye_irq(int irq, void *dev_id, struct pt_regs *regs) ...@@ -802,6 +809,8 @@ static irqreturn_t meye_irq(int irq, void *dev_id, struct pt_regs *regs)
mchip_hsize() * mchip_vsize() * 2); mchip_hsize() * mchip_vsize() * 2);
meye.grab_buffer[reqnr].size = mchip_hsize() * mchip_vsize() * 2; meye.grab_buffer[reqnr].size = mchip_hsize() * mchip_vsize() * 2;
meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; meye.grab_buffer[reqnr].state = MEYE_BUF_DONE;
do_gettimeofday(&meye.grab_buffer[reqnr].timestamp);
meye.grab_buffer[reqnr].sequence = sequence++;
kfifo_put(meye.doneq, (unsigned char *)&reqnr, sizeof(int)); kfifo_put(meye.doneq, (unsigned char *)&reqnr, sizeof(int));
wake_up_interruptible(&meye.proc_list); wake_up_interruptible(&meye.proc_list);
} else { } else {
...@@ -820,6 +829,8 @@ static irqreturn_t meye_irq(int irq, void *dev_id, struct pt_regs *regs) ...@@ -820,6 +829,8 @@ static irqreturn_t meye_irq(int irq, void *dev_id, struct pt_regs *regs)
size); size);
meye.grab_buffer[reqnr].size = size; meye.grab_buffer[reqnr].size = size;
meye.grab_buffer[reqnr].state = MEYE_BUF_DONE; meye.grab_buffer[reqnr].state = MEYE_BUF_DONE;
do_gettimeofday(&meye.grab_buffer[reqnr].timestamp);
meye.grab_buffer[reqnr].sequence = sequence++;
kfifo_put(meye.doneq, (unsigned char *)&reqnr, sizeof(int)); kfifo_put(meye.doneq, (unsigned char *)&reqnr, sizeof(int));
wake_up_interruptible(&meye.proc_list); wake_up_interruptible(&meye.proc_list);
} }
...@@ -1132,10 +1143,519 @@ static int meye_do_ioctl(struct inode *inode, struct file *file, ...@@ -1132,10 +1143,519 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
break; break;
} }
case VIDIOC_QUERYCAP: {
struct v4l2_capability *cap = arg;
if (forcev4l1)
return -EINVAL;
memset(cap, 0, sizeof(*cap));
strcpy(cap->driver, "meye");
strcpy(cap->card, "meye");
sprintf(cap->bus_info, "PCI:%s", meye.mchip_dev->slot_name);
cap->version = (MEYE_DRIVER_MAJORVERSION << 8) +
MEYE_DRIVER_MINORVERSION;
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING;
break;
}
case VIDIOC_ENUMINPUT: {
struct v4l2_input *i = arg;
if (i->index != 0)
return -EINVAL;
memset(i, 0, sizeof(*i));
i->index = 0;
strcpy(i->name, "Camera");
i->type = V4L2_INPUT_TYPE_CAMERA;
break;
}
case VIDIOC_G_INPUT: {
int *i = arg;
*i = 0;
break;
}
case VIDIOC_S_INPUT: {
int *i = arg;
if (*i != 0)
return -EINVAL;
break;
}
case VIDIOC_QUERYCTRL: {
struct v4l2_queryctrl *c = arg;
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
c->type = V4L2_CTRL_TYPE_INTEGER;
strcpy(c->name, "Brightness");
c->minimum = 0;
c->maximum = 63;
c->step = 1;
c->default_value = 32;
c->flags = 0;
break;
case V4L2_CID_HUE:
c->type = V4L2_CTRL_TYPE_INTEGER;
strcpy(c->name, "Hue");
c->minimum = 0;
c->maximum = 63;
c->step = 1;
c->default_value = 32;
c->flags = 0;
break;
case V4L2_CID_CONTRAST:
c->type = V4L2_CTRL_TYPE_INTEGER;
strcpy(c->name, "Contrast");
c->minimum = 0;
c->maximum = 63;
c->step = 1;
c->default_value = 32;
c->flags = 0;
break;
case V4L2_CID_SATURATION:
c->type = V4L2_CTRL_TYPE_INTEGER;
strcpy(c->name, "Saturation");
c->minimum = 0;
c->maximum = 63;
c->step = 1;
c->default_value = 32;
c->flags = 0;
break;
case V4L2_CID_AGC:
c->type = V4L2_CTRL_TYPE_INTEGER;
strcpy(c->name, "Agc");
c->minimum = 0;
c->maximum = 63;
c->step = 1;
c->default_value = 48;
c->flags = 0;
break;
case V4L2_CID_SHARPNESS:
c->type = V4L2_CTRL_TYPE_INTEGER;
strcpy(c->name, "Sharpness");
c->minimum = 0;
c->maximum = 63;
c->step = 1;
c->default_value = 32;
c->flags = 0;
break;
case V4L2_CID_PICTURE:
c->type = V4L2_CTRL_TYPE_INTEGER;
strcpy(c->name, "Picture");
c->minimum = 0;
c->maximum = 63;
c->step = 1;
c->default_value = 0;
c->flags = 0;
break;
case V4L2_CID_JPEGQUAL:
c->type = V4L2_CTRL_TYPE_INTEGER;
strcpy(c->name, "JPEG quality");
c->minimum = 0;
c->maximum = 10;
c->step = 1;
c->default_value = 8;
c->flags = 0;
break;
case V4L2_CID_FRAMERATE:
c->type = V4L2_CTRL_TYPE_INTEGER;
strcpy(c->name, "Framerate");
c->minimum = 0;
c->maximum = 31;
c->step = 1;
c->default_value = 0;
c->flags = 0;
break;
default:
return -EINVAL;
}
break;
}
case VIDIOC_S_CTRL: {
struct v4l2_control *c = arg;
down(&meye.lock);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
sonypi_camera_command(
SONYPI_COMMAND_SETCAMERABRIGHTNESS, c->value);
break;
case V4L2_CID_HUE:
sonypi_camera_command(
SONYPI_COMMAND_SETCAMERAHUE, c->value);
break;
case V4L2_CID_CONTRAST:
sonypi_camera_command(
SONYPI_COMMAND_SETCAMERACOLOR, c->value);
break;
case V4L2_CID_SATURATION:
sonypi_camera_command(
SONYPI_COMMAND_SETCAMERACOLOR, c->value);
break;
case V4L2_CID_AGC:
sonypi_camera_command(
SONYPI_COMMAND_SETCAMERAAGC, c->value);
break;
case V4L2_CID_SHARPNESS:
sonypi_camera_command(
SONYPI_COMMAND_SETCAMERASHARPNESS, c->value);
break;
case V4L2_CID_PICTURE:
sonypi_camera_command(
SONYPI_COMMAND_SETCAMERAPICTURE, c->value);
break;
case V4L2_CID_JPEGQUAL:
meye.params.quality = c->value;
break;
case V4L2_CID_FRAMERATE:
meye.params.framerate = c->value;
break;
default: default:
return -ENOIOCTLCMD; up(&meye.lock);
return -EINVAL;
}
up(&meye.lock);
break;
}
case VIDIOC_G_CTRL: {
struct v4l2_control *c = arg;
down(&meye.lock);
switch (c->id) {
case V4L2_CID_BRIGHTNESS:
c->value = sonypi_camera_command(
SONYPI_COMMAND_GETCAMERABRIGHTNESS, 0);
break;
case V4L2_CID_HUE:
c->value = sonypi_camera_command(
SONYPI_COMMAND_GETCAMERAHUE, 0);
break;
case V4L2_CID_CONTRAST:
c->value = sonypi_camera_command(
SONYPI_COMMAND_GETCAMERACOLOR, 0);
break;
case V4L2_CID_SATURATION:
c->value = sonypi_camera_command(
SONYPI_COMMAND_GETCAMERACOLOR, 0);
break;
case V4L2_CID_AGC:
c->value = sonypi_camera_command(
SONYPI_COMMAND_GETCAMERAAGC, 0);
break;
case V4L2_CID_SHARPNESS:
c->value = sonypi_camera_command(
SONYPI_COMMAND_GETCAMERASHARPNESS, 0);
break;
case V4L2_CID_PICTURE:
c->value = sonypi_camera_command(
SONYPI_COMMAND_GETCAMERAPICTURE, 0);
break;
case V4L2_CID_JPEGQUAL:
c->value = meye.params.quality;
break;
case V4L2_CID_FRAMERATE:
c->value = meye.params.framerate;
break;
default:
up(&meye.lock);
return -EINVAL;
}
up(&meye.lock);
break;
}
case VIDIOC_ENUM_FMT: {
struct v4l2_fmtdesc *f = arg;
if (f->index > 1)
return -EINVAL;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (f->index == 0) {
/* standard YUV 422 capture */
memset(f, 0, sizeof(*f));
f->index = 0;
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->flags = 0;
strcpy(f->description, "YUV422");
f->pixelformat = V4L2_PIX_FMT_YUYV;
} else {
/* compressed MJPEG capture */
memset(f, 0, sizeof(*f));
f->index = 1;
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
f->flags = V4L2_FMT_FLAG_COMPRESSED;
strcpy(f->description, "MJPEG");
f->pixelformat = V4L2_PIX_FMT_MJPEG;
}
break;
}
case VIDIOC_TRY_FMT: {
struct v4l2_format *f = arg;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
return -EINVAL;
if (f->fmt.pix.field != V4L2_FIELD_ANY &&
f->fmt.pix.field != V4L2_FIELD_NONE)
return -EINVAL;
f->fmt.pix.field = V4L2_FIELD_NONE;
if (f->fmt.pix.width <= 320) {
f->fmt.pix.width = 320;
f->fmt.pix.height = 240;
} else {
f->fmt.pix.width = 640;
f->fmt.pix.height = 480;
}
f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
f->fmt.pix.sizeimage = f->fmt.pix.height *
f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
f->fmt.pix.priv = 0;
break;
}
case VIDIOC_G_FMT: {
struct v4l2_format *f = arg;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
switch (meye.mchip_mode) {
case MCHIP_HIC_MODE_CONT_OUT:
default:
f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
break;
case MCHIP_HIC_MODE_CONT_COMP:
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
break;
}
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.width = mchip_hsize();
f->fmt.pix.height = mchip_vsize();
f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
f->fmt.pix.sizeimage = f->fmt.pix.height *
f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
f->fmt.pix.priv = 0;
break;
}
case VIDIOC_S_FMT: {
struct v4l2_format *f = arg;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
return -EINVAL;
if (f->fmt.pix.field != V4L2_FIELD_ANY &&
f->fmt.pix.field != V4L2_FIELD_NONE)
return -EINVAL;
f->fmt.pix.field = V4L2_FIELD_NONE;
down(&meye.lock);
if (f->fmt.pix.width <= 320) {
f->fmt.pix.width = 320;
f->fmt.pix.height = 240;
meye.params.subsample = 1;
} else {
f->fmt.pix.width = 640;
f->fmt.pix.height = 480;
meye.params.subsample = 0;
}
switch (f->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_YUYV:
meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT;
break;
case V4L2_PIX_FMT_MJPEG:
meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP;
break;
}
up(&meye.lock);
f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
f->fmt.pix.sizeimage = f->fmt.pix.height *
f->fmt.pix.bytesperline;
f->fmt.pix.colorspace = 0;
f->fmt.pix.priv = 0;
break;
}
case VIDIOC_REQBUFS: {
struct v4l2_requestbuffers *req = arg;
int i;
if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (req->memory != V4L2_MEMORY_MMAP)
return -EINVAL;
if (meye.grab_fbuffer && req->count == gbuffers) {
/* already allocated, no modifications */
break;
}
down(&meye.lock);
if (meye.grab_fbuffer) {
for (i = 0; i < gbuffers; i++)
if (meye.vma_use_count[i]) {
up(&meye.lock);
return -EINVAL;
}
rvfree(meye.grab_fbuffer, gbuffers * gbufsize);
meye.grab_fbuffer = NULL;
}
gbuffers = max(2, min((int)req->count, MEYE_MAX_BUFNBRS));
req->count = gbuffers;
meye.grab_fbuffer = rvmalloc(gbuffers * gbufsize);
if (!meye.grab_fbuffer) {
printk(KERN_ERR "meye: v4l framebuffer allocation"
" failed\n");
up(&meye.lock);
return -ENOMEM;
}
for (i = 0; i < gbuffers; i++)
meye.vma_use_count[i] = 0;
up(&meye.lock);
break;
}
case VIDIOC_QUERYBUF: {
struct v4l2_buffer *buf = arg;
int index = buf->index;
if (index < 0 || index >= gbuffers)
return -EINVAL;
memset(buf, 0, sizeof(*buf));
buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf->index = index;
buf->bytesused = meye.grab_buffer[index].size;
buf->flags = V4L2_BUF_FLAG_MAPPED;
if (meye.grab_buffer[index].state == MEYE_BUF_USING)
buf->flags |= V4L2_BUF_FLAG_QUEUED;
if (meye.grab_buffer[index].state == MEYE_BUF_DONE)
buf->flags |= V4L2_BUF_FLAG_DONE;
buf->field = V4L2_FIELD_NONE;
buf->timestamp = meye.grab_buffer[index].timestamp;
buf->sequence = meye.grab_buffer[index].sequence;
buf->memory = V4L2_MEMORY_MMAP;
buf->m.offset = index * gbufsize;
buf->length = gbufsize;
break;
}
case VIDIOC_QBUF: {
struct v4l2_buffer *buf = arg;
if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (buf->memory != V4L2_MEMORY_MMAP)
return -EINVAL;
if (buf->index < 0 || buf->index >= gbuffers)
return -EINVAL;
if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED)
return -EINVAL;
down(&meye.lock);
buf->flags |= V4L2_BUF_FLAG_QUEUED;
buf->flags &= ~V4L2_BUF_FLAG_DONE;
meye.grab_buffer[buf->index].state = MEYE_BUF_USING;
kfifo_put(meye.grabq, (unsigned char *)&buf->index, sizeof(int));
up(&meye.lock);
break;
}
case VIDIOC_DQBUF: {
struct v4l2_buffer *buf = arg;
int reqnr;
if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
if (buf->memory != V4L2_MEMORY_MMAP)
return -EINVAL;
down(&meye.lock);
if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) {
up(&meye.lock);
return -EAGAIN;
}
if (wait_event_interruptible(meye.proc_list,
kfifo_len(meye.doneq) != 0) < 0) {
up(&meye.lock);
return -EINTR;
}
if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr,
sizeof(int))) {
up(&meye.lock);
return -EBUSY;
}
if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) {
up(&meye.lock);
return -EINVAL;
}
buf->index = reqnr;
buf->bytesused = meye.grab_buffer[reqnr].size;
buf->flags = V4L2_BUF_FLAG_MAPPED;
buf->field = V4L2_FIELD_NONE;
buf->timestamp = meye.grab_buffer[reqnr].timestamp;
buf->sequence = meye.grab_buffer[reqnr].sequence;
buf->memory = V4L2_MEMORY_MMAP;
buf->m.offset = reqnr * gbufsize;
buf->length = gbufsize;
meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED;
up(&meye.lock);
break;
}
case VIDIOC_STREAMON: {
down(&meye.lock);
switch (meye.mchip_mode) {
case MCHIP_HIC_MODE_CONT_OUT:
mchip_continuous_start();
break;
case MCHIP_HIC_MODE_CONT_COMP:
mchip_cont_compression_start();
break;
default:
up(&meye.lock);
return -EINVAL;
}
up(&meye.lock);
break;
}
case VIDIOC_STREAMOFF: {
int i;
} /* switch */ down(&meye.lock);
mchip_hic_stop();
kfifo_reset(meye.grabq);
kfifo_reset(meye.doneq);
for (i = 0; i < MEYE_MAX_BUFNBRS; i++)
meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
up(&meye.lock);
break;
}
/*
* XXX what about private snapshot ioctls ?
* Do they need to be converted to V4L2 ?
*/
default:
return -ENOIOCTLCMD;
}
return 0; return 0;
} }
...@@ -1158,9 +1678,27 @@ static unsigned int meye_poll(struct file *file, poll_table *wait) ...@@ -1158,9 +1678,27 @@ static unsigned int meye_poll(struct file *file, poll_table *wait)
return res; return res;
} }
static void meye_vm_open(struct vm_area_struct *vma)
{
int idx = (int)vma->vm_private_data;
meye.vma_use_count[idx]++;
}
static void meye_vm_close(struct vm_area_struct *vma)
{
int idx = (int)vma->vm_private_data;
meye.vma_use_count[idx]--;
}
static struct vm_operations_struct meye_vm_ops = {
.open = meye_vm_open,
.close = meye_vm_close,
};
static int meye_mmap(struct file *file, struct vm_area_struct *vma) { static int meye_mmap(struct file *file, struct vm_area_struct *vma) {
unsigned long start = vma->vm_start; unsigned long start = vma->vm_start;
unsigned long size = vma->vm_end - vma->vm_start; unsigned long size = vma->vm_end - vma->vm_start;
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
unsigned long page, pos; unsigned long page, pos;
down(&meye.lock); down(&meye.lock);
...@@ -1169,6 +1707,8 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma) { ...@@ -1169,6 +1707,8 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma) {
return -EINVAL; return -EINVAL;
} }
if (!meye.grab_fbuffer) { if (!meye.grab_fbuffer) {
int i;
/* lazy allocation */ /* lazy allocation */
meye.grab_fbuffer = rvmalloc(gbuffers*gbufsize); meye.grab_fbuffer = rvmalloc(gbuffers*gbufsize);
if (!meye.grab_fbuffer) { if (!meye.grab_fbuffer) {
...@@ -1176,8 +1716,10 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma) { ...@@ -1176,8 +1716,10 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma) {
up(&meye.lock); up(&meye.lock);
return -ENOMEM; return -ENOMEM;
} }
for (i = 0; i < gbuffers; i++)
meye.vma_use_count[i] = 0;
} }
pos = (unsigned long)meye.grab_fbuffer; pos = (unsigned long)meye.grab_fbuffer + offset;
while (size > 0) { while (size > 0) {
page = vmalloc_to_pfn((void *)pos); page = vmalloc_to_pfn((void *)pos);
...@@ -1187,8 +1729,18 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma) { ...@@ -1187,8 +1729,18 @@ static int meye_mmap(struct file *file, struct vm_area_struct *vma) {
} }
start += PAGE_SIZE; start += PAGE_SIZE;
pos += PAGE_SIZE; pos += PAGE_SIZE;
if (size > PAGE_SIZE)
size -= PAGE_SIZE; size -= PAGE_SIZE;
else
size = 0;
} }
vma->vm_ops = &meye_vm_ops;
vma->vm_flags &= ~VM_IO; /* not I/O memory */
vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
vma->vm_private_data = (void *) (offset / gbufsize);
meye_vm_open(vma);
up(&meye.lock); up(&meye.lock);
return 0; return 0;
} }
......
...@@ -279,6 +279,8 @@ ...@@ -279,6 +279,8 @@
struct meye_grab_buffer { struct meye_grab_buffer {
int state; /* state of buffer */ int state; /* state of buffer */
unsigned long size; /* size of jpg frame */ unsigned long size; /* size of jpg frame */
struct timeval timestamp; /* timestamp */
unsigned long sequence; /* sequence number */
}; };
/* size of kfifos containings buffer indices */ /* size of kfifos containings buffer indices */
...@@ -302,6 +304,7 @@ struct meye { ...@@ -302,6 +304,7 @@ struct meye {
unsigned char *grab_temp; /* temporary buffer */ unsigned char *grab_temp; /* temporary buffer */
/* list of buffers */ /* list of buffers */
struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS]; struct meye_grab_buffer grab_buffer[MEYE_MAX_BUFNBRS];
int vma_use_count[MEYE_MAX_BUFNBRS]; /* mmap count */
/* other */ /* other */
struct semaphore lock; /* semaphore for open/mmap... */ struct semaphore lock; /* semaphore for open/mmap... */
......
...@@ -56,4 +56,11 @@ struct meye_params { ...@@ -56,4 +56,11 @@ struct meye_params {
/* get a jpeg compressed snapshot */ /* get a jpeg compressed snapshot */
#define MEYEIOC_STILLJCAPT _IOR ('v', BASE_VIDIOCPRIVATE+5, int) #define MEYEIOC_STILLJCAPT _IOR ('v', BASE_VIDIOCPRIVATE+5, int)
/* V4L2 private controls */
#define V4L2_CID_AGC V4L2_CID_PRIVATE_BASE
#define V4L2_CID_SHARPNESS (V4L2_CID_PRIVATE_BASE + 1)
#define V4L2_CID_PICTURE (V4L2_CID_PRIVATE_BASE + 2)
#define V4L2_CID_JPEGQUAL (V4L2_CID_PRIVATE_BASE + 3)
#define V4L2_CID_FRAMERATE (V4L2_CID_PRIVATE_BASE + 4)
#endif #endif
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