source: rtems/c/src/lib/libbsp/sparc/erc32/console/console.c @ 5993d02

4.104.114.84.95
Last change on this file since 5993d02 was 5993d02, checked in by Joel Sherrill <joel.sherrill@…>, on Oct 23, 1997 at 3:12:08 PM

Added console_reserve_resources.

  • Property mode set to 100644
File size: 10.8 KB
Line 
1/*
2 *  This file contains the TTY driver for the serial ports on the erc32.
3 *
4 *  This driver uses the termios pseudo 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 be
11 *  found in the file LICENSE in this distribution or at
12 *  http://www.OARcorp.com/rtems/license.html.
13 *
14 *  $Id$
15 */
16
17#include <bsp.h>
18#include <rtems/libio.h>
19#include <stdlib.h>
20#include <assert.h>
21
22/*
23 *  Should we use a polled or interrupt drived console?
24 * 
25 *  NOTE: This is defined in the custom/erc32.cfg file.
26 *
27 *  WARNING:  In sis 1.6, it did not appear that the UART interrupts
28 *            worked in a desirable fashion.  Immediately upon writing
29 *            a character into the TX buffer, an interrupt was generated.
30 *            This did not allow enough time for the program to put more
31 *            characters in the buffer.  So every character resulted in
32 *            "priming" the transmitter.   This effectively results in
33 *            in a polled console with a useless interrupt per character
34 *            on output.  It is reasonable to assume that input does not
35 *            share this problem although it was not investigated.
36 *
37 */
38
39/*
40 *  console_outbyte_polled
41 *
42 *  This routine transmits a character using polling.
43 */
44
45void console_outbyte_polled(
46  int  port,
47  char ch
48)
49{
50  if ( port == 0 ) {
51    while ( (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEA) == 0 );
52    ERC32_MEC.UART_Channel_A = (int) ch;
53    return;
54  }
55
56  while ( (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEB) == 0 );
57  ERC32_MEC.UART_Channel_B = (int) ch;
58}
59
60/*
61 *  console_inbyte_nonblocking
62 *
63 *  This routine polls for a character.
64 */
65
66int console_inbyte_nonblocking(
67  int port,
68  char *c
69)
70{
71  int UStat;
72
73  UStat = ERC32_MEC.UART_Status;
74
75  switch (port) {
76
77    case 0:
78      if (UStat & ERC32_MEC_UART_STATUS_ERRA) {
79        ERC32_MEC.UART_Status = ERC32_MEC_UART_STATUS_CLRA;
80        ERC32_MEC.Control = ERC32_MEC.Control;
81      }
82
83      if ((UStat & ERC32_MEC_UART_STATUS_DRA) == 0)
84         return 0;
85      *c = (char) ERC32_MEC.UART_Channel_A;
86      return 1;
87
88    case 1:
89      if (UStat & ERC32_MEC_UART_STATUS_ERRB) {
90        ERC32_MEC.UART_Status = ERC32_MEC_UART_STATUS_CLRB;
91        ERC32_MEC.Control = ERC32_MEC.Control;
92      }
93
94      if ((UStat & ERC32_MEC_UART_STATUS_DRB) == 0)
95        return 0;
96      *c = (char) ERC32_MEC.UART_Channel_B;
97      return 1;
98
99    default:
100      assert( 0 );
101  }
102
103  return 0;
104}
105
106/*
107 *  Interrupt driven console IO
108 */
109
110#ifdef CONSOLE_USE_INTERRUPTS
111
112/*
113 *  Buffers between task and ISRs
114 */
115
116#include <ringbuf.h>
117 
118Ring_buffer_t  TX_Buffer[ 2 ];
119boolean        Is_TX_active[ 2 ];
120 
121void *console_termios_data[ 2 ];
122
123/*
124 *  console_isr_a
125 *
126 *  This routine is the console interrupt handler for Channel A.
127 *
128 *  Input parameters:
129 *    vector - vector number
130 *
131 *  Output parameters: NONE
132 *
133 *  Return values:     NONE
134 */
135
136rtems_isr console_isr_a(
137  rtems_vector_number vector
138)
139{ 
140  char ch;
141  int UStat;
142 
143  if ( (UStat = ERC32_MEC.UART_Status) & ERC32_MEC_UART_STATUS_DRA ) {
144    if (UStat & ERC32_MEC_UART_STATUS_ERRA) {
145      ERC32_MEC.UART_Status = ERC32_MEC_UART_STATUS_CLRA;
146      ERC32_MEC.Control = ERC32_MEC.Control;
147    }
148    ch = ERC32_MEC.UART_Channel_A;
149
150    rtems_termios_enqueue_raw_characters( console_termios_data[ 0 ], &ch, 1 );
151  }
152 
153  if ( ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEA ) {
154    if ( !Ring_buffer_Is_empty( &TX_Buffer[ 0 ] ) ) {
155      Ring_buffer_Remove_character( &TX_Buffer[ 0 ], ch );
156      ERC32_MEC.UART_Channel_A = (unsigned32) ch;
157    } else
158     Is_TX_active[ 0 ] = FALSE;
159  }
160 
161  ERC32_Clear_interrupt( ERC32_INTERRUPT_UART_A_RX_TX );
162}
163
164/*
165 *  console_isr_b
166 *
167 *  This routine is the console interrupt handler for Channel B.
168 *
169 *  Input parameters:
170 *    vector - vector number
171 *
172 *  Output parameters: NONE
173 *
174 *  Return values:     NONE
175 */
176 
177rtems_isr console_isr_b(
178  rtems_vector_number vector
179)
180{
181  char ch;
182  int UStat;
183
184  if ( (UStat = ERC32_MEC.UART_Status) & ERC32_MEC_UART_STATUS_DRB ) {
185    if (UStat & ERC32_MEC_UART_STATUS_ERRB) {
186      ERC32_MEC.UART_Status = ERC32_MEC_UART_STATUS_CLRB;
187      ERC32_MEC.Control = ERC32_MEC.Control;
188    }
189    ch = ERC32_MEC.UART_Channel_B;
190    rtems_termios_enqueue_raw_characters( console_termios_data[ 1 ], &ch, 1 );
191
192  }
193
194  if ( ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEB ) {
195    if ( !Ring_buffer_Is_empty( &TX_Buffer[ 1 ] ) ) {
196      Ring_buffer_Remove_character( &TX_Buffer[ 1 ], ch );
197      ERC32_MEC.UART_Channel_B = (unsigned32) ch;
198    } else
199     Is_TX_active[ 1 ] = FALSE;
200  }
201
202  ERC32_Clear_interrupt( ERC32_INTERRUPT_UART_B_RX_TX );
203}
204
205/*
206 *  console_exit
207 *
208 *  This routine allows the console to exit by masking its associated interrupt
209 *  vectors.
210 *
211 *  Input parameters:  NONE
212 *
213 *  Output parameters: NONE
214 *
215 *  Return values:     NONE
216 */
217
218void console_exit()
219{
220  rtems_unsigned32 port;
221  rtems_unsigned32 ch;
222
223  /*
224   *  Although the interrupts for the UART are unmasked, the PIL is set to
225   *  disable all external interrupts.  So we might as well do this first.
226   */
227
228  ERC32_Mask_interrupt( ERC32_INTERRUPT_UART_A_RX_TX );
229  ERC32_Mask_interrupt( ERC32_INTERRUPT_UART_B_RX_TX );
230
231  for ( port=0 ; port <= 1 ; port++ ) {
232    while ( !Ring_buffer_Is_empty( &TX_Buffer[ port ] ) ) {
233      Ring_buffer_Remove_character( &TX_Buffer[ port ], ch );
234      console_outbyte_polled( port, ch );
235    }
236  }
237
238  /*
239   *  Now wait for all the data to actually get out ... the send register
240   *  should be empty.
241   */
242 
243  while ( (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEA) != 
244          ERC32_MEC_UART_STATUS_THEA );
245
246  while ( (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEB) != 
247          ERC32_MEC_UART_STATUS_THEB );
248
249}
250
251#define CONSOLE_UART_A_TRAP  ERC32_TRAP_TYPE( ERC32_INTERRUPT_UART_A_RX_TX )
252#define CONSOLE_UART_B_TRAP  ERC32_TRAP_TYPE( ERC32_INTERRUPT_UART_B_RX_TX )
253
254/*
255 *  console_initialize_interrupts
256 *
257 *  This routine initializes the console's receive and transmit
258 *  ring buffers and loads the appropriate vectors to handle the interrupts.
259 *
260 *  Input parameters:  NONE
261 *
262 *  Output parameters: NONE
263 *
264 *  Return values:     NONE
265 */
266
267#ifdef RDB_BREAK_IN
268  extern unsigned32 trap_table[];
269#endif
270
271void console_initialize_interrupts( void )
272{
273  Ring_buffer_Initialize( &TX_Buffer[ 0 ] );
274  Ring_buffer_Initialize( &TX_Buffer[ 1 ] );
275
276  Is_TX_active[ 0 ] = FALSE;
277  Is_TX_active[ 1 ] = FALSE;
278
279  atexit( console_exit );
280
281  set_vector( console_isr_a, CONSOLE_UART_A_TRAP, 1 );
282#ifdef RDB_BREAK_IN
283  if (trap_table[0x150/4] == 0x91d02000)
284#endif
285  set_vector( console_isr_b, CONSOLE_UART_B_TRAP, 1 );
286}
287
288/*
289 *  console_outbyte_interrupts
290 *
291 *  This routine transmits a character out.
292 *
293 *  Input parameters:
294 *    port - port to transmit character to
295 *    ch  - character to be transmitted
296 *
297 *  Output parameters:  NONE
298 *
299 *  Return values:      NONE
300 */
301 
302void console_outbyte_interrupts(
303  int  port,
304  char ch
305)
306{
307  /*
308   *  If this is the first character then we need to prime the pump
309   */
310
311  if ( Is_TX_active[ port ] == FALSE ) {
312    Is_TX_active[ port ] = TRUE;
313    console_outbyte_polled( port, ch );
314    return;
315  }
316
317  while ( Ring_buffer_Is_full( &TX_Buffer[ port ] ) );
318 
319  Ring_buffer_Add_character( &TX_Buffer[ port ], ch );
320}
321
322#endif /* CONSOLE_USE_INTERRUPTS */
323
324/*
325 *  DEBUG_puts
326 *
327 *  This should be safe in the event of an error.  It attempts to insure
328 *  that no TX empty interrupts occur while it is doing polled IO.  Then
329 *  it restores the state of that external interrupt.
330 *
331 *  Input parameters:
332 *    string  - pointer to debug output string
333 *
334 *  Output parameters:  NONE
335 *
336 *  Return values:      NONE
337 */
338
339void DEBUG_puts(
340  char *string
341)
342{
343  char *s;
344  unsigned32 old_level;
345
346  ERC32_Disable_interrupt( ERC32_INTERRUPT_UART_A_RX_TX, old_level );
347    for ( s = string ; *s ; s++ ) 
348      console_outbyte_polled( 0, *s );
349
350    console_outbyte_polled( 0, '\r' );
351    console_outbyte_polled( 0, '\n' );
352  ERC32_Restore_interrupt( ERC32_INTERRUPT_UART_A_RX_TX, old_level );
353}
354
355
356/*
357 *  Console Termios Support Entry Points
358 *
359 */
360
361int console_write_support (int minor, char *buf, int len)
362{
363  int nwrite = 0;
364
365  while (nwrite < len) {
366#if defined(CONSOLE_USE_INTERRUPTS)
367    console_outbyte_interrupt( minor, *buf++ );
368#else
369    console_outbyte_polled( minor, *buf++ );
370#endif
371    nwrite++;
372  }
373  return nwrite;
374}
375
376void console_reserve_resources(
377  rtems_configuration_table *configuration
378)
379{
380  rtems_termios_reserve_resources( configuration, 2 );
381}
382
383/*
384 *  Console Device Driver Entry Points
385 *
386 */
387 
388rtems_device_driver console_initialize(
389  rtems_device_major_number  major,
390  rtems_device_minor_number  minor,
391  void                      *arg
392)
393{
394  rtems_status_code status;
395
396  rtems_termios_initialize();
397
398  /*
399   *  Register Device Names
400   */
401
402  status = rtems_io_register_name( "/dev/console", major, 0 );
403  if (status != RTEMS_SUCCESSFUL)
404    rtems_fatal_error_occurred(status);
405
406  status = rtems_io_register_name( "/dev/console_b", major, 1 );
407  if (status != RTEMS_SUCCESSFUL)
408    rtems_fatal_error_occurred(status);
409
410  /*
411   *  Initialize Hardware
412   */
413 
414#ifdef CONSOLE_USE_INTERRUPTS
415  console_initialize_interrupts();
416#endif
417
418  return RTEMS_SUCCESSFUL;
419}
420
421rtems_device_driver console_open(
422  rtems_device_major_number major,
423  rtems_device_minor_number minor,
424  void                    * arg
425)
426{
427        rtems_status_code sc;
428#if defined(CONSOLE_USE_INTERRUPTS)
429        rtems_libio_open_close_args_t *args = arg;
430#endif
431
432        assert( minor <= 1 );
433        if ( minor > 2 )
434          return RTEMS_INVALID_NUMBER;
435 
436#if defined(CONSOLE_USE_INTERRUPTS)
437        sc = rtems_termios_open (major, minor, arg,
438                        NULL,
439                        NULL,
440                        NULL,
441                        console_write_support);
442
443        console_termios_data[ minor ] = args->iop->data1;
444#else
445        sc = rtems_termios_open (major, minor, arg,
446                        NULL,
447                        NULL,
448                        console_inbyte_nonblocking,
449                        console_write_support);
450#endif
451
452  return RTEMS_SUCCESSFUL;
453}
454 
455rtems_device_driver console_close(
456  rtems_device_major_number major,
457  rtems_device_minor_number minor,
458  void                    * arg
459)
460{
461  return rtems_termios_close (arg);
462}
463 
464rtems_device_driver console_read(
465  rtems_device_major_number major,
466  rtems_device_minor_number minor,
467  void                    * arg
468)
469{
470  return rtems_termios_read (arg);
471}
472 
473rtems_device_driver console_write(
474  rtems_device_major_number major,
475  rtems_device_minor_number minor,
476  void                    * arg
477)
478{
479  return rtems_termios_write (arg);
480}
481 
482rtems_device_driver console_control(
483  rtems_device_major_number major,
484  rtems_device_minor_number minor,
485  void                    * arg
486)
487{
488  return rtems_termios_ioctl (arg);
489}
490
Note: See TracBrowser for help on using the repository browser.