![]() |
|
|||
File indexing completed on 2025-05-11 08:23:43
0001 /* SPDX-License-Identifier: BSD-2-Clause */ 0002 0003 /* shm_driver.h 0004 * 0005 * This include file contains all the constants, structures, 0006 * and global variables for this RTEMS based shared memory 0007 * communications interface driver. 0008 * 0009 * Processor board dependencies are in other files. 0010 * 0011 * COPYRIGHT (c) 1989-2007. 0012 * On-Line Applications Research Corporation (OAR). 0013 * 0014 * Redistribution and use in source and binary forms, with or without 0015 * modification, are permitted provided that the following conditions 0016 * are met: 0017 * 1. Redistributions of source code must retain the above copyright 0018 * notice, this list of conditions and the following disclaimer. 0019 * 2. Redistributions in binary form must reproduce the above copyright 0020 * notice, this list of conditions and the following disclaimer in the 0021 * documentation and/or other materials provided with the distribution. 0022 * 0023 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 0024 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 0025 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 0026 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 0027 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 0028 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 0029 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 0030 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 0031 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 0032 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 0033 * POSSIBILITY OF SUCH DAMAGE. 0034 */ 0035 0036 #ifndef __SHM_h 0037 #define __SHM_h 0038 0039 #include <rtems.h> 0040 #include <rtems/clockdrv.h> 0041 0042 #ifdef __cplusplus 0043 extern "C" { 0044 #endif 0045 0046 /* The information contained in the Node Status, Locked Queue, and 0047 * Envelope Control Blocks must be maintained in a NEUTRAL format. 0048 * Currently the neutral format may be selected as big or little 0049 * endian by simply defining either NEUTRAL_BIG or NEUTRAL_LITTLE. 0050 * 0051 * It is CRITICAL to note that the neutral format can ONLY be 0052 * changed by modifying this file and recompiling the ENTIRE 0053 * SHM driver including ALL target specific support files. 0054 * 0055 * The following table details the memory contents for the endian 0056 * field of the Node Status Control Block in the various 0057 * data format configurations (data is in hexadecimal): 0058 * 0059 * NEUTRAL NATIVE BYTE 0 BYTE 1 BYTE 2 BYTE 3 0060 * ======= ====== ====== ====== ====== ====== 0061 * BIG BIG 00 00 00 01 0062 * BIG LITTLE 10 00 00 00 0063 * LITTLE BIG 01 00 00 00 0064 * LITTLE LITTLE 00 00 00 10 0065 * 0066 * 0067 * NOTE: XXX 0068 * PORTABILITY OF LOCKING INSTRUCTIONS 0069 * =================================== 0070 * The locking mechanism described below is not 0071 * general enough. Where the hardware supports 0072 * it we should use "atomic swap" instructions 0073 * so the values in the lock can be tailored to 0074 * support a CPU with only weak atomic memory 0075 * instructions. There are combinations of 0076 * CPUs with inflexible atomic memory instructions 0077 * which appear to be incompatible. For example, 0078 * the SPARClite instruction uses a byte which is 0079 * 0xFF when locked. The PA-RISC uses 1 to indicate 0080 * locked and 0 when unlocked. These CPUs appear to 0081 * have incompatible lock instructions. But 0082 * they could be used in a heterogenous system 0083 * with does not mix SPARCs and PA-RISCs. For 0084 * example, the i386 and SPARC or i386 and SPARC 0085 * could work together. The bottom line is that 0086 * not every CPU will work together using this 0087 * locking scheme. There are supposed to be 0088 * algorithms to do this without hardware assist 0089 * and one of these should be incorporated into 0090 * the shared memory driver. 0091 * 0092 * The most flexible scheme using the instructions 0093 * of the various CPUs for efficiency would be to use 0094 * "atomic swaps" wherever possible. Make the lock 0095 * and unlock configurable much like BIG vs LITTLE 0096 * endian use of shared memory is now. The values 0097 * of the lock could then reflect the "worst" 0098 * CPU in a system. This still results in mixes 0099 * of CPUs which are incompatible. 0100 * 0101 * The current locking mechanism is based upon the MC68020 0102 * "tas" instruction which is atomic. All ports to other CPUs 0103 * comply with the restrictive placement of lock bit by this 0104 * instruction. The lock bit is the most significant bit in a 0105 * big-endian uint32_t . On other processors, the lock is 0106 * typically implemented via an atomic swap or atomic modify 0107 * bits type instruction. 0108 */ 0109 0110 #define NEUTRAL_BIG 0111 0112 #ifdef NEUTRAL_BIG 0113 #define SHM_BIG 0x00000001 0114 #define SHM_LITTLE 0x10000000 0115 #endif 0116 0117 #ifdef NEUTRAL_LITTLE 0118 #define SHM_BIG 0x01000000 0119 #define SHM_LITTLE 0x00000010 0120 #endif 0121 0122 /* 0123 * The following are the values used to fill in the lock field. Some CPUs 0124 * are able to write only a single value into field. By making the 0125 * lock and unlock values configurable, CPUs which support "atomic swap" 0126 * instructions can generally be made to work in any heterogeneous 0127 * configuration. However, it is possible for two CPUs to be incompatible 0128 * in regards to the lock field values. This occurs when two CPUs 0129 * which write only a single value to the field are used in a system 0130 * but the two CPUs write different incompatible values. 0131 * 0132 * NOTE: The following is a first attempt at defining values which 0133 * have a chance at working together. The m68k should use 0134 * chk2 instead of tas to be less restrictive. Target endian 0135 * problems (like the Force CPU386 which has (broken) big endian 0136 * view of the VMEbus address space) are not addressed yet. 0137 */ 0138 0139 #if defined(__mc68000__) 0140 #define SHM_LOCK_VALUE 0x80000000 0141 #define SHM_UNLOCK_VALUE 0 0142 #define SHM_LOCK_VALUE 0x80000000 0143 #define SHM_UNLOCK_VALUE 0 0144 #elif defined(__i386__) 0145 #define SHM_LOCK_VALUE 0x80000000 0146 #define SHM_UNLOCK_VALUE 0 0147 #elif defined(__mips__) 0148 #define SHM_LOCK_VALUE 0x80000000 0149 #define SHM_UNLOCK_VALUE 0 0150 #elif defined(__hppa__) 0151 #define SHM_LOCK_VALUE 0 0152 #define SHM_UNLOCK_VALUE 1 0153 #elif defined(__PPC__) 0154 #define SHM_LOCK_VALUE 1 0155 #define SHM_UNLOCK_VALUE 0 0156 #elif defined(__unix__) 0157 #define SHM_LOCK_VALUE 0 0158 #define SHM_UNLOCK_VALUE 1 0159 #elif defined(_AM29K) 0160 #define SHM_LOCK_VALUE 0 0161 #define SHM_UNLOCK_VALUE 1 0162 #elif defined(__nios2__) 0163 #define SHM_LOCK_VALUE 1 0164 #define SHM_UNLOCK_VALUE 0 0165 #elif defined(__sparc__) 0166 #define SHM_LOCK_VALUE 1 0167 #define SHM_UNLOCK_VALUE 0 0168 #elif defined(no_cpu) /* for this values are irrelevant */ 0169 #define SHM_LOCK_VALUE 1 0170 #define SHM_UNLOCK_VALUE 0 0171 #else 0172 #error "shm_driver.h - no SHM_LOCK_VALUE defined for this CPU architecture" 0173 #endif 0174 0175 #define Shm_Convert( value ) \ 0176 ((Shm_Configuration->convert) ? \ 0177 (*Shm_Configuration->convert)(value) : (value)) 0178 0179 /* constants */ 0180 0181 #define SHM_MASTER 1 /* master initialization node */ 0182 #define SHM_FIRST_NODE 1 0183 0184 /* size constants */ 0185 0186 #define KILOBYTE (1024) 0187 #define MEGABYTE (1024*1024) 0188 0189 /* inter-node interrupt values */ 0190 0191 #define NO_INTERRUPT 0 /* used for polled nodes */ 0192 #define BYTE 1 0193 #define WORD 2 0194 #define LONG 4 0195 0196 /* operational mode constants -- used in SHM Configuration Table */ 0197 #define POLLED_MODE 0 0198 #define INTR_MODE 1 0199 0200 /* error codes */ 0201 0202 #define NO_ERROR 0 0203 #define SHM_NO_FREE_PKTS 0xf0000 0204 0205 /* null pointers of different types */ 0206 0207 #define NULL_ENV_CB ((Shm_Envelope_control *) 0) 0208 #define NULL_CONVERT 0 0209 0210 /* 0211 * size of stuff before preamble in envelope. 0212 * It must be a constant since we will use it to generate MAX_PACKET_SIZE 0213 */ 0214 0215 #define SHM_ENVELOPE_PREFIX_OVERHEAD (4 * sizeof(vol_u32)) 0216 0217 /* 0218 * The following is adjusted so envelopes are MAX_ENVELOPE_SIZE bytes long. 0219 * It must be >= RTEMS_MINIMUM_PACKET_SIZE in mppkt.h. 0220 */ 0221 0222 #ifndef MAX_ENVELOPE_SIZE 0223 #define MAX_ENVELOPE_SIZE 0x180 0224 #endif 0225 0226 #define MAX_PACKET_SIZE (MAX_ENVELOPE_SIZE - \ 0227 SHM_ENVELOPE_PREFIX_OVERHEAD + \ 0228 sizeof(Shm_Envelope_preamble) + \ 0229 sizeof(Shm_Envelope_postamble)) 0230 0231 0232 /* constants pertinent to Locked Queue routines */ 0233 0234 #define LQ_UNLOCKED SHM_UNLOCK_VALUE 0235 #define LQ_LOCKED SHM_LOCK_VALUE 0236 0237 /* constants related to the Free Envelope Pool */ 0238 0239 #define FREE_ENV_POOL 0 0240 #define FREE_ENV_CB (&Shm_Locked_queues[ FREE_ENV_POOL ]) 0241 0242 /* The following are important when dealing with 0243 * the shared memory communications interface area. 0244 * 0245 * NOTE: The starting address and length of the shared memory 0246 * is defined in a system dependent file. 0247 */ 0248 0249 #define START_NS_CBS ((void *)Shm_Configuration->base) 0250 #define START_LQ_CBS ((START_NS_CBS) + \ 0251 ( (sizeof (Shm_Node_status_control)) * (SHM_MAXIMUM_NODES + 1) ) ) 0252 #define START_ENVELOPES ( ((void *) START_LQ_CBS) + \ 0253 ( (sizeof (Shm_Locked_queue_Control)) * (SHM_MAXIMUM_NODES + 1) ) ) 0254 #define END_SHMCI_AREA ( (void *) START_ENVELOPES + \ 0255 ( (sizeof (Shm_Envelope_control)) * Shm_Maximum_envelopes ) ) 0256 #define END_SHARED_MEM (START_NS_CBS+Shm_Configuration->length) 0257 0258 /* macros */ 0259 0260 #define Shm_Is_master_node() \ 0261 ( SHM_MASTER == rtems_object_get_local_node() ) 0262 0263 #define Shm_Free_envelope( ecb ) \ 0264 Shm_Locked_queue_Add( FREE_ENV_CB, (ecb) ) 0265 #define Shm_Allocate_envelope() \ 0266 Shm_Locked_queue_Get(FREE_ENV_CB) 0267 0268 #define Shm_Initialize_receive_queue(node) \ 0269 Shm_Locked_queue_Initialize( &Shm_Locked_queues[node], node ) 0270 0271 #define Shm_Append_to_receive_queue(node, ecb) \ 0272 Shm_Locked_queue_Add( &Shm_Locked_queues[node], (ecb) ) 0273 0274 #define Shm_Envelope_control_to_packet_prefix_pointer(ecb) \ 0275 ((void *)(ecb)->packet) 0276 0277 #define Shm_Packet_prefix_to_envelope_control_pointer( pkt ) \ 0278 ((Shm_Envelope_control *)((uint8_t*)(pkt) - \ 0279 (sizeof(Shm_Envelope_preamble) + SHM_ENVELOPE_PREFIX_OVERHEAD))) 0280 0281 #define Shm_Build_preamble(ecb, node) \ 0282 (ecb)->Preamble.endian = Shm_Configuration->format 0283 0284 #define Shm_Build_postamble( ecb ) 0285 0286 /* volatile types */ 0287 0288 typedef volatile uint8_t vol_u8; 0289 typedef volatile uint32_t vol_u32; 0290 0291 /* shm control information */ 0292 0293 struct shm_info { 0294 vol_u32 not_currently_used_0; 0295 vol_u32 not_currently_used_1; 0296 vol_u32 not_currently_used_2; 0297 vol_u32 not_currently_used_3; 0298 }; 0299 0300 typedef struct { 0301 /*byte start_of_text;*/ 0302 vol_u32 endian; 0303 vol_u32 not_currently_used_0; 0304 vol_u32 not_currently_used_1; 0305 vol_u32 not_currently_used_2; 0306 } Shm_Envelope_preamble; 0307 0308 typedef struct { 0309 } Shm_Envelope_postamble; 0310 0311 /* WARNING! If you change this structure, don't forget to change 0312 * SHM_ENVELOPE_PREFIX_OVERHEAD and 0313 * Shm_Packet_prefix_to_envelope_control_pointer() above. 0314 */ 0315 0316 /* This comment block describes the contents of each field 0317 * of the Envelope Control Block: 0318 * 0319 * next - The index of the next envelope on this queue. 0320 * queue - The index of the queue this envelope is on. 0321 * index - The index of this envelope. 0322 * Preamble - Generic packet preamble. One day this structure 0323 * could be enhanced to contain routing information. 0324 * packet - RTEMS MPCI packet. Untouched by SHM Driver 0325 * other than copying and format conversion as 0326 * documented in the RTEMS User's Guide. 0327 * Postamble - Generic packet postamble. One day this structure 0328 * could be enhanced to contain checksum information. 0329 */ 0330 0331 typedef struct { 0332 vol_u32 next; /* next envelope on queue */ 0333 vol_u32 queue; /* queue on which this resides */ 0334 vol_u32 index; /* index into array of envelopes*/ 0335 vol_u32 pad0; /* insure the next one is aligned */ 0336 Shm_Envelope_preamble Preamble; /* header information */ 0337 vol_u8 packet[MAX_PACKET_SIZE]; /* RTEMS INFO */ 0338 Shm_Envelope_postamble Postamble;/* trailer information */ 0339 } Shm_Envelope_control; 0340 0341 /* This comment block describes the contents of each field 0342 * of the Locked Queue Control Block: 0343 * 0344 * lock - Lock used to insure mutually exclusive access. 0345 * front - Index of first envelope on queue. This field 0346 * is used to remove head of queue (receive). 0347 * rear - Index of last envelope on queue. This field 0348 * is used to add evelope to queue (send). 0349 * owner - The node number of the recipient (owning) node. 0350 * RTEMS does not use the node number zero (0). 0351 * The zero node is used by the SHM Driver for the 0352 * Free Envelope Queue shared by all nodes. 0353 */ 0354 0355 typedef struct { 0356 vol_u32 lock; /* lock field for this queue */ 0357 vol_u32 front; /* first envelope on queue */ 0358 vol_u32 rear; /* last envelope on queue */ 0359 vol_u32 owner; /* receiving (i.e. owning) node */ 0360 } Shm_Locked_queue_Control; 0361 0362 /* This comment block describes the contents of each field 0363 * of the Node Status Control Block: 0364 * 0365 * status - Node status. Current values are Pending Initialization, 0366 * Initialization Complete, and Active Node. Other values 0367 * could be added to enhance fault tolerance. 0368 * error - Zero if the node has not failed. Otherwise, 0369 * this field contains a status indicating the 0370 * failure reason. 0371 * int_address, int_value, and int_length 0372 * - These field are the Interrupt Information table 0373 * for this node in neutral format. This is how 0374 * each node knows how to generate interrupts. 0375 */ 0376 0377 typedef struct { 0378 vol_u32 status; /* node status information */ 0379 vol_u32 error; /* fatal error code */ 0380 vol_u32 int_address; /* write here for interrupt */ 0381 vol_u32 int_value; /* this value causes interrupt */ 0382 vol_u32 int_length; /* for this length (0,1,2,4) */ 0383 vol_u32 not_currently_used_0; 0384 vol_u32 not_currently_used_1; 0385 vol_u32 not_currently_used_2; 0386 } Shm_Node_status_control; 0387 0388 /* This comment block describes the contents of each field 0389 * of the Interrupt Information Table. This table describes 0390 * how another node can generate an interrupt to this node. 0391 * This information is target board dependent. If the 0392 * SHM Driver is in POLLED_MODE, then all fields should 0393 * be initialized to NO_INTERRUPT. 0394 * 0395 * address - The address to which another node should 0396 * write to cause an interrupt. 0397 * value - The value which must be written 0398 * length - The size of the value to write. Valid 0399 * values are BYTE, WORD, and LONG. 0400 * 0401 * NOTE: The Node Status Control Block contains this 0402 * information in neutral format and not in a 0403 * structure to avoid potential alignment problems. 0404 */ 0405 0406 typedef struct { 0407 vol_u32 *address; /* write here for interrupt */ 0408 vol_u32 value; /* this value causes interrupt */ 0409 vol_u32 length; /* for this length (0,1,2,4) */ 0410 } Shm_Interrupt_information; 0411 0412 /* SHM Configuration Table 0413 * 0414 * This comment block describes the contents of each field 0415 * of the SHM Configuration Table. 0416 * 0417 * base - The base address of the shared memory. This 0418 * address may be specific to this node. 0419 * length - The length of the shared memory in bytes. 0420 * format - The natural format for uint32_t 's in the 0421 * shared memory. Valid values are currently 0422 * only SHM_LITTLE and SHM_BIG. 0423 * convert - The address of the routine which converts 0424 * between neutral and local format. 0425 * poll_intr - The operational mode of the driver. Some 0426 * target boards may not provide hardware for 0427 * an interprocessor interrupt. If POLLED_MODE 0428 * is selected, the SHM driver will use a 0429 * Classiv API Timer instance to poll for 0430 * incoming packets. Throughput is dependent 0431 * on the time between clock interrupts. 0432 * Valid values are POLLED_MODE and INTR_MODE. 0433 * cause_intr - This is the address of the routine used to 0434 * write to a particular address and cause an 0435 * interrupt on another node. This routine 0436 * may need to be target dependent if something 0437 * other than a normal write from C does not work. 0438 * Intr - This structure describes the operation required 0439 * to cause an interrupt to this node. The actual 0440 * contents of this structure are described above. 0441 */ 0442 0443 struct shm_config_info { 0444 vol_u32 *base; /* base address of SHM */ 0445 vol_u32 length; /* length (in bytes) of SHM */ 0446 vol_u32 format; /* SHM is big or little endian */ 0447 uint32_t (*convert)( uint32_t );/* neutral conversion routine */ 0448 vol_u32 poll_intr;/* POLLED or INTR driven mode */ 0449 void (*cause_intr)( uint32_t); 0450 Shm_Interrupt_information Intr; /* cause intr information */ 0451 }; 0452 0453 typedef struct shm_config_info shm_config_table; 0454 0455 #define SHM_MAXIMUM_NODES _MPCI_Configuration.maximum_nodes 0456 0457 /* global variables */ 0458 0459 #ifdef _SHM_INIT 0460 #define SHM_EXTERN 0461 #else 0462 #define SHM_EXTERN extern 0463 #endif 0464 0465 SHM_EXTERN shm_config_table *Shm_Configuration; 0466 SHM_EXTERN Shm_Interrupt_information *Shm_Interrupt_table; 0467 SHM_EXTERN Shm_Node_status_control *Shm_Node_statuses; 0468 SHM_EXTERN Shm_Locked_queue_Control *Shm_Locked_queues; 0469 SHM_EXTERN Shm_Envelope_control *Shm_Envelopes; 0470 SHM_EXTERN uint32_t Shm_Receive_message_count; 0471 SHM_EXTERN uint32_t Shm_Null_message_count; 0472 SHM_EXTERN uint32_t Shm_Interrupt_count; 0473 SHM_EXTERN Shm_Locked_queue_Control *Shm_Local_receive_queue; 0474 SHM_EXTERN Shm_Node_status_control *Shm_Local_node_status; 0475 SHM_EXTERN uint32_t Shm_isrstat; 0476 /* reported by shmdr */ 0477 0478 SHM_EXTERN uint32_t Shm_Pending_initialization; 0479 SHM_EXTERN uint32_t Shm_Initialization_complete; 0480 SHM_EXTERN uint32_t Shm_Active_node; 0481 0482 SHM_EXTERN uint32_t Shm_Maximum_envelopes; 0483 0484 SHM_EXTERN uint32_t Shm_Locked_queue_End_of_list; 0485 SHM_EXTERN uint32_t Shm_Locked_queue_Not_on_list; 0486 0487 /* functions */ 0488 0489 /* locked queue routines */ 0490 void Shm_Locked_queue_Add( 0491 Shm_Locked_queue_Control *, Shm_Envelope_control * ); 0492 Shm_Envelope_control *Shm_Locked_queue_Get( Shm_Locked_queue_Control * ); 0493 void Shm_Locked_queue_Initialize( 0494 Shm_Locked_queue_Control *, uint32_t); 0495 /* Shm_Initialize_lock is CPU dependent */ 0496 /* Shm_Lock is CPU dependent */ 0497 /* Shm_Unlock is CPU dependent */ 0498 0499 /* portable routines */ 0500 void Init_env_pool( void ); 0501 void Shm_Print_statistics( void ); 0502 void MPCI_Fatal( rtems_fatal_source, bool, rtems_fatal_code ); 0503 rtems_task Shm_Cause_interrupt( uint32_t ); 0504 void Shm_install_timer( void ); 0505 void Shm_Convert_packet( rtems_packet_prefix * ); 0506 0507 /* CPU specific routines are inlined in shmcpu.h */ 0508 0509 /* target specific routines */ 0510 void *Shm_Convert_address( void * ); 0511 void Shm_Get_configuration( uint32_t, shm_config_table ** ); 0512 void Shm_isr( void ); 0513 void Shm_setvec( void ); 0514 0515 void Shm_Initialize_lock( Shm_Locked_queue_Control * ); 0516 void Shm_Lock( Shm_Locked_queue_Control * ); 0517 void Shm_Unlock( Shm_Locked_queue_Control * ); 0518 0519 /* MPCI entry points */ 0520 rtems_mpci_entry Shm_Get_packet( 0521 rtems_packet_prefix ** 0522 ); 0523 0524 rtems_mpci_entry Shm_Initialization( void ); 0525 0526 rtems_mpci_entry Shm_Receive_packet( 0527 rtems_packet_prefix ** 0528 ); 0529 0530 rtems_mpci_entry Shm_Return_packet( 0531 rtems_packet_prefix * 0532 ); 0533 0534 rtems_mpci_entry Shm_Send_packet( 0535 uint32_t, 0536 rtems_packet_prefix * 0537 ); 0538 0539 extern rtems_mpci_table MPCI_table; 0540 0541 #ifdef _SHM_INIT 0542 0543 /* multiprocessor communications interface (MPCI) table */ 0544 0545 rtems_mpci_table MPCI_table = { 0546 100000, /* default timeout value in ticks */ 0547 MAX_PACKET_SIZE, /* maximum packet size */ 0548 Shm_Initialization, /* initialization procedure */ 0549 Shm_Get_packet, /* get packet procedure */ 0550 Shm_Return_packet, /* return packet procedure */ 0551 Shm_Send_packet, /* packet send procedure */ 0552 Shm_Receive_packet /* packet receive procedure */ 0553 }; 0554 0555 #endif 0556 0557 #ifdef __cplusplus 0558 } 0559 #endif 0560 0561 #endif 0562 /* end of include file */
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.3.7 LXR engine. The LXR team |
![]() ![]() |