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