source: rtems/c/src/lib/libbsp/sparc/leon2/console/console.c @ c499856

4.115
Last change on this file since c499856 was c499856, checked in by Chris Johns <chrisj@…>, on 03/20/14 at 21:10:47

Change all references of rtems.com to rtems.org.

  • Property mode set to 100644
File size: 10.4 KB
Line 
1/**
2 * @file
3 * @ingroup sparc_leon2
4 * @brief TTY driver driver for the serial ports on the LEON console
5 */
6
7/*
8 *  This file contains the TTY driver for the serial ports on the LEON.
9 *
10 *  This driver uses the termios pseudo driver.
11 *
12 *  COPYRIGHT (c) 1989-1998.
13 *  On-Line Applications Research Corporation (OAR).
14 *
15 *  The license and distribution terms for this file may be
16 *  found in the file LICENSE in this distribution or at
17 *  http://www.rtems.org/license/LICENSE.
18 */
19
20#include <bsp.h>
21#include <rtems/libio.h>
22#include <stdlib.h>
23#include <assert.h>
24#include <rtems/bspIo.h>
25
26/*
27 *  Should we use a polled or interrupt drived console?
28 *
29 *  NOTE: This is defined in the custom/leon.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/* body is in debugputs.c */
55
56/*
57 *  console_inbyte_nonblocking
58 *
59 *  This routine polls for a character.
60 */
61
62int console_inbyte_nonblocking( int port );
63
64/* body is in debugputs.c */
65
66/*
67 *  Interrupt driven console IO
68 */
69
70#if (CONSOLE_USE_INTERRUPTS)
71
72/*
73 *  Buffers between task and ISRs
74 */
75
76#include <ringbuf.h>
77
78Ring_buffer_t  TX_Buffer[ 2 ];
79bool           Is_TX_active[ 2 ];
80
81void *console_termios_data[ 2 ];
82
83/*
84 *  console_isr_a
85 *
86 *  This routine is the console interrupt handler for Channel 1.
87 *
88 *  Input parameters:
89 *    vector - vector number
90 *
91 *  Output parameters: NONE
92 *
93 *  Return values:     NONE
94 */
95
96rtems_isr console_isr_a(
97  rtems_vector_number vector
98)
99{
100  char ch;
101  int UStat;
102
103  if ( (UStat = LEON_REG.UART_Status_1) & LEON_REG_UART_STATUS_DR ) {
104    if (UStat & LEON_REG_UART_STATUS_ERR) {
105      LEON_REG.UART_Status_1 = LEON_REG_UART_STATUS_CLR;
106    }
107    ch = LEON_REG.UART_Channel_1;
108
109    rtems_termios_enqueue_raw_characters( console_termios_data[ 0 ], &ch, 1 );
110  }
111
112  if ( LEON_REG.UART_Status_1 & LEON_REG_UART_STATUS_THE ) {
113    if ( !Ring_buffer_Is_empty( &TX_Buffer[ 0 ] ) ) {
114      Ring_buffer_Remove_character( &TX_Buffer[ 0 ], ch );
115      LEON_REG.UART_Channel_1 = (uint32_t) ch;
116    } else
117     Is_TX_active[ 0 ] = false;
118  }
119
120  LEON_Clear_interrupt( LEON_INTERRUPT_UART_1_RX_TX );
121}
122
123/*
124 *  console_isr_b
125 *
126 *  This routine is the console interrupt handler for Channel 2.
127 *
128 *  Input parameters:
129 *    vector - vector number
130 *
131 *  Output parameters: NONE
132 *
133 *  Return values:     NONE
134 */
135
136rtems_isr console_isr_b(
137  rtems_vector_number vector
138)
139{
140  char ch;
141  int UStat;
142
143  if ( (UStat = LEON_REG.UART_Status_2) & LEON_REG_UART_STATUS_DR ) {
144    if (UStat & LEON_REG_UART_STATUS_ERR) {
145      LEON_REG.UART_Status_2 = LEON_REG_UART_STATUS_CLR;
146    }
147    ch = LEON_REG.UART_Channel_2;
148    rtems_termios_enqueue_raw_characters( console_termios_data[ 1 ], &ch, 1 );
149
150  }
151
152  if ( LEON_REG.UART_Status_2 & LEON_REG_UART_STATUS_THE ) {
153    if ( !Ring_buffer_Is_empty( &TX_Buffer[ 1 ] ) ) {
154      Ring_buffer_Remove_character( &TX_Buffer[ 1 ], ch );
155      LEON_REG.UART_Channel_2 = (uint32_t) ch;
156    } else
157     Is_TX_active[ 1 ] = false;
158  }
159
160  LEON_Clear_interrupt( LEON_INTERRUPT_UART_2_RX_TX );
161}
162
163/*
164 *  console_exit
165 *
166 *  This routine allows the console to exit by masking its associated interrupt
167 *  vectors.
168 *
169 *  Input parameters:  NONE
170 *
171 *  Output parameters: NONE
172 *
173 *  Return values:     NONE
174 */
175
176void console_exit()
177{
178  uint32_t port;
179  uint32_t ch;
180
181  /*
182   *  Although the interrupts for the UART are unmasked, the PIL is set to
183   *  disable all external interrupts.  So we might as well do this first.
184   */
185
186  LEON_Mask_interrupt( LEON_INTERRUPT_UART_1_RX_TX );
187  LEON_Mask_interrupt( LEON_INTERRUPT_UART_2_RX_TX );
188
189  for ( port=0 ; port <= 1 ; port++ ) {
190    while ( !Ring_buffer_Is_empty( &TX_Buffer[ port ] ) ) {
191      Ring_buffer_Remove_character( &TX_Buffer[ port ], ch );
192      console_outbyte_polled( port, ch );
193    }
194  }
195
196  /*
197   *  Now wait for all the data to actually get out ... the send register
198   *  should be empty.
199   */
200
201  while ( (LEON_REG.UART_Status_1 & LEON_REG_UART_STATUS_THE) !=
202          LEON_REG_UART_STATUS_THE );
203
204  while ( (LEON_REG.UART_Status_2 & LEON_REG_UART_STATUS_THE) !=
205          LEON_REG_UART_STATUS_THE );
206
207  LEON_REG.UART_Control_1 = 0;
208  LEON_REG.UART_Control_2 = 0;
209  LEON_REG.UART_Status_1 = 0;
210  LEON_REG.UART_Status_2 = 0;
211
212
213}
214
215#define CONSOLE_UART_1_TRAP  LEON_TRAP_TYPE( LEON_INTERRUPT_UART_1_RX_TX )
216#define CONSOLE_UART_2_TRAP  LEON_TRAP_TYPE( LEON_INTERRUPT_UART_2_RX_TX )
217
218/*
219 *  console_initialize_interrupts
220 *
221 *  This routine initializes the console's receive and transmit
222 *  ring buffers and loads the appropriate vectors to handle the interrupts.
223 *
224 *  Input parameters:  NONE
225 *
226 *  Output parameters: NONE
227 *
228 *  Return values:     NONE
229 */
230
231#ifdef RDB_BREAK_IN
232  extern uint32_t trap_table[];
233#endif
234
235void console_initialize_interrupts( void )
236{
237  Ring_buffer_Initialize( &TX_Buffer[ 0 ] );
238  Ring_buffer_Initialize( &TX_Buffer[ 1 ] );
239
240  Is_TX_active[ 0 ] = false;
241  Is_TX_active[ 1 ] = false;
242
243  atexit( console_exit );
244
245  LEON_REG.UART_Control_1 |= LEON_REG_UART_CTRL_RI | LEON_REG_UART_CTRL_TI;
246  LEON_REG.UART_Control_2 |= LEON_REG_UART_CTRL_RI | LEON_REG_UART_CTRL_TI;
247
248  set_vector( console_isr_a, CONSOLE_UART_1_TRAP, 1 );
249#ifdef RDB_BREAK_IN
250  if (trap_table[0x150/4] == 0x91d02000)
251#endif
252  set_vector( console_isr_b, CONSOLE_UART_2_TRAP, 1 );
253}
254
255/*
256 *  console_outbyte_interrupt
257 *
258 *  This routine transmits a character out.
259 *
260 *  Input parameters:
261 *    port - port to transmit character to
262 *    ch  - character to be transmitted
263 *
264 *  Output parameters:  NONE
265 *
266 *  Return values:      NONE
267 */
268
269void console_outbyte_interrupt(
270  int   port,
271  char  ch
272)
273{
274  /*
275   *  If this is the first character then we need to prime the pump
276   */
277
278  if ( Is_TX_active[ port ] == false ) {
279    Is_TX_active[ port ] = true;
280    console_outbyte_polled( port, ch );
281    return;
282  }
283
284  while ( Ring_buffer_Is_full( &TX_Buffer[ port ] ) );
285
286  Ring_buffer_Add_character( &TX_Buffer[ port ], ch );
287}
288
289#endif /* CONSOLE_USE_INTERRUPTS */
290
291/*
292 *  Console Termios Support Entry Points
293 *
294 */
295
296ssize_t console_write_support (int minor, const char *buf, size_t len)
297{
298  int nwrite = 0;
299
300  while (nwrite < len) {
301#if (CONSOLE_USE_INTERRUPTS)
302    console_outbyte_interrupt( minor, *buf++ );
303#else
304    console_outbyte_polled( minor, *buf++ );
305#endif
306    nwrite++;
307  }
308  return nwrite;
309}
310
311/*
312 *  Console Device Driver Entry Points
313 *
314 */
315
316rtems_device_driver console_initialize(
317  rtems_device_major_number  major,
318  rtems_device_minor_number  minor,
319  void                      *arg
320)
321{
322  rtems_status_code status;
323
324  rtems_termios_initialize();
325
326  /*
327   *  Register Device Names
328   */
329
330  status = rtems_io_register_name( "/dev/console", major, 0 );
331  if (status != RTEMS_SUCCESSFUL)
332    rtems_fatal_error_occurred(status);
333
334  status = rtems_io_register_name( "/dev/console_b", major, 1 );
335  if (status != RTEMS_SUCCESSFUL)
336    rtems_fatal_error_occurred(status);
337
338  /*
339   *  Initialize Hardware
340   */
341
342  LEON_REG.UART_Control_1 |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE;
343  LEON_REG.UART_Control_2 |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE |
344        LEON_REG_UART_CTRL_RI;  /* rx irq default enable for remote debugger */
345  LEON_REG.UART_Status_1 = 0;
346  LEON_REG.UART_Status_2 = 0;
347#if (CONSOLE_USE_INTERRUPTS)
348  console_initialize_interrupts();
349#endif
350
351  return RTEMS_SUCCESSFUL;
352}
353
354rtems_device_driver console_open(
355  rtems_device_major_number major,
356  rtems_device_minor_number minor,
357  void                    * arg
358)
359{
360  rtems_status_code sc;
361#if (CONSOLE_USE_INTERRUPTS)
362  rtems_libio_open_close_args_t *args = arg;
363  static const rtems_termios_callbacks intrCallbacks = {
364    NULL,                        /* firstOpen */
365    NULL,                        /* lastClose */
366    NULL,                        /* pollRead */
367    console_write_support,       /* write */
368    NULL,                        /* setAttributes */
369    NULL,                        /* stopRemoteTx */
370    NULL,                        /* startRemoteTx */
371    0                            /* outputUsesInterrupts */
372  };
373#else
374  static const rtems_termios_callbacks pollCallbacks = {
375    NULL,                        /* firstOpen */
376    NULL,                        /* lastClose */
377    console_inbyte_nonblocking,  /* pollRead */
378    console_write_support,       /* write */
379    NULL,                        /* setAttributes */
380    NULL,                        /* stopRemoteTx */
381    NULL,                        /* startRemoteTx */
382    0                            /* outputUsesInterrupts */
383  };
384#endif
385
386  assert( minor <= 1 );
387  if ( minor > 2 )
388    return RTEMS_INVALID_NUMBER;
389
390#if (CONSOLE_USE_INTERRUPTS)
391  sc = rtems_termios_open (major, minor, arg, &intrCallbacks);
392
393  console_termios_data[ minor ] = args->iop->data1;
394#else
395  sc = rtems_termios_open (major, minor, arg, &pollCallbacks);
396#endif
397
398  return RTEMS_SUCCESSFUL;
399}
400
401rtems_device_driver console_close(
402  rtems_device_major_number major,
403  rtems_device_minor_number minor,
404  void                    * arg
405)
406{
407  return rtems_termios_close (arg);
408}
409
410rtems_device_driver console_read(
411  rtems_device_major_number major,
412  rtems_device_minor_number minor,
413  void                    * arg
414)
415{
416  return rtems_termios_read (arg);
417}
418
419rtems_device_driver console_write(
420  rtems_device_major_number major,
421  rtems_device_minor_number minor,
422  void                    * arg
423)
424{
425  return rtems_termios_write (arg);
426}
427
428rtems_device_driver console_control(
429  rtems_device_major_number major,
430  rtems_device_minor_number minor,
431  void                    * arg
432)
433{
434  return rtems_termios_ioctl (arg);
435}
436
437/* putchar/getchar for printk */
438
439static void bsp_out_char (char c)
440{
441  console_outbyte_polled(0, c);
442}
443
444BSP_output_char_function_type BSP_output_char = bsp_out_char;
445
446static int bsp_in_char(void)
447{
448  int tmp;
449
450  while ((tmp = console_inbyte_nonblocking(0)) < 0);
451  return tmp;
452}
453
454BSP_polling_getchar_function_type BSP_poll_char = bsp_in_char;
Note: See TracBrowser for help on using the repository browser.