source: rtems/c/src/lib/libbsp/sparc/erc32/console/console.c @ 8f35817

4.104.114.84.95
Last change on this file since 8f35817 was 8f35817, checked in by Joel Sherrill <joel.sherrill@…>, on Sep 15, 1997 at 6:52:26 PM

eliminated potential for overfilling buffer on read

  • Property mode set to 100644
File size: 13.8 KB
Line 
1/*
2 *  console.c
3 *
4 *  This file contains the Sparc Instruction Simulator Console driver.
5 *
6 *  COPYRIGHT (c) 1989-1997.
7 *  On-Line Applications Research Corporation (OAR).
8 *  Copyright assigned to U.S. Government, 1994.
9 *
10 *  The license and distribution terms for this file may in
11 *  the file LICENSE in this distribution or at
12 *  http://www.OARcorp.com/rtems/license.html.
13 *
14 *  Ported to ERC32 implementation of the SPARC by On-Line Applications
15 *  Research Corporation (OAR) under contract to the European Space
16 *  Agency (ESA).
17 *
18 *  ERC32 modifications of respective RTEMS file: COPYRIGHT (c) 1995.
19 *  European Space Agency.
20 *
21 *  $Id$
22 */
23
24#include <bsp.h>
25#include <rtems/libio.h>
26#include <stdlib.h>
27
28/*
29 *  Define RDB_BREAK_IN if you need to be able to break in to the
30 *  program with a ctrl-c during remote target debugging. If so,
31 *  UART B will not be accessible from rtems during remote debugging
32 *  if interrupt driven console is used. Does not affect UART A, polled
33 *  mode or when the program runs without remote debugging.
34 */
35
36#define RDB_BREAK_IN
37
38/*
39 *  Should we use a polled or interrupt drived console?
40 * 
41 *  NOTE: Define only one of these by default.
42 *
43 *  WARNING:  As of sis 1.6, it did not appear that the UART interrupts
44 *            worked in a desirable fashion.  Immediately upon writing
45 *            a character into the TX buffer, an interrupt was generated.
46 *            This did not allow enough time for the program to put more
47 *            characters in the buffer.  So every character resulted in
48 *            "priming" the transmitter.   This effectively results in
49 *            in a polled console with a useless interrupt per character
50 *            on output.  It is reasonable to assume that input does not
51 *            share this problem although it was not investigated.
52 */
53
54#ifdef CONSOLE_USE_POLLED
55#define OUTBYTE console_outbyte_polled
56#define INBYTE  console_inbyte_polled
57#else
58#define OUTBYTE console_outbyte_interrupts
59#define INBYTE  console_inbyte_interrupts
60#endif
61
62void console_initialize_interrupts( void );
63
64/*  console_initialize
65 *
66 *  This routine initializes the console IO driver.
67 *
68 *  Input parameters:
69 *    major - console device major number
70 *    minor - console device minor number
71 *    arg   - pointer to optional device driver arguments
72 *
73 *  Output parameters:  NONE
74 *
75 *  Return values:
76 *    rtems_device_driver status code
77 */
78 
79rtems_device_driver console_initialize(
80  rtems_device_major_number  major,
81  rtems_device_minor_number  minor,
82  void                      *arg
83)
84{
85  rtems_status_code status;
86 
87  status = rtems_io_register_name(
88    "/dev/console",
89    major,
90    (rtems_device_minor_number) 0
91  );
92 
93  if (status != RTEMS_SUCCESSFUL)
94    rtems_fatal_error_occurred(status);
95
96#ifdef CONSOLE_USE_INTERRUPTS
97  console_initialize_interrupts();
98#endif
99 
100  return RTEMS_SUCCESSFUL;
101}
102
103/*  console_inbyte_polled
104 *
105 *  This routine reads a character from the UART.
106 *
107 *  Input parameters:
108 *    port - port to read character from
109 *
110 *  Output parameters:  NONE
111 *
112 *  Return values:
113 *    character read from UART
114 */
115
116char console_inbyte_polled( int port )
117{
118  int UStat;
119
120  if ( port == 0 ) {
121    while (((UStat = ERC32_MEC.UART_Status) & ERC32_MEC_UART_STATUS_DRA) == 0 )
122        if (UStat & ERC32_MEC_UART_STATUS_ERRA) {
123            ERC32_MEC.UART_Status = ERC32_MEC_UART_STATUS_CLRA;
124            ERC32_MEC.Control = ERC32_MEC.Control;
125        }
126    return (int) ERC32_MEC.UART_Channel_A;
127  } 
128
129  while (((UStat = ERC32_MEC.UART_Status) & ERC32_MEC_UART_STATUS_DRB) == 0 )
130        if (UStat & ERC32_MEC_UART_STATUS_ERRB) {
131            ERC32_MEC.UART_Status = ERC32_MEC_UART_STATUS_CLRB;
132            ERC32_MEC.Control = ERC32_MEC.Control;
133        }
134  return (int) ERC32_MEC.UART_Channel_B;
135}
136
137
138/*  console_outbyte_polled
139 *
140 *  This routine transmits a character out.
141 *
142 *  Input parameters:
143 *    port - port to transmit character to
144 *    ch  - character to be transmitted
145 *
146 *  Output parameters:  NONE
147 *
148 *  Return values: NONE
149 */
150
151void console_outbyte_polled(
152  int  port,
153  char ch
154)
155{
156  if ( port == 0 ) {
157    while ( (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEA) == 0 );
158    ERC32_MEC.UART_Channel_A = (int) ch;
159    return;
160  }
161
162  while ( (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEB) == 0 );
163  ERC32_MEC.UART_Channel_B = (int) ch;
164}
165
166/*
167 *  Interrupt driven console IO
168 */
169
170#ifdef CONSOLE_USE_INTERRUPTS
171
172/*
173 *  Buffers between task and ISRs
174 */
175
176#include <ringbuf.h>
177 
178Ring_buffer_t  TX_Buffer[ 2 ];
179Ring_buffer_t  RX_Buffer[ 2 ];
180boolean        Is_TX_active[ 2 ];
181 
182/*
183 *  console_isr_a
184 *
185 *  This routine is the console interrupt handler for Channel A.
186 *
187 *  Input parameters:
188 *    vector - vector number
189 *
190 *  Output parameters: NONE
191 *
192 *  Return values:     NONE
193 */
194
195rtems_isr console_isr_a(
196  rtems_vector_number vector
197)
198{ 
199  char ch;
200  int UStat;
201 
202  if ( (UStat = ERC32_MEC.UART_Status) & ERC32_MEC_UART_STATUS_DRA ) {
203    if (UStat & ERC32_MEC_UART_STATUS_ERRA) {
204      ERC32_MEC.UART_Status = ERC32_MEC_UART_STATUS_CLRA;
205      ERC32_MEC.Control = ERC32_MEC.Control;
206    }
207    ch = ERC32_MEC.UART_Channel_A;
208    if ( !Ring_buffer_Is_full( &RX_Buffer[ 0 ] ) )
209      Ring_buffer_Add_character( &RX_Buffer[ 0 ], ch );
210    /* else toss it */
211  }
212 
213  if ( ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEA ) {
214    if ( !Ring_buffer_Is_empty( &TX_Buffer[ 0 ] ) ) {
215      Ring_buffer_Remove_character( &TX_Buffer[ 0 ], ch );
216      ERC32_MEC.UART_Channel_A = (unsigned32) ch;
217    } else
218     Is_TX_active[ 0 ] = FALSE;
219  }
220 
221  ERC32_Clear_interrupt( ERC32_INTERRUPT_UART_A_RX_TX );
222}
223
224/*
225 *  console_isr_b
226 *
227 *  This routine is the console interrupt handler for Channel B.
228 *
229 *  Input parameters:
230 *    vector - vector number
231 *
232 *  Output parameters: NONE
233 *
234 *  Return values:     NONE
235 */
236 
237rtems_isr console_isr_b(
238  rtems_vector_number vector
239)
240{
241  char ch;
242  int UStat;
243
244  if ( (UStat = ERC32_MEC.UART_Status) & ERC32_MEC_UART_STATUS_DRB ) {
245    if (UStat & ERC32_MEC_UART_STATUS_ERRB) {
246      ERC32_MEC.UART_Status = ERC32_MEC_UART_STATUS_CLRB;
247      ERC32_MEC.Control = ERC32_MEC.Control;
248    }
249    ch = ERC32_MEC.UART_Channel_B;
250    if ( !Ring_buffer_Is_full( &RX_Buffer[ 1 ] ) )
251      Ring_buffer_Add_character( &RX_Buffer[ 1 ], ch );
252    /* else toss it */
253  }
254
255  if ( ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEB ) {
256    if ( !Ring_buffer_Is_empty( &TX_Buffer[ 1 ] ) ) {
257      Ring_buffer_Remove_character( &TX_Buffer[ 1 ], ch );
258      ERC32_MEC.UART_Channel_B = (unsigned32) ch;
259    } else
260     Is_TX_active[ 1 ] = FALSE;
261  }
262
263  ERC32_Clear_interrupt( ERC32_INTERRUPT_UART_B_RX_TX );
264}
265
266/*
267 *  console_exit
268 *
269 *  This routine allows the console to exit by masking its associated interrupt
270 *  vectors.
271 *
272 *  Input parameters:  NONE
273 *
274 *  Output parameters: NONE
275 *
276 *  Return values:     NONE
277 */
278
279void console_exit()
280{
281  rtems_unsigned32 port;
282  rtems_unsigned32 ch;
283
284  /*
285   *  Although the interrupts for the UART are unmasked, the PIL is set to
286   *  disable all external interrupts.  So we might as well do this first.
287   */
288
289  ERC32_Mask_interrupt( ERC32_INTERRUPT_UART_A_RX_TX );
290  ERC32_Mask_interrupt( ERC32_INTERRUPT_UART_B_RX_TX );
291
292  for ( port=0 ; port <= 1 ; port++ ) {
293    while ( !Ring_buffer_Is_empty( &TX_Buffer[ port ] ) ) {
294      Ring_buffer_Remove_character( &TX_Buffer[ port ], ch );
295      console_outbyte_polled( port, ch );
296    }
297  }
298
299  /*
300   *  Now wait for all the data to actually get out ... the send register
301   *  should be empty.
302   */
303 
304  while ( (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEA) != 
305          ERC32_MEC_UART_STATUS_THEA );
306
307  while ( (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEB) != 
308          ERC32_MEC_UART_STATUS_THEB );
309
310}
311
312#define CONSOLE_UART_A_TRAP  ERC32_TRAP_TYPE( ERC32_INTERRUPT_UART_A_RX_TX )
313#define CONSOLE_UART_B_TRAP  ERC32_TRAP_TYPE( ERC32_INTERRUPT_UART_B_RX_TX )
314
315/*
316 *  console_initialize_interrupts
317 *
318 *  This routine initializes the console's receive and transmit
319 *  ring buffers and loads the appropriate vectors to handle the interrupts.
320 *
321 *  Input parameters:  NONE
322 *
323 *  Output parameters: NONE
324 *
325 *  Return values:     NONE
326 */
327
328#ifdef RDB_BREAK_IN
329  extern unsigned32 trap_table[];
330#endif
331
332void console_initialize_interrupts()
333{
334  Ring_buffer_Initialize( &RX_Buffer[ 0 ] );
335  Ring_buffer_Initialize( &RX_Buffer[ 1 ] );
336
337  Ring_buffer_Initialize( &TX_Buffer[ 0 ] );
338  Ring_buffer_Initialize( &TX_Buffer[ 1 ] );
339
340  Is_TX_active[ 0 ] = FALSE;
341  Is_TX_active[ 1 ] = FALSE;
342
343  atexit( console_exit );
344
345  set_vector( console_isr_a, CONSOLE_UART_A_TRAP, 1 );
346#ifdef RDB_BREAK_IN
347  if (trap_table[0x150/4] == 0x91d02000)
348#endif
349  set_vector( console_isr_b, CONSOLE_UART_B_TRAP, 1 );
350}
351
352/*
353 *  console_inbyte_interrupts
354 *
355 *  This routine reads a character from the UART.
356 *
357 *  Input parameters: NONE
358 *
359 *  Output parameters:  NONE
360 *
361 *  Return values:
362 *    character read from UART
363 */
364 
365char console_inbyte_interrupts( int port )
366{
367  char ch;
368
369  while ( Ring_buffer_Is_empty( &RX_Buffer[ port ] ) );
370 
371  Ring_buffer_Remove_character( &RX_Buffer[ port ], ch );
372  return ch;
373}
374 
375/*
376 *  console_outbyte_interrupts
377 *
378 *  This routine transmits a character out.
379 *
380 *  Input parameters:
381 *    port - port to transmit character to
382 *    ch  - character to be transmitted
383 *
384 *  Output parameters:  NONE
385 *
386 *  Return values:      NONE
387 */
388 
389void console_outbyte_interrupts(
390  int  port,
391  char ch
392)
393{
394  /*
395   *  If this is the first character then we need to prime the pump
396   */
397
398  if ( Is_TX_active[ port ] == FALSE ) {
399    Is_TX_active[ port ] = TRUE;
400    console_outbyte_polled( port, ch );
401    return;
402  }
403
404  while ( Ring_buffer_Is_full( &TX_Buffer[ port ] ) );
405 
406  Ring_buffer_Add_character( &TX_Buffer[ port ], ch );
407}
408
409#endif /* CONSOLE_USE_INTERRUPTS */
410
411/*
412 *  DEBUG_puts
413 *
414 *  This should be safe in the event of an error.  It attempts to insure
415 *  that no TX empty interrupts occur while it is doing polled IO.  Then
416 *  it restores the state of that external interrupt.
417 *
418 *  Input parameters:
419 *    string  - pointer to debug output string
420 *
421 *  Output parameters:  NONE
422 *
423 *  Return values:      NONE
424 */
425
426void DEBUG_puts(
427  char *string
428)
429{
430  char *s;
431  unsigned32 old_level;
432
433  ERC32_Disable_interrupt( ERC32_INTERRUPT_UART_A_RX_TX, old_level );
434    for ( s = string ; *s ; s++ ) 
435      console_outbyte_polled( 0, *s );
436
437    console_outbyte_polled( 0, '\r' );
438    console_outbyte_polled( 0, '\n' );
439  ERC32_Restore_interrupt( ERC32_INTERRUPT_UART_A_RX_TX, old_level );
440}
441
442
443/*
444 *  console_open
445 *
446 *  This routine is the console device driver open entry point.
447 *
448 *  Input parameters:
449 *    major - console device major number
450 *    minor - console device minor number
451 *    arg   - pointer to optional device driver arguments
452 *
453 *  Output parameters:  NONE
454 *
455 *  Return values:
456 *    rtems_device_driver status code
457 */
458 
459rtems_device_driver console_open(
460  rtems_device_major_number major,
461  rtems_device_minor_number minor,
462  void                    * arg
463)
464{
465  return RTEMS_SUCCESSFUL;
466}
467 
468/*
469 *  console_close
470 *
471 *  This routine is the console device driver close entry point.
472 *
473 *  Input parameters:
474 *    major - console device major number
475 *    minor - console device minor number
476 *    arg   - pointer to optional device driver arguments
477 *
478 *  Output parameters:  NONE
479 *
480 *  Return values:
481 *    rtems_device_driver status code
482 */
483 
484rtems_device_driver console_close(
485  rtems_device_major_number major,
486  rtems_device_minor_number minor,
487  void                    * arg
488)
489{
490  return RTEMS_SUCCESSFUL;
491}
492 
493/*
494 *  console_read
495 *
496 *  This routine is the console device driver read entry point.
497 *
498 *  Input parameters:
499 *    major - console device major number
500 *    minor - console device minor number
501 *    arg   - pointer to optional device driver arguments
502 *
503 *  Output parameters:  NONE
504 *
505 *  Return values:
506 *    rtems_device_driver status code
507 *
508 *  NOTE:  Read bytes from the serial port. We only have stdin.
509 */
510 
511rtems_device_driver console_read(
512  rtems_device_major_number major,
513  rtems_device_minor_number minor,
514  void                    * arg
515)
516{
517  rtems_libio_rw_args_t *rw_args;
518  char *buffer;
519  int maximum;
520  int count = 0;
521 
522  rw_args = (rtems_libio_rw_args_t *) arg;
523 
524  buffer = rw_args->buffer;
525  maximum = rw_args->count;
526 
527  for (count = 0; count < maximum; count++) {
528    buffer[ count ] = INBYTE( minor );
529    if (buffer[ count ] == '\n' || buffer[ count ] == '\r') {
530      buffer[ count++ ]  = '\n';
531      break;
532    }
533  }
534 
535  rw_args->bytes_moved = count;
536  return (count >= 0) ? RTEMS_SUCCESSFUL : RTEMS_UNSATISFIED;
537}
538 
539/*
540 *  console_write
541 *
542 *  This routine is the console device driver write entry point.
543 *
544 *  Input parameters:
545 *    major - console device major number
546 *    minor - console device minor number
547 *    arg   - pointer to optional device driver arguments
548 *
549 *  Output parameters:  NONE
550 *
551 *  Return values:
552 *    rtems_device_driver status code
553 *
554 *  NOTE:  Write bytes to the serial port. Stdout and stderr are the same.
555 */
556 
557rtems_device_driver console_write(
558  rtems_device_major_number major,
559  rtems_device_minor_number minor,
560  void                    * arg
561)
562{
563  int count;
564  int maximum;
565  rtems_libio_rw_args_t *rw_args;
566  char *buffer;
567 
568  rw_args = (rtems_libio_rw_args_t *) arg;
569 
570  buffer = rw_args->buffer;
571  maximum = rw_args->count;
572 
573  for (count = 0; count < maximum; count++) {
574    OUTBYTE( minor, buffer[ count ] );
575    if ( buffer[ count ] == '\n') {
576      OUTBYTE( minor, '\r');
577    }
578  }
579 
580  rw_args->bytes_moved = maximum;
581  return RTEMS_SUCCESSFUL;
582}
583 
584/*
585 *  console_control
586 *
587 *  This routine is the console device driver control entry point.
588 *
589 *  Input parameters:
590 *    major - console device major number
591 *    minor - console device minor number
592 *    arg   - pointer to optional device driver arguments
593 *
594 *  Output parameters:  NONE
595 *
596 *  Return values:
597 *    rtems_device_driver status code
598 */
599 
600rtems_device_driver console_control(
601  rtems_device_major_number major,
602  rtems_device_minor_number minor,
603  void                    * arg
604)
605{
606  return RTEMS_SUCCESSFUL;
607}
608
Note: See TracBrowser for help on using the repository browser.