| [258] | 1 | /////////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 2 | // File     : dma_driver.c | 
|---|
 | 3 | // Date     : 23/11/2013 | 
|---|
 | 4 | // Author   : alain greiner | 
|---|
 | 5 | // Copyright (c) UPMC-LIP6 | 
|---|
 | 6 | /////////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 7 |  | 
|---|
 | 8 | #include <giet_config.h> | 
|---|
| [320] | 9 | #include <hard_config.h> | 
|---|
| [258] | 10 | #include <dma_driver.h> | 
|---|
| [456] | 11 | #include <tty0.h> | 
|---|
| [258] | 12 | #include <vmem.h> | 
|---|
| [320] | 13 | #include <utils.h> | 
|---|
| [345] | 14 | #include <io.h> | 
|---|
| [258] | 15 |  | 
|---|
| [263] | 16 | #if !defined(X_SIZE)  | 
|---|
 | 17 | # error: You must define X_SIZE in the hard_config.h file | 
|---|
| [258] | 18 | #endif | 
|---|
 | 19 |  | 
|---|
| [263] | 20 | #if !defined(Y_SIZE)  | 
|---|
 | 21 | # error: You must define X_SIZE in the hard_config.h file | 
|---|
| [258] | 22 | #endif | 
|---|
 | 23 |  | 
|---|
| [263] | 24 | #if !defined(X_WIDTH)  | 
|---|
 | 25 | # error: You must define X_WIDTH in the hard_config.h file | 
|---|
| [258] | 26 | #endif | 
|---|
 | 27 |  | 
|---|
| [263] | 28 | #if !defined(Y_WIDTH)  | 
|---|
 | 29 | # error: You must define X_WIDTH in the hard_config.h file | 
|---|
| [258] | 30 | #endif | 
|---|
 | 31 |  | 
|---|
| [263] | 32 | #if !defined(NB_DMA_CHANNELS)  | 
|---|
 | 33 | # error: You must define NB_DMA_CHANNELS in the hard_config.h file | 
|---|
| [258] | 34 | #endif | 
|---|
 | 35 |  | 
|---|
| [320] | 36 | #if !defined(SEG_DMA_BASE)  | 
|---|
 | 37 | # error: You must define SEG_DMA_BASE in the hard_config.h file | 
|---|
 | 38 | #endif | 
|---|
 | 39 |  | 
|---|
| [333] | 40 | #if !defined(PERI_CLUSTER_INCREMENT)  | 
|---|
 | 41 | # error: You must define PERI_CLUSTER_INCREMENT in the hard_config.h file | 
|---|
| [320] | 42 | #endif | 
|---|
 | 43 |  | 
|---|
| [345] | 44 | extern volatile unsigned int _ptabs_vaddr[]; | 
|---|
| [258] | 45 |  | 
|---|
| [345] | 46 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 47 | // This low level function returns the value contained in register "index" | 
|---|
 | 48 | // in the DMA component contained in cluster "cluster_xy" | 
|---|
 | 49 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| [496] | 50 |  | 
|---|
 | 51 | #if NB_DMA_CHANNELS > 0 | 
|---|
| [345] | 52 | static | 
|---|
 | 53 | unsigned int _dma_get_register( unsigned int cluster_xy, // cluster index | 
|---|
 | 54 |                                 unsigned int channel_id, // channel index | 
|---|
 | 55 |                                 unsigned int index )     // register index | 
|---|
 | 56 | { | 
|---|
 | 57 |     unsigned int vaddr = | 
|---|
 | 58 |         SEG_DMA_BASE +  | 
|---|
 | 59 |         (cluster_xy * PERI_CLUSTER_INCREMENT) + | 
|---|
 | 60 |         (channel_id * DMA_SPAN) + | 
|---|
 | 61 |         (index << 2); | 
|---|
 | 62 |  | 
|---|
 | 63 |     return ioread32( (void*)vaddr ); | 
|---|
 | 64 | } | 
|---|
| [496] | 65 | #endif | 
|---|
| [345] | 66 |  | 
|---|
 | 67 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 68 | // This low level function sets a new value in register "index" | 
|---|
 | 69 | // in the DMA component contained in cluster "cluster_xy" | 
|---|
 | 70 | /////////////////////////////////////////////////////////////////////////////// | 
|---|
| [496] | 71 |  | 
|---|
 | 72 | #if NB_DMA_CHANNELS > 0 | 
|---|
| [345] | 73 | static | 
|---|
 | 74 | void _dma_set_register( unsigned int cluster_xy,       // cluster index | 
|---|
 | 75 |                         unsigned int channel_id,       // channel index | 
|---|
 | 76 |                         unsigned int index,            // register index | 
|---|
 | 77 |                         unsigned int value )           // value to be written | 
|---|
 | 78 | { | 
|---|
 | 79 |     unsigned int vaddr = | 
|---|
 | 80 |         SEG_DMA_BASE +  | 
|---|
 | 81 |         (cluster_xy * PERI_CLUSTER_INCREMENT) + | 
|---|
 | 82 |         (channel_id * DMA_SPAN) + | 
|---|
 | 83 |         (index << 2); | 
|---|
 | 84 |  | 
|---|
 | 85 |     iowrite32( (void*)vaddr, value ); | 
|---|
 | 86 | } | 
|---|
| [496] | 87 | #endif | 
|---|
| [345] | 88 |  | 
|---|
| [437] | 89 | //////////////////////////////////////////////// | 
|---|
| [529] | 90 | void _dma_disable_irq( unsigned int cluster_xy, | 
|---|
 | 91 |                        unsigned int channel_id ) | 
|---|
| [258] | 92 | { | 
|---|
 | 93 | #if NB_DMA_CHANNELS > 0 | 
|---|
| [263] | 94 |  | 
|---|
| [529] | 95 |     // check DMA channel parameters  | 
|---|
| [263] | 96 |     unsigned int x = cluster_xy >> Y_WIDTH; | 
|---|
 | 97 |     unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1); | 
|---|
| [529] | 98 |     if ( (x >= X_SIZE) || (y >= Y_SIZE) || (channel_id >= NB_DMA_CHANNELS) ) | 
|---|
 | 99 |     { | 
|---|
 | 100 |         _puts("\n[DMA ERROR] in _dma_disable_irq() : illegal DMA channel "); | 
|---|
 | 101 |         _exit(); | 
|---|
 | 102 |     } | 
|---|
| [258] | 103 |  | 
|---|
 | 104 |     // disable interrupt for selected channel | 
|---|
| [345] | 105 |     _dma_set_register(cluster_xy, channel_id, DMA_IRQ_DISABLE, 1); | 
|---|
| [529] | 106 |  | 
|---|
| [258] | 107 | #endif | 
|---|
 | 108 | } | 
|---|
 | 109 |  | 
|---|
| [529] | 110 | ///////////////////////////////////////////////// | 
|---|
 | 111 | void _dma_reset_channel( unsigned int cluster_xy,  | 
|---|
| [258] | 112 |                          unsigned int channel_id )  | 
|---|
 | 113 | { | 
|---|
 | 114 | #if NB_DMA_CHANNELS > 0 | 
|---|
| [263] | 115 |  | 
|---|
| [529] | 116 |     // check DMA channel parameters  | 
|---|
| [263] | 117 |     unsigned int x = cluster_xy >> Y_WIDTH; | 
|---|
 | 118 |     unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1); | 
|---|
| [529] | 119 |     if ( (x >= X_SIZE) || (y >= Y_SIZE) || (channel_id >= NB_DMA_CHANNELS) ) | 
|---|
 | 120 |     { | 
|---|
 | 121 |         _puts("\n[DMA ERROR] in _dma_reset_channel() : illegal DMA channel "); | 
|---|
 | 122 |         _exit(); | 
|---|
 | 123 |     } | 
|---|
| [258] | 124 |  | 
|---|
 | 125 |     // reset selected channel | 
|---|
| [345] | 126 |     _dma_set_register(cluster_xy, channel_id, DMA_RESET, 0); | 
|---|
| [529] | 127 |  | 
|---|
| [258] | 128 | #endif | 
|---|
 | 129 | } | 
|---|
 | 130 |  | 
|---|
| [529] | 131 | /////////////////////////////////////////////////////// | 
|---|
 | 132 | void _dma_get_status( unsigned int  cluster_xy,  | 
|---|
 | 133 |                       unsigned int  channel_id, | 
|---|
 | 134 |                       unsigned int* status )  | 
|---|
| [258] | 135 | { | 
|---|
 | 136 | #if NB_DMA_CHANNELS > 0 | 
|---|
| [263] | 137 |  | 
|---|
| [529] | 138 |     // check DMA channel parameters  | 
|---|
| [263] | 139 |     unsigned int x = cluster_xy >> Y_WIDTH; | 
|---|
 | 140 |     unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1); | 
|---|
| [529] | 141 |     if ( (x >= X_SIZE) || (y >= Y_SIZE) || (channel_id >= NB_DMA_CHANNELS) ) | 
|---|
 | 142 |     { | 
|---|
 | 143 |         _puts("\n[DMA ERROR] in _dma_get_status() : illegal DMA channel "); | 
|---|
 | 144 |         _exit(); | 
|---|
 | 145 |     } | 
|---|
| [258] | 146 |  | 
|---|
| [529] | 147 |     // returns selected channel status | 
|---|
 | 148 |     *status = _dma_get_register(cluster_xy, channel_id, DMA_LEN); | 
|---|
 | 149 |  | 
|---|
| [258] | 150 | #endif | 
|---|
 | 151 | } | 
|---|
 | 152 |  | 
|---|
| [437] | 153 | //////////////////////////////////////////////////////// | 
|---|
| [343] | 154 | void _dma_start_transfer( unsigned int       cluster_xy,  // DMA cluster | 
|---|
 | 155 |                           unsigned int       channel_id,  // DMA channel | 
|---|
 | 156 |                           unsigned long long dst_paddr,   // physical address | 
|---|
 | 157 |                           unsigned long long src_paddr,   // physical address | 
|---|
 | 158 |                           unsigned int       size )       // bytes | 
|---|
| [258] | 159 | { | 
|---|
 | 160 | #if NB_DMA_CHANNELS > 0 | 
|---|
| [263] | 161 |  | 
|---|
| [529] | 162 |     // check DMA channel parameters  | 
|---|
 | 163 |     unsigned int x = cluster_xy >> Y_WIDTH; | 
|---|
 | 164 |     unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1); | 
|---|
 | 165 |     if ( (x >= X_SIZE) || (y >= Y_SIZE) || (channel_id >= NB_DMA_CHANNELS) ) | 
|---|
 | 166 |     { | 
|---|
 | 167 |         _puts("\n[DMA ERROR] in _dma_start_transfer() : illegal DMA channel "); | 
|---|
 | 168 |         _exit(); | 
|---|
 | 169 |     } | 
|---|
 | 170 |  | 
|---|
| [258] | 171 |     // selected channel configuration and lauching | 
|---|
| [345] | 172 |     _dma_set_register(cluster_xy, channel_id, DMA_SRC, | 
|---|
 | 173 |             (unsigned int)(src_paddr)); | 
|---|
 | 174 |     _dma_set_register(cluster_xy, channel_id, DMA_SRC_EXT, | 
|---|
 | 175 |             (unsigned int)(src_paddr>>32)); | 
|---|
 | 176 |     _dma_set_register(cluster_xy, channel_id, DMA_DST, | 
|---|
 | 177 |             (unsigned int)(dst_paddr)); | 
|---|
 | 178 |     _dma_set_register(cluster_xy, channel_id, DMA_DST_EXT, | 
|---|
 | 179 |             (unsigned int)(dst_paddr>>32)); | 
|---|
 | 180 |     _dma_set_register(cluster_xy, channel_id, DMA_LEN, | 
|---|
 | 181 |             (unsigned int)size); | 
|---|
| [258] | 182 | #endif | 
|---|
 | 183 | } | 
|---|
| [343] | 184 |  | 
|---|
| [437] | 185 | /////////////////////////////////////////////////////// | 
|---|
| [343] | 186 | void _dma_physical_copy( unsigned int       cluster_xy,  // DMA cluster | 
|---|
 | 187 |                          unsigned int       channel_id,  // DMA channel | 
|---|
| [529] | 188 |                          unsigned long long dst_paddr,   // dest physical address | 
|---|
 | 189 |                          unsigned long long src_paddr,   // src physical address | 
|---|
| [343] | 190 |                          unsigned int       size )       // bytes | 
|---|
 | 191 | { | 
|---|
 | 192 | #if NB_DMA_CHANNELS > 0 | 
|---|
 | 193 |  | 
|---|
 | 194 |     // check buffers alignment constraints | 
|---|
 | 195 |     if ( (dst_paddr & 0x3)   || (src_paddr & 0x3) || (size & 0x3) ) | 
|---|
 | 196 |     { | 
|---|
| [437] | 197 |         _puts("\n[DMA ERROR] in _dma_physical_copy() : buffer unaligned\n"); | 
|---|
| [343] | 198 |         _exit(); | 
|---|
 | 199 |     } | 
|---|
 | 200 |  | 
|---|
 | 201 | #if GIET_DEBUG_DMA_DRIVER | 
|---|
| [529] | 202 | unsigned int x = cluster_xy >> Y_WIDTH; | 
|---|
 | 203 | unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1); | 
|---|
| [437] | 204 | _puts("\n[DMA DEBUG] enter _dma_physical_copy() for channel["); | 
|---|
 | 205 | _putd( x ); | 
|---|
 | 206 | _puts(","); | 
|---|
 | 207 | _putd( y ); | 
|---|
 | 208 | _puts(","); | 
|---|
 | 209 | _putd( channel_id ); | 
|---|
 | 210 | _puts("] at cycle "); | 
|---|
 | 211 | _putd( _get_proctime() ); | 
|---|
 | 212 | _puts("\n - src_paddr   = "); | 
|---|
 | 213 | _putl( src_paddr ); | 
|---|
 | 214 | _puts("\n - dst_paddr   = "); | 
|---|
 | 215 | _putl( dst_paddr ); | 
|---|
 | 216 | _puts("\n - bytes       = "); | 
|---|
| [529] | 217 | _putx( size ); | 
|---|
| [437] | 218 | _puts("\n"); | 
|---|
| [343] | 219 | #endif | 
|---|
 | 220 |  | 
|---|
| [529] | 221 |     // dma channel configuration  | 
|---|
 | 222 |     _dma_disable_irq( cluster_xy, channel_id ); | 
|---|
 | 223 |  | 
|---|
 | 224 |     // dma transfer lauching | 
|---|
| [343] | 225 |     _dma_start_transfer( cluster_xy, channel_id, dst_paddr, src_paddr, size );  | 
|---|
 | 226 |  | 
|---|
 | 227 |     // scan dma channel status  | 
|---|
| [529] | 228 |     unsigned int status; | 
|---|
 | 229 |     do | 
|---|
| [343] | 230 |     { | 
|---|
| [529] | 231 |         _dma_get_status( cluster_xy, channel_id , &status ); | 
|---|
| [343] | 232 |  | 
|---|
 | 233 | #if GIET_DEBUG_DMA_DRIVER | 
|---|
| [529] | 234 | _puts("\n[DMA DEBUG] _dma_physical_copy() : ... waiting on DMA_STATUS\n"); | 
|---|
| [343] | 235 | #endif | 
|---|
 | 236 |  | 
|---|
 | 237 |     } | 
|---|
| [529] | 238 |     while( (status != DMA_SUCCESS) &&  | 
|---|
 | 239 |            (status != DMA_READ_ERROR) && | 
|---|
 | 240 |            (status != DMA_WRITE_ERROR) ); | 
|---|
| [343] | 241 |      | 
|---|
 | 242 |     // analyse status | 
|---|
 | 243 |     if( status != DMA_SUCCESS ) | 
|---|
 | 244 |     { | 
|---|
| [529] | 245 |         _puts("\n[DMA ERROR] in _dma_physical_copy() : ERROR_STATUS"); | 
|---|
| [343] | 246 |         _exit(); | 
|---|
 | 247 |     } | 
|---|
| [437] | 248 |  | 
|---|
| [343] | 249 |     // reset dma channel | 
|---|
| [529] | 250 |     _dma_reset_channel( cluster_xy , channel_id ); | 
|---|
| [343] | 251 |  | 
|---|
 | 252 | #if GIET_DEBUG_DMA_DRIVER | 
|---|
| [437] | 253 | _puts("\n[DMA DEBUG] exit _dma_physical_copy() at cycle "); | 
|---|
 | 254 | _putd( _get_proctime() ); | 
|---|
 | 255 | _puts("\n"); | 
|---|
| [343] | 256 | #endif | 
|---|
 | 257 |  | 
|---|
 | 258 | #else // NB_DMA_CHANNELS == 0 | 
|---|
| [437] | 259 |  | 
|---|
 | 260 |     _puts("\n[DMA ERROR] in _dma_physical_copy() : NB_DMA_CHANNELS == 0\n"); | 
|---|
| [343] | 261 |     _exit(); | 
|---|
| [437] | 262 |  | 
|---|
| [343] | 263 | #endif | 
|---|
 | 264 | } | 
|---|
 | 265 |  | 
|---|
| [437] | 266 |  | 
|---|
 | 267 | //////////////////////////////////////// | 
|---|
| [343] | 268 | void  _dma_copy( unsigned int cluster_xy,    // DMA cluster | 
|---|
 | 269 |                  unsigned int channel_id,    // DMA channel | 
|---|
 | 270 |                  unsigned int dst_vaddr,     // dst_vaddr buffer vbase | 
|---|
 | 271 |                  unsigned int src_vaddr,     // src_vaddr buffer vbase | 
|---|
 | 272 |                  unsigned int size )         // bytes | 
|---|
| [258] | 273 | { | 
|---|
 | 274 | #if NB_DMA_CHANNELS > 0 | 
|---|
 | 275 |  | 
|---|
| [343] | 276 |     // check buffers alignment constraints | 
|---|
 | 277 |     if ( (dst_vaddr & 0x3)   || (src_vaddr & 0x3) || (size & 0x3) ) | 
|---|
 | 278 |     { | 
|---|
| [437] | 279 |         _puts("\n[DMA ERROR] in _dma_copy() : buffer unaligned\n"); | 
|---|
| [343] | 280 |         _exit(); | 
|---|
 | 281 |     } | 
|---|
 | 282 |  | 
|---|
| [529] | 283 |     unsigned long long src_paddr; | 
|---|
 | 284 |     unsigned long long dst_paddr; | 
|---|
| [258] | 285 |     unsigned int flags; | 
|---|
 | 286 |  | 
|---|
 | 287 | #if GIET_DEBUG_DMA_DRIVER | 
|---|
| [529] | 288 | unsigned int x = cluster_xy >> Y_WIDTH; | 
|---|
 | 289 | unsigned int y = cluster_xy & ((1<<Y_WIDTH)-1); | 
|---|
| [437] | 290 | _puts("\n[DMA DEBUG] enter _dma_copy() for channel["); | 
|---|
 | 291 | _putd( x ); | 
|---|
 | 292 | _puts(","); | 
|---|
 | 293 | _putd( y ); | 
|---|
 | 294 | _puts(","); | 
|---|
 | 295 | _putd( channel_id ); | 
|---|
 | 296 | _puts("] at cycle "); | 
|---|
 | 297 | _putd( _get_proctime() ); | 
|---|
 | 298 | _puts("\n - src_vaddr   = "); | 
|---|
 | 299 | _putx( src_vaddr ); | 
|---|
 | 300 | _puts("\n - dst_vaddr   = "); | 
|---|
 | 301 | _putx( dst_vaddr ); | 
|---|
 | 302 | _puts("\n - bytes       = "); | 
|---|
 | 303 | _putd( size ); | 
|---|
 | 304 | _puts("\n"); | 
|---|
| [258] | 305 | #endif | 
|---|
 | 306 |  | 
|---|
| [343] | 307 |     // get src_paddr buffer physical addresse | 
|---|
| [529] | 308 |     src_paddr = _v2p_translate( src_vaddr , &flags ); | 
|---|
| [258] | 309 |  | 
|---|
| [343] | 310 |     // get dst_paddr buffer physical addresse | 
|---|
| [529] | 311 |     dst_paddr = _v2p_translate( dst_vaddr , &flags ); | 
|---|
| [258] | 312 |  | 
|---|
 | 313 | #if GIET_DEBUG_DMA_DRIVER | 
|---|
| [437] | 314 | _puts("\n - src_paddr   = "); | 
|---|
 | 315 | _putl( src_paddr ); | 
|---|
 | 316 | _puts("\n - dst_paddr   = "); | 
|---|
 | 317 | _putl( dst_paddr ); | 
|---|
 | 318 | _puts("\n"); | 
|---|
| [258] | 319 | #endif | 
|---|
 | 320 |  | 
|---|
 | 321 |     // dma channel configuration & lauching | 
|---|
| [343] | 322 |     _dma_start_transfer(  cluster_xy, channel_id, dst_paddr, src_paddr, size );  | 
|---|
| [258] | 323 |  | 
|---|
 | 324 |     // scan dma channel status  | 
|---|
| [529] | 325 |     unsigned int status; | 
|---|
 | 326 |     do | 
|---|
| [258] | 327 |     { | 
|---|
| [529] | 328 |         _dma_get_status( cluster_xy, channel_id , &status ); | 
|---|
| [258] | 329 |  | 
|---|
 | 330 | #if GIET_DEBUG_DMA_DRIVER | 
|---|
| [529] | 331 | _puts("\n[DMA DEBUG] _dma_physical_copy() : ... waiting on DMA_STATUS\n"); | 
|---|
| [258] | 332 | #endif | 
|---|
 | 333 |  | 
|---|
 | 334 |     } | 
|---|
| [529] | 335 |     while( (status != DMA_SUCCESS) &&  | 
|---|
 | 336 |            (status != DMA_READ_ERROR) && | 
|---|
 | 337 |            (status != DMA_WRITE_ERROR) ); | 
|---|
| [258] | 338 |      | 
|---|
 | 339 |     // analyse status | 
|---|
 | 340 |     if( status != DMA_SUCCESS ) | 
|---|
 | 341 |     { | 
|---|
| [437] | 342 |         _puts("\n[DMA ERROR] in _dma_copy() : bad DMA_STATUS\n"); | 
|---|
| [258] | 343 |         _exit(); | 
|---|
 | 344 |     } | 
|---|
 | 345 |     // reset dma channel | 
|---|
| [529] | 346 |     _dma_reset_channel( cluster_xy, channel_id ); | 
|---|
| [258] | 347 |  | 
|---|
 | 348 | #if GIET_DEBUG_DMA_DRIVER | 
|---|
| [437] | 349 | _puts("\n[DMA DEBUG] exit _dma_copy() at cycle "); | 
|---|
 | 350 | _putd( _get_proctime() ); | 
|---|
 | 351 | _puts("\n"); | 
|---|
| [258] | 352 | #endif | 
|---|
 | 353 |  | 
|---|
 | 354 | #else // NB_DMA_CHANNELS == 0 | 
|---|
| [437] | 355 |  | 
|---|
 | 356 |     _puts("\n[DMA ERROR] in _dma_copy() : NB_DMA_CHANNELS == 0\n"); | 
|---|
| [258] | 357 |     _exit(); | 
|---|
| [437] | 358 |  | 
|---|
| [258] | 359 | #endif | 
|---|
 | 360 | } // end _dma_copy | 
|---|
 | 361 |  | 
|---|
| [529] | 362 |  | 
|---|
| [437] | 363 | ///////////////////////////////////// | 
|---|
| [320] | 364 | void _dma_isr( unsigned int irq_type, | 
|---|
 | 365 |                unsigned int irq_id, | 
|---|
 | 366 |                unsigned int channel ) | 
|---|
 | 367 | { | 
|---|
| [437] | 368 |     _puts("\n[DMA ERROR] _dma_isr() not implemented\n"); | 
|---|
| [320] | 369 |     _exit(); | 
|---|
 | 370 | } | 
|---|
| [258] | 371 |  | 
|---|
 | 372 |  | 
|---|
 | 373 |  | 
|---|
| [320] | 374 |  | 
|---|
| [258] | 375 | // tab-width: 4 | 
|---|
 | 376 | // c-basic-offset: 4 | 
|---|
 | 377 | // c-file-offsets:((innamespace . 0)(inline-open . 0)) | 
|---|
 | 378 | // indent-tabs-mode: nil | 
|---|
 | 379 | // End: | 
|---|
 | 380 | // vim: filetype=c:expandtab:shiftwidth=4:tabstop=4:softtabstop=4 | 
|---|
 | 381 |  | 
|---|