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

4.115
Last change on this file since c8707a3 was c8707a3, checked in by Joel Sherrill <joel.sherrill@…>, on 09/21/13 at 21:25:06

leon3/console.c: Fix misisng prototype issues

  • Property mode set to 100644
File size: 11.6 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 <rtems/libio.h>
31#include <stdlib.h>
32#include <assert.h>
33#include <rtems/bspIo.h>
34#include <amba.h>
35#include <rtems/termiostypes.h>
36
37/* Let user override which on-chip APBUART will be debug UART
38 * 0 = Default APBUART. On MP system CPU0=APBUART0, CPU1=APBUART1...
39 * 1 = APBUART[0]
40 * 2 = APBUART[1]
41 * 3 = APBUART[2]
42 * ...
43 */
44int syscon_uart_index __attribute__((weak)) = 0;
45
46/*
47 *  apbuart_outbyte_polled
48 *
49 *  This routine transmits a character using polling.
50 */
51
52extern void apbuart_outbyte_polled(
53  struct apbuart_regs *regs,
54  unsigned char ch,
55  int do_cr_on_newline,
56  int wait_sent
57  );
58
59
60/* body is in printk_support.c */
61
62/*
63 *  apbuart_inbyte_nonblocking
64 *
65 *  This routine polls for a character.
66 */
67
68extern int apbuart_inbyte_nonblocking(struct apbuart_regs *regs);
69
70/* body is in debugputs.c */
71
72struct apbuart_priv {
73  struct apbuart_regs *regs;
74  unsigned int freq_hz;
75#if CONSOLE_USE_INTERRUPTS
76  int irq;
77  void *cookie;
78  volatile int sending;
79  char *buf;
80#endif
81};
82static struct apbuart_priv apbuarts[BSP_NUMBER_OF_TERMIOS_PORTS];
83static int uarts = 0;
84
85#if CONSOLE_USE_INTERRUPTS
86
87/* Handle UART interrupts */
88void console_isr(void *arg)
89{
90  struct apbuart_priv *uart = arg;
91  unsigned int status;
92  char data;
93
94  /* Get all received characters */
95  while ((status=uart->regs->status) & LEON_REG_UART_STATUS_DR) {
96    /* Data has arrived, get new data */
97    data = uart->regs->data;
98
99    /* Tell termios layer about new character */
100    rtems_termios_enqueue_raw_characters(uart->cookie, &data, 1);
101  }
102
103  if (status & LEON_REG_UART_STATUS_THE) {
104    /* Sent the one char, we disable TX interrupts */
105    uart->regs->ctrl &= ~LEON_REG_UART_CTRL_TI;
106
107    /* Tell close that we sent everything */
108    uart->sending = 0;
109
110    /* write_interrupt will get called from this function */
111    rtems_termios_dequeue_characters(uart->cookie, 1);
112  }
113}
114
115/*
116 *  Console Termios Write-Buffer Support Entry Point
117 *
118 */
119int console_write_interrupt(int minor, const char *buf, int len)
120{
121  if (len > 0) {
122    struct apbuart_priv *uart;
123
124    if (minor == 0)
125      uart = &apbuarts[syscon_uart_index];
126    else
127      uart = &apbuarts[minor - 1];
128
129    /* Remember what position in buffer */
130
131    /* Enable TX interrupt */
132    uart->regs->ctrl |= LEON_REG_UART_CTRL_TI;
133
134    /* start UART TX, this will result in an interrupt when done */
135    uart->regs->data = *buf;
136
137    uart->sending = 1;
138  }
139
140  return 0;
141}
142
143#else
144
145/*
146 * Prototypes to avoid warnings
147 */
148ssize_t console_write_polled(int minor, const char *buf, size_t len);
149int console_pollRead(int minor);
150
151/*
152 *  Console Termios Support Entry Points
153 */
154ssize_t console_write_polled(int minor, const char *buf, size_t len)
155{
156  int nwrite = 0, port;
157
158  if (minor == 0)
159    port = syscon_uart_index;
160  else
161    port = minor - 1;
162
163  while (nwrite < len) {
164    apbuart_outbyte_polled(apbuarts[port].regs, *buf++, 1, 0);
165    nwrite++;
166  }
167  return nwrite;
168}
169
170int console_pollRead(int minor)
171{
172  int port;
173
174  if (minor == 0)
175    port = syscon_uart_index;
176  else
177    port = minor - 1;
178
179  return apbuart_inbyte_nonblocking(apbuarts[port].regs);
180}
181
182#endif
183
184/*
185 * Prototypes to avoid warnings
186 */
187int console_set_attributes(int minor, const struct termios *t);
188int find_matching_apbuart(struct ambapp_dev *dev, int index, void *arg);
189int console_scan_uarts(void);
190
191
192int console_set_attributes(int minor, const struct termios *t)
193{
194  unsigned int scaler;
195  unsigned int ctrl;
196  int baud;
197  struct apbuart_priv *uart;
198
199  switch (t->c_cflag & CSIZE) {
200    default:
201    case CS5:
202    case CS6:
203    case CS7:
204      /* Hardware doesn't support other than CS8 */
205      return -1;
206    case CS8:
207      break;
208  }
209
210  if (minor == 0)
211    uart = &apbuarts[syscon_uart_index];
212  else
213    uart = &apbuarts[minor - 1];
214
215  /* Read out current value */
216  ctrl = uart->regs->ctrl;
217
218  switch (t->c_cflag & (PARENB|PARODD)) {
219    case (PARENB|PARODD):
220      /* Odd parity */
221      ctrl |= LEON_REG_UART_CTRL_PE|LEON_REG_UART_CTRL_PS;
222      break;
223
224    case PARENB:
225      /* Even parity */
226      ctrl &= ~LEON_REG_UART_CTRL_PS;
227      ctrl |= LEON_REG_UART_CTRL_PE;
228      break;
229
230    default:
231    case 0:
232    case PARODD:
233      /* No Parity */
234      ctrl &= ~(LEON_REG_UART_CTRL_PS|LEON_REG_UART_CTRL_PE);
235  }
236
237  if (!(t->c_cflag & CLOCAL)) {
238    ctrl |= LEON_REG_UART_CTRL_FL;
239  } else {
240    ctrl &= ~LEON_REG_UART_CTRL_FL;
241  }
242
243  /* Update new settings */
244  uart->regs->ctrl = ctrl;
245
246  /* Baud rate */
247  baud = rtems_termios_baud_to_number(t->c_cflag);
248  if (baud > 0) {
249    /* Calculate Baud rate generator "scaler" number */
250    scaler = (((uart->freq_hz * 10) / (baud * 8)) - 5) / 10;
251
252    /* Set new baud rate by setting scaler */
253    uart->regs->scaler = scaler;
254  }
255
256  return 0;
257}
258
259/* AMBA PP find routine. Extract AMBA PnP information into data structure. */
260int find_matching_apbuart(struct ambapp_dev *dev, int index, void *arg)
261{
262  struct ambapp_apb_info *apb = (struct ambapp_apb_info *)dev->devinfo;
263
264  /* Extract needed information of one APBUART */
265  apbuarts[uarts].regs = (struct apbuart_regs *)apb->start;
266#if CONSOLE_USE_INTERRUPTS
267  apbuarts[uarts].irq = apb->irq;
268#endif
269  /* Get APBUART core frequency, it is assumed that it is the same
270   * as Bus frequency where the UART is situated
271   */
272  apbuarts[uarts].freq_hz = ambapp_freq_get(&ambapp_plb, dev);
273  uarts++;
274
275  if (uarts >= BSP_NUMBER_OF_TERMIOS_PORTS)
276    return 1; /* Satisfied number of UARTs, stop search */
277  else
278    return 0; /* Continue searching for more UARTs */
279}
280
281/* Find all UARTs */
282int console_scan_uarts(void)
283{
284  memset(apbuarts, 0, sizeof(apbuarts));
285
286  /* Find APBUART cores */
287  ambapp_for_each(&ambapp_plb, (OPTIONS_ALL|OPTIONS_APB_SLVS), VENDOR_GAISLER,
288                  GAISLER_APBUART, find_matching_apbuart, NULL);
289
290  return uarts;
291}
292
293/*
294 *  Console Device Driver Entry Points
295 *
296 */
297
298rtems_device_driver console_initialize(
299  rtems_device_major_number  major,
300  rtems_device_minor_number  minor,
301  void                      *arg
302)
303{
304  rtems_status_code status;
305  int i;
306  char console_name[16];
307
308  rtems_termios_initialize();
309
310  /* Find UARTs */
311  console_scan_uarts();
312
313  /* Update syscon_uart_index to index used as /dev/console
314   * Let user select System console by setting syscon_uart_index. If the
315   * BSP is to provide the default UART (syscon_uart_index==0):
316   *   non-MP: APBUART[0] is system console
317   *   MP: LEON CPU index select UART
318   */
319  if (syscon_uart_index == 0) {
320#if defined(RTEMS_MULTIPROCESSING)
321    syscon_uart_index = LEON3_Cpu_Index;
322#else
323    syscon_uart_index = 0;
324#endif
325  } else {
326    syscon_uart_index = syscon_uart_index - 1; /* User selected sys-console */
327  }
328
329  /*  Register Device Names
330   *
331   *  0 /dev/console   - APBUART[USER-SELECTED, DEFAULT=APBUART[0]]
332   *  1 /dev/console_a - APBUART[0] (by default not present because is console)
333   *  2 /dev/console_b - APBUART[1]
334   *  ...
335   *
336   * On a MP system one should not open UARTs that other OS instances use.
337   */
338  if (syscon_uart_index < uarts) {
339    status = rtems_io_register_name("/dev/console", major, 0);
340    if (status != RTEMS_SUCCESSFUL)
341      rtems_fatal_error_occurred(status);
342  }
343  strcpy(console_name,"/dev/console_a");
344  for (i = 0; i < uarts; i++) {
345    if (i == syscon_uart_index)
346      continue; /* skip UART that is registered as /dev/console */
347    console_name[13] = 'a' + i;
348    status = rtems_io_register_name( console_name, major, i+1);
349  }
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  struct apbuart_priv *uart;
362#if CONSOLE_USE_INTERRUPTS
363  rtems_libio_open_close_args_t *priv = arg;
364
365  /* Interrupt mode routines */
366  static const rtems_termios_callbacks Callbacks = {
367    NULL,                        /* firstOpen */
368    NULL,                        /* lastClose */
369    NULL,                        /* pollRead */
370    console_write_interrupt,     /* write */
371    console_set_attributes,      /* setAttributes */
372    NULL,                        /* stopRemoteTx */
373    NULL,                        /* startRemoteTx */
374    1                            /* outputUsesInterrupts */
375  };
376#else
377  /* Polling mode routines */
378  static const rtems_termios_callbacks Callbacks = {
379    NULL,                        /* firstOpen */
380    NULL,                        /* lastClose */
381    console_pollRead,            /* pollRead */
382    console_write_polled,        /* write */
383    console_set_attributes,      /* setAttributes */
384    NULL,                        /* stopRemoteTx */
385    NULL,                        /* startRemoteTx */
386    0                            /* outputUsesInterrupts */
387  };
388#endif
389
390  assert(minor <= uarts);
391  if (minor > uarts || minor == (syscon_uart_index + 1))
392    return RTEMS_INVALID_NUMBER;
393
394  sc = rtems_termios_open(major, minor, arg, &Callbacks);
395  if (sc != RTEMS_SUCCESSFUL)
396    return sc;
397
398  if (minor == 0)
399    uart = &apbuarts[syscon_uart_index];
400  else
401    uart = &apbuarts[minor - 1];
402
403#if CONSOLE_USE_INTERRUPTS
404  if (priv && priv->iop)
405    uart->cookie = priv->iop->data1;
406  else
407    uart->cookie = NULL;
408
409  /* Register Interrupt handler */
410  sc = rtems_interrupt_handler_install(uart->irq, "console",
411                                       RTEMS_INTERRUPT_SHARED, console_isr,
412                                       uart);
413  if (sc != RTEMS_SUCCESSFUL)
414    return sc;
415
416  uart->sending = 0;
417  /* Enable Receiver and transmitter and Turn on RX interrupts */
418  uart->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE |
419                      LEON_REG_UART_CTRL_RI;
420#else
421  /* Initialize UART on opening */
422  uart->regs->ctrl |= LEON_REG_UART_CTRL_RE | LEON_REG_UART_CTRL_TE;
423#endif
424  uart->regs->status = 0;
425
426  return RTEMS_SUCCESSFUL;
427}
428
429rtems_device_driver console_close(
430  rtems_device_major_number major,
431  rtems_device_minor_number minor,
432  void                    * arg
433)
434{
435#if CONSOLE_USE_INTERRUPTS
436  struct apbuart_priv *uart;
437
438  if (minor == 0)
439    uart = &apbuarts[syscon_uart_index];
440  else
441    uart = &apbuarts[minor - 1];
442
443  /* Turn off RX interrupts */
444  uart->regs->ctrl &= ~(LEON_REG_UART_CTRL_RI);
445
446  /**** Flush device ****/
447  while (uart->sending) {
448    /* Wait until all data has been sent */
449  }
450
451  /* uninstall ISR */
452  rtems_interrupt_handler_remove(uart->irq, console_isr, uart);
453#endif
454  return rtems_termios_close(arg);
455}
456
457rtems_device_driver console_read(
458  rtems_device_major_number major,
459  rtems_device_minor_number minor,
460  void                    * arg
461)
462{
463  return rtems_termios_read(arg);
464}
465
466rtems_device_driver console_write(
467  rtems_device_major_number major,
468  rtems_device_minor_number minor,
469  void                    * arg
470)
471{
472  return rtems_termios_write(arg);
473}
474
475rtems_device_driver console_control(
476  rtems_device_major_number major,
477  rtems_device_minor_number minor,
478  void                    * arg
479)
480{
481  return rtems_termios_ioctl(arg);
482}
483
Note: See TracBrowser for help on using the repository browser.