Skip to content

Commit e81d3ed

Browse files
authored
Merge pull request #41 from liangchingyun/dmabuf-support
Support DMA-BUF memory type in buffer queue
2 parents 4898750 + a3c7c7b commit e81d3ed

File tree

6 files changed

+79
-11
lines changed

6 files changed

+79
-11
lines changed

README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ After running `make`, you should be able to generate the following files:
2727

2828
Before loading this kernel module, you have to satisfy its dependency:
2929
```shell
30-
$ sudo modprobe -a videobuf2_vmalloc videobuf2_v4l2
30+
$ sudo modprobe -a videobuf2_vmalloc videobuf2_v4l2 videobuf2-dma-contig
3131
```
3232

3333
The module can be loaded to Linux kernel by runnning the command:
@@ -56,9 +56,15 @@ $ sudo ./vcam-util -l
5656
You should get:
5757
```
5858
Available virtual V4L2 compatible devices:
59-
1. fbX(640,480,rgb24) -> /dev/video0
59+
1. fbX(640,480,rgb24,mmap) -> /dev/video0
6060
```
6161

62+
The default memory type is MMAP. You can switch to DMA-BUF using the `-t` option, for example:
63+
```shell
64+
$ sudo ./vcam-util -c -t dmabuf
65+
```
66+
The DMA-BUF framework provides a unified way to share buffers across multiple devices.
67+
6268
You can use this command to check if the driver is ok:
6369
```shell
6470
$ sudo v4l2-compliance -d /dev/videoX -f

control.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ static int control_iocontrol_get_device(struct vcam_device_spec *dev_spec)
7373
dev_spec->width = dev->fb_spec.xres_virtual;
7474
dev_spec->height = dev->fb_spec.yres_virtual;
7575
dev_spec->pix_fmt = dev->fb_spec.pix_fmt;
76+
dev_spec->mem_type = dev->fb_spec.mem_type;
7677
dev_spec->cropratio = dev->fb_spec.cropratio;
7778

7879
strncpy((char *) &dev_spec->fb_node, (const char *) vcamfb_get_devnode(dev),
@@ -174,6 +175,7 @@ static struct vcam_device_spec default_vcam_spec = {
174175
.height = 480,
175176
.cropratio = {.numerator = 3, .denominator = 4},
176177
.pix_fmt = VCAM_PIXFMT_RGB24,
178+
.mem_type = VCAM_MEMORY_MMAP,
177179
};
178180

179181
int request_vcam_device(struct vcam_device_spec *dev_spec)

device.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,9 @@ struct vcam_device {
8989
struct v4l2_pix_format output_format;
9090
struct v4l2_pix_format input_format;
9191

92+
/* Memory type */
93+
memtype_t mem_type;
94+
9295
/* Conversion switches */
9396
bool conv_pixfmt_on;
9497
bool conv_res_on;

vcam-util.c

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@
1010

1111
#include "vcam.h"
1212

13-
static const char *short_options = "hcm:r:ls:p:d:";
13+
static const char *short_options = "hcm:r:ls:p:d:t:";
1414

1515
const struct option long_options[] = {
16-
{"help", 0, NULL, 'h'}, {"create", 0, NULL, 'c'},
17-
{"modify", 1, NULL, 'm'}, {"list", 0, NULL, 'l'},
18-
{"size", 1, NULL, 's'}, {"pixfmt", 1, NULL, 'p'},
19-
{"device", 1, NULL, 'd'}, {"remove", 1, NULL, 'r'},
20-
{NULL, 0, NULL, 0}};
16+
{"help", 0, NULL, 'h'}, {"create", 0, NULL, 'c'},
17+
{"modify", 1, NULL, 'm'}, {"list", 0, NULL, 'l'},
18+
{"size", 1, NULL, 's'}, {"pixfmt", 1, NULL, 'p'},
19+
{"device", 1, NULL, 'd'}, {"remove", 1, NULL, 'r'},
20+
{"memtype", 1, NULL, 't'}, {NULL, 0, NULL, 0}};
2121

2222
const char *help =
2323
" -h --help Print this informations.\n"
@@ -37,6 +37,7 @@ const char *help =
3737
"and apply with crop ratio.\n"
3838
"\n"
3939
" -p --pixfmt pix_fmt Specify pixel format (rgb24,yuyv).\n"
40+
" -t --memtype mem_type Specify memory type (mmap,dmabuf).\n"
4041
" -d --device /dev/* Control device node.\n";
4142

4243
enum ACTION { ACTION_NONE, ACTION_CREATE, ACTION_DESTROY, ACTION_MODIFY };
@@ -45,6 +46,7 @@ struct vcam_device_spec device_template = {
4546
.width = 640,
4647
.height = 480,
4748
.pix_fmt = VCAM_PIXFMT_RGB24,
49+
.mem_type = VCAM_MEMORY_MMAP,
4850
.video_node = "",
4951
.fb_node = "",
5052
};
@@ -102,6 +104,14 @@ int determine_pixfmt(char *pixfmt_str)
102104
return -1;
103105
}
104106

107+
int determine_memtype(char *memtype_str)
108+
{
109+
if (!strncmp(memtype_str, "mmap", 4))
110+
return VCAM_MEMORY_MMAP;
111+
if (!strncmp(memtype_str, "dmabuf", 6))
112+
return VCAM_MEMORY_DMABUF;
113+
return -1;
114+
}
105115
int create_device(struct vcam_device_spec *dev)
106116
{
107117
int fd = open(ctl_path, O_RDWR);
@@ -118,6 +128,9 @@ int create_device(struct vcam_device_spec *dev)
118128
if (!dev->pix_fmt)
119129
dev->pix_fmt = device_template.pix_fmt;
120130

131+
if (!dev->mem_type)
132+
dev->mem_type = device_template.mem_type;
133+
121134
int res = ioctl(fd, VCAM_IOCTL_CREATE_DEVICE, dev);
122135
if (res) {
123136
fprintf(stderr, "Failed to create a new device.\n");
@@ -170,6 +183,9 @@ int modify_device(struct vcam_device_spec *dev)
170183
if (!dev->pix_fmt)
171184
dev->pix_fmt = orig_dev.pix_fmt;
172185

186+
if (!dev->mem_type)
187+
dev->mem_type = orig_dev.mem_type;
188+
173189
if (!dev->cropratio.numerator || !dev->cropratio.denominator)
174190
dev->cropratio = orig_dev.cropratio;
175191

@@ -195,10 +211,11 @@ int list_devices()
195211
printf("Available virtual V4L2 compatible devices:\n");
196212
while (!ioctl(fd, VCAM_IOCTL_GET_DEVICE, &dev)) {
197213
dev.idx++;
198-
printf("%d. %s(%d,%d,%d/%d,%s) -> %s\n", dev.idx, dev.fb_node,
214+
printf("%d. %s(%d,%d,%d/%d,%s,%s) -> %s\n", dev.idx, dev.fb_node,
199215
dev.width, dev.height, dev.cropratio.numerator,
200216
dev.cropratio.denominator,
201217
dev.pix_fmt == VCAM_PIXFMT_RGB24 ? "rgb24" : "yuyv",
218+
dev.mem_type == VCAM_MEMORY_MMAP ? "mmap" : "dmabuf",
202219
dev.video_node);
203220
}
204221
close(fd);
@@ -258,6 +275,16 @@ int main(int argc, char *argv[])
258275
dev.pix_fmt = (char) tmp;
259276
printf("Setting pixel format to %s.\n", optarg);
260277
break;
278+
case 't':
279+
tmp = determine_memtype(optarg);
280+
if (tmp < 0) {
281+
fprintf(stderr, "Failed to recognize memory type %s.\n",
282+
optarg);
283+
exit(-1);
284+
}
285+
dev.mem_type = (char) tmp;
286+
printf("Setting memory type to %s.\n", optarg);
287+
break;
261288
case 'd':
262289
printf("Using device %s.\n", optarg);
263290
strncpy(ctl_path, optarg, sizeof(ctl_path) - 1);

vcam.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define VCAM_IOCTL_MODIFY_SETTING 0x555
1111

1212
typedef enum { VCAM_PIXFMT_RGB24 = 0x01, VCAM_PIXFMT_YUYV = 0x02 } pixfmt_t;
13+
typedef enum { VCAM_MEMORY_MMAP = 0, VCAM_MEMORY_DMABUF = 2 } memtype_t;
1314

1415
struct crop_ratio {
1516
__u32 numerator;
@@ -27,6 +28,7 @@ struct vcam_device_spec {
2728
struct crop_ratio cropratio;
2829

2930
pixfmt_t pix_fmt;
31+
memtype_t mem_type;
3032
char video_node[64];
3133
char fb_node[64];
3234
};

videobuf.c

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <linux/spinlock.h>
44
#include <linux/vmalloc.h>
55
#include <media/videobuf2-core.h>
6+
#include <media/videobuf2-dma-contig.h>
67
#include <media/videobuf2-vmalloc.h>
78

89
#include "videobuf.h"
@@ -114,6 +115,23 @@ static void vcam_outbuf_unlock(struct vb2_queue *vq)
114115
mutex_unlock(&dev->vcam_mutex);
115116
}
116117

118+
static int vcam_buf_init(struct vb2_buffer *vb)
119+
{
120+
struct vcam_out_buffer *buf =
121+
container_of(vb, struct vcam_out_buffer, vb.vb2_buf);
122+
123+
buf->filled = 0;
124+
INIT_LIST_HEAD(&buf->list);
125+
126+
pr_debug("vcam_buf_init: buffer initialized\n");
127+
return 0;
128+
}
129+
130+
static void vcam_buf_cleanup(struct vb2_buffer *vb)
131+
{
132+
pr_debug("vcam_buf_cleanup called\n");
133+
}
134+
117135
static const struct vb2_ops vcam_vb2_ops = {
118136
.queue_setup = vcam_out_queue_setup,
119137
.buf_prepare = vcam_out_buffer_prepare,
@@ -122,19 +140,29 @@ static const struct vb2_ops vcam_vb2_ops = {
122140
.stop_streaming = vcam_stop_streaming,
123141
.wait_prepare = vcam_outbuf_unlock,
124142
.wait_finish = vcam_outbuf_lock,
143+
.buf_init = vcam_buf_init,
144+
.buf_cleanup = vcam_buf_cleanup,
125145
};
126146

127147
int vcam_out_videobuf2_setup(struct vcam_device *dev)
128148
{
129149
struct vb2_queue *q = &dev->vb_out_vidq;
130150

131151
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
132-
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
152+
q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ | VB2_DMABUF;
133153
q->drv_priv = dev;
134154
q->buf_struct_size = sizeof(struct vcam_out_buffer);
135155
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
136156
q->ops = &vcam_vb2_ops;
137-
q->mem_ops = &vb2_vmalloc_memops;
157+
pr_info("memory type %d\n", dev->mem_type);
158+
switch (dev->mem_type) {
159+
case VCAM_MEMORY_MMAP:
160+
q->mem_ops = &vb2_vmalloc_memops;
161+
break;
162+
case VCAM_MEMORY_DMABUF:
163+
q->mem_ops = &vb2_dma_contig_memops;
164+
break;
165+
}
138166
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 8, 0)
139167
q->min_queued_buffers = 2;
140168
#else

0 commit comments

Comments
 (0)