/**************************************************************************** * drivers/video/video_framebuff.c * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. The * ASF licenses this file to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the * License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations * under the License. * ****************************************************************************/ /**************************************************************************** * Included Files ****************************************************************************/ #include #include #include #include #include "video_framebuff.h" /**************************************************************************** * Private Functions ****************************************************************************/ static void init_buf_chain(video_framebuff_t *fbuf) { vbuf_container_t *tmp; int i; fbuf->vbuf_empty = fbuf->vbuf_alloced; fbuf->vbuf_next = NULL; fbuf->vbuf_top = NULL; fbuf->vbuf_tail = NULL; tmp = fbuf->vbuf_alloced; for (i = 1; i < fbuf->container_size; i++) { tmp->next = &tmp[1]; tmp++; } } static inline bool is_last_one(video_framebuff_t *fbuf) { return fbuf->vbuf_top == fbuf->vbuf_tail; } static inline vbuf_container_t *dequeue_vbuf_unsafe(video_framebuff_t *fbuf) { vbuf_container_t *ret = fbuf->vbuf_top; if (is_last_one(fbuf)) { fbuf->vbuf_top = NULL; fbuf->vbuf_tail = NULL; fbuf->vbuf_next = NULL; } else { if (fbuf->mode == V4L2_BUF_MODE_RING) { fbuf->vbuf_tail->next = fbuf->vbuf_top->next; } fbuf->vbuf_top = fbuf->vbuf_top->next; } ret->next = NULL; return ret; } /**************************************************************************** * Public Functions ****************************************************************************/ void video_framebuff_init(video_framebuff_t *fbuf) { memset(fbuf, 0, sizeof(video_framebuff_t)); fbuf->mode = V4L2_BUF_MODE_RING; nxmutex_init(&fbuf->lock_empty); } void video_framebuff_uninit(video_framebuff_t *fbuf) { video_framebuff_realloc_container(fbuf, 0); nxmutex_destroy(&fbuf->lock_empty); } int video_framebuff_realloc_container(video_framebuff_t *fbuf, int sz) { vbuf_container_t *vbuf; nxmutex_lock(&fbuf->lock_empty); if (fbuf->container_size == sz) { nxmutex_unlock(&fbuf->lock_empty); return OK; } if (sz > 0) { vbuf = kmm_realloc(fbuf->vbuf_alloced, sizeof(vbuf_container_t) * sz); if (vbuf != NULL) { memset(vbuf, 0, sizeof(vbuf_container_t) * sz); fbuf->vbuf_alloced = vbuf; fbuf->container_size = sz; } else { nxmutex_unlock(&fbuf->lock_empty); return -ENOMEM; } } else { kmm_free(fbuf->vbuf_alloced); fbuf->vbuf_alloced = NULL; fbuf->container_size = 0; } init_buf_chain(fbuf); nxmutex_unlock(&fbuf->lock_empty); return OK; } int video_framebuff_is_empty(video_framebuff_t *fbuf) { return fbuf->vbuf_top == NULL || fbuf->vbuf_top == fbuf->vbuf_next; } vbuf_container_t *video_framebuff_get_container(video_framebuff_t *fbuf) { vbuf_container_t *ret; nxmutex_lock(&fbuf->lock_empty); ret = fbuf->vbuf_empty; if (ret != NULL) { fbuf->vbuf_empty = ret->next; ret->next = NULL; } nxmutex_unlock(&fbuf->lock_empty); return ret; } void video_framebuff_free_container(video_framebuff_t *fbuf, vbuf_container_t *cnt) { nxmutex_lock(&fbuf->lock_empty); cnt->next = fbuf->vbuf_empty; fbuf->vbuf_empty = cnt; nxmutex_unlock(&fbuf->lock_empty); } void video_framebuff_queue_container(video_framebuff_t *fbuf, vbuf_container_t *tgt) { irqstate_t flags; flags = spin_lock_irqsave(&fbuf->lock_queue); if (fbuf->vbuf_top != NULL) { fbuf->vbuf_tail->next = tgt; fbuf->vbuf_tail = tgt; } else { fbuf->vbuf_top = fbuf->vbuf_tail = tgt; } if (fbuf->vbuf_next == NULL) { fbuf->vbuf_next = tgt; } if (fbuf->mode == V4L2_BUF_MODE_RING) { tgt->next = fbuf->vbuf_top; } else /* Case of V4L2_BUF_MODE_FIFO */ { tgt->next = NULL; } spin_unlock_irqrestore(&fbuf->lock_queue, flags); } vbuf_container_t *video_framebuff_dq_valid_container(video_framebuff_t *fbuf) { vbuf_container_t *ret = NULL; irqstate_t flags; flags = spin_lock_irqsave(&fbuf->lock_queue); if (fbuf->vbuf_top != NULL && fbuf->vbuf_top != fbuf->vbuf_next) { ret = dequeue_vbuf_unsafe(fbuf); } spin_unlock_irqrestore(&fbuf->lock_queue, flags); return ret; } vbuf_container_t * video_framebuff_get_vacant_container(video_framebuff_t *fbuf) { vbuf_container_t *ret; irqstate_t flags; flags = spin_lock_irqsave(&fbuf->lock_queue); ret = fbuf->vbuf_next; spin_unlock_irqrestore(&fbuf->lock_queue, flags); return ret; } void video_framebuff_capture_done(video_framebuff_t *fbuf) { irqstate_t flags; flags = spin_lock_irqsave(&fbuf->lock_queue); if (fbuf->vbuf_next != NULL) { fbuf->vbuf_next = fbuf->vbuf_next->next; if (fbuf->vbuf_next == fbuf->vbuf_top) /* RING mode case. */ { fbuf->vbuf_top = fbuf->vbuf_top->next; fbuf->vbuf_tail = fbuf->vbuf_tail->next; } } spin_unlock_irqrestore(&fbuf->lock_queue, flags); } void video_framebuff_change_mode(video_framebuff_t *fbuf, enum v4l2_buf_mode mode) { irqstate_t flags; flags = spin_lock_irqsave(&fbuf->lock_queue); if (fbuf->mode != mode) { if (fbuf->vbuf_tail) { if (mode == V4L2_BUF_MODE_RING) { fbuf->vbuf_tail->next = fbuf->vbuf_top; } else { fbuf->vbuf_tail->next = NULL; } } fbuf->vbuf_next = fbuf->vbuf_top; fbuf->mode = mode; } spin_unlock_irqrestore(&fbuf->lock_queue, flags); } vbuf_container_t *video_framebuff_pop_curr_container(video_framebuff_t *fbuf) { vbuf_container_t *ret = NULL; irqstate_t flags; flags = spin_lock_irqsave(&fbuf->lock_queue); if (fbuf->vbuf_top != NULL) { ret = dequeue_vbuf_unsafe(fbuf); } spin_unlock_irqrestore(&fbuf->lock_queue, flags); return ret; }