[ipc/ipcdev.git] / qnx / src / ipc3x_dev / ti / syslink / utils / hlos / knl / osal / Qnx / OsalIsr.c
1 /*
2 * @file OsalIsr.c
3 *
4 * @brief QNX ISR interface implementation.
5 *
6 * This abstracts the ISR interface on kernel side code.
7 * Installs the handler for individual IRQs and handlers
8 * are invoked as the interrupts occur.
9 *
10 * ============================================================================
11 *
12 * Copyright (c) 20010-2011, Texas Instruments Incorporated
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions
16 * are met:
17 *
18 * * Redistributions of source code must retain the above copyright
19 * notice, this list of conditions and the following disclaimer.
20 *
21 * * Redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution.
24 *
25 * * Neither the name of Texas Instruments Incorporated nor the names of
26 * its contributors may be used to endorse or promote products derived
27 * from this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
30 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
31 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
32 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
33 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
34 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
35 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
36 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
37 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
38 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
39 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 * Contact information for paper mail:
41 * Texas Instruments
42 * Post Office Box 655303
43 * Dallas, Texas 75265
44 * Contact information:
45 * http://www-k.ext.ti.com/sc/technical-support/product-information-centers.htm?
46 * DCMP=TIHomeTracking&HQS=Other+OT+home_d_contact
47 * ============================================================================
48 *
49 */
51 /* Standard headers */
52 #include <ti/syslink/Std.h>
54 /* OSAL and kernel utils */
55 #include <OsalIsr.h>
56 #include <OsalThread.h>
57 #include <ti/syslink/utils/Trace.h>
58 #include <ti/syslink/utils/Memory.h>
60 /* QNX specific header files */
61 #include <errno.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <sys/neutrino.h>
66 #include <sys/syspage.h>
67 #include <pthread.h>
68 #include <signal.h>
69 #include <sys/types.h>
70 #include <unistd.h>
71 #include <sys/mman.h>
72 #include <inttypes.h>
73 #include <hw/inout.h>
74 #include <fcntl.h>
75 #include <sys/slog.h>
76 #include <sys/slogcodes.h>
78 #define ISR_EVENT_PULSE (_PULSE_CODE_MINAVAIL + 1)
80 #if defined (__cplusplus)
81 extern "C" {
82 #endif
85 #define PRIORITY_REALTIME_LOW 29
87 /* =============================================================================
88 * Macros and types
89 * =============================================================================
90 */
91 /*!
92 * @brief Defines object to encapsulate the interrupt service routine.
93 * The definition is OS/platform specific.
94 */
95 typedef struct OsalIsr_Object_tag {
96 UInt32 irq;
97 /*!< The IRQ number handled by this ISR object. */
98 OsalThread_Handle bottomHalf;
99 /*!< OsalThread_Object which is being invoked by the ISR handler */
100 OsalIsr_CheckAndClearFxn checkFunc;
101 /*!< Argument for the CheckAndClear function */
102 Ptr checkFuncArg;
103 /*!< CheckAndClear function registered for this interrupt */
104 Bool isSharedInt;
105 /*!< Is the interrupt a shared interrupt? */
106 OsalIsr_State isrState;
107 /*!< Current state of the ISR. */
108 //OsalIsr_CallbackFxn callbackFunc,
109 //Ptr callbackArgs,
110 Int32 handle;
111 Bool enabled;
112 Int32 chid;
113 Int32 coid;
114 Int32 tid;
115 Int32 index;
116 } OsalIsr_Object;
118 /* =============================================================================
119 * Interrupt event handler declaration
120 * =============================================================================
121 */
122 void *ISR_event_handler (void *area);
124 /* =============================================================================
125 * APIs
126 * =============================================================================
127 */
128 /*!
129 * @brief Creates an ISR object.
130 *
131 * @param fxn ISR handler function to be registered
132 * @param fxnArgs Optional parameter associated with the ISR handler
133 * @param params Parameters with information about the interrupt to be
134 * registered.
135 *
136 * @sa OsalIsr_delete, Memory_alloc
137 */
138 OsalIsr_Handle
139 OsalIsr_create (OsalIsr_CallbackFxn fxn,
140 Ptr fxnArgs,
141 OsalIsr_Params * params)
142 {
143 OsalIsr_Object * isrObj = NULL;
144 OsalThread_Params threadParams;
146 GT_3trace (curTrace, GT_ENTER, "OsalIsr_create", fxn, fxnArgs, params);
148 GT_assert (curTrace, (fxn != NULL));
149 /* fxnArgs are optional and may be passed as NULL. */
150 GT_assert (curTrace, (params != NULL));
152 #if !defined(SYSLINK_BUILD_OPTIMIZE)
153 if (fxn == NULL) {
154 /*! @retval NULL provided for argument fxn */
155 GT_setFailureReason (curTrace,
156 GT_4CLASS,
157 "OsalIsr_create",
158 OSALISR_E_INVALIDARG,
159 "NULL provided for argument fxn");
160 }
161 else if (params == NULL) {
162 /*! @retval NULL provided for argument params */
163 GT_setFailureReason (curTrace,
164 GT_4CLASS,
165 "OsalIsr_create",
166 OSALISR_E_INVALIDARG,
167 "NULL provided for argument params");
168 }
169 else {
170 #endif /* #if !defined(SYSLINK_BUILD_OPTIMIZE) */
171 isrObj = Memory_alloc (NULL, sizeof (OsalIsr_Object), 0, NULL);
172 #if !defined(SYSLINK_BUILD_OPTIMIZE)
173 if (isrObj == NULL) {
174 /*! @retval NULL Failed to allocate memory for ISR object. */
175 GT_setFailureReason (curTrace,
176 GT_4CLASS,
177 "OsalIsr_create",
178 OSALISR_E_MEMORY,
179 "Failed to allocate memory for ISR object.");
180 }
181 else {
182 #endif /* #if !defined(SYSLINK_BUILD_OPTIMIZE) */
183 /* Create the thread object used for the interrupt handler. */
184 threadParams.priority = OsalThread_Priority_High;
185 threadParams.priorityType = OsalThread_PriorityType_Generic;
186 threadParams.once = FALSE;
187 isrObj->bottomHalf = OsalThread_create ((OsalThread_CallbackFxn)
188 fxn,
189 fxnArgs,
190 &threadParams);
191 #if !defined(SYSLINK_BUILD_OPTIMIZE)
192 if (isrObj->bottomHalf == NULL) {
193 /*! @retval NULL Failed to create thread for ISR handler. */
194 GT_setFailureReason (curTrace,
195 GT_4CLASS,
196 "OsalIsr_create",
197 OSALISR_E_THREAD,
198 "Failed to create thread for ISR handler.");
199 Memory_free (NULL, isrObj, sizeof (OsalIsr_Object));
200 isrObj = NULL;
201 }
202 else {
203 #endif /* #if !defined(SYSLINK_BUILD_OPTIMIZE) */
204 /* Copy the creation parameters for further use */
205 isrObj->irq = params->intId;
206 isrObj->isSharedInt = params->sharedInt;
207 isrObj->checkFunc = params->checkAndClearFxn;
208 isrObj->checkFuncArg = params->fxnArgs;
209 //isrObj->callbackFunc = fxn;
210 //isrObj->callbackArgs = fxnArgs;
212 /* Initialize state to uninstalled. */
213 isrObj->isrState = OsalIsr_State_Uninstalled;
215 #if !defined(SYSLINK_BUILD_OPTIMIZE)
216 }
217 }
218 }
219 #endif /* #if !defined(SYSLINK_BUILD_OPTIMIZE) */
221 GT_1trace (curTrace, GT_LEAVE, "OsalIsr_create", isrObj);
223 /*! @retval ISR-handle Operation successfully completed. */
224 return (OsalIsr_Handle) isrObj;
225 }
228 /*!
229 * @brief Delete the ISR object.
230 *
231 * @param isrHandle ISR object handle which needs to be deleted.
232 *
233 * @sa OsalIsr_create, Memory_free
234 */
235 Int
236 OsalIsr_delete (OsalIsr_Handle * isrHandle)
237 {
238 Int status = OSALISR_SUCCESS;
239 OsalIsr_Object * isrObj = NULL;
241 GT_1trace (curTrace, GT_ENTER, "OsalIsr_delete", isrHandle);
243 GT_assert (curTrace, (isrHandle != NULL));
245 #if !defined(SYSLINK_BUILD_OPTIMIZE)
246 if (isrHandle == NULL) {
247 /*! @retval OSALISR_E_INVALIDARG NULL provided for argument isrHandle.*/
248 status = OSALISR_E_INVALIDARG;
249 GT_setFailureReason (curTrace,
250 GT_4CLASS,
251 "OsalIsr_delete",
252 status,
253 "NULL provided for argument isrHandle");
254 }
255 else if (*isrHandle == NULL) {
256 /*! @retval OSALISR_E_HANDLE NULL ISR handle provided. */
257 status = OSALISR_E_HANDLE;
258 GT_setFailureReason (curTrace,
259 GT_4CLASS,
260 "OsalIsr_delete",
261 status,
262 "NULL ISR handle provided.");
263 }
264 else {
265 #endif /* #if !defined(SYSLINK_BUILD_OPTIMIZE) */
266 isrObj = (OsalIsr_Object*) (*isrHandle);
267 /* Delete the thread used for the ISR handler */
268 if (isrObj->bottomHalf != NULL) {
269 OsalThread_delete (&(isrObj->bottomHalf));
270 }
272 /* Free the ISR object. */
273 Memory_free (NULL, isrObj, sizeof (OsalIsr_Object));
274 *isrHandle = NULL;
275 #if !defined(SYSLINK_BUILD_OPTIMIZE)
276 }
277 #endif /* #if !defined(SYSLINK_BUILD_OPTIMIZE) */
279 GT_1trace (curTrace, GT_LEAVE, "OsalIsr_delete", status);
281 /*! @retval OSALISR_SUCCESS Operation successfully completed. */
282 return status;
283 }
286 /*!
287 * @brief Install an interrupt service routine.
288 *
289 * This function calls the InterruptAttachEvent () function and installs
290 * the specified interrupt service routine in non-shared, non-fiq
291 * mode.
292 *
293 * @param isrHandle ISR object handle to be installed
294 *
295 * @sa OsalIsr_uninstall
296 */
297 Int
298 OsalIsr_install (OsalIsr_Handle isrHandle)
299 {
300 Int status = OSALISR_SUCCESS;
301 OsalIsr_Object * isrObj = (OsalIsr_Object *) isrHandle;
302 pthread_attr_t pattr;
303 struct sched_param param;
304 struct sigevent event;
305 char threadName[20];
307 GT_1trace (curTrace, GT_ENTER, "OsalIsr_install", isrHandle);
309 GT_assert (curTrace, (isrHandle != NULL));
311 #if !defined(SYSLINK_BUILD_OPTIMIZE)
312 if (isrHandle == NULL) {
313 /*! @retval OSALISR_E_HANDLE NULL ISR handle provided. */
314 status = OSALISR_E_HANDLE;
315 GT_setFailureReason (curTrace,
316 GT_4CLASS,
317 "OsalIsr_install",
318 status,
319 "NULL ISR handle provided.");
320 }
321 else {
322 #endif /* #if !defined(SYSLINK_BUILD_OPTIMIZE) */
324 if ((isrObj->chid = ChannelCreate(_NTO_CHF_DISCONNECT | _NTO_CHF_UNBLOCK)) == -1 ) {
325 status = OSALISR_E_IRQINSTALL;
326 ChannelDestroy(isrObj->chid);
327 }
328 else {
329 if ((isrObj->coid = ConnectAttach(0, 0, isrObj->chid, _NTO_SIDE_CHANNEL, 0)) == -1) {
330 status = OSALISR_E_IRQINSTALL;
331 ConnectDetach(isrObj->coid);
332 ChannelDestroy(isrObj->chid);
333 }
334 else {
335 pthread_attr_init(&pattr);
336 pthread_attr_setschedpolicy(&pattr, SCHED_RR);
337 param.sched_priority = PRIORITY_REALTIME_LOW;
338 pthread_attr_setschedparam(&pattr, ¶m);
339 pthread_attr_setinheritsched(&pattr, PTHREAD_EXPLICIT_SCHED);
341 if (pthread_create(&isrObj->tid, &pattr, (void *)ISR_event_handler, isrObj)) {
342 status = OSALISR_E_IRQINSTALL;
343 ConnectDetach(isrObj->coid);
344 ChannelDestroy(isrObj->chid);
345 }
346 else {
347 snprintf (threadName, sizeof(threadName), "OsalIsrThread_%d", isrObj->irq);
348 pthread_setname_np(isrObj->tid, threadName);
349 }
350 pthread_attr_destroy(&pattr);
352 event.sigev_notify = SIGEV_PULSE;
353 event.sigev_coid = isrObj->coid;
354 event.sigev_code = ISR_EVENT_PULSE;
355 event.sigev_priority = PRIORITY_REALTIME_LOW + 1;
357 if ((isrObj->handle =
358 InterruptAttachEvent(isrObj->irq, &event,
359 _NTO_INTR_FLAGS_TRK_MSK)) == -1 ) {
360 status = OSALISR_E_IRQINSTALL;
361 }
362 isrObj->isrState = OsalIsr_State_Installed;
363 }
364 }
366 #if !defined(SYSLINK_BUILD_OPTIMIZE)
367 }
368 #endif /* #if !defined(SYSLINK_BUILD_OPTIMIZE) */
370 GT_1trace (curTrace, GT_LEAVE, "OsalIsr_install", status);
372 /*! @retval OSALISR_SUCCESS Operation successfully completed. */
373 return status;
374 }
377 /*!
378 * @brief Uninstalls an interrupt service routine.
379 *
380 * @param isrHandle ISR object handle to be uninstalled.
381 *
382 * @sa OsalIsr_install
383 */
384 Int
385 OsalIsr_uninstall (OsalIsr_Handle isrHandle)
386 {
387 Int status = OSALISR_SUCCESS;
388 OsalIsr_Object * isrObj = (OsalIsr_Object *) isrHandle;
390 GT_1trace (curTrace, GT_ENTER, "OsalIsr_uninstall", isrHandle);
392 GT_assert (curTrace, (isrHandle != NULL));
394 #if !defined(SYSLINK_BUILD_OPTIMIZE)
395 if (isrHandle == NULL) {
396 /*! @retval OSALISR_E_HANDLE NULL ISR handle provided. */
397 status = OSALISR_E_HANDLE;
398 GT_setFailureReason (curTrace,
399 GT_4CLASS,
400 "OsalIsr_uninstall",
401 status,
402 "NULL ISR handle provided.");
403 }
404 else {
405 #endif /* #if !defined(SYSLINK_BUILD_OPTIMIZE) */
406 InterruptDetach (isrObj->handle);
407 pthread_cancel(isrObj->tid);
408 pthread_join(isrObj->tid, NULL);
409 ConnectDetach(isrObj->coid);
410 ChannelDestroy(isrObj->chid);
412 isrObj->isrState = OsalIsr_State_Uninstalled;
413 #if !defined(SYSLINK_BUILD_OPTIMIZE)
414 }
415 #endif /* #if !defined(SYSLINK_BUILD_OPTIMIZE) */
417 GT_1trace (curTrace, GT_LEAVE, "OsalIsr_uninstall", status);
419 /*! @retval OSALISR_SUCCESS Operation successfully completed. */
420 return status;
421 }
424 /*!
425 * @brief Disables the specified ISR.
426 *
427 * This function calls disable_irq () to disable the ISR.
428 * disble_irq() function doesn't return any value so this
429 * function assumes it was successful.
430 *
431 * @param isrHandle ISR object handle for the interrupt to be disabled.
432 *
433 * @sa OsalIsr_enableIsr
434 */
435 Void
436 OsalIsr_disableIsr (OsalIsr_Handle isrHandle)
437 {
438 OsalIsr_Object * isrObj = (OsalIsr_Object *) isrHandle;
440 GT_1trace (curTrace, GT_ENTER, "OsalIsr_disableIsr", isrHandle);
442 GT_assert (curTrace, (isrHandle != NULL));
444 #if !defined(SYSLINK_BUILD_OPTIMIZE)
445 if (isrHandle == NULL) {
446 /* Void function, so status is not set. */
447 GT_setFailureReason (curTrace,
448 GT_4CLASS,
449 "OsalIsr_disableIsr",
450 OSALISR_E_HANDLE,
451 "NULL ISR handle provided.");
452 }
453 else {
454 #endif /* #if !defined(SYSLINK_BUILD_OPTIMIZE) */
455 if (isrObj->isSharedInt != TRUE) {
456 /* Disable the IRQ handler */
457 InterruptMask(isrObj->irq, isrObj->handle);
458 isrObj->enabled = FALSE;
459 isrObj->isrState = OsalIsr_State_Disabled;
460 }
461 #if !defined(SYSLINK_BUILD_OPTIMIZE)
462 }
463 #endif /* #if !defined(SYSLINK_BUILD_OPTIMIZE) */
465 GT_0trace (curTrace, GT_LEAVE, "OsalIsr_disableIsr");
466 }
469 /*!
470 * @brief Enables the specified ISR.
471 *
472 * This function calls enable_irq () to enable the ISR.
473 * enble_irq() function doesn't return any value so this function
474 * assumes it was successful.
475 *
476 * @param isrHandle ISR object handle for the interrupt to be enabled.
477 *
478 * @sa OsalIsr_disableIsr
479 */
480 Void
481 OsalIsr_enableIsr (OsalIsr_Handle isrHandle)
482 {
483 OsalIsr_Object * isrObj = (OsalIsr_Object *) isrHandle;
485 GT_1trace (curTrace, GT_ENTER, "OsalIsr_enableIsr", isrHandle);
487 GT_assert (curTrace, (isrHandle != NULL));
489 #if !defined(SYSLINK_BUILD_OPTIMIZE)
490 if (isrHandle == NULL) {
491 /* Void function, so status is not set. */
492 GT_setFailureReason (curTrace,
493 GT_4CLASS,
494 "OsalIsr_enableIsr",
495 OSALISR_E_HANDLE,
496 "NULL ISR handle provided.");
497 }
498 else {
499 #endif /* #if !defined(SYSLINK_BUILD_OPTIMIZE) */
500 if (isrObj->isSharedInt != TRUE) {
501 InterruptUnmask(isrObj->irq, isrObj->handle);
502 isrObj->enabled = TRUE ;
503 isrObj->isrState = OsalIsr_State_Installed;
504 }
505 #if !defined(SYSLINK_BUILD_OPTIMIZE)
506 }
507 #endif /* #if !defined(SYSLINK_BUILD_OPTIMIZE) */
509 GT_0trace (curTrace, GT_LEAVE, "OsalIsr_enableIsr");
510 }
513 /*!
514 * @brief Disables all interrupts. Returns flags that must be passed to
515 * the corresponding restore API.
516 *
517 * @sa OsalIsr_restore
518 */
519 UInt32 OsalIsr_disable (Void)
520 {
521 unsigned long flags = 0;
523 GT_0trace (curTrace, GT_ENTER, "OsalIsr_disable");
525 InterruptDisable();
527 GT_1trace (curTrace, GT_1CLASS, " ISR disable flags [0x%x]", flags);
528 GT_1trace (curTrace, GT_LEAVE, "OsalIsr_disable", flags);
530 /*! @retval flags State of the interrupts before disable was called. */
531 return flags;
532 }
535 /*!
536 * @brief Restores all interrupts to their status before disable was
537 * called.
538 *
539 * @param flags Flags indicating interrupts state before disable was
540 * called. These are the flags returned from
541 * OsalIsr_disable.
542 *
543 * @sa OsalIsr_disable
544 */
545 Void OsalIsr_restore (UInt32 flags)
546 {
547 GT_1trace (curTrace, GT_ENTER, "OsalIsr_restore", flags);
549 InterruptEnable();
551 GT_0trace (curTrace, GT_LEAVE, "OsalIsr_restore");
552 }
555 /*!
556 * @brief Returns the state of an ISR.
557 *
558 * @param ISR object handle.
559 * @param returned ISR object state.
560 */
561 OsalIsr_State
562 OsalIsr_getState (OsalIsr_Handle isrHandle)
563 {
564 OsalIsr_Object * isrObj = (OsalIsr_Object *) isrHandle;
565 OsalIsr_State isrState = OsalIsr_State_EndValue;
567 GT_1trace (curTrace, GT_ENTER, "OsalIsr_enableIsr", isrHandle);
569 GT_assert (curTrace, (isrHandle != NULL));
571 #if !defined(SYSLINK_BUILD_OPTIMIZE)
572 if (isrHandle == NULL) {
573 /*! @retval OsalIsr_State_EndValue NULL ISR handle provided. */
574 GT_setFailureReason (curTrace,
575 GT_4CLASS,
576 "OsalIsr_getState",
577 OSALISR_E_HANDLE,
578 "NULL ISR handle provided.");
579 }
580 else {
581 #endif /* #if !defined(SYSLINK_BUILD_OPTIMIZE) */
582 isrState = isrObj->isrState;
583 GT_1trace (curTrace, GT_1CLASS, " ISR state [%d]", isrState);
584 #if !defined(SYSLINK_BUILD_OPTIMIZE)
585 }
586 #endif /* #if !defined(SYSLINK_BUILD_OPTIMIZE) */
588 GT_1trace (curTrace, GT_LEAVE, "OsalIsr_getState", isrState);
590 /*! @retval ISR-state State of the ISR */
591 return isrState;
592 }
595 /*!
596 * @brief Returns the state of whether the current context is ISR context.
597 *
598 * @sa
599 */
600 Bool
601 OsalIsr_inIsr (Void)
602 {
603 Bool inIsr = FALSE;
605 GT_0trace (curTrace, GT_ENTER, "OsalIsr_inIsr");
607 // if (in_interrupt() != 0) {
608 // inIsr = TRUE;
609 // }
611 GT_1trace (curTrace, GT_1CLASS, " In ISR context [%d]", inIsr);
612 GT_1trace (curTrace, GT_LEAVE, "OsalIsr_inIsr", inIsr);
614 /*! @retval FALSE Not in ISR context. */
615 return inIsr;
616 }
619 /*!
620 * @brief ISR event handler
621 *
622 * @param ISR object handle.
623 */
624 void *
625 ISR_event_handler (void *area) {
626 struct _pulse pulse;
627 iov_t iov;
628 Bool isAsserted;
629 int rcvid;
630 OsalIsr_Object * isrObj = (OsalIsr_Object * )area;
632 SETIOV( &iov, &pulse, sizeof( pulse ) );
634 while(1) {
635 if ((rcvid = MsgReceivev( isrObj->chid, &iov, 1, NULL )) == -1 ) {
636 if (errno == ESRCH){
637 pthread_exit( NULL );
638 }
639 continue;
640 }
642 isAsserted = TRUE;
644 if (isrObj->checkFunc) {
645 isAsserted = (*isrObj->checkFunc) (isrObj->checkFuncArg);
646 }
648 if (TRUE == isAsserted) {
649 OsalThread_activate (isrObj->bottomHalf);
651 /* Call the bottom half routine */
652 //(*isrObj->callbackFunc) (isrObj->callbackFuncArgs);
653 }
655 /* enble interrupt */
656 InterruptUnmask(isrObj->irq, isrObj->handle);
658 }
659 }
662 #if defined (__cplusplus)
663 }
664 #endif /* defined (_cplusplus)*/