1 /******************************************************************************
2 *
3 * Copyright 2007, Silicon Image, Inc. All rights reserved.
4 * No part of this work may be reproduced, modified, distributed, transmitted,
5 * transcribed, or translated into any language or computer format, in any form
6 * or by any means without written permission of: Silicon Image, Inc., 1060
7 * East Arques Avenue, Sunnyvale, California 94085
8 *
9 *****************************************************************************/
10 /**
11 * @file media_buffer_pool.c
12 *
13 * @brief
14 * Buffer Pool implementation
15 *
16 * <pre>
17 *
18 * Principal Author: Joerg Detert
19 * Creation date: Feb 28, 2008
20 *
21 * </pre>
22 *
23 *****************************************************************************/
24
25 #include <string.h>
26
27 #include "media_buffer_pool.h"
28
29
30
31 #define MEDIA_BUF_ALIGN(buf, align) (((buf)+((align)-1U)) & ~((align)-1U))
32
33
34 /******************************************************************************
35 * MediaBufPoolGetSize
36 *****************************************************************************/
MediaBufPoolGetSize(MediaBufPoolConfig_t * pPoolConfig)37 RESULT MediaBufPoolGetSize(MediaBufPoolConfig_t* pPoolConfig)
38 {
39 RESULT ret = RET_SUCCESS;
40
41 if(pPoolConfig == NULL)
42 {
43 return RET_WRONG_HANDLE;
44 }
45
46 if(pPoolConfig->bufNum > pPoolConfig->maxBufNum)
47 {
48 return RET_WRONG_CONFIG;
49 }
50
51 /* size of extra metadata */
52 pPoolConfig->metaDataMemSize = pPoolConfig->maxBufNum * pPoolConfig->metaDataSizeMediaBuf;
53
54 /* size of media buffer array */
55 pPoolConfig->metaDataMemSize += (uint32_t)(pPoolConfig->maxBufNum * sizeof(MediaBuffer_t));
56
57 /* calculate size of buffer array*/
58 if(pPoolConfig->flags & (uint32_t)BUFPOOL_RINGBUFFER)
59 {
60 /* results in no gaps between buffers but an offset depending on the alignment */
61 pPoolConfig->bufMemSize = (pPoolConfig->maxBufNum * pPoolConfig->bufSize) +
62 pPoolConfig->bufAlign;
63
64 /* the buffer size must be correct to the alignment otherwise we would have
65 * unaligned buffers after the first which is always aligned */
66 if((pPoolConfig->bufSize & ((uint32_t)pPoolConfig->bufAlign - 1U)) != 0U)
67 {
68 return RET_WRONG_CONFIG;
69 }
70 }
71 else
72 {
73 /* this leads to gaps between the buffers dependend on the alignment */
74 pPoolConfig->bufMemSize = pPoolConfig->maxBufNum * (pPoolConfig->bufSize +
75 pPoolConfig->bufAlign);
76 }
77
78 return ret;
79 }
80
81
82 /******************************************************************************
83 * MediaBufPoolCreate
84 *****************************************************************************/
MediaBufPoolCreate(MediaBufPool_t * pBufPool,MediaBufPoolConfig_t * pPoolConfig,MediaBufPoolMemory_t poolMemory)85 RESULT MediaBufPoolCreate(MediaBufPool_t* pBufPool,
86 MediaBufPoolConfig_t* pPoolConfig,
87 MediaBufPoolMemory_t poolMemory)
88 {
89 uint32_t i;
90 uint32_t offset;
91 void* pBuf;
92 RESULT ret = RET_SUCCESS;
93 if(pBufPool == NULL)
94 {
95 return RET_WRONG_HANDLE;
96 }
97
98 if((poolMemory.pMetaDataMemory == NULL) ||
99 (poolMemory.pBufferMemory == NULL))
100 {
101 return RET_INVALID_PARM;
102 }
103
104 if((pPoolConfig->bufNum == 0U) || (pPoolConfig->bufSize == 0U) ||
105 (pPoolConfig->maxBufNum < pPoolConfig->bufNum))
106 {
107 return RET_WRONG_CONFIG;
108 }
109
110 /* If buffer pool is switched to ringbuffer mode, there must not be any gap*/
111 /* between individual buffers inside static buffer pool, introduced by data*/
112 /* alignement issues (e.g. rouding up of internal buffer sizes).*/
113 /* That is, the buffer size must be a multiple of the data alignement.*/
114 if((pPoolConfig->flags & BUFPOOL_RINGBUFFER) &&
115 (pPoolConfig->bufSize % pPoolConfig->bufAlign))
116 {
117 return RET_WRONG_CONFIG;
118 }
119
120 /* initialize buffer pool object*/
121 (void) memset(pBufPool, 0, sizeof(MediaBufPool_t));
122
123 pBufPool->bufSize = pPoolConfig->bufSize;
124 pBufPool->metaDataSizeMediaBuf = pPoolConfig->metaDataSizeMediaBuf;
125 pBufPool->bufNum = pPoolConfig->bufNum;
126 pBufPool->freeBufNum = pPoolConfig->bufNum;
127 pBufPool->maxBufNum = pPoolConfig->maxBufNum;
128 pBufPool->poolSize = pPoolConfig->bufNum * pPoolConfig->bufSize;
129 pBufPool->flags = pPoolConfig->flags;
130
131 /* The memory given by the caller is assigned to the buffer pool */
132 pBufPool->pBaseAddress = poolMemory.pMetaDataMemory;
133
134 /* Make sure that sizes in pPoolConfig are written */
135 (void) MediaBufPoolGetSize(pPoolConfig);
136 /* initialize buffer memory to zero */
137 (void) memset(poolMemory.pMetaDataMemory, 0, (size_t) pPoolConfig->metaDataMemSize);
138
139 /* We use the first partition of memory for the media buffer array */
140 pBufPool->pBufArray = (MediaBuffer_t*) pBufPool->pBaseAddress;
141
142 /* The second partition of memory is used for the buffer meta data array for Media Buffers */
143 offset = (pPoolConfig->maxBufNum * sizeof(MediaBuffer_t));
144 pBufPool->pMetaDataMediaBufBase = (void*) (((ulong_t) pBufPool->pBaseAddress) + offset);
145
146 /* The memory pointed to by pBufferMemory is used for
147 * the real buffer memory. This memory is assigned to the pointers stored in the corresponding
148 * MediaBuffer_t[]. Due to the alignment restrictions given by the user it must be kept in mind
149 * that the alignment is added. */
150 pBuf = poolMemory.pBufferMemory;
151 for(i = 0U; i < pBufPool->maxBufNum; i++)
152 {
153 /* set base address of buffer
154 (will be changed in case that buffer pool is resized) */
155 pBufPool->pBufArray[i].pBaseAddress = (uint8_t*) MEDIA_BUF_ALIGN((ulong_t)pBuf +
156 (i * pPoolConfig->bufSize), (uint32_t)pPoolConfig->bufAlign);
157 /* set base size of buffer
158 (will be changed in case that buffer pool is resized) */
159 pBufPool->pBufArray[i].baseSize = pBufPool->bufSize;
160
161 if ( pPoolConfig->metaDataSizeMediaBuf != 0 )
162 {
163 /* set Media Buffer meta data structure address for
164 (stays the same during lifetime of buffer pool) */
165 pBufPool->pBufArray[i].pMetaData = (void *)((ulong_t) pBufPool->pMetaDataMediaBufBase +
166 (i * pPoolConfig->metaDataSizeMediaBuf));
167 }
168 else
169 {
170 pBufPool->pBufArray[i].pMetaData = NULL;
171 }
172
173 MediaBufInit(&pBufPool->pBufArray[i]);
174 }
175
176 AtomicMutexInit();
177
178 return ret;
179 }
180
181
182 /******************************************************************************
183 * MediaBufPoolDestroy
184 *****************************************************************************/
MediaBufPoolDestroy(MediaBufPool_t * pBufPool)185 RESULT MediaBufPoolDestroy(MediaBufPool_t *pBufPool)
186 {
187 DCT_ASSERT(pBufPool != NULL);
188
189 (void) memset(pBufPool, 0, sizeof(MediaBufPool_t));
190 AtomicMutexDestory();
191 return RET_SUCCESS;
192 }
193
194
195 /******************************************************************************
196 * MediaBufPoolReset
197 *****************************************************************************/
MediaBufPoolReset(MediaBufPool_t * pBufPool)198 RESULT MediaBufPoolReset(MediaBufPool_t* pBufPool)
199 {
200 uint32_t i;
201
202 DCT_ASSERT(pBufPool != NULL);
203
204 /* reset state variables */
205 pBufPool->freeBufNum = pBufPool->bufNum;
206 pBufPool->fillLevel = 0;
207 pBufPool->index = 0;
208
209 /* re-init media buffers */
210 for(i = 0U; i < pBufPool->maxBufNum; i++)
211 {
212 MediaBufInit(&pBufPool->pBufArray[i]);
213 }
214
215 return RET_SUCCESS;
216 }
217
218
219 /******************************************************************************
220 * MediaBufPoolRegisterCb
221 *****************************************************************************/
MediaBufPoolRegisterCb(MediaBufPool_t * pBufPool,MediaBufPoolCbNotify_t fpCallback,void * pUserContext)222 RESULT MediaBufPoolRegisterCb(MediaBufPool_t* pBufPool,
223 MediaBufPoolCbNotify_t fpCallback,
224 void* pUserContext)
225 {
226 RESULT ret = RET_NOTAVAILABLE;
227 int32_t i;
228
229 if(pBufPool == NULL)
230 {
231 return RET_WRONG_HANDLE;
232 }
233
234 if(fpCallback == NULL)
235 {
236 return RET_INVALID_PARM;
237 }
238
239 if(pBufPool->notify.fpCallback == NULL)
240 {
241 pBufPool->notify.fpCallback = fpCallback;
242 pBufPool->notify.pUserContext = pUserContext;
243 ret = RET_SUCCESS;
244 }
245
246 return ret;
247 }
248
249
250 /******************************************************************************
251 * MediaBufPoolDeregisterCb
252 *****************************************************************************/
MediaBufPoolDeregisterCb(MediaBufPool_t * pBufPool,MediaBufPoolCbNotify_t fpCallback)253 RESULT MediaBufPoolDeregisterCb(MediaBufPool_t* pBufPool,
254 MediaBufPoolCbNotify_t fpCallback)
255 {
256 RESULT ret = RET_NOTAVAILABLE;
257 int32_t i;
258
259 if(pBufPool == NULL)
260 {
261 return RET_WRONG_HANDLE;
262 }
263
264 if(fpCallback == NULL)
265 {
266 return RET_INVALID_PARM;
267 }
268
269 if(pBufPool->notify.fpCallback == fpCallback)
270 {
271 pBufPool->notify.fpCallback = NULL;
272 pBufPool->notify.pUserContext = NULL;
273 ret = RET_SUCCESS;
274 }
275
276 return ret;
277 }
278
279
280
281 /******************************************************************************
282 * MediaBufPoolGetBuffer
283 *****************************************************************************/
MediaBufPoolGetBuffer(MediaBufPool_t * pBufPool)284 MediaBuffer_t* MediaBufPoolGetBuffer(MediaBufPool_t* pBufPool)
285 {
286 MediaBuffer_t *pMediaBuffer;
287
288 DCT_ASSERT(pBufPool != NULL);
289
290 for(;;)
291 {
292 /* if the requested number of buffers is greater than the maximum then wait*/
293 while( pBufPool->freeBufNum == 0U )
294 {
295 return NULL;
296 }
297
298 /* at least one buffer is free*/
299 for(;;)
300 {
301 if(!pBufPool->pBufArray[pBufPool->index].lockCount)
302 {
303 /* adjust the resources count*/
304 pBufPool->freeBufNum--;
305 pBufPool->pBufArray[pBufPool->index].lockCount = 1;
306 pBufPool->pBufArray[pBufPool->index].pOwner = pBufPool;
307 pMediaBuffer = &pBufPool->pBufArray[pBufPool->index];
308
309 if(++(pBufPool->index) >= pBufPool->bufNum)
310 {
311 pBufPool->index = 0U;
312 }
313
314 return pMediaBuffer;
315 }
316 else
317 {
318 /* pBufPool->uiIndex points to the next buffer to be checked for a get empty request.*/
319 /* If that buffer is locked, no media buffer is returned, because random access is*/
320 /* not allowed in ringbuffer mode.*/
321 if(pBufPool->flags & BUFPOOL_RINGBUFFER)
322 {
323 return NULL;
324 }
325 }
326 if(++(pBufPool->index) >= pBufPool->bufNum)
327 {
328 pBufPool->index = 0U;
329 }
330 }
331 } /* for( ;;)*/
332 }
333
334
335 /******************************************************************************
336 * MediaBufPoolFreeBuffer
337 *****************************************************************************/
MediaBufPoolFreeBuffer(MediaBufPool_t * pBufPool,MediaBuffer_t * pBuf)338 void MediaBufPoolFreeBuffer(MediaBufPool_t* pBufPool, MediaBuffer_t *pBuf)
339 {
340 int32_t i;
341
342 DCT_ASSERT(pBufPool != NULL);
343 DCT_ASSERT(pBuf != NULL);
344
345 pBuf->lockCount = 0;
346 pBufPool->freeBufNum++;
347
348 if(pBufPool->notify.fpCallback != NULL)
349 {
350 (pBufPool->notify.fpCallback)(pBufPool->notify.pUserContext, pBuf);
351 }
352 }
353
354