updated dma to user space API
Brought to you by:
aeb,
bencollins
From: Sebastien R. <Seb...@sy...> - 2000-04-25 10:21:41
|
I have updated the API for the direct iso dma to user space feature that is available for the ohci driver. Previously the buffer filling was running continuously in the driver, and the user app was only waiting for irq generated for each frame. The problem was doing so you could easily create synchronization problems. Now the user app has to queue the buffers for each frame. If the user app can not keep up with the framerate, the dma context will wait until fresh buffers are queued. It is very similar to the video4linux API. The driver has been tested with 1-2 cameras on the bus, each delivering uncompressed 640x480 YUV422 30Hz video. Works well so far (at least the display is nice). NOTE 1: the driver is probably not safe for SMP machines (will do that later). It might also not be wise to share the device /dev/ohci1394 between several threads/processes. NOTE 2: you still have to enable this feature in ohci1394.h. It seems quite stable now, but I want to wait for some comment/bug reports before enabling it by default. The user app now looks like this: main() { int fd; struct video1394_mmap v; struct video1394_wait w; char *map; v.channel = 0; /* the iso channel you want to listen to */ v.sync_tag = 1; /* the tag in the iso packet for frame sync */ v.nb_buffers = 4; /* the number of buffers you want */ v.buf_size = 320*240*2; /* the size in bytes of one frame */ /* open the driver */ fd = open("/dev/ohci1394",O_RDWR); /* launch the iso context that will do the dma transfer * !!! NOTE: the field v.buf_size is modified by this call !!! * !!! it is rounded up to a multiple of PAGE_SIZE !!! */ if (ioctl(fd, VIDEO1394_LISTEN_CHANNEL, &v)<0) { perror("VIDEO1394_LISTEN_CHANNEL"); } /* map the dma buffer into user space */ if ((map = (char *) mmap(0,v.nb_buffers*v.buf_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd,0)) == (char *)-1) { perror("mmap"); return -1; } w.channel = v.channel; /* queue the buffers for frame acquisition */ for (i=0;i<v.nb_buffers;i++) { w.buffer=i; if (ioctl(fd,VIDEO1394_QUEUE_BUFFER,&w)==-1) { perror("VIDEO1394_QUEUE_BUFFER"); return -1; } /* here you do the camera initialization, start iso transmission */ ........ /* */ w.buffer=0; while(cond) { /* wait for the next frame */ ioctl(fd, VIDEO1394_WAIT_BUFFER, &w); /* put the buffer again in the queue */ ioctl(fd,VIDEO1394_QUEUE_BUFFER, &w); /* the image buffer starts at map+w.buffer*v.buf_size, * and has for length the frame size specified at the * beginning of the program. Here you do whatever you * want with it */ ....... w.buffer = (w.buffer+1)%v.nb_buffers; } /* here you stop iso transmission */ ........ /* */ /* unmap the memory */ if (map!=(char*)-1) munmap(map,v.nb_buffers*v.buf_size); /* deallocate the iso context */ if (ioctl(fd, VIDEO1394_UNLISTEN_CHANNEL, &v.channel)<0) { perror("VIDEO1394_UNLISTEN_CHANNEL"); } /* close the device */ close(fd); } |