source: rtems/c/src/lib/libbsp/sparc/leon3/console/console.c @ 46d7fa5

4.115
Last change on this file since 46d7fa5 was 46d7fa5, checked in by Sebastian Huber <sebastian.huber@…>, on 02/17/14 at 10:54:35

bsp/leon3: Add and use fatal codes

  • Property mode set to 100644
File size: 11.2 KB
Line 
1/*
2 *  This file contains the TTY driver for the serial ports on the LEON.
3 *
4 *  This driver uses the termios pseudo driver.
5 *
6 *  COPYRIGHT (c) 1989-1998.
7 *  On-Line Applications Research Corporation (OAR).
8 *
9 *  Modified for LEON3 BSP.
10 *  COPYRIGHT (c) 2004.
11 *  Gaisler Research.
12 *
13 *  The license and distribution terms for this file may be
14 *  found in the file LICENSE in this distribution or at
15 *  http://www.rtems.com/license/LICENSE.
16 */
17
18/* Define CONSOLE_USE_INTERRUPTS to enable APBUART interrupt handling instead
19 * of polling mode.
20 *
21 * Note that it is not possible to use the interrupt mode of the driver
22 * together with the "old" APBUART and -u to GRMON. However the new
23 * APBUART core (from GRLIB 1.0.17-b2710) has the GRMON debug bit and can
24 * handle interrupts.
25 *
26 * NOTE: This can be defined in the make/custom/leon3.cfg file.
27 */
28
29#include <bsp.h>
30#include <bsp/fatal.h>
31#include <rtems/libio.h>
32#include <stdlib.h>
33#include <assert.h>
34#include <rtems/bspIo.h>
35#include <leon.h>
36#include <rtems/termiostypes.h>
37
38int syscon_uart_index __attribute__((weak)) = 0;
39
40/* body is in debugputs.c */
41
42struct apbuart_priv {
43  struct apbuart_regs *regs;
44  unsigned int freq_hz;
45#if CONSOLE_USE_INTERRUPTS
46  int irq;
47  void *cookie;
48  volatile int sending;
49  char *buf;
50#endif
51};
52static struct apbuart_priv apbuarts[BSP_NUMBER_OF_TERMIOS_PORTS];
53static int uarts = 0;
54
55static struct apbuart_priv *leon3_console_get_uart(int minor)
56{
57  struct apbuart_priv *uart;
58
59  if (minor == 0)
60    uart = &apbuarts[syscon_uart_index];
61  else
62    uart = &apbuarts[minor - 1];
63
64  return uart;
65}
66
67#if CONSOLE_USE_INTERRUPTS
68
69/* Handle UART interrupts */
70static void leon3_console_isr(void *arg)
71{
72  struct apbuart_priv *uart = arg;
73  unsigned int status;
74  char data;
75
76  /* Get all received characters */
77  while ((status=uart->regs->status) & LEON_REG_UART_STATUS_DR) {
78    /* Data has arrived, get new data */
79    data = uart->regs->data;
80
81    /* Tell termios layer about new character */
82    rtems_termios_enqueue_raw_characters(uart->cookie, &data, 1);
83  }
84
85  if (
86    (status & LEON_REG_UART_STATUS_THE)
87      && (uart->regs->ctrl & LEON_REG_UART_CTRL_TI) != 0
88  ) {
89    /* write_interrupt will get called from this function */
90    rtems_termios_dequeue_characters(uart->cookie, 1);
91  }
92}
93
94/*
95 *  Console Termios Write-Buffer Support Entry Point
96 *
97 */
98static int leon3_console_write_support(int minor, const char *buf, size_t len)
99{
100  struct apbuart_priv *uart = leon3_console_get_uart(minor);
101  int sending;
102
103  if (len > 0) {
104    /* Enable TX interrupt (interrupt is edge-triggered) */
105    uart->regs->ctrl |= LEON_REG_UART_CTRL_TI;
106
107    /* start UART TX, this will result in an interrupt when done */
108    uart->regs->data = *buf;
109
110    sending = 1;
111  } else {
112    /* No more to send, disable TX interrupts */
113    uart->regs->ctrl &= ~LEON_REG_UART_CTRL_TI;
114
115    /* Tell close that we sent everything */
116    sending = 0;
117  }
118
119  uart->sending = sending;
120
121  return 0;
122}
123
124#else
125
126/*
127 *  Console Termios Support Entry Points
128 */
129static ssize_t leon3_console_write_polled(
130  int minor,
131  const char *buf,
132  size_t len
133)
134{
135  struct apbuart_priv *uart = leon3_console_get_uart(minor);
136  int nwrite = 0;
137
138  while (nwrite < len) {
139    apbuart_outbyte_polled(uart->regs, *buf++, 1, 0);
140    nwrite++;
141  }
142  return nwrite;
143}
144
145static int leon3_console_pollRead(int minor)
146{
147  struct apbuart_priv *uart = leon3_console_get_uart(minor);
148
149  return apbuart_inbyte_nonblocking(uart->regs);
150}
151
152#endif
153
154static int leon3_console_set_attributes(int minor, const struct termios *t)
155{
156  struct apbuart_priv *uart = leon3_console_get_uart(minor);
157  unsigned int scaler;
158  unsigned int ctrl;
159  int baud;
160
161  switch (t->c_cflag & CSIZE) {
162    default:
163    case CS5:
164    case CS6:
165    case CS7:
166      /* Hardware doesn't support other than CS8 */
167      return -1;
168    case CS8:
169      break;
170  }
171
172  /*
173   * FIXME: This read-modify-write sequence is broken since interrupts may
174   * interfere.
175   */
176
177  /* Read out current value */
178  ctrl = uart->regs->ctrl;
179
180  switch (t->c_cflag & (PARENB|PARODD)) {
181    case (PARENB|PARODD):
182      /* Odd parity */
183      ctrl |= LEON_REG_UART_CTRL_PE|LEON_REG_UART_CTRL_PS;
184      break;
185
186    case PARENB:
187      /* Even parity */
188      ctrl &= ~LEON_REG_UART_CTRL_PS;
189      ctrl |= LEON_REG_UART_CTRL_PE;
190      break;
191
192    default:
193    case 0:
194    case PARODD:
195      /* No Parity */
196      ctrl &= ~(LEON_REG_UART_CTRL_PS|LEON_REG_UART_CTRL_PE);
197  }
198
199  if (!(t->c_cflag & CLOCAL)) {
200    ctrl |= LEON_REG_UART_CTRL_FL;
201  } else {
202    ctrl &= ~LEON_REG_UART_CTRL_FL;
203  }
204
205  /* Update new settings */
206  uart->regs->ctrl = ctrl;
207
208  /* Baud rate */
209  baud = rtems_termios_baud_to_number(t->c_cflag);
210  if (baud > 0) {
211    /* Calculate Baud rate generator "scaler" number */
212    scaler = (((uart->freq_hz * 10) / (baud * 8)) - 5) / 10;
213
214    /* Set new baud rate by setting scaler */
215    uart->regs->scaler = scaler;
216  }
217
218  return 0;
219}
220
221/* AMBA PP find routine. Extract AMBA PnP information into data structure. */
222static int find_matching_apbuart(struct ambapp_dev *dev, int index, void *arg)
223{
224  struct ambapp_apb_info *apb = (struct ambapp_apb_info *)dev->devinfo;
225
226  /* Extract needed information of one APBUART */
227  apbuarts[uarts].regs = (struct apbuart_regs *)apb->start;
228#if CONSOLE_USE_INTERRUPTS
229  apbuarts[uarts].irq = apb->irq;
230#endif
231  /* Get APBUART core frequency, it is assumed that it is the same
232   * as Bus frequency where the UART is situated
233   */
234  apbuarts[uarts].freq_hz = ambapp_freq_get(&ambapp_plb, dev);
235  uarts++;
236
237  if (uarts >= BSP_NUMBER_OF_TERMIOS_PORTS)
238    return 1; /* Satisfied number of UARTs, stop search */
239  else
240    return 0; /* Continue searching for more UARTs */
241}
242
243/* Find all UARTs */
244static void leon3_console_scan_uarts(void)
245{
246  memset(apbuarts, 0, sizeof(apbuarts));
247
248  /* Find APBUART cores */
249  ambapp_for_each(&ambapp_plb, (OPTIONS_ALL|OPTIONS_APB_SLVS), VENDOR_GAISLER,
250                  GAISLER_APBUART, find_matching_apbuart, NULL);
251}
252
253/*
254 *  Console Device Driver Entry Points
255 *
256 */
257
258rtems_device_driver console_initialize(
259  rtems_device_major_number  major,
260  rtems_device_minor_number  minor,
261  void                      *arg
262)
263{
264  rtems_status_code status;
265  int i;
266  char console_name[16];
267
268  rtems_termios_initialize();
269
270  /* Find UARTs */
271  leon3_console_scan_uarts();
272
273  /* Update syscon_uart_index to index used as /dev/console
274   * Let user select System console by setting syscon_uart_index. If the
275   * BSP is to provide the default UART (syscon_uart_index==0):
276   *   non-MP: APBUART[0] is system console
277   *   MP: LEON CPU index select UART
278   */
279  if (syscon_uart_index == 0) {
280#if defined(RTEMS_MULTIPROCESSING)
281    syscon_uart_index = LEON3_Cpu_Index;
282#else
283    syscon_uart_index = 0;
284#endif
285  } else {
286    syscon_uart_index = syscon_uart_index - 1; /* User selected sys-console */
287  }
288
289  /*  Register Device Names
290   *
291   *  0 /dev/console   - APBUART[USER-SELECTED, DEFAULT=APBUART[0]]
292   *  1 /dev/console_a - APBUART[0] (by default not present because is console)
293   *  2 /dev/console_b - APBUART[1]
294   *  ...
295   *
296   * On a MP system one should not open UARTs that other OS instances use.
297   */
298  if (syscon_uart_index < uarts) {
299    status = rtems_io_register_name("/dev/console", major, 0);
300    if (status != RTEMS_SUCCESSFUL)
301      bsp_fatal(LEON3_FATAL_CONSOLE_REGISTER_DEV);
302  }
303  strcpy(console_name,"/dev/console_a");
304  for (i = 0; i < uarts; i++) {
305    if (i == syscon_uart_index)
306      continue; /* skip UART that is registered as /dev/console */
307    console_name[13] = 'a' + i;
308    rtems_io_register_name( console_name, major, i+1);
309  }
310
311  return RTEMS_SUCCESSFUL;
312}
313
314#if CONSOLE_USE_INTERRUPTS
315static struct rtems_termios_tty *leon3_console_get_tty(
316  rtems_libio_open_close_args_t *args
317)
318{
319  return args->iop->data1;
320}
321#endif
322
323static int leon3_console_first_open(int major, int minor, void *arg)
324{
325  struct apbuart_priv *uart = leon3_console_get_uart(minor);
326
327#if CONSOLE_USE_INTERRUPTS
328  rtems_status_code sc;
329
330  uart->cookie = leon3_console_get_tty(arg);
331
332  /* Register Interrupt handler */
333  sc = rtems_interrupt_handler_install(uart->irq, "console",
334                                       RTEMS_INTERRUPT_SHARED,
335                                       leon3_console_isr,
336                                       uart);
337  if (sc != RTEMS_SUCCESSFUL)
338    return -1;
339
340  uart->sending = 0;
341  /* Enable Receiver and transmitter and Turn on RX interrupts */
342  uart->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE |
343                      LEON_REG_UART_CTRL_RI;
344#else
345  /* Initialize UART on opening */
346  uart->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE;
347#endif
348  uart->regs->status = 0;
349
350  return 0;
351}
352
353#if CONSOLE_USE_INTERRUPTS
354static int leon3_console_last_close(int major, int minor, void *arg)
355{
356  struct rtems_termios_tty *tty = leon3_console_get_tty(arg);
357  struct apbuart_priv *uart = leon3_console_get_uart(minor);
358  rtems_interrupt_level level;
359
360  /* Turn off RX interrupts */
361  rtems_termios_interrupt_lock_acquire(tty, level);
362  uart->regs->ctrl &= ~(LEON_REG_UART_CTRL_RI);
363  rtems_termios_interrupt_lock_release(tty, level);
364
365  /**** Flush device ****/
366  while (uart->sending) {
367    /* Wait until all data has been sent */
368  }
369
370  /* uninstall ISR */
371  rtems_interrupt_handler_remove(uart->irq, leon3_console_isr, uart);
372
373  return 0;
374}
375#endif
376
377rtems_device_driver console_open(
378  rtems_device_major_number major,
379  rtems_device_minor_number minor,
380  void                    * arg
381)
382{
383#if CONSOLE_USE_INTERRUPTS
384  /* Interrupt mode routines */
385  static const rtems_termios_callbacks Callbacks = {
386    leon3_console_first_open,    /* firstOpen */
387    leon3_console_last_close,    /* lastClose */
388    NULL,                        /* pollRead */
389    leon3_console_write_support, /* write */
390    leon3_console_set_attributes,/* setAttributes */
391    NULL,                        /* stopRemoteTx */
392    NULL,                        /* startRemoteTx */
393    1                            /* outputUsesInterrupts */
394  };
395#else
396  /* Polling mode routines */
397  static const rtems_termios_callbacks Callbacks = {
398    leon3_console_first_open,    /* firstOpen */
399    NULL,                        /* lastClose */
400    leon3_console_pollRead,      /* pollRead */
401    leon3_console_write_polled,  /* write */
402    leon3_console_set_attributes,/* setAttributes */
403    NULL,                        /* stopRemoteTx */
404    NULL,                        /* startRemoteTx */
405    0                            /* outputUsesInterrupts */
406  };
407#endif
408
409  assert(minor <= uarts);
410  if (minor > uarts || minor == (syscon_uart_index + 1))
411    return RTEMS_INVALID_NUMBER;
412
413  return rtems_termios_open(major, minor, arg, &Callbacks);
414}
415
416rtems_device_driver console_close(
417  rtems_device_major_number major,
418  rtems_device_minor_number minor,
419  void                    * arg
420)
421{
422  return rtems_termios_close(arg);
423}
424
425rtems_device_driver console_read(
426  rtems_device_major_number major,
427  rtems_device_minor_number minor,
428  void                    * arg
429)
430{
431  return rtems_termios_read(arg);
432}
433
434rtems_device_driver console_write(
435  rtems_device_major_number major,
436  rtems_device_minor_number minor,
437  void                    * arg
438)
439{
440  return rtems_termios_write(arg);
441}
442
443rtems_device_driver console_control(
444  rtems_device_major_number major,
445  rtems_device_minor_number minor,
446  void                    * arg
447)
448{
449  return rtems_termios_ioctl(arg);
450}
451
Note: See TracBrowser for help on using the repository browser.