2 * Support for Intel Camera Imaging ISP subsystem.
3 * Copyright (c) 2015, Intel Corporation.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 #include "ia_css_circbuf.h"
17 #include <assert_support.h>
19 /**********************************************************************
21 * Forward declarations.
23 **********************************************************************/
25 * @brief Read the oldest element from the circular buffer.
26 * Read the oldest element WITHOUT checking whehter the
27 * circular buffer is empty or not. The oldest element is
28 * also removed out from the circular buffer.
30 * @param cb The pointer to the circular buffer.
32 * @return the oldest element.
34 static inline ia_css_circbuf_elem_t
35 ia_css_circbuf_read(ia_css_circbuf_t *cb);
38 * @brief Shift a chunk of elements in the circular buffer.
39 * A chunk of elements (i.e. the ones from the "start" position
40 * to the "chunk_src" position) are shifted in the circular buffer,
41 * along the direction of new elements coming.
43 * @param cb The pointer to the circular buffer.
44 * @param chunk_src The position at which the first element in the chunk is.
45 * @param chunk_dest The position to which the first element in the chunk would be shift.
47 static inline void ia_css_circbuf_shift_chunk(ia_css_circbuf_t *cb,
52 * @brief Get the "val" field in the element.
54 * @param elem The pointer to the element.
56 * @return the "val" field.
58 static inline uint32_t
59 ia_css_circbuf_elem_get_val(ia_css_circbuf_elem_t *elem);
61 /**********************************************************************
63 * Non-inline functions.
65 **********************************************************************/
67 * @brief Create the circular buffer.
68 * Refer to "ia_css_circbuf.h" for details.
71 ia_css_circbuf_create(ia_css_circbuf_t *cb,
72 ia_css_circbuf_elem_t *elems,
73 ia_css_circbuf_desc_t *desc)
80 /* Initialize to defaults */
85 for (i = 0; i < cb->desc->size; i++)
86 ia_css_circbuf_elem_init(&elems[i]);
92 * @brief Destroy the circular buffer.
93 * Refer to "ia_css_circbuf.h" for details.
95 void ia_css_circbuf_destroy(ia_css_circbuf_t *cb)
103 * @brief Pop a value out of the circular buffer.
104 * Refer to "ia_css_circbuf.h" for details.
106 uint32_t ia_css_circbuf_pop(ia_css_circbuf_t *cb)
109 ia_css_circbuf_elem_t elem;
111 assert(!ia_css_circbuf_is_empty(cb));
113 /* read an element from the buffer */
114 elem = ia_css_circbuf_read(cb);
115 ret = ia_css_circbuf_elem_get_val(&elem);
120 * @brief Extract a value out of the circular buffer.
121 * Refer to "ia_css_circbuf.h" for details.
123 uint32_t ia_css_circbuf_extract(ia_css_circbuf_t *cb, int offset)
131 /* get the maximum offest */
132 max_offset = ia_css_circbuf_get_offset(cb, cb->desc->start, cb->desc->end);
136 * Step 1: When the target element is at the "start" position.
139 val = ia_css_circbuf_pop(cb);
144 * Step 2: When the target element is out of the range.
146 if (offset > max_offset) {
152 * Step 3: When the target element is between the "start" and
155 /* get the position of the target element */
156 pos = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->start, offset);
158 /* get the value from the target element */
159 val = ia_css_circbuf_elem_get_val(&cb->elems[pos]);
161 /* shift the elements */
162 src_pos = ia_css_circbuf_get_pos_at_offset(cb, pos, -1);
164 ia_css_circbuf_shift_chunk(cb, src_pos, dest_pos);
170 * @brief Peek an element from the circular buffer.
171 * Refer to "ia_css_circbuf.h" for details.
173 uint32_t ia_css_circbuf_peek(ia_css_circbuf_t *cb, int offset)
177 pos = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->end, offset);
179 /* get the value at the position */
180 return cb->elems[pos].val;
184 * @brief Get the value of an element from the circular buffer.
185 * Refer to "ia_css_circbuf.h" for details.
187 uint32_t ia_css_circbuf_peek_from_start(ia_css_circbuf_t *cb, int offset)
191 pos = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->start, offset);
193 /* get the value at the position */
194 return cb->elems[pos].val;
197 /** @brief increase size of a circular buffer.
198 * Use 'CAUTION' before using this function. This was added to
199 * support / fix issue with increasing size for tagger only
200 * Please refer to "ia_css_circbuf.h" for details.
202 bool ia_css_circbuf_increase_size(
203 ia_css_circbuf_t *cb,
204 unsigned int sz_delta,
205 ia_css_circbuf_elem_t *elems)
211 if (!cb || sz_delta == 0)
214 curr_size = cb->desc->size;
215 curr_end = cb->desc->end;
216 /* We assume cb was pre defined as global to allow
217 * increase in size */
218 /* FM: are we sure this cannot cause size to become too big? */
219 if (((uint8_t)(cb->desc->size + (uint8_t)sz_delta) > cb->desc->size) && ((uint8_t)sz_delta == sz_delta))
220 cb->desc->size += (uint8_t)sz_delta;
222 return false; /* overflow in size */
224 /* If elems are passed update them else we assume its been taken
225 * care before calling this function */
227 /* cb element array size will not be increased dynamically,
228 * but pointers to new elements can be added at the end
229 * of existing pre defined cb element array of
230 * size >= new size if not already added */
231 for (i = curr_size; i < cb->desc->size; i++)
232 cb->elems[i] = elems[i - curr_size];
234 /* Fix Start / End */
235 if (curr_end < cb->desc->start) {
238 cb->desc->end = curr_size;
240 /* Move elements and fix Start*/
241 ia_css_circbuf_shift_chunk(cb,
243 curr_size + sz_delta - 1);
250 /****************************************************************
254 ****************************************************************/
256 * @brief Get the "val" field in the element.
257 * Refer to "Forward declarations" for details.
259 static inline uint32_t
260 ia_css_circbuf_elem_get_val(ia_css_circbuf_elem_t *elem)
266 * @brief Read the oldest element from the circular buffer.
267 * Refer to "Forward declarations" for details.
269 static inline ia_css_circbuf_elem_t
270 ia_css_circbuf_read(ia_css_circbuf_t *cb)
272 ia_css_circbuf_elem_t elem;
274 /* get the element from the target position */
275 elem = cb->elems[cb->desc->start];
277 /* clear the target position */
278 ia_css_circbuf_elem_init(&cb->elems[cb->desc->start]);
280 /* adjust the "start" position */
281 cb->desc->start = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->start, 1);
286 * @brief Shift a chunk of elements in the circular buffer.
287 * Refer to "Forward declarations" for details.
290 ia_css_circbuf_shift_chunk(ia_css_circbuf_t *cb,
291 uint32_t chunk_src, uint32_t chunk_dest)
297 /* get the chunk offset and size */
298 chunk_offset = ia_css_circbuf_get_offset(cb,
299 chunk_src, chunk_dest);
300 chunk_sz = ia_css_circbuf_get_offset(cb, cb->desc->start, chunk_src) + 1;
302 /* shift each element to its terminal position */
303 for (i = 0; i < chunk_sz; i++) {
305 /* copy the element from the source to the destination */
306 ia_css_circbuf_elem_cpy(&cb->elems[chunk_src],
307 &cb->elems[chunk_dest]);
309 /* clear the source position */
310 ia_css_circbuf_elem_init(&cb->elems[chunk_src]);
312 /* adjust the source/terminal positions */
313 chunk_src = ia_css_circbuf_get_pos_at_offset(cb, chunk_src, -1);
314 chunk_dest = ia_css_circbuf_get_pos_at_offset(cb, chunk_dest, -1);
318 /* adjust the index "start" */
319 cb->desc->start = ia_css_circbuf_get_pos_at_offset(cb, cb->desc->start, chunk_offset);