source: rtems/c/src/lib/libbsp/sparc/shared/uart/apbuart_termios.c @ 5823bae8

4.115
Last change on this file since 5823bae8 was 5823bae8, checked in by Daniel Hellstrom <daniel@…>, on 02/27/15 at 13:03:15

LEON: move driver headers to bsp/ directory

  • Property mode set to 100644
File size: 7.4 KB
Line 
1/*
2 *  COPYRIGHT (c) 1989-1998.
3 *  On-Line Applications Research Corporation (OAR).
4 *
5 *  Modified for LEON3 BSP.
6 *  COPYRIGHT (c) 2004.
7 *  Gaisler Research.
8 *
9 *  The license and distribution terms for this file may be
10 *  found in the file LICENSE in this distribution or at
11 *  http://www.rtems.org/license/LICENSE.
12 */
13
14#include <bsp/apbuart_termios.h>
15#include <bsp/apbuart.h>
16#include <bsp.h>
17
18static void apbuart_isr(void *arg)
19{
20  rtems_termios_tty *tty = arg;
21  struct apbuart_context *uart = rtems_termios_get_device_context(tty);
22  unsigned int status;
23  char data;
24
25  /* Get all received characters */
26  while ((status=uart->regs->status) & APBUART_STATUS_DR) {
27    /* Data has arrived, get new data */
28    data = uart->regs->data;
29
30    /* Tell termios layer about new character */
31    rtems_termios_enqueue_raw_characters(tty, &data, 1);
32  }
33
34  if (
35    (status & APBUART_STATUS_TE)
36      && (uart->regs->ctrl & APBUART_CTRL_TI) != 0
37  ) {
38    /* write_interrupt will get called from this function */
39    rtems_termios_dequeue_characters(tty, 1);
40  }
41}
42
43static void apbuart_write_support(
44  rtems_termios_device_context *base,
45  const char *buf,
46  size_t len
47)
48{
49  struct apbuart_context *uart = (struct apbuart_context *) base;
50  int sending;
51
52  if (len > 0) {
53    /* Enable TX interrupt (interrupt is edge-triggered) */
54    uart->regs->ctrl |= APBUART_CTRL_TI;
55
56    /* start UART TX, this will result in an interrupt when done */
57    uart->regs->data = *buf;
58
59    sending = 1;
60  } else {
61    /* No more to send, disable TX interrupts */
62    uart->regs->ctrl &= ~APBUART_CTRL_TI;
63
64    /* Tell close that we sent everything */
65    sending = 0;
66  }
67
68  uart->sending = sending;
69}
70
71static void apbuart_write_polled(
72  rtems_termios_device_context *base,
73  const char *buf,
74  size_t len
75)
76{
77  struct apbuart_context *uart = (struct apbuart_context *) base;
78  size_t nwrite = 0;
79
80  while (nwrite < len) {
81    apbuart_outbyte_polled(uart->regs, *buf++, 0, 0);
82    nwrite++;
83  }
84}
85
86static int apbuart_poll_read(rtems_termios_device_context *base)
87{
88  struct apbuart_context *uart = (struct apbuart_context *) base;
89
90  return apbuart_inbyte_nonblocking(uart->regs);
91}
92
93static bool apbuart_set_attributes(
94  rtems_termios_device_context *base,
95  const struct termios *t
96)
97{
98  struct apbuart_context *uart = (struct apbuart_context *) base;
99  rtems_interrupt_lock_context lock_context;
100  unsigned int scaler;
101  unsigned int ctrl;
102  int baud;
103
104  switch (t->c_cflag & CSIZE) {
105    default:
106    case CS5:
107    case CS6:
108    case CS7:
109      /* Hardware doesn't support other than CS8 */
110      return false;
111    case CS8:
112      break;
113  }
114
115  rtems_termios_device_lock_acquire(base, &lock_context);
116
117  /* Read out current value */
118  ctrl = uart->regs->ctrl;
119
120  switch (t->c_cflag & (PARENB|PARODD)) {
121    case (PARENB|PARODD):
122      /* Odd parity */
123      ctrl |= APBUART_CTRL_PE|APBUART_CTRL_PS;
124      break;
125
126    case PARENB:
127      /* Even parity */
128      ctrl &= ~APBUART_CTRL_PS;
129      ctrl |= APBUART_CTRL_PE;
130      break;
131
132    default:
133    case 0:
134    case PARODD:
135      /* No Parity */
136      ctrl &= ~(APBUART_CTRL_PS|APBUART_CTRL_PE);
137  }
138
139  if (!(t->c_cflag & CLOCAL)) {
140    ctrl |= APBUART_CTRL_FL;
141  } else {
142    ctrl &= ~APBUART_CTRL_FL;
143  }
144
145  /* Update new settings */
146  uart->regs->ctrl = ctrl;
147
148  rtems_termios_device_lock_release(base, &lock_context);
149
150  /* Baud rate */
151  baud = rtems_termios_baud_to_number(t->c_cflag);
152  if (baud > 0) {
153    /* Calculate Baud rate generator "scaler" number */
154    scaler = (((uart->freq_hz * 10) / (baud * 8)) - 5) / 10;
155
156    /* Set new baud rate by setting scaler */
157    uart->regs->scaler = scaler;
158  }
159
160  return true;
161}
162
163static void apbuart_set_best_baud(
164  const struct apbuart_context *uart,
165  struct termios *term
166)
167{
168  uint32_t baud = (uart->freq_hz * 10) / ((uart->regs->scaler * 10 + 5) * 8);
169
170  rtems_termios_set_best_baud(term, baud);
171}
172
173static bool apbuart_first_open_polled(
174  rtems_termios_tty *tty,
175  rtems_termios_device_context *base,
176  struct termios *term,
177  rtems_libio_open_close_args_t *args
178)
179{
180  struct apbuart_context *uart = (struct apbuart_context *) base;
181
182  apbuart_set_best_baud(uart, term);
183
184  /* Initialize UART on opening */
185  uart->regs->ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE;
186  uart->regs->status = 0;
187
188  return true;
189}
190
191static bool apbuart_first_open_interrupt(
192  rtems_termios_tty *tty,
193  rtems_termios_device_context *base,
194  struct termios *term,
195  rtems_libio_open_close_args_t *args
196)
197{
198  struct apbuart_context *uart = (struct apbuart_context *) base;
199  rtems_status_code sc;
200
201  apbuart_set_best_baud(uart, term);
202
203  /* Register Interrupt handler */
204  sc = rtems_interrupt_handler_install(uart->irq, "console",
205                                       RTEMS_INTERRUPT_SHARED,
206                                       apbuart_isr,
207                                       tty);
208  if (sc != RTEMS_SUCCESSFUL)
209    return false;
210
211  uart->sending = 0;
212  /* Enable Receiver and transmitter and Turn on RX interrupts */
213  uart->regs->ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE |
214                      APBUART_CTRL_RI;
215  /* Initialize UART on opening */
216  uart->regs->ctrl |= APBUART_CTRL_RE | APBUART_CTRL_TE;
217  uart->regs->status = 0;
218
219  return true;
220}
221
222static void apbuart_last_close_interrupt(
223  rtems_termios_tty *tty,
224  rtems_termios_device_context *base,
225  rtems_libio_open_close_args_t *args
226)
227{
228  struct apbuart_context *uart = (struct apbuart_context *) base;
229  rtems_interrupt_lock_context lock_context;
230
231  /* Turn off RX interrupts */
232  rtems_termios_device_lock_acquire(base, &lock_context);
233  uart->regs->ctrl &= ~(APBUART_CTRL_RI);
234  rtems_termios_device_lock_release(base, &lock_context);
235
236  /**** Flush device ****/
237  while (uart->sending) {
238    /* Wait until all data has been sent */
239  }
240
241  /* uninstall ISR */
242  rtems_interrupt_handler_remove(uart->irq, apbuart_isr, tty);
243}
244
245/*
246 *  apbuart_outbyte_polled
247 *
248 *  This routine transmits a character using polling.
249 */
250void apbuart_outbyte_polled(
251  struct apbuart_regs *regs,
252  unsigned char ch,
253  int do_cr_on_newline,
254  int wait_sent
255)
256{
257send:
258  while ( (regs->status & APBUART_STATUS_TE) == 0 ) {
259    /* Lower bus utilization while waiting for UART */
260    __asm__ volatile ("nop"::); __asm__ volatile ("nop"::);
261    __asm__ volatile ("nop"::); __asm__ volatile ("nop"::);
262    __asm__ volatile ("nop"::); __asm__ volatile ("nop"::);
263    __asm__ volatile ("nop"::); __asm__ volatile ("nop"::);
264  }
265
266  if ((ch == '\n') && do_cr_on_newline) {
267    regs->data = (unsigned int) '\r';
268    do_cr_on_newline = 0;
269    goto send;
270  }
271  regs->data = (unsigned int) ch;
272
273  /* Wait until the character has been sent? */
274  if (wait_sent) {
275    while ((regs->status & APBUART_STATUS_TE) == 0)
276      ;
277  }
278}
279
280/*
281 *  apbuart_inbyte_nonblocking
282 *
283 *  This routine polls for a character.
284 */
285int apbuart_inbyte_nonblocking(struct apbuart_regs *regs)
286{
287  /* Clear errors */
288  if (regs->status & APBUART_STATUS_ERR)
289    regs->status = ~APBUART_STATUS_ERR;
290
291  if ((regs->status & APBUART_STATUS_DR) == 0)
292    return -1;
293  else
294    return (int) regs->data;
295}
296
297const rtems_termios_device_handler apbuart_handler_interrupt = {
298  .first_open = apbuart_first_open_interrupt,
299  .last_close = apbuart_last_close_interrupt,
300  .write = apbuart_write_support,
301  .set_attributes = apbuart_set_attributes,
302  .mode = TERMIOS_IRQ_DRIVEN
303};
304
305const rtems_termios_device_handler apbuart_handler_polled = {
306  .first_open = apbuart_first_open_polled,
307  .poll_read = apbuart_poll_read,
308  .write = apbuart_write_polled,
309  .set_attributes = apbuart_set_attributes,
310  .mode = TERMIOS_POLLED
311};
Note: See TracBrowser for help on using the repository browser.