OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [devs/] [serial/] [arm/] [aaed2000/] [v2_0/] [src/] [aaed2000_serial.c] - Blame information for rev 631

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      io/serial/arm/aaed2000_serial.c
4
//
5
//      Agilent AAED2000 Serial I/O Interface Module (interrupt driven)
6
//
7
//==========================================================================
8
//####ECOSGPLCOPYRIGHTBEGIN####
9
// -------------------------------------------
10
// This file is part of eCos, the Embedded Configurable Operating System.
11
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
12
//
13
// eCos is free software; you can redistribute it and/or modify it under
14
// the terms of the GNU General Public License as published by the Free
15
// Software Foundation; either version 2 or (at your option) any later version.
16
//
17
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
18
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
19
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
20
// for more details.
21
//
22
// You should have received a copy of the GNU General Public License along
23
// with eCos; if not, write to the Free Software Foundation, Inc.,
24
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
25
//
26
// As a special exception, if other files instantiate templates or use macros
27
// or inline functions from this file, or you compile this file and link it
28
// with other works to produce a work based on this file, this file does not
29
// by itself cause the resulting work to be covered by the GNU General Public
30
// License. However the source code for this file must still be made available
31
// in accordance with section (3) of the GNU General Public License.
32
//
33
// This exception does not invalidate any other reasons why a work based on
34
// this file might be covered by the GNU General Public License.
35
//
36
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
37
// at http://sources.redhat.com/ecos/ecos-license/
38
// -------------------------------------------
39
//####ECOSGPLCOPYRIGHTEND####
40
//==========================================================================
41
//#####DESCRIPTIONBEGIN####
42
//
43
// Author(s):   gthomas, jskov
44
// Contributors:gthomas, jskov
45
// Date:        2001-11-12
46
// Purpose:     AAED2000 Serial I/O module (interrupt driven version)
47
// Description: 
48
//
49
//####DESCRIPTIONEND####
50
//
51
//==========================================================================
52
 
53
#include <pkgconf/system.h>
54
#include <pkgconf/io_serial.h>
55
#include <pkgconf/io.h>
56
#include <cyg/io/io.h>
57
#include <cyg/hal/hal_intr.h>           // interrupt
58
#include <cyg/hal/hal_io.h>             // register base
59
#include <cyg/io/devtab.h>
60
#include <cyg/io/serial.h>
61
#include <cyg/infra/diag.h>
62
 
63
#include "aaed2000_serial.h"
64
 
65
typedef struct aaed2000_serial_info {
66
    CYG_ADDRWORD   base;
67
    CYG_WORD       int_num;
68
    cyg_interrupt  serial_interrupt;
69
    cyg_handle_t   serial_interrupt_handle;
70
} aaed2000_serial_info;
71
 
72
static bool aaed2000_serial_init(struct cyg_devtab_entry *tab);
73
static bool aaed2000_serial_putc(serial_channel *chan, unsigned char c);
74
static Cyg_ErrNo aaed2000_serial_lookup(struct cyg_devtab_entry **tab,
75
                                   struct cyg_devtab_entry *sub_tab,
76
                                   const char *name);
77
static unsigned char aaed2000_serial_getc(serial_channel *chan);
78
static Cyg_ErrNo aaed2000_serial_set_config(serial_channel *chan,
79
                                       cyg_uint32 key,
80
                                       const void *xbuf, cyg_uint32 *len);
81
static void aaed2000_serial_start_xmit(serial_channel *chan);
82
static void aaed2000_serial_stop_xmit(serial_channel *chan);
83
 
84
static cyg_uint32 aaed2000_serial_ISR(cyg_vector_t vector, cyg_addrword_t data);
85
static void       aaed2000_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data);
86
 
87
static SERIAL_FUNS(aaed2000_serial_funs,
88
                   aaed2000_serial_putc,
89
                   aaed2000_serial_getc,
90
                   aaed2000_serial_set_config,
91
                   aaed2000_serial_start_xmit,
92
                   aaed2000_serial_stop_xmit
93
    );
94
 
95
#ifdef CYGPKG_IO_SERIAL_ARM_AAED2000_SERIAL0
96
static aaed2000_serial_info aaed2000_serial_info0 = {0x80000800,
97
                                                     CYGNUM_HAL_INTERRUPT_UART3INTR};
98
#if CYGNUM_IO_SERIAL_ARM_AAED2000_SERIAL0_BUFSIZE > 0
99
static unsigned char aaed2000_serial_out_buf0[CYGNUM_IO_SERIAL_ARM_AAED2000_SERIAL0_BUFSIZE];
100
static unsigned char aaed2000_serial_in_buf0[CYGNUM_IO_SERIAL_ARM_AAED2000_SERIAL0_BUFSIZE];
101
 
102
static SERIAL_CHANNEL_USING_INTERRUPTS(aaed2000_serial_channel0,
103
                                       aaed2000_serial_funs,
104
                                       aaed2000_serial_info0,
105
                                       CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_AAED2000_SERIAL0_BAUD),
106
                                       CYG_SERIAL_STOP_DEFAULT,
107
                                       CYG_SERIAL_PARITY_DEFAULT,
108
                                       CYG_SERIAL_WORD_LENGTH_DEFAULT,
109
                                       CYG_SERIAL_FLAGS_DEFAULT,
110
                                       &aaed2000_serial_out_buf0[0], sizeof(aaed2000_serial_out_buf0),
111
                                       &aaed2000_serial_in_buf0[0], sizeof(aaed2000_serial_in_buf0)
112
    );
113
#else
114
static SERIAL_CHANNEL(aaed2000_serial_channel0,
115
                      aaed2000_serial_funs,
116
                      aaed2000_serial_info0,
117
                      CYG_SERIAL_BAUD_RATE(CYGNUM_IO_SERIAL_ARM_AAED2000_SERIAL0_BAUD),
118
                      CYG_SERIAL_STOP_DEFAULT,
119
                      CYG_SERIAL_PARITY_DEFAULT,
120
                      CYG_SERIAL_WORD_LENGTH_DEFAULT,
121
                      CYG_SERIAL_FLAGS_DEFAULT
122
    );
123
#endif
124
 
125
DEVTAB_ENTRY(aaed2000_serial_io0,
126
             CYGDAT_IO_SERIAL_ARM_AAED2000_SERIAL0_NAME,
127
             0,                     // Does not depend on a lower level interface
128
             &cyg_io_serial_devio,
129
             aaed2000_serial_init,
130
             aaed2000_serial_lookup,     // Serial driver may need initializing
131
             &aaed2000_serial_channel0
132
    );
133
#endif //  CYGPKG_IO_SERIAL_ARM_AAED2000_SERIAL0
134
 
135
// Internal function to actually configure the hardware to desired baud rate, etc.
136
static bool
137
aaed2000_serial_config_port(serial_channel *chan, cyg_serial_info_t *new_config, bool init)
138
{
139
    aaed2000_serial_info *aaed2000_chan = (aaed2000_serial_info *)chan->dev_priv;
140
    CYG_ADDRWORD base = aaed2000_chan->base;
141
    unsigned short baud_divisor = select_baud[new_config->baud];
142
    cyg_uint32 _lcr, _intm;
143
    if (baud_divisor == 0) return false;
144
 
145
    // Register writes don't take effect till the UART is enabled.
146
    HAL_WRITE_UINT32(base+AAEC_UART_CTRL, AAEC_UART_CTRL_ENAB);
147
 
148
    // Disable port interrupts while changing hardware
149
    HAL_READ_UINT32(base+AAEC_UART_INTM, _intm);
150
    HAL_WRITE_UINT32(base+AAEC_UART_INTM, 0);
151
 
152
    _lcr = select_word_length[new_config->word_length - CYGNUM_SERIAL_WORD_LENGTH_5] |
153
        select_stop_bits[new_config->stop] |
154
        select_parity[new_config->parity];
155
    HAL_WRITE_UINT32(base+AAEC_UART_BAUD, baud_divisor);
156
    if (init) {
157
        _lcr |= AAEC_UART_LCR_FIFO;  // Enable FIFO
158
        if (chan->out_cbuf.len != 0) {
159
            _intm = AAEC_UART_INT_RIS|AAEC_UART_INT_RTIS;
160
        } else {
161
            _intm = 0;
162
        }
163
    }
164
    if (new_config != &chan->config) {
165
        chan->config = *new_config;
166
    }
167
 
168
    // Set line control and (re)enable interrupts
169
    HAL_WRITE_UINT32(base+AAEC_UART_LCR, _lcr);
170
    HAL_WRITE_UINT32(base+AAEC_UART_INTM, _intm);
171
 
172
    return true;
173
}
174
 
175
// Function to initialize the device.  Called at bootstrap time.
176
static bool
177
aaed2000_serial_init(struct cyg_devtab_entry *tab)
178
{
179
    serial_channel *chan = (serial_channel *)tab->priv;
180
    aaed2000_serial_info *aaed2000_chan = (aaed2000_serial_info *)chan->dev_priv;
181
#ifdef CYGDBG_IO_INIT
182
    diag_printf("AAED2000 SERIAL init - dev: 0x%08x.%d\n",
183
                aaed2000_chan->base, aaed2000_chan->int_num);
184
#endif
185
    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
186
    if (chan->out_cbuf.len != 0) {
187
        cyg_drv_interrupt_create(aaed2000_chan->int_num,
188
                                 1,                    // Priority - unused
189
                                 (cyg_addrword_t)chan, //  Data item passed to interrupt handler
190
                                 aaed2000_serial_ISR,
191
                                 aaed2000_serial_DSR,
192
                                 &aaed2000_chan->serial_interrupt_handle,
193
                                 &aaed2000_chan->serial_interrupt);
194
        cyg_drv_interrupt_attach(aaed2000_chan->serial_interrupt_handle);
195
        cyg_drv_interrupt_unmask(aaed2000_chan->int_num);
196
    }
197
    aaed2000_serial_config_port(chan, &chan->config, true);
198
    return true;
199
}
200
 
201
// This routine is called when the device is "looked" up (i.e. attached)
202
static Cyg_ErrNo
203
aaed2000_serial_lookup(struct cyg_devtab_entry **tab,
204
                  struct cyg_devtab_entry *sub_tab,
205
                  const char *name)
206
{
207
    serial_channel *chan = (serial_channel *)(*tab)->priv;
208
    (chan->callbacks->serial_init)(chan);  // Really only required for interrupt driven devices
209
    return ENOERR;
210
}
211
 
212
// Send a character to the device output buffer.
213
// Return 'true' if character is sent to device
214
static bool
215
aaed2000_serial_putc(serial_channel *chan, unsigned char c)
216
{
217
    aaed2000_serial_info *aaed2000_chan = (aaed2000_serial_info *)chan->dev_priv;
218
    CYG_ADDRWORD base = aaed2000_chan->base;
219
    cyg_uint32 _status;
220
 
221
    HAL_READ_UINT32(base+AAEC_UART_STATUS, _status);
222
    if (_status & AAEC_UART_STATUS_TxFF) {
223
        // No space
224
        return false;
225
    } else {
226
        // Transmit buffer is empty
227
        HAL_WRITE_UINT32(base+AAEC_UART_DATA, (cyg_uint32)c);
228
        return true;
229
    }
230
}
231
 
232
// Fetch a character from the device input buffer, waiting if necessary
233
static unsigned char
234
aaed2000_serial_getc(serial_channel *chan)
235
{
236
    aaed2000_serial_info *aaed2000_chan = (aaed2000_serial_info *)chan->dev_priv;
237
    CYG_ADDRWORD base = aaed2000_chan->base;
238
    cyg_uint32 _status;
239
    cyg_uint32 _c;
240
 
241
    do {
242
        HAL_READ_UINT32(base+AAEC_UART_STATUS, _status);
243
    } while (_status & AAEC_UART_STATUS_RxFE);
244
 
245
    HAL_READ_UINT32(base+AAEC_UART_DATA, _c);
246
    return (unsigned char)_c;
247
}
248
 
249
// Set up the device characteristics; baud rate, etc.
250
static Cyg_ErrNo
251
aaed2000_serial_set_config(serial_channel *chan, cyg_uint32 key,
252
                      const void *xbuf, cyg_uint32 *len)
253
{
254
    switch (key) {
255
    case CYG_IO_SET_CONFIG_SERIAL_INFO:
256
      {
257
        cyg_serial_info_t *config = (cyg_serial_info_t *)xbuf;
258
        if ( *len < sizeof(cyg_serial_info_t) ) {
259
            return -EINVAL;
260
        }
261
        *len = sizeof(cyg_serial_info_t);
262
        if ( true != aaed2000_serial_config_port(chan, config, false) )
263
            return -EINVAL;
264
      }
265
      break;
266
    default:
267
        return -EINVAL;
268
    }
269
    return ENOERR;
270
}
271
 
272
// Enable the transmitter on the device
273
static void
274
aaed2000_serial_start_xmit(serial_channel *chan)
275
{
276
    aaed2000_serial_info *aaed2000_chan = (aaed2000_serial_info *)chan->dev_priv;
277
    CYG_ADDRWORD base = aaed2000_chan->base;
278
    cyg_uint32 _intm;
279
 
280
    HAL_READ_UINT32(base+AAEC_UART_INTM, _intm);
281
    _intm |= AAEC_UART_INT_TIS;
282
    HAL_WRITE_UINT32(base+AAEC_UART_INTM, _intm);
283
}
284
 
285
// Disable the transmitter on the device
286
static void
287
aaed2000_serial_stop_xmit(serial_channel *chan)
288
{
289
    aaed2000_serial_info *aaed2000_chan = (aaed2000_serial_info *)chan->dev_priv;
290
    CYG_ADDRWORD base = aaed2000_chan->base;
291
    cyg_uint32 _intm;
292
 
293
    HAL_READ_UINT32(base+AAEC_UART_INTM, _intm);
294
    _intm &= ~AAEC_UART_INT_TIS;
295
    HAL_WRITE_UINT32(base+AAEC_UART_INTM, _intm);
296
}
297
 
298
// Serial I/O - low level interrupt handler (ISR)
299
static cyg_uint32
300
aaed2000_serial_ISR(cyg_vector_t vector, cyg_addrword_t data)
301
{
302
    serial_channel *chan = (serial_channel *)data;
303
    aaed2000_serial_info *aaed2000_chan = (aaed2000_serial_info *)chan->dev_priv;
304
    cyg_drv_interrupt_mask(aaed2000_chan->int_num);
305
    cyg_drv_interrupt_acknowledge(aaed2000_chan->int_num);
306
    return CYG_ISR_CALL_DSR;  // Cause DSR to be run
307
}
308
 
309
// Serial I/O - high level interrupt handler (DSR)
310
static void
311
aaed2000_serial_DSR(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
312
{
313
    serial_channel *chan = (serial_channel *)data;
314
    aaed2000_serial_info *aaed2000_chan = (aaed2000_serial_info *)chan->dev_priv;
315
    CYG_ADDRWORD base = aaed2000_chan->base;
316
    cyg_uint32 _intres, _c;
317
 
318
    HAL_READ_UINT32(base+AAEC_UART_INTRES, _intres);
319
    _intres &= (AAEC_UART_INT_TIS | AAEC_UART_INT_RIS | AAEC_UART_INT_RTIS);
320
    while (_intres) {
321
 
322
        // Empty Rx FIFO
323
        if (_intres & (AAEC_UART_INT_RIS|AAEC_UART_INT_RTIS)) {
324
            HAL_READ_UINT32(base+AAEC_UART_DATA, _c);
325
            (chan->callbacks->rcv_char)(chan, (unsigned char)_c);
326
        }
327
 
328
        // Fill into Tx FIFO. xmt_char will mask the interrupt when it
329
        // runs out of chars, so doing this in a loop is OK.
330
        if (_intres & AAEC_UART_INT_TIS) {
331
            (chan->callbacks->xmt_char)(chan);
332
        }
333
 
334
        HAL_READ_UINT32(base+AAEC_UART_INTRES, _intres);
335
        _intres &= (AAEC_UART_INT_TIS | AAEC_UART_INT_RIS | AAEC_UART_INT_RTIS);
336
    }
337
 
338
    cyg_drv_interrupt_unmask(aaed2000_chan->int_num);
339
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.