source: rtems/c/src/lib/libbsp/arm/lpc32xx/console/hsu.c @ 1c6926c1

5
Last change on this file since 1c6926c1 was 1c6926c1, checked in by Kevin Kirspel <kevin-kirspel@…>, on 03/21/17 at 19:39:48

termios: Synchronize with latest FreeBSD headers

Adding modified FreeBSD headers to synchronize RTEMS termios with
FreeBSD. Modify termios to support dedicated input and output baud for
termios structure. Updated BSPs to use dedicated input and output baud
in termios structure. Updated tools to use dedicated input and output
baud in termios structure. Updated termios testsuites to use dedicated
input and output baud in termios structure.

Close #2897.

  • Property mode set to 100644
File size: 4.7 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup arm_lpc32xx
5 *
6 * @brief High speed UART driver (14-clock).
7 */
8
9/*
10 * Copyright (c) 2010-2014 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Dornierstr. 4
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
17 *
18 * The license and distribution terms for this file may be
19 * found in the file LICENSE in this distribution or at
20 * http://www.rtems.org/license/LICENSE.
21 */
22
23#include <bsp.h>
24#include <bsp/lpc32xx.h>
25#include <bsp/irq.h>
26#include <bsp/hsu.h>
27
28#define HSU_FIFO_SIZE 64
29
30#define HSU_LEVEL_RX_MASK 0xffU
31#define HSU_LEVEL_TX_MASK 0xff00U
32#define HSU_LEVEL_TX_SHIFT 8
33
34#define HSU_RX_DATA_MASK 0xffU
35#define HSU_RX_EMPTY (1U << 8)
36#define HSU_RX_ERROR (1U << 9)
37#define HSU_RX_BREAK (1U << 10)
38
39#define HSU_IIR_TX (1U << 0)
40#define HSU_IIR_RX_TRIG (1U << 1)
41#define HSU_IIR_RX_TIMEOUT (1U << 2)
42
43#define HSU_CTRL_INTR_DISABLED 0x1280fU
44#define HSU_CTRL_RX_INTR_ENABLED 0x1284fU
45#define HSU_CTRL_RX_AND_TX_INTR_ENABLED 0x1286fU
46
47/* We are interested in RX timeout, RX trigger and TX trigger interrupts */
48#define HSU_IIR_MASK 0x7U
49
50bool lpc32xx_hsu_probe(rtems_termios_device_context *base)
51{
52  lpc32xx_hsu_context *ctx = (lpc32xx_hsu_context *) base;
53  volatile lpc32xx_hsu *hsu = ctx->hsu;
54
55  hsu->ctrl = HSU_CTRL_INTR_DISABLED;
56
57  /* Drain FIFOs */
58  while (hsu->level != 0) {
59    hsu->fifo;
60  }
61
62  return true;
63}
64
65static void lpc32xx_hsu_interrupt_handler(void *arg)
66{
67  rtems_termios_tty *tty = arg;
68  lpc32xx_hsu_context *ctx = rtems_termios_get_device_context(tty);
69  volatile lpc32xx_hsu *hsu = ctx->hsu;
70
71  /* Iterate until no more interrupts are pending */
72  do {
73    int rv = 0;
74    int i = 0;
75    char buf [HSU_FIFO_SIZE];
76
77    /* Enqueue received characters */
78    while (i < HSU_FIFO_SIZE) {
79      uint32_t in = hsu->fifo;
80
81      if ((in & HSU_RX_EMPTY) == 0) {
82        if ((in & HSU_RX_BREAK) == 0) {
83          buf [i] = in & HSU_RX_DATA_MASK;
84          ++i;
85        }
86      } else {
87        break;
88      }
89    }
90    rtems_termios_enqueue_raw_characters(tty, buf, i);
91
92    /* Dequeue transmitted characters */
93    rv = rtems_termios_dequeue_characters(tty, (int) ctx->chars_in_transmission);
94    if (rv == 0) {
95      /* Nothing to transmit */
96    }
97  } while ((hsu->iir & HSU_IIR_MASK) != 0);
98}
99
100static bool lpc32xx_hsu_first_open(
101  struct rtems_termios_tty *tty,
102  rtems_termios_device_context *base,
103  struct termios *term,
104  rtems_libio_open_close_args_t *args
105)
106{
107  lpc32xx_hsu_context *ctx = (lpc32xx_hsu_context *) base;
108  volatile lpc32xx_hsu *hsu = ctx->hsu;
109  rtems_status_code sc;
110  bool ok;
111
112  sc = rtems_interrupt_handler_install(
113    ctx->irq,
114    "HSU",
115    RTEMS_INTERRUPT_UNIQUE,
116    lpc32xx_hsu_interrupt_handler,
117    tty
118  );
119  ok = sc == RTEMS_SUCCESSFUL;
120
121  if (ok) {
122    rtems_termios_set_initial_baud(tty, ctx->initial_baud);
123    hsu->ctrl = HSU_CTRL_RX_INTR_ENABLED;
124  }
125
126  return ok;
127}
128
129static void lpc32xx_hsu_last_close(
130  struct rtems_termios_tty *tty,
131  rtems_termios_device_context *base,
132  rtems_libio_open_close_args_t *args
133)
134{
135  lpc32xx_hsu_context *ctx = (lpc32xx_hsu_context *) base;
136  volatile lpc32xx_hsu *hsu = ctx->hsu;
137
138  hsu->ctrl = HSU_CTRL_INTR_DISABLED;
139
140  rtems_interrupt_handler_remove(
141    ctx->irq,
142    lpc32xx_hsu_interrupt_handler,
143    tty
144  );
145}
146
147static void lpc32xx_hsu_write(
148  rtems_termios_device_context *base,
149  const char *buf,
150  size_t len
151)
152{
153  lpc32xx_hsu_context *ctx = (lpc32xx_hsu_context *) base;
154  volatile lpc32xx_hsu *hsu = ctx->hsu;
155  size_t tx_level = (hsu->level & HSU_LEVEL_TX_MASK) >> HSU_LEVEL_TX_SHIFT;
156  size_t tx_free = HSU_FIFO_SIZE - tx_level;
157  size_t i = 0;
158  size_t out = len > tx_free ? tx_free : len;
159
160  for (i = 0; i < out; ++i) {
161    hsu->fifo = buf [i];
162  }
163
164  ctx->chars_in_transmission = out;
165
166  if (len > 0) {
167    hsu->ctrl = HSU_CTRL_RX_AND_TX_INTR_ENABLED;
168  } else {
169    hsu->ctrl = HSU_CTRL_RX_INTR_ENABLED;
170    hsu->iir = HSU_IIR_TX;
171  }
172}
173
174static bool lpc32xx_hsu_set_attributes(
175  rtems_termios_device_context *base,
176  const struct termios *term
177)
178{
179  lpc32xx_hsu_context *ctx = (lpc32xx_hsu_context *) base;
180  volatile lpc32xx_hsu *hsu = ctx->hsu;
181  int baud_flags = term->c_ospeed;
182
183  if (baud_flags != 0) {
184    int32_t baud = rtems_termios_baud_to_number(baud_flags);
185
186    if (baud > 0) {
187      uint32_t baud_divisor = 14 * (uint32_t) baud;
188      uint32_t rate = LPC32XX_PERIPH_CLK / baud_divisor;
189      uint32_t remainder = LPC32XX_PERIPH_CLK - rate * baud_divisor;
190
191      if (2 * remainder >= baud_divisor) {
192        ++rate;
193      }
194
195      hsu->rate = rate - 1;
196    }
197  }
198
199  return true;
200}
201
202const rtems_termios_device_handler lpc32xx_hsu_fns = {
203  .first_open = lpc32xx_hsu_first_open,
204  .last_close = lpc32xx_hsu_last_close,
205  .write = lpc32xx_hsu_write,
206  .set_attributes = lpc32xx_hsu_set_attributes,
207  .mode = TERMIOS_IRQ_DRIVEN
208};
Note: See TracBrowser for help on using the repository browser.