source: trunk/kernel/devices/dev_txt.c @ 1

Last change on this file since 1 was 1, checked in by alain, 5 years ago

First import

File size: 10.5 KB
Line 
1/*
2 * dev_txt.c - TXT (Text Terminal) generic device API implementation.
3 *
4 * Author  Alain Greiner    (2016)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MK
9 *
10 * ALMOS-MKH.is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH.is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-kernel; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24#include <hal_types.h>
25#include <hal_special.h>
26#include <hal_remote.h>
27#include <soclib_tty.h>
28#include <thread.h>
29#include <rpc.h>
30#include <printk.h>
31#include <dev_txt.h>
32
33/////////////////////////////////////////////////////////////////////////////////////////
34// Extern global variables
35/////////////////////////////////////////////////////////////////////////////////////////
36
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
60    if( impl == IMPL_TXT_TTY )
61    {
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 );
68    }
69    else
70    {
71        printk("\n[PANIC] in %s: undefined TXT device implementation\n", __FUNCTION__ );
72        hal_core_sleep();
73    }
74
75    // create server thread
76    xptr_t     new_thread_xp;
77    thread_t * new_thread_ptr;
78    error_t    error;
79
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 );
109   
110    // start server thread
111    thread_unblock( new_thread_xp , THREAD_BLOCKED_GLOBAL );
112
113} // end dev_txt_init()
114
115
116//////////////////////////////////////////////////////////////////////////////////
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.
125////////////////////////////////////i/////////////////////////////////////////////
126static error_t dev_txt_access( uint32_t   type,
127                               uint32_t   channel,
128                               char     * buffer,
129                               uint32_t   count )
130{
131    thread_t * this = CURRENT_THREAD;
132
133    txt_dmsg("\n[INFO] in %s : thread %x in process %x enters\n", 
134                 __FUNCTION__ , this->trdid , this->process->pid );
135
136    // check channel argument
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    }
152
153    // register command in calling thread descriptor
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    }   
213
214    // return I/O operation status from calling thread descriptor
215    return this->dev.txt.error; 
216
217}  // end dev_txt_access()
218
219/////////////////////////////////////////
220error_t dev_txt_write( uint32_t   channel,
221                       char     * buffer,
222                       uint32_t   count )
223{
224    return dev_txt_access( TXT_WRITE , channel , buffer , count );
225}
226 
227///////////////////////////////////////////////
228error_t dev_txt_sync_write( uint32_t   channel,
229                            char     * buffer,
230                            uint32_t   count )
231{
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 TracBrowser for help on using the repository browser.