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

4.104.114.84.95
Last change on this file since a7e2729 was a7e2729, checked in by Joel Sherrill <joel.sherrill@…>, on Oct 21, 1997 at 6:38:24 PM

Converted to termios style device driver.

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