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);
}



_______________________________________________
Video4linux-list mailing list
[EMAIL PROTECTED]
https://listman.redhat.com/mailman/listinfo/video4linux-list

Reply via email to