From 8d41b006f083b1395fa5e67dbeeda44704c1686d Mon Sep 17 00:00:00 2001 From: Ching-Yun Liang Date: Wed, 18 Jun 2025 01:49:45 +0800 Subject: [PATCH 1/3] Support DMA-BUF memory type in buffer queue - Added VB2_DMABUF to vb2_queue.io_modes - Set mem_ops to vb2_dma_contig_memops for physically contiguous memory - Implemented buf_init() and buf_cleanup() to manage per-buffer state --- videobuf.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/videobuf.c b/videobuf.c index 9a38c57..56f422d 100644 --- a/videobuf.c +++ b/videobuf.c @@ -3,7 +3,7 @@ #include #include #include -#include +#include #include "videobuf.h" @@ -114,6 +114,23 @@ static void vcam_outbuf_unlock(struct vb2_queue *vq) mutex_unlock(&dev->vcam_mutex); } +static int vcam_buf_init(struct vb2_buffer *vb) +{ + struct vcam_out_buffer *buf = + container_of(vb, struct vcam_out_buffer, vb.vb2_buf); + + buf->filled = 0; + INIT_LIST_HEAD(&buf->list); + + pr_debug("vcam_buf_init: buffer initialized\n"); + return 0; +} + +static void vcam_buf_cleanup(struct vb2_buffer *vb) +{ + pr_debug("vcam_buf_cleanup called\n"); +} + static const struct vb2_ops vcam_vb2_ops = { .queue_setup = vcam_out_queue_setup, .buf_prepare = vcam_out_buffer_prepare, @@ -122,6 +139,8 @@ static const struct vb2_ops vcam_vb2_ops = { .stop_streaming = vcam_stop_streaming, .wait_prepare = vcam_outbuf_unlock, .wait_finish = vcam_outbuf_lock, + .buf_init = vcam_buf_init, + .buf_cleanup = vcam_buf_cleanup, }; int vcam_out_videobuf2_setup(struct vcam_device *dev) @@ -129,12 +148,12 @@ int vcam_out_videobuf2_setup(struct vcam_device *dev) struct vb2_queue *q = &dev->vb_out_vidq; q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ; + q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | VB2_DMABUF; q->drv_priv = dev; q->buf_struct_size = sizeof(struct vcam_out_buffer); q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->ops = &vcam_vb2_ops; - q->mem_ops = &vb2_vmalloc_memops; + q->mem_ops = &vb2_dma_contig_memops; #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 8, 0) q->min_queued_buffers = 2; #else From 599a2f997ba622952abaf107bd6d56827ebe3048 Mon Sep 17 00:00:00 2001 From: Ching-Yun Liang Date: Sat, 19 Jul 2025 17:13:36 +0800 Subject: [PATCH 2/3] Add support for selecting memory type (MMAP or DMABUF) Enable configuring vcam device memory type via user-space tool and driver. Users can now specify whether to use MMAP or DMABUF for buffer management. --- README.md | 4 ++-- control.c | 2 ++ device.h | 3 +++ vcam-util.c | 41 ++++++++++++++++++++++++++++++++++------- vcam.h | 2 ++ videobuf.c | 11 ++++++++++- 6 files changed, 53 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 0d203db..3533e55 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ After running `make`, you should be able to generate the following files: Before loading this kernel module, you have to satisfy its dependency: ```shell -$ sudo modprobe -a videobuf2_vmalloc videobuf2_v4l2 +$ sudo modprobe -a videobuf2_vmalloc videobuf2_v4l2 videobuf2-dma-contig ``` The module can be loaded to Linux kernel by runnning the command: @@ -56,7 +56,7 @@ $ sudo ./vcam-util -l You should get: ``` Available virtual V4L2 compatible devices: -1. fbX(640,480,rgb24) -> /dev/video0 +1. fbX(640,480,rgb24,mmap) -> /dev/video0 ``` You can use this command to check if the driver is ok: diff --git a/control.c b/control.c index e840035..d9f6abf 100644 --- a/control.c +++ b/control.c @@ -73,6 +73,7 @@ static int control_iocontrol_get_device(struct vcam_device_spec *dev_spec) dev_spec->width = dev->fb_spec.xres_virtual; dev_spec->height = dev->fb_spec.yres_virtual; dev_spec->pix_fmt = dev->fb_spec.pix_fmt; + dev_spec->mem_type = dev->fb_spec.mem_type; dev_spec->cropratio = dev->fb_spec.cropratio; strncpy((char *) &dev_spec->fb_node, (const char *) vcamfb_get_devnode(dev), @@ -174,6 +175,7 @@ static struct vcam_device_spec default_vcam_spec = { .height = 480, .cropratio = {.numerator = 3, .denominator = 4}, .pix_fmt = VCAM_PIXFMT_RGB24, + .mem_type = VCAM_MEMORY_MMAP, }; int request_vcam_device(struct vcam_device_spec *dev_spec) diff --git a/device.h b/device.h index 5d85001..0b3a45c 100644 --- a/device.h +++ b/device.h @@ -89,6 +89,9 @@ struct vcam_device { struct v4l2_pix_format output_format; struct v4l2_pix_format input_format; + /* Memory type */ + memtype_t mem_type; + /* Conversion switches */ bool conv_pixfmt_on; bool conv_res_on; diff --git a/vcam-util.c b/vcam-util.c index 090832e..1ae86d3 100644 --- a/vcam-util.c +++ b/vcam-util.c @@ -10,14 +10,14 @@ #include "vcam.h" -static const char *short_options = "hcm:r:ls:p:d:"; +static const char *short_options = "hcm:r:ls:p:d:t:"; const struct option long_options[] = { - {"help", 0, NULL, 'h'}, {"create", 0, NULL, 'c'}, - {"modify", 1, NULL, 'm'}, {"list", 0, NULL, 'l'}, - {"size", 1, NULL, 's'}, {"pixfmt", 1, NULL, 'p'}, - {"device", 1, NULL, 'd'}, {"remove", 1, NULL, 'r'}, - {NULL, 0, NULL, 0}}; + {"help", 0, NULL, 'h'}, {"create", 0, NULL, 'c'}, + {"modify", 1, NULL, 'm'}, {"list", 0, NULL, 'l'}, + {"size", 1, NULL, 's'}, {"pixfmt", 1, NULL, 'p'}, + {"device", 1, NULL, 'd'}, {"remove", 1, NULL, 'r'}, + {"memtype", 1, NULL, 't'}, {NULL, 0, NULL, 0}}; const char *help = " -h --help Print this informations.\n" @@ -37,6 +37,7 @@ const char *help = "and apply with crop ratio.\n" "\n" " -p --pixfmt pix_fmt Specify pixel format (rgb24,yuyv).\n" + " -t --memtype mem_type Specify memory type (mmap,dmabuf).\n" " -d --device /dev/* Control device node.\n"; enum ACTION { ACTION_NONE, ACTION_CREATE, ACTION_DESTROY, ACTION_MODIFY }; @@ -45,6 +46,7 @@ struct vcam_device_spec device_template = { .width = 640, .height = 480, .pix_fmt = VCAM_PIXFMT_RGB24, + .mem_type = VCAM_MEMORY_MMAP, .video_node = "", .fb_node = "", }; @@ -102,6 +104,14 @@ int determine_pixfmt(char *pixfmt_str) return -1; } +int determine_memtype(char *memtype_str) +{ + if (!strncmp(memtype_str, "mmap", 4)) + return VCAM_MEMORY_MMAP; + if (!strncmp(memtype_str, "dmabuf", 6)) + return VCAM_MEMORY_DMABUF; + return -1; +} int create_device(struct vcam_device_spec *dev) { int fd = open(ctl_path, O_RDWR); @@ -118,6 +128,9 @@ int create_device(struct vcam_device_spec *dev) if (!dev->pix_fmt) dev->pix_fmt = device_template.pix_fmt; + if (!dev->mem_type) + dev->mem_type = device_template.mem_type; + int res = ioctl(fd, VCAM_IOCTL_CREATE_DEVICE, dev); if (res) { fprintf(stderr, "Failed to create a new device.\n"); @@ -170,6 +183,9 @@ int modify_device(struct vcam_device_spec *dev) if (!dev->pix_fmt) dev->pix_fmt = orig_dev.pix_fmt; + if (!dev->mem_type) + dev->mem_type = orig_dev.mem_type; + if (!dev->cropratio.numerator || !dev->cropratio.denominator) dev->cropratio = orig_dev.cropratio; @@ -195,10 +211,11 @@ int list_devices() printf("Available virtual V4L2 compatible devices:\n"); while (!ioctl(fd, VCAM_IOCTL_GET_DEVICE, &dev)) { dev.idx++; - printf("%d. %s(%d,%d,%d/%d,%s) -> %s\n", dev.idx, dev.fb_node, + printf("%d. %s(%d,%d,%d/%d,%s,%s) -> %s\n", dev.idx, dev.fb_node, dev.width, dev.height, dev.cropratio.numerator, dev.cropratio.denominator, dev.pix_fmt == VCAM_PIXFMT_RGB24 ? "rgb24" : "yuyv", + dev.mem_type == VCAM_MEMORY_MMAP ? "mmap" : "dmabuf", dev.video_node); } close(fd); @@ -258,6 +275,16 @@ int main(int argc, char *argv[]) dev.pix_fmt = (char) tmp; printf("Setting pixel format to %s.\n", optarg); break; + case 't': + tmp = determine_memtype(optarg); + if (tmp < 0) { + fprintf(stderr, "Failed to recognize memory type %s.\n", + optarg); + exit(-1); + } + dev.mem_type = (char) tmp; + printf("Setting memory type to %s.\n", optarg); + break; case 'd': printf("Using device %s.\n", optarg); strncpy(ctl_path, optarg, sizeof(ctl_path) - 1); diff --git a/vcam.h b/vcam.h index c0506c2..dadc06b 100644 --- a/vcam.h +++ b/vcam.h @@ -10,6 +10,7 @@ #define VCAM_IOCTL_MODIFY_SETTING 0x555 typedef enum { VCAM_PIXFMT_RGB24 = 0x01, VCAM_PIXFMT_YUYV = 0x02 } pixfmt_t; +typedef enum { VCAM_MEMORY_MMAP = 0, VCAM_MEMORY_DMABUF = 2 } memtype_t; struct crop_ratio { __u32 numerator; @@ -27,6 +28,7 @@ struct vcam_device_spec { struct crop_ratio cropratio; pixfmt_t pix_fmt; + memtype_t mem_type; char video_node[64]; char fb_node[64]; }; diff --git a/videobuf.c b/videobuf.c index 56f422d..dd5298a 100644 --- a/videobuf.c +++ b/videobuf.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "videobuf.h" @@ -153,7 +154,15 @@ int vcam_out_videobuf2_setup(struct vcam_device *dev) q->buf_struct_size = sizeof(struct vcam_out_buffer); q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; q->ops = &vcam_vb2_ops; - q->mem_ops = &vb2_dma_contig_memops; + pr_info("memory type %d\n", dev->mem_type); + switch (dev->mem_type) { + case VCAM_MEMORY_MMAP: + q->mem_ops = &vb2_vmalloc_memops; + break; + case VCAM_MEMORY_DMABUF: + q->mem_ops = &vb2_dma_contig_memops; + break; + } #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 8, 0) q->min_queued_buffers = 2; #else From a3c7c7bae6da84ac9b9f158cf6bd2e19d323e46e Mon Sep 17 00:00:00 2001 From: Ching-Yun Liang Date: Wed, 23 Jul 2025 00:15:19 +0800 Subject: [PATCH 3/3] Add README section for DMA-BUF support Briefly describe DMA-BUF's purpose for cross-device buffer sharing. --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 3533e55..ef41b9b 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,12 @@ Available virtual V4L2 compatible devices: 1. fbX(640,480,rgb24,mmap) -> /dev/video0 ``` +The default memory type is MMAP. You can switch to DMA-BUF using the `-t` option, for example: +```shell +$ sudo ./vcam-util -c -t dmabuf +``` +The DMA-BUF framework provides a unified way to share buffers across multiple devices. + You can use this command to check if the driver is ok: ```shell $ sudo v4l2-compliance -d /dev/videoX -f