source: rtems/c/src/lib/libbsp/sparc/erc32/console/erc32_console.c @ 5180f7cb

4.10
Last change on this file since 5180f7cb was 5180f7cb, checked in by Joel Sherrill <joel.sherrill@…>, on 03/03/11 at 14:03:48

2011-03-03 Joel Sherrill <joel.sherrilL@…>

PR 1750/bsps

  • console/erc32_console.c: The new console driver did not support polled mode. It also had a bug in which it could lose a transmitter interrupt.
  • Property mode set to 100644
File size: 8.3 KB
Line 
1/**
2 * @file
3 *
4 * @brief Driver for serial ports on the ERC32.
5 */
6
7/*
8 * Copyright (c) 2010 Tiemen Schut <T.Schut@sron.nl>
9 *
10 * The license and distribution terms for this file may be
11 * found in the file LICENSE in this distribution or at
12 * http://www.rtems.com/license/LICENSE.
13 *
14 * $Id$
15 */
16
17#include <unistd.h>
18#include <termios.h>
19#include <stdlib.h>
20
21#include <rtems.h>
22#include <rtems/libio.h>
23#include <rtems/console.h>
24#include <rtems/termiostypes.h>
25
26#include <libchip/serial.h>
27#include <libchip/sersupp.h>
28
29#include <bsp.h>
30#include <bspopts.h>
31
32#define CONSOLE_BUF_SIZE (16)
33
34#define CONSOLE_UART_A_TRAP  ERC32_TRAP_TYPE(ERC32_INTERRUPT_UART_A_RX_TX)
35#define CONSOLE_UART_B_TRAP  ERC32_TRAP_TYPE(ERC32_INTERRUPT_UART_B_RX_TX)
36
37static uint8_t erc32_console_get_register(uint32_t addr, uint8_t i)
38{
39  volatile uint32_t *reg = (volatile uint32_t *)addr;
40  return (uint8_t) reg [i];
41}
42
43static void erc32_console_set_register(uint32_t addr, uint8_t i, uint8_t val)
44{
45  volatile uint32_t *reg = (volatile uint32_t *)addr;
46  reg [i] = val;
47}
48
49static int erc32_console_first_open(int major, int minor, void *arg);
50
51#if (CONSOLE_USE_INTERRUPTS)
52  static ssize_t erc32_console_write_support_int(
53    int minor, const char *buf, size_t len);
54#else
55  int console_inbyte_nonblocking( int port );
56  static ssize_t erc32_console_write_support_polled(
57      int minor, const char *buf, size_t len);
58#endif
59static void erc32_console_initialize(int minor);
60
61rtems_device_minor_number Console_Port_Minor = 0;
62
63#if (CONSOLE_USE_INTERRUPTS)
64  console_fns erc32_fns = {
65    libchip_serial_default_probe,           /* deviceProbe */
66    erc32_console_first_open,               /* deviceFirstOpen */
67    NULL,                                   /* deviceLastClose */
68    NULL,                                   /* deviceRead */
69    erc32_console_write_support_int,        /* deviceWrite */
70    erc32_console_initialize,               /* deviceInitialize */
71    NULL,                                   /* deviceWritePolled */
72    NULL,                                   /* deviceSetAttributes */
73    TERMIOS_IRQ_DRIVEN                      /* deviceOutputUsesInterrupts */
74  };
75#else
76  console_fns erc32_fns = {
77    libchip_serial_default_probe,           /* deviceProbe */
78    erc32_console_first_open,               /* deviceFirstOpen */
79    NULL,                                   /* deviceLastClose */
80    console_inbyte_nonblocking,             /* deviceRead */
81    erc32_console_write_support_polled,     /* deviceWrite */
82    erc32_console_initialize,               /* deviceInitialize */
83    NULL,                                   /* deviceWritePolled */
84    NULL,                                   /* deviceSetAttributes */
85    TERMIOS_POLLED                          /* deviceOutputUsesInterrupts */
86  };
87#endif
88
89console_tbl Console_Port_Tbl [] = {
90  {
91    .sDeviceName = "/dev/console_a",
92    .deviceType = SERIAL_CUSTOM,
93    .pDeviceFns = &erc32_fns,
94    .deviceProbe = NULL,
95    .pDeviceFlow = NULL,
96    .ulMargin = 16,
97    .ulHysteresis = 8,
98    .pDeviceParams = (void *) -1,  /* could be baud rate */
99    .ulCtrlPort1 = 0,
100    .ulCtrlPort2 = 0,
101    .ulDataPort = 0,
102    .getRegister = erc32_console_get_register,
103    .setRegister = erc32_console_set_register,
104    .getData = NULL,
105    .setData = NULL,
106    .ulClock = 16,
107    .ulIntVector = ERC32_INTERRUPT_UART_A_RX_TX
108  },
109  {
110    .sDeviceName = "/dev/console_b",
111    .deviceType = SERIAL_CUSTOM,
112    .pDeviceFns = &erc32_fns,
113    .deviceProbe = NULL,
114    .pDeviceFlow = NULL,
115    .ulMargin = 16,
116    .ulHysteresis = 8,
117    .pDeviceParams = (void *) -1,  /* could be baud rate */
118    .ulCtrlPort1 = 0,
119    .ulCtrlPort2 = 0,
120    .ulDataPort = 0,
121    .getRegister = erc32_console_get_register,
122    .setRegister = erc32_console_set_register,
123    .getData = NULL,
124    .setData = NULL,
125    .ulClock = 16,
126    .ulIntVector = ERC32_INTERRUPT_UART_B_RX_TX
127  },
128};
129
130/* always exactly two uarts for erc32 */
131#define ERC32_UART_COUNT (2)
132
133unsigned long Console_Port_Count = ERC32_UART_COUNT;
134
135console_data Console_Port_Data [ERC32_UART_COUNT];
136
137static int erc32_console_first_open(int major, int minor, void *arg)
138{
139  /* Check minor number */
140  if (minor < 0 || minor > 1) {
141    return -1;
142  }
143 
144  rtems_libio_open_close_args_t *oca = arg;
145  struct rtems_termios_tty *tty = oca->iop->data1;
146  console_tbl *ct = &Console_Port_Tbl [minor];
147  console_data *cd = &Console_Port_Data [minor];
148 
149  cd->termios_data = tty;
150  rtems_termios_set_initial_baud(tty, (int32_t)ct->pDeviceParams);
151 
152  return 0;
153}
154
155#if (CONSOLE_USE_INTERRUPTS)
156static ssize_t erc32_console_write_support_int(int minor, const char *buf, size_t len)
157{
158  console_data *cd = &Console_Port_Data[minor];
159  int k = 0;
160
161  if (minor == 0) { /* uart a */
162    for (k = 0;
163         k < len && (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEA); k ++) {
164      ERC32_MEC.UART_Channel_A = (unsigned char)buf[k];
165    }
166    ERC32_Force_interrupt(ERC32_INTERRUPT_UART_A_RX_TX);
167  } else { /* uart b */
168    for (k = 0;
169         k < len && (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEB); k ++) {
170      ERC32_MEC.UART_Channel_B = (unsigned char)buf[k];
171    }
172    ERC32_Force_interrupt(ERC32_INTERRUPT_UART_B_RX_TX);
173  }
174 
175  if (len > 0) {
176    cd->pDeviceContext = (void *)k;
177    cd->bActive = true;
178  }
179 
180  return 0;
181}
182
183static void erc32_console_isr_a(
184  rtems_vector_number vector
185)
186{
187  console_data *cd = &Console_Port_Data[0];
188
189  /* check for error */
190  if (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_ERRA) {
191    ERC32_MEC.UART_Status = ERC32_MEC_UART_STATUS_CLRA;
192    ERC32_MEC.Control = ERC32_MEC.Control;
193  }
194
195  do {
196    int chars_to_dequeue = (int)cd->pDeviceContext;
197    int rv = 0;
198    int i = 0;
199    char buf[CONSOLE_BUF_SIZE];
200       
201    /* enqueue received chars */
202    while (i < CONSOLE_BUF_SIZE) {
203      if (!(ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_DRA))
204        break;
205      buf[i] = ERC32_MEC.UART_Channel_A;
206      ++i;
207    }
208    if ( i )
209      rtems_termios_enqueue_raw_characters(cd->termios_data, buf, i);
210
211    /* dequeue transmitted chars */
212    if (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEA) {
213      rv = rtems_termios_dequeue_characters(
214         cd->termios_data, chars_to_dequeue);
215      if ( !rv ) {
216        cd->pDeviceContext = 0;
217        cd->bActive = false;
218      }
219      ERC32_Clear_interrupt (ERC32_INTERRUPT_UART_A_RX_TX);
220    }
221  } while (ERC32_Is_interrupt_pending (ERC32_INTERRUPT_UART_A_RX_TX));
222}
223
224static void erc32_console_isr_b(
225  rtems_vector_number vector
226)
227{
228  console_data *cd = &Console_Port_Data[1];
229
230  /* check for error */
231  if (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_ERRB) {
232      ERC32_MEC.UART_Status = ERC32_MEC_UART_STATUS_CLRB;
233      ERC32_MEC.Control = ERC32_MEC.Control;
234  }
235
236  do {
237    int chars_to_dequeue = (int)cd->pDeviceContext;
238    int rv = 0;
239    int i = 0;
240    char buf[CONSOLE_BUF_SIZE];
241       
242    /* enqueue received chars */
243    while (i < CONSOLE_BUF_SIZE) {
244      if (!(ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_DRB))
245        break;
246      buf[i] = ERC32_MEC.UART_Channel_B;
247      ++i;
248    }
249    if ( i )
250      rtems_termios_enqueue_raw_characters(cd->termios_data, buf, i);
251
252    /* dequeue transmitted chars */
253    if (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEB) {
254      rv = rtems_termios_dequeue_characters(
255         cd->termios_data, chars_to_dequeue);
256      if ( !rv ) {
257        cd->pDeviceContext = 0;
258        cd->bActive = false;
259      }
260      ERC32_Clear_interrupt (ERC32_INTERRUPT_UART_B_RX_TX);
261    }
262  } while (ERC32_Is_interrupt_pending (ERC32_INTERRUPT_UART_B_RX_TX));
263}
264#else
265
266extern void console_outbyte_polled( int  port, unsigned char ch );
267
268static ssize_t erc32_console_write_support_polled(
269  int         minor,
270  const char *buf,
271  size_t      len
272)
273{
274  int nwrite = 0;
275
276  while (nwrite < len) {
277    console_outbyte_polled( minor, *buf++ );
278    nwrite++;
279  }
280  return nwrite;
281}
282
283#endif
284
285
286/*
287 *  Console Device Driver Entry Points
288 *
289 */
290
291static void erc32_console_initialize(
292    int minor
293)
294{
295  console_data *cd = &Console_Port_Data [minor];
296
297  cd->bActive = false;
298  cd->pDeviceContext = 0;
299
300 /*
301  * Initialize the Termios infrastructure.  If Termios has already
302  * been initialized by another device driver, then this call will
303  * have no effect.
304  */
305  rtems_termios_initialize();
306
307 /*
308  *  Initialize Hardware
309  */
310  #if (CONSOLE_USE_INTERRUPTS)
311    set_vector(erc32_console_isr_a, CONSOLE_UART_A_TRAP, 1);
312    set_vector(erc32_console_isr_b, CONSOLE_UART_B_TRAP, 1);
313  #endif
314}
Note: See TracBrowser for help on using the repository browser.