Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/teigland/dlm
[linux-2.6] / drivers / staging / epl / SharedBuff.c
1 /****************************************************************************
2
3   (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29
4       www.systec-electronic.com
5
6   Project:      Project independend shared buffer (linear + circular)
7
8   Description:  Implementation of platform independend part for the
9                 shared buffer
10
11   License:
12
13     Redistribution and use in source and binary forms, with or without
14     modification, are permitted provided that the following conditions
15     are met:
16
17     1. Redistributions of source code must retain the above copyright
18        notice, this list of conditions and the following disclaimer.
19
20     2. Redistributions in binary form must reproduce the above copyright
21        notice, this list of conditions and the following disclaimer in the
22        documentation and/or other materials provided with the distribution.
23
24     3. Neither the name of SYSTEC electronic GmbH nor the names of its
25        contributors may be used to endorse or promote products derived
26        from this software without prior written permission. For written
27        permission, please contact info@systec-electronic.com.
28
29     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
32     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
33     COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
34     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
35     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
36     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
37     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
39     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
40     POSSIBILITY OF SUCH DAMAGE.
41
42     Severability Clause:
43
44         If a provision of this License is or becomes illegal, invalid or
45         unenforceable in any jurisdiction, that shall not affect:
46         1. the validity or enforceability in that jurisdiction of any other
47            provision of this License; or
48         2. the validity or enforceability in other jurisdictions of that or
49            any other provision of this License.
50
51   -------------------------------------------------------------------------
52
53   2006/06/27 -rs:   V 1.00 (initial version)
54
55 ****************************************************************************/
56
57 #if defined(WIN32) || defined(_WIN32)
58
59 #ifdef UNDER_RTSS
60         // RTX header
61 #include <windows.h>
62 #include <process.h>
63 #include <rtapi.h>
64
65 #elif __BORLANDC__
66         // borland C header
67 #include <windows.h>
68 #include <process.h>
69
70 #elif WINCE
71 #include <windows.h>
72
73 #else
74         // MSVC needs to include windows.h at first
75         // the following defines ar necessary for function prototypes for waitable timers
76 #define _WIN32_WINDOWS 0x0401
77 #define _WIN32_WINNT   0x0400
78 #include <windows.h>
79 #include <process.h>
80 #endif
81
82 #endif
83
84 #include "global.h"
85 #include "SharedBuff.h"
86 #include "ShbIpc.h"
87
88 // d.k. Linux kernel modules needs other header files for memcpy()
89 #if (TARGET_SYSTEM == _LINUX_) && defined(__KERNEL__)
90 #include <linux/string.h>
91 #else
92 #include <stdio.h>
93 #include <stdlib.h>
94 #include <string.h>
95 #endif
96
97 /***************************************************************************/
98 /*                                                                         */
99 /*                                                                         */
100 /*          G L O B A L   D E F I N I T I O N S                            */
101 /*                                                                         */
102 /*                                                                         */
103 /***************************************************************************/
104
105 #if (!defined(SHAREDBUFF_INLINED)) || defined(INLINE_ENABLED)
106
107 //---------------------------------------------------------------------------
108 //  Configuration
109 //---------------------------------------------------------------------------
110
111 //---------------------------------------------------------------------------
112 //  Constant definitions
113 //---------------------------------------------------------------------------
114
115 #define SBC_MAGIC_ID    0x53424323      // magic ID ("SBC#")
116 #define SBL_MAGIC_ID    0x53424C23      // magic ID ("SBL#")
117
118 //---------------------------------------------------------------------------
119 //  Local types
120 //---------------------------------------------------------------------------
121
122 // structure to administrate circular shared buffer head
123 typedef struct {
124         unsigned long m_ShbCirMagicID;  // magic ID ("SBC#")
125         unsigned long m_ulBufferTotalSize;      // over-all size of complete buffer
126         unsigned long m_ulBufferDataSize;       // size of complete data area
127         unsigned long m_ulWrIndex;      // current write index (set bevore write)
128         unsigned long m_ulRdIndex;      // current read index (set after read)
129         unsigned long m_ulNumOfWriteJobs;       // number of currently (parallel running) write operations
130         unsigned long m_ulDataInUse;    // currently used buffer size (incl. uncompleted write operations)
131         unsigned long m_ulDataApended;  // buffer size of complete new written but not yet readable data (in case of m_ulNumOfWriteJobs>1)
132         unsigned long m_ulBlocksApended;        // number of complete new written but not yet readable data blocks (in case of m_ulNumOfWriteJobs>1)
133         unsigned long m_ulDataReadable; // buffer size with readable (complete written) data
134         unsigned long m_ulBlocksReadable;       // number of readable (complete written) data blocks
135         tShbCirSigHndlrNewData m_pfnSigHndlrNewData;    // application handler to signal new data
136         unsigned int m_fBufferLocked;   // TRUE if buffer is locked (because of pending reset request)
137         tShbCirSigHndlrReset m_pfnSigHndlrReset;        // application handler to signal buffer reset is done
138         unsigned char m_Data;   // start of data area (the real data size is unknown at this time)
139
140 } tShbCirBuff;
141
142 // structure to administrate linear shared buffer head
143 typedef struct {
144         unsigned int m_ShbLinMagicID;   // magic ID ("SBL#")
145         unsigned long m_ulBufferTotalSize;      // over-all size of complete buffer
146         unsigned long m_ulBufferDataSize;       // size of complete data area
147         unsigned char m_Data;   // start of data area (the real data size is unknown at this time)
148
149 } tShbLinBuff;
150
151 // type to save size of a single data block inside the circular shared buffer
152 typedef struct {
153         unsigned int m_uiFullBlockSize:28;      // a single block must not exceed a length of 256MByte :-)
154         unsigned int m_uiAlignFillBytes:4;
155
156 } tShbCirBlockSize;
157
158 #define SBC_BLOCK_ALIGNMENT                  4  // alignment must *not* be lower than sizeof(tShbCirBlockSize)!
159 #define SBC_MAX_BLOCK_SIZE         ((1<<28)-1)  // = (2^28 - 1) = (256MByte - 1) -> should be enought for real life :-)
160
161 #define SBL_BLOCK_ALIGNMENT                  4
162 #define SBL_MAX_BLOCK_SIZE         ((1<<28)-1)  // = (2^28 - 1) = (256MByte - 1) -> should be enought for real life :-)
163
164 //---------------------------------------------------------------------------
165 //  Global variables
166 //---------------------------------------------------------------------------
167
168 //---------------------------------------------------------------------------
169 //  Local variables
170 //---------------------------------------------------------------------------
171
172 //---------------------------------------------------------------------------
173 //  Prototypes of internal functions
174 //---------------------------------------------------------------------------
175
176 //---------------------------------------------------------------------------
177 //  Get pointer to Circular Shared Buffer
178 //---------------------------------------------------------------------------
179
180 INLINE_FUNCTION tShbCirBuff *ShbCirGetBuffer(tShbInstance pShbInstance_p)
181 {
182
183         tShbCirBuff *pShbCirBuff;
184
185         pShbCirBuff = (tShbCirBuff *) ShbIpcGetShMemPtr(pShbInstance_p);
186         ASSERT(pShbCirBuff->m_ShbCirMagicID == SBC_MAGIC_ID);
187
188         return (pShbCirBuff);
189
190 }
191
192 //---------------------------------------------------------------------------
193 //  Get pointer to Linear Shared Buffer
194 //---------------------------------------------------------------------------
195
196 INLINE_FUNCTION tShbLinBuff *ShbLinGetBuffer(tShbInstance pShbInstance_p)
197 {
198
199         tShbLinBuff *pShbLinBuff;
200
201         pShbLinBuff = (tShbLinBuff *) ShbIpcGetShMemPtr(pShbInstance_p);
202         ASSERT(pShbLinBuff->m_ShbLinMagicID == SBL_MAGIC_ID);
203
204         return (pShbLinBuff);
205
206 }
207
208 // not inlined internal functions
209 int ShbCirSignalHandlerNewData(tShbInstance pShbInstance_p);
210 void ShbCirSignalHandlerReset(tShbInstance pShbInstance_p,
211                               unsigned int fTimeOut_p);
212
213 #endif
214
215 //=========================================================================//
216 //                                                                         //
217 //          P U B L I C   F U N C T I O N S                                //
218 //                                                                         //
219 //=========================================================================//
220
221 #if !defined(INLINE_ENABLED)
222 // not inlined external functions
223
224 //---------------------------------------------------------------------------
225 //  Initialize Shared Buffer Module
226 //---------------------------------------------------------------------------
227
228 tShbError ShbInit(void)
229 {
230
231         tShbError ShbError;
232
233         ShbError = ShbIpcInit();
234
235         return (ShbError);
236
237 }
238
239 //---------------------------------------------------------------------------
240 //  Deinitialize Shared Buffer Module
241 //---------------------------------------------------------------------------
242
243 tShbError ShbExit(void)
244 {
245
246         tShbError ShbError;
247
248         ShbError = ShbIpcExit();
249
250         return (ShbError);
251
252 }
253
254 //-------------------------------------------------------------------------//
255 //                                                                         //
256 //          C i r c u l a r   S h a r e d   B u f f e r                    //
257 //                                                                         //
258 //-------------------------------------------------------------------------//
259
260 //---------------------------------------------------------------------------
261 //  Allocate Circular Shared Buffer
262 //---------------------------------------------------------------------------
263
264 tShbError ShbCirAllocBuffer(unsigned long ulBufferSize_p,
265                             const char *pszBufferID_p,
266                             tShbInstance * ppShbInstance_p,
267                             unsigned int *pfShbNewCreated_p)
268 {
269
270         tShbInstance pShbInstance;
271         tShbCirBuff *pShbCirBuff;
272         unsigned int fShbNewCreated;
273         unsigned long ulBufferDataSize;
274         unsigned long ulBufferTotalSize;
275         tShbError ShbError;
276
277         // check arguments
278         if ((ulBufferSize_p == 0) || (ppShbInstance_p == NULL)) {
279                 return (kShbInvalidArg);
280         }
281
282         // calculate length of memory to allocate
283         ulBufferDataSize =
284             (ulBufferSize_p +
285              (SBC_BLOCK_ALIGNMENT - 1)) & ~(SBC_BLOCK_ALIGNMENT - 1);
286         ulBufferTotalSize = ulBufferDataSize + sizeof(tShbCirBuff);
287
288         // allocate a new or open an existing shared buffer
289         ShbError = ShbIpcAllocBuffer(ulBufferTotalSize, pszBufferID_p,
290                                      &pShbInstance, &fShbNewCreated);
291         if (ShbError != kShbOk) {
292                 goto Exit;
293         }
294
295         if (pShbInstance == NULL) {
296                 ShbError = kShbOutOfMem;
297                 goto Exit;
298         }
299
300         // get pointer to shared buffer
301         pShbCirBuff = (tShbCirBuff *) ShbIpcGetShMemPtr(pShbInstance);
302
303         // if the shared buffer was new created, than this process has
304         // to initialize it, otherwise the buffer is already in use
305         // and *must not* be reseted
306         if (fShbNewCreated) {
307 #ifndef NDEBUG
308                 {
309                         memset(pShbCirBuff, 0xCC, ulBufferTotalSize);
310                 }
311 #endif
312
313                 pShbCirBuff->m_ShbCirMagicID = SBC_MAGIC_ID;
314                 pShbCirBuff->m_ulBufferTotalSize = ulBufferTotalSize;
315                 pShbCirBuff->m_ulBufferDataSize = ulBufferDataSize;
316                 pShbCirBuff->m_ulWrIndex = 0;
317                 pShbCirBuff->m_ulRdIndex = 0;
318                 pShbCirBuff->m_ulNumOfWriteJobs = 0;
319                 pShbCirBuff->m_ulDataInUse = 0;
320                 pShbCirBuff->m_ulDataApended = 0;
321                 pShbCirBuff->m_ulBlocksApended = 0;
322                 pShbCirBuff->m_ulDataReadable = 0;
323                 pShbCirBuff->m_ulBlocksReadable = 0;
324                 pShbCirBuff->m_pfnSigHndlrNewData = NULL;
325                 pShbCirBuff->m_fBufferLocked = FALSE;
326                 pShbCirBuff->m_pfnSigHndlrReset = NULL;
327         } else {
328                 if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
329                         ShbError = kShbInvalidBufferType;
330                         goto Exit;
331                 }
332         }
333
334       Exit:
335
336         *ppShbInstance_p = pShbInstance;
337         *pfShbNewCreated_p = fShbNewCreated;
338
339         return (ShbError);
340
341 }
342
343 //---------------------------------------------------------------------------
344 //  Release Circular Shared Buffer
345 //---------------------------------------------------------------------------
346
347 tShbError ShbCirReleaseBuffer(tShbInstance pShbInstance_p)
348 {
349
350         tShbError ShbError;
351
352         // check arguments
353         if (pShbInstance_p == NULL) {
354                 ShbError = kShbOk;
355                 goto Exit;
356         }
357
358         ShbError = ShbIpcReleaseBuffer(pShbInstance_p);
359
360       Exit:
361
362         return (ShbError);
363
364 }
365
366 #endif // !defined(INLINE_ENABLED)
367
368 #if (!defined(SHAREDBUFF_INLINED)) || defined(INLINE_ENABLED)
369
370 //---------------------------------------------------------------------------
371 //  Reset Circular Shared Buffer
372 //---------------------------------------------------------------------------
373
374 INLINE_FUNCTION tShbError ShbCirResetBuffer(tShbInstance pShbInstance_p,
375                                             unsigned long ulTimeOut_p,
376                                             tShbCirSigHndlrReset
377                                             pfnSignalHandlerReset_p)
378 {
379
380         tShbCirBuff *pShbCirBuff;
381         unsigned long ulNumOfWriteJobs = 0;     // d.k. GCC complains about uninitialized variable otherwise
382         tShbError ShbError;
383
384         // check arguments
385         if (pShbInstance_p == NULL) {
386                 ShbError = kShbInvalidArg;
387                 goto Exit;
388         }
389
390         pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
391         ShbError = kShbOk;
392
393         if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
394                 ShbError = kShbInvalidBufferType;
395                 goto Exit;
396         }
397
398         // start reset job by setting request request in buffer header
399         ShbIpcEnterAtomicSection(pShbInstance_p);
400         {
401                 if (!pShbCirBuff->m_fBufferLocked) {
402                         ulNumOfWriteJobs = pShbCirBuff->m_ulNumOfWriteJobs;
403
404                         pShbCirBuff->m_fBufferLocked = TRUE;
405                         pShbCirBuff->m_pfnSigHndlrReset =
406                             pfnSignalHandlerReset_p;
407                 } else {
408                         ShbError = kShbAlreadyReseting;
409                 }
410         }
411         ShbIpcLeaveAtomicSection(pShbInstance_p);
412
413         if (ShbError != kShbOk) {
414                 goto Exit;
415         }
416
417         // if there is currently no running write operation then reset buffer
418         // immediately, otherwise wait until the last write job is ready by
419         // starting a signal process
420         if (ulNumOfWriteJobs == 0) {
421                 // there is currently no running write operation
422                 // -> reset buffer immediately
423                 ShbCirSignalHandlerReset(pShbInstance_p, FALSE);
424                 ShbError = kShbOk;
425         } else {
426                 // there is currently at least one running write operation
427                 // -> starting signal process to wait until the last write job is ready
428                 ShbError =
429                     ShbIpcStartSignalingJobReady(pShbInstance_p, ulTimeOut_p,
430                                                  ShbCirSignalHandlerReset);
431         }
432
433       Exit:
434
435         return (ShbError);
436
437 }
438
439 //---------------------------------------------------------------------------
440 //  Write data block to Circular Shared Buffer
441 //---------------------------------------------------------------------------
442
443 INLINE_FUNCTION tShbError ShbCirWriteDataBlock(tShbInstance pShbInstance_p,
444                                                const void *pSrcDataBlock_p,
445                                                unsigned long ulDataBlockSize_p)
446 {
447
448         tShbCirBuff *pShbCirBuff;
449         tShbCirBlockSize ShbCirBlockSize;
450         unsigned int uiFullBlockSize;
451         unsigned int uiAlignFillBytes;
452         unsigned char *pShbCirDataPtr;
453         unsigned char *pScrDataPtr;
454         unsigned long ulDataSize;
455         unsigned long ulChunkSize;
456         unsigned long ulWrIndex = 0;    // d.k. GCC complains about uninitialized variable otherwise
457         unsigned int fSignalNewData;
458         unsigned int fSignalReset;
459         tShbError ShbError;
460         tShbError ShbError2;
461         int fRes;
462
463         // check arguments
464         if (pShbInstance_p == NULL) {
465                 ShbError = kShbInvalidArg;
466                 goto Exit;
467         }
468
469         if ((pSrcDataBlock_p == NULL) || (ulDataBlockSize_p == 0)) {
470                 // nothing to do here
471                 ShbError = kShbOk;
472                 goto Exit;
473         }
474
475         if (ulDataBlockSize_p > SBC_MAX_BLOCK_SIZE) {
476                 ShbError = kShbExceedDataSizeLimit;
477                 goto Exit;
478         }
479
480         pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
481         pScrDataPtr = (unsigned char *)pSrcDataBlock_p;
482         fSignalNewData = FALSE;
483         fSignalReset = FALSE;
484         ShbError = kShbOk;
485
486         if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
487                 ShbError = kShbInvalidBufferType;
488                 goto Exit;
489         }
490
491         // calculate data block size in circular buffer
492         ulDataSize =
493             (ulDataBlockSize_p +
494              (SBC_BLOCK_ALIGNMENT - 1)) & ~(SBC_BLOCK_ALIGNMENT - 1);
495         uiFullBlockSize = ulDataSize + sizeof(tShbCirBlockSize);        // data size + header
496         uiAlignFillBytes = ulDataSize - ulDataBlockSize_p;
497
498         ShbCirBlockSize.m_uiFullBlockSize = uiFullBlockSize;
499         ShbCirBlockSize.m_uiAlignFillBytes = uiAlignFillBytes;
500
501         // reserve the needed memory for the write operation to do now
502         // and make necessary adjustments in the circular buffer header
503         ShbIpcEnterAtomicSection(pShbInstance_p);
504         {
505                 // check if there is sufficient memory available to store
506                 // the new data
507                 fRes =
508                     uiFullBlockSize <=
509                     (pShbCirBuff->m_ulBufferDataSize -
510                      pShbCirBuff->m_ulDataInUse);
511                 if (fRes) {
512                         // set write pointer for the write operation to do now
513                         // to the current write pointer of the circular buffer
514                         ulWrIndex = pShbCirBuff->m_ulWrIndex;
515
516                         // reserve the needed memory for the write operation to do now
517                         pShbCirBuff->m_ulDataInUse += uiFullBlockSize;
518
519                         // set new write pointer behind the reserved memory
520                         // for the write operation to do now
521                         pShbCirBuff->m_ulWrIndex += uiFullBlockSize;
522                         pShbCirBuff->m_ulWrIndex %=
523                             pShbCirBuff->m_ulBufferDataSize;
524
525                         // increment number of currently (parallel running)
526                         // write operations
527                         pShbCirBuff->m_ulNumOfWriteJobs++;
528                 }
529         }
530         ShbIpcLeaveAtomicSection(pShbInstance_p);
531
532         if (!fRes) {
533                 ShbError = kShbBufferFull;
534                 goto Exit;
535         }
536
537         // copy the data to the circular buffer
538         // (the copy process itself will be done outside of any
539         // critical/locked section)
540         pShbCirDataPtr = &pShbCirBuff->m_Data;  // ptr to start of data area
541
542         // write real size of current block (incl. alignment fill bytes)
543         *(tShbCirBlockSize *) (pShbCirDataPtr + ulWrIndex) = ShbCirBlockSize;
544         ulWrIndex += sizeof(tShbCirBlockSize);
545         ulWrIndex %= pShbCirBuff->m_ulBufferDataSize;
546
547         if (ulWrIndex + ulDataBlockSize_p <= pShbCirBuff->m_ulBufferDataSize) {
548                 // linear write operation
549                 memcpy(pShbCirDataPtr + ulWrIndex, pScrDataPtr,
550                        ulDataBlockSize_p);
551         } else {
552                 // wrap-around write operation
553                 ulChunkSize = pShbCirBuff->m_ulBufferDataSize - ulWrIndex;
554                 memcpy(pShbCirDataPtr + ulWrIndex, pScrDataPtr, ulChunkSize);
555                 memcpy(pShbCirDataPtr, pScrDataPtr + ulChunkSize,
556                        ulDataBlockSize_p - ulChunkSize);
557         }
558
559         // adjust header information for circular buffer with properties
560         // of the wiritten data block
561         ShbIpcEnterAtomicSection(pShbInstance_p);
562         {
563                 pShbCirBuff->m_ulDataApended += uiFullBlockSize;
564                 pShbCirBuff->m_ulBlocksApended++;
565
566                 // decrement number of currently (parallel running) write operations
567                 if (!--pShbCirBuff->m_ulNumOfWriteJobs) {
568                         // if there is no other write process running then
569                         // set new size of readable (complete written) data and
570                         // adjust number of readable blocks
571                         pShbCirBuff->m_ulDataReadable +=
572                             pShbCirBuff->m_ulDataApended;
573                         pShbCirBuff->m_ulBlocksReadable +=
574                             pShbCirBuff->m_ulBlocksApended;
575
576                         pShbCirBuff->m_ulDataApended = 0;
577                         pShbCirBuff->m_ulBlocksApended = 0;
578
579                         fSignalNewData = TRUE;
580                         fSignalReset = pShbCirBuff->m_fBufferLocked;
581                 }
582         }
583         ShbIpcLeaveAtomicSection(pShbInstance_p);
584
585         // signal new data event to a potentially reading application
586         if (fSignalNewData) {
587                 ShbError2 = ShbIpcSignalNewData(pShbInstance_p);
588                 if (ShbError == kShbOk) {
589                         ShbError = ShbError2;
590                 }
591         }
592         // signal that the last write job has been finished to allow
593         // a waiting application to reset the buffer now
594         if (fSignalReset) {
595                 ShbError2 = ShbIpcSignalJobReady(pShbInstance_p);
596                 if (ShbError == kShbOk) {
597                         ShbError = ShbError2;
598                 }
599         }
600
601       Exit:
602
603         return (ShbError);
604
605 }
606
607 //---------------------------------------------------------------------------
608 //  Allocate block within the Circular Shared Buffer for chunk writing
609 //---------------------------------------------------------------------------
610
611 INLINE_FUNCTION tShbError ShbCirAllocDataBlock(tShbInstance pShbInstance_p,
612                                                tShbCirChunk * pShbCirChunk_p,
613                                                unsigned long ulDataBufferSize_p)
614 {
615
616         tShbCirBuff *pShbCirBuff;
617         tShbCirBlockSize ShbCirBlockSize;
618         unsigned int uiFullBlockSize;
619         unsigned int uiAlignFillBytes;
620         unsigned char *pShbCirDataPtr;
621         unsigned long ulDataSize;
622         unsigned long ulWrIndex = 0;    // d.k. GCC complains about uninitialized variable otherwise
623         tShbError ShbError;
624         int fRes;
625
626         // check arguments
627         if ((pShbInstance_p == NULL) || (pShbCirChunk_p == NULL)) {
628                 ShbError = kShbInvalidArg;
629                 goto Exit;
630         }
631
632         if (ulDataBufferSize_p == 0) {
633                 ShbError = kShbInvalidArg;
634                 goto Exit;
635         }
636
637         if (ulDataBufferSize_p > SBC_MAX_BLOCK_SIZE) {
638                 ShbError = kShbExceedDataSizeLimit;
639                 goto Exit;
640         }
641
642         pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
643         ShbError = kShbOk;
644
645         if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
646                 ShbError = kShbInvalidBufferType;
647                 goto Exit;
648         }
649
650         // calculate data block size in circular buffer
651         ulDataSize =
652             (ulDataBufferSize_p +
653              (SBC_BLOCK_ALIGNMENT - 1)) & ~(SBC_BLOCK_ALIGNMENT - 1);
654         uiFullBlockSize = ulDataSize + sizeof(tShbCirBlockSize);        // data size + header
655         uiAlignFillBytes = ulDataSize - ulDataBufferSize_p;
656
657         ShbCirBlockSize.m_uiFullBlockSize = uiFullBlockSize;
658         ShbCirBlockSize.m_uiAlignFillBytes = uiAlignFillBytes;
659
660         // reserve the needed memory for the write operation to do now
661         // and make necessary adjustments in the circular buffer header
662         ShbIpcEnterAtomicSection(pShbInstance_p);
663         {
664                 // check if there is sufficient memory available to store
665                 // the new data
666                 fRes =
667                     (uiFullBlockSize <=
668                      (pShbCirBuff->m_ulBufferDataSize -
669                       pShbCirBuff->m_ulDataInUse));
670                 if (fRes) {
671                         // set write pointer for the write operation to do now
672                         // to the current write pointer of the circular buffer
673                         ulWrIndex = pShbCirBuff->m_ulWrIndex;
674
675                         // reserve the needed memory for the write operation to do now
676                         pShbCirBuff->m_ulDataInUse += uiFullBlockSize;
677
678                         // set new write pointer behind the reserved memory
679                         // for the write operation to do now
680                         pShbCirBuff->m_ulWrIndex += uiFullBlockSize;
681                         pShbCirBuff->m_ulWrIndex %=
682                             pShbCirBuff->m_ulBufferDataSize;
683
684                         // increment number of currently (parallel running)
685                         // write operations
686                         pShbCirBuff->m_ulNumOfWriteJobs++;
687                 }
688         }
689         ShbIpcLeaveAtomicSection(pShbInstance_p);
690
691         if (!fRes) {
692                 ShbError = kShbBufferFull;
693                 goto Exit;
694         }
695
696         // setup header information for allocated buffer
697         pShbCirDataPtr = &pShbCirBuff->m_Data;  // ptr to start of data area
698
699         // write real size of current block (incl. alignment fill bytes)
700         *(tShbCirBlockSize *) (pShbCirDataPtr + ulWrIndex) = ShbCirBlockSize;
701         ulWrIndex += sizeof(tShbCirBlockSize);
702         ulWrIndex %= pShbCirBuff->m_ulBufferDataSize;
703
704         // setup chunk descriptor
705         pShbCirChunk_p->m_uiFullBlockSize = uiFullBlockSize;
706         pShbCirChunk_p->m_ulAvailableSize = ulDataBufferSize_p;
707         pShbCirChunk_p->m_ulWrIndex = ulWrIndex;
708         pShbCirChunk_p->m_fBufferCompleted = FALSE;
709
710       Exit:
711
712         return (ShbError);
713
714 }
715
716 //---------------------------------------------------------------------------
717 //  Write data chunk into an allocated buffer of the Circular Shared Buffer
718 //---------------------------------------------------------------------------
719
720 INLINE_FUNCTION tShbError ShbCirWriteDataChunk(tShbInstance pShbInstance_p,
721                                                tShbCirChunk * pShbCirChunk_p,
722                                                const void *pSrcDataChunk_p,
723                                                unsigned long ulDataChunkSize_p,
724                                                unsigned int
725                                                *pfBufferCompleted_p)
726 {
727
728         tShbCirBuff *pShbCirBuff;
729         unsigned char *pShbCirDataPtr;
730         unsigned char *pScrDataPtr;
731         unsigned long ulSubChunkSize;
732         unsigned long ulWrIndex;
733         unsigned int fBufferCompleted;
734         unsigned int fSignalNewData;
735         unsigned int fSignalReset;
736         tShbError ShbError;
737         tShbError ShbError2;
738
739         // check arguments
740         if ((pShbInstance_p == NULL) || (pShbCirChunk_p == NULL)
741             || (pfBufferCompleted_p == NULL)) {
742                 ShbError = kShbInvalidArg;
743                 goto Exit;
744         }
745
746         if ((pSrcDataChunk_p == NULL) || (ulDataChunkSize_p == 0)) {
747                 // nothing to do here
748                 ShbError = kShbOk;
749                 goto Exit;
750         }
751
752         if (pShbCirChunk_p->m_fBufferCompleted) {
753                 ShbError = kShbBufferAlreadyCompleted;
754                 goto Exit;
755         }
756
757         if (ulDataChunkSize_p > pShbCirChunk_p->m_ulAvailableSize) {
758                 ShbError = kShbExceedDataSizeLimit;
759                 goto Exit;
760         }
761
762         pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
763         pScrDataPtr = (unsigned char *)pSrcDataChunk_p;
764         fSignalNewData = FALSE;
765         fSignalReset = FALSE;
766         ShbError = kShbOk;
767
768         if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
769                 ShbError = kShbInvalidBufferType;
770                 goto Exit;
771         }
772
773         ulWrIndex = pShbCirChunk_p->m_ulWrIndex;
774
775         // copy the data to the circular buffer
776         // (the copy process itself will be done outside of any
777         // critical/locked section)
778         pShbCirDataPtr = &pShbCirBuff->m_Data;  // ptr to start of data area
779
780         if (ulWrIndex + ulDataChunkSize_p <= pShbCirBuff->m_ulBufferDataSize) {
781                 // linear write operation
782                 memcpy(pShbCirDataPtr + ulWrIndex, pScrDataPtr,
783                        ulDataChunkSize_p);
784         } else {
785                 // wrap-around write operation
786                 ulSubChunkSize = pShbCirBuff->m_ulBufferDataSize - ulWrIndex;
787                 memcpy(pShbCirDataPtr + ulWrIndex, pScrDataPtr, ulSubChunkSize);
788                 memcpy(pShbCirDataPtr, pScrDataPtr + ulSubChunkSize,
789                        ulDataChunkSize_p - ulSubChunkSize);
790         }
791
792         // adjust chunk descriptor
793         ulWrIndex += ulDataChunkSize_p;
794         ulWrIndex %= pShbCirBuff->m_ulBufferDataSize;
795
796         pShbCirChunk_p->m_ulAvailableSize -= ulDataChunkSize_p;
797         pShbCirChunk_p->m_ulWrIndex = ulWrIndex;
798
799         fBufferCompleted = (pShbCirChunk_p->m_ulAvailableSize == 0);
800         pShbCirChunk_p->m_fBufferCompleted = fBufferCompleted;
801
802         // if the complete allocated buffer is filled with data then
803         // adjust header information for circular buffer with properties
804         // of the wiritten data block
805         if (fBufferCompleted) {
806                 ShbIpcEnterAtomicSection(pShbInstance_p);
807                 {
808                         pShbCirBuff->m_ulDataApended +=
809                             pShbCirChunk_p->m_uiFullBlockSize;
810                         pShbCirBuff->m_ulBlocksApended++;
811
812                         // decrement number of currently (parallel running) write operations
813                         if (!--pShbCirBuff->m_ulNumOfWriteJobs) {
814                                 // if there is no other write process running then
815                                 // set new size of readable (complete written) data and
816                                 // adjust number of readable blocks
817                                 pShbCirBuff->m_ulDataReadable +=
818                                     pShbCirBuff->m_ulDataApended;
819                                 pShbCirBuff->m_ulBlocksReadable +=
820                                     pShbCirBuff->m_ulBlocksApended;
821
822                                 pShbCirBuff->m_ulDataApended = 0;
823                                 pShbCirBuff->m_ulBlocksApended = 0;
824
825                                 fSignalNewData = TRUE;
826                                 fSignalReset = pShbCirBuff->m_fBufferLocked;
827                         }
828                 }
829                 ShbIpcLeaveAtomicSection(pShbInstance_p);
830         }
831
832         // signal new data event to a potentially reading application
833         if (fSignalNewData) {
834                 ShbError2 = ShbIpcSignalNewData(pShbInstance_p);
835                 if (ShbError == kShbOk) {
836                         ShbError = ShbError2;
837                 }
838         }
839         // signal that the last write job has been finished to allow
840         // a waiting application to reset the buffer now
841         if (fSignalReset) {
842                 ShbError2 = ShbIpcSignalJobReady(pShbInstance_p);
843                 if (ShbError == kShbOk) {
844                         ShbError = ShbError2;
845                 }
846         }
847
848         *pfBufferCompleted_p = fBufferCompleted;
849
850       Exit:
851
852         return (ShbError);
853
854 }
855
856 //---------------------------------------------------------------------------
857 //  Read data block from Circular Shared Buffer
858 //---------------------------------------------------------------------------
859
860 INLINE_FUNCTION tShbError ShbCirReadDataBlock(tShbInstance pShbInstance_p,
861                                               void *pDstDataBlock_p,
862                                               unsigned long ulRdBuffSize_p,
863                                               unsigned long *pulDataBlockSize_p)
864 {
865
866         tShbCirBuff *pShbCirBuff;
867         tShbCirBlockSize ShbCirBlockSize;
868         unsigned long ulDataReadable;
869         unsigned char *pShbCirDataPtr;
870         unsigned char *pDstDataPtr;
871         unsigned long ulDataSize = 0;   // d.k. GCC complains about uninitialized variable otherwise
872         unsigned long ulChunkSize;
873         unsigned long ulRdIndex;
874         tShbError ShbError;
875
876         // check arguments
877         if ((pShbInstance_p == NULL) || (pulDataBlockSize_p == NULL)) {
878                 return (kShbInvalidArg);
879         }
880
881         if ((pDstDataBlock_p == NULL) || (ulRdBuffSize_p == 0)) {
882                 // nothing to do here
883                 ShbError = kShbOk;
884                 goto Exit;
885         }
886
887         ShbError = kShbOk;
888         pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
889         pDstDataPtr = (unsigned char *)pDstDataBlock_p;
890         ulDataSize = 0;
891
892         if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
893                 ShbError = kShbInvalidBufferType;
894                 goto Exit;
895         }
896
897         // get total number of readable bytes for the whole circular buffer
898         ShbIpcEnterAtomicSection(pShbInstance_p);
899         {
900                 ulDataReadable = pShbCirBuff->m_ulDataReadable;
901         }
902         ShbIpcLeaveAtomicSection(pShbInstance_p);
903
904         // if there are readable data available, then there must be at least
905         // one complete readable data block
906         if (ulDataReadable > 0) {
907                 // get pointer to start of data area and current read index
908                 pShbCirDataPtr = &pShbCirBuff->m_Data;  // ptr to start of data area
909                 ulRdIndex = pShbCirBuff->m_ulRdIndex;
910
911                 // get real size of current block (incl. alignment fill bytes)
912                 ShbCirBlockSize =
913                     *(tShbCirBlockSize *) (pShbCirDataPtr + ulRdIndex);
914                 ulRdIndex += sizeof(tShbCirBlockSize);
915                 ulRdIndex %= pShbCirBuff->m_ulBufferDataSize;
916
917                 // get size of user data inside the current block
918                 ulDataSize =
919                     ShbCirBlockSize.m_uiFullBlockSize -
920                     ShbCirBlockSize.m_uiAlignFillBytes;
921                 ulDataSize -= sizeof(tShbCirBlockSize);
922         }
923
924         // ulDataSize = MIN(ulDataSize, ulRdBuffSize_p);
925         if (ulDataSize > ulRdBuffSize_p) {
926                 ulDataSize = ulRdBuffSize_p;
927                 ShbError = kShbDataTruncated;
928         }
929
930         if (ulDataSize == 0) {
931                 // nothing to do here
932                 ShbError = kShbNoReadableData;
933                 goto Exit;
934         }
935
936         // copy the data from the circular buffer
937         // (the copy process itself will be done outside of any
938         // critical/locked section)
939         if (ulRdIndex + ulDataSize <= pShbCirBuff->m_ulBufferDataSize) {
940                 // linear read operation
941                 memcpy(pDstDataPtr, pShbCirDataPtr + ulRdIndex, ulDataSize);
942         } else {
943                 // wrap-around read operation
944                 ulChunkSize = pShbCirBuff->m_ulBufferDataSize - ulRdIndex;
945                 memcpy(pDstDataPtr, pShbCirDataPtr + ulRdIndex, ulChunkSize);
946                 memcpy(pDstDataPtr + ulChunkSize, pShbCirDataPtr,
947                        ulDataSize - ulChunkSize);
948         }
949
950 #ifndef NDEBUG
951         {
952                 tShbCirBlockSize ClrShbCirBlockSize;
953
954                 if (ulRdIndex + ulDataSize <= pShbCirBuff->m_ulBufferDataSize) {
955                         // linear buffer
956                         memset(pShbCirDataPtr + ulRdIndex, 0xDD, ulDataSize);
957                 } else {
958                         // wrap-around read operation
959                         ulChunkSize =
960                             pShbCirBuff->m_ulBufferDataSize - ulRdIndex;
961                         memset(pShbCirDataPtr + ulRdIndex, 0xDD, ulChunkSize);
962                         memset(pShbCirDataPtr, 0xDD, ulDataSize - ulChunkSize);
963                 }
964
965                 ClrShbCirBlockSize.m_uiFullBlockSize = /*(unsigned int) */ -1;  // -1 = xFFFFFFF
966                 ClrShbCirBlockSize.m_uiAlignFillBytes = /*(unsigned int) */ -1; // -1 = Fxxxxxxx
967                 *(tShbCirBlockSize *) (pShbCirDataPtr +
968                                        pShbCirBuff->m_ulRdIndex) =
969                     ClrShbCirBlockSize;
970         }
971 #endif // #ifndef NDEBUG
972
973         // set new size of readable data, data in use, new read index
974         // and adjust number of readable blocks
975         ShbIpcEnterAtomicSection(pShbInstance_p);
976         {
977                 pShbCirBuff->m_ulDataInUse -= ShbCirBlockSize.m_uiFullBlockSize;
978                 pShbCirBuff->m_ulDataReadable -=
979                     ShbCirBlockSize.m_uiFullBlockSize;
980                 pShbCirBuff->m_ulBlocksReadable--;
981
982                 //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
983                 if ((pShbCirBuff->m_ulDataInUse == 0)
984                     && (pShbCirBuff->m_ulDataReadable == 0)) {
985                         ASSERT(pShbCirBuff->m_ulBlocksReadable == 0);
986
987                         pShbCirBuff->m_ulWrIndex = 0;
988                         pShbCirBuff->m_ulRdIndex = 0;
989                 } else
990                         //$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
991                 {
992                         pShbCirBuff->m_ulRdIndex +=
993                             ShbCirBlockSize.m_uiFullBlockSize;
994                         pShbCirBuff->m_ulRdIndex %=
995                             pShbCirBuff->m_ulBufferDataSize;
996                 }
997         }
998         ShbIpcLeaveAtomicSection(pShbInstance_p);
999
1000       Exit:
1001
1002         *pulDataBlockSize_p = ulDataSize;
1003
1004         return (ShbError);
1005
1006 }
1007
1008 //---------------------------------------------------------------------------
1009 //  Get data size of next readable block from Circular Shared Buffer
1010 //---------------------------------------------------------------------------
1011
1012 INLINE_FUNCTION tShbError ShbCirGetReadDataSize(tShbInstance pShbInstance_p,
1013                                                 unsigned long
1014                                                 *pulDataBlockSize_p)
1015 {
1016
1017         tShbCirBuff *pShbCirBuff;
1018         unsigned long ulDataReadable;
1019         unsigned char *pShbCirDataPtr;
1020         tShbCirBlockSize ShbCirBlockSize;
1021         unsigned long ulDataSize;
1022         tShbError ShbError;
1023
1024         // check arguments
1025         if ((pShbInstance_p == NULL) || (pulDataBlockSize_p == NULL)) {
1026                 return (kShbInvalidArg);
1027         }
1028
1029         pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
1030         ulDataSize = 0;
1031         ShbError = kShbOk;
1032
1033         if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
1034                 ShbError = kShbInvalidBufferType;
1035                 goto Exit;
1036         }
1037
1038         // get total number of readable bytes for the whole circular buffer
1039         ShbIpcEnterAtomicSection(pShbInstance_p);
1040         {
1041                 ulDataReadable = pShbCirBuff->m_ulDataReadable;
1042         }
1043         ShbIpcLeaveAtomicSection(pShbInstance_p);
1044
1045         // if there are readable data available, then there must be at least
1046         // one complete readable data block
1047         if (ulDataReadable > 0) {
1048                 pShbCirDataPtr =
1049                     &pShbCirBuff->m_Data + pShbCirBuff->m_ulRdIndex;
1050
1051                 // get real size of current block (incl. alignment fill bytes)
1052                 ShbCirBlockSize = *(tShbCirBlockSize *) pShbCirDataPtr;
1053
1054                 // get size of user data inside the current block
1055                 ulDataSize =
1056                     ShbCirBlockSize.m_uiFullBlockSize -
1057                     ShbCirBlockSize.m_uiAlignFillBytes;
1058                 ulDataSize -= sizeof(tShbCirBlockSize);
1059         }
1060
1061       Exit:
1062
1063         *pulDataBlockSize_p = ulDataSize;
1064
1065         return (ShbError);
1066
1067 }
1068
1069 //---------------------------------------------------------------------------
1070 //  Get number of readable blocks from Circular Shared Buffer
1071 //---------------------------------------------------------------------------
1072
1073 INLINE_FUNCTION tShbError ShbCirGetReadBlockCount(tShbInstance pShbInstance_p,
1074                                                   unsigned long
1075                                                   *pulDataBlockCount_p)
1076 {
1077
1078         tShbCirBuff *pShbCirBuff;
1079         unsigned long ulBlockCount;
1080         tShbError ShbError;
1081
1082         // check arguments
1083         if ((pShbInstance_p == NULL) || (pulDataBlockCount_p == NULL)) {
1084                 ShbError = kShbInvalidArg;
1085                 goto Exit;
1086         }
1087
1088         pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
1089         ulBlockCount = 0;
1090         ShbError = kShbOk;
1091
1092         if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
1093                 ShbError = kShbInvalidBufferType;
1094                 goto Exit;
1095         }
1096
1097         ShbIpcEnterAtomicSection(pShbInstance_p);
1098         {
1099                 ulBlockCount = pShbCirBuff->m_ulBlocksReadable;
1100         }
1101         ShbIpcLeaveAtomicSection(pShbInstance_p);
1102
1103         *pulDataBlockCount_p = ulBlockCount;
1104
1105       Exit:
1106
1107         return (ShbError);
1108
1109 }
1110
1111 //---------------------------------------------------------------------------
1112 //  Set application handler to signal new data for Circular Shared Buffer
1113 //  d.k.: new parameter priority as enum
1114 //---------------------------------------------------------------------------
1115
1116 INLINE_FUNCTION tShbError ShbCirSetSignalHandlerNewData(tShbInstance
1117                                                         pShbInstance_p,
1118                                                         tShbCirSigHndlrNewData
1119                                                         pfnSignalHandlerNewData_p,
1120                                                         tShbPriority
1121                                                         ShbPriority_p)
1122 {
1123
1124         tShbCirBuff *pShbCirBuff;
1125         tShbError ShbError;
1126
1127         // check arguments
1128         if (pShbInstance_p == NULL) {
1129                 ShbError = kShbInvalidArg;
1130                 goto Exit;
1131         }
1132
1133         pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
1134         ShbError = kShbOk;
1135
1136         if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
1137                 ShbError = kShbInvalidBufferType;
1138                 goto Exit;
1139         }
1140
1141         if (pfnSignalHandlerNewData_p != NULL) {
1142                 // set a new signal handler
1143                 if (pShbCirBuff->m_pfnSigHndlrNewData != NULL) {
1144                         ShbError = kShbAlreadySignaling;
1145                         goto Exit;
1146                 }
1147
1148                 pShbCirBuff->m_pfnSigHndlrNewData = pfnSignalHandlerNewData_p;
1149                 ShbError =
1150                     ShbIpcStartSignalingNewData(pShbInstance_p,
1151                                                 ShbCirSignalHandlerNewData,
1152                                                 ShbPriority_p);
1153         } else {
1154                 // remove existing signal handler
1155                 ShbError = ShbIpcStopSignalingNewData(pShbInstance_p);
1156                 if (pShbCirBuff->m_pfnSigHndlrNewData != NULL) {
1157                         pShbCirBuff->m_pfnSigHndlrNewData(pShbInstance_p, 0);
1158                 }
1159                 pShbCirBuff->m_pfnSigHndlrNewData = NULL;
1160         }
1161
1162       Exit:
1163
1164         return (ShbError);
1165
1166 }
1167
1168 #endif
1169
1170 #if !defined(INLINE_ENABLED)
1171
1172 //---------------------------------------------------------------------------
1173 //  DEBUG: Trace Circular Shared Buffer
1174 //---------------------------------------------------------------------------
1175
1176 #ifndef NDEBUG
1177 tShbError ShbCirTraceBuffer(tShbInstance pShbInstance_p)
1178 {
1179
1180         tShbCirBuff *pShbCirBuff;
1181         char szMagigID[sizeof(SBC_MAGIC_ID) + 1];
1182         tShbCirBlockSize ShbCirBlockSize;
1183         unsigned long ulDataReadable;
1184         unsigned char *pShbCirDataPtr;
1185         unsigned long ulBlockIndex;
1186         unsigned int nBlockCount;
1187         unsigned long ulDataSize;
1188         unsigned long ulChunkSize;
1189         unsigned long ulRdIndex;
1190         tShbError ShbError;
1191
1192         TRACE0("\n\n##### Circular Shared Buffer #####\n");
1193
1194         // check arguments
1195         if (pShbInstance_p == NULL) {
1196                 TRACE1("\nERROR: invalid buffer address (0x%08lX)\n",
1197                        (unsigned long)pShbInstance_p);
1198                 ShbError = kShbInvalidArg;
1199                 goto Exit;
1200         }
1201
1202         pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
1203         ShbError = kShbOk;
1204
1205         if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
1206                 ShbError = kShbInvalidBufferType;
1207                 goto Exit;
1208         }
1209
1210         *(unsigned long *)&szMagigID[0] = pShbCirBuff->m_ShbCirMagicID;
1211         szMagigID[sizeof(SBC_MAGIC_ID)] = '\0';
1212
1213         ShbIpcEnterAtomicSection(pShbInstance_p);
1214         {
1215                 TRACE1("\nBuffer Address:   0x%08lX\n",
1216                        (unsigned long)pShbCirBuff);
1217
1218                 TRACE0("\nHeader Info:");
1219                 TRACE2("\nMagigID:          '%s' (%08lX)", szMagigID,
1220                        pShbCirBuff->m_ShbCirMagicID);
1221                 TRACE1("\nBufferTotalSize:  %4lu [Bytes]",
1222                        pShbCirBuff->m_ulBufferTotalSize);
1223                 TRACE1("\nBufferDataSize:   %4lu [Bytes]",
1224                        pShbCirBuff->m_ulBufferDataSize);
1225                 TRACE1("\nWrIndex:          %4lu", pShbCirBuff->m_ulWrIndex);
1226                 TRACE1("\nRdIndex:          %4lu", pShbCirBuff->m_ulRdIndex);
1227                 TRACE1("\nNumOfWriteJobs:   %4lu",
1228                        pShbCirBuff->m_ulNumOfWriteJobs);
1229                 TRACE1("\nDataInUse:        %4lu [Bytes]",
1230                        pShbCirBuff->m_ulDataInUse);
1231                 TRACE1("\nDataApended:      %4lu [Bytes]",
1232                        pShbCirBuff->m_ulDataApended);
1233                 TRACE1("\nBlocksApended:    %4lu",
1234                        pShbCirBuff->m_ulBlocksApended);
1235                 TRACE1("\nDataReadable:     %4lu [Bytes]",
1236                        pShbCirBuff->m_ulDataReadable);
1237                 TRACE1("\nBlocksReadable:   %4lu",
1238                        pShbCirBuff->m_ulBlocksReadable);
1239                 TRACE1("\nSigHndlrNewData:  %08lX",
1240                        (unsigned long)pShbCirBuff->m_pfnSigHndlrNewData);
1241                 TRACE1("\nBufferLocked:     %d", pShbCirBuff->m_fBufferLocked);
1242                 TRACE1("\nSigHndlrReset:    %08lX",
1243                        (unsigned long)pShbCirBuff->m_pfnSigHndlrReset);
1244
1245                 ShbTraceDump(&pShbCirBuff->m_Data,
1246                              pShbCirBuff->m_ulBufferDataSize, 0x00000000L,
1247                              "\nData Area:");
1248
1249                 ulDataReadable = pShbCirBuff->m_ulDataReadable;
1250                 nBlockCount = 1;
1251                 ulBlockIndex = pShbCirBuff->m_ulRdIndex;
1252
1253                 while (ulDataReadable > 0) {
1254                         TRACE1("\n\n--- Block #%u ---", nBlockCount);
1255
1256                         // get pointer to start of data area and current read index
1257                         pShbCirDataPtr = &pShbCirBuff->m_Data;  // ptr to start of data area
1258                         ulRdIndex = ulBlockIndex;
1259
1260                         // get real size of current block (incl. alignment fill bytes)
1261                         ShbCirBlockSize =
1262                             *(tShbCirBlockSize *) (pShbCirDataPtr + ulRdIndex);
1263                         ulRdIndex += sizeof(tShbCirBlockSize);
1264                         ulRdIndex %= pShbCirBuff->m_ulBufferDataSize;
1265
1266                         // get size of user data inside the current block
1267                         ulDataSize =
1268                             ShbCirBlockSize.m_uiFullBlockSize -
1269                             ShbCirBlockSize.m_uiAlignFillBytes;
1270                         ulDataSize -= sizeof(tShbCirBlockSize);
1271
1272                         TRACE1
1273                             ("\nFull Data Size:       %4u [Bytes] (incl. header and alignment fill bytes)",
1274                              ShbCirBlockSize.m_uiFullBlockSize);
1275                         TRACE1("\nUser Data Size:       %4lu [Bytes]",
1276                                ulDataSize);
1277                         TRACE1("\nAlignment Fill Bytes: %4u [Bytes]",
1278                                ShbCirBlockSize.m_uiAlignFillBytes);
1279
1280                         if (ulRdIndex + ulDataSize <=
1281                             pShbCirBuff->m_ulBufferDataSize) {
1282                                 // linear data buffer
1283                                 ShbTraceDump(pShbCirDataPtr + ulRdIndex,
1284                                              ulDataSize, 0x00000000L, NULL);
1285                         } else {
1286                                 // wrap-around data buffer
1287                                 ulChunkSize =
1288                                     pShbCirBuff->m_ulBufferDataSize - ulRdIndex;
1289                                 ShbTraceDump(pShbCirDataPtr + ulRdIndex,
1290                                              ulChunkSize, 0x00000000L, NULL);
1291                                 ShbTraceDump(pShbCirDataPtr,
1292                                              ulDataSize - ulChunkSize,
1293                                              ulChunkSize, NULL);
1294                         }
1295
1296                         nBlockCount++;
1297
1298                         ulBlockIndex += ShbCirBlockSize.m_uiFullBlockSize;
1299                         ulBlockIndex %= pShbCirBuff->m_ulBufferDataSize;
1300
1301                         ulDataReadable -= ShbCirBlockSize.m_uiFullBlockSize;
1302                 }
1303
1304                 ASSERT(pShbCirBuff->m_ulBlocksReadable == nBlockCount - 1);
1305         }
1306         ShbIpcLeaveAtomicSection(pShbInstance_p);
1307
1308       Exit:
1309
1310         return (ShbError);
1311
1312 }
1313 #endif
1314
1315 //-------------------------------------------------------------------------//
1316 //                                                                         //
1317 //          L i n e a r   S h a r e d   B u f f e r                        //
1318 //                                                                         //
1319 //-------------------------------------------------------------------------//
1320
1321 //---------------------------------------------------------------------------
1322 //  Allocate Linear Shared Buffer
1323 //---------------------------------------------------------------------------
1324
1325 tShbError ShbLinAllocBuffer(unsigned long ulBufferSize_p,
1326                             const char *pszBufferID_p,
1327                             tShbInstance * ppShbInstance_p,
1328                             unsigned int *pfShbNewCreated_p)
1329 {
1330
1331         tShbInstance pShbInstance;
1332         tShbLinBuff *pShbLinBuff;
1333         unsigned int fShbNewCreated;
1334         unsigned long ulBufferDataSize;
1335         unsigned long ulBufferTotalSize;
1336         tShbError ShbError;
1337
1338         // check arguments
1339         if ((ulBufferSize_p == 0) || (ppShbInstance_p == NULL)) {
1340                 return (kShbInvalidArg);
1341         }
1342
1343         // calculate length of memory to allocate
1344         ulBufferDataSize =
1345             (ulBufferSize_p +
1346              (SBL_BLOCK_ALIGNMENT - 1)) & ~(SBL_BLOCK_ALIGNMENT - 1);
1347         ulBufferTotalSize = ulBufferDataSize + sizeof(tShbLinBuff);
1348
1349         // allocate a new or open an existing shared buffer
1350         ShbError = ShbIpcAllocBuffer(ulBufferTotalSize, pszBufferID_p,
1351                                      &pShbInstance, &fShbNewCreated);
1352         if (ShbError != kShbOk) {
1353                 goto Exit;
1354         }
1355
1356         if (pShbInstance == NULL) {
1357                 ShbError = kShbOutOfMem;
1358                 goto Exit;
1359         }
1360
1361         // get pointer to shared buffer
1362         pShbLinBuff = (tShbLinBuff *) ShbIpcGetShMemPtr(pShbInstance);
1363
1364         // if the shared buffer was new created, than this process has
1365         // to initialize it, otherwise the buffer is already in use
1366         // and *must not* be reseted
1367         if (fShbNewCreated) {
1368 #ifndef NDEBUG
1369                 {
1370                         memset(pShbLinBuff, 0xCC, ulBufferTotalSize);
1371                 }
1372 #endif
1373
1374                 pShbLinBuff->m_ShbLinMagicID = SBL_MAGIC_ID;
1375                 pShbLinBuff->m_ulBufferTotalSize = ulBufferTotalSize;
1376                 pShbLinBuff->m_ulBufferDataSize = ulBufferDataSize;
1377         } else {
1378                 if (pShbLinBuff->m_ShbLinMagicID != SBL_MAGIC_ID) {
1379                         ShbError = kShbInvalidBufferType;
1380                         goto Exit;
1381                 }
1382         }
1383
1384       Exit:
1385
1386         *ppShbInstance_p = pShbInstance;
1387         *pfShbNewCreated_p = fShbNewCreated;
1388
1389         return (ShbError);
1390
1391 }
1392
1393 //---------------------------------------------------------------------------
1394 //  Release Linear Shared Buffer
1395 //---------------------------------------------------------------------------
1396
1397 tShbError ShbLinReleaseBuffer(tShbInstance pShbInstance_p)
1398 {
1399
1400         tShbError ShbError;
1401
1402         // check arguments
1403         if (pShbInstance_p == NULL) {
1404                 ShbError = kShbOk;
1405                 goto Exit;
1406         }
1407
1408         ShbError = ShbIpcReleaseBuffer(pShbInstance_p);
1409
1410       Exit:
1411
1412         return (ShbError);
1413
1414 }
1415
1416 #endif // !defined(INLINE_ENABLED)
1417
1418 #if (!defined(SHAREDBUFF_INLINED)) || defined(INLINE_ENABLED)
1419
1420 //---------------------------------------------------------------------------
1421 //  Write data block to Linear Shared Buffer
1422 //---------------------------------------------------------------------------
1423
1424 INLINE_FUNCTION tShbError ShbLinWriteDataBlock(tShbInstance pShbInstance_p,
1425                                                unsigned long ulDstBufferOffs_p,
1426                                                const void *pSrcDataBlock_p,
1427                                                unsigned long ulDataBlockSize_p)
1428 {
1429
1430         tShbLinBuff *pShbLinBuff;
1431         unsigned char *pShbLinDataPtr;
1432         unsigned char *pScrDataPtr;
1433         unsigned long ulBufferDataSize;
1434         tShbError ShbError;
1435
1436         // check arguments
1437         if (pShbInstance_p == NULL) {
1438                 ShbError = kShbInvalidArg;
1439                 goto Exit;
1440         }
1441
1442         if ((pSrcDataBlock_p == NULL) || (ulDataBlockSize_p == 0)) {
1443                 // nothing to do here
1444                 ShbError = kShbOk;
1445                 goto Exit;
1446         }
1447
1448         if (ulDataBlockSize_p > SBL_MAX_BLOCK_SIZE) {
1449                 ShbError = kShbExceedDataSizeLimit;
1450                 goto Exit;
1451         }
1452
1453         pShbLinBuff = ShbLinGetBuffer(pShbInstance_p);
1454         pScrDataPtr = (unsigned char *)pSrcDataBlock_p;
1455         ShbError = kShbOk;
1456
1457         if (pShbLinBuff->m_ShbLinMagicID != SBL_MAGIC_ID) {
1458                 ShbError = kShbInvalidBufferType;
1459                 goto Exit;
1460         }
1461
1462         // check if offeset and size for the write operation matches with
1463         // the size of the shared buffer
1464         ulBufferDataSize = pShbLinBuff->m_ulBufferDataSize;
1465         if ((ulDstBufferOffs_p > ulBufferDataSize) ||
1466             (ulDataBlockSize_p > ulBufferDataSize) ||
1467             ((ulDstBufferOffs_p + ulDataBlockSize_p) > ulBufferDataSize)) {
1468                 ShbError = kShbDataOutsideBufferArea;
1469                 goto Exit;
1470         }
1471
1472         // copy the data to the linear buffer
1473         // (the copy process will be done inside of any critical/locked section)
1474         pShbLinDataPtr = &pShbLinBuff->m_Data;  // ptr to start of data area
1475         pShbLinDataPtr += ulDstBufferOffs_p;
1476
1477         ShbIpcEnterAtomicSection(pShbInstance_p);
1478         {
1479                 memcpy(pShbLinDataPtr, pScrDataPtr, ulDataBlockSize_p);
1480         }
1481         ShbIpcLeaveAtomicSection(pShbInstance_p);
1482
1483       Exit:
1484
1485         return (ShbError);
1486
1487 }
1488
1489 //---------------------------------------------------------------------------
1490 //  Read data block from Linear Shared Buffer
1491 //---------------------------------------------------------------------------
1492
1493 INLINE_FUNCTION tShbError ShbLinReadDataBlock(tShbInstance pShbInstance_p,
1494                                               void *pDstDataBlock_p,
1495                                               unsigned long ulSrcBufferOffs_p,
1496                                               unsigned long ulDataBlockSize_p)
1497 {
1498
1499         tShbLinBuff *pShbLinBuff;
1500         unsigned char *pShbLinDataPtr;
1501         unsigned char *pDstDataPtr;
1502         unsigned long ulBufferDataSize;
1503         tShbError ShbError;
1504
1505         // check arguments
1506         if (pShbInstance_p == NULL) {
1507                 ShbError = kShbInvalidArg;
1508                 goto Exit;
1509         }
1510
1511         if ((pDstDataBlock_p == NULL) || (ulDataBlockSize_p == 0)) {
1512                 // nothing to do here
1513                 ShbError = kShbOk;
1514                 goto Exit;
1515         }
1516
1517         if (ulDataBlockSize_p > SBL_MAX_BLOCK_SIZE) {
1518                 ShbError = kShbExceedDataSizeLimit;
1519                 goto Exit;
1520         }
1521
1522         pShbLinBuff = ShbLinGetBuffer(pShbInstance_p);
1523         pDstDataPtr = (unsigned char *)pDstDataBlock_p;
1524         ShbError = kShbOk;
1525
1526         if (pShbLinBuff->m_ShbLinMagicID != SBL_MAGIC_ID) {
1527                 ShbError = kShbInvalidBufferType;
1528                 goto Exit;
1529         }
1530
1531         // check if offeset and size for the read operation matches with
1532         // the size of the shared buffer
1533         ulBufferDataSize = pShbLinBuff->m_ulBufferDataSize;
1534         if ((ulSrcBufferOffs_p > ulBufferDataSize) ||
1535             (ulDataBlockSize_p > ulBufferDataSize) ||
1536             ((ulSrcBufferOffs_p + ulDataBlockSize_p) > ulBufferDataSize)) {
1537                 ShbError = kShbDataOutsideBufferArea;
1538                 goto Exit;
1539         }
1540
1541         // copy the data to the linear buffer
1542         // (the copy process will be done inside of any critical/locked section)
1543         pShbLinDataPtr = &pShbLinBuff->m_Data;  // ptr to start of data area
1544         pShbLinDataPtr += ulSrcBufferOffs_p;
1545
1546         ShbIpcEnterAtomicSection(pShbInstance_p);
1547         {
1548                 memcpy(pDstDataPtr, pShbLinDataPtr, ulDataBlockSize_p);
1549         }
1550         ShbIpcLeaveAtomicSection(pShbInstance_p);
1551
1552       Exit:
1553
1554         return (ShbError);
1555
1556 }
1557
1558 #endif
1559
1560 #if !defined(INLINE_ENABLED)
1561
1562 //---------------------------------------------------------------------------
1563 //  DEBUG: Trace Linear Shared Buffer
1564 //---------------------------------------------------------------------------
1565
1566 #ifndef NDEBUG
1567 tShbError ShbLinTraceBuffer(tShbInstance pShbInstance_p)
1568 {
1569
1570         tShbLinBuff *pShbLinBuff;
1571         char szMagigID[sizeof(SBL_MAGIC_ID) + 1];
1572         tShbError ShbError;
1573
1574         TRACE0("\n\n##### Linear Shared Buffer #####\n");
1575
1576         // check arguments
1577         if (pShbInstance_p == NULL) {
1578                 TRACE1("\nERROR: invalid buffer address (0x%08lX)\n",
1579                        (unsigned long)pShbInstance_p);
1580                 ShbError = kShbInvalidArg;
1581                 goto Exit;
1582         }
1583
1584         pShbLinBuff = ShbLinGetBuffer(pShbInstance_p);
1585         ShbError = kShbOk;
1586
1587         if (pShbLinBuff->m_ShbLinMagicID != SBL_MAGIC_ID) {
1588                 ShbError = kShbInvalidBufferType;
1589                 goto Exit;
1590         }
1591
1592         *(unsigned int *)&szMagigID[0] = pShbLinBuff->m_ShbLinMagicID;
1593         szMagigID[sizeof(SBL_MAGIC_ID)] = '\0';
1594
1595         ShbIpcEnterAtomicSection(pShbInstance_p);
1596         {
1597                 TRACE1("\nBuffer Address:   0x%08lX\n",
1598                        (unsigned long)pShbLinBuff);
1599
1600                 TRACE0("\nHeader Info:");
1601                 TRACE2("\nMagigID:          '%s' (%08X)", szMagigID,
1602                        pShbLinBuff->m_ShbLinMagicID);
1603                 TRACE1("\nBufferTotalSize:  %4lu [Bytes]",
1604                        pShbLinBuff->m_ulBufferTotalSize);
1605                 TRACE1("\nBufferDataSize:   %4lu [Bytes]",
1606                        pShbLinBuff->m_ulBufferDataSize);
1607
1608                 ShbTraceDump(&pShbLinBuff->m_Data,
1609                              pShbLinBuff->m_ulBufferDataSize, 0x00000000L,
1610                              "\nData Area:");
1611         }
1612         ShbIpcLeaveAtomicSection(pShbInstance_p);
1613
1614       Exit:
1615
1616         return (ShbError);
1617
1618 }
1619 #endif
1620
1621 //---------------------------------------------------------------------------
1622 //  Dump buffer contents
1623 //---------------------------------------------------------------------------
1624
1625 #ifndef NDEBUG
1626 tShbError ShbTraceDump(const unsigned char *pabStartAddr_p,
1627                        unsigned long ulDataSize_p,
1628                        unsigned long ulAddrOffset_p, const char *pszInfoText_p)
1629 {
1630
1631         const unsigned char *pabBuffData;
1632         unsigned long ulBuffSize;
1633         unsigned char bData;
1634         int nRow;
1635         int nCol;
1636
1637         // get pointer to buffer and length of buffer
1638         pabBuffData = pabStartAddr_p;
1639         ulBuffSize = ulDataSize_p;
1640
1641         if (pszInfoText_p != NULL) {
1642                 TRACE0(pszInfoText_p);
1643         }
1644         // dump buffer contents
1645         for (nRow = 0;; nRow++) {
1646                 TRACE1("\n%08lX:   ",
1647                        (unsigned long)(nRow * 0x10) + ulAddrOffset_p);
1648
1649                 for (nCol = 0; nCol < 16; nCol++) {
1650                         if ((unsigned long)nCol < ulBuffSize) {
1651                                 TRACE1("%02X ",
1652                                        (unsigned int)*(pabBuffData + nCol));
1653                         } else {
1654                                 TRACE0("   ");
1655                         }
1656                 }
1657
1658                 TRACE0(" ");
1659
1660                 for (nCol = 0; nCol < 16; nCol++) {
1661                         bData = *pabBuffData++;
1662                         if ((unsigned long)nCol < ulBuffSize) {
1663                                 if ((bData >= 0x20) && (bData < 0x7F)) {
1664                                         TRACE1("%c", bData);
1665                                 } else {
1666                                         TRACE0(".");
1667                                 }
1668                         } else {
1669                                 TRACE0(" ");
1670                         }
1671                 }
1672
1673                 if (ulBuffSize > 16) {
1674                         ulBuffSize -= 16;
1675                 } else {
1676                         break;
1677                 }
1678         }
1679
1680         return (kShbOk);
1681
1682 }
1683 #endif // #ifndef NDEBUG
1684
1685 //=========================================================================//
1686 //                                                                         //
1687 //          P R I V A T E   F U N C T I O N S                              //
1688 //                                                                         //
1689 //=========================================================================//
1690
1691 //---------------------------------------------------------------------------
1692 //  Handler to signal new data event for Circular Shared Buffer
1693 //---------------------------------------------------------------------------
1694
1695 int ShbCirSignalHandlerNewData(tShbInstance pShbInstance_p)
1696 {
1697
1698         tShbCirBuff *pShbCirBuff;
1699         unsigned long ulDataSize;
1700         unsigned long ulBlockCount;
1701         tShbError ShbError;
1702
1703         // check arguments
1704         if (pShbInstance_p == NULL) {
1705                 return FALSE;
1706         }
1707
1708         pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
1709         ShbError = kShbOk;
1710
1711         if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
1712                 return FALSE;
1713         }
1714
1715         // call application handler
1716         if (pShbCirBuff->m_pfnSigHndlrNewData != NULL) {
1717 /*        do
1718         {*/
1719                 ShbError = ShbCirGetReadDataSize(pShbInstance_p, &ulDataSize);
1720                 if ((ulDataSize > 0) && (ShbError == kShbOk)) {
1721                         pShbCirBuff->m_pfnSigHndlrNewData(pShbInstance_p,
1722                                                           ulDataSize);
1723                 }
1724
1725                 ShbError =
1726                     ShbCirGetReadBlockCount(pShbInstance_p, &ulBlockCount);
1727 /*        }
1728         while ((ulBlockCount > 0) && (ShbError == kShbOk));*/
1729         }
1730         // Return TRUE if there are pending blocks.
1731         // In that case ShbIpc tries to call this function again immediately if there
1732         // is no other filled shared buffer with higher priority.
1733         return ((ulBlockCount > 0) && (ShbError == kShbOk));
1734
1735 }
1736
1737 //---------------------------------------------------------------------------
1738 //  Handler to reset Circular Shared Buffer
1739 //---------------------------------------------------------------------------
1740
1741 void ShbCirSignalHandlerReset(tShbInstance pShbInstance_p,
1742                               unsigned int fTimeOut_p)
1743 {
1744
1745         tShbCirBuff *pShbCirBuff;
1746
1747         // check arguments
1748         if (pShbInstance_p == NULL) {
1749                 return;
1750         }
1751
1752         pShbCirBuff = ShbCirGetBuffer(pShbInstance_p);
1753         if (pShbCirBuff->m_ShbCirMagicID != SBC_MAGIC_ID) {
1754                 return;
1755         }
1756
1757         // reset buffer header
1758         if (!fTimeOut_p) {
1759                 ShbIpcEnterAtomicSection(pShbInstance_p);
1760                 {
1761                         pShbCirBuff->m_ulWrIndex = 0;
1762                         pShbCirBuff->m_ulRdIndex = 0;
1763                         pShbCirBuff->m_ulNumOfWriteJobs = 0;
1764                         pShbCirBuff->m_ulDataInUse = 0;
1765                         pShbCirBuff->m_ulDataApended = 0;
1766                         pShbCirBuff->m_ulBlocksApended = 0;
1767                         pShbCirBuff->m_ulDataReadable = 0;
1768                         pShbCirBuff->m_ulBlocksReadable = 0;
1769                 }
1770                 ShbIpcLeaveAtomicSection(pShbInstance_p);
1771
1772 #ifndef NDEBUG
1773                 {
1774                         memset(&pShbCirBuff->m_Data, 0xCC,
1775                                pShbCirBuff->m_ulBufferDataSize);
1776                 }
1777 #endif
1778         }
1779
1780         // call application handler
1781         if (pShbCirBuff->m_pfnSigHndlrReset != NULL) {
1782                 pShbCirBuff->m_pfnSigHndlrReset(pShbInstance_p, fTimeOut_p);
1783         }
1784
1785         // unlock buffer
1786         ShbIpcEnterAtomicSection(pShbInstance_p);
1787         {
1788                 pShbCirBuff->m_fBufferLocked = FALSE;
1789                 pShbCirBuff->m_pfnSigHndlrReset = NULL;
1790         }
1791         ShbIpcLeaveAtomicSection(pShbInstance_p);
1792
1793         return;
1794
1795 }
1796
1797 #endif
1798
1799 // EOF