fc374bbb690431dff83854321640f92b0d8b151f
1 /******************************************************************************
2 * FILE PURPOSE: Top level interface file for NWAL Module
3 ******************************************************************************
4 * FILE NAME: pktio.h
5 *
6 * DESCRIPTION: netapi PKTIO module header file
7 *
8 * REVISION HISTORY:
9 *
10 * Copyright (c) Texas Instruments Incorporated 2010-2011
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 *
16 * Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 *
19 * Redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the
22 * distribution.
23 *
24 * Neither the name of Texas Instruments Incorporated nor the names of
25 * its contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 *
40 */
41 /* ============================================================= */
43 /**
44 * @file pktio.h
45 * @brief pktio module main header file for user space transport library
46 */
50 #ifndef __PKTIO__H
51 #define __PKTIO__H
52 #include "netapi.h"
53 #include "ti/runtime/pktlib/pktlib.h"
54 #include "ti/drv/nwal/nwal.h"
55 #include "ti/drv/nwal/nwal_util.h"
56 #include "netapi_err.h"
58 /*--------------------defines-----------------------*/
60 /**
61 * @def PKTIO_NOMEM
62 * This define is used to indicate out of memory to user space application
63 */
64 #define PKTIO_NOMEM NETAPI_ERR_NOMEM
66 /**
67 * @def NETCP_TX
68 * This defines the pktio NETCP transmit INFLOW channel name
69 */
70 #define NETCP_TX "NETCP_TX"
72 /**
73 * @def NETCP_RX
74 * This defines the pktio NETCP receive INFLOW channel name
75 */
76 #define NETCP_RX "NETCP_RX"
78 /**
79 * @def NETCP_SB_RX
80 * This defines the pktio NETCP receive SIDEBAND channel name
81 */
82 #define NETCP_SB_RX "NETCP_SB_RX"
84 /**
85 * @def NETCP_SB_TX
86 * This defines the pktio NETCP transmit SIDEBAND channel name
87 */
88 #define NETCP_SB_TX "NETCP_SB_TX"
90 /**
91 * @def PKTIO_MAX_NAME
92 * This defines the maximum length of a pktio channel name
93 */
94 #define PKTIO_MAX_NAME 19
96 /**
97 * @ingroup netapi_structures
98 * @brief PKTIO meta data information .
99 *
100 * @details PKTIO meta data information TBD
101 */
102 typedef struct PKTIO_METADATA_Tag
103 {
104 int flags1; /**< Meta Data flag configuration */
105 /**
106 * @def PKTIO_META_RX
107 * This defines the pktio NETCP receive INFLOW channel
108 */
109 #define PKTIO_META_RX 0x01
111 /**
112 * @def PKTIO_META_TX
113 * This defines the pktio NETCP transmit INFLOW channel
114 */
115 #define PKTIO_META_TX 0x02
117 /**
118 * @def PKTIO_META_SB_RX
119 * This defines the pktio NETCP SIDEBAND channel channel
120 */
121 #define PKTIO_META_SB_RX 0x4 /**< SB crypto rx */
123 /**
124 * @def PKTIO_META_SB_TX
125 * This defines the pktio NETCP transmit SIDEBAND channel
126 */
127 #define PKTIO_META_SB_TX 0x8 /** <SB crypto tx */
129 /**
130 * @def PKTIO_META_APP_DEF
131 * TBD
132 */
133 #define PKTIO_META_APP_DEF 0x80000000
134 union
135 {
136 nwalRxPktInfo_t * rx_meta; /**< NWAL Packet meta data information for incoming packet */
137 nwalTxPktInfo_t * tx_meta; /**< NWAL Packet meta data information for outgoing packet */
138 nwalDmRxPayloadInfo_t * rx_sb_meta; /**<NWAL Data mode meta data payload information from NetCP */
139 nwalDmTxPayloadInfo_t * tx_sb_meta; /**< NWAL Data Mode Payload information for packet to SA */
140 } u; /**< union NWAL Packet meta data information */
141 void * sa_handle; /**<valid for PKTIO_META_TX with IPSEC inflow or PKTIO_PKTIO_META_SB_TX MUST BE nwal_HANDLE_INVALID otherwise */
142 } PKTIO_METADATA_T;
144 /* the callback function */
145 struct PKTIO_HANDLE_tag;
147 /**
148 * @ingroup netapi_structures
149 * @brief PKTIO polling control struct FUTURE
150 *
151 * @details PKTIO polling control struct FUTURE
152 */
153 typedef struct PKTIO_POLL_Tag
154 {
155 /* future */
156 } PKTIO_POLL_T;
158 /**
159 * @def PKTIO_MAX_RECV
160 * This defines the maximum number of packets to receive in one pktio poll, @ref TUNE_NETAPI_MAX_BURST_RCV
161 */
162 #define PKTIO_MAX_RECV (TUNE_NETAPI_MAX_BURST_RCV)
166 /**
167 * @ingroup netapi_cb_functions
168 * @brief PKTIO_CB Callback function to be issued on packet receive
169 *
170 * @details The application provides a callback function that gets invoked on packet receive
171 * @param[in] channel The PKTIO channel handle, @ref PKTIO_HANDLE_T
172 * @param[in] p_recv Pointer to the packets received.
173 * @param[in] p_meta Pointer to meta data associated with packet, @ref PKTIO_METADATA_T
174 * @param[in] n_pkts Number of packets received.
175 * @param[in] ts Timestamp associted with received packets.
176 * @retval none
177 * @pre @ref pktio_open
178 */
179 typedef void (*PKTIO_CB)(struct PKTIO_HANDLE_tag * channel,
180 Ti_Pkt* p_recv[],
181 PKTIO_METADATA_T p_meta[],
182 int n_pkts,
183 uint64_t ts);
185 /**
186 * @ingroup netapi_pktio_functions
187 * @brief PKTIO_SEND PKTIO specific send function
188 *
189 * @details The application calls this PKTIO specific send function to transmit packet
190 * @param[in] channel The PKTIO channel handle, @ref PKTIO_HANDLE_T
191 * @param[in] p_send Pointer to the packet to send
192 * @param[in] p_meta Pointer to meta data associated with packet, @ref PKTIO_METADATA_T
193 * @param[out] p_err Pointer to error code.
194 * @retval none
195 * @pre @ref pktio_open
196 */
197 typedef int (*PKTIO_SEND)(struct PKTIO_HANDLE_tag * channel,
198 Ti_Pkt* p_send,
199 PKTIO_METADATA_T *p_meta,
200 int * p_err);
203 /**
204 * @ingroup netapi_pktio_functions
205 * @brief PKTIO_POLL PKTIO specific poll function
206 *
207 * @details The application calls this PKTIO specific POLL function
208 * @param[in] channel The PKTIO channel handle, @ref PKTIO_HANDLE_T
209 * @param[in] p_poll_cfg Pointer to pktio poll configuration. @ref PKTIO_POLL_T
210 * @param[out] p_err Pointer to error code.
211 * @retval none
212 * @pre @ref pktio_open
213 */
214 typedef int (*PKTIO_POLL)(struct PKTIO_HANDLE_tag * channel,
215 PKTIO_POLL_T * p_poll_cfg,
216 int * p_err);
218 /**
219 * @brief This defines TBD
220 */
221 #define PKTIO_NA 0
223 /**
224 * @ingroup netapi_structures
225 * @brief PKTIO configuration information
226 *
227 * @details PKTIO :q information
228 */
229 typedef struct PKTIO_CFG_Tag
230 {
231 /**
232 * @def PKTIO_R
233 * This defines the pktio channel as type read TBD
234 */
235 #define PKTIO_R 0x1
237 /**
238 * @def PKTIO_W
239 * This defines the pktio channel as type write TBD
240 */
241 #define PKTIO_W 0x2
243 /**
244 * @def PKTIO_RW
245 * This defines the pktio channel as type read/write TBD
246 */
247 #define PKTIO_RW (PKTIO_R | PKTIO_W)
249 int flags1; /**< Flags for PKTIO channel configuration */
251 /**
252 * @def PKTIO_LOCAL
253 * This defines the pktio channel as type local TBD
254 */
255 #define PKTIO_LOCAL 0x2
257 /**
258 * @def PKTIO_GLOBAL
259 * This defines the pktio channel as type global TBD
260 */
261 #define PKTIO_GLOBAL 0x1
263 /**
264 * @def PKTIO_PKT
265 * This defines the pktio channel is for NETCP
266 */
267 #define PKTIO_PKT 0x4
269 /**
270 * @def PKTIO_SB
271 * This defines the pktio channel is for sideband crypto
272 */
273 #define PKTIO_SB 0x8
275 int flags2; /**< Flags for PKTIO channel configuration */
277 /**
278 * @def PKTIO_Q_ANY
279 * This defines TBD
280 */
281 #define PKTIO_Q_ANY -1
283 int qnum; /**< PKTIO channel queue number */
286 int max_n; /**< Maximum number of packets read in 1 poll */
287 } PKTIO_CFG_T;
289 struct NETAPI_tag;
291 /* a pktio channel .. */
295 /**
296 * @ingroup netapi_structures
297 * @brief PKTIO handle structure definition.
298 *
299 * @details PKTIO handle strucutre which is returned from call to @ref pktio_create
300 */
301 typedef struct PKTIO_HANDLE_Tag
302 {
303 /**
304 * @def PKTIO_INUSE
305 * This defines is used to TBD
306 */
307 #define PKTIO_INUSE 0xfeedfeed
309 int inuse; /**<true is pktio channel is in use TBD */
310 int use_nwal; /**<true if this is managed by nwal */
311 #define PKTIO_4_IPC 0 /**<For IPC */
312 #define PKTIO_4_ADJ_NWAL 1 /**<(RX)app queues managed by NWAL */
313 #define PKTIO_DEF_NWAL 2 /**<default NWAL RX/TX queues */
314 #define PKTIO_4_ADJ_SB 3 /**<(RX) crypto side band app defined */
315 #define PKTIO_DEF_SB 4 /**<crypto side band default */
316 struct NETAPI_tag * back; /**< back handle */
317 void * nwalInstanceHandle; /**<save here for conveninece */
318 PKTIO_CB cb; /**< callback for channel */
319 PKTIO_CFG_T cfg; /**<configuration */
320 Qmss_QueueHnd q; /**<the associated queue handle */
321 Qmss_Queue qInfo; /**<and its qm#/q# */
322 int max_n; /**<max # of pkts to read in one poll */
323 void * cookie; /**<app specific */
324 PKTIO_SEND _send; /**<pktio type specific send function */
325 PKTIO_POLL _poll; /**<pktio type specific POLL function */
326 char name[PKTIO_MAX_NAME+1]; /**< Name of pktio channel */
327 } PKTIO_HANDLE_T;
330 /**
331 * @ingroup netapi_structures
332 * @brief PKTIO control TBD
333 *
334 * @details PKTIO control RBD
335 */
336 typedef struct PKTIO_CONTROL_Tag
337 {
338 /**
339 * @def PKTIO_CLEAR
340 * This defines is used to clear out the PKTIO channel
341 */
342 #define PKTIO_CLEAR 0x1
344 /**
345 * @def PKTIO_DIVERT
346 * This defines is used to divert to dest channel TBD
347 */
348 #define PKTIO_DIVERT 0x2
350 int op; /**< TBD */
351 PKTIO_HANDLE_T *dest; /**< Handle to PKTIO channel */
352 } PKTIO_CONTROL_T;
356 /**
357 * @ingroup netapi_pktio_functions
358 * @brief API creates a NETAPI PKTIO channel
359 *
360 * @details This assigns global resources to a NETAPI pktio channel.
361 * Once created, the channel can be used to send and/or receive
362 * a Ti_Pkt. This can be used for communication with the
363 * the Network co-processor (NETCP) or for internal inter-processor
364 * communication. The channel is saved under the assigned name
365 * and can be opened by other netapi threads instances.
366 * @param[in] netapi_handle The NETAPI handle, @ref NETAPI_T
367 * @param[in] name A pointer to the char string name for channel
368 * @param[in] cb Callback to be issued on packet receive, @ref PKTIO_CB
369 * @param[in] p_cfg Pointer to channel configuration, @ref PKTIO_CFG_T
370 * @param[out] err Pointer to error code.
371 * @retval Handle to the pktio instance or NULL on error, @ref PKTIO_HANDLE_T
372 * @pre @ref netapi_init
373 */
374 PKTIO_HANDLE_T * pktio_create(NETAPI_T netapi_handle,
375 char * name,
376 PKTIO_CB cb,
377 PKTIO_CFG_T* p_cfg,
378 int * err);
380 /**
381 * @ingroup netapi_pktio_functions
382 * @brief API opens an existing NETAPI PKTIO channel
383 *
384 * @details This opens an NETAPI pktio channel for use. The channel
385 * must have already been created via @ref pktio_create or may have
386 * been created internally during the netapi intialization.
387 * Once opened, the channel can be used to send and/or receive
388 * a Ti_Pkt. This can be used for communication with the
389 * the Network co-processor (NETCP) or for internal inter-processor
390 * communication.
391 *
392 * @param[in] netapi_handle The NETAPI handle, @ref NETAPI_T
393 * @param[in] name A pointer to the char string name for channel to open
394 * @param[in] cb Callback to be issued on packet receive, @ref PKTIO_CB
395 * @param[in] p_cfg Pointer to channel configuration, @ref PKTIO_CFG_T
396 * @param[out] err Pointer to error code.
397 * @retval Handle to the pktio instance or NULL on error, @ref PKTIO_HANDLE_T
398 * @pre @ref netapi_init, @ref pktio_create
399 */
400 PKTIO_HANDLE_T * pktio_open(NETAPI_T netapi_handle,
401 char *name,
402 PKTIO_CB cb,
403 PKTIO_CFG_T *p_cfg,
404 int * err);
406 /**
407 * @ingroup netapi_pktio_functions
408 * @brief API controls an existing NETAPI PKTIO channel
409 *
410 * @details This controls an opened pktio channel
411 *
412 * @param[in] handle The PKTIO channel handle, @ref PKTIO_HANDLE_T
413 * @param[in] cb Callback to be issued on packet receive, @ref PKTIO_CB
414 * @param[in] p_cfg Pointer to channel configuration which (optional), @ref PKTIO_CFG_T
415 * @param[in] p_control Pointer to PKTIO control information (optional), @ref PKTIO_CONTROL_T
416 * @param[out] err Pointer to error code.
417 * @retval none
418 * @pre @ref netapi_init, @ref pktio_create, @ref pktio_open
419 */
420 void pktio_control(PKTIO_HANDLE_T * handle,
421 PKTIO_CB cb,
422 PKTIO_CFG_T * p_cfg,
423 PKTIO_CONTROL_T *p_control,
424 int *err);
426 /**
427 * @ingroup netapi_pktio_functions
428 * @brief API closes a PKTIO channel
429 *
430 * @details This closes a PKTIO channel
431 *
432 * @param[in] handle The PKTIO channel handle, @ref PKTIO_HANDLE_T
433 * @param[out] err Pointer to error code.
434 * @retval none
435 * @pre @ref netapi_init, @ref pktio_create, @ref pktio_open
436 */
437 void pktio_close(PKTIO_HANDLE_T * handle,
438 int * err);
440 /**
441 * @ingroup netapi_pktio_functions
442 * @brief API deletes a PKTIO channel
443 *
444 * @details This deletes a PKTIO channel
445 *
446 * @param[in] handle The PKTIO handle, @ref PKTIO_HANDLE_T
447 * @param[out] err Pointer to error code.
448 * @retval none
449 * @pre @ref netapi_init, @ref pktio_create, @ref pktio_open
450 */
451 void pktio_delete(PKTIO_HANDLE_T * handle,
452 int * err);
454 /**
455 * @ingroup netapi_pktio_functions
456 * @brief API sends data to a NETAPI PKTIO channel
457 *
458 * @details This sends a Ti_Pkt and associated meta data,
459 * @ref PKTIO_METADATA_T to a channel. The channel
460 * must have already been created via @ref pktio_create or opened
461 * via @ref pktio_open. It may have
462 * been created internally during the netapi intialization.
463 * @param[in] handle The PKTIO channel handle, @ref PKTIO_HANDLE_T
464 * @param[in] pkt Pointer to the packet to send
465 * @param[in] m Pointer to meta data associated with packet, @ref PKTIO_METADATA_T
466 * @param[out] err Pointer to error code.
467 * @retval 1 if packet sent, 0 if error
468 * @pre @ref netapi_init, @ref pktio_create, @ref pktio_open
469 */
470 static inline int pktio_send(PKTIO_HANDLE_T * handle,
471 Ti_Pkt *pkt,
472 PKTIO_METADATA_T *m,
473 int * err)
474 {
475 return handle->_send((struct PKTIO_HANDLE_tag *)handle, pkt, m, err);
476 }
478 /**
479 * @ingroup netapi_pktio_functions
480 * @brief API sends data to a NETAPI PKTIO channel
481 *
482 * @details This sends an array of Ti_Pkt and associated meta data,
483 * @ref PKTIO_METADATA_T to a channel. The channel
484 * must have already been created via @ref pktio_create or opened
485 * via @ref pktio_open. It may have
486 * been created internally during the netapi intialization.
487 * @param[in] handle The PKTIO channel handle, @ref PKTIO_HANDLE_T
488 * @param[in] pkt Pointer to the packet to send
489 * @param[in] m Pointer to meta data associated with packet, @ref PKTIO_METADATA_T
490 * @param[in] np The number of packets in list to send
491 * @param[out] err Pointer to error code.
492 * @retval Number of packets sent, 0 if error
493 * @pre @ref netapi_init, @ref pktio_create, @ref pktio_open
494 */
495 int pktio_sendMulti(PKTIO_HANDLE_T *handle,
496 Ti_Pkt * pkt[],
497 PKTIO_METADATA_T * m[],
498 int np,
499 int * err);
501 /**
502 * @ingroup netapi_pktio_functions
503 * @brief API polls a NETAPI PKTIO channel for received packets
504 *
505 * @details This api polls a pktio channel. Any pending data in the channel is
506 * passed to the @ref PKTIO_CB registered when the channel was
507 * created or opened. The channel must
508 * have already been created via @ref pktio_create or opened
509 * via @ref pktio_open. It may have
510 * been created internally during the netapi intialization.
511 * @param[in] handle The PKTIO channel handle, @ref PKTIO_HANDLE_T
512 * @param[in] p_poll_cfg Pointer to pktio poll configuration. @ref PKTIO_POLL_T
513 * @param[out] err Pointer to error code.
514 * @retval Number of packets received by poll
515 * @pre @ref netapi_init, @ref pktio_create, @ref pktio_open
516 */
517 static inline int pktio_poll(PKTIO_HANDLE_T * handle,
518 PKTIO_POLL_T * p_poll_cfg,
519 int * err)
520 {
521 return handle->_poll((struct PKTIO_HANDLE_tag *) handle, p_poll_cfg, err);
522 }
524 /**
525 * @ingroup netapi_pktio_functions
526 * @brief API polls all NETAPI PKTIO channels associarted with @ref NETAPI_T instance
527 * for received packets
528 *
529 * @details This api polls all pktio channels attached to an instance.
530 * Any pending data in these channels are
531 * passed to the @ref PKTIO_CB registered when the channel was
532 * created or opened. The channels must
533 * have already been created via @ref pktio_create or opened
534 * via @ref pktio_open. They may have
535 * been created internally during the netapi intialization.
536 * @param[in] handle The PKTIO channel handle, @ref PKTIO_HANDLE_T
537 * @param[in] p_poll_cfg Pointer to pktio poll configuration. @ref PKTIO_POLL_T
538 * @param[out] err Pointer to error code.
539 * @retval Number of packets received by poll
540 * @pre @ref netapi_init, @ref pktio_create, @ref pktio_open
541 */
542 int pktio_pollAll(NETAPI_T handle,
543 PKTIO_POLL_T * p_poll_cfg,
544 int *err);
547 /* update max_n for poll */
550 /**
551 * @brief This define sets the max number of pkts to read in one poll in the @ref PKTIO_HANDLE_T
552 */
553 #define pktio_set_max_n(handle,max_n) (handle)->max_n=max_n;
555 /**
556 * @brief This define returns NETAPI handle stored in the @ref PKTIO_HANDLE_T
557 */
558 #define pktio_get_netapi_handle(handle) (handle)->back
560 /**
561 * @brief This define sets a user space application cookie in the @ref PKTIO_HANDLE_T
562 */
563 #define pktio_set_cookie(handle, cookie) (handle)->cookie = cookie
565 /**
566 * @brief This define returns a previously set user space application cookie stored in the @ref PKTIO_HANDLE_T
567 */
568 #define pktio_get_cookie(handle) (handle)->cookie
571 /**
572 * @brief This define returns a associate queue handle stored in the @ref PKTIO_HANDLE_T
573 */
575 #define pktio_get_q(handle) (handle)->q
577 /*-----------------Extra Fast Path pkt meta data macros--------------------*/
578 #include "cppi_desc.h"
579 #include "ti/drv/pa/pa.h"
580 #include "ti/drv/pa/pasahost.h"
583 /**
584 * @ingroup netapi_pktio_functions
585 * @brief API returns default packet queue to poll for netcp RX
586 * @note: these are expensive calls, so call once and save
587 */
588 static inline Qmss_QueueHnd PKTIO_GET_DEFAULT_NETCP_Q(PKTIO_HANDLE_T *h)
589 {
590 nwalGlobCxtInfo_t Info;
591 nwal_getGlobCxtInfo(h->nwalInstanceHandle,&Info);
592 return Info.rxDefPktQ;
593 }
596 /**
597 * @ingroup netapi_pktio_functions
598 * @brief API returns L4Queue to poll for netcp RX (L4 classifier queue).
599 * @note: these are expensive calls, so call once and save
600 */
601 static inline Qmss_QueueHnd PKTIO_GET_DEFAULT_NETCP_L4Q(PKTIO_HANDLE_T *h)
602 {
603 nwalLocCxtInfo_t Info;
604 nwal_getLocCxtInfo(h->nwalInstanceHandle,&Info);
605 return Info.rxL4PktQ;
606 }
609 /**
610 * @ingroup netapi_pktio_functions
611 * @brief API to perform descriptor push to QMSS Queue
612 */
613 static inline void PKTIO_QMSS_QUEUE_PUSH_DESC_SIZE_RAW(Qmss_QueueHnd hnd,
614 void *descAddr,
615 uint32_t descSize)
616 {
617 return(Qmss_queuePushDescSizeRaw(hnd,descAddr,descSize));
618 }
620 /**
621 * @ingroup netapi_pktio_functions
622 * @brief API to perform descriptor pop from QMSS Queue
623 */
624 static inline void* PKTIO_QMSS_QUEUE_POP_RAW(Qmss_QueueHnd hnd)
625 {
626 return(Qmss_queuePopRaw(hnd));
627 }
629 /**
630 * @ingroup netapi_pktio_functions
631 * @brief API to retrieve NWAL global instance handle.
632 */
633 static inline nwal_Inst PKTIO_GET_NWAL_INSTANCE(PKTIO_HANDLE_T *h)
634 {
635 return h->nwalInstanceHandle;
636 }
639 #endif