Re: v4l2 + kernel

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]



mmap()ing again ...

I've looked around in kernel and bttv2 code while looking for a nice
way to handle v4l2 mappings in bttv.  Using page offsets as magic
cookie isn't a good idea.  The VM will take the offset as real offset
and calculates a new value for it if a application does a partial
unmap().  Which in turn can lead to *ahem* intresting effects like
this one:

bttv0: Granting 4 buffers.
bttv0: vma_close called on buffer 1 (refcount -1)

IHMO there is no way around using the offset as normal offset:
Drivers should make sure that the mappings do not overlap, i.e.
buf[n].offset + buf[n].size <= buf[n+1].offset

There is also vma->vm_private_data which can be used by the drivers
to keep track of the mappings.

  Gerd

--------- [ mmap.c ] -----------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/videodev.h>

#define BUFS 4

struct v4l2_format fmt = {
	type:	V4L2_BUF_TYPE_CAPTURE,
	fmt:	{
		pix:	{
			width:	320,
			height:	240,
			depth:	32,
			pixelformat: V4L2_PIX_FMT_BGR32
		},
	},
};
struct v4l2_requestbuffers req = {
	count:	BUFS,
	type:	V4L2_BUF_TYPE_CAPTURE,
};

struct v4l2_buffer bufs[BUFS];

int
main()
{
	unsigned char *map;
	int	fd,i;

	fd = open("/dev/video0",O_RDWR);
	if (-1 == fd) {
		perror("open /dev/video0");
		exit(1);
	}

	if (-1 == ioctl(fd,VIDIOC_S_FMT,&fmt)) {
		perror("ioctl VIDIOC_S_FMT");
		exit(1);
	}
	if (-1 == ioctl(fd,VIDIOC_REQBUFS,&req)) {
		perror("ioctl VIDIOC_REQBUFS");
		exit(1);
	}
	for (i = 0; i < BUFS; i++) {
		bufs[i].index = i;
		bufs[i].type  = V4L2_BUF_TYPE_CAPTURE;
		if (-1 == ioctl(fd,VIDIOC_QUERYBUF,&bufs[i])) {
			perror("ioctl VIDIOC_QUERYBUF");
			exit(1);
		}
		fprintf(stderr,"%d: offset=0x%x length=%d\n",
			i,bufs[i].offset,bufs[i].length);
	}

	fprintf(stderr,"mmap\n");
	map = mmap(NULL, bufs[0].length, PROT_READ | PROT_WRITE, MAP_SHARED,
		   fd, bufs[0].offset);
	if (-1 == (int)map) {
		perror("mmap");
		exit(1);
	}

	fprintf(stderr,"munmap\n");
	if (-1 == munmap(map, (bufs[1].offset - bufs[0].offset))) {
		perror("munmap");
		exit(1);
	}

	fprintf(stderr,"done\n");
	exit(0);
}





[Index of Archives]     [Linux DVB]     [Video Disk Recorder]     [Asterisk]     [Photo]     [DCCP]     [Netdev]     [Xorg]     [Util Linux NG]     [Xfree86]     [Free Photo Albums]     [Fedora Users]     [Fedora Women]     [ALSA Users]     [ALSA Devel]     [Linux USB]

Powered by Linux