Skip to content

Commit 0cb2ab8

Browse files
committed
drivers: video: Move buffer management stuffs into a separate file
Move buffer management stuffs into a separate video_buffer.c file Signed-off-by: Phi Bang Nguyen <[email protected]>
1 parent 0fc6766 commit 0cb2ab8

File tree

6 files changed

+237
-216
lines changed

6 files changed

+237
-216
lines changed

drivers/video/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
zephyr_library()
44

5+
zephyr_library_sources(video_buffer.c)
56
zephyr_library_sources(video_common.c)
67
zephyr_library_sources(video_ctrls.c)
78
zephyr_library_sources(video_device.c)

drivers/video/video_buffer.c

Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
/*
2+
* Copyright (c) 2019, Linaro Limited
3+
* Copyright (c) 2024-2025, tinyVision.ai Inc.
4+
* Copyright 2024 NXP
5+
*
6+
* SPDX-License-Identifier: Apache-2.0
7+
*/
8+
9+
#include <zephyr/logging/log.h>
10+
#include <zephyr/drivers/video.h>
11+
#include <zephyr/rtio/rtio.h>
12+
13+
#include "video_buffer.h"
14+
#include "video_device.h"
15+
16+
LOG_MODULE_REGISTER(video_buffer, CONFIG_VIDEO_LOG_LEVEL);
17+
18+
#if defined(CONFIG_VIDEO_BUFFER_USE_SHARED_MULTI_HEAP)
19+
#include <zephyr/multi_heap/shared_multi_heap.h>
20+
21+
#define VIDEO_COMMON_HEAP_ALLOC(align, size, timeout) \
22+
shared_multi_heap_aligned_alloc(CONFIG_VIDEO_BUFFER_SMH_ATTRIBUTE, align, size)
23+
#define VIDEO_COMMON_FREE(block) shared_multi_heap_free(block)
24+
#else
25+
K_HEAP_DEFINE(video_buffer_pool, CONFIG_VIDEO_BUFFER_POOL_SZ_MAX *CONFIG_VIDEO_BUFFER_POOL_NUM_MAX);
26+
#define VIDEO_COMMON_HEAP_ALLOC(align, size, timeout) \
27+
k_heap_aligned_alloc(&video_buffer_pool, align, size, timeout);
28+
#define VIDEO_COMMON_FREE(block) k_heap_free(&video_buffer_pool, block)
29+
#endif
30+
31+
static struct video_buffer video_buf[CONFIG_VIDEO_BUFFER_POOL_NUM_MAX];
32+
33+
struct mem_block {
34+
void *data;
35+
};
36+
37+
static struct mem_block video_block[CONFIG_VIDEO_BUFFER_POOL_NUM_MAX];
38+
39+
struct video_buffer *video_buffer_aligned_alloc(size_t size, size_t align, k_timeout_t timeout)
40+
{
41+
struct video_buffer *vbuf = NULL;
42+
struct mem_block *block;
43+
int i;
44+
45+
/* find available video buffer */
46+
for (i = 0; i < ARRAY_SIZE(video_buf); i++) {
47+
if (video_buf[i].buffer == NULL) {
48+
vbuf = &video_buf[i];
49+
block = &video_block[i];
50+
break;
51+
}
52+
}
53+
54+
if (vbuf == NULL) {
55+
return NULL;
56+
}
57+
58+
/* Alloc buffer memory */
59+
block->data = VIDEO_COMMON_HEAP_ALLOC(align, size, timeout);
60+
if (block->data == NULL) {
61+
return NULL;
62+
}
63+
64+
vbuf->buffer = block->data;
65+
66+
return vbuf;
67+
}
68+
69+
struct video_buffer *video_buffer_alloc(size_t size, k_timeout_t timeout)
70+
{
71+
return video_buffer_aligned_alloc(size, sizeof(void *), timeout);
72+
}
73+
74+
void video_buffer_release(struct video_buffer *vbuf)
75+
{
76+
struct mem_block *block = NULL;
77+
int i;
78+
79+
__ASSERT_NO_MSG(vbuf != NULL);
80+
81+
/* vbuf to block */
82+
for (i = 0; i < ARRAY_SIZE(video_block); i++) {
83+
if (video_block[i].data == vbuf->buffer) {
84+
block = &video_block[i];
85+
break;
86+
}
87+
}
88+
89+
vbuf->buffer = NULL;
90+
if (block) {
91+
VIDEO_COMMON_FREE(block->data);
92+
}
93+
}
94+
95+
/* To be completed */
96+
int video_request_buffers(uint8_t count, size_t size, enum video_buf_type type,
97+
enum video_buf_memory memory)
98+
{
99+
struct video_buffer *buffer;
100+
101+
/* TODO: Input request vs Output request for m2m devices */
102+
if (count > CONFIG_VIDEO_BUFFER_POOL_NUM_MAX) {
103+
return -EINVAL;
104+
}
105+
106+
/* TODO: Buffer request is not cumulative. For each new request, free all the buffers
107+
* that are previously requested
108+
*/
109+
110+
/* Allocate buffers */
111+
for (uint8_t i = 0; i < count; i++) {
112+
if (memory == VIDEO_MEMORY_VIDEO) {
113+
buffer = video_buffer_aligned_alloc(size, CONFIG_VIDEO_BUFFER_POOL_ALIGN,
114+
K_FOREVER);
115+
} else {
116+
buffer = &video_buf[i];
117+
}
118+
119+
buffer->type = type;
120+
buffer->index = i;
121+
buffer->size = size;
122+
buffer->bytesused = 0;
123+
buffer->state = VIDEO_BUF_STATE_DONE;
124+
}
125+
126+
return 0;
127+
}
128+
129+
RTIO_DEFINE(rtio, CONFIG_VIDEO_BUFFER_POOL_NUM_MAX, CONFIG_VIDEO_BUFFER_POOL_NUM_MAX);
130+
131+
int video_enqueue(const struct device *dev, struct video_buffer *buf)
132+
{
133+
int ret;
134+
135+
__ASSERT_NO_MSG(dev != NULL);
136+
137+
const struct video_driver_api *api = (const struct video_driver_api *)dev->api;
138+
if (api->enqueue == NULL) {
139+
return -ENOSYS;
140+
}
141+
142+
if (video_buf[buf->index].type != buf->type ||
143+
video_buf[buf->index].memory != buf->memory ||
144+
video_buf[buf->index].state != VIDEO_BUF_STATE_DONE) {
145+
return -EINVAL;
146+
}
147+
148+
if (buf->memory == VIDEO_MEMORY_USER) {
149+
if (buf->size != video_buf[buf->index].size) {
150+
return -EINVAL;
151+
}
152+
153+
video_buf[buf->index].buffer = buf->buffer;
154+
}
155+
156+
ret = api->enqueue(dev, &video_buf[buf->index]);
157+
if (ret < 0) {
158+
return ret;
159+
}
160+
161+
/* RTIO submission */
162+
struct rtio_iodev *ri = video_find_iodev(dev);
163+
struct rtio_sqe *sqe = rtio_sqe_acquire(&rtio);
164+
165+
__ASSERT_NO_MSG(ri != NULL);
166+
__ASSERT_NO_MSG(sqe != NULL);
167+
168+
rtio_sqe_prep_read(sqe, ri, RTIO_PRIO_NORM, video_buf[buf->index].buffer,
169+
video_buf[buf->index].size, &video_buf[buf->index]);
170+
171+
sqe->flags |= RTIO_SQE_MULTISHOT;
172+
173+
/* Do not wait for complete */
174+
rtio_submit(&rtio, 0);
175+
176+
video_buf[buf->index].state = VIDEO_BUF_STATE_QUEUED;
177+
178+
return 0;
179+
}
180+
181+
int video_dequeue(struct video_buffer **buf)
182+
{
183+
struct rtio_cqe *cqe = rtio_cqe_consume_block(&rtio);
184+
*buf = cqe->userdata;
185+
186+
if (cqe->result < 0) {
187+
LOG_ERR("I/O operation failed");
188+
return cqe->result;
189+
}
190+
191+
return 0;
192+
}
193+
194+
void video_release_buf()
195+
{
196+
/* Buffer will be re-queued thanks to RTIO_SQE_MULTISHOT */
197+
rtio_cqe_release(&rtio, rtio_cqe_consume_block(&rtio));
198+
}
199+
200+
struct video_buffer *video_get_buf_sqe(struct mpsc *io_q)
201+
{
202+
struct mpsc_node *node = mpsc_pop(io_q);
203+
if (node == NULL) {
204+
return NULL;
205+
}
206+
207+
struct rtio_iodev_sqe *iodev_sqe = CONTAINER_OF(node, struct rtio_iodev_sqe, q);
208+
struct rtio_sqe *sqe = &iodev_sqe->sqe;
209+
210+
if (sqe->op != RTIO_OP_RX) {
211+
LOG_ERR("Invalid operation %d of length %u for submission %p", sqe->op,
212+
sqe->rx.buf_len, (void *)iodev_sqe);
213+
rtio_iodev_sqe_err(iodev_sqe, -EINVAL);
214+
return NULL;
215+
}
216+
217+
return sqe->userdata;
218+
}
219+
220+
static void video_iodev_submit(struct rtio_iodev_sqe *iodev_sqe)
221+
{
222+
struct video_interface *vi = iodev_sqe->sqe.iodev->data;
223+
224+
mpsc_push(vi->io_q, &iodev_sqe->q);
225+
}
226+
227+
const struct rtio_iodev_api _video_iodev_api = {
228+
.submit = video_iodev_submit,
229+
};

drivers/video/video_buffer.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/*
2+
* Copyright 2025 NXP
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
struct video_buffer *video_get_buf_sqe(struct mpsc *io_q);

0 commit comments

Comments
 (0)