Ignore:
Timestamp:
Mar 26, 2014, 6:44:44 PM (10 years ago)
Author:
alain
Message:

Introducing a major release, to suppoort the tsar_generic_leti platform
and the various (external or internal) peripherals configurations.
The map.xml format has been modified, in order to support the new
vci_iopic componentand a new policy for peripherals initialisation.
The IRQs are nom described in the XICU and IOPIC components
(and not anymore in the processors).
To enforce this major change, the map.xml file signature changed:
The signature value must be: 0xDACE2014

This new release has been tested on the tsar_generic_leti platform
for the following mappings:

  • 4c_4p_sort_leti
  • 4c_4p_sort_leti_ext
  • 4c_4p_transpose_leti
  • 4c_4p_transpose_leti_ext
  • 4c_1p_four_leti_ext
File:
1 edited

Legend:

Unmodified
Added
Removed
  • soft/giet_vm/giet_drivers/hba_driver.c

    r289 r295  
    22// File     : hba_driver.c
    33// Date     : 23/11/2013
    4 // Author   : alain greiner and zhang
     4// Author   : alain greiner
    55// Copyright (c) UPMC-LIP6
    66///////////////////////////////////////////////////////////////////////////////////
     
    99// block oriented, external storage contrÃŽler, respecting the AHCI standard.
    1010//
    11 // It can exist only one ahci-device controler in the architecture.
     11// The seg_ioc_base (standard HBA virtual base address) and seg_ioc_base_bis
     12// (backup HBA virtual base address) must be defined in giet_vsegs.ld file.
     13//////////////////////////////////////////////////////////////////////////////////
     14// Implementation notes:
    1215//
    13 // The _ioc_read() and _ioc_write() functions use the _ioc_access() function,
    14 // that is always blocking, but can be called in 4 modes:
     16// 1. In order to share code, the two _hba_read() and _hba_write() functions
     17//    call the same _hba_set_cmd() function.
    1518//
    16 // - In BOOT_PA mode, the _ioc_access() function use the buffer virtual address
    17 //   as a physical address (as the page tables are not build) and use a polling
    18 //   policy on the IOC_STATUS register to detect transfer completion, as
    19 //   hardware interrupts are not activated. This mode is used by the
    20 //   boot code to load the map.bin file into memory.
    21 //
    22 // - In BOOT_VA mode, the _ioc_access() function makes a V2P translation to
    23 //   compute the buffer physical address, and use a polling policy on IOC_STATUS
    24 //   register to detect transfer completion. This mode is used by the boot code
    25 //   to load the various .elf files into memory.
    26 //
    27 // - In KERNEL mode, the _ioc_access() function makes a V2P translation to
    28 //   compute the buffer physical address, and use a descheduling strategy:
    29 //   The ISR executed when transfer completes should restart the calling task.
    30 //   There is no checking of user access right to the memory buffer.
    31 //   This mode must be used to access IOC, for an "open" system call.
    32 //
    33 // - In USER mode, the _ioc_access() function makes a V2P translation to
    34 //   compute the buffer physical address, and use a descheduling strategy:
    35 //   The ISR executed when transfer completes should restart the calling task,
    36 //   The user access right to the memory buffer must be checked.
    37 //   This mode must be used to access IOC, for a "read/write" system call.
    38 //
    39 // As the IOC component can be used by several programs running in parallel,
    40 // the _ioc_lock variable guaranties exclusive access to the device.  The
    41 // _ioc_read() and _ioc_write() functions use atomic LL/SC to get the lock.
    42 //
    43 // The IOMMU can be activated or not:
    44 //
    45 // 1) When the IOMMU is used, a fixed size 2Mbytes vseg is allocated to
    46 // the IOC peripheral, in the I/O virtual space, and the user buffer is
    47 // dynamically remapped in the IOMMU page table. The corresponding entry
    48 // in the IOMMU PT1 is defined by the kernel _ioc_iommu_ix1 variable.
    49 // The number of pages to be unmapped is stored in the _ioc_npages variable.
    50 // The number of PT2 entries is dynamically computed and stored in the
    51 // kernel _ioc_iommu_npages variable. It cannot be larger than 512.
    52 // The user buffer is unmapped by the _ioc_completed() function when
    53 // the transfer is completed.
    54 //
    55 // 2/ If the IOMMU is not used, we check that  the user buffer is mapped to a
    56 // contiguous physical buffer (this is generally true because the user space
    57 // page tables are statically constructed to use contiguous physical memory).
    58 //
    59 // Finally, the memory buffer must fulfill the following conditions:
    60 // - The buffer must be word aligned,
    61 // - The buffer must be mapped in user space for an user access,
    62 // - The buffer must be writable in case of (to_mem) access,
    63 // - The total number of physical pages occupied by the user buffer cannot
    64 //   be larger than 512 pages if the IOMMU is activated,
    65 // - All physical pages occupied by the user buffer must be contiguous
    66 //   if the IOMMU is not activated.
    67 // An error code is returned if these conditions are not verified.
    68 ///////////////////////////////////////////////////////////////////////////////////
    69 // The seg_ioc_base virtual base addresses must be defined in giet_vsegs.ld file.
     19// 2. All accesses to HBA registers are done by the two
     20//    _hba_set_register() and _hba_get_register() low-level functions,
     21//    that are handling virtual / physical extended addressing.
    7022///////////////////////////////////////////////////////////////////////////////////
    7123
     
    8032#include <vmem.h>
    8133
    82 #if !defined( NB_HBA_CHANNELS )
    83 # error: You must define NB_HBA_CHANNELS in the hard_config.h file
    84 #endif
    85 
    86 #if ( NB_HBA_CHANNELS > 8 )
    87 # error: NB_HBA_CHANNELS cannot be larger than 8
    88 #endif
    89 
    90 #if !defined( USE_IOB )
    91 # error: You must define USE_IOB in the hard_config.h file
    92 #endif
    93 
    94 #if !defined(GIET_USE_IOMMU)
    95 # error: You must define GIET_USE_IOMMU in the giet_config.h file
     34#if !defined( NB_IOC_CHANNELS )
     35# error: You must define NB_IOC_CHANNELS in the hard_config.h file
     36#endif
     37
     38#if ( NB_IOC_CHANNELS > 8 )
     39# error: NB_IOC_CHANNELS cannot be larger than 8
    9640#endif
    9741
     
    10347
    10448// command list array (one per channel)
    105 hba_cmd_list_t   hba_cmd_list[NB_HBA_CHANNELS] __attribute__((aligned(0x1000)));   
     49hba_cmd_list_t   hba_cmd_list[NB_IOC_CHANNELS] __attribute__((aligned(0x1000)));   
    10650
    10751// command tables array (32 command tables per channel)
    108 hba_cmd_table_t  hba_cmd_table[NB_HBA_CHANNELS][32] __attribute__((aligned(0x1000)));
     52hba_cmd_table_t  hba_cmd_table[NB_IOC_CHANNELS][32] __attribute__((aligned(0x1000)));
    10953
    11054// command list physical addresses array (one per channel)
    111 paddr_t          hba_cmd_list_paddr[NB_HBA_CHANNELS];
     55paddr_t          hba_cmd_list_paddr[NB_IOC_CHANNELS];
    11256
    11357// command tables physical addresses array (32 command tables per channel)
    114 paddr_t          hba_cmd_table_paddr[NB_HBA_CHANNELS][32];
     58paddr_t          hba_cmd_table_paddr[NB_IOC_CHANNELS][32];
    11559
    11660// command list pointer array (one per channel)
    117 unsigned int     hba_cmd_slot[NB_HBA_CHANNELS];
    118 
    119 //////////////////////////////////////////////////////////////////
    120 // This function returns the status of a given channel.
    121 // return 0 if success, >0 if error
    122 //////////////////////////////////////////////////////////////////
    123 unsigned int _hba_get_status( unsigned int   channel,
    124                               unsigned int*  status )
    125 {
    126     volatile unsigned int* hba_address;
    127     hba_address = (unsigned int*)(&seg_ioc_base) + (HBA_SPAN*channel);
    128 
    129     if( channel >= NB_HBA_CHANNELS )
    130     {
    131         _tty_get_lock( 0 );
    132         _puts("\n[GIET ERROR] in _hba_get_status() : illegal channel\n");
    133         _tty_release_lock( 0 );
    134         return 1;
    135     }
    136     else
    137     {
    138         *status = hba_address[HBA_PXIS];
    139         return 0;
    140     }
    141 }
    142 //////////////////////////////////////////////////////////////////
    143 // This function reset the status resgister for a given channel.
    144 // return 0 if success, >0 if error
    145 //////////////////////////////////////////////////////////////////
    146 unsigned int _hba_reset_status( unsigned int channel )
    147 {
    148     volatile unsigned int* hba_address;
    149     hba_address = (unsigned int*)(&seg_ioc_base) + (HBA_SPAN*channel);
    150 
    151     if( channel >= NB_HBA_CHANNELS )
    152     {   
    153         _tty_get_lock( 0 );
    154         _puts("\n[GIET ERROR] in _hba_reset_status() : illegal channel\n");
    155         _tty_release_lock( 0 );
    156         return 1;
    157     }
    158     else
    159     {
    160         hba_address[HBA_PXIS] = 0;
    161         return 0;
    162     }
    163 }
     61unsigned int     hba_cmd_slot[NB_IOC_CHANNELS];
     62
     63//////////////////////////////////////////////////////////////////////////////
     64// This low level function returns the value of register (channel / index)
     65//////////////////////////////////////////////////////////////////////////////
     66unsigned int _hba_get_register( unsigned int channel,
     67                                unsigned int index )
     68{
     69    unsigned int* vaddr = (unsigned int*)&seg_ioc_base + channel*HBA_SPAN + index;
     70    return _io_extended_read( vaddr );
     71}
     72
     73//////////////////////////////////////////////////////////////////////////////
     74// This low level function set a new value in register (channel / index) 
     75//////////////////////////////////////////////////////////////////////////////
     76void _hba_set_register( unsigned int channel,
     77                        unsigned int index,
     78                        unsigned int value )
     79{
     80    unsigned int* vaddr = (unsigned int*)&seg_ioc_base + channel*HBA_SPAN + index;
     81    _io_extended_write( vaddr, value );
     82}
     83
     84
    16485///////////////////////////////////////////////////////////////////////////////
    16586// This function register a command in both the command list
     
    17192// return 0 if success, > 0 if error
    17293///////////////////////////////////////////////////////////////////////////////
    173 unsigned int _hba_cmd_set( unsigned int  is_read,     // to memory
     94unsigned int _hba_cmd_set( unsigned int  channel,     // channel index
     95                           unsigned int  is_read,     // to memory
    17496                           unsigned int  lba,         // logic block address
    175                            unsigned int  buf_vaddr,   // buffer virtual address
     97                           paddr_t       buffer,      // buffer physical address
    17698                           unsigned int  count )      // number of blocks
    17799{
    178     volatile unsigned int *hba_address;
    179 
    180100    unsigned int       block_size;     // defined by the block device (bytes)
    181     unsigned int       channel_id;     // channel index
    182101    unsigned int       pxci;           // command list status
    183102    unsigned int       cmd_id;         // command index in command list
    184     unsigned int       buf_id;         // for physical buffers covering user buffer
    185     unsigned int       user_pt_vbase;  // user page table virtual base address
    186     unsigned int       vpn;            // for all pages covering the userbuffer
    187     unsigned int       vpn_min;        // first virtual page index for user buffer
    188     unsigned int       vpn_max;        // last  virtual page index for user buffer
    189     unsigned int       offset;         // unaligned bytes in page frame: buf_vaddr & 0xFFF
    190     unsigned int       offset_last;    // unaligned bytes in last frame
     103
    191104    hba_cmd_desc_t*    cmd_desc;       // command descriptor pointer   
    192105    hba_cmd_table_t*   cmd_table;      // command table pointer
     
    195108
    196109    // check buffer alignment
    197     if( buf_vaddr & (block_size-1) )
    198     {
    199         _tty_get_lock( 0 );
    200         _puts("\n[GIET ERROR] in _hba_set_cmd() : user buffer not block aligned\n");
    201         _tty_release_lock( 0 );
     110    if( buffer & (block_size-1) )
     111    {
     112        _printf("\n[GIET ERROR] in _hba_set_cmd() : user buffer not block aligned\n");
    202113        return 1;
    203114    }
    204115
    205     // get channel index
    206     channel_id = _get_context_slot(CTX_HBA_ID);
    207     if ( channel_id == 0xFFFFFFFF )
    208     {
    209         _tty_get_lock( 0 );
    210         _puts("\n[GIET ERROR] in _hba_set_cmd() : no HBA channel allocated\n");
    211         _tty_release_lock( 0 );
     116    // get command list status from PXCI register
     117    pxci = _hba_get_register( channel, HBA_PXCI );
     118
     119    // get command index and return error if command list full
     120    cmd_id = hba_cmd_slot[channel];
     121    if( pxci & (1<<cmd_id ) )
     122    {
     123        _printf("\n[GIET ERROR] in _hba_set_cmd() : command list full for channel %d\n",
     124                channel );
    212125        return 1;
    213126    }
    214127
    215     // get hba device address
    216     hba_address = (unsigned int*)(&seg_ioc_base) + (HBA_SPAN * channel_id);
    217 
    218     // get command list status
    219     pxci = hba_address[HBA_PXCI];
    220 
    221     // get command index and return error if command list full
    222     cmd_id = hba_cmd_slot[channel_id];
    223     if( pxci & (1<<cmd_id ) )
    224     {
    225         _tty_get_lock( 0 );
    226         _puts("\n[GIET ERROR] in _hba_set_cmd() : command list full in channel \n");
    227         _putd( channel_id );
    228         _puts("\n");
    229         _tty_release_lock( 0 );
    230         return 1;
    231     }
    232 
    233128    // compute pointers on command descriptor and command table   
    234     cmd_desc  = (hba_cmd_desc_t*)(&(hba_cmd_list[channel_id].desc[cmd_id]));
    235     cmd_table = (hba_cmd_table_t*)(&(hba_cmd_table[channel_id][cmd_id]));
     129    cmd_desc  = (hba_cmd_desc_t*)(&(hba_cmd_list[channel].desc[cmd_id]));
     130    cmd_table = (hba_cmd_table_t*)(&(hba_cmd_table[channel][cmd_id]));
     131
     132    // set  buffer descriptor in command table
     133    cmd_table->entry[0].dba  = (unsigned int)(buffer);
     134    cmd_table->entry[0].dbau = (unsigned int)(buffer >> 32);
     135    cmd_table->entry[0].dbc  = count * block_size;
     136
     137    // initialize command table header
     138    cmd_table->header.lba0 = (char)lba;
     139    cmd_table->header.lba1 = (char)(lba>>8);
     140    cmd_table->header.lba2 = (char)(lba>>16);
     141    cmd_table->header.lba3 = (char)(lba>>24);
     142    cmd_table->header.lba4 = 0;
     143    cmd_table->header.lba5 = 0;
     144
     145    // initialise command descriptor
     146    cmd_desc->prdtl[0] = 1;
     147    cmd_desc->prdtl[1] = 0;
     148    cmd_desc->ctba     = (unsigned int)(hba_cmd_table_paddr[channel][cmd_id]);
     149    cmd_desc->ctbau    = (unsigned int)(hba_cmd_table_paddr[channel][cmd_id]>>32);
     150    if( is_read ) cmd_desc->flag[0] = 0x00;
     151    else          cmd_desc->flag[0] = 0x40;     
     152   
     153    // update PXCI register
     154    _hba_set_register( channel, HBA_PXCI, (1<<cmd_id) );
     155
     156    // update command pointer
     157    hba_cmd_slot[channel] = (cmd_id + 1)%32;
     158
     159    return  0;
     160}
     161
     162/* This can be used for a future use with buffer in virtual space
    236163
    237164    // get user space page table virtual address
     
    262189        if ( ko )
    263190        {
    264             _tty_get_lock( 0 );
    265             _puts("[GIET ERROR] in _hba_set_cmd() : user buffer unmapped\n");
    266             _tty_release_lock( 0 );
     191            _printf("[GIET ERROR] in _hba_set_cmd() : user buffer unmapped\n");
    267192            return 1;
    268193        }
    269194        if ((flags & PTE_U) == 0)
    270195        {
    271             _tty_get_lock( 0 );
    272             _puts("[GIET ERROR] in _hba_set_cmd() : user buffer not in user space\n");
    273             _tty_release_lock( 0 );
     196            _printf("[GIET ERROR] in _hba_set_cmd() : user buffer not in user space\n");
    274197            return 1;
    275198        }
    276199        if (((flags & PTE_W) == 0 ) && (is_read == 0) )
    277200        {
    278             _tty_get_lock( 0 );
    279             _puts("[GIET ERROR] in _hba_set_cmd() : user buffer not writable\n");
    280             _tty_release_lock( 0 );
     201            _printf("[GIET ERROR] in _hba_set_cmd() : user buffer not writable\n");
    281202            return 1;
    282203        }
     
    285206        if( buf_id > 245 )
    286207        {
    287             _tty_get_lock( 0 );
    288             _puts("[GIET ERROR] in _hba_set_cmd() : max number of buffers is 248\n");
    289             _tty_release_lock( 0 );
     208            _printf("[GIET ERROR] in _hba_set_cmd() : max number of buffers is 248\n");
    290209            return 1;
    291210        }
     
    301220
    302221#if GIET_DEBUG_HBA_DRIVER
    303 _puts("\n- buf_index = ");
     222_printf("\n- buf_index = ");
    304223_putd( buf_id );
    305 _puts(" / paddr = ");
     224_printf(" / paddr = ");
    306225_putl( paddr );
    307 _puts(" / count = ");
     226_printf(" / count = ");
    308227_putd( count );
    309 _puts("\n");
     228_printf("\n");
    310229#endif
    311230            buf_id++;
     
    320239
    321240#if GIET_DEBUG_HBA_DRIVER
    322 _puts("\n- buf_index = ");
     241_printf("\n- buf_index = ");
    323242_putd( buf_id );
    324 _puts(" / paddr = ");
     243_printf(" / paddr = ");
    325244_putl( paddr );
    326 _puts(" / count = ");
     245_printf(" / count = ");
    327246_putd( count );
    328 _puts("\n");
     247_printf("\n");
    329248#endif
    330249            buf_id++;
     
    340259
    341260#if GIET_DEBUG_HBA_DRIVER
    342 _puts("\n- buf_index = ");
     261_printf("\n- buf_index = ");
    343262_putd( buf_id );
    344 _puts(" / paddr = ");
     263_printf(" / paddr = ");
    345264_putl( paddr );
    346 _puts(" / count = ");
     265_printf(" / count = ");
    347266_putd( count );
    348 _puts("\n");
     267_printf("\n");
    349268#endif
    350269            buf_id++;
     
    357276
    358277#if GIET_DEBUG_HBA_DRIVER
    359 _puts("\n- buf_index = ");
     278_printf("\n- buf_index = ");
    360279_putd( buf_id );
    361 _puts(" / paddr = ");
     280_printf(" / paddr = ");
    362281_putl( paddr );
    363 _puts(" / count = ");
     282_printf(" / count = ");
    364283_putd( count );
    365 _puts("\n");
     284_printf("\n");
    366285#endif
    367286            buf_id++;
     
    376295
    377296#if GIET_DEBUG_HBA_DRIVER
    378 _puts("\n- buf_index = ");
     297_printf("\n- buf_index = ");
    379298_putd( buf_id );
    380 _puts(" / paddr = ");
     299_printf(" / paddr = ");
    381300_putl( paddr );
    382 _puts(" / count = ");
     301_printf(" / count = ");
    383302_putd( count );
    384 _puts("\n");
     303_printf("\n");
    385304#endif
    386305            buf_id++;
    387306        }
    388307    }
    389 
    390     // initialize command table header
    391     cmd_table->header.lba0 = (char)lba;
    392     cmd_table->header.lba1 = (char)(lba>>8);
    393     cmd_table->header.lba2 = (char)(lba>>16);
    394     cmd_table->header.lba3 = (char)(lba>>24);
    395 
    396     // initialise command descriptor
    397     cmd_desc->prdtl[0] = (unsigned char)(buf_id);
    398     cmd_desc->prdtl[1] = (unsigned char)(buf_id>>8);
    399     cmd_desc->ctba     = (unsigned int)(hba_cmd_table_paddr[channel_id][cmd_id]);
    400     cmd_desc->ctbau    = (unsigned int)(hba_cmd_table_paddr[channel_id][cmd_id]>>32);
    401     if( is_read ) cmd_desc->flag[0] = 0x00;
    402     else          cmd_desc->flag[0] = 0x40;     
    403    
    404     // update PXCI register
    405     hba_address[HBA_PXCI] = (1<<cmd_id);
    406 
    407     // update command pointer
    408     hba_cmd_slot[channel_id] = (cmd_id + 1)%32;
    409 
    410     return  0;
    411 }
     308*/
     309
     310
    412311///////////////////////////////////////////////////////////////////
    413312// Register a write command in Command List and Command Table
    414 // for a single buffer.
     313// for a single physical buffer.
    415314// Returns 0 if success, > 0 if error.
    416315///////////////////////////////////////////////////////////////////
    417 unsigned int _hba_write( unsigned int  mode,
     316unsigned int _hba_write( unsigned int  channel,
     317                         unsigned int  mode,
    418318                         unsigned int  lba,
    419                          void*         buffer,
     319                         paddr_t       buffer,
    420320                         unsigned int  count )
    421321{
    422     return _hba_cmd_set( 0, lba, (unsigned int)buffer, count );
     322    return _hba_cmd_set( channel,
     323                         0,         // write
     324                         lba,
     325                         buffer,
     326                         count );
    423327}
    424328
    425329///////////////////////////////////////////////////////////////////
    426330// Register a read command in Command List and Command Table
    427 // for a single buffer.
     331// for a single physical buffer.
    428332// Returns 0 if success, > 0 if error.
    429333///////////////////////////////////////////////////////////////////
    430 unsigned int _hba_read( unsigned int  mode,
     334unsigned int _hba_read( unsigned int  channel,
     335                        unsigned int  mode,
    431336                        unsigned int  lba,
    432                         void*         buffer,
     337                        paddr_t       buffer,
    433338                        unsigned int  count )
    434339{
    435     return _hba_cmd_set( 1, lba, (unsigned int)buffer, count );
    436 }
     340    return _hba_cmd_set( channel,
     341                         1,          // read
     342                         lba,
     343                         buffer,
     344                         count );
     345}
     346
    437347//////////////////////////////////////////////////////////////////
    438348// This function initializes for a given channel
     
    453363    unsigned int pt = _get_context_slot(CTX_PTAB_ID);
    454364
    455     // HBA registers
    456     unsigned int*  hba_address;
    457     hba_address = (unsigned int*)&seg_ioc_base + HBA_SPAN * channel;
    458 
    459     hba_address[HBA_PXCLB]  = (unsigned int)(&hba_cmd_list[channel]);
    460     hba_address[HBA_PXCLBU] = 0;
    461     hba_address[HBA_PXIE]   = 0x40000001;
    462     hba_address[HBA_PXIS]   = 0;
    463     hba_address[HBA_PXCI]   = 0;
    464     hba_address[HBA_PXCMD]  = 1;
     365    // HBA registers TODO: ne faut_il pas un V2P pour PXCLB/PXCLBU ? (AG)
     366    _hba_set_register( channel, HBA_PXCLB , (unsigned int)&hba_cmd_list[channel] );
     367    _hba_set_register( channel, HBA_PXCLBU, 0 );
     368    _hba_set_register( channel, HBA_PXIE  , 0x40000001 );
     369    _hba_set_register( channel, HBA_PXIS  , 0 );
     370    _hba_set_register( channel, HBA_PXCI  , 0 );
     371    _hba_set_register( channel, HBA_PXCMD , 1 );
    465372
    466373    // command list pointer       
     
    475382    if ( fail )
    476383    {
    477         _tty_get_lock( 0 );
    478         _puts("[GIET ERROR] in _hba_init() : command list unmapped\n");
    479         _tty_release_lock( 0 );
     384        _printf("[GIET ERROR] in _hba_init() : command list unmapped\n");
    480385        return 1;
    481386    }
     
    492397        if ( fail )
    493398        {
    494             _tty_get_lock( 0 );
    495             _puts("[GIET ERROR] in _hba_init() : command table unmapped\n");
    496             _tty_release_lock( 0 );
     399            _printf("[GIET ERROR] in _hba_init() : command table unmapped\n");
    497400            return 1;
    498401        }
     
    513416}
    514417
     418/////////////////////////////////////////////////////////////////////////////////////
     419// This function returns the content of the HBA_PXIS register for a given channel,
     420// and reset this register to acknoledge IRQ.
     421// return 0 if success, > 0 if error
     422/////////////////////////////////////////////////////////////////////////////////////
     423unsigned int _hba_get_status( unsigned int channel )
     424{
     425
     426    if( channel >= NB_IOC_CHANNELS )
     427    {
     428        _printf("\n[GIET ERROR] in _hba_get_status() : illegal channel\n");
     429        _exit();
     430    }
     431
     432    // get HBA_PXIS value
     433    unsigned int status = _hba_get_register( channel, HBA_PXIS );
     434
     435    // reset HBA_PXIS
     436    _hba_set_register( channel, HBA_PXIS, 0 );
     437
     438    return status;
     439}
    515440
    516441// Local Variables:
Note: See TracChangeset for help on using the changeset viewer.