From a8ed8c04c119e5a323a2c79fcd0d28b4d29fc28a Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 23 Apr 2015 22:56:09 -0300 Subject: [PATCH] v4l2: use REQBUFS properly There are two issues on this driver with regards to buffer request: 1) it is not calling VIDIOC_REQBUFS for USERPTR; 2) It is calling VIDIOC_REQBUFS at probe, to check the max number of supported buffers, but it doesn't deallocate the buffers at the end of the probe function. Fix those issues. Also, improve the error/warning messages associated with possible problems. This is based on the issues detected by the patch proposed to fix this bug: https://bugs.archlinux.org/task/44091 Signed-off-by: Mauro Carvalho Chehab diff --git a/zbar/video/v4l2.c b/zbar/video/v4l2.c index aabd16643ddc..f6662d3707f9 100644 --- a/zbar/video/v4l2.c +++ b/zbar/video/v4l2.c @@ -201,21 +201,6 @@ static int v4l2_cleanup (zbar_video_t *vdo) static int v4l2_mmap_buffers (zbar_video_t *vdo) { - struct v4l2_requestbuffers rb; - memset(&rb, 0, sizeof(rb)); - rb.count = vdo->num_images; - rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - rb.memory = V4L2_MEMORY_MMAP; - if(v4l2_ioctl(vdo->fd, VIDIOC_REQBUFS, &rb) < 0) - return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_SYSTEM, __func__, - "requesting video frame buffers (VIDIOC_REQBUFS)")); - zprintf(1, "mapping %u buffers (of %d requested)\n", - rb.count, vdo->num_images); - if(!rb.count) - return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_INVALID, __func__, - "driver returned 0 buffers")); - if(vdo->num_images > rb.count) - vdo->num_images = rb.count; struct v4l2_buffer vbuf; memset(&vbuf, 0, sizeof(vbuf)); @@ -313,8 +298,32 @@ static int v4l2_set_format (zbar_video_t *vdo, static int v4l2_init (zbar_video_t *vdo, uint32_t fmt) { + struct v4l2_requestbuffers rb; if(v4l2_set_format(vdo, fmt)) return(-1); + + memset(&rb, 0, sizeof(rb)); + rb.count = vdo->num_images; + rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + if(vdo->iomode == VIDEO_MMAP) + rb.memory = V4L2_MEMORY_MMAP; + else + rb.memory = V4L2_MEMORY_USERPTR; + + if(v4l2_ioctl(vdo->fd, VIDIOC_REQBUFS, &rb) < 0) + return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_SYSTEM, __func__, + "requesting video frame buffers (VIDIOC_REQBUFS)")); + + if(!rb.count) + return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_INVALID, __func__, + "driver returned 0 buffers")); + + if(vdo->num_images > rb.count) + vdo->num_images = rb.count; + + zprintf(1, "using %u buffers (of %d requested)\n", + rb.count, vdo->num_images); + if(vdo->iomode == VIDEO_MMAP) return(v4l2_mmap_buffers(vdo)); return(0); @@ -324,7 +333,7 @@ static int v4l2_probe_iomode (zbar_video_t *vdo) { struct v4l2_requestbuffers rb; memset(&rb, 0, sizeof(rb)); - rb.count = vdo->num_images; /* FIXME workaround broken drivers */ + rb.count = vdo->num_images; rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if(vdo->iomode == VIDEO_MMAP) rb.memory = V4L2_MEMORY_MMAP; @@ -340,14 +349,31 @@ static int v4l2_probe_iomode (zbar_video_t *vdo) return(err_capture(vdo, SEV_ERROR, ZBAR_ERR_SYSTEM, __func__, "querying streaming mode (VIDIOC_REQBUFS)")); #ifdef HAVE_SYS_MMAN_H + err_capture(vdo, SEV_WARNING, ZBAR_ERR_SYSTEM, __func__, + "USERPTR failed. Falling back to mmap"); vdo->iomode = VIDEO_MMAP; +#else + return err_capture(vdo, SEV_ERROR, ZBAR_ERR_SYSTEM, __func__, + "Userptr not supported, and zbar was compiled without mmap support")); #endif } else { if(!vdo->iomode) - vdo->iomode = VIDEO_USERPTR; + rb.memory = V4L2_MEMORY_USERPTR; + /* Update the num_images with the max supported by the driver */ if(rb.count) vdo->num_images = rb.count; + else + err_capture(vdo, SEV_WARNING, ZBAR_ERR_SYSTEM, __func__, + "Something is wrong: number of buffers returned by REQBUF is zero!"); + + /* requesting 0 buffers + * This cleans up the buffers allocated previously on probe + */ + rb.count = 0; + if(v4l2_ioctl(vdo->fd, VIDIOC_REQBUFS, &rb) < 0) + err_capture(vdo, SEV_WARNING, ZBAR_ERR_SYSTEM, __func__, + "releasing video frame buffers (VIDIOC_REQBUFS)"); } return(0); }