Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/kernel/devices/dev_txt.c

    r3 r1  
    3535/////////////////////////////////////////////////////////////////////////////////////////
    3636
    37 extern chdev_directory_t  chdev_dir;         // allocated in kernel_init.c
    38 
    39 extern chdev_pic_input_t  chdev_pic_input;   // allocated in kernel_init.c
    40 
    41 ////////////////////////////////////
    42 void dev_txt_init( chdev_t * chdev )
    43 {
    44     // the local ICU chdev must be initialized before the TXT chdev, because
    45     // the TXT chdev initialisation requires allocation of a WTI from local ICU
    46     xptr_t  icu_xp  = chdev_dir.icu[local_cxy];
    47     assert( (icu_xp != XPTR_NULL) , __FUNCTION__ , "ICU not initialised before TXT" );
    48 
    49     // get implementation and channel index
    50     uint32_t  impl    = chdev->impl;
    51     uint32_t  channel = chdev->channel;
    52 
    53     // set fields "cmd", "isr", and call driver init function
     37extern devices_directory_t  devices_dir;         // allocated in kernel_init.c
     38
     39extern devices_input_irq_t  devices_input_irq;   // allocated in kernel_init.c
     40
     41//////////////////////////////////
     42void dev_txt_init( xptr_t  dev_xp )
     43{
     44    // get device descriptor cluster and local pointer
     45    cxy_t      dev_cxy = GET_CXY( dev_xp );
     46    device_t * dev_ptr = (device_t *)GET_PTR( dev_xp );
     47
     48    // get implementation index from device descriptor
     49    uint32_t  impl = hal_remote_lw( XPTR( dev_cxy , &dev_ptr->impl ) );
     50
     51    // get channel index from device descriptor
     52    // uint32_t  channel = hal_remote_lw( XPTR( dev_cxy , &dev_ptr->channel ) );
     53
     54    // set fields "cmd", "isr", and "name" in device descriptor
     55    // and call implementation specific init function
     56
     57    // TODO replace fixed "TXT_TTY" name by a channel indexed "TXT_TTY%d" name
     58    // as soon as the sprintk() function is available
     59
    5460    if( impl == IMPL_TXT_TTY )
    5561    {
    56         chdev->cmd = &soclib_tty_cmd;
    57         chdev->isr = &soclib_tty_isr;
    58         soclib_tty_init( chdev );
     62        hal_remote_spt( XPTR( dev_cxy , &dev_ptr->cmd ) , &soclib_tty_command );
     63        hal_remote_spt( XPTR( dev_cxy , &dev_ptr->isr ) , &soclib_tty_isr );
     64        // sprintk( name , "TXT_TTY%d" , channel )
     65        hal_remote_memcpy( XPTR( dev_cxy , &dev_ptr->name ),
     66                           XPTR( local_cxy , "TXT_TTY" ) , 16 );
     67        soclib_tty_init( dev_xp );
    5968    }
    6069    else
    6170    {
    62         assert( false , __FUNCTION__ , "undefined TXT device implementation" );
    63     }
    64 
    65     // get a WTI mailbox from local ICU
    66     uint32_t wti_id = dev_icu_wti_alloc();
    67 
    68     assert( (wti_id != -1) , __FUNCTION__ , "cannot allocate WTI mailbox" );
    69 
    70     // select a core
    71     lid_t lid = cluster_select_local_core();
    72 
    73     // enable WTI IRQ and update WTI interrupt vector
    74     dev_icu_enable_irq( lid , WTI_TYPE , wti_id , chdev );
    75 
    76     // link IOC IRQ to WTI mailbox in PIC component
    77     uint32_t irq_id = chdev_pic_input.txt[channel];
    78     dev_pic_bind_irq( irq_id , local_cxy , wti_id );
     71        printk("\n[PANIC] in %s: undefined TXT device implementation\n", __FUNCTION__ );
     72        hal_core_sleep();
     73    }
    7974
    8075    // create server thread
    81     thread_t * new_thread;
     76    xptr_t     new_thread_xp;
     77    thread_t * new_thread_ptr;
    8278    error_t    error;
    8379
    84     error = thread_kernel_create( &new_thread,
    85                                   THREAD_DEV,
    86                                   &chdev_sequencial_server,
    87                                   chdev,
    88                                   lid );
    89     assert( (error == 0) , __FUNCTION__ , "cannot create server thread" );
    90 
    91     // set "server" field in chdev descriptor
    92     chdev->server = new_thread;
     80    if( dev_cxy == local_cxy )         // device cluster is local
     81    {
     82        error = thread_kernel_create( &new_thread_ptr,
     83                                      THREAD_DEV,
     84                                      &dev_txt_server,
     85                                      dev_ptr,
     86                                      cluster_select_local_core() );
     87 
     88        new_thread_xp = XPTR( local_cxy , new_thread_ptr );
     89    }
     90    else                                        // device cluster is remote
     91    {
     92        rpc_thread_kernel_create_client( dev_cxy,
     93                                         THREAD_DEV,
     94                                         &dev_txt_server,
     95                                         dev_ptr,
     96                                         &new_thread_xp,
     97                                         &error );
     98
     99        new_thread_ptr = (thread_t *)GET_PTR( new_thread_xp );
     100    }
     101    if( error )
     102    {
     103        printk("\n[PANIC] in %s : cannot create server thread\n", __FUNCTION__ );
     104        hal_core_sleep();
     105    }
     106
     107    // initialises server field in device descriptor
     108    hal_remote_spt( XPTR( dev_cxy , &dev_ptr->server ) , new_thread_ptr );
    93109   
    94110    // start server thread
    95     thread_unblock( XPTR( local_cxy , new_thread ) , THREAD_BLOCKED_GLOBAL );
     111    thread_unblock( new_thread_xp , THREAD_BLOCKED_GLOBAL );
    96112
    97113} // end dev_txt_init()
     
    99115
    100116//////////////////////////////////////////////////////////////////////////////////
    101 // This static function is called by dev_txt_read(), dev_txt_write() functions.
     117// This static function is called by dev_txt_read(), dev_txt_write(), and
     118// dev_txt_sync_write() functions.
     119// For the TXT_READ and TXT_WRITE operation types:
     120//  - it build the command, and registers it in the calling thread descriptor.
     121//  - then, it registers the calling thead in device waiting queue.
     122//  - finally, it blocks on the THREAD_BLOCKED_DEV condition and deschedule.
     123// For the TXT_SYNC_WRITE operation type:
     124//  - it directly call the relevant driver, using a busy waiting policy.
    102125////////////////////////////////////i/////////////////////////////////////////////
    103126static error_t dev_txt_access( uint32_t   type,
     
    112135
    113136    // check channel argument
    114     assert( (channel < CONFIG_MAX_TXT_CHANNELS) , __FUNCTION__ , "illegal channel index" );
    115 
    116     // get extended pointer on remote TXT chdev descriptor
    117     xptr_t  dev_xp = chdev_dir.txt[channel];
    118 
    119     assert( (dev_xp != XPTR_NULL) , __FUNCTION__ , "undefined TXT chdev descriptor" );
     137    if( channel >= CONFIG_MAX_TXT_CHANNELS )
     138    {
     139        printk("\n[PANIC] in %s : illegal channel index = %d\n", __FUNCTION__ , channel );
     140        hal_core_sleep();
     141    }
     142
     143    // get extended pointer on remote TXT device descriptor
     144    xptr_t  dev_xp = devices_dir.txt[channel];
     145
     146    if ( dev_xp == XPTR_NULL )
     147    {
     148        printk("\n[PANIC] in %s : undefined TXT device descriptor for channel %d\n",
     149               __FUNCTION__ , channel );
     150        hal_core_sleep();
     151    }
    120152
    121153    // register command in calling thread descriptor
    122     this->command.txt.dev_xp  = dev_xp;
    123     this->command.txt.type    = type;
    124     this->command.txt.buf_xp  = XPTR( local_cxy , buffer );
    125     this->command.txt.count   = count;
    126 
    127     // register client thread in waiting queue, activate server thread
    128     // block client thread on THREAD_BLOCKED_IO and deschedule.
    129     // it is re-activated by the ISR signaling IO operation completion.
    130     chdev_register_command( dev_xp , this );
    131 
    132     txt_dmsg("\n[INFO] in %s : thread %x in process %x completes / error = %d\n",
    133              __FUNCTION__ , this->trdid , this->process->pid , this->command.txt.error );
     154    this->dev.txt.dev_xp  = dev_xp;
     155    this->dev.txt.type    = type;
     156    this->dev.txt.buf_xp  = XPTR( local_cxy , buffer );
     157    this->dev.txt.count   = count;
     158
     159
     160    if( (type == TXT_READ) || (type == TXT_WRITE) )  // descheduling policy
     161    {
     162        // get a free WTI mailbox 
     163        uint32_t wti_id;
     164        while( 1 )
     165        {
     166            wti_id = dev_icu_wti_alloc();
     167            if( wti_id == -1 )  sched_yield();
     168            else                break;
     169        }
     170
     171        // enable WTI IRQ in local ICU and update WTI interrupt vector
     172        dev_icu_enable_irq( local_cxy , CURRENT_CORE->lid , WTI_TYPE , wti_id , dev_xp );
     173
     174        // link TXT IRQ to WTI mailbox in PIC component
     175        uint32_t irq_id = devices_input_irq.txt[channel];
     176        dev_pic_bind_irq( irq_id , local_cxy , wti_id );
     177
     178        // register client thread in waiting queue, activate server thread
     179        // block client thread on THREAD_BLOCKED_IO and deschedule.
     180        // it is re-activated by the ISR signaling IO operation completion.
     181        device_register_command( dev_xp , this );
     182
     183        // access PIC to unlink the IOC IRQ
     184        dev_pic_unbind_irq( irq_id );
     185
     186        // disable WTI IRQ in ICU and update interrupt vector
     187        dev_icu_disable_irq( local_cxy , CURRENT_CORE->lid , WTI_TYPE , wti_id );
     188
     189        // release  WTI mailbox
     190        dev_icu_wti_release( wti_id );
     191
     192        txt_dmsg("\n[INFO] in %s : thread %x in process %x completes / error = %d\n",
     193                     __FUNCTION__ , this->trdid , this->process->pid , this->dev.txt.error );
     194    }
     195    else if( type == TXT_SYNC_WRITE )            // busy waiting policy
     196    {
     197        // get driver command function pointer from remote TXT device descriptor
     198        cxy_t       dev_cxy = GET_CXY( dev_xp );
     199        device_t  * dev_ptr = (device_t *)GET_PTR( dev_xp );
     200        dev_cmd_t * cmd = (dev_cmd_t *)hal_remote_lpt( XPTR( dev_cxy , &dev_ptr->cmd ) );
     201
     202        // take the TXT device lock, because the calling thread does NOT
     203        // register in device waiting queue for this synchronous command,
     204        // and has exclusive access to the terminal...
     205        remote_spinlock_lock( XPTR( dev_cxy , &dev_ptr->wait_lock ) );
     206 
     207        // call directly driver command
     208        cmd( XPTR( local_cxy , this ) );
     209
     210        // release the TXT device lock
     211        remote_spinlock_unlock( XPTR( dev_cxy , &dev_ptr->wait_lock ) );
     212    }   
    134213
    135214    // return I/O operation status from calling thread descriptor
    136     return this->command.txt.error; 
     215    return this->dev.txt.error; 
    137216
    138217}  // end dev_txt_access()
     
    146225}
    147226 
    148 /////////////////////////////////////////
    149 error_t dev_txt_read( uint32_t   channel,
    150                       char     * buffer )
    151 {
    152     return dev_txt_access( TXT_READ , channel , buffer , 1 );
    153 }
    154 
    155227///////////////////////////////////////////////
    156228error_t dev_txt_sync_write( uint32_t   channel,
     
    158230                            uint32_t   count )
    159231{
    160     // get pointer on calling thread
    161     thread_t * this = CURRENT_THREAD;
    162 
    163     // get extended pointer on TXT[0] chdev
    164     xptr_t  dev_xp = chdev_dir.txt[channel];
    165 
    166     // register command in calling thread
    167     this->command.txt.dev_xp  = dev_xp;
    168     this->command.txt.type    = TXT_SYNC_WRITE;
    169     this->command.txt.buf_xp  = XPTR( local_cxy , buffer );
    170     this->command.txt.count   = count;
    171 
    172     // get driver command function
    173     cxy_t       dev_cxy = GET_CXY( dev_xp );
    174     chdev_t   * dev_ptr = (chdev_t *)GET_PTR( dev_xp );
    175     dev_cmd_t * cmd = (dev_cmd_t *)hal_remote_lpt( XPTR( dev_cxy , &dev_ptr->cmd ) );
    176 
    177     // call directly driver command after taking chdev lock
    178     remote_spinlock_lock( XPTR( dev_cxy , &dev_ptr->wait_lock ) );
    179     cmd( XPTR( local_cxy , this ) );
    180     remote_spinlock_unlock( XPTR( dev_cxy , &dev_ptr->wait_lock ) );
    181 
    182     // return I/O operation status from calling thread descriptor
    183     return this->command.txt.error;
    184  
    185 }  // end dev_txt_sync_write()
    186 
     232    return dev_txt_access( TXT_SYNC_WRITE , channel , buffer , count );
     233}
     234 
     235/////////////////////////////////////////
     236error_t dev_txt_read( uint32_t   channel,
     237                      char     * buffer )
     238{
     239    return dev_txt_access( TXT_READ , channel , buffer , 1 );
     240}
     241
     242/////////////////////////////////////
     243void dev_txt_server( device_t * dev )
     244{
     245    xptr_t          client_xp;    // extended pointer on waiting thread
     246    cxy_t           client_cxy;   // cluster of client thread
     247    thread_t      * client_ptr;   // local pointer on client thread
     248    thread_t      * server;       // local pointer on server thread
     249    xptr_t          root_xp;      // extended pointer on device waiting queue root
     250
     251    server = CURRENT_THREAD;
     252
     253    root_xp = XPTR( local_cxy , &dev->wait_root );
     254
     255        // infinite loop handling commands of threads
     256    // registered in the TXT waiting queue
     257    while( 1 )
     258    {
     259        // get lock protecting queue
     260        remote_spinlock_lock( XPTR( local_cxy , &dev->wait_lock ) );
     261
     262        // block and deschedule server thread if waiting queue empty
     263        if( xlist_is_empty( root_xp ) )
     264        {
     265            thread_block( server , THREAD_BLOCKED_DEV_QUEUE );
     266            remote_spinlock_unlock( XPTR( local_cxy , &dev->wait_lock ) );
     267            sched_yield();
     268        }
     269        else
     270        {
     271            remote_spinlock_unlock( XPTR( local_cxy , &dev->wait_lock ) );
     272        }
     273
     274        // get extended pointer on first client thread
     275        client_xp = XLIST_FIRST_ELEMENT( root_xp , thread_t , wait_list );
     276
     277        // call driver command function to start I/O operation
     278        dev->cmd( client_xp );
     279       
     280        // get client thread cluster and local pointer
     281        client_cxy = GET_CXY( client_xp );
     282        client_ptr = (thread_t *)GET_PTR( client_xp );
     283
     284        // remove the client thread from waiting queue
     285        remote_spinlock_lock( XPTR( local_cxy , &dev->wait_lock ) );
     286        xlist_unlink( XPTR( client_cxy , &client_ptr->wait_list ) );
     287        remote_spinlock_unlock( XPTR( local_cxy , &dev->wait_lock ) );
     288
     289    }  // end while
     290
     291}  // end dev_txt_server()
     292
Note: See TracChangeset for help on using the changeset viewer.