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

4.115
Last change on this file since bf00d1d was bf00d1d, checked in by Joel Sherrill <joel.sherrill@…>, on 02/28/11 at 20:14:29

2011-02-28 Joel Sherrill <joel.sherrill@…>

  • console/erc32_console.c: Add polled support. Tinker with interrupt handler to not dequeue characters unless TX is empty.
  • Property mode set to 100644
File size: 8.8 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)
52static ssize_t erc32_console_write_support_int(
53    int minor, const char *buf, size_t len);
54#else
55int console_inbyte_nonblocking( int port );
56static 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; k < len && (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEA); k ++) {
163            ERC32_MEC.UART_Channel_A = (unsigned char)buf[k];
164        }
165        ERC32_Force_interrupt(ERC32_INTERRUPT_UART_A_RX_TX);
166    } else { /* uart b */
167        for (k = 0; k < len && (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEB); k ++) {
168            ERC32_MEC.UART_Channel_B = (unsigned char)buf[k];
169        }
170        ERC32_Force_interrupt(ERC32_INTERRUPT_UART_B_RX_TX);
171    }
172   
173    if (len > 0) {
174        cd->pDeviceContext = (void *)k;
175        cd->bActive = true;
176    }
177   
178    return 0;
179}
180
181static void erc32_console_isr_a(
182    rtems_vector_number vector
183)
184{
185    console_data *cd = &Console_Port_Data[0];
186
187    /* check for error */
188    if (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_ERRA) {
189        ERC32_MEC.UART_Status = ERC32_MEC_UART_STATUS_CLRA;
190        ERC32_MEC.Control = ERC32_MEC.Control;
191    }
192
193    do {
194        int chars_to_dequeue = (int)cd->pDeviceContext;
195        int rv = 0;
196        int i = 0;
197        char buf[CONSOLE_BUF_SIZE];
198       
199        /* enqueue received chars */
200        while (i < CONSOLE_BUF_SIZE) {
201            if (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_DRA) {
202                buf[i] = ERC32_MEC.UART_Channel_A;
203                ++i;
204            } else {
205                break;
206            }
207        }
208        rtems_termios_enqueue_raw_characters(cd->termios_data, buf, i);
209
210        /* dequeue transmitted chars */
211        cd->pDeviceContext = 0;
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->bActive = false;
217            ERC32_Clear_interrupt (ERC32_INTERRUPT_UART_A_RX_TX);
218          }
219        }
220    } while (ERC32_Is_interrupt_pending (ERC32_INTERRUPT_UART_A_RX_TX));
221}
222
223static void erc32_console_isr_b(
224    rtems_vector_number vector
225)
226{
227    console_data *cd = &Console_Port_Data[1];
228
229    /* check for error */
230    if (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_ERRB) {
231        ERC32_MEC.UART_Status = ERC32_MEC_UART_STATUS_CLRB;
232        ERC32_MEC.Control = ERC32_MEC.Control;
233    }
234
235    do {
236        int chars_to_dequeue = (int)cd->pDeviceContext;
237        int rv = 0;
238        int i = 0;
239        char buf[CONSOLE_BUF_SIZE];
240       
241        /* enqueue received chars */
242        while (i < CONSOLE_BUF_SIZE) {
243            if (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_DRB) {
244                buf[i] = ERC32_MEC.UART_Channel_B;
245                ++i;
246            } else {
247                break;
248            }
249        }
250        rtems_termios_enqueue_raw_characters(cd->termios_data, buf, i);
251
252        /* dequeue transmitted chars */
253        cd->pDeviceContext = 0;
254        if (ERC32_MEC.UART_Status & ERC32_MEC_UART_STATUS_THEB) {
255          rv = rtems_termios_dequeue_characters(
256             cd->termios_data, chars_to_dequeue);
257          if ( !rv ) {
258            cd->bActive = false;
259            ERC32_Clear_interrupt (ERC32_INTERRUPT_UART_B_RX_TX);
260          }
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.